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.
We were performing a check whether source pixels would fall into a
clipped rect too early. Since we already clamp the resulting source
coordinates to the clipped rect, we can just remove this code.
Box sampling is a scaling algorithm that averages all the pixels that
form the source for the target pixel. For example, if you would resize a
9x9 image to 3x3, each target pixel would encompass a 3x3 pixel area in
the source image.
Box sampling is a near perfect scaling algorithm for downscaling. When
upscaling with this algorithm, the result is similar to nearest neighbor
or smooth pixels.
We were performing a check whether source pixels would fall into a
clipped rect too early. Since we already clamp the resulting source
coordinates to the clipped rect, we can just remove this code.
Box sampling is a scaling algorithm that averages all the pixels that
form the source for the target pixel. For example, if you would resize a
9x9 image to 3x3, each target pixel would encompass a 3x3 pixel area in
the source image.
Box sampling is a near perfect scaling algorithm for downscaling. When
upscaling with this algorithm, the result is similar to nearest neighbor
or smooth pixels.
...and instead assume it's BGRx8888 or BGRA8888, for now. Always
treating the target as BGRA8888 leads to the alpha channel being
interpreted incorrectly sometimes (as can be seen with WindowServer
overlays).
Fixes#18749
An oval approximated by quadratic bezier curves ended up with 2048 line
segments when rasterized to a bitmap of around 35 by 35 pixels, which
seems a bit much. :^)
By increasing the tolerance by an order of magnitude, that same oval is
now split up into 512 line segments, which is still more than enough for
a high quality render.
This now applies clipping to the destination bounding box before
painting, which cuts out a load of clipped computation and allows
using the faster set_physical_pixel() method.
Alongside this it also combines the source_transform and
inverse_transform outside the hot loop (which might cut things down
a little).
The `destination_quad.contains()` check is also removed in favour
of just checking if the mapped point is inside the source rect,
which takes less work to compute than checking the bounding box.
This takes this method down from 98% of the time to 10% of the
time when painting Google Street View (with no obvious issues).
This is mostly a simple grayscale bilinear scale, with an extra step
of computing the distance and alpha with a little smoothing. This
can be used to paint more scalable UI elements/icons from rather
small distance fields. A tiny 16x16 SDF seems to do a decent job
for simple icons.
This commit replaces usages of `Color::interpolate()` with
`Color::mixed_with()` in image scaling functions. The latter
uses premultiplied alpha, which results in more visually
pleasing edges when images are scaled against a transparent
background.
These changes affect the SmoothPixels and BilinearBlend scaling modes
of `Painter::draw_scaled_bitmap()` as well as the `Bitmap::scaled()`
function.
Fixes#17153.
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>>.
Ultimately, we should find a way to route all emoji access through
the font code, but for now, this patch adds a special case for fonts
that are known to have embedded color bitmaps so we can test them.
This patch does three things:
- Font::has_color_bitmaps() (true if CBLC and CBDT are present)
- Glyph now knows when its bitmap comes from a color bitmap font
- Painter draws color bitmap glyphs with the appropriate scaling etc
This API is used by LibWeb's text painter. Bring it up to date with the
glyph width computations performed in draw_text_line() used by other GUI
applications.
This reverts commit eb1ef59603c13c43b87c099c43c4d118dc8441f6.
The idea of saving clip box to apply it to handle `overflow: hidden`
turned out to break painting if box is painted before it's containing
block (it is possible if box has negative z-index).
For example, consider the Pirate Flag emoji, which is the code point
sequence U+1F3F4 U+200D U+2620 U+FE0F. Our current emoji resolution does
not consider U+200D (Zero Width Joiner) as part of an emoji sequence.
Therefore fonts like Katica, which have a glyph for U+1F3F4, will draw
that glyph without checking if we have an emoji bitmap.
This removes some hard-coded code points and consults the UCD's code
point properties for emoji sequence components and variation selectors.
This recognizes the ZWJ code point as part of an emoji sequence.
Currently, we compute the width of text one code point at a time. This
ignores grapheme clusters (emoji in particular). One effect of this is
when highlighting a multi-code point emoji. We will errantly increase
the highlight rect to the sum of all code point widths, rather than
just the width of the resolved emoji bitmap.
The new Painter::set_clip_rect(IntRect) API was able to make the clip
rect larger than the underlying target bitmap. This was not good, as it
could make it possible to draw outside the bitmap memory.
Fixes a crash when viewing https://twinings.co.uk/ in the browser. :^)
Previously checkerboard patterns were anchored to the top left of the
bitmap they were being drawn into.
This makes the transparency grid in PixelPaint static relative to the
canvas when panning.
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.
This moves the CSS gradient painting to the painter creating:
- Painter::fill_rect_with_linear_gradient()
- Painter::fill_rect_with_conic_gradient()
- Painter::fill_rect_with_radial_gradient()
This has a few benefits:
- The gradients can now easily respect the painter scale
- The Painter::fill_pixels() escape hatch can be removed
- We can remove the old fixed color stop gradient code
- The old functions are now just a shim
- Anywhere can now easily use this gradient painting code!
This only leaves the color stop resolution in LibWeb (which is fine).
Just means in LibGfx you have to actually specify color stop positions.
(Also while here add a small optimization to avoid generating
excessively long gradient lines)
This is achieved by simplifying the logic in TextLayout. We get rid
of all the various ways that the layout bounding rect can get cropped.
Then we make sure to use the right pixel metrics.
Finally we use the font's own line gap metrics instead of hard-coding 4.
The end result is that text painted with vector fonts now gets pretty
reasonable vertical alignment in most cases.