Skip to content

LibWeb: Move the style system's inner loops into Rust - #10787

Merged
awesomekling merged 33 commits into
LadybirdBrowser:masterfrom
awesomekling:stylecore
Jul 21, 2026
Merged

LibWeb: Move the style system's inner loops into Rust#10787
awesomekling merged 33 commits into
LadybirdBrowser:masterfrom
awesomekling:stylecore

Conversation

@awesomekling

Copy link
Copy Markdown
Member

Parts of the style system already run in Rust: selector matching, the cascade store, calc, style values and property computation. But C++ still drove them through fine-grained callbacks, so computing one element's style crossed the C++/Rust boundary constantly: once per declaration, per longhand, per style value queried, per ComputedValues field. Those crossings are pure overhead, and they're also what keeps the style system from becoming a self-contained Rust component. This PR makes the loops themselves run in Rust, with the boundary reduced to a few bulk calls per element.

To keep the work honest, the branch starts by adding simple counters for every crossing of the style FFI boundary (exposed as internals.styleFfiCounters(), with fixed workload pages in Meta/StyleFfiBaseline/). This is temporary scaffolding to steer the port and catch regressions in coarseness, and it goes away once the port is done. On the inheritance-heavy workload we started at roughly 1330 crossings per element. Then, in order:

  • Value selection: the Rust driver now picks each longhand's cascaded, inherited or initial value itself, using a shared initial-value table and a per-element snapshot of the parent's inherited values. This deletes the per-longhand callback set and takes crossings from ~1330 to ~343 per element.
  • Computation: results are stored in one batch per element instead of one call per property. Simple values (keywords, numbers, plain lengths) and a growing set of properties (border widths, spacings, corner shapes, math-depth, the font cluster, line-height) compute natively; anything Rust can't compute yet rides the same batch and C++ computes it at flush time, in the same order as before. The loop is now ~1 crossing per element.
  • ComputedValues building: 22 of 23 style groups are now filled in by Rust from small per-field descriptor tables, including deciding when a group can share its parent's or the default payload. Only the Font group stays C++-populated, since it holds platform font resources that don't belong in the CSS core.
  • The cascade: instead of applying matched rules one declaration list at a time, C++ hands Rust all of an element's matched blocks in one call and Rust runs the whole cascade (origins, layers, !important, inline style, presentational hints) natively. Cascade crossings drop from ~17 to 2 per element.

Since Rust now owns decisions that used to live in C++, the branch adds parity tests comparing every Rust-generated property table (inheritance, computation order, logical aliases, shorthands, initial values) against the C++ generator, plus regression tests for the edges the port exposed (animated inherited font-size, explicit inherit of non-inherited properties, computed-value precision). Full test-web passes at every commit, and a final commit deletes dead code found while auditing the crate's #[allow(dead_code)] markers.

The point of all this: styling an element is now a Rust pipeline that C++ calls a handful of times, instead of a C++ pipeline that calls Rust thousands of times. What still crosses per-element is known and counted: selector matching's DOM lookups, custom properties, and the finishing/animation passes. As those close, full style computation becomes a Rust component with C++ only supplying fonts and consuming the result, which is what clears the way for styling the whole tree in parallel by default and, eventually, for a Rust layout engine reading Rust-owned style directly.

The style port needs to measure which C++/Rust seams dominate before
removing them. Add a per-operation counter table to the CSS Rust crate,
bumped at every entry point into the style core and at every callback
the core makes back into C++: the longhand driver stages, cascade
origin stages, declaration application, shorthand expansion, selector
DOM callbacks, calc operations, style value shell retain/release, and
style group clone/free. The counters are always-on relaxed atomics; one
increment per crossing is negligible next to the crossing itself.

The counters are exposed to tests as internals.styleFfiCounters() and
internals.resetStyleFfiCounters(), and a new test covers that surface.
Baseline measurements on deterministic workloads show the per-longhand
computation loop dominating every other boundary by two orders of
magnitude: roughly 1330 crossings per recomputed element, of which 333
are compute_and_store callbacks, ~330 are initial and inherited value
fetches, and ~980 are per-longhand style value queries made from C++.
Deterministic pages measuring the style FFI boundary counters over
representative DOM shapes: a small document, a stylesheet-heavy
document, an inheritance-heavy chain, custom properties, shadow DOM
with slots and parts, animations and transitions, and a targeted
single-element restyle. collect.py copies them into the LibWeb test
tree, runs them through test-web, prints each workload's counters, and
cleans up again. The output is a measurement of the current boundary,
not a regression test, so the pages stay out of the committed suite.
The longhand computation loop calls back into C++ once per property that
falls back to its initial value, only to have C++ look the value up in a
process-wide table. Pin every longhand's initial value for the process
lifetime and install the (shell, data) pointer pairs into the Rust style
computation core alongside the other style metadata tables, so the core
can select initial values without crossing the FFI.

A parity test compares every table entry against property_initial_value
on the C++ side, which is now exported from LibWeb for that purpose. The
table is installed but not yet consumed; the driver switches over when
longhand value selection moves into the core.
The property computation driver called back into C++ up to four times
per longhand: to pin the winning cascaded value, to fetch the inherited
value, to select the initial value, and to compute and store the
result, with C++ then re-entering Rust three more times per longhand to
decide whether the specified value must be kept for re-resolution when
an ancestor changes.

Move longhand value selection into the driver itself. The winning
cascaded value comes straight from the cascaded property store, initial
values come from the process-wide table installed by the previous
commit, and inherited values come from a per-element parent snapshot of
the inheritable computed values that C++ prepares in bulk before the
drive. The importance and inheritance bitmaps, the raw cascaded
font-size, and the viewport font-metric and shadow-root inheritance
side effects accumulate in a results block that C++ applies once after
the loop, replacing the C++ LonghandFlowState protocol entirely. The
inheritance-dependence decision runs natively over the Rust value
graph, with C++ consulted only for value kinds whose computational
independence rule still lives with their shells. Explicit inherit of a
non-inherited property fetches the parent value through a separately
counted rare callback, since the snapshot only carries the
inherited-by-default longhands.

The one remaining per-longhand callback computes and stores the
selected value. It also copies the parent's animated value for
inherited properties at the same point in the flow as before, so that
computation contexts built later in the loop still see animated
inherited values; a new test pins that ordering by checking that a
child's percentage line-height resolves against the parent's animated
font-size.

On the inheritance-heavy baseline workload this removes every
per-longhand selection and query crossing: longhand callbacks drop from
about 665 to about 334 per element and style value query entries from
about 980 to about 4 per element, while the parent snapshot adds no
style value allocations because inheritable keyword values are shared
singletons.
Roughly 270 of the 333 longhands per element crossed the FFI only to
store their selected value and run its bookkeeping, because the value
itself requires no computation. Queue those store operations natively
in the driver and flush the queue in one crossing before any callback
that may read the stored values: the compute callback, the writing-mode
query, and the end of the drive. The C++ side thus observes exactly the
same store, animated-inheritance and bookkeeping sequence that one call
per property used to produce, and the compute callback now only runs
for properties that actually require computation.

Batching extends how long the driver holds value shells: the fetched
parent value of an explicitly inherited non-inherited property used to
be consumed immediately, but can now sit in the queue until the next
flush. The fetch pin therefore keeps every fetched value alive for the
whole drive instead of only until the next fetch; with the shorter pin,
the WPT ref tests that explicitly inherit freshly built grid track
lists and overflow-clip-margin values crashed on released shells. A new
test covers a batch of explicitly inherited non-inherited properties,
including freshly built grid track lists.

On the inheritance-heavy baseline workload, per-element longhand
crossings drop from about 334 to about 42: 28 compute callbacks plus 14
batch flushes. The counters test now checks the compute and batch
crossings together.
For properties without a dedicated computed-value rule, computation is
absolutization of the specified value. Handle the two most common value
shapes natively in the driver: value types whose absolutization is the
identity (keywords that are not resolvable colors, numbers, integers,
strings, custom identifiers, percentages, flex values, unicode ranges
and URLs) queue directly into the store batch, and plain length values
absolutize through the core's existing length resolution math against a
per-kind cached resolution context fetched once from C++, entering the
batch either unchanged or as a computed pixel length that the flush
materializes.

The C++ side installs a color keyword bitmap alongside the other style
metadata tables so the core can tell which keywords resolve to
something else at computed-value time, and hands out length resolution
contexts through a new callback that mirrors the per-element context
caching, flushing queued stores first since context construction reads
stored values. Viewport dependency flags recorded during native
absolutization travel through the driver results block.

The remaining per-longhand compute crossings on the baseline workloads
are almost exactly the properties with dedicated computed-value rules;
cascaded keyword, percentage and length values on other properties now
compute without crossing. A precision test pins that font-relative
lengths absolutize to unquantized pixel values: the batch flush
constructs the computed pixel length from the raw double exactly like
the C++ absolutization path, without rounding through the CSSPixels
fixed-point grid, observable through outline-offset which serializes
its computed value directly.
Border and outline widths and letter- and word-spacing have dedicated
computed-value rules whose logic already lives in the core as leaf
functions the C++ dispatcher calls per value. Run them natively in the
driver instead: the specified value absolutizes natively first (the
identity for the line-width and normal keywords, the length resolution
math for plain lengths), then the border-width snapping or the
normal-to-zero spacing rule produces a pixel result that joins the
store batch. Values the core cannot absolutize, such as calc, still
fall back to the compute callback.

The driver takes the device pixel ratio as an argument since the
border-width snapping needs it, and the letter-or-word-spacing rule is
now callable natively instead of only through its FFI wrapper.

On the inheritance-heavy baseline workload this drops per-element
longhand crossings from about 42 to about 24: 19 compute callbacks plus
5 batch flushes, with the remaining computes concentrated in the font
cluster, line-height, and the list-valued rules.
Both rules already live in the core as leaf functions; run them
natively in the driver. The store batch entry's pixel-length flag
becomes a computed-value kind so the flush can materialize pixel
lengths, integers, or superellipse corner shapes, keeping the C++
round-value cache for the common corner case.

The inherited math-depth and math-style that the math-depth rule needs
come straight from the parent snapshot as an integer and the compact
keyword check, with the initial values applying when there is no
inheritance parent. Superellipse-valued corner shapes and calc-valued
math-depth still fall back to the compute callback, since their
absolutization and resolution stay with C++ for now.

Per-element longhand crossings on the inheritance-heavy baseline
workload drop from about 24 to about 15: 11 compute callbacks plus 4
batch flushes, leaving the font cluster, line-height, and the
list-valued rules.
Two moves take the last per-longhand crossings out of the property
computation loop.

First, the rules whose leaf logic already lives in the core now run
natively in the driver: font-size, with the inherited size and
math-depth read from the parent snapshot and the computed math-depth
tracked across the loop; font-weight; font-style; font-width;
line-height, resolving percentages against the font size carried by the
line-height resolution context; the keyword forms of the font feature
and variation settings; and single-name animation-name values.
Font-family lists and the keyword-valued coordinated background lists
are recognized as unchanged by computation, using the background-image
layer count the driver records in passing. The computed writing-mode
and direction are tracked natively as well, so logical alias pairing no
longer queries C++.

Second, values whose computation still lives in C++ no longer cross
individually: the driver queues them in the store batch as
compute-in-C++ entries, and the flush handler runs the dispatcher in
entry order. Deferring computation into the batch preserves the
previous semantics exactly, because C++ only ever reads stored values
from inside callbacks the driver invokes after flushing. The
per-longhand compute callback is deleted from the driver's callback
table.

On the inheritance-heavy baseline workload the longhand loop now
crosses the FFI about once per element, a single batch flush, with
per-value slow paths remaining only for the computational-independence
decision of the deliberately C++-backed grid track lists. The remaining
C++-computed entries, about seven per element, are counted separately
as the porting backlog.
Start the port of ComputedValues group population into the Rust core
with the inherited box group, whose five fields are computed keyword
values and whose payload layout is already defined in Rust. The group
builds from the computed style value data in one call, sharing instead
of allocating whenever it can: the parent's payload when every field
matches it, and the immortal default payload when every field holds its
initial value. A value the core cannot map falls back to the C++
setters, which remain for the other groups.

The group registry keeps the default payloads it hands to C++ so
builders can share them, and payload retention mirrors the C++ side's
intentionally-leaked sentinel handling. The main style path passes the
inheritance parent into ComputedValues::create() so the builder can
share payloads at construction time rather than only through the
post-construction adoption pass; sharing with a parent whose inherited
box is not the default is now covered by the group sharing test, along
with a child override ending the sharing.
Same recipe as the inherited box group: the three table keywords map
natively and border-spacing reads a computed pixel length, with the
payload shared from the parent or the defaults whenever the values
allow. Two-value border-spacing lists fall back to the C++ setters,
since list children are only reachable through their shells for now.
Byte-wise Rust construction only works for the fully-plain groups whose
layouts are defined in Rust. For the mixed groups, whose payloads hold
C++ vectors, references and variants alongside plain fields, add a
generic builder driven by per-group field descriptors that C++ registers
once: each pokeable field carries its offset and kind (a keyword-mapped
enum byte, a number, a pixel length, or an integer), enum fields carry a
keyword-to-code table built on the C++ side from its own converters, and
hard fields register as keyword constraints that let the constructor's
initial value stand.

The builder decodes every descriptor or returns null for the C++
population path, default-constructs a scratch payload through the group
vtable, pokes the plain fields, and shares the parent or default payload
when the result compares equal through the vtable's new field-wise
equality callback; groups without a comparable layout report false and
conservatively keep their payloads unshared. No group registers
descriptors yet, so behavior is unchanged; groups switch over one table
at a time.
The first group on the generic builder: twelve enum and number fields
poke through registered descriptors, with the keyword-code tables built
from the C++ converters at registration time, and the flex-basis and gap
fields registering as keyword constraints so the constructor's initial
values stand for their common forms. Compound alignment values and
non-initial gaps fail descriptor decoding and fall back to the C++
setters. An i32 field kind joins the builder for order, which can be
negative.
Color fields resolve against the element's own colors, which the group
builder core cannot do, so the gathered value entries grow a resolved
raw color that the C++ gather loop fills from its color resolution
context, and a color field kind pokes it. The text reset group uses it
for text-decoration-color, with the decoration line, thickness and
white-space-trim registering as keyword constraints and the remaining
fields as keyword-mapped enums.

The constraint for text-decoration-line exposed that the group's
constructor default held the none keyword's enum in a one-element
vector, while the computed representation of none is the empty list;
the payloads never compared equal, which also kept every element from
sharing the group's default payload. The constructor default now
matches the computed representation.
Opacity's normalization has not moved into the core, so the gathered
value entries grow a resolved number that the C++ gather loop fills,
mirroring the resolved-color arrangement, and a resolved-f32 field kind
pokes it. The blend mode and isolation fields map as keyword enums, and
the filters, box-shadow and clip register as keyword constraints.

A pixel-length constraint kind joins the builder alongside, for fields
like the scroll margins whose initial values are zero lengths rather
than keywords.
The largest descriptor table so far: thirty-four descriptors cover the
group's twenty-six fields, with four new field kinds rounding out the
builder. A color-or-keyword kind lets outline-color's auto keyword leave
the constructor default standing while resolvable colors poke through
the gather-resolved path; an initial-value constraint compares the value
data against the initial table by pointer identity, which holds exactly
for untouched properties since the driver selects the table's entries
directly; a non-negative pixel kind clamps outline-width the way its
setter does; and a resolved-f64 kind carries shape-image-threshold's
normalized number.

Appearance feeds two descriptors from one property: the appearance
field maps through a keyword table with the compatibility keywords
excluded, so pages using them take the C++ path, while
computed_appearance maps the raw keyword. The conditional setter sites
keep their conditions and gain the adoption gate.
The largest inherited group brings two field kinds that unlock the
remaining shell-bearing groups. A retained-shell kind pokes a style
value shell into a single-pointer reference slot, retaining it through
the core's existing shell reference bridge; the slot's constructor
default must be null, and parent sharing falls out of pointer equality
since inherited values and untouched initial values reference the same
process-wide shells. A keyword-equality kind pokes derived booleans like
whether -webkit-text-fill-color is currentcolor.

The group builds right after the element's color is computed, resolving
its color fields against a context copy that already carries that
color, since the shared context only receives it further down.
overflow-wrap maps through a hand-written converter matching the
switch it replaces, having no generated one, and text-underline-position
stays constraint-only since its compound forms have no single-keyword
mapping.
The caret and accent colors pair a gather-resolved used color, poked at
the nested offset inside their color-or-auto fields, with an auto
keyword constraint on the computed part, since the used value resolves
against the element's colors even when the computed value stays auto. A
resolved-byte kind carries the used color-scheme, which depends on the
page's preference rather than the value alone, alongside an
initial-value constraint covering the scheme list fields.

The color-scheme setters move from the top of create() down beside the
group build: nothing in the function reads the group's scheme fields,
since color resolution carries the scheme in its own context.
All six size fields register as keyword constraints, so the group
adopts a shared payload when every size is untouched and falls back to
the setters otherwise, until the core learns the size representation.
The transform list, the individual transform properties and perspective
register as none-keyword constraints, the origins as initial-value
constraints, and the box and style fields map as keyword enums. The
group's seeded default payload keeps the comparisons sound.
The mask image and clip-path register as none-keyword constraints, the
mask type as a keyword enum, and the seven coordinated mask layer
properties as initial-value constraints, so the group adopts a shared
payload whenever no masking applies and falls back to the setters
otherwise. The url and image conditional setter sites keep their
conditions inside the adoption gate.
Every grid field registers as an initial-value constraint, so the group
adopts a shared payload for the overwhelmingly common case of an
element with no grid properties, until the core learns the grid track
and placement representations.
All twenty-one animation, timeline and transition properties register
as initial-value constraints, so elements without any of them, the
overwhelming majority, adopt a shared payload and skip the whole
comma-list construction cluster.
The geometry properties register as initial-value and auto-keyword
constraints, the stop and flood colors resolve through the gather, the
opacities ride the resolved-number path, and vector-effect and
shape-rendering map as keyword enums.
The paint fields, dash array and offset, and stroke-width register as
constraints, the opacities ride the resolved-number path, miterlimit
pokes as a number, and the rules, line joins, interpolation modes and
text-anchor map as keyword enums, with clip-rule sharing fill-rule's
table since the enums alias. The paint-order trio and the branchy
stroke sites keep their conditions inside the adoption gate.
The list style type registers as an initial-value constraint since it
spans counter styles and strings, the image and quotes as keyword
constraints, and the position as a keyword enum.
Both groups are constraint-only: content, the counters, the anchor
names and scopes, and the position-anchor family all register as
keyword constraints, so elements using none of them, the common case,
adopt shared payloads and skip the construction blocks entirely. The
gather helper hoists above the first constraint-only builds, which run
before any value resolution since they need none.
Float, clear, position, the overflows, box-sizing and resize map as
keyword enums; aspect-ratio, z-index, vertical-align, containment, the
container fields and will-change register as keyword constraints; and
display registers as an initial-value constraint, which also pins the
pre-transformation display since the box type transformation replaces
the stored value whenever it applies.
The insets register as auto-keyword constraints, which also covers the
anchor inset references since anchor values are not the auto keyword,
and the margins and paddings as zero-pixel constraints, until the core
learns the length box representation.
Each side pairs a gather-resolved border color and its retained shell
with a none-style keyword constraint, which also pins the border data
width at the constructor's zero per the used-width rule, while the
computed width pokes separately since it survives the zeroing. The
radii and border-image fields register as constraints and the corner
shape parameters poke as resolved numbers, since the corner properties
always carry computed superellipse values.
The background color pairs its gather-resolved color with the retained
shell, and the image and every coordinated layer property register as
initial-value constraints, which also pins the derived color clip and
the default layer vector. Elements without backgrounds beyond a plain
color, the common case, skip the whole layer construction.

This is the last group on the descriptor machinery: the font group's
population intentionally stays with C++, since its payload holds the
platform font list and resists field-wise comparison, making it the
coarse platform-resource boundary the style core is designed around.
The cascade previously ran as seven origin stage callbacks from the
core into C++, each re-entering the core once per matched declaration
block, with per-declaration callbacks for applicability and source slot
assignment. C++ now collects every matched declaration block into one
bulk description per element, tagged with origin, author context and
layer indices, inline-style and whitelist-bypass flags, layer names and
source identifiers, and the core derives the css-cascade-5 application
order natively: normal user agent, user and presentational hint
declarations, normal author declarations with inner shadow contexts
first and layers in declaration order followed by the context's inline
style, important author declarations with outer contexts first and
layers reversed while preserving rule order within each layer and
without layer names, then important user and user agent declarations.

Source slots report back in one batch resolved through a per-block
source table, the pseudo-element property check only crosses for
elements with a pseudo-element, and unresolved-value parsing remains
the counted parser slow path. The stage callback table, the
per-declaration-block application entry point and the C++ stage and
application helpers are deleted.

On the baseline workloads the cascade drops from about seventeen
crossings per recomputed element to two: the bulk entry and the source
slot batch.
The calc tree normalizes subtraction and division into Negate and Invert
nodes per css-values-4, and sum simplification folds same-unit leaves on
their raw values, so CalcResult::add, subtract, divide_by and negate can
never gain a caller; only multiply_by and invert are used by the product
fold. CalcSerializer's resolve_as field was written at construction and
never read. Delete all of it, along with the Calculated destructuring
that only fed the dead field, and drop the CalcResult doc's reference to
the C++ CalculationResult, which no longer exists.

Most allow(dead_code) markers in the crate covered code that has since
gained callers; strip the stale ones so rustc checks those items again.
The markers that remain are load-bearing lint suppressions, not dead
code: the selector FFI enums have variants only constructed by C++
across the boundary, and StyleValueData's payload fields are only read
by C++ through the exposed layout, neither of which the lint can see.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The CSS style pipeline now performs bulk Rust-backed cascading and longhand computation, constructs and shares computed-style groups through FFI, exposes style-boundary counters, and adds metadata, CSS behavior, and baseline coverage.

Changes

CSS style pipeline

Layer / File(s) Summary
Computed-style group construction and sharing
Libraries/LibWeb/CSS/ComputedValues.*, Libraries/LibWeb/CSS/StyleStructRef.h, Libraries/LibWeb/CSS/Rust/src/computed_values.rs
Registers group field descriptors, builds inherited and non-inherited payloads in Rust, shares equal parent/default payloads, and conditionally adopts groups in ComputedValues::create.
Bulk cascade and property computation
Libraries/LibWeb/CSS/StyleComputer.*, Libraries/LibWeb/CSS/Rust/src/cascaded_properties.rs, Libraries/LibWeb/CSS/Rust/src/style_compute.rs
Replaces per-property FFI orchestration with bulk declaration blocks, parent snapshots, batched computed stores, and result bitmasks.
FFI instrumentation
Libraries/LibWeb/CSS/Rust/src/ffi_stats.rs, Libraries/LibWeb/CSS/Rust/src/{calc,cascaded_properties,selector_engine,style_compute,style_value}.rs, Libraries/LibWeb/Internals/*
Adds counters for style-system entries and callbacks, with reset and snapshot APIs exposed through Internals.
Validation and baselines
Tests/LibWeb/..., Meta/StyleFfiBaseline/*
Adds coverage for inherited animated values, group sharing, fractional lengths, explicit inheritance, metadata parity, and FFI counter workloads.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DOM
  participant StyleComputer
  participant RustCascade
  participant RustDriver
  participant ComputedValues
  DOM->>StyleComputer: update style
  StyleComputer->>RustCascade: cascade matched declaration blocks
  RustCascade-->>StyleComputer: cascaded properties and source slots
  StyleComputer->>RustDriver: compute longhands with parent snapshot
  RustDriver-->>StyleComputer: batched computed values and flags
  StyleComputer->>ComputedValues: create computed values with parent
  ComputedValues->>ComputedValues: adopt shared or newly built groups
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description accurately matches the style-system Rust port, FFI counters, bulk cascade/computation changes, and added tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Meta/StyleFfiBaseline/collect.py`:
- Around line 22-29: Update Meta/StyleFfiBaseline/collect.py lines 22-29 and the
staged page imports in Meta/StyleFfiBaseline/animation-transition.html line 2,
custom-property-heavy.html line 2, inheritance-heavy.html line 2, and
shadow-slots-parts.html line 2 so the pages load include.js from their staged
location: use the deeper relative path, or change staging to preserve the
original location and document/support that choice.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 161bffde-3bb1-45f8-a23e-115a95761d55

📥 Commits

Reviewing files that changed from the base of the PR and between eecf459 and 994b811.

📒 Files selected for processing (42)
  • Libraries/LibWeb/CSS/ComputedValues.cpp
  • Libraries/LibWeb/CSS/ComputedValues.h
  • Libraries/LibWeb/CSS/Rust/build.rs
  • Libraries/LibWeb/CSS/Rust/src/calc.rs
  • Libraries/LibWeb/CSS/Rust/src/cascaded_properties.rs
  • Libraries/LibWeb/CSS/Rust/src/computed_values.rs
  • Libraries/LibWeb/CSS/Rust/src/ffi_stats.rs
  • Libraries/LibWeb/CSS/Rust/src/lib.rs
  • Libraries/LibWeb/CSS/Rust/src/property_metadata.rs
  • Libraries/LibWeb/CSS/Rust/src/selector_engine.rs
  • Libraries/LibWeb/CSS/Rust/src/style_compute.rs
  • Libraries/LibWeb/CSS/Rust/src/style_value.rs
  • Libraries/LibWeb/CSS/RustStyleBridge.cpp
  • Libraries/LibWeb/CSS/RustStyleBridge.h
  • Libraries/LibWeb/CSS/StyleComputer.cpp
  • Libraries/LibWeb/CSS/StyleComputer.h
  • Libraries/LibWeb/CSS/StyleStructRef.h
  • Libraries/LibWeb/CSS/StyleValues/RustStyleValueHandle.h
  • Libraries/LibWeb/Internals/Internals.cpp
  • Libraries/LibWeb/Internals/Internals.h
  • Libraries/LibWeb/Internals/Internals.idl
  • Meta/Generators/generate_libweb_css_property_id.py
  • Meta/StyleFfiBaseline/animation-transition.html
  • Meta/StyleFfiBaseline/collect.py
  • Meta/StyleFfiBaseline/custom-property-heavy.html
  • Meta/StyleFfiBaseline/harness.js
  • Meta/StyleFfiBaseline/inheritance-heavy.html
  • Meta/StyleFfiBaseline/shadow-slots-parts.html
  • Meta/StyleFfiBaseline/single-element-restyle.html
  • Meta/StyleFfiBaseline/small-document.html
  • Meta/StyleFfiBaseline/stylesheet-heavy.html
  • Tests/LibWeb/TestStylePropertyMetadataParity.cpp
  • Tests/LibWeb/Text/expected/css/animated-inherited-font-size-line-height.txt
  • Tests/LibWeb/Text/expected/css/computed-values-group-sharing.txt
  • Tests/LibWeb/Text/expected/css/em-length-computed-value-precision.txt
  • Tests/LibWeb/Text/expected/css/explicit-inherit-non-inherited-properties.txt
  • Tests/LibWeb/Text/expected/css/style-ffi-counters.txt
  • Tests/LibWeb/Text/input/css/animated-inherited-font-size-line-height.html
  • Tests/LibWeb/Text/input/css/computed-values-group-sharing.html
  • Tests/LibWeb/Text/input/css/em-length-computed-value-precision.html
  • Tests/LibWeb/Text/input/css/explicit-inherit-non-inherited-properties.html
  • Tests/LibWeb/Text/input/css/style-ffi-counters.html
💤 Files with no reviewable changes (1)
  • Libraries/LibWeb/CSS/StyleComputer.h

Comment thread Meta/StyleFfiBaseline/collect.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant