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