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
EntrySkBitmapCache::Entry27 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
~EntrySkBitmapCache::Entry33 ~Entry() { sk_free(fBuffer); }
34
equalsSkBitmapCache::Entry35 bool equals(const void* buffer, size_t size) const {
36 return (fSize == size) && !memcmp(fBuffer, buffer, size);
37 }
38 };
39
SkBitmapCache(int max)40 SkBitmapCache::SkBitmapCache(int max) : fMaxEntries(max) {
41 fEntryCount = 0;
42 fHead = fTail = NULL;
43
44 this->validate();
45 }
46
~SkBitmapCache()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
detach(Entry * entry) const58 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
attachToHead(Entry * entry) const76 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
find(const void * buffer,size_t size,SkBitmap * bm) const87 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
add(const void * buffer,size_t len,const SkBitmap & bm)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
validate() const124 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