Home | History | Annotate | Download | only in wince
      1 /*
      2 * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.
      3 * Copyright (C) 2007-2009 Torch Mobile, Inc.
      4 *
      5 * Redistribution and use in source and binary forms, with or without
      6 * modification, are permitted provided that the following conditions
      7 * are met:
      8 *
      9 * 1.  Redistributions of source code must retain the above copyright
     10 *     notice, this list of conditions and the following disclaimer.
     11 * 2.  Redistributions in binary form must reproduce the above copyright
     12 *     notice, this list of conditions and the following disclaimer in the
     13 *     documentation and/or other materials provided with the distribution.
     14 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15 *     its contributors may be used to endorse or promote products derived
     16 *     from this software without specific prior written permission.
     17 *
     18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 */
     29 
     30 #include "config.h"
     31 #include "FontCache.h"
     32 
     33 #include "Font.h"
     34 #include "FontData.h"
     35 #include "SimpleFontData.h"
     36 #include "UnicodeRange.h"
     37 #include "wtf/OwnPtr.h"
     38 
     39 #include <windows.h>
     40 #include <mlang.h>
     41 
     42 namespace WebCore {
     43 
     44 extern HDC g_screenDC;
     45 
     46 static IMultiLanguage *multiLanguage = 0;
     47 
     48 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
     49 static IMLangFontLink2* langFontLink = 0;
     50 #else
     51 static IMLangFontLink* langFontLink = 0;
     52 #endif
     53 
     54 IMultiLanguage* getMultiLanguageInterface()
     55 {
     56     if (!multiLanguage)
     57         CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&multiLanguage);
     58 
     59     return multiLanguage;
     60 }
     61 
     62 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
     63 IMLangFontLink2* FontCache::getFontLinkInterface()
     64 #else
     65 IMLangFontLink* FontCache::getFontLinkInterface()
     66 #endif
     67 {
     68     if (!langFontLink) {
     69         if (IMultiLanguage* mli = getMultiLanguageInterface())
     70             mli->QueryInterface(&langFontLink);
     71     }
     72 
     73     return langFontLink;
     74 }
     75 
     76 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
     77 static bool currentFontContainsCharacter(IMLangFontLink2* langFontLink, HDC hdc, UChar character)
     78 {
     79     UINT unicodeRanges;
     80     if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, 0))
     81         return false;
     82 
     83     static Vector<UNICODERANGE, 64> glyphsetBuffer;
     84     glyphsetBuffer.resize(unicodeRanges);
     85 
     86     if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, glyphsetBuffer.data()))
     87         return false;
     88 
     89     // FIXME: Change this to a binary search. (Yong Li: That's easy. But, is it guaranteed that the ranges are sorted?)
     90     for (Vector<UNICODERANGE, 64>::const_iterator i = glyphsetBuffer.begin(); i != glyphsetBuffer.end(); ++i) {
     91         if (i->wcTo >= character)
     92             return i->wcFrom <= character;
     93     }
     94 
     95     return false;
     96 }
     97 #else
     98 static bool currentFontContainsCharacter(IMLangFontLink* langFontLink, HDC hdc, HFONT hfont, UChar character, const wchar_t* faceName)
     99 {
    100     DWORD fontCodePages = 0, charCodePages = 0;
    101     HRESULT result = langFontLink->GetFontCodePages(hdc, hfont, &fontCodePages);
    102     if (result != S_OK)
    103         return false;
    104     result = langFontLink->GetCharCodePages(character, &charCodePages);
    105     if (result != S_OK)
    106         return false;
    107 
    108     fontCodePages |= FontPlatformData::getKnownFontCodePages(faceName);
    109     if (fontCodePages & charCodePages)
    110         return true;
    111 
    112     return false;
    113 }
    114 #endif
    115 
    116 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
    117 static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0)
    118 {
    119     HFONT mlangFont;
    120     if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &mlangFont)))
    121         return mlangFont;
    122 
    123     return 0;
    124 }
    125 #else
    126 static HFONT createMLangFont(IMLangFontLink* langFontLink, HDC hdc, const FontPlatformData& refFont, DWORD codePageMask)
    127 {
    128     HFONT mlangFont;
    129     LRESULT result = langFontLink->MapFont(hdc, codePageMask, refFont.hfont(), &mlangFont);
    130 
    131     return result == S_OK ? mlangFont : 0;
    132 }
    133 #endif
    134 
    135 static const Vector<DWORD, 4>& getCJKCodePageMasks()
    136 {
    137     // The default order in which we look for a font for a CJK character. If the user's default code page is
    138     // one of these, we will use it first.
    139     static const UINT CJKCodePages[] = {
    140         932, /* Japanese */
    141         936, /* Simplified Chinese */
    142         950, /* Traditional Chinese */
    143         949  /* Korean */
    144     };
    145 
    146     static Vector<DWORD, 4> codePageMasks;
    147     static bool initialized;
    148     if (!initialized) {
    149         initialized = true;
    150 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
    151         IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
    152 #else
    153         IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface();
    154 #endif
    155         if (!langFontLink)
    156             return codePageMasks;
    157 
    158         UINT defaultCodePage;
    159         DWORD defaultCodePageMask = 0;
    160         if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage)))
    161             langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask);
    162 
    163         if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3])
    164             codePageMasks.append(defaultCodePageMask);
    165         for (unsigned i = 0; i < 4; ++i) {
    166             if (defaultCodePage != CJKCodePages[i]) {
    167                 DWORD codePageMask;
    168                 langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask);
    169                 codePageMasks.append(codePageMask);
    170             }
    171         }
    172     }
    173     return codePageMasks;
    174 }
    175 
    176 
    177 struct TraitsInFamilyProcData {
    178     TraitsInFamilyProcData(const AtomicString& familyName)
    179         : m_familyName(familyName)
    180     {
    181     }
    182 
    183     const AtomicString& m_familyName;
    184     HashSet<unsigned> m_traitsMasks;
    185 };
    186 
    187 static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
    188 {
    189     TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam);
    190 
    191     unsigned traitsMask = 0;
    192     traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask;
    193     traitsMask |= FontVariantNormalMask;
    194     LONG weight = FontPlatformData::adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName);
    195     traitsMask |= weight == FW_THIN ? FontWeight100Mask :
    196         weight == FW_EXTRALIGHT ? FontWeight200Mask :
    197         weight == FW_LIGHT ? FontWeight300Mask :
    198         weight == FW_NORMAL ? FontWeight400Mask :
    199         weight == FW_MEDIUM ? FontWeight500Mask :
    200         weight == FW_SEMIBOLD ? FontWeight600Mask :
    201         weight == FW_BOLD ? FontWeight700Mask :
    202         weight == FW_EXTRABOLD ? FontWeight800Mask :
    203                                  FontWeight900Mask;
    204     procData->m_traitsMasks.add(traitsMask);
    205     return 1;
    206 }
    207 
    208 void FontCache::platformInit()
    209 {
    210 }
    211 
    212 void FontCache::comInitialize()
    213 {
    214 }
    215 
    216 void FontCache::comUninitialize()
    217 {
    218     if (langFontLink) {
    219         langFontLink->Release();
    220         langFontLink = 0;
    221     }
    222     if (multiLanguage) {
    223         multiLanguage->Release();
    224         multiLanguage = 0;
    225     }
    226 }
    227 
    228 const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
    229 {
    230     String familyName;
    231     WCHAR name[LF_FACESIZE];
    232 
    233     UChar character = characters[0];
    234     const FontPlatformData& origFont = font.primaryFont()->fontDataForCharacter(character)->platformData();
    235     unsigned unicodeRange = findCharUnicodeRange(character);
    236 
    237 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
    238     if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
    239 #else
    240     if (IMLangFontLink* langFontLink = getFontLinkInterface()) {
    241 #endif
    242         HGDIOBJ oldFont = GetCurrentObject(g_screenDC, OBJ_FONT);
    243         HFONT hfont = 0;
    244         DWORD codePages = 0;
    245         UINT codePage = 0;
    246         // Try MLang font linking first.
    247         langFontLink->GetCharCodePages(character, &codePages);
    248         if (codePages && unicodeRange == cRangeSetCJK) {
    249             // The CJK character may belong to multiple code pages. We want to
    250             // do font linking against a single one of them, preferring the default
    251             // code page for the user's locale.
    252             const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
    253             unsigned numCodePages = CJKCodePageMasks.size();
    254             for (unsigned i = 0; i < numCodePages; ++i) {
    255 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
    256                 hfont = createMLangFont(langFontLink, g_screenDC, CJKCodePageMasks[i]);
    257 #else
    258                 hfont = createMLangFont(langFontLink, g_screenDC, origFont, CJKCodePageMasks[i]);
    259 #endif
    260                 if (!hfont)
    261                     continue;
    262 
    263                 SelectObject(g_screenDC, hfont);
    264                 GetTextFace(g_screenDC, LF_FACESIZE, name);
    265 
    266                 if (hfont && !(codePages & CJKCodePageMasks[i])) {
    267                     // We asked about a code page that is not one of the code pages
    268                     // returned by MLang, so the font might not contain the character.
    269 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
    270                     if (!currentFontContainsCharacter(langFontLink, g_screenDC, character)) {
    271 #else
    272                     if (!currentFontContainsCharacter(langFontLink, g_screenDC, hfont, character, name)) {
    273 #endif
    274                         SelectObject(g_screenDC, oldFont);
    275                         langFontLink->ReleaseFont(hfont);
    276                         hfont = 0;
    277                         continue;
    278                     }
    279                 }
    280                 break;
    281             }
    282         } else {
    283 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
    284             hfont = createMLangFont(langFontLink, g_screenDC, codePages, character);
    285 #else
    286             hfont = createMLangFont(langFontLink, g_screenDC, origFont, codePages);
    287 #endif
    288             SelectObject(g_screenDC, hfont);
    289             GetTextFace(g_screenDC, LF_FACESIZE, name);
    290         }
    291         SelectObject(g_screenDC, oldFont);
    292 
    293         if (hfont) {
    294             familyName = name;
    295             langFontLink->ReleaseFont(hfont);
    296         } else
    297             FontPlatformData::mapKnownFont(codePages, familyName);
    298     }
    299 
    300     if (familyName.isEmpty())
    301         familyName = FontPlatformData::defaultFontFamily();
    302 
    303     if (!familyName.isEmpty()) {
    304         // FIXME: temporary workaround for Thai font problem
    305         FontDescription fontDescription(font.fontDescription());
    306         if (unicodeRange == cRangeThai && fontDescription.weight() > FontWeightNormal)
    307             fontDescription.setWeight(FontWeightNormal);
    308 
    309         FontPlatformData* result = getCachedFontPlatformData(fontDescription, familyName);
    310         if (result && result->hash() != origFont.hash()) {
    311             if (SimpleFontData* fontData = getCachedFontData(result))
    312                 return fontData;
    313         }
    314     }
    315 
    316     return 0;
    317 }
    318 
    319 SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
    320 {
    321     return 0;
    322 }
    323 
    324 SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDesc)
    325 {
    326     // FIXME: Would be even better to somehow get the user's default font here.  For now we'll pick
    327     // the default that the user would get without changing any prefs.
    328     return getCachedFontData(fontDesc, FontPlatformData::defaultFontFamily());
    329 }
    330 
    331 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
    332 {
    333     FontPlatformData* result = new FontPlatformData(fontDescription, family);
    334     return result;
    335 }
    336 
    337 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
    338 {
    339     LOGFONT logFont;
    340     logFont.lfCharSet = DEFAULT_CHARSET;
    341     unsigned familyLength = std::min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1));
    342     memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar));
    343     logFont.lfFaceName[familyLength] = 0;
    344     logFont.lfPitchAndFamily = 0;
    345 
    346     TraitsInFamilyProcData procData(familyName);
    347     EnumFontFamiliesEx(g_screenDC, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
    348     copyToVector(procData.m_traitsMasks, traitsMasks);
    349 }
    350 
    351 }
    352 
    353