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