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

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2012 Google Inc.
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 #ifndef SkBitmapHeap_DEFINED
michael@0 9 #define SkBitmapHeap_DEFINED
michael@0 10
michael@0 11 #include "SkBitmap.h"
michael@0 12 #include "SkFlattenable.h"
michael@0 13 #include "SkRefCnt.h"
michael@0 14 #include "SkTDArray.h"
michael@0 15 #include "SkThread.h"
michael@0 16 #include "SkTRefArray.h"
michael@0 17
michael@0 18 /**
michael@0 19 * SkBitmapHeapEntry provides users of SkBitmapHeap (using internal storage) with a means to...
michael@0 20 * (1) get access a bitmap in the heap
michael@0 21 * (2) indicate they are done with bitmap by releasing their reference (if they were an owner).
michael@0 22 */
michael@0 23 class SkBitmapHeapEntry : SkNoncopyable {
michael@0 24 public:
michael@0 25 ~SkBitmapHeapEntry();
michael@0 26
michael@0 27 int32_t getSlot() { return fSlot; }
michael@0 28
michael@0 29 SkBitmap* getBitmap() { return &fBitmap; }
michael@0 30
michael@0 31 void releaseRef() {
michael@0 32 sk_atomic_dec(&fRefCount);
michael@0 33 }
michael@0 34
michael@0 35 private:
michael@0 36 SkBitmapHeapEntry();
michael@0 37
michael@0 38 void addReferences(int count);
michael@0 39
michael@0 40 int32_t fSlot;
michael@0 41 int32_t fRefCount;
michael@0 42
michael@0 43 SkBitmap fBitmap;
michael@0 44 // Keep track of the bytes allocated for this bitmap. When replacing the
michael@0 45 // bitmap or removing this HeapEntry we know how much memory has been
michael@0 46 // reclaimed.
michael@0 47 size_t fBytesAllocated;
michael@0 48
michael@0 49 friend class SkBitmapHeap;
michael@0 50 friend class SkBitmapHeapTester;
michael@0 51 };
michael@0 52
michael@0 53
michael@0 54 class SkBitmapHeapReader : public SkRefCnt {
michael@0 55 public:
michael@0 56 SK_DECLARE_INST_COUNT(SkBitmapHeapReader)
michael@0 57
michael@0 58 SkBitmapHeapReader() : INHERITED() {}
michael@0 59 virtual SkBitmap* getBitmap(int32_t slot) const = 0;
michael@0 60 virtual void releaseRef(int32_t slot) = 0;
michael@0 61 private:
michael@0 62 typedef SkRefCnt INHERITED;
michael@0 63 };
michael@0 64
michael@0 65
michael@0 66 /**
michael@0 67 * TODO: stores immutable bitmaps into a heap
michael@0 68 */
michael@0 69 class SkBitmapHeap : public SkBitmapHeapReader {
michael@0 70 public:
michael@0 71 class ExternalStorage : public SkRefCnt {
michael@0 72 public:
michael@0 73 SK_DECLARE_INST_COUNT(ExternalStorage)
michael@0 74
michael@0 75 virtual bool insert(const SkBitmap& bitmap, int32_t slot) = 0;
michael@0 76
michael@0 77 private:
michael@0 78 typedef SkRefCnt INHERITED;
michael@0 79 };
michael@0 80
michael@0 81 static const int32_t UNLIMITED_SIZE = -1;
michael@0 82 static const int32_t IGNORE_OWNERS = -1;
michael@0 83 static const int32_t INVALID_SLOT = -1;
michael@0 84
michael@0 85 /**
michael@0 86 * Constructs a heap that is responsible for allocating and managing its own storage. In the
michael@0 87 * case where we choose to allow the heap to grow indefinitely (i.e. UNLIMITED_SIZE) we
michael@0 88 * guarantee that once allocated in the heap a bitmap's index in the heap is immutable.
michael@0 89 * Otherwise we guarantee the bitmaps placement in the heap until its owner count goes to zero.
michael@0 90 *
michael@0 91 * @param preferredSize Specifies the preferred maximum number of bitmaps to store. This is
michael@0 92 * not a hard limit as it can grow larger if the number of bitmaps in the heap with active
michael@0 93 * owners exceeds this limit.
michael@0 94 * @param ownerCount The number of owners to assign to each inserted bitmap. NOTE: while a
michael@0 95 * bitmap in the heap has a least one owner it can't be removed.
michael@0 96 */
michael@0 97 SkBitmapHeap(int32_t preferredSize = UNLIMITED_SIZE, int32_t ownerCount = IGNORE_OWNERS);
michael@0 98
michael@0 99 /**
michael@0 100 * Constructs a heap that defers the responsibility of storing the bitmaps to an external
michael@0 101 * function. This is especially useful if the bitmaps will be used in a separate process as the
michael@0 102 * external storage can ensure the data is properly shuttled to the appropriate processes.
michael@0 103 *
michael@0 104 * Our LRU implementation assumes that inserts into the external storage are consumed in the
michael@0 105 * order that they are inserted (i.e. SkPipe). This ensures that we don't need to query the
michael@0 106 * external storage to see if a slot in the heap is eligible to be overwritten.
michael@0 107 *
michael@0 108 * @param externalStorage The class responsible for storing the bitmaps inserted into the heap
michael@0 109 * @param heapSize The maximum size of the heap. Because of the sequential limitation imposed
michael@0 110 * by our LRU implementation we can guarantee that the heap will never grow beyond this size.
michael@0 111 */
michael@0 112 SkBitmapHeap(ExternalStorage* externalStorage, int32_t heapSize = UNLIMITED_SIZE);
michael@0 113
michael@0 114 virtual ~SkBitmapHeap();
michael@0 115
michael@0 116 /**
michael@0 117 * Makes a shallow copy of all bitmaps currently in the heap and returns them as an array. The
michael@0 118 * array indices match their position in the heap.
michael@0 119 *
michael@0 120 * @return a ptr to an array of bitmaps or NULL if external storage is being used.
michael@0 121 */
michael@0 122 SkTRefArray<SkBitmap>* extractBitmaps() const;
michael@0 123
michael@0 124 /**
michael@0 125 * Retrieves the bitmap from the specified slot in the heap
michael@0 126 *
michael@0 127 * @return The bitmap located at that slot or NULL if external storage is being used.
michael@0 128 */
michael@0 129 virtual SkBitmap* getBitmap(int32_t slot) const SK_OVERRIDE {
michael@0 130 SkASSERT(fExternalStorage == NULL);
michael@0 131 SkBitmapHeapEntry* entry = getEntry(slot);
michael@0 132 if (entry) {
michael@0 133 return &entry->fBitmap;
michael@0 134 }
michael@0 135 return NULL;
michael@0 136 }
michael@0 137
michael@0 138 /**
michael@0 139 * Retrieves the bitmap from the specified slot in the heap
michael@0 140 *
michael@0 141 * @return The bitmap located at that slot or NULL if external storage is being used.
michael@0 142 */
michael@0 143 virtual void releaseRef(int32_t slot) SK_OVERRIDE {
michael@0 144 SkASSERT(fExternalStorage == NULL);
michael@0 145 if (fOwnerCount != IGNORE_OWNERS) {
michael@0 146 SkBitmapHeapEntry* entry = getEntry(slot);
michael@0 147 if (entry) {
michael@0 148 entry->releaseRef();
michael@0 149 }
michael@0 150 }
michael@0 151 }
michael@0 152
michael@0 153 /**
michael@0 154 * Inserts a bitmap into the heap. The stored version of bitmap is guaranteed to be immutable
michael@0 155 * and is not dependent on the lifecycle of the provided bitmap.
michael@0 156 *
michael@0 157 * @param bitmap the bitmap to be inserted into the heap
michael@0 158 * @return the slot in the heap where the bitmap is stored or INVALID_SLOT if the bitmap could
michael@0 159 * not be added to the heap. If it was added the slot will remain valid...
michael@0 160 * (1) indefinitely if no owner count has been specified.
michael@0 161 * (2) until all owners have called releaseRef on the appropriate SkBitmapHeapEntry*
michael@0 162 */
michael@0 163 int32_t insert(const SkBitmap& bitmap);
michael@0 164
michael@0 165 /**
michael@0 166 * Retrieves an entry from the heap at a given slot.
michael@0 167 *
michael@0 168 * @param slot the slot in the heap where a bitmap was stored.
michael@0 169 * @return a SkBitmapHeapEntry that wraps the bitmap or NULL if external storage is used.
michael@0 170 */
michael@0 171 SkBitmapHeapEntry* getEntry(int32_t slot) const {
michael@0 172 SkASSERT(slot <= fStorage.count());
michael@0 173 if (fExternalStorage != NULL) {
michael@0 174 return NULL;
michael@0 175 }
michael@0 176 return fStorage[slot];
michael@0 177 }
michael@0 178
michael@0 179 /**
michael@0 180 * Returns a count of the number of items currently in the heap
michael@0 181 */
michael@0 182 int count() const {
michael@0 183 SkASSERT(fExternalStorage != NULL ||
michael@0 184 fStorage.count() - fUnusedSlots.count() == fLookupTable.count());
michael@0 185 return fLookupTable.count();
michael@0 186 }
michael@0 187
michael@0 188 /**
michael@0 189 * Returns the total number of bytes allocated by the bitmaps in the heap
michael@0 190 */
michael@0 191 size_t bytesAllocated() const {
michael@0 192 return fBytesAllocated;
michael@0 193 }
michael@0 194
michael@0 195 /**
michael@0 196 * Attempt to reduce the storage allocated.
michael@0 197 * @param bytesToFree minimum number of bytes that should be attempted to
michael@0 198 * be freed.
michael@0 199 * @return number of bytes actually freed.
michael@0 200 */
michael@0 201 size_t freeMemoryIfPossible(size_t bytesToFree);
michael@0 202
michael@0 203 /**
michael@0 204 * Defer any increments of owner counts until endAddingOwnersDeferral is called. So if an
michael@0 205 * existing SkBitmap is inserted into the SkBitmapHeap, its corresponding SkBitmapHeapEntry will
michael@0 206 * not have addReferences called on it, and the client does not need to make a corresponding
michael@0 207 * call to releaseRef. Only meaningful if this SkBitmapHeap was created with an owner count not
michael@0 208 * equal to IGNORE_OWNERS.
michael@0 209 */
michael@0 210 void deferAddingOwners();
michael@0 211
michael@0 212 /**
michael@0 213 * Resume adding references when duplicate SkBitmaps are inserted.
michael@0 214 * @param add If true, add references to the SkBitmapHeapEntrys whose SkBitmaps were re-inserted
michael@0 215 * while deferring.
michael@0 216 */
michael@0 217 void endAddingOwnersDeferral(bool add);
michael@0 218
michael@0 219 private:
michael@0 220 struct LookupEntry {
michael@0 221 LookupEntry(const SkBitmap& bm)
michael@0 222 : fGenerationId(bm.getGenerationID())
michael@0 223 , fPixelOrigin(bm.pixelRefOrigin())
michael@0 224 , fWidth(bm.width())
michael@0 225 , fHeight(bm.height())
michael@0 226 , fMoreRecentlyUsed(NULL)
michael@0 227 , fLessRecentlyUsed(NULL){}
michael@0 228
michael@0 229 const uint32_t fGenerationId; // SkPixelRef GenerationID.
michael@0 230 const SkIPoint fPixelOrigin;
michael@0 231 const uint32_t fWidth;
michael@0 232 const uint32_t fHeight;
michael@0 233
michael@0 234 // TODO: Generalize the LRU caching mechanism
michael@0 235 LookupEntry* fMoreRecentlyUsed;
michael@0 236 LookupEntry* fLessRecentlyUsed;
michael@0 237
michael@0 238 uint32_t fStorageSlot; // slot of corresponding bitmap in fStorage.
michael@0 239
michael@0 240 /**
michael@0 241 * Compare two LookupEntry pointers for sorting and searching.
michael@0 242 */
michael@0 243 static bool Less(const LookupEntry& a, const LookupEntry& b);
michael@0 244 };
michael@0 245
michael@0 246 /**
michael@0 247 * Remove the entry from the lookup table. Also deletes the entry pointed
michael@0 248 * to by the table. Therefore, if a pointer to that one was passed in, the
michael@0 249 * pointer should no longer be used, since the object to which it points has
michael@0 250 * been deleted.
michael@0 251 * @return The index in the lookup table of the entry before removal.
michael@0 252 */
michael@0 253 int removeEntryFromLookupTable(LookupEntry*);
michael@0 254
michael@0 255 /**
michael@0 256 * Searches for the bitmap in the lookup table and returns the bitmaps index within the table.
michael@0 257 * If the bitmap was not already in the table it is added.
michael@0 258 *
michael@0 259 * @param key The key to search the lookup table, created from a bitmap.
michael@0 260 * @param entry A pointer to a SkBitmapHeapEntry* that if non-null AND the bitmap is found
michael@0 261 * in the lookup table is populated with the entry from the heap storage.
michael@0 262 */
michael@0 263 int findInLookupTable(const LookupEntry& key, SkBitmapHeapEntry** entry);
michael@0 264
michael@0 265 LookupEntry* findEntryToReplace(const SkBitmap& replacement);
michael@0 266 bool copyBitmap(const SkBitmap& originalBitmap, SkBitmap& copiedBitmap);
michael@0 267
michael@0 268 /**
michael@0 269 * Remove a LookupEntry from the LRU, in preparation for either deleting or appending as most
michael@0 270 * recent. Points the LookupEntry's old neighbors at each other, and sets fLeastRecentlyUsed
michael@0 271 * (if there is still an entry left). Sets LookupEntry's fMoreRecentlyUsed to NULL and leaves
michael@0 272 * its fLessRecentlyUsed unmodified.
michael@0 273 */
michael@0 274 void removeFromLRU(LookupEntry* entry);
michael@0 275
michael@0 276 /**
michael@0 277 * Append a LookupEntry to the end of the LRU cache, marking it as the most
michael@0 278 * recently used. Assumes that the LookupEntry is already in fLookupTable,
michael@0 279 * but is not in the LRU cache. If it is in the cache, removeFromLRU should
michael@0 280 * be called first.
michael@0 281 */
michael@0 282 void appendToLRU(LookupEntry*);
michael@0 283
michael@0 284 // searchable index that maps to entries in the heap
michael@0 285 SkTDArray<LookupEntry*> fLookupTable;
michael@0 286
michael@0 287 // heap storage
michael@0 288 SkTDArray<SkBitmapHeapEntry*> fStorage;
michael@0 289 // Used to mark slots in fStorage as deleted without actually deleting
michael@0 290 // the slot so as not to mess up the numbering.
michael@0 291 SkTDArray<int> fUnusedSlots;
michael@0 292 ExternalStorage* fExternalStorage;
michael@0 293
michael@0 294 LookupEntry* fMostRecentlyUsed;
michael@0 295 LookupEntry* fLeastRecentlyUsed;
michael@0 296
michael@0 297 const int32_t fPreferredCount;
michael@0 298 const int32_t fOwnerCount;
michael@0 299 size_t fBytesAllocated;
michael@0 300
michael@0 301 bool fDeferAddingOwners;
michael@0 302 SkTDArray<int> fDeferredEntries;
michael@0 303
michael@0 304 typedef SkBitmapHeapReader INHERITED;
michael@0 305 };
michael@0 306
michael@0 307 #endif // SkBitmapHeap_DEFINED

mercurial