summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/effects/imagefilters/SkImageImageFilter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/effects/imagefilters/SkImageImageFilter.cpp')
-rw-r--r--gfx/skia/skia/src/effects/imagefilters/SkImageImageFilter.cpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/effects/imagefilters/SkImageImageFilter.cpp b/gfx/skia/skia/src/effects/imagefilters/SkImageImageFilter.cpp
new file mode 100644
index 0000000000..66ecf66052
--- /dev/null
+++ b/gfx/skia/skia/src/effects/imagefilters/SkImageImageFilter.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkColor.h"
+#include "include/core/SkFlattenable.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkImageFilter.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkPoint.h"
+#include "include/core/SkRect.h"
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkSamplingOptions.h"
+#include "include/core/SkScalar.h"
+#include "include/effects/SkImageFilters.h"
+#include "src/core/SkImageFilter_Base.h"
+#include "src/core/SkPicturePriv.h"
+#include "src/core/SkReadBuffer.h"
+#include "src/core/SkSamplingPriv.h"
+#include "src/core/SkSpecialImage.h"
+#include "src/core/SkSpecialSurface.h"
+#include "src/core/SkWriteBuffer.h"
+
+#include <utility>
+
+namespace {
+
+class SkImageImageFilter final : public SkImageFilter_Base {
+public:
+ SkImageImageFilter(sk_sp<SkImage> image, const SkRect& srcRect, const SkRect& dstRect,
+ const SkSamplingOptions& sampling)
+ : INHERITED(nullptr, 0, nullptr)
+ , fImage(std::move(image))
+ , fSrcRect(srcRect)
+ , fDstRect(dstRect)
+ , fSampling(sampling) {}
+
+ SkRect computeFastBounds(const SkRect& src) const override;
+
+protected:
+ void flatten(SkWriteBuffer&) const override;
+
+ sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
+
+ SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm,
+ MapDirection, const SkIRect* inputRect) const override;
+
+ MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
+
+private:
+ friend void ::SkRegisterImageImageFilterFlattenable();
+ SK_FLATTENABLE_HOOKS(SkImageImageFilter)
+
+ sk_sp<SkImage> fImage;
+ SkRect fSrcRect, fDstRect;
+ SkSamplingOptions fSampling;
+
+ using INHERITED = SkImageFilter_Base;
+};
+
+} // end namespace
+
+sk_sp<SkImageFilter> SkImageFilters::Image(sk_sp<SkImage> image,
+ const SkRect& srcRect,
+ const SkRect& dstRect,
+ const SkSamplingOptions& sampling) {
+ if (!image || srcRect.width() <= 0.0f || srcRect.height() <= 0.0f) {
+ return nullptr;
+ }
+
+ return sk_sp<SkImageFilter>(new SkImageImageFilter(
+ std::move(image), srcRect, dstRect, sampling));
+}
+
+void SkRegisterImageImageFilterFlattenable() {
+ SK_REGISTER_FLATTENABLE(SkImageImageFilter);
+ // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
+ SkFlattenable::Register("SkImageSourceImpl", SkImageImageFilter::CreateProc);
+}
+
+sk_sp<SkFlattenable> SkImageImageFilter::CreateProc(SkReadBuffer& buffer) {
+ SkSamplingOptions sampling;
+ if (buffer.isVersionLT(SkPicturePriv::kImageFilterImageSampling_Version)) {
+ sampling = SkSamplingPriv::FromFQ(buffer.checkFilterQuality(), kLinear_SkMediumAs);
+ } else {
+ sampling = buffer.readSampling();
+ }
+
+ SkRect src, dst;
+ buffer.readRect(&src);
+ buffer.readRect(&dst);
+
+ sk_sp<SkImage> image(buffer.readImage());
+ if (!image) {
+ return nullptr;
+ }
+
+ return SkImageFilters::Image(std::move(image), src, dst, sampling);
+}
+
+void SkImageImageFilter::flatten(SkWriteBuffer& buffer) const {
+ buffer.writeSampling(fSampling);
+ buffer.writeRect(fSrcRect);
+ buffer.writeRect(fDstRect);
+ buffer.writeImage(fImage.get());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkSpecialImage> SkImageImageFilter::onFilterImage(const Context& ctx,
+ SkIPoint* offset) const {
+ const SkRect dstBounds = ctx.ctm().mapRect(fDstRect);
+ const SkIRect dstIBounds = dstBounds.roundOut();
+
+ // Quick check to see if we can return the image directly, which can be done if the transform
+ // ends up being an integer translate and sampling would have no effect on the output.
+ // TODO: This currently means cubic sampling can be skipped, even though it would change results
+ // for integer translation draws.
+ // TODO: This is prone to false negatives due to the floating point math; we could probably
+ // get away with dimensions and translates being epsilon close to integers.
+ const bool passthroughTransform = ctx.ctm().isScaleTranslate() &&
+ ctx.ctm().getScaleX() > 0.f &&
+ ctx.ctm().getScaleY() > 0.f;
+ const bool passthroughSrcOffsets = SkScalarIsInt(fSrcRect.fLeft) &&
+ SkScalarIsInt(fSrcRect.fTop);
+ const bool passthroughDstOffsets = SkScalarIsInt(dstBounds.fLeft) &&
+ SkScalarIsInt(dstBounds.fTop);
+ const bool passthroughDims =
+ SkScalarIsInt(fSrcRect.width()) && fSrcRect.width() == dstBounds.width() &&
+ SkScalarIsInt(fSrcRect.height()) && fSrcRect.height() == dstBounds.height();
+
+ if (passthroughTransform && passthroughSrcOffsets && passthroughDstOffsets && passthroughDims) {
+ // Can pass through fImage directly, applying the dst's location to 'offset'. If fSrcRect
+ // extends outside of the image, we adjust dst to match since those areas would have been
+ // transparent black anyways.
+ SkIRect srcIBounds = fSrcRect.roundOut();
+ SkIPoint srcOffset = srcIBounds.topLeft();
+ if (!srcIBounds.intersect(SkIRect::MakeWH(fImage->width(), fImage->height()))) {
+ return nullptr;
+ }
+
+ *offset = dstIBounds.topLeft() + srcIBounds.topLeft() - srcOffset;
+ return SkSpecialImage::MakeFromImage(ctx.getContext(), srcIBounds, fImage,
+ ctx.surfaceProps());
+ }
+
+ sk_sp<SkSpecialSurface> surf(ctx.makeSurface(dstIBounds.size()));
+ if (!surf) {
+ return nullptr;
+ }
+
+ SkCanvas* canvas = surf->getCanvas();
+ // Subtract off the integer component of the translation (will be applied in offset, below).
+ canvas->translate(-dstIBounds.fLeft, -dstIBounds.fTop);
+ canvas->concat(ctx.ctm());
+ // TODO(skbug.com/5075): Canvases from GPU special surfaces come with unitialized content
+ canvas->clear(SK_ColorTRANSPARENT);
+ canvas->drawImageRect(fImage.get(), fSrcRect, fDstRect, fSampling, nullptr,
+ SkCanvas::kStrict_SrcRectConstraint);
+
+ *offset = dstIBounds.topLeft();
+ return surf->makeImageSnapshot();
+}
+
+SkRect SkImageImageFilter::computeFastBounds(const SkRect& src) const {
+ return fDstRect;
+}
+
+SkIRect SkImageImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ MapDirection direction,
+ const SkIRect* inputRect) const {
+ if (kReverse_MapDirection == direction) {
+ return INHERITED::onFilterNodeBounds(src, ctm, direction, inputRect);
+ }
+
+ SkRect dstRect = fDstRect;
+ ctm.mapRect(&dstRect);
+ return dstRect.roundOut();
+}