首页
/ Ladybird 浏览器 CSS 生成文件详解:从 JSON 数据驱动到 PropertyID 等 C++ 代码的完整解析

Ladybird 浏览器 CSS 生成文件详解:从 JSON 数据驱动到 PropertyID 等 C++ 代码的完整解析

2026-09-04 10:07:12作者:翟江哲Frasier

本篇技术指南聚焦 Ladybird 浏览器中「CSS 生成文件」这一构建机制:它如何以一组 .json 数据文件为输入,通过 Meta/Generators 下的 Python 生成器在构建期自动产出 PropertyID.hGeneratedCSSStyleProperties.cpp 等 C++ 代码。读完后,你能够完整理解每个 JSON 输入文件的字段语义与生成产物,掌握新增或修改 CSS 属性、描述符、伪元素等数据时的实操路径,并能结合生成器源码定位底层实现细节。

生成机制总览:JSON 输入、生成器与输出位置

Ladybird 会为 CSS 相关代码生成大量 C++ 代码:输入是 Libraries/LibWeb/CSS 目录下的一个或多个 .json 文件,输出是构建产物目录 Build/<build-preset>/Libraries/LibWeb/CSS/ 下的 C++ 头文件与实现文件。当你需要新增或修改某个 CSS 属性及其取值时,基本都会与这些生成文件打交道。

生成器统一位于 Meta/Generators 目录,它们作为构建流程的一部分被自动执行,日常开发中大多可以直接忽略它们。整个 CSS 生成流程由 CMake 函数 generate_css_implementation() 统一调度,该函数定义在 Meta/CMake/libweb_generators.cmake,并在 Libraries/LibWeb/CMakeLists.txt 中被调用。从该文件的调用清单看,各 JSON 输入与生成器的对应关系如下:

JSON 输入文件 生成器脚本 生成产物
Descriptors.json generate_libweb_css_descriptors.py CSS/DescriptorID.hCSS/DescriptorID.cpp
Enums.json generate_libweb_css_enums.py CSS/Enums.hCSS/Enums.cpp
MediaFeatures.json generate_libweb_css_media_feature_id.py CSS/MediaFeatureID.h
Properties.json generate_libweb_css_property_id.py CSS/PropertyID.hCSS/PropertyID.cpp
PseudoClasses.json generate_libweb_css_pseudo_class.py CSS/PseudoClass.h
PseudoElements.json generate_libweb_css_pseudo_element.py CSS/PseudoElement.hCSS/PseudoElement.cpp
TransformFunctions.json generate_libweb_css_transform_functions.py CSS/TransformFunctions.hCSS/TransformFunctions.cpp
Units.json generate_libweb_css_units.py CSS/Units.hCSS/Units.cpp
Keywords.json generate_libweb_css_keyword.py CSS/Keyword.hCSS/Keyword.cpp
Units.json generate_libweb_css_numeric_factory_methods.py CSS/GeneratedCSSNumericFactoryMethods.{h,cpp,idl}
Properties.json generate_libweb_css_style_properties.py CSS/GeneratedCSSStyleProperties.{h,cpp,idl}

其中 PropertyID 的生成器接收三个输入:除主输入 -j Properties.json 外,还通过 -e Enums.json-g LogicalPropertyGroups.json 引入额外的数据源,并在 libweb_generators.cmake 中显式声明了对 Enums.jsonLogicalPropertyGroups.json 的依赖——任一文件变更都会触发重新生成。

Properties.json:CSS 属性的完整数据源

每个 CSS 属性都在 Properties.json 中有一条条目,描述它接受哪些取值、是否可继承等元数据。该文件会生成 PropertyID.hPropertyID.cppGeneratedCSSStyleProperties.hGeneratedCSSStyleProperties.cpp 以及 GeneratedCSSStyleProperties.idl。这些数据的绝大部分可以在相应 CSS 规范中该属性的信息框(information box)里找到。

文件组织形式是单个 JSON 对象,键为属性名,值为该属性的数据。每个属性会带有下列字段中的若干个(注意:设置了 legacy-alias-forlogical-alias-for 的属性可以省略必填字段):

字段 是否必填 默认值 说明 生成的函数
affects-layout true 布尔值。修改该属性是否会触发元素布局失效。 bool property_affects_layout(PropertyID)
affects-stacking-context false 布尔值。该属性是否可能为元素创建新的层叠上下文。 bool property_affects_stacking_context(PropertyID)
animation-type 字符串。属性应该如何被动画化,取值由规范定义,见下文。 AnimationType animation_type_from_longhand_property(PropertyID)
inherited 布尔值。属性是否被子元素继承。仅对 longhand 属性有意义。 bool is_inherited_property(PropertyID)
initial 字符串。属性未指定时的初始值。 NonnullRefPtr<StyleValue const> property_initial_value(PropertyID)
legacy-alias-for 字符串。本属性是哪个属性的遗留别名,见下文。
logical-alias-for 对象,结构见下文。 bool property_is_logical_alias(PropertyID);
PropertyID map_logical_alias_to_physical_property(PropertyID, LogicalAliasMappingContext const&)
PropertyID map_physical_property_to_logical_alias(PropertyID, LogicalAliasMappingContext const&)
longhands [] 字符串数组。若本属性是简写(shorthand),这些是它展开后的属性名。 Vector<PropertyID> longhands_for_shorthand(PropertyID)
Vector<PropertyID> expanded_longhands_for_shorthand(PropertyID)
Vector<PropertyID> shorthands_for_longhand(PropertyID)
max-values 1 整数。该属性最多可解析出多少个值,例如 margin 最多可有 4 个值。 size_t property_maximum_value_count(PropertyID)
multiplicity "single" 字符串。标识该属性是单值还是取值列表,见下文。 bool property_is_single_valued(PropertyID)
bool property_is_list_valued(PropertyID)
PropertyMultiplicity property_multiplicity(PropertyID)
percentages-resolve-to 字符串。百分比被解析为什么类型,例如 width 的百分比会解析为 length 值。 Optional<ValueType> property_resolves_percentages_relative_to(PropertyID)
positional-value-list-shorthand false 布尔值。该属性是否为"位置取值列表简写",见下文。 bool property_is_positional_value_list_shorthand(PropertyID)
quirks [] 字符串数组。部分属性在怪异模式(quirks mode)下有特殊行为,在此列出,见下文。 bool property_has_quirk(PropertyID, Quirk)
requires-computation 字符串。描述该属性的值何时需要经过计算过程,见下文。 bool property_requires_computation_with_inherited_value(PropertyID)
bool property_requires_computation_with_initial_value(PropertyID)
bool property_requires_computation_with_cascaded_value(PropertyID)
valid-identifiers [] 字符串数组。属性接受的关键词,见下文。 bool property_accepts_keyword(PropertyID, Keyword)
Optional<Keyword> resolve_legacy_value_alias(PropertyID, Keyword)
valid-types [] 字符串数组。属性接受的取值类型,见下文。 bool property_accepts_type(PropertyID, ValueType)
needs-layout-for-getcomputedstyle false 布尔值。该属性被 getComputedStyle() 查询前是否需要最新的布局结果。 bool property_needs_layout_for_getcomputedstyle(PropertyID)

生成器 generate_libweb_css_property_id.py 对输入数据做了几项强校验,理解它们有助于编写正确的条目:

  • 强制字母序:verify_alphabetical() 会检查 Properties.json 中的属性名必须按字母序排列,违反时直接报错退出(提示 "Please keep this list alphabetical!")。
  • 逻辑别名展开:replace_logical_aliases() 会把每个逻辑属性组中的第一个物理属性作为"模板",深拷贝其全部字段填充到逻辑别名上,并丢弃 quirks 字段(quirks 不会传递给逻辑别名)。
  • all 属性自动补全:populate_all_property_longhands() 要求 all 属性存在,并把所有非 shorthand、非遗留别名的属性自动追加进 alllonghands 列表。
  • 可动画性检查:is_animatable_property() 要求每个属性要么声明 animation-type,要么声明 longhands,shorthand 的可动画性由其 longhands 决定。

animation-type 字段

Web Animations 规范定义了此处允许的取值,规范术语到 JSON 值的映射如下:

规范术语 JSON 取值
not animatable(不可动画) none
discrete(离散) discrete
by computed value(按计算值) by-computed-value
repeatable list(可重复列表) repeatable-list
(见规范正文) custom

legacy-alias-for 字段

(注意与下文的 logical-alias-for 区分。)

遗留名称别名(Legacy name alias)指的是:属性在规范中的名字变了,但语法没变,因此"设置旧名"被直接定义为"设置新名"。例如 font-stretch 被重命名为 font-width,所以 font-stretch 现在是 font-width 的遗留名称别名。

logical-alias-for 字段

(注意与上文的 legacy-alias-for 区分。)

逻辑别名是像 margin-block-start 这样的属性:它可能根据所应用元素的具体情况,把值赋给多个属性中的某一个(如 margin-topmargin-bottommargin-leftmargin-right)。

logical-alias-for 应是一个包含两个字段的对象,两者均为必填:

字段 说明
group 字符串。该逻辑属性所属的逻辑属性组名称(见下文 LogicalPropertyGroups.json 一节)。
mapping 字符串。该属性与组的关系,例如它是块的末端值时填 block-end

multiplicity 字段

三个可能的取值为 "single""list""coordinating-list"

多数属性表示单个"东西",它可能由多个部分组成。例如 border 接受颜色、样式和粗细,但它仍然是一条边。也有属性是列表:background 接受以逗号分隔的多个图层;counter-increment 虽然没有逗号,但它同样是递增的计数器列表。

列表也可以是指纹规范中的"协调列表属性"(coordinating list properties,即 css-values 规范中的 linked properties),此时应标记为 coordinating-list 而非 list

positional-value-list-shorthand 字段

部分简写属性与常规简写不同:提供的值与 longhand 的映射并非 1 对 1,而是取决于提供了多少个值,例如 marginborder-widthgap 等。

这些属性在解析和序列化时有各自不同的行为,标记它们允许生成代码以统一的方式实现这类行为。

quirks 字段

取值来自 WHATWG 的 Quirks 规范中 CSS 部分,映射关系如下:

规范术语 JSON 取值
The hashless hex color quirk(无井号十六进制颜色怪异) hashless-hex-color
The unitless length quirk(无单位长度怪异) unitless-length

requires-computation 字段

一个元素上属性的指定值(specified value)有三种确定方式:

  • 继承(Inherited):例如它是继承属性且未指定值,或者指定了 inherit 关键词;
  • 初始(Initial):例如它_不是_继承属性且未指定值,或者指定了 initial 关键词;
  • 级联(Cascaded):基于样式为该元素级联出了一个值。

之后,系统通过执行计算过程把指定值转为计算值(computed value,见 StyleComputer.cpp 中的 StyleComputer::compute_value_of_property)。

由于某些属性在上述某些情形下,其计算值保证与指定值相同,通过声明那些_不_相同的情形,就可以把计算过程限定为仅在必要时执行:

取值 行为
always 无论指定值如何确定,始终执行计算过程
non-inherited-value 仅当指定值基于初始值或级联值确定时执行计算过程
cascaded-value 仅当指定值基于级联值确定时执行计算过程
never 始终跳过计算过程

valid-identifiers 字段

一个 CSS 关键词名列表,表示该属性接受的关键词。如果规范为这样一组关键词提供了命名,更推荐定义一个枚举并把枚举名放进 valid-types 数组。

部分属性存在遗留取值别名(legacy value alias):某个关键词被解析为另一个关键词。这可以通过 "foo>bar" 的形式支持,表示让 foo 成为 bar 的别名。

valid-types 字段

valid-types 数组列出 CSS 取值类型的名称,取自最新 CSS Values and Units 规范,并去掉名称两侧的 <>。对于数值类型,使用带括号的区间表示法(bracketed range notation),例如 width 可取任意非负长度,所以它的 valid-types 数组中有 "length [0,∞]"。对于 <custom-ident>,被排除的标识符放在 ![] 内,例如 "custom-ident ![all,none]"

LogicalPropertyGroups.json:逻辑属性组

一组相互对应的 CSS 属性可以被归入一个所谓"逻辑属性组"(logical property group)。例如所有 margin-* 属性都在 margin 组中。

LogicalPropertyGroups.json 中的数据用于在运行时把逻辑属性(如 margin-block-start)映射到其物理对应项(如 margin-top),映射依据书写方向(writing direction)。该文件本身不直接生成任何代码,而是作为生成 PropertyID 代码的一部分被使用——这一点与 generate_css_implementation()-g 参数的传入方式一致。

文件是单个对象,键为逻辑属性组名,值为对象:把物理维度、边或角映射到相关属性。具体有哪些键取决于该组——例如 size 组包含 widthheight

Descriptors.json:at-rule 的描述符

描述符(Descriptors)基本就是"属性",只不过面向 at-rule 而非普通样式。整体结构是单个 JSON 对象,键为 at-rule 名,值为该 at-rule 的数据,主体部分是该 at-rule 可以拥有的描述符信息。生成代码提供:

  • 一个 AtRuleID 枚举,主要用作解析描述符的参数,因为多个 at-rule 可能拥有同名描述符;
  • FlyString to_string(AtRuleID),主要用于调试日志;
  • 一个 DescriptorID 枚举,列出所有描述符;
  • Optional<DescriptorID> descriptor_id_from_string(AtRuleID, Utf16View),用于从字符串获取某个 at-rule 下若存在的 DescriptorID;
  • Utf16FlyString const& to_string(DescriptorID),用于序列化描述符名;
  • bool at_rule_supports_descriptor(AtRuleID, DescriptorID),查询给定 at-rule 是否允许该描述符;
  • RefPtr<StyleValue const> descriptor_initial_value(AtRuleID, DescriptorID),获取描述符的初始值;
  • DescriptorMetadata get_descriptor_metadata(AtRuleID, DescriptorID),返回解析描述符时使用的元数据。

生成器 generate_libweb_css_descriptors.py 产出的 DescriptorID.h/cppCSS/Descriptor.cppCSSDescriptors.h 等运行时类型的数据基础。

at-rule 字段

每个 at-rule 对象包含以下字段,前两个必填:

字段 说明
spec 字符串。定义该 at-rule 的规范 URL。
descriptors 对象,键为描述符名,值为其属性对象,见下文。
custom-descriptors 对象,自定义描述符(即 --foo 这类)的配置。省略表示禁止自定义描述符。

描述符字段

每个描述符对象可以有如下字段:

字段 默认值 必填 说明
allow-arbitrary-substitution-functions false 布尔值。该描述符是否支持任意替换函数。
allow-css-wide-keywords false 布尔值。基于 PropertyID 的解析是否包含 CSS 全局关键词(如 initialinherit)。
initial 字符串。未提供时描述符的初始值。
legacy-alias-for 字符串。本描述符是哪一个描述符的别名。
syntax N/A 字符串数组。每个字符串是规范中的一个可选取值。
FIXMENOTE 字符串,用于留下备注。

自定义描述符字段

每个自定义描述符对象包含如下字段:

字段 默认值 必填 说明
allow-arbitrary-substitution-functions false 布尔值。该描述符是否支持任意替换函数。
allow-css-wide-keywords false 布尔值。基于 PropertyID 的解析是否包含 CSS 全局关键词(如 initialinherit)。
syntax N/A 字符串数组。每个字符串是一个可选取值。
FIXMENOTE 字符串,用于留下备注。

Keywords.json:CSS 关键词全集

Keywords.json 是单个 JSON 字符串数组,每个元素是一个 CSS 关键词,例如 autononemediumcurrentcolor。它会生成 Keyword.hKeyword.cpp任何属性或媒体特性用到的关键词都必须在此定义——这是新增 CSS 属性取值时的硬性前置条件。

生成代码提供:

  • KeywordStyleValue 使用的 Keyword 枚举;
  • Optional<Keyword> keyword_from_string(StringView),尝试把字符串转换为 Keyword;
  • StringView string_from_keyword(Keyword),把 Keyword 转回字符串;
  • bool is_css_wide_keyword(StringView),判断字符串是否为特殊的 "CSS 全局关键词"。

Enums.json:关键词枚举的自动封装

Enums.json 是单个 JSON 对象,键为枚举名,值为关键词名数组。它会生成 Enums.hEnums.cpp

我们经常需要定义"由若干关键词组成"的枚举。Enums.json 允许自动生成这些枚举,以及配套的 Keyword 之间相互转换、转字符串的函数。这些枚举还可以直接用于 Properties.json 中的属性定义——把枚举名放进 valid-types 数组即可。这有助于减少重复:例如所有 border-*-style 属性接受同一组关键词,于是它们统一实现为一个 line-style 枚举。

生成代码为每个枚举(以 "foo" 为例)提供:

  • 一个 Foo 枚举,列出其取值;
  • Optional<Foo> keyword_to_foo(Keyword),把 Keyword 转换为 Foo;
  • Keyword to_keyword(Foo),把 Foo 转回 Keyword;
  • StringView to_string(Foo),把 Foo 直接转成字符串。

Enums.json 同时还是 PropertyID 生成器的输入之一(-e 参数),两者在数据层面互相咬合。

PseudoClasses.json:伪类

PseudoClasses.json 是单个 JSON 对象,键为选择器伪类名,值为包含该伪类字段信息的对象。它生成 PseudoClass.h

每个条目包含以下属性:

字段 是否必填 默认值 说明
argument 除非指定了 legacy-alias-for 字符串,描述该伪类函数参数的语法;对于标识符样式的伪类留空。语法直接取自规范。
legacy-alias-for 用于声明本条目应被视为指定伪类的遗留选择器别名(legacy selector alias)。

生成代码提供:

  • 一个 PseudoClass 枚举,列出所有伪类名。

PseudoElements.json:伪元素

PseudoElements.json 是单个 JSON 对象,键为伪元素名,值为包含该伪元素字段信息的对象。它生成 PseudoElement.hPseudoElement.cpp

每个条目包含以下属性:

字段 是否必填 默认值 说明
alias-for 声明本伪元素是指定伪元素的别名。
function-syntax 若为函数型伪元素,其函数参数的语法,直接抄自规范。
implementation 除非 type"function" 该伪元素的实现方式,"synthetic""element-reference",见下文。
is-allowed-in-has false 是否为允许用于 :has() 的伪元素。
is-element-backed false 是否为元素支撑(element-backed)伪元素。
is-pseudo-root false 是否为伪元素根(pseudo-element root)。
is-tree-abiding false 是否为 tree-abiding 伪元素。
property-whitelist 部分伪元素只允许特定属性。若有,在此数组中列出属性名,并支持若干表示属性类别的特殊值——见下文。
spec 规范定义的链接,仅供参考,不会用于生成代码。
type "identifier" 伪元素类型:"identifier""function""both"

生成代码提供:

  • 一个 PseudoElement 枚举,列出所有伪元素名;
  • StringView pseudo_element_name(PseudoElement),把 PseudoElement 转回字符串;
  • bool is_tree_abiding_pseudo_element(PseudoElement),判断伪元素是否为 tree-abiding;
  • bool is_pseudo_element_root(PseudoElement),判断伪元素是否为伪元素根。

property-whitelist 字段

这是一个字符串数组。属性可以直接给出属性名(如 "color"),也可以用前导 # 表示属性类别(如 "#font-properties")——因为规范经常直接说明允许"某一组"属性而不是逐一点名。尚未支持的属性可以加 FIXME: 前缀,会被忽略。属性组与"始终适用"的属性定义在 PseudoElementPropertyGroups.txt 中,并生成进 Rust 侧的级联表。

支持的类别有:

  • #background-properties:background 及其 longhand;
  • #border-properties:borderborder-radius 及其 longhand;
  • #custom-properties:自定义属性,即 CSS 变量;
  • #font-properties:font、其 longhand 以及其他 font-* 属性;
  • #inline-layout-properties:CSS Inline 规范中定义的属性;
  • #inline-typesetting-properties:CSS Text 规范中定义的属性;
  • #margin-properties:margin 及其 longhand;
  • #padding-properties:padding 及其 longhand;
  • #text-decoration-properties:CSS Text Decoration 规范中定义的属性。

implementation 字段

伪元素有两种实现方式:

  • "synthetic"(合成):源元素是伪元素数据的权威方(如动画、计算样式等),并自行处理其行为(例如生布局节点)。::first-line::before 属于此类;
  • "element-reference"(元素引用):伪元素引用 DOM 中另一处的"真实"元素,通常位于源元素的影子树(shadow tree)中,因此本身不是权威方。表单类伪元素(如 ::placeholder)属于此类。

注意:"element-reference" 是实现细节,与规范中的 "element-backed" 伪元素概念不同。按撰写时情况,所有 "element-backed" 伪元素都是 "element-reference",但反之不成立。

MediaFeatures.json:媒体特性

MediaFeatures.json 是单个 JSON 对象,键为媒体特性名,值为包含该媒体特性字段信息的对象。它生成 MediaFeatureID.hMediaFeatureID.cpp

<media-feature> 是媒体查询可以检查的取值,在最新 Media Queries 规范的 @media 描述符表中列出。

这里的定义类似 Properties.json 定义的简化版:

字段 说明
type 字符串。媒体特性的求值方式,discreterange
values 字符串数组。直接取自规范,关键词原样保留,类型名带 <>。类型可以是 <boolean><integer><length><ratio><resolution>
false-keywords 字符串数组。媒体特性按 @media (foo) 求值时应视为 false 的关键词。通常只有单个值,如 "none"

生成代码提供:

  • 一个 MediaFeatureID 枚举,列出每个媒体特性;
  • StringView string_from_media_feature_id(MediaFeatureID),把 MediaFeatureID 转回字符串;
  • bool media_feature_accepts_type(MediaFeatureID, QueryValueType),判断该媒体特性是否接受此类型的值;
  • bool media_feature_accepts_keyword(MediaFeatureID, Keyword),判断该媒体特性是否接受此关键词;
  • bool media_feature_keyword_is_falsey(MediaFeatureID, Keyword),判断给定关键词在布尔上下文(如 @media (foo))中求值时是否视为 false。

MathFunctions.json:CSS 数学函数

MathFunctions.json 是单个 JSON 对象,描述每个 CSS 数学函数,键为函数名,值为描述该函数属性的对象。它生成 MathFunctions.hMathFunctions.cpp

每个条目有两个属性:

字段 说明
parameter-validation 可选字符串。"same""consistent",取决于规范要求输入计算式是同一类型还是兼容类型。默认 "same"。只有一个参数时可忽略。
parameters 参数定义对象数组,见下文。

参数定义包含以下属性:

字段 说明
name 字符串。参数名,与规范中一致。
type 字符串。参数接受的类型,单个字符串内用 | 分隔。
required 布尔值。该参数是否必填。

生成代码提供:

  • 一个 MathFunction 枚举,列出数学函数;
  • CSS 解析器 parse_math_function() 方法的实现。

TransformFunctions.json:变换函数

TransformFunctions.json 是单个 JSON 对象,描述每个 CSS 变换函数,键为函数名,值为描述该函数属性的对象。它生成 TransformFunctions.hTransformFunctions.cpp

每个条目目前只有一个 parameters 属性,为参数定义对象数组。参数定义包含:

字段 说明
type 字符串。参数接受的类型。
required 布尔值。该参数是否必填。

生成代码提供:

  • 一个 TransformFunction 枚举,列出变换函数;
  • Optional<TransformFunction> transform_function_from_string(StringView),把字符串解析为 TransformFunction;
  • StringView to_string(TransformFunction),把 TransformFunction 转回字符串;
  • TransformFunctionMetadata transform_function_metadata(TransformFunction),获取变换函数的元数据,例如参数列表。

EnvironmentVariables.json:CSS 环境变量

EnvironmentVariables.json 是单个 JSON 对象,描述每个 CSS 环境变量,键为环境变量名,值为描述变量属性的对象。它生成 EnvironmentVariable.hEnvironmentVariable.cpp

每个条目有三个属性,全部取自规范:

字段 说明
spec 字符串。该环境变量的规范定义 URL。
type 字符串。变量的 CSS 取值类型,如 <length>
dimensions 整数。变量的维度数,标量为 0

生成代码提供:

  • 一个 EnvironmentVariable 枚举,列出环境变量;
  • StringView to_string(EnvironmentVariable),把 EnvironmentVariable 转回字符串;
  • ValueType environment_variable_type(EnvironmentVariable),获取变量的取值类型;
  • u32 environment_variable_dimension_count(EnvironmentVariable),获取其维度数。

Units.json:维度与单位

Units.json 是 JSON 对象,键为维度类型名,值为对象;该对象的键是单位名,值是每个单位的数据。它生成 Units.hUnits.cpp

每个单位包含以下属性:

字段 说明
is-canonical-unit 布尔值,默认 false。每个维度有一个规范单位(canonical unit)。
number-of-canonical-unit 数值。一个该单位等价于多少个规范单位。相对单位与规范单位本身可忽略此项。
is-relative-to 字符串。某些长度单位相对字体或视口,为这类单位设置为 "font""viewport"

生成代码提供:

  • 一个 DimensionType 枚举,列出定义了单位的每种维度类型;
  • Optional<DimensionType> dimension_for_unit(StringView),查询某单位归属哪个维度(若有);
  • 为每个维度 "foo" 生成一个 FooUnit 枚举,列出该维度的所有单位;对其中每个枚举……
    • constexpr FooUnit canonical_foo_unit(),该类型的规范单位;
    • Optional<FooUnit> string_to_foo_unit(StringView),从字符串解析单位;
    • StringView to_string(FooUnit),序列化这些单位;
    • bool units_are_compatible(FooUnit, FooUnit),判断两者是否兼容——即能否从一种换算到另一种;
    • double ratio_between_units(FooUnit, FooUnit),获取把第一个单位换算为第二个单位的乘数;
  • bool is_absolute(LengthUnit)bool is_font_relative(LengthUnit)bool is_viewport_relative(LengthUnit)bool is_relative(LengthUnit),用于判断长度单位类别。

Units.json 除了驱动 Units.{h,cpp} 的生成,还会被 generate_libweb_css_numeric_factory_methods.py 二次消费,额外生成 GeneratedCSSNumericFactoryMethods 的头文件、实现与 IDL 绑定,供网页侧构造 CSS 数值对象使用。

实战:新增或修改一个 CSS 属性时的完整路径

把上述文件串起来,一个典型的变更流程是:

  1. 确认属性涉及的关键词:先在 Keywords.json 中登记所有用到的关键词(属性与媒体特性共用该表,缺失会导致解析失败);
  2. 复用或新增枚举:若属性接受一组具名关键词,在 Enums.json 中定义枚举,把枚举名写入属性的 valid-types,而不是散列在 valid-identifiers;
  3. 登记属性条目:在 Properties.json 中按字母序新增条目,填齐 animation-typeinheritedinitialrequires-computation 等必填字段(生成器会校验字母序与必填项);简写属性通过 longhands 关联其展开项;
  4. 涉及逻辑属性时:在 LogicalPropertyGroups.json 中确认属性组定义,用 logical-alias-forgroup + mapping 两个字段挂载逻辑属性,生成器会自动以组内第一个物理属性为模板补齐其余字段;
  5. 重新构建:generate_css_implementation() 声明了对各 JSON 的依赖,任何输入变更都会自动触发对应生成器重新运行,无需手工执行生成脚本;产物落在 Build/<build-preset>/Libraries/LibWeb/CSS/ 下参与后续编译。

小结

Ladybird 的 CSS 生成机制把"规范中的数据"(属性表、关键词表、描述符表、媒体特性表、单位表等)全部收敛到 Libraries/LibWeb/CSS 目录下的一组 JSON 文件中,由 Meta/Generators 下的 Python 脚本在 CMake 构建期统一生成 PropertyIDGeneratedCSSStylePropertiesKeywordEnumsPseudoClassPseudoElementMediaFeatureIDUnitsDescriptorIDTransformFunctionsMathFunctionsEnvironmentVariable 等 C++ 代码。理解"每个字段映射到哪些生成函数"是阅读与扩展这套系统的关键:无论是新增属性、登记新关键词,还是定义逻辑属性组与伪元素白名单,入口都是修改对应 JSON 后交给构建系统自动再生成,而无需手工维护任何 C++ 枚举或查询函数。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
docsdocs
暂无描述
Markdown
889
5.78 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.17 K
341