1 /* 2 Copyright 2010 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #include "SkBitmapCache.h" 18 19 struct SkBitmapCache::Entry { 20 Entry* fPrev; 21 Entry* fNext; 22 23 void* fBuffer; 24 size_t fSize; 25 SkBitmap fBitmap; 26 27 Entry(const void* buffer, size_t size, const SkBitmap& bm) : fBitmap(bm) { 28 fBuffer = sk_malloc_throw(size); 29 fSize = size; 30 memcpy(fBuffer, buffer, size); 31 } 32 33 ~Entry() { sk_free(fBuffer); } 34 35 bool equals(const void* buffer, size_t size) const { 36 return (fSize == size) && !memcmp(fBuffer, buffer, size); 37 } 38 }; 39 40 SkBitmapCache::SkBitmapCache(int max) : fMaxEntries(max) { 41 fEntryCount = 0; 42 fHead = fTail = NULL; 43 44 this->validate(); 45 } 46 47 SkBitmapCache::~SkBitmapCache() { 48 this->validate(); 49 50 Entry* entry = fHead; 51 while (entry) { 52 Entry* next = entry->fNext; 53 delete entry; 54 entry = next; 55 } 56 } 57 58 SkBitmapCache::Entry* SkBitmapCache::detach(Entry* entry) const { 59 if (entry->fPrev) { 60 SkASSERT(fHead != entry); 61 entry->fPrev->fNext = entry->fNext; 62 } else { 63 SkASSERT(fHead == entry); 64 fHead = entry->fNext; 65 } 66 if (entry->fNext) { 67 SkASSERT(fTail != entry); 68 entry->fNext->fPrev = entry->fPrev; 69 } else { 70 SkASSERT(fTail == entry); 71 fTail = entry->fPrev; 72 } 73 return entry; 74 } 75 76 void SkBitmapCache::attachToHead(Entry* entry) const { 77 entry->fPrev = NULL; 78 entry->fNext = fHead; 79 if (fHead) { 80 fHead->fPrev = entry; 81 } else { 82 fTail = entry; 83 } 84 fHead = entry; 85 } 86 87 bool SkBitmapCache::find(const void* buffer, size_t size, SkBitmap* bm) const { 88 AutoValidate av(this); 89 90 Entry* entry = fHead; 91 while (entry) { 92 if (entry->equals(buffer, size)) { 93 if (bm) { 94 *bm = entry->fBitmap; 95 } 96 // move to the head of our list, so we purge it last 97 this->detach(entry); 98 this->attachToHead(entry); 99 return true; 100 } 101 entry = entry->fNext; 102 } 103 return false; 104 } 105 106 void SkBitmapCache::add(const void* buffer, size_t len, const SkBitmap& bm) { 107 AutoValidate av(this); 108 109 if (fEntryCount == fMaxEntries) { 110 SkASSERT(fTail); 111 delete this->detach(fTail); 112 fEntryCount -= 1; 113 } 114 115 Entry* entry = new Entry(buffer, len, bm); 116 this->attachToHead(entry); 117 fEntryCount += 1; 118 } 119 120 /////////////////////////////////////////////////////////////////////////////// 121 122 #ifdef SK_DEBUG 123 124 void SkBitmapCache::validate() const { 125 SkASSERT(fEntryCount >= 0 && fEntryCount <= fMaxEntries); 126 127 if (fEntryCount > 0) { 128 SkASSERT(NULL == fHead->fPrev); 129 SkASSERT(NULL == fTail->fNext); 130 131 if (fEntryCount == 1) { 132 SkASSERT(fHead == fTail); 133 } else { 134 SkASSERT(fHead != fTail); 135 } 136 137 Entry* entry = fHead; 138 int count = 0; 139 while (entry) { 140 count += 1; 141 entry = entry->fNext; 142 } 143 SkASSERT(count == fEntryCount); 144 145 entry = fTail; 146 while (entry) { 147 count -= 1; 148 entry = entry->fPrev; 149 } 150 SkASSERT(0 == count); 151 } else { 152 SkASSERT(NULL == fHead); 153 SkASSERT(NULL == fTail); 154 } 155 } 156 157 #endif 158 159