blob: c3704f7599c93cc743a7a8c589975348f63991b4 [file] [log] [blame]
/*
* Copyright 2019 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "modules/skottie/src/effects/Effects.h"
#include "modules/skottie/src/SkottieJson.h"
#include "modules/sksg/include/SkSGRenderEffect.h"
#include "src/utils/SkJSON.h"
namespace skottie {
namespace internal {
EffectBuilder::EffectBuilder(const AnimationBuilder* abuilder, const SkSize& layer_size)
: fBuilder(abuilder)
, fLayerSize(layer_size) {}
EffectBuilder::EffectBuilderT EffectBuilder::findBuilder(const skjson::ObjectValue& jeffect) const {
// First, try assigned types.
enum : int32_t {
kTint_Effect = 20,
kFill_Effect = 21,
kTritone_Effect = 23,
kDropShadow_Effect = 25,
kRadialWipe_Effect = 26,
kGaussianBlur_Effect = 29,
};
const auto ty = ParseDefault<int>(jeffect["ty"], -1);
switch (ty) {
case kTint_Effect:
return &EffectBuilder::attachTintEffect;
case kFill_Effect:
return &EffectBuilder::attachFillEffect;
case kTritone_Effect:
return &EffectBuilder::attachTritoneEffect;
case kDropShadow_Effect:
return &EffectBuilder::attachDropShadowEffect;
case kRadialWipe_Effect:
return &EffectBuilder::attachRadialWipeEffect;
case kGaussianBlur_Effect:
return &EffectBuilder::attachGaussianBlurEffect;
default:
break;
}
// Some effects don't have an assigned type, but the data is still present.
// Try a name-based lookup.
static constexpr char kGradientEffectMN[] = "ADBE Ramp",
kHueSaturationMN[] = "ADBE HUE SATURATION",
kLevelsEffectMN[] = "ADBE Easy Levels2",
kLinearWipeEffectMN[] = "ADBE Linear Wipe",
kMotionTileEffectMN[] = "ADBE Tile",
kTransformEffectMN[] = "ADBE Geometry2",
kVenetianBlindsEffectMN[] = "ADBE Venetian Blinds";
if (const skjson::StringValue* mn = jeffect["mn"]) {
if (!strcmp(mn->begin(), kGradientEffectMN)) {
return &EffectBuilder::attachGradientEffect;
}
if (!strcmp(mn->begin(), kHueSaturationMN)) {
return &EffectBuilder::attachHueSaturationEffect;
}
if (!strcmp(mn->begin(), kLevelsEffectMN)) {
return &EffectBuilder::attachLevelsEffect;
}
if (!strcmp(mn->begin(), kLinearWipeEffectMN)) {
return &EffectBuilder::attachLinearWipeEffect;
}
if (!strcmp(mn->begin(), kMotionTileEffectMN)) {
return &EffectBuilder::attachMotionTileEffect;
}
if (!strcmp(mn->begin(), kTransformEffectMN)) {
return &EffectBuilder::attachTransformEffect;
}
if (!strcmp(mn->begin(), kVenetianBlindsEffectMN)) {
return &EffectBuilder::attachVenetianBlindsEffect;
}
}
fBuilder->log(Logger::Level::kWarning, nullptr, "Unsupported layer effect type: %d.", ty);
return nullptr;
}
sk_sp<sksg::RenderNode> EffectBuilder::attachEffects(const skjson::ArrayValue& jeffects,
sk_sp<sksg::RenderNode> layer) const {
if (!layer) {
return nullptr;
}
for (const skjson::ObjectValue* jeffect : jeffects) {
if (!jeffect) {
continue;
}
const auto builder = this->findBuilder(*jeffect);
const skjson::ArrayValue* jprops = (*jeffect)["ef"];
if (!builder || !jprops) {
continue;
}
const AnimationBuilder::AutoPropertyTracker apt(fBuilder, *jeffect);
layer = (this->*builder)(*jprops, std::move(layer));
if (!layer) {
fBuilder->log(Logger::Level::kError, jeffect, "Invalid layer effect.");
return nullptr;
}
}
return layer;
}
const skjson::Value& EffectBuilder::GetPropValue(const skjson::ArrayValue& jprops,
size_t prop_index) {
static skjson::NullValue kNull;
if (prop_index >= jprops.size()) {
return kNull;
}
const skjson::ObjectValue* jprop = jprops[prop_index];
return jprop ? (*jprop)["v"] : kNull;
}
MaskFilterEffectBase::MaskFilterEffectBase(sk_sp<sksg::RenderNode> child, const SkSize& ls)
: fMaskNode(sksg::MaskFilter::Make(nullptr))
, fMaskEffectNode(sksg::MaskFilterEffect::Make(std::move(child), fMaskNode))
, fLayerSize(ls) {}
MaskFilterEffectBase::~MaskFilterEffectBase() = default;
void MaskFilterEffectBase::apply() const {
const auto minfo = this->onMakeMask();
fMaskEffectNode->setVisible(minfo.fVisible);
fMaskNode->setMaskFilter(std::move(minfo.fMask));
}
} // namespace internal
} // namespace skottie