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__anon640ca2140311::CacheImpl::Value528 Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
529 : fKey(key), fBitmap(bitmap), fOffset(offset) {}
Value__anon640ca2140311::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__anon640ca2140311::CacheImpl::Value537 static const Key& GetKey(const Value& v) {
538 return v.fKey;
539 }
Hash__anon640ca2140311::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