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