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