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/FEComposite.h"
     28 
     29 #include "SkArithmeticMode.h"
     30 #include "SkFlattenableBuffers.h"
     31 #include "SkXfermodeImageFilter.h"
     32 
     33 #include "core/platform/graphics/GraphicsContext.h"
     34 #include "core/platform/graphics/cpu/arm/filters/FECompositeArithmeticNEON.h"
     35 #include "core/platform/graphics/filters/Filter.h"
     36 #include "core/platform/text/TextStream.h"
     37 #include "core/rendering/RenderTreeAsText.h"
     38 #include "third_party/skia/include/core/SkDevice.h"
     39 
     40 #include "wtf/Uint8ClampedArray.h"
     41 
     42 #include "core/platform/graphics/filters/SkiaImageFilterBuilder.h"
     43 
     44 namespace WebCore {
     45 
     46 class CompositeImageFilter : public SkImageFilter {
     47 public:
     48     CompositeImageFilter(SkXfermode::Mode mode, SkImageFilter* background, SkImageFilter* foreground) : SkImageFilter(background, foreground), m_mode(mode)
     49     {
     50     }
     51 
     52     virtual bool onFilterImage(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* dst, SkIPoint* offset)
     53     {
     54         SkBitmap background = src;
     55         SkBitmap foreground = src;
     56         SkImageFilter* backgroundInput = getInput(0);
     57         SkImageFilter* foregroundInput = getInput(1);
     58         SkIPoint backgroundOffset = SkIPoint::Make(0, 0), foregroundOffset = SkIPoint::Make(0, 0);
     59         if (backgroundInput && !backgroundInput->filterImage(proxy, src, ctm, &background, &backgroundOffset))
     60             return false;
     61 
     62         if (foregroundInput && !foregroundInput->filterImage(proxy, src, ctm, &foreground, &foregroundOffset))
     63             return false;
     64 
     65         SkAutoTUnref<SkDevice> device(proxy->createDevice(background.width(), background.height()));
     66         SkCanvas canvas(device);
     67         SkPaint paint;
     68         paint.setXfermodeMode(SkXfermode::kSrc_Mode);
     69         canvas.drawBitmap(background, backgroundOffset.fX, backgroundOffset.fY, &paint);
     70         paint.setXfermodeMode(m_mode);
     71         canvas.drawBitmap(foreground, foregroundOffset.fX, foregroundOffset.fY, &paint);
     72         *dst = device->accessBitmap(false);
     73         return true;
     74     }
     75 
     76     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(CompositeImageFilter)
     77 
     78 protected:
     79     explicit CompositeImageFilter(SkFlattenableReadBuffer& buffer)
     80         : SkImageFilter(buffer)
     81     {
     82         m_mode = (SkXfermode::Mode) buffer.readInt();
     83     }
     84 
     85     virtual void flatten(SkFlattenableWriteBuffer& buffer) const
     86     {
     87         this->SkImageFilter::flatten(buffer);
     88         buffer.writeInt((int) m_mode);
     89     }
     90 
     91 private:
     92     SkXfermode::Mode m_mode;
     93 };
     94 
     95 FEComposite::FEComposite(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
     96     : FilterEffect(filter)
     97     , m_type(type)
     98     , m_k1(k1)
     99     , m_k2(k2)
    100     , m_k3(k3)
    101     , m_k4(k4)
    102 {
    103 }
    104 
    105 PassRefPtr<FEComposite> FEComposite::create(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
    106 {
    107     return adoptRef(new FEComposite(filter, type, k1, k2, k3, k4));
    108 }
    109 
    110 CompositeOperationType FEComposite::operation() const
    111 {
    112     return m_type;
    113 }
    114 
    115 bool FEComposite::setOperation(CompositeOperationType type)
    116 {
    117     if (m_type == type)
    118         return false;
    119     m_type = type;
    120     return true;
    121 }
    122 
    123 float FEComposite::k1() const
    124 {
    125     return m_k1;
    126 }
    127 
    128 bool FEComposite::setK1(float k1)
    129 {
    130     if (m_k1 == k1)
    131         return false;
    132     m_k1 = k1;
    133     return true;
    134 }
    135 
    136 float FEComposite::k2() const
    137 {
    138     return m_k2;
    139 }
    140 
    141 bool FEComposite::setK2(float k2)
    142 {
    143     if (m_k2 == k2)
    144         return false;
    145     m_k2 = k2;
    146     return true;
    147 }
    148 
    149 float FEComposite::k3() const
    150 {
    151     return m_k3;
    152 }
    153 
    154 bool FEComposite::setK3(float k3)
    155 {
    156     if (m_k3 == k3)
    157         return false;
    158     m_k3 = k3;
    159     return true;
    160 }
    161 
    162 float FEComposite::k4() const
    163 {
    164     return m_k4;
    165 }
    166 
    167 bool FEComposite::setK4(float k4)
    168 {
    169     if (m_k4 == k4)
    170         return false;
    171     m_k4 = k4;
    172     return true;
    173 }
    174 
    175 void FEComposite::correctFilterResultIfNeeded()
    176 {
    177     if (m_type != FECOMPOSITE_OPERATOR_ARITHMETIC)
    178         return;
    179 
    180     forceValidPreMultipliedPixels();
    181 }
    182 
    183 template <int b1, int b4>
    184 static inline void computeArithmeticPixels(unsigned char* source, unsigned char* destination, int pixelArrayLength,
    185                                     float k1, float k2, float k3, float k4)
    186 {
    187     float scaledK1;
    188     float scaledK4;
    189     if (b1)
    190         scaledK1 = k1 / 255.0f;
    191     if (b4)
    192         scaledK4 = k4 * 255.0f;
    193 
    194     while (--pixelArrayLength >= 0) {
    195         unsigned char i1 = *source;
    196         unsigned char i2 = *destination;
    197         float result = k2 * i1 + k3 * i2;
    198         if (b1)
    199             result += scaledK1 * i1 * i2;
    200         if (b4)
    201             result += scaledK4;
    202 
    203         if (result <= 0)
    204             *destination = 0;
    205         else if (result >= 255)
    206             *destination = 255;
    207         else
    208             *destination = result;
    209         ++source;
    210         ++destination;
    211     }
    212 }
    213 
    214 // computeArithmeticPixelsUnclamped is a faster version of computeArithmeticPixels for the common case where clamping
    215 // is not necessary. This enables aggresive compiler optimizations such as auto-vectorization.
    216 template <int b1, int b4>
    217 static inline void computeArithmeticPixelsUnclamped(unsigned char* source, unsigned char* destination, int pixelArrayLength, float k1, float k2, float k3, float k4)
    218 {
    219     float scaledK1;
    220     float scaledK4;
    221     if (b1)
    222         scaledK1 = k1 / 255.0f;
    223     if (b4)
    224         scaledK4 = k4 * 255.0f;
    225 
    226     while (--pixelArrayLength >= 0) {
    227         unsigned char i1 = *source;
    228         unsigned char i2 = *destination;
    229         float result = k2 * i1 + k3 * i2;
    230         if (b1)
    231             result += scaledK1 * i1 * i2;
    232         if (b4)
    233             result += scaledK4;
    234 
    235         *destination = result;
    236         ++source;
    237         ++destination;
    238     }
    239 }
    240 
    241 static inline void arithmeticSoftware(unsigned char* source, unsigned char* destination, int pixelArrayLength, float k1, float k2, float k3, float k4)
    242 {
    243     float upperLimit = std::max(0.0f, k1) + std::max(0.0f, k2) + std::max(0.0f, k3) + k4;
    244     float lowerLimit = std::min(0.0f, k1) + std::min(0.0f, k2) + std::min(0.0f, k3) + k4;
    245     if ((k4 >= 0.0f && k4 <= 1.0f) && (upperLimit >= 0.0f && upperLimit <= 1.0f) && (lowerLimit >= 0.0f && lowerLimit <= 1.0f)) {
    246         if (k4) {
    247             if (k1)
    248                 computeArithmeticPixelsUnclamped<1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
    249             else
    250                 computeArithmeticPixelsUnclamped<0, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
    251         } else {
    252             if (k1)
    253                 computeArithmeticPixelsUnclamped<1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
    254             else
    255                 computeArithmeticPixelsUnclamped<0, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
    256         }
    257         return;
    258     }
    259 
    260     if (k4) {
    261         if (k1)
    262             computeArithmeticPixels<1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
    263         else
    264             computeArithmeticPixels<0, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
    265     } else {
    266         if (k1)
    267             computeArithmeticPixels<1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
    268         else
    269             computeArithmeticPixels<0, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
    270     }
    271 }
    272 
    273 inline void FEComposite::platformArithmeticSoftware(Uint8ClampedArray* source, Uint8ClampedArray* destination,
    274     float k1, float k2, float k3, float k4)
    275 {
    276     int length = source->length();
    277     ASSERT(length == static_cast<int>(destination->length()));
    278     // The selection here eventually should happen dynamically.
    279 #if HAVE(ARM_NEON_INTRINSICS)
    280     ASSERT(!(length & 0x3));
    281     platformArithmeticNeon(source->data(), destination->data(), length, k1, k2, k3, k4);
    282 #else
    283     arithmeticSoftware(source->data(), destination->data(), length, k1, k2, k3, k4);
    284 #endif
    285 }
    286 
    287 void FEComposite::determineAbsolutePaintRect()
    288 {
    289     switch (m_type) {
    290     case FECOMPOSITE_OPERATOR_IN:
    291     case FECOMPOSITE_OPERATOR_ATOP:
    292         // For In and Atop the first effect just influences the result of
    293         // the second effect. So just use the absolute paint rect of the second effect here.
    294         setAbsolutePaintRect(inputEffect(1)->absolutePaintRect());
    295         return;
    296     case FECOMPOSITE_OPERATOR_ARITHMETIC:
    297         // Arithmetic may influnce the compele filter primitive region. So we can't
    298         // optimize the paint region here.
    299         setAbsolutePaintRect(enclosingIntRect(maxEffectRect()));
    300         return;
    301     default:
    302         // Take the union of both input effects.
    303         FilterEffect::determineAbsolutePaintRect();
    304         return;
    305     }
    306 }
    307 
    308 void FEComposite::applySoftware()
    309 {
    310     FilterEffect* in = inputEffect(0);
    311     FilterEffect* in2 = inputEffect(1);
    312 
    313     if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) {
    314         Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult();
    315         if (!dstPixelArray)
    316             return;
    317 
    318         IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
    319         RefPtr<Uint8ClampedArray> srcPixelArray = in->asPremultipliedImage(effectADrawingRect);
    320 
    321         IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
    322         in2->copyPremultipliedImage(dstPixelArray, effectBDrawingRect);
    323 
    324         platformArithmeticSoftware(srcPixelArray.get(), dstPixelArray, m_k1, m_k2, m_k3, m_k4);
    325         return;
    326     }
    327 
    328     ImageBuffer* resultImage = createImageBufferResult();
    329     if (!resultImage)
    330         return;
    331     GraphicsContext* filterContext = resultImage->context();
    332 
    333     ImageBuffer* imageBuffer = in->asImageBuffer();
    334     ImageBuffer* imageBuffer2 = in2->asImageBuffer();
    335     ASSERT(imageBuffer);
    336     ASSERT(imageBuffer2);
    337 
    338     switch (m_type) {
    339     case FECOMPOSITE_OPERATOR_OVER:
    340         filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
    341         filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()));
    342         break;
    343     case FECOMPOSITE_OPERATOR_IN: {
    344         // Applies only to the intersected region.
    345         IntRect destinationRect = in->absolutePaintRect();
    346         destinationRect.intersect(in2->absolutePaintRect());
    347         destinationRect.intersect(absolutePaintRect());
    348         if (destinationRect.isEmpty())
    349             break;
    350         IntPoint destinationPoint(destinationRect.x() - absolutePaintRect().x(), destinationRect.y() - absolutePaintRect().y());
    351         IntRect sourceRect(IntPoint(destinationRect.x() - in->absolutePaintRect().x(),
    352                                     destinationRect.y() - in->absolutePaintRect().y()), destinationRect.size());
    353         IntRect source2Rect(IntPoint(destinationRect.x() - in2->absolutePaintRect().x(),
    354                                      destinationRect.y() - in2->absolutePaintRect().y()), destinationRect.size());
    355         filterContext->drawImageBuffer(imageBuffer2, destinationPoint, source2Rect);
    356         filterContext->drawImageBuffer(imageBuffer, destinationPoint, sourceRect, CompositeSourceIn);
    357         break;
    358     }
    359     case FECOMPOSITE_OPERATOR_OUT:
    360         filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()));
    361         filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()), IntRect(IntPoint(), imageBuffer2->logicalSize()), CompositeDestinationOut);
    362         break;
    363     case FECOMPOSITE_OPERATOR_ATOP:
    364         filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
    365         filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), IntRect(IntPoint(), imageBuffer->logicalSize()), CompositeSourceAtop);
    366         break;
    367     case FECOMPOSITE_OPERATOR_XOR:
    368         filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
    369         filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), IntRect(IntPoint(), imageBuffer->logicalSize()), CompositeXOR);
    370         break;
    371     default:
    372         break;
    373     }
    374 }
    375 
    376 SkXfermode::Mode toXfermode(WebCore::CompositeOperationType mode)
    377 {
    378     switch (mode) {
    379     case WebCore::FECOMPOSITE_OPERATOR_OVER:
    380         return SkXfermode::kSrcOver_Mode;
    381     case WebCore::FECOMPOSITE_OPERATOR_IN:
    382         return SkXfermode::kSrcIn_Mode;
    383     case WebCore::FECOMPOSITE_OPERATOR_OUT:
    384         return SkXfermode::kSrcOut_Mode;
    385     case WebCore::FECOMPOSITE_OPERATOR_ATOP:
    386         return SkXfermode::kSrcATop_Mode;
    387     case WebCore::FECOMPOSITE_OPERATOR_XOR:
    388         return SkXfermode::kXor_Mode;
    389     default:
    390         ASSERT_NOT_REACHED();
    391         return SkXfermode::kSrcOver_Mode;
    392     }
    393 }
    394 
    395 PassRefPtr<SkImageFilter> FEComposite::createImageFilter(SkiaImageFilterBuilder* builder)
    396 {
    397     RefPtr<SkImageFilter> foreground(builder->build(inputEffect(0), operatingColorSpace()));
    398     RefPtr<SkImageFilter> background(builder->build(inputEffect(1), operatingColorSpace()));
    399     if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) {
    400         SkAutoTUnref<SkXfermode> mode(SkArithmeticMode::Create(SkFloatToScalar(m_k1), SkFloatToScalar(m_k2), SkFloatToScalar(m_k3), SkFloatToScalar(m_k4)));
    401         return adoptRef(new SkXfermodeImageFilter(mode, background.get(), foreground.get()));
    402     }
    403     return adoptRef(new CompositeImageFilter(toXfermode(m_type), background.get(), foreground.get()));
    404 }
    405 
    406 static TextStream& operator<<(TextStream& ts, const CompositeOperationType& type)
    407 {
    408     switch (type) {
    409     case FECOMPOSITE_OPERATOR_UNKNOWN:
    410         ts << "UNKNOWN";
    411         break;
    412     case FECOMPOSITE_OPERATOR_OVER:
    413         ts << "OVER";
    414         break;
    415     case FECOMPOSITE_OPERATOR_IN:
    416         ts << "IN";
    417         break;
    418     case FECOMPOSITE_OPERATOR_OUT:
    419         ts << "OUT";
    420         break;
    421     case FECOMPOSITE_OPERATOR_ATOP:
    422         ts << "ATOP";
    423         break;
    424     case FECOMPOSITE_OPERATOR_XOR:
    425         ts << "XOR";
    426         break;
    427     case FECOMPOSITE_OPERATOR_ARITHMETIC:
    428         ts << "ARITHMETIC";
    429         break;
    430     }
    431     return ts;
    432 }
    433 
    434 TextStream& FEComposite::externalRepresentation(TextStream& ts, int indent) const
    435 {
    436     writeIndent(ts, indent);
    437     ts << "[feComposite";
    438     FilterEffect::externalRepresentation(ts);
    439     ts << " operation=\"" << m_type << "\"";
    440     if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC)
    441         ts << " k1=\"" << m_k1 << "\" k2=\"" << m_k2 << "\" k3=\"" << m_k3 << "\" k4=\"" << m_k4 << "\"";
    442     ts << "]\n";
    443     inputEffect(0)->externalRepresentation(ts, indent + 1);
    444     inputEffect(1)->externalRepresentation(ts, indent + 1);
    445     return ts;
    446 }
    447 
    448 } // namespace WebCore
    449