OLD | NEW |
---|---|
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 Loading... | |
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; |
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); |
107 if (trailing > 0) { | 116 if (trailing) { |
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), |
118 trailing > 0 ? SelectionModel::TRAILING : SelectionModel::LEADING); | 124 trailing ? CURSOR_BACKWARD : CURSOR_FORWARD); |
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. |
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())) |
179 if (caret_placement == SelectionModel::TRAILING) | 138 return edge; |
180 return SelectionModel(caret, caret, SelectionModel::LEADING); | 139 else if (direction == CURSOR_RIGHT) |
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) { | |
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) { | |
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()); |
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); |
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 Loading... | |
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 // NB: exploits unsigned wraparound (0 - 1) | |
Alexei Svitkine (slow)
2012/02/14 20:16:31
This is undefined behavior per the C++ standard, s
benrg
2012/02/14 23:39:02
Only signed arithmetic overflow is undefined. Unsi
| |
415 ui::Range pos(position, caret.caret_affinity() == CURSOR_BACKWARD ? | |
416 position - 1 : position + 1); | |
477 GSList* run = current_line_->runs; | 417 GSList* run = current_line_->runs; |
478 while (run) { | 418 while (run) { |
479 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; | 419 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
480 size_t run_start = Utf8IndexToUtf16Index(item->offset); | 420 if (ui::Range(item->offset, item->offset + item->length).Contains(pos)) |
481 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); | |
482 | |
483 if (position >= run_start && position < run_end) | |
484 return run; | 421 return run; |
485 run = run->next; | 422 run = run->next; |
486 } | 423 } |
487 return NULL; | 424 return NULL; |
488 } | 425 } |
489 | 426 |
490 size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( | 427 size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( |
491 size_t utf8_index_of_current_grapheme, | 428 size_t utf8_index_of_current_grapheme, |
492 LogicalCursorDirection direction) const { | 429 LogicalCursorDirection direction) const { |
493 const char* ch = layout_text_ + utf8_index_of_current_grapheme; | 430 const char* ch = layout_text_ + utf8_index_of_current_grapheme; |
(...skipping 14 matching lines...) Expand all Loading... | |
508 !log_attrs_[char_offset].is_cursor_position); | 445 !log_attrs_[char_offset].is_cursor_position); |
509 } | 446 } |
510 } | 447 } |
511 | 448 |
512 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); | 449 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); |
513 return static_cast<size_t>(ch - layout_text_); | 450 return static_cast<size_t>(ch - layout_text_); |
514 } | 451 } |
515 | 452 |
516 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( | 453 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( |
517 const PangoItem* item) const { | 454 const PangoItem* item) const { |
518 size_t caret = Utf8IndexToUtf16Index(item->offset); | |
519 size_t cursor = Utf8IndexToUtf16Index( | 455 size_t cursor = Utf8IndexToUtf16Index( |
520 Utf8IndexOfAdjacentGrapheme(item->offset, CURSOR_FORWARD)); | 456 Utf8IndexOfAdjacentGrapheme(item->offset, CURSOR_FORWARD)); |
521 return SelectionModel(cursor, caret, SelectionModel::TRAILING); | 457 return SelectionModel(cursor, CURSOR_BACKWARD); |
522 } | 458 } |
523 | 459 |
524 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( | 460 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( |
525 const PangoItem* item) const { | 461 const PangoItem* item) const { |
526 size_t caret = Utf8IndexToUtf16Index(Utf8IndexOfAdjacentGrapheme( | 462 size_t caret = Utf8IndexToUtf16Index(Utf8IndexOfAdjacentGrapheme( |
527 item->offset + item->length, CURSOR_BACKWARD)); | 463 item->offset + item->length, CURSOR_BACKWARD)); |
528 return SelectionModel(caret, caret, SelectionModel::LEADING); | 464 return SelectionModel(caret, CURSOR_FORWARD); |
529 } | 465 } |
530 | 466 |
531 void RenderTextLinux::ResetLayout() { | 467 void RenderTextLinux::ResetLayout() { |
532 // set_cached_bounds_and_offset_valid(false) is done in RenderText for every | 468 // set_cached_bounds_and_offset_valid(false) is done in RenderText for every |
533 // operation that triggers ResetLayout(). | 469 // operation that triggers ResetLayout(). |
534 if (layout_) { | 470 if (layout_) { |
535 g_object_unref(layout_); | 471 g_object_unref(layout_); |
536 layout_ = NULL; | 472 layout_ = NULL; |
537 } | 473 } |
538 if (current_line_) { | 474 if (current_line_) { |
(...skipping 29 matching lines...) Expand all Loading... | |
568 | 504 |
569 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { | 505 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { |
570 int32_t utf16_index = 0; | 506 int32_t utf16_index = 0; |
571 UErrorCode ec = U_ZERO_ERROR; | 507 UErrorCode ec = U_ZERO_ERROR; |
572 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); | 508 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); |
573 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || | 509 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || |
574 ec == U_STRING_NOT_TERMINATED_WARNING); | 510 ec == U_STRING_NOT_TERMINATED_WARNING); |
575 return utf16_index; | 511 return utf16_index; |
576 } | 512 } |
577 | 513 |
578 std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(size_t from, | 514 std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(ui::Range range) { |
579 size_t to) { | |
580 int* ranges; | 515 int* ranges; |
581 int n_ranges; | 516 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( | 517 pango_layout_line_get_x_ranges( |
585 current_line_, | 518 current_line_, |
586 std::min(from_in_utf8, to_in_utf8), | 519 Utf16IndexToUtf8Index(range.GetMin()), |
587 std::max(from_in_utf8, to_in_utf8), | 520 Utf16IndexToUtf8Index(range.GetMax()), |
588 &ranges, | 521 &ranges, |
589 &n_ranges); | 522 &n_ranges); |
590 | 523 |
591 int height; | 524 int height; |
592 pango_layout_get_pixel_size(layout_, NULL, &height); | 525 pango_layout_get_pixel_size(layout_, NULL, &height); |
593 | 526 |
594 int y = (display_rect().height() - height) / 2; | 527 int y = (display_rect().height() - height) / 2; |
595 | 528 |
596 std::vector<Rect> bounds; | 529 std::vector<Rect> bounds; |
597 for (int i = 0; i < n_ranges; ++i) { | 530 for (int i = 0; i < n_ranges; ++i) { |
598 int x = PANGO_PIXELS(ranges[2 * i]); | 531 int x = PANGO_PIXELS(ranges[2 * i]); |
599 int width = PANGO_PIXELS(ranges[2 * i + 1]) - x; | 532 int width = PANGO_PIXELS(ranges[2 * i + 1]) - x; |
600 Rect rect(x, y, width, height); | 533 Rect rect(x, y, width, height); |
601 rect.set_origin(ToViewPoint(rect.origin())); | 534 rect.set_origin(ToViewPoint(rect.origin())); |
602 bounds.push_back(rect); | 535 bounds.push_back(rect); |
603 } | 536 } |
604 g_free(ranges); | 537 g_free(ranges); |
605 return bounds; | 538 return bounds; |
606 } | 539 } |
607 | 540 |
608 std::vector<Rect> RenderTextLinux::GetSelectionBounds() { | 541 std::vector<Rect> RenderTextLinux::GetSelectionBounds() { |
609 if (selection_visual_bounds_.empty()) | 542 if (selection_visual_bounds_.empty()) |
610 selection_visual_bounds_ = | 543 selection_visual_bounds_ = CalculateSubstringBounds(selection()); |
611 CalculateSubstringBounds(GetSelectionStart(), GetCursorPosition()); | |
612 return selection_visual_bounds_; | 544 return selection_visual_bounds_; |
613 } | 545 } |
614 | 546 |
615 } // namespace gfx | 547 } // namespace gfx |
OLD | NEW |