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 * first,SkImageFilter * second,SkXfermode::Mode mode,const CropRect * cropRect)43 SkMergeImageFilter::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
SkMergeImageFilter(SkImageFilter * filters[],int count,const SkXfermode::Mode modes[],const CropRect * cropRect)54 SkMergeImageFilter::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
~SkMergeImageFilter()61 SkMergeImageFilter::~SkMergeImageFilter() {
62
63 if (fModes != SkTCast<uint8_t*>(fStorage)) {
64 sk_free(fModes);
65 }
66 }
67
onFilterImage(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const68 bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
69 const Context& ctx,
70 SkBitmap* result, SkIPoint* offset) const {
71 if (countInputs() < 1) {
72 return false;
73 }
74
75 SkIRect bounds;
76 if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
77 return false;
78 }
79
80 const int x0 = bounds.left();
81 const int y0 = bounds.top();
82
83 SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
84 if (NULL == dst) {
85 return false;
86 }
87 SkCanvas canvas(dst);
88 SkPaint paint;
89
90 int inputCount = countInputs();
91 for (int i = 0; i < inputCount; ++i) {
92 SkBitmap tmp;
93 const SkBitmap* srcPtr;
94 SkIPoint pos = SkIPoint::Make(0, 0);
95 SkImageFilter* filter = getInput(i);
96 if (filter) {
97 if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) {
98 return false;
99 }
100 srcPtr = &tmp;
101 } else {
102 srcPtr = &src;
103 }
104
105 if (fModes) {
106 paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
107 } else {
108 paint.setXfermode(NULL);
109 }
110 canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
111 }
112
113 offset->fX = bounds.left();
114 offset->fY = bounds.top();
115 *result = dst->accessBitmap(false);
116 return true;
117 }
118
flatten(SkWriteBuffer & buffer) const119 void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
120 this->INHERITED::flatten(buffer);
121
122 buffer.writeBool(fModes != NULL);
123 if (fModes) {
124 buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
125 }
126 }
127
SkMergeImageFilter(SkReadBuffer & buffer)128 SkMergeImageFilter::SkMergeImageFilter(SkReadBuffer& buffer)
129 : INHERITED(-1, buffer) {
130 bool hasModes = buffer.readBool();
131 if (hasModes) {
132 this->initAllocModes();
133 int nbInputs = countInputs();
134 size_t size = nbInputs * sizeof(fModes[0]);
135 SkASSERT(buffer.getArrayCount() == size);
136 if (buffer.validate(buffer.getArrayCount() == size) &&
137 buffer.readByteArray(fModes, size)) {
138 for (int i = 0; i < nbInputs; ++i) {
139 buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
140 }
141 }
142 } else {
143 fModes = 0;
144 }
145 }
146