Home | History | Annotate | Download | only in wince
      1 /*
      2  *  Copyright (C) 2007-2009 Torch Mobile Inc.
      3  *
      4  *  This library is free software; you can redistribute it and/or
      5  *  modify it under the terms of the GNU Library General Public
      6  *  License as published by the Free Software Foundation; either
      7  *  version 2 of the License, or (at your option) any later version.
      8  *
      9  *  This library is distributed in the hope that it will be useful,
     10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  *  Library General Public License for more details.
     13  *
     14  *  You should have received a copy of the GNU Library General Public License
     15  *  along with this library; see the file COPYING.LIB.  If not, write to
     16  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  *  Boston, MA 02110-1301, USA.
     18  *
     19  */
     20 
     21 #include "config.h"
     22 #include "FontPlatformData.h"
     23 
     24 #include "Font.h"
     25 #include "FontCache.h"
     26 #include "FontData.h"
     27 #include "PlatformString.h"
     28 #include "SimpleFontData.h"
     29 #include "UnicodeRange.h"
     30 #include "wtf/OwnPtr.h"
     31 
     32 #include <windows.h>
     33 #include <mlang.h>
     34 
     35 namespace WebCore {
     36 
     37 extern HDC g_screenDC;
     38 
     39 static wchar_t songTiStr[] = { 0x5b8b, 0x4f53, 0 };
     40 static wchar_t heiTiStr[] = { 0x9ed1, 0x4f53, 0 };
     41 
     42 class FontFamilyCodePageInfo {
     43 public:
     44     FontFamilyCodePageInfo()
     45         : m_codePage(0), m_codePages(0)
     46     {
     47     }
     48     FontFamilyCodePageInfo(const wchar_t* family, UINT codePage)
     49         : m_family(family), m_codePage(codePage), m_codePages(0)
     50     {
     51     }
     52     DWORD codePages() const
     53     {
     54         if (!m_codePages) {
     55 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
     56             if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface())
     57                 langFontLink->CodePageToCodePages(m_codePage, &m_codePages);
     58 #else
     59             if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface())
     60                 langFontLink->CodePageToCodePages(m_codePage, &m_codePages);
     61 #endif
     62         }
     63         return m_codePages;
     64     }
     65 
     66     String m_family;
     67     UINT m_codePage;
     68 private:
     69     mutable DWORD m_codePages;
     70 };
     71 
     72 class FontFamilyChecker {
     73 public:
     74     FontFamilyChecker(const wchar_t* family)
     75         : m_exists(false)
     76     {
     77         EnumFontFamilies(g_screenDC, family, enumFontFamProc, (LPARAM)this);
     78     }
     79     bool isSupported() const { return m_exists; }
     80 private:
     81     bool m_exists;
     82     static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam);
     83 };
     84 
     85 class ValidFontFamilyFinder {
     86 public:
     87     ValidFontFamilyFinder()
     88     {
     89         EnumFontFamilies(g_screenDC, 0, enumFontFamProc, (LPARAM)this);
     90     }
     91     const String& family() const { return m_family; }
     92 private:
     93     String m_family;
     94     static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam);
     95 };
     96 
     97 class FixedSizeFontData: public RefCounted<FixedSizeFontData> {
     98 public:
     99     LOGFONT m_font;
    100     OwnPtr<HFONT> m_hfont;
    101     TEXTMETRIC m_metrics;
    102     DWORD m_codePages;
    103     unsigned m_weight;
    104     bool m_italic;
    105 
    106     static PassRefPtr<FixedSizeFontData> create(const AtomicString& family, unsigned weight, bool italic);
    107 private:
    108     FixedSizeFontData()
    109         : m_codePages(0)
    110         , m_weight(0)
    111         , m_italic(false)
    112     {
    113         memset(&m_font, 0, sizeof(m_font));
    114         memset(&m_metrics, 0, sizeof(m_metrics));
    115     }
    116 };
    117 
    118 struct FixedSizeFontDataKey {
    119     FixedSizeFontDataKey(const AtomicString& family = AtomicString(), unsigned weight = 0, bool italic = false)
    120         : m_family(family)
    121         , m_weight(weight)
    122         , m_italic(italic)
    123     {
    124     }
    125 
    126     FixedSizeFontDataKey(WTF::HashTableDeletedValueType) : m_weight(-2) { }
    127     bool isHashTableDeletedValue() const { return m_weight == -2; }
    128 
    129     bool operator==(const FixedSizeFontDataKey& other) const
    130     {
    131         return equalIgnoringCase(m_family, other.m_family)
    132             && m_weight == other.m_weight
    133             && m_italic == other.m_italic;
    134     }
    135 
    136     AtomicString m_family;
    137     unsigned m_weight;
    138     bool m_italic;
    139 };
    140 
    141 struct FixedSizeFontDataKeyHash {
    142     static unsigned hash(const FixedSizeFontDataKey& font)
    143     {
    144         unsigned hashCodes[] = {
    145             CaseFoldingHash::hash(font.m_family),
    146             font.m_weight,
    147             // static_cast<unsigned>(font.m_italic);
    148         };
    149         return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
    150     }
    151 
    152     static bool equal(const FixedSizeFontDataKey& a, const FixedSizeFontDataKey& b)
    153     {
    154         return a == b;
    155     }
    156 
    157     static const bool safeToCompareToEmptyOrDeleted = true;
    158 };
    159 
    160 struct FixedSizeFontDataKeyTraits : WTF::GenericHashTraits<FixedSizeFontDataKey> {
    161     static const bool emptyValueIsZero = true;
    162     static const FixedSizeFontDataKey& emptyValue()
    163     {
    164         DEFINE_STATIC_LOCAL(FixedSizeFontDataKey, key, (nullAtom));
    165         return key;
    166     }
    167     static void constructDeletedValue(FixedSizeFontDataKey& slot)
    168     {
    169         new (&slot) FixedSizeFontDataKey(WTF::HashTableDeletedValue);
    170     }
    171     static bool isDeletedValue(const FixedSizeFontDataKey& value)
    172     {
    173         return value.isHashTableDeletedValue();
    174     }
    175 };
    176 
    177 int CALLBACK FontFamilyChecker::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam)
    178 {
    179     ((FontFamilyChecker*)lParam)->m_exists = true;
    180     return 0;
    181 }
    182 
    183 int CALLBACK ValidFontFamilyFinder::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam)
    184 {
    185     if (lpelf->lfCharSet != SYMBOL_CHARSET) {
    186         ((ValidFontFamilyFinder*)lParam)->m_family = String(lpelf->lfFaceName);
    187         return 0;
    188     }
    189     return 1;
    190 }
    191 
    192 typedef Vector<FontFamilyCodePageInfo> KnownFonts;
    193 static KnownFonts& knownFonts()
    194 {
    195     static KnownFonts fonts;
    196     static bool firstTime = true;
    197     if (firstTime) {
    198         firstTime = false;
    199         if (FontPlatformData::isSongTiSupported())
    200             fonts.append(FontFamilyCodePageInfo(songTiStr, 936));
    201     }
    202     return fonts;
    203 }
    204 
    205 static String getDefaultFontFamily()
    206 {
    207     if (FontFamilyChecker(L"Tahoma").isSupported())
    208         return String(L"Tahoma");
    209 
    210     bool good = false;
    211     String family;
    212     HKEY key;
    213     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\GDI\\SysFnt", 0, 0, &key) == ERROR_SUCCESS) {
    214         DWORD maxlen, type;
    215         if (RegQueryValueEx(key, L"Nm", 0, &type, 0, &maxlen) == ERROR_SUCCESS && type == REG_SZ) {
    216             ++maxlen;
    217             if (wchar_t* buffer = new wchar_t[maxlen]) {
    218                 if (RegQueryValueEx(key, L"Nm", 0, &type, (LPBYTE)buffer, &maxlen) == ERROR_SUCCESS) {
    219                     family = String(buffer, maxlen);
    220                     good = true;
    221                 }
    222                 delete[] buffer;
    223             }
    224         }
    225         RegCloseKey(key);
    226     }
    227     if (good)
    228         return family;
    229 
    230     return ValidFontFamilyFinder().family();
    231 }
    232 
    233 typedef HashMap<FixedSizeFontDataKey, RefPtr<FixedSizeFontData>, FixedSizeFontDataKeyHash, FixedSizeFontDataKeyTraits> FixedSizeFontCache;
    234 FixedSizeFontCache g_fixedSizeFontCache;
    235 
    236 PassRefPtr<FixedSizeFontData> FixedSizeFontData::create(const AtomicString& family, unsigned weight, bool italic)
    237 {
    238     FixedSizeFontData* fontData = new FixedSizeFontData();
    239 
    240     fontData->m_weight = weight;
    241     fontData->m_italic = italic;
    242 
    243     LOGFONT& winFont = fontData->m_font;
    244     // The size here looks unusual.  The negative number is intentional.
    245     winFont.lfHeight = -72;
    246     winFont.lfWidth = 0;
    247     winFont.lfEscapement = 0;
    248     winFont.lfOrientation = 0;
    249     winFont.lfUnderline = false;
    250     winFont.lfStrikeOut = false;
    251     winFont.lfCharSet = DEFAULT_CHARSET;
    252     winFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
    253     winFont.lfQuality = CLEARTYPE_QUALITY; //DEFAULT_QUALITY;
    254     winFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    255     winFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    256     winFont.lfItalic = italic;
    257     winFont.lfWeight = FontPlatformData::adjustedGDIFontWeight(weight, family);
    258 
    259     int len = std::min(family.length(), (unsigned int)LF_FACESIZE - 1);
    260     wmemcpy(winFont.lfFaceName, family.characters(), len);
    261     winFont.lfFaceName[len] = L'\0';
    262 
    263     fontData->m_hfont.set(CreateFontIndirect(&winFont));
    264 
    265     HGDIOBJ oldFont = SelectObject(g_screenDC, fontData->m_hfont.get());
    266 
    267     GetTextMetrics(g_screenDC, &fontData->m_metrics);
    268 
    269 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
    270     if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface()) {
    271 #else
    272     if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface()) {
    273 #endif
    274         langFontLink->GetFontCodePages(g_screenDC, fontData->m_hfont.get(), &fontData->m_codePages);
    275         fontData->m_codePages |= FontPlatformData::getKnownFontCodePages(winFont.lfFaceName);
    276     }
    277 
    278     SelectObject(g_screenDC, oldFont);
    279 
    280     return adoptRef(fontData);
    281 }
    282 
    283 static PassRefPtr<FixedSizeFontData> createFixedSizeFontData(const AtomicString& family, unsigned weight, bool italic)
    284 {
    285     FixedSizeFontDataKey key(family, weight, italic);
    286     pair<FixedSizeFontCache::iterator, bool> result = g_fixedSizeFontCache.add(key, RefPtr<FixedSizeFontData>());
    287     if (result.second)
    288         result.first->second = FixedSizeFontData::create(family, weight, italic);
    289 
    290     return result.first->second;
    291 }
    292 
    293 static LONG toGDIFontWeight(FontWeight fontWeight)
    294 {
    295     static LONG gdiFontWeights[] = {
    296         FW_THIN,        // FontWeight100
    297         FW_EXTRALIGHT,  // FontWeight200
    298         FW_LIGHT,       // FontWeight300
    299         FW_NORMAL,      // FontWeight400
    300         FW_MEDIUM,      // FontWeight500
    301         FW_SEMIBOLD,    // FontWeight600
    302         FW_BOLD,        // FontWeight700
    303         FW_EXTRABOLD,   // FontWeight800
    304         FW_HEAVY        // FontWeight900
    305     };
    306     return gdiFontWeights[fontWeight];
    307 }
    308 
    309 class FontPlatformPrivateData {
    310 public:
    311     int m_reference;
    312     RefPtr<FixedSizeFontData> m_rootFontData;
    313     AtomicString m_family;
    314     FontDescription m_fontDescription;
    315     OwnPtr<HFONT> m_hfontScaled;
    316     int m_size;
    317     long m_fontScaledWidth;
    318     long m_fontScaledHeight;
    319     bool m_disabled;
    320     FontPlatformPrivateData(int size, unsigned weight)
    321         : m_reference(1)
    322         , m_family(FontPlatformData::defaultFontFamily())
    323         , m_size(size)
    324         , m_fontScaledWidth(0)
    325         , m_fontScaledHeight(0)
    326         , m_disabled(false)
    327     {
    328         m_rootFontData = createFixedSizeFontData(m_family, weight, false);
    329     }
    330     FontPlatformPrivateData(const FontDescription& fontDescription, const AtomicString& family)
    331         : m_reference(1)
    332         , m_size(fontDescription.computedPixelSize())
    333         , m_fontDescription(fontDescription)
    334         , m_family(family)
    335         , m_fontScaledWidth(0)
    336         , m_fontScaledHeight(0)
    337         , m_disabled(!fontDescription.specifiedSize())
    338     {
    339         m_rootFontData = FixedSizeFontData::create(family, toGDIFontWeight(fontDescription.weight()), fontDescription.italic());
    340     }
    341 };
    342 
    343 FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& desiredFamily, bool useDefaultFontIfNotPresent)
    344 {
    345     String family(desiredFamily);
    346     if (!equalIgnoringCase(family, defaultFontFamily()) && !FontFamilyChecker(family.charactersWithNullTermination()).isSupported()) {
    347         if (equalIgnoringCase(family, String(heiTiStr)) && isSongTiSupported())
    348             family = String(songTiStr);
    349         else if (useDefaultFontIfNotPresent)
    350             family = defaultFontFamily();
    351     }
    352 
    353     m_private = new FontPlatformPrivateData(fontDescription, family);
    354 }
    355 
    356 FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
    357 {
    358     if (!size)
    359         m_private = 0;
    360     else
    361         m_private = new FontPlatformPrivateData((int)(size + 0.5), bold ? FW_BOLD : FW_NORMAL);
    362 }
    363 
    364 FontPlatformData::~FontPlatformData()
    365 {
    366     if (isValid() && !--m_private->m_reference) {
    367         if (m_private->m_rootFontData->refCount() == 2) {
    368             FixedSizeFontDataKey key(m_private->m_family, m_private->m_rootFontData->m_weight, m_private->m_rootFontData->m_italic);
    369             g_fixedSizeFontCache.remove(key);
    370         }
    371         delete m_private;
    372     }
    373 }
    374 
    375 FontPlatformData& FontPlatformData::operator=(const FontPlatformData& o)
    376 {
    377     if (isValid() && !--m_private->m_reference)
    378         delete m_private;
    379 
    380     if (m_private = o.m_private)
    381         ++m_private->m_reference;
    382 
    383     return *this;
    384 }
    385 
    386 HFONT FontPlatformData::hfont() const
    387 {
    388     if (!isValid())
    389         return 0;
    390 
    391     if (m_private->m_disabled)
    392         return 0;
    393 
    394     if (!m_private->m_rootFontData->m_hfont)
    395         m_private->m_rootFontData->m_hfont.set(CreateFontIndirect(&m_private->m_rootFontData->m_font));
    396 
    397     return m_private->m_rootFontData->m_hfont.get();
    398 }
    399 
    400 HFONT FontPlatformData::getScaledFontHandle(int height, int width) const
    401 {
    402     if (!isValid() || m_private->m_disabled)
    403         return 0;
    404 
    405     if (!m_private->m_hfontScaled || m_private->m_fontScaledHeight != height || m_private->m_fontScaledWidth != width) {
    406         m_private->m_fontScaledHeight = height;
    407         m_private->m_fontScaledWidth = width;
    408         LOGFONT font = m_private->m_rootFontData->m_font;
    409         font.lfHeight = -height;
    410         font.lfWidth = width;
    411         m_private->m_hfontScaled.set(CreateFontIndirect(&font));
    412     }
    413 
    414     return m_private->m_hfontScaled.get();
    415 }
    416 
    417 bool FontPlatformData::discardFontHandle()
    418 {
    419     if (!isValid())
    420         return false;
    421 
    422     if (m_private->m_rootFontData->m_hfont) {
    423         m_private->m_rootFontData->m_hfont.set(0);
    424         return true;
    425     }
    426 
    427     if (m_private->m_hfontScaled) {
    428         m_private->m_hfontScaled.set(0);
    429         return true;
    430     }
    431     return false;
    432 }
    433 
    434 const TEXTMETRIC& FontPlatformData::metrics() const
    435 {
    436     return m_private->m_rootFontData->m_metrics;
    437 }
    438 
    439 bool FontPlatformData::isSystemFont() const
    440 {
    441     return false;
    442 }
    443 
    444 int FontPlatformData::size() const
    445 {
    446     return m_private->m_size;
    447 }
    448 
    449 const FontDescription& FontPlatformData::fontDescription() const
    450 {
    451     return m_private->m_fontDescription;
    452 }
    453 
    454 const AtomicString& FontPlatformData::family() const
    455 {
    456     return m_private->m_family;
    457 }
    458 
    459 const LOGFONT& FontPlatformData::logFont() const
    460 {
    461     return m_private->m_rootFontData->m_font;
    462 }
    463 
    464 int FontPlatformData::averageCharWidth() const
    465 {
    466     return (m_private->m_rootFontData->m_metrics.tmAveCharWidth * size() + 36) / 72;
    467 }
    468 
    469 bool FontPlatformData::isDisabled() const
    470 {
    471     return !isValid() || m_private->m_disabled;
    472 }
    473 
    474 DWORD FontPlatformData::codePages() const
    475 {
    476     return m_private->m_rootFontData->m_codePages;
    477 }
    478 
    479 bool FontPlatformData::isSongTiSupported()
    480 {
    481     static bool exists = FontFamilyChecker(songTiStr).isSupported();
    482     return exists;
    483 }
    484 
    485 bool FontPlatformData::mapKnownFont(DWORD codePages, String& family)
    486 {
    487     KnownFonts& fonts = knownFonts();
    488     for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) {
    489         if (i->codePages() & codePages) {
    490             family = i->m_family;
    491             return true;
    492         }
    493     }
    494     return false;
    495 }
    496 
    497 DWORD FontPlatformData::getKnownFontCodePages(const wchar_t* family)
    498 {
    499     KnownFonts& fonts = knownFonts();
    500     for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) {
    501         if (equalIgnoringCase(i->m_family, String(family)))
    502             return i->codePages();
    503     }
    504     return 0;
    505 }
    506 
    507 const String& FontPlatformData::defaultFontFamily()
    508 {
    509     static String family(getDefaultFontFamily());
    510     return family;
    511 }
    512 
    513 LONG FontPlatformData::adjustedGDIFontWeight(LONG gdiFontWeight, const String& family)
    514 {
    515     static AtomicString lucidaStr("Lucida Grande");
    516     if (equalIgnoringCase(family, lucidaStr)) {
    517         if (gdiFontWeight == FW_NORMAL)
    518             return FW_MEDIUM;
    519         if (gdiFontWeight == FW_BOLD)
    520             return FW_SEMIBOLD;
    521     }
    522     return gdiFontWeight;
    523 }
    524 
    525 #ifndef NDEBUG
    526 String FontPlatformData::description() const
    527 {
    528     return String();
    529 }
    530 #endif
    531 
    532 }
    533