1 /* 2 * Copyright 2010 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 9 #include "SkGradientBitmapCache.h" 10 11 #include "SkMalloc.h" 12 13 struct SkGradientBitmapCache::Entry { 14 Entry* fPrev; 15 Entry* fNext; 16 17 void* fBuffer; 18 size_t fSize; 19 SkBitmap fBitmap; 20 21 Entry(const void* buffer, size_t size, const SkBitmap& bm) 22 : fPrev(nullptr), 23 fNext(nullptr), 24 fBitmap(bm) { 25 fBuffer = sk_malloc_throw(size); 26 fSize = size; 27 memcpy(fBuffer, buffer, size); 28 } 29 30 ~Entry() { sk_free(fBuffer); } 31 32 bool equals(const void* buffer, size_t size) const { 33 return (fSize == size) && !memcmp(fBuffer, buffer, size); 34 } 35 }; 36 37 SkGradientBitmapCache::SkGradientBitmapCache(int max) : fMaxEntries(max) { 38 fEntryCount = 0; 39 fHead = fTail = nullptr; 40 41 this->validate(); 42 } 43 44 SkGradientBitmapCache::~SkGradientBitmapCache() { 45 this->validate(); 46 47 Entry* entry = fHead; 48 while (entry) { 49 Entry* next = entry->fNext; 50 delete entry; 51 entry = next; 52 } 53 } 54 55 SkGradientBitmapCache::Entry* SkGradientBitmapCache::release(Entry* entry) const { 56 if (entry->fPrev) { 57 SkASSERT(fHead != entry); 58 entry->fPrev->fNext = entry->fNext; 59 } else { 60 SkASSERT(fHead == entry); 61 fHead = entry->fNext; 62 } 63 if (entry->fNext) { 64 SkASSERT(fTail != entry); 65 entry->fNext->fPrev = entry->fPrev; 66 } else { 67 SkASSERT(fTail == entry); 68 fTail = entry->fPrev; 69 } 70 return entry; 71 } 72 73 void SkGradientBitmapCache::attachToHead(Entry* entry) const { 74 entry->fPrev = nullptr; 75 entry->fNext = fHead; 76 if (fHead) { 77 fHead->fPrev = entry; 78 } else { 79 fTail = entry; 80 } 81 fHead = entry; 82 } 83 84 bool SkGradientBitmapCache::find(const void* buffer, size_t size, SkBitmap* bm) const { 85 AutoValidate av(this); 86 87 Entry* entry = fHead; 88 while (entry) { 89 if (entry->equals(buffer, size)) { 90 if (bm) { 91 *bm = entry->fBitmap; 92 } 93 // move to the head of our list, so we purge it last 94 this->release(entry); 95 this->attachToHead(entry); 96 return true; 97 } 98 entry = entry->fNext; 99 } 100 return false; 101 } 102 103 void SkGradientBitmapCache::add(const void* buffer, size_t len, const SkBitmap& bm) { 104 AutoValidate av(this); 105 106 if (fEntryCount == fMaxEntries) { 107 SkASSERT(fTail); 108 delete this->release(fTail); 109 fEntryCount -= 1; 110 } 111 112 Entry* entry = new Entry(buffer, len, bm); 113 this->attachToHead(entry); 114 fEntryCount += 1; 115 } 116 117 /////////////////////////////////////////////////////////////////////////////// 118 119 #ifdef SK_DEBUG 120 121 void SkGradientBitmapCache::validate() const { 122 SkASSERT(fEntryCount >= 0 && fEntryCount <= fMaxEntries); 123 124 if (fEntryCount > 0) { 125 SkASSERT(nullptr == fHead->fPrev); 126 SkASSERT(nullptr == fTail->fNext); 127 128 if (fEntryCount == 1) { 129 SkASSERT(fHead == fTail); 130 } else { 131 SkASSERT(fHead != fTail); 132 } 133 134 Entry* entry = fHead; 135 int count = 0; 136 while (entry) { 137 count += 1; 138 entry = entry->fNext; 139 } 140 SkASSERT(count == fEntryCount); 141 142 entry = fTail; 143 while (entry) { 144 count -= 1; 145 entry = entry->fPrev; 146 } 147 SkASSERT(0 == count); 148 } else { 149 SkASSERT(nullptr == fHead); 150 SkASSERT(nullptr == fTail); 151 } 152 } 153 154 #endif 155