diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/core/SkGlyphCache.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/core/SkGlyphCache.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,276 @@ + +/* + * 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 "SkScalerContext.h" +#include "SkTemplates.h" +#include "SkTDArray.h" + +struct SkDeviceProperties; +class SkPaint; + +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 cahced, 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, tho + 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(); + +#ifdef SK_BUILD_FOR_ANDROID + /** Returns the base glyph count for this strike. + */ + unsigned getBaseGlyphCount(SkUnichar charCode) const { + return fScalerContext->getBaseGlyphCount(charCode); + } +#endif + + /** 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(); + } + + /* 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; } + + /** Call proc on all cache entries, stopping early if proc returns true. + The proc should not create or delete caches, since it could produce + deadlock. + */ + static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx); + + /** 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 NULL. + */ + 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, NULL); + } + +#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 = NULL; + } + private: + const SkGlyphCache* fCache; + }; + +private: + // we take ownership of the scalercontext + SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); + ~SkGlyphCache(); + + enum MetricsType { + kJustAdvance_MetricsType, + kFull_MetricsType + }; + + SkGlyph* lookupMetrics(uint32_t id, MetricsType); + static bool DetachProc(const SkGlyphCache*, void*) { return true; } + + SkGlyphCache* fNext, *fPrev; + SkDescriptor* fDesc; + SkScalerContext* fScalerContext; + SkPaint::FontMetrics fFontMetrics; + + enum { + kHashBits = 8, + kHashCount = 1 << kHashBits, + kHashMask = kHashCount - 1 + }; + SkGlyph* fGlyphHash[kHashCount]; + SkTDArray fGlyphArray; + SkChunkAlloc fGlyphAlloc; + + struct CharGlyphRec { + uint32_t fID; // unichar + subpixel + SkGlyph* fGlyph; + }; + // no reason to use the same kHashCount as fGlyphHash, but we do for now + CharGlyphRec fCharToGlyphHash[kHashCount]; + + static inline unsigned ID2HashIndex(uint32_t id) { + id ^= id >> 16; + id ^= id >> 8; + return id & kHashMask; + } + + // used to track (approx) how much ram is tied-up in this cache + size_t fMemoryUsed; + + struct AuxProcRec { + AuxProcRec* fNext; + void (*fProc)(void*); + void* fData; + }; + AuxProcRec* fAuxProcList; + void invokeAndRemoveAuxProcs(); + + inline static SkGlyphCache* FindTail(SkGlyphCache* head); + + friend class SkGlyphCache_Globals; +}; + +class SkAutoGlyphCache { +public: + SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {} + SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) { + fCache = SkGlyphCache::DetachCache(typeface, desc); + } + SkAutoGlyphCache(const SkPaint& paint, + const SkDeviceProperties* deviceProperties, + const SkMatrix* matrix) { + fCache = paint.detachCache(deviceProperties, matrix); + } + ~SkAutoGlyphCache() { + if (fCache) { + SkGlyphCache::AttachCache(fCache); + } + } + + SkGlyphCache* getCache() const { return fCache; } + + void release() { + if (fCache) { + SkGlyphCache::AttachCache(fCache); + fCache = NULL; + } + } + +private: + SkGlyphCache* fCache; + + static bool DetachProc(const SkGlyphCache*, void*); +}; +#define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) + +#endif