From 0beec63c86d8cb04f183249c8a2c81b49e17e03e Mon Sep 17 00:00:00 2001 From: Smitty Date: Fri, 1 Mar 2024 02:42:18 -0500 Subject: [PATCH] script: Implement `` (#31468) * script: Implement * Address review comments --- components/script/dom/document.rs | 39 ++++++ components/script/dom/htmlmetaelement.rs | 129 +++++++++++++++++- components/script/dom/location.rs | 19 ++- .../script/dom/webidls/HTMLMetaElement.webidl | 4 +- components/script/timers.rs | 3 + .../HTMLMetaElement.html.ini | 6 - ...t-meta-refresh.https.optional.sub.html.ini | 38 +++--- ...element-meta-refresh.optional.sub.html.ini | 44 +----- .../html/dom/idlharness.https.html.ini | 6 - .../html/dom/reflection-metadata.html.ini | 114 ---------------- .../test-timing-client-redirect.html.ini | 2 - ...resource_subframe_self_navigation.html.ini | 5 +- .../HTMLMetaElement.html.ini | 6 - ...t-meta-refresh.https.optional.sub.html.ini | 38 +++--- ...element-meta-refresh.optional.sub.html.ini | 44 +----- .../meta/html/dom/idlharness.https.html.ini | 6 - .../html/dom/reflection-metadata.html.ini | 114 ---------------- .../test-timing-client-redirect.html.ini | 2 - ...resource_subframe_self_navigation.html.ini | 4 +- 19 files changed, 227 insertions(+), 396 deletions(-) delete mode 100644 tests/wpt/meta-legacy-layout/custom-elements/reactions/customized-builtins/HTMLMetaElement.html.ini delete mode 100644 tests/wpt/meta-legacy-layout/navigation-timing/test-timing-client-redirect.html.ini delete mode 100644 tests/wpt/meta/custom-elements/reactions/customized-builtins/HTMLMetaElement.html.ini delete mode 100644 tests/wpt/meta/navigation-timing/test-timing-client-redirect.html.ini diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 512c3870b1f..019cc07529f 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -140,6 +140,7 @@ use crate::dom::htmlhtmlelement::HTMLHtmlElement; use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::htmlimageelement::HTMLImageElement; use crate::dom::htmlinputelement::HTMLInputElement; +use crate::dom::htmlmetaelement::RefreshRedirectDue; use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult}; use crate::dom::htmltextareaelement::HTMLTextAreaElement; use crate::dom::htmltitleelement::HTMLTitleElement; @@ -233,6 +234,17 @@ enum FocusTransaction { InTransaction(Option>), } +/// Information about a declarative refresh +#[derive(JSTraceable, MallocSizeOf)] +pub enum DeclarativeRefresh { + PendingLoad { + #[no_trace] + url: ServoUrl, + time: u64, + }, + CreatedAfterLoad, +} + /// #[dom_struct] pub struct Document { @@ -435,6 +447,8 @@ pub struct Document { animations: DomRefCell, /// The nearest inclusive ancestors to all the nodes that require a restyle. dirty_root: MutNullableDom, + /// + declarative_refresh: DomRefCell>, } #[derive(JSTraceable, MallocSizeOf)] @@ -2399,6 +2413,19 @@ impl Document { task!(completely_loaded: move || { let document = document.root(); document.completely_loaded.set(true); + if let Some(DeclarativeRefresh::PendingLoad { + url, + time + }) = &*document.declarative_refresh.borrow() { + // https://html.spec.whatwg.org/multipage/#shared-declarative-refresh-steps + document.window.upcast::().schedule_callback( + OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue { + window: window_from_node(&*document), + url: url.clone(), + }), + MsDuration::new(time.saturating_mul(1000)), + ); + } // Note: this will, among others, result in the "iframe-load-event-steps" being run. // https://html.spec.whatwg.org/multipage/#iframe-load-event-steps document.notify_constellation_load(); @@ -2409,6 +2436,10 @@ impl Document { } } + pub fn completely_loaded(&self) -> bool { + self.completely_loaded.get() + } + // https://html.spec.whatwg.org/multipage/#pending-parsing-blocking-script pub fn set_pending_parsing_blocking_script( &self, @@ -3195,6 +3226,7 @@ impl Document { }, animations: DomRefCell::new(Animations::new()), dirty_root: Default::default(), + declarative_refresh: Default::default(), } } @@ -3940,6 +3972,13 @@ impl Document { pub(crate) fn cancel_animations_for_node(&self, node: &Node) { self.animations.borrow().cancel_animations_for_node(node); } + + pub(crate) fn will_declaratively_refresh(&self) -> bool { + self.declarative_refresh.borrow().is_some() + } + pub(crate) fn set_declarative_refresh(&self, refresh: DeclarativeRefresh) { + *self.declarative_refresh.borrow_mut() = Some(refresh); + } } impl Element { diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index 61ec43ac96a..46e3137a92b 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -2,29 +2,57 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::str::FromStr; + use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; use js::rust::HandleObject; +use regex::bytes::Regex; +use script_traits::{HistoryEntryReplacement, MsDuration}; +use servo_url::ServoUrl; use style::str::HTML_SPACE_CHARACTERS; use crate::dom::attr::Attr; +use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; -use crate::dom::document::Document; +use crate::dom::document::{DeclarativeRefresh, Document}; use crate::dom::element::{AttributeMutation, Element}; +use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlheadelement::HTMLHeadElement; -use crate::dom::node::{BindContext, Node, UnbindContext}; +use crate::dom::location::NavigationType; +use crate::dom::node::{document_from_node, window_from_node, BindContext, Node, UnbindContext}; use crate::dom::virtualmethods::VirtualMethods; +use crate::dom::window::Window; +use crate::timers::OneshotTimerCallback; #[dom_struct] pub struct HTMLMetaElement { htmlelement: HTMLElement, } +#[derive(JSTraceable, MallocSizeOf)] +pub struct RefreshRedirectDue { + #[no_trace] + pub url: ServoUrl, + #[ignore_malloc_size_of = "non-owning"] + pub window: DomRoot, +} +impl RefreshRedirectDue { + pub fn invoke(self) { + self.window.Location().navigate( + self.url.clone(), + HistoryEntryReplacement::Enabled, + NavigationType::DeclarativeRefresh, + ); + } +} + impl HTMLMetaElement { fn new_inherited( local_name: LocalName, @@ -58,6 +86,8 @@ impl HTMLMetaElement { if name == "referrer" { self.apply_referrer(); } + } else if &*self.HttpEquiv() != "" { + self.declarative_refresh(); } } @@ -81,6 +111,96 @@ impl HTMLMetaElement { } } } + + /// + fn declarative_refresh(&self) { + // 2 + let content = self.Content(); + // 1 + if !content.is_empty() { + // 3 + self.shared_declarative_refresh_steps(content); + } + } + + /// + fn shared_declarative_refresh_steps(&self, content: DOMString) { + // 1 + let document = document_from_node(self); + if document.will_declaratively_refresh() { + return; + } + + // 2-11 + lazy_static::lazy_static! { + static ref REFRESH_REGEX: Regex = Regex::new( + r#"(?x) + ^ + \s* # 3 + ((?