Home | History | Annotate | Download | only in effects
      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