• 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 #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:
FontFamilyCodePageInfo()46     FontFamilyCodePageInfo()
47         : m_codePage(0), m_codePages(0)
48     {
49     }
FontFamilyCodePageInfo(const wchar_t * family,UINT codePage)50     FontFamilyCodePageInfo(const wchar_t* family, UINT codePage)
51         : m_family(family), m_codePage(codePage), m_codePages(0)
52     {
53     }
codePages() const54     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:
FontFamilyChecker(const wchar_t * family)76     FontFamilyChecker(const wchar_t* family)
77         : m_exists(false)
78     {
79         EnumFontFamilies(g_screenDC, family, enumFontFamProc, (LPARAM)this);
80     }
isSupported() const81     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:
ValidFontFamilyFinder()89     ValidFontFamilyFinder()
90     {
91         EnumFontFamilies(g_screenDC, 0, enumFontFamProc, (LPARAM)this);
92     }
family() const93     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:
FixedSizeFontData()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 {
FixedSizeFontDataKeyWebCore::FixedSizeFontDataKey121     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 
FixedSizeFontDataKeyWebCore::FixedSizeFontDataKey128     FixedSizeFontDataKey(WTF::HashTableDeletedValueType) : m_weight(-2) { }
isHashTableDeletedValueWebCore::FixedSizeFontDataKey129     bool isHashTableDeletedValue() const { return m_weight == -2; }
130 
operator ==WebCore::FixedSizeFontDataKey131     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 {
hashWebCore::FixedSizeFontDataKeyHash144     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 
equalWebCore::FixedSizeFontDataKeyHash154     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;
emptyValueWebCore::FixedSizeFontDataKeyTraits164     static const FixedSizeFontDataKey& emptyValue()
165     {
166         DEFINE_STATIC_LOCAL(FixedSizeFontDataKey, key, (nullAtom));
167         return key;
168     }
constructDeletedValueWebCore::FixedSizeFontDataKeyTraits169     static void constructDeletedValue(FixedSizeFontDataKey& slot)
170     {
171         new (&slot) FixedSizeFontDataKey(WTF::HashTableDeletedValue);
172     }
isDeletedValueWebCore::FixedSizeFontDataKeyTraits173     static bool isDeletedValue(const FixedSizeFontDataKey& value)
174     {
175         return value.isHashTableDeletedValue();
176     }
177 };
178 
enumFontFamProc(const LOGFONT FAR * lpelf,const TEXTMETRIC FAR * lpntm,DWORD FontType,LPARAM lParam)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 
enumFontFamProc(const LOGFONT FAR * lpelf,const TEXTMETRIC FAR * lpntm,DWORD FontType,LPARAM lParam)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;
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 
getDefaultFontFamily()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 
create(const AtomicString & family,unsigned weight,bool italic)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