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

LibWeb+WebContent: Move scrollbar painting into WebContent #24554

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
16 changes: 0 additions & 16 deletions Ladybird/AppKit/UI/LadybirdWebView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -351,22 +351,6 @@ - (void)setWebViewCallbacks
self.event_being_redispatched = nil;
};

m_web_view_bridge->on_scroll = [self](auto position) {
auto content_rect = [self frame];
auto document_rect = [[self documentView] frame];
auto ns_position = Ladybird::gfx_point_to_ns_point(position);

ns_position.x = max(ns_position.x, document_rect.origin.x);
ns_position.x = min(ns_position.x, document_rect.size.width - content_rect.size.width);

ns_position.y = max(ns_position.y, document_rect.origin.y);
ns_position.y = min(ns_position.y, document_rect.size.height - content_rect.size.height);

[self scrollToPoint:ns_position];
[[self scrollView] reflectScrolledClipView:self];
[self updateViewportRect:Ladybird::WebViewBridge::ForResize::No];
};

m_web_view_bridge->on_cursor_change = [self](auto cursor) {
if (cursor == Gfx::StandardCursor::Hidden) {
if (!m_hidden_cursor.has_value()) {
Expand Down
22 changes: 4 additions & 18 deletions Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,6 @@ WebViewBridge::WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float de
, m_preferred_color_scheme(preferred_color_scheme)
{
m_device_pixel_ratio = device_pixel_ratio;

on_scroll_by_delta = [this](auto x_delta, auto y_delta) {
auto position = m_viewport_rect.location();
position.set_x(position.x() + x_delta);
position.set_y(position.y() + y_delta);

if (on_scroll_to_point)
on_scroll_to_point(position);
};

on_scroll_to_point = [this](auto position) {
if (on_scroll)
on_scroll(to_widget_position(position));
};
}

WebViewBridge::~WebViewBridge() = default;
Expand All @@ -67,9 +53,9 @@ void WebViewBridge::set_system_visibility_state(bool is_visible)
void WebViewBridge::set_viewport_rect(Gfx::IntRect viewport_rect, ForResize for_resize)
{
viewport_rect.set_size(scale_for_device(viewport_rect.size(), m_device_pixel_ratio));
m_viewport_rect = viewport_rect;
m_viewport_size = viewport_rect.size();

client().async_set_viewport_rect(m_client_state.page_index, m_viewport_rect.to_type<Web::DevicePixels>());
client().async_set_viewport_size(m_client_state.page_index, m_viewport_size.to_type<Web::DevicePixels>());

if (for_resize == ForResize::Yes) {
handle_resize();
Expand Down Expand Up @@ -126,9 +112,9 @@ void WebViewBridge::update_zoom()
on_zoom_level_changed();
}

Web::DevicePixelRect WebViewBridge::viewport_rect() const
Web::DevicePixelSize WebViewBridge::viewport_size() const
{
return m_viewport_rect.to_type<Web::DevicePixels>();
return m_viewport_size.to_type<Web::DevicePixels>();
}

Gfx::IntPoint WebViewBridge::to_content_position(Gfx::IntPoint widget_position) const
Expand Down
5 changes: 2 additions & 3 deletions Ladybird/AppKit/UI/LadybirdWebViewBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,17 @@ class WebViewBridge final : public WebView::ViewImplementation {

Function<NonnullRefPtr<WebView::WebContentClient>()> on_request_web_content;
Function<void()> on_zoom_level_changed;
Function<void(Gfx::IntPoint)> on_scroll;

private:
WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, WebContentOptions const&, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme);

virtual void update_zoom() override;
virtual Web::DevicePixelRect viewport_rect() const override;
virtual Web::DevicePixelSize viewport_size() const override;
virtual Gfx::IntPoint to_content_position(Gfx::IntPoint widget_position) const override;
virtual Gfx::IntPoint to_widget_position(Gfx::IntPoint content_position) const override;

Vector<Web::DevicePixelRect> m_screen_rects;
Gfx::IntRect m_viewport_rect;
Gfx::IntSize m_viewport_size;

WebContentOptions m_web_content_options;
Optional<StringView> m_webdriver_content_ipc_path;
Expand Down
4 changes: 2 additions & 2 deletions Ladybird/AppKit/UI/Tab.mm
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ - (instancetype)init
[self.search_panel setHidden:YES];

auto* scroll_view = [[NSScrollView alloc] init];
[scroll_view setHasVerticalScroller:YES];
[scroll_view setHasHorizontalScroller:YES];
[scroll_view setHasVerticalScroller:NO];
[scroll_view setHasHorizontalScroller:NO];
[scroll_view setLineScroll:24];

[scroll_view setContentView:self.web_view];
Expand Down
55 changes: 16 additions & 39 deletions Ladybird/Qt/WebContentView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ WebContentView::WebContentView(QWidget* window, WebContentOptions const& web_con
, m_web_content_options(web_content_options)
, m_webdriver_content_ipc_path(webdriver_content_ipc_path)
{
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

m_client_state.client = parent_client;
m_client_state.page_index = page_index;

Expand All @@ -68,13 +71,6 @@ WebContentView::WebContentView(QWidget* window, WebContentOptions const& web_con
verticalScrollBar()->setSingleStep(24);
horizontalScrollBar()->setSingleStep(24);

QObject::connect(verticalScrollBar(), &QScrollBar::valueChanged, [this](int) {
update_viewport_rect();
});
QObject::connect(horizontalScrollBar(), &QScrollBar::valueChanged, [this](int) {
update_viewport_rect();
});

QObject::connect(qGuiApp, &QGuiApplication::screenRemoved, [this](QScreen*) {
update_screen_rects();
});
Expand All @@ -85,29 +81,10 @@ WebContentView::WebContentView(QWidget* window, WebContentOptions const& web_con

initialize_client((parent_client == nullptr) ? CreateNewClient::Yes : CreateNewClient::No);

on_did_layout = [this](auto content_size) {
verticalScrollBar()->setMinimum(0);
verticalScrollBar()->setMaximum(content_size.height() - m_viewport_rect.height());
verticalScrollBar()->setPageStep(m_viewport_rect.height());
horizontalScrollBar()->setMinimum(0);
horizontalScrollBar()->setMaximum(content_size.width() - m_viewport_rect.width());
horizontalScrollBar()->setPageStep(m_viewport_rect.width());
};

on_ready_to_paint = [this]() {
viewport()->update();
};

on_scroll_by_delta = [this](auto x_delta, auto y_delta) {
horizontalScrollBar()->setValue(max(0, horizontalScrollBar()->value() + x_delta));
verticalScrollBar()->setValue(max(0, verticalScrollBar()->value() + y_delta));
};

on_scroll_to_point = [this](auto position) {
horizontalScrollBar()->setValue(position.x());
verticalScrollBar()->setValue(position.y());
};

on_cursor_change = [this](auto cursor) {
update_cursor(cursor);
};
Expand Down Expand Up @@ -445,14 +422,14 @@ void WebContentView::paintEvent(QPaintEvent*)
void WebContentView::resizeEvent(QResizeEvent* event)
{
QAbstractScrollArea::resizeEvent(event);
update_viewport_rect();
update_viewport_size();
handle_resize();
}

void WebContentView::set_viewport_rect(Gfx::IntRect rect)
{
m_viewport_rect = rect;
client().async_set_viewport_rect(m_client_state.page_index, rect.to_type<Web::DevicePixels>());
m_viewport_size = rect.size();
client().async_set_viewport_size(m_client_state.page_index, rect.size().to_type<Web::DevicePixels>());
}

void WebContentView::set_window_size(Gfx::IntSize size)
Expand All @@ -469,23 +446,23 @@ void WebContentView::set_device_pixel_ratio(double device_pixel_ratio)
{
m_device_pixel_ratio = device_pixel_ratio;
client().async_set_device_pixels_per_css_pixel(m_client_state.page_index, m_device_pixel_ratio * m_zoom_level);
update_viewport_rect();
update_viewport_size();
handle_resize();
}

void WebContentView::update_viewport_rect()
void WebContentView::update_viewport_size()
{
auto scaled_width = int(viewport()->width() * m_device_pixel_ratio);
auto scaled_height = int(viewport()->height() * m_device_pixel_ratio);
Gfx::IntRect rect(max(0, horizontalScrollBar()->value()), max(0, verticalScrollBar()->value()), scaled_width, scaled_height);
Gfx::IntRect rect(0, 0, scaled_width, scaled_height);

set_viewport_rect(rect);
}

void WebContentView::update_zoom()
{
client().async_set_device_pixels_per_css_pixel(m_client_state.page_index, m_device_pixel_ratio * m_zoom_level);
update_viewport_rect();
update_viewport_size();
}

void WebContentView::showEvent(QShowEvent* event)
Expand Down Expand Up @@ -662,9 +639,9 @@ void WebContentView::update_cursor(Gfx::StandardCursor cursor)
}
}

Web::DevicePixelRect WebContentView::viewport_rect() const
Web::DevicePixelSize WebContentView::viewport_size() const
{
return m_viewport_rect.to_type<Web::DevicePixels>();
return m_viewport_size.to_type<Web::DevicePixels>();
}

QPoint WebContentView::map_point_to_global_position(Gfx::IntPoint position) const
Expand All @@ -674,12 +651,12 @@ QPoint WebContentView::map_point_to_global_position(Gfx::IntPoint position) cons

Gfx::IntPoint WebContentView::to_content_position(Gfx::IntPoint widget_position) const
{
return widget_position.translated(max(0, horizontalScrollBar()->value()), max(0, verticalScrollBar()->value()));
return widget_position;
}

Gfx::IntPoint WebContentView::to_widget_position(Gfx::IntPoint content_position) const
{
return content_position.translated(-(max(0, horizontalScrollBar()->value())), -(max(0, verticalScrollBar()->value())));
return content_position;
}

bool WebContentView::event(QEvent* event)
Expand Down Expand Up @@ -716,7 +693,7 @@ ErrorOr<String> WebContentView::dump_layout_tree()

void WebContentView::enqueue_native_event(Web::MouseEvent::Type type, QSinglePointEvent const& event)
{
auto position = to_content_position({ event.position().x() * m_device_pixel_ratio, event.position().y() * m_device_pixel_ratio });
Web::DevicePixelPoint position = { event.position().x() * m_device_pixel_ratio, event.position().y() * m_device_pixel_ratio };
auto screen_position = Gfx::IntPoint { event.globalPosition().x() * m_device_pixel_ratio, event.globalPosition().y() * m_device_pixel_ratio };

auto button = get_button_from_qt_event(event);
Expand Down Expand Up @@ -752,7 +729,7 @@ void WebContentView::enqueue_native_event(Web::MouseEvent::Type type, QSinglePoi
}
}

enqueue_input_event(Web::MouseEvent { type, position.to_type<Web::DevicePixels>(), screen_position.to_type<Web::DevicePixels>(), button, buttons, modifiers, wheel_delta_x, wheel_delta_y, nullptr });
enqueue_input_event(Web::MouseEvent { type, position, screen_position.to_type<Web::DevicePixels>(), button, buttons, modifiers, wheel_delta_x, wheel_delta_y, nullptr });
}

struct KeyData : Web::ChromeInputData {
Expand Down
6 changes: 3 additions & 3 deletions Ladybird/Qt/WebContentView.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ class WebContentView final
// ^WebView::ViewImplementation
virtual void initialize_client(CreateNewClient) override;
virtual void update_zoom() override;
virtual Web::DevicePixelRect viewport_rect() const override;
virtual Web::DevicePixelSize viewport_size() const override;
virtual Gfx::IntPoint to_content_position(Gfx::IntPoint widget_position) const override;
virtual Gfx::IntPoint to_widget_position(Gfx::IntPoint content_position) const override;

void update_viewport_rect();
void update_viewport_size();
void update_cursor(Gfx::StandardCursor cursor);

void enqueue_native_event(Web::MouseEvent::Type, QSinglePointEvent const& event);
Expand All @@ -104,7 +104,7 @@ class WebContentView final

bool m_should_show_line_box_borders { false };

Gfx::IntRect m_viewport_rect;
Gfx::IntSize m_viewport_size;

WebContentOptions m_web_content_options;
StringView m_webdriver_content_ipc_path;
Expand Down
4 changes: 4 additions & 0 deletions Tests/LibWeb/Ref/css-background-clip-text.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
<title>Document</title>

<style>
html {
scrollbar-width: none;
}

p, .container {
border: 0.8em darkviolet;
border-style: dotted double;
Expand Down
3 changes: 3 additions & 0 deletions Tests/LibWeb/Ref/reference/css-background-clip-text-ref.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
body {
background-color: white;
}
html {
scrollbar-width: none;
}
</style>
<!-- To rebase:
1. Open background-clip-text.html in Ladybird
Expand Down
5 changes: 4 additions & 1 deletion Tests/LibWeb/Ref/scroll-iframe.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
<script>
const iframe = document.createElement("iframe");
iframe.srcdoc = `
<style>body { margin: 0 }</style>
<style>
body { margin: 0 }
html { scrollbar-width: none; }
</style>
<div style="width: 200px; height: 200px; background-color: darkblue"></div>
<div style="width: 200px; height: 200px; background-color: blue"></div>
<div style="width: 200px; height: 200px; background-color: magenta"></div>
Expand Down
25 changes: 21 additions & 4 deletions Userland/Libraries/LibWeb/DOM/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,15 @@ void Document::invalidate_layout()
schedule_layout_update();
}

static void propagate_scrollbar_width_to_viewport(Element& root_element, Layout::Viewport& viewport)
{
// https://drafts.csswg.org/css-scrollbars/#scrollbar-width
// UAs must apply the scrollbar-color value set on the root element to the viewport.
auto& viewport_computed_values = viewport.mutable_computed_values();
auto& root_element_computed_values = root_element.layout_node()->computed_values();
viewport_computed_values.set_scrollbar_width(root_element_computed_values.scrollbar_width());
}

static void propagate_overflow_to_viewport(Element& root_element, Layout::Viewport& viewport)
{
// https://drafts.csswg.org/css-overflow-3/#overflow-propagation
Expand Down Expand Up @@ -1090,6 +1099,7 @@ void Document::update_layout()

if (document_element && document_element->layout_node()) {
propagate_overflow_to_viewport(*document_element, *m_layout_root);
propagate_scrollbar_width_to_viewport(*document_element, *m_layout_root);
}
}

Expand Down Expand Up @@ -1136,6 +1146,11 @@ void Document::update_layout()
paintable()->recompute_selection_states();

m_needs_layout = false;

// Scrolling by zero offset will clamp scroll offset back to valid range if it was out of bounds
// after the viewport size change.
if (auto window = this->window())
window->scroll_by(0, 0);
}

[[nodiscard]] static CSS::RequiredInvalidationAfterStyleChange update_style_recursively(Node& node, CSS::StyleComputer& style_computer)
Expand Down Expand Up @@ -1906,10 +1921,12 @@ void Document::set_focused_element(Element* element)

// Scroll the viewport if necessary to make the newly focused element visible.
if (m_focused_element) {
ScrollIntoViewOptions scroll_options;
scroll_options.block = Bindings::ScrollLogicalPosition::Nearest;
scroll_options.inline_ = Bindings::ScrollLogicalPosition::Nearest;
(void)m_focused_element->scroll_into_view(scroll_options);
m_focused_element->queue_an_element_task(HTML::Task::Source::UserInteraction, [&]() {
ScrollIntoViewOptions scroll_options;
scroll_options.block = Bindings::ScrollLogicalPosition::Nearest;
scroll_options.inline_ = Bindings::ScrollLogicalPosition::Nearest;
(void)m_focused_element->scroll_into_view(scroll_options);
});
}
}

Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibWeb/DOM/Element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ JS::NonnullGCPtr<Geometry::DOMRectList> Element::get_client_rects() const

if (auto const* paintable_box = this->paintable_box()) {
transform = Gfx::extract_2d_affine_transform(paintable_box->transform());
for (auto const* containing_block = paintable->containing_block(); containing_block; containing_block = containing_block->containing_block()) {
for (auto const* containing_block = paintable->containing_block(); !containing_block->is_viewport(); containing_block = containing_block->containing_block()) {
transform = Gfx::extract_2d_affine_transform(containing_block->transform()).multiply(transform);
scroll_offset.translate_by(containing_block->scroll_offset());
}
Expand Down
Loading
Loading