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