1/*
2 * Copyright 2012 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 "SkOffsetImageFilter.h"
9#include "SkBitmap.h"
10#include "SkCanvas.h"
11#include "SkDevice.h"
12#include "SkReadBuffer.h"
13#include "SkWriteBuffer.h"
14#include "SkMatrix.h"
15#include "SkPaint.h"
16
17bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source,
18                                        const Context& ctx,
19                                        SkBitmap* result,
20                                        SkIPoint* offset) const {
21    SkImageFilter* input = getInput(0);
22    SkBitmap src = source;
23    SkIPoint srcOffset = SkIPoint::Make(0, 0);
24#ifdef SK_DISABLE_OFFSETIMAGEFILTER_OPTIMIZATION
25    if (false) {
26#else
27    if (!cropRectIsSet()) {
28#endif
29        if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
30            return false;
31        }
32
33        SkVector vec;
34        ctx.ctm().mapVectors(&vec, &fOffset, 1);
35
36        offset->fX = srcOffset.fX + SkScalarRoundToInt(vec.fX);
37        offset->fY = srcOffset.fY + SkScalarRoundToInt(vec.fY);
38        *result = src;
39    } else {
40        if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
41            return false;
42        }
43
44        SkIRect bounds;
45        if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) {
46            return false;
47        }
48
49        SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
50        if (NULL == device.get()) {
51            return false;
52        }
53        SkCanvas canvas(device);
54        SkPaint paint;
55        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
56        canvas.translate(SkIntToScalar(srcOffset.fX - bounds.fLeft),
57                         SkIntToScalar(srcOffset.fY - bounds.fTop));
58        SkVector vec;
59        ctx.ctm().mapVectors(&vec, &fOffset, 1);
60        canvas.drawBitmap(src, vec.x(), vec.y(), &paint);
61        *result = device->accessBitmap(false);
62        offset->fX = bounds.fLeft;
63        offset->fY = bounds.fTop;
64    }
65    return true;
66}
67
68void SkOffsetImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
69    if (getInput(0)) {
70        getInput(0)->computeFastBounds(src, dst);
71    } else {
72        *dst = src;
73    }
74    SkRect copy = *dst;
75    dst->offset(fOffset.fX, fOffset.fY);
76    dst->join(copy);
77}
78
79bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
80                                         SkIRect* dst) const {
81    SkVector vec;
82    ctm.mapVectors(&vec, &fOffset, 1);
83
84    SkIRect bounds = src;
85    bounds.offset(-SkScalarCeilToInt(vec.fX), -SkScalarCeilToInt(vec.fY));
86    bounds.join(src);
87    if (getInput(0)) {
88        return getInput(0)->filterBounds(bounds, ctm, dst);
89    }
90    *dst = bounds;
91    return true;
92}
93
94SkFlattenable* SkOffsetImageFilter::CreateProc(SkReadBuffer& buffer) {
95    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
96    SkPoint offset;
97    buffer.readPoint(&offset);
98    return Create(offset.x(), offset.y(), common.getInput(0), &common.cropRect(), common.uniqueID());
99}
100
101void SkOffsetImageFilter::flatten(SkWriteBuffer& buffer) const {
102    this->INHERITED::flatten(buffer);
103    buffer.writePoint(fOffset);
104}
105
106SkOffsetImageFilter::SkOffsetImageFilter(SkScalar dx, SkScalar dy, SkImageFilter* input,
107                                         const CropRect* cropRect, uint32_t uniqueID)
108  : INHERITED(1, &input, cropRect, uniqueID) {
109    fOffset.set(dx, dy);
110}
111
112#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
113SkOffsetImageFilter::SkOffsetImageFilter(SkReadBuffer& buffer)
114  : INHERITED(1, buffer) {
115    buffer.readPoint(&fOffset);
116    buffer.validate(SkScalarIsFinite(fOffset.fX) &&
117                    SkScalarIsFinite(fOffset.fY));
118}
119#endif
120