|  | /* | 
|  | * Copyright 2006 The Android Open Source Project | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #ifndef SkGlyphCache_DEFINED | 
|  | #define SkGlyphCache_DEFINED | 
|  |  | 
|  | #include "SkBitmap.h" | 
|  | #include "SkChunkAlloc.h" | 
|  | #include "SkDescriptor.h" | 
|  | #include "SkGlyph.h" | 
|  | #include "SkTHash.h" | 
|  | #include "SkScalerContext.h" | 
|  | #include "SkTemplates.h" | 
|  | #include "SkTDArray.h" | 
|  |  | 
|  | class SkPaint; | 
|  | class SkTraceMemoryDump; | 
|  |  | 
|  | class SkGlyphCache_Globals; | 
|  |  | 
|  | /** \class SkGlyphCache | 
|  |  | 
|  | This class represents a strike: a specific combination of typeface, size, matrix, etc., and | 
|  | holds the glyphs for that strike. Calling any of the getUnichar.../getGlyphID... methods will | 
|  | return the requested glyph, either instantly if it is already cached, or by first generating | 
|  | it and then adding it to the strike. | 
|  |  | 
|  | The strikes are held in a global list, available to all threads. To interact with one, call | 
|  | either VisitCache() or DetachCache(). | 
|  | */ | 
|  | class SkGlyphCache { | 
|  | public: | 
|  | /** Returns a glyph with valid fAdvance and fDevKern fields. The remaining fields may be | 
|  | valid, but that is not guaranteed. If you require those, call getUnicharMetrics or | 
|  | getGlyphIDMetrics instead. | 
|  | */ | 
|  | const SkGlyph& getUnicharAdvance(SkUnichar); | 
|  | const SkGlyph& getGlyphIDAdvance(uint16_t); | 
|  |  | 
|  | /** Returns a glyph with all fields valid except fImage and fPath, which may be null. If they | 
|  | are null, call findImage or findPath for those. If they are not null, then they are valid. | 
|  |  | 
|  | This call is potentially slower than the matching ...Advance call. If you only need the | 
|  | fAdvance/fDevKern fields, call those instead. | 
|  | */ | 
|  | const SkGlyph& getUnicharMetrics(SkUnichar); | 
|  | const SkGlyph& getGlyphIDMetrics(uint16_t); | 
|  |  | 
|  | /** These are variants that take the device position of the glyph. Call these only if you are | 
|  | drawing in subpixel mode. Passing 0, 0 is effectively the same as calling the variants | 
|  | w/o the extra params, though a tiny bit slower. | 
|  | */ | 
|  | const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); | 
|  | const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); | 
|  |  | 
|  | /** Return the glyphID for the specified Unichar. If the char has already been seen, use the | 
|  | existing cache entry. If not, ask the scalercontext to compute it for us. | 
|  | */ | 
|  | uint16_t unicharToGlyph(SkUnichar); | 
|  |  | 
|  | /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to a character code of zero. | 
|  | */ | 
|  | SkUnichar glyphToUnichar(uint16_t); | 
|  |  | 
|  | /** Returns the number of glyphs for this strike. | 
|  | */ | 
|  | unsigned getGlyphCount() const; | 
|  |  | 
|  | /** Return the number of glyphs currently cached. */ | 
|  | int countCachedGlyphs() const; | 
|  |  | 
|  | /** Return the image associated with the glyph. If it has not been generated this will | 
|  | trigger that. | 
|  | */ | 
|  | const void* findImage(const SkGlyph&); | 
|  |  | 
|  | /** Return the Path associated with the glyph. If it has not been generated this will trigger | 
|  | that. | 
|  | */ | 
|  | const SkPath* findPath(const SkGlyph&); | 
|  |  | 
|  | /** Return the vertical metrics for this strike. | 
|  | */ | 
|  | const SkPaint::FontMetrics& getFontMetrics() const { | 
|  | return fFontMetrics; | 
|  | } | 
|  |  | 
|  | const SkDescriptor& getDescriptor() const { return *fDesc; } | 
|  |  | 
|  | SkMask::Format getMaskFormat() const { | 
|  | return fScalerContext->getMaskFormat(); | 
|  | } | 
|  |  | 
|  | bool isSubpixel() const { | 
|  | return fScalerContext->isSubpixel(); | 
|  | } | 
|  |  | 
|  | /** Return the approx RAM usage for this cache. */ | 
|  | size_t getMemoryUsed() const { return fMemoryUsed; } | 
|  |  | 
|  | void dump() const; | 
|  |  | 
|  | /** AuxProc/Data allow a client to associate data with this cache entry. Multiple clients can | 
|  | use this, as their data is keyed with a function pointer. In addition to serving as a | 
|  | key, the function pointer is called with the data when the glyphcache object is deleted, | 
|  | so the client can cleanup their data as well. | 
|  | NOTE: the auxProc must not try to access this glyphcache in any way, since it may be in | 
|  | the process of being deleted. | 
|  | */ | 
|  |  | 
|  | //! If the proc is found, return true and set *dataPtr to its data | 
|  | bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; | 
|  |  | 
|  | //! Add a proc/data pair to the glyphcache. proc should be non-null | 
|  | void setAuxProc(void (*auxProc)(void*), void* auxData); | 
|  |  | 
|  | SkScalerContext* getScalerContext() const { return fScalerContext; } | 
|  |  | 
|  | /** Find a matching cache entry, and call proc() with it. If none is found create a new one. | 
|  | If the proc() returns true, detach the cache and return it, otherwise leave it and return | 
|  | nullptr. | 
|  | */ | 
|  | static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, | 
|  | bool (*proc)(const SkGlyphCache*, void*), | 
|  | void* context); | 
|  |  | 
|  | /** Given a strike that was returned by either VisitCache() or DetachCache() add it back into | 
|  | the global cache list (after which the caller should not reference it anymore. | 
|  | */ | 
|  | static void AttachCache(SkGlyphCache*); | 
|  |  | 
|  | /** Detach a strike from the global cache matching the specified descriptor. Once detached, | 
|  | it can be queried/modified by the current thread, and when finished, be reattached to the | 
|  | global cache with AttachCache(). While detached, if another request is made with the same | 
|  | descriptor, a different strike will be generated. This is fine. It does mean we can have | 
|  | more than 1 strike for the same descriptor, but that will eventually get purged, and the | 
|  | win is that different thread will never block each other while a strike is being used. | 
|  | */ | 
|  | static SkGlyphCache* DetachCache(SkTypeface* typeface, const SkDescriptor* desc) { | 
|  | return VisitCache(typeface, desc, DetachProc, nullptr); | 
|  | } | 
|  |  | 
|  | static void Dump(); | 
|  |  | 
|  | /** Dump memory usage statistics of all the attaches caches in the process using the | 
|  | SkTraceMemoryDump interface. | 
|  | */ | 
|  | static void DumpMemoryStatistics(SkTraceMemoryDump* dump); | 
|  |  | 
|  | typedef void (*Visitor)(const SkGlyphCache&, void* context); | 
|  | static void VisitAll(Visitor, void* context); | 
|  |  | 
|  | #ifdef SK_DEBUG | 
|  | void validate() const; | 
|  | #else | 
|  | void validate() const {} | 
|  | #endif | 
|  |  | 
|  | class AutoValidate : SkNoncopyable { | 
|  | public: | 
|  | AutoValidate(const SkGlyphCache* cache) : fCache(cache) { | 
|  | if (fCache) { | 
|  | fCache->validate(); | 
|  | } | 
|  | } | 
|  | ~AutoValidate() { | 
|  | if (fCache) { | 
|  | fCache->validate(); | 
|  | } | 
|  | } | 
|  | void forget() { | 
|  | fCache = nullptr; | 
|  | } | 
|  | private: | 
|  | const SkGlyphCache* fCache; | 
|  | }; | 
|  |  | 
|  | private: | 
|  | friend class SkGlyphCache_Globals; | 
|  |  | 
|  | enum { | 
|  | kHashBits           = 8, | 
|  | kHashCount          = 1 << kHashBits, | 
|  | kHashMask           = kHashCount - 1 | 
|  | }; | 
|  |  | 
|  | typedef uint32_t PackedGlyphID;    // glyph-index + subpixel-pos | 
|  | typedef uint32_t PackedUnicharID;  // unichar + subpixel-pos | 
|  |  | 
|  | struct CharGlyphRec { | 
|  | PackedUnicharID    fPackedUnicharID; | 
|  | PackedGlyphID      fPackedGlyphID; | 
|  | }; | 
|  |  | 
|  | struct AuxProcRec { | 
|  | AuxProcRec* fNext; | 
|  | void (*fProc)(void*); | 
|  | void* fData; | 
|  | }; | 
|  |  | 
|  | // SkGlyphCache takes ownership of the scalercontext. | 
|  | SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); | 
|  | ~SkGlyphCache(); | 
|  |  | 
|  | // Return the SkGlyph* associated with MakeID. The id parameter is the | 
|  | // combined glyph/x/y id generated by MakeID. If it is just a glyph id | 
|  | // then x and y are assumed to be zero. | 
|  | SkGlyph* lookupByPackedGlyphID(PackedGlyphID packedGlyphID); | 
|  |  | 
|  | // Return a SkGlyph* associated with unicode id and position x and y. | 
|  | SkGlyph* lookupByChar(SkUnichar id, SkFixed x = 0, SkFixed y = 0); | 
|  |  | 
|  | // Return a new SkGlyph for the glyph ID and subpixel position id. | 
|  | SkGlyph* allocateNewGlyph(PackedGlyphID packedGlyphID); | 
|  |  | 
|  | static bool DetachProc(const SkGlyphCache*, void*) { return true; } | 
|  |  | 
|  | // The id arg is a combined id generated by MakeID. | 
|  | CharGlyphRec* getCharGlyphRec(PackedUnicharID id); | 
|  |  | 
|  | void invokeAndRemoveAuxProcs(); | 
|  |  | 
|  | inline static SkGlyphCache* FindTail(SkGlyphCache* head); | 
|  |  | 
|  | SkGlyphCache*          fNext; | 
|  | SkGlyphCache*          fPrev; | 
|  | SkDescriptor* const    fDesc; | 
|  | SkScalerContext* const fScalerContext; | 
|  | SkPaint::FontMetrics   fFontMetrics; | 
|  |  | 
|  | // Map from a combined GlyphID and sub-pixel position to a SkGlyph. | 
|  | SkTHashTable<SkGlyph, PackedGlyphID, SkGlyph::HashTraits> fGlyphMap; | 
|  |  | 
|  | SkChunkAlloc           fGlyphAlloc; | 
|  |  | 
|  | SkAutoTArray<CharGlyphRec> fPackedUnicharIDToPackedGlyphID; | 
|  |  | 
|  | // used to track (approx) how much ram is tied-up in this cache | 
|  | size_t                 fMemoryUsed; | 
|  |  | 
|  | AuxProcRec*            fAuxProcList; | 
|  | }; | 
|  |  | 
|  | class SkAutoGlyphCacheBase { | 
|  | public: | 
|  | SkGlyphCache* getCache() const { return fCache; } | 
|  |  | 
|  | void release() { | 
|  | if (fCache) { | 
|  | SkGlyphCache::AttachCache(fCache); | 
|  | fCache = nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | protected: | 
|  | // Hide the constructors so we can't create one of these directly. Create SkAutoGlyphCache or | 
|  | // SkAutoGlyphCacheNoCache instead. | 
|  | SkAutoGlyphCacheBase(SkGlyphCache* cache) : fCache(cache) {} | 
|  | SkAutoGlyphCacheBase(SkTypeface* typeface, const SkDescriptor* desc) { | 
|  | fCache = SkGlyphCache::DetachCache(typeface, desc); | 
|  | } | 
|  | SkAutoGlyphCacheBase(const SkPaint& /*paint*/, | 
|  | const SkSurfaceProps* /*surfaceProps*/, | 
|  | const SkMatrix* /*matrix*/) { | 
|  | fCache = nullptr; | 
|  | } | 
|  | SkAutoGlyphCacheBase() { | 
|  | fCache = nullptr; | 
|  | } | 
|  | ~SkAutoGlyphCacheBase() { | 
|  | if (fCache) { | 
|  | SkGlyphCache::AttachCache(fCache); | 
|  | } | 
|  | } | 
|  |  | 
|  | SkGlyphCache*   fCache; | 
|  |  | 
|  | private: | 
|  | static bool DetachProc(const SkGlyphCache*, void*); | 
|  | }; | 
|  |  | 
|  | class SkAutoGlyphCache : public SkAutoGlyphCacheBase { | 
|  | public: | 
|  | SkAutoGlyphCache(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {} | 
|  | SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) : | 
|  | SkAutoGlyphCacheBase(typeface, desc) {} | 
|  | SkAutoGlyphCache(const SkPaint& paint, | 
|  | const SkSurfaceProps* surfaceProps, | 
|  | const SkMatrix* matrix) { | 
|  | fCache = paint.detachCache(surfaceProps, matrix, false); | 
|  | } | 
|  |  | 
|  | private: | 
|  | SkAutoGlyphCache() : SkAutoGlyphCacheBase() {} | 
|  | }; | 
|  | #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) | 
|  |  | 
|  | class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCacheBase { | 
|  | public: | 
|  | SkAutoGlyphCacheNoGamma(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {} | 
|  | SkAutoGlyphCacheNoGamma(SkTypeface* typeface, const SkDescriptor* desc) : | 
|  | SkAutoGlyphCacheBase(typeface, desc) {} | 
|  | SkAutoGlyphCacheNoGamma(const SkPaint& paint, | 
|  | const SkSurfaceProps* surfaceProps, | 
|  | const SkMatrix* matrix) { | 
|  | fCache = paint.detachCache(surfaceProps, matrix, true); | 
|  | } | 
|  |  | 
|  | private: | 
|  | SkAutoGlyphCacheNoGamma() : SkAutoGlyphCacheBase() {} | 
|  | }; | 
|  | #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma) | 
|  |  | 
|  | #endif |