• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2008 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 <map>
9 #include <string>
10 
11 #include <fontconfig/fontconfig.h>
12 
13 #include "SkFontHost.h"
14 #include "SkStream.h"
15 
16 /** An extern from SkFontHost_FreeType. */
17 SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);
18 
19 /** This lock must be held while modifying global_fc_* globals. */
20 SK_DECLARE_STATIC_MUTEX(global_fc_map_lock);
21 
22 /** Map from file names to file ids. */
23 static std::map<std::string, unsigned> global_fc_map;
24 /** Map from file ids to file names. */
25 static std::map<unsigned, std::string> global_fc_map_inverted;
26 /** The next file id. */
27 static unsigned global_fc_map_next_id = 0;
28 
29 /**
30  * Check to see if the filename has already been assigned a fileid and, if so, use it.
31  * Otherwise, assign one. Return the resulting fileid.
32  */
FileIdFromFilename(const char * filename)33 static unsigned FileIdFromFilename(const char* filename) {
34     SkAutoMutexAcquire ac(global_fc_map_lock);
35 
36     std::map<std::string, unsigned>::const_iterator i = global_fc_map.find(filename);
37     if (i == global_fc_map.end()) {
38         const unsigned fileid = global_fc_map_next_id++;
39         global_fc_map[filename] = fileid;
40         global_fc_map_inverted[fileid] = filename;
41         return fileid;
42     } else {
43         return i->second;
44     }
45 }
46 
FileIdFromUniqueId(unsigned uniqueid)47 static unsigned FileIdFromUniqueId(unsigned uniqueid) {
48     return uniqueid >> 8;
49 }
50 
StyleFromUniqueId(unsigned uniqueid)51 static SkTypeface::Style StyleFromUniqueId(unsigned uniqueid) {
52     return static_cast<SkTypeface::Style>(uniqueid & 0xff);
53 }
54 
UniqueIdFromFileIdAndStyle(unsigned fileid,SkTypeface::Style style)55 static unsigned UniqueIdFromFileIdAndStyle(unsigned fileid, SkTypeface::Style style) {
56     SkASSERT((style & 0xff) == style);
57     return (fileid << 8) | static_cast<int>(style);
58 }
59 
60 class FontConfigTypeface : public SkTypeface {
61 public:
FontConfigTypeface(Style style,uint32_t id)62     FontConfigTypeface(Style style, uint32_t id) : SkTypeface(style, id) { }
63 };
64 
65 /**
66  * Find a matching font where @type (one of FC_*) is equal to @value. For a
67  * list of types, see http://fontconfig.org/fontconfig-devel/x19.html#AEN27.
68  * The variable arguments are a list of triples, just like the first three
69  * arguments, and must be NULL terminated.
70  *
71  * For example,
72  *   FontMatchString(FC_FILE, FcTypeString, "/usr/share/fonts/myfont.ttf", NULL);
73  */
FontMatch(const char * type,FcType vtype,const void * value,...)74 static FcPattern* FontMatch(const char* type, FcType vtype, const void* value, ...) {
75     va_list ap;
76     va_start(ap, value);
77 
78     FcPattern* pattern = FcPatternCreate();
79 
80     for (;;) {
81         FcValue fcvalue;
82         fcvalue.type = vtype;
83         switch (vtype) {
84             case FcTypeString:
85                 fcvalue.u.s = (FcChar8*) value;
86                 break;
87             case FcTypeInteger:
88                 fcvalue.u.i = (int)(intptr_t)value;
89                 break;
90             default:
91                 SkDEBUGFAIL("FontMatch unhandled type");
92         }
93         FcPatternAdd(pattern, type, fcvalue, FcFalse);
94 
95         type = va_arg(ap, const char *);
96         if (!type)
97             break;
98         // FcType is promoted to int when passed through ...
99         vtype = static_cast<FcType>(va_arg(ap, int));
100         value = va_arg(ap, const void *);
101     };
102     va_end(ap);
103 
104     FcConfigSubstitute(NULL, pattern, FcMatchPattern);
105     FcDefaultSubstitute(pattern);
106 
107     FcResult result;
108     FcPattern* match = FcFontMatch(NULL, pattern, &result);
109     FcPatternDestroy(pattern);
110 
111     return match;
112 }
113 
114 // static
CreateTypeface(const SkTypeface * familyFace,const char familyName[],SkTypeface::Style style)115 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
116                                        const char familyName[],
117                                        SkTypeface::Style style)
118 {
119     const char* resolved_family_name = NULL;
120     FcPattern* face_match = NULL;
121 
122     {
123         SkAutoMutexAcquire ac(global_fc_map_lock);
124         if (FcTrue != FcInit()) {
125             SkASSERT(false && "Could not initialize fontconfig.");
126         }
127     }
128 
129     if (familyFace) {
130         // Here we use the inverted global id map to find the filename from the
131         // SkTypeface object. Given the filename we can ask fontconfig for the
132         // familyname of the font.
133         SkAutoMutexAcquire ac(global_fc_map_lock);
134 
135         const unsigned fileid = FileIdFromUniqueId(familyFace->uniqueID());
136         std::map<unsigned, std::string>::const_iterator i = global_fc_map_inverted.find(fileid);
137         if (i == global_fc_map_inverted.end()) {
138             return NULL;
139         }
140 
141         face_match = FontMatch(FC_FILE, FcTypeString, i->second.c_str(), NULL);
142         if (!face_match) {
143             return NULL;
144         }
145 
146         FcChar8* family;
147         if (FcPatternGetString(face_match, FC_FAMILY, 0, &family)) {
148             FcPatternDestroy(face_match);
149             return NULL;
150         }
151         // At this point, @family is pointing into the @face_match object so we
152         // cannot release it yet.
153 
154         resolved_family_name = reinterpret_cast<char*>(family);
155     } else if (familyName) {
156         resolved_family_name = familyName;
157     }
158 
159     const int bold = (style & SkTypeface::kBold) ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL;
160     const int italic = (style & SkTypeface::kItalic) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
161 
162     FcPattern* match;
163     if (resolved_family_name) {
164         match = FontMatch(FC_FAMILY, FcTypeString, resolved_family_name,
165                           FC_WEIGHT, FcTypeInteger, bold,
166                           FC_SLANT, FcTypeInteger, italic,
167                           NULL);
168     } else {
169         match = FontMatch(FC_WEIGHT, FcTypeInteger, reinterpret_cast<void*>(bold),
170                           FC_SLANT, FcTypeInteger, italic,
171                           NULL);
172     }
173 
174     if (face_match)
175         FcPatternDestroy(face_match);
176 
177     if (!match)
178         return NULL;
179 
180     FcChar8* filename;
181     if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) {
182         FcPatternDestroy(match);
183         return NULL;
184     }
185     // Now @filename is pointing into @match
186 
187     const unsigned fileid = FileIdFromFilename(reinterpret_cast<char*>(filename));
188     const unsigned id = UniqueIdFromFileIdAndStyle(fileid, style);
189     SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id));
190     FcPatternDestroy(match);
191 
192     return typeface;
193 }
194 
195 // static
CreateTypefaceFromStream(SkStream * stream)196 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
197     SkDEBUGFAIL("SkFontHost::CreateTypefaceFromStream unimplemented");
198     return NULL;
199 }
200 
201 // static
CreateTypefaceFromFile(const char path[])202 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
203     SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
204     return NULL;
205 }
206 
207 // static
OpenStream(uint32_t id)208 SkStream* SkFontHost::OpenStream(uint32_t id) {
209     SkAutoMutexAcquire ac(global_fc_map_lock);
210     const unsigned fileid = FileIdFromUniqueId(id);
211 
212     std::map<unsigned, std::string>::const_iterator i = global_fc_map_inverted.find(fileid);
213     if (i == global_fc_map_inverted.end()) {
214         return NULL;
215     }
216 
217     return SkNEW_ARGS(SkFILEStream, (i->second.c_str()));
218 }
219 
GetFileName(SkFontID fontID,char path[],size_t length,int32_t * index)220 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, int32_t* index) {
221     SkAutoMutexAcquire ac(global_fc_map_lock);
222     const unsigned fileid = FileIdFromUniqueId(fontID);
223 
224     std::map<unsigned, std::string>::const_iterator i = global_fc_map_inverted.find(fileid);
225     if (i == global_fc_map_inverted.end()) {
226         return 0;
227     }
228 
229     const std::string& str = i->second;
230     if (path) {
231         memcpy(path, str.c_str(), SkMin32(str.size(), length));
232     }
233     if (index) {    // TODO: check if we're in a TTC
234         *index = 0;
235     }
236     return str.size();
237 }
238 
Serialize(const SkTypeface *,SkWStream *)239 void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
240     SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
241 }
242 
Deserialize(SkStream * stream)243 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
244     SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
245     return NULL;
246 }
247 
NextLogicalFont(SkFontID currFontID,SkFontID origFontID)248 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
249     // We don't handle font fallback, WebKit does.
250     return 0;
251 }
252