diff options
Diffstat (limited to 'gfx/skia/skia/src/effects/imagefilters/SkImageImageFilter.cpp')
-rw-r--r-- | gfx/skia/skia/src/effects/imagefilters/SkImageImageFilter.cpp | 183 |
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(); +} |