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