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