aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects/imagefilters/SkImageSource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/effects/imagefilters/SkImageSource.cpp')
-rw-r--r--src/effects/imagefilters/SkImageSource.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/effects/imagefilters/SkImageSource.cpp b/src/effects/imagefilters/SkImageSource.cpp
new file mode 100644
index 0000000000..960de37b33
--- /dev/null
+++ b/src/effects/imagefilters/SkImageSource.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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 "SkImageSource.h"
+
+#include "SkCanvas.h"
+#include "SkColorSpaceXformer.h"
+#include "SkImage.h"
+#include "SkReadBuffer.h"
+#include "SkSpecialImage.h"
+#include "SkSpecialSurface.h"
+#include "SkWriteBuffer.h"
+#include "SkString.h"
+
+sk_sp<SkImageFilter> SkImageSource::Make(sk_sp<SkImage> image) {
+ if (!image) {
+ return nullptr;
+ }
+
+ return sk_sp<SkImageFilter>(new SkImageSource(std::move(image)));
+}
+
+sk_sp<SkImageFilter> SkImageSource::Make(sk_sp<SkImage> image,
+ const SkRect& srcRect,
+ const SkRect& dstRect,
+ SkFilterQuality filterQuality) {
+ if (!image || srcRect.width() <= 0.0f || srcRect.height() <= 0.0f) {
+ return nullptr;
+ }
+
+ return sk_sp<SkImageFilter>(new SkImageSource(std::move(image),
+ srcRect, dstRect,
+ filterQuality));
+}
+
+SkImageSource::SkImageSource(sk_sp<SkImage> image)
+ : INHERITED(nullptr, 0, nullptr)
+ , fImage(std::move(image))
+ , fSrcRect(SkRect::MakeIWH(fImage->width(), fImage->height()))
+ , fDstRect(fSrcRect)
+ , fFilterQuality(kHigh_SkFilterQuality) {
+}
+
+SkImageSource::SkImageSource(sk_sp<SkImage> image,
+ const SkRect& srcRect,
+ const SkRect& dstRect,
+ SkFilterQuality filterQuality)
+ : INHERITED(nullptr, 0, nullptr)
+ , fImage(std::move(image))
+ , fSrcRect(srcRect)
+ , fDstRect(dstRect)
+ , fFilterQuality(filterQuality) {
+}
+
+sk_sp<SkFlattenable> SkImageSource::CreateProc(SkReadBuffer& buffer) {
+ SkFilterQuality filterQuality = (SkFilterQuality)buffer.readInt();
+
+ SkRect src, dst;
+ buffer.readRect(&src);
+ buffer.readRect(&dst);
+
+ sk_sp<SkImage> image(buffer.readImage());
+ if (!image) {
+ return nullptr;
+ }
+
+ return SkImageSource::Make(std::move(image), src, dst, filterQuality);
+}
+
+void SkImageSource::flatten(SkWriteBuffer& buffer) const {
+ buffer.writeInt(fFilterQuality);
+ buffer.writeRect(fSrcRect);
+ buffer.writeRect(fDstRect);
+ buffer.writeImage(fImage.get());
+}
+
+sk_sp<SkSpecialImage> SkImageSource::onFilterImage(SkSpecialImage* source, const Context& ctx,
+ SkIPoint* offset) const {
+ SkRect dstRect;
+ ctx.ctm().mapRect(&dstRect, fDstRect);
+
+ SkRect bounds = SkRect::MakeIWH(fImage->width(), fImage->height());
+ if (fSrcRect == bounds) {
+ int iLeft = dstRect.fLeft;
+ int iTop = dstRect.fTop;
+ // TODO: this seems to be a very noise-prone way to determine this (esp. the floating-point
+ // widths & heights).
+ if (dstRect.width() == bounds.width() && dstRect.height() == bounds.height() &&
+ iLeft == dstRect.fLeft && iTop == dstRect.fTop) {
+ // The dest is just an un-scaled integer translation of the entire image; return it
+ offset->fX = iLeft;
+ offset->fY = iTop;
+
+ return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(fImage->width(), fImage->height()),
+ fImage, ctx.outputProperties().colorSpace(),
+ &source->props());
+ }
+ }
+
+ const SkIRect dstIRect = dstRect.roundOut();
+
+ sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), dstIRect.size()));
+ if (!surf) {
+ return nullptr;
+ }
+
+ SkCanvas* canvas = surf->getCanvas();
+ SkASSERT(canvas);
+
+ // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075)
+ canvas->clear(0x0);
+
+ SkPaint paint;
+
+ // Subtract off the integer component of the translation (will be applied in offset, below).
+ dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop));
+ paint.setBlendMode(SkBlendMode::kSrc);
+ // FIXME: this probably shouldn't be necessary, but drawImageRect asserts
+ // None filtering when it's translate-only
+ paint.setFilterQuality(
+ fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height() ?
+ kNone_SkFilterQuality : fFilterQuality);
+ canvas->drawImageRect(fImage.get(), fSrcRect, dstRect, &paint,
+ SkCanvas::kStrict_SrcRectConstraint);
+
+ offset->fX = dstIRect.fLeft;
+ offset->fY = dstIRect.fTop;
+ return surf->makeImageSnapshot();
+}
+
+sk_sp<SkImageFilter> SkImageSource::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
+ SkASSERT(0 == this->countInputs());
+
+ auto image = xformer->apply(fImage.get());
+ if (image != fImage) {
+ return SkImageSource::Make(image, fSrcRect, fDstRect, fFilterQuality);
+ }
+ return this->refMe();
+}
+
+SkRect SkImageSource::computeFastBounds(const SkRect& src) const {
+ return fDstRect;
+}
+
+SkIRect SkImageSource::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ MapDirection direction, const SkIRect* inputRect) const {
+ if (kReverse_MapDirection == direction) {
+ return SkImageFilter::onFilterNodeBounds(src, ctm, direction, inputRect);
+ }
+
+ SkRect dstRect = fDstRect;
+ ctm.mapRect(&dstRect);
+ return dstRect.roundOut();
+}
+