xref: /third_party/skia/modules/sksg/src/SkSGNode.cpp (revision cb93a386)
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