We don't need intrinsic scale factors for Gfx::Bitmap in Ladybird,
as everything flows through the CSS / device pixel ratio mechanism.
This patch also removes various unused functions instead of adapting
them to the change.
This is an implementation of the scanline edge-flag algorithm for
antialiased path filling described here:
https://mlab.taik.fi/~kkallio/antialiasing/EdgeFlagAA.pdf
The initial implementation does not try to implement every possible
optimization in favour of keeping things simple. However, it does
support:
- Both evenodd and nonzero fill rules
- Applying paint styles/gradients
- A range of samples per pixel (8, 16, 32)
- Very nice antialiasing :^)
This replaces the previous path filling code, that only really applied
antialiasing in the x-axis.
There's some very nice improvements around the web with this change,
especially for small icons. Strokes are still a bit wonky, as they don't
yet use this rasterizer, but I think it should be possible to convert
them to do so.
Previously, calling `.right()` on a `Gfx::Rect` would return the last
column's coordinate still inside the rectangle, or `left + width - 1`.
This is called 'endpoint inclusive' and does not make a lot of sense for
`Gfx::Rect<float>` where a rectangle of width 5 at position (0, 0) would
return 4 as its right side. This same problem exists for `.bottom()`.
This changes `Gfx::Rect` to be endpoint exclusive, which gives us the
nice property that `width = right - left` and `height = bottom - top`.
It enables us to treat `Gfx::Rect<int>` and `Gfx::Rect<float>` exactly
the same.
All users of `Gfx::Rect` have been updated accordingly.
"The official project language is American English […]."
5d2e915623/CONTRIBUTING.md (L30)
Here's a short statistic of the occurrences of the word "behavio(u)r":
$ git grep -IPioh 'behaviou?r' | sort | uniq -c | sort -n
2 BEHAVIOR
24 Behaviour
32 behaviour
407 Behavior
992 behavior
Therefore, it is clear that "behaviour" (56 occurrences) should be
regarded a typo, and "behavior" (1401 occurrences) should be preferred.
Note that The occurrences in LibJS are intentionally NOT changed,
because there are taken verbatim from the specification. Hence:
$ git grep -IPioh 'behaviou?r' | sort | uniq -c | sort -n
2 BEHAVIOR
10 behaviour
24 Behaviour
407 Behavior
1014 behavior
This makes all the code for fill_path() member functions of the painter,
and moves them into a new FillPathImplementation.cpp. This allows us
to avoid polluting Painter.h with implementation details, and makes
the edit, compile, retry loop much shorter.
This improves fill_path() performance by adding an API to the painter
that allows painting an entire scanline rather than just a pixel.
With this paths can be clipped a scanline at a time rather than each
pixel, removing a fair amount of checks.
Along with optimized clipping, this can now use a fast_u32_fill() to
paint all but the subpixels of a scanline if a solid color with no
alpha channel is used (which is quite common in SVGs).
This reduces scrolling around on svg.html from 21% in set_pixel() and
19% in fill_path() to just 7.8% in fill_path (with set_pixel()
eliminated). Now fill_path() is far from the slowest code when
scrolling the page.
This class had slightly confusing semantics and the added weirdness
doesn't seem worth it just so we can say "." instead of "->" when
iterating over a vector of NNRPs.
This patch replaces NonnullRefPtrVector<T> with Vector<NNRP<T>>.
The initial signs were wrong for the deltas of f(x), the ellipse
equation. This seemed to be fine for larger circles/ellipses but
broke things at a small scale, this was previously fixed with a
horrible "error = error / 4" hack. With this change, all ellipses
look a little better :^)
This also fixed a signed integer overflow Andreas found with UBSAN,
which happened for circles with a 1px radius.
This means fill_path() now paints the scanlines its self rather than
calling draw_line() which easily allows each pixel along the scanline
to have a different color.
Without this change, the upcoming LibWeb pixel types will require a
silly doubled conversion in some places.
eg: `some_rect.to_type<int>().to_type<float>()`
With these overloads, we can get away with `some_rect.to_type<int>()`.
Turns out most things expect lines to include the endpoint,
e.g. 0,0 -> 3,0 is a 4px long line. But the fill_path() implementation
seems to expect the line to be the distance between the two points
(so the above example is a 3px line instead).
This now adds an option to pick between PointToPoint line length or
Distance line length and uses the latter for fill_path().
m_rotated_rectangle_path was unused and m_intersection_edge_path was
cleared/free'd each time it was used. So sticking in the class just
bloats the size.
The main fix is stopping fill_path() scanlines being rounded to the
wrong pixel. The y-value is now floored to ensure it always snaps
in the same direction.
draw_line_for_path() is the same as the standard antialiased
draw_line() but with a few few small hacks to improve the look of
paths.
AntiAliasPolicy is also removed as it's now unused.
This is not any 'proper' algorithm, this was just a shower thought
idea. There probably is a better algorithm to achieve the same effect
out there, if someone knows of one please replace this code :^).
This works by rendering the line a scanline at a time, which avoids
repainting over any pixel on the line (so opacity now works with AA
lines). This generally seems to achieve a much nicer looking line.
I've not done any proper benchmarking of this, but some little messing
around showed that this new implementation was a little faster than
the old one too, so that's a nice little bonus.
With the inclusion of a few minor hacks this also goes a surprisingly
far way in improving our SVG rendering too (for both filled and stroked
paths). :^)
This patch optimizes the drawing of aa-lines by rotating the drawn
rectangle to the direction where the line points. That enables us to
draw non-straight lines with the proper width.
If a aa-line is drawn that is infact a straigt line we now dont plot
those lines with multipe rectangles across the line - insted we draw
straight lines in one go with just one rectangle of proper size.
Stroking of lines has been enhanced to take care of the edges between
two lines with drawing the stroke till the intersections of two
connected lines.
Doesn't use them in libc headers so that those don't have to pull in
AK/Platform.h.
AK_COMPILER_GCC is set _only_ for gcc, not for clang too. (__GNUC__ is
defined in clang builds as well.) Using AK_COMPILER_GCC simplifies
things some.
AK_COMPILER_CLANG isn't as much of a win, other than that it's
consistent with AK_COMPILER_GCC.
This adds simple dotted lines (horizontal/vertical only for now).
There's a little number fudging added in to make sure the final
dot is always drawn at the endpoint (for lines with at least a
handful of dots).
It's a common pattern on the web to draw a circle/ellipse by setting
the border-radius to 50%. Previously the painter would do a lot of
extra work painting and clipping each corner, this now detects that
case and replaces it with a single call to fill_ellipse().
The issue mentioned in the previous FIXME also applied to circles,
I just had not noticed. This is still not a prefect fix rather it
just papers over it, but it now seems to render circles correctly.
This is a first pass at antialiased outline ellipses, currently
this is done by painting two filled AA ellipses, and then
subtracting the inner ellipse from the outer.
This produces a good result, but unfortunately requires allocating
a temporary bitmap in the painter. I did try a simpler method
using the existing line painting functions, and drawing the
ellipse as many line segments, but that produced very poor results.
I think with some work it should be possible to remove the extra
allocation, and I've left a big FIXME for this, but I could not
get this working well.