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_win.h" | 5 #include "ui/gfx/render_text_win.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/i18n/break_iterator.h" | 9 #include "base/i18n/break_iterator.h" |
10 #include "base/i18n/char_iterator.h" | 10 #include "base/i18n/char_iterator.h" |
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 }; | 497 }; |
498 | 498 |
499 } // namespace internal | 499 } // namespace internal |
500 | 500 |
501 // static | 501 // static |
502 HDC RenderTextWin::cached_hdc_ = NULL; | 502 HDC RenderTextWin::cached_hdc_ = NULL; |
503 | 503 |
504 // static | 504 // static |
505 std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_; | 505 std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_; |
506 | 506 |
507 RenderTextWin::RenderTextWin() | 507 RenderTextWin::RenderTextWin() : RenderText(), needs_layout_(false) { |
508 : RenderText(), | |
509 needs_layout_(false) { | |
510 set_truncate_length(kMaxUniscribeTextLength); | 508 set_truncate_length(kMaxUniscribeTextLength); |
511 | |
512 memset(&script_control_, 0, sizeof(script_control_)); | 509 memset(&script_control_, 0, sizeof(script_control_)); |
513 memset(&script_state_, 0, sizeof(script_state_)); | 510 memset(&script_state_, 0, sizeof(script_state_)); |
514 | |
515 MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT)); | 511 MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT)); |
516 } | 512 } |
517 | 513 |
518 RenderTextWin::~RenderTextWin() { | 514 RenderTextWin::~RenderTextWin() {} |
519 } | |
520 | 515 |
521 Size RenderTextWin::GetStringSize() { | 516 Size RenderTextWin::GetStringSize() { |
522 EnsureLayout(); | 517 EnsureLayout(); |
523 return multiline_string_size_; | 518 return multiline_string_size_; |
524 } | 519 } |
525 | 520 |
526 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { | 521 SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { |
527 if (text().empty()) | 522 if (text().empty()) |
528 return SelectionModel(); | 523 return SelectionModel(); |
529 | 524 |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
709 } | 704 } |
710 for (size_t i = 0; i < bounds.size(); ++i) { | 705 for (size_t i = 0; i < bounds.size(); ++i) { |
711 std::vector<Rect> current_rects = TextBoundsToViewBounds(bounds[i]); | 706 std::vector<Rect> current_rects = TextBoundsToViewBounds(bounds[i]); |
712 rects.insert(rects.end(), current_rects.begin(), current_rects.end()); | 707 rects.insert(rects.end(), current_rects.begin(), current_rects.end()); |
713 } | 708 } |
714 return rects; | 709 return rects; |
715 } | 710 } |
716 | 711 |
717 size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const { | 712 size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const { |
718 DCHECK_LE(index, text().length()); | 713 DCHECK_LE(index, text().length()); |
719 ptrdiff_t i = obscured() ? gfx::UTF16IndexToOffset(text(), 0, index) : index; | 714 ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index; |
720 CHECK_GE(i, 0); | 715 CHECK_GE(i, 0); |
721 // Clamp layout indices to the length of the text actually used for layout. | 716 // Clamp layout indices to the length of the text actually used for layout. |
722 return std::min<size_t>(GetLayoutText().length(), i); | 717 return std::min<size_t>(GetLayoutText().length(), i); |
723 } | 718 } |
724 | 719 |
725 size_t RenderTextWin::LayoutIndexToTextIndex(size_t index) const { | 720 size_t RenderTextWin::LayoutIndexToTextIndex(size_t index) const { |
726 if (!obscured()) | 721 if (!obscured()) |
727 return index; | 722 return index; |
728 | 723 |
729 DCHECK_LE(index, GetLayoutText().length()); | 724 DCHECK_LE(index, GetLayoutText().length()); |
730 const size_t text_index = gfx::UTF16OffsetToIndex(text(), 0, index); | 725 const size_t text_index = UTF16OffsetToIndex(text(), 0, index); |
731 DCHECK_LE(text_index, text().length()); | 726 DCHECK_LE(text_index, text().length()); |
732 return text_index; | 727 return text_index; |
733 } | 728 } |
734 | 729 |
735 bool RenderTextWin::IsCursorablePosition(size_t position) { | 730 bool RenderTextWin::IsValidCursorIndex(size_t index) { |
736 if (position == 0 || position == text().length()) | 731 if (index == 0 || index == text().length()) |
737 return true; | 732 return true; |
| 733 if (!IsValidLogicalIndex(index)) |
| 734 return false; |
738 EnsureLayout(); | 735 EnsureLayout(); |
739 | 736 // Disallow indices amid multi-character graphemes by checking glyph bounds. |
740 // Check that the index is at a valid code point (not mid-surrgate-pair), | 737 // These characters are not surrogate-pairs, but may yield a single glyph: |
741 // that it is not truncated from layout text (its glyph is shown on screen), | 738 // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts. |
742 // and that its glyph has distinct bounds (not mid-multi-character-grapheme). | 739 // \x0e08\x0e33 - (cho chan + sara am) - a Thai consonant and vowel pair. |
743 // An example of a multi-character-grapheme that is not a surrogate-pair is: | 740 return GetGlyphBounds(index) != GetGlyphBounds(index - 1); |
744 // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts. | |
745 return gfx::IsValidCodePointIndex(text(), position) && | |
746 position < LayoutIndexToTextIndex(GetLayoutText().length()) && | |
747 GetGlyphBounds(position) != GetGlyphBounds(position - 1); | |
748 } | 741 } |
749 | 742 |
750 void RenderTextWin::ResetLayout() { | 743 void RenderTextWin::ResetLayout() { |
751 // Layout is performed lazily as needed for drawing/metrics. | 744 // Layout is performed lazily as needed for drawing/metrics. |
752 needs_layout_ = true; | 745 needs_layout_ = true; |
753 } | 746 } |
754 | 747 |
755 void RenderTextWin::EnsureLayout() { | 748 void RenderTextWin::EnsureLayout() { |
756 if (needs_layout_) { | 749 if (needs_layout_) { |
757 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. | 750 // TODO(msw): Skip complex processing if ScriptIsComplex returns false. |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
853 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style); | 846 renderer.SetFontFamilyWithStyle(run->font.GetFontName(), run->font_style); |
854 | 847 |
855 for (BreakList<SkColor>::const_iterator it = | 848 for (BreakList<SkColor>::const_iterator it = |
856 colors().GetBreak(segment->char_range.start()); | 849 colors().GetBreak(segment->char_range.start()); |
857 it != colors().breaks().end() && | 850 it != colors().breaks().end() && |
858 it->first < segment->char_range.end(); | 851 it->first < segment->char_range.end(); |
859 ++it) { | 852 ++it) { |
860 const Range intersection = | 853 const Range intersection = |
861 colors().GetRange(it).Intersect(segment->char_range); | 854 colors().GetRange(it).Intersect(segment->char_range); |
862 const Range colored_glyphs = CharRangeToGlyphRange(*run, intersection); | 855 const Range colored_glyphs = CharRangeToGlyphRange(*run, intersection); |
| 856 // The range may be empty if a portion of a multi-character grapheme is |
| 857 // selected, yielding two colors for a single glyph. For now, this just |
| 858 // paints the glyph with a single style, but it should paint it twice, |
| 859 // clipped according to selection bounds. See http://crbug.com/366786 |
| 860 if (colored_glyphs.is_empty()) |
| 861 continue; |
863 DCHECK(glyph_range.Contains(colored_glyphs)); | 862 DCHECK(glyph_range.Contains(colored_glyphs)); |
864 DCHECK(!colored_glyphs.is_empty()); | |
865 const SkPoint& start_pos = | 863 const SkPoint& start_pos = |
866 pos[colored_glyphs.start() - glyph_range.start()]; | 864 pos[colored_glyphs.start() - glyph_range.start()]; |
867 const SkPoint& end_pos = | 865 const SkPoint& end_pos = |
868 pos[colored_glyphs.end() - glyph_range.start()]; | 866 pos[colored_glyphs.end() - glyph_range.start()]; |
869 | 867 |
870 renderer.SetForegroundColor(it->second); | 868 renderer.SetForegroundColor(it->second); |
871 renderer.DrawPosText(&start_pos, &run->glyphs[colored_glyphs.start()], | 869 renderer.DrawPosText(&start_pos, &run->glyphs[colored_glyphs.start()], |
872 colored_glyphs.length()); | 870 colored_glyphs.length()); |
873 renderer.DrawDecorations(start_pos.x(), text_offset.y(), | 871 renderer.DrawDecorations(start_pos.x(), text_offset.y(), |
874 SkScalarCeilToInt(end_pos.x() - start_pos.x()), | 872 SkScalarCeilToInt(end_pos.x() - start_pos.x()), |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1273 size_t position = LayoutIndexToTextIndex(run->range.end()); | 1271 size_t position = LayoutIndexToTextIndex(run->range.end()); |
1274 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); | 1272 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); |
1275 return SelectionModel(position, CURSOR_FORWARD); | 1273 return SelectionModel(position, CURSOR_FORWARD); |
1276 } | 1274 } |
1277 | 1275 |
1278 RenderText* RenderText::CreateInstance() { | 1276 RenderText* RenderText::CreateInstance() { |
1279 return new RenderTextWin; | 1277 return new RenderTextWin; |
1280 } | 1278 } |
1281 | 1279 |
1282 } // namespace gfx | 1280 } // namespace gfx |
OLD | NEW |