Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Unified Diff: content/browser/web_contents/web_contents_impl.cc

Issue 1934703002: Fix keyboard focus for OOPIF-<webview>. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address comments. Fix tab focus change. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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,

Powered by Google App Engine
This is Rietveld 408576698