1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkGlyphCache.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,718 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkGlyphCache.h" 1.14 +#include "SkGlyphCache_Globals.h" 1.15 +#include "SkGraphics.h" 1.16 +#include "SkPaint.h" 1.17 +#include "SkPath.h" 1.18 +#include "SkTemplates.h" 1.19 +#include "SkTLS.h" 1.20 +#include "SkTypeface.h" 1.21 + 1.22 +//#define SPEW_PURGE_STATUS 1.23 +//#define RECORD_HASH_EFFICIENCY 1.24 + 1.25 +bool gSkSuppressFontCachePurgeSpew; 1.26 + 1.27 +// Returns the shared globals 1.28 +static SkGlyphCache_Globals& getSharedGlobals() { 1.29 + // we leak this, so we don't incur any shutdown cost of the destructor 1.30 + static SkGlyphCache_Globals* gGlobals = SkNEW_ARGS(SkGlyphCache_Globals, 1.31 + (SkGlyphCache_Globals::kYes_UseMutex)); 1.32 + return *gGlobals; 1.33 +} 1.34 + 1.35 +// Returns the TLS globals (if set), or the shared globals 1.36 +static SkGlyphCache_Globals& getGlobals() { 1.37 + SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS(); 1.38 + return tls ? *tls : getSharedGlobals(); 1.39 +} 1.40 + 1.41 +/////////////////////////////////////////////////////////////////////////////// 1.42 + 1.43 +#ifdef RECORD_HASH_EFFICIENCY 1.44 + static uint32_t gHashSuccess; 1.45 + static uint32_t gHashCollision; 1.46 + 1.47 + static void RecordHashSuccess() { 1.48 + gHashSuccess += 1; 1.49 + } 1.50 + 1.51 + static void RecordHashCollisionIf(bool pred) { 1.52 + if (pred) { 1.53 + gHashCollision += 1; 1.54 + 1.55 + uint32_t total = gHashSuccess + gHashCollision; 1.56 + SkDebugf("Font Cache Hash success rate: %d%%\n", 1.57 + 100 * gHashSuccess / total); 1.58 + } 1.59 + } 1.60 +#else 1.61 + #define RecordHashSuccess() (void)0 1.62 + #define RecordHashCollisionIf(pred) (void)0 1.63 +#endif 1.64 +#define RecordHashCollision() RecordHashCollisionIf(true) 1.65 + 1.66 +/////////////////////////////////////////////////////////////////////////////// 1.67 + 1.68 +// so we don't grow our arrays a lot 1.69 +#define kMinGlyphCount 16 1.70 +#define kMinGlyphImageSize (16*2) 1.71 +#define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphCount) 1.72 + 1.73 +SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkScalerContext* ctx) 1.74 + : fScalerContext(ctx), fGlyphAlloc(kMinAllocAmount) { 1.75 + SkASSERT(typeface); 1.76 + SkASSERT(desc); 1.77 + SkASSERT(ctx); 1.78 + 1.79 + fPrev = fNext = NULL; 1.80 + 1.81 + fDesc = desc->copy(); 1.82 + fScalerContext->getFontMetrics(&fFontMetrics); 1.83 + 1.84 + // init to 0 so that all of the pointers will be null 1.85 + memset(fGlyphHash, 0, sizeof(fGlyphHash)); 1.86 + // init with 0xFF so that the charCode field will be -1, which is invalid 1.87 + memset(fCharToGlyphHash, 0xFF, sizeof(fCharToGlyphHash)); 1.88 + 1.89 + fMemoryUsed = sizeof(*this); 1.90 + 1.91 + fGlyphArray.setReserve(kMinGlyphCount); 1.92 + 1.93 + fAuxProcList = NULL; 1.94 +} 1.95 + 1.96 +SkGlyphCache::~SkGlyphCache() { 1.97 +#if 0 1.98 + { 1.99 + size_t ptrMem = fGlyphArray.count() * sizeof(SkGlyph*); 1.100 + size_t glyphAlloc = fGlyphAlloc.totalCapacity(); 1.101 + size_t glyphHashUsed = 0; 1.102 + size_t uniHashUsed = 0; 1.103 + for (int i = 0; i < kHashCount; ++i) { 1.104 + glyphHashUsed += fGlyphHash[i] ? sizeof(fGlyphHash[0]) : 0; 1.105 + uniHashUsed += fCharToGlyphHash[i].fID != 0xFFFFFFFF ? sizeof(fCharToGlyphHash[0]) : 0; 1.106 + } 1.107 + size_t glyphUsed = fGlyphArray.count() * sizeof(SkGlyph); 1.108 + size_t imageUsed = 0; 1.109 + for (int i = 0; i < fGlyphArray.count(); ++i) { 1.110 + const SkGlyph& g = *fGlyphArray[i]; 1.111 + if (g.fImage) { 1.112 + imageUsed += g.fHeight * g.rowBytes(); 1.113 + } 1.114 + } 1.115 + 1.116 + printf("glyphPtrArray,%zu, Alloc,%zu, imageUsed,%zu, glyphUsed,%zu, glyphHashAlloc,%zu, glyphHashUsed,%zu, unicharHashAlloc,%zu, unicharHashUsed,%zu\n", 1.117 + ptrMem, glyphAlloc, imageUsed, glyphUsed, sizeof(fGlyphHash), glyphHashUsed, sizeof(fCharToGlyphHash), uniHashUsed); 1.118 + 1.119 + } 1.120 +#endif 1.121 + SkGlyph** gptr = fGlyphArray.begin(); 1.122 + SkGlyph** stop = fGlyphArray.end(); 1.123 + while (gptr < stop) { 1.124 + SkPath* path = (*gptr)->fPath; 1.125 + if (path) { 1.126 + SkDELETE(path); 1.127 + } 1.128 + gptr += 1; 1.129 + } 1.130 + SkDescriptor::Free(fDesc); 1.131 + SkDELETE(fScalerContext); 1.132 + this->invokeAndRemoveAuxProcs(); 1.133 +} 1.134 + 1.135 +/////////////////////////////////////////////////////////////////////////////// 1.136 + 1.137 +#ifdef SK_DEBUG 1.138 +#define VALIDATE() AutoValidate av(this) 1.139 +#else 1.140 +#define VALIDATE() 1.141 +#endif 1.142 + 1.143 +uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) { 1.144 + VALIDATE(); 1.145 + uint32_t id = SkGlyph::MakeID(charCode); 1.146 + const CharGlyphRec& rec = fCharToGlyphHash[ID2HashIndex(id)]; 1.147 + 1.148 + if (rec.fID == id) { 1.149 + return rec.fGlyph->getGlyphID(); 1.150 + } else { 1.151 + return fScalerContext->charToGlyphID(charCode); 1.152 + } 1.153 +} 1.154 + 1.155 +SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) { 1.156 + return fScalerContext->glyphIDToChar(glyphID); 1.157 +} 1.158 + 1.159 +unsigned SkGlyphCache::getGlyphCount() { 1.160 + return fScalerContext->getGlyphCount(); 1.161 +} 1.162 + 1.163 +/////////////////////////////////////////////////////////////////////////////// 1.164 + 1.165 +const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) { 1.166 + VALIDATE(); 1.167 + uint32_t id = SkGlyph::MakeID(charCode); 1.168 + CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)]; 1.169 + 1.170 + if (rec->fID != id) { 1.171 + // this ID is based on the UniChar 1.172 + rec->fID = id; 1.173 + // this ID is based on the glyph index 1.174 + id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode)); 1.175 + rec->fGlyph = this->lookupMetrics(id, kJustAdvance_MetricsType); 1.176 + } 1.177 + return *rec->fGlyph; 1.178 +} 1.179 + 1.180 +const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) { 1.181 + VALIDATE(); 1.182 + uint32_t id = SkGlyph::MakeID(glyphID); 1.183 + unsigned index = ID2HashIndex(id); 1.184 + SkGlyph* glyph = fGlyphHash[index]; 1.185 + 1.186 + if (NULL == glyph || glyph->fID != id) { 1.187 + glyph = this->lookupMetrics(glyphID, kJustAdvance_MetricsType); 1.188 + fGlyphHash[index] = glyph; 1.189 + } 1.190 + return *glyph; 1.191 +} 1.192 + 1.193 +/////////////////////////////////////////////////////////////////////////////// 1.194 + 1.195 +const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) { 1.196 + VALIDATE(); 1.197 + uint32_t id = SkGlyph::MakeID(charCode); 1.198 + CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)]; 1.199 + 1.200 + if (rec->fID != id) { 1.201 + RecordHashCollisionIf(rec->fGlyph != NULL); 1.202 + // this ID is based on the UniChar 1.203 + rec->fID = id; 1.204 + // this ID is based on the glyph index 1.205 + id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode)); 1.206 + rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType); 1.207 + } else { 1.208 + RecordHashSuccess(); 1.209 + if (rec->fGlyph->isJustAdvance()) { 1.210 + fScalerContext->getMetrics(rec->fGlyph); 1.211 + } 1.212 + } 1.213 + SkASSERT(rec->fGlyph->isFullMetrics()); 1.214 + return *rec->fGlyph; 1.215 +} 1.216 + 1.217 +const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode, 1.218 + SkFixed x, SkFixed y) { 1.219 + VALIDATE(); 1.220 + uint32_t id = SkGlyph::MakeID(charCode, x, y); 1.221 + CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)]; 1.222 + 1.223 + if (rec->fID != id) { 1.224 + RecordHashCollisionIf(rec->fGlyph != NULL); 1.225 + // this ID is based on the UniChar 1.226 + rec->fID = id; 1.227 + // this ID is based on the glyph index 1.228 + id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode), x, y); 1.229 + rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType); 1.230 + } else { 1.231 + RecordHashSuccess(); 1.232 + if (rec->fGlyph->isJustAdvance()) { 1.233 + fScalerContext->getMetrics(rec->fGlyph); 1.234 + } 1.235 + } 1.236 + SkASSERT(rec->fGlyph->isFullMetrics()); 1.237 + return *rec->fGlyph; 1.238 +} 1.239 + 1.240 +const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) { 1.241 + VALIDATE(); 1.242 + uint32_t id = SkGlyph::MakeID(glyphID); 1.243 + unsigned index = ID2HashIndex(id); 1.244 + SkGlyph* glyph = fGlyphHash[index]; 1.245 + 1.246 + if (NULL == glyph || glyph->fID != id) { 1.247 + RecordHashCollisionIf(glyph != NULL); 1.248 + glyph = this->lookupMetrics(glyphID, kFull_MetricsType); 1.249 + fGlyphHash[index] = glyph; 1.250 + } else { 1.251 + RecordHashSuccess(); 1.252 + if (glyph->isJustAdvance()) { 1.253 + fScalerContext->getMetrics(glyph); 1.254 + } 1.255 + } 1.256 + SkASSERT(glyph->isFullMetrics()); 1.257 + return *glyph; 1.258 +} 1.259 + 1.260 +const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, 1.261 + SkFixed x, SkFixed y) { 1.262 + VALIDATE(); 1.263 + uint32_t id = SkGlyph::MakeID(glyphID, x, y); 1.264 + unsigned index = ID2HashIndex(id); 1.265 + SkGlyph* glyph = fGlyphHash[index]; 1.266 + 1.267 + if (NULL == glyph || glyph->fID != id) { 1.268 + RecordHashCollisionIf(glyph != NULL); 1.269 + glyph = this->lookupMetrics(id, kFull_MetricsType); 1.270 + fGlyphHash[index] = glyph; 1.271 + } else { 1.272 + RecordHashSuccess(); 1.273 + if (glyph->isJustAdvance()) { 1.274 + fScalerContext->getMetrics(glyph); 1.275 + } 1.276 + } 1.277 + SkASSERT(glyph->isFullMetrics()); 1.278 + return *glyph; 1.279 +} 1.280 + 1.281 +SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) { 1.282 + SkGlyph* glyph; 1.283 + 1.284 + int hi = 0; 1.285 + int count = fGlyphArray.count(); 1.286 + 1.287 + if (count) { 1.288 + SkGlyph** gptr = fGlyphArray.begin(); 1.289 + int lo = 0; 1.290 + 1.291 + hi = count - 1; 1.292 + while (lo < hi) { 1.293 + int mid = (hi + lo) >> 1; 1.294 + if (gptr[mid]->fID < id) { 1.295 + lo = mid + 1; 1.296 + } else { 1.297 + hi = mid; 1.298 + } 1.299 + } 1.300 + glyph = gptr[hi]; 1.301 + if (glyph->fID == id) { 1.302 + if (kFull_MetricsType == mtype && glyph->isJustAdvance()) { 1.303 + fScalerContext->getMetrics(glyph); 1.304 + } 1.305 + return glyph; 1.306 + } 1.307 + 1.308 + // check if we need to bump hi before falling though to the allocator 1.309 + if (glyph->fID < id) { 1.310 + hi += 1; 1.311 + } 1.312 + } 1.313 + 1.314 + // not found, but hi tells us where to inser the new glyph 1.315 + fMemoryUsed += sizeof(SkGlyph); 1.316 + 1.317 + glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph), 1.318 + SkChunkAlloc::kThrow_AllocFailType); 1.319 + glyph->init(id); 1.320 + *fGlyphArray.insert(hi) = glyph; 1.321 + 1.322 + if (kJustAdvance_MetricsType == mtype) { 1.323 + fScalerContext->getAdvance(glyph); 1.324 + } else { 1.325 + SkASSERT(kFull_MetricsType == mtype); 1.326 + fScalerContext->getMetrics(glyph); 1.327 + } 1.328 + 1.329 + return glyph; 1.330 +} 1.331 + 1.332 +const void* SkGlyphCache::findImage(const SkGlyph& glyph) { 1.333 + if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) { 1.334 + if (glyph.fImage == NULL) { 1.335 + size_t size = glyph.computeImageSize(); 1.336 + const_cast<SkGlyph&>(glyph).fImage = fGlyphAlloc.alloc(size, 1.337 + SkChunkAlloc::kReturnNil_AllocFailType); 1.338 + // check that alloc() actually succeeded 1.339 + if (glyph.fImage) { 1.340 + fScalerContext->getImage(glyph); 1.341 + // TODO: the scaler may have changed the maskformat during 1.342 + // getImage (e.g. from AA or LCD to BW) which means we may have 1.343 + // overallocated the buffer. Check if the new computedImageSize 1.344 + // is smaller, and if so, strink the alloc size in fImageAlloc. 1.345 + fMemoryUsed += size; 1.346 + } 1.347 + } 1.348 + } 1.349 + return glyph.fImage; 1.350 +} 1.351 + 1.352 +const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) { 1.353 + if (glyph.fWidth) { 1.354 + if (glyph.fPath == NULL) { 1.355 + const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath); 1.356 + fScalerContext->getPath(glyph, glyph.fPath); 1.357 + fMemoryUsed += sizeof(SkPath) + 1.358 + glyph.fPath->countPoints() * sizeof(SkPoint); 1.359 + } 1.360 + } 1.361 + return glyph.fPath; 1.362 +} 1.363 + 1.364 +/////////////////////////////////////////////////////////////////////////////// 1.365 + 1.366 +bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const { 1.367 + const AuxProcRec* rec = fAuxProcList; 1.368 + while (rec) { 1.369 + if (rec->fProc == proc) { 1.370 + if (dataPtr) { 1.371 + *dataPtr = rec->fData; 1.372 + } 1.373 + return true; 1.374 + } 1.375 + rec = rec->fNext; 1.376 + } 1.377 + return false; 1.378 +} 1.379 + 1.380 +void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) { 1.381 + if (proc == NULL) { 1.382 + return; 1.383 + } 1.384 + 1.385 + AuxProcRec* rec = fAuxProcList; 1.386 + while (rec) { 1.387 + if (rec->fProc == proc) { 1.388 + rec->fData = data; 1.389 + return; 1.390 + } 1.391 + rec = rec->fNext; 1.392 + } 1.393 + // not found, create a new rec 1.394 + rec = SkNEW(AuxProcRec); 1.395 + rec->fProc = proc; 1.396 + rec->fData = data; 1.397 + rec->fNext = fAuxProcList; 1.398 + fAuxProcList = rec; 1.399 +} 1.400 + 1.401 +void SkGlyphCache::invokeAndRemoveAuxProcs() { 1.402 + AuxProcRec* rec = fAuxProcList; 1.403 + while (rec) { 1.404 + rec->fProc(rec->fData); 1.405 + AuxProcRec* next = rec->fNext; 1.406 + SkDELETE(rec); 1.407 + rec = next; 1.408 + } 1.409 +} 1.410 + 1.411 +/////////////////////////////////////////////////////////////////////////////// 1.412 +/////////////////////////////////////////////////////////////////////////////// 1.413 + 1.414 +#include "SkThread.h" 1.415 + 1.416 +size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { 1.417 + static const size_t minLimit = 256 * 1024; 1.418 + if (newLimit < minLimit) { 1.419 + newLimit = minLimit; 1.420 + } 1.421 + 1.422 + SkAutoMutexAcquire ac(fMutex); 1.423 + 1.424 + size_t prevLimit = fCacheSizeLimit; 1.425 + fCacheSizeLimit = newLimit; 1.426 + this->internalPurge(); 1.427 + return prevLimit; 1.428 +} 1.429 + 1.430 +int SkGlyphCache_Globals::setCacheCountLimit(int newCount) { 1.431 + if (newCount < 0) { 1.432 + newCount = 0; 1.433 + } 1.434 + 1.435 + SkAutoMutexAcquire ac(fMutex); 1.436 + 1.437 + int prevCount = fCacheCountLimit; 1.438 + fCacheCountLimit = newCount; 1.439 + this->internalPurge(); 1.440 + return prevCount; 1.441 +} 1.442 + 1.443 +void SkGlyphCache_Globals::purgeAll() { 1.444 + SkAutoMutexAcquire ac(fMutex); 1.445 + this->internalPurge(fTotalMemoryUsed); 1.446 +} 1.447 + 1.448 +void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), 1.449 + void* context) { 1.450 + SkGlyphCache_Globals& globals = getGlobals(); 1.451 + SkAutoMutexAcquire ac(globals.fMutex); 1.452 + SkGlyphCache* cache; 1.453 + 1.454 + globals.validate(); 1.455 + 1.456 + for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) { 1.457 + if (proc(cache, context)) { 1.458 + break; 1.459 + } 1.460 + } 1.461 + 1.462 + globals.validate(); 1.463 +} 1.464 + 1.465 +/* This guy calls the visitor from within the mutext lock, so the visitor 1.466 + cannot: 1.467 + - take too much time 1.468 + - try to acquire the mutext again 1.469 + - call a fontscaler (which might call into the cache) 1.470 +*/ 1.471 +SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, 1.472 + const SkDescriptor* desc, 1.473 + bool (*proc)(const SkGlyphCache*, void*), 1.474 + void* context) { 1.475 + if (!typeface) { 1.476 + typeface = SkTypeface::GetDefaultTypeface(); 1.477 + } 1.478 + SkASSERT(desc); 1.479 + 1.480 + SkGlyphCache_Globals& globals = getGlobals(); 1.481 + SkAutoMutexAcquire ac(globals.fMutex); 1.482 + SkGlyphCache* cache; 1.483 + bool insideMutex = true; 1.484 + 1.485 + globals.validate(); 1.486 + 1.487 + for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) { 1.488 + if (cache->fDesc->equals(*desc)) { 1.489 + globals.internalDetachCache(cache); 1.490 + goto FOUND_IT; 1.491 + } 1.492 + } 1.493 + 1.494 + /* Release the mutex now, before we create a new entry (which might have 1.495 + side-effects like trying to access the cache/mutex (yikes!) 1.496 + */ 1.497 + ac.release(); // release the mutex now 1.498 + insideMutex = false; // can't use globals anymore 1.499 + 1.500 + // Check if we can create a scaler-context before creating the glyphcache. 1.501 + // If not, we may have exhausted OS/font resources, so try purging the 1.502 + // cache once and try again. 1.503 + { 1.504 + // pass true the first time, to notice if the scalercontext failed, 1.505 + // so we can try the purge. 1.506 + SkScalerContext* ctx = typeface->createScalerContext(desc, true); 1.507 + if (!ctx) { 1.508 + getSharedGlobals().purgeAll(); 1.509 + ctx = typeface->createScalerContext(desc, false); 1.510 + SkASSERT(ctx); 1.511 + } 1.512 + cache = SkNEW_ARGS(SkGlyphCache, (typeface, desc, ctx)); 1.513 + } 1.514 + 1.515 +FOUND_IT: 1.516 + 1.517 + AutoValidate av(cache); 1.518 + 1.519 + if (!proc(cache, context)) { // need to reattach 1.520 + if (insideMutex) { 1.521 + globals.internalAttachCacheToHead(cache); 1.522 + } else { 1.523 + globals.attachCacheToHead(cache); 1.524 + } 1.525 + cache = NULL; 1.526 + } 1.527 + return cache; 1.528 +} 1.529 + 1.530 +void SkGlyphCache::AttachCache(SkGlyphCache* cache) { 1.531 + SkASSERT(cache); 1.532 + SkASSERT(cache->fNext == NULL); 1.533 + 1.534 + getGlobals().attachCacheToHead(cache); 1.535 +} 1.536 + 1.537 +/////////////////////////////////////////////////////////////////////////////// 1.538 + 1.539 +void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { 1.540 + SkAutoMutexAcquire ac(fMutex); 1.541 + 1.542 + this->validate(); 1.543 + cache->validate(); 1.544 + 1.545 + this->internalAttachCacheToHead(cache); 1.546 + this->internalPurge(); 1.547 +} 1.548 + 1.549 +SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const { 1.550 + SkGlyphCache* cache = fHead; 1.551 + if (cache) { 1.552 + while (cache->fNext) { 1.553 + cache = cache->fNext; 1.554 + } 1.555 + } 1.556 + return cache; 1.557 +} 1.558 + 1.559 +size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) { 1.560 + this->validate(); 1.561 + 1.562 + size_t bytesNeeded = 0; 1.563 + if (fTotalMemoryUsed > fCacheSizeLimit) { 1.564 + bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit; 1.565 + } 1.566 + bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded); 1.567 + if (bytesNeeded) { 1.568 + // no small purges! 1.569 + bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed >> 2); 1.570 + } 1.571 + 1.572 + int countNeeded = 0; 1.573 + if (fCacheCount > fCacheCountLimit) { 1.574 + countNeeded = fCacheCount - fCacheCountLimit; 1.575 + // no small purges! 1.576 + countNeeded = SkMax32(countNeeded, fCacheCount >> 2); 1.577 + } 1.578 + 1.579 + // early exit 1.580 + if (!countNeeded && !bytesNeeded) { 1.581 + return 0; 1.582 + } 1.583 + 1.584 + size_t bytesFreed = 0; 1.585 + int countFreed = 0; 1.586 + 1.587 + // we start at the tail and proceed backwards, as the linklist is in LRU 1.588 + // order, with unimportant entries at the tail. 1.589 + SkGlyphCache* cache = this->internalGetTail(); 1.590 + while (cache != NULL && 1.591 + (bytesFreed < bytesNeeded || countFreed < countNeeded)) { 1.592 + SkGlyphCache* prev = cache->fPrev; 1.593 + bytesFreed += cache->fMemoryUsed; 1.594 + countFreed += 1; 1.595 + 1.596 + this->internalDetachCache(cache); 1.597 + SkDELETE(cache); 1.598 + cache = prev; 1.599 + } 1.600 + 1.601 + this->validate(); 1.602 + 1.603 +#ifdef SPEW_PURGE_STATUS 1.604 + if (countFreed && !gSkSuppressFontCachePurgeSpew) { 1.605 + SkDebugf("purging %dK from font cache [%d entries]\n", 1.606 + (int)(bytesFreed >> 10), countFreed); 1.607 + } 1.608 +#endif 1.609 + 1.610 + return bytesFreed; 1.611 +} 1.612 + 1.613 +void SkGlyphCache_Globals::internalAttachCacheToHead(SkGlyphCache* cache) { 1.614 + SkASSERT(NULL == cache->fPrev && NULL == cache->fNext); 1.615 + if (fHead) { 1.616 + fHead->fPrev = cache; 1.617 + cache->fNext = fHead; 1.618 + } 1.619 + fHead = cache; 1.620 + 1.621 + fCacheCount += 1; 1.622 + fTotalMemoryUsed += cache->fMemoryUsed; 1.623 +} 1.624 + 1.625 +void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) { 1.626 + SkASSERT(fCacheCount > 0); 1.627 + fCacheCount -= 1; 1.628 + fTotalMemoryUsed -= cache->fMemoryUsed; 1.629 + 1.630 + if (cache->fPrev) { 1.631 + cache->fPrev->fNext = cache->fNext; 1.632 + } else { 1.633 + fHead = cache->fNext; 1.634 + } 1.635 + if (cache->fNext) { 1.636 + cache->fNext->fPrev = cache->fPrev; 1.637 + } 1.638 + cache->fPrev = cache->fNext = NULL; 1.639 +} 1.640 + 1.641 +/////////////////////////////////////////////////////////////////////////////// 1.642 + 1.643 +#ifdef SK_DEBUG 1.644 + 1.645 +void SkGlyphCache::validate() const { 1.646 +#ifdef SK_DEBUG_GLYPH_CACHE 1.647 + int count = fGlyphArray.count(); 1.648 + for (int i = 0; i < count; i++) { 1.649 + const SkGlyph* glyph = fGlyphArray[i]; 1.650 + SkASSERT(glyph); 1.651 + SkASSERT(fGlyphAlloc.contains(glyph)); 1.652 + if (glyph->fImage) { 1.653 + SkASSERT(fGlyphAlloc.contains(glyph->fImage)); 1.654 + } 1.655 + } 1.656 +#endif 1.657 +} 1.658 + 1.659 +void SkGlyphCache_Globals::validate() const { 1.660 + size_t computedBytes = 0; 1.661 + int computedCount = 0; 1.662 + 1.663 + const SkGlyphCache* head = fHead; 1.664 + while (head != NULL) { 1.665 + computedBytes += head->fMemoryUsed; 1.666 + computedCount += 1; 1.667 + head = head->fNext; 1.668 + } 1.669 + 1.670 + SkASSERT(fTotalMemoryUsed == computedBytes); 1.671 + SkASSERT(fCacheCount == computedCount); 1.672 +} 1.673 + 1.674 +#endif 1.675 + 1.676 +/////////////////////////////////////////////////////////////////////////////// 1.677 +/////////////////////////////////////////////////////////////////////////////// 1.678 + 1.679 +#include "SkTypefaceCache.h" 1.680 + 1.681 +size_t SkGraphics::GetFontCacheLimit() { 1.682 + return getSharedGlobals().getCacheSizeLimit(); 1.683 +} 1.684 + 1.685 +size_t SkGraphics::SetFontCacheLimit(size_t bytes) { 1.686 + return getSharedGlobals().setCacheSizeLimit(bytes); 1.687 +} 1.688 + 1.689 +size_t SkGraphics::GetFontCacheUsed() { 1.690 + return getSharedGlobals().getTotalMemoryUsed(); 1.691 +} 1.692 + 1.693 +int SkGraphics::GetFontCacheCountLimit() { 1.694 + return getSharedGlobals().getCacheCountLimit(); 1.695 +} 1.696 + 1.697 +int SkGraphics::SetFontCacheCountLimit(int count) { 1.698 + return getSharedGlobals().setCacheCountLimit(count); 1.699 +} 1.700 + 1.701 +int SkGraphics::GetFontCacheCountUsed() { 1.702 + return getSharedGlobals().getCacheCountUsed(); 1.703 +} 1.704 + 1.705 +void SkGraphics::PurgeFontCache() { 1.706 + getSharedGlobals().purgeAll(); 1.707 + SkTypefaceCache::PurgeAll(); 1.708 +} 1.709 + 1.710 +size_t SkGraphics::GetTLSFontCacheLimit() { 1.711 + const SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS(); 1.712 + return tls ? tls->getCacheSizeLimit() : 0; 1.713 +} 1.714 + 1.715 +void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { 1.716 + if (0 == bytes) { 1.717 + SkGlyphCache_Globals::DeleteTLS(); 1.718 + } else { 1.719 + SkGlyphCache_Globals::GetTLS().setCacheSizeLimit(bytes); 1.720 + } 1.721 +}