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