Update CSSFontSelector's matching algorithm to understand ranges
[WebKit.git] / Source / WebCore / platform / graphics / freetype / FontCacheFreeType.cpp
1 /*
2  * Copyright (C) 2008 Alp Toker <alp@atoker.com>
3  * Copyright (C) 2010 Igalia S.L.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #include "config.h"
23 #include "FontCache.h"
24
25 #include "FcUniquePtr.h"
26 #include "Font.h"
27 #include "RefPtrCairo.h"
28 #include "UTF16UChar32Iterator.h"
29 #include <cairo-ft.h>
30 #include <cairo.h>
31 #include <fontconfig/fcfreetype.h>
32 #include <wtf/Assertions.h>
33 #include <wtf/text/CString.h>
34
35 namespace WebCore {
36
37 void FontCache::platformInit()
38 {
39     // It's fine to call FcInit multiple times per the documentation.
40     if (!FcInit())
41         ASSERT_NOT_REACHED();
42 }
43
44 static RefPtr<FcPattern> createFontConfigPatternForCharacters(const UChar* characters, int bufferLength)
45 {
46     RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
47     FcUniquePtr<FcCharSet> fontConfigCharSet(FcCharSetCreate());
48
49     UTF16UChar32Iterator iterator(characters, bufferLength);
50     UChar32 character = iterator.next();
51     while (character != iterator.end()) {
52         FcCharSetAddChar(fontConfigCharSet.get(), character);
53         character = iterator.next();
54     }
55
56     FcPatternAddCharSet(pattern.get(), FC_CHARSET, fontConfigCharSet.get());
57
58     FcPatternAddBool(pattern.get(), FC_SCALABLE, FcTrue);
59     FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern);
60     FcDefaultSubstitute(pattern.get());
61     return pattern;
62 }
63
64 static RefPtr<FcPattern> findBestFontGivenFallbacks(const FontPlatformData& fontData, FcPattern* pattern)
65 {
66     FcFontSet* fallbacks = fontData.fallbacks();
67     if (!fallbacks)
68         return nullptr;
69
70     FcResult fontConfigResult;
71     return FcFontSetMatch(nullptr, &fallbacks, 1, pattern, &fontConfigResult);
72 }
73
74 RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& description, const Font* originalFontData, bool, const UChar* characters, unsigned length)
75 {
76     RefPtr<FcPattern> pattern = createFontConfigPatternForCharacters(characters, length);
77     const FontPlatformData& fontData = originalFontData->platformData();
78
79     RefPtr<FcPattern> fallbackPattern = findBestFontGivenFallbacks(fontData, pattern.get());
80     if (fallbackPattern) {
81         FontPlatformData alternateFontData(fallbackPattern.get(), description);
82         return fontForPlatformData(alternateFontData);
83     }
84
85     FcResult fontConfigResult;
86     RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(nullptr, pattern.get(), &fontConfigResult));
87     if (!resultPattern)
88         return nullptr;
89     FontPlatformData alternateFontData(resultPattern.get(), description);
90     return fontForPlatformData(alternateFontData);
91 }
92
93 static Vector<String> patternToFamilies(FcPattern& pattern)
94 {
95     char* patternChars = reinterpret_cast<char*>(FcPatternFormat(&pattern, reinterpret_cast<const FcChar8*>("%{family}")));
96     String patternString = String::fromUTF8(patternChars);
97     free(patternChars);
98
99     Vector<String> results;
100     patternString.split(',', results);
101     return results;
102 }
103
104 Vector<String> FontCache::systemFontFamilies()
105 {
106     RefPtr<FcPattern> scalablesOnlyPattern = adoptRef(FcPatternCreate());
107     FcPatternAddBool(scalablesOnlyPattern.get(), FC_SCALABLE, FcTrue);
108
109     FcUniquePtr<FcObjectSet> familiesOnly(FcObjectSetBuild(FC_FAMILY, nullptr));
110     FcUniquePtr<FcFontSet> fontSet(FcFontList(nullptr, scalablesOnlyPattern.get(), familiesOnly.get()));
111
112     Vector<String> fontFamilies;
113     for (int i = 0; i < fontSet->nfont; i++) {
114         FcPattern* pattern = fontSet->fonts[i];
115         FcChar8* family = nullptr;
116         FcPatternGetString(pattern, FC_FAMILY, 0, &family);
117         if (family)
118             fontFamilies.appendVector(patternToFamilies(*pattern));
119     }
120
121     return fontFamilies;
122 }
123
124 Ref<Font> FontCache::lastResortFallbackFontForEveryCharacter(const FontDescription& fontDescription)
125 {
126     return lastResortFallbackFont(fontDescription);
127 }
128
129 Ref<Font> FontCache::lastResortFallbackFont(const FontDescription& fontDescription)
130 {
131     // We want to return a fallback font here, otherwise the logic preventing FontConfig
132     // matches for non-fallback fonts might return 0. See isFallbackFontAllowed.
133     static AtomicString timesStr("serif");
134     if (RefPtr<Font> font = fontForFamily(fontDescription, timesStr))
135         return *font;
136
137     // This could be reached due to improperly-installed or misconfigured fontconfig.
138     RELEASE_ASSERT_NOT_REACHED();
139 }
140
141 auto FontCache::getTraitsAndStretchInFamily(const AtomicString& familyName) -> Vector<TraitsAndStretch>
142 {
143     return { };
144 }
145
146 static String getFamilyNameStringFromFamily(const AtomicString& family)
147 {
148     // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into
149     // the fallback name (like "monospace") that fontconfig understands.
150     if (family.length() && !family.startsWith("-webkit-"))
151         return family.string();
152
153     if (family == standardFamily || family == serifFamily)
154         return "serif";
155     if (family == sansSerifFamily)
156         return "sans-serif";
157     if (family == monospaceFamily)
158         return "monospace";
159     if (family == cursiveFamily)
160         return "cursive";
161     if (family == fantasyFamily)
162         return "fantasy";
163     return "";
164 }
165
166 static int fontWeightToFontconfigWeight(FontWeight weight)
167 {
168     switch (weight) {
169     case FontWeight100:
170         return FC_WEIGHT_THIN;
171     case FontWeight200:
172         return FC_WEIGHT_ULTRALIGHT;
173     case FontWeight300:
174         return FC_WEIGHT_LIGHT;
175     case FontWeight400:
176         return FC_WEIGHT_REGULAR;
177     case FontWeight500:
178         return FC_WEIGHT_MEDIUM;
179     case FontWeight600:
180         return FC_WEIGHT_SEMIBOLD;
181     case FontWeight700:
182         return FC_WEIGHT_BOLD;
183     case FontWeight800:
184         return FC_WEIGHT_EXTRABOLD;
185     case FontWeight900:
186         return FC_WEIGHT_ULTRABLACK;
187     default:
188         ASSERT_NOT_REACHED();
189         return FC_WEIGHT_REGULAR;
190     }
191 }
192
193 // This is based on Chromium BSD code from Skia (src/ports/SkFontMgr_fontconfig.cpp). It is a
194 // hack for lack of API in Fontconfig: https://bugs.freedesktop.org/show_bug.cgi?id=19375
195 // FIXME: This is horrible. It should be deleted once Fontconfig can do this itself.
196 enum class AliasStrength {
197     Weak,
198     Strong,
199     Done
200 };
201
202 static AliasStrength strengthOfFirstAlias(const FcPattern& original)
203 {
204     // Ideally there would exist a call like
205     // FcResult FcPatternIsWeak(pattern, object, id, FcBool* isWeak);
206     //
207     // However, there is no such call and as of Fc 2.11.0 even FcPatternEquals ignores the weak bit.
208     // Currently, the only reliable way of finding the weak bit is by its effect on matching.
209     // The weak bit only affects the matching of FC_FAMILY and FC_POSTSCRIPT_NAME object values.
210     // A element with the weak bit is scored after FC_LANG, without the weak bit is scored before.
211     // Note that the weak bit is stored on the element, not on the value it holds.
212     FcValue value;
213     FcResult result = FcPatternGet(&original, FC_FAMILY, 0, &value);
214     if (result != FcResultMatch)
215         return AliasStrength::Done;
216
217     RefPtr<FcPattern> pattern = adoptRef(FcPatternDuplicate(&original));
218     FcBool hasMultipleFamilies = true;
219     while (hasMultipleFamilies)
220         hasMultipleFamilies = FcPatternRemove(pattern.get(), FC_FAMILY, 1);
221
222     // Create a font set with two patterns.
223     // 1. the same FC_FAMILY as pattern and a lang object with only 'nomatchlang'.
224     // 2. a different FC_FAMILY from pattern and a lang object with only 'matchlang'.
225     FcUniquePtr<FcFontSet> fontSet(FcFontSetCreate());
226
227     FcUniquePtr<FcLangSet> strongLangSet(FcLangSetCreate());
228     FcLangSetAdd(strongLangSet.get(), reinterpret_cast<const FcChar8*>("nomatchlang"));
229     // Ownership of this FcPattern will be transferred with FcFontSetAdd.
230     FcPattern* strong = FcPatternDuplicate(pattern.get());
231     FcPatternAddLangSet(strong, FC_LANG, strongLangSet.get());
232
233     FcUniquePtr<FcLangSet> weakLangSet(FcLangSetCreate());
234     FcLangSetAdd(weakLangSet.get(), reinterpret_cast<const FcChar8*>("matchlang"));
235     // Ownership of this FcPattern will be transferred via FcFontSetAdd.
236     FcPattern* weak = FcPatternCreate();
237     FcPatternAddString(weak, FC_FAMILY, reinterpret_cast<const FcChar8*>("nomatchstring"));
238     FcPatternAddLangSet(weak, FC_LANG, weakLangSet.get());
239
240     FcFontSetAdd(fontSet.get(), strong);
241     FcFontSetAdd(fontSet.get(), weak);
242
243     // Add 'matchlang' to the copy of the pattern.
244     FcPatternAddLangSet(pattern.get(), FC_LANG, weakLangSet.get());
245
246     // Run a match against the copy of the pattern.
247     // If the first element was weak, then we should match the pattern with 'matchlang'.
248     // If the first element was strong, then we should match the pattern with 'nomatchlang'.
249
250     // Note that this config is only used for FcFontRenderPrepare, which we don't even want.
251     // However, there appears to be no way to match/sort without it.
252     RefPtr<FcConfig> config = adoptRef(FcConfigCreate());
253     FcFontSet* fontSets[1] = { fontSet.get() };
254     RefPtr<FcPattern> match = adoptRef(FcFontSetMatch(config.get(), fontSets, 1, pattern.get(), &result));
255
256     FcLangSet* matchLangSet;
257     FcPatternGetLangSet(match.get(), FC_LANG, 0, &matchLangSet);
258     return FcLangEqual == FcLangSetHasLang(matchLangSet, reinterpret_cast<const FcChar8*>("matchlang"))
259         ? AliasStrength::Weak : AliasStrength::Strong;
260 }
261
262 static Vector<String> strongAliasesForFamily(const String& family)
263 {
264     RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
265     if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(family.utf8().data())))
266         return Vector<String>();
267
268     FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern);
269     FcDefaultSubstitute(pattern.get());
270
271     FcUniquePtr<FcObjectSet> familiesOnly(FcObjectSetBuild(FC_FAMILY, nullptr));
272     RefPtr<FcPattern> minimal = adoptRef(FcPatternFilter(pattern.get(), familiesOnly.get()));
273
274     // We really want to match strong (preferred) and same (acceptable) only here.
275     // If a family name was specified, assume that any weak matches after the last strong match
276     // are weak (default) and ignore them.
277     // The reason for is that after substitution the pattern for 'sans-serif' looks like
278     // "wwwwwwwwwwwwwwswww" where there are many weak but preferred names, followed by defaults.
279     // So it is possible to have weakly matching but preferred names.
280     // In aliases, bindings are weak by default, so this is easy and common.
281     // If no family name was specified, we'll probably only get weak matches, but that's ok.
282     int lastStrongId = -1;
283     int numIds = 0;
284     for (int id = 0; ; ++id) {
285         AliasStrength result = strengthOfFirstAlias(*minimal);
286         if (result == AliasStrength::Done) {
287             numIds = id;
288             break;
289         }
290         if (result == AliasStrength::Strong)
291             lastStrongId = id;
292         if (!FcPatternRemove(minimal.get(), FC_FAMILY, 0))
293             return Vector<String>();
294     }
295
296     // If they were all weak, then leave the pattern alone.
297     if (lastStrongId < 0)
298         return Vector<String>();
299
300     // Remove everything after the last strong.
301     for (int id = lastStrongId + 1; id < numIds; ++id) {
302         if (!FcPatternRemove(pattern.get(), FC_FAMILY, lastStrongId + 1)) {
303             ASSERT_NOT_REACHED();
304             return Vector<String>();
305         }
306     }
307
308     return patternToFamilies(*pattern);
309 }
310
311 static bool areStronglyAliased(const String& familyA, const String& familyB)
312 {
313     for (auto& family : strongAliasesForFamily(familyA)) {
314         if (family == familyB)
315             return true;
316     }
317     return false;
318 }
319
320 static inline bool isCommonlyUsedGenericFamily(const String& familyNameString)
321 {
322     return equalLettersIgnoringASCIICase(familyNameString, "sans")
323         || equalLettersIgnoringASCIICase(familyNameString, "sans-serif")
324         || equalLettersIgnoringASCIICase(familyNameString, "serif")
325         || equalLettersIgnoringASCIICase(familyNameString, "monospace")
326         || equalLettersIgnoringASCIICase(familyNameString, "fantasy")
327         || equalLettersIgnoringASCIICase(familyNameString, "cursive");
328 }
329
330 std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, const FontFeatureSettings*, const FontVariantSettings*)
331 {
332     // The CSS font matching algorithm (http://www.w3.org/TR/css3-fonts/#font-matching-algorithm)
333     // says that we must find an exact match for font family, slant (italic or oblique can be used)
334     // and font weight (we only match bold/non-bold here).
335     RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
336     // Never choose unscalable fonts, as they pixelate when displayed at different sizes.
337     FcPatternAddBool(pattern.get(), FC_SCALABLE, FcTrue);
338     String familyNameString(getFamilyNameStringFromFamily(family));
339     if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.utf8().data())))
340         return nullptr;
341
342     bool italic = fontDescription.italic();
343     if (!FcPatternAddInteger(pattern.get(), FC_SLANT, italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN))
344         return nullptr;
345     if (!FcPatternAddInteger(pattern.get(), FC_WEIGHT, fontWeightToFontconfigWeight(fontDescription.weight())))
346         return nullptr;
347     if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize()))
348         return nullptr;
349
350     // The strategy is originally from Skia (src/ports/SkFontHost_fontconfig.cpp):
351     //
352     // We do not normally allow fontconfig to substitute one font family for another, since this
353     // would break CSS font family fallback: the website should be in control of fallback. During
354     // normal font matching, the only font family substitution permitted is for generic families
355     // (sans, serif, monospace) or for strongly-aliased fonts (which are to be treated as
356     // effectively identical). This is because the font matching step is designed to always find a
357     // match for the font, which we don't want.
358     //
359     // Fontconfig is used in two stages: (1) configuration and (2) matching. During the
360     // configuration step, before any matching occurs, we allow arbitrary family substitutions,
361     // since this is an exact matter of respecting the user's font configuration.
362     FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern);
363     FcDefaultSubstitute(pattern.get());
364
365     FcChar8* fontConfigFamilyNameAfterConfiguration;
366     FcPatternGetString(pattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration);
367     String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration));
368
369     FcResult fontConfigResult;
370     RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(nullptr, pattern.get(), &fontConfigResult));
371     if (!resultPattern) // No match.
372         return nullptr;
373
374     FcChar8* fontConfigFamilyNameAfterMatching;
375     FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching);
376     String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching));
377
378     // If Fontconfig gave us a different font family than the one we requested, we should ignore it
379     // and allow WebCore to give us the next font on the CSS fallback list. The exceptions are if
380     // this family name is a commonly-used generic family, or if the families are strongly-aliased.
381     // Checking for a strong alias comes last, since it is slow.
382     if (!equalIgnoringASCIICase(familyNameAfterConfiguration, familyNameAfterMatching) && !isCommonlyUsedGenericFamily(familyNameString) && !areStronglyAliased(familyNameAfterConfiguration, familyNameAfterMatching))
383         return nullptr;
384
385     // Verify that this font has an encoding compatible with Fontconfig. Fontconfig currently
386     // supports three encodings in FcFreeTypeCharIndex: Unicode, Symbol and AppleRoman.
387     // If this font doesn't have one of these three encodings, don't select it.
388     auto platformData = std::make_unique<FontPlatformData>(resultPattern.get(), fontDescription);
389     if (!platformData->hasCompatibleCharmap())
390         return nullptr;
391
392     return platformData;
393 }
394
395 const AtomicString& FontCache::platformAlternateFamilyName(const AtomicString&)
396 {
397     return nullAtom;
398 }
399
400 }