1 /* 2 * Copyright (C) 2006, 2007 Apple Computer, Inc. 3 * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "config.h" 33 #include "platform/fonts/FontCache.h" 34 35 #include "SkFontMgr.h" 36 #include "SkTypeface_win.h" 37 #include "platform/RuntimeEnabledFeatures.h" 38 #include "platform/fonts/FontDescription.h" 39 #include "platform/fonts/FontFaceCreationParams.h" 40 #include "platform/fonts/FontPlatformData.h" 41 #include "platform/fonts/SimpleFontData.h" 42 #include "platform/fonts/win/FontFallbackWin.h" 43 44 namespace blink { 45 46 HashMap<String, RefPtr<SkTypeface> >* FontCache::s_sideloadedFonts = 0; 47 48 // static 49 void FontCache::addSideloadedFontForTesting(SkTypeface* typeface) 50 { 51 if (!s_sideloadedFonts) 52 s_sideloadedFonts = new HashMap<String, RefPtr<SkTypeface> >; 53 SkString name; 54 typeface->getFamilyName(&name); 55 s_sideloadedFonts->set(name.c_str(), adoptRef(typeface)); 56 } 57 58 FontCache::FontCache() 59 : m_purgePreventCount(0) 60 { 61 SkFontMgr* fontManager; 62 63 if (s_useDirectWrite) { 64 fontManager = SkFontMgr_New_DirectWrite(s_directWriteFactory); 65 s_useSubpixelPositioning = RuntimeEnabledFeatures::subpixelFontScalingEnabled(); 66 } else { 67 fontManager = SkFontMgr_New_GDI(); 68 // Subpixel text positioning is not supported by the GDI backend. 69 s_useSubpixelPositioning = false; 70 } 71 72 ASSERT(fontManager); 73 m_fontManager = adoptPtr(fontManager); 74 } 75 76 77 // Given the desired base font, this will create a SimpleFontData for a specific 78 // font that can be used to render the given range of characters. 79 PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter( 80 const FontDescription& fontDescription, UChar32 character, 81 const SimpleFontData* originalFontData) 82 { 83 // First try the specified font with standard style & weight. 84 if (fontDescription.style() == FontStyleItalic 85 || fontDescription.weight() >= FontWeightBold) { 86 RefPtr<SimpleFontData> fontData = fallbackOnStandardFontStyle( 87 fontDescription, character); 88 if (fontData) 89 return fontData; 90 } 91 92 // FIXME: Consider passing fontDescription.dominantScript() 93 // to GetFallbackFamily here. 94 UScriptCode script; 95 const wchar_t* family = getFallbackFamily(character, 96 fontDescription.genericFamily(), 97 &script, 98 m_fontManager.get()); 99 FontPlatformData* data = 0; 100 if (family) { 101 FontFaceCreationParams createByFamily(AtomicString(family, wcslen(family))); 102 data = getFontPlatformData(fontDescription, createByFamily); 103 } 104 105 // Last resort font list : PanUnicode. CJK fonts have a pretty 106 // large repertoire. Eventually, we need to scan all the fonts 107 // on the system to have a Firefox-like coverage. 108 // Make sure that all of them are lowercased. 109 const static wchar_t* const cjkFonts[] = { 110 L"arial unicode ms", 111 L"ms pgothic", 112 L"simsun", 113 L"gulim", 114 L"pmingliu", 115 L"wenquanyi zen hei", // Partial CJK Ext. A coverage but more widely known to Chinese users. 116 L"ar pl shanheisun uni", 117 L"ar pl zenkai uni", 118 L"han nom a", // Complete CJK Ext. A coverage. 119 L"code2000" // Complete CJK Ext. A coverage. 120 // CJK Ext. B fonts are not listed here because it's of no use 121 // with our current non-BMP character handling because we use 122 // Uniscribe for it and that code path does not go through here. 123 }; 124 125 const static wchar_t* const commonFonts[] = { 126 L"tahoma", 127 L"arial unicode ms", 128 L"lucida sans unicode", 129 L"microsoft sans serif", 130 L"palatino linotype", 131 // Six fonts below (and code2000 at the end) are not from MS, but 132 // once installed, cover a very wide range of characters. 133 L"dejavu serif", 134 L"dejavu sasns", 135 L"freeserif", 136 L"freesans", 137 L"gentium", 138 L"gentiumalt", 139 L"ms pgothic", 140 L"simsun", 141 L"gulim", 142 L"pmingliu", 143 L"code2000" 144 }; 145 146 const wchar_t* const* panUniFonts = 0; 147 int numFonts = 0; 148 if (script == USCRIPT_HAN) { 149 panUniFonts = cjkFonts; 150 numFonts = WTF_ARRAY_LENGTH(cjkFonts); 151 } else { 152 panUniFonts = commonFonts; 153 numFonts = WTF_ARRAY_LENGTH(commonFonts); 154 } 155 // Font returned from getFallbackFamily may not cover |character| 156 // because it's based on script to font mapping. This problem is 157 // critical enough for non-Latin scripts (especially Han) to 158 // warrant an additional (real coverage) check with fontCotainsCharacter. 159 int i; 160 for (i = 0; (!data || !data->fontContainsCharacter(character)) && i < numFonts; ++i) { 161 family = panUniFonts[i]; 162 FontFaceCreationParams createByFamily(AtomicString(family, wcslen(family))); 163 data = getFontPlatformData(fontDescription, createByFamily); 164 } 165 166 // For font fallback we want to match the subpixel behavior of the original 167 // font. Mixing subpixel and non-subpixel in the same text run looks really 168 // odd and causes problems with preferred width calculations. 169 if (data && originalFontData) { 170 const FontPlatformData& platformData = originalFontData->platformData(); 171 data->setMinSizeForAntiAlias(platformData.minSizeForAntiAlias()); 172 data->setMinSizeForSubpixel(platformData.minSizeForSubpixel()); 173 } 174 175 // When i-th font (0-base) in |panUniFonts| contains a character and 176 // we get out of the loop, |i| will be |i + 1|. That is, if only the 177 // last font in the array covers the character, |i| will be numFonts. 178 // So, we have to use '<=" rather than '<' to see if we found a font 179 // covering the character. 180 if (i <= numFonts) 181 return fontDataFromFontPlatformData(data, DoNotRetain); 182 183 return nullptr; 184 } 185 186 static inline bool equalIgnoringCase(const AtomicString& a, const SkString& b) 187 { 188 return equalIgnoringCase(a, AtomicString::fromUTF8(b.c_str())); 189 } 190 191 static bool typefacesMatchesFamily(const SkTypeface* tf, const AtomicString& family) 192 { 193 SkTypeface::LocalizedStrings* actualFamilies = tf->createFamilyNameIterator(); 194 bool matchesRequestedFamily = false; 195 SkTypeface::LocalizedString actualFamily; 196 197 while (actualFamilies->next(&actualFamily)) { 198 if (equalIgnoringCase(family, actualFamily.fString)) { 199 matchesRequestedFamily = true; 200 break; 201 } 202 } 203 actualFamilies->unref(); 204 205 // getFamilyName may return a name not returned by the createFamilyNameIterator. 206 // Specifically in cases where Windows substitutes the font based on the 207 // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes registry entries. 208 if (!matchesRequestedFamily) { 209 SkString familyName; 210 tf->getFamilyName(&familyName); 211 if (equalIgnoringCase(family, familyName)) 212 matchesRequestedFamily = true; 213 } 214 215 return matchesRequestedFamily; 216 } 217 218 static bool typefacesHasWeightSuffix(const AtomicString& family, 219 AtomicString& adjustedName, FontWeight& variantWeight) 220 { 221 struct FamilyWeightSuffix { 222 const wchar_t* suffix; 223 size_t length; 224 FontWeight weight; 225 }; 226 // Mapping from suffix to weight from the DirectWrite documentation. 227 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368082.aspx 228 const static FamilyWeightSuffix variantForSuffix[] = { 229 { L" thin", 5, FontWeight100 }, 230 { L" extralight", 11, FontWeight200 }, 231 { L" ultralight", 11, FontWeight200 }, 232 { L" light", 6, FontWeight300 }, 233 { L" medium", 7, FontWeight500 }, 234 { L" demibold", 9, FontWeight600 }, 235 { L" semibold", 9, FontWeight600 }, 236 { L" extrabold", 10, FontWeight800 }, 237 { L" ultrabold", 10, FontWeight800 }, 238 { L" black", 6, FontWeight900 }, 239 { L" heavy", 6, FontWeight900 } 240 }; 241 size_t numVariants = WTF_ARRAY_LENGTH(variantForSuffix); 242 bool caseSensitive = false; 243 for (size_t i = 0; i < numVariants; i++) { 244 const FamilyWeightSuffix& entry = variantForSuffix[i]; 245 if (family.endsWith(entry.suffix, caseSensitive)) { 246 String familyName = family.string(); 247 familyName.truncate(family.length() - entry.length); 248 adjustedName = AtomicString(familyName); 249 variantWeight = entry.weight; 250 return true; 251 } 252 } 253 254 return false; 255 } 256 257 static bool typefacesHasStretchSuffix(const AtomicString& family, 258 AtomicString& adjustedName, FontStretch& variantStretch) 259 { 260 struct FamilyStretchSuffix { 261 const wchar_t* suffix; 262 size_t length; 263 FontStretch stretch; 264 }; 265 // Mapping from suffix to stretch value from the DirectWrite documentation. 266 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368078.aspx 267 // Also includes Narrow as a synonym for Condensed to to support Arial 268 // Narrow and other fonts following the same naming scheme. 269 const static FamilyStretchSuffix variantForSuffix[] = { 270 { L" ultracondensed", 15, FontStretchUltraCondensed }, 271 { L" extracondensed", 15, FontStretchExtraCondensed }, 272 { L" condensed", 10, FontStretchCondensed }, 273 { L" narrow", 7, FontStretchCondensed }, 274 { L" semicondensed", 14, FontStretchSemiCondensed }, 275 { L" semiexpanded", 13, FontStretchSemiExpanded }, 276 { L" expanded", 9, FontStretchExpanded }, 277 { L" extraexpanded", 14, FontStretchExtraExpanded }, 278 { L" ultraexpanded", 14, FontStretchUltraExpanded } 279 }; 280 size_t numVariants = WTF_ARRAY_LENGTH(variantForSuffix); 281 bool caseSensitive = false; 282 for (size_t i = 0; i < numVariants; i++) { 283 const FamilyStretchSuffix& entry = variantForSuffix[i]; 284 if (family.endsWith(entry.suffix, caseSensitive)) { 285 String familyName = family.string(); 286 familyName.truncate(family.length() - entry.length); 287 adjustedName = AtomicString(familyName); 288 variantStretch = entry.stretch; 289 return true; 290 } 291 } 292 293 return false; 294 } 295 296 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize) 297 { 298 ASSERT(creationParams.creationType() == CreateFontByFamily); 299 300 CString name; 301 RefPtr<SkTypeface> tf = createTypeface(fontDescription, creationParams, name); 302 // Windows will always give us a valid pointer here, even if the face name 303 // is non-existent. We have to double-check and see if the family name was 304 // really used. 305 if (!tf || !typefacesMatchesFamily(tf.get(), creationParams.family())) { 306 AtomicString adjustedName; 307 FontWeight variantWeight; 308 FontStretch variantStretch; 309 310 if (typefacesHasWeightSuffix(creationParams.family(), adjustedName, 311 variantWeight)) { 312 FontFaceCreationParams adjustedParams(adjustedName); 313 FontDescription adjustedFontDescription = fontDescription; 314 adjustedFontDescription.setWeight(variantWeight); 315 tf = createTypeface(adjustedFontDescription, adjustedParams, name); 316 if (!tf || !typefacesMatchesFamily(tf.get(), adjustedName)) 317 return 0; 318 319 } else if (typefacesHasStretchSuffix(creationParams.family(), 320 adjustedName, variantStretch)) { 321 FontFaceCreationParams adjustedParams(adjustedName); 322 FontDescription adjustedFontDescription = fontDescription; 323 adjustedFontDescription.setStretch(variantStretch); 324 tf = createTypeface(adjustedFontDescription, adjustedParams, name); 325 if (!tf || !typefacesMatchesFamily(tf.get(), adjustedName)) 326 return 0; 327 328 } else { 329 return 0; 330 } 331 } 332 333 FontPlatformData* result = new FontPlatformData(tf, 334 name.data(), 335 fontSize, 336 fontDescription.weight() >= FontWeight600 && !tf->isBold() || fontDescription.isSyntheticBold(), 337 fontDescription.style() == FontStyleItalic && !tf->isItalic() || fontDescription.isSyntheticItalic(), 338 fontDescription.orientation(), 339 s_useSubpixelPositioning); 340 341 struct FamilyMinSize { 342 const wchar_t* family; 343 unsigned minSize; 344 }; 345 const static FamilyMinSize minAntiAliasSizeForFont[] = { 346 { L"simsun", 11 }, 347 { L"dotum", 12 }, 348 { L"gulim", 12 }, 349 { L"pmingliu", 11 } 350 }; 351 size_t numFonts = WTF_ARRAY_LENGTH(minAntiAliasSizeForFont); 352 for (size_t i = 0; i < numFonts; i++) { 353 FamilyMinSize entry = minAntiAliasSizeForFont[i]; 354 if (typefacesMatchesFamily(tf.get(), entry.family)) { 355 result->setMinSizeForAntiAlias(entry.minSize); 356 break; 357 } 358 } 359 360 // List of fonts that look bad with subpixel text rendering at smaller font 361 // sizes. This includes all fonts in the Microsoft Core fonts for the Web 362 // collection. 363 const static wchar_t* noSubpixelForSmallSizeFont[] = { 364 L"andale mono", 365 L"arial", 366 L"comic sans", 367 L"courier new", 368 L"georgia", 369 L"impact", 370 L"lucida console", 371 L"tahoma", 372 L"times new roman", 373 L"trebuchet ms", 374 L"verdana", 375 L"webdings" 376 }; 377 const static float minSizeForSubpixelForFont = 16.0f; 378 numFonts = WTF_ARRAY_LENGTH(noSubpixelForSmallSizeFont); 379 for (size_t i = 0; i < numFonts; i++) { 380 const wchar_t* family = noSubpixelForSmallSizeFont[i]; 381 if (typefacesMatchesFamily(tf.get(), family)) { 382 result->setMinSizeForSubpixel(minSizeForSubpixelForFont); 383 break; 384 } 385 } 386 387 return result; 388 } 389 390 } // namespace blink 391