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,
205e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco                                         SkImageFilter* input,
215e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco                                         uint32_t uniqueID)
225e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco  : INHERITED(1, &input, NULL, uniqueID),
23fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    fTransform(transform),
24fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    fFilterLevel(filterLevel) {
25fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
26fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
27fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgSkMatrixImageFilter* SkMatrixImageFilter::Create(const SkMatrix& transform,
28fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                                 SkPaint::FilterLevel filterLevel,
295e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco                                                 SkImageFilter* input,
305e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco                                                 uint32_t uniqueID) {
315e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco    return SkNEW_ARGS(SkMatrixImageFilter, (transform, filterLevel, input, uniqueID));
32fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
33fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
349fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
35fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgSkMatrixImageFilter::SkMatrixImageFilter(SkReadBuffer& buffer)
36fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org  : INHERITED(1, buffer) {
37fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    buffer.readMatrix(&fTransform);
38fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    fFilterLevel = static_cast<SkPaint::FilterLevel>(buffer.readInt());
39fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
409fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif
419fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
429fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkMatrixImageFilter::CreateProc(SkReadBuffer& buffer) {
439fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
449fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkMatrix matrix;
459fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    buffer.readMatrix(&matrix);
469fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    SkPaint::FilterLevel level = static_cast<SkPaint::FilterLevel>(buffer.readInt());
475e5f948b6b363dbfc8c076d8ff0c6b8e9ea99958senorblanco    return Create(matrix, level, common.getInput(0), common.uniqueID());
489fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
49fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
50fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgvoid SkMatrixImageFilter::flatten(SkWriteBuffer& buffer) const {
51fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    this->INHERITED::flatten(buffer);
52fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    buffer.writeMatrix(fTransform);
53fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    buffer.writeInt(fFilterLevel);
54fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
55fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
56fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgSkMatrixImageFilter::~SkMatrixImageFilter() {
57fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
58fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
59fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgbool SkMatrixImageFilter::onFilterImage(Proxy* proxy,
60fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                        const SkBitmap& source,
61fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                        const Context& ctx,
62fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                        SkBitmap* result,
63fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                        SkIPoint* offset) const {
64fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkBitmap src = source;
65fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkIPoint srcOffset = SkIPoint::Make(0, 0);
66fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) {
67fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
68fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
69fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
70fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkRect dstRect;
71fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkIRect srcBounds, dstBounds;
72fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    src.getBounds(&srcBounds);
73fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    srcBounds.offset(srcOffset);
74fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkRect srcRect = SkRect::Make(srcBounds);
75fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix matrix;
76fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (!ctx.ctm().invert(&matrix)) {
77fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
78fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
79fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(fTransform);
80fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(ctx.ctm());
81fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.mapRect(&dstRect, srcRect);
82fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    dstRect.roundOut(&dstBounds);
83fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
84fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height()));
85fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (NULL == device.get()) {
86fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
87fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
88fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
89fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkCanvas canvas(device.get());
90fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    canvas.translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y()));
91fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    canvas.concat(matrix);
92fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkPaint paint;
93fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
94fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
95fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    paint.setFilterLevel(fFilterLevel);
96fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    canvas.drawBitmap(src, srcRect.x(), srcRect.y(), &paint);
97fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
98fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    *result = device.get()->accessBitmap(false);
99fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    offset->fX = dstBounds.fLeft;
100fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    offset->fY = dstBounds.fTop;
101fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    return true;
102fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
103fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
104fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgvoid SkMatrixImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
105fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkRect bounds = src;
106fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (getInput(0)) {
107fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        getInput(0)->computeFastBounds(src, &bounds);
108fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
109fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix matrix;
110fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.setTranslate(-bounds.x(), -bounds.y());
111fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(fTransform);
112fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postTranslate(bounds.x(), bounds.y());
113fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.mapRect(dst, bounds);
114fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
115fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
116fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.orgbool SkMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
117fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org                                         SkIRect* dst) const {
118fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix transformInverse;
119fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (!fTransform.invert(&transformInverse)) {
120fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
121fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
122fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkMatrix matrix;
123fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (!ctm.invert(&matrix)) {
124fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
125fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
126fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(transformInverse);
127fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.postConcat(ctm);
128fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkRect floatBounds;
129fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    matrix.mapRect(&floatBounds, SkRect::Make(src));
130fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    SkIRect bounds;
131fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    floatBounds.roundOut(&bounds);
132fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) {
133fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org        return false;
134fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    }
135fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org
136fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    *dst = bounds;
137fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org    return true;
138fd0ec2c76a27ce26a62da23eb75017839959e7cbsenorblanco@chromium.org}
139