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 21SkStreamAsset* 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().release(); 30 } 31 32 return fFCI->openStream(this->getIdentity()); 33} 34 35std::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 45void 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 55class SkFontStyleSet_FCI : public SkFontStyleSet { 56public: 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 67class SkFontRequestCache { 68public: 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 103private: 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 122public: 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 145static 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 155class 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 167public: 168 SkFontMgr_FCI(sk_sp<SkFontConfigInterface> fci) 169 : fFCI(std::move(fci)) 170 , fCache(kMaxSize) 171 {} 172 173protected: 174 int onCountFamilies() const override { 175 return 0; 176 } 177 178 void onGetFamilyName(int index, SkString* familyName) const override { 179 SK_ABORT("Not implemented."); 180 } 181 182 SkFontStyleSet* onCreateStyleSet(int index) const override { 183 SK_ABORT("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 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override { return nullptr; } 202 203 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream, 204 int ttcIndex) const override { 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 sk_sp<SkTypeface>(SkTypeface_FCI::Create(std::move(fontData), std::move(name), 223 style, isFixedPitch)); 224 } 225 226 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream, 227 const SkFontArguments& args) const override { 228 using Scanner = SkTypeface_FreeType::Scanner; 229 const size_t length = stream->getLength(); 230 if (!length) { 231 return nullptr; 232 } 233 if (length >= 1024 * 1024 * 1024) { 234 return nullptr; // don't accept too large fonts (>= 1GB) for safety. 235 } 236 237 bool isFixedPitch; 238 SkFontStyle style; 239 SkString name; 240 Scanner::AxisDefinitions axisDefinitions; 241 if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(), 242 &name, &style, &isFixedPitch, &axisDefinitions)) 243 { 244 return nullptr; 245 } 246 247 SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); 248 Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(), 249 axisValues, name); 250 251 auto fontData = skstd::make_unique<SkFontData>(std::move(stream), 252 args.getCollectionIndex(), 253 axisValues.get(), 254 axisDefinitions.count()); 255 return sk_sp<SkTypeface>(SkTypeface_FCI::Create(std::move(fontData), std::move(name), 256 style, isFixedPitch)); 257 } 258 259 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override { 260 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path); 261 return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr; 262 } 263 264 sk_sp<SkTypeface> onLegacyMakeTypeface(const char requestedFamilyName[], 265 SkFontStyle requestedStyle) const override 266 { 267 SkAutoMutexAcquire ama(fMutex); 268 269 // Check if this request is already in the request cache. 270 using Request = SkFontRequestCache::Request; 271 std::unique_ptr<Request> request(Request::Create(requestedFamilyName, requestedStyle)); 272 SkTypeface* face = fCache.findAndRef(request.get()); 273 if (face) { 274 return sk_sp<SkTypeface>(face); 275 } 276 277 SkFontConfigInterface::FontIdentity identity; 278 SkString outFamilyName; 279 SkFontStyle outStyle; 280 if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, 281 &identity, &outFamilyName, &outStyle)) 282 { 283 return nullptr; 284 } 285 286 // Check if a typeface with this FontIdentity is already in the FontIdentity cache. 287 face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); 288 if (!face) { 289 face = SkTypeface_FCI::Create(fFCI, identity, std::move(outFamilyName), outStyle); 290 // Add this FontIdentity to the FontIdentity cache. 291 fTFCache.add(face); 292 } 293 // Add this request to the request cache. 294 fCache.add(face, request.release()); 295 296 return sk_sp<SkTypeface>(face); 297 } 298}; 299 300SK_API sk_sp<SkFontMgr> SkFontMgr_New_FCI(sk_sp<SkFontConfigInterface> fci) { 301 SkASSERT(fci); 302 return sk_make_sp<SkFontMgr_FCI>(std::move(fci)); 303} 304