diff options
36 files changed, 396 insertions, 525 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9df8210ab64..97046da9bac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2478,9 +2478,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -7791,9 +7791,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", diff --git a/components/devtools/actors/browsing_context.rs b/components/devtools/actors/browsing_context.rs index c4ead7272bd..5de0855df4a 100644 --- a/components/devtools/actors/browsing_context.rs +++ b/components/devtools/actors/browsing_context.rs @@ -31,6 +31,7 @@ use crate::actors::thread::ThreadActor; use crate::actors::watcher::{SessionContext, SessionContextType, WatcherActor}; use crate::id::{DevtoolsBrowserId, DevtoolsBrowsingContextId, DevtoolsOuterWindowId, IdMap}; use crate::protocol::JsonPacketStream; +use crate::resource::ResourceAvailable; use crate::{EmptyReplyMsg, StreamId}; #[derive(Serialize)] @@ -57,14 +58,6 @@ struct FrameUpdateMsg { } #[derive(Serialize)] -struct ResourceAvailableReply<T: Serialize> { - from: String, - #[serde(rename = "type")] - type_: String, - array: Vec<(String, Vec<T>)>, -} - -#[derive(Serialize)] struct TabNavigated { from: String, #[serde(rename = "type")] @@ -152,6 +145,16 @@ pub(crate) struct BrowsingContextActor { pub watcher: String, } +impl ResourceAvailable for BrowsingContextActor { + fn actor_name(&self) -> String { + self.name.clone() + } + + fn get_streams(&self) -> &RefCell<HashMap<StreamId, TcpStream>> { + &self.streams + } +} + impl Actor for BrowsingContextActor { fn name(&self) -> String { self.name.clone() @@ -358,26 +361,6 @@ impl BrowsingContextActor { }); } - pub(crate) fn resource_available<T: Serialize>(&self, resource: T, resource_type: String) { - self.resources_available(vec![resource], resource_type); - } - - pub(crate) fn resources_available<T: Serialize>( - &self, - resources: Vec<T>, - resource_type: String, - ) { - let msg = ResourceAvailableReply::<T> { - from: self.name(), - type_: "resources-available-array".into(), - array: vec![(resource_type, resources)], - }; - - for stream in self.streams.borrow_mut().values_mut() { - let _ = stream.write_json_packet(&msg); - } - } - pub fn simulate_color_scheme(&self, theme: Theme) -> Result<(), ()> { self.script_chan .send(SimulateColorScheme(self.active_pipeline_id.get(), theme)) diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs index ecd718e47d4..3897ffa0fce 100644 --- a/components/devtools/actors/console.rs +++ b/components/devtools/actors/console.rs @@ -30,6 +30,7 @@ use crate::actors::browsing_context::BrowsingContextActor; use crate::actors::object::ObjectActor; use crate::actors::worker::WorkerActor; use crate::protocol::JsonPacketStream; +use crate::resource::ResourceAvailable; use crate::{StreamId, UniqueId}; trait EncodableConsoleMessage { diff --git a/components/devtools/actors/watcher.rs b/components/devtools/actors/watcher.rs index 77f82c1023a..d48374fc523 100644 --- a/components/devtools/actors/watcher.rs +++ b/components/devtools/actors/watcher.rs @@ -29,6 +29,7 @@ use crate::actors::watcher::thread_configuration::{ ThreadConfigurationActor, ThreadConfigurationActorMsg, }; use crate::protocol::JsonPacketStream; +use crate::resource::ResourceAvailable; use crate::{EmptyReplyMsg, StreamId}; pub mod network_parent; diff --git a/components/devtools/actors/worker.rs b/components/devtools/actors/worker.rs index 046befe9dc9..42c9d9a9c28 100644 --- a/components/devtools/actors/worker.rs +++ b/components/devtools/actors/worker.rs @@ -17,6 +17,7 @@ use servo_url::ServoUrl; use crate::StreamId; use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; use crate::protocol::JsonPacketStream; +use crate::resource::ResourceAvailable; #[derive(Clone, Copy)] #[allow(dead_code)] @@ -53,6 +54,16 @@ impl WorkerActor { } } +impl ResourceAvailable for WorkerActor { + fn actor_name(&self) -> String { + self.name.clone() + } + + fn get_streams(&self) -> &RefCell<HashMap<StreamId, TcpStream>> { + &self.streams + } +} + impl Actor for WorkerActor { fn name(&self) -> String { self.name.clone() diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index 74b028d5655..d4c3095b025 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -30,6 +30,7 @@ use devtools_traits::{ use embedder_traits::{AllowOrDeny, EmbedderMsg, EmbedderProxy}; use ipc_channel::ipc::{self, IpcSender}; use log::trace; +use resource::ResourceAvailable; use serde::Serialize; use servo_rand::RngCore; @@ -75,6 +76,7 @@ mod actors { mod id; mod network_handler; mod protocol; +mod resource; #[derive(Clone, Debug, Eq, Hash, PartialEq)] enum UniqueId { diff --git a/components/devtools/resource.rs b/components/devtools/resource.rs new file mode 100644 index 00000000000..7cef8188cc8 --- /dev/null +++ b/components/devtools/resource.rs @@ -0,0 +1,42 @@ +/* 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::cell::RefCell; +use std::collections::HashMap; +use std::net::TcpStream; + +use serde::Serialize; + +use crate::StreamId; +use crate::protocol::JsonPacketStream; + +#[derive(Serialize)] +pub(crate) struct ResourceAvailableReply<T: Serialize> { + pub from: String, + #[serde(rename = "type")] + pub type_: String, + pub array: Vec<(String, Vec<T>)>, +} + +pub(crate) trait ResourceAvailable { + fn actor_name(&self) -> String; + + fn get_streams(&self) -> &RefCell<HashMap<StreamId, TcpStream>>; + + fn resource_available<T: Serialize>(&self, resource: T, resource_type: String) { + self.resources_available(vec![resource], resource_type); + } + + fn resources_available<T: Serialize>(&self, resources: Vec<T>, resource_type: String) { + let msg = ResourceAvailableReply::<T> { + from: self.actor_name(), + type_: "resources-available-array".into(), + array: vec![(resource_type, resources)], + }; + + for stream in self.get_streams().borrow_mut().values_mut() { + let _ = stream.write_json_packet(&msg); + } + } +} diff --git a/components/layout/flow/root.rs b/components/layout/flow/root.rs index 390b4664e60..e8b7b6f5402 100644 --- a/components/layout/flow/root.rs +++ b/components/layout/flow/root.rs @@ -428,13 +428,14 @@ impl BoxTree { acc.union(&child_overflow) }); - FragmentTree { + FragmentTree::new( + layout_context, root_fragments, scrollable_overflow, - initial_containing_block: physical_containing_block, - canvas_background: self.canvas_background.clone(), - viewport_scroll_sensitivity: self.viewport_scroll_sensitivity, - } + physical_containing_block, + self.canvas_background.clone(), + self.viewport_scroll_sensitivity, + ) } } diff --git a/components/layout/fragment_tree/box_fragment.rs b/components/layout/fragment_tree/box_fragment.rs index 30be154caf1..0e83c0d71a6 100644 --- a/components/layout/fragment_tree/box_fragment.rs +++ b/components/layout/fragment_tree/box_fragment.rs @@ -65,6 +65,10 @@ pub(crate) struct BoxFragment { /// does not include padding, border, or margin -- it only includes content. pub content_rect: PhysicalRect<Au>, + /// This [`BoxFragment`]'s containing block rectangle in coordinates relative to + /// the initial containing block, but not taking into account any transforms. + pub cumulative_containing_block_rect: PhysicalRect<Au>, + pub padding: PhysicalSides<Au>, pub border: PhysicalSides<Au>, pub margin: PhysicalSides<Au>, @@ -120,6 +124,7 @@ impl BoxFragment { style, children, content_rect, + cumulative_containing_block_rect: Default::default(), padding, border, margin, @@ -195,6 +200,8 @@ impl BoxFragment { self } + /// Get the scrollable overflow for this [`BoxFragment`] relative to its + /// containing block. pub fn scrollable_overflow(&self) -> PhysicalRect<Au> { let physical_padding_rect = self.padding_rect(); let content_origin = self.content_rect.origin.to_vector(); @@ -205,6 +212,10 @@ impl BoxFragment { ) } + pub fn offset_by_containing_block(&self, rect: &PhysicalRect<Au>) -> PhysicalRect<Au> { + rect.translate(self.cumulative_containing_block_rect.origin.to_vector()) + } + pub(crate) fn padding_rect(&self) -> PhysicalRect<Au> { self.content_rect.outer_rect(self.padding) } @@ -278,10 +289,7 @@ impl BoxFragment { overflow } - pub(crate) fn calculate_resolved_insets_if_positioned( - &self, - containing_block: &PhysicalRect<Au>, - ) -> PhysicalSides<AuOrAuto> { + pub(crate) fn calculate_resolved_insets_if_positioned(&self) -> PhysicalSides<AuOrAuto> { let position = self.style.get_box().position; debug_assert_ne!( position, @@ -309,7 +317,10 @@ impl BoxFragment { // used value. Otherwise the resolved value is the computed value." // https://drafts.csswg.org/cssom/#resolved-values let insets = self.style.physical_box_offsets(); - let (cb_width, cb_height) = (containing_block.width(), containing_block.height()); + let (cb_width, cb_height) = ( + self.cumulative_containing_block_rect.width(), + self.cumulative_containing_block_rect.height(), + ); if position == ComputedPosition::Relative { let get_resolved_axis = |start: &LengthPercentageOrAuto, end: &LengthPercentageOrAuto, @@ -394,4 +405,8 @@ impl BoxFragment { _ => CollapsedBlockMargins::zero(), } } + + pub(crate) fn set_containing_block(&mut self, containing_block: &PhysicalRect<Au>) { + self.cumulative_containing_block_rect = *containing_block; + } } diff --git a/components/layout/fragment_tree/fragment.rs b/components/layout/fragment_tree/fragment.rs index d0d1b9b1104..c08ddae55e9 100644 --- a/components/layout/fragment_tree/fragment.rs +++ b/components/layout/fragment_tree/fragment.rs @@ -112,6 +112,7 @@ impl Fragment { Fragment::Float(fragment) => fragment.borrow().base.clone(), }) } + pub(crate) fn mutate_content_rect(&mut self, callback: impl FnOnce(&mut PhysicalRect<Au>)) { match self { Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => { @@ -124,6 +125,26 @@ impl Fragment { } } + pub(crate) fn set_containing_block(&self, containing_block: &PhysicalRect<Au>) { + match self { + Fragment::Box(box_fragment) => box_fragment + .borrow_mut() + .set_containing_block(containing_block), + Fragment::Float(float_fragment) => float_fragment + .borrow_mut() + .set_containing_block(containing_block), + Fragment::Positioning(_) => {}, + Fragment::AbsoluteOrFixedPositioned(hoisted_shared_fragment) => { + if let Some(ref fragment) = hoisted_shared_fragment.borrow().fragment { + fragment.set_containing_block(containing_block); + } + }, + Fragment::Text(_) => {}, + Fragment::Image(_) => {}, + Fragment::IFrame(_) => {}, + } + } + pub fn tag(&self) -> Option<Tag> { self.base().and_then(|base| base.tag) } @@ -146,12 +167,12 @@ impl Fragment { } } - pub fn scrolling_area(&self, containing_block: &PhysicalRect<Au>) -> PhysicalRect<Au> { + pub fn scrolling_area(&self) -> PhysicalRect<Au> { match self { - Fragment::Box(fragment) | Fragment::Float(fragment) => fragment - .borrow() - .scrollable_overflow() - .translate(containing_block.origin.to_vector()), + Fragment::Box(fragment) | Fragment::Float(fragment) => { + let fragment = fragment.borrow(); + fragment.offset_by_containing_block(&fragment.scrollable_overflow()) + }, _ => self.scrollable_overflow(), } } diff --git a/components/layout/fragment_tree/fragment_tree.rs b/components/layout/fragment_tree/fragment_tree.rs index bb3c659466c..589ae69e8e5 100644 --- a/components/layout/fragment_tree/fragment_tree.rs +++ b/components/layout/fragment_tree/fragment_tree.rs @@ -13,6 +13,7 @@ use style::dom::OpaqueNode; use webrender_api::units; use super::{ContainingBlockManager, Fragment, Tag}; +use crate::context::LayoutContext; use crate::display_list::StackingContext; use crate::flow::CanvasBackground; use crate::geom::{PhysicalPoint, PhysicalRect}; @@ -44,6 +45,58 @@ pub struct FragmentTree { } impl FragmentTree { + pub(crate) fn new( + layout_context: &LayoutContext, + root_fragments: Vec<Fragment>, + scrollable_overflow: PhysicalRect<Au>, + initial_containing_block: PhysicalRect<Au>, + canvas_background: CanvasBackground, + viewport_scroll_sensitivity: AxesScrollSensitivity, + ) -> Self { + let fragment_tree = Self { + root_fragments, + scrollable_overflow, + initial_containing_block, + canvas_background, + viewport_scroll_sensitivity, + }; + + // As part of building the fragment tree, we want to stop animating elements and + // pseudo-elements that used to be animating or had animating images attached to + // them. Create a set of all elements that used to be animating. + let mut animations = layout_context.style_context.animations.sets.write(); + let mut invalid_animating_nodes: FxHashSet<_> = animations.keys().cloned().collect(); + let mut image_animations = layout_context.node_image_animation_map.write().to_owned(); + let mut invalid_image_animating_nodes: FxHashSet<_> = image_animations + .keys() + .cloned() + .map(|node| AnimationSetKey::new(node, None)) + .collect(); + + fragment_tree.find(|fragment, _level, containing_block| { + if let Some(tag) = fragment.tag() { + invalid_animating_nodes.remove(&AnimationSetKey::new(tag.node, tag.pseudo)); + invalid_image_animating_nodes.remove(&AnimationSetKey::new(tag.node, tag.pseudo)); + } + + fragment.set_containing_block(containing_block); + None::<()> + }); + + // Cancel animations for any elements and pseudo-elements that are no longer found + // in the fragment tree. + for node in &invalid_animating_nodes { + if let Some(state) = animations.get_mut(node) { + state.cancel_all_animations(); + } + } + for node in &invalid_image_animating_nodes { + image_animations.remove(&node.node); + } + + fragment_tree + } + pub(crate) fn build_display_list( &self, builder: &mut crate::display_list::DisplayListBuilder, @@ -86,14 +139,6 @@ impl FragmentTree { .find_map(|child| child.find(&info, 0, &mut process_func)) } - pub fn remove_nodes_in_fragment_tree_from_set(&self, set: &mut FxHashSet<AnimationSetKey>) { - self.find(|fragment, _, _| { - let tag = fragment.tag()?; - set.remove(&AnimationSetKey::new(tag.node, tag.pseudo)); - None::<()> - }); - } - /// Get the vector of rectangles that surrounds the fragments of the node with the given address. /// This function answers the `getClientRects()` query and the union of the rectangles answers /// the `getBoundingClientRect()` query. @@ -173,22 +218,8 @@ impl FragmentTree { pub fn get_scrolling_area_for_viewport(&self) -> PhysicalRect<Au> { let mut scroll_area = self.initial_containing_block; for fragment in self.root_fragments.iter() { - scroll_area = fragment - .scrolling_area(&self.initial_containing_block) - .union(&scroll_area); + scroll_area = fragment.scrolling_area().union(&scroll_area); } scroll_area } - - pub fn get_scrolling_area_for_node(&self, requested_node: OpaqueNode) -> PhysicalRect<Au> { - let tag_to_find = Tag::new(requested_node); - let scroll_area = self.find(|fragment, _, containing_block| { - if fragment.tag() == Some(tag_to_find) { - Some(fragment.scrolling_area(containing_block)) - } else { - None - } - }); - scroll_area.unwrap_or_else(PhysicalRect::<Au>::zero) - } } diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index c661f2c2c7b..361760692d2 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -23,7 +23,7 @@ use euclid::{Point2D, Scale, Size2D, Vector2D}; use fnv::FnvHashMap; use fonts::{FontContext, FontContextWebFontMethods}; use fonts_traits::StylesheetWebFontLoadFinishedCallback; -use fxhash::{FxHashMap, FxHashSet}; +use fxhash::FxHashMap; use ipc_channel::ipc::IpcSender; use log::{debug, error}; use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps}; @@ -37,15 +37,15 @@ use profile_traits::{path, time_profile}; use rayon::ThreadPool; use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode}; use script_layout_interface::{ - ImageAnimationState, Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, - OffsetParentResponse, ReflowGoal, ReflowRequest, ReflowResult, TrustedNodeAddress, + Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, ReflowGoal, + ReflowRequest, ReflowResult, TrustedNodeAddress, }; use script_traits::{DrawAPaintImageResult, PaintWorkletError, Painter, ScriptThreadMessage}; use servo_arc::Arc as ServoArc; use servo_config::opts::{self, DebugOptions}; use servo_config::pref; use servo_url::ServoUrl; -use style::animation::{AnimationSetKey, DocumentAnimationSet}; +use style::animation::DocumentAnimationSet; use style::context::{ QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters, SharedStyleContext, }; @@ -330,14 +330,7 @@ impl Layout for LayoutThread { TraversalFlags::empty(), ); - let fragment_tree = self.fragment_tree.borrow().clone(); - process_resolved_style_request( - &shared_style_context, - node, - &pseudo, - &property_id, - fragment_tree, - ) + process_resolved_style_request(&shared_style_context, node, &pseudo, &property_id) } #[cfg_attr( @@ -380,7 +373,8 @@ impl Layout for LayoutThread { feature = "tracing", tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") )] - fn query_scrolling_area(&self, node: Option<OpaqueNode>) -> UntypedRect<i32> { + fn query_scrolling_area(&self, node: Option<TrustedNodeAddress>) -> UntypedRect<i32> { + let node = node.map(|node| unsafe { ServoLayoutNode::new(&node) }); process_node_scroll_area_request(node, self.fragment_tree.borrow().clone()) } @@ -790,18 +784,6 @@ impl LayoutThread { run_layout() }); - Self::cancel_animations_for_nodes_not_in_fragment_tree( - &recalc_style_traversal.context().style_context.animations, - &fragment_tree, - ); - Self::cancel_image_animation_for_nodes_not_in_fragment_tree( - recalc_style_traversal - .context() - .node_image_animation_map - .clone(), - &fragment_tree, - ); - *self.fragment_tree.borrow_mut() = Some(fragment_tree); if self.debug.dump_style_tree { @@ -922,42 +904,6 @@ impl LayoutThread { }) } - /// Cancel animations for any nodes which have been removed from fragment tree. - /// TODO(mrobinson): We should look into a way of doing this during flow tree construction. - /// This also doesn't yet handles nodes that have been reparented. - fn cancel_animations_for_nodes_not_in_fragment_tree( - animations: &DocumentAnimationSet, - root: &FragmentTree, - ) { - // Assume all nodes have been removed until proven otherwise. - let mut animations = animations.sets.write(); - let mut invalid_nodes = animations.keys().cloned().collect(); - root.remove_nodes_in_fragment_tree_from_set(&mut invalid_nodes); - - // Cancel animations for any nodes that are no longer in the fragment tree. - for node in &invalid_nodes { - if let Some(state) = animations.get_mut(node) { - state.cancel_all_animations(); - } - } - } - - fn cancel_image_animation_for_nodes_not_in_fragment_tree( - image_animation_set: Arc<RwLock<FxHashMap<OpaqueNode, ImageAnimationState>>>, - root: &FragmentTree, - ) { - let mut image_animations = image_animation_set.write().to_owned(); - let mut invalid_nodes: FxHashSet<AnimationSetKey> = image_animations - .keys() - .cloned() - .map(|node| AnimationSetKey::new(node, None)) - .collect(); - root.remove_nodes_in_fragment_tree_from_set(&mut invalid_nodes); - for node in &invalid_nodes { - image_animations.remove(&node.node); - } - } - fn viewport_did_change(&mut self, viewport_details: ViewportDetails) -> bool { let new_pixel_ratio = viewport_details.hidpi_scale_factor.get(); let new_viewport_size = Size2D::new( diff --git a/components/layout/query.rs b/components/layout/query.rs index 08b264deea9..3409f7c1923 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -83,14 +83,21 @@ pub fn process_node_geometry_request( } /// <https://drafts.csswg.org/cssom-view/#scrolling-area> -pub fn process_node_scroll_area_request( - requested_node: Option<OpaqueNode>, +pub fn process_node_scroll_area_request<'dom>( + requested_node: Option<impl LayoutNode<'dom> + 'dom>, fragment_tree: Option<Arc<FragmentTree>>, ) -> Rect<i32> { - let rect = match (fragment_tree, requested_node) { - (Some(tree), Some(node)) => tree.get_scrolling_area_for_node(node), - (Some(tree), None) => tree.get_scrolling_area_for_viewport(), - _ => return Rect::zero(), + let Some(tree) = fragment_tree else { + return Rect::zero(); + }; + + let rect = match requested_node { + Some(node) => node + .fragments_for_pseudo(None) + .first() + .map(Fragment::scrolling_area) + .unwrap_or_default(), + None => tree.get_scrolling_area_for_viewport(), }; Rect::new( @@ -109,7 +116,6 @@ pub fn process_resolved_style_request<'dom>( node: impl LayoutNode<'dom> + 'dom, pseudo: &Option<PseudoElement>, property: &PropertyId, - fragment_tree: Option<Arc<FragmentTree>>, ) -> String { if !node.as_element().unwrap().has_data() { return process_resolved_style_request_for_unstyled_node(context, node, pseudo, property); @@ -161,8 +167,6 @@ pub fn process_resolved_style_request<'dom>( _ => style.computed_value_to_string(PropertyDeclarationId::Longhand(longhand_id)), }; - let tag_to_find = Tag::new_pseudo(node.opaque(), *pseudo); - // https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle // Here we are trying to conform to the specification that says that getComputedStyle // should return the used values in certain circumstances. For size and positional @@ -191,107 +195,87 @@ pub fn process_resolved_style_request<'dom>( return computed_style(None); } - let resolve_for_fragment = - |fragment: &Fragment, containing_block: Option<&PhysicalRect<Au>>| { - let (content_rect, margins, padding, specific_layout_info) = match fragment { - Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => { - let box_fragment = box_fragment.borrow(); - if style.get_box().position != Position::Static { - let resolved_insets = || { - box_fragment - .calculate_resolved_insets_if_positioned(containing_block.unwrap()) - }; - match longhand_id { - LonghandId::Top => return resolved_insets().top.to_css_string(), - LonghandId::Right => { - return resolved_insets().right.to_css_string(); - }, - LonghandId::Bottom => { - return resolved_insets().bottom.to_css_string(); - }, - LonghandId::Left => { - return resolved_insets().left.to_css_string(); - }, - _ => {}, - } - } - let content_rect = box_fragment.content_rect; - let margins = box_fragment.margin; - let padding = box_fragment.padding; - let specific_layout_info = box_fragment.specific_layout_info.clone(); - (content_rect, margins, padding, specific_layout_info) - }, - Fragment::Positioning(positioning_fragment) => { - let content_rect = positioning_fragment.borrow().rect; - ( - content_rect, - SideOffsets2D::zero(), - SideOffsets2D::zero(), - None, - ) - }, - _ => return computed_style(Some(fragment)), - }; - - // https://drafts.csswg.org/css-grid/#resolved-track-list - // > The grid-template-rows and grid-template-columns properties are - // > resolved value special case properties. - // - // > When an element generates a grid container box... - if display.inside() == DisplayInside::Grid { - if let Some(SpecificLayoutInfo::Grid(info)) = specific_layout_info { - if let Some(value) = resolve_grid_template(&info, style, longhand_id) { - return value; + let resolve_for_fragment = |fragment: &Fragment| { + let (content_rect, margins, padding, specific_layout_info) = match fragment { + Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => { + let box_fragment = box_fragment.borrow(); + if style.get_box().position != Position::Static { + let resolved_insets = || box_fragment.calculate_resolved_insets_if_positioned(); + match longhand_id { + LonghandId::Top => return resolved_insets().top.to_css_string(), + LonghandId::Right => { + return resolved_insets().right.to_css_string(); + }, + LonghandId::Bottom => { + return resolved_insets().bottom.to_css_string(); + }, + LonghandId::Left => { + return resolved_insets().left.to_css_string(); + }, + _ => {}, } } - } + let content_rect = box_fragment.content_rect; + let margins = box_fragment.margin; + let padding = box_fragment.padding; + let specific_layout_info = box_fragment.specific_layout_info.clone(); + (content_rect, margins, padding, specific_layout_info) + }, + Fragment::Positioning(positioning_fragment) => { + let content_rect = positioning_fragment.borrow().rect; + ( + content_rect, + SideOffsets2D::zero(), + SideOffsets2D::zero(), + None, + ) + }, + _ => return computed_style(Some(fragment)), + }; - // https://drafts.csswg.org/cssom/#resolved-value-special-case-property-like-height - // > If the property applies to the element or pseudo-element and the resolved value of the - // > display property is not none or contents, then the resolved value is the used value. - // > Otherwise the resolved value is the computed value. - // - // However, all browsers ignore that for margin and padding properties, and resolve to a length - // even if the property doesn't apply: https://github.com/w3c/csswg-drafts/issues/10391 - match longhand_id { - LonghandId::Width if resolved_size_should_be_used_value(fragment) => { - content_rect.size.width - }, - LonghandId::Height if resolved_size_should_be_used_value(fragment) => { - content_rect.size.height - }, - LonghandId::MarginBottom => margins.bottom, - LonghandId::MarginTop => margins.top, - LonghandId::MarginLeft => margins.left, - LonghandId::MarginRight => margins.right, - LonghandId::PaddingBottom => padding.bottom, - LonghandId::PaddingTop => padding.top, - LonghandId::PaddingLeft => padding.left, - LonghandId::PaddingRight => padding.right, - _ => return computed_style(Some(fragment)), + // https://drafts.csswg.org/css-grid/#resolved-track-list + // > The grid-template-rows and grid-template-columns properties are + // > resolved value special case properties. + // + // > When an element generates a grid container box... + if display.inside() == DisplayInside::Grid { + if let Some(SpecificLayoutInfo::Grid(info)) = specific_layout_info { + if let Some(value) = resolve_grid_template(&info, style, longhand_id) { + return value; + } } - .to_css_string() - }; + } - if !matches!( - longhand_id, - LonghandId::Top | LonghandId::Bottom | LonghandId::Left | LonghandId::Right - ) { - if let Some(fragment) = node.fragments_for_pseudo(*pseudo).first() { - return resolve_for_fragment(fragment, None); + // https://drafts.csswg.org/cssom/#resolved-value-special-case-property-like-height + // > If the property applies to the element or pseudo-element and the resolved value of the + // > display property is not none or contents, then the resolved value is the used value. + // > Otherwise the resolved value is the computed value. + // + // However, all browsers ignore that for margin and padding properties, and resolve to a length + // even if the property doesn't apply: https://github.com/w3c/csswg-drafts/issues/10391 + match longhand_id { + LonghandId::Width if resolved_size_should_be_used_value(fragment) => { + content_rect.size.width + }, + LonghandId::Height if resolved_size_should_be_used_value(fragment) => { + content_rect.size.height + }, + LonghandId::MarginBottom => margins.bottom, + LonghandId::MarginTop => margins.top, + LonghandId::MarginLeft => margins.left, + LonghandId::MarginRight => margins.right, + LonghandId::PaddingBottom => padding.bottom, + LonghandId::PaddingTop => padding.top, + LonghandId::PaddingLeft => padding.left, + LonghandId::PaddingRight => padding.right, + _ => return computed_style(Some(fragment)), } - } + .to_css_string() + }; - fragment_tree - .and_then(|fragment_tree| { - fragment_tree.find(|fragment, _, containing_block| { - if Some(tag_to_find) == fragment.tag() { - Some(resolve_for_fragment(fragment, Some(containing_block))) - } else { - None - } - }) - }) + node.fragments_for_pseudo(*pseudo) + .first() + .map(resolve_for_fragment) .unwrap_or_else(|| computed_style(None)) } diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index b0fd301df6a..f5bd03cd8d7 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -93,6 +93,7 @@ pub(crate) fn throw_dom_exception( Error::NotReadable => DOMErrorName::NotReadableError, Error::Data => DOMErrorName::DataError, Error::Operation => DOMErrorName::OperationError, + Error::NotAllowed => DOMErrorName::NotAllowedError, Error::Type(message) => unsafe { assert!(!JS_IsExceptionPending(*cx)); throw_type_error(*cx, &message); diff --git a/components/script/dom/bindings/serializable.rs b/components/script/dom/bindings/serializable.rs index 4aa1a94a0a4..d0e851b4799 100644 --- a/components/script/dom/bindings/serializable.rs +++ b/components/script/dom/bindings/serializable.rs @@ -11,7 +11,7 @@ use base::id::{Index, NamespaceIndex, PipelineNamespaceId}; use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; +use crate::dom::bindings::structuredclone::StructuredData; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::CanGc; @@ -65,13 +65,7 @@ where /// Returns the field of [StructuredDataReader]/[StructuredDataWriter] that /// should be used to read/store serialized instances of this type. - fn serialized_storage( - data: StructuredData<'_>, - ) -> &mut Option<HashMap<NamespaceIndex<Self::Index>, Self::Data>>; - - /// Returns the field of [StructuredDataReader] that should be used to store - /// deserialized instances of this type. - fn deserialized_storage( - reader: &mut StructuredDataReader, - ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>>; + fn serialized_storage<'a>( + data: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<NamespaceIndex<Self::Index>, Self::Data>>; } diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs index 915a4951bb5..c9a49ba00c9 100644 --- a/components/script/dom/bindings/structuredclone.rs +++ b/components/script/dom/bindings/structuredclone.rs @@ -16,13 +16,14 @@ use constellation_traits::{ BlobImpl, DomException, DomPoint, MessagePortImpl, Serializable as SerializableInterface, StructuredSerializedData, Transferrable as TransferrableInterface, }; +use js::gc::RootedVec; use js::glue::{ CopyJSStructuredCloneData, DeleteJSAutoStructuredCloneBuffer, GetLengthOfJSStructuredCloneData, NewJSAutoStructuredCloneBuffer, WriteBytesToJSStructuredCloneData, }; use js::jsapi::{ - CloneDataPolicy, HandleObject as RawHandleObject, JS_ClearPendingException, JS_ReadUint32Pair, - JS_STRUCTURED_CLONE_VERSION, JS_WriteUint32Pair, JSContext, JSObject, + CloneDataPolicy, HandleObject as RawHandleObject, Heap, JS_ClearPendingException, + JS_ReadUint32Pair, JS_STRUCTURED_CLONE_VERSION, JS_WriteUint32Pair, JSContext, JSObject, JSStructuredCloneCallbacks, JSStructuredCloneReader, JSStructuredCloneWriter, MutableHandleObject as RawMutableHandleObject, StructuredCloneScope, TransferableOwnership, }; @@ -93,7 +94,7 @@ fn reader_for_type( ) -> unsafe fn( &GlobalScope, *mut JSStructuredCloneReader, - &mut StructuredDataReader, + &mut StructuredDataReader<'_>, CanGc, ) -> *mut JSObject { match val { @@ -107,7 +108,7 @@ fn reader_for_type( unsafe fn read_object<T: Serializable>( owner: &GlobalScope, r: *mut JSStructuredCloneReader, - sc_reader: &mut StructuredDataReader, + sc_reader: &mut StructuredDataReader<'_>, can_gc: CanGc, ) -> *mut JSObject { let mut name_space: u32 = 0; @@ -136,9 +137,8 @@ unsafe fn read_object<T: Serializable>( } if let Ok(obj) = T::deserialize(owner, serialized, can_gc) { - let destination = T::deserialized_storage(sc_reader).get_or_insert_with(HashMap::new); let reflector = obj.reflector().get_jsobject().get(); - destination.insert(storage_key, obj); + sc_reader.roots.push(Heap::boxed(reflector)); return reflector; } warn!("Reading structured data failed in {:?}.", owner.get_url()); @@ -191,7 +191,7 @@ unsafe extern "C" fn read_callback( "tag should be higher than StructuredCloneTags::Min" ); - let sc_reader = &mut *(closure as *mut StructuredDataReader); + let sc_reader = &mut *(closure as *mut StructuredDataReader<'_>); let in_realm_proof = AlreadyInRealm::assert_for_cx(SafeJSContext::from_ptr(cx)); let global = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof)); for serializable in SerializableInterface::iter() { @@ -259,7 +259,8 @@ unsafe extern "C" fn write_callback( fn receiver_for_type( val: TransferrableInterface, -) -> fn(&GlobalScope, &mut StructuredDataReader, u64, RawMutableHandleObject) -> Result<(), ()> { +) -> fn(&GlobalScope, &mut StructuredDataReader<'_>, u64, RawMutableHandleObject) -> Result<(), ()> +{ match val { TransferrableInterface::MessagePort => receive_object::<MessagePort>, TransferrableInterface::ReadableStream => receive_object::<ReadableStream>, @@ -269,7 +270,7 @@ fn receiver_for_type( fn receive_object<T: Transferable>( owner: &GlobalScope, - sc_reader: &mut StructuredDataReader, + sc_reader: &mut StructuredDataReader<'_>, extra_data: u64, return_object: RawMutableHandleObject, ) -> Result<(), ()> { @@ -305,13 +306,12 @@ fn receive_object<T: Transferable>( ); }; - if let Ok(received) = T::transfer_receive(owner, id, serialized) { - return_object.set(received.reflector().rootable().get()); - let storage = T::deserialized_storage(sc_reader).get_or_insert_with(Vec::new); - storage.push(received); - return Ok(()); - } - Err(()) + let Ok(received) = T::transfer_receive(owner, id, serialized) else { + return Err(()); + }; + return_object.set(received.reflector().rootable().get()); + sc_reader.roots.push(Heap::boxed(return_object.get())); + Ok(()) } unsafe extern "C" fn read_transfer_callback( @@ -324,7 +324,7 @@ unsafe extern "C" fn read_transfer_callback( closure: *mut raw::c_void, return_object: RawMutableHandleObject, ) -> bool { - let sc_reader = &mut *(closure as *mut StructuredDataReader); + let sc_reader = &mut *(closure as *mut StructuredDataReader<'_>); let in_realm_proof = AlreadyInRealm::assert_for_cx(SafeJSContext::from_ptr(cx)); let owner = GlobalScope::from_context(cx, InRealm::Already(&in_realm_proof)); @@ -489,8 +489,8 @@ static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredClon sabCloned: Some(sab_cloned_callback), }; -pub(crate) enum StructuredData<'a> { - Reader(&'a mut StructuredDataReader), +pub(crate) enum StructuredData<'a, 'b> { + Reader(&'a mut StructuredDataReader<'b>), Writer(&'a mut StructuredDataWriter), } @@ -503,19 +503,11 @@ pub(crate) struct DOMErrorRecord { /// Reader and writer structs for results from, and inputs to, structured-data read/write operations. /// <https://html.spec.whatwg.org/multipage/#safe-passing-of-structured-data> #[repr(C)] -pub(crate) struct StructuredDataReader { +pub(crate) struct StructuredDataReader<'a> { /// A struct of error message. - pub(crate) errors: DOMErrorRecord, - /// A map of deserialized blobs, stored temporarily here to keep them rooted. - pub(crate) blobs: Option<HashMap<StorageKey, DomRoot<Blob>>>, - /// A map of deserialized points, stored temporarily here to keep them rooted. - pub(crate) points_read_only: Option<HashMap<StorageKey, DomRoot<DOMPointReadOnly>>>, - pub(crate) dom_points: Option<HashMap<StorageKey, DomRoot<DOMPoint>>>, - /// A map of deserialized exceptions, stored temporarily here to keep them rooted. - pub(crate) dom_exceptions: Option<HashMap<StorageKey, DomRoot<DOMException>>>, - /// A vec of transfer-received DOM ports, - /// to be made available to script through a message event. - pub(crate) message_ports: Option<Vec<DomRoot<MessagePort>>>, + errors: DOMErrorRecord, + /// Rooted copies of every deserialized object to ensure they are not garbage collected. + roots: RootedVec<'a, Box<Heap<*mut JSObject>>>, /// A map of port implementations, /// used as part of the "transfer-receiving" steps of ports, /// to produce the DOM ports stored in `message_ports` above. @@ -528,12 +520,6 @@ pub(crate) struct StructuredDataReader { pub(crate) points: Option<HashMap<DomPointId, DomPoint>>, /// A map of serialized exceptions. pub(crate) exceptions: Option<HashMap<DomExceptionId, DomException>>, - - /// <https://streams.spec.whatwg.org/#rs-transfer> - pub(crate) readable_streams: Option<Vec<DomRoot<ReadableStream>>>, - - /// <https://streams.spec.whatwg.org/#ws-transfer> - pub(crate) writable_streams: Option<Vec<DomRoot<WritableStream>>>, } /// A data holder for transferred and serialized objects. @@ -618,19 +604,14 @@ pub(crate) fn read( ) -> Fallible<Vec<DomRoot<MessagePort>>> { let cx = GlobalScope::get_cx(); let _ac = enter_realm(global); + rooted_vec!(let mut roots); let mut sc_reader = StructuredDataReader { - blobs: None, - message_ports: None, - points_read_only: None, - dom_points: None, - dom_exceptions: None, + roots, port_impls: data.ports.take(), blob_impls: data.blobs.take(), points: data.points.take(), exceptions: data.exceptions.take(), errors: DOMErrorRecord { message: None }, - readable_streams: None, - writable_streams: None, }; let sc_reader_ptr = &mut sc_reader as *mut _; unsafe { @@ -666,8 +647,15 @@ pub(crate) fn read( DeleteJSAutoStructuredCloneBuffer(scbuf); + let mut message_ports = vec![]; + for reflector in sc_reader.roots.iter() { + let Ok(message_port) = root_from_object::<MessagePort>(reflector.get(), *cx) else { + continue; + }; + message_ports.push(message_port); + } // Any transfer-received port-impls should have been taken out. assert!(sc_reader.port_impls.is_none()); - Ok(sc_reader.message_ports.take().unwrap_or_default()) + Ok(message_ports) } } diff --git a/components/script/dom/bindings/transferable.rs b/components/script/dom/bindings/transferable.rs index b720c05ae37..e6b2f000f3a 100644 --- a/components/script/dom/bindings/transferable.rs +++ b/components/script/dom/bindings/transferable.rs @@ -12,7 +12,7 @@ use base::id::NamespaceIndex; use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; +use crate::dom::bindings::structuredclone::StructuredData; use crate::dom::globalscope::GlobalScope; pub(crate) trait Transferable: DomObject where @@ -32,8 +32,7 @@ where serialized: Self::Data, ) -> Result<DomRoot<Self>, ()>; - fn serialized_storage( - data: StructuredData<'_>, - ) -> &mut Option<HashMap<NamespaceIndex<Self::Index>, Self::Data>>; - fn deserialized_storage(reader: &mut StructuredDataReader) -> &mut Option<Vec<DomRoot<Self>>>; + fn serialized_storage<'a>( + data: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<NamespaceIndex<Self::Index>, Self::Data>>; } diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index df2afafd698..27aa382c3fc 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -24,9 +24,9 @@ use crate::dom::bindings::codegen::UnionTypes::ArrayBufferOrArrayBufferViewOrBlo use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto}; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::serializable::{Serializable, StorageKey}; +use crate::dom::bindings::serializable::Serializable; use crate::dom::bindings::str::DOMString; -use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; +use crate::dom::bindings::structuredclone::StructuredData; use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::dom::readablestream::ReadableStream; @@ -119,18 +119,14 @@ impl Serializable for Blob { Ok(deserialized_blob) } - fn serialized_storage(reader: StructuredData<'_>) -> &mut Option<HashMap<BlobId, Self::Data>> { + fn serialized_storage<'a>( + reader: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<BlobId, Self::Data>> { match reader { StructuredData::Reader(r) => &mut r.blob_impls, StructuredData::Writer(w) => &mut w.blobs, } } - - fn deserialized_storage( - data: &mut StructuredDataReader, - ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>> { - &mut data.blobs - } } /// Extract bytes from BlobParts, used by Blob and File constructor diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs index 421e8f45523..a367c9943de 100644 --- a/components/script/dom/cssstylesheet.rs +++ b/components/script/dom/cssstylesheet.rs @@ -24,7 +24,7 @@ use crate::dom::bindings::reflector::{ DomGlobal, reflect_dom_object, reflect_dom_object_with_proto, }; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; -use crate::dom::bindings::str::DOMString; +use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::cssrulelist::{CSSRuleList, RulesSource}; use crate::dom::element::Element; use crate::dom::medialist::MediaList; @@ -290,4 +290,32 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet { // > 8. Return -1. Ok(-1) } + + /// <https://drafts.csswg.org/cssom/#synchronously-replace-the-rules-of-a-cssstylesheet> + fn ReplaceSync(&self, text: USVString) -> Result<(), Error> { + // Step 1. If the constructed flag is not set throw a NotAllowedError + if !self.is_constructed { + return Err(Error::NotAllowed); + } + + // Step 2. Let rules be the result of running parse a stylesheet’s contents from text. + let global = self.global(); + let window = global.as_window(); + + StyleStyleSheet::update_from_str( + &self.style_stylesheet, + &text, + UrlExtraData(window.get_url().get_arc()), + None, + window.css_error_reporter(), + AllowImportRules::No, // Step 3.If rules contains one or more @import rules, remove those rules from rules. + ); + + // Step 4. Set sheet’s CSS rules to rules. + // We reset our rule list, which will be initialized properly + // at the next getter access. + self.rulelist.set(None); + + Ok(()) + } } diff --git a/components/script/dom/domexception.rs b/components/script/dom/domexception.rs index e63c3ff1f53..fbb807b7a95 100644 --- a/components/script/dom/domexception.rs +++ b/components/script/dom/domexception.rs @@ -17,9 +17,9 @@ use crate::dom::bindings::reflector::{ Reflector, reflect_dom_object, reflect_dom_object_with_proto, }; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::serializable::{Serializable, StorageKey}; +use crate::dom::bindings::serializable::Serializable; use crate::dom::bindings::str::DOMString; -use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; +use crate::dom::bindings::structuredclone::StructuredData; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::CanGc; @@ -53,6 +53,7 @@ pub(crate) enum DOMErrorName { NotReadableError, DataError, OperationError, + NotAllowedError, } impl DOMErrorName { @@ -84,6 +85,7 @@ impl DOMErrorName { "NotReadableError" => Some(DOMErrorName::NotReadableError), "DataError" => Some(DOMErrorName::DataError), "OperationError" => Some(DOMErrorName::OperationError), + "NotAllowedError" => Some(DOMErrorName::NotAllowedError), _ => None, } } @@ -135,6 +137,10 @@ impl DOMException { DOMErrorName::OperationError => { "The operation failed for an operation-specific reason." }, + DOMErrorName::NotAllowedError => { + r#"The request is not allowed by the user agent or the platform in the current context, + possibly because the user denied permission."# + }, }; ( @@ -252,18 +258,12 @@ impl Serializable for DOMException { )) } - fn serialized_storage( - data: StructuredData<'_>, - ) -> &mut Option<HashMap<DomExceptionId, Self::Data>> { + fn serialized_storage<'a>( + data: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<DomExceptionId, Self::Data>> { match data { StructuredData::Reader(reader) => &mut reader.exceptions, StructuredData::Writer(writer) => &mut writer.exceptions, } } - - fn deserialized_storage( - reader: &mut StructuredDataReader, - ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>> { - &mut reader.dom_exceptions - } } diff --git a/components/script/dom/dompoint.rs b/components/script/dom/dompoint.rs index 006abb50def..5e848c43c47 100644 --- a/components/script/dom/dompoint.rs +++ b/components/script/dom/dompoint.rs @@ -14,8 +14,8 @@ use crate::dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::DOMPointRe use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::reflect_dom_object_with_proto; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::serializable::{Serializable, StorageKey}; -use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; +use crate::dom::bindings::serializable::Serializable; +use crate::dom::bindings::structuredclone::StructuredData; use crate::dom::dompointreadonly::{DOMPointReadOnly, DOMPointWriteMethods}; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::CanGc; @@ -163,18 +163,12 @@ impl Serializable for DOMPoint { )) } - fn serialized_storage( - data: StructuredData<'_>, - ) -> &mut Option<HashMap<DomPointId, Self::Data>> { + fn serialized_storage<'a>( + data: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<DomPointId, Self::Data>> { match data { StructuredData::Reader(reader) => &mut reader.points, StructuredData::Writer(writer) => &mut writer.points, } } - - fn deserialized_storage( - reader: &mut StructuredDataReader, - ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>> { - &mut reader.dom_points - } } diff --git a/components/script/dom/dompointreadonly.rs b/components/script/dom/dompointreadonly.rs index 44e4a70b680..eb6bc9b93a9 100644 --- a/components/script/dom/dompointreadonly.rs +++ b/components/script/dom/dompointreadonly.rs @@ -15,8 +15,8 @@ use crate::dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::DOMPointRe use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto}; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::serializable::{Serializable, StorageKey}; -use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; +use crate::dom::bindings::serializable::Serializable; +use crate::dom::bindings::structuredclone::StructuredData; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::CanGc; @@ -172,18 +172,12 @@ impl Serializable for DOMPointReadOnly { )) } - fn serialized_storage( - data: StructuredData<'_>, - ) -> &mut Option<HashMap<DomPointId, Self::Data>> { + fn serialized_storage<'a>( + data: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<DomPointId, Self::Data>> { match data { StructuredData::Reader(r) => &mut r.points, StructuredData::Writer(w) => &mut w.points, } } - - fn deserialized_storage( - reader: &mut StructuredDataReader, - ) -> &mut Option<HashMap<StorageKey, DomRoot<Self>>> { - &mut reader.points_read_only - } } diff --git a/components/script/dom/messageport.rs b/components/script/dom/messageport.rs index fe590052db4..85d94c1aa7a 100644 --- a/components/script/dom/messageport.rs +++ b/components/script/dom/messageport.rs @@ -23,7 +23,7 @@ use crate::dom::bindings::error::{Error, ErrorResult, ErrorToJsval}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object}; use crate::dom::bindings::root::DomRoot; -use crate::dom::bindings::structuredclone::{self, StructuredData, StructuredDataReader}; +use crate::dom::bindings::structuredclone::{self, StructuredData}; use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::bindings::transferable::Transferable; use crate::dom::bindings::utils::set_dictionary_property; @@ -268,18 +268,14 @@ impl Transferable for MessagePort { Ok(transferred_port) } - fn serialized_storage( - data: StructuredData<'_>, - ) -> &mut Option<HashMap<MessagePortId, Self::Data>> { + fn serialized_storage<'a>( + data: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<MessagePortId, Self::Data>> { match data { StructuredData::Reader(r) => &mut r.port_impls, StructuredData::Writer(w) => &mut w.ports, } } - - fn deserialized_storage(reader: &mut StructuredDataReader) -> &mut Option<Vec<DomRoot<Self>>> { - &mut reader.message_ports - } } impl MessagePortMethods<crate::DomTypeHolder> for MessagePort { diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs index b445fb4b9fc..37899f18fec 100644 --- a/components/script/dom/readablestream.rs +++ b/components/script/dom/readablestream.rs @@ -59,7 +59,7 @@ use crate::realms::{enter_realm, InRealm}; use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler}; use crate::dom::bindings::transferable::Transferable; -use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; +use crate::dom::bindings::structuredclone::StructuredData; use super::bindings::buffer_source::HeapBufferSource; use super::bindings::codegen::Bindings::ReadableStreamBYOBReaderBinding::ReadableStreamBYOBReaderReadOptions; @@ -2247,16 +2247,12 @@ impl Transferable for ReadableStream { } /// Note: we are relying on the port transfer, so the data returned here are related to the port. - fn serialized_storage( - data: StructuredData<'_>, - ) -> &mut Option<HashMap<MessagePortId, Self::Data>> { + fn serialized_storage<'a>( + data: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<MessagePortId, Self::Data>> { match data { StructuredData::Reader(r) => &mut r.port_impls, StructuredData::Writer(w) => &mut w.ports, } } - - fn deserialized_storage(reader: &mut StructuredDataReader) -> &mut Option<Vec<DomRoot<Self>>> { - &mut reader.readable_streams - } } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 96176132b6b..efe61007ef8 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -2281,11 +2281,12 @@ impl Window { node: Option<&Node>, can_gc: CanGc, ) -> UntypedRect<i32> { - let opaque = node.map(|node| node.to_opaque()); if !self.layout_reflow(QueryMsg::ScrollingAreaQuery, can_gc) { return Rect::zero(); } - self.layout.borrow().query_scrolling_area(opaque) + self.layout + .borrow() + .query_scrolling_area(node.map(Node::to_trusted_node_address)) } pub(crate) fn scroll_offset_query(&self, node: &Node) -> Vector2D<f32, LayoutPixel> { diff --git a/components/script/dom/writablestream.rs b/components/script/dom/writablestream.rs index 1490fc694ef..e7e9ce906a6 100644 --- a/components/script/dom/writablestream.rs +++ b/components/script/dom/writablestream.rs @@ -27,7 +27,7 @@ use crate::dom::bindings::conversions::ConversionResult; use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; -use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader}; +use crate::dom::bindings::structuredclone::StructuredData; use crate::dom::bindings::transferable::Transferable; use crate::dom::countqueuingstrategy::{extract_high_water_mark, extract_size_algorithm}; use crate::dom::domexception::{DOMErrorName, DOMException}; @@ -1182,16 +1182,12 @@ impl Transferable for WritableStream { } /// Note: we are relying on the port transfer, so the data returned here are related to the port. - fn serialized_storage( - data: StructuredData<'_>, - ) -> &mut Option<HashMap<MessagePortId, Self::Data>> { + fn serialized_storage<'a>( + data: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<MessagePortId, Self::Data>> { match data { StructuredData::Reader(r) => &mut r.port_impls, StructuredData::Writer(w) => &mut w.ports, } } - - fn deserialized_storage(reader: &mut StructuredDataReader) -> &mut Option<Vec<DomRoot<Self>>> { - &mut reader.writable_streams - } } diff --git a/components/script_bindings/error.rs b/components/script_bindings/error.rs index 8424ff0fa95..a95d0b0b78c 100644 --- a/components/script_bindings/error.rs +++ b/components/script_bindings/error.rs @@ -59,6 +59,8 @@ pub enum Error { Data, /// OperationError DOMException Operation, + /// NotAllowedError DOMException + NotAllowed, /// TypeError JavaScript Error Type(String), diff --git a/components/script_bindings/webidls/CSSStyleSheet.webidl b/components/script_bindings/webidls/CSSStyleSheet.webidl index 1241b5c2769..302e7433300 100644 --- a/components/script_bindings/webidls/CSSStyleSheet.webidl +++ b/components/script_bindings/webidls/CSSStyleSheet.webidl @@ -11,6 +11,7 @@ interface CSSStyleSheet : StyleSheet { [Throws, SameObject] readonly attribute CSSRuleList cssRules; [Throws] unsigned long insertRule(DOMString rule, optional unsigned long index = 0); [Throws] undefined deleteRule(unsigned long index); + [Throws] undefined replaceSync(USVString text); }; dictionary CSSStyleSheetInit { diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index 9b052642c32..69e577e139d 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -265,7 +265,7 @@ pub trait Layout { animations: DocumentAnimationSet, animation_timeline_value: f64, ) -> Option<ServoArc<Font>>; - fn query_scrolling_area(&self, node: Option<OpaqueNode>) -> Rect<i32>; + fn query_scrolling_area(&self, node: Option<TrustedNodeAddress>) -> Rect<i32>; fn query_text_indext(&self, node: OpaqueNode, point: Point2D<f32>) -> Option<usize>; } diff --git a/tests/wpt/meta/css/css-mixins/at-function-parsing.html.ini b/tests/wpt/meta/css/css-mixins/at-function-parsing.html.ini index de4e8c0d888..439bfaf373b 100644 --- a/tests/wpt/meta/css/css-mixins/at-function-parsing.html.ini +++ b/tests/wpt/meta/css/css-mixins/at-function-parsing.html.ini @@ -11,12 +11,6 @@ [@function --foo( --x ) is valid] expected: FAIL - [@function --foo () is invalid] - expected: FAIL - - [@function --foo (--x) is invalid] - expected: FAIL - [@function --foo(--x auto) is valid] expected: FAIL @@ -113,9 +107,6 @@ [@function --foo(--x <angle>: 10px) is valid] expected: FAIL - [@function --foo(--x: 10px !important) is invalid] - expected: FAIL - [@function --foo(--x <length>#) is valid] expected: FAIL @@ -131,30 +122,6 @@ [@function --foo(--x <transform-function>+) is valid] expected: FAIL - [@function --foo(--x <transform-list>#) is invalid] - expected: FAIL - - [@function --foo(--x <transform-list>+) is invalid] - expected: FAIL - - [@function --foo(--x *) is invalid] - expected: FAIL - - [@function --foo(--x !) is invalid] - expected: FAIL - - [@function --foo(--x 50px) is invalid] - expected: FAIL - - [@function --foo(--x <length> | auto) is invalid] - expected: FAIL - - [@function --foo(--x none | auto) is invalid] - expected: FAIL - - [@function --foo(--x <dino>) is invalid] - expected: FAIL - [@function --foo(--x) returns type(*) is valid] expected: FAIL @@ -173,71 +140,5 @@ [@function --foo(--x) returns type(foo | bar) is valid] expected: FAIL - [@function --foo(--x) ! is invalid] - expected: FAIL - - [@function --foo(--x) length is invalid] - expected: FAIL - - [@function --foo(--x) returns is invalid] - expected: FAIL - - [@function --foo(--x) returns is invalid] - expected: FAIL - - [@function --foo(--x) returns * is invalid] - expected: FAIL - - [@function --foo(--x) returns <transform-list># is invalid] - expected: FAIL - - [@function --foo(--x) returns <transform-list>+ is invalid] - expected: FAIL - - [@function --foo(--x) returns auto | none is invalid] - expected: FAIL - - [@function --foo(--x): <length> is invalid] - expected: FAIL - - [@function --foo(--x): length is invalid] - expected: FAIL - - [@function --foo(--x) returneth <length> is invalid] - expected: FAIL - [@function --foo(--x:1px, --y, --z:2px) is valid] expected: FAIL - - [@function --foo(!) is invalid] - expected: FAIL - - [@function --foo(--x: !) is invalid] - expected: FAIL - - [@function --foo(--x type(!)) is invalid] - expected: FAIL - - [@function --foo(,) is invalid] - expected: FAIL - - [@function --foo(,,,) is invalid] - expected: FAIL - - [@function --foo(--x, ;) is invalid] - expected: FAIL - - [@function --foo(;) is invalid] - expected: FAIL - - [@function --foo(\]) is invalid] - expected: FAIL - - [@function --foo(, --x\]) is invalid] - expected: FAIL - - [@function --foo(--x) ! <length> is invalid] - expected: FAIL - - [@function --foo(--x) returns <length>! is invalid] - expected: FAIL diff --git a/tests/wpt/meta/css/css-nesting/nested-declarations-cssom.html.ini b/tests/wpt/meta/css/css-nesting/nested-declarations-cssom.html.ini index 42ccc3a16cc..28d16a619d3 100644 --- a/tests/wpt/meta/css/css-nesting/nested-declarations-cssom.html.ini +++ b/tests/wpt/meta/css/css-nesting/nested-declarations-cssom.html.ini @@ -1,33 +1,3 @@ [nested-declarations-cssom.html] - [Trailing declarations] - expected: FAIL - - [Mixed declarations] - expected: FAIL - - [CSSNestedDeclarations.style] - expected: FAIL - - [Nested group rule] - expected: FAIL - - [Nested @scope rule] - expected: FAIL - - [Inner rule starting with an ident] - expected: FAIL - - [Inserting a CSSNestedDeclaration rule into style rule] - expected: FAIL - [Inserting a CSSNestedDeclaration rule into nested group rule] expected: FAIL - - [Attempting to insert a CSSNestedDeclaration rule into top-level @media rule] - expected: FAIL - - [Attempting to insert a CSSNestedDeclaration rule, empty block] - expected: FAIL - - [Attempting to insert a CSSNestedDeclaration rule, all invalid declarations] - expected: FAIL diff --git a/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable-baseURL.html.ini b/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable-baseURL.html.ini index a9bad39b1da..f9b211c4a49 100644 --- a/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable-baseURL.html.ini +++ b/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable-baseURL.html.ini @@ -1,9 +1,3 @@ [CSSStyleSheet-constructable-baseURL.html] - [Constructing sheet with custom base URL ueses that URL for CSS rules] - expected: FAIL - - [Constructing sheet with relative URL adds to the constructor document's base URL] - expected: FAIL - [Constructing sheet with invalid base URL throws a NotAllowedError] expected: FAIL diff --git a/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable-disabled-regular-sheet-insertion.html.ini b/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable-disabled-regular-sheet-insertion.html.ini deleted file mode 100644 index d9dd9972f10..00000000000 --- a/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable-disabled-regular-sheet-insertion.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[CSSStyleSheet-constructable-disabled-regular-sheet-insertion.html] - [Shouldn't crash / assert when inserting a stylesheet after there are disabled constructable sheets] - expected: FAIL - diff --git a/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable.html.ini b/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable.html.ini index e02c46febe6..b8d885c47bd 100644 --- a/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable.html.ini +++ b/tests/wpt/meta/css/cssom/CSSStyleSheet-constructable.html.ini @@ -41,9 +41,6 @@ [Adding non-constructed stylesheet to AdoptedStyleSheets is not allowed when the owner document of the stylesheet and the AdoptedStyleSheets are in different document trees] expected: FAIL - [CSSStyleSheet.replaceSync replaces stylesheet text synchronously] - expected: FAIL - [CSSStyleSheet.replaceSync correctly updates the style of its adopters synchronously] expected: FAIL @@ -62,9 +59,6 @@ [CSSStyleSheet.replace ignores @import rule but still loads other rules] expected: FAIL - [CSSStyleSheet.replaceSync allows, but ignores, import rule inside] - expected: FAIL - [CSSStyleSheet.replace does not reject on failed imports] expected: FAIL @@ -73,9 +67,3 @@ [Adopting a shadow host's ancestor will empty adoptedStyleSheets if adopting to a different document] expected: FAIL - - [Modifying an adopted stylesheet on a disconnected shadow root should not crash.] - expected: FAIL - - [Constructing a sheet with the default base URL uses the constructor document's base URL for CSS rules] - expected: FAIL diff --git a/tests/wpt/meta/css/cssom/adoptedstylesheets-modify-array-and-sheet.html.ini b/tests/wpt/meta/css/cssom/adoptedstylesheets-modify-array-and-sheet.html.ini index 97401f0fd7c..f3585fe7abf 100644 --- a/tests/wpt/meta/css/cssom/adoptedstylesheets-modify-array-and-sheet.html.ini +++ b/tests/wpt/meta/css/cssom/adoptedstylesheets-modify-array-and-sheet.html.ini @@ -1,2 +1,9 @@ [adoptedstylesheets-modify-array-and-sheet.html] - expected: ERROR + [Add the two sheets. Text should be red.] + expected: FAIL + + [Flip the two sheet. Still red.] + expected: FAIL + + [Modify the color declaration. Should now be green.] + expected: FAIL diff --git a/tests/wpt/meta/css/cssom/idlharness.html.ini b/tests/wpt/meta/css/cssom/idlharness.html.ini index 4e3a2cedada..e87e7a353d2 100644 --- a/tests/wpt/meta/css/cssom/idlharness.html.ini +++ b/tests/wpt/meta/css/cssom/idlharness.html.ini @@ -395,21 +395,12 @@ [CSSStyleSheet interface: operation replace(USVString)] expected: FAIL - [CSSStyleSheet interface: operation replaceSync(USVString)] - expected: FAIL - [CSSStyleSheet interface: sheet must inherit property "replace(USVString)" with the proper type] expected: FAIL [CSSStyleSheet interface: calling replace(USVString) on sheet with too few arguments must throw TypeError] expected: FAIL - [CSSStyleSheet interface: sheet must inherit property "replaceSync(USVString)" with the proper type] - expected: FAIL - - [CSSStyleSheet interface: calling replaceSync(USVString) on sheet with too few arguments must throw TypeError] - expected: FAIL - [Document interface: attribute adoptedStyleSheets] expected: FAIL |