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