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