[skottie] Add shape layer Offset Paths support
Based on SkPathOps for now. Change-Id: Id27c8a235cbd4ab5083735b67cf5d2635ee16cfc Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300497 Commit-Queue: Florin Malita <fmalita@google.com> Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
parent
c05b2de8fe
commit
6ec66b9d38
@ -72,6 +72,7 @@ skia_skottie_sources = [
|
|||||||
"$_src/layers/shapelayer/FillStroke.cpp",
|
"$_src/layers/shapelayer/FillStroke.cpp",
|
||||||
"$_src/layers/shapelayer/Gradient.cpp",
|
"$_src/layers/shapelayer/Gradient.cpp",
|
||||||
"$_src/layers/shapelayer/MergePaths.cpp",
|
"$_src/layers/shapelayer/MergePaths.cpp",
|
||||||
|
"$_src/layers/shapelayer/OffsetPaths.cpp",
|
||||||
"$_src/layers/shapelayer/Polystar.cpp",
|
"$_src/layers/shapelayer/Polystar.cpp",
|
||||||
"$_src/layers/shapelayer/Rectangle.cpp",
|
"$_src/layers/shapelayer/Rectangle.cpp",
|
||||||
"$_src/layers/shapelayer/Repeater.cpp",
|
"$_src/layers/shapelayer/Repeater.cpp",
|
||||||
|
67
modules/skottie/src/layers/shapelayer/OffsetPaths.cpp
Normal file
67
modules/skottie/src/layers/shapelayer/OffsetPaths.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/Adapter.h"
|
||||||
|
#include "modules/skottie/src/SkottieJson.h"
|
||||||
|
#include "modules/skottie/src/SkottiePriv.h"
|
||||||
|
#include "modules/skottie/src/SkottieValue.h"
|
||||||
|
#include "modules/skottie/src/layers/shapelayer/ShapeLayer.h"
|
||||||
|
#include "modules/sksg/include/SkSGGeometryEffect.h"
|
||||||
|
|
||||||
|
namespace skottie::internal {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class OffsetPathsAdapter final : public DiscardableAdapterBase<OffsetPathsAdapter,
|
||||||
|
sksg::OffsetEffect> {
|
||||||
|
public:
|
||||||
|
OffsetPathsAdapter(const skjson::ObjectValue& joffset,
|
||||||
|
const AnimationBuilder& abuilder,
|
||||||
|
sk_sp<sksg::GeometryNode> child)
|
||||||
|
: INHERITED(sksg::OffsetEffect::Make(std::move(child))) {
|
||||||
|
static constexpr SkPaint::Join gJoinMap[] = {
|
||||||
|
SkPaint::kMiter_Join, // 'lj': 1
|
||||||
|
SkPaint::kRound_Join, // 'lj': 2
|
||||||
|
SkPaint::kBevel_Join, // 'lj': 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto join = ParseDefault<int>(joffset["lj"], 1) - 1;
|
||||||
|
this->node()->setJoin(gJoinMap[SkTPin<int>(join, 0, SK_ARRAY_COUNT(gJoinMap) - 1)]);
|
||||||
|
|
||||||
|
this->bind(abuilder, joffset["a" ], fAmount);
|
||||||
|
this->bind(abuilder, joffset["ml"], fMiterLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onSync() override {
|
||||||
|
this->node()->setOffset(fAmount);
|
||||||
|
this->node()->setMiterLimit(fMiterLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalarValue fAmount = 0,
|
||||||
|
fMiterLimit = 0;
|
||||||
|
|
||||||
|
using INHERITED = DiscardableAdapterBase<OffsetPathsAdapter, sksg::OffsetEffect>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::vector<sk_sp<sksg::GeometryNode>> ShapeBuilder::AttachOffsetGeometryEffect(
|
||||||
|
const skjson::ObjectValue& jround, const AnimationBuilder* abuilder,
|
||||||
|
std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
|
||||||
|
std::vector<sk_sp<sksg::GeometryNode>> offsetted;
|
||||||
|
offsetted.reserve(geos.size());
|
||||||
|
|
||||||
|
for (auto& g : geos) {
|
||||||
|
offsetted.push_back(abuilder->attachDiscardableAdapter<OffsetPathsAdapter>
|
||||||
|
(jround, *abuilder, std::move(g)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return offsetted;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace skottie::internal
|
@ -47,6 +47,7 @@ static constexpr GeometryEffectAttacherT gGeometryEffectAttachers[] = {
|
|||||||
ShapeBuilder::AttachMergeGeometryEffect,
|
ShapeBuilder::AttachMergeGeometryEffect,
|
||||||
ShapeBuilder::AttachTrimGeometryEffect,
|
ShapeBuilder::AttachTrimGeometryEffect,
|
||||||
ShapeBuilder::AttachRoundGeometryEffect,
|
ShapeBuilder::AttachRoundGeometryEffect,
|
||||||
|
ShapeBuilder::AttachOffsetGeometryEffect,
|
||||||
};
|
};
|
||||||
|
|
||||||
using PaintAttacherT = sk_sp<sksg::PaintNode> (*)(const skjson::ObjectValue&,
|
using PaintAttacherT = sk_sp<sksg::PaintNode> (*)(const skjson::ObjectValue&,
|
||||||
@ -99,6 +100,7 @@ const ShapeInfo* FindShapeInfo(const skjson::ObjectValue& jshape) {
|
|||||||
{ "gr", ShapeType::kGroup , 0 }, // group -> Inline handler
|
{ "gr", ShapeType::kGroup , 0 }, // group -> Inline handler
|
||||||
{ "gs", ShapeType::kPaint , 3 }, // gstroke -> AttachGradientStroke
|
{ "gs", ShapeType::kPaint , 3 }, // gstroke -> AttachGradientStroke
|
||||||
{ "mm", ShapeType::kGeometryEffect, 0 }, // merge -> AttachMergeGeometryEffect
|
{ "mm", ShapeType::kGeometryEffect, 0 }, // merge -> AttachMergeGeometryEffect
|
||||||
|
{ "op", ShapeType::kGeometryEffect, 3 }, // offset -> AttachOffsetGeometryEffect
|
||||||
{ "rc", ShapeType::kGeometry , 1 }, // rrect -> AttachRRectGeometry
|
{ "rc", ShapeType::kGeometry , 1 }, // rrect -> AttachRRectGeometry
|
||||||
{ "rd", ShapeType::kGeometryEffect, 2 }, // round -> AttachRoundGeometryEffect
|
{ "rd", ShapeType::kGeometryEffect, 2 }, // round -> AttachRoundGeometryEffect
|
||||||
{ "rp", ShapeType::kDrawEffect , 0 }, // repeater -> AttachRepeaterDrawEffect
|
{ "rp", ShapeType::kDrawEffect , 0 }, // repeater -> AttachRepeaterDrawEffect
|
||||||
|
@ -67,6 +67,9 @@ public:
|
|||||||
static std::vector<sk_sp<sksg::GeometryNode>> AttachRoundGeometryEffect(
|
static std::vector<sk_sp<sksg::GeometryNode>> AttachRoundGeometryEffect(
|
||||||
const skjson::ObjectValue&, const AnimationBuilder*,
|
const skjson::ObjectValue&, const AnimationBuilder*,
|
||||||
std::vector<sk_sp<sksg::GeometryNode>>&&);
|
std::vector<sk_sp<sksg::GeometryNode>>&&);
|
||||||
|
static std::vector<sk_sp<sksg::GeometryNode>> AttachOffsetGeometryEffect(
|
||||||
|
const skjson::ObjectValue&, const AnimationBuilder*,
|
||||||
|
std::vector<sk_sp<sksg::GeometryNode>>&&);
|
||||||
static std::vector<sk_sp<sksg::GeometryNode>> AdjustStrokeGeometry(
|
static std::vector<sk_sp<sksg::GeometryNode>> AdjustStrokeGeometry(
|
||||||
const skjson::ObjectValue&, const AnimationBuilder*,
|
const skjson::ObjectValue&, const AnimationBuilder*,
|
||||||
std::vector<sk_sp<sksg::GeometryNode>>&&);
|
std::vector<sk_sp<sksg::GeometryNode>>&&);
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "modules/sksg/include/SkSGGeometryNode.h"
|
#include "modules/sksg/include/SkSGGeometryNode.h"
|
||||||
|
|
||||||
|
#include "include/core/SkPaint.h"
|
||||||
#include "include/core/SkPath.h"
|
#include "include/core/SkPath.h"
|
||||||
#include "include/effects/SkTrimPathEffect.h"
|
#include "include/effects/SkTrimPathEffect.h"
|
||||||
#include "modules/sksg/include/SkSGTransform.h"
|
#include "modules/sksg/include/SkSGTransform.h"
|
||||||
@ -139,6 +140,31 @@ private:
|
|||||||
using INHERITED = GeometryEffect;
|
using INHERITED = GeometryEffect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply an offset effect to the child geometry.
|
||||||
|
*/
|
||||||
|
class OffsetEffect final : public GeometryEffect {
|
||||||
|
public:
|
||||||
|
static sk_sp<OffsetEffect> Make(sk_sp<GeometryNode> child) {
|
||||||
|
return child ? sk_sp<OffsetEffect>(new OffsetEffect(std::move(child))) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_ATTRIBUTE(Offset , SkScalar , fOffset )
|
||||||
|
SG_ATTRIBUTE(MiterLimit , SkScalar , fMiterLimit)
|
||||||
|
SG_ATTRIBUTE(Join , SkPaint::Join, fJoin )
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit OffsetEffect(sk_sp<GeometryNode> child) : INHERITED(std::move(child)) {}
|
||||||
|
|
||||||
|
SkPath onRevalidateEffect(const sk_sp<GeometryNode>&) override;
|
||||||
|
|
||||||
|
SkScalar fOffset = 0,
|
||||||
|
fMiterLimit = 4;
|
||||||
|
SkPaint::Join fJoin = SkPaint::kMiter_Join;
|
||||||
|
|
||||||
|
using INHERITED = GeometryEffect;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace sksg
|
} // namespace sksg
|
||||||
|
|
||||||
#endif // SkSGGeometryEffect_DEFINED
|
#endif // SkSGGeometryEffect_DEFINED
|
||||||
|
@ -12,8 +12,11 @@
|
|||||||
#include "include/effects/SkCornerPathEffect.h"
|
#include "include/effects/SkCornerPathEffect.h"
|
||||||
#include "include/effects/SkDashPathEffect.h"
|
#include "include/effects/SkDashPathEffect.h"
|
||||||
#include "include/effects/SkTrimPathEffect.h"
|
#include "include/effects/SkTrimPathEffect.h"
|
||||||
|
#include "include/pathops/SkPathOps.h"
|
||||||
#include "modules/sksg/src/SkSGTransformPriv.h"
|
#include "modules/sksg/src/SkSGTransformPriv.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace sksg {
|
namespace sksg {
|
||||||
|
|
||||||
GeometryEffect::GeometryEffect(sk_sp<GeometryNode> child)
|
GeometryEffect::GeometryEffect(sk_sp<GeometryNode> child)
|
||||||
@ -133,4 +136,30 @@ SkPath RoundEffect::onRevalidateEffect(const sk_sp<GeometryNode>& child) {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SkPath OffsetEffect::onRevalidateEffect(const sk_sp<GeometryNode>& child) {
|
||||||
|
SkPath path = child->asPath();
|
||||||
|
|
||||||
|
if (!SkScalarNearlyZero(fOffset)) {
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setStyle(SkPaint::kStroke_Style);
|
||||||
|
paint.setStrokeWidth(std::abs(fOffset) * 2);
|
||||||
|
paint.setStrokeMiter(fMiterLimit);
|
||||||
|
paint.setStrokeJoin(fJoin);
|
||||||
|
|
||||||
|
SkPath fill_path;
|
||||||
|
paint.getFillPath(path, &fill_path, nullptr);
|
||||||
|
|
||||||
|
if (fOffset > 0) {
|
||||||
|
Op(path, fill_path, kUnion_SkPathOp, &path);
|
||||||
|
} else {
|
||||||
|
Op(path, fill_path, kDifference_SkPathOp, &path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this seems to break path combining (winding mismatch?)
|
||||||
|
// Simplify(path, &path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
} // namesapce sksg
|
} // namesapce sksg
|
||||||
|
1
resources/skottie/skottie-offsetpaths-effect.json
Normal file
1
resources/skottie/skottie-offsetpaths-effect.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user