public:
static const SkFixed kSubpixelRound = SK_FixedHalf >> SkGlyph::kSubBits;
+ // A value that can never be generated by MakeID.
+ static const uint32_t kImpossibleID = ~0;
void* fImage;
SkPath* fPath;
SkFixed fAdvanceX, fAdvanceY;
static uint32_t MakeID(unsigned code) {
SkASSERT(code <= kCodeMask);
+ SkASSERT(code != kImpossibleID);
return code;
}
SkASSERT(code <= kCodeMask);
x = FixedToSub(x);
y = FixedToSub(y);
- return (x << (kSubShift + kSubShiftX)) |
- (y << (kSubShift + kSubShiftY)) |
- code;
+ uint32_t ID = (x << (kSubShift + kSubShiftX)) |
+ (y << (kSubShift + kSubShiftY)) |
+ code;
+ SkASSERT(ID != kImpossibleID);
+ return ID;
}
// FIXME - This is needed because the Android frame work directly
fDesc = desc->copy();
fScalerContext->getFontMetrics(&fFontMetrics);
-
+
// Create the sentinel SkGlyph.
- SkGlyph* sentinel = fGlyphArray.insert(kSentinelGlyphIndex);
- sentinel->initGlyphFromCombinedID(kSentinelGlyphID);
-
+ SkGlyph* sentinel = fGlyphArray.insert(0);
+ sentinel->initGlyphFromCombinedID(SkGlyph::kImpossibleID);
+
// Initialize all index to zero which points to the sentinel SkGlyph.
memset(fGlyphHash, 0x00, sizeof(fGlyphHash));
if (NULL == fCharToGlyphHash.get()) {
// Allocate the array.
fCharToGlyphHash.reset(kHashCount);
- // Initialize entries of fCharToGlyphHash to index the sentinel glyph.
- memset(fCharToGlyphHash.get(), 0x00,
- sizeof(CharGlyphRec) * kHashCount);
+ // Initialize entries of fCharToGlyphHash to index the sentinel glyph and
+ // an fID value that will not match any id.
+ for (int i = 0; i <kHashCount; ++i) {
+ fCharToGlyphHash[i].fID = SkGlyph::kImpossibleID;
+ fCharToGlyphHash[i].fGlyphIndex = 0;
+ }
}
-
+
return &fCharToGlyphHash[ID2HashIndex(id)];
}
CharGlyphRec* rec = this->getCharGlyphRec(id);
SkGlyph* glyph;
if (rec->fID != id) {
- RecordHashCollisionIf(glyph_index != kSentinelGlyphIndex);
+ RecordHashCollisionIf(glyph_index != SkGlyph::kImpossibleID);
// this ID is based on the UniChar
rec->fID = id;
// this ID is based on the glyph index
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);
+ RecordHashCollisionIf(glyph_index != SkGlyph::kImpossibleID);
glyph_index = this->lookupMetrics(id, type);
fGlyphHash[hash_index] = glyph_index;
glyph = &fGlyphArray[glyph_index];
}
uint16_t SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) {
+ SkASSERT(id != SkGlyph::kImpossibleID);
// 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.
if (kFull_MetricsType == mtype && glyph->isJustAdvance()) {
fScalerContext->getMetrics(glyph);
}
- SkASSERT(glyph_index != kSentinelGlyphIndex);
+ SkASSERT(glyph->fID != SkGlyph::kImpossibleID);
return glyph_index;
}
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 = fGlyphArray.insert(glyph_index);
fScalerContext->getMetrics(glyph);
}
- SkASSERT(glyph_index != kSentinelGlyphIndex);
+ SkASSERT(glyph->fID != SkGlyph::kImpossibleID);
return glyph_index;
}
enum {
kHashBits = 8,
kHashCount = 1 << kHashBits,
- kHashMask = kHashCount - 1,
- kSentinelGlyphIndex = 0,
- kSentinelGlyphID = ~0
+ kHashMask = kHashCount - 1
};
-
+
// A quick lookup to avoid the binary search looking for glyphs in fGlyphArray.
uint16_t fGlyphHash[kHashCount];
+ // Contains the SkGlyphs that are used by fGlyphHash and fCharToGlyphHash. The zero element
+ // is reserved for a sentinel SkGlyph that reduces the logic to check for collisions in the
+ // hash arrays. The zero element has an fID of SkGlyph::kImpossibleID which never matches
+ // any combined id generated for a char or a glyph.
SkTDArray<SkGlyph> fGlyphArray;
SkChunkAlloc fGlyphAlloc;