| |
| /* |
| * Copyright 2010 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| |
| |
| #ifndef GrTextStrike_DEFINED |
| #define GrTextStrike_DEFINED |
| |
| #include "GrAtlas.h" |
| #include "GrDrawTarget.h" |
| #include "GrFontScaler.h" |
| #include "GrGlyph.h" |
| #include "SkTDynamicHash.h" |
| #include "SkVarAlloc.h" |
| |
| class GrFontCache; |
| class GrGpu; |
| class GrFontPurgeListener; |
| |
| /** |
| * The textstrike maps a hostfontscaler instance to a dictionary of |
| * glyphid->strike |
| */ |
| class GrTextStrike { |
| public: |
| GrTextStrike(GrFontCache*, const GrFontDescKey* fontScalerKey); |
| ~GrTextStrike(); |
| |
| const GrFontDescKey* getFontScalerKey() const { return fFontScalerKey; } |
| GrFontCache* getFontCache() const { return fFontCache; } |
| |
| inline GrGlyph* getGlyph(GrGlyph::PackedID packed, GrFontScaler* scaler) { |
| GrGlyph* glyph = fCache.find(packed); |
| if (NULL == glyph) { |
| glyph = this->generateGlyph(packed, scaler); |
| } |
| return glyph; |
| } |
| |
| // returns true if glyph (or glyph+padding for distance field) |
| // is too large to ever fit in texture atlas subregions (GrPlots) |
| bool glyphTooLargeForAtlas(GrGlyph*); |
| // returns true if glyph successfully added to texture atlas, false otherwise |
| bool addGlyphToAtlas(GrGlyph*, GrFontScaler*); |
| |
| // testing |
| int countGlyphs() const { return fCache.count(); } |
| |
| // remove any references to this plot |
| void removePlot(const GrPlot* plot); |
| |
| static const GrFontDescKey& GetKey(const GrTextStrike& ts) { |
| return *(ts.fFontScalerKey); |
| } |
| static uint32_t Hash(const GrFontDescKey& key) { |
| return key.getHash(); |
| } |
| |
| public: |
| // for easy removal from list |
| GrTextStrike* fPrev; |
| GrTextStrike* fNext; |
| |
| private: |
| SkTDynamicHash<GrGlyph, GrGlyph::PackedID> fCache; |
| const GrFontDescKey* fFontScalerKey; |
| SkVarAlloc fPool; |
| |
| GrFontCache* fFontCache; |
| bool fUseDistanceField; |
| |
| GrAtlas::ClientPlotUsage fPlotUsage; |
| |
| GrGlyph* generateGlyph(GrGlyph::PackedID packed, GrFontScaler* scaler); |
| |
| friend class GrFontCache; |
| }; |
| |
| class GrFontCache { |
| public: |
| GrFontCache(GrGpu*); |
| ~GrFontCache(); |
| |
| inline GrTextStrike* getStrike(GrFontScaler* scaler, bool useDistanceField) { |
| this->validate(); |
| |
| GrTextStrike* strike = fCache.find(*(scaler->getKey())); |
| if (NULL == strike) { |
| strike = this->generateStrike(scaler); |
| } else if (strike->fPrev) { |
| // Need to put the strike at the head of its dllist, since that is how |
| // we age the strikes for purging (we purge from the back of the list) |
| this->detachStrikeFromList(strike); |
| // attach at the head |
| fHead->fPrev = strike; |
| strike->fNext = fHead; |
| strike->fPrev = NULL; |
| fHead = strike; |
| } |
| strike->fUseDistanceField = useDistanceField; |
| this->validate(); |
| return strike; |
| } |
| |
| // add to texture atlas that matches this format |
| GrPlot* addToAtlas(GrMaskFormat format, GrAtlas::ClientPlotUsage* usage, |
| int width, int height, const void* image, |
| SkIPoint16* loc); |
| |
| void freeAll(); |
| |
| // make an unused plot available for this glyph |
| bool freeUnusedPlot(GrTextStrike* preserveStrike, const GrGlyph* glyph); |
| |
| // testing |
| int countStrikes() const { return fCache.count(); } |
| GrTextStrike* getHeadStrike() const { return fHead; } |
| |
| void updateTextures() { |
| for (int i = 0; i < kAtlasCount; ++i) { |
| if (fAtlases[i]) { |
| fAtlases[i]->uploadPlotsToTexture(); |
| } |
| } |
| } |
| |
| #ifdef SK_DEBUG |
| void validate() const; |
| #else |
| void validate() const {} |
| #endif |
| |
| void dump() const; |
| |
| enum AtlasType { |
| kA8_AtlasType, //!< 1-byte per pixel |
| k565_AtlasType, //!< 2-bytes per pixel |
| k8888_AtlasType, //!< 4-bytes per pixel |
| |
| kLast_AtlasType = k8888_AtlasType |
| }; |
| static const int kAtlasCount = kLast_AtlasType + 1; |
| |
| private: |
| friend class GrFontPurgeListener; |
| |
| SkTDynamicHash<GrTextStrike, GrFontDescKey> fCache; |
| // for LRU |
| GrTextStrike* fHead; |
| GrTextStrike* fTail; |
| |
| GrGpu* fGpu; |
| GrAtlas* fAtlases[kAtlasCount]; |
| |
| GrTextStrike* generateStrike(GrFontScaler*); |
| |
| inline void detachStrikeFromList(GrTextStrike* strike) { |
| if (strike->fPrev) { |
| SkASSERT(fHead != strike); |
| strike->fPrev->fNext = strike->fNext; |
| } else { |
| SkASSERT(fHead == strike); |
| fHead = strike->fNext; |
| } |
| |
| if (strike->fNext) { |
| SkASSERT(fTail != strike); |
| strike->fNext->fPrev = strike->fPrev; |
| } else { |
| SkASSERT(fTail == strike); |
| fTail = strike->fPrev; |
| } |
| } |
| |
| void purgeStrike(GrTextStrike* strike); |
| }; |
| |
| #endif |