Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Unified Diff: ui/gfx/render_text_win.cc

Issue 8570003: Implement font fallback in RenderTextWin, try #2. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | views/controls/textfield/native_textfield_views_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/render_text_win.cc
===================================================================
--- ui/gfx/render_text_win.cc (revision 110489)
+++ ui/gfx/render_text_win.cc (working copy)
@@ -5,15 +5,16 @@
#include "ui/gfx/render_text_win.h"
#include <algorithm>
-#include <map>
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/win/scoped_hdc.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/platform_font.h"
namespace {
@@ -62,6 +63,63 @@
}
}
+// 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()|.
+bool ChooseFallbackFont(HDC hdc,
+ const gfx::Font& font,
+ const wchar_t* text,
+ int text_length,
+ gfx::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 = gfx::Font(UTF16ToUTF8(log_font.lfFaceName), font.GetFontSize());
+ found_fallback = true;
+ }
+ }
+ DeleteEnhMetaFile(meta_file);
+
+ return found_fallback;
+}
+
} // namespace
namespace gfx {
@@ -73,16 +131,20 @@
underline(false),
width(0),
preceding_run_widths(0),
- glyph_count(0) {
+ glyph_count(0),
+ script_cache(NULL) {
}
+TextRun::~TextRun() {
+ ScriptFreeCache(&script_cache);
+}
+
} // namespace internal
RenderTextWin::RenderTextWin()
: RenderText(),
script_control_(),
script_state_(),
- script_cache_(NULL),
string_width_(0) {
// Omitting default constructors for script_* would leave POD uninitialized.
HRESULT hr = 0;
@@ -102,7 +164,6 @@
}
RenderTextWin::~RenderTextWin() {
- ScriptFreeCache(&script_cache_);
STLDeleteContainerPointers(runs_.begin(), runs_.end());
}
@@ -341,7 +402,6 @@
}
void RenderTextWin::ItemizeLogicalText() {
- text_is_dirty_ = false;
STLDeleteContainerPointers(runs_.begin(), runs_.end());
runs_.clear();
if (text().empty())
@@ -352,18 +412,18 @@
HRESULT hr = E_OUTOFMEMORY;
int script_items_count = 0;
- scoped_array<SCRIPT_ITEM> script_items;
+ std::vector<SCRIPT_ITEM> script_items;
for (size_t n = kGuessItems; hr == E_OUTOFMEMORY && n < kMaxItems; n *= 2) {
// Derive the array of Uniscribe script items from the logical text.
// ScriptItemize always adds a terminal array item so that the length of the
// last item can be derived from the terminal SCRIPT_ITEM::iCharPos.
- script_items.reset(new SCRIPT_ITEM[n]);
+ script_items.resize(n);
hr = ScriptItemize(raw_text,
text_length,
n - 1,
&script_control_,
&script_state_,
- script_items.get(),
+ &script_items[0],
&script_items_count);
}
DCHECK(SUCCEEDED(hr));
@@ -375,7 +435,7 @@
// TODO(msw): Only break for font changes, not color etc. See TextRun comment.
// TODO(msw): Apply the overriding selection and composition styles.
StyleRanges::const_iterator style = style_ranges().begin();
- SCRIPT_ITEM* script_item = script_items.get();
+ SCRIPT_ITEM* script_item = &script_items[0];
for (int run_break = 0; run_break < text_length;) {
internal::TextRun* run = new internal::TextRun();
run->range.set_start(run_break);
@@ -418,7 +478,7 @@
run->glyphs.reset(new WORD[max_glyphs]);
run->visible_attributes.reset(new SCRIPT_VISATTR[max_glyphs]);
hr = ScriptShape(hdc,
- &script_cache_,
+ &run->script_cache,
run_text,
run_length,
max_glyphs,
@@ -430,12 +490,20 @@
if (hr == E_OUTOFMEMORY) {
max_glyphs *= 2;
} else if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
- // The run's font doesn't contain the required glyphs, use an alternate.
- // TODO(msw): Font fallback... Don't use SCRIPT_UNDEFINED.
+ // TODO(msw): Don't use SCRIPT_UNDEFINED. Apparently Uniscribe can crash
+ // on certain surrogate pairs with SCRIPT_UNDEFINED.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=341500
// And http://maxradi.us/documents/uniscribe/
if (run->script_analysis.eScript == SCRIPT_UNDEFINED)
break;
+
+ // The run's font doesn't contain the required glyphs, use an alternate.
+ if (ChooseFallbackFont(hdc, run->font, run_text, run_length,
+ &run->font)) {
+ ScriptFreeCache(&run->script_cache);
+ SelectObject(hdc, run->font.GetNativeFont());
+ }
+
run->script_analysis.eScript = SCRIPT_UNDEFINED;
} else {
break;
@@ -447,7 +515,7 @@
run->advance_widths.reset(new int[run->glyph_count]);
run->offsets.reset(new GOFFSET[run->glyph_count]);
hr = ScriptPlace(hdc,
- &script_cache_,
+ &run->script_cache,
run->glyphs.get(),
run->glyph_count,
run->visible_attributes.get(),
@@ -507,7 +575,6 @@
return run;
}
-
SelectionModel RenderTextWin::FirstSelectionModelInsideRun(
internal::TextRun* run) {
size_t caret = run->range.start();
« no previous file with comments | « ui/gfx/render_text_win.h ('k') | views/controls/textfield/native_textfield_views_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698