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