1/*
2 * Copyright (C) 2010 University of Szeged
3 * Copyright (C) 2010 Zoltan Herczeg
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28
29#if ENABLE(FILTERS)
30#include "FELighting.h"
31
32#include "LightSource.h"
33#include "PointLightSource.h"
34#include "SpotLightSource.h"
35
36#if CPU(ARM_NEON) && COMPILER(GCC)
37#include "FELightingNEON.h"
38#include <wtf/Vector.h>
39#endif
40
41namespace WebCore {
42
43FELighting::FELighting(Filter* filter, LightingType lightingType, const Color& lightingColor, float surfaceScale,
44    float diffuseConstant, float specularConstant, float specularExponent,
45    float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource)
46    : FilterEffect(filter)
47    , m_lightingType(lightingType)
48    , m_lightSource(lightSource)
49    , m_lightingColor(lightingColor)
50    , m_surfaceScale(surfaceScale)
51    , m_diffuseConstant(diffuseConstant)
52    , m_specularConstant(specularConstant)
53    , m_specularExponent(specularExponent)
54    , m_kernelUnitLengthX(kernelUnitLengthX)
55    , m_kernelUnitLengthY(kernelUnitLengthY)
56{
57}
58
59const static int cPixelSize = 4;
60const static int cAlphaChannelOffset = 3;
61const static unsigned char cOpaqueAlpha = static_cast<unsigned char>(0xff);
62const static float cFactor1div2 = -1 / 2.f;
63const static float cFactor1div3 = -1 / 3.f;
64const static float cFactor1div4 = -1 / 4.f;
65const static float cFactor2div3 = -2 / 3.f;
66
67// << 1 is signed multiply by 2
68inline void FELighting::LightingData::topLeft(int offset, IntPoint& normalVector)
69{
70    int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
71    int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
72    offset += widthMultipliedByPixelSize;
73    int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
74    int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
75    normalVector.setX(-(center << 1) + (right << 1) - bottom + bottomRight);
76    normalVector.setY(-(center << 1) - right + (bottom << 1) + bottomRight);
77}
78
79inline void FELighting::LightingData::topRow(int offset, IntPoint& normalVector)
80{
81    int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
82    int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
83    int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
84    offset += widthMultipliedByPixelSize;
85    int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
86    int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
87    int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
88    normalVector.setX(-(left << 1) + (right << 1) - bottomLeft + bottomRight);
89    normalVector.setY(-left - (center << 1) - right + bottomLeft + (bottom << 1) + bottomRight);
90}
91
92inline void FELighting::LightingData::topRight(int offset, IntPoint& normalVector)
93{
94    int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
95    int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
96    offset += widthMultipliedByPixelSize;
97    int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
98    int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
99    normalVector.setX(-(left << 1) + (center << 1) - bottomLeft + bottom);
100    normalVector.setY(-left - (center << 1) + bottomLeft + (bottom << 1));
101}
102
103inline void FELighting::LightingData::leftColumn(int offset, IntPoint& normalVector)
104{
105    int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
106    int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
107    offset -= widthMultipliedByPixelSize;
108    int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
109    int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
110    offset += widthMultipliedByPixelSize << 1;
111    int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
112    int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
113    normalVector.setX(-top + topRight - (center << 1) + (right << 1) - bottom + bottomRight);
114    normalVector.setY(-(top << 1) - topRight + (bottom << 1) + bottomRight);
115}
116
117inline void FELighting::LightingData::interior(int offset, IntPoint& normalVector)
118{
119    int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
120    int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
121    offset -= widthMultipliedByPixelSize;
122    int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
123    int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
124    int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
125    offset += widthMultipliedByPixelSize << 1;
126    int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
127    int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
128    int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
129    normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1) - bottomLeft + bottomRight);
130    normalVector.setY(-topLeft - (top << 1) - topRight + bottomLeft + (bottom << 1) + bottomRight);
131}
132
133inline void FELighting::LightingData::rightColumn(int offset, IntPoint& normalVector)
134{
135    int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
136    int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
137    offset -= widthMultipliedByPixelSize;
138    int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
139    int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
140    offset += widthMultipliedByPixelSize << 1;
141    int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
142    int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
143    normalVector.setX(-topLeft + top - (left << 1) + (center << 1) - bottomLeft + bottom);
144    normalVector.setY(-topLeft - (top << 1) + bottomLeft + (bottom << 1));
145}
146
147inline void FELighting::LightingData::bottomLeft(int offset, IntPoint& normalVector)
148{
149    int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
150    int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
151    offset -= widthMultipliedByPixelSize;
152    int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
153    int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
154    normalVector.setX(-top + topRight - (center << 1) + (right << 1));
155    normalVector.setY(-(top << 1) - topRight + (center << 1) + right);
156}
157
158inline void FELighting::LightingData::bottomRow(int offset, IntPoint& normalVector)
159{
160    int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
161    int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
162    int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
163    offset -= widthMultipliedByPixelSize;
164    int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
165    int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
166    int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset));
167    normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1));
168    normalVector.setY(-topLeft - (top << 1) - topRight + left + (center << 1) + right);
169}
170
171inline void FELighting::LightingData::bottomRight(int offset, IntPoint& normalVector)
172{
173    int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
174    int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
175    offset -= widthMultipliedByPixelSize;
176    int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset));
177    int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset));
178    normalVector.setX(-topLeft + top - (left << 1) + (center << 1));
179    normalVector.setY(-topLeft - (top << 1) + left + (center << 1));
180}
181
182inline void FELighting::inlineSetPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData,
183                                       int lightX, int lightY, float factorX, float factorY, IntPoint& normal2DVector)
184{
185    m_lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->get(offset + cAlphaChannelOffset)) * data.surfaceScale);
186
187    float lightStrength;
188    if (!normal2DVector.x() && !normal2DVector.y()) {
189        // Normal vector is (0, 0, 1). This is a quite frequent case.
190        if (m_lightingType == FELighting::DiffuseLighting)
191            lightStrength = m_diffuseConstant * paintingData.lightVector.z() / paintingData.lightVectorLength;
192        else {
193            FloatPoint3D halfwayVector = paintingData.lightVector;
194            halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength);
195            float halfwayVectorLength = halfwayVector.length();
196            if (m_specularExponent == 1)
197                lightStrength = m_specularConstant * halfwayVector.z() / halfwayVectorLength;
198            else
199                lightStrength = m_specularConstant * powf(halfwayVector.z() / halfwayVectorLength, m_specularExponent);
200        }
201    } else {
202        FloatPoint3D normalVector;
203        normalVector.setX(factorX * static_cast<float>(normal2DVector.x()) * data.surfaceScale);
204        normalVector.setY(factorY * static_cast<float>(normal2DVector.y()) * data.surfaceScale);
205        normalVector.setZ(1);
206        float normalVectorLength = normalVector.length();
207
208        if (m_lightingType == FELighting::DiffuseLighting)
209            lightStrength = m_diffuseConstant * (normalVector * paintingData.lightVector) / (normalVectorLength * paintingData.lightVectorLength);
210        else {
211            FloatPoint3D halfwayVector = paintingData.lightVector;
212            halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength);
213            float halfwayVectorLength = halfwayVector.length();
214            if (m_specularExponent == 1)
215                lightStrength = m_specularConstant * (normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength);
216            else
217                lightStrength = m_specularConstant * powf((normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength), m_specularExponent);
218        }
219    }
220
221    if (lightStrength > 1)
222        lightStrength = 1;
223    if (lightStrength < 0)
224        lightStrength = 0;
225
226    data.pixels->set(offset, static_cast<unsigned char>(lightStrength * paintingData.colorVector.x()));
227    data.pixels->set(offset + 1, static_cast<unsigned char>(lightStrength * paintingData.colorVector.y()));
228    data.pixels->set(offset + 2, static_cast<unsigned char>(lightStrength * paintingData.colorVector.z()));
229}
230
231void FELighting::setPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData,
232                          int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector)
233{
234    inlineSetPixel(offset, data, paintingData, lightX, lightY, factorX, factorY, normalVector);
235}
236
237bool FELighting::drawLighting(ByteArray* pixels, int width, int height)
238{
239    LightSource::PaintingData paintingData;
240    LightingData data;
241
242    if (!m_lightSource)
243        return false;
244
245    // FIXME: do something if width or height (or both) is 1 pixel.
246    // The W3 spec does not define this case. Now the filter just returns.
247    if (width <= 2 || height <= 2)
248        return false;
249
250    data.pixels = pixels;
251    data.surfaceScale = m_surfaceScale / 255.0f;
252    data.widthMultipliedByPixelSize = width * cPixelSize;
253    data.widthDecreasedByOne = width - 1;
254    data.heightDecreasedByOne = height - 1;
255    paintingData.colorVector = FloatPoint3D(m_lightingColor.red(), m_lightingColor.green(), m_lightingColor.blue());
256    m_lightSource->initPaintingData(paintingData);
257
258    // Top/Left corner
259    IntPoint normalVector;
260    int offset = 0;
261    data.topLeft(offset, normalVector);
262    setPixel(offset, data, paintingData, 0, 0, cFactor2div3, cFactor2div3, normalVector);
263
264    // Top/Right pixel
265    offset = data.widthMultipliedByPixelSize - cPixelSize;
266    data.topRight(offset, normalVector);
267    setPixel(offset, data, paintingData, data.widthDecreasedByOne, 0, cFactor2div3, cFactor2div3, normalVector);
268
269    // Bottom/Left pixel
270    offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize;
271    data.bottomLeft(offset, normalVector);
272    setPixel(offset, data, paintingData, 0, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector);
273
274    // Bottom/Right pixel
275    offset = height * data.widthMultipliedByPixelSize - cPixelSize;
276    data.bottomRight(offset, normalVector);
277    setPixel(offset, data, paintingData, data.widthDecreasedByOne, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector);
278
279    if (width >= 3) {
280        // Top row
281        offset = cPixelSize;
282        for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
283            data.topRow(offset, normalVector);
284            inlineSetPixel(offset, data, paintingData, x, 0, cFactor1div3, cFactor1div2, normalVector);
285        }
286        // Bottom row
287        offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize + cPixelSize;
288        for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
289            data.bottomRow(offset, normalVector);
290            inlineSetPixel(offset, data, paintingData, x, data.heightDecreasedByOne, cFactor1div3, cFactor1div2, normalVector);
291        }
292    }
293
294    if (height >= 3) {
295        // Left column
296        offset = data.widthMultipliedByPixelSize;
297        for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) {
298            data.leftColumn(offset, normalVector);
299            inlineSetPixel(offset, data, paintingData, 0, y, cFactor1div2, cFactor1div3, normalVector);
300        }
301        // Right column
302        offset = (data.widthMultipliedByPixelSize << 1) - cPixelSize;
303        for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) {
304            data.rightColumn(offset, normalVector);
305            inlineSetPixel(offset, data, paintingData, data.widthDecreasedByOne, y, cFactor1div2, cFactor1div3, normalVector);
306        }
307    }
308
309    if (width >= 3 && height >= 3) {
310        // Interior pixels
311#if CPU(ARM_NEON) && COMPILER(GCC)
312        drawInteriorPixels(data, paintingData);
313#else
314        for (int y = 1; y < data.heightDecreasedByOne; ++y) {
315            offset = y * data.widthMultipliedByPixelSize + cPixelSize;
316            for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
317                data.interior(offset, normalVector);
318                inlineSetPixel(offset, data, paintingData, x, y, cFactor1div4, cFactor1div4, normalVector);
319            }
320        }
321#endif
322    }
323
324    int lastPixel = data.widthMultipliedByPixelSize * height;
325    if (m_lightingType == DiffuseLighting) {
326        for (int i = cAlphaChannelOffset; i < lastPixel; i += cPixelSize)
327            data.pixels->set(i, cOpaqueAlpha);
328    } else {
329        for (int i = 0; i < lastPixel; i += cPixelSize) {
330            unsigned char a1 = data.pixels->get(i);
331            unsigned char a2 = data.pixels->get(i + 1);
332            unsigned char a3 = data.pixels->get(i + 2);
333            // alpha set to set to max(a1, a2, a3)
334            data.pixels->set(i + 3, a1 >= a2 ? (a1 >= a3 ? a1 : a3) : (a2 >= a3 ? a2 : a3));
335        }
336    }
337
338    return true;
339}
340
341void FELighting::apply()
342{
343    if (hasResult())
344        return;
345    FilterEffect* in = inputEffect(0);
346    in->apply();
347    if (!in->hasResult())
348        return;
349
350    ByteArray* srcPixelArray = createUnmultipliedImageResult();
351    if (!srcPixelArray)
352        return;
353
354    setIsAlphaImage(false);
355
356    IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
357    in->copyUnmultipliedImage(srcPixelArray, effectDrawingRect);
358
359    // FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3
360    // standard has no test case for them, and other browsers (like Firefox) has strange
361    // output for various kernelUnitLengths, and I am not sure they are reliable.
362    // Anyway, feConvolveMatrix should also use the implementation
363
364    IntSize absolutePaintSize = absolutePaintRect().size();
365    drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height());
366}
367
368#if CPU(ARM_NEON) && COMPILER(GCC)
369
370static int getPowerCoefficients(float exponent)
371{
372    // Calling a powf function from the assembly code would require to save
373    // and reload a lot of NEON registers. Since the base is in range [0..1]
374    // and only 8 bit precision is required, we use our own powf function.
375    // This is probably not the best, but it uses only a few registers and
376    // gives us enough precision (modifying the exponent field directly would
377    // also be possible).
378
379    // First, we limit the exponent to maximum of 64, which gives us enough
380    // precision. We split the exponent to an integer and fraction part,
381    // since a^x = (a^y)*(a^z) where x = y+z. The integer exponent of the
382    // power is estimated by square, and the fraction exponent of the power
383    // is estimated by square root assembly instructions.
384    int i, result;
385
386    if (exponent < 0)
387        exponent = 1 / (-exponent);
388
389    if (exponent > 63.99)
390        exponent = 63.99;
391
392    exponent /= 64;
393    result = 0;
394    for (i = 11; i >= 0; --i) {
395        exponent *= 2;
396        if (exponent >= 1) {
397            result |= 1 << i;
398            exponent -= 1;
399        }
400    }
401    return result;
402}
403
404void FELighting::drawInteriorPixels(LightingData& data, LightSource::PaintingData& paintingData)
405{
406    WTF_ALIGNED(FELightingFloatArgumentsForNeon, floatArguments, 16);
407
408    FELightingPaintingDataForNeon neonData = {
409        data.pixels->data(),
410        data.widthDecreasedByOne - 1,
411        data.heightDecreasedByOne - 1,
412        0,
413        0,
414        0,
415        &floatArguments,
416        feLightingConstantsForNeon()
417    };
418
419    // Set light source arguments.
420    floatArguments.constOne = 1;
421
422    floatArguments.colorRed = m_lightingColor.red();
423    floatArguments.colorGreen = m_lightingColor.green();
424    floatArguments.colorBlue = m_lightingColor.blue();
425    floatArguments.padding4 = 0;
426
427    if (m_lightSource->type() == LS_POINT) {
428        neonData.flags |= FLAG_POINT_LIGHT;
429        PointLightSource* pointLightSource = static_cast<PointLightSource*>(m_lightSource.get());
430        floatArguments.lightX = pointLightSource->position().x();
431        floatArguments.lightY = pointLightSource->position().y();
432        floatArguments.lightZ = pointLightSource->position().z();
433        floatArguments.padding2 = 0;
434    } else if (m_lightSource->type() == LS_SPOT) {
435        neonData.flags |= FLAG_SPOT_LIGHT;
436        SpotLightSource* spotLightSource = static_cast<SpotLightSource*>(m_lightSource.get());
437        floatArguments.lightX = spotLightSource->position().x();
438        floatArguments.lightY = spotLightSource->position().y();
439        floatArguments.lightZ = spotLightSource->position().z();
440        floatArguments.padding2 = 0;
441
442        floatArguments.directionX = paintingData.directionVector.x();
443        floatArguments.directionY = paintingData.directionVector.y();
444        floatArguments.directionZ = paintingData.directionVector.z();
445        floatArguments.padding3 = 0;
446
447        floatArguments.coneCutOffLimit = paintingData.coneCutOffLimit;
448        floatArguments.coneFullLight = paintingData.coneFullLight;
449        floatArguments.coneCutOffRange = paintingData.coneCutOffLimit - paintingData.coneFullLight;
450        neonData.coneExponent = getPowerCoefficients(spotLightSource->specularExponent());
451        if (spotLightSource->specularExponent() == 1)
452            neonData.flags |= FLAG_CONE_EXPONENT_IS_1;
453    } else {
454        ASSERT(m_lightSource.type == LS_DISTANT);
455        floatArguments.lightX = paintingData.lightVector.x();
456        floatArguments.lightY = paintingData.lightVector.y();
457        floatArguments.lightZ = paintingData.lightVector.z();
458        floatArguments.padding2 = 1;
459    }
460
461    // Set lighting arguments.
462    floatArguments.surfaceScale = data.surfaceScale;
463    floatArguments.minusSurfaceScaleDividedByFour = -data.surfaceScale / 4;
464    if (m_lightingType == FELighting::DiffuseLighting)
465        floatArguments.diffuseConstant = m_diffuseConstant;
466    else {
467        neonData.flags |= FLAG_SPECULAR_LIGHT;
468        floatArguments.diffuseConstant = m_specularConstant;
469        neonData.specularExponent = getPowerCoefficients(m_specularExponent);
470        if (m_specularExponent == 1)
471            neonData.flags |= FLAG_SPECULAR_EXPONENT_IS_1;
472    }
473    if (floatArguments.diffuseConstant == 1)
474        neonData.flags |= FLAG_DIFFUSE_CONST_IS_1;
475
476    neonDrawLighting(&neonData);
477}
478#endif // CPU(ARM_NEON) && COMPILER(GCC)
479
480} // namespace WebCore
481
482#endif // ENABLE(FILTERS)
483