* Add initial support for css-text-3 whitespace handling
This adds initial support for whitespace handling from the CSS
specification for Layout 2020. In general, the basics are covered. Since
test output is very sensitive to whitespace handling, this change
incorporates several fixes:
1. Whitespace is collapsed according to the Phase 1 rules of the
specification, though language-specific unbreaking rules are not
handled properly yet.
2. Whitespace is mostly trimmed and positioned according to the Phase 2
rules, but full support for removing whitespace at the end of lines
is pending on a temporary data structure to hold lines under
construction.
3. Completely empty box fragments left over immediately after line
breaks are now trimmed from the fragment tree.
4. This change tries to detect when an inline formatting context
collapses through.
Fixes#29994.
Co-authored-by: Mukilan Thiyagarajan <me@mukilan.in>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
* Update test results
---------
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Mukilan Thiyagarajan <me@mukilan.in>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Remove rayon_croissant and refactor the way that information about
floats in flows bubbles up. This simplifies the code a good deal and
lets us take advantage of some more optimized functions provided by
rayon. This removes 2 crates from the dependency tree.
In addition, this allows avoiding passing `contains_floats` up from
every box tree construction function. This makes things simpler, but
also opens up the possibility of passing more of these flags up in the
future (such as `contains_counters`).
layout_2020: Do linebreak for atomic inline-level elements
<!-- Please describe your changes on the following line: -->
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix#29591 (GitHub issue number if applicable)
<!-- Either: -->
- [x] There are tests for these changes OR
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Clearance was implemented as a Length, where zero meant no clearance.
However, having a clearance of 0px should be different than having
no clearance, since the former can still prevent margin collapse.
This patch keeps the existing behavior, so it won't be possible to get
a clearance of Some(Length::zero()), but it prepares the terrain for
a follow-up to fix calculate_clearance to return the proper thing.
Margins should be able to collapse through floats when collapsing with
parent blocks (the containing block). To properly place floats in this
situation, we need to look at these subsequent floats to find out how
much of the margin will collapse with the parent.
This initial implementation is very basic and the second step would be
to cache this in order to avoid having to constantly recalculate it.
Fixes#29915.
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
Absolutes with static insets need to be laid out at their ancestor
containing blocks, but their position is dependent on their parent's
layout. The static layout position is passed up the tree during hoisting
and ancestors each add their own offset to the position until it is
relative to the containing block that contains the absolute.
This is currently done with a closure and a fairly tricky "tree rank"
numbering system that needs to be threaded through the entire layout.
This change replaces that system.
Every time a child is laid out we create a positioning context to hold
any absolute children (this can be optimized away at a later time). At
each of these moments, we call a method to aggregate offsets to the
static insets of hoisted absolutes. This makes the logic easier to
follow and will also allow implementing this behavior for inline-blocks,
which was impossible with the old system.
This is a simple code organization change with no behavior change with
the idea of making Layout 2020 easier to understand by new folks to the
project. The idea is that we will have a cleaner separation between the
different parts of layout ie one directory for the fragment tree and one
(currently multiple) directory for the box tree.
Instead of hoisting floated fragments to be siblings of the fragment
created by their containing block formatting context, keep them in
"normal" fragment tree position and adjust their positioning to be
relative to the containing block. This means that float fragments follow
the existing invariants of the fragment tree and properly handle hit
testing, painting order, and relative positioning.
The tradeoff here is more complexity tracking the containing block
offsets from the block formatting context (including handling collapsed
margins), but less complexity dealing with hoisting / shared ownership
in addition to the correctness benefits.
Some tests are failing now because this change revealed some additional
shortcomings with clearing block formatting context content size past
the end of their contained floats. This will be fixed in a followup
change.
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit puts floats behind the `layout.floats.enabled` pref, because of the
following issues and unimplemented features:
* Inline formatting contexts don't take floats into account, so text doesn't
flow around the floats yet.
* Non-floated block formatting contexts don't take floats into account, so BFCs
can overlap floats.
* Block formatting contexts that contain floats don't expand vertically to
contain all the floats. That is, floats can stick out the bottom of BFCs,
contra spec.
layout_2020: Only count for content size for height of non-replaced inline elements
<!-- Please describe your changes on the following line: -->
Accorinding to https://drafts.csswg.org/css2/#inline-non-replaced, The vertical padding, border and margin of an inline, non-replaced box start at the top and bottom of the content area, and has nothing to do with the line-height. But only the line-height is used when calculating the height of the line box.
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
<!-- Either: -->
- [x] There are tests for these changes OR
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
inline elements
Accorinding to https://drafts.csswg.org/css2/#inline-non-replaced, The
vertical padding, border and margin of an inline, non-replaced box
start at the top and bottom of the content area, and has nothing to do
with the line-height. But only the line-height is used when
calculating the height of the line box.
During layout it is often useful, for various specification reasons, to
know if an element is the `<body>` element of an `<html>` element root. There
are a couple places where a brittle heuristic is used to detect `<body>`
elements. This information is going to be even more important to
properly handle `<html>` elements that inherit their overflow property from
their `<body>` children.
Implementing this properly requires updating the DOM wrapper interface.
This check does reach up to the parent of thread-safe nodes, but this is
essentially the same kind of operation that `parent_style()` does, so is
ostensibly safe.
This change should not change any behavior and is just a preparation
step for properly handle `<body>` overflow.
Manage containing blocks and WebRender SpaceAndClip during stacking
context tree constuction using the ContainingBlockInfo data structure.
This will allow us to reuse this data structure whenever we traverse the
fragment tree. In addition, StackingContextBuilder is no longer
necessary at all. This change also fixes some bugs where fixed position
fragments were not placed in the correct spatial node. Unfortunately,
these fixes are difficult to test because of #29659.
It was only applied to the 1st inline formatting context of a block
container. Other IFCs were created with the Default trait, implying
TextDecorationLine::NONE.
… and converting them to flow-relative geometric values.
These values are almost always used to size and position a fragment within its containing block, so using the mode of the containing block seems more correct.
Note that the `writing-mode` and `direction` properties are disabled in Servo at the moment, so this PR by itself should have no effect: the writing mode of an element is always the same of that of its containing block since they’re both horizontal rtl.
We want to mutate them when lazily computing their content sizes, but they
are behind an Arc for the hoisting infra, so it also needs its own layer
of inner mutability.
We want to compute content sizes on demand rather than eagerly so we will
need to mutate the independent formatting contexts that own the content sizes.
This avoids the use of lookup tables for containing blocks when
constructing the stacking context tree.
This seems to catch some laid-out hoisted fragments that were otherwise
dropped in the previous design. The changes cause one new test to pass
and one to fail. Visual examination of the failing tests reveals that
it's a progression (list markers are appearing when they were previously
not rendered).
Add support for tracking containing blocks when doing inline layout.
This requires setting up a PositioningContext for inline boxes when
necessary. Instead of using the PositioningContext helper methods
and we reuse the contexts between line breaks.
Fixes#25279.
Instead of painting hoisted position fragments in the order to which
they are hoisted, paint them in tree order and properly incorporate them
into the stacking context.
We do this by creating a placeholder fragment in the original tree position
of hoisted fragments. The ghost fragment contains an atomic id which
links back to the hoisted fragment in the containing block.
While building the stacking context, we keep track of containing blocks
and their children. When encountering a placeholder fragment we look at
the containing block's hoisted children in order to properly paint the
hoisted fragment.
One notable design modification in this change is that hoisted fragments
no longer need an AnonymousFragment as their parent. Instead they are
now direct children of the fragment that establishes their containing block.
This method doesn't actually do any layout, but converts this block to a
HoistedAbsolutelyPositionedBox which is hoisted and then laid-out with
its containing block later. This makes the code a little easier to read.