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/SimpleFontData.h" 40 #include "platform/fonts/harfbuzz/FontPlatformDataHarfbuzz.h" 41 #include "platform/fonts/win/FontFallbackWin.h" 42 43 namespace WebCore { 44 45 HashMap<String, SkTypeface*>* FontCache::s_sideloadedFonts = 0; 46 47 // static 48 void FontCache::addSideloadedFontForTesting(SkTypeface* typeface) 49 { 50 if (!s_sideloadedFonts) 51 s_sideloadedFonts = new HashMap<String, SkTypeface*>; 52 SkString name; 53 typeface->getFamilyName(&name); 54 s_sideloadedFonts->set(name.c_str(), typeface); 55 } 56 57 FontCache::FontCache() 58 : m_purgePreventCount(0) 59 { 60 SkFontMgr* fontManager; 61 62 if (s_useDirectWrite) { 63 fontManager = SkFontMgr_New_DirectWrite(s_directWriteFactory); 64 s_useSubpixelPositioning = RuntimeEnabledFeatures::subpixelFontScalingEnabled(); 65 } else { 66 fontManager = SkFontMgr_New_GDI(); 67 // Subpixel text positioning is not supported by the GDI backend. 68 s_useSubpixelPositioning = false; 69 } 70 71 ASSERT(fontManager); 72 m_fontManager = adoptPtr(fontManager); 73 } 74 75 static bool fontContainsCharacter(const FontPlatformData* fontData, const wchar_t* family, UChar32 character) 76 { 77 SkPaint paint; 78 fontData->setupPaint(&paint); 79 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); 80 81 uint16_t glyph; 82 paint.textToGlyphs(&character, sizeof(character), &glyph); 83 return glyph; 84 } 85 86 // Given the desired base font, this will create a SimpleFontData for a specific 87 // font that can be used to render the given range of characters. 88 PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 character, const SimpleFontData*) 89 { 90 // FIXME: Consider passing fontDescription.dominantScript() 91 // to GetFallbackFamily here. 92 UScriptCode script; 93 const wchar_t* family = getFallbackFamily(character, 94 fontDescription.genericFamily(), 95 &script, 96 m_fontManager.get()); 97 FontPlatformData* data = 0; 98 if (family) 99 data = getFontPlatformData(fontDescription, AtomicString(family, wcslen(family))); 100 101 // Last resort font list : PanUnicode. CJK fonts have a pretty 102 // large repertoire. Eventually, we need to scan all the fonts 103 // on the system to have a Firefox-like coverage. 104 // Make sure that all of them are lowercased. 105 const static wchar_t* const cjkFonts[] = { 106 L"arial unicode ms", 107 L"ms pgothic", 108 L"simsun", 109 L"gulim", 110 L"pmingliu", 111 L"wenquanyi zen hei", // Partial CJK Ext. A coverage but more widely known to Chinese users. 112 L"ar pl shanheisun uni", 113 L"ar pl zenkai uni", 114 L"han nom a", // Complete CJK Ext. A coverage. 115 L"code2000" // Complete CJK Ext. A coverage. 116 // CJK Ext. B fonts are not listed here because it's of no use 117 // with our current non-BMP character handling because we use 118 // Uniscribe for it and that code path does not go through here. 119 }; 120 121 const static wchar_t* const commonFonts[] = { 122 L"tahoma", 123 L"arial unicode ms", 124 L"lucida sans unicode", 125 L"microsoft sans serif", 126 L"palatino linotype", 127 // Six fonts below (and code2000 at the end) are not from MS, but 128 // once installed, cover a very wide range of characters. 129 L"dejavu serif", 130 L"dejavu sasns", 131 L"freeserif", 132 L"freesans", 133 L"gentium", 134 L"gentiumalt", 135 L"ms pgothic", 136 L"simsun", 137 L"gulim", 138 L"pmingliu", 139 L"code2000" 140 }; 141 142 const wchar_t* const* panUniFonts = 0; 143 int numFonts = 0; 144 if (script == USCRIPT_HAN) { 145 panUniFonts = cjkFonts; 146 numFonts = WTF_ARRAY_LENGTH(cjkFonts); 147 } else { 148 panUniFonts = commonFonts; 149 numFonts = WTF_ARRAY_LENGTH(commonFonts); 150 } 151 // Font returned from getFallbackFamily may not cover |character| 152 // because it's based on script to font mapping. This problem is 153 // critical enough for non-Latin scripts (especially Han) to 154 // warrant an additional (real coverage) check with fontCotainsCharacter. 155 int i; 156 for (i = 0; (!data || !fontContainsCharacter(data, family, character)) && i < numFonts; ++i) { 157 family = panUniFonts[i]; 158 data = getFontPlatformData(fontDescription, AtomicString(family, wcslen(family))); 159 } 160 161 // When i-th font (0-base) in |panUniFonts| contains a character and 162 // we get out of the loop, |i| will be |i + 1|. That is, if only the 163 // last font in the array covers the character, |i| will be numFonts. 164 // So, we have to use '<=" rather than '<' to see if we found a font 165 // covering the character. 166 if (i <= numFonts) 167 return fontDataFromFontPlatformData(data, DoNotRetain); 168 169 return nullptr; 170 } 171 172 static inline bool equalIgnoringCase(const AtomicString& a, const SkString& b) 173 { 174 return equalIgnoringCase(a, AtomicString::fromUTF8(b.c_str())); 175 } 176 177 static bool typefacesMatchesFamily(const SkTypeface* tf, const AtomicString& family) 178 { 179 SkTypeface::LocalizedStrings* actualFamilies = tf->createFamilyNameIterator(); 180 bool matchesRequestedFamily = false; 181 SkTypeface::LocalizedString actualFamily; 182 183 while (actualFamilies->next(&actualFamily)) { 184 if (equalIgnoringCase(family, actualFamily.fString)) { 185 matchesRequestedFamily = true; 186 break; 187 } 188 } 189 actualFamilies->unref(); 190 191 // getFamilyName may return a name not returned by the createFamilyNameIterator. 192 // Specifically in cases where Windows substitutes the font based on the 193 // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes registry entries. 194 if (!matchesRequestedFamily) { 195 SkString familyName; 196 tf->getFamilyName(&familyName); 197 if (equalIgnoringCase(family, familyName)) 198 matchesRequestedFamily = true; 199 } 200 201 return matchesRequestedFamily; 202 } 203 204 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, float fontSize) 205 { 206 CString name; 207 RefPtr<SkTypeface> tf = createTypeface(fontDescription, family, name); 208 if (!tf) 209 return 0; 210 211 // Windows will always give us a valid pointer here, even if the face name 212 // is non-existent. We have to double-check and see if the family name was 213 // really used. 214 // FIXME: Do we need to use predefined fonts "guaranteed" to exist 215 // when we're running in layout-test mode? 216 if (!typefacesMatchesFamily(tf.get(), family)) { 217 return 0; 218 } 219 220 FontPlatformData* result = new FontPlatformData(tf, 221 name.data(), 222 fontSize, 223 fontDescription.weight() >= FontWeightBold && !tf->isBold() || fontDescription.isSyntheticBold(), 224 fontDescription.style() == FontStyleItalic && !tf->isItalic() || fontDescription.isSyntheticItalic(), 225 fontDescription.orientation(), 226 s_useSubpixelPositioning); 227 228 struct FamilyMinSize { 229 const wchar_t* family; 230 unsigned minSize; 231 }; 232 const static FamilyMinSize minAntiAliasSizeForFont[] = { 233 { L"simsun", 16 }, 234 { L"dotum", 12 }, 235 { L"gulim", 12 } 236 }; 237 size_t numFonts = WTF_ARRAY_LENGTH(minAntiAliasSizeForFont); 238 for (size_t i = 0; i < numFonts; i++) { 239 FamilyMinSize entry = minAntiAliasSizeForFont[i]; 240 if (typefacesMatchesFamily(tf.get(), entry.family)) { 241 result->setMinSizeForAntiAlias(entry.minSize); 242 break; 243 } 244 } 245 246 return result; 247 } 248 249 } 250