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