2011-04-20 Cris Neckar <cdn@chromium.org>
[WebKit-https.git] / Source / WebCore / platform / graphics / filters / FilterEffect.cpp
1 /*
2  * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com>
3  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
4  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #if ENABLE(FILTERS)
25 #include "FilterEffect.h"
26
27 #include "Filter.h"
28 #include "ImageBuffer.h"
29 #include "TextStream.h"
30 #include <wtf/ByteArray.h>
31
32 namespace WebCore {
33
34 FilterEffect::FilterEffect(Filter* filter)
35     : m_alphaImage(false)
36     , m_filter(filter)
37     , m_hasX(false)
38     , m_hasY(false)
39     , m_hasWidth(false)
40     , m_hasHeight(false)
41 {
42     ASSERT(m_filter);
43 }
44
45 FilterEffect::~FilterEffect()
46 {
47 }
48
49 void FilterEffect::determineAbsolutePaintRect()
50 {
51     m_absolutePaintRect = IntRect();
52     unsigned size = m_inputEffects.size();
53     for (unsigned i = 0; i < size; ++i)
54         m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect());
55     
56     // SVG specification wants us to clip to primitive subregion.
57     m_absolutePaintRect.intersect(m_maxEffectRect);
58 }
59
60 IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const
61 {
62     ASSERT(hasResult());
63     IntPoint location = m_absolutePaintRect.location();
64     location.move(-effectRect.x(), -effectRect.y());
65     return IntRect(location, m_absolutePaintRect.size());
66 }
67
68 IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
69 {
70     return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(),
71                             srcRect.y() - m_absolutePaintRect.y()), srcRect.size());
72 }
73
74 FilterEffect* FilterEffect::inputEffect(unsigned number) const
75 {
76     ASSERT(number < m_inputEffects.size());
77     return m_inputEffects.at(number).get();
78 }
79
80 void FilterEffect::clearResult()
81 {
82     if (m_imageBufferResult)
83         m_imageBufferResult.clear();
84     if (m_unmultipliedImageResult)
85         m_unmultipliedImageResult.clear();
86     if (m_premultipliedImageResult)
87         m_premultipliedImageResult.clear();
88 }
89
90 ImageBuffer* FilterEffect::asImageBuffer()
91 {
92     if (!hasResult())
93         return 0;
94     if (m_imageBufferResult)
95         return m_imageBufferResult.get();
96     m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
97     IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
98     if (m_premultipliedImageResult)
99         m_imageBufferResult->putPremultipliedImageData(m_premultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
100     else
101         m_imageBufferResult->putUnmultipliedImageData(m_unmultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
102     return m_imageBufferResult.get();
103 }
104
105 PassRefPtr<ByteArray> FilterEffect::asUnmultipliedImage(const IntRect& rect)
106 {
107     RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
108     copyUnmultipliedImage(imageData.get(), rect);
109     return imageData.release();
110 }
111
112 PassRefPtr<ByteArray> FilterEffect::asPremultipliedImage(const IntRect& rect)
113 {
114     RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
115     copyPremultipliedImage(imageData.get(), rect);
116     return imageData.release();
117 }
118
119 inline void FilterEffect::copyImageBytes(ByteArray* source, ByteArray* destination, const IntRect& rect)
120 {
121     // Initialize the destination to transparent black, if not entirely covered by the source.
122     if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > m_absolutePaintRect.width() || rect.maxY() > m_absolutePaintRect.height())
123         memset(destination->data(), 0, destination->length());
124
125     // Early return if the rect does not intersect with the source.
126     if (rect.maxX() <= 0 || rect.maxY() <= 0 || rect.x() >= m_absolutePaintRect.width() || rect.y() >= m_absolutePaintRect.height())
127         return;
128
129     int xOrigin = rect.x();
130     int xDest = 0;
131     if (xOrigin < 0) {
132         xDest = -xOrigin;
133         xOrigin = 0;
134     }
135     int xEnd = rect.maxX();
136     if (xEnd > m_absolutePaintRect.width())
137         xEnd = m_absolutePaintRect.width();
138
139     int yOrigin = rect.y();
140     int yDest = 0;
141     if (yOrigin < 0) {
142         yDest = -yOrigin;
143         yOrigin = 0;
144     }
145     int yEnd = rect.maxY();
146     if (yEnd > m_absolutePaintRect.height())
147         yEnd = m_absolutePaintRect.height();
148
149     int size = (xEnd - xOrigin) * 4;
150     int destinationScanline = rect.width() * 4;
151     int sourceScanline = m_absolutePaintRect.width() * 4;
152     unsigned char *destinationPixel = destination->data() + ((yDest * rect.width()) + xDest) * 4;
153     unsigned char *sourcePixel = source->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4;
154
155     while (yOrigin < yEnd) {
156         memcpy(destinationPixel, sourcePixel, size);
157         destinationPixel += destinationScanline;
158         sourcePixel += sourceScanline;
159         ++yOrigin;
160     }
161 }
162
163 void FilterEffect::copyUnmultipliedImage(ByteArray* destination, const IntRect& rect)
164 {
165     ASSERT(hasResult());
166
167     if (!m_unmultipliedImageResult) {
168         // We prefer a conversion from the image buffer.
169         if (m_imageBufferResult)
170             m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
171         else {
172             m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
173             unsigned char* sourceComponent = m_premultipliedImageResult->data();
174             unsigned char* destinationComponent = m_unmultipliedImageResult->data();
175             unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
176             while (sourceComponent < end) {
177                 int alpha = sourceComponent[3];
178                 if (alpha) {
179                     destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha;
180                     destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha;
181                     destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha;
182                 } else {
183                     destinationComponent[0] = 0;
184                     destinationComponent[1] = 0;
185                     destinationComponent[2] = 0;
186                 }
187                 destinationComponent[3] = alpha;
188                 sourceComponent += 4;
189                 destinationComponent += 4;
190             }
191         }
192     }
193     copyImageBytes(m_unmultipliedImageResult.get(), destination, rect);
194 }
195
196 void FilterEffect::copyPremultipliedImage(ByteArray* destination, const IntRect& rect)
197 {
198     ASSERT(hasResult());
199
200     if (!m_premultipliedImageResult) {
201         // We prefer a conversion from the image buffer.
202         if (m_imageBufferResult)
203             m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
204         else {
205             m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
206             unsigned char* sourceComponent = m_unmultipliedImageResult->data();
207             unsigned char* destinationComponent = m_premultipliedImageResult->data();
208             unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
209             while (sourceComponent < end) {
210                 int alpha = sourceComponent[3];
211                 destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
212                 destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255;
213                 destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255;
214                 destinationComponent[3] = alpha;
215                 sourceComponent += 4;
216                 destinationComponent += 4;
217             }
218         }
219     }
220     copyImageBytes(m_premultipliedImageResult.get(), destination, rect);
221 }
222
223 ImageBuffer* FilterEffect::createImageBufferResult()
224 {
225     // Only one result type is allowed.
226     ASSERT(!hasResult());
227     determineAbsolutePaintRect();
228     if (m_absolutePaintRect.isEmpty())
229         return 0;
230     m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
231     if (!m_imageBufferResult)
232         return 0;
233     ASSERT(m_imageBufferResult->context());
234     return m_imageBufferResult.get();
235 }
236
237 ByteArray* FilterEffect::createUnmultipliedImageResult()
238 {
239     // Only one result type is allowed.
240     ASSERT(!hasResult());
241     determineAbsolutePaintRect();
242     if (m_absolutePaintRect.isEmpty())
243         return 0;
244     m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
245     return m_unmultipliedImageResult.get();
246 }
247
248 ByteArray* FilterEffect::createPremultipliedImageResult()
249 {
250     // Only one result type is allowed.
251     ASSERT(!hasResult());
252     determineAbsolutePaintRect();
253     if (m_absolutePaintRect.isEmpty())
254         return 0;
255     m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
256     return m_premultipliedImageResult.get();
257 }
258
259 TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
260 {
261     // FIXME: We should dump the subRegions of the filter primitives here later. This isn't
262     // possible at the moment, because we need more detailed informations from the target object.
263     return ts;
264 }
265
266 } // namespace WebCore
267
268 #endif // ENABLE(FILTERS)