1 /* 2 * Copyright 2013 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 "SkFontConfigInterface.h" 9 #include "SkFontConfigTypeface.h" 10 #include "SkFontDescriptor.h" 11 #include "SkFontMgr.h" 12 #include "SkFontMgr_FontConfigInterface.h" 13 #include "SkFontStyle.h" 14 #include "SkMakeUnique.h" 15 #include "SkMutex.h" 16 #include "SkString.h" 17 #include "SkTypeface.h" 18 #include "SkTypefaceCache.h" 19 #include "SkResourceCache.h" 20 21 SkStreamAsset* SkTypeface_FCI::onOpenStream(int* ttcIndex) const { 22 *ttcIndex = this->getIdentity().fTTCIndex; 23 24 if (fFontData) { 25 SkStreamAsset* stream = fFontData->getStream(); 26 if (!stream) { 27 return nullptr; 28 } 29 return stream->duplicate(); 30 } 31 32 return fFCI->openStream(this->getIdentity()); 33 } 34 35 std::unique_ptr<SkFontData> SkTypeface_FCI::onMakeFontData() const { 36 if (fFontData) { 37 return skstd::make_unique<SkFontData>(*fFontData); 38 } 39 40 const SkFontConfigInterface::FontIdentity& id = this->getIdentity(); 41 return skstd::make_unique<SkFontData>(std::unique_ptr<SkStreamAsset>(fFCI->openStream(id)), 42 id.fTTCIndex, nullptr, 0); 43 } 44 45 void SkTypeface_FCI::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocalStream) const { 46 SkString name; 47 this->getFamilyName(&name); 48 desc->setFamilyName(name.c_str()); 49 desc->setStyle(this->fontStyle()); 50 *isLocalStream = SkToBool(fFontData); 51 } 52 53 /////////////////////////////////////////////////////////////////////////////// 54 55 class SkFontStyleSet_FCI : public SkFontStyleSet { 56 public: 57 SkFontStyleSet_FCI() {} 58 59 int count() override { return 0; } 60 void getStyle(int index, SkFontStyle*, SkString* style) override { SkASSERT(false); } 61 SkTypeface* createTypeface(int index) override { SkASSERT(false); return nullptr; } 62 SkTypeface* matchStyle(const SkFontStyle& pattern) override { return nullptr; } 63 }; 64 65 /////////////////////////////////////////////////////////////////////////////// 66 67 class SkFontRequestCache { 68 public: 69 struct Request : public SkResourceCache::Key { 70 private: 71 Request(const char* name, size_t nameLen, const SkFontStyle& style) : fStyle(style) { 72 /** Pointer to just after the last field of this class. */ 73 char* content = const_cast<char*>(SkTAfter<const char>(&this->fStyle)); 74 75 // No holes. 76 SkASSERT(SkTAddOffset<char>(this, sizeof(SkResourceCache::Key) + keySize) == content); 77 78 // Has a size divisible by size of uint32_t. 79 SkASSERT((content - reinterpret_cast<char*>(this)) % sizeof(uint32_t) == 0); 80 81 size_t contentLen = SkAlign4(nameLen); 82 sk_careful_memcpy(content, name, nameLen); 83 sk_bzero(content + nameLen, contentLen - nameLen); 84 this->init(nullptr, 0, keySize + contentLen); 85 } 86 const SkFontStyle fStyle; 87 /** The sum of the sizes of the fields of this class. */ 88 static const size_t keySize = sizeof(fStyle); 89 90 public: 91 static Request* Create(const char* name, const SkFontStyle& style) { 92 size_t nameLen = name ? strlen(name) : 0; 93 size_t contentLen = SkAlign4(nameLen); 94 char* storage = new char[sizeof(Request) + contentLen]; 95 return new (storage) Request(name, nameLen, style); 96 } 97 void operator delete(void* storage) { 98 delete[] reinterpret_cast<char*>(storage); 99 } 100 }; 101 102 103 private: 104 struct Result : public SkResourceCache::Rec { 105 Result(Request* request, SkTypeface* typeface) 106 : fRequest(request) 107 , fFace(SkSafeRef(typeface)) {} 108 Result(Result&&) = default; 109 Result& operator=(Result&&) = default; 110 111 const Key& getKey() const override { return *fRequest; } 112 size_t bytesUsed() const override { return fRequest->size() + sizeof(fFace); } 113 const char* getCategory() const override { return "request_cache"; } 114 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; } 115 116 std::unique_ptr<Request> fRequest; 117 sk_sp<SkTypeface> fFace; 118 }; 119 120 SkResourceCache fCachedResults; 121 122 public: 123 SkFontRequestCache(size_t maxSize) : fCachedResults(maxSize) {} 124 125 /** Takes ownership of request. It will be deleted when no longer needed. */ 126 void add(SkTypeface* face, Request* request) { 127 fCachedResults.add(new Result(request, face)); 128 } 129 /** Does not take ownership of request. */ 130 SkTypeface* findAndRef(Request* request) { 131 SkTypeface* face = nullptr; 132 fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void* context) -> bool { 133 const Result& result = static_cast<const Result&>(rec); 134 SkTypeface** face = static_cast<SkTypeface**>(context); 135 136 *face = result.fFace.get(); 137 return true; 138 }, &face); 139 return SkSafeRef(face); 140 } 141 }; 142 143 /////////////////////////////////////////////////////////////////////////////// 144 145 static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { 146 typedef SkFontConfigInterface::FontIdentity FontIdentity; 147 SkTypeface_FCI* cachedFCTypeface = static_cast<SkTypeface_FCI*>(cachedTypeface); 148 FontIdentity* identity = static_cast<FontIdentity*>(ctx); 149 150 return cachedFCTypeface->getIdentity() == *identity; 151 } 152 153 /////////////////////////////////////////////////////////////////////////////// 154 155 class SkFontMgr_FCI : public SkFontMgr { 156 sk_sp<SkFontConfigInterface> fFCI; 157 SkTypeface_FreeType::Scanner fScanner; 158 159 mutable SkMutex fMutex; 160 mutable SkTypefaceCache fTFCache; 161 162 // The value of maxSize here is a compromise between cache hits and cache size. 163 // See https://crbug.com/424082#63 for reason for current size. 164 static const size_t kMaxSize = 1 << 15; 165 mutable SkFontRequestCache fCache; 166 167 public: 168 SkFontMgr_FCI(sk_sp<SkFontConfigInterface> fci) 169 : fFCI(std::move(fci)) 170 , fCache(kMaxSize) 171 {} 172 173 protected: 174 int onCountFamilies() const override { 175 return 0; 176 } 177 178 void onGetFamilyName(int index, SkString* familyName) const override { 179 SkFAIL("Not implemented."); 180 } 181 182 SkFontStyleSet* onCreateStyleSet(int index) const override { 183 SkFAIL("Not implemented."); 184 return nullptr; 185 } 186 187 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { 188 return new SkFontStyleSet_FCI(); 189 } 190 191 SkTypeface* onMatchFamilyStyle(const char familyName[], 192 const SkFontStyle&) const override { return nullptr; } 193 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, 194 const char* bcp47[], int bcp47Count, 195 SkUnichar character) const override { 196 return nullptr; 197 } 198 SkTypeface* onMatchFaceStyle(const SkTypeface*, 199 const SkFontStyle&) const override { return nullptr; } 200 201 SkTypeface* onCreateFromData(SkData*, int ttcIndex) const override { return nullptr; } 202 203 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override { 204 std::unique_ptr<SkStreamAsset> stream(bareStream); 205 const size_t length = stream->getLength(); 206 if (!length) { 207 return nullptr; 208 } 209 if (length >= 1024 * 1024 * 1024) { 210 return nullptr; // don't accept too large fonts (>= 1GB) for safety. 211 } 212 213 // TODO should the caller give us the style or should we get it from freetype? 214 SkString name; 215 SkFontStyle style; 216 bool isFixedPitch = false; 217 if (!fScanner.scanFont(stream.get(), 0, &name, &style, &isFixedPitch, nullptr)) { 218 return nullptr; 219 } 220 221 auto fontData = skstd::make_unique<SkFontData>(std::move(stream), ttcIndex, nullptr, 0); 222 return SkTypeface_FCI::Create(std::move(fontData), std::move(name), style, isFixedPitch); 223 } 224 225 SkTypeface* onCreateFromStream(SkStreamAsset* s, const SkFontArguments& args) const override { 226 using Scanner = SkTypeface_FreeType::Scanner; 227 std::unique_ptr<SkStreamAsset> stream(s); 228 const size_t length = stream->getLength(); 229 if (!length) { 230 return nullptr; 231 } 232 if (length >= 1024 * 1024 * 1024) { 233 return nullptr; // don't accept too large fonts (>= 1GB) for safety. 234 } 235 236 bool isFixedPitch; 237 SkFontStyle style; 238 SkString name; 239 Scanner::AxisDefinitions axisDefinitions; 240 if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(), 241 &name, &style, &isFixedPitch, &axisDefinitions)) 242 { 243 return nullptr; 244 } 245 246 SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); 247 Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(), 248 axisValues, name); 249 250 auto fontData = skstd::make_unique<SkFontData>(std::move(stream), 251 args.getCollectionIndex(), 252 axisValues.get(), 253 axisDefinitions.count()); 254 return SkTypeface_FCI::Create(std::move(fontData), std::move(name), style, isFixedPitch); 255 } 256 257 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { 258 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path); 259 return stream.get() ? this->createFromStream(stream.release(), ttcIndex) : nullptr; 260 } 261 262 SkTypeface* onLegacyCreateTypeface(const char requestedFamilyName[], 263 SkFontStyle requestedStyle) const override 264 { 265 SkAutoMutexAcquire ama(fMutex); 266 267 // Check if this request is already in the request cache. 268 using Request = SkFontRequestCache::Request; 269 std::unique_ptr<Request> request(Request::Create(requestedFamilyName, requestedStyle)); 270 SkTypeface* face = fCache.findAndRef(request.get()); 271 if (face) { 272 return face; 273 } 274 275 SkFontConfigInterface::FontIdentity identity; 276 SkString outFamilyName; 277 SkFontStyle outStyle; 278 if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, 279 &identity, &outFamilyName, &outStyle)) 280 { 281 return nullptr; 282 } 283 284 // Check if a typeface with this FontIdentity is already in the FontIdentity cache. 285 face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); 286 if (!face) { 287 face = SkTypeface_FCI::Create(fFCI, identity, std::move(outFamilyName), outStyle); 288 // Add this FontIdentity to the FontIdentity cache. 289 fTFCache.add(face); 290 } 291 // Add this request to the request cache. 292 fCache.add(face, request.release()); 293 294 return face; 295 } 296 }; 297 298 SK_API sk_sp<SkFontMgr> SkFontMgr_New_FCI(sk_sp<SkFontConfigInterface> fci) { 299 SkASSERT(fci); 300 return sk_make_sp<SkFontMgr_FCI>(std::move(fci)); 301 } 302