Skip to content

Commit

Permalink
[skottie] Initial drop shadow style support
Browse files Browse the repository at this point in the history
Plumb layer style parsing, and extend existing DropShadowAdapter to
support both drop shadow style and drop shadow effect.

Change-Id: Id99a419dacd06dc38dc4cf84ff4ecb92218c45f7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/279020
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
  • Loading branch information
fmalita authored and Skia Commit-Bot committed Mar 25, 2020
1 parent 9686528 commit ae58199
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 29 deletions.
5 changes: 5 additions & 0 deletions modules/skottie/src/Layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,11 @@ sk_sp<sksg::RenderNode> LayerBuilder::buildRenderTree(const AnimationBuilder& ab
layer = sksg::TransformEffect::Make(std::move(layer), std::move(fLayerTransform));
}

// Optional layer styles.
if (const skjson::ArrayValue* jstyles = fJlayer["sy"]) {
layer = EffectBuilder(&abuilder, layer_info.fSize).attachStyles(*jstyles, std::move(layer));
}

// Optional layer opacity.
// TODO: de-dupe this "ks" lookup with matrix above.
if (const skjson::ObjectValue* jtransform = fJlayer["ks"]) {
Expand Down
100 changes: 71 additions & 29 deletions modules/skottie/src/effects/DropShadowEffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,9 @@ namespace {

class DropShadowAdapter final : public AnimatablePropertyContainer {
public:
static sk_sp<DropShadowAdapter> Make(const skjson::ArrayValue& jprops,
sk_sp<sksg::RenderNode> layer,
const AnimationBuilder* abuilder) {
return sk_sp<DropShadowAdapter>(new DropShadowAdapter(jprops, std::move(layer), abuilder));
}

const sk_sp<sksg::RenderNode>& node() const { return fImageFilterEffect; }

private:
DropShadowAdapter(const skjson::ArrayValue& jprops,
sk_sp<sksg::RenderNode> layer,
const AnimationBuilder* abuilder)
: fDropShadow(sksg::DropShadowImageFilter::Make())
, fImageFilterEffect(sksg::ImageFilterEffect::Make(std::move(layer), fDropShadow)) {
static sk_sp<DropShadowAdapter> MakeEffect(const skjson::ArrayValue& jprops,
sk_sp<sksg::RenderNode> layer,
const AnimationBuilder& abuilder) {
enum : size_t {
kShadowColor_Index = 0,
kOpacity_Index = 1,
Expand All @@ -41,22 +30,55 @@ class DropShadowAdapter final : public AnimatablePropertyContainer {
kShadowOnly_Index = 5,
};

EffectBinder(jprops, *abuilder, this)
.bind(kShadowColor_Index, fColor )
.bind( kOpacity_Index, fOpacity )
.bind( kDirection_Index, fDirection)
.bind( kDistance_Index, fDistance )
.bind( kSoftness_Index, fSoftness )
.bind( kShadowOnly_Index, fShdwOnly );
sk_sp<DropShadowAdapter> adapter(new DropShadowAdapter(std::move(layer), Type::fEffect));

EffectBinder(jprops, abuilder, adapter.get())
.bind(kShadowColor_Index, adapter->fColor )
.bind( kOpacity_Index, adapter->fOpacity )
.bind( kDirection_Index, adapter->fDirection)
.bind( kDistance_Index, adapter->fDistance )
.bind( kSoftness_Index, adapter->fSoftness )
.bind( kShadowOnly_Index, adapter->fShdwOnly );

return adapter;
}

static sk_sp<DropShadowAdapter> MakeStyle(const skjson::ObjectValue& jstyle,
sk_sp<sksg::RenderNode> layer,
const AnimationBuilder& abuilder) {
sk_sp<DropShadowAdapter> adapter(new DropShadowAdapter(std::move(layer), Type::fStyle));

adapter->bind(abuilder, jstyle["a"], adapter->fDirection);
adapter->bind(abuilder, jstyle["c"], adapter->fColor );
adapter->bind(abuilder, jstyle["d"], adapter->fDistance );
adapter->bind(abuilder, jstyle["o"], adapter->fOpacity );
adapter->bind(abuilder, jstyle["s"], adapter->fSoftness );

return adapter;
}

const sk_sp<sksg::RenderNode>& node() const { return fImageFilterEffect; }

private:
enum class Type { fEffect, fStyle };
DropShadowAdapter(sk_sp<sksg::RenderNode> layer, Type ty)
: fDropShadow(sksg::DropShadowImageFilter::Make())
, fImageFilterEffect(sksg::ImageFilterEffect::Make(std::move(layer), fDropShadow))
, fType(ty) {
fOpacity = this->maxOpacity();
}

void onSync() override {
// fColor -> RGB, fOpacity -> A
const auto color = ValueTraits<VectorValue>::As<SkColor>(fColor);
fDropShadow->setColor(SkColorSetA(color, SkTPin(SkScalarRoundToInt(fOpacity), 0, 255)));

// The offset is specified in terms of a bearing angle + distance.
SkScalar rad = SkDegreesToRadians(90 - fDirection);
fDropShadow->setColor(SkColorSetA(color,
SkScalarRoundToInt(SkTPin(fOpacity / this->maxOpacity(),
0.0f, 1.0f) * 255)));

// The offset is specified in terms of an angle + distance.
const auto rad = SkDegreesToRadians(fType == Type::fEffect
? 90 - fDirection // bearing (effect)
: 180 + fDirection); // 0deg -> left (style)
fDropShadow->setOffset(SkVector::Make( fDistance * SkScalarCos(rad),
-fDistance * SkScalarSin(rad)));

Expand All @@ -68,11 +90,18 @@ class DropShadowAdapter final : public AnimatablePropertyContainer {
: sksg::DropShadowImageFilter::Mode::kShadowAndForeground);
}

float maxOpacity() const {
return fType == Type::fEffect
? 255.0f // effect: 0 - 255
: 100.0f; // style : 0 - 100
}

const sk_sp<sksg::DropShadowImageFilter> fDropShadow;
const sk_sp<sksg::RenderNode> fImageFilterEffect;
const Type fType;

VectorValue fColor = { 0, 0, 0, 1 };
ScalarValue fOpacity = 255.f,
ScalarValue fOpacity, // initialized explicitly depending on type
fDirection = 0,
fDistance = 0,
fSoftness = 0,
Expand All @@ -83,9 +112,22 @@ class DropShadowAdapter final : public AnimatablePropertyContainer {

sk_sp<sksg::RenderNode> EffectBuilder::attachDropShadowEffect(const skjson::ArrayValue& jprops,
sk_sp<sksg::RenderNode> layer) const {
return fBuilder->attachDiscardableAdapter<DropShadowAdapter>(jprops,
std::move(layer),
fBuilder);
auto adapter = DropShadowAdapter::MakeEffect(jprops, std::move(layer), *fBuilder);
auto effect_node = adapter->node();

fBuilder->attachDiscardableAdapter(std::move(adapter));

return effect_node;
}

sk_sp<sksg::RenderNode> EffectBuilder::attachDropShadowStyle(const skjson::ObjectValue& jstyle,
sk_sp<sksg::RenderNode> layer) const {
auto adapter = DropShadowAdapter::MakeStyle(jstyle, std::move(layer), *fBuilder);
auto effect_node = adapter->node();

fBuilder->attachDiscardableAdapter(std::move(adapter));

return effect_node;
}

} // namespace internal
Expand Down
37 changes: 37 additions & 0 deletions modules/skottie/src/effects/Effects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,43 @@ sk_sp<sksg::RenderNode> EffectBuilder::attachEffects(const skjson::ArrayValue& j
return layer;
}

sk_sp<sksg::RenderNode> EffectBuilder::attachStyles(const skjson::ArrayValue& jstyles,
sk_sp<sksg::RenderNode> layer) const {
#if !defined(SKOTTIE_DISABLE_STYLES)
if (!layer) {
return nullptr;
}

using StyleBuilder =
sk_sp<sksg::RenderNode> (EffectBuilder::*)(const skjson::ObjectValue&,
sk_sp<sksg::RenderNode>) const;
static constexpr StyleBuilder gStyleBuilders[] = {
nullptr, // 'ty': 0 -> stroke
&EffectBuilder::attachDropShadowStyle, // 'ty': 1 -> drop shadow
};

for (const skjson::ObjectValue* jstyle : jstyles) {
if (!jstyle) {
continue;
}

const auto style_type =
ParseDefault<size_t>((*jstyle)["ty"], std::numeric_limits<size_t>::max());
auto builder = style_type < SK_ARRAY_COUNT(gStyleBuilders) ? gStyleBuilders[style_type]
: nullptr;

if (!builder) {
fBuilder->log(Logger::Level::kWarning, jstyle, "Unsupported layer style.");
continue;
}

layer = (this->*builder)(*jstyle, std::move(layer));
}
#endif // !defined(SKOTTIE_DISABLE_STYLES)

return layer;
}

const skjson::Value& EffectBuilder::GetPropValue(const skjson::ArrayValue& jprops,
size_t prop_index) {
static skjson::NullValue kNull;
Expand Down
6 changes: 6 additions & 0 deletions modules/skottie/src/effects/Effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class EffectBuilder final : public SkNoncopyable {
sk_sp<sksg::RenderNode> attachEffects(const skjson::ArrayValue&,
sk_sp<sksg::RenderNode>) const;

sk_sp<sksg::RenderNode> attachStyles(const skjson::ArrayValue&,
sk_sp<sksg::RenderNode>) const;

static const skjson::Value& GetPropValue(const skjson::ArrayValue& jprops, size_t prop_index);

private:
Expand Down Expand Up @@ -66,6 +69,9 @@ class EffectBuilder final : public SkNoncopyable {
sk_sp<sksg::RenderNode> attachShiftChannelsEffect (const skjson::ArrayValue&,
sk_sp<sksg::RenderNode>) const;

sk_sp<sksg::RenderNode> attachDropShadowStyle(const skjson::ObjectValue&,
sk_sp<sksg::RenderNode>) const;

EffectBuilderT findBuilder(const skjson::ObjectValue&) const;

const AnimationBuilder* fBuilder;
Expand Down
1 change: 1 addition & 0 deletions resources/skottie/skottie-dropshadow-style.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"v":"5.6.6","fr":60,"ip":0,"op":600,"w":500,"h":500,"nm":"drop shadow","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":600,"s":[720]}],"ix":5},"ir":{"a":0,"k":35,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":100,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.186933204532,0.489476114511,1,1],"ix":4},"o":{"a":0,"k":75,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[150,150],"ix":2},"p":{"a":0,"k":[80,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.230637252331,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":21,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.799341320992,0.889966309071,0.211565569043,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":600,"s":[-360]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":601,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"precomp","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":599,"s":[-360]}],"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[250,250,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":150,"s":[150,150,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":300,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":450,"s":[75,75,100]},{"t":599,"s":[100,100,100]}],"ix":6}},"ao":0,"sy":[{"c":{"a":0,"k":[0,0,0,1],"ix":2},"o":{"a":0,"k":75,"ix":3},"a":{"a":0,"k":45,"ix":5},"s":{"a":0,"k":17,"ix":8},"d":{"a":0,"k":50,"ix":6},"ch":{"a":0,"k":0,"ix":7},"bm":{"a":0,"k":1,"ix":1},"no":{"a":0,"k":0,"ix":9},"lc":{"a":0,"k":1,"ix":10},"ty":1,"nm":"Drop Shadow"}],"w":500,"h":500,"ip":0,"op":601,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":1,"nm":"bg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[250,250,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"sw":500,"sh":500,"sc":"#ffffff","ip":0,"op":600,"st":0,"bm":0}],"markers":[]}

0 comments on commit ae58199

Please sign in to comment.