LibWeb/HTML: Port Window.scrollBy() to IDL

This commit is contained in:
Linus Groh 2023-03-06 21:17:19 +00:00
parent 2b6d9cca1a
commit 3d075e55f5
Notes: sideshowbarker 2024-07-17 03:03:37 +09:00
3 changed files with 43 additions and 54 deletions

View file

@ -1017,8 +1017,6 @@ WebIDL::ExceptionOr<void> Window::initialize_web_interfaces(Badge<WindowEnvironm
define_native_function(realm, "fetch", Bindings::fetch, 1, attr);
// FIXME: These properties should be [Replaceable] according to the spec, but [Writable+Configurable] is the closest we have.
define_native_function(realm, "scrollBy", scroll_by, 2, attr);
define_native_accessor(realm, "screenX", screen_x_getter, {}, attr);
define_native_accessor(realm, "screenY", screen_y_getter, {}, attr);
define_native_accessor(realm, "screenLeft", screen_left_getter, {}, attr);
@ -1417,12 +1415,51 @@ void Window::scroll(double x, double y)
auto options = ScrollToOptions {};
// 2. Let x and y be the arguments, respectively.
options.left = x;
options.top = y;
scroll(options);
}
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-window-scrollby
void Window::scroll_by(ScrollToOptions options)
{
// 2. Normalize non-finite values for the left and top dictionary members of options.
auto x = options.left.value_or(0);
auto y = options.top.value_or(0);
x = JS::Value(x).is_finite_number() ? x : 0;
y = JS::Value(y).is_finite_number() ? y : 0;
// 3. Add the value of scrollX to the left dictionary member.
options.left = x + scroll_x();
// 4. Add the value of scrollY to the top dictionary member.
options.top = y + scroll_y();
// 5. Act as if the scroll() method was invoked with options as the only argument.
scroll(options);
}
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-window-scrollby
void 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]
auto options = ScrollToOptions {};
// 2. Let x and y be the arguments, respectively.
// 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.
options.top = y;
scroll_by(options);
}
// https://w3c.github.io/hr-time/#dom-windoworworkerglobalscope-performance
WebIDL::ExceptionOr<JS::NonnullGCPtr<HighResolutionTime::Performance>> Window::performance()
{
@ -1643,56 +1680,6 @@ JS_DEFINE_NATIVE_FUNCTION(Window::get_selection)
return impl->associated_document().get_selection();
}
// https://www.w3.org/TR/cssom-view/#dom-window-scrollby
JS_DEFINE_NATIVE_FUNCTION(Window::scroll_by)
{
auto& realm = *vm.current_realm();
auto* impl = TRY(impl_from(vm));
if (!impl->page())
return JS::js_undefined();
auto& page = *impl->page();
JS::Object* options = nullptr;
if (vm.argument_count() == 0) {
options = JS::Object::create(realm, nullptr);
} else if (vm.argument_count() == 1) {
options = TRY(vm.argument(0).to_object(vm));
} else if (vm.argument_count() >= 2) {
// We ignore arguments 2+ in line with behavior of Chrome and Firefox
options = JS::Object::create(realm, nullptr);
MUST(options->set("left", vm.argument(0), ShouldThrowExceptions::No));
MUST(options->set("top", vm.argument(1), ShouldThrowExceptions::No));
MUST(options->set("behavior", MUST_OR_THROW_OOM(JS::PrimitiveString::create(vm, "auto"sv)), ShouldThrowExceptions::No));
}
auto left_value = TRY(options->get("left"));
auto left = TRY(left_value.to_double(vm));
auto top_value = TRY(options->get("top"));
auto top = TRY(top_value.to_double(vm));
left = JS::Value(left).is_finite_number() ? left : 0.0;
top = JS::Value(top).is_finite_number() ? top : 0.0;
auto current_scroll_position = page.top_level_browsing_context().viewport_scroll_offset().to_type<float>();
left = left + static_cast<double>(current_scroll_position.x());
top = top + static_cast<double>(current_scroll_position.y());
auto behavior_string_value = TRY(options->get("behavior"));
auto behavior_string = behavior_string_value.is_undefined() ? "auto" : TRY(behavior_string_value.to_deprecated_string(vm));
if (behavior_string != "smooth" && behavior_string != "auto")
return vm.throw_completion<JS::TypeError>("Behavior is not one of 'smooth' or 'auto'"sv);
auto behavior = (behavior_string == "smooth") ? Bindings::ScrollBehavior::Smooth : Bindings::ScrollBehavior::Auto;
// FIXME: Spec wants us to call scroll(options) here.
// The only difference is that would invoke the viewport calculations that scroll()
// is not actually doing yet, so this is the same for now.
perform_a_scroll(page, left, top, nullptr, behavior);
return JS::js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(Window::screen_left_getter)
{
auto* impl = TRY(impl_from(vm));

View file

@ -177,6 +177,8 @@ public:
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);
WebIDL::ExceptionOr<JS::NonnullGCPtr<HighResolutionTime::Performance>> performance();
@ -246,8 +248,6 @@ private:
JS_DECLARE_NATIVE_FUNCTION(device_pixel_ratio_getter);
JS_DECLARE_NATIVE_FUNCTION(scroll_by);
JS_DECLARE_NATIVE_FUNCTION(screen_x_getter);
JS_DECLARE_NATIVE_FUNCTION(screen_y_getter);
JS_DECLARE_NATIVE_FUNCTION(screen_left_getter);

View file

@ -61,6 +61,8 @@ interface Window : EventTarget {
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);
// FIXME: Everything from here on should be shared through WindowOrWorkerGlobalScope
// https://w3c.github.io/hr-time/#the-performance-attribute