blob: ee24d96964f5008cd8a8e6bb7c512bb8fea14f0e [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;
Matt Sarett31abf1f2017-04-07 16:54:04 -040023class SkColorSpaceXformer;
reed2c55d7b2015-06-09 08:18:39 -070024struct SkIPoint;
robertphillipsdf7bb472016-02-19 08:19:40 -080025class SkSpecialImage;
senorblanco900c3672016-04-27 11:31:23 -070026class SkImageFilterCache;
27struct SkImageFilterCacheKey;
reed@google.com15356a62011-11-03 19:29:08 +000028
29/**
reed@google.com15356a62011-11-03 19:29:08 +000030 * Base class for image filters. If one is installed in the paint, then
31 * all drawing occurs as usual, but it is as if the drawing happened into an
32 * offscreen (before the xfermode is applied). This offscreen bitmap will
33 * then be handed to the imagefilter, who in turn creates a new bitmap which
34 * is what will finally be drawn to the device (using the original xfermode).
reed@google.com15356a62011-11-03 19:29:08 +000035 */
senorblanco@chromium.org54e01b22011-11-16 18:20:47 +000036class SK_API SkImageFilter : public SkFlattenable {
reed@google.com894aa9a2011-09-23 14:49:49 +000037public:
brianosman2a75e5d2016-09-22 07:15:37 -070038 // Extra information about the output of a filter DAG. For now, this is just the color space
39 // (of the original requesting device). This is used when constructing intermediate rendering
40 // surfaces, so that we ensure we land in a surface that's similar/compatible to the final
41 // consumer of the DAG's output.
42 class OutputProperties {
43 public:
44 explicit OutputProperties(SkColorSpace* colorSpace) : fColorSpace(colorSpace) {}
45
46 SkColorSpace* colorSpace() const { return fColorSpace; }
47
48 private:
49 // This will be a pointer to the device's color space, and our lifetime is bounded by
50 // the device, so we can store a bare pointer.
51 SkColorSpace* fColorSpace;
52 };
53
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000054 class Context {
55 public:
brianosman2a75e5d2016-09-22 07:15:37 -070056 Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache,
57 const OutputProperties& outputProperties)
reedc9b5f8b2015-10-22 13:20:20 -070058 : fCTM(ctm)
59 , fClipBounds(clipBounds)
60 , fCache(cache)
brianosman2a75e5d2016-09-22 07:15:37 -070061 , fOutputProperties(outputProperties)
reedc9b5f8b2015-10-22 13:20:20 -070062 {}
63
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000064 const SkMatrix& ctm() const { return fCTM; }
65 const SkIRect& clipBounds() const { return fClipBounds; }
senorblanco900c3672016-04-27 11:31:23 -070066 SkImageFilterCache* cache() const { return fCache; }
brianosman2a75e5d2016-09-22 07:15:37 -070067 const OutputProperties& outputProperties() const { return fOutputProperties; }
reedc9b5f8b2015-10-22 13:20:20 -070068
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000069 private:
senorblanco900c3672016-04-27 11:31:23 -070070 SkMatrix fCTM;
71 SkIRect fClipBounds;
72 SkImageFilterCache* fCache;
brianosman2a75e5d2016-09-22 07:15:37 -070073 OutputProperties fOutputProperties;
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000074 };
75
reed18918632015-07-16 13:17:13 -070076 class CropRect {
77 public:
78 enum CropEdge {
79 kHasLeft_CropEdge = 0x01,
80 kHasTop_CropEdge = 0x02,
senorblancoed7cf272015-07-16 15:19:11 -070081 kHasWidth_CropEdge = 0x04,
82 kHasHeight_CropEdge = 0x08,
reed18918632015-07-16 13:17:13 -070083 kHasAll_CropEdge = 0x0F,
84 };
85 CropRect() {}
86 explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge)
87 : fRect(rect), fFlags(flags) {}
88 uint32_t flags() const { return fFlags; }
89 const SkRect& rect() const { return fRect; }
90#ifndef SK_IGNORE_TO_STRING
91 void toString(SkString* str) const;
92#endif
93
94 /**
95 * Apply this cropRect to the imageBounds. If a given edge of the cropRect is not
senorblanco6db0a7b2016-04-01 16:41:10 -070096 * set, then the corresponding edge from imageBounds will be used. If "embiggen"
97 * is true, the crop rect is allowed to enlarge the size of the rect, otherwise
98 * it may only reduce the rect. Filters that can affect transparent black should
99 * pass "true", while all other filters should pass "false".
reed18918632015-07-16 13:17:13 -0700100 *
101 * Note: imageBounds is in "device" space, as the output cropped rectangle will be,
senorblancod8ff5b32016-01-28 08:23:02 -0800102 * so the matrix is ignored for those. It is only applied the croprect's bounds.
reed18918632015-07-16 13:17:13 -0700103 */
senorblanco6db0a7b2016-04-01 16:41:10 -0700104 void applyTo(const SkIRect& imageBounds, const SkMatrix&, bool embiggen,
105 SkIRect* cropped) const;
reed18918632015-07-16 13:17:13 -0700106
107 private:
108 SkRect fRect;
109 uint32_t fFlags;
110 };
111
senorblancoa9fbd162016-01-11 14:09:09 -0800112 enum TileUsage {
113 kPossible_TileUsage, //!< the created device may be drawn tiled
114 kNever_TileUsage, //!< the created device will never be drawn tiled
115 };
116
reed@google.com894aa9a2011-09-23 14:49:49 +0000117 /**
senorblanco5878dbd2016-05-19 14:50:29 -0700118 * Request a new filtered image to be created from the src image.
reed@google.com894aa9a2011-09-23 14:49:49 +0000119 *
robertphillips4418dba2016-03-07 12:45:14 -0800120 * The context contains the environment in which the filter is occurring.
121 * It includes the clip bounds, CTM and cache.
reed@google.com894aa9a2011-09-23 14:49:49 +0000122 *
123 * Offset is the amount to translate the resulting image relative to the
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000124 * src when it is drawn. This is an out-param.
reed@google.com894aa9a2011-09-23 14:49:49 +0000125 *
senorblanco5878dbd2016-05-19 14:50:29 -0700126 * If the result image cannot be created, or the result would be
127 * transparent black, return null, in which case the offset parameter
128 * should be ignored by the caller.
robertphillips4418dba2016-03-07 12:45:14 -0800129 *
130 * TODO: Right now the imagefilters sometimes return empty result bitmaps/
131 * specialimages. That doesn't seem quite right.
reed@google.com894aa9a2011-09-23 14:49:49 +0000132 */
robertphillips2302de92016-03-24 07:26:32 -0700133 sk_sp<SkSpecialImage> filterImage(SkSpecialImage* src, const Context&, SkIPoint* offset) const;
robertphillipseaf086e2016-03-07 04:51:10 -0800134
senorblancod8ff5b32016-01-28 08:23:02 -0800135 enum MapDirection {
136 kForward_MapDirection,
137 kReverse_MapDirection
138 };
reed@google.com15356a62011-11-03 19:29:08 +0000139 /**
senorblancod8ff5b32016-01-28 08:23:02 -0800140 * Map a device-space rect recursively forward or backward through the
141 * filter DAG. kForward_MapDirection is used to determine which pixels of
142 * the destination canvas a source image rect would touch after filtering.
jbroman127fe3e2016-03-21 08:28:48 -0700143 * kReverse_MapDirection is used to determine which rect of the source
senorblancod8ff5b32016-01-28 08:23:02 -0800144 * image would be required to fill the given rect (typically, clip bounds).
145 * Used for clipping and temp-buffer allocations, so the result need not
146 * be exact, but should never be smaller than the real answer. The default
senorblancoe5e79842016-03-21 14:51:59 -0700147 * implementation recursively unions all input bounds, or returns the
148 * source rect if no inputs.
reed@google.com32d25b62011-12-20 16:19:00 +0000149 */
senorblancoe5e79842016-03-21 14:51:59 -0700150 SkIRect filterBounds(const SkIRect& src, const SkMatrix& ctm,
151 MapDirection = kReverse_MapDirection) const;
152
robertphillipsaf9b8c82016-04-12 11:02:25 -0700153#if SK_SUPPORT_GPU
brianosman2a75e5d2016-09-22 07:15:37 -0700154 static sk_sp<SkSpecialImage> DrawWithFP(GrContext* context,
robertphillipsaf9b8c82016-04-12 11:02:25 -0700155 sk_sp<GrFragmentProcessor> fp,
brianosmanafbf71d2016-07-21 07:15:37 -0700156 const SkIRect& bounds,
brianosman2a75e5d2016-09-22 07:15:37 -0700157 const OutputProperties& outputProperties);
robertphillipsaf9b8c82016-04-12 11:02:25 -0700158#endif
159
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000160 /**
sugoi@google.coma1c511b2013-02-21 15:02:28 +0000161 * Returns whether this image filter is a color filter and puts the color filter into the
sugoi@google.com4b6d4322013-02-21 20:26:50 +0000162 * "filterPtr" parameter if it can. Does nothing otherwise.
163 * If this returns false, then the filterPtr is unchanged.
164 * If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
165 * (i.e. it may not be set to NULL).
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000166 */
reedcedc36f2015-03-08 04:42:52 -0700167 bool isColorFilterNode(SkColorFilter** filterPtr) const {
168 return this->onIsColorFilterNode(filterPtr);
169 }
170
171 // DEPRECATED : use isColorFilterNode() instead
172 bool asColorFilter(SkColorFilter** filterPtr) const {
173 return this->isColorFilterNode(filterPtr);
174 }
175
vjiaoblacke1e5c742016-08-23 11:13:14 -0700176 static sk_sp<SkImageFilter> MakeBlur(SkScalar sigmaX, SkScalar sigmaY,
177 sk_sp<SkImageFilter> input,
178 const CropRect* cropRect = nullptr);
179
reedcedc36f2015-03-08 04:42:52 -0700180 /**
181 * Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely
182 * replaced by the returned colorfilter. i.e. the two effects will affect drawing in the
183 * same way.
184 */
senorblancoa544eda2015-12-07 07:48:34 -0800185 bool asAColorFilter(SkColorFilter** filterPtr) const;
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000186
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000187 /**
188 * Returns the number of inputs this filter will accept (some inputs can
189 * be NULL).
190 */
robertphillips6b134732016-04-15 09:58:37 -0700191 int countInputs() const { return fInputs.count(); }
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000192
193 /**
194 * Returns the input filter at a given index, or NULL if no input is
195 * connected. The indices used are filter-specific.
196 */
197 SkImageFilter* getInput(int i) const {
robertphillips6b134732016-04-15 09:58:37 -0700198 SkASSERT(i < fInputs.count());
199 return fInputs[i].get();
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000200 }
201
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000202 /**
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000203 * Returns whether any edges of the crop rect have been set. The crop
204 * rect is set at construction time, and determines which pixels from the
reed18918632015-07-16 13:17:13 -0700205 * input image will be processed, and which pixels in the output image will be allowed.
206 * The size of the crop rect should be
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000207 * used as the size of the destination image. The origin of this rect
208 * should be used to offset access to the input images, and should also
robertphillips3e302272016-04-20 11:48:36 -0700209 * be added to the "offset" parameter in onFilterImage.
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000210 */
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000211 bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000212
reedb3fe1b82015-06-23 08:29:20 -0700213 CropRect getCropRect() const { return fCropRect; }
214
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000215 // Default impl returns union of all input bounds.
senorblancoe5e79842016-03-21 14:51:59 -0700216 virtual SkRect computeFastBounds(const SkRect&) const;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000217
senorblanco0abdf762015-08-20 11:10:41 -0700218 // Can this filter DAG compute the resulting bounds of an object-space rectangle?
senorblanco6db0a7b2016-04-01 16:41:10 -0700219 bool canComputeFastBounds() const;
senorblanco0abdf762015-08-20 11:10:41 -0700220
senorblanco8c874ee2015-03-20 06:38:17 -0700221 /**
reed94dd7a52015-10-14 07:49:35 -0700222 * If this filter can be represented by another filter + a localMatrix, return that filter,
223 * else return null.
224 */
robertphillips372177e2016-03-30 07:32:28 -0700225 sk_sp<SkImageFilter> makeWithLocalMatrix(const SkMatrix&) const;
226
reed94dd7a52015-10-14 07:49:35 -0700227 /**
reedbb34a8a2016-04-23 15:19:07 -0700228 * ImageFilters can natively handle scaling and translate components in the CTM. Only some of
229 * them can handle affine (or more complex) matrices. This call returns true iff the filter
230 * and all of its (non-null) inputs can handle these more complex matrices.
231 */
reed96a04f32016-04-25 09:25:15 -0700232 bool canHandleComplexCTM() const;
reedbb34a8a2016-04-23 15:19:07 -0700233
234 /**
reed8c30a812016-04-20 16:36:51 -0700235 * Return an imagefilter which transforms its input by the given matrix.
senorblanco8c874ee2015-03-20 06:38:17 -0700236 */
robertphillipsae8c9332016-04-05 15:09:00 -0700237 static sk_sp<SkImageFilter> MakeMatrixFilter(const SkMatrix& matrix,
reed8c30a812016-04-20 16:36:51 -0700238 SkFilterQuality quality,
robertphillipsae8c9332016-04-05 15:09:00 -0700239 sk_sp<SkImageFilter> input);
reed8c30a812016-04-20 16:36:51 -0700240
robertphillipsf3f5bad2014-12-19 13:49:15 -0800241 SK_TO_STRING_PUREVIRT()
mtklein3b375452016-04-04 14:57:19 -0700242 SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter)
vjiaoblacke1e5c742016-08-23 11:13:14 -0700243 SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000244
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000245protected:
reedb959ec72014-07-17 07:03:09 -0700246 class Common {
247 public:
reed9fa60da2014-08-21 07:59:51 -0700248 /**
249 * Attempt to unflatten the cropRect and the expected number of input filters.
250 * If any number of input filters is valid, pass -1.
251 * If this fails (i.e. corrupt buffer or contents) then return false and common will
252 * be left uninitialized.
253 * If this returns true, then inputCount() is the number of found input filters, each
254 * of which may be NULL or a valid imagefilter.
255 */
256 bool unflatten(SkReadBuffer&, int expectedInputs);
reedb959ec72014-07-17 07:03:09 -0700257
reed9fa60da2014-08-21 07:59:51 -0700258 const CropRect& cropRect() const { return fCropRect; }
reedb959ec72014-07-17 07:03:09 -0700259 int inputCount() const { return fInputs.count(); }
robertphillips2238c9d2016-03-30 13:34:16 -0700260 sk_sp<SkImageFilter>* inputs() const { return fInputs.get(); }
reedb959ec72014-07-17 07:03:09 -0700261
robertphillips2238c9d2016-03-30 13:34:16 -0700262 sk_sp<SkImageFilter> getInput(int index) const { return fInputs[index]; }
reed9fa60da2014-08-21 07:59:51 -0700263
reedb959ec72014-07-17 07:03:09 -0700264 private:
265 CropRect fCropRect;
266 // most filters accept at most 2 input-filters
robertphillips2238c9d2016-03-30 13:34:16 -0700267 SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
reedb959ec72014-07-17 07:03:09 -0700268
269 void allocInputs(int count);
270 };
271
robertphillips372177e2016-03-30 07:32:28 -0700272 SkImageFilter(sk_sp<SkImageFilter>* inputs, int inputCount, const CropRect* cropRect);
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000273
Brian Salomond3b65972017-03-22 12:05:03 -0400274 ~SkImageFilter() override;
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000275
commit-bot@chromium.orgc84728d2013-12-04 20:07:47 +0000276 /**
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000277 * Constructs a new SkImageFilter read from an SkReadBuffer object.
commit-bot@chromium.orgc84728d2013-12-04 20:07:47 +0000278 *
279 * @param inputCount The exact number of inputs expected for this SkImageFilter object.
280 * -1 can be used if the filter accepts any number of inputs.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000281 * @param rb SkReadBuffer object from which the SkImageFilter is read.
commit-bot@chromium.orgc84728d2013-12-04 20:07:47 +0000282 */
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000283 explicit SkImageFilter(int inputCount, SkReadBuffer& rb);
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000284
mtklein36352bf2015-03-25 18:17:31 -0700285 void flatten(SkWriteBuffer&) const override;
reed@google.com32d25b62011-12-20 16:19:00 +0000286
Matt Sarett31abf1f2017-04-07 16:54:04 -0400287 const CropRect* getCropRectIfSet() const {
288 return this->cropRectIsSet() ? &fCropRect : nullptr;
289 }
290
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000291 /**
292 * This is the virtual which should be overridden by the derived class
293 * to perform image filtering.
294 *
295 * src is the original primitive bitmap. If the filter has a connected
296 * input, it should recurse on that input and use that in place of src.
297 *
298 * The matrix is the current matrix on the canvas.
299 *
300 * Offset is the amount to translate the resulting image relative to the
301 * src when it is drawn. This is an out-param.
302 *
robertphillips3e302272016-04-20 11:48:36 -0700303 * If the result image cannot be created (either because of error or if, say, the result
304 * is entirely clipped out), this should return nullptr.
305 * Callers that affect transparent black should explicitly handle nullptr
306 * results and press on. In the error case this behavior will produce a better result
307 * than nothing and is necessary for the clipped out case.
308 * If the return value is nullptr then offset should be ignored.
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000309 */
robertphillips2302de92016-03-24 07:26:32 -0700310 virtual sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
robertphillips3e302272016-04-20 11:48:36 -0700311 SkIPoint* offset) const = 0;
robertphillipseaf086e2016-03-07 04:51:10 -0800312
senorblancod8ff5b32016-01-28 08:23:02 -0800313 /**
senorblancoe5e79842016-03-21 14:51:59 -0700314 * This function recurses into its inputs with the given rect (first
senorblancod8ff5b32016-01-28 08:23:02 -0800315 * argument), calls filterBounds() with the given map direction on each,
senorblancoe5e79842016-03-21 14:51:59 -0700316 * and returns the union of those results. If a derived class has special
317 * recursion requirements (e.g., it has an input which does not participate
318 * in bounds computation), it can be overridden here.
senorblancod8ff5b32016-01-28 08:23:02 -0800319 *
320 * Note that this function is *not* responsible for mapping the rect for
321 * this node's filter bounds requirements (i.e., calling
322 * onFilterNodeBounds()); that is handled by filterBounds().
323 */
senorblancoe5e79842016-03-21 14:51:59 -0700324 virtual SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const;
senorblancodb64af32015-12-09 10:11:43 -0800325
326 /**
327 * Performs a forwards or reverse mapping of the given rect to accommodate
328 * this filter's margin requirements. kForward_MapDirection is used to
329 * determine the destination pixels which would be touched by filtering
330 * the given given source rect (e.g., given source bitmap bounds,
331 * determine the optimal bounds of the filtered offscreen bitmap).
332 * kReverse_MapDirection is used to determine which pixels of the
333 * input(s) would be required to fill the given destination rect
334 * (e.g., clip bounds). NOTE: these operations may not be the
335 * inverse of the other. For example, blurring expands the given rect
336 * in both forward and reverse directions. Unlike
337 * onFilterBounds(), this function is non-recursive.
338 */
senorblancoe5e79842016-03-21 14:51:59 -0700339 virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const;
reed@google.com894aa9a2011-09-23 14:49:49 +0000340
senorblancob9519f82015-10-15 12:15:13 -0700341 // Helper function which invokes filter processing on the input at the
robertphillips3e302272016-04-20 11:48:36 -0700342 // specified "index". If the input is null, it returns "src" and leaves
343 // "offset" untouched. If the input is non-null, it
344 // calls filterImage() on that input, and returns the result.
345 sk_sp<SkSpecialImage> filterInput(int index,
346 SkSpecialImage* src,
347 const Context&,
348 SkIPoint* offset) const;
senorblancob9519f82015-10-15 12:15:13 -0700349
reedcedc36f2015-03-08 04:42:52 -0700350 /**
351 * Return true (and return a ref'd colorfilter) if this node in the DAG is just a
352 * colorfilter w/o CropRect constraints.
353 */
354 virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const {
355 return false;
356 }
357
reed96a04f32016-04-25 09:25:15 -0700358 /**
359 * Override this to describe the behavior of your subclass - as a leaf node. The caller will
360 * take care of calling your inputs (and return false if any of them could not handle it).
361 */
362 virtual bool onCanHandleComplexCTM() const { return false; }
reedbb34a8a2016-04-23 15:19:07 -0700363
robertphillipsaf9b8c82016-04-12 11:02:25 -0700364 /** Given a "srcBounds" rect, computes destination bounds for this filter.
365 * "dstBounds" are computed by transforming the crop rect by the context's
366 * CTM, applying it to the initial bounds, and intersecting the result with
367 * the context's clip bounds. "srcBounds" (if non-null) are computed by
368 * intersecting the initial bounds with "dstBounds", to ensure that we never
369 * sample outside of the crop rect (this restriction may be relaxed in the
senorblancoafec27f2016-02-16 09:11:18 -0800370 * future).
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000371 */
senorblancoafec27f2016-02-16 09:11:18 -0800372 bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const;
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000373
senorblancoafec27f2016-02-16 09:11:18 -0800374 /** A variant of the above call which takes the original source bitmap and
375 * source offset. If the resulting crop rect is not entirely contained by
376 * the source bitmap's bounds, it creates a new bitmap in "result" and
377 * pads the edges with transparent black. In that case, the srcOffset is
378 * modified to be the same as the bounds, since no further adjustment is
379 * needed by the caller. This version should only be used by filters
380 * which are not capable of processing a smaller source bitmap into a
381 * larger destination.
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000382 */
robertphillips2302de92016-03-24 07:26:32 -0700383 sk_sp<SkSpecialImage> applyCropRect(const Context&, SkSpecialImage* src, SkIPoint* srcOffset,
384 SkIRect* bounds) const;
robertphillipseaf086e2016-03-07 04:51:10 -0800385
senorblanco@chromium.org1aa68722013-10-17 19:35:09 +0000386 /**
senorblancodb64af32015-12-09 10:11:43 -0800387 * Creates a modified Context for use when recursing up the image filter DAG.
388 * The clip bounds are adjusted to accommodate any margins that this
389 * filter requires by calling this node's
390 * onFilterNodeBounds(..., kReverse_MapDirection).
391 */
392 Context mapContext(const Context& ctx) const;
393
Brian Osman615d66d2016-12-29 09:18:20 -0500394#if SK_SUPPORT_GPU
395 /**
396 * Returns a version of the passed-in image (possibly the original), that is in a colorspace
397 * with the same gamut as the one from the OutputProperties. This allows filters that do many
398 * texture samples to guarantee that any color space conversion has happened before running.
399 */
400 static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src, const OutputProperties&);
401#endif
402
Matt Sarett31abf1f2017-04-07 16:54:04 -0400403 /**
404 * Returns an image filter transformed into a new color space via the |xformer|.
405 */
406 sk_sp<SkImageFilter> makeColorSpace(SkColorSpaceXformer* xformer) const {
407 return this->onMakeColorSpace(xformer);
408 }
409 virtual sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const {
410 return sk_ref_sp(const_cast<SkImageFilter*>(this));
411 }
412
reed@google.com894aa9a2011-09-23 14:49:49 +0000413private:
Matt Sarett6d72ed92017-04-10 16:35:33 -0400414 // For makeColorSpace().
Matt Sarett31abf1f2017-04-07 16:54:04 -0400415 friend class ArithmeticImageFilterImpl;
Matt Sarett6d72ed92017-04-10 16:35:33 -0400416 friend class SkAlphaThresholdFilterImpl;
417 friend class SkBlurImageFilterImpl;
418 friend class SkColorFilterImageFilter;
Matt Sarett31abf1f2017-04-07 16:54:04 -0400419 friend class SkColorSpaceXformer;
Matt Sarett6d72ed92017-04-10 16:35:33 -0400420 friend class SkComposeImageFilter;
421 friend class SkDisplacementMapEffect;
422 friend class SkDropShadowImageFilter;
423 friend class SkImageSource;
424 friend class SkMagnifierImageFilter;
425 friend class SkMatrixConvolutionImageFilter;
426 friend class SkMergeImageFilter;
427 friend class SkMorphologyImageFilter;
428 friend class SkOffsetImageFilter;
429 friend class SkTileImageFilter;
430 friend class SkXfermodeImageFilter_Base;
431
mtklein242397a2015-09-29 12:17:08 -0700432 friend class SkGraphics;
Matt Sarett31abf1f2017-04-07 16:54:04 -0400433
mtklein242397a2015-09-29 12:17:08 -0700434 static void PurgeCache();
435
robertphillips6b134732016-04-15 09:58:37 -0700436 void init(sk_sp<SkImageFilter>* inputs, int inputCount, const CropRect* cropRect);
robertphillips4418dba2016-03-07 12:45:14 -0800437
senorblanco55b6d8b2014-07-30 11:26:46 -0700438 bool usesSrcInput() const { return fUsesSrcInput; }
senorblanco6db0a7b2016-04-01 16:41:10 -0700439 virtual bool affectsTransparentBlack() const { return false; }
senorblanco55b6d8b2014-07-30 11:26:46 -0700440
robertphillips6b134732016-04-15 09:58:37 -0700441 SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
442
senorblanco55b6d8b2014-07-30 11:26:46 -0700443 bool fUsesSrcInput;
senorblanco@chromium.orgb295fb62013-10-10 13:51:19 +0000444 CropRect fCropRect;
senorblanco55b6d8b2014-07-30 11:26:46 -0700445 uint32_t fUniqueID; // Globally unique
senorblanco900c3672016-04-27 11:31:23 -0700446 mutable SkTArray<SkImageFilterCacheKey> fCacheKeys;
xidachen23526962016-02-01 05:27:16 -0800447 mutable SkMutex fMutex;
robertphillips6b134732016-04-15 09:58:37 -0700448 typedef SkFlattenable INHERITED;
reed@google.com894aa9a2011-09-23 14:49:49 +0000449};
450
reed9fa60da2014-08-21 07:59:51 -0700451/**
452 * Helper to unflatten the common data, and return NULL if we fail.
453 */
454#define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount) \
455 Common localVar; \
456 do { \
457 if (!localVar.unflatten(buffer, expectedCount)) { \
458 return NULL; \
459 } \
460 } while (0)
461
reed@google.com894aa9a2011-09-23 14:49:49 +0000462#endif