1fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org/*
2fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org * Copyright 2014 The Android Open Source Project
3fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org *
4fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org * Use of this source code is governed by a BSD-style license that can be
5fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org * found in the LICENSE file.
6fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org */
7fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
8fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkMatrixImageFilter.h"
908541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips
10fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkCanvas.h"
11fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkReadBuffer.h"
1208541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips#include "SkSpecialImage.h"
1308541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips#include "SkSpecialSurface.h"
14fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkWriteBuffer.h"
15fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkRect.h"
16fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
17fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgSkMatrixImageFilter::SkMatrixImageFilter(const SkMatrix& transform,
1893a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed                                         SkFilterQuality filterQuality,
19ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips                                         sk_sp<SkImageFilter> input)
20ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips    : INHERITED(&input, 1, nullptr)
2108541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    , fTransform(transform)
2208541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    , fFilterQuality(filterQuality) {
23fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
24fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
25ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillipssk_sp<SkImageFilter> SkMatrixImageFilter::Make(const SkMatrix& transform,
26ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips                                               SkFilterQuality filterQuality,
27ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips                                               sk_sp<SkImageFilter> input) {
28ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips    return sk_sp<SkImageFilter>(new SkMatrixImageFilter(transform,
29ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips                                                        filterQuality,
30ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips                                                        std::move(input)));
31fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
32fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
3360c9b58b3214b0154c931656e91e39b230e987d8reedsk_sp<SkFlattenable> SkMatrixImageFilter::CreateProc(SkReadBuffer& buffer) {
349fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
359fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkMatrix matrix;
369fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.readMatrix(&matrix);
3793a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed    SkFilterQuality quality = static_cast<SkFilterQuality>(buffer.readInt());
38ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips    return Make(matrix, quality, common.getInput(0));
399fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
40fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
41fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgvoid SkMatrixImageFilter::flatten(SkWriteBuffer& buffer) const {
42fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    this->INHERITED::flatten(buffer);
43fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    buffer.writeMatrix(fTransform);
4493a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed    buffer.writeInt(fFilterQuality);
45fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
46fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
4708541d5340a9cadcca60b2f04b1f2dde73be2587robertphillipssk_sp<SkSpecialImage> SkMatrixImageFilter::onFilterImage(SkSpecialImage* source,
4808541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips                                                         const Context& ctx,
4908541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips                                                         SkIPoint* offset) const {
50fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
5108541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    SkIPoint inputOffset = SkIPoint::Make(0, 0);
5208541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
5308541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    if (!input) {
5408541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips        return nullptr;
55fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
56fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
57fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix matrix;
58fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (!ctx.ctm().invert(&matrix)) {
5908541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips        return nullptr;
60fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
61fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(fTransform);
62fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(ctx.ctm());
6308541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips
6408541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    const SkIRect srcBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
6508541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips                                                input->width(), input->height());
6608541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    const SkRect srcRect = SkRect::Make(srcBounds);
6708541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips
6808541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    SkRect dstRect;
69fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.mapRect(&dstRect, srcRect);
7008541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    SkIRect dstBounds;
71fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    dstRect.roundOut(&dstBounds);
72fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
73eed6b0e1d865a1f93143c09961debba0aca592cabrianosman    sk_sp<SkSpecialSurface> surf(input->makeSurface(ctx.outputProperties(), dstBounds.size()));
7408541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    if (!surf) {
7508541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips        return nullptr;
76fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
77fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
7808541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    SkCanvas* canvas = surf->getCanvas();
7908541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    SkASSERT(canvas);
8008541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips
8108541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    canvas->clear(0x0);
82daa57bfd4204f5a7d304c580bcf5ad99d0121e1freed
8308541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    canvas->translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y()));
8408541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    canvas->concat(matrix);
8508541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips
8608541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    SkPaint paint;
878c30a8196dd5903d2d23b4d0a5dc888e802bf698reed    paint.setAntiAlias(true);
88374772bd61951f01bf84fe17bf53d8867681c9aereed    paint.setBlendMode(SkBlendMode::kSrc);
89daa57bfd4204f5a7d304c580bcf5ad99d0121e1freed    paint.setFilterQuality(fFilterQuality);
90fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
9108541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    input->draw(canvas, srcRect.x(), srcRect.y(), &paint);
9208541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips
93fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    offset->fX = dstBounds.fLeft;
94fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    offset->fY = dstBounds.fTop;
9508541d5340a9cadcca60b2f04b1f2dde73be2587robertphillips    return surf->makeImageSnapshot();
96fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
97fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
98e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblancoSkRect SkMatrixImageFilter::computeFastBounds(const SkRect& src) const {
99e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco    SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
100e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco    SkRect dst;
101e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco    fTransform.mapRect(&dst, bounds);
102e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco    return dst;
103fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
104fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
105e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblancoSkIRect SkMatrixImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
106e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco                                                MapDirection direction) const {
107fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix matrix;
108fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (!ctm.invert(&matrix)) {
109e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco        return src;
110db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    }
111db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    if (kForward_MapDirection == direction) {
112db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco        matrix.postConcat(fTransform);
113db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco    } else {
114db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco        SkMatrix transformInverse;
115db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco        if (!fTransform.invert(&transformInverse)) {
116e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco            return src;
117db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco        }
118db64af3b178a19ecb47d2b9a373113687d8921fdsenorblanco        matrix.postConcat(transformInverse);
119fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
120fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(ctm);
121fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkRect floatBounds;
122fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.mapRect(&floatBounds, SkRect::Make(src));
123e5e79840ef38ab1d3f03abcf1b2df66fb9940018senorblanco    return floatBounds.roundOut();
124fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
125f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
126f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#ifndef SK_IGNORE_TO_STRING
127f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillipsvoid SkMatrixImageFilter::toString(SkString* str) const {
128f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("SkMatrixImageFilter: (");
129f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
130f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf("transform: (%f %f %f %f %f %f %f %f %f)",
131f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fTransform[SkMatrix::kMScaleX],
132f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fTransform[SkMatrix::kMSkewX],
133f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fTransform[SkMatrix::kMTransX],
134f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fTransform[SkMatrix::kMSkewY],
135f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fTransform[SkMatrix::kMScaleY],
136f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fTransform[SkMatrix::kMTransY],
137f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fTransform[SkMatrix::kMPersp0],
138f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fTransform[SkMatrix::kMPersp1],
139f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips                 fTransform[SkMatrix::kMPersp2]);
140f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
141f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->append("<dt>FilterLevel:</dt><dd>");
142f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    static const char* gFilterLevelStrings[] = { "None", "Low", "Medium", "High" };
14393a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed    str->append(gFilterLevelStrings[fFilterQuality]);
144f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->append("</dd>");
145f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips
146f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips    str->appendf(")");
147f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips}
148f3f5bad7ded35265c0b5d042cc4174386b197a33robertphillips#endif
149