[skottie] Add support for fill effect opacity

Also, it turns out layer effect properties are keyed by their
index in the property array, and not by "ty".  Update the
implementation to reflect this.


Change-Id: I72c6cf83f60ee1f8240222c7e2be2d567555a772
Reviewed-on: https://skia-review.googlesource.com/c/161840
Commit-Queue: Florin Malita <fmalita@chromium.org>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/modules/skottie/src/SkottieLayerEffect.cpp b/modules/skottie/src/SkottieLayerEffect.cpp
index e66ab7f..16aa6a7 100644
--- a/modules/skottie/src/SkottieLayerEffect.cpp
+++ b/modules/skottie/src/SkottieLayerEffect.cpp
@@ -9,6 +9,7 @@
 
 #include "SkJSON.h"
 #include "SkottieJson.h"
+#include "SkottieValue.h"
 #include "SkSGColor.h"
 #include "SkSGColorFilter.h"
 
@@ -21,27 +22,46 @@
                                               const AnimationBuilder* abuilder,
                                               AnimatorScope* ascope,
                                               sk_sp<sksg::RenderNode> layer) {
-    if (!jeffect_props) return layer;
+    if (!jeffect_props) return nullptr;
 
-    sk_sp<sksg::Color> color_node;
+    // Effect properties are index-based.
+    enum {
+        kFillMask_Index = 0,
+        kAllMasks_Index = 1,
+        kColor_Index    = 2,
+        kInvert_Index   = 3,
+        kHFeather_Index = 4,
+        kVFeather_Index = 5,
+        kOpacity_Index  = 6,
 
-    for (const skjson::ObjectValue* jprop : *jeffect_props) {
-        if (!jprop) continue;
+        kMax_Index      = kOpacity_Index,
+    };
 
-        switch (const auto ty = ParseDefault<int>((*jprop)["ty"], -1)) {
-        case 2: // color
-            color_node = abuilder->attachColor(*jprop, ascope, "v");
-            break;
-        default:
-            abuilder->log(Logger::Level::kWarning, nullptr,
-                          "Ignoring unsupported fill effect poperty type: %d.", ty);
-            break;
-        }
+    if (jeffect_props->size() <= kMax_Index) {
+        return nullptr;
     }
 
-    return color_node
-        ? sksg::ColorModeFilter::Make(std::move(layer), std::move(color_node), SkBlendMode::kSrcIn)
-        : nullptr;
+    const skjson::ObjectValue*   color_prop = (*jeffect_props)[  kColor_Index];
+    const skjson::ObjectValue* opacity_prop = (*jeffect_props)[kOpacity_Index];
+    if (!color_prop || !opacity_prop) {
+        return nullptr;
+    }
+
+    sk_sp<sksg::Color> color_node = abuilder->attachColor(*color_prop, ascope, "v");
+    if (!color_node) {
+        return nullptr;
+    }
+
+    abuilder->bindProperty<ScalarValue>((*opacity_prop)["v"], ascope,
+        [color_node](const ScalarValue& o) {
+            const auto c = color_node->getColor();
+            const auto a = sk_float_round2int_no_saturate(SkTPin(o, 0.0f, 1.0f) * 255);
+            color_node->setColor(SkColorSetA(c, a));
+        });
+
+    return sksg::ColorModeFilter::Make(std::move(layer),
+                                       std::move(color_node),
+                                       SkBlendMode::kSrcIn);
 }
 
 } // namespace
@@ -60,6 +80,11 @@
             this->log(Logger::Level::kWarning, nullptr, "Unsupported layer effect type: %d.", ty);
             break;
         }
+
+        if (!layer) {
+            this->log(Logger::Level::kError, jeffect, "Invalid layer effect.");
+            return nullptr;
+        }
     }
 
     return layer;