initial import
[vuplus_webkit] / Source / WebCore / platform / graphics / wince / FontCacheWinCE.cpp
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, DoNotRetain))
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, ShouldRetain shouldRetain)
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(), false, shouldRetain);
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