| /* |
| * 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 "ChromiumBridge.h" |
| #include "Font.h" |
| #include "FontUtilsChromiumWin.h" |
| #include "HashMap.h" |
| #include "HashSet.h" |
| #include "SimpleFontData.h" |
| #include <unicode/uniset.h> |
| #include <wtf/text/StringHash.h> |
| |
| #include <windows.h> |
| #include <objidl.h> |
| #include <mlang.h> |
| |
| 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<String, const FontCodepage*> 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<int>(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<HFONT>(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<const wchar_t*, icu::UnicodeSet*> 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<const wchar_t*, icu::UnicodeSet*>::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<HFONT>(SelectObject(hdc, hfont)); |
| int count = GetFontUnicodeRanges(hdc, 0); |
| if (count == 0 && ChromiumBridge::ensureFontLoaded(hfont)) |
| count = GetFontUnicodeRanges(hdc, 0); |
| if (count == 0) { |
| LOG_ERROR("Unable to get the font unicode range after second attempt"); |
| SelectObject(hdc, oldFont); |
| ReleaseDC(0, hdc); |
| return true; |
| } |
| |
| static Vector<char, 512> glyphsetBuffer; |
| glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); |
| GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(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 = ChromiumBridge::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<unsigned> m_traitsMasks; |
| }; |
| |
| static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) |
| { |
| TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(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; |
| } |
| |
| 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<HFONT>(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; |
| } |
| |
| ASSERT_NOT_REACHED(); |
| return 0; |
| } |
| |
| void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) |
| { |
| HDC hdc = GetDC(0); |
| |
| LOGFONT logFont; |
| logFont.lfCharSet = DEFAULT_CHARSET; |
| unsigned familyLength = min(familyName.length(), static_cast<unsigned>(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<LPARAM>(&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()); |
| } |
| |
| } |