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

Side by Side Diff: ui/gfx/render_text_win.cc

Issue 331713003: RenderTextHarfBuzz: Implement font fallback for Win and Linux (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments addressed 5 Created 6 years, 5 months 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/gfx/render_text_harfbuzz.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/i18n/char_iterator.h" 10 #include "base/i18n/char_iterator.h"
(...skipping 19 matching lines...) Expand all
30 const size_t kMaxUniscribeTextLength = 10000; 30 const size_t kMaxUniscribeTextLength = 10000;
31 31
32 // The initial guess and maximum supported number of runs; arbitrary values. 32 // The initial guess and maximum supported number of runs; arbitrary values.
33 // TODO(msw): Support more runs, determine a better initial guess, etc. 33 // TODO(msw): Support more runs, determine a better initial guess, etc.
34 const int kGuessRuns = 100; 34 const int kGuessRuns = 100;
35 const size_t kMaxRuns = 10000; 35 const size_t kMaxRuns = 10000;
36 36
37 // The maximum number of glyphs per run; ScriptShape fails on larger values. 37 // The maximum number of glyphs per run; ScriptShape fails on larger values.
38 const size_t kMaxGlyphs = 65535; 38 const size_t kMaxGlyphs = 65535;
39 39
40 // Callback to |EnumEnhMetaFile()| to intercept font creation.
41 int CALLBACK MetaFileEnumProc(HDC hdc,
42 HANDLETABLE* table,
43 CONST ENHMETARECORD* record,
44 int table_entries,
45 LPARAM log_font) {
46 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
47 const EMREXTCREATEFONTINDIRECTW* create_font_record =
48 reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
49 *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
50 }
51 return 1;
52 }
53
54 // Finds a fallback font to use to render the specified |text| with respect to
55 // an initial |font|. Returns the resulting font via out param |result|. Returns
56 // |true| if a fallback font was found.
57 // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
58 // TODO(asvitkine): This should be moved to font_fallback_win.cc.
59 bool ChooseFallbackFont(HDC hdc,
60 const Font& font,
61 const wchar_t* text,
62 int text_length,
63 Font* result) {
64 // Use a meta file to intercept the fallback font chosen by Uniscribe.
65 HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
66 if (!meta_file_dc)
67 return false;
68
69 SelectObject(meta_file_dc, font.GetNativeFont());
70
71 SCRIPT_STRING_ANALYSIS script_analysis;
72 HRESULT hresult =
73 ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
74 SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
75 0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
76
77 if (SUCCEEDED(hresult)) {
78 hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
79 ScriptStringFree(&script_analysis);
80 }
81
82 bool found_fallback = false;
83 HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
84 if (SUCCEEDED(hresult)) {
85 LOGFONT log_font;
86 log_font.lfFaceName[0] = 0;
87 EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
88 if (log_font.lfFaceName[0]) {
89 *result = Font(base::UTF16ToUTF8(log_font.lfFaceName),
90 font.GetFontSize());
91 found_fallback = true;
92 }
93 }
94 DeleteEnhMetaFile(meta_file);
95
96 return found_fallback;
97 }
98
99 // Changes |font| to have the specified |font_size| (or |font_height| on Windows 40 // Changes |font| to have the specified |font_size| (or |font_height| on Windows
100 // XP) and |font_style| if it is not the case already. Only considers bold and 41 // XP) and |font_style| if it is not the case already. Only considers bold and
101 // italic styles, since the underlined style has no effect on glyph shaping. 42 // italic styles, since the underlined style has no effect on glyph shaping.
102 void DeriveFontIfNecessary(int font_size, 43 void DeriveFontIfNecessary(int font_size,
103 int font_height, 44 int font_height,
104 int font_style, 45 int font_style,
105 Font* font) { 46 Font* font) {
106 const int kStyleMask = (Font::BOLD | Font::ITALIC); 47 const int kStyleMask = (Font::BOLD | Font::ITALIC);
107 const int target_style = (font_style & kStyleMask); 48 const int target_style = (font_style & kStyleMask);
108 49
(...skipping 939 matching lines...) Expand 10 before | Expand all | Expand 10 after
1048 run->width = abc.abcA + abc.abcB + abc.abcC; 989 run->width = abc.abcA + abc.abcB + abc.abcC;
1049 preceding_run_widths += run->width; 990 preceding_run_widths += run->width;
1050 } 991 }
1051 string_width_ = preceding_run_widths; 992 string_width_ = preceding_run_widths;
1052 } 993 }
1053 994
1054 void RenderTextWin::LayoutTextRun(internal::TextRun* run) { 995 void RenderTextWin::LayoutTextRun(internal::TextRun* run) {
1055 const size_t run_length = run->range.length(); 996 const size_t run_length = run->range.length();
1056 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]); 997 const wchar_t* run_text = &(GetLayoutText()[run->range.start()]);
1057 Font original_font = run->font; 998 Font original_font = run->font;
1058 LinkedFontsIterator fonts(original_font); 999 std::vector<std::string> fonts =
1000 GetFallbackFontFamilies(original_font.GetFontName());
Alexei Svitkine (slow) 2014/07/18 13:08:48 Nit: Can this be moved down right above the loop o
ckocagil 2014/07/18 15:50:11 Done.
1059 1001
1060 run->logical_clusters.reset(new WORD[run_length]); 1002 run->logical_clusters.reset(new WORD[run_length]);
1061 1003
1062 // Try to shape with the first font in the fallback list, which is 1004 // Try to shape with the first font in the fallback list, which is
1063 // |original_font|. 1005 // |original_font|.
1064 Font current_font; 1006 Font current_font(fonts[0], original_font.GetFontSize());
Alexei Svitkine (slow) 2014/07/18 13:08:48 With the suggestion above, this can just be initia
ckocagil 2014/07/18 15:50:11 Done.
1065 fonts.NextFont(&current_font);
1066 int missing_count = CountCharsWithMissingGlyphs(run, 1007 int missing_count = CountCharsWithMissingGlyphs(run,
1067 ShapeTextRunWithFont(run, current_font)); 1008 ShapeTextRunWithFont(run, current_font));
1068 if (missing_count == 0) 1009 if (missing_count == 0)
1069 return; 1010 return;
1070 1011
1071 // Keep track of the font that is able to display the greatest number of 1012 // Keep track of the font that is able to display the greatest number of
1072 // characters for which ScriptShape() returned S_OK. This font will be used 1013 // characters for which ScriptShape() returned S_OK. This font will be used
1073 // in the case where no font is able to display the entire run. 1014 // in the case where no font is able to display the entire run.
1074 int best_partial_font_missing_char_count = missing_count; 1015 int best_partial_font_missing_char_count = missing_count;
1075 Font best_partial_font = current_font; 1016 Font best_partial_font = current_font;
1076 1017
1077 // Try to shape with the cached font from previous runs, if any. 1018 // Try to shape with the cached font from previous runs, if any.
1078 std::map<std::string, Font>::const_iterator it = 1019 std::map<std::string, Font>::const_iterator it =
1079 successful_substitute_fonts_.find(original_font.GetFontName()); 1020 successful_substitute_fonts_.find(original_font.GetFontName());
1080 if (it != successful_substitute_fonts_.end()) { 1021 if (it != successful_substitute_fonts_.end()) {
1081 current_font = it->second; 1022 current_font = it->second;
1082 missing_count = CountCharsWithMissingGlyphs(run, 1023 missing_count = CountCharsWithMissingGlyphs(run,
1083 ShapeTextRunWithFont(run, current_font)); 1024 ShapeTextRunWithFont(run, current_font));
1084 if (missing_count == 0) 1025 if (missing_count == 0)
1085 return; 1026 return;
1086 if (missing_count < best_partial_font_missing_char_count) { 1027 if (missing_count < best_partial_font_missing_char_count) {
1087 best_partial_font_missing_char_count = missing_count; 1028 best_partial_font_missing_char_count = missing_count;
1088 best_partial_font = current_font; 1029 best_partial_font = current_font;
1089 } 1030 }
1090 } 1031 }
1091 1032
1092 // Try finding a fallback font using a meta file. 1033 // Try finding a fallback font using a meta file.
1093 // TODO(msw|asvitkine): Support RenderText's font_list()? 1034 // TODO(msw|asvitkine): Support RenderText's font_list()?
1094 if (ChooseFallbackFont(cached_hdc_, run->font, run_text, run_length, 1035 if (GetUniscribeFallbackFont(run->font, run_text, run_length,
1095 &current_font)) { 1036 &current_font)) {
1096 missing_count = CountCharsWithMissingGlyphs(run, 1037 missing_count = CountCharsWithMissingGlyphs(run,
1097 ShapeTextRunWithFont(run, current_font)); 1038 ShapeTextRunWithFont(run, current_font));
1098 if (missing_count == 0) { 1039 if (missing_count == 0) {
1099 successful_substitute_fonts_[original_font.GetFontName()] = current_font; 1040 successful_substitute_fonts_[original_font.GetFontName()] = current_font;
1100 return; 1041 return;
1101 } 1042 }
1102 if (missing_count < best_partial_font_missing_char_count) { 1043 if (missing_count < best_partial_font_missing_char_count) {
1103 best_partial_font_missing_char_count = missing_count; 1044 best_partial_font_missing_char_count = missing_count;
1104 best_partial_font = current_font; 1045 best_partial_font = current_font;
1105 } 1046 }
1106 } 1047 }
1107 1048
1108 // Try the rest of fonts in the fallback list. 1049 // Try the rest of fonts in the fallback list.
1109 while (fonts.NextFont(&current_font)) { 1050 for (size_t i = 1; i < fonts.size(); ++i) {
1110 missing_count = CountCharsWithMissingGlyphs(run, 1051 missing_count = CountCharsWithMissingGlyphs(run,
1111 ShapeTextRunWithFont(run, current_font)); 1052 ShapeTextRunWithFont(run, Font(fonts[i], original_font.GetFontSize())));
1112 if (missing_count == 0) { 1053 if (missing_count == 0) {
1113 successful_substitute_fonts_[original_font.GetFontName()] = current_font; 1054 successful_substitute_fonts_[original_font.GetFontName()] = current_font;
1114 return; 1055 return;
1115 } 1056 }
1116 if (missing_count < best_partial_font_missing_char_count) { 1057 if (missing_count < best_partial_font_missing_char_count) {
1117 best_partial_font_missing_char_count = missing_count; 1058 best_partial_font_missing_char_count = missing_count;
1118 best_partial_font = current_font; 1059 best_partial_font = current_font;
1119 } 1060 }
1120 } 1061 }
1121 1062
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
1281 size_t position = LayoutIndexToTextIndex(run->range.end()); 1222 size_t position = LayoutIndexToTextIndex(run->range.end());
1282 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD); 1223 position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
1283 return SelectionModel(position, CURSOR_FORWARD); 1224 return SelectionModel(position, CURSOR_FORWARD);
1284 } 1225 }
1285 1226
1286 RenderText* RenderText::CreateNativeInstance() { 1227 RenderText* RenderText::CreateNativeInstance() {
1287 return new RenderTextWin; 1228 return new RenderTextWin;
1288 } 1229 }
1289 1230
1290 } // namespace gfx 1231 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_harfbuzz.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698