aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock12
-rw-r--r--Cargo.toml4
-rw-r--r--components/layout/fragment_tree/base_fragment.rs5
-rw-r--r--components/layout/fragment_tree/box_fragment.rs8
-rw-r--r--components/layout/fragment_tree/fragment.rs11
-rw-r--r--components/layout/fragment_tree/positioning_fragment.rs14
-rw-r--r--components/layout/layout_impl.rs5
-rw-r--r--components/layout/query.rs340
-rw-r--r--components/layout/table/layout.rs12
-rw-r--r--components/net/fetch/methods.rs67
-rw-r--r--components/script/dom/globalscope.rs54
-rw-r--r--components/script/dom/window.rs5
-rw-r--r--components/script/script_runtime.rs55
-rw-r--r--components/script/timers.rs3
-rw-r--r--components/shared/script_layout/lib.rs2
-rw-r--r--ports/servoshell/Cargo.toml45
-rw-r--r--tests/wpt/meta/content-security-policy/default-src/default-src-sri_hash.sub.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/generic/304-response-should-update-csp.sub.html.ini6
-rw-r--r--tests/wpt/meta/content-security-policy/img-src/img-src-self-unique-origin.html.ini4
-rw-r--r--tests/wpt/meta/content-security-policy/resource-hints/prefetch-generate-directives.html.ini10
-rw-r--r--tests/wpt/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-external-hash-policy.html.ini6
-rw-r--r--tests/wpt/meta/content-security-policy/script-src/script-src-sri_hash.sub.html.ini7
-rw-r--r--tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_discard_source_expressions.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub.html.ini3
-rw-r--r--tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.ini24
-rw-r--r--tests/wpt/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini3
-rw-r--r--tests/wpt/meta/css/cssom-view/offsetParent-block-in-inline.html.ini3
-rw-r--r--tests/wpt/meta/css/filter-effects/backdrop-filter-edge-clipping-2.html.ini2
-rw-r--r--tests/wpt/meta/css/filter-effects/backdrop-filter-edge-mirror.html.ini2
-rw-r--r--tests/wpt/meta/css/filter-effects/backdrop-filter-edge-pixels-2.html.ini2
-rw-r--r--tests/wpt/meta/shadow-dom/offsetParent-across-shadow-boundaries.html.ini24
-rw-r--r--tests/wpt/meta/shadow-dom/offsetTop-offsetLeft-across-shadow-boundaries.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-001.html.ini30
-rw-r--r--tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-002.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-003.html.ini15
-rw-r--r--tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-004-worker.html.ini6
-rw-r--r--tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-005.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-eval-reporting-no-unsafe-eval.html.ini3
-rw-r--r--tests/wpt/meta/trusted-types/trusted-types-reporting.html.ini3
39 files changed, 321 insertions, 493 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 11c6ce403ad..4928ea1be00 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -853,9 +853,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.19"
+version = "1.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
+checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
dependencies = [
"jobserver",
"libc",
@@ -1074,7 +1074,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -1232,7 +1232,7 @@ dependencies = [
[[package]]
name = "content-security-policy"
version = "0.5.4"
-source = "git+https://github.com/servo/rust-content-security-policy/?branch=servo-csp#827eea44ec0f3d91457d1c0467881cb4f9752520"
+source = "git+https://github.com/servo/rust-content-security-policy/?branch=servo-csp#81f95254fbfe98dd6e130260fd872cf950de9fcd"
dependencies = [
"base64 0.22.1",
"bitflags 2.9.0",
@@ -4252,7 +4252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
- "windows-targets 0.48.5",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -8785,7 +8785,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index cd2cbb54b63..21bc94bcfda 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -243,3 +243,7 @@ codegen-units = 1
#
# [patch."https://github.com/servo/<repository>"]
# <crate> = { path = "/path/to/local/checkout" }
+#
+# [patch."https://github.com/servo/rust-content-security-policy"]
+# content-security-policy = { path = "../rust-content-security-policy/" }
+# content-security-policy = { git = "https://github.com/timvdlippe/rust-content-security-policy/", branch = "fix-report-checks", features = ["serde"] }
diff --git a/components/layout/fragment_tree/base_fragment.rs b/components/layout/fragment_tree/base_fragment.rs
index 48d672a8547..0cf6ee511cb 100644
--- a/components/layout/fragment_tree/base_fragment.rs
+++ b/components/layout/fragment_tree/base_fragment.rs
@@ -132,11 +132,6 @@ impl Tag {
Tag { node, pseudo }
}
- /// Returns true if this tag is for a pseudo element.
- pub(crate) fn is_pseudo(&self) -> bool {
- self.pseudo.is_some()
- }
-
pub(crate) fn to_display_list_fragment_id(self) -> u64 {
combine_id_with_fragment_type(self.node.id(), self.pseudo.into())
}
diff --git a/components/layout/fragment_tree/box_fragment.rs b/components/layout/fragment_tree/box_fragment.rs
index 0e83c0d71a6..e87826ec3ca 100644
--- a/components/layout/fragment_tree/box_fragment.rs
+++ b/components/layout/fragment_tree/box_fragment.rs
@@ -212,6 +212,10 @@ impl BoxFragment {
)
}
+ pub(crate) fn set_containing_block(&mut self, containing_block: &PhysicalRect<Au>) {
+ self.cumulative_containing_block_rect = *containing_block;
+ }
+
pub fn offset_by_containing_block(&self, rect: &PhysicalRect<Au>) -> PhysicalRect<Au> {
rect.translate(self.cumulative_containing_block_rect.origin.to_vector())
}
@@ -405,8 +409,4 @@ 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 ceccd1ec304..7708b0893ee 100644
--- a/components/layout/fragment_tree/fragment.rs
+++ b/components/layout/fragment_tree/fragment.rs
@@ -134,7 +134,9 @@ impl Fragment {
Fragment::Float(float_fragment) => float_fragment
.borrow_mut()
.set_containing_block(containing_block),
- Fragment::Positioning(_) => {},
+ Fragment::Positioning(positioning_fragment) => positioning_fragment
+ .borrow_mut()
+ .set_containing_block(containing_block),
Fragment::AbsoluteOrFixedPositioned(hoisted_shared_fragment) => {
if let Some(ref fragment) = hoisted_shared_fragment.borrow().fragment {
fragment.set_containing_block(containing_block);
@@ -191,13 +193,16 @@ impl Fragment {
}
}
- pub(crate) fn cumulative_content_box_rect(&self) -> Option<PhysicalRect<Au>> {
+ pub(crate) fn cumulative_border_box_rect(&self) -> Option<PhysicalRect<Au>> {
match self {
Fragment::Box(fragment) | Fragment::Float(fragment) => {
let fragment = fragment.borrow();
Some(fragment.offset_by_containing_block(&fragment.border_rect()))
},
- Fragment::Positioning(_) |
+ Fragment::Positioning(fragment) => {
+ let fragment = fragment.borrow();
+ Some(fragment.offset_by_containing_block(&fragment.rect))
+ },
Fragment::Text(_) |
Fragment::AbsoluteOrFixedPositioned(_) |
Fragment::Image(_) |
diff --git a/components/layout/fragment_tree/positioning_fragment.rs b/components/layout/fragment_tree/positioning_fragment.rs
index 853caed6709..1fe968eb484 100644
--- a/components/layout/fragment_tree/positioning_fragment.rs
+++ b/components/layout/fragment_tree/positioning_fragment.rs
@@ -20,12 +20,17 @@ pub(crate) struct PositioningFragment {
pub base: BaseFragment,
pub rect: PhysicalRect<Au>,
pub children: Vec<Fragment>,
+
/// The scrollable overflow of this anonymous fragment's children.
pub scrollable_overflow: PhysicalRect<Au>,
/// If this fragment was created with a style, the style of the fragment.
#[conditional_malloc_size_of]
pub style: Option<ServoArc<ComputedValues>>,
+
+ /// This [`PositioningFragment`]'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>,
}
impl PositioningFragment {
@@ -61,9 +66,18 @@ impl PositioningFragment {
rect,
children,
scrollable_overflow,
+ cumulative_containing_block_rect: PhysicalRect::zero(),
})
}
+ pub(crate) fn set_containing_block(&mut self, containing_block: &PhysicalRect<Au>) {
+ self.cumulative_containing_block_rect = *containing_block;
+ }
+
+ pub fn offset_by_containing_block(&self, rect: &PhysicalRect<Au>) -> PhysicalRect<Au> {
+ rect.translate(self.cumulative_containing_block_rect.origin.to_vector())
+ }
+
pub fn print(&self, tree: &mut PrintTree) {
tree.new_level(format!(
"PositioningFragment\
diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs
index 941fa641cc9..3110899d76e 100644
--- a/components/layout/layout_impl.rs
+++ b/components/layout/layout_impl.rs
@@ -300,8 +300,9 @@ impl Layout for LayoutThread {
feature = "tracing",
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
)]
- fn query_offset_parent(&self, node: OpaqueNode) -> OffsetParentResponse {
- process_offset_parent_query(node, self.fragment_tree.borrow().clone())
+ fn query_offset_parent(&self, node: TrustedNodeAddress) -> OffsetParentResponse {
+ let node = unsafe { ServoLayoutNode::new(&node) };
+ process_offset_parent_query(node).unwrap_or_default()
}
#[cfg_attr(
diff --git a/components/layout/query.rs b/components/layout/query.rs
index 3badff83672..e78acdd0ca8 100644
--- a/components/layout/query.rs
+++ b/components/layout/query.rs
@@ -7,7 +7,7 @@ use std::sync::Arc;
use app_units::Au;
use euclid::default::{Point2D, Rect};
-use euclid::{SideOffsets2D, Size2D, Vector2D};
+use euclid::{SideOffsets2D, Size2D};
use itertools::Itertools;
use script_layout_interface::wrapper_traits::{
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
@@ -38,19 +38,19 @@ use style::values::specified::GenericGridTemplateComponent;
use style::values::specified::box_::DisplayInside;
use style_traits::{ParsingMode, ToCss};
+use crate::ArcRefCell;
use crate::dom::NodeExt;
use crate::flow::inline::construct::{TextTransformation, WhitespaceCollapse};
use crate::fragment_tree::{
- BoxFragment, Fragment, FragmentFlags, FragmentTree, SpecificLayoutInfo, Tag,
+ BoxFragment, Fragment, FragmentFlags, FragmentTree, SpecificLayoutInfo,
};
-use crate::geom::{PhysicalRect, PhysicalVec};
use crate::taffy::SpecificTaffyGridInfo;
pub fn process_content_box_request<'dom>(node: impl LayoutNode<'dom> + 'dom) -> Option<Rect<Au>> {
let rects: Vec<_> = node
.fragments_for_pseudo(None)
.iter()
- .filter_map(Fragment::cumulative_content_box_rect)
+ .filter_map(Fragment::cumulative_border_box_rect)
.collect();
if rects.is_empty() {
return None;
@@ -64,7 +64,7 @@ pub fn process_content_box_request<'dom>(node: impl LayoutNode<'dom> + 'dom) ->
pub fn process_content_boxes_request<'dom>(node: impl LayoutNode<'dom> + 'dom) -> Vec<Rect<Au>> {
node.fragments_for_pseudo(None)
.iter()
- .filter_map(Fragment::cumulative_content_box_rect)
+ .filter_map(Fragment::cumulative_border_box_rect)
.map(|rect| rect.to_untyped())
.collect()
}
@@ -428,231 +428,157 @@ fn shorthand_to_css_string(
}
}
-pub fn process_offset_parent_query(
- node: OpaqueNode,
- fragment_tree: Option<Arc<FragmentTree>>,
-) -> OffsetParentResponse {
- process_offset_parent_query_inner(node, fragment_tree).unwrap_or_default()
+struct OffsetParentFragments {
+ parent: ArcRefCell<BoxFragment>,
+ grandparent: Option<Fragment>,
}
-#[inline]
-fn process_offset_parent_query_inner(
- node: OpaqueNode,
- fragment_tree: Option<Arc<FragmentTree>>,
-) -> Option<OffsetParentResponse> {
- let fragment_tree = fragment_tree?;
-
- struct NodeOffsetBoxInfo {
- border_box: Rect<Au>,
- offset_parent_node_address: Option<OpaqueNode>,
- is_static_body_element: bool,
+/// <https://www.w3.org/TR/2016/WD-cssom-view-1-20160317/#dom-htmlelement-offsetparent>
+fn offset_parent_fragments<'dom>(
+ node: impl LayoutNode<'dom> + 'dom,
+) -> Option<OffsetParentFragments> {
+ // 1. If any of the following holds true return null and terminate this algorithm:
+ // * The element does not have an associated CSS layout box.
+ // * The element is the root element.
+ // * The element is the HTML body element.
+ // * The element’s computed value of the position property is fixed.
+ let fragment = node.fragments_for_pseudo(None).first().cloned()?;
+ let flags = fragment.base()?.flags;
+ if flags.intersects(
+ FragmentFlags::IS_ROOT_ELEMENT | FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT,
+ ) {
+ return None;
+ }
+ if matches!(
+ fragment, Fragment::Box(fragment) if fragment.borrow().style.get_box().position == Position::Fixed
+ ) {
+ return None;
}
- // https://www.w3.org/TR/2016/WD-cssom-view-1-20160317/#extensions-to-the-htmlelement-interface
- let mut parent_node_addresses: Vec<Option<(OpaqueNode, bool)>> = Vec::new();
- let tag_to_find = Tag::new(node);
- let node_offset_box = fragment_tree.find(|fragment, level, containing_block| {
- let base = fragment.base()?;
- let is_body_element = base
- .flags
- .contains(FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT);
-
- if fragment.tag() == Some(tag_to_find) {
- // Only consider the first fragment of the node found as per a
- // possible interpretation of the specification: "[...] return the
- // y-coordinate of the top border edge of the first CSS layout box
- // associated with the element [...]"
- //
- // FIXME: Browsers implement this all differently (e.g., [1]) -
- // Firefox does returns the union of all layout elements of some
- // sort. Chrome returns the first fragment for a block element (the
- // same as ours) or the union of all associated fragments in the
- // first containing block fragment for an inline element. We could
- // implement Chrome's behavior, but our fragment tree currently
- // provides insufficient information.
- //
- // [1]: https://github.com/w3c/csswg-drafts/issues/4541
- let fragment_relative_rect = match fragment {
- Fragment::Box(fragment) | Fragment::Float(fragment) => fragment.borrow().border_rect(),
- Fragment::Text(fragment) => fragment.borrow().rect,
- Fragment::Positioning(fragment) => fragment.borrow().rect,
- Fragment::AbsoluteOrFixedPositioned(_) |
- Fragment::Image(_) |
- Fragment::IFrame(_) => unreachable!(),
+ // 2. Return the nearest ancestor element of the element for which at least one of
+ // the following is true and terminate this algorithm if such an ancestor is found:
+ // * The computed value of the position property is not static.
+ // * It is the HTML body element.
+ // * The computed value of the position property of the element is static and the
+ // ancestor is one of the following HTML elements: td, th, or table.
+ let mut maybe_parent_node = node.parent_node();
+ while let Some(parent_node) = maybe_parent_node {
+ maybe_parent_node = parent_node.parent_node();
+
+ if let Some(parent_fragment) = parent_node.fragments_for_pseudo(None).first() {
+ let parent_fragment = match parent_fragment {
+ Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => box_fragment,
+ _ => continue,
};
- let mut border_box = fragment_relative_rect.translate(containing_block.origin.to_vector()).to_untyped();
-
- // "If any of the following holds true return null and terminate
- // this algorithm: [...] The element’s computed value of the
- // `position` property is `fixed`."
- let is_fixed = matches!(
- fragment, Fragment::Box(fragment) if fragment.borrow().style.get_box().position == Position::Fixed
- );
+ let grandparent_fragment =
+ maybe_parent_node.and_then(|node| node.fragments_for_pseudo(None).first().cloned());
- if is_body_element {
- // "If the element is the HTML body element or [...] return zero
- // and terminate this algorithm."
- border_box.origin = Point2D::zero();
+ if parent_fragment.borrow().style.get_box().position != Position::Static {
+ return Some(OffsetParentFragments {
+ parent: parent_fragment.clone(),
+ grandparent: grandparent_fragment,
+ });
}
- let offset_parent_node = if is_fixed {
- None
- } else {
- // Find the nearest ancestor element eligible as `offsetParent`.
- parent_node_addresses[..level]
- .iter()
- .rev()
- .cloned()
- .find_map(std::convert::identity)
- };
-
- Some(NodeOffsetBoxInfo {
- border_box,
- offset_parent_node_address: offset_parent_node.map(|node| node.0),
- is_static_body_element: offset_parent_node.is_some_and(|node| node.1),
- })
- } else {
- // Record the paths of the nodes being traversed.
- let parent_node_address = match fragment {
- Fragment::Box(fragment) | Fragment::Float(fragment) => {
- let fragment = &*fragment.borrow();
- let is_eligible_parent = is_eligible_parent(fragment);
- let is_static_body_element = is_body_element &&
- fragment.style.get_box().position == Position::Static;
- match base.tag {
- Some(tag) if is_eligible_parent && !tag.is_pseudo() => {
- Some((tag.node, is_static_body_element))
- },
- _ => None,
- }
- },
- Fragment::AbsoluteOrFixedPositioned(_) |
- Fragment::IFrame(_) |
- Fragment::Image(_) |
- Fragment::Positioning(_) |
- Fragment::Text(_) => None,
- };
-
- while parent_node_addresses.len() <= level {
- parent_node_addresses.push(None);
+ let flags = parent_fragment.borrow().base.flags;
+ if flags.intersects(
+ FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT |
+ FragmentFlags::IS_TABLE_TH_OR_TD_ELEMENT,
+ ) {
+ return Some(OffsetParentFragments {
+ parent: parent_fragment.clone(),
+ grandparent: grandparent_fragment,
+ });
}
- parent_node_addresses[level] = parent_node_address;
- None
}
- });
+ }
- // Bail out if the element doesn't have an associated fragment.
- // "If any of the following holds true return null and terminate this
- // algorithm: [...] The element does not have an associated CSS layout box."
- // (`offsetParent`) "If the element is the HTML body element [...] return
- // zero and terminate this algorithm." (others)
- let node_offset_box = node_offset_box?;
+ None
+}
- let offset_parent_padding_box_corner = if let Some(offset_parent_node_address) =
- node_offset_box.offset_parent_node_address
- {
- // The spec (https://www.w3.org/TR/cssom-view-1/#extensions-to-the-htmlelement-interface)
- // says that offsetTop/offsetLeft are always relative to the padding box of the offsetParent.
- // However, in practice this is not true in major browsers in the case that the offsetParent is the body
- // element and the body element is position:static. In that case offsetLeft/offsetTop are computed
- // relative to the root node's border box.
- if node_offset_box.is_static_body_element {
- fn extract_box_fragment(
- fragment: &Fragment,
- containing_block: &PhysicalRect<Au>,
- ) -> PhysicalVec<Au> {
- let (Fragment::Box(fragment) | Fragment::Float(fragment)) = fragment else {
- unreachable!();
- };
- // Again, take the *first* associated CSS layout box.
- fragment.borrow().border_rect().origin.to_vector() +
- containing_block.origin.to_vector()
- }
+#[inline]
+pub fn process_offset_parent_query<'dom>(
+ node: impl LayoutNode<'dom> + 'dom,
+) -> Option<OffsetParentResponse> {
+ // Only consider the first fragment of the node found as per a
+ // possible interpretation of the specification: "[...] return the
+ // y-coordinate of the top border edge of the first CSS layout box
+ // associated with the element [...]"
+ //
+ // FIXME: Browsers implement this all differently (e.g., [1]) -
+ // Firefox does returns the union of all layout elements of some
+ // sort. Chrome returns the first fragment for a block element (the
+ // same as ours) or the union of all associated fragments in the
+ // first containing block fragment for an inline element. We could
+ // implement Chrome's behavior, but our fragment tree currently
+ // provides insufficient information.
+ //
+ // [1]: https://github.com/w3c/csswg-drafts/issues/4541
+ // > 1. If the element is the HTML body element or does not have any associated CSS
+ // layout box return zero and terminate this algorithm.
+ let fragment = node.fragments_for_pseudo(None).first().cloned()?;
+ let mut border_box = fragment.cumulative_border_box_rect()?;
+
+ // 2. If the offsetParent of the element is null return the x-coordinate of the left
+ // border edge of the first CSS layout box associated with the element, relative to
+ // the initial containing block origin, ignoring any transforms that apply to the
+ // element and its ancestors, and terminate this algorithm.
+ let Some(offset_parent_fragment) = offset_parent_fragments(node) else {
+ return Some(OffsetParentResponse {
+ node_address: None,
+ rect: border_box.to_untyped(),
+ });
+ };
- let containing_block = &fragment_tree.initial_containing_block;
- let fragment = &fragment_tree.root_fragments[0];
- if let Fragment::AbsoluteOrFixedPositioned(shared_fragment) = fragment {
- let shared_fragment = &*shared_fragment.borrow();
- let fragment = shared_fragment.fragment.as_ref().unwrap();
- extract_box_fragment(fragment, containing_block)
- } else {
- extract_box_fragment(fragment, containing_block)
- }
+ let parent_fragment = offset_parent_fragment.parent.borrow();
+ let parent_is_static_body_element = parent_fragment
+ .base
+ .flags
+ .contains(FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT) &&
+ parent_fragment.style.get_box().position == Position::Static;
+
+ // For `offsetLeft`:
+ // 3. Return the result of subtracting the y-coordinate of the top padding edge of the
+ // first CSS layout box associated with the offsetParent of the element from the
+ // y-coordinate of the top border edge of the first CSS layout box associated with the
+ // element, relative to the initial containing block origin, ignoring any transforms
+ // that apply to the element and its ancestors.
+ //
+ // We generalize this for `offsetRight` as described in the specification.
+ let grandparent_box_fragment = || match offset_parent_fragment.grandparent {
+ Some(Fragment::Box(box_fragment)) | Some(Fragment::Float(box_fragment)) => {
+ Some(box_fragment)
+ },
+ _ => None,
+ };
+
+ // The spec (https://www.w3.org/TR/cssom-view-1/#extensions-to-the-htmlelement-interface)
+ // says that offsetTop/offsetLeft are always relative to the padding box of the offsetParent.
+ // However, in practice this is not true in major browsers in the case that the offsetParent is the body
+ // element and the body element is position:static. In that case offsetLeft/offsetTop are computed
+ // relative to the root node's border box.
+ //
+ // See <https://github.com/w3c/csswg-drafts/issues/10549>.
+ let parent_offset_rect = if parent_is_static_body_element {
+ if let Some(grandparent_fragment) = grandparent_box_fragment() {
+ let grandparent_fragment = grandparent_fragment.borrow();
+ grandparent_fragment.offset_by_containing_block(&grandparent_fragment.border_rect())
} else {
- // Find the top and left padding edges of "the first CSS layout box
- // associated with the `offsetParent` of the element".
- //
- // Since we saw `offset_parent_node_address` once, we should be able
- // to find it again.
- let offset_parent_node_tag = Tag::new(offset_parent_node_address);
- fragment_tree
- .find(|fragment, _, containing_block| {
- match fragment {
- Fragment::Box(fragment) | Fragment::Float(fragment) => {
- let fragment = fragment.borrow();
- if fragment.base.tag == Some(offset_parent_node_tag) {
- // Again, take the *first* associated CSS layout box.
- let padding_box_corner = fragment.padding_rect().origin.to_vector()
- + containing_block.origin.to_vector();
- Some(padding_box_corner)
- } else {
- None
- }
- },
- Fragment::AbsoluteOrFixedPositioned(_)
- | Fragment::Text(_)
- | Fragment::Image(_)
- | Fragment::IFrame(_)
- | Fragment::Positioning(_) => None,
- }
- })
- .unwrap()
+ parent_fragment.offset_by_containing_block(&parent_fragment.padding_rect())
}
} else {
- // "If the offsetParent of the element is null," subtract zero in the
- // following step.
- Vector2D::zero()
+ parent_fragment.offset_by_containing_block(&parent_fragment.padding_rect())
};
+ border_box = border_box.translate(-parent_offset_rect.origin.to_vector());
+
Some(OffsetParentResponse {
- node_address: node_offset_box.offset_parent_node_address.map(Into::into),
- // "Return the result of subtracting the x-coordinate of the left
- // padding edge of the first CSS layout box associated with the
- // `offsetParent` of the element from the x-coordinate of the left
- // border edge of the first CSS layout box associated with the element,
- // relative to the initial containing block origin, ignoring any
- // transforms that apply to the element and its ancestors." (and vice
- // versa for the top border edge)
- rect: node_offset_box
- .border_box
- .translate(-offset_parent_padding_box_corner.to_untyped()),
+ node_address: parent_fragment.base.tag.map(|tag| tag.node.into()),
+ rect: border_box.to_untyped(),
})
}
-/// Returns whether or not the element with the given style and body element determination
-/// is eligible to be a parent element for offset* queries.
-///
-/// From <https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsetparent>:
-///
-/// > Return the nearest ancestor element of the element for which at least one of the following is
-/// > true and terminate this algorithm if such an ancestor is found:
-/// > 1. The computed value of the position property is not static.
-/// > 2. It is the HTML body element.
-/// > 3. The computed value of the position property of the element is static and the ancestor is
-/// > one of the following HTML elements: td, th, or table.
-fn is_eligible_parent(fragment: &BoxFragment) -> bool {
- fragment
- .base
- .flags
- .contains(FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT) ||
- fragment.style.get_box().position != Position::Static ||
- fragment
- .base
- .flags
- .contains(FragmentFlags::IS_TABLE_TH_OR_TD_ELEMENT)
-}
-
/// <https://html.spec.whatwg.org/multipage/#get-the-text-steps>
pub fn get_the_text_steps<'dom>(node: impl LayoutNode<'dom>) -> String {
// Step 1: If element is not being rendered or if the user agent is a non-CSS user agent, then
diff --git a/components/layout/table/layout.rs b/components/layout/table/layout.rs
index 57b48ae0bca..2261f7d165c 100644
--- a/components/layout/table/layout.rs
+++ b/components/layout/table/layout.rs
@@ -2142,23 +2142,27 @@ impl<'a> TableLayout<'a> {
for column_group in self.table.column_groups.iter() {
let column_group = column_group.borrow();
if !column_group.is_empty() {
- fragments.push(Fragment::Positioning(PositioningFragment::new_empty(
+ let fragment = Fragment::Positioning(PositioningFragment::new_empty(
column_group.base.base_fragment_info,
dimensions
.get_column_group_rect(&column_group)
.as_physical(None),
column_group.base.style.clone(),
- )));
+ ));
+ column_group.base.set_fragment(fragment.clone());
+ fragments.push(fragment);
}
}
for (column_index, column) in self.table.columns.iter().enumerate() {
let column = column.borrow();
- fragments.push(Fragment::Positioning(PositioningFragment::new_empty(
+ let fragment = Fragment::Positioning(PositioningFragment::new_empty(
column.base.base_fragment_info,
dimensions.get_column_rect(column_index).as_physical(None),
column.base.style.clone(),
- )));
+ ));
+ column.base.set_fragment(fragment.clone());
+ fragments.push(fragment);
}
}
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs
index 53bc2817292..b1ad01b81e0 100644
--- a/components/net/fetch/methods.rs
+++ b/components/net/fetch/methods.rs
@@ -23,8 +23,8 @@ use net_traits::http_status::HttpStatus;
use net_traits::policy_container::{PolicyContainer, RequestPolicyContainer};
use net_traits::request::{
BodyChunkRequest, BodyChunkResponse, CredentialsMode, Destination, Initiator,
- InsecureRequestsPolicy, Origin, RedirectMode, Referrer, Request, RequestMode, ResponseTainting,
- Window, is_cors_safelisted_method, is_cors_safelisted_request_header,
+ InsecureRequestsPolicy, Origin, ParserMetadata, RedirectMode, Referrer, Request, RequestMode,
+ ResponseTainting, Window, is_cors_safelisted_method, is_cors_safelisted_request_header,
};
use net_traits::response::{Response, ResponseBody, ResponseType};
use net_traits::{
@@ -169,6 +169,29 @@ pub async fn fetch_with_cors_cache(
// TODO: We don't implement fetchParams as defined in the spec
}
+fn convert_request_to_csp_request(request: &Request, origin: &ImmutableOrigin) -> csp::Request {
+ csp::Request {
+ url: request.url().into_url(),
+ origin: origin.clone().into_url_origin(),
+ redirect_count: request.redirect_count,
+ destination: request.destination,
+ initiator: match request.initiator {
+ Initiator::Download => csp::Initiator::Download,
+ Initiator::ImageSet => csp::Initiator::ImageSet,
+ Initiator::Manifest => csp::Initiator::Manifest,
+ Initiator::Prefetch => csp::Initiator::Prefetch,
+ _ => csp::Initiator::None,
+ },
+ nonce: request.cryptographic_nonce_metadata.clone(),
+ integrity_metadata: request.integrity_metadata.clone(),
+ parser_metadata: match request.parser_metadata {
+ ParserMetadata::ParserInserted => csp::ParserMetadata::ParserInserted,
+ ParserMetadata::NotParserInserted => csp::ParserMetadata::NotParserInserted,
+ ParserMetadata::Default => csp::ParserMetadata::None,
+ },
+ }
+}
+
/// <https://www.w3.org/TR/CSP/#should-block-request>
pub fn should_request_be_blocked_by_csp(
request: &Request,
@@ -178,17 +201,7 @@ pub fn should_request_be_blocked_by_csp(
Origin::Client => return (csp::CheckResult::Allowed, Vec::new()),
Origin::Origin(origin) => origin,
};
-
- let csp_request = csp::Request {
- url: request.url().into_url(),
- origin: origin.clone().into_url_origin(),
- redirect_count: request.redirect_count,
- destination: request.destination,
- initiator: csp::Initiator::None,
- nonce: request.cryptographic_nonce_metadata.clone(),
- integrity_metadata: request.integrity_metadata.clone(),
- parser_metadata: csp::ParserMetadata::None,
- };
+ let csp_request = convert_request_to_csp_request(request, origin);
policy_container
.csp_list
@@ -197,6 +210,24 @@ pub fn should_request_be_blocked_by_csp(
.unwrap_or((csp::CheckResult::Allowed, Vec::new()))
}
+/// <https://www.w3.org/TR/CSP/#report-for-request>
+pub fn report_violations_for_request_by_csp(
+ request: &Request,
+ policy_container: &PolicyContainer,
+) -> Vec<csp::Violation> {
+ let origin = match &request.origin {
+ Origin::Client => return Vec::new(),
+ Origin::Origin(origin) => origin,
+ };
+ let csp_request = convert_request_to_csp_request(request, origin);
+
+ policy_container
+ .csp_list
+ .as_ref()
+ .map(|c| c.report_violations_for_request(&csp_request))
+ .unwrap_or_default()
+}
+
/// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch)
pub async fn main_fetch(
fetch_params: &mut FetchParams,
@@ -232,9 +263,6 @@ pub async fn main_fetch(
)));
}
- // Step 2.2.
- // TODO: Report violations.
-
// The request should have a valid policy_container associated with it.
// TODO: This should not be `Client` here
let policy_container = match &request.policy_container {
@@ -242,6 +270,13 @@ pub async fn main_fetch(
RequestPolicyContainer::PolicyContainer(container) => container.to_owned(),
};
+ // Step 2.2.
+ let violations = report_violations_for_request_by_csp(request, &policy_container);
+
+ if !violations.is_empty() {
+ target.process_csp_violations(request, violations);
+ }
+
// Step 3.
// TODO: handle request abort.
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 77d1ee37c03..b3345b90fc0 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -2422,7 +2422,8 @@ impl GlobalScope {
headers: &Option<Serde<HeaderMap>>,
) -> Option<CspList> {
// TODO: Implement step 1 (local scheme special case)
- let mut csp = headers.as_ref()?.get_all("content-security-policy").iter();
+ let headers = headers.as_ref()?;
+ let mut csp = headers.get_all("content-security-policy").iter();
// This silently ignores the CSP if it contains invalid Unicode.
// We should probably report an error somewhere.
let c = csp.next().and_then(|c| c.to_str().ok())?;
@@ -2435,6 +2436,19 @@ impl GlobalScope {
PolicyDisposition::Enforce,
));
}
+ let csp_report = headers
+ .get_all("content-security-policy-report-only")
+ .iter();
+ // This silently ignores the CSP if it contains invalid Unicode.
+ // We should probably report an error somewhere.
+ for c in csp_report {
+ let c = c.to_str().ok()?;
+ csp_list.append(CspList::parse(
+ c,
+ PolicySource::Header,
+ PolicyDisposition::Report,
+ ));
+ }
Some(csp_list)
}
@@ -2822,36 +2836,16 @@ impl GlobalScope {
}))
}
- #[allow(unsafe_code)]
- pub(crate) fn is_js_evaluation_allowed(&self, cx: SafeJSContext) -> bool {
+ pub(crate) fn is_js_evaluation_allowed(&self, source: &str) -> bool {
let Some(csp_list) = self.get_csp_list() else {
return true;
};
- let scripted_caller = unsafe { describe_scripted_caller(*cx) }.unwrap_or_default();
- let is_js_evaluation_allowed = csp_list.is_js_evaluation_allowed() == CheckResult::Allowed;
-
- if !is_js_evaluation_allowed {
- // FIXME: Don't fire event if `script-src` and `default-src`
- // were not passed.
- for policy in csp_list.0 {
- let report = CSPViolationReportBuilder::default()
- .resource("eval".to_owned())
- .effective_directive("script-src".to_owned())
- .report_only(policy.disposition == PolicyDisposition::Report)
- .source_file(scripted_caller.filename.clone())
- .line_number(scripted_caller.line)
- .column_number(scripted_caller.col)
- .build(self);
- let task = CSPViolationReportTask::new(self, report);
+ let (is_js_evaluation_allowed, violations) = csp_list.is_js_evaluation_allowed(source);
- self.task_manager()
- .dom_manipulation_task_source()
- .queue(task);
- }
- }
+ self.report_csp_violations(violations);
- is_js_evaluation_allowed
+ is_js_evaluation_allowed == CheckResult::Allowed
}
pub(crate) fn create_image_bitmap(
@@ -3464,10 +3458,13 @@ impl GlobalScope {
unreachable!();
}
+ #[allow(unsafe_code)]
pub(crate) fn report_csp_violations(&self, violations: Vec<Violation>) {
+ let scripted_caller =
+ unsafe { describe_scripted_caller(*GlobalScope::get_cx()) }.unwrap_or_default();
for violation in violations {
let (sample, resource) = match violation.resource {
- ViolationResource::Inline { .. } => (None, "inline".to_owned()),
+ ViolationResource::Inline { sample } => (sample, "inline".to_owned()),
ViolationResource::Url(url) => (None, url.into()),
ViolationResource::TrustedTypePolicy { sample } => {
(Some(sample), "trusted-types-policy".to_owned())
@@ -3475,6 +3472,8 @@ impl GlobalScope {
ViolationResource::TrustedTypeSink { sample } => {
(Some(sample), "trusted-types-sink".to_owned())
},
+ ViolationResource::Eval { sample } => (sample, "eval".to_owned()),
+ ViolationResource::WasmEval => (None, "wasm-eval".to_owned()),
};
let report = CSPViolationReportBuilder::default()
.resource(resource)
@@ -3482,6 +3481,9 @@ impl GlobalScope {
.effective_directive(violation.directive.name)
.original_policy(violation.policy.to_string())
.report_only(violation.policy.disposition == PolicyDisposition::Report)
+ .source_file(scripted_caller.filename.clone())
+ .line_number(scripted_caller.line)
+ .column_number(scripted_caller.col + 1)
.build(self);
let task = CSPViolationReportTask::new(self, report);
self.task_manager()
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 418c737acd4..932a9ec7f2d 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -2392,7 +2392,10 @@ impl Window {
return (None, Rect::zero());
}
- let response = self.layout.borrow().query_offset_parent(node.to_opaque());
+ let response = self
+ .layout
+ .borrow()
+ .query_offset_parent(node.to_trusted_node_address());
let element = response.node_address.and_then(|parent_node_address| {
let node = unsafe { from_untrusted_node_address(parent_node_address) };
DomRoot::downcast(node)
diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs
index d6832a644ec..1f05c15d74e 100644
--- a/components/script/script_runtime.rs
+++ b/components/script/script_runtime.rs
@@ -19,7 +19,7 @@ use std::time::{Duration, Instant};
use std::{os, ptr, thread};
use background_hang_monitor_api::ScriptHangAnnotation;
-use content_security_policy::{CheckResult, PolicyDisposition};
+use content_security_policy::CheckResult;
use js::conversions::jsstr_to_string;
use js::glue::{
CollectServoSizes, CreateJobQueue, DeleteJobQueue, DispatchableRun, JobQueueTraps,
@@ -45,7 +45,7 @@ pub(crate) use js::rust::ThreadSafeJSContext;
use js::rust::wrappers::{GetPromiseIsHandled, JS_GetPromiseResult};
use js::rust::{
Handle, HandleObject as RustHandleObject, IntoHandle, JSEngine, JSEngineHandle, ParentRuntime,
- Runtime as RustRuntime, describe_scripted_caller,
+ Runtime as RustRuntime,
};
use malloc_size_of::MallocSizeOfOps;
use malloc_size_of_derive::MallocSizeOf;
@@ -82,7 +82,6 @@ use crate::microtask::{EnqueuedPromiseCallback, Microtask, MicrotaskQueue};
use crate::realms::{AlreadyInRealm, InRealm};
use crate::script_module::EnsureModuleHooksInitialized;
use crate::script_thread::trace_thread;
-use crate::security_manager::{CSPViolationReportBuilder, CSPViolationReportTask};
use crate::task_source::SendableTaskSource;
static JOB_QUEUE_TRAPS: JobQueueTraps = JobQueueTraps {
@@ -373,10 +372,6 @@ unsafe extern "C" fn content_security_policy_allows(
let cx = JSContext::from_ptr(cx);
wrap_panic(&mut || {
// SpiderMonkey provides null pointer when executing webassembly.
- let sample = match sample {
- sample if !sample.is_null() => Some(jsstr_to_string(*cx, *sample)),
- _ => None,
- };
let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
let global = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
let Some(csp_list) = global.get_csp_list() else {
@@ -384,43 +379,19 @@ unsafe extern "C" fn content_security_policy_allows(
return;
};
- let is_js_evaluation_allowed = csp_list.is_js_evaluation_allowed() == CheckResult::Allowed;
- let is_wasm_evaluation_allowed =
- csp_list.is_wasm_evaluation_allowed() == CheckResult::Allowed;
- let scripted_caller = describe_scripted_caller(*cx).unwrap_or_default();
-
- let resource = match runtime_code {
- RuntimeCode::JS => "eval".to_owned(),
- RuntimeCode::WASM => "wasm-eval".to_owned(),
- };
-
- allowed = match runtime_code {
- RuntimeCode::JS if is_js_evaluation_allowed => true,
- RuntimeCode::WASM if is_wasm_evaluation_allowed => true,
- _ => false,
+ let (is_evaluation_allowed, violations) = match runtime_code {
+ RuntimeCode::JS => {
+ let source = match sample {
+ sample if !sample.is_null() => &jsstr_to_string(*cx, *sample),
+ _ => "",
+ };
+ csp_list.is_js_evaluation_allowed(source)
+ },
+ RuntimeCode::WASM => csp_list.is_wasm_evaluation_allowed(),
};
- if !allowed {
- // FIXME: Don't fire event if `script-src` and `default-src`
- // were not passed.
- for policy in csp_list.0 {
- let report = CSPViolationReportBuilder::default()
- .resource(resource.clone())
- .sample(sample.clone())
- .report_only(policy.disposition == PolicyDisposition::Report)
- .source_file(scripted_caller.filename.clone())
- .line_number(scripted_caller.line)
- .column_number(scripted_caller.col)
- .effective_directive("script-src".to_owned())
- .build(&global);
- let task = CSPViolationReportTask::new(&global, report);
-
- global
- .task_manager()
- .dom_manipulation_task_source()
- .queue(task);
- }
- }
+ global.report_csp_violations(violations);
+ allowed = is_evaluation_allowed == CheckResult::Allowed;
});
allowed
}
diff --git a/components/script/timers.rs b/components/script/timers.rs
index 244aa2df4ed..0afc3da164a 100644
--- a/components/script/timers.rs
+++ b/components/script/timers.rs
@@ -421,8 +421,7 @@ impl JsTimers {
) -> i32 {
let callback = match callback {
TimerCallback::StringTimerCallback(code_str) => {
- let cx = GlobalScope::get_cx();
- if global.is_js_evaluation_allowed(cx) {
+ if global.is_js_evaluation_allowed(code_str.as_ref()) {
InternalTimerCallback::StringTimerCallback(code_str)
} else {
return 0;
diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs
index 499d99753fe..a40b8c403c1 100644
--- a/components/shared/script_layout/lib.rs
+++ b/components/shared/script_layout/lib.rs
@@ -252,7 +252,7 @@ pub trait Layout {
point: Point2D<f32>,
query_type: NodesFromPointQueryType,
) -> Vec<UntrustedNodeAddress>;
- fn query_offset_parent(&self, node: OpaqueNode) -> OffsetParentResponse;
+ fn query_offset_parent(&self, node: TrustedNodeAddress) -> OffsetParentResponse;
fn query_resolved_style(
&self,
node: TrustedNodeAddress,
diff --git a/ports/servoshell/Cargo.toml b/ports/servoshell/Cargo.toml
index ed3a340e8d4..c77ea06fa15 100644
--- a/ports/servoshell/Cargo.toml
+++ b/ports/servoshell/Cargo.toml
@@ -22,7 +22,7 @@ bench = false
# since build-scripts can't detect the cargo target os at build-time, we
# must unconditionally add these dependencies. See https://github.com/rust-lang/cargo/issues/4932
[build-dependencies]
-# MacOS only
+# macOS only
cc = "1.2"
[target.'cfg(windows)'.build-dependencies]
@@ -37,7 +37,7 @@ ProductName = "Servo"
[features]
crown = ["libservo/crown"]
debugmozjs = ["libservo/debugmozjs"]
-default = ["max_log_level", "webdriver", "webxr", "webgpu"]
+default = ["max_log_level", "webdriver", "webgpu", "webxr"]
jitspew = ["libservo/jitspew"]
js_backtrace = ["libservo/js_backtrace"]
max_log_level = ["log/release_max_level_info"]
@@ -50,30 +50,30 @@ tracing-hitrace = ["tracing", "dep:hitrace"]
tracing-perfetto = ["tracing", "dep:tracing-perfetto"]
webdriver = ["libservo/webdriver"]
webgl_backtrace = ["libservo/webgl_backtrace"]
-webxr = ["libservo/webxr"]
webgpu = ["libservo/webgpu"]
+webxr = ["libservo/webxr"]
[dependencies]
+cfg-if = { workspace = true }
dpi = { workspace = true }
euclid = { workspace = true }
-libc = { workspace = true }
-libservo = { path = "../../components/servo", features = ["background_hang_monitor", "bluetooth"] }
-cfg-if = { workspace = true }
-keyboard-types = { workspace = true }
-log = { workspace = true }
getopts = { workspace = true }
hitrace = { workspace = true, optional = true }
+icu_locid = "1.5.0"
image = { workspace = true }
+keyboard-types = { workspace = true }
+libc = { workspace = true }
+libservo = { path = "../../components/servo", features = ["background_hang_monitor", "bluetooth"] }
+log = { workspace = true }
mime_guess = { workspace = true }
-url = { workspace = true }
raw-window-handle = { workspace = true }
rustls = { workspace = true, features = ["aws-lc-rs"] }
servo-tracing = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true, optional = true }
-tracing-subscriber = { workspace = true, optional = true, features = ["env-filter"] }
tracing-perfetto = { workspace = true, optional = true }
-icu_locid = "1.5.0"
+tracing-subscriber = { workspace = true, optional = true, features = ["env-filter"] }
+url = { workspace = true }
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.15"
@@ -81,36 +81,34 @@ ipc-channel = { workspace = true }
jni = "0.21.1"
libloading = "0.8"
-
[target.'cfg(not(target_os = "android"))'.dependencies]
backtrace = { workspace = true }
[target.'cfg(target_env = "ohos")'.dependencies]
env_filter = "0.1.3"
euclid = { workspace = true }
+hilog = "0.2.0"
# force inprocess, until libc-rs 0.2.156 is released containing
# https://github.com/rust-lang/libc/commit/9e248e212c5602cb4e98676e4c21ea0382663a12
ipc-channel = { workspace = true, features = ["force-inprocess"] }
-hilog = "0.2.0"
napi-derive-ohos = "1.0.4"
napi-ohos = "1.0.4"
-ohos-vsync = "0.1.3"
-ohos-ime = { version = "0.2" }
+ohos-ime = "0.2"
ohos-ime-sys = "0.1.4"
+ohos-vsync = "0.1.3"
xcomponent-sys = { version = "0.3.1", features = ["api-12", "keyboard-types"] }
[target.'cfg(any(target_os = "android", target_env = "ohos"))'.dependencies]
nix = { workspace = true, features = ["fs"] }
-surfman = { workspace = true, features = ["sm-angle-default"] }
serde_json = { workspace = true }
+surfman = { workspace = true, features = ["sm-angle-default"] }
[target.'cfg(not(any(target_os = "android", target_env = "ohos")))'.dependencies]
-# For optional feature servo_allocator/use-system-allocator
-servo_allocator = { path = "../../components/allocator" }
dirs = "5.0"
-egui = { version = "0.31.1" }
-egui_glow = { version = "0.31.1", features = ["winit"] }
+egui = "0.31.1"
+egui-file-dialog = "0.9.0"
egui-winit = { version = "0.31.1", default-features = false, features = ["clipboard", "wayland"] }
+egui_glow = { version = "0.31.1", features = ["winit"] }
gilrs = "0.11.0"
gleam = { workspace = true }
glow = "0.16.0"
@@ -119,17 +117,18 @@ http = { workspace = true }
net = { path = "../../components/net" }
net_traits = { workspace = true }
serde_json = { workspace = true }
+# For optional feature servo_allocator/use-system-allocator
+servo_allocator = { path = "../../components/allocator" }
shellwords = "1.0.0"
-surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] }
-egui-file-dialog = "0.9.0"
+surfman = { workspace = true, features = ["sm-raw-window-handle-06", "sm-x11"] }
winit = "0.30.9"
[target.'cfg(any(all(target_os = "linux", not(target_env = "ohos")), target_os = "macos"))'.dependencies]
sig = "1.0"
[target.'cfg(target_os = "windows")'.dependencies]
-windows-sys = { workspace = true, features = ["Win32_Graphics_Gdi"] }
libservo = { path = "../../components/servo", features = ["no-wgl"] }
+windows-sys = { workspace = true, features = ["Win32_Graphics_Gdi"] }
[target.'cfg(target_os = "macos")'.dependencies]
objc2-app-kit = { version = "0.2.2", default-features = false, features = [
diff --git a/tests/wpt/meta/content-security-policy/default-src/default-src-sri_hash.sub.html.ini b/tests/wpt/meta/content-security-policy/default-src/default-src-sri_hash.sub.html.ini
index b86623fcf06..ee237b70bc4 100644
--- a/tests/wpt/meta/content-security-policy/default-src/default-src-sri_hash.sub.html.ini
+++ b/tests/wpt/meta/content-security-policy/default-src/default-src-sri_hash.sub.html.ini
@@ -2,8 +2,11 @@
[multiple matching integrity]
expected: FAIL
- [partially matching integrity]
+ [matching integrity]
expected: FAIL
- [External script in a script tag with matching SRI hash should run.]
+ [matching integrity (case-insensitive algorithm)]
+ expected: FAIL
+
+ [matching plus unsupported integrity]
expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/generic/304-response-should-update-csp.sub.html.ini b/tests/wpt/meta/content-security-policy/generic/304-response-should-update-csp.sub.html.ini
deleted file mode 100644
index f4f10d1a85c..00000000000
--- a/tests/wpt/meta/content-security-policy/generic/304-response-should-update-csp.sub.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[304-response-should-update-csp.sub.html]
- [Test that the first frame does not use nonce def]
- expected: FAIL
-
- [Test that the second frame does not use nonce abc]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/img-src/img-src-self-unique-origin.html.ini b/tests/wpt/meta/content-security-policy/img-src/img-src-self-unique-origin.html.ini
deleted file mode 100644
index f5ccd49ccee..00000000000
--- a/tests/wpt/meta/content-security-policy/img-src/img-src-self-unique-origin.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[img-src-self-unique-origin.html]
- expected: TIMEOUT
- [Image's url must not match with 'self'. Image must be blocked.]
- expected: TIMEOUT
diff --git a/tests/wpt/meta/content-security-policy/resource-hints/prefetch-generate-directives.html.ini b/tests/wpt/meta/content-security-policy/resource-hints/prefetch-generate-directives.html.ini
index 7843cf2984c..df10ea63fd6 100644
--- a/tests/wpt/meta/content-security-policy/resource-hints/prefetch-generate-directives.html.ini
+++ b/tests/wpt/meta/content-security-policy/resource-hints/prefetch-generate-directives.html.ini
@@ -1,19 +1,19 @@
[prefetch-generate-directives.html]
expected: TIMEOUT
[Test that script-src enabled with everything else disabled allows prefetching]
- expected: FAIL
+ expected: TIMEOUT
[Test that script-src enabled with default-src disabled allows prefetching]
- expected: FAIL
+ expected: NOTRUN
[Test that img-src enabled with everything else disabled allows prefetching]
- expected: FAIL
+ expected: NOTRUN
[Test that img-src enabled with default-src disabled allows prefetching]
- expected: FAIL
+ expected: NOTRUN
[Test that connect-src enabled with everything else disabled allows prefetching]
- expected: TIMEOUT
+ expected: NOTRUN
[Test that connect-src enabled with default-src disabled allows prefetching]
expected: NOTRUN
diff --git a/tests/wpt/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-external-hash-policy.html.ini b/tests/wpt/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-external-hash-policy.html.ini
deleted file mode 100644
index 6ff412416ae..00000000000
--- a/tests/wpt/meta/content-security-policy/script-src/script-src-report-only-policy-works-with-external-hash-policy.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[script-src-report-only-policy-works-with-external-hash-policy.html]
- [Should fire securitypolicyviolation event]
- expected: FAIL
-
- [External script in a script tag with matching SRI hash should run.]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/script-src/script-src-sri_hash.sub.html.ini b/tests/wpt/meta/content-security-policy/script-src/script-src-sri_hash.sub.html.ini
index 7ce862f5a16..3324bf91bd7 100644
--- a/tests/wpt/meta/content-security-policy/script-src/script-src-sri_hash.sub.html.ini
+++ b/tests/wpt/meta/content-security-policy/script-src/script-src-sri_hash.sub.html.ini
@@ -2,8 +2,11 @@
[multiple matching integrity]
expected: FAIL
- [partially matching integrity]
+ [matching integrity]
expected: FAIL
- [External script in a script tag with matching SRI hash should run.]
+ [matching integrity (case-insensitive algorithm)]
+ expected: FAIL
+
+ [matching plus unsupported integrity]
expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_discard_source_expressions.html.ini b/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_discard_source_expressions.html.ini
deleted file mode 100644
index 63cfa444854..00000000000
--- a/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_discard_source_expressions.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[script-src-strict_dynamic_discard_source_expressions.html]
- [Allowed scripts without a correct nonce are not permitted with `strict-dynamic`.]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub.html.ini b/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub.html.ini
deleted file mode 100644
index c9d74462151..00000000000
--- a/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[script-src-strict_dynamic_double_policy_honor_source_expressions.sub.html]
- [Non-allowed script injected via `appendChild` is not permitted with `strict-dynamic` + a nonce+allowed double policy.]
- expected: FAIL
diff --git a/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.ini b/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.ini
index 44bc930f887..67a423f9b8a 100644
--- a/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.ini
+++ b/tests/wpt/meta/content-security-policy/script-src/script-src-strict_dynamic_parser_inserted.html.ini
@@ -1,29 +1,5 @@
[script-src-strict_dynamic_parser_inserted.html]
expected: TIMEOUT
- [Parser-inserted script via `document.write` without a correct nonce is not allowed with `strict-dynamic`.]
- expected: FAIL
-
- [Parser-inserted script via `document.writeln` without a correct nonce is not allowed with `strict-dynamic`.]
- expected: FAIL
-
- [Parser-inserted deferred script via `document.write` without a correct nonce is not allowed with `strict-dynamic`.]
- expected: FAIL
-
- [Parser-inserted deferred script via `document.writeln` without a correct nonce is not allowed with `strict-dynamic`.]
- expected: FAIL
-
- [Parser-inserted async script via `document.write` without a correct nonce is not allowed with `strict-dynamic`.]
- expected: FAIL
-
- [Parser-inserted async script via `document.writeln` without a correct nonce is not allowed with `strict-dynamic`.]
- expected: FAIL
-
- [Parser-inserted deferred async script via `document.write` without a correct nonce is not allowed with `strict-dynamic`.]
- expected: FAIL
-
- [Parser-inserted deferred async script via `document.writeln` without a correct nonce is not allowed with `strict-dynamic`.]
- expected: TIMEOUT
-
[Script injected via `innerHTML` is not allowed with `strict-dynamic`.]
expected: TIMEOUT
diff --git a/tests/wpt/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini b/tests/wpt/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini
index da41ac13664..f84e31682d3 100644
--- a/tests/wpt/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini
+++ b/tests/wpt/meta/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html.ini
@@ -1,8 +1,5 @@
[upgrade-insecure-requests-reporting.https.html]
expected: TIMEOUT
- [Upgraded image is reported]
- expected: TIMEOUT
-
[Upgraded iframe is reported]
expected: TIMEOUT
diff --git a/tests/wpt/meta/css/cssom-view/offsetParent-block-in-inline.html.ini b/tests/wpt/meta/css/cssom-view/offsetParent-block-in-inline.html.ini
deleted file mode 100644
index aa1109f1600..00000000000
--- a/tests/wpt/meta/css/cssom-view/offsetParent-block-in-inline.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[offsetParent-block-in-inline.html]
- [offsetParent-block-in-inline]
- expected: FAIL
diff --git a/tests/wpt/meta/css/filter-effects/backdrop-filter-edge-clipping-2.html.ini b/tests/wpt/meta/css/filter-effects/backdrop-filter-edge-clipping-2.html.ini
new file mode 100644
index 00000000000..4a08b41acc2
--- /dev/null
+++ b/tests/wpt/meta/css/filter-effects/backdrop-filter-edge-clipping-2.html.ini
@@ -0,0 +1,2 @@
+[backdrop-filter-edge-clipping-2.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/filter-effects/backdrop-filter-edge-mirror.html.ini b/tests/wpt/meta/css/filter-effects/backdrop-filter-edge-mirror.html.ini
new file mode 100644
index 00000000000..51318cbb1d2
--- /dev/null
+++ b/tests/wpt/meta/css/filter-effects/backdrop-filter-edge-mirror.html.ini
@@ -0,0 +1,2 @@
+[backdrop-filter-edge-mirror.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/css/filter-effects/backdrop-filter-edge-pixels-2.html.ini b/tests/wpt/meta/css/filter-effects/backdrop-filter-edge-pixels-2.html.ini
new file mode 100644
index 00000000000..19d53f587ad
--- /dev/null
+++ b/tests/wpt/meta/css/filter-effects/backdrop-filter-edge-pixels-2.html.ini
@@ -0,0 +1,2 @@
+[backdrop-filter-edge-pixels-2.html]
+ expected: FAIL
diff --git a/tests/wpt/meta/shadow-dom/offsetParent-across-shadow-boundaries.html.ini b/tests/wpt/meta/shadow-dom/offsetParent-across-shadow-boundaries.html.ini
deleted file mode 100644
index afd8ee2cf06..00000000000
--- a/tests/wpt/meta/shadow-dom/offsetParent-across-shadow-boundaries.html.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[offsetParent-across-shadow-boundaries.html]
- [offsetParent must skip offset parents of an element when the context object is assigned to a slot in a shadow tree of open mode]
- expected: FAIL
-
- [offsetParent must skip offset parents of an element when the context object is assigned to a slot in a shadow tree of closed mode]
- expected: FAIL
-
- [offsetParent must skip multiple offset parents of an element when the context object is assigned to a slot in a shadow tree of open mode]
- expected: FAIL
-
- [offsetParent must skip multiple offset parents of an element when the context object is assigned to a slot in a shadow tree of closed mode]
- expected: FAIL
-
- [offsetParent must skip offset parents of an element when the context object is assigned to a slot in nested shadow trees of open mode]
- expected: FAIL
-
- [offsetParent must skip offset parents of an element when the context object is assigned to a slot in nested shadow trees of closed mode]
- expected: FAIL
-
- [offsetParent must find the first offset parent which is a shadow-including ancestor of the context object even some shadow tree of open mode did not have any offset parent]
- expected: FAIL
-
- [offsetParent must find the first offset parent which is a shadow-including ancestor of the context object even some shadow tree of closed mode did not have any offset parent]
- expected: FAIL
diff --git a/tests/wpt/meta/shadow-dom/offsetTop-offsetLeft-across-shadow-boundaries.html.ini b/tests/wpt/meta/shadow-dom/offsetTop-offsetLeft-across-shadow-boundaries.html.ini
index 88f45f3b6a7..5ebeb149de3 100644
--- a/tests/wpt/meta/shadow-dom/offsetTop-offsetLeft-across-shadow-boundaries.html.ini
+++ b/tests/wpt/meta/shadow-dom/offsetTop-offsetLeft-across-shadow-boundaries.html.ini
@@ -4,6 +4,3 @@
[Verifies that HTMLElement.offsetTop accounts for shadow boundaries when nested in multiple shadow roots.]
expected: FAIL
-
- [Verifies that HTMLElement.offsetLeft accounts for shadow boundaries.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-001.html.ini b/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-001.html.ini
deleted file mode 100644
index 097af84d4ee..00000000000
--- a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-001.html.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[should-trusted-type-policy-creation-be-blocked-by-csp-001.html]
- [single report-only policy with directive "trusted-type tt-policy-name"]
- expected: FAIL
-
- [single report-only policy with directive "trusted-type *"]
- expected: FAIL
-
- [single report-only policy with directive "trusted-type 'none'"]
- expected: FAIL
-
- [single report-only policy with directive "trusted-type 'allow-duplicates'"]
- expected: FAIL
-
- [single report-only policy with directive "trusted-type tt-policy-name 'allow-duplicates'"]
- expected: FAIL
-
- [single report-only policy with directive "trusted-type 'none' 'allow-duplicates'"]
- expected: FAIL
-
- [single report-only policy with directive "trusted-type 'none' tt-policy-name"]
- expected: FAIL
-
- [single report-only policy with directive "trusted-type 'none' *"]
- expected: FAIL
-
- [single report-only policy with directive "trusted-type tt-policy-name *"]
- expected: FAIL
-
- [single report-only policy with directive "trusted-type tt-policy-name1 tt-policy-name2 tt-policy-name3"]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-002.html.ini b/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-002.html.ini
index b42c980eebc..65aaf704101 100644
--- a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-002.html.ini
+++ b/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-002.html.ini
@@ -1,8 +1,5 @@
[should-trusted-type-policy-creation-be-blocked-by-csp-002.html]
expected: TIMEOUT
- [invalid tt-policy-name name "policy name"]
- expected: FAIL
-
[invalid tt-policy-name name "policy*name"]
expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-003.html.ini b/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-003.html.ini
deleted file mode 100644
index d18359a0c91..00000000000
--- a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-003.html.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[should-trusted-type-policy-creation-be-blocked-by-csp-003.html]
- [Multiple report-only trusted-types directives.]
- expected: FAIL
-
- [One violated report-only trusted-types directive followed by multiple enforce directives.]
- expected: FAIL
-
- [One violated enforce trusted-types directive followed by multiple report-only directives.]
- expected: FAIL
-
- [Mixing enforce and report-only policies with trusted-types directives]
- expected: FAIL
-
- [Mixing enforce and report-only policies with trusted-types directives (duplicate policy)]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-004-worker.html.ini b/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-004-worker.html.ini
deleted file mode 100644
index e9ae8caa720..00000000000
--- a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-004-worker.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[should-trusted-type-policy-creation-be-blocked-by-csp-004-worker.html]
- [Exception and violations for CSP with multiple enforce and report-only policies.]
- expected: FAIL
-
- [Location of trusted-types violations.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-005.html.ini b/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-005.html.ini
deleted file mode 100644
index 7a8b7095515..00000000000
--- a/tests/wpt/meta/trusted-types/should-trusted-type-policy-creation-be-blocked-by-csp-005.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[should-trusted-type-policy-creation-be-blocked-by-csp-005.html]
- [Location of trusted-types violations.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-eval-reporting-no-unsafe-eval.html.ini b/tests/wpt/meta/trusted-types/trusted-types-eval-reporting-no-unsafe-eval.html.ini
index 927b135f628..d3440d323c2 100644
--- a/tests/wpt/meta/trusted-types/trusted-types-eval-reporting-no-unsafe-eval.html.ini
+++ b/tests/wpt/meta/trusted-types/trusted-types-eval-reporting-no-unsafe-eval.html.ini
@@ -4,6 +4,3 @@
[Trusted Type violation report: evaluating a Trusted Script violates script-src.]
expected: FAIL
-
- [Trusted Type violation report: script-src restrictions apply after the default policy runs.]
- expected: FAIL
diff --git a/tests/wpt/meta/trusted-types/trusted-types-reporting.html.ini b/tests/wpt/meta/trusted-types/trusted-types-reporting.html.ini
index 8347bf66f28..27c9a258d53 100644
--- a/tests/wpt/meta/trusted-types/trusted-types-reporting.html.ini
+++ b/tests/wpt/meta/trusted-types/trusted-types-reporting.html.ini
@@ -1,7 +1,4 @@
[trusted-types-reporting.html]
- [Trusted Type violation report: creating a forbidden policy.]
- expected: FAIL
-
[Trusted Type violation report: creating a report-only-forbidden policy.]
expected: FAIL