blob: e1db69a4bd721404ef3852243d8f200527d7c3fb [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
reed@google.comd71fe992013-02-25 20:38:07 +00008#include "SkFontConfigInterface.h"
9#include "SkFontDescriptor.h"
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +000010#include "SkFontHost.h"
reed@google.com822bde72013-03-04 16:28:33 +000011#include "SkFontStream.h"
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +000012#include "SkStream.h"
reed@google.com80f54652013-02-25 22:19:20 +000013#include "SkTypeface.h"
reed@google.comf71a2332013-02-27 19:06:30 +000014#include "SkTypefaceCache.h"
reed@google.comb1c65b62013-02-26 15:50:51 +000015
reed@google.comd71fe992013-02-25 20:38:07 +000016SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex);
17static SkFontConfigInterface* gFontConfigInterface;
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +000018
reed@google.comd71fe992013-02-25 20:38:07 +000019SkFontConfigInterface* SkFontConfigInterface::RefGlobal() {
20 SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
skia.committer@gmail.com5ca3bd02013-02-26 07:01:22 +000021
reed@google.comd71fe992013-02-25 20:38:07 +000022 return SkSafeRef(gFontConfigInterface);
23}
bungeman@google.comb13d63c2012-11-06 16:55:24 +000024
reed@google.comd71fe992013-02-25 20:38:07 +000025SkFontConfigInterface* SkFontConfigInterface::SetGlobal(SkFontConfigInterface* fc) {
26 SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +000027
reed@google.comd71fe992013-02-25 20:38:07 +000028 SkRefCnt_SafeAssign(gFontConfigInterface, fc);
29 return fc;
30}
bungeman@google.comb13d63c2012-11-06 16:55:24 +000031
reed@google.comd71fe992013-02-25 20:38:07 +000032///////////////////////////////////////////////////////////////////////////////
reed@google.comf71a2332013-02-27 19:06:30 +000033///////////////////////////////////////////////////////////////////////////////
34
35// convenience function to create the direct interface if none is installed.
36extern SkFontConfigInterface* SkCreateDirectFontConfigInterface();
reed@google.comd71fe992013-02-25 20:38:07 +000037
reed@google.com80f54652013-02-25 22:19:20 +000038static SkFontConfigInterface* RefFCI() {
reed@google.comb1c65b62013-02-26 15:50:51 +000039 for (;;) {
40 SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal();
41 if (fci) {
42 return fci;
43 }
reed@google.comd66045e2013-03-04 19:07:02 +000044 fci = SkFontConfigInterface::GetSingletonDirectInterface();
45 SkFontConfigInterface::SetGlobal(fci);
reed@google.comb1c65b62013-02-26 15:50:51 +000046 }
reed@google.com80f54652013-02-25 22:19:20 +000047}
48
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +000049class FontConfigTypeface : public SkTypeface {
reed@google.comf71a2332013-02-27 19:06:30 +000050 SkFontConfigInterface::FontIdentity fIdentity;
51 SkString fFamilyName;
52 SkStream* fLocalStream;
53
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +000054public:
reed@google.comf71a2332013-02-27 19:06:30 +000055 FontConfigTypeface(Style style,
56 const SkFontConfigInterface::FontIdentity& fi,
57 const SkString& familyName)
58 : SkTypeface(style, SkTypefaceCache::NewFontID())
59 , fIdentity(fi)
60 , fFamilyName(familyName)
61 , fLocalStream(NULL) {}
62
63 FontConfigTypeface(Style style, SkStream* localStream)
64 : SkTypeface(style, SkTypefaceCache::NewFontID()) {
65 // we default to empty fFamilyName and fIdentity
66 fLocalStream = localStream;
67 SkSafeRef(localStream);
68 }
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +000069
reed@google.com80f54652013-02-25 22:19:20 +000070 virtual ~FontConfigTypeface() {
reed@google.comf71a2332013-02-27 19:06:30 +000071 SkSafeUnref(fLocalStream);
72 }
73
74 const SkFontConfigInterface::FontIdentity& getIdentity() const {
75 return fIdentity;
76 }
77
78 const char* getFamilyName() const { return fFamilyName.c_str(); }
79 SkStream* getLocalStream() const { return fLocalStream; }
80
81 bool isFamilyName(const char* name) const {
82 return fFamilyName.equals(name);
reed@google.comd71fe992013-02-25 20:38:07 +000083 }
reed@google.com822bde72013-03-04 16:28:33 +000084
85protected:
86 friend class SkFontHost; // hack until we can make public versions
87
88 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
89 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
90 size_t length, void* data) const SK_OVERRIDE;
91 virtual void onGetFontDescriptor(SkFontDescriptor*) const SK_OVERRIDE;
92
93private:
94 typedef SkTypeface INHERITED;
reed@google.comd71fe992013-02-25 20:38:07 +000095};
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +000096
reed@google.comf71a2332013-02-27 19:06:30 +000097///////////////////////////////////////////////////////////////////////////////
98
99struct FindRec {
100 FindRec(const char* name, SkTypeface::Style style)
101 : fFamilyName(name) // don't need to make a deep copy
102 , fStyle(style) {}
103
104 const char* fFamilyName;
105 SkTypeface::Style fStyle;
106};
107
108static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
109 FontConfigTypeface* fci = (FontConfigTypeface*)face;
110 const FindRec* rec = (const FindRec*)ctx;
111
112 return rec->fStyle == style && fci->isFamilyName(rec->fFamilyName);
113}
114
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +0000115SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
116 const char familyName[],
reed@google.com80f54652013-02-25 22:19:20 +0000117 SkTypeface::Style style) {
118 SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
119 if (NULL == fci.get()) {
120 return NULL;
121 }
122
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +0000123 if (familyFace) {
reed@google.comf71a2332013-02-27 19:06:30 +0000124 FontConfigTypeface* fct = (FontConfigTypeface*)familyFace;
125 familyName = fct->getFamilyName();
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +0000126 }
127
reed@google.comf71a2332013-02-27 19:06:30 +0000128 FindRec rec(familyName, style);
129 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_proc, &rec);
130 if (face) {
131 return face;
132 }
133
134 SkFontConfigInterface::FontIdentity indentity;
135 SkString outFamilyName;
136 SkTypeface::Style outStyle;
137
138 if (!fci->matchFamilyName(familyName, style,
139 &indentity, &outFamilyName, &outStyle)) {
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +0000140 return NULL;
141 }
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +0000142
reed@google.comf71a2332013-02-27 19:06:30 +0000143 face = SkNEW_ARGS(FontConfigTypeface, (outStyle, indentity, outFamilyName));
144 SkTypefaceCache::Add(face, style);
145 return face;
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +0000146}
147
reed@google.com80f54652013-02-25 22:19:20 +0000148SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
149 if (!stream) {
reed@google.comd71fe992013-02-25 20:38:07 +0000150 return NULL;
reed@google.com80f54652013-02-25 22:19:20 +0000151 }
reed@google.comf71a2332013-02-27 19:06:30 +0000152 const size_t length = stream->getLength();
reed@google.com80f54652013-02-25 22:19:20 +0000153 if (!length) {
reed@google.comd71fe992013-02-25 20:38:07 +0000154 return NULL;
reed@google.com80f54652013-02-25 22:19:20 +0000155 }
156 if (length >= 1024 * 1024 * 1024) {
reed@google.comd71fe992013-02-25 20:38:07 +0000157 return NULL; // don't accept too large fonts (>= 1GB) for safety.
reed@google.com80f54652013-02-25 22:19:20 +0000158 }
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +0000159
reed@google.comf71a2332013-02-27 19:06:30 +0000160 // TODO should the caller give us the style?
161 SkTypeface::Style style = SkTypeface::kNormal;
162 SkTypeface* face = SkNEW_ARGS(FontConfigTypeface, (style, stream));
163 SkTypefaceCache::Add(face, style);
164 return face;
reed@android.comac981542009-07-31 16:17:01 +0000165}
166
reed@google.com80f54652013-02-25 22:19:20 +0000167SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
reed@google.com8d33a242013-02-26 17:11:07 +0000168 SkTypeface* face = NULL;
169 SkFILEStream* stream = SkNEW_ARGS(SkFILEStream, (path));
170
171 if (stream->isValid()) {
172 face = CreateTypefaceFromStream(stream);
173 }
174 stream->unref();
175 return face;
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +0000176}
177
reed@google.com822bde72013-03-04 16:28:33 +0000178///////////////////////////////////////////////////////////////////////////////
179
180// DEPRECATED
181int SkFontHost::CountTables(SkFontID fontID) {
182 SkTypeface* face = SkTypefaceCache::FindByID(fontID);
183 return face ? face->onGetTableTags(NULL) : 0;
184}
185
186// DEPRECATED
187int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) {
188 SkTypeface* face = SkTypefaceCache::FindByID(fontID);
189 return face ? face->onGetTableTags(tags) : 0;
190}
191
192// DEPRECATED
193size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) {
194 SkTypeface* face = SkTypefaceCache::FindByID(fontID);
195 return face ? face->onGetTableData(tag, 0, ~0U, NULL) : 0;
196}
197
198// DEPRECATED
199size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag,
200 size_t offset, size_t length, void* dst) {
201 SkTypeface* face = SkTypefaceCache::FindByID(fontID);
202 return face ? face->onGetTableData(tag, offset, length, dst) : 0;
203}
204
205// DEPRECATED
reed@google.comd71fe992013-02-25 20:38:07 +0000206uint32_t SkFontHost::NextLogicalFont(SkFontID curr, SkFontID orig) {
reed@google.com80f54652013-02-25 22:19:20 +0000207 // We don't handle font fallback.
agl@chromium.orgdf8ecfb2009-04-28 17:30:01 +0000208 return 0;
209}
reed@google.comd71fe992013-02-25 20:38:07 +0000210
211///////////////////////////////////////////////////////////////////////////////
212
213// Serialize, Deserialize need to be compatible across platforms, hence the use
214// of SkFontDescriptor.
215
216void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
reed@google.comf71a2332013-02-27 19:06:30 +0000217 FontConfigTypeface* fct = (FontConfigTypeface*)face;
reed@google.comd71fe992013-02-25 20:38:07 +0000218
reed@google.com822bde72013-03-04 16:28:33 +0000219 SkFontDescriptor desc;
220 fct->onGetFontDescriptor(&desc);
reed@google.comd71fe992013-02-25 20:38:07 +0000221 desc.serialize(stream);
skia.committer@gmail.com5ca3bd02013-02-26 07:01:22 +0000222
reed@google.comd71fe992013-02-25 20:38:07 +0000223 // by convention, we also write out the actual sfnt data, preceeded by
224 // a packed-length. For now we skip that, so we just write the zero.
225 stream->writePackedUInt(0);
226}
227
228SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
reed@google.comee619a02013-02-26 22:58:09 +0000229 SkFontDescriptor descriptor(stream);
230 const char* familyName = descriptor.getFamilyName();
231 const SkTypeface::Style style = descriptor.getStyle();
reed@google.comd71fe992013-02-25 20:38:07 +0000232
reed@google.comf71a2332013-02-27 19:06:30 +0000233 size_t length = stream->readPackedUInt();
234 if (length > 0) {
235 void* addr = sk_malloc_flags(length, 0);
236 if (addr) {
237 SkAutoTUnref<SkStream> localStream(SkNEW_ARGS(SkMemoryStream,
238 (addr, length, false)));
239 return SkFontHost::CreateTypefaceFromStream(localStream.get());
240 }
241 // failed to allocate, so just skip and create-from-name
242 stream->skip(length);
reed@google.comee619a02013-02-26 22:58:09 +0000243 }
reed@google.comf71a2332013-02-27 19:06:30 +0000244
245 return SkFontHost::CreateTypeface(NULL, familyName, style);
reed@google.comd71fe992013-02-25 20:38:07 +0000246}
247
248///////////////////////////////////////////////////////////////////////////////
249
reed@google.com5bfc8392013-03-05 22:12:11 +0000250static SkStream* open_stream(const FontConfigTypeface* face, int* ttcIndex) {
reed@google.comf71a2332013-02-27 19:06:30 +0000251 SkStream* stream = face->getLocalStream();
252 if (stream) {
253 stream->ref();
reed@google.com5bfc8392013-03-05 22:12:11 +0000254 // should have been provided by CreateFromStream()
255 *ttcIndex = 0;
reed@google.comf71a2332013-02-27 19:06:30 +0000256 } else {
257 SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
258 if (NULL == fci.get()) {
259 return NULL;
260 }
261 stream = fci->openStream(face->getIdentity());
reed@google.com8c9737e2013-03-06 13:06:03 +0000262 *ttcIndex = face->getIdentity().fTTCIndex;
reed@google.comf71a2332013-02-27 19:06:30 +0000263 }
264 return stream;
reed@google.comd71fe992013-02-25 20:38:07 +0000265}
266
reed@google.com822bde72013-03-04 16:28:33 +0000267SkStream* SkFontHost::OpenStream(uint32_t id) {
268 FontConfigTypeface* face = (FontConfigTypeface*)SkTypefaceCache::FindByID(id);
269 if (NULL == face) {
270 return NULL;
271 }
skia.committer@gmail.com64334352013-03-06 07:01:46 +0000272
reed@google.com5bfc8392013-03-05 22:12:11 +0000273 int ttcIndex;
274 // We should return ttcIndex from this call.
275 return open_stream(face, &ttcIndex);
reed@google.com822bde72013-03-04 16:28:33 +0000276}
277
reed@google.comd71fe992013-02-25 20:38:07 +0000278size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
279 int32_t* index) {
skia.committer@gmail.com631cdcb2013-03-01 12:12:55 +0000280 FontConfigTypeface* face = (FontConfigTypeface*)SkTypefaceCache::FindByID(fontID);
reed@google.comf71a2332013-02-27 19:06:30 +0000281 if (NULL == face || face->getLocalStream()) {
reed@google.comd71fe992013-02-25 20:38:07 +0000282 return 0;
reed@google.comd71fe992013-02-25 20:38:07 +0000283 }
284
reed@google.comf71a2332013-02-27 19:06:30 +0000285 // Here we cheat, and "know" what is in the identity fields.
reed@google.comd71fe992013-02-25 20:38:07 +0000286
reed@google.comf71a2332013-02-27 19:06:30 +0000287 const SkString& filename = face->getIdentity().fString;
288 if (index) {
reed@google.com8c9737e2013-03-06 13:06:03 +0000289 *index = face->getIdentity().fTTCIndex;
reed@google.comf71a2332013-02-27 19:06:30 +0000290 }
291 if (path) {
292 size_t len = SkMin32(length, filename.size());
293 memcpy(path, filename.c_str(), len);
294 }
295 return filename.size();
reed@google.comd71fe992013-02-25 20:38:07 +0000296}
reed@google.com822bde72013-03-04 16:28:33 +0000297
298///////////////////////////////////////////////////////////////////////////////
299
300int FontConfigTypeface::onGetTableTags(SkFontTableTag tags[]) const {
reed@google.com5bfc8392013-03-05 22:12:11 +0000301 int ttcIndex;
302 SkAutoTUnref<SkStream> stream(open_stream(this, &ttcIndex));
303 return stream.get()
304 ? SkFontStream::GetTableTags(stream, ttcIndex, tags)
305 : 0;
reed@google.com822bde72013-03-04 16:28:33 +0000306}
307
308size_t FontConfigTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
309 size_t length, void* data) const {
reed@google.com5bfc8392013-03-05 22:12:11 +0000310 int ttcIndex;
311 SkAutoTUnref<SkStream> stream(open_stream(this, &ttcIndex));
312 return stream.get()
313 ? SkFontStream::GetTableData(stream, ttcIndex,
314 tag, offset, length, data)
315 : 0;
reed@google.com822bde72013-03-04 16:28:33 +0000316}
317
318void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc) const {
319 desc->setStyle(this->style());
320 desc->setFamilyName(this->getFamilyName());
321}