Home | History | Annotate | Download | only in gradients
      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 
     21     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 
     30     ~Entry() { sk_free(fBuffer); }
     31 
     32     bool equals(const void* buffer, size_t size) const {
     33         return (fSize == size) && !memcmp(fBuffer, buffer, size);
     34     }
     35 };
     36 
     37 SkGradientBitmapCache::SkGradientBitmapCache(int max) : fMaxEntries(max) {
     38     fEntryCount = 0;
     39     fHead = fTail = nullptr;
     40 
     41     this->validate();
     42 }
     43 
     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 
     55 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 
     73 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 
     84 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 
    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 
    121 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