| 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 579 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |