| Index: content/browser/frame_host/navigation_entry_impl.cc
|
| diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
|
| index aafda050485b733938d3332713e9a5ce93c123e6..9250e6811a31745d126c71bf78b67cae448382cd 100644
|
| --- a/content/browser/frame_host/navigation_entry_impl.cc
|
| +++ b/content/browser/frame_host/navigation_entry_impl.cc
|
| @@ -116,24 +116,58 @@ bool NavigationEntryImpl::TreeNode::MatchesFrame(FrameTreeNode* frame_tree_node,
|
|
|
| std::unique_ptr<NavigationEntryImpl::TreeNode>
|
| NavigationEntryImpl::TreeNode::CloneAndReplace(
|
| - FrameTreeNode* frame_tree_node,
|
| FrameNavigationEntry* frame_navigation_entry,
|
| + bool clone_children_of_target,
|
| + FrameTreeNode* target_frame_tree_node,
|
| + FrameTreeNode* current_frame_tree_node,
|
| bool is_root_tree_node) const {
|
| - if (frame_tree_node && MatchesFrame(frame_tree_node, is_root_tree_node)) {
|
| - // Replace this node in the cloned tree and prune its children.
|
| - return base::WrapUnique(
|
| - new NavigationEntryImpl::TreeNode(frame_navigation_entry));
|
| - }
|
| -
|
| - // Clone the tree using a copy of the FrameNavigationEntry, without sharing.
|
| - // TODO(creis): Share FNEs unless it's for another tab.
|
| + // Clone this TreeNode, possibly replacing its FrameNavigationEntry.
|
| + bool is_target_frame =
|
| + target_frame_tree_node &&
|
| + MatchesFrame(target_frame_tree_node, is_root_tree_node);
|
| std::unique_ptr<NavigationEntryImpl::TreeNode> copy(
|
| - new NavigationEntryImpl::TreeNode(frame_entry->Clone()));
|
| -
|
| - // Recursively clone the children.
|
| - for (auto* child : children) {
|
| - copy->children.push_back(
|
| - child->CloneAndReplace(frame_tree_node, frame_navigation_entry, false));
|
| + new NavigationEntryImpl::TreeNode(
|
| + is_target_frame ? frame_navigation_entry : frame_entry->Clone()));
|
| +
|
| + // Recursively clone the children if needed.
|
| + if (!is_target_frame || clone_children_of_target) {
|
| + for (size_t i = 0; i < children.size(); i++) {
|
| + NavigationEntryImpl::TreeNode* child = children[i];
|
| +
|
| + // Don't check whether it's still in the tree if |current_frame_tree_node|
|
| + // is null.
|
| + if (!current_frame_tree_node) {
|
| + copy->children.push_back(child->CloneAndReplace(
|
| + frame_navigation_entry, clone_children_of_target,
|
| + target_frame_tree_node, nullptr, false));
|
| + continue;
|
| + }
|
| +
|
| + // Otherwise, make sure the frame is still in the tree before cloning it.
|
| + // This is O(N^2) in the worst case because we need to look up each frame
|
| + // (and since we want to avoid a map of unique names, which can be very
|
| + // long). To partly mitigate this, we add an optimization for the common
|
| + // case that the two child lists are the same length and are likely in the
|
| + // same order: we pick the starting offset of the inner loop to get O(N).
|
| + size_t ftn_child_count = current_frame_tree_node->child_count();
|
| + for (size_t j = 0; j < ftn_child_count; j++) {
|
| + size_t index = j;
|
| + // If the two lists of children are the same length, start looking at
|
| + // the same index as |child|.
|
| + if (children.size() == ftn_child_count)
|
| + index = (i + j) % ftn_child_count;
|
| +
|
| + if (current_frame_tree_node->child_at(index)->unique_name() ==
|
| + child->frame_entry->frame_unique_name()) {
|
| + // Found |child| in the tree. Clone it and break out of inner loop.
|
| + copy->children.push_back(child->CloneAndReplace(
|
| + frame_navigation_entry, clone_children_of_target,
|
| + target_frame_tree_node, current_frame_tree_node->child_at(index),
|
| + false));
|
| + break;
|
| + }
|
| + }
|
| + }
|
| }
|
|
|
| return copy;
|
| @@ -516,19 +550,22 @@ void NavigationEntryImpl::ClearExtraData(const std::string& key) {
|
| }
|
|
|
| std::unique_ptr<NavigationEntryImpl> NavigationEntryImpl::Clone() const {
|
| - return NavigationEntryImpl::CloneAndReplace(nullptr, nullptr);
|
| + return NavigationEntryImpl::CloneAndReplace(nullptr, false, nullptr, nullptr);
|
| }
|
|
|
| std::unique_ptr<NavigationEntryImpl> NavigationEntryImpl::CloneAndReplace(
|
| - FrameTreeNode* frame_tree_node,
|
| - FrameNavigationEntry* frame_navigation_entry) const {
|
| + FrameNavigationEntry* frame_navigation_entry,
|
| + bool clone_children_of_target,
|
| + FrameTreeNode* target_frame_tree_node,
|
| + FrameTreeNode* root_frame_tree_node) const {
|
| std::unique_ptr<NavigationEntryImpl> copy =
|
| base::WrapUnique(new NavigationEntryImpl());
|
|
|
| // TODO(creis): Only share the same FrameNavigationEntries if cloning within
|
| // the same tab.
|
| copy->frame_tree_ = frame_tree_->CloneAndReplace(
|
| - frame_tree_node, frame_navigation_entry, true);
|
| + frame_navigation_entry, clone_children_of_target, target_frame_tree_node,
|
| + root_frame_tree_node, true);
|
|
|
| // Copy most state over, unless cleared in ResetForCommit.
|
| // Don't copy unique_id_, otherwise it won't be unique.
|
|
|