| Index: content/browser/web_contents/web_contents_impl.cc
|
| diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
| index bb4128c8f0fda709aef73e59c5b2819c0d1bd7d6..7d8261b22f7c55537b27838106f8a8a33b7e84ee 100644
|
| --- a/content/browser/web_contents/web_contents_impl.cc
|
| +++ b/content/browser/web_contents/web_contents_impl.cc
|
| @@ -328,28 +328,30 @@ WebContentsImpl::ColorChooserInfo::~ColorChooserInfo() {
|
| }
|
|
|
| // WebContentsImpl::WebContentsTreeNode ----------------------------------------
|
| -WebContentsImpl::WebContentsTreeNode::WebContentsTreeNode()
|
| - : outer_web_contents_(nullptr),
|
| +WebContentsImpl::WebContentsTreeNode::WebContentsTreeNode(
|
| + WebContentsImpl* web_contents)
|
| + : web_contents_(web_contents),
|
| + outer_web_contents_(nullptr),
|
| outer_contents_frame_tree_node_id_(
|
| - FrameTreeNode::kFrameTreeNodeInvalidId) {
|
| -}
|
| + FrameTreeNode::kFrameTreeNodeInvalidId) {}
|
|
|
| WebContentsImpl::WebContentsTreeNode::~WebContentsTreeNode() {
|
| // Remove child pointer from our parent.
|
| if (outer_web_contents_) {
|
| - ChildrenSet& child_ptrs_in_parent =
|
| + ChildrenMap& child_ptrs_in_parent =
|
| outer_web_contents_->node_->inner_web_contents_tree_nodes_;
|
| - ChildrenSet::iterator iter = child_ptrs_in_parent.find(this);
|
| + ChildrenMap::iterator iter =
|
| + child_ptrs_in_parent.find(outer_contents_frame_tree_node_id_);
|
| DCHECK(iter != child_ptrs_in_parent.end());
|
| - child_ptrs_in_parent.erase(this);
|
| + child_ptrs_in_parent.erase(iter);
|
| }
|
|
|
| // Remove parent pointers from our children.
|
| // TODO(lazyboy): We should destroy the children WebContentses too. If the
|
| // children do not manage their own lifetime, then we would leak their
|
| // WebContentses.
|
| - for (WebContentsTreeNode* child : inner_web_contents_tree_nodes_)
|
| - child->outer_web_contents_ = nullptr;
|
| + for (auto& child : inner_web_contents_tree_nodes_)
|
| + child.second->outer_web_contents_ = nullptr;
|
| }
|
|
|
| void WebContentsImpl::WebContentsTreeNode::ConnectToOuterWebContents(
|
| @@ -360,9 +362,22 @@ void WebContentsImpl::WebContentsTreeNode::ConnectToOuterWebContents(
|
| outer_contents_frame->frame_tree_node()->frame_tree_node_id();
|
|
|
| if (!outer_web_contents_->node_)
|
| - outer_web_contents_->node_.reset(new WebContentsTreeNode());
|
| + outer_web_contents_->node_.reset(
|
| + new WebContentsTreeNode(outer_web_contents_));
|
| +
|
| + outer_web_contents_->node_
|
| + ->inner_web_contents_tree_nodes_[outer_contents_frame_tree_node_id_] =
|
| + this;
|
| +}
|
|
|
| - outer_web_contents_->node_->inner_web_contents_tree_nodes_.insert(this);
|
| +const WebContentsImpl*
|
| +WebContentsImpl::WebContentsTreeNode::FindInnerWebContentsAtFrame(
|
| + const FrameTreeNode* node) const {
|
| + auto iter = inner_web_contents_tree_nodes_.find(node->frame_tree_node_id());
|
| + if (iter != inner_web_contents_tree_nodes_.end()) {
|
| + return iter->second->web_contents_;
|
| + }
|
| + return nullptr;
|
| }
|
|
|
| // WebContentsImpl -------------------------------------------------------------
|
| @@ -1393,7 +1408,7 @@ void WebContentsImpl::AttachToOuterWebContentsFrame(
|
| CreateRenderWidgetHostViewForRenderManager(GetRenderViewHost());
|
|
|
| // Create a link to our outer WebContents.
|
| - node_.reset(new WebContentsTreeNode());
|
| + node_.reset(new WebContentsTreeNode(this));
|
| node_->ConnectToOuterWebContents(
|
| static_cast<WebContentsImpl*>(outer_web_contents),
|
| static_cast<RenderFrameHostImpl*>(outer_contents_frame));
|
| @@ -1793,6 +1808,15 @@ RenderWidgetHostImpl* WebContentsImpl::GetFocusedRenderWidgetHost(
|
| if (!focused_frame)
|
| return receiving_widget;
|
|
|
| + // If there is an inner web contents (<webview>, <guestview>, ...) with focus,
|
| + // return its RenderWidgetHost. This will recurse to an arbitrary number of
|
| + // WebContents to the deepest focused one.
|
| + WebContentsImpl* inner_contents =
|
| + (node_) ? node_->FindInnerWebContentsAtFrame(focused_frame) : nullptr;
|
| + if (inner_contents) {
|
| + return inner_contents->GetFocusedRenderWidgetHost(
|
| + inner_contents->GetMainFrame()->GetRenderWidgetHost());
|
| + }
|
| // The view may be null if a subframe's renderer process has crashed while
|
| // the subframe has focus. Drop the event in that case. Do not give
|
| // it to the main frame, so that the user doesn't unexpectedly type into the
|
| @@ -4485,6 +4509,66 @@ void WebContentsImpl::EnsureOpenerProxiesExist(RenderFrameHost* source_rfh) {
|
| }
|
| }
|
|
|
| +void WebContentsImpl::SetFocusedFrame(FrameTreeNode* node,
|
| + SiteInstance* source) {
|
| + SetFocusedFrameInternal(node, source, true /* can visit outer contents */);
|
| +
|
| + RenderWidgetHostImpl* rwh = node->current_frame_host()->GetRenderWidgetHost();
|
| + if (rwh)
|
| + rwh->Focus();
|
| +}
|
| +
|
| +void WebContentsImpl::SetFocusedFrameInternal(FrameTreeNode* node,
|
| + SiteInstance* source,
|
| + bool can_visit_outer_contents) {
|
| + // Approach: Recursively unfocus any inner web contents. Then set
|
| + // representation of this web contents in the outer contents to be focused,
|
| + // finally focus the node in current frame tree.
|
| + //
|
| + // Usually only one of unfocusing children and focusing self in parent would
|
| + // happen. If unfocusing a child, then we're already focused in our parent, if
|
| + // we have one.
|
| +
|
| + FrameTreeNode* old_focused_node = frame_tree_.GetFocusedFrame();
|
| +
|
| + if (old_focused_node != nullptr && node_) {
|
| + if (!node || old_focused_node != node) {
|
| + WebContentsImpl* inner_contents =
|
| + node_->FindInnerWebContentsAtFrame(old_focused_node);
|
| + if (inner_contents)
|
| + inner_contents->SetFocusedFrameInternal(nullptr, source, false);
|
| + }
|
| + }
|
| +
|
| + // focus in parent.
|
| + WebContentsImpl* outer_contents = GetOuterWebContents();
|
| + // If we're coming from parent, we don't want to recurse back into the parent.
|
| + if (outer_contents && can_visit_outer_contents) {
|
| + FrameTreeNode* outer_node =
|
| + outer_contents->frame_tree_.FindByID(GetOuterDelegateFrameTreeNodeId());
|
| + if (outer_node == nullptr) {
|
| + // With browser plugin, we will have an outer contents but no node in the
|
| + // outer contents' frame tree.
|
| + // HACK: We are assuming that the guest contents can only be embedded
|
| + // within the embedder's main frame.
|
| + outer_contents->SetFocusedFrameInternal(
|
| + outer_contents->frame_tree_.root(), source, true);
|
| + } else {
|
| + // Notify outer about our focus change.
|
| + SiteInstance* outer_node_site_instance =
|
| + outer_node->parent()->current_frame_host()->GetSiteInstance();
|
| + RenderFrameProxyHost* outer_proxy =
|
| + frame_tree_.root()->render_manager()->GetRenderFrameProxyHost(
|
| + outer_node_site_instance);
|
| + if (outer_proxy)
|
| + outer_proxy->SetFocusedFrame();
|
| + outer_contents->SetFocusedFrameInternal(outer_node, source, true);
|
| + }
|
| + }
|
| + // Set focus for myself.
|
| + frame_tree_.SetFocusedFrame(node, source);
|
| +}
|
| +
|
| bool WebContentsImpl::AddMessageToConsole(int32_t level,
|
| const base::string16& message,
|
| int32_t line_no,
|
|
|