/* * Copyright (C) 2006, 2007 Apple Computer, Inc. * Copyright (c) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "FontCache.h" #include "Font.h" #include "FontUtilsChromiumWin.h" #include "HashMap.h" #include "HashSet.h" #include "PlatformBridge.h" #include "SimpleFontData.h" #include #include #include #include #include using std::min; namespace WebCore { // FIXME: consider adding to WebKit String class static bool charactersAreAllASCII(const String& s) { return WTF::charactersAreAllASCII(s.characters(), s.length()); } // When asked for a CJK font with a native name under a non-CJK locale or // asked for a CJK font with a Romanized name under a CJK locale, // |GetTextFace| (after |CreateFont*|) returns a 'bogus' value (e.g. Arial). // This is not consistent with what MSDN says !! // Therefore, before we call |CreateFont*|, we have to map a Romanized name to // the corresponding native name under a CJK locale and vice versa // under a non-CJK locale. // See the corresponding gecko bugs at // https://bugzilla.mozilla.org/show_bug.cgi?id=373952 // https://bugzilla.mozilla.org/show_bug.cgi?id=231426 static bool LookupAltName(const String& name, String& altName) { struct FontCodepage { WCHAR* name; int codePage; }; struct NamePair { WCHAR* name; FontCodepage altNameCodepage; }; const int japaneseCodepage = 932; const int simplifiedChineseCodepage = 936; const int koreanCodepage = 949; const int traditionalChineseCodepage = 950; // FIXME(jungshik) : This list probably covers 99% of cases. // To cover the remaining 1% and cut down the file size, // consider accessing 'NAME' table of a truetype font // using |GetFontData| and caching the mapping. // In the table below, the ASCII keys are all lower-cased for // case-insensitive matching. static const NamePair namePairs[] = { // MS Pゴシック, MS PGothic {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", {L"MS PGothic", japaneseCodepage}}, {L"ms pgothic", {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", japaneseCodepage}}, // MS P明朝, MS PMincho {L"\xFF2D\xFF33 \xFF30\x660E\x671D", {L"MS PMincho", japaneseCodepage}}, {L"ms pmincho", {L"\xFF2D\xFF33 \xFF30\x660E\x671D", japaneseCodepage}}, // MSゴシック, MS Gothic {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", {L"MS Gothic", japaneseCodepage}}, {L"ms gothic", {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", japaneseCodepage}}, // MS 明朝, MS Mincho {L"\xFF2D\xFF33 \x660E\x671D", {L"MS Mincho", japaneseCodepage}}, {L"ms mincho", {L"\xFF2D\xFF33 \x660E\x671D", japaneseCodepage}}, // メイリオ, Meiryo {L"\x30E1\x30A4\x30EA\x30AA", {L"Meiryo", japaneseCodepage}}, {L"meiryo", {L"\x30E1\x30A4\x30EA\x30AA", japaneseCodepage}}, // 바탕, Batang {L"\xBC14\xD0D5", {L"Batang", koreanCodepage}}, {L"batang", {L"\xBC14\xD0D5", koreanCodepage}}, // 바탕체, Batangche {L"\xBC14\xD0D5\xCCB4", {L"Batangche", koreanCodepage}}, {L"batangche", {L"\xBC14\xD0D5\xCCB4", koreanCodepage}}, // 굴림, Gulim {L"\xAD74\xB9BC", {L"Gulim", koreanCodepage}}, {L"gulim", {L"\xAD74\xB9BC", koreanCodepage}}, // 굴림체, Gulimche {L"\xAD74\xB9BC\xCCB4", {L"Gulimche", koreanCodepage}}, {L"gulimche", {L"\xAD74\xB9BC\xCCB4", koreanCodepage}}, // 돋움, Dotum {L"\xB3CB\xC6C0", {L"Dotum", koreanCodepage}}, {L"dotum", {L"\xB3CB\xC6C0", koreanCodepage}}, // 돋움체, Dotumche {L"\xB3CB\xC6C0\xCCB4", {L"Dotumche", koreanCodepage}}, {L"dotumche", {L"\xB3CB\xC6C0\xCCB4", koreanCodepage}}, // 궁서, Gungsuh {L"\xAD81\xC11C", {L"Gungsuh", koreanCodepage}}, {L"gungsuh", {L"\xAD81\xC11C", koreanCodepage}}, // 궁서체, Gungsuhche {L"\xAD81\xC11C\xCCB4", {L"Gungsuhche", koreanCodepage}}, {L"gungsuhche", {L"\xAD81\xC11C\xCCB4", koreanCodepage}}, // 맑은 고딕, Malgun Gothic {L"\xB9D1\xC740 \xACE0\xB515", {L"Malgun Gothic", koreanCodepage}}, {L"malgun gothic", {L"\xB9D1\xC740 \xACE0\xB515", koreanCodepage}}, // 宋体, SimSun {L"\x5B8B\x4F53", {L"SimSun", simplifiedChineseCodepage}}, {L"simsun", {L"\x5B8B\x4F53", simplifiedChineseCodepage}}, // 宋体-ExtB, SimSun-ExtB {L"\x5B8B\x4F53-ExtB", {L"SimSun-ExtB", simplifiedChineseCodepage}}, {L"simsun-extb", {L"\x5B8B\x4F53-extb", simplifiedChineseCodepage}}, // 黑体, SimHei {L"\x9ED1\x4F53", {L"SimHei", simplifiedChineseCodepage}}, {L"simhei", {L"\x9ED1\x4F53", simplifiedChineseCodepage}}, // 新宋体, NSimSun {L"\x65B0\x5B8B\x4F53", {L"NSimSun", simplifiedChineseCodepage}}, {L"nsimsun", {L"\x65B0\x5B8B\x4F53", simplifiedChineseCodepage}}, // 微软雅黑, Microsoft Yahei {L"\x5FAE\x8F6F\x96C5\x9ED1", {L"Microsoft Yahei", simplifiedChineseCodepage}}, {L"microsoft yahei", {L"\x5FAE\x8F6F\x96C5\x9ED1", simplifiedChineseCodepage}}, // 仿宋, FangSong {L"\x4EFF\x5B8B", {L"FangSong", simplifiedChineseCodepage}}, {L"fangsong", {L"\x4EFF\x5B8B", simplifiedChineseCodepage}}, // 楷体, KaiTi {L"\x6977\x4F53", {L"KaiTi", simplifiedChineseCodepage}}, {L"kaiti", {L"\x6977\x4F53", simplifiedChineseCodepage}}, // 仿宋_GB2312, FangSong_GB2312 {L"\x4EFF\x5B8B_GB2312", {L"FangSong_GB2312", simplifiedChineseCodepage}}, {L"fangsong_gb2312", {L"\x4EFF\x5B8B_gb2312", simplifiedChineseCodepage}}, // 楷体_GB2312, KaiTi_GB2312 {L"\x6977\x4F53", {L"KaiTi_GB2312", simplifiedChineseCodepage}}, {L"kaiti_gb2312", {L"\x6977\x4F53_gb2312", simplifiedChineseCodepage}}, // 新細明體, PMingLiu {L"\x65B0\x7D30\x660E\x9AD4", {L"PMingLiu", traditionalChineseCodepage}}, {L"pmingliu", {L"\x65B0\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, // 新細明體-ExtB, PMingLiu-ExtB {L"\x65B0\x7D30\x660E\x9AD4-ExtB", {L"PMingLiu-ExtB", traditionalChineseCodepage}}, {L"pmingliu-extb", {L"\x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCodepage}}, // 細明體, MingLiu {L"\x7D30\x660E\x9AD4", {L"MingLiu", traditionalChineseCodepage}}, {L"mingliu", {L"\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, // 細明體-ExtB, MingLiu-ExtB {L"\x7D30\x660E\x9AD4-ExtB", {L"MingLiu-ExtB", traditionalChineseCodepage}}, {L"mingliu-extb", {L"x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCodepage}}, // 微軟正黑體, Microsoft JhengHei {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", {L"Microsoft JhengHei", traditionalChineseCodepage}}, {L"microsoft jhengHei", {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", traditionalChineseCodepage}}, // 標楷體, DFKai-SB {L"\x6A19\x6977\x9AD4", {L"DFKai-SB", traditionalChineseCodepage}}, {L"dfkai-sb", {L"\x6A19\x6977\x9AD4", traditionalChineseCodepage}}, // WenQuanYi Zen Hei {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", {L"WenQuanYi Zen Hei", traditionalChineseCodepage}}, {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", traditionalChineseCodepage}}, // WenQuanYi Zen Hei {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", {L"WenQuanYi Zen Hei", simplifiedChineseCodepage}}, {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", simplifiedChineseCodepage}}, // AR PL ShanHeiSun Uni, {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", {L"AR PL ShanHeiSun Uni", traditionalChineseCodepage}}, {L"ar pl shanheisun uni", {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", traditionalChineseCodepage}}, // AR PL ShanHeiSun Uni, {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", {L"AR PL ShanHeiSun Uni", simplifiedChineseCodepage}}, {L"ar pl shanheisun uni", {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", simplifiedChineseCodepage}}, // AR PL ZenKai Uni // Traditional Chinese and Simplified Chinese names are // identical. {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", traditionalChineseCodepage}}, {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", traditionalChineseCodepage}}, {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", simplifiedChineseCodepage}}, {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", simplifiedChineseCodepage}}, }; typedef HashMap NameMap; static NameMap* fontNameMap = 0; if (!fontNameMap) { fontNameMap = new NameMap; for (size_t i = 0; i < WTF_ARRAY_LENGTH(namePairs); ++i) fontNameMap->set(String(namePairs[i].name), &(namePairs[i].altNameCodepage)); } bool isAscii = false; String n; // use |lower| only for ASCII names // For non-ASCII names, we don't want to invoke an expensive // and unnecessary |lower|. if (charactersAreAllASCII(name)) { isAscii = true; n = name.lower(); } else n = name; NameMap::iterator iter = fontNameMap->find(n); if (iter == fontNameMap->end()) return false; static int systemCp = ::GetACP(); int fontCp = iter->second->codePage; if ((isAscii && systemCp == fontCp) || (!isAscii && systemCp != fontCp)) { altName = String(iter->second->name); return true; } return false; } static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winfont, String* winName) { int len = min(static_cast(family.length()), LF_FACESIZE - 1); memcpy(winfont->lfFaceName, family.characters(), len * sizeof(WORD)); winfont->lfFaceName[len] = '\0'; HFONT hfont = CreateFontIndirect(winfont); if (!hfont) return 0; HDC dc = GetDC(0); HGDIOBJ oldFont = static_cast(SelectObject(dc, hfont)); WCHAR name[LF_FACESIZE]; unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name); if (resultLength > 0) resultLength--; // ignore the null terminator SelectObject(dc, oldFont); ReleaseDC(0, dc); *winName = String(name, resultLength); return hfont; } // This maps font family names to their repertoires of supported Unicode // characters. Because it's family names rather than font faces we use // as keys, there might be edge cases where one face of a font family // has a different repertoire from another face of the same family. typedef HashMap FontCmapCache; static bool fontContainsCharacter(const FontPlatformData* fontData, const wchar_t* family, UChar32 character) { // FIXME: For non-BMP characters, GetFontUnicodeRanges is of // no use. We have to read directly from the cmap table of a font. // Return true for now. if (character > 0xFFFF) return true; // This cache is just leaked on shutdown. static FontCmapCache* fontCmapCache = 0; if (!fontCmapCache) fontCmapCache = new FontCmapCache; HashMap::iterator it = fontCmapCache->find(family); if (it != fontCmapCache->end()) return it->second->contains(character); HFONT hfont = fontData->hfont(); HDC hdc = GetDC(0); HGDIOBJ oldFont = static_cast(SelectObject(hdc, hfont)); int count = GetFontUnicodeRanges(hdc, 0); if (!count && PlatformBridge::ensureFontLoaded(hfont)) count = GetFontUnicodeRanges(hdc, 0); if (!count) { LOG_ERROR("Unable to get the font unicode range after second attempt"); SelectObject(hdc, oldFont); ReleaseDC(0, hdc); return true; } static Vector glyphsetBuffer; glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); GLYPHSET* glyphset = reinterpret_cast(glyphsetBuffer.data()); // In addition, refering to the OS/2 table and converting the codepage list // to the coverage map might be faster. count = GetFontUnicodeRanges(hdc, glyphset); ASSERT(count > 0); SelectObject(hdc, oldFont); ReleaseDC(0, hdc); // FIXME: consider doing either of the following two: // 1) port back ICU 4.0's faster look-up code for UnicodeSet // 2) port Mozilla's CompressedCharMap or gfxSparseBitset unsigned i = 0; icu::UnicodeSet* cmap = new icu::UnicodeSet; while (i < glyphset->cRanges) { WCHAR start = glyphset->ranges[i].wcLow; cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1); i++; } cmap->freeze(); // We don't lowercase |family| because all of them are under our control // and they're already lowercased. fontCmapCache->set(family, cmap); return cmap->contains(character); } // Tries the given font and save it |outFontFamilyName| if it succeeds. static SimpleFontData* fontDataFromDescriptionAndLogFont(FontCache* fontCache, const FontDescription& fontDescription, const LOGFONT& font, wchar_t* outFontFamilyName) { SimpleFontData* fontData = fontCache->getCachedFontData(fontDescription, font.lfFaceName); if (fontData) memcpy(outFontFamilyName, font.lfFaceName, sizeof(font.lfFaceName)); return fontData; } static LONG toGDIFontWeight(FontWeight fontWeight) { static LONG gdiFontWeights[] = { FW_THIN, // FontWeight100 FW_EXTRALIGHT, // FontWeight200 FW_LIGHT, // FontWeight300 FW_NORMAL, // FontWeight400 FW_MEDIUM, // FontWeight500 FW_SEMIBOLD, // FontWeight600 FW_BOLD, // FontWeight700 FW_EXTRABOLD, // FontWeight800 FW_HEAVY // FontWeight900 }; return gdiFontWeights[fontWeight]; } static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont) { // The size here looks unusual. The negative number is intentional. // Unlike WebKit trunk, we don't multiply the size by 32. That seems to be // some kind of artifact of their CG backend, or something. winfont->lfHeight = -fontDescription.computedPixelSize(); winfont->lfWidth = 0; winfont->lfEscapement = 0; winfont->lfOrientation = 0; winfont->lfUnderline = false; winfont->lfStrikeOut = false; winfont->lfCharSet = DEFAULT_CHARSET; winfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; winfont->lfQuality = PlatformBridge::layoutTestMode() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY; // Honor user's desktop settings. winfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; winfont->lfItalic = fontDescription.italic(); winfont->lfWeight = toGDIFontWeight(fontDescription.weight()); } struct TraitsInFamilyProcData { TraitsInFamilyProcData(const AtomicString& familyName) : m_familyName(familyName) { } const AtomicString& m_familyName; HashSet m_traitsMasks; }; static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) { TraitsInFamilyProcData* procData = reinterpret_cast(lParam); unsigned traitsMask = 0; traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; traitsMask |= FontVariantNormalMask; LONG weight = logFont->lfWeight; traitsMask |= weight == FW_THIN ? FontWeight100Mask : weight == FW_EXTRALIGHT ? FontWeight200Mask : weight == FW_LIGHT ? FontWeight300Mask : weight == FW_NORMAL ? FontWeight400Mask : weight == FW_MEDIUM ? FontWeight500Mask : weight == FW_SEMIBOLD ? FontWeight600Mask : weight == FW_BOLD ? FontWeight700Mask : weight == FW_EXTRABOLD ? FontWeight800Mask : FontWeight900Mask; procData->m_traitsMasks.add(traitsMask); return 1; } struct GetLastResortFallbackFontProcData { GetLastResortFallbackFontProcData(FontCache* fontCache, const FontDescription* fontDescription, wchar_t* fontName) : m_fontCache(fontCache) , m_fontDescription(fontDescription) , m_fontName(fontName) , m_fontData(0) { } FontCache* m_fontCache; const FontDescription* m_fontDescription; wchar_t* m_fontName; SimpleFontData* m_fontData; }; static int CALLBACK getLastResortFallbackFontProc(const LOGFONT* logFont, const TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) { GetLastResortFallbackFontProcData* procData = reinterpret_cast(lParam); procData->m_fontData = fontDataFromDescriptionAndLogFont(procData->m_fontCache, *procData->m_fontDescription, *logFont, procData->m_fontName); return !procData->m_fontData; } void FontCache::platformInit() { // Not needed on Windows. } // Given the desired base font, this will create a SimpleFontData for a specific // font that can be used to render the given range of characters. const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) { // FIXME: Consider passing fontDescription.dominantScript() // to GetFallbackFamily here. FontDescription fontDescription = font.fontDescription(); UChar32 c; UScriptCode script; const wchar_t* family = getFallbackFamily(characters, length, fontDescription.genericFamily(), &c, &script); FontPlatformData* data = 0; if (family) data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)), false); // Last resort font list : PanUnicode. CJK fonts have a pretty // large repertoire. Eventually, we need to scan all the fonts // on the system to have a Firefox-like coverage. // Make sure that all of them are lowercased. const static wchar_t* const cjkFonts[] = { L"arial unicode ms", L"ms pgothic", L"simsun", L"gulim", L"pmingliu", L"wenquanyi zen hei", // partial CJK Ext. A coverage but more // widely known to Chinese users. L"ar pl shanheisun uni", L"ar pl zenkai uni", L"han nom a", // Complete CJK Ext. A coverage L"code2000", // Complete CJK Ext. A coverage // CJK Ext. B fonts are not listed here because it's of no use // with our current non-BMP character handling because we use // Uniscribe for it and that code path does not go through here. }; const static wchar_t* const commonFonts[] = { L"tahoma", L"arial unicode ms", L"lucida sans unicode", L"microsoft sans serif", L"palatino linotype", // Six fonts below (and code2000 at the end) are not from MS, but // once installed, cover a very wide range of characters. L"dejavu serif", L"dejavu sasns", L"freeserif", L"freesans", L"gentium", L"gentiumalt", L"ms pgothic", L"simsun", L"gulim", L"pmingliu", L"code2000", }; const wchar_t* const* panUniFonts = 0; int numFonts = 0; if (script == USCRIPT_HAN) { panUniFonts = cjkFonts; numFonts = WTF_ARRAY_LENGTH(cjkFonts); } else { panUniFonts = commonFonts; numFonts = WTF_ARRAY_LENGTH(commonFonts); } // Font returned from GetFallbackFamily may not cover |characters| // because it's based on script to font mapping. This problem is // critical enough for non-Latin scripts (especially Han) to // warrant an additional (real coverage) check with fontCotainsCharacter. int i; for (i = 0; (!data || !fontContainsCharacter(data, family, c)) && i < numFonts; ++i) { family = panUniFonts[i]; data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family))); } // When i-th font (0-base) in |panUniFonts| contains a character and // we get out of the loop, |i| will be |i + 1|. That is, if only the // last font in the array covers the character, |i| will be numFonts. // So, we have to use '<=" rather than '<' to see if we found a font // covering the character. if (i <= numFonts) return getCachedFontData(data); return 0; } SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font) { return 0; } SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& description) { FontDescription::GenericFamilyType generic = description.genericFamily(); // FIXME: Would be even better to somehow get the user's default font here. // For now we'll pick the default that the user would get without changing // any prefs. static AtomicString timesStr("Times New Roman"); static AtomicString courierStr("Courier New"); static AtomicString arialStr("Arial"); AtomicString& fontStr = timesStr; if (generic == FontDescription::SansSerifFamily) fontStr = arialStr; else if (generic == FontDescription::MonospaceFamily) fontStr = courierStr; SimpleFontData* simpleFont = getCachedFontData(description, fontStr); if (simpleFont) return simpleFont; // Fall back to system fonts as Win Safari does because this function must // return a valid font. Once we find a valid system font, we save its name // to a static variable and use it to prevent trying system fonts again. static wchar_t fallbackFontName[LF_FACESIZE] = {0}; if (fallbackFontName[0]) return getCachedFontData(description, fallbackFontName); // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available. if (HFONT defaultGUIFont = static_cast(GetStockObject(DEFAULT_GUI_FONT))) { LOGFONT defaultGUILogFont; GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont); if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, defaultGUILogFont, fallbackFontName)) return simpleFont; } // Fall back to Non-client metrics fonts. NONCLIENTMETRICS nonClientMetrics = {0}; nonClientMetrics.cbSize = sizeof(nonClientMetrics); if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) { if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfMessageFont, fallbackFontName)) return simpleFont; if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfMenuFont, fallbackFontName)) return simpleFont; if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfStatusFont, fallbackFontName)) return simpleFont; if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfCaptionFont, fallbackFontName)) return simpleFont; if (simpleFont = fontDataFromDescriptionAndLogFont(this, description, nonClientMetrics.lfSmCaptionFont, fallbackFontName)) return simpleFont; } // Fall back to all the fonts installed in this PC. When a font has a // localized name according to the system locale as well as an English name, // both GetTextFace() and EnumFontFamilies() return the localized name. So, // FontCache::createFontPlatformData() does not filter out the fonts // returned by this EnumFontFamilies() call. HDC dc = GetDC(0); if (dc) { GetLastResortFallbackFontProcData procData(this, &description, fallbackFontName); EnumFontFamilies(dc, 0, getLastResortFallbackFontProc, reinterpret_cast(&procData)); ReleaseDC(0, dc); if (procData.m_fontData) return procData.m_fontData; } ASSERT_NOT_REACHED(); return 0; } void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector& traitsMasks) { HDC hdc = GetDC(0); LOGFONT logFont; logFont.lfCharSet = DEFAULT_CHARSET; unsigned familyLength = min(familyName.length(), static_cast(LF_FACESIZE - 1)); memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar)); logFont.lfFaceName[familyLength] = 0; logFont.lfPitchAndFamily = 0; TraitsInFamilyProcData procData(familyName); EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast(&procData), 0); copyToVector(procData.m_traitsMasks, traitsMasks); ReleaseDC(0, hdc); } FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) { LOGFONT winfont = {0}; FillLogFont(fontDescription, &winfont); // Windows will always give us a valid pointer here, even if the face name // is non-existent. We have to double-check and see if the family name was // really used. String winName; HFONT hfont = createFontIndirectAndGetWinName(family, &winfont, &winName); if (!hfont) return 0; // FIXME: Do we need to use predefined fonts "guaranteed" to exist // when we're running in layout-test mode? if (!equalIgnoringCase(family, winName)) { // For CJK fonts with both English and native names, // GetTextFace returns a native name under the font's "locale" // and an English name under other locales regardless of // lfFaceName field of LOGFONT. As a result, we need to check // if a font has an alternate name. If there is, we need to // compare it with what's requested in the first place. String altName; if (!LookupAltName(family, altName) || !equalIgnoringCase(altName, winName)) { DeleteObject(hfont); return 0; } } return new FontPlatformData(hfont, fontDescription.computedPixelSize()); } }