Home | History | Annotate | Download | only in gradients
      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 "SkBitmapCache.h"
     11 
     12 struct SkBitmapCache::Entry {
     13     Entry*      fPrev;
     14     Entry*      fNext;
     15 
     16     void*       fBuffer;
     17     size_t      fSize;
     18     SkBitmap    fBitmap;
     19 
     20     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 
     29     ~Entry() { sk_free(fBuffer); }
     30 
     31     bool equals(const void* buffer, size_t size) const {
     32         return (fSize == size) && !memcmp(fBuffer, buffer, size);
     33     }
     34 };
     35 
     36 SkBitmapCache::SkBitmapCache(int max) : fMaxEntries(max) {
     37     fEntryCount = 0;
     38     fHead = fTail = NULL;
     39 
     40     this->validate();
     41 }
     42 
     43 SkBitmapCache::~SkBitmapCache() {
     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 
     54 SkBitmapCache::Entry* SkBitmapCache::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 
     72 void SkBitmapCache::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 
     83 bool SkBitmapCache::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 
    102 void SkBitmapCache::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 
    120 void SkBitmapCache::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