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 "platform/fonts/FontCache.h"
34
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/FontPlatformData.h"
41#include "platform/fonts/SimpleFontData.h"
42#include "platform/fonts/win/FontFallbackWin.h"
43
44namespace blink {
45
46HashMap<String, RefPtr<SkTypeface> >* FontCache::s_sideloadedFonts = 0;
47
48// static
49void FontCache::addSideloadedFontForTesting(SkTypeface* typeface)
50{
51    if (!s_sideloadedFonts)
52        s_sideloadedFonts = new HashMap<String, RefPtr<SkTypeface> >;
53    SkString name;
54    typeface->getFamilyName(&name);
55    s_sideloadedFonts->set(name.c_str(), adoptRef(typeface));
56}
57
58FontCache::FontCache()
59    : m_purgePreventCount(0)
60{
61    SkFontMgr* fontManager;
62
63    if (s_useDirectWrite) {
64        fontManager = SkFontMgr_New_DirectWrite(s_directWriteFactory);
65        s_useSubpixelPositioning = RuntimeEnabledFeatures::subpixelFontScalingEnabled();
66    } else {
67        fontManager = SkFontMgr_New_GDI();
68        // Subpixel text positioning is not supported by the GDI backend.
69        s_useSubpixelPositioning = false;
70    }
71
72    ASSERT(fontManager);
73    m_fontManager = adoptPtr(fontManager);
74}
75
76
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.
79PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(
80    const FontDescription& fontDescription, UChar32 character,
81    const SimpleFontData* originalFontData)
82{
83    // First try the specified font with standard style & weight.
84    if (fontDescription.style() == FontStyleItalic
85        || fontDescription.weight() >= FontWeightBold) {
86        RefPtr<SimpleFontData> fontData = fallbackOnStandardFontStyle(
87            fontDescription, character);
88        if (fontData)
89            return fontData;
90    }
91
92    // FIXME: Consider passing fontDescription.dominantScript()
93    // to GetFallbackFamily here.
94    UScriptCode script;
95    const wchar_t* family = getFallbackFamily(character,
96        fontDescription.genericFamily(),
97        &script,
98        m_fontManager.get());
99    FontPlatformData* data = 0;
100    if (family) {
101        FontFaceCreationParams createByFamily(AtomicString(family, wcslen(family)));
102        data = getFontPlatformData(fontDescription, createByFamily);
103    }
104
105    // Last resort font list : PanUnicode. CJK fonts have a pretty
106    // large repertoire. Eventually, we need to scan all the fonts
107    // on the system to have a Firefox-like coverage.
108    // Make sure that all of them are lowercased.
109    const static wchar_t* const cjkFonts[] = {
110        L"arial unicode ms",
111        L"ms pgothic",
112        L"simsun",
113        L"gulim",
114        L"pmingliu",
115        L"wenquanyi zen hei", // Partial CJK Ext. A coverage but more widely known to Chinese users.
116        L"ar pl shanheisun uni",
117        L"ar pl zenkai uni",
118        L"han nom a", // Complete CJK Ext. A coverage.
119        L"code2000" // Complete CJK Ext. A coverage.
120        // CJK Ext. B fonts are not listed here because it's of no use
121        // with our current non-BMP character handling because we use
122        // Uniscribe for it and that code path does not go through here.
123    };
124
125    const static wchar_t* const commonFonts[] = {
126        L"tahoma",
127        L"arial unicode ms",
128        L"lucida sans unicode",
129        L"microsoft sans serif",
130        L"palatino linotype",
131        // Six fonts below (and code2000 at the end) are not from MS, but
132        // once installed, cover a very wide range of characters.
133        L"dejavu serif",
134        L"dejavu sasns",
135        L"freeserif",
136        L"freesans",
137        L"gentium",
138        L"gentiumalt",
139        L"ms pgothic",
140        L"simsun",
141        L"gulim",
142        L"pmingliu",
143        L"code2000"
144    };
145
146    const wchar_t* const* panUniFonts = 0;
147    int numFonts = 0;
148    if (script == USCRIPT_HAN) {
149        panUniFonts = cjkFonts;
150        numFonts = WTF_ARRAY_LENGTH(cjkFonts);
151    } else {
152        panUniFonts = commonFonts;
153        numFonts = WTF_ARRAY_LENGTH(commonFonts);
154    }
155    // Font returned from getFallbackFamily may not cover |character|
156    // because it's based on script to font mapping. This problem is
157    // critical enough for non-Latin scripts (especially Han) to
158    // warrant an additional (real coverage) check with fontCotainsCharacter.
159    int i;
160    for (i = 0; (!data || !data->fontContainsCharacter(character)) && i < numFonts; ++i) {
161        family = panUniFonts[i];
162        FontFaceCreationParams createByFamily(AtomicString(family, wcslen(family)));
163        data = getFontPlatformData(fontDescription, createByFamily);
164    }
165
166    // For font fallback we want to match the subpixel behavior of the original
167    // font. Mixing subpixel and non-subpixel in the same text run looks really
168    // odd and causes problems with preferred width calculations.
169    if (data && originalFontData) {
170        const FontPlatformData& platformData = originalFontData->platformData();
171        data->setMinSizeForAntiAlias(platformData.minSizeForAntiAlias());
172        data->setMinSizeForSubpixel(platformData.minSizeForSubpixel());
173    }
174
175    // When i-th font (0-base) in |panUniFonts| contains a character and
176    // we get out of the loop, |i| will be |i + 1|. That is, if only the
177    // last font in the array covers the character, |i| will be numFonts.
178    // So, we have to use '<=" rather than '<' to see if we found a font
179    // covering the character.
180    if (i <= numFonts)
181        return fontDataFromFontPlatformData(data, DoNotRetain);
182
183    return nullptr;
184}
185
186static inline bool equalIgnoringCase(const AtomicString& a, const SkString& b)
187{
188    return equalIgnoringCase(a, AtomicString::fromUTF8(b.c_str()));
189}
190
191static bool typefacesMatchesFamily(const SkTypeface* tf, const AtomicString& family)
192{
193    SkTypeface::LocalizedStrings* actualFamilies = tf->createFamilyNameIterator();
194    bool matchesRequestedFamily = false;
195    SkTypeface::LocalizedString actualFamily;
196
197    while (actualFamilies->next(&actualFamily)) {
198        if (equalIgnoringCase(family, actualFamily.fString)) {
199            matchesRequestedFamily = true;
200            break;
201        }
202    }
203    actualFamilies->unref();
204
205    // getFamilyName may return a name not returned by the createFamilyNameIterator.
206    // Specifically in cases where Windows substitutes the font based on the
207    // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes registry entries.
208    if (!matchesRequestedFamily) {
209        SkString familyName;
210        tf->getFamilyName(&familyName);
211        if (equalIgnoringCase(family, familyName))
212            matchesRequestedFamily = true;
213    }
214
215    return matchesRequestedFamily;
216}
217
218static bool typefacesHasWeightSuffix(const AtomicString& family,
219    AtomicString& adjustedName, FontWeight& variantWeight)
220{
221    struct FamilyWeightSuffix {
222        const wchar_t* suffix;
223        size_t length;
224        FontWeight weight;
225    };
226    // Mapping from suffix to weight from the DirectWrite documentation.
227    // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368082.aspx
228    const static FamilyWeightSuffix variantForSuffix[] = {
229        { L" thin", 5,  FontWeight100 },
230        { L" extralight", 11,  FontWeight200 },
231        { L" ultralight", 11,  FontWeight200 },
232        { L" light", 6,  FontWeight300 },
233        { L" medium", 7,  FontWeight500 },
234        { L" demibold", 9,  FontWeight600 },
235        { L" semibold", 9,  FontWeight600 },
236        { L" extrabold", 10,  FontWeight800 },
237        { L" ultrabold", 10,  FontWeight800 },
238        { L" black", 6,  FontWeight900 },
239        { L" heavy", 6,  FontWeight900 }
240    };
241    size_t numVariants = WTF_ARRAY_LENGTH(variantForSuffix);
242    bool caseSensitive = false;
243    for (size_t i = 0; i < numVariants; i++) {
244        const FamilyWeightSuffix& entry = variantForSuffix[i];
245        if (family.endsWith(entry.suffix, caseSensitive)) {
246            String familyName = family.string();
247            familyName.truncate(family.length() - entry.length);
248            adjustedName = AtomicString(familyName);
249            variantWeight = entry.weight;
250            return true;
251        }
252    }
253
254    return false;
255}
256
257static bool typefacesHasStretchSuffix(const AtomicString& family,
258    AtomicString& adjustedName, FontStretch& variantStretch)
259{
260    struct FamilyStretchSuffix {
261        const wchar_t* suffix;
262        size_t length;
263        FontStretch stretch;
264    };
265    // Mapping from suffix to stretch value from the DirectWrite documentation.
266    // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368078.aspx
267    // Also includes Narrow as a synonym for Condensed to to support Arial
268    // Narrow and other fonts following the same naming scheme.
269    const static FamilyStretchSuffix variantForSuffix[] = {
270        { L" ultracondensed", 15,  FontStretchUltraCondensed },
271        { L" extracondensed", 15,  FontStretchExtraCondensed },
272        { L" condensed", 10,  FontStretchCondensed },
273        { L" narrow", 7,  FontStretchCondensed },
274        { L" semicondensed", 14,  FontStretchSemiCondensed },
275        { L" semiexpanded", 13,  FontStretchSemiExpanded },
276        { L" expanded", 9,  FontStretchExpanded },
277        { L" extraexpanded", 14,  FontStretchExtraExpanded },
278        { L" ultraexpanded", 14,  FontStretchUltraExpanded }
279    };
280    size_t numVariants = WTF_ARRAY_LENGTH(variantForSuffix);
281    bool caseSensitive = false;
282    for (size_t i = 0; i < numVariants; i++) {
283        const FamilyStretchSuffix& entry = variantForSuffix[i];
284        if (family.endsWith(entry.suffix, caseSensitive)) {
285            String familyName = family.string();
286            familyName.truncate(family.length() - entry.length);
287            adjustedName = AtomicString(familyName);
288            variantStretch = entry.stretch;
289            return true;
290        }
291    }
292
293    return false;
294}
295
296FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize)
297{
298    ASSERT(creationParams.creationType() == CreateFontByFamily);
299
300    CString name;
301    RefPtr<SkTypeface> tf = createTypeface(fontDescription, creationParams, name);
302    // Windows will always give us a valid pointer here, even if the face name
303    // is non-existent. We have to double-check and see if the family name was
304    // really used.
305    if (!tf || !typefacesMatchesFamily(tf.get(), creationParams.family())) {
306        AtomicString adjustedName;
307        FontWeight variantWeight;
308        FontStretch variantStretch;
309
310        if (typefacesHasWeightSuffix(creationParams.family(), adjustedName,
311            variantWeight)) {
312            FontFaceCreationParams adjustedParams(adjustedName);
313            FontDescription adjustedFontDescription = fontDescription;
314            adjustedFontDescription.setWeight(variantWeight);
315            tf = createTypeface(adjustedFontDescription, adjustedParams, name);
316            if (!tf || !typefacesMatchesFamily(tf.get(), adjustedName))
317                return 0;
318
319        } else if (typefacesHasStretchSuffix(creationParams.family(),
320            adjustedName, variantStretch)) {
321            FontFaceCreationParams adjustedParams(adjustedName);
322            FontDescription adjustedFontDescription = fontDescription;
323            adjustedFontDescription.setStretch(variantStretch);
324            tf = createTypeface(adjustedFontDescription, adjustedParams, name);
325            if (!tf || !typefacesMatchesFamily(tf.get(), adjustedName))
326                return 0;
327
328        } else {
329            return 0;
330        }
331    }
332
333    FontPlatformData* result = new FontPlatformData(tf,
334        name.data(),
335        fontSize,
336        fontDescription.weight() >= FontWeight600 && !tf->isBold() || fontDescription.isSyntheticBold(),
337        fontDescription.style() == FontStyleItalic && !tf->isItalic() || fontDescription.isSyntheticItalic(),
338        fontDescription.orientation(),
339        s_useSubpixelPositioning);
340
341    struct FamilyMinSize {
342        const wchar_t* family;
343        unsigned minSize;
344    };
345    const static FamilyMinSize minAntiAliasSizeForFont[] = {
346        { L"simsun", 11 },
347        { L"dotum", 12 },
348        { L"gulim", 12 },
349        { L"pmingliu", 11 }
350    };
351    size_t numFonts = WTF_ARRAY_LENGTH(minAntiAliasSizeForFont);
352    for (size_t i = 0; i < numFonts; i++) {
353        FamilyMinSize entry = minAntiAliasSizeForFont[i];
354        if (typefacesMatchesFamily(tf.get(), entry.family)) {
355            result->setMinSizeForAntiAlias(entry.minSize);
356            break;
357        }
358    }
359
360    // List of fonts that look bad with subpixel text rendering at smaller font
361    // sizes. This includes all fonts in the Microsoft Core fonts for the Web
362    // collection.
363    const static wchar_t* noSubpixelForSmallSizeFont[] = {
364        L"andale mono",
365        L"arial",
366        L"comic sans",
367        L"courier new",
368        L"georgia",
369        L"impact",
370        L"lucida console",
371        L"tahoma",
372        L"times new roman",
373        L"trebuchet ms",
374        L"verdana",
375        L"webdings"
376    };
377    const static float minSizeForSubpixelForFont = 16.0f;
378    numFonts = WTF_ARRAY_LENGTH(noSubpixelForSmallSizeFont);
379    for (size_t i = 0; i < numFonts; i++) {
380        const wchar_t* family = noSubpixelForSmallSizeFont[i];
381        if (typefacesMatchesFamily(tf.get(), family)) {
382            result->setMinSizeForSubpixel(minSizeForSubpixelForFont);
383            break;
384        }
385    }
386
387    return result;
388}
389
390} // namespace blink
391