1 2 /* 3 * Copyright 2017 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #ifndef SkShadowUtils_DEFINED 9 #define SkShadowUtils_DEFINED 10 11 #include "SkColor.h" 12 #include "SkScalar.h" 13 #include "../private/SkShadowFlags.h" 14 #include <functional> 15 16 class SkCanvas; 17 class SkPath; 18 class SkResourceCache; 19 20 class SkShadowUtils { 21 public: 22 /** 23 * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc 24 * light. The shadow may be cached, depending on the path type and canvas matrix. If the 25 * matrix is perspective or the path is volatile, it will not be cached. 26 * 27 * @param canvas The canvas on which to draw the shadows. 28 * @param path The occluder used to generate the shadows. 29 * @param zPlaneParams Values for the plane function which returns the Z offset of the 30 * occluder from the canvas based on local x and y values (the current matrix is not applied). 31 * @param lightPos The 3D position of the light relative to the canvas plane. This is 32 * independent of the canvas's current matrix. 33 * @param lightRadius The radius of the disc light. 34 * @param ambientAlpha The maximum alpha of the ambient shadow. 35 * @param spotAlpha The maxium alpha of the spot shadow. 36 * @param color The shadow color. 37 * @param flags Options controlling opaque occluder optimizations and shadow appearance. See 38 * SkShadowFlags. 39 */ 40 static void DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams, 41 const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha, 42 SkScalar spotAlpha, SkColor color, 43 uint32_t flags = SkShadowFlags::kNone_ShadowFlag); 44 45 /** 46 * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc 47 * light. 48 * 49 * Deprecated version with height value (to be removed when Flutter is updated). 50 * 51 * @param canvas The canvas on which to draw the shadows. 52 * @param path The occluder used to generate the shadows. 53 * @param occluderHeight The vertical offset of the occluder from the canvas. This is 54 * independent of the canvas's current matrix. 55 * @param lightPos The 3D position of the light relative to the canvas plane. This is 56 * independent of the canvas's current matrix. 57 * @param lightRadius The radius of the disc light. 58 * @param ambientAlpha The maximum alpha of the ambient shadow. 59 * @param spotAlpha The maxium alpha of the spot shadow. 60 * @param color The shadow color. 61 * @param flags Options controlling opaque occluder optimizations and shadow appearance. See 62 * SkShadowFlags. 63 */ 64 static void DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight, 65 const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha, 66 SkScalar spotAlpha, SkColor color, 67 uint32_t flags = SkShadowFlags::kNone_ShadowFlag) { 68 SkPoint3 zPlane = SkPoint3::Make(0, 0, occluderHeight); 69 DrawShadow(canvas, path, zPlane, lightPos, lightRadius, ambientAlpha, spotAlpha, 70 color, flags); 71 } 72 73 /** 74 * Helper routine to compute scale alpha values for one-pass tonal alpha. 75 * 76 * The final color we want to emulate is generated by rendering a color shadow (C_rgb) using an 77 * alpha computed from the color's luminance (C_a), and then a black shadow with alpha (S_a) 78 * which is an adjusted value of 'a'. Assuming SrcOver, a background color of B_rgb, and 79 * ignoring edge falloff, this becomes 80 * 81 * (C_a - S_a*C_a)*C_rgb + (1 - (S_a + C_a - S_a*C_a))*B_rgb 82 * 83 * Since we use premultiplied alpha, this means we can scale the color by (C_a - S_a*C_a) and 84 * set the alpha to (S_a + C_a - S_a*C_a). 85 * 86 * @param r Red value of color 87 * @param g Red value of color 88 * @param b Red value of color 89 * @param a Red value of color 90 * @param colorScale Factor to scale color values by 91 * @param tonalAlpha Value to set alpha to 92 */ ComputeTonalColorParams(SkScalar r,SkScalar g,SkScalar b,SkScalar a,SkScalar * colorScale,SkScalar * tonalAlpha)93 static inline void ComputeTonalColorParams(SkScalar r, SkScalar g, SkScalar b, SkScalar a, 94 SkScalar* colorScale, SkScalar* tonalAlpha) { 95 SkScalar max = SkTMax(SkTMax(r, g), b); 96 SkScalar min = SkTMin(SkTMin(r, g), b); 97 SkScalar luminance = 0.5f*(max + min); 98 99 // We get best results with a luminance between 0.3 and 0.5, with smoothstep applied 100 SkScalar adjustedLuminance = (0.6f - 0.4f*luminance)*luminance*luminance + 0.3f; 101 // Similarly, we need to tone down the given greyscale alpha depending on how 102 // much color we're applying. 103 a -= (0.5f*adjustedLuminance - 0.15f); 104 105 *colorScale = adjustedLuminance*(SK_Scalar1 - a); 106 *tonalAlpha = *colorScale + a; 107 } 108 }; 109 110 #endif 111