mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
script: Batch scroll
event firing (#38222)
The user interaction triggered `scroll` event was initially implemented in https://github.com/servo/servo/pull/36687. In triggering the `scroll` event, the event should be batched and triggered within update the rendering. This serves as a preparatory PR for the JS API triggered `scroll` event. Part of: #31665 --------- Signed-off-by: Jo Steven Novaryo <jo.steven.novaryo@huawei.com>
This commit is contained in:
parent
eeac336518
commit
1fb782bc38
2 changed files with 107 additions and 11 deletions
|
@ -572,6 +572,8 @@ pub(crate) struct Document {
|
||||||
/// Cached frozen array of [`Self::adopted_stylesheets`]
|
/// Cached frozen array of [`Self::adopted_stylesheets`]
|
||||||
#[ignore_malloc_size_of = "mozjs"]
|
#[ignore_malloc_size_of = "mozjs"]
|
||||||
adopted_stylesheets_frozen_types: CachedFrozenArray,
|
adopted_stylesheets_frozen_types: CachedFrozenArray,
|
||||||
|
/// <https://drafts.csswg.org/cssom-view/#document-pending-scroll-event-targets>
|
||||||
|
pending_scroll_event_targets: DomRefCell<Vec<Dom<EventTarget>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -2402,10 +2404,102 @@ impl Document {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/cssom-view/#document-run-the-scroll-steps>
|
||||||
|
pub(crate) fn run_the_scroll_steps(&self, can_gc: CanGc) {
|
||||||
|
// Step 1.
|
||||||
|
// > Run the steps to dispatch pending scrollsnapchanging events for doc.
|
||||||
|
// TODO(#7673): Implement scroll snapping
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
// > For each item target in doc’s pending scroll event targets, in the order they
|
||||||
|
// > were added to the list, run these substeps:
|
||||||
|
for target in self.pending_scroll_event_targets.borrow().iter() {
|
||||||
|
// Step 2.1
|
||||||
|
// > If target is a Document, fire an event named scroll that bubbles at target.
|
||||||
|
if target.downcast::<Document>().is_some() {
|
||||||
|
target.fire_bubbling_event(Atom::from("scroll"), can_gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2.2
|
||||||
|
// > Otherwise, fire an event named scroll at target.
|
||||||
|
if target.downcast::<Element>().is_some() {
|
||||||
|
target.fire_event(Atom::from("scroll"), can_gc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
// > Empty doc’s pending scroll event targets.
|
||||||
|
self.pending_scroll_event_targets.borrow_mut().clear();
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
// > Run the steps to dispatch pending scrollsnapchange events for doc.
|
||||||
|
// TODO(#7673): Implement scroll snapping
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whenever a viewport gets scrolled (whether in response to user interaction or by an
|
||||||
|
/// API), the user agent must run these steps:
|
||||||
|
/// <https://drafts.csswg.org/cssom-view/#scrolling-events>
|
||||||
|
pub(crate) fn handle_viewport_scroll_event(&self) {
|
||||||
|
// Step 2.
|
||||||
|
// > If doc is a snap container, run the steps to update scrollsnapchanging targets
|
||||||
|
// > for doc with doc’s eventual snap target in the block axis as newBlockTarget and
|
||||||
|
// > doc’s eventual snap target in the inline axis as newInlineTarget.
|
||||||
|
// TODO(#7673): Implement scroll snapping
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
// > If doc is already in doc’s pending scroll event targets, abort these steps.
|
||||||
|
let target = self.upcast::<EventTarget>();
|
||||||
|
if self
|
||||||
|
.pending_scroll_event_targets
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.any(|other_target| *other_target == target)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
// > Append doc to doc’s pending scroll event targets.
|
||||||
|
self.pending_scroll_event_targets
|
||||||
|
.borrow_mut()
|
||||||
|
.push(Dom::from_ref(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whenever an element gets scrolled (whether in response to user interaction or by an
|
||||||
|
/// API), the user agent must run these steps:
|
||||||
|
/// <https://drafts.csswg.org/cssom-view/#scrolling-events>
|
||||||
|
pub(crate) fn handle_element_scroll_event(&self, element: &Element) {
|
||||||
|
// Step 2.
|
||||||
|
// > If the element is a snap container, run the steps to update scrollsnapchanging
|
||||||
|
// > targets for the element with the element’s eventual snap target in the block
|
||||||
|
// > axis as newBlockTarget and the element’s eventual snap target in the inline axis
|
||||||
|
// > as newInlineTarget.
|
||||||
|
// TODO(#7673): Implement scroll snapping
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
// > If the element is already in doc’s pending scroll event targets, abort these steps.
|
||||||
|
let target = element.upcast::<EventTarget>();
|
||||||
|
if self
|
||||||
|
.pending_scroll_event_targets
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.any(|other_target| *other_target == target)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
// > Append the element to doc’s pending scroll event targets.
|
||||||
|
self.pending_scroll_event_targets
|
||||||
|
.borrow_mut()
|
||||||
|
.push(Dom::from_ref(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle scroll event triggered by user interactions from embedder side.
|
||||||
|
/// <https://drafts.csswg.org/cssom-view/#scrolling-events>
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub(crate) fn handle_scroll_event(&self, event: ScrollEvent, can_gc: CanGc) {
|
pub(crate) fn handle_embedder_scroll_event(&self, event: ScrollEvent) {
|
||||||
// <https://drafts.csswg.org/cssom-view/#scrolling-events>
|
// If it is a viewport scroll.
|
||||||
// If target is a Document, fire an event named scroll that bubbles at target.
|
|
||||||
if event.external_id.is_root() {
|
if event.external_id.is_root() {
|
||||||
let Some(document) = self
|
let Some(document) = self
|
||||||
.node
|
.node
|
||||||
|
@ -2415,10 +2509,10 @@ impl Document {
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
DomRoot::upcast::<EventTarget>(document)
|
|
||||||
.fire_bubbling_event(Atom::from("scroll"), can_gc);
|
document.handle_viewport_scroll_event();
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, fire an event named scroll at target.
|
// Otherwise, check whether it is for a relevant element within the document.
|
||||||
let Some(node_id) = node_id_from_scroll_id(event.external_id.0 as usize) else {
|
let Some(node_id) = node_id_from_scroll_id(event.external_id.0 as usize) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -2432,7 +2526,8 @@ impl Document {
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
DomRoot::upcast::<EventTarget>(element).fire_event(Atom::from("scroll"), can_gc);
|
|
||||||
|
self.handle_element_scroll_event(&element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4266,6 +4361,7 @@ impl Document {
|
||||||
highlighted_dom_node: Default::default(),
|
highlighted_dom_node: Default::default(),
|
||||||
adopted_stylesheets: Default::default(),
|
adopted_stylesheets: Default::default(),
|
||||||
adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
|
adopted_stylesheets_frozen_types: CachedFrozenArray::new(),
|
||||||
|
pending_scroll_event_targets: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1148,7 +1148,7 @@ impl ScriptThread {
|
||||||
document.handle_editing_action(editing_action_event, can_gc);
|
document.handle_editing_action(editing_action_event, can_gc);
|
||||||
},
|
},
|
||||||
InputEvent::Scroll(scroll_event) => {
|
InputEvent::Scroll(scroll_event) => {
|
||||||
document.handle_scroll_event(scroll_event, can_gc);
|
document.handle_embedder_scroll_event(scroll_event);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1254,9 +1254,6 @@ impl ScriptThread {
|
||||||
// https://html.spec.whatwg.org/multipage/#flush-autofocus-candidates.
|
// https://html.spec.whatwg.org/multipage/#flush-autofocus-candidates.
|
||||||
self.process_pending_input_events(*pipeline_id, can_gc);
|
self.process_pending_input_events(*pipeline_id, can_gc);
|
||||||
|
|
||||||
// TODO(#31665): Implement the "run the scroll steps" from
|
|
||||||
// https://drafts.csswg.org/cssom-view/#document-run-the-scroll-steps.
|
|
||||||
|
|
||||||
// > 8. For each doc of docs, run the resize steps for doc. [CSSOMVIEW]
|
// > 8. For each doc of docs, run the resize steps for doc. [CSSOMVIEW]
|
||||||
if document.window().run_the_resize_steps(can_gc) {
|
if document.window().run_the_resize_steps(can_gc) {
|
||||||
// Evaluate media queries and report changes.
|
// Evaluate media queries and report changes.
|
||||||
|
@ -1269,6 +1266,9 @@ impl ScriptThread {
|
||||||
document.react_to_environment_changes()
|
document.react_to_environment_changes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// > 9. For each doc of docs, run the scroll steps for doc.
|
||||||
|
document.run_the_scroll_steps(can_gc);
|
||||||
|
|
||||||
// > 11. For each doc of docs, update animations and send events for doc, passing
|
// > 11. For each doc of docs, update animations and send events for doc, passing
|
||||||
// > in relative high resolution time given frameTimestamp and doc's relevant
|
// > in relative high resolution time given frameTimestamp and doc's relevant
|
||||||
// > global object as the timestamp [WEBANIMATIONS]
|
// > global object as the timestamp [WEBANIMATIONS]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue