gfx/skia/trunk/src/core/SkGlyphCache.h

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

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

mercurial