• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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