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/FEComponentTransfer.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/MathExtras.h"
     35 #include "wtf/StdLibExtras.h"
     36 #include "wtf/Uint8ClampedArray.h"
     37 
     38 #include "SkColorFilterImageFilter.h"
     39 #include "SkTableColorFilter.h"
     40 #include "core/platform/graphics/filters/SkiaImageFilterBuilder.h"
     41 #include "core/platform/graphics/skia/NativeImageSkia.h"
     42 
     43 namespace WebCore {
     44 
     45 typedef void (*TransferType)(unsigned char*, const ComponentTransferFunction&);
     46 
     47 FEComponentTransfer::FEComponentTransfer(Filter* filter, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc,
     48                                          const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc)
     49     : FilterEffect(filter)
     50     , m_redFunc(redFunc)
     51     , m_greenFunc(greenFunc)
     52     , m_blueFunc(blueFunc)
     53     , m_alphaFunc(alphaFunc)
     54 {
     55 }
     56 
     57 PassRefPtr<FEComponentTransfer> FEComponentTransfer::create(Filter* filter, const ComponentTransferFunction& redFunc,
     58     const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc)
     59 {
     60     return adoptRef(new FEComponentTransfer(filter, redFunc, greenFunc, blueFunc, alphaFunc));
     61 }
     62 
     63 ComponentTransferFunction FEComponentTransfer::redFunction() const
     64 {
     65     return m_redFunc;
     66 }
     67 
     68 void FEComponentTransfer::setRedFunction(const ComponentTransferFunction& func)
     69 {
     70     m_redFunc = func;
     71 }
     72 
     73 ComponentTransferFunction FEComponentTransfer::greenFunction() const
     74 {
     75     return m_greenFunc;
     76 }
     77 
     78 void FEComponentTransfer::setGreenFunction(const ComponentTransferFunction& func)
     79 {
     80     m_greenFunc = func;
     81 }
     82 
     83 ComponentTransferFunction FEComponentTransfer::blueFunction() const
     84 {
     85     return m_blueFunc;
     86 }
     87 
     88 void FEComponentTransfer::setBlueFunction(const ComponentTransferFunction& func)
     89 {
     90     m_blueFunc = func;
     91 }
     92 
     93 ComponentTransferFunction FEComponentTransfer::alphaFunction() const
     94 {
     95     return m_alphaFunc;
     96 }
     97 
     98 void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func)
     99 {
    100     m_alphaFunc = func;
    101 }
    102 
    103 static void identity(unsigned char*, const ComponentTransferFunction&)
    104 {
    105 }
    106 
    107 static void table(unsigned char* values, const ComponentTransferFunction& transferFunction)
    108 {
    109     const Vector<float>& tableValues = transferFunction.tableValues;
    110     unsigned n = tableValues.size();
    111     if (n < 1)
    112         return;
    113     for (unsigned i = 0; i < 256; ++i) {
    114         double c = i / 255.0;
    115         unsigned k = static_cast<unsigned>(c * (n - 1));
    116         double v1 = tableValues[k];
    117         double v2 = tableValues[std::min((k + 1), (n - 1))];
    118         double val = 255.0 * (v1 + (c * (n - 1) - k) * (v2 - v1));
    119         val = std::max(0.0, std::min(255.0, val));
    120         values[i] = static_cast<unsigned char>(val);
    121     }
    122 }
    123 
    124 static void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction)
    125 {
    126     const Vector<float>& tableValues = transferFunction.tableValues;
    127     unsigned n = tableValues.size();
    128     if (n < 1)
    129         return;
    130     for (unsigned i = 0; i < 256; ++i) {
    131         unsigned k = static_cast<unsigned>((i * n) / 255.0);
    132         k = std::min(k, n - 1);
    133         double val = 255 * tableValues[k];
    134         val = std::max(0.0, std::min(255.0, val));
    135         values[i] = static_cast<unsigned char>(val);
    136     }
    137 }
    138 
    139 static void linear(unsigned char* values, const ComponentTransferFunction& transferFunction)
    140 {
    141     for (unsigned i = 0; i < 256; ++i) {
    142         double val = transferFunction.slope * i + 255 * transferFunction.intercept;
    143         val = std::max(0.0, std::min(255.0, val));
    144         values[i] = static_cast<unsigned char>(val);
    145     }
    146 }
    147 
    148 static void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction)
    149 {
    150     for (unsigned i = 0; i < 256; ++i) {
    151         double exponent = transferFunction.exponent; // RCVT doesn't like passing a double and a float to pow, so promote this to double
    152         double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), exponent) + transferFunction.offset);
    153         val = std::max(0.0, std::min(255.0, val));
    154         values[i] = static_cast<unsigned char>(val);
    155     }
    156 }
    157 
    158 void FEComponentTransfer::applySoftware()
    159 {
    160     FilterEffect* in = inputEffect(0);
    161 
    162     Uint8ClampedArray* pixelArray = createUnmultipliedImageResult();
    163     if (!pixelArray)
    164         return;
    165 
    166     unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
    167     getValues(rValues, gValues, bValues, aValues);
    168     unsigned char* tables[] = { rValues, gValues, bValues, aValues };
    169 
    170     IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
    171     in->copyUnmultipliedImage(pixelArray, drawingRect);
    172 
    173     unsigned pixelArrayLength = pixelArray->length();
    174     for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
    175         for (unsigned channel = 0; channel < 4; ++channel) {
    176             unsigned char c = pixelArray->item(pixelOffset + channel);
    177             pixelArray->set(pixelOffset + channel, tables[channel][c]);
    178         }
    179     }
    180 }
    181 
    182 bool FEComponentTransfer::applySkia()
    183 {
    184     FilterEffect* in = inputEffect(0);
    185     ImageBuffer* resultImage = createImageBufferResult();
    186     if (!resultImage)
    187         return false;
    188 
    189     RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore);
    190     RefPtr<NativeImageSkia> nativeImage = image->nativeImageForCurrentFrame();
    191     if (!nativeImage)
    192         return false;
    193 
    194     unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
    195     getValues(rValues, gValues, bValues, aValues);
    196 
    197     SkPaint paint;
    198     paint.setColorFilter(SkTableColorFilter::CreateARGB(aValues, rValues, gValues, bValues))->unref();
    199     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    200     resultImage->context()->drawBitmap(nativeImage->bitmap(), 0, 0, &paint);
    201 
    202     return true;
    203 }
    204 
    205 PassRefPtr<SkImageFilter> FEComponentTransfer::createImageFilter(SkiaImageFilterBuilder* builder)
    206 {
    207     RefPtr<SkImageFilter> input(builder->build(inputEffect(0), operatingColorSpace()));
    208 
    209     unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
    210     getValues(rValues, gValues, bValues, aValues);
    211 
    212     SkAutoTUnref<SkColorFilter> colorFilter(SkTableColorFilter::CreateARGB(aValues, rValues, gValues, bValues));
    213 
    214     return adoptRef(SkColorFilterImageFilter::Create(colorFilter, input.get()));
    215 }
    216 
    217 void FEComponentTransfer::getValues(unsigned char rValues[256], unsigned char gValues[256], unsigned char bValues[256], unsigned char aValues[256])
    218 {
    219     for (unsigned i = 0; i < 256; ++i)
    220         rValues[i] = gValues[i] = bValues[i] = aValues[i] = i;
    221     unsigned char* tables[] = { rValues, gValues, bValues, aValues };
    222     ComponentTransferFunction transferFunction[] = {m_redFunc, m_greenFunc, m_blueFunc, m_alphaFunc};
    223     TransferType callEffect[] = {identity, identity, table, discrete, linear, gamma};
    224 
    225     for (unsigned channel = 0; channel < 4; channel++) {
    226         ASSERT_WITH_SECURITY_IMPLICATION(static_cast<size_t>(transferFunction[channel].type) < WTF_ARRAY_LENGTH(callEffect));
    227         (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]);
    228     }
    229 }
    230 
    231 static TextStream& operator<<(TextStream& ts, const ComponentTransferType& type)
    232 {
    233     switch (type) {
    234     case FECOMPONENTTRANSFER_TYPE_UNKNOWN:
    235         ts << "UNKNOWN";
    236         break;
    237     case FECOMPONENTTRANSFER_TYPE_IDENTITY:
    238         ts << "IDENTITY";
    239         break;
    240     case FECOMPONENTTRANSFER_TYPE_TABLE:
    241         ts << "TABLE";
    242         break;
    243     case FECOMPONENTTRANSFER_TYPE_DISCRETE:
    244         ts << "DISCRETE";
    245         break;
    246     case FECOMPONENTTRANSFER_TYPE_LINEAR:
    247         ts << "LINEAR";
    248         break;
    249     case FECOMPONENTTRANSFER_TYPE_GAMMA:
    250         ts << "GAMMA";
    251         break;
    252     }
    253     return ts;
    254 }
    255 
    256 static TextStream& operator<<(TextStream& ts, const ComponentTransferFunction& function)
    257 {
    258     ts << "type=\"" << function.type
    259        << "\" slope=\"" << function.slope
    260        << "\" intercept=\"" << function.intercept
    261        << "\" amplitude=\"" << function.amplitude
    262        << "\" exponent=\"" << function.exponent
    263        << "\" offset=\"" << function.offset << "\"";
    264     return ts;
    265 }
    266 
    267 TextStream& FEComponentTransfer::externalRepresentation(TextStream& ts, int indent) const
    268 {
    269     writeIndent(ts, indent);
    270     ts << "[feComponentTransfer";
    271     FilterEffect::externalRepresentation(ts);
    272     ts << " \n";
    273     writeIndent(ts, indent + 2);
    274     ts << "{red: " << m_redFunc << "}\n";
    275     writeIndent(ts, indent + 2);
    276     ts << "{green: " << m_greenFunc << "}\n";
    277     writeIndent(ts, indent + 2);
    278     ts << "{blue: " << m_blueFunc << "}\n";
    279     writeIndent(ts, indent + 2);
    280     ts << "{alpha: " << m_alphaFunc << "}]\n";
    281     inputEffect(0)->externalRepresentation(ts, indent + 1);
    282     return ts;
    283 }
    284 
    285 } // namespace WebCore
    286