Use the snapshot from the previous commit to let CompositorThread apply experimental viewport wheel deltas when async scrolling is enabled. The event handler first performs synchronous admission on the main thread, then enqueues a compositor scroll command instead of mutating live document scroll state directly. Rasterize accepted scrolls through the same compositor presentation path added earlier. The compositor stores the newest async viewport offset so the next main-thread display-list recording can adopt it before repainting, preventing older paints from snapping the visible position backward. Keep DOM wheel dispatch on the main thread. When the compositor already performed the default action, dispatch the wheel as non-cancelable and suppress a second default scroll. Non-viewport targets, nested scrollers, and pages with blocking wheel listeners stay synchronous.
132 lines
4.5 KiB
C++
132 lines
4.5 KiB
C++
/*
|
|
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibIPC/Decoder.h>
|
|
#include <LibIPC/Encoder.h>
|
|
#include <LibWeb/Page/InputEvent.h>
|
|
#include <math.h>
|
|
|
|
namespace Web {
|
|
|
|
KeyEvent KeyEvent::clone_without_browser_data() const
|
|
{
|
|
return { type, key, modifiers, code_point, repeat, nullptr };
|
|
}
|
|
|
|
MouseEvent MouseEvent::clone_without_browser_data() const
|
|
{
|
|
return { type, position, screen_position, button, buttons, modifiers, wheel_delta_x, wheel_delta_y, click_count, nullptr, async_scroll_performed_default_action };
|
|
}
|
|
|
|
DragEvent DragEvent::clone_without_browser_data() const
|
|
{
|
|
return { type, position, screen_position, button, buttons, modifiers, {}, nullptr };
|
|
}
|
|
|
|
}
|
|
|
|
template<>
|
|
ErrorOr<void> IPC::encode(Encoder& encoder, Web::KeyEvent const& event)
|
|
{
|
|
TRY(encoder.encode(event.type));
|
|
TRY(encoder.encode(event.key));
|
|
TRY(encoder.encode(event.modifiers));
|
|
TRY(encoder.encode(event.code_point));
|
|
TRY(encoder.encode(event.repeat));
|
|
return {};
|
|
}
|
|
|
|
template<>
|
|
ErrorOr<Web::KeyEvent> IPC::decode(Decoder& decoder)
|
|
{
|
|
auto type = TRY(decoder.decode<Web::KeyEvent::Type>());
|
|
auto key = TRY(decoder.decode<Web::UIEvents::KeyCode>());
|
|
auto modifiers = TRY(decoder.decode<Web::UIEvents::KeyModifier>());
|
|
auto code_point = TRY(decoder.decode<u32>());
|
|
auto repeat = TRY(decoder.decode<bool>());
|
|
|
|
return Web::KeyEvent { type, key, modifiers, code_point, repeat, nullptr };
|
|
}
|
|
|
|
template<>
|
|
ErrorOr<void> IPC::encode(Encoder& encoder, Web::MouseEvent const& event)
|
|
{
|
|
TRY(encoder.encode(event.type));
|
|
TRY(encoder.encode(event.position));
|
|
TRY(encoder.encode(event.screen_position));
|
|
TRY(encoder.encode(event.button));
|
|
TRY(encoder.encode(event.buttons));
|
|
TRY(encoder.encode(event.modifiers));
|
|
TRY(encoder.encode(event.wheel_delta_x));
|
|
TRY(encoder.encode(event.wheel_delta_y));
|
|
TRY(encoder.encode(event.click_count));
|
|
TRY(encoder.encode(event.async_scroll_performed_default_action));
|
|
return {};
|
|
}
|
|
|
|
template<>
|
|
ErrorOr<Web::MouseEvent> IPC::decode(Decoder& decoder)
|
|
{
|
|
auto type = TRY(decoder.decode<Web::MouseEvent::Type>());
|
|
auto position = TRY(decoder.decode<Web::DevicePixelPoint>());
|
|
auto screen_position = TRY(decoder.decode<Web::DevicePixelPoint>());
|
|
auto button = TRY(decoder.decode<Web::UIEvents::MouseButton>());
|
|
auto buttons = TRY(decoder.decode<Web::UIEvents::MouseButton>());
|
|
auto modifiers = TRY(decoder.decode<Web::UIEvents::KeyModifier>());
|
|
auto wheel_delta_x = TRY(decoder.decode<int>());
|
|
auto wheel_delta_y = TRY(decoder.decode<int>());
|
|
auto click_count = TRY(decoder.decode<int>());
|
|
auto async_scroll_performed_default_action = TRY(decoder.decode<bool>());
|
|
|
|
return Web::MouseEvent { type, position, screen_position, button, buttons, modifiers, wheel_delta_x, wheel_delta_y, click_count, nullptr, async_scroll_performed_default_action };
|
|
}
|
|
|
|
template<>
|
|
ErrorOr<void> IPC::encode(Encoder& encoder, Web::DragEvent const& event)
|
|
{
|
|
TRY(encoder.encode(event.type));
|
|
TRY(encoder.encode(event.position));
|
|
TRY(encoder.encode(event.screen_position));
|
|
TRY(encoder.encode(event.button));
|
|
TRY(encoder.encode(event.buttons));
|
|
TRY(encoder.encode(event.modifiers));
|
|
TRY(encoder.encode(event.files));
|
|
return {};
|
|
}
|
|
|
|
template<>
|
|
ErrorOr<Web::DragEvent> IPC::decode(Decoder& decoder)
|
|
{
|
|
auto type = TRY(decoder.decode<Web::DragEvent::Type>());
|
|
auto position = TRY(decoder.decode<Web::DevicePixelPoint>());
|
|
auto screen_position = TRY(decoder.decode<Web::DevicePixelPoint>());
|
|
auto button = TRY(decoder.decode<Web::UIEvents::MouseButton>());
|
|
auto buttons = TRY(decoder.decode<Web::UIEvents::MouseButton>());
|
|
auto modifiers = TRY(decoder.decode<Web::UIEvents::KeyModifier>());
|
|
auto files = TRY(decoder.decode<Vector<Web::HTML::SelectedFile>>());
|
|
|
|
return Web::DragEvent { type, position, screen_position, button, buttons, modifiers, move(files), nullptr };
|
|
}
|
|
|
|
template<>
|
|
WEB_API ErrorOr<void> IPC::encode(Encoder& encoder, Web::PinchEvent const& event)
|
|
{
|
|
TRY(encoder.encode(event.position));
|
|
TRY(encoder.encode(event.scale_delta));
|
|
return {};
|
|
}
|
|
|
|
template<>
|
|
WEB_API ErrorOr<Web::PinchEvent> IPC::decode(Decoder& decoder)
|
|
{
|
|
auto position = TRY(decoder.decode<Web::DevicePixelPoint>());
|
|
auto scale_delta = TRY(decoder.decode<double>());
|
|
|
|
if (isnan(scale_delta) || isinf(scale_delta))
|
|
return Error::from_string_literal("IPC: Invalid scale_delta value");
|
|
|
|
return Web::PinchEvent { position, scale_delta };
|
|
}
|