OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2006, 2007, 2008, 2009, 2010, 2012 Google Inc. All rights reser
ved. | 2 * Copyright (c) 2006, 2007, 2008, 2009, 2010, 2012 Google Inc. All rights reser
ved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 24 matching lines...) Expand all Loading... |
35 #include "SkTypeface.h" | 35 #include "SkTypeface.h" |
36 #include "wtf/HashMap.h" | 36 #include "wtf/HashMap.h" |
37 #include "wtf/StringExtras.h" | 37 #include "wtf/StringExtras.h" |
38 #include "wtf/text/StringHash.h" | 38 #include "wtf/text/StringHash.h" |
39 #include "wtf/text/WTFString.h" | 39 #include "wtf/text/WTFString.h" |
40 #include <limits> | 40 #include <limits> |
41 #include <unicode/uchar.h> | 41 #include <unicode/uchar.h> |
42 | 42 |
43 namespace blink { | 43 namespace blink { |
44 | 44 |
| 45 static bool isUnambiguousUnifiedHanScript(UScriptCode script) |
| 46 { |
| 47 // localeToScriptCodeForFontSelection() does not return these values. |
| 48 ASSERT(script != USCRIPT_HIRAGANA && script != USCRIPT_KATAKANA); |
| 49 return script == USCRIPT_KATAKANA_OR_HIRAGANA |
| 50 || script == USCRIPT_SIMPLIFIED_HAN |
| 51 || script == USCRIPT_TRADITIONAL_HAN |
| 52 || script == USCRIPT_HANGUL; |
| 53 } |
| 54 |
| 55 static UScriptCode scriptCodeForUnifiedHanFromSubtag(const String& subtag) |
| 56 { |
| 57 struct SubtagScript { |
| 58 const char* subtag; |
| 59 UScriptCode script; |
| 60 }; |
| 61 |
| 62 static const SubtagScript subtagScriptList[] = { |
| 63 { "cn", USCRIPT_SIMPLIFIED_HAN }, |
| 64 { "hans", USCRIPT_SIMPLIFIED_HAN }, |
| 65 { "hant", USCRIPT_TRADITIONAL_HAN }, |
| 66 { "hk", USCRIPT_TRADITIONAL_HAN }, |
| 67 { "jp", USCRIPT_HIRAGANA }, |
| 68 { "kr", USCRIPT_HANGUL }, |
| 69 { "tw", USCRIPT_TRADITIONAL_HAN }, |
| 70 }; |
| 71 |
| 72 typedef HashMap<String, UScriptCode> SubtagScriptMap; |
| 73 DEFINE_STATIC_LOCAL(SubtagScriptMap, subtagScriptMap, ()); |
| 74 if (subtagScriptMap.isEmpty()) { |
| 75 for (size_t i = 0; i < WTF_ARRAY_LENGTH(subtagScriptList); ++i) |
| 76 subtagScriptMap.set(subtagScriptList[i].subtag, subtagScriptList[i].
script); |
| 77 } |
| 78 |
| 79 const auto& it = subtagScriptMap.find(subtag.lower()); |
| 80 return it != subtagScriptMap.end() ? it->value : USCRIPT_COMMON; |
| 81 } |
| 82 |
| 83 UScriptCode scriptCodeForUnifiedHanFromSubtags(const String& locale) |
| 84 { |
| 85 // Some sites emit lang="en-JP" when English is set as the preferred |
| 86 // language. Use script/region subtags of the content locale to pick the |
| 87 // fallback font for unified Han ideographs. |
| 88 for (size_t delimiter = locale.find('-'); delimiter != kNotFound; ) { |
| 89 ++delimiter; |
| 90 size_t end = locale.find('-', delimiter); |
| 91 UScriptCode script = scriptCodeForUnifiedHanFromSubtag( |
| 92 locale.substring(delimiter, |
| 93 end == kNotFound ? UINT_MAX : end - delimiter)); |
| 94 if (script != USCRIPT_COMMON) |
| 95 return script; |
| 96 delimiter = end; |
| 97 } |
| 98 |
| 99 // Fallback to the UI locale. |
| 100 return USCRIPT_HAN; |
| 101 } |
| 102 |
45 UScriptCode scriptCodeForUnifiedHanFromLocale(const icu::Locale& locale) | 103 UScriptCode scriptCodeForUnifiedHanFromLocale(const icu::Locale& locale) |
46 { | 104 { |
47 // ICU default locale may have country as an empty string or differently. | 105 // ICU default locale may have country as an empty string or differently. |
48 // Avoid fullName comparisons for Japanese and Korean where language() | 106 // Avoid fullName comparisons for Japanese and Korean where language() |
49 // can safely disambiguate. | 107 // can safely disambiguate. |
50 if (strcasecmp(locale.getLanguage(), icu::Locale::getJapanese().getLanguage(
)) == 0) | 108 if (strcasecmp(locale.getLanguage(), icu::Locale::getJapanese().getLanguage(
)) == 0) |
51 return USCRIPT_HIRAGANA; | 109 return USCRIPT_HIRAGANA; |
52 if (strcasecmp(locale.getLanguage(), icu::Locale::getKorean().getLanguage())
== 0) | 110 if (strcasecmp(locale.getLanguage(), icu::Locale::getKorean().getLanguage())
== 0) |
53 return USCRIPT_HANGUL; | 111 return USCRIPT_HANGUL; |
54 | 112 |
55 const icu::Locale& traditionalChinese = icu::Locale::getTraditionalChinese()
; | 113 // Chinese and non-CJK languages may be able to determine from subtags. |
56 if (strcasecmp(locale.getLanguage(), traditionalChinese.getLanguage()) == 0 | 114 UScriptCode script = scriptCodeForUnifiedHanFromSubtag(locale.getScript()); |
57 && (strcasecmp(locale.getCountry(), traditionalChinese.getCountry()) ==
0 | 115 if (script != USCRIPT_COMMON) |
58 || strcasecmp(locale.getCountry(), "HK") == 0 | 116 return script; |
59 || strcasecmp(locale.getScript(), "Hant") == 0)) { | 117 script = scriptCodeForUnifiedHanFromSubtag(locale.getCountry()); |
60 return USCRIPT_TRADITIONAL_HAN; | 118 if (script != USCRIPT_COMMON) |
61 } | 119 return script; |
62 | 120 |
63 // For other locales, use the simplified Chinese font for Han. | 121 // For other locales, use the simplified Chinese font for Han. |
64 return USCRIPT_SIMPLIFIED_HAN; | 122 return USCRIPT_SIMPLIFIED_HAN; |
65 } | 123 } |
66 | 124 |
67 namespace { | 125 namespace { |
68 | 126 |
69 static inline bool isFontPresent(const UChar* fontName, SkFontMgr* fontManager) | 127 static inline bool isFontPresent(const UChar* fontName, SkFontMgr* fontManager) |
70 { | 128 { |
71 String family = fontName; | 129 String family = fontName; |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 // FIXME: | 452 // FIXME: |
395 // - Handle 'Inherited', 'Common' and 'Unknown' | 453 // - Handle 'Inherited', 'Common' and 'Unknown' |
396 // (see http://www.unicode.org/reports/tr24/#Usage_Model ) | 454 // (see http://www.unicode.org/reports/tr24/#Usage_Model ) |
397 // For 'Inherited' and 'Common', perhaps we need to | 455 // For 'Inherited' and 'Common', perhaps we need to |
398 // accept another parameter indicating the previous family | 456 // accept another parameter indicating the previous family |
399 // and just return it. | 457 // and just return it. |
400 // - All the characters (or characters up to the point a single | 458 // - All the characters (or characters up to the point a single |
401 // font can cover) need to be taken into account | 459 // font can cover) need to be taken into account |
402 const UChar* getFallbackFamily(UChar32 character, | 460 const UChar* getFallbackFamily(UChar32 character, |
403 FontDescription::GenericFamilyType generic, | 461 FontDescription::GenericFamilyType generic, |
| 462 UScriptCode contentScript, |
| 463 const AtomicString& contentLocale, |
404 UScriptCode* scriptChecked, | 464 UScriptCode* scriptChecked, |
405 SkFontMgr* fontManager) | 465 SkFontMgr* fontManager) |
406 { | 466 { |
407 ASSERT(character); | 467 ASSERT(character); |
408 ASSERT(fontManager); | 468 ASSERT(fontManager); |
409 const UChar* family = getFontBasedOnUnicodeBlock(character, fontManager); | 469 const UChar* family = getFontBasedOnUnicodeBlock(character, fontManager); |
410 if (family) { | 470 if (family) { |
411 if (scriptChecked) | 471 if (scriptChecked) |
412 *scriptChecked = USCRIPT_INVALID_CODE; | 472 *scriptChecked = USCRIPT_INVALID_CODE; |
413 return family; | 473 return family; |
414 } | 474 } |
415 | 475 |
416 UScriptCode script = getScript(character); | 476 UScriptCode script = getScript(character); |
417 | 477 |
418 // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for | 478 // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for |
419 // Han (determined in a locale-dependent way above). Full-width ASCII | 479 // Han (determined in a locale-dependent way above). Full-width ASCII |
420 // characters are rather widely used in Japanese and Chinese documents and | 480 // characters are rather widely used in Japanese and Chinese documents and |
421 // they're fully covered by Chinese, Japanese and Korean fonts. | 481 // they're fully covered by Chinese, Japanese and Korean fonts. |
422 if (0xFF00 < character && character < 0xFF5F) | 482 if (0xFF00 < character && character < 0xFF5F) |
423 script = USCRIPT_HAN; | 483 script = USCRIPT_HAN; |
424 | 484 |
425 if (script == USCRIPT_COMMON) | 485 if (script == USCRIPT_COMMON) |
426 script = getScriptBasedOnUnicodeBlock(character); | 486 script = getScriptBasedOnUnicodeBlock(character); |
427 | 487 |
| 488 // For unified-Han scripts, try the lang attribute. |
| 489 if (script == USCRIPT_HAN) { |
| 490 if (isUnambiguousUnifiedHanScript(contentScript)) |
| 491 script = contentScript; |
| 492 else |
| 493 script = scriptCodeForUnifiedHanFromSubtags(contentLocale); |
| 494 } |
| 495 |
428 family = getFontFamilyForScript(script, generic, fontManager); | 496 family = getFontFamilyForScript(script, generic, fontManager); |
429 // Another lame work-around to cover non-BMP characters. | 497 // Another lame work-around to cover non-BMP characters. |
430 // If the font family for script is not found or the character is | 498 // If the font family for script is not found or the character is |
431 // not in BMP (> U+FFFF), we resort to the hard-coded list of | 499 // not in BMP (> U+FFFF), we resort to the hard-coded list of |
432 // fallback fonts for now. | 500 // fallback fonts for now. |
433 if (!family || character > 0xFFFF) { | 501 if (!family || character > 0xFFFF) { |
434 int plane = character >> 16; | 502 int plane = character >> 16; |
435 switch (plane) { | 503 switch (plane) { |
436 case 1: | 504 case 1: |
437 family = L"code2001"; | 505 family = L"code2001"; |
(...skipping 13 matching lines...) Expand all Loading... |
451 family = L"lucida sans unicode"; | 519 family = L"lucida sans unicode"; |
452 } | 520 } |
453 } | 521 } |
454 | 522 |
455 if (scriptChecked) | 523 if (scriptChecked) |
456 *scriptChecked = script; | 524 *scriptChecked = script; |
457 return family; | 525 return family; |
458 } | 526 } |
459 | 527 |
460 } // namespace blink | 528 } // namespace blink |
OLD | NEW |