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

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: Ready for review: Fix works with oopif webview but does not fix crbug.com/609903 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..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,

Powered by Google App Engine
This is Rietveld 408576698