Add tonal color support for shadows.

Bug: skia:
Change-Id: Ib9bd9083da1d8a9fa90ae7c710386e6903541fd5
Reviewed-on: https://skia-review.googlesource.com/18148
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp
index 0f13340..f15df9f 100644
--- a/samplecode/SampleAndroidShadows.cpp
+++ b/samplecode/SampleAndroidShadows.cpp
@@ -144,6 +144,7 @@
         if (fUseAlt) {
             flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
         }
+
         SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
                                   lightPos, lightWidth,
                                   ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
diff --git a/samplecode/SampleShadowColor.cpp b/samplecode/SampleShadowColor.cpp
new file mode 100755
index 0000000..8a7e462
--- /dev/null
+++ b/samplecode/SampleShadowColor.cpp
@@ -0,0 +1,223 @@
+
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "Resources.h"
+#include "SkCanvas.h"
+#include "SkImage.h"
+#include "SkPath.h"
+#include "SkPoint3.h"
+#include "SkShadowUtils.h"
+
+////////////////////////////////////////////////////////////////////////////
+// Sample to demonstrate tonal color shadows
+
+class ShadowColorView : public SampleView {
+    SkPath    fRectPath;
+    int       fZIndex;
+
+    bool      fShowAmbient;
+    bool      fShowSpot;
+    bool      fUseAlt;
+    bool      fShowObject;
+    bool      fTwoPassColor;
+    bool      fDarkBackground;
+
+public:
+    ShadowColorView()
+        : fZIndex(8)
+        , fShowAmbient(true)
+        , fShowSpot(true)
+        , fUseAlt(false)
+        , fShowObject(true)
+        , fTwoPassColor(false)
+        , fDarkBackground(false) {}
+
+protected:
+    void onOnceBeforeDraw() override {
+        fRectPath.addRect(SkRect::MakeXYWH(-50, -50, 100, 100));
+    }
+
+    // overrides from SkEventSink
+    bool onQuery(SkEvent* evt) override {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "ShadowColor");
+            return true;
+        }
+
+        SkUnichar uni;
+        if (SampleCode::CharQ(*evt, &uni)) {
+            bool handled = false;
+            switch (uni) {
+                case 'W':
+                    fShowAmbient = !fShowAmbient;
+                    handled = true;
+                    break;
+                case 'S':
+                    fShowSpot = !fShowSpot;
+                    handled = true;
+                    break;
+                case 'T':
+                    fUseAlt = !fUseAlt;
+                    handled = true;
+                    break;
+                case 'O':
+                    fShowObject = !fShowObject;
+                    handled = true;
+                    break;
+                case 'X':
+                    fTwoPassColor = !fTwoPassColor;
+                    handled = true;
+                    break;
+                case 'Z':
+                    fDarkBackground = !fDarkBackground;
+                    handled = true;
+                    break;
+                case '>':
+                    fZIndex = SkTMin(9, fZIndex+1);
+                    handled = true;
+                    break;
+                case '<':
+                    fZIndex = SkTMax(0, fZIndex-1);
+                    handled = true;
+                    break;
+                default:
+                    break;
+            }
+            if (handled) {
+                this->inval(nullptr);
+                return true;
+            }
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
+                          const SkPoint3& zPlaneParams,
+                          const SkPaint& paint, SkScalar ambientAlpha,
+                          const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
+        if (!fShowAmbient) {
+            ambientAlpha = 0;
+        }
+        if (!fShowSpot) {
+            spotAlpha = 0;
+        }
+        uint32_t flags = 0;
+        if (fUseAlt) {
+            flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
+        }
+
+        if (fTwoPassColor) {
+            SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
+                                      lightPos, lightWidth,
+                                      ambientAlpha, 0, SK_ColorBLACK, flags);
+
+            if (paint.getColor() != SK_ColorBLACK) {
+                SkColor color = paint.getColor();
+
+                uint8_t max = SkTMax(SkTMax(SkColorGetR(color), SkColorGetG(color)),
+                                     SkColorGetB(color));
+                uint8_t min = SkTMin(SkTMin(SkColorGetR(color), SkColorGetG(color)),
+                                     SkColorGetB(color));
+                SkScalar luminance = 0.5f*(max + min) / 255.f;
+                SkScalar alpha = (.6 - .4*luminance)*luminance*luminance + 0.3f;
+                spotAlpha -= (alpha - 0.3f)*.5f;
+
+                SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
+                                          lightPos, lightWidth,
+                                          0, alpha, paint.getColor(), flags);
+            }
+
+            SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
+                                      lightPos, lightWidth,
+                                      0, spotAlpha, SK_ColorBLACK, flags);
+        } else {
+            flags |= SkShadowFlags::kTonalColor_ShadowFlag;
+            SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
+                                      lightPos, lightWidth,
+                                      ambientAlpha, spotAlpha, paint.getColor(), flags);
+        }
+        if (fShowObject) {
+            canvas->drawPath(path, paint);
+        } else {
+            SkPaint strokePaint;
+
+            strokePaint.setColor(paint.getColor());
+            strokePaint.setStyle(SkPaint::kStroke_Style);
+
+            canvas->drawPath(path, strokePaint);
+        }
+    }
+
+    void onDrawContent(SkCanvas* canvas) override {
+        const SkScalar kLightWidth = 600;
+        const SkScalar kAmbientAlpha = 0.03f;
+        const SkScalar kSpotAlpha = 0.25f;
+
+        const SkScalar kZValues[10] = { 1, 2, 3, 4, 6, 8, 9, 12, 16, 24 };
+
+        const SkColor kColors[30] = {
+            // purples
+            0xFF3A0072, 0xFF5D0099, 0xFF7F12B2, 0xFFA02AD1, 0xFFC245E5,
+            0xFFE95AF9, 0xFFFC79F0, 0xFFFDA6F0, 0xFFFFCCF8, 0xFFFFE1F9,
+            // oranges
+            0xFFEA3200, 0xFFFF4E00, 0xFFFF7300, 0xFFFF9100, 0xFFFFB000,
+            0xFFFFCE00, 0xFFFFE000, 0xFFFFF64D, 0xFFFFF98F, 0xFFFFFBCC,
+            // teals
+            0xFF004D51, 0xFF066266, 0xFF057F7F, 0xFF009999, 0xFF00B2B2,
+            0xFF15CCBE, 0xFF25E5CE, 0xFF2CFFE0, 0xFF80FFEA, 0xFFB3FFF0
+        };
+
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        if (fDarkBackground) {
+            canvas->drawColor(0xFF111111);
+            paint.setColor(SK_ColorWHITE);
+        } else {
+            canvas->drawColor(0xFFEAEAEA);
+            paint.setColor(SK_ColorBLACK);
+        }
+
+        if (fTwoPassColor) {
+            canvas->drawText("Two pass", 8, 10, 15, paint);
+        } else {
+            canvas->drawText("One pass", 8, 10, 15, paint);
+        }
+
+        SkPoint3 lightPos = { 75, -400, 600 };
+        SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, kZValues[fZIndex]);
+        SkScalar yPos = 75;
+
+        for (int row = 0; row < 3; ++row) {
+            lightPos.fX = 75;
+            SkScalar xPos = 75;
+            for (int col = 0; col < 10; ++col) {
+                paint.setColor(kColors[10*row + col]);
+
+                canvas->save();
+                canvas->translate(xPos, yPos);
+                this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, kAmbientAlpha,
+                                       lightPos, kLightWidth, kSpotAlpha);
+                canvas->restore();
+
+                lightPos.fX += 120;
+                xPos += 120;
+            }
+
+            lightPos.fY += 200;
+            yPos += 200;
+        }
+    }
+
+private:
+    typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ShadowColorView; }
+static SkViewRegister reg(MyFactory);