2 * Copyright (C) 2006, 2007 Apple Computer, Inc.
3 * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #include "platform/fonts/FontCache.h"
35 #include "SkFontMgr.h"
36 #include "SkTypeface_win.h"
37 #include "platform/RuntimeEnabledFeatures.h"
38 #include "platform/fonts/FontDescription.h"
39 #include "platform/fonts/FontFaceCreationParams.h"
40 #include "platform/fonts/SimpleFontData.h"
41 #include "platform/fonts/harfbuzz/FontPlatformDataHarfbuzz.h"
42 #include "platform/fonts/win/FontFallbackWin.h"
46 HashMap<String, SkTypeface*>* FontCache::s_sideloadedFonts = 0;
49 void FontCache::addSideloadedFontForTesting(SkTypeface* typeface)
51 if (!s_sideloadedFonts)
52 s_sideloadedFonts = new HashMap<String, SkTypeface*>;
54 typeface->getFamilyName(&name);
55 s_sideloadedFonts->set(name.c_str(), typeface);
58 FontCache::FontCache()
59 : m_purgePreventCount(0)
61 SkFontMgr* fontManager;
63 if (s_useDirectWrite) {
64 fontManager = SkFontMgr_New_DirectWrite(s_directWriteFactory);
65 s_useSubpixelPositioning = RuntimeEnabledFeatures::subpixelFontScalingEnabled();
67 fontManager = SkFontMgr_New_GDI();
68 // Subpixel text positioning is not supported by the GDI backend.
69 s_useSubpixelPositioning = false;
73 m_fontManager = adoptPtr(fontManager);
77 // Given the desired base font, this will create a SimpleFontData for a specific
78 // font that can be used to render the given range of characters.
79 PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 character, const SimpleFontData*)
81 // First try the specified font with standard style & weight.
82 if (fontDescription.style() == FontStyleItalic
83 || fontDescription.weight() >= FontWeightBold) {
84 RefPtr<SimpleFontData> fontData = fallbackOnStandardFontStyle(
85 fontDescription, character);
90 // FIXME: Consider passing fontDescription.dominantScript()
91 // to GetFallbackFamily here.
93 const wchar_t* family = getFallbackFamily(character,
94 fontDescription.genericFamily(),
97 FontPlatformData* data = 0;
99 FontFaceCreationParams createByFamily(AtomicString(family, wcslen(family)));
100 data = getFontPlatformData(fontDescription, createByFamily);
103 // Last resort font list : PanUnicode. CJK fonts have a pretty
104 // large repertoire. Eventually, we need to scan all the fonts
105 // on the system to have a Firefox-like coverage.
106 // Make sure that all of them are lowercased.
107 const static wchar_t* const cjkFonts[] = {
113 L"wenquanyi zen hei", // Partial CJK Ext. A coverage but more widely known to Chinese users.
114 L"ar pl shanheisun uni",
116 L"han nom a", // Complete CJK Ext. A coverage.
117 L"code2000" // Complete CJK Ext. A coverage.
118 // CJK Ext. B fonts are not listed here because it's of no use
119 // with our current non-BMP character handling because we use
120 // Uniscribe for it and that code path does not go through here.
123 const static wchar_t* const commonFonts[] = {
126 L"lucida sans unicode",
127 L"microsoft sans serif",
128 L"palatino linotype",
129 // Six fonts below (and code2000 at the end) are not from MS, but
130 // once installed, cover a very wide range of characters.
144 const wchar_t* const* panUniFonts = 0;
146 if (script == USCRIPT_HAN) {
147 panUniFonts = cjkFonts;
148 numFonts = WTF_ARRAY_LENGTH(cjkFonts);
150 panUniFonts = commonFonts;
151 numFonts = WTF_ARRAY_LENGTH(commonFonts);
153 // Font returned from getFallbackFamily may not cover |character|
154 // because it's based on script to font mapping. This problem is
155 // critical enough for non-Latin scripts (especially Han) to
156 // warrant an additional (real coverage) check with fontCotainsCharacter.
158 for (i = 0; (!data || !data->fontContainsCharacter(character)) && i < numFonts; ++i) {
159 family = panUniFonts[i];
160 FontFaceCreationParams createByFamily(AtomicString(family, wcslen(family)));
161 data = getFontPlatformData(fontDescription, createByFamily);
164 // When i-th font (0-base) in |panUniFonts| contains a character and
165 // we get out of the loop, |i| will be |i + 1|. That is, if only the
166 // last font in the array covers the character, |i| will be numFonts.
167 // So, we have to use '<=" rather than '<' to see if we found a font
168 // covering the character.
170 return fontDataFromFontPlatformData(data, DoNotRetain);
175 static inline bool equalIgnoringCase(const AtomicString& a, const SkString& b)
177 return equalIgnoringCase(a, AtomicString::fromUTF8(b.c_str()));
180 static bool typefacesMatchesFamily(const SkTypeface* tf, const AtomicString& family)
182 SkTypeface::LocalizedStrings* actualFamilies = tf->createFamilyNameIterator();
183 bool matchesRequestedFamily = false;
184 SkTypeface::LocalizedString actualFamily;
186 while (actualFamilies->next(&actualFamily)) {
187 if (equalIgnoringCase(family, actualFamily.fString)) {
188 matchesRequestedFamily = true;
192 actualFamilies->unref();
194 // getFamilyName may return a name not returned by the createFamilyNameIterator.
195 // Specifically in cases where Windows substitutes the font based on the
196 // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes registry entries.
197 if (!matchesRequestedFamily) {
199 tf->getFamilyName(&familyName);
200 if (equalIgnoringCase(family, familyName))
201 matchesRequestedFamily = true;
204 return matchesRequestedFamily;
207 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize)
209 ASSERT(creationParams.creationType() == CreateFontByFamily);
211 RefPtr<SkTypeface> tf = createTypeface(fontDescription, creationParams, name);
215 // Windows will always give us a valid pointer here, even if the face name
216 // is non-existent. We have to double-check and see if the family name was
218 // FIXME: Do we need to use predefined fonts "guaranteed" to exist
219 // when we're running in layout-test mode?
220 if (!typefacesMatchesFamily(tf.get(), creationParams.family())) {
224 FontPlatformData* result = new FontPlatformData(tf,
227 fontDescription.weight() >= FontWeight600 && !tf->isBold() || fontDescription.isSyntheticBold(),
228 fontDescription.style() == FontStyleItalic && !tf->isItalic() || fontDescription.isSyntheticItalic(),
229 fontDescription.orientation(),
230 s_useSubpixelPositioning);
232 struct FamilyMinSize {
233 const wchar_t* family;
236 const static FamilyMinSize minAntiAliasSizeForFont[] = {
242 size_t numFonts = WTF_ARRAY_LENGTH(minAntiAliasSizeForFont);
243 for (size_t i = 0; i < numFonts; i++) {
244 FamilyMinSize entry = minAntiAliasSizeForFont[i];
245 if (typefacesMatchesFamily(tf.get(), entry.family)) {
246 result->setMinSizeForAntiAlias(entry.minSize);