blob: 3b5e99365ef04f388978de7797874669756795af [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkFontHost.h"
11#include "SkDescriptor.h"
12#include "SkString.h"
13#include "SkStream.h"
14#include <stdio.h>
15
16/* define this if we can use mmap() to access fonts from the filesystem */
rmistry@google.comd6176b02012-08-23 18:14:13 +000017#define SK_CAN_USE_MMAP
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
19#ifndef SK_FONTPATH
20 #define SK_FONTPATH "the complete path for a font file"
21#endif
22
23struct FontFaceRec {
rmistry@google.comd6176b02012-08-23 18:14:13 +000024 const char* fFileName;
reed@android.com8a1c16f2008-12-17 15:59:43 +000025 uint8_t fFamilyIndex;
26 SkBool8 fBold;
27 SkBool8 fItalic;
28
reed@android.comb50a60c2009-01-14 17:51:08 +000029 static const FontFaceRec& FindFace(const FontFaceRec rec[], int count,
30 int isBold, int isItalic);
reed@android.com8a1c16f2008-12-17 15:59:43 +000031};
32
33struct FontFamilyRec {
34 const FontFaceRec* fFaces;
35 int fFaceCount;
36};
37
reed@android.comb50a60c2009-01-14 17:51:08 +000038const FontFaceRec& FontFaceRec::FindFace(const FontFaceRec rec[], int count,
39 int isBold, int isItalic)
reed@android.com8a1c16f2008-12-17 15:59:43 +000040{
41 SkASSERT(count > 0);
rmistry@google.comd6176b02012-08-23 18:14:13 +000042
reed@android.com8a1c16f2008-12-17 15:59:43 +000043 int i;
44
45 // look for an exact match
46 for (i = 0; i < count; i++) {
47 if (rec[i].fBold == isBold && rec[i].fItalic == isItalic)
48 return rec[i];
49 }
50 // look for a match in the bold field
51 for (i = 0; i < count; i++) {
52 if (rec[i].fBold == isBold)
53 return rec[i];
54 }
55 // look for a normal/regular face
56 for (i = 0; i < count; i++) {
57 if (!rec[i].fBold && !rec[i].fItalic)
58 return rec[i];
59 }
60 // give up
61 return rec[0];
62}
63
64enum {
65 DEFAULT_FAMILY_INDEX,
rmistry@google.comd6176b02012-08-23 18:14:13 +000066
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 FAMILY_INDEX_COUNT
68};
69
70static const FontFaceRec gDefaultFaces[] = {
71 { SK_FONTPATH, DEFAULT_FAMILY_INDEX, 0, 0 }
72};
73
74// This table must be in the same order as the ..._FAMILY_INDEX enum specifies
75static const FontFamilyRec gFamilies[] = {
76 { gDefaultFaces, SK_ARRAY_COUNT(gDefaultFaces) }
77};
78
79#define DEFAULT_FAMILY_INDEX DEFAULT_FAMILY_INDEX
80#define DEFAULT_FAMILY_FACE_INDEX 0
81
reed@android.comb50a60c2009-01-14 17:51:08 +000082///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000083
84/* map common "web" font names to our font list */
85
86struct FontFamilyMatchRec {
87 const char* fLCName;
88 int fFamilyIndex;
89};
90
91/* This is a table of synonyms for collapsing font names
92 down to their pseudo-equivalents (i.e. in terms of fonts
93 we actually have.)
94 Keep this sorted by the first field so we can do a binary search.
95 If this gets big, we could switch to a hash...
96*/
97static const FontFamilyMatchRec gMatches[] = {
98#if 0
99 { "Ahem", Ahem_FAMILY_INDEX },
100 { "arial", SANS_FAMILY_INDEX },
101 { "courier", MONO_FAMILY_INDEX },
102 { "courier new", MONO_FAMILY_INDEX },
103 { "cursive", SERIF_FAMILY_INDEX },
104 { "fantasy", SERIF_FAMILY_INDEX },
105 { "georgia", SERIF_FAMILY_INDEX },
106 { "goudy", SERIF_FAMILY_INDEX },
107 { "helvetica", SANS_FAMILY_INDEX },
108 { "palatino", SERIF_FAMILY_INDEX },
109 { "tahoma", SANS_FAMILY_INDEX },
110 { "sans-serif", SANS_FAMILY_INDEX },
111 { "serif", SERIF_FAMILY_INDEX },
112 { "times", SERIF_FAMILY_INDEX },
113 { "times new roman", SERIF_FAMILY_INDEX },
114 { "verdana", SANS_FAMILY_INDEX }
115#endif
116};
117
reed@android.comb50a60c2009-01-14 17:51:08 +0000118///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119
120#include "SkTSearch.h"
121
122static bool contains_only_ascii(const char s[])
123{
124 for (;;)
125 {
126 int c = *s++;
127 if (c == 0)
128 break;
129 if ((c >> 7) != 0)
130 return false;
131 }
132 return true;
133}
134
135#define TRACE_FONT_NAME(code)
136//#define TRACE_FONT_NAME(code) code
137
138const FontFamilyRec* find_family_rec(const char target[])
139{
140 int index;
141
142 // If we're asked for a font name that contains non-ascii,
143 // 1) SkStrLCSearch can't handle it
144 // 2) All of our fonts are have ascii names, so...
145
146TRACE_FONT_NAME(printf("----------------- font request <%s>", target);)
147
148 if (contains_only_ascii(target))
149 {
150 // Search for the font by matching the entire name
reed@android.comb50a60c2009-01-14 17:51:08 +0000151 index = SkStrLCSearch(&gMatches[0].fLCName, SK_ARRAY_COUNT(gMatches),
152 target, sizeof(gMatches[0]));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 if (index >= 0)
154 {
155 TRACE_FONT_NAME(printf(" found %d\n", index);)
156 return &gFamilies[gMatches[index].fFamilyIndex];
157 }
158 }
159
160 // Sniff for key words...
161
162#if 0
163 if (strstr(target, "sans") || strstr(target, "Sans"))
164 {
165 TRACE_FONT_NAME(printf(" found sans\n");)
166 return &gFamilies[SANS_FAMILY_INDEX];
167 }
168 if (strstr(target, "serif") || strstr(target, "Serif"))
169 {
170 TRACE_FONT_NAME(printf(" found serif\n");)
171 return &gFamilies[SERIF_FAMILY_INDEX];
172 }
173 if (strstr(target, "mono") || strstr(target, "Mono"))
174 {
175 TRACE_FONT_NAME(printf(" found mono\n");)
176 return &gFamilies[MONO_FAMILY_INDEX];
177 }
178#endif
179
180 TRACE_FONT_NAME(printf(" use default\n");)
181 // we give up, just give them the default font
182 return &gFamilies[DEFAULT_FAMILY_INDEX];
183}
184
reed@android.comb50a60c2009-01-14 17:51:08 +0000185///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186
187static const FontFaceRec* get_default_face()
188{
189 return &gFamilies[DEFAULT_FAMILY_INDEX].fFaces[DEFAULT_FAMILY_FACE_INDEX];
190}
191
reed@android.com563771e2009-01-14 14:16:46 +0000192static SkTypeface::Style get_style(const FontFaceRec& face) {
193 int style = 0;
194 if (face.fBold) {
195 style |= SkTypeface::kBold;
196 }
197 if (face.fItalic) {
198 style |= SkTypeface::kItalic;
199 }
200 return static_cast<SkTypeface::Style>(style);
201}
202
203// This global const reference completely identifies the face
204static uint32_t get_id(const FontFaceRec& face) {
205 uintptr_t id = reinterpret_cast<uintptr_t>(&face);
206 return static_cast<uint32_t>(id);
207}
208
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209class FontFaceRec_Typeface : public SkTypeface {
210public:
reed@android.com563771e2009-01-14 14:16:46 +0000211 FontFaceRec_Typeface(const FontFaceRec& face) :
212 SkTypeface(get_style(face), get_id(face)),
213 fFace(face)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 }
216
217 // This global const reference completely identifies the face
218 const FontFaceRec& fFace;
219};
220
221static const FontFaceRec* get_typeface_rec(const SkTypeface* face)
222{
223 const FontFaceRec_Typeface* f = (FontFaceRec_Typeface*)face;
224 return f ? &f->fFace : get_default_face();
225}
226
227static uint32_t ptr2uint32(const void* p)
228{
229 // cast so we avoid warnings on 64bit machines that a ptr difference
230 // which might be 64bits is being trucated from 64 to 32
231 return (uint32_t)((char*)p - (char*)0);
232}
233
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000234SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
235 const char familyName[],
236 SkTypeface::Style style)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237{
238 const FontFamilyRec* family;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 if (familyFace)
reed@android.comb50a60c2009-01-14 17:51:08 +0000241 family = &gFamilies[
242 ((FontFaceRec_Typeface*)familyFace)->fFace.fFamilyIndex];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 else if (familyName)
244 family = find_family_rec(familyName);
245 else
246 family = &gFamilies[DEFAULT_FAMILY_INDEX];
247
reed@android.comb50a60c2009-01-14 17:51:08 +0000248 const FontFaceRec& face = FontFaceRec::FindFace(family->fFaces,
249 family->fFaceCount,
250 (style & SkTypeface::kBold) != 0,
251 (style & SkTypeface::kItalic) != 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252
253 // if we're returning our input parameter, no need to create a new instance
reed@android.comb50a60c2009-01-14 17:51:08 +0000254 if (familyFace != NULL &&
255 &((FontFaceRec_Typeface*)familyFace)->fFace == &face)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 {
257 familyFace->ref();
258 return (SkTypeface*)familyFace;
259 }
260 return SkNEW_ARGS(FontFaceRec_Typeface, (face));
261}
262
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000263// static
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000264SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +0000265 uint32_t fontID,
tomhudson@google.comeebd62a2012-03-23 15:38:28 +0000266 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
267 const uint32_t* glyphIDs,
268 uint32_t glyphIDsCount) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000269 sk_throw(); // not implemented
270 return NULL;
271}
272
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000273SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
reed@android.com563771e2009-01-14 14:16:46 +0000274 sk_throw(); // not implemented
275 return NULL;
276}
277
278SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
279 sk_throw(); // not implemented
280 return NULL;
281}
282
reed@android.com563771e2009-01-14 14:16:46 +0000283SkStream* SkFontHost::OpenStream(uint32_t fontID) {
284 sk_throw(); // not implemented
285 return NULL;
286}
287
reed@android.comac981542009-07-31 16:17:01 +0000288size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
289 int32_t* index) {
290 SkDebugf("SkFontHost::GetFileName unimplemented\n");
291 return 0;
292}
293
reed@android.com563771e2009-01-14 14:16:46 +0000294void SkFontHost::Serialize(const SkTypeface* tface, SkWStream* stream) {
reed@android.comb50a60c2009-01-14 17:51:08 +0000295 const FontFaceRec* face = &((const FontFaceRec_Typeface*)tface)->fFace;
reed@android.com563771e2009-01-14 14:16:46 +0000296 stream->write(face, sizeof(face));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297}
298
reed@android.com563771e2009-01-14 14:16:46 +0000299SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
300 const FontFaceRec* face;
301 stream->read(&face, sizeof(face));
302 return new FontFaceRec_Typeface(*face);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303}
304
reed@android.comb50a60c2009-01-14 17:51:08 +0000305SkScalerContext* SkFontHost::CreateFallbackScalerContext(
306 const SkScalerContext::Rec& rec)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307{
308 const FontFaceRec* face = get_default_face();
309
reed@android.comb50a60c2009-01-14 17:51:08 +0000310 SkAutoDescriptor ad(sizeof(rec) + sizeof(face) +
311 SkDescriptor::ComputeOverhead(2));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312 SkDescriptor* desc = ad.getDesc();
reed@android.com563771e2009-01-14 14:16:46 +0000313 SkScalerContext::Rec* newRec;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314
315 desc->init();
reed@android.com563771e2009-01-14 14:16:46 +0000316 newRec = reinterpret_cast<SkScalerContext::Rec*>(
317 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec));
318 newRec->fFontID = get_id(*face);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000319 desc->computeChecksum();
320
321 return SkFontHost::CreateScalerContext(desc);
322}