• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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