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