| 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 |