gfx/skia/trunk/src/core/SkGlyphCache.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     2 /*
     3  * Copyright 2006 The Android Open Source Project
     4  *
     5  * Use of this source code is governed by a BSD-style license that can be
     6  * found in the LICENSE file.
     7  */
    10 #include "SkGlyphCache.h"
    11 #include "SkGlyphCache_Globals.h"
    12 #include "SkGraphics.h"
    13 #include "SkPaint.h"
    14 #include "SkPath.h"
    15 #include "SkTemplates.h"
    16 #include "SkTLS.h"
    17 #include "SkTypeface.h"
    19 //#define SPEW_PURGE_STATUS
    20 //#define RECORD_HASH_EFFICIENCY
    22 bool gSkSuppressFontCachePurgeSpew;
    24 // Returns the shared globals
    25 static SkGlyphCache_Globals& getSharedGlobals() {
    26     // we leak this, so we don't incur any shutdown cost of the destructor
    27     static SkGlyphCache_Globals* gGlobals = SkNEW_ARGS(SkGlyphCache_Globals,
    28                                                        (SkGlyphCache_Globals::kYes_UseMutex));
    29     return *gGlobals;
    30 }
    32 // Returns the TLS globals (if set), or the shared globals
    33 static SkGlyphCache_Globals& getGlobals() {
    34     SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS();
    35     return tls ? *tls : getSharedGlobals();
    36 }
    38 ///////////////////////////////////////////////////////////////////////////////
    40 #ifdef RECORD_HASH_EFFICIENCY
    41     static uint32_t gHashSuccess;
    42     static uint32_t gHashCollision;
    44     static void RecordHashSuccess() {
    45         gHashSuccess += 1;
    46     }
    48     static void RecordHashCollisionIf(bool pred) {
    49         if (pred) {
    50             gHashCollision += 1;
    52             uint32_t total = gHashSuccess + gHashCollision;
    53             SkDebugf("Font Cache Hash success rate: %d%%\n",
    54                      100 * gHashSuccess / total);
    55         }
    56     }
    57 #else
    58     #define RecordHashSuccess() (void)0
    59     #define RecordHashCollisionIf(pred) (void)0
    60 #endif
    61 #define RecordHashCollision() RecordHashCollisionIf(true)
    63 ///////////////////////////////////////////////////////////////////////////////
    65 // so we don't grow our arrays a lot
    66 #define kMinGlyphCount      16
    67 #define kMinGlyphImageSize  (16*2)
    68 #define kMinAllocAmount     ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphCount)
    70 SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkScalerContext* ctx)
    71         : fScalerContext(ctx), fGlyphAlloc(kMinAllocAmount) {
    72     SkASSERT(typeface);
    73     SkASSERT(desc);
    74     SkASSERT(ctx);
    76     fPrev = fNext = NULL;
    78     fDesc = desc->copy();
    79     fScalerContext->getFontMetrics(&fFontMetrics);
    81     // init to 0 so that all of the pointers will be null
    82     memset(fGlyphHash, 0, sizeof(fGlyphHash));
    83     // init with 0xFF so that the charCode field will be -1, which is invalid
    84     memset(fCharToGlyphHash, 0xFF, sizeof(fCharToGlyphHash));
    86     fMemoryUsed = sizeof(*this);
    88     fGlyphArray.setReserve(kMinGlyphCount);
    90     fAuxProcList = NULL;
    91 }
    93 SkGlyphCache::~SkGlyphCache() {
    94 #if 0
    95     {
    96         size_t ptrMem = fGlyphArray.count() * sizeof(SkGlyph*);
    97         size_t glyphAlloc = fGlyphAlloc.totalCapacity();
    98         size_t glyphHashUsed = 0;
    99         size_t uniHashUsed = 0;
   100         for (int i = 0; i < kHashCount; ++i) {
   101             glyphHashUsed += fGlyphHash[i] ? sizeof(fGlyphHash[0]) : 0;
   102             uniHashUsed += fCharToGlyphHash[i].fID != 0xFFFFFFFF ? sizeof(fCharToGlyphHash[0]) : 0;
   103         }
   104         size_t glyphUsed = fGlyphArray.count() * sizeof(SkGlyph);
   105         size_t imageUsed = 0;
   106         for (int i = 0; i < fGlyphArray.count(); ++i) {
   107             const SkGlyph& g = *fGlyphArray[i];
   108             if (g.fImage) {
   109                 imageUsed += g.fHeight * g.rowBytes();
   110             }
   111         }
   113         printf("glyphPtrArray,%zu, Alloc,%zu, imageUsed,%zu, glyphUsed,%zu, glyphHashAlloc,%zu, glyphHashUsed,%zu, unicharHashAlloc,%zu, unicharHashUsed,%zu\n",
   114                  ptrMem, glyphAlloc, imageUsed, glyphUsed, sizeof(fGlyphHash), glyphHashUsed, sizeof(fCharToGlyphHash), uniHashUsed);
   116     }
   117 #endif
   118     SkGlyph**   gptr = fGlyphArray.begin();
   119     SkGlyph**   stop = fGlyphArray.end();
   120     while (gptr < stop) {
   121         SkPath* path = (*gptr)->fPath;
   122         if (path) {
   123             SkDELETE(path);
   124         }
   125         gptr += 1;
   126     }
   127     SkDescriptor::Free(fDesc);
   128     SkDELETE(fScalerContext);
   129     this->invokeAndRemoveAuxProcs();
   130 }
   132 ///////////////////////////////////////////////////////////////////////////////
   134 #ifdef SK_DEBUG
   135 #define VALIDATE()  AutoValidate av(this)
   136 #else
   137 #define VALIDATE()
   138 #endif
   140 uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) {
   141     VALIDATE();
   142     uint32_t id = SkGlyph::MakeID(charCode);
   143     const CharGlyphRec& rec = fCharToGlyphHash[ID2HashIndex(id)];
   145     if (rec.fID == id) {
   146         return rec.fGlyph->getGlyphID();
   147     } else {
   148         return fScalerContext->charToGlyphID(charCode);
   149     }
   150 }
   152 SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) {
   153     return fScalerContext->glyphIDToChar(glyphID);
   154 }
   156 unsigned SkGlyphCache::getGlyphCount() {
   157     return fScalerContext->getGlyphCount();
   158 }
   160 ///////////////////////////////////////////////////////////////////////////////
   162 const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) {
   163     VALIDATE();
   164     uint32_t id = SkGlyph::MakeID(charCode);
   165     CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
   167     if (rec->fID != id) {
   168         // this ID is based on the UniChar
   169         rec->fID = id;
   170         // this ID is based on the glyph index
   171         id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode));
   172         rec->fGlyph = this->lookupMetrics(id, kJustAdvance_MetricsType);
   173     }
   174     return *rec->fGlyph;
   175 }
   177 const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) {
   178     VALIDATE();
   179     uint32_t id = SkGlyph::MakeID(glyphID);
   180     unsigned index = ID2HashIndex(id);
   181     SkGlyph* glyph = fGlyphHash[index];
   183     if (NULL == glyph || glyph->fID != id) {
   184         glyph = this->lookupMetrics(glyphID, kJustAdvance_MetricsType);
   185         fGlyphHash[index] = glyph;
   186     }
   187     return *glyph;
   188 }
   190 ///////////////////////////////////////////////////////////////////////////////
   192 const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) {
   193     VALIDATE();
   194     uint32_t id = SkGlyph::MakeID(charCode);
   195     CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
   197     if (rec->fID != id) {
   198         RecordHashCollisionIf(rec->fGlyph != NULL);
   199         // this ID is based on the UniChar
   200         rec->fID = id;
   201         // this ID is based on the glyph index
   202         id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode));
   203         rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType);
   204     } else {
   205         RecordHashSuccess();
   206         if (rec->fGlyph->isJustAdvance()) {
   207             fScalerContext->getMetrics(rec->fGlyph);
   208         }
   209     }
   210     SkASSERT(rec->fGlyph->isFullMetrics());
   211     return *rec->fGlyph;
   212 }
   214 const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode,
   215                                                SkFixed x, SkFixed y) {
   216     VALIDATE();
   217     uint32_t id = SkGlyph::MakeID(charCode, x, y);
   218     CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
   220     if (rec->fID != id) {
   221         RecordHashCollisionIf(rec->fGlyph != NULL);
   222         // this ID is based on the UniChar
   223         rec->fID = id;
   224         // this ID is based on the glyph index
   225         id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode), x, y);
   226         rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType);
   227     } else {
   228         RecordHashSuccess();
   229         if (rec->fGlyph->isJustAdvance()) {
   230             fScalerContext->getMetrics(rec->fGlyph);
   231         }
   232     }
   233     SkASSERT(rec->fGlyph->isFullMetrics());
   234     return *rec->fGlyph;
   235 }
   237 const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) {
   238     VALIDATE();
   239     uint32_t id = SkGlyph::MakeID(glyphID);
   240     unsigned index = ID2HashIndex(id);
   241     SkGlyph* glyph = fGlyphHash[index];
   243     if (NULL == glyph || glyph->fID != id) {
   244         RecordHashCollisionIf(glyph != NULL);
   245         glyph = this->lookupMetrics(glyphID, kFull_MetricsType);
   246         fGlyphHash[index] = glyph;
   247     } else {
   248         RecordHashSuccess();
   249         if (glyph->isJustAdvance()) {
   250             fScalerContext->getMetrics(glyph);
   251         }
   252     }
   253     SkASSERT(glyph->isFullMetrics());
   254     return *glyph;
   255 }
   257 const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID,
   258                                                SkFixed x, SkFixed y) {
   259     VALIDATE();
   260     uint32_t id = SkGlyph::MakeID(glyphID, x, y);
   261     unsigned index = ID2HashIndex(id);
   262     SkGlyph* glyph = fGlyphHash[index];
   264     if (NULL == glyph || glyph->fID != id) {
   265         RecordHashCollisionIf(glyph != NULL);
   266         glyph = this->lookupMetrics(id, kFull_MetricsType);
   267         fGlyphHash[index] = glyph;
   268     } else {
   269         RecordHashSuccess();
   270         if (glyph->isJustAdvance()) {
   271             fScalerContext->getMetrics(glyph);
   272         }
   273     }
   274     SkASSERT(glyph->isFullMetrics());
   275     return *glyph;
   276 }
   278 SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) {
   279     SkGlyph* glyph;
   281     int     hi = 0;
   282     int     count = fGlyphArray.count();
   284     if (count) {
   285         SkGlyph**   gptr = fGlyphArray.begin();
   286         int     lo = 0;
   288         hi = count - 1;
   289         while (lo < hi) {
   290             int mid = (hi + lo) >> 1;
   291             if (gptr[mid]->fID < id) {
   292                 lo = mid + 1;
   293             } else {
   294                 hi = mid;
   295             }
   296         }
   297         glyph = gptr[hi];
   298         if (glyph->fID == id) {
   299             if (kFull_MetricsType == mtype && glyph->isJustAdvance()) {
   300                 fScalerContext->getMetrics(glyph);
   301             }
   302             return glyph;
   303         }
   305         // check if we need to bump hi before falling though to the allocator
   306         if (glyph->fID < id) {
   307             hi += 1;
   308         }
   309     }
   311     // not found, but hi tells us where to inser the new glyph
   312     fMemoryUsed += sizeof(SkGlyph);
   314     glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph),
   315                                         SkChunkAlloc::kThrow_AllocFailType);
   316     glyph->init(id);
   317     *fGlyphArray.insert(hi) = glyph;
   319     if (kJustAdvance_MetricsType == mtype) {
   320         fScalerContext->getAdvance(glyph);
   321     } else {
   322         SkASSERT(kFull_MetricsType == mtype);
   323         fScalerContext->getMetrics(glyph);
   324     }
   326     return glyph;
   327 }
   329 const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
   330     if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) {
   331         if (glyph.fImage == NULL) {
   332             size_t  size = glyph.computeImageSize();
   333             const_cast<SkGlyph&>(glyph).fImage = fGlyphAlloc.alloc(size,
   334                                         SkChunkAlloc::kReturnNil_AllocFailType);
   335             // check that alloc() actually succeeded
   336             if (glyph.fImage) {
   337                 fScalerContext->getImage(glyph);
   338                 // TODO: the scaler may have changed the maskformat during
   339                 // getImage (e.g. from AA or LCD to BW) which means we may have
   340                 // overallocated the buffer. Check if the new computedImageSize
   341                 // is smaller, and if so, strink the alloc size in fImageAlloc.
   342                 fMemoryUsed += size;
   343             }
   344         }
   345     }
   346     return glyph.fImage;
   347 }
   349 const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) {
   350     if (glyph.fWidth) {
   351         if (glyph.fPath == NULL) {
   352             const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath);
   353             fScalerContext->getPath(glyph, glyph.fPath);
   354             fMemoryUsed += sizeof(SkPath) +
   355                     glyph.fPath->countPoints() * sizeof(SkPoint);
   356         }
   357     }
   358     return glyph.fPath;
   359 }
   361 ///////////////////////////////////////////////////////////////////////////////
   363 bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const {
   364     const AuxProcRec* rec = fAuxProcList;
   365     while (rec) {
   366         if (rec->fProc == proc) {
   367             if (dataPtr) {
   368                 *dataPtr = rec->fData;
   369             }
   370             return true;
   371         }
   372         rec = rec->fNext;
   373     }
   374     return false;
   375 }
   377 void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) {
   378     if (proc == NULL) {
   379         return;
   380     }
   382     AuxProcRec* rec = fAuxProcList;
   383     while (rec) {
   384         if (rec->fProc == proc) {
   385             rec->fData = data;
   386             return;
   387         }
   388         rec = rec->fNext;
   389     }
   390     // not found, create a new rec
   391     rec = SkNEW(AuxProcRec);
   392     rec->fProc = proc;
   393     rec->fData = data;
   394     rec->fNext = fAuxProcList;
   395     fAuxProcList = rec;
   396 }
   398 void SkGlyphCache::invokeAndRemoveAuxProcs() {
   399     AuxProcRec* rec = fAuxProcList;
   400     while (rec) {
   401         rec->fProc(rec->fData);
   402         AuxProcRec* next = rec->fNext;
   403         SkDELETE(rec);
   404         rec = next;
   405     }
   406 }
   408 ///////////////////////////////////////////////////////////////////////////////
   409 ///////////////////////////////////////////////////////////////////////////////
   411 #include "SkThread.h"
   413 size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) {
   414     static const size_t minLimit = 256 * 1024;
   415     if (newLimit < minLimit) {
   416         newLimit = minLimit;
   417     }
   419     SkAutoMutexAcquire    ac(fMutex);
   421     size_t prevLimit = fCacheSizeLimit;
   422     fCacheSizeLimit = newLimit;
   423     this->internalPurge();
   424     return prevLimit;
   425 }
   427 int SkGlyphCache_Globals::setCacheCountLimit(int newCount) {
   428     if (newCount < 0) {
   429         newCount = 0;
   430     }
   432     SkAutoMutexAcquire    ac(fMutex);
   434     int prevCount = fCacheCountLimit;
   435     fCacheCountLimit = newCount;
   436     this->internalPurge();
   437     return prevCount;
   438 }
   440 void SkGlyphCache_Globals::purgeAll() {
   441     SkAutoMutexAcquire    ac(fMutex);
   442     this->internalPurge(fTotalMemoryUsed);
   443 }
   445 void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*),
   446                                   void* context) {
   447     SkGlyphCache_Globals& globals = getGlobals();
   448     SkAutoMutexAcquire    ac(globals.fMutex);
   449     SkGlyphCache*         cache;
   451     globals.validate();
   453     for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) {
   454         if (proc(cache, context)) {
   455             break;
   456         }
   457     }
   459     globals.validate();
   460 }
   462 /*  This guy calls the visitor from within the mutext lock, so the visitor
   463     cannot:
   464     - take too much time
   465     - try to acquire the mutext again
   466     - call a fontscaler (which might call into the cache)
   467 */
   468 SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface,
   469                               const SkDescriptor* desc,
   470                               bool (*proc)(const SkGlyphCache*, void*),
   471                               void* context) {
   472     if (!typeface) {
   473         typeface = SkTypeface::GetDefaultTypeface();
   474     }
   475     SkASSERT(desc);
   477     SkGlyphCache_Globals& globals = getGlobals();
   478     SkAutoMutexAcquire    ac(globals.fMutex);
   479     SkGlyphCache*         cache;
   480     bool                  insideMutex = true;
   482     globals.validate();
   484     for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) {
   485         if (cache->fDesc->equals(*desc)) {
   486             globals.internalDetachCache(cache);
   487             goto FOUND_IT;
   488         }
   489     }
   491     /* Release the mutex now, before we create a new entry (which might have
   492         side-effects like trying to access the cache/mutex (yikes!)
   493     */
   494     ac.release();           // release the mutex now
   495     insideMutex = false;    // can't use globals anymore
   497     // Check if we can create a scaler-context before creating the glyphcache.
   498     // If not, we may have exhausted OS/font resources, so try purging the
   499     // cache once and try again.
   500     {
   501         // pass true the first time, to notice if the scalercontext failed,
   502         // so we can try the purge.
   503         SkScalerContext* ctx = typeface->createScalerContext(desc, true);
   504         if (!ctx) {
   505             getSharedGlobals().purgeAll();
   506             ctx = typeface->createScalerContext(desc, false);
   507             SkASSERT(ctx);
   508         }
   509         cache = SkNEW_ARGS(SkGlyphCache, (typeface, desc, ctx));
   510     }
   512 FOUND_IT:
   514     AutoValidate av(cache);
   516     if (!proc(cache, context)) {   // need to reattach
   517         if (insideMutex) {
   518             globals.internalAttachCacheToHead(cache);
   519         } else {
   520             globals.attachCacheToHead(cache);
   521         }
   522         cache = NULL;
   523     }
   524     return cache;
   525 }
   527 void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
   528     SkASSERT(cache);
   529     SkASSERT(cache->fNext == NULL);
   531     getGlobals().attachCacheToHead(cache);
   532 }
   534 ///////////////////////////////////////////////////////////////////////////////
   536 void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) {
   537     SkAutoMutexAcquire    ac(fMutex);
   539     this->validate();
   540     cache->validate();
   542     this->internalAttachCacheToHead(cache);
   543     this->internalPurge();
   544 }
   546 SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const {
   547     SkGlyphCache* cache = fHead;
   548     if (cache) {
   549         while (cache->fNext) {
   550             cache = cache->fNext;
   551         }
   552     }
   553     return cache;
   554 }
   556 size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) {
   557     this->validate();
   559     size_t bytesNeeded = 0;
   560     if (fTotalMemoryUsed > fCacheSizeLimit) {
   561         bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit;
   562     }
   563     bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded);
   564     if (bytesNeeded) {
   565         // no small purges!
   566         bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed >> 2);
   567     }
   569     int countNeeded = 0;
   570     if (fCacheCount > fCacheCountLimit) {
   571         countNeeded = fCacheCount - fCacheCountLimit;
   572         // no small purges!
   573         countNeeded = SkMax32(countNeeded, fCacheCount >> 2);
   574     }
   576     // early exit
   577     if (!countNeeded && !bytesNeeded) {
   578         return 0;
   579     }
   581     size_t  bytesFreed = 0;
   582     int     countFreed = 0;
   584     // we start at the tail and proceed backwards, as the linklist is in LRU
   585     // order, with unimportant entries at the tail.
   586     SkGlyphCache* cache = this->internalGetTail();
   587     while (cache != NULL &&
   588            (bytesFreed < bytesNeeded || countFreed < countNeeded)) {
   589         SkGlyphCache* prev = cache->fPrev;
   590         bytesFreed += cache->fMemoryUsed;
   591         countFreed += 1;
   593         this->internalDetachCache(cache);
   594         SkDELETE(cache);
   595         cache = prev;
   596     }
   598     this->validate();
   600 #ifdef SPEW_PURGE_STATUS
   601     if (countFreed && !gSkSuppressFontCachePurgeSpew) {
   602         SkDebugf("purging %dK from font cache [%d entries]\n",
   603                  (int)(bytesFreed >> 10), countFreed);
   604     }
   605 #endif
   607     return bytesFreed;
   608 }
   610 void SkGlyphCache_Globals::internalAttachCacheToHead(SkGlyphCache* cache) {
   611     SkASSERT(NULL == cache->fPrev && NULL == cache->fNext);
   612     if (fHead) {
   613         fHead->fPrev = cache;
   614         cache->fNext = fHead;
   615     }
   616     fHead = cache;
   618     fCacheCount += 1;
   619     fTotalMemoryUsed += cache->fMemoryUsed;
   620 }
   622 void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) {
   623     SkASSERT(fCacheCount > 0);
   624     fCacheCount -= 1;
   625     fTotalMemoryUsed -= cache->fMemoryUsed;
   627     if (cache->fPrev) {
   628         cache->fPrev->fNext = cache->fNext;
   629     } else {
   630         fHead = cache->fNext;
   631     }
   632     if (cache->fNext) {
   633         cache->fNext->fPrev = cache->fPrev;
   634     }
   635     cache->fPrev = cache->fNext = NULL;
   636 }
   638 ///////////////////////////////////////////////////////////////////////////////
   640 #ifdef SK_DEBUG
   642 void SkGlyphCache::validate() const {
   643 #ifdef SK_DEBUG_GLYPH_CACHE
   644     int count = fGlyphArray.count();
   645     for (int i = 0; i < count; i++) {
   646         const SkGlyph* glyph = fGlyphArray[i];
   647         SkASSERT(glyph);
   648         SkASSERT(fGlyphAlloc.contains(glyph));
   649         if (glyph->fImage) {
   650             SkASSERT(fGlyphAlloc.contains(glyph->fImage));
   651         }
   652     }
   653 #endif
   654 }
   656 void SkGlyphCache_Globals::validate() const {
   657     size_t computedBytes = 0;
   658     int computedCount = 0;
   660     const SkGlyphCache* head = fHead;
   661     while (head != NULL) {
   662         computedBytes += head->fMemoryUsed;
   663         computedCount += 1;
   664         head = head->fNext;
   665     }
   667     SkASSERT(fTotalMemoryUsed == computedBytes);
   668     SkASSERT(fCacheCount == computedCount);
   669 }
   671 #endif
   673 ///////////////////////////////////////////////////////////////////////////////
   674 ///////////////////////////////////////////////////////////////////////////////
   676 #include "SkTypefaceCache.h"
   678 size_t SkGraphics::GetFontCacheLimit() {
   679     return getSharedGlobals().getCacheSizeLimit();
   680 }
   682 size_t SkGraphics::SetFontCacheLimit(size_t bytes) {
   683     return getSharedGlobals().setCacheSizeLimit(bytes);
   684 }
   686 size_t SkGraphics::GetFontCacheUsed() {
   687     return getSharedGlobals().getTotalMemoryUsed();
   688 }
   690 int SkGraphics::GetFontCacheCountLimit() {
   691     return getSharedGlobals().getCacheCountLimit();
   692 }
   694 int SkGraphics::SetFontCacheCountLimit(int count) {
   695     return getSharedGlobals().setCacheCountLimit(count);
   696 }
   698 int SkGraphics::GetFontCacheCountUsed() {
   699     return getSharedGlobals().getCacheCountUsed();
   700 }
   702 void SkGraphics::PurgeFontCache() {
   703     getSharedGlobals().purgeAll();
   704     SkTypefaceCache::PurgeAll();
   705 }
   707 size_t SkGraphics::GetTLSFontCacheLimit() {
   708     const SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS();
   709     return tls ? tls->getCacheSizeLimit() : 0;
   710 }
   712 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) {
   713     if (0 == bytes) {
   714         SkGlyphCache_Globals::DeleteTLS();
   715     } else {
   716         SkGlyphCache_Globals::GetTLS().setCacheSizeLimit(bytes);
   717     }
   718 }

mercurial