FontUtilsChromiumWin.cpp [plain text]
#include "config.h"
#include "FontUtilsChromiumWin.h"
#include <limits>
#include "PlatformString.h"
#include "StringHash.h"
#include "UniscribeHelper.h"
#include <unicode/locid.h>
#include <unicode/uchar.h>
#include <wtf/HashMap.h>
namespace WebCore {
namespace {
typedef const UChar* ScriptToFontMap[USCRIPT_CODE_LIMIT];
void initializeScriptFontMap(ScriptToFontMap& scriptFontMap)
{
struct FontMap {
UScriptCode script;
const UChar* family;
};
const static 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_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_ORIYA, L"kalinga"},
{USCRIPT_TAMIL, L"latha"},
{USCRIPT_TELUGU, L"gautami"},
{USCRIPT_KANNADA, L"tunga"},
{USCRIPT_MALAYALAM, L"kartika"},
{USCRIPT_LAO, L"dokchampa"},
{USCRIPT_TIBETAN, L"microsoft himalaya"},
{USCRIPT_GEORGIAN, L"sylfaen"},
{USCRIPT_ARMENIAN, L"sylfaen"},
{USCRIPT_ETHIOPIC, L"nyala"},
{USCRIPT_CANADIAN_ABORIGINAL, L"euphemia"},
{USCRIPT_CHEROKEE, L"plantagenet cherokee"},
{USCRIPT_YI, L"microsoft yi balti"},
{USCRIPT_SINHALA, L"iskoola pota"},
{USCRIPT_SYRIAC, L"estrangelo edessa"},
{USCRIPT_KHMER, L"daunpenh"},
{USCRIPT_THAANA, L"mv boli"},
{USCRIPT_MONGOLIAN, L"mongolian balti"},
{USCRIPT_MYANMAR, L"padauk"},
};
for (int i = 0; i < sizeof(fontMap) / sizeof(fontMap[0]); ++i)
scriptFontMap[fontMap[i].script] = fontMap[i].family;
Locale locale = Locale::getDefault();
const UChar* localeFamily = 0;
if (locale == Locale::getJapanese())
localeFamily = scriptFontMap[USCRIPT_HIRAGANA];
else if (locale == Locale::getKorean())
localeFamily = scriptFontMap[USCRIPT_HANGUL];
else {
localeFamily = scriptFontMap[USCRIPT_SIMPLIFIED_HAN];
}
if (localeFamily)
scriptFontMap[USCRIPT_HAN] = localeFamily;
}
const int kUndefinedAscent = std::numeric_limits<int>::min();
int getAscent(HFONT hfont)
{
HDC dc = GetDC(0);
HGDIOBJ oldFont = SelectObject(dc, hfont);
TEXTMETRIC tm;
BOOL gotMetrics = GetTextMetrics(dc, &tm);
SelectObject(dc, oldFont);
ReleaseDC(0, dc);
return gotMetrics ? tm.tmAscent : kUndefinedAscent;
}
struct FontData {
FontData()
: hfont(0)
, ascent(kUndefinedAscent)
, scriptCache(0)
{
}
HFONT hfont;
int ascent;
mutable SCRIPT_CACHE scriptCache;
};
typedef HashMap<String, FontData> FontDataCache;
}
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(const UChar* characters,
int length,
FontDescription::GenericFamilyType generic,
UChar32* charChecked,
UScriptCode* scriptChecked)
{
ASSERT(characters && characters[0] && length > 0);
UScriptCode script = USCRIPT_COMMON;
int i = 0;
UChar32 ucs4 = 0;
while (i < length && script == USCRIPT_COMMON || script == USCRIPT_INVALID_CODE) {
U16_NEXT(characters, i, length, ucs4);
UErrorCode err = U_ZERO_ERROR;
script = uscript_getScript(ucs4, &err);
}
if (0xFF00 < ucs4 && ucs4 < 0xFF5F)
script = USCRIPT_HAN;
if (script == USCRIPT_COMMON || script == USCRIPT_INHERITED) {
UBlockCode block = ublock_getCode(ucs4);
switch (block) {
case UBLOCK_BASIC_LATIN:
script = USCRIPT_LATIN;
break;
case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
script = USCRIPT_HAN;
break;
case UBLOCK_HIRAGANA:
case UBLOCK_KATAKANA:
script = USCRIPT_HIRAGANA;
break;
case UBLOCK_ARABIC:
script = USCRIPT_ARABIC;
break;
case UBLOCK_GREEK:
script = USCRIPT_GREEK;
break;
case UBLOCK_DEVANAGARI:
script = USCRIPT_DEVANAGARI;
break;
case UBLOCK_ARMENIAN:
script = USCRIPT_ARMENIAN;
break;
case UBLOCK_GEORGIAN:
script = USCRIPT_GEORGIAN;
break;
case UBLOCK_KANNADA:
script = USCRIPT_KANNADA;
break;
}
}
const UChar* family = getFontFamilyForScript(script, generic);
if (!family) {
int plane = ucs4 >> 16;
switch (plane) {
case 1:
family = L"code2001";
break;
case 2:
family = L"simsun-extb";
break;
default:
family = L"lucida sans unicode";
}
}
if (charChecked)
*charChecked = ucs4;
if (scriptChecked)
*scriptChecked = script;
return family;
}
bool getDerivedFontData(const UChar* family,
int style,
LOGFONT* logfont,
int* ascent,
HFONT* hfont,
SCRIPT_CACHE** scriptCache)
{
ASSERT(logfont);
ASSERT(family);
ASSERT(*family);
static FontDataCache fontDataCache;
String fontKey = String::format("%1d:%d:%ls", style, logfont->lfHeight, family);
FontDataCache::iterator iter = fontDataCache.find(fontKey);
FontData* derived;
if (iter == fontDataCache.end()) {
ASSERT(wcslen(family) < LF_FACESIZE);
wcscpy_s(logfont->lfFaceName, LF_FACESIZE, family);
pair<FontDataCache::iterator, bool> entry = fontDataCache.add(fontKey, FontData());
derived = &entry.first->second;
derived->hfont = CreateFontIndirect(logfont);
derived->ascent = getAscent(derived->hfont);
} else {
derived = &iter->second;
if (kUndefinedAscent == derived->ascent)
derived->ascent = getAscent(derived->hfont);
}
*hfont = derived->hfont;
*ascent = derived->ascent;
*scriptCache = &(derived->scriptCache);
return *ascent != kUndefinedAscent;
}
int getStyleFromLogfont(const LOGFONT* logfont)
{
if (!logfont) {
ASSERT_NOT_REACHED();
return FontStyleNormal;
}
return (logfont->lfItalic ? FontStyleItalic : FontStyleNormal) |
(logfont->lfUnderline ? FontStyleUnderlined : FontStyleNormal) |
(logfont->lfWeight >= 700 ? FontStyleBold : FontStyleNormal);
}
}