| OLD | NEW |
| (Empty) |
| 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 | |
| 41 using std::min; | |
| 42 | |
| 43 namespace WebCore | |
| 44 { | |
| 45 | |
| 46 void FontCache::platformInit() | |
| 47 { | |
| 48 } | |
| 49 | |
| 50 IMLangFontLinkType* FontCache::getFontLinkInterface() | |
| 51 { | |
| 52 static IMultiLanguage *multiLanguage; | |
| 53 if (!multiLanguage) { | |
| 54 if (CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLang
uage, (void**)&multiLanguage) != S_OK) | |
| 55 return 0; | |
| 56 } | |
| 57 | |
| 58 static IMLangFontLinkType* langFontLink; | |
| 59 if (!langFontLink) { | |
| 60 if (multiLanguage->QueryInterface(&langFontLink) != S_OK) | |
| 61 return 0; | |
| 62 } | |
| 63 | |
| 64 return langFontLink; | |
| 65 } | |
| 66 | |
| 67 static int CALLBACK metaFileEnumProc(HDC hdc, HANDLETABLE* table, CONST ENHMETAR
ECORD* record, int tableEntries, LPARAM logFont) | |
| 68 { | |
| 69 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) { | |
| 70 const EMREXTCREATEFONTINDIRECTW* createFontRecord = reinterpret_cast<con
st EMREXTCREATEFONTINDIRECTW*>(record); | |
| 71 *reinterpret_cast<LOGFONT*>(logFont) = createFontRecord->elfw.elfLogFont
; | |
| 72 } | |
| 73 return true; | |
| 74 } | |
| 75 | |
| 76 static int CALLBACK linkedFontEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC*
metrics, DWORD fontType, LPARAM hfont) | |
| 77 { | |
| 78 *reinterpret_cast<HFONT*>(hfont) = CreateFontIndirect(logFont); | |
| 79 return false; | |
| 80 } | |
| 81 | |
| 82 static const Vector<String>* getLinkedFonts(String& family) | |
| 83 { | |
| 84 static HashMap<String, Vector<String>*> systemLinkMap; | |
| 85 Vector<String>* result = systemLinkMap.get(family); | |
| 86 if (result) | |
| 87 return result; | |
| 88 | |
| 89 result = new Vector<String>; | |
| 90 systemLinkMap.set(family, result); | |
| 91 HKEY fontLinkKey; | |
| 92 if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows N
T\\CurrentVersion\\FontLink\\SystemLink", 0, KEY_READ, &fontLinkKey))) | |
| 93 return result; | |
| 94 | |
| 95 DWORD linkedFontsBufferSize = 0; | |
| 96 RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL
, NULL, &linkedFontsBufferSize); | |
| 97 WCHAR* linkedFonts = reinterpret_cast<WCHAR*>(malloc(linkedFontsBufferSize))
; | |
| 98 if (SUCCEEDED(RegQueryValueEx(fontLinkKey, family.charactersWithNullTerminat
ion(), 0, NULL, reinterpret_cast<BYTE*>(linkedFonts), &linkedFontsBufferSize)))
{ | |
| 99 unsigned i = 0; | |
| 100 unsigned length = linkedFontsBufferSize / sizeof(*linkedFonts); | |
| 101 while (i < length) { | |
| 102 while (i < length && linkedFonts[i] != ',') | |
| 103 i++; | |
| 104 i++; | |
| 105 unsigned j = i; | |
| 106 while (j < length && linkedFonts[j]) | |
| 107 j++; | |
| 108 result->append(String(linkedFonts + i, j - i)); | |
| 109 i = j + 1; | |
| 110 } | |
| 111 } | |
| 112 free(linkedFonts); | |
| 113 RegCloseKey(fontLinkKey); | |
| 114 return result; | |
| 115 } | |
| 116 | |
| 117 static const Vector<DWORD, 4>& getCJKCodePageMasks() | |
| 118 { | |
| 119 // The default order in which we look for a font for a CJK character. If the
user's default code page is | |
| 120 // one of these, we will use it first. | |
| 121 static const UINT CJKCodePages[] = { | |
| 122 932, /* Japanese */ | |
| 123 936, /* Simplified Chinese */ | |
| 124 950, /* Traditional Chinese */ | |
| 125 949 /* Korean */ | |
| 126 }; | |
| 127 | |
| 128 static Vector<DWORD, 4> codePageMasks; | |
| 129 static bool initialized; | |
| 130 if (!initialized) { | |
| 131 initialized = true; | |
| 132 IMLangFontLinkType* langFontLink = fontCache()->getFontLinkInterface(); | |
| 133 if (!langFontLink) | |
| 134 return codePageMasks; | |
| 135 | |
| 136 UINT defaultCodePage; | |
| 137 DWORD defaultCodePageMask = 0; | |
| 138 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDE
FAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCod
ePage))) | |
| 139 langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageM
ask); | |
| 140 | |
| 141 if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePage
s[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3]
) | |
| 142 codePageMasks.append(defaultCodePageMask); | |
| 143 for (unsigned i = 0; i < 4; ++i) { | |
| 144 if (defaultCodePage != CJKCodePages[i]) { | |
| 145 DWORD codePageMask; | |
| 146 langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask
); | |
| 147 codePageMasks.append(codePageMask); | |
| 148 } | |
| 149 } | |
| 150 } | |
| 151 return codePageMasks; | |
| 152 } | |
| 153 | |
| 154 static bool currentFontContainsCharacter(HDC hdc, UChar character) | |
| 155 { | |
| 156 static Vector<char, 512> glyphsetBuffer; | |
| 157 glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); | |
| 158 GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data()); | |
| 159 GetFontUnicodeRanges(hdc, glyphset); | |
| 160 | |
| 161 // FIXME: Change this to a binary search. | |
| 162 unsigned i = 0; | |
| 163 while (i < glyphset->cRanges && glyphset->ranges[i].wcLow <= character) | |
| 164 i++; | |
| 165 | |
| 166 return i && glyphset->ranges[i - 1].wcLow + glyphset->ranges[i - 1].cGlyphs
> character; | |
| 167 } | |
| 168 | |
| 169 static HFONT createMLangFont(IMLangFontLinkType* langFontLink, HDC hdc, DWORD co
dePageMask, UChar character = 0) | |
| 170 { | |
| 171 HFONT MLangFont; | |
| 172 HFONT hfont = 0; | |
| 173 if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &MLangFont
)) && MLangFont) { | |
| 174 LOGFONT lf; | |
| 175 GetObject(MLangFont, sizeof(LOGFONT), &lf); | |
| 176 langFontLink->ReleaseFont(MLangFont); | |
| 177 hfont = CreateFontIndirect(&lf); | |
| 178 } | |
| 179 return hfont; | |
| 180 } | |
| 181 | |
| 182 PassRefPtr<SimpleFontData> FontCache::getFontDataForCharacters(const Font& font,
const UChar* characters, int length) | |
| 183 { | |
| 184 UChar character = characters[0]; | |
| 185 RefPtr<SimpleFontData> fontData; | |
| 186 HWndDC hdc(0); | |
| 187 HFONT primaryFont = font.primaryFont()->fontDataForCharacter(character)->pla
tformData().hfont(); | |
| 188 HGDIOBJ oldFont = SelectObject(hdc, primaryFont); | |
| 189 HFONT hfont = 0; | |
| 190 | |
| 191 if (IMLangFontLinkType* langFontLink = getFontLinkInterface()) { | |
| 192 // Try MLang font linking first. | |
| 193 DWORD codePages = 0; | |
| 194 langFontLink->GetCharCodePages(character, &codePages); | |
| 195 | |
| 196 if (codePages && findCharUnicodeRange(character) == cRangeSetCJK) { | |
| 197 // The CJK character may belong to multiple code pages. We want to | |
| 198 // do font linking against a single one of them, preferring the defa
ult | |
| 199 // code page for the user's locale. | |
| 200 const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks(); | |
| 201 unsigned numCodePages = CJKCodePageMasks.size(); | |
| 202 for (unsigned i = 0; i < numCodePages && !hfont; ++i) { | |
| 203 hfont = createMLangFont(langFontLink, hdc, CJKCodePageMasks[i]); | |
| 204 if (hfont && !(codePages & CJKCodePageMasks[i])) { | |
| 205 // We asked about a code page that is not one of the code pa
ges | |
| 206 // returned by MLang, so the font might not contain the char
acter. | |
| 207 SelectObject(hdc, hfont); | |
| 208 if (!currentFontContainsCharacter(hdc, character)) { | |
| 209 DeleteObject(hfont); | |
| 210 hfont = 0; | |
| 211 } | |
| 212 SelectObject(hdc, primaryFont); | |
| 213 } | |
| 214 } | |
| 215 } else | |
| 216 hfont = createMLangFont(langFontLink, hdc, codePages, character); | |
| 217 } | |
| 218 | |
| 219 // A font returned from MLang is trusted to contain the character. | |
| 220 bool containsCharacter = hfont; | |
| 221 | |
| 222 if (!hfont) { | |
| 223 // To find out what font Uniscribe would use, we make it draw into a met
afile and intercept | |
| 224 // calls to CreateFontIndirect(). | |
| 225 HDC metaFileDc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); | |
| 226 SelectObject(metaFileDc, primaryFont); | |
| 227 | |
| 228 bool scriptStringOutSucceeded = false; | |
| 229 SCRIPT_STRING_ANALYSIS ssa; | |
| 230 | |
| 231 // FIXME: If length is greater than 1, we actually return the font for t
he last character. | |
| 232 // This function should be renamed getFontDataForCharacter and take a si
ngle 32-bit character. | |
| 233 if (SUCCEEDED(ScriptStringAnalyse(metaFileDc, characters, length, 0, -1,
SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, | |
| 234 0, NULL, NULL, NULL, NULL, NULL, &ssa))) { | |
| 235 scriptStringOutSucceeded = SUCCEEDED(ScriptStringOut(ssa, 0, 0, 0, N
ULL, 0, 0, FALSE)); | |
| 236 ScriptStringFree(&ssa); | |
| 237 } | |
| 238 HENHMETAFILE metaFile = CloseEnhMetaFile(metaFileDc); | |
| 239 if (scriptStringOutSucceeded) { | |
| 240 LOGFONT logFont; | |
| 241 logFont.lfFaceName[0] = 0; | |
| 242 EnumEnhMetaFile(0, metaFile, metaFileEnumProc, &logFont, NULL); | |
| 243 if (logFont.lfFaceName[0]) | |
| 244 hfont = CreateFontIndirect(&logFont); | |
| 245 } | |
| 246 DeleteEnhMetaFile(metaFile); | |
| 247 } | |
| 248 | |
| 249 String familyName; | |
| 250 const Vector<String>* linkedFonts = 0; | |
| 251 unsigned linkedFontIndex = 0; | |
| 252 while (hfont) { | |
| 253 SelectObject(hdc, hfont); | |
| 254 WCHAR name[LF_FACESIZE]; | |
| 255 GetTextFace(hdc, LF_FACESIZE, name); | |
| 256 familyName = name; | |
| 257 | |
| 258 if (containsCharacter || currentFontContainsCharacter(hdc, character)) | |
| 259 break; | |
| 260 | |
| 261 if (!linkedFonts) | |
| 262 linkedFonts = getLinkedFonts(familyName); | |
| 263 SelectObject(hdc, oldFont); | |
| 264 DeleteObject(hfont); | |
| 265 hfont = 0; | |
| 266 | |
| 267 if (linkedFonts->size() <= linkedFontIndex) | |
| 268 break; | |
| 269 | |
| 270 LOGFONT logFont; | |
| 271 logFont.lfCharSet = DEFAULT_CHARSET; | |
| 272 memcpy(logFont.lfFaceName, linkedFonts->at(linkedFontIndex).characters()
, linkedFonts->at(linkedFontIndex).length() * sizeof(WCHAR)); | |
| 273 logFont.lfFaceName[linkedFonts->at(linkedFontIndex).length()] = 0; | |
| 274 EnumFontFamiliesEx(hdc, &logFont, linkedFontEnumProc, reinterpret_cast<L
PARAM>(&hfont), 0); | |
| 275 linkedFontIndex++; | |
| 276 } | |
| 277 | |
| 278 if (hfont) { | |
| 279 if (!familyName.isEmpty()) { | |
| 280 FontPlatformData* result = getCachedFontPlatformData(font.fontDescri
ption(), familyName); | |
| 281 if (result) | |
| 282 fontData = getCachedFontData(result, DoNotRetain); | |
| 283 } | |
| 284 | |
| 285 SelectObject(hdc, oldFont); | |
| 286 DeleteObject(hfont); | |
| 287 } | |
| 288 | |
| 289 return fontData.release(); | |
| 290 } | |
| 291 | |
| 292 PassRefPtr<SimpleFontData> FontCache::getSimilarFontPlatformData(const Font& fon
t) | |
| 293 { | |
| 294 return 0; | |
| 295 } | |
| 296 | |
| 297 PassRefPtr<SimpleFontData> FontCache::fontDataFromDescriptionAndLogFont(const Fo
ntDescription& fontDescription, ShouldRetain shouldRetain, const LOGFONT& font,
AtomicString& outFontFamilyName) | |
| 298 { | |
| 299 AtomicString familyName = String(font.lfFaceName, wcsnlen(font.lfFaceName, L
F_FACESIZE)); | |
| 300 RefPtr<SimpleFontData> fontData = getCachedFontData(fontDescription, familyN
ame, false, shouldRetain); | |
| 301 if (fontData) | |
| 302 outFontFamilyName = familyName; | |
| 303 return fontData.release(); | |
| 304 } | |
| 305 | |
| 306 PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescri
ption& fontDescription, ShouldRetain shouldRetain) | |
| 307 { | |
| 308 DEFINE_STATIC_LOCAL(AtomicString, fallbackFontName, ()); | |
| 309 if (!fallbackFontName.isEmpty()) | |
| 310 return getCachedFontData(fontDescription, fallbackFontName, false, shoul
dRetain); | |
| 311 | |
| 312 // FIXME: Would be even better to somehow get the user's default font here.
For now we'll pick | |
| 313 // the default that the user would get without changing any prefs. | |
| 314 | |
| 315 // Search all typical Windows-installed full Unicode fonts. | |
| 316 // Sorted by most to least glyphs according to http://en.wikipedia.org/wiki/
Unicode_typefaces | |
| 317 // Start with Times New Roman also since it is the default if the user doesn
't change prefs. | |
| 318 static AtomicString fallbackFonts[] = { | |
| 319 AtomicString("Times New Roman", AtomicString::ConstructFromLiteral), | |
| 320 AtomicString("Microsoft Sans Serif", AtomicString::ConstructFromLiteral)
, | |
| 321 AtomicString("Tahoma", AtomicString::ConstructFromLiteral), | |
| 322 AtomicString("Lucida Sans Unicode", AtomicString::ConstructFromLiteral), | |
| 323 AtomicString("Arial", AtomicString::ConstructFromLiteral) | |
| 324 }; | |
| 325 RefPtr<SimpleFontData> simpleFont; | |
| 326 for (size_t i = 0; i < WTF_ARRAY_LENGTH(fallbackFonts); ++i) { | |
| 327 if (simpleFont = getCachedFontData(fontDescription, fallbackFonts[i], fa
lse, shouldRetain)) { | |
| 328 fallbackFontName = fallbackFonts[i]; | |
| 329 return simpleFont.release(); | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available
. | |
| 334 if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FON
T))) { | |
| 335 LOGFONT defaultGUILogFont; | |
| 336 GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont)
; | |
| 337 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shou
ldRetain, defaultGUILogFont, fallbackFontName)) | |
| 338 return simpleFont.release(); | |
| 339 } | |
| 340 | |
| 341 // Fall back to Non-client metrics fonts. | |
| 342 NONCLIENTMETRICS nonClientMetrics = {0}; | |
| 343 nonClientMetrics.cbSize = sizeof(nonClientMetrics); | |
| 344 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics),
&nonClientMetrics, 0)) { | |
| 345 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shou
ldRetain, nonClientMetrics.lfMessageFont, fallbackFontName)) | |
| 346 return simpleFont.release(); | |
| 347 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shou
ldRetain, nonClientMetrics.lfMenuFont, fallbackFontName)) | |
| 348 return simpleFont.release(); | |
| 349 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shou
ldRetain, nonClientMetrics.lfStatusFont, fallbackFontName)) | |
| 350 return simpleFont.release(); | |
| 351 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shou
ldRetain, nonClientMetrics.lfCaptionFont, fallbackFontName)) | |
| 352 return simpleFont.release(); | |
| 353 if (simpleFont = fontDataFromDescriptionAndLogFont(fontDescription, shou
ldRetain, nonClientMetrics.lfSmCaptionFont, fallbackFontName)) | |
| 354 return simpleFont.release(); | |
| 355 } | |
| 356 | |
| 357 ASSERT_NOT_REACHED(); | |
| 358 return 0; | |
| 359 } | |
| 360 | |
| 361 static LONG toGDIFontWeight(FontWeight fontWeight) | |
| 362 { | |
| 363 static LONG gdiFontWeights[] = { | |
| 364 FW_THIN, // FontWeight100 | |
| 365 FW_EXTRALIGHT, // FontWeight200 | |
| 366 FW_LIGHT, // FontWeight300 | |
| 367 FW_NORMAL, // FontWeight400 | |
| 368 FW_MEDIUM, // FontWeight500 | |
| 369 FW_SEMIBOLD, // FontWeight600 | |
| 370 FW_BOLD, // FontWeight700 | |
| 371 FW_EXTRABOLD, // FontWeight800 | |
| 372 FW_HEAVY // FontWeight900 | |
| 373 }; | |
| 374 return gdiFontWeights[fontWeight]; | |
| 375 } | |
| 376 | |
| 377 static inline bool isGDIFontWeightBold(LONG gdiFontWeight) | |
| 378 { | |
| 379 return gdiFontWeight >= FW_SEMIBOLD; | |
| 380 } | |
| 381 | |
| 382 static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family) | |
| 383 { | |
| 384 static AtomicString lucidaStr("Lucida Grande"); | |
| 385 if (equalIgnoringCase(family, lucidaStr)) { | |
| 386 if (gdiFontWeight == FW_NORMAL) | |
| 387 return FW_MEDIUM; | |
| 388 if (gdiFontWeight == FW_BOLD) | |
| 389 return FW_SEMIBOLD; | |
| 390 } | |
| 391 return gdiFontWeight; | |
| 392 } | |
| 393 | |
| 394 struct MatchImprovingProcData { | |
| 395 MatchImprovingProcData(LONG desiredWeight, bool desiredItalic) | |
| 396 : m_desiredWeight(desiredWeight) | |
| 397 , m_desiredItalic(desiredItalic) | |
| 398 , m_hasMatched(false) | |
| 399 { | |
| 400 } | |
| 401 | |
| 402 LONG m_desiredWeight; | |
| 403 bool m_desiredItalic; | |
| 404 bool m_hasMatched; | |
| 405 LOGFONT m_chosen; | |
| 406 }; | |
| 407 | |
| 408 static int CALLBACK matchImprovingEnumProc(CONST LOGFONT* candidate, CONST TEXTM
ETRIC* metrics, DWORD fontType, LPARAM lParam) | |
| 409 { | |
| 410 MatchImprovingProcData* matchData = reinterpret_cast<MatchImprovingProcData*
>(lParam); | |
| 411 | |
| 412 if (!matchData->m_hasMatched) { | |
| 413 matchData->m_hasMatched = true; | |
| 414 matchData->m_chosen = *candidate; | |
| 415 return 1; | |
| 416 } | |
| 417 | |
| 418 if (!candidate->lfItalic != !matchData->m_chosen.lfItalic) { | |
| 419 if (!candidate->lfItalic == !matchData->m_desiredItalic) | |
| 420 matchData->m_chosen = *candidate; | |
| 421 | |
| 422 return 1; | |
| 423 } | |
| 424 | |
| 425 unsigned chosenWeightDeltaMagnitude = abs(matchData->m_chosen.lfWeight - mat
chData->m_desiredWeight); | |
| 426 unsigned candidateWeightDeltaMagnitude = abs(candidate->lfWeight - matchData
->m_desiredWeight); | |
| 427 | |
| 428 // If both are the same distance from the desired weight, prefer the candida
te if it is further from regular. | |
| 429 if (chosenWeightDeltaMagnitude == candidateWeightDeltaMagnitude && abs(candi
date->lfWeight - FW_NORMAL) > abs(matchData->m_chosen.lfWeight - FW_NORMAL)) { | |
| 430 matchData->m_chosen = *candidate; | |
| 431 return 1; | |
| 432 } | |
| 433 | |
| 434 // Otherwise, prefer the one closer to the desired weight. | |
| 435 if (candidateWeightDeltaMagnitude < chosenWeightDeltaMagnitude) | |
| 436 matchData->m_chosen = *candidate; | |
| 437 | |
| 438 return 1; | |
| 439 } | |
| 440 | |
| 441 static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool
desiredItalic, int size, bool synthesizeItalic) | |
| 442 { | |
| 443 HWndDC hdc(0); | |
| 444 | |
| 445 LOGFONT logFont; | |
| 446 logFont.lfCharSet = DEFAULT_CHARSET; | |
| 447 unsigned familyLength = min(family.length(), static_cast<unsigned>(LF_FACESI
ZE - 1)); | |
| 448 memcpy(logFont.lfFaceName, family.characters(), familyLength * sizeof(UChar)
); | |
| 449 logFont.lfFaceName[familyLength] = 0; | |
| 450 logFont.lfPitchAndFamily = 0; | |
| 451 | |
| 452 MatchImprovingProcData matchData(desiredWeight, desiredItalic); | |
| 453 EnumFontFamiliesEx(hdc, &logFont, matchImprovingEnumProc, reinterpret_cast<L
PARAM>(&matchData), 0); | |
| 454 | |
| 455 if (!matchData.m_hasMatched) | |
| 456 return 0; | |
| 457 | |
| 458 matchData.m_chosen.lfHeight = -size; | |
| 459 matchData.m_chosen.lfWidth = 0; | |
| 460 matchData.m_chosen.lfEscapement = 0; | |
| 461 matchData.m_chosen.lfOrientation = 0; | |
| 462 matchData.m_chosen.lfUnderline = false; | |
| 463 matchData.m_chosen.lfStrikeOut = false; | |
| 464 matchData.m_chosen.lfCharSet = DEFAULT_CHARSET; | |
| 465 matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS; | |
| 466 matchData.m_chosen.lfQuality = DEFAULT_QUALITY; | |
| 467 matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; | |
| 468 | |
| 469 if (desiredItalic && !matchData.m_chosen.lfItalic && synthesizeItalic) | |
| 470 matchData.m_chosen.lfItalic = 1; | |
| 471 | |
| 472 HFONT result = CreateFontIndirect(&matchData.m_chosen); | |
| 473 if (!result) | |
| 474 return 0; | |
| 475 | |
| 476 HWndDC dc(0); | |
| 477 SaveDC(dc); | |
| 478 SelectObject(dc, result); | |
| 479 WCHAR actualName[LF_FACESIZE]; | |
| 480 GetTextFace(dc, LF_FACESIZE, actualName); | |
| 481 RestoreDC(dc, -1); | |
| 482 | |
| 483 if (wcsicmp(matchData.m_chosen.lfFaceName, actualName)) { | |
| 484 DeleteObject(result); | |
| 485 result = 0; | |
| 486 } | |
| 487 | |
| 488 return result; | |
| 489 } | |
| 490 | |
| 491 struct TraitsInFamilyProcData { | |
| 492 TraitsInFamilyProcData(const AtomicString& familyName) | |
| 493 : m_familyName(familyName) | |
| 494 { | |
| 495 } | |
| 496 | |
| 497 const AtomicString& m_familyName; | |
| 498 HashSet<unsigned> m_traitsMasks; | |
| 499 }; | |
| 500 | |
| 501 static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMET
RIC* metrics, DWORD fontType, LPARAM lParam) | |
| 502 { | |
| 503 TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>
(lParam); | |
| 504 | |
| 505 unsigned traitsMask = 0; | |
| 506 traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; | |
| 507 traitsMask |= FontVariantNormalMask; | |
| 508 LONG weight = adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyNam
e); | |
| 509 traitsMask |= weight == FW_THIN ? FontWeight100Mask : | |
| 510 weight == FW_EXTRALIGHT ? FontWeight200Mask : | |
| 511 weight == FW_LIGHT ? FontWeight300Mask : | |
| 512 weight == FW_NORMAL ? FontWeight400Mask : | |
| 513 weight == FW_MEDIUM ? FontWeight500Mask : | |
| 514 weight == FW_SEMIBOLD ? FontWeight600Mask : | |
| 515 weight == FW_BOLD ? FontWeight700Mask : | |
| 516 weight == FW_EXTRABOLD ? FontWeight800Mask : | |
| 517 FontWeight900Mask; | |
| 518 procData->m_traitsMasks.add(traitsMask); | |
| 519 return 1; | |
| 520 } | |
| 521 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne
d>& traitsMasks) | |
| 522 { | |
| 523 HWndDC hdc(0); | |
| 524 | |
| 525 LOGFONT logFont; | |
| 526 logFont.lfCharSet = DEFAULT_CHARSET; | |
| 527 unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FA
CESIZE - 1)); | |
| 528 memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UC
har)); | |
| 529 logFont.lfFaceName[familyLength] = 0; | |
| 530 logFont.lfPitchAndFamily = 0; | |
| 531 | |
| 532 TraitsInFamilyProcData procData(familyName); | |
| 533 EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<L
PARAM>(&procData), 0); | |
| 534 copyToVector(procData.m_traitsMasks, traitsMasks); | |
| 535 } | |
| 536 | |
| 537 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
escription, const AtomicString& family) | |
| 538 { | |
| 539 bool isLucidaGrande = false; | |
| 540 static AtomicString lucidaStr("Lucida Grande"); | |
| 541 if (equalIgnoringCase(family, lucidaStr)) | |
| 542 isLucidaGrande = true; | |
| 543 | |
| 544 bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !
isLucidaGrande; | |
| 545 | |
| 546 // The logical size constant is 32. We do this for subpixel precision when r
endering using Uniscribe. | |
| 547 // This masks rounding errors related to the HFONT metrics being different
from the CGFont metrics. | |
| 548 // FIXME: We will eventually want subpixel precision for GDI mode, but the s
caled rendering doesn't | |
| 549 // look as nice. That may be solvable though. | |
| 550 LONG weight = adjustedGDIFontWeight(toGDIFontWeight(fontDescription.weight()
), family); | |
| 551 HFONT hfont = createGDIFont(family, weight, fontDescription.italic(), | |
| 552 fontDescription.computedPixelSize() * (useGDI ?
1 : 32), useGDI); | |
| 553 | |
| 554 if (!hfont) | |
| 555 return 0; | |
| 556 | |
| 557 if (isLucidaGrande) | |
| 558 useGDI = false; // Never use GDI for Lucida Grande. | |
| 559 | |
| 560 LOGFONT logFont; | |
| 561 GetObject(hfont, sizeof(LOGFONT), &logFont); | |
| 562 | |
| 563 bool synthesizeBold = isGDIFontWeightBold(weight) && !isGDIFontWeightBold(lo
gFont.lfWeight); | |
| 564 bool synthesizeItalic = fontDescription.italic() && !logFont.lfItalic; | |
| 565 | |
| 566 FontPlatformData* result = new FontPlatformData(hfont, fontDescription.compu
tedPixelSize(), synthesizeBold, synthesizeItalic, useGDI); | |
| 567 | |
| 568 if (fontCreationFailed) { | |
| 569 // The creation of the CGFontRef failed for some reason. We already ass
erted in debug builds, but to make | |
| 570 // absolutely sure that we don't use this font, go ahead and return 0 so
that we can fall back to the next | |
| 571 // font. | |
| 572 delete result; | |
| 573 DeleteObject(hfont); | |
| 574 return 0; | |
| 575 } | |
| 576 | |
| 577 return result; | |
| 578 } | |
| 579 | |
| 580 } | |
| 581 | |
| OLD | NEW |