From a97944e483ffcd4c21046fdc99de236e6405bc9d Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 13 Apr 2022 16:48:03 +0100 Subject: [PATCH] LibWeb: Add a new code generator for CSS enums Alias values are represented by "alias-name=real-name". We have a lot of repetitive code for converting between ValueID and property-specific enums. Let's see if we can generate it. :^) This first step just produces the enums, from a JSON file. The values in there are a duplication of what's in Properties.json, but eventually those will go away. --- .../CodeGenerators/LibWeb/CMakeLists.txt | 1 + .../LibWeb/GenerateCSSEnums.cpp | 100 ++++++++ Userland/Libraries/LibWeb/CMakeLists.txt | 11 + Userland/Libraries/LibWeb/CSS/Enums.json | 216 ++++++++++++++++++ 4 files changed, 328 insertions(+) create mode 100644 Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSEnums.cpp create mode 100644 Userland/Libraries/LibWeb/CSS/Enums.json diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/LibWeb/CMakeLists.txt index 5f96f85aa4..7b3e7904e7 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/CMakeLists.txt +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/CMakeLists.txt @@ -1,5 +1,6 @@ set(SOURCES "") # avoid pulling SOURCES from parent scope +lagom_tool(GenerateCSSEnums SOURCES GenerateCSSEnums.cpp LIBS LagomMain) lagom_tool(GenerateCSSMediaFeatureID SOURCES GenerateCSSMediaFeatureID.cpp LIBS LagomMain) lagom_tool(GenerateCSSPropertyID SOURCES GenerateCSSPropertyID.cpp LIBS LagomMain) lagom_tool(GenerateCSSValueID SOURCES GenerateCSSValueID.cpp LIBS LagomMain) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSEnums.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSEnums.cpp new file mode 100644 index 0000000000..5672208d19 --- /dev/null +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSEnums.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "GeneratorUtil.h" +#include +#include +#include +#include + +ErrorOr generate_header_file(JsonObject& enums_data, Core::Stream::File& file); +ErrorOr generate_implementation_file(JsonObject& enums_data, Core::Stream::File& file); + +ErrorOr serenity_main(Main::Arguments arguments) +{ + StringView generated_header_path; + StringView generated_implementation_path; + StringView identifiers_json_path; + + Core::ArgsParser args_parser; + args_parser.add_option(generated_header_path, "Path to the Enums header file to generate", "generated-header-path", 'h', "generated-header-path"); + args_parser.add_option(generated_implementation_path, "Path to the Enums implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path"); + args_parser.add_option(identifiers_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(identifiers_json_path)); + VERIFY(json.is_object()); + auto enums_data = json.as_object(); + + auto generated_header_file = TRY(Core::Stream::File::open(generated_header_path, Core::Stream::OpenMode::Write)); + auto generated_implementation_file = TRY(Core::Stream::File::open(generated_implementation_path, Core::Stream::OpenMode::Write)); + + TRY(generate_header_file(enums_data, *generated_header_file)); + TRY(generate_implementation_file(enums_data, *generated_implementation_file)); + + return 0; +} + +ErrorOr generate_header_file(JsonObject& enums_data, Core::Stream::File& file) +{ + StringBuilder builder; + SourceGenerator generator { builder }; + + generator.append(R"~~~( +#pragma once + +namespace Web::CSS { + +enum class ValueID; + +)~~~"); + + enums_data.for_each_member([&](auto& name, auto& value) { + VERIFY(value.is_array()); + auto& members = value.as_array(); + + auto enum_generator = generator.fork(); + enum_generator.set("name:titlecase", title_casify(name)); + enum_generator.appendln("enum class @name:titlecase@ {"); + + for (auto& member : members.values()) { + auto member_name = member.to_string(); + // Don't include aliases in the enum. + if (member_name.contains('=')) + continue; + auto member_generator = enum_generator.fork(); + member_generator.set("member:titlecase", title_casify(member_name)); + member_generator.appendln(" @member:titlecase@,"); + } + + enum_generator.appendln("};\n"); + }); + + generator.appendln("}"); + + TRY(file.write(generator.as_string_view().bytes())); + return {}; +} + +ErrorOr generate_implementation_file(JsonObject& enums_data, Core::Stream::File& file) +{ + StringBuilder builder; + SourceGenerator generator { builder }; + + generator.append(R"~~~( +#include + +namespace Web::CSS { +)~~~"); + + // TODO: Generate some things! + (void)enums_data; + + generator.appendln("}"); + + TRY(file.write(generator.as_string_view().bytes())); + return {}; +} diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index eb495c7657..89c72b2ce0 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -36,6 +36,7 @@ set(SOURCES CSS/CSSSupportsRule.cpp CSS/DefaultStyleSheetSource.cpp CSS/Display.cpp + CSS/Enums.cpp CSS/FontFace.cpp CSS/Frequency.cpp CSS/Length.cpp @@ -616,6 +617,16 @@ libweb_js_wrapper(XHR/ProgressEvent) libweb_js_wrapper(XHR/XMLHttpRequest) libweb_js_wrapper(XHR/XMLHttpRequestEventTarget) +invoke_generator( + "Enums" + Lagom::GenerateCSSEnums + "${CMAKE_CURRENT_SOURCE_DIR}/CSS/Enums.json" + "" + "CSS/Enums.h" + "CSS/Enums.cpp" + arguments -j "${CMAKE_CURRENT_SOURCE_DIR}/CSS/Enums.json" +) + invoke_generator( "MediaFeatureID" Lagom::GenerateCSSMediaFeatureID diff --git a/Userland/Libraries/LibWeb/CSS/Enums.json b/Userland/Libraries/LibWeb/CSS/Enums.json new file mode 100644 index 0000000000..d46f8f15df --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/Enums.json @@ -0,0 +1,216 @@ +{ + "align-items": [ + "flex-start", + "flex-end", + "center", + "baseline", + "stretch" + ], + "background-attachment": [ + "fixed", + "local", + "scroll" + ], + "background-box": [ + "border-box", + "content-box", + "padding-box" + ], + "box-sizing": [ + "border-box", + "content-box" + ], + "clear": [ + "none", + "left", + "right", + "both" + ], + "cursor": [ + "auto", + "default", + "none", + "context-menu", + "help", + "pointer", + "progress", + "wait", + "cell", + "crosshair", + "text", + "vertical-text", + "alias", + "copy", + "move", + "no-drop", + "not-allowed", + "grab", + "grabbing", + "e-resize", + "n-resize", + "ne-resize", + "nw-resize", + "s-resize", + "se-resize", + "sw-resize", + "w-resize", + "ew-resize", + "ns-resize", + "nesw-resize", + "nwse-resize", + "col-resize", + "row-resize", + "all-scroll", + "zoom-in", + "zoom-out" + ], + "flex-direction": [ + "row", + "row-reverse", + "column", + "column-reverse" + ], + "flex-wrap": [ + "nowrap", + "wrap", + "wrap-reverse" + ], + "float": [ + "none", + "left", + "right" + ], + "font-variant": [ + "normal", + "small-caps" + ], + "image-rendering": [ + "auto", + "crisp-edges", + "high-quality", + "pixelated", + "smooth" + ], + "justify-content": [ + "flex-start", + "flex-end", + "center", + "space-between", + "space-around" + ], + "line-style": [ + "none", + "hidden", + "dotted", + "dashed", + "solid", + "double", + "groove", + "ridge", + "inset", + "outset" + ], + "list-style-type": [ + "circle", + "decimal", + "decimal-leading-zero", + "disc", + "lower-alpha", + "lower-latin", + "lower-roman", + "none", + "square", + "upper-alpha", + "upper-latin", + "upper-roman" + ], + "overflow": [ + "auto", + "clip", + "hidden", + "scroll", + "visible" + ], + "pointer-events": [ + "auto", + "all", + "none" + ], + "position": [ + "absolute", + "fixed", + "relative", + "static", + "sticky" + ], + "position-edge": [ + "left", + "right", + "top", + "bottom" + ], + "repeat": [ + "no-repeat", + "repeat", + "round", + "space" + ], + "text-align": [ + "center", + "justify", + "left", + "right", + "-libweb-center" + ], + "text-decoration-line": [ + "blink", + "line-through", + "none", + "overline", + "underline" + ], + "text-decoration-style": [ + "dashed", + "dotted", + "double", + "solid", + "wavy" + ], + "text-justify": [ + "auto", + "none", + "inter-word", + "inter-character", + "distribute=inter-character" + ], + "text-transform": [ + "capitalize", + "full-size-kana", + "full-width", + "lowercase", + "none", + "uppercase" + ], + "vertical-align": [ + "baseline", + "bottom", + "middle", + "sub", + "super", + "text-bottom", + "text-top", + "top" + ], + "visibility": [ + "collapse", + "hidden", + "visible" + ], + "white-space": [ + "normal", + "nowrap", + "pre", + "pre-line", + "pre-wrap" + ] +}