Move SkImageFilter functionality into private SkImageFilter_Base
Bug: skia:9281
Change-Id: I189dbf652580805641f8c4b9a6587cf15a9049dd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/231256
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 3f60698..e80b042 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -14,6 +14,6 @@
- Provide new factory API in include/effects/SkImageFilters
- Consolidated enum types to use SkTileMode and SkColorChannel
- Hide filter implementation classes
- - Bumps SkPicture version number
+ - Hide previously public functions on SkImageFilter that were intended for internal use only
* SkColorFilters::HSLAMatrix - new matrix color filter operating in HSLA space.
diff --git a/fuzz/FuzzPolyUtils.cpp b/fuzz/FuzzPolyUtils.cpp
index 9a9d388..e4b3c8b 100644
--- a/fuzz/FuzzPolyUtils.cpp
+++ b/fuzz/FuzzPolyUtils.cpp
@@ -6,6 +6,8 @@
*/
#include "fuzz/Fuzz.h"
+
+#include "include/private/SkTemplates.h"
#include "src/utils/SkPolyUtils.h"
void inline ignoreResult(bool ) {}
diff --git a/gm/imagefiltersbase.cpp b/gm/imagefiltersbase.cpp
index 4989bef..80f28cb 100644
--- a/gm/imagefiltersbase.cpp
+++ b/gm/imagefiltersbase.cpp
@@ -27,7 +27,7 @@
#include "include/effects/SkColorFilterImageFilter.h"
#include "include/effects/SkDropShadowImageFilter.h"
#include "include/utils/SkTextUtils.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkSpecialImage.h"
#include "tools/ToolUtils.h"
@@ -35,7 +35,7 @@
class SkReadBuffer;
-class FailImageFilter : public SkImageFilter {
+class FailImageFilter : public SkImageFilter_Base {
public:
static sk_sp<SkImageFilter> Make() {
return sk_sp<SkImageFilter>(new FailImageFilter);
@@ -52,7 +52,7 @@
private:
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
@@ -60,7 +60,7 @@
return FailImageFilter::Make();
}
-class IdentityImageFilter : public SkImageFilter {
+class IdentityImageFilter : public SkImageFilter_Base {
public:
static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilter> input) {
return sk_sp<SkImageFilter>(new IdentityImageFilter(std::move(input)));
@@ -78,7 +78,7 @@
private:
IdentityImageFilter(sk_sp<SkImageFilter> input) : INHERITED(&input, 1, nullptr) {}
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
// Register these image filters as deserializable before main().
diff --git a/gm/offsetimagefilter.cpp b/gm/offsetimagefilter.cpp
index 4b9fcaa..38ae539 100644
--- a/gm/offsetimagefilter.cpp
+++ b/gm/offsetimagefilter.cpp
@@ -20,6 +20,7 @@
#include "include/core/SkString.h"
#include "include/effects/SkImageSource.h"
#include "include/effects/SkOffsetImageFilter.h"
+#include "src/core/SkImageFilter_Base.h"
#include "tools/ToolUtils.h"
#include <utility>
@@ -128,8 +129,9 @@
p.setStyle(SkPaint::kFill_Style);
}
- if (imgf && imgf->cropRectIsSet()) {
- SkImageFilter::CropRect cr = imgf->getCropRect();
+ // Visualize the crop rect for debugging
+ if (imgf && as_IFB(imgf)->cropRectIsSet()) {
+ SkImageFilter::CropRect cr = as_IFB(imgf)->getCropRect();
p.setColor(0x66FF00FF);
p.setStyle(SkPaint::kStroke_Style);
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
index 5991fdb..d6da4d7 100644
--- a/include/core/SkImageFilter.h
+++ b/include/core/SkImageFilter.h
@@ -8,87 +8,28 @@
#ifndef SkImageFilter_DEFINED
#define SkImageFilter_DEFINED
-#include "include/core/SkColorSpace.h"
#include "include/core/SkFilterQuality.h"
#include "include/core/SkFlattenable.h"
-#include "include/core/SkImageInfo.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkRect.h"
-#include "include/private/SkMutex.h"
-#include "include/private/SkTArray.h"
-#include "include/private/SkTemplates.h"
-#if SK_SUPPORT_GPU
-#include "include/gpu/GrTypes.h"
-#endif
-class GrFragmentProcessor;
class SkColorFilter;
-struct SkIPoint;
-class GrRecordingContext;
-class SkSpecialImage;
-class SkImageFilterCache;
-struct SkImageFilterCacheKey;
/**
- * Base class for image filters. If one is installed in the paint, then
- * all drawing occurs as usual, but it is as if the drawing happened into an
- * offscreen (before the xfermode is applied). This offscreen bitmap will
- * then be handed to the imagefilter, who in turn creates a new bitmap which
- * is what will finally be drawn to the device (using the original xfermode).
+ * Base class for image filters. If one is installed in the paint, then all drawing occurs as
+ * usual, but it is as if the drawing happened into an offscreen (before the xfermode is applied).
+ * This offscreen bitmap will then be handed to the imagefilter, who in turn creates a new bitmap
+ * which is what will finally be drawn to the device (using the original xfermode).
+ *
+ * The local space of image filters matches the local space of the drawn geometry. For instance if
+ * there is rotation on the canvas, the blur will be computed along those rotated axes and not in
+ * the device space. In order to achieve this result, the actual drawing of the geometry may happen
+ * in an unrotated coordinate system so that the filtered image can be computed more easily, and
+ * then it will be post transformed to match what would have been produced if the geometry were
+ * drawn with the total canvas matrix to begin with.
*/
class SK_API SkImageFilter : public SkFlattenable {
public:
- // Extra information about the output of a filter DAG. For now, this is just the color space
- // (of the original requesting device). This is used when constructing intermediate rendering
- // surfaces, so that we ensure we land in a surface that's similar/compatible to the final
- // consumer of the DAG's output.
- class OutputProperties {
- public:
- explicit OutputProperties(SkColorType colorType, SkColorSpace* colorSpace)
- : fColorType(colorType), fColorSpace(colorSpace) {}
-
- SkColorType colorType() const { return fColorType; }
- SkColorSpace* colorSpace() const { return fColorSpace; }
-
- private:
- SkColorType fColorType;
- // This will be a pointer to the device's color space, and our lifetime is bounded by
- // the device, so we can store a bare pointer.
- SkColorSpace* fColorSpace;
- };
-
- class Context {
- public:
- Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache,
- const OutputProperties& outputProperties)
- : fCTM(ctm)
- , fClipBounds(clipBounds)
- , fCache(cache)
- , fOutputProperties(outputProperties)
- {}
-
- const SkMatrix& ctm() const { return fCTM; }
- const SkIRect& clipBounds() const { return fClipBounds; }
- SkImageFilterCache* cache() const { return fCache; }
- const OutputProperties& outputProperties() const { return fOutputProperties; }
-
- /**
- * Since a context can be build directly, its constructor has no chance to
- * "return null" if it's given invalid or unsupported inputs. Call this to
- * know of the the context can be used.
- *
- * The SkImageFilterCache Key, for example, requires a finite ctm (no infinities
- * or NaN), so that test is part of isValid.
- */
- bool isValid() const { return fCTM.isFinite(); }
-
- private:
- SkMatrix fCTM;
- SkIRect fClipBounds;
- SkImageFilterCache* fCache;
- OutputProperties fOutputProperties;
- };
-
class CropRect {
public:
enum CropEdge {
@@ -105,14 +46,14 @@
const SkRect& rect() const { return fRect; }
/**
- * Apply this cropRect to the imageBounds. If a given edge of the cropRect is not
- * set, then the corresponding edge from imageBounds will be used. If "embiggen"
- * is true, the crop rect is allowed to enlarge the size of the rect, otherwise
- * it may only reduce the rect. Filters that can affect transparent black should
- * pass "true", while all other filters should pass "false".
+ * Apply this cropRect to the imageBounds. If a given edge of the cropRect is not set, then
+ * the corresponding edge from imageBounds will be used. If "embiggen" is true, the crop
+ * rect is allowed to enlarge the size of the rect, otherwise it may only reduce the rect.
+ * Filters that can affect transparent black should pass "true", while all other filters
+ * should pass "false".
*
- * Note: imageBounds is in "device" space, as the output cropped rectangle will be,
- * so the matrix is ignored for those. It is only applied the croprect's bounds.
+ * Note: imageBounds is in "device" space, as the output cropped rectangle will be, so the
+ * matrix is ignored for those. It is only applied to the cropRect's bounds.
*/
void applyTo(const SkIRect& imageBounds, const SkMatrix& matrix, bool embiggen,
SkIRect* cropped) const;
@@ -122,61 +63,26 @@
uint32_t fFlags;
};
- enum TileUsage {
- kPossible_TileUsage, //!< the created device may be drawn tiled
- kNever_TileUsage, //!< the created device will never be drawn tiled
- };
-
- /**
- * Request a new filtered image to be created from the src image.
- *
- * The context contains the environment in which the filter is occurring.
- * It includes the clip bounds, CTM and cache.
- *
- * Offset is the amount to translate the resulting image relative to the
- * src when it is drawn. This is an out-param.
- *
- * If the result image cannot be created, or the result would be
- * transparent black, return null, in which case the offset parameter
- * should be ignored by the caller.
- *
- * TODO: Right now the imagefilters sometimes return empty result bitmaps/
- * specialimages. That doesn't seem quite right.
- */
- sk_sp<SkSpecialImage> filterImage(SkSpecialImage* src, const Context& context,
- SkIPoint* offset) const;
-
enum MapDirection {
kForward_MapDirection,
kReverse_MapDirection,
};
/**
- * Map a device-space rect recursively forward or backward through the
- * filter DAG. kForward_MapDirection is used to determine which pixels of
- * the destination canvas a source image rect would touch after filtering.
- * kReverse_MapDirection is used to determine which rect of the source
- * image would be required to fill the given rect (typically, clip bounds).
- * Used for clipping and temp-buffer allocations, so the result need not
- * be exact, but should never be smaller than the real answer. The default
- * implementation recursively unions all input bounds, or returns the
- * source rect if no inputs.
+ * Map a device-space rect recursively forward or backward through the filter DAG.
+ * kForward_MapDirection is used to determine which pixels of the destination canvas a source
+ * image rect would touch after filtering. kReverse_MapDirection is used to determine which rect
+ * of the source image would be required to fill the given rect (typically, clip bounds). Used
+ * for clipping and temp-buffer allocations, so the result need not be exact, but should never
+ * be smaller than the real answer. The default implementation recursively unions all input
+ * bounds, or returns the source rect if no inputs.
*
* In kReverse mode, 'inputRect' is the device-space bounds of the input pixels. In kForward
- * mode it should always be null. If 'inputRect' is null in kReverse mode the resulting
- * answer may be incorrect.
+ * mode it should always be null. If 'inputRect' is null in kReverse mode the resulting answer
+ * may be incorrect.
*/
SkIRect filterBounds(const SkIRect& src, const SkMatrix& ctm,
MapDirection, const SkIRect* inputRect = nullptr) const;
-#if SK_SUPPORT_GPU
- static sk_sp<SkSpecialImage> DrawWithFP(GrRecordingContext* context,
- std::unique_ptr<GrFragmentProcessor>
- fp,
- const SkIRect& bounds,
- const OutputProperties& outputProperties,
- GrProtected isProtected = GrProtected::kNo);
-#endif
-
/**
* Returns whether this image filter is a color filter and puts the color filter into the
* "filterPtr" parameter if it can. Does nothing otherwise.
@@ -184,51 +90,30 @@
* If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
* (i.e. it may not be set to NULL).
*/
- bool isColorFilterNode(SkColorFilter** filterPtr) const {
- return this->onIsColorFilterNode(filterPtr);
- }
+ bool isColorFilterNode(SkColorFilter** filterPtr) const;
// DEPRECATED : use isColorFilterNode() instead
bool asColorFilter(SkColorFilter** filterPtr) const {
return this->isColorFilterNode(filterPtr);
}
- void removeKey(const SkImageFilterCacheKey& key) const;
-
/**
* Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely
- * replaced by the returned colorfilter. i.e. the two effects will affect drawing in the
- * same way.
+ * replaced by the returned colorfilter. i.e. the two effects will affect drawing in the same
+ * way.
*/
bool asAColorFilter(SkColorFilter** filterPtr) const;
/**
- * Returns the number of inputs this filter will accept (some inputs can
- * be NULL).
+ * Returns the number of inputs this filter will accept (some inputs can be NULL).
*/
- int countInputs() const { return fInputs.count(); }
+ int countInputs() const;
/**
- * Returns the input filter at a given index, or NULL if no input is
- * connected. The indices used are filter-specific.
+ * Returns the input filter at a given index, or NULL if no input is connected. The indices
+ * used are filter-specific.
*/
- SkImageFilter* getInput(int i) const {
- SkASSERT(i < fInputs.count());
- return fInputs[i].get();
- }
-
- /**
- * Returns whether any edges of the crop rect have been set. The crop
- * rect is set at construction time, and determines which pixels from the
- * input image will be processed, and which pixels in the output image will be allowed.
- * The size of the crop rect should be
- * used as the size of the destination image. The origin of this rect
- * should be used to offset access to the input images, and should also
- * be added to the "offset" parameter in onFilterImage.
- */
- bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
-
- CropRect getCropRect() const { return fCropRect; }
+ const SkImageFilter* getInput(int i) const;
// Default impl returns union of all input bounds.
virtual SkRect computeFastBounds(const SkRect& bounds) const;
@@ -243,13 +128,6 @@
sk_sp<SkImageFilter> makeWithLocalMatrix(const SkMatrix& matrix) const;
/**
- * ImageFilters can natively handle scaling and translate components in the CTM. Only some of
- * them can handle affine (or more complex) matrices. This call returns true iff the filter
- * and all of its (non-null) inputs can handle these more complex matrices.
- */
- bool canHandleComplexCTM() const;
-
- /**
* Return an imagefilter which transforms its input by the given matrix.
* DEPRECATED: Use include/effects/SkImageFilters::MatrixTransform
*/
@@ -268,206 +146,17 @@
static sk_sp<SkImageFilter> Deserialize(const void* data, size_t size,
const SkDeserialProcs* procs = nullptr) {
return sk_sp<SkImageFilter>(static_cast<SkImageFilter*>(
- SkFlattenable::Deserialize(
- kSkImageFilter_Type, data, size, procs).release()));
+ SkFlattenable::Deserialize(kSkImageFilter_Type, data, size, procs).release()));
}
protected:
- class Common {
- public:
- /**
- * Attempt to unflatten the cropRect and the expected number of input filters.
- * If any number of input filters is valid, pass -1.
- * If this fails (i.e. corrupt buffer or contents) then return false and common will
- * be left uninitialized.
- * If this returns true, then inputCount() is the number of found input filters, each
- * of which may be NULL or a valid imagefilter.
- */
- bool unflatten(SkReadBuffer&, int expectedInputs);
-
- const CropRect& cropRect() const { return fCropRect; }
- int inputCount() const { return fInputs.count(); }
- sk_sp<SkImageFilter>* inputs() { return fInputs.begin(); }
-
- sk_sp<SkImageFilter> getInput(int index) { return fInputs[index]; }
-
- private:
- CropRect fCropRect;
- // most filters accept at most 2 input-filters
- SkSTArray<2, sk_sp<SkImageFilter>, true> fInputs;
- };
-
- SkImageFilter(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect);
-
- ~SkImageFilter() override;
-
- /**
- * Constructs a new SkImageFilter read from an SkReadBuffer object.
- *
- * @param inputCount The exact number of inputs expected for this SkImageFilter object.
- * -1 can be used if the filter accepts any number of inputs.
- * @param rb SkReadBuffer object from which the SkImageFilter is read.
- */
- explicit SkImageFilter(int inputCount, SkReadBuffer& rb);
-
- void flatten(SkWriteBuffer&) const override;
-
- const CropRect* getCropRectIfSet() const {
- return this->cropRectIsSet() ? &fCropRect : nullptr;
- }
-
- /**
- * This is the virtual which should be overridden by the derived class
- * to perform image filtering.
- *
- * src is the original primitive bitmap. If the filter has a connected
- * input, it should recurse on that input and use that in place of src.
- *
- * The matrix is the current matrix on the canvas.
- *
- * Offset is the amount to translate the resulting image relative to the
- * src when it is drawn. This is an out-param.
- *
- * If the result image cannot be created (either because of error or if, say, the result
- * is entirely clipped out), this should return nullptr.
- * Callers that affect transparent black should explicitly handle nullptr
- * results and press on. In the error case this behavior will produce a better result
- * than nothing and is necessary for the clipped out case.
- * If the return value is nullptr then offset should be ignored.
- */
- virtual sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
- SkIPoint* offset) const = 0;
-
- /**
- * This function recurses into its inputs with the given rect (first
- * argument), calls filterBounds() with the given map direction on each,
- * and returns the union of those results. If a derived class has special
- * recursion requirements (e.g., it has an input which does not participate
- * in bounds computation), it can be overridden here.
- * In kReverse mode, 'inputRect' is the device-space bounds of the input pixels. In kForward
- * mode it should always be null. If 'inputRect' is null in kReverse mode the resulting
- * answer may be incorrect.
- *
- * Note that this function is *not* responsible for mapping the rect for
- * this node's filter bounds requirements (i.e., calling
- * onFilterNodeBounds()); that is handled by filterBounds().
- */
- virtual SkIRect onFilterBounds(const SkIRect&, const SkMatrix& ctm,
- MapDirection, const SkIRect* inputRect) const;
-
- /**
- * Performs a forwards or reverse mapping of the given rect to accommodate
- * this filter's margin requirements. kForward_MapDirection is used to
- * determine the destination pixels which would be touched by filtering
- * the given source rect (e.g., given source bitmap bounds,
- * determine the optimal bounds of the filtered offscreen bitmap).
- * kReverse_MapDirection is used to determine which pixels of the
- * input(s) would be required to fill the given destination rect
- * (e.g., clip bounds). NOTE: these operations may not be the
- * inverse of the other. For example, blurring expands the given rect
- * in both forward and reverse directions. Unlike
- * onFilterBounds(), this function is non-recursive.
- * In kReverse mode, 'inputRect' will be the device space bounds of the input pixels. In
- * kForward mode, 'inputRect' should always be null. If 'inputRect' is null in kReverse mode
- * the resulting answer may be incorrect.
- */
- virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm,
- MapDirection, const SkIRect* inputRect) const;
-
- // Helper function which invokes filter processing on the input at the
- // specified "index". If the input is null, it returns "src" and leaves
- // "offset" untouched. If the input is non-null, it
- // calls filterImage() on that input, and returns the result.
- sk_sp<SkSpecialImage> filterInput(int index,
- SkSpecialImage* src,
- const Context&,
- SkIPoint* offset) const;
-
- /**
- * Return true (and return a ref'd colorfilter) if this node in the DAG is just a
- * colorfilter w/o CropRect constraints.
- */
- virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const {
- return false;
- }
-
- /**
- * Override this to describe the behavior of your subclass - as a leaf node. The caller will
- * take care of calling your inputs (and return false if any of them could not handle it).
- */
- virtual bool onCanHandleComplexCTM() const { return false; }
-
- /** Given a "srcBounds" rect, computes destination bounds for this filter.
- * "dstBounds" are computed by transforming the crop rect by the context's
- * CTM, applying it to the initial bounds, and intersecting the result with
- * the context's clip bounds. "srcBounds" (if non-null) are computed by
- * intersecting the initial bounds with "dstBounds", to ensure that we never
- * sample outside of the crop rect (this restriction may be relaxed in the
- * future).
- */
- bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const;
-
- /** A variant of the above call which takes the original source bitmap and
- * source offset. If the resulting crop rect is not entirely contained by
- * the source bitmap's bounds, it creates a new bitmap in "result" and
- * pads the edges with transparent black. In that case, the srcOffset is
- * modified to be the same as the bounds, since no further adjustment is
- * needed by the caller. This version should only be used by filters
- * which are not capable of processing a smaller source bitmap into a
- * larger destination.
- */
- sk_sp<SkSpecialImage> applyCropRectAndPad(const Context&, SkSpecialImage* src,
- SkIPoint* srcOffset, SkIRect* bounds) const;
-
- /**
- * Creates a modified Context for use when recursing up the image filter DAG.
- * The clip bounds are adjusted to accommodate any margins that this
- * filter requires by calling this node's
- * onFilterNodeBounds(..., kReverse_MapDirection).
- */
- Context mapContext(const Context& ctx) const;
-
-#if SK_SUPPORT_GPU
- /**
- * Returns a version of the passed-in image (possibly the original), that is in a colorspace
- * with the same gamut as the one from the OutputProperties. This allows filters that do many
- * texture samples to guarantee that any color space conversion has happened before running.
- */
- static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src, const OutputProperties&);
-#endif
sk_sp<SkImageFilter> refMe() const {
return sk_ref_sp(const_cast<SkImageFilter*>(this));
}
- // If 'srcBounds' will sample outside the border of 'originalSrcBounds' (i.e., the sample
- // will wrap around to the other side) we must preserve the far side of the src along that
- // axis (e.g., if we will sample beyond the left edge of the src, the right side must be
- // preserved for the repeat sampling to work).
- static SkIRect DetermineRepeatedSrcBound(const SkIRect& srcBounds,
- const SkIVector& filterOffset,
- const SkISize& filterSize,
- const SkIRect& originalSrcBounds);
-
private:
- friend class SkGraphics;
- friend bool SkIsSameFilter(const SkImageFilter* a, const SkImageFilter* b);
- // Helper method to inspect onFilterNodeBounds() without going through filterBounds()
- friend SkIRect SkFilterNodeBounds(const SkImageFilter*, const SkIRect& srcRect, const SkMatrix&,
- MapDirection, const SkIRect* inputRect);
-
- static void PurgeCache();
-
- void init(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect);
-
- bool usesSrcInput() const { return fUsesSrcInput; }
- virtual bool affectsTransparentBlack() const { return false; }
-
- SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
-
- bool fUsesSrcInput;
- CropRect fCropRect;
- uint32_t fUniqueID; // Globally unique
+ friend class SkImageFilter_Base;
typedef SkFlattenable INHERITED;
};
diff --git a/include/private/SkFloatingPoint.h b/include/private/SkFloatingPoint.h
index adac689..f0ca4bb 100644
--- a/include/private/SkFloatingPoint.h
+++ b/include/private/SkFloatingPoint.h
@@ -31,6 +31,7 @@
constexpr float SK_FloatSqrt2 = 1.41421356f;
constexpr float SK_FloatPI = 3.14159265f;
+constexpr double SK_DoublePI = 3.14159265358979323846264338327950288;
// C++98 cmath std::pow seems to be the earliest portable way to get float pow.
// However, on Linux including cmath undefines isfinite.
diff --git a/samplecode/SampleImageFilterDAG.cpp b/samplecode/SampleImageFilterDAG.cpp
index a2f9e22..40301d4 100644
--- a/samplecode/SampleImageFilterDAG.cpp
+++ b/samplecode/SampleImageFilterDAG.cpp
@@ -23,7 +23,7 @@
#include "include/effects/SkGradientShader.h"
#include "include/effects/SkImageFilters.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkSpecialImage.h"
#include "tools/ToolUtils.h"
@@ -122,9 +122,8 @@
// For isolated forward filtering, it uses the same input but should not be propagated
// to the inputs, so get the filter node bounds directly.
- fForwardIsolatedBounds = SkFilterNodeBounds(
- fFilter.get(), srcRect, fLocalCTM,
- SkImageFilter::kForward_MapDirection, nullptr);
+ fForwardIsolatedBounds = as_IFB(fFilter)->filterNodeBounds(
+ srcRect, fLocalCTM, SkImageFilter::kForward_MapDirection, nullptr);
} else {
fForwardBounds = srcRect;
fForwardIsolatedBounds = srcRect;
@@ -138,9 +137,8 @@
void computeReverseLocalIsolatedBounds(const SkIRect& srcRect) {
if (fFilter) {
- fReverseLocalIsolatedBounds = SkFilterNodeBounds(
- fFilter.get(), srcRect, fLocalCTM,
- SkImageFilter::kReverse_MapDirection, &srcRect);
+ fReverseLocalIsolatedBounds = as_IFB(fFilter)->filterNodeBounds(
+ srcRect, fLocalCTM, SkImageFilter::kReverse_MapDirection, &srcRect);
} else {
fReverseLocalIsolatedBounds = srcRect;
}
@@ -182,9 +180,8 @@
// To calculate the appropriate intermediate reverse bounds for the children, we
// need this node's onFilterNodeBounds() results based on its parents' bounds (the
// current 'srcRect').
- nextSrcRect = SkFilterNodeBounds(
- fFilter.get(), srcRect, fLocalCTM,
- SkImageFilter::kReverse_MapDirection, &srcRect);
+ nextSrcRect = as_IFB(fFilter)->filterNodeBounds(
+ srcRect, fLocalCTM, SkImageFilter::kReverse_MapDirection, &srcRect);
}
// Fill in the children. The union of these bounds should equal the value calculated
@@ -242,14 +239,14 @@
const SkImageFilter* rootFilter) {
// Emulate SkCanvas::internalSaveLayer's decomposition of the CTM.
SkMatrix local;
- sk_sp<SkImageFilter> finalFilter = SkApplyCTMToFilter(rootFilter, ctm, &local);
+ sk_sp<SkImageFilter> finalFilter = as_IFB(rootFilter)->applyCTM(ctm, &local);
// In ApplyCTMToFilter, the CTM is decomposed such that CTM = remainder * local. The matrix
// that is embedded in 'finalFilter' is actually local^-1*remainder*local to account for
// how SkMatrixImageFilter is specified, but we want the true remainder since it is what should
// transform the results to put in the correct place after filtering.
SkMatrix invLocal, remaining;
- if (!SkIsSameFilter(finalFilter.get(), rootFilter) && local.invert(&invLocal)) {
+ if (as_IFB(rootFilter)->uniqueID() != as_IFB(finalFilter)->uniqueID()) {
remaining = SkMatrix::Concat(ctm, invLocal);
} else {
remaining = SkMatrix::I();
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 162bf11..bf0d4e5 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -18,6 +18,7 @@
#include "src/core/SkDraw.h"
#include "src/core/SkGlyphRun.h"
#include "src/core/SkImageFilterCache.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkMakeUnique.h"
#include "src/core/SkRasterClip.h"
#include "src/core/SkSpecialImage.h"
@@ -613,10 +614,11 @@
SkMatrix::MakeTrans(SkIntToScalar(-x), SkIntToScalar(-y)), this->ctm());
const SkIRect clipBounds = fRCStack.rc().getBounds().makeOffset(-x, -y);
sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
- SkImageFilter::OutputProperties outputProperties(fBitmap.colorType(), fBitmap.colorSpace());
- SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
+ SkImageFilter_Base::OutputProperties outputProperties(fBitmap.colorType(),
+ fBitmap.colorSpace());
+ SkImageFilter_Base::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
- filteredImage = filter->filterImage(src, ctx, &offset);
+ filteredImage = as_IFB(filter)->filterImage(src, ctx, &offset);
if (!filteredImage) {
return;
}
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 02a29ba..fd6e093 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -28,7 +28,7 @@
#include "src/core/SkDraw.h"
#include "src/core/SkGlyphRun.h"
#include "src/core/SkImageFilterCache.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkLatticeIter.h"
#include "src/core/SkMSAN.h"
#include "src/core/SkMakeUnique.h"
@@ -907,7 +907,7 @@
snapBounds = newBounds;
SkMatrix localCTM;
- sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToBackdropFilter(filter, ctm, &localCTM);
+ sk_sp<SkImageFilter> modifiedFilter = as_IFB(filter)->applyCTMForBackdrop(ctm, &localCTM);
// Account for the origin offset in the CTM
localCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
@@ -915,7 +915,7 @@
// since there's no device CTM stack that provides it to the image filter context.
// FIXME skbug.com/9074 - once perspective is properly supported, drop the
// localCTM.hasPerspective condition from assert.
- SkASSERT(localCTM.isScaleTranslate() || filter->canHandleComplexCTM() ||
+ SkASSERT(localCTM.isScaleTranslate() || as_IFB(filter)->canHandleComplexCTM() ||
localCTM.hasPerspective());
p.setImageFilter(modifiedFilter->makeWithLocalMatrix(localCTM));
}
@@ -983,11 +983,11 @@
*/
if (imageFilter) {
SkMatrix modifiedCTM;
- sk_sp<SkImageFilter> modifiedFilter = SkApplyCTMToFilter(imageFilter, stashedMatrix,
- &modifiedCTM);
- if (!SkIsSameFilter(modifiedFilter.get(), imageFilter)) {
+ sk_sp<SkImageFilter> modifiedFilter = as_IFB(imageFilter)->applyCTM(stashedMatrix,
+ &modifiedCTM);
+ if (as_IFB(modifiedFilter)->uniqueID() != as_IFB(imageFilter)->uniqueID()) {
// The original filter couldn't support the CTM entirely
- SkASSERT(modifiedCTM.isScaleTranslate() || imageFilter->canHandleComplexCTM());
+ SkASSERT(modifiedCTM.isScaleTranslate() || as_IFB(imageFilter)->canHandleComplexCTM());
modifiedRec = fMCRec;
this->internalSetMatrix(modifiedCTM);
SkPaint* p = lazyP.set(*paint);
diff --git a/src/core/SkGraphics.cpp b/src/core/SkGraphics.cpp
index c8e4ba3..5db7daa 100644
--- a/src/core/SkGraphics.cpp
+++ b/src/core/SkGraphics.cpp
@@ -8,7 +8,6 @@
#include "include/core/SkGraphics.h"
#include "include/core/SkCanvas.h"
-#include "include/core/SkImageFilter.h"
#include "include/core/SkMath.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPath.h"
@@ -20,6 +19,7 @@
#include "src/core/SkBlitter.h"
#include "src/core/SkCpu.h"
#include "src/core/SkGeometry.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkOpts.h"
#include "src/core/SkResourceCache.h"
#include "src/core/SkScalerContext.h"
@@ -46,7 +46,7 @@
void SkGraphics::PurgeAllCaches() {
SkGraphics::PurgeFontCache();
SkGraphics::PurgeResourceCache();
- SkImageFilter::PurgeCache();
+ SkImageFilter_Base::PurgeCache();
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 5bfa7ac..a7eb4cb 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -13,6 +13,7 @@
#include "include/private/SkSafe32.h"
#include "src/core/SkFuzzLogging.h"
#include "src/core/SkImageFilterCache.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkLocalMatrixImageFilter.h"
#include "src/core/SkMatrixImageFilter.h"
#include "src/core/SkReadBuffer.h"
@@ -33,10 +34,225 @@
#endif
#include <atomic>
-void SkImageFilter::CropRect::applyTo(const SkIRect& imageBounds,
- const SkMatrix& ctm,
- bool embiggen,
- SkIRect* cropped) const {
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// SkImageFilter - A number of the public APIs on SkImageFilter downcast to SkImageFilter_Base
+// in order to perform their actual work.
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Returns the number of inputs this filter will accept (some inputs can
+ * be NULL).
+ */
+int SkImageFilter::countInputs() const { return as_IFB(this)->fInputs.count(); }
+
+/**
+ * Returns the input filter at a given index, or NULL if no input is
+ * connected. The indices used are filter-specific.
+ */
+const SkImageFilter* SkImageFilter::getInput(int i) const {
+ SkASSERT(i < this->countInputs());
+ return as_IFB(this)->fInputs[i].get();
+}
+
+bool SkImageFilter::isColorFilterNode(SkColorFilter** filterPtr) const {
+ return as_IFB(this)->onIsColorFilterNode(filterPtr);
+}
+
+SkIRect SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
+ MapDirection direction, const SkIRect* inputRect) const {
+ if (kReverse_MapDirection == direction) {
+ SkIRect bounds = as_IFB(this)->onFilterNodeBounds(src, ctm, direction, inputRect);
+ return as_IFB(this)->onFilterBounds(bounds, ctm, direction, &bounds);
+ } else {
+ SkASSERT(!inputRect);
+ SkIRect bounds = as_IFB(this)->onFilterBounds(src, ctm, direction, nullptr);
+ bounds = as_IFB(this)->onFilterNodeBounds(bounds, ctm, direction, nullptr);
+ SkIRect dst;
+ as_IFB(this)->getCropRect().applyTo(
+ bounds, ctm, as_IFB(this)->affectsTransparentBlack(), &dst);
+ return dst;
+ }
+}
+
+SkRect SkImageFilter::computeFastBounds(const SkRect& src) const {
+ if (0 == this->countInputs()) {
+ return src;
+ }
+ SkRect combinedBounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
+ for (int i = 1; i < this->countInputs(); i++) {
+ const SkImageFilter* input = this->getInput(i);
+ if (input) {
+ combinedBounds.join(input->computeFastBounds(src));
+ } else {
+ combinedBounds.join(src);
+ }
+ }
+ return combinedBounds;
+}
+
+bool SkImageFilter::canComputeFastBounds() const {
+ if (as_IFB(this)->affectsTransparentBlack()) {
+ return false;
+ }
+ for (int i = 0; i < this->countInputs(); i++) {
+ const SkImageFilter* input = this->getInput(i);
+ if (input && !input->canComputeFastBounds()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SkImageFilter::asAColorFilter(SkColorFilter** filterPtr) const {
+ SkASSERT(nullptr != filterPtr);
+ if (!this->isColorFilterNode(filterPtr)) {
+ return false;
+ }
+ if (nullptr != this->getInput(0) || (*filterPtr)->affectsTransparentBlack()) {
+ (*filterPtr)->unref();
+ return false;
+ }
+ return true;
+}
+
+sk_sp<SkImageFilter> SkImageFilter::MakeMatrixFilter(const SkMatrix& matrix,
+ SkFilterQuality filterQuality,
+ sk_sp<SkImageFilter> input) {
+ return SkMatrixImageFilter::Make(matrix, filterQuality, std::move(input));
+}
+
+sk_sp<SkImageFilter> SkImageFilter::makeWithLocalMatrix(const SkMatrix& matrix) const {
+ return SkLocalMatrixImageFilter::Make(matrix, this->refMe());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// SkImageFilter_Base
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static int32_t next_image_filter_unique_id() {
+ static std::atomic<int32_t> nextID{1};
+
+ int32_t id;
+ do {
+ id = nextID++;
+ } while (id == 0);
+ return id;
+}
+
+SkImageFilter_Base::SkImageFilter_Base(sk_sp<SkImageFilter> const* inputs,
+ int inputCount, const CropRect* cropRect)
+ : fUsesSrcInput(false)
+ , fUniqueID(next_image_filter_unique_id()) {
+ fCropRect = cropRect ? *cropRect : CropRect(SkRect(), 0x0);
+
+ fInputs.reset(inputCount);
+
+ for (int i = 0; i < inputCount; ++i) {
+ if (!inputs[i] || as_IFB(inputs[i])->fUsesSrcInput) {
+ fUsesSrcInput = true;
+ }
+ fInputs[i] = inputs[i];
+ }
+}
+
+SkImageFilter_Base::~SkImageFilter_Base() {
+ SkImageFilterCache::Get()->purgeByImageFilter(this);
+}
+
+bool SkImageFilter_Base::Common::unflatten(SkReadBuffer& buffer, int expectedCount) {
+ const int count = buffer.readInt();
+ if (!buffer.validate(count >= 0)) {
+ return false;
+ }
+ if (!buffer.validate(expectedCount < 0 || count == expectedCount)) {
+ return false;
+ }
+
+ SkASSERT(fInputs.empty());
+ for (int i = 0; i < count; i++) {
+ fInputs.push_back(buffer.readBool() ? buffer.readImageFilter() : nullptr);
+ if (!buffer.isValid()) {
+ return false;
+ }
+ }
+ SkRect rect;
+ buffer.readRect(&rect);
+ if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) {
+ return false;
+ }
+
+ uint32_t flags = buffer.readUInt();
+ fCropRect = CropRect(rect, flags);
+ return buffer.isValid();
+}
+
+void SkImageFilter_Base::flatten(SkWriteBuffer& buffer) const {
+ buffer.writeInt(fInputs.count());
+ for (int i = 0; i < fInputs.count(); i++) {
+ const SkImageFilter* input = this->getInput(i);
+ buffer.writeBool(input != nullptr);
+ if (input != nullptr) {
+ buffer.writeFlattenable(input);
+ }
+ }
+ buffer.writeRect(fCropRect.rect());
+ buffer.writeUInt(fCropRect.flags());
+}
+
+sk_sp<SkSpecialImage> SkImageFilter_Base::filterImage(SkSpecialImage* src, const Context& context,
+ SkIPoint* offset) const {
+ SkASSERT(src && offset);
+ if (!context.isValid()) {
+ return nullptr;
+ }
+
+ uint32_t srcGenID = fUsesSrcInput ? src->uniqueID() : 0;
+ const SkIRect srcSubset = fUsesSrcInput ? src->subset() : SkIRect::MakeWH(0, 0);
+ SkImageFilterCacheKey key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID, srcSubset);
+ if (context.cache()) {
+ sk_sp<SkSpecialImage> result = context.cache()->get(key, offset);
+ if (result) {
+ return result;
+ }
+ }
+
+ sk_sp<SkSpecialImage> result(this->onFilterImage(src, context, offset));
+
+#if SK_SUPPORT_GPU
+ if (src->isTextureBacked() && result && !result->isTextureBacked()) {
+ // Keep the result on the GPU - this is still required for some
+ // image filters that don't support GPU in all cases
+ auto context = src->getContext();
+ result = result->makeTextureImage(context);
+ }
+#endif
+
+ if (result && context.cache()) {
+ context.cache()->set(key, result.get(), *offset, this);
+ }
+
+ return result;
+}
+
+bool SkImageFilter_Base::canHandleComplexCTM() const {
+ // CropRects need to apply in the source coordinate system, but are not aware of complex CTMs
+ // when performing clipping. For a simple fix, any filter with a crop rect set cannot support
+ // complex CTMs until that's updated.
+ if (this->cropRectIsSet() || !this->onCanHandleComplexCTM()) {
+ return false;
+ }
+ const int count = this->countInputs();
+ for (int i = 0; i < count; ++i) {
+ const SkImageFilter_Base* input = as_IFB(this->getInput(i));
+ if (input && !input->canHandleComplexCTM()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void SkImageFilter::CropRect::applyTo(const SkIRect& imageBounds, const SkMatrix& ctm,
+ bool embiggen, SkIRect* cropped) const {
*cropped = imageBounds;
if (fFlags) {
SkRect devCropR;
@@ -71,182 +287,131 @@
}
}
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-static int32_t next_image_filter_unique_id() {
- static std::atomic<int32_t> nextID{1};
-
- int32_t id;
- do {
- id = nextID++;
- } while (id == 0);
- return id;
+bool SkImageFilter_Base::applyCropRect(const Context& ctx, const SkIRect& srcBounds,
+ SkIRect* dstBounds) const {
+ SkIRect tmpDst = this->onFilterNodeBounds(srcBounds, ctx.ctm(), kForward_MapDirection, nullptr);
+ fCropRect.applyTo(tmpDst, ctx.ctm(), this->affectsTransparentBlack(), dstBounds);
+ // Intersect against the clip bounds, in case the crop rect has
+ // grown the bounds beyond the original clip. This can happen for
+ // example in tiling, where the clip is much smaller than the filtered
+ // primitive. If we didn't do this, we would be processing the filter
+ // at the full crop rect size in every tile.
+ return dstBounds->intersect(ctx.clipBounds());
}
-bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) {
- const int count = buffer.readInt();
- if (!buffer.validate(count >= 0)) {
- return false;
- }
- if (!buffer.validate(expectedCount < 0 || count == expectedCount)) {
- return false;
- }
-
- SkASSERT(fInputs.empty());
- for (int i = 0; i < count; i++) {
- fInputs.push_back(buffer.readBool() ? buffer.readImageFilter() : nullptr);
- if (!buffer.isValid()) {
- return false;
- }
- }
- SkRect rect;
- buffer.readRect(&rect);
- if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) {
- return false;
- }
-
- uint32_t flags = buffer.readUInt();
- fCropRect = CropRect(rect, flags);
- return buffer.isValid();
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void SkImageFilter::init(sk_sp<SkImageFilter> const* inputs,
- int inputCount,
- const CropRect* cropRect) {
- fCropRect = cropRect ? *cropRect : CropRect(SkRect(), 0x0);
-
- fInputs.reset(inputCount);
-
- for (int i = 0; i < inputCount; ++i) {
- if (!inputs[i] || inputs[i]->usesSrcInput()) {
- fUsesSrcInput = true;
- }
- fInputs[i] = inputs[i];
- }
-}
-
-SkImageFilter::SkImageFilter(sk_sp<SkImageFilter> const* inputs,
- int inputCount,
- const CropRect* cropRect)
- : fUsesSrcInput(false)
- , fUniqueID(next_image_filter_unique_id()) {
- this->init(inputs, inputCount, cropRect);
-}
-
-SkImageFilter::~SkImageFilter() {
- SkImageFilterCache::Get()->purgeByImageFilter(this);
-}
-
-SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer)
- : fUsesSrcInput(false)
- , fCropRect(SkRect(), 0x0)
- , fUniqueID(next_image_filter_unique_id()) {
- Common common;
- if (common.unflatten(buffer, inputCount)) {
- this->init(common.inputs(), common.inputCount(), &common.cropRect());
- }
-}
-
-void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
- buffer.writeInt(fInputs.count());
- for (int i = 0; i < fInputs.count(); i++) {
- SkImageFilter* input = this->getInput(i);
- buffer.writeBool(input != nullptr);
- if (input != nullptr) {
- buffer.writeFlattenable(input);
- }
- }
- buffer.writeRect(fCropRect.rect());
- buffer.writeUInt(fCropRect.flags());
-}
-
-sk_sp<SkSpecialImage> SkImageFilter::filterImage(SkSpecialImage* src, const Context& context,
- SkIPoint* offset) const {
- SkASSERT(src && offset);
- if (!context.isValid()) {
+// Return a larger (newWidth x newHeight) copy of 'src' with black padding
+// around it.
+static sk_sp<SkSpecialImage> pad_image(SkSpecialImage* src,
+ const SkImageFilter_Base::OutputProperties& outProps,
+ int newWidth, int newHeight, int offX, int offY) {
+ // We would like to operate in the source's color space (so that we return an "identical"
+ // image, other than the padding. To achieve that, we'd create new output properties:
+ //
+ // SkImageFilter::OutputProperties outProps(src->getColorSpace());
+ //
+ // That fails in at least two ways. For formats that are texturable but not renderable (like
+ // F16 on some ES implementations), we can't create a surface to do the work. For sRGB, images
+ // may be tagged with an sRGB color space (which leads to an sRGB config in makeSurface). But
+ // the actual config of that sRGB image on a device with no sRGB support is non-sRGB.
+ //
+ // Rather than try to special case these situations, we execute the image padding in the
+ // destination color space. This should not affect the output of the DAG in (almost) any case,
+ // because the result of this call is going to be used as an input, where it would have been
+ // switched to the destination space anyway. The one exception would be a filter that expected
+ // to consume unclamped F16 data, but the padded version of the image is pre-clamped to 8888.
+ // We can revisit this logic if that ever becomes an actual problem.
+ sk_sp<SkSpecialSurface> surf(src->makeSurface(outProps, SkISize::Make(newWidth, newHeight)));
+ if (!surf) {
return nullptr;
}
- uint32_t srcGenID = fUsesSrcInput ? src->uniqueID() : 0;
- const SkIRect srcSubset = fUsesSrcInput ? src->subset() : SkIRect::MakeWH(0, 0);
- SkImageFilterCacheKey key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID, srcSubset);
- if (context.cache()) {
- sk_sp<SkSpecialImage> result = context.cache()->get(key, offset);
- if (result) {
- return result;
+ SkCanvas* canvas = surf->getCanvas();
+ SkASSERT(canvas);
+
+ canvas->clear(0x0);
+
+ src->draw(canvas, offX, offY, nullptr);
+
+ return surf->makeImageSnapshot();
+}
+
+sk_sp<SkSpecialImage> SkImageFilter_Base::applyCropRectAndPad(const Context& ctx,
+ SkSpecialImage* src,
+ SkIPoint* srcOffset,
+ SkIRect* bounds) const {
+ const SkIRect srcBounds = SkIRect::MakeXYWH(srcOffset->x(), srcOffset->y(),
+ src->width(), src->height());
+
+ if (!this->applyCropRect(ctx, srcBounds, bounds)) {
+ return nullptr;
+ }
+
+ if (srcBounds.contains(*bounds)) {
+ return sk_sp<SkSpecialImage>(SkRef(src));
+ } else {
+ sk_sp<SkSpecialImage> img(pad_image(src, ctx.outputProperties(),
+ bounds->width(), bounds->height(),
+ Sk32_sat_sub(srcOffset->x(), bounds->x()),
+ Sk32_sat_sub(srcOffset->y(), bounds->y())));
+ *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
+ return img;
+ }
+}
+
+SkIRect SkImageFilter_Base::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
+ MapDirection dir, const SkIRect* inputRect) const {
+ if (this->countInputs() < 1) {
+ return src;
+ }
+
+ SkIRect totalBounds;
+ for (int i = 0; i < this->countInputs(); ++i) {
+ const SkImageFilter* filter = this->getInput(i);
+ SkIRect rect = filter ? filter->filterBounds(src, ctm, dir, inputRect) : src;
+ if (0 == i) {
+ totalBounds = rect;
+ } else {
+ totalBounds.join(rect);
}
}
- sk_sp<SkSpecialImage> result(this->onFilterImage(src, context, offset));
+ return totalBounds;
+}
-#if SK_SUPPORT_GPU
- if (src->isTextureBacked() && result && !result->isTextureBacked()) {
- // Keep the result on the GPU - this is still required for some
- // image filters that don't support GPU in all cases
- auto context = src->getContext();
- result = result->makeTextureImage(context);
- }
-#endif
+SkIRect SkImageFilter_Base::onFilterNodeBounds(const SkIRect& src, const SkMatrix&,
+ MapDirection, const SkIRect*) const {
+ return src;
+}
- if (result && context.cache()) {
- context.cache()->set(key, result.get(), *offset, this);
+sk_sp<SkSpecialImage> SkImageFilter_Base::filterInput(int index,
+ SkSpecialImage* src,
+ const Context& ctx,
+ SkIPoint* offset) const {
+ const SkImageFilter* input = this->getInput(index);
+ if (!input) {
+ return sk_sp<SkSpecialImage>(SkRef(src));
}
+ sk_sp<SkSpecialImage> result(as_IFB(input)->filterImage(src, this->mapContext(ctx), offset));
+
+ SkASSERT(!result || src->isTextureBacked() == result->isTextureBacked());
+
return result;
}
-SkIRect SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
- MapDirection direction, const SkIRect* inputRect) const {
- if (kReverse_MapDirection == direction) {
- SkIRect bounds = this->onFilterNodeBounds(src, ctm, direction, inputRect);
- return this->onFilterBounds(bounds, ctm, direction, &bounds);
- } else {
- SkASSERT(!inputRect);
- SkIRect bounds = this->onFilterBounds(src, ctm, direction, nullptr);
- bounds = this->onFilterNodeBounds(bounds, ctm, direction, nullptr);
- SkIRect dst;
- this->getCropRect().applyTo(bounds, ctm, this->affectsTransparentBlack(), &dst);
- return dst;
- }
-}
-
-SkRect SkImageFilter::computeFastBounds(const SkRect& src) const {
- if (0 == this->countInputs()) {
- return src;
- }
- SkRect combinedBounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
- for (int i = 1; i < this->countInputs(); i++) {
- SkImageFilter* input = this->getInput(i);
- if (input) {
- combinedBounds.join(input->computeFastBounds(src));
- } else {
- combinedBounds.join(src);
- }
- }
- return combinedBounds;
-}
-
-bool SkImageFilter::canComputeFastBounds() const {
- if (this->affectsTransparentBlack()) {
- return false;
- }
- for (int i = 0; i < this->countInputs(); i++) {
- SkImageFilter* input = this->getInput(i);
- if (input && !input->canComputeFastBounds()) {
- return false;
- }
- }
- return true;
+SkImageFilter_Base::Context SkImageFilter_Base::mapContext(const Context& ctx) const {
+ SkIRect clipBounds = this->onFilterNodeBounds(ctx.clipBounds(), ctx.ctm(),
+ MapDirection::kReverse_MapDirection,
+ &ctx.clipBounds());
+ return Context(ctx.ctm(), clipBounds, ctx.cache(), ctx.outputProperties());
}
#if SK_SUPPORT_GPU
-sk_sp<SkSpecialImage> SkImageFilter::DrawWithFP(GrRecordingContext* context,
- std::unique_ptr<GrFragmentProcessor> fp,
- const SkIRect& bounds,
- const OutputProperties& outputProperties,
- GrProtected isProtected) {
+sk_sp<SkSpecialImage> SkImageFilter_Base::DrawWithFP(GrRecordingContext* context,
+ std::unique_ptr<GrFragmentProcessor> fp,
+ const SkIRect& bounds,
+ const OutputProperties& outputProperties,
+ GrProtected isProtected) {
GrPaint paint;
paint.addColorFragmentProcessor(std::move(fp));
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
@@ -282,52 +447,9 @@
renderTargetContext->asTextureProxyRef(),
renderTargetContext->colorSpaceInfo().refColorSpace());
}
-#endif
-bool SkImageFilter::asAColorFilter(SkColorFilter** filterPtr) const {
- SkASSERT(nullptr != filterPtr);
- if (!this->isColorFilterNode(filterPtr)) {
- return false;
- }
- if (nullptr != this->getInput(0) || (*filterPtr)->affectsTransparentBlack()) {
- (*filterPtr)->unref();
- return false;
- }
- return true;
-}
-
-bool SkImageFilter::canHandleComplexCTM() const {
- // CropRects need to apply in the source coordinate system, but are not aware of complex CTMs
- // when performing clipping. For a simple fix, any filter with a crop rect set cannot support
- // complex CTMs until that's updated.
- if (this->cropRectIsSet() || !this->onCanHandleComplexCTM()) {
- return false;
- }
- const int count = this->countInputs();
- for (int i = 0; i < count; ++i) {
- SkImageFilter* input = this->getInput(i);
- if (input && !input->canHandleComplexCTM()) {
- return false;
- }
- }
- return true;
-}
-
-bool SkImageFilter::applyCropRect(const Context& ctx, const SkIRect& srcBounds,
- SkIRect* dstBounds) const {
- SkIRect tmpDst = this->onFilterNodeBounds(srcBounds, ctx.ctm(), kForward_MapDirection, nullptr);
- fCropRect.applyTo(tmpDst, ctx.ctm(), this->affectsTransparentBlack(), dstBounds);
- // Intersect against the clip bounds, in case the crop rect has
- // grown the bounds beyond the original clip. This can happen for
- // example in tiling, where the clip is much smaller than the filtered
- // primitive. If we didn't do this, we would be processing the filter
- // at the full crop rect size in every tile.
- return dstBounds->intersect(ctx.clipBounds());
-}
-
-#if SK_SUPPORT_GPU
-sk_sp<SkSpecialImage> SkImageFilter::ImageToColorSpace(SkSpecialImage* src,
- const OutputProperties& outProps) {
+sk_sp<SkSpecialImage> SkImageFilter_Base::ImageToColorSpace(SkSpecialImage* src,
+ const OutputProperties& outProps) {
// There are several conditions that determine if we actually need to convert the source to the
// destination's color space. Rather than duplicate that logic here, just try to make an xform
// object. If that produces something, then both are tagged, and the source is in a different
@@ -356,134 +478,12 @@
}
#endif
-// Return a larger (newWidth x newHeight) copy of 'src' with black padding
-// around it.
-static sk_sp<SkSpecialImage> pad_image(SkSpecialImage* src,
- const SkImageFilter::OutputProperties& outProps,
- int newWidth, int newHeight, int offX, int offY) {
- // We would like to operate in the source's color space (so that we return an "identical"
- // image, other than the padding. To achieve that, we'd create new output properties:
- //
- // SkImageFilter::OutputProperties outProps(src->getColorSpace());
- //
- // That fails in at least two ways. For formats that are texturable but not renderable (like
- // F16 on some ES implementations), we can't create a surface to do the work. For sRGB, images
- // may be tagged with an sRGB color space (which leads to an sRGB config in makeSurface). But
- // the actual config of that sRGB image on a device with no sRGB support is non-sRGB.
- //
- // Rather than try to special case these situations, we execute the image padding in the
- // destination color space. This should not affect the output of the DAG in (almost) any case,
- // because the result of this call is going to be used as an input, where it would have been
- // switched to the destination space anyway. The one exception would be a filter that expected
- // to consume unclamped F16 data, but the padded version of the image is pre-clamped to 8888.
- // We can revisit this logic if that ever becomes an actual problem.
- sk_sp<SkSpecialSurface> surf(src->makeSurface(outProps, SkISize::Make(newWidth, newHeight)));
- if (!surf) {
- return nullptr;
- }
-
- SkCanvas* canvas = surf->getCanvas();
- SkASSERT(canvas);
-
- canvas->clear(0x0);
-
- src->draw(canvas, offX, offY, nullptr);
-
- return surf->makeImageSnapshot();
-}
-
-sk_sp<SkSpecialImage> SkImageFilter::applyCropRectAndPad(const Context& ctx,
- SkSpecialImage* src,
- SkIPoint* srcOffset,
- SkIRect* bounds) const {
- const SkIRect srcBounds = SkIRect::MakeXYWH(srcOffset->x(), srcOffset->y(),
- src->width(), src->height());
-
- if (!this->applyCropRect(ctx, srcBounds, bounds)) {
- return nullptr;
- }
-
- if (srcBounds.contains(*bounds)) {
- return sk_sp<SkSpecialImage>(SkRef(src));
- } else {
- sk_sp<SkSpecialImage> img(pad_image(src, ctx.outputProperties(),
- bounds->width(), bounds->height(),
- Sk32_sat_sub(srcOffset->x(), bounds->x()),
- Sk32_sat_sub(srcOffset->y(), bounds->y())));
- *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
- return img;
- }
-}
-
-SkIRect SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
- MapDirection dir, const SkIRect* inputRect) const {
- if (this->countInputs() < 1) {
- return src;
- }
-
- SkIRect totalBounds;
- for (int i = 0; i < this->countInputs(); ++i) {
- SkImageFilter* filter = this->getInput(i);
- SkIRect rect = filter ? filter->filterBounds(src, ctm, dir, inputRect) : src;
- if (0 == i) {
- totalBounds = rect;
- } else {
- totalBounds.join(rect);
- }
- }
-
- return totalBounds;
-}
-
-SkIRect SkImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix&,
- MapDirection, const SkIRect*) const {
- return src;
-}
-
-
-SkImageFilter::Context SkImageFilter::mapContext(const Context& ctx) const {
- SkIRect clipBounds = this->onFilterNodeBounds(ctx.clipBounds(), ctx.ctm(),
- MapDirection::kReverse_MapDirection,
- &ctx.clipBounds());
- return Context(ctx.ctm(), clipBounds, ctx.cache(), ctx.outputProperties());
-}
-
-sk_sp<SkImageFilter> SkImageFilter::MakeMatrixFilter(const SkMatrix& matrix,
- SkFilterQuality filterQuality,
- sk_sp<SkImageFilter> input) {
- return SkMatrixImageFilter::Make(matrix, filterQuality, std::move(input));
-}
-
-sk_sp<SkImageFilter> SkImageFilter::makeWithLocalMatrix(const SkMatrix& matrix) const {
- return SkLocalMatrixImageFilter::Make(matrix, this->refMe());
-}
-
-sk_sp<SkSpecialImage> SkImageFilter::filterInput(int index,
- SkSpecialImage* src,
- const Context& ctx,
- SkIPoint* offset) const {
- SkImageFilter* input = this->getInput(index);
- if (!input) {
- return sk_sp<SkSpecialImage>(SkRef(src));
- }
-
- sk_sp<SkSpecialImage> result(input->filterImage(src, this->mapContext(ctx), offset));
-
- SkASSERT(!result || src->isTextureBacked() == result->isTextureBacked());
-
- return result;
-}
-
-void SkImageFilter::PurgeCache() {
- SkImageFilterCache::Get()->purge();
-}
-
// In repeat mode, when we are going to sample off one edge of the srcBounds we require the
// opposite side be preserved.
-SkIRect SkImageFilter::DetermineRepeatedSrcBound(const SkIRect& srcBounds,
- const SkIVector& filterOffset,
- const SkISize& filterSize,
- const SkIRect& originalSrcBounds) {
+SkIRect SkImageFilter_Base::DetermineRepeatedSrcBound(const SkIRect& srcBounds,
+ const SkIVector& filterOffset,
+ const SkISize& filterSize,
+ const SkIRect& originalSrcBounds) {
SkIRect tmp = srcBounds;
tmp.adjust(-filterOffset.fX, -filterOffset.fY,
filterSize.fWidth - filterOffset.fX, filterSize.fHeight - filterOffset.fY);
@@ -500,11 +500,13 @@
return tmp;
}
-/////////////////////////////////////////////////////////////////////////////////////////////////
+void SkImageFilter_Base::PurgeCache() {
+ SkImageFilterCache::Get()->purge();
+}
static sk_sp<SkImageFilter> apply_ctm_to_filter(sk_sp<SkImageFilter> input, const SkMatrix& ctm,
SkMatrix* remainder, bool asBackdrop) {
- if (ctm.isScaleTranslate() || input->canHandleComplexCTM()) {
+ if (ctm.isScaleTranslate() || as_IFB(input)->canHandleComplexCTM()) {
// The filter supports the CTM, so leave it as-is and 'remainder' stores the whole CTM
*remainder = ctm;
return input;
@@ -556,29 +558,14 @@
SkMatrixImageFilter::Make(invEmbed, kLow_SkFilterQuality, nullptr));
}
}
- return SkMatrixImageFilter::Make(ctmToEmbed, kLow_SkFilterQuality, std::move(input));
+ return SkMatrixImageFilter::Make(ctmToEmbed, kLow_SkFilterQuality, input);
}
-sk_sp<SkImageFilter> SkApplyCTMToFilter(const SkImageFilter* filter, const SkMatrix& ctm,
- SkMatrix* remainder) {
- return apply_ctm_to_filter(sk_ref_sp(filter), ctm, remainder, false);
+sk_sp<SkImageFilter> SkImageFilter_Base::applyCTM(const SkMatrix& ctm, SkMatrix* remainder) const {
+ return apply_ctm_to_filter(this->refMe(), ctm, remainder, false);
}
-sk_sp<SkImageFilter> SkApplyCTMToBackdropFilter(const SkImageFilter* filter, const SkMatrix& ctm,
- SkMatrix* remainder) {
- return apply_ctm_to_filter(sk_ref_sp(filter), ctm, remainder, true);
-}
-
-bool SkIsSameFilter(const SkImageFilter* a, const SkImageFilter* b) {
- if (!a || !b) {
- // The filters are the "same" if they're both null
- return !a && !b;
- } else {
- return a->fUniqueID == b->fUniqueID;
- }
-}
-
-SkIRect SkFilterNodeBounds(const SkImageFilter* filter, const SkIRect& srcRect, const SkMatrix& ctm,
- SkImageFilter::MapDirection dir, const SkIRect* inputRect) {
- return filter->onFilterNodeBounds(srcRect, ctm, dir, inputRect);
+sk_sp<SkImageFilter> SkImageFilter_Base::applyCTMForBackdrop(const SkMatrix& ctm,
+ SkMatrix* remainder) const {
+ return apply_ctm_to_filter(this->refMe(), ctm, remainder, true);
}
diff --git a/src/core/SkImageFilterPriv.h b/src/core/SkImageFilterPriv.h
deleted file mode 100644
index 690979e..0000000
--- a/src/core/SkImageFilterPriv.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkImageFilterPriv_DEFINED
-#define SkImageFilterPriv_DEFINED
-
-#include "include/core/SkImageFilter.h"
-
-/**
- * Helper to unflatten the common data, and return nullptr if we fail.
- */
-#define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount) \
- Common localVar; \
- do { \
- if (!localVar.unflatten(buffer, expectedCount)) { \
- return nullptr; \
- } \
- } while (0)
-
-/**
- * Return an image filter representing this filter applied with the given ctm. This will modify the
- * DAG as needed if this filter does not support complex CTMs and 'ctm' is not simple. The ctm
- * matrix will be decomposed such that ctm = A*B; B will be incorporated directly into the DAG and A
- * must be the ctm set on the context passed to filterImage(). 'remainder' will be set to A.
- *
- * If this filter supports complex ctms, or 'ctm' is not complex, then A = ctm and B = I. When the
- * filter does not support complex ctms, and the ctm is complex, then A represents the extracted
- * simple portion of the ctm, and the complex portion is baked into a new DAG using a matrix filter.
- *
- * This will never return null.
- */
-sk_sp<SkImageFilter> SkApplyCTMToFilter(const SkImageFilter* filter, const SkMatrix& ctm,
- SkMatrix* remainder);
-
-/**
- * Similar to SkApplyCTMToFilter except this assumes the input content is an existing backdrop image
- * to be filtered. As such, the input to this filter will also be transformed by B^-1 if the filter
- * can't support complex CTMs, since backdrop content is already in device space and must be
- * transformed back into the CTM's local space.
- */
-sk_sp<SkImageFilter> SkApplyCTMToBackdropFilter(const SkImageFilter* filter, const SkMatrix& ctm,
- SkMatrix* remainder);
-
-bool SkIsSameFilter(const SkImageFilter* a, const SkImageFilter* b);
-
-// Exposes just the behavior of the protected SkImageFilter::onFilterNodeBounds()
-SkIRect SkFilterNodeBounds(const SkImageFilter* filter, const SkIRect& srcRect, const SkMatrix& ctm,
- SkImageFilter::MapDirection dir, const SkIRect* inputRect);
-
-#endif
diff --git a/src/core/SkImageFilter_Base.h b/src/core/SkImageFilter_Base.h
new file mode 100644
index 0000000..b2306e4
--- /dev/null
+++ b/src/core/SkImageFilter_Base.h
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkImageFilter_Base_DEFINED
+#define SkImageFilter_Base_DEFINED
+
+#include "include/core/SkColorSpace.h"
+#include "include/core/SkImageFilter.h"
+#include "include/core/SkImageInfo.h"
+#include "include/private/SkTArray.h"
+
+#if SK_SUPPORT_GPU
+#include "include/gpu/GrTypes.h"
+#endif
+
+class GrFragmentProcessor;
+class GrRecordingContext;
+class SkSpecialImage;
+class SkSpecialSurface;
+class SkImageFilterCache;
+struct SkImageFilterCacheKey;
+
+// True base class that all SkImageFilter implementations need to extend from. This provides the
+// actual API surface that Skia will use to compute the filtered images.
+class SkImageFilter_Base : public SkImageFilter {
+public:
+ // Extra information about the output of a filter DAG. For now, this is just the color space
+ // (of the original requesting device). This is used when constructing intermediate rendering
+ // surfaces, so that we ensure we land in a surface that's similar/compatible to the final
+ // consumer of the DAG's output.
+ class OutputProperties {
+ public:
+ explicit OutputProperties(SkColorType colorType, SkColorSpace* colorSpace)
+ : fColorType(colorType), fColorSpace(colorSpace) {}
+
+ SkColorType colorType() const { return fColorType; }
+ SkColorSpace* colorSpace() const { return fColorSpace; }
+
+ private:
+ SkColorType fColorType;
+ // This will be a pointer to the device's color space, and our lifetime is bounded by
+ // the device, so we can store a bare pointer.
+ SkColorSpace* fColorSpace;
+ };
+
+ class Context {
+ public:
+ Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache,
+ const OutputProperties& outputProperties)
+ : fCTM(ctm)
+ , fClipBounds(clipBounds)
+ , fCache(cache)
+ , fOutputProperties(outputProperties)
+ {}
+
+ const SkMatrix& ctm() const { return fCTM; }
+ const SkIRect& clipBounds() const { return fClipBounds; }
+ SkImageFilterCache* cache() const { return fCache; }
+ const OutputProperties& outputProperties() const { return fOutputProperties; }
+
+ /**
+ * Since a context can be build directly, its constructor has no chance to
+ * "return null" if it's given invalid or unsupported inputs. Call this to
+ * know of the the context can be used.
+ *
+ * The SkImageFilterCache Key, for example, requires a finite ctm (no infinities
+ * or NaN), so that test is part of isValid.
+ */
+ bool isValid() const { return fCTM.isFinite(); }
+
+ private:
+ SkMatrix fCTM;
+ SkIRect fClipBounds;
+ SkImageFilterCache* fCache;
+ OutputProperties fOutputProperties;
+ };
+
+ /**
+ * Request a new filtered image to be created from the src image.
+ *
+ * The context contains the environment in which the filter is occurring.
+ * It includes the clip bounds, CTM and cache.
+ *
+ * Offset is the amount to translate the resulting image relative to the
+ * src when it is drawn. This is an out-param.
+ *
+ * If the result image cannot be created, or the result would be
+ * transparent black, return null, in which case the offset parameter
+ * should be ignored by the caller.
+ *
+ * TODO: Right now the imagefilters sometimes return empty result bitmaps/
+ * specialimages. That doesn't seem quite right.
+ */
+ sk_sp<SkSpecialImage> filterImage(SkSpecialImage* src, const Context& context,
+ SkIPoint* offset) const;
+
+ /**
+ * Returns whether any edges of the crop rect have been set. The crop
+ * rect is set at construction time, and determines which pixels from the
+ * input image will be processed, and which pixels in the output image will be allowed.
+ * The size of the crop rect should be
+ * used as the size of the destination image. The origin of this rect
+ * should be used to offset access to the input images, and should also
+ * be added to the "offset" parameter in onFilterImage.
+ */
+ bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
+
+ CropRect getCropRect() const { return fCropRect; }
+
+ // Expose isolated node bounds behavior for SampleImageFilterDAG and debugging
+ SkIRect filterNodeBounds(const SkIRect& srcRect, const SkMatrix& ctm,
+ MapDirection dir, const SkIRect* inputRect) const {
+ return this->onFilterNodeBounds(srcRect, ctm, dir, inputRect);
+ }
+
+ /**
+ * ImageFilters can natively handle scaling and translate components in the CTM. Only some of
+ * them can handle affine (or more complex) matrices. This call returns true iff the filter
+ * and all of its (non-null) inputs can handle these more complex matrices.
+ */
+ bool canHandleComplexCTM() const;
+
+ /**
+ * Return an image filter representing this filter applied with the given ctm. This will modify
+ * the DAG as needed if this filter does not support complex CTMs and 'ctm' is not simple. The
+ * ctm matrix will be decomposed such that ctm = A*B; B will be incorporated directly into the
+ * DAG and A must be the ctm set on the context passed to filterImage(). 'remainder' will be set
+ * to A.
+ *
+ * If this filter supports complex ctms, or 'ctm' is not complex, then A = ctm and B = I. When
+ * the filter does not support complex ctms, and the ctm is complex, then A represents the
+ * extracted simple portion of the ctm, and the complex portion is baked into a new DAG using a
+ * matrix filter.
+ *
+ * This will never return null.
+ */
+ sk_sp<SkImageFilter> applyCTM(const SkMatrix& ctm, SkMatrix* remainder) const;
+ /**
+ * Similar to SkApplyCTMToFilter except this assumes the input content is an existing backdrop
+ * image to be filtered. As such, the input to this filter will also be transformed by B^-1 if
+ * the filter can't support complex CTMs, since backdrop content is already in device space and
+ * must be transformed back into the CTM's local space.
+ */
+ sk_sp<SkImageFilter> applyCTMForBackdrop(const SkMatrix& ctm, SkMatrix* remainder) const;
+
+ uint32_t uniqueID() const { return fUniqueID; }
+
+protected:
+ class Common {
+ public:
+ /**
+ * Attempt to unflatten the cropRect and the expected number of input filters.
+ * If any number of input filters is valid, pass -1.
+ * If this fails (i.e. corrupt buffer or contents) then return false and common will
+ * be left uninitialized.
+ * If this returns true, then inputCount() is the number of found input filters, each
+ * of which may be NULL or a valid imagefilter.
+ */
+ bool unflatten(SkReadBuffer&, int expectedInputs);
+
+ const CropRect& cropRect() const { return fCropRect; }
+ int inputCount() const { return fInputs.count(); }
+ sk_sp<SkImageFilter>* inputs() { return fInputs.begin(); }
+
+ sk_sp<SkImageFilter> getInput(int index) { return fInputs[index]; }
+
+ private:
+ CropRect fCropRect;
+ // most filters accept at most 2 input-filters
+ SkSTArray<2, sk_sp<SkImageFilter>, true> fInputs;
+ };
+
+ SkImageFilter_Base(sk_sp<SkImageFilter> const* inputs, int inputCount,
+ const CropRect* cropRect);
+
+ ~SkImageFilter_Base() override;
+
+ void flatten(SkWriteBuffer&) const override;
+
+ virtual bool affectsTransparentBlack() const { return false; }
+
+ /**
+ * This is the virtual which should be overridden by the derived class
+ * to perform image filtering.
+ *
+ * src is the original primitive bitmap. If the filter has a connected
+ * input, it should recurse on that input and use that in place of src.
+ *
+ * The matrix is the matrix used to draw the geometry into the current
+ * layer that produced the 'src' image. This may be the total canvas'
+ * matrix, or part of its decomposition (depending on what the filter DAG
+ * is able to support).
+ *
+ * Offset is the amount to translate the resulting image relative to the
+ * src when it is drawn. This is an out-param.
+ *
+ * If the result image cannot be created (either because of error or if, say, the result
+ * is entirely clipped out), this should return nullptr.
+ * Callers that affect transparent black should explicitly handle nullptr
+ * results and press on. In the error case this behavior will produce a better result
+ * than nothing and is necessary for the clipped out case.
+ * If the return value is nullptr then offset should be ignored.
+ */
+ virtual sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
+ SkIPoint* offset) const = 0;
+
+ /**
+ * This function recurses into its inputs with the given rect (first
+ * argument), calls filterBounds() with the given map direction on each,
+ * and returns the union of those results. If a derived class has special
+ * recursion requirements (e.g., it has an input which does not participate
+ * in bounds computation), it can be overridden here.
+ * In kReverse mode, 'inputRect' is the device-space bounds of the input pixels. In kForward
+ * mode it should always be null. If 'inputRect' is null in kReverse mode the resulting
+ * answer may be incorrect.
+ *
+ * Note that this function is *not* responsible for mapping the rect for
+ * this node's filter bounds requirements (i.e., calling
+ * onFilterNodeBounds()); that is handled by filterBounds().
+ */
+ virtual SkIRect onFilterBounds(const SkIRect&, const SkMatrix& ctm,
+ MapDirection, const SkIRect* inputRect) const;
+
+ /**
+ * Performs a forwards or reverse mapping of the given rect to accommodate
+ * this filter's margin requirements. kForward_MapDirection is used to
+ * determine the destination pixels which would be touched by filtering
+ * the given source rect (e.g., given source bitmap bounds,
+ * determine the optimal bounds of the filtered offscreen bitmap).
+ * kReverse_MapDirection is used to determine which pixels of the
+ * input(s) would be required to fill the given destination rect
+ * (e.g., clip bounds). NOTE: these operations may not be the
+ * inverse of the other. For example, blurring expands the given rect
+ * in both forward and reverse directions. Unlike
+ * onFilterBounds(), this function is non-recursive.
+ * In kReverse mode, 'inputRect' will be the device space bounds of the input pixels. In
+ * kForward mode, 'inputRect' should always be null. If 'inputRect' is null in kReverse mode
+ * the resulting answer may be incorrect.
+ */
+ virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm,
+ MapDirection, const SkIRect* inputRect) const;
+
+ // Helper function which invokes filter processing on the input at the
+ // specified "index". If the input is null, it returns "src" and leaves
+ // "offset" untouched. If the input is non-null, it
+ // calls filterImage() on that input, and returns the result.
+ sk_sp<SkSpecialImage> filterInput(int index,
+ SkSpecialImage* src,
+ const Context&,
+ SkIPoint* offset) const;
+
+ /**
+ * Return true (and returns a ref'd colorfilter) if this node in the DAG is just a
+ * colorfilter w/o CropRect constraints.
+ */
+ virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const {
+ return false;
+ }
+
+ /**
+ * Override this to describe the behavior of your subclass - as a leaf node. The caller will
+ * take care of calling your inputs (and return false if any of them could not handle it).
+ */
+ virtual bool onCanHandleComplexCTM() const { return false; }
+
+ const CropRect* getCropRectIfSet() const {
+ return this->cropRectIsSet() ? &fCropRect : nullptr;
+ }
+
+ /** Given a "srcBounds" rect, computes destination bounds for this filter.
+ * "dstBounds" are computed by transforming the crop rect by the context's
+ * CTM, applying it to the initial bounds, and intersecting the result with
+ * the context's clip bounds. "srcBounds" (if non-null) are computed by
+ * intersecting the initial bounds with "dstBounds", to ensure that we never
+ * sample outside of the crop rect (this restriction may be relaxed in the
+ * future).
+ */
+ bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const;
+
+ /** A variant of the above call which takes the original source bitmap and
+ * source offset. If the resulting crop rect is not entirely contained by
+ * the source bitmap's bounds, it creates a new bitmap in "result" and
+ * pads the edges with transparent black. In that case, the srcOffset is
+ * modified to be the same as the bounds, since no further adjustment is
+ * needed by the caller. This version should only be used by filters
+ * which are not capable of processing a smaller source bitmap into a
+ * larger destination.
+ */
+ sk_sp<SkSpecialImage> applyCropRectAndPad(const Context&, SkSpecialImage* src,
+ SkIPoint* srcOffset, SkIRect* bounds) const;
+
+ /**
+ * Creates a modified Context for use when recursing up the image filter DAG.
+ * The clip bounds are adjusted to accommodate any margins that this
+ * filter requires by calling this node's
+ * onFilterNodeBounds(..., kReverse_MapDirection).
+ */
+ Context mapContext(const Context& ctx) const;
+
+#if SK_SUPPORT_GPU
+ static sk_sp<SkSpecialImage> DrawWithFP(GrRecordingContext* context,
+ std::unique_ptr<GrFragmentProcessor>
+ fp,
+ const SkIRect& bounds,
+ const OutputProperties& outputProperties,
+ GrProtected isProtected = GrProtected::kNo);
+
+ /**
+ * Returns a version of the passed-in image (possibly the original), that is in a colorspace
+ * with the same gamut as the one from the OutputProperties. This allows filters that do many
+ * texture samples to guarantee that any color space conversion has happened before running.
+ */
+ static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src, const OutputProperties&);
+#endif
+
+ // If 'srcBounds' will sample outside the border of 'originalSrcBounds' (i.e., the sample
+ // will wrap around to the other side) we must preserve the far side of the src along that
+ // axis (e.g., if we will sample beyond the left edge of the src, the right side must be
+ // preserved for the repeat sampling to work).
+ static SkIRect DetermineRepeatedSrcBound(const SkIRect& srcBounds,
+ const SkIVector& filterOffset,
+ const SkISize& filterSize,
+ const SkIRect& originalSrcBounds);
+
+private:
+ friend class SkImageFilter;
+ // For PurgeCache()
+ friend class SkGraphics;
+
+ static void PurgeCache();
+
+ void init(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect);
+
+ SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
+
+ bool fUsesSrcInput;
+ CropRect fCropRect;
+ uint32_t fUniqueID; // Globally unique
+
+ typedef SkImageFilter INHERITED;
+};
+
+static inline SkImageFilter_Base* as_IFB(SkImageFilter* filter) {
+ return static_cast<SkImageFilter_Base*>(filter);
+}
+
+static inline SkImageFilter_Base* as_IFB(const sk_sp<SkImageFilter>& filter) {
+ return static_cast<SkImageFilter_Base*>(filter.get());
+}
+
+static inline const SkImageFilter_Base* as_IFB(const SkImageFilter* filter) {
+ return static_cast<const SkImageFilter_Base*>(filter);
+}
+
+/**
+ * Helper to unflatten the common data, and return nullptr if we fail.
+ */
+#define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount) \
+ Common localVar; \
+ do { \
+ if (!localVar.unflatten(buffer, expectedCount)) { \
+ return nullptr; \
+ } \
+ } while (0)
+
+#endif // SkImageFilter_Base_DEFINED
diff --git a/src/core/SkLocalMatrixImageFilter.cpp b/src/core/SkLocalMatrixImageFilter.cpp
index 97d8002..9092c5a 100644
--- a/src/core/SkLocalMatrixImageFilter.cpp
+++ b/src/core/SkLocalMatrixImageFilter.cpp
@@ -6,7 +6,6 @@
*/
#include "include/core/SkString.h"
-#include "src/core/SkImageFilterPriv.h"
#include "src/core/SkLocalMatrixImageFilter.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
@@ -19,7 +18,7 @@
if (localM.isIdentity()) {
return input;
}
- if (!input->canHandleComplexCTM() && !localM.isScaleTranslate()) {
+ if (!as_IFB(input)->canHandleComplexCTM() && !localM.isScaleTranslate()) {
// Nothing we can do at this point
return nullptr;
}
diff --git a/src/core/SkLocalMatrixImageFilter.h b/src/core/SkLocalMatrixImageFilter.h
index a96e609..132c302 100644
--- a/src/core/SkLocalMatrixImageFilter.h
+++ b/src/core/SkLocalMatrixImageFilter.h
@@ -9,13 +9,13 @@
#define SkLocalMatrixImageFilter_DEFINED
#include "include/core/SkFlattenable.h"
-#include "include/core/SkImageFilter.h"
+#include "src/core/SkImageFilter_Base.h"
/**
* Wraps another imagefilter + matrix, such that using this filter will give the same result
* as using the wrapped filter with the matrix applied to its context.
*/
-class SkLocalMatrixImageFilter : public SkImageFilter {
+class SkLocalMatrixImageFilter : public SkImageFilter_Base {
public:
static sk_sp<SkImageFilter> Make(const SkMatrix& localM, sk_sp<SkImageFilter> input);
@@ -35,7 +35,7 @@
SkMatrix fLocalM;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
#endif
diff --git a/src/core/SkMatrixImageFilter.cpp b/src/core/SkMatrixImageFilter.cpp
index 66ea469..9a69c8e 100644
--- a/src/core/SkMatrixImageFilter.cpp
+++ b/src/core/SkMatrixImageFilter.cpp
@@ -9,7 +9,6 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkRect.h"
-#include "src/core/SkImageFilterPriv.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
diff --git a/src/core/SkMatrixImageFilter.h b/src/core/SkMatrixImageFilter.h
index b13efb2..b8c571d 100644
--- a/src/core/SkMatrixImageFilter.h
+++ b/src/core/SkMatrixImageFilter.h
@@ -9,15 +9,15 @@
#define SkMatrixImageFilter_DEFINED
#include "include/core/SkFlattenable.h"
-#include "include/core/SkImageFilter.h"
#include "include/core/SkMatrix.h"
+#include "src/core/SkImageFilter_Base.h"
/*! \class SkMatrixImageFilter
Matrix transformation image filter. This filter draws its source
input transformed by the given matrix.
*/
-class SkMatrixImageFilter : public SkImageFilter {
+class SkMatrixImageFilter : public SkImageFilter_Base {
public:
/** Construct a 2D transformation image filter.
* @param transform The matrix to apply when drawing the src bitmap
@@ -48,7 +48,7 @@
SkMatrix fTransform;
SkFilterQuality fFilterQuality;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
#endif
diff --git a/src/core/SkPicturePriv.h b/src/core/SkPicturePriv.h
index c14751c..fc3b06d 100644
--- a/src/core/SkPicturePriv.h
+++ b/src/core/SkPicturePriv.h
@@ -73,6 +73,7 @@
// V70: Image filters definitions hidden, registered names updated to include "Impl"
// V71: Unify erode and dilate image filters
// V72: SkColorFilter_Matrix domain (rgba vs. hsla)
+
enum Version {
kTileModeInBlurImageFilter_Version = 56,
kTileInfoInSweepGradient_Version = 57,
diff --git a/src/core/SkResourceCache.cpp b/src/core/SkResourceCache.cpp
index 1208937d..61197f8 100644
--- a/src/core/SkResourceCache.cpp
+++ b/src/core/SkResourceCache.cpp
@@ -11,6 +11,7 @@
#include "include/private/SkMutex.h"
#include "include/private/SkTo.h"
#include "src/core/SkDiscardableMemory.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkMessageBus.h"
#include "src/core/SkMipMap.h"
#include "src/core/SkOpts.h"
@@ -566,7 +567,7 @@
}
void SkGraphics::PurgeResourceCache() {
- SkImageFilter::PurgeCache();
+ SkImageFilter_Base::PurgeCache();
return SkResourceCache::PurgeAll();
}
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index 4e113a4..2f5cf2d 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -57,16 +57,17 @@
// from the content rect by the non-virtual makeSubset().
virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
- virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
- const SkISize& size, SkAlphaType at,
- const SkSurfaceProps* = nullptr) const = 0;
+ virtual sk_sp<SkSpecialSurface> onMakeSurface(
+ const SkImageFilter_Base::OutputProperties& outProps, const SkISize& size,
+ SkAlphaType at, const SkSurfaceProps* = nullptr) const = 0;
// This subset (when not null) is relative to the backing store's coordinate frame, it has
// already been mapped from the content rect by the non-virtual asImage().
virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
- virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
- const SkISize& size, SkAlphaType at) const = 0;
+ virtual sk_sp<SkSurface> onMakeTightSurface(
+ const SkImageFilter_Base::OutputProperties& outProps,
+ const SkISize& size, SkAlphaType at) const = 0;
private:
typedef SkSpecialImage INHERITED;
@@ -157,14 +158,15 @@
}
#endif
-sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
- const SkISize& size, SkAlphaType at,
- const SkSurfaceProps* props) const {
+sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(
+ const SkImageFilter_Base::OutputProperties& outProps, const SkISize& size,
+ SkAlphaType at, const SkSurfaceProps* props) const {
return as_SIB(this)->onMakeSurface(outProps, size, at, props);
}
-sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
- const SkISize& size, SkAlphaType at) const {
+sk_sp<SkSurface> SkSpecialImage::makeTightSurface(
+ const SkImageFilter_Base::OutputProperties& outProps, const SkISize& size,
+ SkAlphaType at) const {
return as_SIB(this)->onMakeTightSurface(outProps, size, at);
}
@@ -263,7 +265,7 @@
}
#endif
- sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
+ sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter_Base::OutputProperties& outProps,
const SkISize& size, SkAlphaType at,
const SkSurfaceProps* props) const override {
SkColorSpace* colorSpace = outProps.colorSpace();
@@ -292,7 +294,7 @@
return SkImage::MakeFromBitmap(fBitmap);
}
- sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
+ sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter_Base::OutputProperties& outProps,
const SkISize& size, SkAlphaType at) const override {
SkColorSpace* colorSpace = outProps.colorSpace();
SkColorType colorType = kN32_SkColorType; // TODO: find ways to allow f16
@@ -453,7 +455,7 @@
return fColorSpace.get();
}
- sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
+ sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter_Base::OutputProperties& outProps,
const SkISize& size, SkAlphaType at,
const SkSurfaceProps* props) const override {
if (!fContext) {
@@ -507,7 +509,7 @@
return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace);
}
- sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
+ sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter_Base::OutputProperties& outProps,
const SkISize& size, SkAlphaType at) const override {
SkColorSpace* colorSpace = outProps.colorSpace();
SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
diff --git a/src/core/SkSpecialImage.h b/src/core/SkSpecialImage.h
index 77b9cbf..eb9aa3e 100644
--- a/src/core/SkSpecialImage.h
+++ b/src/core/SkSpecialImage.h
@@ -8,13 +8,12 @@
#ifndef SkSpecialImage_DEFINED
#define SkSpecialImage_DEFINED
+#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurfaceProps.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkNextID.h"
-#include "include/core/SkImageFilter.h"
-#include "include/core/SkImageInfo.h"
-
class GrRecordingContext;
class GrTextureProxy;
class SkBitmap;
@@ -92,7 +91,7 @@
/**
* Create a new special surface with a backend that is compatible with this special image.
*/
- sk_sp<SkSpecialSurface> makeSurface(const SkImageFilter::OutputProperties& outProps,
+ sk_sp<SkSpecialSurface> makeSurface(const SkImageFilter_Base::OutputProperties& outProps,
const SkISize& size,
SkAlphaType at = kPremul_SkAlphaType,
const SkSurfaceProps* props = nullptr) const;
@@ -101,7 +100,7 @@
* Create a new surface with a backend that is compatible with this special image.
* TODO: switch this to makeSurface once we resolved the naming issue
*/
- sk_sp<SkSurface> makeTightSurface(const SkImageFilter::OutputProperties& outProps,
+ sk_sp<SkSurface> makeTightSurface(const SkImageFilter_Base::OutputProperties& outProps,
const SkISize& size,
SkAlphaType at = kPremul_SkAlphaType) const;
diff --git a/src/effects/imagefilters/SkAlphaThresholdFilter.cpp b/src/effects/imagefilters/SkAlphaThresholdFilter.cpp
index 8a15884..110ef7c 100644
--- a/src/effects/imagefilters/SkAlphaThresholdFilter.cpp
+++ b/src/effects/imagefilters/SkAlphaThresholdFilter.cpp
@@ -9,7 +9,7 @@
#include "include/core/SkBitmap.h"
#include "include/core/SkRegion.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkWriteBuffer.h"
@@ -29,7 +29,7 @@
namespace {
-class SkAlphaThresholdFilterImpl final : public SkImageFilter {
+class SkAlphaThresholdFilterImpl final : public SkImageFilter_Base {
public:
SkAlphaThresholdFilterImpl(const SkRegion& region, SkScalar innerThreshold,
SkScalar outerThreshold, sk_sp<SkImageFilter> input,
@@ -59,7 +59,7 @@
SkScalar fInnerThreshold;
SkScalar fOuterThreshold;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
}; // end namespace
diff --git a/src/effects/imagefilters/SkArithmeticImageFilter.cpp b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
index 9eb794a..4ef8a07 100644
--- a/src/effects/imagefilters/SkArithmeticImageFilter.cpp
+++ b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
@@ -10,7 +10,7 @@
#include "include/core/SkCanvas.h"
#include "include/effects/SkXfermodeImageFilter.h"
#include "include/private/SkNx.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
@@ -48,7 +48,7 @@
namespace {
-class ArithmeticImageFilterImpl final : public SkImageFilter {
+class ArithmeticImageFilterImpl final : public SkImageFilter_Base {
public:
ArithmeticImageFilterImpl(float k1, float k2, float k3, float k4, bool enforcePMColor,
sk_sp<SkImageFilter> inputs[2], const CropRect* cropRect)
@@ -84,7 +84,7 @@
const float fK[4];
const bool fEnforcePMColor;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
}; // end namespace
@@ -273,7 +273,7 @@
MapDirection dir,
const SkIRect* inputRect) const {
if (kReverse_MapDirection == dir) {
- return SkImageFilter::onFilterBounds(src, ctm, dir, inputRect);
+ return INHERITED::onFilterBounds(src, ctm, dir, inputRect);
}
SkASSERT(2 == this->countInputs());
diff --git a/src/effects/imagefilters/SkBlurImageFilter.cpp b/src/effects/imagefilters/SkBlurImageFilter.cpp
index 9a8161f..3f0d5e6 100644
--- a/src/effects/imagefilters/SkBlurImageFilter.cpp
+++ b/src/effects/imagefilters/SkBlurImageFilter.cpp
@@ -17,7 +17,7 @@
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkGpuBlurUtils.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkOpts.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
@@ -29,11 +29,9 @@
#include "src/gpu/SkGr.h"
#endif
-static constexpr double kPi = 3.14159265358979323846264338327950288;
-
namespace {
-class SkBlurImageFilterImpl final : public SkImageFilter {
+class SkBlurImageFilterImpl final : public SkImageFilter_Base {
public:
SkBlurImageFilterImpl(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode,
sk_sp<SkImageFilter> input, const CropRect* cropRect)
@@ -64,7 +62,7 @@
SkSize fSigma;
SkTileMode fTileMode;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
@@ -168,7 +166,7 @@
// window = floor(sigma * 3 * sqrt(2 * kPi) / 4 + 0.5)
// For window <= 255, the largest value for sigma is 136.
sigma = SkTPin(sigma, 0.0, 136.0);
- auto possibleWindow = static_cast<int>(floor(sigma * 3 * sqrt(2 * kPi) / 4 + 0.5));
+ auto possibleWindow = static_cast<int>(floor(sigma * 3 * sqrt(2 * SK_DoublePI) / 4 + 0.5));
return std::max(1, possibleWindow);
}
diff --git a/src/effects/imagefilters/SkColorFilterImageFilter.cpp b/src/effects/imagefilters/SkColorFilterImageFilter.cpp
index 9baaa27..0d44a68 100644
--- a/src/effects/imagefilters/SkColorFilterImageFilter.cpp
+++ b/src/effects/imagefilters/SkColorFilterImageFilter.cpp
@@ -9,7 +9,7 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkColorFilter.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
@@ -17,7 +17,7 @@
namespace {
-class SkColorFilterImageFilterImpl final : public SkImageFilter {
+class SkColorFilterImageFilterImpl final : public SkImageFilter_Base {
public:
SkColorFilterImageFilterImpl(sk_sp<SkColorFilter> cf, sk_sp<SkImageFilter> input,
const CropRect* cropRect)
@@ -38,7 +38,7 @@
sk_sp<SkColorFilter> fColorFilter;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
diff --git a/src/effects/imagefilters/SkComposeImageFilter.cpp b/src/effects/imagefilters/SkComposeImageFilter.cpp
index a09006a..48ec150 100644
--- a/src/effects/imagefilters/SkComposeImageFilter.cpp
+++ b/src/effects/imagefilters/SkComposeImageFilter.cpp
@@ -7,14 +7,14 @@
#include "include/effects/SkComposeImageFilter.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkWriteBuffer.h"
namespace {
-class SkComposeImageFilterImpl final : public SkImageFilter {
+class SkComposeImageFilterImpl final : public SkImageFilter_Base {
public:
explicit SkComposeImageFilterImpl(sk_sp<SkImageFilter> inputs[2])
: INHERITED(inputs, 2, nullptr) {
@@ -35,7 +35,7 @@
friend void SkComposeImageFilter::RegisterFlattenables();
SK_FLATTENABLE_HOOKS(SkComposeImageFilterImpl)
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
@@ -66,8 +66,8 @@
}
SkRect SkComposeImageFilterImpl::computeFastBounds(const SkRect& src) const {
- SkImageFilter* outer = this->getInput(0);
- SkImageFilter* inner = this->getInput(1);
+ const SkImageFilter* outer = this->getInput(0);
+ const SkImageFilter* inner = this->getInput(1);
return outer->computeFastBounds(inner->computeFastBounds(src));
}
@@ -106,8 +106,8 @@
SkIRect SkComposeImageFilterImpl::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
MapDirection dir, const SkIRect* inputRect) const {
- SkImageFilter* outer = this->getInput(0);
- SkImageFilter* inner = this->getInput(1);
+ const SkImageFilter* outer = this->getInput(0);
+ const SkImageFilter* inner = this->getInput(1);
const SkIRect innerRect = inner->filterBounds(src, ctm, dir, inputRect);
return outer->filterBounds(innerRect, ctm, dir,
diff --git a/src/effects/imagefilters/SkDisplacementMapEffect.cpp b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
index 0eb16ab..7d67b1a 100644
--- a/src/effects/imagefilters/SkDisplacementMapEffect.cpp
+++ b/src/effects/imagefilters/SkDisplacementMapEffect.cpp
@@ -10,7 +10,7 @@
#include "include/core/SkBitmap.h"
#include "include/core/SkUnPreMultiply.h"
#include "include/private/SkColorData.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkWriteBuffer.h"
@@ -34,7 +34,7 @@
namespace {
-class SkDisplacementMapEffectImpl final : public SkImageFilter {
+class SkDisplacementMapEffectImpl final : public SkImageFilter_Base {
public:
SkDisplacementMapEffectImpl(SkColorChannel xChannelSelector, SkColorChannel yChannelSelector,
SkScalar scale, sk_sp<SkImageFilter> inputs[2],
@@ -68,7 +68,7 @@
const SkImageFilter* getDisplacementInput() const { return getInput(0); }
const SkImageFilter* getColorInput() const { return getInput(1); }
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
// Shift values to extract channels from an SkColor (SkColorGetR, SkColorGetG, etc)
diff --git a/src/effects/imagefilters/SkDropShadowImageFilter.cpp b/src/effects/imagefilters/SkDropShadowImageFilter.cpp
index ba5a67a..fd69078 100644
--- a/src/effects/imagefilters/SkDropShadowImageFilter.cpp
+++ b/src/effects/imagefilters/SkDropShadowImageFilter.cpp
@@ -9,7 +9,7 @@
#include "include/core/SkCanvas.h"
#include "include/effects/SkBlurImageFilter.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
@@ -17,7 +17,7 @@
namespace {
-class SkDropShadowImageFilterImpl final : public SkImageFilter {
+class SkDropShadowImageFilterImpl final : public SkImageFilter_Base {
public:
SkDropShadowImageFilterImpl(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY,
SkColor color, bool shadowOnly, sk_sp<SkImageFilter> input,
@@ -47,7 +47,7 @@
SkColor fColor;
bool fShadowOnly;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
diff --git a/src/effects/imagefilters/SkImageSource.cpp b/src/effects/imagefilters/SkImageSource.cpp
index f0893a6..e14526e 100644
--- a/src/effects/imagefilters/SkImageSource.cpp
+++ b/src/effects/imagefilters/SkImageSource.cpp
@@ -10,6 +10,7 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkImage.h"
#include "include/core/SkString.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
@@ -17,7 +18,7 @@
namespace {
-class SkImageSourceImpl final : public SkImageFilter {
+class SkImageSourceImpl final : public SkImageFilter_Base {
public:
SkImageSourceImpl(sk_sp<SkImage> image, const SkRect& srcRect, const SkRect& dstRect,
SkFilterQuality filterQuality)
@@ -46,7 +47,7 @@
SkRect fSrcRect, fDstRect;
SkFilterQuality fFilterQuality;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
@@ -160,7 +161,7 @@
MapDirection direction,
const SkIRect* inputRect) const {
if (kReverse_MapDirection == direction) {
- return SkImageFilter::onFilterNodeBounds(src, ctm, direction, inputRect);
+ return INHERITED::onFilterNodeBounds(src, ctm, direction, inputRect);
}
SkRect dstRect = fDstRect;
diff --git a/src/effects/imagefilters/SkLightingImageFilter.cpp b/src/effects/imagefilters/SkLightingImageFilter.cpp
index d971cc8..1da1729 100644
--- a/src/effects/imagefilters/SkLightingImageFilter.cpp
+++ b/src/effects/imagefilters/SkLightingImageFilter.cpp
@@ -11,7 +11,7 @@
#include "include/core/SkPoint3.h"
#include "include/core/SkTypes.h"
#include "include/private/SkColorData.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkWriteBuffer.h"
@@ -398,7 +398,7 @@
kBoundaryModeCount,
};
-class SkLightingImageFilterInternal : public SkImageFilter {
+class SkLightingImageFilterInternal : public SkImageFilter_Base {
protected:
SkLightingImageFilterInternal(sk_sp<SkImageFilterLight> light,
SkScalar surfaceScale,
@@ -448,7 +448,7 @@
sk_sp<SkImageFilterLight> fLight;
SkScalar fSurfaceScale;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
#if SK_SUPPORT_GPU
diff --git a/src/effects/imagefilters/SkMagnifierImageFilter.cpp b/src/effects/imagefilters/SkMagnifierImageFilter.cpp
index 2fd4c15..85c8894 100644
--- a/src/effects/imagefilters/SkMagnifierImageFilter.cpp
+++ b/src/effects/imagefilters/SkMagnifierImageFilter.cpp
@@ -9,7 +9,7 @@
#include "include/core/SkBitmap.h"
#include "include/private/SkColorData.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkValidationUtils.h"
@@ -30,7 +30,7 @@
namespace {
-class SkMagnifierImageFilterImpl final : public SkImageFilter {
+class SkMagnifierImageFilterImpl final : public SkImageFilter_Base {
public:
SkMagnifierImageFilterImpl(const SkRect& srcRect, SkScalar inset, sk_sp<SkImageFilter> input,
const CropRect* cropRect)
@@ -53,7 +53,7 @@
SkRect fSrcRect;
SkScalar fInset;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
diff --git a/src/effects/imagefilters/SkMatrixConvolutionImageFilter.cpp b/src/effects/imagefilters/SkMatrixConvolutionImageFilter.cpp
index 362108a..3c63b05 100644
--- a/src/effects/imagefilters/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/imagefilters/SkMatrixConvolutionImageFilter.cpp
@@ -12,7 +12,7 @@
#include "include/core/SkTileMode.h"
#include "include/core/SkUnPreMultiply.h"
#include "include/private/SkColorData.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkWriteBuffer.h"
@@ -25,7 +25,7 @@
namespace {
-class SkMatrixConvolutionImageFilterImpl final : public SkImageFilter {
+class SkMatrixConvolutionImageFilterImpl final : public SkImageFilter_Base {
public:
SkMatrixConvolutionImageFilterImpl(const SkISize& kernelSize, const SkScalar* kernel,
SkScalar gain, SkScalar bias, const SkIPoint& kernelOffset,
@@ -95,7 +95,7 @@
const SkIRect& rect,
const SkIRect& bounds) const;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
class UncheckedPixelFetcher {
diff --git a/src/effects/imagefilters/SkMergeImageFilter.cpp b/src/effects/imagefilters/SkMergeImageFilter.cpp
index b514c7c..07dbf41 100644
--- a/src/effects/imagefilters/SkMergeImageFilter.cpp
+++ b/src/effects/imagefilters/SkMergeImageFilter.cpp
@@ -8,6 +8,7 @@
#include "include/effects/SkMergeImageFilter.h"
#include "include/core/SkCanvas.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
@@ -16,7 +17,7 @@
namespace {
-class SkMergeImageFilterImpl final : public SkImageFilter {
+class SkMergeImageFilterImpl final : public SkImageFilter_Base {
public:
SkMergeImageFilterImpl(sk_sp<SkImageFilter>* const filters, int count,
const CropRect* cropRect)
@@ -33,7 +34,7 @@
friend void SkMergeImageFilter::RegisterFlattenables();
SK_FLATTENABLE_HOOKS(SkMergeImageFilterImpl)
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
diff --git a/src/effects/imagefilters/SkMorphologyImageFilter.cpp b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
index b41d87d..f46b30c 100644
--- a/src/effects/imagefilters/SkMorphologyImageFilter.cpp
+++ b/src/effects/imagefilters/SkMorphologyImageFilter.cpp
@@ -10,7 +10,7 @@
#include "include/core/SkBitmap.h"
#include "include/core/SkRect.h"
#include "include/private/SkColorData.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkWriteBuffer.h"
@@ -42,7 +42,7 @@
enum class MorphDirection { kX, kY };
-class SkMorphologyImageFilterImpl final : public SkImageFilter {
+class SkMorphologyImageFilterImpl final : public SkImageFilter_Base {
public:
SkMorphologyImageFilterImpl(MorphType type, int radiusX, int radiusY,
sk_sp<SkImageFilter> input, const CropRect* cropRect)
@@ -91,7 +91,7 @@
MorphType fType;
SkISize fRadius;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
@@ -547,7 +547,7 @@
static sk_sp<SkSpecialImage> apply_morphology(
GrRecordingContext* context, SkSpecialImage* input, const SkIRect& rect,
MorphType morphType, SkISize radius,
- const SkImageFilter::OutputProperties& outputProperties) {
+ const SkImageFilter_Base::OutputProperties& outputProperties) {
sk_sp<GrTextureProxy> srcTexture(input->asTextureProxyRef(context));
SkASSERT(srcTexture);
sk_sp<SkColorSpace> colorSpace = sk_ref_sp(outputProperties.colorSpace());
diff --git a/src/effects/imagefilters/SkOffsetImageFilter.cpp b/src/effects/imagefilters/SkOffsetImageFilter.cpp
index facd138..cd47f94 100644
--- a/src/effects/imagefilters/SkOffsetImageFilter.cpp
+++ b/src/effects/imagefilters/SkOffsetImageFilter.cpp
@@ -10,7 +10,7 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkPointPriv.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
@@ -19,7 +19,7 @@
namespace {
-class SkOffsetImageFilterImpl final : public SkImageFilter {
+class SkOffsetImageFilterImpl final : public SkImageFilter_Base {
public:
SkOffsetImageFilterImpl(SkScalar dx, SkScalar dy, sk_sp<SkImageFilter> input,
const CropRect* cropRect)
@@ -42,7 +42,7 @@
SkVector fOffset;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
diff --git a/src/effects/imagefilters/SkPaintImageFilter.cpp b/src/effects/imagefilters/SkPaintImageFilter.cpp
index 4c2565e..3d44b1f 100644
--- a/src/effects/imagefilters/SkPaintImageFilter.cpp
+++ b/src/effects/imagefilters/SkPaintImageFilter.cpp
@@ -9,7 +9,7 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
@@ -17,7 +17,7 @@
namespace {
-class SkPaintImageFilterImpl final : public SkImageFilter {
+class SkPaintImageFilterImpl final : public SkImageFilter_Base {
public:
SkPaintImageFilterImpl(const SkPaint& paint, const CropRect* rect)
: INHERITED(nullptr, 0, rect)
@@ -36,7 +36,7 @@
SkPaint fPaint;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
diff --git a/src/effects/imagefilters/SkPictureImageFilter.cpp b/src/effects/imagefilters/SkPictureImageFilter.cpp
index 47e3a02..63a1a7a 100644
--- a/src/effects/imagefilters/SkPictureImageFilter.cpp
+++ b/src/effects/imagefilters/SkPictureImageFilter.cpp
@@ -10,6 +10,7 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkPicture.h"
#include "include/effects/SkImageSource.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkPicturePriv.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
@@ -19,7 +20,7 @@
namespace {
-class SkPictureImageFilterImpl final : public SkImageFilter {
+class SkPictureImageFilterImpl final : public SkImageFilter_Base {
public:
SkPictureImageFilterImpl(sk_sp<SkPicture> picture, const SkRect& cropRect)
: INHERITED(nullptr, 0, nullptr)
@@ -44,7 +45,7 @@
sk_sp<SkPicture> fPicture;
SkRect fCropRect;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
diff --git a/src/effects/imagefilters/SkTileImageFilter.cpp b/src/effects/imagefilters/SkTileImageFilter.cpp
index 3558be6..b9f1ee4 100644
--- a/src/effects/imagefilters/SkTileImageFilter.cpp
+++ b/src/effects/imagefilters/SkTileImageFilter.cpp
@@ -14,7 +14,7 @@
#include "include/core/SkShader.h"
#include "include/core/SkSurface.h"
#include "include/effects/SkOffsetImageFilter.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
@@ -23,7 +23,7 @@
namespace {
-class SkTileImageFilterImpl final : public SkImageFilter {
+class SkTileImageFilterImpl final : public SkImageFilter_Base {
public:
SkTileImageFilterImpl(const SkRect& srcRect, const SkRect& dstRect, sk_sp<SkImageFilter> input)
: INHERITED(&input, 1, nullptr)
@@ -49,7 +49,7 @@
SkRect fSrcRect;
SkRect fDstRect;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
diff --git a/src/effects/imagefilters/SkXfermodeImageFilter.cpp b/src/effects/imagefilters/SkXfermodeImageFilter.cpp
index c8f7cb8..d51f435 100644
--- a/src/effects/imagefilters/SkXfermodeImageFilter.cpp
+++ b/src/effects/imagefilters/SkXfermodeImageFilter.cpp
@@ -9,7 +9,7 @@
#include "include/core/SkCanvas.h"
#include "include/private/SkColorData.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
@@ -32,7 +32,7 @@
namespace {
-class SkXfermodeImageFilterImpl : public SkImageFilter {
+class SkXfermodeImageFilterImpl : public SkImageFilter_Base {
public:
SkXfermodeImageFilterImpl(SkBlendMode mode, sk_sp<SkImageFilter> inputs[2],
const CropRect* cropRect)
@@ -70,7 +70,7 @@
SkBlendMode fMode;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
} // end namespace
@@ -184,7 +184,7 @@
MapDirection dir,
const SkIRect* inputRect) const {
if (kReverse_MapDirection == dir) {
- return SkImageFilter::onFilterBounds(src, ctm, dir, inputRect);
+ return INHERITED::onFilterBounds(src, ctm, dir, inputRect);
}
SkASSERT(!inputRect);
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index e5eb2d3..a463867 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -20,6 +20,7 @@
#include "src/core/SkClipStack.h"
#include "src/core/SkDraw.h"
#include "src/core/SkImageFilterCache.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkLatticeIter.h"
#include "src/core/SkMakeUnique.h"
#include "src/core/SkPictureData.h"
@@ -176,11 +177,11 @@
if (colorType == kUnknown_SkColorType) {
colorType = kRGBA_8888_SkColorType;
}
- SkImageFilter::OutputProperties outputProperties(
+ SkImageFilter_Base::OutputProperties outputProperties(
colorType, fRenderTargetContext->colorSpaceInfo().colorSpace());
- SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
+ SkImageFilter_Base::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
- return filter->filterImage(srcImg, ctx, offset);
+ return as_IFB(filter)->filterImage(srcImg, ctx, offset);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index c869bb3..079992a 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -18,6 +18,7 @@
#include "src/core/SkCachedData.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkImageFilterCache.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkImagePriv.h"
#include "src/core/SkNextID.h"
#include "src/core/SkSpecialImage.h"
@@ -282,17 +283,18 @@
sk_sp<SkImageFilterCache> cache(
SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
- SkImageFilter::OutputProperties outputProperties(fInfo.colorType(), fInfo.colorSpace());
+ SkImageFilter_Base::OutputProperties outputProperties(fInfo.colorType(), fInfo.colorSpace());
// The filters operate in the local space of the src image, where (0,0) corresponds to the
// subset's top left corner. But the clip bounds and any crop rects on the filters are in the
// original coordinate system, so configure the CTM to correct crop rects and explicitly adjust
// the clip bounds (since it is assumed to already be in image space).
- SkImageFilter::Context context(SkMatrix::MakeTrans(-subset.x(), -subset.y()),
- clipBounds.makeOffset(-subset.x(), -subset.y()),
- cache.get(), outputProperties);
+ SkImageFilter_Base::Context context(SkMatrix::MakeTrans(-subset.x(), -subset.y()),
+ clipBounds.makeOffset(-subset.x(), -subset.y()),
+ cache.get(), outputProperties);
- sk_sp<SkSpecialImage> result = filter->filterImage(srcSpecialImage.get(), context, offset);
+ sk_sp<SkSpecialImage> result = as_IFB(filter)->filterImage(srcSpecialImage.get(), context,
+ offset);
if (!result) {
return nullptr;
}
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index cdb35a7..73e3651 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -28,6 +28,7 @@
#include "src/core/SkDraw.h"
#include "src/core/SkGlyphRun.h"
#include "src/core/SkImageFilterCache.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkMakeUnique.h"
#include "src/core/SkMaskFilterBase.h"
#include "src/core/SkRasterClip.h"
@@ -1728,10 +1729,11 @@
sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
// TODO: Should PDF be operating in a specified color type/space? For now, run the filter
// in the same color space as the source (this is different from all other backends).
- SkImageFilter::OutputProperties outputProperties(kN32_SkColorType, srcImg->getColorSpace());
- SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
+ SkImageFilter_Base::OutputProperties outputProperties(
+ kN32_SkColorType, srcImg->getColorSpace());
+ SkImageFilter_Base::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
- sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
+ sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(srcImg, ctx, &offset));
if (resultImg) {
SkPaint tmpUnfiltered(paint);
tmpUnfiltered.setImageFilter(nullptr);
diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp
index c3ac060..2dc5b0d 100644
--- a/tests/CanvasTest.cpp
+++ b/tests/CanvasTest.cpp
@@ -39,6 +39,7 @@
#include "include/utils/SkNWayCanvas.h"
#include "include/utils/SkPaintFilterCanvas.h"
#include "src/core/SkClipOpPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkSpecialImage.h"
#include "src/utils/SkCanvasStack.h"
#include "tests/Test.h"
@@ -595,7 +596,7 @@
namespace {
-class ZeroBoundsImageFilter : public SkImageFilter {
+class ZeroBoundsImageFilter : public SkImageFilter_Base {
public:
static sk_sp<SkImageFilter> Make() { return sk_sp<SkImageFilter>(new ZeroBoundsImageFilter); }
@@ -613,7 +614,7 @@
ZeroBoundsImageFilter() : INHERITED(nullptr, 0, nullptr) {}
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
sk_sp<SkFlattenable> ZeroBoundsImageFilter::CreateProc(SkReadBuffer& buffer) {
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index e1427b1..3a340a0 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -33,7 +33,7 @@
#include "include/effects/SkTableColorFilter.h"
#include "include/effects/SkTileImageFilter.h"
#include "include/effects/SkXfermodeImageFilter.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
#include "src/core/SkSpecialSurface.h"
@@ -49,7 +49,7 @@
namespace {
-class MatrixTestImageFilter : public SkImageFilter {
+class MatrixTestImageFilter : public SkImageFilter_Base {
public:
static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
const SkMatrix& expectedMatrix) {
@@ -80,12 +80,12 @@
skiatest::Reporter* fReporter;
SkMatrix fExpectedMatrix;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
-class FailImageFilter : public SkImageFilter {
+class FailImageFilter : public SkImageFilter_Base {
public:
- FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
+ FailImageFilter() : INHERITED(nullptr, 0, nullptr) { }
sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
const Context& ctx,
@@ -96,7 +96,7 @@
SK_FLATTENABLE_HOOKS(FailImageFilter)
private:
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
@@ -275,10 +275,10 @@
SkTArray<Filter> fFilters;
};
-class FixedBoundsImageFilter : public SkImageFilter {
+class FixedBoundsImageFilter : public SkImageFilter_Base {
public:
FixedBoundsImageFilter(const SkIRect& bounds)
- : SkImageFilter(nullptr, 0, nullptr), fBounds(bounds) {}
+ : INHERITED(nullptr, 0, nullptr), fBounds(bounds) {}
private:
Factory getFactory() const override { return nullptr; }
@@ -295,6 +295,8 @@
}
SkIRect fBounds;
+
+ typedef SkImageFilter_Base INHERITED;
};
}
@@ -523,9 +525,10 @@
for (int i = 0; i < filters.count(); ++i) {
SkImageFilter* filter = filters.getFilter(i);
SkIPoint offset;
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
- sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
+ noColorSpace);
+ sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(srcImg.get(), ctx, &offset));
REPORTER_ASSERT(reporter, resultImg, filters.getName(i));
REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
}
@@ -546,28 +549,28 @@
gradient));
SkIPoint offset;
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
- sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
+ sk_sp<SkSpecialImage> positiveResult1(
+ as_IFB(positiveFilter)->filterImage(imgSrc.get(), ctx, &offset));
REPORTER_ASSERT(reporter, positiveResult1);
- sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
+ sk_sp<SkSpecialImage> negativeResult1(
+ as_IFB(negativeFilter)->filterImage(imgSrc.get(), ctx, &offset));
REPORTER_ASSERT(reporter, negativeResult1);
SkMatrix negativeScale;
negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
- SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
- noColorSpace);
+ SkImageFilter_Base::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
+ noColorSpace);
- sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
- negativeCTX,
- &offset));
+ sk_sp<SkSpecialImage> negativeResult2(
+ as_IFB(positiveFilter)->filterImage(imgSrc.get(), negativeCTX, &offset));
REPORTER_ASSERT(reporter, negativeResult2);
- sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
- negativeCTX,
- &offset));
+ sk_sp<SkSpecialImage> positiveResult2(
+ as_IFB(negativeFilter)->filterImage(imgSrc.get(), negativeCTX, &offset));
REPORTER_ASSERT(reporter, positiveResult2);
@@ -623,10 +626,10 @@
sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
SkIPoint offset;
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
- sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
+ sk_sp<SkSpecialImage> result(as_IFB(filter)->filterImage(image.get(), ctx, &offset));
REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
REPORTER_ASSERT(reporter, result);
REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
@@ -660,14 +663,15 @@
static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
sk_sp<FailImageFilter> failFilter(new FailImageFilter());
sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr,
+ noColorSpace);
sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
SkASSERT(green->affectsTransparentBlack());
sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
std::move(failFilter)));
SkIPoint offset;
- sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
+ sk_sp<SkSpecialImage> result(as_IFB(greenFilter)->filterImage(source.get(), ctx, &offset));
REPORTER_ASSERT(reporter, nullptr != result.get());
if (result.get()) {
SkBitmap resultBM;
@@ -951,12 +955,12 @@
sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
- noColorSpace);
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
+ noColorSpace);
SkIPoint offset;
- sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
+ sk_sp<SkSpecialImage> resultImg(as_IFB(merge)->filterImage(srcImg.get(), ctx, &offset));
REPORTER_ASSERT(reporter, resultImg);
REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
@@ -1120,9 +1124,10 @@
SkASSERT(srcImg);
SkIPoint offset;
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
- sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
+ noColorSpace);
+ sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(srcImg.get(), ctx, &offset));
REPORTER_ASSERT(reporter, resultImg);
REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
@@ -1192,10 +1197,11 @@
sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
SkIPoint offset;
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr,
+ noColorSpace);
- sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
+ sk_sp<SkSpecialImage> resultImage(as_IFB(imageFilter)->filterImage(srcImg.get(), ctx, &offset));
REPORTER_ASSERT(reporter, !resultImage);
}
@@ -1444,10 +1450,12 @@
sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
std::move(offsetFilter)));
SkIPoint offset;
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
+ noColorSpace);
- sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
+ sk_sp<SkSpecialImage> resultImg(
+ as_IFB(composedFilter)->filterImage(srcImg.get(), ctx, &offset));
REPORTER_ASSERT(reporter, resultImg);
REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
}
@@ -1479,10 +1487,12 @@
std::move(pictureFilter)));
sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
+ noColorSpace);
SkIPoint offset;
- sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
+ sk_sp<SkSpecialImage> result(
+ as_IFB(composedFilter)->filterImage(sourceImage.get(), ctx, &offset));
REPORTER_ASSERT(reporter, offset.isZero());
REPORTER_ASSERT(reporter, result);
REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
@@ -1507,10 +1517,11 @@
SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
SkIPoint offset;
- SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
- SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
+ SkImageFilter_Base::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
+ SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
+ noColorSpace);
- sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
+ sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(srcImg.get(), ctx, &offset));
REPORTER_ASSERT(reporter, resultImg);
REPORTER_ASSERT(reporter, offset.fX == 0);
@@ -1791,7 +1802,7 @@
};
for (const auto& rec : recs) {
- const bool canHandle = rec.fFilter->canHandleComplexCTM();
+ const bool canHandle = as_IFB(rec.fFilter)->canHandleComplexCTM();
REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
}
}
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index 6c3c311..4a11a00 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -21,7 +21,7 @@
#include "include/effects/SkPerlinNoiseShader.h"
#include "include/private/SkTo.h"
#include "src/core/SkGlyphRun.h"
-#include "src/core/SkImageFilterPriv.h"
+#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkMakeUnique.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkSpecialImage.h"
@@ -247,7 +247,7 @@
namespace {
-class DummyImageFilter : public SkImageFilter {
+class DummyImageFilter : public SkImageFilter_Base {
public:
static sk_sp<DummyImageFilter> Make(bool visited = false) {
return sk_sp<DummyImageFilter>(new DummyImageFilter(visited));
@@ -269,7 +269,7 @@
mutable bool fVisited;
- typedef SkImageFilter INHERITED;
+ typedef SkImageFilter_Base INHERITED;
};
sk_sp<SkFlattenable> DummyImageFilter::CreateProc(SkReadBuffer& buffer) {
diff --git a/tests/SpecialImageTest.cpp b/tests/SpecialImageTest.cpp
index 1c6b36c..42dbcb8 100644
--- a/tests/SpecialImageTest.cpp
+++ b/tests/SpecialImageTest.cpp
@@ -81,7 +81,7 @@
//--------------
// Test that draw restricts itself to the subset
- SkImageFilter::OutputProperties outProps(kN32_SkColorType, img->getColorSpace());
+ SkImageFilter_Base::OutputProperties outProps(kN32_SkColorType, img->getColorSpace());
sk_sp<SkSpecialSurface> surf(img->makeSurface(outProps, SkISize::Make(kFullSize, kFullSize),
kPremul_SkAlphaType));
@@ -118,7 +118,7 @@
REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap));
}
{
- SkImageFilter::OutputProperties outProps(kN32_SkColorType, img->getColorSpace());
+ SkImageFilter_Base::OutputProperties outProps(kN32_SkColorType, img->getColorSpace());
sk_sp<SkSurface> tightSurf(img->makeTightSurface(outProps, subset.size()));
REPORTER_ASSERT(reporter, tightSurf->width() == subset.width());