1/* 2 * Copyright 2008 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 "SkStream.h" 12#include "SkTemplates.h" 13#include "SkTypeface.h" 14#include "SkTypefaceCache.h" 15#include "SkResourceCache.h" 16 17/////////////////////////////////////////////////////////////////////////////// 18/////////////////////////////////////////////////////////////////////////////// 19 20SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex); 21static SkFontConfigInterface* gFontConfigInterface; 22 23SkFontConfigInterface* SkFontConfigInterface::RefGlobal() { 24 SkAutoMutexAcquire ac(gFontConfigInterfaceMutex); 25 26 return SkSafeRef(gFontConfigInterface); 27} 28 29SkFontConfigInterface* SkFontConfigInterface::SetGlobal(SkFontConfigInterface* fc) { 30 SkAutoMutexAcquire ac(gFontConfigInterfaceMutex); 31 32 SkRefCnt_SafeAssign(gFontConfigInterface, fc); 33 return fc; 34} 35 36/////////////////////////////////////////////////////////////////////////////// 37/////////////////////////////////////////////////////////////////////////////// 38 39// convenience function to create the direct interface if none is installed. 40extern SkFontConfigInterface* SkCreateDirectFontConfigInterface(); 41 42static SkFontConfigInterface* RefFCI() { 43 for (;;) { 44 SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal(); 45 if (fci) { 46 return fci; 47 } 48 fci = SkFontConfigInterface::GetSingletonDirectInterface(&gFontConfigInterfaceMutex); 49 SkFontConfigInterface::SetGlobal(fci); 50 } 51} 52 53// export this to SkFontMgr_fontconfig.cpp until this file just goes away. 54SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); 55SkFontConfigInterface* SkFontHost_fontconfig_ref_global() { 56 return RefFCI(); 57} 58 59/////////////////////////////////////////////////////////////////////////////// 60 61static bool find_by_FontIdentity(SkTypeface* cachedTypeface, const SkFontStyle&, void* ctx) { 62 typedef SkFontConfigInterface::FontIdentity FontIdentity; 63 FontConfigTypeface* cachedFCTypeface = static_cast<FontConfigTypeface*>(cachedTypeface); 64 FontIdentity* identity = static_cast<FontIdentity*>(ctx); 65 66 return cachedFCTypeface->getIdentity() == *identity; 67} 68 69SK_DECLARE_STATIC_MUTEX(gSkFontHostRequestCacheMutex); 70class SkFontHostRequestCache { 71 72 // The value of maxSize here is a compromise between cache hits and cache size. 73 static const size_t gMaxSize = 1 << 12; 74 75 static SkFontHostRequestCache& Get() { 76 gSkFontHostRequestCacheMutex.assertHeld(); 77 static SkFontHostRequestCache gCache(gMaxSize); 78 return gCache; 79 } 80 81public: 82 struct Request : public SkResourceCache::Key { 83 private: 84 Request(const char* name, size_t nameLen, const SkFontStyle& style) : fStyle(style) { 85 /** Pointer to just after the last field of this class. */ 86 char* content = const_cast<char*>(SkTAfter<const char>(&this->fStyle)); 87 88 // No holes. 89 SkASSERT(SkTAddOffset<char>(this, sizeof(SkResourceCache::Key) + keySize) == content); 90 91 // Has a size divisible by size of uint32_t. 92 SkASSERT((content - reinterpret_cast<char*>(this)) % sizeof(uint32_t) == 0); 93 94 size_t contentLen = SkAlign4(nameLen); 95 sk_careful_memcpy(content, name, nameLen); 96 sk_bzero(content + nameLen, contentLen - nameLen); 97 this->init(&gSkFontHostRequestCacheMutex, 0, keySize + contentLen); 98 } 99 const SkFontStyle fStyle; 100 /** The sum of the sizes of the fields of this class. */ 101 static const size_t keySize = sizeof(fStyle); 102 103 public: 104 static Request* Create(const char* name, const SkFontStyle& style) { 105 size_t nameLen = name ? strlen(name) : 0; 106 size_t contentLen = SkAlign4(nameLen); 107 char* storage = new char[sizeof(Request) + contentLen]; 108 return new (storage) Request(name, nameLen, style); 109 } 110 void operator delete(void* storage) { 111 delete[] reinterpret_cast<char*>(storage); 112 } 113 }; 114 115 116private: 117 struct Result : public SkResourceCache::Rec { 118 Result(Request* request, SkTypeface* typeface) 119 : fRequest(request) 120 , fFace(SkSafeRef(typeface)) {} 121 Result(Result&&) = default; 122 Result& operator=(Result&&) = default; 123 124 const Key& getKey() const override { return *fRequest; } 125 size_t bytesUsed() const override { return fRequest->size() + sizeof(fFace); } 126 const char* getCategory() const override { return "request_cache"; } 127 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; } 128 129 SkAutoTDelete<Request> fRequest; 130 SkAutoTUnref<SkTypeface> fFace; 131 }; 132 133 SkResourceCache fCachedResults; 134 135public: 136 SkFontHostRequestCache(size_t maxSize) : fCachedResults(maxSize) {} 137 138 /** Takes ownership of request. It will be deleted when no longer needed. */ 139 void add(SkTypeface* face, Request* request) { 140 fCachedResults.add(new Result(request, face)); 141 } 142 /** Does not take ownership of request. */ 143 SkTypeface* findAndRef(Request* request) { 144 SkTypeface* face = nullptr; 145 fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void* context) -> bool { 146 const Result& result = static_cast<const Result&>(rec); 147 SkTypeface** face = static_cast<SkTypeface**>(context); 148 149 *face = result.fFace; 150 return true; 151 }, &face); 152 return SkSafeRef(face); 153 } 154 155 /** Takes ownership of request. It will be deleted when no longer needed. */ 156 static void Add(SkTypeface* face, Request* request) { 157 SkAutoMutexAcquire ama(gSkFontHostRequestCacheMutex); 158 Get().add(face, request); 159 } 160 161 /** Does not take ownership of request. */ 162 static SkTypeface* FindAndRef(Request* request) { 163 SkAutoMutexAcquire ama(gSkFontHostRequestCacheMutex); 164 return Get().findAndRef(request); 165 } 166}; 167 168SkTypeface* FontConfigTypeface::LegacyCreateTypeface(const char requestedFamilyName[], 169 SkTypeface::Style requestedOldStyle) 170{ 171 SkAutoTUnref<SkFontConfigInterface> fci(RefFCI()); 172 if (nullptr == fci.get()) { 173 return nullptr; 174 } 175 176 // Check if this request is already in the request cache. 177 using Request = SkFontHostRequestCache::Request; 178 SkFontStyle requestedStyle(requestedOldStyle); 179 SkAutoTDelete<Request> request(Request::Create(requestedFamilyName, requestedStyle)); 180 SkTypeface* face = SkFontHostRequestCache::FindAndRef(request); 181 if (face) { 182 return face; 183 } 184 185 SkFontConfigInterface::FontIdentity identity; 186 SkString outFamilyName; 187 SkTypeface::Style outOldStyle; 188 if (!fci->matchFamilyName(requestedFamilyName, requestedOldStyle, 189 &identity, &outFamilyName, &outOldStyle)) 190 { 191 return nullptr; 192 } 193 194 // Check if a typeface with this FontIdentity is already in the FontIdentity cache. 195 face = SkTypefaceCache::FindByProcAndRef(find_by_FontIdentity, &identity); 196 if (!face) { 197 face = FontConfigTypeface::Create(SkFontStyle(outOldStyle), identity, outFamilyName); 198 // Add this FontIdentity to the FontIdentity cache. 199 SkTypefaceCache::Add(face, SkFontStyle(outOldStyle)); 200 } 201 // Add this request to the request cache. 202 SkFontHostRequestCache::Add(face, request.release()); 203 204 return face; 205} 206 207/////////////////////////////////////////////////////////////////////////////// 208 209SkStreamAsset* FontConfigTypeface::onOpenStream(int* ttcIndex) const { 210 SkStreamAsset* stream = this->getLocalStream(); 211 if (stream) { 212 // TODO: should have been provided by CreateFromStream() 213 *ttcIndex = 0; 214 return stream->duplicate(); 215 } 216 217 SkAutoTUnref<SkFontConfigInterface> fci(RefFCI()); 218 if (nullptr == fci.get()) { 219 return nullptr; 220 } 221 222 *ttcIndex = this->getIdentity().fTTCIndex; 223 return fci->openStream(this->getIdentity()); 224} 225 226void FontConfigTypeface::onGetFamilyName(SkString* familyName) const { 227 *familyName = fFamilyName; 228} 229 230void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc, 231 bool* isLocalStream) const { 232 SkString name; 233 this->getFamilyName(&name); 234 desc->setFamilyName(name.c_str()); 235 *isLocalStream = SkToBool(this->getLocalStream()); 236} 237