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. */ 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 } 147 private: 148 SkAutoTUnref<const SkFontMgr_Indirect> fOwner; 149 int fFamilyIndex; 150 SkAutoTUnref<SkRemotableFontIdentitySet> fData; 151 }; 152 153 void SkFontMgr_Indirect::set_up_family_names(const SkFontMgr_Indirect* self) { 154 self->fFamilyNames.reset(self->fProxy->getFamilyNames()); 155 } 156 157 int SkFontMgr_Indirect::onCountFamilies() const { 158 SkOnce(&fFamilyNamesInited, &fFamilyNamesMutex, SkFontMgr_Indirect::set_up_family_names, this); 159 return fFamilyNames->count(); 160 } 161 162 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 171 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 179 SkFontStyleSet* SkFontMgr_Indirect::onMatchFamily(const char familyName[]) const { 180 return SkNEW_ARGS(SkStyleSet_Indirect, (this, -1, fProxy->matchName(familyName))); 181 } 182 183 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 242 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 249 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 259 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 268 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 275 SkTypeface* SkFontMgr_Indirect::onCreateFromStream(SkStream* stream, int ttcIndex) const { 276 return fImpl->createFromStream(stream, ttcIndex); 277 } 278 279 SkTypeface* SkFontMgr_Indirect::onCreateFromFile(const char path[], int ttcIndex) const { 280 return fImpl->createFromFile(path, ttcIndex); 281 } 282 283 SkTypeface* SkFontMgr_Indirect::onCreateFromData(SkData* data, int ttcIndex) const { 284 return fImpl->createFromData(data, ttcIndex); 285 } 286 287 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