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
initAllocModes()17 void SkMergeImageFilter::initAllocModes() {
18 int inputCount = this->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 = nullptr;
28 }
29 }
30
initModes(const SkXfermode::Mode modes[])31 void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
32 if (modes) {
33 this->initAllocModes();
34 int inputCount = this->countInputs();
35 for (int i = 0; i < inputCount; ++i) {
36 fModes[i] = SkToU8(modes[i]);
37 }
38 } else {
39 fModes = nullptr;
40 }
41 }
42
SkMergeImageFilter(SkImageFilter * filters[],int count,const SkXfermode::Mode modes[],const CropRect * cropRect)43 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
44 const SkXfermode::Mode modes[],
45 const CropRect* cropRect)
46 : INHERITED(count, filters, cropRect) {
47 SkASSERT(count >= 0);
48 this->initModes(modes);
49 }
50
~SkMergeImageFilter()51 SkMergeImageFilter::~SkMergeImageFilter() {
52
53 if (fModes != SkTCast<uint8_t*>(fStorage)) {
54 sk_free(fModes);
55 }
56 }
57
onFilterImageDeprecated(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const58 bool SkMergeImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src,
59 const Context& ctx,
60 SkBitmap* result, SkIPoint* offset) const {
61 int inputCount = this->countInputs();
62 if (inputCount < 1) {
63 return false;
64 }
65
66 SkIRect bounds;
67
68 SkAutoTDeleteArray<SkBitmap> inputs(new SkBitmap[inputCount]);
69 SkAutoTDeleteArray<SkIPoint> offsets(new SkIPoint[inputCount]);
70 bool didProduceResult = false;
71
72 // Filter all of the inputs.
73 for (int i = 0; i < inputCount; ++i) {
74 inputs[i] = src;
75 offsets[i].setZero();
76 if (!this->filterInputDeprecated(i, proxy, src, ctx, &inputs[i], &offsets[i])) {
77 inputs[i].reset();
78 continue;
79 }
80 SkIRect srcBounds;
81 inputs[i].getBounds(&srcBounds);
82 srcBounds.offset(offsets[i]);
83 if (!didProduceResult) {
84 bounds = srcBounds;
85 didProduceResult = true;
86 } else {
87 bounds.join(srcBounds);
88 }
89 }
90 if (!didProduceResult) {
91 return false;
92 }
93
94 // Apply the crop rect to the union of the inputs' bounds.
95 this->getCropRect().applyTo(bounds, ctx.ctm(), &bounds);
96 if (!bounds.intersect(ctx.clipBounds())) {
97 return false;
98 }
99
100 const int x0 = bounds.left();
101 const int y0 = bounds.top();
102
103 // Allocate the destination buffer.
104 SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
105 if (nullptr == dst) {
106 return false;
107 }
108 SkCanvas canvas(dst);
109
110 // Composite all of the filter inputs.
111 for (int i = 0; i < inputCount; ++i) {
112 SkPaint paint;
113 if (fModes) {
114 paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
115 }
116 canvas.drawBitmap(inputs[i], SkIntToScalar(offsets[i].x() - x0),
117 SkIntToScalar(offsets[i].y() - y0), &paint);
118 }
119
120 offset->fX = bounds.left();
121 offset->fY = bounds.top();
122 *result = dst->accessBitmap(false);
123 return true;
124 }
125
CreateProc(SkReadBuffer & buffer)126 SkFlattenable* SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) {
127 Common common;
128 if (!common.unflatten(buffer, -1)) {
129 return nullptr;
130 }
131
132 const int count = common.inputCount();
133 bool hasModes = buffer.readBool();
134 if (hasModes) {
135 SkAutoSTArray<4, SkXfermode::Mode> modes(count);
136 SkAutoSTArray<4, uint8_t> modes8(count);
137 if (!buffer.readByteArray(modes8.get(), count)) {
138 return nullptr;
139 }
140 for (int i = 0; i < count; ++i) {
141 modes[i] = (SkXfermode::Mode)modes8[i];
142 buffer.validate(SkIsValidMode(modes[i]));
143 }
144 if (!buffer.isValid()) {
145 return nullptr;
146 }
147 return Create(common.inputs(), count, modes.get(), &common.cropRect());
148 }
149 return Create(common.inputs(), count, nullptr, &common.cropRect());
150 }
151
flatten(SkWriteBuffer & buffer) const152 void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
153 this->INHERITED::flatten(buffer);
154 buffer.writeBool(fModes != nullptr);
155 if (fModes) {
156 buffer.writeByteArray(fModes, this->countInputs() * sizeof(fModes[0]));
157 }
158 }
159
160 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const161 void SkMergeImageFilter::toString(SkString* str) const {
162 str->appendf("SkMergeImageFilter: (");
163
164 for (int i = 0; i < this->countInputs(); ++i) {
165 SkImageFilter* filter = this->getInput(i);
166 str->appendf("%d: (", i);
167 filter->toString(str);
168 str->appendf(")");
169 }
170
171 str->append(")");
172 }
173 #endif
174