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

Side by Side Diff: Source/platform/exported/linux/WebFontInfo.cpp

Issue 342823005: Cache character fallback information in WebFontInfo::fallbackFontForChar (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rebaselines for files with missing glyph (new code doesn't just return Arial if no glyph is found) 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
« no previous file with comments | « LayoutTests/TestExpectations ('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 /* 1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved. 2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 15 matching lines...) Expand all
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 #include "config.h" 31 #include "config.h"
32 #include "public/platform/linux/WebFontInfo.h" 32 #include "public/platform/linux/WebFontInfo.h"
33 33
34 #include "public/platform/linux/WebFallbackFont.h" 34 #include "public/platform/linux/WebFallbackFont.h"
35 #include "public/platform/linux/WebFontRenderStyle.h" 35 #include "public/platform/linux/WebFontRenderStyle.h"
36 #include "wtf/HashMap.h"
37 #include "wtf/Noncopyable.h"
38 #include "wtf/OwnPtr.h"
39 #include "wtf/PassOwnPtr.h"
40 #include "wtf/Vector.h"
41 #include "wtf/text/AtomicString.h"
42 #include "wtf/text/AtomicStringHash.h"
36 #include <fontconfig/fontconfig.h> 43 #include <fontconfig/fontconfig.h>
37 #include <string.h> 44 #include <string.h>
38 #include <unicode/utf16.h> 45 #include <unicode/utf16.h>
39 46
40 namespace blink { 47 namespace blink {
41 48
42 static bool useSubpixelPositioning = false; 49 static bool useSubpixelPositioning = false;
43 50
44 void WebFontInfo::setSubpixelPositioning(bool subpixelPositioning) 51 void WebFontInfo::setSubpixelPositioning(bool subpixelPositioning)
45 { 52 {
46 useSubpixelPositioning = subpixelPositioning; 53 useSubpixelPositioning = subpixelPositioning;
47 } 54 }
48 55
49 void WebFontInfo::fallbackFontForChar(WebUChar32 c, const char* preferredLocale, WebFallbackFont* fallbackFont) 56 class CachedFont {
57 public:
58 // Note: We pass the charset explicitly as callers
59 // should not create CachedFont entries without knowing
60 // that the FcPattern contains a valid charset.
61 CachedFont(FcPattern* pattern, FcCharSet* charSet)
62 : m_supportedCharacters(charSet)
63 {
64 ASSERT(pattern);
65 ASSERT(charSet);
66 m_fallbackFont.name = fontName(pattern);
67 m_fallbackFont.filename = fontFilename(pattern);
68 m_fallbackFont.ttcIndex = fontTtcIndex(pattern);
69 m_fallbackFont.isBold = fontIsBold(pattern);
70 m_fallbackFont.isItalic = fontIsItalic(pattern);
71 }
72 const WebFallbackFont& fallbackFont() const { return m_fallbackFont; }
73 bool hasGlyphForCharacter(WebUChar32 c)
74 {
75 return m_supportedCharacters && FcCharSetHasChar(m_supportedCharacters, c);
76 }
77
78 private:
79 static WebCString fontName(FcPattern* pattern)
80 {
81 FcChar8* familyName;
82 if (FcPatternGetString(pattern, FC_FAMILY, 0, &familyName) != FcResultMa tch)
83 return WebCString();
84
85 // FCChar8 is unsigned char, so we cast to char for WebCString.
86 const char* charFamily = reinterpret_cast<char*>(familyName);
87 return WebCString(charFamily, strlen(charFamily));
88 }
89
90 static WebCString fontFilename(FcPattern* pattern)
91 {
92 FcChar8* cFilename;
93 if (FcPatternGetString(pattern, FC_FILE, 0, &cFilename) != FcResultMatch )
94 return WebCString();
95 const char* fontFilename = reinterpret_cast<char*>(cFilename);
96 return WebCString(fontFilename, strlen(fontFilename));
97 }
98
99 static int fontTtcIndex(FcPattern* pattern)
100 {
101 int ttcIndex;
102 if (FcPatternGetInteger(pattern, FC_INDEX, 0, &ttcIndex) != FcResultMatc h && ttcIndex < 0)
103 return 0;
104 return ttcIndex;
105 }
106
107 static bool fontIsBold(FcPattern* pattern)
108 {
109 int weight;
110 if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight) != FcResultMatch )
111 return false;
112 return weight >= FC_WEIGHT_BOLD;
113 }
114
115 static bool fontIsItalic(FcPattern* pattern)
116 {
117 int slant;
118 if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant) != FcResultMatch)
119 return false;
120 return slant != FC_SLANT_ROMAN;
121 }
122
123 WebFallbackFont m_fallbackFont;
124 // m_supportedCharaters is owned by the parent
125 // FcFontSet and should never be freed.
126 FcCharSet* m_supportedCharacters;
127 };
128
129
130 class CachedFontSet {
131 WTF_MAKE_NONCOPYABLE(CachedFontSet);
132 public:
133 // CachedFontSet takes ownership of the passed FcFontSet.
134 static PassOwnPtr<CachedFontSet> createForLocale(const char* locale)
135 {
136 FcFontSet* fontSet = createFcFontSetForLocale(locale);
137 return adoptPtr(new CachedFontSet(fontSet));
138 }
139
140 ~CachedFontSet()
141 {
142 m_fallbackList.clear();
143 FcFontSetDestroy(m_fontSet);
144 }
145
146 WebFallbackFont fallbackFontForChar(WebUChar32 c)
147 {
148 Vector<CachedFont>::iterator itr = m_fallbackList.begin();
149 for (; itr != m_fallbackList.end(); itr++) {
150 if (itr->hasGlyphForCharacter(c))
151 return itr->fallbackFont();
152 }
153 // The previous code just returned garbage if the user didn't
154 // have the necessary fonts, this seems better than garbage.
155 // Current callers happen to ignore any values with an empty family stri ng.
156 return WebFallbackFont();
157 }
158
159 private:
160 static FcFontSet* createFcFontSetForLocale(const char* locale)
161 {
162 FcPattern* pattern = FcPatternCreate();
163
164 if (locale) {
165 // FcChar* is unsigned char* so we have to cast.
166 FcPatternAddString(pattern, FC_LANG, reinterpret_cast<const FcChar8* >(locale));
167 }
168
169 FcValue fcvalue;
170 fcvalue.type = FcTypeBool;
171 fcvalue.u.b = FcTrue;
172 FcPatternAdd(pattern, FC_SCALABLE, fcvalue, FcFalse);
173
174 FcConfigSubstitute(0, pattern, FcMatchPattern);
175 FcDefaultSubstitute(pattern);
176
177 if (!locale)
178 FcPatternDel(pattern, FC_LANG);
179
180 // The result parameter returns if any fonts were found.
181 // We already handle 0 fonts correctly, so we ignore the param.
182 FcResult result;
183 FcFontSet* fontSet = FcFontSort(0, pattern, 0, 0, &result);
184 FcPatternDestroy(pattern);
185
186 // The caller will take ownership of this FcFontSet.
187 return fontSet;
188 }
189
190 CachedFontSet(FcFontSet* fontSet)
191 : m_fontSet(fontSet)
192 {
193 fillFallbackList();
194 }
195
196 void fillFallbackList()
197 {
198 ASSERT(m_fallbackList.isEmpty());
199 if (!m_fontSet)
200 return;
201
202 for (int i = 0; i < m_fontSet->nfont; ++i) {
203 FcPattern* pattern = m_fontSet->fonts[i];
204
205 // Ignore any bitmap fonts users may still have installed from last century.
206 FcBool isScalable;
207 if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &isScalable) != FcResu ltMatch || !isScalable)
208 continue;
209
210 // Ignore any fonts FontConfig knows about, but that we don't have p ermission to read.
211 FcChar8* cFilename;
212 if (FcPatternGetString(pattern, FC_FILE, 0, &cFilename) != FcResultM atch)
213 continue;
214 if (access(reinterpret_cast<char*>(cFilename), R_OK))
215 continue;
216
217 // Make sure this font can tell us what characters it has glyphs for .
218 FcCharSet* charSet;
219 if (FcPatternGetCharSet(pattern, FC_CHARSET, 0, &charSet) != FcResul tMatch)
220 continue;
221
222 m_fallbackList.append(CachedFont(pattern, charSet));
223 }
224 }
225
226 FcFontSet* m_fontSet; // Owned by this object.
227 // CachedFont has a FcCharset* which points into the FcFontSet.
228 // If the FcFontSet is ever destroyed, the fallbackList
229 // must be cleared first.
230 Vector<CachedFont> m_fallbackList;
231 };
232
233 class FontSetCache {
234 public:
235 static FontSetCache& shared()
236 {
237 DEFINE_STATIC_LOCAL(FontSetCache, cache, ());
238 return cache;
239 }
240
241 WebFallbackFont fallbackFontForCharInLocale(WebUChar32 c, const char* locale )
242 {
243 DEFINE_STATIC_LOCAL(AtomicString, kNoLocale, ("NO_LOCALE_SPECIFIED"));
244 AtomicString localeKey;
245 if (locale && strlen(locale)) {
246 localeKey = AtomicString(locale);
247 } else {
248 // String hash computation the m_setsByLocale map needs
249 // a non-empty string.
250 localeKey = kNoLocale;
251 }
252
253 LocaleToCachedFont::iterator itr = m_setsByLocale.find(localeKey);
254 if (itr == m_setsByLocale.end()) {
255 OwnPtr<CachedFontSet> newEntry = CachedFontSet::createForLocale(strl en(locale) ? locale : 0);
256 return m_setsByLocale.add(localeKey, newEntry.release()).storedValue ->value->fallbackFontForChar(c);
257 }
258 return itr.get()->value->fallbackFontForChar(c);
259 }
260 // FIXME: We may wish to add a way to prune the cache at a later time.
261
262 private:
263 // FIXME: This shouldn't need to be AtomicString, but
264 // currently HashTraits<const char*> isn't smart enough
265 // to hash the string (only does pointer compares).
266 typedef HashMap<AtomicString, OwnPtr<CachedFontSet> > LocaleToCachedFont;
267 LocaleToCachedFont m_setsByLocale;
268 };
269
270 void WebFontInfo::fallbackFontForChar(WebUChar32 c, const char* locale, WebFallb ackFont* fallbackFont)
50 { 271 {
51 FcCharSet* cset = FcCharSetCreate(); 272 *fallbackFont = FontSetCache::shared().fallbackFontForCharInLocale(c, locale );
52 FcCharSetAddChar(cset, c);
53 FcPattern* pattern = FcPatternCreate();
54
55 FcValue fcvalue;
56 fcvalue.type = FcTypeCharSet;
57 fcvalue.u.c = cset;
58 FcPatternAdd(pattern, FC_CHARSET, fcvalue, FcFalse);
59
60 fcvalue.type = FcTypeBool;
61 fcvalue.u.b = FcTrue;
62 FcPatternAdd(pattern, FC_SCALABLE, fcvalue, FcFalse);
63
64 if (preferredLocale && strlen(preferredLocale)) {
65 FcLangSet* langset = FcLangSetCreate();
66 FcLangSetAdd(langset, reinterpret_cast<const FcChar8 *>(preferredLocale) );
67 FcPatternAddLangSet(pattern, FC_LANG, langset);
68 FcLangSetDestroy(langset);
69 }
70
71 FcConfigSubstitute(0, pattern, FcMatchPattern);
72 FcDefaultSubstitute(pattern);
73
74 // Default substitution reintroduces an FC_LANG entry,
75 // which causes sorting order to change.
76 if (!preferredLocale || !strlen(preferredLocale))
77 FcPatternDel(pattern, FC_LANG);
78
79 FcResult result;
80 FcFontSet* fontSet = FcFontSort(0, pattern, 0, 0, &result);
81 FcPatternDestroy(pattern);
82 FcCharSetDestroy(cset);
83
84 if (!fontSet) {
85 fallbackFont->name = WebCString();
86 fallbackFont->isBold = false;
87 fallbackFont->isItalic = false;
88 return;
89 }
90 // Older versions of fontconfig have a bug where they cannot select
91 // only scalable fonts so we have to manually filter the results.
92 for (int i = 0; i < fontSet->nfont; ++i) {
93 FcPattern* current = fontSet->fonts[i];
94 FcBool isScalable;
95
96 if (FcPatternGetBool(current, FC_SCALABLE, 0, &isScalable) != FcResultMa tch
97 || !isScalable)
98 continue;
99
100 // fontconfig can also return fonts which are unreadable
101 FcChar8* cFilename;
102 if (FcPatternGetString(current, FC_FILE, 0, &cFilename) != FcResultMatch )
103 continue;
104
105 if (access(reinterpret_cast<char*>(cFilename), R_OK))
106 continue;
107
108 const char* fontFilename = reinterpret_cast<char*>(cFilename);
109 fallbackFont->filename = WebCString(fontFilename, strlen(fontFilename));
110
111 // Index into font collection.
112 int ttcIndex;
113 if (FcPatternGetInteger(current, FC_INDEX, 0, &ttcIndex) != FcResultMatc h && ttcIndex < 0)
114 continue;
115 fallbackFont->ttcIndex = ttcIndex;
116
117 FcChar8* familyName;
118 if (FcPatternGetString(current, FC_FAMILY, 0, &familyName) == FcResultMa tch) {
119 const char* charFamily = reinterpret_cast<char*>(familyName);
120 fallbackFont->name = WebCString(charFamily, strlen(charFamily));
121 }
122 int weight;
123 if (FcPatternGetInteger(current, FC_WEIGHT, 0, &weight) == FcResultMatch )
124 fallbackFont->isBold = weight >= FC_WEIGHT_BOLD;
125 else
126 fallbackFont->isBold = false;
127 int slant;
128 if (FcPatternGetInteger(current, FC_SLANT, 0, &slant) == FcResultMatch)
129 fallbackFont->isItalic = slant != FC_SLANT_ROMAN;
130 else
131 fallbackFont->isItalic = false;
132 FcFontSetDestroy(fontSet);
133 return;
134 }
135
136 FcFontSetDestroy(fontSet);
137 } 273 }
138 274
139 void WebFontInfo::renderStyleForStrike(const char* family, int sizeAndStyle, Web FontRenderStyle* out) 275 void WebFontInfo::renderStyleForStrike(const char* family, int sizeAndStyle, Web FontRenderStyle* out)
140 { 276 {
141 bool isBold = sizeAndStyle & 1; 277 bool isBold = sizeAndStyle & 1;
142 bool isItalic = sizeAndStyle & 2; 278 bool isItalic = sizeAndStyle & 2;
143 int pixelSize = sizeAndStyle >> 2; 279 int pixelSize = sizeAndStyle >> 2;
144 280
145 FcPattern* pattern = FcPatternCreate(); 281 FcPattern* pattern = FcPatternCreate();
146 FcValue fcvalue; 282 FcValue fcvalue;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 } 349 }
214 350
215 // FontConfig doesn't provide parameters to configure whether subpixel 351 // FontConfig doesn't provide parameters to configure whether subpixel
216 // positioning should be used or not, so we just use a global setting. 352 // positioning should be used or not, so we just use a global setting.
217 out->useSubpixelPositioning = useSubpixelPositioning; 353 out->useSubpixelPositioning = useSubpixelPositioning;
218 354
219 FcPatternDestroy(match); 355 FcPatternDestroy(match);
220 } 356 }
221 357
222 } // namespace blink 358 } // namespace blink
OLDNEW
« no previous file with comments | « LayoutTests/TestExpectations ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698