1/* 2 * Copyright 2014 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkMatrixImageFilter.h" 9#include "SkBitmap.h" 10#include "SkCanvas.h" 11#include "SkDevice.h" 12#include "SkColorPriv.h" 13#include "SkReadBuffer.h" 14#include "SkWriteBuffer.h" 15#include "SkMatrix.h" 16#include "SkRect.h" 17 18SkMatrixImageFilter::SkMatrixImageFilter(const SkMatrix& transform, 19 SkPaint::FilterLevel filterLevel, 20 SkImageFilter* input, 21 uint32_t uniqueID) 22 : INHERITED(1, &input, NULL, uniqueID), 23 fTransform(transform), 24 fFilterLevel(filterLevel) { 25} 26 27SkMatrixImageFilter* SkMatrixImageFilter::Create(const SkMatrix& transform, 28 SkPaint::FilterLevel filterLevel, 29 SkImageFilter* input, 30 uint32_t uniqueID) { 31 return SkNEW_ARGS(SkMatrixImageFilter, (transform, filterLevel, input, uniqueID)); 32} 33 34#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 35SkMatrixImageFilter::SkMatrixImageFilter(SkReadBuffer& buffer) 36 : INHERITED(1, buffer) { 37 buffer.readMatrix(&fTransform); 38 fFilterLevel = static_cast<SkPaint::FilterLevel>(buffer.readInt()); 39} 40#endif 41 42SkFlattenable* SkMatrixImageFilter::CreateProc(SkReadBuffer& buffer) { 43 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 44 SkMatrix matrix; 45 buffer.readMatrix(&matrix); 46 SkPaint::FilterLevel level = static_cast<SkPaint::FilterLevel>(buffer.readInt()); 47 return Create(matrix, level, common.getInput(0), common.uniqueID()); 48} 49 50void SkMatrixImageFilter::flatten(SkWriteBuffer& buffer) const { 51 this->INHERITED::flatten(buffer); 52 buffer.writeMatrix(fTransform); 53 buffer.writeInt(fFilterLevel); 54} 55 56SkMatrixImageFilter::~SkMatrixImageFilter() { 57} 58 59bool SkMatrixImageFilter::onFilterImage(Proxy* proxy, 60 const SkBitmap& source, 61 const Context& ctx, 62 SkBitmap* result, 63 SkIPoint* offset) const { 64 SkBitmap src = source; 65 SkIPoint srcOffset = SkIPoint::Make(0, 0); 66 if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) { 67 return false; 68 } 69 70 SkRect dstRect; 71 SkIRect srcBounds, dstBounds; 72 src.getBounds(&srcBounds); 73 srcBounds.offset(srcOffset); 74 SkRect srcRect = SkRect::Make(srcBounds); 75 SkMatrix matrix; 76 if (!ctx.ctm().invert(&matrix)) { 77 return false; 78 } 79 matrix.postConcat(fTransform); 80 matrix.postConcat(ctx.ctm()); 81 matrix.mapRect(&dstRect, srcRect); 82 dstRect.roundOut(&dstBounds); 83 84 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height())); 85 if (NULL == device.get()) { 86 return false; 87 } 88 89 SkCanvas canvas(device.get()); 90 canvas.translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y())); 91 canvas.concat(matrix); 92 SkPaint paint; 93 94 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 95 paint.setFilterLevel(fFilterLevel); 96 canvas.drawBitmap(src, srcRect.x(), srcRect.y(), &paint); 97 98 *result = device.get()->accessBitmap(false); 99 offset->fX = dstBounds.fLeft; 100 offset->fY = dstBounds.fTop; 101 return true; 102} 103 104void SkMatrixImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { 105 SkRect bounds = src; 106 if (getInput(0)) { 107 getInput(0)->computeFastBounds(src, &bounds); 108 } 109 SkMatrix matrix; 110 matrix.setTranslate(-bounds.x(), -bounds.y()); 111 matrix.postConcat(fTransform); 112 matrix.postTranslate(bounds.x(), bounds.y()); 113 matrix.mapRect(dst, bounds); 114} 115 116bool SkMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 117 SkIRect* dst) const { 118 SkMatrix transformInverse; 119 if (!fTransform.invert(&transformInverse)) { 120 return false; 121 } 122 SkMatrix matrix; 123 if (!ctm.invert(&matrix)) { 124 return false; 125 } 126 matrix.postConcat(transformInverse); 127 matrix.postConcat(ctm); 128 SkRect floatBounds; 129 matrix.mapRect(&floatBounds, SkRect::Make(src)); 130 SkIRect bounds; 131 floatBounds.roundOut(&bounds); 132 if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { 133 return false; 134 } 135 136 *dst = bounds; 137 return true; 138} 139