blob: 53378ce02520f5cf35321a03f2904e7c79b782ab [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_TRAVERSAL_ROOT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_TRAVERSAL_ROOT_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/container_node.h"
namespace blink {
// Class used to represent a common ancestor for all dirty nodes in a DOM tree.
// Subclasses implement the various types of dirtiness for style recalc, style
// invalidation, and layout tree rebuild. The common ancestor is used as a
// starting point for traversal to avoid unnecessary DOM tree traversal.
//
// The first dirty node is stored as a single root. When a second node is
// added with a common child-dirty ancestor which is not dirty, we store that
// as a common root. Any subsequent dirty nodes added whose closest child-dirty
// ancestor is not itself dirty, or is the current root, will cause us to fall
// back to use the document as the root node. In order to find a lowest common
// ancestor we would have had to traverse up the ancestor chain to see if we are
// below the current common root or not.
//
// Note that when the common ancestor candidate passed into Update is itself
// dirty, we know that we are currently below the current root node and don't
// have to modify it.
class CORE_EXPORT StyleTraversalRoot {
DISALLOW_NEW();
public:
// Update the common ancestor root when dirty_node is marked dirty. The
// common_ancestor is the closest ancestor of dirty_node which was already
// marked as having dirty children.
void Update(ContainerNode* common_ancestor, Node* dirty_node);
// Update the root node if the current has been removed from the tree.
// The 'tree' here may refer to the flat tree if marking ancestors happen in
// the flat for the given subclass.
virtual void SubtreeModified(ContainerNode& parent) = 0;
Node* GetRootNode() const { return root_node_; }
void Clear() {
root_node_ = nullptr;
root_type_ = RootType::kSingleRoot;
}
void Trace(Visitor* visitor) const { visitor->Trace(root_node_); }
protected:
virtual ~StyleTraversalRoot() = default;
#if DCHECK_IS_ON()
// Return the parent node for type of traversal for which the implementation
// is a root.
virtual ContainerNode* Parent(const Node&) const = 0;
// Return true if the given node is marked dirty or child-dirty.
virtual bool IsChildDirty(const Node&) const = 0;
#endif // DCHECK_IS_ON()
// Return true if the given node is dirty.
virtual bool IsDirty(const Node&) const = 0;
bool IsSingleRoot() const { return root_type_ == RootType::kSingleRoot; }
private:
friend class StyleTraversalRootTestImpl;
#if DCHECK_IS_ON()
bool RootIsBeingRemoved() const;
#endif
void AssertRootNodeInvariants() {
#if DCHECK_IS_ON()
DCHECK(!root_node_ || root_node_->IsDocumentNode() ||
IsDirty(*root_node_) || IsChildDirty(*root_node_) ||
RootIsBeingRemoved());
#endif
}
// The current root for dirty nodes.
Member<Node> root_node_;
// Is the current root a common ancestor or a single dirty node.
enum class RootType { kSingleRoot, kCommonRoot };
RootType root_type_ = RootType::kSingleRoot;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_TRAVERSAL_ROOT_H_