1/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkSGNode_DEFINED
9#define SkSGNode_DEFINED
10
11#include "include/core/SkRect.h"
12#include "include/core/SkRefCnt.h"
13
14#include <vector>
15
16class SkCanvas;
17class SkMatrix;
18
19namespace sksg {
20
21class InvalidationController;
22
23/**
24 * Base class for all scene graph nodes.
25 *
26 * Handles ingress edge management for the DAG (i.e. node -> "parent" node mapping),
27 * and invalidation.
28 *
29 * Note: egress edges are only implemented/supported in container subclasses
30 * (e.g. Group, Effect, Draw).
31 */
32class Node : public SkRefCnt {
33public:
34 // Traverse the DAG and revalidate any dependant/invalidated nodes.
35 // Returns the bounding box for the DAG fragment.
36 const SkRect& revalidate(InvalidationController*, const SkMatrix&);
37
38protected:
39 enum InvalTraits {
40 // Nodes with this trait never generate direct damage -- instead,
41 // the damage bubbles up to ancestors.
42 kBubbleDamage_Trait = 1 << 0,
43
44 // Nodes with this trait obscure the descendants' damage and always override it.
45 kOverrideDamage_Trait = 1 << 1,
46 };
47
48 explicit Node(uint32_t invalTraits);
49 ~Node() override;
50
51 const SkRect& bounds() const {
52 SkASSERT(!this->hasInval());
53 return fBounds;
54 }
55
56 // Tag this node for invalidation and optional damage.
57 void invalidate(bool damage = true);
58 bool hasInval() const { return fFlags & kInvalidated_Flag; }
59
60 // Dispatched on revalidation. Subclasses are expected to recompute/cache their properties
61 // and return their bounding box in local coordinates.
62 virtual SkRect onRevalidate(InvalidationController*, const SkMatrix& ctm) = 0;
63
64 // Register/unregister |this| to receive invalidation events from a descendant.
65 void observeInval(const sk_sp<Node>&);
66 void unobserveInval(const sk_sp<Node>&);
67
68private:
69 enum Flags {
70 kInvalidated_Flag = 1 << 0, // the node or its descendants require revalidation
71 kDamage_Flag = 1 << 1, // the node contributes damage during revalidation
72 kObserverArray_Flag = 1 << 2, // the node has more than one inval observer
73 kInTraversal_Flag = 1 << 3, // the node is part of a traversal (cycle detection)
74 };
75
76 template <typename Func>
77 void forEachInvalObserver(Func&&) const;
78
79 class ScopedFlag;
80
81 union {
82 Node* fInvalObserver;
83 std::vector<Node*>* fInvalObserverArray;
84 };
85 SkRect fBounds;
86 const uint32_t fInvalTraits : 2;
87 uint32_t fFlags : 4; // Internal flags.
88 uint32_t fNodeFlags : 8; // Accessible from select subclasses.
89 // Free bits : 18;
90
91 friend class NodePriv;
92 friend class RenderNode; // node flags access
93
94 typedef SkRefCnt INHERITED;
95};
96
97// Helper for defining attribute getters/setters in subclasses.
98#define SG_ATTRIBUTE(attr_name, attr_type, attr_container) \
99 const attr_type& get##attr_name() const { return attr_container; } \
100 void set##attr_name(const attr_type& v) { \
101 if (attr_container == v) return; \
102 attr_container = v; \
103 this->invalidate(); \
104 } \
105 void set##attr_name(attr_type&& v) { \
106 if (attr_container == v) return; \
107 attr_container = std::move(v); \
108 this->invalidate(); \
109 }
110
111#define SG_MAPPED_ATTRIBUTE(attr_name, attr_type, attr_container) \
112 attr_type get##attr_name() const { return attr_container.get##attr_name(); } \
113 void set##attr_name(const attr_type& v) { \
114 if (attr_container.get##attr_name() == v) return; \
115 attr_container.set##attr_name(v); \
116 this->invalidate(); \
117 } \
118 void set##attr_name(attr_type&& v) { \
119 if (attr_container.get##attr_name() == v) return; \
120 attr_container.set##attr_name(std::move(v)); \
121 this->invalidate(); \
122 }
123
124} // namespace sksg
125
126#endif // SkSGNode_DEFINED
127