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 |