From 9d31fc3ea3c3b83607056a78e53cace057f9c784 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sat, 7 Oct 2023 17:21:00 -0400 Subject: [PATCH] Ladybird: Implement content zooming in the AppKit chrome This lets the user zoom in and out on a web page using the View menu or keyboard shortcuts. This does not implement zooming with ctrl+scroll. In the future, it'd be nice to embed the zoom level display inside the location toolbar. But to do that, we will need to invent our own custom search field and all of the UI classes (controller, cell, etc.) to draw the field. So for now, this places the zoom level display to the right of the location toolbar. --- .../AppKit/Application/ApplicationDelegate.mm | 17 ++++++ Ladybird/AppKit/UI/LadybirdWebView.h | 5 ++ Ladybird/AppKit/UI/LadybirdWebView.mm | 24 +++++++++ Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp | 6 ++- Ladybird/AppKit/UI/LadybirdWebViewBridge.h | 2 + Ladybird/AppKit/UI/TabController.mm | 52 +++++++++++++++++++ 6 files changed, 105 insertions(+), 1 deletion(-) diff --git a/Ladybird/AppKit/Application/ApplicationDelegate.mm b/Ladybird/AppKit/Application/ApplicationDelegate.mm index ccc5786b0e..dca160cf5b 100644 --- a/Ladybird/AppKit/Application/ApplicationDelegate.mm +++ b/Ladybird/AppKit/Application/ApplicationDelegate.mm @@ -303,7 +303,24 @@ keyEquivalent:@""]; [color_scheme_menu_item setSubmenu:color_scheme_menu]; + auto* zoom_menu = [[NSMenu alloc] init]; + [zoom_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Zoom In" + action:@selector(zoomIn:) + keyEquivalent:@"+"]]; + [zoom_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Zoom Out" + action:@selector(zoomOut:) + keyEquivalent:@"-"]]; + [zoom_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Actual Size" + action:@selector(resetZoom:) + keyEquivalent:@"0"]]; + + auto* zoom_menu_item = [[NSMenuItem alloc] initWithTitle:@"Zoom" + action:nil + keyEquivalent:@""]; + [zoom_menu_item setSubmenu:zoom_menu]; + [submenu addItem:color_scheme_menu_item]; + [submenu addItem:zoom_menu_item]; [submenu addItem:[NSMenuItem separatorItem]]; [menu setSubmenu:submenu]; diff --git a/Ladybird/AppKit/UI/LadybirdWebView.h b/Ladybird/AppKit/UI/LadybirdWebView.h index 87e5b7adbd..7fd65edd8f 100644 --- a/Ladybird/AppKit/UI/LadybirdWebView.h +++ b/Ladybird/AppKit/UI/LadybirdWebView.h @@ -54,6 +54,11 @@ - (void)setPreferredColorScheme:(Web::CSS::PreferredColorScheme)color_scheme; +- (void)zoomIn; +- (void)zoomOut; +- (void)resetZoom; +- (float)zoomLevel; + - (void)debugRequest:(DeprecatedString const&)request argument:(DeprecatedString const&)argument; - (void)viewSource; diff --git a/Ladybird/AppKit/UI/LadybirdWebView.mm b/Ladybird/AppKit/UI/LadybirdWebView.mm index ebb120cc7c..cf242bcdfa 100644 --- a/Ladybird/AppKit/UI/LadybirdWebView.mm +++ b/Ladybird/AppKit/UI/LadybirdWebView.mm @@ -149,6 +149,26 @@ struct HideCursor { m_web_view_bridge->set_system_visibility_state(is_visible); } +- (void)zoomIn +{ + m_web_view_bridge->zoom_in(); +} + +- (void)zoomOut +{ + m_web_view_bridge->zoom_out(); +} + +- (void)resetZoom +{ + m_web_view_bridge->reset_zoom(); +} + +- (float)zoomLevel +{ + return m_web_view_bridge->zoom_level(); +} + - (void)setPreferredColorScheme:(Web::CSS::PreferredColorScheme)color_scheme { m_web_view_bridge->set_preferred_color_scheme(color_scheme); @@ -344,6 +364,10 @@ struct HideCursor { } }; + m_web_view_bridge->on_zoom_level_changed = [self]() { + [self updateViewportRect:Ladybird::WebViewBridge::ForResize::Yes]; + }; + m_web_view_bridge->on_navigate_back = [self]() { [self.observer onNavigateBack]; }; diff --git a/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp b/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp index 73059cfe94..a22e530a09 100644 --- a/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp +++ b/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp @@ -70,7 +70,7 @@ WebViewBridge::~WebViewBridge() = default; void WebViewBridge::set_device_pixel_ratio(float device_pixel_ratio) { m_device_pixel_ratio = device_pixel_ratio; - client().async_set_device_pixels_per_css_pixel(device_pixel_ratio); + client().async_set_device_pixels_per_css_pixel(m_device_pixel_ratio * m_zoom_level); } void WebViewBridge::set_system_visibility_state(bool is_visible) @@ -158,6 +158,10 @@ Optional WebViewBridge::paintable() void WebViewBridge::update_zoom() { + client().async_set_device_pixels_per_css_pixel(m_device_pixel_ratio * m_zoom_level); + + if (on_zoom_level_changed) + on_zoom_level_changed(); } Gfx::IntRect WebViewBridge::viewport_rect() const diff --git a/Ladybird/AppKit/UI/LadybirdWebViewBridge.h b/Ladybird/AppKit/UI/LadybirdWebViewBridge.h index 337ba94a1c..1910651bd1 100644 --- a/Ladybird/AppKit/UI/LadybirdWebViewBridge.h +++ b/Ladybird/AppKit/UI/LadybirdWebViewBridge.h @@ -55,6 +55,8 @@ public: }; Optional paintable(); + Function on_zoom_level_changed; + private: WebViewBridge(Vector screen_rects, float device_pixel_ratio, Optional webdriver_content_ipc_path, Web::CSS::PreferredColorScheme); diff --git a/Ladybird/AppKit/UI/TabController.mm b/Ladybird/AppKit/UI/TabController.mm index c6bdc696a2..a43c57d6d8 100644 --- a/Ladybird/AppKit/UI/TabController.mm +++ b/Ladybird/AppKit/UI/TabController.mm @@ -24,6 +24,7 @@ static NSString* const TOOLBAR_NAVIGATE_BACK_IDENTIFIER = @"ToolbarNavigateBackI static NSString* const TOOLBAR_NAVIGATE_FORWARD_IDENTIFIER = @"ToolbarNavigateForwardIdentifier"; static NSString* const TOOLBAR_RELOAD_IDENTIFIER = @"ToolbarReloadIdentifier"; static NSString* const TOOLBAR_LOCATION_IDENTIFIER = @"ToolbarLocationIdentifier"; +static NSString* const TOOLBAR_ZOOM_IDENTIFIER = @"ToolbarZoomIdentifier"; static NSString* const TOOLBAR_NEW_TAB_IDENTIFIER = @"ToolbarNewTabIdentifier"; static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIdentifer"; @@ -49,6 +50,7 @@ enum class IsHistoryNavigation { @property (nonatomic, strong) NSToolbarItem* navigate_forward_toolbar_item; @property (nonatomic, strong) NSToolbarItem* reload_toolbar_item; @property (nonatomic, strong) NSToolbarItem* location_toolbar_item; +@property (nonatomic, strong) NSToolbarItem* zoom_toolbar_item; @property (nonatomic, strong) NSToolbarItem* new_tab_toolbar_item; @property (nonatomic, strong) NSToolbarItem* tab_overview_toolbar_item; @@ -63,6 +65,7 @@ enum class IsHistoryNavigation { @synthesize navigate_forward_toolbar_item = _navigate_forward_toolbar_item; @synthesize reload_toolbar_item = _reload_toolbar_item; @synthesize location_toolbar_item = _location_toolbar_item; +@synthesize zoom_toolbar_item = _zoom_toolbar_item; @synthesize new_tab_toolbar_item = _new_tab_toolbar_item; @synthesize tab_overview_toolbar_item = _tab_overview_toolbar_item; @@ -119,6 +122,24 @@ enum class IsHistoryNavigation { m_history.update_title(m_title); } +- (void)zoomIn:(id)sender +{ + [[[self tab] web_view] zoomIn]; + [self updateZoomButton]; +} + +- (void)zoomOut:(id)sender +{ + [[[self tab] web_view] zoomOut]; + [self updateZoomButton]; +} + +- (void)resetZoom:(id)sender +{ + [[[self tab] web_view] resetZoom]; + [self updateZoomButton]; +} + - (void)navigateBack:(id)sender { if (!m_history.can_go_back()) { @@ -221,6 +242,17 @@ enum class IsHistoryNavigation { self.tab.titlebarAppearsTransparent = YES; } +- (void)updateZoomButton +{ + auto zoom_level = [[[self tab] web_view] zoomLevel]; + + auto* zoom_level_text = [NSString stringWithFormat:@"%d%%", round_to(zoom_level * 100.0f)]; + [self.zoom_toolbar_item setTitle:zoom_level_text]; + + auto zoom_button_hidden = zoom_level == 1.0 ? YES : NO; + [[self.zoom_toolbar_item view] setHidden:zoom_button_hidden]; +} + - (void)dumpDOMTree:(id)sender { [self debugRequest:"dump-dom-tree" argument:""]; @@ -392,6 +424,22 @@ enum class IsHistoryNavigation { return _location_toolbar_item; } +- (NSToolbarItem*)zoom_toolbar_item +{ + if (!_zoom_toolbar_item) { + auto* button = [NSButton buttonWithTitle:@"100%" + target:self + action:@selector(resetZoom:)]; + [button setToolTip:@"Reset zoom level"]; + [button setHidden:YES]; + + _zoom_toolbar_item = [[NSToolbarItem alloc] initWithItemIdentifier:TOOLBAR_ZOOM_IDENTIFIER]; + [_zoom_toolbar_item setView:button]; + } + + return _zoom_toolbar_item; +} + - (NSToolbarItem*)new_tab_toolbar_item { if (!_new_tab_toolbar_item) { @@ -429,6 +477,7 @@ enum class IsHistoryNavigation { NSToolbarFlexibleSpaceItemIdentifier, TOOLBAR_RELOAD_IDENTIFIER, TOOLBAR_LOCATION_IDENTIFIER, + TOOLBAR_ZOOM_IDENTIFIER, NSToolbarFlexibleSpaceItemIdentifier, TOOLBAR_NEW_TAB_IDENTIFIER, TOOLBAR_TAB_OVERVIEW_IDENTIFIER, @@ -518,6 +567,9 @@ enum class IsHistoryNavigation { if ([identifier isEqual:TOOLBAR_LOCATION_IDENTIFIER]) { return self.location_toolbar_item; } + if ([identifier isEqual:TOOLBAR_ZOOM_IDENTIFIER]) { + return self.zoom_toolbar_item; + } if ([identifier isEqual:TOOLBAR_NEW_TAB_IDENTIFIER]) { return self.new_tab_toolbar_item; }