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 uint32_t uniqueID) 22 : INHERITED(1, &input, NULL, uniqueID), 23 fTransform(transform), 24 fFilterLevel(filterLevel) { 25 } 26 27 SkMatrixImageFilter* 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 35 SkMatrixImageFilter::SkMatrixImageFilter(SkReadBuffer& buffer) 36 : INHERITED(1, buffer) { 37 buffer.readMatrix(&fTransform); 38 fFilterLevel = static_cast<SkPaint::FilterLevel>(buffer.readInt()); 39 } 40 #endif 41 42 SkFlattenable* 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 50 void SkMatrixImageFilter::flatten(SkWriteBuffer& buffer) const { 51 this->INHERITED::flatten(buffer); 52 buffer.writeMatrix(fTransform); 53 buffer.writeInt(fFilterLevel); 54 } 55 56 SkMatrixImageFilter::~SkMatrixImageFilter() { 57 } 58 59 bool 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 104 void 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 116 bool 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