LibWeb: Generate the "Numeric Factory" OM methods on the CSS namespace

Generating boilerplate is nice! This also has the bonus that we're more
correct: I included all the units listed in the spec before,
(see https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory )
but we're supposed to exactly include ones for the units we support:

> If an implementation supports additional CSS units that do not have a
  corresponding method in the above list, but that do correspond to one
  of the existing CSSNumericType values, it must additionally support
  such a method, named after the unit in its defined canonical casing,
  using the generic behavior defined above.

> If an implementation does not support a given unit, it must not
  implement its corresponding method from the list above.

Now, our factory functions will exactly match the units we support.

The changed test result is partly the order being different, and partly
that the container-query units are no longer included as we don't
actually support them.
This commit is contained in:
Sam Atkins 2025-09-02 15:50:05 +01:00
commit 82f5be871a
Notes: github-actions[bot] 2025-09-11 16:07:48 +00:00
8 changed files with 394 additions and 699 deletions

View file

@ -1072,6 +1072,8 @@ set(GENERATED_SOURCES
CSS/DescriptorID.cpp CSS/DescriptorID.cpp
CSS/Enums.cpp CSS/Enums.cpp
CSS/EnvironmentVariable.cpp CSS/EnvironmentVariable.cpp
CSS/GeneratedCSSNumericFactoryMethods.cpp
CSS/GeneratedCSSNumericFactoryMethods.idl
CSS/GeneratedCSSStyleProperties.cpp CSS/GeneratedCSSStyleProperties.cpp
CSS/GeneratedCSSStyleProperties.idl CSS/GeneratedCSSStyleProperties.idl
CSS/Keyword.cpp CSS/Keyword.cpp

View file

@ -144,333 +144,4 @@ WebIDL::ExceptionOr<void> register_property(JS::VM& vm, PropertyDefinition defin
return {}; return {};
} }
// https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory
inline GC::Ref<CSSUnitValue> numeric_factory(JS::VM& vm, WebIDL::Double value, FlyString unit)
{
// All of the above methods must, when called with a double value, return a new CSSUnitValue whose value internal
// slot is set to value and whose unit internal slot is set to the name of the method as defined here.
return CSSUnitValue::create(*vm.current_realm(), value, move(unit));
}
GC::Ref<CSSUnitValue> number(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "number"_fly_string);
}
GC::Ref<CSSUnitValue> percent(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "percent"_fly_string);
}
// <length>
GC::Ref<CSSUnitValue> cap(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "cap"_fly_string);
}
GC::Ref<CSSUnitValue> ch(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "ch"_fly_string);
}
GC::Ref<CSSUnitValue> em(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "em"_fly_string);
}
GC::Ref<CSSUnitValue> ex(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "ex"_fly_string);
}
GC::Ref<CSSUnitValue> ic(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "ic"_fly_string);
}
GC::Ref<CSSUnitValue> lh(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "lh"_fly_string);
}
GC::Ref<CSSUnitValue> rcap(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "rcap"_fly_string);
}
GC::Ref<CSSUnitValue> rch(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "rch"_fly_string);
}
GC::Ref<CSSUnitValue> rem(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "rem"_fly_string);
}
GC::Ref<CSSUnitValue> rex(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "rex"_fly_string);
}
GC::Ref<CSSUnitValue> ric(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "ric"_fly_string);
}
GC::Ref<CSSUnitValue> rlh(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "rlh"_fly_string);
}
GC::Ref<CSSUnitValue> vw(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "vw"_fly_string);
}
GC::Ref<CSSUnitValue> vh(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "vh"_fly_string);
}
GC::Ref<CSSUnitValue> vi(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "vi"_fly_string);
}
GC::Ref<CSSUnitValue> vb(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "vb"_fly_string);
}
GC::Ref<CSSUnitValue> vmin(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "vmin"_fly_string);
}
GC::Ref<CSSUnitValue> vmax(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "vmax"_fly_string);
}
GC::Ref<CSSUnitValue> svw(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "svw"_fly_string);
}
GC::Ref<CSSUnitValue> svh(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "svh"_fly_string);
}
GC::Ref<CSSUnitValue> svi(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "svi"_fly_string);
}
GC::Ref<CSSUnitValue> svb(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "svb"_fly_string);
}
GC::Ref<CSSUnitValue> svmin(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "svmin"_fly_string);
}
GC::Ref<CSSUnitValue> svmax(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "svmax"_fly_string);
}
GC::Ref<CSSUnitValue> lvw(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "lvw"_fly_string);
}
GC::Ref<CSSUnitValue> lvh(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "lvh"_fly_string);
}
GC::Ref<CSSUnitValue> lvi(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "lvi"_fly_string);
}
GC::Ref<CSSUnitValue> lvb(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "lvb"_fly_string);
}
GC::Ref<CSSUnitValue> lvmin(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "lvmin"_fly_string);
}
GC::Ref<CSSUnitValue> lvmax(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "lvmax"_fly_string);
}
GC::Ref<CSSUnitValue> dvw(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "dvw"_fly_string);
}
GC::Ref<CSSUnitValue> dvh(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "dvh"_fly_string);
}
GC::Ref<CSSUnitValue> dvi(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "dvi"_fly_string);
}
GC::Ref<CSSUnitValue> dvb(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "dvb"_fly_string);
}
GC::Ref<CSSUnitValue> dvmin(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "dvmin"_fly_string);
}
GC::Ref<CSSUnitValue> dvmax(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "dvmax"_fly_string);
}
GC::Ref<CSSUnitValue> cqw(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "cqw"_fly_string);
}
GC::Ref<CSSUnitValue> cqh(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "cqh"_fly_string);
}
GC::Ref<CSSUnitValue> cqi(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "cqi"_fly_string);
}
GC::Ref<CSSUnitValue> cqb(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "cqb"_fly_string);
}
GC::Ref<CSSUnitValue> cqmin(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "cqmin"_fly_string);
}
GC::Ref<CSSUnitValue> cqmax(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "cqmax"_fly_string);
}
GC::Ref<CSSUnitValue> cm(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "cm"_fly_string);
}
GC::Ref<CSSUnitValue> mm(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "mm"_fly_string);
}
GC::Ref<CSSUnitValue> q(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "q"_fly_string);
}
GC::Ref<CSSUnitValue> in(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "in"_fly_string);
}
GC::Ref<CSSUnitValue> pt(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "pt"_fly_string);
}
GC::Ref<CSSUnitValue> pc(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "pc"_fly_string);
}
GC::Ref<CSSUnitValue> px(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "px"_fly_string);
}
// <angle>
GC::Ref<CSSUnitValue> deg(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "deg"_fly_string);
}
GC::Ref<CSSUnitValue> grad(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "grad"_fly_string);
}
GC::Ref<CSSUnitValue> rad(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "rad"_fly_string);
}
GC::Ref<CSSUnitValue> turn(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "turn"_fly_string);
}
// <time>
GC::Ref<CSSUnitValue> s(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "s"_fly_string);
}
GC::Ref<CSSUnitValue> ms(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "ms"_fly_string);
}
// <frequency>
GC::Ref<CSSUnitValue> hz(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "hz"_fly_string);
}
GC::Ref<CSSUnitValue> k_hz(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "khz"_fly_string);
}
// <resolution>
GC::Ref<CSSUnitValue> dpi(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "dpi"_fly_string);
}
GC::Ref<CSSUnitValue> dpcm(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "dpcm"_fly_string);
}
GC::Ref<CSSUnitValue> dppx(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "dppx"_fly_string);
}
// <flex>
GC::Ref<CSSUnitValue> fr(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "fr"_fly_string);
}
} }

View file

@ -10,6 +10,7 @@
#include <AK/String.h> #include <AK/String.h>
#include <AK/StringView.h> #include <AK/StringView.h>
#include <LibJS/Forward.h> #include <LibJS/Forward.h>
#include <LibWeb/CSS/GeneratedCSSNumericFactoryMethods.h>
#include <LibWeb/Export.h> #include <LibWeb/Export.h>
#include <LibWeb/WebIDL/ExceptionOr.h> #include <LibWeb/WebIDL/ExceptionOr.h>
#include <LibWeb/WebIDL/Types.h> #include <LibWeb/WebIDL/Types.h>
@ -31,80 +32,7 @@ WEB_API WebIDL::ExceptionOr<bool> supports(JS::VM&, StringView condition_text);
WEB_API WebIDL::ExceptionOr<void> register_property(JS::VM&, PropertyDefinition definition); WEB_API WebIDL::ExceptionOr<void> register_property(JS::VM&, PropertyDefinition definition);
GC::Ref<CSSUnitValue> number(JS::VM&, WebIDL::Double value); // NB: Numeric factory functions (https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory) are generated,
GC::Ref<CSSUnitValue> percent(JS::VM&, WebIDL::Double value); // see GenerateCSSNumericFactoryMethods.cpp
// <length>
GC::Ref<CSSUnitValue> cap(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> ch(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> em(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> ex(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> ic(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> lh(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> rcap(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> rch(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> rem(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> rex(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> ric(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> rlh(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> vw(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> vh(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> vi(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> vb(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> vmin(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> vmax(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> svw(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> svh(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> svi(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> svb(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> svmin(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> svmax(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> lvw(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> lvh(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> lvi(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> lvb(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> lvmin(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> lvmax(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> dvw(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> dvh(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> dvi(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> dvb(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> dvmin(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> dvmax(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> cqw(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> cqh(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> cqi(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> cqb(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> cqmin(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> cqmax(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> cm(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> mm(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> q(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> in(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> pt(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> pc(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> px(JS::VM&, WebIDL::Double value);
// <angle>
GC::Ref<CSSUnitValue> deg(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> grad(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> rad(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> turn(JS::VM&, WebIDL::Double value);
// <time>
GC::Ref<CSSUnitValue> s(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> ms(JS::VM&, WebIDL::Double value);
// <frequency>
GC::Ref<CSSUnitValue> hz(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> k_hz(JS::VM&, WebIDL::Double value);
// <resolution>
GC::Ref<CSSUnitValue> dpi(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> dpcm(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> dppx(JS::VM&, WebIDL::Double value);
// <flex>
GC::Ref<CSSUnitValue> fr(JS::VM&, WebIDL::Double value);
} }

View file

@ -1,4 +1,5 @@
#import <CSS/CSSUnitValue.idl> #import <CSS/CSSUnitValue.idl>
#import <CSS/GeneratedCSSNumericFactoryMethods.idl>
dictionary PropertyDefinition { dictionary PropertyDefinition {
required CSSOMString name; required CSSOMString name;
@ -19,79 +20,5 @@ namespace CSS {
undefined registerProperty(PropertyDefinition definition); undefined registerProperty(PropertyDefinition definition);
// https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory // https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory
CSSUnitValue number(double value); // NB: Generated by GenerateCSSNumericFactoryMethods.cpp
CSSUnitValue percent(double value);
// <length>
CSSUnitValue cap(double value);
CSSUnitValue ch(double value);
CSSUnitValue em(double value);
CSSUnitValue ex(double value);
CSSUnitValue ic(double value);
CSSUnitValue lh(double value);
CSSUnitValue rcap(double value);
CSSUnitValue rch(double value);
CSSUnitValue rem(double value);
CSSUnitValue rex(double value);
CSSUnitValue ric(double value);
CSSUnitValue rlh(double value);
CSSUnitValue vw(double value);
CSSUnitValue vh(double value);
CSSUnitValue vi(double value);
CSSUnitValue vb(double value);
CSSUnitValue vmin(double value);
CSSUnitValue vmax(double value);
CSSUnitValue svw(double value);
CSSUnitValue svh(double value);
CSSUnitValue svi(double value);
CSSUnitValue svb(double value);
CSSUnitValue svmin(double value);
CSSUnitValue svmax(double value);
CSSUnitValue lvw(double value);
CSSUnitValue lvh(double value);
CSSUnitValue lvi(double value);
CSSUnitValue lvb(double value);
CSSUnitValue lvmin(double value);
CSSUnitValue lvmax(double value);
CSSUnitValue dvw(double value);
CSSUnitValue dvh(double value);
CSSUnitValue dvi(double value);
CSSUnitValue dvb(double value);
CSSUnitValue dvmin(double value);
CSSUnitValue dvmax(double value);
CSSUnitValue cqw(double value);
CSSUnitValue cqh(double value);
CSSUnitValue cqi(double value);
CSSUnitValue cqb(double value);
CSSUnitValue cqmin(double value);
CSSUnitValue cqmax(double value);
CSSUnitValue cm(double value);
CSSUnitValue mm(double value);
CSSUnitValue Q(double value);
CSSUnitValue in(double value);
CSSUnitValue pt(double value);
CSSUnitValue pc(double value);
CSSUnitValue px(double value);
// <angle>
CSSUnitValue deg(double value);
CSSUnitValue grad(double value);
CSSUnitValue rad(double value);
CSSUnitValue turn(double value);
// <time>
CSSUnitValue s(double value);
CSSUnitValue ms(double value);
// <frequency>
CSSUnitValue Hz(double value);
CSSUnitValue kHz(double value);
// <resolution>
CSSUnitValue dpi(double value);
CSSUnitValue dpcm(double value);
CSSUnitValue dppx(double value);
// <flex>
CSSUnitValue fr(double value);
}; };

View file

@ -104,6 +104,17 @@ function (generate_css_implementation)
arguments -j "${LIBWEB_INPUT_FOLDER}/CSS/Keywords.json" arguments -j "${LIBWEB_INPUT_FOLDER}/CSS/Keywords.json"
) )
invoke_idl_generator(
"GeneratedCSSNumericFactoryMethods.cpp"
"GeneratedCSSNumericFactoryMethods.idl"
Lagom::GenerateCSSNumericFactoryMethods
"${LIBWEB_INPUT_FOLDER}/CSS/Units.json"
"CSS/GeneratedCSSNumericFactoryMethods.h"
"CSS/GeneratedCSSNumericFactoryMethods.cpp"
"CSS/GeneratedCSSNumericFactoryMethods.idl"
arguments -j "${LIBWEB_INPUT_FOLDER}/CSS/Units.json"
)
invoke_idl_generator( invoke_idl_generator(
"GeneratedCSSStyleProperties.cpp" "GeneratedCSSStyleProperties.cpp"
"GeneratedCSSStyleProperties.idl" "GeneratedCSSStyleProperties.idl"
@ -151,6 +162,7 @@ function (generate_css_implementation)
"CSS/Enums.h" "CSS/Enums.h"
"CSS/EnvironmentVariable.h" "CSS/EnvironmentVariable.h"
"CSS/GeneratedCSSStyleProperties.h" "CSS/GeneratedCSSStyleProperties.h"
"CSS/GeneratedCSSNumericFactoryMethods.h"
"CSS/Keyword.h" "CSS/Keyword.h"
"CSS/MathFunctions.h" "CSS/MathFunctions.h"
"CSS/MediaFeatureID.h" "CSS/MediaFeatureID.h"
@ -168,6 +180,7 @@ function (generate_css_implementation)
set(CSS_GENERATED_IDL set(CSS_GENERATED_IDL
"GeneratedCSSStyleProperties.idl" "GeneratedCSSStyleProperties.idl"
"GeneratedCSSNumericFactoryMethods.idl"
) )
list(APPEND LIBWEB_ALL_GENERATED_IDL ${CSS_GENERATED_IDL}) list(APPEND LIBWEB_ALL_GENERATED_IDL ${CSS_GENERATED_IDL})
set(LIBWEB_ALL_GENERATED_IDL ${LIBWEB_ALL_GENERATED_IDL} PARENT_SCOPE) set(LIBWEB_ALL_GENERATED_IDL ${LIBWEB_ALL_GENERATED_IDL} PARENT_SCOPE)

View file

@ -6,6 +6,7 @@ lagom_tool(GenerateCSSEnvironmentVariable SOURCES GenerateCSSEnvironmentVariab
lagom_tool(GenerateCSSKeyword SOURCES GenerateCSSKeyword.cpp LIBS LibMain) lagom_tool(GenerateCSSKeyword SOURCES GenerateCSSKeyword.cpp LIBS LibMain)
lagom_tool(GenerateCSSMathFunctions SOURCES GenerateCSSMathFunctions.cpp LIBS LibMain) lagom_tool(GenerateCSSMathFunctions SOURCES GenerateCSSMathFunctions.cpp LIBS LibMain)
lagom_tool(GenerateCSSMediaFeatureID SOURCES GenerateCSSMediaFeatureID.cpp LIBS LibMain) lagom_tool(GenerateCSSMediaFeatureID SOURCES GenerateCSSMediaFeatureID.cpp LIBS LibMain)
lagom_tool(GenerateCSSNumericFactoryMethods SOURCES GenerateCSSNumericFactoryMethods.cpp LIBS LibMain)
lagom_tool(GenerateCSSPropertyID SOURCES GenerateCSSPropertyID.cpp LIBS LibMain) lagom_tool(GenerateCSSPropertyID SOURCES GenerateCSSPropertyID.cpp LIBS LibMain)
lagom_tool(GenerateCSSPseudoClass SOURCES GenerateCSSPseudoClass.cpp LIBS LibMain) lagom_tool(GenerateCSSPseudoClass SOURCES GenerateCSSPseudoClass.cpp LIBS LibMain)
lagom_tool(GenerateCSSPseudoElement SOURCES GenerateCSSPseudoElement.cpp LIBS LibMain) lagom_tool(GenerateCSSPseudoElement SOURCES GenerateCSSPseudoElement.cpp LIBS LibMain)

View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "GeneratorUtil.h"
#include <AK/SourceGenerator.h>
#include <AK/StringBuilder.h>
#include <LibCore/ArgsParser.h>
#include <LibMain/Main.h>
ErrorOr<void> generate_header_file(JsonObject& units_data, Core::File& file);
ErrorOr<void> generate_implementation_file(JsonObject& units_data, Core::File& file);
ErrorOr<void> generate_idl_file(JsonObject& units_data, Core::File& file);
ErrorOr<int> ladybird_main(Main::Arguments arguments)
{
StringView generated_header_path;
StringView generated_implementation_path;
StringView generated_idl_path;
StringView units_json_path;
Core::ArgsParser args_parser;
args_parser.add_option(generated_header_path, "Path to the CSSNumericFactoryMethods header file to generate", "generated-header-path", 'h', "generated-header-path");
args_parser.add_option(generated_implementation_path, "Path to the CSSNumericFactoryMethods implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
args_parser.add_option(generated_idl_path, "Path to the CSSNumericFactoryMethods IDL file to generate", "generated-idl-path", 'i', "generated-idl-path");
args_parser.add_option(units_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path");
args_parser.parse(arguments);
auto json = TRY(read_entire_file_as_json(units_json_path));
VERIFY(json.is_object());
auto units_data = json.as_object();
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
auto generated_idl_file = TRY(Core::File::open(generated_idl_path, Core::File::OpenMode::Write));
TRY(generate_header_file(units_data, *generated_header_file));
TRY(generate_implementation_file(units_data, *generated_implementation_file));
TRY(generate_idl_file(units_data, *generated_idl_file));
return 0;
}
ErrorOr<void> generate_header_file(JsonObject& units_data, Core::File& file)
{
StringBuilder builder;
SourceGenerator generator { builder };
generator.append(R"~~~(
#pragma once
#include <LibGC/Ptr.h>
#include <LibJS/Forward.h>
#include <LibWeb/Forward.h>
#include <LibWeb/WebIDL/Types.h>
// https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory
namespace Web::CSS {
GC::Ref<CSSUnitValue> number(JS::VM&, WebIDL::Double value);
GC::Ref<CSSUnitValue> percent(JS::VM&, WebIDL::Double value);
)~~~");
units_data.for_each_member([&](auto& dimension_name, JsonValue const& dimension) {
auto dimension_generator = generator.fork();
dimension_generator.set("dimension:acceptable_cpp", make_name_acceptable_cpp(snake_casify(dimension_name, TrimLeadingUnderscores::Yes)));
dimension_generator.appendln("\n// <@dimension:acceptable_cpp@>");
dimension.as_object().for_each_member([&](auto& unit_name, JsonValue const&) {
auto unit_generator = dimension_generator.fork();
unit_generator.set("unit:acceptable_cpp", make_name_acceptable_cpp(unit_name.to_ascii_lowercase()));
unit_generator.appendln("GC::Ref<CSSUnitValue> @unit:acceptable_cpp@(JS::VM&, WebIDL::Double value);");
});
});
generator.append(R"~~~(
}
)~~~");
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
return {};
}
ErrorOr<void> generate_implementation_file(JsonObject& units_data, Core::File& file)
{
StringBuilder builder;
SourceGenerator generator { builder };
generator.append(R"~~~(
#include <AK/FlyString.h>
#include <LibJS/Runtime/VM.h>
#include <LibWeb/CSS/CSSUnitValue.h>
#include <LibWeb/CSS/GeneratedCSSNumericFactoryMethods.h>
namespace Web::CSS {
// https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory
inline GC::Ref<CSSUnitValue> numeric_factory(JS::VM& vm, WebIDL::Double value, FlyString unit)
{
// All of the above methods must, when called with a double value, return a new CSSUnitValue whose value internal
// slot is set to value and whose unit internal slot is set to the name of the method as defined here.
return CSSUnitValue::create(*vm.current_realm(), value, move(unit));
}
GC::Ref<CSSUnitValue> number(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "number"_fly_string);
}
GC::Ref<CSSUnitValue> percent(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "percent"_fly_string);
}
)~~~");
units_data.for_each_member([&](auto& dimension_name, JsonValue const& dimension) {
auto dimension_generator = generator.fork();
dimension_generator.set("dimension:acceptable_cpp", make_name_acceptable_cpp(snake_casify(dimension_name, TrimLeadingUnderscores::Yes)));
dimension_generator.appendln("\n// <@dimension:acceptable_cpp@>");
dimension.as_object().for_each_member([&](auto& unit_name, JsonValue const&) {
auto unit_generator = dimension_generator.fork();
unit_generator.set("unit:name", unit_name);
unit_generator.set("unit:acceptable_cpp", make_name_acceptable_cpp(unit_name.to_ascii_lowercase()));
unit_generator.append(R"~~~(
GC::Ref<CSSUnitValue> @unit:acceptable_cpp@(JS::VM& vm, WebIDL::Double value)
{
return numeric_factory(vm, value, "@unit:name@"_fly_string);
}
)~~~");
});
});
generator.append(R"~~~(
}
)~~~");
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
return {};
}
ErrorOr<void> generate_idl_file(JsonObject& units_data, Core::File& file)
{
StringBuilder builder;
SourceGenerator generator { builder };
generator.append(R"~~~(
partial namespace CSS {
CSSUnitValue number(double value);
CSSUnitValue percent(double value);
)~~~");
units_data.for_each_member([&](auto& dimension_name, JsonValue const& dimension) {
auto dimension_generator = generator.fork();
dimension_generator.set("dimension:acceptable_cpp", make_name_acceptable_cpp(snake_casify(dimension_name, TrimLeadingUnderscores::Yes)));
dimension_generator.append(R"~~~(
// <@dimension:acceptable_cpp@>
)~~~");
dimension.as_object().for_each_member([&](auto& unit_name, JsonValue const&) {
auto unit_generator = dimension_generator.fork();
unit_generator.set("unit:name", unit_name);
unit_generator.set("unit:acceptable_cpp", make_name_acceptable_cpp(unit_name.to_ascii_lowercase()));
unit_generator.appendln(" [ImplementedAs=@unit:acceptable_cpp@] CSSUnitValue @unit:name@(double value);");
});
});
generator.append(R"~~~(
};
)~~~");
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
return {};
}

View file

@ -24,6 +24,41 @@ percent configurable: true
percent enumerable: true percent enumerable: true
percent value before: function percent() { [native code] } percent value before: function percent() { [native code] }
percent value after: replaced percent value after: replaced
deg writable: true
deg configurable: true
deg enumerable: true
deg value before: function deg() { [native code] }
deg value after: replaced
grad writable: true
grad configurable: true
grad enumerable: true
grad value before: function grad() { [native code] }
grad value after: replaced
rad writable: true
rad configurable: true
rad enumerable: true
rad value before: function rad() { [native code] }
rad value after: replaced
turn writable: true
turn configurable: true
turn enumerable: true
turn value before: function turn() { [native code] }
turn value after: replaced
fr writable: true
fr configurable: true
fr enumerable: true
fr value before: function fr() { [native code] }
fr value after: replaced
Hz writable: true
Hz configurable: true
Hz enumerable: true
Hz value before: function Hz() { [native code] }
Hz value after: replaced
kHz writable: true
kHz configurable: true
kHz enumerable: true
kHz value before: function kHz() { [native code] }
kHz value after: replaced
cap writable: true cap writable: true
cap configurable: true cap configurable: true
cap enumerable: true cap enumerable: true
@ -34,6 +69,41 @@ ch configurable: true
ch enumerable: true ch enumerable: true
ch value before: function ch() { [native code] } ch value before: function ch() { [native code] }
ch value after: replaced ch value after: replaced
cm writable: true
cm configurable: true
cm enumerable: true
cm value before: function cm() { [native code] }
cm value after: replaced
dvb writable: true
dvb configurable: true
dvb enumerable: true
dvb value before: function dvb() { [native code] }
dvb value after: replaced
dvh writable: true
dvh configurable: true
dvh enumerable: true
dvh value before: function dvh() { [native code] }
dvh value after: replaced
dvi writable: true
dvi configurable: true
dvi enumerable: true
dvi value before: function dvi() { [native code] }
dvi value after: replaced
dvmax writable: true
dvmax configurable: true
dvmax enumerable: true
dvmax value before: function dvmax() { [native code] }
dvmax value after: replaced
dvmin writable: true
dvmin configurable: true
dvmin enumerable: true
dvmin value before: function dvmin() { [native code] }
dvmin value after: replaced
dvw writable: true
dvw configurable: true
dvw enumerable: true
dvw value before: function dvw() { [native code] }
dvw value after: replaced
em writable: true em writable: true
em configurable: true em configurable: true
em enumerable: true em enumerable: true
@ -49,11 +119,71 @@ ic configurable: true
ic enumerable: true ic enumerable: true
ic value before: function ic() { [native code] } ic value before: function ic() { [native code] }
ic value after: replaced ic value after: replaced
in writable: true
in configurable: true
in enumerable: true
in value before: function in() { [native code] }
in value after: replaced
lh writable: true lh writable: true
lh configurable: true lh configurable: true
lh enumerable: true lh enumerable: true
lh value before: function lh() { [native code] } lh value before: function lh() { [native code] }
lh value after: replaced lh value after: replaced
lvb writable: true
lvb configurable: true
lvb enumerable: true
lvb value before: function lvb() { [native code] }
lvb value after: replaced
lvh writable: true
lvh configurable: true
lvh enumerable: true
lvh value before: function lvh() { [native code] }
lvh value after: replaced
lvi writable: true
lvi configurable: true
lvi enumerable: true
lvi value before: function lvi() { [native code] }
lvi value after: replaced
lvmax writable: true
lvmax configurable: true
lvmax enumerable: true
lvmax value before: function lvmax() { [native code] }
lvmax value after: replaced
lvmin writable: true
lvmin configurable: true
lvmin enumerable: true
lvmin value before: function lvmin() { [native code] }
lvmin value after: replaced
lvw writable: true
lvw configurable: true
lvw enumerable: true
lvw value before: function lvw() { [native code] }
lvw value after: replaced
mm writable: true
mm configurable: true
mm enumerable: true
mm value before: function mm() { [native code] }
mm value after: replaced
pc writable: true
pc configurable: true
pc enumerable: true
pc value before: function pc() { [native code] }
pc value after: replaced
pt writable: true
pt configurable: true
pt enumerable: true
pt value before: function pt() { [native code] }
pt value after: replaced
px writable: true
px configurable: true
px enumerable: true
px value before: function px() { [native code] }
px value after: replaced
Q writable: true
Q configurable: true
Q enumerable: true
Q value before: function Q() { [native code] }
Q value after: replaced
rcap writable: true rcap writable: true
rcap configurable: true rcap configurable: true
rcap enumerable: true rcap enumerable: true
@ -84,41 +214,11 @@ rlh configurable: true
rlh enumerable: true rlh enumerable: true
rlh value before: function rlh() { [native code] } rlh value before: function rlh() { [native code] }
rlh value after: replaced rlh value after: replaced
vw writable: true svb writable: true
vw configurable: true svb configurable: true
vw enumerable: true svb enumerable: true
vw value before: function vw() { [native code] } svb value before: function svb() { [native code] }
vw value after: replaced svb value after: replaced
vh writable: true
vh configurable: true
vh enumerable: true
vh value before: function vh() { [native code] }
vh value after: replaced
vi writable: true
vi configurable: true
vi enumerable: true
vi value before: function vi() { [native code] }
vi value after: replaced
vb writable: true
vb configurable: true
vb enumerable: true
vb value before: function vb() { [native code] }
vb value after: replaced
vmin writable: true
vmin configurable: true
vmin enumerable: true
vmin value before: function vmin() { [native code] }
vmin value after: replaced
vmax writable: true
vmax configurable: true
vmax enumerable: true
vmax value before: function vmax() { [native code] }
vmax value after: replaced
svw writable: true
svw configurable: true
svw enumerable: true
svw value before: function svw() { [native code] }
svw value after: replaced
svh writable: true svh writable: true
svh configurable: true svh configurable: true
svh enumerable: true svh enumerable: true
@ -129,206 +229,81 @@ svi configurable: true
svi enumerable: true svi enumerable: true
svi value before: function svi() { [native code] } svi value before: function svi() { [native code] }
svi value after: replaced svi value after: replaced
svb writable: true
svb configurable: true
svb enumerable: true
svb value before: function svb() { [native code] }
svb value after: replaced
svmin writable: true
svmin configurable: true
svmin enumerable: true
svmin value before: function svmin() { [native code] }
svmin value after: replaced
svmax writable: true svmax writable: true
svmax configurable: true svmax configurable: true
svmax enumerable: true svmax enumerable: true
svmax value before: function svmax() { [native code] } svmax value before: function svmax() { [native code] }
svmax value after: replaced svmax value after: replaced
lvw writable: true svmin writable: true
lvw configurable: true svmin configurable: true
lvw enumerable: true svmin enumerable: true
lvw value before: function lvw() { [native code] } svmin value before: function svmin() { [native code] }
lvw value after: replaced svmin value after: replaced
lvh writable: true svw writable: true
lvh configurable: true svw configurable: true
lvh enumerable: true svw enumerable: true
lvh value before: function lvh() { [native code] } svw value before: function svw() { [native code] }
lvh value after: replaced svw value after: replaced
lvi writable: true vb writable: true
lvi configurable: true vb configurable: true
lvi enumerable: true vb enumerable: true
lvi value before: function lvi() { [native code] } vb value before: function vb() { [native code] }
lvi value after: replaced vb value after: replaced
lvb writable: true vh writable: true
lvb configurable: true vh configurable: true
lvb enumerable: true vh enumerable: true
lvb value before: function lvb() { [native code] } vh value before: function vh() { [native code] }
lvb value after: replaced vh value after: replaced
lvmin writable: true vi writable: true
lvmin configurable: true vi configurable: true
lvmin enumerable: true vi enumerable: true
lvmin value before: function lvmin() { [native code] } vi value before: function vi() { [native code] }
lvmin value after: replaced vi value after: replaced
lvmax writable: true vmax writable: true
lvmax configurable: true vmax configurable: true
lvmax enumerable: true vmax enumerable: true
lvmax value before: function lvmax() { [native code] } vmax value before: function vmax() { [native code] }
lvmax value after: replaced vmax value after: replaced
dvw writable: true vmin writable: true
dvw configurable: true vmin configurable: true
dvw enumerable: true vmin enumerable: true
dvw value before: function dvw() { [native code] } vmin value before: function vmin() { [native code] }
dvw value after: replaced vmin value after: replaced
dvh writable: true vw writable: true
dvh configurable: true vw configurable: true
dvh enumerable: true vw enumerable: true
dvh value before: function dvh() { [native code] } vw value before: function vw() { [native code] }
dvh value after: replaced vw value after: replaced
dvi writable: true
dvi configurable: true
dvi enumerable: true
dvi value before: function dvi() { [native code] }
dvi value after: replaced
dvb writable: true
dvb configurable: true
dvb enumerable: true
dvb value before: function dvb() { [native code] }
dvb value after: replaced
dvmin writable: true
dvmin configurable: true
dvmin enumerable: true
dvmin value before: function dvmin() { [native code] }
dvmin value after: replaced
dvmax writable: true
dvmax configurable: true
dvmax enumerable: true
dvmax value before: function dvmax() { [native code] }
dvmax value after: replaced
cqw writable: true
cqw configurable: true
cqw enumerable: true
cqw value before: function cqw() { [native code] }
cqw value after: replaced
cqh writable: true
cqh configurable: true
cqh enumerable: true
cqh value before: function cqh() { [native code] }
cqh value after: replaced
cqi writable: true
cqi configurable: true
cqi enumerable: true
cqi value before: function cqi() { [native code] }
cqi value after: replaced
cqb writable: true
cqb configurable: true
cqb enumerable: true
cqb value before: function cqb() { [native code] }
cqb value after: replaced
cqmin writable: true
cqmin configurable: true
cqmin enumerable: true
cqmin value before: function cqmin() { [native code] }
cqmin value after: replaced
cqmax writable: true
cqmax configurable: true
cqmax enumerable: true
cqmax value before: function cqmax() { [native code] }
cqmax value after: replaced
cm writable: true
cm configurable: true
cm enumerable: true
cm value before: function cm() { [native code] }
cm value after: replaced
mm writable: true
mm configurable: true
mm enumerable: true
mm value before: function mm() { [native code] }
mm value after: replaced
Q writable: true
Q configurable: true
Q enumerable: true
Q value before: function Q() { [native code] }
Q value after: replaced
in writable: true
in configurable: true
in enumerable: true
in value before: function in() { [native code] }
in value after: replaced
pt writable: true
pt configurable: true
pt enumerable: true
pt value before: function pt() { [native code] }
pt value after: replaced
pc writable: true
pc configurable: true
pc enumerable: true
pc value before: function pc() { [native code] }
pc value after: replaced
px writable: true
px configurable: true
px enumerable: true
px value before: function px() { [native code] }
px value after: replaced
deg writable: true
deg configurable: true
deg enumerable: true
deg value before: function deg() { [native code] }
deg value after: replaced
grad writable: true
grad configurable: true
grad enumerable: true
grad value before: function grad() { [native code] }
grad value after: replaced
rad writable: true
rad configurable: true
rad enumerable: true
rad value before: function rad() { [native code] }
rad value after: replaced
turn writable: true
turn configurable: true
turn enumerable: true
turn value before: function turn() { [native code] }
turn value after: replaced
s writable: true
s configurable: true
s enumerable: true
s value before: function s() { [native code] }
s value after: replaced
ms writable: true
ms configurable: true
ms enumerable: true
ms value before: function ms() { [native code] }
ms value after: replaced
Hz writable: true
Hz configurable: true
Hz enumerable: true
Hz value before: function Hz() { [native code] }
Hz value after: replaced
kHz writable: true
kHz configurable: true
kHz enumerable: true
kHz value before: function kHz() { [native code] }
kHz value after: replaced
dpi writable: true
dpi configurable: true
dpi enumerable: true
dpi value before: function dpi() { [native code] }
dpi value after: replaced
dpcm writable: true dpcm writable: true
dpcm configurable: true dpcm configurable: true
dpcm enumerable: true dpcm enumerable: true
dpcm value before: function dpcm() { [native code] } dpcm value before: function dpcm() { [native code] }
dpcm value after: replaced dpcm value after: replaced
dpi writable: true
dpi configurable: true
dpi enumerable: true
dpi value before: function dpi() { [native code] }
dpi value after: replaced
dppx writable: true dppx writable: true
dppx configurable: true dppx configurable: true
dppx enumerable: true dppx enumerable: true
dppx value before: function dppx() { [native code] } dppx value before: function dppx() { [native code] }
dppx value after: replaced dppx value after: replaced
fr writable: true x writable: true
fr configurable: true x configurable: true
fr enumerable: true x enumerable: true
fr value before: function fr() { [native code] } x value before: function x() { [native code] }
fr value after: replaced x value after: replaced
ms writable: true
ms configurable: true
ms enumerable: true
ms value before: function ms() { [native code] }
ms value after: replaced
s writable: true
s configurable: true
s enumerable: true
s value before: function s() { [native code] }
s value after: replaced
== WebAssembly property descriptors == WebAssembly property descriptors
validate writable: true validate writable: true
validate configurable: true validate configurable: true