1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-11 18:20:43 +09:00

LibWeb: Handle WebContent process crashes gracefully :^)

The OOPWV will now detect WebContent process crashes/disconnections and
simply create a new WebContent process in its place. We also generate a
little error page with a link to the crashing URL so you can reload and
try again.

This a huge step forward for OOPWV since it now has a feature that IPWV
can never replicate. :^)
This commit is contained in:
Andreas Kling 2021-01-30 18:20:40 +01:00
parent 322936115e
commit f3e85e43c7
Notes: sideshowbarker 2024-07-18 22:43:25 +09:00
4 changed files with 80 additions and 35 deletions

View file

@ -41,14 +41,40 @@ OutOfProcessWebView::OutOfProcessWebView()
{ {
set_should_hide_unnecessary_scrollbars(true); set_should_hide_unnecessary_scrollbars(true);
set_focus_policy(GUI::FocusPolicy::StrongFocus); set_focus_policy(GUI::FocusPolicy::StrongFocus);
m_client = WebContentClient::construct(*this);
client().post_message(Messages::WebContentServer::UpdateSystemTheme(Gfx::current_system_theme_buffer())); create_client();
} }
OutOfProcessWebView::~OutOfProcessWebView() OutOfProcessWebView::~OutOfProcessWebView()
{ {
} }
void OutOfProcessWebView::create_client()
{
m_client_state = {};
m_client_state.client = WebContentClient::construct(*this);
m_client_state.client->on_web_content_process_crash = [this] {
create_client();
ASSERT(m_client_state.client);
handle_resize();
StringBuilder builder;
builder.append("<html><head><title>Crashed: ");
builder.append(m_url.to_string());
builder.append("</title></head><body>");
builder.append("<h1>Web page crashed");
if (!m_url.host().is_empty()) {
builder.appendff(" on {}", m_url.host());
}
builder.append("</h1>");
builder.appendff("The web page <a href='{}'>{}</a> has crashed.<br><br>You can reload the page to try again.", m_url, m_url);
builder.append("</body></html>");
load_html(builder.to_string(), m_url);
};
client().post_message(Messages::WebContentServer::UpdateSystemTheme(Gfx::current_system_theme_buffer()));
}
void OutOfProcessWebView::load(const URL& url) void OutOfProcessWebView::load(const URL& url)
{ {
m_url = url; m_url = url;
@ -78,7 +104,7 @@ void OutOfProcessWebView::paint_event(GUI::PaintEvent& event)
GUI::Painter painter(*this); GUI::Painter painter(*this);
painter.add_clip_rect(event.rect()); painter.add_clip_rect(event.rect());
if (!m_has_usable_bitmap) { if (!m_client_state.has_usable_bitmap) {
painter.fill_rect(frame_inner_rect(), palette().base()); painter.fill_rect(frame_inner_rect(), palette().base());
return; return;
} }
@ -86,43 +112,47 @@ void OutOfProcessWebView::paint_event(GUI::PaintEvent& event)
painter.add_clip_rect(frame_inner_rect()); painter.add_clip_rect(frame_inner_rect());
painter.translate(frame_thickness(), frame_thickness()); painter.translate(frame_thickness(), frame_thickness());
ASSERT(m_front_bitmap); ASSERT(m_client_state.front_bitmap);
painter.blit({ 0, 0 }, *m_front_bitmap, m_front_bitmap->rect()); painter.blit({ 0, 0 }, *m_client_state.front_bitmap, m_client_state.front_bitmap->rect());
} }
void OutOfProcessWebView::resize_event(GUI::ResizeEvent& event) void OutOfProcessWebView::resize_event(GUI::ResizeEvent& event)
{ {
GUI::ScrollableWidget::resize_event(event); GUI::ScrollableWidget::resize_event(event);
handle_resize();
}
void OutOfProcessWebView::handle_resize()
{
client().post_message(Messages::WebContentServer::SetViewportRect(Gfx::IntRect({ horizontal_scrollbar().value(), vertical_scrollbar().value() }, available_size()))); client().post_message(Messages::WebContentServer::SetViewportRect(Gfx::IntRect({ horizontal_scrollbar().value(), vertical_scrollbar().value() }, available_size())));
if (m_front_bitmap) { if (m_client_state.front_bitmap) {
m_front_bitmap = nullptr; m_client_state.front_bitmap = nullptr;
client().post_message(Messages::WebContentServer::RemoveBackingStore(m_front_bitmap_id)); client().post_message(Messages::WebContentServer::RemoveBackingStore(m_client_state.front_bitmap_id));
} }
if (m_back_bitmap) { if (m_client_state.back_bitmap) {
m_back_bitmap = nullptr; m_client_state.back_bitmap = nullptr;
client().post_message(Messages::WebContentServer::RemoveBackingStore(m_back_bitmap_id)); client().post_message(Messages::WebContentServer::RemoveBackingStore(m_client_state.back_bitmap_id));
} }
m_front_bitmap_id = -1; m_client_state.front_bitmap_id = -1;
m_back_bitmap_id = -1; m_client_state.back_bitmap_id = -1;
m_has_usable_bitmap = false; m_client_state.has_usable_bitmap = false;
if (available_size().is_empty()) if (available_size().is_empty())
return; return;
if (auto new_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::RGB32, available_size())) { if (auto new_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::RGB32, available_size())) {
m_front_bitmap = move(new_bitmap); m_client_state.front_bitmap = move(new_bitmap);
m_front_bitmap_id = m_next_bitmap_id++; m_client_state.front_bitmap_id = m_client_state.next_bitmap_id++;
client().post_message(Messages::WebContentServer::AddBackingStore(m_front_bitmap_id, m_front_bitmap->to_shareable_bitmap())); client().post_message(Messages::WebContentServer::AddBackingStore(m_client_state.front_bitmap_id, m_client_state.front_bitmap->to_shareable_bitmap()));
} }
if (auto new_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::RGB32, available_size())) { if (auto new_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::RGB32, available_size())) {
m_back_bitmap = move(new_bitmap); m_client_state.back_bitmap = move(new_bitmap);
m_back_bitmap_id = m_next_bitmap_id++; m_client_state.back_bitmap_id = m_client_state.next_bitmap_id++;
client().post_message(Messages::WebContentServer::AddBackingStore(m_back_bitmap_id, m_back_bitmap->to_shareable_bitmap())); client().post_message(Messages::WebContentServer::AddBackingStore(m_client_state.back_bitmap_id, m_client_state.back_bitmap->to_shareable_bitmap()));
} }
request_repaint(); request_repaint();
@ -157,10 +187,10 @@ void OutOfProcessWebView::theme_change_event(GUI::ThemeChangeEvent& event)
void OutOfProcessWebView::notify_server_did_paint(Badge<WebContentClient>, i32 bitmap_id) void OutOfProcessWebView::notify_server_did_paint(Badge<WebContentClient>, i32 bitmap_id)
{ {
if (m_back_bitmap_id == bitmap_id) { if (m_client_state.back_bitmap_id == bitmap_id) {
m_has_usable_bitmap = true; m_client_state.has_usable_bitmap = true;
swap(m_back_bitmap, m_front_bitmap); swap(m_client_state.back_bitmap, m_client_state.front_bitmap);
swap(m_back_bitmap_id, m_front_bitmap_id); swap(m_client_state.back_bitmap_id, m_client_state.front_bitmap_id);
update(); update();
} }
} }
@ -256,14 +286,15 @@ void OutOfProcessWebView::request_repaint()
{ {
// If this widget was instantiated but not yet added to a window, // If this widget was instantiated but not yet added to a window,
// it won't have a back bitmap yet, so we can just skip repaint requests. // it won't have a back bitmap yet, so we can just skip repaint requests.
if (!m_back_bitmap) if (!m_client_state.back_bitmap)
return; return;
client().post_message(Messages::WebContentServer::Paint(m_back_bitmap->rect().translated(horizontal_scrollbar().value(), vertical_scrollbar().value()), m_back_bitmap_id)); client().post_message(Messages::WebContentServer::Paint(m_client_state.back_bitmap->rect().translated(horizontal_scrollbar().value(), vertical_scrollbar().value()), m_client_state.back_bitmap_id));
} }
WebContentClient& OutOfProcessWebView::client() WebContentClient& OutOfProcessWebView::client()
{ {
return *m_client; ASSERT(m_client_state.client);
return *m_client_state.client;
} }
} }

View file

@ -81,18 +81,22 @@ private:
virtual void did_scroll() override; virtual void did_scroll() override;
void request_repaint(); void request_repaint();
void handle_resize();
void create_client();
WebContentClient& client(); WebContentClient& client();
URL m_url; URL m_url;
RefPtr<WebContentClient> m_client; struct ClientState {
RefPtr<Gfx::Bitmap> m_front_bitmap; RefPtr<WebContentClient> client;
RefPtr<Gfx::Bitmap> m_back_bitmap; RefPtr<Gfx::Bitmap> front_bitmap;
i32 m_front_bitmap_id { -1 }; RefPtr<Gfx::Bitmap> back_bitmap;
i32 m_back_bitmap_id { -1 }; i32 front_bitmap_id { -1 };
i32 m_next_bitmap_id { 0 }; i32 back_bitmap_id { -1 };
bool m_has_usable_bitmap { false }; i32 next_bitmap_id { 0 };
bool has_usable_bitmap { false };
} m_client_state;
}; };
} }

View file

@ -37,6 +37,12 @@ WebContentClient::WebContentClient(OutOfProcessWebView& view)
handshake(); handshake();
} }
void WebContentClient::die()
{
ASSERT(on_web_content_process_crash);
on_web_content_process_crash();
}
void WebContentClient::handshake() void WebContentClient::handshake()
{ {
auto response = send_sync<Messages::WebContentServer::Greet>(getpid()); auto response = send_sync<Messages::WebContentServer::Greet>(getpid());

View file

@ -35,7 +35,7 @@ namespace Web {
class OutOfProcessWebView; class OutOfProcessWebView;
class WebContentClient class WebContentClient final
: public IPC::ServerConnection<WebContentClientEndpoint, WebContentServerEndpoint> : public IPC::ServerConnection<WebContentClientEndpoint, WebContentServerEndpoint>
, public WebContentClientEndpoint { , public WebContentClientEndpoint {
C_OBJECT(WebContentClient); C_OBJECT(WebContentClient);
@ -43,9 +43,13 @@ class WebContentClient
public: public:
virtual void handshake() override; virtual void handshake() override;
Function<void()> on_web_content_process_crash;
private: private:
WebContentClient(OutOfProcessWebView&); WebContentClient(OutOfProcessWebView&);
virtual void die() override;
virtual void handle(const Messages::WebContentClient::DidPaint&) override; virtual void handle(const Messages::WebContentClient::DidPaint&) override;
virtual void handle(const Messages::WebContentClient::DidFinishLoading&) override; virtual void handle(const Messages::WebContentClient::DidFinishLoading&) override;
virtual void handle(const Messages::WebContentClient::DidInvalidateContentRect&) override; virtual void handle(const Messages::WebContentClient::DidInvalidateContentRect&) override;