) [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.