| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2006, 2007 Apple Computer, Inc. | |
| 3 * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. All rights reserved. | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions are | |
| 7 * met: | |
| 8 * | |
| 9 * * Redistributions of source code must retain the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer. | |
| 11 * * Redistributions in binary form must reproduce the above | |
| 12 * copyright notice, this list of conditions and the following disclaimer | |
| 13 * in the documentation and/or other materials provided with the | |
| 14 * distribution. | |
| 15 * * Neither the name of Google Inc. nor the names of its | |
| 16 * contributors may be used to endorse or promote products derived from | |
| 17 * this software without specific prior written permission. | |
| 18 * | |
| 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 30 */ | |
| 31 | |
| 32 #include "config.h" | |
| 33 #include "core/platform/graphics/FontCache.h" | |
| 34 | |
| 35 #include <unicode/uniset.h> | |
| 36 #include "core/platform/graphics/Font.h" | |
| 37 #include "core/platform/graphics/SimpleFontData.h" | |
| 38 #include "core/platform/graphics/chromium/FontPlatformDataChromiumWin.h" | |
| 39 #include "platform/LayoutTestSupport.h" | |
| 40 #include "platform/fonts/FontFallbackWin.h" | |
| 41 #include "platform/win/HWndDC.h" | |
| 42 #include "wtf/HashMap.h" | |
| 43 #include "wtf/HashSet.h" | |
| 44 #include "wtf/text/StringHash.h" | |
| 45 | |
| 46 #include <windows.h> | |
| 47 #include <mlang.h> | |
| 48 #include <objidl.h> | |
| 49 | |
| 50 using std::min; | |
| 51 | |
| 52 namespace WebCore | |
| 53 { | |
| 54 | |
| 55 // When asked for a CJK font with a native name under a non-CJK locale or | |
| 56 // asked for a CJK font with a Romanized name under a CJK locale, | |
| 57 // |GetTextFace| (after |CreateFont*|) returns a 'bogus' value (e.g. Arial). | |
| 58 // This is not consistent with what MSDN says !! | |
| 59 // Therefore, before we call |CreateFont*|, we have to map a Romanized name to | |
| 60 // the corresponding native name under a CJK locale and vice versa | |
| 61 // under a non-CJK locale. | |
| 62 // See the corresponding gecko bugs at | |
| 63 // https://bugzilla.mozilla.org/show_bug.cgi?id=373952 | |
| 64 // https://bugzilla.mozilla.org/show_bug.cgi?id=231426 | |
| 65 static bool LookupAltName(const String& name, String& altName) | |
| 66 { | |
| 67 struct FontCodepage { | |
| 68 const WCHAR* name; | |
| 69 int codePage; | |
| 70 }; | |
| 71 | |
| 72 struct NamePair { | |
| 73 const WCHAR* name; | |
| 74 FontCodepage altNameCodepage; | |
| 75 }; | |
| 76 | |
| 77 const int japaneseCodepage = 932; | |
| 78 const int simplifiedChineseCodepage = 936; | |
| 79 const int koreanCodepage = 949; | |
| 80 const int traditionalChineseCodepage = 950; | |
| 81 | |
| 82 // FIXME(jungshik) : This list probably covers 99% of cases. | |
| 83 // To cover the remaining 1% and cut down the file size, | |
| 84 // consider accessing 'NAME' table of a truetype font | |
| 85 // using |GetFontData| and caching the mapping. | |
| 86 // In the table below, the ASCII keys are all lower-cased for | |
| 87 // case-insensitive matching. | |
| 88 static const NamePair namePairs[] = { | |
| 89 // MS Pゴシック, MS PGothic | |
| 90 {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", {L"MS PGothic", japanes
eCodepage}}, | |
| 91 {L"ms pgothic", {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", japanes
eCodepage}}, | |
| 92 // MS P明朝, MS PMincho | |
| 93 {L"\xFF2D\xFF33 \xFF30\x660E\x671D", {L"MS PMincho", japaneseCodepage}}, | |
| 94 {L"ms pmincho", {L"\xFF2D\xFF33 \xFF30\x660E\x671D", japaneseCodepage}}, | |
| 95 // MSゴシック, MS Gothic | |
| 96 {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", {L"MS Gothic", japaneseCodepa
ge}}, | |
| 97 {L"ms gothic", {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", japaneseCodepa
ge}}, | |
| 98 // MS 明朝, MS Mincho | |
| 99 {L"\xFF2D\xFF33 \x660E\x671D", {L"MS Mincho", japaneseCodepage}}, | |
| 100 {L"ms mincho", {L"\xFF2D\xFF33 \x660E\x671D", japaneseCodepage}}, | |
| 101 // メイリオ, Meiryo | |
| 102 {L"\x30E1\x30A4\x30EA\x30AA", {L"Meiryo", japaneseCodepage}}, | |
| 103 {L"meiryo", {L"\x30E1\x30A4\x30EA\x30AA", japaneseCodepage}}, | |
| 104 // 바탕, Batang | |
| 105 {L"\xBC14\xD0D5", {L"Batang", koreanCodepage}}, | |
| 106 {L"batang", {L"\xBC14\xD0D5", koreanCodepage}}, | |
| 107 // 바탕체, Batangche | |
| 108 {L"\xBC14\xD0D5\xCCB4", {L"Batangche", koreanCodepage}}, | |
| 109 {L"batangche", {L"\xBC14\xD0D5\xCCB4", koreanCodepage}}, | |
| 110 // 굴림, Gulim | |
| 111 {L"\xAD74\xB9BC", {L"Gulim", koreanCodepage}}, | |
| 112 {L"gulim", {L"\xAD74\xB9BC", koreanCodepage}}, | |
| 113 // 굴림체, Gulimche | |
| 114 {L"\xAD74\xB9BC\xCCB4", {L"Gulimche", koreanCodepage}}, | |
| 115 {L"gulimche", {L"\xAD74\xB9BC\xCCB4", koreanCodepage}}, | |
| 116 // 돋움, Dotum | |
| 117 {L"\xB3CB\xC6C0", {L"Dotum", koreanCodepage}}, | |
| 118 {L"dotum", {L"\xB3CB\xC6C0", koreanCodepage}}, | |
| 119 // 돋움체, Dotumche | |
| 120 {L"\xB3CB\xC6C0\xCCB4", {L"Dotumche", koreanCodepage}}, | |
| 121 {L"dotumche", {L"\xB3CB\xC6C0\xCCB4", koreanCodepage}}, | |
| 122 // 궁서, Gungsuh | |
| 123 {L"\xAD81\xC11C", {L"Gungsuh", koreanCodepage}}, | |
| 124 {L"gungsuh", {L"\xAD81\xC11C", koreanCodepage}}, | |
| 125 // 궁서체, Gungsuhche | |
| 126 {L"\xAD81\xC11C\xCCB4", {L"Gungsuhche", koreanCodepage}}, | |
| 127 {L"gungsuhche", {L"\xAD81\xC11C\xCCB4", koreanCodepage}}, | |
| 128 // 맑은 고딕, Malgun Gothic | |
| 129 {L"\xB9D1\xC740 \xACE0\xB515", {L"Malgun Gothic", koreanCodepage}}, | |
| 130 {L"malgun gothic", {L"\xB9D1\xC740 \xACE0\xB515", koreanCodepage}}, | |
| 131 // 宋体, SimSun | |
| 132 {L"\x5B8B\x4F53", {L"SimSun", simplifiedChineseCodepage}}, | |
| 133 {L"simsun", {L"\x5B8B\x4F53", simplifiedChineseCodepage}}, | |
| 134 // 宋体-ExtB, SimSun-ExtB | |
| 135 {L"\x5B8B\x4F53-ExtB", {L"SimSun-ExtB", simplifiedChineseCodepage}}, | |
| 136 {L"simsun-extb", {L"\x5B8B\x4F53-extb", simplifiedChineseCodepage}}, | |
| 137 // 黑体, SimHei | |
| 138 {L"\x9ED1\x4F53", {L"SimHei", simplifiedChineseCodepage}}, | |
| 139 {L"simhei", {L"\x9ED1\x4F53", simplifiedChineseCodepage}}, | |
| 140 // 新宋体, NSimSun | |
| 141 {L"\x65B0\x5B8B\x4F53", {L"NSimSun", simplifiedChineseCodepage}}, | |
| 142 {L"nsimsun", {L"\x65B0\x5B8B\x4F53", simplifiedChineseCodepage}}, | |
| 143 // 微软雅黑, Microsoft Yahei | |
| 144 {L"\x5FAE\x8F6F\x96C5\x9ED1", {L"Microsoft Yahei", simplifiedChineseCode
page}}, | |
| 145 {L"microsoft yahei", {L"\x5FAE\x8F6F\x96C5\x9ED1", simplifiedChineseCode
page}}, | |
| 146 // 仿宋, FangSong | |
| 147 {L"\x4EFF\x5B8B", {L"FangSong", simplifiedChineseCodepage}}, | |
| 148 {L"fangsong", {L"\x4EFF\x5B8B", simplifiedChineseCodepage}}, | |
| 149 // 楷体, KaiTi | |
| 150 {L"\x6977\x4F53", {L"KaiTi", simplifiedChineseCodepage}}, | |
| 151 {L"kaiti", {L"\x6977\x4F53", simplifiedChineseCodepage}}, | |
| 152 // 仿宋_GB2312, FangSong_GB2312 | |
| 153 {L"\x4EFF\x5B8B_GB2312", {L"FangSong_GB2312", simplifiedChineseCodepage
}}, | |
| 154 {L"fangsong_gb2312", {L"\x4EFF\x5B8B_gb2312", simplifiedChineseCodepage}
}, | |
| 155 // 楷体_GB2312, KaiTi_GB2312 | |
| 156 {L"\x6977\x4F53", {L"KaiTi_GB2312", simplifiedChineseCodepage}}, | |
| 157 {L"kaiti_gb2312", {L"\x6977\x4F53_gb2312", simplifiedChineseCodepage}}, | |
| 158 // 新細明體, PMingLiu | |
| 159 {L"\x65B0\x7D30\x660E\x9AD4", {L"PMingLiu", traditionalChineseCodepage}}
, | |
| 160 {L"pmingliu", {L"\x65B0\x7D30\x660E\x9AD4", traditionalChineseCodepage}}
, | |
| 161 // 新細明體-ExtB, PMingLiu-ExtB | |
| 162 {L"\x65B0\x7D30\x660E\x9AD4-ExtB", {L"PMingLiu-ExtB", traditionalChinese
Codepage}}, | |
| 163 {L"pmingliu-extb", {L"\x65B0\x7D30\x660E\x9AD4-extb", traditionalChinese
Codepage}}, | |
| 164 // 細明體, MingLiu | |
| 165 {L"\x7D30\x660E\x9AD4", {L"MingLiu", traditionalChineseCodepage}}, | |
| 166 {L"mingliu", {L"\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, | |
| 167 // 細明體-ExtB, MingLiu-ExtB | |
| 168 {L"\x7D30\x660E\x9AD4-ExtB", {L"MingLiu-ExtB", traditionalChineseCodepag
e}}, | |
| 169 {L"mingliu-extb", {L"x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCo
depage}}, | |
| 170 // 微軟正黑體, Microsoft JhengHei | |
| 171 {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", {L"Microsoft JhengHei", traditionalC
hineseCodepage}}, | |
| 172 {L"microsoft jhengHei", {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", traditionalC
hineseCodepage}}, | |
| 173 // 標楷體, DFKai-SB | |
| 174 {L"\x6A19\x6977\x9AD4", {L"DFKai-SB", traditionalChineseCodepage}}, | |
| 175 {L"dfkai-sb", {L"\x6A19\x6977\x9AD4", traditionalChineseCodepage}}, | |
| 176 // WenQuanYi Zen Hei | |
| 177 {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", {L"WenQuanYi Zen Hei", traditionalCh
ineseCodepage}}, | |
| 178 {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", traditionalCh
ineseCodepage}}, | |
| 179 // WenQuanYi Zen Hei | |
| 180 {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", {L"WenQuanYi Zen Hei", simplifiedChi
neseCodepage}}, | |
| 181 {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", simplifiedChi
neseCodepage}}, | |
| 182 // AR PL ShanHeiSun Uni, | |
| 183 {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", | |
| 184 {L"AR PL ShanHeiSun Uni", traditionalChineseCodepage}}, | |
| 185 {L"ar pl shanheisun uni", | |
| 186 {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069",
traditionalChineseCodepage}}, | |
| 187 // AR PL ShanHeiSun Uni, | |
| 188 {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", | |
| 189 {L"AR PL ShanHeiSun Uni", simplifiedChineseCodepage}}, | |
| 190 {L"ar pl shanheisun uni", | |
| 191 {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069",
simplifiedChineseCodepage}}, | |
| 192 // AR PL ZenKai Uni | |
| 193 // Traditional Chinese and Simplified Chinese names are | |
| 194 // identical. | |
| 195 {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Un
i", traditionalChineseCodepage}}, | |
| 196 {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x006
9", traditionalChineseCodepage}}, | |
| 197 {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Un
i", simplifiedChineseCodepage}}, | |
| 198 {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x006
9", simplifiedChineseCodepage}}, | |
| 199 }; | |
| 200 | |
| 201 typedef HashMap<String, const FontCodepage*> NameMap; | |
| 202 static NameMap* fontNameMap = 0; | |
| 203 | |
| 204 if (!fontNameMap) { | |
| 205 fontNameMap = new NameMap; | |
| 206 for (size_t i = 0; i < WTF_ARRAY_LENGTH(namePairs); ++i) | |
| 207 fontNameMap->set(String(namePairs[i].name), &(namePairs[i].altNameCo
depage)); | |
| 208 } | |
| 209 | |
| 210 bool isAscii = false; | |
| 211 String n; | |
| 212 // use |lower| only for ASCII names | |
| 213 // For non-ASCII names, we don't want to invoke an expensive | |
| 214 // and unnecessary |lower|. | |
| 215 if (name.containsOnlyASCII()) { | |
| 216 isAscii = true; | |
| 217 n = name.lower(); | |
| 218 } else | |
| 219 n = name; | |
| 220 | |
| 221 NameMap::iterator iter = fontNameMap->find(n); | |
| 222 if (iter == fontNameMap->end()) | |
| 223 return false; | |
| 224 | |
| 225 static int systemCp = ::GetACP(); | |
| 226 int fontCp = iter->value->codePage; | |
| 227 | |
| 228 if ((isAscii && systemCp == fontCp) || (!isAscii && systemCp != fontCp)) { | |
| 229 altName = String(iter->value->name); | |
| 230 return true; | |
| 231 } | |
| 232 | |
| 233 return false; | |
| 234 } | |
| 235 | |
| 236 static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winf
ont, String* winName) | |
| 237 { | |
| 238 unsigned len = family.copyTo(winfont->lfFaceName, 0, LF_FACESIZE - 1); | |
| 239 winfont->lfFaceName[len] = '\0'; | |
| 240 | |
| 241 HFONT hfont = CreateFontIndirect(winfont); | |
| 242 if (!hfont) | |
| 243 return 0; | |
| 244 | |
| 245 HWndDC dc(0); | |
| 246 HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont)); | |
| 247 WCHAR name[LF_FACESIZE]; | |
| 248 unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name); | |
| 249 if (resultLength > 0) | |
| 250 resultLength--; // ignore the null terminator | |
| 251 | |
| 252 SelectObject(dc, oldFont); | |
| 253 *winName = String(name, resultLength); | |
| 254 return hfont; | |
| 255 } | |
| 256 | |
| 257 // This maps font family names to their repertoires of supported Unicode | |
| 258 // characters. Because it's family names rather than font faces we use | |
| 259 // as keys, there might be edge cases where one face of a font family | |
| 260 // has a different repertoire from another face of the same family. | |
| 261 typedef HashMap<const wchar_t*, icu::UnicodeSet*> FontCmapCache; | |
| 262 | |
| 263 static bool fontContainsCharacter(const FontPlatformData* fontData, | |
| 264 const wchar_t* family, UChar32 character) | |
| 265 { | |
| 266 // FIXME: For non-BMP characters, GetFontUnicodeRanges is of | |
| 267 // no use. We have to read directly from the cmap table of a font. | |
| 268 // Return true for now. | |
| 269 if (character > 0xFFFF) | |
| 270 return true; | |
| 271 | |
| 272 // This cache is just leaked on shutdown. | |
| 273 static FontCmapCache* fontCmapCache = 0; | |
| 274 if (!fontCmapCache) | |
| 275 fontCmapCache = new FontCmapCache; | |
| 276 | |
| 277 HashMap<const wchar_t*, icu::UnicodeSet*>::iterator it = fontCmapCache->find
(family); | |
| 278 if (it != fontCmapCache->end()) | |
| 279 return it->value->contains(character); | |
| 280 | |
| 281 HFONT hfont = fontData->hfont(); | |
| 282 HWndDC hdc(0); | |
| 283 HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(hdc, hfont)); | |
| 284 int count = GetFontUnicodeRanges(hdc, 0); | |
| 285 if (!count && FontPlatformData::ensureFontLoaded(hfont)) | |
| 286 count = GetFontUnicodeRanges(hdc, 0); | |
| 287 if (!count) { | |
| 288 LOG_ERROR("Unable to get the font unicode range after second attempt"); | |
| 289 SelectObject(hdc, oldFont); | |
| 290 return true; | |
| 291 } | |
| 292 | |
| 293 static Vector<char, 512>* gGlyphsetBuffer = 0; | |
| 294 if (!gGlyphsetBuffer) | |
| 295 gGlyphsetBuffer = new Vector<char, 512>(); | |
| 296 gGlyphsetBuffer->resize(GetFontUnicodeRanges(hdc, 0)); | |
| 297 GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(gGlyphsetBuffer->data()); | |
| 298 // In addition, refering to the OS/2 table and converting the codepage list | |
| 299 // to the coverage map might be faster. | |
| 300 count = GetFontUnicodeRanges(hdc, glyphset); | |
| 301 ASSERT(count > 0); | |
| 302 SelectObject(hdc, oldFont); | |
| 303 | |
| 304 // FIXME: consider doing either of the following two: | |
| 305 // 1) port back ICU 4.0's faster look-up code for UnicodeSet | |
| 306 // 2) port Mozilla's CompressedCharMap or gfxSparseBitset | |
| 307 unsigned i = 0; | |
| 308 icu::UnicodeSet* cmap = new icu::UnicodeSet; | |
| 309 while (i < glyphset->cRanges) { | |
| 310 WCHAR start = glyphset->ranges[i].wcLow; | |
| 311 cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1); | |
| 312 i++; | |
| 313 } | |
| 314 cmap->freeze(); | |
| 315 // We don't lowercase |family| because all of them are under our control | |
| 316 // and they're already lowercased. | |
| 317 fontCmapCache->set(family, cmap); | |
| 318 return cmap->contains(character); | |
| 319 } | |
| 320 | |
| 321 // Tries the given font and save it |outFontFamilyName| if it succeeds. | |
| 322 PassRefPtr<SimpleFontData> FontCache::fontDataFromDescriptionAndLogFont(const Fo
ntDescription& fontDescription, ShouldRetain shouldRetain, const LOGFONT& font,
wchar_t* outFontFamilyName) | |
| 323 { | |
| 324 RefPtr<SimpleFontData> fontData = getFontResourceData(fontDescription, font.
lfFaceName, false, shouldRetain); | |
| 325 if (fontData) | |
| 326 memcpy(outFontFamilyName, font.lfFaceName, sizeof(font.lfFaceName)); | |
| 327 return fontData.release(); | |
| 328 } | |
| 329 | |
| 330 static LONG toGDIFontWeight(FontWeight fontWeight) | |
| 331 { | |
| 332 static LONG gdiFontWeights[] = { | |
| 333 FW_THIN, // FontWeight100 | |
| 334 FW_EXTRALIGHT, // FontWeight200 | |
| 335 FW_LIGHT, // FontWeight300 | |
| 336 FW_NORMAL, // FontWeight400 | |
| 337 FW_MEDIUM, // FontWeight500 | |
| 338 FW_SEMIBOLD, // FontWeight600 | |
| 339 FW_BOLD, // FontWeight700 | |
| 340 FW_EXTRABOLD, // FontWeight800 | |
| 341 FW_HEAVY // FontWeight900 | |
| 342 }; | |
| 343 return gdiFontWeights[fontWeight]; | |
| 344 } | |
| 345 | |
| 346 static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont
) | |
| 347 { | |
| 348 // The size here looks unusual. The negative number is intentional. | |
| 349 // Unlike WebKit trunk, we don't multiply the size by 32. That seems to be | |
| 350 // some kind of artifact of their CG backend, or something. | |
| 351 winfont->lfHeight = -fontDescription.computedPixelSize(); | |
| 352 winfont->lfWidth = 0; | |
| 353 winfont->lfEscapement = 0; | |
| 354 winfont->lfOrientation = 0; | |
| 355 winfont->lfUnderline = false; | |
| 356 winfont->lfStrikeOut = false; | |
| 357 winfont->lfCharSet = DEFAULT_CHARSET; | |
| 358 winfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; | |
| 359 winfont->lfQuality = isRunningLayoutTest() ? NONANTIALIASED_QUALITY : DEFAUL
T_QUALITY; // Honor user's desktop settings. | |
| 360 winfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; | |
| 361 winfont->lfItalic = fontDescription.italic(); | |
| 362 winfont->lfWeight = toGDIFontWeight(fontDescription.weight()); | |
| 363 } | |
| 364 | |
| 365 struct TraitsInFamilyProcData { | |
| 366 TraitsInFamilyProcData(const AtomicString& familyName) | |
| 367 : m_familyName(familyName) | |
| 368 { | |
| 369 } | |
| 370 | |
| 371 const AtomicString& m_familyName; | |
| 372 HashSet<unsigned> m_traitsMasks; | |
| 373 }; | |
| 374 | |
| 375 static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMET
RIC* metrics, DWORD fontType, LPARAM lParam) | |
| 376 { | |
| 377 TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>
(lParam); | |
| 378 | |
| 379 unsigned traitsMask = 0; | |
| 380 traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; | |
| 381 traitsMask |= FontVariantNormalMask; | |
| 382 LONG weight = logFont->lfWeight; | |
| 383 traitsMask |= weight == FW_THIN ? FontWeight100Mask : | |
| 384 weight == FW_EXTRALIGHT ? FontWeight200Mask : | |
| 385 weight == FW_LIGHT ? FontWeight300Mask : | |
| 386 weight == FW_NORMAL ? FontWeight400Mask : | |
| 387 weight == FW_MEDIUM ? FontWeight500Mask : | |
| 388 weight == FW_SEMIBOLD ? FontWeight600Mask : | |
| 389 weight == FW_BOLD ? FontWeight700Mask : | |
| 390 weight == FW_EXTRABOLD ? FontWeight800Mask : | |
| 391 FontWeight900Mask; | |
| 392 procData->m_traitsMasks.add(traitsMask); | |
| 393 return 1; | |
| 394 } | |
| 395 | |
| 396 struct GetLastResortFallbackFontProcData { | |
| 397 GetLastResortFallbackFontProcData(FontCache* fontCache, const FontDescriptio
n* fontDescription, FontCache::ShouldRetain shouldRetain, wchar_t* fontName) | |
| 398 : m_fontCache(fontCache) | |
| 399 , m_fontDescription(fontDescription) | |
| 400 , m_shouldRetain(shouldRetain) | |
| 401 , m_fontName(fontName) | |
| 402 , m_fontData(0) | |
| 403 { | |
| 404 } | |
| 405 | |
| 406 FontCache* m_fontCache; | |
| 407 const FontDescription* m_fontDescription; | |
| 408 FontCache::ShouldRetain m_shouldRetain; | |
| 409 wchar_t* m_fontName; | |
| 410 RefPtr<SimpleFontData> m_fontData; | |
| 411 }; | |
| 412 | |
| 413 static int CALLBACK getLastResortFallbackFontProc(const LOGFONT* logFont, const
TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) | |
| 414 { | |
| 415 GetLastResortFallbackFontProcData* procData = reinterpret_cast<GetLastResort
FallbackFontProcData*>(lParam); | |
| 416 procData->m_fontData = procData->m_fontCache->fontDataFromDescriptionAndLogF
ont(*procData->m_fontDescription, procData->m_shouldRetain, *logFont, procData->
m_fontName); | |
| 417 return !procData->m_fontData; | |
| 418 } | |
| 419 | |
| 420 void FontCache::platformInit() | |
| 421 { | |
| 422 // Not needed on Windows. | |
| 423 } | |
| 424 | |
| 425 // Given the desired base font, this will create a SimpleFontData for a specific | |
| 426 // font that can be used to render the given range of characters. | |
| 427 PassRefPtr<SimpleFontData> FontCache::getFontDataForCharacter(const Font& font,
UChar32 inputC) | |
| 428 { | |
| 429 // FIXME: We should fix getFallbackFamily to take a UChar32 | |
| 430 // and remove this split-to-UChar16 code. | |
| 431 UChar codeUnits[2]; | |
| 432 int codeUnitsLength; | |
| 433 if (inputC <= 0xFFFF) { | |
| 434 codeUnits[0] = inputC; | |
| 435 codeUnitsLength = 1; | |
| 436 } else { | |
| 437 codeUnits[0] = U16_LEAD(inputC); | |
| 438 codeUnits[1] = U16_TRAIL(inputC); | |
| 439 codeUnitsLength = 2; | |
| 440 } | |
| 441 | |
| 442 // FIXME: Consider passing fontDescription.dominantScript() | |
| 443 // to GetFallbackFamily here. | |
| 444 FontDescription fontDescription = font.fontDescription(); | |
| 445 UChar32 c; | |
| 446 UScriptCode script; | |
| 447 const wchar_t* family = getFallbackFamily(codeUnits, codeUnitsLength, fontDe
scription.genericFamily(), &c, &script); | |
| 448 FontPlatformData* data = 0; | |
| 449 if (family) | |
| 450 data = getFontResourcePlatformData(font.fontDescription(), AtomicString
(family, wcslen(family)), false); | |
| 451 | |
| 452 // Last resort font list : PanUnicode. CJK fonts have a pretty | |
| 453 // large repertoire. Eventually, we need to scan all the fonts | |
| 454 // on the system to have a Firefox-like coverage. | |
| 455 // Make sure that all of them are lowercased. | |
| 456 const static wchar_t* const cjkFonts[] = { | |
| 457 L"arial unicode ms", | |
| 458 L"ms pgothic", | |
| 459 L"simsun", | |
| 460 L"gulim", | |
| 461 L"pmingliu", | |
| 462 L"wenquanyi zen hei", // partial CJK Ext. A coverage but more | |
| 463 // widely known to Chinese users. | |
| 464 L"ar pl shanheisun uni", | |
| 465 L"ar pl zenkai uni", | |
| 466 L"han nom a", // Complete CJK Ext. A coverage | |
| 467 L"code2000", // Complete CJK Ext. A coverage | |
| 468 // CJK Ext. B fonts are not listed here because it's of no use | |
| 469 // with our current non-BMP character handling because we use | |
| 470 // Uniscribe for it and that code path does not go through here. | |
| 471 }; | |
| 472 | |
| 473 const static wchar_t* const commonFonts[] = { | |
| 474 L"tahoma", | |
| 475 L"arial unicode ms", | |
| 476 L"lucida sans unicode", | |
| 477 L"microsoft sans serif", | |
| 478 L"palatino linotype", | |
| 479 // Six fonts below (and code2000 at the end) are not from MS, but | |
| 480 // once installed, cover a very wide range of characters. | |
| 481 L"dejavu serif", | |
| 482 L"dejavu sasns", | |
| 483 L"freeserif", | |
| 484 L"freesans", | |
| 485 L"gentium", | |
| 486 L"gentiumalt", | |
| 487 L"ms pgothic", | |
| 488 L"simsun", | |
| 489 L"gulim", | |
| 490 L"pmingliu", | |
| 491 L"code2000", | |
| 492 }; | |
| 493 | |
| 494 const wchar_t* const* panUniFonts = 0; | |
| 495 int numFonts = 0; | |
| 496 if (script == USCRIPT_HAN) { | |
| 497 panUniFonts = cjkFonts; | |
| 498 numFonts = WTF_ARRAY_LENGTH(cjkFonts); | |
| 499 } else { | |
| 500 panUniFonts = commonFonts; | |
| 501 numFonts = WTF_ARRAY_LENGTH(commonFonts); | |
| 502 } | |
| 503 // Font returned from GetFallbackFamily may not cover |characters| | |
| 504 // because it's based on script to font mapping. This problem is | |
| 505 // critical enough for non-Latin scripts (especially Han) to | |
| 506 // warrant an additional (real coverage) check with fontCotainsCharacter. | |
| 507 int i; | |
| 508 for (i = 0; (!data || !fontContainsCharacter(data, family, c)) && i < numFon
ts; ++i) { | |
| 509 family = panUniFonts[i]; | |
| 510 data = getFontResourcePlatformData(font.fontDescription(), AtomicString(
family, wcslen(family))); | |
| 511 } | |
| 512 // When i-th font (0-base) in |panUniFonts| contains a character and | |
| 513 // we get out of the loop, |i| will be |i + 1|. That is, if only the | |
| 514 // last font in the array covers the character, |i| will be numFonts. | |
| 515 // So, we have to use '<=" rather than '<' to see if we found a font | |
| 516 // covering the character. | |
| 517 if (i <= numFonts) | |
| 518 return getFontResourceData(data, DoNotRetain); | |
| 519 | |
| 520 return 0; | |
| 521 | |
| 522 } | |
| 523 | |
| 524 PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescri
ption& description, ShouldRetain shouldRetain) | |
| 525 { | |
| 526 FontDescription::GenericFamilyType generic = description.genericFamily(); | |
| 527 | |
| 528 // FIXME: Would be even better to somehow get the user's default font here. | |
| 529 // For now we'll pick the default that the user would get without changing | |
| 530 // any prefs. | |
| 531 DEFINE_STATIC_LOCAL(AtomicString, timesStr, "Times New Roman"); | |
| 532 DEFINE_STATIC_LOCAL(AtomicString, courierStr, "Courier New"); | |
| 533 DEFINE_STATIC_LOCAL(AtomicString, arialStr, "Arial"); | |
| 534 | |
| 535 AtomicString& fontStr = timesStr; | |
| 536 if (generic == FontDescription::SansSerifFamily) | |
| 537 fontStr = arialStr; | |
| 538 else if (generic == FontDescription::MonospaceFamily) | |
| 539 fontStr = courierStr; | |
| 540 | |
| 541 RefPtr<SimpleFontData> simpleFont = getFontResourceData(description, fontStr
, false, shouldRetain); | |
| 542 if (simpleFont) | |
| 543 return simpleFont.release(); | |
| 544 | |
| 545 // Fall back to system fonts as Win Safari does because this function must | |
| 546 // return a valid font. Once we find a valid system font, we save its name | |
| 547 // to a static variable and use it to prevent trying system fonts again. | |
| 548 static wchar_t fallbackFontName[LF_FACESIZE] = {0}; | |
| 549 if (fallbackFontName[0]) | |
| 550 return getFontResourceData(description, fallbackFontName, false, shouldR
etain); | |
| 551 | |
| 552 // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available
. | |
| 553 if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FON
T))) { | |
| 554 LOGFONT defaultGUILogFont; | |
| 555 GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont)
; | |
| 556 if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRe
tain, defaultGUILogFont, fallbackFontName)) | |
| 557 return simpleFont.release(); | |
| 558 } | |
| 559 | |
| 560 // Fall back to Non-client metrics fonts. | |
| 561 NONCLIENTMETRICS nonClientMetrics = {0}; | |
| 562 nonClientMetrics.cbSize = sizeof(nonClientMetrics); | |
| 563 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics),
&nonClientMetrics, 0)) { | |
| 564 if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRe
tain, nonClientMetrics.lfMessageFont, fallbackFontName)) | |
| 565 return simpleFont.release(); | |
| 566 if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRe
tain, nonClientMetrics.lfMenuFont, fallbackFontName)) | |
| 567 return simpleFont.release(); | |
| 568 if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRe
tain, nonClientMetrics.lfStatusFont, fallbackFontName)) | |
| 569 return simpleFont.release(); | |
| 570 if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRe
tain, nonClientMetrics.lfCaptionFont, fallbackFontName)) | |
| 571 return simpleFont.release(); | |
| 572 if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRe
tain, nonClientMetrics.lfSmCaptionFont, fallbackFontName)) | |
| 573 return simpleFont.release(); | |
| 574 } | |
| 575 | |
| 576 // Fall back to all the fonts installed in this PC. When a font has a | |
| 577 // localized name according to the system locale as well as an English name, | |
| 578 // both GetTextFace() and EnumFontFamilies() return the localized name. So, | |
| 579 // FontCache::createFontPlatformData() does not filter out the fonts | |
| 580 // returned by this EnumFontFamilies() call. | |
| 581 HWndDC dc(0); | |
| 582 if (dc) { | |
| 583 GetLastResortFallbackFontProcData procData(this, &description, shouldRet
ain, fallbackFontName); | |
| 584 EnumFontFamilies(dc, 0, getLastResortFallbackFontProc, reinterpret_cast<
LPARAM>(&procData)); | |
| 585 | |
| 586 if (procData.m_fontData) | |
| 587 return procData.m_fontData.release(); | |
| 588 } | |
| 589 | |
| 590 ASSERT_NOT_REACHED(); | |
| 591 return 0; | |
| 592 } | |
| 593 | |
| 594 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne
d>& traitsMasks) | |
| 595 { | |
| 596 HWndDC hdc(0); | |
| 597 | |
| 598 LOGFONT logFont; | |
| 599 logFont.lfCharSet = DEFAULT_CHARSET; | |
| 600 unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FA
CESIZE - 1)); | |
| 601 familyName.string().copyTo(logFont.lfFaceName, 0, familyLength); | |
| 602 logFont.lfFaceName[familyLength] = 0; | |
| 603 logFont.lfPitchAndFamily = 0; | |
| 604 | |
| 605 TraitsInFamilyProcData procData(familyName); | |
| 606 EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<L
PARAM>(&procData), 0); | |
| 607 copyToVector(procData.m_traitsMasks, traitsMasks); | |
| 608 } | |
| 609 | |
| 610 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
escription, const AtomicString& family, float fontSize) | |
| 611 { | |
| 612 LOGFONT winfont = {0}; | |
| 613 FillLogFont(fontDescription, &winfont); | |
| 614 | |
| 615 // Windows will always give us a valid pointer here, even if the face name | |
| 616 // is non-existent. We have to double-check and see if the family name was | |
| 617 // really used. | |
| 618 String winName; | |
| 619 HFONT hfont = createFontIndirectAndGetWinName(family, &winfont, &winName); | |
| 620 if (!hfont) | |
| 621 return 0; | |
| 622 | |
| 623 // FIXME: Do we need to use predefined fonts "guaranteed" to exist | |
| 624 // when we're running in layout-test mode? | |
| 625 if (!equalIgnoringCase(family, winName)) { | |
| 626 // For CJK fonts with both English and native names, | |
| 627 // GetTextFace returns a native name under the font's "locale" | |
| 628 // and an English name under other locales regardless of | |
| 629 // lfFaceName field of LOGFONT. As a result, we need to check | |
| 630 // if a font has an alternate name. If there is, we need to | |
| 631 // compare it with what's requested in the first place. | |
| 632 String altName; | |
| 633 if (!LookupAltName(family, altName) || !equalIgnoringCase(altName, winNa
me)) { | |
| 634 DeleteObject(hfont); | |
| 635 return 0; | |
| 636 } | |
| 637 } | |
| 638 | |
| 639 return new FontPlatformData(hfont, fontSize, fontDescription.orientation()); | |
| 640 } | |
| 641 | |
| 642 } | |
| OLD | NEW |