aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/SkGlyphCache.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:36 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:36 -0800
commit6eb364108744656fcd23a96a478aa772cd4e85bc (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /src/core/SkGlyphCache.cpp
parenta23c4e24d873b11674987f97f1946e1c4d97e782 (diff)
downloadexternal_skia-6eb364108744656fcd23a96a478aa772cd4e85bc.zip
external_skia-6eb364108744656fcd23a96a478aa772cd4e85bc.tar.gz
external_skia-6eb364108744656fcd23a96a478aa772cd4e85bc.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'src/core/SkGlyphCache.cpp')
-rw-r--r--src/core/SkGlyphCache.cpp662
1 files changed, 0 insertions, 662 deletions
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp
deleted file mode 100644
index 6b214df..0000000
--- a/src/core/SkGlyphCache.cpp
+++ /dev/null
@@ -1,662 +0,0 @@
-/* libs/graphics/sgl/SkGlyphCache.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include "SkGlyphCache.h"
-#include "SkFontHost.h"
-#include "SkPaint.h"
-#include "SkTemplates.h"
-
-#define SPEW_PURGE_STATUS
-//#define USE_CACHE_HASH
-//#define RECORD_HASH_EFFICIENCY
-
-///////////////////////////////////////////////////////////////////////////////
-
-#ifdef RECORD_HASH_EFFICIENCY
- static uint32_t gHashSuccess;
- static uint32_t gHashCollision;
-
- static void RecordHashSuccess() {
- gHashSuccess += 1;
- }
-
- static void RecordHashCollisionIf(bool pred) {
- if (pred) {
- gHashCollision += 1;
-
- uint32_t total = gHashSuccess + gHashCollision;
- SkDebugf("Font Cache Hash success rate: %d%%\n",
- 100 * gHashSuccess / total);
- }
- }
-#else
- #define RecordHashSuccess() (void)0
- #define RecordHashCollisionIf(pred) (void)0
-#endif
-#define RecordHashCollision() RecordHashCollisionIf(true)
-
-///////////////////////////////////////////////////////////////////////////////
-
-#define kMinGlphAlloc (sizeof(SkGlyph) * 64)
-#define kMinImageAlloc (24 * 64) // should be pointsize-dependent
-
-#define METRICS_RESERVE_COUNT 128 // so we don't grow this array a lot
-
-SkGlyphCache::SkGlyphCache(const SkDescriptor* desc)
- : fGlyphAlloc(kMinGlphAlloc), fImageAlloc(kMinImageAlloc) {
- fPrev = fNext = NULL;
-
- fDesc = desc->copy();
- fScalerContext = SkScalerContext::Create(desc);
- fScalerContext->getFontMetrics(NULL, &fFontMetricsY);
-
- // init to 0 so that all of the pointers will be null
- memset(fGlyphHash, 0, sizeof(fGlyphHash));
- // init with 0xFF so that the charCode field will be -1, which is invalid
- memset(fCharToGlyphHash, 0xFF, sizeof(fCharToGlyphHash));
-
- fMemoryUsed = sizeof(*this) + kMinGlphAlloc + kMinImageAlloc;
-
- fGlyphArray.setReserve(METRICS_RESERVE_COUNT);
-
- fMetricsCount = 0;
- fAdvanceCount = 0;
- fAuxProcList = NULL;
-}
-
-SkGlyphCache::~SkGlyphCache() {
- SkGlyph** gptr = fGlyphArray.begin();
- SkGlyph** stop = fGlyphArray.end();
- while (gptr < stop) {
- SkPath* path = (*gptr)->fPath;
- if (path) {
- SkDELETE(path);
- }
- gptr += 1;
- }
- SkDescriptor::Free(fDesc);
- SkDELETE(fScalerContext);
- this->invokeAndRemoveAuxProcs();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#ifdef SK_DEBUG
-class AutoCheckForNull {
-public:
- AutoCheckForNull(const SkTDArray<SkGlyph*>& array) : fArray(array) {
- for (int i = 0; i < array.count(); i++)
- SkASSERT(array[i]);
- }
- ~AutoCheckForNull() {
- const SkTDArray<SkGlyph*>& array = fArray;
- for (int i = 0; i < array.count(); i++) {
- SkASSERT(array[i]);
- }
- }
-private:
- const SkTDArray<SkGlyph*>& fArray;
-};
-#define VALIDATE() AutoCheckForNull acfn(fGlyphArray)
-#else
-#define VALIDATE()
-#endif
-
-uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) {
- VALIDATE();
- uint32_t id = SkGlyph::MakeID(charCode);
- const CharGlyphRec& rec = fCharToGlyphHash[ID2HashIndex(id)];
-
- if (rec.fID == id) {
- return rec.fGlyph->getGlyphID();
- } else {
- return fScalerContext->charToGlyphID(charCode);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) {
- VALIDATE();
- uint32_t id = SkGlyph::MakeID(charCode);
- CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
-
- if (rec->fID != id) {
- // this ID is based on the UniChar
- rec->fID = id;
- // this ID is based on the glyph index
- id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode));
- rec->fGlyph = this->lookupMetrics(id, kJustAdvance_MetricsType);
- }
- return *rec->fGlyph;
-}
-
-const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) {
- VALIDATE();
- uint32_t id = SkGlyph::MakeID(glyphID);
- unsigned index = ID2HashIndex(id);
- SkGlyph* glyph = fGlyphHash[index];
-
- if (NULL == glyph || glyph->fID != id) {
- glyph = this->lookupMetrics(glyphID, kJustAdvance_MetricsType);
- fGlyphHash[index] = glyph;
- }
- return *glyph;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) {
- VALIDATE();
- uint32_t id = SkGlyph::MakeID(charCode);
- CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
-
- if (rec->fID != id) {
- RecordHashCollisionIf(rec->fGlyph != NULL);
- // this ID is based on the UniChar
- rec->fID = id;
- // this ID is based on the glyph index
- id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode));
- rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType);
- } else {
- RecordHashSuccess();
- if (rec->fGlyph->isJustAdvance()) {
- fScalerContext->getMetrics(rec->fGlyph);
- }
- }
- SkASSERT(rec->fGlyph->isFullMetrics());
- return *rec->fGlyph;
-}
-
-const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode,
- SkFixed x, SkFixed y) {
- VALIDATE();
- uint32_t id = SkGlyph::MakeID(charCode, x, y);
- CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
-
- if (rec->fID != id) {
- RecordHashCollisionIf(rec->fGlyph != NULL);
- // this ID is based on the UniChar
- rec->fID = id;
- // this ID is based on the glyph index
- id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode), x, y);
- rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType);
- } else {
- RecordHashSuccess();
- if (rec->fGlyph->isJustAdvance()) {
- fScalerContext->getMetrics(rec->fGlyph);
- }
- }
- SkASSERT(rec->fGlyph->isFullMetrics());
- return *rec->fGlyph;
-}
-
-const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) {
- VALIDATE();
- uint32_t id = SkGlyph::MakeID(glyphID);
- unsigned index = ID2HashIndex(id);
- SkGlyph* glyph = fGlyphHash[index];
-
- if (NULL == glyph || glyph->fID != id) {
- RecordHashCollisionIf(glyph != NULL);
- glyph = this->lookupMetrics(glyphID, kFull_MetricsType);
- fGlyphHash[index] = glyph;
- } else {
- RecordHashSuccess();
- if (glyph->isJustAdvance()) {
- fScalerContext->getMetrics(glyph);
- }
- }
- SkASSERT(glyph->isFullMetrics());
- return *glyph;
-}
-
-const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID,
- SkFixed x, SkFixed y) {
- VALIDATE();
- uint32_t id = SkGlyph::MakeID(glyphID, x, y);
- unsigned index = ID2HashIndex(id);
- SkGlyph* glyph = fGlyphHash[index];
-
- if (NULL == glyph || glyph->fID != id) {
- RecordHashCollisionIf(glyph != NULL);
- glyph = this->lookupMetrics(id, kFull_MetricsType);
- fGlyphHash[index] = glyph;
- } else {
- RecordHashSuccess();
- if (glyph->isJustAdvance()) {
- fScalerContext->getMetrics(glyph);
- }
- }
- SkASSERT(glyph->isFullMetrics());
- return *glyph;
-}
-
-SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) {
- SkGlyph* glyph;
-
- int hi = 0;
- int count = fGlyphArray.count();
-
- if (count) {
- SkGlyph** gptr = fGlyphArray.begin();
- int lo = 0;
-
- hi = count - 1;
- while (lo < hi) {
- int mid = (hi + lo) >> 1;
- if (gptr[mid]->fID < id) {
- lo = mid + 1;
- } else {
- hi = mid;
- }
- }
- glyph = gptr[hi];
- if (glyph->fID == id) {
- if (kFull_MetricsType == mtype && glyph->isJustAdvance()) {
- fScalerContext->getMetrics(glyph);
- }
- return glyph;
- }
-
- // check if we need to bump hi before falling though to the allocator
- if (glyph->fID < id) {
- hi += 1;
- }
- }
-
- // not found, but hi tells us where to inser the new glyph
- fMemoryUsed += sizeof(SkGlyph);
-
- glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph),
- SkChunkAlloc::kThrow_AllocFailType);
- glyph->fID = id;
- glyph->fImage = NULL;
- glyph->fPath = NULL;
- *fGlyphArray.insert(hi) = glyph;
-
- if (kJustAdvance_MetricsType == mtype) {
- fScalerContext->getAdvance(glyph);
- fAdvanceCount += 1;
- } else {
- SkASSERT(kFull_MetricsType == mtype);
- fScalerContext->getMetrics(glyph);
- fMetricsCount += 1;
- }
-
- return glyph;
-}
-
-const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
- if (glyph.fWidth) {
- if (glyph.fImage == NULL) {
- size_t size = glyph.computeImageSize();
- const_cast<SkGlyph&>(glyph).fImage = fImageAlloc.alloc(size,
- SkChunkAlloc::kReturnNil_AllocFailType);
- fScalerContext->getImage(glyph);
- fMemoryUsed += size;
- }
- }
- return glyph.fImage;
-}
-
-const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) {
- if (glyph.fWidth) {
- if (glyph.fPath == NULL) {
- const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath);
- fScalerContext->getPath(glyph, glyph.fPath);
- fMemoryUsed += sizeof(SkPath) +
- glyph.fPath->getPoints(NULL, 0x7FFFFFFF) * sizeof(SkPoint);
- }
- }
- return glyph.fPath;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const {
- const AuxProcRec* rec = fAuxProcList;
- while (rec) {
- if (rec->fProc == proc) {
- if (dataPtr) {
- *dataPtr = rec->fData;
- }
- return true;
- }
- rec = rec->fNext;
- }
- return false;
-}
-
-void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) {
- if (proc == NULL) {
- return;
- }
-
- AuxProcRec* rec = fAuxProcList;
- while (rec) {
- if (rec->fProc == proc) {
- rec->fData = data;
- return;
- }
- rec = rec->fNext;
- }
- // not found, create a new rec
- rec = SkNEW(AuxProcRec);
- rec->fProc = proc;
- rec->fData = data;
- rec->fNext = fAuxProcList;
- fAuxProcList = rec;
-}
-
-void SkGlyphCache::removeAuxProc(void (*proc)(void*)) {
- AuxProcRec* rec = fAuxProcList;
- AuxProcRec* prev = NULL;
- while (rec) {
- AuxProcRec* next = rec->fNext;
- if (rec->fProc == proc) {
- if (prev) {
- prev->fNext = next;
- } else {
- fAuxProcList = next;
- }
- SkDELETE(rec);
- return;
- }
- prev = rec;
- rec = next;
- }
-}
-
-void SkGlyphCache::invokeAndRemoveAuxProcs() {
- AuxProcRec* rec = fAuxProcList;
- while (rec) {
- rec->fProc(rec->fData);
- AuxProcRec* next = rec->fNext;
- SkDELETE(rec);
- rec = next;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-#include "SkGlobals.h"
-#include "SkThread.h"
-
-#define SkGlyphCache_GlobalsTag SkSetFourByteTag('g', 'l', 'f', 'c')
-
-#ifdef USE_CACHE_HASH
- #define HASH_BITCOUNT 6
- #define HASH_COUNT (1 << HASH_BITCOUNT)
- #define HASH_MASK (HASH_COUNT - 1)
-
- static unsigned desc_to_hashindex(const SkDescriptor* desc)
- {
- SkASSERT(HASH_MASK < 256); // since our munging reduces to 8 bits
-
- uint32_t n = *(const uint32_t*)desc; //desc->getChecksum();
- SkASSERT(n == desc->getChecksum());
-
- // don't trust that the low bits of checksum vary enough, so...
- n ^= (n >> 24) ^ (n >> 16) ^ (n >> 8) ^ (n >> 30);
-
- return n & HASH_MASK;
- }
-#endif
-
-class SkGlyphCache_Globals : public SkGlobals::Rec {
-public:
- SkMutex fMutex;
- SkGlyphCache* fHead;
- size_t fTotalMemoryUsed;
-#ifdef USE_CACHE_HASH
- SkGlyphCache* fHash[HASH_COUNT];
-#endif
-
-#ifdef SK_DEBUG
- void validate() const;
-#else
- void validate() const {}
-#endif
-};
-
-#ifdef SK_USE_RUNTIME_GLOBALS
- static SkGlobals::Rec* create_globals() {
- SkGlyphCache_Globals* rec = SkNEW(SkGlyphCache_Globals);
- rec->fHead = NULL;
- rec->fTotalMemoryUsed = 0;
-#ifdef USE_CACHE_HASH
- memset(rec->fHash, 0, sizeof(rec->fHash));
-#endif
- return rec;
- }
-
- #define FIND_GC_GLOBALS() *(SkGlyphCache_Globals*)SkGlobals::Find(SkGlyphCache_GlobalsTag, create_globals)
- #define GET_GC_GLOBALS() *(SkGlyphCache_Globals*)SkGlobals::Get(SkGlyphCache_GlobalsTag)
-#else
- static SkGlyphCache_Globals gGCGlobals;
- #define FIND_GC_GLOBALS() gGCGlobals
- #define GET_GC_GLOBALS() gGCGlobals
-#endif
-
-void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*),
- void* context) {
- SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
- SkAutoMutexAcquire ac(globals.fMutex);
- SkGlyphCache* cache;
-
- globals.validate();
-
- for (cache = globals.fHead; cache != NULL; cache = cache->fNext) {
- if (proc(cache, context)) {
- break;
- }
- }
-
- globals.validate();
-}
-
-/* This guy calls the visitor from within the mutext lock, so the visitor
- cannot:
- - take too much time
- - try to acquire the mutext again
- - call a fontscaler (which might call into the cache)
-*/
-SkGlyphCache* SkGlyphCache::VisitCache(const SkDescriptor* desc,
- bool (*proc)(const SkGlyphCache*, void*),
- void* context) {
- SkASSERT(desc);
-
- SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
- SkAutoMutexAcquire ac(globals.fMutex);
- SkGlyphCache* cache;
- bool insideMutex = true;
-
- globals.validate();
-
-#ifdef USE_CACHE_HASH
- SkGlyphCache** hash = globals.fHash;
- unsigned index = desc_to_hashindex(desc);
- cache = hash[index];
- if (cache && *cache->fDesc == *desc) {
- cache->detach(&globals.fHead);
- goto FOUND_IT;
- }
-#endif
-
- for (cache = globals.fHead; cache != NULL; cache = cache->fNext) {
- if (cache->fDesc->equals(*desc)) {
- cache->detach(&globals.fHead);
- goto FOUND_IT;
- }
- }
-
- /* Release the mutex now, before we create a new entry (which might have
- side-effects like trying to access the cache/mutex (yikes!)
- */
- ac.release(); // release the mutex now
- insideMutex = false; // can't use globals anymore
-
- cache = SkNEW_ARGS(SkGlyphCache, (desc));
-
-FOUND_IT:
- if (proc(cache, context)) { // stay detached
- if (insideMutex) {
- SkASSERT(globals.fTotalMemoryUsed >= cache->fMemoryUsed);
- globals.fTotalMemoryUsed -= cache->fMemoryUsed;
-#ifdef USE_CACHE_HASH
- hash[index] = NULL;
-#endif
- }
- } else { // reattach
- if (insideMutex) {
- cache->attachToHead(&globals.fHead);
-#ifdef USE_CACHE_HASH
- hash[index] = cache;
-#endif
- } else {
- AttachCache(cache);
- }
- cache = NULL;
- }
- return cache;
-}
-
-void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
- SkASSERT(cache);
- SkASSERT(cache->fNext == NULL);
-
- SkGlyphCache_Globals& globals = GET_GC_GLOBALS();
- SkAutoMutexAcquire ac(globals.fMutex);
-
- globals.validate();
-
- // if we have a fixed budget for our cache, do a purge here
- {
- size_t allocated = globals.fTotalMemoryUsed + cache->fMemoryUsed;
- size_t amountToFree = SkFontHost::ShouldPurgeFontCache(allocated);
- if (amountToFree)
- (void)InternalFreeCache(&globals, amountToFree);
- }
-
- cache->attachToHead(&globals.fHead);
- globals.fTotalMemoryUsed += cache->fMemoryUsed;
-
-#ifdef USE_CACHE_HASH
- unsigned index = desc_to_hashindex(cache->fDesc);
- SkASSERT(globals.fHash[index] != cache);
- globals.fHash[index] = cache;
-#endif
-
- globals.validate();
-}
-
-size_t SkGlyphCache::GetCacheUsed() {
- SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
- SkAutoMutexAcquire ac(globals.fMutex);
-
- return SkGlyphCache::ComputeMemoryUsed(globals.fHead);
-}
-
-bool SkGlyphCache::SetCacheUsed(size_t bytesUsed) {
- size_t curr = SkGlyphCache::GetCacheUsed();
-
- if (curr > bytesUsed) {
- SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
- SkAutoMutexAcquire ac(globals.fMutex);
-
- return InternalFreeCache(&globals, curr - bytesUsed) > 0;
- }
- return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-SkGlyphCache* SkGlyphCache::FindTail(SkGlyphCache* cache) {
- if (cache) {
- while (cache->fNext) {
- cache = cache->fNext;
- }
- }
- return cache;
-}
-
-size_t SkGlyphCache::ComputeMemoryUsed(const SkGlyphCache* head) {
- size_t size = 0;
-
- while (head != NULL) {
- size += head->fMemoryUsed;
- head = head->fNext;
- }
- return size;
-}
-
-#ifdef SK_DEBUG
-void SkGlyphCache_Globals::validate() const {
- size_t computed = SkGlyphCache::ComputeMemoryUsed(fHead);
- if (fTotalMemoryUsed != computed) {
- printf("total %d, computed %d\n", (int)fTotalMemoryUsed, (int)computed);
- }
- SkASSERT(fTotalMemoryUsed == computed);
-}
-#endif
-
-size_t SkGlyphCache::InternalFreeCache(SkGlyphCache_Globals* globals,
- size_t bytesNeeded) {
- globals->validate();
-
- size_t bytesFreed = 0;
- int count = 0;
-
- // don't do any "small" purges
- size_t minToPurge = globals->fTotalMemoryUsed >> 2;
- if (bytesNeeded < minToPurge)
- bytesNeeded = minToPurge;
-
- SkGlyphCache* cache = FindTail(globals->fHead);
- while (cache != NULL && bytesFreed < bytesNeeded) {
- SkGlyphCache* prev = cache->fPrev;
- bytesFreed += cache->fMemoryUsed;
-
-#ifdef USE_CACHE_HASH
- unsigned index = desc_to_hashindex(cache->fDesc);
- if (cache == globals->fHash[index]) {
- globals->fHash[index] = NULL;
- }
-#endif
-
- cache->detach(&globals->fHead);
- SkDELETE(cache);
- cache = prev;
- count += 1;
- }
-
- SkASSERT(bytesFreed <= globals->fTotalMemoryUsed);
- globals->fTotalMemoryUsed -= bytesFreed;
- globals->validate();
-
-#ifdef SPEW_PURGE_STATUS
- if (count) {
- SkDebugf("purging %dK from font cache [%d entries]\n",
- (int)(bytesFreed >> 10), count);
- }
-#endif
-
- return bytesFreed;
-}
-