Chromium Code Reviews| 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..facfbbc33ba2bb026880fc4da37f2b0bc6c764bb 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* inner) |
| + : inner_web_contents_(inner), |
| + 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 children : inner_web_contents_tree_nodes_) |
|
lfg
2016/05/06 21:23:33
Use auto&, so you don't make a copy of the pair to
avallee
2016/05/11 18:26:11
Done.
|
| + children.second->outer_web_contents_ = nullptr; |
| } |
| void WebContentsImpl::WebContentsTreeNode::ConnectToOuterWebContents( |
| @@ -360,9 +362,21 @@ 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); |
| +WebContentsImpl* WebContentsImpl::WebContentsTreeNode::find_contents_for_frame( |
| + int frame_id) const { |
| + auto iter = inner_web_contents_tree_nodes_.find(frame_id); |
| + if (iter != inner_web_contents_tree_nodes_.end()) { |
| + return iter->second->inner_web_contents_; |
| + } |
| + return nullptr; |
| } |
| // WebContentsImpl ------------------------------------------------------------- |
| @@ -1393,7 +1407,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 +1807,16 @@ RenderWidgetHostImpl* WebContentsImpl::GetFocusedRenderWidgetHost( |
| if (!focused_frame) |
| return receiving_widget; |
| + // If there is an inner web contents (<webview>, <guestview>, ...) with focus, |
| + // return its RenderWidgetHost. |
| + WebContentsImpl* inner_contents = |
| + (node_.get()) |
| + ? node_->find_contents_for_frame(focused_frame->frame_tree_node_id()) |
| + : 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,68 @@ void WebContentsImpl::EnsureOpenerProxiesExist(RenderFrameHost* source_rfh) { |
| } |
| } |
| +void WebContentsImpl::SetFocusedFrame(FrameTreeNode* node, |
| + SiteInstance* source) { |
| + SetFocusedFrameInternal(node, source, true /* can visit outer contents */); |
| + |
| + auto rwh = node->current_frame_host()->GetRenderWidgetHost(); |
| + if (rwh) { |
|
lfg
2016/05/06 21:23:33
nit: {}
avallee
2016/05/11 18:26:11
Done.
|
| + 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. |
| + |
| + auto old_focus_node = frame_tree_.GetFocusedFrame(); |
| + |
| + if (old_focus_node != nullptr && node_.get()) { |
| + if (!node || old_focus_node != node) { |
| + WebContentsImpl* inner_contents = |
| + node_->find_contents_for_frame(old_focus_node->frame_tree_node_id()); |
| + if (inner_contents) { |
|
lfg
2016/05/06 21:23:33
nit: {}
avallee
2016/05/11 18:26:11
Done.
|
| + inner_contents->SetFocusedFrameInternal(nullptr, source, false); |
| + } |
| + } |
| + } |
| + |
| + // focus in parent. |
| + auto 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) { |
| + auto 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. |
| + // maybe focus outer main frame. |
|
lfg
2016/05/06 21:23:33
Not sure I follow this. Why are we focusing the ro
avallee
2016/05/11 18:26:11
Comment should answer this. It's not ideal, but it
|
| + outer_contents->SetFocusedFrameInternal( |
| + outer_contents->frame_tree_.root(), source, true); |
| + } else { |
| + // Notify outer about our focus change. |
| + auto outer_node_site_instance = |
| + outer_node->current_frame_host()->GetSiteInstance(); |
|
lfg
2016/05/06 21:23:33
I think this should be outer_node->parent()->curre
avallee
2016/05/11 18:26:11
Done.
|
| + auto outer_proxy = |
| + frame_tree_.root()->render_manager()->GetRenderFrameProxyHost( |
| + outer_node_site_instance); |
| + if (outer_proxy) { |
|
lfg
2016/05/06 21:23:33
nit: {}
avallee
2016/05/11 18:26:11
Done.
|
| + 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, |