Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: Prevent crash when right clicking on an unloaded image #3210

Merged
merged 1 commit into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Libraries/LibWeb/Page/EventHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,11 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
if (is<HTML::HTMLImageElement>(*node)) {
auto& image_element = verify_cast<HTML::HTMLImageElement>(*node);
auto image_url = image_element.document().encoding_parse_url(image_element.src());
m_navigable->page().client().page_did_request_image_context_menu(viewport_position, image_url, "", modifiers, image_element.immutable_bitmap()->bitmap());
Optional<Gfx::Bitmap const*> bitmap;
if (image_element.immutable_bitmap())
bitmap = image_element.immutable_bitmap()->bitmap();

m_navigable->page().client().page_did_request_image_context_menu(viewport_position, image_url, "", modifiers, bitmap);
} else if (is<HTML::HTMLMediaElement>(*node)) {
auto& media_element = verify_cast<HTML::HTMLMediaElement>(*node);

Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/Page/Page.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ class PageClient : public JS::Cell {
virtual void page_did_request_cursor_change(Gfx::StandardCursor) { }
virtual void page_did_request_context_menu(CSSPixelPoint) { }
virtual void page_did_request_link_context_menu(CSSPixelPoint, URL::URL const&, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers) { }
virtual void page_did_request_image_context_menu(CSSPixelPoint, URL::URL const&, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers, Gfx::Bitmap const*) { }
virtual void page_did_request_image_context_menu(CSSPixelPoint, URL::URL const&, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers, Optional<Gfx::Bitmap const*>) { }
virtual void page_did_request_media_context_menu(CSSPixelPoint, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers, Page::MediaContextMenu) { }
virtual void page_did_click_link(URL::URL const&, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers) { }
virtual void page_did_middle_click_link(URL::URL const&, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers) { }
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWebView/ViewImplementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class ViewImplementation {
Function<void()> on_close;
Function<void(Gfx::IntPoint screen_position)> on_context_menu_request;
Function<void(URL::URL const&, Gfx::IntPoint screen_position)> on_link_context_menu_request;
Function<void(URL::URL const&, Gfx::IntPoint screen_position, Gfx::ShareableBitmap const&)> on_image_context_menu_request;
Function<void(URL::URL const&, Gfx::IntPoint screen_position, Optional<Gfx::ShareableBitmap> const&)> on_image_context_menu_request;
Function<void(Gfx::IntPoint screen_position, Web::Page::MediaContextMenu const&)> on_media_context_menu_request;
Function<void(URL::URL const&)> on_link_hover;
Function<void()> on_link_unhover;
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWebView/WebContentClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ void WebContentClient::did_request_link_context_menu(u64 page_id, Gfx::IntPoint
}
}

void WebContentClient::did_request_image_context_menu(u64 page_id, Gfx::IntPoint content_position, URL::URL const& url, ByteString const&, unsigned, Gfx::ShareableBitmap const& bitmap)
void WebContentClient::did_request_image_context_menu(u64 page_id, Gfx::IntPoint content_position, URL::URL const& url, ByteString const&, unsigned, Optional<Gfx::ShareableBitmap> const& bitmap)
{
if (auto view = view_for_page_id(page_id); view.has_value()) {
if (view->on_image_context_menu_request)
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWebView/WebContentClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class WebContentClient final
virtual void did_start_loading(u64 page_id, URL::URL const&, bool) override;
virtual void did_request_context_menu(u64 page_id, Gfx::IntPoint) override;
virtual void did_request_link_context_menu(u64 page_id, Gfx::IntPoint, URL::URL const&, ByteString const&, unsigned) override;
virtual void did_request_image_context_menu(u64 page_id, Gfx::IntPoint, URL::URL const&, ByteString const&, unsigned, Gfx::ShareableBitmap const&) override;
virtual void did_request_image_context_menu(u64 page_id, Gfx::IntPoint, URL::URL const&, ByteString const&, unsigned, Optional<Gfx::ShareableBitmap> const&) override;
virtual void did_request_media_context_menu(u64 page_id, Gfx::IntPoint, ByteString const&, unsigned, Web::Page::MediaContextMenu const&) override;
virtual void did_get_source(u64 page_id, URL::URL const&, URL::URL const&, String const&) override;
virtual void did_inspect_dom_tree(u64 page_id, ByteString const&) override;
Expand Down
7 changes: 5 additions & 2 deletions Services/WebContent/PageClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,12 @@ void PageClient::page_did_request_link_context_menu(Web::CSSPixelPoint content_p
client().async_did_request_link_context_menu(m_id, page().css_to_device_point(content_position).to_type<int>(), url, target, modifiers);
}

void PageClient::page_did_request_image_context_menu(Web::CSSPixelPoint content_position, URL::URL const& url, ByteString const& target, unsigned modifiers, Gfx::Bitmap const* bitmap_pointer)
void PageClient::page_did_request_image_context_menu(Web::CSSPixelPoint content_position, URL::URL const& url, ByteString const& target, unsigned modifiers, Optional<Gfx::Bitmap const*> bitmap_pointer)
{
auto bitmap = bitmap_pointer ? bitmap_pointer->to_shareable_bitmap() : Gfx::ShareableBitmap();
Optional<Gfx::ShareableBitmap> bitmap;
if (bitmap_pointer.has_value() && bitmap_pointer.value())
bitmap = bitmap_pointer.value()->to_shareable_bitmap();

client().async_did_request_image_context_menu(m_id, page().css_to_device_point(content_position).to_type<int>(), url, target, modifiers, bitmap);
}

Expand Down
2 changes: 1 addition & 1 deletion Services/WebContent/PageClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class PageClient final : public Web::PageClient {
virtual void page_did_middle_click_link(URL::URL const&, ByteString const& target, unsigned modifiers) override;
virtual void page_did_request_context_menu(Web::CSSPixelPoint) override;
virtual void page_did_request_link_context_menu(Web::CSSPixelPoint, URL::URL const&, ByteString const& target, unsigned modifiers) override;
virtual void page_did_request_image_context_menu(Web::CSSPixelPoint, URL::URL const&, ByteString const& target, unsigned modifiers, Gfx::Bitmap const*) override;
virtual void page_did_request_image_context_menu(Web::CSSPixelPoint, URL::URL const&, ByteString const& target, unsigned modifiers, Optional<Gfx::Bitmap const*>) override;
virtual void page_did_request_media_context_menu(Web::CSSPixelPoint, ByteString const& target, unsigned modifiers, Web::Page::MediaContextMenu) override;
virtual void page_did_start_loading(URL::URL const&, bool) override;
virtual void page_did_create_new_document(Web::DOM::Document&) override;
Expand Down
2 changes: 1 addition & 1 deletion Services/WebContent/WebContentClient.ipc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ endpoint WebContentClient
did_middle_click_link(u64 page_id, URL::URL url, ByteString target, unsigned modifiers) =|
did_request_context_menu(u64 page_id, Gfx::IntPoint content_position) =|
did_request_link_context_menu(u64 page_id, Gfx::IntPoint content_position, URL::URL url, ByteString target, unsigned modifiers) =|
did_request_image_context_menu(u64 page_id, Gfx::IntPoint content_position, URL::URL url, ByteString target, unsigned modifiers, Gfx::ShareableBitmap bitmap) =|
did_request_image_context_menu(u64 page_id, Gfx::IntPoint content_position, URL::URL url, ByteString target, unsigned modifiers, Optional<Gfx::ShareableBitmap> bitmap) =|
did_request_media_context_menu(u64 page_id, Gfx::IntPoint content_position, ByteString target, unsigned modifiers, Web::Page::MediaContextMenu menu) =|
did_request_alert(u64 page_id, String message) =|
did_request_confirm(u64 page_id, String message) =|
Expand Down
19 changes: 15 additions & 4 deletions UI/AppKit/Interface/LadybirdWebView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
static constexpr NSInteger CONTEXT_MENU_LOOP_TAG = 4;
static constexpr NSInteger CONTEXT_MENU_SEARCH_SELECTED_TEXT_TAG = 5;
static constexpr NSInteger CONTEXT_MENU_COPY_LINK_TAG = 6;
static constexpr NSInteger CONTEXT_MENU_COPY_IMAGE_TAG = 7;

// Calls to [NSCursor hide] and [NSCursor unhide] must be balanced. We use this struct to ensure
// we only call [NSCursor hide] once and to ensure that we do call [NSCursor unhide].
Expand All @@ -54,7 +55,7 @@ @interface LadybirdWebView () <NSDraggingDestination>
OwnPtr<Ladybird::WebViewBridge> m_web_view_bridge;

URL::URL m_context_menu_url;
Gfx::ShareableBitmap m_context_menu_bitmap;
Optional<Gfx::ShareableBitmap> m_context_menu_bitmap;
Optional<String> m_context_menu_search_text;

Optional<HideCursor> m_hidden_cursor;
Expand Down Expand Up @@ -669,6 +670,9 @@ - (void)setWebViewCallbacks
TemporaryChange change_url { m_context_menu_url, url };
TemporaryChange change_bitmap { m_context_menu_bitmap, bitmap };

auto* copy_image_menu_item = [self.image_context_menu itemWithTag:CONTEXT_MENU_COPY_IMAGE_TAG];
[copy_image_menu_item setEnabled:bitmap.has_value()];

auto* event = Ladybird::create_context_menu_mouse_event(self, position);
[NSMenu popUpContextMenu:self.image_context_menu withEvent:event forView:self];
};
Expand Down Expand Up @@ -1186,7 +1190,10 @@ - (void)copyLink:(id)sender

- (void)copyImage:(id)sender
{
auto* bitmap = m_context_menu_bitmap.bitmap();
if (!m_context_menu_bitmap.has_value()) {
return;
}
auto* bitmap = m_context_menu_bitmap.value().bitmap();
if (bitmap == nullptr) {
return;
}
Expand Down Expand Up @@ -1310,6 +1317,7 @@ - (NSMenu*)image_context_menu
{
if (!_image_context_menu) {
_image_context_menu = [[NSMenu alloc] initWithTitle:@"Image Context Menu"];
[_image_context_menu setAutoenablesItems:NO];

[_image_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Open Image"
action:@selector(openLink:)
Expand All @@ -1319,9 +1327,12 @@ - (NSMenu*)image_context_menu
keyEquivalent:@""]];
[_image_context_menu addItem:[NSMenuItem separatorItem]];

[_image_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Copy Image"
auto* copy_image_menu_item = [[NSMenuItem alloc] initWithTitle:@"Copy Image"
action:@selector(copyImage:)
keyEquivalent:@""]];
keyEquivalent:@""];
[copy_image_menu_item setTag:CONTEXT_MENU_COPY_IMAGE_TAG];
[_image_context_menu addItem:copy_image_menu_item];

[_image_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Copy Image URL"
action:@selector(copyLink:)
keyEquivalent:@""]];
Expand Down
16 changes: 10 additions & 6 deletions UI/Qt/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,10 +592,13 @@ Tab::Tab(BrowserWindow* window, RefPtr<WebView::WebContentClient> parent_client,
open_link_in_new_tab(m_image_context_menu_url);
});

auto* copy_image_action = new QAction("&Copy Image", this);
copy_image_action->setIcon(load_icon_from_uri("resource://icons/16x16/edit-copy.png"sv));
QObject::connect(copy_image_action, &QAction::triggered, this, [this]() {
auto* bitmap = m_image_context_menu_bitmap.bitmap();
m_image_context_menu_copy_image_action = new QAction("&Copy Image", this);
m_image_context_menu_copy_image_action->setIcon(load_icon_from_uri("resource://icons/16x16/edit-copy.png"sv));
QObject::connect(m_image_context_menu_copy_image_action, &QAction::triggered, this, [this]() {
if (!m_image_context_menu_bitmap.has_value())
return;

auto* bitmap = m_image_context_menu_bitmap.value().bitmap();
if (bitmap == nullptr)
return;

Expand All @@ -621,14 +624,15 @@ Tab::Tab(BrowserWindow* window, RefPtr<WebView::WebContentClient> parent_client,
m_image_context_menu->addAction(open_image_action);
m_image_context_menu->addAction(open_image_in_new_tab_action);
m_image_context_menu->addSeparator();
m_image_context_menu->addAction(copy_image_action);
m_image_context_menu->addAction(m_image_context_menu_copy_image_action);
m_image_context_menu->addAction(copy_image_url_action);
m_image_context_menu->addSeparator();
m_image_context_menu->addAction(&m_window->inspect_dom_node_action());

view().on_image_context_menu_request = [this](auto& image_url, Gfx::IntPoint content_position, Gfx::ShareableBitmap const& shareable_bitmap) {
view().on_image_context_menu_request = [this](auto& image_url, Gfx::IntPoint content_position, Optional<Gfx::ShareableBitmap> const& shareable_bitmap) {
m_image_context_menu_url = image_url;
m_image_context_menu_bitmap = shareable_bitmap;
m_image_context_menu_copy_image_action->setEnabled(shareable_bitmap.has_value());

m_image_context_menu->exec(view().map_point_to_global_position(content_position));
};
Expand Down
3 changes: 2 additions & 1 deletion UI/Qt/Tab.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ public slots:
URL::URL m_link_context_menu_url;

QMenu* m_image_context_menu { nullptr };
Gfx::ShareableBitmap m_image_context_menu_bitmap;
QAction* m_image_context_menu_copy_image_action { nullptr };
Optional<Gfx::ShareableBitmap> m_image_context_menu_bitmap;
URL::URL m_image_context_menu_url;

QMenu* m_audio_context_menu { nullptr };
Expand Down
Loading