servo/components/script/dom/htmltablecolelement.rs
Martin Robinson 0d21992edd
script: Clamp table spans according to the HTML specification (#36703)
Previously, spans were partially clamped during layout, but this means
that accessing and setting these properties via script wouldn't behave
according to the HTML specification. In addition, the value wasn't
floored in layout, so could lead to panics. This change improves
clamping and moves it to script.
    
Testing: This change includes a new WPT test.
Fixes #36699.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-05-01 13:25:34 +00:00

115 lines
4 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use super::bindings::root::LayoutDom;
use super::element::Element;
use crate::dom::bindings::codegen::Bindings::HTMLTableColElementBinding::HTMLTableColElementMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::document::Document;
use crate::dom::element::LayoutElementHelpers;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::node::Node;
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
#[dom_struct]
pub(crate) struct HTMLTableColElement {
htmlelement: HTMLElement,
}
impl HTMLTableColElement {
fn new_inherited(
local_name: LocalName,
prefix: Option<Prefix>,
document: &Document,
) -> HTMLTableColElement {
HTMLTableColElement {
htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
}
}
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
pub(crate) fn new(
local_name: LocalName,
prefix: Option<Prefix>,
document: &Document,
proto: Option<HandleObject>,
can_gc: CanGc,
) -> DomRoot<HTMLTableColElement> {
let n = Node::reflect_node_with_proto(
Box::new(HTMLTableColElement::new_inherited(
local_name, prefix, document,
)),
document,
proto,
can_gc,
);
n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}
}
impl HTMLTableColElementMethods<crate::DomTypeHolder> for HTMLTableColElement {
// <https://html.spec.whatwg.org/multipage/#attr-col-span>
make_uint_getter!(Span, "span", 1);
// <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.
make_clamped_uint_setter!(SetSpan, "span", 1, 1000, 1);
}
pub(crate) trait HTMLTableColElementLayoutHelpers<'dom> {
fn get_span(self) -> Option<u32>;
fn get_width(self) -> LengthOrPercentageOrAuto;
}
impl<'dom> HTMLTableColElementLayoutHelpers<'dom> for LayoutDom<'dom, HTMLTableColElement> {
fn get_span(self) -> Option<u32> {
self.upcast::<Element>()
.get_attr_for_layout(&ns!(), &local_name!("span"))
.map(AttrValue::as_uint)
}
fn get_width(self) -> LengthOrPercentageOrAuto {
self.upcast::<Element>()
.get_attr_for_layout(&ns!(), &local_name!("width"))
.map(AttrValue::as_dimension)
.cloned()
.unwrap_or(LengthOrPercentageOrAuto::Auto)
}
}
impl VirtualMethods for HTMLTableColElement {
fn super_type(&self) -> Option<&dyn VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
}
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(), 1);
if let AttrValue::UInt(_, ref mut val) = attr {
// 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
},
local_name!("width") => AttrValue::from_dimension(value.into()),
_ => self
.super_type()
.unwrap()
.parse_plain_attribute(local_name, value),
}
}
}