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 18 SkMatrixImageFilter::SkMatrixImageFilter(const SkMatrix& transform, 19 SkPaint::FilterLevel filterLevel, 20 SkImageFilter* input) 21 : INHERITED(input), 22 fTransform(transform), 23 fFilterLevel(filterLevel) { 24 } 25 26 SkMatrixImageFilter* SkMatrixImageFilter::Create(const SkMatrix& transform, 27 SkPaint::FilterLevel filterLevel, 28 SkImageFilter* input) { 29 return SkNEW_ARGS(SkMatrixImageFilter, (transform, filterLevel, input)); 30 } 31 32 SkMatrixImageFilter::SkMatrixImageFilter(SkReadBuffer& buffer) 33 : INHERITED(1, buffer) { 34 buffer.readMatrix(&fTransform); 35 fFilterLevel = static_cast<SkPaint::FilterLevel>(buffer.readInt()); 36 } 37 38 void SkMatrixImageFilter::flatten(SkWriteBuffer& buffer) const { 39 this->INHERITED::flatten(buffer); 40 buffer.writeMatrix(fTransform); 41 buffer.writeInt(fFilterLevel); 42 } 43 44 SkMatrixImageFilter::~SkMatrixImageFilter() { 45 } 46 47 bool SkMatrixImageFilter::onFilterImage(Proxy* proxy, 48 const SkBitmap& source, 49 const Context& ctx, 50 SkBitmap* result, 51 SkIPoint* offset) const { 52 SkBitmap src = source; 53 SkIPoint srcOffset = SkIPoint::Make(0, 0); 54 if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) { 55 return false; 56 } 57 58 SkRect dstRect; 59 SkIRect srcBounds, dstBounds; 60 src.getBounds(&srcBounds); 61 srcBounds.offset(srcOffset); 62 SkRect srcRect = SkRect::Make(srcBounds); 63 SkMatrix matrix; 64 if (!ctx.ctm().invert(&matrix)) { 65 return false; 66 } 67 matrix.postConcat(fTransform); 68 matrix.postConcat(ctx.ctm()); 69 matrix.mapRect(&dstRect, srcRect); 70 dstRect.roundOut(&dstBounds); 71 72 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height())); 73 if (NULL == device.get()) { 74 return false; 75 } 76 77 SkCanvas canvas(device.get()); 78 canvas.translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y())); 79 canvas.concat(matrix); 80 SkPaint paint; 81 82 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 83 paint.setFilterLevel(fFilterLevel); 84 canvas.drawBitmap(src, srcRect.x(), srcRect.y(), &paint); 85 86 *result = device.get()->accessBitmap(false); 87 offset->fX = dstBounds.fLeft; 88 offset->fY = dstBounds.fTop; 89 return true; 90 } 91 92 void SkMatrixImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { 93 SkRect bounds = src; 94 if (getInput(0)) { 95 getInput(0)->computeFastBounds(src, &bounds); 96 } 97 SkMatrix matrix; 98 matrix.setTranslate(-bounds.x(), -bounds.y()); 99 matrix.postConcat(fTransform); 100 matrix.postTranslate(bounds.x(), bounds.y()); 101 matrix.mapRect(dst, bounds); 102 } 103 104 bool SkMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 105 SkIRect* dst) const { 106 SkMatrix transformInverse; 107 if (!fTransform.invert(&transformInverse)) { 108 return false; 109 } 110 SkMatrix matrix; 111 if (!ctm.invert(&matrix)) { 112 return false; 113 } 114 matrix.postConcat(transformInverse); 115 matrix.postConcat(ctm); 116 SkRect floatBounds; 117 matrix.mapRect(&floatBounds, SkRect::Make(src)); 118 SkIRect bounds; 119 floatBounds.roundOut(&bounds); 120 if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { 121 return false; 122 } 123 124 *dst = bounds; 125 return true; 126 } 127