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 10#include "SkCanvas.h" 11#include "SkReadBuffer.h" 12#include "SkSpecialImage.h" 13#include "SkSpecialSurface.h" 14#include "SkWriteBuffer.h" 15#include "SkRect.h" 16 17SkMatrixImageFilter::SkMatrixImageFilter(const SkMatrix& transform, 18 SkFilterQuality filterQuality, 19 sk_sp<SkImageFilter> input) 20 : INHERITED(&input, 1, nullptr) 21 , fTransform(transform) 22 , fFilterQuality(filterQuality) { 23} 24 25sk_sp<SkImageFilter> SkMatrixImageFilter::Make(const SkMatrix& transform, 26 SkFilterQuality filterQuality, 27 sk_sp<SkImageFilter> input) { 28 return sk_sp<SkImageFilter>(new SkMatrixImageFilter(transform, 29 filterQuality, 30 std::move(input))); 31} 32 33sk_sp<SkFlattenable> SkMatrixImageFilter::CreateProc(SkReadBuffer& buffer) { 34 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 35 SkMatrix matrix; 36 buffer.readMatrix(&matrix); 37 SkFilterQuality quality = static_cast<SkFilterQuality>(buffer.readInt()); 38 return Make(matrix, quality, common.getInput(0)); 39} 40 41void SkMatrixImageFilter::flatten(SkWriteBuffer& buffer) const { 42 this->INHERITED::flatten(buffer); 43 buffer.writeMatrix(fTransform); 44 buffer.writeInt(fFilterQuality); 45} 46 47sk_sp<SkSpecialImage> SkMatrixImageFilter::onFilterImage(SkSpecialImage* source, 48 const Context& ctx, 49 SkIPoint* offset) const { 50 51 SkIPoint inputOffset = SkIPoint::Make(0, 0); 52 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); 53 if (!input) { 54 return nullptr; 55 } 56 57 SkMatrix matrix; 58 if (!ctx.ctm().invert(&matrix)) { 59 return nullptr; 60 } 61 matrix.postConcat(fTransform); 62 matrix.postConcat(ctx.ctm()); 63 64 const SkIRect srcBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(), 65 input->width(), input->height()); 66 const SkRect srcRect = SkRect::Make(srcBounds); 67 68 SkRect dstRect; 69 matrix.mapRect(&dstRect, srcRect); 70 SkIRect dstBounds; 71 dstRect.roundOut(&dstBounds); 72 73 sk_sp<SkSpecialSurface> surf(input->makeSurface(ctx.outputProperties(), dstBounds.size())); 74 if (!surf) { 75 return nullptr; 76 } 77 78 SkCanvas* canvas = surf->getCanvas(); 79 SkASSERT(canvas); 80 81 canvas->clear(0x0); 82 83 canvas->translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y())); 84 canvas->concat(matrix); 85 86 SkPaint paint; 87 paint.setAntiAlias(true); 88 paint.setBlendMode(SkBlendMode::kSrc); 89 paint.setFilterQuality(fFilterQuality); 90 91 input->draw(canvas, srcRect.x(), srcRect.y(), &paint); 92 93 offset->fX = dstBounds.fLeft; 94 offset->fY = dstBounds.fTop; 95 return surf->makeImageSnapshot(); 96} 97 98SkRect SkMatrixImageFilter::computeFastBounds(const SkRect& src) const { 99 SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src; 100 SkRect dst; 101 fTransform.mapRect(&dst, bounds); 102 return dst; 103} 104 105SkIRect SkMatrixImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, 106 MapDirection direction) const { 107 SkMatrix matrix; 108 if (!ctm.invert(&matrix)) { 109 return src; 110 } 111 if (kForward_MapDirection == direction) { 112 matrix.postConcat(fTransform); 113 } else { 114 SkMatrix transformInverse; 115 if (!fTransform.invert(&transformInverse)) { 116 return src; 117 } 118 matrix.postConcat(transformInverse); 119 } 120 matrix.postConcat(ctm); 121 SkRect floatBounds; 122 matrix.mapRect(&floatBounds, SkRect::Make(src)); 123 return floatBounds.roundOut(); 124} 125 126#ifndef SK_IGNORE_TO_STRING 127void SkMatrixImageFilter::toString(SkString* str) const { 128 str->appendf("SkMatrixImageFilter: ("); 129 130 str->appendf("transform: (%f %f %f %f %f %f %f %f %f)", 131 fTransform[SkMatrix::kMScaleX], 132 fTransform[SkMatrix::kMSkewX], 133 fTransform[SkMatrix::kMTransX], 134 fTransform[SkMatrix::kMSkewY], 135 fTransform[SkMatrix::kMScaleY], 136 fTransform[SkMatrix::kMTransY], 137 fTransform[SkMatrix::kMPersp0], 138 fTransform[SkMatrix::kMPersp1], 139 fTransform[SkMatrix::kMPersp2]); 140 141 str->append("<dt>FilterLevel:</dt><dd>"); 142 static const char* gFilterLevelStrings[] = { "None", "Low", "Medium", "High" }; 143 str->append(gFilterLevelStrings[fFilterQuality]); 144 str->append("</dd>"); 145 146 str->appendf(")"); 147} 148#endif 149