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_indirect.h"
9
10#include "SkDataTable.h"
11#include "SkFontStyle.h"
12#include "SkOnce.h"
13#include "SkStream.h"
14#include "SkTSearch.h"
15#include "SkTypeface.h"
16
17class SkData;
18class SkString;
19
20class SkStyleSet_Indirect : public SkFontStyleSet {
21public:
22    /** Takes ownership of the SkRemotableFontIdentitySet. */
23    SkStyleSet_Indirect(const SkFontMgr_Indirect* owner, int familyIndex,
24                        SkRemotableFontIdentitySet* data)
25        : fOwner(SkRef(owner)), fFamilyIndex(familyIndex), fData(data)
26    { }
27
28    virtual int count() SK_OVERRIDE { return fData->count(); }
29
30    virtual void getStyle(int index, SkFontStyle* fs, SkString* style) SK_OVERRIDE {
31        if (fs) {
32            *fs = fData->at(index).fFontStyle;
33        }
34        if (style) {
35            // TODO: is this useful? Current locale?
36            style->reset();
37        }
38    }
39
40    virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
41        return fOwner->createTypefaceFromFontId(fData->at(index));
42    }
43
44    virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
45        if (fFamilyIndex >= 0) {
46            SkFontIdentity id = fOwner->fProxy->matchIndexStyle(fFamilyIndex, pattern);
47            return fOwner->createTypefaceFromFontId(id);
48        }
49
50        // If this SkStyleSet was created via onMatchFamily we would need a call like
51        // fOwner->fProxy->matchNameStyle(fFamilyName, pattern);
52        // but would not activate fonts (only consider fonts which would come back from matchName).
53
54        // CSS policy sounds good.
55        struct Score {
56            int score;
57            int index;
58        };
59
60        // Width has the greatest priority.
61        // If the value of pattern.width is 5 (normal) or less,
62        //    narrower width values are checked first, then wider values.
63        // If the value of pattern.width is greater than 5 (normal),
64        //    wider values are checked first, followed by narrower values.
65
66        // Italic/Oblique has the next highest priority.
67        // If italic requested and there is some italic font, use it.
68        // If oblique requested and there is some oblique font, use it.
69        // If italic requested and there is some oblique font, use it.
70        // If oblique requested and there is some italic font, use it.
71
72        // Exact match.
73        // If pattern.weight < 400, weights below pattern.weight are checked
74        //   in descending order followed by weights above pattern.weight
75        //   in ascending order until a match is found.
76        // If pattern.weight > 500, weights above pattern.weight are checked
77        //   in ascending order followed by weights below pattern.weight
78        //   in descending order until a match is found.
79        // If pattern.weight is 400, 500 is checked first
80        //   and then the rule for pattern.weight < 400 is used.
81        // If pattern.weight is 500, 400 is checked first
82        //   and then the rule for pattern.weight < 400 is used
83
84        Score maxScore = { 0, 0 };
85        for (int i = 0; i < fData->count(); ++i) {
86            const SkFontStyle& current = fData->at(i).fFontStyle;
87            Score currentScore = { 0, i };
88
89            // CSS stretch. (This is the width.)
90            // This has the highest priority.
91            if (pattern.width() <= SkFontStyle::kNormal_Width) {
92                if (current.width() <= pattern.width()) {
93                    currentScore.score += 10 - pattern.width() + current.width();
94                } else {
95                    currentScore.score += 10 - current.width();
96                }
97            } else {
98                if (current.width() > pattern.width()) {
99                    currentScore.score += 10 + pattern.width() - current.width();
100                } else {
101                    currentScore.score += current.width();
102                }
103            }
104            currentScore.score *= 1002;
105
106            // CSS style (italic/oblique)
107            // Being italic trumps all valid weights which are not italic.
108            // Note that newer specs differentiate between italic and oblique.
109            if (pattern.isItalic() && current.isItalic()) {
110                currentScore.score += 1001;
111            }
112
113            // Synthetics (weight/style) [no stretch synthetic?]
114
115            // The 'closer' to the target weight, the higher the score.
116            // 1000 is the 'heaviest' recognized weight
117            if (pattern.weight() == current.weight()) {
118                currentScore.score += 1000;
119            } else if (pattern.weight() <= 500) {
120                if (pattern.weight() >= 400 && pattern.weight() < 450) {
121                    if (current.weight() >= 450 && current.weight() <= 500) {
122                        // Artificially boost the 500 weight.
123                        // TODO: determine correct number to use.
124                        currentScore.score += 500;
125                    }
126                }
127                if (current.weight() <= pattern.weight()) {
128                    currentScore.score += 1000 - pattern.weight() + current.weight();
129                } else {
130                    currentScore.score += 1000 - current.weight();
131                }
132            } else if (pattern.weight() > 500) {
133                if (current.weight() > pattern.weight()) {
134                    currentScore.score += 1000 + pattern.weight() - current.weight();
135                } else {
136                    currentScore.score += current.weight();
137                }
138            }
139
140            if (currentScore.score > maxScore.score) {
141                maxScore = currentScore;
142            }
143        }
144
145        return this->createTypeface(maxScore.index);
146    }
147private:
148    SkAutoTUnref<const SkFontMgr_Indirect> fOwner;
149    int fFamilyIndex;
150    SkAutoTUnref<SkRemotableFontIdentitySet> fData;
151};
152
153void SkFontMgr_Indirect::set_up_family_names(const SkFontMgr_Indirect* self) {
154    self->fFamilyNames.reset(self->fProxy->getFamilyNames());
155}
156
157int SkFontMgr_Indirect::onCountFamilies() const {
158    SkOnce(&fFamilyNamesInited, &fFamilyNamesMutex, SkFontMgr_Indirect::set_up_family_names, this);
159    return fFamilyNames->count();
160}
161
162void SkFontMgr_Indirect::onGetFamilyName(int index, SkString* familyName) const {
163    SkOnce(&fFamilyNamesInited, &fFamilyNamesMutex, SkFontMgr_Indirect::set_up_family_names, this);
164    if (index >= fFamilyNames->count()) {
165        familyName->reset();
166        return;
167    }
168    familyName->set(fFamilyNames->atStr(index));
169}
170
171SkFontStyleSet* SkFontMgr_Indirect::onCreateStyleSet(int index) const {
172    SkRemotableFontIdentitySet* set = fProxy->getIndex(index);
173    if (NULL == set) {
174        return NULL;
175    }
176    return SkNEW_ARGS(SkStyleSet_Indirect, (this, index, set));
177}
178
179SkFontStyleSet* SkFontMgr_Indirect::onMatchFamily(const char familyName[]) const {
180    return SkNEW_ARGS(SkStyleSet_Indirect, (this, -1, fProxy->matchName(familyName)));
181}
182
183SkTypeface* SkFontMgr_Indirect::createTypefaceFromFontId(const SkFontIdentity& id) const {
184    if (id.fDataId == SkFontIdentity::kInvalidDataId) {
185        return NULL;
186    }
187
188    SkAutoMutexAcquire ama(fDataCacheMutex);
189
190    SkAutoTUnref<SkTypeface> dataTypeface;
191    int dataTypefaceIndex = 0;
192    for (int i = 0; i < fDataCache.count(); ++i) {
193        const DataEntry& entry = fDataCache[i];
194        if (entry.fDataId == id.fDataId) {
195            if (entry.fTtcIndex == id.fTtcIndex &&
196                !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref())
197            {
198                return entry.fTypeface;
199            }
200            if (dataTypeface.get() == NULL &&
201                !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref())
202            {
203                dataTypeface.reset(entry.fTypeface);
204                dataTypefaceIndex = entry.fTtcIndex;
205            }
206        }
207
208        if (entry.fTypeface->weak_expired()) {
209            fDataCache.removeShuffle(i);
210            --i;
211        }
212    }
213
214    // No exact match, but did find a data match.
215    if (dataTypeface.get() != NULL) {
216        SkAutoTUnref<SkStream> stream(dataTypeface->openStream(NULL));
217        if (stream.get() != NULL) {
218            return fImpl->createFromStream(stream.get(), dataTypefaceIndex);
219        }
220    }
221
222    // No data match, request data and add entry.
223    SkAutoTUnref<SkStreamAsset> stream(fProxy->getData(id.fDataId));
224    if (stream.get() == NULL) {
225        return NULL;
226    }
227
228    SkAutoTUnref<SkTypeface> typeface(fImpl->createFromStream(stream, id.fTtcIndex));
229    if (typeface.get() == NULL) {
230        return NULL;
231    }
232
233    DataEntry& newEntry = fDataCache.push_back();
234    typeface->weak_ref();
235    newEntry.fDataId = id.fDataId;
236    newEntry.fTtcIndex = id.fTtcIndex;
237    newEntry.fTypeface = typeface.get();  // weak reference passed to new entry.
238
239    return typeface.detach();
240}
241
242SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyle(const char familyName[],
243                                                   const SkFontStyle& fontStyle) const {
244    SkFontIdentity id = fProxy->matchNameStyle(familyName, fontStyle);
245    return this->createTypefaceFromFontId(id);
246}
247
248#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
249SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyleCharacter(const char familyName[],
250                                                            const SkFontStyle& style,
251                                                            const char* bcp47[],
252                                                            int bcp47Count,
253                                                            SkUnichar character) const {
254    SkFontIdentity id = fProxy->matchNameStyleCharacter(familyName, style, bcp47,
255                                                        bcp47Count, character);
256    return this->createTypefaceFromFontId(id);
257}
258#else
259SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyleCharacter(const char familyName[],
260                                                            const SkFontStyle& style,
261                                                            const char bcp47[],
262                                                            SkUnichar character) const {
263    SkFontIdentity id = fProxy->matchNameStyleCharacter(familyName, style, bcp47, character);
264    return this->createTypefaceFromFontId(id);
265}
266#endif
267
268SkTypeface* SkFontMgr_Indirect::onMatchFaceStyle(const SkTypeface* familyMember,
269                                                 const SkFontStyle& fontStyle) const {
270    SkString familyName;
271    familyMember->getFamilyName(&familyName);
272    return this->matchFamilyStyle(familyName.c_str(), fontStyle);
273}
274
275SkTypeface* SkFontMgr_Indirect::onCreateFromStream(SkStream* stream, int ttcIndex) const {
276    return fImpl->createFromStream(stream, ttcIndex);
277}
278
279SkTypeface* SkFontMgr_Indirect::onCreateFromFile(const char path[], int ttcIndex) const {
280    return fImpl->createFromFile(path, ttcIndex);
281}
282
283SkTypeface* SkFontMgr_Indirect::onCreateFromData(SkData* data, int ttcIndex) const {
284    return fImpl->createFromData(data, ttcIndex);
285}
286
287SkTypeface* SkFontMgr_Indirect::onLegacyCreateTypeface(const char familyName[],
288                                                       unsigned styleBits) const {
289    bool bold = SkToBool(styleBits & SkTypeface::kBold);
290    bool italic = SkToBool(styleBits & SkTypeface::kItalic);
291    SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight
292                                         : SkFontStyle::kNormal_Weight,
293                                    SkFontStyle::kNormal_Width,
294                                    italic ? SkFontStyle::kItalic_Slant
295                                           : SkFontStyle::kUpright_Slant);
296
297    SkAutoTUnref<SkTypeface> face(this->matchFamilyStyle(familyName, style));
298
299    if (NULL == face.get()) {
300        face.reset(this->matchFamilyStyle(NULL, style));
301    }
302
303    if (NULL == face.get()) {
304        SkFontIdentity fontId = this->fProxy->matchIndexStyle(0, style);
305        face.reset(this->createTypefaceFromFontId(fontId));
306    }
307
308    return face.detach();
309}
310