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

Side by Side 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: comments Created 8 years, 10 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/render_text_linux.h" 5 #include "ui/gfx/render_text_linux.h"
6 6
7 #include <pango/pangocairo.h> 7 #include <pango/pangocairo.h>
8 #include <algorithm> 8 #include <algorithm>
9 #include <string> 9 #include <string>
10 #include <vector> 10 #include <vector>
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 71
72 base::i18n::TextDirection RenderTextLinux::GetTextDirection() { 72 base::i18n::TextDirection RenderTextLinux::GetTextDirection() {
73 EnsureLayout(); 73 EnsureLayout();
74 74
75 PangoDirection base_dir = pango_find_base_dir(layout_text_, -1); 75 PangoDirection base_dir = pango_find_base_dir(layout_text_, -1);
76 if (base_dir == PANGO_DIRECTION_RTL || base_dir == PANGO_DIRECTION_WEAK_RTL) 76 if (base_dir == PANGO_DIRECTION_RTL || base_dir == PANGO_DIRECTION_WEAK_RTL)
77 return base::i18n::RIGHT_TO_LEFT; 77 return base::i18n::RIGHT_TO_LEFT;
78 return base::i18n::LEFT_TO_RIGHT; 78 return base::i18n::LEFT_TO_RIGHT;
79 } 79 }
80 80
81 int RenderTextLinux::GetStringWidth() { 81 Size RenderTextLinux::GetStringSize() {
82 EnsureLayout(); 82 EnsureLayout();
83 int width; 83 int width, height;
msw 2012/02/16 00:09:21 Please explicitly init these locals.
benrg 2012/02/16 09:20:55 I'm not sure what to initialize them to.
msw 2012/02/21 21:13:39 I see that you updated them to 0; that's better th
84 pango_layout_get_pixel_size(layout_, &width, NULL); 84 pango_layout_get_pixel_size(layout_, &width, &height);
85 return width; 85 return Size(width, height);
86 }
87
88 void RenderTextLinux::GetGlyphBounds(size_t index,
89 ui::Range* xspan,
90 int* height) {
91 PangoRectangle pos;
92 pango_layout_index_to_pos(layout_, Utf16IndexToUtf8Index(index), &pos);
93 *xspan = ui::Range(PANGO_PIXELS(pos.x), PANGO_PIXELS(pos.x + pos.width));
94 *height = PANGO_PIXELS(pos.height);
86 } 95 }
87 96
88 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { 97 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) {
89 EnsureLayout(); 98 EnsureLayout();
90 99
91 if (text().empty()) 100 if (text().empty())
92 return SelectionModel(0, 0, SelectionModel::LEADING); 101 return SelectionModel(0, CURSOR_FORWARD);
93 102
94 Point p(ToTextPoint(point)); 103 Point p(ToTextPoint(point));
95 104
96 // When the point is outside of text, return HOME/END position. 105 // When the point is outside of text, return HOME/END position.
97 if (p.x() < 0) 106 if (p.x() < 0)
98 return EdgeSelectionModel(CURSOR_LEFT); 107 return EdgeSelectionModel(CURSOR_LEFT);
99 else if (p.x() > GetStringWidth()) 108 else if (p.x() > GetStringSize().width())
100 return EdgeSelectionModel(CURSOR_RIGHT); 109 return EdgeSelectionModel(CURSOR_RIGHT);
101 110
102 int caret_pos, trailing; 111 int caret_pos, trailing;
103 pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, 112 pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE,
104 &caret_pos, &trailing); 113 &caret_pos, &trailing);
105 114
106 size_t selection_end = caret_pos; 115 DCHECK(trailing >= 0);
msw 2012/02/16 00:09:21 Use DCHECK_GE.
107 if (trailing > 0) { 116 if (trailing) {
msw 2012/02/16 00:09:21 Why remove the explicit check for "> 0"?
benrg 2012/02/16 09:20:55 No reason. Reverted.
108 const char* ch = g_utf8_offset_to_pointer(layout_text_ + caret_pos, 117 caret_pos = g_utf8_offset_to_pointer(layout_text_ + caret_pos,
109 trailing); 118 trailing) - layout_text_;
110 DCHECK_GE(ch, layout_text_); 119 DCHECK_LE(static_cast<size_t>(caret_pos), layout_text_len_);
111 DCHECK_LE(ch, layout_text_ + layout_text_len_);
112 selection_end = ch - layout_text_;
113 } 120 }
114 121
115 return SelectionModel( 122 return SelectionModel(
116 Utf8IndexToUtf16Index(selection_end),
117 Utf8IndexToUtf16Index(caret_pos), 123 Utf8IndexToUtf16Index(caret_pos),
msw 2012/02/16 00:09:21 nit: move to the line above and fix the next line'
118 trailing > 0 ? SelectionModel::TRAILING : SelectionModel::LEADING); 124 trailing ? CURSOR_BACKWARD : CURSOR_FORWARD);
xji 2012/02/16 02:38:29 "trailing > 0" here too.
119 } 125 }
120 126
121 Rect RenderTextLinux::GetCursorBounds(const SelectionModel& selection,
122 bool insert_mode) {
123 EnsureLayout();
124
125 size_t caret_pos = insert_mode ? selection.caret_pos() :
126 selection.selection_end();
127 PangoRectangle pos;
128 pango_layout_index_to_pos(layout_, Utf16IndexToUtf8Index(caret_pos), &pos);
129
130 SelectionModel::CaretPlacement caret_placement = selection.caret_placement();
131 int x = pos.x;
132 if ((insert_mode && caret_placement == SelectionModel::TRAILING) ||
133 (!insert_mode && pos.width < 0))
134 x += pos.width;
135 x = PANGO_PIXELS(x);
136
137 int h = std::min(display_rect().height(), PANGO_PIXELS(pos.height));
138 Rect bounds(x, (display_rect().height() - h) / 2, 0, h);
139 bounds.set_origin(ToViewPoint(bounds.origin()));
140
141 if (!insert_mode)
142 bounds.set_width(PANGO_PIXELS(std::abs(pos.width)));
143
144 return bounds;
145 }
146
147 // Assume caret_pos in |current| is n, 'l' represents leading in
148 // caret_placement and 't' represents trailing in caret_placement. Following
149 // is the calculation from (caret_pos, caret_placement) in |current| to
150 // (selection_end, caret_pos, caret_placement) when moving cursor left/right by
151 // one grapheme (for simplicity, assume each grapheme is one character).
152 // If n is in LTR (if moving left) or RTL (if moving right) run,
153 // (n, t) --> (n, n, l).
154 // (n, l) --> (n-1, n-1, l) if n is inside run (not at boundary).
155 // (n, l) --> goto across run case if n is at run boundary.
156 // Otherwise,
157 // (n, l) --> (n+1, n, t).
158 // (n, t) --> (n+2, n+1, t) if n is inside run.
159 // (n, t) --> goto across run case if n is at run boundary.
160 // If n is at run boundary, get its visually left/right run,
161 // If left/right run is LTR/RTL run,
162 // (n, t) --> (left/right run's end, left/right run's end, l).
163 // Otherwise,
164 // (n, t) --> (left/right run's begin + 1, left/right run's begin, t).
165 SelectionModel RenderTextLinux::AdjacentCharSelectionModel( 127 SelectionModel RenderTextLinux::AdjacentCharSelectionModel(
166 const SelectionModel& selection, 128 const SelectionModel& selection,
167 VisualCursorDirection direction) { 129 VisualCursorDirection direction) {
168 size_t caret = selection.caret_pos(); 130 size_t caret = selection.caret_pos();
169 SelectionModel::CaretPlacement caret_placement = selection.caret_placement();
170 GSList* run = GetRunContainingPosition(caret);
171 DCHECK(run);
172 131
173 PangoLayoutRun* layout_run = reinterpret_cast<PangoLayoutRun*>(run->data); 132 GSList* run = GetRunContainingCaret(selection);
174 PangoItem* item = layout_run->item; 133 if (!run) {
175 size_t run_start = Utf8IndexToUtf16Index(item->offset); 134 // Cursor not in any run: we're at the visual & logical edge.
msw 2012/02/16 00:09:21 grammar nit: "The cursor is not". Also, use "and"
176 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); 135 SelectionModel edge = EdgeSelectionModel(direction);
177 136 if (text().empty() ||
178 if (!IsForwardMotion(direction, item)) { 137 edge == SelectionModel(caret, selection.caret_affinity()))
msw 2012/02/16 00:09:21 Use |selection| instead of constructing an identic
benrg 2012/02/16 09:20:55 It's not identical since |selection| might have a
179 if (caret_placement == SelectionModel::TRAILING) 138 return edge;
180 return SelectionModel(caret, caret, SelectionModel::LEADING); 139 else if (direction == CURSOR_RIGHT)
xji 2012/02/16 02:38:29 why need to check the condition at line 136/137? a
benrg 2012/02/16 09:20:55 if (!run) then the caret is either at (0, backward
xji 2012/02/16 19:52:55 Ha, I realized that. Thanks for the explanation.
181 else if (caret > run_start) { 140 run = current_line_->runs;
182 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); 141 else
183 return SelectionModel(caret, caret, SelectionModel::LEADING); 142 run = g_slist_last(current_line_->runs);
143 } else {
144 // If the cursor is moving within the current run, just move it by one
145 // grapheme in the appropriate direction.
146 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item;
147 if (IsForwardMotion(direction, item)) {
148 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length);
149 if (caret < run_end) {
msw 2012/02/16 00:09:21 nit: inline the |run_end| value calc here.
150 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
151 return SelectionModel(caret, CURSOR_BACKWARD);
152 }
153 } else {
154 size_t run_start = Utf8IndexToUtf16Index(item->offset);
155 if (caret > run_start) {
msw 2012/02/16 00:09:21 nit: inline the |run_start| value calc here and us
benrg 2012/02/16 09:20:55 The then and else clauses here are mirror images.
156 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD);
157 return SelectionModel(caret, CURSOR_FORWARD);
158 }
184 } 159 }
185 } else { 160 // The cursor is at the edge of a run; move to the visually adjacent run.
186 if (caret_placement == SelectionModel::LEADING) { 161 // TODO(xji): Keep a vector of runs to avoid using a singly-linked list.
187 size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); 162 run = (direction == CURSOR_RIGHT) ?
188 return SelectionModel(cursor, caret, SelectionModel::TRAILING); 163 run->next : GSListPrevious(current_line_->runs, run);
189 } else if (selection.selection_end() < run_end) { 164 if (!run)
190 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); 165 return EdgeSelectionModel(direction);
191 size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
192 return SelectionModel(cursor, caret, SelectionModel::TRAILING);
193 }
194 } 166 }
195 167 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item;
196 // The character is at the edge of its run; advance to the adjacent visual
197 // run.
198 // TODO(xji): Keep a vector of runs to avoid using a singly-linked list.
199 GSList* adjacent_run = (direction == CURSOR_RIGHT) ?
200 run->next : GSListPrevious(current_line_->runs, run);
201 if (!adjacent_run)
202 return EdgeSelectionModel(direction);
203
204 item = reinterpret_cast<PangoLayoutRun*>(adjacent_run->data)->item;
205 return IsForwardMotion(direction, item) ? 168 return IsForwardMotion(direction, item) ?
206 FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); 169 FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item);
207 } 170 }
208 171
209 SelectionModel RenderTextLinux::AdjacentWordSelectionModel( 172 SelectionModel RenderTextLinux::AdjacentWordSelectionModel(
210 const SelectionModel& selection, 173 const SelectionModel& selection,
211 VisualCursorDirection direction) { 174 VisualCursorDirection direction) {
212 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 175 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
213 bool success = iter.Init(); 176 bool success = iter.Init();
214 DCHECK(success); 177 DCHECK(success);
215 if (!success) 178 if (!success)
216 return selection; 179 return selection;
217 180
218 SelectionModel end = EdgeSelectionModel(direction);
219 SelectionModel cur(selection); 181 SelectionModel cur(selection);
220 while (!cur.Equals(end)) { 182 for (;;) {
221 cur = AdjacentCharSelectionModel(cur, direction); 183 cur = AdjacentCharSelectionModel(cur, direction);
222 size_t caret = cur.caret_pos(); 184 GSList* run = GetRunContainingCaret(cur);
223 GSList* run = GetRunContainingPosition(caret); 185 if (!run)
224 DCHECK(run); 186 break;
225 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; 187 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item;
226 size_t cursor = cur.selection_end(); 188 size_t cursor = cur.caret_pos();
227 if (IsForwardMotion(direction, item) ? 189 if (IsForwardMotion(direction, item) ?
228 iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) 190 iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor))
229 return cur; 191 break;
230 } 192 }
231 193
232 return end; 194 return cur;
233 }
234
235 SelectionModel RenderTextLinux::EdgeSelectionModel(
236 VisualCursorDirection direction) {
237 if (direction == GetVisualDirectionOfLogicalEnd()) {
238 // Advance to the logical end of the text.
239 GSList* run = current_line_->runs;
240 if (direction == CURSOR_RIGHT)
241 run = g_slist_last(run);
242 if (run) {
243 PangoLayoutRun* end_run = reinterpret_cast<PangoLayoutRun*>(run->data);
244 PangoItem* item = end_run->item;
245 if (IsForwardMotion(direction, item)) {
246 size_t caret = Utf8IndexToUtf16Index(
247 Utf8IndexOfAdjacentGrapheme(item->offset + item->length,
248 CURSOR_BACKWARD));
249 return SelectionModel(text().length(), caret, SelectionModel::TRAILING);
250 } else {
251 size_t caret = Utf8IndexToUtf16Index(item->offset);
252 return SelectionModel(text().length(), caret, SelectionModel::LEADING);
253 }
254 }
255 }
256 return SelectionModel(0, 0, SelectionModel::LEADING);
257 } 195 }
258 196
259 void RenderTextLinux::SetSelectionModel(const SelectionModel& model) { 197 void RenderTextLinux::SetSelectionModel(const SelectionModel& model) {
260 if (GetSelectionStart() != model.selection_start() || 198 if (selection() != model.selection())
261 GetCursorPosition() != model.selection_end()) {
262 selection_visual_bounds_.clear(); 199 selection_visual_bounds_.clear();
263 }
264 200
265 RenderText::SetSelectionModel(model); 201 RenderText::SetSelectionModel(model);
266 } 202 }
267 203
268 std::vector<Rect> RenderTextLinux::GetSubstringBounds(size_t from, size_t to) { 204 std::vector<Rect> RenderTextLinux::GetSubstringBounds(ui::Range range) {
269 DCHECK(from <= text().length()); 205 DCHECK(range.GetMax() <= text().length());
msw 2012/02/16 00:09:21 DCHECK_LE
270 DCHECK(to <= text().length());
271 206
272 if (from == to) 207 if (range.is_empty())
273 return std::vector<Rect>(); 208 return std::vector<Rect>();
274 209
275 EnsureLayout(); 210 EnsureLayout();
276 211
277 if (from == GetSelectionStart() && to == GetCursorPosition()) 212 if (range == selection())
278 return GetSelectionBounds(); 213 return GetSelectionBounds();
279 else 214 else
280 return CalculateSubstringBounds(from, to); 215 return CalculateSubstringBounds(range);
msw 2012/02/16 00:09:21 Move this return out of the else block.
281 } 216 }
282 217
283 bool RenderTextLinux::IsCursorablePosition(size_t position) { 218 bool RenderTextLinux::IsCursorablePosition(size_t position) {
284 if (position == 0 && text().empty()) 219 if (position == 0 && text().empty())
285 return true; 220 return true;
286 221
287 EnsureLayout(); 222 EnsureLayout();
288 return (position < static_cast<size_t>(num_log_attrs_) && 223 return (position < static_cast<size_t>(num_log_attrs_) &&
289 log_attrs_[position].is_cursor_position); 224 log_attrs_[position].is_cursor_position);
290 } 225 }
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 size_t RenderTextLinux::IndexOfAdjacentGrapheme( 401 size_t RenderTextLinux::IndexOfAdjacentGrapheme(
467 size_t index, 402 size_t index,
468 LogicalCursorDirection direction) { 403 LogicalCursorDirection direction) {
469 if (index > text().length()) 404 if (index > text().length())
470 return text().length(); 405 return text().length();
471 EnsureLayout(); 406 EnsureLayout();
472 return Utf8IndexToUtf16Index( 407 return Utf8IndexToUtf16Index(
473 Utf8IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), direction)); 408 Utf8IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), direction));
474 } 409 }
475 410
476 GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { 411 GSList* RenderTextLinux::GetRunContainingCaret(
412 const SelectionModel& caret) const {
413 size_t position = Utf16IndexToUtf8Index(caret.caret_pos());
414 LogicalCursorDirection affinity = caret.caret_affinity();
477 GSList* run = current_line_->runs; 415 GSList* run = current_line_->runs;
478 while (run) { 416 while (run) {
479 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; 417 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item;
480 size_t run_start = Utf8IndexToUtf16Index(item->offset); 418 if (RangeContainsCaret(ui::Range(item->offset, item->offset + item->length),
xji 2012/02/16 02:38:29 hm... what happens if you continuously press left/
xji 2012/02/16 02:40:51 forgot to update the comment. It is handled in mov
481 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); 419 position, affinity))
482
483 if (position >= run_start && position < run_end)
484 return run; 420 return run;
485 run = run->next; 421 run = run->next;
486 } 422 }
487 return NULL; 423 return NULL;
488 } 424 }
489 425
490 size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( 426 size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme(
491 size_t utf8_index_of_current_grapheme, 427 size_t utf8_index_of_current_grapheme,
492 LogicalCursorDirection direction) const { 428 LogicalCursorDirection direction) const {
493 const char* ch = layout_text_ + utf8_index_of_current_grapheme; 429 const char* ch = layout_text_ + utf8_index_of_current_grapheme;
(...skipping 14 matching lines...) Expand all
508 !log_attrs_[char_offset].is_cursor_position); 444 !log_attrs_[char_offset].is_cursor_position);
509 } 445 }
510 } 446 }
511 447
512 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); 448 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset);
513 return static_cast<size_t>(ch - layout_text_); 449 return static_cast<size_t>(ch - layout_text_);
514 } 450 }
515 451
516 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( 452 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun(
517 const PangoItem* item) const { 453 const PangoItem* item) const {
518 size_t caret = Utf8IndexToUtf16Index(item->offset);
519 size_t cursor = Utf8IndexToUtf16Index( 454 size_t cursor = Utf8IndexToUtf16Index(
520 Utf8IndexOfAdjacentGrapheme(item->offset, CURSOR_FORWARD)); 455 Utf8IndexOfAdjacentGrapheme(item->offset, CURSOR_FORWARD));
521 return SelectionModel(cursor, caret, SelectionModel::TRAILING); 456 return SelectionModel(cursor, CURSOR_BACKWARD);
522 } 457 }
523 458
524 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( 459 SelectionModel RenderTextLinux::LastSelectionModelInsideRun(
525 const PangoItem* item) const { 460 const PangoItem* item) const {
526 size_t caret = Utf8IndexToUtf16Index(Utf8IndexOfAdjacentGrapheme( 461 size_t caret = Utf8IndexToUtf16Index(Utf8IndexOfAdjacentGrapheme(
527 item->offset + item->length, CURSOR_BACKWARD)); 462 item->offset + item->length, CURSOR_BACKWARD));
528 return SelectionModel(caret, caret, SelectionModel::LEADING); 463 return SelectionModel(caret, CURSOR_FORWARD);
529 } 464 }
530 465
531 void RenderTextLinux::ResetLayout() { 466 void RenderTextLinux::ResetLayout() {
532 // set_cached_bounds_and_offset_valid(false) is done in RenderText for every 467 // set_cached_bounds_and_offset_valid(false) is done in RenderText for every
533 // operation that triggers ResetLayout(). 468 // operation that triggers ResetLayout().
534 if (layout_) { 469 if (layout_) {
535 g_object_unref(layout_); 470 g_object_unref(layout_);
536 layout_ = NULL; 471 layout_ = NULL;
537 } 472 }
538 if (current_line_) { 473 if (current_line_) {
(...skipping 29 matching lines...) Expand all
568 503
569 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { 504 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const {
570 int32_t utf16_index = 0; 505 int32_t utf16_index = 0;
571 UErrorCode ec = U_ZERO_ERROR; 506 UErrorCode ec = U_ZERO_ERROR;
572 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); 507 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec);
573 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || 508 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR ||
574 ec == U_STRING_NOT_TERMINATED_WARNING); 509 ec == U_STRING_NOT_TERMINATED_WARNING);
575 return utf16_index; 510 return utf16_index;
576 } 511 }
577 512
578 std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(size_t from, 513 std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(ui::Range range) {
579 size_t to) {
580 int* ranges; 514 int* ranges;
581 int n_ranges; 515 int n_ranges;
582 size_t from_in_utf8 = Utf16IndexToUtf8Index(from);
583 size_t to_in_utf8 = Utf16IndexToUtf8Index(to);
584 pango_layout_line_get_x_ranges( 516 pango_layout_line_get_x_ranges(
585 current_line_, 517 current_line_,
586 std::min(from_in_utf8, to_in_utf8), 518 Utf16IndexToUtf8Index(range.GetMin()),
587 std::max(from_in_utf8, to_in_utf8), 519 Utf16IndexToUtf8Index(range.GetMax()),
588 &ranges, 520 &ranges,
589 &n_ranges); 521 &n_ranges);
590 522
591 int height; 523 int height;
592 pango_layout_get_pixel_size(layout_, NULL, &height); 524 pango_layout_get_pixel_size(layout_, NULL, &height);
593 525
594 int y = (display_rect().height() - height) / 2; 526 int y = (display_rect().height() - height) / 2;
595 527
596 std::vector<Rect> bounds; 528 std::vector<Rect> bounds;
597 for (int i = 0; i < n_ranges; ++i) { 529 for (int i = 0; i < n_ranges; ++i) {
598 int x = PANGO_PIXELS(ranges[2 * i]); 530 int x = PANGO_PIXELS(ranges[2 * i]);
599 int width = PANGO_PIXELS(ranges[2 * i + 1]) - x; 531 int width = PANGO_PIXELS(ranges[2 * i + 1]) - x;
600 Rect rect(x, y, width, height); 532 Rect rect(x, y, width, height);
601 rect.set_origin(ToViewPoint(rect.origin())); 533 rect.set_origin(ToViewPoint(rect.origin()));
602 bounds.push_back(rect); 534 bounds.push_back(rect);
603 } 535 }
604 g_free(ranges); 536 g_free(ranges);
605 return bounds; 537 return bounds;
606 } 538 }
607 539
608 std::vector<Rect> RenderTextLinux::GetSelectionBounds() { 540 std::vector<Rect> RenderTextLinux::GetSelectionBounds() {
609 if (selection_visual_bounds_.empty()) 541 if (selection_visual_bounds_.empty())
610 selection_visual_bounds_ = 542 selection_visual_bounds_ = CalculateSubstringBounds(selection());
611 CalculateSubstringBounds(GetSelectionStart(), GetCursorPosition());
612 return selection_visual_bounds_; 543 return selection_visual_bounds_;
613 } 544 }
614 545
615 } // namespace gfx 546 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698