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"
9fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkBitmap.h"
10fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkCanvas.h"
11fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkDevice.h"
12fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkColorPriv.h"
13fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkReadBuffer.h"
14fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkWriteBuffer.h"
15fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkMatrix.h"
16fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org#include "SkRect.h"
17fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
18fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgSkMatrixImageFilter::SkMatrixImageFilter(const SkMatrix& transform,
19fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                         SkPaint::FilterLevel filterLevel,
20fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                         SkImageFilter* input)
21fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org  : INHERITED(input),
22fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    fTransform(transform),
23fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    fFilterLevel(filterLevel) {
24fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
25fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
26fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgSkMatrixImageFilter* SkMatrixImageFilter::Create(const SkMatrix& transform,
27fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                                 SkPaint::FilterLevel filterLevel,
28fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                                 SkImageFilter* input) {
29fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    return SkNEW_ARGS(SkMatrixImageFilter, (transform, filterLevel, input));
30fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
31fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
32fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgSkMatrixImageFilter::SkMatrixImageFilter(SkReadBuffer& buffer)
33fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org  : INHERITED(1, buffer) {
34fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    buffer.readMatrix(&fTransform);
35fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    fFilterLevel = static_cast<SkPaint::FilterLevel>(buffer.readInt());
36fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
37fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
38fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgvoid SkMatrixImageFilter::flatten(SkWriteBuffer& buffer) const {
39fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    this->INHERITED::flatten(buffer);
40fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    buffer.writeMatrix(fTransform);
41fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    buffer.writeInt(fFilterLevel);
42fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
43fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
44fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgSkMatrixImageFilter::~SkMatrixImageFilter() {
45fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
46fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
47fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgbool SkMatrixImageFilter::onFilterImage(Proxy* proxy,
48fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                        const SkBitmap& source,
49fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                        const Context& ctx,
50fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                        SkBitmap* result,
51fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                        SkIPoint* offset) const {
52fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkBitmap src = source;
53fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkIPoint srcOffset = SkIPoint::Make(0, 0);
54fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) {
55fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
56fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
57fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
58fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkRect dstRect;
59fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkIRect srcBounds, dstBounds;
60fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    src.getBounds(&srcBounds);
61fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    srcBounds.offset(srcOffset);
62fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkRect srcRect = SkRect::Make(srcBounds);
63fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix matrix;
64fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (!ctx.ctm().invert(&matrix)) {
65fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
66fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
67fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(fTransform);
68fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(ctx.ctm());
69fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.mapRect(&dstRect, srcRect);
70fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    dstRect.roundOut(&dstBounds);
71fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
72fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height()));
73fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (NULL == device.get()) {
74fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
75fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
76fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
77fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkCanvas canvas(device.get());
78fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    canvas.translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y()));
79fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    canvas.concat(matrix);
80fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkPaint paint;
81fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
82fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
83fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    paint.setFilterLevel(fFilterLevel);
84fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    canvas.drawBitmap(src, srcRect.x(), srcRect.y(), &paint);
85fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
86fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    *result = device.get()->accessBitmap(false);
87fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    offset->fX = dstBounds.fLeft;
88fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    offset->fY = dstBounds.fTop;
89fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    return true;
90fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
91fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
92fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgvoid SkMatrixImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
93fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkRect bounds = src;
94fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (getInput(0)) {
95fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        getInput(0)->computeFastBounds(src, &bounds);
96fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
97fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix matrix;
98fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.setTranslate(-bounds.x(), -bounds.y());
99fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(fTransform);
100fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postTranslate(bounds.x(), bounds.y());
101fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.mapRect(dst, bounds);
102fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
103fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
104fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgbool SkMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
105fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                         SkIRect* dst) const {
106fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix transformInverse;
107fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (!fTransform.invert(&transformInverse)) {
108fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
109fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
110fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix matrix;
111fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (!ctm.invert(&matrix)) {
112fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
113fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
114fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(transformInverse);
115fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(ctm);
116fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkRect floatBounds;
117fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.mapRect(&floatBounds, SkRect::Make(src));
118fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkIRect bounds;
119fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    floatBounds.roundOut(&bounds);
120fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) {
121fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
122fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
123fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
124fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    *dst = bounds;
125fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    return true;
126fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
127