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