Index: src/effects/SkTransformImageFilter.cpp |
diff --git a/src/effects/SkTransformImageFilter.cpp b/src/effects/SkTransformImageFilter.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f4c078165666dfebd18fce019b446dc22d6fb01a |
--- /dev/null |
+++ b/src/effects/SkTransformImageFilter.cpp |
@@ -0,0 +1,126 @@ |
+/* |
+ * Copyright 2014 The Android Open Source Project |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkTransformImageFilter.h" |
+#include "SkBitmap.h" |
+#include "SkCanvas.h" |
+#include "SkDevice.h" |
+#include "SkColorPriv.h" |
+#include "SkReadBuffer.h" |
+#include "SkWriteBuffer.h" |
+#include "SkMatrix.h" |
+#include "SkRect.h" |
+ |
+SkTransformImageFilter::SkTransformImageFilter(const SkMatrix& transform, |
+ SkPaint::FilterLevel filterLevel, |
+ SkImageFilter* input) |
+ : INHERITED(input), |
+ fTransform(transform), |
+ fFilterLevel(filterLevel) { |
+} |
+ |
+SkTransformImageFilter* SkTransformImageFilter::Create(const SkMatrix& transform, |
+ SkPaint::FilterLevel filterLevel, |
+ SkImageFilter* input) { |
+ return SkNEW_ARGS(SkTransformImageFilter, (transform, filterLevel, input)); |
+} |
+ |
+SkTransformImageFilter::SkTransformImageFilter(SkReadBuffer& buffer) |
+ : INHERITED(1, buffer) { |
+ buffer.readMatrix(&fTransform); |
+ fFilterLevel = static_cast<SkPaint::FilterLevel>(buffer.readInt()); |
+} |
+ |
+void SkTransformImageFilter::flatten(SkWriteBuffer& buffer) const { |
+ this->INHERITED::flatten(buffer); |
+ buffer.writeMatrix(fTransform); |
+ buffer.writeInt(fFilterLevel); |
+} |
+ |
+SkTransformImageFilter::~SkTransformImageFilter() { |
+} |
+ |
+bool SkTransformImageFilter::onFilterImage(Proxy* proxy, |
+ const SkBitmap& source, |
+ const Context& ctx, |
+ SkBitmap* result, |
+ SkIPoint* offset) const { |
+ SkBitmap src = source; |
+ SkIPoint srcOffset = SkIPoint::Make(0, 0); |
+ if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) { |
+ return false; |
+ } |
+ |
+ SkRect dstRect; |
+ SkIRect srcBounds, dstBounds; |
+ src.getBounds(&srcBounds); |
+ srcBounds.offset(srcOffset); |
+ SkRect srcRect = SkRect::Make(srcBounds); |
+ SkMatrix matrix; |
+ if (!ctx.ctm().invert(&matrix)) { |
+ return false; |
+ } |
+ matrix.postConcat(fTransform); |
+ matrix.postConcat(ctx.ctm()); |
+ matrix.mapRect(&dstRect, srcRect); |
+ dstRect.roundOut(&dstBounds); |
+ |
+ SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height())); |
+ if (NULL == device.get()) { |
+ return false; |
+ } |
+ |
+ SkCanvas canvas(device.get()); |
+ canvas.translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y())); |
+ canvas.concat(matrix); |
+ SkPaint paint; |
+ |
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
+ paint.setFilterLevel(fFilterLevel); |
+ canvas.drawBitmap(src, srcRect.x(), srcRect.y(), &paint); |
+ |
+ *result = device.get()->accessBitmap(false); |
+ offset->fX = dstBounds.fLeft; |
+ offset->fY = dstBounds.fTop; |
+ return true; |
+} |
+ |
+void SkTransformImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { |
+ SkRect bounds = src; |
+ if (getInput(0)) { |
+ getInput(0)->computeFastBounds(src, &bounds); |
+ } |
+ SkMatrix matrix; |
+ matrix.setTranslate(-bounds.x(), -bounds.y()); |
+ matrix.postConcat(fTransform); |
+ matrix.postTranslate(bounds.x(), bounds.y()); |
+ matrix.mapRect(dst, bounds); |
+} |
+ |
+bool SkTransformImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, |
+ SkIRect* dst) const { |
+ SkMatrix transformInverse; |
+ if (!fTransform.invert(&transformInverse)) { |
+ return false; |
+ } |
+ SkMatrix matrix; |
+ if (!ctm.invert(&matrix)) { |
+ return false; |
+ } |
+ matrix.postConcat(transformInverse); |
+ matrix.postConcat(ctm); |
+ SkRect floatBounds; |
+ matrix.mapRect(&floatBounds, SkRect::Make(src)); |
+ SkIRect bounds; |
+ floatBounds.roundOut(&bounds); |
+ if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { |
+ return false; |
+ } |
+ |
+ *dst = bounds; |
+ return true; |
+} |