| /* |
| * Copyright 2017 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef SkSGNode_DEFINED |
| #define SkSGNode_DEFINED |
| |
| #include "include/core/SkRect.h" |
| #include "include/core/SkRefCnt.h" |
| |
| #include <vector> |
| |
| class SkCanvas; |
| class SkMatrix; |
| |
| namespace sksg { |
| |
| class InvalidationController; |
| |
| /** |
| * Base class for all scene graph nodes. |
| * |
| * Handles ingress edge management for the DAG (i.e. node -> "parent" node mapping), |
| * and invalidation. |
| * |
| * Note: egress edges are only implemented/supported in container subclasses |
| * (e.g. Group, Effect, Draw). |
| */ |
| class Node : public SkRefCnt { |
| public: |
| // Traverse the DAG and revalidate any dependant/invalidated nodes. |
| // Returns the bounding box for the DAG fragment. |
| const SkRect& revalidate(InvalidationController*, const SkMatrix&); |
| |
| protected: |
| enum InvalTraits { |
| // Nodes with this trait never generate direct damage -- instead, |
| // the damage bubbles up to ancestors. |
| kBubbleDamage_Trait = 1 << 0, |
| |
| // Nodes with this trait obscure the descendants' damage and always override it. |
| kOverrideDamage_Trait = 1 << 1, |
| }; |
| |
| explicit Node(uint32_t invalTraits); |
| ~Node() override; |
| |
| const SkRect& bounds() const { |
| SkASSERT(!this->hasInval()); |
| return fBounds; |
| } |
| |
| // Tag this node for invalidation and optional damage. |
| void invalidate(bool damage = true); |
| bool hasInval() const { return fFlags & kInvalidated_Flag; } |
| |
| // Dispatched on revalidation. Subclasses are expected to recompute/cache their properties |
| // and return their bounding box in local coordinates. |
| virtual SkRect onRevalidate(InvalidationController*, const SkMatrix& ctm) = 0; |
| |
| // Register/unregister |this| to receive invalidation events from a descendant. |
| void observeInval(const sk_sp<Node>&); |
| void unobserveInval(const sk_sp<Node>&); |
| |
| private: |
| enum Flags { |
| kInvalidated_Flag = 1 << 0, // the node or its descendants require revalidation |
| kDamage_Flag = 1 << 1, // the node contributes damage during revalidation |
| kObserverArray_Flag = 1 << 2, // the node has more than one inval observer |
| kInTraversal_Flag = 1 << 3, // the node is part of a traversal (cycle detection) |
| }; |
| |
| template <typename Func> |
| void forEachInvalObserver(Func&&) const; |
| |
| class ScopedFlag; |
| |
| union { |
| Node* fInvalObserver; |
| std::vector<Node*>* fInvalObserverArray; |
| }; |
| SkRect fBounds; |
| const uint32_t fInvalTraits : 2; |
| uint32_t fFlags : 4; // Internal flags. |
| uint32_t fNodeFlags : 8; // Accessible from select subclasses. |
| // Free bits : 18; |
| |
| friend class NodePriv; |
| friend class RenderNode; // node flags access |
| |
| using INHERITED = SkRefCnt; |
| }; |
| |
| // Helper for defining attribute getters/setters in subclasses. |
| #define SG_ATTRIBUTE(attr_name, attr_type, attr_container) \ |
| const attr_type& get##attr_name() const { return attr_container; } \ |
| void set##attr_name(const attr_type& v) { \ |
| if (attr_container == v) return; \ |
| attr_container = v; \ |
| this->invalidate(); \ |
| } \ |
| void set##attr_name(attr_type&& v) { \ |
| if (attr_container == v) return; \ |
| attr_container = std::move(v); \ |
| this->invalidate(); \ |
| } |
| |
| #define SG_MAPPED_ATTRIBUTE(attr_name, attr_type, attr_container) \ |
| attr_type get##attr_name() const { return attr_container.get##attr_name(); } \ |
| void set##attr_name(const attr_type& v) { \ |
| if (attr_container.get##attr_name() == v) return; \ |
| attr_container.set##attr_name(v); \ |
| this->invalidate(); \ |
| } \ |
| void set##attr_name(attr_type&& v) { \ |
| if (attr_container.get##attr_name() == v) return; \ |
| attr_container.set##attr_name(std::move(v)); \ |
| this->invalidate(); \ |
| } |
| |
| } // namespace sksg |
| |
| #endif // SkSGNode_DEFINED |