Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2013 Google Inc.
      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 "SkTileImageFilter.h"
      9 #include "SkColorSpaceXformer.h"
     10 #include "SkCanvas.h"
     11 #include "SkImage.h"
     12 #include "SkMatrix.h"
     13 #include "SkOffsetImageFilter.h"
     14 #include "SkPaint.h"
     15 #include "SkReadBuffer.h"
     16 #include "SkShader.h"
     17 #include "SkSpecialImage.h"
     18 #include "SkSpecialSurface.h"
     19 #include "SkSurface.h"
     20 #include "SkValidationUtils.h"
     21 #include "SkWriteBuffer.h"
     22 
     23 sk_sp<SkImageFilter> SkTileImageFilter::Make(const SkRect& srcRect, const SkRect& dstRect,
     24                                              sk_sp<SkImageFilter> input) {
     25     if (!SkIsValidRect(srcRect) || !SkIsValidRect(dstRect)) {
     26         return nullptr;
     27     }
     28     if (srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()) {
     29         SkRect ir = dstRect;
     30         if (!ir.intersect(srcRect)) {
     31             return input;
     32         }
     33         CropRect cropRect(ir);
     34         return SkOffsetImageFilter::Make(dstRect.x() - srcRect.x(),
     35                                          dstRect.y() - srcRect.y(),
     36                                          std::move(input),
     37                                          &cropRect);
     38     }
     39     return sk_sp<SkImageFilter>(new SkTileImageFilter(srcRect, dstRect, std::move(input)));
     40 }
     41 
     42 sk_sp<SkSpecialImage> SkTileImageFilter::onFilterImage(SkSpecialImage* source,
     43                                                        const Context& ctx,
     44                                                        SkIPoint* offset) const {
     45     SkIPoint inputOffset = SkIPoint::Make(0, 0);
     46     sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
     47     if (!input) {
     48         return nullptr;
     49     }
     50 
     51     SkRect dstRect;
     52     ctx.ctm().mapRect(&dstRect, fDstRect);
     53     if (!dstRect.intersect(SkRect::Make(ctx.clipBounds()))) {
     54         return nullptr;
     55     }
     56 
     57     const SkIRect dstIRect = dstRect.roundOut();
     58     if (!fSrcRect.width() || !fSrcRect.height() || !dstIRect.width() || !dstIRect.height()) {
     59         return nullptr;
     60     }
     61 
     62     SkRect srcRect;
     63     ctx.ctm().mapRect(&srcRect, fSrcRect);
     64     SkIRect srcIRect;
     65     srcRect.roundOut(&srcIRect);
     66     srcIRect.offset(-inputOffset);
     67     const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height());
     68 
     69     if (!SkIRect::Intersects(srcIRect, inputBounds)) {
     70         return nullptr;
     71     }
     72 
     73     // We create an SkImage here b.c. it needs to be a tight fit for the tiling
     74     sk_sp<SkImage> subset;
     75     if (inputBounds.contains(srcIRect)) {
     76         subset = input->asImage(&srcIRect);
     77         if (!subset) {
     78             return nullptr;
     79         }
     80     } else {
     81         sk_sp<SkSurface> surf(input->makeTightSurface(ctx.outputProperties(), srcIRect.size()));
     82         if (!surf) {
     83             return nullptr;
     84         }
     85 
     86         SkCanvas* canvas = surf->getCanvas();
     87         SkASSERT(canvas);
     88 
     89         SkPaint paint;
     90         paint.setBlendMode(SkBlendMode::kSrc);
     91 
     92         input->draw(canvas,
     93                     SkIntToScalar(inputOffset.x()), SkIntToScalar(inputOffset.y()),
     94                     &paint);
     95 
     96         subset = surf->makeImageSnapshot();
     97     }
     98     SkASSERT(subset->width() == srcIRect.width());
     99     SkASSERT(subset->height() == srcIRect.height());
    100 
    101     sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), dstIRect.size()));
    102     if (!surf) {
    103         return nullptr;
    104     }
    105 
    106     SkCanvas* canvas = surf->getCanvas();
    107     SkASSERT(canvas);
    108 
    109     SkPaint paint;
    110     paint.setBlendMode(SkBlendMode::kSrc);
    111     paint.setShader(subset->makeShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
    112     canvas->translate(-dstRect.fLeft, -dstRect.fTop);
    113     canvas->drawRect(dstRect, paint);
    114     offset->fX = dstIRect.fLeft;
    115     offset->fY = dstIRect.fTop;
    116     return surf->makeImageSnapshot();
    117 }
    118 
    119 sk_sp<SkImageFilter> SkTileImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    120     SkASSERT(1 == this->countInputs());
    121 
    122     auto input = xformer->apply(this->getInput(0));
    123     if (input.get() != this->getInput(0)) {
    124         return SkTileImageFilter::Make(fSrcRect, fDstRect, std::move(input));
    125     }
    126     return this->refMe();
    127 }
    128 
    129 SkIRect SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
    130                                               MapDirection direction) const {
    131     SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect;
    132     ctm.mapRect(&rect);
    133     return rect.roundOut();
    134 }
    135 
    136 SkIRect SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix&, MapDirection) const {
    137     // Don't recurse into inputs.
    138     return src;
    139 }
    140 
    141 SkRect SkTileImageFilter::computeFastBounds(const SkRect& src) const {
    142     return fDstRect;
    143 }
    144 
    145 sk_sp<SkFlattenable> SkTileImageFilter::CreateProc(SkReadBuffer& buffer) {
    146     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
    147     SkRect src, dst;
    148     buffer.readRect(&src);
    149     buffer.readRect(&dst);
    150     return Make(src, dst, common.getInput(0));
    151 }
    152 
    153 void SkTileImageFilter::flatten(SkWriteBuffer& buffer) const {
    154     this->INHERITED::flatten(buffer);
    155     buffer.writeRect(fSrcRect);
    156     buffer.writeRect(fDstRect);
    157 }
    158 
    159 #ifndef SK_IGNORE_TO_STRING
    160 void SkTileImageFilter::toString(SkString* str) const {
    161     str->appendf("SkTileImageFilter: (");
    162     str->appendf("src: %.2f %.2f %.2f %.2f",
    163                  fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom);
    164     str->appendf(" dst: %.2f %.2f %.2f %.2f",
    165                  fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom);
    166     if (this->getInput(0)) {
    167         str->appendf("input: (");
    168         this->getInput(0)->toString(str);
    169         str->appendf(")");
    170     }
    171     str->append(")");
    172 }
    173 #endif
    174