Commit 8c17e13d authored by ckocagil@chromium.org's avatar ckocagil@chromium.org

RenderTextHarfBuzz: Implement font fallback for Win and Linux

BUG=321868

Review URL: https://codereview.chromium.org/331713003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284297 0039d316-1c4b-4281-b951-d872f2087c98
parent 79132945
...@@ -87,6 +87,9 @@ component("gfx") { ...@@ -87,6 +87,9 @@ component("gfx") {
"favicon_size.h", "favicon_size.h",
"font.cc", "font.cc",
"font.h", "font.h",
"font_fallback.h",
"font_fallback_linux.cc",
"font_fallback_mac.cc",
"font_fallback_win.cc", "font_fallback_win.cc",
"font_fallback_win.h", "font_fallback_win.h",
"font_list.cc", "font_list.cc",
...@@ -255,7 +258,7 @@ component("gfx") { ...@@ -255,7 +258,7 @@ component("gfx") {
sources += [ "render_text_ozone.cc" ] sources += [ "render_text_ozone.cc" ]
} }
} }
# iOS. # iOS.
if (is_ios) { if (is_ios) {
sources -= [ sources -= [
......
// Copyright 2014 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.
#ifndef UI_GFX_FONT_FALLBACK_H_
#define UI_GFX_FONT_FALLBACK_H_
#include <string>
#include <vector>
namespace gfx {
// Given a font family name, returns the names of font families that are
// suitable for fallback.
std::vector<std::string> GetFallbackFontFamilies(
const std::string& font_family);
} // namespace gfx
#endif // UI_GFX_FONT_FALLBACK_H_
// Copyright 2014 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 "ui/gfx/font_fallback.h"
#include <fontconfig/fontconfig.h>
#include <map>
#include <string>
#include <vector>
#include "base/lazy_instance.h"
namespace gfx {
namespace {
typedef std::map<std::string, std::vector<std::string> > FallbackCache;
base::LazyInstance<FallbackCache>::Leaky g_fallback_cache =
LAZY_INSTANCE_INITIALIZER;
} // namespace
std::vector<std::string> GetFallbackFontFamilies(
const std::string& font_family) {
std::vector<std::string>* fallback_fonts =
&g_fallback_cache.Get()[font_family];
if (!fallback_fonts->empty())
return *fallback_fonts;
FcPattern* pattern = FcPatternCreate();
FcValue family;
family.type = FcTypeString;
family.u.s = reinterpret_cast<const FcChar8*>(font_family.c_str());
FcPatternAdd(pattern, FC_FAMILY, family, FcFalse);
if (FcConfigSubstitute(NULL, pattern, FcMatchPattern) == FcTrue) {
FcDefaultSubstitute(pattern);
FcResult result;
FcFontSet* fonts = FcFontSort(NULL, pattern, FcTrue, NULL, &result);
if (fonts) {
for (int i = 0; i < fonts->nfont; ++i) {
char* name = NULL;
FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0,
reinterpret_cast<FcChar8**>(&name));
// FontConfig returns multiple fonts with the same family name and
// different configurations. Check to prevent duplicate family names.
if (fallback_fonts->empty() || fallback_fonts->back() != name)
fallback_fonts->push_back(std::string(name));
}
FcFontSetDestroy(fonts);
}
}
FcPatternDestroy(pattern);
if (fallback_fonts->empty())
fallback_fonts->push_back(font_family);
return *fallback_fonts;
}
} // namespace gfx
// Copyright 2014 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 "ui/gfx/font_fallback.h"
#include <string>
#include <vector>
#include "base/logging.h"
namespace gfx {
std::vector<std::string> GetFallbackFontFamilies(
const std::string& font_family) {
NOTIMPLEMENTED();
return std::vector<std::string>(1, font_family);
}
} // namespace gfx
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "ui/gfx/font_fallback_win.h" #include "ui/gfx/font_fallback_win.h"
#include <usp10.h>
#include <map> #include <map>
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
...@@ -12,6 +14,7 @@ ...@@ -12,6 +14,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h" #include "base/win/registry.h"
#include "ui/gfx/font.h" #include "ui/gfx/font.h"
#include "ui/gfx/font_fallback.h"
namespace gfx { namespace gfx {
...@@ -149,6 +152,20 @@ CachedFontLinkSettings::CachedFontLinkSettings() { ...@@ -149,6 +152,20 @@ CachedFontLinkSettings::CachedFontLinkSettings() {
CachedFontLinkSettings::~CachedFontLinkSettings() { CachedFontLinkSettings::~CachedFontLinkSettings() {
} }
// Callback to |EnumEnhMetaFile()| to intercept font creation.
int CALLBACK MetaFileEnumProc(HDC hdc,
HANDLETABLE* table,
CONST ENHMETARECORD* record,
int table_entries,
LPARAM log_font) {
if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
const EMREXTCREATEFONTINDIRECTW* create_font_record =
reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
*reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
}
return 1;
}
} // namespace } // namespace
namespace internal { namespace internal {
...@@ -186,8 +203,6 @@ void ParseFontFamilyString(const std::string& family, ...@@ -186,8 +203,6 @@ void ParseFontFamilyString(const std::string& family,
} }
} }
} // namespace internal
LinkedFontsIterator::LinkedFontsIterator(Font font) LinkedFontsIterator::LinkedFontsIterator(Font font)
: original_font_(font), : original_font_(font),
next_font_set_(false), next_font_set_(false),
...@@ -243,4 +258,66 @@ const std::vector<Font>* LinkedFontsIterator::GetLinkedFonts() const { ...@@ -243,4 +258,66 @@ const std::vector<Font>* LinkedFontsIterator::GetLinkedFonts() const {
return fonts; return fonts;
} }
} // namespace internal
std::vector<std::string> GetFallbackFontFamilies(
const std::string& font_family) {
// LinkedFontsIterator doesn't care about the font size, so we always pass 10.
internal::LinkedFontsIterator linked_fonts(Font(font_family, 10));
std::vector<std::string> fallback_fonts;
Font current;
while (linked_fonts.NextFont(&current))
fallback_fonts.push_back(current.GetFontName());
return fallback_fonts;
}
bool GetUniscribeFallbackFont(const Font& font,
const wchar_t* text,
int text_length,
Font* result) {
// Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
// Uniscribe doesn't expose a method to query fallback fonts, so this works by
// drawing the text to an EMF object with Uniscribe's ScriptStringOut and then
// inspecting the EMF object to figure out which font Uniscribe used.
//
// DirectWrite in Windows 8.1 provides a cleaner alternative:
// http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx
static HDC hdc = CreateCompatibleDC(NULL);
// Use a meta file to intercept the fallback font chosen by Uniscribe.
HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
if (!meta_file_dc)
return false;
SelectObject(meta_file_dc, font.GetNativeFont());
SCRIPT_STRING_ANALYSIS script_analysis;
HRESULT hresult =
ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
if (SUCCEEDED(hresult)) {
hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
ScriptStringFree(&script_analysis);
}
bool found_fallback = false;
HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
if (SUCCEEDED(hresult)) {
LOGFONT log_font;
log_font.lfFaceName[0] = 0;
EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
if (log_font.lfFaceName[0]) {
*result = Font(base::UTF16ToUTF8(log_font.lfFaceName),
font.GetFontSize());
found_fallback = true;
}
}
DeleteEnhMetaFile(meta_file);
return found_fallback;
}
} // namespace gfx } // namespace gfx
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "ui/gfx/font.h" #include "ui/gfx/font.h"
#include "ui/gfx/font_fallback.h"
namespace gfx { namespace gfx {
...@@ -29,8 +30,6 @@ void GFX_EXPORT ParseFontLinkEntry(const std::string& entry, ...@@ -29,8 +30,6 @@ void GFX_EXPORT ParseFontLinkEntry(const std::string& entry,
void GFX_EXPORT ParseFontFamilyString(const std::string& family, void GFX_EXPORT ParseFontFamilyString(const std::string& family,
std::vector<std::string>* font_names); std::vector<std::string>* font_names);
} // namespace internal
// Iterator over linked fallback fonts for a given font. The linked font chain // Iterator over linked fallback fonts for a given font. The linked font chain
// comes from the Windows registry, but gets cached between uses. // comes from the Windows registry, but gets cached between uses.
class GFX_EXPORT LinkedFontsIterator { class GFX_EXPORT LinkedFontsIterator {
...@@ -77,6 +76,16 @@ class GFX_EXPORT LinkedFontsIterator { ...@@ -77,6 +76,16 @@ class GFX_EXPORT LinkedFontsIterator {
DISALLOW_COPY_AND_ASSIGN(LinkedFontsIterator); DISALLOW_COPY_AND_ASSIGN(LinkedFontsIterator);
}; };
} // namespace internal
// Finds a fallback font to render the specified |text| with respect to an
// initial |font|. Returns the resulting font via out param |result|. Returns
// |true| if a fallback font was found.
bool GetUniscribeFallbackFont(const Font& font,
const wchar_t* text,
int text_length,
Font* result);
} // namespace gfx } // namespace gfx
#endif // UI_GFX_FONT_FALLBACK_WIN_H_ #endif // UI_GFX_FONT_FALLBACK_WIN_H_
...@@ -11,7 +11,7 @@ namespace { ...@@ -11,7 +11,7 @@ namespace {
// Subclass of LinkedFontsIterator for testing that allows mocking the linked // Subclass of LinkedFontsIterator for testing that allows mocking the linked
// fonts vector. // fonts vector.
class TestLinkedFontsIterator : public LinkedFontsIterator { class TestLinkedFontsIterator : public internal::LinkedFontsIterator {
public: public:
explicit TestLinkedFontsIterator(Font font) : LinkedFontsIterator(font) { explicit TestLinkedFontsIterator(Font font) : LinkedFontsIterator(font) {
} }
......
...@@ -160,6 +160,9 @@ ...@@ -160,6 +160,9 @@
'favicon_size.h', 'favicon_size.h',
'font.cc', 'font.cc',
'font.h', 'font.h',
'font_fallback.h',
'font_fallback_linux.cc',
'font_fallback_mac.cc',
'font_fallback_win.cc', 'font_fallback_win.cc',
'font_fallback_win.h', 'font_fallback_win.h',
'font_list.cc', 'font_list.cc',
......
...@@ -16,9 +16,14 @@ ...@@ -16,9 +16,14 @@
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkTypeface.h" #include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/font_fallback.h"
#include "ui/gfx/font_render_params.h" #include "ui/gfx/font_render_params.h"
#include "ui/gfx/utf16_indexing.h" #include "ui/gfx/utf16_indexing.h"
#if defined(OS_WIN)
#include "ui/gfx/font_fallback_win.h"
#endif
namespace gfx { namespace gfx {
namespace { namespace {
...@@ -463,14 +468,12 @@ Range TextRunHarfBuzz::CharRangeToGlyphRange(const Range& char_range) const { ...@@ -463,14 +468,12 @@ Range TextRunHarfBuzz::CharRangeToGlyphRange(const Range& char_range) const {
return Range(first, glyph_count); return Range(first, glyph_count);
} }
// Returns whether the given shaped run contains any missing glyphs. size_t TextRunHarfBuzz::CountMissingGlyphs() const {
bool TextRunHarfBuzz::HasMissingGlyphs() const {
static const int kMissingGlyphId = 0; static const int kMissingGlyphId = 0;
for (size_t i = 0; i < glyph_count; ++i) { size_t missing = 0;
if (glyphs[i] == kMissingGlyphId) for (size_t i = 0; i < glyph_count; ++i)
return true; missing += (glyphs[i] == kMissingGlyphId) ? 1 : 0;
} return missing;
return false;
} }
int TextRunHarfBuzz::GetGlyphXBoundary(size_t text_index, bool trailing) const { int TextRunHarfBuzz::GetGlyphXBoundary(size_t text_index, bool trailing) const {
...@@ -948,13 +951,54 @@ void RenderTextHarfBuzz::ItemizeText() { ...@@ -948,13 +951,54 @@ void RenderTextHarfBuzz::ItemizeText() {
} }
void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) { void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) {
const base::string16& text = GetLayoutText();
// TODO(ckocagil|yukishiino): Implement font fallback.
const Font& primary_font = font_list().GetPrimaryFont(); const Font& primary_font = font_list().GetPrimaryFont();
run->skia_face = internal::CreateSkiaTypeface(primary_font.GetFontName(), const std::string primary_font_name = primary_font.GetFontName();
run->font_style);
run->font_size = primary_font.GetFontSize(); run->font_size = primary_font.GetFontSize();
// Try shaping with |primary_font|.
ShapeRunWithFont(run, primary_font_name);
size_t best_font_missing = run->CountMissingGlyphs();
if (best_font_missing == 0)
return;
std::string best_font = primary_font_name;
#if defined(OS_WIN)
Font uniscribe_font;
const base::char16* run_text = &(GetLayoutText()[run->range.start()]);
if (GetUniscribeFallbackFont(primary_font, run_text, run->range.length(),
&uniscribe_font)) {
ShapeRunWithFont(run, uniscribe_font.GetFontName());
size_t current_missing = run->CountMissingGlyphs();
if (current_missing == 0)
return;
if (current_missing < best_font_missing) {
best_font_missing = current_missing;
best_font = uniscribe_font.GetFontName();
}
}
#endif
// Try shaping with the fonts in the fallback list except the first, which is
// |primary_font|.
std::vector<std::string> fonts = GetFallbackFontFamilies(primary_font_name);
for (size_t i = 1; i < fonts.size(); ++i) {
ShapeRunWithFont(run, fonts[i]);
size_t current_missing = run->CountMissingGlyphs();
if (current_missing == 0)
return;
if (current_missing < best_font_missing) {
best_font_missing = current_missing;
best_font = fonts[i];
}
}
ShapeRunWithFont(run, best_font);
}
void RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run,
const std::string& font_family) {
const base::string16& text = GetLayoutText();
run->skia_face = internal::CreateSkiaTypeface(font_family, run->font_style);
hb_font_t* harfbuzz_font = CreateHarfBuzzFont(run->skia_face.get(), hb_font_t* harfbuzz_font = CreateHarfBuzzFont(run->skia_face.get(),
run->font_size); run->font_size);
...@@ -967,8 +1011,7 @@ void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) { ...@@ -967,8 +1011,7 @@ void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) {
hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script)); hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script));
hb_buffer_set_direction(buffer, hb_buffer_set_direction(buffer,
run->is_rtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); run->is_rtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
// TODO(ckocagil): Should we determine the actual language? // TODO(ckocagil): Should we call |hb_buffer_set_language()| here?
hb_buffer_set_language(buffer, hb_language_get_default());
// Shape the text. // Shape the text.
hb_shape(harfbuzz_font, buffer, NULL, 0); hb_shape(harfbuzz_font, buffer, NULL, 0);
...@@ -976,12 +1019,13 @@ void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) { ...@@ -976,12 +1019,13 @@ void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) {
// Populate the run fields with the resulting glyph data in the buffer. // Populate the run fields with the resulting glyph data in the buffer.
unsigned int glyph_count = 0; unsigned int glyph_count = 0;
hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count); hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count);
hb_glyph_position_t* hb_positions = hb_buffer_get_glyph_positions(buffer,
NULL);
run->glyph_count = glyph_count; run->glyph_count = glyph_count;
hb_glyph_position_t* hb_positions =
hb_buffer_get_glyph_positions(buffer, NULL);
run->glyphs.reset(new uint16[run->glyph_count]); run->glyphs.reset(new uint16[run->glyph_count]);
run->glyph_to_char.reset(new uint32[run->glyph_count]); run->glyph_to_char.reset(new uint32[run->glyph_count]);
run->positions.reset(new SkPoint[run->glyph_count]); run->positions.reset(new SkPoint[run->glyph_count]);
run->width = 0;
for (size_t i = 0; i < run->glyph_count; ++i) { for (size_t i = 0; i < run->glyph_count; ++i) {
run->glyphs[i] = infos[i].codepoint; run->glyphs[i] = infos[i].codepoint;
run->glyph_to_char[i] = infos[i].cluster; run->glyph_to_char[i] = infos[i].cluster;
...@@ -989,7 +1033,7 @@ void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) { ...@@ -989,7 +1033,7 @@ void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) {
SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_offset)); SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_offset));
const int y_offset = const int y_offset =
SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].y_offset)); SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].y_offset));
run->positions[i].set(run->width + x_offset, -y_offset); run->positions[i].set(run->width + x_offset, y_offset);
run->width += run->width +=
SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance)); SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance));
} }
......
...@@ -29,8 +29,8 @@ struct GFX_EXPORT TextRunHarfBuzz { ...@@ -29,8 +29,8 @@ struct GFX_EXPORT TextRunHarfBuzz {
// value is in run-space (0 corresponds to the first glyph in the run). // value is in run-space (0 corresponds to the first glyph in the run).
Range CharRangeToGlyphRange(const Range& range) const; Range CharRangeToGlyphRange(const Range& range) const;
// Returns whether the given shaped run contains any missing glyphs. // Returns the number of missing glyphs in the shaped text run.
bool HasMissingGlyphs() const; size_t CountMissingGlyphs() const;
// Returns the X coordinate of the leading or |trailing| edge of the glyph // Returns the X coordinate of the leading or |trailing| edge of the glyph
// starting at |text_index|, relative to the left of the text (not the view). // starting at |text_index|, relative to the left of the text (not the view).
...@@ -112,6 +112,8 @@ class GFX_EXPORT RenderTextHarfBuzz : public RenderText { ...@@ -112,6 +112,8 @@ class GFX_EXPORT RenderTextHarfBuzz : public RenderText {
// Shape the glyphs needed for the text |run|. // Shape the glyphs needed for the text |run|.
void ShapeRun(internal::TextRunHarfBuzz* run); void ShapeRun(internal::TextRunHarfBuzz* run);
void ShapeRunWithFont(internal::TextRunHarfBuzz* run,
const std::string& font);
// Text runs in logical order. // Text runs in logical order.
ScopedVector<internal::TextRunHarfBuzz> runs_; ScopedVector<internal::TextRunHarfBuzz> runs_;
......
...@@ -37,65 +37,6 @@ const size_t kMaxRuns = 10000; ...@@ -37,65 +37,6 @@ const size_t kMaxRuns = 10000;
// The maximum number of glyphs per run; ScriptShape fails on larger values. // The maximum number of glyphs per run; ScriptShape fails on larger values.
const size_t kMaxGlyphs = 65535; const size_t kMaxGlyphs = 65535;
// Callback to |EnumEnhMetaFile()| to intercept font creation.
int CALLBACK MetaFileEnumProc(HDC hdc,
HANDLETABLE* table,
CONST ENHMETARECORD* record,
int table_entries,
LPARAM log_font) {
if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
const EMREXTCREATEFONTINDIRECTW* create_font_record =
reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
*reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
}
return 1;
}
// Finds a fallback font to use to render the specified |text| with respect to
// an initial |font|. Returns the resulting font via out param |result|. Returns
// |true| if a fallback font was found.
// Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
// TODO(asvitkine): This should be moved to font_fallback_win.cc.
bool ChooseFallbackFont(HDC hdc,
const Font& font,
const wchar_t* text,
int text_length,
Font* result) {
// Use a meta file to intercept the fallback font chosen by Uniscribe.
HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
if (!meta_file_dc)
return false;
SelectObject(meta_file_dc, font.GetNativeFont());
SCRIPT_STRING_ANALYSIS script_analysis;
HRESULT hresult =
ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
if (SUCCEEDED(hresult)) {
hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
ScriptStringFree(&script_analysis);
}
bool found_fallback = false;
HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
if (SUCCEEDED(hresult)) {
LOGFONT log_font;
log_font.lfFaceName[0] = 0;
EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
if (log_font.lfFaceName[0]) {
*result = Font(base::UTF16ToUTF8(log_font.lfFaceName),
font.GetFontSize());
found_fallback = true;
}
}
DeleteEnhMetaFile(meta_file);
return found_fallback;
}
// Changes |font| to have the specified |font_size| (or |font_height| on Windows // Changes |font| to have the specified |font_size| (or |font_height| on Windows
// XP) and |font_style| if it is not the case already. Only considers bold and // XP) and |font_style| if it is not the case already. Only considers bold and
// italic styles, since the underlined style has no effect on glyph shaping. // italic styles, since the underlined style has no effect on glyph shaping.
...@@ -1056,14 +997,11 @@ void RenderTextWin::LayoutTextRun(internal::TextRun* run) { ...@@ -1056,14 +997,11 @@ void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
const size_t run_length = run->range.length(); const size_t run_length = run->range.length();
const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
Font original_font = run->font; Font original_font = run->font;
LinkedFontsIterator fonts(original_font);
run->logical_clusters.reset(new WORD[run_length]); run->logical_clusters.reset(new WORD[run_length]);
// Try to shape with the first font in the fallback list, which is // Try shaping with |original_font|.
// |original_font|. Font current_font = original_font;
Font current_font;
fonts.NextFont(&current_font);
int missing_count = CountCharsWithMissingGlyphs(run, int missing_count = CountCharsWithMissingGlyphs(run,
ShapeTextRunWithFont(run, current_font)); ShapeTextRunWithFont(run, current_font));
if (missing_count == 0) if (missing_count == 0)
...@@ -1092,8 +1030,8 @@ void RenderTextWin::LayoutTextRun(internal::TextRun* run) { ...@@ -1092,8 +1030,8 @@ void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
// Try finding a fallback font using a meta file. // Try finding a fallback font using a meta file.
// TODO(msw|asvitkine): Support RenderText's font_list()? // TODO(msw|asvitkine): Support RenderText's font_list()?
if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length, if (GetUniscribeFallbackFont(original_font, run_text, run_length,
&current_font)) { &current_font)) {
missing_count = CountCharsWithMissingGlyphs(run, missing_count = CountCharsWithMissingGlyphs(run,
ShapeTextRunWithFont(run, current_font)); ShapeTextRunWithFont(run, current_font));
if (missing_count == 0) { if (missing_count == 0) {
...@@ -1106,10 +1044,12 @@ void RenderTextWin::LayoutTextRun(internal::TextRun* run) { ...@@ -1106,10 +1044,12 @@ void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
} }
} }
// Try the rest of fonts in the fallback list. // Try fonts in the fallback list except the first, which is |original_font|.
while (fonts.NextFont(&current_font)) { std::vector<std::string> fonts =
GetFallbackFontFamilies(original_font.GetFontName());
for (size_t i = 1; i < fonts.size(); ++i) {
missing_count = CountCharsWithMissingGlyphs(run, missing_count = CountCharsWithMissingGlyphs(run,
ShapeTextRunWithFont(run, current_font)); ShapeTextRunWithFont(run, Font(fonts[i], original_font.GetFontSize())));
if (missing_count == 0) { if (missing_count == 0) {
successful_substitute_fonts_[original_font.GetFontName()] = current_font; successful_substitute_fonts_[original_font.GetFontName()] = current_font;
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment