Implement the size presentational hint for <hr> elements (#37211)

This presentational hint either sets the width values of all borders,
removes the bottom border or sets the height of the element, depending
on the context.

This change also implements the corresponding idl attribute (and the
`noshade` attribute, which does nothing in html5)

Testing: Adds new web platform tests

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
Simon Wülker 2025-06-03 13:22:44 +02:00 committed by GitHub
parent b4035cc88e
commit 8937542fe3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 204 additions and 251 deletions

View file

@ -121,7 +121,7 @@ use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmlfieldsetelement::HTMLFieldSetElement;
use crate::dom::htmlfontelement::{HTMLFontElement, HTMLFontElementLayoutHelpers};
use crate::dom::htmlformelement::FormControlElementHelpers;
use crate::dom::htmlhrelement::{HTMLHRElement, HTMLHRLayoutHelpers};
use crate::dom::htmlhrelement::{HTMLHRElement, HTMLHRLayoutHelpers, SizePresentationalHint};
use crate::dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
use crate::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
use crate::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
@ -1306,6 +1306,47 @@ impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> {
PropertyDeclaration::PaddingRight(cellpadding),
));
}
// https://html.spec.whatwg.org/multipage/#the-hr-element-2
if let Some(size_info) = self
.downcast::<HTMLHRElement>()
.and_then(|hr_element| hr_element.get_size_info())
{
match size_info {
SizePresentationalHint::SetHeightTo(height) => {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Height(height),
));
},
SizePresentationalHint::SetAllBorderWidthValuesTo(border_width) => {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderLeftWidth(border_width.clone()),
));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderRightWidth(border_width.clone()),
));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderTopWidth(border_width.clone()),
));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderBottomWidth(border_width),
));
},
SizePresentationalHint::SetBottomBorderWidthToZero => {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderBottomWidth(
specified::border::BorderSideWidth::from_px(0.),
),
));
},
}
}
}
fn get_span(self) -> Option<u32> {

View file

@ -2,11 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::str::FromStr;
use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix, local_name, ns};
use js::rust::HandleObject;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::color::AbsoluteColor;
use style::values::generics::NonNegative;
use style::values::specified::border::BorderSideWidth;
use style::values::specified::length::Size;
use style::values::specified::{LengthPercentage, NoCalcLength};
use crate::dom::bindings::codegen::Bindings::HTMLHRElementBinding::HTMLHRElementMethods;
use crate::dom::bindings::inheritance::Castable;
@ -65,6 +71,18 @@ impl HTMLHRElementMethods<crate::DomTypeHolder> for HTMLHRElement {
// https://html.spec.whatwg.org/multipage/#dom-hr-color
make_legacy_color_setter!(SetColor, "color");
// https://html.spec.whatwg.org/multipage/#dom-hr-noshade
make_bool_getter!(NoShade, "noshade");
// https://html.spec.whatwg.org/multipage/#dom-hr-noshade
make_bool_setter!(SetNoShade, "noshade");
// https://html.spec.whatwg.org/multipage/#dom-hr-size
make_getter!(Size, "size");
// https://html.spec.whatwg.org/multipage/#dom-hr-size
make_dimension_setter!(SetSize, "size");
// https://html.spec.whatwg.org/multipage/#dom-hr-width
make_getter!(Width, "width");
@ -72,9 +90,20 @@ impl HTMLHRElementMethods<crate::DomTypeHolder> for HTMLHRElement {
make_dimension_setter!(SetWidth, "width");
}
/// The result of applying the the presentational hint for the `size` attribute.
///
/// (This attribute can mean different things depending on its value and other attributes)
#[allow(clippy::enum_variant_names)]
pub(crate) enum SizePresentationalHint {
SetHeightTo(Size),
SetAllBorderWidthValuesTo(BorderSideWidth),
SetBottomBorderWidthToZero,
}
pub(crate) trait HTMLHRLayoutHelpers {
fn get_color(self) -> Option<AbsoluteColor>;
fn get_width(self) -> LengthOrPercentageOrAuto;
fn get_size_info(self) -> Option<SizePresentationalHint>;
}
impl HTMLHRLayoutHelpers for LayoutDom<'_, HTMLHRElement> {
@ -92,6 +121,35 @@ impl HTMLHRLayoutHelpers for LayoutDom<'_, HTMLHRElement> {
.cloned()
.unwrap_or(LengthOrPercentageOrAuto::Auto)
}
fn get_size_info(self) -> Option<SizePresentationalHint> {
// https://html.spec.whatwg.org/multipage/#the-hr-element-2
let element = self.upcast::<Element>();
let size_value = element
.get_attr_val_for_layout(&ns!(), &local_name!("size"))
.and_then(|value| usize::from_str(value).ok())
.filter(|value| *value != 0)?;
let hint = if element
.get_attr_for_layout(&ns!(), &local_name!("color"))
.is_some() ||
element
.get_attr_for_layout(&ns!(), &local_name!("noshade"))
.is_some()
{
SizePresentationalHint::SetAllBorderWidthValuesTo(BorderSideWidth::from_px(
size_value as f32 / 2.0,
))
} else if size_value == 1 {
SizePresentationalHint::SetBottomBorderWidthToZero
} else {
SizePresentationalHint::SetHeightTo(Size::LengthPercentage(NonNegative(
LengthPercentage::Length(NoCalcLength::from_px((size_value - 2) as f32)),
)))
};
Some(hint)
}
}
impl VirtualMethods for HTMLHRElement {