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
FilterEffect(Filter * filter)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
~FilterEffect()45 FilterEffect::~FilterEffect()
46 {
47 }
48
isFilterSizeValid(IntRect rect)49 inline bool isFilterSizeValid(IntRect rect)
50 {
51 if (rect.width() < 0 || rect.width() > kMaxFilterSize
52 || rect.height() < 0 || rect.height() > kMaxFilterSize)
53 return false;
54 return true;
55 }
56
determineAbsolutePaintRect()57 void FilterEffect::determineAbsolutePaintRect()
58 {
59 m_absolutePaintRect = IntRect();
60 unsigned size = m_inputEffects.size();
61 for (unsigned i = 0; i < size; ++i)
62 m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect());
63
64 // SVG specification wants us to clip to primitive subregion.
65 m_absolutePaintRect.intersect(enclosingIntRect(m_maxEffectRect));
66 }
67
requestedRegionOfInputImageData(const IntRect & effectRect) const68 IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const
69 {
70 ASSERT(hasResult());
71 IntPoint location = m_absolutePaintRect.location();
72 location.move(-effectRect.x(), -effectRect.y());
73 return IntRect(location, m_absolutePaintRect.size());
74 }
75
drawingRegionOfInputImage(const IntRect & srcRect) const76 IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
77 {
78 return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(),
79 srcRect.y() - m_absolutePaintRect.y()), srcRect.size());
80 }
81
inputEffect(unsigned number) const82 FilterEffect* FilterEffect::inputEffect(unsigned number) const
83 {
84 ASSERT(number < m_inputEffects.size());
85 return m_inputEffects.at(number).get();
86 }
87
clearResult()88 void FilterEffect::clearResult()
89 {
90 if (m_imageBufferResult)
91 m_imageBufferResult.clear();
92 if (m_unmultipliedImageResult)
93 m_unmultipliedImageResult.clear();
94 if (m_premultipliedImageResult)
95 m_premultipliedImageResult.clear();
96 }
97
asImageBuffer()98 ImageBuffer* FilterEffect::asImageBuffer()
99 {
100 if (!hasResult())
101 return 0;
102 if (m_imageBufferResult)
103 return m_imageBufferResult.get();
104 m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
105 IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
106 if (m_premultipliedImageResult)
107 m_imageBufferResult->putPremultipliedImageData(m_premultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
108 else
109 m_imageBufferResult->putUnmultipliedImageData(m_unmultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
110 return m_imageBufferResult.get();
111 }
112
asUnmultipliedImage(const IntRect & rect)113 PassRefPtr<ByteArray> FilterEffect::asUnmultipliedImage(const IntRect& rect)
114 {
115 ASSERT(isFilterSizeValid(rect));
116 RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
117 copyUnmultipliedImage(imageData.get(), rect);
118 return imageData.release();
119 }
120
asPremultipliedImage(const IntRect & rect)121 PassRefPtr<ByteArray> FilterEffect::asPremultipliedImage(const IntRect& rect)
122 {
123 ASSERT(isFilterSizeValid(rect));
124 RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
125 copyPremultipliedImage(imageData.get(), rect);
126 return imageData.release();
127 }
128
copyImageBytes(ByteArray * source,ByteArray * destination,const IntRect & rect)129 inline void FilterEffect::copyImageBytes(ByteArray* source, ByteArray* destination, const IntRect& rect)
130 {
131 // Initialize the destination to transparent black, if not entirely covered by the source.
132 if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > m_absolutePaintRect.width() || rect.maxY() > m_absolutePaintRect.height())
133 memset(destination->data(), 0, destination->length());
134
135 // Early return if the rect does not intersect with the source.
136 if (rect.maxX() <= 0 || rect.maxY() <= 0 || rect.x() >= m_absolutePaintRect.width() || rect.y() >= m_absolutePaintRect.height())
137 return;
138
139 int xOrigin = rect.x();
140 int xDest = 0;
141 if (xOrigin < 0) {
142 xDest = -xOrigin;
143 xOrigin = 0;
144 }
145 int xEnd = rect.maxX();
146 if (xEnd > m_absolutePaintRect.width())
147 xEnd = m_absolutePaintRect.width();
148
149 int yOrigin = rect.y();
150 int yDest = 0;
151 if (yOrigin < 0) {
152 yDest = -yOrigin;
153 yOrigin = 0;
154 }
155 int yEnd = rect.maxY();
156 if (yEnd > m_absolutePaintRect.height())
157 yEnd = m_absolutePaintRect.height();
158
159 int size = (xEnd - xOrigin) * 4;
160 int destinationScanline = rect.width() * 4;
161 int sourceScanline = m_absolutePaintRect.width() * 4;
162 unsigned char *destinationPixel = destination->data() + ((yDest * rect.width()) + xDest) * 4;
163 unsigned char *sourcePixel = source->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4;
164
165 while (yOrigin < yEnd) {
166 memcpy(destinationPixel, sourcePixel, size);
167 destinationPixel += destinationScanline;
168 sourcePixel += sourceScanline;
169 ++yOrigin;
170 }
171 }
172
copyUnmultipliedImage(ByteArray * destination,const IntRect & rect)173 void FilterEffect::copyUnmultipliedImage(ByteArray* destination, const IntRect& rect)
174 {
175 ASSERT(hasResult());
176
177 if (!m_unmultipliedImageResult) {
178 // We prefer a conversion from the image buffer.
179 if (m_imageBufferResult)
180 m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
181 else {
182 ASSERT(isFilterSizeValid(m_absolutePaintRect));
183 m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
184 unsigned char* sourceComponent = m_premultipliedImageResult->data();
185 unsigned char* destinationComponent = m_unmultipliedImageResult->data();
186 unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
187 while (sourceComponent < end) {
188 int alpha = sourceComponent[3];
189 if (alpha) {
190 destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha;
191 destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha;
192 destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha;
193 } else {
194 destinationComponent[0] = 0;
195 destinationComponent[1] = 0;
196 destinationComponent[2] = 0;
197 }
198 destinationComponent[3] = alpha;
199 sourceComponent += 4;
200 destinationComponent += 4;
201 }
202 }
203 }
204 copyImageBytes(m_unmultipliedImageResult.get(), destination, rect);
205 }
206
copyPremultipliedImage(ByteArray * destination,const IntRect & rect)207 void FilterEffect::copyPremultipliedImage(ByteArray* destination, const IntRect& rect)
208 {
209 ASSERT(hasResult());
210
211 if (!m_premultipliedImageResult) {
212 // We prefer a conversion from the image buffer.
213 if (m_imageBufferResult)
214 m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
215 else {
216 ASSERT(isFilterSizeValid(m_absolutePaintRect));
217 m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
218 unsigned char* sourceComponent = m_unmultipliedImageResult->data();
219 unsigned char* destinationComponent = m_premultipliedImageResult->data();
220 unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
221 while (sourceComponent < end) {
222 int alpha = sourceComponent[3];
223 destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
224 destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255;
225 destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255;
226 destinationComponent[3] = alpha;
227 sourceComponent += 4;
228 destinationComponent += 4;
229 }
230 }
231 }
232 copyImageBytes(m_premultipliedImageResult.get(), destination, rect);
233 }
234
createImageBufferResult()235 ImageBuffer* FilterEffect::createImageBufferResult()
236 {
237 // Only one result type is allowed.
238 ASSERT(!hasResult());
239 determineAbsolutePaintRect();
240 if (m_absolutePaintRect.isEmpty())
241 return 0;
242 m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
243 if (!m_imageBufferResult)
244 return 0;
245 ASSERT(m_imageBufferResult->context());
246 return m_imageBufferResult.get();
247 }
248
createUnmultipliedImageResult()249 ByteArray* FilterEffect::createUnmultipliedImageResult()
250 {
251 // Only one result type is allowed.
252 ASSERT(!hasResult());
253 ASSERT(isFilterSizeValid(m_absolutePaintRect));
254
255 determineAbsolutePaintRect();
256 if (m_absolutePaintRect.isEmpty())
257 return 0;
258 m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
259 return m_unmultipliedImageResult.get();
260 }
261
createPremultipliedImageResult()262 ByteArray* FilterEffect::createPremultipliedImageResult()
263 {
264 // Only one result type is allowed.
265 ASSERT(!hasResult());
266 ASSERT(isFilterSizeValid(m_absolutePaintRect));
267
268 determineAbsolutePaintRect();
269 if (m_absolutePaintRect.isEmpty())
270 return 0;
271 m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
272 return m_premultipliedImageResult.get();
273 }
274
externalRepresentation(TextStream & ts,int) const275 TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
276 {
277 // FIXME: We should dump the subRegions of the filter primitives here later. This isn't
278 // possible at the moment, because we need more detailed informations from the target object.
279 return ts;
280 }
281
282 } // namespace WebCore
283
284 #endif // ENABLE(FILTERS)
285