diff options
-rw-r--r-- | chromium/content/browser/renderer_host/render_frame_host_impl.cc | 27 | ||||
-rw-r--r-- | chromium/content/common/frame.mojom | 6 | ||||
-rw-r--r-- | chromium/content/renderer/render_view_impl.cc | 28 |
3 files changed, 41 insertions, 20 deletions
diff --git a/chromium/content/browser/renderer_host/render_frame_host_impl.cc b/chromium/content/browser/renderer_host/render_frame_host_impl.cc index 6c3b61e8580..47cb4f5ec27 100644 --- a/chromium/content/browser/renderer_host/render_frame_host_impl.cc +++ b/chromium/content/browser/renderer_host/render_frame_host_impl.cc @@ -5295,17 +5295,22 @@ void RenderFrameHostImpl::CreateNewWindow( can_create_window = false; } - bool was_consumed = false; - if (can_create_window) { - // Consume activation even w/o User Activation v2, to sync other renderers - // with calling renderer. - was_consumed = frame_tree_node_->UpdateUserActivationState( - blink::mojom::UserActivationUpdateType::kConsumeTransientActivation, - blink::mojom::UserActivationNotificationType::kNone); - } else { - std::move(callback).Run(mojom::CreateNewWindowStatus::kIgnore, nullptr); - return; - } + // If this frame isn't allowed to create a window, return early (before we + // consume transient user activation). + if (!can_create_window) { + std::move(callback).Run(mojom::CreateNewWindowStatus::kBlocked, nullptr); + return; + } + + // Otherwise, consume user activation before we proceed. In particular, it is + // important to do this before we return from the |opener_suppressed| case + // below. + // NB: This call will consume activations in the browser and the remote frame + // proxies for this frame. The initiating renderer will consume its view of + // the activations after we return. + bool was_consumed = frame_tree_node_->UpdateUserActivationState( + blink::mojom::UserActivationUpdateType::kConsumeTransientActivation, + blink::mojom::UserActivationNotificationType::kNone); // For Android WebView, we support a pop-up like behavior for window.open() // even if the embedding app doesn't support multiple windows. In this case, diff --git a/chromium/content/common/frame.mojom b/chromium/content/common/frame.mojom index b2f13658455..87276f2295e 100644 --- a/chromium/content/common/frame.mojom +++ b/chromium/content/common/frame.mojom @@ -532,8 +532,10 @@ struct CreateNewWindowParams { // Operation result when the renderer asks the browser to create a new window. enum CreateNewWindowStatus { - // Ignore creation of the new window. This can happen because creation is - // blocked or because the new window should have no opener relationship. + // Creation of the new window was blocked, e.g. because the source frame + // doesn't have user activation. + kBlocked, + // Ignore creation of the new window, e.g. because noopener is in effect. kIgnore, // Reuse the current window rather than creating a new window. kReuse, diff --git a/chromium/content/renderer/render_view_impl.cc b/chromium/content/renderer/render_view_impl.cc index 68838d79e17..1aacbc56300 100644 --- a/chromium/content/renderer/render_view_impl.cc +++ b/chromium/content/renderer/render_view_impl.cc @@ -352,8 +352,27 @@ WebView* RenderViewImpl::CreateView( mojom::CreateNewWindowStatus status; mojom::CreateNewWindowReplyPtr reply; auto* frame_host = creator_frame->GetFrameHost(); - bool err = !frame_host->CreateNewWindow(std::move(params), &status, &reply); - if (err || status == mojom::CreateNewWindowStatus::kIgnore) + if (!frame_host->CreateNewWindow(std::move(params), &status, &reply)) { + // The sync IPC failed, e.g. maybe the render process is in the middle of + // shutting down. Can't create a new window without the browser process, + // so just bail out. + return nullptr; + } + + // If creation of the window was blocked (e.g. because this frame doesn't + // have user activation), return before consuming user activation. A frame + // that isn't allowed to open a window shouldn't be able to consume the + // activation for the rest of the frame tree. + if (status == mojom::CreateNewWindowStatus::kBlocked) + return nullptr; + + // Consume the transient user activation in the current renderer. + consumed_user_gesture = creator->ConsumeTransientUserActivation( + blink::UserActivationUpdateSource::kBrowser); + + // If we should ignore the new window (e.g. because of `noopener`), return + // now that user activation was consumed. + if (status == mojom::CreateNewWindowStatus::kIgnore) return nullptr; // For Android WebView, we support a pop-up like behavior for window.open() @@ -373,11 +392,6 @@ WebView* RenderViewImpl::CreateView( DCHECK_NE(MSG_ROUTING_NONE, reply->main_frame_route_id); DCHECK_NE(MSG_ROUTING_NONE, reply->widget_params->routing_id); - // The browser allowed creation of a new window and consumed the user - // activation. - consumed_user_gesture = creator->ConsumeTransientUserActivation( - blink::UserActivationUpdateSource::kBrowser); - // While this view may be a background extension page, it can spawn a visible // render view. So we just assume that the new one is not another background // page instead of passing on our own value. |