summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-28 18:14:49 +0000
committerasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-28 18:14:49 +0000
commitcb0264c4a8443578418de54ac7278fdb9efcbe3d (patch)
tree69062d0fda021d25de3bad9f2175c92041a7af24
parent1adf1eb2d340b970b1713935a8c936de1b2e2a4d (diff)
downloadchromium_src-cb0264c4a8443578418de54ac7278fdb9efcbe3d.zip
chromium_src-cb0264c4a8443578418de54ac7278fdb9efcbe3d.tar.gz
chromium_src-cb0264c4a8443578418de54ac7278fdb9efcbe3d.tar.bz2
Implement font linking for RenderTextWin.
Font linking is needed for East Asian fonts where Windows font fallback doesn't work. This change adds support for font linking by making RenderTextWin read and cache the font link lists from the registry and use these when there are missing glyphs returned from ScriptShape(). BUG=90426, 105550 TEST=Build Chrome on Windows with use_canvas_skia_skia=1. Go to http://www.google.co.jp/shopping?hl=ja. The tab title should correctly display Japanese characters and not boxes. Review URL: https://chromiumcodereview.appspot.com/9429061 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123998 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/win/registry.cc35
-rw-r--r--base/win/registry.h9
-rw-r--r--ui/gfx/render_text_win.cc85
-rw-r--r--ui/gfx/render_text_win.h8
4 files changed, 135 insertions, 2 deletions
diff --git a/base/win/registry.cc b/base/win/registry.cc
index 25499d3..c96f804 100644
--- a/base/win/registry.cc
+++ b/base/win/registry.cc
@@ -1,10 +1,11 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/win/registry.h"
#include <shlwapi.h>
+#include <algorithm>
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
@@ -216,6 +217,38 @@ LONG RegKey::ReadValue(const wchar_t* name,
return result;
}
+LONG RegKey::ReadValues(const wchar_t* name,
+ std::vector<std::wstring>* values) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ values->clear();
+
+ DWORD type = REG_MULTI_SZ;
+ DWORD size = 0;
+ LONG result = ReadValue(name, NULL, &size, NULL);
+ if (FAILED(result) || size == 0)
+ return result;
+
+ if (type != REG_MULTI_SZ)
+ return ERROR_CANTREAD;
+
+ std::vector<wchar_t> buffer(size / sizeof(wchar_t));
+ result = ReadValue(name, &buffer[0], &size, NULL);
+ if (FAILED(result) || size == 0)
+ return result;
+
+ // Parse the double-null-terminated list of strings.
+ // Note: This code is paranoid to not read outside of |buf|, in the case where
+ // it may not be properly terminated.
+ const wchar_t* entry = &buffer[0];
+ const wchar_t* buffer_end = entry + (size / sizeof(wchar_t));
+ while (entry < buffer_end && entry[0] != '\0') {
+ const wchar_t* entry_end = std::find(entry, buffer_end, L'\0');
+ values->push_back(std::wstring(entry, entry_end));
+ entry = entry_end + 1;
+ }
+ return 0;
+}
+
LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
return WriteValue(
name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD);
diff --git a/base/win/registry.h b/base/win/registry.h
index 9bc1576..abdf17a3 100644
--- a/base/win/registry.h
+++ b/base/win/registry.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,6 +8,7 @@
#include <windows.h>
#include <string>
+#include <vector>
#include "base/base_export.h"
#include "base/basictypes.h"
@@ -80,6 +81,12 @@ class BASE_EXPORT RegKey {
// value, if any.
LONG ReadValue(const wchar_t* name, std::wstring* out_value) const;
+ // Reads a REG_MULTI_SZ registry field into a vector of strings. Clears
+ // |values| initially and adds further strings to the list. Returns
+ // ERROR_CANTREAD if type is not REG_MULTI_SZ.
+ LONG RegKey::ReadValues(const wchar_t* name,
+ std::vector<std::wstring>* values);
+
// Returns raw data. If |name| is NULL or empty, returns the default
// value, if any.
LONG ReadValue(const wchar_t* name,
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_;