1/* 2 * Copyright 2012 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 "SkOffsetImageFilter.h" 9 10#include "SkCanvas.h" 11#include "SkMatrix.h" 12#include "SkPaint.h" 13#include "SkReadBuffer.h" 14#include "SkSpecialImage.h" 15#include "SkSpecialSurface.h" 16#include "SkWriteBuffer.h" 17 18sk_sp<SkImageFilter> SkOffsetImageFilter::Make(SkScalar dx, SkScalar dy, 19 sk_sp<SkImageFilter> input, 20 const CropRect* cropRect) { 21 if (!SkScalarIsFinite(dx) || !SkScalarIsFinite(dy)) { 22 return nullptr; 23 } 24 25 return sk_sp<SkImageFilter>(new SkOffsetImageFilter(dx, dy, std::move(input), cropRect)); 26} 27 28sk_sp<SkSpecialImage> SkOffsetImageFilter::onFilterImage(SkSpecialImage* source, 29 const Context& ctx, 30 SkIPoint* offset) const { 31 SkIPoint srcOffset = SkIPoint::Make(0, 0); 32 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &srcOffset)); 33 if (!input) { 34 return nullptr; 35 } 36 37 SkVector vec; 38 ctx.ctm().mapVectors(&vec, &fOffset, 1); 39 40 if (!this->cropRectIsSet()) { 41 offset->fX = srcOffset.fX + SkScalarRoundToInt(vec.fX); 42 offset->fY = srcOffset.fY + SkScalarRoundToInt(vec.fY); 43 return input; 44 } else { 45 SkIRect bounds; 46 SkIRect srcBounds = SkIRect::MakeWH(input->width(), input->height()); 47 srcBounds.offset(srcOffset); 48 if (!this->applyCropRect(ctx, srcBounds, &bounds)) { 49 return nullptr; 50 } 51 52 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size())); 53 if (!surf) { 54 return nullptr; 55 } 56 57 SkCanvas* canvas = surf->getCanvas(); 58 SkASSERT(canvas); 59 60 // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075) 61 canvas->clear(0x0); 62 63 SkPaint paint; 64 paint.setBlendMode(SkBlendMode::kSrc); 65 canvas->translate(SkIntToScalar(srcOffset.fX - bounds.fLeft), 66 SkIntToScalar(srcOffset.fY - bounds.fTop)); 67 68 input->draw(canvas, vec.x(), vec.y(), &paint); 69 70 offset->fX = bounds.fLeft; 71 offset->fY = bounds.fTop; 72 return surf->makeImageSnapshot(); 73 } 74} 75 76SkRect SkOffsetImageFilter::computeFastBounds(const SkRect& src) const { 77 SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src; 78 bounds.offset(fOffset.fX, fOffset.fY); 79 return bounds; 80} 81 82SkIRect SkOffsetImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, 83 MapDirection direction) const { 84 SkVector vec; 85 ctm.mapVectors(&vec, &fOffset, 1); 86 if (kReverse_MapDirection == direction) { 87 vec.negate(); 88 } 89 90 return src.makeOffset(SkScalarCeilToInt(vec.fX), SkScalarCeilToInt(vec.fY)); 91} 92 93sk_sp<SkFlattenable> SkOffsetImageFilter::CreateProc(SkReadBuffer& buffer) { 94 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 95 SkPoint offset; 96 buffer.readPoint(&offset); 97 return Make(offset.x(), offset.y(), common.getInput(0), &common.cropRect()); 98} 99 100void SkOffsetImageFilter::flatten(SkWriteBuffer& buffer) const { 101 this->INHERITED::flatten(buffer); 102 buffer.writePoint(fOffset); 103} 104 105SkOffsetImageFilter::SkOffsetImageFilter(SkScalar dx, SkScalar dy, 106 sk_sp<SkImageFilter> input, 107 const CropRect* cropRect) 108 : INHERITED(&input, 1, cropRect) { 109 fOffset.set(dx, dy); 110} 111 112#ifndef SK_IGNORE_TO_STRING 113void SkOffsetImageFilter::toString(SkString* str) const { 114 str->appendf("SkOffsetImageFilter: ("); 115 str->appendf("offset: (%f, %f) ", fOffset.fX, fOffset.fY); 116 str->append("input: ("); 117 if (this->getInput(0)) { 118 this->getInput(0)->toString(str); 119 } 120 str->append("))"); 121} 122#endif 123