[skottie] Layer clip support

TBR=

Change-Id: Ibf65efc69031f8f6e19f4f28cccab29c357e704d
Reviewed-on: https://skia-review.googlesource.com/101540
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
Florin Malita 2018-01-29 16:31:14 -05:00 committed by Skia Commit-Bot
parent eed48b66eb
commit 38ea40eb75
16 changed files with 157 additions and 5 deletions

View File

@ -1400,6 +1400,7 @@ if (skia_enable_tools) {
"experimental/sksg/SkSGPaintNode.cpp",
"experimental/sksg/SkSGRenderNode.cpp",
"experimental/sksg/SkSGScene.cpp",
"experimental/sksg/effects/SkSGClipEffect.cpp",
"experimental/sksg/effects/SkSGMaskEffect.cpp",
"experimental/sksg/effects/SkSGOpacityEffect.cpp",
"experimental/sksg/effects/SkSGTransform.cpp",

View File

@ -19,6 +19,7 @@
#include "SkPaint.h"
#include "SkParse.h"
#include "SkPoint.h"
#include "SkSGClipEffect.h"
#include "SkSGColor.h"
#include "SkSGDraw.h"
#include "SkSGGeometryTransform.h"
@ -944,12 +945,23 @@ sk_sp<sksg::RenderNode> AttachLayer(const Json::Value& jlayer,
// Layer content.
auto layer = gLayerAttachers[type](jlayer, &local_ctx, &time_bias, &time_scale);
// Clip layers with explicit dimensions.
float w, h;
if (Parse(jlayer["w"], &w) && Parse(jlayer["h"], &h)) {
layer = sksg::ClipEffect::Make(std::move(layer),
sksg::Rect::Make(SkRect::MakeWH(w, h)),
true);
}
// Optional layer mask.
layer = AttachMask(jlayer["masksProperties"], &local_ctx, std::move(layer));
// Optional layer transform.
if (auto layerMatrix = layerCtx->AttachLayerMatrix(jlayer)) {
layer = sksg::Transform::Make(std::move(layer), std::move(layerMatrix));
}
// Optional layer opacity.
layer = AttachOpacity(jlayer["ks"], &local_ctx, std::move(layer));

View File

@ -14,6 +14,11 @@ namespace sksg {
// Geometry nodes don't generate damage on their own, but via their aggregation ancestor Draw nodes.
GeometryNode::GeometryNode() : INHERITED(kBubbleDamage_Trait) {}
void GeometryNode::clip(SkCanvas* canvas, bool aa) const {
SkASSERT(!this->hasInval());
this->onClip(canvas, aa);
}
void GeometryNode::draw(SkCanvas* canvas, const SkPaint& paint) const {
SkASSERT(!this->hasInval());
this->onDraw(canvas, paint);

View File

@ -24,6 +24,7 @@ namespace sksg {
*/
class GeometryNode : public Node {
public:
void clip(SkCanvas*, bool antiAlias) const;
void draw(SkCanvas*, const SkPaint&) const;
SkPath asPath() const;
@ -31,6 +32,8 @@ public:
protected:
GeometryNode();
virtual void onClip(SkCanvas*, bool antiAlias) const = 0;
virtual void onDraw(SkCanvas*, const SkPaint&) const = 0;
virtual SkPath onAsPath() const = 0;

View File

@ -0,0 +1,50 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkSGClipEffect.h"
#include "SkCanvas.h"
#include "SkPath.h"
#include "SkSGGeometryNode.h"
namespace sksg {
ClipEffect::ClipEffect(sk_sp<RenderNode> child, sk_sp<GeometryNode> clip, bool aa)
: INHERITED(std::move(child))
, fClipNode(std::move(clip))
, fAntiAlias(aa) {
this->observeInval(fClipNode);
}
ClipEffect::~ClipEffect() {
this->unobserveInval(fClipNode);
}
void ClipEffect::onRender(SkCanvas* canvas) const {
if (this->bounds().isEmpty())
return;
SkAutoCanvasRestore acr(canvas, !fNoop);
if (!fNoop) {
fClipNode->clip(canvas, fAntiAlias);
}
this->INHERITED::onRender(canvas);
}
SkRect ClipEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
SkASSERT(this->hasInval());
const auto clipBounds = fClipNode->revalidate(ic, ctm);
auto childBounds = this->INHERITED::onRevalidate(ic, ctm);
fNoop = fClipNode->asPath().conservativelyContainsRect(childBounds);
return childBounds.intersect(clipBounds) ? childBounds : SkRect::MakeEmpty();
}
} // namespace sksg

View File

@ -0,0 +1,50 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkSGClipEffect_DEFINED
#define SkSGClipEffect_DEFINED
#include "SkSGEffectNode.h"
namespace sksg {
class GeometryNode;
/**
* Concrete Effect node, applying a clip to its descendants.
*
*/
class ClipEffect final : public EffectNode {
public:
static sk_sp<ClipEffect> Make(sk_sp<RenderNode> child, sk_sp<GeometryNode> clip,
bool aa = false) {
return (child && clip)
? sk_sp<ClipEffect>(new ClipEffect(std::move(child), std::move(clip), aa))
: nullptr;
}
~ClipEffect() override;
protected:
ClipEffect(sk_sp<RenderNode>, sk_sp<GeometryNode>, bool aa);
void onRender(SkCanvas*) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
private:
const sk_sp<GeometryNode> fClipNode;
const bool fAntiAlias;
bool fNoop = false;
typedef EffectNode INHERITED;
};
} // namespace sksg
#endif // SkSGClipEffect_DEFINED

View File

@ -23,6 +23,14 @@ GeometryTransform::~GeometryTransform() {
this->unobserveInval(fMatrix);
}
void GeometryTransform::onClip(SkCanvas* canvas, bool antiAlias) const {
canvas->clipPath(fTransformed, SkClipOp::kIntersect, antiAlias);
}
void GeometryTransform::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
canvas->drawPath(fTransformed, paint);
}
SkRect GeometryTransform::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
SkASSERT(this->hasInval());
@ -42,8 +50,4 @@ SkPath GeometryTransform::onAsPath() const {
return fTransformed;
}
void GeometryTransform::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
canvas->drawPath(fTransformed, paint);
}
} // namespace sksg

View File

@ -37,9 +37,11 @@ public:
const sk_sp<Matrix>& getMatrix() const { return fMatrix; }
protected:
void onClip(SkCanvas*, bool antiAlias) const override;
void onDraw(SkCanvas*, const SkPaint&) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
SkPath onAsPath() const override;
void onDraw(SkCanvas*, const SkPaint&) const override;
private:
GeometryTransform(sk_sp<GeometryNode>, sk_sp<Matrix>);

View File

@ -26,6 +26,10 @@ Merge::~Merge() {
}
}
void Merge::onClip(SkCanvas* canvas, bool antiAlias) const {
canvas->clipPath(fMerged, SkClipOp::kIntersect, antiAlias);
}
void Merge::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
canvas->drawPath(fMerged, paint);
}

View File

@ -43,6 +43,7 @@ public:
~Merge() override;
protected:
void onClip(SkCanvas*, bool antiAlias) const override;
void onDraw(SkCanvas*, const SkPaint&) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;

View File

@ -14,6 +14,10 @@ namespace sksg {
Path::Path(const SkPath& path) : fPath(path) {}
void Path::onClip(SkCanvas* canvas, bool antiAlias) const {
canvas->clipPath(fPath, SkClipOp::kIntersect, antiAlias);
}
void Path::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
canvas->drawPath(fPath, paint);
}

View File

@ -28,6 +28,7 @@ public:
SG_ATTRIBUTE(Path, SkPath, fPath)
protected:
void onClip(SkCanvas*, bool antiAlias) const override;
void onDraw(SkCanvas*, const SkPaint&) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;

View File

@ -15,6 +15,10 @@ namespace sksg {
Rect::Rect(const SkRect& rect) : fRect(rect) {}
void Rect::onClip(SkCanvas* canvas, bool antiAlias) const {
canvas->clipRect(fRect, SkClipOp::kIntersect, antiAlias);
}
void Rect::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
canvas->drawRect(fRect, paint);
}
@ -33,6 +37,10 @@ SkPath Rect::onAsPath() const {
RRect::RRect(const SkRRect& rr) : fRRect(rr) {}
void RRect::onClip(SkCanvas* canvas, bool antiAlias) const {
canvas->clipRRect(fRRect, SkClipOp::kIntersect, antiAlias);
}
void RRect::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
canvas->drawRRect(fRRect, paint);
}

View File

@ -32,6 +32,7 @@ public:
SG_ATTRIBUTE(B, SkScalar, fRect.fBottom)
protected:
void onClip(SkCanvas*, bool antiAlias) const override;
void onDraw(SkCanvas*, const SkPaint&) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
@ -54,6 +55,7 @@ public:
SG_ATTRIBUTE(RRect, SkRRect, fRRect)
protected:
void onClip(SkCanvas*, bool antiAlias) const override;
void onDraw(SkCanvas*, const SkPaint&) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;

View File

@ -22,6 +22,10 @@ TrimEffect::~TrimEffect() {
this->unobserveInval(fChild);
}
void TrimEffect::onClip(SkCanvas* canvas, bool antiAlias) const {
canvas->clipPath(fChild->asPath(), SkClipOp::kIntersect, antiAlias);
}
// TODO
// This is a quick hack to get something on the screen. What we really want here is to apply
// the geometry transformation and cache the result on revalidation. Or an SkTrimPathEffect.

View File

@ -33,6 +33,7 @@ public:
SG_ATTRIBUTE(Offset, SkScalar, fOffset)
protected:
void onClip(SkCanvas*, bool antiAlias) const override;
void onDraw(SkCanvas*, const SkPaint&) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;