• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 The Android Open Source Project
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 "SkImageFilter.h"
9 #include "SkImageFilterCacheKey.h"
10 
11 #include "SkBitmap.h"
12 #include "SkBitmapDevice.h"
13 #include "SkChecksum.h"
14 #include "SkDevice.h"
15 #include "SkLocalMatrixImageFilter.h"
16 #include "SkMatrixImageFilter.h"
17 #include "SkOncePtr.h"
18 #include "SkReadBuffer.h"
19 #include "SkRect.h"
20 #include "SkSpecialImage.h"
21 #include "SkTDynamicHash.h"
22 #include "SkTInternalLList.h"
23 #include "SkValidationUtils.h"
24 #include "SkWriteBuffer.h"
25 #if SK_SUPPORT_GPU
26 #include "GrContext.h"
27 #include "GrDrawContext.h"
28 #include "SkGrPixelRef.h"
29 #include "SkGr.h"
30 #endif
31 
32 #ifdef SK_BUILD_FOR_IOS
33   enum { kDefaultCacheSize = 2 * 1024 * 1024 };
34 #else
35   enum { kDefaultCacheSize = 128 * 1024 * 1024 };
36 #endif
37 
38 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const39 void SkImageFilter::CropRect::toString(SkString* str) const {
40     if (!fFlags) {
41         return;
42     }
43 
44     str->appendf("cropRect (");
45     if (fFlags & CropRect::kHasLeft_CropEdge) {
46         str->appendf("%.2f, ", fRect.fLeft);
47     } else {
48         str->appendf("X, ");
49     }
50     if (fFlags & CropRect::kHasTop_CropEdge) {
51         str->appendf("%.2f, ", fRect.fTop);
52     } else {
53         str->appendf("X, ");
54     }
55     if (fFlags & CropRect::kHasWidth_CropEdge) {
56         str->appendf("%.2f, ", fRect.width());
57     } else {
58         str->appendf("X, ");
59     }
60     if (fFlags & CropRect::kHasHeight_CropEdge) {
61         str->appendf("%.2f", fRect.height());
62     } else {
63         str->appendf("X");
64     }
65     str->appendf(") ");
66 }
67 #endif
68 
applyTo(const SkIRect & imageBounds,const SkMatrix & ctm,SkIRect * cropped) const69 void SkImageFilter::CropRect::applyTo(const SkIRect& imageBounds,
70                                       const SkMatrix& ctm,
71                                       SkIRect* cropped) const {
72     *cropped = imageBounds;
73     if (fFlags) {
74         SkRect devCropR;
75         ctm.mapRect(&devCropR, fRect);
76         const SkIRect devICropR = devCropR.roundOut();
77 
78         // Compute the left/top first, in case we have to read them to compute right/bottom
79         if (fFlags & kHasLeft_CropEdge) {
80             cropped->fLeft = devICropR.fLeft;
81         }
82         if (fFlags & kHasTop_CropEdge) {
83             cropped->fTop = devICropR.fTop;
84         }
85         if (fFlags & kHasWidth_CropEdge) {
86             cropped->fRight = cropped->fLeft + devICropR.width();
87         }
88         if (fFlags & kHasHeight_CropEdge) {
89             cropped->fBottom = cropped->fTop + devICropR.height();
90         }
91     }
92 }
93 
94 ///////////////////////////////////////////////////////////////////////////////////////////////////
95 
next_image_filter_unique_id()96 static int32_t next_image_filter_unique_id() {
97     static int32_t gImageFilterUniqueID;
98 
99     // Never return 0.
100     int32_t id;
101     do {
102         id = sk_atomic_inc(&gImageFilterUniqueID) + 1;
103     } while (0 == id);
104     return id;
105 }
106 
~Common()107 SkImageFilter::Common::~Common() {
108     for (int i = 0; i < fInputs.count(); ++i) {
109         SkSafeUnref(fInputs[i]);
110     }
111 }
112 
allocInputs(int count)113 void SkImageFilter::Common::allocInputs(int count) {
114     const size_t size = count * sizeof(SkImageFilter*);
115     fInputs.reset(count);
116     sk_bzero(fInputs.get(), size);
117 }
118 
detachInputs(SkImageFilter ** inputs)119 void SkImageFilter::Common::detachInputs(SkImageFilter** inputs) {
120     const size_t size = fInputs.count() * sizeof(SkImageFilter*);
121     memcpy(inputs, fInputs.get(), size);
122     sk_bzero(fInputs.get(), size);
123 }
124 
unflatten(SkReadBuffer & buffer,int expectedCount)125 bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) {
126     const int count = buffer.readInt();
127     if (!buffer.validate(count >= 0)) {
128         return false;
129     }
130     if (!buffer.validate(expectedCount < 0 || count == expectedCount)) {
131         return false;
132     }
133 
134     this->allocInputs(count);
135     for (int i = 0; i < count; i++) {
136         if (buffer.readBool()) {
137             fInputs[i] = buffer.readImageFilter();
138         }
139         if (!buffer.isValid()) {
140             return false;
141         }
142     }
143     SkRect rect;
144     buffer.readRect(&rect);
145     if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) {
146         return false;
147     }
148 
149     uint32_t flags = buffer.readUInt();
150     fCropRect = CropRect(rect, flags);
151     if (buffer.isVersionLT(SkReadBuffer::kImageFilterNoUniqueID_Version)) {
152 
153         (void) buffer.readUInt();
154     }
155     return buffer.isValid();
156 }
157 
158 ///////////////////////////////////////////////////////////////////////////////////////////////////
159 
SkImageFilter(int inputCount,SkImageFilter ** inputs,const CropRect * cropRect)160 SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
161   : fInputCount(inputCount),
162     fInputs(new SkImageFilter*[inputCount]),
163     fUsesSrcInput(false),
164     fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)),
165     fUniqueID(next_image_filter_unique_id()) {
166     for (int i = 0; i < inputCount; ++i) {
167         if (nullptr == inputs[i] || inputs[i]->usesSrcInput()) {
168             fUsesSrcInput = true;
169         }
170         fInputs[i] = inputs[i];
171         SkSafeRef(fInputs[i]);
172     }
173 }
174 
~SkImageFilter()175 SkImageFilter::~SkImageFilter() {
176     for (int i = 0; i < fInputCount; i++) {
177         SkSafeUnref(fInputs[i]);
178     }
179     delete[] fInputs;
180     Cache::Get()->purgeByKeys(fCacheKeys.begin(), fCacheKeys.count());
181 }
182 
SkImageFilter(int inputCount,SkReadBuffer & buffer)183 SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer)
184   : fUsesSrcInput(false)
185   , fUniqueID(next_image_filter_unique_id()) {
186     Common common;
187     if (common.unflatten(buffer, inputCount)) {
188         fCropRect = common.cropRect();
189         fInputCount = common.inputCount();
190         fInputs = new SkImageFilter* [fInputCount];
191         common.detachInputs(fInputs);
192         for (int i = 0; i < fInputCount; ++i) {
193             if (nullptr == fInputs[i] || fInputs[i]->usesSrcInput()) {
194                 fUsesSrcInput = true;
195             }
196         }
197     } else {
198         fInputCount = 0;
199         fInputs = nullptr;
200     }
201 }
202 
flatten(SkWriteBuffer & buffer) const203 void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
204     buffer.writeInt(fInputCount);
205     for (int i = 0; i < fInputCount; i++) {
206         SkImageFilter* input = this->getInput(i);
207         buffer.writeBool(input != nullptr);
208         if (input != nullptr) {
209             buffer.writeFlattenable(input);
210         }
211     }
212     buffer.writeRect(fCropRect.rect());
213     buffer.writeUInt(fCropRect.flags());
214 }
215 
filterImageDeprecated(Proxy * proxy,const SkBitmap & src,const Context & context,SkBitmap * result,SkIPoint * offset) const216 bool SkImageFilter::filterImageDeprecated(Proxy* proxy, const SkBitmap& src,
217                                           const Context& context,
218                                           SkBitmap* result, SkIPoint* offset) const {
219     SkASSERT(result);
220     SkASSERT(offset);
221     uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0;
222     Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(),
223                    srcGenID, SkIRect::MakeWH(0, 0));
224     if (context.cache()) {
225         if (context.cache()->get(key, result, offset)) {
226             return true;
227         }
228     }
229     /*
230      *  Give the proxy first shot at the filter. If it returns false, ask
231      *  the filter to do it.
232      */
233     if ((proxy && proxy->filterImage(this, src, context, result, offset)) ||
234         this->onFilterImageDeprecated(proxy, src, context, result, offset)) {
235         if (context.cache()) {
236             context.cache()->set(key, *result, *offset);
237             SkAutoMutexAcquire mutex(fMutex);
238             fCacheKeys.push_back(key);
239         }
240         return true;
241     }
242     return false;
243 }
244 
filterInputDeprecated(int index,Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const245 bool SkImageFilter::filterInputDeprecated(int index, Proxy* proxy, const SkBitmap& src,
246                                           const Context& ctx,
247                                           SkBitmap* result, SkIPoint* offset) const {
248     SkImageFilter* input = this->getInput(index);
249     if (!input) {
250         return true;
251     }
252     return input->filterImageDeprecated(proxy, src, this->mapContext(ctx), result, offset);
253 }
254 
filterBounds(const SkIRect & src,const SkMatrix & ctm,SkIRect * dst,MapDirection direction) const255 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst,
256                                  MapDirection direction) const {
257     SkASSERT(dst);
258     SkIRect bounds;
259     if (kReverse_MapDirection == direction) {
260         this->onFilterNodeBounds(src, ctm, &bounds, direction);
261         return this->onFilterBounds(bounds, ctm, dst, direction);
262     } else {
263         SkIRect temp;
264         if (!this->onFilterBounds(src, ctm, &bounds, direction)) {
265             return false;
266         }
267         this->onFilterNodeBounds(bounds, ctm, &temp, direction);
268         this->getCropRect().applyTo(temp, ctm, dst);
269         return true;
270     }
271 }
272 
computeFastBounds(const SkRect & src,SkRect * dst) const273 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
274     if (0 == fInputCount) {
275         *dst = src;
276         return;
277     }
278     if (this->getInput(0)) {
279         this->getInput(0)->computeFastBounds(src, dst);
280     } else {
281         *dst = src;
282     }
283     for (int i = 1; i < fInputCount; i++) {
284         SkImageFilter* input = this->getInput(i);
285         if (input) {
286             SkRect bounds;
287             input->computeFastBounds(src, &bounds);
288             dst->join(bounds);
289         } else {
290             dst->join(src);
291         }
292     }
293 }
294 
canComputeFastBounds() const295 bool SkImageFilter::canComputeFastBounds() const {
296     for (int i = 0; i < fInputCount; i++) {
297         SkImageFilter* input = this->getInput(i);
298         if (input && !input->canComputeFastBounds()) {
299             return false;
300         }
301     }
302     return true;
303 }
304 
onFilterImageDeprecated(Proxy *,const SkBitmap &,const Context &,SkBitmap *,SkIPoint *) const305 bool SkImageFilter::onFilterImageDeprecated(Proxy*, const SkBitmap&, const Context&,
306                                             SkBitmap*, SkIPoint*) const {
307     return false;
308 }
309 
canFilterImageGPU() const310 bool SkImageFilter::canFilterImageGPU() const {
311     return this->asFragmentProcessor(nullptr, nullptr, SkMatrix::I(), SkIRect());
312 }
313 
filterImageGPUDeprecated(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const314 bool SkImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx,
315                                              SkBitmap* result, SkIPoint* offset) const {
316 #if SK_SUPPORT_GPU
317     SkBitmap input = src;
318     SkASSERT(fInputCount == 1);
319     SkIPoint srcOffset = SkIPoint::Make(0, 0);
320     if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &input, &srcOffset)) {
321         return false;
322     }
323     GrTexture* srcTexture = input.getTexture();
324     SkIRect bounds;
325     if (!this->applyCropRectDeprecated(ctx, proxy, input, &srcOffset, &bounds, &input)) {
326         return false;
327     }
328     GrContext* context = srcTexture->getContext();
329 
330     GrSurfaceDesc desc;
331     desc.fFlags = kRenderTarget_GrSurfaceFlag,
332     desc.fWidth = bounds.width();
333     desc.fHeight = bounds.height();
334     desc.fConfig = kRGBA_8888_GrPixelConfig;
335 
336     SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
337     if (!dst) {
338         return false;
339     }
340 
341     GrFragmentProcessor* fp;
342     offset->fX = bounds.left();
343     offset->fY = bounds.top();
344     bounds.offset(-srcOffset);
345     SkMatrix matrix(ctx.ctm());
346     matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
347     GrPaint paint;
348     if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) {
349         SkASSERT(fp);
350         paint.addColorFragmentProcessor(fp)->unref();
351         paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
352 
353         SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
354         if (drawContext) {
355             SkRect srcRect = SkRect::Make(bounds);
356             SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
357             GrClip clip(dstRect);
358             drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
359 
360             GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result);
361             return true;
362         }
363     }
364 #endif
365     return false;
366 }
367 
asAColorFilter(SkColorFilter ** filterPtr) const368 bool SkImageFilter::asAColorFilter(SkColorFilter** filterPtr) const {
369     SkASSERT(nullptr != filterPtr);
370     if (!this->isColorFilterNode(filterPtr)) {
371         return false;
372     }
373     if (nullptr != this->getInput(0) || (*filterPtr)->affectsTransparentBlack()) {
374         (*filterPtr)->unref();
375         return false;
376     }
377     return true;
378 }
379 
applyCropRect(const Context & ctx,const SkIRect & srcBounds,SkIRect * dstBounds) const380 bool SkImageFilter::applyCropRect(const Context& ctx, const SkIRect& srcBounds,
381                                   SkIRect* dstBounds) const {
382     this->onFilterNodeBounds(srcBounds, ctx.ctm(), dstBounds, kForward_MapDirection);
383     fCropRect.applyTo(*dstBounds, ctx.ctm(), dstBounds);
384     // Intersect against the clip bounds, in case the crop rect has
385     // grown the bounds beyond the original clip. This can happen for
386     // example in tiling, where the clip is much smaller than the filtered
387     // primitive. If we didn't do this, we would be processing the filter
388     // at the full crop rect size in every tile.
389     return dstBounds->intersect(ctx.clipBounds());
390 }
391 
applyCropRectDeprecated(const Context & ctx,Proxy * proxy,const SkBitmap & src,SkIPoint * srcOffset,SkIRect * bounds,SkBitmap * dst) const392 bool SkImageFilter::applyCropRectDeprecated(const Context& ctx, Proxy* proxy, const SkBitmap& src,
393                                             SkIPoint* srcOffset, SkIRect* bounds,
394                                             SkBitmap* dst) const {
395     SkIRect srcBounds;
396     src.getBounds(&srcBounds);
397     srcBounds.offset(*srcOffset);
398     SkIRect dstBounds;
399     this->onFilterNodeBounds(srcBounds, ctx.ctm(), &dstBounds, kForward_MapDirection);
400     fCropRect.applyTo(dstBounds, ctx.ctm(), bounds);
401     if (!bounds->intersect(ctx.clipBounds())) {
402         return false;
403     }
404 
405     if (srcBounds.contains(*bounds)) {
406         *dst = src;
407         return true;
408     } else {
409         SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
410         if (!device) {
411             return false;
412         }
413         SkCanvas canvas(device);
414         canvas.clear(0x00000000);
415         canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y());
416         *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
417         *dst = device->accessBitmap(false);
418         return true;
419     }
420 }
421 
onFilterBounds(const SkIRect & src,const SkMatrix & ctm,SkIRect * dst,MapDirection direction) const422 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
423                                    SkIRect* dst, MapDirection direction) const {
424     if (fInputCount < 1) {
425         *dst = src;
426         return true;
427     }
428 
429     SkIRect totalBounds;
430     for (int i = 0; i < fInputCount; ++i) {
431         SkImageFilter* filter = this->getInput(i);
432         SkIRect rect = src;
433         if (filter && !filter->filterBounds(src, ctm, &rect, direction)) {
434             return false;
435         }
436         if (0 == i) {
437             totalBounds = rect;
438         } else {
439             totalBounds.join(rect);
440         }
441     }
442 
443     // don't modify dst until now, so we don't accidentally change it in the
444     // loop, but then return false on the next filter.
445     *dst = totalBounds;
446     return true;
447 }
448 
onFilterNodeBounds(const SkIRect & src,const SkMatrix &,SkIRect * dst,MapDirection) const449 void SkImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix&,
450                                        SkIRect* dst, MapDirection) const {
451     *dst = src;
452 }
453 
454 
mapContext(const Context & ctx) const455 SkImageFilter::Context SkImageFilter::mapContext(const Context& ctx) const {
456     SkIRect clipBounds;
457     this->onFilterNodeBounds(ctx.clipBounds(), ctx.ctm(), &clipBounds,
458                              MapDirection::kReverse_MapDirection);
459     return Context(ctx.ctm(), clipBounds, ctx.cache());
460 }
461 
asFragmentProcessor(GrFragmentProcessor **,GrTexture *,const SkMatrix &,const SkIRect &) const462 bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*,
463                                         const SkMatrix&, const SkIRect&) const {
464     return false;
465 }
466 
CreateMatrixFilter(const SkMatrix & matrix,SkFilterQuality filterQuality,SkImageFilter * input)467 SkImageFilter* SkImageFilter::CreateMatrixFilter(const SkMatrix& matrix,
468                                                  SkFilterQuality filterQuality,
469                                                  SkImageFilter* input) {
470     return SkMatrixImageFilter::Create(matrix, filterQuality, input);
471 }
472 
newWithLocalMatrix(const SkMatrix & matrix) const473 SkImageFilter* SkImageFilter::newWithLocalMatrix(const SkMatrix& matrix) const {
474     // SkLocalMatrixImageFilter takes SkImage* in its factory, but logically that parameter
475     // is *always* treated as a const ptr. Hence the const-cast here.
476     //
477     return SkLocalMatrixImageFilter::Create(matrix, const_cast<SkImageFilter*>(this));
478 }
479 
480 #if SK_SUPPORT_GPU
481 
filterInputGPUDeprecated(int index,SkImageFilter::Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const482 bool SkImageFilter::filterInputGPUDeprecated(int index, SkImageFilter::Proxy* proxy,
483                                              const SkBitmap& src, const Context& ctx,
484                                              SkBitmap* result, SkIPoint* offset) const {
485     SkImageFilter* input = this->getInput(index);
486     if (!input) {
487         return true;
488     }
489     // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity
490     // matrix with no clip and that the matrix, clip, and render target set before this function was
491     // called are restored before we return to the caller.
492     GrContext* context = src.getTexture()->getContext();
493     if (input->filterImageDeprecated(proxy, src, this->mapContext(ctx), result, offset)) {
494         if (!result->getTexture()) {
495             const SkImageInfo info = result->info();
496             if (kUnknown_SkColorType == info.colorType()) {
497                 return false;
498             }
499             SkAutoTUnref<GrTexture> resultTex(
500                 GrRefCachedBitmapTexture(context, *result, GrTextureParams::ClampNoFilter()));
501             if (!resultTex) {
502                 return false;
503             }
504             result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref();
505         }
506         return true;
507     } else {
508         return false;
509     }
510 }
511 #endif
512 
513 namespace {
514 
515 class CacheImpl : public SkImageFilter::Cache {
516 public:
CacheImpl(size_t maxBytes)517     CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { }
~CacheImpl()518     ~CacheImpl() override {
519         SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
520 
521         while (!iter.done()) {
522             Value* v = &*iter;
523             ++iter;
524             delete v;
525         }
526     }
527     struct Value {
Value__anonc1c06a500311::CacheImpl::Value528         Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
529             : fKey(key), fBitmap(bitmap), fOffset(offset) {}
Value__anonc1c06a500311::CacheImpl::Value530         Value(const Key& key, SkSpecialImage* image, const SkIPoint& offset)
531             : fKey(key), fImage(SkRef(image)), fOffset(offset) {}
532 
533         Key fKey;
534         SkBitmap fBitmap;
535         SkAutoTUnref<SkSpecialImage> fImage;
536         SkIPoint fOffset;
GetKey__anonc1c06a500311::CacheImpl::Value537         static const Key& GetKey(const Value& v) {
538             return v.fKey;
539         }
Hash__anonc1c06a500311::CacheImpl::Value540         static uint32_t Hash(const Key& key) {
541             return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
542         }
543         SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
544     };
545 
get(const Key & key,SkBitmap * result,SkIPoint * offset) const546     bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const override {
547         SkAutoMutexAcquire mutex(fMutex);
548         if (Value* v = fLookup.find(key)) {
549             *result = v->fBitmap;
550             *offset = v->fOffset;
551             if (v != fLRU.head()) {
552                 fLRU.remove(v);
553                 fLRU.addToHead(v);
554             }
555             return true;
556         }
557         return false;
558     }
559 
get(const Key & key,SkIPoint * offset) const560     SkSpecialImage* get(const Key& key, SkIPoint* offset) const override {
561         SkAutoMutexAcquire mutex(fMutex);
562         if (Value* v = fLookup.find(key)) {
563             *offset = v->fOffset;
564             if (v != fLRU.head()) {
565                 fLRU.remove(v);
566                 fLRU.addToHead(v);
567             }
568             return v->fImage;
569         }
570         return nullptr;
571     }
572 
set(const Key & key,const SkBitmap & result,const SkIPoint & offset)573     void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) override {
574         SkAutoMutexAcquire mutex(fMutex);
575         if (Value* v = fLookup.find(key)) {
576             this->removeInternal(v);
577         }
578         Value* v = new Value(key, result, offset);
579         fLookup.add(v);
580         fLRU.addToHead(v);
581         fCurrentBytes += result.getSize();
582         while (fCurrentBytes > fMaxBytes) {
583             Value* tail = fLRU.tail();
584             SkASSERT(tail);
585             if (tail == v) {
586                 break;
587             }
588             this->removeInternal(tail);
589         }
590     }
591 
set(const Key & key,SkSpecialImage * image,const SkIPoint & offset)592     void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset) override {
593         SkAutoMutexAcquire mutex(fMutex);
594         if (Value* v = fLookup.find(key)) {
595             this->removeInternal(v);
596         }
597         Value* v = new Value(key, image, offset);
598         fLookup.add(v);
599         fLRU.addToHead(v);
600         fCurrentBytes += image->getSize();
601         while (fCurrentBytes > fMaxBytes) {
602             Value* tail = fLRU.tail();
603             SkASSERT(tail);
604             if (tail == v) {
605                 break;
606             }
607             this->removeInternal(tail);
608         }
609     }
610 
purge()611     void purge() override {
612         SkAutoMutexAcquire mutex(fMutex);
613         while (fCurrentBytes > 0) {
614             Value* tail = fLRU.tail();
615             SkASSERT(tail);
616             this->removeInternal(tail);
617         }
618     }
619 
purgeByKeys(const Key keys[],int count)620     void purgeByKeys(const Key keys[], int count) override {
621         SkAutoMutexAcquire mutex(fMutex);
622         for (int i = 0; i < count; i++) {
623             if (Value* v = fLookup.find(keys[i])) {
624                 this->removeInternal(v);
625             }
626         }
627     }
628 
629 private:
removeInternal(Value * v)630     void removeInternal(Value* v) {
631         if (v->fImage) {
632             fCurrentBytes -= v->fImage->getSize();
633         } else {
634             fCurrentBytes -= v->fBitmap.getSize();
635         }
636         fLRU.remove(v);
637         fLookup.remove(v->fKey);
638         delete v;
639     }
640 private:
641     SkTDynamicHash<Value, Key>            fLookup;
642     mutable SkTInternalLList<Value>       fLRU;
643     size_t                                fMaxBytes;
644     size_t                                fCurrentBytes;
645     mutable SkMutex                       fMutex;
646 };
647 
648 } // namespace
649 
Create(size_t maxBytes)650 SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
651     return new CacheImpl(maxBytes);
652 }
653 
654 SK_DECLARE_STATIC_ONCE_PTR(SkImageFilter::Cache, cache);
Get()655 SkImageFilter::Cache* SkImageFilter::Cache::Get() {
656     return cache.get([]{ return SkImageFilter::Cache::Create(kDefaultCacheSize); });
657 }
658 
PurgeCache()659 void SkImageFilter::PurgeCache() {
660     Cache::Get()->purge();
661 }
662 
663 ///////////////////////////////////////////////////////////////////////////////////////////////////
664 
createDevice(int w,int h,TileUsage usage)665 SkBaseDevice* SkImageFilter::DeviceProxy::createDevice(int w, int h, TileUsage usage) {
666     SkBaseDevice::CreateInfo cinfo(SkImageInfo::MakeN32Premul(w, h),
667                                    kPossible_TileUsage == usage ? SkBaseDevice::kPossible_TileUsage
668                                                                 : SkBaseDevice::kNever_TileUsage,
669                                    kUnknown_SkPixelGeometry,
670                                    false,   /* preserveLCDText */
671                                    true /*forImageFilter*/);
672     SkBaseDevice* dev = fDevice->onCreateDevice(cinfo, nullptr);
673     if (nullptr == dev) {
674         const SkSurfaceProps surfaceProps(fDevice->fSurfaceProps.flags(),
675                                           kUnknown_SkPixelGeometry);
676         dev = SkBitmapDevice::Create(cinfo.fInfo, surfaceProps);
677     }
678     return dev;
679 }
680 
filterImage(const SkImageFilter * filter,const SkBitmap & src,const SkImageFilter::Context & ctx,SkBitmap * result,SkIPoint * offset)681 bool SkImageFilter::DeviceProxy::filterImage(const SkImageFilter* filter, const SkBitmap& src,
682                                        const SkImageFilter::Context& ctx,
683                                        SkBitmap* result, SkIPoint* offset) {
684     return fDevice->filterImage(filter, src, ctx, result, offset);
685 }
686 
687