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 blink {
     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     ImageBuffer* resultImage = createImageBufferResult();
    157     if (!resultImage)
    158         return;
    159 
    160     RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore);
    161     RefPtr<NativeImageSkia> nativeImage = image->nativeImageForCurrentFrame();
    162     if (!nativeImage)
    163         return;
    164 
    165     unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
    166     getValues(rValues, gValues, bValues, aValues);
    167 
    168     IntRect destRect = drawingRegionOfInputImage(in->absolutePaintRect());
    169     SkPaint paint;
    170     paint.setColorFilter(SkTableColorFilter::CreateARGB(aValues, rValues, gValues, bValues))->unref();
    171     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
    172     resultImage->context()->drawBitmap(nativeImage->bitmap(), destRect.x(), destRect.y(), &paint);
    173 
    174     if (affectsTransparentPixels()) {
    175         IntRect fullRect = IntRect(IntPoint(), absolutePaintRect().size());
    176         resultImage->context()->clipOut(destRect);
    177         resultImage->context()->fillRect(fullRect, Color(rValues[0], gValues[0], bValues[0], aValues[0]));
    178     }
    179 }
    180 
    181 bool FEComponentTransfer::affectsTransparentPixels()
    182 {
    183     double intercept = 0;
    184     switch (m_alphaFunc.type) {
    185     case FECOMPONENTTRANSFER_TYPE_UNKNOWN:
    186     case FECOMPONENTTRANSFER_TYPE_IDENTITY:
    187         break;
    188     case FECOMPONENTTRANSFER_TYPE_TABLE:
    189     case FECOMPONENTTRANSFER_TYPE_DISCRETE:
    190         if (m_alphaFunc.tableValues.size() > 0)
    191             intercept = m_alphaFunc.tableValues[0];
    192         break;
    193     case FECOMPONENTTRANSFER_TYPE_LINEAR:
    194         intercept = m_alphaFunc.intercept;
    195         break;
    196     case FECOMPONENTTRANSFER_TYPE_GAMMA:
    197         intercept = m_alphaFunc.offset;
    198         break;
    199     }
    200     return 255 * intercept >= 1;
    201 }
    202 
    203 PassRefPtr<SkImageFilter> FEComponentTransfer::createImageFilter(SkiaImageFilterBuilder* builder)
    204 {
    205     RefPtr<SkImageFilter> input(builder->build(inputEffect(0), operatingColorSpace()));
    206 
    207     unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
    208     getValues(rValues, gValues, bValues, aValues);
    209 
    210     SkAutoTUnref<SkColorFilter> colorFilter(SkTableColorFilter::CreateARGB(aValues, rValues, gValues, bValues));
    211 
    212     SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset());
    213     return adoptRef(SkColorFilterImageFilter::Create(colorFilter, input.get(), &cropRect));
    214 }
    215 
    216 void FEComponentTransfer::getValues(unsigned char rValues[256], unsigned char gValues[256], unsigned char bValues[256], unsigned char aValues[256])
    217 {
    218     for (unsigned i = 0; i < 256; ++i)
    219         rValues[i] = gValues[i] = bValues[i] = aValues[i] = i;
    220     unsigned char* tables[] = { rValues, gValues, bValues, aValues };
    221     ComponentTransferFunction transferFunction[] = {m_redFunc, m_greenFunc, m_blueFunc, m_alphaFunc};
    222     TransferType callEffect[] = {identity, identity, table, discrete, linear, gamma};
    223 
    224     for (unsigned channel = 0; channel < 4; channel++) {
    225         ASSERT_WITH_SECURITY_IMPLICATION(static_cast<size_t>(transferFunction[channel].type) < WTF_ARRAY_LENGTH(callEffect));
    226         (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]);
    227     }
    228 }
    229 
    230 static TextStream& operator<<(TextStream& ts, const ComponentTransferType& type)
    231 {
    232     switch (type) {
    233     case FECOMPONENTTRANSFER_TYPE_UNKNOWN:
    234         ts << "UNKNOWN";
    235         break;
    236     case FECOMPONENTTRANSFER_TYPE_IDENTITY:
    237         ts << "IDENTITY";
    238         break;
    239     case FECOMPONENTTRANSFER_TYPE_TABLE:
    240         ts << "TABLE";
    241         break;
    242     case FECOMPONENTTRANSFER_TYPE_DISCRETE:
    243         ts << "DISCRETE";
    244         break;
    245     case FECOMPONENTTRANSFER_TYPE_LINEAR:
    246         ts << "LINEAR";
    247         break;
    248     case FECOMPONENTTRANSFER_TYPE_GAMMA:
    249         ts << "GAMMA";
    250         break;
    251     }
    252     return ts;
    253 }
    254 
    255 static TextStream& operator<<(TextStream& ts, const ComponentTransferFunction& function)
    256 {
    257     ts << "type=\"" << function.type
    258        << "\" slope=\"" << function.slope
    259        << "\" intercept=\"" << function.intercept
    260        << "\" amplitude=\"" << function.amplitude
    261        << "\" exponent=\"" << function.exponent
    262        << "\" offset=\"" << function.offset << "\"";
    263     return ts;
    264 }
    265 
    266 TextStream& FEComponentTransfer::externalRepresentation(TextStream& ts, int indent) const
    267 {
    268     writeIndent(ts, indent);
    269     ts << "[feComponentTransfer";
    270     FilterEffect::externalRepresentation(ts);
    271     ts << " \n";
    272     writeIndent(ts, indent + 2);
    273     ts << "{red: " << m_redFunc << "}\n";
    274     writeIndent(ts, indent + 2);
    275     ts << "{green: " << m_greenFunc << "}\n";
    276     writeIndent(ts, indent + 2);
    277     ts << "{blue: " << m_blueFunc << "}\n";
    278     writeIndent(ts, indent + 2);
    279     ts << "{alpha: " << m_alphaFunc << "}]\n";
    280     inputEffect(0)->externalRepresentation(ts, indent + 1);
    281     return ts;
    282 }
    283 
    284 } // namespace blink
    285