blob: 804a89c5584ccacd04d0eece5d21b546cfd4e662 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/sad_tab_controller.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/contents_web_view.h"
#include "chrome/browser/ui/views/sad_tab_view.h"
#include "components/tabs/public/tab_interface.h"
#include "content/public/browser/web_contents.h"
#include "ui/views/view.h"
#include "ui/views/view_utils.h"
namespace {
ContentsWebView* FindContentsWebView(content::WebContents* web_contents) {
tabs::TabInterface* tab =
tabs::TabInterface::MaybeGetFromContents(web_contents);
if (!tab) {
return nullptr;
}
// In unit tests, browser->GetWindow() might not be a real BrowserView.
BrowserWindowInterface* browser = tab->GetBrowserWindowInterface();
if (!browser || !browser->GetWindow() ||
!browser->GetWindow()->GetNativeWindow()) {
return nullptr;
}
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
DCHECK(browser_view);
for (auto* contents_view : browser_view->GetAllVisibleContentsWebViews()) {
if (contents_view->web_contents() == web_contents) {
return contents_view;
}
}
return nullptr;
}
} // namespace
SadTabController::SadTabController(content::WebContents* web_contents,
SadTabKind kind)
: SadTab(web_contents, kind) {
ReinstallInWebView();
}
SadTabController::~SadTabController() {
ContentsWebView* contents_view = FindContentsWebView(web_contents());
if (!contents_view) {
return;
}
if (view_tracker_ && !owned_sad_tab_view_) {
auto crashed_overlay_view = contents_view->DetachCrashedOverlayView();
CHECK_EQ(view_tracker_.view(), crashed_overlay_view.get());
}
}
void SadTabController::ReinstallInWebView() {
std::unique_ptr<SadTabView> sad_tab_view;
if (owned_sad_tab_view_) {
sad_tab_view = std::move(owned_sad_tab_view_);
} else if (view_tracker_) {
// If the controller doesn't own the SadTabView, get ownership from its
// parent.
auto* parent = view_tracker_.view()->parent();
sad_tab_view = views::AsViewClass<views::WebView>(parent)
->DetachCrashedOverlayView<SadTabView>();
CHECK(sad_tab_view);
}
ContentsWebView* contents_view = FindContentsWebView(web_contents());
if (!contents_view) {
owned_sad_tab_view_ = std::move(sad_tab_view);
return;
}
if (!sad_tab_view) {
sad_tab_view = std::make_unique<SadTabView>(
this, kind(), GetTitle(), GetInfoMessage(), GetSubMessages(),
GetErrorCodeFormatString(), GetCrashedErrorCode(), GetButtonTitle(),
GetHelpLinkTitle());
view_tracker_.SetView(sad_tab_view.get());
}
CHECK_EQ(view_tracker_.view(), sad_tab_view.get());
sad_tab_view->SetBackgroundRadii(contents_view->GetBackgroundRadii());
contents_view->TakeCrashedOverlayView(
std::move(sad_tab_view),
base::BindOnce(
[](base::WeakPtr<SadTabController> controller,
std::unique_ptr<views::View> crashed_overlay_view) {
CHECK(!controller->owned_sad_tab_view_);
std::unique_ptr<SadTabView> sad_tab_view =
views::AsViewClass<SadTabView>(std::move(crashed_overlay_view));
CHECK(sad_tab_view);
controller->owned_sad_tab_view_.swap(sad_tab_view);
},
weak_factory_.GetWeakPtr()));
}
void SadTabController::SetBackgroundRadii(const gfx::RoundedCornersF& radii) {
if (view_tracker_.view()) {
views::AsViewClass<SadTabView>(view_tracker_.view())
->SetBackgroundRadii(radii);
}
}
gfx::RoundedCornersF SadTabController::GetBackgroundRadii() const {
if (view_tracker_) {
return views::AsViewClass<SadTabView>(view_tracker_.view())
->GetBackgroundRadii();
}
return gfx::RoundedCornersF();
}
void SadTabController::RequestFocus() {
if (view_tracker_) {
view_tracker_.view()->RequestFocus();
}
}
// SadTab::Create implementation moved here.
std::unique_ptr<SadTab> SadTab::Create(content::WebContents* web_contents,
SadTabKind kind) {
return std::make_unique<SadTabController>(web_contents, kind);
}