1/* 2 * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> 3 * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> 4 * Copyright (C) 2005 Eric Seidel <eric@webkit.org> 5 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 */ 23 24#include "config.h" 25 26#if ENABLE(FILTERS) 27#include "FEComposite.h" 28 29#include "Filter.h" 30#include "GraphicsContext.h" 31#include "RenderTreeAsText.h" 32#include "TextStream.h" 33 34#include <wtf/ByteArray.h> 35 36namespace WebCore { 37 38FEComposite::FEComposite(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4) 39 : FilterEffect(filter) 40 , m_type(type) 41 , m_k1(k1) 42 , m_k2(k2) 43 , m_k3(k3) 44 , m_k4(k4) 45{ 46} 47 48PassRefPtr<FEComposite> FEComposite::create(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4) 49{ 50 return adoptRef(new FEComposite(filter, type, k1, k2, k3, k4)); 51} 52 53CompositeOperationType FEComposite::operation() const 54{ 55 return m_type; 56} 57 58bool FEComposite::setOperation(CompositeOperationType type) 59{ 60 if (m_type == type) 61 return false; 62 m_type = type; 63 return true; 64} 65 66float FEComposite::k1() const 67{ 68 return m_k1; 69} 70 71bool FEComposite::setK1(float k1) 72{ 73 if (m_k1 == k1) 74 return false; 75 m_k1 = k1; 76 return true; 77} 78 79float FEComposite::k2() const 80{ 81 return m_k2; 82} 83 84bool FEComposite::setK2(float k2) 85{ 86 if (m_k2 == k2) 87 return false; 88 m_k2 = k2; 89 return true; 90} 91 92float FEComposite::k3() const 93{ 94 return m_k3; 95} 96 97bool FEComposite::setK3(float k3) 98{ 99 if (m_k3 == k3) 100 return false; 101 m_k3 = k3; 102 return true; 103} 104 105float FEComposite::k4() const 106{ 107 return m_k4; 108} 109 110bool FEComposite::setK4(float k4) 111{ 112 if (m_k4 == k4) 113 return false; 114 m_k4 = k4; 115 return true; 116} 117 118template <int b1, int b2, int b3, int b4> 119inline void computeArithmeticPixels(unsigned char* source, unsigned char* destination, int pixelArrayLength, 120 float k1, float k2, float k3, float k4) 121{ 122 float scaledK4; 123 float scaledK1; 124 if (b1) 125 scaledK1 = k1 / 255.f; 126 if (b4) 127 scaledK4 = k4 * 255.f; 128 129 while (--pixelArrayLength >= 0) { 130 unsigned char i1 = *source; 131 unsigned char i2 = *destination; 132 float result = 0; 133 if (b1) 134 result += scaledK1 * i1 * i2; 135 if (b2) 136 result += k2 * i1; 137 if (b3) 138 result += k3 * i2; 139 if (b4) 140 result += scaledK4; 141 142 if (result <= 0) 143 *destination = 0; 144 else if (result >= 255) 145 *destination = 255; 146 else 147 *destination = result; 148 ++source; 149 ++destination; 150 } 151} 152 153inline void arithmetic(ByteArray* srcPixelArrayA, ByteArray* srcPixelArrayB, 154 float k1, float k2, float k3, float k4) 155{ 156 int pixelArrayLength = srcPixelArrayA->length(); 157 ASSERT(pixelArrayLength == static_cast<int>(srcPixelArrayB->length())); 158 unsigned char* source = srcPixelArrayA->data(); 159 unsigned char* destination = srcPixelArrayB->data(); 160 161 if (!k4) { 162 if (!k1) { 163 computeArithmeticPixels<0, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4); 164 return; 165 } 166 167 computeArithmeticPixels<1, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4); 168 return; 169 } 170 171 if (!k1) { 172 computeArithmeticPixels<0, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4); 173 return; 174 } 175 computeArithmeticPixels<1, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4); 176} 177 178void FEComposite::determineAbsolutePaintRect() 179{ 180 switch (m_type) { 181 case FECOMPOSITE_OPERATOR_IN: 182 case FECOMPOSITE_OPERATOR_ATOP: 183 // For In and Atop the first effect just influences the result of 184 // the second effect. So just use the absolute paint rect of the second effect here. 185 setAbsolutePaintRect(inputEffect(1)->absolutePaintRect()); 186 return; 187 case FECOMPOSITE_OPERATOR_ARITHMETIC: 188 // Arithmetic may influnce the compele filter primitive region. So we can't 189 // optimize the paint region here. 190 setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); 191 return; 192 default: 193 // Take the union of both input effects. 194 FilterEffect::determineAbsolutePaintRect(); 195 return; 196 } 197} 198 199void FEComposite::apply() 200{ 201 if (hasResult()) 202 return; 203 FilterEffect* in = inputEffect(0); 204 FilterEffect* in2 = inputEffect(1); 205 in->apply(); 206 in2->apply(); 207 if (!in->hasResult() || !in2->hasResult()) 208 return; 209 210 if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) { 211 ByteArray* dstPixelArray = createPremultipliedImageResult(); 212 if (!dstPixelArray) 213 return; 214 215 IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); 216 RefPtr<ByteArray> srcPixelArray = in->asPremultipliedImage(effectADrawingRect); 217 218 IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); 219 in2->copyPremultipliedImage(dstPixelArray, effectBDrawingRect); 220 221 arithmetic(srcPixelArray.get(), dstPixelArray, m_k1, m_k2, m_k3, m_k4); 222 return; 223 } 224 225 ImageBuffer* resultImage = createImageBufferResult(); 226 if (!resultImage) 227 return; 228 GraphicsContext* filterContext = resultImage->context(); 229 230 FloatRect srcRect = FloatRect(0, 0, -1, -1); 231 switch (m_type) { 232 case FECOMPOSITE_OPERATOR_OVER: 233 filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); 234 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); 235 break; 236 case FECOMPOSITE_OPERATOR_IN: 237 filterContext->save(); 238 filterContext->clipToImageBuffer(in2->asImageBuffer(), drawingRegionOfInputImage(in2->absolutePaintRect())); 239 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); 240 filterContext->restore(); 241 break; 242 case FECOMPOSITE_OPERATOR_OUT: 243 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); 244 filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut); 245 break; 246 case FECOMPOSITE_OPERATOR_ATOP: 247 filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); 248 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop); 249 break; 250 case FECOMPOSITE_OPERATOR_XOR: 251 filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); 252 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR); 253 break; 254 default: 255 break; 256 } 257} 258 259void FEComposite::dump() 260{ 261} 262 263static TextStream& operator<<(TextStream& ts, const CompositeOperationType& type) 264{ 265 switch (type) { 266 case FECOMPOSITE_OPERATOR_UNKNOWN: 267 ts << "UNKNOWN"; 268 break; 269 case FECOMPOSITE_OPERATOR_OVER: 270 ts << "OVER"; 271 break; 272 case FECOMPOSITE_OPERATOR_IN: 273 ts << "IN"; 274 break; 275 case FECOMPOSITE_OPERATOR_OUT: 276 ts << "OUT"; 277 break; 278 case FECOMPOSITE_OPERATOR_ATOP: 279 ts << "ATOP"; 280 break; 281 case FECOMPOSITE_OPERATOR_XOR: 282 ts << "XOR"; 283 break; 284 case FECOMPOSITE_OPERATOR_ARITHMETIC: 285 ts << "ARITHMETIC"; 286 break; 287 } 288 return ts; 289} 290 291TextStream& FEComposite::externalRepresentation(TextStream& ts, int indent) const 292{ 293 writeIndent(ts, indent); 294 ts << "[feComposite"; 295 FilterEffect::externalRepresentation(ts); 296 ts << " operation=\"" << m_type << "\""; 297 if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) 298 ts << " k1=\"" << m_k1 << "\" k2=\"" << m_k2 << "\" k3=\"" << m_k3 << "\" k4=\"" << m_k4 << "\""; 299 ts << "]\n"; 300 inputEffect(0)->externalRepresentation(ts, indent + 1); 301 inputEffect(1)->externalRepresentation(ts, indent + 1); 302 return ts; 303} 304 305} // namespace WebCore 306 307#endif // ENABLE(FILTERS) 308