Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
| 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 <SkOnce.h> | |
| 8 #include "SkGlyphCache.h" | 9 #include "SkGlyphCache.h" |
| 9 #include "SkGlyphCache_Globals.h" | 10 #include "SkGlyphCache_Globals.h" |
| 10 #include "SkGraphics.h" | 11 #include "SkGraphics.h" |
| 11 #include "SkLazyPtr.h" | 12 #include "SkLazyPtr.h" |
| 12 #include "SkPath.h" | 13 #include "SkPath.h" |
| 13 #include "SkTemplates.h" | 14 #include "SkTemplates.h" |
| 14 #include "SkTypeface.h" | 15 #include "SkTypeface.h" |
| 15 | 16 |
| 16 //#define SPEW_PURGE_STATUS | 17 //#define SPEW_PURGE_STATUS |
| 17 | 18 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 31 } | 32 } |
| 32 | 33 |
| 33 /////////////////////////////////////////////////////////////////////////////// | 34 /////////////////////////////////////////////////////////////////////////////// |
| 34 | 35 |
| 35 // so we don't grow our arrays a lot | 36 // so we don't grow our arrays a lot |
| 36 #define kMinGlyphCount 16 | 37 #define kMinGlyphCount 16 |
| 37 #define kMinGlyphImageSize (16*2) | 38 #define kMinGlyphImageSize (16*2) |
| 38 #define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphC ount) | 39 #define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphC ount) |
| 39 | 40 |
| 40 SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkSca lerContext* ctx) | 41 SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkSca lerContext* ctx) |
| 41 : fDesc(desc->copy()) | 42 : fNext(NULL) |
| 43 , fPrev(NULL) | |
| 44 , fDesc(desc->copy()) | |
| 45 , refCount(0) | |
| 46 , fGlyphAlloc(kMinAllocAmount) | |
| 47 , fMemoryUsed(sizeof(*this)) | |
| 42 , fScalerContext(ctx) | 48 , fScalerContext(ctx) |
| 43 , fGlyphAlloc(kMinAllocAmount) { | 49 , fAuxProcList(NULL) { |
| 44 SkASSERT(typeface); | 50 SkASSERT(typeface); |
| 45 SkASSERT(desc); | 51 SkASSERT(desc); |
| 46 SkASSERT(ctx); | 52 SkASSERT(ctx); |
| 47 | 53 |
| 48 fPrev = fNext = NULL; | |
| 49 | |
| 50 fScalerContext->getFontMetrics(&fFontMetrics); | 54 fScalerContext->getFontMetrics(&fFontMetrics); |
| 51 | |
| 52 fMemoryUsed = sizeof(*this); | |
| 53 | |
| 54 fAuxProcList = NULL; | |
| 55 } | 55 } |
| 56 | 56 |
| 57 SkGlyphCache::~SkGlyphCache() { | 57 SkGlyphCache::~SkGlyphCache() { |
| 58 fGlyphMap.foreach( | 58 fGlyphMap.foreach( |
| 59 [](SkGlyph* g) { | 59 [](SkGlyph* g) { |
| 60 SkDELETE(g->fPath); | 60 SkDELETE(g->fPath); |
| 61 } | 61 } |
| 62 ); | 62 ); |
| 63 SkDescriptor::Free(fDesc); | 63 SkDescriptor::Free(fDesc); |
| 64 SkDELETE(fScalerContext); | 64 SkDELETE(fScalerContext); |
| 65 this->invokeAndRemoveAuxProcs(); | 65 this->invokeAndRemoveAuxProcs(); |
| 66 } | 66 } |
| 67 | 67 |
| 68 void SkGlyphCache::increaseMemoryUsed(size_t used) { | |
| 69 fMemoryUsed += used; | |
| 70 get_globals().increaseTotalMemoryUsed(used); | |
| 71 } | |
| 72 | |
| 73 SkGlyphCache::CharGlyphRec SkGlyphCache::PackedUnicharIDtoCharGlyphRec(PackedUni charID packedUnicharID) { | |
| 74 SkFixed x = SkGlyph::SubToFixed(SkGlyph::ID2SubX(packedUnicharID)); | |
| 75 SkFixed y = SkGlyph::SubToFixed(SkGlyph::ID2SubY(packedUnicharID)); | |
| 76 SkUnichar unichar = SkGlyph::ID2Code(packedUnicharID); | |
| 77 | |
| 78 SkAutoMutexAcquire lock(fScalerMutex); | |
| 79 PackedGlyphID packedGlyphID = SkGlyph::MakeID(fScalerContext->charToGlyphID( unichar), x, y); | |
| 80 | |
| 81 return {packedUnicharID, packedGlyphID}; | |
| 82 } | |
| 83 | |
| 68 SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(PackedUnicharID packed UnicharID) { | 84 SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(PackedUnicharID packed UnicharID) { |
| 69 if (NULL == fPackedUnicharIDToPackedGlyphID.get()) { | 85 if (NULL == fPackedUnicharIDToPackedGlyphID.get()) { |
| 70 // Allocate the array. | 86 fMu.releaseShared(); |
|
mtklein_C
2015/08/14 15:31:37
Let's add assertShared() / assertExclusive() metho
| |
| 71 fPackedUnicharIDToPackedGlyphID.reset(kHashCount); | 87 |
| 72 // Initialize array to map character and position with the impossible gl yph ID. This | 88 // Add the map only if there is a call for char -> glyph mapping. |
| 73 // represents no mapping. | 89 { |
| 74 for (int i = 0; i <kHashCount; ++i) { | 90 SkAutoTAcquire<SkSharedMutex> lock(fMu); |
| 75 fPackedUnicharIDToPackedGlyphID[i].fPackedUnicharID = SkGlyph::kImpo ssibleID; | 91 |
| 76 fPackedUnicharIDToPackedGlyphID[i].fPackedGlyphID = 0; | 92 // Now that the cache is locked exclusively, make sure no one added this array while unlocked. |
| 93 if (NULL == fPackedUnicharIDToPackedGlyphID.get()) { | |
| 94 // Allocate the array. | |
| 95 fPackedUnicharIDToPackedGlyphID.reset(SkNEW(PackedUnicharIDToPac kedGlyphIDMap)); | |
| 96 } | |
| 97 | |
| 98 fPackedUnicharIDToPackedGlyphID->set(PackedUnicharIDtoCharGlyphRec(p ackedUnicharID)); | |
| 77 } | 99 } |
| 100 fMu.acquireShared(); | |
| 101 | |
| 102 return fPackedUnicharIDToPackedGlyphID->find(packedUnicharID); | |
| 78 } | 103 } |
| 79 | 104 |
| 80 return &fPackedUnicharIDToPackedGlyphID[SkChecksum::CheapMix(packedUnicharID ) & kHashMask]; | 105 CharGlyphRec* answer = fPackedUnicharIDToPackedGlyphID->find(packedUnicharID ); |
| 106 if (NULL == answer) { | |
| 107 fMu.releaseShared(); | |
| 108 // Add a new char -> glyph mapping. | |
| 109 { | |
| 110 SkAutoTAcquire<SkSharedMutex> lock(fMu); | |
| 111 answer = fPackedUnicharIDToPackedGlyphID->find(packedUnicharID); | |
| 112 if (NULL == answer) { | |
| 113 fPackedUnicharIDToPackedGlyphID->set(PackedUnicharIDtoCharGlyphR ec(packedUnicharID)); | |
| 114 } | |
| 115 } | |
| 116 fMu.acquireShared(); | |
| 117 return fPackedUnicharIDToPackedGlyphID->find(packedUnicharID); | |
| 118 } | |
| 119 | |
| 120 return answer; | |
| 81 } | 121 } |
| 82 | 122 |
| 83 /////////////////////////////////////////////////////////////////////////////// | 123 /////////////////////////////////////////////////////////////////////////////// |
| 84 | 124 |
| 85 #ifdef SK_DEBUG | 125 #ifdef SK_DEBUG |
| 86 #define VALIDATE() AutoValidate av(this) | 126 #define VALIDATE() AutoValidate av(this) |
| 87 #else | 127 #else |
| 88 #define VALIDATE() | 128 #define VALIDATE() |
| 89 #endif | 129 #endif |
| 90 | 130 |
| 91 uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) { | 131 uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) { |
| 92 VALIDATE(); | 132 VALIDATE(); |
| 93 PackedUnicharID packedUnicharID = SkGlyph::MakeID(charCode); | 133 PackedUnicharID packedUnicharID = SkGlyph::MakeID(charCode); |
| 94 const CharGlyphRec& rec = *this->getCharGlyphRec(packedUnicharID); | 134 const CharGlyphRec& rec = *this->getCharGlyphRec(packedUnicharID); |
| 95 | 135 return SkGlyph::ID2Code(rec.fPackedGlyphID); |
| 96 if (rec.fPackedUnicharID == packedUnicharID) { | |
| 97 return SkGlyph::ID2Code(rec.fPackedGlyphID); | |
| 98 } else { | |
| 99 return fScalerContext->charToGlyphID(charCode); | |
| 100 } | |
| 101 } | 136 } |
| 102 | 137 |
| 103 SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) { | 138 SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) { |
| 104 return fScalerContext->glyphIDToChar(glyphID); | 139 SkUnichar answer; |
| 140 SkAutoMutexAcquire lock(fScalerMutex); | |
|
mtklein_C
2015/08/14 15:31:37
Is this different from
SkAutoMutexAcquire lock(f
| |
| 141 answer = fScalerContext->glyphIDToChar(glyphID); | |
| 142 return answer; | |
| 105 } | 143 } |
| 106 | 144 |
| 107 unsigned SkGlyphCache::getGlyphCount() { | 145 unsigned SkGlyphCache::getGlyphCount() { |
| 108 return fScalerContext->getGlyphCount(); | 146 return fScalerContext->getGlyphCount(); |
| 109 } | 147 } |
| 110 | 148 |
| 111 /////////////////////////////////////////////////////////////////////////////// | 149 /////////////////////////////////////////////////////////////////////////////// |
| 112 | 150 |
| 113 const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) { | 151 const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) { |
| 114 VALIDATE(); | 152 VALIDATE(); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 139 return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType); | 177 return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType); |
| 140 } | 178 } |
| 141 | 179 |
| 142 const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFi xed y) { | 180 const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFi xed y) { |
| 143 VALIDATE(); | 181 VALIDATE(); |
| 144 PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID, x, y); | 182 PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID, x, y); |
| 145 return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType); | 183 return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType); |
| 146 } | 184 } |
| 147 | 185 |
| 148 SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, MetricsType type, SkFixe d x, SkFixed y) { | 186 SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, MetricsType type, SkFixe d x, SkFixed y) { |
| 149 PackedUnicharID id = SkGlyph::MakeID(charCode, x, y); | 187 PackedUnicharID targetUnicharID = SkGlyph::MakeID(charCode, x, y); |
| 150 CharGlyphRec* rec = this->getCharGlyphRec(id); | 188 CharGlyphRec* rec = this->getCharGlyphRec(targetUnicharID); |
| 151 if (rec->fPackedUnicharID != id) { | 189 PackedGlyphID packedGlyphID = rec->fPackedGlyphID; |
| 152 // this ID is based on the UniChar | 190 |
| 153 rec->fPackedUnicharID = id; | 191 return this->lookupByPackedGlyphID(packedGlyphID, type); |
| 154 // this ID is based on the glyph index | |
| 155 PackedGlyphID combinedID = SkGlyph::MakeID(fScalerContext->charToGlyphID (charCode), x, y); | |
| 156 rec->fPackedGlyphID = combinedID; | |
| 157 return this->lookupByPackedGlyphID(combinedID, type); | |
| 158 } else { | |
| 159 return this->lookupByPackedGlyphID(rec->fPackedGlyphID, type); | |
| 160 } | |
| 161 } | 192 } |
| 162 | 193 |
| 163 SkGlyph* SkGlyphCache::lookupByPackedGlyphID(PackedGlyphID packedGlyphID, Metric sType type) { | 194 SkGlyph* SkGlyphCache::lookupByPackedGlyphID(PackedGlyphID packedGlyphID, Metric sType type) { |
| 164 SkGlyph* glyph = fGlyphMap.find(packedGlyphID); | 195 SkGlyph* glyph = fGlyphMap.find(packedGlyphID); |
| 165 | 196 |
| 166 if (NULL == glyph) { | 197 if (NULL == glyph) { |
| 167 glyph = this->allocateNewGlyph(packedGlyphID, type); | 198 glyph = this->allocateNewGlyph(packedGlyphID, type); |
| 168 } else { | 199 } else { |
| 169 if (type == kFull_MetricsType && glyph->isJustAdvance()) { | 200 if (type == kFull_MetricsType && glyph->isJustAdvance()) { |
| 170 fScalerContext->getMetrics(glyph); | 201 addFullMetrics(glyph); |
|
mtklein_C
2015/08/14 15:31:37
this->
| |
| 171 } | 202 } |
| 172 } | 203 } |
| 173 return glyph; | 204 return glyph; |
| 174 } | 205 } |
| 175 | 206 |
| 176 SkGlyph* SkGlyphCache::allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType mtype) { | 207 SkGlyph* SkGlyphCache::allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType mtype) { |
| 177 fMemoryUsed += sizeof(SkGlyph); | |
| 178 | 208 |
| 179 SkGlyph* glyphPtr; | 209 SkGlyph* glyphPtr; |
| 180 { | 210 { |
| 181 SkGlyph glyph; | 211 fMu.releaseShared(); |
| 182 glyph.initGlyphFromCombinedID(packedGlyphID); | 212 { |
| 183 glyphPtr = fGlyphMap.set(glyph); | 213 SkAutoTAcquire<SkSharedMutex> mapLock(fMu); |
|
mtklein_C
2015/08/14 15:31:37
Let's find some common naming scheme between fMu a
| |
| 184 } | 214 glyphPtr = fGlyphMap.find(packedGlyphID); |
| 215 if (NULL == glyphPtr) { | |
| 216 SkGlyph glyph; | |
| 217 glyph.initGlyphFromCombinedID(packedGlyphID); | |
| 218 { | |
| 219 SkAutoMutexAcquire lock(fScalerMutex); | |
| 220 if (kJustAdvance_MetricsType == mtype) { | |
| 221 fScalerContext->getAdvance(&glyph); | |
| 222 } else { | |
| 223 SkASSERT(kFull_MetricsType == mtype); | |
| 224 fScalerContext->getMetrics(&glyph); | |
| 225 } | |
| 226 increaseMemoryUsed(sizeof(SkGlyph)); | |
|
mtklein_C
2015/08/14 15:31:37
this->
| |
| 227 } // drop scaler lock | |
| 228 glyphPtr = fGlyphMap.set(glyph); | |
| 185 | 229 |
| 186 if (kJustAdvance_MetricsType == mtype) { | 230 } else if (kFull_MetricsType == mtype && glyphPtr->isJustAdvance()) { |
| 187 fScalerContext->getAdvance(glyphPtr); | 231 // Some other thread added the glyph, but only calculated just-a dvance metrics. |
| 188 } else { | 232 SkAutoMutexAcquire lock(fScalerMutex); |
| 189 SkASSERT(kFull_MetricsType == mtype); | 233 fScalerContext->getMetrics(glyphPtr); |
| 190 fScalerContext->getMetrics(glyphPtr); | 234 } |
| 235 } // drop map lock | |
| 236 fMu.acquireShared(); | |
| 237 glyphPtr = fGlyphMap.find(packedGlyphID); | |
| 191 } | 238 } |
| 192 | 239 |
| 193 SkASSERT(glyphPtr->fID != SkGlyph::kImpossibleID); | 240 SkASSERT(glyphPtr->fID != SkGlyph::kImpossibleID); |
| 194 return glyphPtr; | 241 return glyphPtr; |
| 195 } | 242 } |
| 196 | 243 |
| 197 const void* SkGlyphCache::findImage(const SkGlyph& glyph) { | 244 void SkGlyphCache::addFullMetrics(SkGlyph* glyph) { |
| 198 if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) { | 245 // Now that the cache is exclusively owned, check again. |
| 199 if (NULL == glyph.fImage) { | 246 SkAutoMutexAcquire lock(fScalerMutex); |
| 200 size_t size = glyph.computeImageSize(); | 247 if (glyph->isJustAdvance()) { |
| 201 const_cast<SkGlyph&>(glyph).fImage = fGlyphAlloc.alloc(size, | 248 fScalerContext->getMetrics(glyph); |
| 202 SkChunkAlloc::kReturnNil_AllocFailType); | 249 } |
| 203 // check that alloc() actually succeeded | 250 } |
| 204 if (glyph.fImage) { | 251 |
| 205 fScalerContext->getImage(glyph); | 252 void SkGlyphCache::onceFillInImage(GlyphAndCache gc) { |
|
mtklein_C
2015/08/14 15:31:37
It'd be nice to remind ourselves we're holding the
| |
| 206 // TODO: the scaler may have changed the maskformat during | 253 SkGlyphCache* cache = gc.cache; |
| 207 // getImage (e.g. from AA or LCD to BW) which means we may have | 254 const SkGlyph* glyph = gc.glyph; |
| 208 // overallocated the buffer. Check if the new computedImageSize | 255 if (glyph->fWidth > 0 && glyph->fWidth < kMaxGlyphWidth) { |
| 209 // is smaller, and if so, strink the alloc size in fImageAlloc. | 256 size_t size = glyph->computeImageSize(); |
| 210 fMemoryUsed += size; | 257 sk_atomic_store(&const_cast<SkGlyph*>(glyph)->fImage, |
|
mtklein_C
2015/08/14 15:31:37
This shouldn't need to be atomic under this scheme
| |
| 211 } | 258 cache->fGlyphAlloc.alloc(size, SkChunkAlloc::kReturnNil_AllocFai lType), |
| 259 sk_memory_order_relaxed); | |
| 260 if (glyph->fImage != NULL) { | |
| 261 cache->fScalerContext->getImage(*glyph); | |
| 262 cache->increaseMemoryUsed(size); | |
| 212 } | 263 } |
| 213 } | 264 } |
| 214 return glyph.fImage; | 265 } |
| 266 | |
| 267 const void* SkGlyphCache::findImage(const SkGlyph& glyph) { | |
| 268 SkOnce(&glyph.fImageIsSet, &fScalerMutex, &SkGlyphCache::onceFillInImage, {t his, &glyph}); | |
| 269 return sk_atomic_load(&glyph.fImage, sk_memory_order_relaxed); | |
|
mtklein_C
2015/08/14 15:31:37
Again, I think these do not need to be atomic.
herb_g
2015/08/21 19:16:50
I don't think this is correct. I think that making
| |
| 270 } | |
| 271 | |
| 272 void SkGlyphCache::onceFillInPath(GlyphAndCache gc) { | |
| 273 SkGlyphCache* cache = gc.cache; | |
| 274 const SkGlyph* glyph = gc.glyph; | |
| 275 if (glyph->fWidth > 0) { | |
| 276 sk_atomic_store(&const_cast<SkGlyph*>(glyph)->fPath, SkNEW(SkPath), sk_m emory_order_relaxed); | |
|
mtklein_C
2015/08/14 15:31:37
ditto
| |
| 277 cache->fScalerContext->getPath(*glyph, glyph->fPath); | |
| 278 size_t size = sizeof(SkPath) + glyph->fPath->countPoints() * sizeof(SkPo int); | |
| 279 cache->increaseMemoryUsed(size); | |
| 280 } | |
| 215 } | 281 } |
| 216 | 282 |
| 217 const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) { | 283 const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) { |
| 218 if (glyph.fWidth) { | 284 SkOnce(&glyph.fPathIsSet, &fScalerMutex, &SkGlyphCache::onceFillInPath, {thi s, &glyph}); |
| 219 if (glyph.fPath == NULL) { | 285 return sk_atomic_load(&glyph.fPath, sk_memory_order_relaxed); |
|
mtklein_C
2015/08/14 15:31:37
ditto
| |
| 220 const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath); | |
| 221 fScalerContext->getPath(glyph, glyph.fPath); | |
| 222 fMemoryUsed += sizeof(SkPath) + | |
| 223 glyph.fPath->countPoints() * sizeof(SkPoint); | |
| 224 } | |
| 225 } | |
| 226 return glyph.fPath; | |
| 227 } | 286 } |
| 228 | 287 |
| 229 void SkGlyphCache::dump() const { | 288 void SkGlyphCache::dump() const { |
| 230 const SkTypeface* face = fScalerContext->getTypeface(); | 289 const SkTypeface* face = fScalerContext->getTypeface(); |
| 231 const SkScalerContextRec& rec = fScalerContext->getRec(); | 290 const SkScalerContextRec& rec = fScalerContext->getRec(); |
| 232 SkMatrix matrix; | 291 SkMatrix matrix; |
| 233 rec.getSingleMatrix(&matrix); | 292 rec.getSingleMatrix(&matrix); |
| 234 matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize) ); | 293 matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize) ); |
| 235 SkString name; | 294 SkString name; |
| 236 face->getFamilyName(&name); | 295 face->getFamilyName(&name); |
| 237 | 296 |
| 238 SkString msg; | 297 SkString msg; |
| 239 msg.printf("cache typeface:%x %25s:%d size:%2g [%g %g %g %g] lum:%02X devG:% d pntG:%d cntr:%d glyphs:%3d", | 298 msg.printf("cache typeface:%x %25s:%d size:%2g [%g %g %g %g] lum:%02X devG:% d pntG:%d cntr:%d glyphs:%3d", |
| 240 face->uniqueID(), name.c_str(), face->style(), rec.fTextSize, | 299 face->uniqueID(), name.c_str(), face->style(), rec.fTextSize, |
| 241 matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX], | 300 matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX], |
| 242 matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY], | 301 matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY], |
| 243 rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fCont rast, | 302 rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fCont rast, |
| 244 fGlyphMap.count()); | 303 fGlyphMap.count()); |
| 245 SkDebugf("%s\n", msg.c_str()); | 304 SkDebugf("%s\n", msg.c_str()); |
| 246 } | 305 } |
| 247 | 306 |
| 248 /////////////////////////////////////////////////////////////////////////////// | 307 /////////////////////////////////////////////////////////////////////////////// |
| 249 | 308 |
| 250 bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const { | 309 bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const { |
| 310 SkAutoMutexAcquire lock(fScalerMutex); | |
|
mtklein_C
2015/08/14 15:31:37
It's not obvious why these hold fScalerMutex?
| |
| 251 const AuxProcRec* rec = fAuxProcList; | 311 const AuxProcRec* rec = fAuxProcList; |
| 252 while (rec) { | 312 while (rec) { |
| 253 if (rec->fProc == proc) { | 313 if (rec->fProc == proc) { |
| 254 if (dataPtr) { | 314 if (dataPtr) { |
| 255 *dataPtr = rec->fData; | 315 *dataPtr = rec->fData; |
| 256 } | 316 } |
| 257 return true; | 317 return true; |
| 258 } | 318 } |
| 259 rec = rec->fNext; | 319 rec = rec->fNext; |
| 260 } | 320 } |
| 261 return false; | 321 return false; |
| 262 } | 322 } |
| 263 | 323 |
| 264 void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) { | 324 void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) { |
| 265 if (proc == NULL) { | 325 if (proc == NULL) { |
| 266 return; | 326 return; |
| 267 } | 327 } |
| 268 | 328 |
| 329 SkAutoMutexAcquire lock(fScalerMutex); | |
| 269 AuxProcRec* rec = fAuxProcList; | 330 AuxProcRec* rec = fAuxProcList; |
| 270 while (rec) { | 331 while (rec) { |
| 271 if (rec->fProc == proc) { | 332 if (rec->fProc == proc) { |
| 272 rec->fData = data; | 333 rec->fData = data; |
| 273 return; | 334 return; |
| 274 } | 335 } |
| 275 rec = rec->fNext; | 336 rec = rec->fNext; |
| 276 } | 337 } |
| 277 // not found, create a new rec | 338 // not found, create a new rec |
| 278 rec = SkNEW(AuxProcRec); | 339 rec = SkNEW(AuxProcRec); |
| 279 rec->fProc = proc; | 340 rec->fProc = proc; |
| 280 rec->fData = data; | 341 rec->fData = data; |
| 281 rec->fNext = fAuxProcList; | 342 rec->fNext = fAuxProcList; |
| 282 fAuxProcList = rec; | 343 fAuxProcList = rec; |
| 283 } | 344 } |
| 284 | 345 |
| 285 void SkGlyphCache::invokeAndRemoveAuxProcs() { | 346 void SkGlyphCache::invokeAndRemoveAuxProcs() { |
| 286 AuxProcRec* rec = fAuxProcList; | 347 AuxProcRec* rec = fAuxProcList; |
| 287 while (rec) { | 348 while (rec) { |
| 288 rec->fProc(rec->fData); | 349 rec->fProc(rec->fData); |
| 289 AuxProcRec* next = rec->fNext; | 350 AuxProcRec* next = rec->fNext; |
| 290 SkDELETE(rec); | 351 SkDELETE(rec); |
| 291 rec = next; | 352 rec = next; |
| 292 } | 353 } |
| 293 } | 354 } |
| 294 | 355 |
| 295 /////////////////////////////////////////////////////////////////////////////// | 356 /////////////////////////////////////////////////////////////////////////////// |
| 296 /////////////////////////////////////////////////////////////////////////////// | 357 /////////////////////////////////////////////////////////////////////////////// |
| 297 | 358 |
| 298 | 359 typedef SkAutoTAcquire<SkSpinlock> AutoAcquire; |
| 299 class AutoAcquire { | |
| 300 public: | |
| 301 AutoAcquire(SkSpinlock& lock) : fLock(lock) { fLock.acquire(); } | |
| 302 ~AutoAcquire() { fLock.release(); } | |
| 303 private: | |
| 304 SkSpinlock& fLock; | |
| 305 }; | |
| 306 | 360 |
| 307 size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { | 361 size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { |
| 308 static const size_t minLimit = 256 * 1024; | 362 static const size_t minLimit = 256 * 1024; |
| 309 if (newLimit < minLimit) { | 363 if (newLimit < minLimit) { |
| 310 newLimit = minLimit; | 364 newLimit = minLimit; |
| 311 } | 365 } |
| 312 | 366 |
| 313 AutoAcquire ac(fLock); | 367 AutoAcquire ac(fLock); |
| 314 | 368 |
| 315 size_t prevLimit = fCacheSizeLimit; | 369 size_t prevLimit = fCacheSizeLimit; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 326 AutoAcquire ac(fLock); | 380 AutoAcquire ac(fLock); |
| 327 | 381 |
| 328 int prevCount = fCacheCountLimit; | 382 int prevCount = fCacheCountLimit; |
| 329 fCacheCountLimit = newCount; | 383 fCacheCountLimit = newCount; |
| 330 this->internalPurge(); | 384 this->internalPurge(); |
| 331 return prevCount; | 385 return prevCount; |
| 332 } | 386 } |
| 333 | 387 |
| 334 void SkGlyphCache_Globals::purgeAll() { | 388 void SkGlyphCache_Globals::purgeAll() { |
| 335 AutoAcquire ac(fLock); | 389 AutoAcquire ac(fLock); |
| 336 this->internalPurge(fTotalMemoryUsed); | 390 this->internalPurge(fTotalMemoryUsed.load()); |
| 337 } | 391 } |
| 338 | 392 |
| 339 /* This guy calls the visitor from within the mutext lock, so the visitor | 393 /* This guy calls the visitor from within the mutext lock, so the visitor |
| 340 cannot: | 394 cannot: |
| 341 - take too much time | 395 - take too much time |
| 342 - try to acquire the mutext again | 396 - try to acquire the mutext again |
| 343 - call a fontscaler (which might call into the cache) | 397 - call a fontscaler (which might call into the cache) |
| 344 */ | 398 */ |
| 345 SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, | 399 SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, const SkDescriptor* desc, VisitProc proc, void* context) { |
| 346 const SkDescriptor* desc, | |
| 347 bool (*proc)(const SkGlyphCache*, void*), | |
| 348 void* context) { | |
| 349 if (!typeface) { | 400 if (!typeface) { |
| 350 typeface = SkTypeface::GetDefaultTypeface(); | 401 typeface = SkTypeface::GetDefaultTypeface(); |
| 351 } | 402 } |
| 352 SkASSERT(desc); | 403 SkASSERT(desc); |
| 353 | 404 |
| 354 SkGlyphCache_Globals& globals = get_globals(); | 405 SkGlyphCache_Globals& globals = get_globals(); |
| 355 SkGlyphCache* cache; | 406 SkGlyphCache* cache; |
| 356 | 407 |
| 357 { | 408 { |
| 358 AutoAcquire ac(globals.fLock); | 409 AutoAcquire ac(globals.fLock); |
| 359 | 410 |
| 360 globals.validate(); | 411 globals.validate(); |
| 361 | 412 |
| 362 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fN ext) { | 413 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fN ext) { |
| 363 if (cache->fDesc->equals(*desc)) { | 414 if (cache->fDesc->equals(*desc)) { |
| 364 globals.internalDetachCache(cache); | 415 globals.internalMoveToHead(cache); |
| 416 cache->fMu.acquireShared(); | |
| 365 if (!proc(cache, context)) { | 417 if (!proc(cache, context)) { |
| 366 globals.internalAttachCacheToHead(cache); | 418 cache->fMu.releaseShared(); |
| 367 cache = NULL; | 419 return NULL; |
| 368 } | 420 } |
| 421 cache->refCount += 1; | |
|
mtklein_C
2015/08/14 15:31:37
This seems odd. Are all these cache->refCounts al
| |
| 369 return cache; | 422 return cache; |
| 370 } | 423 } |
| 371 } | 424 } |
| 372 } | 425 } |
| 373 | 426 |
| 374 // Check if we can create a scaler-context before creating the glyphcache. | 427 // Check if we can create a scaler-context before creating the glyphcache. |
| 375 // If not, we may have exhausted OS/font resources, so try purging the | 428 // If not, we may have exhausted OS/font resources, so try purging the |
| 376 // cache once and try again. | 429 // cache once and try again. |
| 377 { | 430 { |
| 378 // pass true the first time, to notice if the scalercontext failed, | 431 // pass true the first time, to notice if the scalercontext failed, |
| 379 // so we can try the purge. | 432 // so we can try the purge. |
| 380 SkScalerContext* ctx = typeface->createScalerContext(desc, true); | 433 SkScalerContext* ctx = typeface->createScalerContext(desc, true); |
| 381 if (!ctx) { | 434 if (NULL == ctx) { |
| 382 get_globals().purgeAll(); | 435 get_globals().purgeAll(); |
| 383 ctx = typeface->createScalerContext(desc, false); | 436 ctx = typeface->createScalerContext(desc, false); |
| 384 SkASSERT(ctx); | 437 SkASSERT(ctx); |
| 385 } | 438 } |
| 386 cache = SkNEW_ARGS(SkGlyphCache, (typeface, desc, ctx)); | 439 cache = SkNEW_ARGS(SkGlyphCache, (typeface, desc, ctx)); |
| 440 | |
| 441 globals.attachCacheToHead(cache); | |
| 387 } | 442 } |
| 388 | 443 |
| 389 AutoValidate av(cache); | 444 AutoValidate av(cache); |
| 445 AutoAcquire ac(globals.fLock); | |
| 390 | 446 |
| 447 cache->fMu.acquireShared(); | |
| 391 if (!proc(cache, context)) { // need to reattach | 448 if (!proc(cache, context)) { // need to reattach |
| 392 globals.attachCacheToHead(cache); | 449 cache->fMu.releaseShared(); |
| 393 cache = NULL; | 450 return NULL; |
| 394 } | 451 } |
| 452 cache->refCount += 1; | |
| 395 return cache; | 453 return cache; |
| 396 } | 454 } |
| 397 | 455 |
| 398 void SkGlyphCache::AttachCache(SkGlyphCache* cache) { | 456 void SkGlyphCache::AttachCache(SkGlyphCache* cache) { |
| 399 SkASSERT(cache); | 457 SkASSERT(cache); |
| 400 SkASSERT(cache->fNext == NULL); | 458 cache->fMu.releaseShared(); |
| 401 | 459 SkGlyphCache_Globals& globals = get_globals(); |
| 402 get_globals().attachCacheToHead(cache); | 460 AutoAcquire ac(globals.fLock); |
| 461 globals.validate(); | |
| 462 cache->validate(); | |
| 463 if (cache->refCount == 0) { | |
| 464 delete cache; | |
| 465 } | |
| 466 globals.internalPurge(); | |
| 403 } | 467 } |
| 404 | 468 |
| 405 void SkGlyphCache::Dump() { | 469 void SkGlyphCache::Dump() { |
| 406 SkGlyphCache_Globals& globals = get_globals(); | 470 SkGlyphCache_Globals& globals = get_globals(); |
| 407 AutoAcquire ac(globals.fLock); | 471 AutoAcquire ac(globals.fLock); |
| 408 SkGlyphCache* cache; | 472 SkGlyphCache* cache; |
| 409 | 473 |
| 410 globals.validate(); | 474 globals.validate(); |
| 411 | 475 |
| 412 SkDebugf("SkGlyphCache strikes:%d memory:%d\n", | 476 SkDebugf("SkGlyphCache strikes:%d memory:%d\n", |
| 413 globals.getCacheCountUsed(), (int)globals.getTotalMemoryUsed()); | 477 globals.getCacheCountUsed(), (int)globals.getTotalMemoryUsed()); |
| 414 | 478 |
| 415 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) { | 479 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) { |
| 416 cache->dump(); | 480 cache->dump(); |
| 417 } | 481 } |
| 418 } | 482 } |
| 419 | 483 |
| 420 /////////////////////////////////////////////////////////////////////////////// | 484 /////////////////////////////////////////////////////////////////////////////// |
| 421 | 485 |
| 422 void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { | 486 void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { |
| 423 AutoAcquire ac(fLock); | 487 AutoAcquire ac(fLock); |
| 424 | 488 |
| 489 fCacheCount += 1; | |
| 490 cache->refCount += 1; | |
| 491 // Access to cache->fMemoryUsed is single threaded until internalMoveToHead. | |
| 492 fTotalMemoryUsed.fetch_add(cache->fMemoryUsed); | |
| 493 | |
| 494 this->internalMoveToHead(cache); | |
| 495 | |
| 425 this->validate(); | 496 this->validate(); |
| 426 cache->validate(); | 497 cache->validate(); |
| 427 | 498 |
| 428 this->internalAttachCacheToHead(cache); | |
| 429 this->internalPurge(); | 499 this->internalPurge(); |
| 430 } | 500 } |
| 431 | 501 |
| 432 SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const { | 502 SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const { |
| 433 SkGlyphCache* cache = fHead; | 503 SkGlyphCache* cache = fHead; |
| 434 if (cache) { | 504 if (cache) { |
| 435 while (cache->fNext) { | 505 while (cache->fNext) { |
| 436 cache = cache->fNext; | 506 cache = cache->fNext; |
| 437 } | 507 } |
| 438 } | 508 } |
| 439 return cache; | 509 return cache; |
| 440 } | 510 } |
| 441 | 511 |
| 442 size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) { | 512 size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) { |
| 443 this->validate(); | 513 this->validate(); |
| 444 | 514 |
| 445 size_t bytesNeeded = 0; | 515 size_t bytesNeeded = 0; |
| 446 if (fTotalMemoryUsed > fCacheSizeLimit) { | 516 if (fTotalMemoryUsed.load() > fCacheSizeLimit) { |
| 447 bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit; | 517 bytesNeeded = fTotalMemoryUsed.load() - fCacheSizeLimit; |
| 448 } | 518 } |
| 449 bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded); | 519 bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded); |
| 450 if (bytesNeeded) { | 520 if (bytesNeeded) { |
| 451 // no small purges! | 521 // no small purges! |
| 452 bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed >> 2); | 522 bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed.load() >> 2); |
| 453 } | 523 } |
| 454 | 524 |
| 455 int countNeeded = 0; | 525 int countNeeded = 0; |
| 456 if (fCacheCount > fCacheCountLimit) { | 526 if (fCacheCount > fCacheCountLimit) { |
| 457 countNeeded = fCacheCount - fCacheCountLimit; | 527 countNeeded = fCacheCount - fCacheCountLimit; |
| 458 // no small purges! | 528 // no small purges! |
| 459 countNeeded = SkMax32(countNeeded, fCacheCount >> 2); | 529 countNeeded = SkMax32(countNeeded, fCacheCount >> 2); |
| 460 } | 530 } |
| 461 | 531 |
| 462 // early exit | 532 // early exit |
| 463 if (!countNeeded && !bytesNeeded) { | 533 if (!countNeeded && !bytesNeeded) { |
| 464 return 0; | 534 return 0; |
| 465 } | 535 } |
| 466 | 536 |
| 467 size_t bytesFreed = 0; | 537 size_t bytesFreed = 0; |
| 468 int countFreed = 0; | 538 int countFreed = 0; |
| 469 | 539 |
| 470 // we start at the tail and proceed backwards, as the linklist is in LRU | 540 // we start at the tail and proceed backwards, as the linklist is in LRU |
| 471 // order, with unimportant entries at the tail. | 541 // order, with unimportant entries at the tail. |
| 472 SkGlyphCache* cache = this->internalGetTail(); | 542 SkGlyphCache* cache = this->internalGetTail(); |
| 473 while (cache != NULL && | 543 while (cache != NULL && |
| 474 (bytesFreed < bytesNeeded || countFreed < countNeeded)) { | 544 (bytesFreed < bytesNeeded || countFreed < countNeeded)) { |
| 475 SkGlyphCache* prev = cache->fPrev; | 545 SkGlyphCache* prev = cache->fPrev; |
| 476 bytesFreed += cache->fMemoryUsed; | 546 bytesFreed += cache->fMemoryUsed; |
| 477 countFreed += 1; | 547 countFreed += 1; |
| 478 | 548 |
| 479 this->internalDetachCache(cache); | 549 this->internalDetachCache(cache); |
| 480 SkDELETE(cache); | 550 if (0 == cache->refCount) { |
| 551 SkDELETE(cache); | |
| 552 } | |
| 481 cache = prev; | 553 cache = prev; |
| 482 } | 554 } |
| 483 | 555 |
| 484 this->validate(); | 556 this->validate(); |
| 485 | 557 |
| 486 #ifdef SPEW_PURGE_STATUS | 558 #ifdef SPEW_PURGE_STATUS |
| 487 if (countFreed) { | 559 if (countFreed) { |
| 488 SkDebugf("purging %dK from font cache [%d entries]\n", | 560 SkDebugf("purging %dK from font cache [%d entries]\n", |
| 489 (int)(bytesFreed >> 10), countFreed); | 561 (int)(bytesFreed >> 10), countFreed); |
| 490 } | 562 } |
| 491 #endif | 563 #endif |
| 492 | 564 |
| 493 return bytesFreed; | 565 return bytesFreed; |
| 494 } | 566 } |
| 495 | 567 |
| 496 void SkGlyphCache_Globals::internalAttachCacheToHead(SkGlyphCache* cache) { | 568 void SkGlyphCache_Globals::internalMoveToHead(SkGlyphCache *cache) { |
| 497 SkASSERT(NULL == cache->fPrev && NULL == cache->fNext); | 569 if (cache != fHead) { |
| 498 if (fHead) { | 570 if (cache->fPrev) { |
| 499 fHead->fPrev = cache; | 571 cache->fPrev->fNext = cache->fNext; |
| 500 cache->fNext = fHead; | 572 } |
| 573 if (cache->fNext) { | |
| 574 cache->fNext->fPrev = cache->fPrev; | |
| 575 } | |
| 576 cache->fNext = NULL; | |
| 577 cache->fPrev = NULL; | |
| 578 if (fHead) { | |
| 579 fHead->fPrev = cache; | |
| 580 cache->fNext = fHead; | |
| 581 } | |
| 582 fHead = cache; | |
| 501 } | 583 } |
| 502 fHead = cache; | |
| 503 | |
| 504 fCacheCount += 1; | |
| 505 fTotalMemoryUsed += cache->fMemoryUsed; | |
| 506 } | 584 } |
| 507 | 585 |
| 508 void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) { | 586 void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) { |
| 509 SkASSERT(fCacheCount > 0); | |
| 510 fCacheCount -= 1; | 587 fCacheCount -= 1; |
| 511 fTotalMemoryUsed -= cache->fMemoryUsed; | 588 fTotalMemoryUsed.fetch_add(-cache->fMemoryUsed); |
| 512 | 589 |
| 513 if (cache->fPrev) { | 590 if (cache->fPrev) { |
| 514 cache->fPrev->fNext = cache->fNext; | 591 cache->fPrev->fNext = cache->fNext; |
| 515 } else { | 592 } else { |
| 516 fHead = cache->fNext; | 593 fHead = cache->fNext; |
| 517 } | 594 } |
| 518 if (cache->fNext) { | 595 if (cache->fNext) { |
| 519 cache->fNext->fPrev = cache->fPrev; | 596 cache->fNext->fPrev = cache->fPrev; |
| 520 } | 597 } |
| 521 cache->fPrev = cache->fNext = NULL; | 598 cache->fPrev = cache->fNext = NULL; |
| 599 cache->refCount -= 1; | |
| 600 | |
| 522 } | 601 } |
| 523 | 602 |
| 603 | |
| 524 /////////////////////////////////////////////////////////////////////////////// | 604 /////////////////////////////////////////////////////////////////////////////// |
| 525 | 605 |
| 526 #ifdef SK_DEBUG | 606 #ifdef SK_DEBUG |
| 527 | 607 |
| 528 void SkGlyphCache::validate() const { | 608 void SkGlyphCache::validate() const { |
| 529 #ifdef SK_DEBUG_GLYPH_CACHE | 609 #ifdef SK_DEBUG_GLYPH_CACHE |
| 530 int count = fGlyphArray.count(); | 610 int count = fGlyphArray.count(); |
| 531 for (int i = 0; i < count; i++) { | 611 for (int i = 0; i < count; i++) { |
| 532 const SkGlyph* glyph = &fGlyphArray[i]; | 612 const SkGlyph* glyph = &fGlyphArray[i]; |
| 533 SkASSERT(glyph); | 613 SkASSERT(glyph); |
| 534 if (glyph->fImage) { | 614 if (glyph->fImage) { |
| 535 SkASSERT(fGlyphAlloc.contains(glyph->fImage)); | 615 SkASSERT(fGlyphAlloc.contains(glyph->fImage)); |
| 536 } | 616 } |
| 537 } | 617 } |
| 538 #endif | 618 #endif |
| 539 } | 619 } |
| 540 | 620 |
| 541 void SkGlyphCache_Globals::validate() const { | 621 void SkGlyphCache_Globals::validate() const { |
| 542 size_t computedBytes = 0; | |
| 543 int computedCount = 0; | 622 int computedCount = 0; |
| 544 | 623 |
| 545 const SkGlyphCache* head = fHead; | 624 SkGlyphCache* head = fHead; |
| 546 while (head != NULL) { | 625 while (head != NULL) { |
| 547 computedBytes += head->fMemoryUsed; | |
| 548 computedCount += 1; | 626 computedCount += 1; |
| 549 head = head->fNext; | 627 head = head->fNext; |
| 550 } | 628 } |
| 551 | 629 |
| 552 SkASSERTF(fCacheCount == computedCount, "fCacheCount: %d, computedCount: %d" , fCacheCount, | 630 SkASSERTF(fCacheCount == computedCount, "fCacheCount: %d, computedCount: %d" , fCacheCount, |
| 553 computedCount); | 631 computedCount); |
| 554 SkASSERTF(fTotalMemoryUsed == computedBytes, "fTotalMemoryUsed: %d, computed Bytes: %d", | |
| 555 fTotalMemoryUsed, computedBytes); | |
| 556 } | 632 } |
| 557 | 633 |
| 558 #endif | 634 #endif |
| 559 | 635 |
| 560 /////////////////////////////////////////////////////////////////////////////// | 636 /////////////////////////////////////////////////////////////////////////////// |
| 561 /////////////////////////////////////////////////////////////////////////////// | 637 /////////////////////////////////////////////////////////////////////////////// |
| 562 | 638 |
| 563 #include "SkTypefaceCache.h" | 639 #include "SkTypefaceCache.h" |
| 564 | 640 |
| 565 size_t SkGraphics::GetFontCacheLimit() { | 641 size_t SkGraphics::GetFontCacheLimit() { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 587 } | 663 } |
| 588 | 664 |
| 589 void SkGraphics::PurgeFontCache() { | 665 void SkGraphics::PurgeFontCache() { |
| 590 get_globals().purgeAll(); | 666 get_globals().purgeAll(); |
| 591 SkTypefaceCache::PurgeAll(); | 667 SkTypefaceCache::PurgeAll(); |
| 592 } | 668 } |
| 593 | 669 |
| 594 // TODO(herb): clean up TLS apis. | 670 // TODO(herb): clean up TLS apis. |
| 595 size_t SkGraphics::GetTLSFontCacheLimit() { return 0; } | 671 size_t SkGraphics::GetTLSFontCacheLimit() { return 0; } |
| 596 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { } | 672 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { } |
| OLD | NEW |