Previously gradient painting was dominated by the clipping checks in
Painter::set_pixel(). This commit changes gradient painting to use the
new Painter::fill_pixels() function (which does all these checks outside
the hot loop).
With this change gradient painting drops from 96% of the profile to 51%
when scrolling around on gradients.html. A nice 45% reduction :^)
Previously we were doing this at the painting stage, which meant that
layout potentially used the wrong glyphs when measuring text.
This would lead to incorrect layout metrics and was visible on the
HTML5Test score display, for example. :^)
This was wrong twice making it right... But let's fix that.
The center was being passed as a DevicePixelPoint, but was in fact in
CSS pixels, the size was passed as a Gfx::FloatSize but was in
CSS pixels again. Then we were scaling from device pixels to CSS pixels
when painting which does not need to be done if everything is passed
which the correct scale factors already applied.
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.
Store the ratio between device and CSS pixels on the PaintContext, so
that it can convert between the two.
Co-authored-by: MacDue <macdue@dueutil.tech>
The indexes are into the _node_, not in the fragment, so when a node is
split into multiple fragments, simply taking the length of the fragment
is incorrect. This patch corrects this mistake.
...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:
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.
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.
This fixes a rendering issue where box-shadows would not appear or
render completely broken if the blur radius was larger than the
border radius (border-radius < 2 * blur-radius to be exact).
When starting to drag the cursor below the text, we would start the
selection from the closest point in the line above in the last
fragment. This is not the behavior seen in other browsers, and it
causes weird behavior when the cursor is to the left of the last
fragment, for instances when trying to select with the text
`before <span>middle</span> after`.
By starting the selection from the _end_ of the last fragment,
including the line end character, selection behavior is similar to
that of other browsers.
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)
The container appears to be null for certain elements such as the
"update your browser" box when clicking on the document during certain
parts of loading. Skipping it works fine, but should obviously be
fixed, so it prints a debug output when this happens.
This makes the center position the center of the pixel rather than
the top left corner (which fixes some small artifacts on a few
gradients).
This also now floors the angle used to sample from the gradient line,
this avoids the colors diverging the further away from the center you
get (which is noticeable on hard-edge gradients).
This commit tweaks gradients so resolve_color_stop_positions() no
longer cares about the actual length of the gradient. All stops
are resolved to relative positions along the gradient line
(between 0 and 1), and are only scaled back to pixels (if required)
during the actual painting.
This has no immediate benefit right now, but it might make using
CSS pixels for gradients easier :^)
This also includes some mild refactoring.
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.