blob: 3b4ad314563217ded15baa1756d36f63ce7aa960 [file] [log] [blame]
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +00001/*
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"
robertphillipsdf7bb472016-02-19 08:19:40 -08009#include "SkImageFilterCacheKey.h"
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +000010
11#include "SkBitmap.h"
robertphillips9a53fd72015-06-22 09:46:59 -070012#include "SkBitmapDevice.h"
mtklein19fcc742014-07-11 08:42:17 -070013#include "SkChecksum.h"
senorblanco@chromium.org11825292014-03-14 17:44:41 +000014#include "SkDevice.h"
senorblanco20311d42015-10-14 04:53:31 -070015#include "SkLocalMatrixImageFilter.h"
senorblanco8c874ee2015-03-20 06:38:17 -070016#include "SkMatrixImageFilter.h"
mtklein6c59d802015-09-09 09:09:53 -070017#include "SkOncePtr.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000018#include "SkReadBuffer.h"
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000019#include "SkRect.h"
robertphillipsdf7bb472016-02-19 08:19:40 -080020#include "SkSpecialImage.h"
robertphillipseaf086e2016-03-07 04:51:10 -080021#include "SkSpecialSurface.h"
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +000022#include "SkTDynamicHash.h"
senorblanco55b6d8b2014-07-30 11:26:46 -070023#include "SkTInternalLList.h"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000024#include "SkValidationUtils.h"
mtklein1b249332015-07-07 12:21:21 -070025#include "SkWriteBuffer.h"
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +000026#if SK_SUPPORT_GPU
27#include "GrContext.h"
robertphillipsea461502015-05-26 11:38:03 -070028#include "GrDrawContext.h"
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +000029#include "SkGrPixelRef.h"
30#include "SkGr.h"
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +000031#endif
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000032
mtklein242397a2015-09-29 12:17:08 -070033#ifdef SK_BUILD_FOR_IOS
34 enum { kDefaultCacheSize = 2 * 1024 * 1024 };
35#else
36 enum { kDefaultCacheSize = 128 * 1024 * 1024 };
37#endif
38
reed18918632015-07-16 13:17:13 -070039#ifndef SK_IGNORE_TO_STRING
40void SkImageFilter::CropRect::toString(SkString* str) const {
41 if (!fFlags) {
42 return;
43 }
44
45 str->appendf("cropRect (");
46 if (fFlags & CropRect::kHasLeft_CropEdge) {
47 str->appendf("%.2f, ", fRect.fLeft);
48 } else {
49 str->appendf("X, ");
50 }
51 if (fFlags & CropRect::kHasTop_CropEdge) {
52 str->appendf("%.2f, ", fRect.fTop);
53 } else {
54 str->appendf("X, ");
55 }
senorblancoed7cf272015-07-16 15:19:11 -070056 if (fFlags & CropRect::kHasWidth_CropEdge) {
57 str->appendf("%.2f, ", fRect.width());
reed18918632015-07-16 13:17:13 -070058 } else {
59 str->appendf("X, ");
60 }
senorblancoed7cf272015-07-16 15:19:11 -070061 if (fFlags & CropRect::kHasHeight_CropEdge) {
62 str->appendf("%.2f", fRect.height());
reed18918632015-07-16 13:17:13 -070063 } else {
64 str->appendf("X");
65 }
66 str->appendf(") ");
67}
68#endif
69
senorblancod8ff5b32016-01-28 08:23:02 -080070void SkImageFilter::CropRect::applyTo(const SkIRect& imageBounds,
71 const SkMatrix& ctm,
reed18918632015-07-16 13:17:13 -070072 SkIRect* cropped) const {
73 *cropped = imageBounds;
74 if (fFlags) {
75 SkRect devCropR;
senorblancod8ff5b32016-01-28 08:23:02 -080076 ctm.mapRect(&devCropR, fRect);
reed18918632015-07-16 13:17:13 -070077 const SkIRect devICropR = devCropR.roundOut();
78
79 // Compute the left/top first, in case we have to read them to compute right/bottom
80 if (fFlags & kHasLeft_CropEdge) {
81 cropped->fLeft = devICropR.fLeft;
82 }
83 if (fFlags & kHasTop_CropEdge) {
84 cropped->fTop = devICropR.fTop;
85 }
senorblancoed7cf272015-07-16 15:19:11 -070086 if (fFlags & kHasWidth_CropEdge) {
reed18918632015-07-16 13:17:13 -070087 cropped->fRight = cropped->fLeft + devICropR.width();
88 }
senorblancoed7cf272015-07-16 15:19:11 -070089 if (fFlags & kHasHeight_CropEdge) {
reed18918632015-07-16 13:17:13 -070090 cropped->fBottom = cropped->fTop + devICropR.height();
91 }
92 }
reed18918632015-07-16 13:17:13 -070093}
94
95///////////////////////////////////////////////////////////////////////////////////////////////////
96
senorblanco55b6d8b2014-07-30 11:26:46 -070097static int32_t next_image_filter_unique_id() {
98 static int32_t gImageFilterUniqueID;
99
100 // Never return 0.
101 int32_t id;
102 do {
103 id = sk_atomic_inc(&gImageFilterUniqueID) + 1;
104 } while (0 == id);
105 return id;
106}
107
reedb959ec72014-07-17 07:03:09 -0700108void SkImageFilter::Common::allocInputs(int count) {
reedb959ec72014-07-17 07:03:09 -0700109 fInputs.reset(count);
reedb959ec72014-07-17 07:03:09 -0700110}
111
112void SkImageFilter::Common::detachInputs(SkImageFilter** inputs) {
robertphillips2238c9d2016-03-30 13:34:16 -0700113 for (int i = 0; i < fInputs.count(); ++i) {
114 inputs[i] = fInputs[i].release();
115 }
reedb959ec72014-07-17 07:03:09 -0700116}
117
118bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) {
reed9fa60da2014-08-21 07:59:51 -0700119 const int count = buffer.readInt();
120 if (!buffer.validate(count >= 0)) {
121 return false;
reedb959ec72014-07-17 07:03:09 -0700122 }
reed9fa60da2014-08-21 07:59:51 -0700123 if (!buffer.validate(expectedCount < 0 || count == expectedCount)) {
reedb959ec72014-07-17 07:03:09 -0700124 return false;
125 }
126
127 this->allocInputs(count);
128 for (int i = 0; i < count; i++) {
129 if (buffer.readBool()) {
robertphillips2238c9d2016-03-30 13:34:16 -0700130 fInputs[i] = sk_sp<SkImageFilter>(buffer.readImageFilter());
reedb959ec72014-07-17 07:03:09 -0700131 }
132 if (!buffer.isValid()) {
133 return false;
134 }
135 }
136 SkRect rect;
137 buffer.readRect(&rect);
138 if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) {
139 return false;
140 }
mtklein148ec592014-10-13 13:17:56 -0700141
reedb959ec72014-07-17 07:03:09 -0700142 uint32_t flags = buffer.readUInt();
143 fCropRect = CropRect(rect, flags);
senorblanco4a22a432015-03-18 13:14:54 -0700144 if (buffer.isVersionLT(SkReadBuffer::kImageFilterNoUniqueID_Version)) {
145
146 (void) buffer.readUInt();
147 }
reedb959ec72014-07-17 07:03:09 -0700148 return buffer.isValid();
149}
150
151///////////////////////////////////////////////////////////////////////////////////////////////////
152
robertphillips372177e2016-03-30 07:32:28 -0700153SkImageFilter::SkImageFilter(sk_sp<SkImageFilter>* inputs,
154 int inputCount,
155 const CropRect* cropRect)
156 : fInputCount(inputCount),
157 fInputs(new SkImageFilter*[inputCount]),
158 fUsesSrcInput(false),
159 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)),
160 fUniqueID(next_image_filter_unique_id()) {
161 for (int i = 0; i < inputCount; ++i) {
162 if (nullptr == inputs[i] || inputs[i]->usesSrcInput()) {
163 fUsesSrcInput = true;
164 }
165 fInputs[i] = SkSafeRef(inputs[i].get());
166 }
167}
168
senorblanco24e06d52015-03-18 12:11:33 -0700169SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000170 : fInputCount(inputCount),
171 fInputs(new SkImageFilter*[inputCount]),
senorblanco55b6d8b2014-07-30 11:26:46 -0700172 fUsesSrcInput(false),
173 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)),
senorblanco24e06d52015-03-18 12:11:33 -0700174 fUniqueID(next_image_filter_unique_id()) {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000175 for (int i = 0; i < inputCount; ++i) {
halcanary96fcdcc2015-08-27 07:41:13 -0700176 if (nullptr == inputs[i] || inputs[i]->usesSrcInput()) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700177 fUsesSrcInput = true;
178 }
robertphillips372177e2016-03-30 07:32:28 -0700179 fInputs[i] = SkSafeRef(inputs[i]);
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000180 }
181}
182
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000183SkImageFilter::~SkImageFilter() {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000184 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000185 SkSafeUnref(fInputs[i]);
186 }
187 delete[] fInputs;
xidachen23526962016-02-01 05:27:16 -0800188 Cache::Get()->purgeByKeys(fCacheKeys.begin(), fCacheKeys.count());
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000189}
190
senorblanco55b6d8b2014-07-30 11:26:46 -0700191SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer)
senorblanco24e06d52015-03-18 12:11:33 -0700192 : fUsesSrcInput(false)
193 , fUniqueID(next_image_filter_unique_id()) {
reedb959ec72014-07-17 07:03:09 -0700194 Common common;
195 if (common.unflatten(buffer, inputCount)) {
196 fCropRect = common.cropRect();
197 fInputCount = common.inputCount();
halcanary385fe4d2015-08-26 13:07:48 -0700198 fInputs = new SkImageFilter* [fInputCount];
reedb959ec72014-07-17 07:03:09 -0700199 common.detachInputs(fInputs);
senorblanco55b6d8b2014-07-30 11:26:46 -0700200 for (int i = 0; i < fInputCount; ++i) {
halcanary96fcdcc2015-08-27 07:41:13 -0700201 if (nullptr == fInputs[i] || fInputs[i]->usesSrcInput()) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700202 fUsesSrcInput = true;
203 }
204 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000205 } else {
206 fInputCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700207 fInputs = nullptr;
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000208 }
209}
210
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000211void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000212 buffer.writeInt(fInputCount);
213 for (int i = 0; i < fInputCount; i++) {
senorblancob9519f82015-10-15 12:15:13 -0700214 SkImageFilter* input = this->getInput(i);
halcanary96fcdcc2015-08-27 07:41:13 -0700215 buffer.writeBool(input != nullptr);
216 if (input != nullptr) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000217 buffer.writeFlattenable(input);
218 }
219 }
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000220 buffer.writeRect(fCropRect.rect());
221 buffer.writeUInt(fCropRect.flags());
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000222}
223
robertphillips2302de92016-03-24 07:26:32 -0700224sk_sp<SkSpecialImage> SkImageFilter::filterImage(SkSpecialImage* src, const Context& context,
225 SkIPoint* offset) const {
robertphillipseaf086e2016-03-07 04:51:10 -0800226 SkASSERT(src && offset);
227
228 uint32_t srcGenID = fUsesSrcInput ? src->uniqueID() : 0;
229 const SkIRect srcSubset = fUsesSrcInput ? src->subset() : SkIRect::MakeWH(0, 0);
230 Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID, srcSubset);
231 if (context.cache()) {
232 SkSpecialImage* result = context.cache()->get(key, offset);
233 if (result) {
robertphillips2302de92016-03-24 07:26:32 -0700234 return sk_sp<SkSpecialImage>(SkRef(result));
robertphillipseaf086e2016-03-07 04:51:10 -0800235 }
236 }
237
robertphillips2302de92016-03-24 07:26:32 -0700238 sk_sp<SkSpecialImage> result(this->onFilterImage(src, context, offset));
robertphillipseaf086e2016-03-07 04:51:10 -0800239 if (result && context.cache()) {
robertphillips2302de92016-03-24 07:26:32 -0700240 context.cache()->set(key, result.get(), *offset);
robertphillipsbd590aa2016-03-08 08:37:18 -0800241 SkAutoMutexAcquire mutex(fMutex);
242 fCacheKeys.push_back(key);
robertphillipseaf086e2016-03-07 04:51:10 -0800243 }
244
245 return result;
246}
247
robertphillips48e78462016-02-17 13:57:16 -0800248bool SkImageFilter::filterImageDeprecated(Proxy* proxy, const SkBitmap& src,
249 const Context& context,
250 SkBitmap* result, SkIPoint* offset) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000251 SkASSERT(result);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000252 SkASSERT(offset);
senorblanco55b6d8b2014-07-30 11:26:46 -0700253 uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0;
robertphillipsdf7bb472016-02-19 08:19:40 -0800254 Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(),
255 srcGenID, SkIRect::MakeWH(0, 0));
senorblancobe129b22014-08-08 07:14:35 -0700256 if (context.cache()) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700257 if (context.cache()->get(key, result, offset)) {
258 return true;
259 }
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000260 }
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000261 /*
262 * Give the proxy first shot at the filter. If it returns false, ask
263 * the filter to do it.
264 */
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000265 if ((proxy && proxy->filterImage(this, src, context, result, offset)) ||
robertphillips48e78462016-02-17 13:57:16 -0800266 this->onFilterImageDeprecated(proxy, src, context, result, offset)) {
senorblancobe129b22014-08-08 07:14:35 -0700267 if (context.cache()) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700268 context.cache()->set(key, *result, *offset);
xidachen23526962016-02-01 05:27:16 -0800269 SkAutoMutexAcquire mutex(fMutex);
270 fCacheKeys.push_back(key);
senorblanco55b6d8b2014-07-30 11:26:46 -0700271 }
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000272 return true;
273 }
274 return false;
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000275}
276
robertphillips48e78462016-02-17 13:57:16 -0800277bool SkImageFilter::filterInputDeprecated(int index, Proxy* proxy, const SkBitmap& src,
278 const Context& ctx,
279 SkBitmap* result, SkIPoint* offset) const {
senorblancob9519f82015-10-15 12:15:13 -0700280 SkImageFilter* input = this->getInput(index);
reedc9b5f8b2015-10-22 13:20:20 -0700281 if (!input) {
282 return true;
283 }
robertphillips4418dba2016-03-07 12:45:14 -0800284
robertphillips37bd7c32016-03-17 14:31:39 -0700285 sk_sp<SkSpecialImage> specialSrc(SkSpecialImage::internal_fromBM(proxy, src));
robertphillips4418dba2016-03-07 12:45:14 -0800286 if (!specialSrc) {
287 return false;
288 }
289
robertphillips2302de92016-03-24 07:26:32 -0700290 sk_sp<SkSpecialImage> tmp(input->onFilterImage(specialSrc.get(),
291 this->mapContext(ctx),
292 offset));
robertphillips4418dba2016-03-07 12:45:14 -0800293 if (!tmp) {
294 return false;
295 }
296
297 return tmp->internal_getBM(result);
senorblancob9519f82015-10-15 12:15:13 -0700298}
299
senorblancoe5e79842016-03-21 14:51:59 -0700300SkIRect SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
301 MapDirection direction) const {
senorblancod8ff5b32016-01-28 08:23:02 -0800302 if (kReverse_MapDirection == direction) {
senorblancoe5e79842016-03-21 14:51:59 -0700303 SkIRect bounds = this->onFilterNodeBounds(src, ctm, direction);
304 return this->onFilterBounds(bounds, ctm, direction);
senorblancod8ff5b32016-01-28 08:23:02 -0800305 } else {
senorblancoe5e79842016-03-21 14:51:59 -0700306 SkIRect bounds = this->onFilterBounds(src, ctm, direction);
307 bounds = this->onFilterNodeBounds(bounds, ctm, direction);
308 SkIRect dst;
309 this->getCropRect().applyTo(bounds, ctm, &dst);
310 return dst;
senorblancod8ff5b32016-01-28 08:23:02 -0800311 }
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000312}
313
senorblancoe5e79842016-03-21 14:51:59 -0700314SkRect SkImageFilter::computeFastBounds(const SkRect& src) const {
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000315 if (0 == fInputCount) {
senorblancoe5e79842016-03-21 14:51:59 -0700316 return src;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000317 }
senorblancoe5e79842016-03-21 14:51:59 -0700318 SkRect combinedBounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000319 for (int i = 1; i < fInputCount; i++) {
320 SkImageFilter* input = this->getInput(i);
321 if (input) {
senorblancoe5e79842016-03-21 14:51:59 -0700322 combinedBounds.join(input->computeFastBounds(src));
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000323 } else {
jbroman0e3129d2016-03-17 12:24:23 -0700324 combinedBounds.join(src);
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000325 }
326 }
senorblancoe5e79842016-03-21 14:51:59 -0700327 return combinedBounds;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000328}
329
senorblanco0abdf762015-08-20 11:10:41 -0700330bool SkImageFilter::canComputeFastBounds() const {
senorblanco0abdf762015-08-20 11:10:41 -0700331 for (int i = 0; i < fInputCount; i++) {
332 SkImageFilter* input = this->getInput(i);
333 if (input && !input->canComputeFastBounds()) {
334 return false;
335 }
336 }
337 return true;
338}
339
robertphillips48e78462016-02-17 13:57:16 -0800340bool SkImageFilter::onFilterImageDeprecated(Proxy*, const SkBitmap&, const Context&,
341 SkBitmap*, SkIPoint*) const {
robertphillips4418dba2016-03-07 12:45:14 -0800342 // Only classes that now use the new SkSpecialImage-based path will not have
343 // onFilterImageDeprecated methods. For those classes we should never be
344 // calling this method.
345 SkASSERT(0);
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000346 return false;
347}
348
robertphillips4418dba2016-03-07 12:45:14 -0800349// SkImageFilter-derived classes that do not yet have their own onFilterImage
350// implementation convert back to calling the deprecated filterImage method
robertphillips2302de92016-03-24 07:26:32 -0700351sk_sp<SkSpecialImage> SkImageFilter::onFilterImage(SkSpecialImage* src, const Context& ctx,
352 SkIPoint* offset) const {
robertphillipseaf086e2016-03-07 04:51:10 -0800353 SkBitmap srcBM, resultBM;
354
355 if (!src->internal_getBM(&srcBM)) {
356 return nullptr;
357 }
358
robertphillips4418dba2016-03-07 12:45:14 -0800359 // This is the only valid call to the old filterImage path
robertphillipseaf086e2016-03-07 04:51:10 -0800360 if (!this->filterImageDeprecated(src->internal_getProxy(), srcBM, ctx, &resultBM, offset)) {
361 return nullptr;
362 }
363
robertphillips2302de92016-03-24 07:26:32 -0700364 return SkSpecialImage::internal_fromBM(src->internal_getProxy(), resultBM);
robertphillipseaf086e2016-03-07 04:51:10 -0800365}
366
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000367bool SkImageFilter::canFilterImageGPU() const {
bsalomon4a339522015-10-06 08:40:50 -0700368 return this->asFragmentProcessor(nullptr, nullptr, SkMatrix::I(), SkIRect());
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000369}
370
robertphillips48e78462016-02-17 13:57:16 -0800371bool SkImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx,
372 SkBitmap* result, SkIPoint* offset) const {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000373#if SK_SUPPORT_GPU
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000374 SkBitmap input = src;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000375 SkASSERT(fInputCount == 1);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000376 SkIPoint srcOffset = SkIPoint::Make(0, 0);
robertphillips48e78462016-02-17 13:57:16 -0800377 if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &input, &srcOffset)) {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000378 return false;
379 }
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000380 GrTexture* srcTexture = input.getTexture();
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000381 SkIRect bounds;
robertphillips48e78462016-02-17 13:57:16 -0800382 if (!this->applyCropRectDeprecated(ctx, proxy, input, &srcOffset, &bounds, &input)) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000383 return false;
384 }
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000385 GrContext* context = srcTexture->getContext();
386
bsalomonf2703d82014-10-28 14:33:06 -0700387 GrSurfaceDesc desc;
388 desc.fFlags = kRenderTarget_GrSurfaceFlag,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000389 desc.fWidth = bounds.width();
390 desc.fHeight = bounds.height();
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000391 desc.fConfig = kRGBA_8888_GrPixelConfig;
392
reed4e23cda2016-01-11 10:56:59 -0800393 SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc));
bsalomone3059732014-10-14 11:47:22 -0700394 if (!dst) {
senorblanco673d9732014-08-15 10:48:43 -0700395 return false;
396 }
joshualitt25d9c152015-02-18 12:29:52 -0800397
joshualittb0a8a372014-09-23 09:50:21 -0700398 GrFragmentProcessor* fp;
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000399 offset->fX = bounds.left();
400 offset->fY = bounds.top();
401 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000402 SkMatrix matrix(ctx.ctm());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000403 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
joshualitt85ff25e2015-07-08 09:10:03 -0700404 GrPaint paint;
bsalomon4a339522015-10-06 08:40:50 -0700405 if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) {
bsalomonb501ecd2014-10-14 08:40:57 -0700406 SkASSERT(fp);
bsalomonac856c92015-08-27 06:30:17 -0700407 paint.addColorFragmentProcessor(fp)->unref();
egdanielc4b72722015-11-23 13:20:41 -0800408 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000409
robertphillips2e1e51f2015-10-15 08:01:48 -0700410 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700411 if (drawContext) {
senorblancoeae84c22016-01-26 08:41:02 -0800412 SkRect srcRect = SkRect::Make(bounds);
413 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
414 GrClip clip(dstRect);
bsalomona2e69fc2015-11-05 10:41:43 -0800415 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
robertphillipsea461502015-05-26 11:38:03 -0700416
robertphillips1de87df2016-01-14 06:03:29 -0800417 GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result);
robertphillipsea461502015-05-26 11:38:03 -0700418 return true;
419 }
bsalomonb501ecd2014-10-14 08:40:57 -0700420 }
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000421#endif
bsalomonb501ecd2014-10-14 08:40:57 -0700422 return false;
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000423}
424
senorblancoa544eda2015-12-07 07:48:34 -0800425bool SkImageFilter::asAColorFilter(SkColorFilter** filterPtr) const {
426 SkASSERT(nullptr != filterPtr);
427 if (!this->isColorFilterNode(filterPtr)) {
428 return false;
429 }
430 if (nullptr != this->getInput(0) || (*filterPtr)->affectsTransparentBlack()) {
431 (*filterPtr)->unref();
432 return false;
433 }
434 return true;
435}
436
senorblancoafec27f2016-02-16 09:11:18 -0800437bool SkImageFilter::applyCropRect(const Context& ctx, const SkIRect& srcBounds,
438 SkIRect* dstBounds) const {
senorblancoe5e79842016-03-21 14:51:59 -0700439 SkIRect temp = this->onFilterNodeBounds(srcBounds, ctx.ctm(), kForward_MapDirection);
440 fCropRect.applyTo(temp, ctx.ctm(), dstBounds);
senorblancod8ff5b32016-01-28 08:23:02 -0800441 // Intersect against the clip bounds, in case the crop rect has
442 // grown the bounds beyond the original clip. This can happen for
443 // example in tiling, where the clip is much smaller than the filtered
444 // primitive. If we didn't do this, we would be processing the filter
445 // at the full crop rect size in every tile.
446 return dstBounds->intersect(ctx.clipBounds());
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000447}
448
robertphillips48e78462016-02-17 13:57:16 -0800449bool SkImageFilter::applyCropRectDeprecated(const Context& ctx, Proxy* proxy, const SkBitmap& src,
450 SkIPoint* srcOffset, SkIRect* bounds,
451 SkBitmap* dst) const {
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000452 SkIRect srcBounds;
453 src.getBounds(&srcBounds);
454 srcBounds.offset(*srcOffset);
senorblancoe5e79842016-03-21 14:51:59 -0700455 SkIRect dstBounds = this->onFilterNodeBounds(srcBounds, ctx.ctm(), kForward_MapDirection);
senorblancod8ff5b32016-01-28 08:23:02 -0800456 fCropRect.applyTo(dstBounds, ctx.ctm(), bounds);
457 if (!bounds->intersect(ctx.clipBounds())) {
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000458 return false;
459 }
reed18918632015-07-16 13:17:13 -0700460
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000461 if (srcBounds.contains(*bounds)) {
462 *dst = src;
463 return true;
464 } else {
465 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
466 if (!device) {
467 return false;
468 }
469 SkCanvas canvas(device);
470 canvas.clear(0x00000000);
471 canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y());
472 *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
473 *dst = device->accessBitmap(false);
474 return true;
475 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000476}
477
robertphillipseaf086e2016-03-07 04:51:10 -0800478// Return a larger (newWidth x newHeight) copy of 'src' with black padding
479// around it.
robertphillips37bd7c32016-03-17 14:31:39 -0700480static sk_sp<SkSpecialImage> pad_image(SkSpecialImage* src,
481 int newWidth, int newHeight, int offX, int offY) {
robertphillipseaf086e2016-03-07 04:51:10 -0800482
483 SkImageInfo info = SkImageInfo::MakeN32Premul(newWidth, newHeight);
robertphillips37bd7c32016-03-17 14:31:39 -0700484 sk_sp<SkSpecialSurface> surf(src->makeSurface(info));
robertphillipseaf086e2016-03-07 04:51:10 -0800485 if (!surf) {
486 return nullptr;
487 }
488
489 SkCanvas* canvas = surf->getCanvas();
490 SkASSERT(canvas);
491
492 canvas->clear(0x0);
493
494 src->draw(canvas, offX, offY, nullptr);
495
robertphillips37bd7c32016-03-17 14:31:39 -0700496 return surf->makeImageSnapshot();
robertphillipseaf086e2016-03-07 04:51:10 -0800497}
498
robertphillips2302de92016-03-24 07:26:32 -0700499sk_sp<SkSpecialImage> SkImageFilter::applyCropRect(const Context& ctx,
500 SkSpecialImage* src,
501 SkIPoint* srcOffset,
502 SkIRect* bounds) const {
robertphillipseaf086e2016-03-07 04:51:10 -0800503 SkIRect srcBounds;
504 srcBounds = SkIRect::MakeXYWH(srcOffset->fX, srcOffset->fY, src->width(), src->height());
505
senorblancoe5e79842016-03-21 14:51:59 -0700506 SkIRect dstBounds = this->onFilterNodeBounds(srcBounds, ctx.ctm(), kForward_MapDirection);
robertphillipseaf086e2016-03-07 04:51:10 -0800507 fCropRect.applyTo(dstBounds, ctx.ctm(), bounds);
508 if (!bounds->intersect(ctx.clipBounds())) {
509 return nullptr;
510 }
511
512 if (srcBounds.contains(*bounds)) {
robertphillips2302de92016-03-24 07:26:32 -0700513 return sk_sp<SkSpecialImage>(SkRef(src));
robertphillipseaf086e2016-03-07 04:51:10 -0800514 } else {
robertphillips37bd7c32016-03-17 14:31:39 -0700515 sk_sp<SkSpecialImage> img(pad_image(src,
516 bounds->width(), bounds->height(),
517 srcOffset->x() - bounds->x(),
518 srcOffset->y() - bounds->y()));
robertphillipseaf086e2016-03-07 04:51:10 -0800519 *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
robertphillips2302de92016-03-24 07:26:32 -0700520 return img;
robertphillipseaf086e2016-03-07 04:51:10 -0800521 }
522}
523
senorblancoe5e79842016-03-21 14:51:59 -0700524SkIRect SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
525 MapDirection direction) const {
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000526 if (fInputCount < 1) {
senorblancoe5e79842016-03-21 14:51:59 -0700527 return src;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000528 }
529
senorblancod8ff5b32016-01-28 08:23:02 -0800530 SkIRect totalBounds;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000531 for (int i = 0; i < fInputCount; ++i) {
532 SkImageFilter* filter = this->getInput(i);
senorblancoe5e79842016-03-21 14:51:59 -0700533 SkIRect rect = filter ? filter->filterBounds(src, ctm, direction) : src;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000534 if (0 == i) {
senorblancodb64af32015-12-09 10:11:43 -0800535 totalBounds = rect;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000536 } else {
senorblancodb64af32015-12-09 10:11:43 -0800537 totalBounds.join(rect);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000538 }
539 }
540
senorblancoe5e79842016-03-21 14:51:59 -0700541 return totalBounds;
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000542}
543
senorblancoe5e79842016-03-21 14:51:59 -0700544SkIRect SkImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix&, MapDirection) const {
545 return src;
senorblancodb64af32015-12-09 10:11:43 -0800546}
547
548
549SkImageFilter::Context SkImageFilter::mapContext(const Context& ctx) const {
senorblancoe5e79842016-03-21 14:51:59 -0700550 SkIRect clipBounds = this->onFilterNodeBounds(ctx.clipBounds(), ctx.ctm(),
551 MapDirection::kReverse_MapDirection);
reed4e23cda2016-01-11 10:56:59 -0800552 return Context(ctx.ctm(), clipBounds, ctx.cache());
senorblancodb64af32015-12-09 10:11:43 -0800553}
554
bsalomon4a339522015-10-06 08:40:50 -0700555bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*,
joshualitt85ff25e2015-07-08 09:10:03 -0700556 const SkMatrix&, const SkIRect&) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000557 return false;
558}
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000559
senorblanco8c874ee2015-03-20 06:38:17 -0700560SkImageFilter* SkImageFilter::CreateMatrixFilter(const SkMatrix& matrix,
561 SkFilterQuality filterQuality,
562 SkImageFilter* input) {
563 return SkMatrixImageFilter::Create(matrix, filterQuality, input);
564}
565
robertphillips372177e2016-03-30 07:32:28 -0700566sk_sp<SkImageFilter> SkImageFilter::makeWithLocalMatrix(const SkMatrix& matrix) const {
reed94dd7a52015-10-14 07:49:35 -0700567 // SkLocalMatrixImageFilter takes SkImage* in its factory, but logically that parameter
568 // is *always* treated as a const ptr. Hence the const-cast here.
569 //
robertphillips372177e2016-03-30 07:32:28 -0700570 SkImageFilter* nonConstThis = const_cast<SkImageFilter*>(this);
571 return SkLocalMatrixImageFilter::Make(matrix, sk_ref_sp<SkImageFilter>(nonConstThis));
senorblanco20311d42015-10-14 04:53:31 -0700572}
573
robertphillips2302de92016-03-24 07:26:32 -0700574sk_sp<SkSpecialImage> SkImageFilter::filterInput(int index,
575 SkSpecialImage* src,
576 const Context& ctx,
577 SkIPoint* offset) const {
robertphillipseaf086e2016-03-07 04:51:10 -0800578 SkImageFilter* input = this->getInput(index);
579 if (!input) {
robertphillips2302de92016-03-24 07:26:32 -0700580 return sk_sp<SkSpecialImage>(SkRef(src));
robertphillipseaf086e2016-03-07 04:51:10 -0800581 }
582
robertphillips2302de92016-03-24 07:26:32 -0700583 sk_sp<SkSpecialImage> result(input->filterImage(src, this->mapContext(ctx), offset));
robertphillips83c17fa2016-03-18 08:14:27 -0700584
585#if SK_SUPPORT_GPU
586 if (src->peekTexture() && result && !result->peekTexture()) {
587 // Keep the result on the GPU - this is still required for some
588 // image filters that don't support GPU in all cases
589 GrContext* context = src->peekTexture()->getContext();
robertphillips2302de92016-03-24 07:26:32 -0700590 return result->makeTextureImage(src->internal_getProxy(), context);
robertphillips83c17fa2016-03-18 08:14:27 -0700591 }
592#endif
593
robertphillips2302de92016-03-24 07:26:32 -0700594 return result;
robertphillipseaf086e2016-03-07 04:51:10 -0800595}
596
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000597#if SK_SUPPORT_GPU
598
robertphillips48e78462016-02-17 13:57:16 -0800599bool SkImageFilter::filterInputGPUDeprecated(int index, SkImageFilter::Proxy* proxy,
600 const SkBitmap& src, const Context& ctx,
601 SkBitmap* result, SkIPoint* offset) const {
senorblanco9a70b6e2015-10-16 11:35:14 -0700602 SkImageFilter* input = this->getInput(index);
603 if (!input) {
604 return true;
605 }
robertphillips4418dba2016-03-07 12:45:14 -0800606
robertphillips37bd7c32016-03-17 14:31:39 -0700607 sk_sp<SkSpecialImage> specialSrc(SkSpecialImage::internal_fromBM(proxy, src));
robertphillips4418dba2016-03-07 12:45:14 -0800608 if (!specialSrc) {
senorblanco7b87ee72015-10-26 06:55:47 -0700609 return false;
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000610 }
robertphillips4418dba2016-03-07 12:45:14 -0800611
robertphillips2302de92016-03-24 07:26:32 -0700612 sk_sp<SkSpecialImage> tmp(input->onFilterImage(specialSrc.get(),
613 this->mapContext(ctx),
614 offset));
robertphillips4418dba2016-03-07 12:45:14 -0800615 if (!tmp) {
616 return false;
617 }
618
619 if (!tmp->internal_getBM(result)) {
620 return false;
621 }
622
623 if (!result->getTexture()) {
624 GrContext* context = src.getTexture()->getContext();
625
626 const SkImageInfo info = result->info();
627 if (kUnknown_SkColorType == info.colorType()) {
628 return false;
629 }
630 SkAutoTUnref<GrTexture> resultTex(
631 GrRefCachedBitmapTexture(context, *result, GrTextureParams::ClampNoFilter()));
632 if (!resultTex) {
633 return false;
634 }
635 result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref();
636 }
637
638 return true;
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000639}
640#endif
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000641
senorblanco55b6d8b2014-07-30 11:26:46 -0700642namespace {
643
mtklein242397a2015-09-29 12:17:08 -0700644class CacheImpl : public SkImageFilter::Cache {
senorblanco55b6d8b2014-07-30 11:26:46 -0700645public:
robertphillipsdf7bb472016-02-19 08:19:40 -0800646 CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { }
647 ~CacheImpl() override {
mtklein242397a2015-09-29 12:17:08 -0700648 SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
649
650 while (!iter.done()) {
651 Value* v = &*iter;
652 ++iter;
653 delete v;
senorblanco55b6d8b2014-07-30 11:26:46 -0700654 }
mtklein242397a2015-09-29 12:17:08 -0700655 }
656 struct Value {
657 Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
658 : fKey(key), fBitmap(bitmap), fOffset(offset) {}
robertphillipsdf7bb472016-02-19 08:19:40 -0800659 Value(const Key& key, SkSpecialImage* image, const SkIPoint& offset)
660 : fKey(key), fImage(SkRef(image)), fOffset(offset) {}
661
mtklein242397a2015-09-29 12:17:08 -0700662 Key fKey;
663 SkBitmap fBitmap;
robertphillipsdf7bb472016-02-19 08:19:40 -0800664 SkAutoTUnref<SkSpecialImage> fImage;
mtklein242397a2015-09-29 12:17:08 -0700665 SkIPoint fOffset;
666 static const Key& GetKey(const Value& v) {
667 return v.fKey;
668 }
669 static uint32_t Hash(const Key& key) {
670 return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
671 }
672 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
senorblanco55b6d8b2014-07-30 11:26:46 -0700673 };
robertphillipsdf7bb472016-02-19 08:19:40 -0800674
mtklein242397a2015-09-29 12:17:08 -0700675 bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const override {
676 SkAutoMutexAcquire mutex(fMutex);
677 if (Value* v = fLookup.find(key)) {
678 *result = v->fBitmap;
679 *offset = v->fOffset;
680 if (v != fLRU.head()) {
681 fLRU.remove(v);
682 fLRU.addToHead(v);
683 }
684 return true;
senorblanco55b6d8b2014-07-30 11:26:46 -0700685 }
mtklein242397a2015-09-29 12:17:08 -0700686 return false;
687 }
robertphillipsdf7bb472016-02-19 08:19:40 -0800688
689 SkSpecialImage* get(const Key& key, SkIPoint* offset) const override {
690 SkAutoMutexAcquire mutex(fMutex);
691 if (Value* v = fLookup.find(key)) {
692 *offset = v->fOffset;
693 if (v != fLRU.head()) {
694 fLRU.remove(v);
695 fLRU.addToHead(v);
696 }
697 return v->fImage;
698 }
699 return nullptr;
700 }
701
mtklein242397a2015-09-29 12:17:08 -0700702 void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) override {
703 SkAutoMutexAcquire mutex(fMutex);
704 if (Value* v = fLookup.find(key)) {
robertphillipsdf7bb472016-02-19 08:19:40 -0800705 this->removeInternal(v);
mtklein242397a2015-09-29 12:17:08 -0700706 }
707 Value* v = new Value(key, result, offset);
708 fLookup.add(v);
709 fLRU.addToHead(v);
710 fCurrentBytes += result.getSize();
711 while (fCurrentBytes > fMaxBytes) {
712 Value* tail = fLRU.tail();
713 SkASSERT(tail);
714 if (tail == v) {
715 break;
716 }
robertphillipsdf7bb472016-02-19 08:19:40 -0800717 this->removeInternal(tail);
718 }
719 }
720
721 void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset) override {
722 SkAutoMutexAcquire mutex(fMutex);
723 if (Value* v = fLookup.find(key)) {
724 this->removeInternal(v);
725 }
726 Value* v = new Value(key, image, offset);
727 fLookup.add(v);
728 fLRU.addToHead(v);
729 fCurrentBytes += image->getSize();
730 while (fCurrentBytes > fMaxBytes) {
731 Value* tail = fLRU.tail();
732 SkASSERT(tail);
733 if (tail == v) {
734 break;
735 }
736 this->removeInternal(tail);
mtklein242397a2015-09-29 12:17:08 -0700737 }
senorblanco55b6d8b2014-07-30 11:26:46 -0700738 }
mtklein75135d82015-09-29 12:15:52 -0700739
mtklein242397a2015-09-29 12:17:08 -0700740 void purge() override {
741 SkAutoMutexAcquire mutex(fMutex);
742 while (fCurrentBytes > 0) {
743 Value* tail = fLRU.tail();
744 SkASSERT(tail);
745 this->removeInternal(tail);
746 }
747 }
mtklein75135d82015-09-29 12:15:52 -0700748
xidachen23526962016-02-01 05:27:16 -0800749 void purgeByKeys(const Key keys[], int count) override {
xidachen62776912015-12-21 07:29:03 -0800750 SkAutoMutexAcquire mutex(fMutex);
xidachen23526962016-02-01 05:27:16 -0800751 for (int i = 0; i < count; i++) {
752 if (Value* v = fLookup.find(keys[i])) {
753 this->removeInternal(v);
xidachen62776912015-12-21 07:29:03 -0800754 }
xidachen62776912015-12-21 07:29:03 -0800755 }
756 }
757
mtklein75135d82015-09-29 12:15:52 -0700758private:
mtklein242397a2015-09-29 12:17:08 -0700759 void removeInternal(Value* v) {
robertphillipsdf7bb472016-02-19 08:19:40 -0800760 if (v->fImage) {
761 fCurrentBytes -= v->fImage->getSize();
762 } else {
763 fCurrentBytes -= v->fBitmap.getSize();
764 }
mtklein242397a2015-09-29 12:17:08 -0700765 fLRU.remove(v);
766 fLookup.remove(v->fKey);
767 delete v;
senorblanco55b6d8b2014-07-30 11:26:46 -0700768 }
769private:
xidachen62776912015-12-21 07:29:03 -0800770 SkTDynamicHash<Value, Key> fLookup;
xidachen62776912015-12-21 07:29:03 -0800771 mutable SkTInternalLList<Value> fLRU;
772 size_t fMaxBytes;
773 size_t fCurrentBytes;
774 mutable SkMutex fMutex;
senorblanco55b6d8b2014-07-30 11:26:46 -0700775};
776
senorblanco55b6d8b2014-07-30 11:26:46 -0700777} // namespace
778
senorblancobe129b22014-08-08 07:14:35 -0700779SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
mtklein242397a2015-09-29 12:17:08 -0700780 return new CacheImpl(maxBytes);
senorblanco55b6d8b2014-07-30 11:26:46 -0700781}
782
mtklein6c59d802015-09-09 09:09:53 -0700783SK_DECLARE_STATIC_ONCE_PTR(SkImageFilter::Cache, cache);
senorblancobe129b22014-08-08 07:14:35 -0700784SkImageFilter::Cache* SkImageFilter::Cache::Get() {
mtklein242397a2015-09-29 12:17:08 -0700785 return cache.get([]{ return SkImageFilter::Cache::Create(kDefaultCacheSize); });
786}
787
788void SkImageFilter::PurgeCache() {
789 Cache::Get()->purge();
reed67ca2a92015-05-20 13:22:58 -0700790}
reed2c55d7b2015-06-09 08:18:39 -0700791
792///////////////////////////////////////////////////////////////////////////////////////////////////
793
senorblancoa9fbd162016-01-11 14:09:09 -0800794SkBaseDevice* SkImageFilter::DeviceProxy::createDevice(int w, int h, TileUsage usage) {
reed2c55d7b2015-06-09 08:18:39 -0700795 SkBaseDevice::CreateInfo cinfo(SkImageInfo::MakeN32Premul(w, h),
senorblancoa9fbd162016-01-11 14:09:09 -0800796 kPossible_TileUsage == usage ? SkBaseDevice::kPossible_TileUsage
797 : SkBaseDevice::kNever_TileUsage,
reed2c55d7b2015-06-09 08:18:39 -0700798 kUnknown_SkPixelGeometry,
reed70ee31b2015-12-10 13:44:45 -0800799 false, /* preserveLCDText */
reed2c55d7b2015-06-09 08:18:39 -0700800 true /*forImageFilter*/);
halcanary96fcdcc2015-08-27 07:41:13 -0700801 SkBaseDevice* dev = fDevice->onCreateDevice(cinfo, nullptr);
802 if (nullptr == dev) {
robertphillips9a53fd72015-06-22 09:46:59 -0700803 const SkSurfaceProps surfaceProps(fDevice->fSurfaceProps.flags(),
804 kUnknown_SkPixelGeometry);
805 dev = SkBitmapDevice::Create(cinfo.fInfo, surfaceProps);
reed2c55d7b2015-06-09 08:18:39 -0700806 }
807 return dev;
808}
809
reed88d064d2015-10-12 11:30:02 -0700810bool SkImageFilter::DeviceProxy::filterImage(const SkImageFilter* filter, const SkBitmap& src,
reed2c55d7b2015-06-09 08:18:39 -0700811 const SkImageFilter::Context& ctx,
812 SkBitmap* result, SkIPoint* offset) {
813 return fDevice->filterImage(filter, src, ctx, result, offset);
814}