Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2015 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 "SkImageSource.h"
      9 
     10 #include "SkCanvas.h"
     11 #include "SkColorSpaceXformer.h"
     12 #include "SkImage.h"
     13 #include "SkReadBuffer.h"
     14 #include "SkSpecialImage.h"
     15 #include "SkSpecialSurface.h"
     16 #include "SkWriteBuffer.h"
     17 #include "SkString.h"
     18 
     19 sk_sp<SkImageFilter> SkImageSource::Make(sk_sp<SkImage> image) {
     20     if (!image) {
     21         return nullptr;
     22     }
     23 
     24     return sk_sp<SkImageFilter>(new SkImageSource(std::move(image)));
     25 }
     26 
     27 sk_sp<SkImageFilter> SkImageSource::Make(sk_sp<SkImage> image,
     28                                          const SkRect& srcRect,
     29                                          const SkRect& dstRect,
     30                                          SkFilterQuality filterQuality) {
     31     if (!image || srcRect.width() <= 0.0f || srcRect.height() <= 0.0f) {
     32         return nullptr;
     33     }
     34 
     35     return sk_sp<SkImageFilter>(new SkImageSource(std::move(image),
     36                                                   srcRect, dstRect,
     37                                                   filterQuality));
     38 }
     39 
     40 SkImageSource::SkImageSource(sk_sp<SkImage> image)
     41     : INHERITED(nullptr, 0, nullptr)
     42     , fImage(std::move(image))
     43     , fSrcRect(SkRect::MakeIWH(fImage->width(), fImage->height()))
     44     , fDstRect(fSrcRect)
     45     , fFilterQuality(kHigh_SkFilterQuality) {
     46 }
     47 
     48 SkImageSource::SkImageSource(sk_sp<SkImage> image,
     49                              const SkRect& srcRect,
     50                              const SkRect& dstRect,
     51                              SkFilterQuality filterQuality)
     52     : INHERITED(nullptr, 0, nullptr)
     53     , fImage(std::move(image))
     54     , fSrcRect(srcRect)
     55     , fDstRect(dstRect)
     56     , fFilterQuality(filterQuality) {
     57 }
     58 
     59 sk_sp<SkFlattenable> SkImageSource::CreateProc(SkReadBuffer& buffer) {
     60     SkFilterQuality filterQuality = (SkFilterQuality)buffer.readInt();
     61 
     62     SkRect src, dst;
     63     buffer.readRect(&src);
     64     buffer.readRect(&dst);
     65 
     66     sk_sp<SkImage> image(buffer.readImage());
     67     if (!image) {
     68         return nullptr;
     69     }
     70 
     71     return SkImageSource::Make(std::move(image), src, dst, filterQuality);
     72 }
     73 
     74 void SkImageSource::flatten(SkWriteBuffer& buffer) const {
     75     buffer.writeInt(fFilterQuality);
     76     buffer.writeRect(fSrcRect);
     77     buffer.writeRect(fDstRect);
     78     buffer.writeImage(fImage.get());
     79 }
     80 
     81 sk_sp<SkSpecialImage> SkImageSource::onFilterImage(SkSpecialImage* source, const Context& ctx,
     82                                                    SkIPoint* offset) const {
     83     SkRect dstRect;
     84     ctx.ctm().mapRect(&dstRect, fDstRect);
     85 
     86     SkRect bounds = SkRect::MakeIWH(fImage->width(), fImage->height());
     87     if (fSrcRect == bounds) {
     88         int iLeft = dstRect.fLeft;
     89         int iTop = dstRect.fTop;
     90         // TODO: this seems to be a very noise-prone way to determine this (esp. the floating-point
     91         // widths & heights).
     92         if (dstRect.width() == bounds.width() && dstRect.height() == bounds.height() &&
     93             iLeft == dstRect.fLeft && iTop == dstRect.fTop) {
     94             // The dest is just an un-scaled integer translation of the entire image; return it
     95             offset->fX = iLeft;
     96             offset->fY = iTop;
     97 
     98             return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(fImage->width(), fImage->height()),
     99                                                  fImage, ctx.outputProperties().colorSpace(),
    100                                                  &source->props());
    101         }
    102     }
    103 
    104     const SkIRect dstIRect = dstRect.roundOut();
    105 
    106     sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), dstIRect.size()));
    107     if (!surf) {
    108         return nullptr;
    109     }
    110 
    111     SkCanvas* canvas = surf->getCanvas();
    112     SkASSERT(canvas);
    113 
    114     // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075)
    115     canvas->clear(0x0);
    116 
    117     SkPaint paint;
    118 
    119     // Subtract off the integer component of the translation (will be applied in offset, below).
    120     dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop));
    121     paint.setBlendMode(SkBlendMode::kSrc);
    122     // FIXME: this probably shouldn't be necessary, but drawImageRect asserts
    123     // None filtering when it's translate-only
    124     paint.setFilterQuality(
    125         fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height() ?
    126                kNone_SkFilterQuality : fFilterQuality);
    127     canvas->drawImageRect(fImage.get(), fSrcRect, dstRect, &paint,
    128                           SkCanvas::kStrict_SrcRectConstraint);
    129 
    130     offset->fX = dstIRect.fLeft;
    131     offset->fY = dstIRect.fTop;
    132     return surf->makeImageSnapshot();
    133 }
    134 
    135 sk_sp<SkImageFilter> SkImageSource::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    136     SkASSERT(0 == this->countInputs());
    137 
    138     auto image = xformer->apply(fImage.get());
    139     if (image != fImage) {
    140         return SkImageSource::Make(image, fSrcRect, fDstRect, fFilterQuality);
    141     }
    142     return this->refMe();
    143 }
    144 
    145 SkRect SkImageSource::computeFastBounds(const SkRect& src) const {
    146     return fDstRect;
    147 }
    148 
    149 SkIRect SkImageSource::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
    150                                           MapDirection direction) const {
    151     if (kReverse_MapDirection == direction) {
    152         return SkImageFilter::onFilterNodeBounds(src, ctm, direction);
    153     }
    154 
    155     SkRect dstRect = fDstRect;
    156     ctm.mapRect(&dstRect);
    157     return dstRect.roundOut();
    158 }
    159 
    160 #ifndef SK_IGNORE_TO_STRING
    161 void SkImageSource::toString(SkString* str) const {
    162     str->appendf("SkImageSource: (");
    163     str->appendf("src: (%f,%f,%f,%f) dst: (%f,%f,%f,%f) ",
    164                  fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom,
    165                  fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom);
    166     str->appendf("image: (%d,%d)",
    167                  fImage->width(), fImage->height());
    168     str->append(")");
    169 }
    170 #endif
    171