From 48e14be7ff17874d68eb394a649449cf848ed257 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Mon, 14 Jul 2025 10:26:29 +0200 Subject: [PATCH] script: Unify script-based "update the rendering" and throttle it to 60 FPS Instead of running "update the rendering" at every IPC message, only run it when a timeout has occured in script. In addition, avoid updating the rendering if a rendering update isn't necessary. This should greatly reduce the amount of processing that has to happen in script. Because we are running many fewer calls to "update the rendering" it is reasonable now to ensure that these always work the same way. In particular, we always run rAF and update the animation timeline when updating the ernder In addition, pull the following things out of reflow: - Code dealing with informing the Constellation that a Pipeline has become Idle when waiting for a screenshot. - Detecting when it is time to fulfill the `document.fonts.ready` promise. The latter means that reflow can never cause a garbage collection, making timing of reflows more consistent and simplifying many callsites that need to do script queries. Followup changes will seek to simplify the way that ScriptThread-driven animation timeouts happen even simpler. Signed-off-by: Martin Robinson Co-authored-by: Oriol Brufau --- components/layout/layout_impl.rs | 4 + components/script/canvas_state.rs | 49 +--- components/script/devtools.rs | 15 +- components/script/dom/canvasgradient.rs | 4 +- .../script/dom/canvasrenderingcontext2d.rs | 28 +- components/script/dom/cssstyledeclaration.rs | 18 +- components/script/dom/document.rs | 112 ++++++-- components/script/dom/documentorshadowroot.rs | 11 +- components/script/dom/element.rs | 169 +++++------ components/script/dom/fontfaceset.rs | 13 +- components/script/dom/history.rs | 2 +- components/script/dom/htmlanchorelement.rs | 4 +- components/script/dom/htmlelement.rs | 34 +-- components/script/dom/htmliframeelement.rs | 2 +- components/script/dom/htmlimageelement.rs | 8 +- components/script/dom/htmlinputelement.rs | 9 +- components/script/dom/htmlscriptelement.rs | 4 +- components/script/dom/htmlselectelement.rs | 6 +- components/script/dom/mouseevent.rs | 13 +- components/script/dom/node.rs | 27 +- .../dom/offscreencanvasrenderingcontext2d.rs | 20 +- .../script/dom/paintrenderingcontext2d.rs | 12 +- components/script/dom/pointerevent.rs | 2 +- components/script/dom/range.rs | 7 +- components/script/dom/resizeobserver.rs | 15 +- components/script/dom/servoparser/mod.rs | 4 +- components/script/dom/shadowroot.rs | 17 +- components/script/dom/wheelevent.rs | 4 +- components/script/dom/window.rs | 233 +++++++--------- components/script/microtask.rs | 2 - components/script/script_thread.rs | 263 ++++++++---------- components/script/task_manager.rs | 1 - components/script/webdriver_handlers.rs | 28 +- .../script_bindings/codegen/Bindings.conf | 34 +-- components/shared/layout/lib.rs | 3 + .../layer-statement-before-import.html.ini | 3 - tests/wpt/mozilla/meta/MANIFEST.json | 6 +- .../css/animations/basic-transition.html | 21 +- .../tests/css/animations/transition-raf.html | 7 +- .../tests/css/stylesheet_media_queries.html | 6 +- 40 files changed, 566 insertions(+), 654 deletions(-) delete mode 100644 tests/wpt/meta/css/css-cascade/layer-statement-before-import.html.ini diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index 43fa3f5a132..15820ad574b 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -495,6 +495,10 @@ impl Layout for LayoutThread { .as_mut() .and_then(|tree| tree.compositor_info.scroll_tree.scroll_offset(id)) } + + fn needs_new_display_list(&self) -> bool { + self.need_new_display_list.get() + } } impl LayoutThread { diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs index c95c9d736ce..190069962d2 100644 --- a/components/script/canvas_state.rs +++ b/components/script/canvas_state.rs @@ -1097,13 +1097,8 @@ impl CanvasState { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor - pub(crate) fn set_shadow_color( - &self, - canvas: Option<&HTMLCanvasElement>, - value: DOMString, - can_gc: CanGc, - ) { - if let Ok(rgba) = parse_color(canvas, &value, can_gc) { + pub(crate) fn set_shadow_color(&self, canvas: Option<&HTMLCanvasElement>, value: DOMString) { + if let Ok(rgba) = parse_color(canvas, &value) { self.state.borrow_mut().shadow_color = rgba; } } @@ -1130,11 +1125,10 @@ impl CanvasState { &self, canvas: Option<&HTMLCanvasElement>, value: StringOrCanvasGradientOrCanvasPattern, - can_gc: CanGc, ) { match value { StringOrCanvasGradientOrCanvasPattern::String(string) => { - if let Ok(rgba) = parse_color(canvas, &string, can_gc) { + if let Ok(rgba) = parse_color(canvas, &string) { self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba); } }, @@ -1174,11 +1168,10 @@ impl CanvasState { &self, canvas: Option<&HTMLCanvasElement>, value: StringOrCanvasGradientOrCanvasPattern, - can_gc: CanGc, ) { match value { StringOrCanvasGradientOrCanvasPattern::String(string) => { - if let Ok(rgba) = parse_color(canvas, &string, can_gc) { + if let Ok(rgba) = parse_color(canvas, &string) { self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba); } }, @@ -1383,7 +1376,6 @@ impl CanvasState { x: f64, y: f64, max_width: Option, - can_gc: CanGc, ) { if !x.is_finite() || !y.is_finite() { return; @@ -1392,11 +1384,7 @@ impl CanvasState { return; } if self.state.borrow().font_style.is_none() { - self.set_font( - canvas, - CanvasContextState::DEFAULT_FONT_STYLE.into(), - can_gc, - ) + self.set_font(canvas, CanvasContextState::DEFAULT_FONT_STYLE.into()) } let is_rtl = match self.state.borrow().direction { @@ -1429,11 +1417,7 @@ impl CanvasState { can_gc: CanGc, ) -> DomRoot { if self.state.borrow().font_style.is_none() { - self.set_font( - canvas, - CanvasContextState::DEFAULT_FONT_STYLE.into(), - can_gc, - ); + self.set_font(canvas, CanvasContextState::DEFAULT_FONT_STYLE.into()); } let (sender, receiver) = ipc::channel::().unwrap(); @@ -1463,23 +1447,17 @@ impl CanvasState { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-font - pub(crate) fn set_font( - &self, - canvas: Option<&HTMLCanvasElement>, - value: DOMString, - can_gc: CanGc, - ) { + pub(crate) fn set_font(&self, canvas: Option<&HTMLCanvasElement>, value: DOMString) { let canvas = match canvas { Some(element) => element, None => return, // offscreen canvas doesn't have a placeholder canvas }; let node = canvas.upcast::(); let window = canvas.owner_window(); - let resolved_font_style = - match window.resolved_font_style_query(node, value.to_string(), can_gc) { - Some(value) => value, - None => return, // syntax error - }; + let resolved_font_style = match window.resolved_font_style_query(node, value.to_string()) { + Some(value) => value, + None => return, // syntax error + }; self.state.borrow_mut().font_style = Some((*resolved_font_style).clone()); } @@ -2204,7 +2182,6 @@ impl Drop for CanvasState { pub(crate) fn parse_color( canvas: Option<&HTMLCanvasElement>, string: &str, - can_gc: CanGc, ) -> Result { let mut input = ParserInput::new(string); let mut parser = Parser::new(&mut input); @@ -2233,8 +2210,8 @@ pub(crate) fn parse_color( None => AbsoluteColor::BLACK, Some(canvas) => { let canvas_element = canvas.upcast::(); - match canvas_element.style(can_gc) { - Some(ref s) if canvas_element.has_css_layout_box(can_gc) => { + match canvas_element.style() { + Some(ref s) if canvas_element.has_css_layout_box() => { s.get_inherited_text().color }, _ => AbsoluteColor::BLACK, diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 945470194e2..37554210cf4 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -216,7 +216,7 @@ pub(crate) fn handle_get_attribute_style( let name = style.Item(i); NodeStyle { name: name.to_string(), - value: style.GetPropertyValue(name.clone(), can_gc).to_string(), + value: style.GetPropertyValue(name.clone()).to_string(), priority: style.GetPropertyPriority(name).to_string(), } }) @@ -259,7 +259,7 @@ pub(crate) fn handle_get_stylesheet_style( let name = style.Item(i); NodeStyle { name: name.to_string(), - value: style.GetPropertyValue(name.clone(), can_gc).to_string(), + value: style.GetPropertyValue(name.clone()).to_string(), priority: style.GetPropertyPriority(name).to_string(), } }) @@ -315,7 +315,6 @@ pub(crate) fn handle_get_computed_style( pipeline: PipelineId, node_id: String, reply: IpcSender>>, - can_gc: CanGc, ) { let node = match find_node_by_unique_id(documents, pipeline, &node_id) { None => return reply.send(None).unwrap(), @@ -333,9 +332,7 @@ pub(crate) fn handle_get_computed_style( let name = computed_style.Item(i); NodeStyle { name: name.to_string(), - value: computed_style - .GetPropertyValue(name.clone(), can_gc) - .to_string(), + value: computed_style.GetPropertyValue(name.clone()).to_string(), priority: computed_style.GetPropertyPriority(name).to_string(), } }) @@ -375,7 +372,7 @@ pub(crate) fn handle_get_layout( position: String::from(computed_style.Position()), z_index: String::from(computed_style.ZIndex()), box_sizing: String::from(computed_style.BoxSizing()), - auto_margins: determine_auto_margins(&node, can_gc), + auto_margins: determine_auto_margins(&node), margin_top: String::from(computed_style.MarginTop()), margin_right: String::from(computed_style.MarginRight()), margin_bottom: String::from(computed_style.MarginBottom()), @@ -394,8 +391,8 @@ pub(crate) fn handle_get_layout( .unwrap(); } -fn determine_auto_margins(node: &Node, can_gc: CanGc) -> AutoMargins { - let style = node.style(can_gc).unwrap(); +fn determine_auto_margins(node: &Node) -> AutoMargins { + let style = node.style().unwrap(); let margin = style.get_margin(); AutoMargins { top: margin.margin_top.is_auto(), diff --git a/components/script/dom/canvasgradient.rs b/components/script/dom/canvasgradient.rs index 5eb1318d707..c6f0c52cb8c 100644 --- a/components/script/dom/canvasgradient.rs +++ b/components/script/dom/canvasgradient.rs @@ -57,12 +57,12 @@ impl CanvasGradient { impl CanvasGradientMethods for CanvasGradient { // https://html.spec.whatwg.org/multipage/#dom-canvasgradient-addcolorstop - fn AddColorStop(&self, offset: Finite, color: DOMString, can_gc: CanGc) -> ErrorResult { + fn AddColorStop(&self, offset: Finite, color: DOMString) -> ErrorResult { if *offset < 0f64 || *offset > 1f64 { return Err(Error::IndexSize); } - let color = match parse_color(None, &color, can_gc) { + let color = match parse_color(None, &color) { Ok(color) => color, Err(_) => return Err(Error::Syntax), }; diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index d6c94ccc1cb..2e12f93eafb 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -327,15 +327,9 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingCo } // https://html.spec.whatwg.org/multipage/#dom-context-2d-filltext - fn FillText(&self, text: DOMString, x: f64, y: f64, max_width: Option, can_gc: CanGc) { - self.canvas_state.fill_text( - self.canvas.canvas().as_deref(), - text, - x, - y, - max_width, - can_gc, - ); + fn FillText(&self, text: DOMString, x: f64, y: f64, max_width: Option) { + self.canvas_state + .fill_text(self.canvas.canvas().as_deref(), text, x, y, max_width); self.mark_as_dirty(); } @@ -355,9 +349,9 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingCo } // https://html.spec.whatwg.org/multipage/#dom-context-2d-font - fn SetFont(&self, value: DOMString, can_gc: CanGc) { + fn SetFont(&self, value: DOMString) { self.canvas_state - .set_font(self.canvas.canvas().as_deref(), value, can_gc) + .set_font(self.canvas.canvas().as_deref(), value) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign @@ -504,9 +498,9 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingCo } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle - fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern, can_gc: CanGc) { + fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) { self.canvas_state - .set_stroke_style(self.canvas.canvas().as_deref(), value, can_gc) + .set_stroke_style(self.canvas.canvas().as_deref(), value) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle @@ -515,9 +509,9 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingCo } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle - fn SetFillStyle(&self, value: StringOrCanvasGradientOrCanvasPattern, can_gc: CanGc) { + fn SetFillStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) { self.canvas_state - .set_fill_style(self.canvas.canvas().as_deref(), value, can_gc) + .set_fill_style(self.canvas.canvas().as_deref(), value) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata @@ -715,8 +709,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingCo } // https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor - fn SetShadowColor(&self, value: DOMString, can_gc: CanGc) { + fn SetShadowColor(&self, value: DOMString) { self.canvas_state - .set_shadow_color(self.canvas.canvas().as_deref(), value, can_gc) + .set_shadow_color(self.canvas.canvas().as_deref(), value) } } diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index de4b87cb2ca..2cb2f979088 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -204,7 +204,7 @@ macro_rules! css_properties( $id.enabled_for_all_content(), "Someone forgot a #[Pref] annotation" ); - self.get_property_value($id, CanGc::note()) + self.get_property_value($id) } fn $setter(&self, value: DOMString) -> ErrorResult { debug_assert!( @@ -268,7 +268,7 @@ impl CSSStyleDeclaration { ) } - fn get_computed_style(&self, property: PropertyId, can_gc: CanGc) -> DOMString { + fn get_computed_style(&self, property: PropertyId) -> DOMString { match self.owner { CSSStyleOwner::CSSRule(..) => { panic!("get_computed_style called on CSSStyleDeclaration with a CSSRule owner") @@ -280,20 +280,20 @@ impl CSSStyleDeclaration { } let addr = node.to_trusted_node_address(); node.owner_window() - .resolved_style_query(addr, self.pseudo, property, can_gc) + .resolved_style_query(addr, self.pseudo, property) }, CSSStyleOwner::Null => DOMString::new(), } } - fn get_property_value(&self, id: PropertyId, can_gc: CanGc) -> DOMString { + fn get_property_value(&self, id: PropertyId) -> DOMString { if matches!(self.owner, CSSStyleOwner::Null) { return DOMString::new(); } if self.readonly { // Readonly style declarations are used for getComputedStyle. - return self.get_computed_style(id, can_gc); + return self.get_computed_style(id); } let mut string = String::new(); @@ -431,12 +431,12 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration { } // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue - fn GetPropertyValue(&self, property: DOMString, can_gc: CanGc) -> DOMString { + fn GetPropertyValue(&self, property: DOMString) -> DOMString { let id = match PropertyId::parse_enabled_for_all_content(&property) { Ok(id) => id, Err(..) => return DOMString::new(), }; - self.get_property_value(id, can_gc) + self.get_property_value(id) } // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority @@ -502,8 +502,8 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration { } // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat - fn CssFloat(&self, can_gc: CanGc) -> DOMString { - self.get_property_value(PropertyId::NonCustom(LonghandId::Float.into()), can_gc) + fn CssFloat(&self) -> DOMString { + self.get_property_value(PropertyId::NonCustom(LonghandId::Float.into())) } // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-cssfloat diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 6c659550411..88325f10654 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -1034,7 +1034,7 @@ impl Document { /// Scroll to the target element, and when we do not find a target /// and the fragment is empty or "top", scroll to the top. /// - pub(crate) fn check_and_scroll_fragment(&self, fragment: &str, can_gc: CanGc) { + pub(crate) fn check_and_scroll_fragment(&self, fragment: &str) { let target = self.find_fragment_node(fragment); // Step 1 @@ -1047,9 +1047,7 @@ impl Document { // inside other scrollable containers. Ideally this should use an implementation of // `scrollIntoView` when that is available: // See https://github.com/servo/servo/issues/24059. - let rect = element - .upcast::() - .bounding_content_box_or_zero(can_gc); + let rect = element.upcast::().bounding_content_box_or_zero(); // In order to align with element edges, we snap to unscaled pixel boundaries, since // the paint thread currently does the same for drawing elements. This is important @@ -1073,7 +1071,7 @@ impl Document { if let Some((x, y)) = point { self.window - .scroll(x as f64, y as f64, ScrollBehavior::Instant, can_gc) + .scroll(x as f64, y as f64, ScrollBehavior::Instant) } } @@ -1349,7 +1347,7 @@ impl Document { // Notify the embedder to display an input method. if let Some(kind) = elem.input_method_type() { - let rect = elem.upcast::().bounding_content_box_or_zero(can_gc); + let rect = elem.upcast::().bounding_content_box_or_zero(); let rect = Rect::new( Point2D::new(rect.origin.x.to_px(), rect.origin.y.to_px()), Size2D::new(rect.size.width.to_px(), rect.size.height.to_px()), @@ -2886,7 +2884,7 @@ impl Document { // We finished loading the page, so if the `Window` is still waiting for // the first layout, allow it. if self.has_browsing_context && self.is_fully_active() { - self.window().allow_layout_if_necessary(can_gc); + self.window().allow_layout_if_necessary(); } // Deferred scripts have to wait for page to finish loading, @@ -3124,7 +3122,7 @@ impl Document { update_with_current_instant(&document.load_event_end); if let Some(fragment) = document.url().fragment() { - document.check_and_scroll_fragment(fragment, CanGc::note()); + document.check_and_scroll_fragment(fragment); } })); @@ -3658,6 +3656,31 @@ impl Document { self.webgpu_contexts.clone() } + /// Whether or not this [`Document`] needs a rendering update, due to changed + /// contents or pending events. + pub(crate) fn needs_rendering_update(&self) -> bool { + if !self.is_fully_active() { + return false; + } + if !self.window().layout_blocked() && + (!self.restyle_reason().is_empty() || + self.window().layout().needs_new_display_list()) + { + return true; + } + if self.has_pending_input_events() { + return true; + } + if self.has_pending_scroll_events() { + return true; + } + if self.window().has_unhandled_resize_event() { + return true; + } + + false + } + /// An implementation of step 22 from /// : /// @@ -3665,7 +3688,7 @@ impl Document { // > doc and its node navigable to reflect the current state. // // Returns true if a reflow occured. - pub(crate) fn update_the_rendering(&self, can_gc: CanGc) -> bool { + pub(crate) fn update_the_rendering(&self) -> bool { self.update_animating_images(); // All dirty canvases are flushed before updating the rendering. @@ -3701,10 +3724,40 @@ impl Document { } self.window() - .reflow(ReflowGoal::UpdateTheRendering, can_gc) + .reflow(ReflowGoal::UpdateTheRendering) .reflow_issued } + /// From : + /// + /// > A FontFaceSet is pending on the environment if any of the following are true: + /// > - the document is still loading + /// > - the document has pending stylesheet requests + /// > - the document has pending layout operations which might cause the user agent to request + /// > a font, or which depend on recently-loaded fonts + /// + /// Returns true if the promise was fulfilled. + pub(crate) fn maybe_fulfill_font_ready_promise(&self, can_gc: CanGc) -> bool { + if !self.is_fully_active() { + return false; + } + + let fonts = self.Fonts(can_gc); + if !fonts.waiting_to_fullfill_promise() { + return false; + } + if self.window().font_context().web_fonts_still_loading() != 0 { + return false; + } + if self.ReadyState() != DocumentReadyState::Complete { + return false; + } + if !self.restyle_reason().is_empty() { + return false; + } + fonts.fulfill_ready_promise_if_needed(can_gc) + } + pub(crate) fn id_map(&self) -> Ref>>> { self.id_map.borrow() } @@ -3720,19 +3773,22 @@ impl Document { .push(Dom::from_ref(resize_observer)); } + /// Whether or not this [`Document`] has any active [`ResizeObserver`]. + pub(crate) fn has_resize_observers(&self) -> bool { + !self.resize_observers.borrow().is_empty() + } + /// /// pub(crate) fn gather_active_resize_observations_at_depth( &self, depth: &ResizeObservationDepth, - can_gc: CanGc, ) -> bool { let mut has_active_resize_observations = false; for observer in self.resize_observers.borrow_mut().iter_mut() { observer.gather_active_resize_observations_at_depth( depth, &mut has_active_resize_observations, - can_gc, ); } has_active_resize_observations @@ -4431,6 +4487,18 @@ impl Document { mem::take(&mut *self.pending_input_events.borrow_mut()) } + /// Whether or not this [`Document`] has any pending input events to be processed during + /// "update the rendering." + pub(crate) fn has_pending_input_events(&self) -> bool { + !self.pending_input_events.borrow().is_empty() + } + + /// Whether or not this [`Document`] has any pending scroll events to be processed during + /// "update the rendering." + fn has_pending_scroll_events(&self) -> bool { + !self.pending_scroll_event_targets.borrow().is_empty() + } + pub(crate) fn set_csp_list(&self, csp_list: Option) { self.policy_container.borrow_mut().set_csp_list(csp_list); } @@ -6524,39 +6592,27 @@ impl DocumentMethods for Document { ); // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint - fn ElementFromPoint( - &self, - x: Finite, - y: Finite, - can_gc: CanGc, - ) -> Option> { + fn ElementFromPoint(&self, x: Finite, y: Finite) -> Option> { self.document_or_shadow_root.element_from_point( x, y, self.GetDocumentElement(), self.has_browsing_context, - can_gc, ) } // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint - fn ElementsFromPoint( - &self, - x: Finite, - y: Finite, - can_gc: CanGc, - ) -> Vec> { + fn ElementsFromPoint(&self, x: Finite, y: Finite) -> Vec> { self.document_or_shadow_root.elements_from_point( x, y, self.GetDocumentElement(), self.has_browsing_context, - can_gc, ) } /// - fn GetScrollingElement(&self, can_gc: CanGc) -> Option> { + fn GetScrollingElement(&self) -> Option> { // Step 1. If the Document is in quirks mode, follow these steps: if self.quirks_mode() == QuirksMode::Quirks { // Step 1.1. If the body element exists, @@ -6565,7 +6621,7 @@ impl DocumentMethods for Document { // and it is not potentially scrollable, return the body element and abort these steps. // For this purpose, a value of overflow:clip on the the body element’s parent element // must be treated as overflow:hidden. - if !e.is_potentially_scrollable_body_for_scrolling_element(can_gc) { + if !e.is_potentially_scrollable_body_for_scrolling_element() { return Some(DomRoot::from_ref(e)); } } diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs index 1de7f574944..0e617712d34 100644 --- a/components/script/dom/documentorshadowroot.rs +++ b/components/script/dom/documentorshadowroot.rs @@ -35,7 +35,6 @@ use crate::dom::shadowroot::ShadowRoot; use crate::dom::stylesheetlist::StyleSheetListOwner; use crate::dom::types::CSSStyleSheet; use crate::dom::window::Window; -use crate::script_runtime::CanGc; use crate::stylesheet_set::StylesheetSetRef; /// Stylesheet could be constructed by a CSSOM object CSSStylesheet or parsed @@ -141,10 +140,8 @@ impl DocumentOrShadowRoot { &self, client_point: &Point2D, query_type: NodesFromPointQueryType, - can_gc: CanGc, ) -> Vec { - self.window - .layout_reflow(QueryMsg::NodesFromPointQuery, can_gc); + self.window.layout_reflow(QueryMsg::NodesFromPointQuery); self.window .layout() .query_nodes_from_point(*client_point, query_type) @@ -158,7 +155,6 @@ impl DocumentOrShadowRoot { y: Finite, document_element: Option>, has_browsing_context: bool, - can_gc: CanGc, ) -> Option> { let x = *x as f32; let y = *y as f32; @@ -174,7 +170,7 @@ impl DocumentOrShadowRoot { } match self - .nodes_from_point(point, NodesFromPointQueryType::Topmost, can_gc) + .nodes_from_point(point, NodesFromPointQueryType::Topmost) .first() { Some(address) => { @@ -206,7 +202,6 @@ impl DocumentOrShadowRoot { y: Finite, document_element: Option>, has_browsing_context: bool, - can_gc: CanGc, ) -> Vec> { let x = *x as f32; let y = *y as f32; @@ -223,7 +218,7 @@ impl DocumentOrShadowRoot { } // Step 1 and Step 3 - let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All, can_gc); + let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All); let mut elements: Vec> = nodes .iter() .flat_map(|&untrusted_node_address| { diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 00d1e0a62c6..cbfbf630eb4 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -464,34 +464,30 @@ impl Element { /// style will be `None` for elements in a `display: none` subtree. otherwise, the element has a /// layout box iff it doesn't have `display: none`. - pub(crate) fn style(&self, can_gc: CanGc) -> Option> { - self.upcast::().style(can_gc) + pub(crate) fn style(&self) -> Option> { + self.upcast::().style() } // https://drafts.csswg.org/cssom-view/#css-layout-box - pub(crate) fn has_css_layout_box(&self, can_gc: CanGc) -> bool { - self.style(can_gc) + pub(crate) fn has_css_layout_box(&self) -> bool { + self.style() .is_some_and(|s| !s.get_box().clone_display().is_none()) } /// - pub(crate) fn is_potentially_scrollable_body(&self, can_gc: CanGc) -> bool { - self.is_potentially_scrollable_body_shared_logic(false, can_gc) + pub(crate) fn is_potentially_scrollable_body(&self) -> bool { + self.is_potentially_scrollable_body_shared_logic(false) } /// - pub(crate) fn is_potentially_scrollable_body_for_scrolling_element( - &self, - can_gc: CanGc, - ) -> bool { - self.is_potentially_scrollable_body_shared_logic(true, can_gc) + pub(crate) fn is_potentially_scrollable_body_for_scrolling_element(&self) -> bool { + self.is_potentially_scrollable_body_shared_logic(true) } /// fn is_potentially_scrollable_body_shared_logic( &self, treat_overflow_clip_on_parent_as_hidden: bool, - can_gc: CanGc, ) -> bool { let node = self.upcast::(); debug_assert!( @@ -502,14 +498,14 @@ impl Element { // "An element body (which will be the body element) is potentially // scrollable if all of the following conditions are true: // - body has an associated box." - if !self.has_css_layout_box(can_gc) { + if !self.has_css_layout_box() { return false; } // " - body’s parent element’s computed value of the overflow-x or // overflow-y properties is neither visible nor clip." if let Some(parent) = node.GetParentElement() { - if let Some(style) = parent.style(can_gc) { + if let Some(style) = parent.style() { let mut overflow_x = style.get_box().clone_overflow_x(); let mut overflow_y = style.get_box().clone_overflow_y(); @@ -532,7 +528,7 @@ impl Element { // " - body’s computed value of the overflow-x or overflow-y properties // is neither visible nor clip." - if let Some(style) = self.style(can_gc) { + if let Some(style) = self.style() { if !style.get_box().clone_overflow_x().is_scrollable() && !style.get_box().clone_overflow_y().is_scrollable() { @@ -544,18 +540,17 @@ impl Element { } // https://drafts.csswg.org/cssom-view/#scrolling-box - fn has_scrolling_box(&self, can_gc: CanGc) -> bool { + fn has_scrolling_box(&self) -> bool { // TODO: scrolling mechanism, such as scrollbar (We don't have scrollbar yet) // self.has_scrolling_mechanism() - self.style(can_gc).is_some_and(|style| { + self.style().is_some_and(|style| { style.get_box().clone_overflow_x().is_scrollable() || style.get_box().clone_overflow_y().is_scrollable() }) } - fn has_overflow(&self, can_gc: CanGc) -> bool { - self.ScrollHeight(can_gc) > self.ClientHeight(can_gc) || - self.ScrollWidth(can_gc) > self.ClientWidth(can_gc) + fn has_overflow(&self) -> bool { + self.ScrollHeight() > self.ClientHeight() || self.ScrollWidth() > self.ClientWidth() } pub(crate) fn shadow_root(&self) -> Option> { @@ -2477,7 +2472,7 @@ impl Element { // https://drafts.csswg.org/cssom-view/#dom-element-scroll // TODO(stevennovaryo): Need to update the scroll API to follow the spec since it is quite outdated. - pub(crate) fn scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior, can_gc: CanGc) { + pub(crate) fn scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior) { // Step 1.2 or 2.3 let x = if x_.is_finite() { x_ } else { 0.0f64 }; let y = if y_.is_finite() { y_ } else { 0.0f64 }; @@ -2501,7 +2496,7 @@ impl Element { // Step 7 if *self.root_element() == *self { if doc.quirks_mode() != QuirksMode::Quirks { - win.scroll(x, y, behavior, can_gc); + win.scroll(x, y, behavior); } return; @@ -2510,22 +2505,19 @@ impl Element { // Step 9 if doc.GetBody().as_deref() == self.downcast::() && doc.quirks_mode() == QuirksMode::Quirks && - !self.is_potentially_scrollable_body(can_gc) + !self.is_potentially_scrollable_body() { - win.scroll(x, y, behavior, can_gc); + win.scroll(x, y, behavior); return; } // Step 10 - if !self.has_css_layout_box(can_gc) || - !self.has_scrolling_box(can_gc) || - !self.has_overflow(can_gc) - { + if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() { return; } // Step 11 - win.scroll_an_element(self, x, y, behavior, can_gc); + win.scroll_an_element(self, x, y, behavior); } /// @@ -3058,7 +3050,7 @@ impl ElementMethods for Element { // https://drafts.csswg.org/cssom-view/#dom-element-getclientrects fn GetClientRects(&self, can_gc: CanGc) -> DomRoot { let win = self.owner_window(); - let raw_rects = self.upcast::().content_boxes(can_gc); + let raw_rects = self.upcast::().content_boxes(); let rects: Vec> = raw_rects .iter() .map(|rect| { @@ -3078,7 +3070,7 @@ impl ElementMethods for Element { // https://drafts.csswg.org/cssom-view/#dom-element-getboundingclientrect fn GetBoundingClientRect(&self, can_gc: CanGc) -> DomRoot { let win = self.owner_window(); - let rect = self.upcast::().bounding_content_box_or_zero(can_gc); + let rect = self.upcast::().bounding_content_box_or_zero(); DOMRect::new( win.upcast(), rect.origin.x.to_f64_px(), @@ -3090,52 +3082,47 @@ impl ElementMethods for Element { } // https://drafts.csswg.org/cssom-view/#dom-element-scroll - fn Scroll(&self, options: &ScrollToOptions, can_gc: CanGc) { + fn Scroll(&self, options: &ScrollToOptions) { // Step 1 - let left = options.left.unwrap_or(self.ScrollLeft(can_gc)); - let top = options.top.unwrap_or(self.ScrollTop(can_gc)); - self.scroll(left, top, options.parent.behavior, can_gc); + let left = options.left.unwrap_or(self.ScrollLeft()); + let top = options.top.unwrap_or(self.ScrollTop()); + self.scroll(left, top, options.parent.behavior); } // https://drafts.csswg.org/cssom-view/#dom-element-scroll - fn Scroll_(&self, x: f64, y: f64, can_gc: CanGc) { - self.scroll(x, y, ScrollBehavior::Auto, can_gc); + fn Scroll_(&self, x: f64, y: f64) { + self.scroll(x, y, ScrollBehavior::Auto); } // https://drafts.csswg.org/cssom-view/#dom-element-scrollto - fn ScrollTo(&self, options: &ScrollToOptions, can_gc: CanGc) { - self.Scroll(options, can_gc); + fn ScrollTo(&self, options: &ScrollToOptions) { + self.Scroll(options); } // https://drafts.csswg.org/cssom-view/#dom-element-scrollto - fn ScrollTo_(&self, x: f64, y: f64, can_gc: CanGc) { - self.Scroll_(x, y, can_gc); + fn ScrollTo_(&self, x: f64, y: f64) { + self.Scroll_(x, y); } // https://drafts.csswg.org/cssom-view/#dom-element-scrollby - fn ScrollBy(&self, options: &ScrollToOptions, can_gc: CanGc) { + fn ScrollBy(&self, options: &ScrollToOptions) { // Step 2 let delta_left = options.left.unwrap_or(0.0f64); let delta_top = options.top.unwrap_or(0.0f64); - let left = self.ScrollLeft(can_gc); - let top = self.ScrollTop(can_gc); - self.scroll( - left + delta_left, - top + delta_top, - options.parent.behavior, - can_gc, - ); + let left = self.ScrollLeft(); + let top = self.ScrollTop(); + self.scroll(left + delta_left, top + delta_top, options.parent.behavior); } // https://drafts.csswg.org/cssom-view/#dom-element-scrollby - fn ScrollBy_(&self, x: f64, y: f64, can_gc: CanGc) { - let left = self.ScrollLeft(can_gc); - let top = self.ScrollTop(can_gc); - self.scroll(left + x, top + y, ScrollBehavior::Auto, can_gc); + fn ScrollBy_(&self, x: f64, y: f64) { + let left = self.ScrollLeft(); + let top = self.ScrollTop(); + self.scroll(left + x, top + y, ScrollBehavior::Auto); } // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop - fn ScrollTop(&self, can_gc: CanGc) -> f64 { + fn ScrollTop(&self) -> f64 { let node = self.upcast::(); // Step 1 @@ -3165,24 +3152,24 @@ impl ElementMethods for Element { // Step 7 if doc.GetBody().as_deref() == self.downcast::() && doc.quirks_mode() == QuirksMode::Quirks && - !self.is_potentially_scrollable_body(can_gc) + !self.is_potentially_scrollable_body() { return win.ScrollY() as f64; } // Step 8 - if !self.has_css_layout_box(can_gc) { + if !self.has_css_layout_box() { return 0.0; } // Step 9 - let point = win.scroll_offset_query(node, can_gc); + let point = win.scroll_offset_query(node); point.y.abs() as f64 } // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop // TODO(stevennovaryo): Need to update the scroll API to follow the spec since it is quite outdated. - fn SetScrollTop(&self, y_: f64, can_gc: CanGc) { + fn SetScrollTop(&self, y_: f64) { let behavior = ScrollBehavior::Auto; // Step 1, 2 @@ -3207,7 +3194,7 @@ impl ElementMethods for Element { // Step 7 if *self.root_element() == *self { if doc.quirks_mode() != QuirksMode::Quirks { - win.scroll(win.ScrollX() as f64, y, behavior, can_gc); + win.scroll(win.ScrollX() as f64, y, behavior); } return; @@ -3216,26 +3203,23 @@ impl ElementMethods for Element { // Step 9 if doc.GetBody().as_deref() == self.downcast::() && doc.quirks_mode() == QuirksMode::Quirks && - !self.is_potentially_scrollable_body(can_gc) + !self.is_potentially_scrollable_body() { - win.scroll(win.ScrollX() as f64, y, behavior, can_gc); + win.scroll(win.ScrollX() as f64, y, behavior); return; } // Step 10 - if !self.has_css_layout_box(can_gc) || - !self.has_scrolling_box(can_gc) || - !self.has_overflow(can_gc) - { + if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() { return; } // Step 11 - win.scroll_an_element(self, self.ScrollLeft(can_gc), y, behavior, can_gc); + win.scroll_an_element(self, self.ScrollLeft(), y, behavior); } // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop - fn ScrollLeft(&self, can_gc: CanGc) -> f64 { + fn ScrollLeft(&self) -> f64 { let node = self.upcast::(); // Step 1 @@ -3265,23 +3249,23 @@ impl ElementMethods for Element { // Step 7 if doc.GetBody().as_deref() == self.downcast::() && doc.quirks_mode() == QuirksMode::Quirks && - !self.is_potentially_scrollable_body(can_gc) + !self.is_potentially_scrollable_body() { return win.ScrollX() as f64; } // Step 8 - if !self.has_css_layout_box(can_gc) { + if !self.has_css_layout_box() { return 0.0; } // Step 9 - let point = win.scroll_offset_query(node, can_gc); + let point = win.scroll_offset_query(node); point.x.abs() as f64 } // https://drafts.csswg.org/cssom-view/#dom-element-scrollleft - fn SetScrollLeft(&self, x_: f64, can_gc: CanGc) { + fn SetScrollLeft(&self, x_: f64) { let behavior = ScrollBehavior::Auto; // Step 1, 2 @@ -3309,59 +3293,56 @@ impl ElementMethods for Element { return; } - win.scroll(x, win.ScrollY() as f64, behavior, can_gc); + win.scroll(x, win.ScrollY() as f64, behavior); return; } // Step 9 if doc.GetBody().as_deref() == self.downcast::() && doc.quirks_mode() == QuirksMode::Quirks && - !self.is_potentially_scrollable_body(can_gc) + !self.is_potentially_scrollable_body() { - win.scroll(x, win.ScrollY() as f64, behavior, can_gc); + win.scroll(x, win.ScrollY() as f64, behavior); return; } // Step 10 - if !self.has_css_layout_box(can_gc) || - !self.has_scrolling_box(can_gc) || - !self.has_overflow(can_gc) - { + if !self.has_css_layout_box() || !self.has_scrolling_box() || !self.has_overflow() { return; } // Step 11 - win.scroll_an_element(self, x, self.ScrollTop(can_gc), behavior, can_gc); + win.scroll_an_element(self, x, self.ScrollTop(), behavior); } // https://drafts.csswg.org/cssom-view/#dom-element-scrollwidth - fn ScrollWidth(&self, can_gc: CanGc) -> i32 { - self.upcast::().scroll_area(can_gc).size.width + fn ScrollWidth(&self) -> i32 { + self.upcast::().scroll_area().size.width } // https://drafts.csswg.org/cssom-view/#dom-element-scrollheight - fn ScrollHeight(&self, can_gc: CanGc) -> i32 { - self.upcast::().scroll_area(can_gc).size.height + fn ScrollHeight(&self) -> i32 { + self.upcast::().scroll_area().size.height } // https://drafts.csswg.org/cssom-view/#dom-element-clienttop - fn ClientTop(&self, can_gc: CanGc) -> i32 { - self.client_rect(can_gc).origin.y + fn ClientTop(&self) -> i32 { + self.client_rect().origin.y } // https://drafts.csswg.org/cssom-view/#dom-element-clientleft - fn ClientLeft(&self, can_gc: CanGc) -> i32 { - self.client_rect(can_gc).origin.x + fn ClientLeft(&self) -> i32 { + self.client_rect().origin.x } // https://drafts.csswg.org/cssom-view/#dom-element-clientwidth - fn ClientWidth(&self, can_gc: CanGc) -> i32 { - self.client_rect(can_gc).size.width + fn ClientWidth(&self) -> i32 { + self.client_rect().size.width } // https://drafts.csswg.org/cssom-view/#dom-element-clientheight - fn ClientHeight(&self, can_gc: CanGc) -> i32 { - self.client_rect(can_gc).size.height + fn ClientHeight(&self) -> i32 { + self.client_rect().size.height } /// @@ -4777,7 +4758,7 @@ impl SelectorsElement for SelectorWrapper<'_> { } impl Element { - fn client_rect(&self, can_gc: CanGc) -> Rect { + fn client_rect(&self) -> Rect { let doc = self.node.owner_doc(); if let Some(rect) = self @@ -4791,7 +4772,7 @@ impl Element { } } - let mut rect = self.upcast::().client_rect(can_gc); + let mut rect = self.upcast::().client_rect(); let in_quirks_mode = doc.quirks_mode() == QuirksMode::Quirks; if (in_quirks_mode && doc.GetBody().as_deref() == self.downcast::()) || diff --git a/components/script/dom/fontfaceset.rs b/components/script/dom/fontfaceset.rs index 084f9b4d5a0..1d0dde66dea 100644 --- a/components/script/dom/fontfaceset.rs +++ b/components/script/dom/fontfaceset.rs @@ -69,10 +69,17 @@ impl FontFaceSet { } } - pub(crate) fn fulfill_ready_promise_if_needed(&self, can_gc: CanGc) { - if !self.promise.is_fulfilled() { - self.promise.resolve_native(self, can_gc); + /// Fulfill the font ready promise, returning true if it was not already fulfilled beforehand. + pub(crate) fn fulfill_ready_promise_if_needed(&self, can_gc: CanGc) -> bool { + if self.promise.is_fulfilled() { + return false; } + self.promise.resolve_native(self, can_gc); + true + } + + pub(crate) fn waiting_to_fullfill_promise(&self) -> bool { + !self.promise.is_fulfilled() } } diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index 4b51f3e62d2..149c9f66834 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -101,7 +101,7 @@ impl History { // Step 8 if let Some(fragment) = url.fragment() { - document.check_and_scroll_fragment(fragment, can_gc); + document.check_and_scroll_fragment(fragment); } // Step 11 diff --git a/components/script/dom/htmlanchorelement.rs b/components/script/dom/htmlanchorelement.rs index 5a59c9254a0..514126b214b 100644 --- a/components/script/dom/htmlanchorelement.rs +++ b/components/script/dom/htmlanchorelement.rs @@ -319,7 +319,7 @@ impl Activatable for HTMLAnchorElement { } //https://html.spec.whatwg.org/multipage/#the-a-element:activation-behaviour - fn activation_behavior(&self, event: &Event, target: &EventTarget, can_gc: CanGc) { + fn activation_behavior(&self, event: &Event, target: &EventTarget, _: CanGc) { let element = self.as_element(); let mouse_event = event.downcast::().unwrap(); let mut ismap_suffix = None; @@ -329,7 +329,7 @@ impl Activatable for HTMLAnchorElement { if let Some(element) = target.downcast::() { if target.is::() && element.has_attribute(&local_name!("ismap")) { let target_node = element.upcast::(); - let rect = target_node.bounding_content_box_or_zero(can_gc); + let rect = target_node.bounding_content_box_or_zero(); ismap_suffix = Some(format!( "?{},{}", mouse_event.ClientX().to_f32().unwrap() - rect.origin.x.to_f32_px(), diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index b5edc6bd7c9..8ef1fc8a767 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -116,18 +116,18 @@ impl HTMLElement { /// `.outerText` in JavaScript.` /// /// - pub(crate) fn get_inner_outer_text(&self, can_gc: CanGc) -> DOMString { + pub(crate) fn get_inner_outer_text(&self) -> DOMString { let node = self.upcast::(); let window = node.owner_window(); let element = self.as_element(); // Step 1. - let element_not_rendered = !node.is_connected() || !element.has_css_layout_box(can_gc); + let element_not_rendered = !node.is_connected() || !element.has_css_layout_box(); if element_not_rendered { return node.GetTextContent().unwrap(); } - window.layout_reflow(QueryMsg::ElementInnerOuterTextQuery, can_gc); + window.layout_reflow(QueryMsg::ElementInnerOuterTextQuery); let text = window .layout() .query_element_inner_outer_text(node.to_trusted_node_address()); @@ -438,65 +438,65 @@ impl HTMLElementMethods for HTMLElement { } /// - fn GetOffsetParent(&self, can_gc: CanGc) -> Option> { + fn GetOffsetParent(&self) -> Option> { if self.is_body_element() || self.is::() { return None; } let node = self.upcast::(); let window = self.owner_window(); - let (element, _) = window.offset_parent_query(node, can_gc); + let (element, _) = window.offset_parent_query(node); element } // https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsettop - fn OffsetTop(&self, can_gc: CanGc) -> i32 { + fn OffsetTop(&self) -> i32 { if self.is_body_element() { return 0; } let node = self.upcast::(); let window = self.owner_window(); - let (_, rect) = window.offset_parent_query(node, can_gc); + let (_, rect) = window.offset_parent_query(node); rect.origin.y.to_nearest_px() } // https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetleft - fn OffsetLeft(&self, can_gc: CanGc) -> i32 { + fn OffsetLeft(&self) -> i32 { if self.is_body_element() { return 0; } let node = self.upcast::(); let window = self.owner_window(); - let (_, rect) = window.offset_parent_query(node, can_gc); + let (_, rect) = window.offset_parent_query(node); rect.origin.x.to_nearest_px() } // https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetwidth - fn OffsetWidth(&self, can_gc: CanGc) -> i32 { + fn OffsetWidth(&self) -> i32 { let node = self.upcast::(); let window = self.owner_window(); - let (_, rect) = window.offset_parent_query(node, can_gc); + let (_, rect) = window.offset_parent_query(node); rect.size.width.to_nearest_px() } // https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetheight - fn OffsetHeight(&self, can_gc: CanGc) -> i32 { + fn OffsetHeight(&self) -> i32 { let node = self.upcast::(); let window = self.owner_window(); - let (_, rect) = window.offset_parent_query(node, can_gc); + let (_, rect) = window.offset_parent_query(node); rect.size.height.to_nearest_px() } /// - fn InnerText(&self, can_gc: CanGc) -> DOMString { - self.get_inner_outer_text(can_gc) + fn InnerText(&self) -> DOMString { + self.get_inner_outer_text() } /// @@ -505,8 +505,8 @@ impl HTMLElementMethods for HTMLElement { } /// - fn GetOuterText(&self, can_gc: CanGc) -> Fallible { - Ok(self.get_inner_outer_text(can_gc)) + fn GetOuterText(&self) -> Fallible { + Ok(self.get_inner_outer_text()) } /// diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index ee6cd312e2e..0137f3c8ef1 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -210,7 +210,7 @@ impl HTMLIFrameElement { }; let viewport_details = window - .get_iframe_viewport_details_if_known(browsing_context_id, can_gc) + .get_iframe_viewport_details_if_known(browsing_context_id) .unwrap_or_else(|| ViewportDetails { hidpi_scale_factor: window.device_pixel_ratio(), ..Default::default() diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 3a38c851bcf..ac17f6094bd 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -1655,9 +1655,9 @@ impl HTMLImageElementMethods for HTMLImageElement { make_bool_setter!(SetIsMap, "ismap"); // https://html.spec.whatwg.org/multipage/#dom-img-width - fn Width(&self, can_gc: CanGc) -> u32 { + fn Width(&self) -> u32 { let node = self.upcast::(); - match node.bounding_content_box(can_gc) { + match node.bounding_content_box() { Some(rect) => rect.size.width.to_px() as u32, None => self.NaturalWidth(), } @@ -1669,9 +1669,9 @@ impl HTMLImageElementMethods for HTMLImageElement { } // https://html.spec.whatwg.org/multipage/#dom-img-height - fn Height(&self, can_gc: CanGc) -> u32 { + fn Height(&self) -> u32 { let node = self.upcast::(); - match node.bounding_content_box(can_gc) { + match node.bounding_content_box() { Some(rect) => rect.size.height.to_px() as u32, None => self.NaturalHeight(), } diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 102d14653b7..a9966a425a6 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -2736,7 +2736,7 @@ impl HTMLInputElement { let (ipc_sender, ipc_receiver) = ipc::channel::>().expect("Failed to create IPC channel!"); let document = self.owner_document(); - let rect = self.upcast::().bounding_content_box_or_zero(can_gc); + let rect = self.upcast::().bounding_content_box_or_zero(); let rect = Rect::new( Point2D::new(rect.origin.x.to_px(), rect.origin.y.to_px()), Size2D::new(rect.size.width.to_px(), rect.size.height.to_px()), @@ -3074,11 +3074,8 @@ impl VirtualMethods for HTMLInputElement { // now. if let Some(point_in_target) = mouse_event.point_in_target() { let window = self.owner_window(); - let index = window.text_index_query( - self.upcast::(), - point_in_target.to_untyped(), - can_gc, - ); + let index = window + .text_index_query(self.upcast::(), point_in_target.to_untyped()); // Position the caret at the click position or at the end of the current // value. let edit_point_index = match index { diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 7a028504109..0ec0a30a9e4 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -1551,9 +1551,9 @@ impl HTMLScriptElementMethods for HTMLScriptElement { make_setter!(SetReferrerPolicy, "referrerpolicy"); /// - fn InnerText(&self, can_gc: CanGc) -> TrustedScriptOrString { + fn InnerText(&self) -> TrustedScriptOrString { // Step 1: Return the result of running get the text steps with this. - TrustedScriptOrString::String(self.upcast::().get_inner_outer_text(can_gc)) + TrustedScriptOrString::String(self.upcast::().get_inner_outer_text()) } /// diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index f7730913783..e4ca7a247be 100644 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -339,7 +339,7 @@ impl HTMLSelectElement { .or_else(|| self.list_of_options().next()) } - pub(crate) fn show_menu(&self, can_gc: CanGc) -> Option { + pub(crate) fn show_menu(&self) -> Option { let (ipc_sender, ipc_receiver) = ipc::channel().expect("Failed to create IPC channel!"); // Collect list of optgroups and options @@ -377,7 +377,7 @@ impl HTMLSelectElement { }) .collect(); - let rect = self.upcast::().bounding_content_box_or_zero(can_gc); + let rect = self.upcast::().bounding_content_box_or_zero(); let rect = Rect::new( Point2D::new(rect.origin.x.to_px(), rect.origin.y.to_px()), Size2D::new(rect.size.width.to_px(), rect.size.height.to_px()), @@ -782,7 +782,7 @@ impl Activatable for HTMLSelectElement { } fn activation_behavior(&self, _event: &Event, _target: &EventTarget, can_gc: CanGc) { - let Some(selected_value) = self.show_menu(can_gc) else { + let Some(selected_value) = self.show_menu() else { // The user did not select a value return; }; diff --git a/components/script/dom/mouseevent.rs b/components/script/dom/mouseevent.rs index bb02f9451e3..c0938ed39f8 100644 --- a/components/script/dom/mouseevent.rs +++ b/components/script/dom/mouseevent.rs @@ -278,7 +278,7 @@ impl MouseEventMethods for MouseEvent { ) -> Fallible> { let bubbles = EventBubbles::from(init.parent.parent.parent.bubbles); let cancelable = EventCancelable::from(init.parent.parent.parent.cancelable); - let scroll_offset = window.scroll_offset(can_gc); + let scroll_offset = window.scroll_offset(); let page_point = Point2D::new( scroll_offset.x as i32 + init.clientX, scroll_offset.y as i32 + init.clientY, @@ -370,7 +370,7 @@ impl MouseEventMethods for MouseEvent { } /// - fn OffsetX(&self, can_gc: CanGc) -> i32 { + fn OffsetX(&self) -> i32 { // > The offsetX attribute must follow these steps: // > 1. If the event’s dispatch flag is set, return the x-coordinate of the position // > where the event occurred relative to the origin of the padding edge of the @@ -384,7 +384,7 @@ impl MouseEventMethods for MouseEvent { let Some(node) = target.downcast::() else { return 0; }; - return self.ClientX() - node.client_rect(can_gc).origin.x; + return self.ClientX() - node.client_rect().origin.x; } // > 2. Return the value of the event’s pageX attribute. @@ -392,7 +392,7 @@ impl MouseEventMethods for MouseEvent { } /// - fn OffsetY(&self, can_gc: CanGc) -> i32 { + fn OffsetY(&self) -> i32 { // > The offsetY attribute must follow these steps: // > 1. If the event’s dispatch flag is set, return the y-coordinate of the // > position where the event occurred relative to the origin of the padding edge of @@ -406,7 +406,7 @@ impl MouseEventMethods for MouseEvent { let Some(node) = target.downcast::() else { return 0; }; - return self.ClientY() - node.client_rect(can_gc).origin.y; + return self.ClientY() - node.client_rect().origin.y; } // 2. Return the value of the event’s pageY attribute. @@ -479,7 +479,6 @@ impl MouseEventMethods for MouseEvent { meta_key_arg: bool, button_arg: i16, related_target_arg: Option<&EventTarget>, - can_gc: CanGc, ) { if self.upcast::().dispatching() { return; @@ -498,7 +497,7 @@ impl MouseEventMethods for MouseEvent { .set(Point2D::new(client_x_arg, client_y_arg)); let global = self.global(); - let scroll_offset = global.as_window().scroll_offset(can_gc); + let scroll_offset = global.as_window().scroll_offset(); self.page_point.set(Point2D::new( scroll_offset.x as i32 + client_x_arg, scroll_offset.y as i32 + client_y_arg, diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index bc1589dee1c..aae644cc010 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -944,29 +944,29 @@ impl Node { /// Returns the rendered bounding content box if the element is rendered, /// and none otherwise. - pub(crate) fn bounding_content_box(&self, can_gc: CanGc) -> Option> { - self.owner_window().content_box_query(self, can_gc) + pub(crate) fn bounding_content_box(&self) -> Option> { + self.owner_window().content_box_query(self) } - pub(crate) fn bounding_content_box_or_zero(&self, can_gc: CanGc) -> Rect { - self.bounding_content_box(can_gc).unwrap_or_else(Rect::zero) + pub(crate) fn bounding_content_box_or_zero(&self) -> Rect { + self.bounding_content_box().unwrap_or_else(Rect::zero) } pub(crate) fn bounding_content_box_no_reflow(&self) -> Option> { self.owner_window().content_box_query_unchecked(self) } - pub(crate) fn content_boxes(&self, can_gc: CanGc) -> Vec> { - self.owner_window().content_boxes_query(self, can_gc) + pub(crate) fn content_boxes(&self) -> Vec> { + self.owner_window().content_boxes_query(self) } - pub(crate) fn client_rect(&self, can_gc: CanGc) -> Rect { - self.owner_window().client_rect_query(self, can_gc) + pub(crate) fn client_rect(&self) -> Rect { + self.owner_window().client_rect_query(self) } /// /// - pub(crate) fn scroll_area(&self, can_gc: CanGc) -> Rect { + pub(crate) fn scroll_area(&self) -> Rect { // "1. Let document be the element’s node document."" let document = self.owner_doc(); @@ -992,7 +992,7 @@ impl Node { // element is not potentially scrollable, return max(viewport scrolling area // width, viewport width)." if (is_root && !in_quirks_mode) || (is_body_element && in_quirks_mode) { - let viewport_scrolling_area = window.scrolling_area_query(None, can_gc); + let viewport_scrolling_area = window.scrolling_area_query(None); return Rect::new( viewport_scrolling_area.origin, viewport_scrolling_area.size.max(viewport), @@ -1002,7 +1002,7 @@ impl Node { // "6. If the element does not have any associated box return zero and terminate // these steps." // "7. Return the width of the element’s scrolling area." - window.scrolling_area_query(Some(self), can_gc) + window.scrolling_area_query(Some(self)) } /// @@ -1461,9 +1461,8 @@ impl Node { }) } - pub(crate) fn style(&self, can_gc: CanGc) -> Option> { - self.owner_window() - .layout_reflow(QueryMsg::StyleQuery, can_gc); + pub(crate) fn style(&self) -> Option> { + self.owner_window().layout_reflow(QueryMsg::StyleQuery); self.style_data .borrow() .as_ref() diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs index 242e8312871..09c2f092cb2 100644 --- a/components/script/dom/offscreencanvasrenderingcontext2d.rs +++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs @@ -161,8 +161,8 @@ impl OffscreenCanvasRenderingContext2DMethods } // https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor - fn SetShadowColor(&self, value: DOMString, can_gc: CanGc) { - self.context.SetShadowColor(value, can_gc) + fn SetShadowColor(&self, value: DOMString) { + self.context.SetShadowColor(value) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle @@ -171,8 +171,8 @@ impl OffscreenCanvasRenderingContext2DMethods } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle - fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern, can_gc: CanGc) { - self.context.SetStrokeStyle(value, can_gc) + fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) { + self.context.SetStrokeStyle(value) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle @@ -181,8 +181,8 @@ impl OffscreenCanvasRenderingContext2DMethods } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle - fn SetFillStyle(&self, value: StringOrCanvasGradientOrCanvasPattern, can_gc: CanGc) { - self.context.SetFillStyle(value, can_gc) + fn SetFillStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) { + self.context.SetFillStyle(value) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient @@ -269,8 +269,8 @@ impl OffscreenCanvasRenderingContext2DMethods } // https://html.spec.whatwg.org/multipage/#dom-context-2d-filltext - fn FillText(&self, text: DOMString, x: f64, y: f64, max_width: Option, can_gc: CanGc) { - self.context.FillText(text, x, y, max_width, can_gc) + fn FillText(&self, text: DOMString, x: f64, y: f64, max_width: Option) { + self.context.FillText(text, x, y, max_width) } // https://html.spec.whatwg.org/multipage/#textmetrics @@ -284,8 +284,8 @@ impl OffscreenCanvasRenderingContext2DMethods } // https://html.spec.whatwg.org/multipage/#dom-context-2d-font - fn SetFont(&self, value: DOMString, can_gc: CanGc) { - self.context.SetFont(value, can_gc) + fn SetFont(&self, value: DOMString) { + self.context.SetFont(value) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-textalign diff --git a/components/script/dom/paintrenderingcontext2d.rs b/components/script/dom/paintrenderingcontext2d.rs index 3d5cc3b1f77..47bb205866f 100644 --- a/components/script/dom/paintrenderingcontext2d.rs +++ b/components/script/dom/paintrenderingcontext2d.rs @@ -343,8 +343,8 @@ impl PaintRenderingContext2DMethods for PaintRenderingCont } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle - fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern, can_gc: CanGc) { - self.canvas_state.set_stroke_style(None, value, can_gc) + fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) { + self.canvas_state.set_stroke_style(None, value) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle @@ -353,8 +353,8 @@ impl PaintRenderingContext2DMethods for PaintRenderingCont } // https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle - fn SetFillStyle(&self, value: StringOrCanvasGradientOrCanvasPattern, can_gc: CanGc) { - self.canvas_state.set_fill_style(None, value, can_gc) + fn SetFillStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) { + self.canvas_state.set_fill_style(None, value) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient @@ -497,7 +497,7 @@ impl PaintRenderingContext2DMethods for PaintRenderingCont } // https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor - fn SetShadowColor(&self, value: DOMString, can_gc: CanGc) { - self.canvas_state.set_shadow_color(None, value, can_gc) + fn SetShadowColor(&self, value: DOMString) { + self.canvas_state.set_shadow_color(None, value) } } diff --git a/components/script/dom/pointerevent.rs b/components/script/dom/pointerevent.rs index 88238f64dd2..664737af6c2 100644 --- a/components/script/dom/pointerevent.rs +++ b/components/script/dom/pointerevent.rs @@ -233,7 +233,7 @@ impl PointerEventMethods for PointerEvent { ) -> DomRoot { let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles); let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable); - let scroll_offset = window.scroll_offset(can_gc); + let scroll_offset = window.scroll_offset(); let page_point = Point2D::new( scroll_offset.x as i32 + init.parent.clientX, scroll_offset.y as i32 + init.parent.clientY, diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 59b4ef93035..3472c1897b8 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -329,7 +329,6 @@ impl Range { fn client_rects( &self, - can_gc: CanGc, ) -> impl Iterator> { // FIXME: For text nodes that are only partially selected, this should return the client // rect of the selected part, not the whole text node. @@ -341,7 +340,7 @@ impl Range { .following_nodes(document.upcast::()) .take_while(move |node| node != &end) .chain(iter::once(end_clone)) - .flat_map(move |node| node.content_boxes(can_gc)) + .flat_map(move |node| node.content_boxes()) } /// @@ -1153,7 +1152,7 @@ impl RangeMethods for Range { let window = start.owner_window(); let client_rects = self - .client_rects(can_gc) + .client_rects() .map(|rect| { DOMRect::new( window.upcast(), @@ -1174,7 +1173,7 @@ impl RangeMethods for Range { let window = self.start_container().owner_window(); // Step 1. Let list be the result of invoking getClientRects() on the same range this method was invoked on. - let list = self.client_rects(can_gc); + let list = self.client_rects(); // Step 2. If list is empty return a DOMRect object whose x, y, width and height members are zero. // Step 3. If all rectangles in list have zero width or height, return the first rectangle in list. diff --git a/components/script/dom/resizeobserver.rs b/components/script/dom/resizeobserver.rs index b685151c153..c56897009d9 100644 --- a/components/script/dom/resizeobserver.rs +++ b/components/script/dom/resizeobserver.rs @@ -81,7 +81,6 @@ impl ResizeObserver { &self, depth: &ResizeObservationDepth, has_active: &mut bool, - can_gc: CanGc, ) { // Step 2.1 Clear observer’s [[activeTargets]], and [[skippedTargets]]. // NOTE: This happens as part of Step 2.2 @@ -91,7 +90,7 @@ impl ResizeObserver { observation.state = Default::default(); // Step 2.2.1 If observation.isActive() is true - if let Some(size) = observation.is_active(target, can_gc) { + if let Some(size) = observation.is_active(target) { // Step 2.2.1.1 Let targetDepth be result of calculate depth for node for observation.target. let target_depth = calculate_depth_for_node(target); @@ -284,9 +283,9 @@ impl ResizeObservation { /// /// Returning an optional calculated size, instead of a boolean, /// to avoid recalculating the size in the subsequent broadcast. - fn is_active(&self, target: &Element, can_gc: CanGc) -> Option> { + fn is_active(&self, target: &Element) -> Option> { let last_reported_size = self.last_reported_sizes[0]; - let box_size = calculate_box_size(target, &self.observed_box, can_gc); + let box_size = calculate_box_size(target, &self.observed_box); let is_active = box_size.width().to_f64_px() != last_reported_size.inline_size() || box_size.height().to_f64_px() != last_reported_size.block_size(); if is_active { Some(box_size) } else { None } @@ -301,18 +300,14 @@ fn calculate_depth_for_node(target: &Element) -> ResizeObservationDepth { } /// -fn calculate_box_size( - target: &Element, - observed_box: &ResizeObserverBoxOptions, - can_gc: CanGc, -) -> Rect { +fn calculate_box_size(target: &Element, observed_box: &ResizeObserverBoxOptions) -> Rect { match observed_box { ResizeObserverBoxOptions::Content_box => { // Note: only taking first fragment, // but the spec will expand to cover all fragments. target .upcast::() - .content_boxes(can_gc) + .content_boxes() .pop() .unwrap_or_else(Rect::zero) }, diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index aa88c142c08..79f58e6ad8f 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -659,9 +659,7 @@ impl ServoParser { assert!(!self.suspended.get()); assert!(!self.aborted.get()); - self.document - .window() - .reflow_if_reflow_timer_expired(can_gc); + self.document.window().reflow_if_reflow_timer_expired(); let script = match feed(&self.tokenizer) { TokenizerResult::Done => return, TokenizerResult::Script(script) => script, diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 7ab11d9e1d1..4832b26e571 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -370,12 +370,7 @@ impl ShadowRootMethods for ShadowRoot { } // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint - fn ElementFromPoint( - &self, - x: Finite, - y: Finite, - can_gc: CanGc, - ) -> Option> { + fn ElementFromPoint(&self, x: Finite, y: Finite) -> Option> { // Return the result of running the retargeting algorithm with context object // and the original result as input. match self.document_or_shadow_root.element_from_point( @@ -383,7 +378,6 @@ impl ShadowRootMethods for ShadowRoot { y, None, self.document.has_browsing_context(), - can_gc, ) { Some(e) => { let retargeted_node = self @@ -396,18 +390,13 @@ impl ShadowRootMethods for ShadowRoot { } // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint - fn ElementsFromPoint( - &self, - x: Finite, - y: Finite, - can_gc: CanGc, - ) -> Vec> { + fn ElementsFromPoint(&self, x: Finite, y: Finite) -> Vec> { // Return the result of running the retargeting algorithm with context object // and the original result as input let mut elements = Vec::new(); for e in self .document_or_shadow_root - .elements_from_point(x, y, None, self.document.has_browsing_context(), can_gc) + .elements_from_point(x, y, None, self.document.has_browsing_context()) .iter() { let retargeted_node = self diff --git a/components/script/dom/wheelevent.rs b/components/script/dom/wheelevent.rs index 05d8cd2c03a..2c9bdb7a42d 100644 --- a/components/script/dom/wheelevent.rs +++ b/components/script/dom/wheelevent.rs @@ -204,7 +204,7 @@ impl WheelEventMethods for WheelEvent { ) -> Fallible> { let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles); let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable); - let scroll_offset = window.scroll_offset(can_gc); + let scroll_offset = window.scroll_offset(); let page_point = Point2D::::new( scroll_offset.x as i32 + init.parent.clientX, @@ -269,7 +269,6 @@ impl WheelEventMethods for WheelEvent { delta_y_arg: Finite, delta_z_arg: Finite, delta_mode_arg: u32, - can_gc: CanGc, ) { if self.upcast::().dispatching() { return; @@ -291,7 +290,6 @@ impl WheelEventMethods for WheelEvent { self.mouseevent.MetaKey(), self.mouseevent.Button(), self.mouseevent.GetRelatedTarget().as_deref(), - can_gc, ); self.delta_x.set(delta_x_arg); self.delta_y.set(delta_y_arg); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 17bf449d0ef..0f52f3fd22e 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1634,7 +1634,7 @@ impl WindowMethods for Window { /// fn ScrollX(&self) -> i32 { - self.scroll_offset(CanGc::note()).x as i32 + self.scroll_offset().x as i32 } // https://drafts.csswg.org/cssom-view/#dom-window-pagexoffset @@ -1644,7 +1644,7 @@ impl WindowMethods for Window { /// fn ScrollY(&self) -> i32 { - self.scroll_offset(CanGc::note()).y as i32 + self.scroll_offset().y as i32 } // https://drafts.csswg.org/cssom-view/#dom-window-pageyoffset @@ -1653,47 +1653,47 @@ impl WindowMethods for Window { } // https://drafts.csswg.org/cssom-view/#dom-window-scroll - fn Scroll(&self, options: &ScrollToOptions, can_gc: CanGc) { + fn Scroll(&self, options: &ScrollToOptions) { // Step 1 let left = options.left.unwrap_or(0.0f64); let top = options.top.unwrap_or(0.0f64); - self.scroll(left, top, options.parent.behavior, can_gc); + self.scroll(left, top, options.parent.behavior); } // https://drafts.csswg.org/cssom-view/#dom-window-scroll - fn Scroll_(&self, x: f64, y: f64, can_gc: CanGc) { - self.scroll(x, y, ScrollBehavior::Auto, can_gc); + fn Scroll_(&self, x: f64, y: f64) { + self.scroll(x, y, ScrollBehavior::Auto); } // https://drafts.csswg.org/cssom-view/#dom-window-scrollto fn ScrollTo(&self, options: &ScrollToOptions) { - self.Scroll(options, CanGc::note()); + self.Scroll(options); } // https://drafts.csswg.org/cssom-view/#dom-window-scrollto fn ScrollTo_(&self, x: f64, y: f64) { - self.scroll(x, y, ScrollBehavior::Auto, CanGc::note()); + self.scroll(x, y, ScrollBehavior::Auto); } // https://drafts.csswg.org/cssom-view/#dom-window-scrollby - fn ScrollBy(&self, options: &ScrollToOptions, can_gc: CanGc) { + fn ScrollBy(&self, options: &ScrollToOptions) { // Step 1 let x = options.left.unwrap_or(0.0f64); let y = options.top.unwrap_or(0.0f64); - self.ScrollBy_(x, y, can_gc); - self.scroll(x, y, options.parent.behavior, can_gc); + self.ScrollBy_(x, y); + self.scroll(x, y, options.parent.behavior); } // https://drafts.csswg.org/cssom-view/#dom-window-scrollby - fn ScrollBy_(&self, x: f64, y: f64, can_gc: CanGc) { - let scroll_offset = self.scroll_offset(can_gc); + fn ScrollBy_(&self, x: f64, y: f64) { + let scroll_offset = self.scroll_offset(); // Step 3 let left = x + scroll_offset.x as f64; // Step 4 let top = y + scroll_offset.y as f64; // Step 5 - self.scroll(left, top, ScrollBehavior::Auto, can_gc); + self.scroll(left, top, ScrollBehavior::Auto); } // https://drafts.csswg.org/cssom-view/#dom-window-resizeto @@ -2012,11 +2012,8 @@ impl WindowMethods for Window { } impl Window { - pub(crate) fn scroll_offset(&self, can_gc: CanGc) -> Vector2D { - self.scroll_offset_query_with_external_scroll_id( - self.pipeline_id().root_scroll_id(), - can_gc, - ) + pub(crate) fn scroll_offset(&self) -> Vector2D { + self.scroll_offset_query_with_external_scroll_id(self.pipeline_id().root_scroll_id()) } // https://heycam.github.io/webidl/#named-properties-object @@ -2114,7 +2111,7 @@ impl Window { } /// - pub(crate) fn scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior, can_gc: CanGc) { + pub(crate) fn scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior) { // Step 3 let xfinite = if x_.is_finite() { x_ } else { 0.0f64 }; let yfinite = if y_.is_finite() { y_ } else { 0.0f64 }; @@ -2127,7 +2124,7 @@ impl Window { // Step 7 & 8 // TODO: Consider `block-end` and `inline-end` overflow direction. - let scrolling_area = self.scrolling_area_query(None, can_gc); + let scrolling_area = self.scrolling_area_query(None); let x = xfinite .min(scrolling_area.width() as f64 - viewport.width as f64) .max(0.0f64); @@ -2137,7 +2134,7 @@ impl Window { // Step 10 //TODO handling ongoing smooth scrolling - let scroll_offset = self.scroll_offset(can_gc); + let scroll_offset = self.scroll_offset(); if x == scroll_offset.x as f64 && y == scroll_offset.y as f64 { return; } @@ -2153,7 +2150,6 @@ impl Window { self.pipeline_id().root_scroll_id(), behavior, None, - can_gc, ); } @@ -2165,7 +2161,6 @@ impl Window { scroll_id: ExternalScrollId, _behavior: ScrollBehavior, element: Option<&Element>, - can_gc: CanGc, ) { // TODO Step 1 // TODO(mrobinson, #18709): Add smooth scrolling support to WebRender so that we can @@ -2173,10 +2168,7 @@ impl Window { let WindowReflowResult { update_scroll_reflow_target_scrolled, .. - } = self.reflow( - ReflowGoal::UpdateScrollNode(scroll_id, Vector2D::new(x, y)), - can_gc, - ); + } = self.reflow(ReflowGoal::UpdateScrollNode(scroll_id, Vector2D::new(x, y))); // > If the scroll position did not change as a result of the user interaction or programmatic // > invocation, where no translations were applied as a result, then no scrollend event fires @@ -2218,9 +2210,15 @@ impl Window { /// /// NOTE: This method should almost never be called directly! Layout and rendering updates should /// happen as part of the HTML event loop via *update the rendering*. - fn force_reflow(&self, reflow_goal: ReflowGoal) -> WindowReflowResult { + pub(crate) fn reflow(&self, reflow_goal: ReflowGoal) -> WindowReflowResult { let document = self.Document(); - document.ensure_safe_to_run_script_or_layout(); + + // Never reflow inactive Documents. + if !document.is_fully_active() { + return WindowReflowResult::new_empty(); + } + + self.Document().ensure_safe_to_run_script_or_layout(); // If layouts are blocked, we block all layouts that are for display only. Other // layouts (for queries and scrolling) are not blocked, as they do not display @@ -2314,88 +2312,60 @@ impl Window { } } - /// Reflows the page if it's possible to do so and the page is dirty. Returns true if layout - /// actually happened and produced a new display list, false otherwise. - /// - /// NOTE: This method should almost never be called directly! Layout and rendering updates - /// should happen as part of the HTML event loop via *update the rendering*. Currerntly, the - /// only exceptions are script queries and scroll requests. - pub(crate) fn reflow(&self, reflow_goal: ReflowGoal, can_gc: CanGc) -> WindowReflowResult { - // Never reflow inactive Documents. - if !self.Document().is_fully_active() { - return WindowReflowResult::new_empty(); + pub(crate) fn maybe_send_idle_document_state_to_constellation(&self) { + if !opts::get().wait_for_stable_image { + return; } - // Count the pending web fonts before layout, in case a font loads during the layout. - let waiting_for_web_fonts_to_load = self.font_context.web_fonts_still_loading() != 0; - - self.Document().ensure_safe_to_run_script_or_layout(); - - let updating_the_rendering = reflow_goal == ReflowGoal::UpdateTheRendering; - let reflow_result = self.force_reflow(reflow_goal); + if self.has_sent_idle_message.get() { + return; + } let document = self.Document(); - let font_face_set = document.Fonts(can_gc); - let is_ready_state_complete = document.ReadyState() == DocumentReadyState::Complete; - - // From https://drafts.csswg.org/css-font-loading/#font-face-set-ready: - // > A FontFaceSet is pending on the environment if any of the following are true: - // > - the document is still loading - // > - the document has pending stylesheet requests - // > - the document has pending layout operations which might cause the user agent to request - // > a font, or which depend on recently-loaded fonts - // - // Thus, we are queueing promise resolution here. This reflow should have been triggered by - // a "rendering opportunity" in `ScriptThread::handle_web_font_loaded, which should also - // make sure a microtask checkpoint happens, triggering the promise callback. - if !waiting_for_web_fonts_to_load && is_ready_state_complete { - font_face_set.fulfill_ready_promise_if_needed(can_gc); + if document.ReadyState() != DocumentReadyState::Complete { + return; + } + + // Checks if the html element has reftest-wait attribute present. + // See http://testthewebforward.org/docs/reftests.html + // and https://web-platform-tests.org/writing-tests/crashtest.html + if document.GetDocumentElement().is_some_and(|elem| { + elem.has_class(&atom!("reftest-wait"), CaseSensitivity::CaseSensitive) || + elem.has_class(&Atom::from("test-wait"), CaseSensitivity::CaseSensitive) + }) { + return; + } + + if self.font_context.web_fonts_still_loading() != 0 { + return; + } + + if !self.pending_layout_images.borrow().is_empty() || + !self.pending_images_for_rasterization.borrow().is_empty() + { + return; + } + + if self.Document().needs_rendering_update() { + return; } - // If writing a screenshot, check if the script has reached a state - // where it's safe to write the image. This means that: - // 1) The reflow is for display (otherwise it could be a query) - // 2) The html element doesn't contain the 'reftest-wait' class - // 3) The load event has fired. // When all these conditions are met, notify the constellation // that this pipeline is ready to write the image (from the script thread // perspective at least). - if opts::get().wait_for_stable_image && updating_the_rendering { - // Checks if the html element has reftest-wait attribute present. - // See http://testthewebforward.org/docs/reftests.html - // and https://web-platform-tests.org/writing-tests/crashtest.html - let html_element = document.GetDocumentElement(); - let reftest_wait = html_element.is_some_and(|elem| { - elem.has_class(&atom!("reftest-wait"), CaseSensitivity::CaseSensitive) || - elem.has_class(&Atom::from("test-wait"), CaseSensitivity::CaseSensitive) - }); - - let has_sent_idle_message = self.has_sent_idle_message.get(); - let no_pending_images = self.pending_layout_images.borrow().is_empty() && - self.pending_images_for_rasterization.borrow().is_empty(); - - if !has_sent_idle_message && - is_ready_state_complete && - !reftest_wait && - no_pending_images && - !waiting_for_web_fonts_to_load - { - debug!( - "{:?}: Sending DocumentState::Idle to Constellation", - self.pipeline_id() - ); - let event = ScriptToConstellationMessage::SetDocumentState(DocumentState::Idle); - self.send_to_constellation(event); - self.has_sent_idle_message.set(true); - } - } - - reflow_result + debug!( + "{:?}: Sending DocumentState::Idle to Constellation", + self.pipeline_id() + ); + self.send_to_constellation(ScriptToConstellationMessage::SetDocumentState( + DocumentState::Idle, + )); + self.has_sent_idle_message.set(true); } /// If parsing has taken a long time and reflows are still waiting for the `load` event, /// start allowing them. See . - pub(crate) fn reflow_if_reflow_timer_expired(&self, can_gc: CanGc) { + pub(crate) fn reflow_if_reflow_timer_expired(&self) { // Only trigger a long parsing time reflow if we are in the first parse of `` // and it started more than `INITIAL_REFLOW_DELAY` ago. if !matches!( @@ -2404,7 +2374,7 @@ impl Window { ) { return; } - self.allow_layout_if_necessary(can_gc); + self.allow_layout_if_necessary(); } /// Block layout for this `Window` until parsing is done. If parsing takes a long time, @@ -2423,7 +2393,7 @@ impl Window { /// Inform the [`Window`] that layout is allowed either because `load` has happened /// or because parsing the `` took so long that we cannot wait any longer. - pub(crate) fn allow_layout_if_necessary(&self, can_gc: CanGc) { + pub(crate) fn allow_layout_if_necessary(&self) { if matches!( self.layout_blocker.get(), LayoutBlocker::FiredLoadEventOrParsingTimerExpired @@ -2445,7 +2415,7 @@ impl Window { // iframe size updates. // // See - self.Document().update_the_rendering(can_gc); + self.Document().update_the_rendering(); } pub(crate) fn layout_blocked(&self) -> bool { @@ -2471,17 +2441,16 @@ impl Window { } /// Trigger a reflow that is required by a certain queries. - pub(crate) fn layout_reflow(&self, query_msg: QueryMsg, can_gc: CanGc) { - self.reflow(ReflowGoal::LayoutQuery(query_msg), can_gc); + pub(crate) fn layout_reflow(&self, query_msg: QueryMsg) { + self.reflow(ReflowGoal::LayoutQuery(query_msg)); } pub(crate) fn resolved_font_style_query( &self, node: &Node, value: String, - can_gc: CanGc, ) -> Option> { - self.layout_reflow(QueryMsg::ResolvedFontStyleQuery, can_gc); + self.layout_reflow(QueryMsg::ResolvedFontStyleQuery); let document = self.Document(); let animations = document.animations().sets.clone(); @@ -2500,20 +2469,20 @@ impl Window { .query_content_box(node.to_trusted_node_address()) } - pub(crate) fn content_box_query(&self, node: &Node, can_gc: CanGc) -> Option> { - self.layout_reflow(QueryMsg::ContentBox, can_gc); + pub(crate) fn content_box_query(&self, node: &Node) -> Option> { + self.layout_reflow(QueryMsg::ContentBox); self.content_box_query_unchecked(node) } - pub(crate) fn content_boxes_query(&self, node: &Node, can_gc: CanGc) -> Vec> { - self.layout_reflow(QueryMsg::ContentBoxes, can_gc); + pub(crate) fn content_boxes_query(&self, node: &Node) -> Vec> { + self.layout_reflow(QueryMsg::ContentBoxes); self.layout .borrow() .query_content_boxes(node.to_trusted_node_address()) } - pub(crate) fn client_rect_query(&self, node: &Node, can_gc: CanGc) -> UntypedRect { - self.layout_reflow(QueryMsg::ClientRectQuery, can_gc); + pub(crate) fn client_rect_query(&self, node: &Node) -> UntypedRect { + self.layout_reflow(QueryMsg::ClientRectQuery); self.layout .borrow() .query_client_rect(node.to_trusted_node_address()) @@ -2521,35 +2490,26 @@ impl Window { /// Find the scroll area of the given node, if it is not None. If the node /// is None, find the scroll area of the viewport. - pub(crate) fn scrolling_area_query( - &self, - node: Option<&Node>, - can_gc: CanGc, - ) -> UntypedRect { - self.layout_reflow(QueryMsg::ScrollingAreaOrOffsetQuery, can_gc); + pub(crate) fn scrolling_area_query(&self, node: Option<&Node>) -> UntypedRect { + self.layout_reflow(QueryMsg::ScrollingAreaOrOffsetQuery); self.layout .borrow() .query_scrolling_area(node.map(Node::to_trusted_node_address)) } - pub(crate) fn scroll_offset_query( - &self, - node: &Node, - can_gc: CanGc, - ) -> Vector2D { + pub(crate) fn scroll_offset_query(&self, node: &Node) -> Vector2D { let external_scroll_id = ExternalScrollId( combine_id_with_fragment_type(node.to_opaque().id(), FragmentType::FragmentBody), self.pipeline_id().into(), ); - self.scroll_offset_query_with_external_scroll_id(external_scroll_id, can_gc) + self.scroll_offset_query_with_external_scroll_id(external_scroll_id) } fn scroll_offset_query_with_external_scroll_id( &self, external_scroll_id: ExternalScrollId, - can_gc: CanGc, ) -> Vector2D { - self.layout_reflow(QueryMsg::ScrollingAreaOrOffsetQuery, can_gc); + self.layout_reflow(QueryMsg::ScrollingAreaOrOffsetQuery); self.scroll_offset_query_with_external_scroll_id_no_reflow(external_scroll_id) } @@ -2571,7 +2531,6 @@ impl Window { x_: f64, y_: f64, behavior: ScrollBehavior, - can_gc: CanGc, ) { let scroll_id = ExternalScrollId( combine_id_with_fragment_type( @@ -2590,7 +2549,6 @@ impl Window { scroll_id, behavior, Some(element), - can_gc, ); } @@ -2599,9 +2557,8 @@ impl Window { element: TrustedNodeAddress, pseudo: Option, property: PropertyId, - can_gc: CanGc, ) -> DOMString { - self.layout_reflow(QueryMsg::ResolvedStyleQuery, can_gc); + self.layout_reflow(QueryMsg::ResolvedStyleQuery); let document = self.Document(); let animations = document.animations().sets.clone(); @@ -2620,10 +2577,9 @@ impl Window { pub(crate) fn get_iframe_viewport_details_if_known( &self, browsing_context_id: BrowsingContextId, - can_gc: CanGc, ) -> Option { // Reflow might fail, but do a best effort to return the right size. - self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery, can_gc); + self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery); self.Document() .iframes() .get(browsing_context_id) @@ -2634,9 +2590,8 @@ impl Window { pub(crate) fn offset_parent_query( &self, node: &Node, - can_gc: CanGc, ) -> (Option>, UntypedRect) { - self.layout_reflow(QueryMsg::OffsetParentQuery, can_gc); + self.layout_reflow(QueryMsg::OffsetParentQuery); let response = self .layout .borrow() @@ -2652,9 +2607,8 @@ impl Window { &self, node: &Node, point_in_node: UntypedPoint2D, - can_gc: CanGc, ) -> Option { - self.layout_reflow(QueryMsg::TextIndexQuery, can_gc); + self.layout_reflow(QueryMsg::TextIndexQuery); self.layout .borrow() .query_text_indext(node.to_opaque(), point_in_node) @@ -2710,7 +2664,7 @@ impl Window { load_data.url.clone(), history_handling, )); - doc.check_and_scroll_fragment(fragment, can_gc); + doc.check_and_scroll_fragment(fragment); let this = Trusted::new(self); let old_url = doc.url().into_string(); let new_url = load_data.url.clone().into_string(); @@ -2832,6 +2786,11 @@ impl Window { self.unhandled_resize_event.borrow_mut().take() } + /// Whether or not this [`Window`] has any resize events that have not been processed. + pub(crate) fn has_unhandled_resize_event(&self) -> bool { + self.unhandled_resize_event.borrow().is_some() + } + pub(crate) fn set_viewport_size(&self, new_viewport_size: UntypedSize2D) { let new_viewport_size = Size2D::new( Au::from_f32_px(new_viewport_size.width), diff --git a/components/script/microtask.rs b/components/script/microtask.rs index 3f5969e7b7f..b034e8154a3 100644 --- a/components/script/microtask.rs +++ b/components/script/microtask.rs @@ -100,8 +100,6 @@ impl MicrotaskQueue { // Step 1 self.performing_a_microtask_checkpoint.set(true); - debug!("Now performing a microtask checkpoint"); - // Steps 2 while !self.microtask_queue.borrow().is_empty() { rooted_vec!(let mut pending_queue); diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 28d44487f13..3a527f7ef5c 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -200,7 +200,8 @@ type NodeIdSet = HashSet; #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub struct ScriptThread { /// - last_render_opportunity_time: DomRefCell>, + last_render_opportunity_time: Cell>, + /// The documents for pipelines managed by this thread documents: DomRefCell, /// The window proxies known by this thread @@ -348,7 +349,7 @@ pub struct ScriptThread { /// [`ScriptThreadMessage::TickAllAnimations`] message or because the [`ScriptThread`] /// itself is managing animations the the timer fired triggering a [`ScriptThread`]-based /// animation tick. - has_pending_animation_tick: Arc, + needs_rendering_update: Arc, debugger_global: Dom, } @@ -600,8 +601,7 @@ impl ScriptThread { } pub(crate) fn set_has_pending_animation_tick(&self) { - self.has_pending_animation_tick - .store(true, Ordering::Relaxed); + self.needs_rendering_update.store(true, Ordering::Relaxed); } /// Step 13 of @@ -999,7 +999,7 @@ impl ScriptThread { layout_factory, relative_mouse_down_point: Cell::new(Point2D::zero()), scheduled_script_thread_animation_timer: Default::default(), - has_pending_animation_tick: Arc::new(AtomicBool::new(false)), + needs_rendering_update: Arc::new(AtomicBool::new(false)), debugger_global: debugger_global.as_traced(), } } @@ -1208,37 +1208,50 @@ impl ScriptThread { })); } + fn cancel_scheduled_update_the_rendering(&self) { + if let Some(timer_id) = self + .scheduled_script_thread_animation_timer + .borrow_mut() + .take() + { + self.timer_scheduler.borrow_mut().cancel_timer(timer_id); + } + } + + fn schedule_update_the_rendering_timer_if_necessary(&self, delay: Duration) { + if self + .scheduled_script_thread_animation_timer + .borrow() + .is_some() + { + return; + } + + debug!("Scheduling ScriptThread animation frame."); + let trigger_script_thread_animation = self.needs_rendering_update.clone(); + let timer_id = self.schedule_timer(TimerEventRequest { + callback: Box::new(move || { + trigger_script_thread_animation.store(true, Ordering::Relaxed); + }), + duration: delay, + }); + + *self.scheduled_script_thread_animation_timer.borrow_mut() = Some(timer_id); + } + /// /// /// Attempt to update the rendering and then do a microtask checkpoint if rendering was actually /// updated. pub(crate) fn update_the_rendering(&self, can_gc: CanGc) { - *self.last_render_opportunity_time.borrow_mut() = Some(Instant::now()); - - let is_animation_tick = self.has_pending_animation_tick.load(Ordering::Relaxed); - if is_animation_tick { - self.has_pending_animation_tick - .store(false, Ordering::Relaxed); - // If this is an animation tick, cancel any upcoming ScriptThread-based animation timer. - // This tick serves the purpose and we to limit animation ticks if some are coming from - // the renderer. - if let Some(timer_id) = self - .scheduled_script_thread_animation_timer - .borrow_mut() - .take() - { - self.timer_scheduler.borrow_mut().cancel_timer(timer_id); - } - } + self.last_render_opportunity_time.set(Some(Instant::now())); + self.cancel_scheduled_update_the_rendering(); + self.needs_rendering_update.store(false, Ordering::Relaxed); if !self.can_continue_running_inner() { return; } - let any_animations_running = self.documents.borrow().iter().any(|(_, document)| { - document.is_fully_active() && document.animations().running_animation_count() != 0 - }); - // TODO: The specification says to filter out non-renderable documents, // as well as those for which a rendering update would be unnecessary, // but this isn't happening here. @@ -1247,13 +1260,6 @@ impl ScriptThread { // has pending initial observation targets // https://w3c.github.io/IntersectionObserver/#pending-initial-observation - // If we aren't explicitly running rAFs, this update wasn't requested by the compositor, - // and we are running animations, then wait until the compositor tells us it is time to - // update the rendering via a TickAllAnimations message. - if !is_animation_tick && any_animations_running { - return; - } - // > 2. Let docs be all fully active Document objects whose relevant agent's event loop // > is eventLoop, sorted arbitrarily except that the following conditions must be // > met: @@ -1326,14 +1332,12 @@ impl ScriptThread { // > 14. For each doc of docs, run the animation frame callbacks for doc, passing // > in the relative high resolution time given frameTimestamp and doc's // > relevant global object as the timestamp. - if is_animation_tick { - document.run_the_animation_frame_callbacks(can_gc); - } + document.run_the_animation_frame_callbacks(can_gc); // Run the resize observer steps. let _realm = enter_realm(&*document); let mut depth = Default::default(); - while document.gather_active_resize_observations_at_depth(&depth, can_gc) { + while document.gather_active_resize_observations_at_depth(&depth) { // Note: this will reflow the doc. depth = document.broadcast_active_resize_observations(can_gc); } @@ -1358,7 +1362,7 @@ impl ScriptThread { // > Step 22: For each doc of docs, update the rendering or user interface of // > doc and its node navigable to reflect the current state. - saw_any_reflows = document.update_the_rendering(can_gc) || saw_any_reflows; + saw_any_reflows = document.update_the_rendering() || saw_any_reflows; // TODO: Process top layer removals according to // https://drafts.csswg.org/css-position-4/#process-top-layer-removals. @@ -1368,106 +1372,90 @@ impl ScriptThread { // should be run in a task and a microtask checkpoint is always done when running tasks. self.perform_a_microtask_checkpoint(can_gc); - // If there are pending reflows, they were probably caused by the execution of - // the microtask checkpoint above and we should spin the event loop one more - // time to resolve them. - self.schedule_rendering_opportunity_if_necessary(); - - // If this was a animation update request, then potentially schedule a new - // animation update in the case that the compositor might not do it due to - // not receiving any display lists. - if is_animation_tick { - self.schedule_script_thread_animation_tick_if_necessary(saw_any_reflows); - } + self.maybe_schedule_rendering_opportunity_after_rendering_update(saw_any_reflows); } - // If there are any pending reflows and we are not having rendering opportunities - // driven by the compositor, then schedule the next rendering opportunity. - // - // TODO: This is a workaround until rendering opportunities can be triggered from a - // timer in the script thread. - fn schedule_rendering_opportunity_if_necessary(&self) { - // If any Document has active animations of rAFs, then we should be receiving - // regular rendering opportunities from the compositor (or fake animation frame - // ticks). In this case, don't schedule an opportunity, just wait for the next - // one. + fn maybe_schedule_rendering_opportunity_after_rendering_update(&self, saw_any_reflows: bool) { + // If there are any pending reflows and we are not having rendering opportunities + // immediately after running "update the rendering," run it one more time. if self.documents.borrow().iter().any(|(_, document)| { - document.is_fully_active() && - (document.animations().running_animation_count() != 0 || - document.has_active_request_animation_frame_callbacks()) + document.needs_rendering_update() || + (saw_any_reflows && document.has_resize_observers()) }) { - return; + self.cancel_scheduled_update_the_rendering(); + self.schedule_update_the_rendering_timer_if_necessary(Duration::ZERO); } - let Some((_, document)) = self.documents.borrow().iter().find(|(_, document)| { - document.is_fully_active() && - !document.window().layout_blocked() && - !document.restyle_reason().is_empty() - }) else { - return; - }; - - // Queues a task to update the rendering. - // - // - // Note: The specification says to queue a task using the navigable's active - // window, but then updates the rendering for all documents. - // - // This task is empty because any new IPC messages in the ScriptThread trigger a - // rendering update when animations are not running. - let _realm = enter_realm(&*document); - document - .owner_global() - .task_manager() - .rendering_task_source() - .queue_unconditionally(task!(update_the_rendering: move || { })); + if !saw_any_reflows && + self.documents.borrow().iter().any(|(_, document)| { + document.is_fully_active() && + !document.window().throttled() && + (document.animations().running_animation_count() != 0 || + document.has_active_request_animation_frame_callbacks()) + }) + { + const SCRIPT_THREAD_ANIMATION_TICK_DELAY: Duration = Duration::from_millis(30); + self.schedule_update_the_rendering_timer_if_necessary( + SCRIPT_THREAD_ANIMATION_TICK_DELAY, + ); + } } - /// The renderer triggers animation ticks based on the arrival and painting of new - /// display lists. In the case that a `WebView` is animating or has a - /// requestAnimationFrame callback, it may be that an animation tick reflow does - /// not change anything and thus does not send a new display list to the renderer. - /// If that's the case, we need to schedule a ScriptThread-based animation update - /// (to avoid waking the renderer up). - fn schedule_script_thread_animation_tick_if_necessary(&self, saw_any_reflows: bool) { - if saw_any_reflows { + fn maybe_schedule_rendering_opportunity_after_ipc_message(&self) { + // If no document needs a rendering update, exit early to avoid doing more work. + if !self + .documents + .borrow() + .iter() + .any(|(_, document)| document.needs_rendering_update()) + { return; } - // Always schedule a ScriptThread-based animation tick, unless none of the - // documents are active and have animations running and/or rAF callbacks. - if !self.documents.borrow().iter().any(|(_, document)| { - document.is_fully_active() && - !document.window().throttled() && - (document.animations().running_animation_count() != 0 || - document.has_active_request_animation_frame_callbacks()) - }) { - return; - } + // Wait 20 milliseconds between frames triggered by the script thread itself. This + // should, in theory, allow compositor-based ticks to arrive sooner. + const SCRIPT_THREAD_ANIMATION_TICK_DELAY: Duration = Duration::from_millis(20); + let time_since_last_rendering_opportunity = self + .last_render_opportunity_time + .get() + .map(|last_render_opportunity_time| Instant::now() - last_render_opportunity_time) + .unwrap_or(Duration::MAX) + .min(SCRIPT_THREAD_ANIMATION_TICK_DELAY); - /// The amount of time between ScriptThread animation ticks when nothing is - /// changing. In order to be more efficient, only tick at around 30 frames a - /// second, which also gives time for any renderer ticks to come in and cancel - /// this tick. A renderer tick might happen for a variety of reasons, such as a - /// Pipeline in another ScriptThread producing a display list. - const SCRIPT_THREAD_ANIMATION_TICK_DELAY: u64 = 30; + //eprintln!(" - scheduling update\n"); + //// If it's been more than the time of a single frame the last rendering opportunity, + //// just run it now. + //if time_since_last_rendering_opportunity > SCRIPT_THREAD_ANIMATION_TICK_DELAY { + // println!(" - running immediately"); + // self.update_the_rendering(can_gc); + // return; + //} - debug!("Scheduling ScriptThread animation frame."); - let trigger_script_thread_animation = self.has_pending_animation_tick.clone(); - let timer_id = self.schedule_timer(TimerEventRequest { - callback: Box::new(move || { - trigger_script_thread_animation.store(true, Ordering::Relaxed); - }), - duration: Duration::from_millis(SCRIPT_THREAD_ANIMATION_TICK_DELAY), - }); - - let mut scheduled_script_thread_animation_timer = - self.scheduled_script_thread_animation_timer.borrow_mut(); - assert!( - scheduled_script_thread_animation_timer.is_none(), - "Should never schedule a new timer when one is already scheduled." + self.schedule_update_the_rendering_timer_if_necessary( + SCRIPT_THREAD_ANIMATION_TICK_DELAY - time_since_last_rendering_opportunity, ); - *scheduled_script_thread_animation_timer = Some(timer_id); + } + + fn maybe_fulfill_font_ready_promises(&self, can_gc: CanGc) { + let mut sent_message = false; + for (_, document) in self.documents.borrow().iter() { + sent_message = document.maybe_fulfill_font_ready_promise(can_gc) || sent_message; + } + + if sent_message { + self.perform_a_microtask_checkpoint(can_gc); + } + } + + fn maybe_send_document_state_messages(&self) { + if !opts::get().wait_for_stable_image { + return; + } + for (_, document) in self.documents.borrow().iter() { + document + .window() + .maybe_send_idle_document_state_to_constellation(); + } } /// Handle incoming messages from other tasks and the task queue. @@ -1679,10 +1667,13 @@ impl ScriptThread { docs.clear(); } - // Update the rendering whenever we receive an IPC message. This may not actually do anything if - // we are running animations and the compositor hasn't requested a new frame yet via a TickAllAnimatons - // message. - self.update_the_rendering(can_gc); + if self.needs_rendering_update.load(Ordering::Relaxed) { + self.update_the_rendering(can_gc); + } + + self.maybe_fulfill_font_ready_promises(can_gc); + self.maybe_schedule_rendering_opportunity_after_ipc_message(); + self.maybe_send_document_state_messages(); true } @@ -2194,7 +2185,7 @@ impl ScriptThread { devtools::handle_get_selectors(&documents, id, node_id, reply, can_gc) }, DevtoolScriptControlMsg::GetComputedStyle(id, node_id, reply) => { - devtools::handle_get_computed_style(&documents, id, node_id, reply, can_gc) + devtools::handle_get_computed_style(&documents, id, node_id, reply) }, DevtoolScriptControlMsg::GetLayout(id, node_id, reply) => { devtools::handle_get_layout(&documents, id, node_id, reply, can_gc) @@ -2317,7 +2308,6 @@ impl ScriptThread { selector, partial, reply, - can_gc, ) }, WebDriverScriptCommand::FindElementsTagName(selector, reply) => { @@ -2359,7 +2349,6 @@ impl ScriptThread { selector, partial, reply, - can_gc, ), WebDriverScriptCommand::FindElementElementsTagName(selector, element_id, reply) => { webdriver_handlers::handle_find_element_elements_tag_name( @@ -2406,7 +2395,6 @@ impl ScriptThread { selector, partial, reply, - can_gc, ), WebDriverScriptCommand::FindShadowElementsTagName(selector, shadow_root_id, reply) => { webdriver_handlers::handle_find_shadow_elements_tag_name( @@ -2489,14 +2477,7 @@ impl ScriptThread { ) }, WebDriverScriptCommand::GetElementCSS(node_id, name, reply) => { - webdriver_handlers::handle_get_css( - &documents, - pipeline_id, - node_id, - name, - reply, - can_gc, - ) + webdriver_handlers::handle_get_css(&documents, pipeline_id, node_id, name, reply) }, WebDriverScriptCommand::GetElementRect(node_id, reply) => { webdriver_handlers::handle_get_rect(&documents, pipeline_id, node_id, reply, can_gc) @@ -2511,7 +2492,7 @@ impl ScriptThread { ) }, WebDriverScriptCommand::GetElementText(node_id, reply) => { - webdriver_handlers::handle_get_text(&documents, pipeline_id, node_id, reply, can_gc) + webdriver_handlers::handle_get_text(&documents, pipeline_id, node_id, reply) }, WebDriverScriptCommand::GetElementInViewCenterPoint(node_id, reply) => { webdriver_handlers::handle_get_element_in_view_center_point( diff --git a/components/script/task_manager.rs b/components/script/task_manager.rs index b81ec1e86f0..2c012416165 100644 --- a/components/script/task_manager.rs +++ b/components/script/task_manager.rs @@ -145,7 +145,6 @@ impl TaskManager { task_source_functions!(self, performance_timeline_task_source, PerformanceTimeline); task_source_functions!(self, port_message_queue, PortMessage); task_source_functions!(self, remote_event_task_source, RemoteEvent); - task_source_functions!(self, rendering_task_source, Rendering); task_source_functions!(self, timer_task_source, Timer); task_source_functions!(self, user_interaction_task_source, UserInteraction); task_source_functions!(self, websocket_task_source, WebSocket); diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 865aa01423d..3de4c44e959 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -194,14 +194,13 @@ fn matching_links( links: &NodeList, link_text: String, partial: bool, - can_gc: CanGc, ) -> impl Iterator + '_ { links .iter() .filter(move |node| { let content = node .downcast::() - .map(|element| element.InnerText(can_gc)) + .map(|element| element.InnerText()) .map_or("".to_owned(), String::from) .trim() .to_owned(); @@ -218,7 +217,6 @@ fn all_matching_links( root_node: &Node, link_text: String, partial: bool, - can_gc: CanGc, ) -> Result, ErrorStatus> { // // Step 7.2. If a DOMException, SyntaxError, XPathException, or other error occurs @@ -226,7 +224,7 @@ fn all_matching_links( root_node .query_selector_all(DOMString::from("a")) .map_err(|_| ErrorStatus::InvalidSelector) - .map(|nodes| matching_links(&nodes, link_text, partial, can_gc).collect()) + .map(|nodes| matching_links(&nodes, link_text, partial).collect()) } #[allow(unsafe_code)] @@ -749,7 +747,6 @@ pub(crate) fn handle_find_elements_link_text( selector: String, partial: bool, reply: IpcSender, ErrorStatus>>, - can_gc: CanGc, ) { match retrieve_document_and_check_root_existence(documents, pipeline) { Ok(document) => reply @@ -757,7 +754,6 @@ pub(crate) fn handle_find_elements_link_text( document.upcast::(), selector.clone(), partial, - can_gc, )) .unwrap(), Err(error) => reply.send(Err(error)).unwrap(), @@ -896,12 +892,11 @@ pub(crate) fn handle_find_element_elements_link_text( selector: String, partial: bool, reply: IpcSender, ErrorStatus>>, - can_gc: CanGc, ) { reply .send( get_known_element(documents, pipeline, element_id).and_then(|element| { - all_matching_links(element.upcast::(), selector.clone(), partial, can_gc) + all_matching_links(element.upcast::(), selector.clone(), partial) }), ) .unwrap(); @@ -986,17 +981,11 @@ pub(crate) fn handle_find_shadow_elements_link_text( selector: String, partial: bool, reply: IpcSender, ErrorStatus>>, - can_gc: CanGc, ) { reply .send( get_known_shadow_root(documents, pipeline, shadow_root_id).and_then(|shadow_root| { - all_matching_links( - shadow_root.upcast::(), - selector.clone(), - partial, - can_gc, - ) + all_matching_links(shadow_root.upcast::(), selector.clone(), partial) }), ) .unwrap(); @@ -1540,14 +1529,13 @@ pub(crate) fn handle_get_text( pipeline: PipelineId, node_id: String, reply: IpcSender>, - can_gc: CanGc, ) { reply .send( get_known_element(documents, pipeline, node_id).map(|element| { element .downcast::() - .map(|htmlelement| htmlelement.InnerText(can_gc).to_string()) + .map(|htmlelement| htmlelement.InnerText().to_string()) .unwrap_or_else(|| { element .upcast::() @@ -1652,7 +1640,6 @@ pub(crate) fn handle_get_css( node_id: String, name: String, reply: IpcSender>, - can_gc: CanGc, ) { reply .send( @@ -1661,7 +1648,7 @@ pub(crate) fn handle_get_css( String::from( window .GetComputedStyle(&element, None) - .GetPropertyValue(DOMString::from(name), can_gc), + .GetPropertyValue(DOMString::from(name)), ) }), ) @@ -1912,7 +1899,7 @@ fn is_element_in_view(element: &Element, document: &Document, can_gc: CanGc) -> // An element is said to have pointer events disabled // if the resolved value of its "pointer-events" style property is "none". let pointer_events_enabled = element - .style(can_gc) + .style() .is_none_or(|style| style.get_inherited_ui().pointer_events != PointerEvents::None); // An element is in view if it is a member of its own pointer-interactable paint tree, @@ -1939,7 +1926,6 @@ fn get_element_pointer_interactable_paint_tree( Some(center_point) => document.ElementsFromPoint( Finite::wrap(center_point.x as f64), Finite::wrap(center_point.y as f64), - can_gc, ), None => Vec::new(), } diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf index e356cb52b53..60791a0b66e 100644 --- a/components/script_bindings/codegen/Bindings.conf +++ b/components/script_bindings/codegen/Bindings.conf @@ -80,12 +80,8 @@ DOMInterfaces = { 'canGc': ['GetSize'], }, -'CanvasGradient': { - 'canGc': ['AddColorStop'], -}, - 'CanvasRenderingContext2D': { - 'canGc': ['GetTransform','GetImageData', 'CreateImageData', 'CreateImageData_', 'SetFont', 'FillText', 'MeasureText', 'SetStrokeStyle', 'SetFillStyle', 'SetShadowColor', 'CreateLinearGradient', 'CreatePattern', 'CreateRadialGradient'], + 'canGc': ['GetTransform','GetImageData', 'CreateImageData', 'CreateImageData_', 'MeasureText', 'CreateLinearGradient', 'CreatePattern', 'CreateRadialGradient'], }, 'CharacterData': { @@ -146,7 +142,7 @@ DOMInterfaces = { }, 'CSSStyleDeclaration': { - 'canGc': ['RemoveProperty', 'SetCssText', 'GetPropertyValue', 'SetProperty', 'CssFloat', 'SetCssFloat'] + 'canGc': ['RemoveProperty', 'SetCssText', 'SetProperty', 'SetCssFloat'] }, 'CustomElementRegistry': { @@ -172,7 +168,7 @@ DOMInterfaces = { 'Document': { 'additionalTraits': ["crate::interfaces::DocumentHelpers"], - 'canGc': ['Close', 'CreateElement', 'CreateElementNS', 'ImportNode', 'SetTitle', 'Write', 'Writeln', 'CreateEvent', 'CreateRange', 'Open', 'Open_', 'CreateComment', 'CreateAttribute', 'CreateAttributeNS', 'CreateDocumentFragment', 'CreateTextNode', 'CreateCDATASection', 'CreateProcessingInstruction', 'Prepend', 'Append', 'ReplaceChildren', 'SetBgColor', 'SetFgColor', 'Fonts', 'ElementFromPoint', 'ElementsFromPoint', 'GetScrollingElement', 'ExitFullscreen', 'CreateExpression', 'CreateNSResolver', 'Evaluate', 'StyleSheets', 'Implementation', 'GetElementsByTagName', 'GetElementsByTagNameNS', 'GetElementsByClassName', 'AdoptNode', 'CreateNodeIterator', 'SetBody', 'GetElementsByName', 'Images', 'Embeds', 'Plugins', 'Links', 'Forms', 'Scripts', 'Anchors', 'Applets', 'Children', 'GetSelection', 'NamedGetter', 'AdoptedStyleSheets'], + 'canGc': ['Close', 'CreateElement', 'CreateElementNS', 'ImportNode', 'SetTitle', 'Write', 'Writeln', 'CreateEvent', 'CreateRange', 'Open', 'Open_', 'CreateComment', 'CreateAttribute', 'CreateAttributeNS', 'CreateDocumentFragment', 'CreateTextNode', 'CreateCDATASection', 'CreateProcessingInstruction', 'Prepend', 'Append', 'ReplaceChildren', 'SetBgColor', 'SetFgColor', 'Fonts', 'ExitFullscreen', 'CreateExpression', 'CreateNSResolver', 'Evaluate', 'StyleSheets', 'Implementation', 'GetElementsByTagName', 'GetElementsByTagNameNS', 'GetElementsByClassName', 'AdoptNode', 'CreateNodeIterator', 'SetBody', 'GetElementsByName', 'Images', 'Embeds', 'Plugins', 'Links', 'Forms', 'Scripts', 'Anchors', 'Applets', 'Children', 'GetSelection', 'NamedGetter', 'AdoptedStyleSheets'], }, 'DissimilarOriginWindow': { @@ -236,7 +232,7 @@ DOMInterfaces = { }, 'Element': { - 'canGc': ['SetHTMLUnsafe', 'SetInnerHTML', 'SetOuterHTML', 'InsertAdjacentHTML', 'GetClientRects', 'GetBoundingClientRect', 'InsertAdjacentText', 'ToggleAttribute', 'SetAttribute', 'SetAttributeNS', 'SetId','SetClassName','Prepend','Append','ReplaceChildren','Before','After','ReplaceWith', 'SetRole', 'SetAriaAtomic', 'SetAriaAutoComplete', 'SetAriaBrailleLabel', 'SetAriaBrailleRoleDescription', 'SetAriaBusy', 'SetAriaChecked', 'SetAriaColCount', 'SetAriaColIndex', 'SetAriaColIndexText', 'SetAriaColSpan', 'SetAriaCurrent', 'SetAriaDescription', 'SetAriaDisabled', 'SetAriaExpanded', 'SetAriaHasPopup', 'SetAriaHidden', 'SetAriaInvalid', 'SetAriaKeyShortcuts', 'SetAriaLabel', 'SetAriaLevel', 'SetAriaLive', 'SetAriaModal', 'SetAriaMultiLine', 'SetAriaMultiSelectable', 'SetAriaOrientation', 'SetAriaPlaceholder', 'SetAriaPosInSet', 'SetAriaPressed','SetAriaReadOnly', 'SetAriaRelevant', 'SetAriaRequired', 'SetAriaRoleDescription', 'SetAriaRowCount', 'SetAriaRowIndex', 'SetAriaRowIndexText', 'SetAriaRowSpan', 'SetAriaSelected', 'SetAriaSetSize','SetAriaSort', 'SetAriaValueMax', 'SetAriaValueMin', 'SetAriaValueNow', 'SetAriaValueText', 'SetScrollTop', 'SetScrollLeft', 'Scroll', 'Scroll_', 'ScrollBy', 'ScrollBy_', 'ScrollWidth', 'ScrollHeight', 'ScrollTop', 'ScrollLeft', 'ClientTop', 'ClientLeft', 'ClientWidth', 'ClientHeight', 'RequestFullscreen', 'GetHTML', 'GetInnerHTML', 'GetOuterHTML', 'ClassList', 'Attributes', 'SetAttributeNode', 'SetAttributeNodeNS', 'RemoveAttribute', 'RemoveAttributeNS', 'RemoveAttributeNode', 'GetElementsByTagName', 'GetElementsByTagNameNS', 'GetElementsByClassName', 'ScrollTo', 'ScrollTo_', 'Children', 'Remove', 'InsertAdjacentElement', 'AttachShadow'], + 'canGc': ['SetHTMLUnsafe', 'SetInnerHTML', 'SetOuterHTML', 'InsertAdjacentHTML', 'GetClientRects', 'GetBoundingClientRect', 'InsertAdjacentText', 'ToggleAttribute', 'SetAttribute', 'SetAttributeNS', 'SetId','SetClassName','Prepend','Append','ReplaceChildren','Before','After','ReplaceWith', 'SetRole', 'SetAriaAtomic', 'SetAriaAutoComplete', 'SetAriaBrailleLabel', 'SetAriaBrailleRoleDescription', 'SetAriaBusy', 'SetAriaChecked', 'SetAriaColCount', 'SetAriaColIndex', 'SetAriaColIndexText', 'SetAriaColSpan', 'SetAriaCurrent', 'SetAriaDescription', 'SetAriaDisabled', 'SetAriaExpanded', 'SetAriaHasPopup', 'SetAriaHidden', 'SetAriaInvalid', 'SetAriaKeyShortcuts', 'SetAriaLabel', 'SetAriaLevel', 'SetAriaLive', 'SetAriaModal', 'SetAriaMultiLine', 'SetAriaMultiSelectable', 'SetAriaOrientation', 'SetAriaPlaceholder', 'SetAriaPosInSet', 'SetAriaPressed','SetAriaReadOnly', 'SetAriaRelevant', 'SetAriaRequired', 'SetAriaRoleDescription', 'SetAriaRowCount', 'SetAriaRowIndex', 'SetAriaRowIndexText', 'SetAriaRowSpan', 'SetAriaSelected', 'SetAriaSetSize','SetAriaSort', 'SetAriaValueMax', 'SetAriaValueMin', 'SetAriaValueNow', 'SetAriaValueText', 'RequestFullscreen', 'GetHTML', 'GetInnerHTML', 'GetOuterHTML', 'ClassList', 'Attributes', 'SetAttributeNode', 'SetAttributeNodeNS', 'RemoveAttribute', 'RemoveAttributeNS', 'RemoveAttributeNode', 'GetElementsByTagName', 'GetElementsByTagNameNS', 'GetElementsByClassName', 'Children', 'Remove', 'InsertAdjacentElement', 'AttachShadow'], }, 'ElementInternals': { @@ -362,7 +358,7 @@ DOMInterfaces = { }, 'HTMLElement': { - 'canGc': ['AttachInternals', 'Focus', 'Blur', 'Click', 'SetInnerText', 'SetOuterText', "SetTranslate", 'SetAutofocus', 'GetOffsetParent', 'OffsetTop', 'OffsetLeft', 'OffsetWidth', 'OffsetHeight', 'InnerText', 'GetOuterText', 'GetOnerror', 'GetOnload', 'GetOnblur', 'GetOnfocus', 'GetOnresize', 'GetOnscroll', 'Style', 'Dataset'], + 'canGc': ['AttachInternals', 'Focus', 'Blur', 'Click', 'SetInnerText', 'SetOuterText', "SetTranslate", 'SetAutofocus', 'GetOnerror', 'GetOnload', 'GetOnblur', 'GetOnfocus', 'GetOnresize', 'GetOnscroll', 'Style', 'Dataset'], }, 'HTMLFieldSetElement': { @@ -386,7 +382,7 @@ DOMInterfaces = { }, 'HTMLImageElement': { - 'canGc': ['RequestSubmit', 'ReportValidity', 'Reset','SetRel', 'Width', 'Height', 'Decode', 'SetCrossOrigin', 'SetWidth', 'SetHeight', 'SetReferrerPolicy'], + 'canGc': ['RequestSubmit', 'ReportValidity', 'Reset','SetRel', 'Decode', 'SetCrossOrigin', 'SetWidth', 'SetHeight', 'SetReferrerPolicy'], }, 'HTMLInputElement': { @@ -427,7 +423,7 @@ DOMInterfaces = { }, 'HTMLScriptElement': { - 'canGc': ['InnerText', 'SetAsync', 'SetCrossOrigin', 'SetInnerText', 'SetSrc', 'SetText', 'SetTextContent'] + 'canGc': ['SetAsync', 'SetCrossOrigin', 'SetInnerText', 'SetSrc', 'SetText', 'SetTextContent'] }, 'HTMLSelectElement': { @@ -492,10 +488,6 @@ DOMInterfaces = { 'canGc': ['Ports'], }, -'MouseEvent': { - 'canGc': ['InitMouseEvent', 'OffsetX', 'OffsetY'], -}, - 'NavigationPreloadManager': { 'inRealms': ['Disable', 'Enable', 'GetState', 'SetHeaderValue'], 'canGc': ['Disable', 'Enable', 'GetState', 'SetHeaderValue'], @@ -528,11 +520,11 @@ DOMInterfaces = { }, 'OffscreenCanvasRenderingContext2D': { - 'canGc': ['CreateImageData', 'CreateImageData_', 'GetImageData', 'GetTransform', 'SetFont', 'FillText', 'MeasureText', 'SetStrokeStyle', 'SetFillStyle', 'SetShadowColor', 'CreateLinearGradient', 'CreatePattern', 'CreateRadialGradient'], + 'canGc': ['CreateImageData', 'CreateImageData_', 'GetImageData', 'GetTransform', 'MeasureText', 'CreateLinearGradient', 'CreatePattern', 'CreateRadialGradient'], }, 'PaintRenderingContext2D': { - 'canGc': ['GetTransform', 'SetStrokeStyle', 'SetFillStyle', 'SetShadowColor'], + 'canGc': ['GetTransform'], }, 'Performance': { @@ -591,7 +583,7 @@ DOMInterfaces = { }, 'ShadowRoot': { - 'canGc': ['SetHTMLUnsafe', 'ElementFromPoint', 'ElementsFromPoint', 'SetInnerHTML', 'GetHTML', 'InnerHTML', 'AdoptedStyleSheets'], + 'canGc': ['SetHTMLUnsafe', 'SetInnerHTML', 'GetHTML', 'InnerHTML', 'AdoptedStyleSheets'], }, 'StaticRange': { @@ -654,12 +646,8 @@ DOMInterfaces = { 'additionalTraits': ['crate::interfaces::WebGL2RenderingContextHelpers'], }, -'WheelEvent': { - 'canGc': ['InitWheelEvent'], -}, - 'Window': { - 'canGc': ['Stop', 'Fetch', 'Scroll', 'Scroll_','ScrollBy', 'ScrollBy_', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap', 'CreateImageBitmap_', 'TrustedTypes', 'WebdriverCallback', 'WebdriverException'], + 'canGc': ['Stop', 'Fetch', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap', 'CreateImageBitmap_', 'TrustedTypes', 'WebdriverCallback', 'WebdriverException'], 'inRealms': ['Fetch', 'GetOpener', 'WebdriverCallback', 'WebdriverException'], 'additionalTraits': ['crate::interfaces::WindowHelpers'], }, diff --git a/components/shared/layout/lib.rs b/components/shared/layout/lib.rs index 7d182fe5fc4..1f93159982c 100644 --- a/components/shared/layout/lib.rs +++ b/components/shared/layout/lib.rs @@ -259,6 +259,9 @@ pub trait Layout { /// not exist in the tree. fn scroll_offset(&self, id: ExternalScrollId) -> Option; + /// Returns true if this layout needs to produce a new display list for rendering updates. + fn needs_new_display_list(&self) -> bool; + fn query_content_box(&self, node: TrustedNodeAddress) -> Option>; fn query_content_boxes(&self, node: TrustedNodeAddress) -> Vec>; fn query_client_rect(&self, node: TrustedNodeAddress) -> Rect; diff --git a/tests/wpt/meta/css/css-cascade/layer-statement-before-import.html.ini b/tests/wpt/meta/css/css-cascade/layer-statement-before-import.html.ini deleted file mode 100644 index 8fed2a8d383..00000000000 --- a/tests/wpt/meta/css/css-cascade/layer-statement-before-import.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[layer-statement-before-import.html] - [insert other rules before the first layer statement without imports] - expected: FAIL diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 014d6baa7d9..53a5ca705e1 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -12595,7 +12595,7 @@ ] ], "basic-transition.html": [ - "b80e8a666a6e6202b4ecafe628ef00ebcecfe168", + "c3461d3a5f9f1259296168742028db3bd4fc3668", [ null, {} @@ -12623,7 +12623,7 @@ ] ], "transition-raf.html": [ - "c38404503408e04b3c75b42df18ec3a7ec0819f5", + "aa3ed54e3e08a190f227c87165523306aed5a6bc", [ null, {} @@ -12743,7 +12743,7 @@ ] ], "stylesheet_media_queries.html": [ - "49956367a16c3de98d173d4cf5692c05451340a0", + "d04eb4b23f107b1e4d127cf633d4155ab3bdf629", [ null, {} diff --git a/tests/wpt/mozilla/tests/css/animations/basic-transition.html b/tests/wpt/mozilla/tests/css/animations/basic-transition.html index b80e8a666a6..c3461d3a5f9 100644 --- a/tests/wpt/mozilla/tests/css/animations/basic-transition.html +++ b/tests/wpt/mozilla/tests/css/animations/basic-transition.html @@ -20,15 +20,26 @@ var div = document.getElementById('check-me'); var span = div.childNodes[0]; async_test(function(t) { window.addEventListener('load', function() { - assert_equals(getComputedStyle(div).getPropertyValue('background-color'), 'rgb(255, 0, 0)'); - div.id = "check-me-2"; - requestAnimationFrame(function() { - var test = new window.TestBinding(); + var test = new window.TestBinding(); + + div.addEventListener("transitionstart", () => { + // The transition should have just started so the current value of the style should + // not be the value expected after the transition. + assert_not_equals(getComputedStyle(div).getPropertyValue('background-color'), 'rgb(0, 0, 0)'); test.advanceClock(2000); - span.innerHTML = "a"; + }); + + div.addEventListener("transitionend", () => { + // The transition should be finished so the value of the style should be the final one. assert_equals(getComputedStyle(div).getPropertyValue('background-color'), 'rgb(0, 0, 0)'); t.done(); }); + + // The starting value should be the one set in the style. + assert_equals(getComputedStyle(div).getPropertyValue('background-color'), 'rgb(255, 0, 0)'); + + // Start the transition. + div.id = "check-me-2"; }) }) diff --git a/tests/wpt/mozilla/tests/css/animations/transition-raf.html b/tests/wpt/mozilla/tests/css/animations/transition-raf.html index c3840450340..aa3ed54e3e0 100644 --- a/tests/wpt/mozilla/tests/css/animations/transition-raf.html +++ b/tests/wpt/mozilla/tests/css/animations/transition-raf.html @@ -32,9 +32,12 @@ async_test(function(t) { window.addEventListener('load', function() { assert_equals(getComputedStyle(box).getPropertyValue('width'), '100px'); + + box.addEventListener("transitionstart", () => { + // Let the first restyle run at zero, then advance the clock. + test.advanceClock(500); + }); box.className = "expose"; - // Let the first restyle run at zero, then advance the clock. - setTimeout(function() { test.advanceClock(500) }, 0); }); }, "Transitions should work during RAF loop") diff --git a/tests/wpt/mozilla/tests/css/stylesheet_media_queries.html b/tests/wpt/mozilla/tests/css/stylesheet_media_queries.html index 49956367a16..d04eb4b23f1 100644 --- a/tests/wpt/mozilla/tests/css/stylesheet_media_queries.html +++ b/tests/wpt/mozilla/tests/css/stylesheet_media_queries.html @@ -14,8 +14,10 @@ window.onload = test.step_func(function() { assert_equals(frame.contentWindow.getComputedStyle(element).backgroundColor, "rgb(255, 0, 0)"); frame.width = "300"; frameDoc.documentElement.offsetWidth; // Force layout - window.requestAnimationFrame(test.step_func_done(function () { + window.requestAnimationFrame(() => { + window.requestAnimationFrame(test.step_func_done(function () { assert_equals(frame.contentWindow.getComputedStyle(element).backgroundColor, "rgb(0, 255, 0)"); - })); + })) + }); });