I realized that we're supposed to float the boxes sideways, but not
always to y=0, so that makes it logical to share the placement logic
with other normal non-replaced blocks.
This is still pretty buggy but we're getting closer. :^)
This is definitely not fully-featured, but basically we now handle
the clear property by forcing the cleared box below the bottom-most
floated box on the relevant side.
I don't know why basing the available space between floats on the y
coordinate in the middle of each line seemed like a good idea. It just
creates situations with a few pixels of floats overlapping text!
I'm not sure what this was trying to achieve, but it was moving all
line fragments upwards and a lot of things look a lot better if we
just stop doing that.
I had guessed that floating boxes should somehow be hoisted up to the
nearest block ancestor that creates a block formatting context, but
that's just wrong. They move up to the nearest block ancestor like any
other box that's not absolutely (or fixed) positioned. :^)
Boxes can now be floated left or right, which makes text within the
same block formatting context flow around them.
We were creating way too many block formatting contexts. As it turns
out, we don't need one for every new block, but rather there's a set
of rules that determines whether a given block creates a new block
formatting context.
Each BFC keeps track of the floating boxes within it, and IFC's can
then query it to find the available space for line boxes.
There's a huge hack in here where we assume all lines are the exact
line-height. Making this work with vertically non-uniform lines will
require some architectural changes.
We were not accounting for space occupied by borders when computing
the vertical (y) position of blocks. This meant that blocks with wide
top/bottom borders could bleed into each other incorrectly.
Fix this by using the combined padding+border geometry instead of just
the padding when placing blocks on the y axis.
We were incorrectly resolving relative length units (ex, em, etc.)
against the containing block in many cases. Fix this to resolve them
against the descendant box we're currently processing.
Instead of doing a CSS property lookup for the line style of each
border edge during paint, we now cache the final CSS::LineStyle to use
in the Layout::BorderData.
In order for inline elements (e.g <span>) to contribute padding etc.
to line boxes, we now create special "leading" and "trailing" fragments
for Layout::InlineNode and size them according to the horizontal
padding values.
The height of these fragments is taken from the tallest fragment on the
line. (Perhaps we should stop having per-fragment heights and just keep
a single height per line box, but that's a separate issue.)
In order to make things look nice, we now also adjust the height of all
fragments on a line so that nobody is shorter than the CSS line-height.
Fragment painting was very limited by only being called during the
foreground paint phase. We now paint fragments as part of every phase
(and the phase is passed to paint_fragment() of course!)
We were rejecting perfectly valid z-index values like '1000' since we
were passing all CSS values through the length parser and unit-less
lengths are not valid in this context.
It's yet another hack for the ad-hoc CSS parser (its days are numbered)
but this makes the top header links on google.com actually work. :^)
Calling Frame::set_size() already triggered a relayout, so calling
layout() again right after meant we did all the work one more time.
Not being dumb like this makes resizing significantly smoother. :^)
Layout was using an outdated viewport rect that we set *after* doing
a layout due to resize. That meant that layout-in-response-to-resize
was always lagging behind the current size of the view.
The root of this problem was how Frame kept both a viewport rect
(with both scroll offset and size) and a frame size. To fix this,
only store the viewport scroll offset, and always use the frame size.
This way they can't get out of sync and the problem goes away. :^)
Fixes#4250.
Note that we're taking a shortcut here and returning the elements as an
Array instead of HTMLCollection. One day we'll have to bite the bullet
and deal with HTMLCollection, but not today.
Note that this is the old CSS2 syntax, we don't support the CSS3 syntax
just yet. Also we don't actually implement the pseudo-elements, this is
really just to make the selectors distinct from the same ones without
these pseudo-elements.
Proxy is an "exotic object" and doesn't have its own prototype. Use the
regular object prototype instead, but most stuff is happening on the
target object anyway. :^)
We were incorrectly hoisting non-inline children of inline-block boxes
to the nearest non-inline ancestor.
Since inline-block boxes are only inline on the *outside*, it's fine
for them to have non-inline children.
Eventually we should clarify these relationships by making the inside
and outside display types more explicit.
Instead of hiding JS exceptions raised on the web, we now print them to
the debug log. This will make it a bit easier to work out why some web
pages aren't working right. :^)
We didn't notice that the layout tree had disappeared after dispatching
a mousedown event, because we only checked EventHandler::layout_root()
which happily returned the *new* layout tree after a window.reload().
This patch fixes that by verifying that the frame is still showing the
same DOM's layout tree after event dispatch.
Fixes#4224.
We can now build partial layout trees (this happens for example when an
element's "display" property is programmatically toggled from "none" to
something else.)
We can't say that "no replaced boxes can have children", since that
breaks SVG. Instead, let each LayoutNode decide whether it's allowed
to have children.
Fixes#4223.
We were messing up the box tree for tables by hoisting cells up to
become children of the table row group (instead of the table row.)
Table rows are non-block boxes, and it's fine for them to have cell
(block) children.
Fixes#4225.
We already have a wrap() in EventWrapperFactory.cpp. It would be nice
to generate that at some point but it will require a lot more work on
the wrapper generator.