| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkFontConfigInterface.h" | 8 #include "../ports/SkFontMgr_FontConfigInterface.cpp" |
| 9 #include "SkFontConfigTypeface.h" | |
| 10 #include "SkFontDescriptor.h" | |
| 11 #include "SkFontMgr.h" | |
| 12 #include "SkFontStyle.h" | |
| 13 #include "SkMutex.h" | |
| 14 #include "SkString.h" | |
| 15 #include "SkTypeface.h" | |
| 16 #include "SkTypefaceCache.h" | |
| 17 #include "SkResourceCache.h" | |
| 18 | |
| 19 SkStreamAsset* SkTypeface_FCI::onOpenStream(int* ttcIndex) const { | |
| 20 *ttcIndex = this->getIdentity().fTTCIndex; | |
| 21 | |
| 22 SkStreamAsset* stream = this->getLocalStream(); | |
| 23 if (stream) { | |
| 24 return stream->duplicate(); | |
| 25 } | |
| 26 | |
| 27 return fFCI->openStream(this->getIdentity()); | |
| 28 } | |
| 29 | |
| 30 void SkTypeface_FCI::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocalSt
ream) const { | |
| 31 SkString name; | |
| 32 this->getFamilyName(&name); | |
| 33 desc->setFamilyName(name.c_str()); | |
| 34 desc->setStyle(this->fontStyle()); | |
| 35 *isLocalStream = SkToBool(this->getLocalStream()); | |
| 36 } | |
| 37 | |
| 38 /////////////////////////////////////////////////////////////////////////////// | |
| 39 | |
| 40 class SkFontStyleSet_FCI : public SkFontStyleSet { | |
| 41 public: | |
| 42 SkFontStyleSet_FCI() {} | |
| 43 | |
| 44 int count() override { return 0; } | |
| 45 void getStyle(int index, SkFontStyle*, SkString* style) override { SkASSERT(
false); } | |
| 46 SkTypeface* createTypeface(int index) override { SkASSERT(false); return nul
lptr; } | |
| 47 SkTypeface* matchStyle(const SkFontStyle& pattern) override { return nullptr
; } | |
| 48 }; | |
| 49 | |
| 50 /////////////////////////////////////////////////////////////////////////////// | |
| 51 | |
| 52 class SkFontRequestCache { | |
| 53 public: | |
| 54 struct Request : public SkResourceCache::Key { | |
| 55 private: | |
| 56 Request(const char* name, size_t nameLen, const SkFontStyle& style) : fS
tyle(style) { | |
| 57 /** Pointer to just after the last field of this class. */ | |
| 58 char* content = const_cast<char*>(SkTAfter<const char>(&this->fStyle
)); | |
| 59 | |
| 60 // No holes. | |
| 61 SkASSERT(SkTAddOffset<char>(this, sizeof(SkResourceCache::Key) + key
Size) == content); | |
| 62 | |
| 63 // Has a size divisible by size of uint32_t. | |
| 64 SkASSERT((content - reinterpret_cast<char*>(this)) % sizeof(uint32_t
) == 0); | |
| 65 | |
| 66 size_t contentLen = SkAlign4(nameLen); | |
| 67 sk_careful_memcpy(content, name, nameLen); | |
| 68 sk_bzero(content + nameLen, contentLen - nameLen); | |
| 69 this->init(nullptr, 0, keySize + contentLen); | |
| 70 } | |
| 71 const SkFontStyle fStyle; | |
| 72 /** The sum of the sizes of the fields of this class. */ | |
| 73 static const size_t keySize = sizeof(fStyle); | |
| 74 | |
| 75 public: | |
| 76 static Request* Create(const char* name, const SkFontStyle& style) { | |
| 77 size_t nameLen = name ? strlen(name) : 0; | |
| 78 size_t contentLen = SkAlign4(nameLen); | |
| 79 char* storage = new char[sizeof(Request) + contentLen]; | |
| 80 return new (storage) Request(name, nameLen, style); | |
| 81 } | |
| 82 void operator delete(void* storage) { | |
| 83 delete[] reinterpret_cast<char*>(storage); | |
| 84 } | |
| 85 }; | |
| 86 | |
| 87 | |
| 88 private: | |
| 89 struct Result : public SkResourceCache::Rec { | |
| 90 Result(Request* request, SkTypeface* typeface) | |
| 91 : fRequest(request) | |
| 92 , fFace(SkSafeRef(typeface)) {} | |
| 93 Result(Result&&) = default; | |
| 94 Result& operator=(Result&&) = default; | |
| 95 | |
| 96 const Key& getKey() const override { return *fRequest; } | |
| 97 size_t bytesUsed() const override { return fRequest->size() + sizeof(fFa
ce); } | |
| 98 const char* getCategory() const override { return "request_cache"; } | |
| 99 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { r
eturn nullptr; } | |
| 100 | |
| 101 SkAutoTDelete<Request> fRequest; | |
| 102 SkAutoTUnref<SkTypeface> fFace; | |
| 103 }; | |
| 104 | |
| 105 SkResourceCache fCachedResults; | |
| 106 | |
| 107 public: | |
| 108 SkFontRequestCache(size_t maxSize) : fCachedResults(maxSize) {} | |
| 109 | |
| 110 /** Takes ownership of request. It will be deleted when no longer needed. */ | |
| 111 void add(SkTypeface* face, Request* request) { | |
| 112 fCachedResults.add(new Result(request, face)); | |
| 113 } | |
| 114 /** Does not take ownership of request. */ | |
| 115 SkTypeface* findAndRef(Request* request) { | |
| 116 SkTypeface* face = nullptr; | |
| 117 fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void*
context) -> bool { | |
| 118 const Result& result = static_cast<const Result&>(rec); | |
| 119 SkTypeface** face = static_cast<SkTypeface**>(context); | |
| 120 | |
| 121 *face = result.fFace; | |
| 122 return true; | |
| 123 }, &face); | |
| 124 return SkSafeRef(face); | |
| 125 } | |
| 126 }; | |
| 127 | |
| 128 /////////////////////////////////////////////////////////////////////////////// | |
| 129 | |
| 130 static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { | |
| 131 typedef SkFontConfigInterface::FontIdentity FontIdentity; | |
| 132 SkTypeface_FCI* cachedFCTypeface = static_cast<SkTypeface_FCI*>(cachedTypefa
ce); | |
| 133 FontIdentity* identity = static_cast<FontIdentity*>(ctx); | |
| 134 | |
| 135 return cachedFCTypeface->getIdentity() == *identity; | |
| 136 } | |
| 137 | |
| 138 /////////////////////////////////////////////////////////////////////////////// | |
| 139 | |
| 140 class SkFontMgr_FCI : public SkFontMgr { | |
| 141 SkAutoTUnref<SkFontConfigInterface> fFCI; | |
| 142 SkAutoTUnref<SkDataTable> fFamilyNames; | |
| 143 SkTypeface_FreeType::Scanner fScanner; | |
| 144 | |
| 145 mutable SkMutex fMutex; | |
| 146 mutable SkTypefaceCache fTFCache; | |
| 147 | |
| 148 // The value of maxSize here is a compromise between cache hits and cache si
ze. | |
| 149 // See https://crbug.com/424082#63 for reason for current size. | |
| 150 static const size_t kMaxSize = 1 << 15; | |
| 151 mutable SkFontRequestCache fCache; | |
| 152 | |
| 153 public: | |
| 154 SkFontMgr_FCI(SkFontConfigInterface* fci) | |
| 155 : fFCI(fci) | |
| 156 , fFamilyNames(fFCI->getFamilyNames()) | |
| 157 , fCache(kMaxSize) | |
| 158 {} | |
| 159 | |
| 160 protected: | |
| 161 int onCountFamilies() const override { | |
| 162 return fFamilyNames->count(); | |
| 163 } | |
| 164 | |
| 165 void onGetFamilyName(int index, SkString* familyName) const override { | |
| 166 familyName->set(fFamilyNames->atStr(index)); | |
| 167 } | |
| 168 | |
| 169 SkFontStyleSet* onCreateStyleSet(int index) const override { | |
| 170 return this->onMatchFamily(fFamilyNames->atStr(index)); | |
| 171 } | |
| 172 | |
| 173 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { | |
| 174 return new SkFontStyleSet_FCI(); | |
| 175 } | |
| 176 | |
| 177 SkTypeface* onMatchFamilyStyle(const char familyName[], | |
| 178 const SkFontStyle&) const override { return n
ullptr; } | |
| 179 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFon
tStyle&, | |
| 180 const char* bcp47[], int bcp47Count, | |
| 181 SkUnichar character) const override
{ | |
| 182 return nullptr; | |
| 183 } | |
| 184 SkTypeface* onMatchFaceStyle(const SkTypeface*, | |
| 185 const SkFontStyle&) const override { return nul
lptr; } | |
| 186 | |
| 187 SkTypeface* onCreateFromData(SkData*, int ttcIndex) const override { return
nullptr; } | |
| 188 | |
| 189 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) cons
t override { | |
| 190 SkAutoTDelete<SkStreamAsset> stream(bareStream); | |
| 191 const size_t length = stream->getLength(); | |
| 192 if (!length) { | |
| 193 return nullptr; | |
| 194 } | |
| 195 if (length >= 1024 * 1024 * 1024) { | |
| 196 return nullptr; // don't accept too large fonts (>= 1GB) for safety
. | |
| 197 } | |
| 198 | |
| 199 // TODO should the caller give us the style or should we get it from fre
etype? | |
| 200 SkFontStyle style; | |
| 201 bool isFixedWidth = false; | |
| 202 if (!fScanner.scanFont(stream, 0, nullptr, &style, &isFixedWidth, nullpt
r)) { | |
| 203 return nullptr; | |
| 204 } | |
| 205 | |
| 206 return SkTypeface_FCI::Create(style, isFixedWidth, stream.release(), ttc
Index); | |
| 207 } | |
| 208 | |
| 209 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override
{ | |
| 210 SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path)); | |
| 211 return stream.get() ? this->createFromStream(stream.release(), ttcIndex)
: nullptr; | |
| 212 } | |
| 213 | |
| 214 SkTypeface* onLegacyCreateTypeface(const char requestedFamilyName[], | |
| 215 SkFontStyle requestedStyle) const overrid
e | |
| 216 { | |
| 217 SkAutoMutexAcquire ama(fMutex); | |
| 218 | |
| 219 // Check if this request is already in the request cache. | |
| 220 using Request = SkFontRequestCache::Request; | |
| 221 SkAutoTDelete<Request> request(Request::Create(requestedFamilyName, requ
estedStyle)); | |
| 222 SkTypeface* face = fCache.findAndRef(request); | |
| 223 if (face) { | |
| 224 return face; | |
| 225 } | |
| 226 | |
| 227 SkFontConfigInterface::FontIdentity identity; | |
| 228 SkString outFamilyName; | |
| 229 SkFontStyle outStyle; | |
| 230 if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, | |
| 231 &identity, &outFamilyName, &outStyle)) | |
| 232 { | |
| 233 return nullptr; | |
| 234 } | |
| 235 | |
| 236 // Check if a typeface with this FontIdentity is already in the FontIden
tity cache. | |
| 237 face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); | |
| 238 if (!face) { | |
| 239 face = SkTypeface_FCI::Create(fFCI, identity, outFamilyName, outStyl
e); | |
| 240 // Add this FontIdentity to the FontIdentity cache. | |
| 241 fTFCache.add(face); | |
| 242 } | |
| 243 // Add this request to the request cache. | |
| 244 fCache.add(face, request.release()); | |
| 245 | |
| 246 return face; | |
| 247 } | |
| 248 }; | |
| 249 | |
| 250 SK_API SkFontMgr* SkFontMgr_New_FCI(SkFontConfigInterface* fci) { | |
| 251 SkASSERT(fci); | |
| 252 return new SkFontMgr_FCI(fci); | |
| 253 } | |
| OLD | NEW |