• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
FontFamilyCodePageInfo()44     FontFamilyCodePageInfo()
45         : m_codePage(0), m_codePages(0)
46     {
47     }
FontFamilyCodePageInfo(const wchar_t * family,UINT codePage)48     FontFamilyCodePageInfo(const wchar_t* family, UINT codePage)
49         : m_family(family), m_codePage(codePage), m_codePages(0)
50     {
51     }
codePages() const52     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:
FontFamilyChecker(const wchar_t * family)74     FontFamilyChecker(const wchar_t* family)
75         : m_exists(false)
76     {
77         EnumFontFamilies(g_screenDC, family, enumFontFamProc, (LPARAM)this);
78     }
isSupported() const79     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:
ValidFontFamilyFinder()87     ValidFontFamilyFinder()
88     {
89         EnumFontFamilies(g_screenDC, 0, enumFontFamProc, (LPARAM)this);
90     }
family() const91     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:
FixedSizeFontData()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 {
FixedSizeFontDataKeyWebCore::FixedSizeFontDataKey119     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 
FixedSizeFontDataKeyWebCore::FixedSizeFontDataKey126     FixedSizeFontDataKey(WTF::HashTableDeletedValueType) : m_weight(-2) { }
isHashTableDeletedValueWebCore::FixedSizeFontDataKey127     bool isHashTableDeletedValue() const { return m_weight == -2; }
128 
operator ==WebCore::FixedSizeFontDataKey129     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 {
hashWebCore::FixedSizeFontDataKeyHash142     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 
equalWebCore::FixedSizeFontDataKeyHash152     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;
emptyValueWebCore::FixedSizeFontDataKeyTraits162     static const FixedSizeFontDataKey& emptyValue()
163     {
164         DEFINE_STATIC_LOCAL(FixedSizeFontDataKey, key, (nullAtom));
165         return key;
166     }
constructDeletedValueWebCore::FixedSizeFontDataKeyTraits167     static void constructDeletedValue(FixedSizeFontDataKey& slot)
168     {
169         new (&slot) FixedSizeFontDataKey(WTF::HashTableDeletedValue);
170     }
isDeletedValueWebCore::FixedSizeFontDataKeyTraits171     static bool isDeletedValue(const FixedSizeFontDataKey& value)
172     {
173         return value.isHashTableDeletedValue();
174     }
175 };
176 
enumFontFamProc(const LOGFONT FAR * lpelf,const TEXTMETRIC FAR * lpntm,DWORD FontType,LPARAM lParam)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 
enumFontFamProc(const LOGFONT FAR * lpelf,const TEXTMETRIC FAR * lpntm,DWORD FontType,LPARAM lParam)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;
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 
getDefaultFontFamily()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 
create(const AtomicString & family,unsigned weight,bool italic)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