diff options
19 files changed, 322 insertions, 177 deletions
diff --git a/Cargo.lock b/Cargo.lock index f4a32a14a0f..bc1d392c755 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5467,7 +5467,7 @@ dependencies = [ [[package]] name = "peek-poke" version = "0.3.0" -source = "git+https://github.com/servo/webrender?branch=0.66#88462530746749163bcf1dc89be20a19f2394e71" +source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5dce8a17415a2cd1563074" dependencies = [ "euclid", "peek-poke-derive", @@ -5476,13 +5476,12 @@ dependencies = [ [[package]] name = "peek-poke-derive" version = "0.3.0" -source = "git+https://github.com/servo/webrender?branch=0.66#88462530746749163bcf1dc89be20a19f2394e71" +source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5dce8a17415a2cd1563074" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", - "unicode-xid", ] [[package]] @@ -6082,14 +6081,15 @@ dependencies = [ [[package]] name = "ron" -version = "0.8.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +checksum = "beceb6f7bf81c73e73aeef6dd1356d9a1b2b4909e1f0fc3e59b034f9572d7b7f" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.9.0", "serde", "serde_derive", + "unicode-ident", ] [[package]] @@ -8044,12 +8044,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] name = "universal-hash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -8553,7 +8547,7 @@ dependencies = [ [[package]] name = "webrender" version = "0.66.0" -source = "git+https://github.com/servo/webrender?branch=0.66#88462530746749163bcf1dc89be20a19f2394e71" +source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5dce8a17415a2cd1563074" dependencies = [ "allocator-api2", "bincode", @@ -8588,7 +8582,7 @@ dependencies = [ [[package]] name = "webrender_api" version = "0.66.0" -source = "git+https://github.com/servo/webrender?branch=0.66#88462530746749163bcf1dc89be20a19f2394e71" +source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5dce8a17415a2cd1563074" dependencies = [ "app_units", "bitflags 2.9.0", @@ -8609,7 +8603,7 @@ dependencies = [ [[package]] name = "webrender_build" version = "0.0.2" -source = "git+https://github.com/servo/webrender?branch=0.66#88462530746749163bcf1dc89be20a19f2394e71" +source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5dce8a17415a2cd1563074" dependencies = [ "bitflags 2.9.0", "lazy_static", @@ -9229,7 +9223,7 @@ dependencies = [ [[package]] name = "wr_glyph_rasterizer" version = "0.1.0" -source = "git+https://github.com/servo/webrender?branch=0.66#88462530746749163bcf1dc89be20a19f2394e71" +source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5dce8a17415a2cd1563074" dependencies = [ "core-foundation 0.9.4", "core-graphics", @@ -9253,8 +9247,8 @@ dependencies = [ [[package]] name = "wr_malloc_size_of" -version = "0.0.3" -source = "git+https://github.com/servo/webrender?branch=0.66#88462530746749163bcf1dc89be20a19f2394e71" +version = "0.2.0" +source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5dce8a17415a2cd1563074" dependencies = [ "app_units", "euclid", diff --git a/Cargo.toml b/Cargo.toml index 21bc94bcfda..b43c38b21b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -166,15 +166,15 @@ uuid = { version = "1.12.1", features = ["v4"] } webdriver = "0.51.0" webgpu_traits = { path = "components/shared/webgpu" } webpki-roots = "0.26" -webrender = { git = "https://github.com/servo/webrender", branch = "0.66", features = ["capture"] } -webrender_api = { git = "https://github.com/servo/webrender", branch = "0.66" } +webrender = { git = "https://github.com/servo/webrender", branch = "0.67", features = ["capture"] } +webrender_api = { git = "https://github.com/servo/webrender", branch = "0.67" } webxr-api = { path = "components/shared/webxr" } wgpu-core = "25" wgpu-types = "25" winapi = "0.3" windows-sys = "0.59" wio = "0.2" -wr_malloc_size_of = { git = "https://github.com/servo/webrender", branch = "0.66" } +wr_malloc_size_of = { git = "https://github.com/servo/webrender", branch = "0.67" } xi-unicode = "0.3.0" xml5ever = "0.22" diff --git a/components/canvas/backend.rs b/components/canvas/backend.rs index c83eebe3bee..53acbea8b8d 100644 --- a/components/canvas/backend.rs +++ b/components/canvas/backend.rs @@ -2,8 +2,12 @@ * 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 canvas_traits::canvas::{FillOrStrokeStyle, LineCapStyle, LineJoinStyle}; +use canvas_traits::canvas::{ + CompositionOrBlending, FillOrStrokeStyle, LineCapStyle, LineJoinStyle, +}; +use euclid::Angle; use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D}; +use lyon_geom::Arc; use style::color::AbsoluteColor; use crate::canvas_data::{CanvasPaintState, Filter, TextRun}; @@ -14,10 +18,10 @@ pub(crate) trait Backend: Clone + Sized { type Color: Clone; type DrawOptions: DrawOptionsHelpers + Clone; type CompositionOp; - type CompositionOrBlending; type DrawTarget: GenericDrawTarget<Self>; type PathBuilder: GenericPathBuilder<Self>; type SourceSurface; + type Bytes<'a>: AsRef<[u8]>; type Path: PathHelpers<Self> + Clone; type GradientStop; type GradientStops; @@ -39,7 +43,7 @@ pub(crate) trait Backend: Clone + Sized { ); fn set_global_composition( &mut self, - op: Self::CompositionOrBlending, + op: CompositionOrBlending, state: &mut CanvasPaintState<'_, Self>, ); fn create_drawtarget(&self, size: Size2D<u64>) -> Self::DrawTarget; @@ -95,7 +99,6 @@ pub(crate) trait GenericDrawTarget<B: Backend> { fn pop_clip(&mut self); fn push_clip(&mut self, path: &B::Path); fn set_transform(&mut self, matrix: &Transform2D<f32>); - fn snapshot(&self) -> B::SourceSurface; fn stroke( &mut self, path: &B::Path, @@ -118,7 +121,8 @@ pub(crate) trait GenericDrawTarget<B: Backend> { stroke_options: &B::StrokeOptions, draw_options: &B::DrawOptions, ); - fn snapshot_data(&self) -> &[u8]; + fn surface(&self) -> B::SourceSurface; + fn bytes(&'_ self) -> B::Bytes<'_>; } /// A generic PathBuilder that abstracts the interface for azure's and raqote's PathBuilder. @@ -148,7 +152,54 @@ pub(crate) trait GenericPathBuilder<B: Backend> { start_angle: f32, end_angle: f32, anticlockwise: bool, - ); + ) { + let mut start = Angle::radians(start_angle); + let mut end = Angle::radians(end_angle); + + // Wrap angles mod 2 * PI if necessary + if !anticlockwise && start > end + Angle::two_pi() || + anticlockwise && end > start + Angle::two_pi() + { + start = start.positive(); + end = end.positive(); + } + + // Calculate the total arc we're going to sweep. + let sweep = match anticlockwise { + true => { + if end - start == Angle::two_pi() { + -Angle::two_pi() + } else if end > start { + -(Angle::two_pi() - (end - start)) + } else { + -(start - end) + } + }, + false => { + if start - end == Angle::two_pi() { + Angle::two_pi() + } else if start > end { + Angle::two_pi() - (start - end) + } else { + end - start + } + }, + }; + + let arc: Arc<f32> = Arc { + center: origin, + radii: Vector2D::new(radius_x, radius_y), + start_angle: start, + sweep_angle: sweep, + x_rotation: Angle::radians(rotation_angle), + }; + + self.line_to(arc.from()); + + arc.for_each_quadratic_bezier(&mut |q| { + self.quadratic_curve_to(&q.ctrl, &q.to); + }); + } fn get_current_point(&mut self) -> Option<Point2D<f32>>; fn line_to(&mut self, point: Point2D<f32>); fn move_to(&mut self, point: Point2D<f32>); diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 7d8b4a9cdbc..ea30589d0af 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -426,7 +426,7 @@ impl<'a, B: Backend> CanvasData<'a, B> { flags: ImageDescriptorFlags::empty(), }; let data = - SerializableImageData::Raw(IpcSharedMemory::from_bytes(draw_target.snapshot_data())); + SerializableImageData::Raw(IpcSharedMemory::from_bytes(draw_target.bytes().as_ref())); compositor_api.update_images(vec![ImageUpdate::AddImage(image_key, descriptor, data)]); CanvasData { state: backend.new_paint_state(), @@ -1183,7 +1183,7 @@ impl<'a, B: Backend> CanvasData<'a, B> { self.state.draw_options.set_alpha(alpha); } - pub(crate) fn set_global_composition(&mut self, op: B::CompositionOrBlending) { + pub(crate) fn set_global_composition(&mut self, op: CompositionOrBlending) { self.backend.set_global_composition(op, &mut self.state); } @@ -1209,7 +1209,7 @@ impl<'a, B: Backend> CanvasData<'a, B> { flags: ImageDescriptorFlags::empty(), }; let data = SerializableImageData::Raw(IpcSharedMemory::from_bytes( - self.drawtarget.snapshot_data(), + self.drawtarget.bytes().as_ref(), )); self.compositor_api @@ -1292,7 +1292,7 @@ impl<'a, B: Backend> CanvasData<'a, B> { let mut new_draw_target = self.create_draw_target_for_shadow(&shadow_src_rect); draw_shadow_source(&mut new_draw_target); self.drawtarget.draw_surface_with_shadow( - new_draw_target.snapshot(), + new_draw_target.surface(), &Point2D::new(shadow_src_rect.origin.x, shadow_src_rect.origin.y), &self.state.shadow_color, &Vector2D::new( @@ -1323,11 +1323,11 @@ impl<'a, B: Backend> CanvasData<'a, B> { { vec![] } else { - let bytes = self.drawtarget.snapshot_data(); - pixels::rgba8_get_rect(bytes, canvas_size, read_rect).to_vec() + pixels::rgba8_get_rect(self.drawtarget.bytes().as_ref(), canvas_size, read_rect) + .to_vec() } } else { - self.drawtarget.snapshot_data().to_vec() + self.drawtarget.bytes().as_ref().to_vec() }; Snapshot::from_vec( diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index e88de701336..efe0ffd05b8 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -7,12 +7,10 @@ use std::collections::HashMap; use canvas_traits::canvas::*; use cssparser::color::clamp_unit_f32; -use euclid::Angle; use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D}; use font_kit::font::Font; use fonts::{ByteIndex, FontIdentifier, FontTemplateRefMethods}; use log::warn; -use lyon_geom::Arc; use range::Range; use raqote::PathOp; use style::color::AbsoluteColor; @@ -40,10 +38,10 @@ impl Backend for RaqoteBackend { type Color = raqote::SolidSource; type DrawOptions = raqote::DrawOptions; type CompositionOp = raqote::BlendMode; - type CompositionOrBlending = CompositionOrBlending; type DrawTarget = raqote::DrawTarget; type PathBuilder = PathBuilder; type SourceSurface = Vec<u8>; // TODO: See if we can avoid the alloc (probably?) + type Bytes<'a> = &'a [u8]; type Path = raqote::Path; type GradientStop = raqote::GradientStop; type GradientStops = Vec<raqote::GradientStop>; @@ -84,7 +82,7 @@ impl Backend for RaqoteBackend { fn set_global_composition( &mut self, - op: Self::CompositionOrBlending, + op: CompositionOrBlending, state: &mut CanvasPaintState<'_, Self>, ) { state.draw_options.blend_mode = op.to_raqote_style(); @@ -598,8 +596,8 @@ impl GenericDrawTarget<RaqoteBackend> for raqote::DrawTarget { fn set_transform(&mut self, matrix: &Transform2D<f32>) { self.set_transform(matrix); } - fn snapshot(&self) -> <RaqoteBackend as Backend>::SourceSurface { - self.snapshot_data().to_vec() + fn surface(&self) -> <RaqoteBackend as Backend>::SourceSurface { + self.bytes().to_vec() } fn stroke( &mut self, @@ -658,7 +656,7 @@ impl GenericDrawTarget<RaqoteBackend> for raqote::DrawTarget { ); } #[allow(unsafe_code)] - fn snapshot_data(&self) -> &[u8] { + fn bytes(&self) -> &[u8] { let v = self.get_data(); unsafe { std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of_val(v)) } } @@ -701,6 +699,7 @@ impl GenericPathBuilder<RaqoteBackend> for PathBuilder { anticlockwise, ); } + fn bezier_curve_to( &mut self, control_point1: &Point2D<f32>, @@ -716,66 +715,10 @@ impl GenericPathBuilder<RaqoteBackend> for PathBuilder { control_point3.y, ); } + fn close(&mut self) { self.0.as_mut().unwrap().close(); } - fn ellipse( - &mut self, - origin: Point2D<f32>, - radius_x: f32, - radius_y: f32, - rotation_angle: f32, - start_angle: f32, - end_angle: f32, - anticlockwise: bool, - ) { - let mut start = Angle::radians(start_angle); - let mut end = Angle::radians(end_angle); - - // Wrap angles mod 2 * PI if necessary - if !anticlockwise && start > end + Angle::two_pi() || - anticlockwise && end > start + Angle::two_pi() - { - start = start.positive(); - end = end.positive(); - } - - // Calculate the total arc we're going to sweep. - let sweep = match anticlockwise { - true => { - if end - start == Angle::two_pi() { - -Angle::two_pi() - } else if end > start { - -(Angle::two_pi() - (end - start)) - } else { - -(start - end) - } - }, - false => { - if start - end == Angle::two_pi() { - Angle::two_pi() - } else if start > end { - Angle::two_pi() - (start - end) - } else { - end - start - } - }, - }; - - let arc: Arc<f32> = Arc { - center: origin, - radii: Vector2D::new(radius_x, radius_y), - start_angle: start, - sweep_angle: sweep, - x_rotation: Angle::radians(rotation_angle), - }; - - self.line_to(arc.from()); - - arc.for_each_quadratic_bezier(&mut |q| { - self.quadratic_curve_to(&q.ctrl, &q.to); - }); - } fn svg_arc( &mut self, diff --git a/components/devtools/actors/inspector/node.rs b/components/devtools/actors/inspector/node.rs index 10ff9801844..a731f15b2d8 100644 --- a/components/devtools/actors/inspector/node.rs +++ b/components/devtools/actors/inspector/node.rs @@ -78,6 +78,18 @@ pub struct NodeActorMsg { shadow_root_mode: Option<String>, traits: HashMap<String, ()>, attrs: Vec<AttrMsg>, + + /// The `DOCTYPE` name if this is a `DocumentType` node, `None` otherwise + #[serde(skip_serializing_if = "Option::is_none")] + name: Option<String>, + + /// The `DOCTYPE` public identifier if this is a `DocumentType` node, `None` otherwise + #[serde(skip_serializing_if = "Option::is_none")] + public_id: Option<String>, + + /// The `DOCTYPE` system identifier if this is a `DocumentType` node, `None` otherwise + #[serde(skip_serializing_if = "Option::is_none")] + system_id: Option<String>, } pub struct NodeActor { @@ -276,6 +288,9 @@ impl NodeInfoToProtocol for NodeInfo { value: attr.value, }) .collect(), + name: self.doctype_name, + public_id: self.doctype_public_identifier, + system_id: self.doctype_system_identifier, } } } diff --git a/components/layout/table/construct.rs b/components/layout/table/construct.rs index f20360d3b56..56e11320be4 100644 --- a/components/layout/table/construct.rs +++ b/components/layout/table/construct.rs @@ -1019,15 +1019,16 @@ where DisplayLayoutInternal::TableCell => { // This value will already have filtered out rowspan=0 // in quirks mode, so we don't have to worry about that. - // - // The HTML specification limits the parsed value of `rowspan` to - // 65534 and `colspan` to 1000, so we also enforce the same limits - // when dealing with arbitrary DOM elements (perhaps created via - // script). let (rowspan, colspan) = if info.pseudo_element_type.is_none() { let node = info.node.to_threadsafe(); - let rowspan = node.get_rowspan().unwrap_or(1).min(65534) as usize; - let colspan = node.get_colspan().unwrap_or(1).min(1000) as usize; + let rowspan = node.get_rowspan().unwrap_or(1) as usize; + let colspan = node.get_colspan().unwrap_or(1) as usize; + + // The HTML specification clamps value of `rowspan` to [0, 65534] and + // `colspan` to [1, 1000]. + assert!((1..=1000).contains(&colspan)); + assert!((0..=65534).contains(&rowspan)); + (rowspan, colspan) } else { (1, 1) @@ -1140,21 +1141,19 @@ fn add_column<'dom, Node: NodeExt<'dom>>( is_anonymous: bool, ) -> ArcRefCell<TableTrack> { let span = if column_info.pseudo_element_type.is_none() { - column_info - .node - .to_threadsafe() - .get_span() - .unwrap_or(1) - .min(1000) as usize + column_info.node.to_threadsafe().get_span().unwrap_or(1) } else { 1 }; + // The HTML specification clamps value of `span` for `<col>` to [1, 1000]. + assert!((1..=1000).contains(&span)); + let column = ArcRefCell::new(TableTrack { base: LayoutBoxBase::new(column_info.into(), column_info.style.clone()), group_index, is_anonymous, }); - collection.extend(repeat(column.clone()).take(span)); + collection.extend(repeat(column.clone()).take(span as usize)); column } diff --git a/components/script/dom/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs index 4f312e928c4..8b553923230 100644 --- a/components/script/dom/htmltablecellelement.rs +++ b/components/script/dom/htmltablecellelement.rs @@ -70,13 +70,17 @@ impl HTMLTableCellElementMethods<crate::DomTypeHolder> for HTMLTableCellElement make_uint_getter!(ColSpan, "colspan", DEFAULT_COLSPAN); // https://html.spec.whatwg.org/multipage/#dom-tdth-colspan - make_uint_setter!(SetColSpan, "colspan", DEFAULT_COLSPAN); + // > The colSpan IDL attribute must reflect the colspan content attribute. It is clamped to + // > the range [1, 1000], and its default value is 1. + make_clamped_uint_setter!(SetColSpan, "colspan", 1, 1000, 1); // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan make_uint_getter!(RowSpan, "rowspan", DEFAULT_ROWSPAN); // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan - make_uint_setter!(SetRowSpan, "rowspan", DEFAULT_ROWSPAN); + // > The rowSpan IDL attribute must reflect the rowspan content attribute. It is clamped to + // > the range [0, 65534], and its default value is 1. + make_clamped_uint_setter!(SetRowSpan, "rowspan", 0, 65534, 1); // https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor make_getter!(BgColor, "bgcolor"); @@ -174,23 +178,26 @@ impl VirtualMethods for HTMLTableCellElement { match *local_name { local_name!("colspan") => { let mut attr = AttrValue::from_u32(value.into(), DEFAULT_COLSPAN); - if let AttrValue::UInt(_, ref mut val) = attr { - if *val == 0 { - *val = 1; - } + if let AttrValue::UInt(_, ref mut value) = attr { + // From <https://html.spec.whatwg.org/multipage/#dom-tdth-colspan>: + // > The colSpan IDL attribute must reflect the colspan content attribute. It is clamped to + // > the range [1, 1000], and its default value is 1. + *value = (*value).clamp(1, 1000); } attr }, local_name!("rowspan") => { let mut attr = AttrValue::from_u32(value.into(), DEFAULT_ROWSPAN); - if let AttrValue::UInt(_, ref mut val) = attr { - if *val == 0 { - let node = self.upcast::<Node>(); - let doc = node.owner_doc(); - // rowspan = 0 is not supported in quirks mode - if doc.quirks_mode() != QuirksMode::NoQuirks { - *val = 1; - } + if let AttrValue::UInt(_, ref mut value) = attr { + // From <https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan>: + // > The rowSpan IDL attribute must reflect the rowspan content attribute. It is clamped to + // > the range [0, 65534], and its default value is 1. + // Note that rowspan = 0 is not supported in quirks mode. + let document = self.upcast::<Node>().owner_doc(); + if document.quirks_mode() != QuirksMode::NoQuirks { + *value = (*value).clamp(1, 65534); + } else { + *value = (*value).clamp(0, 65534); } } attr diff --git a/components/script/dom/htmltablecolelement.rs b/components/script/dom/htmltablecolelement.rs index c7ad4afd944..9e8eecf1147 100644 --- a/components/script/dom/htmltablecolelement.rs +++ b/components/script/dom/htmltablecolelement.rs @@ -20,8 +20,6 @@ use crate::dom::node::Node; use crate::dom::virtualmethods::VirtualMethods; use crate::script_runtime::CanGc; -const DEFAULT_SPAN: u32 = 1; - #[dom_struct] pub(crate) struct HTMLTableColElement { htmlelement: HTMLElement, @@ -62,9 +60,11 @@ impl HTMLTableColElement { impl HTMLTableColElementMethods<crate::DomTypeHolder> for HTMLTableColElement { // <https://html.spec.whatwg.org/multipage/#attr-col-span> - make_uint_getter!(Span, "span", DEFAULT_SPAN); + make_uint_getter!(Span, "span", 1); // <https://html.spec.whatwg.org/multipage/#attr-col-span> - make_uint_setter!(SetSpan, "span", DEFAULT_SPAN); + // > The span IDL attribute must reflect the content attribute of the same name. It is clamped + // > to the range [1, 1000], and its default value is 1. + make_clamped_uint_setter!(SetSpan, "span", 1, 1000, 1); } pub(crate) trait HTMLTableColElementLayoutHelpers<'dom> { @@ -96,11 +96,12 @@ impl VirtualMethods for HTMLTableColElement { fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue { match *local_name { local_name!("span") => { - let mut attr = AttrValue::from_u32(value.into(), DEFAULT_SPAN); + let mut attr = AttrValue::from_u32(value.into(), 1); if let AttrValue::UInt(_, ref mut val) = attr { - if *val == 0 { - *val = 1; - } + // From <https://html.spec.whatwg.org/multipage/#attr-col-span>: + // > The span IDL attribute must reflect the content attribute of the same name. + // > It is clamped to the range [1, 1000], and its default value is 1. + *val = (*val).clamp(1, 1000); } attr }, diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index c2f5ba37c21..997341984c6 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -318,6 +318,26 @@ macro_rules! make_uint_setter( ); #[macro_export] +macro_rules! make_clamped_uint_setter( + ($attr:ident, $htmlname:tt, $min:expr, $max:expr, $default:expr) => ( + fn $attr(&self, value: u32) { + use $crate::dom::bindings::inheritance::Castable; + use $crate::dom::element::Element; + use $crate::dom::values::UNSIGNED_LONG_MAX; + use $crate::script_runtime::CanGc; + let value = if value > UNSIGNED_LONG_MAX { + $default + } else { + value.clamp($min, $max) + }; + + let element = self.upcast::<Element>(); + element.set_uint_attribute(&html5ever::local_name!($htmlname), value, CanGc::note()) + } + ); +); + +#[macro_export] macro_rules! make_limited_uint_setter( ($attr:ident, $htmlname:tt, $default:expr) => ( fn $attr(&self, value: u32) -> $crate::dom::bindings::error::ErrorResult { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 1117eff6d3c..2caec47de25 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1283,6 +1283,21 @@ impl Node { is_shadow_host, shadow_root_mode, display, + doctype_name: self + .downcast::<DocumentType>() + .map(DocumentType::name) + .cloned() + .map(String::from), + doctype_public_identifier: self + .downcast::<DocumentType>() + .map(DocumentType::public_id) + .cloned() + .map(String::from), + doctype_system_identifier: self + .downcast::<DocumentType>() + .map(DocumentType::system_id) + .cloned() + .map(String::from), } } diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 6f39e773e4e..366685e1123 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -120,6 +120,7 @@ pub use {bluetooth, bluetooth_traits}; use crate::proxies::ConstellationProxy; use crate::responders::ServoErrorChannel; pub use crate::servo_delegate::{ServoDelegate, ServoError}; +use crate::webrender_api::FrameReadyParams; pub use crate::webview::{WebView, WebViewBuilder}; pub use crate::webview_delegate::{ AllowOrDenyRequest, AuthenticationRequest, FormControl, NavigationRequest, PermissionRequest, @@ -233,14 +234,13 @@ impl webrender_api::RenderNotifier for RenderNotifier { fn new_frame_ready( &self, document_id: DocumentId, - _scrolled: bool, - composite_needed: bool, - _frame_publish_id: FramePublishId, + _: FramePublishId, + frame_ready_params: &FrameReadyParams, ) { self.compositor_proxy .send(CompositorMsg::NewWebRenderFrameReady( document_id, - composite_needed, + frame_ready_params.render, )); } } diff --git a/components/shared/devtools/lib.rs b/components/shared/devtools/lib.rs index 0cf99d22658..c07f4529073 100644 --- a/components/shared/devtools/lib.rs +++ b/components/shared/devtools/lib.rs @@ -144,6 +144,15 @@ pub struct NodeInfo { pub shadow_root_mode: Option<ShadowRootMode>, pub is_shadow_host: bool, pub display: Option<String>, + + /// The `DOCTYPE` name if this is a `DocumentType` node, `None` otherwise + pub doctype_name: Option<String>, + + /// The `DOCTYPE` public identifier if this is a `DocumentType` node , `None` otherwise + pub doctype_public_identifier: Option<String>, + + /// The `DOCTYPE` system identifier if this is a `DocumentType` node, `None` otherwise + pub doctype_system_identifier: Option<String>, } pub struct StartedTimelineMarker { diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index b5e319c83c3..5385c0403b4 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -4916,6 +4916,13 @@ {} ] ], + "colspan-zero-crash.html": [ + "a50586a5bfa7551724b838a0438339a34b4930fb", + [ + null, + {} + ] + ], "crashtests": { "caption-repaint-crash.html": [ "6a024d0c1d7ef58da06a489d80d187bcb2a3e350", @@ -7833,6 +7840,13 @@ {} ] ], + "iframe-hit-test-during-load-event-crash.html": [ + "f668fc51573647e633fc3ac6430735d6fb4dfea7", + [ + null, + {} + ] + ], "iframe-loading-lazy-simple-crash.html": [ "b0b251438f73811ce2ec4d82fe47ffb3a2445c93", [ @@ -739702,14 +739716,14 @@ ], "processing-model-1": { "col-span-limits.html": [ - "a4a425b9c1f70926c77ad3eb1b8a8a87a4655de9", + "2a1ac80e65ad37a0e15ca383e67889b79f2308d0", [ null, {} ] ], "span-limits.html": [ - "cdfa61bbcdc06ea62b80d042440d55fb0c89a186", + "798639b387562a54965d5283673a50773c2a3c49", [ null, { diff --git a/tests/wpt/meta/html/dom/reflection-tabular.html.ini b/tests/wpt/meta/html/dom/reflection-tabular.html.ini index 7550e2dc15d..1aeec1b3ef7 100644 --- a/tests/wpt/meta/html/dom/reflection-tabular.html.ini +++ b/tests/wpt/meta/html/dom/reflection-tabular.html.ini @@ -1487,9 +1487,6 @@ [colgroup.tabIndex: IDL set to -2147483648] expected: FAIL - [colgroup.span: setAttribute() to 2147483647] - expected: FAIL - [colgroup.span: setAttribute() to 2147483648] expected: FAIL @@ -1499,9 +1496,6 @@ [colgroup.span: setAttribute() to 4294967296] expected: FAIL - [colgroup.span: setAttribute() to 1001] - expected: FAIL - [colgroup.span: IDL set to 0] expected: FAIL @@ -2276,9 +2270,6 @@ [col.tabIndex: IDL set to -2147483648] expected: FAIL - [col.span: setAttribute() to 2147483647] - expected: FAIL - [col.span: setAttribute() to 2147483648] expected: FAIL @@ -2288,9 +2279,6 @@ [col.span: setAttribute() to 4294967296] expected: FAIL - [col.span: setAttribute() to 1001] - expected: FAIL - [col.span: IDL set to 0] expected: FAIL @@ -5657,9 +5645,6 @@ [td.tabIndex: IDL set to -2147483648] expected: FAIL - [td.colSpan: setAttribute() to 2147483647] - expected: FAIL - [td.colSpan: setAttribute() to 2147483648] expected: FAIL @@ -5669,9 +5654,6 @@ [td.colSpan: setAttribute() to 4294967296] expected: FAIL - [td.colSpan: setAttribute() to 1001] - expected: FAIL - [td.colSpan: IDL set to 0] expected: FAIL @@ -5684,9 +5666,6 @@ [td.colSpan: IDL set to 1001] expected: FAIL - [td.rowSpan: setAttribute() to 2147483647] - expected: FAIL - [td.rowSpan: setAttribute() to 2147483648] expected: FAIL @@ -5696,9 +5675,6 @@ [td.rowSpan: setAttribute() to 4294967296] expected: FAIL - [td.rowSpan: setAttribute() to 65535] - expected: FAIL - [td.rowSpan: IDL set to 2147483647] expected: FAIL @@ -7157,9 +7133,6 @@ [th.tabIndex: IDL set to -2147483648] expected: FAIL - [th.colSpan: setAttribute() to 2147483647] - expected: FAIL - [th.colSpan: setAttribute() to 2147483648] expected: FAIL @@ -7169,9 +7142,6 @@ [th.colSpan: setAttribute() to 4294967296] expected: FAIL - [th.colSpan: setAttribute() to 1001] - expected: FAIL - [th.colSpan: IDL set to 0] expected: FAIL @@ -7184,9 +7154,6 @@ [th.colSpan: IDL set to 1001] expected: FAIL - [th.rowSpan: setAttribute() to 2147483647] - expected: FAIL - [th.rowSpan: setAttribute() to 2147483648] expected: FAIL @@ -7196,9 +7163,6 @@ [th.rowSpan: setAttribute() to 4294967296] expected: FAIL - [th.rowSpan: setAttribute() to 65535] - expected: FAIL - [th.rowSpan: IDL set to 2147483647] expected: FAIL diff --git a/tests/wpt/tests/css/css-tables/colspan-zero-crash.html b/tests/wpt/tests/css/css-tables/colspan-zero-crash.html new file mode 100644 index 00000000000..a50586a5bfa --- /dev/null +++ b/tests/wpt/tests/css/css-tables/colspan-zero-crash.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<link rel="help" href="https://github.com/servo/servo/issues/36699"> +<link rel="author" href="mailto:fwang@igalia.com" title="Frédéric Wang"> +<span id="span"></span> +<script> + let th = document.createElement("th"); + span.replaceWith(th); + th.colSpan = 0; +</script> + diff --git a/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-hit-test-during-load-event-crash.html b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-hit-test-during-load-event-crash.html new file mode 100644 index 00000000000..f668fc51573 --- /dev/null +++ b/tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-hit-test-during-load-event-crash.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<div style="visibility: hidden;"> + <iframe id="iframe"></iframe> +</div> +<script> + window.addEventListener("load", _ => + iframe.contentDocument.elementFromPoint(0, 0) + ); +</script> diff --git a/tests/wpt/tests/html/semantics/tabular-data/processing-model-1/col-span-limits.html b/tests/wpt/tests/html/semantics/tabular-data/processing-model-1/col-span-limits.html index a4a425b9c1f..2a1ac80e65a 100644 --- a/tests/wpt/tests/html/semantics/tabular-data/processing-model-1/col-span-limits.html +++ b/tests/wpt/tests/html/semantics/tabular-data/processing-model-1/col-span-limits.html @@ -39,12 +39,21 @@ These two must look the same, each having 2 cells in one row: </table> <br> <table id=table3> - <col span=1001> + <col id="colspan-3" span=1001> <tr> <td colspan=1000><div class="square"></div></td> <td><div class="square"></div></td> </tr> </table> +<table> + <tr> + <td id="colspan-limit-test1" colspan=5></td> + <td id="colspan-limit-test2" colspan=0></td> + <td id="colspan-limit-test3" colspan=1000></td> + <td id="colspan-limit-test4" colspan=1001></td> + <td id="colspan-limit-test5" colspan=5555555></td> + </tr> +</table> </main> <script> @@ -56,4 +65,48 @@ test(() => { assert_equals(table2.offsetWidth, 51, "table2 width"); assert_equals(table3.offsetWidth, 51, "table3 width"); }, "col span of 1001 must be treated as 1000"); + +test(() => { + let td = document.createElement("td"); + td.colSpan = 5; + assert_equals(td.colSpan, 5); + + td.colSpan = 0; + assert_equals(td.colSpan, 1); + + td.colSpan = 1000; + assert_equals(td.colSpan, 1000); + + td.colSpan = 1001; + assert_equals(td.colSpan, 1000); + + td.colSpan = 555555; + assert_equals(td.colSpan, 1000); +}, "colspan must be clamped to [1, 1000] when set via script"); + +test(() => { + assert_equals(document.getElementById("colspan-limit-test1").colSpan, 5); + assert_equals(document.getElementById("colspan-limit-test2").colSpan, 1); + assert_equals(document.getElementById("colspan-limit-test3").colSpan, 1000); + assert_equals(document.getElementById("colspan-limit-test4").colSpan, 1000); + assert_equals(document.getElementById("colspan-limit-test5").colSpan, 1000); +}, "colspan must be clamped to [1, 1000] when parsing attributes"); + +test(() => { + let column = document.getElementById("colspan-3"); + column.span = 5; + assert_equals(column.span, 5); + + column.span = 0; + assert_equals(column.span, 1); + + column.span = 1000; + assert_equals(column.span, 1000); + + column.span = 1001; + assert_equals(column.span, 1000); + + column.span = 555555; + assert_equals(column.span, 1000); +}, "column span must be clamped to [1, 1000] when set via script"); </script> diff --git a/tests/wpt/tests/html/semantics/tabular-data/processing-model-1/span-limits.html b/tests/wpt/tests/html/semantics/tabular-data/processing-model-1/span-limits.html index cdfa61bbcdc..798639b3875 100644 --- a/tests/wpt/tests/html/semantics/tabular-data/processing-model-1/span-limits.html +++ b/tests/wpt/tests/html/semantics/tabular-data/processing-model-1/span-limits.html @@ -29,6 +29,17 @@ <!-- We'll add another 65534 rows later --> </table> +<table> + <tr> + <td id="rowspan-limit-test1" rowspan=5></td> + <td id="rowspan-limit-test2" rowspan=0></td> + <td id="rowspan-limit-test3" rowspan=1000></td> + <td id="rowspan-limit-test4" rowspan=65534></td> + <td id="rowspan-limit-test5" rowspan=65535></td> + <td id="rowspan-limit-test6" rowspan=5555555></td> + </tr> +</table> + <script> var $ = document.querySelector.bind(document); @@ -63,4 +74,34 @@ test(() => { assert_equals($("#d1").getBoundingClientRect().bottom, $("#d2").getBoundingClientRect().bottom); }, "rowspan of 65535 must be treated as 65534"); + +test(() => { + let td = document.createElement("td"); + td.rowSpan = 5; + assert_equals(td.rowSpan, 5); + + td.rowSpan = 0; + assert_equals(td.rowSpan, 0); + + td.rowSpan = 1000; + assert_equals(td.rowSpan, 1000); + + td.rowSpan = 65534; + assert_equals(td.rowSpan, 65534); + + td.rowSpan = 65535; + assert_equals(td.rowSpan, 65534); + + td.rowSpan = 555555; + assert_equals(td.rowSpan, 65534); +}, "rowspan must be clamped to [0, 65534] when set via script"); + +test(() => { + assert_equals(document.getElementById("rowspan-limit-test1").rowSpan, 5); + assert_equals(document.getElementById("rowspan-limit-test2").rowSpan, 0); + assert_equals(document.getElementById("rowspan-limit-test3").rowSpan, 1000); + assert_equals(document.getElementById("rowspan-limit-test4").rowSpan, 65534); + assert_equals(document.getElementById("rowspan-limit-test5").rowSpan, 65534); + assert_equals(document.getElementById("rowspan-limit-test6").rowSpan, 65534); +}, "rowspan must be clamped to [0, 65534] when parsing attributes"); </script> |