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
EntrySkGradientBitmapCache::Entry21 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
~EntrySkGradientBitmapCache::Entry30 ~Entry() { sk_free(fBuffer); }
31
equalsSkGradientBitmapCache::Entry32 bool equals(const void* buffer, size_t size) const {
33 return (fSize == size) && !memcmp(fBuffer, buffer, size);
34 }
35 };
36
SkGradientBitmapCache(int max)37 SkGradientBitmapCache::SkGradientBitmapCache(int max) : fMaxEntries(max) {
38 fEntryCount = 0;
39 fHead = fTail = nullptr;
40
41 this->validate();
42 }
43
~SkGradientBitmapCache()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
release(Entry * entry) const55 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
attachToHead(Entry * entry) const73 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
find(const void * buffer,size_t size,SkBitmap * bm) const84 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
add(const void * buffer,size_t len,const SkBitmap & bm)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
validate() const121 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