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 27 #include "core/platform/graphics/filters/FEDisplacementMap.h" 28 29 #include "core/platform/graphics/GraphicsContext.h" 30 #include "core/platform/graphics/filters/Filter.h" 31 #include "core/platform/text/TextStream.h" 32 #include "core/rendering/RenderTreeAsText.h" 33 34 #include "wtf/Uint8ClampedArray.h" 35 36 #include "SkBitmapSource.h" 37 #include "SkDisplacementMapEffect.h" 38 #include "core/platform/graphics/filters/SkiaImageFilterBuilder.h" 39 #include "core/platform/graphics/skia/NativeImageSkia.h" 40 41 namespace WebCore { 42 43 FEDisplacementMap::FEDisplacementMap(Filter* filter, ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float scale) 44 : FilterEffect(filter) 45 , m_xChannelSelector(xChannelSelector) 46 , m_yChannelSelector(yChannelSelector) 47 , m_scale(scale) 48 { 49 } 50 51 PassRefPtr<FEDisplacementMap> FEDisplacementMap::create(Filter* filter, ChannelSelectorType xChannelSelector, 52 ChannelSelectorType yChannelSelector, float scale) 53 { 54 return adoptRef(new FEDisplacementMap(filter, xChannelSelector, yChannelSelector, scale)); 55 } 56 57 ChannelSelectorType FEDisplacementMap::xChannelSelector() const 58 { 59 return m_xChannelSelector; 60 } 61 62 bool FEDisplacementMap::setXChannelSelector(const ChannelSelectorType xChannelSelector) 63 { 64 if (m_xChannelSelector == xChannelSelector) 65 return false; 66 m_xChannelSelector = xChannelSelector; 67 return true; 68 } 69 70 ChannelSelectorType FEDisplacementMap::yChannelSelector() const 71 { 72 return m_yChannelSelector; 73 } 74 75 bool FEDisplacementMap::setYChannelSelector(const ChannelSelectorType yChannelSelector) 76 { 77 if (m_yChannelSelector == yChannelSelector) 78 return false; 79 m_yChannelSelector = yChannelSelector; 80 return true; 81 } 82 83 float FEDisplacementMap::scale() const 84 { 85 return m_scale; 86 } 87 88 bool FEDisplacementMap::setScale(float scale) 89 { 90 if (m_scale == scale) 91 return false; 92 m_scale = scale; 93 return true; 94 } 95 96 void FEDisplacementMap::setResultColorSpace(ColorSpace) 97 { 98 // Spec: The 'color-interpolation-filters' property only applies to the 'in2' source image 99 // and does not apply to the 'in' source image. The 'in' source image must remain in its 100 // current color space. 101 // The result is in that smae color space because it is a displacement of the 'in' image. 102 FilterEffect::setResultColorSpace(inputEffect(0)->resultColorSpace()); 103 } 104 105 void FEDisplacementMap::transformResultColorSpace(FilterEffect* in, const int index) 106 { 107 // Do not transform the first primitive input, as per the spec. 108 if (index) 109 in->transformResultColorSpace(operatingColorSpace()); 110 } 111 112 void FEDisplacementMap::applySoftware() 113 { 114 FilterEffect* in = inputEffect(0); 115 FilterEffect* in2 = inputEffect(1); 116 117 ASSERT(m_xChannelSelector != CHANNEL_UNKNOWN); 118 ASSERT(m_yChannelSelector != CHANNEL_UNKNOWN); 119 120 Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); 121 if (!dstPixelArray) 122 return; 123 124 IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); 125 RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect); 126 127 IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); 128 RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asUnmultipliedImage(effectBDrawingRect); 129 130 ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); 131 132 Filter* filter = this->filter(); 133 IntSize paintSize = absolutePaintRect().size(); 134 float scaleX = filter->applyHorizontalScale(m_scale); 135 float scaleY = filter->applyVerticalScale(m_scale); 136 float scaleForColorX = scaleX / 255.0; 137 float scaleForColorY = scaleY / 255.0; 138 float scaledOffsetX = 0.5 - scaleX * 0.5; 139 float scaledOffsetY = 0.5 - scaleY * 0.5; 140 int stride = paintSize.width() * 4; 141 for (int y = 0; y < paintSize.height(); ++y) { 142 int line = y * stride; 143 for (int x = 0; x < paintSize.width(); ++x) { 144 int dstIndex = line + x * 4; 145 int srcX = x + static_cast<int>(scaleForColorX * srcPixelArrayB->item(dstIndex + m_xChannelSelector - 1) + scaledOffsetX); 146 int srcY = y + static_cast<int>(scaleForColorY * srcPixelArrayB->item(dstIndex + m_yChannelSelector - 1) + scaledOffsetY); 147 for (unsigned channel = 0; channel < 4; ++channel) { 148 if (srcX < 0 || srcX >= paintSize.width() || srcY < 0 || srcY >= paintSize.height()) 149 dstPixelArray->set(dstIndex + channel, static_cast<unsigned char>(0)); 150 else { 151 unsigned char pixelValue = srcPixelArrayA->item(srcY * stride + srcX * 4 + channel); 152 dstPixelArray->set(dstIndex + channel, pixelValue); 153 } 154 } 155 } 156 } 157 } 158 159 static SkDisplacementMapEffect::ChannelSelectorType toSkiaMode(ChannelSelectorType type) 160 { 161 switch (type) { 162 case CHANNEL_R: 163 return SkDisplacementMapEffect::kR_ChannelSelectorType; 164 case CHANNEL_G: 165 return SkDisplacementMapEffect::kG_ChannelSelectorType; 166 case CHANNEL_B: 167 return SkDisplacementMapEffect::kB_ChannelSelectorType; 168 case CHANNEL_A: 169 return SkDisplacementMapEffect::kA_ChannelSelectorType; 170 case CHANNEL_UNKNOWN: 171 default: 172 return SkDisplacementMapEffect::kUnknown_ChannelSelectorType; 173 } 174 } 175 176 bool FEDisplacementMap::applySkia() 177 { 178 // For now, only use the skia implementation for accelerated rendering. 179 if (filter()->renderingMode() != Accelerated) 180 return false; 181 182 FilterEffect* in = inputEffect(0); 183 FilterEffect* in2 = inputEffect(1); 184 185 if (!in || !in2) 186 return false; 187 188 ImageBuffer* resultImage = createImageBufferResult(); 189 if (!resultImage) 190 return false; 191 192 RefPtr<Image> color = in->asImageBuffer()->copyImage(DontCopyBackingStore); 193 RefPtr<Image> displ = in2->asImageBuffer()->copyImage(DontCopyBackingStore); 194 195 RefPtr<NativeImageSkia> colorNativeImage = color->nativeImageForCurrentFrame(); 196 RefPtr<NativeImageSkia> displNativeImage = displ->nativeImageForCurrentFrame(); 197 198 if (!colorNativeImage || !displNativeImage) 199 return false; 200 201 SkBitmap colorBitmap = colorNativeImage->bitmap(); 202 SkBitmap displBitmap = displNativeImage->bitmap(); 203 204 SkAutoTUnref<SkImageFilter> colorSource(new SkBitmapSource(colorBitmap)); 205 SkAutoTUnref<SkImageFilter> displSource(new SkBitmapSource(displBitmap)); 206 SkDisplacementMapEffect::ChannelSelectorType typeX = toSkiaMode(m_xChannelSelector); 207 SkDisplacementMapEffect::ChannelSelectorType typeY = toSkiaMode(m_yChannelSelector); 208 // FIXME : Only applyHorizontalScale is used and applyVerticalScale is ignored 209 // This can be fixed by adding a 2nd scale parameter to SkDisplacementMapEffect 210 SkAutoTUnref<SkImageFilter> displEffect(new SkDisplacementMapEffect( 211 typeX, typeY, SkFloatToScalar(filter()->applyHorizontalScale(m_scale)), displSource, colorSource)); 212 SkPaint paint; 213 paint.setImageFilter(displEffect); 214 resultImage->context()->drawBitmap(colorBitmap, 0, 0, &paint); 215 return true; 216 } 217 218 PassRefPtr<SkImageFilter> FEDisplacementMap::createImageFilter(SkiaImageFilterBuilder* builder) 219 { 220 RefPtr<SkImageFilter> color = builder->build(inputEffect(0), operatingColorSpace()); 221 RefPtr<SkImageFilter> displ = builder->build(inputEffect(1), operatingColorSpace()); 222 SkDisplacementMapEffect::ChannelSelectorType typeX = toSkiaMode(m_xChannelSelector); 223 SkDisplacementMapEffect::ChannelSelectorType typeY = toSkiaMode(m_yChannelSelector); 224 // FIXME : Only applyHorizontalScale is used and applyVerticalScale is ignored 225 // This can be fixed by adding a 2nd scale parameter to SkDisplacementMapEffect 226 return adoptRef(new SkDisplacementMapEffect(typeX, typeY, SkFloatToScalar(filter()->applyHorizontalScale(m_scale)), displ.get(), color.get())); 227 } 228 229 static TextStream& operator<<(TextStream& ts, const ChannelSelectorType& type) 230 { 231 switch (type) { 232 case CHANNEL_UNKNOWN: 233 ts << "UNKNOWN"; 234 break; 235 case CHANNEL_R: 236 ts << "RED"; 237 break; 238 case CHANNEL_G: 239 ts << "GREEN"; 240 break; 241 case CHANNEL_B: 242 ts << "BLUE"; 243 break; 244 case CHANNEL_A: 245 ts << "ALPHA"; 246 break; 247 } 248 return ts; 249 } 250 251 TextStream& FEDisplacementMap::externalRepresentation(TextStream& ts, int indent) const 252 { 253 writeIndent(ts, indent); 254 ts << "[feDisplacementMap"; 255 FilterEffect::externalRepresentation(ts); 256 ts << " scale=\"" << m_scale << "\" " 257 << "xChannelSelector=\"" << m_xChannelSelector << "\" " 258 << "yChannelSelector=\"" << m_yChannelSelector << "\"]\n"; 259 inputEffect(0)->externalRepresentation(ts, indent + 1); 260 inputEffect(1)->externalRepresentation(ts, indent + 1); 261 return ts; 262 } 263 264 } // namespace WebCore 265