Chromium Code Reviews| 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 |