aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock30
-rw-r--r--Cargo.toml6
-rw-r--r--components/canvas/backend.rs63
-rw-r--r--components/canvas/canvas_data.rs14
-rw-r--r--components/canvas/raqote_backend.rs71
-rw-r--r--components/devtools/actors/inspector/node.rs15
-rw-r--r--components/layout/table/construct.rs27
-rw-r--r--components/script/dom/htmltablecellelement.rs35
-rw-r--r--components/script/dom/htmltablecolelement.rs17
-rw-r--r--components/script/dom/macros.rs20
-rw-r--r--components/script/dom/node.rs15
-rw-r--r--components/servo/lib.rs8
-rw-r--r--components/shared/devtools/lib.rs9
-rw-r--r--tests/wpt/meta/MANIFEST.json18
-rw-r--r--tests/wpt/meta/html/dom/reflection-tabular.html.ini36
-rw-r--r--tests/wpt/tests/css/css-tables/colspan-zero-crash.html10
-rw-r--r--tests/wpt/tests/html/semantics/embedded-content/the-iframe-element/iframe-hit-test-during-load-event-crash.html9
-rw-r--r--tests/wpt/tests/html/semantics/tabular-data/processing-model-1/col-span-limits.html55
-rw-r--r--tests/wpt/tests/html/semantics/tabular-data/processing-model-1/span-limits.html41
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>