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..ad213f1d8e464ca02aa254d3597e64637338f47f 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_) |
|
alexmos
2016/05/12 20:28:41
nit: s/children/child/ (it's still referring to j
avallee
2016/05/16 20:26:43
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); |
| +const WebContentsImpl* |
| +WebContentsImpl::WebContentsTreeNode::FindContentsForFrame(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. |
|
alexmos
2016/05/12 20:28:40
This will recurse down if there are multiple level
avallee
2016/05/16 20:26:43
Done.
|
| + WebContentsImpl* inner_contents = |
| + (node_.get()) |
|
alexmos
2016/05/12 20:28:42
nit: .get() shouldn't be necessary
avallee
2016/05/16 20:26:44
Done.
|
| + ? node_->FindContentsForFrame(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,66 @@ 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(); |
|
alexmos
2016/05/12 20:28:40
nit: RenderWidgetHostImpl* instead of auto might b
avallee
2016/05/16 20:26:43
Done.
|
| + if (rwh) |
| + rwh->Focus(); |
|
alexmos
2016/05/12 20:28:40
Why is this necessary? Page focus and frame focus
avallee
2016/05/16 20:26:43
Without this call, the renderer for the webview do
alexmos
2016/05/19 00:08:09
Yup, that very likely indicates a problem with pag
avallee
2016/05/24 20:07:07
Added note in code. Will fix in follow-up cl. My f
|
| +} |
| + |
| +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. |
|
alexmos
2016/05/12 20:28:40
I had trouble following this comment when I first
avallee
2016/05/16 20:26:43
Here's an enhanced version of your example https:/
alexmos
2016/05/19 00:08:09
Thanks for the detailed examples, this makes sense
avallee
2016/05/24 20:07:07
Your approach I think would work nicely. It's simp
|
| + |
| + auto old_focus_node = frame_tree_.GetFocusedFrame(); |
|
alexmos
2016/05/12 20:28:40
nit: s/old_focus_node/old_focused_node/
avallee
2016/05/16 20:26:43
Done.
|
| + |
| + if (old_focus_node != nullptr && node_.get()) { |
|
alexmos
2016/05/12 20:28:42
nit: .get() not necessary
avallee
2016/05/16 20:26:44
Done.
|
| + if (!node || old_focus_node != node) { |
| + WebContentsImpl* inner_contents = |
| + node_->FindContentsForFrame(old_focus_node->frame_tree_node_id()); |
| + if (inner_contents) |
| + inner_contents->SetFocusedFrameInternal(nullptr, source, false); |
|
alexmos
2016/05/12 20:28:41
I think this whole function could be simplified to
avallee
2016/05/16 20:26:43
I agree that the split could work.
1. Find the com
alexmos
2016/05/19 00:08:09
This makes sense, though I'm not sure if the code
|
| + } |
| + } |
| + |
| + // 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. |
| + // HACK: We are assuming that the guest contents can only be embedded |
| + // within the embedder's main frame. |
| + outer_contents->SetFocusedFrameInternal( |
|
alexmos
2016/05/12 20:28:40
Please follow up on this hack with BrowserPlugin e
avallee
2016/05/16 20:26:44
We tested it and it seems we can only embed in the
alexmos
2016/05/19 00:08:09
Acknowledged. Can you remove the "HACK" from the
avallee
2016/05/24 20:07:07
Deleted this whole function.
|
| + outer_contents->frame_tree_.root(), source, true); |
| + } else { |
| + // Notify outer about our focus change. |
| + auto outer_node_site_instance = |
| + outer_node->parent()->current_frame_host()->GetSiteInstance(); |
| + auto outer_proxy = |
| + frame_tree_.root()->render_manager()->GetRenderFrameProxyHost( |
| + outer_node_site_instance); |
| + if (outer_proxy) |
|
alexmos
2016/05/12 20:28:40
Why would outer_proxy be null? After talking thro
avallee
2016/05/16 20:26:44
Agreed, it should exist.
alexmos
2016/05/19 00:08:09
So then, can you remove this if?
avallee
2016/05/24 20:07:07
Deleted
|
| + outer_proxy->SetFocusedFrame(); |
|
alexmos
2016/05/12 20:28:42
Won't you notify the embedder's SiteInstance as pa
avallee
2016/05/16 20:26:43
For the webview specific case, the rfp that we wan
alexmos
2016/05/19 00:08:09
Sorry, I'm confused about this. Consider the samp
avallee
2016/05/24 20:07:07
I think that this is no longer necessary with the
|
| + 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, |