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
GetAllocator()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 */
get_bounds_from_bitmap(const SkBitmap & bm)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:
BitmapKeyBitmapKey33 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 {
BitmapRecBitmapRec51 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
getKeyBitmapRec60 virtual const Key& getKey() const SK_OVERRIDE { return fKey; }
bytesUsedBitmapRec61 virtual size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + fBitmap.getSize(); }
62
VisitorBitmapRec63 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
Find(const SkBitmap & src,SkScalar invScaleX,SkScalar invScaleY,SkBitmap * result,SkResourceCache * localCache)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
Add(const SkBitmap & src,SkScalar invScaleX,SkScalar invScaleY,const SkBitmap & result,SkResourceCache * localCache)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
Find(uint32_t genID,const SkIRect & subset,SkBitmap * result,SkResourceCache * localCache)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
Add(uint32_t genID,const SkIRect & subset,const SkBitmap & result,SkResourceCache * localCache)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 {
MipMapRecMipMapRec126 MipMapRec(const SkBitmap& src, const SkMipMap* result)
127 : fKey(src.getGenerationID(), 0, 0, get_bounds_from_bitmap(src))
128 , fMipMap(SkRef(result))
129 {}
130
~MipMapRecMipMapRec131 virtual ~MipMapRec() {
132 fMipMap->unref();
133 }
134
135 BitmapKey fKey;
136 const SkMipMap* fMipMap;
137
getKeyMipMapRec138 virtual const Key& getKey() const SK_OVERRIDE { return fKey; }
bytesUsedMipMapRec139 virtual size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + fMipMap->getSize(); }
140
VisitorMipMapRec141 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
FindAndRef(const SkBitmap & src)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
Add(const SkBitmap & src,const SkMipMap * result)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