Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2014 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 "SkMatrixImageFilter.h"
      9 
     10 #include "SkCanvas.h"
     11 #include "SkColorSpaceXformer.h"
     12 #include "SkImageFilterPriv.h"
     13 #include "SkReadBuffer.h"
     14 #include "SkSpecialImage.h"
     15 #include "SkSpecialSurface.h"
     16 #include "SkWriteBuffer.h"
     17 #include "SkRect.h"
     18 
     19 SkMatrixImageFilter::SkMatrixImageFilter(const SkMatrix& transform,
     20                                          SkFilterQuality filterQuality,
     21                                          sk_sp<SkImageFilter> input)
     22     : INHERITED(&input, 1, nullptr)
     23     , fTransform(transform)
     24     , fFilterQuality(filterQuality) {
     25 }
     26 
     27 sk_sp<SkImageFilter> SkMatrixImageFilter::Make(const SkMatrix& transform,
     28                                                SkFilterQuality filterQuality,
     29                                                sk_sp<SkImageFilter> input) {
     30     return sk_sp<SkImageFilter>(new SkMatrixImageFilter(transform,
     31                                                         filterQuality,
     32                                                         std::move(input)));
     33 }
     34 
     35 sk_sp<SkFlattenable> SkMatrixImageFilter::CreateProc(SkReadBuffer& buffer) {
     36     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
     37     SkMatrix matrix;
     38     buffer.readMatrix(&matrix);
     39 
     40     return Make(matrix, buffer.read32LE(kLast_SkFilterQuality), common.getInput(0));
     41 }
     42 
     43 void SkMatrixImageFilter::flatten(SkWriteBuffer& buffer) const {
     44     this->INHERITED::flatten(buffer);
     45     buffer.writeMatrix(fTransform);
     46     buffer.writeInt(fFilterQuality);
     47 }
     48 
     49 sk_sp<SkSpecialImage> SkMatrixImageFilter::onFilterImage(SkSpecialImage* source,
     50                                                          const Context& ctx,
     51                                                          SkIPoint* offset) const {
     52 
     53     SkIPoint inputOffset = SkIPoint::Make(0, 0);
     54     sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
     55     if (!input) {
     56         return nullptr;
     57     }
     58 
     59     SkMatrix matrix;
     60     if (!ctx.ctm().invert(&matrix)) {
     61         return nullptr;
     62     }
     63     matrix.postConcat(fTransform);
     64     matrix.postConcat(ctx.ctm());
     65 
     66     const SkIRect srcBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
     67                                                 input->width(), input->height());
     68     const SkRect srcRect = SkRect::Make(srcBounds);
     69 
     70     SkRect dstRect;
     71     matrix.mapRect(&dstRect, srcRect);
     72     SkIRect dstBounds;
     73     dstRect.roundOut(&dstBounds);
     74 
     75     sk_sp<SkSpecialSurface> surf(input->makeSurface(ctx.outputProperties(), dstBounds.size()));
     76     if (!surf) {
     77         return nullptr;
     78     }
     79 
     80     SkCanvas* canvas = surf->getCanvas();
     81     SkASSERT(canvas);
     82 
     83     canvas->clear(0x0);
     84 
     85     canvas->translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y()));
     86     canvas->concat(matrix);
     87 
     88     SkPaint paint;
     89     paint.setAntiAlias(true);
     90     paint.setBlendMode(SkBlendMode::kSrc);
     91     paint.setFilterQuality(fFilterQuality);
     92 
     93     input->draw(canvas, srcRect.x(), srcRect.y(), &paint);
     94 
     95     offset->fX = dstBounds.fLeft;
     96     offset->fY = dstBounds.fTop;
     97     return surf->makeImageSnapshot();
     98 }
     99 
    100 sk_sp<SkImageFilter> SkMatrixImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    101     SkASSERT(1 == this->countInputs());
    102     auto input = xformer->apply(this->getInput(0));
    103     if (input.get() != this->getInput(0)) {
    104         return SkMatrixImageFilter::Make(fTransform, fFilterQuality, std::move(input));
    105     }
    106     return this->refMe();
    107 }
    108 
    109 SkRect SkMatrixImageFilter::computeFastBounds(const SkRect& src) const {
    110     SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
    111     SkRect dst;
    112     fTransform.mapRect(&dst, bounds);
    113     return dst;
    114 }
    115 
    116 SkIRect SkMatrixImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
    117                                                 MapDirection direction) const {
    118     SkMatrix matrix;
    119     if (!ctm.invert(&matrix)) {
    120         return src;
    121     }
    122     if (kForward_MapDirection == direction) {
    123         matrix.postConcat(fTransform);
    124     } else {
    125         SkMatrix transformInverse;
    126         if (!fTransform.invert(&transformInverse)) {
    127             return src;
    128         }
    129         matrix.postConcat(transformInverse);
    130     }
    131     matrix.postConcat(ctm);
    132     SkRect floatBounds;
    133     matrix.mapRect(&floatBounds, SkRect::Make(src));
    134     return floatBounds.roundOut();
    135 }
    136 
    137 #ifndef SK_IGNORE_TO_STRING
    138 void SkMatrixImageFilter::toString(SkString* str) const {
    139     str->appendf("SkMatrixImageFilter: (");
    140 
    141     str->appendf("transform: (%f %f %f %f %f %f %f %f %f)",
    142                  fTransform[SkMatrix::kMScaleX],
    143                  fTransform[SkMatrix::kMSkewX],
    144                  fTransform[SkMatrix::kMTransX],
    145                  fTransform[SkMatrix::kMSkewY],
    146                  fTransform[SkMatrix::kMScaleY],
    147                  fTransform[SkMatrix::kMTransY],
    148                  fTransform[SkMatrix::kMPersp0],
    149                  fTransform[SkMatrix::kMPersp1],
    150                  fTransform[SkMatrix::kMPersp2]);
    151 
    152     str->append("<dt>FilterLevel:</dt><dd>");
    153     static const char* gFilterLevelStrings[] = { "None", "Low", "Medium", "High" };
    154     str->append(gFilterLevelStrings[fFilterQuality]);
    155     str->append("</dd>");
    156 
    157     str->appendf(")");
    158 }
    159 #endif
    160