Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / fonts / win / FontFallbackWin.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 "platform/fonts/win/FontFallbackWin.h"
33
34 #include "SkFontMgr.h"
35 #include "SkTypeface.h"
36 #include "wtf/HashMap.h"
37 #include "wtf/text/StringHash.h"
38 #include "wtf/text/WTFString.h"
39 #include <limits>
40 #include <unicode/locid.h>
41 #include <unicode/uchar.h>
42
43 namespace WebCore {
44
45 namespace {
46
47 static inline bool isFontPresent(const UChar* fontName, SkFontMgr* fontManager)
48 {
49     String family = fontName;
50     RefPtr<SkTypeface> tf = adoptRef(fontManager->legacyCreateTypeface(family.utf8().data(), SkTypeface::kNormal));
51     if (!tf)
52         return false;
53
54     SkTypeface::LocalizedStrings* actualFamilies = tf->createFamilyNameIterator();
55     bool matchesRequestedFamily = false;
56     SkTypeface::LocalizedString actualFamily;
57     while (actualFamilies->next(&actualFamily)) {
58         if (equalIgnoringCase(family, AtomicString::fromUTF8(actualFamily.fString.c_str()))) {
59             matchesRequestedFamily = true;
60             break;
61         }
62     }
63     actualFamilies->unref();
64
65     return matchesRequestedFamily;
66 }
67
68 // A simple mapping from UScriptCode to family name. This is a sparse array,
69 // which works well since the range of UScriptCode values is small.
70 typedef const UChar* ScriptToFontMap[USCRIPT_CODE_LIMIT];
71
72 void initializeScriptFontMap(ScriptToFontMap& scriptFontMap, SkFontMgr* fontManager)
73 {
74     struct FontMap {
75         UScriptCode script;
76         const UChar* family;
77     };
78
79     static const FontMap fontMap[] = {
80         {USCRIPT_LATIN, L"times new roman"},
81         {USCRIPT_GREEK, L"times new roman"},
82         {USCRIPT_CYRILLIC, L"times new roman"},
83         // FIXME: Consider trying new Vista fonts before XP fonts for CJK.
84         // Some Vista users do want to use Vista cleartype CJK fonts. If we
85         // did, the results of tests with CJK characters would have to be
86         // regenerated for Vista.
87         {USCRIPT_SIMPLIFIED_HAN, L"simsun"},
88         {USCRIPT_TRADITIONAL_HAN, L"pmingliu"},
89         {USCRIPT_HIRAGANA, L"ms pgothic"},
90         {USCRIPT_KATAKANA, L"ms pgothic"},
91         {USCRIPT_KATAKANA_OR_HIRAGANA, L"ms pgothic"},
92         {USCRIPT_HANGUL, L"gulim"},
93         {USCRIPT_THAI, L"tahoma"},
94         {USCRIPT_HEBREW, L"david"},
95         {USCRIPT_ARABIC, L"tahoma"},
96         {USCRIPT_DEVANAGARI, L"mangal"},
97         {USCRIPT_BENGALI, L"vrinda"},
98         {USCRIPT_GURMUKHI, L"raavi"},
99         {USCRIPT_GUJARATI, L"shruti"},
100         {USCRIPT_TAMIL, L"latha"},
101         {USCRIPT_TELUGU, L"gautami"},
102         {USCRIPT_KANNADA, L"tunga"},
103         {USCRIPT_GEORGIAN, L"sylfaen"},
104         {USCRIPT_ARMENIAN, L"sylfaen"},
105         {USCRIPT_THAANA, L"mv boli"},
106         {USCRIPT_CANADIAN_ABORIGINAL, L"euphemia"},
107         {USCRIPT_CHEROKEE, L"plantagenet cherokee"},
108         {USCRIPT_MONGOLIAN, L"mongolian balti"},
109         // For USCRIPT_COMMON, we map blocks to scripts when
110         // that makes sense.
111     };
112
113     struct ScriptToFontFamilies {
114         UScriptCode script;
115         const UChar** families;
116     };
117
118     // Kartika on Vista or earlier lacks the support for Chillu
119     // letters added to Unicode 5.1.
120     // Try AnjaliOldLipi (a very widely used Malaylalam font with the full
121     // Unicode 5.x support) before falling back to Kartika.
122     static const UChar* malayalamFonts[] = {L"AnjaliOldLipi", L"Lohit Malayalam", L"Kartika", L"Rachana", 0};
123     // Try Khmer OS before Vista fonts because 'Khmer OS' goes along better
124     // with Latin and looks better/larger for the same size.
125     static const UChar* khmerFonts[] = {L"Khmer OS", L"MoolBoran", L"DaunPenh", L"Code2000", 0};
126     // For the following 6 scripts, two or fonts are listed. The fonts in
127     // the 1st slot are not available on Windows XP. To support these
128     // scripts on XP, listed in the rest of slots are widely used
129     // fonts.
130     static const UChar* ethiopicFonts[] = {L"Nyala", L"Abyssinica SIL", L"Ethiopia Jiret", L"Visual Geez Unicode", L"GF Zemen Unicode", 0};
131     static const UChar* oriyaFonts[] = {L"Kalinga", L"ori1Uni", L"Lohit Oriya", 0};
132     static const UChar* laoFonts[] = {L"DokChampa", L"Saysettha OT", L"Phetsarath OT", L"Code2000", 0};
133     static const UChar* tibetanFonts[] = {L"Microsoft Himalaya", L"Jomolhari", L"Tibetan Machine Uni", 0};
134     static const UChar* sinhalaFonts[] = {L"Iskoola Pota", L"AksharUnicode", 0};
135     static const UChar* yiFonts[] = {L"Microsoft Yi Balti", L"Nuosu SIL", L"Code2000", 0};
136     // http://www.bethmardutho.org/support/meltho/download/index.php
137     static const UChar* syriacFonts[] = {L"Estrangelo Edessa", L"Estrangelo Nisibin", L"Code2000", 0};
138     // No Myanmar/Burmese font is shipped with Windows, yet. Try a few
139     // widely available/used ones that supports Unicode 5.1 or later.
140     static const UChar* myanmarFonts[] = {L"Padauk", L"Parabaik", L"Myanmar3", L"Code2000", 0};
141
142     static const ScriptToFontFamilies scriptToFontFamilies[] = {
143         {USCRIPT_MALAYALAM, malayalamFonts},
144         {USCRIPT_KHMER, khmerFonts},
145         {USCRIPT_ETHIOPIC, ethiopicFonts},
146         {USCRIPT_ORIYA, oriyaFonts},
147         {USCRIPT_LAO, laoFonts},
148         {USCRIPT_TIBETAN, tibetanFonts},
149         {USCRIPT_SINHALA, sinhalaFonts},
150         {USCRIPT_YI, yiFonts},
151         {USCRIPT_SYRIAC, syriacFonts},
152         {USCRIPT_MYANMAR, myanmarFonts},
153     };
154
155     for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontMap); ++i)
156         scriptFontMap[fontMap[i].script] = fontMap[i].family;
157
158     // FIXME: Instead of scanning the hard-coded list, we have to
159     // use EnumFont* to 'inspect' fonts to pick up fonts covering scripts
160     // when it's possible (e.g. using OS/2 table). If we do that, this
161     // had better be pulled out of here.
162     for (size_t i = 0; i < WTF_ARRAY_LENGTH(scriptToFontFamilies); ++i) {
163         UScriptCode script = scriptToFontFamilies[i].script;
164         scriptFontMap[script] = 0;
165         const UChar** familyPtr = scriptToFontFamilies[i].families;
166         while (*familyPtr) {
167             if (isFontPresent(*familyPtr, fontManager)) {
168                 scriptFontMap[script] = *familyPtr;
169                 break;
170             }
171             ++familyPtr;
172         }
173     }
174
175     // Initialize the locale-dependent mapping.
176     // Since Chrome synchronizes the ICU default locale with its UI locale,
177     // this ICU locale tells the current UI locale of Chrome.
178     icu::Locale locale = icu::Locale::getDefault();
179     const UChar* localeFamily = 0;
180     if (locale == icu::Locale::getJapanese()) {
181         localeFamily = scriptFontMap[USCRIPT_HIRAGANA];
182     } else if (locale == icu::Locale::getKorean()) {
183         localeFamily = scriptFontMap[USCRIPT_HANGUL];
184     } else if (locale == icu::Locale::getTraditionalChinese()) {
185         localeFamily = scriptFontMap[USCRIPT_TRADITIONAL_HAN];
186     } else {
187         // For other locales, use the simplified Chinese font for Han.
188         localeFamily = scriptFontMap[USCRIPT_SIMPLIFIED_HAN];
189     }
190     if (localeFamily)
191         scriptFontMap[USCRIPT_HAN] = localeFamily;
192 }
193
194 // There are a lot of characters in USCRIPT_COMMON that can be covered
195 // by fonts for scripts closely related to them. See
196 // http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:]
197 // FIXME: make this more efficient with a wider coverage
198 UScriptCode getScriptBasedOnUnicodeBlock(int ucs4)
199 {
200     UBlockCode block = ublock_getCode(ucs4);
201     switch (block) {
202     case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
203         return USCRIPT_HAN;
204     case UBLOCK_HIRAGANA:
205     case UBLOCK_KATAKANA:
206         return USCRIPT_HIRAGANA;
207     case UBLOCK_ARABIC:
208         return USCRIPT_ARABIC;
209     case UBLOCK_THAI:
210         return USCRIPT_THAI;
211     case UBLOCK_GREEK:
212         return USCRIPT_GREEK;
213     case UBLOCK_DEVANAGARI:
214         // For Danda and Double Danda (U+0964, U+0965), use a Devanagari
215         // font for now although they're used by other scripts as well.
216         // Without a context, we can't do any better.
217         return USCRIPT_DEVANAGARI;
218     case UBLOCK_ARMENIAN:
219         return USCRIPT_ARMENIAN;
220     case UBLOCK_GEORGIAN:
221         return USCRIPT_GEORGIAN;
222     case UBLOCK_KANNADA:
223         return USCRIPT_KANNADA;
224     default:
225         return USCRIPT_COMMON;
226     }
227 }
228
229 UScriptCode getScript(int ucs4)
230 {
231     UErrorCode err = U_ZERO_ERROR;
232     UScriptCode script = uscript_getScript(ucs4, &err);
233     // If script is invalid, common or inherited or there's an error,
234     // infer a script based on the unicode block of a character.
235     if (script <= USCRIPT_INHERITED || U_FAILURE(err))
236         script = getScriptBasedOnUnicodeBlock(ucs4);
237     return script;
238 }
239
240 } // namespace
241
242 // FIXME: this is font fallback code version 0.1
243 //  - Cover all the scripts
244 //  - Get the default font for each script/generic family from the
245 //    preference instead of hardcoding in the source.
246 //    (at least, read values from the registry for IE font settings).
247 //  - Support generic families (from FontDescription)
248 //  - If the default font for a script is not available,
249 //    try some more fonts known to support it. Finally, we can
250 //    use EnumFontFamilies or similar APIs to come up with a list of
251 //    fonts supporting the script and cache the result.
252 //  - Consider using UnicodeSet (or UnicodeMap) converted from
253 //    GLYPHSET (BMP) or directly read from truetype cmap tables to
254 //    keep track of which character is supported by which font
255 //  - Update script_font_cache in response to WM_FONTCHANGE
256
257 const UChar* getFontFamilyForScript(UScriptCode script,
258     FontDescription::GenericFamilyType generic,
259     SkFontMgr* fontManager)
260 {
261     static ScriptToFontMap scriptFontMap;
262     static bool initialized = false;
263     if (!initialized) {
264         initializeScriptFontMap(scriptFontMap, fontManager);
265         initialized = true;
266     }
267     if (script == USCRIPT_INVALID_CODE)
268         return 0;
269     ASSERT(script < USCRIPT_CODE_LIMIT);
270     return scriptFontMap[script];
271 }
272
273 // FIXME:
274 //  - Handle 'Inherited', 'Common' and 'Unknown'
275 //    (see http://www.unicode.org/reports/tr24/#Usage_Model )
276 //    For 'Inherited' and 'Common', perhaps we need to
277 //    accept another parameter indicating the previous family
278 //    and just return it.
279 //  - All the characters (or characters up to the point a single
280 //    font can cover) need to be taken into account
281 const UChar* getFallbackFamily(UChar32 character,
282     FontDescription::GenericFamilyType generic,
283     UScriptCode* scriptChecked,
284     SkFontMgr* fontManager)
285 {
286     ASSERT(character);
287     UScriptCode script = getScript(character);
288
289     // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for
290     // Han (determined in a locale-dependent way above). Full-width ASCII
291     // characters are rather widely used in Japanese and Chinese documents and
292     // they're fully covered by Chinese, Japanese and Korean fonts.
293     if (0xFF00 < character && character < 0xFF5F)
294         script = USCRIPT_HAN;
295
296     if (script == USCRIPT_COMMON)
297         script = getScriptBasedOnUnicodeBlock(character);
298
299     const UChar* family = getFontFamilyForScript(script, generic, fontManager);
300     // Another lame work-around to cover non-BMP characters.
301     // If the font family for script is not found or the character is
302     // not in BMP (> U+FFFF), we resort to the hard-coded list of
303     // fallback fonts for now.
304     if (!family || character > 0xFFFF) {
305         int plane = character >> 16;
306         switch (plane) {
307         case 1:
308             family = L"code2001";
309             break;
310         case 2:
311             // Use a Traditional Chinese ExtB font if in Traditional Chinese locale.
312             // Otherwise, use a Simplified Chinese ExtB font. Windows Japanese
313             // fonts do support a small subset of ExtB (that are included in JIS X 0213),
314             // but its coverage is rather sparse.
315             // Eventually, this should be controlled by lang/xml:lang.
316             if (icu::Locale::getDefault() == icu::Locale::getTraditionalChinese())
317                 family = L"pmingliu-extb";
318             else
319                 family = L"simsun-extb";
320             break;
321         default:
322             family = L"lucida sans unicode";
323         }
324     }
325
326     if (scriptChecked)
327         *scriptChecked = script;
328     return family;
329 }
330
331 } // namespace WebCore