1/*
2 * Copyright 2014 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 "SkFontMgr.h"
9#include "SkFontMgr_indirect.h"
10#include "SkFontStyle.h"
11#include "SkMutex.h"
12#include "SkOnce.h"
13#include "SkRefCnt.h"
14#include "SkRemotableFontMgr.h"
15#include "SkStream.h"
16#include "SkString.h"
17#include "SkTArray.h"
18#include "SkTypeface.h"
19#include "SkTypes.h"
20#include "SkTemplates.h"
21
22class SkData;
23
24class SkStyleSet_Indirect : public SkFontStyleSet {
25public:
26    /** Takes ownership of the SkRemotableFontIdentitySet. */
27    SkStyleSet_Indirect(const SkFontMgr_Indirect* owner, int familyIndex,
28                        SkRemotableFontIdentitySet* data)
29        : fOwner(SkRef(owner)), fFamilyIndex(familyIndex), fData(data)
30    { }
31
32    int count() override { return fData->count(); }
33
34    void getStyle(int index, SkFontStyle* fs, SkString* style) override {
35        if (fs) {
36            *fs = fData->at(index).fFontStyle;
37        }
38        if (style) {
39            // TODO: is this useful? Current locale?
40            style->reset();
41        }
42    }
43
44    SkTypeface* createTypeface(int index) override {
45        return fOwner->createTypefaceFromFontId(fData->at(index));
46    }
47
48    SkTypeface* matchStyle(const SkFontStyle& pattern) override {
49        if (fFamilyIndex >= 0) {
50            SkFontIdentity id = fOwner->fProxy->matchIndexStyle(fFamilyIndex, pattern);
51            return fOwner->createTypefaceFromFontId(id);
52        }
53
54        return this->matchStyleCSS3(pattern);
55    }
56private:
57    sk_sp<const SkFontMgr_Indirect> fOwner;
58    int fFamilyIndex;
59    sk_sp<SkRemotableFontIdentitySet> fData;
60};
61
62int SkFontMgr_Indirect::onCountFamilies() const {
63    return 0;
64}
65
66void SkFontMgr_Indirect::onGetFamilyName(int index, SkString* familyName) const {
67    SkFAIL("Not implemented");
68}
69
70SkFontStyleSet* SkFontMgr_Indirect::onCreateStyleSet(int index) const {
71    SkFAIL("Not implemented");
72    return nullptr;
73}
74
75SkFontStyleSet* SkFontMgr_Indirect::onMatchFamily(const char familyName[]) const {
76    return new SkStyleSet_Indirect(this, -1, fProxy->matchName(familyName));
77}
78
79SkTypeface* SkFontMgr_Indirect::createTypefaceFromFontId(const SkFontIdentity& id) const {
80    if (id.fDataId == SkFontIdentity::kInvalidDataId) {
81        return nullptr;
82    }
83
84    SkAutoMutexAcquire ama(fDataCacheMutex);
85
86    sk_sp<SkTypeface> dataTypeface;
87    int dataTypefaceIndex = 0;
88    for (int i = 0; i < fDataCache.count(); ++i) {
89        const DataEntry& entry = fDataCache[i];
90        if (entry.fDataId == id.fDataId) {
91            if (entry.fTtcIndex == id.fTtcIndex &&
92                !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref())
93            {
94                return entry.fTypeface;
95            }
96            if (dataTypeface.get() == nullptr &&
97                !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref())
98            {
99                dataTypeface.reset(entry.fTypeface);
100                dataTypefaceIndex = entry.fTtcIndex;
101            }
102        }
103
104        if (entry.fTypeface->weak_expired()) {
105            fDataCache.removeShuffle(i);
106            --i;
107        }
108    }
109
110    // No exact match, but did find a data match.
111    if (dataTypeface.get() != nullptr) {
112        std::unique_ptr<SkStreamAsset> stream(dataTypeface->openStream(nullptr));
113        if (stream.get() != nullptr) {
114            return fImpl->createFromStream(stream.release(), dataTypefaceIndex);
115        }
116    }
117
118    // No data match, request data and add entry.
119    std::unique_ptr<SkStreamAsset> stream(fProxy->getData(id.fDataId));
120    if (stream.get() == nullptr) {
121        return nullptr;
122    }
123
124    sk_sp<SkTypeface> typeface(fImpl->createFromStream(stream.release(), id.fTtcIndex));
125    if (typeface.get() == nullptr) {
126        return nullptr;
127    }
128
129    DataEntry& newEntry = fDataCache.push_back();
130    typeface->weak_ref();
131    newEntry.fDataId = id.fDataId;
132    newEntry.fTtcIndex = id.fTtcIndex;
133    newEntry.fTypeface = typeface.get();  // weak reference passed to new entry.
134
135    return typeface.release();
136}
137
138SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyle(const char familyName[],
139                                                   const SkFontStyle& fontStyle) const {
140    SkFontIdentity id = fProxy->matchNameStyle(familyName, fontStyle);
141    return this->createTypefaceFromFontId(id);
142}
143
144SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyleCharacter(const char familyName[],
145                                                            const SkFontStyle& style,
146                                                            const char* bcp47[],
147                                                            int bcp47Count,
148                                                            SkUnichar character) const {
149    SkFontIdentity id = fProxy->matchNameStyleCharacter(familyName, style, bcp47,
150                                                        bcp47Count, character);
151    return this->createTypefaceFromFontId(id);
152}
153
154SkTypeface* SkFontMgr_Indirect::onMatchFaceStyle(const SkTypeface* familyMember,
155                                                 const SkFontStyle& fontStyle) const {
156    SkString familyName;
157    familyMember->getFamilyName(&familyName);
158    return this->matchFamilyStyle(familyName.c_str(), fontStyle);
159}
160
161SkTypeface* SkFontMgr_Indirect::onCreateFromStream(SkStreamAsset* stream, int ttcIndex) const {
162    return fImpl->createFromStream(stream, ttcIndex);
163}
164
165SkTypeface* SkFontMgr_Indirect::onCreateFromFile(const char path[], int ttcIndex) const {
166    return fImpl->createFromFile(path, ttcIndex);
167}
168
169SkTypeface* SkFontMgr_Indirect::onCreateFromData(SkData* data, int ttcIndex) const {
170    return fImpl->createFromData(data, ttcIndex);
171}
172
173SkTypeface* SkFontMgr_Indirect::onLegacyCreateTypeface(const char familyName[],
174                                                       SkFontStyle style) const {
175    sk_sp<SkTypeface> face(this->matchFamilyStyle(familyName, style));
176
177    if (nullptr == face.get()) {
178        face.reset(this->matchFamilyStyle(nullptr, style));
179    }
180
181    if (nullptr == face.get()) {
182        SkFontIdentity fontId = this->fProxy->matchIndexStyle(0, style);
183        face.reset(this->createTypefaceFromFontId(fontId));
184    }
185
186    return face.release();
187}
188