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  *
      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 "FEBlend.h"
     27 
     28 #include "Filter.h"
     29 #include "FloatPoint.h"
     30 #include "GraphicsContext.h"
     31 #include "RenderTreeAsText.h"
     32 #include "TextStream.h"
     33 
     34 #include <wtf/ByteArray.h>
     35 
     36 typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB);
     37 
     38 namespace WebCore {
     39 
     40 FEBlend::FEBlend(Filter* filter, BlendModeType mode)
     41     : FilterEffect(filter)
     42     , m_mode(mode)
     43 {
     44 }
     45 
     46 PassRefPtr<FEBlend> FEBlend::create(Filter* filter, BlendModeType mode)
     47 {
     48     return adoptRef(new FEBlend(filter, mode));
     49 }
     50 
     51 BlendModeType FEBlend::blendMode() const
     52 {
     53     return m_mode;
     54 }
     55 
     56 bool FEBlend::setBlendMode(BlendModeType mode)
     57 {
     58     if (m_mode == mode)
     59         return false;
     60     m_mode = mode;
     61     return true;
     62 }
     63 
     64 static unsigned char unknown(unsigned char, unsigned char, unsigned char, unsigned char)
     65 {
     66     return 0;
     67 }
     68 
     69 static unsigned char normal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char)
     70 {
     71     return (((255 - alphaA) * colorB + colorA * 255) / 255);
     72 }
     73 
     74 static unsigned char multiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
     75 {
     76     return (((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA) / 255);
     77 }
     78 
     79 static unsigned char screen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char)
     80 {
     81     return (((colorB + colorA) * 255 - colorA * colorB) / 255);
     82 }
     83 
     84 static unsigned char darken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
     85 {
     86     return ((std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255);
     87 }
     88 
     89 static unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
     90 {
     91     return ((std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255);
     92 }
     93 
     94 void FEBlend::apply()
     95 {
     96     if (hasResult())
     97         return;
     98     FilterEffect* in = inputEffect(0);
     99     FilterEffect* in2 = inputEffect(1);
    100     in->apply();
    101     in2->apply();
    102     if (!in->hasResult() || !in2->hasResult())
    103         return;
    104 
    105     if (m_mode <= FEBLEND_MODE_UNKNOWN || m_mode > FEBLEND_MODE_LIGHTEN)
    106         return;
    107 
    108     ByteArray* dstPixelArray = createPremultipliedImageResult();
    109     if (!dstPixelArray)
    110         return;
    111 
    112     IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
    113     RefPtr<ByteArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect);
    114 
    115     IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
    116     RefPtr<ByteArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect);
    117 
    118     // Keep synchronized with BlendModeType
    119     static const BlendType callEffect[] = {unknown, normal, multiply, screen, darken, lighten};
    120 
    121     unsigned pixelArrayLength = srcPixelArrayA->length();
    122     ASSERT(pixelArrayLength == srcPixelArrayB->length());
    123     for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
    124         unsigned char alphaA = srcPixelArrayA->get(pixelOffset + 3);
    125         unsigned char alphaB = srcPixelArrayB->get(pixelOffset + 3);
    126         for (unsigned channel = 0; channel < 3; ++channel) {
    127             unsigned char colorA = srcPixelArrayA->get(pixelOffset + channel);
    128             unsigned char colorB = srcPixelArrayB->get(pixelOffset + channel);
    129 
    130             unsigned char result = (*callEffect[m_mode])(colorA, colorB, alphaA, alphaB);
    131             dstPixelArray->set(pixelOffset + channel, result);
    132         }
    133         unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255;
    134         dstPixelArray->set(pixelOffset + 3, alphaR);
    135     }
    136 }
    137 
    138 void FEBlend::dump()
    139 {
    140 }
    141 
    142 static TextStream& operator<<(TextStream& ts, const BlendModeType& type)
    143 {
    144     switch (type) {
    145     case FEBLEND_MODE_UNKNOWN:
    146         ts << "UNKNOWN";
    147         break;
    148     case FEBLEND_MODE_NORMAL:
    149         ts << "NORMAL";
    150         break;
    151     case FEBLEND_MODE_MULTIPLY:
    152         ts << "MULTIPLY";
    153         break;
    154     case FEBLEND_MODE_SCREEN:
    155         ts << "SCREEN";
    156         break;
    157     case FEBLEND_MODE_DARKEN:
    158         ts << "DARKEN";
    159         break;
    160     case FEBLEND_MODE_LIGHTEN:
    161         ts << "LIGHTEN";
    162         break;
    163     }
    164     return ts;
    165 }
    166 
    167 TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const
    168 {
    169     writeIndent(ts, indent);
    170     ts << "[feBlend";
    171     FilterEffect::externalRepresentation(ts);
    172     ts << " mode=\"" << m_mode << "\"]\n";
    173     inputEffect(0)->externalRepresentation(ts, indent + 1);
    174     inputEffect(1)->externalRepresentation(ts, indent + 1);
    175     return ts;
    176 }
    177 
    178 } // namespace WebCore
    179 
    180 #endif // ENABLE(FILTERS)
    181