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 #include "platform/graphics/filters/FELighting.h" 30 31 #include "SkLightingImageFilter.h" 32 #include "platform/graphics/filters/DistantLightSource.h" 33 #include "platform/graphics/filters/ParallelJobs.h" 34 #include "platform/graphics/filters/SkiaImageFilterBuilder.h" 35 #include "platform/graphics/skia/NativeImageSkia.h" 36 37 namespace blink { 38 39 FELighting::FELighting(Filter* filter, LightingType lightingType, const Color& lightingColor, float surfaceScale, 40 float diffuseConstant, float specularConstant, float specularExponent, 41 float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) 42 : FilterEffect(filter) 43 , m_lightingType(lightingType) 44 , m_lightSource(lightSource) 45 , m_lightingColor(lightingColor) 46 , m_surfaceScale(surfaceScale) 47 , m_diffuseConstant(std::max(diffuseConstant, 0.0f)) 48 , m_specularConstant(std::max(specularConstant, 0.0f)) 49 , m_specularExponent(std::min(std::max(specularExponent, 1.0f), 128.0f)) 50 , m_kernelUnitLengthX(kernelUnitLengthX) 51 , m_kernelUnitLengthY(kernelUnitLengthY) 52 { 53 } 54 55 FloatRect FELighting::mapPaintRect(const FloatRect& rect, bool) 56 { 57 FloatRect result = rect; 58 // The areas affected need to be a pixel bigger to accommodate the Sobel kernel. 59 result.inflate(1); 60 return result; 61 } 62 63 const static int cPixelSize = 4; 64 const static int cAlphaChannelOffset = 3; 65 const static unsigned char cOpaqueAlpha = static_cast<unsigned char>(0xff); 66 const static float cFactor1div2 = -1 / 2.f; 67 const static float cFactor1div3 = -1 / 3.f; 68 const static float cFactor1div4 = -1 / 4.f; 69 const static float cFactor2div3 = -2 / 3.f; 70 71 // << 1 is signed multiply by 2 72 inline void FELighting::LightingData::topLeft(int offset, IntPoint& normalVector) 73 { 74 int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 75 int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 76 offset += widthMultipliedByPixelSize; 77 int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 78 int bottomRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 79 normalVector.setX(-(center << 1) + (right << 1) - bottom + bottomRight); 80 normalVector.setY(-(center << 1) - right + (bottom << 1) + bottomRight); 81 } 82 83 inline void FELighting::LightingData::topRow(int offset, IntPoint& normalVector) 84 { 85 int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 86 int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 87 int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 88 offset += widthMultipliedByPixelSize; 89 int bottomLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 90 int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 91 int bottomRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 92 normalVector.setX(-(left << 1) + (right << 1) - bottomLeft + bottomRight); 93 normalVector.setY(-left - (center << 1) - right + bottomLeft + (bottom << 1) + bottomRight); 94 } 95 96 inline void FELighting::LightingData::topRight(int offset, IntPoint& normalVector) 97 { 98 int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 99 int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 100 offset += widthMultipliedByPixelSize; 101 int bottomLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 102 int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 103 normalVector.setX(-(left << 1) + (center << 1) - bottomLeft + bottom); 104 normalVector.setY(-left - (center << 1) + bottomLeft + (bottom << 1)); 105 } 106 107 inline void FELighting::LightingData::leftColumn(int offset, IntPoint& normalVector) 108 { 109 int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 110 int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 111 offset -= widthMultipliedByPixelSize; 112 int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 113 int topRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 114 offset += widthMultipliedByPixelSize << 1; 115 int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 116 int bottomRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 117 normalVector.setX(-top + topRight - (center << 1) + (right << 1) - bottom + bottomRight); 118 normalVector.setY(-(top << 1) - topRight + (bottom << 1) + bottomRight); 119 } 120 121 inline void FELighting::LightingData::interior(int offset, IntPoint& normalVector) 122 { 123 int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 124 int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 125 offset -= widthMultipliedByPixelSize; 126 int topLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 127 int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 128 int topRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 129 offset += widthMultipliedByPixelSize << 1; 130 int bottomLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 131 int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 132 int bottomRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 133 normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1) - bottomLeft + bottomRight); 134 normalVector.setY(-topLeft - (top << 1) - topRight + bottomLeft + (bottom << 1) + bottomRight); 135 } 136 137 inline void FELighting::LightingData::rightColumn(int offset, IntPoint& normalVector) 138 { 139 int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 140 int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 141 offset -= widthMultipliedByPixelSize; 142 int topLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 143 int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 144 offset += widthMultipliedByPixelSize << 1; 145 int bottomLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 146 int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 147 normalVector.setX(-topLeft + top - (left << 1) + (center << 1) - bottomLeft + bottom); 148 normalVector.setY(-topLeft - (top << 1) + bottomLeft + (bottom << 1)); 149 } 150 151 inline void FELighting::LightingData::bottomLeft(int offset, IntPoint& normalVector) 152 { 153 int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 154 int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 155 offset -= widthMultipliedByPixelSize; 156 int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 157 int topRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 158 normalVector.setX(-top + topRight - (center << 1) + (right << 1)); 159 normalVector.setY(-(top << 1) - topRight + (center << 1) + right); 160 } 161 162 inline void FELighting::LightingData::bottomRow(int offset, IntPoint& normalVector) 163 { 164 int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 165 int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 166 int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 167 offset -= widthMultipliedByPixelSize; 168 int topLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 169 int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 170 int topRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset)); 171 normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1)); 172 normalVector.setY(-topLeft - (top << 1) - topRight + left + (center << 1) + right); 173 } 174 175 inline void FELighting::LightingData::bottomRight(int offset, IntPoint& normalVector) 176 { 177 int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 178 int center = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 179 offset -= widthMultipliedByPixelSize; 180 int topLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset)); 181 int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset)); 182 normalVector.setX(-topLeft + top - (left << 1) + (center << 1)); 183 normalVector.setY(-topLeft - (top << 1) + left + (center << 1)); 184 } 185 186 inline void FELighting::inlineSetPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData, 187 int lightX, int lightY, float factorX, float factorY, IntPoint& normal2DVector) 188 { 189 data.lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->item(offset + cAlphaChannelOffset)) * data.surfaceScale); 190 191 float lightStrength; 192 if (!normal2DVector.x() && !normal2DVector.y()) { 193 // Normal vector is (0, 0, 1). This is a quite frequent case. 194 if (m_lightingType == FELighting::DiffuseLighting) { 195 lightStrength = m_diffuseConstant * paintingData.lightVector.z() / paintingData.lightVectorLength; 196 } else { 197 FloatPoint3D halfwayVector = paintingData.lightVector; 198 halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength); 199 float halfwayVectorLength = halfwayVector.length(); 200 if (m_specularExponent == 1) 201 lightStrength = m_specularConstant * halfwayVector.z() / halfwayVectorLength; 202 else 203 lightStrength = m_specularConstant * powf(halfwayVector.z() / halfwayVectorLength, m_specularExponent); 204 } 205 } else { 206 FloatPoint3D normalVector; 207 normalVector.setX(factorX * static_cast<float>(normal2DVector.x()) * data.surfaceScale); 208 normalVector.setY(factorY * static_cast<float>(normal2DVector.y()) * data.surfaceScale); 209 normalVector.setZ(1); 210 float normalVectorLength = normalVector.length(); 211 212 if (m_lightingType == FELighting::DiffuseLighting) { 213 lightStrength = m_diffuseConstant * (normalVector * paintingData.lightVector) / (normalVectorLength * paintingData.lightVectorLength); 214 } else { 215 FloatPoint3D halfwayVector = paintingData.lightVector; 216 halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength); 217 float halfwayVectorLength = halfwayVector.length(); 218 if (m_specularExponent == 1) 219 lightStrength = m_specularConstant * (normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength); 220 else 221 lightStrength = m_specularConstant * powf((normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength), m_specularExponent); 222 } 223 } 224 225 if (lightStrength > 1) 226 lightStrength = 1; 227 if (lightStrength < 0) 228 lightStrength = 0; 229 230 data.pixels->set(offset, static_cast<unsigned char>(lightStrength * paintingData.colorVector.x())); 231 data.pixels->set(offset + 1, static_cast<unsigned char>(lightStrength * paintingData.colorVector.y())); 232 data.pixels->set(offset + 2, static_cast<unsigned char>(lightStrength * paintingData.colorVector.z())); 233 } 234 235 void FELighting::setPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData, 236 int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector) 237 { 238 inlineSetPixel(offset, data, paintingData, lightX, lightY, factorX, factorY, normalVector); 239 } 240 241 inline void FELighting::platformApplyGenericPaint(LightingData& data, LightSource::PaintingData& paintingData, int startY, int endY) 242 { 243 IntPoint normalVector; 244 int offset = 0; 245 246 for (int y = startY; y < endY; ++y) { 247 offset = y * data.widthMultipliedByPixelSize + cPixelSize; 248 for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) { 249 data.interior(offset, normalVector); 250 inlineSetPixel(offset, data, paintingData, x, y, cFactor1div4, cFactor1div4, normalVector); 251 } 252 } 253 } 254 255 void FELighting::platformApplyGenericWorker(PlatformApplyGenericParameters* parameters) 256 { 257 parameters->filter->platformApplyGenericPaint(parameters->data, parameters->paintingData, parameters->yStart, parameters->yEnd); 258 } 259 260 inline void FELighting::platformApplyGeneric(LightingData& data, LightSource::PaintingData& paintingData) 261 { 262 int optimalThreadNumber = ((data.widthDecreasedByOne - 1) * (data.heightDecreasedByOne - 1)) / s_minimalRectDimension; 263 if (optimalThreadNumber > 1) { 264 // Initialize parallel jobs 265 ParallelJobs<PlatformApplyGenericParameters> parallelJobs(&platformApplyGenericWorker, optimalThreadNumber); 266 267 // Fill the parameter array 268 int job = parallelJobs.numberOfJobs(); 269 if (job > 1) { 270 // Split the job into "yStep"-sized jobs but there a few jobs that need to be slightly larger since 271 // yStep * jobs < total size. These extras are handled by the remainder "jobsWithExtra". 272 const int yStep = (data.heightDecreasedByOne - 1) / job; 273 const int jobsWithExtra = (data.heightDecreasedByOne - 1) % job; 274 275 int yStart = 1; 276 for (--job; job >= 0; --job) { 277 PlatformApplyGenericParameters& params = parallelJobs.parameter(job); 278 params.filter = this; 279 params.data = data; 280 params.paintingData = paintingData; 281 params.yStart = yStart; 282 yStart += job < jobsWithExtra ? yStep + 1 : yStep; 283 params.yEnd = yStart; 284 } 285 parallelJobs.execute(); 286 return; 287 } 288 // Fallback to single threaded mode. 289 } 290 291 platformApplyGenericPaint(data, paintingData, 1, data.heightDecreasedByOne); 292 } 293 294 inline void FELighting::platformApply(LightingData& data, LightSource::PaintingData& paintingData) 295 { 296 platformApplyGeneric(data, paintingData); 297 } 298 299 void FELighting::getTransform(FloatPoint3D* scale, FloatSize* offset) const 300 { 301 FloatRect initialEffectRect = effectBoundaries(); 302 FloatRect absoluteEffectRect = filter()->mapLocalRectToAbsoluteRect(initialEffectRect); 303 FloatPoint absoluteLocation(absolutePaintRect().location()); 304 FloatSize positionOffset(absoluteLocation - absoluteEffectRect.location()); 305 offset->setWidth(positionOffset.width()); 306 offset->setHeight(positionOffset.height()); 307 scale->setX(initialEffectRect.width() > 0.0f && initialEffectRect.width() > 0.0f ? absoluteEffectRect.width() / initialEffectRect.width() : 1.0f); 308 scale->setY(initialEffectRect.height() > 0.0f && initialEffectRect.height() > 0.0f ? absoluteEffectRect.height() / initialEffectRect.height() : 1.0f); 309 // X and Y scale should be the same, but, if not, do a best effort by averaging the 2 for Z scale 310 scale->setZ(0.5f * (scale->x() + scale->y())); 311 } 312 313 bool FELighting::drawLighting(Uint8ClampedArray* pixels, int width, int height) 314 { 315 LightSource::PaintingData paintingData; 316 LightingData data; 317 318 if (!m_lightSource) 319 return false; 320 321 // FIXME: do something if width or height (or both) is 1 pixel. 322 // The W3 spec does not define this case. Now the filter just returns. 323 if (width <= 2 || height <= 2) 324 return false; 325 326 data.pixels = pixels; 327 data.surfaceScale = m_surfaceScale / 255.0f; 328 data.widthMultipliedByPixelSize = width * cPixelSize; 329 data.widthDecreasedByOne = width - 1; 330 data.heightDecreasedByOne = height - 1; 331 FloatPoint3D worldScale; 332 FloatSize originOffset; 333 getTransform(&worldScale, &originOffset); 334 RefPtr<LightSource> lightSource = m_lightSource->create(worldScale, originOffset); 335 data.lightSource = lightSource.get(); 336 Color lightColor = adaptColorToOperatingColorSpace(m_lightingColor); 337 paintingData.colorVector = FloatPoint3D(lightColor.red(), lightColor.green(), lightColor.blue()); 338 data.lightSource->initPaintingData(paintingData); 339 340 // Top/Left corner. 341 IntPoint normalVector; 342 int offset = 0; 343 data.topLeft(offset, normalVector); 344 setPixel(offset, data, paintingData, 0, 0, cFactor2div3, cFactor2div3, normalVector); 345 346 // Top/Right pixel. 347 offset = data.widthMultipliedByPixelSize - cPixelSize; 348 data.topRight(offset, normalVector); 349 setPixel(offset, data, paintingData, data.widthDecreasedByOne, 0, cFactor2div3, cFactor2div3, normalVector); 350 351 // Bottom/Left pixel. 352 offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize; 353 data.bottomLeft(offset, normalVector); 354 setPixel(offset, data, paintingData, 0, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector); 355 356 // Bottom/Right pixel. 357 offset = height * data.widthMultipliedByPixelSize - cPixelSize; 358 data.bottomRight(offset, normalVector); 359 setPixel(offset, data, paintingData, data.widthDecreasedByOne, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector); 360 361 if (width >= 3) { 362 // Top row. 363 offset = cPixelSize; 364 for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) { 365 data.topRow(offset, normalVector); 366 inlineSetPixel(offset, data, paintingData, x, 0, cFactor1div3, cFactor1div2, normalVector); 367 } 368 // Bottom row. 369 offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize + cPixelSize; 370 for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) { 371 data.bottomRow(offset, normalVector); 372 inlineSetPixel(offset, data, paintingData, x, data.heightDecreasedByOne, cFactor1div3, cFactor1div2, normalVector); 373 } 374 } 375 376 if (height >= 3) { 377 // Left column. 378 offset = data.widthMultipliedByPixelSize; 379 for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) { 380 data.leftColumn(offset, normalVector); 381 inlineSetPixel(offset, data, paintingData, 0, y, cFactor1div2, cFactor1div3, normalVector); 382 } 383 // Right column. 384 offset = (data.widthMultipliedByPixelSize << 1) - cPixelSize; 385 for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) { 386 data.rightColumn(offset, normalVector); 387 inlineSetPixel(offset, data, paintingData, data.widthDecreasedByOne, y, cFactor1div2, cFactor1div3, normalVector); 388 } 389 } 390 391 if (width >= 3 && height >= 3) { 392 // Interior pixels. 393 platformApply(data, paintingData); 394 } 395 396 int lastPixel = data.widthMultipliedByPixelSize * height; 397 if (m_lightingType == DiffuseLighting) { 398 for (int i = cAlphaChannelOffset; i < lastPixel; i += cPixelSize) 399 data.pixels->set(i, cOpaqueAlpha); 400 } else { 401 for (int i = 0; i < lastPixel; i += cPixelSize) { 402 unsigned char a1 = data.pixels->item(i); 403 unsigned char a2 = data.pixels->item(i + 1); 404 unsigned char a3 = data.pixels->item(i + 2); 405 // alpha set to set to max(a1, a2, a3) 406 data.pixels->set(i + 3, a1 >= a2 ? (a1 >= a3 ? a1 : a3) : (a2 >= a3 ? a2 : a3)); 407 } 408 } 409 410 return true; 411 } 412 413 void FELighting::applySoftware() 414 { 415 FilterEffect* in = inputEffect(0); 416 417 Uint8ClampedArray* srcPixelArray = createPremultipliedImageResult(); 418 if (!srcPixelArray) 419 return; 420 421 setIsAlphaImage(false); 422 423 IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); 424 in->copyPremultipliedImage(srcPixelArray, effectDrawingRect); 425 426 // FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3 427 // standard has no test case for them, and other browsers (like Firefox) has strange 428 // output for various kernelUnitLengths, and I am not sure they are reliable. 429 // Anyway, feConvolveMatrix should also use the implementation 430 431 IntSize absolutePaintSize = absolutePaintRect().size(); 432 drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height()); 433 } 434 435 PassRefPtr<SkImageFilter> FELighting::createImageFilter(SkiaImageFilterBuilder* builder) 436 { 437 SkImageFilter::CropRect rect = getCropRect(builder ? builder->cropOffset() : FloatSize()); 438 Color lightColor = adaptColorToOperatingColorSpace(m_lightingColor); 439 RefPtr<SkImageFilter> input(builder ? builder->build(inputEffect(0), operatingColorSpace()) : nullptr); 440 switch (m_lightSource->type()) { 441 case LS_DISTANT: { 442 DistantLightSource* distantLightSource = static_cast<DistantLightSource*>(m_lightSource.get()); 443 float azimuthRad = deg2rad(distantLightSource->azimuth()); 444 float elevationRad = deg2rad(distantLightSource->elevation()); 445 SkPoint3 direction(cosf(azimuthRad) * cosf(elevationRad), 446 sinf(azimuthRad) * cosf(elevationRad), 447 sinf(elevationRad)); 448 if (m_specularConstant > 0) 449 return adoptRef(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect)); 450 return adoptRef(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect)); 451 } 452 case LS_POINT: { 453 PointLightSource* pointLightSource = static_cast<PointLightSource*>(m_lightSource.get()); 454 FloatPoint3D position = pointLightSource->position(); 455 SkPoint3 skPosition(position.x(), position.y(), position.z()); 456 if (m_specularConstant > 0) 457 return adoptRef(SkLightingImageFilter::CreatePointLitSpecular(skPosition, lightColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect)); 458 return adoptRef(SkLightingImageFilter::CreatePointLitDiffuse(skPosition, lightColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect)); 459 } 460 case LS_SPOT: { 461 SpotLightSource* spotLightSource = static_cast<SpotLightSource*>(m_lightSource.get()); 462 SkPoint3 location(spotLightSource->position().x(), spotLightSource->position().y(), spotLightSource->position().z()); 463 SkPoint3 target(spotLightSource->direction().x(), spotLightSource->direction().y(), spotLightSource->direction().z()); 464 float specularExponent = spotLightSource->specularExponent(); 465 float limitingConeAngle = spotLightSource->limitingConeAngle(); 466 if (!limitingConeAngle || limitingConeAngle > 90 || limitingConeAngle < -90) 467 limitingConeAngle = 90; 468 if (m_specularConstant > 0) 469 return adoptRef(SkLightingImageFilter::CreateSpotLitSpecular(location, target, specularExponent, limitingConeAngle, lightColor.rgb(), m_surfaceScale, m_specularConstant, m_specularExponent, input.get(), &rect)); 470 return adoptRef(SkLightingImageFilter::CreateSpotLitDiffuse(location, target, specularExponent, limitingConeAngle, lightColor.rgb(), m_surfaceScale, m_diffuseConstant, input.get(), &rect)); 471 } 472 default: 473 ASSERT_NOT_REACHED(); 474 return nullptr; 475 } 476 } 477 478 } // namespace blink 479