Files
ladybird/Libraries/LibWeb/HTML/HTMLHeadingElement.cpp
Tim Ledbetter d1fc4b4234 LibWeb: Route presentational hints through the CSS cascade
Previously, presentational hints bypassed the regular cascade pipeline
and wrote directly into `CascadedProperties` under
`CascadeOrigin::Author`. That meant `var()` substitution and the
invalid-at-computed-value-time fallback had to be duplicated in a
separate per-element pass, which in practice missed the IACVT step and
could leave a `GuaranteedInvalidStyleValue` in the cascaded
properties. This caused a crash in downstream code that assumed the
value had been resolved.

This introduces an `AuthorPresentationalHint` cascade origin and feeds
them through the cascade as normal declarations. This means that
`var()` resolution now happens in only one place.
2026-04-30 19:50:28 +01:00

70 lines
2.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/HTMLHeadingElement.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/CSS/ComputedProperties.h>
#include <LibWeb/CSS/StyleValues/KeywordStyleValue.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/HTML/HTMLHeadingElement.h>
namespace Web::HTML {
GC_DEFINE_ALLOCATOR(HTMLHeadingElement);
HTMLHeadingElement::HTMLHeadingElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: HTMLElement(document, move(qualified_name))
{
}
HTMLHeadingElement::~HTMLHeadingElement() = default;
void HTMLHeadingElement::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(HTMLHeadingElement);
Base::initialize(realm);
}
bool HTMLHeadingElement::is_presentational_hint(FlyString const& name) const
{
if (Base::is_presentational_hint(name))
return true;
return name == HTML::AttributeNames::align;
}
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2
void HTMLHeadingElement::apply_presentational_hints(Vector<CSS::StyleProperty>& properties) const
{
HTMLElement::apply_presentational_hints(properties);
for_each_attribute([&](auto& name, auto& value) {
if (name == HTML::AttributeNames::align) {
if (value == "left"sv)
properties.append({ .property_id = CSS::PropertyID::TextAlign, .value = CSS::KeywordStyleValue::create(CSS::Keyword::Left) });
else if (value == "right"sv)
properties.append({ .property_id = CSS::PropertyID::TextAlign, .value = CSS::KeywordStyleValue::create(CSS::Keyword::Right) });
else if (value == "center"sv)
properties.append({ .property_id = CSS::PropertyID::TextAlign, .value = CSS::KeywordStyleValue::create(CSS::Keyword::Center) });
else if (value == "justify"sv)
properties.append({ .property_id = CSS::PropertyID::TextAlign, .value = CSS::KeywordStyleValue::create(CSS::Keyword::Justify) });
}
});
}
// https://html.spec.whatwg.org/multipage/sections.html#heading-level
WebIDL::UnsignedLong HTMLHeadingElement::heading_level() const
{
// h1h6 elements have a heading level, which is given by getting the element's computed heading level.
if (m_dom_tree_version_for_cached_heading_level < document().dom_tree_version()) {
m_dom_tree_version_for_cached_heading_level = document().dom_tree_version();
m_cached_heading_level = computed_heading_level();
}
return m_cached_heading_level;
}
}