Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2014 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 #include "SkBitmapCache.h"
      9 #include "SkResourceCache.h"
     10 #include "SkMipMap.h"
     11 #include "SkRect.h"
     12 
     13 SkBitmap::Allocator* SkBitmapCache::GetAllocator() {
     14     return SkResourceCache::GetAllocator();
     15 }
     16 
     17 /**
     18  This function finds the bounds of the bitmap *within its pixelRef*.
     19  If the bitmap lacks a pixelRef, it will return an empty rect, since
     20  that doesn't make sense.  This may be a useful enough function that
     21  it should be somewhere else (in SkBitmap?).
     22  */
     23 static SkIRect get_bounds_from_bitmap(const SkBitmap& bm) {
     24     if (!(bm.pixelRef())) {
     25         return SkIRect::MakeEmpty();
     26     }
     27     SkIPoint origin = bm.pixelRefOrigin();
     28     return SkIRect::MakeXYWH(origin.fX, origin.fY, bm.width(), bm.height());
     29 }
     30 
     31 struct BitmapKey : public SkResourceCache::Key {
     32 public:
     33     BitmapKey(uint32_t genID, SkScalar scaleX, SkScalar scaleY, const SkIRect& bounds)
     34     : fGenID(genID)
     35     , fScaleX(scaleX)
     36     , fScaleY(scaleY)
     37     , fBounds(bounds)
     38     {
     39         this->init(sizeof(fGenID) + sizeof(fScaleX) + sizeof(fScaleY) + sizeof(fBounds));
     40     }
     41 
     42     uint32_t    fGenID;
     43     SkScalar    fScaleX;
     44     SkScalar    fScaleY;
     45     SkIRect     fBounds;
     46 };
     47 
     48 //////////////////////////////////////////////////////////////////////////////////////////
     49 
     50 struct BitmapRec : public SkResourceCache::Rec {
     51     BitmapRec(uint32_t genID, SkScalar scaleX, SkScalar scaleY, const SkIRect& bounds,
     52               const SkBitmap& result)
     53         : fKey(genID, scaleX, scaleY, bounds)
     54         , fBitmap(result)
     55     {}
     56 
     57     BitmapKey   fKey;
     58     SkBitmap    fBitmap;
     59 
     60     virtual const Key& getKey() const SK_OVERRIDE { return fKey; }
     61     virtual size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + fBitmap.getSize(); }
     62 
     63     static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
     64         const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec);
     65         SkBitmap* result = (SkBitmap*)contextBitmap;
     66 
     67         *result = rec.fBitmap;
     68         result->lockPixels();
     69         return SkToBool(result->getPixels());
     70     }
     71 };
     72 
     73 #define CHECK_LOCAL(localCache, localName, globalName, ...) \
     74     (localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__)
     75 
     76 bool SkBitmapCache::Find(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY, SkBitmap* result,
     77                          SkResourceCache* localCache) {
     78     if (0 == invScaleX || 0 == invScaleY) {
     79         // degenerate, and the key we use for mipmaps
     80         return false;
     81     }
     82     BitmapKey key(src.getGenerationID(), invScaleX, invScaleY, get_bounds_from_bitmap(src));
     83 
     84     return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Visitor, result);
     85 }
     86 
     87 void SkBitmapCache::Add(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY,
     88                         const SkBitmap& result, SkResourceCache* localCache) {
     89     if (0 == invScaleX || 0 == invScaleY) {
     90         // degenerate, and the key we use for mipmaps
     91         return;
     92     }
     93     SkASSERT(result.isImmutable());
     94     BitmapRec* rec = SkNEW_ARGS(BitmapRec, (src.getGenerationID(), invScaleX, invScaleY,
     95                                             get_bounds_from_bitmap(src), result));
     96     CHECK_LOCAL(localCache, add, Add, rec);
     97 }
     98 
     99 bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result,
    100                          SkResourceCache* localCache) {
    101     BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset);
    102 
    103     return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Visitor, result);
    104 }
    105 
    106 bool SkBitmapCache::Add(uint32_t genID, const SkIRect& subset, const SkBitmap& result,
    107                         SkResourceCache* localCache) {
    108     SkASSERT(result.isImmutable());
    109 
    110     if (subset.isEmpty()
    111         || subset.top() < 0
    112         || subset.left() < 0
    113         || result.width() != subset.width()
    114         || result.height() != subset.height()) {
    115         return false;
    116     } else {
    117         BitmapRec* rec = SkNEW_ARGS(BitmapRec, (genID, SK_Scalar1, SK_Scalar1, subset, result));
    118 
    119         CHECK_LOCAL(localCache, add, Add, rec);
    120         return true;
    121     }
    122 }
    123 //////////////////////////////////////////////////////////////////////////////////////////
    124 
    125 struct MipMapRec : public SkResourceCache::Rec {
    126     MipMapRec(const SkBitmap& src, const SkMipMap* result)
    127         : fKey(src.getGenerationID(), 0, 0, get_bounds_from_bitmap(src))
    128         , fMipMap(SkRef(result))
    129     {}
    130 
    131     virtual ~MipMapRec() {
    132         fMipMap->unref();
    133     }
    134 
    135     BitmapKey       fKey;
    136     const SkMipMap* fMipMap;
    137 
    138     virtual const Key& getKey() const SK_OVERRIDE { return fKey; }
    139     virtual size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + fMipMap->getSize(); }
    140 
    141     static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextMip) {
    142         const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
    143         const SkMipMap** result = (const SkMipMap**)contextMip;
    144 
    145         *result = SkRef(rec.fMipMap);
    146         // mipmaps don't use the custom allocator yet, so we don't need to check pixels
    147         return true;
    148     }
    149 };
    150 
    151 const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmap& src) {
    152     BitmapKey key(src.getGenerationID(), 0, 0, get_bounds_from_bitmap(src));
    153     const SkMipMap* result;
    154     if (!SkResourceCache::Find(key, MipMapRec::Visitor, &result)) {
    155         result = NULL;
    156     }
    157     return result;
    158 }
    159 
    160 void SkMipMapCache::Add(const SkBitmap& src, const SkMipMap* result) {
    161     if (result) {
    162         SkResourceCache::Add(SkNEW_ARGS(MipMapRec, (src, result)));
    163     }
    164 }
    165 
    166