1 /* 2 * Copyright (C) 2006, 2007 Apple Computer, Inc. 3 * Copyright (c) 2006, 2007, 2008, 2009 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 "FontCache.h" 34 35 #include "Font.h" 36 #include "FontUtilsChromiumWin.h" 37 #include "HashMap.h" 38 #include "HashSet.h" 39 #include "PlatformBridge.h" 40 #include "SimpleFontData.h" 41 #include <unicode/uniset.h> 42 #include <wtf/text/StringHash.h> 43 44 #include <windows.h> 45 #include <objidl.h> 46 #include <mlang.h> 47 48 using std::min; 49 50 namespace WebCore 51 { 52 53 // FIXME: consider adding to WebKit String class 54 static bool charactersAreAllASCII(const String& s) 55 { 56 return WTF::charactersAreAllASCII(s.characters(), s.length()); 57 } 58 59 // When asked for a CJK font with a native name under a non-CJK locale or 60 // asked for a CJK font with a Romanized name under a CJK locale, 61 // |GetTextFace| (after |CreateFont*|) returns a 'bogus' value (e.g. Arial). 62 // This is not consistent with what MSDN says !! 63 // Therefore, before we call |CreateFont*|, we have to map a Romanized name to 64 // the corresponding native name under a CJK locale and vice versa 65 // under a non-CJK locale. 66 // See the corresponding gecko bugs at 67 // https://bugzilla.mozilla.org/show_bug.cgi?id=373952 68 // https://bugzilla.mozilla.org/show_bug.cgi?id=231426 69 static bool LookupAltName(const String& name, String& altName) 70 { 71 struct FontCodepage { 72 WCHAR* name; 73 int codePage; 74 }; 75 76 struct NamePair { 77 WCHAR* name; 78 FontCodepage altNameCodepage; 79 }; 80 81 const int japaneseCodepage = 932; 82 const int simplifiedChineseCodepage = 936; 83 const int koreanCodepage = 949; 84 const int traditionalChineseCodepage = 950; 85 86 // FIXME(jungshik) : This list probably covers 99% of cases. 87 // To cover the remaining 1% and cut down the file size, 88 // consider accessing 'NAME' table of a truetype font 89 // using |GetFontData| and caching the mapping. 90 // In the table below, the ASCII keys are all lower-cased for 91 // case-insensitive matching. 92 static const NamePair namePairs[] = { 93 // , MS PGothic 94 {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", {L"MS PGothic", japaneseCodepage}}, 95 {L"ms pgothic", {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", japaneseCodepage}}, 96 // , MS PMincho 97 {L"\xFF2D\xFF33 \xFF30\x660E\x671D", {L"MS PMincho", japaneseCodepage}}, 98 {L"ms pmincho", {L"\xFF2D\xFF33 \xFF30\x660E\x671D", japaneseCodepage}}, 99 // , MS Gothic 100 {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", {L"MS Gothic", japaneseCodepage}}, 101 {L"ms gothic", {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", japaneseCodepage}}, 102 // , MS Mincho 103 {L"\xFF2D\xFF33 \x660E\x671D", {L"MS Mincho", japaneseCodepage}}, 104 {L"ms mincho", {L"\xFF2D\xFF33 \x660E\x671D", japaneseCodepage}}, 105 // , Meiryo 106 {L"\x30E1\x30A4\x30EA\x30AA", {L"Meiryo", japaneseCodepage}}, 107 {L"meiryo", {L"\x30E1\x30A4\x30EA\x30AA", japaneseCodepage}}, 108 // , Batang 109 {L"\xBC14\xD0D5", {L"Batang", koreanCodepage}}, 110 {L"batang", {L"\xBC14\xD0D5", koreanCodepage}}, 111 // , Batangche 112 {L"\xBC14\xD0D5\xCCB4", {L"Batangche", koreanCodepage}}, 113 {L"batangche", {L"\xBC14\xD0D5\xCCB4", koreanCodepage}}, 114 // , Gulim 115 {L"\xAD74\xB9BC", {L"Gulim", koreanCodepage}}, 116 {L"gulim", {L"\xAD74\xB9BC", koreanCodepage}}, 117 // , Gulimche 118 {L"\xAD74\xB9BC\xCCB4", {L"Gulimche", koreanCodepage}}, 119 {L"gulimche", {L"\xAD74\xB9BC\xCCB4", koreanCodepage}}, 120 // , Dotum 121 {L"\xB3CB\xC6C0", {L"Dotum", koreanCodepage}}, 122 {L"dotum", {L"\xB3CB\xC6C0", koreanCodepage}}, 123 // , Dotumche 124 {L"\xB3CB\xC6C0\xCCB4", {L"Dotumche", koreanCodepage}}, 125 {L"dotumche", {L"\xB3CB\xC6C0\xCCB4", koreanCodepage}}, 126 // , Gungsuh 127 {L"\xAD81\xC11C", {L"Gungsuh", koreanCodepage}}, 128 {L"gungsuh", {L"\xAD81\xC11C", koreanCodepage}}, 129 // , Gungsuhche 130 {L"\xAD81\xC11C\xCCB4", {L"Gungsuhche", koreanCodepage}}, 131 {L"gungsuhche", {L"\xAD81\xC11C\xCCB4", koreanCodepage}}, 132 // , Malgun Gothic 133 {L"\xB9D1\xC740 \xACE0\xB515", {L"Malgun Gothic", koreanCodepage}}, 134 {L"malgun gothic", {L"\xB9D1\xC740 \xACE0\xB515", koreanCodepage}}, 135 // , SimSun 136 {L"\x5B8B\x4F53", {L"SimSun", simplifiedChineseCodepage}}, 137 {L"simsun", {L"\x5B8B\x4F53", simplifiedChineseCodepage}}, 138 // -ExtB, SimSun-ExtB 139 {L"\x5B8B\x4F53-ExtB", {L"SimSun-ExtB", simplifiedChineseCodepage}}, 140 {L"simsun-extb", {L"\x5B8B\x4F53-extb", simplifiedChineseCodepage}}, 141 // , SimHei 142 {L"\x9ED1\x4F53", {L"SimHei", simplifiedChineseCodepage}}, 143 {L"simhei", {L"\x9ED1\x4F53", simplifiedChineseCodepage}}, 144 // , NSimSun 145 {L"\x65B0\x5B8B\x4F53", {L"NSimSun", simplifiedChineseCodepage}}, 146 {L"nsimsun", {L"\x65B0\x5B8B\x4F53", simplifiedChineseCodepage}}, 147 // , Microsoft Yahei 148 {L"\x5FAE\x8F6F\x96C5\x9ED1", {L"Microsoft Yahei", simplifiedChineseCodepage}}, 149 {L"microsoft yahei", {L"\x5FAE\x8F6F\x96C5\x9ED1", simplifiedChineseCodepage}}, 150 // , FangSong 151 {L"\x4EFF\x5B8B", {L"FangSong", simplifiedChineseCodepage}}, 152 {L"fangsong", {L"\x4EFF\x5B8B", simplifiedChineseCodepage}}, 153 // , KaiTi 154 {L"\x6977\x4F53", {L"KaiTi", simplifiedChineseCodepage}}, 155 {L"kaiti", {L"\x6977\x4F53", simplifiedChineseCodepage}}, 156 // _GB2312, FangSong_GB2312 157 {L"\x4EFF\x5B8B_GB2312", {L"FangSong_GB2312", simplifiedChineseCodepage}}, 158 {L"fangsong_gb2312", {L"\x4EFF\x5B8B_gb2312", simplifiedChineseCodepage}}, 159 // _GB2312, KaiTi_GB2312 160 {L"\x6977\x4F53", {L"KaiTi_GB2312", simplifiedChineseCodepage}}, 161 {L"kaiti_gb2312", {L"\x6977\x4F53_gb2312", simplifiedChineseCodepage}}, 162 // , PMingLiu 163 {L"\x65B0\x7D30\x660E\x9AD4", {L"PMingLiu", traditionalChineseCodepage}}, 164 {L"pmingliu", {L"\x65B0\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, 165 // -ExtB, PMingLiu-ExtB 166 {L"\x65B0\x7D30\x660E\x9AD4-ExtB", {L"PMingLiu-ExtB", traditionalChineseCodepage}}, 167 {L"pmingliu-extb", {L"\x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCodepage}}, 168 // , MingLiu 169 {L"\x7D30\x660E\x9AD4", {L"MingLiu", traditionalChineseCodepage}}, 170 {L"mingliu", {L"\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, 171 // -ExtB, MingLiu-ExtB 172 {L"\x7D30\x660E\x9AD4-ExtB", {L"MingLiu-ExtB", traditionalChineseCodepage}}, 173 {L"mingliu-extb", {L"x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCodepage}}, 174 // , Microsoft JhengHei 175 {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", {L"Microsoft JhengHei", traditionalChineseCodepage}}, 176 {L"microsoft jhengHei", {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", traditionalChineseCodepage}}, 177 // , DFKai-SB 178 {L"\x6A19\x6977\x9AD4", {L"DFKai-SB", traditionalChineseCodepage}}, 179 {L"dfkai-sb", {L"\x6A19\x6977\x9AD4", traditionalChineseCodepage}}, 180 // WenQuanYi Zen Hei 181 {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", {L"WenQuanYi Zen Hei", traditionalChineseCodepage}}, 182 {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", traditionalChineseCodepage}}, 183 // WenQuanYi Zen Hei 184 {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", {L"WenQuanYi Zen Hei", simplifiedChineseCodepage}}, 185 {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", simplifiedChineseCodepage}}, 186 // AR PL ShanHeiSun Uni, 187 {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", 188 {L"AR PL ShanHeiSun Uni", traditionalChineseCodepage}}, 189 {L"ar pl shanheisun uni", 190 {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", traditionalChineseCodepage}}, 191 // AR PL ShanHeiSun Uni, 192 {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", 193 {L"AR PL ShanHeiSun Uni", simplifiedChineseCodepage}}, 194 {L"ar pl shanheisun uni", 195 {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", simplifiedChineseCodepage}}, 196 // AR PL ZenKai Uni 197 // Traditional Chinese and Simplified Chinese names are 198 // identical. 199 {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", traditionalChineseCodepage}}, 200 {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", traditionalChineseCodepage}}, 201 {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", simplifiedChineseCodepage}}, 202 {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", simplifiedChineseCodepage}}, 203 }; 204 205 typedef HashMap<String, const FontCodepage*> NameMap; 206 static NameMap* fontNameMap = 0; 207 208 if (!fontNameMap) { 209 fontNameMap = new NameMap; 210 for (size_t i = 0; i < WTF_ARRAY_LENGTH(namePairs); ++i) 211 fontNameMap->set(String(namePairs[i].name), &(namePairs[i].altNameCodepage)); 212 } 213 214 bool isAscii = false; 215 String n; 216 // use |lower| only for ASCII names 217 // For non-ASCII names, we don't want to invoke an expensive 218 // and unnecessary |lower|. 219 if (charactersAreAllASCII(name)) { 220 isAscii = true; 221 n = name.lower(); 222 } else 223 n = name; 224 225 NameMap::iterator iter = fontNameMap->find(n); 226 if (iter == fontNameMap->end()) 227 return false; 228 229 static int systemCp = ::GetACP(); 230 int fontCp = iter->second->codePage; 231 232 if ((isAscii && systemCp == fontCp) || (!isAscii && systemCp != fontCp)) { 233 altName = String(iter->second->name); 234 return true; 235 } 236 237 return false; 238 } 239 240 static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winfont, String* winName) 241 { 242 int len = min(static_cast<int>(family.length()), LF_FACESIZE - 1); 243 memcpy(winfont->lfFaceName, family.characters(), len * sizeof(WORD)); 244 winfont->lfFaceName[len] = '\0'; 245 246 HFONT hfont = CreateFontIndirect(winfont); 247 if (!hfont) 248 return 0; 249 250 HDC dc = GetDC(0); 251 HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont)); 252 WCHAR name[LF_FACESIZE]; 253 unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name); 254 if (resultLength > 0) 255 resultLength--; // ignore the null terminator 256 257 SelectObject(dc, oldFont); 258 ReleaseDC(0, dc); 259 *winName = String(name, resultLength); 260 return hfont; 261 } 262 263 // This maps font family names to their repertoires of supported Unicode 264 // characters. Because it's family names rather than font faces we use 265 // as keys, there might be edge cases where one face of a font family 266 // has a different repertoire from another face of the same family. 267 typedef HashMap<const wchar_t*, icu::UnicodeSet*> FontCmapCache; 268 269 static bool fontContainsCharacter(const FontPlatformData* fontData, 270 const wchar_t* family, UChar32 character) 271 { 272 // FIXME: For non-BMP characters, GetFontUnicodeRanges is of 273 // no use. We have to read directly from the cmap table of a font. 274 // Return true for now. 275 if (character > 0xFFFF) 276 return true; 277 278 // This cache is just leaked on shutdown. 279 static FontCmapCache* fontCmapCache = 0; 280 if (!fontCmapCache) 281 fontCmapCache = new FontCmapCache; 282 283 HashMap<const wchar_t*, icu::UnicodeSet*>::iterator it = fontCmapCache->find(family); 284 if (it != fontCmapCache->end()) 285 return it->second->contains(character); 286 287 HFONT hfont = fontData->hfont(); 288 HDC hdc = GetDC(0); 289 HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(hdc, hfont)); 290 int count = GetFontUnicodeRanges(hdc, 0); 291 if (!count && PlatformBridge::ensureFontLoaded(hfont)) 292 count = GetFontUnicodeRanges(hdc, 0); 293 if (!count) { 294 LOG_ERROR("Unable to get the font unicode range after second attempt"); 295 SelectObject(hdc, oldFont); 296 ReleaseDC(0, hdc); 297 return true; 298 } 299 300 static Vector<char, 512> glyphsetBuffer; 301 glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); 302 GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data()); 303 // In addition, refering to the OS/2 table and converting the codepage list 304 // to the coverage map might be faster. 305 count = GetFontUnicodeRanges(hdc, glyphset); 306 ASSERT(count > 0); 307 SelectObject(hdc, oldFont); 308 ReleaseDC(0, hdc); 309 310 // FIXME: consider doing either of the following two: 311 // 1) port back ICU 4.0's faster look-up code for UnicodeSet 312 // 2) port Mozilla's CompressedCharMap or gfxSparseBitset 313 unsigned i = 0; 314 icu::UnicodeSet* cmap = new icu::UnicodeSet; 315 while (i < glyphset->cRanges) { 316 WCHAR start = glyphset->ranges[i].wcLow; 317 cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1); 318 i++; 319 } 320 cmap->freeze(); 321 // We don't lowercase |family| because all of them are under our control 322 // and they're already lowercased. 323 fontCmapCache->set(family, cmap); 324 return cmap->contains(character); 325 } 326 327 // Tries the given font and save it |outFontFamilyName| if it succeeds. 328 static SimpleFontData* fontDataFromDescriptionAndLogFont(FontCache* fontCache, const FontDescription& fontDescription, const LOGFONT& font, wchar_t* outFontFamilyName) 329 { 330 SimpleFontData* fontData = fontCache->getCachedFontData(fontDescription, font.lfFaceName); 331 if (fontData) 332 memcpy(outFontFamilyName, font.lfFaceName, sizeof(font.lfFaceName)); 333 return fontData; 334 } 335 336 static LONG toGDIFontWeight(FontWeight fontWeight) 337 { 338 static LONG gdiFontWeights[] = { 339 FW_THIN, // FontWeight100 340 FW_EXTRALIGHT, // FontWeight200 341 FW_LIGHT, // FontWeight300 342 FW_NORMAL, // FontWeight400 343 FW_MEDIUM, // FontWeight500 344 FW_SEMIBOLD, // FontWeight600 345 FW_BOLD, // FontWeight700 346 FW_EXTRABOLD, // FontWeight800 347 FW_HEAVY // FontWeight900 348 }; 349 return gdiFontWeights[fontWeight]; 350 } 351 352 static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont) 353 { 354 // The size here looks unusual. The negative number is intentional. 355 // Unlike WebKit trunk, we don't multiply the size by 32. That seems to be 356 // some kind of artifact of their CG backend, or something. 357 winfont->lfHeight = -fontDescription.computedPixelSize(); 358 winfont->lfWidth = 0; 359 winfont->lfEscapement = 0; 360 winfont->lfOrientation = 0; 361 winfont->lfUnderline = false; 362 winfont->lfStrikeOut = false; 363 winfont->lfCharSet = DEFAULT_CHARSET; 364 winfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; 365 winfont->lfQuality = PlatformBridge::layoutTestMode() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY; // Honor user's desktop settings. 366 winfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; 367 winfont->lfItalic = fontDescription.italic(); 368 winfont->lfWeight = toGDIFontWeight(fontDescription.weight()); 369 } 370 371 struct TraitsInFamilyProcData { 372 TraitsInFamilyProcData(const AtomicString& familyName) 373 : m_familyName(familyName) 374 { 375 } 376 377 const AtomicString& m_familyName; 378 HashSet<unsigned> m_traitsMasks; 379 }; 380 381 static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) 382 { 383 TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam); 384 385 unsigned traitsMask = 0; 386 traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; 387 traitsMask |= FontVariantNormalMask; 388 LONG weight = logFont->lfWeight; 389 traitsMask |= weight == FW_THIN ? FontWeight100Mask : 390 weight == FW_EXTRALIGHT ? FontWeight200Mask : 391 weight == FW_LIGHT ? FontWeight300Mask : 392 weight == FW_NORMAL ? FontWeight400Mask : 393 weight == FW_MEDIUM ? FontWeight500Mask : 394 weight == FW_SEMIBOLD ? FontWeight600Mask : 395 weight == FW_BOLD ? FontWeight700Mask : 396 weight == FW_EXTRABOLD ? FontWeight800Mask : 397 FontWeight900Mask; 398 procData->m_traitsMasks.add(traitsMask); 399 return 1; 400 } 401 402 struct GetLastResortFallbackFontProcData { 403 GetLastResortFallbackFontProcData(FontCache* fontCache, const FontDescription* fontDescription, wchar_t* fontName) 404 : m_fontCache(fontCache) 405 , m_fontDescription(fontDescription) 406 , m_fontName(fontName) 407 , m_fontData(0) 408 { 409 } 410 411 FontCache* m_fontCache; 412 const FontDescription* m_fontDescription; 413 wchar_t* m_fontName; 414 SimpleFontData* m_fontData; 415 }; 416 417 static int CALLBACK getLastResortFallbackFontProc(const LOGFONT* logFont, const TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) 418 { 419 GetLastResortFallbackFontProcData* procData = reinterpret_cast<GetLastResortFallbackFontProcData*>(lParam); 420 procData->m_fontData = fontDataFromDescriptionAndLogFont(procData->m_fontCache, *procData->m_fontDescription, *logFont, procData->m_fontName); 421 return !procData->m_fontData; 422 } 423 424 void FontCache::platformInit() 425 { 426 // Not needed on Windows. 427 } 428 429 // Given the desired base font, this will create a SimpleFontData for a specific 430 // font that can be used to render the given range of characters. 431 const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) 432 { 433 // FIXME: Consider passing fontDescription.dominantScript() 434 // to GetFallbackFamily here. 435 FontDescription fontDescription = font.fontDescription(); 436 UChar32 c; 437 UScriptCode script; 438 const wchar_t* family = getFallbackFamily(characters, length, 439 fontDescription.genericFamily(), &c, &script); 440 FontPlatformData* data = 0; 441 if (family) 442 data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)), false); 443 444 // Last resort font list : PanUnicode. CJK fonts have a pretty 445 // large repertoire. Eventually, we need to scan all the fonts 446 // on the system to have a Firefox-like coverage. 447 // Make sure that all of them are lowercased. 448 const static wchar_t* const cjkFonts[] = { 449 L"arial unicode ms", 450 L"ms pgothic", 451 L"simsun", 452 L"gulim", 453 L"pmingliu", 454 L"wenquanyi zen hei", // partial CJK Ext. A coverage but more 455 // widely known to Chinese users. 456 L"ar pl shanheisun uni", 457 L"ar pl zenkai uni", 458 L"han nom a", // Complete CJK Ext. A coverage 459 L"code2000", // Complete CJK Ext. A coverage 460 // CJK Ext. B fonts are not listed here because it's of no use 461 // with our current non-BMP character handling because we use 462 // Uniscribe for it and that code path does not go through here. 463 }; 464 465 const static wchar_t* const commonFonts[] = { 466 L"tahoma", 467 L"arial unicode ms", 468 L"lucida sans unicode", 469 L"microsoft sans serif", 470 L"palatino linotype", 471 // Six fonts below (and code2000 at the end) are not from MS, but 472 // once installed, cover a very wide range of characters. 473 L"dejavu serif", 474 L"dejavu sasns", 475 L"freeserif", 476 L"freesans", 477 L"gentium", 478 L"gentiumalt", 479 L"ms pgothic", 480 L"simsun", 481 L"gulim", 482 L"pmingliu", 483 L"code2000", 484 }; 485 486 const wchar_t* const* panUniFonts = 0; 487 int numFonts = 0; 488 if (script == USCRIPT_HAN) { 489 panUniFonts = cjkFonts; 490 numFonts = WTF_ARRAY_LENGTH(cjkFonts); 491 } else { 492 panUniFonts = commonFonts; 493 numFonts = WTF_ARRAY_LENGTH(commonFonts); 494 } 495 // Font returned from GetFallbackFamily may not cover |characters| 496 // because it's based on script to font mapping. This problem is 497 // critical enough for non-Latin scripts (especially Han) to 498 // warrant an additional (real coverage) check with fontCotainsCharacter. 499 int i; 500 for (i = 0; (!data || !fontContainsCharacter(data, family, c)) && i < numFonts; ++i) { 501 family = panUniFonts[i]; 502 data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family))); 503 } 504 // When i-th font (0-base) in |panUniFonts| contains a character and 505 // we get out of the loop, |i| will be |i + 1|. That is, if only the 506 // last font in the array covers the character, |i| will be numFonts. 507 // So, we have to use '<=" rather than '<' to see if we found a font 508 // covering the character. 509 if (i <= numFonts) 510 return getCachedFontData(data); 511 512 return 0; 513 514 } 515 516 SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font) 517 { 518 return 0; 519 } 520 521 SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& description) 522 { 523 FontDescription::GenericFamilyType generic = description.genericFamily(); 524 525 // FIXME: Would be even better to somehow get the user's default font here. 526 // For now we'll pick the default that the user would get without changing 527 // any prefs. 528 static AtomicString timesStr("Times New Roman"); 529 static AtomicString courierStr("Courier New"); 530 static AtomicString arialStr("Arial"); 531 532 AtomicString& fontStr = timesStr; 533 if (generic == FontDescription::SansSerifFamily) 534 fontStr = arialStr; 535 else if (generic == FontDescription::MonospaceFamily) 536 fontStr = courierStr; 537 538 SimpleFontData* simpleFont = getCachedFontData(description, fontStr); 539 if (simpleFont) 540 return simpleFont; 541 542 // Fall back to system fonts as Win Safari does because this function must 543 // return a valid font. Once we find a valid system font, we save its name 544 // to a static variable and use it to prevent trying system fonts again. 545 static wchar_t fallbackFontName[LF_FACESIZE] = {0}; 546 if (fallbackFontName[0]) 547 return getCachedFontData(description, fallbackFontName); 548 549 // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available. 550 if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))) { 551 LOGFONT defaultGUILogFont; 552 GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont); 553 if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, defaultGUILogFont, fallbackFontName)) 554 return simpleFont; 555 } 556 557 // Fall back to Non-client metrics fonts. 558 NONCLIENTMETRICS nonClientMetrics = {0}; 559 nonClientMetrics.cbSize = sizeof(nonClientMetrics); 560 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) { 561 if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfMessageFont, fallbackFontName)) 562 return simpleFont; 563 if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfMenuFont, fallbackFontName)) 564 return simpleFont; 565 if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfStatusFont, fallbackFontName)) 566 return simpleFont; 567 if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfCaptionFont, fallbackFontName)) 568 return simpleFont; 569 if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfSmCaptionFont, fallbackFontName)) 570 return simpleFont; 571 } 572 573 // Fall back to all the fonts installed in this PC. When a font has a 574 // localized name according to the system locale as well as an English name, 575 // both GetTextFace() and EnumFontFamilies() return the localized name. So, 576 // FontCache::createFontPlatformData() does not filter out the fonts 577 // returned by this EnumFontFamilies() call. 578 HDC dc = GetDC(0); 579 if (dc) { 580 GetLastResortFallbackFontProcData procData(this, &description, fallbackFontName); 581 EnumFontFamilies(dc, 0, getLastResortFallbackFontProc, reinterpret_cast<LPARAM>(&procData)); 582 ReleaseDC(0, dc); 583 584 if (procData.m_fontData) 585 return procData.m_fontData; 586 } 587 588 ASSERT_NOT_REACHED(); 589 return 0; 590 } 591 592 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) 593 { 594 HDC hdc = GetDC(0); 595 596 LOGFONT logFont; 597 logFont.lfCharSet = DEFAULT_CHARSET; 598 unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1)); 599 memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar)); 600 logFont.lfFaceName[familyLength] = 0; 601 logFont.lfPitchAndFamily = 0; 602 603 TraitsInFamilyProcData procData(familyName); 604 EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); 605 copyToVector(procData.m_traitsMasks, traitsMasks); 606 607 ReleaseDC(0, hdc); 608 } 609 610 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) 611 { 612 LOGFONT winfont = {0}; 613 FillLogFont(fontDescription, &winfont); 614 615 // Windows will always give us a valid pointer here, even if the face name 616 // is non-existent. We have to double-check and see if the family name was 617 // really used. 618 String winName; 619 HFONT hfont = createFontIndirectAndGetWinName(family, &winfont, &winName); 620 if (!hfont) 621 return 0; 622 623 // FIXME: Do we need to use predefined fonts "guaranteed" to exist 624 // when we're running in layout-test mode? 625 if (!equalIgnoringCase(family, winName)) { 626 // For CJK fonts with both English and native names, 627 // GetTextFace returns a native name under the font's "locale" 628 // and an English name under other locales regardless of 629 // lfFaceName field of LOGFONT. As a result, we need to check 630 // if a font has an alternate name. If there is, we need to 631 // compare it with what's requested in the first place. 632 String altName; 633 if (!LookupAltName(family, altName) || 634 !equalIgnoringCase(altName, winName)) { 635 DeleteObject(hfont); 636 return 0; 637 } 638 } 639 640 return new FontPlatformData(hfont, 641 fontDescription.computedPixelSize()); 642 } 643 644 } 645