2020-01-18 09:38:21 +01:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2023-05-10 17:28:15 +01:00
* Copyright ( c ) 2021 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
2020-01-18 09:38:21 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2022-03-08 14:36:18 +00:00
# include "GeneratorUtil.h"
2023-05-31 15:36:21 +01:00
# include <AK/CharacterTypes.h>
2023-05-10 17:28:15 +01:00
# include <AK/GenericShorthands.h>
2020-10-23 18:37:35 +02:00
# include <AK/SourceGenerator.h>
2019-11-18 11:12:58 +01:00
# include <AK/StringBuilder.h>
2022-04-01 17:41:43 +01:00
# include <LibCore/ArgsParser.h>
2022-03-10 11:55:06 +00:00
# include <LibMain/Main.h>
2021-09-29 20:29:44 +02:00
2023-05-25 23:57:09 -07:00
ErrorOr < void > replace_logical_aliases ( JsonObject & properties ) ;
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_header_file ( JsonObject & properties , Core : : File & file ) ;
ErrorOr < void > generate_implementation_file ( JsonObject & properties , Core : : File & file ) ;
2023-06-17 12:40:43 +01:00
ErrorOr < void > generate_bounds_checking_function ( JsonObject & properties , SourceGenerator & parent_generator , StringView css_type_name , StringView type_name , Optional < StringView > default_unit_name = { } , Optional < StringView > value_getter = { } ) ;
2022-04-01 17:41:43 +01:00
2023-05-10 17:28:15 +01:00
static bool type_name_is_enum ( StringView type_name )
{
2023-06-15 16:37:36 +01:00
return ! AK : : first_is_one_of ( type_name , " angle " sv , " color " sv , " custom-ident " sv , " frequency " sv , " image " sv , " integer " sv , " length " sv , " number " sv , " paint " sv , " percentage " sv , " ratio " sv , " rect " sv , " resolution " sv , " string " sv , " time " sv , " url " sv ) ;
2023-05-10 17:28:15 +01:00
}
2022-03-10 11:55:06 +00:00
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
2019-11-18 11:12:58 +01:00
{
2022-04-01 17:41:43 +01:00
StringView generated_header_path ;
StringView generated_implementation_path ;
StringView properties_json_path ;
Core : : ArgsParser args_parser ;
args_parser . add_option ( generated_header_path , " Path to the PropertyID header file to generate " , " generated-header-path " , ' h ' , " generated-header-path " ) ;
args_parser . add_option ( generated_implementation_path , " Path to the PropertyID implementation file to generate " , " generated-implementation-path " , ' c ' , " generated-implementation-path " ) ;
args_parser . add_option ( properties_json_path , " Path to the JSON file to read from " , " json-path " , ' j ' , " json-path " ) ;
args_parser . parse ( arguments ) ;
2019-11-18 11:12:58 +01:00
2022-04-01 17:41:43 +01:00
auto json = TRY ( read_entire_file_as_json ( properties_json_path ) ) ;
2021-11-15 01:46:51 +01:00
VERIFY ( json . is_object ( ) ) ;
2022-04-01 17:41:43 +01:00
auto properties = json . as_object ( ) ;
2023-05-25 23:57:09 -07:00
TRY ( replace_logical_aliases ( properties ) ) ;
2023-02-09 03:02:46 +01:00
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 ) ) ;
2022-04-01 17:41:43 +01:00
TRY ( generate_header_file ( properties , * generated_header_file ) ) ;
TRY ( generate_implementation_file ( properties , * generated_implementation_file ) ) ;
return 0 ;
}
2023-05-25 23:57:09 -07:00
ErrorOr < void > replace_logical_aliases ( JsonObject & properties )
{
AK : : HashMap < DeprecatedString , DeprecatedString > logical_aliases ;
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
const auto & value_as_object = value . as_object ( ) ;
2023-06-06 10:35:16 +02:00
const auto logical_alias_for = value_as_object . get_array ( " logical-alias-for " sv ) ;
2023-05-25 23:57:09 -07:00
if ( logical_alias_for . has_value ( ) ) {
2023-06-06 10:35:16 +02:00
auto const & aliased_properties = logical_alias_for . value ( ) ;
for ( auto const & aliased_property : aliased_properties . values ( ) ) {
logical_aliases . set ( name , aliased_property . to_deprecated_string ( ) ) ;
}
2023-05-25 23:57:09 -07:00
}
} ) ;
for ( auto & [ name , alias ] : logical_aliases ) {
auto const maybe_alias_object = properties . get_object ( alias ) ;
if ( ! maybe_alias_object . has_value ( ) ) {
dbgln ( " No property '{}' found for logical alias '{}' " , alias , name ) ;
VERIFY_NOT_REACHED ( ) ;
}
JsonObject alias_object = maybe_alias_object . value ( ) ;
// Copy over anything the logical property overrides
properties . get_object ( name ) . value ( ) . for_each_member ( [ & ] ( auto & key , auto & value ) {
alias_object . set ( key , value ) ;
} ) ;
properties . set ( name , alias_object ) ;
}
return { } ;
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_header_file ( JsonObject & properties , Core : : File & file )
2022-04-01 17:41:43 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2022-04-01 17:41:43 +01:00
# pragma once
# include <AK/NonnullRefPtr.h>
# include <AK/StringView.h>
# include <AK/Traits.h>
2023-02-28 16:54:25 +00:00
# include <LibJS/Forward.h>
2022-04-01 17:41:43 +01:00
# include <LibWeb/Forward.h>
namespace Web : : CSS {
enum class PropertyID {
Invalid ,
Custom ,
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2022-04-01 17:41:43 +01:00
2022-12-04 18:02:33 +00:00
Vector < DeprecatedString > shorthand_property_ids ;
Vector < DeprecatedString > longhand_property_ids ;
2022-04-01 17:41:43 +01:00
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " longhands " sv ) )
2022-04-01 17:41:43 +01:00
shorthand_property_ids . append ( name ) ;
else
longhand_property_ids . append ( name ) ;
} ) ;
auto first_property_id = shorthand_property_ids . first ( ) ;
auto last_property_id = longhand_property_ids . last ( ) ;
2019-11-18 11:12:58 +01:00
2022-04-01 17:41:43 +01:00
for ( auto & name : shorthand_property_ids ) {
2023-06-17 13:12:36 +01:00
auto member_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( member_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2022-04-01 17:41:43 +01:00
2023-06-17 14:23:59 +01:00
TRY ( member_generator . try_append ( R " ~~~(
2022-04-01 17:41:43 +01:00
@ name : titlecase @ ,
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2022-04-01 17:41:43 +01:00
}
for ( auto & name : longhand_property_ids ) {
2023-06-17 13:12:36 +01:00
auto member_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( member_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2022-04-01 17:41:43 +01:00
2023-06-17 14:23:59 +01:00
TRY ( member_generator . try_append ( R " ~~~(
2022-04-01 17:41:43 +01:00
@ name : titlecase @ ,
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2022-04-01 17:41:43 +01:00
}
2021-09-11 17:26:38 +01:00
2023-06-17 12:40:43 +01:00
TRY ( generator . set ( " first_property_id " , TRY ( title_casify ( first_property_id ) ) ) ) ;
TRY ( generator . set ( " last_property_id " , TRY ( title_casify ( last_property_id ) ) ) ) ;
2022-04-01 17:41:43 +01:00
2023-06-17 12:40:43 +01:00
TRY ( generator . set ( " first_shorthand_property_id " , TRY ( title_casify ( shorthand_property_ids . first ( ) ) ) ) ) ;
TRY ( generator . set ( " last_shorthand_property_id " , TRY ( title_casify ( shorthand_property_ids . last ( ) ) ) ) ) ;
2022-04-01 17:41:43 +01:00
2023-06-17 12:40:43 +01:00
TRY ( generator . set ( " first_longhand_property_id " , TRY ( title_casify ( longhand_property_ids . first ( ) ) ) ) ) ;
TRY ( generator . set ( " last_longhand_property_id " , TRY ( title_casify ( longhand_property_ids . last ( ) ) ) ) ) ;
2022-04-01 17:41:43 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2022-04-01 17:41:43 +01:00
} ;
2023-05-10 13:01:30 +01:00
Optional < PropertyID > property_id_from_camel_case_string ( StringView ) ;
Optional < PropertyID > property_id_from_string ( StringView ) ;
2022-07-11 17:32:29 +00:00
StringView string_from_property_id ( PropertyID ) ;
2022-04-01 17:41:43 +01:00
bool is_inherited_property ( PropertyID ) ;
2023-05-02 15:09:46 +01:00
ErrorOr < NonnullRefPtr < StyleValue > > property_initial_value ( JS : : Realm & , PropertyID ) ;
2022-04-01 17:41:43 +01:00
2023-05-10 17:28:15 +01:00
enum class ValueType {
Angle ,
Color ,
2023-05-25 12:43:52 +01:00
CustomIdent ,
2023-05-10 17:28:15 +01:00
FilterValueList ,
Frequency ,
Image ,
Integer ,
Length ,
Number ,
Paint ,
Percentage ,
Position ,
2023-06-06 15:42:43 +01:00
Ratio ,
2023-05-10 17:28:15 +01:00
Rect ,
Resolution ,
String ,
Time ,
Url ,
} ;
bool property_accepts_type ( PropertyID , ValueType ) ;
bool property_accepts_identifier ( PropertyID , ValueID ) ;
2023-05-31 15:36:21 +01:00
// These perform range-checking, but are also safe to call with properties that don't accept that type. (They'll just return false.)
bool property_accepts_angle ( PropertyID , Angle const & ) ;
bool property_accepts_frequency ( PropertyID , Frequency const & ) ;
bool property_accepts_integer ( PropertyID , i64 const & ) ;
bool property_accepts_length ( PropertyID , Length const & ) ;
bool property_accepts_number ( PropertyID , double const & ) ;
bool property_accepts_percentage ( PropertyID , Percentage const & ) ;
bool property_accepts_resolution ( PropertyID , Resolution const & ) ;
bool property_accepts_time ( PropertyID , Time const & ) ;
2023-05-26 23:16:43 +03:30
Vector < PropertyID > longhands_for_shorthand ( PropertyID ) ;
2022-04-01 17:41:43 +01:00
size_t property_maximum_value_count ( PropertyID ) ;
bool property_affects_layout ( PropertyID ) ;
bool property_affects_stacking_context ( PropertyID ) ;
constexpr PropertyID first_property_id = PropertyID : : @ first_property_id @ ;
constexpr PropertyID last_property_id = PropertyID : : @ last_property_id @ ;
constexpr PropertyID first_shorthand_property_id = PropertyID : : @ first_shorthand_property_id @ ;
constexpr PropertyID last_shorthand_property_id = PropertyID : : @ last_shorthand_property_id @ ;
constexpr PropertyID first_longhand_property_id = PropertyID : : @ first_longhand_property_id @ ;
constexpr PropertyID last_longhand_property_id = PropertyID : : @ last_longhand_property_id @ ;
enum class Quirk {
// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
HashlessHexColor ,
// https://quirks.spec.whatwg.org/#the-unitless-length-quirk
UnitlessLength ,
} ;
bool property_has_quirk ( PropertyID , Quirk ) ;
} // namespace Web::CSS
namespace AK {
template < >
struct Traits < Web : : CSS : : PropertyID > : public GenericTraits < Web : : CSS : : PropertyID > {
static unsigned hash ( Web : : CSS : : PropertyID property_id ) { return int_hash ( ( unsigned ) property_id ) ; }
} ;
} // namespace AK
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2022-04-01 17:41:43 +01:00
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-01 17:41:43 +01:00
return { } ;
}
2023-06-17 12:40:43 +01:00
ErrorOr < void > generate_bounds_checking_function ( JsonObject & properties , SourceGenerator & parent_generator , StringView css_type_name , StringView type_name , Optional < StringView > default_unit_name , Optional < StringView > value_getter )
2023-05-31 15:36:21 +01:00
{
2023-06-17 13:12:36 +01:00
auto generator = TRY ( parent_generator . fork ( ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( generator . set ( " css_type_name " , TRY ( String : : from_utf8 ( css_type_name ) ) ) ) ;
TRY ( generator . set ( " type_name " , TRY ( String : : from_utf8 ( type_name ) ) ) ) ;
2023-05-31 15:36:21 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2023-05-31 15:36:21 +01:00
bool property_accepts_ @ css_type_name @ ( PropertyID property_id , [[maybe_unused]] @ type_name @ const & value )
{
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-05-31 15:36:21 +01:00
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , JsonValue const & value ) - > ErrorOr < void > {
2023-05-31 15:36:21 +01:00
VERIFY ( value . is_object ( ) ) ;
if ( auto maybe_valid_types = value . as_object ( ) . get_array ( " valid-types " sv ) ; maybe_valid_types . has_value ( ) & & ! maybe_valid_types - > is_empty ( ) ) {
for ( auto valid_type : maybe_valid_types - > values ( ) ) {
auto type_and_range = valid_type . as_string ( ) . split_view ( ' ' ) ;
if ( type_and_range . first ( ) ! = css_type_name )
continue ;
2023-06-17 13:12:36 +01:00
auto property_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( property_generator . set ( " property_name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-05-31 15:36:21 +01:00
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_append ( R " ~~~(
2023-05-31 15:36:21 +01:00
case PropertyID : : @ property_name : titlecase @ :
2023-06-17 14:23:59 +01:00
return ) ~ ~ ~ " ));
2023-05-31 15:36:21 +01:00
if ( type_and_range . size ( ) > 1 ) {
auto range = type_and_range [ 1 ] ;
VERIFY ( range . starts_with ( ' [ ' ) & & range . ends_with ( ' ] ' ) & & range . contains ( ' , ' ) ) ;
auto comma_index = range . find ( ' , ' ) . value ( ) ;
StringView min_value_string = range . substring_view ( 1 , comma_index - 1 ) ;
StringView max_value_string = range . substring_view ( comma_index + 1 , range . length ( ) - comma_index - 2 ) ;
// If the min/max value is infinite, we can just skip that side of the check.
if ( min_value_string = = " -∞ " )
min_value_string = { } ;
if ( max_value_string = = " ∞ " )
max_value_string = { } ;
2023-06-02 17:14:27 +01:00
if ( min_value_string . is_empty ( ) & & max_value_string . is_empty ( ) ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " true; " ) ) ;
2023-06-02 17:14:27 +01:00
break ;
}
2023-06-17 12:40:43 +01:00
auto output_check = [ & ] ( auto & value_string , StringView comparator ) - > ErrorOr < void > {
2023-05-31 15:36:21 +01:00
if ( value_getter . has_value ( ) ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . set ( " value_number " , TRY ( String : : from_utf8 ( value_string ) ) ) ) ;
TRY ( property_generator . set ( " value_getter " , TRY ( String : : from_utf8 ( value_getter . value ( ) ) ) ) ) ;
TRY ( property_generator . set ( " comparator " , TRY ( String : : from_utf8 ( comparator ) ) ) ) ;
TRY ( property_generator . try_append ( " @value_getter@ @comparator@ @value_number@ " ) ) ;
2023-06-17 12:40:43 +01:00
return { } ;
2023-05-31 15:36:21 +01:00
}
GenericLexer lexer { value_string } ;
auto value_number = lexer . consume_until ( is_ascii_alpha ) ;
auto value_unit = lexer . consume_while ( is_ascii_alpha ) ;
if ( value_unit . is_empty ( ) )
value_unit = default_unit_name . value ( ) ;
VERIFY ( lexer . is_eof ( ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( property_generator . set ( " value_number " , TRY ( String : : from_utf8 ( value_number ) ) ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( property_generator . set ( " value_unit " , TRY ( title_casify ( value_unit ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( property_generator . set ( " comparator " , TRY ( String : : from_utf8 ( comparator ) ) ) ) ;
TRY ( property_generator . try_append ( " value @comparator@ @type_name@(@value_number@, @type_name@::Type::@value_unit@) " ) ) ;
2023-06-17 12:40:43 +01:00
return { } ;
2023-05-31 15:36:21 +01:00
} ;
if ( ! min_value_string . is_empty ( ) )
2023-06-17 12:40:43 +01:00
TRY ( output_check ( min_value_string , " >= " sv ) ) ;
2023-05-31 15:36:21 +01:00
if ( ! min_value_string . is_empty ( ) & & ! max_value_string . is_empty ( ) )
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_append ( " && " ) ) ;
2023-05-31 15:36:21 +01:00
if ( ! max_value_string . is_empty ( ) )
2023-06-17 12:40:43 +01:00
TRY ( output_check ( max_value_string , " <= " sv ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " ; " ) ) ;
2023-05-31 15:36:21 +01:00
} else {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " true; " ) ) ;
2023-05-31 15:36:21 +01:00
}
break ;
}
}
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2023-05-31 15:36:21 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2023-05-31 15:36:21 +01:00
default :
return false ;
}
}
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-06-17 12:40:43 +01:00
return { } ;
2023-05-31 15:36:21 +01:00
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_implementation_file ( JsonObject & properties , Core : : File & file )
2022-04-01 17:41:43 +01:00
{
2020-10-23 18:37:35 +02:00
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2020-10-23 18:37:35 +02:00
# include <AK/Assertions.h>
2022-04-14 11:23:23 +01:00
# include <LibWeb/CSS/Enums.h>
2021-08-16 17:42:09 +01:00
# include <LibWeb/CSS/Parser/Parser.h>
2020-10-23 18:37:35 +02:00
# include <LibWeb/CSS/PropertyID.h>
2021-08-16 17:42:09 +01:00
# include <LibWeb/CSS/StyleValue.h>
2023-03-24 17:28:43 +00:00
# include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
2023-05-26 23:16:43 +03:30
# include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
2023-02-17 16:43:28 +00:00
# include <LibWeb/Infra/Strings.h>
2020-10-23 18:37:35 +02:00
namespace Web : : CSS {
2019-11-18 11:12:58 +01:00
2023-05-10 13:01:30 +01:00
Optional < PropertyID > property_id_from_camel_case_string ( StringView string )
2021-09-29 20:29:44 +02:00
{
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-09-29 20:29:44 +02:00
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2021-09-29 20:29:44 +02:00
VERIFY ( value . is_object ( ) ) ;
2023-06-17 13:12:36 +01:00
auto member_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . set ( " name " , TRY ( String : : from_deprecated_string ( name ) ) ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( member_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
TRY ( member_generator . set ( " name:camelcase " , TRY ( camel_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . try_append ( R " ~~~(
2023-03-10 08:48:54 +01:00
if ( string . equals_ignoring_ascii_case ( " @name:camelcase@ " sv ) )
2021-09-29 20:29:44 +02:00
return PropertyID : : @ name : titlecase @ ;
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2021-09-29 20:29:44 +02:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2023-05-10 13:01:30 +01:00
return { } ;
2021-09-29 20:29:44 +02:00
}
2023-05-10 13:01:30 +01:00
Optional < PropertyID > property_id_from_string ( StringView string )
2020-10-23 18:37:35 +02:00
{
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2019-11-18 11:12:58 +01:00
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2021-02-23 20:42:32 +01:00
VERIFY ( value . is_object ( ) ) ;
2020-10-23 18:37:35 +02:00
2023-06-17 13:12:36 +01:00
auto member_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . set ( " name " , TRY ( String : : from_deprecated_string ( name ) ) ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( member_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . try_append ( R " ~~~(
2023-02-17 16:43:28 +00:00
if ( Infra : : is_ascii_case_insensitive_match ( string , " @name@ " sv ) )
2020-10-23 18:37:35 +02:00
return PropertyID : : @ name : titlecase @ ;
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2019-11-18 11:12:58 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2023-05-10 13:01:30 +01:00
return { } ;
2020-10-23 18:37:35 +02:00
}
2019-11-18 11:12:58 +01:00
2022-07-11 17:32:29 +00:00
StringView string_from_property_id ( PropertyID property_id ) {
2020-10-23 18:37:35 +02:00
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2019-11-18 11:12:58 +01:00
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2021-02-23 20:42:32 +01:00
VERIFY ( value . is_object ( ) ) ;
2020-10-23 18:37:35 +02:00
2023-06-17 13:12:36 +01:00
auto member_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . set ( " name " , TRY ( String : : from_deprecated_string ( name ) ) ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( member_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . try_append ( R " ~~~(
2020-10-23 18:37:35 +02:00
case PropertyID : : @ name : titlecase @ :
2022-07-11 17:32:29 +00:00
return " @name@ " sv ;
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2019-11-18 11:12:58 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2020-10-23 18:37:35 +02:00
default :
2022-07-11 17:32:29 +00:00
return " (invalid CSS::PropertyID) " sv ;
2020-10-23 18:37:35 +02:00
}
}
2021-08-16 16:07:13 +01:00
bool is_inherited_property ( PropertyID property_id )
{
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-08-16 16:07:13 +01:00
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2021-08-16 16:07:13 +01:00
VERIFY ( value . is_object ( ) ) ;
bool inherited = false ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " inherited " sv ) ) {
2022-12-21 14:37:27 +00:00
auto inherited_value = value . as_object ( ) . get_bool ( " inherited " sv ) ;
VERIFY ( inherited_value . has_value ( ) ) ;
inherited = inherited_value . value ( ) ;
2021-08-16 16:07:13 +01:00
}
if ( inherited ) {
2023-06-17 13:12:36 +01:00
auto member_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( member_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . try_append ( R " ~~~(
2021-08-16 16:07:13 +01:00
case PropertyID : : @ name : titlecase @ :
return true ;
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-08-16 16:07:13 +01:00
}
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2021-08-16 16:07:13 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2021-08-16 16:07:13 +01:00
default :
return false ;
}
}
2022-03-16 17:46:24 +01:00
bool property_affects_layout ( PropertyID property_id )
{
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2022-03-16 17:46:24 +01:00
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2022-03-16 17:46:24 +01:00
VERIFY ( value . is_object ( ) ) ;
bool affects_layout = true ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " affects-layout " sv ) )
2022-12-21 14:37:27 +00:00
affects_layout = value . as_object ( ) . get_bool ( " affects-layout " sv ) . value_or ( false ) ;
2022-03-16 17:46:24 +01:00
if ( affects_layout ) {
2023-06-17 13:12:36 +01:00
auto member_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( member_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . try_append ( R " ~~~(
2022-03-16 17:46:24 +01:00
case PropertyID : : @ name : titlecase @ :
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2022-03-16 17:46:24 +01:00
}
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2022-03-16 17:46:24 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2022-03-16 17:46:24 +01:00
return true ;
default :
return false ;
}
}
2022-03-21 10:58:51 +01:00
bool property_affects_stacking_context ( PropertyID property_id )
{
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2022-03-21 10:58:51 +01:00
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2022-03-21 10:58:51 +01:00
VERIFY ( value . is_object ( ) ) ;
2022-03-25 00:59:42 +01:00
bool affects_stacking_context = false ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " affects-stacking-context " sv ) )
2022-12-21 14:37:27 +00:00
affects_stacking_context = value . as_object ( ) . get_bool ( " affects-stacking-context " sv ) . value_or ( false ) ;
2022-03-21 10:58:51 +01:00
2022-03-25 00:59:42 +01:00
if ( affects_stacking_context ) {
2023-06-17 13:12:36 +01:00
auto member_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( member_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . try_append ( R " ~~~(
2022-03-21 10:58:51 +01:00
case PropertyID : : @ name : titlecase @ :
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2022-03-21 10:58:51 +01:00
}
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2022-03-21 10:58:51 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2022-03-21 10:58:51 +01:00
return true ;
default :
return false ;
}
}
2023-05-02 15:09:46 +01:00
ErrorOr < NonnullRefPtr < StyleValue > > property_initial_value ( JS : : Realm & context_realm , PropertyID property_id )
2021-08-16 17:42:09 +01:00
{
2022-03-13 17:15:58 +01:00
static Array < RefPtr < StyleValue > , to_underlying ( last_property_id ) + 1 > initial_values ;
2023-04-02 22:46:22 +01:00
if ( auto initial_value = initial_values [ to_underlying ( property_id ) ] )
return initial_value . release_nonnull ( ) ;
// Lazily parse initial values as needed.
// This ensures the shorthands will always be able to get the initial values of their longhands.
// This also now allows a longhand have its own longhand (like background-position-x).
2021-08-16 17:42:09 +01:00
2023-04-02 22:46:22 +01:00
Parser : : ParsingContext parsing_context ( context_realm ) ;
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
LibWeb: Generate shorthand initial values after their longhands
When parsing shorthand values, we'd like to use
`property_initial_value()` to get their longhand property values,
instead of hard-coding them as we currently do. That involves
recursively calling that function while the `initial_values` map is
being initialized, which causes problems because the shorthands appear
alphabetically before their longhand components, so the longhands aren't
initialized yet!
The solution here is to perform 2 passes when generating the code,
outputting properties without "longhands" first, and the rest after.
This could potentially cause issues when shorthands have multiple
levels, in particular `border` -> `border-color` -> `border-left-color`.
But, we do not currently define a default value for `border`, and
`border-color` takes only a single value, so it's fine for now. :^)
2021-09-17 16:53:43 +01:00
2023-06-17 12:40:43 +01:00
auto output_initial_value_code = [ & ] ( auto & name , auto & object ) - > ErrorOr < void > {
2022-07-11 17:32:29 +00:00
if ( ! object . has ( " initial " sv ) ) {
2021-11-10 13:48:41 +00:00
dbgln ( " No initial value specified for property '{}' " , name ) ;
VERIFY_NOT_REACHED ( ) ;
}
2022-12-21 14:37:27 +00:00
auto initial_value = object . get_deprecated_string ( " initial " sv ) ;
VERIFY ( initial_value . has_value ( ) ) ;
auto & initial_value_string = initial_value . value ( ) ;
2021-08-16 17:42:09 +01:00
2023-06-17 13:12:36 +01:00
auto member_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( member_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( member_generator . set ( " initial_value_string " , TRY ( String : : from_deprecated_string ( initial_value_string ) ) ) ) ;
TRY ( member_generator . try_append (
2023-04-02 22:46:22 +01:00
R " ~~~( case PropertyID::@name:titlecase@:
2021-11-10 13:48:41 +00:00
{
2023-05-02 15:09:46 +01:00
auto parsed_value = TRY ( parse_css_value ( parsing_context , " @initial_value_string@ " sv , PropertyID : : @ name : titlecase @ ) ) ;
2021-11-10 13:48:41 +00:00
VERIFY ( ! parsed_value . is_null ( ) ) ;
2023-04-02 22:46:22 +01:00
auto initial_value = parsed_value . release_nonnull ( ) ;
initial_values [ to_underlying ( PropertyID : : @ name : titlecase @ ) ] = initial_value ;
return initial_value ;
2021-08-16 17:42:09 +01:00
}
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-06-17 12:40:43 +01:00
return { } ;
LibWeb: Generate shorthand initial values after their longhands
When parsing shorthand values, we'd like to use
`property_initial_value()` to get their longhand property values,
instead of hard-coding them as we currently do. That involves
recursively calling that function while the `initial_values` map is
being initialized, which causes problems because the shorthands appear
alphabetically before their longhand components, so the longhands aren't
initialized yet!
The solution here is to perform 2 passes when generating the code,
outputting properties without "longhands" first, and the rest after.
This could potentially cause issues when shorthands have multiple
levels, in particular `border` -> `border-color` -> `border-left-color`.
But, we do not currently define a default value for `border`, and
`border-color` takes only a single value, so it's fine for now. :^)
2021-09-17 16:53:43 +01:00
} ;
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
LibWeb: Generate shorthand initial values after their longhands
When parsing shorthand values, we'd like to use
`property_initial_value()` to get their longhand property values,
instead of hard-coding them as we currently do. That involves
recursively calling that function while the `initial_values` map is
being initialized, which causes problems because the shorthands appear
alphabetically before their longhand components, so the longhands aren't
initialized yet!
The solution here is to perform 2 passes when generating the code,
outputting properties without "longhands" first, and the rest after.
This could potentially cause issues when shorthands have multiple
levels, in particular `border` -> `border-color` -> `border-left-color`.
But, we do not currently define a default value for `border`, and
`border-color` takes only a single value, so it's fine for now. :^)
2021-09-17 16:53:43 +01:00
VERIFY ( value . is_object ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( output_initial_value_code ( name , value . as_object ( ) ) ) ;
return { } ;
} ) ) ;
LibWeb: Generate shorthand initial values after their longhands
When parsing shorthand values, we'd like to use
`property_initial_value()` to get their longhand property values,
instead of hard-coding them as we currently do. That involves
recursively calling that function while the `initial_values` map is
being initialized, which causes problems because the shorthands appear
alphabetically before their longhand components, so the longhands aren't
initialized yet!
The solution here is to perform 2 passes when generating the code,
outputting properties without "longhands" first, and the rest after.
This could potentially cause issues when shorthands have multiple
levels, in particular `border` -> `border-color` -> `border-left-color`.
But, we do not currently define a default value for `border`, and
`border-color` takes only a single value, so it's fine for now. :^)
2021-09-17 16:53:43 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append (
2023-04-02 22:46:22 +01:00
R " ~~~( default: VERIFY_NOT_REACHED();
2021-08-16 17:42:09 +01:00
}
2023-04-02 22:46:22 +01:00
VERIFY_NOT_REACHED ( ) ;
2021-08-16 17:42:09 +01:00
}
2021-09-11 17:26:38 +01:00
bool property_has_quirk ( PropertyID property_id , Quirk quirk )
{
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-09-11 17:26:38 +01:00
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2021-09-11 17:26:38 +01:00
VERIFY ( value . is_object ( ) ) ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " quirks " sv ) ) {
2022-12-21 14:37:27 +00:00
auto quirks_value = value . as_object ( ) . get_array ( " quirks " sv ) ;
VERIFY ( quirks_value . has_value ( ) ) ;
auto & quirks = quirks_value . value ( ) ;
2021-09-11 17:26:38 +01:00
if ( ! quirks . is_empty ( ) ) {
2023-06-17 13:12:36 +01:00
auto property_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( property_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_append ( R " ~~~(
2021-09-11 17:26:38 +01:00
case PropertyID : : @ name : titlecase @ : {
switch ( quirk ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-09-11 17:26:38 +01:00
for ( auto & quirk : quirks . values ( ) ) {
VERIFY ( quirk . is_string ( ) ) ;
2023-06-17 13:12:36 +01:00
auto quirk_generator = TRY ( property_generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( quirk_generator . set ( " quirk:titlecase " , TRY ( title_casify ( quirk . as_string ( ) ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( quirk_generator . try_append ( R " ~~~(
2021-09-11 17:26:38 +01:00
case Quirk : : @ quirk : titlecase @ :
return true ;
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-09-11 17:26:38 +01:00
}
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_append ( R " ~~~(
2021-09-11 17:26:38 +01:00
default :
return false ;
}
}
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-09-11 17:26:38 +01:00
}
}
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2021-09-11 17:26:38 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2021-09-11 17:26:38 +01:00
default :
return false ;
}
}
2023-05-10 17:28:15 +01:00
bool property_accepts_type ( PropertyID property_id , ValueType value_type )
{
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2023-05-10 17:28:15 +01:00
VERIFY ( value . is_object ( ) ) ;
auto & object = value . as_object ( ) ;
if ( auto maybe_valid_types = object . get_array ( " valid-types " sv ) ; maybe_valid_types . has_value ( ) & & ! maybe_valid_types - > is_empty ( ) ) {
auto & valid_types = maybe_valid_types . value ( ) ;
2023-06-17 13:12:36 +01:00
auto property_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( property_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_append ( R " ~~~(
2023-05-10 17:28:15 +01:00
case PropertyID : : @ name : titlecase @ : {
switch ( value_type ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-05-10 17:28:15 +01:00
bool did_output_accepted_type = false ;
for ( auto & type : valid_types . values ( ) ) {
VERIFY ( type . is_string ( ) ) ;
auto type_name = type . as_string ( ) . split_view ( ' ' ) . first ( ) ;
if ( type_name_is_enum ( type_name ) )
continue ;
if ( type_name = = " angle " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Angle: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " color " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Color: " ) ) ;
2023-05-25 12:43:52 +01:00
} else if ( type_name = = " custom-ident " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::CustomIdent: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " frequency " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Frequency: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " image " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Image: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " integer " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Integer: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " length " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Length: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " number " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Number: " ) ) ;
2023-06-15 16:37:36 +01:00
} else if ( type_name = = " paint " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Paint: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " percentage " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Percentage: " ) ) ;
2023-06-06 15:42:43 +01:00
} else if ( type_name = = " ratio " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Ratio: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " rect " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Rect: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " resolution " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Resolution: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " string " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::String: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " time " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Time: " ) ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " url " ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case ValueType::Url: " ) ) ;
2023-05-10 17:28:15 +01:00
} else {
VERIFY_NOT_REACHED ( ) ;
}
did_output_accepted_type = true ;
}
if ( did_output_accepted_type )
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " return true; " ) ) ;
2023-05-10 17:28:15 +01:00
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_append ( R " ~~~(
2023-05-10 17:28:15 +01:00
default :
return false ;
}
}
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-05-10 17:28:15 +01:00
}
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2023-05-10 17:28:15 +01:00
default :
return false ;
}
}
bool property_accepts_identifier ( PropertyID property_id , ValueID identifier )
{
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2023-05-10 17:28:15 +01:00
VERIFY ( value . is_object ( ) ) ;
auto & object = value . as_object ( ) ;
2023-06-17 13:12:36 +01:00
auto property_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( property_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " case PropertyID::@name:titlecase@: { " ) ) ;
2023-05-10 17:28:15 +01:00
if ( auto maybe_valid_identifiers = object . get_array ( " valid-identifiers " sv ) ; maybe_valid_identifiers . has_value ( ) & & ! maybe_valid_identifiers - > is_empty ( ) ) {
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_appendln ( " switch (identifier) { " ) ) ;
2023-05-10 17:28:15 +01:00
auto & valid_identifiers = maybe_valid_identifiers . value ( ) ;
for ( auto & identifier : valid_identifiers . values ( ) ) {
2023-06-17 13:12:36 +01:00
auto identifier_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( identifier_generator . set ( " identifier:titlecase " , TRY ( title_casify ( identifier . as_string ( ) ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( identifier_generator . try_appendln ( " case ValueID::@identifier:titlecase@: " ) ) ;
2023-05-10 17:28:15 +01:00
}
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_append ( R " ~~~(
2023-05-10 17:28:15 +01:00
return true ;
default :
break ;
}
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-05-10 17:28:15 +01:00
}
if ( auto maybe_valid_types = object . get_array ( " valid-types " sv ) ; maybe_valid_types . has_value ( ) & & ! maybe_valid_types - > is_empty ( ) ) {
auto & valid_types = maybe_valid_types . value ( ) ;
for ( auto & valid_type : valid_types . values ( ) ) {
auto type_name = valid_type . as_string ( ) . split_view ( ' ' ) . first ( ) ;
if ( ! type_name_is_enum ( type_name ) )
continue ;
2023-06-17 13:12:36 +01:00
auto type_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( type_generator . set ( " type_name:snakecase " , TRY ( snake_casify ( type_name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( type_generator . try_append ( R " ~~~(
2023-05-10 17:28:15 +01:00
if ( value_id_to_ @ type_name : snakecase @ ( identifier ) . has_value ( ) )
return true ;
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-05-10 17:28:15 +01:00
}
}
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_append ( R " ~~~(
2023-05-10 17:28:15 +01:00
return false ;
}
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2023-05-10 17:28:15 +01:00
default :
return false ;
}
}
2021-09-22 12:24:33 +01:00
size_t property_maximum_value_count ( PropertyID property_id )
{
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-09-22 12:24:33 +01:00
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2021-09-22 12:24:33 +01:00
VERIFY ( value . is_object ( ) ) ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " max-values " sv ) ) {
2022-12-21 14:37:27 +00:00
auto max_values = value . as_object ( ) . get ( " max-values " sv ) ;
VERIFY ( max_values . has_value ( ) & & max_values - > is_number ( ) & & ! max_values - > is_double ( ) ) ;
2023-06-17 13:12:36 +01:00
auto property_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( property_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( property_generator . set ( " max_values " , TRY ( String : : from_deprecated_string ( max_values - > to_deprecated_string ( ) ) ) ) ) ;
TRY ( property_generator . try_append ( R " ~~~(
2021-09-22 12:24:33 +01:00
case PropertyID : : @ name : titlecase @ :
return @ max_values @ ;
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-09-22 12:24:33 +01:00
}
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2021-09-22 12:24:33 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2021-09-22 12:24:33 +01:00
default :
return 1 ;
}
2023-06-17 14:23:59 +01:00
} ) ~ ~ ~ " ));
2021-09-22 12:24:33 +01:00
2023-06-17 12:40:43 +01:00
TRY ( generate_bounds_checking_function ( properties , generator , " angle " sv , " Angle " sv , " Deg " sv ) ) ;
TRY ( generate_bounds_checking_function ( properties , generator , " frequency " sv , " Frequency " sv , " Hertz " sv ) ) ;
TRY ( generate_bounds_checking_function ( properties , generator , " integer " sv , " i64 " sv , { } , " value " sv ) ) ;
TRY ( generate_bounds_checking_function ( properties , generator , " length " sv , " Length " sv , { } , " value.raw_value() " sv ) ) ;
TRY ( generate_bounds_checking_function ( properties , generator , " number " sv , " double " sv , { } , " value " sv ) ) ;
TRY ( generate_bounds_checking_function ( properties , generator , " percentage " sv , " Percentage " sv , { } , " value.value() " sv ) ) ;
TRY ( generate_bounds_checking_function ( properties , generator , " resolution " sv , " Resolution " sv , " Dpi " sv ) ) ;
TRY ( generate_bounds_checking_function ( properties , generator , " time " sv , " Time " sv , " S " sv ) ) ;
2023-05-31 15:36:21 +01:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2023-05-26 23:16:43 +03:30
Vector < PropertyID > longhands_for_shorthand ( PropertyID property_id )
{
switch ( property_id ) {
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-06-17 12:40:43 +01:00
TRY ( properties . try_for_each_member ( [ & ] ( auto & name , auto & value ) - > ErrorOr < void > {
2023-05-26 23:16:43 +03:30
if ( value . as_object ( ) . has ( " longhands " sv ) ) {
auto longhands = value . as_object ( ) . get ( " longhands " sv ) ;
VERIFY ( longhands . has_value ( ) & & longhands - > is_array ( ) ) ;
auto longhand_values = longhands - > as_array ( ) ;
2023-06-17 13:12:36 +01:00
auto property_generator = TRY ( generator . fork ( ) ) ;
2023-06-17 12:40:43 +01:00
TRY ( property_generator . set ( " name:titlecase " , TRY ( title_casify ( name ) ) ) ) ;
2023-05-26 23:16:43 +03:30
StringBuilder builder ;
bool first = true ;
2023-06-17 12:40:43 +01:00
TRY ( longhand_values . try_for_each ( [ & ] ( auto & longhand ) - > ErrorOr < IterationDecision > {
2023-05-26 23:16:43 +03:30
if ( first )
first = false ;
else
2023-06-17 14:23:59 +01:00
TRY ( builder . try_append ( " , " sv ) ) ;
TRY ( builder . try_appendff ( " PropertyID::{} " , TRY ( title_casify ( longhand . to_deprecated_string ( ) ) ) ) ) ;
2023-05-26 23:16:43 +03:30
return IterationDecision : : Continue ;
2023-06-17 12:40:43 +01:00
} ) ) ;
2023-05-26 23:16:43 +03:30
property_generator . set ( " longhands " , builder . to_deprecated_string ( ) ) ;
2023-06-17 14:23:59 +01:00
TRY ( property_generator . try_append ( R " ~~~(
2023-05-26 23:16:43 +03:30
case PropertyID : : @ name : titlecase @ :
return { @ longhands @ } ;
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2023-05-26 23:16:43 +03:30
}
2023-06-17 12:40:43 +01:00
return { } ;
} ) ) ;
2023-05-26 23:16:43 +03:30
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2023-05-26 23:16:43 +03:30
default :
return { } ;
}
}
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2021-04-05 10:12:37 -04:00
2023-06-17 14:23:59 +01:00
TRY ( generator . try_append ( R " ~~~(
2023-05-26 23:16:43 +03:30
} // namespace Web::CSS
2023-06-17 14:23:59 +01:00
) ~ ~ ~ " ));
2020-10-23 18:37:35 +02:00
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-01 17:41:43 +01:00
return { } ;
2019-11-18 11:12:58 +01:00
}