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