Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
michael@0 | 1 | |
michael@0 | 2 | /* |
michael@0 | 3 | * Copyright 2006 The Android Open Source Project |
michael@0 | 4 | * |
michael@0 | 5 | * Use of this source code is governed by a BSD-style license that can be |
michael@0 | 6 | * found in the LICENSE file. |
michael@0 | 7 | */ |
michael@0 | 8 | |
michael@0 | 9 | |
michael@0 | 10 | #ifndef SkGlyphCache_DEFINED |
michael@0 | 11 | #define SkGlyphCache_DEFINED |
michael@0 | 12 | |
michael@0 | 13 | #include "SkBitmap.h" |
michael@0 | 14 | #include "SkChunkAlloc.h" |
michael@0 | 15 | #include "SkDescriptor.h" |
michael@0 | 16 | #include "SkGlyph.h" |
michael@0 | 17 | #include "SkScalerContext.h" |
michael@0 | 18 | #include "SkTemplates.h" |
michael@0 | 19 | #include "SkTDArray.h" |
michael@0 | 20 | |
michael@0 | 21 | struct SkDeviceProperties; |
michael@0 | 22 | class SkPaint; |
michael@0 | 23 | |
michael@0 | 24 | class SkGlyphCache_Globals; |
michael@0 | 25 | |
michael@0 | 26 | /** \class SkGlyphCache |
michael@0 | 27 | |
michael@0 | 28 | This class represents a strike: a specific combination of typeface, size, |
michael@0 | 29 | matrix, etc., and holds the glyphs for that strike. Calling any of the |
michael@0 | 30 | getUnichar.../getGlyphID... methods will return the requested glyph, |
michael@0 | 31 | either instantly if it is already cahced, or by first generating it and then |
michael@0 | 32 | adding it to the strike. |
michael@0 | 33 | |
michael@0 | 34 | The strikes are held in a global list, available to all threads. To interact |
michael@0 | 35 | with one, call either VisitCache() or DetachCache(). |
michael@0 | 36 | */ |
michael@0 | 37 | class SkGlyphCache { |
michael@0 | 38 | public: |
michael@0 | 39 | /** Returns a glyph with valid fAdvance and fDevKern fields. |
michael@0 | 40 | The remaining fields may be valid, but that is not guaranteed. If you |
michael@0 | 41 | require those, call getUnicharMetrics or getGlyphIDMetrics instead. |
michael@0 | 42 | */ |
michael@0 | 43 | const SkGlyph& getUnicharAdvance(SkUnichar); |
michael@0 | 44 | const SkGlyph& getGlyphIDAdvance(uint16_t); |
michael@0 | 45 | |
michael@0 | 46 | /** Returns a glyph with all fields valid except fImage and fPath, which |
michael@0 | 47 | may be null. If they are null, call findImage or findPath for those. |
michael@0 | 48 | If they are not null, then they are valid. |
michael@0 | 49 | |
michael@0 | 50 | This call is potentially slower than the matching ...Advance call. If |
michael@0 | 51 | you only need the fAdvance/fDevKern fields, call those instead. |
michael@0 | 52 | */ |
michael@0 | 53 | const SkGlyph& getUnicharMetrics(SkUnichar); |
michael@0 | 54 | const SkGlyph& getGlyphIDMetrics(uint16_t); |
michael@0 | 55 | |
michael@0 | 56 | /** These are variants that take the device position of the glyph. Call |
michael@0 | 57 | these only if you are drawing in subpixel mode. Passing 0, 0 is |
michael@0 | 58 | effectively the same as calling the variants w/o the extra params, tho |
michael@0 | 59 | a tiny bit slower. |
michael@0 | 60 | */ |
michael@0 | 61 | const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); |
michael@0 | 62 | const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); |
michael@0 | 63 | |
michael@0 | 64 | /** Return the glyphID for the specified Unichar. If the char has already |
michael@0 | 65 | been seen, use the existing cache entry. If not, ask the scalercontext |
michael@0 | 66 | to compute it for us. |
michael@0 | 67 | */ |
michael@0 | 68 | uint16_t unicharToGlyph(SkUnichar); |
michael@0 | 69 | |
michael@0 | 70 | /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to |
michael@0 | 71 | a character code of zero. |
michael@0 | 72 | */ |
michael@0 | 73 | SkUnichar glyphToUnichar(uint16_t); |
michael@0 | 74 | |
michael@0 | 75 | /** Returns the number of glyphs for this strike. |
michael@0 | 76 | */ |
michael@0 | 77 | unsigned getGlyphCount(); |
michael@0 | 78 | |
michael@0 | 79 | #ifdef SK_BUILD_FOR_ANDROID |
michael@0 | 80 | /** Returns the base glyph count for this strike. |
michael@0 | 81 | */ |
michael@0 | 82 | unsigned getBaseGlyphCount(SkUnichar charCode) const { |
michael@0 | 83 | return fScalerContext->getBaseGlyphCount(charCode); |
michael@0 | 84 | } |
michael@0 | 85 | #endif |
michael@0 | 86 | |
michael@0 | 87 | /** Return the image associated with the glyph. If it has not been generated |
michael@0 | 88 | this will trigger that. |
michael@0 | 89 | */ |
michael@0 | 90 | const void* findImage(const SkGlyph&); |
michael@0 | 91 | /** Return the Path associated with the glyph. If it has not been generated |
michael@0 | 92 | this will trigger that. |
michael@0 | 93 | */ |
michael@0 | 94 | const SkPath* findPath(const SkGlyph&); |
michael@0 | 95 | |
michael@0 | 96 | /** Return the vertical metrics for this strike. |
michael@0 | 97 | */ |
michael@0 | 98 | const SkPaint::FontMetrics& getFontMetrics() const { |
michael@0 | 99 | return fFontMetrics; |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | const SkDescriptor& getDescriptor() const { return *fDesc; } |
michael@0 | 103 | |
michael@0 | 104 | SkMask::Format getMaskFormat() const { |
michael@0 | 105 | return fScalerContext->getMaskFormat(); |
michael@0 | 106 | } |
michael@0 | 107 | |
michael@0 | 108 | bool isSubpixel() const { |
michael@0 | 109 | return fScalerContext->isSubpixel(); |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | /* AuxProc/Data allow a client to associate data with this cache entry. |
michael@0 | 113 | Multiple clients can use this, as their data is keyed with a function |
michael@0 | 114 | pointer. In addition to serving as a key, the function pointer is called |
michael@0 | 115 | with the data when the glyphcache object is deleted, so the client can |
michael@0 | 116 | cleanup their data as well. NOTE: the auxProc must not try to access |
michael@0 | 117 | this glyphcache in any way, since it may be in the process of being |
michael@0 | 118 | deleted. |
michael@0 | 119 | */ |
michael@0 | 120 | |
michael@0 | 121 | //! If the proc is found, return true and set *dataPtr to its data |
michael@0 | 122 | bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; |
michael@0 | 123 | //! Add a proc/data pair to the glyphcache. proc should be non-null |
michael@0 | 124 | void setAuxProc(void (*auxProc)(void*), void* auxData); |
michael@0 | 125 | |
michael@0 | 126 | SkScalerContext* getScalerContext() const { return fScalerContext; } |
michael@0 | 127 | |
michael@0 | 128 | /** Call proc on all cache entries, stopping early if proc returns true. |
michael@0 | 129 | The proc should not create or delete caches, since it could produce |
michael@0 | 130 | deadlock. |
michael@0 | 131 | */ |
michael@0 | 132 | static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx); |
michael@0 | 133 | |
michael@0 | 134 | /** Find a matching cache entry, and call proc() with it. If none is found |
michael@0 | 135 | create a new one. If the proc() returns true, detach the cache and |
michael@0 | 136 | return it, otherwise leave it and return NULL. |
michael@0 | 137 | */ |
michael@0 | 138 | static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, |
michael@0 | 139 | bool (*proc)(const SkGlyphCache*, void*), |
michael@0 | 140 | void* context); |
michael@0 | 141 | |
michael@0 | 142 | /** Given a strike that was returned by either VisitCache() or DetachCache() |
michael@0 | 143 | add it back into the global cache list (after which the caller should |
michael@0 | 144 | not reference it anymore. |
michael@0 | 145 | */ |
michael@0 | 146 | static void AttachCache(SkGlyphCache*); |
michael@0 | 147 | |
michael@0 | 148 | /** Detach a strike from the global cache matching the specified descriptor. |
michael@0 | 149 | Once detached, it can be queried/modified by the current thread, and |
michael@0 | 150 | when finished, be reattached to the global cache with AttachCache(). |
michael@0 | 151 | While detached, if another request is made with the same descriptor, |
michael@0 | 152 | a different strike will be generated. This is fine. It does mean we |
michael@0 | 153 | can have more than 1 strike for the same descriptor, but that will |
michael@0 | 154 | eventually get purged, and the win is that different thread will never |
michael@0 | 155 | block each other while a strike is being used. |
michael@0 | 156 | */ |
michael@0 | 157 | static SkGlyphCache* DetachCache(SkTypeface* typeface, |
michael@0 | 158 | const SkDescriptor* desc) { |
michael@0 | 159 | return VisitCache(typeface, desc, DetachProc, NULL); |
michael@0 | 160 | } |
michael@0 | 161 | |
michael@0 | 162 | #ifdef SK_DEBUG |
michael@0 | 163 | void validate() const; |
michael@0 | 164 | #else |
michael@0 | 165 | void validate() const {} |
michael@0 | 166 | #endif |
michael@0 | 167 | |
michael@0 | 168 | class AutoValidate : SkNoncopyable { |
michael@0 | 169 | public: |
michael@0 | 170 | AutoValidate(const SkGlyphCache* cache) : fCache(cache) { |
michael@0 | 171 | if (fCache) { |
michael@0 | 172 | fCache->validate(); |
michael@0 | 173 | } |
michael@0 | 174 | } |
michael@0 | 175 | ~AutoValidate() { |
michael@0 | 176 | if (fCache) { |
michael@0 | 177 | fCache->validate(); |
michael@0 | 178 | } |
michael@0 | 179 | } |
michael@0 | 180 | void forget() { |
michael@0 | 181 | fCache = NULL; |
michael@0 | 182 | } |
michael@0 | 183 | private: |
michael@0 | 184 | const SkGlyphCache* fCache; |
michael@0 | 185 | }; |
michael@0 | 186 | |
michael@0 | 187 | private: |
michael@0 | 188 | // we take ownership of the scalercontext |
michael@0 | 189 | SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); |
michael@0 | 190 | ~SkGlyphCache(); |
michael@0 | 191 | |
michael@0 | 192 | enum MetricsType { |
michael@0 | 193 | kJustAdvance_MetricsType, |
michael@0 | 194 | kFull_MetricsType |
michael@0 | 195 | }; |
michael@0 | 196 | |
michael@0 | 197 | SkGlyph* lookupMetrics(uint32_t id, MetricsType); |
michael@0 | 198 | static bool DetachProc(const SkGlyphCache*, void*) { return true; } |
michael@0 | 199 | |
michael@0 | 200 | SkGlyphCache* fNext, *fPrev; |
michael@0 | 201 | SkDescriptor* fDesc; |
michael@0 | 202 | SkScalerContext* fScalerContext; |
michael@0 | 203 | SkPaint::FontMetrics fFontMetrics; |
michael@0 | 204 | |
michael@0 | 205 | enum { |
michael@0 | 206 | kHashBits = 8, |
michael@0 | 207 | kHashCount = 1 << kHashBits, |
michael@0 | 208 | kHashMask = kHashCount - 1 |
michael@0 | 209 | }; |
michael@0 | 210 | SkGlyph* fGlyphHash[kHashCount]; |
michael@0 | 211 | SkTDArray<SkGlyph*> fGlyphArray; |
michael@0 | 212 | SkChunkAlloc fGlyphAlloc; |
michael@0 | 213 | |
michael@0 | 214 | struct CharGlyphRec { |
michael@0 | 215 | uint32_t fID; // unichar + subpixel |
michael@0 | 216 | SkGlyph* fGlyph; |
michael@0 | 217 | }; |
michael@0 | 218 | // no reason to use the same kHashCount as fGlyphHash, but we do for now |
michael@0 | 219 | CharGlyphRec fCharToGlyphHash[kHashCount]; |
michael@0 | 220 | |
michael@0 | 221 | static inline unsigned ID2HashIndex(uint32_t id) { |
michael@0 | 222 | id ^= id >> 16; |
michael@0 | 223 | id ^= id >> 8; |
michael@0 | 224 | return id & kHashMask; |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | // used to track (approx) how much ram is tied-up in this cache |
michael@0 | 228 | size_t fMemoryUsed; |
michael@0 | 229 | |
michael@0 | 230 | struct AuxProcRec { |
michael@0 | 231 | AuxProcRec* fNext; |
michael@0 | 232 | void (*fProc)(void*); |
michael@0 | 233 | void* fData; |
michael@0 | 234 | }; |
michael@0 | 235 | AuxProcRec* fAuxProcList; |
michael@0 | 236 | void invokeAndRemoveAuxProcs(); |
michael@0 | 237 | |
michael@0 | 238 | inline static SkGlyphCache* FindTail(SkGlyphCache* head); |
michael@0 | 239 | |
michael@0 | 240 | friend class SkGlyphCache_Globals; |
michael@0 | 241 | }; |
michael@0 | 242 | |
michael@0 | 243 | class SkAutoGlyphCache { |
michael@0 | 244 | public: |
michael@0 | 245 | SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {} |
michael@0 | 246 | SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) { |
michael@0 | 247 | fCache = SkGlyphCache::DetachCache(typeface, desc); |
michael@0 | 248 | } |
michael@0 | 249 | SkAutoGlyphCache(const SkPaint& paint, |
michael@0 | 250 | const SkDeviceProperties* deviceProperties, |
michael@0 | 251 | const SkMatrix* matrix) { |
michael@0 | 252 | fCache = paint.detachCache(deviceProperties, matrix); |
michael@0 | 253 | } |
michael@0 | 254 | ~SkAutoGlyphCache() { |
michael@0 | 255 | if (fCache) { |
michael@0 | 256 | SkGlyphCache::AttachCache(fCache); |
michael@0 | 257 | } |
michael@0 | 258 | } |
michael@0 | 259 | |
michael@0 | 260 | SkGlyphCache* getCache() const { return fCache; } |
michael@0 | 261 | |
michael@0 | 262 | void release() { |
michael@0 | 263 | if (fCache) { |
michael@0 | 264 | SkGlyphCache::AttachCache(fCache); |
michael@0 | 265 | fCache = NULL; |
michael@0 | 266 | } |
michael@0 | 267 | } |
michael@0 | 268 | |
michael@0 | 269 | private: |
michael@0 | 270 | SkGlyphCache* fCache; |
michael@0 | 271 | |
michael@0 | 272 | static bool DetachProc(const SkGlyphCache*, void*); |
michael@0 | 273 | }; |
michael@0 | 274 | #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) |
michael@0 | 275 | |
michael@0 | 276 | #endif |