| 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 |