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 = 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 } | |
| 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_GE(trailing, 0); |
| 107 if (trailing > 0) { | 116 if (trailing > 0) { |
| 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(Utf8IndexToUtf16Index(caret_pos), |
| 116 Utf8IndexToUtf16Index(selection_end), | 123 trailing > 0 ? CURSOR_BACKWARD : CURSOR_FORWARD); |
|
msw
2012/02/21 21:13:39
nit: Put parens around the condition here.
| |
| 117 Utf8IndexToUtf16Index(caret_pos), | |
| 118 trailing > 0 ? SelectionModel::TRAILING : SelectionModel::LEADING); | |
| 119 } | 124 } |
| 120 | 125 |
| 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( | 126 SelectionModel RenderTextLinux::AdjacentCharSelectionModel( |
| 166 const SelectionModel& selection, | 127 const SelectionModel& selection, |
| 167 VisualCursorDirection direction) { | 128 VisualCursorDirection direction) { |
| 168 size_t caret = selection.caret_pos(); | 129 GSList* run = GetRunContainingCaret(selection); |
| 169 SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); | 130 if (!run) { |
| 170 GSList* run = GetRunContainingPosition(caret); | 131 // The cursor is not in any run: we're at the visual and logical edge. |
| 171 DCHECK(run); | 132 SelectionModel edge = EdgeSelectionModel(direction); |
| 172 | 133 if (edge.caret_pos() == selection.caret_pos()) |
| 173 PangoLayoutRun* layout_run = reinterpret_cast<PangoLayoutRun*>(run->data); | 134 return edge; |
| 174 PangoItem* item = layout_run->item; | 135 else |
| 175 size_t run_start = Utf8IndexToUtf16Index(item->offset); | 136 run = direction == CURSOR_RIGHT ? |
|
msw
2012/02/21 21:13:39
nit: Put parens around the condition here.
| |
| 176 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); | 137 current_line_->runs : g_slist_last(current_line_->runs); |
| 177 | 138 } else { |
| 178 if (!IsForwardMotion(direction, item)) { | 139 // If the cursor is moving within the current run, just move it by one |
| 179 if (caret_placement == SelectionModel::TRAILING) | 140 // grapheme in the appropriate direction. |
| 180 return SelectionModel(caret, caret, SelectionModel::LEADING); | 141 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
| 181 else if (caret > run_start) { | 142 size_t caret = selection.caret_pos(); |
| 182 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); | 143 if (IsForwardMotion(direction, item)) { |
| 183 return SelectionModel(caret, caret, SelectionModel::LEADING); | 144 if (caret < Utf8IndexToUtf16Index(item->offset + item->length)) { |
| 145 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | |
| 146 return SelectionModel(caret, CURSOR_BACKWARD); | |
| 147 } | |
| 148 } else { | |
| 149 if (caret > Utf8IndexToUtf16Index(item->offset)) { | |
| 150 caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); | |
| 151 return SelectionModel(caret, CURSOR_FORWARD); | |
| 152 } | |
| 184 } | 153 } |
| 185 } else { | 154 // The cursor is at the edge of a run; move to the visually adjacent run. |
| 186 if (caret_placement == SelectionModel::LEADING) { | 155 // TODO(xji): Keep a vector of runs to avoid using a singly-linked list. |
| 187 size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | 156 run = (direction == CURSOR_RIGHT) ? |
| 188 return SelectionModel(cursor, caret, SelectionModel::TRAILING); | 157 run->next : GSListPrevious(current_line_->runs, run); |
| 189 } else if (selection.selection_end() < run_end) { | 158 if (!run) |
| 190 caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | 159 return EdgeSelectionModel(direction); |
| 191 size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); | |
| 192 return SelectionModel(cursor, caret, SelectionModel::TRAILING); | |
| 193 } | |
| 194 } | 160 } |
| 195 | 161 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) ? | 162 return IsForwardMotion(direction, item) ? |
| 206 FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); | 163 FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); |
| 207 } | 164 } |
| 208 | 165 |
| 209 SelectionModel RenderTextLinux::AdjacentWordSelectionModel( | 166 SelectionModel RenderTextLinux::AdjacentWordSelectionModel( |
| 210 const SelectionModel& selection, | 167 const SelectionModel& selection, |
| 211 VisualCursorDirection direction) { | 168 VisualCursorDirection direction) { |
| 212 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | 169 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
| 213 bool success = iter.Init(); | 170 bool success = iter.Init(); |
| 214 DCHECK(success); | 171 DCHECK(success); |
| 215 if (!success) | 172 if (!success) |
| 216 return selection; | 173 return selection; |
| 217 | 174 |
| 218 SelectionModel end = EdgeSelectionModel(direction); | |
| 219 SelectionModel cur(selection); | 175 SelectionModel cur(selection); |
| 220 while (!cur.Equals(end)) { | 176 for (;;) { |
| 221 cur = AdjacentCharSelectionModel(cur, direction); | 177 cur = AdjacentCharSelectionModel(cur, direction); |
| 222 size_t caret = cur.caret_pos(); | 178 GSList* run = GetRunContainingCaret(cur); |
| 223 GSList* run = GetRunContainingPosition(caret); | 179 if (!run) |
| 224 DCHECK(run); | 180 break; |
| 225 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; | 181 PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
| 226 size_t cursor = cur.selection_end(); | 182 size_t cursor = cur.caret_pos(); |
| 227 if (IsForwardMotion(direction, item) ? | 183 if (IsForwardMotion(direction, item) ? |
| 228 iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) | 184 iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) |
| 229 return cur; | 185 break; |
| 230 } | 186 } |
| 231 | 187 |
| 232 return end; | 188 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 } | 189 } |
| 258 | 190 |
| 259 void RenderTextLinux::SetSelectionModel(const SelectionModel& model) { | 191 void RenderTextLinux::SetSelectionModel(const SelectionModel& model) { |
| 260 if (GetSelectionStart() != model.selection_start() || | 192 if (selection() != model.selection()) |
| 261 GetCursorPosition() != model.selection_end()) { | |
| 262 selection_visual_bounds_.clear(); | 193 selection_visual_bounds_.clear(); |
| 263 } | |
| 264 | 194 |
| 265 RenderText::SetSelectionModel(model); | 195 RenderText::SetSelectionModel(model); |
| 266 } | 196 } |
| 267 | 197 |
| 268 std::vector<Rect> RenderTextLinux::GetSubstringBounds(size_t from, size_t to) { | 198 std::vector<Rect> RenderTextLinux::GetSubstringBounds(ui::Range range) { |
| 269 DCHECK(from <= text().length()); | 199 DCHECK_LE(range.GetMax(), text().length()); |
| 270 DCHECK(to <= text().length()); | |
| 271 | 200 |
| 272 if (from == to) | 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 if (RangeContainsCaret(ui::Range(item->offset, item->offset + item->length), |
| 481 size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); | 411 position, affinity)) |
|
msw
2012/02/21 21:13:39
|affinity| should be on its own line.
benrg
2012/02/21 23:21:45
The style guide allows this ("When calling a funct
| |
| 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 |