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 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 7 * Copyright (C) 2013 Google Inc. All rights reserved. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Library General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Library General Public License for more details. 18 * 19 * You should have received a copy of the GNU Library General Public License 20 * along with this library; see the file COPYING.LIB. If not, write to 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Boston, MA 02110-1301, USA. 23 */ 24 25 #include "config.h" 26 #include "platform/graphics/filters/FEDisplacementMap.h" 27 28 #include "SkBitmapSource.h" 29 #include "SkDisplacementMapEffect.h" 30 #include "platform/graphics/GraphicsContext.h" 31 #include "platform/graphics/filters/SkiaImageFilterBuilder.h" 32 #include "platform/graphics/skia/NativeImageSkia.h" 33 #include "platform/text/TextStream.h" 34 #include "wtf/Uint8ClampedArray.h" 35 36 namespace WebCore { 37 38 FEDisplacementMap::FEDisplacementMap(Filter* filter, ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float scale) 39 : FilterEffect(filter) 40 , m_xChannelSelector(xChannelSelector) 41 , m_yChannelSelector(yChannelSelector) 42 , m_scale(scale) 43 { 44 } 45 46 PassRefPtr<FEDisplacementMap> FEDisplacementMap::create(Filter* filter, ChannelSelectorType xChannelSelector, 47 ChannelSelectorType yChannelSelector, float scale) 48 { 49 return adoptRef(new FEDisplacementMap(filter, xChannelSelector, yChannelSelector, scale)); 50 } 51 52 FloatRect FEDisplacementMap::mapPaintRect(const FloatRect& rect, bool) 53 { 54 FloatRect result = rect; 55 result.inflateX(filter()->applyHorizontalScale(m_scale / 2)); 56 result.inflateY(filter()->applyVerticalScale(m_scale / 2)); 57 return result; 58 } 59 60 ChannelSelectorType FEDisplacementMap::xChannelSelector() const 61 { 62 return m_xChannelSelector; 63 } 64 65 bool FEDisplacementMap::setXChannelSelector(const ChannelSelectorType xChannelSelector) 66 { 67 if (m_xChannelSelector == xChannelSelector) 68 return false; 69 m_xChannelSelector = xChannelSelector; 70 return true; 71 } 72 73 ChannelSelectorType FEDisplacementMap::yChannelSelector() const 74 { 75 return m_yChannelSelector; 76 } 77 78 bool FEDisplacementMap::setYChannelSelector(const ChannelSelectorType yChannelSelector) 79 { 80 if (m_yChannelSelector == yChannelSelector) 81 return false; 82 m_yChannelSelector = yChannelSelector; 83 return true; 84 } 85 86 float FEDisplacementMap::scale() const 87 { 88 return m_scale; 89 } 90 91 bool FEDisplacementMap::setScale(float scale) 92 { 93 if (m_scale == scale) 94 return false; 95 m_scale = scale; 96 return true; 97 } 98 99 void FEDisplacementMap::setResultColorSpace(ColorSpace) 100 { 101 // Spec: The 'color-interpolation-filters' property only applies to the 'in2' source image 102 // and does not apply to the 'in' source image. The 'in' source image must remain in its 103 // current color space. 104 // The result is in that smae color space because it is a displacement of the 'in' image. 105 FilterEffect::setResultColorSpace(inputEffect(0)->resultColorSpace()); 106 } 107 108 void FEDisplacementMap::transformResultColorSpace(FilterEffect* in, const int index) 109 { 110 // Do not transform the first primitive input, as per the spec. 111 if (index) 112 in->transformResultColorSpace(operatingColorSpace()); 113 } 114 115 void FEDisplacementMap::applySoftware() 116 { 117 FilterEffect* in = inputEffect(0); 118 FilterEffect* in2 = inputEffect(1); 119 120 ASSERT(m_xChannelSelector != CHANNEL_UNKNOWN); 121 ASSERT(m_yChannelSelector != CHANNEL_UNKNOWN); 122 123 Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); 124 if (!dstPixelArray) 125 return; 126 127 IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); 128 RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect); 129 130 IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); 131 RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asUnmultipliedImage(effectBDrawingRect); 132 133 ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); 134 135 Filter* filter = this->filter(); 136 IntSize paintSize = absolutePaintRect().size(); 137 float scaleX = filter->applyHorizontalScale(m_scale); 138 float scaleY = filter->applyVerticalScale(m_scale); 139 float scaleForColorX = scaleX / 255.0; 140 float scaleForColorY = scaleY / 255.0; 141 float scaledOffsetX = 0.5 - scaleX * 0.5; 142 float scaledOffsetY = 0.5 - scaleY * 0.5; 143 int stride = paintSize.width() * 4; 144 for (int y = 0; y < paintSize.height(); ++y) { 145 int line = y * stride; 146 for (int x = 0; x < paintSize.width(); ++x) { 147 int dstIndex = line + x * 4; 148 int srcX = x + static_cast<int>(scaleForColorX * srcPixelArrayB->item(dstIndex + m_xChannelSelector - 1) + scaledOffsetX); 149 int srcY = y + static_cast<int>(scaleForColorY * srcPixelArrayB->item(dstIndex + m_yChannelSelector - 1) + scaledOffsetY); 150 for (unsigned channel = 0; channel < 4; ++channel) { 151 if (srcX < 0 || srcX >= paintSize.width() || srcY < 0 || srcY >= paintSize.height()) { 152 dstPixelArray->set(dstIndex + channel, static_cast<unsigned char>(0)); 153 } else { 154 unsigned char pixelValue = srcPixelArrayA->item(srcY * stride + srcX * 4 + channel); 155 dstPixelArray->set(dstIndex + channel, pixelValue); 156 } 157 } 158 } 159 } 160 } 161 162 static SkDisplacementMapEffect::ChannelSelectorType toSkiaMode(ChannelSelectorType type) 163 { 164 switch (type) { 165 case CHANNEL_R: 166 return SkDisplacementMapEffect::kR_ChannelSelectorType; 167 case CHANNEL_G: 168 return SkDisplacementMapEffect::kG_ChannelSelectorType; 169 case CHANNEL_B: 170 return SkDisplacementMapEffect::kB_ChannelSelectorType; 171 case CHANNEL_A: 172 return SkDisplacementMapEffect::kA_ChannelSelectorType; 173 case CHANNEL_UNKNOWN: 174 default: 175 return SkDisplacementMapEffect::kUnknown_ChannelSelectorType; 176 } 177 } 178 179 PassRefPtr<SkImageFilter> FEDisplacementMap::createImageFilter(SkiaImageFilterBuilder* builder) 180 { 181 RefPtr<SkImageFilter> color = builder->build(inputEffect(0), operatingColorSpace()); 182 RefPtr<SkImageFilter> displ = builder->build(inputEffect(1), operatingColorSpace()); 183 SkDisplacementMapEffect::ChannelSelectorType typeX = toSkiaMode(m_xChannelSelector); 184 SkDisplacementMapEffect::ChannelSelectorType typeY = toSkiaMode(m_yChannelSelector); 185 SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); 186 // FIXME : Only applyHorizontalScale is used and applyVerticalScale is ignored 187 // This can be fixed by adding a 2nd scale parameter to SkDisplacementMapEffect 188 return adoptRef(SkDisplacementMapEffect::Create(typeX, typeY, SkFloatToScalar(filter()->applyHorizontalScale(m_scale)), displ.get(), color.get(), &cropRect)); 189 } 190 191 static TextStream& operator<<(TextStream& ts, const ChannelSelectorType& type) 192 { 193 switch (type) { 194 case CHANNEL_UNKNOWN: 195 ts << "UNKNOWN"; 196 break; 197 case CHANNEL_R: 198 ts << "RED"; 199 break; 200 case CHANNEL_G: 201 ts << "GREEN"; 202 break; 203 case CHANNEL_B: 204 ts << "BLUE"; 205 break; 206 case CHANNEL_A: 207 ts << "ALPHA"; 208 break; 209 } 210 return ts; 211 } 212 213 TextStream& FEDisplacementMap::externalRepresentation(TextStream& ts, int indent) const 214 { 215 writeIndent(ts, indent); 216 ts << "[feDisplacementMap"; 217 FilterEffect::externalRepresentation(ts); 218 ts << " scale=\"" << m_scale << "\" " 219 << "xChannelSelector=\"" << m_xChannelSelector << "\" " 220 << "yChannelSelector=\"" << m_yChannelSelector << "\"]\n"; 221 inputEffect(0)->externalRepresentation(ts, indent + 1); 222 inputEffect(1)->externalRepresentation(ts, indent + 1); 223 return ts; 224 } 225 226 } // namespace WebCore 227