f07d00cc7ea7ab546c6fddd5904b47ef92f2e57a
[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     // Copy the necessary lines.
122     if (rect.x() < 0 || rect.y() < 0 || rect.maxY() > m_absolutePaintRect.width() || rect.maxY() > m_absolutePaintRect.height())
123         memset(destination->data(), 0, destination->length());
124
125     int xOrigin = rect.x();
126     int xDest = 0;
127     if (xOrigin < 0) {
128         xDest = -xOrigin;
129         xOrigin = 0;
130     }
131     int xEnd = rect.maxX();
132     if (xEnd > m_absolutePaintRect.width())
133         xEnd = m_absolutePaintRect.width();
134
135     int yOrigin = rect.y();
136     int yDest = 0;
137     if (yOrigin < 0) {
138         yDest = -yOrigin;
139         yOrigin = 0;
140     }
141     int yEnd = rect.maxY();
142     if (yEnd > m_absolutePaintRect.height())
143         yEnd = m_absolutePaintRect.height();
144
145     int size = (xEnd - xOrigin) * 4;
146     int destinationScanline = rect.width() * 4;
147     int sourceScanline = m_absolutePaintRect.width() * 4;
148     unsigned char *destinationPixel = destination->data() + ((yDest * rect.width()) + xDest) * 4;
149     unsigned char *sourcePixel = source->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4;
150
151     while (yOrigin < yEnd) {
152         memcpy(destinationPixel, sourcePixel, size);
153         destinationPixel += destinationScanline;
154         sourcePixel += sourceScanline;
155         ++yOrigin;
156     }
157 }
158
159 void FilterEffect::copyUnmultipliedImage(ByteArray* destination, const IntRect& rect)
160 {
161     ASSERT(hasResult());
162
163     if (!m_unmultipliedImageResult) {
164         // We prefer a conversion from the image buffer.
165         if (m_imageBufferResult)
166             m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
167         else {
168             m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
169             unsigned char* sourceComponent = m_premultipliedImageResult->data();
170             unsigned char* destinationComponent = m_unmultipliedImageResult->data();
171             unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
172             while (sourceComponent < end) {
173                 int alpha = sourceComponent[3];
174                 if (alpha) {
175                     destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha;
176                     destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha;
177                     destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha;
178                 } else {
179                     destinationComponent[0] = 0;
180                     destinationComponent[1] = 0;
181                     destinationComponent[2] = 0;
182                 }
183                 destinationComponent[3] = alpha;
184                 sourceComponent += 4;
185                 destinationComponent += 4;
186             }
187         }
188     }
189     copyImageBytes(m_unmultipliedImageResult.get(), destination, rect);
190 }
191
192 void FilterEffect::copyPremultipliedImage(ByteArray* destination, const IntRect& rect)
193 {
194     ASSERT(hasResult());
195
196     if (!m_premultipliedImageResult) {
197         // We prefer a conversion from the image buffer.
198         if (m_imageBufferResult)
199             m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
200         else {
201             m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
202             unsigned char* sourceComponent = m_unmultipliedImageResult->data();
203             unsigned char* destinationComponent = m_premultipliedImageResult->data();
204             unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
205             while (sourceComponent < end) {
206                 int alpha = sourceComponent[3];
207                 destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
208                 destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255;
209                 destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255;
210                 destinationComponent[3] = alpha;
211                 sourceComponent += 4;
212                 destinationComponent += 4;
213             }
214         }
215     }
216     copyImageBytes(m_premultipliedImageResult.get(), destination, rect);
217 }
218
219 ImageBuffer* FilterEffect::createImageBufferResult()
220 {
221     // Only one result type is allowed.
222     ASSERT(!hasResult());
223     determineAbsolutePaintRect();
224     if (m_absolutePaintRect.isEmpty())
225         return 0;
226     m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
227     if (!m_imageBufferResult)
228         return 0;
229     ASSERT(m_imageBufferResult->context());
230     return m_imageBufferResult.get();
231 }
232
233 ByteArray* FilterEffect::createUnmultipliedImageResult()
234 {
235     // Only one result type is allowed.
236     ASSERT(!hasResult());
237     determineAbsolutePaintRect();
238     if (m_absolutePaintRect.isEmpty())
239         return 0;
240     m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
241     return m_unmultipliedImageResult.get();
242 }
243
244 ByteArray* FilterEffect::createPremultipliedImageResult()
245 {
246     // Only one result type is allowed.
247     ASSERT(!hasResult());
248     determineAbsolutePaintRect();
249     if (m_absolutePaintRect.isEmpty())
250         return 0;
251     m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
252     return m_premultipliedImageResult.get();
253 }
254
255 TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
256 {
257     // FIXME: We should dump the subRegions of the filter primitives here later. This isn't
258     // possible at the moment, because we need more detailed informations from the target object.
259     return ts;
260 }
261
262 } // namespace WebCore
263
264 #endif // ENABLE(FILTERS)