Index: src/core/SkGlyphCache.cpp |
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp |
index f0fd859385e02d1c3dfb3be213b4421af6a4d5d5..3fe8f0ae9e57c69faae0cd2c9c08a58fbca78f0c 100755 |
--- a/src/core/SkGlyphCache.cpp |
+++ b/src/core/SkGlyphCache.cpp |
@@ -66,10 +66,14 @@ SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkSca |
fDesc = desc->copy(); |
fScalerContext->getFontMetrics(&fFontMetrics); |
- |
- // init to 0 so that all of the pointers will be null |
- memset(fGlyphHash, 0, sizeof(fGlyphHash)); |
+ // Create the sentinel SkGlyph. |
+ SkGlyph* sentinel = fGlyphArray.insert(kSentinelGlyphIndex); |
+ sentinel->initGlyphFromCombinedID(kSentinelGlyphID); |
+ |
+ // Initialize all index to zero which points to the sentinel SkGlyph. |
+ memset(fGlyphHash, 0x00, sizeof(fGlyphHash)); |
+ |
fMemoryUsed = sizeof(*this); |
fGlyphArray.setReserve(kMinGlyphCount); |
@@ -106,10 +110,10 @@ SkGlyphCache::~SkGlyphCache() { |
} |
#endif |
- SkGlyph** gptr = fGlyphArray.begin(); |
- SkGlyph** stop = fGlyphArray.end(); |
+ SkGlyph* gptr = fGlyphArray.begin(); |
+ SkGlyph* stop = fGlyphArray.end(); |
while (gptr < stop) { |
- SkPath* path = (*gptr)->fPath; |
+ SkPath* path = gptr->fPath; |
if (path) { |
SkDELETE(path); |
} |
@@ -122,15 +126,31 @@ SkGlyphCache::~SkGlyphCache() { |
SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(uint32_t id) { |
if (NULL == fCharToGlyphHash.get()) { |
+ // Allocate the array. |
fCharToGlyphHash.reset(kHashCount); |
- // init with 0xFF so that the charCode field will be -1, which is invalid |
- memset(fCharToGlyphHash.get(), 0xFF, |
+ // Initialize entries of fCharToGlyphHash to index the sentinel glyph. |
+ memset(fCharToGlyphHash.get(), 0x00, |
sizeof(CharGlyphRec) * kHashCount); |
} |
return &fCharToGlyphHash[ID2HashIndex(id)]; |
} |
+void SkGlyphCache::adjustCaches(int insertion_index) { |
+ for (int i = 0; i < kHashCount; ++i) { |
+ if (fGlyphHash[i] >= SkToU16(insertion_index)) { |
+ fGlyphHash[i] += 1; |
+ } |
+ } |
+ if (fCharToGlyphHash.get() != NULL) { |
+ for (int i = 0; i < kHashCount; ++i) { |
+ if (fCharToGlyphHash[i].fGlyphIndex >= SkToU16(insertion_index)) { |
+ fCharToGlyphHash[i].fGlyphIndex += 1; |
+ } |
+ } |
+ } |
+} |
+ |
/////////////////////////////////////////////////////////////////////////////// |
#ifdef SK_DEBUG |
@@ -145,7 +165,7 @@ uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) { |
const CharGlyphRec& rec = *this->getCharGlyphRec(id); |
if (rec.fID == id) { |
- return rec.fGlyph->getGlyphID(); |
+ return fGlyphArray[rec.fGlyphIndex].getGlyphID(); |
} else { |
return fScalerContext->charToGlyphID(charCode); |
} |
@@ -163,159 +183,119 @@ unsigned SkGlyphCache::getGlyphCount() { |
const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) { |
VALIDATE(); |
- uint32_t id = SkGlyph::MakeID(charCode); |
- CharGlyphRec* rec = this->getCharGlyphRec(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; |
+ return *this->lookupByChar(charCode, kJustAdvance_MetricsType); |
} |
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; |
+ return *this->lookupByCombinedID(id, kJustAdvance_MetricsType); |
} |
/////////////////////////////////////////////////////////////////////////////// |
const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) { |
VALIDATE(); |
- uint32_t id = SkGlyph::MakeID(charCode); |
- CharGlyphRec* rec = this->getCharGlyphRec(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; |
+ return *this->lookupByChar(charCode, kFull_MetricsType); |
} |
const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode, |
SkFixed x, SkFixed y) { |
VALIDATE(); |
+ return *this->lookupByChar(charCode, kFull_MetricsType, x, y); |
+} |
+ |
+const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) { |
+ VALIDATE(); |
+ uint32_t id = SkGlyph::MakeID(glyphID); |
+ return *this->lookupByCombinedID(id, kFull_MetricsType); |
+} |
+ |
+const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFixed y) { |
+ VALIDATE(); |
+ uint32_t id = SkGlyph::MakeID(glyphID, x, y); |
+ return *this->lookupByCombinedID(id, kFull_MetricsType); |
+} |
+ |
+SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, MetricsType type, SkFixed x, SkFixed y) { |
uint32_t id = SkGlyph::MakeID(charCode, x, y); |
CharGlyphRec* rec = this->getCharGlyphRec(id); |
- |
+ SkGlyph* glyph; |
if (rec->fID != id) { |
- RecordHashCollisionIf(rec->fGlyph != NULL); |
+ RecordHashCollisionIf(glyph_index != kSentinelGlyphIndex); |
// 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); |
+ rec->fGlyphIndex = this->lookupMetrics(id, type); |
+ glyph = &fGlyphArray[rec->fGlyphIndex]; |
} 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()) { |
+ glyph = &fGlyphArray[rec->fGlyphIndex]; |
+ if (type == kFull_MetricsType && glyph->isJustAdvance()) { |
fScalerContext->getMetrics(glyph); |
} |
} |
- SkASSERT(glyph->isFullMetrics()); |
- return *glyph; |
+ 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; |
+SkGlyph* SkGlyphCache::lookupByCombinedID(uint32_t id, MetricsType type) { |
+ uint32_t hash_index = ID2HashIndex(id); |
+ uint16_t glyph_index = fGlyphHash[hash_index]; |
+ SkGlyph* glyph = &fGlyphArray[glyph_index]; |
+ |
+ if (glyph->fID != id) { |
+ RecordHashCollisionIf(glyph_index != kSentinelGlyphIndex); |
+ glyph_index = this->lookupMetrics(id, type); |
+ fGlyphHash[hash_index] = glyph_index; |
+ glyph = &fGlyphArray[glyph_index]; |
} else { |
RecordHashSuccess(); |
- if (glyph->isJustAdvance()) { |
- fScalerContext->getMetrics(glyph); |
+ if (type == kFull_MetricsType && glyph->isJustAdvance()) { |
+ fScalerContext->getMetrics(glyph); |
} |
} |
- SkASSERT(glyph->isFullMetrics()); |
- return *glyph; |
+ 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; |
+uint16_t SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) { |
+ // Count is always greater than 0 because of the sentinel. |
+ // The fGlyphArray cache is in descending order, so that the sentinel with a value of ~0 is |
+ // always at index 0. |
+ SkGlyph* gptr = fGlyphArray.begin(); |
+ int lo = 0; |
+ int hi = fGlyphArray.count() - 1; |
+ while (lo < hi) { |
+ int mid = (hi + lo) >> 1; |
+ if (gptr[mid].fID > id) { |
+ lo = mid + 1; |
+ } else { |
+ hi = mid; |
} |
+ } |
- // check if we need to bump hi before falling though to the allocator |
- if (glyph->fID < id) { |
- hi += 1; |
+ uint16_t glyph_index = hi; |
+ SkGlyph* glyph = &gptr[glyph_index]; |
+ if (glyph->fID == id) { |
+ if (kFull_MetricsType == mtype && glyph->isJustAdvance()) { |
+ fScalerContext->getMetrics(glyph); |
} |
+ SkASSERT(glyph_index != kSentinelGlyphIndex); |
+ return glyph_index; |
} |
- // not found, but hi tells us where to inser the new glyph |
+ // check if we need to bump hi before falling though to the allocator |
+ if (glyph->fID > id) { |
+ glyph_index += 1; |
+ } |
+ |
+ // Not found, but hi contains the index of the insertion point of the new glyph. |
fMemoryUsed += sizeof(SkGlyph); |
+ |
+ this->adjustCaches(glyph_index); |
- glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph), |
- SkChunkAlloc::kThrow_AllocFailType); |
- glyph->initCommon(id); |
- *fGlyphArray.insert(hi) = glyph; |
+ glyph = fGlyphArray.insert(glyph_index); |
+ glyph->initGlyphFromCombinedID(id); |
if (kJustAdvance_MetricsType == mtype) { |
fScalerContext->getAdvance(glyph); |
@@ -324,7 +304,8 @@ SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) { |
fScalerContext->getMetrics(glyph); |
} |
- return glyph; |
+ SkASSERT(glyph_index != kSentinelGlyphIndex); |
+ return glyph_index; |
} |
const void* SkGlyphCache::findImage(const SkGlyph& glyph) { |