OLD | NEW |
| (Empty) |
1 /* libs/graphics/ports/SkFontHost_android.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
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 #include "SkFontHost.h" | |
19 #include "SkDescriptor.h" | |
20 #include "SkString.h" | |
21 #include "SkStream.h" | |
22 #include <stdio.h> | |
23 | |
24 /* define this if we can use mmap() to access fonts from the filesystem */ | |
25 #define SK_CAN_USE_MMAP | |
26 | |
27 #ifndef SK_FONTPATH | |
28 #define SK_FONTPATH "the complete path for a font file" | |
29 #endif | |
30 | |
31 struct FontFaceRec { | |
32 const char* fFileName; | |
33 uint8_t fFamilyIndex; | |
34 SkBool8 fBold; | |
35 SkBool8 fItalic; | |
36 | |
37 static const FontFaceRec& FindFace(const FontFaceRec rec[], int count, int i
sBold, int isItalic); | |
38 }; | |
39 | |
40 struct FontFamilyRec { | |
41 const FontFaceRec* fFaces; | |
42 int fFaceCount; | |
43 }; | |
44 | |
45 const FontFaceRec& FontFaceRec::FindFace(const FontFaceRec rec[], int count, int
isBold, int isItalic) | |
46 { | |
47 SkASSERT(count > 0); | |
48 | |
49 int i; | |
50 | |
51 // look for an exact match | |
52 for (i = 0; i < count; i++) { | |
53 if (rec[i].fBold == isBold && rec[i].fItalic == isItalic) | |
54 return rec[i]; | |
55 } | |
56 // look for a match in the bold field | |
57 for (i = 0; i < count; i++) { | |
58 if (rec[i].fBold == isBold) | |
59 return rec[i]; | |
60 } | |
61 // look for a normal/regular face | |
62 for (i = 0; i < count; i++) { | |
63 if (!rec[i].fBold && !rec[i].fItalic) | |
64 return rec[i]; | |
65 } | |
66 // give up | |
67 return rec[0]; | |
68 } | |
69 | |
70 enum { | |
71 DEFAULT_FAMILY_INDEX, | |
72 | |
73 FAMILY_INDEX_COUNT | |
74 }; | |
75 | |
76 static const FontFaceRec gDefaultFaces[] = { | |
77 { SK_FONTPATH, DEFAULT_FAMILY_INDEX, 0, 0 } | |
78 }; | |
79 | |
80 // This table must be in the same order as the ..._FAMILY_INDEX enum specifies | |
81 static const FontFamilyRec gFamilies[] = { | |
82 { gDefaultFaces, SK_ARRAY_COUNT(gDefaultFaces) } | |
83 }; | |
84 | |
85 #define DEFAULT_FAMILY_INDEX DEFAULT_FAMILY_INDEX | |
86 #define DEFAULT_FAMILY_FACE_INDEX 0 | |
87 | |
88 ////////////////////////////////////////////////////////////////////////////////
//////// | |
89 | |
90 /* map common "web" font names to our font list */ | |
91 | |
92 struct FontFamilyMatchRec { | |
93 const char* fLCName; | |
94 int fFamilyIndex; | |
95 }; | |
96 | |
97 /* This is a table of synonyms for collapsing font names | |
98 down to their pseudo-equivalents (i.e. in terms of fonts | |
99 we actually have.) | |
100 Keep this sorted by the first field so we can do a binary search. | |
101 If this gets big, we could switch to a hash... | |
102 */ | |
103 static const FontFamilyMatchRec gMatches[] = { | |
104 #if 0 | |
105 { "Ahem", Ahem_FAMILY_INDEX }, | |
106 { "arial", SANS_FAMILY_INDEX }, | |
107 { "courier", MONO_FAMILY_INDEX }, | |
108 { "courier new", MONO_FAMILY_INDEX }, | |
109 { "cursive", SERIF_FAMILY_INDEX }, | |
110 { "fantasy", SERIF_FAMILY_INDEX }, | |
111 { "georgia", SERIF_FAMILY_INDEX }, | |
112 { "goudy", SERIF_FAMILY_INDEX }, | |
113 { "helvetica", SANS_FAMILY_INDEX }, | |
114 { "palatino", SERIF_FAMILY_INDEX }, | |
115 { "tahoma", SANS_FAMILY_INDEX }, | |
116 { "sans-serif", SANS_FAMILY_INDEX }, | |
117 { "serif", SERIF_FAMILY_INDEX }, | |
118 { "times", SERIF_FAMILY_INDEX }, | |
119 { "times new roman", SERIF_FAMILY_INDEX }, | |
120 { "verdana", SANS_FAMILY_INDEX } | |
121 #endif | |
122 }; | |
123 | |
124 ////////////////////////////////////////////////////////////////////////////////
//////// | |
125 | |
126 #include "SkTSearch.h" | |
127 | |
128 static bool contains_only_ascii(const char s[]) | |
129 { | |
130 for (;;) | |
131 { | |
132 int c = *s++; | |
133 if (c == 0) | |
134 break; | |
135 if ((c >> 7) != 0) | |
136 return false; | |
137 } | |
138 return true; | |
139 } | |
140 | |
141 #define TRACE_FONT_NAME(code) | |
142 //#define TRACE_FONT_NAME(code) code | |
143 | |
144 const FontFamilyRec* find_family_rec(const char target[]) | |
145 { | |
146 int index; | |
147 | |
148 // If we're asked for a font name that contains non-ascii, | |
149 // 1) SkStrLCSearch can't handle it | |
150 // 2) All of our fonts are have ascii names, so... | |
151 | |
152 TRACE_FONT_NAME(printf("----------------- font request <%s>", target);) | |
153 | |
154 if (contains_only_ascii(target)) | |
155 { | |
156 // Search for the font by matching the entire name | |
157 index = SkStrLCSearch(&gMatches[0].fLCName, SK_ARRAY_COUNT(gMatches), ta
rget, sizeof(gMatches[0])); | |
158 if (index >= 0) | |
159 { | |
160 TRACE_FONT_NAME(printf(" found %d\n", index);) | |
161 return &gFamilies[gMatches[index].fFamilyIndex]; | |
162 } | |
163 } | |
164 | |
165 // Sniff for key words... | |
166 | |
167 #if 0 | |
168 if (strstr(target, "sans") || strstr(target, "Sans")) | |
169 { | |
170 TRACE_FONT_NAME(printf(" found sans\n");) | |
171 return &gFamilies[SANS_FAMILY_INDEX]; | |
172 } | |
173 if (strstr(target, "serif") || strstr(target, "Serif")) | |
174 { | |
175 TRACE_FONT_NAME(printf(" found serif\n");) | |
176 return &gFamilies[SERIF_FAMILY_INDEX]; | |
177 } | |
178 if (strstr(target, "mono") || strstr(target, "Mono")) | |
179 { | |
180 TRACE_FONT_NAME(printf(" found mono\n");) | |
181 return &gFamilies[MONO_FAMILY_INDEX]; | |
182 } | |
183 #endif | |
184 | |
185 TRACE_FONT_NAME(printf(" use default\n");) | |
186 // we give up, just give them the default font | |
187 return &gFamilies[DEFAULT_FAMILY_INDEX]; | |
188 } | |
189 | |
190 ////////////////////////////////////////////////////////////////////////////////
/////////////// | |
191 | |
192 static const FontFaceRec* get_default_face() | |
193 { | |
194 return &gFamilies[DEFAULT_FAMILY_INDEX].fFaces[DEFAULT_FAMILY_FACE_INDEX]; | |
195 } | |
196 | |
197 class FontFaceRec_Typeface : public SkTypeface { | |
198 public: | |
199 FontFaceRec_Typeface(const FontFaceRec& face) : fFace(face) | |
200 { | |
201 int style = 0; | |
202 if (face.fBold) | |
203 style |= SkTypeface::kBold; | |
204 if (face.fItalic) | |
205 style |= SkTypeface::kItalic; | |
206 this->setStyle((SkTypeface::Style)style); | |
207 } | |
208 | |
209 // This global const reference completely identifies the face | |
210 const FontFaceRec& fFace; | |
211 }; | |
212 | |
213 static const FontFaceRec* get_typeface_rec(const SkTypeface* face) | |
214 { | |
215 const FontFaceRec_Typeface* f = (FontFaceRec_Typeface*)face; | |
216 return f ? &f->fFace : get_default_face(); | |
217 } | |
218 | |
219 static uint32_t ptr2uint32(const void* p) | |
220 { | |
221 // cast so we avoid warnings on 64bit machines that a ptr difference | |
222 // which might be 64bits is being trucated from 64 to 32 | |
223 return (uint32_t)((char*)p - (char*)0); | |
224 } | |
225 | |
226 uint32_t SkFontHost::TypefaceHash(const SkTypeface* face) | |
227 { | |
228 // just use our address as the hash value | |
229 return ptr2uint32(get_typeface_rec(face)); | |
230 } | |
231 | |
232 bool SkFontHost::TypefaceEqual(const SkTypeface* facea, const SkTypeface* faceb) | |
233 { | |
234 return get_typeface_rec(facea) == get_typeface_rec(faceb); | |
235 } | |
236 | |
237 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, const char
familyName[], SkTypeface::Style style) | |
238 { | |
239 const FontFamilyRec* family; | |
240 | |
241 if (familyFace) | |
242 family = &gFamilies[((FontFaceRec_Typeface*)familyFace)->fFace.fFamilyIn
dex]; | |
243 else if (familyName) | |
244 family = find_family_rec(familyName); | |
245 else | |
246 family = &gFamilies[DEFAULT_FAMILY_INDEX]; | |
247 | |
248 const FontFaceRec& face = FontFaceRec::FindFace(family->fFaces, family->fFac
eCount, | |
249 (style & SkTypeface::kBold)
!= 0, | |
250 (style & SkTypeface::kItalic
) != 0); | |
251 | |
252 // if we're returning our input parameter, no need to create a new instance | |
253 if (familyFace != NULL && &((FontFaceRec_Typeface*)familyFace)->fFace == &fa
ce) | |
254 { | |
255 familyFace->ref(); | |
256 return (SkTypeface*)familyFace; | |
257 } | |
258 return SkNEW_ARGS(FontFaceRec_Typeface, (face)); | |
259 } | |
260 | |
261 uint32_t SkFontHost::FlattenTypeface(const SkTypeface* tface, void* buffer) | |
262 { | |
263 const FontFaceRec* face; | |
264 | |
265 if (tface) | |
266 face = &((const FontFaceRec_Typeface*)tface)->fFace; | |
267 else | |
268 face = get_default_face(); | |
269 | |
270 size_t size = sizeof(face); | |
271 if (buffer) | |
272 memcpy(buffer, &face, size); | |
273 return size; | |
274 } | |
275 | |
276 void SkFontHost::GetDescriptorKeyString(const SkDescriptor* desc, SkString* key) | |
277 { | |
278 key->set(SK_FONTPATH); | |
279 } | |
280 | |
281 #ifdef SK_CAN_USE_MMAP | |
282 #include <unistd.h> | |
283 #include <sys/mman.h> | |
284 #include <fcntl.h> | |
285 #include <errno.h> | |
286 | |
287 class SkMMAPStream : public SkMemoryStream { | |
288 public: | |
289 SkMMAPStream(const char filename[]); | |
290 virtual ~SkMMAPStream(); | |
291 | |
292 virtual void setMemory(const void* data, size_t length); | |
293 private: | |
294 int fFildes; | |
295 void* fAddr; | |
296 size_t fSize; | |
297 | |
298 void closeMMap(); | |
299 | |
300 typedef SkMemoryStream INHERITED; | |
301 }; | |
302 | |
303 SkMMAPStream::SkMMAPStream(const char filename[]) | |
304 { | |
305 fFildes = -1; // initialize to failure case | |
306 | |
307 int fildes = open(filename, O_RDONLY); | |
308 if (fildes < 0) | |
309 { | |
310 SkDEBUGF(("---- failed to open(%s) for mmap stream error=%d\n", filename
, errno)); | |
311 return; | |
312 } | |
313 | |
314 off_t size = lseek(fildes, 0, SEEK_END); // find the file size | |
315 if (size == -1) | |
316 { | |
317 SkDEBUGF(("---- failed to lseek(%s) for mmap stream error=%d\n", filenam
e, errno)); | |
318 close(fildes); | |
319 return; | |
320 } | |
321 (void)lseek(fildes, 0, SEEK_SET); // restore file offset to beginning | |
322 | |
323 void* addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fildes, 0); | |
324 if (MAP_FAILED == addr) | |
325 { | |
326 SkDEBUGF(("---- failed to mmap(%s) for mmap stream error=%d\n", filename
, errno)); | |
327 close(fildes); | |
328 return; | |
329 } | |
330 | |
331 this->INHERITED::setMemory(addr, size); | |
332 | |
333 fFildes = fildes; | |
334 fAddr = addr; | |
335 fSize = size; | |
336 } | |
337 | |
338 SkMMAPStream::~SkMMAPStream() | |
339 { | |
340 this->closeMMap(); | |
341 } | |
342 | |
343 void SkMMAPStream::setMemory(const void* data, size_t length) | |
344 { | |
345 this->closeMMap(); | |
346 this->INHERITED::setMemory(data, length); | |
347 } | |
348 | |
349 void SkMMAPStream::closeMMap() | |
350 { | |
351 if (fFildes >= 0) | |
352 { | |
353 munmap(fAddr, fSize); | |
354 close(fFildes); | |
355 fFildes = -1; | |
356 } | |
357 } | |
358 | |
359 #endif | |
360 | |
361 SkStream* SkFontHost::OpenDescriptorStream(const SkDescriptor* desc, const char
keyString[]) | |
362 { | |
363 // our key string IS our filename, so we can ignore desc | |
364 SkStream* strm; | |
365 | |
366 #ifdef SK_CAN_USE_MMAP | |
367 strm = new SkMMAPStream(keyString); | |
368 if (strm->getLength() > 0) | |
369 return strm; | |
370 | |
371 // strm not valid | |
372 delete strm; | |
373 // fall through to FILEStream attempt | |
374 #endif | |
375 | |
376 strm = new SkFILEStream(keyString); | |
377 if (strm->getLength() > 0) | |
378 return strm; | |
379 | |
380 // strm not valid | |
381 delete strm; | |
382 return NULL; | |
383 } | |
384 | |
385 SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::
Rec& rec) | |
386 { | |
387 const FontFaceRec* face = get_default_face(); | |
388 | |
389 SkAutoDescriptor ad(sizeof(rec) + sizeof(face) + SkDescriptor::ComputeOve
rhead(2)); | |
390 SkDescriptor* desc = ad.getDesc(); | |
391 | |
392 desc->init(); | |
393 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); | |
394 desc->addEntry(kTypeface_SkDescriptorTag, sizeof(face), &face); | |
395 desc->computeChecksum(); | |
396 | |
397 return SkFontHost::CreateScalerContext(desc); | |
398 } | |
399 | |
400 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) | |
401 { | |
402 return 0; // nothing to do (change me if you want to limit the font cache) | |
403 } | |
404 | |
405 int SkFontHost::ComputeGammaFlag(const SkPaint& paint) | |
406 { | |
407 return 0; | |
408 } | |
409 | |
410 void SkFontHost::GetGammaTables(const uint8_t* tables[2]) | |
411 { | |
412 tables[0] = NULL; // black gamma (e.g. exp=1.4) | |
413 tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) | |
414 } | |
415 | |
OLD | NEW |