blob: 3cbccaf36e0b10d3277bc962b8941ecb243f68cb [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* 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
31struct 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 isBold, int isItalic);
38};
39
40struct FontFamilyRec {
41 const FontFaceRec* fFaces;
42 int fFaceCount;
43};
44
45const 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
70enum {
71 DEFAULT_FAMILY_INDEX,
72
73 FAMILY_INDEX_COUNT
74};
75
76static 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
81static 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
92struct 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*/
103static 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
128static 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
144const 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
152TRACE_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), target, 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
192static const FontFaceRec* get_default_face()
193{
194 return &gFamilies[DEFAULT_FAMILY_INDEX].fFaces[DEFAULT_FAMILY_FACE_INDEX];
195}
196
197class FontFaceRec_Typeface : public SkTypeface {
198public:
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
213static 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
219static 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
226uint32_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
232bool SkFontHost::TypefaceEqual(const SkTypeface* facea, const SkTypeface* faceb)
233{
234 return get_typeface_rec(facea) == get_typeface_rec(faceb);
235}
236
237SkTypeface* 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.fFamilyIndex];
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->fFaceCount,
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 == &face)
254 {
255 familyFace->ref();
256 return (SkTypeface*)familyFace;
257 }
258 return SkNEW_ARGS(FontFaceRec_Typeface, (face));
259}
260
261uint32_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
276void 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
287class SkMMAPStream : public SkMemoryStream {
288public:
289 SkMMAPStream(const char filename[]);
290 virtual ~SkMMAPStream();
291
292 virtual void setMemory(const void* data, size_t length);
293private:
294 int fFildes;
295 void* fAddr;
296 size_t fSize;
297
298 void closeMMap();
299
300 typedef SkMemoryStream INHERITED;
301};
302
303SkMMAPStream::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", filename, 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
338SkMMAPStream::~SkMMAPStream()
339{
340 this->closeMMap();
341}
342
343void SkMMAPStream::setMemory(const void* data, size_t length)
344{
345 this->closeMMap();
346 this->INHERITED::setMemory(data, length);
347}
348
349void SkMMAPStream::closeMMap()
350{
351 if (fFildes >= 0)
352 {
353 munmap(fAddr, fSize);
354 close(fFildes);
355 fFildes = -1;
356 }
357}
358
359#endif
360
361SkStream* 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
385SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec)
386{
387 const FontFaceRec* face = get_default_face();
388
389 SkAutoDescriptor ad(sizeof(rec) + sizeof(face) + SkDescriptor::ComputeOverhead(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
400size_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
405int SkFontHost::ComputeGammaFlag(const SkPaint& paint)
406{
407 return 0;
408}
409
410void 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