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/logging.h" | 10 #include "base/logging.h" |
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 void RenderTextWin::LayoutVisualText() { | 599 void RenderTextWin::LayoutVisualText() { |
600 DCHECK(!runs_.empty()); | 600 DCHECK(!runs_.empty()); |
601 | 601 |
602 if (!cached_hdc_) | 602 if (!cached_hdc_) |
603 cached_hdc_ = CreateCompatibleDC(NULL); | 603 cached_hdc_ = CreateCompatibleDC(NULL); |
604 | 604 |
605 HRESULT hr = E_FAIL; | 605 HRESULT hr = E_FAIL; |
606 string_size_.set_height(0); | 606 string_size_.set_height(0); |
607 for (size_t i = 0; i < runs_.size(); ++i) { | 607 for (size_t i = 0; i < runs_.size(); ++i) { |
608 internal::TextRun* run = runs_[i]; | 608 internal::TextRun* run = runs_[i]; |
609 size_t run_length = run->range.length(); | 609 const size_t run_length = run->range.length(); |
610 const wchar_t* run_text = &(text()[run->range.start()]); | 610 const wchar_t* run_text = &(text()[run->range.start()]); |
611 bool tried_fallback = false; | 611 bool tried_fallback = false; |
612 size_t linked_font_index = 0; | 612 size_t linked_font_index = 0; |
613 const std::vector<Font>* linked_fonts = NULL; | 613 const std::vector<Font>* linked_fonts = NULL; |
614 Font original_font = run->font; | 614 Font original_font = run->font; |
615 | 615 |
616 // Select the font desired for glyph generation. | 616 // Select the font desired for glyph generation. |
617 SelectObject(cached_hdc_, run->font.GetNativeFont()); | 617 SelectObject(cached_hdc_, run->font.GetNativeFont()); |
618 | 618 |
619 SCRIPT_FONTPROPERTIES properties; | |
620 memset(&properties, 0, sizeof(properties)); | |
621 properties.cBytes = sizeof(properties); | |
622 | |
623 run->logical_clusters.reset(new WORD[run_length]); | 619 run->logical_clusters.reset(new WORD[run_length]); |
624 run->glyph_count = 0; | 620 run->glyph_count = 0; |
625 // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx | 621 // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx |
626 size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16); | 622 size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16); |
627 while (max_glyphs < kMaxGlyphs) { | 623 while (max_glyphs < kMaxGlyphs) { |
628 bool glyphs_missing = false; | |
629 run->glyphs.reset(new WORD[max_glyphs]); | 624 run->glyphs.reset(new WORD[max_glyphs]); |
630 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]); | 625 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]); |
631 hr = ScriptShape(cached_hdc_, | 626 hr = ScriptShape(cached_hdc_, |
632 &run->script_cache, | 627 &run->script_cache, |
633 run_text, | 628 run_text, |
634 run_length, | 629 run_length, |
635 max_glyphs, | 630 max_glyphs, |
636 &(run->script_analysis), | 631 &(run->script_analysis), |
637 run->glyphs.get(), | 632 run->glyphs.get(), |
638 run->logical_clusters.get(), | 633 run->logical_clusters.get(), |
639 run->visible_attributes.get(), | 634 run->visible_attributes.get(), |
640 &(run->glyph_count)); | 635 &(run->glyph_count)); |
641 if (hr == E_OUTOFMEMORY) { | 636 if (hr == E_OUTOFMEMORY) { |
642 max_glyphs *= 2; | 637 max_glyphs *= 2; |
643 continue; | 638 continue; |
644 } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { | 639 } |
| 640 |
| 641 bool glyphs_missing = false; |
| 642 if (hr == USP_E_SCRIPT_NOT_IN_FONT) { |
645 glyphs_missing = true; | 643 glyphs_missing = true; |
646 } else if (hr == S_OK) { | 644 } else if (hr == S_OK) { |
647 // If |hr| is S_OK, there could still be missing glyphs in the output, | 645 // If |hr| is S_OK, there could still be missing glyphs in the output, |
648 // see: http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564
.aspx | 646 // see: http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564
.aspx |
649 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties); | 647 glyphs_missing = HasMissingGlyphs(run); |
650 for (int i = 0; i < run->glyph_count; ++i) { | |
651 if (run->glyphs[i] == properties.wgDefault) { | |
652 glyphs_missing = true; | |
653 break; | |
654 } | |
655 } | |
656 } | 648 } |
657 | 649 |
658 // Skip font substitution if there are no missing glyphs. | 650 // Skip font substitution if there are no missing glyphs. |
659 if (!glyphs_missing) | 651 if (!glyphs_missing) |
660 break; | 652 break; |
661 | 653 |
662 // If there are missing glyphs, first try finding a fallback font using a | 654 // If there are missing glyphs, first try finding a fallback font using a |
663 // meta file, if it hasn't yet been attempted for this run. | 655 // meta file, if it hasn't yet been attempted for this run. |
664 // TODO(msw|asvitkine): Support RenderText's font_list()? | 656 // TODO(msw|asvitkine): Support RenderText's font_list()? |
665 // TODO(msw|asvitkine): Cache previous successful replacement fonts? | 657 // TODO(msw|asvitkine): Cache previous successful replacement fonts? |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 void RenderTextWin::ApplySubstituteFont(internal::TextRun* run, | 752 void RenderTextWin::ApplySubstituteFont(internal::TextRun* run, |
761 const Font& font) { | 753 const Font& font) { |
762 const int font_size = run->font.GetFontSize(); | 754 const int font_size = run->font.GetFontSize(); |
763 const int font_height = run->font.GetHeight(); | 755 const int font_height = run->font.GetHeight(); |
764 run->font = font; | 756 run->font = font; |
765 DeriveFontIfNecessary(font_size, font_height, run->font_style, &run->font); | 757 DeriveFontIfNecessary(font_size, font_height, run->font_style, &run->font); |
766 ScriptFreeCache(&run->script_cache); | 758 ScriptFreeCache(&run->script_cache); |
767 SelectObject(cached_hdc_, run->font.GetNativeFont()); | 759 SelectObject(cached_hdc_, run->font.GetNativeFont()); |
768 } | 760 } |
769 | 761 |
| 762 bool RenderTextWin::HasMissingGlyphs(internal::TextRun* run) const { |
| 763 SCRIPT_FONTPROPERTIES properties; |
| 764 memset(&properties, 0, sizeof(properties)); |
| 765 properties.cBytes = sizeof(properties); |
| 766 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &properties); |
| 767 |
| 768 const wchar_t* run_text = &(text()[run->range.start()]); |
| 769 for (size_t char_index = 0; char_index < run->range.length(); ++char_index) { |
| 770 const int glyph_index = run->logical_clusters[char_index]; |
| 771 DCHECK_GE(glyph_index, 0); |
| 772 DCHECK_LT(glyph_index, run->glyph_count); |
| 773 |
| 774 if (run->glyphs[glyph_index] == properties.wgDefault) |
| 775 return true; |
| 776 |
| 777 // Windows Vista sometimes returns glyphs equal to wgBlank (instead of |
| 778 // wgDefault), with fZeroWidth set. Treat such cases as having missing |
| 779 // glyphs if the corresponding character is not whitespace. |
| 780 // See: http://crbug.com/125629 |
| 781 if (run->glyphs[glyph_index] == properties.wgBlank && |
| 782 run->visible_attributes[glyph_index].fZeroWidth && |
| 783 !IsWhitespace(run_text[char_index])) { |
| 784 return true; |
| 785 } |
| 786 } |
| 787 |
| 788 return false; |
| 789 } |
| 790 |
770 const std::vector<Font>* RenderTextWin::GetLinkedFonts(const Font& font) const { | 791 const std::vector<Font>* RenderTextWin::GetLinkedFonts(const Font& font) const { |
771 const std::string& font_name = font.GetFontName(); | 792 const std::string& font_name = font.GetFontName(); |
772 std::map<std::string, std::vector<Font> >::const_iterator it = | 793 std::map<std::string, std::vector<Font> >::const_iterator it = |
773 cached_linked_fonts_.find(font_name); | 794 cached_linked_fonts_.find(font_name); |
774 if (it != cached_linked_fonts_.end()) | 795 if (it != cached_linked_fonts_.end()) |
775 return &it->second; | 796 return &it->second; |
776 | 797 |
777 cached_linked_fonts_[font_name] = std::vector<Font>(); | 798 cached_linked_fonts_[font_name] = std::vector<Font>(); |
778 std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name]; | 799 std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name]; |
779 QueryLinkedFontsFromRegistry(font, linked_fonts); | 800 QueryLinkedFontsFromRegistry(font, linked_fonts); |
(...skipping 16 matching lines...) Expand all Loading... |
796 // Find the text run containing the argument point (assumed already offset). | 817 // Find the text run containing the argument point (assumed already offset). |
797 size_t run = 0; | 818 size_t run = 0; |
798 for (; run < runs_.size(); ++run) | 819 for (; run < runs_.size(); ++run) |
799 if (runs_[run]->preceding_run_widths <= point.x() && | 820 if (runs_[run]->preceding_run_widths <= point.x() && |
800 runs_[run]->preceding_run_widths + runs_[run]->width > point.x()) | 821 runs_[run]->preceding_run_widths + runs_[run]->width > point.x()) |
801 break; | 822 break; |
802 return run; | 823 return run; |
803 } | 824 } |
804 | 825 |
805 SelectionModel RenderTextWin::FirstSelectionModelInsideRun( | 826 SelectionModel RenderTextWin::FirstSelectionModelInsideRun( |
806 internal::TextRun* run) { | 827 const internal::TextRun* run) { |
807 size_t cursor = IndexOfAdjacentGrapheme(run->range.start(), CURSOR_FORWARD); | 828 size_t cursor = IndexOfAdjacentGrapheme(run->range.start(), CURSOR_FORWARD); |
808 return SelectionModel(cursor, CURSOR_BACKWARD); | 829 return SelectionModel(cursor, CURSOR_BACKWARD); |
809 } | 830 } |
810 | 831 |
811 SelectionModel RenderTextWin::LastSelectionModelInsideRun( | 832 SelectionModel RenderTextWin::LastSelectionModelInsideRun( |
812 internal::TextRun* run) { | 833 const internal::TextRun* run) { |
813 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD); | 834 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD); |
814 return SelectionModel(caret, CURSOR_FORWARD); | 835 return SelectionModel(caret, CURSOR_FORWARD); |
815 } | 836 } |
816 | 837 |
817 RenderText* RenderText::CreateRenderText() { | 838 RenderText* RenderText::CreateRenderText() { |
818 return new RenderTextWin; | 839 return new RenderTextWin; |
819 } | 840 } |
820 | 841 |
821 } // namespace gfx | 842 } // namespace gfx |
OLD | NEW |