Commit graph

24 commits

Author SHA1 Message Date
Oriol Brufau
18b3e5fe21
layout: Make lines non-phantom if they have inline padding/border/margin (#39058)
According to https://drafts.csswg.org/css-inline/#invisible-line-boxes,
if a line box contains non-zero inline-axis margins, padding or borders,
then it can't be phantom.

Therefore, this patch makes adds a `has_inline_pbm` flag to the line.
Note that we can't use the `has_content` flag, because that would add a
soft wrap opportunity between the padding/border/margin and the first
content of the line.

The patch also renames `InlineFormattingContext::had_inflow_content` to
`has_line_boxes`, which is what we care about for collapsing margins
through.

Testing: Adding new tests
Fixes: #39057

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-09-16 22:18:46 +00:00
Oriol Brufau
4451ce0ef1
layout: Fix propagation of overflow to viewport (#39173)
This patch refactors the logic for propagating overflow to the viewport,
fixing various issues:
- Now we won't propagate from the root element if it has no box. Note
the fix isn't observable in Servo because we lack scrollbars.
- If the first `<body>` element has no box, we won't keep searching for
other `<body>` elements. This deviates from the spec, but aligns us with
other browsers.
- We won't propagate from the `<body>` if it has no box. We were already
handling `display: none` but not `display: contents`. This deviates from
the spec, but aligns us with other browsers.

Also, when we flag the root or `<body>` as having propagated `overflow`
to the viewport, we retrieve the `LayoutBoxBase`. Therefore, now we get
the computed style from the `LayoutBoxBase` in a single operation,
instead of first retrieving the style from the DOM element and then
getting the `LayoutBoxBase` from the box.

Testing: Adding more tests. We were only failing one of them, but it's
hard to test the fixes given that we don't show scrollbars. The tests
that were already passing are useful too, e.g. Firefox fails one of
them.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-09-16 20:53:46 +00:00
Oriol Brufau
c11670b067
layout: Take text-indent into account in min/max-content inline sizes (#39230)
The min-content and max-content inline sizes of an inline formatting
contentext need to take `text-indent` into account. Note it can be set
to a negative amount, so the `ContentSizesComputation` logic needs some
tweaks to handle it well.

Testing: Fixes various WPT tests

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-09-13 06:20:39 +00:00
Oriol Brufau
9e9bd80bba
layout: Add style to ConstraintSpace and IndefiniteContainingBlock (#39229)
They only had the writing mode, now they will have the entire computed
style.
This is needed for #39230.

Testing: Not needed, no behavior change

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-09-11 21:53:14 +00:00
Oriol Brufau
433a6bf47b
layout: Set baseline even if line box has no fragment (#39235)
`InlineFormattingContextLayout::finish_current_line_and_reset()` has an
early return in case the line has no fragment. However, if the line only
has a forced line break, then we still need to set the baseline.

Testing: Adding new test.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-09-10 05:17:25 +00:00
Oriol Brufau
5b9a23ebdb
layout: Add method to retrieve only the first LayoutBoxBase of a box (#39165)
A LayoutBox typically has one LayoutBoxBase, or none in the case of
`LayoutBox::DisplayContents`. However, `LayoutBox::InlineLevel` can
contain multiple inline items, each one with its base. But since things
like the style or the fragment flags should be the same for all of them,
getting the first base is sometimes enough.

Testing: not needed, no change in behavior.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-09-05 16:19:58 +00:00
Oriol Brufau
6e92e1d7d5
layout: Avoid setting baseline for phantom line boxes (#39055)
Phantom line boxes should be treated as non-existing for most purposes,
so don't let them affect the baseline of their block container.

Testing: An existing test passes, and also adding a new one which
doesn't rely on `<button>`

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-09-01 02:52:17 +00:00
Shubham Gupta
d8ff9c7a08
layout: Use overflow: visible if overflow was propagated to viewport (#38598)
The `overflow-*` values of either the root element or the `<body>` get
propagated to the viewport. However, we were missing this part:
> The element from which the value is propagated must then have a used
`overflow` value of `visible`.

See https://drafts.csswg.org/css-overflow/#overflow-propagation

Testing:
 - `css/cssom-view/scrolling-quirks-vs-nonquirks.html`
 - `css/css-overflow/overflow-body-propagation-007.html`
 - `css/css-overflow/overflow-body-propagation-008.html`
 - `css/css-overflow/overflow-body-propagation-009.html`
 - `css/css-overflow/scrollable-overflow-with-nested-elements-001.html` 
 - `css/css-overflow/scrollable-overflow-with-nested-elements-002.html` 
 - `css/css-overflow/scrollable-overflow-with-nested-elements-003.html`
 - `css/css-overflow/scrollable-overflow-with-nested-elements-004.html`
 - `css/css-overflow/scrollbar-gutter-scroll-into-view.html`

Failures:
 - `css/css-overflow/overflow-body-propagation-010.html`
   Failing because of missing support for `contain: paint`.
- `css/css-overflow/scrollable-overflow-with-nested-elements-005.html`
Failing because of wrong `data-expected-height`, but correct
`data-expected-scroll-height` which is core of this PR.
`data-expected-height` can be dealt separately.


Fixes: #38248

---------

Signed-off-by: Shubham Gupta <shubham13297@gmail.com>
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2025-08-20 14:21:51 +00:00
Martin Robinson
ee7c1d9109
layout: Use ServoThreadSafeLayoutNode in more places (#38626)
Use `ServoThreadSafeLayoutNode` in more places in layout rather than
`ServoLayoutNode`. The former is meant to be used during layout, but
layout 2020 was written against the latter. In general, this reduces the
amount of conversion to the thread-safe version in many places in
layout.

In addition, an unused iterator from the `script` crate
`ServoThreadSafeLayoutNodeChildrenIterator` is replaced with the child
iterator from `layout`. The `layout` version must be directly in
`script` now as it uses the dangerous variants of `next_sibling` and
`first_child`, which allow encapsulating the unsafe bits into one
module.

This will ultimately be useful for storing the layout data of
pseudo-element children of pseudo-elements properly.

Testing: This should not change any behavior and thus is covered by
existing tests.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2025-08-13 14:55:19 +00:00
Oriol Brufau
c7c33f5f47
layout: Make IndependentFormattingContext::contents private (again) (#38350)
This was done in #24871, but after some refactorings it became public.
This makes it private again. As said in
b2b3ea992c:

> Privacy forces the rest of the code to go through methods
> rather than matching on the enum,
> reducing accidental layout-mode-specific behavior.

It also avoids the risk of accidentally calling `layout()` on the inner
layout-mode-specific struct, bypassing caching.

Testing: Not needed (no behavior change)

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-07-30 12:55:32 +00:00
Jo Steven Novaryo
3cb16eb864
Reland Input type=text Shadow DOM With Performance Improvement (#37483)
Depends on #37427.

In addition to the changes introduced by
https://github.com/servo/servo/pull/37065, there are several performance
improvements and nits as follows:
- Use the internal pseudo element for style matching, this will reduce
the performance regression by ~66%.
- Manual construction of the `Text` node inside a text container. This
is followed by the modification of the inner `Text` node instead of
using `SetTextContent` which is more expensive.
- Use `implemented_pseudo_element` instead of
`text_control_inner_editor` `NodeFlag` to handle the special cases that
these elements should follow, specifically the:
  - focus delegation workaround;
  - selections; and
  - line height resolving.
- More documentation.

Servo's side of: https://github.com/servo/stylo/pull/217

Testing: No new unexpected WPT failure, except for the one introduced by
https://github.com/servo/servo/pull/37065/.
Fixes: #36307 #37205

---------

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
2025-07-23 09:08:24 +00:00
Oriol Brufau
ff050b71fa
layout: Remove IndependentNonReplacedContents (#37971)
With the work to unify the layout logic for replaced and non-replaced
boxes (#37942), I think the `IndependentNonReplacedContents` enum does
no longer make much sense.

Therefore, this removes `IndependentNonReplacedContents`, merging its
values into `IndependentFormattingContextContents`.

The methods defined on `IndependentFormattingContextContents` can now be
on `IndependentFormattingContext`, in particular this implies that the
layout results of a replaced box will now be cached.

Testing: Unneeded (no behavior change)
This part of #37942

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-07-10 07:46:04 +00:00
Oriol Brufau
47c56d8d74
layout: Unify layout logic for replaced and non-replaced floats&atomics (#37897)
Laying out a float or atomic inline will now use the same logic
regardless of whether it's replaced or not.
This reduces the amount of code, and should have no observable effect.

Testing: Unneeded (no behavior change)
This part of #37942

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-07-09 19:46:22 +00:00
Martin Robinson
436c9072c4
layout: Skip box tree construction when possible (#37957)
When a style change does not chang the structure of the box tree, it is
possible to skip box tree rebuilding for an element. This change adds
support for reusing old box trees when no element has that type of
damage. In order to make this happen, there needs to be a type of
"empty" `LayoutDamage` that just indicates that a fragment tree layout
is necessary.

This is the first step toward incremental fragment tree layout.

Testing: This should not change observable behavior and thus is covered
by
existing WPT tests. Performance numbers to follow.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2025-07-09 17:33:09 +00:00
Martin Robinson
69ff4afa58
Rename script_layout_interface to layout_api (#37591)
Now that we are standardizing on the `_traits` crates becoming `_api`
and exposing the API of the crate that they get their name from [^1],
`script_layout_interface` becomes `layout_api` as it exposes the API for
`layout` that is used by `script` This brings the crate in line with the
naming of the other ones in `shared`.

[^1]:
https://servo.zulipchat.com/#narrow/channel/263398-general/topic/Organizing.20*_traits.20crates/with/396893711

Testing: This should not change any behavior and thus is covered by
existing tests.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-06-20 17:13:05 +00:00
Bhuwan Pandit
04bcafa140
chore: Simplify tracing with servo_tracing macro (#36661) (#37497)
This pull request refactors existing tracing annotations to leverage the
new `servo_tracing::instrument` macro introduced in #36573.

Specifically, the following transformations were applied:
- Removed `#[cfg_attr(feature = "tracing", ...)]` wrappers.
- Replaced `tracing::instrument` with `servo_tracing::instrument`.
- Removed `level = "trace"`
- Removed `fields(servo_profiling = true)` from tracing attributes
however retained others like `name`. `skip type`

Closes: #36661

---------

Signed-off-by: Bhuwan Pandit <bhuwanpandit109@gmail.com>
Signed-off-by: Jonathan Schwender <55576758+jschwe@users.noreply.github.com>
Co-authored-by: Jonathan Schwender <55576758+jschwe@users.noreply.github.com>
2025-06-18 16:18:04 +00:00
Martin Robinson
9781f1241a
layout: Move text decoration propagation to stacking context tree construction (#37069)
Text decorations have a special kind of propagation. Instead of
propating these during box tree construction, move propagation to
stacking context tree construction. This will allow for using a very
easy type of incremental layout when text decorations change. For
instance, when a link changes color during hovering over it, we can skip
all of box and fragment tree construction.

In addition, propagation works a bit better now and color and style
properly move down from their originating `Fragment`s.

This introduces three new failures, because now we are drawing the
text-decoration with the correct color in more places, which exposes an
issue we have with text-decorations not being drawn in relation to the
baseline (taking into account `vertical-align`).

Testing: There are tests for these changes.
Fixes #31736.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2025-05-21 16:38:29 +00:00
Martin Robinson
573663d502
layout: Correct damage propagation and style repair for repaint-only layout (#37004)
When making last-minute changes to the repaint-only layout pass, damage
propagation was broken, meaning that full layout was always done. This
change fixes that, meaning that times in the `blaster.html` test case
now reflect those described in the original commit message from #36978.

In addition, some style repair is now fixed:
- `InlineFormattingContext`s now keep a `SharedInlineStyles` for the
root of the IFC
    which is updated during style repair.
 - `BlockFormattingContext`s now properly update their style.

These changes are verified by turning on repaint only layout for more
properties
in Stylo via servo/stylo#183.

Testing: Manual performance testing via `blaster.html`.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-05-19 10:17:49 +00:00
Martin Robinson
8808f9a468
layout: Add a repaint-only incremental layout mode (#36978)
This change adds the simplest kind of incremental layout. When Servo
detects that all style changes only require a repaint, only run stacking
context tree and WebRender display list generation. This means that
these kind of restyles do not need a re-layout. Instead, the existing
box and fragment trees will be used and the styles of damaged nodes will
be updated in their box and fragment tree nodes.

This requires a new style repair DOM traversal for nodes that have had
their style damaged. In addition, careful accounting of all the places
where we store style must happen in order ot update those styles.

Testing: This is covered by existing WPT tests as it should not change
observable behavior.

We have created a test case which shows a 50% speedup when run
in Servo, even though there still a long way to go to match the speed
of other browsers:
https://gist.github.com/mrobinson/44ec87d028c0198917a7715a06dd98a0

Co-authored-by: Oriol Brufau <obrufau@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2025-05-12 17:03:50 +00:00
Martin Robinson
a0dd2c1beb
layout: Share styles to inline box children via SharedInlineStyles (#36896)
`TextRun`s use their parent style to render. Previously, these styles
were cloned and stored directly in the box tree `TextRun` and resulting
`TextFragment`s. This presents a problem for incremental layout.
Wrapping the style in another layer of shared ownership and mutability
will allow updating all `TextFragment`s during repaint-only incremental
layout by simply updating the box tree styles of the original text
parents.

This adds a new set of borrows when accessing text styles, but also
makes it so that during box tree block construction
`InlineFormattingContext`s are created lazily and now
`InlineFormattingContextBuilder::finish` consumes the builder, making
the API make a bit more sense. This should also improve performance of
box tree block construction slightly.

Testing: This should not change observable behavior and thus is covered
by existing WPT tests.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2025-05-12 09:38:50 +00:00
Martin Robinson
9bc16482a3
layout: Simplify PositioningContext by having it hold a single Vec (#36795)
`PositioningContext` held two vectors, one inside an `Option`, to
differentiate between the version used for a containing block for all
descendants (including `position: absolute` and `position: fixed`) or
only for `position: absolute` descendants. This distinction was really
hard to reason about and required a lot of bookkeeping about what kind
of `PositioningContext` a layout box's parent expected. In addition, it
led to a lot of mistakes.

This change simplifies things so that `PositioningContext` only holds a
single vector. When it comes time to lay out hoisted absolutely
positioned
fragments, the code then:
 - lays out all of them (in the case of a `PositioningContext` for all
   descendants), or
 - only lays out the `position: absolute` descendants and preserves the
   `position: fixed` descendants (in the case the `PositioningContext`
   is only for `position: absolute`.), or
- lays out none of them if the `PositioningContext` was created for
  box that did not establish a containing block for absolutes.

It's possible that this way of dealing with hoisted absolutes is a bit
less efficient, but, the number of these descendants is typically quite
small, so it should not be significant. In addition, this decreases the
size in memory of all `PositioningContexts` which are created in more
situations as time goes on.

Testing: There is a new WPT test with this change.
Fixes: #36696.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-05-02 12:20:11 +00:00
haval0
ec88b5d752
layout: Check if root before establishing containing block (#36360)
As per
[w3.org/TR/filter-effects-1#FilterProperty](https://www.w3.org/TR/filter-effects-1/#FilterProperty),
`filter` shouldn't make the root element establish a containing block
for absolute and fixed positioned descendants. `will-change: filter` has
matching behavior.

This PR adds a check for if we are the root element before establishing
such a block.

To know if we are the root element, we look at the `FragmentFlags`
passed in. Previously for our function, these were dummy flags, always
constructed as empty. Thus, this PR also makes sure the correct
FragmentFlags are passed down the chain to the function
`establishes_containing_block_for_all_descendants`.

Testing:
- `/css/filter-effects/filtered-html-is-not-container.html` now passes
- `/css/css-will-change/will-change-fixedpos-cb-003.html` now passes
- Manual tests are working

Fixes: #35391

---------

Signed-off-by: haval0 <56519858+haval0@users.noreply.github.com>
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2025-04-29 19:19:31 +00:00
Martin Robinson
b63a1818c4
layout: Implement node geometry queries against BoxTree's Fragment (#36663)
This is a followup to #36629, continuing to implement script-based
layout queries  using the `Fragment`s attached to the `BoxTree`. In this
change, geometry queris (apart from parent offset) are calculated using
`Fragment`s hanging of the `BoxTree`.

In order to make this work, all `Fragment`s for inlines split by blocks,
need to be accessible in the `BoxTree`. This required some changes to
the way that box tree items were stored in DOM `BoxSlot`s. Now every
inline level item can have more than a single `BoxTree` item. These are
carefully collected by the `InlineFormattingContextBuilder` -- currently
a bit fragile, but with more documentation.

Testing: There are tests for these changes.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2025-04-25 13:38:05 +00:00
Martin Robinson
7787cab521
layout: Combine layout_2020 and layout_thread_2020 into a crate called layout (#36613)
Now that legacy layout has been removed, the name `layout_2020` doesn't
make much sense any longer, also it's 2025 now for better or worse. The
split between the "layout thread" and "layout" also doesn't make as much
sense since layout doesn't run on it's own thread. There's a possibility
that it will in the future, but that should be something that the user
of the crate controls rather than layout iself.

This is part of the larger layout interface cleanup and optimization
that
@Looriool and I are doing.

Testing: Covered by existing tests as this is just code movement.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-04-19 10:17:03 +00:00
Renamed from components/layout_2020/flow/inline/mod.rs (Browse further)