FontCacheWin.cpp 9.04 KB
Newer Older
hyatt's avatar
hyatt committed
1
/*
aroben's avatar
aroben committed
2
 * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
hyatt's avatar
hyatt committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer. 
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution. 
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
darin's avatar
darin committed
30
#include <winsock2.h>
sfalken's avatar
sfalken committed
31
#include "FontCache.h"
32
#include "FontData.h"
hyatt's avatar
hyatt committed
33
#include "Font.h"
34
#include <windows.h>
aroben's avatar
aroben committed
35 36 37
#include <mlang.h>
#include <ApplicationServices/ApplicationServices.h>
#include <WebKitSystemInterface/WebKitSystemInterface.h>
hyatt's avatar
hyatt committed
38

39 40
using std::min;

sfalken's avatar
sfalken committed
41 42
namespace WebCore
{
hyatt's avatar
hyatt committed
43 44 45

void FontCache::platformInit()
{
aroben's avatar
aroben committed
46
    wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac.
hyatt's avatar
hyatt committed
47 48
}

49 50
IMLangFontLink2* FontCache::getFontLinkInterface()
{
sfalken's avatar
sfalken committed
51 52
    static IMultiLanguage *multiLanguage;
    if (!multiLanguage) {
darin's avatar
darin committed
53
        if (CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLanguage, (void**)&multiLanguage) != S_OK)
54
            return 0;
55 56
    }

sfalken's avatar
sfalken committed
57 58 59 60 61 62 63
    static IMLangFontLink2* langFontLink;
    if (!langFontLink) {
        if (multiLanguage->QueryInterface(&langFontLink) != S_OK)
            return 0;
    }

    return langFontLink;
64 65
}

hyatt's avatar
hyatt committed
66 67
const FontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
{
68
    // IMLangFontLink::MapFont Method does what we want.
69 70 71 72 73 74
    IMLangFontLink2* langFontLink = getFontLinkInterface();
    if (!langFontLink)
        return 0;

    FontData* fontData = 0;
    HDC hdc = GetDC(0);
aroben's avatar
aroben committed
75 76
    HFONT primaryFont = font.primaryFont()->m_font.hfont();
    HGDIOBJ oldFont = SelectObject(hdc, primaryFont);
sfalken's avatar
sfalken committed
77
    HFONT hfont = 0;
78

hyatt's avatar
hyatt committed
79 80 81
    DWORD acpCodePages;
    langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);

82 83
    DWORD actualCodePages;
    long cchActual;
hyatt's avatar
hyatt committed
84
    langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &cchActual);
85 86 87
    if (cchActual) {
        HFONT result;
        if (langFontLink->MapFont(hdc, actualCodePages, characters[0], &result) == S_OK) {
88 89 90 91 92
            // Fill in a log font with the returned font from MLang, and then use that to create a new font.
            LOGFONT lf;
            GetObject(result, sizeof(LOGFONT), &lf);
            langFontLink->ReleaseFont(result);

sfalken's avatar
sfalken committed
93
            hfont = CreateFontIndirect(&lf);
94 95 96 97 98 99 100 101 102
            SelectObject(hdc, hfont);

            WCHAR name[LF_FACESIZE];
            GetTextFace(hdc, LF_FACESIZE, name);
            
            String familyName(name);
            if (!familyName.isEmpty()) {
                FontPlatformData* result = getCachedFontPlatformData(font.fontDescription(), familyName);
                if (result)
103
                    fontData = getCachedFontData(result);
104
            }
105 106 107
        }
    }

aroben's avatar
aroben committed
108
    SelectObject(hdc, oldFont);
sfalken's avatar
sfalken committed
109 110
    if (hfont)
        DeleteObject(hfont);
111
    ReleaseDC(0, hdc);
112
    return fontData;
hyatt's avatar
hyatt committed
113 114 115 116 117 118 119
}

FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
{
    return 0;
}

120
FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
hyatt's avatar
hyatt committed
121 122 123 124
{
    // FIXME: Would be even better to somehow get the user's default font here.  For now we'll pick
    // the default that the user would get without changing any prefs.
    static AtomicString timesStr("Times New Roman");
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
    return getCachedFontPlatformData(fontDescription, timesStr);
}

bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
{
    LOGFONT winfont;

    // The size here looks unusual.  The negative number is intentional.  The logical size constant is 32.
    winfont.lfHeight = -fontDescription.computedPixelSize() * 32;
    winfont.lfWidth = 0;
    winfont.lfEscapement = 0;
    winfont.lfOrientation = 0;
    winfont.lfUnderline = false;
    winfont.lfStrikeOut = false;
    winfont.lfCharSet = DEFAULT_CHARSET;
#if PLATFORM(CG)
    winfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
#else
    winfont.lfOutPrecision = OUT_TT_PRECIS;
#endif
    winfont.lfQuality = 5; // Force cleartype.
    winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    winfont.lfItalic = fontDescription.italic();

    // FIXME: Support weights for real.  Do our own enumeration of the available weights.
    // We can't rely on Windows here, since we need to follow the CSS2 algorithm for how to fill in
    // gaps in the weight list.
    // FIXME: Hardcoding Lucida Grande for now.  It uses different weights than typical Win32 fonts
    // (500/600 instead of 400/700).
    static AtomicString lucidaStr("Lucida Grande");
    if (equalIgnoringCase(family, lucidaStr))
        winfont.lfWeight = fontDescription.bold() ? 600 : 500;
    else
        winfont.lfWeight = fontDescription.bold() ? 700 : 400;
    int len = min(family.length(), (unsigned int)LF_FACESIZE - 1);
    memcpy(winfont.lfFaceName, family.characters(), len * sizeof(WORD));
    winfont.lfFaceName[len] = '\0';

    HFONT hfont = CreateFontIndirect(&winfont);
    // Windows will always give us a valid pointer here, even if the face name is non-existent.  We have to double-check
    // and see if the family name was really used.
    HDC dc = GetDC((HWND)0);
    SaveDC(dc);
    SelectObject(dc, hfont);
    WCHAR name[LF_FACESIZE];
    GetTextFace(dc, LF_FACESIZE, name);
    RestoreDC(dc, -1);
    ReleaseDC(0, dc);

    DeleteObject(hfont);

    return !wcsicmp(winfont.lfFaceName, name);
hyatt's avatar
hyatt committed
177 178 179 180 181 182
}

FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
{
    LOGFONT winfont;

183
    // The size here looks unusual.  The negative number is intentional.  The logical size constant is 32.
aroben's avatar
aroben committed
184
    winfont.lfHeight = -fontDescription.computedPixelSize() * 32;
hyatt's avatar
hyatt committed
185 186 187 188 189 190
    winfont.lfWidth = 0;
    winfont.lfEscapement = 0;
    winfont.lfOrientation = 0;
    winfont.lfUnderline = false;
    winfont.lfStrikeOut = false;
    winfont.lfCharSet = DEFAULT_CHARSET;
aroben's avatar
aroben committed
191 192 193
#if PLATFORM(CG)
    winfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
#else
194
    winfont.lfOutPrecision = OUT_TT_PRECIS;
aroben's avatar
aroben committed
195
#endif
hyatt's avatar
hyatt committed
196 197 198
    winfont.lfQuality = 5; // Force cleartype.
    winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    winfont.lfItalic = fontDescription.italic();
aroben's avatar
aroben committed
199 200 201 202 203 204 205 206 207 208 209 210

    // FIXME: Support weights for real.  Do our own enumeration of the available weights.
    // We can't rely on Windows here, since we need to follow the CSS2 algorithm for how to fill in
    // gaps in the weight list.
    // FIXME: Hardcoding Lucida Grande for now.  It uses different weights than typical Win32 fonts
    // (500/600 instead of 400/700).
    static AtomicString lucidaStr("Lucida Grande");
    if (equalIgnoringCase(family, lucidaStr))
        winfont.lfWeight = fontDescription.bold() ? 600 : 500;
    else
        winfont.lfWeight = fontDescription.bold() ? 700 : 400;
    int len = min(family.length(), (unsigned int)LF_FACESIZE - 1);
hyatt's avatar
hyatt committed
211 212 213 214 215 216 217 218 219 220
    memcpy(winfont.lfFaceName, family.characters(), len * sizeof(WORD));
    winfont.lfFaceName[len] = '\0';

    HFONT hfont = CreateFontIndirect(&winfont);
    // Windows will always give us a valid pointer here, even if the face name is non-existent.  We have to double-check
    // and see if the family name was really used.
    HDC dc = GetDC((HWND)0);
    SaveDC(dc);
    SelectObject(dc, hfont);
    WCHAR name[LF_FACESIZE];
aroben's avatar
aroben committed
221
    GetTextFace(dc, LF_FACESIZE, name);
hyatt's avatar
hyatt committed
222 223
    RestoreDC(dc, -1);
    ReleaseDC(0, dc);
aroben's avatar
aroben committed
224 225

    if (_wcsicmp(winfont.lfFaceName, name)) {
hyatt's avatar
hyatt committed
226 227 228 229
        DeleteObject(hfont);
        return 0;
    }
    
230 231 232 233 234 235 236 237 238 239 240 241
    FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(),
                                                    fontDescription.bold(), fontDescription.italic());
    if (!result->cgFont()) {
        // The creation of the CGFontRef failed for some reason.  We already asserted in debug builds, but to make
        // absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next
        // font.
        delete result;
        DeleteObject(hfont);
        return 0;
    }        

    return result;
aroben's avatar
aroben committed
242 243
}

hyatt's avatar
hyatt committed
244 245
}