SkFontHost_fontconfig.cpp revision 52f1e2bbad4c5b0c778c9563508866142ef7cfd8
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 "SkFontConfigInterface.h"
9#include "SkFontConfigTypeface.h"
10#include "SkFontDescriptor.h"
11#include "SkFontHost.h"
12#include "SkFontHost_FreeType_common.h"
13#include "SkFontStream.h"
14#include "SkStream.h"
15#include "SkTypeface.h"
16#include "SkTypefaceCache.h"
17
18// Defined in SkFontHost_FreeType.cpp
19bool find_name_and_attributes(SkStream* stream, SkString* name,
20                              SkTypeface::Style* style, bool* isFixedWidth);
21
22///////////////////////////////////////////////////////////////////////////////
23///////////////////////////////////////////////////////////////////////////////
24
25SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex);
26static SkFontConfigInterface* gFontConfigInterface;
27
28SkFontConfigInterface* SkFontConfigInterface::RefGlobal() {
29    SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
30
31    return SkSafeRef(gFontConfigInterface);
32}
33
34SkFontConfigInterface* SkFontConfigInterface::SetGlobal(SkFontConfigInterface* fc) {
35    SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
36
37    SkRefCnt_SafeAssign(gFontConfigInterface, fc);
38    return fc;
39}
40
41///////////////////////////////////////////////////////////////////////////////
42///////////////////////////////////////////////////////////////////////////////
43
44// convenience function to create the direct interface if none is installed.
45extern SkFontConfigInterface* SkCreateDirectFontConfigInterface();
46
47static SkFontConfigInterface* RefFCI() {
48    for (;;) {
49        SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal();
50        if (fci) {
51            return fci;
52        }
53        fci = SkFontConfigInterface::GetSingletonDirectInterface();
54        SkFontConfigInterface::SetGlobal(fci);
55    }
56}
57
58// export this to SkFontMgr_fontconfig.cpp until this file just goes away.
59SkFontConfigInterface* SkFontHost_fontconfig_ref_global();
60SkFontConfigInterface* SkFontHost_fontconfig_ref_global() {
61    return RefFCI();
62}
63
64///////////////////////////////////////////////////////////////////////////////
65
66struct FindRec {
67    FindRec(const char* name, SkTypeface::Style style)
68        : fFamilyName(name)  // don't need to make a deep copy
69        , fStyle(style) {}
70
71    const char* fFamilyName;
72    SkTypeface::Style fStyle;
73};
74
75static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
76    FontConfigTypeface* fci = (FontConfigTypeface*)face;
77    const FindRec* rec = (const FindRec*)ctx;
78
79    return rec->fStyle == style && fci->isFamilyName(rec->fFamilyName);
80}
81
82SkTypeface* FontConfigTypeface::LegacyCreateTypeface(
83                const SkTypeface* familyFace,
84                const char familyName[],
85                SkTypeface::Style style) {
86    SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
87    if (NULL == fci.get()) {
88        return NULL;
89    }
90
91    if (familyFace) {
92        FontConfigTypeface* fct = (FontConfigTypeface*)familyFace;
93        familyName = fct->getFamilyName();
94    }
95
96    FindRec rec(familyName, style);
97    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_proc, &rec);
98    if (face) {
99//        SkDebugf("found cached face <%s> <%s> %p [%d]\n", familyName, ((FontConfigTypeface*)face)->getFamilyName(), face, face->getRefCnt());
100        return face;
101    }
102
103    SkFontConfigInterface::FontIdentity indentity;
104    SkString                            outFamilyName;
105    SkTypeface::Style                   outStyle;
106
107    if (!fci->matchFamilyName(familyName, style,
108                              &indentity, &outFamilyName, &outStyle)) {
109        return NULL;
110    }
111
112    face = SkNEW_ARGS(FontConfigTypeface, (outStyle, indentity, outFamilyName));
113    SkTypefaceCache::Add(face, style);
114//    SkDebugf("add face <%s> <%s> %p [%d]\n", familyName, outFamilyName.c_str(), face, face->getRefCnt());
115    return face;
116}
117
118#ifndef SK_FONTHOST_USES_FONTMGR
119
120SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
121                                       const char familyName[],
122                                       SkTypeface::Style style) {
123    return FontConfigTypeface::LegacyCreateTypeface(familyFace, familyName,
124                                                    style);
125}
126
127SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
128    if (!stream) {
129        return NULL;
130    }
131    const size_t length = stream->getLength();
132    if (!length) {
133        return NULL;
134    }
135    if (length >= 1024 * 1024 * 1024) {
136        return NULL;  // don't accept too large fonts (>= 1GB) for safety.
137    }
138
139    // ask freetype for reported style and if it is a fixed width font
140    SkTypeface::Style style = SkTypeface::kNormal;
141    bool isFixedWidth = false;
142    if (!find_name_and_attributes(stream, NULL, &style, &isFixedWidth)) {
143        return NULL;
144    }
145
146    SkTypeface* face = SkNEW_ARGS(FontConfigTypeface, (style, isFixedWidth, stream));
147    return face;
148}
149
150SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
151    SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
152    return stream.get() ? CreateTypefaceFromStream(stream) : NULL;
153}
154
155#endif
156
157///////////////////////////////////////////////////////////////////////////////
158
159SkStream* FontConfigTypeface::onOpenStream(int* ttcIndex) const {
160    SkStream* stream = this->getLocalStream();
161    if (stream) {
162        // should have been provided by CreateFromStream()
163        *ttcIndex = 0;
164
165        SkAutoTUnref<SkStream> dupStream(stream->duplicate());
166        if (dupStream) {
167            return dupStream.detach();
168        }
169
170        // TODO: update interface use, remove the following code in this block.
171        size_t length = stream->getLength();
172
173        const void* memory = stream->getMemoryBase();
174        if (NULL != memory) {
175            return new SkMemoryStream(memory, length, true);
176        }
177
178        SkAutoTMalloc<uint8_t> allocMemory(length);
179        stream->rewind();
180        if (length == stream->read(allocMemory.get(), length)) {
181            SkAutoTUnref<SkMemoryStream> copyStream(new SkMemoryStream());
182            copyStream->setMemoryOwned(allocMemory.detach(), length);
183            return copyStream.detach();
184        }
185
186        stream->rewind();
187        stream->ref();
188    } else {
189        SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
190        if (NULL == fci.get()) {
191            return NULL;
192        }
193        stream = fci->openStream(this->getIdentity());
194        *ttcIndex = this->getIdentity().fTTCIndex;
195    }
196    return stream;
197}
198
199void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
200                                             bool* isLocalStream) const {
201    desc->setFamilyName(this->getFamilyName());
202    *isLocalStream = SkToBool(this->getLocalStream());
203}
204
205SkTypeface* FontConfigTypeface::onRefMatchingStyle(Style style) const {
206    return LegacyCreateTypeface(this, NULL, style);
207}
208