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 FcPattern* findBestFontGivenFallbacks(const FontPlatformData& fontData, FcPattern* pattern)
78 #if ENABLE(TIZEN_USER_SETTING_FONT)
79 //If we don't find glyphs for characters, we can use SLP fallback font that is selected by user in Setting
80 RefPtr<FcPattern> settingsPattern = adoptRef(FcPatternCreate());
81 String settingsFamilyNameString = "SLP";
83 if (!FcPatternAddString(settingsPattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(settingsFamilyNameString.utf8().data())))
86 FcConfigSubstitute(0, settingsPattern.get(), FcMatchPattern);
87 FcDefaultSubstitute(settingsPattern.get());
89 FcResult fallbackFontConfigResult;
90 FcFontSet* fallbacks = FcFontSort(0, settingsPattern.get(), FcTrue, 0, &fallbackFontConfigResult);
92 FcFontSet* fcSets[] = { fallbacks };
93 return FcFontSetMatch(0, fcSets, 1, pattern, &fallbackFontConfigResult);
96 if (!fontData.m_pattern)
99 if (!fontData.m_fallbacks) {
100 FcResult fontConfigResult;
101 fontData.m_fallbacks = FcFontSort(0, fontData.m_pattern.get(), FcTrue, 0, &fontConfigResult);
104 if (!fontData.m_fallbacks)
107 FcFontSet* sets[] = { fontData.m_fallbacks };
108 FcResult fontConfigResult;
109 return FcFontSetMatch(0, sets, 1, pattern, &fontConfigResult);
112 const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
114 RefPtr<FcPattern> pattern = adoptRef(createFontConfigPatternForCharacters(characters, length));
115 const FontPlatformData& fontData = font.primaryFont()->platformData();
117 RefPtr<FcPattern> fallbackPattern = adoptRef(findBestFontGivenFallbacks(fontData, pattern.get()));
118 if (fallbackPattern) {
119 FontPlatformData alternateFontData(fallbackPattern.get(), font.fontDescription());
120 return getCachedFontData(&alternateFontData, DoNotRetain);
123 FcResult fontConfigResult;
124 RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(0, pattern.get(), &fontConfigResult));
127 FontPlatformData alternateFontData(resultPattern.get(), font.fontDescription());
128 return getCachedFontData(&alternateFontData, DoNotRetain);
131 SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
136 SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription, ShouldRetain shouldRetain)
138 // We want to return a fallback font here, otherwise the logic preventing FontConfig
139 // matches for non-fallback fonts might return 0. See isFallbackFontAllowed.
140 static AtomicString timesStr("serif");
141 return getCachedFontData(fontDescription, timesStr, false, shouldRetain);
144 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
148 static String getFamilyNameStringFromFontDescriptionAndFamily(const FontDescription& fontDescription, const AtomicString& family)
150 // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into
151 // the fallback name (like "monospace") that fontconfig understands.
152 if (family.length() && !family.startsWith("-webkit-"))
153 return family.string();
155 switch (fontDescription.genericFamily()) {
156 case FontDescription::StandardFamily:
157 case FontDescription::SerifFamily:
159 case FontDescription::SansSerifFamily:
161 case FontDescription::MonospaceFamily:
163 case FontDescription::CursiveFamily:
165 case FontDescription::FantasyFamily:
167 case FontDescription::NoFamily:
173 int fontWeightToFontconfigWeight(FontWeight weight)
177 return FC_WEIGHT_THIN;
179 return FC_WEIGHT_ULTRALIGHT;
181 return FC_WEIGHT_LIGHT;
183 return FC_WEIGHT_REGULAR;
185 return FC_WEIGHT_MEDIUM;
187 return FC_WEIGHT_SEMIBOLD;
189 return FC_WEIGHT_BOLD;
191 return FC_WEIGHT_EXTRABOLD;
193 return FC_WEIGHT_ULTRABLACK;
195 ASSERT_NOT_REACHED();
196 return FC_WEIGHT_REGULAR;
200 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
202 // The CSS font matching algorithm (http://www.w3.org/TR/css3-fonts/#font-matching-algorithm)
203 // says that we must find an exact match for font family, slant (italic or oblique can be used)
204 // and font weight (we only match bold/non-bold here).
205 RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
206 String familyNameString(getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family));
207 if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.utf8().data())))
210 bool italic = fontDescription.italic();
211 if (!FcPatternAddInteger(pattern.get(), FC_SLANT, italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN))
213 if (!FcPatternAddInteger(pattern.get(), FC_WEIGHT, fontWeightToFontconfigWeight(fontDescription.weight())))
215 if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize()))
218 // The strategy is originally from Skia (src/ports/SkFontHost_fontconfig.cpp):
220 // Allow Fontconfig to do pre-match substitution. Unless we are accessing a "fallback"
221 // family like "sans," this is the only time we allow Fontconfig to substitute one
222 // family name for another (i.e. if the fonts are aliased to each other).
223 FcConfigSubstitute(0, pattern.get(), FcMatchPattern);
224 FcDefaultSubstitute(pattern.get());
226 FcChar8* fontConfigFamilyNameAfterConfiguration;
227 FcPatternGetString(pattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration);
228 String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration));
230 FcResult fontConfigResult;
231 RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(0, pattern.get(), &fontConfigResult));
232 if (!resultPattern) // No match.
235 FcChar8* fontConfigFamilyNameAfterMatching;
236 FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching);
237 String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching));
239 // If Fontconfig gave use a different font family than the one we requested, we should ignore it
240 // and allow WebCore to give us the next font on the CSS fallback list. The only exception is if
241 // this family name is a commonly used generic family.
242 if (!equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching)
243 && !(equalIgnoringCase(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif")
244 || equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace")
245 || equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive")))
248 // Verify that this font has an encoding compatible with Fontconfig. Fontconfig currently
249 // supports three encodings in FcFreeTypeCharIndex: Unicode, Symbol and AppleRoman.
250 // If this font doesn't have one of these three encodings, don't select it.
251 FontPlatformData* platformData = new FontPlatformData(resultPattern.get(), fontDescription);
252 if (!platformData->hasCompatibleCharmap()) {