summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/scrolling/ScrollingStateTree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/scrolling/ScrollingStateTree.cpp')
-rw-r--r--Source/WebCore/page/scrolling/ScrollingStateTree.cpp191
1 files changed, 133 insertions, 58 deletions
diff --git a/Source/WebCore/page/scrolling/ScrollingStateTree.cpp b/Source/WebCore/page/scrolling/ScrollingStateTree.cpp
index e06f22168..0bbc1b733 100644
--- a/Source/WebCore/page/scrolling/ScrollingStateTree.cpp
+++ b/Source/WebCore/page/scrolling/ScrollingStateTree.cpp
@@ -30,15 +30,16 @@
#include "AsyncScrollingCoordinator.h"
#include "ScrollingStateFixedNode.h"
-#include "ScrollingStateScrollingNode.h"
+#include "ScrollingStateFrameScrollingNode.h"
+#include "ScrollingStateOverflowScrollingNode.h"
#include "ScrollingStateStickyNode.h"
+#include <wtf/text/CString.h>
-namespace WebCore {
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
-PassOwnPtr<ScrollingStateTree> ScrollingStateTree::create(AsyncScrollingCoordinator* scrollingCoordinator)
-{
- return adoptPtr(new ScrollingStateTree(scrollingCoordinator));
-}
+namespace WebCore {
ScrollingStateTree::ScrollingStateTree(AsyncScrollingCoordinator* scrollingCoordinator)
: m_scrollingCoordinator(scrollingCoordinator)
@@ -66,27 +67,58 @@ void ScrollingStateTree::setHasChangedProperties(bool changedProperties)
#endif
}
+Ref<ScrollingStateNode> ScrollingStateTree::createNode(ScrollingNodeType nodeType, ScrollingNodeID nodeID)
+{
+ switch (nodeType) {
+ case FixedNode:
+ return ScrollingStateFixedNode::create(*this, nodeID);
+ case StickyNode:
+ return ScrollingStateStickyNode::create(*this, nodeID);
+ case FrameScrollingNode:
+ return ScrollingStateFrameScrollingNode::create(*this, nodeID);
+ case OverflowScrollingNode:
+ return ScrollingStateOverflowScrollingNode::create(*this, nodeID);
+ }
+ ASSERT_NOT_REACHED();
+ return ScrollingStateFixedNode::create(*this, nodeID);
+}
+
+bool ScrollingStateTree::nodeTypeAndParentMatch(ScrollingStateNode& node, ScrollingNodeType nodeType, ScrollingNodeID parentID) const
+{
+ if (node.nodeType() != nodeType)
+ return false;
+
+ ScrollingStateNode* parent = stateNodeForID(parentID);
+ if (!parent)
+ return true;
+
+ return node.parent() == parent;
+}
+
ScrollingNodeID ScrollingStateTree::attachNode(ScrollingNodeType nodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID)
{
ASSERT(newNodeID);
if (ScrollingStateNode* node = stateNodeForID(newNodeID)) {
- ScrollingStateNode* parent = stateNodeForID(parentID);
- if (!parent)
- return newNodeID;
- if (node->parent() == parent)
+ if (nodeTypeAndParentMatch(*node, nodeType, parentID))
return newNodeID;
- // The node is being re-parented. To do that, we'll remove it, and then re-create a new node.
- removeNode(node);
+#if ENABLE(ASYNC_SCROLLING)
+ // If the type has changed, we need to destroy and recreate the node with a new ID.
+ if (nodeType != node->nodeType())
+ newNodeID = m_scrollingCoordinator->uniqueScrollLayerID();
+#endif
+
+ // The node is being re-parented. To do that, we'll remove it, and then create a new node.
+ removeNodeAndAllDescendants(node, SubframeNodeRemoval::Orphan);
}
- ScrollingStateNode* newNode = 0;
+ ScrollingStateNode* newNode = nullptr;
if (!parentID) {
// If we're resetting the root node, we should clear the HashMap and destroy the current children.
clear();
- setRootStateNode(ScrollingStateScrollingNode::create(*this, newNodeID));
+ setRootStateNode(ScrollingStateFrameScrollingNode::create(*this, newNodeID));
newNode = rootStateNode();
m_hasNewRootStateNode = true;
} else {
@@ -94,31 +126,22 @@ ScrollingNodeID ScrollingStateTree::attachNode(ScrollingNodeType nodeType, Scrol
if (!parent)
return 0;
- switch (nodeType) {
- case FixedNode: {
- OwnPtr<ScrollingStateFixedNode> fixedNode = ScrollingStateFixedNode::create(*this, newNodeID);
- newNode = fixedNode.get();
- parent->appendChild(fixedNode.release());
- break;
- }
- case StickyNode: {
- OwnPtr<ScrollingStateStickyNode> stickyNode = ScrollingStateStickyNode::create(*this, newNodeID);
- newNode = stickyNode.get();
- parent->appendChild(stickyNode.release());
- break;
- }
- case ScrollingNode: {
- // FIXME: We currently only support child nodes that are fixed.
- ASSERT_NOT_REACHED();
- OwnPtr<ScrollingStateScrollingNode> scrollingNode = ScrollingStateScrollingNode::create(*this, newNodeID);
- newNode = scrollingNode.get();
- parent->appendChild(scrollingNode.release());
- break;
+ if (nodeType == FrameScrollingNode && parentID) {
+ if (auto orphanedNode = m_orphanedSubframeNodes.take(newNodeID)) {
+ newNode = orphanedNode.get();
+ parent->appendChild(orphanedNode.releaseNonNull());
+ }
}
+
+ if (!newNode) {
+ auto stateNode = createNode(nodeType, newNodeID);
+ newNode = stateNode.ptr();
+ parent->appendChild(WTFMove(stateNode));
}
}
m_stateNodeMap.set(newNodeID, newNode);
+ m_nodesRemovedSinceLastCommit.remove(newNodeID);
return newNodeID;
}
@@ -132,35 +155,46 @@ void ScrollingStateTree::detachNode(ScrollingNodeID nodeID)
if (!node)
return;
- removeNode(node);
+ removeNodeAndAllDescendants(node, SubframeNodeRemoval::Orphan);
}
void ScrollingStateTree::clear()
{
- removeNode(rootStateNode());
+ if (rootStateNode())
+ removeNodeAndAllDescendants(rootStateNode());
+
m_stateNodeMap.clear();
+ m_orphanedSubframeNodes.clear();
}
-PassOwnPtr<ScrollingStateTree> ScrollingStateTree::commit(LayerRepresentation::Type preferredLayerRepresentation)
+std::unique_ptr<ScrollingStateTree> ScrollingStateTree::commit(LayerRepresentation::Type preferredLayerRepresentation)
{
+ if (!m_orphanedSubframeNodes.isEmpty()) {
+ // If we still have orphaned subtrees, remove them from m_stateNodeMap since they will be deleted
+ // when clearing m_orphanedSubframeNodes.
+ for (auto& orphanNode : m_orphanedSubframeNodes.values())
+ recursiveNodeWillBeRemoved(orphanNode.get(), SubframeNodeRemoval::Delete);
+ m_orphanedSubframeNodes.clear();
+ }
+
// This function clones and resets the current state tree, but leaves the tree structure intact.
- OwnPtr<ScrollingStateTree> treeStateClone = ScrollingStateTree::create();
+ std::unique_ptr<ScrollingStateTree> treeStateClone = std::make_unique<ScrollingStateTree>();
treeStateClone->setPreferredLayerRepresentation(preferredLayerRepresentation);
if (m_rootStateNode)
- treeStateClone->setRootStateNode(static_pointer_cast<ScrollingStateScrollingNode>(m_rootStateNode->cloneAndReset(*treeStateClone)));
+ treeStateClone->setRootStateNode(static_reference_cast<ScrollingStateFrameScrollingNode>(m_rootStateNode->cloneAndReset(*treeStateClone)));
// Copy the IDs of the nodes that have been removed since the last commit into the clone.
treeStateClone->m_nodesRemovedSinceLastCommit.swap(m_nodesRemovedSinceLastCommit);
// Now the clone tree has changed properties, and the original tree does not.
- treeStateClone->m_hasChangedProperties = true;
+ treeStateClone->m_hasChangedProperties = m_hasChangedProperties;
m_hasChangedProperties = false;
treeStateClone->m_hasNewRootStateNode = m_hasNewRootStateNode;
m_hasNewRootStateNode = false;
- return treeStateClone.release();
+ return treeStateClone;
}
void ScrollingStateTree::addNode(ScrollingStateNode* node)
@@ -168,39 +202,54 @@ void ScrollingStateTree::addNode(ScrollingStateNode* node)
m_stateNodeMap.add(node->scrollingNodeID(), node);
}
-void ScrollingStateTree::removeNode(ScrollingStateNode* node)
+void ScrollingStateTree::removeNodeAndAllDescendants(ScrollingStateNode* node, SubframeNodeRemoval subframeNodeRemoval)
{
- if (!node)
- return;
+ ScrollingStateNode* parent = node->parent();
- if (node == m_rootStateNode) {
- didRemoveNode(node->scrollingNodeID());
+ recursiveNodeWillBeRemoved(node, subframeNodeRemoval);
+
+ if (node == m_rootStateNode)
m_rootStateNode = nullptr;
+ else if (parent) {
+ ASSERT(parent->children());
+ ASSERT(parent->children()->find(node) != notFound);
+ if (auto children = parent->children()) {
+ size_t index = children->find(node);
+ if (index != notFound)
+ children->remove(index);
+ }
+ }
+}
+
+void ScrollingStateTree::recursiveNodeWillBeRemoved(ScrollingStateNode* currNode, SubframeNodeRemoval subframeNodeRemoval)
+{
+ currNode->setParent(nullptr);
+ if (subframeNodeRemoval == SubframeNodeRemoval::Orphan && currNode != m_rootStateNode && currNode->isFrameScrollingNode()) {
+ m_orphanedSubframeNodes.add(currNode->scrollingNodeID(), currNode);
return;
}
- ASSERT(m_rootStateNode);
- m_rootStateNode->removeChild(node);
+ willRemoveNode(currNode);
- // ScrollingStateTree::removeNode() will destroy children, so we have to make sure we remove those children
- // from the HashMap.
- size_t size = m_nodesRemovedSinceLastCommit.size();
- for (size_t i = 0; i < size; ++i)
- m_stateNodeMap.remove(m_nodesRemovedSinceLastCommit[i]);
+ if (auto children = currNode->children()) {
+ for (auto& child : *children)
+ recursiveNodeWillBeRemoved(child.get(), subframeNodeRemoval);
+ }
}
-void ScrollingStateTree::didRemoveNode(ScrollingNodeID nodeID)
+void ScrollingStateTree::willRemoveNode(ScrollingStateNode* node)
{
- m_nodesRemovedSinceLastCommit.append(nodeID);
+ m_nodesRemovedSinceLastCommit.add(node->scrollingNodeID());
+ m_stateNodeMap.remove(node->scrollingNodeID());
setHasChangedProperties();
}
-void ScrollingStateTree::setRemovedNodes(Vector<ScrollingNodeID> nodes)
+void ScrollingStateTree::setRemovedNodes(HashSet<ScrollingNodeID> nodes)
{
- m_nodesRemovedSinceLastCommit = std::move(nodes);
+ m_nodesRemovedSinceLastCommit = WTFMove(nodes);
}
-ScrollingStateNode* ScrollingStateTree::stateNodeForID(ScrollingNodeID scrollLayerID)
+ScrollingStateNode* ScrollingStateTree::stateNodeForID(ScrollingNodeID scrollLayerID) const
{
if (!scrollLayerID)
return 0;
@@ -215,4 +264,30 @@ ScrollingStateNode* ScrollingStateTree::stateNodeForID(ScrollingNodeID scrollLay
} // namespace WebCore
+#ifndef NDEBUG
+void showScrollingStateTree(const WebCore::ScrollingStateTree* tree)
+{
+ if (!tree)
+ return;
+
+ auto rootNode = tree->rootStateNode();
+ if (!rootNode) {
+ fprintf(stderr, "Scrolling state tree %p with no root node\n", tree);
+ return;
+ }
+
+ String output = rootNode->scrollingStateTreeAsText();
+ fprintf(stderr, "%s\n", output.utf8().data());
+}
+
+void showScrollingStateTree(const WebCore::ScrollingStateNode* node)
+{
+ if (!node)
+ return;
+
+ showScrollingStateTree(&node->scrollingStateTree());
+}
+
+#endif
+
#endif // ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS)