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 594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
605 SCRIPT_FONTPROPERTIES font_properties; | 605 SCRIPT_FONTPROPERTIES font_properties; |
606 memset(&font_properties, 0, sizeof(font_properties)); | 606 memset(&font_properties, 0, sizeof(font_properties)); |
607 font_properties.cBytes = sizeof(SCRIPT_FONTPROPERTIES); | 607 font_properties.cBytes = sizeof(SCRIPT_FONTPROPERTIES); |
608 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &font_properties); | 608 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &font_properties); |
609 | 609 |
610 run->logical_clusters.reset(new WORD[run_length]); | 610 run->logical_clusters.reset(new WORD[run_length]); |
611 run->glyph_count = 0; | 611 run->glyph_count = 0; |
612 // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx | 612 // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx |
613 size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16); | 613 size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16); |
614 while (max_glyphs < kMaxGlyphs) { | 614 while (max_glyphs < kMaxGlyphs) { |
615 bool glyphs_missing = false; | |
615 run->glyphs.reset(new WORD[max_glyphs]); | 616 run->glyphs.reset(new WORD[max_glyphs]); |
616 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]); | 617 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]); |
617 hr = ScriptShape(cached_hdc_, | 618 hr = ScriptShape(cached_hdc_, |
618 &run->script_cache, | 619 &run->script_cache, |
619 run_text, | 620 run_text, |
620 run_length, | 621 run_length, |
621 max_glyphs, | 622 max_glyphs, |
622 &(run->script_analysis), | 623 &(run->script_analysis), |
623 run->glyphs.get(), | 624 run->glyphs.get(), |
624 run->logical_clusters.get(), | 625 run->logical_clusters.get(), |
625 run->visible_attributes.get(), | 626 run->visible_attributes.get(), |
626 &(run->glyph_count)); | 627 &(run->glyph_count)); |
627 if (hr == E_OUTOFMEMORY) { | 628 if (hr == E_OUTOFMEMORY) { |
628 max_glyphs *= 2; | 629 max_glyphs *= 2; |
630 continue; | |
631 } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { | |
632 glyphs_missing = true; | |
629 } else if (hr == S_OK) { | 633 } else if (hr == S_OK) { |
630 // If |hr| is S_OK, there could still be missing glyphs in the output, | 634 // If |hr| is S_OK, there could still be missing glyphs in the output, |
631 // see: http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564 .aspx | 635 // see: http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564 .aspx |
632 // | 636 for (int i = 0; i < run->glyph_count; ++i) { |
633 // If there are missing glyphs, use font linking to try to find a | |
634 // matching font. | |
635 bool glyphs_missing = false; | |
636 for (int i = 0; i < run->glyph_count; i++) { | |
637 if (run->glyphs[i] == font_properties.wgDefault) { | 637 if (run->glyphs[i] == font_properties.wgDefault) { |
638 glyphs_missing = true; | 638 glyphs_missing = true; |
639 break; | 639 break; |
640 } | 640 } |
641 } | 641 } |
642 // No glyphs missing - good to go. | 642 } |
643 if (!glyphs_missing) | |
644 break; | |
645 | 643 |
646 // First time through, get the linked fonts list. | 644 // Skip font substitution if there are no missing glyphs. |
647 if (linked_fonts == NULL) | 645 if (!glyphs_missing) |
648 linked_fonts = GetLinkedFonts(run->font); | 646 break; |
649 | 647 |
650 // None of the linked fonts worked - break out of the loop. | 648 // If there are missing glyphs, first try finding a fallback font using a |
651 if (linked_font_index == linked_fonts->size()) | 649 // meta file, if it hasn't yet been attempted for this run. |
652 break; | 650 // TODO(msw|asvitkine): Support RenderText's font_list()? |
653 | 651 if (!tried_fallback) { |
654 // Try the next linked font. | 652 tried_fallback = true; |
655 run->font = linked_fonts->at(linked_font_index++); | |
656 DeriveFontIfNecessary(font_size, run->font_style, &run->font); | |
657 ScriptFreeCache(&run->script_cache); | |
658 SelectObject(cached_hdc_, run->font.GetNativeFont()); | |
659 } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { | |
660 // Only try font fallback if it hasn't yet been attempted for this run. | |
661 if (tried_fallback) { | |
662 // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can | |
663 // crash on certain surrogate pairs with SCRIPT_UNDEFINED. | |
664 // See https://bugzilla.mozilla.org/show_bug.cgi?id=341500 | |
665 // And http://maxradi.us/documents/uniscribe/ | |
666 run->script_analysis.eScript = SCRIPT_UNDEFINED; | |
667 // Reset |hr| to 0 to not trigger the DCHECK() below when a font is | |
668 // not found that can display the text. This is expected behavior | |
669 // under Windows XP without additional language packs installed and | |
670 // may also happen on newer versions when trying to display text in | |
671 // an obscure script that the system doesn't have the right font for. | |
672 hr = 0; | |
673 break; | |
674 } | |
675 | |
676 // The run's font doesn't contain the required glyphs, use an alternate. | |
677 // TODO(msw): support RenderText's font_list(). | |
678 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length, | 653 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length, |
679 &run->font)) { | 654 &run->font)) { |
680 DeriveFontIfNecessary(font_size, run->font_style, &run->font); | 655 UpdateRunFont(run, font_size); |
681 ScriptFreeCache(&run->script_cache); | 656 continue; |
682 SelectObject(cached_hdc_, run->font.GetNativeFont()); | |
683 } | 657 } |
658 } | |
684 | 659 |
685 tried_fallback = true; | 660 // Couldn't find a replacement font using the meta file, try to find one |
msw
2012/04/12 21:32:14
nit: consider "The meta file did not yield a repla
Alexei Svitkine (slow)
2012/04/13 13:56:15
Done.
| |
686 } else { | 661 // using font linking. First time through, get the linked fonts list. |
662 if (linked_fonts == NULL) | |
663 linked_fonts = GetLinkedFonts(run->font); | |
664 | |
665 // None of the linked fonts worked - break out of the loop. | |
666 if (linked_font_index == linked_fonts->size()) { | |
667 // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can | |
668 // crash on certain surrogate pairs with SCRIPT_UNDEFINED. | |
669 // See https://bugzilla.mozilla.org/show_bug.cgi?id=341500 | |
670 // And http://maxradi.us/documents/uniscribe/ | |
671 run->script_analysis.eScript = SCRIPT_UNDEFINED; | |
672 // Reset |hr| to 0 to not trigger the DCHECK() below when a font is | |
673 // not found that can display the text. This is expected behavior | |
674 // under Windows XP without additional language packs installed and | |
675 // may also happen on newer versions when trying to display text in | |
676 // an obscure script that the system doesn't have the right font for. | |
677 hr = 0; | |
687 break; | 678 break; |
688 } | 679 } |
680 | |
681 // Try the next linked font. | |
682 run->font = linked_fonts->at(linked_font_index++); | |
683 UpdateRunFont(run, font_size); | |
689 } | 684 } |
690 DCHECK(SUCCEEDED(hr)); | 685 DCHECK(SUCCEEDED(hr)); |
691 string_size_.set_height(std::max(string_size_.height(), | 686 string_size_.set_height(std::max(string_size_.height(), |
692 run->font.GetHeight())); | 687 run->font.GetHeight())); |
693 common_baseline_ = std::max(common_baseline_, run->font.GetBaseline()); | 688 common_baseline_ = std::max(common_baseline_, run->font.GetBaseline()); |
694 | 689 |
695 if (run->glyph_count > 0) { | 690 if (run->glyph_count > 0) { |
696 run->advance_widths.reset(new int[run->glyph_count]); | 691 run->advance_widths.reset(new int[run->glyph_count]); |
697 run->offsets.reset(new GOFFSET[run->glyph_count]); | 692 run->offsets.reset(new GOFFSET[run->glyph_count]); |
698 hr = ScriptPlace(cached_hdc_, | 693 hr = ScriptPlace(cached_hdc_, |
(...skipping 28 matching lines...) Expand all Loading... | |
727 for (size_t i = 0; i < runs_.size(); ++i) { | 722 for (size_t i = 0; i < runs_.size(); ++i) { |
728 internal::TextRun* run = runs_[visual_to_logical_[i]]; | 723 internal::TextRun* run = runs_[visual_to_logical_[i]]; |
729 run->preceding_run_widths = preceding_run_widths; | 724 run->preceding_run_widths = preceding_run_widths; |
730 const ABC& abc = run->abc_widths; | 725 const ABC& abc = run->abc_widths; |
731 run->width = abc.abcA + abc.abcB + abc.abcC; | 726 run->width = abc.abcA + abc.abcB + abc.abcC; |
732 preceding_run_widths += run->width; | 727 preceding_run_widths += run->width; |
733 } | 728 } |
734 string_size_.set_width(preceding_run_widths); | 729 string_size_.set_width(preceding_run_widths); |
735 } | 730 } |
736 | 731 |
732 void RenderTextWin::UpdateRunFont(internal::TextRun* run, int font_size) { | |
msw
2012/04/12 21:32:14
I think it'd be a better to supply the substitute
Alexei Svitkine (slow)
2012/04/12 22:11:43
I agree it would be cleaner from an interface POV,
Alexei Svitkine (slow)
2012/04/13 13:56:15
Done.
| |
733 DeriveFontIfNecessary(font_size, run->font_style, &run->font); | |
734 ScriptFreeCache(&run->script_cache); | |
735 SelectObject(cached_hdc_, run->font.GetNativeFont()); | |
736 } | |
737 | |
737 const std::vector<Font>* RenderTextWin::GetLinkedFonts(const Font& font) const { | 738 const std::vector<Font>* RenderTextWin::GetLinkedFonts(const Font& font) const { |
738 const std::string& font_name = font.GetFontName(); | 739 const std::string& font_name = font.GetFontName(); |
739 std::map<std::string, std::vector<Font> >::const_iterator it = | 740 std::map<std::string, std::vector<Font> >::const_iterator it = |
740 cached_linked_fonts_.find(font_name); | 741 cached_linked_fonts_.find(font_name); |
741 if (it != cached_linked_fonts_.end()) | 742 if (it != cached_linked_fonts_.end()) |
742 return &it->second; | 743 return &it->second; |
743 | 744 |
744 cached_linked_fonts_[font_name] = std::vector<Font>(); | 745 cached_linked_fonts_[font_name] = std::vector<Font>(); |
745 std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name]; | 746 std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name]; |
746 QueryLinkedFontsFromRegistry(font, linked_fonts); | 747 QueryLinkedFontsFromRegistry(font, linked_fonts); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
779 internal::TextRun* run) { | 780 internal::TextRun* run) { |
780 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD); | 781 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD); |
781 return SelectionModel(caret, CURSOR_FORWARD); | 782 return SelectionModel(caret, CURSOR_FORWARD); |
782 } | 783 } |
783 | 784 |
784 RenderText* RenderText::CreateRenderText() { | 785 RenderText* RenderText::CreateRenderText() { |
785 return new RenderTextWin; | 786 return new RenderTextWin; |
786 } | 787 } |
787 | 788 |
788 } // namespace gfx | 789 } // namespace gfx |
OLD | NEW |