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 = 0, height = 0; |
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 } | 86 } |
87 | 87 |
88 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { | 88 SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { |
89 EnsureLayout(); | 89 EnsureLayout(); |
90 | 90 |
91 if (text().empty()) | 91 if (text().empty()) |
92 return SelectionModel(0, 0, SelectionModel::LEADING); | 92 return SelectionModel(0, CURSOR_FORWARD); |
93 | 93 |
94 Point p(ToTextPoint(point)); | 94 Point p(ToTextPoint(point)); |
95 | 95 |
96 // When the point is outside of text, return HOME/END position. | 96 // When the point is outside of text, return HOME/END position. |
97 if (p.x() < 0) | 97 if (p.x() < 0) |
98 return EdgeSelectionModel(CURSOR_LEFT); | 98 return EdgeSelectionModel(CURSOR_LEFT); |
99 else if (p.x() > GetStringWidth()) | 99 else if (p.x() > GetStringSize().width()) |
100 return EdgeSelectionModel(CURSOR_RIGHT); | 100 return EdgeSelectionModel(CURSOR_RIGHT); |
101 | 101 |
102 int caret_pos, trailing; | 102 int caret_pos, trailing; |
msw
2012/02/28 22:51:32
Init these locals to 0.
benrg
2012/03/07 01:04:44
Done (under protest -- though I don't feel all tha
| |
103 pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, | 103 pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, |
104 &caret_pos, &trailing); | 104 &caret_pos, &trailing); |
105 | 105 |
106 size_t selection_end = caret_pos; | 106 DCHECK_GE(trailing, 0); |
107 if (trailing > 0) { | 107 if (trailing > 0) { |
108 const char* ch = g_utf8_offset_to_pointer(layout_text_ + caret_pos, | 108 caret_pos = g_utf8_offset_to_pointer(layout_text_ + caret_pos, |
109 trailing); | 109 trailing) - layout_text_; |
110 DCHECK_GE(ch, layout_text_); | 110 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 } | 111 } |
114 | 112 |
115 return SelectionModel( | 113 return SelectionModel(Utf8IndexToUtf16Index(caret_pos), |
116 Utf8IndexToUtf16Index(selection_end), | 114 (trailing > 0) ? CURSOR_BACKWARD : CURSOR_FORWARD); |
117 Utf8IndexToUtf16Index(caret_pos), | |
118 trailing > 0 ? SelectionModel::TRAILING : SelectionModel::LEADING); | |
119 } | 115 } |
120 | 116 |
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( | 117 SelectionModel RenderTextLinux::AdjacentCharSelectionModel( |
166 const SelectionModel& selection, | 118 const SelectionModel& selection, |
167 VisualCursorDirection direction) { | 119 VisualCursorDirection direction) { |
168 size_t caret = selection.caret_pos(); | 120 GSList* run = GetRunContainingCaret(selection); |
169 SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); | 121 if (!run) { |
170 GSList* run = GetRunContainingPosition(caret); | 122 // The cursor is not in any run: we're at the visual and logical edge. |
171 DCHECK(run); | 123 SelectionModel edge = EdgeSelectionModel(direction); |
172 | 124 if (edge.caret_pos() == selection.caret_pos()) |
173 PangoLayoutRun* layout_run = reinterpret_cast<PangoLayoutRun*>(run->data); | 125 return edge; |
174 PangoItem* item = layout_run->item; | 126 else |
175 size_t run_start = Utf8IndexToUtf16Index(item->offset); | 127 run = (direction == CURSOR_RIGHT) ? |
176 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); | 128 current_line_->runs : g_slist_last(current_line_->runs); |
177 | 129 } else { |
178 if (!IsForwardMotion(direction, item)) { | 130 // If the cursor is moving within the current run, just move it by one |
179 if (caret_placement == SelectionModel::TRAILING) | 131 // grapheme in the appropriate direction. |
180 return SelectionModel(caret, caret, SelectionModel::LEADING); | 132 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
181 else if (caret > run_start) { | 133 size_t caret = selection.caret_pos(); |
182 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); | 134 if (IsForwardMotion(direction, item)) { |
183 return SelectionModel(caret, caret, SelectionModel::LEADING); | 135 if (caret < Utf8IndexToUtf16Index(item->offset + item->length)) { |
136 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | |
137 return SelectionModel(caret, CURSOR_BACKWARD); | |
138 } | |
139 } else { | |
140 if (caret > Utf8IndexToUtf16Index(item->offset)) { | |
141 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); | |
142 return SelectionModel(caret, CURSOR_FORWARD); | |
143 } | |
184 } | 144 } |
185 } else { | 145 // The cursor is at the edge of a run; move to the visually adjacent run. |
186 if (caret_placement == SelectionModel::LEADING) { | 146 // TODO(xji): Keep a vector of runs to avoid using a singly-linked list. |
187 size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | 147 run = (direction == CURSOR_RIGHT) ? |
188 return SelectionModel(cursor, caret, SelectionModel::TRAILING); | 148 run->next : GSListPrevious(current_line_->runs, run); |
189 } else if (selection.selection_end() < run_end) { | 149 if (!run) |
190 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | 150 return EdgeSelectionModel(direction); |
191 size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | |
192 return SelectionModel(cursor, caret, SelectionModel::TRAILING); | |
193 } | |
194 } | 151 } |
195 | 152 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) ? | 153 return IsForwardMotion(direction, item) ? |
206 FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); | 154 FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); |
207 } | 155 } |
208 | 156 |
209 SelectionModel RenderTextLinux::AdjacentWordSelectionModel( | 157 SelectionModel RenderTextLinux::AdjacentWordSelectionModel( |
210 const SelectionModel& selection, | 158 const SelectionModel& selection, |
211 VisualCursorDirection direction) { | 159 VisualCursorDirection direction) { |
212 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | 160 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
213 bool success = iter.Init(); | 161 bool success = iter.Init(); |
214 DCHECK(success); | 162 DCHECK(success); |
215 if (!success) | 163 if (!success) |
216 return selection; | 164 return selection; |
217 | 165 |
218 SelectionModel end = EdgeSelectionModel(direction); | |
219 SelectionModel cur(selection); | 166 SelectionModel cur(selection); |
220 while (!cur.Equals(end)) { | 167 for (;;) { |
221 cur = AdjacentCharSelectionModel(cur, direction); | 168 cur = AdjacentCharSelectionModel(cur, direction); |
222 size_t caret = cur.caret_pos(); | 169 GSList* run = GetRunContainingCaret(cur); |
223 GSList* run = GetRunContainingPosition(caret); | 170 if (!run) |
224 DCHECK(run); | 171 break; |
225 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; | 172 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
226 size_t cursor = cur.selection_end(); | 173 size_t cursor = cur.caret_pos(); |
227 if (IsForwardMotion(direction, item) ? | 174 if (IsForwardMotion(direction, item) ? |
228 iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) | 175 iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) |
229 return cur; | 176 break; |
230 } | 177 } |
231 | 178 |
232 return end; | 179 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 } | 180 } |
258 | 181 |
259 void RenderTextLinux::SetSelectionModel(const SelectionModel& model) { | 182 void RenderTextLinux::SetSelectionModel(const SelectionModel& model) { |
260 if (GetSelectionStart() != model.selection_start() || | 183 if (selection() != model.selection()) |
261 GetCursorPosition() != model.selection_end()) { | |
262 selection_visual_bounds_.clear(); | 184 selection_visual_bounds_.clear(); |
263 } | |
264 | 185 |
265 RenderText::SetSelectionModel(model); | 186 RenderText::SetSelectionModel(model); |
266 } | 187 } |
267 | 188 |
268 std::vector<Rect> RenderTextLinux::GetSubstringBounds(size_t from, size_t to) { | 189 void RenderTextLinux::GetGlyphBounds(size_t index, |
269 DCHECK(from <= text().length()); | 190 ui::Range* xspan, |
270 DCHECK(to <= text().length()); | 191 int* height) { |
192 PangoRectangle pos; | |
193 pango_layout_index_to_pos(layout_, Utf16IndexToUtf8Index(index), &pos); | |
194 *xspan = ui::Range(PANGO_PIXELS(pos.x), PANGO_PIXELS(pos.x + pos.width)); | |
195 *height = PANGO_PIXELS(pos.height); | |
196 } | |
271 | 197 |
272 if (from == to) | 198 std::vector<Rect> RenderTextLinux::GetSubstringBounds(ui::Range range) { |
199 DCHECK_LE(range.GetMax(), text().length()); | |
200 | |
201 if (range.is_empty()) | |
273 return std::vector<Rect>(); | 202 return std::vector<Rect>(); |
274 | 203 |
275 EnsureLayout(); | 204 EnsureLayout(); |
276 | 205 if (range == selection()) |
277 if (from == GetSelectionStart() && to == GetCursorPosition()) | |
278 return GetSelectionBounds(); | 206 return GetSelectionBounds(); |
279 else | 207 return CalculateSubstringBounds(range); |
280 return CalculateSubstringBounds(from, to); | |
281 } | 208 } |
282 | 209 |
283 bool RenderTextLinux::IsCursorablePosition(size_t position) { | 210 bool RenderTextLinux::IsCursorablePosition(size_t position) { |
284 if (position == 0 && text().empty()) | 211 if (position == 0 && text().empty()) |
285 return true; | 212 return true; |
286 | 213 |
287 EnsureLayout(); | 214 EnsureLayout(); |
288 return (position < static_cast<size_t>(num_log_attrs_) && | 215 return (position < static_cast<size_t>(num_log_attrs_) && |
289 log_attrs_[position].is_cursor_position); | 216 log_attrs_[position].is_cursor_position); |
290 } | 217 } |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
466 size_t RenderTextLinux::IndexOfAdjacentGrapheme( | 393 size_t RenderTextLinux::IndexOfAdjacentGrapheme( |
467 size_t index, | 394 size_t index, |
468 LogicalCursorDirection direction) { | 395 LogicalCursorDirection direction) { |
469 if (index > text().length()) | 396 if (index > text().length()) |
470 return text().length(); | 397 return text().length(); |
471 EnsureLayout(); | 398 EnsureLayout(); |
472 return Utf8IndexToUtf16Index( | 399 return Utf8IndexToUtf16Index( |
473 Utf8IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), direction)); | 400 Utf8IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), direction)); |
474 } | 401 } |
475 | 402 |
476 GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { | 403 GSList* RenderTextLinux::GetRunContainingCaret( |
404 const SelectionModel& caret) const { | |
405 size_t position = Utf16IndexToUtf8Index(caret.caret_pos()); | |
406 LogicalCursorDirection affinity = caret.caret_affinity(); | |
477 GSList* run = current_line_->runs; | 407 GSList* run = current_line_->runs; |
478 while (run) { | 408 while (run) { |
479 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; | 409 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
480 size_t run_start = Utf8IndexToUtf16Index(item->offset); | 410 ui::Range item_range(item->offset, item->offset + item->length); |
481 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); | 411 if (RangeContainsCaret(item_range, position, affinity)) |
482 | |
483 if (position >= run_start && position < run_end) | |
484 return run; | 412 return run; |
485 run = run->next; | 413 run = run->next; |
486 } | 414 } |
487 return NULL; | 415 return NULL; |
488 } | 416 } |
489 | 417 |
490 size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( | 418 size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( |
491 size_t utf8_index_of_current_grapheme, | 419 size_t utf8_index_of_current_grapheme, |
492 LogicalCursorDirection direction) const { | 420 LogicalCursorDirection direction) const { |
493 const char* ch = layout_text_ + utf8_index_of_current_grapheme; | 421 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); | 436 !log_attrs_[char_offset].is_cursor_position); |
509 } | 437 } |
510 } | 438 } |
511 | 439 |
512 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); | 440 ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); |
513 return static_cast<size_t>(ch - layout_text_); | 441 return static_cast<size_t>(ch - layout_text_); |
514 } | 442 } |
515 | 443 |
516 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( | 444 SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( |
517 const PangoItem* item) const { | 445 const PangoItem* item) const { |
518 size_t caret = Utf8IndexToUtf16Index(item->offset); | |
519 size_t cursor = Utf8IndexToUtf16Index( | 446 size_t cursor = Utf8IndexToUtf16Index( |
520 Utf8IndexOfAdjacentGrapheme(item->offset, CURSOR_FORWARD)); | 447 Utf8IndexOfAdjacentGrapheme(item->offset, CURSOR_FORWARD)); |
521 return SelectionModel(cursor, caret, SelectionModel::TRAILING); | 448 return SelectionModel(cursor, CURSOR_BACKWARD); |
522 } | 449 } |
523 | 450 |
524 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( | 451 SelectionModel RenderTextLinux::LastSelectionModelInsideRun( |
525 const PangoItem* item) const { | 452 const PangoItem* item) const { |
526 size_t caret = Utf8IndexToUtf16Index(Utf8IndexOfAdjacentGrapheme( | 453 size_t caret = Utf8IndexToUtf16Index(Utf8IndexOfAdjacentGrapheme( |
527 item->offset + item->length, CURSOR_BACKWARD)); | 454 item->offset + item->length, CURSOR_BACKWARD)); |
528 return SelectionModel(caret, caret, SelectionModel::LEADING); | 455 return SelectionModel(caret, CURSOR_FORWARD); |
529 } | 456 } |
530 | 457 |
531 void RenderTextLinux::ResetLayout() { | 458 void RenderTextLinux::ResetLayout() { |
532 // set_cached_bounds_and_offset_valid(false) is done in RenderText for every | 459 // set_cached_bounds_and_offset_valid(false) is done in RenderText for every |
533 // operation that triggers ResetLayout(). | 460 // operation that triggers ResetLayout(). |
534 if (layout_) { | 461 if (layout_) { |
535 g_object_unref(layout_); | 462 g_object_unref(layout_); |
536 layout_ = NULL; | 463 layout_ = NULL; |
537 } | 464 } |
538 if (current_line_) { | 465 if (current_line_) { |
(...skipping 29 matching lines...) Expand all Loading... | |
568 | 495 |
569 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { | 496 size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { |
570 int32_t utf16_index = 0; | 497 int32_t utf16_index = 0; |
571 UErrorCode ec = U_ZERO_ERROR; | 498 UErrorCode ec = U_ZERO_ERROR; |
572 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); | 499 u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); |
573 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || | 500 DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || |
574 ec == U_STRING_NOT_TERMINATED_WARNING); | 501 ec == U_STRING_NOT_TERMINATED_WARNING); |
575 return utf16_index; | 502 return utf16_index; |
576 } | 503 } |
577 | 504 |
578 std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(size_t from, | 505 std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(ui::Range range) { |
579 size_t to) { | |
580 int* ranges; | 506 int* ranges; |
581 int n_ranges; | 507 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( | 508 pango_layout_line_get_x_ranges( |
585 current_line_, | 509 current_line_, |
586 std::min(from_in_utf8, to_in_utf8), | 510 Utf16IndexToUtf8Index(range.GetMin()), |
587 std::max(from_in_utf8, to_in_utf8), | 511 Utf16IndexToUtf8Index(range.GetMax()), |
588 &ranges, | 512 &ranges, |
589 &n_ranges); | 513 &n_ranges); |
590 | 514 |
591 int height; | 515 int height; |
592 pango_layout_get_pixel_size(layout_, NULL, &height); | 516 pango_layout_get_pixel_size(layout_, NULL, &height); |
593 | 517 |
594 int y = (display_rect().height() - height) / 2; | 518 int y = (display_rect().height() - height) / 2; |
595 | 519 |
596 std::vector<Rect> bounds; | 520 std::vector<Rect> bounds; |
597 for (int i = 0; i < n_ranges; ++i) { | 521 for (int i = 0; i < n_ranges; ++i) { |
598 int x = PANGO_PIXELS(ranges[2 * i]); | 522 int x = PANGO_PIXELS(ranges[2 * i]); |
599 int width = PANGO_PIXELS(ranges[2 * i + 1]) - x; | 523 int width = PANGO_PIXELS(ranges[2 * i + 1]) - x; |
600 Rect rect(x, y, width, height); | 524 Rect rect(x, y, width, height); |
601 rect.set_origin(ToViewPoint(rect.origin())); | 525 rect.set_origin(ToViewPoint(rect.origin())); |
602 bounds.push_back(rect); | 526 bounds.push_back(rect); |
603 } | 527 } |
604 g_free(ranges); | 528 g_free(ranges); |
605 return bounds; | 529 return bounds; |
606 } | 530 } |
607 | 531 |
608 std::vector<Rect> RenderTextLinux::GetSelectionBounds() { | 532 std::vector<Rect> RenderTextLinux::GetSelectionBounds() { |
609 if (selection_visual_bounds_.empty()) | 533 if (selection_visual_bounds_.empty()) |
610 selection_visual_bounds_ = | 534 selection_visual_bounds_ = CalculateSubstringBounds(selection()); |
611 CalculateSubstringBounds(GetSelectionStart(), GetCursorPosition()); | |
612 return selection_visual_bounds_; | 535 return selection_visual_bounds_; |
613 } | 536 } |
614 | 537 |
615 } // namespace gfx | 538 } // namespace gfx |
OLD | NEW |