The box tree and line boxes now all store a relative offset from their
containing block, instead of an absolute (document-relative) position.
This removes a huge pain point from the layout system which was having
to adjust offsets recursively when something moved. It also makes some
layout logic significantly simpler.
Every box can still find its absolute position by walking its chain
of containing blocks and accumulating the translation from the root.
This is currently what we do both for rendering and hit testing.
This patch introduces support for more than just "absolute px" units in
our Length class. It now also supports "em" and "rem", which are units
relative to the font-size of the current layout node and the <html>
element's layout node respectively.
LayoutReplaced now has intrinsic width, height and ratio. Only some of
the values may be present. The layout algorithm takes the various
configurations into account per the CSS specification.
This is still pretty immature but at least we're moving forward. :^)
We now implement the somewhat fuzzy shrink-to-fit algorithm when laying
out inline-block elements with both block and inline children.
Shrink-to-fit works by doing two speculative layouts of the entire
subtree inside the current block, to compute two things:
1. Preferred minimum width: If we made a line break at every chance we
had, how wide would the widest line be?
2. Preferred width: We break only when explicitly told to (e.g "<br>")
How wide would the widest line be?
We then shrink the width of the inline-block element to an appropriate
value based on the above, taking the available width in the containing
block into consideration (sans all the box model fluff.)
To make the speculative layouts possible, plumb a LayoutMode enum
throughout the layout system since it needs to be respected in various
places.
Note that this is quite hackish and I'm sure there are smarter ways to
do a lot of this. But it does kinda work! :^)
When hit testing encountered a block with inline children, we assumed
that the inline children are nothing but text boxes. An inline-block
box is actually a block child of a block with inline children, so we
have to handle that scenario as well. :^)
Fixes#2353.
Many properties can now have percentage values that get resolved in
layout. The reference value (what is this a percentage *of*?) differs
per property, so I've added a helper where you provide a reference
value as an added parameter to the existing length_or_fallback().
This display type is implemented using a LayoutBlock that is_inline().
Basically it behaves like a block internally, and its children are laid
out in the normal block layout fashion. Externally however, it behaves
like an atomic inline-level box.
Layout of inline-block boxes happens in three stages:
1. The outer dimensions of the block are computed during the recursive
normal layout pass. We skip positioning, but lay out children.
2. Later on, during line layout in the *containing block*, the inline
block now contributes a linebox fragment. When linebox fragments are
positioned, we learn the final position of the inline block. That's
when we set the inline block's position.
3. We re-layout the inline block's children once again. This is done to
make sure they end up in the right position. The layout tree doesn't
use relative offsets, so after we position the inline block in (2),
its children will not have its positions updated. Relayout moves
all children of inline blocks to the right place.
This is a rather naive approach but it does get the basic behavior into
place so we can iterate on it. :^)
This momentarily handles the CSS property "position: absolute;" in
combination with the properties "top" and "left", so that elements can
be placed anywhere on the page independently from their parents.
Statically positioned elements ignore absolute positioned elements when
calculating their position as they don't take up space.