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 = 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
initModes(const SkXfermode::Mode modes[])31 void 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
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
onFilterImage(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const58 bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
59 const Context& ctx,
60 SkBitmap* result, SkIPoint* offset) const {
61 if (countInputs() < 1) {
62 return false;
63 }
64
65 SkIRect bounds;
66 if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
67 return false;
68 }
69
70 const int x0 = bounds.left();
71 const int y0 = bounds.top();
72
73 SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
74 if (NULL == dst) {
75 return false;
76 }
77 SkCanvas canvas(dst);
78 SkPaint paint;
79
80 int inputCount = countInputs();
81 for (int i = 0; i < inputCount; ++i) {
82 SkBitmap tmp;
83 const SkBitmap* srcPtr;
84 SkIPoint pos = SkIPoint::Make(0, 0);
85 SkImageFilter* filter = getInput(i);
86 if (filter) {
87 if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) {
88 return false;
89 }
90 srcPtr = &tmp;
91 } else {
92 srcPtr = &src;
93 }
94
95 if (fModes) {
96 paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
97 } else {
98 paint.setXfermode(NULL);
99 }
100 canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
101 }
102
103 offset->fX = bounds.left();
104 offset->fY = bounds.top();
105 *result = dst->accessBitmap(false);
106 return true;
107 }
108
CreateProc(SkReadBuffer & buffer)109 SkFlattenable* SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) {
110 Common common;
111 if (!common.unflatten(buffer, -1)) {
112 return NULL;
113 }
114
115 const int count = common.inputCount();
116 bool hasModes = buffer.readBool();
117 if (hasModes) {
118 SkAutoSTArray<4, SkXfermode::Mode> modes(count);
119 SkAutoSTArray<4, uint8_t> modes8(count);
120 if (!buffer.readByteArray(modes8.get(), count)) {
121 return NULL;
122 }
123 for (int i = 0; i < count; ++i) {
124 modes[i] = (SkXfermode::Mode)modes8[i];
125 buffer.validate(SkIsValidMode(modes[i]));
126 }
127 if (!buffer.isValid()) {
128 return NULL;
129 }
130 return Create(common.inputs(), count, modes.get(), &common.cropRect());
131 }
132 return Create(common.inputs(), count, NULL, &common.cropRect());
133 }
134
flatten(SkWriteBuffer & buffer) const135 void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
136 this->INHERITED::flatten(buffer);
137 buffer.writeBool(fModes != NULL);
138 if (fModes) {
139 buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
140 }
141 }
142
143 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const144 void SkMergeImageFilter::toString(SkString* str) const {
145 str->appendf("SkMergeImageFilter: (");
146
147 for (int i = 0; i < this->countInputs(); ++i) {
148 SkImageFilter* filter = this->getInput(i);
149 str->appendf("%d: (", i);
150 filter->toString(str);
151 str->appendf(")");
152 }
153
154 str->append(")");
155 }
156 #endif
157