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