[chromium] Convert uses of GetDC to HWndDC.
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / FontUtilsChromiumWin.cpp
1 /*
2  * Copyright (c) 2006, 2007, 2008, 2009, 2010, 2012 Google Inc. All rights reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "FontUtilsChromiumWin.h"
33
34 #include <limits>
35
36 #include "HWndDC.h"
37 #include "PlatformString.h"
38 #include "UniscribeHelper.h"
39 #include <unicode/locid.h>
40 #include <unicode/uchar.h>
41 #include <wtf/HashMap.h>
42 #include <wtf/text/StringHash.h>
43
44 namespace WebCore {
45
46 namespace {
47
48 bool isFontPresent(const UChar* fontName)
49 {
50     HFONT hfont = CreateFont(12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51                              fontName);
52     if (!hfont)
53         return false;
54     HWndDC dc(0);
55     HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont));
56     WCHAR actualFontName[LF_FACESIZE];
57     GetTextFace(dc, LF_FACESIZE, actualFontName);
58     actualFontName[LF_FACESIZE - 1] = 0;
59     SelectObject(dc, oldFont);
60     DeleteObject(hfont);
61     // We don't have to worry about East Asian fonts with locale-dependent
62     // names here for now.
63     return !wcscmp(fontName, actualFontName);
64 }
65
66 // A simple mapping from UScriptCode to family name.  This is a sparse array,
67 // which works well since the range of UScriptCode values is small.
68 typedef const UChar* ScriptToFontMap[USCRIPT_CODE_LIMIT];
69
70 void initializeScriptFontMap(ScriptToFontMap& scriptFontMap)
71 {
72     struct FontMap {
73         UScriptCode script;
74         const UChar* family;
75     };
76
77     static const FontMap fontMap[] = {
78         {USCRIPT_LATIN, L"times new roman"},
79         {USCRIPT_GREEK, L"times new roman"},
80         {USCRIPT_CYRILLIC, L"times new roman"},
81         // FIXME: Consider trying new Vista fonts before XP fonts for CJK.
82         // Some Vista users do want to use Vista cleartype CJK fonts. If we
83         // did, the results of tests with CJK characters would have to be
84         // regenerated for Vista.
85         {USCRIPT_SIMPLIFIED_HAN, L"simsun"},
86         {USCRIPT_TRADITIONAL_HAN, L"pmingliu"},
87         {USCRIPT_HIRAGANA, L"ms pgothic"},
88         {USCRIPT_KATAKANA, L"ms pgothic"},
89         {USCRIPT_KATAKANA_OR_HIRAGANA, L"ms pgothic"},
90         {USCRIPT_HANGUL, L"gulim"},
91         {USCRIPT_THAI, L"tahoma"},
92         {USCRIPT_HEBREW, L"david"},
93         {USCRIPT_ARABIC, L"tahoma"},
94         {USCRIPT_DEVANAGARI, L"mangal"},
95         {USCRIPT_BENGALI, L"vrinda"},
96         {USCRIPT_GURMUKHI, L"raavi"},
97         {USCRIPT_GUJARATI, L"shruti"},
98         {USCRIPT_TAMIL, L"latha"},
99         {USCRIPT_TELUGU, L"gautami"},
100         {USCRIPT_KANNADA, L"tunga"},
101         {USCRIPT_GEORGIAN, L"sylfaen"},
102         {USCRIPT_ARMENIAN, L"sylfaen"},
103         {USCRIPT_THAANA, L"mv boli"},
104         {USCRIPT_CANADIAN_ABORIGINAL, L"euphemia"},
105         {USCRIPT_CHEROKEE, L"plantagenet cherokee"},
106         {USCRIPT_MONGOLIAN, L"mongolian balti"},
107         // For USCRIPT_COMMON, we map blocks to scripts when
108         // that makes sense.
109     };
110
111     struct ScriptToFontFamilies {
112         UScriptCode script;
113         const UChar** families;
114     };
115
116     // Kartika on Vista or earlier lacks the support for Chillu 
117     // letters added to Unicode 5.1.
118     // Try AnjaliOldLipi (a very widely used Malaylalam font with the full
119     // Unicode 5.x support) before falling back to Kartika.
120     static const UChar* malayalamFonts[] = {L"AnjaliOldLipi", L"Lohit Malayalam", L"Kartika", L"Rachana", 0};
121     // Try Khmer OS before Vista fonts because 'Khmer OS' goes along better
122     // with Latin and looks better/larger for the same size.
123     static const UChar* khmerFonts[] = {L"Khmer OS", L"MoolBoran", L"DaunPenh", L"Code2000", 0};
124     // For the following 6 scripts, two or fonts are listed. The fonts in 
125     // the 1st slot are not available on Windows XP. To support these
126     // scripts on XP, listed in the rest of slots are widely used
127     // fonts.
128     static const UChar* ethiopicFonts[] = {L"Nyala", L"Abyssinica SIL", L"Ethiopia Jiret", L"Visual Geez Unicode", L"GF Zemen Unicode", 0};
129     static const UChar* oriyaFonts[] = {L"Kalinga", L"ori1Uni", L"Lohit Oriya", 0};
130     static const UChar* laoFonts[] = {L"DokChampa", L"Saysettha OT", L"Phetsarath OT", L"Code2000", 0};
131     static const UChar* tibetanFonts[] = {L"Microsoft Himalaya", L"Jomolhari", L"Tibetan Machine Uni", 0};
132     static const UChar* sinhalaFonts[] = {L"Iskoola Pota", L"AksharUnicode", 0};
133     static const UChar* yiFonts[] = {L"Microsoft Yi Balti", L"Nuosu SIL", L"Code2000", 0};
134     // http://www.bethmardutho.org/support/meltho/download/index.php
135     static const UChar* syriacFonts[] = {L"Estrangelo Edessa", L"Estrangelo Nisibin", L"Code2000", 0};
136     // No Myanmar/Burmese font is shipped with Windows, yet. Try a few
137     // widely available/used ones that supports Unicode 5.1 or later. 
138     static const UChar* myanmarFonts[] = {L"Padauk", L"Parabaik", L"Myanmar3", L"Code2000", 0};
139
140     static const ScriptToFontFamilies scriptToFontFamilies[] = {
141         {USCRIPT_MALAYALAM, malayalamFonts},
142         {USCRIPT_KHMER, khmerFonts},
143         {USCRIPT_ETHIOPIC, ethiopicFonts},
144         {USCRIPT_ORIYA, oriyaFonts},
145         {USCRIPT_LAO, laoFonts},
146         {USCRIPT_TIBETAN, tibetanFonts},
147         {USCRIPT_SINHALA, sinhalaFonts},
148         {USCRIPT_YI, yiFonts},
149         {USCRIPT_SYRIAC, syriacFonts},
150         {USCRIPT_MYANMAR, myanmarFonts},
151     };
152
153     for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontMap); ++i)
154         scriptFontMap[fontMap[i].script] = fontMap[i].family;
155
156     // FIXME: Instead of scanning the hard-coded list, we have to 
157     // use EnumFont* to 'inspect' fonts to pick up fonts covering scripts
158     // when it's possible (e.g. using OS/2 table). If we do that, this 
159     // had better be pulled out of here.
160     for (size_t i = 0; i < WTF_ARRAY_LENGTH(scriptToFontFamilies); ++i) {
161         UScriptCode script = scriptToFontFamilies[i].script;
162         scriptFontMap[script] = 0;
163         const UChar** familyPtr = scriptToFontFamilies[i].families;
164         while (*familyPtr) {
165             if (isFontPresent(*familyPtr)) {
166                 scriptFontMap[script] = *familyPtr;
167                 break;
168             }
169             ++familyPtr;
170         }
171     }
172
173     // Initialize the locale-dependent mapping.
174     // Since Chrome synchronizes the ICU default locale with its UI locale,
175     // this ICU locale tells the current UI locale of Chrome.
176     icu::Locale locale = icu::Locale::getDefault();
177     const UChar* localeFamily = 0;
178     if (locale == icu::Locale::getJapanese())
179         localeFamily = scriptFontMap[USCRIPT_HIRAGANA];
180     else if (locale == icu::Locale::getKorean())
181         localeFamily = scriptFontMap[USCRIPT_HANGUL];
182     else if (locale == icu::Locale::getTraditionalChinese())
183         localeFamily = scriptFontMap[USCRIPT_TRADITIONAL_HAN];
184     else {
185         // For other locales, use the simplified Chinese font for Han.
186         localeFamily = scriptFontMap[USCRIPT_SIMPLIFIED_HAN];
187     }
188     if (localeFamily)
189         scriptFontMap[USCRIPT_HAN] = localeFamily;
190 }
191
192 // There are a lot of characters in USCRIPT_COMMON that can be covered
193 // by fonts for scripts closely related to them. See
194 // http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:]
195 // FIXME: make this more efficient with a wider coverage
196 UScriptCode getScriptBasedOnUnicodeBlock(int ucs4)
197 {
198     UBlockCode block = ublock_getCode(ucs4);
199     switch (block) {
200     case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
201         return USCRIPT_HAN;
202     case UBLOCK_HIRAGANA:
203     case UBLOCK_KATAKANA:
204         return USCRIPT_HIRAGANA;
205     case UBLOCK_ARABIC:
206         return USCRIPT_ARABIC;
207     case UBLOCK_THAI:
208         return USCRIPT_THAI;
209     case UBLOCK_GREEK:
210         return USCRIPT_GREEK;
211     case UBLOCK_DEVANAGARI:
212         // For Danda and Double Danda (U+0964, U+0965), use a Devanagari
213         // font for now although they're used by other scripts as well.
214         // Without a context, we can't do any better.
215         return USCRIPT_DEVANAGARI;
216     case UBLOCK_ARMENIAN:
217         return USCRIPT_ARMENIAN;
218     case UBLOCK_GEORGIAN:
219         return USCRIPT_GEORGIAN;
220     case UBLOCK_KANNADA:
221         return USCRIPT_KANNADA;
222     default:
223         return USCRIPT_COMMON;
224     }
225 }
226
227 UScriptCode getScript(int ucs4)
228 {
229     UErrorCode err = U_ZERO_ERROR;
230     UScriptCode script = uscript_getScript(ucs4, &err);
231     // If script is invalid, common or inherited or there's an error,
232     // infer a script based on the unicode block of a character.
233     if (script <= USCRIPT_INHERITED || U_FAILURE(err))
234         script = getScriptBasedOnUnicodeBlock(ucs4);
235     return script;
236 }
237
238 const int kUndefinedAscent = std::numeric_limits<int>::min();
239
240 // Given an HFONT, return the ascent. If GetTextMetrics fails,
241 // kUndefinedAscent is returned, instead.
242 int getAscent(HFONT hfont)
243 {
244     HWndDC dc(0);
245     HGDIOBJ oldFont = SelectObject(dc, hfont);
246     TEXTMETRIC tm;
247     BOOL gotMetrics = GetTextMetrics(dc, &tm);
248     SelectObject(dc, oldFont);
249     return gotMetrics ? tm.tmAscent : kUndefinedAscent;
250 }
251
252 WORD getSpaceGlyph(HFONT hfont) 
253 {
254     HWndDC dc(0);
255     HGDIOBJ oldFont = SelectObject(dc, hfont);
256     WCHAR space = L' ';
257     WORD spaceGlyph = 0;
258     GetGlyphIndices(dc, &space, 1, &spaceGlyph, 0);
259     SelectObject(dc, oldFont);
260     return spaceGlyph;
261 }
262
263 struct FontData {
264     FontData()
265         : hfont(0)
266         , ascent(kUndefinedAscent)
267         , scriptCache(0)
268         , spaceGlyph(0)
269     {
270     }
271
272     HFONT hfont;
273     int ascent;
274     mutable SCRIPT_CACHE scriptCache;
275     WORD spaceGlyph;
276 };
277
278 // Again, using hash_map does not earn us much here.  page_cycler_test intl2
279 // gave us a 'better' result with map than with hash_map even though they're
280 // well-within 1-sigma of each other so that the difference is not significant.
281 // On the other hand, some pages in intl2 seem to take longer to load with map
282 // in the 1st pass. Need to experiment further.
283 typedef HashMap<String, FontData> FontDataCache;
284
285 } // namespace
286
287 // FIXME: this is font fallback code version 0.1
288 //  - Cover all the scripts
289 //  - Get the default font for each script/generic family from the
290 //    preference instead of hardcoding in the source.
291 //    (at least, read values from the registry for IE font settings).
292 //  - Support generic families (from FontDescription)
293 //  - If the default font for a script is not available,
294 //    try some more fonts known to support it. Finally, we can
295 //    use EnumFontFamilies or similar APIs to come up with a list of
296 //    fonts supporting the script and cache the result.
297 //  - Consider using UnicodeSet (or UnicodeMap) converted from
298 //    GLYPHSET (BMP) or directly read from truetype cmap tables to
299 //    keep track of which character is supported by which font
300 //  - Update script_font_cache in response to WM_FONTCHANGE
301
302 const UChar* getFontFamilyForScript(UScriptCode script,
303                                     FontDescription::GenericFamilyType generic)
304 {
305     static ScriptToFontMap scriptFontMap;
306     static bool initialized = false;
307     if (!initialized) {
308         initializeScriptFontMap(scriptFontMap);
309         initialized = true;
310     }
311     if (script == USCRIPT_INVALID_CODE)
312         return 0;
313     ASSERT(script < USCRIPT_CODE_LIMIT);
314     return scriptFontMap[script];
315 }
316
317 // FIXME:
318 //  - Handle 'Inherited', 'Common' and 'Unknown'
319 //    (see http://www.unicode.org/reports/tr24/#Usage_Model )
320 //    For 'Inherited' and 'Common', perhaps we need to
321 //    accept another parameter indicating the previous family
322 //    and just return it.
323 //  - All the characters (or characters up to the point a single
324 //    font can cover) need to be taken into account
325 const UChar* getFallbackFamily(const UChar* characters,
326                                int length,
327                                FontDescription::GenericFamilyType generic,
328                                UChar32* charChecked,
329                                UScriptCode* scriptChecked)
330 {
331     ASSERT(characters && characters[0] && length > 0);
332     UScriptCode script = USCRIPT_COMMON;
333
334     // Sometimes characters common to script (e.g. space) is at
335     // the beginning of a string so that we need to skip them
336     // to get a font required to render the string.
337     int i = 0;
338     UChar32 ucs4 = 0;
339     while (i < length && script == USCRIPT_COMMON) {
340         U16_NEXT(characters, i, length, ucs4);
341         script = getScript(ucs4);
342     }
343
344     // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for
345     // Han (determined in a locale-dependent way above). Full-width ASCII
346     // characters are rather widely used in Japanese and Chinese documents and
347     // they're fully covered by Chinese, Japanese and Korean fonts.
348     if (0xFF00 < ucs4 && ucs4 < 0xFF5F)
349         script = USCRIPT_HAN;
350
351     if (script == USCRIPT_COMMON)
352         script = getScriptBasedOnUnicodeBlock(ucs4);
353
354     const UChar* family = getFontFamilyForScript(script, generic);
355     // Another lame work-around to cover non-BMP characters.
356     // If the font family for script is not found or the character is
357     // not in BMP (> U+FFFF), we resort to the hard-coded list of
358     // fallback fonts for now.
359     if (!family || ucs4 > 0xFFFF) {
360         int plane = ucs4 >> 16;
361         switch (plane) {
362         case 1:
363             family = L"code2001";
364             break;
365         case 2:
366             // Use a Traditional Chinese ExtB font if in Traditional Chinese locale.
367             // Otherwise, use a Simplified Chinese ExtB font. Windows Japanese
368             // fonts do support a small subset of ExtB (that are included in JIS X 0213),
369             // but its coverage is rather sparse.
370             // Eventually, this should be controlled by lang/xml:lang.
371             if (icu::Locale::getDefault() == icu::Locale::getTraditionalChinese())
372               family = L"pmingliu-extb";
373             else
374               family = L"simsun-extb";
375             break;
376         default:
377             family = L"lucida sans unicode";
378         }
379     }
380
381     if (charChecked)
382         *charChecked = ucs4;
383     if (scriptChecked)
384         *scriptChecked = script;
385     return family;
386 }
387
388 // Be aware that this is not thread-safe.
389 bool getDerivedFontData(const UChar* family,
390                         int style,
391                         LOGFONT* logfont,
392                         int* ascent,
393                         HFONT* hfont,
394                         SCRIPT_CACHE** scriptCache,
395                         WORD* spaceGlyph)
396 {
397     ASSERT(logfont);
398     ASSERT(family);
399     ASSERT(*family);
400
401     // It does not matter that we leak font data when we exit.
402     static FontDataCache fontDataCache;
403
404     // FIXME: This comes up pretty high in the profile so that
405     // we need to measure whether using SHA256 (after coercing all the
406     // fields to char*) is faster than String::format.
407     String fontKey = String::format("%1d:%d:%ls", style, logfont->lfHeight, family);
408     FontDataCache::iterator iter = fontDataCache.find(fontKey);
409     FontData* derived;
410     if (iter == fontDataCache.end()) {
411         ASSERT(wcslen(family) < LF_FACESIZE);
412         wcscpy_s(logfont->lfFaceName, LF_FACESIZE, family);
413         // FIXME: CreateFontIndirect always comes up with
414         // a font even if there's no font matching the name. Need to
415         // check it against what we actually want (as is done in
416         // FontCacheWin.cpp)
417         pair<FontDataCache::iterator, bool> entry = fontDataCache.add(fontKey, FontData());
418         derived = &entry.first->second;
419         derived->hfont = CreateFontIndirect(logfont);
420         // GetAscent may return kUndefinedAscent, but we still want to
421         // cache it so that we won't have to call CreateFontIndirect once
422         // more for HFONT next time.
423         derived->ascent = getAscent(derived->hfont);
424         derived->spaceGlyph = getSpaceGlyph(derived->hfont);
425     } else {
426         derived = &iter->second;
427         // Last time, GetAscent failed so that only HFONT was
428         // cached. Try once more assuming that TryPreloadFont
429         // was called by a caller between calls.
430         if (kUndefinedAscent == derived->ascent)
431             derived->ascent = getAscent(derived->hfont);
432     }
433     *hfont = derived->hfont;
434     *ascent = derived->ascent;
435     *scriptCache = &(derived->scriptCache);
436     *spaceGlyph = derived->spaceGlyph;
437     return *ascent != kUndefinedAscent;
438 }
439
440 int getStyleFromLogfont(const LOGFONT* logfont)
441 {
442     // FIXME: consider defining UNDEFINED or INVALID for style and
443     //                  returning it when logfont is 0
444     if (!logfont) {
445         ASSERT_NOT_REACHED();
446         return FontStyleNormal;
447     }
448     return (logfont->lfItalic ? FontStyleItalic : FontStyleNormal) |
449            (logfont->lfUnderline ? FontStyleUnderlined : FontStyleNormal) |
450            (logfont->lfWeight >= 700 ? FontStyleBold : FontStyleNormal);
451 }
452
453 } // namespace WebCore