fix: bind offscreen paint callback to child WebContents (#50152)

fix: bind offscreen paint callback to child WebContents

Previously, MaybeOverrideCreateParamsForNewWindow bound the
OffScreenWebContentsView's paint callback to the parent WebContents
using base::Unretained(this). This was both unsafe (dangling pointer
risk if the parent is destroyed before the child) and semantically
incorrect — paint events belong to the child window, not the opener.

Replace the callback in MaybeOverrideCreateParamsForNewWindow with
base::DoNothing(), then rebind it to the child WebContents in
AddNewContents via a new SetCallback method on OffScreenWebContentsView.
This commit is contained in:
Shelley Vohr
2026-03-10 09:43:51 +01:00
committed by GitHub
parent 616a63bc73
commit cb4d31ae61
3 changed files with 17 additions and 2 deletions

View File

@@ -1311,10 +1311,11 @@ void WebContents::MaybeOverrideCreateParamsForNewWindow(
dict.Get(options::kOffscreen, &is_offscreen) && is_offscreen);
if (is_offscreen) {
// Use a no-op callback here. The real OnPaint callback will be bound
// to the child WebContents in AddNewContents via SetCallback().
auto* view = new OffScreenWebContentsView(
false, offscreen_use_shared_texture_,
offscreen_shared_texture_pixel_format_,
base::BindRepeating(&WebContents::OnPaint, base::Unretained(this)));
offscreen_shared_texture_pixel_format_, base::DoNothing());
create_params->view = view;
create_params->delegate_view = view;
}
@@ -1342,6 +1343,15 @@ content::WebContents* WebContents::AddNewContents(
v8::HandleScope handle_scope(isolate);
auto api_web_contents = CreateAndTake(isolate, std::move(new_contents), type);
// Rebind the paint callback to the child WebContents. The
// OffScreenWebContentsView was initially created with the parent's OnPaint
// in MaybeOverrideCreateParamsForNewWindow, but the paint data
// belongs to the child.
if (auto* osr_view = api_web_contents->GetOffScreenWebContentsView()) {
osr_view->SetCallback(base::BindRepeating(&WebContents::OnPaint,
api_web_contents->GetWeakPtr()));
}
// We call RenderFrameCreated here as at this point the empty "about:blank"
// render frame has already been created. If the window never navigates again
// RenderFrameCreated won't be called and certain prefs like

View File

@@ -45,6 +45,10 @@ void OffScreenWebContentsView::SetWebContents(
view->InstallTransparency();
}
void OffScreenWebContentsView::SetCallback(const OnPaintCallback& callback) {
callback_ = callback;
}
void OffScreenWebContentsView::SetNativeWindow(NativeWindow* window) {
if (native_window_)
native_window_->RemoveObserver(this);

View File

@@ -43,6 +43,7 @@ class OffScreenWebContentsView : public content::WebContentsView,
void SetWebContents(content::WebContents*);
void SetNativeWindow(NativeWindow* window);
void SetCallback(const OnPaintCallback& callback);
// NativeWindowObserver:
void OnWindowResize() override;