This commit adds some finagling and shrinking of the corner bitmap
to handle drawing shadows on elements where the shadow radius >
half the width or height of the element. Previously things would
go horribly wrong when this happend.
There could still be some edge cases, but things seem to be working
fairly well now.
This fixes a issue due to the background/border painting using
.to_rounded<int>() to get an IntRect, but shadow painting was using
enclosing_int_rect().
enclosing_int_rect() uses some floors/ceils and does not always match
.to_rounded<int>().
This now allows passing a 'fill_color' to the blur, any fully
transparent pixels will be replaced with this color (with the alpha
set to 0).
For box-shadows, if this color is set to the same as the shadow,
the issues around the fringes are fixed. This also fixes some places
where dark shadows appeared light / the wrong color.
With this change the blur no longer dominates the profile. On my PC
it is down to 27% (which is the same as the AA ellipse painting).
The box-shadow.html test page now also feels more responsive.
This commit adds support for using all your favorite border radii with
box-shadow, that is elliptical, circular, rounded rectangle etc. :^)
There is some work needed to make this more performant. The larger
your border radius is the larger the corner bitmap needs to be,
which means more time spent in FastBoxBlurFilter. There are probably
some tricks to bring this down.
Fixes#14325
Previously, this was slightly off and not doing what the spec comment
above asked for. This led to really small values for x_step and
y_step, making the `backgrounds.html' example use crazy amounts of
CPU whist painting.
This is a helper class for clipping the corners off a element.
This works in a similar way to how (outline) borders are painted.
The steps are:
1. A small bitmap that fits only the corners is allocated
2. The corners are painted into the bitmap
3. The existing pixels (where the corners will be painted)
are copied using the (inverse) corner bitmap as a mask
(done before the element is painted)
4. The element is painted
5. The areas outside the corner radii are restored
Like with the borders, this only requires allocation on the first
paint.
This commit reimplements the (normally) 45 degree (depends on
the widths) connection between to adjacent borders. Which is
needed to paint the 'caret' icon seen in a few buttons on GitHub.
The issue of overlapping pixels while painting this has also
been solved for the 45 degree case (the the most likely case,
the other cases only occur of mixed-with borders).
This commit adds some much nicer border painting, which now supports:
- Elliptical corners
- Blending between different border thicknesses, with rounded corners
- Anti-aliasing
There are some little TODOs left to tackle:
- Painting the corners with line styles other than solid
- Blending between colors on the corners (see comments)
The painting requires allocating a small bitmap, that only fits the
corners (so in most cases this is very small).
This bitmap is then cached so for all paints but the first there will
be no further allocations.
Since the layout_box of a SVGGraphicsPaintable is already casted to the
right type, the underlying dom_node was also always of the right type.
This triggers a warning on Lagom builds.
The spec grammar for `text-decoration-line` is:
`none | [ underline || overline || line-through || blink ]`
Which means that it's either `none`, or any combination of the other
values. This patch makes that parse for `text-decoration-line` and
`text-decoration`, stores the results as a Vector, and adjusts
`paint_text_decoration()` to run as a loop over all the values that are
provided.
As noted, storing a Vector of values is a bit wasteful, as they could be
stored as flags in a single `u8`. But I was getting too confused trying
to do that in a nice way.
Give the Paintable class some basic helpers for traversing the paint
tree. Note that they actually piggy-back on the layout tree for links
between nodes.
When cloning the PaintContext we should be using the painter backed by
the bitmap created for this stacking context layer.
Fixes: 54c3053bc3 ("LibWeb: Preserve paint state when painting...")
Previously the default was always 1px, which didn't look great on higher
font sizes.
This changes the default thickness to one-tenth to the font height. The
one-tenth part was chosen arbitrarily, but I think it does the job
pretty well. :^)
We now position inline-level boxes based on ascent and descent metrics
from the font in use. This makes our basic text layouts look a lot more
like those produced by other browsers. :^)
I've tried to match the terminology used by the CSS Inline Layout spec.
This will regress Acid2 a little bit, and probably various other sites,
but on the whole it's the direction we should be heading, so let's go.
This avoids a bunch of unnecessary work in Painter which not only took
time, but sometimes also led to alignment issues. draw_text_run() will
draw the text where we tell it, and that's it.
Preserve floating point precision and delay rounding until the last
moment when figuring out where to paint background layers. This fixes an
issue on Acid3 where a thin sliver of red was visible because the
background X position was incorrectly rounded by 1px.
By using enclosing_int_rect(), borders and backgrounds of boxes were
sometimes 1 pixel off, making things slightly larger than they should
be. Fix this by using to_rounded() instead of enclosing_int_rect().
There's definitely more of these type of issues lurking in the code,
and we'll get to them in time.
Relatively positioned boxes should not affect the *layout* of their
siblings. So instead of applying relative inset as a layout-time
translation on the box, we now perform the adjustment at the paintable
level instead.
This makes position:relative actually work as expected, and exposes some
new bugs we need to take care of for Acid2. :^)
For layers that require indirect painting (due to opacity, transform,
etc.) we create a nested PaintContext. Until now, that PaintContext
was created fresh without transferring all the state from the parent
PaintContext.
Instead of using the absolute_rect(), use absolute_border_box_rect() -
at least for PaintableBox - and inflate it by 2px on each side.
This looks much nicer for text input elements, especially when they have
padding, which would be applied outside the focus rect previously.
Rather than dividing the rect width and high by the border lengths,
this change multiples those lengths by the reciprocal of the width
and height because this is a faster operation. When mousing around on
the html spec website, the profile showed that inline painting
went from ~15% to ~3%
This fixes the placement of several background images on Acid2, most
notably the background of the eyes and the red rectangle near the bottom
of the head.
Normally, paintable coordinates are relative to the nearest containing
block, but in the SVG case, since <svg> doesn't form a containing block,
we have to specialize the computation of SVGPaintable::absolute_rect().
We don't yet take the spread-distance parameter into account, since we
don't have a way to "inflate" the text shadow.
Also, I'm not sure if we need to inflate the shadow slightly anyway.
Blurred shadows of our pixel fonts seem very faint. Part of this is
that a blur of < 3px does nothing, see #13231, but even so we might
want to inflate it a little.
The `text-shadow` property is almost identical to `box-shadow`:
> Values are interpreted as for box-shadow [CSS-BACKGROUNDS-3].
> (But note that the inset keyword are not allowed.)
So, let's use the same data structures and parsing code for both. :^)
This replaces the usage of `rounded_int_rect`, whose name did not
accurately reflect the rounding operation happening. For example, the
position of the rect was not rounded but floored, and the size was
pulled through `roundf` before casting to `int` which could result in
inadvertent flooring if the resulting floating point could not exactly
represent the rounded value.