Index: ui/gfx/render_text_linux.cc |
diff --git a/ui/gfx/render_text_linux.cc b/ui/gfx/render_text_linux.cc |
index a770de0a98e87b24012a2bcf986f876f8a8cc1d1..c9ec938aa57ace24752a5d16e4131153080d2671 100644 |
--- a/ui/gfx/render_text_linux.cc |
+++ b/ui/gfx/render_text_linux.cc |
@@ -77,129 +77,78 @@ base::i18n::TextDirection RenderTextLinux::GetTextDirection() { |
return base::i18n::LEFT_TO_RIGHT; |
} |
-int RenderTextLinux::GetStringWidth() { |
+Size RenderTextLinux::GetStringSize() { |
EnsureLayout(); |
- int width; |
- pango_layout_get_pixel_size(layout_, &width, NULL); |
- return width; |
+ int width = 0, height = 0; |
+ pango_layout_get_pixel_size(layout_, &width, &height); |
+ return Size(width, height); |
} |
SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { |
EnsureLayout(); |
if (text().empty()) |
- return SelectionModel(0, 0, SelectionModel::LEADING); |
+ return SelectionModel(0, CURSOR_FORWARD); |
Point p(ToTextPoint(point)); |
// When the point is outside of text, return HOME/END position. |
if (p.x() < 0) |
return EdgeSelectionModel(CURSOR_LEFT); |
- else if (p.x() > GetStringWidth()) |
+ else if (p.x() > GetStringSize().width()) |
return EdgeSelectionModel(CURSOR_RIGHT); |
- int caret_pos, trailing; |
+ int caret_pos = 0, trailing = 0; |
pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, |
&caret_pos, &trailing); |
- size_t selection_end = caret_pos; |
+ DCHECK_GE(trailing, 0); |
if (trailing > 0) { |
- const char* ch = g_utf8_offset_to_pointer(layout_text_ + caret_pos, |
- trailing); |
- DCHECK_GE(ch, layout_text_); |
- DCHECK_LE(ch, layout_text_ + layout_text_len_); |
- selection_end = ch - layout_text_; |
+ caret_pos = g_utf8_offset_to_pointer(layout_text_ + caret_pos, |
+ trailing) - layout_text_; |
+ DCHECK_LE(static_cast<size_t>(caret_pos), layout_text_len_); |
} |
- return SelectionModel( |
- LayoutIndexToTextIndex(selection_end), |
- LayoutIndexToTextIndex(caret_pos), |
- trailing > 0 ? SelectionModel::TRAILING : SelectionModel::LEADING); |
+ return SelectionModel(LayoutIndexToTextIndex(caret_pos), |
+ (trailing > 0) ? CURSOR_BACKWARD : CURSOR_FORWARD); |
} |
-Rect RenderTextLinux::GetCursorBounds(const SelectionModel& selection, |
- bool insert_mode) { |
- EnsureLayout(); |
- |
- size_t caret_pos = insert_mode ? selection.caret_pos() : |
- selection.selection_end(); |
- PangoRectangle pos; |
- pango_layout_index_to_pos(layout_, TextIndexToLayoutIndex(caret_pos), &pos); |
- |
- SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); |
- int x = pos.x; |
- if ((insert_mode && caret_placement == SelectionModel::TRAILING) || |
- (!insert_mode && pos.width < 0)) |
- x += pos.width; |
- x = PANGO_PIXELS(x); |
- |
- int h = std::min(display_rect().height(), PANGO_PIXELS(pos.height)); |
- Rect bounds(x, (display_rect().height() - h) / 2, 0, h); |
- bounds.set_origin(ToViewPoint(bounds.origin())); |
- |
- if (!insert_mode) |
- bounds.set_width(PANGO_PIXELS(std::abs(pos.width))); |
- |
- return bounds; |
-} |
- |
-// Assume caret_pos in |current| is n, 'l' represents leading in |
-// caret_placement and 't' represents trailing in caret_placement. Following |
-// is the calculation from (caret_pos, caret_placement) in |current| to |
-// (selection_end, caret_pos, caret_placement) when moving cursor left/right by |
-// one grapheme (for simplicity, assume each grapheme is one character). |
-// If n is in LTR (if moving left) or RTL (if moving right) run, |
-// (n, t) --> (n, n, l). |
-// (n, l) --> (n-1, n-1, l) if n is inside run (not at boundary). |
-// (n, l) --> goto across run case if n is at run boundary. |
-// Otherwise, |
-// (n, l) --> (n+1, n, t). |
-// (n, t) --> (n+2, n+1, t) if n is inside run. |
-// (n, t) --> goto across run case if n is at run boundary. |
-// If n is at run boundary, get its visually left/right run, |
-// If left/right run is LTR/RTL run, |
-// (n, t) --> (left/right run's end, left/right run's end, l). |
-// Otherwise, |
-// (n, t) --> (left/right run's begin + 1, left/right run's begin, t). |
SelectionModel RenderTextLinux::AdjacentCharSelectionModel( |
const SelectionModel& selection, |
VisualCursorDirection direction) { |
- size_t caret = selection.caret_pos(); |
- SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); |
- GSList* run = GetRunContainingPosition(caret); |
- DCHECK(run); |
- |
- PangoLayoutRun* layout_run = reinterpret_cast<PangoLayoutRun*>(run->data); |
- PangoItem* item = layout_run->item; |
- size_t run_start = LayoutIndexToTextIndex(item->offset); |
- size_t run_end = LayoutIndexToTextIndex(item->offset + item->length); |
- if (!IsForwardMotion(direction, item)) { |
- if (caret_placement == SelectionModel::TRAILING) |
- return SelectionModel(caret, caret, SelectionModel::LEADING); |
- else if (caret > run_start) { |
- caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); |
- return SelectionModel(caret, caret, SelectionModel::LEADING); |
- } |
+ GSList* run = GetRunContainingCaret(selection); |
+ if (!run) { |
+ // The cursor is not in any run: we're at the visual and logical edge. |
+ SelectionModel edge = EdgeSelectionModel(direction); |
+ if (edge.caret_pos() == selection.caret_pos()) |
+ return edge; |
+ else |
+ run = (direction == CURSOR_RIGHT) ? |
+ current_line_->runs : g_slist_last(current_line_->runs); |
} else { |
- if (caret_placement == SelectionModel::LEADING) { |
- size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); |
- return SelectionModel(cursor, caret, SelectionModel::TRAILING); |
- } else if (selection.selection_end() < run_end) { |
- caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); |
- size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); |
- return SelectionModel(cursor, caret, SelectionModel::TRAILING); |
+ // If the cursor is moving within the current run, just move it by one |
+ // grapheme in the appropriate direction. |
+ PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
+ size_t caret = selection.caret_pos(); |
+ if (IsForwardMotion(direction, item)) { |
+ if (caret < LayoutIndexToTextIndex(item->offset + item->length)) { |
+ caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); |
+ return SelectionModel(caret, CURSOR_BACKWARD); |
+ } |
+ } else { |
+ if (caret > LayoutIndexToTextIndex(item->offset)) { |
+ caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); |
+ return SelectionModel(caret, CURSOR_FORWARD); |
+ } |
} |
+ // The cursor is at the edge of a run; move to the visually adjacent run. |
+ // TODO(xji): Keep a vector of runs to avoid using a singly-linked list. |
+ run = (direction == CURSOR_RIGHT) ? |
+ run->next : GSListPrevious(current_line_->runs, run); |
+ if (!run) |
+ return EdgeSelectionModel(direction); |
} |
- |
- // The character is at the edge of its run; advance to the adjacent visual |
- // run. |
- // TODO(xji): Keep a vector of runs to avoid using a singly-linked list. |
- GSList* adjacent_run = (direction == CURSOR_RIGHT) ? |
- run->next : GSListPrevious(current_line_->runs, run); |
- if (!adjacent_run) |
- return EdgeSelectionModel(direction); |
- |
- item = reinterpret_cast<PangoLayoutRun*>(adjacent_run->data)->item; |
+ PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
return IsForwardMotion(direction, item) ? |
FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); |
} |
@@ -216,69 +165,48 @@ SelectionModel RenderTextLinux::AdjacentWordSelectionModel( |
if (!success) |
return selection; |
- SelectionModel end = EdgeSelectionModel(direction); |
SelectionModel cur(selection); |
- while (!cur.Equals(end)) { |
+ for (;;) { |
cur = AdjacentCharSelectionModel(cur, direction); |
- size_t caret = cur.caret_pos(); |
- GSList* run = GetRunContainingPosition(caret); |
- DCHECK(run); |
+ GSList* run = GetRunContainingCaret(cur); |
+ if (!run) |
+ break; |
PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
- size_t cursor = cur.selection_end(); |
+ size_t cursor = cur.caret_pos(); |
if (IsForwardMotion(direction, item) ? |
iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) |
- return cur; |
+ break; |
} |
- return end; |
-} |
- |
-SelectionModel RenderTextLinux::EdgeSelectionModel( |
- VisualCursorDirection direction) { |
- if (direction == GetVisualDirectionOfLogicalEnd()) { |
- // Advance to the logical end of the text. |
- GSList* run = current_line_->runs; |
- if (direction == CURSOR_RIGHT) |
- run = g_slist_last(run); |
- if (run) { |
- PangoLayoutRun* end_run = reinterpret_cast<PangoLayoutRun*>(run->data); |
- PangoItem* item = end_run->item; |
- if (IsForwardMotion(direction, item)) { |
- size_t caret = IndexOfAdjacentGrapheme( |
- LayoutIndexToTextIndex(item->offset + item->length), |
- CURSOR_BACKWARD); |
- return SelectionModel(text().length(), caret, SelectionModel::TRAILING); |
- } else { |
- size_t caret = LayoutIndexToTextIndex(item->offset); |
- return SelectionModel(text().length(), caret, SelectionModel::LEADING); |
- } |
- } |
- } |
- return SelectionModel(0, 0, SelectionModel::LEADING); |
+ return cur; |
} |
void RenderTextLinux::SetSelectionModel(const SelectionModel& model) { |
- if (GetSelectionStart() != model.selection_start() || |
- GetCursorPosition() != model.selection_end()) { |
+ if (selection() != model.selection()) |
selection_visual_bounds_.clear(); |
- } |
RenderText::SetSelectionModel(model); |
} |
-std::vector<Rect> RenderTextLinux::GetSubstringBounds(size_t from, size_t to) { |
- DCHECK(from <= text().length()); |
- DCHECK(to <= text().length()); |
+void RenderTextLinux::GetGlyphBounds(size_t index, |
+ ui::Range* xspan, |
+ int* height) { |
+ PangoRectangle pos; |
+ pango_layout_index_to_pos(layout_, TextIndexToLayoutIndex(index), &pos); |
+ *xspan = ui::Range(PANGO_PIXELS(pos.x), PANGO_PIXELS(pos.x + pos.width)); |
+ *height = PANGO_PIXELS(pos.height); |
+} |
- if (from == to) |
+std::vector<Rect> RenderTextLinux::GetSubstringBounds(ui::Range range) { |
+ DCHECK_LE(range.GetMax(), text().length()); |
+ |
+ if (range.is_empty()) |
return std::vector<Rect>(); |
EnsureLayout(); |
- |
- if (from == GetSelectionStart() && to == GetCursorPosition()) |
+ if (range == selection()) |
return GetSelectionBounds(); |
- else |
- return CalculateSubstringBounds(from, to); |
+ return CalculateSubstringBounds(range); |
} |
bool RenderTextLinux::IsCursorablePosition(size_t position) { |
@@ -504,16 +432,16 @@ GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { |
SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( |
const PangoItem* item) { |
- size_t caret = LayoutIndexToTextIndex(item->offset); |
- size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); |
- return SelectionModel(cursor, caret, SelectionModel::TRAILING); |
+ size_t caret = IndexOfAdjacentGrapheme( |
+ LayoutIndexToTextIndex(item->offset), CURSOR_FORWARD); |
+ return SelectionModel(caret, CURSOR_BACKWARD); |
} |
SelectionModel RenderTextLinux::LastSelectionModelInsideRun( |
const PangoItem* item) { |
size_t caret = IndexOfAdjacentGrapheme( |
LayoutIndexToTextIndex(item->offset + item->length), CURSOR_BACKWARD); |
- return SelectionModel(caret, caret, SelectionModel::LEADING); |
+ return SelectionModel(caret, CURSOR_FORWARD); |
} |
void RenderTextLinux::ResetLayout() { |
@@ -556,16 +484,13 @@ size_t RenderTextLinux::LayoutIndexToTextIndex(size_t layout_index) const { |
return ui::UTF16OffsetToIndex(text(), 0, offset); |
} |
-std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(size_t from, |
- size_t to) { |
+std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(ui::Range range) { |
int* ranges; |
int n_ranges; |
- size_t from_in_utf8 = TextIndexToLayoutIndex(from); |
- size_t to_in_utf8 = TextIndexToLayoutIndex(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), |
+ TextIndexToLayoutIndex(range.GetMin()), |
+ TextIndexToLayoutIndex(range.GetMax()), |
&ranges, |
&n_ranges); |
@@ -588,8 +513,7 @@ std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(size_t from, |
std::vector<Rect> RenderTextLinux::GetSelectionBounds() { |
if (selection_visual_bounds_.empty()) |
- selection_visual_bounds_ = |
- CalculateSubstringBounds(GetSelectionStart(), GetCursorPosition()); |
+ selection_visual_bounds_ = CalculateSubstringBounds(selection()); |
return selection_visual_bounds_; |
} |