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 int count() override { return fData->count(); }
29
getStyle(int index,SkFontStyle * fs,SkString * style)30 void getStyle(int index, SkFontStyle* fs, SkString* style) 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 SkTypeface* createTypeface(int index) override {
41 return fOwner->createTypefaceFromFontId(fData->at(index));
42 }
43
matchStyle(const SkFontStyle & pattern)44 SkTypeface* matchStyle(const SkFontStyle& pattern) 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 SkAutoTDelete<SkStreamAsset> stream(dataTypeface->openStream(NULL));
217 if (stream.get() != NULL) {
218 return fImpl->createFromStream(stream.detach(), dataTypefaceIndex);
219 }
220 }
221
222 // No data match, request data and add entry.
223 SkAutoTDelete<SkStreamAsset> stream(fProxy->getData(id.fDataId));
224 if (stream.get() == NULL) {
225 return NULL;
226 }
227
228 SkAutoTUnref<SkTypeface> typeface(fImpl->createFromStream(stream.detach(), 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
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const248 SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyleCharacter(const char familyName[],
249 const SkFontStyle& style,
250 const char* bcp47[],
251 int bcp47Count,
252 SkUnichar character) const {
253 SkFontIdentity id = fProxy->matchNameStyleCharacter(familyName, style, bcp47,
254 bcp47Count, character);
255 return this->createTypefaceFromFontId(id);
256 }
257
onMatchFaceStyle(const SkTypeface * familyMember,const SkFontStyle & fontStyle) const258 SkTypeface* SkFontMgr_Indirect::onMatchFaceStyle(const SkTypeface* familyMember,
259 const SkFontStyle& fontStyle) const {
260 SkString familyName;
261 familyMember->getFamilyName(&familyName);
262 return this->matchFamilyStyle(familyName.c_str(), fontStyle);
263 }
264
onCreateFromStream(SkStreamAsset * stream,int ttcIndex) const265 SkTypeface* SkFontMgr_Indirect::onCreateFromStream(SkStreamAsset* stream, int ttcIndex) const {
266 return fImpl->createFromStream(stream, ttcIndex);
267 }
268
onCreateFromFile(const char path[],int ttcIndex) const269 SkTypeface* SkFontMgr_Indirect::onCreateFromFile(const char path[], int ttcIndex) const {
270 return fImpl->createFromFile(path, ttcIndex);
271 }
272
onCreateFromData(SkData * data,int ttcIndex) const273 SkTypeface* SkFontMgr_Indirect::onCreateFromData(SkData* data, int ttcIndex) const {
274 return fImpl->createFromData(data, ttcIndex);
275 }
276
onLegacyCreateTypeface(const char familyName[],unsigned styleBits) const277 SkTypeface* SkFontMgr_Indirect::onLegacyCreateTypeface(const char familyName[],
278 unsigned styleBits) const {
279 bool bold = SkToBool(styleBits & SkTypeface::kBold);
280 bool italic = SkToBool(styleBits & SkTypeface::kItalic);
281 SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight
282 : SkFontStyle::kNormal_Weight,
283 SkFontStyle::kNormal_Width,
284 italic ? SkFontStyle::kItalic_Slant
285 : SkFontStyle::kUpright_Slant);
286
287 SkAutoTUnref<SkTypeface> face(this->matchFamilyStyle(familyName, style));
288
289 if (NULL == face.get()) {
290 face.reset(this->matchFamilyStyle(NULL, style));
291 }
292
293 if (NULL == face.get()) {
294 SkFontIdentity fontId = this->fProxy->matchIndexStyle(0, style);
295 face.reset(this->createTypefaceFromFontId(fontId));
296 }
297
298 return face.detach();
299 }
300