1 /* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2007-2009 Torch Mobile, Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "config.h" 31 #include "FontCache.h" 32 33 #include "Font.h" 34 #include "FontData.h" 35 #include "SimpleFontData.h" 36 #include "UnicodeRange.h" 37 #include "wtf/OwnPtr.h" 38 39 #include <windows.h> 40 #include <mlang.h> 41 42 namespace WebCore { 43 44 extern HDC g_screenDC; 45 46 static IMultiLanguage *multiLanguage = 0; 47 48 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) 49 static IMLangFontLink2* langFontLink = 0; 50 #else 51 static IMLangFontLink* langFontLink = 0; 52 #endif 53 54 IMultiLanguage* FontCache::getMultiLanguageInterface() 55 { 56 if (!multiLanguage) 57 CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&multiLanguage); 58 59 return multiLanguage; 60 } 61 62 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) 63 IMLangFontLink2* FontCache::getFontLinkInterface() 64 #else 65 IMLangFontLink* FontCache::getFontLinkInterface() 66 #endif 67 { 68 if (!langFontLink) { 69 if (IMultiLanguage* mli = getMultiLanguageInterface()) 70 mli->QueryInterface(&langFontLink); 71 } 72 73 return langFontLink; 74 } 75 76 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) 77 static bool currentFontContainsCharacter(IMLangFontLink2* langFontLink, HDC hdc, UChar character) 78 { 79 UINT unicodeRanges; 80 if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, 0)) 81 return false; 82 83 static Vector<UNICODERANGE, 64> glyphsetBuffer; 84 glyphsetBuffer.resize(unicodeRanges); 85 86 if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, glyphsetBuffer.data())) 87 return false; 88 89 // FIXME: Change this to a binary search. (Yong Li: That's easy. But, is it guaranteed that the ranges are sorted?) 90 for (Vector<UNICODERANGE, 64>::const_iterator i = glyphsetBuffer.begin(); i != glyphsetBuffer.end(); ++i) { 91 if (i->wcTo >= character) 92 return i->wcFrom <= character; 93 } 94 95 return false; 96 } 97 #else 98 static bool currentFontContainsCharacter(IMLangFontLink* langFontLink, HDC hdc, HFONT hfont, UChar character, const wchar_t* faceName) 99 { 100 DWORD fontCodePages = 0, charCodePages = 0; 101 HRESULT result = langFontLink->GetFontCodePages(hdc, hfont, &fontCodePages); 102 if (result != S_OK) 103 return false; 104 result = langFontLink->GetCharCodePages(character, &charCodePages); 105 if (result != S_OK) 106 return false; 107 108 fontCodePages |= FontPlatformData::getKnownFontCodePages(faceName); 109 if (fontCodePages & charCodePages) 110 return true; 111 112 return false; 113 } 114 #endif 115 116 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) 117 static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0) 118 { 119 HFONT mlangFont; 120 if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &mlangFont))) 121 return mlangFont; 122 123 return 0; 124 } 125 #else 126 static HFONT createMLangFont(IMLangFontLink* langFontLink, HDC hdc, const FontPlatformData& refFont, DWORD codePageMask) 127 { 128 HFONT mlangFont; 129 LRESULT result = langFontLink->MapFont(hdc, codePageMask, refFont.hfont(), &mlangFont); 130 131 return result == S_OK ? mlangFont : 0; 132 } 133 #endif 134 135 static const Vector<DWORD, 4>& getCJKCodePageMasks() 136 { 137 // The default order in which we look for a font for a CJK character. If the user's default code page is 138 // one of these, we will use it first. 139 static const UINT CJKCodePages[] = { 140 932, /* Japanese */ 141 936, /* Simplified Chinese */ 142 950, /* Traditional Chinese */ 143 949 /* Korean */ 144 }; 145 146 static Vector<DWORD, 4> codePageMasks; 147 static bool initialized; 148 if (!initialized) { 149 initialized = true; 150 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) 151 IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface(); 152 #else 153 IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface(); 154 #endif 155 if (!langFontLink) 156 return codePageMasks; 157 158 UINT defaultCodePage; 159 DWORD defaultCodePageMask = 0; 160 if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage))) 161 langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask); 162 163 if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3]) 164 codePageMasks.append(defaultCodePageMask); 165 for (unsigned i = 0; i < 4; ++i) { 166 if (defaultCodePage != CJKCodePages[i]) { 167 DWORD codePageMask; 168 langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask); 169 codePageMasks.append(codePageMask); 170 } 171 } 172 } 173 return codePageMasks; 174 } 175 176 177 struct TraitsInFamilyProcData { 178 TraitsInFamilyProcData(const AtomicString& familyName) 179 : m_familyName(familyName) 180 { 181 } 182 183 const AtomicString& m_familyName; 184 HashSet<unsigned> m_traitsMasks; 185 }; 186 187 static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) 188 { 189 TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam); 190 191 unsigned traitsMask = 0; 192 traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; 193 traitsMask |= FontVariantNormalMask; 194 LONG weight = FontPlatformData::adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName); 195 traitsMask |= weight == FW_THIN ? FontWeight100Mask : 196 weight == FW_EXTRALIGHT ? FontWeight200Mask : 197 weight == FW_LIGHT ? FontWeight300Mask : 198 weight == FW_NORMAL ? FontWeight400Mask : 199 weight == FW_MEDIUM ? FontWeight500Mask : 200 weight == FW_SEMIBOLD ? FontWeight600Mask : 201 weight == FW_BOLD ? FontWeight700Mask : 202 weight == FW_EXTRABOLD ? FontWeight800Mask : 203 FontWeight900Mask; 204 procData->m_traitsMasks.add(traitsMask); 205 return 1; 206 } 207 208 void FontCache::platformInit() 209 { 210 } 211 212 void FontCache::comInitialize() 213 { 214 } 215 216 void FontCache::comUninitialize() 217 { 218 if (langFontLink) { 219 langFontLink->Release(); 220 langFontLink = 0; 221 } 222 if (multiLanguage) { 223 multiLanguage->Release(); 224 multiLanguage = 0; 225 } 226 } 227 228 const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) 229 { 230 String familyName; 231 WCHAR name[LF_FACESIZE]; 232 233 UChar character = characters[0]; 234 const FontPlatformData& origFont = font.primaryFont()->fontDataForCharacter(character)->platformData(); 235 unsigned unicodeRange = findCharUnicodeRange(character); 236 237 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) 238 if (IMLangFontLink2* langFontLink = getFontLinkInterface()) { 239 #else 240 if (IMLangFontLink* langFontLink = getFontLinkInterface()) { 241 #endif 242 HGDIOBJ oldFont = GetCurrentObject(g_screenDC, OBJ_FONT); 243 HFONT hfont = 0; 244 DWORD codePages = 0; 245 UINT codePage = 0; 246 // Try MLang font linking first. 247 langFontLink->GetCharCodePages(character, &codePages); 248 if (codePages && unicodeRange == cRangeSetCJK) { 249 // The CJK character may belong to multiple code pages. We want to 250 // do font linking against a single one of them, preferring the default 251 // code page for the user's locale. 252 const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks(); 253 unsigned numCodePages = CJKCodePageMasks.size(); 254 for (unsigned i = 0; i < numCodePages; ++i) { 255 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) 256 hfont = createMLangFont(langFontLink, g_screenDC, CJKCodePageMasks[i]); 257 #else 258 hfont = createMLangFont(langFontLink, g_screenDC, origFont, CJKCodePageMasks[i]); 259 #endif 260 if (!hfont) 261 continue; 262 263 SelectObject(g_screenDC, hfont); 264 GetTextFace(g_screenDC, LF_FACESIZE, name); 265 266 if (hfont && !(codePages & CJKCodePageMasks[i])) { 267 // We asked about a code page that is not one of the code pages 268 // returned by MLang, so the font might not contain the character. 269 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) 270 if (!currentFontContainsCharacter(langFontLink, g_screenDC, character)) { 271 #else 272 if (!currentFontContainsCharacter(langFontLink, g_screenDC, hfont, character, name)) { 273 #endif 274 SelectObject(g_screenDC, oldFont); 275 langFontLink->ReleaseFont(hfont); 276 hfont = 0; 277 continue; 278 } 279 } 280 break; 281 } 282 } else { 283 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) 284 hfont = createMLangFont(langFontLink, g_screenDC, codePages, character); 285 #else 286 hfont = createMLangFont(langFontLink, g_screenDC, origFont, codePages); 287 #endif 288 SelectObject(g_screenDC, hfont); 289 GetTextFace(g_screenDC, LF_FACESIZE, name); 290 } 291 SelectObject(g_screenDC, oldFont); 292 293 if (hfont) { 294 familyName = name; 295 langFontLink->ReleaseFont(hfont); 296 } else 297 FontPlatformData::mapKnownFont(codePages, familyName); 298 } 299 300 if (familyName.isEmpty()) 301 familyName = FontPlatformData::defaultFontFamily(); 302 303 if (!familyName.isEmpty()) { 304 // FIXME: temporary workaround for Thai font problem 305 FontDescription fontDescription(font.fontDescription()); 306 if (unicodeRange == cRangeThai && fontDescription.weight() > FontWeightNormal) 307 fontDescription.setWeight(FontWeightNormal); 308 309 FontPlatformData* result = getCachedFontPlatformData(fontDescription, familyName); 310 if (result && result->hash() != origFont.hash()) { 311 if (SimpleFontData* fontData = getCachedFontData(result)) 312 return fontData; 313 } 314 } 315 316 return 0; 317 } 318 319 SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font) 320 { 321 return 0; 322 } 323 324 SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDesc) 325 { 326 // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick 327 // the default that the user would get without changing any prefs. 328 return getCachedFontData(fontDesc, FontPlatformData::defaultFontFamily()); 329 } 330 331 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) 332 { 333 FontPlatformData* result = new FontPlatformData(fontDescription, family); 334 return result; 335 } 336 337 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) 338 { 339 LOGFONT logFont; 340 logFont.lfCharSet = DEFAULT_CHARSET; 341 unsigned familyLength = std::min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1)); 342 memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar)); 343 logFont.lfFaceName[familyLength] = 0; 344 logFont.lfPitchAndFamily = 0; 345 346 TraitsInFamilyProcData procData(familyName); 347 EnumFontFamiliesEx(g_screenDC, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); 348 copyToVector(procData.m_traitsMasks, traitsMasks); 349 } 350 351 } // namespace WebCore 352