2 * Copyright (C) 2008 Alp Toker <alp@atoker.com>
3 * Copyright (C) 2010 Igalia S.L.
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.
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.
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.
23 #include "FontCache.h"
26 #include "OwnPtrCairo.h"
27 #include "RefPtrCairo.h"
28 #include "SimpleFontData.h"
31 #include <fontconfig/fcfreetype.h>
32 #include <wtf/Assertions.h>
33 #include <wtf/text/CString.h>
35 #if ENABLE(TIZEN_WEBKIT_OWN_FONT_FILES)
36 #define APP_FONT_DIR "/usr/share/app_fonts"
41 void FontCache::platformInit()
43 #if ENABLE(TIZEN_WEBKIT_OWN_FONT_FILES)
45 fc_config = FcConfigGetCurrent();
46 FcConfigAppFontAddDir(fc_config, (FcChar8*)APP_FONT_DIR);
47 FcConfigSetCurrent(fc_config);
49 // It's fine to call FcInit multiple times per the documentation.
54 FcPattern* createFontConfigPatternForCharacters(const UChar* characters, int length)
56 FcPattern* pattern = FcPatternCreate();
58 FcCharSet* fontConfigCharSet = FcCharSetCreate();
59 for (int i = 0; i < length; ++i) {
60 if (U16_IS_SURROGATE(characters[i]) && U16_IS_SURROGATE_LEAD(characters[i])
61 && i != length - 1 && U16_IS_TRAIL(characters[i + 1])) {
62 FcCharSetAddChar(fontConfigCharSet, U16_GET_SUPPLEMENTARY(characters[i], characters[i+1]));
65 FcCharSetAddChar(fontConfigCharSet, characters[i]);
67 FcPatternAddCharSet(pattern, FC_CHARSET, fontConfigCharSet);
68 FcCharSetDestroy(fontConfigCharSet);
70 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
71 FcConfigSubstitute(0, pattern, FcMatchPattern);
72 FcDefaultSubstitute(pattern);
76 #if ENABLE(TIZEN_USER_SETTING_FONT)
77 PassRefPtr<FcPattern> createTizenPattern()
79 RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
80 if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>("Tizen")))
83 FcConfigSubstitute(0, pattern.get(), FcMatchPattern);
84 FcDefaultSubstitute(pattern.get());
85 return pattern.release();
89 FcPattern* findBestFontGivenFallbacks(const FontPlatformData& fontData, FcPattern* pattern)
91 #if ENABLE(TIZEN_USER_SETTING_FONT)
92 //If we don't find glyphs for characters, we can use SLP fallback font that is selected by user in Setting
93 static RefPtr<FcPattern> settingsPattern = createTizenPattern();
95 FcResult fallbackFontConfigResult;
96 if (!fontData.m_fallbacks)
97 fontData.m_fallbacks = FcFontSort(0, settingsPattern.get(), FcTrue, 0, &fallbackFontConfigResult);
99 if (!fontData.m_fallbacks)
102 FcFontSet* fcSets[] = { fontData.m_fallbacks };
103 return FcFontSetMatch(0, fcSets, 1, pattern, &fallbackFontConfigResult);
105 if (!fontData.m_pattern)
108 if (!fontData.m_fallbacks) {
109 FcResult fontConfigResult;
110 fontData.m_fallbacks = FcFontSort(0, fontData.m_pattern.get(), FcTrue, 0, &fontConfigResult);
113 if (!fontData.m_fallbacks)
116 FcFontSet* sets[] = { fontData.m_fallbacks };
117 FcResult fontConfigResult;
118 return FcFontSetMatch(0, sets, 1, pattern, &fontConfigResult);
122 const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
124 RefPtr<FcPattern> pattern = adoptRef(createFontConfigPatternForCharacters(characters, length));
125 const FontPlatformData& fontData = font.primaryFont()->platformData();
127 RefPtr<FcPattern> fallbackPattern = adoptRef(findBestFontGivenFallbacks(fontData, pattern.get()));
128 if (fallbackPattern) {
129 FontPlatformData alternateFontData(fallbackPattern.get(), font.fontDescription());
130 return getCachedFontData(&alternateFontData, DoNotRetain);
133 FcResult fontConfigResult;
134 RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(0, pattern.get(), &fontConfigResult));
137 FontPlatformData alternateFontData(resultPattern.get(), font.fontDescription());
138 return getCachedFontData(&alternateFontData, DoNotRetain);
141 SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
146 SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription, ShouldRetain shouldRetain)
148 // We want to return a fallback font here, otherwise the logic preventing FontConfig
149 // matches for non-fallback fonts might return 0. See isFallbackFontAllowed.
150 static AtomicString timesStr("serif");
151 return getCachedFontData(fontDescription, timesStr, false, shouldRetain);
154 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
158 static String getFamilyNameStringFromFontDescriptionAndFamily(const FontDescription& fontDescription, const AtomicString& family)
160 // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into
161 // the fallback name (like "monospace") that fontconfig understands.
162 if (family.length() && !family.startsWith("-webkit-"))
163 return family.string();
165 switch (fontDescription.genericFamily()) {
166 case FontDescription::StandardFamily:
167 case FontDescription::SerifFamily:
169 case FontDescription::SansSerifFamily:
171 case FontDescription::MonospaceFamily:
173 case FontDescription::CursiveFamily:
175 case FontDescription::FantasyFamily:
177 case FontDescription::NoFamily:
183 int fontWeightToFontconfigWeight(FontWeight weight)
187 return FC_WEIGHT_THIN;
189 return FC_WEIGHT_ULTRALIGHT;
191 return FC_WEIGHT_LIGHT;
193 return FC_WEIGHT_REGULAR;
195 return FC_WEIGHT_MEDIUM;
197 return FC_WEIGHT_SEMIBOLD;
199 return FC_WEIGHT_BOLD;
201 return FC_WEIGHT_EXTRABOLD;
203 return FC_WEIGHT_ULTRABLACK;
205 ASSERT_NOT_REACHED();
206 return FC_WEIGHT_REGULAR;
210 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
212 // The CSS font matching algorithm (http://www.w3.org/TR/css3-fonts/#font-matching-algorithm)
213 // says that we must find an exact match for font family, slant (italic or oblique can be used)
214 // and font weight (we only match bold/non-bold here).
215 RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
216 String familyNameString(getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family));
217 if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.utf8().data())))
220 bool italic = fontDescription.italic();
221 if (!FcPatternAddInteger(pattern.get(), FC_SLANT, italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN))
223 if (!FcPatternAddInteger(pattern.get(), FC_WEIGHT, fontWeightToFontconfigWeight(fontDescription.weight())))
225 if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize()))
228 // The strategy is originally from Skia (src/ports/SkFontHost_fontconfig.cpp):
230 // Allow Fontconfig to do pre-match substitution. Unless we are accessing a "fallback"
231 // family like "sans," this is the only time we allow Fontconfig to substitute one
232 // family name for another (i.e. if the fonts are aliased to each other).
233 FcConfigSubstitute(0, pattern.get(), FcMatchPattern);
234 FcDefaultSubstitute(pattern.get());
236 FcChar8* fontConfigFamilyNameAfterConfiguration;
237 FcPatternGetString(pattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration);
238 String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration));
240 FcResult fontConfigResult;
241 RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(0, pattern.get(), &fontConfigResult));
242 if (!resultPattern) // No match.
245 FcChar8* fontConfigFamilyNameAfterMatching;
246 FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching);
247 String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching));
249 // If Fontconfig gave use a different font family than the one we requested, we should ignore it
250 // and allow WebCore to give us the next font on the CSS fallback list. The only exception is if
251 // this family name is a commonly used generic family.
252 if (!equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching)
253 && !(equalIgnoringCase(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif")
254 || equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace")
255 || equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive")))
258 // Verify that this font has an encoding compatible with Fontconfig. Fontconfig currently
259 // supports three encodings in FcFreeTypeCharIndex: Unicode, Symbol and AppleRoman.
260 // If this font doesn't have one of these three encodings, don't select it.
261 FontPlatformData* platformData = new FontPlatformData(resultPattern.get(), fontDescription);
262 if (!platformData->hasCompatibleCharmap()) {