| 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 "SkFontConfigInterface.h" |
| 9 #include "SkFontConfigTypeface.h" | 9 #include "SkFontConfigTypeface.h" |
| 10 #include "SkFontDescriptor.h" |
| 10 #include "SkFontMgr.h" | 11 #include "SkFontMgr.h" |
| 11 #include "SkFontStyle.h" | 12 #include "SkFontStyle.h" |
| 12 #include "SkMath.h" | |
| 13 #include "SkMutex.h" | 13 #include "SkMutex.h" |
| 14 #include "SkString.h" | 14 #include "SkString.h" |
| 15 #include "SkTDArray.h" | 15 #include "SkTypeface.h" |
| 16 #include "SkTypefaceCache.h" |
| 17 #include "SkResourceCache.h" |
| 16 | 18 |
| 17 // for now we pull these in directly. eventually we will solely rely on the | 19 SkStreamAsset* SkTypeface_FCI::onOpenStream(int* ttcIndex) const { |
| 18 // SkFontConfigInterface instance. | 20 *ttcIndex = this->getIdentity().fTTCIndex; |
| 19 #include <fontconfig/fontconfig.h> | |
| 20 #include <unistd.h> | |
| 21 | 21 |
| 22 namespace { | 22 SkStreamAsset* stream = this->getLocalStream(); |
| 23 | 23 if (stream) { |
| 24 // Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a glo
bal mutex. | 24 return stream->duplicate(); |
| 25 // See skia:1497 for background. | |
| 26 SK_DECLARE_STATIC_MUTEX(gFCMutex); | |
| 27 static bool gFCSafeToUse; | |
| 28 | |
| 29 struct FCLocker { | |
| 30 FCLocker() { | |
| 31 if (FcGetVersion() < 21091) { // We assume FcGetVersion() has always be
en thread safe. | |
| 32 gFCMutex.acquire(); | |
| 33 fUnlock = true; | |
| 34 } else { | |
| 35 fUnlock = false; | |
| 36 } | |
| 37 gFCSafeToUse = true; | |
| 38 } | 25 } |
| 39 | 26 |
| 40 ~FCLocker() { | 27 return fFCI->openStream(this->getIdentity()); |
| 41 if (fUnlock) { | 28 } |
| 42 gFCSafeToUse = false; | 29 |
| 43 gFCMutex.release(); | 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 *isLocalStream = SkToBool(this->getLocalStream()); |
| 35 } |
| 36 |
| 37 /////////////////////////////////////////////////////////////////////////////// |
| 38 |
| 39 class SkFontStyleSet_FCI : public SkFontStyleSet { |
| 40 public: |
| 41 SkFontStyleSet_FCI() {} |
| 42 |
| 43 int count() override { return 0; } |
| 44 void getStyle(int index, SkFontStyle*, SkString* style) override { SkASSERT(
false); } |
| 45 SkTypeface* createTypeface(int index) override { SkASSERT(false); return nul
lptr; } |
| 46 SkTypeface* matchStyle(const SkFontStyle& pattern) override { return nullptr
; } |
| 47 }; |
| 48 |
| 49 /////////////////////////////////////////////////////////////////////////////// |
| 50 |
| 51 class SkFontRequestCache { |
| 52 public: |
| 53 struct Request : public SkResourceCache::Key { |
| 54 private: |
| 55 Request(const char* name, size_t nameLen, const SkFontStyle& style) : fS
tyle(style) { |
| 56 /** Pointer to just after the last field of this class. */ |
| 57 char* content = const_cast<char*>(SkTAfter<const char>(&this->fStyle
)); |
| 58 |
| 59 // No holes. |
| 60 SkASSERT(SkTAddOffset<char>(this, sizeof(SkResourceCache::Key) + key
Size) == content); |
| 61 |
| 62 // Has a size divisible by size of uint32_t. |
| 63 SkASSERT((content - reinterpret_cast<char*>(this)) % sizeof(uint32_t
) == 0); |
| 64 |
| 65 size_t contentLen = SkAlign4(nameLen); |
| 66 sk_careful_memcpy(content, name, nameLen); |
| 67 sk_bzero(content + nameLen, contentLen - nameLen); |
| 68 this->init(nullptr, 0, keySize + contentLen); |
| 44 } | 69 } |
| 45 } | 70 const SkFontStyle fStyle; |
| 71 /** The sum of the sizes of the fields of this class. */ |
| 72 static const size_t keySize = sizeof(fStyle); |
| 73 |
| 74 public: |
| 75 static Request* Create(const char* name, const SkFontStyle& style) { |
| 76 size_t nameLen = name ? strlen(name) : 0; |
| 77 size_t contentLen = SkAlign4(nameLen); |
| 78 char* storage = new char[sizeof(Request) + contentLen]; |
| 79 return new (storage) Request(name, nameLen, style); |
| 80 } |
| 81 void operator delete(void* storage) { |
| 82 delete[] reinterpret_cast<char*>(storage); |
| 83 } |
| 84 }; |
| 85 |
| 46 | 86 |
| 47 private: | 87 private: |
| 48 bool fUnlock; | 88 struct Result : public SkResourceCache::Rec { |
| 89 Result(Request* request, SkTypeface* typeface) |
| 90 : fRequest(request) |
| 91 , fFace(SkSafeRef(typeface)) {} |
| 92 Result(Result&&) = default; |
| 93 Result& operator=(Result&&) = default; |
| 94 |
| 95 const Key& getKey() const override { return *fRequest; } |
| 96 size_t bytesUsed() const override { return fRequest->size() + sizeof(fFa
ce); } |
| 97 const char* getCategory() const override { return "request_cache"; } |
| 98 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { r
eturn nullptr; } |
| 99 |
| 100 SkAutoTDelete<Request> fRequest; |
| 101 SkAutoTUnref<SkTypeface> fFace; |
| 102 }; |
| 103 |
| 104 SkResourceCache fCachedResults; |
| 105 |
| 106 public: |
| 107 SkFontRequestCache(size_t maxSize) : fCachedResults(maxSize) {} |
| 108 |
| 109 /** Takes ownership of request. It will be deleted when no longer needed. */ |
| 110 void add(SkTypeface* face, Request* request) { |
| 111 fCachedResults.add(new Result(request, face)); |
| 112 } |
| 113 /** Does not take ownership of request. */ |
| 114 SkTypeface* findAndRef(Request* request) { |
| 115 SkTypeface* face = nullptr; |
| 116 fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void*
context) -> bool { |
| 117 const Result& result = static_cast<const Result&>(rec); |
| 118 SkTypeface** face = static_cast<SkTypeface**>(context); |
| 119 |
| 120 *face = result.fFace; |
| 121 return true; |
| 122 }, &face); |
| 123 return SkSafeRef(face); |
| 124 } |
| 49 }; | 125 }; |
| 50 | 126 |
| 51 } // namespace | 127 /////////////////////////////////////////////////////////////////////////////// |
| 52 | 128 |
| 53 // borrow this global from SkFontHost_fontconfig. eventually that file should | 129 static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { |
| 54 // go away, and be replaced with this one. | 130 typedef SkFontConfigInterface::FontIdentity FontIdentity; |
| 55 extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); | 131 SkTypeface_FCI* cachedFCTypeface = static_cast<SkTypeface_FCI*>(cachedTypefa
ce); |
| 56 static SkFontConfigInterface* RefFCI() { | 132 FontIdentity* identity = static_cast<FontIdentity*>(ctx); |
| 57 return SkFontHost_fontconfig_ref_global(); | 133 |
| 134 return cachedFCTypeface->getIdentity() == *identity; |
| 58 } | 135 } |
| 59 | 136 |
| 60 // look for the last substring after a '/' and return that, or return null. | 137 /////////////////////////////////////////////////////////////////////////////// |
| 61 static const char* find_just_name(const char* str) { | |
| 62 const char* last = strrchr(str, '/'); | |
| 63 return last ? last + 1 : nullptr; | |
| 64 } | |
| 65 | 138 |
| 66 static bool is_lower(char c) { | 139 class SkFontMgr_FCI : public SkFontMgr { |
| 67 return c >= 'a' && c <= 'z'; | |
| 68 } | |
| 69 | |
| 70 static int get_int(FcPattern* pattern, const char field[]) { | |
| 71 SkASSERT(gFCSafeToUse); | |
| 72 int value; | |
| 73 if (FcPatternGetInteger(pattern, field, 0, &value) != FcResultMatch) { | |
| 74 value = SK_MinS32; | |
| 75 } | |
| 76 return value; | |
| 77 } | |
| 78 | |
| 79 static const char* get_name(FcPattern* pattern, const char field[]) { | |
| 80 SkASSERT(gFCSafeToUse); | |
| 81 const char* name; | |
| 82 if (FcPatternGetString(pattern, field, 0, (FcChar8**)&name) != FcResultMatch
) { | |
| 83 name = ""; | |
| 84 } | |
| 85 return name; | |
| 86 } | |
| 87 | |
| 88 static bool valid_pattern(FcPattern* pattern) { | |
| 89 SkASSERT(gFCSafeToUse); | |
| 90 FcBool is_scalable; | |
| 91 if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch
|| !is_scalable) { | |
| 92 return false; | |
| 93 } | |
| 94 | |
| 95 // fontconfig can also return fonts which are unreadable | |
| 96 const char* c_filename = get_name(pattern, FC_FILE); | |
| 97 if (0 == *c_filename) { | |
| 98 return false; | |
| 99 } | |
| 100 if (access(c_filename, R_OK) != 0) { | |
| 101 return false; | |
| 102 } | |
| 103 return true; | |
| 104 } | |
| 105 | |
| 106 static bool match_name(FcPattern* pattern, const char family_name[]) { | |
| 107 return !strcasecmp(family_name, get_name(pattern, FC_FAMILY)); | |
| 108 } | |
| 109 | |
| 110 static FcPattern** MatchFont(FcFontSet* font_set, | |
| 111 const char post_config_family[], | |
| 112 int* count) { | |
| 113 // Older versions of fontconfig have a bug where they cannot select | |
| 114 // only scalable fonts so we have to manually filter the results. | |
| 115 | |
| 116 FcPattern** iter = font_set->fonts; | |
| 117 FcPattern** stop = iter + font_set->nfont; | |
| 118 // find the first good match | |
| 119 for (; iter < stop; ++iter) { | |
| 120 if (valid_pattern(*iter)) { | |
| 121 break; | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 if (iter == stop || !match_name(*iter, post_config_family)) { | |
| 126 return nullptr; | |
| 127 } | |
| 128 | |
| 129 FcPattern** firstIter = iter++; | |
| 130 for (; iter < stop; ++iter) { | |
| 131 if (!valid_pattern(*iter) || !match_name(*iter, post_config_family)) { | |
| 132 break; | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 *count = iter - firstIter; | |
| 137 return firstIter; | |
| 138 } | |
| 139 | |
| 140 class SkFontStyleSet_FC : public SkFontStyleSet { | |
| 141 public: | |
| 142 SkFontStyleSet_FC(FcPattern** matches, int count); | |
| 143 virtual ~SkFontStyleSet_FC(); | |
| 144 | |
| 145 int count() override { return fRecCount; } | |
| 146 void getStyle(int index, SkFontStyle*, SkString* style) override; | |
| 147 SkTypeface* createTypeface(int index) override; | |
| 148 SkTypeface* matchStyle(const SkFontStyle& pattern) override; | |
| 149 | |
| 150 private: | |
| 151 struct Rec { | |
| 152 SkString fStyleName; | |
| 153 SkString fFileName; | |
| 154 SkFontStyle fStyle; | |
| 155 }; | |
| 156 Rec* fRecs; | |
| 157 int fRecCount; | |
| 158 }; | |
| 159 | |
| 160 static int map_range(int value, | |
| 161 int old_min, int old_max, int new_min, int new_max) { | |
| 162 SkASSERT(old_min < old_max); | |
| 163 SkASSERT(new_min < new_max); | |
| 164 return new_min + SkMulDiv(value - old_min, | |
| 165 new_max - new_min, old_max - old_min); | |
| 166 } | |
| 167 | |
| 168 static SkFontStyle make_fontconfig_style(FcPattern* match) { | |
| 169 int weight = get_int(match, FC_WEIGHT); | |
| 170 int width = get_int(match, FC_WIDTH); | |
| 171 int fcSlant = get_int(match, FC_SLANT); | |
| 172 | |
| 173 // fontconfig weight seems to be 0..200 or so, so we remap it here | |
| 174 weight = map_range(weight, 0, 80, 0, 400); | |
| 175 width = map_range(width, 0, 200, 0, 9); | |
| 176 SkFontStyle::Slant skSlant = SkFontStyle::kUpright_Slant; | |
| 177 switch (fcSlant) { | |
| 178 case FC_SLANT_ROMAN: skSlant = SkFontStyle::kUpright_Slant; break; | |
| 179 case FC_SLANT_ITALIC : skSlant = SkFontStyle::kItalic_Slant ; break; | |
| 180 case FC_SLANT_OBLIQUE: skSlant = SkFontStyle::kOblique_Slant; break; | |
| 181 default: SkASSERT(false); break; | |
| 182 } | |
| 183 return SkFontStyle(weight, width, skSlant); | |
| 184 } | |
| 185 | |
| 186 SkFontStyleSet_FC::SkFontStyleSet_FC(FcPattern** matches, int count) { | |
| 187 fRecCount = count; | |
| 188 fRecs = new Rec[count]; | |
| 189 for (int i = 0; i < count; ++i) { | |
| 190 fRecs[i].fStyleName.set(get_name(matches[i], FC_STYLE)); | |
| 191 fRecs[i].fFileName.set(get_name(matches[i], FC_FILE)); | |
| 192 fRecs[i].fStyle = make_fontconfig_style(matches[i]); | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 SkFontStyleSet_FC::~SkFontStyleSet_FC() { delete[] fRecs; } | |
| 197 | |
| 198 void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style, | |
| 199 SkString* styleName) { | |
| 200 SkASSERT((unsigned)index < (unsigned)fRecCount); | |
| 201 if (style) { | |
| 202 *style = fRecs[index].fStyle; | |
| 203 } | |
| 204 if (styleName) { | |
| 205 *styleName = fRecs[index].fStyleName; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 SkTypeface* SkFontStyleSet_FC::createTypeface(int index) { | |
| 210 return nullptr; | |
| 211 } | |
| 212 | |
| 213 SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) { | |
| 214 return nullptr; | |
| 215 } | |
| 216 | |
| 217 class SkFontMgr_fontconfig : public SkFontMgr { | |
| 218 SkAutoTUnref<SkFontConfigInterface> fFCI; | 140 SkAutoTUnref<SkFontConfigInterface> fFCI; |
| 219 SkDataTable* fFamilyNames; | 141 SkAutoTUnref<SkDataTable> fFamilyNames; |
| 220 SkTypeface_FreeType::Scanner fScanner; | 142 SkTypeface_FreeType::Scanner fScanner; |
| 221 | 143 |
| 144 mutable SkMutex fMutex; |
| 145 mutable SkTypefaceCache fTFCache; |
| 146 |
| 147 // The value of maxSize here is a compromise between cache hits and cache si
ze. |
| 148 // See https://crbug.com/424082#63 for reason for current size. |
| 149 static const size_t kMaxSize = 1 << 15; |
| 150 mutable SkFontRequestCache fCache; |
| 151 |
| 222 public: | 152 public: |
| 223 SkFontMgr_fontconfig(SkFontConfigInterface* fci) | 153 SkFontMgr_FCI(SkFontConfigInterface* fci) |
| 224 : fFCI(fci) | 154 : fFCI(fci) |
| 225 , fFamilyNames(fFCI->getFamilyNames()) {} | 155 , fFamilyNames(fFCI->getFamilyNames()) |
| 226 | 156 , fCache(kMaxSize) |
| 227 virtual ~SkFontMgr_fontconfig() { | 157 {} |
| 228 SkSafeUnref(fFamilyNames); | |
| 229 } | |
| 230 | 158 |
| 231 protected: | 159 protected: |
| 232 int onCountFamilies() const override { | 160 int onCountFamilies() const override { |
| 233 return fFamilyNames->count(); | 161 return fFamilyNames->count(); |
| 234 } | 162 } |
| 235 | 163 |
| 236 void onGetFamilyName(int index, SkString* familyName) const override { | 164 void onGetFamilyName(int index, SkString* familyName) const override { |
| 237 familyName->set(fFamilyNames->atStr(index)); | 165 familyName->set(fFamilyNames->atStr(index)); |
| 238 } | 166 } |
| 239 | 167 |
| 240 SkFontStyleSet* onCreateStyleSet(int index) const override { | 168 SkFontStyleSet* onCreateStyleSet(int index) const override { |
| 241 return this->onMatchFamily(fFamilyNames->atStr(index)); | 169 return this->onMatchFamily(fFamilyNames->atStr(index)); |
| 242 } | 170 } |
| 243 | 171 |
| 244 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { | 172 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { |
| 245 FCLocker lock; | 173 return new SkFontStyleSet_FCI(); |
| 246 | |
| 247 FcPattern* pattern = FcPatternCreate(); | |
| 248 | |
| 249 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); | |
| 250 #if 0 | |
| 251 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); | |
| 252 #endif | |
| 253 FcConfigSubstitute(nullptr, pattern, FcMatchPattern); | |
| 254 FcDefaultSubstitute(pattern); | |
| 255 | |
| 256 const char* post_config_family = get_name(pattern, FC_FAMILY); | |
| 257 | |
| 258 FcResult result; | |
| 259 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); | |
| 260 if (!font_set) { | |
| 261 FcPatternDestroy(pattern); | |
| 262 return nullptr; | |
| 263 } | |
| 264 | |
| 265 int count; | |
| 266 FcPattern** match = MatchFont(font_set, post_config_family, &count); | |
| 267 if (!match) { | |
| 268 FcPatternDestroy(pattern); | |
| 269 FcFontSetDestroy(font_set); | |
| 270 return nullptr; | |
| 271 } | |
| 272 | |
| 273 FcPatternDestroy(pattern); | |
| 274 | |
| 275 SkTDArray<FcPattern*> trimmedMatches; | |
| 276 for (int i = 0; i < count; ++i) { | |
| 277 const char* justName = find_just_name(get_name(match[i], FC_FILE)); | |
| 278 if (!is_lower(*justName)) { | |
| 279 *trimmedMatches.append() = match[i]; | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 SkFontStyleSet_FC* sset = | |
| 284 new SkFontStyleSet_FC(trimmedMatches.begin(), trimmedMatches.cou
nt()); | |
| 285 return sset; | |
| 286 } | 174 } |
| 287 | 175 |
| 288 SkTypeface* onMatchFamilyStyle(const char familyName[], | 176 SkTypeface* onMatchFamilyStyle(const char familyName[], |
| 289 const SkFontStyle&) const override { return n
ullptr; } | 177 const SkFontStyle&) const override { return n
ullptr; } |
| 290 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFon
tStyle&, | 178 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFon
tStyle&, |
| 291 const char* bcp47[], int bcp47Count, | 179 const char* bcp47[], int bcp47Count, |
| 292 SkUnichar character) const override
{ | 180 SkUnichar character) const override
{ |
| 293 return nullptr; | 181 return nullptr; |
| 294 } | 182 } |
| 295 SkTypeface* onMatchFaceStyle(const SkTypeface*, | 183 SkTypeface* onMatchFaceStyle(const SkTypeface*, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 307 return nullptr; // don't accept too large fonts (>= 1GB) for safety
. | 195 return nullptr; // don't accept too large fonts (>= 1GB) for safety
. |
| 308 } | 196 } |
| 309 | 197 |
| 310 // TODO should the caller give us the style or should we get it from fre
etype? | 198 // TODO should the caller give us the style or should we get it from fre
etype? |
| 311 SkFontStyle style; | 199 SkFontStyle style; |
| 312 bool isFixedWidth = false; | 200 bool isFixedWidth = false; |
| 313 if (!fScanner.scanFont(stream, 0, nullptr, &style, &isFixedWidth, nullpt
r)) { | 201 if (!fScanner.scanFont(stream, 0, nullptr, &style, &isFixedWidth, nullpt
r)) { |
| 314 return nullptr; | 202 return nullptr; |
| 315 } | 203 } |
| 316 | 204 |
| 317 SkTypeface* face = FontConfigTypeface::Create(style, isFixedWidth, strea
m.release()); | 205 return SkTypeface_FCI::Create(style, isFixedWidth, stream.release(), ttc
Index); |
| 318 return face; | |
| 319 } | 206 } |
| 320 | 207 |
| 321 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override
{ | 208 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override
{ |
| 322 SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path)); | 209 SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path)); |
| 323 return stream.get() ? this->createFromStream(stream.release(), ttcIndex)
: nullptr; | 210 return stream.get() ? this->createFromStream(stream.release(), ttcIndex)
: nullptr; |
| 324 } | 211 } |
| 325 | 212 |
| 326 SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle styl
e) const override { | 213 SkTypeface* onLegacyCreateTypeface(const char requestedFamilyName[], |
| 327 FCLocker lock; | 214 SkFontStyle requestedStyle) const overrid
e |
| 328 return FontConfigTypeface::LegacyCreateTypeface(familyName, style); | 215 { |
| 216 SkAutoMutexAcquire ama(fMutex); |
| 217 |
| 218 // Check if this request is already in the request cache. |
| 219 using Request = SkFontRequestCache::Request; |
| 220 SkAutoTDelete<Request> request(Request::Create(requestedFamilyName, requ
estedStyle)); |
| 221 SkTypeface* face = fCache.findAndRef(request); |
| 222 if (face) { |
| 223 return face; |
| 224 } |
| 225 |
| 226 SkFontConfigInterface::FontIdentity identity; |
| 227 SkString outFamilyName; |
| 228 SkFontStyle outStyle; |
| 229 if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, |
| 230 &identity, &outFamilyName, &outStyle)) |
| 231 { |
| 232 return nullptr; |
| 233 } |
| 234 |
| 235 // Check if a typeface with this FontIdentity is already in the FontIden
tity cache. |
| 236 face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); |
| 237 if (!face) { |
| 238 face = SkTypeface_FCI::Create(fFCI, identity, outFamilyName, outStyl
e); |
| 239 // Add this FontIdentity to the FontIdentity cache. |
| 240 fTFCache.add(face); |
| 241 } |
| 242 // Add this request to the request cache. |
| 243 fCache.add(face, request.release()); |
| 244 |
| 245 return face; |
| 329 } | 246 } |
| 330 }; | 247 }; |
| 331 | 248 |
| 332 SkFontMgr* SkFontMgr::Factory() { | 249 SK_API SkFontMgr* SkFontMgr_New_FCI(SkFontConfigInterface* fci) { |
| 333 SkFontConfigInterface* fci = RefFCI(); | 250 SkASSERT(fci); |
| 334 return fci ? new SkFontMgr_fontconfig(fci) : nullptr; | 251 return new SkFontMgr_FCI(fci); |
| 335 } | 252 } |
| OLD | NEW |