michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkGlyphCache_DEFINED michael@0: #define SkGlyphCache_DEFINED michael@0: michael@0: #include "SkBitmap.h" michael@0: #include "SkChunkAlloc.h" michael@0: #include "SkDescriptor.h" michael@0: #include "SkGlyph.h" michael@0: #include "SkScalerContext.h" michael@0: #include "SkTemplates.h" michael@0: #include "SkTDArray.h" michael@0: michael@0: struct SkDeviceProperties; michael@0: class SkPaint; michael@0: michael@0: class SkGlyphCache_Globals; michael@0: michael@0: /** \class SkGlyphCache michael@0: michael@0: This class represents a strike: a specific combination of typeface, size, michael@0: matrix, etc., and holds the glyphs for that strike. Calling any of the michael@0: getUnichar.../getGlyphID... methods will return the requested glyph, michael@0: either instantly if it is already cahced, or by first generating it and then michael@0: adding it to the strike. michael@0: michael@0: The strikes are held in a global list, available to all threads. To interact michael@0: with one, call either VisitCache() or DetachCache(). michael@0: */ michael@0: class SkGlyphCache { michael@0: public: michael@0: /** Returns a glyph with valid fAdvance and fDevKern fields. michael@0: The remaining fields may be valid, but that is not guaranteed. If you michael@0: require those, call getUnicharMetrics or getGlyphIDMetrics instead. michael@0: */ michael@0: const SkGlyph& getUnicharAdvance(SkUnichar); michael@0: const SkGlyph& getGlyphIDAdvance(uint16_t); michael@0: michael@0: /** Returns a glyph with all fields valid except fImage and fPath, which michael@0: may be null. If they are null, call findImage or findPath for those. michael@0: If they are not null, then they are valid. michael@0: michael@0: This call is potentially slower than the matching ...Advance call. If michael@0: you only need the fAdvance/fDevKern fields, call those instead. michael@0: */ michael@0: const SkGlyph& getUnicharMetrics(SkUnichar); michael@0: const SkGlyph& getGlyphIDMetrics(uint16_t); michael@0: michael@0: /** These are variants that take the device position of the glyph. Call michael@0: these only if you are drawing in subpixel mode. Passing 0, 0 is michael@0: effectively the same as calling the variants w/o the extra params, tho michael@0: a tiny bit slower. michael@0: */ michael@0: const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); michael@0: const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); michael@0: michael@0: /** Return the glyphID for the specified Unichar. If the char has already michael@0: been seen, use the existing cache entry. If not, ask the scalercontext michael@0: to compute it for us. michael@0: */ michael@0: uint16_t unicharToGlyph(SkUnichar); michael@0: michael@0: /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to michael@0: a character code of zero. michael@0: */ michael@0: SkUnichar glyphToUnichar(uint16_t); michael@0: michael@0: /** Returns the number of glyphs for this strike. michael@0: */ michael@0: unsigned getGlyphCount(); michael@0: michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: /** Returns the base glyph count for this strike. michael@0: */ michael@0: unsigned getBaseGlyphCount(SkUnichar charCode) const { michael@0: return fScalerContext->getBaseGlyphCount(charCode); michael@0: } michael@0: #endif michael@0: michael@0: /** Return the image associated with the glyph. If it has not been generated michael@0: this will trigger that. michael@0: */ michael@0: const void* findImage(const SkGlyph&); michael@0: /** Return the Path associated with the glyph. If it has not been generated michael@0: this will trigger that. michael@0: */ michael@0: const SkPath* findPath(const SkGlyph&); michael@0: michael@0: /** Return the vertical metrics for this strike. michael@0: */ michael@0: const SkPaint::FontMetrics& getFontMetrics() const { michael@0: return fFontMetrics; michael@0: } michael@0: michael@0: const SkDescriptor& getDescriptor() const { return *fDesc; } michael@0: michael@0: SkMask::Format getMaskFormat() const { michael@0: return fScalerContext->getMaskFormat(); michael@0: } michael@0: michael@0: bool isSubpixel() const { michael@0: return fScalerContext->isSubpixel(); michael@0: } michael@0: michael@0: /* AuxProc/Data allow a client to associate data with this cache entry. michael@0: Multiple clients can use this, as their data is keyed with a function michael@0: pointer. In addition to serving as a key, the function pointer is called michael@0: with the data when the glyphcache object is deleted, so the client can michael@0: cleanup their data as well. NOTE: the auxProc must not try to access michael@0: this glyphcache in any way, since it may be in the process of being michael@0: deleted. michael@0: */ michael@0: michael@0: //! If the proc is found, return true and set *dataPtr to its data michael@0: bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; michael@0: //! Add a proc/data pair to the glyphcache. proc should be non-null michael@0: void setAuxProc(void (*auxProc)(void*), void* auxData); michael@0: michael@0: SkScalerContext* getScalerContext() const { return fScalerContext; } michael@0: michael@0: /** Call proc on all cache entries, stopping early if proc returns true. michael@0: The proc should not create or delete caches, since it could produce michael@0: deadlock. michael@0: */ michael@0: static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx); michael@0: michael@0: /** Find a matching cache entry, and call proc() with it. If none is found michael@0: create a new one. If the proc() returns true, detach the cache and michael@0: return it, otherwise leave it and return NULL. michael@0: */ michael@0: static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, michael@0: bool (*proc)(const SkGlyphCache*, void*), michael@0: void* context); michael@0: michael@0: /** Given a strike that was returned by either VisitCache() or DetachCache() michael@0: add it back into the global cache list (after which the caller should michael@0: not reference it anymore. michael@0: */ michael@0: static void AttachCache(SkGlyphCache*); michael@0: michael@0: /** Detach a strike from the global cache matching the specified descriptor. michael@0: Once detached, it can be queried/modified by the current thread, and michael@0: when finished, be reattached to the global cache with AttachCache(). michael@0: While detached, if another request is made with the same descriptor, michael@0: a different strike will be generated. This is fine. It does mean we michael@0: can have more than 1 strike for the same descriptor, but that will michael@0: eventually get purged, and the win is that different thread will never michael@0: block each other while a strike is being used. michael@0: */ michael@0: static SkGlyphCache* DetachCache(SkTypeface* typeface, michael@0: const SkDescriptor* desc) { michael@0: return VisitCache(typeface, desc, DetachProc, NULL); michael@0: } michael@0: michael@0: #ifdef SK_DEBUG michael@0: void validate() const; michael@0: #else michael@0: void validate() const {} michael@0: #endif michael@0: michael@0: class AutoValidate : SkNoncopyable { michael@0: public: michael@0: AutoValidate(const SkGlyphCache* cache) : fCache(cache) { michael@0: if (fCache) { michael@0: fCache->validate(); michael@0: } michael@0: } michael@0: ~AutoValidate() { michael@0: if (fCache) { michael@0: fCache->validate(); michael@0: } michael@0: } michael@0: void forget() { michael@0: fCache = NULL; michael@0: } michael@0: private: michael@0: const SkGlyphCache* fCache; michael@0: }; michael@0: michael@0: private: michael@0: // we take ownership of the scalercontext michael@0: SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); michael@0: ~SkGlyphCache(); michael@0: michael@0: enum MetricsType { michael@0: kJustAdvance_MetricsType, michael@0: kFull_MetricsType michael@0: }; michael@0: michael@0: SkGlyph* lookupMetrics(uint32_t id, MetricsType); michael@0: static bool DetachProc(const SkGlyphCache*, void*) { return true; } michael@0: michael@0: SkGlyphCache* fNext, *fPrev; michael@0: SkDescriptor* fDesc; michael@0: SkScalerContext* fScalerContext; michael@0: SkPaint::FontMetrics fFontMetrics; michael@0: michael@0: enum { michael@0: kHashBits = 8, michael@0: kHashCount = 1 << kHashBits, michael@0: kHashMask = kHashCount - 1 michael@0: }; michael@0: SkGlyph* fGlyphHash[kHashCount]; michael@0: SkTDArray fGlyphArray; michael@0: SkChunkAlloc fGlyphAlloc; michael@0: michael@0: struct CharGlyphRec { michael@0: uint32_t fID; // unichar + subpixel michael@0: SkGlyph* fGlyph; michael@0: }; michael@0: // no reason to use the same kHashCount as fGlyphHash, but we do for now michael@0: CharGlyphRec fCharToGlyphHash[kHashCount]; michael@0: michael@0: static inline unsigned ID2HashIndex(uint32_t id) { michael@0: id ^= id >> 16; michael@0: id ^= id >> 8; michael@0: return id & kHashMask; michael@0: } michael@0: michael@0: // used to track (approx) how much ram is tied-up in this cache michael@0: size_t fMemoryUsed; michael@0: michael@0: struct AuxProcRec { michael@0: AuxProcRec* fNext; michael@0: void (*fProc)(void*); michael@0: void* fData; michael@0: }; michael@0: AuxProcRec* fAuxProcList; michael@0: void invokeAndRemoveAuxProcs(); michael@0: michael@0: inline static SkGlyphCache* FindTail(SkGlyphCache* head); michael@0: michael@0: friend class SkGlyphCache_Globals; michael@0: }; michael@0: michael@0: class SkAutoGlyphCache { michael@0: public: michael@0: SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {} michael@0: SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) { michael@0: fCache = SkGlyphCache::DetachCache(typeface, desc); michael@0: } michael@0: SkAutoGlyphCache(const SkPaint& paint, michael@0: const SkDeviceProperties* deviceProperties, michael@0: const SkMatrix* matrix) { michael@0: fCache = paint.detachCache(deviceProperties, matrix); michael@0: } michael@0: ~SkAutoGlyphCache() { michael@0: if (fCache) { michael@0: SkGlyphCache::AttachCache(fCache); michael@0: } michael@0: } michael@0: michael@0: SkGlyphCache* getCache() const { return fCache; } michael@0: michael@0: void release() { michael@0: if (fCache) { michael@0: SkGlyphCache::AttachCache(fCache); michael@0: fCache = NULL; michael@0: } michael@0: } michael@0: michael@0: private: michael@0: SkGlyphCache* fCache; michael@0: michael@0: static bool DetachProc(const SkGlyphCache*, void*); michael@0: }; michael@0: #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) michael@0: michael@0: #endif