mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
Compare commits
14 Commits
f9cfd05af8
...
626af595f2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
626af595f2 | ||
|
|
a09c334a52 | ||
|
|
35671d9dde | ||
|
|
8ced3d1b8e | ||
|
|
1464ffd68a | ||
|
|
6e4a9e85a2 | ||
|
|
71a5dfabdd | ||
|
|
430105468f | ||
|
|
93ae710c07 | ||
|
|
8590dd74c9 | ||
|
|
8470478270 | ||
|
|
ee72fca571 | ||
|
|
551100c8bb | ||
|
|
22da16139d |
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -3098,9 +3098,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "grid"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9e2d4c0a8296178d8802098410ca05d86b17a10bb5ab559b3fb404c1f948220"
|
||||
checksum = "b40ca9252762c466af32d0b1002e91e4e1bc5398f77455e55474deb466355ff5"
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
|
||||
@@ -10,11 +10,41 @@ use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
/// <https://searchfox.org/mozilla-central/source/devtools/server/actors/resources/stylesheets.js>
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct StyleSheetData {
|
||||
/// Unique identifier for this stylesheet.
|
||||
resource_id: String,
|
||||
/// The URL of the stylesheet. Optional for inline stylesheets.
|
||||
href: Option<String>,
|
||||
/// The URL of the document that owns this stylesheet.
|
||||
node_href: String,
|
||||
/// Whether the stylesheet is disabled.
|
||||
disabled: bool,
|
||||
/// The title of the stylesheet.
|
||||
title: String,
|
||||
/// Whether this is a browser stylesheet.
|
||||
system: bool,
|
||||
/// Whether this stylesheet was created by DevTools.
|
||||
is_new: bool,
|
||||
/// Optional source map URL.
|
||||
source_map_url: Option<String>,
|
||||
/// The index of this stylesheet in the document's stylesheet list.
|
||||
style_sheet_index: i32,
|
||||
// TODO: the following fields will be implemented later once we fetch the stylesheets
|
||||
// constructed: bool,
|
||||
// file_name: Option<String>,
|
||||
// at_rules: Vec<Rule>,
|
||||
// rule_count: u32,
|
||||
// source_map_base_url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GetStyleSheetsReply {
|
||||
from: String,
|
||||
style_sheets: Vec<u32>, // TODO: real JSON structure.
|
||||
style_sheets: Vec<StyleSheetData>,
|
||||
}
|
||||
|
||||
#[derive(MallocSizeOf)]
|
||||
@@ -38,6 +68,7 @@ impl Actor for StyleSheetsActor {
|
||||
"getStyleSheets" => {
|
||||
let msg = GetStyleSheetsReply {
|
||||
from: self.name(),
|
||||
// TODO: Fetch actual stylesheets from the script thread.
|
||||
style_sheets: vec![],
|
||||
};
|
||||
request.reply_final(&msg)?
|
||||
|
||||
@@ -84,7 +84,7 @@ impl SessionContext {
|
||||
("network-event", true),
|
||||
("network-event-stacktrace", false),
|
||||
("reflow", true),
|
||||
("stylesheet", false),
|
||||
("stylesheet", true),
|
||||
("source", true),
|
||||
("thread-state", false),
|
||||
("server-sent-event", false),
|
||||
@@ -386,6 +386,17 @@ impl Actor for WatcherActor {
|
||||
);
|
||||
}
|
||||
},
|
||||
"stylesheet" => {
|
||||
// TODO: Fetch actual stylesheets from the script thread.
|
||||
// For now, send an empty array.
|
||||
let empty: Vec<serde_json::Value> = vec![];
|
||||
browsing_context_actor.resources_array(
|
||||
empty,
|
||||
resource.into(),
|
||||
ResourceArrayType::Available,
|
||||
&mut request,
|
||||
);
|
||||
},
|
||||
"network-event" => {},
|
||||
_ => warn!("resource {} not handled yet", resource),
|
||||
}
|
||||
|
||||
@@ -5,16 +5,29 @@
|
||||
use std::path::Path;
|
||||
use std::{env, fs};
|
||||
|
||||
use chrono::Local;
|
||||
use chrono::{TimeZone, Utc};
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-env-changed=SOURCE_DATE_EPOCH");
|
||||
// Parsing as suggested on <https://reproducible-builds.org/docs/source-date-epoch/>
|
||||
let now = match env::var("SOURCE_DATE_EPOCH") {
|
||||
Ok(val) => Utc
|
||||
.timestamp_opt(
|
||||
val.parse::<i64>()
|
||||
.expect("SOURCE_DATE_EPOCH should be a valid integer"),
|
||||
0,
|
||||
)
|
||||
.unwrap(),
|
||||
Err(_) => Utc::now(),
|
||||
};
|
||||
|
||||
let build_id = now.format("%Y%m%d%H%M%S").to_string();
|
||||
|
||||
let path = Path::new(&env::var_os("OUT_DIR").unwrap()).join("build_id.rs");
|
||||
fs::write(
|
||||
path,
|
||||
format!(
|
||||
"const BUILD_ID: &str = \"{}\";",
|
||||
Local::now().format("%Y%m%d%H%M%S")
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
// The build ID is used in Firefox devtools, `getDateFromBuildID` function:
|
||||
// <https://searchfox.org/firefox-main/rev/be31b3948198286e39a9855e414823cb17b6e94c/devtools/client/shared/remote-debugging/version-checker.js#21-24>
|
||||
// The expected format is: yyyyMMddHHmmss.
|
||||
// The date is than later used to check devtools compatibility:
|
||||
// <https://searchfox.org/firefox-main/rev/be31b3948198286e39a9855e414823cb17b6e94c/devtools/client/shared/remote-debugging/version-checker.js#133-139>
|
||||
fs::write(path, format!("const BUILD_ID: &str = \"{build_id}\";")).unwrap();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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::sync::LazyLock;
|
||||
|
||||
use accesskit::Role;
|
||||
use layout_api::LayoutNode;
|
||||
use layout_api::{LayoutElement, LayoutNode, LayoutNodeType};
|
||||
use log::trace;
|
||||
use rustc_hash::FxHashMap;
|
||||
use script::layout_dom::ServoLayoutNode;
|
||||
use servo_base::Epoch;
|
||||
use style::dom::{NodeInfo, OpaqueNode};
|
||||
use style::dom::OpaqueNode;
|
||||
use web_atoms::{LocalName, local_name};
|
||||
|
||||
use crate::ArcRefCell;
|
||||
|
||||
@@ -35,47 +37,28 @@ impl AccessibilityTree {
|
||||
const ROOT_NODE_ID: accesskit::NodeId = accesskit::NodeId(0);
|
||||
|
||||
pub(super) fn new(tree_id: accesskit::TreeId, epoch: Epoch) -> Self {
|
||||
// The root node doesn't correspond to a DOM node, but contains the root DOM node.
|
||||
let mut root_node = AccessibilityNode::new(AccessibilityTree::ROOT_NODE_ID);
|
||||
root_node
|
||||
.accesskit_node
|
||||
.set_role(accesskit::Role::RootWebArea);
|
||||
root_node
|
||||
.accesskit_node
|
||||
.add_action(accesskit::Action::Focus);
|
||||
|
||||
let mut tree = Self {
|
||||
nodes: Default::default(),
|
||||
accesskit_tree: accesskit::Tree::new(root_node.id),
|
||||
Self {
|
||||
nodes: FxHashMap::default(),
|
||||
accesskit_tree: accesskit::Tree::new(AccessibilityTree::ROOT_NODE_ID),
|
||||
tree_id,
|
||||
epoch,
|
||||
};
|
||||
tree.nodes.insert(root_node.id, ArcRefCell::new(root_node));
|
||||
|
||||
tree
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn update_tree(
|
||||
&mut self,
|
||||
root_dom_node: &ServoLayoutNode<'_>,
|
||||
) -> Option<accesskit::TreeUpdate> {
|
||||
let root_node = self.get_or_create_node(root_dom_node);
|
||||
self.accesskit_tree.root = root_node.borrow().id;
|
||||
|
||||
let mut tree_update = AccessibilityUpdate::new(self.accesskit_tree.clone(), self.tree_id);
|
||||
let any_node_updated = self.update_node_and_children(root_dom_node, &mut tree_update);
|
||||
|
||||
{
|
||||
let root_dom_node_id = Self::to_accesskit_id(&root_dom_node.opaque());
|
||||
let root_node = self
|
||||
.nodes
|
||||
.get_mut(&AccessibilityTree::ROOT_NODE_ID)
|
||||
.expect("Guaranteed by Self::new");
|
||||
let mut root_node = root_node.borrow_mut();
|
||||
root_node
|
||||
.accesskit_node
|
||||
.set_children(vec![root_dom_node_id]);
|
||||
|
||||
tree_update.add(&root_node);
|
||||
if !any_node_updated {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.update_node_and_children(root_dom_node, &mut tree_update);
|
||||
Some(tree_update.finalize())
|
||||
}
|
||||
|
||||
@@ -83,9 +66,26 @@ impl AccessibilityTree {
|
||||
&mut self,
|
||||
dom_node: &ServoLayoutNode<'_>,
|
||||
tree_update: &mut AccessibilityUpdate,
|
||||
) {
|
||||
// TODO: read accessibility damage from dom_node (right now, assume damage is complete)
|
||||
) -> bool {
|
||||
// TODO: read accessibility damage (right now, assume damage is complete)
|
||||
let (node_id, updated) = self.update_node(dom_node);
|
||||
|
||||
let mut any_descendant_updated = false;
|
||||
for dom_child in dom_node.flat_tree_children() {
|
||||
// TODO: We actually need to propagate damage within the accessibility tree, rather than
|
||||
// assuming it matches the DOM tree, but this will do for now.
|
||||
any_descendant_updated |= self.update_node_and_children(&dom_child, tree_update);
|
||||
}
|
||||
|
||||
if updated {
|
||||
let node = self.assert_node_by_id(node_id);
|
||||
tree_update.add(&node.borrow());
|
||||
}
|
||||
|
||||
updated || any_descendant_updated
|
||||
}
|
||||
|
||||
fn update_node(&mut self, dom_node: &ServoLayoutNode<'_>) -> (accesskit::NodeId, bool) {
|
||||
let node = self.get_or_create_node(dom_node);
|
||||
let mut node = node.borrow_mut();
|
||||
let accesskit_node = &mut node.accesskit_node;
|
||||
@@ -99,21 +99,26 @@ impl AccessibilityTree {
|
||||
accesskit_node.set_children(new_children);
|
||||
}
|
||||
|
||||
if dom_node.is_text_node() {
|
||||
if let Some(dom_element) = dom_node.as_element() {
|
||||
accesskit_node.set_role(Role::GenericContainer);
|
||||
let local_name = dom_element.local_name().to_ascii_lowercase();
|
||||
accesskit_node.set_html_tag(&*local_name);
|
||||
let role = HTML_ELEMENT_ROLE_MAPPINGS
|
||||
.get(&local_name)
|
||||
.unwrap_or(&Role::GenericContainer);
|
||||
accesskit_node.set_role(*role);
|
||||
} else if dom_node.type_id() == Some(LayoutNodeType::Text) {
|
||||
accesskit_node.set_role(Role::TextRun);
|
||||
let text_content = dom_node.text_content();
|
||||
trace!("node text content = {text_content:?}");
|
||||
// FIXME: this should take into account editing selection units (grapheme clusters?)
|
||||
accesskit_node.set_value(&*text_content);
|
||||
} else if dom_node.as_element().is_some() {
|
||||
} else {
|
||||
accesskit_node.set_role(Role::GenericContainer);
|
||||
}
|
||||
|
||||
tree_update.add(&node);
|
||||
|
||||
for dom_child in dom_node.flat_tree_children() {
|
||||
self.update_node_and_children(&dom_child, tree_update);
|
||||
}
|
||||
// TODO: only return true if any update actually happened
|
||||
(node.id, true)
|
||||
}
|
||||
|
||||
fn get_or_create_node(
|
||||
@@ -129,6 +134,16 @@ impl AccessibilityTree {
|
||||
node.clone()
|
||||
}
|
||||
|
||||
fn assert_node_by_id(&self, id: accesskit::NodeId) -> ArcRefCell<AccessibilityNode> {
|
||||
let Some(node) = self.nodes.get(&id) else {
|
||||
panic!("Stale node ID found: {id:?}");
|
||||
};
|
||||
node.clone()
|
||||
}
|
||||
|
||||
// TODO: Using the OpaqueNode as the identifier for the accessibility node will inevitably
|
||||
// create issues as OpaqueNodes will be reused when DOM nodes are destroyed. Instead, we should
|
||||
// make a monotonically increasing ID, and have some other way to retrieve it based on DOM node.
|
||||
fn to_accesskit_id(opaque: &OpaqueNode) -> accesskit::NodeId {
|
||||
accesskit::NodeId(opaque.0 as u64)
|
||||
}
|
||||
@@ -229,3 +244,25 @@ fn test_accessibility_update_add_some_nodes_twice() {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
static HTML_ELEMENT_ROLE_MAPPINGS: LazyLock<FxHashMap<LocalName, Role>> = LazyLock::new(|| {
|
||||
[
|
||||
(local_name!("article"), Role::Article),
|
||||
(local_name!("aside"), Role::Complementary),
|
||||
(local_name!("body"), Role::RootWebArea),
|
||||
(local_name!("footer"), Role::ContentInfo),
|
||||
(local_name!("h1"), Role::Heading),
|
||||
(local_name!("h2"), Role::Heading),
|
||||
(local_name!("h3"), Role::Heading),
|
||||
(local_name!("h4"), Role::Heading),
|
||||
(local_name!("h5"), Role::Heading),
|
||||
(local_name!("h6"), Role::Heading),
|
||||
(local_name!("header"), Role::Banner),
|
||||
(local_name!("hr"), Role::Splitter),
|
||||
(local_name!("main"), Role::Main),
|
||||
(local_name!("nav"), Role::Navigation),
|
||||
(local_name!("p"), Role::Paragraph),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
});
|
||||
|
||||
@@ -156,30 +156,34 @@ impl DebuggerGlobalScope {
|
||||
|
||||
pub(crate) fn fire_add_debuggee(
|
||||
&self,
|
||||
can_gc: CanGc,
|
||||
cx: &mut JSContext,
|
||||
debuggee_global: &GlobalScope,
|
||||
debuggee_pipeline_id: PipelineId,
|
||||
debuggee_worker_id: Option<WorkerId>,
|
||||
) {
|
||||
let _realm = enter_realm(self);
|
||||
let debuggee_pipeline_id =
|
||||
crate::dom::pipelineid::PipelineId::new(self.upcast(), debuggee_pipeline_id, can_gc);
|
||||
let mut realm = enter_auto_realm(cx, self);
|
||||
let cx = &mut realm;
|
||||
let debuggee_pipeline_id = crate::dom::pipelineid::PipelineId::new(
|
||||
self.upcast(),
|
||||
debuggee_pipeline_id,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
let event = DomRoot::upcast::<Event>(DebuggerAddDebuggeeEvent::new(
|
||||
self.upcast(),
|
||||
debuggee_global,
|
||||
&debuggee_pipeline_id,
|
||||
debuggee_worker_id.map(|id| id.to_string().into()),
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
));
|
||||
assert!(
|
||||
event.fire(self.upcast(), can_gc),
|
||||
event.fire(self.upcast(), CanGc::from_cx(cx)),
|
||||
"Guaranteed by DebuggerAddDebuggeeEvent::new"
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn fire_eval(
|
||||
&self,
|
||||
can_gc: CanGc,
|
||||
cx: &mut JSContext,
|
||||
code: DOMString,
|
||||
debuggee_pipeline_id: PipelineId,
|
||||
debuggee_worker_id: Option<WorkerId>,
|
||||
@@ -191,26 +195,30 @@ impl DebuggerGlobalScope {
|
||||
.replace(Some(result_sender))
|
||||
.is_none()
|
||||
);
|
||||
let _realm = enter_realm(self);
|
||||
let debuggee_pipeline_id =
|
||||
crate::dom::pipelineid::PipelineId::new(self.upcast(), debuggee_pipeline_id, can_gc);
|
||||
let mut realm = enter_auto_realm(cx, self);
|
||||
let cx = &mut realm;
|
||||
let debuggee_pipeline_id = crate::dom::pipelineid::PipelineId::new(
|
||||
self.upcast(),
|
||||
debuggee_pipeline_id,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
let event = DomRoot::upcast::<Event>(DebuggerEvalEvent::new(
|
||||
self.upcast(),
|
||||
code,
|
||||
&debuggee_pipeline_id,
|
||||
debuggee_worker_id.map(|id| id.to_string().into()),
|
||||
frame_actor_id.map(|id| id.into()),
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
));
|
||||
assert!(
|
||||
event.fire(self.upcast(), can_gc),
|
||||
event.fire(self.upcast(), CanGc::from_cx(cx)),
|
||||
"Guaranteed by DebuggerEvalEvent::new"
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn fire_get_possible_breakpoints(
|
||||
&self,
|
||||
can_gc: CanGc,
|
||||
cx: &mut JSContext,
|
||||
spidermonkey_id: u32,
|
||||
result_sender: GenericSender<Vec<devtools_traits::RecommendedBreakpointLocation>>,
|
||||
) {
|
||||
@@ -223,17 +231,17 @@ impl DebuggerGlobalScope {
|
||||
let event = DomRoot::upcast::<Event>(DebuggerGetPossibleBreakpointsEvent::new(
|
||||
self.upcast(),
|
||||
spidermonkey_id,
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
));
|
||||
assert!(
|
||||
event.fire(self.upcast(), can_gc),
|
||||
event.fire(self.upcast(), CanGc::from_cx(cx)),
|
||||
"Guaranteed by DebuggerGetPossibleBreakpointsEvent::new"
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn fire_set_breakpoint(
|
||||
&self,
|
||||
can_gc: CanGc,
|
||||
cx: &mut JSContext,
|
||||
spidermonkey_id: u32,
|
||||
script_id: u32,
|
||||
offset: u32,
|
||||
@@ -243,10 +251,10 @@ impl DebuggerGlobalScope {
|
||||
spidermonkey_id,
|
||||
script_id,
|
||||
offset,
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
));
|
||||
assert!(
|
||||
event.fire(self.upcast(), can_gc),
|
||||
event.fire(self.upcast(), CanGc::from_cx(cx)),
|
||||
"Guaranteed by DebuggerSetBreakpointEvent::new"
|
||||
);
|
||||
}
|
||||
@@ -290,9 +298,9 @@ impl DebuggerGlobalScope {
|
||||
|
||||
pub(crate) fn fire_get_environment(
|
||||
&self,
|
||||
cx: &mut JSContext,
|
||||
frame_actor_id: String,
|
||||
result_sender: GenericSender<String>,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
assert!(
|
||||
self.get_environment_result_sender
|
||||
@@ -303,35 +311,35 @@ impl DebuggerGlobalScope {
|
||||
let event = DomRoot::upcast::<Event>(DebuggerGetEnvironmentEvent::new(
|
||||
self.upcast(),
|
||||
frame_actor_id.into(),
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
));
|
||||
assert!(
|
||||
event.fire(self.upcast(), can_gc),
|
||||
event.fire(self.upcast(), CanGc::from_cx(cx)),
|
||||
"Guaranteed by DebuggerGetEnvironmentEvent::new"
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn fire_resume(
|
||||
&self,
|
||||
cx: &mut JSContext,
|
||||
resume_limit_type: Option<String>,
|
||||
frame_actor_id: Option<String>,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
let event = DomRoot::upcast::<Event>(DebuggerResumeEvent::new(
|
||||
self.upcast(),
|
||||
resume_limit_type.map(DOMString::from),
|
||||
frame_actor_id.map(DOMString::from),
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
));
|
||||
assert!(
|
||||
event.fire(self.upcast(), can_gc),
|
||||
event.fire(self.upcast(), CanGc::from_cx(cx)),
|
||||
"Guaranteed by DebuggerResumeEvent::new"
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn fire_clear_breakpoint(
|
||||
&self,
|
||||
can_gc: CanGc,
|
||||
cx: &mut JSContext,
|
||||
spidermonkey_id: u32,
|
||||
script_id: u32,
|
||||
offset: u32,
|
||||
@@ -341,10 +349,10 @@ impl DebuggerGlobalScope {
|
||||
spidermonkey_id,
|
||||
script_id,
|
||||
offset,
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
));
|
||||
assert!(
|
||||
event.fire(self.upcast(), can_gc),
|
||||
event.fire(self.upcast(), CanGc::from_cx(cx)),
|
||||
"Guaranteed by DebuggerClearBreakpointEvent::new"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -710,14 +710,16 @@ impl Document {
|
||||
self.root_removal_noted.set(false);
|
||||
|
||||
if let Some(dirty_root) = self.dirty_root.get() {
|
||||
// There was an existing dirty root so we mark its
|
||||
// ancestors as dirty until the document element.
|
||||
for ancestor in dirty_root
|
||||
.upcast::<Node>()
|
||||
.inclusive_ancestors_in_flat_tree()
|
||||
{
|
||||
if ancestor.is::<Element>() {
|
||||
ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
|
||||
if dirty_root.is_connected() {
|
||||
// There was an existing dirty root so we mark its
|
||||
// ancestors as dirty until the document element.
|
||||
for ancestor in dirty_root
|
||||
.upcast::<Node>()
|
||||
.inclusive_ancestors_in_flat_tree()
|
||||
{
|
||||
if ancestor.is::<Element>() {
|
||||
ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3720,19 +3722,17 @@ impl Document {
|
||||
.set(self.script_and_layout_blockers.get() + 1);
|
||||
}
|
||||
|
||||
#[expect(unsafe_code)]
|
||||
/// Terminate the period in which JS or layout is disallowed from running.
|
||||
/// If no further blockers remain, any delayed tasks in the queue will
|
||||
/// be executed in queue order until the queue is empty.
|
||||
pub(crate) fn remove_script_and_layout_blocker(&self) {
|
||||
pub(crate) fn remove_script_and_layout_blocker(&self, cx: &mut js::context::JSContext) {
|
||||
assert!(self.script_and_layout_blockers.get() > 0);
|
||||
self.script_and_layout_blockers
|
||||
.set(self.script_and_layout_blockers.get() - 1);
|
||||
while self.script_and_layout_blockers.get() == 0 && !self.delayed_tasks.borrow().is_empty()
|
||||
{
|
||||
let task = self.delayed_tasks.borrow_mut().remove(0);
|
||||
let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
|
||||
task.run_box(&mut cx);
|
||||
task.run_box(cx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,14 +15,14 @@ use crate::dom::bindings::codegen::Bindings::TextDecoderBinding;
|
||||
use crate::dom::bindings::codegen::Bindings::TextDecoderStreamBinding::TextDecoderStreamMethods;
|
||||
use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_cx};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::encoding::textdecodercommon::TextDecoderCommon;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::stream::transformstreamdefaultcontroller::TransformerType;
|
||||
use crate::dom::types::{TransformStream, TransformStreamDefaultController};
|
||||
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
/// <https://encoding.spec.whatwg.org/#decode-and-enqueue-a-chunk>
|
||||
#[expect(unsafe_code)]
|
||||
@@ -122,25 +122,24 @@ impl TextDecoderStream {
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
cx: SafeJSContext,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
encoding: &'static Encoding,
|
||||
fatal: bool,
|
||||
ignoreBOM: bool,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<DomRoot<Self>> {
|
||||
let decoder = Rc::new(TextDecoderCommon::new_inherited(encoding, fatal, ignoreBOM));
|
||||
let transformer_type = TransformerType::Decoder(decoder.clone());
|
||||
|
||||
let transform_stream = TransformStream::new_with_proto(global, None, can_gc);
|
||||
transform_stream.set_up(cx, global, transformer_type, can_gc)?;
|
||||
let transform_stream = TransformStream::new_with_proto(global, None, CanGc::from_cx(cx));
|
||||
transform_stream.set_up(cx, global, transformer_type)?;
|
||||
|
||||
Ok(reflect_dom_object_with_proto(
|
||||
Ok(reflect_dom_object_with_proto_and_cx(
|
||||
Box::new(TextDecoderStream::new_inherited(decoder, &transform_stream)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
cx,
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -148,9 +147,9 @@ impl TextDecoderStream {
|
||||
impl TextDecoderStreamMethods<crate::DomTypeHolder> for TextDecoderStream {
|
||||
/// <https://encoding.spec.whatwg.org/#dom-textdecoderstream>
|
||||
fn Constructor(
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
can_gc: CanGc,
|
||||
label: DOMString,
|
||||
options: &TextDecoderBinding::TextDecoderOptions,
|
||||
) -> Fallible<DomRoot<TextDecoderStream>> {
|
||||
@@ -164,13 +163,12 @@ impl TextDecoderStreamMethods<crate::DomTypeHolder> for TextDecoderStream {
|
||||
};
|
||||
|
||||
Self::new_with_proto(
|
||||
GlobalScope::get_cx(),
|
||||
cx,
|
||||
global,
|
||||
proto,
|
||||
encoding,
|
||||
options.fatal,
|
||||
options.ignoreBOM,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,13 +23,14 @@ use script_bindings::conversions::SafeToJSValConvertible;
|
||||
use crate::dom::bindings::buffer_source::create_buffer_source;
|
||||
use crate::dom::bindings::codegen::Bindings::TextEncoderStreamBinding::TextEncoderStreamMethods;
|
||||
use crate::dom::bindings::error::{Error, Fallible, throw_dom_exception};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_cx};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::stream::readablestream::ReadableStream;
|
||||
use crate::dom::stream::transformstreamdefaultcontroller::TransformerType;
|
||||
use crate::dom::stream::writablestream::WritableStream;
|
||||
use crate::dom::types::{GlobalScope, TransformStream, TransformStreamDefaultController};
|
||||
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
||||
use crate::{DomTypeHolder, DomTypes};
|
||||
|
||||
/// String converted from an input JS Value
|
||||
enum ConvertedInput<'a> {
|
||||
@@ -341,10 +342,9 @@ impl TextEncoderStream {
|
||||
|
||||
/// <https://encoding.spec.whatwg.org/#dom-textencoderstream>
|
||||
fn new_with_proto(
|
||||
cx: SafeJSContext,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<DomRoot<TextEncoderStream>> {
|
||||
// Step 1. Set this’s encoder to an instance of the UTF-8 encoder.
|
||||
let encoder = Encoder::default();
|
||||
@@ -356,29 +356,29 @@ impl TextEncoderStream {
|
||||
let transformer_type = TransformerType::Encoder(encoder);
|
||||
|
||||
// Step 4. Let transformStream be a new TransformStream.
|
||||
let transform = TransformStream::new_with_proto(global, None, can_gc);
|
||||
let transform = TransformStream::new_with_proto(global, None, CanGc::from_cx(cx));
|
||||
// Step 5. Set up transformStream with transformAlgorithm set to transformAlgorithm
|
||||
// and flushAlgorithm set to flushAlgorithm.
|
||||
transform.set_up(cx, global, transformer_type, can_gc)?;
|
||||
transform.set_up(cx, global, transformer_type)?;
|
||||
|
||||
// Step 6. Set this’s transform to transformStream.
|
||||
Ok(reflect_dom_object_with_proto(
|
||||
Ok(reflect_dom_object_with_proto_and_cx(
|
||||
Box::new(TextEncoderStream::new_inherited(&transform)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
cx,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl TextEncoderStreamMethods<DomTypeHolder> for TextEncoderStream {
|
||||
impl TextEncoderStreamMethods<crate::DomTypeHolder> for TextEncoderStream {
|
||||
/// <https://encoding.spec.whatwg.org/#dom-textencoderstream>
|
||||
fn Constructor(
|
||||
global: &<DomTypeHolder as DomTypes>::GlobalScope,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<DomRoot<<DomTypeHolder as DomTypes>::TextEncoderStream>> {
|
||||
TextEncoderStream::new_with_proto(GlobalScope::get_cx(), global, proto, can_gc)
|
||||
) -> Fallible<DomRoot<TextEncoderStream>> {
|
||||
TextEncoderStream::new_with_proto(cx, global, proto)
|
||||
}
|
||||
|
||||
/// <https://encoding.spec.whatwg.org/#dom-textencoder-encoding>
|
||||
@@ -388,12 +388,12 @@ impl TextEncoderStreamMethods<DomTypeHolder> for TextEncoderStream {
|
||||
}
|
||||
|
||||
/// <https://streams.spec.whatwg.org/#dom-generictransformstream-readable>
|
||||
fn Readable(&self) -> DomRoot<<DomTypeHolder as DomTypes>::ReadableStream> {
|
||||
fn Readable(&self) -> DomRoot<ReadableStream> {
|
||||
self.transform.get_readable()
|
||||
}
|
||||
|
||||
/// <https://streams.spec.whatwg.org/#dom-generictransformstream-writable>
|
||||
fn Writable(&self) -> DomRoot<<DomTypeHolder as DomTypes>::WritableStream> {
|
||||
fn Writable(&self) -> DomRoot<WritableStream> {
|
||||
self.transform.get_writable()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,15 @@
|
||||
* 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::cell::Cell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::{GamepadSupportedHapticEffects, GamepadUpdateType};
|
||||
use js::rust::MutableHandleValue;
|
||||
use js::typedarray::{Float64, HeapFloat64Array};
|
||||
use script_bindings::trace::RootedTraceableBox;
|
||||
|
||||
use super::gamepadbutton::GamepadButton;
|
||||
use super::gamepadhapticactuator::GamepadHapticActuator;
|
||||
use super::gamepadpose::GamepadPose;
|
||||
use crate::dom::bindings::buffer_source::HeapBufferSource;
|
||||
use crate::dom::bindings::codegen::Bindings::GamepadBinding::{GamepadHand, GamepadMethods};
|
||||
use crate::dom::bindings::frozenarray::CachedFrozenArray;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
@@ -24,7 +21,6 @@ use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::gamepadevent::{GamepadEvent, GamepadEventType};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::{CanGc, JSContext};
|
||||
|
||||
@@ -45,10 +41,11 @@ pub(crate) struct Gamepad {
|
||||
timestamp: Cell<f64>,
|
||||
mapping_type: String,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
axes: HeapBufferSource<Float64>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
frozen_buttons: CachedFrozenArray,
|
||||
buttons: Vec<Dom<GamepadButton>>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
frozen_axes: CachedFrozenArray,
|
||||
axes: RefCell<Vec<f64>>,
|
||||
pose: Option<Dom<GamepadPose>>,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webvr"]
|
||||
hand: GamepadHand,
|
||||
@@ -82,12 +79,13 @@ impl Gamepad {
|
||||
connected: Cell::new(connected),
|
||||
timestamp: Cell::new(timestamp),
|
||||
mapping_type,
|
||||
axes: HeapBufferSource::default(),
|
||||
frozen_buttons: CachedFrozenArray::new(),
|
||||
buttons: buttons
|
||||
.iter()
|
||||
.map(|button| Dom::from_ref(*button))
|
||||
.collect(),
|
||||
frozen_axes: CachedFrozenArray::new(),
|
||||
axes: RefCell::new(Vec::new()),
|
||||
pose: pose.map(Dom::from_ref),
|
||||
hand,
|
||||
axis_bounds,
|
||||
@@ -137,7 +135,7 @@ impl Gamepad {
|
||||
window,
|
||||
can_gc,
|
||||
);
|
||||
gamepad.init_axes(can_gc);
|
||||
gamepad.init_axes();
|
||||
gamepad
|
||||
}
|
||||
}
|
||||
@@ -169,10 +167,9 @@ impl GamepadMethods<crate::DomTypeHolder> for Gamepad {
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/gamepad/#dom-gamepad-axes>
|
||||
fn Axes(&self, _cx: JSContext) -> RootedTraceableBox<HeapFloat64Array> {
|
||||
self.axes
|
||||
.get_typed_array()
|
||||
.expect("Failed to get gamepad axes.")
|
||||
fn Axes(&self, cx: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
|
||||
self.frozen_axes
|
||||
.get_or_init(|| self.axes.borrow().clone(), cx, retval, can_gc);
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/gamepad/#dom-gamepad-buttons>
|
||||
@@ -275,19 +272,15 @@ impl Gamepad {
|
||||
|
||||
/// Initialize the number of axes in the "standard" gamepad mapping.
|
||||
/// <https://www.w3.org/TR/gamepad/#dfn-initializing-axes>
|
||||
fn init_axes(&self, can_gc: CanGc) {
|
||||
let initial_axes: Vec<f64> = vec![
|
||||
fn init_axes(&self) {
|
||||
*self.axes.borrow_mut() = vec![
|
||||
0., // Horizontal axis for left stick (negative left/positive right)
|
||||
0., // Vertical axis for left stick (negative up/positive down)
|
||||
0., // Horizontal axis for right stick (negative left/positive right)
|
||||
0., // Vertical axis for right stick (negative up/positive down)
|
||||
];
|
||||
self.axes
|
||||
.set_data(GlobalScope::get_cx(), &initial_axes, can_gc)
|
||||
.expect("Failed to set axes data on gamepad.")
|
||||
}
|
||||
|
||||
#[expect(unsafe_code)]
|
||||
/// <https://www.w3.org/TR/gamepad/#dfn-map-and-normalize-axes>
|
||||
pub(crate) fn map_and_normalize_axes(&self, axis_index: usize, value: f64) {
|
||||
// Let normalizedValue be 2 (logicalValue − logicalMinimum) / (logicalMaximum − logicalMinimum) − 1.
|
||||
@@ -296,13 +289,8 @@ impl Gamepad {
|
||||
if denominator != 0.0 && denominator.is_finite() {
|
||||
let normalized_value: f64 = 2.0 * numerator / denominator - 1.0;
|
||||
if normalized_value.is_finite() {
|
||||
let mut axis_vec = self
|
||||
.axes
|
||||
.typed_array_to_option()
|
||||
.expect("Axes have not been initialized!");
|
||||
unsafe {
|
||||
axis_vec.as_mut_slice()[axis_index] = normalized_value;
|
||||
}
|
||||
self.axes.borrow_mut()[axis_index] = normalized_value;
|
||||
self.frozen_axes.clear();
|
||||
} else {
|
||||
warn!("Axis value is not finite!");
|
||||
}
|
||||
|
||||
@@ -2881,8 +2881,8 @@ impl Node {
|
||||
}
|
||||
}
|
||||
|
||||
old_doc.remove_script_and_layout_blocker();
|
||||
document.remove_script_and_layout_blocker();
|
||||
old_doc.remove_script_and_layout_blocker(cx);
|
||||
document.remove_script_and_layout_blocker(cx);
|
||||
}
|
||||
|
||||
/// <https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity>
|
||||
@@ -3251,8 +3251,8 @@ impl Node {
|
||||
}),
|
||||
);
|
||||
|
||||
parent_document.remove_script_and_layout_blocker();
|
||||
from_document.remove_script_and_layout_blocker();
|
||||
parent_document.remove_script_and_layout_blocker(cx);
|
||||
from_document.remove_script_and_layout_blocker(cx);
|
||||
}
|
||||
|
||||
/// <https://dom.spec.whatwg.org/#concept-node-replace-all>
|
||||
@@ -3303,7 +3303,7 @@ impl Node {
|
||||
});
|
||||
MutationObserver::queue_a_mutation_record(parent, mutation);
|
||||
}
|
||||
parent.owner_doc().remove_script_and_layout_blocker();
|
||||
parent.owner_doc().remove_script_and_layout_blocker(cx);
|
||||
}
|
||||
|
||||
/// <https://dom.spec.whatwg.org/multipage/#string-replace-all>
|
||||
@@ -3417,7 +3417,7 @@ impl Node {
|
||||
});
|
||||
MutationObserver::queue_a_mutation_record(parent, mutation);
|
||||
}
|
||||
parent.owner_doc().remove_script_and_layout_blocker();
|
||||
parent.owner_doc().remove_script_and_layout_blocker(cx);
|
||||
}
|
||||
|
||||
/// <https://dom.spec.whatwg.org/#live-range-pre-remove-steps>
|
||||
|
||||
@@ -19,9 +19,10 @@ use crate::dom::bindings::codegen::Bindings::SanitizerBinding::{
|
||||
use crate::dom::bindings::codegen::UnionTypes::SanitizerConfigOrSanitizerPresets;
|
||||
use crate::dom::bindings::domname::is_valid_attribute_local_name;
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_cx};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto_and_cx};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::types::Console;
|
||||
use crate::dom::window::Window;
|
||||
|
||||
#[dom_struct]
|
||||
@@ -190,12 +191,291 @@ impl SanitizerMethods<crate::DomTypeHolder> for Sanitizer {
|
||||
// Step 10. Return config.
|
||||
(*config).clone()
|
||||
}
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#dom-sanitizer-allowelement>
|
||||
fn AllowElement(&self, element: SanitizerElementWithAttributes) -> bool {
|
||||
// Step 1. Let configuration be this’s configuration.
|
||||
let mut configuration = self.configuration.borrow_mut();
|
||||
|
||||
// Step 2. Assert: configuration is valid.
|
||||
assert!(configuration.is_valid());
|
||||
|
||||
// Step 3. Set element to the result of canonicalize a sanitizer element with attributes
|
||||
// with element.
|
||||
let mut element = element.canonicalize();
|
||||
|
||||
// Step 4. If configuration["elements"] exists:
|
||||
if configuration.elements.is_some() {
|
||||
// Step 4.1. Set modified to the result of remove element from
|
||||
// configuration["replaceWithChildrenElements"].
|
||||
let modified = if let Some(replace_with_children_elements) =
|
||||
&mut configuration.replaceWithChildrenElements
|
||||
{
|
||||
replace_with_children_elements.remove_item(&element)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Step 4.2. Comment: We need to make sure the per-element attributes do not overlap
|
||||
// with global attributes.
|
||||
|
||||
match &configuration.attributes {
|
||||
// Step 4.3. If configuration["attributes"] exists:
|
||||
Some(configuration_attributes) => {
|
||||
// Step 4.3.1. If element["attributes"] exists:
|
||||
if let Some(element_attributes) = element.attributes_mut() {
|
||||
// Step 4.3.1.1. Set element["attributes"] to remove duplicates from
|
||||
// element["attributes"].
|
||||
element_attributes.remove_duplicates();
|
||||
|
||||
// Step 4.3.1.2. Set element["attributes"] to the difference of
|
||||
// element["attributes"] and configuration["attributes"].
|
||||
element_attributes.difference(configuration_attributes);
|
||||
|
||||
// Step 4.3.1.3. If configuration["dataAttributes"] is true:
|
||||
if configuration.dataAttributes == Some(true) {
|
||||
// Step 4.3.1.3.1. Remove all items item from element["attributes"]
|
||||
// where item is a custom data attribute.
|
||||
element_attributes.retain(|attribute| {
|
||||
!is_custom_data_attribute(
|
||||
&attribute.name().str(),
|
||||
attribute
|
||||
.namespace()
|
||||
.map(|namespace| namespace.str())
|
||||
.as_deref(),
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4.3.2. If element["removeAttributes"] exists:
|
||||
if let Some(element_remove_attributes) = element.remove_attributes_mut() {
|
||||
// Step 4.3.2.1. set element["removeattributes"] to remove duplicates from
|
||||
// element["removeattributes"].
|
||||
element_remove_attributes.remove_duplicates();
|
||||
|
||||
// Step 4.3.2.2. set element["removeattributes"] to the intersection of
|
||||
// element["removeattributes"] and configuration["attributes"].
|
||||
element_remove_attributes.intersection(configuration_attributes);
|
||||
}
|
||||
},
|
||||
// Step 4.4. Otherwise:
|
||||
None => {
|
||||
// NOTE: To avoid borrowing `element` again at Step 4.4.1.2 and 4.4.1.3 after
|
||||
// borrowing `element` mutably at the beginning of Step 4.4.1, we clone
|
||||
// element["attributes"] first, and call `set_attributes` at the end of Step
|
||||
// 4.4.1 to put it back into `element`.
|
||||
|
||||
// Step 4.4.1. If element["attributes"] exists:
|
||||
if let Some(mut element_attributes) = element.attributes_mut().cloned() {
|
||||
// Step 4.4.1.1. Set element["attributes"] to remove duplicates from
|
||||
// element["attributes"].
|
||||
element_attributes.remove_duplicates();
|
||||
|
||||
// Step 4.4.1.2. Set element["attributes"] to the difference of
|
||||
// element["attributes"] and element["removeAttributes"] with default « ».
|
||||
element_attributes
|
||||
.difference(element.remove_attributes().unwrap_or_default());
|
||||
|
||||
// Step 4.4.1.3. Remove element["removeAttributes"].
|
||||
element.set_remove_attributes(None);
|
||||
|
||||
// Step 4.4.1.4. Set element["attributes"] to the difference of
|
||||
// element["attributes"] and configuration["removeAttributes"].
|
||||
element_attributes.difference(
|
||||
configuration
|
||||
.removeAttributes
|
||||
.as_deref()
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
|
||||
element.set_attributes(Some(element_attributes));
|
||||
}
|
||||
|
||||
// Step 4.4.2. If element["removeAttributes"] exists:
|
||||
if let Some(mut element_remove_attributes) = element.remove_attributes_mut() {
|
||||
// Step 4.4.2.1. Set element["removeAttributes"] to remove duplicates from
|
||||
// element["removeAttributes"].
|
||||
element_remove_attributes = element_remove_attributes.remove_duplicates();
|
||||
|
||||
// Step 4.4.2.2. Set element["removeAttributes"] to the difference of
|
||||
// element["removeAttributes"] and configuration["removeAttributes"].
|
||||
element_remove_attributes.difference(
|
||||
configuration
|
||||
.removeAttributes
|
||||
.as_deref()
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Step 4.5. If configuration["elements"] does not contain element:
|
||||
let configuration_elements = configuration
|
||||
.elements
|
||||
.as_mut()
|
||||
.expect("Guaranteed by Step 4");
|
||||
if !configuration_elements.contains_item(&element) {
|
||||
// Step 4.5.1. Comment: This is the case with a global allow-list that does not yet
|
||||
// contain element.
|
||||
|
||||
// Step 4.5.2. Append element to configuration["elements"].
|
||||
configuration_elements.push(element.clone());
|
||||
|
||||
// Step 4.5.3. Return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 4.6. Comment: This is the case with a global allow-list that already contains
|
||||
// element.
|
||||
|
||||
// Step 4.7. Let current element be the item in configuration["elements"] where
|
||||
// item["name"] equals element["name"] and item["namespace"] equals
|
||||
// element["namespace"].
|
||||
let current_element = configuration_elements
|
||||
.iter()
|
||||
.find(|item| {
|
||||
item.name() == element.name() && item.namespace() == element.namespace()
|
||||
})
|
||||
.expect("Guaranteed by Step 4.5 and Step 4.5.2");
|
||||
|
||||
// Step 4.8. If element equals current element then return modified.
|
||||
if element == *current_element {
|
||||
return modified;
|
||||
}
|
||||
|
||||
// Step 4.9. Remove element from configuration["elements"].
|
||||
configuration_elements.remove_item(&element);
|
||||
|
||||
// Step 4.10. Append element to configuration["elements"]
|
||||
configuration_elements.push(element);
|
||||
|
||||
// Step 4.11. Return true.
|
||||
true
|
||||
}
|
||||
// Step 5. Otherwise:
|
||||
else {
|
||||
// Step 5.1. If element["attributes"] exists or element["removeAttributes"] with default
|
||||
// « » is not empty:
|
||||
if element.attributes().is_some() ||
|
||||
!element.remove_attributes().unwrap_or_default().is_empty()
|
||||
{
|
||||
// Step 5.1.1. The user agent may report a warning to the console that this
|
||||
// operation is not supported.
|
||||
Console::internal_warn(
|
||||
&self.global(),
|
||||
"Do not support adding an element with attributes to a sanitizer \
|
||||
whose configuration[\"elements\"] does not exist."
|
||||
.into(),
|
||||
);
|
||||
|
||||
// Step 5.1.2. Return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 5.2. Set modified to the result of remove element from
|
||||
// configuration["replaceWithChildrenElements"].
|
||||
let modified = if let Some(replace_with_children_elements) =
|
||||
&mut configuration.replaceWithChildrenElements
|
||||
{
|
||||
replace_with_children_elements.remove_item(&element)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Step 5.3. If configuration["removeElements"] does not contain element:
|
||||
if !configuration
|
||||
.removeElements
|
||||
.as_ref()
|
||||
.is_some_and(|configuration_remove_elements| {
|
||||
configuration_remove_elements.contains_item(&element)
|
||||
})
|
||||
{
|
||||
// Step 5.3.1. Comment: This is the case with a global remove-list that does not
|
||||
// contain element.
|
||||
|
||||
// Step 5.3.2. Return modified.
|
||||
return modified;
|
||||
}
|
||||
|
||||
// Step 5.4. Comment: This is the case with a global remove-list that contains element.
|
||||
|
||||
// Step 5.5. Remove element from configuration["removeElements"].
|
||||
if let Some(configuration_remove_elements) = &mut configuration.removeElements {
|
||||
configuration_remove_elements.remove_item(&element);
|
||||
}
|
||||
|
||||
// Step 5.6. Return true.
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#dom-sanitizer-removeelement>
|
||||
fn RemoveElement(&self, element: SanitizerElement) -> bool {
|
||||
// Remove an element with element and this’s configuration.
|
||||
self.configuration.borrow_mut().remove_element(element)
|
||||
}
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#dom-sanitizer-replaceelementwithchildren>
|
||||
fn ReplaceElementWithChildren(&self, element: SanitizerElement) -> bool {
|
||||
// Step 1. Let configuration be this’s configuration.
|
||||
let mut configuration = self.configuration.borrow_mut();
|
||||
|
||||
// Step 2. Assert: configuration is valid.
|
||||
assert!(configuration.is_valid());
|
||||
|
||||
// Step 3. Set element to the result of canonicalize a sanitizer element with element.
|
||||
let element = element.canonicalize();
|
||||
|
||||
// Step 4. If the built-in non-replaceable elements list contains element:
|
||||
if built_in_non_replaceable_elements_list().contains_item(&element) {
|
||||
// Step 4.1. Return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 5. If configuration["replaceWithChildrenElements"] contains element:
|
||||
if configuration
|
||||
.replaceWithChildrenElements
|
||||
.as_ref()
|
||||
.is_some_and(|configuration_replace_with_children_elements| {
|
||||
configuration_replace_with_children_elements.contains_item(&element)
|
||||
})
|
||||
{
|
||||
// Step 5.1. Return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 6. Remove element from configuration["removeElements"].
|
||||
if let Some(configuration_remove_elements) = &mut configuration.removeElements {
|
||||
configuration_remove_elements.remove_item(&element);
|
||||
}
|
||||
|
||||
// Step 7. Remove element from configuration["elements"] list.
|
||||
if let Some(configuration_elements) = &mut configuration.elements {
|
||||
configuration_elements.remove_item(&element);
|
||||
}
|
||||
|
||||
// Step 8. Add element to configuration["replaceWithChildrenElements"].
|
||||
if let Some(configuration_replace_with_children_elements) =
|
||||
&mut configuration.replaceWithChildrenElements
|
||||
{
|
||||
configuration_replace_with_children_elements.add_item(element);
|
||||
} else {
|
||||
configuration.replaceWithChildrenElements = Some(vec![element]);
|
||||
}
|
||||
|
||||
// Step 9. Return true.
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
trait SanitizerConfigAlgorithm {
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-valid>
|
||||
fn is_valid(&self) -> bool;
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizer-remove-an-element>
|
||||
fn remove_element(&mut self, element: SanitizerElement) -> bool;
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizer-canonicalize-the-configuration>
|
||||
fn canonicalize(&mut self, allow_comments_pis_and_data_attributes: bool);
|
||||
}
|
||||
@@ -310,7 +590,7 @@ impl SanitizerConfigAlgorithm for SanitizerConfig {
|
||||
for element in config_replace_with_children_elements {
|
||||
// Step 15.1.1. If the built-in non-replaceable elements list contains element, then
|
||||
// return false.
|
||||
if built_in_non_replaceable_elements_list().contains_name(element) {
|
||||
if built_in_non_replaceable_elements_list().contains_item(element) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -388,7 +668,7 @@ impl SanitizerConfigAlgorithm for SanitizerConfig {
|
||||
.remove_attributes()
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.all(|entry| config_attributes.contains_name(entry))
|
||||
.all(|entry| config_attributes.contains_item(entry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -502,6 +782,72 @@ impl SanitizerConfigAlgorithm for SanitizerConfig {
|
||||
true
|
||||
}
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizer-remove-an-element>
|
||||
fn remove_element(&mut self, element: SanitizerElement) -> bool {
|
||||
// Step 1. Assert: configuration is valid.
|
||||
assert!(self.is_valid());
|
||||
|
||||
// Step 2. Set element to the result of canonicalize a sanitizer element with element.
|
||||
let element = element.canonicalize();
|
||||
|
||||
// Step 3. Set modified to the result of remove element from
|
||||
// configuration["replaceWithChildrenElements"].
|
||||
let modified = if let Some(configuration_replace_with_children_elements) =
|
||||
&mut self.replaceWithChildrenElements
|
||||
{
|
||||
configuration_replace_with_children_elements.remove_item(&element)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Step 4. If configuration["elements"] exists:
|
||||
if let Some(configuration_elements) = &mut self.elements {
|
||||
// Step 4.1. If configuration["elements"] contains element:
|
||||
if configuration_elements.contains_item(&element) {
|
||||
// Step 4.1.1. Comment: We have a global allow list and it contains element.
|
||||
|
||||
// Step 4.1.2. Remove element from configuration["elements"].
|
||||
configuration_elements.remove_item(&element);
|
||||
|
||||
// Step 4.1.3. Return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 4.2. Comment: We have a global allow list and it does not contain element.
|
||||
|
||||
// Step 4.3. Return modified.
|
||||
modified
|
||||
}
|
||||
// Step 5. Otherwise:
|
||||
else {
|
||||
// Step 5.1. If configuration["removeElements"] contains element:
|
||||
if self
|
||||
.removeElements
|
||||
.as_mut()
|
||||
.is_some_and(|configuration_remove_elements| {
|
||||
configuration_remove_elements.contains_item(&element)
|
||||
})
|
||||
{
|
||||
// Step 5.1.1. Comment: We have a global remove list and it already contains element.
|
||||
|
||||
// Step 5.1.2. Return modified.
|
||||
return modified;
|
||||
}
|
||||
|
||||
// Step 5.2. Comment: We have a global remove list and it does not contain element.
|
||||
|
||||
// Step 5.3. Add element to configuration["removeElements"].
|
||||
if let Some(configuration_remove_elements) = &mut self.removeElements {
|
||||
configuration_remove_elements.add_item(element);
|
||||
} else {
|
||||
self.removeElements = Some(vec![element]);
|
||||
}
|
||||
|
||||
// Step 5.4. Return true.
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizer-canonicalize-the-configuration>
|
||||
fn canonicalize(&mut self, allow_comments_pis_and_data_attributes: bool) {
|
||||
// Step 1. If neither configuration["elements"] nor configuration["removeElements"] exist,
|
||||
@@ -803,7 +1149,7 @@ where
|
||||
T: NameMember + Canonicalization + Clone,
|
||||
{
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-contains>
|
||||
fn contains_name<S: NameMember>(&self, other: &S) -> bool;
|
||||
fn contains_item<S: NameMember>(&self, other: &S) -> bool;
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-has-duplicates>
|
||||
fn has_duplicates(&self) -> bool;
|
||||
@@ -821,7 +1167,7 @@ where
|
||||
T: NameMember + Canonicalization + Clone,
|
||||
{
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-contains>
|
||||
fn contains_name<S: NameMember>(&self, other: &S) -> bool {
|
||||
fn contains_item<S: NameMember>(&self, other: &S) -> bool {
|
||||
// A Sanitizer name list contains an item if there exists an entry of list that is an
|
||||
// ordered map, and where item["name"] equals entry["name"] and item["namespace"] equals
|
||||
// entry["namespace"].
|
||||
@@ -872,6 +1218,107 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Supporting algorithms on lists of elements and lists of attributes, from the specification.
|
||||
trait NameVec<T>
|
||||
where
|
||||
T: NameMember + Canonicalization + Clone,
|
||||
{
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-remove>
|
||||
fn remove_item<S: NameMember>(&mut self, item: &S) -> bool;
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-add>
|
||||
fn add_item(&mut self, name: T);
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-remove-duplicates>
|
||||
fn remove_duplicates(&mut self) -> &mut Self;
|
||||
|
||||
/// Set itself to the set intersection of itself and another list.
|
||||
///
|
||||
/// <https://infra.spec.whatwg.org/#set-intersection>
|
||||
fn intersection<S>(&mut self, others: &[S])
|
||||
where
|
||||
S: NameMember + Canonicalization + Clone;
|
||||
|
||||
/// <https://infra.spec.whatwg.org/#set-difference>
|
||||
fn difference(&mut self, others: &[T]);
|
||||
}
|
||||
|
||||
impl<T> NameVec<T> for Vec<T>
|
||||
where
|
||||
T: NameMember + Canonicalization + Clone,
|
||||
{
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-remove>
|
||||
fn remove_item<S: NameMember>(&mut self, item: &S) -> bool {
|
||||
// Step 1. Set removed to false.
|
||||
let mut removed = false;
|
||||
|
||||
// Step 2. For each entry of list:
|
||||
// Step 2.1. If item["name"] equals entry["name"] and item["namespace"] equals entry["namespace"]:
|
||||
// Step 2.1.1. Remove item entry from list.
|
||||
// Step 2.1.2. Set removed to true.
|
||||
self.retain(|entry| {
|
||||
let matched = item.name() == entry.name() && item.namespace() == entry.namespace();
|
||||
if matched {
|
||||
removed = true;
|
||||
}
|
||||
!matched
|
||||
});
|
||||
|
||||
// Step 3. Return removed.
|
||||
removed
|
||||
}
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-add>
|
||||
fn add_item(&mut self, name: T) {
|
||||
// Step 1. If list contains name, then return.
|
||||
if self.contains_item(&name) {
|
||||
return;
|
||||
};
|
||||
|
||||
// Step 2. Append name to list.
|
||||
self.push(name);
|
||||
}
|
||||
|
||||
/// <https://wicg.github.io/sanitizer-api/#sanitizerconfig-remove-duplicates>
|
||||
fn remove_duplicates(&mut self) -> &mut Self {
|
||||
// Step 1. Let result be « ».
|
||||
// Step 2. For each entry of list, add entry to result.
|
||||
// Step 3. Return result.
|
||||
self.sort_by(|item_a, item_b| item_a.compare(item_b));
|
||||
self.dedup_by_key(|item| (item.name().clone(), item.namespace().cloned()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set itself to the set intersection of itself and another list.
|
||||
///
|
||||
/// <https://infra.spec.whatwg.org/#set-intersection>
|
||||
fn intersection<S>(&mut self, others: &[S])
|
||||
where
|
||||
S: NameMember + Canonicalization + Clone,
|
||||
{
|
||||
// The intersection of ordered sets A and B, is the result of creating a new ordered set set
|
||||
// and, for each item of A, if B contains item, appending item to set.
|
||||
self.retain(|item| {
|
||||
others
|
||||
.iter()
|
||||
.any(|other| other.name() == item.name() && other.namespace() == item.namespace())
|
||||
})
|
||||
}
|
||||
|
||||
/// Set itself to the set difference of itself and another list.
|
||||
///
|
||||
/// <https://infra.spec.whatwg.org/#set-difference>
|
||||
fn difference(&mut self, others: &[T]) {
|
||||
// The difference of ordered sets A and B, is the result of creating a new ordered set set
|
||||
// and, for each item of A, if B does not contain item, appending item to set.
|
||||
self.retain(|item| {
|
||||
!others
|
||||
.iter()
|
||||
.any(|other| other.name() == item.name() && other.namespace() == item.namespace())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper functions for accessing the "name" and "namespace" members of
|
||||
/// [`SanitizerElementWithAttributes`], [`SanitizerElement`] and [`SanitizerAttribute`].
|
||||
trait NameMember: Sized {
|
||||
|
||||
@@ -24,7 +24,7 @@ use crate::dom::bindings::codegen::Bindings::CompressionStreamBinding::{
|
||||
use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
|
||||
use crate::dom::bindings::conversions::{SafeFromJSValConvertible, SafeToJSValConvertible};
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_cx};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::stream::transformstreamdefaultcontroller::TransformerType;
|
||||
use crate::dom::types::{
|
||||
@@ -63,17 +63,17 @@ impl CompressionStream {
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
transform: &TransformStream,
|
||||
format: CompressionFormat,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<CompressionStream> {
|
||||
reflect_dom_object_with_proto(
|
||||
reflect_dom_object_with_proto_and_cx(
|
||||
Box::new(CompressionStream::new_inherited(transform, format)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -81,9 +81,9 @@ impl CompressionStream {
|
||||
impl CompressionStreamMethods<crate::DomTypeHolder> for CompressionStream {
|
||||
/// <https://compression.spec.whatwg.org/#dom-compressionstream-compressionstream>
|
||||
fn Constructor(
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
can_gc: CanGc,
|
||||
format: CompressionFormat,
|
||||
) -> Fallible<DomRoot<CompressionStream>> {
|
||||
// Step 1. If format is unsupported in CompressionStream, then throw a TypeError.
|
||||
@@ -91,9 +91,9 @@ impl CompressionStreamMethods<crate::DomTypeHolder> for CompressionStream {
|
||||
|
||||
// Step 2. Set this’s format to format.
|
||||
// Step 5. Set this’s transform to a new TransformStream.
|
||||
let transform = TransformStream::new_with_proto(global, None, can_gc);
|
||||
let transform = TransformStream::new_with_proto(global, None, CanGc::from_cx(cx));
|
||||
let compression_stream =
|
||||
CompressionStream::new_with_proto(global, proto, &transform, format, can_gc);
|
||||
CompressionStream::new_with_proto(cx, global, proto, &transform, format);
|
||||
|
||||
// Step 3. Let transformAlgorithm be an algorithm which takes a chunk argument and runs the
|
||||
// compress and enqueue a chunk algorithm with this and chunk.
|
||||
@@ -103,8 +103,7 @@ impl CompressionStreamMethods<crate::DomTypeHolder> for CompressionStream {
|
||||
|
||||
// Step 6. Set up this’s transform with transformAlgorithm set to transformAlgorithm and
|
||||
// flushAlgorithm set to flushAlgorithm.
|
||||
let cx = GlobalScope::get_cx();
|
||||
transform.set_up(cx, global, transformer_type, can_gc)?;
|
||||
transform.set_up(cx, global, transformer_type)?;
|
||||
|
||||
Ok(compression_stream)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::dom::bindings::codegen::Bindings::CompressionStreamBinding::Compressi
|
||||
use crate::dom::bindings::codegen::Bindings::DecompressionStreamBinding::DecompressionStreamMethods;
|
||||
use crate::dom::bindings::conversions::SafeToJSValConvertible;
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_cx};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::stream::compressionstream::{BROTLI_BUFFER_SIZE, convert_chunk_to_vec};
|
||||
use crate::dom::stream::transformstreamdefaultcontroller::TransformerType;
|
||||
@@ -59,17 +59,17 @@ impl DecompressionStream {
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
transform: &TransformStream,
|
||||
format: CompressionFormat,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<DecompressionStream> {
|
||||
reflect_dom_object_with_proto(
|
||||
reflect_dom_object_with_proto_and_cx(
|
||||
Box::new(DecompressionStream::new_inherited(transform, format)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -77,9 +77,9 @@ impl DecompressionStream {
|
||||
impl DecompressionStreamMethods<crate::DomTypeHolder> for DecompressionStream {
|
||||
/// <https://compression.spec.whatwg.org/#dom-decompressionstream-decompressionstream>
|
||||
fn Constructor(
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
can_gc: CanGc,
|
||||
format: CompressionFormat,
|
||||
) -> Fallible<DomRoot<DecompressionStream>> {
|
||||
// Step 1. If format is unsupported in DecompressionStream, then throw a TypeError.
|
||||
@@ -87,9 +87,9 @@ impl DecompressionStreamMethods<crate::DomTypeHolder> for DecompressionStream {
|
||||
|
||||
// Step 2. Set this’s format to format.
|
||||
// Step 5. Set this’s transform to a new TransformStream.
|
||||
let transform = TransformStream::new_with_proto(global, None, can_gc);
|
||||
let transform = TransformStream::new_with_proto(global, None, CanGc::from_cx(cx));
|
||||
let decompression_stream =
|
||||
DecompressionStream::new_with_proto(global, proto, &transform, format, can_gc);
|
||||
DecompressionStream::new_with_proto(cx, global, proto, &transform, format);
|
||||
|
||||
// Step 3. Let transformAlgorithm be an algorithm which takes a chunk argument and runs the
|
||||
// decompress and enqueue a chunk algorithm with this and chunk.
|
||||
@@ -99,8 +99,7 @@ impl DecompressionStreamMethods<crate::DomTypeHolder> for DecompressionStream {
|
||||
|
||||
// Step 6. Set up this’s transform with transformAlgorithm set to transformAlgorithm and
|
||||
// flushAlgorithm set to flushAlgorithm.
|
||||
let cx = GlobalScope::get_cx();
|
||||
transform.set_up(cx, global, transformer_type, can_gc)?;
|
||||
transform.set_up(cx, global, transformer_type)?;
|
||||
|
||||
Ok(decompression_stream)
|
||||
}
|
||||
|
||||
@@ -451,22 +451,23 @@ impl TransformStream {
|
||||
/// <https://streams.spec.whatwg.org/#transformstream-set-up>
|
||||
pub(crate) fn set_up(
|
||||
&self,
|
||||
cx: SafeJSContext,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
transformer_type: TransformerType,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<()> {
|
||||
// Step1. Let writableHighWaterMark be 1.
|
||||
let writable_high_water_mark = 1.0;
|
||||
|
||||
// Step 2. Let writableSizeAlgorithm be an algorithm that returns 1.
|
||||
let writable_size_algorithm = extract_size_algorithm(&Default::default(), can_gc);
|
||||
let writable_size_algorithm =
|
||||
extract_size_algorithm(&Default::default(), CanGc::from_cx(cx));
|
||||
|
||||
// Step 3. Let readableHighWaterMark be 0.
|
||||
let readable_high_water_mark = 0.0;
|
||||
|
||||
// Step 4. Let readableSizeAlgorithm be an algorithm that returns 1.
|
||||
let readable_size_algorithm = extract_size_algorithm(&Default::default(), can_gc);
|
||||
let readable_size_algorithm =
|
||||
extract_size_algorithm(&Default::default(), CanGc::from_cx(cx));
|
||||
|
||||
// Step 5. Let transformAlgorithmWrapper be an algorithm that runs these steps given a value chunk:
|
||||
// Step 6. Let flushAlgorithmWrapper be an algorithm that runs these steps:
|
||||
@@ -474,7 +475,7 @@ impl TransformStream {
|
||||
// NOTE: These steps are implemented in `TransformStreamDefaultController::new`
|
||||
|
||||
// Step 8. Let startPromise be a promise resolved with undefined.
|
||||
let start_promise = Promise::new_resolved(global, cx, (), can_gc);
|
||||
let start_promise = Promise::new_resolved(global, cx.into(), (), CanGc::from_cx(cx));
|
||||
|
||||
// Step 9. Perform ! InitializeTransformStream(stream, startPromise,
|
||||
// writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark,
|
||||
@@ -487,11 +488,11 @@ impl TransformStream {
|
||||
writable_size_algorithm,
|
||||
readable_high_water_mark,
|
||||
readable_size_algorithm,
|
||||
can_gc,
|
||||
)?;
|
||||
|
||||
// Step 10. Let controller be a new TransformStreamDefaultController.
|
||||
let controller = TransformStreamDefaultController::new(global, transformer_type, can_gc);
|
||||
let controller =
|
||||
TransformStreamDefaultController::new(global, transformer_type, CanGc::from_cx(cx));
|
||||
|
||||
// Step 11. Perform ! SetUpTransformStreamDefaultController(stream,
|
||||
// controller, transformAlgorithmWrapper, flushAlgorithmWrapper,
|
||||
@@ -518,17 +519,16 @@ impl TransformStream {
|
||||
}
|
||||
|
||||
/// <https://streams.spec.whatwg.org/#initialize-transform-stream>
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn initialize(
|
||||
&self,
|
||||
cx: SafeJSContext,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
start_promise: Rc<Promise>,
|
||||
writable_high_water_mark: f64,
|
||||
writable_size_algorithm: Rc<QueuingStrategySize>,
|
||||
readable_high_water_mark: f64,
|
||||
readable_size_algorithm: Rc<QueuingStrategySize>,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<()> {
|
||||
// Let startAlgorithm be an algorithm that returns startPromise.
|
||||
// Let writeAlgorithm be the following steps, taking a chunk argument:
|
||||
@@ -547,7 +547,6 @@ impl TransformStream {
|
||||
writable_high_water_mark,
|
||||
writable_size_algorithm,
|
||||
UnderlyingSinkType::Transform(Dom::from_ref(self), start_promise.clone()),
|
||||
can_gc,
|
||||
)?;
|
||||
self.writable.set(Some(&writable));
|
||||
|
||||
@@ -567,7 +566,7 @@ impl TransformStream {
|
||||
UnderlyingSourceType::Transform(Dom::from_ref(self), start_promise),
|
||||
Some(readable_size_algorithm),
|
||||
Some(readable_high_water_mark),
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
self.readable.set(Some(&readable));
|
||||
|
||||
@@ -575,7 +574,7 @@ impl TransformStream {
|
||||
// Note: This is done in the constructor.
|
||||
|
||||
// Perform ! TransformStreamSetBackpressure(stream, true).
|
||||
self.set_backpressure(global, true, can_gc);
|
||||
self.set_backpressure(global, true, CanGc::from_cx(cx));
|
||||
|
||||
// Set stream.[[controller]] to undefined.
|
||||
self.controller.set(None);
|
||||
@@ -962,22 +961,21 @@ impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream {
|
||||
/// <https://streams.spec.whatwg.org/#ts-constructor>
|
||||
#[expect(unsafe_code)]
|
||||
fn Constructor(
|
||||
cx: SafeJSContext,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
can_gc: CanGc,
|
||||
transformer: Option<*mut JSObject>,
|
||||
writable_strategy: &QueuingStrategy,
|
||||
readable_strategy: &QueuingStrategy,
|
||||
) -> Fallible<DomRoot<TransformStream>> {
|
||||
// If transformer is missing, set it to null.
|
||||
rooted!(in(*cx) let transformer_obj = transformer.unwrap_or(ptr::null_mut()));
|
||||
rooted!(&in(cx) let transformer_obj = transformer.unwrap_or(ptr::null_mut()));
|
||||
|
||||
// Let underlyingSinkDict be underlyingSink,
|
||||
// converted to an IDL value of type UnderlyingSink.
|
||||
let transformer_dict = if !transformer_obj.is_null() {
|
||||
rooted!(in(*cx) let obj_val = ObjectValue(transformer_obj.get()));
|
||||
match Transformer::new(cx, obj_val.handle(), can_gc) {
|
||||
rooted!(&in(cx) let obj_val = ObjectValue(transformer_obj.get()));
|
||||
match Transformer::new(cx.into(), obj_val.handle(), CanGc::from_cx(cx)) {
|
||||
Ok(ConversionResult::Success(val)) => val,
|
||||
Ok(ConversionResult::Failure(error)) => {
|
||||
return Err(Error::Type(error.into_owned()));
|
||||
@@ -1004,20 +1002,20 @@ impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream {
|
||||
let readable_high_water_mark = extract_high_water_mark(readable_strategy, 0.0)?;
|
||||
|
||||
// Let readableSizeAlgorithm be ! ExtractSizeAlgorithm(readableStrategy).
|
||||
let readable_size_algorithm = extract_size_algorithm(readable_strategy, can_gc);
|
||||
let readable_size_algorithm = extract_size_algorithm(readable_strategy, CanGc::from_cx(cx));
|
||||
|
||||
// Let writableHighWaterMark be ? ExtractHighWaterMark(writableStrategy, 1).
|
||||
let writable_high_water_mark = extract_high_water_mark(writable_strategy, 1.0)?;
|
||||
|
||||
// Let writableSizeAlgorithm be ! ExtractSizeAlgorithm(writableStrategy).
|
||||
let writable_size_algorithm = extract_size_algorithm(writable_strategy, can_gc);
|
||||
let writable_size_algorithm = extract_size_algorithm(writable_strategy, CanGc::from_cx(cx));
|
||||
|
||||
// Let startPromise be a new promise.
|
||||
let start_promise = Promise::new(global, can_gc);
|
||||
let start_promise = Promise::new2(cx, global);
|
||||
|
||||
// Perform ! InitializeTransformStream(this, startPromise, writableHighWaterMark,
|
||||
// writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm).
|
||||
let stream = TransformStream::new_with_proto(global, proto, can_gc);
|
||||
let stream = TransformStream::new_with_proto(global, proto, CanGc::from_cx(cx));
|
||||
stream.initialize(
|
||||
cx,
|
||||
global,
|
||||
@@ -1026,7 +1024,6 @@ impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream {
|
||||
writable_size_algorithm,
|
||||
readable_high_water_mark,
|
||||
readable_size_algorithm,
|
||||
can_gc,
|
||||
)?;
|
||||
|
||||
// Perform ? SetUpTransformStreamDefaultControllerFromTransformer(this, transformer, transformerDict).
|
||||
@@ -1034,22 +1031,22 @@ impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream {
|
||||
global,
|
||||
transformer_obj.handle(),
|
||||
&transformer_dict,
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
|
||||
// If transformerDict["start"] exists, then resolve startPromise with the
|
||||
// result of invoking transformerDict["start"]
|
||||
// with argument list « this.[[controller]] » and callback this value transformer.
|
||||
if let Some(start) = &transformer_dict.start {
|
||||
rooted!(in(*cx) let mut result_object = ptr::null_mut::<JSObject>());
|
||||
rooted!(in(*cx) let mut result: JSVal);
|
||||
rooted!(in(*cx) let this_object = transformer_obj.get());
|
||||
rooted!(&in(cx) let mut result_object = ptr::null_mut::<JSObject>());
|
||||
rooted!(&in(cx) let mut result: JSVal);
|
||||
rooted!(&in(cx) let this_object = transformer_obj.get());
|
||||
start.Call_(
|
||||
&this_object.handle(),
|
||||
&stream.get_controller(),
|
||||
result.handle_mut(),
|
||||
ExceptionHandling::Rethrow,
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
)?;
|
||||
let is_promise = unsafe {
|
||||
if result.is_object() {
|
||||
@@ -1060,14 +1057,14 @@ impl TransformStreamMethods<crate::DomTypeHolder> for TransformStream {
|
||||
}
|
||||
};
|
||||
let promise = if is_promise {
|
||||
Promise::new_with_js_promise(result_object.handle(), cx)
|
||||
Promise::new_with_js_promise(result_object.handle(), cx.into())
|
||||
} else {
|
||||
Promise::new_resolved(global, cx, result.get(), can_gc)
|
||||
Promise::new_resolved(global, cx.into(), result.get(), CanGc::from_cx(cx))
|
||||
};
|
||||
start_promise.resolve_native(&promise, can_gc);
|
||||
start_promise.resolve_native(&promise, CanGc::from_cx(cx));
|
||||
} else {
|
||||
// Otherwise, resolve startPromise with undefined.
|
||||
start_promise.resolve_native(&(), can_gc);
|
||||
start_promise.resolve_native(&(), CanGc::from_cx(cx));
|
||||
};
|
||||
|
||||
Ok(stream)
|
||||
|
||||
@@ -914,21 +914,20 @@ impl WritableStream {
|
||||
|
||||
// Perform ! SetUpWritableStreamDefaultController
|
||||
controller
|
||||
.setup(cx.into(), &global, self, CanGc::from_cx(cx))
|
||||
.setup(cx, &global, self)
|
||||
.expect("Setup for transfer cannot fail");
|
||||
}
|
||||
/// <https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller-from-underlying-sink>
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn setup_from_underlying_sink(
|
||||
fn setup_from_underlying_sink(
|
||||
&self,
|
||||
cx: SafeJSContext,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
stream: &WritableStream,
|
||||
underlying_sink_obj: SafeHandleObject,
|
||||
underlying_sink: &UnderlyingSink,
|
||||
strategy_hwm: f64,
|
||||
strategy_size: Rc<QueuingStrategySize>,
|
||||
can_gc: CanGc,
|
||||
) -> Result<(), Error> {
|
||||
// Let controller be a new WritableStreamDefaultController.
|
||||
|
||||
@@ -965,7 +964,7 @@ impl WritableStream {
|
||||
),
|
||||
strategy_hwm,
|
||||
strategy_size,
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
|
||||
// Note: this must be done before `setup`,
|
||||
@@ -973,26 +972,25 @@ impl WritableStream {
|
||||
controller.set_underlying_sink_this_object(underlying_sink_obj);
|
||||
|
||||
// Perform ? SetUpWritableStreamDefaultController
|
||||
controller.setup(cx, global, stream, can_gc)
|
||||
controller.setup(cx, global, stream)
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://streams.spec.whatwg.org/#create-writable-stream>
|
||||
#[cfg_attr(crown, expect(crown::unrooted_must_root))]
|
||||
pub(crate) fn create_writable_stream(
|
||||
cx: SafeJSContext,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
writable_high_water_mark: f64,
|
||||
writable_size_algorithm: Rc<QueuingStrategySize>,
|
||||
underlying_sink_type: UnderlyingSinkType,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<DomRoot<WritableStream>> {
|
||||
// Assert: ! IsNonNegativeNumber(highWaterMark) is true.
|
||||
assert!(writable_high_water_mark >= 0.0);
|
||||
|
||||
// Let stream be a new WritableStream.
|
||||
// Perform ! InitializeWritableStream(stream).
|
||||
let stream = WritableStream::new_with_proto(global, None, can_gc);
|
||||
let stream = WritableStream::new_with_proto(global, None, CanGc::from_cx(cx));
|
||||
|
||||
// Let controller be a new WritableStreamDefaultController.
|
||||
let controller = WritableStreamDefaultController::new(
|
||||
@@ -1000,12 +998,12 @@ pub(crate) fn create_writable_stream(
|
||||
underlying_sink_type,
|
||||
writable_high_water_mark,
|
||||
writable_size_algorithm,
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
|
||||
// Perform ? SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm,
|
||||
// closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm).
|
||||
controller.setup(cx, global, &stream, can_gc)?;
|
||||
controller.setup(cx, global, &stream)?;
|
||||
|
||||
// Return stream.
|
||||
Ok(stream)
|
||||
@@ -1014,21 +1012,20 @@ pub(crate) fn create_writable_stream(
|
||||
impl WritableStreamMethods<crate::DomTypeHolder> for WritableStream {
|
||||
/// <https://streams.spec.whatwg.org/#ws-constructor>
|
||||
fn Constructor(
|
||||
cx: SafeJSContext,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
proto: Option<SafeHandleObject>,
|
||||
can_gc: CanGc,
|
||||
underlying_sink: Option<*mut JSObject>,
|
||||
strategy: &QueuingStrategy,
|
||||
) -> Fallible<DomRoot<WritableStream>> {
|
||||
// If underlyingSink is missing, set it to null.
|
||||
rooted!(in(*cx) let underlying_sink_obj = underlying_sink.unwrap_or(ptr::null_mut()));
|
||||
rooted!(&in(cx) let underlying_sink_obj = underlying_sink.unwrap_or(ptr::null_mut()));
|
||||
|
||||
// Let underlyingSinkDict be underlyingSink,
|
||||
// converted to an IDL value of type UnderlyingSink.
|
||||
let underlying_sink_dict = if !underlying_sink_obj.is_null() {
|
||||
rooted!(in(*cx) let obj_val = ObjectValue(underlying_sink_obj.get()));
|
||||
match UnderlyingSink::new(cx, obj_val.handle(), can_gc) {
|
||||
rooted!(&in(cx) let obj_val = ObjectValue(underlying_sink_obj.get()));
|
||||
match UnderlyingSink::new(cx.into(), obj_val.handle(), CanGc::from_cx(cx)) {
|
||||
Ok(ConversionResult::Success(val)) => val,
|
||||
Ok(ConversionResult::Failure(error)) => {
|
||||
return Err(Error::Type(error.into_owned()));
|
||||
@@ -1047,10 +1044,10 @@ impl WritableStreamMethods<crate::DomTypeHolder> for WritableStream {
|
||||
}
|
||||
|
||||
// Perform ! InitializeWritableStream(this).
|
||||
let stream = WritableStream::new_with_proto(global, proto, can_gc);
|
||||
let stream = WritableStream::new_with_proto(global, proto, CanGc::from_cx(cx));
|
||||
|
||||
// Let sizeAlgorithm be ! ExtractSizeAlgorithm(strategy).
|
||||
let size_algorithm = extract_size_algorithm(strategy, can_gc);
|
||||
let size_algorithm = extract_size_algorithm(strategy, CanGc::from_cx(cx));
|
||||
|
||||
// Let highWaterMark be ? ExtractHighWaterMark(strategy, 1).
|
||||
let high_water_mark = extract_high_water_mark(strategy, 1.0)?;
|
||||
@@ -1065,7 +1062,6 @@ impl WritableStreamMethods<crate::DomTypeHolder> for WritableStream {
|
||||
&underlying_sink_dict,
|
||||
high_water_mark,
|
||||
size_algorithm,
|
||||
can_gc,
|
||||
)?;
|
||||
|
||||
Ok(stream)
|
||||
|
||||
@@ -29,7 +29,7 @@ use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler};
|
||||
use crate::dom::readablestreamdefaultcontroller::{EnqueuedValue, QueueWithSizes, ValueWithSize};
|
||||
use crate::dom::stream::writablestream::WritableStream;
|
||||
use crate::dom::types::{AbortController, AbortSignal, TransformStream};
|
||||
use crate::realms::{InRealm, enter_auto_realm, enter_realm};
|
||||
use crate::realms::{InRealm, enter_auto_realm};
|
||||
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
||||
|
||||
impl js::gc::Rootable for CloseAlgorithmFulfillmentHandler {}
|
||||
@@ -442,10 +442,9 @@ impl WritableStreamDefaultController {
|
||||
/// <https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller>
|
||||
pub(crate) fn setup(
|
||||
&self,
|
||||
cx: SafeJSContext,
|
||||
cx: &mut js::context::JSContext,
|
||||
global: &GlobalScope,
|
||||
stream: &WritableStream,
|
||||
can_gc: CanGc,
|
||||
) -> Result<(), Error> {
|
||||
// Assert: stream implements WritableStream.
|
||||
// Implied by stream type.
|
||||
@@ -481,21 +480,21 @@ impl WritableStreamDefaultController {
|
||||
let backpressure = self.get_backpressure();
|
||||
|
||||
// Perform ! WritableStreamUpdateBackpressure(stream, backpressure).
|
||||
stream.update_backpressure(backpressure, global, can_gc);
|
||||
stream.update_backpressure(backpressure, global, CanGc::from_cx(cx));
|
||||
|
||||
// Let startResult be the result of performing startAlgorithm. (This may throw an exception.)
|
||||
// Let startPromise be a promise resolved with startResult.
|
||||
let start_promise = self.start_algorithm(cx, global, can_gc)?;
|
||||
let start_promise = self.start_algorithm(cx.into(), global, CanGc::from_cx(cx))?;
|
||||
|
||||
let rooted_default_controller = DomRoot::from_ref(self);
|
||||
|
||||
// Upon fulfillment of startPromise,
|
||||
rooted!(in(*cx) let mut fulfillment_handler = Some(StartAlgorithmFulfillmentHandler {
|
||||
rooted!(&in(cx) let mut fulfillment_handler = Some(StartAlgorithmFulfillmentHandler {
|
||||
controller: Dom::from_ref(&rooted_default_controller),
|
||||
}));
|
||||
|
||||
// Upon rejection of startPromise with reason r,
|
||||
rooted!(in(*cx) let mut rejection_handler = Some(StartAlgorithmRejectionHandler {
|
||||
rooted!(&in(cx) let mut rejection_handler = Some(StartAlgorithmRejectionHandler {
|
||||
controller: Dom::from_ref(&rooted_default_controller),
|
||||
}));
|
||||
|
||||
@@ -503,11 +502,14 @@ impl WritableStreamDefaultController {
|
||||
global,
|
||||
fulfillment_handler.take().map(|h| Box::new(h) as Box<_>),
|
||||
rejection_handler.take().map(|h| Box::new(h) as Box<_>),
|
||||
can_gc,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
let realm = enter_realm(global);
|
||||
let comp = InRealm::Entered(&realm);
|
||||
start_promise.append_native_handler(&handler, comp, can_gc);
|
||||
let mut realm = enter_auto_realm(cx, global);
|
||||
let cx = &mut realm.current_realm();
|
||||
|
||||
let in_realm_proof = cx.into();
|
||||
let comp = InRealm::Already(&in_realm_proof);
|
||||
start_promise.append_native_handler(&handler, comp, CanGc::from_cx(cx));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -494,7 +494,7 @@ impl DedicatedWorkerGlobalScope {
|
||||
cx,
|
||||
);
|
||||
debugger_global.fire_add_debuggee(
|
||||
CanGc::from_cx(cx),
|
||||
cx,
|
||||
global.upcast(),
|
||||
pipeline_id,
|
||||
Some(worker_id),
|
||||
@@ -675,7 +675,7 @@ impl DedicatedWorkerGlobalScope {
|
||||
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, _bool_val) => {},
|
||||
DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, reply) => {
|
||||
self.debugger_global.fire_eval(
|
||||
CanGc::from_cx(cx),
|
||||
cx,
|
||||
code.into(),
|
||||
id,
|
||||
Some(self.upcast::<WorkerGlobalScope>().worker_id()),
|
||||
|
||||
@@ -399,7 +399,7 @@ impl ServiceWorkerGlobalScope {
|
||||
|
||||
if let Some(debugger_global) = debugger_global.as_deref() {
|
||||
debugger_global.fire_add_debuggee(
|
||||
CanGc::from_cx(cx),
|
||||
cx,
|
||||
global_scope,
|
||||
pipeline_id,
|
||||
Some(worker_scope.worker_id()),
|
||||
@@ -500,7 +500,7 @@ impl ServiceWorkerGlobalScope {
|
||||
DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, reply) => {
|
||||
if let Some(debugger_global) = self.debugger_global.as_deref() {
|
||||
debugger_global.fire_eval(
|
||||
CanGc::from_cx(cx),
|
||||
cx,
|
||||
code.into(),
|
||||
id,
|
||||
Some(self.upcast::<WorkerGlobalScope>().worker_id()),
|
||||
|
||||
@@ -2237,37 +2237,23 @@ impl ScriptThread {
|
||||
)
|
||||
},
|
||||
DevtoolScriptControlMsg::Eval(code, id, frame_actor_id, reply) => {
|
||||
self.debugger_global.fire_eval(
|
||||
CanGc::from_cx(cx),
|
||||
code.into(),
|
||||
id,
|
||||
None,
|
||||
frame_actor_id,
|
||||
reply,
|
||||
);
|
||||
self.debugger_global
|
||||
.fire_eval(cx, code.into(), id, None, frame_actor_id, reply);
|
||||
},
|
||||
DevtoolScriptControlMsg::GetPossibleBreakpoints(spidermonkey_id, result_sender) => {
|
||||
self.debugger_global.fire_get_possible_breakpoints(
|
||||
CanGc::from_cx(cx),
|
||||
cx,
|
||||
spidermonkey_id,
|
||||
result_sender,
|
||||
);
|
||||
},
|
||||
DevtoolScriptControlMsg::SetBreakpoint(spidermonkey_id, script_id, offset) => {
|
||||
self.debugger_global.fire_set_breakpoint(
|
||||
CanGc::from_cx(cx),
|
||||
spidermonkey_id,
|
||||
script_id,
|
||||
offset,
|
||||
);
|
||||
self.debugger_global
|
||||
.fire_set_breakpoint(cx, spidermonkey_id, script_id, offset);
|
||||
},
|
||||
DevtoolScriptControlMsg::ClearBreakpoint(spidermonkey_id, script_id, offset) => {
|
||||
self.debugger_global.fire_clear_breakpoint(
|
||||
CanGc::from_cx(cx),
|
||||
spidermonkey_id,
|
||||
script_id,
|
||||
offset,
|
||||
);
|
||||
self.debugger_global
|
||||
.fire_clear_breakpoint(cx, spidermonkey_id, script_id, offset);
|
||||
},
|
||||
DevtoolScriptControlMsg::Interrupt => {
|
||||
self.debugger_global.fire_interrupt(CanGc::from_cx(cx));
|
||||
@@ -2282,18 +2268,12 @@ impl ScriptThread {
|
||||
);
|
||||
},
|
||||
DevtoolScriptControlMsg::GetEnvironment(frame_actor_id, result_sender) => {
|
||||
self.debugger_global.fire_get_environment(
|
||||
frame_actor_id,
|
||||
result_sender,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
self.debugger_global
|
||||
.fire_get_environment(cx, frame_actor_id, result_sender);
|
||||
},
|
||||
DevtoolScriptControlMsg::Resume(resume_limit_type, frame_actor_id) => {
|
||||
self.debugger_global.fire_resume(
|
||||
resume_limit_type,
|
||||
frame_actor_id,
|
||||
CanGc::from_cx(cx),
|
||||
);
|
||||
self.debugger_global
|
||||
.fire_resume(cx, resume_limit_type, frame_actor_id);
|
||||
self.debugger_paused.set(false);
|
||||
},
|
||||
}
|
||||
@@ -3460,12 +3440,8 @@ impl ScriptThread {
|
||||
incomplete.theme,
|
||||
self.this.clone(),
|
||||
);
|
||||
self.debugger_global.fire_add_debuggee(
|
||||
CanGc::from_cx(cx),
|
||||
window.upcast(),
|
||||
incomplete.pipeline_id,
|
||||
None,
|
||||
);
|
||||
self.debugger_global
|
||||
.fire_add_debuggee(cx, window.upcast(), incomplete.pipeline_id, None);
|
||||
|
||||
let mut realm = enter_auto_realm(cx, &*window);
|
||||
let cx = &mut realm;
|
||||
|
||||
@@ -114,6 +114,10 @@ DOMInterfaces = {
|
||||
'cx': ['Constructor']
|
||||
},
|
||||
|
||||
'CompressionStream': {
|
||||
'cx': ['Constructor'],
|
||||
},
|
||||
|
||||
'CookieStore': {
|
||||
'cx': ['Set', 'Set_', 'Get', 'Get_', 'GetAll', 'GetAll_', 'Delete', 'Delete_'],
|
||||
},
|
||||
@@ -197,6 +201,10 @@ DOMInterfaces = {
|
||||
'useSystemCompartment': True,
|
||||
},
|
||||
|
||||
'DecompressionStream': {
|
||||
'cx': ['Constructor'],
|
||||
},
|
||||
|
||||
'DedicatedWorkerGlobalScope': {
|
||||
'cx': ['PostMessage', 'PostMessage_'],
|
||||
},
|
||||
@@ -337,6 +345,10 @@ DOMInterfaces = {
|
||||
'canGc': ['Load'],
|
||||
},
|
||||
|
||||
'Gamepad': {
|
||||
'canGc': ['Axes']
|
||||
},
|
||||
|
||||
'GamepadHapticActuator': {
|
||||
'inRealms': ['PlayEffect', 'Reset'],
|
||||
'canGc': ['PlayEffect', 'Reset', 'Effects'],
|
||||
@@ -873,10 +885,22 @@ DOMInterfaces = {
|
||||
'cx_no_gc': ['WholeText']
|
||||
},
|
||||
|
||||
'TextDecoderStream': {
|
||||
'cx': ['Constructor'],
|
||||
},
|
||||
|
||||
'TextEncoder': {
|
||||
'canGc': ['Encode']
|
||||
},
|
||||
|
||||
'TextEncoderStream': {
|
||||
'cx': ['Constructor'],
|
||||
},
|
||||
|
||||
'TransformStream': {
|
||||
'cx': ['Constructor'],
|
||||
},
|
||||
|
||||
'TreeWalker': {
|
||||
'cx': ['ParentNode', 'PreviousNode', 'NextNode', 'FirstChild', 'LastChild', 'PreviousSibling', 'NextSibling']
|
||||
},
|
||||
@@ -1069,6 +1093,7 @@ DOMInterfaces = {
|
||||
|
||||
'WritableStream': {
|
||||
'canGc': ['Close', 'GetWriter'],
|
||||
'cx': ['Constructor'],
|
||||
'inRealms': ['GetWriter'],
|
||||
'realm': ['Abort', 'Close']
|
||||
},
|
||||
@@ -1167,21 +1192,21 @@ Dictionaries = {
|
||||
},
|
||||
|
||||
'SanitizerAttributeNamespace': {
|
||||
'derives': ['Clone', 'MallocSizeOf']
|
||||
},
|
||||
|
||||
'SanitizerElementNamespace': {
|
||||
'derives': ['Clone', 'MallocSizeOf'],
|
||||
},
|
||||
|
||||
'SanitizerElementNamespaceWithAttributes': {
|
||||
'derives': ['Clone', 'MallocSizeOf'],
|
||||
'derives': ['Clone', 'MallocSizeOf', 'PartialEq']
|
||||
},
|
||||
|
||||
'SanitizerConfig': {
|
||||
'derives': ['Clone', 'MallocSizeOf']
|
||||
},
|
||||
|
||||
'SanitizerElementNamespace': {
|
||||
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
|
||||
},
|
||||
|
||||
'SanitizerElementNamespaceWithAttributes': {
|
||||
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
|
||||
},
|
||||
|
||||
'ScrollOptions': {
|
||||
'derives': ['Clone'],
|
||||
},
|
||||
@@ -1226,15 +1251,15 @@ Unions = {
|
||||
},
|
||||
|
||||
'StringOrSanitizerAttributeNamespace': {
|
||||
'derives': ['Clone', 'MallocSizeOf'],
|
||||
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
|
||||
},
|
||||
|
||||
'StringOrSanitizerElementNamespace': {
|
||||
'derives': ['Clone', 'MallocSizeOf'],
|
||||
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
|
||||
},
|
||||
|
||||
'StringOrSanitizerElementNamespaceWithAttributes': {
|
||||
'derives': ['Clone', 'MallocSizeOf'],
|
||||
'derives': ['Clone', 'MallocSizeOf', 'PartialEq'],
|
||||
},
|
||||
|
||||
'RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict': {
|
||||
|
||||
@@ -12,8 +12,8 @@ interface Gamepad {
|
||||
readonly attribute boolean connected;
|
||||
readonly attribute DOMHighResTimeStamp timestamp;
|
||||
readonly attribute DOMString mapping;
|
||||
readonly attribute Float64Array axes;
|
||||
readonly attribute any buttons;
|
||||
readonly attribute /* FrozenArray<double> */ any axes;
|
||||
[SameObject] readonly attribute GamepadHapticActuator vibrationActuator;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ interface Sanitizer {
|
||||
SanitizerConfig get();
|
||||
|
||||
// Modify a Sanitizer's lists and fields:
|
||||
// boolean allowElement(SanitizerElementWithAttributes element);
|
||||
// boolean removeElement(SanitizerElement element);
|
||||
// boolean replaceElementWithChildren(SanitizerElement element);
|
||||
boolean allowElement(SanitizerElementWithAttributes element);
|
||||
boolean removeElement(SanitizerElement element);
|
||||
boolean replaceElementWithChildren(SanitizerElement element);
|
||||
// boolean allowAttribute(SanitizerAttribute attribute);
|
||||
// boolean removeAttribute(SanitizerAttribute attribute);
|
||||
// boolean setComments(boolean allow);
|
||||
|
||||
@@ -201,6 +201,63 @@ fn test_accessibility_after_navigate_and_back() {
|
||||
|
||||
// TODO(accessibility): write test for resend a11y tree when clicking back or forward
|
||||
|
||||
#[test]
|
||||
fn test_accessibility_basic_mapping() {
|
||||
let servo_test = ServoTest::new_with_builder(|builder| {
|
||||
let mut preferences = Preferences::default();
|
||||
preferences.accessibility_enabled = true;
|
||||
builder.preferences(preferences)
|
||||
});
|
||||
let delegate = Rc::new(WebViewDelegateImpl::default());
|
||||
|
||||
let mut element_role_pairs = VecDeque::from([
|
||||
("article", Role::Article),
|
||||
("aside", Role::Complementary),
|
||||
("footer", Role::ContentInfo),
|
||||
("h1", Role::Heading),
|
||||
("h2", Role::Heading),
|
||||
("h3", Role::Heading),
|
||||
("h4", Role::Heading),
|
||||
("h5", Role::Heading),
|
||||
("h6", Role::Heading),
|
||||
("header", Role::Banner),
|
||||
("hr", Role::Splitter),
|
||||
("main", Role::Main),
|
||||
("nav", Role::Navigation),
|
||||
("p", Role::Paragraph),
|
||||
]);
|
||||
|
||||
let mut url: String = "data:text/html,<!DOCTYPE html>".to_owned();
|
||||
for (element, _) in element_role_pairs.iter() {
|
||||
url.push_str(format!("<{element}></{element}>").as_str());
|
||||
}
|
||||
let webview = WebViewBuilder::new(servo_test.servo(), servo_test.rendering_context.clone())
|
||||
.delegate(delegate.clone())
|
||||
.url(Url::parse(url.as_str()).unwrap())
|
||||
.build();
|
||||
|
||||
webview.set_accessibility_active(true);
|
||||
|
||||
let load_webview = webview.clone();
|
||||
servo_test.spin(move || load_webview.load_status() != LoadStatus::Complete);
|
||||
|
||||
let updates = wait_for_min_updates(&servo_test, delegate.clone(), 2);
|
||||
let tree = build_tree(updates);
|
||||
let root = assert_tree_structure_and_get_root_web_area(&tree);
|
||||
assert_eq!(root.children().len(), element_role_pairs.len());
|
||||
for child in root.children() {
|
||||
let Some((tag, role)) = element_role_pairs.pop_front() else {
|
||||
panic!("Number of children of root node should match number of tag/role pairs");
|
||||
};
|
||||
assert_eq!(child.data().html_tag(), Some(tag));
|
||||
assert_eq!(child.role(), role);
|
||||
}
|
||||
assert!(
|
||||
element_role_pairs.is_empty(),
|
||||
"Number of children of root node should match number of tag/role pairs"
|
||||
);
|
||||
}
|
||||
|
||||
fn wait_for_min_updates(
|
||||
servo_test: &ServoTest,
|
||||
delegate: Rc<WebViewDelegateImpl>,
|
||||
@@ -266,13 +323,8 @@ fn assert_tree_structure_and_get_root_web_area<'tree>(
|
||||
let graft_node = scroll_view_children[0];
|
||||
assert!(graft_node.is_graft());
|
||||
|
||||
let graft_node_children: Vec<accesskit_consumer::Node<'_>> = graft_node.children().collect();
|
||||
assert_eq!(graft_node_children.len(), 1);
|
||||
|
||||
let root_web_area = graft_node_children[0];
|
||||
assert_eq!(root_web_area.role(), Role::RootWebArea);
|
||||
|
||||
root_web_area
|
||||
find_first_matching_node(graft_node, |node| node.role() == Role::RootWebArea)
|
||||
.expect("Should have a RootWebArea")
|
||||
}
|
||||
|
||||
fn find_first_matching_node(
|
||||
|
||||
7
tests/wpt/meta/MANIFEST.json
vendored
7
tests/wpt/meta/MANIFEST.json
vendored
@@ -7739,6 +7739,13 @@
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"replaceWith-document-element-crash.html": [
|
||||
"299542341ad27da315951f7863c3f0198e2ecfcb",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
]
|
||||
},
|
||||
"ranges": {
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
[idlharness.https.window.html]
|
||||
[Sanitizer interface: operation allowElement(SanitizerElementWithAttributes)]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: operation removeElement(SanitizerElement)]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: operation replaceElementWithChildren(SanitizerElement)]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: operation allowAttribute(SanitizerAttribute)]
|
||||
expected: FAIL
|
||||
|
||||
@@ -23,24 +14,6 @@
|
||||
[Sanitizer interface: operation removeUnsafe()]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: new Sanitizer({}) must inherit property "allowElement(SanitizerElementWithAttributes)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: calling allowElement(SanitizerElementWithAttributes) on new Sanitizer({}) with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: new Sanitizer({}) must inherit property "removeElement(SanitizerElement)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: calling removeElement(SanitizerElement) on new Sanitizer({}) with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: new Sanitizer({}) must inherit property "replaceElementWithChildren(SanitizerElement)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: calling replaceElementWithChildren(SanitizerElement) on new Sanitizer({}) with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[Sanitizer interface: new Sanitizer({}) must inherit property "allowAttribute(SanitizerAttribute)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
[sanitizer-basic-filtering.tentative.html]
|
||||
expected: ERROR
|
||||
[setHTML testcase text/0, "text"]
|
||||
expected: FAIL
|
||||
|
||||
@@ -29,3 +28,378 @@
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase elements/1, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase elements/1, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase elements/1, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase elements/2, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase elements/2, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase elements/2, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase elements/2, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase elements/2, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase elements/2, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase elements/3, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase elements/3, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase elements/3, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase elements/3, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase elements/3, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase elements/3, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase elements/4, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase elements/4, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase elements/4, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase elements/4, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase elements/4, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase elements/4, "<div><p>Hello <b>World!</b>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase attributes/0, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase attributes/0, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase attributes/0, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase attributes/1, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase attributes/2, "<p id="hello" style="font-weight: bold">x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase attributes-per-element/0, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase attributes-per-element/1, "<div style="font-weight: bold" class="bourgeoisie">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase comments/0, "a <!-- comment --> b"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase comments/0, "a <!-- comment --> b"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase comments/0, "a <!-- comment --> b"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase comments/1, "a <!-- comment --> b"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase comments/1, "a <!-- comment --> b"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase comments/1, "a <!-- comment --> b"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase comments/1, "a <!-- comment --> b"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase comments/1, "a <!-- comment --> b"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase comments/1, "a <!-- comment --> b"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase dataAttributes/0, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase dataAttributes/0, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase dataAttributes/0, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase dataAttributes/1, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase dataAttributes/2, "<p data-x="1" data-y="2" data-z="3">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/0, "<svg><rect></svg><math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/0, "<svg><rect></svg><math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/0, "<svg><rect></svg><math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/1, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase namespaces/1, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/1, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase namespaces/1, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/1, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase namespaces/1, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/2, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/2, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/2, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/3, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase namespaces/3, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/3, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase namespaces/3, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/3, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase namespaces/3, "<svg><rect>"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/4, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase namespaces/4, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/4, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase namespaces/4, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/4, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase namespaces/4, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/5, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/5, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/5, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/6, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase namespaces/6, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/6, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase namespaces/6, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/6, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase namespaces/6, "<math><mi>x"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/7, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/7, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/7, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase namespaces/8, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase namespaces/9, "<svg xml:space="default" xlink:href="about:blank" xmlns:foo="barspace">"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTML testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
|
||||
expected: FAIL
|
||||
|
||||
[setHTMLUnsafe testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTML testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
|
||||
expected: FAIL
|
||||
|
||||
[ShadowRoot.setHTMLUnsafe testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTML testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
|
||||
expected: FAIL
|
||||
|
||||
[parseHTMLUnsafe testcase defaults-with-attributes-per-element/0, "<div start=1 value=5 lang=en><ol start=1 value=5 lang=en><li start=1 value=5 lang=en>xx"]
|
||||
expected: FAIL
|
||||
|
||||
@@ -5,23 +5,8 @@
|
||||
[SanitizerConfig dataAttributes field.]
|
||||
expected: FAIL
|
||||
|
||||
[Test elements addition.]
|
||||
expected: FAIL
|
||||
|
||||
[Test elements removal.]
|
||||
expected: FAIL
|
||||
|
||||
[Test elements replacewithchildren.]
|
||||
expected: FAIL
|
||||
|
||||
[Test attribute addition.]
|
||||
expected: FAIL
|
||||
|
||||
[Test attribute removal.]
|
||||
expected: FAIL
|
||||
|
||||
[Test attribute-per-element sets (i.e. overwrites).]
|
||||
expected: FAIL
|
||||
|
||||
[Test removeAttribute-per-element sets (i.e. overwrites).]
|
||||
expected: FAIL
|
||||
|
||||
@@ -28,30 +28,3 @@
|
||||
|
||||
[sanitizer.removeAttribute() with global removeAttributes and element's removeAttributes]
|
||||
expected: FAIL
|
||||
|
||||
[sanitizer.removeElement() with global elements]
|
||||
expected: FAIL
|
||||
|
||||
[sanitizer.removeElement() with global removeElements]
|
||||
expected: FAIL
|
||||
|
||||
[sanitizer.replaceElementWithChildren() with global elements]
|
||||
expected: FAIL
|
||||
|
||||
[sanitizer.replaceElementWithChildren() with global removeElements]
|
||||
expected: FAIL
|
||||
|
||||
[sanitizer.allowElement() with global elements]
|
||||
expected: FAIL
|
||||
|
||||
[sanitizer.allowElement() with global removeElements]
|
||||
expected: FAIL
|
||||
|
||||
[sanitizer.allowElement() with global elements and attributes]
|
||||
expected: FAIL
|
||||
|
||||
[sanitizer.allowElement() with global elements and removeAttributes]
|
||||
expected: FAIL
|
||||
|
||||
[sanitizer.replaceElementWithChildren does not allow 'html' element.]
|
||||
expected: FAIL
|
||||
|
||||
10
tests/wpt/tests/dom/nodes/replaceWith-document-element-crash.html
vendored
Normal file
10
tests/wpt/tests/dom/nodes/replaceWith-document-element-crash.html
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<meta name="assert" content="Test replaceWith in a cycle">
|
||||
<link rel=help href="https://github.com/servo/servo/issues/35698">
|
||||
<link rel="author" title="Euclid Ye" href="mailto:yezhizhenjiakang@gmail.com">
|
||||
<script>
|
||||
var oldRoot = document.documentElement;
|
||||
var newRoot = document.createElement("html");
|
||||
oldRoot.replaceWith(newRoot);
|
||||
newRoot.replaceWith(oldRoot);
|
||||
</script>
|
||||
Reference in New Issue
Block a user