[WK2] Small Caps font variant issue for Italic fonts
[framework/web/webkit-efl.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 "Font.h"
26 #include "OwnPtrCairo.h"
27 #include "RefPtrCairo.h"
28 #include "SimpleFontData.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 #if ENABLE(TIZEN_WEBKIT_OWN_FONT_FILES)
36 #define APP_FONT_DIR "/usr/share/app_fonts"
37 #endif
38
39 namespace WebCore {
40
41 void FontCache::platformInit()
42 {
43 #if ENABLE(TIZEN_WEBKIT_OWN_FONT_FILES)
44     FcConfig *fc_config;
45     fc_config = FcConfigGetCurrent();
46     FcConfigAppFontAddDir(fc_config, (FcChar8*)APP_FONT_DIR);
47     FcConfigSetCurrent(fc_config);
48 #endif
49     // It's fine to call FcInit multiple times per the documentation.
50     if (!FcInit())
51         ASSERT_NOT_REACHED();
52 }
53
54 FcPattern* createFontConfigPatternForCharacters(const UChar* characters, int length)
55 {
56     FcPattern* pattern = FcPatternCreate();
57
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]));
63             i++;
64         } else
65             FcCharSetAddChar(fontConfigCharSet, characters[i]);
66     }
67     FcPatternAddCharSet(pattern, FC_CHARSET, fontConfigCharSet);
68     FcCharSetDestroy(fontConfigCharSet);
69
70     FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
71     FcConfigSubstitute(0, pattern, FcMatchPattern);
72     FcDefaultSubstitute(pattern);
73     return pattern;
74 }
75
76 #if ENABLE(TIZEN_USER_SETTING_FONT)
77 PassRefPtr<FcPattern> createTizenPattern()
78 {
79     RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
80     if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>("Tizen")))
81         return 0;
82
83     FcConfigSubstitute(0, pattern.get(), FcMatchPattern);
84     FcDefaultSubstitute(pattern.get());
85     return pattern.release();
86 }
87 #endif
88
89 FcPattern* findBestFontGivenFallbacks(const FontPlatformData& fontData, FcPattern* pattern)
90 {
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();
94
95     FcResult fallbackFontConfigResult;
96     if (!fontData.m_fallbacks)
97         fontData.m_fallbacks = FcFontSort(0, settingsPattern.get(), FcTrue, 0, &fallbackFontConfigResult);
98
99     if (!fontData.m_fallbacks)
100         return 0;
101
102     FcFontSet* fcSets[] = { fontData.m_fallbacks };
103     return FcFontSetMatch(0, fcSets, 1, pattern, &fallbackFontConfigResult);
104 #else
105     if (!fontData.m_pattern)
106         return 0;
107
108     if (!fontData.m_fallbacks) {
109         FcResult fontConfigResult;
110         fontData.m_fallbacks = FcFontSort(0, fontData.m_pattern.get(), FcTrue, 0, &fontConfigResult);
111     }
112
113     if (!fontData.m_fallbacks)
114         return 0;
115
116     FcFontSet* sets[] = { fontData.m_fallbacks };
117     FcResult fontConfigResult;
118     return FcFontSetMatch(0, sets, 1, pattern, &fontConfigResult);
119 #endif
120 }
121
122 const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
123 {
124     RefPtr<FcPattern> pattern = adoptRef(createFontConfigPatternForCharacters(characters, length));
125     const FontPlatformData& fontData = font.primaryFont()->platformData();
126
127     RefPtr<FcPattern> fallbackPattern = adoptRef(findBestFontGivenFallbacks(fontData, pattern.get()));
128     if (fallbackPattern) {
129         FontPlatformData alternateFontData(fallbackPattern.get(), font.fontDescription());
130         return getCachedFontData(&alternateFontData, DoNotRetain);
131     }
132
133     FcResult fontConfigResult;
134     RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(0, pattern.get(), &fontConfigResult));
135     if (!resultPattern)
136         return 0;
137     FontPlatformData alternateFontData(resultPattern.get(), font.fontDescription());
138     return getCachedFontData(&alternateFontData, DoNotRetain);
139 }
140
141 SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
142 {
143     return 0;
144 }
145
146 SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription, ShouldRetain shouldRetain)
147 {
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);
152 }
153
154 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
155 {
156 }
157
158 static String getFamilyNameStringFromFontDescriptionAndFamily(const FontDescription& fontDescription, const AtomicString& family)
159 {
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();
164
165     switch (fontDescription.genericFamily()) {
166     case FontDescription::StandardFamily:
167     case FontDescription::SerifFamily:
168         return "serif";
169     case FontDescription::SansSerifFamily:
170         return "sans-serif";
171     case FontDescription::MonospaceFamily:
172         return "monospace";
173     case FontDescription::CursiveFamily:
174         return "cursive";
175     case FontDescription::FantasyFamily:
176         return "fantasy";
177     case FontDescription::NoFamily:
178     default:
179         return "";
180     }
181 }
182
183 int fontWeightToFontconfigWeight(FontWeight weight)
184 {
185     switch (weight) {
186     case FontWeight100:
187         return FC_WEIGHT_THIN;
188     case FontWeight200:
189         return FC_WEIGHT_ULTRALIGHT;
190     case FontWeight300:
191         return FC_WEIGHT_LIGHT;
192     case FontWeight400:
193         return FC_WEIGHT_REGULAR;
194     case FontWeight500:
195         return FC_WEIGHT_MEDIUM;
196     case FontWeight600:
197         return FC_WEIGHT_SEMIBOLD;
198     case FontWeight700:
199         return FC_WEIGHT_BOLD;
200     case FontWeight800:
201         return FC_WEIGHT_EXTRABOLD;
202     case FontWeight900:
203         return FC_WEIGHT_ULTRABLACK;
204     default:
205         ASSERT_NOT_REACHED();
206         return FC_WEIGHT_REGULAR;
207     }
208 }
209
210 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
211 {
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())))
218         return 0;
219
220     bool italic = fontDescription.italic();
221 #if ENABLE(TIZEN_FAKE_ITALIC_SMALLCAPS_COMBINATION)
222     bool smallCaps = fontDescription.smallCaps();
223     if (!FcPatternAddInteger(pattern.get(), FC_SLANT, (italic && !smallCaps) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN))
224         return 0;
225 #else
226     if (!FcPatternAddInteger(pattern.get(), FC_SLANT, italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN))
227         return 0;
228 #endif
229
230     if (!FcPatternAddInteger(pattern.get(), FC_WEIGHT, fontWeightToFontconfigWeight(fontDescription.weight())))
231         return 0;
232     if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize()))
233         return 0;
234
235     // The strategy is originally from Skia (src/ports/SkFontHost_fontconfig.cpp):
236
237     // Allow Fontconfig to do pre-match substitution. Unless we are accessing a "fallback"
238     // family like "sans," this is the only time we allow Fontconfig to substitute one
239     // family name for another (i.e. if the fonts are aliased to each other).
240     FcConfigSubstitute(0, pattern.get(), FcMatchPattern);
241     FcDefaultSubstitute(pattern.get());
242
243     FcChar8* fontConfigFamilyNameAfterConfiguration;
244     FcPatternGetString(pattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration);
245     String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration));
246
247     FcResult fontConfigResult;
248     RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(0, pattern.get(), &fontConfigResult));
249     if (!resultPattern) // No match.
250         return 0;
251
252     FcChar8* fontConfigFamilyNameAfterMatching;
253     FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching);
254     String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching));
255
256     // If Fontconfig gave use a different font family than the one we requested, we should ignore it
257     // and allow WebCore to give us the next font on the CSS fallback list. The only exception is if
258     // this family name is a commonly used generic family.
259     if (!equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching)
260         && !(equalIgnoringCase(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif")
261           || equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace")
262           || equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive")))
263         return 0;
264
265     // Verify that this font has an encoding compatible with Fontconfig. Fontconfig currently
266     // supports three encodings in FcFreeTypeCharIndex: Unicode, Symbol and AppleRoman.
267     // If this font doesn't have one of these three encodings, don't select it.
268     FontPlatformData* platformData = new FontPlatformData(resultPattern.get(), fontDescription);
269     if (!platformData->hasCompatibleCharmap()) {
270         delete platformData;
271         return 0;
272     }
273
274     return platformData;
275 }
276
277 }