mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-19 02:10:26 +00:00
LibWeb/HTML: Return Promises from Window scroll methods
Corresponds to part of:
c548a9a1d4
This commit is contained in:
parent
cae526286a
commit
a610639119
Notes:
github-actions[bot]
2025-12-23 13:25:39 +00:00
Author: https://github.com/AtkinsSJ
Commit: a610639119
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/7184
Reviewed-by: https://github.com/kalenikaliaksandr ✅
7 changed files with 95 additions and 56 deletions
|
|
@ -2784,7 +2784,7 @@ RefPtr<Gfx::SkiaBackendContext> Navigable::skia_backend_context() const
|
|||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#viewport-perform-a-scroll
|
||||
void Navigable::scroll_viewport_by_delta(CSSPixelPoint delta)
|
||||
GC::Ref<WebIDL::Promise> Navigable::scroll_viewport_by_delta(CSSPixelPoint delta)
|
||||
{
|
||||
// 1. Let doc be the viewport’s associated Document.
|
||||
auto doc = active_document();
|
||||
|
|
@ -2828,9 +2828,13 @@ void Navigable::scroll_viewport_by_delta(CSSPixelPoint delta)
|
|||
|
||||
// 13. Let element be doc’s root element if there is one, null otherwise.
|
||||
|
||||
// 14. Perform a scroll of the viewport’s scrolling box to its current scroll position + (layout dx, layout dy) with element as the associated element, and behavior as the scroll behavior.
|
||||
// 14. Perform a scroll of the viewport’s scrolling box to its current scroll position + (layout dx, layout dy)
|
||||
// with element as the associated element, and behavior as the scroll behavior. Let scrollPromise1 be the
|
||||
// Promise returned from this step.
|
||||
// FIXME: Get a Promise from this.
|
||||
// AD-HOC: Skip scrolling unscrollable boxes.
|
||||
if (!doc->paintable_box()->could_be_scrolled_by_wheel_event())
|
||||
return;
|
||||
return WebIDL::create_resolved_promise(doc->realm(), JS::js_undefined());
|
||||
auto scrolling_area = doc->paintable_box()->scrollable_overflow_rect()->to_type<float>();
|
||||
auto new_viewport_scroll_offset = m_viewport_scroll_offset.to_type<double>() + Gfx::Point(layout_dx, layout_dy);
|
||||
// NOTE: Clamp to the scrolling area.
|
||||
|
|
@ -2838,9 +2842,21 @@ void Navigable::scroll_viewport_by_delta(CSSPixelPoint delta)
|
|||
new_viewport_scroll_offset.set_y(max(0.0, min(new_viewport_scroll_offset.y(), scrolling_area.height() - viewport_size().height().to_double())));
|
||||
perform_scroll_of_viewport(new_viewport_scroll_offset.to_type<CSSPixels>());
|
||||
|
||||
// 15. Perform a scroll of vv’s scrolling box to its current scroll position + (visual dx, visual dy) with element as the associated element, and behavior as the scroll behavior.
|
||||
// 15. Perform a scroll of vv’s scrolling box to its current scroll position + (visual dx, visual dy) with element
|
||||
// as the associated element, and behavior as the scroll behavior. Let scrollPromise2 be the Promise returned
|
||||
// from this step.
|
||||
// FIXME: Get a Promise from this.
|
||||
vv->scroll_by({ visual_dx, visual_dy });
|
||||
doc->set_needs_display(InvalidateDisplayList::No);
|
||||
|
||||
// 16. Let scrollPromise be a new Promise.
|
||||
auto scroll_promise = WebIDL::create_promise(doc->realm());
|
||||
|
||||
// 17. Return scrollPromise, and run the remaining steps in parallel.
|
||||
// 18. Resolve scrollPromise when both scrollPromise1 and scrollPromise2 have settled.
|
||||
// FIXME: Actually wait for scroll to occur. For now, all our scrolls are instant.
|
||||
WebIDL::resolve_promise(doc->realm(), scroll_promise);
|
||||
return scroll_promise;
|
||||
}
|
||||
|
||||
void Navigable::reset_zoom()
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ public:
|
|||
template<typename T>
|
||||
bool fast_is() const = delete;
|
||||
|
||||
void scroll_viewport_by_delta(CSSPixelPoint delta);
|
||||
GC::Ref<WebIDL::Promise> scroll_viewport_by_delta(CSSPixelPoint delta);
|
||||
void reset_zoom();
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -1472,31 +1472,38 @@ double Window::scroll_y() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-window-scroll
|
||||
void Window::scroll(ScrollToOptions const& options)
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scroll
|
||||
GC::Ref<WebIDL::Promise> Window::scroll(ScrollToOptions const& options)
|
||||
{
|
||||
// 4. If there is no viewport, abort these steps.
|
||||
// 4. If there is no viewport, return a resolved Promise and abort the remaining steps.
|
||||
// AD-HOC: Done here as step 1 requires the viewport.
|
||||
auto navigable = associated_document().navigable();
|
||||
if (!navigable)
|
||||
return;
|
||||
return WebIDL::create_resolved_promise(realm(), JS::js_undefined());
|
||||
|
||||
// 1. If invoked with one argument, follow these substeps:
|
||||
// NB: This Window::scroll() overload always has one argument.
|
||||
|
||||
// 1. Let options be the argument.
|
||||
// 1. Let options be the argument.
|
||||
auto viewport_rect = navigable->viewport_rect().to_type<float>();
|
||||
|
||||
// 2. Let x be the value of the left dictionary member of options, if present, or the viewport’s current scroll
|
||||
// 2. Let x be the value of the left dictionary member of options, if present, or the viewport’s current scroll
|
||||
// position on the x axis otherwise.
|
||||
auto x = options.left.value_or(viewport_rect.x());
|
||||
|
||||
// 3. Let y be the value of the top dictionary member of options, if present, or the viewport’s current scroll
|
||||
// position on the y axis otherwise.
|
||||
// 3. Let y be the value of the top dictionary member of options, if present, or the viewport’s current scroll
|
||||
// position on the y axis otherwise.
|
||||
auto y = options.top.value_or(viewport_rect.y());
|
||||
|
||||
// 2. If invoked with two arguments, follow these substeps:
|
||||
// NB: Implemented by other Window::scroll() overload.
|
||||
|
||||
// 3. Normalize non-finite values for x and y.
|
||||
x = HTML::normalize_non_finite_values(x);
|
||||
y = HTML::normalize_non_finite_values(y);
|
||||
|
||||
// AD-HOC: Step 4 is done at the start.
|
||||
|
||||
// 5. Let viewport width be the width of the viewport excluding the width of the scroll bar, if any.
|
||||
auto viewport_width = viewport_rect.width();
|
||||
|
||||
|
|
@ -1506,7 +1513,7 @@ void Window::scroll(ScrollToOptions const& options)
|
|||
auto const document = navigable->active_document();
|
||||
VERIFY(document);
|
||||
|
||||
// Make sure layout is up-to-date before looking at scrollable overflow metrics.
|
||||
// NB: Make sure layout is up-to-date before looking at scrollable overflow metrics.
|
||||
document->update_layout(DOM::UpdateLayoutReason::WindowScroll);
|
||||
|
||||
VERIFY(document->paintable_box());
|
||||
|
|
@ -1531,38 +1538,49 @@ void Window::scroll(ScrollToOptions const& options)
|
|||
// with the top of the viewport.
|
||||
auto position = Gfx::FloatPoint { x, y };
|
||||
|
||||
// FIXME: We need an execution context to resolve promises, are we missing one in a caller?
|
||||
TemporaryExecutionContext temporary_execution_context { realm() };
|
||||
|
||||
// 10. If position is the same as the viewport’s current scroll position, and the viewport does not have an ongoing
|
||||
// smooth scroll, abort these steps.
|
||||
// smooth scroll, return a resolved Promise and abort the remaining steps.
|
||||
if (position == viewport_rect.location())
|
||||
return;
|
||||
return WebIDL::create_resolved_promise(realm(), JS::js_undefined());
|
||||
|
||||
// 11. Let document be the viewport’s associated Document.
|
||||
// NOTE: document is already defined above.
|
||||
// NB: document is already defined above.
|
||||
|
||||
// 12. Perform a scroll of the viewport to position, document’s root element as the associated element, if there is
|
||||
// one, or null otherwise, and the scroll behavior being the value of the behavior dictionary member of options.
|
||||
navigable->perform_scroll_of_viewport({ x, y });
|
||||
// Let scrollPromise be the Promise returned from this step.
|
||||
auto scroll_promise = navigable->scroll_viewport_by_delta({ x, y });
|
||||
|
||||
// 13. Return scrollPromise.
|
||||
return scroll_promise;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-window-scroll
|
||||
void Window::scroll(double x, double y)
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scroll
|
||||
GC::Ref<WebIDL::Promise> Window::scroll(double x, double y)
|
||||
{
|
||||
// NB: This just implements step 2, and then forwards to the other Window::scroll() overload.
|
||||
|
||||
// 2. If invoked with two arguments, follow these substeps:
|
||||
|
||||
// 1. Let options be null converted to a ScrollToOptions dictionary. [WEBIDL]
|
||||
// 1. Let options be null converted to a ScrollToOptions dictionary. [WEBIDL]
|
||||
auto options = ScrollToOptions {};
|
||||
|
||||
// 2. Let x and y be the arguments, respectively.
|
||||
|
||||
// 2. Let x and y be the arguments, respectively.
|
||||
options.left = x;
|
||||
options.top = y;
|
||||
|
||||
scroll(options);
|
||||
return scroll(options);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-window-scrollby
|
||||
void Window::scroll_by(ScrollToOptions options)
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scrollby
|
||||
GC::Ref<WebIDL::Promise> Window::scroll_by(ScrollToOptions options)
|
||||
{
|
||||
// 1. If invoked with two arguments, follow these substeps:
|
||||
// NB: Implemented by the other overload, which then calls this.
|
||||
|
||||
// 2. Normalize non-finite values for the left and top dictionary members of options.
|
||||
auto left = HTML::normalize_non_finite_values(options.left);
|
||||
auto top = HTML::normalize_non_finite_values(options.top);
|
||||
|
|
@ -1573,27 +1591,28 @@ void Window::scroll_by(ScrollToOptions options)
|
|||
// 4. Add the value of scrollY to the top dictionary member.
|
||||
options.top = top + scroll_y();
|
||||
|
||||
// 5. Act as if the scroll() method was invoked with options as the only argument.
|
||||
scroll(options);
|
||||
// 5. Return the Promise returned from scroll() after the method is invoked with options as the only argument.
|
||||
return scroll(options);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-window-scrollby
|
||||
void Window::scroll_by(double x, double y)
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scrollby
|
||||
GC::Ref<WebIDL::Promise> Window::scroll_by(double x, double y)
|
||||
{
|
||||
// 1. If invoked with two arguments, follow these substeps:
|
||||
|
||||
// 1. Let options be null converted to a ScrollToOptions dictionary. [WEBIDL]
|
||||
// 1. Let options be null converted to a ScrollToOptions dictionary. [WEBIDL]
|
||||
auto options = ScrollToOptions {};
|
||||
|
||||
// 2. Let x and y be the arguments, respectively.
|
||||
// 2. Let x and y be the arguments, respectively.
|
||||
|
||||
// 3. Let the left dictionary member of options have the value x.
|
||||
// 3. Let the left dictionary member of options have the value x.
|
||||
options.left = x;
|
||||
|
||||
// 4. Let the top dictionary member of options have the value y.
|
||||
// 4. Let the top dictionary member of options have the value y.
|
||||
options.top = y;
|
||||
|
||||
scroll_by(options);
|
||||
// NB: Complete the algorithm using the other overload.
|
||||
return scroll_by(options);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-window-screenx
|
||||
|
|
|
|||
|
|
@ -220,10 +220,10 @@ public:
|
|||
|
||||
double scroll_x() const;
|
||||
double scroll_y() const;
|
||||
void scroll(ScrollToOptions const&);
|
||||
void scroll(double x, double y);
|
||||
void scroll_by(ScrollToOptions);
|
||||
void scroll_by(double x, double y);
|
||||
GC::Ref<WebIDL::Promise> scroll(ScrollToOptions const&);
|
||||
GC::Ref<WebIDL::Promise> scroll(double x, double y);
|
||||
GC::Ref<WebIDL::Promise> scroll_by(ScrollToOptions);
|
||||
GC::Ref<WebIDL::Promise> scroll_by(double x, double y);
|
||||
|
||||
i32 screen_x() const;
|
||||
i32 screen_y() const;
|
||||
|
|
|
|||
|
|
@ -94,12 +94,12 @@ interface Window : EventTarget {
|
|||
[Replaceable, ImplementedAs=scroll_x] readonly attribute double pageXOffset;
|
||||
[Replaceable] readonly attribute double scrollY;
|
||||
[Replaceable, ImplementedAs=scroll_y] readonly attribute double pageYOffset;
|
||||
undefined scroll(optional ScrollToOptions options = {});
|
||||
undefined scroll(unrestricted double x, unrestricted double y);
|
||||
[ImplementedAs=scroll] undefined scrollTo(optional ScrollToOptions options = {});
|
||||
[ImplementedAs=scroll] undefined scrollTo(unrestricted double x, unrestricted double y);
|
||||
undefined scrollBy(optional ScrollToOptions options = {});
|
||||
undefined scrollBy(unrestricted double x, unrestricted double y);
|
||||
Promise<undefined> scroll(optional ScrollToOptions options = {});
|
||||
Promise<undefined> scroll(unrestricted double x, unrestricted double y);
|
||||
[ImplementedAs=scroll] Promise<undefined> scrollTo(optional ScrollToOptions options = {});
|
||||
[ImplementedAs=scroll] Promise<undefined> scrollTo(unrestricted double x, unrestricted double y);
|
||||
Promise<undefined> scrollBy(optional ScrollToOptions options = {});
|
||||
Promise<undefined> scrollBy(unrestricted double x, unrestricted double y);
|
||||
|
||||
// client
|
||||
[Replaceable] readonly attribute long screenX;
|
||||
|
|
|
|||
|
|
@ -1430,10 +1430,14 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u
|
|||
case UIEvents::KeyCode::Key_Down:
|
||||
if (modifiers && modifiers != UIEvents::KeyModifier::Mod_PlatformCtrl)
|
||||
break;
|
||||
if (modifiers)
|
||||
key == UIEvents::KeyCode::Key_Up ? document->scroll_to_the_beginning_of_the_document() : document->window()->scroll_by(0, INT64_MAX);
|
||||
else
|
||||
if (modifiers) {
|
||||
if (key == UIEvents::KeyCode::Key_Up)
|
||||
document->scroll_to_the_beginning_of_the_document();
|
||||
else
|
||||
document->window()->scroll_by(0, INT64_MAX);
|
||||
} else {
|
||||
document->window()->scroll_by(0, key == UIEvents::KeyCode::Key_Up ? -arrow_key_scroll_distance : arrow_key_scroll_distance);
|
||||
}
|
||||
return EventResult::Handled;
|
||||
case UIEvents::KeyCode::Key_Left:
|
||||
case UIEvents::KeyCode::Key_Right:
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
|||
|
||||
Found 415 tests
|
||||
|
||||
325 Pass
|
||||
90 Fail
|
||||
331 Pass
|
||||
84 Fail
|
||||
Pass idl_test setup
|
||||
Pass idl_test validation
|
||||
Pass Partial interface Window: original interface defined
|
||||
|
|
@ -272,12 +272,12 @@ Pass Window interface: attribute scrollX
|
|||
Pass Window interface: attribute pageXOffset
|
||||
Pass Window interface: attribute scrollY
|
||||
Pass Window interface: attribute pageYOffset
|
||||
Fail Window interface: operation scroll(optional ScrollToOptions)
|
||||
Fail Window interface: operation scroll(unrestricted double, unrestricted double)
|
||||
Fail Window interface: operation scrollTo(optional ScrollToOptions)
|
||||
Fail Window interface: operation scrollTo(unrestricted double, unrestricted double)
|
||||
Fail Window interface: operation scrollBy(optional ScrollToOptions)
|
||||
Fail Window interface: operation scrollBy(unrestricted double, unrestricted double)
|
||||
Pass Window interface: operation scroll(optional ScrollToOptions)
|
||||
Pass Window interface: operation scroll(unrestricted double, unrestricted double)
|
||||
Pass Window interface: operation scrollTo(optional ScrollToOptions)
|
||||
Pass Window interface: operation scrollTo(unrestricted double, unrestricted double)
|
||||
Pass Window interface: operation scrollBy(optional ScrollToOptions)
|
||||
Pass Window interface: operation scrollBy(unrestricted double, unrestricted double)
|
||||
Pass Window interface: attribute screenX
|
||||
Pass Window interface: attribute screenLeft
|
||||
Pass Window interface: attribute screenY
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue