diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/gfx/render_text_win.cc | 85 | ||||
-rw-r--r-- | ui/gfx/render_text_win.h | 8 |
2 files changed, 93 insertions, 0 deletions
diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc index 608cc7d..ae31475 100644 --- a/ui/gfx/render_text_win.cc +++ b/ui/gfx/render_text_win.cc @@ -10,7 +10,9 @@ #include "base/logging.h" #include "base/stl_util.h" #include "base/string_util.h" +#include "base/threading/thread_restrictions.h" #include "base/utf_string_conversions.h" +#include "base/win/registry.h" #include "ui/gfx/font_smoothing_win.h" #include "ui/gfx/canvas.h" #include "ui/gfx/canvas_skia.h" @@ -84,6 +86,37 @@ bool ChooseFallbackFont(HDC hdc, return found_fallback; } +// Queries the Registry to get a list of linked fonts for |font|. +void QueryLinkedFontsFromRegistry(const gfx::Font& font, + std::vector<gfx::Font>* linked_fonts) { + base::ThreadRestrictions::ScopedAllowIO allow_io; + const wchar_t* kSystemLink = + L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink"; + + base::win::RegKey key; + if (FAILED(key.Open(HKEY_LOCAL_MACHINE, kSystemLink, KEY_READ))) + return; + + const std::wstring font_name = UTF8ToWide(font.GetFontName()); + std::vector<std::wstring> values; + if (FAILED(key.ReadValues(font_name.c_str(), &values))) { + key.Close(); + return; + } + + for (size_t i = 0; i < values.size(); i++) { + // The font name follows the comma in each entry. + const size_t index = values[i].find(','); + if ((index != string16::npos) && (index + 1 != values[i].length())) { + const std::string linked_name = UTF16ToUTF8(values[i].substr(index + 1)); + const gfx::Font linked_font(linked_name, font.GetFontSize()); + linked_fonts->push_back(linked_font); + } + } + + key.Close(); +} + } // namespace namespace gfx { @@ -110,6 +143,9 @@ TextRun::~TextRun() { // static HDC RenderTextWin::cached_hdc_ = NULL; +// static +std::map<std::string, std::vector<Font> > RenderTextWin::cached_linked_fonts_; + RenderTextWin::RenderTextWin() : RenderText(), string_width_(0), @@ -603,10 +639,17 @@ void RenderTextWin::LayoutVisualText() { size_t run_length = run->range.length(); const wchar_t* run_text = &(text()[run->range.start()]); bool tried_fallback = false; + size_t linked_font_index = 0; + const std::vector<gfx::Font>* linked_fonts = NULL; // Select the font desired for glyph generation. SelectObject(cached_hdc_, run->font.GetNativeFont()); + SCRIPT_FONTPROPERTIES font_properties; + memset(&font_properties, 0, sizeof(font_properties)); + font_properties.cBytes = sizeof(SCRIPT_FONTPROPERTIES); + ScriptGetFontProperties(cached_hdc_, &run->script_cache, &font_properties); + run->logical_clusters.reset(new WORD[run_length]); run->glyph_count = 0; // Max glyph guess: http://msdn.microsoft.com/en-us/library/dd368564.aspx @@ -626,6 +669,35 @@ void RenderTextWin::LayoutVisualText() { &(run->glyph_count)); if (hr == E_OUTOFMEMORY) { max_glyphs *= 2; + } else if (hr == S_OK) { + // If |hr| is S_OK, there could still be missing glyphs in the output, + // see: http://msdn.microsoft.com/en-us/library/windows/desktop/dd368564.aspx + // + // If there are missing glyphs, use font linking to try to find a + // matching font. + bool glyphs_missing = false; + for (int i = 0; i < run->glyph_count; i++) { + if (run->glyphs[i] == font_properties.wgDefault) { + glyphs_missing = true; + break; + } + } + // No glyphs missing - good to go. + if (!glyphs_missing) + break; + + // First time through, get the linked fonts list. + if (linked_fonts == NULL) + linked_fonts = GetLinkedFonts(run->font); + + // None of the linked fonts worked - break out of the loop. + if (linked_font_index == linked_fonts->size()) + break; + + // Try the next linked font. + run->font = linked_fonts->at(linked_font_index++); + ScriptFreeCache(&run->script_cache); + SelectObject(cached_hdc_, run->font.GetNativeFont()); } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { // Only try font fallback if it hasn't yet been attempted for this run. if (tried_fallback) { @@ -702,6 +774,19 @@ void RenderTextWin::LayoutVisualText() { string_width_ = preceding_run_widths; } +const std::vector<Font>* RenderTextWin::GetLinkedFonts(const Font& font) const { + const std::string& font_name = font.GetFontName(); + std::map<std::string, std::vector<Font> >::const_iterator it = + cached_linked_fonts_.find(font_name); + if (it != cached_linked_fonts_.end()) + return &it->second; + + cached_linked_fonts_[font_name] = std::vector<Font>(); + std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name]; + QueryLinkedFontsFromRegistry(font, linked_fonts); + return linked_fonts; +} + size_t RenderTextWin::GetRunContainingPosition(size_t position) const { DCHECK(!needs_layout_); // Find the text run containing the argument position. diff --git a/ui/gfx/render_text_win.h b/ui/gfx/render_text_win.h index d34c219..1b25171 100644 --- a/ui/gfx/render_text_win.h +++ b/ui/gfx/render_text_win.h @@ -8,6 +8,8 @@ #include <usp10.h> +#include <map> +#include <string> #include <vector> #include "base/memory/scoped_ptr.h" @@ -95,6 +97,9 @@ class RenderTextWin : public RenderText { void ItemizeLogicalText(); void LayoutVisualText(); + // Returns a vector of linked fonts corresponding to |font|. + const std::vector<Font>* GetLinkedFonts(const Font& font) const; + // Return the run index that contains the argument; or the length of the // |runs_| vector if argument exceeds the text length or width. size_t GetRunContainingPosition(size_t position) const; @@ -109,6 +114,9 @@ class RenderTextWin : public RenderText { // Cached HDC for performing Uniscribe API calls. static HDC cached_hdc_; + // Cached map from font names to vectors of linked fonts. + static std::map<std::string, std::vector<Font> > cached_linked_fonts_; + SCRIPT_CONTROL script_control_; SCRIPT_STATE script_state_; |