• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 class SkData;
18 class SkString;
19 
20 class SkStyleSet_Indirect : public SkFontStyleSet {
21 public:
22     /** Takes ownership of the SkRemotableFontIdentitySet. */
SkStyleSet_Indirect(const SkFontMgr_Indirect * owner,int familyIndex,SkRemotableFontIdentitySet * data)23     SkStyleSet_Indirect(const SkFontMgr_Indirect* owner, int familyIndex,
24                         SkRemotableFontIdentitySet* data)
25         : fOwner(SkRef(owner)), fFamilyIndex(familyIndex), fData(data)
26     { }
27 
count()28     virtual int count() SK_OVERRIDE { return fData->count(); }
29 
getStyle(int index,SkFontStyle * fs,SkString * style)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 
createTypeface(int index)40     virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
41         return fOwner->createTypefaceFromFontId(fData->at(index));
42     }
43 
matchStyle(const SkFontStyle & pattern)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     }
147 private:
148     SkAutoTUnref<const SkFontMgr_Indirect> fOwner;
149     int fFamilyIndex;
150     SkAutoTUnref<SkRemotableFontIdentitySet> fData;
151 };
152 
set_up_family_names(const SkFontMgr_Indirect * self)153 void SkFontMgr_Indirect::set_up_family_names(const SkFontMgr_Indirect* self) {
154     self->fFamilyNames.reset(self->fProxy->getFamilyNames());
155 }
156 
onCountFamilies() const157 int SkFontMgr_Indirect::onCountFamilies() const {
158     SkOnce(&fFamilyNamesInited, &fFamilyNamesMutex, SkFontMgr_Indirect::set_up_family_names, this);
159     return fFamilyNames->count();
160 }
161 
onGetFamilyName(int index,SkString * familyName) const162 void 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 
onCreateStyleSet(int index) const171 SkFontStyleSet* 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 
onMatchFamily(const char familyName[]) const179 SkFontStyleSet* SkFontMgr_Indirect::onMatchFamily(const char familyName[]) const {
180     return SkNEW_ARGS(SkStyleSet_Indirect, (this, -1, fProxy->matchName(familyName)));
181 }
182 
createTypefaceFromFontId(const SkFontIdentity & id) const183 SkTypeface* 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 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontStyle) const242 SkTypeface* 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
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const249 SkTypeface* 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
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char bcp47[],SkUnichar character) const259 SkTypeface* 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 
onMatchFaceStyle(const SkTypeface * familyMember,const SkFontStyle & fontStyle) const268 SkTypeface* 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 
onCreateFromStream(SkStream * stream,int ttcIndex) const275 SkTypeface* SkFontMgr_Indirect::onCreateFromStream(SkStream* stream, int ttcIndex) const {
276     return fImpl->createFromStream(stream, ttcIndex);
277 }
278 
onCreateFromFile(const char path[],int ttcIndex) const279 SkTypeface* SkFontMgr_Indirect::onCreateFromFile(const char path[], int ttcIndex) const {
280     return fImpl->createFromFile(path, ttcIndex);
281 }
282 
onCreateFromData(SkData * data,int ttcIndex) const283 SkTypeface* SkFontMgr_Indirect::onCreateFromData(SkData* data, int ttcIndex) const {
284     return fImpl->createFromData(data, ttcIndex);
285 }
286 
onLegacyCreateTypeface(const char familyName[],unsigned styleBits) const287 SkTypeface* 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