C++11 override should now be supported by all of {bots,Chrome,Android,Mozilla}
[platform/upstream/libSkiaSharp.git] / src / fonts / SkFontMgr_fontconfig.cpp
1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "SkFontMgr.h"
9 #include "SkFontStyle.h"
10 #include "SkFontConfigInterface.h"
11 #include "SkFontConfigTypeface.h"
12 #include "SkMath.h"
13 #include "SkString.h"
14 #include "SkTDArray.h"
15 #include "SkThread.h"
16
17 // for now we pull these in directly. eventually we will solely rely on the
18 // SkFontConfigInterface instance.
19 #include <fontconfig/fontconfig.h>
20 #include <unistd.h>
21
22 namespace {
23
24 // Fontconfig is not threadsafe before 2.10.91.  Before that, we lock with a global mutex.
25 // See skia:1497 for background.
26 SK_DECLARE_STATIC_MUTEX(gFCMutex);
27 static bool gFCSafeToUse;
28
29 struct FCLocker {
30     FCLocker() {
31         if (FcGetVersion() < 21091) {  // We assume FcGetVersion() has always been thread safe.
32             gFCMutex.acquire();
33             fUnlock = true;
34         } else {
35             fUnlock = false;
36         }
37         gFCSafeToUse = true;
38     }
39
40     ~FCLocker() {
41         if (fUnlock) {
42             gFCSafeToUse = false;
43             gFCMutex.release();
44         }
45     }
46
47 private:
48     bool fUnlock;
49 };
50
51 } // namespace
52
53 // borrow this global from SkFontHost_fontconfig. eventually that file should
54 // go away, and be replaced with this one.
55 extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global();
56 static SkFontConfigInterface* RefFCI() {
57     return SkFontHost_fontconfig_ref_global();
58 }
59
60 // look for the last substring after a '/' and return that, or return null.
61 static const char* find_just_name(const char* str) {
62     const char* last = strrchr(str, '/');
63     return last ? last + 1 : NULL;
64 }
65
66 static bool is_lower(char c) {
67     return c >= 'a' && c <= 'z';
68 }
69
70 static int get_int(FcPattern* pattern, const char field[]) {
71     SkASSERT(gFCSafeToUse);
72     int value;
73     if (FcPatternGetInteger(pattern, field, 0, &value) != FcResultMatch) {
74         value = SK_MinS32;
75     }
76     return value;
77 }
78
79 static const char* get_name(FcPattern* pattern, const char field[]) {
80     SkASSERT(gFCSafeToUse);
81     const char* name;
82     if (FcPatternGetString(pattern, field, 0, (FcChar8**)&name) != FcResultMatch) {
83         name = "";
84     }
85     return name;
86 }
87
88 static bool valid_pattern(FcPattern* pattern) {
89     SkASSERT(gFCSafeToUse);
90     FcBool is_scalable;
91     if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch || !is_scalable) {
92         return false;
93     }
94
95     // fontconfig can also return fonts which are unreadable
96     const char* c_filename = get_name(pattern, FC_FILE);
97     if (0 == *c_filename) {
98         return false;
99     }
100     if (access(c_filename, R_OK) != 0) {
101         return false;
102     }
103     return true;
104 }
105
106 static bool match_name(FcPattern* pattern, const char family_name[]) {
107     return !strcasecmp(family_name, get_name(pattern, FC_FAMILY));
108 }
109
110 static FcPattern** MatchFont(FcFontSet* font_set,
111                              const char post_config_family[],
112                              int* count) {
113   // Older versions of fontconfig have a bug where they cannot select
114   // only scalable fonts so we have to manually filter the results.
115
116     FcPattern** iter = font_set->fonts;
117     FcPattern** stop = iter + font_set->nfont;
118     // find the first good match
119     for (; iter < stop; ++iter) {
120         if (valid_pattern(*iter)) {
121             break;
122         }
123     }
124
125     if (iter == stop || !match_name(*iter, post_config_family)) {
126         return NULL;
127     }
128
129     FcPattern** firstIter = iter++;
130     for (; iter < stop; ++iter) {
131         if (!valid_pattern(*iter) || !match_name(*iter, post_config_family)) {
132             break;
133         }
134     }
135
136     *count = iter - firstIter;
137     return firstIter;
138 }
139
140 class SkFontStyleSet_FC : public SkFontStyleSet {
141 public:
142     SkFontStyleSet_FC(FcPattern** matches, int count);
143     virtual ~SkFontStyleSet_FC();
144
145     int count() override { return fRecCount; }
146     void getStyle(int index, SkFontStyle*, SkString* style) override;
147     SkTypeface* createTypeface(int index) override;
148     SkTypeface* matchStyle(const SkFontStyle& pattern) override;
149
150 private:
151     struct Rec {
152         SkString    fStyleName;
153         SkString    fFileName;
154         SkFontStyle fStyle;
155     };
156     Rec* fRecs;
157     int  fRecCount;
158 };
159
160 static int map_range(int value,
161                      int old_min, int old_max, int new_min, int new_max) {
162     SkASSERT(old_min < old_max);
163     SkASSERT(new_min < new_max);
164     return new_min + SkMulDiv(value - old_min,
165                               new_max - new_min, old_max - old_min);
166 }
167
168 static SkFontStyle make_fontconfig_style(FcPattern* match) {
169     int weight = get_int(match, FC_WEIGHT);
170     int width = get_int(match, FC_WIDTH);
171     int slant = get_int(match, FC_SLANT);
172 //    SkDebugf("old weight %d new weight %d\n", weight, map_range(weight, 0, 80, 0, 400));
173
174     // fontconfig weight seems to be 0..200 or so, so we remap it here
175     weight = map_range(weight, 0, 80, 0, 400);
176     width = map_range(width, 0, 200, 0, 9);
177     return SkFontStyle(weight, width, slant > 0 ? SkFontStyle::kItalic_Slant
178                                                 : SkFontStyle::kUpright_Slant);
179 }
180
181 SkFontStyleSet_FC::SkFontStyleSet_FC(FcPattern** matches, int count) {
182     fRecCount = count;
183     fRecs = SkNEW_ARRAY(Rec, count);
184     for (int i = 0; i < count; ++i) {
185         fRecs[i].fStyleName.set(get_name(matches[i], FC_STYLE));
186         fRecs[i].fFileName.set(get_name(matches[i], FC_FILE));
187         fRecs[i].fStyle = make_fontconfig_style(matches[i]);
188     }
189 }
190
191 SkFontStyleSet_FC::~SkFontStyleSet_FC() {
192     SkDELETE_ARRAY(fRecs);
193 }
194
195 void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style,
196                                  SkString* styleName) {
197     SkASSERT((unsigned)index < (unsigned)fRecCount);
198     if (style) {
199         *style = fRecs[index].fStyle;
200     }
201     if (styleName) {
202         *styleName = fRecs[index].fStyleName;
203     }
204 }
205
206 SkTypeface* SkFontStyleSet_FC::createTypeface(int index) {
207     return NULL;
208 }
209
210 SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) {
211     return NULL;
212 }
213
214 class SkFontMgr_fontconfig : public SkFontMgr {
215     SkAutoTUnref<SkFontConfigInterface> fFCI;
216     SkDataTable* fFamilyNames;
217     SkTypeface_FreeType::Scanner fScanner;
218
219 public:
220     SkFontMgr_fontconfig(SkFontConfigInterface* fci)
221         : fFCI(fci)
222         , fFamilyNames(fFCI->getFamilyNames()) {}
223
224     virtual ~SkFontMgr_fontconfig() {
225         SkSafeUnref(fFamilyNames);
226     }
227
228 protected:
229     int onCountFamilies() const override {
230         return fFamilyNames->count();
231     }
232
233     void onGetFamilyName(int index, SkString* familyName) const override {
234         familyName->set(fFamilyNames->atStr(index));
235     }
236
237     SkFontStyleSet* onCreateStyleSet(int index) const override {
238         return this->onMatchFamily(fFamilyNames->atStr(index));
239     }
240
241     SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
242         FCLocker lock;
243
244         FcPattern* pattern = FcPatternCreate();
245
246         FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
247 #if 0
248         FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
249 #endif
250         FcConfigSubstitute(NULL, pattern, FcMatchPattern);
251         FcDefaultSubstitute(pattern);
252
253         const char* post_config_family = get_name(pattern, FC_FAMILY);
254
255         FcResult result;
256         FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
257         if (!font_set) {
258             FcPatternDestroy(pattern);
259             return NULL;
260         }
261
262         int count;
263         FcPattern** match = MatchFont(font_set, post_config_family, &count);
264         if (!match) {
265             FcPatternDestroy(pattern);
266             FcFontSetDestroy(font_set);
267             return NULL;
268         }
269
270         FcPatternDestroy(pattern);
271
272         SkTDArray<FcPattern*> trimmedMatches;
273         for (int i = 0; i < count; ++i) {
274             const char* justName = find_just_name(get_name(match[i], FC_FILE));
275             if (!is_lower(*justName)) {
276                 *trimmedMatches.append() = match[i];
277             }
278         }
279
280         SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC,
281                                              (trimmedMatches.begin(),
282                                               trimmedMatches.count()));
283         return sset;
284     }
285
286     virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
287                                            const SkFontStyle&) const override { return NULL; }
288     virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
289                                                     const char* bcp47[], int bcp47Count,
290                                                     SkUnichar character) const override {
291         return NULL;
292     }
293     virtual SkTypeface* onMatchFaceStyle(const SkTypeface*,
294                                          const SkFontStyle&) const override { return NULL; }
295
296     SkTypeface* onCreateFromData(SkData*, int ttcIndex) const override { return NULL; }
297
298     SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
299         SkAutoTDelete<SkStreamAsset> stream(bareStream);
300         const size_t length = stream->getLength();
301         if (!length) {
302             return NULL;
303         }
304         if (length >= 1024 * 1024 * 1024) {
305             return NULL;  // don't accept too large fonts (>= 1GB) for safety.
306         }
307
308         // TODO should the caller give us the style or should we get it from freetype?
309         SkFontStyle style;
310         bool isFixedWidth = false;
311         if (!fScanner.scanFont(stream, 0, NULL, &style, &isFixedWidth)) {
312             return NULL;
313         }
314
315         SkTypeface* face = FontConfigTypeface::Create(style, isFixedWidth, stream.detach());
316         return face;
317     }
318
319     SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
320         SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path));
321         return stream.get() ? this->createFromStream(stream.detach(), ttcIndex) : NULL;
322     }
323
324     virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
325                                                unsigned styleBits) const override {
326         FCLocker lock;
327         return FontConfigTypeface::LegacyCreateTypeface(familyName, (SkTypeface::Style)styleBits);
328     }
329 };
330
331 SkFontMgr* SkFontMgr::Factory() {
332     SkFontConfigInterface* fci = RefFCI();
333     return fci ? SkNEW_ARGS(SkFontMgr_fontconfig, (fci)) : NULL;
334 }