blob: 86e12e1f4fd689142ea453dd7417f7bbd34615de [file] [log] [blame]
reed@google.com894aa9a2011-09-23 14:49:49 +00001/*
2 * Copyright 2011 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#ifndef SkImageFilter_DEFINED
9#define SkImageFilter_DEFINED
10
bungemanbf521ff2016-02-17 13:13:44 -080011#include "../private/SkTArray.h"
bungemanf3c15b72015-08-19 11:56:48 -070012#include "../private/SkTemplates.h"
xidachen23526962016-02-01 05:27:16 -080013#include "../private/SkMutex.h"
brianosmanafbf71d2016-07-21 07:15:37 -070014#include "SkColorSpace.h"
senorblanco8c874ee2015-03-20 06:38:17 -070015#include "SkFilterQuality.h"
reed@google.com894aa9a2011-09-23 14:49:49 +000016#include "SkFlattenable.h"
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000017#include "SkMatrix.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000018#include "SkRect.h"
reed@google.com894aa9a2011-09-23 14:49:49 +000019
robertphillipsaf9b8c82016-04-12 11:02:25 -070020class GrContext;
joshualittb0a8a372014-09-23 09:50:21 -070021class GrFragmentProcessor;
reed2c55d7b2015-06-09 08:18:39 -070022class SkColorFilter;
23struct SkIPoint;
robertphillipsdf7bb472016-02-19 08:19:40 -080024class SkSpecialImage;
senorblanco900c3672016-04-27 11:31:23 -070025class SkImageFilterCache;
26struct SkImageFilterCacheKey;
reed@google.com15356a62011-11-03 19:29:08 +000027
28/**
reed@google.com15356a62011-11-03 19:29:08 +000029 * Base class for image filters. If one is installed in the paint, then
30 * all drawing occurs as usual, but it is as if the drawing happened into an
31 * offscreen (before the xfermode is applied). This offscreen bitmap will
32 * then be handed to the imagefilter, who in turn creates a new bitmap which
33 * is what will finally be drawn to the device (using the original xfermode).
reed@google.com15356a62011-11-03 19:29:08 +000034 */
senorblanco@chromium.org54e01b22011-11-16 18:20:47 +000035class SK_API SkImageFilter : public SkFlattenable {
reed@google.com894aa9a2011-09-23 14:49:49 +000036public:
brianosman2a75e5d2016-09-22 07:15:37 -070037 // Extra information about the output of a filter DAG. For now, this is just the color space
38 // (of the original requesting device). This is used when constructing intermediate rendering
39 // surfaces, so that we ensure we land in a surface that's similar/compatible to the final
40 // consumer of the DAG's output.
41 class OutputProperties {
42 public:
43 explicit OutputProperties(SkColorSpace* colorSpace) : fColorSpace(colorSpace) {}
44
45 SkColorSpace* colorSpace() const { return fColorSpace; }
46
47 private:
48 // This will be a pointer to the device's color space, and our lifetime is bounded by
49 // the device, so we can store a bare pointer.
50 SkColorSpace* fColorSpace;
51 };
52
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000053 class Context {
54 public:
brianosman2a75e5d2016-09-22 07:15:37 -070055 Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache,
56 const OutputProperties& outputProperties)
reedc9b5f8b2015-10-22 13:20:20 -070057 : fCTM(ctm)
58 , fClipBounds(clipBounds)
59 , fCache(cache)
brianosman2a75e5d2016-09-22 07:15:37 -070060 , fOutputProperties(outputProperties)
reedc9b5f8b2015-10-22 13:20:20 -070061 {}
62
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000063 const SkMatrix& ctm() const { return fCTM; }
64 const SkIRect& clipBounds() const { return fClipBounds; }
senorblanco900c3672016-04-27 11:31:23 -070065 SkImageFilterCache* cache() const { return fCache; }
brianosman2a75e5d2016-09-22 07:15:37 -070066 const OutputProperties& outputProperties() const { return fOutputProperties; }
reedc9b5f8b2015-10-22 13:20:20 -070067
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000068 private:
senorblanco900c3672016-04-27 11:31:23 -070069 SkMatrix fCTM;
70 SkIRect fClipBounds;
71 SkImageFilterCache* fCache;
brianosman2a75e5d2016-09-22 07:15:37 -070072 OutputProperties fOutputProperties;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000073 };
74
reed18918632015-07-16 13:17:13 -070075 class CropRect {
76 public:
77 enum CropEdge {
78 kHasLeft_CropEdge = 0x01,
79 kHasTop_CropEdge = 0x02,
senorblancoed7cf272015-07-16 15:19:11 -070080 kHasWidth_CropEdge = 0x04,
81 kHasHeight_CropEdge = 0x08,
reed18918632015-07-16 13:17:13 -070082 kHasAll_CropEdge = 0x0F,
83 };
84 CropRect() {}
85 explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge)
86 : fRect(rect), fFlags(flags) {}
87 uint32_t flags() const { return fFlags; }
88 const SkRect& rect() const { return fRect; }
89#ifndef SK_IGNORE_TO_STRING
90 void toString(SkString* str) const;
91#endif
92
93 /**
94 * Apply this cropRect to the imageBounds. If a given edge of the cropRect is not
senorblanco6db0a7b2016-04-01 16:41:10 -070095 * set, then the corresponding edge from imageBounds will be used. If "embiggen"
96 * is true, the crop rect is allowed to enlarge the size of the rect, otherwise
97 * it may only reduce the rect. Filters that can affect transparent black should
98 * pass "true", while all other filters should pass "false".
reed18918632015-07-16 13:17:13 -070099 *
100 * Note: imageBounds is in "device" space, as the output cropped rectangle will be,
senorblancod8ff5b32016-01-28 08:23:02 -0800101 * so the matrix is ignored for those. It is only applied the croprect's bounds.
reed18918632015-07-16 13:17:13 -0700102 */
senorblanco6db0a7b2016-04-01 16:41:10 -0700103 void applyTo(const SkIRect& imageBounds, const SkMatrix&, bool embiggen,
104 SkIRect* cropped) const;
reed18918632015-07-16 13:17:13 -0700105
106 private:
107 SkRect fRect;
108 uint32_t fFlags;
109 };
110
senorblancoa9fbd162016-01-11 14:09:09 -0800111 enum TileUsage {
112 kPossible_TileUsage, //!< the created device may be drawn tiled
113 kNever_TileUsage, //!< the created device will never be drawn tiled
114 };
115
reed@google.com894aa9a2011-09-23 14:49:49 +0000116 /**
senorblanco5878dbd2016-05-19 14:50:29 -0700117 * Request a new filtered image to be created from the src image.
reed@google.com894aa9a2011-09-23 14:49:49 +0000118 *
robertphillips4418dba2016-03-07 12:45:14 -0800119 * The context contains the environment in which the filter is occurring.
120 * It includes the clip bounds, CTM and cache.
reed@google.com894aa9a2011-09-23 14:49:49 +0000121 *
122 * Offset is the amount to translate the resulting image relative to the
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000123 * src when it is drawn. This is an out-param.
reed@google.com894aa9a2011-09-23 14:49:49 +0000124 *
senorblanco5878dbd2016-05-19 14:50:29 -0700125 * If the result image cannot be created, or the result would be
126 * transparent black, return null, in which case the offset parameter
127 * should be ignored by the caller.
robertphillips4418dba2016-03-07 12:45:14 -0800128 *
129 * TODO: Right now the imagefilters sometimes return empty result bitmaps/
130 * specialimages. That doesn't seem quite right.
reed@google.com894aa9a2011-09-23 14:49:49 +0000131 */
robertphillips2302de92016-03-24 07:26:32 -0700132 sk_sp<SkSpecialImage> filterImage(SkSpecialImage* src, const Context&, SkIPoint* offset) const;
robertphillipseaf086e2016-03-07 04:51:10 -0800133
senorblancod8ff5b32016-01-28 08:23:02 -0800134 enum MapDirection {
135 kForward_MapDirection,
136 kReverse_MapDirection
137 };
reed@google.com15356a62011-11-03 19:29:08 +0000138 /**
senorblancod8ff5b32016-01-28 08:23:02 -0800139 * Map a device-space rect recursively forward or backward through the
140 * filter DAG. kForward_MapDirection is used to determine which pixels of
141 * the destination canvas a source image rect would touch after filtering.
jbroman127fe3e2016-03-21 08:28:48 -0700142 * kReverse_MapDirection is used to determine which rect of the source
senorblancod8ff5b32016-01-28 08:23:02 -0800143 * image would be required to fill the given rect (typically, clip bounds).
144 * Used for clipping and temp-buffer allocations, so the result need not
145 * be exact, but should never be smaller than the real answer. The default
senorblancoe5e79842016-03-21 14:51:59 -0700146 * implementation recursively unions all input bounds, or returns the
147 * source rect if no inputs.
reed@google.com32d25b62011-12-20 16:19:00 +0000148 */
senorblancoe5e79842016-03-21 14:51:59 -0700149 SkIRect filterBounds(const SkIRect& src, const SkMatrix& ctm,
150 MapDirection = kReverse_MapDirection) const;
151
robertphillipsaf9b8c82016-04-12 11:02:25 -0700152#if SK_SUPPORT_GPU
brianosman2a75e5d2016-09-22 07:15:37 -0700153 static sk_sp<SkSpecialImage> DrawWithFP(GrContext* context,
robertphillipsaf9b8c82016-04-12 11:02:25 -0700154 sk_sp<GrFragmentProcessor> fp,
brianosmanafbf71d2016-07-21 07:15:37 -0700155 const SkIRect& bounds,
brianosman2a75e5d2016-09-22 07:15:37 -0700156 const OutputProperties& outputProperties);
robertphillipsaf9b8c82016-04-12 11:02:25 -0700157#endif
158
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000159 /**
sugoi@google.coma1c511b2013-02-21 15:02:28 +0000160 * Returns whether this image filter is a color filter and puts the color filter into the
sugoi@google.com4b6d4322013-02-21 20:26:50 +0000161 * "filterPtr" parameter if it can. Does nothing otherwise.
162 * If this returns false, then the filterPtr is unchanged.
163 * If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
164 * (i.e. it may not be set to NULL).
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000165 */
reedcedc36f2015-03-08 04:42:52 -0700166 bool isColorFilterNode(SkColorFilter** filterPtr) const {
167 return this->onIsColorFilterNode(filterPtr);
168 }
169
170 // DEPRECATED : use isColorFilterNode() instead
171 bool asColorFilter(SkColorFilter** filterPtr) const {
172 return this->isColorFilterNode(filterPtr);
173 }
174
vjiaoblacke1e5c742016-08-23 11:13:14 -0700175 static sk_sp<SkImageFilter> MakeBlur(SkScalar sigmaX, SkScalar sigmaY,
176 sk_sp<SkImageFilter> input,
177 const CropRect* cropRect = nullptr);
178
reedcedc36f2015-03-08 04:42:52 -0700179 /**
180 * Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely
181 * replaced by the returned colorfilter. i.e. the two effects will affect drawing in the
182 * same way.
183 */
senorblancoa544eda2015-12-07 07:48:34 -0800184 bool asAColorFilter(SkColorFilter** filterPtr) const;
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000185
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000186 /**
187 * Returns the number of inputs this filter will accept (some inputs can
188 * be NULL).
189 */
robertphillips6b134732016-04-15 09:58:37 -0700190 int countInputs() const { return fInputs.count(); }
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000191
192 /**
193 * Returns the input filter at a given index, or NULL if no input is
194 * connected. The indices used are filter-specific.
195 */
196 SkImageFilter* getInput(int i) const {
robertphillips6b134732016-04-15 09:58:37 -0700197 SkASSERT(i < fInputs.count());
198 return fInputs[i].get();
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000199 }
200
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000201 /**
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000202 * Returns whether any edges of the crop rect have been set. The crop
203 * rect is set at construction time, and determines which pixels from the
reed18918632015-07-16 13:17:13 -0700204 * input image will be processed, and which pixels in the output image will be allowed.
205 * The size of the crop rect should be
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000206 * used as the size of the destination image. The origin of this rect
207 * should be used to offset access to the input images, and should also
robertphillips3e302272016-04-20 11:48:36 -0700208 * be added to the "offset" parameter in onFilterImage.
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000209 */
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000210 bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000211
reedb3fe1b82015-06-23 08:29:20 -0700212 CropRect getCropRect() const { return fCropRect; }
213
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000214 // Default impl returns union of all input bounds.
senorblancoe5e79842016-03-21 14:51:59 -0700215 virtual SkRect computeFastBounds(const SkRect&) const;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000216
senorblanco0abdf762015-08-20 11:10:41 -0700217 // Can this filter DAG compute the resulting bounds of an object-space rectangle?
senorblanco6db0a7b2016-04-01 16:41:10 -0700218 bool canComputeFastBounds() const;
senorblanco0abdf762015-08-20 11:10:41 -0700219
senorblanco8c874ee2015-03-20 06:38:17 -0700220 /**
reed94dd7a52015-10-14 07:49:35 -0700221 * If this filter can be represented by another filter + a localMatrix, return that filter,
222 * else return null.
223 */
robertphillips372177e2016-03-30 07:32:28 -0700224 sk_sp<SkImageFilter> makeWithLocalMatrix(const SkMatrix&) const;
225
reed94dd7a52015-10-14 07:49:35 -0700226 /**
reedbb34a8a2016-04-23 15:19:07 -0700227 * ImageFilters can natively handle scaling and translate components in the CTM. Only some of
228 * them can handle affine (or more complex) matrices. This call returns true iff the filter
229 * and all of its (non-null) inputs can handle these more complex matrices.
230 */
reed96a04f32016-04-25 09:25:15 -0700231 bool canHandleComplexCTM() const;
reedbb34a8a2016-04-23 15:19:07 -0700232
233 /**
reed8c30a812016-04-20 16:36:51 -0700234 * Return an imagefilter which transforms its input by the given matrix.
senorblanco8c874ee2015-03-20 06:38:17 -0700235 */
robertphillipsae8c9332016-04-05 15:09:00 -0700236 static sk_sp<SkImageFilter> MakeMatrixFilter(const SkMatrix& matrix,
reed8c30a812016-04-20 16:36:51 -0700237 SkFilterQuality quality,
robertphillipsae8c9332016-04-05 15:09:00 -0700238 sk_sp<SkImageFilter> input);
reed8c30a812016-04-20 16:36:51 -0700239
robertphillipsf3f5bad2014-12-19 13:49:15 -0800240 SK_TO_STRING_PUREVIRT()
mtklein3b375452016-04-04 14:57:19 -0700241 SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter)
vjiaoblacke1e5c742016-08-23 11:13:14 -0700242 SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000243
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000244protected:
reedb959ec72014-07-17 07:03:09 -0700245 class Common {
246 public:
reed9fa60da2014-08-21 07:59:51 -0700247 /**
248 * Attempt to unflatten the cropRect and the expected number of input filters.
249 * If any number of input filters is valid, pass -1.
250 * If this fails (i.e. corrupt buffer or contents) then return false and common will
251 * be left uninitialized.
252 * If this returns true, then inputCount() is the number of found input filters, each
253 * of which may be NULL or a valid imagefilter.
254 */
255 bool unflatten(SkReadBuffer&, int expectedInputs);
reedb959ec72014-07-17 07:03:09 -0700256
reed9fa60da2014-08-21 07:59:51 -0700257 const CropRect& cropRect() const { return fCropRect; }
reedb959ec72014-07-17 07:03:09 -0700258 int inputCount() const { return fInputs.count(); }
robertphillips2238c9d2016-03-30 13:34:16 -0700259 sk_sp<SkImageFilter>* inputs() const { return fInputs.get(); }
reedb959ec72014-07-17 07:03:09 -0700260
robertphillips2238c9d2016-03-30 13:34:16 -0700261 sk_sp<SkImageFilter> getInput(int index) const { return fInputs[index]; }
reed9fa60da2014-08-21 07:59:51 -0700262
reedb959ec72014-07-17 07:03:09 -0700263 private:
264 CropRect fCropRect;
265 // most filters accept at most 2 input-filters
robertphillips2238c9d2016-03-30 13:34:16 -0700266 SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
reedb959ec72014-07-17 07:03:09 -0700267
268 void allocInputs(int count);
269 };
270
robertphillips372177e2016-03-30 07:32:28 -0700271 SkImageFilter(sk_sp<SkImageFilter>* inputs, int inputCount, const CropRect* cropRect);
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000272
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000273 virtual ~SkImageFilter();
274
commit-bot@chromium.orgc84728d2013-12-04 20:07:47 +0000275 /**
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000276 * Constructs a new SkImageFilter read from an SkReadBuffer object.
commit-bot@chromium.orgc84728d2013-12-04 20:07:47 +0000277 *
278 * @param inputCount The exact number of inputs expected for this SkImageFilter object.
279 * -1 can be used if the filter accepts any number of inputs.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000280 * @param rb SkReadBuffer object from which the SkImageFilter is read.
commit-bot@chromium.orgc84728d2013-12-04 20:07:47 +0000281 */
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000282 explicit SkImageFilter(int inputCount, SkReadBuffer& rb);
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000283
mtklein36352bf2015-03-25 18:17:31 -0700284 void flatten(SkWriteBuffer&) const override;
reed@google.com32d25b62011-12-20 16:19:00 +0000285
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000286 /**
287 * This is the virtual which should be overridden by the derived class
288 * to perform image filtering.
289 *
290 * src is the original primitive bitmap. If the filter has a connected
291 * input, it should recurse on that input and use that in place of src.
292 *
293 * The matrix is the current matrix on the canvas.
294 *
295 * Offset is the amount to translate the resulting image relative to the
296 * src when it is drawn. This is an out-param.
297 *
robertphillips3e302272016-04-20 11:48:36 -0700298 * If the result image cannot be created (either because of error or if, say, the result
299 * is entirely clipped out), this should return nullptr.
300 * Callers that affect transparent black should explicitly handle nullptr
301 * results and press on. In the error case this behavior will produce a better result
302 * than nothing and is necessary for the clipped out case.
303 * If the return value is nullptr then offset should be ignored.
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000304 */
robertphillips2302de92016-03-24 07:26:32 -0700305 virtual sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
robertphillips3e302272016-04-20 11:48:36 -0700306 SkIPoint* offset) const = 0;
robertphillipseaf086e2016-03-07 04:51:10 -0800307
senorblancod8ff5b32016-01-28 08:23:02 -0800308 /**
senorblancoe5e79842016-03-21 14:51:59 -0700309 * This function recurses into its inputs with the given rect (first
senorblancod8ff5b32016-01-28 08:23:02 -0800310 * argument), calls filterBounds() with the given map direction on each,
senorblancoe5e79842016-03-21 14:51:59 -0700311 * and returns the union of those results. If a derived class has special
312 * recursion requirements (e.g., it has an input which does not participate
313 * in bounds computation), it can be overridden here.
senorblancod8ff5b32016-01-28 08:23:02 -0800314 *
315 * Note that this function is *not* responsible for mapping the rect for
316 * this node's filter bounds requirements (i.e., calling
317 * onFilterNodeBounds()); that is handled by filterBounds().
318 */
senorblancoe5e79842016-03-21 14:51:59 -0700319 virtual SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const;
senorblancodb64af32015-12-09 10:11:43 -0800320
321 /**
322 * Performs a forwards or reverse mapping of the given rect to accommodate
323 * this filter's margin requirements. kForward_MapDirection is used to
324 * determine the destination pixels which would be touched by filtering
325 * the given given source rect (e.g., given source bitmap bounds,
326 * determine the optimal bounds of the filtered offscreen bitmap).
327 * kReverse_MapDirection is used to determine which pixels of the
328 * input(s) would be required to fill the given destination rect
329 * (e.g., clip bounds). NOTE: these operations may not be the
330 * inverse of the other. For example, blurring expands the given rect
331 * in both forward and reverse directions. Unlike
332 * onFilterBounds(), this function is non-recursive.
333 */
senorblancoe5e79842016-03-21 14:51:59 -0700334 virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const;
reed@google.com894aa9a2011-09-23 14:49:49 +0000335
senorblancob9519f82015-10-15 12:15:13 -0700336 // Helper function which invokes filter processing on the input at the
robertphillips3e302272016-04-20 11:48:36 -0700337 // specified "index". If the input is null, it returns "src" and leaves
338 // "offset" untouched. If the input is non-null, it
339 // calls filterImage() on that input, and returns the result.
340 sk_sp<SkSpecialImage> filterInput(int index,
341 SkSpecialImage* src,
342 const Context&,
343 SkIPoint* offset) const;
senorblancob9519f82015-10-15 12:15:13 -0700344
reedcedc36f2015-03-08 04:42:52 -0700345 /**
346 * Return true (and return a ref'd colorfilter) if this node in the DAG is just a
347 * colorfilter w/o CropRect constraints.
348 */
349 virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const {
350 return false;
351 }
352
reed96a04f32016-04-25 09:25:15 -0700353 /**
354 * Override this to describe the behavior of your subclass - as a leaf node. The caller will
355 * take care of calling your inputs (and return false if any of them could not handle it).
356 */
357 virtual bool onCanHandleComplexCTM() const { return false; }
reedbb34a8a2016-04-23 15:19:07 -0700358
robertphillipsaf9b8c82016-04-12 11:02:25 -0700359 /** Given a "srcBounds" rect, computes destination bounds for this filter.
360 * "dstBounds" are computed by transforming the crop rect by the context's
361 * CTM, applying it to the initial bounds, and intersecting the result with
362 * the context's clip bounds. "srcBounds" (if non-null) are computed by
363 * intersecting the initial bounds with "dstBounds", to ensure that we never
364 * sample outside of the crop rect (this restriction may be relaxed in the
senorblancoafec27f2016-02-16 09:11:18 -0800365 * future).
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000366 */
senorblancoafec27f2016-02-16 09:11:18 -0800367 bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const;
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000368
senorblancoafec27f2016-02-16 09:11:18 -0800369 /** A variant of the above call which takes the original source bitmap and
370 * source offset. If the resulting crop rect is not entirely contained by
371 * the source bitmap's bounds, it creates a new bitmap in "result" and
372 * pads the edges with transparent black. In that case, the srcOffset is
373 * modified to be the same as the bounds, since no further adjustment is
374 * needed by the caller. This version should only be used by filters
375 * which are not capable of processing a smaller source bitmap into a
376 * larger destination.
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000377 */
robertphillips2302de92016-03-24 07:26:32 -0700378 sk_sp<SkSpecialImage> applyCropRect(const Context&, SkSpecialImage* src, SkIPoint* srcOffset,
379 SkIRect* bounds) const;
robertphillipseaf086e2016-03-07 04:51:10 -0800380
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000381 /**
senorblancodb64af32015-12-09 10:11:43 -0800382 * Creates a modified Context for use when recursing up the image filter DAG.
383 * The clip bounds are adjusted to accommodate any margins that this
384 * filter requires by calling this node's
385 * onFilterNodeBounds(..., kReverse_MapDirection).
386 */
387 Context mapContext(const Context& ctx) const;
388
Brian Osman615d66d2016-12-29 09:18:20 -0500389#if SK_SUPPORT_GPU
390 /**
391 * Returns a version of the passed-in image (possibly the original), that is in a colorspace
392 * with the same gamut as the one from the OutputProperties. This allows filters that do many
393 * texture samples to guarantee that any color space conversion has happened before running.
394 */
395 static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src, const OutputProperties&);
396#endif
397
reed@google.com894aa9a2011-09-23 14:49:49 +0000398private:
mtklein242397a2015-09-29 12:17:08 -0700399 friend class SkGraphics;
400 static void PurgeCache();
401
robertphillips6b134732016-04-15 09:58:37 -0700402 void init(sk_sp<SkImageFilter>* inputs, int inputCount, const CropRect* cropRect);
robertphillips4418dba2016-03-07 12:45:14 -0800403
senorblanco55b6d8b2014-07-30 11:26:46 -0700404 bool usesSrcInput() const { return fUsesSrcInput; }
senorblanco6db0a7b2016-04-01 16:41:10 -0700405 virtual bool affectsTransparentBlack() const { return false; }
senorblanco55b6d8b2014-07-30 11:26:46 -0700406
robertphillips6b134732016-04-15 09:58:37 -0700407 SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
408
senorblanco55b6d8b2014-07-30 11:26:46 -0700409 bool fUsesSrcInput;
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000410 CropRect fCropRect;
senorblanco55b6d8b2014-07-30 11:26:46 -0700411 uint32_t fUniqueID; // Globally unique
senorblanco900c3672016-04-27 11:31:23 -0700412 mutable SkTArray<SkImageFilterCacheKey> fCacheKeys;
xidachen23526962016-02-01 05:27:16 -0800413 mutable SkMutex fMutex;
robertphillips6b134732016-04-15 09:58:37 -0700414 typedef SkFlattenable INHERITED;
reed@google.com894aa9a2011-09-23 14:49:49 +0000415};
416
reed9fa60da2014-08-21 07:59:51 -0700417/**
418 * Helper to unflatten the common data, and return NULL if we fail.
419 */
420#define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount) \
421 Common localVar; \
422 do { \
423 if (!localVar.unflatten(buffer, expectedCount)) { \
424 return NULL; \
425 } \
426 } while (0)
427
reed@google.com894aa9a2011-09-23 14:49:49 +0000428#endif