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    using INHERITED = SkRefCnt;
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