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///////////////////////////////////////////////////////////////////////////////
19///////////////////////////////////////////////////////////////////////////////
20
21SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex);
22static SkFontConfigInterface* gFontConfigInterface;
23
24SkFontConfigInterface* SkFontConfigInterface::RefGlobal() {
25    SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
26
27    return SkSafeRef(gFontConfigInterface);
28}
29
30SkFontConfigInterface* SkFontConfigInterface::SetGlobal(SkFontConfigInterface* fc) {
31    SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
32
33    SkRefCnt_SafeAssign(gFontConfigInterface, fc);
34    return fc;
35}
36
37///////////////////////////////////////////////////////////////////////////////
38///////////////////////////////////////////////////////////////////////////////
39
40// convenience function to create the direct interface if none is installed.
41extern SkFontConfigInterface* SkCreateDirectFontConfigInterface();
42
43static SkFontConfigInterface* RefFCI() {
44    for (;;) {
45        SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal();
46        if (fci) {
47            return fci;
48        }
49        fci = SkFontConfigInterface::GetSingletonDirectInterface(&gFontConfigInterfaceMutex);
50        SkFontConfigInterface::SetGlobal(fci);
51    }
52}
53
54// export this to SkFontMgr_fontconfig.cpp until this file just goes away.
55SkFontConfigInterface* SkFontHost_fontconfig_ref_global();
56SkFontConfigInterface* SkFontHost_fontconfig_ref_global() {
57    return RefFCI();
58}
59
60///////////////////////////////////////////////////////////////////////////////
61
62struct FindRec {
63    FindRec(const char* name, SkTypeface::Style style)
64        : fFamilyName(name)  // don't need to make a deep copy
65        , fStyle(style) {}
66
67    const char* fFamilyName;
68    SkTypeface::Style fStyle;
69};
70
71static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
72    FontConfigTypeface* fci = (FontConfigTypeface*)face;
73    const FindRec* rec = (const FindRec*)ctx;
74
75    return rec->fStyle == style && fci->isFamilyName(rec->fFamilyName);
76}
77
78SkTypeface* FontConfigTypeface::LegacyCreateTypeface(
79                const SkTypeface* familyFace,
80                const char familyName[],
81                SkTypeface::Style style) {
82    SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
83    if (NULL == fci.get()) {
84        return NULL;
85    }
86
87    if (familyFace) {
88        FontConfigTypeface* fct = (FontConfigTypeface*)familyFace;
89        familyName = fct->getFamilyName();
90    }
91
92    FindRec rec(familyName, style);
93    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_proc, &rec);
94    if (face) {
95//        SkDebugf("found cached face <%s> <%s> %p [%d]\n", familyName, ((FontConfigTypeface*)face)->getFamilyName(), face, face->getRefCnt());
96        return face;
97    }
98
99    SkFontConfigInterface::FontIdentity indentity;
100    SkString                            outFamilyName;
101    SkTypeface::Style                   outStyle;
102
103    if (!fci->matchFamilyName(familyName, style,
104                              &indentity, &outFamilyName, &outStyle)) {
105        return NULL;
106    }
107
108    // check if we, in fact, already have this. perhaps fontconfig aliased the
109    // requested name to some other name we actually have...
110    rec.fFamilyName = outFamilyName.c_str();
111    rec.fStyle = outStyle;
112    face = SkTypefaceCache::FindByProcAndRef(find_proc, &rec);
113    if (face) {
114        return face;
115    }
116
117    face = FontConfigTypeface::Create(outStyle, indentity, outFamilyName);
118    SkTypefaceCache::Add(face, style);
119//    SkDebugf("add face <%s> <%s> %p [%d]\n", familyName, outFamilyName.c_str(), face, face->getRefCnt());
120    return face;
121}
122
123///////////////////////////////////////////////////////////////////////////////
124
125SkStream* FontConfigTypeface::onOpenStream(int* ttcIndex) const {
126    SkStream* stream = this->getLocalStream();
127    if (stream) {
128        // should have been provided by CreateFromStream()
129        *ttcIndex = 0;
130
131        SkAutoTUnref<SkStream> dupStream(stream->duplicate());
132        if (dupStream) {
133            return dupStream.detach();
134        }
135
136        // TODO: update interface use, remove the following code in this block.
137        size_t length = stream->getLength();
138
139        const void* memory = stream->getMemoryBase();
140        if (memory) {
141            return new SkMemoryStream(memory, length, true);
142        }
143
144        SkAutoTMalloc<uint8_t> allocMemory(length);
145        stream->rewind();
146        if (length == stream->read(allocMemory.get(), length)) {
147            SkAutoTUnref<SkMemoryStream> copyStream(new SkMemoryStream());
148            copyStream->setMemoryOwned(allocMemory.detach(), length);
149            return copyStream.detach();
150        }
151
152        stream->rewind();
153        stream->ref();
154    } else {
155        SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
156        if (NULL == fci.get()) {
157            return NULL;
158        }
159        stream = fci->openStream(this->getIdentity());
160        *ttcIndex = this->getIdentity().fTTCIndex;
161    }
162    return stream;
163}
164
165void FontConfigTypeface::onGetFamilyName(SkString* familyName) const {
166    *familyName = this->getFamilyName();
167}
168
169void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
170                                             bool* isLocalStream) const {
171    desc->setFamilyName(this->getFamilyName());
172    desc->setFontIndex(this->getIdentity().fTTCIndex);
173    *isLocalStream = SkToBool(this->getLocalStream());
174}
175