This source file includes following definitions.
- isFontPresent
- initializeScriptFontMap
- getScriptBasedOnUnicodeBlock
- getScript
- getFontFamilyForScript
- getFallbackFamily
- getFallbackFamilyForFirstNonCommonCharacter
#include "config.h"
#include "platform/fonts/win/FontFallbackWin.h"
#include "SkTypeface.h"
#include "wtf/HashMap.h"
#include "wtf/text/StringHash.h"
#include "wtf/text/WTFString.h"
#include <limits>
#include <unicode/locid.h>
#include <unicode/uchar.h>
namespace WebCore {
namespace {
static inline bool isFontPresent(const UChar* fontName)
{
String family = fontName;
RefPtr<SkTypeface> tf = adoptRef(SkTypeface::CreateFromName(family.utf8().data(), SkTypeface::kNormal));
if (!tf)
return false;
SkTypeface::LocalizedStrings* actualFamilies = tf->createFamilyNameIterator();
bool matchesRequestedFamily = false;
SkTypeface::LocalizedString actualFamily;
while (actualFamilies->next(&actualFamily)) {
if (equalIgnoringCase(family, AtomicString::fromUTF8(actualFamily.fString.c_str()))) {
matchesRequestedFamily = true;
break;
}
}
actualFamilies->unref();
return matchesRequestedFamily;
}
typedef const UChar* ScriptToFontMap[USCRIPT_CODE_LIMIT];
void initializeScriptFontMap(ScriptToFontMap& scriptFontMap)
{
struct FontMap {
UScriptCode script;
const UChar* family;
};
static const FontMap fontMap[] = {
{USCRIPT_LATIN, L"times new roman"},
{USCRIPT_GREEK, L"times new roman"},
{USCRIPT_CYRILLIC, L"times new roman"},
{USCRIPT_SIMPLIFIED_HAN, L"simsun"},
{USCRIPT_TRADITIONAL_HAN, L"pmingliu"},
{USCRIPT_HIRAGANA, L"ms pgothic"},
{USCRIPT_KATAKANA, L"ms pgothic"},
{USCRIPT_KATAKANA_OR_HIRAGANA, L"ms pgothic"},
{USCRIPT_HANGUL, L"gulim"},
{USCRIPT_THAI, L"tahoma"},
{USCRIPT_HEBREW, L"david"},
{USCRIPT_ARABIC, L"tahoma"},
{USCRIPT_DEVANAGARI, L"mangal"},
{USCRIPT_BENGALI, L"vrinda"},
{USCRIPT_GURMUKHI, L"raavi"},
{USCRIPT_GUJARATI, L"shruti"},
{USCRIPT_TAMIL, L"latha"},
{USCRIPT_TELUGU, L"gautami"},
{USCRIPT_KANNADA, L"tunga"},
{USCRIPT_GEORGIAN, L"sylfaen"},
{USCRIPT_ARMENIAN, L"sylfaen"},
{USCRIPT_THAANA, L"mv boli"},
{USCRIPT_CANADIAN_ABORIGINAL, L"euphemia"},
{USCRIPT_CHEROKEE, L"plantagenet cherokee"},
{USCRIPT_MONGOLIAN, L"mongolian balti"},
};
struct ScriptToFontFamilies {
UScriptCode script;
const UChar** families;
};
static const UChar* malayalamFonts[] = {L"AnjaliOldLipi", L"Lohit Malayalam", L"Kartika", L"Rachana", 0};
static const UChar* khmerFonts[] = {L"Khmer OS", L"MoolBoran", L"DaunPenh", L"Code2000", 0};
static const UChar* ethiopicFonts[] = {L"Nyala", L"Abyssinica SIL", L"Ethiopia Jiret", L"Visual Geez Unicode", L"GF Zemen Unicode", 0};
static const UChar* oriyaFonts[] = {L"Kalinga", L"ori1Uni", L"Lohit Oriya", 0};
static const UChar* laoFonts[] = {L"DokChampa", L"Saysettha OT", L"Phetsarath OT", L"Code2000", 0};
static const UChar* tibetanFonts[] = {L"Microsoft Himalaya", L"Jomolhari", L"Tibetan Machine Uni", 0};
static const UChar* sinhalaFonts[] = {L"Iskoola Pota", L"AksharUnicode", 0};
static const UChar* yiFonts[] = {L"Microsoft Yi Balti", L"Nuosu SIL", L"Code2000", 0};
static const UChar* syriacFonts[] = {L"Estrangelo Edessa", L"Estrangelo Nisibin", L"Code2000", 0};
static const UChar* myanmarFonts[] = {L"Padauk", L"Parabaik", L"Myanmar3", L"Code2000", 0};
static const ScriptToFontFamilies scriptToFontFamilies[] = {
{USCRIPT_MALAYALAM, malayalamFonts},
{USCRIPT_KHMER, khmerFonts},
{USCRIPT_ETHIOPIC, ethiopicFonts},
{USCRIPT_ORIYA, oriyaFonts},
{USCRIPT_LAO, laoFonts},
{USCRIPT_TIBETAN, tibetanFonts},
{USCRIPT_SINHALA, sinhalaFonts},
{USCRIPT_YI, yiFonts},
{USCRIPT_SYRIAC, syriacFonts},
{USCRIPT_MYANMAR, myanmarFonts},
};
for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontMap); ++i)
scriptFontMap[fontMap[i].script] = fontMap[i].family;
for (size_t i = 0; i < WTF_ARRAY_LENGTH(scriptToFontFamilies); ++i) {
UScriptCode script = scriptToFontFamilies[i].script;
scriptFontMap[script] = 0;
const UChar** familyPtr = scriptToFontFamilies[i].families;
while (*familyPtr) {
if (isFontPresent(*familyPtr)) {
scriptFontMap[script] = *familyPtr;
break;
}
++familyPtr;
}
}
icu::Locale locale = icu::Locale::getDefault();
const UChar* localeFamily = 0;
if (locale == icu::Locale::getJapanese()) {
localeFamily = scriptFontMap[USCRIPT_HIRAGANA];
} else if (locale == icu::Locale::getKorean()) {
localeFamily = scriptFontMap[USCRIPT_HANGUL];
} else if (locale == icu::Locale::getTraditionalChinese()) {
localeFamily = scriptFontMap[USCRIPT_TRADITIONAL_HAN];
} else {
localeFamily = scriptFontMap[USCRIPT_SIMPLIFIED_HAN];
}
if (localeFamily)
scriptFontMap[USCRIPT_HAN] = localeFamily;
}
UScriptCode getScriptBasedOnUnicodeBlock(int ucs4)
{
UBlockCode block = ublock_getCode(ucs4);
switch (block) {
case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
return USCRIPT_HAN;
case UBLOCK_HIRAGANA:
case UBLOCK_KATAKANA:
return USCRIPT_HIRAGANA;
case UBLOCK_ARABIC:
return USCRIPT_ARABIC;
case UBLOCK_THAI:
return USCRIPT_THAI;
case UBLOCK_GREEK:
return USCRIPT_GREEK;
case UBLOCK_DEVANAGARI:
return USCRIPT_DEVANAGARI;
case UBLOCK_ARMENIAN:
return USCRIPT_ARMENIAN;
case UBLOCK_GEORGIAN:
return USCRIPT_GEORGIAN;
case UBLOCK_KANNADA:
return USCRIPT_KANNADA;
default:
return USCRIPT_COMMON;
}
}
UScriptCode getScript(int ucs4)
{
UErrorCode err = U_ZERO_ERROR;
UScriptCode script = uscript_getScript(ucs4, &err);
if (script <= USCRIPT_INHERITED || U_FAILURE(err))
script = getScriptBasedOnUnicodeBlock(ucs4);
return script;
}
}
const UChar* getFontFamilyForScript(UScriptCode script,
FontDescription::GenericFamilyType generic)
{
static ScriptToFontMap scriptFontMap;
static bool initialized = false;
if (!initialized) {
initializeScriptFontMap(scriptFontMap);
initialized = true;
}
if (script == USCRIPT_INVALID_CODE)
return 0;
ASSERT(script < USCRIPT_CODE_LIMIT);
return scriptFontMap[script];
}
const UChar* getFallbackFamily(UChar32 character,
FontDescription::GenericFamilyType generic,
UScriptCode* scriptChecked)
{
ASSERT(character);
UScriptCode script = getScript(character);
if (0xFF00 < character && character < 0xFF5F)
script = USCRIPT_HAN;
if (script == USCRIPT_COMMON)
script = getScriptBasedOnUnicodeBlock(character);
const UChar* family = getFontFamilyForScript(script, generic);
if (!family || character > 0xFFFF) {
int plane = character >> 16;
switch (plane) {
case 1:
family = L"code2001";
break;
case 2:
if (icu::Locale::getDefault() == icu::Locale::getTraditionalChinese())
family = L"pmingliu-extb";
else
family = L"simsun-extb";
break;
default:
family = L"lucida sans unicode";
}
}
if (scriptChecked)
*scriptChecked = script;
return family;
}
const UChar* getFallbackFamilyForFirstNonCommonCharacter(const UChar* characters,
int length,
FontDescription::GenericFamilyType generic)
{
ASSERT(characters && characters[0] && length > 0);
UScriptCode script = USCRIPT_COMMON;
int i = 0;
UChar32 ucs4 = 0;
while (i < length && script == USCRIPT_COMMON) {
U16_NEXT(characters, i, length, ucs4);
script = getScript(ucs4);
}
const UChar* family = getFallbackFamily(ucs4, generic, 0);
return family;
}
}