1/* 2 * Copyright (C) 2006, 2007, 2008 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 Computer, 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 "UnicodeRange.h" 36#include <mlang.h> 37#include <windows.h> 38#include <wtf/StdLibExtras.h> 39#include <wtf/text/StringHash.h> 40#if USE(CG) 41#include <ApplicationServices/ApplicationServices.h> 42#include <WebKitSystemInterface/WebKitSystemInterface.h> 43#endif 44 45using std::min; 46 47namespace WebCore 48{ 49 50void FontCache::platformInit() 51{ 52#if USE(CG) 53 wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac. 54#endif 55} 56 57IMLangFontLinkType* FontCache::getFontLinkInterface() 58{ 59 static IMultiLanguage *multiLanguage; 60 if (!multiLanguage) { 61 if (CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLanguage, (void**)&multiLanguage) != S_OK) 62 return 0; 63 } 64 65 static IMLangFontLinkType* langFontLink; 66 if (!langFontLink) { 67 if (multiLanguage->QueryInterface(&langFontLink) != S_OK) 68 return 0; 69 } 70 71 return langFontLink; 72} 73 74static int CALLBACK metaFileEnumProc(HDC hdc, HANDLETABLE* table, CONST ENHMETARECORD* record, int tableEntries, LPARAM logFont) 75{ 76 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) { 77 const EMREXTCREATEFONTINDIRECTW* createFontRecord = reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record); 78 *reinterpret_cast<LOGFONT*>(logFont) = createFontRecord->elfw.elfLogFont; 79 } 80 return true; 81} 82 83static int CALLBACK linkedFontEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM hfont) 84{ 85 *reinterpret_cast<HFONT*>(hfont) = CreateFontIndirect(logFont); 86 return false; 87} 88 89static const Vector<String>* getLinkedFonts(String& family) 90{ 91 static HashMap<String, Vector<String>*> systemLinkMap; 92 Vector<String>* result = systemLinkMap.get(family); 93 if (result) 94 return result; 95 96 result = new Vector<String>; 97 systemLinkMap.set(family, result); 98 HKEY fontLinkKey; 99 if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", 0, KEY_READ, &fontLinkKey))) 100 return result; 101 102 DWORD linkedFontsBufferSize = 0; 103 RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, NULL, &linkedFontsBufferSize); 104 WCHAR* linkedFonts = reinterpret_cast<WCHAR*>(malloc(linkedFontsBufferSize)); 105 if (SUCCEEDED(RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, reinterpret_cast<BYTE*>(linkedFonts), &linkedFontsBufferSize))) { 106 unsigned i = 0; 107 unsigned length = linkedFontsBufferSize / sizeof(*linkedFonts); 108 while (i < length) { 109 while (i < length && linkedFonts[i] != ',') 110 i++; 111 i++; 112 unsigned j = i; 113 while (j < length && linkedFonts[j]) 114 j++; 115 result->append(String(linkedFonts + i, j - i)); 116 i = j + 1; 117 } 118 } 119 free(linkedFonts); 120 RegCloseKey(fontLinkKey); 121 return result; 122} 123 124static const Vector<DWORD, 4>& getCJKCodePageMasks() 125{ 126 // The default order in which we look for a font for a CJK character. If the user's default code page is 127 // one of these, we will use it first. 128 static const UINT CJKCodePages[] = { 129 932, /* Japanese */ 130 936, /* Simplified Chinese */ 131 950, /* Traditional Chinese */ 132 949 /* Korean */ 133 }; 134 135 static Vector<DWORD, 4> codePageMasks; 136 static bool initialized; 137 if (!initialized) { 138 initialized = true; 139 IMLangFontLinkType* langFontLink = fontCache()->getFontLinkInterface(); 140 if (!langFontLink) 141 return codePageMasks; 142 143 UINT defaultCodePage; 144 DWORD defaultCodePageMask = 0; 145 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage))) 146 langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask); 147 148 if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3]) 149 codePageMasks.append(defaultCodePageMask); 150 for (unsigned i = 0; i < 4; ++i) { 151 if (defaultCodePage != CJKCodePages[i]) { 152 DWORD codePageMask; 153 langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask); 154 codePageMasks.append(codePageMask); 155 } 156 } 157 } 158 return codePageMasks; 159} 160 161static bool currentFontContainsCharacter(HDC hdc, UChar character) 162{ 163 static Vector<char, 512> glyphsetBuffer; 164 glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); 165 GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data()); 166 GetFontUnicodeRanges(hdc, glyphset); 167 168 // FIXME: Change this to a binary search. 169 unsigned i = 0; 170 while (i < glyphset->cRanges && glyphset->ranges[i].wcLow <= character) 171 i++; 172 173 return i && glyphset->ranges[i - 1].wcLow + glyphset->ranges[i - 1].cGlyphs > character; 174} 175 176static HFONT createMLangFont(IMLangFontLinkType* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0) 177{ 178 HFONT MLangFont; 179 HFONT hfont = 0; 180 if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &MLangFont)) && MLangFont) { 181 LOGFONT lf; 182 GetObject(MLangFont, sizeof(LOGFONT), &lf); 183 langFontLink->ReleaseFont(MLangFont); 184 hfont = CreateFontIndirect(&lf); 185 } 186 return hfont; 187} 188 189PassRefPtr<SimpleFontData> FontCache::systemFallbackForCharacters(const FontDescription& description, const SimpleFontData* originalFontData, bool, const UChar* characters, int length) 190{ 191 UChar character = characters[0]; 192 RefPtr<SimpleFontData> fontData; 193 HWndDC hdc(0); 194 HFONT primaryFont = originalFontData->platformData().hfont(); 195 HGDIOBJ oldFont = SelectObject(hdc, primaryFont); 196 HFONT hfont = 0; 197 198 if (IMLangFontLinkType* langFontLink = getFontLinkInterface()) { 199 // Try MLang font linking first. 200 DWORD codePages = 0; 201 langFontLink->GetCharCodePages(character, &codePages); 202 203 if (codePages && findCharUnicodeRange(character) == cRangeSetCJK) { 204 // The CJK character may belong to multiple code pages. We want to 205 // do font linking against a single one of them, preferring the default 206 // code page for the user's locale. 207 const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks(); 208 unsigned numCodePages = CJKCodePageMasks.size(); 209 for (unsigned i = 0; i < numCodePages && !hfont; ++i) { 210 hfont = createMLangFont(langFontLink, hdc, CJKCodePageMasks[i]); 211 if (hfont && !(codePages & CJKCodePageMasks[i])) { 212 // We asked about a code page that is not one of the code pages 213 // returned by MLang, so the font might not contain the character. 214 SelectObject(hdc, hfont); 215 if (!currentFontContainsCharacter(hdc, character)) { 216 DeleteObject(hfont); 217 hfont = 0; 218 } 219 SelectObject(hdc, primaryFont); 220 } 221 } 222 } else 223 hfont = createMLangFont(langFontLink, hdc, codePages, character); 224 } 225 226 // A font returned from MLang is trusted to contain the character. 227 bool containsCharacter = hfont; 228 229 if (!hfont) { 230 // To find out what font Uniscribe would use, we make it draw into a metafile and intercept 231 // calls to CreateFontIndirect(). 232 HDC metaFileDc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); 233 SelectObject(metaFileDc, primaryFont); 234 235 bool scriptStringOutSucceeded = false; 236 SCRIPT_STRING_ANALYSIS ssa; 237 238 // FIXME: If length is greater than 1, we actually return the font for the last character. 239 // This function should be renamed getFontDataForCharacter and take a single 32-bit character. 240 if (SUCCEEDED(ScriptStringAnalyse(metaFileDc, characters, length, 0, -1, SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, 241 0, NULL, NULL, NULL, NULL, NULL, &ssa))) { 242 scriptStringOutSucceeded = SUCCEEDED(ScriptStringOut(ssa, 0, 0, 0, NULL, 0, 0, FALSE)); 243 ScriptStringFree(&ssa); 244 } 245 HENHMETAFILE metaFile = CloseEnhMetaFile(metaFileDc); 246 if (scriptStringOutSucceeded) { 247 LOGFONT logFont; 248 logFont.lfFaceName[0] = 0; 249 EnumEnhMetaFile(0, metaFile, metaFileEnumProc, &logFont, NULL); 250 if (logFont.lfFaceName[0]) 251 hfont = CreateFontIndirect(&logFont); 252 } 253 DeleteEnhMetaFile(metaFile); 254 } 255 256 String familyName; 257 const Vector<String>* linkedFonts = 0; 258 unsigned linkedFontIndex = 0; 259 while (hfont) { 260 SelectObject(hdc, hfont); 261 WCHAR name[LF_FACESIZE]; 262 GetTextFace(hdc, LF_FACESIZE, name); 263 familyName = name; 264 265 if (containsCharacter || currentFontContainsCharacter(hdc, character)) 266 break; 267 268 if (!linkedFonts) 269 linkedFonts = getLinkedFonts(familyName); 270 SelectObject(hdc, oldFont); 271 DeleteObject(hfont); 272 hfont = 0; 273 274 if (linkedFonts->size() <= linkedFontIndex) 275 break; 276 277 LOGFONT logFont; 278 logFont.lfCharSet = DEFAULT_CHARSET; 279 memcpy(logFont.lfFaceName, linkedFonts->at(linkedFontIndex).characters(), linkedFonts->at(linkedFontIndex).length() * sizeof(WCHAR)); 280 logFont.lfFaceName[linkedFonts->at(linkedFontIndex).length()] = 0; 281 EnumFontFamiliesEx(hdc, &logFont, linkedFontEnumProc, reinterpret_cast<LPARAM>(&hfont), 0); 282 linkedFontIndex++; 283 } 284 285 if (hfont) { 286 if (!familyName.isEmpty()) { 287 FontPlatformData* result = getCachedFontPlatformData(description, familyName); 288 if (result) 289 fontData = getCachedFontData(result, DoNotRetain); 290 } 291 292 SelectObject(hdc, oldFont); 293 DeleteObject(hfont); 294 } 295 296 return fontData.release(); 297} 298 299PassRefPtr<SimpleFontData> FontCache::fontDataFromDescriptionAndLogFont(const FontDescription& fontDescription, ShouldRetain shouldRetain, const LOGFONT& font, AtomicString& outFontFamilyName) 300{ 301 AtomicString familyName = String(font.lfFaceName, wcsnlen(font.lfFaceName, LF_FACESIZE)); 302 RefPtr<SimpleFontData> fontData = getCachedFontData(fontDescription, familyName, false, shouldRetain); 303 if (fontData) 304 outFontFamilyName = familyName; 305 return fontData.release(); 306} 307 308PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& fontDescription, ShouldRetain shouldRetain) 309{ 310 DEFINE_STATIC_LOCAL(AtomicString, fallbackFontName, ()); 311 if (!fallbackFontName.isEmpty()) 312 return getCachedFontData(fontDescription, fallbackFontName, false, shouldRetain); 313 314 // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick 315 // the default that the user would get without changing any prefs. 316 317 // Search all typical Windows-installed full Unicode fonts. 318 // Sorted by most to least glyphs according to http://en.wikipedia.org/wiki/Unicode_typefaces 319 // Start with Times New Roman also since it is the default if the user doesn't change prefs. 320 static AtomicString fallbackFonts[] = { 321 AtomicString("Times New Roman", AtomicString::ConstructFromLiteral), 322 AtomicString("Microsoft Sans Serif", AtomicString::ConstructFromLiteral), 323 AtomicString("Tahoma", AtomicString::ConstructFromLiteral), 324 AtomicString("Lucida Sans Unicode", AtomicString::ConstructFromLiteral), 325 AtomicString("Arial", AtomicString::ConstructFromLiteral) 326 }; 327 RefPtr<SimpleFontData> simpleFont; 328 for (size_t i = 0; i < WTF_ARRAY_LENGTH(fallbackFonts); ++i) { 329 if (simpleFont = getCachedFontData(fontDescription, fallbackFonts[i], false, shouldRetain)) { 330 fallbackFontName = fallbackFonts[i]; 331 return simpleFont.release(); 332 } 333 } 334 335 // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available. 336 if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))) { 337 LOGFONT defaultGUILogFont; 338 GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont); 339 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, defaultGUILogFont, fallbackFontName)) 340 return simpleFont.release(); 341 } 342 343 // Fall back to Non-client metrics fonts. 344 NONCLIENTMETRICS nonClientMetrics = {0}; 345 nonClientMetrics.cbSize = sizeof(nonClientMetrics); 346 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) { 347 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfMessageFont, fallbackFontName)) 348 return simpleFont.release(); 349 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfMenuFont, fallbackFontName)) 350 return simpleFont.release(); 351 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfStatusFont, fallbackFontName)) 352 return simpleFont.release(); 353 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfCaptionFont, fallbackFontName)) 354 return simpleFont.release(); 355 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shouldRetain, nonClientMetrics.lfSmCaptionFont, fallbackFontName)) 356 return simpleFont.release(); 357 } 358 359 ASSERT_NOT_REACHED(); 360 return 0; 361} 362 363static LONG toGDIFontWeight(FontWeight fontWeight) 364{ 365 static LONG gdiFontWeights[] = { 366 FW_THIN, // FontWeight100 367 FW_EXTRALIGHT, // FontWeight200 368 FW_LIGHT, // FontWeight300 369 FW_NORMAL, // FontWeight400 370 FW_MEDIUM, // FontWeight500 371 FW_SEMIBOLD, // FontWeight600 372 FW_BOLD, // FontWeight700 373 FW_EXTRABOLD, // FontWeight800 374 FW_HEAVY // FontWeight900 375 }; 376 return gdiFontWeights[fontWeight]; 377} 378 379static inline bool isGDIFontWeightBold(LONG gdiFontWeight) 380{ 381 return gdiFontWeight >= FW_SEMIBOLD; 382} 383 384static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family) 385{ 386 static AtomicString lucidaStr("Lucida Grande"); 387 if (equalIgnoringCase(family, lucidaStr)) { 388 if (gdiFontWeight == FW_NORMAL) 389 return FW_MEDIUM; 390 if (gdiFontWeight == FW_BOLD) 391 return FW_SEMIBOLD; 392 } 393 return gdiFontWeight; 394} 395 396struct MatchImprovingProcData { 397 MatchImprovingProcData(LONG desiredWeight, bool desiredItalic) 398 : m_desiredWeight(desiredWeight) 399 , m_desiredItalic(desiredItalic) 400 , m_hasMatched(false) 401 { 402 } 403 404 LONG m_desiredWeight; 405 bool m_desiredItalic; 406 bool m_hasMatched; 407 LOGFONT m_chosen; 408}; 409 410static int CALLBACK matchImprovingEnumProc(CONST LOGFONT* candidate, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) 411{ 412 MatchImprovingProcData* matchData = reinterpret_cast<MatchImprovingProcData*>(lParam); 413 414 if (!matchData->m_hasMatched) { 415 matchData->m_hasMatched = true; 416 matchData->m_chosen = *candidate; 417 return 1; 418 } 419 420 if (!candidate->lfItalic != !matchData->m_chosen.lfItalic) { 421 if (!candidate->lfItalic == !matchData->m_desiredItalic) 422 matchData->m_chosen = *candidate; 423 424 return 1; 425 } 426 427 unsigned chosenWeightDeltaMagnitude = abs(matchData->m_chosen.lfWeight - matchData->m_desiredWeight); 428 unsigned candidateWeightDeltaMagnitude = abs(candidate->lfWeight - matchData->m_desiredWeight); 429 430 // If both are the same distance from the desired weight, prefer the candidate if it is further from regular. 431 if (chosenWeightDeltaMagnitude == candidateWeightDeltaMagnitude && abs(candidate->lfWeight - FW_NORMAL) > abs(matchData->m_chosen.lfWeight - FW_NORMAL)) { 432 matchData->m_chosen = *candidate; 433 return 1; 434 } 435 436 // Otherwise, prefer the one closer to the desired weight. 437 if (candidateWeightDeltaMagnitude < chosenWeightDeltaMagnitude) 438 matchData->m_chosen = *candidate; 439 440 return 1; 441} 442 443static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool desiredItalic, int size, bool synthesizeItalic) 444{ 445 HWndDC hdc(0); 446 447 LOGFONT logFont; 448 logFont.lfCharSet = DEFAULT_CHARSET; 449 unsigned familyLength = min(family.length(), static_cast<unsigned>(LF_FACESIZE - 1)); 450 memcpy(logFont.lfFaceName, family.characters(), familyLength * sizeof(UChar)); 451 logFont.lfFaceName[familyLength] = 0; 452 logFont.lfPitchAndFamily = 0; 453 454 MatchImprovingProcData matchData(desiredWeight, desiredItalic); 455 EnumFontFamiliesEx(hdc, &logFont, matchImprovingEnumProc, reinterpret_cast<LPARAM>(&matchData), 0); 456 457 if (!matchData.m_hasMatched) 458 return 0; 459 460 matchData.m_chosen.lfHeight = -size; 461 matchData.m_chosen.lfWidth = 0; 462 matchData.m_chosen.lfEscapement = 0; 463 matchData.m_chosen.lfOrientation = 0; 464 matchData.m_chosen.lfUnderline = false; 465 matchData.m_chosen.lfStrikeOut = false; 466 matchData.m_chosen.lfCharSet = DEFAULT_CHARSET; 467#if USE(CG) || USE(CAIRO) 468 matchData.m_chosen.lfOutPrecision = OUT_TT_ONLY_PRECIS; 469#else 470 matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS; 471#endif 472 matchData.m_chosen.lfQuality = DEFAULT_QUALITY; 473 matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; 474 475 if (desiredItalic && !matchData.m_chosen.lfItalic && synthesizeItalic) 476 matchData.m_chosen.lfItalic = 1; 477 478 HFONT result = CreateFontIndirect(&matchData.m_chosen); 479 if (!result) 480 return 0; 481 482 HWndDC dc(0); 483 SaveDC(dc); 484 SelectObject(dc, result); 485 WCHAR actualName[LF_FACESIZE]; 486 GetTextFace(dc, LF_FACESIZE, actualName); 487 RestoreDC(dc, -1); 488 489 if (wcsicmp(matchData.m_chosen.lfFaceName, actualName)) { 490 DeleteObject(result); 491 result = 0; 492 } 493 494 return result; 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 unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1)); 534 memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar)); 535 logFont.lfFaceName[familyLength] = 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 HFONT 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, 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(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 DeleteObject(hfont); 586 return nullptr; 587 } 588 589 return adoptPtr(result); 590} 591 592} 593 594