skia2/experimental/sksg/SkSGNode.h
Florin Malita c75e2401a8 [sksg] Refine invalidation logic
We need to discriminate between nodes whose bounds updates contribute to the dirty
region, and nodes whose bounds changes do not.

E.g. animated shape in a group: the animated shape node bounds should yield damage,
but the ancestor group bounds should not.

To accomplish this, we refine the invalidation state:

  1) self invalidation == the node itself was invalidated, and its bounds updates
     yield damage.
  2) descendant invalidation == the node has some (self-)invalidated descendant,
     but its own bounds are not contributing damage.

Also:

  * hoist the bounding box invalidation logic into the base class (Node::revalidate)
    and update to respect the states described above.
  * remove (now-redundant) GeometryNode bbox logic.
  * update revalidation methods to return the node bbox instead of void

TBR=
Change-Id: I8023d1793fb501c945a53f2dc2d2983e5b620ade
Reviewed-on: https://skia-review.googlesource.com/90581
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
2018-01-04 00:59:20 +00:00

94 lines
2.8 KiB
C++

/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkSGNode_DEFINED
#define SkSGNode_DEFINED
#include "SkRect.h"
#include "SkRefCnt.h"
#include "SkTDArray.h"
class SkCanvas;
class SkMatrix;
namespace sksg {
class InvalidationController;
/**
* Base class for all scene graph nodes.
*
* Handles ingress edge management for the DAG (i.e. node -> "parent" node mapping),
* and invalidation.
*
* Note: egress edges are only implemented/supported in container subclasses
* (e.g. Group, Effect, Draw).
*/
class Node : public SkRefCnt {
public:
// Traverse the DAG and revalidate any dependant/invalidated nodes.
// Returns the bounding box for the DAG fragment.
const SkRect& revalidate(InvalidationController*, const SkMatrix&);
protected:
Node();
~Node() override;
void invalidateSelf();
void invalidateAncestors();
bool hasSelfInval() const { return fFlags & kInvalSelf_Flag; }
bool hasDescendantInval() const { return fFlags & kInvalDescendant_Flag; }
bool hasInval() const { return this->hasSelfInval() || this->hasDescendantInval(); }
// Dispatched on revalidation. Subclasses are expected to recompute/cache their properties
// and return their bounding box in local coordinates.
virtual SkRect onRevalidate(InvalidationController*, const SkMatrix& ctm) = 0;
private:
void addInvalReceiver(Node*);
void removeInvalReceiver(Node*);
friend class Draw;
friend class EffectNode;
friend class Group;
friend class Stroke;
template <typename Func>
void forEachInvalReceiver(Func&&) const;
enum Flags {
kInvalSelf_Flag = 1 << 0, // the node requires revalidation
kInvalDescendant_Flag = 1 << 1, // the node's descendents require invalidation
kReceiverArray_Flag = 1 << 2, // the node has more than one inval receiver
kInTraversal_Flag = 1 << 3, // the node is part of a traversal (cycle detection)
};
class ScopedFlag;
union {
Node* fInvalReceiver;
SkTDArray<Node*>* fInvalReceiverArray;
};
SkRect fBounds;
uint32_t fFlags;
typedef SkRefCnt INHERITED;
};
// Helper for defining attribute getters/setters in subclasses.
#define SG_ATTRIBUTE(attr_name, attr_type, attr_container) \
attr_type get##attr_name() const { return attr_container; } \
void set##attr_name(attr_type v) { \
if (attr_container == v) return; \
attr_container = v; \
this->invalidateSelf(); \
}
} // namespace sksg
#endif // SkSGNode_DEFINED