OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |