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

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: Blink ASSERT was missing.. 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..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();
alexmos 2016/05/19 00:08:09 I don't think you need parent() here -- seems like
avallee 2016/05/24 20:07:08 lfg suggested the change as the outer_node does no
+ 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,

Powered by Google App Engine
This is Rietveld 408576698