• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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