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 "include/core/SkFontMgr.h" 9#include "include/core/SkFontStyle.h" 10#include "include/core/SkString.h" 11#include "include/core/SkTypeface.h" 12#include "include/ports/SkFontConfigInterface.h" 13#include "include/ports/SkFontMgr_FontConfigInterface.h" 14#include "include/private/SkMutex.h" 15#include "src/core/SkFontDescriptor.h" 16#include "src/core/SkResourceCache.h" 17#include "src/core/SkTypefaceCache.h" 18#include "src/ports/SkFontConfigTypeface.h" 19#include <new> 20 21std::unique_ptr<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 std::unique_ptr<SkStreamAsset>(fFCI->openStream(this->getIdentity())); 33} 34 35std::unique_ptr<SkFontData> SkTypeface_FCI::onMakeFontData() const { 36 if (fFontData) { 37 return std::make_unique<SkFontData>(*fFontData); 38 } 39 40 const SkFontConfigInterface::FontIdentity& id = this->getIdentity(); 41 return std::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, sk_sp<SkTypeface> typeface) 106 : fRequest(request), fFace(std::move(typeface)) {} 107 Result(Result&&) = default; 108 Result& operator=(Result&&) = default; 109 110 const Key& getKey() const override { return *fRequest; } 111 size_t bytesUsed() const override { return fRequest->size() + sizeof(fFace); } 112 const char* getCategory() const override { return "request_cache"; } 113 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; } 114 115 std::unique_ptr<Request> fRequest; 116 sk_sp<SkTypeface> fFace; 117 }; 118 119 SkResourceCache fCachedResults; 120 121public: 122 SkFontRequestCache(size_t maxSize) : fCachedResults(maxSize) {} 123 124 /** Takes ownership of request. It will be deleted when no longer needed. */ 125 void add(sk_sp<SkTypeface> face, Request* request) { 126 fCachedResults.add(new Result(request, std::move(face))); 127 } 128 /** Does not take ownership of request. */ 129 sk_sp<SkTypeface> findAndRef(Request* request) { 130 sk_sp<SkTypeface> face; 131 fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void* context) -> bool { 132 const Result& result = static_cast<const Result&>(rec); 133 sk_sp<SkTypeface>* face = static_cast<sk_sp<SkTypeface>*>(context); 134 135 *face = result.fFace; 136 return true; 137 }, &face); 138 return face; 139 } 140}; 141 142/////////////////////////////////////////////////////////////////////////////// 143 144static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { 145 typedef SkFontConfigInterface::FontIdentity FontIdentity; 146 SkTypeface_FCI* cachedFCTypeface = static_cast<SkTypeface_FCI*>(cachedTypeface); 147 FontIdentity* identity = static_cast<FontIdentity*>(ctx); 148 149 return cachedFCTypeface->getIdentity() == *identity; 150} 151 152/////////////////////////////////////////////////////////////////////////////// 153 154class SkFontMgr_FCI : public SkFontMgr { 155 sk_sp<SkFontConfigInterface> fFCI; 156 SkTypeface_FreeType::Scanner fScanner; 157 158 mutable SkMutex fMutex; 159 mutable SkTypefaceCache fTFCache; 160 161 // The value of maxSize here is a compromise between cache hits and cache size. 162 // See https://crbug.com/424082#63 for reason for current size. 163 static const size_t kMaxSize = 1 << 15; 164 mutable SkFontRequestCache fCache; 165 166public: 167 SkFontMgr_FCI(sk_sp<SkFontConfigInterface> fci) 168 : fFCI(std::move(fci)) 169 , fCache(kMaxSize) 170 {} 171 172protected: 173 int onCountFamilies() const override { 174 SK_ABORT("Not implemented."); 175 } 176 177 void onGetFamilyName(int index, SkString* familyName) const override { 178 SK_ABORT("Not implemented."); 179 } 180 181 SkFontStyleSet* onCreateStyleSet(int index) const override { 182 SK_ABORT("Not implemented."); 183 } 184 185 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { 186 SK_ABORT("Not implemented."); 187 } 188 189 SkTypeface* onMatchFamilyStyle(const char requestedFamilyName[], 190 const SkFontStyle& requestedStyle) const override 191 { 192 SkAutoMutexExclusive ama(fMutex); 193 194 SkFontConfigInterface::FontIdentity identity; 195 SkString outFamilyName; 196 SkFontStyle outStyle; 197 if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, 198 &identity, &outFamilyName, &outStyle)) 199 { 200 return nullptr; 201 } 202 203 // Check if a typeface with this FontIdentity is already in the FontIdentity cache. 204 sk_sp<SkTypeface> face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); 205 if (!face) { 206 face.reset(SkTypeface_FCI::Create(fFCI, identity, std::move(outFamilyName), outStyle)); 207 // Add this FontIdentity to the FontIdentity cache. 208 fTFCache.add(face); 209 } 210 return face.release(); 211 } 212 213 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, 214 const char* bcp47[], int bcp47Count, 215 SkUnichar character) const override { 216 SK_ABORT("Not implemented."); 217 } 218 219 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override { 220 return this->onMakeFromStreamIndex(SkMemoryStream::Make(std::move(data)), ttcIndex); 221 } 222 223 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream, 224 int ttcIndex) const override { 225 const size_t length = stream->getLength(); 226 if (!length) { 227 return nullptr; 228 } 229 if (length >= 1024 * 1024 * 1024) { 230 return nullptr; // don't accept too large fonts (>= 1GB) for safety. 231 } 232 233 // TODO should the caller give us the style or should we get it from freetype? 234 SkString name; 235 SkFontStyle style; 236 bool isFixedPitch = false; 237 if (!fScanner.scanFont(stream.get(), 0, &name, &style, &isFixedPitch, nullptr)) { 238 return nullptr; 239 } 240 241 auto fontData = std::make_unique<SkFontData>(std::move(stream), ttcIndex, nullptr, 0); 242 return sk_sp<SkTypeface>(SkTypeface_FCI::Create(std::move(fontData), std::move(name), 243 style, isFixedPitch)); 244 } 245 246 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream, 247 const SkFontArguments& args) const override { 248 using Scanner = SkTypeface_FreeType::Scanner; 249 const size_t length = stream->getLength(); 250 if (!length) { 251 return nullptr; 252 } 253 if (length >= 1024 * 1024 * 1024) { 254 return nullptr; // don't accept too large fonts (>= 1GB) for safety. 255 } 256 257 SkString name; 258 SkFontStyle style; 259 bool isFixedPitch = false; 260 Scanner::AxisDefinitions axisDefinitions; 261 if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(), 262 &name, &style, &isFixedPitch, &axisDefinitions)) 263 { 264 return nullptr; 265 } 266 267 SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); 268 Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(), 269 axisValues, name); 270 271 auto fontData = std::make_unique<SkFontData>(std::move(stream), 272 args.getCollectionIndex(), 273 axisValues.get(), 274 axisDefinitions.count()); 275 return sk_sp<SkTypeface>(SkTypeface_FCI::Create(std::move(fontData), std::move(name), 276 style, isFixedPitch)); 277 } 278 279 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override { 280 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path); 281 return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr; 282 } 283 284 sk_sp<SkTypeface> onLegacyMakeTypeface(const char requestedFamilyName[], 285 SkFontStyle requestedStyle) const override 286 { 287 SkAutoMutexExclusive ama(fMutex); 288 289 // Check if this request is already in the request cache. 290 using Request = SkFontRequestCache::Request; 291 std::unique_ptr<Request> request(Request::Create(requestedFamilyName, requestedStyle)); 292 sk_sp<SkTypeface> face = fCache.findAndRef(request.get()); 293 if (face) { 294 return sk_sp<SkTypeface>(face); 295 } 296 297 SkFontConfigInterface::FontIdentity identity; 298 SkString outFamilyName; 299 SkFontStyle outStyle; 300 if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, 301 &identity, &outFamilyName, &outStyle)) 302 { 303 return nullptr; 304 } 305 306 // Check if a typeface with this FontIdentity is already in the FontIdentity cache. 307 face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); 308 if (!face) { 309 face.reset(SkTypeface_FCI::Create(fFCI, identity, std::move(outFamilyName), outStyle)); 310 // Add this FontIdentity to the FontIdentity cache. 311 fTFCache.add(face); 312 } 313 // Add this request to the request cache. 314 fCache.add(face, request.release()); 315 316 return face; 317 } 318}; 319 320SK_API sk_sp<SkFontMgr> SkFontMgr_New_FCI(sk_sp<SkFontConfigInterface> fci) { 321 SkASSERT(fci); 322 return sk_make_sp<SkFontMgr_FCI>(std::move(fci)); 323} 324