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 #include "SkRectPriv.h"
9 #include "SkSGNode.h"
10 #include "SkSGInvalidationController.h"
11 
12 namespace sksg {
13 
14 class Node::ScopedFlag {
15 public:
16     ScopedFlag(Node* node, uint32_t flag)
17         : fNode(node)
18         , fFlag(flag)
19         , fWasSet(node->fFlags & flag) {
20         node->fFlags |= flag;
21     }
22     ~ScopedFlag() {
23         if (!fWasSet) {
24             fNode->fFlags &= ~fFlag;;
25         }
26     }
27 
28     bool wasSet() const { return fWasSet; }
29 
30 private:
31     Node*    fNode;
32     uint32_t fFlag;
33     bool     fWasSet;
34 };
35 
36 #define TRAVERSAL_GUARD                                  \
37     ScopedFlag traversal_guard(this, kInTraversal_Flag); \
38     if (traversal_guard.wasSet())                        \
39         return
40 
41 Node::Node(uint32_t invalTraits)
42     : fInvalObserver(nullptr)
43     , fBounds(SkRectPriv::MakeLargeS32())
44     , fInvalTraits(invalTraits)
45     , fFlags(kInvalidated_Flag) {}
46 
47 Node::~Node() {
48     if (fFlags & kObserverArray_Flag) {
49         SkASSERT(fInvalObserverArray->isEmpty());
50         delete fInvalObserverArray;
51     } else {
52         SkASSERT(!fInvalObserver);
53     }
54 }
55 
56 void Node::observeInval(const sk_sp<Node>& node) {
57     SkASSERT(node);
58     if (!(node->fFlags & kObserverArray_Flag)) {
59         if (!node->fInvalObserver) {
60             node->fInvalObserver = this;
61             return;
62         }
63 
64         auto observers = new SkTDArray<Node*>();
65         observers->setReserve(2);
66         observers->push(node->fInvalObserver);
67 
68         node->fInvalObserverArray = observers;
69         node->fFlags |= kObserverArray_Flag;
70     }
71 
72     // No duplicate observers.
73     SkASSERT(node->fInvalObserverArray->find(this) < 0);
74 
75     node->fInvalObserverArray->push(this);
76 }
77 
78 void Node::unobserveInval(const sk_sp<Node>& node) {
79     SkASSERT(node);
80     if (!(node->fFlags & kObserverArray_Flag)) {
81         SkASSERT(node->fInvalObserver == this);
82         node->fInvalObserver = nullptr;
83         return;
84     }
85 
86     const auto idx = node->fInvalObserverArray->find(this);
87     SkASSERT(idx >= 0);
88     node->fInvalObserverArray->remove(idx);
89 }
90 
91 template <typename Func>
92 void Node::forEachInvalObserver(Func&& func) const {
93     if (fFlags & kObserverArray_Flag) {
94         for (const auto& parent : *fInvalObserverArray) {
95             func(parent);
96         }
97         return;
98     }
99 
100     if (fInvalObserver) {
101         func(fInvalObserver);
102     }
103 }
104 
105 void Node::invalidate(bool damageBubbling) {
106     TRAVERSAL_GUARD;
107 
108     if (this->hasInval() && (!damageBubbling || (fFlags & kDamage_Flag))) {
109         // All done.
110         return;
111     }
112 
113     if (damageBubbling && !(fInvalTraits & kBubbleDamage_Trait)) {
114         // Found a damage observer.
115         fFlags |= kDamage_Flag;
116         damageBubbling = false;
117     }
118 
119     fFlags |= kInvalidated_Flag;
120 
121     forEachInvalObserver([&](Node* observer) {
122         observer->invalidate(damageBubbling);
123     });
124 }
125 
126 const SkRect& Node::revalidate(InvalidationController* ic, const SkMatrix& ctm) {
127     TRAVERSAL_GUARD fBounds;
128 
129     if (!this->hasInval()) {
130         return fBounds;
131     }
132 
133     SkRect prevBounds;
134     if (fFlags & kDamage_Flag) {
135         prevBounds = fBounds;
136     }
137 
138     fBounds = this->onRevalidate(ic, ctm);
139 
140     if (fFlags & kDamage_Flag) {
141         ic->inval(prevBounds, ctm);
142         if (fBounds != prevBounds) {
143             ic->inval(fBounds, ctm);
144         }
145     }
146 
147     fFlags &= ~(kInvalidated_Flag | kDamage_Flag);
148 
149     return fBounds;
150 }
151 
152 } // namespace sksg
153