Commit graph

104 commits

Author SHA1 Message Date
Valtteri Koskivuori
2c5a062c8f LibWeb: Teach CSS transformed StackingContexts about image-rendering
Previously, all StackingContexts which were scaled using CSS transforms
were hard-coded to use BilinearBlend. This fix maps specified
image-rendering properties to reasonable ScalingModes for painting.
2023-06-13 06:14:17 +02:00
Aliaksandr Kalenik
147c3b3d97 LibWeb+WebContent: Forbid access to underlying type of CSSPixels
Although DistinctNumeric, which is supposed to abstract the underlying
type, was used to represent CSSPixels, we have a whole bunch of places
in the layout code that assume CSSPixels::value() returns a
floating-point type. This assumption makes it difficult to replace the
underlying type in CSSPixels with a non-floating type.

To make it easier to transition CSSPixels to fixed-point math, one step
we can take is to prevent access to the underlying type using value()
and instead use explicit conversions with the to_float(), to_double(),
and to_int() methods.
2023-06-13 06:08:27 +02:00
Andreas Kling
d6c3cbd958 LibWeb: Make StackingContext sorting a lot faster
Stacking contexts are sorted after building a tree of them. They are
sorted by z-index first, DOM tree order second.

Sorting was previously *very* slow on pages with many stacking contexts.
That was because the sort() function used Node::is_before() in the
quick_sort comparator to see if one StackingContext was before another.
is_before() does tree traversal and can take quite a long time per call.

This patch avoids all that by letting StackingContext know its index
among all StackingContexts within the same document in tree order.
There's a noticeable snappiness increase on the CSS-FLEXBOX-1 spec page,
for instance. :^)
2023-06-02 15:00:38 +02:00
stelar7
421559d725 LibWeb: Change calc node representation from float to double 2023-05-31 10:56:32 +02:00
Andreas Kling
655d9d1462 LibWeb: Make CSSPixels and Length use 64-bit (double) floating point
This fixes a plethora of rounding problems on many websites.
In the future, we may want to replace this with fixed-point arithmetic
(bug #18566) for performance (and consistency with other engines),
but in the meantime this makes the web look a bit better. :^)

There's a lot more things that could be converted to doubles, which
would reduce the amount of casting necessary in this patch.
We can do that incrementally, however.
2023-05-24 14:40:35 +02:00
Andreas Kling
ca1fa5f748 LibWeb: Use the new to_px() helpers in CSS, SVG and layout code
There should be no behavior change from this, only slightly less
verbosity. :^)
2023-05-06 18:41:34 +02:00
Sam Atkins
d16600a48b LibWeb: Propagate errors from StyleValue construction
Turns out we create a lot of these, mostly from places that don't return
ErrorOr. The yak stack grows.
2023-05-06 08:07:28 +02:00
Linus Groh
36d35c9c82 LibWeb: Rename remaining paint_box variables to paintable_box
These don't match the type name, which is confusing.
2023-04-20 20:43:30 +02:00
Linus Groh
754e458d0a LibWeb/Layout: Rename Box::{paint => paintable}_box()
It returns a PaintableBox, not a 'PaintBox'.
2023-04-20 20:43:30 +02:00
Linus Groh
ec37b55777 LibWeb/Painting: Rename StackingContext::paintable{ => _box}()
It returns a PaintableBox, not any Paintable.
2023-04-20 20:43:30 +02:00
MacDue
d2fc8efd9e LibWeb: Make SC hit testing more closely follow reverse paint order
Previously, we would hit test positioned elements, then stacking
contexts with z-index 0, as two seperate steps. This did not really
follow the reverse paint order, where positioned elements and stacking
contexts with z-index 0 are painted during the same tree transversal.

This commit updates
for_each_in_subtree_of_type_within_same_stacking_context_in_reverse()
to return the stacking contexts it comes across too, but not recurse
into them. This more closely follows the paint order.

This fixes examples such as:

<div id="a" style="width: 10px; height: 10px">
  <div id="b" style="position: absolute; width: 10px; height: 10px">
    <div
     style="position: absolute; width: 10px; height: 10px; z-index: 0"
    >
      <div id="c"
           style="width: 100%; height: 100%; background-color:red;"
           onclick="alert('You Win!')">
      </div>
    </div>
  </div>
</div>

Where previously the onclick on #c would never fire as hit testing
always stopped at #b. This is reduced from Google Street View,
which becomes interactable after this commit.
2023-04-12 07:40:22 +02:00
Sam Atkins
7a1a97f153 LibWeb: Remove CalculatedStyleValue from Angle
...and replace it with AngleOrCalculated.

This has the nice bonus effect of actually handling `calc()` for angles
in a transform function. :^) (Previously we just would have asserted.)
2023-03-30 21:29:50 +02:00
Sam Atkins
cd06b1341b LibWeb: Split TransformationStyleValue out of StyleValue.{h,cpp} 2023-03-25 16:56:04 +00:00
Matthew Olsson
7c0c1c8f49 LibJS+LibWeb: Wrap raw JS::Cell*/& fields in GCPtr/NonnullGCPtr 2023-03-15 08:48:49 +01:00
Andreas Kling
7e76a51cb0 LibWeb: Rename Layout::InitialContainingBlock to Layout::Viewport
The name "initial containing block" was wrong for this, as it doesn't
correspond to the HTML element, and that's specifically what it's
supposed to do! :^)
2023-02-28 12:21:56 +01:00
Aliaksandr Kalenik
05b5a3bfba LibWeb: Transform translate() values to device pixels before painting 2023-02-19 00:43:40 +01:00
Aliaksandr Kalenik
2649bc737f LibWeb: Use device pixels for transform rect of stacking context 2023-02-10 15:38:54 +01:00
Aliaksandr Kalenik
08f217526a LibWeb: Use rect of containing block instead of parent to clip overflow
Move overflow clipping from `before_children_paint` into separate
method and call this method on containing block instead of parent.

Example that got fixed:
```html
<!DOCTYPE html><html><head><style>
    * {
      border: 2px solid black;
    }
    body {
      overflow: hidden;
    }
    .inner {
      position: absolute;
      width: 100px;
      height: 100px;
      background: lime;
    }
</style></head><body><div class=inner></div>
```
2023-01-25 10:44:58 +01:00
Andreas Kling
4d401bf796 LibWeb: Make the paint tree GC-allocated
This simplifies the ownership model between DOM/layout/paint nodes
immensely by deferring to the garbage collector for figuring out what's
live and what's not.
2023-01-11 12:55:00 +01:00
martinfalisse
ce0f41b9fb LibWeb+WebContent: Use new String class in CSS::StyleValue
Converts uses of DeprecatedString to String in StyleValue, and patches
surrounding files that depend on these functions.
2023-01-09 11:09:31 +01:00
Sam Atkins
8cc0bdf777 LibWeb: Resolve Lengths to CSSPixels 2023-01-05 17:42:31 +01:00
Sam Atkins
ab49dbf137 LibWeb: Convert Paintable coordinates to new pixel units
This fixes a few sizing issues too. The page size is now correct in most
cases! \o/

We get to remove some of the `to_type<>()` shenanigans, though it
reappears in some other places.
2022-12-14 16:47:57 +00:00
Sam Atkins
3c7bd5a317 LibWeb+WebContent+headless-browser: Use CSSPixels for PageClient events
...and also for hit testing, which is involved in most of them.

Much of this is temporary conversions and other awkwardness, which
should resolve itself as the rest of LibWeb is converted to these new
types. Hopefully. :thousandyakstare:
2022-12-10 12:03:19 +00:00
Luke Wilde
2b55ccf6e5 LibWeb: Actually hit-test child stacking contents with z-index of 0
Discord modals/pop-outs are in a "layerContainer" <div> with
`z-index: 1002`, which then has an immediate child <div> called
"positionLayer" with `z-index: 0`. We only ever hit test child stacking
contexts with z-index set to anything but 0 (step 7 and step 1 of the
hit test), but not for exactly 0 (step 6). This made it impossible to
hit any element inside positionLayer, making pop-ups such as the emojis
and GIFs unusable.
2022-12-10 00:21:10 +00:00
MacDue
e011eafd37 Meta+Userland: Pass Gfx::FloatPoint by value
Just a small 8-byte value like Gfx::IntPoint.
2022-12-07 11:48:27 +01:00
Linus Groh
57dc179b1f Everywhere: Rename to_{string => deprecated_string}() where applicable
This will make it easier to support both string types at the same time
while we convert code, and tracking down remaining uses.

One big exception is Value::to_string() in LibJS, where the name is
dictated by the ToString AO.
2022-12-06 08:54:33 +01:00
Aliaksandr Kalenik
adf0262b54 LubWeb: Call before_children_paint for positioned descendants
Add before_children_paint and after_children_paint calls for
positioned descendants with z-index: auto during painting
2022-11-15 22:53:47 +01:00
Aliaksandr Kalenik
f3d57e1157 LibWeb: Clip hidden overflow by absolute rect of containing block
Since handling overflow: hidden in PaintableBox::before_children_paint
while following paint traversal order can't result in correctly computed
clip rectangle for elements that create their own stacking context
(because before_children_paint is called only for parent but overflow:
hidden can be set somewhere deeper but not in direct ancestor), here
introduced new function PaintableBox::clip_rect() that computes clip
rectangle by looking into containing block.

should_clip_overflow flag that disables clip for absolutely positioned
elements in before_children_paint and after_children_paint is removed
because after changing clip rectangle to be computed from not parent
but containing block it is not needed anymore (absolutely positioned
item is clipped if it's containing block has hidden overflow)
2022-11-15 22:53:47 +01:00
Andreas Kling
5aeb6fec68 LibWeb: Make hit testing traverse positioned descendants in right order
We were doing a forward traversal in hit testing which led to sometimes
incorrect results when multiple boxes were occupying the same X and Y
coordinate.
2022-11-04 10:38:00 +01:00
Aliaksandr Kalenik
e4db71c88b LibWeb: Support translate3d 2022-11-02 11:04:23 +00:00
Andreas Kling
8aab33de5f LibWeb: Skip positioned children in paint_descendants()
Positioned descendants are now handled entirely by paint_internal()
so we can just skip over positioned children in paint_descendants().
This avoids drawing the same boxes multiple times.
2022-10-23 23:32:42 +02:00
Andreas Kling
8bf0e71c0c LibWeb: Paint non-positioned stacking contexts with z-index 0 or auto
As I understand it, these have to be painted interleaved with positioned
descendants in the same z-index category, in tree order.
2022-10-23 23:32:42 +02:00
Andreas Kling
447519f678 LibWeb: Paint positioned descendants with z-index: auto
This "worked" before because all positioned elements would create their
own stacking context. When we stopped doing this, there was nobody to
actually paint positioned descendants with `z-index: auto`.

This patch splits up steps 8 and 9 of the paint order algorithm and
implements step 8 as a paint tree traversal. There's more to step 8 than
I've implemented here, so I've left a FIXME for our future selves.
2022-10-23 23:32:42 +02:00
Andreas Kling
8a0e40c5b0 LibWeb: Update StackingContext::paint_descendants() for new rule
Since positioned elements no longer automatically create stacking
contexts, we can't rely on this assumption when painting descendants of
a stacking context.

In this commit, we fix an issue that manifested as a failure to
Gfx::Painter::restore() in the "Overlay" paint phase. What happened was
that a CSS clip was being applied in the "Background" paint phase, and
then unapplied in the "Overlay" phase. Due to bogus checks in
paint_descendants(), the "Background" phase never ran for positioned
elements, but the "Overlay" phase did.

The check for positioned elements was bogus in the first place and had
never actually worked before, since we would always skip over positioned
descendants due to them having stacking contexts.
2022-10-23 23:32:42 +02:00
Andreas Kling
055a1998c1 LibWeb: StackingContext::paint_descendants() can take const layout node
It doesn't mutate the layout tree in any way.
2022-10-23 23:32:42 +02:00
Aliaksandr Kalenik
66e424a084 LibWeb: Fix pointer-events check in hit_test 2022-10-20 17:58:16 +02:00
Aliaksandr Kalenik
dfc3a4772b LibWeb: Ignore "pointer-events: none" elements in hit_test 2022-10-19 16:11:15 +02:00
Andreas Kling
90b66533d0 LibWeb: Don't hit test all child stacking contexts twice
We're supposed to hit test positive z-index stacking contexts first,
and negative z-index stacking contexts later. Instead, we were hit
testing all stacking contexts both times.

This made hit testing unbearably slow on some websites.

While we're here, also add an extra comment about why stacking contexts
are traversed in reverse order. It tripped me up while looking at this,
so I'm sure it could trip someone else up too.

Regressed in 44057c9482.
2022-10-07 12:10:59 +02:00
Andreas Kling
95a3da86c3 LibWeb: Reset painter translation when painting fixed-position elements
This makes nested position:fixed elements work, previously we'd apply
the viewport scroll offset once at every nesting level.
2022-10-02 21:14:02 +02:00
Hendiadyoin1
e68309144b LibWeb: Don't scale by x, x when a scale x, y is provided as a transform 2022-10-01 21:08:50 +01:00
Luke Wilde
dbe12662b8 LibWeb: Implement matrix3d transform function from css-transforms-2 2022-10-01 14:07:47 +02:00
Luke Wilde
0fdd924db2 LibWeb: Implement rotation transform functions from css-transforms-2 2022-10-01 14:07:47 +02:00
Andreas Kling
b7f9387f69 LibWeb: Don't draw only-translated stacking contexts via bitmap
If the 2D transform in effect is just a simple translation, we don't
need to draw into a temporary bitmap and then transform it. We can
just translate the painter. :^)
2022-09-29 20:10:02 +02:00
MacDue
f6264523b9 LibWeb: Fix destination bitmap edge clip case in transform painting
This fixes an edge case, where the destination rect falls partly
outside the painter, so is clipped to a smaller size in
`get_region_bitmap()` (which needs to be accounted for with an extra
offset).
2022-09-26 01:38:30 +02:00
MacDue
3fad64dfbc LibWeb: Sample the destination when painting element opacity/transform
This now copies the area under the destination to a new bitmap, that
is then scaled to the size of the source. The element is then painted
into that bitmap, which is then scaled and painted back to
the destination. This is done as many effects such as shadows, border
radii, filters, etc require being able to read pixels from the painter.

This does work (and is not that noticeable in many cases), but it does
mean there may be a few scaling artifacts in the background
around transformed elements. Though that was already the case before
anyway for the elements (since it is just a bitmap scale).

What we really want is to (where possible) just scale the paintable
and its descendants, then paint things normally, which would give
much nicer results (but is much more tricky to achieve).

This also now makes it so only a bitmap of the size of the paintable is
copied/created, rather than the whole page.
2022-09-25 18:37:31 +02:00
Andreas Kling
5c6621547c LibWeb: Compute StackingContext transform origin only once
When mousing over twitter, 17% of time was spent computing stacking
context transform origins. Since this never changes after the stacking
context is created, we can cache it and avoid all that work.
2022-09-24 23:06:09 +02:00
MacDue
c3841e1667 LibWeb: Restore clipping of positioned descendants
63c727a was meant to stop clipping absolutely positioned descendants,
but used `is_positioned()` rather than `is_absolutely_positioned()`,
which meant it disabled clipping in many more cases that it should
have.
2022-09-24 19:06:57 +02:00
Brian Gianforcaro
d0a1775369 Everywhere: Fix a variety of typos
Spelling fixes found by `codespell`.
2022-09-14 04:46:49 +00:00
Andreas Kling
63c727a4a3 LibWeb: Don't clip to containing block when painting abspos descendants 2022-09-14 00:09:49 +02:00
Sam Atkins
75e0b21940 LibWeb: Store calculated transformation matrix on the StackingContext
This is mainly so we can easily read that matrix later, but also has the
benefit of only calculating the matrix once, instead of every time we
paint. :^)
2022-07-21 16:36:08 +02:00