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 32namespace WebCore { 33 34FilterEffect::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 45FilterEffect::~FilterEffect() 46{ 47} 48 49inline 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 57void 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 68IntRect 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 76IntRect 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 82FilterEffect* FilterEffect::inputEffect(unsigned number) const 83{ 84 ASSERT(number < m_inputEffects.size()); 85 return m_inputEffects.at(number).get(); 86} 87 88void 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 98ImageBuffer* 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 113PassRefPtr<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 121PassRefPtr<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 129inline 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 173void 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 207void 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 235ImageBuffer* 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 249ByteArray* 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 262ByteArray* 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 275TextStream& 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