2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2007-2009 Torch Mobile, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "FontCache.h"
35 #include "SimpleFontData.h"
36 #include "UnicodeRange.h"
37 #include "wtf/OwnPtr.h"
44 extern HDC g_screenDC;
46 static IMultiLanguage *multiLanguage = 0;
48 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
49 static IMLangFontLink2* langFontLink = 0;
51 static IMLangFontLink* langFontLink = 0;
54 IMultiLanguage* FontCache::getMultiLanguageInterface()
57 CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&multiLanguage);
62 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
63 IMLangFontLink2* FontCache::getFontLinkInterface()
65 IMLangFontLink* FontCache::getFontLinkInterface()
69 if (IMultiLanguage* mli = getMultiLanguageInterface())
70 mli->QueryInterface(&langFontLink);
76 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
77 static bool currentFontContainsCharacter(IMLangFontLink2* langFontLink, HDC hdc, UChar character)
80 if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, 0))
83 static Vector<UNICODERANGE, 64> glyphsetBuffer;
84 glyphsetBuffer.resize(unicodeRanges);
86 if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, glyphsetBuffer.data()))
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;
98 static bool currentFontContainsCharacter(IMLangFontLink* langFontLink, HDC hdc, HFONT hfont, UChar character, const wchar_t* faceName)
100 DWORD fontCodePages = 0, charCodePages = 0;
101 HRESULT result = langFontLink->GetFontCodePages(hdc, hfont, &fontCodePages);
104 result = langFontLink->GetCharCodePages(character, &charCodePages);
108 fontCodePages |= FontPlatformData::getKnownFontCodePages(faceName);
109 if (fontCodePages & charCodePages)
116 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
117 static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0)
120 if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &mlangFont)))
126 static HFONT createMLangFont(IMLangFontLink* langFontLink, HDC hdc, const FontPlatformData& refFont, DWORD codePageMask)
129 LRESULT result = langFontLink->MapFont(hdc, codePageMask, refFont.hfont(), &mlangFont);
131 return result == S_OK ? mlangFont : 0;
135 static const Vector<DWORD, 4>& getCJKCodePageMasks()
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[] = {
141 936, /* Simplified Chinese */
142 950, /* Traditional Chinese */
146 static Vector<DWORD, 4> codePageMasks;
147 static bool initialized;
150 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
151 IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
153 IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface();
156 return codePageMasks;
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);
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]) {
168 langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask);
169 codePageMasks.append(codePageMask);
173 return codePageMasks;
177 struct TraitsInFamilyProcData {
178 TraitsInFamilyProcData(const AtomicString& familyName)
179 : m_familyName(familyName)
183 const AtomicString& m_familyName;
184 HashSet<unsigned> m_traitsMasks;
187 static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
189 TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam);
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 :
204 procData->m_traitsMasks.add(traitsMask);
208 void FontCache::platformInit()
212 void FontCache::comInitialize()
216 void FontCache::comUninitialize()
219 langFontLink->Release();
223 multiLanguage->Release();
228 const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
231 WCHAR name[LF_FACESIZE];
233 UChar character = characters[0];
234 const FontPlatformData& origFont = font.primaryFont()->fontDataForCharacter(character)->platformData();
235 unsigned unicodeRange = findCharUnicodeRange(character);
237 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
238 if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
240 if (IMLangFontLink* langFontLink = getFontLinkInterface()) {
242 HGDIOBJ oldFont = GetCurrentObject(g_screenDC, OBJ_FONT);
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]);
258 hfont = createMLangFont(langFontLink, g_screenDC, origFont, CJKCodePageMasks[i]);
263 SelectObject(g_screenDC, hfont);
264 GetTextFace(g_screenDC, LF_FACESIZE, name);
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)) {
272 if (!currentFontContainsCharacter(langFontLink, g_screenDC, hfont, character, name)) {
274 SelectObject(g_screenDC, oldFont);
275 langFontLink->ReleaseFont(hfont);
283 #if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
284 hfont = createMLangFont(langFontLink, g_screenDC, codePages, character);
286 hfont = createMLangFont(langFontLink, g_screenDC, origFont, codePages);
288 SelectObject(g_screenDC, hfont);
289 GetTextFace(g_screenDC, LF_FACESIZE, name);
291 SelectObject(g_screenDC, oldFont);
295 langFontLink->ReleaseFont(hfont);
297 FontPlatformData::mapKnownFont(codePages, familyName);
300 if (familyName.isEmpty())
301 familyName = FontPlatformData::defaultFontFamily();
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);
309 FontPlatformData* result = getCachedFontPlatformData(fontDescription, familyName);
310 if (result && result->hash() != origFont.hash()) {
311 if (SimpleFontData* fontData = getCachedFontData(result, DoNotRetain))
319 SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
324 SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDesc, ShouldRetain shouldRetain)
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(), false, shouldRetain);
331 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
333 FontPlatformData* result = new FontPlatformData(fontDescription, family);
337 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
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;
346 TraitsInFamilyProcData procData(familyName);
347 EnumFontFamiliesEx(g_screenDC, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
348 copyToVector(procData.m_traitsMasks, traitsMasks);
351 } // namespace WebCore