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:
ScopedFlag(Node * node,uint32_t flag)16 ScopedFlag(Node* node, uint32_t flag)
17 : fNode(node)
18 , fFlag(flag)
19 , fWasSet(node->fFlags & flag) {
20 node->fFlags |= flag;
21 }
~ScopedFlag()22 ~ScopedFlag() {
23 if (!fWasSet) {
24 fNode->fFlags &= ~fFlag;;
25 }
26 }
27
wasSet() const28 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
Node(uint32_t invalTraits)41 Node::Node(uint32_t invalTraits)
42 : fInvalObserver(nullptr)
43 , fBounds(SkRectPriv::MakeLargeS32())
44 , fInvalTraits(invalTraits)
45 , fFlags(kInvalidated_Flag) {}
46
~Node()47 Node::~Node() {
48 if (fFlags & kObserverArray_Flag) {
49 SkASSERT(fInvalObserverArray->isEmpty());
50 delete fInvalObserverArray;
51 } else {
52 SkASSERT(!fInvalObserver);
53 }
54 }
55
observeInval(const sk_sp<Node> & node)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
unobserveInval(const sk_sp<Node> & node)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>
forEachInvalObserver(Func && func) const92 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
invalidate(bool damageBubbling)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
revalidate(InvalidationController * ic,const SkMatrix & ctm)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