diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/page/scrolling/ScrollingStateTree.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/page/scrolling/ScrollingStateTree.cpp')
-rw-r--r-- | Source/WebCore/page/scrolling/ScrollingStateTree.cpp | 191 |
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) |