diff --git a/Tests/LibWeb/Layout/expected/css-namespace-tag-name-selector.txt b/Tests/LibWeb/Layout/expected/css-namespace-tag-name-selector.txt index 79b76a628d..f6e14de298 100644 --- a/Tests/LibWeb/Layout/expected/css-namespace-tag-name-selector.txt +++ b/Tests/LibWeb/Layout/expected/css-namespace-tag-name-selector.txt @@ -1,6 +1,6 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline - BlockContainer at (8,8) content-size 784x201.125 children: not-inline + BlockContainer at (8,8) content-size 784x201.15625 children: not-inline BlockContainer <(anonymous)> at (8,8) content-size 784x155.46875 children: inline line 0 width: 312, height: 155.46875, bottom: 155.46875, baseline: 152 frag 0 from SVGSVGBox start: 0, length: 0, rect: [9,9 300x150] @@ -16,24 +16,24 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline Box at (8,8) content-size 100x100 children: inline TextNode <#text> TextNode <#text> - BlockContainer
at (9,164.46875) content-size 782x43.65625 children: inline - line 0 width: 101.453125, height: 43.65625, bottom: 43.65625, baseline: 33.828125 + BlockContainer
at (9,164.46875) content-size 782x43.6875 children: inline + line 0 width: 101.453125, height: 43.6875, bottom: 43.6875, baseline: 33.84375 frag 0 from TextNode start: 0, length: 5, rect: [10,164.46875 99.453125x43.671875] "Hello" InlineNode TextNode <#text> - BlockContainer <(anonymous)> at (8,209.125) content-size 784x0 children: inline + BlockContainer <(anonymous)> at (8,209.15625) content-size 784x0 children: inline TextNode <#text> ViewportPaintable (Viewport<#document>) [0,0 800x600] PaintableWithLines (BlockContainer) [0,0 800x600] - PaintableWithLines (BlockContainer) [8,8 784x201.125] + PaintableWithLines (BlockContainer) [8,8 784x201.15625] PaintableWithLines (BlockContainer(anonymous)) [8,8 784x155.46875] SVGSVGPaintable (SVGSVGBox) [8,8 302x152] TextPaintable (TextNode<#text>) PaintableBox (Box) [318,50 2x110] overflow: [8,8 100x100] PaintableBox (Box) [8,8 100x100] - PaintableWithLines (BlockContainer
) [8,163.46875 784x45.65625] overflow: [9,164.46875 782x43.671875] + PaintableWithLines (BlockContainer
) [8,163.46875 784x45.6875] InlinePaintable (InlineNode) TextPaintable (TextNode<#text>) - PaintableWithLines (BlockContainer(anonymous)) [8,209.125 784x0] + PaintableWithLines (BlockContainer(anonymous)) [8,209.15625 784x0] diff --git a/Tests/LibWeb/Text/expected/css/math-depth.txt b/Tests/LibWeb/Text/expected/css/math-depth.txt new file mode 100644 index 0000000000..7377930412 --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/math-depth.txt @@ -0,0 +1,6 @@ + 0 +1 +1 +1 +2 +2 diff --git a/Tests/LibWeb/Text/input/css/math-depth.html b/Tests/LibWeb/Text/input/css/math-depth.html new file mode 100644 index 0000000000..0e0ca670ce --- /dev/null +++ b/Tests/LibWeb/Text/input/css/math-depth.html @@ -0,0 +1,26 @@ + + + + +
    +
  • +
  • +
      +
    • +
    • +
    +
  • +
+ diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 60fdd97e4d..738abe203a 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -111,6 +111,7 @@ set(SOURCES CSS/StyleValues/LengthStyleValue.cpp CSS/StyleValues/LinearGradientStyleValue.cpp CSS/StyleValues/ListStyleStyleValue.cpp + CSS/StyleValues/MathDepthStyleValue.cpp CSS/StyleValues/NumberStyleValue.cpp CSS/StyleValues/OverflowStyleValue.cpp CSS/StyleValues/PlaceContentStyleValue.cpp diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index 415cf1c80b..739620738e 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -123,6 +123,7 @@ public: static CSS::MathShift math_shift() { return CSS::MathShift::Normal; } static CSS::MathStyle math_style() { return CSS::MathStyle::Normal; } + static int math_depth() { return 0; } }; enum class BackgroundSize { @@ -351,6 +352,7 @@ public: CSS::MathShift math_shift() const { return m_inherited.math_shift; } CSS::MathStyle math_style() const { return m_inherited.math_style; } + int math_depth() const { return m_inherited.math_depth; } ComputedValues clone_inherited_values() const { @@ -394,6 +396,7 @@ protected: CSS::MathShift math_shift { InitialValues::math_shift() }; CSS::MathStyle math_style { InitialValues::math_style() }; + int math_depth { InitialValues::math_depth() }; } m_inherited; struct { @@ -591,6 +594,7 @@ public: void set_math_shift(CSS::MathShift value) { m_inherited.math_shift = value; } void set_math_style(CSS::MathStyle value) { m_inherited.math_style = value; } + void set_math_depth(int value) { m_inherited.math_depth = value; } }; } diff --git a/Userland/Libraries/LibWeb/CSS/Identifiers.json b/Userland/Libraries/LibWeb/CSS/Identifiers.json index c62c31410b..786831d24e 100644 --- a/Userland/Libraries/LibWeb/CSS/Identifiers.json +++ b/Userland/Libraries/LibWeb/CSS/Identifiers.json @@ -73,6 +73,7 @@ "anywhere", "appworkspace", "auto", + "auto-add", "back", "background", "backwards", diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index e408fda748..9fe7d9f5c2 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -4455,6 +4456,51 @@ RefPtr Parser::parse_list_style_value(Vector const& return ListStyleStyleValue::create(list_position.release_nonnull(), list_image.release_nonnull(), list_type.release_nonnull()); } +RefPtr Parser::parse_math_depth_value(Vector const& component_values) +{ + // https://w3c.github.io/mathml-core/#propdef-math-depth + // auto-add | add() | + auto tokens = TokenStream { component_values }; + + tokens.skip_whitespace(); + auto token = tokens.next_token(); + tokens.skip_whitespace(); + if (tokens.has_next_token()) + return nullptr; + + // auto-add + if (token.is_ident("auto-add"sv)) + return MathDepthStyleValue::create_auto_add(); + + // FIXME: Make it easier to parse "thing that might be or literally anything that resolves to it" and get rid of this + auto parse_something_that_resolves_to_integer = [this](ComponentValue& token) -> RefPtr { + if (token.is(Token::Type::Number) && token.token().number().is_integer()) + return IntegerStyleValue::create(token.token().to_integer()); + if (auto value = parse_calculated_value(token); value && value->resolves_to_number()) + return value; + return nullptr; + }; + + // add() + if (token.is_function("add"sv)) { + auto add_tokens = TokenStream { token.function().values() }; + add_tokens.skip_whitespace(); + auto integer_token = add_tokens.next_token(); + add_tokens.skip_whitespace(); + if (add_tokens.has_next_token()) + return nullptr; + if (auto integer_value = parse_something_that_resolves_to_integer(integer_token)) + return MathDepthStyleValue::create_add(integer_value.release_nonnull()); + return nullptr; + } + + // + if (auto integer_value = parse_something_that_resolves_to_integer(token)) + return MathDepthStyleValue::create_integer(integer_value.release_nonnull()); + + return nullptr; +} + RefPtr Parser::parse_overflow_value(Vector const& component_values) { auto tokens = TokenStream { component_values }; @@ -5799,6 +5845,10 @@ Parser::ParseErrorOr> Parser::parse_css_value(Property if (auto parsed_value = parse_list_style_value(component_values)) return parsed_value.release_nonnull(); return ParseError::SyntaxError; + case PropertyID::MathDepth: + if (auto parsed_value = parse_math_depth_value(component_values)) + return parsed_value.release_nonnull(); + return ParseError::SyntaxError; case PropertyID::Overflow: if (auto parsed_value = parse_overflow_value(component_values)) return parsed_value.release_nonnull(); diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index d40f318d00..d886939f5a 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -238,6 +238,7 @@ private: RefPtr parse_font_value(Vector const&); RefPtr parse_font_family_value(TokenStream&); RefPtr parse_list_style_value(Vector const&); + RefPtr parse_math_depth_value(Vector const&); RefPtr parse_overflow_value(Vector const&); RefPtr parse_place_content_value(Vector const&); RefPtr parse_place_items_value(Vector const&); diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index 9ec266edd4..375d20e1a4 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -1479,6 +1479,17 @@ "unitless-length" ] }, + "math-depth": { + "inherited": true, + "initial": "0", + "__comment": "FIXME: `add()` is also valid but we can't represent that here yet.", + "valid-types": [ + "integer" + ], + "valid-identifiers": [ + "auto-add" + ] + }, "math-shift": { "inherited": true, "initial": "normal", diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index 66101ead36..4a607f2a42 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -2314,6 +2315,7 @@ void StyleComputer::transform_box_type_if_needed(StyleProperties& style, DOM::El NonnullRefPtr StyleComputer::create_document_style() const { auto style = StyleProperties::create(); + compute_math_depth(style, nullptr, {}); compute_font(style, nullptr, {}); compute_defaulted_values(style, nullptr, {}); absolutize_values(style, nullptr, {}); @@ -2346,16 +2348,19 @@ ErrorOr> StyleComputer::compute_style_impl(DOM::Element& if (mode == ComputeStyleMode::CreatePseudoElementStyleIfNeeded && !did_match_any_pseudo_element_rules) return nullptr; - // 2. Compute the font, since that may be needed for font-relative CSS units + // 2. Compute the math-depth property, since that might affect the font-size + compute_math_depth(style, &element, pseudo_element); + + // 3. Compute the font, since that may be needed for font-relative CSS units compute_font(style, &element, pseudo_element); - // 3. Absolutize values, turning font/viewport relative lengths into absolute lengths + // 4. Absolutize values, turning font/viewport relative lengths into absolute lengths absolutize_values(style, &element, pseudo_element); - // 4. Default the values, applying inheritance and 'initial' as needed + // 5. Default the values, applying inheritance and 'initial' as needed compute_defaulted_values(style, &element, pseudo_element); - // 5. Run automatic box type transformations + // 6. Run automatic box type transformations transform_box_type_if_needed(style, element, pseudo_element); return style; @@ -2605,4 +2610,57 @@ void StyleComputer::load_fonts_from_sheet(CSSStyleSheet const& sheet) } } +void StyleComputer::compute_math_depth(StyleProperties& style, DOM::Element const* element, Optional pseudo_element) const +{ + // https://w3c.github.io/mathml-core/#propdef-math-depth + + // First, ensure that the relevant CSS properties have been defaulted. + // FIXME: This should be more sophisticated. + compute_defaulted_property_value(style, element, CSS::PropertyID::MathDepth, pseudo_element); + compute_defaulted_property_value(style, element, CSS::PropertyID::MathStyle, pseudo_element); + + auto inherited_math_depth = [&]() { + if (!element || !element->parent_element()) + return InitialValues::math_depth(); + return element->parent_element()->computed_css_values()->math_depth(); + }; + + auto value = style.property(CSS::PropertyID::MathDepth); + if (!value->is_math_depth()) { + style.set_math_depth(inherited_math_depth()); + return; + } + auto& math_depth = value->as_math_depth(); + + auto resolve_integer = [&](StyleValue const& integer_value) { + if (integer_value.is_integer()) + return integer_value.as_integer().integer(); + if (integer_value.is_calculated()) + return integer_value.as_calculated().resolve_integer().value(); + VERIFY_NOT_REACHED(); + }; + + // The computed value of the math-depth value is determined as follows: + // - If the specified value of math-depth is auto-add and the inherited value of math-style is compact + // then the computed value of math-depth of the element is its inherited value plus one. + if (math_depth.is_auto_add() && style.property(CSS::PropertyID::MathStyle)->to_identifier() == CSS::ValueID::Compact) { + style.set_math_depth(inherited_math_depth() + 1); + return; + } + // - If the specified value of math-depth is of the form add() then the computed value of + // math-depth of the element is its inherited value plus the specified integer. + if (math_depth.is_add()) { + style.set_math_depth(inherited_math_depth() + resolve_integer(*math_depth.integer_value())); + return; + } + // - If the specified value of math-depth is of the form then the computed value of math-depth + // of the element is the specified integer. + if (math_depth.is_integer()) { + style.set_math_depth(resolve_integer(*math_depth.integer_value())); + return; + } + // - Otherwise, the computed value of math-depth of the element is the inherited one. + style.set_math_depth(inherited_math_depth()); +} + } diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.h b/Userland/Libraries/LibWeb/CSS/StyleComputer.h index 2e83f3f9e9..720cde8fb7 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.h +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.h @@ -127,6 +127,7 @@ private: static RefPtr find_matching_font_weight_descending(Vector const& candidates, int target_weight, float font_size_in_pt, bool inclusive); RefPtr font_matching_algorithm(FontFaceKey const& key, float font_size_in_pt) const; void compute_font(StyleProperties&, DOM::Element const*, Optional) const; + void compute_math_depth(StyleProperties&, DOM::Element const*, Optional) const; void compute_defaulted_values(StyleProperties&, DOM::Element const*, Optional) const; void absolutize_values(StyleProperties&, DOM::Element const*, Optional) const; void transform_box_type_if_needed(StyleProperties&, DOM::Element const&, Optional) const; diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 971cff83c9..7e0907f355 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -982,4 +983,11 @@ Color StyleProperties::stop_color() const return Color::Black; } +void StyleProperties::set_math_depth(int math_depth) +{ + m_math_depth = math_depth; + // Make our children inherit our computed value, not our specified value. + set_property(PropertyID::MathDepth, MathDepthStyleValue::create_integer(IntegerStyleValue::create(math_depth))); +} + } diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 2f7102634d..0662ee750f 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -143,6 +143,9 @@ public: Optional position() const; Optional z_index() const; + void set_math_depth(int math_depth); + int math_depth() const { return m_math_depth; } + static NonnullRefPtr font_fallback(bool monospace, bool bold); private: @@ -152,6 +155,7 @@ private: Optional overflow(CSS::PropertyID) const; Vector shadow(CSS::PropertyID, Layout::Node const&) const; + int m_math_depth { InitialValues::math_depth() }; mutable RefPtr m_font; }; diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index 01746f3d96..d39b3afc76 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 470ecabf85..f5a0b8c282 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -119,6 +119,7 @@ using StyleValueVector = Vector>; __ENUMERATE_STYLE_VALUE_TYPE(Length, length) \ __ENUMERATE_STYLE_VALUE_TYPE(LinearGradient, linear_gradient) \ __ENUMERATE_STYLE_VALUE_TYPE(ListStyle, list_style) \ + __ENUMERATE_STYLE_VALUE_TYPE(MathDepth, math_depth) \ __ENUMERATE_STYLE_VALUE_TYPE(Number, number) \ __ENUMERATE_STYLE_VALUE_TYPE(Overflow, overflow) \ __ENUMERATE_STYLE_VALUE_TYPE(Percentage, percentage) \ diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/MathDepthStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/MathDepthStyleValue.cpp new file mode 100644 index 0000000000..e47aeee0c5 --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/MathDepthStyleValue.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "MathDepthStyleValue.h" + +namespace Web::CSS { + +ValueComparingNonnullRefPtr MathDepthStyleValue::create_auto_add() +{ + return adopt_ref(*new (nothrow) MathDepthStyleValue(MathDepthType::AutoAdd)); +} + +ValueComparingNonnullRefPtr MathDepthStyleValue::create_add(ValueComparingNonnullRefPtr integer_value) +{ + return adopt_ref(*new (nothrow) MathDepthStyleValue(MathDepthType::Add, move(integer_value))); +} + +ValueComparingNonnullRefPtr MathDepthStyleValue::create_integer(ValueComparingNonnullRefPtr integer_value) +{ + return adopt_ref(*new (nothrow) MathDepthStyleValue(MathDepthType::Integer, move(integer_value))); +} + +MathDepthStyleValue::MathDepthStyleValue(MathDepthType type, ValueComparingRefPtr integer_value) + : StyleValueWithDefaultOperators(Type::MathDepth) + , m_type(type) + , m_integer_value(move(integer_value)) +{ +} + +bool MathDepthStyleValue::properties_equal(MathDepthStyleValue const& other) const +{ + return m_type == other.m_type + && m_integer_value == other.m_integer_value; +} + +String MathDepthStyleValue::to_string() const +{ + switch (m_type) { + case MathDepthType::AutoAdd: + return "auto-add"_string; + case MathDepthType::Add: + return MUST(String::formatted("add({})", m_integer_value->to_string())); + case MathDepthType::Integer: + return m_integer_value->to_string(); + } + VERIFY_NOT_REACHED(); +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/MathDepthStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/MathDepthStyleValue.h new file mode 100644 index 0000000000..9d5380d2d4 --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/MathDepthStyleValue.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::CSS { + +class MathDepthStyleValue : public StyleValueWithDefaultOperators { +public: + static ValueComparingNonnullRefPtr create_auto_add(); + static ValueComparingNonnullRefPtr create_add(ValueComparingNonnullRefPtr integer_value); + static ValueComparingNonnullRefPtr create_integer(ValueComparingNonnullRefPtr integer_value); + virtual ~MathDepthStyleValue() override = default; + + bool is_auto_add() const { return m_type == MathDepthType::AutoAdd; } + bool is_add() const { return m_type == MathDepthType::Add; } + bool is_integer() const { return m_type == MathDepthType::Integer; } + auto integer_value() const + { + VERIFY(!m_integer_value.is_null()); + return m_integer_value; + } + virtual String to_string() const override; + + bool properties_equal(MathDepthStyleValue const& other) const; + +private: + enum class MathDepthType { + AutoAdd, + Add, + Integer, + }; + + MathDepthStyleValue(MathDepthType type, ValueComparingRefPtr integer_value = nullptr); + + MathDepthType m_type; + ValueComparingRefPtr m_integer_value; +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 74b34e66d3..dd75acf5a9 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -137,6 +137,7 @@ class LengthPercentage; class LengthStyleValue; class LinearGradientStyleValue; class ListStyleStyleValue; +class MathDepthStyleValue; class MediaFeatureValue; class MediaList; class MediaQuery; diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index c7d231508a..beb08f91e5 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -797,6 +798,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) if (auto math_style = value_id_to_math_style(math_style_value->to_identifier()); math_style.has_value()) computed_values.set_math_style(math_style.value()); + computed_values.set_math_depth(computed_style.math_depth()); + // Update any anonymous children that inherit from this node. // FIXME: This is pretty hackish. It would be nicer if they shared the inherited style // data structure somehow, so this wasn't necessary.