Home | History | Annotate | Download | only in filters
      1 /*
      2  * Copyright (C) 2010 University of Szeged
      3  * Copyright (C) 2010 Zoltan Herczeg
      4  * Copyright (C) 2013 Google Inc. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
     16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
     19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "config.h"
     29 
     30 #include "core/platform/graphics/filters/FELighting.h"
     31 
     32 #include "core/platform/graphics/cpu/arm/filters/FELightingNEON.h"
     33 #include "wtf/ParallelJobs.h"
     34 
     35 #include "SkLightingImageFilter.h"
     36 #include "core/platform/graphics/filters/DistantLightSource.h"
     37 #include "core/platform/graphics/filters/PointLightSource.h"
     38 #include "core/platform/graphics/filters/SkiaImageFilterBuilder.h"
     39 #include "core/platform/graphics/filters/SpotLightSource.h"
     40 #include "core/platform/graphics/skia/NativeImageSkia.h"
     41 
     42 namespace WebCore {
     43 
     44 FELighting::FELighting(Filter* filter, LightingType lightingType, const Color& lightingColor, float surfaceScale,
     45     float diffuseConstant, float specularConstant, float specularExponent,
     46     float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource)
     47     : FilterEffect(filter)
     48     , m_lightingType(lightingType)
     49     , m_lightSource(lightSource)
     50     , m_lightingColor(lightingColor)
     51     , m_surfaceScale(surfaceScale)
     52     , m_diffuseConstant(diffuseConstant)
     53     , m_specularConstant(specularConstant)
     54     , m_specularExponent(specularExponent)
     55     , m_kernelUnitLengthX(kernelUnitLengthX)
     56     , m_kernelUnitLengthY(kernelUnitLengthY)
     57 {
     58 }
     59 
     60 const static int cPixelSize = 4;
     61 const static int cAlphaChannelOffset = 3;
     62 const static unsigned char cOpaqueAlpha = static_cast<unsigned char>(0xff);
     63 const static float cFactor1div2 = -1 / 2.f;
     64 const static float cFactor1div3 = -1 / 3.f;
     65 const static float cFactor1div4 = -1 / 4.f;
     66 const static float cFactor2div3 = -2 / 3.f;
     67 
     68 // << 1 is signed multiply by 2
     69 inline void FELighting::LightingData::topLeft(int offset, IntPoint& normalVector)
     70 {
     71     int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
     72     int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
     73     offset += widthMultipliedByPixelSize;
     74     int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
     75     int bottomRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
     76     normalVector.setX(-(center << 1) + (right << 1) - bottom + bottomRight);
     77     normalVector.setY(-(center << 1) - right + (bottom << 1) + bottomRight);
     78 }
     79 
     80 inline void FELighting::LightingData::topRow(int offset, IntPoint& normalVector)
     81 {
     82     int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
     83     int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
     84     int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
     85     offset += widthMultipliedByPixelSize;
     86     int bottomLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
     87     int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
     88     int bottomRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
     89     normalVector.setX(-(left << 1) + (right << 1) - bottomLeft + bottomRight);
     90     normalVector.setY(-left - (center << 1) - right + bottomLeft + (bottom << 1) + bottomRight);
     91 }
     92 
     93 inline void FELighting::LightingData::topRight(int offset, IntPoint& normalVector)
     94 {
     95     int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
     96     int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
     97     offset += widthMultipliedByPixelSize;
     98     int bottomLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
     99     int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    100     normalVector.setX(-(left << 1) + (center << 1) - bottomLeft + bottom);
    101     normalVector.setY(-left - (center << 1) + bottomLeft + (bottom << 1));
    102 }
    103 
    104 inline void FELighting::LightingData::leftColumn(int offset, IntPoint& normalVector)
    105 {
    106     int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    107     int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    108     offset -= widthMultipliedByPixelSize;
    109     int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    110     int topRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    111     offset += widthMultipliedByPixelSize << 1;
    112     int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    113     int bottomRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    114     normalVector.setX(-top + topRight - (center << 1) + (right << 1) - bottom + bottomRight);
    115     normalVector.setY(-(top << 1) - topRight + (bottom << 1) + bottomRight);
    116 }
    117 
    118 inline void FELighting::LightingData::interior(int offset, IntPoint& normalVector)
    119 {
    120     int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    121     int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    122     offset -= widthMultipliedByPixelSize;
    123     int topLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    124     int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    125     int topRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    126     offset += widthMultipliedByPixelSize << 1;
    127     int bottomLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    128     int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    129     int bottomRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    130     normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1) - bottomLeft + bottomRight);
    131     normalVector.setY(-topLeft - (top << 1) - topRight + bottomLeft + (bottom << 1) + bottomRight);
    132 }
    133 
    134 inline void FELighting::LightingData::rightColumn(int offset, IntPoint& normalVector)
    135 {
    136     int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    137     int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    138     offset -= widthMultipliedByPixelSize;
    139     int topLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    140     int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    141     offset += widthMultipliedByPixelSize << 1;
    142     int bottomLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    143     int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    144     normalVector.setX(-topLeft + top - (left << 1) + (center << 1) - bottomLeft + bottom);
    145     normalVector.setY(-topLeft - (top << 1) + bottomLeft + (bottom << 1));
    146 }
    147 
    148 inline void FELighting::LightingData::bottomLeft(int offset, IntPoint& normalVector)
    149 {
    150     int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    151     int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    152     offset -= widthMultipliedByPixelSize;
    153     int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    154     int topRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    155     normalVector.setX(-top + topRight - (center << 1) + (right << 1));
    156     normalVector.setY(-(top << 1) - topRight + (center << 1) + right);
    157 }
    158 
    159 inline void FELighting::LightingData::bottomRow(int offset, IntPoint& normalVector)
    160 {
    161     int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    162     int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    163     int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    164     offset -= widthMultipliedByPixelSize;
    165     int topLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    166     int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    167     int topRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
    168     normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1));
    169     normalVector.setY(-topLeft - (top << 1) - topRight + left + (center << 1) + right);
    170 }
    171 
    172 inline void FELighting::LightingData::bottomRight(int offset, IntPoint& normalVector)
    173 {
    174     int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    175     int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    176     offset -= widthMultipliedByPixelSize;
    177     int topLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
    178     int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
    179     normalVector.setX(-topLeft + top - (left << 1) + (center << 1));
    180     normalVector.setY(-topLeft - (top << 1) + left + (center << 1));
    181 }
    182 
    183 inline void FELighting::inlineSetPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData,
    184                                        int lightX, int lightY, float factorX, float factorY, IntPoint& normal2DVector)
    185 {
    186     m_lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->item(offset + cAlphaChannelOffset)) * data.surfaceScale);
    187 
    188     float lightStrength;
    189     if (!normal2DVector.x() && !normal2DVector.y()) {
    190         // Normal vector is (0, 0, 1). This is a quite frequent case.
    191         if (m_lightingType == FELighting::DiffuseLighting)
    192             lightStrength = m_diffuseConstant * paintingData.lightVector.z() / paintingData.lightVectorLength;
    193         else {
    194             FloatPoint3D halfwayVector = paintingData.lightVector;
    195             halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength);
    196             float halfwayVectorLength = halfwayVector.length();
    197             if (m_specularExponent == 1)
    198                 lightStrength = m_specularConstant * halfwayVector.z() / halfwayVectorLength;
    199             else
    200                 lightStrength = m_specularConstant * powf(halfwayVector.z() / halfwayVectorLength, m_specularExponent);
    201         }
    202     } else {
    203         FloatPoint3D normalVector;
    204         normalVector.setX(factorX * static_cast<float>(normal2DVector.x()) * data.surfaceScale);
    205         normalVector.setY(factorY * static_cast<float>(normal2DVector.y()) * data.surfaceScale);
    206         normalVector.setZ(1);
    207         float normalVectorLength = normalVector.length();
    208 
    209         if (m_lightingType == FELighting::DiffuseLighting)
    210             lightStrength = m_diffuseConstant * (normalVector * paintingData.lightVector) / (normalVectorLength * paintingData.lightVectorLength);
    211         else {
    212             FloatPoint3D halfwayVector = paintingData.lightVector;
    213             halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength);
    214             float halfwayVectorLength = halfwayVector.length();
    215             if (m_specularExponent == 1)
    216                 lightStrength = m_specularConstant * (normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength);
    217             else
    218                 lightStrength = m_specularConstant * powf((normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength), m_specularExponent);
    219         }
    220     }
    221 
    222     if (lightStrength > 1)
    223         lightStrength = 1;
    224     if (lightStrength < 0)
    225         lightStrength = 0;
    226 
    227     data.pixels->set(offset, static_cast<unsigned char>(lightStrength * paintingData.colorVector.x()));
    228     data.pixels->set(offset + 1, static_cast<unsigned char>(lightStrength * paintingData.colorVector.y()));
    229     data.pixels->set(offset + 2, static_cast<unsigned char>(lightStrength * paintingData.colorVector.z()));
    230 }
    231 
    232 void FELighting::setPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData,
    233                           int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector)
    234 {
    235     inlineSetPixel(offset, data, paintingData, lightX, lightY, factorX, factorY, normalVector);
    236 }
    237 
    238 inline void FELighting::platformApplyGenericPaint(LightingData& data, LightSource::PaintingData& paintingData, int startY, int endY)
    239 {
    240     IntPoint normalVector;
    241     int offset = 0;
    242 
    243     for (int y = startY; y < endY; ++y) {
    244         offset = y * data.widthMultipliedByPixelSize + cPixelSize;
    245         for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
    246             data.interior(offset, normalVector);
    247             inlineSetPixel(offset, data, paintingData, x, y, cFactor1div4, cFactor1div4, normalVector);
    248         }
    249     }
    250 }
    251 
    252 void FELighting::platformApplyGenericWorker(PlatformApplyGenericParameters* parameters)
    253 {
    254     parameters->filter->platformApplyGenericPaint(parameters->data, parameters->paintingData, parameters->yStart, parameters->yEnd);
    255 }
    256 
    257 inline void FELighting::platformApplyGeneric(LightingData& data, LightSource::PaintingData& paintingData)
    258 {
    259     int optimalThreadNumber = ((data.widthDecreasedByOne - 1) * (data.heightDecreasedByOne - 1)) / s_minimalRectDimension;
    260     if (optimalThreadNumber > 1) {
    261         // Initialize parallel jobs
    262         WTF::ParallelJobs<PlatformApplyGenericParameters> parallelJobs(&platformApplyGenericWorker, optimalThreadNumber);
    263 
    264         // Fill the parameter array
    265         int job = parallelJobs.numberOfJobs();
    266         if (job > 1) {
    267             // Split the job into "yStep"-sized jobs but there a few jobs that need to be slightly larger since
    268             // yStep * jobs < total size. These extras are handled by the remainder "jobsWithExtra".
    269             const int yStep = (data.heightDecreasedByOne - 1) / job;
    270             const int jobsWithExtra = (data.heightDecreasedByOne - 1) % job;
    271 
    272             int yStart = 1;
    273             for (--job; job >= 0; --job) {
    274                 PlatformApplyGenericParameters& params = parallelJobs.parameter(job);
    275                 params.filter = this;
    276                 params.data = data;
    277                 params.paintingData = paintingData;
    278                 params.yStart = yStart;
    279                 yStart += job < jobsWithExtra ? yStep + 1 : yStep;
    280                 params.yEnd = yStart;
    281             }
    282             parallelJobs.execute();
    283             return;
    284         }
    285         // Fallback to single threaded mode.
    286     }
    287 
    288     platformApplyGenericPaint(data, paintingData, 1, data.heightDecreasedByOne);
    289 }
    290 
    291 inline void FELighting::platformApply(LightingData& data, LightSource::PaintingData& paintingData)
    292 {
    293     // The selection here eventually should happen dynamically on some platforms.
    294 #if CPU(ARM_NEON) && CPU(ARM_TRADITIONAL) && COMPILER(GCC)
    295     platformApplyNeon(data, paintingData);
    296 #else
    297     platformApplyGeneric(data, paintingData);
    298 #endif
    299 }
    300 
    301 bool FELighting::drawLighting(Uint8ClampedArray* pixels, int width, int height)
    302 {
    303     LightSource::PaintingData paintingData;
    304     LightingData data;
    305 
    306     if (!m_lightSource)
    307         return false;
    308 
    309     // FIXME: do something if width or height (or both) is 1 pixel.
    310     // The W3 spec does not define this case. Now the filter just returns.
    311     if (width <= 2 || height <= 2)
    312         return false;
    313 
    314     data.pixels = pixels;
    315     data.surfaceScale = m_surfaceScale / 255.0f;
    316     data.widthMultipliedByPixelSize = width * cPixelSize;
    317     data.widthDecreasedByOne = width - 1;
    318     data.heightDecreasedByOne = height - 1;
    319     paintingData.colorVector = FloatPoint3D(m_lightingColor.red(), m_lightingColor.green(), m_lightingColor.blue());
    320     m_lightSource->initPaintingData(paintingData);
    321 
    322     // Top/Left corner.
    323     IntPoint normalVector;
    324     int offset = 0;
    325     data.topLeft(offset, normalVector);
    326     setPixel(offset, data, paintingData, 0, 0, cFactor2div3, cFactor2div3, normalVector);
    327 
    328     // Top/Right pixel.
    329     offset = data.widthMultipliedByPixelSize - cPixelSize;
    330     data.topRight(offset, normalVector);
    331     setPixel(offset, data, paintingData, data.widthDecreasedByOne, 0, cFactor2div3, cFactor2div3, normalVector);
    332 
    333     // Bottom/Left pixel.
    334     offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize;
    335     data.bottomLeft(offset, normalVector);
    336     setPixel(offset, data, paintingData, 0, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector);
    337 
    338     // Bottom/Right pixel.
    339     offset = height * data.widthMultipliedByPixelSize - cPixelSize;
    340     data.bottomRight(offset, normalVector);
    341     setPixel(offset, data, paintingData, data.widthDecreasedByOne, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector);
    342 
    343     if (width >= 3) {
    344         // Top row.
    345         offset = cPixelSize;
    346         for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
    347             data.topRow(offset, normalVector);
    348             inlineSetPixel(offset, data, paintingData, x, 0, cFactor1div3, cFactor1div2, normalVector);
    349         }
    350         // Bottom row.
    351         offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize + cPixelSize;
    352         for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
    353             data.bottomRow(offset, normalVector);
    354             inlineSetPixel(offset, data, paintingData, x, data.heightDecreasedByOne, cFactor1div3, cFactor1div2, normalVector);
    355         }
    356     }
    357 
    358     if (height >= 3) {
    359         // Left column.
    360         offset = data.widthMultipliedByPixelSize;
    361         for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) {
    362             data.leftColumn(offset, normalVector);
    363             inlineSetPixel(offset, data, paintingData, 0, y, cFactor1div2, cFactor1div3, normalVector);
    364         }
    365         // Right column.
    366         offset = (data.widthMultipliedByPixelSize << 1) - cPixelSize;
    367         for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) {
    368             data.rightColumn(offset, normalVector);
    369             inlineSetPixel(offset, data, paintingData, data.widthDecreasedByOne, y, cFactor1div2, cFactor1div3, normalVector);
    370         }
    371     }
    372 
    373     if (width >= 3 && height >= 3) {
    374         // Interior pixels.
    375         platformApply(data, paintingData);
    376     }
    377 
    378     int lastPixel = data.widthMultipliedByPixelSize * height;
    379     if (m_lightingType == DiffuseLighting) {
    380         for (int i = cAlphaChannelOffset; i < lastPixel; i += cPixelSize)
    381             data.pixels->set(i, cOpaqueAlpha);
    382     } else {
    383         for (int i = 0; i < lastPixel; i += cPixelSize) {
    384             unsigned char a1 = data.pixels->item(i);
    385             unsigned char a2 = data.pixels->item(i + 1);
    386             unsigned char a3 = data.pixels->item(i + 2);
    387             // alpha set to set to max(a1, a2, a3)
    388             data.pixels->set(i + 3, a1 >= a2 ? (a1 >= a3 ? a1 : a3) : (a2 >= a3 ? a2 : a3));
    389         }
    390     }
    391 
    392     return true;
    393 }
    394 
    395 void FELighting::applySoftware()
    396 {
    397     FilterEffect* in = inputEffect(0);
    398 
    399     Uint8ClampedArray* srcPixelArray = createPremultipliedImageResult();
    400     if (!srcPixelArray)
    401         return;
    402 
    403     setIsAlphaImage(false);
    404 
    405     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
    406     in->copyPremultipliedImage(srcPixelArray, effectDrawingRect);
    407 
    408     // FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3
    409     // standard has no test case for them, and other browsers (like Firefox) has strange
    410     // output for various kernelUnitLengths, and I am not sure they are reliable.
    411     // Anyway, feConvolveMatrix should also use the implementation
    412 
    413     IntSize absolutePaintSize = absolutePaintRect().size();
    414     drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height());
    415 }
    416 
    417 PassRefPtr<SkImageFilter> FELighting::createImageFilter(SkiaImageFilterBuilder* builder)
    418 {
    419     RefPtr<SkImageFilter> input(builder ? builder->build(inputEffect(0), operatingColorSpace()) : 0);
    420     switch (m_lightSource->type()) {
    421     case LS_DISTANT: {
    422         DistantLightSource* distantLightSource = static_cast<DistantLightSource*>(m_lightSource.get());
    423         float azimuthRad = deg2rad(distantLightSource->azimuth());
    424         float elevationRad = deg2rad(distantLightSource->elevation());
    425         SkPoint3 direction(cosf(azimuthRad) * cosf(elevationRad),
    426                            sinf(azimuthRad) * cosf(elevationRad),
    427                            sinf(elevationRad));
    428         if (m_specularConstant > 0)
    429             return adoptRef(SkLightingImageFilter::CreateDistantLitSpecular(direction, m_lightingColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get()));
    430         else
    431             return adoptRef(SkLightingImageFilter::CreateDistantLitDiffuse(direction, m_lightingColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get()));
    432     }
    433     case LS_POINT: {
    434         PointLightSource* pointLightSource = static_cast<PointLightSource*>(m_lightSource.get());
    435         FloatPoint3D position = pointLightSource->position();
    436         SkPoint3 skPosition(position.x(), position.y(), position.z());
    437         if (m_specularConstant > 0)
    438             return adoptRef(SkLightingImageFilter::CreatePointLitSpecular(skPosition, m_lightingColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get()));
    439         else
    440             return adoptRef(SkLightingImageFilter::CreatePointLitDiffuse(skPosition, m_lightingColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get()));
    441     }
    442     case LS_SPOT: {
    443         SpotLightSource* spotLightSource = static_cast<SpotLightSource*>(m_lightSource.get());
    444         SkPoint3 location(spotLightSource->position().x(), spotLightSource->position().y(), spotLightSource->position().z());
    445         SkPoint3 target(spotLightSource->direction().x(), spotLightSource->direction().y(), spotLightSource->direction().z());
    446         float specularExponent = spotLightSource->specularExponent();
    447         float limitingConeAngle = spotLightSource->limitingConeAngle();
    448         if (!limitingConeAngle || limitingConeAngle > 90 || limitingConeAngle < -90)
    449             limitingConeAngle = 90;
    450         if (m_specularConstant > 0)
    451             return adoptRef(SkLightingImageFilter::CreateSpotLitSpecular(location, target, specularExponent, limitingConeAngle, m_lightingColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get()));
    452         else
    453             return adoptRef(SkLightingImageFilter::CreateSpotLitDiffuse(location, target, specularExponent, limitingConeAngle, m_lightingColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get()));
    454     }
    455     default:
    456         ASSERT_NOT_REACHED();
    457         return 0;
    458     }
    459 }
    460 
    461 bool FELighting::applySkia()
    462 {
    463     // For now, only use the skia implementation for accelerated rendering.
    464     if (filter()->renderingMode() != Accelerated)
    465         return false;
    466 
    467     ImageBuffer* resultImage = createImageBufferResult();
    468     if (!resultImage)
    469         return false;
    470 
    471     FilterEffect* in = inputEffect(0);
    472 
    473     IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect());
    474 
    475     setIsAlphaImage(in->isAlphaImage());
    476 
    477     RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore);
    478     RefPtr<NativeImageSkia> nativeImage = image->nativeImageForCurrentFrame();
    479     if (!nativeImage)
    480         return false;
    481 
    482     GraphicsContext* dstContext = resultImage->context();
    483 
    484     SkPaint paint;
    485     RefPtr<SkImageFilter> filter = createImageFilter(0);
    486     paint.setImageFilter(filter.get());
    487     dstContext->drawBitmap(nativeImage->bitmap(), drawingRegion.location().x(), drawingRegion.location().y(), &paint);
    488     return true;
    489 }
    490 
    491 } // namespace WebCore
    492