Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: ui/gfx/render_text_win.cc

Issue 10010047: Always try metafile font fallback in the case of missing glyphs in RenderTextWin. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 579 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 590
591 HRESULT hr = E_FAIL; 591 HRESULT hr = E_FAIL;
592 string_size_.set_height(0); 592 string_size_.set_height(0);
593 for (size_t i = 0; i < runs_.size(); ++i) { 593 for (size_t i = 0; i < runs_.size(); ++i) {
594 internal::TextRun* run = runs_[i]; 594 internal::TextRun* run = runs_[i];
595 size_t run_length = run->range.length(); 595 size_t run_length = run->range.length();
596 const wchar_t* run_text = &(text()[run->range.start()]); 596 const wchar_t* run_text = &(text()[run->range.start()]);
597 bool tried_fallback = false; 597 bool tried_fallback = false;
598 size_t linked_font_index = 0; 598 size_t linked_font_index = 0;
599 const std::vector<Font>* linked_fonts = NULL; 599 const std::vector<Font>* linked_fonts = NULL;
600 const int font_size = run->font.GetFontSize();
601 600
602 // Select the font desired for glyph generation. 601 // Select the font desired for glyph generation.
603 SelectObject(cached_hdc_, run->font.GetNativeFont()); 602 SelectObject(cached_hdc_, run->font.GetNativeFont());
604 603
605 SCRIPT_FONTPROPERTIES font_properties; 604 SCRIPT_FONTPROPERTIES font_properties;
606 memset(&font_properties, 0, sizeof(font_properties)); 605 memset(&font_properties, 0, sizeof(font_properties));
607 font_properties.cBytes = sizeof(SCRIPT_FONTPROPERTIES); 606 font_properties.cBytes = sizeof(SCRIPT_FONTPROPERTIES);
608 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &font_properties); 607 ScriptGetFontProperties(cached_hdc_, &run->script_cache, &font_properties);
609 608
610 run->logical_clusters.reset(new WORD[run_length]); 609 run->logical_clusters.reset(new WORD[run_length]);
611 run->glyph_count = 0; 610 run->glyph_count = 0;
612 // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx 611 // 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); 612 size_t max_glyphs = static_cast<size_t>(1.5 * run_length + 16);
614 while (max_glyphs < kMaxGlyphs) { 613 while (max_glyphs < kMaxGlyphs) {
614 bool glyphs_missing = false;
615 run->glyphs.reset(new WORD[max_glyphs]); 615 run->glyphs.reset(new WORD[max_glyphs]);
616 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]); 616 run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]);
617 hr = ScriptShape(cached_hdc_, 617 hr = ScriptShape(cached_hdc_,
618 &run->script_cache, 618 &run->script_cache,
619 run_text, 619 run_text,
620 run_length, 620 run_length,
621 max_glyphs, 621 max_glyphs,
622 &(run->script_analysis), 622 &(run->script_analysis),
623 run->glyphs.get(), 623 run->glyphs.get(),
624 run->logical_clusters.get(), 624 run->logical_clusters.get(),
625 run->visible_attributes.get(), 625 run->visible_attributes.get(),
626 &(run->glyph_count)); 626 &(run->glyph_count));
627 if (hr == E_OUTOFMEMORY) { 627 if (hr == E_OUTOFMEMORY) {
628 max_glyphs *= 2; 628 max_glyphs *= 2;
629 continue;
630 } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
631 glyphs_missing = true;
629 } else if (hr == S_OK) { 632 } else if (hr == S_OK) {
630 // If |hr| is S_OK, there could still be missing glyphs in the output, 633 // 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 634 // see: http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564 .aspx
632 // 635 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) { 636 if (run->glyphs[i] == font_properties.wgDefault) {
638 glyphs_missing = true; 637 glyphs_missing = true;
639 break; 638 break;
640 } 639 }
641 } 640 }
642 // No glyphs missing - good to go. 641 }
643 if (!glyphs_missing)
644 break;
645 642
646 // First time through, get the linked fonts list. 643 // Skip font substitution if there are no missing glyphs.
647 if (linked_fonts == NULL) 644 if (!glyphs_missing)
648 linked_fonts = GetLinkedFonts(run->font); 645 break;
649 646
650 // None of the linked fonts worked - break out of the loop. 647 // If there are missing glyphs, first try finding a fallback font using a
651 if (linked_font_index == linked_fonts->size()) 648 // meta file, if it hasn't yet been attempted for this run.
652 break; 649 // TODO(msw|asvitkine): Support RenderText's font_list()?
650 // TODO(msw|asvitkine): Cache previous successful replacement fonts?
651 if (!tried_fallback) {
652 tried_fallback = true;
653 653
654 // Try the next linked font. 654 Font fallback_font;
655 run->font = linked_fonts->at(linked_font_index++); 655 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length,
656 DeriveFontIfNecessary(font_size, run->font_style, &run->font); 656 &fallback_font)) {
657 ScriptFreeCache(&run->script_cache); 657 ApplySubstituteFont(run, fallback_font);
658 SelectObject(cached_hdc_, run->font.GetNativeFont()); 658 continue;
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 } 659 }
660 }
675 661
676 // The run's font doesn't contain the required glyphs, use an alternate. 662 // The meta file approach did not yield a replacement font, try to find
677 // TODO(msw): support RenderText's font_list(). 663 // one using font linking. First time through, get the linked fonts list.
678 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length, 664 if (linked_fonts == NULL)
679 &run->font)) { 665 linked_fonts = GetLinkedFonts(run->font);
680 DeriveFontIfNecessary(font_size, run->font_style, &run->font);
681 ScriptFreeCache(&run->script_cache);
682 SelectObject(cached_hdc_, run->font.GetNativeFont());
683 }
684 666
685 tried_fallback = true; 667 // None of the linked fonts worked, break out of the loop.
686 } else { 668 if (linked_font_index == linked_fonts->size()) {
669 // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can
670 // crash on certain surrogate pairs with SCRIPT_UNDEFINED.
671 // See https://bugzilla.mozilla.org/show_bug.cgi?id=341500
672 // And http://maxradi.us/documents/uniscribe/
673 run->script_analysis.eScript = SCRIPT_UNDEFINED;
674 // Reset |hr| to 0 to not trigger the DCHECK() below when a font is
675 // not found that can display the text. This is expected behavior
676 // under Windows XP without additional language packs installed and
677 // may also happen on newer versions when trying to display text in
678 // an obscure script that the system doesn't have the right font for.
679 hr = 0;
687 break; 680 break;
688 } 681 }
682
683 // Try the next linked font.
684 ApplySubstituteFont(run, linked_fonts->at(linked_font_index++));
689 } 685 }
690 DCHECK(SUCCEEDED(hr)); 686 DCHECK(SUCCEEDED(hr));
691 string_size_.set_height(std::max(string_size_.height(), 687 string_size_.set_height(std::max(string_size_.height(),
692 run->font.GetHeight())); 688 run->font.GetHeight()));
693 common_baseline_ = std::max(common_baseline_, run->font.GetBaseline()); 689 common_baseline_ = std::max(common_baseline_, run->font.GetBaseline());
694 690
695 if (run->glyph_count > 0) { 691 if (run->glyph_count > 0) {
696 run->advance_widths.reset(new int[run->glyph_count]); 692 run->advance_widths.reset(new int[run->glyph_count]);
697 run->offsets.reset(new GOFFSET[run->glyph_count]); 693 run->offsets.reset(new GOFFSET[run->glyph_count]);
698 hr = ScriptPlace(cached_hdc_, 694 hr = ScriptPlace(cached_hdc_,
(...skipping 28 matching lines...) Expand all
727 for (size_t i = 0; i < runs_.size(); ++i) { 723 for (size_t i = 0; i < runs_.size(); ++i) {
728 internal::TextRun* run = runs_[visual_to_logical_[i]]; 724 internal::TextRun* run = runs_[visual_to_logical_[i]];
729 run->preceding_run_widths = preceding_run_widths; 725 run->preceding_run_widths = preceding_run_widths;
730 const ABC& abc = run->abc_widths; 726 const ABC& abc = run->abc_widths;
731 run->width = abc.abcA + abc.abcB + abc.abcC; 727 run->width = abc.abcA + abc.abcB + abc.abcC;
732 preceding_run_widths += run->width; 728 preceding_run_widths += run->width;
733 } 729 }
734 string_size_.set_width(preceding_run_widths); 730 string_size_.set_width(preceding_run_widths);
735 } 731 }
736 732
733 void RenderTextWin::ApplySubstituteFont(internal::TextRun* run,
734 const Font& font) {
735 const int font_size = run->font.GetFontSize();
736 run->font = font;
737 DeriveFontIfNecessary(font_size, run->font_style, &run->font);
738 ScriptFreeCache(&run->script_cache);
739 SelectObject(cached_hdc_, run->font.GetNativeFont());
740 }
741
737 const std::vector<Font>* RenderTextWin::GetLinkedFonts(const Font& font) const { 742 const std::vector<Font>* RenderTextWin::GetLinkedFonts(const Font& font) const {
738 const std::string& font_name = font.GetFontName(); 743 const std::string& font_name = font.GetFontName();
739 std::map<std::string, std::vector<Font> >::const_iterator it = 744 std::map<std::string, std::vector<Font> >::const_iterator it =
740 cached_linked_fonts_.find(font_name); 745 cached_linked_fonts_.find(font_name);
741 if (it != cached_linked_fonts_.end()) 746 if (it != cached_linked_fonts_.end())
742 return &it->second; 747 return &it->second;
743 748
744 cached_linked_fonts_[font_name] = std::vector<Font>(); 749 cached_linked_fonts_[font_name] = std::vector<Font>();
745 std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name]; 750 std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name];
746 QueryLinkedFontsFromRegistry(font, linked_fonts); 751 QueryLinkedFontsFromRegistry(font, linked_fonts);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 internal::TextRun* run) { 784 internal::TextRun* run) {
780 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD); 785 size_t caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD);
781 return SelectionModel(caret, CURSOR_FORWARD); 786 return SelectionModel(caret, CURSOR_FORWARD);
782 } 787 }
783 788
784 RenderText* RenderText::CreateRenderText() { 789 RenderText* RenderText::CreateRenderText() {
785 return new RenderTextWin; 790 return new RenderTextWin;
786 } 791 }
787 792
788 } // namespace gfx 793 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698