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