blob: bcd4ba98b4b55d8b61535cee9bf1a96f2717c657 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/css/layout_tree_rebuild_root.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
namespace blink {
Element& LayoutTreeRebuildRoot::RootElement() const {
Node* root_node = GetRootNode();
DCHECK(root_node);
DCHECK(root_node->isConnected());
DCHECK(root_node->GetDocument().documentElement());
// We need to start from the closest non-dirty ancestor which has a
// LayoutObject to make WhitespaceAttacher work correctly because text node
// siblings of nodes being re-attached needs to be traversed to re-evaluate
// the need for a LayoutText. Single roots are typically dirty, but we need an
// extra check for IsSingleRoot() because we mark nodes which have siblings
// removed with MarkAncestorsWithChildNeedsReattachLayoutTree() in
// Element::RecalcStyle() if the LayoutObject is marked with
// WhitespaceChildrenMayChange(). In that case we need to start from the
// ancestor to traverse all whitespace siblings.
if (IsSingleRoot() || root_node->IsDirtyForRebuildLayoutTree() ||
!root_node->GetLayoutObject()) {
Element* root_element = root_node->GetReattachParent();
while (root_element && !root_element->GetLayoutObject()) {
root_element = root_element->GetReattachParent();
}
if (root_element) {
return *root_element;
}
}
if (Element* element = DynamicTo<Element>(root_node)) {
return *element;
}
return *root_node->GetDocument().documentElement();
}
#if DCHECK_IS_ON()
ContainerNode* LayoutTreeRebuildRoot::Parent(const Node& node) const {
return node.GetReattachParent();
}
bool LayoutTreeRebuildRoot::IsChildDirty(const Node& node) const {
return node.ChildNeedsReattachLayoutTree();
}
#endif // DCHECK_IS_ON()
bool LayoutTreeRebuildRoot::IsDirty(const Node& node) const {
return node.IsDirtyForRebuildLayoutTree();
}
void LayoutTreeRebuildRoot::SubtreeModified(ContainerNode& parent) {
if (!GetRootNode()) {
return;
}
if (GetRootNode()->isConnected()) {
return;
}
// LayoutTreeRebuildRoot is only used for marking for layout tree rebuild
// during style recalc. We do not allow DOM modifications during style recalc
// or the layout tree rebuild that happens right after. The only time we
// should end up here is when we find out that we need to remove generated
// pseudo elements like ::first-letter or ::marker during layout tree rebuild.
DCHECK(parent.isConnected());
DCHECK(GetRootNode()->IsPseudoElement());
Element* ancestor = DynamicTo<Element>(parent);
if (!ancestor) {
// The parent should be the pseudo element's originating element.
NOTREACHED();
ancestor = parent.ParentOrShadowHostElement();
}
for (; ancestor; ancestor = ancestor->GetReattachParent()) {
DCHECK(ancestor->ChildNeedsReattachLayoutTree());
DCHECK(!ancestor->IsDirtyForRebuildLayoutTree());
ancestor->ClearChildNeedsReattachLayoutTree();
}
Clear();
}
} // namespace blink