The existing implementation, which is used by Node::hit_test() and
sub-classes, does not include stacking contexts which prevents hit
testing from returning elements contained by those stacking contexts
in some situations.
This is quite rough and definitely not optimal. The stacking contexts
are not retrieved in the correct order. They should be sorted by
z-index then tree order.
This change makes DuckDuckGo technically usable with all the absolute
and relative positioning they use.
Here's roughly how this works:
- InlineLevelIterator keeps a nesting stack of inline-level nodes with
box model metrics.
- When entering a node with box model metrics, we add them to the
current "leading metrics".
- When exiting a node with box model metrics, we add them to the
current "trailing metrics".
- Pending leading metrics are consumed by the first fragment added
to the line.
- Pending trailing metrics are consumed by the last fragment added
to the line.
Like before, the position of a line box fragment is the top left of its
content box. However, fragments are placed horizontally along the line
with space inserted for padding and border.
InlineNode::paint() now expands the content rect as appropriate when
painting background and borders.
Note that margins and margin collapsing is not yet implemented.
This makes the eyes on ACID2 horizontally centered. :^)
Until now, some formatting contexts (BFC in particular) have been
assigning size to the root box. This is really the responsibility of the
parent formatting context, so let's stop doing it.
To keep position:absolute working, parent formatting contexts now notify
child contexts when the child's root box has been sized. (Note that the
important thing here is for the child root to have its final used height
before it's able to place bottom-relative boxes.)
This breaks flexbox layout in some ways, but we'll have to address those
by improving the spec compliance of FFC.)
We sometimes had a stale stacking context tree sitting around, causing
incorrect paints until the next full layout invalidation.
Fix this by simply rebuilding the stacking context tree when asked to.
BFC currently has a number of architectural issues due to it being
responsible for setting the dimensions of the BFC root.
This patch moves the logic for setting up the ICB from BFC to Document.
From the spec:
> Interface SVGGeometryElement represents SVG elements whose rendering
> is defined by geometry with an equivalent path, and which can be
> filled and stroked. This includes paths and the basic shapes.
- https://svgwg.org/svg2-draft/types.html#InterfaceSVGGeometryElement
Making them all create an SVGPathBox, and return a Path from get_path(),
means we can implement the "basic shapes" using the path system we
already have. :^)
Before this, we were filling and stroking every <path>, whether they had
a fill/stroke color or not. We can avoid a bunch of unnecessary work by
checking if the color is transparent (also the case if unset) before
doing the painting work.
If there is no fill color, we also avoid making a copy of the path to
ensure that it's closed.
We also pass whether the shadow goes inside or outside the element. Only
outer shadows are rendered currently, and inner ones may want to be
handled separately from them, as they will never interfere with each
other.
This property represents the CSS content size, so let's reduce ambiguity
by using the spec terminology.
We also bring a bunch of related functions along for the ride.
Instead of making each Layout::Node compute style for itself, we now
compute it in TreeBuilder before even calling create_layout_node().
For non-element DOM nodes, we create the style and layout tree node
in TreeBuilder. This allows us to move create_layout_node() from
DOM::Node to DOM::Element.
Most of the time, we cannot resolve a `calc()` expression until we go to
use it. Since any `<length-percentage>` can legally be a `calc
()`, let's store it in `LengthPercentage` rather than make every single
user care about this distinction.
While IFC flows text into a block container, floating objects are
anchored at the BFC root, not necessarily the local block container.
Because of this, we have to use root-relative coordinates when checking
how much space is available in between left and right floated objects.
Block placement is now divided into a vertical and horizontal step. The
vertical step runs before formatting boxes internally. The horizontal
step still runs after (since we may need the final width value.)
This solves a long-standing architectural problem where IFC didn't know
its origin Y position within the BFC root box. This is required for
figuring out how to flow around floating objects. (Floating objects are
always relative to the BFC root.)
If we run out of horizontal space when placing floating objects,
we now perform a "break" and continue with a new line of floats
below the bottommost margin edge of the current line.
This is definitely not 100% to-spec yet, but a huge improvement
on ACID1 already. :^)
This patch adds a BFC::FloatSideData struct so we can contain left and
right floating object layout state in a struct. This is preparation for
adding more per-side state.
This is poorly factored. TextNode needs to know whether the most
recently inserted fragment on the current line was empty or ended in
whitespace. This is used when deciding what to do with leading
whitespace in text nodes.
Let's keep this working for now, but we should eventually sort this out
and make text chunk iteration not depend on this information.
When collapsing whitespace, we can skip over all-whitespace chunks at
the start of each line, and immediately following fragments that
themselves end in whitespace.
Now that we build lines incrementally, we no longer need the atomic line
splitting API.
The new InlineLevelIterator and LineBuilder setup does have some
regressions from the old behavior, but we can deal with them as we go.
We don't want to descend into inline-block containers when iterating
inline-level items, since that would make the inline-level children of
the inline-block bubble up to the containing block of the inline-block.
This resolves a long-standing architectural problem in LibWeb that made
it unable to place CSS floating objects correctly due to not having
final vertical position information when computing the amount of
available horizontal space for each line.