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