Chromium Code Reviews| 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 |