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(NULL),
22               fNext(NULL),
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 = NULL;
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 = NULL;
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 = SkNEW_ARGS(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(NULL == fHead->fPrev);
125         SkASSERT(NULL == 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(NULL == fHead);
149         SkASSERT(NULL == fTail);
150     }
151 }
152 
153 #endif
154