Home | History | Annotate | Download | only in filters
      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