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