1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-18 21:35:06 +00:00
Commit graph

584 commits

Author SHA1 Message Date
Andreas Kling
8d5768b103 LibWeb: Don't treat inline-level children of flex items as whitespace
This was causing us to collapse some children of flex items as if they
were useless whitespace text nodes.
2022-03-19 12:42:10 +01:00
Andreas Kling
28b771560a LibWeb: Make SVG <svg> elements behave as CSS replaced elements
This makes SVG-in-HTML behave quite a bit better by following general
replaced layout rules. It also turns <svg> elements into inline-level
boxes instead of block-level boxes.
2022-03-19 12:42:10 +01:00
Andreas Kling
a19b9b727d LibWeb: Place right-side floats relative to their containing block
We were incorrectly placing them relative to the BFC root, but CSS2
says they are relative to their own containing block.
2022-03-18 19:28:58 +01:00
Simon Wanner
a2331e8dd3 LibWeb: Implement CSS transforms on stacking contexts
Since there is currently no easy way to handle rotations and skews
with LibGfx this only implements translation and scaling by first
constructing a general 4x4 transformation matrix like outlined in
the css-transforms-1 specification. This is then downgraded to a
Gfx::AffineTransform in order to transform the destination rectangle
used with draw_scaled_bitmap()

While rotation would be nice this already looks pretty good :^)
2022-03-18 18:51:42 +01:00
Simon Wanner
7c79fc209f LibWeb: Establish a new stacking context for elements with transform 2022-03-18 18:51:42 +01:00
Andreas Kling
39b7fbfeb9 LibWeb: Rewrite CSS float implementation to use offset-from-edge
The previous implementation used relative X offsets for both left and
right-side floats. This made right-side floats super awkward, since we
could only determine their X position once the width of the BFC root was
known, and for BFC roots with automatic width, this was not even working
at all most of the time.

This patch changes the way we deal with floats so that BFC keeps track
of the offset-from-edge for each float. The offset is the distance from
the BFC root edge (left or right, depending on float direction) to the
"innermost" margin edge of the floating box.

Floating box are now laid out in two passes: while going through the
normal flow layout, we put floats in their *static* position (i.e the
position they would have occupied if they weren't floating) and then
update the Y position value to the final one.

The second pass occurs later on, when the BFC root has had its width
assigned by the parent context. Once we know the root width, we can
set the X position value of floating boxes. (Because the X position of
right-side floats is relative to the right edge of the BFC root.)
2022-03-18 15:18:48 +01:00
Andreas Kling
28642de6ed LibWeb: Make LineBuilder aware of the current LayoutMode
This will allow us to override the available space correctly when doing
intrinsic sizing.
2022-03-18 15:18:48 +01:00
Andreas Kling
915ee66bd6 LibWeb: Implement shrink-to-fit layout on top of intrinsic size cache
Using the intrinsic size cache means we only perform the nested layout
to determine intrinsic size *once* per root layout pass.

Furthermore, by using a throwaway FormattingState, details of the nested
layout can't leak into and mutate the outer layout.
2022-03-18 15:18:48 +01:00
Andreas Kling
39ca39204b LibWeb: Cache intrinsic sizes on the root FormattingState
Instead of caching them with the current state, we can cache them at the
root of the state tree. Since intrinsic sizes are immutable during the
same layout, this allows layout to take advantage of intrinsic sizes
discovered during nested layout (and avoids a *lot* of duplicate work.)
2022-03-18 15:18:48 +01:00
Andreas Kling
d3932b5880 LibWeb: Give FormattingState a reference to its root state
FormattingStates can have parents, in case we're performing nested
layouts to determine something's intrinsic size. In those cases, it will
soon be useful to find the outermost (root) state.
2022-03-18 15:18:48 +01:00
Andreas Kling
60c781ebc7 LibWeb: Simplify Layout::Node::containing_block()
Use first_ancestor_of_type<BlockContainer>() instead of implementing a
custom traversal lambda.
2022-03-18 15:18:48 +01:00
Andreas Kling
ef8a72ff3f LibWeb: Move available_space_for_line() from IFC to BFC
This is preparation for allowing blocks with their own internal BFC to
flow around floating boxes in the parent BFC.

Note that IFC still has the available_space_for_line() API, which
returns space available within the IFC's own containing block, while the
BFC available_space_for_line() returns space available within its root.
2022-03-18 15:18:48 +01:00
Lenny Maiorani
c37820b898 Libraries: Use default constructors/destructors in LibWeb
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#cother-other-default-operation-rules

"The compiler is more likely to get the default semantics right and
you cannot implement these functions better than the compiler."
2022-03-17 17:23:49 +00:00
Andreas Kling
be5f0b5ac4 LibWeb: Move text fragment painting to PaintableWithLines
All the other painting code has moved to paintables already.
2022-03-16 23:13:05 +01:00
sin-ack
29583104d2 LibWeb: Refactor all LabelableNode subclasses + input event handling :^)
This commit is messy due to the Paintable and Layout classes being
tangled together.

The RadioButton, CheckBox and ButtonBox classes are now subclasses of
FormAssociatedLabelableNode. This subclass separates these layout nodes
from LabelableNode, which is also the superclass of non-form associated
labelable nodes (Progress).

ButtonPaintable, CheckBoxPaintable and RadioButtonPaintable no longer
call events on DOM nodes directly from their mouse event handlers;
instead, all the functionality is now directly in EventHandler, which
dispatches the related events. handle_mousedown and related methods
return a bool indicating whether the event handling should proceed.

Paintable classes can now return an alternative DOM::Node which should
be the target of the mouse event. Labels use this to indicate that the
labeled control should be the target of the mouse events.

HTMLInputElement put its activation behavior on run_activation_behavior,
which wasn't actually called anywhere and had to be manually called by
other places. We now use activation_behavior which is used by
EventDispatcher.

This commit also brings HTMLInputElement closer to spec by removing the
did_foo functions that did ad-hoc event dispatching and unifies the
behavior under run_input_activation_behavior.
2022-03-16 00:38:31 +01:00
Andreas Kling
b8ee4dfda8 LibWeb: Don't compute style *again* for elements in Layout::TreeBuilder
TreeBuilder wasn't taking advantage of the fact that we already have
computed style cached on each DOM::Element by the time we're
constructing a layout tree.

So instead of using the cached style, we recomputed it from scratch for
every element. This was done because invalidation was broken in many
places, but now that it's more or less trustworthy, stop recomputing
style on the fly in TreeBuilder and use what the preceding style update
pass gave us instead.

This basically cuts style computation work in half. :^)
2022-03-15 22:43:44 +01:00
Andreas Kling
e31fe3eeb8 LibWeb: Rename Element::specified_css_values() => computed_css_values()
Let's make it very clear that these are *computed* values, and not at
all the specified values. The specified values are currently discarded
by the CSS cascade algorithm.
2022-03-15 19:48:19 +01:00
Andreas Kling
72e6bff8b8 LibWeb: Remove unused code for constructing partial layout trees
We only ever build the whole layout tree in one go. Maybe one day we'll
support partial rebuilds, but for now, let's keep things simple.
2022-03-15 19:48:19 +01:00
Brian Gianforcaro
af50895fa3 LibWeb: Fix height/width copy paste bug in SVGFormattingContext::run
This was found by SonarCloud:
- Identical sub-expressions on both sides of operator "&&".
2022-03-14 22:30:22 +01:00
Andreas Kling
afc5fade05 LibWeb: Add some fast_is<T> helpers for hot classes on GitHub :^) 2022-03-13 18:09:43 +01:00
Andreas Kling
f5c2e87965 LibWeb: Sort stacking context tree once, after fully building it
Instead of calling quick_sort() every time a StackingContext child
is added to a parent, we now do a single pass of sorting work after the
full StackingContext tree has been built.

Before this change, the quick_sort() was ~13.5% of the profile while
hovering links on GitHub in the Browser. After the change, it's down to
~0.6%. Pretty good! :^)
2022-03-13 18:09:43 +01:00
Andreas Kling
ab9d9709b9 LibWeb: Give flex containers with percentage cross size some dimensions
Instead of making them zero-sized on the cross axis, just treat
percentage sizes like auto for now. Better to have *some* size than none
at all.
2022-03-13 00:04:51 +01:00
Andreas Kling
bd94f2c4c8 LibWeb: Add a debug helper to dump current state of an FFC 2022-03-13 00:04:51 +01:00
Andreas Kling
ad8d65fd6e LibWeb: Fix calculation of hypothetical cross size in column flex layout
Simplify automatic cross sizing of items in flex-direction:column by
using the fit-content width directly.

There's obviously a lot more nuance to this, but for now this makes
flex items with both width:auto and height:auto actually get some height
in column flex layouts.
2022-03-13 00:04:51 +01:00
Andreas Kling
2f3d7a7c36 LibWeb: Swap min-content and max-content intrinsic sizes if needed
I'm a little confused about intrinsic heights *really* work, and I'm
struggling to extract that information from the spec. In the meantime,
let's ensure that min-content is always smaller than (or equal to)
max-content so that other math works as expected.
2022-03-13 00:04:51 +01:00
Andreas Kling
515db5fc1b LibWeb: Make Layout::FormattingState copies shallow
Previously, each NodeState in a FormattingState was shared with the
parent FormattingState, but the HashMap of NodeState had to be copied
when making FormattingState copies.

This patch makes copying instant by keeping a pointer to the parent
FormattingState instead. When fetching immutable state via get(), we may
now return a reference to a NodeState owned by a parent FormattingState.

get_mutable() will copy any NodeState found in the ancestor chain before
making a brand new one.
2022-03-13 00:04:51 +01:00
Andreas Kling
8c91e8016c LibWeb: Handle many more cases with intrinsic/auto sizing in flex layout
The flexbox specification barely even handwaves about automatically
sized items, but there's actually a lot of work to do in order for them
to get the correct size.

This patch is messy, but does make significant progress on supporting
flex items with indefinite width and/or height.

There's a fair amount of nested layout going on here, but do note that
we'll be hitting the intrinsic sizes cache whenever possible.
2022-03-13 00:04:51 +01:00
Andreas Kling
3f2b17f602 LibWeb: Add functions for calculating intrinsic sizes of a Layout::Box
FormattingContext can now calculate the intrinsic sizes (min-content and
max-content in both axes) for a given Layout::Box.

This is a rather expensive operation, as it necessitates performing two
throwaway layouts of the subtree rooted at the box. Fortunately, we can
cache the results of these calculations, as intrinsic sizes don't change
based on other context around the box. They are intrinsic after all. :^)
2022-03-13 00:04:51 +01:00
Andreas Kling
aa969cc591 LibWeb: Make Layout::SVGBox a BlockContainer again
This wasn't worth the headache of trying to make SVG boxes work together
with BFC right now. Let's just make it a block container once again, and
have its corresponding SVGPaintable inherit from PaintableWithLines.

We'll have to revisit this as SVG support improves.
2022-03-13 00:04:51 +01:00
Andreas Kling
e4eb6d4f1f LibWeb: Add FFC helpers for resolving definite main/cross sizes
Although something has a definite size, we may still have to "resolve"
it, since FFC is quite liberal in what it considers to be definite.

Let's put that logic in a set of helper functions.
2022-03-13 00:04:51 +01:00
Andreas Kling
5c8e7217f7 LibWeb: Remove ad-hoc setup step from FFC layout algorithm
This step will not be necessary when we implement indefinite size
calculations more correctly.
2022-03-13 00:04:51 +01:00
Andreas Kling
12ac6861e3 LibWeb: Improve how layout nodes decide whether they have definite sizes
1. Make this decision *after* we've inserted the layout node into the
   layout tree. Otherwise, we can't reach its containing block!
2. Per css-sizing-3, consider auto-sized blocks whose sizes resolve
   solely against other definite sizes as definite themselves.

In particular, (2) makes us consider width:auto block children of a
definite-size containing block as having definite size. This becomes
very important in flex layout.
2022-03-13 00:04:51 +01:00
Andreas Kling
6de10858b9 LibWeb: Only collapse vertical margin between BlockContainer siblings
If there's some non-block-level box (like an SVG element of some kind)
between to blocks, just skip over the non-block for purposes of margin
collapsing. This is basically a hack, and something we'll need to
improve as part of our general SVG support.
2022-03-13 00:04:51 +01:00
Andreas Kling
43b8f65d82 LibWeb: Support indefinite flex container cross sizes
Instead of assuming that any indefinite cross size must be "auto", check
what is actually is, and resolve it accordingly.
2022-03-13 00:04:51 +01:00
Andreas Kling
a3a10b2379 LibWeb: Fix flex line alignment in single-line flex containers
For single-line flex containers, center the only flex line along the
cross axis. Alignment of multi-line flex containers are left as a FIXME.

This patch also moves out the assignment of final metrics to the
FormattingState from align_all_flex_lines() to a separate function.
2022-03-13 00:04:51 +01:00
Andreas Kling
1dfb3d555c LibWeb: Remove FFC::cross_size_is_absolute_or_resolved_nicely()
This is now answered authoritatively by Layout::Box itself.
2022-03-13 00:04:51 +01:00
Andreas Kling
1ce1af5d8b LibWeb: Improve FFC step 7 (hypothetical cross size)
- Avoid performing inside layout on definite-size flex items (since
  their computed size can be used as-is.)

- Use FormattingState::clone() to generate a throwaway layout instead of
  mutating the tree in-place.

- Update spec link & comments based on current CSSWG draft. The latest
  version is quite a bit clearer on how this should work.
2022-03-13 00:04:51 +01:00
Andreas Kling
b904bff838 LibWeb: Put available space information in an FFC member
This makes it easier for each step of the flex layout algorithm to
access this information.
2022-03-13 00:04:51 +01:00
Andreas Kling
88302b0dca LibWeb: Layout inside of flex items at the end of FFC layout
Instead of doing internal child layout incrementally as we go, save it
for the end of flex layout. The code will become simpler if we can focus
on simply computing the dimensions of each flex item while we're doing
the main FFC algorithm.
2022-03-13 00:04:51 +01:00
Andreas Kling
7c5b578df9 LibWeb: Move unrelated things out of FFC step 1
Setting some initial width and height on the flex container is totally
unrelated to the "generate anonymous flex items" step.
2022-03-13 00:04:51 +01:00
Andreas Kling
3506a91349 LibWeb: Avoid unnecessary layout_inside() in FFC step 1
We don't need to perform inside layout here. The only information we
need in this step is whether an anonymous block container has nothing
but empty-or-whitespace text children.

This information is already accurate after the initial layout tree
construction. Performing a layout does not change the answer. It does
however have many other side effects, so let's defer those.
2022-03-13 00:04:51 +01:00
sin-ack
b801ddf73d LibWeb: Apply the current text-justify value when justifying
This implements at least some of the specification. inter-character is
not yet handled. However as our current algorithm only considers
whitespace as word breaks, inter-word could technically be considered to
be handled. :^)
2022-03-12 21:51:38 +01:00
sin-ack
0679eadd62 LibWeb: Add support for the text-justify property
This commit adds the text-justify property as defined in:
https://drafts.csswg.org/css-text/#propdef-text-justify
2022-03-12 21:51:38 +01:00
sin-ack
7fe3f2d970 LibWeb: Refactor text justification code + only justify below threshold
All the justification-related code is now in
InlineFormattingContext::apply_justification_to_fragments and is
performed after all the line boxes have been added.

Text justification now only happens on the last line if the excess space
including whitespace is below a certain threshold. 10% seemed reasonable
since it prevents the "over-justification" of text. Note that fragments
in line boxes before the last one are always justified.
2022-03-12 21:51:38 +01:00
Andreas Kling
e099960e4d LibWeb: Remove a bunch of no-longer needed #includes 2022-03-11 00:21:49 +01:00
Andreas Kling
5779a910e5 LibWeb: Move hit testing to the painting tree 2022-03-11 00:21:49 +01:00
Andreas Kling
ba606d9057 LibWeb: Move PaintingBox to its own .cpp and .h files 2022-03-11 00:21:49 +01:00
Andreas Kling
f017c1c064 LibWeb: Make hit testing return a { paintable, offset }
Everything related to hit testing is better off using the painting tree.
The thing being mousemoved over is a paintable, so let's hand that out
directly instead of the corresponding layout node.
2022-03-11 00:21:49 +01:00
Andreas Kling
cb0c5390ff LibWeb: Move mouse event and label logic from layout to painting tree
Input events have nothing to do with layout, so let's not send them to
layout nodes.

The job of Paintable starts to become clear. It represents a paintable
item that can be rendered into the viewport, which means it can also
be targeted by the mouse cursor.
2022-03-11 00:21:49 +01:00
Andreas Kling
ed84fbce47 LibWeb: Make Paintable ref-counted
This will allow us to use a protective NonnullRefPtr to keep paintables
alive while running arbitrary JavaScript in response to events.
2022-03-11 00:21:49 +01:00