1/* 2 * Copyright (C) 2006, 2007, 2008, 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include <winsock2.h> 31#include "FontCache.h" 32#include "Font.h" 33#include "HWndDC.h" 34#include "SimpleFontData.h" 35#include <mlang.h> 36#include <windows.h> 37#include <wtf/StdLibExtras.h> 38#include <wtf/text/StringHash.h> 39#include <wtf/text/StringView.h> 40#include <wtf/win/GDIObject.h> 41 42#if USE(CG) 43#include <ApplicationServices/ApplicationServices.h> 44#include <WebKitSystemInterface/WebKitSystemInterface.h> 45#endif 46 47using std::min; 48 49namespace WebCore 50{ 51 52void FontCache::platformInit() 53{ 54#if USE(CG) 55 wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac. 56#endif 57} 58 59IMLangFontLinkType* FontCache::getFontLinkInterface() 60{ 61 static IMultiLanguage *multiLanguage; 62 if (!multiLanguage) { 63 if (CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLanguage, (void**)&multiLanguage) != S_OK) 64 return 0; 65 } 66 67 static IMLangFontLinkType* langFontLink; 68 if (!langFontLink) { 69 if (multiLanguage->QueryInterface(&langFontLink) != S_OK) 70 return 0; 71 } 72 73 return langFontLink; 74} 75 76static int CALLBACK metaFileEnumProc(HDC hdc, HANDLETABLE* table, CONST ENHMETARECORD* record, int tableEntries, LPARAM logFont) 77{ 78 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) { 79 const EMREXTCREATEFONTINDIRECTW* createFontRecord = reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record); 80 *reinterpret_cast<LOGFONT*>(logFont) = createFontRecord->elfw.elfLogFont; 81 } 82 return true; 83} 84 85static int CALLBACK linkedFontEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM hfont) 86{ 87 *reinterpret_cast<HFONT*>(hfont) = CreateFontIndirect(logFont); 88 return false; 89} 90 91static const Vector<String>* getLinkedFonts(String& family) 92{ 93 static HashMap<String, Vector<String>*> systemLinkMap; 94 Vector<String>* result = systemLinkMap.get(family); 95 if (result) 96 return result; 97 98 result = new Vector<String>; 99 systemLinkMap.set(family, result); 100 HKEY fontLinkKey; 101 if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", 0, KEY_READ, &fontLinkKey))) 102 return result; 103 104 DWORD linkedFontsBufferSize = 0; 105 RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination().data(), 0, NULL, NULL, &linkedFontsBufferSize); 106 WCHAR* linkedFonts = reinterpret_cast<WCHAR*>(malloc(linkedFontsBufferSize)); 107 if (SUCCEEDED(RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination().data(), 0, NULL, reinterpret_cast<BYTE*>(linkedFonts), &linkedFontsBufferSize))) { 108 unsigned i = 0; 109 unsigned length = linkedFontsBufferSize / sizeof(*linkedFonts); 110 while (i < length) { 111 while (i < length && linkedFonts[i] != ',') 112 i++; 113 i++; 114 unsigned j = i; 115 while (j < length && linkedFonts[j]) 116 j++; 117 result->append(String(linkedFonts + i, j - i)); 118 i = j + 1; 119 } 120 } 121 free(linkedFonts); 122 RegCloseKey(fontLinkKey); 123 return result; 124} 125 126static const Vector<DWORD, 4>& getCJKCodePageMasks() 127{ 128 // The default order in which we look for a font for a CJK character. If the user's default code page is 129 // one of these, we will use it first. 130 static const UINT CJKCodePages[] = { 131 932, /* Japanese */ 132 936, /* Simplified Chinese */ 133 950, /* Traditional Chinese */ 134 949 /* Korean */ 135 }; 136 137 static Vector<DWORD, 4> codePageMasks; 138 static bool initialized; 139 if (!initialized) { 140 initialized = true; 141 IMLangFontLinkType* langFontLink = fontCache().getFontLinkInterface(); 142 if (!langFontLink) 143 return codePageMasks; 144 145 UINT defaultCodePage; 146 DWORD defaultCodePageMask = 0; 147 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage))) 148 langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask); 149 150 if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3]) 151 codePageMasks.append(defaultCodePageMask); 152 for (unsigned i = 0; i < 4; ++i) { 153 if (defaultCodePage != CJKCodePages[i]) { 154 DWORD codePageMask; 155 langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask); 156 codePageMasks.append(codePageMask); 157 } 158 } 159 } 160 return codePageMasks; 161} 162 163static bool currentFontContainsCharacter(HDC hdc, UChar character) 164{ 165 static Vector<char, 512> glyphsetBuffer; 166 glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); 167 GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data()); 168 GetFontUnicodeRanges(hdc, glyphset); 169 170 // FIXME: Change this to a binary search. 171 unsigned i = 0; 172 while (i < glyphset->cRanges && glyphset->ranges[i].wcLow <= character) 173 i++; 174 175 return i && glyphset->ranges[i - 1].wcLow + glyphset->ranges[i - 1].cGlyphs > character; 176} 177 178static HFONT createMLangFont(IMLangFontLinkType* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0) 179{ 180 HFONT MLangFont; 181 HFONT hfont = 0; 182 if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &MLangFont)) && MLangFont) { 183 LOGFONT lf; 184 GetObject(MLangFont, sizeof(LOGFONT), &lf); 185 langFontLink->ReleaseFont(MLangFont); 186 hfont = CreateFontIndirect(&lf); 187 } 188 return hfont; 189} 190 191PassRefPtr<SimpleFontData> FontCache::systemFallbackForCharacters(const FontDescription& description, const SimpleFontData* originalFontData, bool, const UChar* characters, int length) 192{ 193 UChar character = characters[0]; 194 RefPtr<SimpleFontData> fontData; 195 HWndDC hdc(0); 196 HFONT primaryFont = originalFontData->platformData().hfont(); 197 HGDIOBJ oldFont = SelectObject(hdc, primaryFont); 198 HFONT hfont = 0; 199 200 if (IMLangFontLinkType* langFontLink = getFontLinkInterface()) { 201 // Try MLang font linking first. 202 DWORD codePages = 0; 203 langFontLink->GetCharCodePages(character, &codePages); 204 205 if (codePages && u_getIntPropertyValue(character, UCHAR_UNIFIED_IDEOGRAPH)) { 206 // The CJK character may belong to multiple code pages. We want to 207 // do font linking against a single one of them, preferring the default 208 // code page for the user's locale. 209 const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks(); 210 unsigned numCodePages = CJKCodePageMasks.size(); 211 for (unsigned i = 0; i < numCodePages && !hfont; ++i) { 212 hfont = createMLangFont(langFontLink, hdc, CJKCodePageMasks[i]); 213 if (hfont && !(codePages & CJKCodePageMasks[i])) { 214 // We asked about a code page that is not one of the code pages 215 // returned by MLang, so the font might not contain the character. 216 SelectObject(hdc, hfont); 217 if (!currentFontContainsCharacter(hdc, character)) { 218 DeleteObject(hfont); 219 hfont = 0; 220 } 221 SelectObject(hdc, primaryFont); 222 } 223 } 224 } else 225 hfont = createMLangFont(langFontLink, hdc, codePages, character); 226 } 227 228 // A font returned from MLang is trusted to contain the character. 229 bool containsCharacter = hfont; 230 231 if (!hfont) { 232 // To find out what font Uniscribe would use, we make it draw into a metafile and intercept 233 // calls to CreateFontIndirect(). 234 HDC metaFileDc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); 235 SelectObject(metaFileDc, primaryFont); 236 237 bool scriptStringOutSucceeded = false; 238 SCRIPT_STRING_ANALYSIS ssa; 239 240 // FIXME: If length is greater than 1, we actually return the font for the last character. 241 // This function should be renamed getFontDataForCharacter and take a single 32-bit character. 242 if (SUCCEEDED(ScriptStringAnalyse(metaFileDc, characters, length, 0, -1, SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, 243 0, NULL, NULL, NULL, NULL, NULL, &ssa))) { 244 scriptStringOutSucceeded = SUCCEEDED(ScriptStringOut(ssa, 0, 0, 0, NULL, 0, 0, FALSE)); 245 ScriptStringFree(&ssa); 246 } 247 HENHMETAFILE metaFile = CloseEnhMetaFile(metaFileDc); 248 if (scriptStringOutSucceeded) { 249 LOGFONT logFont; 250 logFont.lfFaceName[0] = 0; 251 EnumEnhMetaFile(0, metaFile, metaFileEnumProc, &logFont, NULL); 252 if (logFont.lfFaceName[0]) 253 hfont = CreateFontIndirect(&logFont); 254 } 255 DeleteEnhMetaFile(metaFile); 256 } 257 258 String familyName; 259 const Vector<String>* linkedFonts = 0; 260 unsigned linkedFontIndex = 0; 261 while (hfont) { 262 SelectObject(hdc, hfont); 263 WCHAR name[LF_FACESIZE]; 264 GetTextFace(hdc, LF_FACESIZE, name); 265 familyName = name; 266 267 if (containsCharacter || currentFontContainsCharacter(hdc, character)) 268 break; 269 270 if (!linkedFonts) 271 linkedFonts = getLinkedFonts(familyName); 272 SelectObject(hdc, oldFont); 273 DeleteObject(hfont); 274 hfont = 0; 275 276 if (linkedFonts->size() <= linkedFontIndex) 277 break; 278 279 LOGFONT logFont; 280 logFont.lfCharSet = DEFAULT_CHARSET; 281 StringView(linkedFonts->at(linkedFontIndex)).getCharactersWithUpconvert(logFont.lfFaceName); 282 logFont.lfFaceName[linkedFonts->at(linkedFontIndex).length()] = 0; 283 EnumFontFamiliesEx(hdc, &logFont, linkedFontEnumProc, reinterpret_cast<LPARAM>(&hfont), 0); 284 linkedFontIndex++; 285 } 286 287 if (hfont) { 288 if (!familyName.isEmpty()) { 289 FontPlatformData* result = getCachedFontPlatformData(description, familyName); 290 if (result) 291 fontData = getCachedFontData(result, DoNotRetain); 292 } 293 294 SelectObject(hdc, oldFont); 295 DeleteObject(hfont); 296 } 297 298 return fontData.release(); 299} 300 301PassRefPtr<SimpleFontData> FontCache::fontDataFromDescriptionAndLogFont(const FontDescription& fontDescription, ShouldRetain shouldRetain, const LOGFONT& font, AtomicString& outFontFamilyName) 302{ 303 AtomicString familyName = String(font.lfFaceName, wcsnlen(font.lfFaceName, LF_FACESIZE)); 304 RefPtr<SimpleFontData> fontData = getCachedFontData(fontDescription, familyName, false, shouldRetain); 305 if (fontData) 306 outFontFamilyName = familyName; 307 return fontData.release(); 308} 309 310PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& fontDescription, ShouldRetain shouldRetain) 311{ 312 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, fallbackFontName, ()); 313 if (!fallbackFontName.isEmpty()) 314 return getCachedFontData(fontDescription, fallbackFontName, false, shouldRetain); 315 316 // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick 317 // the default that the user would get without changing any prefs. 318 319 // Search all typical Windows-installed full Unicode fonts. 320 // Sorted by most to least glyphs according to http://en.wikipedia.org/wiki/Unicode_typefaces 321 // Start with Times New Roman also since it is the default if the user doesn't change prefs. 322 static AtomicString fallbackFonts[] = { 323 AtomicString("Times New Roman", AtomicString::ConstructFromLiteral), 324 AtomicString("Microsoft Sans Serif", AtomicString::ConstructFromLiteral), 325 AtomicString("Tahoma", AtomicString::ConstructFromLiteral), 326 AtomicString("Lucida Sans Unicode", AtomicString::ConstructFromLiteral), 327 AtomicString("Arial", AtomicString::ConstructFromLiteral) 328 }; 329 RefPtr<SimpleFontData> simpleFont; 330 for (size_t i = 0; i < WTF_ARRAY_LENGTH(fallbackFonts); ++i) { 331 if (simpleFont = getCachedFontData(fontDescription, fallbackFonts[i], false, shouldRetain)) { 332 fallbackFontName = fallbackFonts[i]; 333 return simpleFont.release(); 334 } 335 } 336 337 // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available. 338 if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))) { 339 LOGFONT defaultGUILogFont; 340 GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont); 341 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, defaultGUILogFont, fallbackFontName)) 342 return simpleFont.release(); 343 } 344 345 // Fall back to Non-client metrics fonts. 346 NONCLIENTMETRICS nonClientMetrics = {0}; 347 nonClientMetrics.cbSize = sizeof(nonClientMetrics); 348 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) { 349 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfMessageFont, fallbackFontName)) 350 return simpleFont.release(); 351 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfMenuFont, fallbackFontName)) 352 return simpleFont.release(); 353 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfStatusFont, fallbackFontName)) 354 return simpleFont.release(); 355 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfCaptionFont, fallbackFontName)) 356 return simpleFont.release(); 357 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfSmCaptionFont, fallbackFontName)) 358 return simpleFont.release(); 359 } 360 361 ASSERT_NOT_REACHED(); 362 return 0; 363} 364 365static LONG toGDIFontWeight(FontWeight fontWeight) 366{ 367 static LONG gdiFontWeights[] = { 368 FW_THIN, // FontWeight100 369 FW_EXTRALIGHT, // FontWeight200 370 FW_LIGHT, // FontWeight300 371 FW_NORMAL, // FontWeight400 372 FW_MEDIUM, // FontWeight500 373 FW_SEMIBOLD, // FontWeight600 374 FW_BOLD, // FontWeight700 375 FW_EXTRABOLD, // FontWeight800 376 FW_HEAVY // FontWeight900 377 }; 378 return gdiFontWeights[fontWeight]; 379} 380 381static inline bool isGDIFontWeightBold(LONG gdiFontWeight) 382{ 383 return gdiFontWeight >= FW_SEMIBOLD; 384} 385 386static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family) 387{ 388 static AtomicString lucidaStr("Lucida Grande"); 389 if (equalIgnoringCase(family, lucidaStr)) { 390 if (gdiFontWeight == FW_NORMAL) 391 return FW_MEDIUM; 392 if (gdiFontWeight == FW_BOLD) 393 return FW_SEMIBOLD; 394 } 395 return gdiFontWeight; 396} 397 398struct MatchImprovingProcData { 399 MatchImprovingProcData(LONG desiredWeight, bool desiredItalic) 400 : m_desiredWeight(desiredWeight) 401 , m_desiredItalic(desiredItalic) 402 , m_hasMatched(false) 403 { 404 } 405 406 LONG m_desiredWeight; 407 bool m_desiredItalic; 408 bool m_hasMatched; 409 LOGFONT m_chosen; 410}; 411 412static int CALLBACK matchImprovingEnumProc(CONST LOGFONT* candidate, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) 413{ 414 MatchImprovingProcData* matchData = reinterpret_cast<MatchImprovingProcData*>(lParam); 415 416 if (!matchData->m_hasMatched) { 417 matchData->m_hasMatched = true; 418 matchData->m_chosen = *candidate; 419 return 1; 420 } 421 422 if (!candidate->lfItalic != !matchData->m_chosen.lfItalic) { 423 if (!candidate->lfItalic == !matchData->m_desiredItalic) 424 matchData->m_chosen = *candidate; 425 426 return 1; 427 } 428 429 unsigned chosenWeightDeltaMagnitude = abs(matchData->m_chosen.lfWeight - matchData->m_desiredWeight); 430 unsigned candidateWeightDeltaMagnitude = abs(candidate->lfWeight - matchData->m_desiredWeight); 431 432 // If both are the same distance from the desired weight, prefer the candidate if it is further from regular. 433 if (chosenWeightDeltaMagnitude == candidateWeightDeltaMagnitude && abs(candidate->lfWeight - FW_NORMAL) > abs(matchData->m_chosen.lfWeight - FW_NORMAL)) { 434 matchData->m_chosen = *candidate; 435 return 1; 436 } 437 438 // Otherwise, prefer the one closer to the desired weight. 439 if (candidateWeightDeltaMagnitude < chosenWeightDeltaMagnitude) 440 matchData->m_chosen = *candidate; 441 442 return 1; 443} 444 445static GDIObject<HFONT> createGDIFont(const AtomicString& family, LONG desiredWeight, bool desiredItalic, int size, bool synthesizeItalic) 446{ 447 HWndDC hdc(0); 448 449 LOGFONT logFont; 450 logFont.lfCharSet = DEFAULT_CHARSET; 451 StringView truncatedFamily = StringView(family).substring(0, static_cast<unsigned>(LF_FACESIZE - 1)); 452 truncatedFamily.getCharactersWithUpconvert(logFont.lfFaceName); 453 logFont.lfFaceName[truncatedFamily.length()] = 0; 454 logFont.lfPitchAndFamily = 0; 455 456 MatchImprovingProcData matchData(desiredWeight, desiredItalic); 457 EnumFontFamiliesEx(hdc, &logFont, matchImprovingEnumProc, reinterpret_cast<LPARAM>(&matchData), 0); 458 459 if (!matchData.m_hasMatched) 460 return nullptr; 461 462 matchData.m_chosen.lfHeight = -size; 463 matchData.m_chosen.lfWidth = 0; 464 matchData.m_chosen.lfEscapement = 0; 465 matchData.m_chosen.lfOrientation = 0; 466 matchData.m_chosen.lfUnderline = false; 467 matchData.m_chosen.lfStrikeOut = false; 468 matchData.m_chosen.lfCharSet = DEFAULT_CHARSET; 469#if USE(CG) || USE(CAIRO) 470 matchData.m_chosen.lfOutPrecision = OUT_TT_ONLY_PRECIS; 471#else 472 matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS; 473#endif 474 matchData.m_chosen.lfQuality = DEFAULT_QUALITY; 475 matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; 476 477 if (desiredItalic && !matchData.m_chosen.lfItalic && synthesizeItalic) 478 matchData.m_chosen.lfItalic = 1; 479 480 auto chosenFont = adoptGDIObject(::CreateFontIndirect(&matchData.m_chosen)); 481 if (!chosenFont) 482 return nullptr; 483 484 HWndDC dc(0); 485 SaveDC(dc); 486 SelectObject(dc, chosenFont.get()); 487 WCHAR actualName[LF_FACESIZE]; 488 GetTextFace(dc, LF_FACESIZE, actualName); 489 RestoreDC(dc, -1); 490 491 if (wcsicmp(matchData.m_chosen.lfFaceName, actualName)) 492 return nullptr; 493 494 return chosenFont; 495} 496 497struct TraitsInFamilyProcData { 498 TraitsInFamilyProcData(const AtomicString& familyName) 499 : m_familyName(familyName) 500 { 501 } 502 503 const AtomicString& m_familyName; 504 HashSet<unsigned> m_traitsMasks; 505}; 506 507static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) 508{ 509 TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam); 510 511 unsigned traitsMask = 0; 512 traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; 513 traitsMask |= FontVariantNormalMask; 514 LONG weight = adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName); 515 traitsMask |= weight == FW_THIN ? FontWeight100Mask : 516 weight == FW_EXTRALIGHT ? FontWeight200Mask : 517 weight == FW_LIGHT ? FontWeight300Mask : 518 weight == FW_NORMAL ? FontWeight400Mask : 519 weight == FW_MEDIUM ? FontWeight500Mask : 520 weight == FW_SEMIBOLD ? FontWeight600Mask : 521 weight == FW_BOLD ? FontWeight700Mask : 522 weight == FW_EXTRABOLD ? FontWeight800Mask : 523 FontWeight900Mask; 524 procData->m_traitsMasks.add(traitsMask); 525 return 1; 526} 527void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) 528{ 529 HWndDC hdc(0); 530 531 LOGFONT logFont; 532 logFont.lfCharSet = DEFAULT_CHARSET; 533 StringView truncatedFamily = StringView(familyName).substring(0, static_cast<unsigned>(LF_FACESIZE - 1)); 534 truncatedFamily.getCharactersWithUpconvert(logFont.lfFaceName); 535 logFont.lfFaceName[truncatedFamily.length()] = 0; 536 logFont.lfPitchAndFamily = 0; 537 538 TraitsInFamilyProcData procData(familyName); 539 EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); 540 copyToVector(procData.m_traitsMasks, traitsMasks); 541} 542 543PassOwnPtr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) 544{ 545 bool isLucidaGrande = false; 546 static AtomicString lucidaStr("Lucida Grande"); 547 if (equalIgnoringCase(family, lucidaStr)) 548 isLucidaGrande = true; 549 550 bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande; 551 552 // The logical size constant is 32. We do this for subpixel precision when rendering using Uniscribe. 553 // This masks rounding errors related to the HFONT metrics being different from the CGFont metrics. 554 // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't 555 // look as nice. That may be solvable though. 556 LONG weight = adjustedGDIFontWeight(toGDIFontWeight(fontDescription.weight()), family); 557 auto hfont = createGDIFont(family, weight, fontDescription.italic(), 558 fontDescription.computedPixelSize() * (useGDI ? 1 : 32), useGDI); 559 560 if (!hfont) 561 return nullptr; 562 563 if (isLucidaGrande) 564 useGDI = false; // Never use GDI for Lucida Grande. 565 566 LOGFONT logFont; 567 GetObject(hfont.get(), sizeof(LOGFONT), &logFont); 568 569 bool synthesizeBold = isGDIFontWeightBold(weight) && !isGDIFontWeightBold(logFont.lfWeight); 570 bool synthesizeItalic = fontDescription.italic() && !logFont.lfItalic; 571 572 FontPlatformData* result = new FontPlatformData(WTF::move(hfont), fontDescription.computedPixelSize(), synthesizeBold, synthesizeItalic, useGDI); 573 574#if USE(CG) 575 bool fontCreationFailed = !result->cgFont(); 576#elif USE(CAIRO) 577 bool fontCreationFailed = !result->scaledFont(); 578#endif 579 580 if (fontCreationFailed) { 581 // The creation of the CGFontRef failed for some reason. We already asserted in debug builds, but to make 582 // absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next 583 // font. 584 delete result; 585 return nullptr; 586 } 587 588 return adoptPtr(result); 589} 590 591} 592