LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkGlyphCache.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 305 0 0.0 %
Date: 2012-06-02 Functions: 30 0 0.0 %

       1                 : 
       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                 :  */
       8                 : 
       9                 : 
      10                 : #include "SkGlyphCache.h"
      11                 : #include "SkGraphics.h"
      12                 : #include "SkPaint.h"
      13                 : #include "SkTemplates.h"
      14                 : 
      15                 : #define SPEW_PURGE_STATUS
      16                 : //#define USE_CACHE_HASH
      17                 : //#define RECORD_HASH_EFFICIENCY
      18                 : 
      19                 : bool gSkSuppressFontCachePurgeSpew;
      20                 : 
      21                 : ///////////////////////////////////////////////////////////////////////////////
      22                 : 
      23                 : #ifdef RECORD_HASH_EFFICIENCY
      24                 :     static uint32_t gHashSuccess;
      25                 :     static uint32_t gHashCollision;
      26                 : 
      27                 :     static void RecordHashSuccess() {
      28                 :         gHashSuccess += 1;
      29                 :     }
      30                 : 
      31                 :     static void RecordHashCollisionIf(bool pred) {
      32                 :         if (pred) {
      33                 :             gHashCollision += 1;
      34                 : 
      35                 :             uint32_t total = gHashSuccess + gHashCollision;
      36                 :             SkDebugf("Font Cache Hash success rate: %d%%\n",
      37                 :                      100 * gHashSuccess / total);
      38                 :         }
      39                 :     }
      40                 : #else
      41                 :     #define RecordHashSuccess() (void)0
      42                 :     #define RecordHashCollisionIf(pred) (void)0
      43                 : #endif
      44                 : #define RecordHashCollision() RecordHashCollisionIf(true)
      45                 : 
      46                 : ///////////////////////////////////////////////////////////////////////////////
      47                 : 
      48                 : #define kMinGlphAlloc       (sizeof(SkGlyph) * 64)
      49                 : #define kMinImageAlloc      (24 * 64)   // should be pointsize-dependent
      50                 : 
      51                 : #define METRICS_RESERVE_COUNT  128  // so we don't grow this array a lot
      52                 : 
      53               0 : SkGlyphCache::SkGlyphCache(const SkDescriptor* desc)
      54               0 :         : fGlyphAlloc(kMinGlphAlloc), fImageAlloc(kMinImageAlloc) {
      55               0 :     fPrev = fNext = NULL;
      56                 : 
      57               0 :     fDesc = desc->copy();
      58               0 :     fScalerContext = SkScalerContext::Create(desc);
      59               0 :     fScalerContext->getFontMetrics(NULL, &fFontMetricsY);
      60                 : 
      61                 :     // init to 0 so that all of the pointers will be null
      62               0 :     memset(fGlyphHash, 0, sizeof(fGlyphHash));
      63                 :     // init with 0xFF so that the charCode field will be -1, which is invalid
      64               0 :     memset(fCharToGlyphHash, 0xFF, sizeof(fCharToGlyphHash));
      65                 : 
      66               0 :     fMemoryUsed = sizeof(*this) + kMinGlphAlloc + kMinImageAlloc;
      67                 : 
      68               0 :     fGlyphArray.setReserve(METRICS_RESERVE_COUNT);
      69                 : 
      70               0 :     fMetricsCount = 0;
      71               0 :     fAdvanceCount = 0;
      72               0 :     fAuxProcList = NULL;
      73               0 : }
      74                 : 
      75               0 : SkGlyphCache::~SkGlyphCache() {
      76               0 :     SkGlyph**   gptr = fGlyphArray.begin();
      77               0 :     SkGlyph**   stop = fGlyphArray.end();
      78               0 :     while (gptr < stop) {
      79               0 :         SkPath* path = (*gptr)->fPath;
      80               0 :         if (path) {
      81               0 :             SkDELETE(path);
      82                 :         }
      83               0 :         gptr += 1;
      84                 :     }
      85               0 :     SkDescriptor::Free(fDesc);
      86               0 :     SkDELETE(fScalerContext);
      87               0 :     this->invokeAndRemoveAuxProcs();
      88               0 : }
      89                 : 
      90                 : ///////////////////////////////////////////////////////////////////////////////
      91                 : 
      92                 : #ifdef SK_DEBUG
      93                 : #define VALIDATE()  AutoValidate av(this)
      94                 : #else
      95                 : #define VALIDATE()
      96                 : #endif
      97                 : 
      98               0 : uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) {
      99               0 :     VALIDATE();
     100               0 :     uint32_t id = SkGlyph::MakeID(charCode);
     101               0 :     const CharGlyphRec& rec = fCharToGlyphHash[ID2HashIndex(id)];
     102                 : 
     103               0 :     if (rec.fID == id) {
     104               0 :         return rec.fGlyph->getGlyphID();
     105                 :     } else {
     106               0 :         return fScalerContext->charToGlyphID(charCode);
     107                 :     }
     108                 : }
     109                 : 
     110               0 : SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) {
     111               0 :     return fScalerContext->glyphIDToChar(glyphID);
     112                 : }
     113                 : 
     114               0 : unsigned SkGlyphCache::getGlyphCount() {
     115               0 :     return fScalerContext->getGlyphCount();
     116                 : }
     117                 : 
     118                 : ///////////////////////////////////////////////////////////////////////////////
     119                 : 
     120               0 : const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) {
     121               0 :     VALIDATE();
     122               0 :     uint32_t id = SkGlyph::MakeID(charCode);
     123               0 :     CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
     124                 : 
     125               0 :     if (rec->fID != id) {
     126                 :         // this ID is based on the UniChar
     127               0 :         rec->fID = id;
     128                 :         // this ID is based on the glyph index
     129               0 :         id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode));
     130               0 :         rec->fGlyph = this->lookupMetrics(id, kJustAdvance_MetricsType);
     131                 :     }
     132               0 :     return *rec->fGlyph;
     133                 : }
     134                 : 
     135               0 : const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) {
     136               0 :     VALIDATE();
     137               0 :     uint32_t id = SkGlyph::MakeID(glyphID);
     138               0 :     unsigned index = ID2HashIndex(id);
     139               0 :     SkGlyph* glyph = fGlyphHash[index];
     140                 : 
     141               0 :     if (NULL == glyph || glyph->fID != id) {
     142               0 :         glyph = this->lookupMetrics(glyphID, kJustAdvance_MetricsType);
     143               0 :         fGlyphHash[index] = glyph;
     144                 :     }
     145               0 :     return *glyph;
     146                 : }
     147                 : 
     148                 : ///////////////////////////////////////////////////////////////////////////////
     149                 : 
     150               0 : const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) {
     151               0 :     VALIDATE();
     152               0 :     uint32_t id = SkGlyph::MakeID(charCode);
     153               0 :     CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
     154                 : 
     155               0 :     if (rec->fID != id) {
     156                 :         RecordHashCollisionIf(rec->fGlyph != NULL);
     157                 :         // this ID is based on the UniChar
     158               0 :         rec->fID = id;
     159                 :         // this ID is based on the glyph index
     160               0 :         id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode));
     161               0 :         rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType);
     162                 :     } else {
     163                 :         RecordHashSuccess();
     164               0 :         if (rec->fGlyph->isJustAdvance()) {
     165               0 :             fScalerContext->getMetrics(rec->fGlyph);
     166                 :         }
     167                 :     }
     168               0 :     SkASSERT(rec->fGlyph->isFullMetrics());
     169               0 :     return *rec->fGlyph;
     170                 : }
     171                 : 
     172               0 : const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode,
     173                 :                                                SkFixed x, SkFixed y) {
     174               0 :     VALIDATE();
     175               0 :     uint32_t id = SkGlyph::MakeID(charCode, x, y);
     176               0 :     CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
     177                 : 
     178               0 :     if (rec->fID != id) {
     179                 :         RecordHashCollisionIf(rec->fGlyph != NULL);
     180                 :         // this ID is based on the UniChar
     181               0 :         rec->fID = id;
     182                 :         // this ID is based on the glyph index
     183               0 :         id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode), x, y);
     184               0 :         rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType);
     185                 :     } else {
     186                 :         RecordHashSuccess();
     187               0 :         if (rec->fGlyph->isJustAdvance()) {
     188               0 :             fScalerContext->getMetrics(rec->fGlyph);
     189                 :         }
     190                 :     }
     191               0 :     SkASSERT(rec->fGlyph->isFullMetrics());
     192               0 :     return *rec->fGlyph;
     193                 : }
     194                 : 
     195               0 : const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) {
     196               0 :     VALIDATE();
     197               0 :     uint32_t id = SkGlyph::MakeID(glyphID);
     198               0 :     unsigned index = ID2HashIndex(id);
     199               0 :     SkGlyph* glyph = fGlyphHash[index];
     200                 : 
     201               0 :     if (NULL == glyph || glyph->fID != id) {
     202                 :         RecordHashCollisionIf(glyph != NULL);
     203               0 :         glyph = this->lookupMetrics(glyphID, kFull_MetricsType);
     204               0 :         fGlyphHash[index] = glyph;
     205                 :     } else {
     206                 :         RecordHashSuccess();
     207               0 :         if (glyph->isJustAdvance()) {
     208               0 :             fScalerContext->getMetrics(glyph);
     209                 :         }
     210                 :     }
     211               0 :     SkASSERT(glyph->isFullMetrics());
     212               0 :     return *glyph;
     213                 : }
     214                 : 
     215               0 : const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID,
     216                 :                                                SkFixed x, SkFixed y) {
     217               0 :     VALIDATE();
     218               0 :     uint32_t id = SkGlyph::MakeID(glyphID, x, y);
     219               0 :     unsigned index = ID2HashIndex(id);
     220               0 :     SkGlyph* glyph = fGlyphHash[index];
     221                 : 
     222               0 :     if (NULL == glyph || glyph->fID != id) {
     223                 :         RecordHashCollisionIf(glyph != NULL);
     224               0 :         glyph = this->lookupMetrics(id, kFull_MetricsType);
     225               0 :         fGlyphHash[index] = glyph;
     226                 :     } else {
     227                 :         RecordHashSuccess();
     228               0 :         if (glyph->isJustAdvance()) {
     229               0 :             fScalerContext->getMetrics(glyph);
     230                 :         }
     231                 :     }
     232               0 :     SkASSERT(glyph->isFullMetrics());
     233               0 :     return *glyph;
     234                 : }
     235                 : 
     236               0 : SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) {
     237                 :     SkGlyph* glyph;
     238                 : 
     239               0 :     int     hi = 0;
     240               0 :     int     count = fGlyphArray.count();
     241                 : 
     242               0 :     if (count) {
     243               0 :         SkGlyph**   gptr = fGlyphArray.begin();
     244               0 :         int     lo = 0;
     245                 : 
     246               0 :         hi = count - 1;
     247               0 :         while (lo < hi) {
     248               0 :             int mid = (hi + lo) >> 1;
     249               0 :             if (gptr[mid]->fID < id) {
     250               0 :                 lo = mid + 1;
     251                 :             } else {
     252               0 :                 hi = mid;
     253                 :             }
     254                 :         }
     255               0 :         glyph = gptr[hi];
     256               0 :         if (glyph->fID == id) {
     257               0 :             if (kFull_MetricsType == mtype && glyph->isJustAdvance()) {
     258               0 :                 fScalerContext->getMetrics(glyph);
     259                 :             }
     260               0 :             return glyph;
     261                 :         }
     262                 : 
     263                 :         // check if we need to bump hi before falling though to the allocator
     264               0 :         if (glyph->fID < id) {
     265               0 :             hi += 1;
     266                 :         }
     267                 :     }
     268                 : 
     269                 :     // not found, but hi tells us where to inser the new glyph
     270               0 :     fMemoryUsed += sizeof(SkGlyph);
     271                 : 
     272                 :     glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph),
     273               0 :                                         SkChunkAlloc::kThrow_AllocFailType);
     274               0 :     glyph->init(id);
     275               0 :     *fGlyphArray.insert(hi) = glyph;
     276                 : 
     277               0 :     if (kJustAdvance_MetricsType == mtype) {
     278               0 :         fScalerContext->getAdvance(glyph);
     279               0 :         fAdvanceCount += 1;
     280                 :     } else {
     281               0 :         SkASSERT(kFull_MetricsType == mtype);
     282               0 :         fScalerContext->getMetrics(glyph);
     283               0 :         fMetricsCount += 1;
     284                 :     }
     285                 : 
     286               0 :     return glyph;
     287                 : }
     288                 : 
     289               0 : const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
     290               0 :     if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) {
     291               0 :         if (glyph.fImage == NULL) {
     292               0 :             size_t  size = glyph.computeImageSize();
     293                 :             const_cast<SkGlyph&>(glyph).fImage = fImageAlloc.alloc(size,
     294               0 :                                         SkChunkAlloc::kReturnNil_AllocFailType);
     295                 :             // check that alloc() actually succeeded
     296               0 :             if (glyph.fImage) {
     297               0 :                 fScalerContext->getImage(glyph);
     298                 :                 // TODO: the scaler may have changed the maskformat during
     299                 :                 // getImage (e.g. from AA or LCD to BW) which means we may have
     300                 :                 // overallocated the buffer. Check if the new computedImageSize
     301                 :                 // is smaller, and if so, strink the alloc size in fImageAlloc.
     302               0 :                 fMemoryUsed += size;
     303                 :             }
     304                 :         }
     305                 :     }
     306               0 :     return glyph.fImage;
     307                 : }
     308                 : 
     309               0 : const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) {
     310               0 :     if (glyph.fWidth) {
     311               0 :         if (glyph.fPath == NULL) {
     312               0 :             const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath);
     313               0 :             fScalerContext->getPath(glyph, glyph.fPath);
     314                 :             fMemoryUsed += sizeof(SkPath) +
     315               0 :                     glyph.fPath->getPoints(NULL, 0x7FFFFFFF) * sizeof(SkPoint);
     316                 :         }
     317                 :     }
     318               0 :     return glyph.fPath;
     319                 : }
     320                 : 
     321                 : ///////////////////////////////////////////////////////////////////////////////
     322                 : 
     323               0 : bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const {
     324               0 :     const AuxProcRec* rec = fAuxProcList;
     325               0 :     while (rec) {
     326               0 :         if (rec->fProc == proc) {
     327               0 :             if (dataPtr) {
     328               0 :                 *dataPtr = rec->fData;
     329                 :             }
     330               0 :             return true;
     331                 :         }
     332               0 :         rec = rec->fNext;
     333                 :     }
     334               0 :     return false;
     335                 : }
     336                 : 
     337               0 : void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) {
     338               0 :     if (proc == NULL) {
     339               0 :         return;
     340                 :     }
     341                 : 
     342               0 :     AuxProcRec* rec = fAuxProcList;
     343               0 :     while (rec) {
     344               0 :         if (rec->fProc == proc) {
     345               0 :             rec->fData = data;
     346               0 :             return;
     347                 :         }
     348               0 :         rec = rec->fNext;
     349                 :     }
     350                 :     // not found, create a new rec
     351               0 :     rec = SkNEW(AuxProcRec);
     352               0 :     rec->fProc = proc;
     353               0 :     rec->fData = data;
     354               0 :     rec->fNext = fAuxProcList;
     355               0 :     fAuxProcList = rec;
     356                 : }
     357                 : 
     358               0 : void SkGlyphCache::removeAuxProc(void (*proc)(void*)) {
     359               0 :     AuxProcRec* rec = fAuxProcList;
     360               0 :     AuxProcRec* prev = NULL;
     361               0 :     while (rec) {
     362               0 :         AuxProcRec* next = rec->fNext;
     363               0 :         if (rec->fProc == proc) {
     364               0 :             if (prev) {
     365               0 :                 prev->fNext = next;
     366                 :             } else {
     367               0 :                 fAuxProcList = next;
     368                 :             }
     369               0 :             SkDELETE(rec);
     370               0 :             return;
     371                 :         }
     372               0 :         prev = rec;
     373               0 :         rec = next;
     374                 :     }
     375                 : }
     376                 : 
     377               0 : void SkGlyphCache::invokeAndRemoveAuxProcs() {
     378               0 :     AuxProcRec* rec = fAuxProcList;
     379               0 :     while (rec) {
     380               0 :         rec->fProc(rec->fData);
     381               0 :         AuxProcRec* next = rec->fNext;
     382               0 :         SkDELETE(rec);
     383               0 :         rec = next;
     384                 :     }
     385               0 : }
     386                 : 
     387                 : ///////////////////////////////////////////////////////////////////////////////
     388                 : ///////////////////////////////////////////////////////////////////////////////
     389                 : 
     390                 : #ifdef USE_CACHE_HASH
     391                 :     #define HASH_BITCOUNT   6
     392                 :     #define HASH_COUNT      (1 << HASH_BITCOUNT)
     393                 :     #define HASH_MASK       (HASH_COUNT - 1)
     394                 : 
     395                 :     static unsigned desc_to_hashindex(const SkDescriptor* desc)
     396                 :     {
     397                 :         SkASSERT(HASH_MASK < 256);  // since our munging reduces to 8 bits
     398                 : 
     399                 :         uint32_t n = *(const uint32_t*)desc;    //desc->getChecksum();
     400                 :         SkASSERT(n == desc->getChecksum());
     401                 : 
     402                 :         // don't trust that the low bits of checksum vary enough, so...
     403                 :         n ^= (n >> 24) ^ (n >> 16) ^ (n >> 8) ^ (n >> 30);
     404                 : 
     405                 :         return n & HASH_MASK;
     406                 :     }
     407                 : #endif
     408                 : 
     409                 : #include "SkThread.h"
     410                 : 
     411                 : class SkGlyphCache_Globals {
     412                 : public:
     413               0 :     SkGlyphCache_Globals() {
     414               0 :         fHead = NULL;
     415               0 :         fTotalMemoryUsed = 0;
     416                 : #ifdef USE_CACHE_HASH
     417                 :         sk_bzero(fHash, sizeof(fHash));
     418                 : #endif
     419               0 :     }
     420                 : 
     421                 :     SkMutex         fMutex;
     422                 :     SkGlyphCache*   fHead;
     423                 :     size_t          fTotalMemoryUsed;
     424                 : #ifdef USE_CACHE_HASH
     425                 :     SkGlyphCache*   fHash[HASH_COUNT];
     426                 : #endif
     427                 : 
     428                 : #ifdef SK_DEBUG
     429                 :     void validate() const;
     430                 : #else
     431                 :     void validate() const {}
     432                 : #endif
     433                 : };
     434                 : 
     435               0 : static SkGlyphCache_Globals& getGlobals() {
     436                 :     // we leak this, so we don't incur any shutdown cost of the destructor
     437               0 :     static SkGlyphCache_Globals* gGlobals = new SkGlyphCache_Globals;
     438               0 :     return *gGlobals;
     439                 : }
     440                 : 
     441               0 : void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*),
     442                 :                                   void* context) {
     443               0 :     SkGlyphCache_Globals& globals = getGlobals();
     444               0 :     SkAutoMutexAcquire    ac(globals.fMutex);
     445                 :     SkGlyphCache*         cache;
     446                 : 
     447               0 :     globals.validate();
     448                 : 
     449               0 :     for (cache = globals.fHead; cache != NULL; cache = cache->fNext) {
     450               0 :         if (proc(cache, context)) {
     451               0 :             break;
     452                 :         }
     453                 :     }
     454                 : 
     455               0 :     globals.validate();
     456               0 : }
     457                 : 
     458                 : /*  This guy calls the visitor from within the mutext lock, so the visitor
     459                 :     cannot:
     460                 :     - take too much time
     461                 :     - try to acquire the mutext again
     462                 :     - call a fontscaler (which might call into the cache)
     463                 : */
     464               0 : SkGlyphCache* SkGlyphCache::VisitCache(const SkDescriptor* desc,
     465                 :                               bool (*proc)(const SkGlyphCache*, void*),
     466                 :                               void* context) {
     467               0 :     SkASSERT(desc);
     468                 : 
     469               0 :     SkGlyphCache_Globals& globals = getGlobals();
     470               0 :     SkAutoMutexAcquire    ac(globals.fMutex);
     471                 :     SkGlyphCache*         cache;
     472               0 :     bool                  insideMutex = true;
     473                 : 
     474               0 :     globals.validate();
     475                 : 
     476                 : #ifdef USE_CACHE_HASH
     477                 :     SkGlyphCache** hash = globals.fHash;
     478                 :     unsigned index = desc_to_hashindex(desc);
     479                 :     cache = hash[index];
     480                 :     if (cache && *cache->fDesc == *desc) {
     481                 :         cache->detach(&globals.fHead);
     482                 :         goto FOUND_IT;
     483                 :     }
     484                 : #endif
     485                 : 
     486               0 :     for (cache = globals.fHead; cache != NULL; cache = cache->fNext) {
     487               0 :         if (cache->fDesc->equals(*desc)) {
     488               0 :             cache->detach(&globals.fHead);
     489               0 :             goto FOUND_IT;
     490                 :         }
     491                 :     }
     492                 : 
     493                 :     /* Release the mutex now, before we create a new entry (which might have
     494                 :         side-effects like trying to access the cache/mutex (yikes!)
     495                 :     */
     496               0 :     ac.release();           // release the mutex now
     497               0 :     insideMutex = false;    // can't use globals anymore
     498                 : 
     499               0 :     cache = SkNEW_ARGS(SkGlyphCache, (desc));
     500                 : 
     501                 : FOUND_IT:
     502                 : 
     503               0 :     AutoValidate av(cache);
     504                 : 
     505               0 :     if (proc(cache, context)) {   // stay detached
     506               0 :         if (insideMutex) {
     507               0 :             SkASSERT(globals.fTotalMemoryUsed >= cache->fMemoryUsed);
     508               0 :             globals.fTotalMemoryUsed -= cache->fMemoryUsed;
     509                 : #ifdef USE_CACHE_HASH
     510                 :             hash[index] = NULL;
     511                 : #endif
     512                 :         }
     513                 :     } else {                        // reattach
     514               0 :         if (insideMutex) {
     515               0 :             cache->attachToHead(&globals.fHead);
     516                 : #ifdef USE_CACHE_HASH
     517                 :             hash[index] = cache;
     518                 : #endif
     519                 :         } else {
     520               0 :             AttachCache(cache);
     521                 :         }
     522               0 :         cache = NULL;
     523                 :     }
     524               0 :     return cache;
     525                 : }
     526                 : 
     527               0 : void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
     528               0 :     SkASSERT(cache);
     529               0 :     SkASSERT(cache->fNext == NULL);
     530                 : 
     531               0 :     SkGlyphCache_Globals& globals = getGlobals();
     532               0 :     SkAutoMutexAcquire    ac(globals.fMutex);
     533                 : 
     534               0 :     globals.validate();
     535               0 :     cache->validate();
     536                 : 
     537                 :     // if we have a fixed budget for our cache, do a purge here
     538                 :     {
     539               0 :         size_t allocated = globals.fTotalMemoryUsed + cache->fMemoryUsed;
     540               0 :         size_t budgeted = SkGraphics::GetFontCacheLimit();
     541               0 :         if (allocated > budgeted) {
     542               0 :             (void)InternalFreeCache(&globals, allocated - budgeted);
     543                 :         }
     544                 :     }
     545                 : 
     546               0 :     cache->attachToHead(&globals.fHead);
     547               0 :     globals.fTotalMemoryUsed += cache->fMemoryUsed;
     548                 : 
     549                 : #ifdef USE_CACHE_HASH
     550                 :     unsigned index = desc_to_hashindex(cache->fDesc);
     551                 :     SkASSERT(globals.fHash[index] != cache);
     552                 :     globals.fHash[index] = cache;
     553                 : #endif
     554                 : 
     555               0 :     globals.validate();
     556               0 : }
     557                 : 
     558               0 : size_t SkGlyphCache::GetCacheUsed() {
     559               0 :     SkGlyphCache_Globals& globals = getGlobals();
     560               0 :     SkAutoMutexAcquire  ac(globals.fMutex);
     561                 : 
     562               0 :     return SkGlyphCache::ComputeMemoryUsed(globals.fHead);
     563                 : }
     564                 : 
     565               0 : bool SkGlyphCache::SetCacheUsed(size_t bytesUsed) {
     566               0 :     size_t curr = SkGlyphCache::GetCacheUsed();
     567                 : 
     568               0 :     if (curr > bytesUsed) {
     569               0 :         SkGlyphCache_Globals& globals = getGlobals();
     570               0 :         SkAutoMutexAcquire  ac(globals.fMutex);
     571                 : 
     572               0 :         return InternalFreeCache(&globals, curr - bytesUsed) > 0;
     573                 :     }
     574               0 :     return false;
     575                 : }
     576                 : 
     577                 : ///////////////////////////////////////////////////////////////////////////////
     578                 : 
     579               0 : SkGlyphCache* SkGlyphCache::FindTail(SkGlyphCache* cache) {
     580               0 :     if (cache) {
     581               0 :         while (cache->fNext) {
     582               0 :             cache = cache->fNext;
     583                 :         }
     584                 :     }
     585               0 :     return cache;
     586                 : }
     587                 : 
     588               0 : size_t SkGlyphCache::ComputeMemoryUsed(const SkGlyphCache* head) {
     589               0 :     size_t size = 0;
     590                 : 
     591               0 :     while (head != NULL) {
     592               0 :         size += head->fMemoryUsed;
     593               0 :         head = head->fNext;
     594                 :     }
     595               0 :     return size;
     596                 : }
     597                 : 
     598                 : #ifdef SK_DEBUG
     599               0 : void SkGlyphCache_Globals::validate() const {
     600               0 :     size_t computed = SkGlyphCache::ComputeMemoryUsed(fHead);
     601               0 :     if (fTotalMemoryUsed != computed) {
     602               0 :         printf("total %d, computed %d\n", (int)fTotalMemoryUsed, (int)computed);
     603                 :     }
     604               0 :     SkASSERT(fTotalMemoryUsed == computed);
     605               0 : }
     606                 : #endif
     607                 : 
     608               0 : size_t SkGlyphCache::InternalFreeCache(SkGlyphCache_Globals* globals,
     609                 :                                        size_t bytesNeeded) {
     610               0 :     globals->validate();
     611                 : 
     612               0 :     size_t  bytesFreed = 0;
     613               0 :     int     count = 0;
     614                 : 
     615                 :     // don't do any "small" purges
     616               0 :     size_t minToPurge = globals->fTotalMemoryUsed >> 2;
     617               0 :     if (bytesNeeded < minToPurge)
     618               0 :         bytesNeeded = minToPurge;
     619                 : 
     620               0 :     SkGlyphCache* cache = FindTail(globals->fHead);
     621               0 :     while (cache != NULL && bytesFreed < bytesNeeded) {
     622               0 :         SkGlyphCache* prev = cache->fPrev;
     623               0 :         bytesFreed += cache->fMemoryUsed;
     624                 : 
     625                 : #ifdef USE_CACHE_HASH
     626                 :         unsigned index = desc_to_hashindex(cache->fDesc);
     627                 :         if (cache == globals->fHash[index]) {
     628                 :             globals->fHash[index] = NULL;
     629                 :         }
     630                 : #endif
     631                 : 
     632               0 :         cache->detach(&globals->fHead);
     633               0 :         SkDELETE(cache);
     634               0 :         cache = prev;
     635               0 :         count += 1;
     636                 :     }
     637                 : 
     638               0 :     SkASSERT(bytesFreed <= globals->fTotalMemoryUsed);
     639               0 :     globals->fTotalMemoryUsed -= bytesFreed;
     640               0 :     globals->validate();
     641                 : 
     642                 : #ifdef SPEW_PURGE_STATUS
     643               0 :     if (count && !gSkSuppressFontCachePurgeSpew) {
     644                 :         SkDebugf("purging %dK from font cache [%d entries]\n",
     645               0 :                  (int)(bytesFreed >> 10), count);
     646                 :     }
     647                 : #endif
     648                 : 
     649               0 :     return bytesFreed;
     650                 : }
     651                 : 
     652                 : ///////////////////////////////////////////////////////////////////////////////
     653                 : #ifdef SK_DEBUG
     654                 : 
     655               0 : void SkGlyphCache::validate() const {
     656               0 :     int count = fGlyphArray.count();
     657               0 :     for (int i = 0; i < count; i++) {
     658               0 :         const SkGlyph* glyph = fGlyphArray[i];
     659               0 :         SkASSERT(glyph);
     660               0 :         SkASSERT(fGlyphAlloc.contains(glyph));
     661               0 :         if (glyph->fImage) {
     662               0 :             SkASSERT(fImageAlloc.contains(glyph->fImage));
     663                 :         }
     664                 :     }
     665               0 : }
     666                 : 
     667                 : #endif

Generated by: LCOV version 1.7