Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(266)

Side by Side Diff: skia/ports/SkFontHost_fontconfig.cpp

Issue 113827: Remove the remainder of the skia source code from the Chromium repo.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « skia/ports/SkFontHost_ascender.cpp ('k') | skia/ports/SkFontHost_gamma.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* libs/graphics/ports/SkFontHost_fontconfig.cpp
2 **
3 ** Copyright 2008, Google Inc.
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 // -----------------------------------------------------------------------------
19 // This file provides implementations of the font resolution members of
20 // SkFontHost by using the fontconfig[1] library. Fontconfig is usually found
21 // on Linux systems and handles configuration, parsing and caching issues
22 // involved with enumerating and matching fonts.
23 //
24 // [1] http://fontconfig.org
25 // -----------------------------------------------------------------------------
26
27 #include <map>
28 #include <string>
29
30 #include <fontconfig/fontconfig.h>
31
32 #include "SkDescriptor.h"
33 #include "SkFontHost.h"
34 #include "SkMMapStream.h"
35 #include "SkPaint.h"
36 #include "SkStream.h"
37 #include "SkString.h"
38 #include "SkThread.h"
39 #include "SkTSearch.h"
40
41 // This is an extern from SkFontHost_FreeType
42 SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);
43
44 // -----------------------------------------------------------------------------
45 // The rest of Skia requires that fonts be identified by a unique unsigned id
46 // and that we be able to load them given the id. What we actually get from
47 // fontconfig is the filename of the font so we keep a locked map from
48 // filenames to fileid numbers and back.
49 //
50 // Note that there's also a unique id in the SkTypeface. This is unique over
51 // both filename and style. Thus we encode that id as (fileid << 8) | style.
52 // Although truetype fonts can support multiple faces in a single file, at the
53 // moment Skia doesn't.
54 // -----------------------------------------------------------------------------
55 static SkMutex global_fc_map_lock;
56 static std::map<std::string, unsigned> global_fc_map;
57 static std::map<unsigned, std::string> global_fc_map_inverted;
58 static std::map<uint32_t, SkTypeface *> global_fc_typefaces;
59 static unsigned global_fc_map_next_id = 0;
60
61 // This is the maximum size of the font cache.
62 static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB
63
64 static unsigned UniqueIdToFileId(unsigned uniqueid)
65 {
66 return uniqueid >> 8;
67 }
68
69 static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid)
70 {
71 return static_cast<SkTypeface::Style>(uniqueid & 0xff);
72 }
73
74 static unsigned FileIdAndStyleToUniqueId(unsigned fileid,
75 SkTypeface::Style style)
76 {
77 SkASSERT(style & 0xff == style);
78 return (fileid << 8) | static_cast<int>(style);
79 }
80
81 class FontConfigTypeface : public SkTypeface {
82 public:
83 FontConfigTypeface(Style style, uint32_t id)
84 : SkTypeface(style, id)
85 { }
86 };
87
88 // -----------------------------------------------------------------------------
89 // Find a matching font where @type (one of FC_*) is equal to @value. For a
90 // list of types, see http://fontconfig.org/fontconfig-devel/x19.html#AEN27.
91 // The variable arguments are a list of triples, just like the first three
92 // arguments, and must be NULL terminated.
93 //
94 // For example, FontMatchString(FC_FILE, FcTypeString,
95 // "/usr/share/fonts/myfont.ttf", NULL);
96 // -----------------------------------------------------------------------------
97 static FcPattern* FontMatch(bool is_fallback,
98 const char* type, FcType vtype, const void* value,
99 ...)
100 {
101 va_list ap;
102 va_start(ap, value);
103
104 FcPattern* pattern = FcPatternCreate();
105 bool family_requested = false;
106
107 for (;;) {
108 FcValue fcvalue;
109 fcvalue.type = vtype;
110 switch (vtype) {
111 case FcTypeString:
112 fcvalue.u.s = (FcChar8*) value;
113 break;
114 case FcTypeInteger:
115 fcvalue.u.i = (int) value;
116 break;
117 default:
118 SkASSERT(!"FontMatch unhandled type");
119 }
120 FcPatternAdd(pattern, type, fcvalue, 0);
121
122 if (vtype == FcTypeString && strcmp(type, FC_FAMILY) == 0)
123 family_requested = true;
124
125 type = va_arg(ap, const char *);
126 if (!type)
127 break;
128 // FcType is promoted to int when passed through ...
129 vtype = static_cast<FcType>(va_arg(ap, int));
130 value = va_arg(ap, const void *);
131 };
132 va_end(ap);
133
134 FcConfigSubstitute(0, pattern, FcMatchPattern);
135 FcDefaultSubstitute(pattern);
136
137 // Font matching:
138 // CSS often specifies a fallback list of families:
139 // font-family: a, b, c, serif;
140 // However, fontconfig will always do its best to find *a* font when asked
141 // for something so we need a way to tell if the match which it has found is
142 // "good enough" for us. Otherwise, we can return NULL which gets piped up
143 // and lets WebKit know to try the next CSS family name. However, fontconfig
144 // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
145 // wish to support that.
146 //
147 // Thus, if a specific family is requested we set @family_requested. Then we
148 // record two strings: the family name after config processing and the
149 // family name after resolving. If the two are equal, it's a good match.
150 //
151 // So consider the case where a user has mapped Arial to Helvetica in their
152 // config.
153 // requested family: "Arial"
154 // post_config_family: "Helvetica"
155 // post_match_family: "Helvetica"
156 // -> good match
157 //
158 // and for a missing font:
159 // requested family: "Monaco"
160 // post_config_family: "Monaco"
161 // post_match_family: "Times New Roman"
162 // -> BAD match
163 FcChar8* post_config_family;
164 FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family);
165
166 FcResult result;
167 FcPattern* match = FcFontMatch(0, pattern, &result);
168 if (!match) {
169 FcPatternDestroy(pattern);
170 return NULL;
171 }
172
173 FcChar8* post_match_family;
174 FcPatternGetString(match, FC_FAMILY, 0, &post_match_family);
175 const bool family_names_match =
176 !family_requested ?
177 true :
178 strcasecmp((char *) post_config_family, (char *) post_match_family) == 0 ;
179
180 FcPatternDestroy(pattern);
181
182 if (!family_names_match && !is_fallback) {
183 FcPatternDestroy(match);
184 return NULL;
185 }
186
187 return match;
188 }
189
190 // -----------------------------------------------------------------------------
191 // Check to see if the filename has already been assigned a fileid and, if so,
192 // use it. Otherwise, assign one. Return the resulting fileid.
193 // -----------------------------------------------------------------------------
194 static unsigned FileIdFromFilename(const char* filename)
195 {
196 SkAutoMutexAcquire ac(global_fc_map_lock);
197
198 std::map<std::string, unsigned>::const_iterator i =
199 global_fc_map.find(filename);
200 if (i == global_fc_map.end()) {
201 const unsigned fileid = global_fc_map_next_id++;
202 global_fc_map[filename] = fileid;
203 global_fc_map_inverted[fileid] = filename;
204 return fileid;
205 } else {
206 return i->second;
207 }
208 }
209
210 SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace,
211 const char familyName[],
212 SkTypeface::Style style)
213 {
214 const char* resolved_family_name = NULL;
215 FcPattern* face_match = NULL;
216
217 if (familyFace) {
218 // Here we use the inverted global id map to find the filename from the
219 // SkTypeface object. Given the filename we can ask fontconfig for the
220 // familyname of the font.
221 SkAutoMutexAcquire ac(global_fc_map_lock);
222
223 const unsigned fileid = UniqueIdToFileId(familyFace->uniqueID());
224 std::map<unsigned, std::string>::const_iterator i =
225 global_fc_map_inverted.find(fileid);
226 if (i == global_fc_map_inverted.end())
227 return NULL;
228
229 FcInit();
230 face_match = FontMatch(false, FC_FILE, FcTypeString, i->second.c_str(),
231 NULL);
232
233 if (!face_match)
234 return NULL;
235 FcChar8* family;
236 if (FcPatternGetString(face_match, FC_FAMILY, 0, &family)) {
237 FcPatternDestroy(face_match);
238 return NULL;
239 }
240 // At this point, @family is pointing into the @face_match object so we
241 // cannot release it yet.
242
243 resolved_family_name = reinterpret_cast<char*>(family);
244 } else if (familyName) {
245 resolved_family_name = familyName;
246 } else {
247 return NULL;
248 }
249
250 {
251 SkAutoMutexAcquire ac(global_fc_map_lock);
252 FcInit();
253 }
254
255 // At this point, we have a resolved_family_name from somewhere
256 SkASSERT(resolved_family_name);
257
258 const int bold = style & SkTypeface::kBold ?
259 FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL;
260 const int italic = style & SkTypeface::kItalic ?
261 FC_SLANT_ITALIC : FC_SLANT_ROMAN;
262 FcPattern* match = FontMatch(false,
263 FC_FAMILY, FcTypeString, resolved_family_name,
264 FC_WEIGHT, FcTypeInteger, bold,
265 FC_SLANT, FcTypeInteger, italic,
266 NULL);
267 if (face_match)
268 FcPatternDestroy(face_match);
269
270 if (!match)
271 return NULL;
272
273 FcChar8* filename;
274 if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
275 FcPatternDestroy(match);
276 return NULL;
277 }
278 // Now @filename is pointing into @match
279
280 const unsigned fileid = FileIdFromFilename(reinterpret_cast<char*>(filename) );
281 const unsigned id = FileIdAndStyleToUniqueId(fileid, style);
282 SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id));
283 FcPatternDestroy(match);
284
285 {
286 SkAutoMutexAcquire ac(global_fc_map_lock);
287 global_fc_typefaces[id] = typeface;
288 }
289
290 return typeface;
291 }
292
293 SkTypeface* SkFontHost::ResolveTypeface(uint32_t id)
294 {
295 SkAutoMutexAcquire ac(global_fc_map_lock);
296 const std::map<uint32_t, SkTypeface *>::iterator
297 i = global_fc_typefaces.find(id);
298
299 if (i == global_fc_typefaces.end())
300 return NULL;
301 return i->second;
302 }
303
304 SkStream* SkFontHost::OpenStream(uint32_t id)
305 {
306 SkAutoMutexAcquire ac(global_fc_map_lock);
307 const unsigned fileid = UniqueIdToFileId(id);
308
309 std::map<unsigned, std::string>::const_iterator i =
310 global_fc_map_inverted.find(fileid);
311 if (i == global_fc_map_inverted.end())
312 return NULL;
313
314 return SkNEW_ARGS(SkFILEStream, (i->second.c_str()));
315 }
316
317 void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream)
318 {
319 }
320
321 SkTypeface* SkFontHost::CreateTypeface(SkStream* stream)
322 {
323 SkASSERT(!"SkFontHost::CreateTypeface unimplemented");
324 return NULL;
325 }
326
327 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
328 SkASSERT(!"SkFontHost::Deserialize unimplemented");
329 return NULL;
330 }
331
332 void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
333 SkASSERT(!"SkFontHost::Serialize unimplemented");
334 }
335
336 SkScalerContext* SkFontHost::CreateFallbackScalerContext
337 (const SkScalerContext::Rec& rec) {
338 FcPattern* match = FontMatch(true, FC_FAMILY, FcTypeString, "serif",
339 NULL);
340
341 // This will fail when we have no fonts on the system.
342 SkASSERT(match);
343
344 FcChar8* filename;
345 if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
346 FcPatternDestroy(match);
347 return NULL;
348 }
349 // Now @filename is pointing into @match
350
351 const unsigned id = FileIdFromFilename(reinterpret_cast<char*>(filename));
352 FcPatternDestroy(match);
353
354 SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
355 SkDescriptor* desc = ad.getDesc();
356
357 desc->init();
358 SkScalerContext::Rec* newRec =
359 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
360 sizeof(rec), &rec);
361 newRec->fFontID = id;
362 desc->computeChecksum();
363
364 return SkFontHost::CreateScalerContext(desc);
365 }
366
367 ///////////////////////////////////////////////////////////////////////////////
368
369 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar)
370 {
371 if (sizeAllocatedSoFar > kFontCacheMemoryBudget)
372 return sizeAllocatedSoFar - kFontCacheMemoryBudget;
373 else
374 return 0; // nothing to do
375 }
OLDNEW
« no previous file with comments | « skia/ports/SkFontHost_ascender.cpp ('k') | skia/ports/SkFontHost_gamma.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698