summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorxji@chromium.org <xji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-30 10:18:42 +0000
committerxji@chromium.org <xji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-30 10:18:42 +0000
commit6002a4f38fa52c3d5ffafff7af5c80b3620f2b69 (patch)
tree55db03775c4538e277df212413f6acce28513c8d /ui
parentcb66c5afe08ffd1bc5e5a3602e14bad192d79c31 (diff)
downloadchromium_src-6002a4f38fa52c3d5ffafff7af5c80b3620f2b69.zip
chromium_src-6002a4f38fa52c3d5ffafff7af5c80b3620f2b69.tar.gz
chromium_src-6002a4f38fa52c3d5ffafff7af5c80b3620f2b69.tar.bz2
Separate selection highlight from pango layout, highlight selection using skia.
Cache substring bounds to avoid unnecessary g_free. Consolidate drawing functions with RenderTextWin. Remove UpdateLayout() from RenderText::SetSelectionModel(). BUG=103647 TEST=TextfieldViewModelTest; Manual test selection highlight on bidi text. (Do not really know how to test "fi" ligature part. But since the selection highlight is not done by using pango attribute, I would assume that solves the problem). Review URL: http://codereview.chromium.org/8536047 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112188 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/gfx/render_text.cc121
-rw-r--r--ui/gfx/render_text.h39
-rw-r--r--ui/gfx/render_text_linux.cc232
-rw-r--r--ui/gfx/render_text_linux.h24
-rw-r--r--ui/gfx/render_text_win.cc177
-rw-r--r--ui/gfx/render_text_win.h13
6 files changed, 294 insertions, 312 deletions
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
index c3d9b6f..696a4f0 100644
--- a/ui/gfx/render_text.cc
+++ b/ui/gfx/render_text.cc
@@ -123,6 +123,8 @@ void RenderText::SetText(const string16& text) {
// Reset selection model. SetText should always followed by SetSelectionModel
// or SetCursorPosition in upper layer.
SetSelectionModel(SelectionModel(0, 0, SelectionModel::LEADING));
+
+ UpdateLayout();
}
void RenderText::ToggleInsertMode() {
@@ -344,57 +346,13 @@ int RenderText::GetStringWidth() {
}
void RenderText::Draw(Canvas* canvas) {
- // Clip the canvas to the text display area.
- canvas->ClipRect(display_rect_);
-
- // Draw the selection.
- std::vector<Rect> selection(GetSubstringBounds(GetSelectionStart(),
- GetCursorPosition()));
- SkColor selection_color =
- focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor;
- for (std::vector<Rect>::const_iterator i = selection.begin();
- i < selection.end(); ++i) {
- Rect r(*i);
- canvas->FillRect(selection_color, r);
- }
-
- // Create a temporary copy of the style ranges for composition and selection.
- StyleRanges style_ranges(style_ranges_);
- ApplyCompositionAndSelectionStyles(&style_ranges);
-
- // Draw the text.
- Rect bounds(display_rect_);
- bounds.Offset(GetUpdatedDisplayOffset());
- for (StyleRanges::const_iterator i = style_ranges.begin();
- i < style_ranges.end(); ++i) {
- const Font& font = !i->underline ? i->font :
- i->font.DeriveFont(0, i->font.GetStyle() | Font::UNDERLINED);
- string16 text = text_.substr(i->range.start(), i->range.length());
- bounds.set_width(font.GetStringWidth(text));
- canvas->DrawStringInt(text, font, i->foreground, bounds);
-
- // Draw the strikethrough.
- if (i->strike) {
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(i->foreground);
- paint.setStrokeWidth(kStrikeWidth);
- canvas->GetSkCanvas()->drawLine(SkIntToScalar(bounds.x()),
- SkIntToScalar(bounds.bottom()),
- SkIntToScalar(bounds.right()),
- SkIntToScalar(bounds.y()),
- paint);
- }
+ EnsureLayout();
- bounds.set_x(bounds.x() + bounds.width());
+ if (!text().empty()) {
+ DrawSelection(canvas);
+ DrawVisualText(canvas);
}
-
- // Paint cursor. Replace cursor is drawn as rectangle for now.
- Rect cursor(GetUpdatedCursorBounds());
- if (cursor_visible() && focused())
- canvas->DrawRectInt(kCursorColor, cursor.x(), cursor.y(),
- cursor.width(), cursor.height());
+ DrawCursor(canvas);
}
SelectionModel RenderText::FindCursorPosition(const Point& point) {
@@ -426,13 +384,6 @@ SelectionModel RenderText::FindCursorPosition(const Point& point) {
return SelectionModel(left_pos);
}
-Rect RenderText::GetCursorBounds(const SelectionModel& selection,
- bool insert_mode) {
- size_t from = selection.selection_end();
- size_t to = insert_mode ? from : std::min(text_.length(), from + 1);
- return GetSubstringBounds(from, to)[0];
-}
-
const Rect& RenderText::GetUpdatedCursorBounds() {
UpdateCachedBoundsAndOffset();
return cursor_bounds_;
@@ -549,22 +500,21 @@ SelectionModel RenderText::RightEndSelectionModel() {
return SelectionModel(cursor, caret_pos, placement);
}
-size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) {
- return IndexOfAdjacentGrapheme(position, false);
+void RenderText::SetSelectionModel(const SelectionModel& model) {
+ DCHECK_LE(model.selection_start(), text().length());
+ selection_model_.set_selection_start(model.selection_start());
+ DCHECK_LE(model.selection_end(), text().length());
+ selection_model_.set_selection_end(model.selection_end());
+ DCHECK_LT(model.caret_pos(),
+ std::max(text().length(), static_cast<size_t>(1)));
+ selection_model_.set_caret_pos(model.caret_pos());
+ selection_model_.set_caret_placement(model.caret_placement());
+
+ cached_bounds_and_offset_valid_ = false;
}
-std::vector<Rect> RenderText::GetSubstringBounds(size_t from, size_t to) {
- size_t start = std::min(from, to);
- size_t end = std::max(from, to);
- const Font& font = default_style_.font;
- int start_x = font.GetStringWidth(text().substr(0, start));
- int end_x = font.GetStringWidth(text().substr(0, end));
- Rect rect(start_x, 0, end_x - start_x, font.GetHeight());
- rect.Offset(display_rect_.origin());
- rect.Offset(GetUpdatedDisplayOffset());
- // Center the rect vertically in |display_rect_|.
- rect.Offset(Point(0, (display_rect_.height() - rect.height()) / 2));
- return std::vector<Rect>(1, rect);
+size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) {
+ return IndexOfAdjacentGrapheme(position, false);
}
void RenderText::ApplyCompositionAndSelectionStyles(
@@ -605,20 +555,6 @@ Point RenderText::ToViewPoint(const Point& point) {
return p;
}
-void RenderText::SetSelectionModel(const SelectionModel& selection_model) {
- DCHECK_LE(selection_model.selection_start(), text().length());
- selection_model_.set_selection_start(selection_model.selection_start());
- DCHECK_LE(selection_model.selection_end(), text().length());
- selection_model_.set_selection_end(selection_model.selection_end());
- DCHECK_LT(selection_model.caret_pos(),
- std::max(text().length(), static_cast<size_t>(1)));
- selection_model_.set_caret_pos(selection_model.caret_pos());
- selection_model_.set_caret_placement(selection_model.caret_placement());
-
- cached_bounds_and_offset_valid_ = false;
- UpdateLayout();
-}
-
void RenderText::MoveCursorTo(size_t position, bool select) {
size_t cursor = std::min(position, text().length());
size_t caret_pos = GetIndexOfPreviousGrapheme(cursor);
@@ -664,4 +600,21 @@ void RenderText::UpdateCachedBoundsAndOffset() {
cursor_bounds_.Offset(delta_offset, 0);
}
+void RenderText::DrawSelection(Canvas* canvas) {
+ std::vector<Rect> sel;
+ GetSubstringBounds(GetSelectionStart(), GetCursorPosition(), &sel);
+ SkColor color = focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor;
+ for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
+ canvas->FillRect(color, *i);
+}
+
+void RenderText::DrawCursor(Canvas* canvas) {
+ // Paint cursor. Replace cursor is drawn as rectangle for now.
+ // TODO(msw): Draw a better cursor with a better indication of association.
+ if (cursor_visible() && focused()) {
+ Rect r(GetUpdatedCursorBounds());
+ canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height());
+ }
+}
+
} // namespace gfx
diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h
index 6b39d16..da3607d 100644
--- a/ui/gfx/render_text.h
+++ b/ui/gfx/render_text.h
@@ -21,9 +21,6 @@
namespace gfx {
-// Strike line width.
-const int kStrikeWidth = 2;
-
// Color settings for text, backgrounds and cursor.
// These are tentative, and should be derived from theme, system
// settings and current settings.
@@ -172,7 +169,7 @@ class UI_EXPORT RenderText {
// may be outside the visible region if the text is longer than the textfield.
// Subsequent text, cursor, or bounds changes may invalidate returned values.
virtual Rect GetCursorBounds(const SelectionModel& selection,
- bool insert_mode);
+ bool insert_mode) = 0;
// Compute the current cursor bounds, panning the text to show the cursor in
// the display rect if necessary. These bounds are in local coordinates.
@@ -209,25 +206,36 @@ class UI_EXPORT RenderText {
virtual SelectionModel LeftEndSelectionModel();
virtual SelectionModel RightEndSelectionModel();
- // Get the logical index of the grapheme preceeding the argument |position|.
- virtual size_t GetIndexOfPreviousGrapheme(size_t position);
+ // Sets the selection model, the argument is assumed to be valid.
+ virtual void SetSelectionModel(const SelectionModel& model);
// Get the visual bounds containing the logical substring within |from| to
- // |to|. These bounds could be visually discontinuous if the substring is
- // split by a LTR/RTL level change. These bounds are in local coordinates, but
- // may be outside the visible region if the text is longer than the textfield.
+ // |to| into |bounds|. If |from| equals to |to|, |bounds| is set as empty.
+ // These bounds could be visually discontinuous if the substring is split by a
+ // LTR/RTL level change. These bounds are in local coordinates, but may be
+ // outside the visible region if the text is longer than the textfield.
// Subsequent text, cursor, or bounds changes may invalidate returned values.
- // TODO(msw) Re-evaluate this function's necessity and signature.
- virtual std::vector<Rect> GetSubstringBounds(size_t from, size_t to);
+ virtual void GetSubstringBounds(size_t from,
+ size_t to,
+ std::vector<Rect>* bounds) = 0;
// Return true if cursor can appear in front of the character at |position|,
// which means it is a grapheme boundary or the first character in the text.
virtual bool IsCursorablePosition(size_t position) = 0;
- // Updates the layout so that the next draw request can correctly
+ // Update the layout so that the next draw request can correctly
// render the text and its attributes.
virtual void UpdateLayout() = 0;
+ // Ensure the text is laid out.
+ virtual void EnsureLayout() = 0;
+
+ // Draw the text.
+ virtual void DrawVisualText(Canvas* canvas) = 0;
+
+ // Get the logical index of the grapheme preceding the argument |position|.
+ size_t GetIndexOfPreviousGrapheme(size_t position);
+
// Apply composition style (underline) to composition range and selection
// style (foreground) to selection range.
void ApplyCompositionAndSelectionStyles(StyleRanges* style_ranges) const;
@@ -249,9 +257,6 @@ class UI_EXPORT RenderText {
// The return value is bounded by 0 and the text length, inclusive.
virtual size_t IndexOfAdjacentGrapheme(size_t index, bool next) = 0;
- // Sets the selection model, the argument is assumed to be valid.
- void SetSelectionModel(const SelectionModel& selection_model);
-
// Set the cursor to |position|, with the caret trailing the previous
// grapheme, or if there is no previous grapheme, leading the cursor position.
// If |select| is false, the selection start is moved to the same position.
@@ -263,6 +268,10 @@ class UI_EXPORT RenderText {
// cursor is within the visible display area.
void UpdateCachedBoundsAndOffset();
+ // Draw the selection and cursor.
+ void DrawSelection(Canvas* canvas);
+ void DrawCursor(Canvas* canvas);
+
// Logical UTF-16 string data to be drawn.
string16 text_;
diff --git a/ui/gfx/render_text_linux.cc b/ui/gfx/render_text_linux.cc
index ab6e725..e2f0d67 100644
--- a/ui/gfx/render_text_linux.cc
+++ b/ui/gfx/render_text_linux.cc
@@ -5,7 +5,6 @@
#include "ui/gfx/render_text_linux.h"
#include <pango/pangocairo.h>
-
#include <algorithm>
#include "base/i18n/break_iterator.h"
@@ -58,48 +57,14 @@ base::i18n::TextDirection RenderTextLinux::GetTextDirection() {
}
int RenderTextLinux::GetStringWidth() {
- PangoLayout* layout = EnsureLayout();
+ EnsureLayout();
int width;
- pango_layout_get_pixel_size(layout, &width, NULL);
+ pango_layout_get_pixel_size(layout_, &width, NULL);
return width;
}
-void RenderTextLinux::Draw(Canvas* canvas) {
- PangoLayout* layout = EnsureLayout();
- Rect bounds(display_rect());
-
- // Clip the canvas to the text display area.
- SkCanvas* canvas_skia = canvas->GetSkCanvas();
-
- skia::ScopedPlatformPaint scoped_platform_paint(canvas_skia);
- cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
- cairo_save(cr);
- cairo_rectangle(cr, bounds.x(), bounds.y(), bounds.width(), bounds.height());
- cairo_clip(cr);
-
- int text_width, text_height;
- pango_layout_get_pixel_size(layout, &text_width, &text_height);
- Point offset(ToViewPoint(Point()));
- // Vertically centered.
- int text_y = offset.y() + ((bounds.height() - text_height) / 2);
- // TODO(xji): need to use SkCanvas->drawPosText() for gpu acceleration.
- cairo_move_to(cr, offset.x(), text_y);
- pango_cairo_show_layout(cr, layout);
-
- cairo_restore(cr);
-
- // Paint cursor.
- bounds = GetUpdatedCursorBounds();
- if (cursor_visible() && focused())
- canvas->DrawRectInt(kCursorColor,
- bounds.x(),
- bounds.y(),
- bounds.width(),
- bounds.height());
-}
-
SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) {
- PangoLayout* layout = EnsureLayout();
+ EnsureLayout();
if (text().empty())
return SelectionModel(0, 0, SelectionModel::LEADING);
@@ -113,7 +78,7 @@ SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) {
return RightEndSelectionModel();
int caret_pos, trailing;
- pango_layout_xy_to_index(layout, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE,
+ pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE,
&caret_pos, &trailing);
size_t selection_end = caret_pos;
@@ -133,12 +98,12 @@ SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) {
Rect RenderTextLinux::GetCursorBounds(const SelectionModel& selection,
bool insert_mode) {
- PangoLayout* layout = EnsureLayout();
+ EnsureLayout();
size_t caret_pos = insert_mode ? selection.caret_pos() :
selection.selection_end();
PangoRectangle pos;
- pango_layout_index_to_pos(layout, Utf16IndexToUtf8Index(caret_pos), &pos);
+ pango_layout_index_to_pos(layout_, Utf16IndexToUtf8Index(caret_pos), &pos);
SelectionModel::CaretPlacement caret_placement = selection.caret_placement();
int x = pos.x;
@@ -220,6 +185,33 @@ SelectionModel RenderTextLinux::RightEndSelectionModel() {
return SelectionModel(0, 0, SelectionModel::LEADING);
}
+void RenderTextLinux::SetSelectionModel(const SelectionModel& model) {
+ if (GetSelectionStart() != model.selection_start() ||
+ GetCursorPosition() != model.selection_end()) {
+ selection_visual_bounds_.clear();
+ }
+
+ RenderText::SetSelectionModel(model);
+}
+
+void RenderTextLinux::GetSubstringBounds(size_t from,
+ size_t to,
+ std::vector<Rect>* bounds) {
+ DCHECK(from <= text().length());
+ DCHECK(to <= text().length());
+
+ bounds->clear();
+ if (from == to)
+ return;
+
+ EnsureLayout();
+
+ if (from == GetSelectionStart() && to == GetCursorPosition())
+ GetSelectionBounds(bounds);
+ else
+ CalculateSubstringBounds(from, to, bounds);
+}
+
bool RenderTextLinux::IsCursorablePosition(size_t position) {
if (position == 0 && text().empty())
return true;
@@ -233,6 +225,64 @@ void RenderTextLinux::UpdateLayout() {
ResetLayout();
}
+void RenderTextLinux::EnsureLayout() {
+ if (layout_ == NULL) {
+ CanvasSkia canvas(display_rect().width(), display_rect().height(), false);
+ skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
+ cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
+
+ layout_ = pango_cairo_create_layout(cr);
+ SetupPangoLayout(
+ layout_,
+ text(),
+ default_style().font,
+ display_rect().width(),
+ base::i18n::GetFirstStrongCharacterDirection(text()),
+ CanvasSkia::DefaultCanvasTextAlignment());
+
+ // No width set so that the x-axis position is relative to the start of the
+ // text. ToViewPoint and ToTextPoint take care of the position conversion
+ // between text space and view spaces.
+ pango_layout_set_width(layout_, -1);
+ // TODO(xji): If RenderText will be used for displaying purpose, such as
+ // label, we will need to remove the single-line-mode setting.
+ pango_layout_set_single_paragraph_mode(layout_, true);
+ SetupPangoAttributes(layout_);
+
+ current_line_ = pango_layout_get_line_readonly(layout_, 0);
+ pango_layout_line_ref(current_line_);
+
+ pango_layout_get_log_attrs(layout_, &log_attrs_, &num_log_attrs_);
+
+ layout_text_ = pango_layout_get_text(layout_);
+ layout_text_len_ = strlen(layout_text_);
+ }
+}
+
+void RenderTextLinux::DrawVisualText(Canvas* canvas) {
+ Rect bounds(display_rect());
+
+ // Clip the canvas to the text display area.
+ SkCanvas* canvas_skia = canvas->GetSkCanvas();
+
+ skia::ScopedPlatformPaint scoped_platform_paint(canvas_skia);
+ cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
+ cairo_save(cr);
+ cairo_rectangle(cr, bounds.x(), bounds.y(), bounds.width(), bounds.height());
+ cairo_clip(cr);
+
+ int text_width, text_height;
+ pango_layout_get_pixel_size(layout_, &text_width, &text_height);
+ Point offset(ToViewPoint(Point()));
+ // Vertically centered.
+ int text_y = offset.y() + ((bounds.height() - text_height) / 2);
+ // TODO(xji): need to use SkCanvas->drawPosText() for gpu acceleration.
+ cairo_move_to(cr, offset.x(), text_y);
+ pango_cairo_show_layout(cr, layout_);
+
+ cairo_restore(cr);
+}
+
size_t RenderTextLinux::IndexOfAdjacentGrapheme(size_t index, bool next) {
EnsureLayout();
return Utf16IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), next);
@@ -474,41 +524,6 @@ SelectionModel RenderTextLinux::RightSelectionModelByWord(
return right_end;
}
-PangoLayout* RenderTextLinux::EnsureLayout() {
- if (layout_ == NULL) {
- CanvasSkia canvas(display_rect().width(), display_rect().height(), false);
- skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
- cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
-
- layout_ = pango_cairo_create_layout(cr);
- SetupPangoLayout(
- layout_,
- text(),
- default_style().font,
- display_rect().width(),
- base::i18n::GetFirstStrongCharacterDirection(text()),
- CanvasSkia::DefaultCanvasTextAlignment());
-
- // No width set so that the x-axis position is relative to the start of the
- // text. ToViewPoint and ToTextPoint take care of the position conversion
- // between text space and view spaces.
- pango_layout_set_width(layout_, -1);
- // TODO(xji): If RenderText will be used for displaying purpose, such as
- // label, we will need to remove the single-line-mode setting.
- pango_layout_set_single_paragraph_mode(layout_, true);
- SetupPangoAttributes(layout_);
-
- current_line_ = pango_layout_get_line_readonly(layout_, 0);
- pango_layout_line_ref(current_line_);
-
- pango_layout_get_log_attrs(layout_, &log_attrs_, &num_log_attrs_);
-
- layout_text_ = pango_layout_get_text(layout_);
- layout_text_len_ = strlen(layout_text_);
- }
- return layout_;
-}
-
void RenderTextLinux::ResetLayout() {
// set_cached_bounds_and_offset_valid(false) is done in RenderText for every
// operation that triggers ResetLayout().
@@ -525,44 +540,25 @@ void RenderTextLinux::ResetLayout() {
log_attrs_ = NULL;
num_log_attrs_ = 0;
}
+ if (!selection_visual_bounds_.empty())
+ selection_visual_bounds_.clear();
layout_text_ = NULL;
layout_text_len_ = 0;
}
void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) {
PangoAttrList* attrs = pango_attr_list_new();
- // Set selection background color.
- // TODO(xji): There's a bug in pango that it can't use two colors in one
- // glyph. Please refer to https://bugzilla.gnome.org/show_bug.cgi?id=648157
- // for detail. So for example, if a font has "ffi" ligature, but you select
- // half of that glyph, you either get the entire "ffi" ligature
- // selection-colored, or none of it.
- // We could use clipping to render selection.
- // Use pango_glyph_item_get_logical_widths to find the exact boundaries of
- // selection, then cairo_clip that, paint background, set color to white and
- // redraw the layout.
- SkColor selection_color =
- focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor;
- size_t start = std::min(MinOfSelection(), text().length());
- size_t end = std::min(MaxOfSelection(), text().length());
- PangoAttribute* pango_attr;
- if (end > start) {
- pango_attr = pango_attr_background_new(
- ConvertColorFrom8BitTo16Bit(SkColorGetR(selection_color)),
- ConvertColorFrom8BitTo16Bit(SkColorGetG(selection_color)),
- ConvertColorFrom8BitTo16Bit(SkColorGetB(selection_color)));
- AppendPangoAttribute(start, end, pango_attr, attrs);
- }
StyleRanges ranges_of_style(style_ranges());
ApplyCompositionAndSelectionStyles(&ranges_of_style);
PlatformFont* default_platform_font = default_style().font.platform_font();
+ PangoAttribute* pango_attr;
for (StyleRanges::const_iterator i = ranges_of_style.begin();
i < ranges_of_style.end(); ++i) {
- start = std::min(i->range.start(), text().length());
- end = std::min(i->range.end(), text().length());
+ size_t start = std::min(i->range.start(), text().length());
+ size_t end = std::min(i->range.end(), text().length());
if (start >= end)
continue;
@@ -657,4 +653,40 @@ size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const {
return utf16_index;
}
+void RenderTextLinux::CalculateSubstringBounds(size_t from,
+ size_t to,
+ std::vector<Rect>* bounds) {
+ int* ranges;
+ int n_ranges;
+ size_t from_in_utf8 = Utf16IndexToUtf8Index(from);
+ size_t to_in_utf8 = Utf16IndexToUtf8Index(to);
+ pango_layout_line_get_x_ranges(
+ current_line_,
+ std::min(from_in_utf8, to_in_utf8),
+ std::max(from_in_utf8, to_in_utf8),
+ &ranges,
+ &n_ranges);
+
+ int height;
+ pango_layout_get_pixel_size(layout_, NULL, &height);
+
+ int y = (display_rect().height() - height) / 2;
+
+ for (int i = 0; i < n_ranges; ++i) {
+ int x = PANGO_PIXELS(ranges[2 * i]);
+ int width = PANGO_PIXELS(ranges[2 * i + 1]) - x;
+ Rect rect(x, y, width, height);
+ rect.set_origin(ToViewPoint(rect.origin()));
+ bounds->push_back(rect);
+ }
+ g_free(ranges);
+}
+
+void RenderTextLinux::GetSelectionBounds(std::vector<Rect>* bounds) {
+ if (selection_visual_bounds_.empty())
+ CalculateSubstringBounds(GetSelectionStart(), GetCursorPosition(),
+ &selection_visual_bounds_);
+ *bounds = selection_visual_bounds_;
+}
+
} // namespace gfx
diff --git a/ui/gfx/render_text_linux.h b/ui/gfx/render_text_linux.h
index b473d9d..462494d 100644
--- a/ui/gfx/render_text_linux.h
+++ b/ui/gfx/render_text_linux.h
@@ -7,6 +7,7 @@
#pragma once
#include <pango/pango.h>
+#include <vector>
#include "ui/gfx/render_text.h"
@@ -21,7 +22,6 @@ class RenderTextLinux : public RenderText {
// Overridden from RenderText:
virtual base::i18n::TextDirection GetTextDirection() OVERRIDE;
virtual int GetStringWidth() OVERRIDE;
- virtual void Draw(Canvas* canvas) OVERRIDE;
virtual SelectionModel FindCursorPosition(const Point& point) OVERRIDE;
virtual Rect GetCursorBounds(const SelectionModel& position,
bool insert_mode) OVERRIDE;
@@ -34,8 +34,14 @@ class RenderTextLinux : public RenderText {
BreakType break_type) OVERRIDE;
virtual SelectionModel LeftEndSelectionModel() OVERRIDE;
virtual SelectionModel RightEndSelectionModel() OVERRIDE;
+ virtual void GetSubstringBounds(size_t from,
+ size_t to,
+ std::vector<Rect>* bounds) OVERRIDE;
+ virtual void SetSelectionModel(const SelectionModel& model) OVERRIDE;
virtual bool IsCursorablePosition(size_t position) OVERRIDE;
virtual void UpdateLayout() OVERRIDE;
+ virtual void EnsureLayout() OVERRIDE;
+ virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
private:
virtual size_t IndexOfAdjacentGrapheme(size_t index, bool next) OVERRIDE;
@@ -69,10 +75,6 @@ class RenderTextLinux : public RenderText {
SelectionModel LeftSelectionModelByWord(const SelectionModel& current);
SelectionModel RightSelectionModelByWord(const SelectionModel& current);
- // If |layout_| is NULL, create and setup |layout_|, retain and ref
- // |current_line_|. Return |layout_|.
- PangoLayout* EnsureLayout();
-
// Unref |layout_| and |pango_line_|. Set them to NULL.
void ResetLayout();
@@ -96,6 +98,15 @@ class RenderTextLinux : public RenderText {
size_t Utf16IndexToUtf8Index(size_t index) const;
size_t Utf8IndexToUtf16Index(size_t index) const;
+ // Calculate the visual bounds containing the logical substring within |from|
+ // to |to| into |bounds|.
+ void CalculateSubstringBounds(size_t from,
+ size_t to,
+ std::vector<Rect>* bounds);
+
+ // Save the visual bounds of logical selection into |bounds|.
+ void GetSelectionBounds(std::vector<Rect>* bounds);
+
// Pango Layout.
PangoLayout* layout_;
// A single line layout resulting from laying out via |layout_|.
@@ -106,6 +117,9 @@ class RenderTextLinux : public RenderText {
// Number of attributes in |log_attrs_|.
int num_log_attrs_;
+ // Vector of the visual bounds containing the logical substring of selection.
+ std::vector<Rect> selection_visual_bounds_;
+
// The text in the |layout_|.
const char* layout_text_;
// The text length.
diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc
index e5c64d0..3fcd856 100644
--- a/ui/gfx/render_text_win.cc
+++ b/ui/gfx/render_text_win.cc
@@ -173,13 +173,6 @@ int RenderTextWin::GetStringWidth() {
return string_width_;
}
-void RenderTextWin::Draw(Canvas* canvas) {
- EnsureLayout();
- DrawSelection(canvas);
- DrawVisualText(canvas);
- DrawCursor(canvas);
-}
-
SelectionModel RenderTextWin::FindCursorPosition(const Point& point) {
if (text().empty())
return SelectionModel();
@@ -319,14 +312,19 @@ SelectionModel RenderTextWin::RightEndSelectionModel() {
return SelectionModel(cursor, caret, placement);
}
-std::vector<Rect> RenderTextWin::GetSubstringBounds(size_t from, size_t to) {
+void RenderTextWin::GetSubstringBounds(size_t from,
+ size_t to,
+ std::vector<Rect>* bounds) {
DCHECK(!needs_layout_);
ui::Range range(from, to);
DCHECK(ui::Range(0, text().length()).Contains(range));
Point display_offset(GetUpdatedDisplayOffset());
- std::vector<Rect> bounds;
HRESULT hr = 0;
+ bounds->clear();
+ if (from == to)
+ return;
+
// Add a Rect for each run/selection intersection.
// TODO(msw): The bounds should probably not always be leading the range ends.
for (size_t i = 0; i < runs_.size(); ++i) {
@@ -364,14 +362,13 @@ std::vector<Rect> RenderTextWin::GetSubstringBounds(size_t from, size_t to) {
rect.Offset(0, (display_rect().height() - rect.height()) / 2);
rect.set_origin(ToViewPoint(rect.origin()));
// Union this with the last rect if they're adjacent.
- if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) {
- rect = rect.Union(bounds.back());
- bounds.pop_back();
+ if (!bounds->empty() && rect.SharesEdgeWith(bounds->back())) {
+ rect = rect.Union(bounds->back());
+ bounds->pop_back();
}
- bounds.push_back(rect);
+ bounds->push_back(rect);
}
}
- return bounds;
}
bool RenderTextWin::IsCursorablePosition(size_t position) {
@@ -396,6 +393,72 @@ void RenderTextWin::UpdateLayout() {
needs_layout_ = true;
}
+void RenderTextWin::EnsureLayout() {
+ if (!needs_layout_)
+ return;
+ // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
+ ItemizeLogicalText();
+ if (!runs_.empty())
+ LayoutVisualText();
+ needs_layout_ = false;
+}
+
+void RenderTextWin::DrawVisualText(Canvas* canvas) {
+ SkCanvas* canvas_skia = canvas->GetSkCanvas();
+
+ Point offset(ToViewPoint(Point()));
+ // TODO(msw): Establish a vertical baseline for strings of mixed font heights.
+ size_t height = default_style().font.GetHeight();
+
+ SkScalar x = SkIntToScalar(offset.x());
+ SkScalar y = SkIntToScalar(offset.y());
+ // Center the text vertically in the display area.
+ y += (display_rect().height() - height) / 2;
+ // Offset by the font size to account for Skia expecting y to be the bottom.
+ y += default_style().font.GetFontSize();
+
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setAntiAlias(true);
+ paint.setSubpixelText(true);
+ paint.setLCDRenderText(true);
+
+ std::vector<SkPoint> pos;
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ // Get the run specified by the visual-to-logical map.
+ internal::TextRun* run = runs_[visual_to_logical_[i]];
+
+ // TODO(msw): Font default/fallback and style integration.
+ SkTypeface::Style style = SkTypeface::kNormal;
+ SkTypeface* typeface =
+ SkTypeface::CreateFromName(run->font.GetFontName().c_str(), style);
+ if (typeface) {
+ paint.setTypeface(typeface);
+ // |paint| adds its own ref. Release the ref from CreateFromName.
+ typeface->unref();
+ }
+ paint.setTextSize(run->font.GetFontSize());
+ paint.setColor(run->foreground);
+
+ SkScalar run_x = x;
+
+ // Based on WebCore::skiaDrawText.
+ pos.resize(run->glyph_count);
+ for (int glyph = 0; glyph < run->glyph_count; glyph++) {
+ pos[glyph].set(x + run->offsets[glyph].du,
+ y + run->offsets[glyph].dv);
+ x += SkIntToScalar(run->advance_widths[glyph]);
+ }
+
+ size_t byte_length = run->glyph_count * sizeof(WORD);
+ canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
+
+ if (run->strike || run->underline)
+ DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
+ }
+}
+
size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) {
EnsureLayout();
size_t run_index = GetRunContainingPosition(index);
@@ -416,16 +479,6 @@ size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) {
return std::max(std::min(ch, length) + start, 0);
}
-void RenderTextWin::EnsureLayout() {
- if (!needs_layout_)
- return;
- // TODO(msw): Skip complex processing if ScriptIsComplex returns false.
- ItemizeLogicalText();
- if (!runs_.empty())
- LayoutVisualText();
- needs_layout_ = false;
-}
-
void RenderTextWin::ItemizeLogicalText() {
STLDeleteContainerPointers(runs_.begin(), runs_.end());
runs_.clear();
@@ -690,82 +743,6 @@ SelectionModel RenderTextWin::RightSelectionModel(
FirstSelectionModelInsideRun(next);
}
-void RenderTextWin::DrawSelection(Canvas* canvas) {
- std::vector<Rect> sel(
- GetSubstringBounds(GetSelectionStart(), GetCursorPosition()));
- SkColor color = focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor;
- for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
- canvas->FillRect(color, *i);
-}
-
-void RenderTextWin::DrawVisualText(Canvas* canvas) {
- if (text().empty())
- return;
-
- SkCanvas* canvas_skia = canvas->GetSkCanvas();
-
- Point offset(ToViewPoint(Point()));
- // TODO(msw): Establish a vertical baseline for strings of mixed font heights.
- size_t height = default_style().font.GetHeight();
-
- SkScalar x = SkIntToScalar(offset.x());
- SkScalar y = SkIntToScalar(offset.y());
- // Center the text vertically in the display area.
- y += (display_rect().height() - height) / 2;
- // Offset by the font size to account for Skia expecting y to be the bottom.
- y += default_style().font.GetFontSize();
-
- SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setStyle(SkPaint::kFill_Style);
- paint.setAntiAlias(true);
- paint.setSubpixelText(true);
- paint.setLCDRenderText(true);
-
- std::vector<SkPoint> pos;
- for (size_t i = 0; i < runs_.size(); ++i) {
- // Get the run specified by the visual-to-logical map.
- internal::TextRun* run = runs_[visual_to_logical_[i]];
-
- // TODO(msw): Font default/fallback and style integration.
- SkTypeface::Style style = SkTypeface::kNormal;
- SkTypeface* typeface =
- SkTypeface::CreateFromName(run->font.GetFontName().c_str(), style);
- if (typeface) {
- paint.setTypeface(typeface);
- // |paint| adds its own ref. Release the ref from CreateFromName.
- typeface->unref();
- }
- paint.setTextSize(run->font.GetFontSize());
- paint.setColor(run->foreground);
-
- SkScalar run_x = x;
-
- // Based on WebCore::skiaDrawText.
- pos.resize(run->glyph_count);
- for (int glyph = 0; glyph < run->glyph_count; glyph++) {
- pos[glyph].set(x + run->offsets[glyph].du,
- y + run->offsets[glyph].dv);
- x += SkIntToScalar(run->advance_widths[glyph]);
- }
-
- size_t byte_length = run->glyph_count * sizeof(WORD);
- canvas_skia->drawPosText(run->glyphs.get(), byte_length, &pos[0], paint);
-
- if (run->strike || run->underline)
- DrawTextRunDecorations(canvas_skia, paint, *run, run_x, y);
- }
-}
-
-void RenderTextWin::DrawCursor(Canvas* canvas) {
- // Paint cursor. Replace cursor is drawn as rectangle for now.
- // TODO(msw): Draw a better cursor with a better indication of association.
- if (cursor_visible() && focused()) {
- Rect r(GetUpdatedCursorBounds());
- canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height());
- }
-}
-
RenderText* RenderText::CreateRenderText() {
return new RenderTextWin;
}
diff --git a/ui/gfx/render_text_win.h b/ui/gfx/render_text_win.h
index 1711d7b..5733760 100644
--- a/ui/gfx/render_text_win.h
+++ b/ui/gfx/render_text_win.h
@@ -60,7 +60,6 @@ class RenderTextWin : public RenderText {
// Overridden from RenderText:
virtual int GetStringWidth() OVERRIDE;
- virtual void Draw(Canvas* canvas) OVERRIDE;
virtual SelectionModel FindCursorPosition(const Point& point) OVERRIDE;
virtual Rect GetCursorBounds(const SelectionModel& selection,
bool insert_mode) OVERRIDE;
@@ -73,14 +72,17 @@ class RenderTextWin : public RenderText {
BreakType break_type) OVERRIDE;
virtual SelectionModel LeftEndSelectionModel() OVERRIDE;
virtual SelectionModel RightEndSelectionModel() OVERRIDE;
- virtual std::vector<Rect> GetSubstringBounds(size_t from, size_t to) OVERRIDE;
+ virtual void GetSubstringBounds(size_t from,
+ size_t to,
+ std::vector<Rect>* bounds) OVERRIDE;
virtual bool IsCursorablePosition(size_t position) OVERRIDE;
virtual void UpdateLayout() OVERRIDE;
+ virtual void EnsureLayout() OVERRIDE;
+ virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
private:
virtual size_t IndexOfAdjacentGrapheme(size_t index, bool next) OVERRIDE;
- void EnsureLayout();
void ItemizeLogicalText();
void LayoutVisualText();
@@ -100,11 +102,6 @@ class RenderTextWin : public RenderText {
SelectionModel LeftSelectionModel(const SelectionModel& selection);
SelectionModel RightSelectionModel(const SelectionModel& selection);
- // Draw the text, cursor, and selection.
- void DrawSelection(Canvas* canvas);
- void DrawVisualText(Canvas* canvas);
- void DrawCursor(Canvas* canvas);
-
// National Language Support native digit and digit substitution settings.
SCRIPT_DIGITSUBSTITUTE digit_substitute_;