From 579e63af00480df2f0608d7c9c5f1c60dac76fa0 Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Fri, 19 Jun 2020 14:21:33 -0400 Subject: [PATCH] [skrive] Reset the node system Tacking another hierarchy on top of SkSG doesn't work well. Let's start fresh. TBR= Change-Id: Ieb379b57e1a77df3c62048d3be7e81e1429f9b23 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297807 Reviewed-by: Florin Malita Commit-Queue: Florin Malita --- experimental/skrive/BUILD.gn | 1 + experimental/skrive/include/SkRive.h | 161 +++++++++++++++++-------- experimental/skrive/skrive.gni | 1 + experimental/skrive/src/Artboard.cpp | 42 +++---- experimental/skrive/src/Component.cpp | 47 ++++++++ experimental/skrive/src/Node.cpp | 23 ++-- experimental/skrive/src/Shape.cpp | 10 +- experimental/skrive/tests/DomTypes.cpp | 35 ++++++ tools/viewer/SkRiveSlide.cpp | 1 - 9 files changed, 239 insertions(+), 82 deletions(-) create mode 100644 experimental/skrive/src/Component.cpp create mode 100644 experimental/skrive/tests/DomTypes.cpp diff --git a/experimental/skrive/BUILD.gn b/experimental/skrive/BUILD.gn index 4bbb322d8a..4f77a546d4 100644 --- a/experimental/skrive/BUILD.gn +++ b/experimental/skrive/BUILD.gn @@ -32,6 +32,7 @@ if (skia_enable_skrive) { ] sources = [ "tests/BinaryReader.cpp", + "tests/DomTypes.cpp", "tests/JsonReader.cpp", ] diff --git a/experimental/skrive/include/SkRive.h b/experimental/skrive/include/SkRive.h index d1b347238f..6973229186 100644 --- a/experimental/skrive/include/SkRive.h +++ b/experimental/skrive/include/SkRive.h @@ -9,100 +9,159 @@ #define SkRive_DEFINED #include "include/core/SkBlendMode.h" +#include "include/core/SkColor.h" #include "include/core/SkM44.h" #include "include/core/SkRefCnt.h" #include "include/core/SkString.h" -#include "modules/sksg/include/SkSGGroup.h" -#include "modules/sksg/include/SkSGRenderNode.h" #include +#include #include +class SkCanvas; class SkStreamAsset; namespace skrive { -class Node : public sksg::Group { -public: - SG_ATTRIBUTE(Name , SkString , fName ) - SG_ATTRIBUTE(Translation , SkV2 , fTranslation ) - SG_ATTRIBUTE(Scale , SkV2 , fScale ) - SG_ATTRIBUTE(Rotation , float , fRotation ) - SG_ATTRIBUTE(Opacity , float , fOpacity ) - SG_ATTRIBUTE(CollapsedVisibility, bool , fCollapsedVisibility) +#define ACTOR_ATTR(attr_name, attr_type, attr_default) \ +private: \ + attr_type f##attr_name = attr_default; \ +public: \ + const attr_type& get##attr_name() const { return f##attr_name; } \ + void set##attr_name(const attr_type& v) { \ + if (f##attr_name == v) return; \ + f##attr_name = v; \ + this->invalidate(); \ + } \ + void set##attr_name(attr_type&& v) { \ + if (f##attr_name == v) return; \ + f##attr_name = std::move(v); \ + this->invalidate(); \ + } - Node() : Node(Type::kNode) {} +class Node; + +class Component : public SkRefCnt { +public: + ACTOR_ATTR(Name, SkString, SkString()) + + template + std::enable_if_t::value, bool> + is() const { + if constexpr(std::is_same::value) { + return true; + } else { + return is_base_of(fType); + } + } + + template + operator const T*() const { + return this->is() ? reinterpret_cast(this) : nullptr; + } + + template + operator T*() { + return this->is() ? reinterpret_cast(this) : nullptr; + } + + void revalidate(); protected: enum class Type : uint32_t { - kNode, // base group node + kNode, + kShape, }; - explicit Node(Type t) : fType(t) {} + explicit Component(Type t) : fType(t) {} - SkRect onRevalidate(sksg::InvalidationController*, const SkMatrix&) override; + void invalidate(); - Type type() const { return fType; } + bool hasInval() const { return fDirty; } + + virtual void onRevalidate() = 0; private: - const Type fType; + friend class Node; // parent access - SkString fName; - SkV2 fTranslation = {0, 0}, - fScale = {1, 1}; - float fRotation = 0, - fOpacity = 1; - bool fCollapsedVisibility = false; + template + static constexpr bool is_base_of(Type t); - using INHERITED = sksg::Group; + const Type fType; + + Node* fParent = nullptr; + bool fDirty = true; +}; + +class Node : public Component { +public: + Node() : INHERITED(Type::kNode) {} + + ACTOR_ATTR(Translation , SkV2 , SkV2({0, 0})) + ACTOR_ATTR(Scale , SkV2 , SkV2({1, 1})) + ACTOR_ATTR(Rotation , float, 0 ) + ACTOR_ATTR(Opacity , float, 1 ) + ACTOR_ATTR(CollapsedVisibility, bool , false ) + + void addChild(sk_sp); + +protected: + explicit Node(Type t) : INHERITED(t) {} + +private: + void onRevalidate() override; + + std::vector> fChildren; + + using INHERITED = Component; }; class Drawable : public Node { public: - SG_ATTRIBUTE(DrawOrder, size_t , fDrawOrder) - SG_ATTRIBUTE(BlendMode, SkBlendMode, fBlendMode) - SG_ATTRIBUTE(IsHidden , bool , fIsHidden ) + ACTOR_ATTR(DrawOrder, size_t , 0 ) + ACTOR_ATTR(BlendMode, SkBlendMode, SkBlendMode::kSrcOver) + ACTOR_ATTR(IsHidden , bool , false ) + +protected: + explicit Drawable(Type t) : INHERITED(t) {} private: - size_t fDrawOrder = 0; - SkBlendMode fBlendMode = SkBlendMode::kSrcOver; - bool fIsHidden = false; - using INHERITED = Node; }; class Shape final : public Drawable { public: - SG_ATTRIBUTE(TransformAffectsStroke, bool, fTransformAffectsStroke) + Shape() : INHERITED(Type::kShape) {} + + ACTOR_ATTR(TransformAffectsStroke, bool, true) private: - bool fTransformAffectsStroke = true; + void onRevalidate() override; using INHERITED = Drawable; }; -class Artboard final : public sksg::RenderNode { +template +constexpr bool Component::is_base_of(Type t) { + if (t == Type::kNode ) return std::is_base_of::value; + if (t == Type::kShape) return std::is_base_of::value; + + return false; +} + +class Artboard final : public SkRefCnt { public: - SG_ATTRIBUTE(Name , SkString , fName ) // TODO: non-invalidating attributes? - SG_ATTRIBUTE(Color , SkColor4f, fColor ) - SG_ATTRIBUTE(Size , SkV2 , fSize ) - SG_ATTRIBUTE(Origin , SkV2 , fOrigin ) - SG_ATTRIBUTE(Translation , SkV2 , fTranslation ) - SG_ATTRIBUTE(ClipContents, bool , fClipContents) + ACTOR_ATTR(Name , SkString , SkString() ) + ACTOR_ATTR(Color , SkColor4f, SkColors::kBlack) + ACTOR_ATTR(Size , SkV2 , SkV2({0,0}) ) + ACTOR_ATTR(Origin , SkV2 , SkV2({0,0}) ) + ACTOR_ATTR(Translation , SkV2 , SkV2({0,0}) ) + ACTOR_ATTR(ClipContents, bool , false ) + + void render(SkCanvas*) const; private: - SkRect onRevalidate(sksg::InvalidationController*, const SkMatrix&) override; - void onRender(SkCanvas*, const RenderContext*) const override; - const RenderNode* onNodeAt(const SkPoint&) const override; - - SkString fName; - SkColor4f fColor = {0, 0, 0, 1}; - SkV2 fSize = {0, 0}, - fOrigin = {0, 0}, - fTranslation = {0, 0}; - bool fClipContents = false; - - using INHERITED = RenderNode; + void invalidate() {} }; class SK_API SkRive final : public SkNVRefCnt { diff --git a/experimental/skrive/skrive.gni b/experimental/skrive/skrive.gni index 1fd0950748..ef8b34e80a 100644 --- a/experimental/skrive/skrive.gni +++ b/experimental/skrive/skrive.gni @@ -11,6 +11,7 @@ skia_skrive_public = [ "$_include/SkRive.h" ] skia_skrive_sources = [ "$_src/Artboard.cpp", + "$_src/Component.cpp", "$_src/Drawable.cpp", "$_src/Node.cpp", "$_src/Shape.cpp", diff --git a/experimental/skrive/src/Artboard.cpp b/experimental/skrive/src/Artboard.cpp index 47edbd92f2..773c58439a 100644 --- a/experimental/skrive/src/Artboard.cpp +++ b/experimental/skrive/src/Artboard.cpp @@ -28,7 +28,7 @@ std::tuple, size_t> make_from_stream(StreamReader* sr) { return std::make_tuple(std::move(node), parent_index); } -std::tuple, size_t> parse_component(StreamReader* sr) { +std::tuple, size_t> parse_component(StreamReader* sr) { StreamReader::AutoBlock block(sr); switch (block.type()) { case StreamReader::BlockType::kActorNode : return make_from_stream(sr); @@ -44,24 +44,31 @@ std::tuple, size_t> parse_component(StreamReader* sr) { sk_sp parse_components(StreamReader* sr) { const auto count = sr->readLength16(); - std::vector> nodes; - nodes.reserve(count); + std::vector> components; + components.reserve(count); for (size_t i = 0; i < count; ++i) { - auto [ node, parent_index ] = parse_component(sr); + auto [ component, parent_index ] = parse_component(sr); - if (node && parent_index < i && nodes[parent_index]) { - nodes[parent_index]->addChild(node); + if (component && parent_index < i && components[parent_index]) { + if (Node* node = *components[parent_index]) { + node->addChild(component); + } } - nodes.push_back(std::move(node)); + components.push_back(std::move(component)); } - SkDebugf(".. parsed %zu nodes\n", nodes.size()); + SkDebugf(".. parsed %zu components\n", components.size()); - return count > 0 - ? std::move(nodes[0]) - : nullptr; + // hmm... + for (const auto& comp : components) { + if (comp && comp->is()) { + return sk_ref_sp(static_cast(*comp)); + } + } + + return nullptr; } sk_sp parse_artboard(StreamReader* sr) { @@ -99,19 +106,12 @@ sk_sp parse_artboard(StreamReader* sr) { } // namespace internal -SkRect Artboard::onRevalidate(sksg::InvalidationController*, const SkMatrix&) { - return SkRect::MakeXYWH(fTranslation.x, fTranslation.y, fSize.x, fSize.y); -} - -const sksg::RenderNode* Artboard::onNodeAt(const SkPoint&) const { - return this; -} - -void Artboard::onRender(SkCanvas* canvas, const RenderContext*) const { +void Artboard::render(SkCanvas* canvas) const { SkPaint paint; paint.setColor4f(fColor); - canvas->drawRect(this->bounds(), paint); + const auto rect = SkRect::MakeXYWH(fTranslation.x, fTranslation.y, fSize.x, fSize.y); + canvas->drawRect(rect, paint); } } // namespace skrive diff --git a/experimental/skrive/src/Component.cpp b/experimental/skrive/src/Component.cpp new file mode 100644 index 0000000000..ca9436b781 --- /dev/null +++ b/experimental/skrive/src/Component.cpp @@ -0,0 +1,47 @@ +/* + * 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 "experimental/skrive/include/SkRive.h" + +#include "experimental/skrive/src/reader/StreamReader.h" + +namespace skrive { +namespace internal { + +template +size_t parse_node(StreamReader*, T*); + +template <> +size_t parse_node(StreamReader* sr, Component* node) { + node->setName(sr->readString("name")); + + const auto parent_index = sr->readUInt16("parent"); + + SkDebugf(".. %s -> %d\n", node->getName().c_str(), parent_index); + + return parent_index; +} + +} // namespace internal + +void Component::invalidate() { + auto* node = this; + + do { + node->fDirty = true; + node = node->fParent; + } while (node && !node->hasInval()); +} + +void Component::revalidate() { + if (this->hasInval()) { + this->onRevalidate(); + fDirty = false; + } +} + +} // namespace skrive diff --git a/experimental/skrive/src/Node.cpp b/experimental/skrive/src/Node.cpp index 75c1c68736..2cb25b393f 100644 --- a/experimental/skrive/src/Node.cpp +++ b/experimental/skrive/src/Node.cpp @@ -19,8 +19,7 @@ size_t parse_node(StreamReader*, T*); template <> size_t parse_node(StreamReader* sr, Node* node) { - node->setName(sr->readString("name")); - const auto parent = sr->readUInt16("parent"); + const auto parent_index = parse_node(sr, node); node->setTranslation(sr->readV2("translation")); node->setRotation(sr->readFloat("rotation")); @@ -28,8 +27,6 @@ size_t parse_node(StreamReader* sr, Node* node) { node->setOpacity(sr->readFloat("opacity")); node->setCollapsedVisibility(sr->readBool("isCollapsed")); - SkDebugf(".. '%s' -> %d\n", node->getName().c_str(), parent); - if (sr->openArray("clips")) { const auto count = sr->readLength8(); @@ -48,13 +45,25 @@ size_t parse_node(StreamReader* sr, Node* node) { sr->closeArray(); } - return parent; + return parent_index; } } // namespace skrive -SkRect Node::onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) { - return this->INHERITED::onRevalidate(ic, ctm); +void Node::addChild(sk_sp child) { + child->fParent = this; + fChildren.push_back(std::move(child)); + this->invalidate(); +} + +void Node::onRevalidate() { + SkASSERT(this->hasInval()); + + for (const auto& child : fChildren) { + if (child) { + child->revalidate(); + } + } } } // namespace internal diff --git a/experimental/skrive/src/Shape.cpp b/experimental/skrive/src/Shape.cpp index 8584e89847..1091216161 100644 --- a/experimental/skrive/src/Shape.cpp +++ b/experimental/skrive/src/Shape.cpp @@ -9,7 +9,9 @@ #include "experimental/skrive/src/reader/StreamReader.h" -namespace skrive::internal { +namespace skrive { +namespace internal { + template size_t parse_node(StreamReader*, T*); @@ -22,4 +24,8 @@ size_t parse_node(StreamReader* sr, Shape* node) { return parent_index; } -} // namespace skrive::internal +} // namespace internal + +void Shape::onRevalidate() {} + +} // namespace skrive diff --git a/experimental/skrive/tests/DomTypes.cpp b/experimental/skrive/tests/DomTypes.cpp new file mode 100644 index 0000000000..0be6855faa --- /dev/null +++ b/experimental/skrive/tests/DomTypes.cpp @@ -0,0 +1,35 @@ +/* + * 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 "experimental/skrive/include/SkRive.h" +#include "tests/Test.h" + +template +void check_type(skiatest::Reporter* reporter, const sk_sp& node, bool expected) { + REPORTER_ASSERT(reporter, node->template is() == expected); + REPORTER_ASSERT(reporter, !!static_cast(*node.get()) == expected); +} + +DEF_TEST(SkRive_DomTypes, reporter) { + { + auto node = sk_make_sp(); + + check_type(reporter, node, true); + check_type(reporter, node, true); + check_type(reporter, node, false); + check_type(reporter, node, false); + } + + { + auto node = sk_make_sp(); + + check_type(reporter, node, true); + check_type(reporter, node, true); + check_type(reporter, node, true); + check_type(reporter, node, true); + } +} diff --git a/tools/viewer/SkRiveSlide.cpp b/tools/viewer/SkRiveSlide.cpp index 5be5d81ef2..de29104c01 100644 --- a/tools/viewer/SkRiveSlide.cpp +++ b/tools/viewer/SkRiveSlide.cpp @@ -62,7 +62,6 @@ void SkRiveSlide::draw(SkCanvas* canvas) { SkMatrix::kCenter_ScaleToFit )); for (const auto& ab : fRive->artboards()) { - ab->revalidate(nullptr, SkMatrix::I()); ab->render(canvas); } }