1 /* 2 * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005 Rob Buis <buis (at) kde.org> 4 * Copyright (C) 2005 Eric Seidel <eric (at) webkit.org> 5 * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 */ 22 23 #include "config.h" 24 25 #if ENABLE(FILTERS) 26 #include "FEColorMatrix.h" 27 28 #include "Filter.h" 29 #include "GraphicsContext.h" 30 #include "RenderTreeAsText.h" 31 #include "TextStream.h" 32 33 #include <wtf/ByteArray.h> 34 #include <wtf/MathExtras.h> 35 36 namespace WebCore { 37 38 FEColorMatrix::FEColorMatrix(Filter* filter, ColorMatrixType type, const Vector<float>& values) 39 : FilterEffect(filter) 40 , m_type(type) 41 , m_values(values) 42 { 43 } 44 45 PassRefPtr<FEColorMatrix> FEColorMatrix::create(Filter* filter, ColorMatrixType type, const Vector<float>& values) 46 { 47 return adoptRef(new FEColorMatrix(filter, type, values)); 48 } 49 50 ColorMatrixType FEColorMatrix::type() const 51 { 52 return m_type; 53 } 54 55 bool FEColorMatrix::setType(ColorMatrixType type) 56 { 57 if (m_type == type) 58 return false; 59 m_type = type; 60 return true; 61 } 62 63 const Vector<float>& FEColorMatrix::values() const 64 { 65 return m_values; 66 } 67 68 bool FEColorMatrix::setValues(const Vector<float> &values) 69 { 70 if (m_values == values) 71 return false; 72 m_values = values; 73 return true; 74 } 75 76 inline void matrix(double& red, double& green, double& blue, double& alpha, const Vector<float>& values) 77 { 78 double r = values[0] * red + values[1] * green + values[2] * blue + values[3] * alpha + values[4] * 255; 79 double g = values[5] * red + values[6] * green + values[7] * blue + values[8] * alpha + values[9] * 255; 80 double b = values[10] * red + values[11] * green + values[12] * blue + values[13] * alpha + values[14] * 255; 81 double a = values[15] * red + values[16] * green + values[17] * blue + values[18] * alpha + values[19] * 255; 82 83 red = r; 84 green = g; 85 blue = b; 86 alpha = a; 87 } 88 89 inline void saturate(double& red, double& green, double& blue, const float& s) 90 { 91 double r = (0.213 + 0.787 * s) * red + (0.715 - 0.715 * s) * green + (0.072 - 0.072 * s) * blue; 92 double g = (0.213 - 0.213 * s) * red + (0.715 + 0.285 * s) * green + (0.072 - 0.072 * s) * blue; 93 double b = (0.213 - 0.213 * s) * red + (0.715 - 0.715 * s) * green + (0.072 + 0.928 * s) * blue; 94 95 red = r; 96 green = g; 97 blue = b; 98 } 99 100 inline void huerotate(double& red, double& green, double& blue, const float& hue) 101 { 102 double cosHue = cos(hue * piDouble / 180); 103 double sinHue = sin(hue * piDouble / 180); 104 double r = red * (0.213 + cosHue * 0.787 - sinHue * 0.213) + 105 green * (0.715 - cosHue * 0.715 - sinHue * 0.715) + 106 blue * (0.072 - cosHue * 0.072 + sinHue * 0.928); 107 double g = red * (0.213 - cosHue * 0.213 + sinHue * 0.143) + 108 green * (0.715 + cosHue * 0.285 + sinHue * 0.140) + 109 blue * (0.072 - cosHue * 0.072 - sinHue * 0.283); 110 double b = red * (0.213 - cosHue * 0.213 - sinHue * 0.787) + 111 green * (0.715 - cosHue * 0.715 + sinHue * 0.715) + 112 blue * (0.072 + cosHue * 0.928 + sinHue * 0.072); 113 114 red = r; 115 green = g; 116 blue = b; 117 } 118 119 inline void luminance(double& red, double& green, double& blue, double& alpha) 120 { 121 alpha = 0.2125 * red + 0.7154 * green + 0.0721 * blue; 122 red = 0; 123 green = 0; 124 blue = 0; 125 } 126 127 template<ColorMatrixType filterType> 128 void effectType(ByteArray* pixelArray, const Vector<float>& values) 129 { 130 unsigned pixelArrayLength = pixelArray->length(); 131 for (unsigned pixelByteOffset = 0; pixelByteOffset < pixelArrayLength; pixelByteOffset += 4) { 132 double red = pixelArray->get(pixelByteOffset); 133 double green = pixelArray->get(pixelByteOffset + 1); 134 double blue = pixelArray->get(pixelByteOffset + 2); 135 double alpha = pixelArray->get(pixelByteOffset + 3); 136 137 switch (filterType) { 138 case FECOLORMATRIX_TYPE_MATRIX: 139 matrix(red, green, blue, alpha, values); 140 break; 141 case FECOLORMATRIX_TYPE_SATURATE: 142 saturate(red, green, blue, values[0]); 143 break; 144 case FECOLORMATRIX_TYPE_HUEROTATE: 145 huerotate(red, green, blue, values[0]); 146 break; 147 case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: 148 luminance(red, green, blue, alpha); 149 break; 150 } 151 152 pixelArray->set(pixelByteOffset, red); 153 pixelArray->set(pixelByteOffset + 1, green); 154 pixelArray->set(pixelByteOffset + 2, blue); 155 pixelArray->set(pixelByteOffset + 3, alpha); 156 } 157 } 158 159 void FEColorMatrix::apply() 160 { 161 if (hasResult()) 162 return; 163 FilterEffect* in = inputEffect(0); 164 in->apply(); 165 if (!in->hasResult()) 166 return; 167 168 ImageBuffer* resultImage = createImageBufferResult(); 169 if (!resultImage) 170 return; 171 172 resultImage->context()->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); 173 174 IntRect imageRect(IntPoint(), absolutePaintRect().size()); 175 RefPtr<ByteArray> pixelArray = resultImage->getUnmultipliedImageData(imageRect); 176 177 switch (m_type) { 178 case FECOLORMATRIX_TYPE_UNKNOWN: 179 break; 180 case FECOLORMATRIX_TYPE_MATRIX: 181 effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), m_values); 182 break; 183 case FECOLORMATRIX_TYPE_SATURATE: 184 effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), m_values); 185 break; 186 case FECOLORMATRIX_TYPE_HUEROTATE: 187 effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), m_values); 188 break; 189 case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: 190 effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), m_values); 191 setIsAlphaImage(true); 192 break; 193 } 194 195 resultImage->putUnmultipliedImageData(pixelArray.get(), imageRect.size(), imageRect, IntPoint()); 196 } 197 198 void FEColorMatrix::dump() 199 { 200 } 201 202 static TextStream& operator<<(TextStream& ts, const ColorMatrixType& type) 203 { 204 switch (type) { 205 case FECOLORMATRIX_TYPE_UNKNOWN: 206 ts << "UNKNOWN"; 207 break; 208 case FECOLORMATRIX_TYPE_MATRIX: 209 ts << "MATRIX"; 210 break; 211 case FECOLORMATRIX_TYPE_SATURATE: 212 ts << "SATURATE"; 213 break; 214 case FECOLORMATRIX_TYPE_HUEROTATE: 215 ts << "HUEROTATE"; 216 break; 217 case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: 218 ts << "LUMINANCETOALPHA"; 219 break; 220 } 221 return ts; 222 } 223 224 TextStream& FEColorMatrix::externalRepresentation(TextStream& ts, int indent) const 225 { 226 writeIndent(ts, indent); 227 ts << "[feColorMatrix"; 228 FilterEffect::externalRepresentation(ts); 229 ts << " type=\"" << m_type << "\""; 230 if (!m_values.isEmpty()) { 231 ts << " values=\""; 232 Vector<float>::const_iterator ptr = m_values.begin(); 233 const Vector<float>::const_iterator end = m_values.end(); 234 while (ptr < end) { 235 ts << *ptr; 236 ++ptr; 237 if (ptr < end) 238 ts << " "; 239 } 240 ts << "\""; 241 } 242 ts << "]\n"; 243 inputEffect(0)->externalRepresentation(ts, indent + 1); 244 return ts; 245 } 246 247 } // namespace WebCore 248 249 #endif // ENABLE(FILTERS) 250