OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_harfbuzz.h" | 5 #include "ui/gfx/render_text_harfbuzz.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/debug/leak_annotations.h" | 9 #include "base/debug/leak_annotations.h" |
10 #include "base/i18n/bidi_line_iterator.h" | 10 #include "base/i18n/bidi_line_iterator.h" |
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 run = runs_[visual_to_logical_[visual_index]]; | 644 run = runs_[visual_to_logical_[visual_index]]; |
645 } | 645 } |
646 bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); | 646 bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT); |
647 return forward_motion ? FirstSelectionModelInsideRun(run) : | 647 return forward_motion ? FirstSelectionModelInsideRun(run) : |
648 LastSelectionModelInsideRun(run); | 648 LastSelectionModelInsideRun(run); |
649 } | 649 } |
650 | 650 |
651 SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel( | 651 SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel( |
652 const SelectionModel& selection, | 652 const SelectionModel& selection, |
653 VisualCursorDirection direction) { | 653 VisualCursorDirection direction) { |
654 // TODO(ckocagil): This implementation currently matches RenderTextWin, but it | |
655 // should match the native behavior on other platforms. | |
656 if (obscured()) | 654 if (obscured()) |
657 return EdgeSelectionModel(direction); | 655 return EdgeSelectionModel(direction); |
658 | 656 |
659 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | 657 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
660 bool success = iter.Init(); | 658 bool success = iter.Init(); |
661 DCHECK(success); | 659 DCHECK(success); |
662 if (!success) | 660 if (!success) |
663 return selection; | 661 return selection; |
664 | 662 |
| 663 // Match OS specific word break behavior. |
| 664 #if defined(OS_WIN) |
665 size_t pos; | 665 size_t pos; |
666 if (direction == CURSOR_RIGHT) { | 666 if (direction == CURSOR_RIGHT) { |
667 pos = std::min(selection.caret_pos() + 1, text().length()); | 667 pos = std::min(selection.caret_pos() + 1, text().length()); |
668 while (iter.Advance()) { | 668 while (iter.Advance()) { |
669 pos = iter.pos(); | 669 pos = iter.pos(); |
670 if (iter.IsWord() && pos > selection.caret_pos()) | 670 if (iter.IsWord() && pos > selection.caret_pos()) |
671 break; | 671 break; |
672 } | 672 } |
673 } else { // direction == CURSOR_LEFT | 673 } else { // direction == CURSOR_LEFT |
674 // Notes: We always iterate words from the beginning. | 674 // Notes: We always iterate words from the beginning. |
(...skipping 12 matching lines...) Expand all Loading... |
687 // The cursor is in the middle or at the end of a word. | 687 // The cursor is in the middle or at the end of a word. |
688 // Move to the top of current word. | 688 // Move to the top of current word. |
689 pos = begin; | 689 pos = begin; |
690 break; | 690 break; |
691 } | 691 } |
692 pos = iter.pos() - iter.GetString().length(); | 692 pos = iter.pos() - iter.GetString().length(); |
693 } | 693 } |
694 } | 694 } |
695 } | 695 } |
696 return SelectionModel(pos, CURSOR_FORWARD); | 696 return SelectionModel(pos, CURSOR_FORWARD); |
| 697 #else |
| 698 SelectionModel cur(selection); |
| 699 for (;;) { |
| 700 cur = AdjacentCharSelectionModel(cur, direction); |
| 701 size_t run = GetRunContainingCaret(cur); |
| 702 if (run == runs_.size()) |
| 703 break; |
| 704 const bool is_forward = runs_[run]->is_rtl == (direction == CURSOR_LEFT); |
| 705 size_t cursor = cur.caret_pos(); |
| 706 if (is_forward ? iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) |
| 707 break; |
| 708 } |
| 709 return cur; |
| 710 #endif |
697 } | 711 } |
698 | 712 |
699 std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) { | 713 std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) { |
700 DCHECK(!needs_layout_); | 714 DCHECK(!needs_layout_); |
701 DCHECK(Range(0, text().length()).Contains(range)); | 715 DCHECK(Range(0, text().length()).Contains(range)); |
702 Range layout_range(TextIndexToLayoutIndex(range.start()), | 716 Range layout_range(TextIndexToLayoutIndex(range.start()), |
703 TextIndexToLayoutIndex(range.end())); | 717 TextIndexToLayoutIndex(range.end())); |
704 DCHECK(Range(0, GetLayoutText().length()).Contains(layout_range)); | 718 DCHECK(Range(0, GetLayoutText().length()).Contains(layout_range)); |
705 | 719 |
706 std::vector<Rect> rects; | 720 std::vector<Rect> rects; |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1121 run->width += | 1135 run->width += |
1122 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance)); | 1136 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance)); |
1123 } | 1137 } |
1124 | 1138 |
1125 hb_buffer_destroy(buffer); | 1139 hb_buffer_destroy(buffer); |
1126 hb_font_destroy(harfbuzz_font); | 1140 hb_font_destroy(harfbuzz_font); |
1127 return true; | 1141 return true; |
1128 } | 1142 } |
1129 | 1143 |
1130 } // namespace gfx | 1144 } // namespace gfx |
OLD | NEW |