diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 0e62146fe18..5f9d1cac8b5 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -116,6 +116,7 @@ set(SOURCES CSS/CSSLayerBlockRule.cpp CSS/CSSLayerStatementRule.cpp CSS/CSSMarginRule.cpp + CSS/CSSMathNegate.cpp CSS/CSSMathProduct.cpp CSS/CSSMathSum.cpp CSS/CSSMathValue.cpp diff --git a/Libraries/LibWeb/CSS/CSSMathNegate.cpp b/Libraries/LibWeb/CSS/CSSMathNegate.cpp new file mode 100644 index 00000000000..fd214b510b6 --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSMathNegate.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "CSSMathNegate.h" +#include +#include +#include + +namespace Web::CSS { + +GC_DEFINE_ALLOCATOR(CSSMathNegate); + +GC::Ref CSSMathNegate::create(JS::Realm& realm, NumericType type, GC::Ref values) +{ + return realm.create(realm, move(type), move(values)); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathnegate-cssmathnegate +WebIDL::ExceptionOr> CSSMathNegate::construct_impl(JS::Realm& realm, CSSNumberish value) +{ + // The CSSMathNegate(arg) constructor must, when called, perform the following steps: + // 1. Replace arg with the result of rectifying a numberish value for arg. + auto converted_value = rectify_a_numberish_value(realm, value); + + // 2. Return a new CSSMathNegate whose value internal slot is set to arg. + return CSSMathNegate::create(realm, converted_value->type(), converted_value); +} + +CSSMathNegate::CSSMathNegate(JS::Realm& realm, NumericType type, GC::Ref values) + : CSSMathValue(realm, Bindings::CSSMathOperator::Negate, move(type)) + , m_value(move(values)) +{ +} + +CSSMathNegate::~CSSMathNegate() = default; + +void CSSMathNegate::initialize(JS::Realm& realm) +{ + WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSMathNegate); + Base::initialize(realm); +} + +void CSSMathNegate::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_value); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#serialize-a-cssmathvalue +String CSSMathNegate::serialize_math_value(Nested nested, Parens parens) const +{ + // NB: Only steps 1 and 4 apply here. + // 1. Let s initially be the empty string. + StringBuilder s; + + // 4. Otherwise, if this is a CSSMathNegate: + { + // 1. If paren-less is true, continue to the next step; otherwise, if nested is true, append "(" to s; + // otherwise, append "calc(" to s. + if (parens == Parens::With) { + if (nested == Nested::Yes) { + s.append("("sv); + } else { + s.append("calc("sv); + } + } + + // 2. Append "-" to s. + s.append("-"sv); + + // 3. Serialize this’s value internal slot with nested set to true, and append the result to s. + s.append(m_value->to_string({ .nested = true })); + + // 4. If paren-less is false, append ")" to s, + if (parens == Parens::With) + s.append(")"sv); + + // 5. Return s. + return s.to_string_without_validation(); + } +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathnegate-value +GC::Ref CSSMathNegate::value() const +{ + return m_value; +} + +} diff --git a/Libraries/LibWeb/CSS/CSSMathNegate.h b/Libraries/LibWeb/CSS/CSSMathNegate.h new file mode 100644 index 00000000000..4470f74a5df --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSMathNegate.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::CSS { + +// https://drafts.css-houdini.org/css-typed-om-1/#cssmathnegate +class CSSMathNegate : public CSSMathValue { + WEB_PLATFORM_OBJECT(CSSMathNegate, CSSMathValue); + GC_DECLARE_ALLOCATOR(CSSMathNegate); + +public: + [[nodiscard]] static GC::Ref create(JS::Realm&, NumericType, GC::Ref); + static WebIDL::ExceptionOr> construct_impl(JS::Realm&, CSSNumberish); + + virtual ~CSSMathNegate() override; + + virtual void initialize(JS::Realm&) override; + virtual void visit_edges(Visitor&) override; + + GC::Ref value() const; + + virtual String serialize_math_value(Nested, Parens) const override; + +private: + CSSMathNegate(JS::Realm&, NumericType, GC::Ref); + GC::Ref m_value; +}; + +} diff --git a/Libraries/LibWeb/CSS/CSSMathNegate.idl b/Libraries/LibWeb/CSS/CSSMathNegate.idl new file mode 100644 index 00000000000..278df117a38 --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSMathNegate.idl @@ -0,0 +1,9 @@ +#import +#import + +// https://drafts.css-houdini.org/css-typed-om-1/#cssmathnegate +[Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)] +interface CSSMathNegate : CSSMathValue { + constructor(CSSNumberish arg); + readonly attribute CSSNumericValue value; +}; diff --git a/Libraries/LibWeb/CSS/CSSMathSum.cpp b/Libraries/LibWeb/CSS/CSSMathSum.cpp index acfcfdf8d21..bd60e175ade 100644 --- a/Libraries/LibWeb/CSS/CSSMathSum.cpp +++ b/Libraries/LibWeb/CSS/CSSMathSum.cpp @@ -7,6 +7,7 @@ #include "CSSMathSum.h" #include #include +#include #include #include #include @@ -109,10 +110,9 @@ String CSSMathSum::serialize_math_value(Nested nested, Parens parens) const // 1. If arg is a CSSMathNegate, append " - " to s, then serialize arg’s value internal slot with nested // set to true, and append the result to s. - // FIXME: Detect CSSMathNegate once that's implemented. - if (false) { + if (auto* negate = as_if(*arg)) { s.append(" - "sv); - s.append(arg->to_string({ .nested = true })); + s.append(negate->value()->to_string({ .nested = true })); } // 2. Otherwise, append " + " to s, then serialize arg with nested set to true, and append the result to s. diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 19ce1eae141..69ff65e3c1b 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -242,6 +242,7 @@ class CSSKeywordValue; class CSSLayerBlockRule; class CSSLayerStatementRule; class CSSMarginRule; +class CSSMathNegate; class CSSMathProduct; class CSSMathSum; class CSSMathValue; diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake index 33a3fadbad9..0ba14faa6c0 100644 --- a/Libraries/LibWeb/idl_files.cmake +++ b/Libraries/LibWeb/idl_files.cmake @@ -36,6 +36,7 @@ libweb_js_bindings(CSS/CSSKeywordValue) libweb_js_bindings(CSS/CSSLayerBlockRule) libweb_js_bindings(CSS/CSSLayerStatementRule) libweb_js_bindings(CSS/CSSMarginRule) +libweb_js_bindings(CSS/CSSMathNegate) libweb_js_bindings(CSS/CSSMathProduct) libweb_js_bindings(CSS/CSSMathSum) libweb_js_bindings(CSS/CSSMathValue) diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index 0e89b57248c..95fb9230bf1 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -49,6 +49,7 @@ CSSKeywordValue CSSLayerBlockRule CSSLayerStatementRule CSSMarginRule +CSSMathNegate CSSMathProduct CSSMathSum CSSMathValue