1 /* 2 * Copyright (C) 2008 Alex Mathews <possessedpenguinbob (at) gmail.com> 3 * Copyright (C) 2009 Dirk Schulze <krit (at) 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 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 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 68 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 76 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 82 FilterEffect* FilterEffect::inputEffect(unsigned number) const 83 { 84 ASSERT(number < m_inputEffects.size()); 85 return m_inputEffects.at(number).get(); 86 } 87 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 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 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 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 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 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 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 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 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 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 275 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