Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(847)

Unified Diff: ui/gfx/render_text_linux.cc

Issue 9390022: Simplify handling of BiDi cursor movement (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase (no changes) Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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_;
}

Powered by Google App Engine
This is Rietveld 408576698