SkMergeImageFilter.cpp revision 8b0e8ac5f582de80356019406e2975079bf0829d
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 "SkMergeImageFilter.h"
9#include "SkCanvas.h"
10#include "SkDevice.h"
11#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
13#include "SkValidationUtils.h"
14
15///////////////////////////////////////////////////////////////////////////////
16
17void SkMergeImageFilter::initAllocModes() {
18    int inputCount = countInputs();
19    if (inputCount) {
20        size_t size = sizeof(uint8_t) * inputCount;
21        if (size <= sizeof(fStorage)) {
22            fModes = SkTCast<uint8_t*>(fStorage);
23        } else {
24            fModes = SkTCast<uint8_t*>(sk_malloc_throw(size));
25        }
26    } else {
27        fModes = NULL;
28    }
29}
30
31void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
32    if (modes) {
33        this->initAllocModes();
34        int inputCount = countInputs();
35        for (int i = 0; i < inputCount; ++i) {
36            fModes[i] = SkToU8(modes[i]);
37        }
38    } else {
39        fModes = NULL;
40    }
41}
42
43SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
44                                       SkXfermode::Mode mode,
45                                       const CropRect* cropRect) : INHERITED(first, second, cropRect) {
46    if (SkXfermode::kSrcOver_Mode != mode) {
47        SkXfermode::Mode modes[] = { mode, mode };
48        this->initModes(modes);
49    } else {
50        fModes = NULL;
51    }
52}
53
54SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
55                                       const SkXfermode::Mode modes[],
56                                       const CropRect* cropRect) : INHERITED(count, filters, cropRect) {
57    SkASSERT(count >= 0);
58    this->initModes(modes);
59}
60
61SkMergeImageFilter::~SkMergeImageFilter() {
62
63    if (fModes != SkTCast<uint8_t*>(fStorage)) {
64        sk_free(fModes);
65    }
66}
67
68bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
69                                        SkIRect* dst) {
70    if (countInputs() < 1) {
71        return false;
72    }
73
74    SkIRect totalBounds;
75
76    int inputCount = countInputs();
77    for (int i = 0; i < inputCount; ++i) {
78        SkImageFilter* filter = getInput(i);
79        SkIRect r;
80        if (filter) {
81            if (!filter->filterBounds(src, ctm, &r)) {
82                return false;
83            }
84        } else {
85            r = src;
86        }
87        if (0 == i) {
88            totalBounds = r;
89        } else {
90            totalBounds.join(r);
91        }
92    }
93
94    // don't modify dst until now, so we don't accidentally change it in the
95    // loop, but then return false on the next filter.
96    *dst = totalBounds;
97    return true;
98}
99
100bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
101                                       const SkMatrix& ctm,
102                                       SkBitmap* result, SkIPoint* offset) {
103    if (countInputs() < 1) {
104        return false;
105    }
106
107    SkIRect bounds;
108    src.getBounds(&bounds);
109    if (!this->applyCropRect(&bounds, ctm)) {
110        return false;
111    }
112
113    const int x0 = bounds.left();
114    const int y0 = bounds.top();
115
116    SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
117    if (NULL == dst) {
118        return false;
119    }
120    SkCanvas canvas(dst);
121    SkPaint paint;
122
123    int inputCount = countInputs();
124    for (int i = 0; i < inputCount; ++i) {
125        SkBitmap tmp;
126        const SkBitmap* srcPtr;
127        SkIPoint pos = SkIPoint::Make(0, 0);
128        SkImageFilter* filter = getInput(i);
129        if (filter) {
130            if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) {
131                return false;
132            }
133            srcPtr = &tmp;
134        } else {
135            srcPtr = &src;
136        }
137
138        if (fModes) {
139            paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
140        } else {
141            paint.setXfermode(NULL);
142        }
143        canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
144    }
145
146    offset->fX = bounds.left();
147    offset->fY = bounds.top();
148    *result = dst->accessBitmap(false);
149    return true;
150}
151
152void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
153    this->INHERITED::flatten(buffer);
154
155    buffer.writeBool(fModes != NULL);
156    if (fModes) {
157        buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
158    }
159}
160
161SkMergeImageFilter::SkMergeImageFilter(SkReadBuffer& buffer)
162  : INHERITED(-1, buffer) {
163    bool hasModes = buffer.readBool();
164    if (hasModes) {
165        this->initAllocModes();
166        int nbInputs = countInputs();
167        size_t size = nbInputs * sizeof(fModes[0]);
168        SkASSERT(buffer.getArrayCount() == size);
169        if (buffer.validate(buffer.getArrayCount() == size) &&
170            buffer.readByteArray(fModes, size)) {
171            for (int i = 0; i < nbInputs; ++i) {
172                buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
173            }
174        }
175    } else {
176        fModes = 0;
177    }
178}
179