1 /* 2 * Copyright 2018 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkottiePriv.h" 9 10 #include "SkJSON.h" 11 #include "SkottieJson.h" 12 #include "SkottieValue.h" 13 #include "SkSGColor.h" 14 #include "SkSGColorFilter.h" 15 16 namespace skottie { 17 namespace internal { 18 19 namespace { 20 21 sk_sp<sksg::RenderNode> AttachFillLayerEffect(const skjson::ArrayValue* jeffect_props, 22 const AnimationBuilder* abuilder, 23 AnimatorScope* ascope, 24 sk_sp<sksg::RenderNode> layer) { 25 if (!jeffect_props) return nullptr; 26 27 // Effect properties are index-based. 28 enum { 29 kFillMask_Index = 0, 30 kAllMasks_Index = 1, 31 kColor_Index = 2, 32 kInvert_Index = 3, 33 kHFeather_Index = 4, 34 kVFeather_Index = 5, 35 kOpacity_Index = 6, 36 37 kMax_Index = kOpacity_Index, 38 }; 39 40 if (jeffect_props->size() <= kMax_Index) { 41 return nullptr; 42 } 43 44 const skjson::ObjectValue* color_prop = (*jeffect_props)[ kColor_Index]; 45 const skjson::ObjectValue* opacity_prop = (*jeffect_props)[kOpacity_Index]; 46 if (!color_prop || !opacity_prop) { 47 return nullptr; 48 } 49 50 sk_sp<sksg::Color> color_node = abuilder->attachColor(*color_prop, ascope, "v"); 51 if (!color_node) { 52 return nullptr; 53 } 54 55 abuilder->bindProperty<ScalarValue>((*opacity_prop)["v"], ascope, 56 [color_node](const ScalarValue& o) { 57 const auto c = color_node->getColor(); 58 const auto a = sk_float_round2int_no_saturate(SkTPin(o, 0.0f, 1.0f) * 255); 59 color_node->setColor(SkColorSetA(c, a)); 60 }); 61 62 return sksg::ColorModeFilter::Make(std::move(layer), 63 std::move(color_node), 64 SkBlendMode::kSrcIn); 65 } 66 67 } // namespace 68 69 sk_sp<sksg::RenderNode> AnimationBuilder::attachLayerEffects(const skjson::ArrayValue& jeffects, 70 AnimatorScope* ascope, 71 sk_sp<sksg::RenderNode> layer) const { 72 for (const skjson::ObjectValue* jeffect : jeffects) { 73 if (!jeffect) continue; 74 75 switch (const auto ty = ParseDefault<int>((*jeffect)["ty"], -1)) { 76 case 21: // Fill 77 layer = AttachFillLayerEffect((*jeffect)["ef"], this, ascope, std::move(layer)); 78 break; 79 default: 80 this->log(Logger::Level::kWarning, nullptr, "Unsupported layer effect type: %d.", ty); 81 break; 82 } 83 84 if (!layer) { 85 this->log(Logger::Level::kError, jeffect, "Invalid layer effect."); 86 return nullptr; 87 } 88 } 89 90 return layer; 91 } 92 93 } // namespace internal 94 } // namespace skottie 95