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