Age | Commit message (Collapse) | Author |
|
This was previously masked by sorting the edges on max_y, but if the
last added edge pointed to an edge that ended on the current scanline,
that edge (and what it points to) would also end up added to the active
edges. These edges would then never get removed, and break things very
badly!
|
|
Remove SplitLineSegment and replace it with a FloatLine, nobody was
interested in its extra fields anymore. Also, remove the sorting of
the split segments, this really should not have been done here
anyway, and is not required by the rasterizer anymore. Keeping the
segments in stroke order will also make it possible to generate
stroked path geometry (in future).
|
|
This patch removes a long time remnant of the pre-`AK::Error` era.
|
|
The spec doesn't talk about this happening in the text, but
`dequant_init()` in 20.4 processes segment adjustment and quantization
index adjustment in the same variable `q` before clamping.
Since we had to adjust the latter step in the previous commit, do
it for the former step too.
I haven't seen this happen in the wild yet (and now, I hopefully
never will notice it if it happens).
|
|
The spec doesn't talk about this happening in the text, but
`dequant_init()` in 20.4 stores `q` in an int and clamps that
to 0 later.
|
|
It's up to callers of the ImageDecoderPlugin to honor loop_count().
The ImageDecoderPlugin doesn't have to look at it when decoding frames.
No behavior change.
|
|
The spec says that the AC dequantization factor for Y2 data should
be at least 8, so do that.
This only has a very small effect (only the first two AC table
entries are < 8 after multiplying with 155 / 100, so this would
have only a small effect on brightness), and this case is hit
exactly 0 times in all my test images. But it's still good to match
the spec.
|
|
No behavior change.
|
|
For a 1024x1024 image, saves about a quarter MB of memory use while
decoding (compared to the decompressed image data itself needing
4 MiB). Not a huge win, but also very easy to do, so might as well.
No behavior change, no measurable performance impact.
|
|
No functional or performance changes; they were probably already
optimized away by the compiler.
|
|
I could not discover proof that this is actually faster than the non-SSE
version. In addition, for these relatively simple structures, the
compiler is often sufficiently smart to generate SSE code itself.
For a synthetic font benchmark I wrote, this results in a nice 11%
decrease in runtime.
|
|
For some reason, we were decoding the source color twice for every pixel
in the inner-most loop of `blit_filtered`. This makes sure we only
decode the source color once, and rearranges the code to improve
readability.
For my synthetic font rendering benchmark, this improves glyph rendering
performance by ~9%.
|
|
When the background color has an alpha < 255, we can't copy over the
pixel alpha.
|
|
for_each_line_segment_on_elliptical_arc() flips the start/end points
for negative theta deltas. When doing this we have to make sure the
line segments emitted swap the start/end points back, so that the
(correct) winding order can be calculated from them.
This makes nonzero fills not totally broken for a lot of SVGs.
|
|
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.
|
|
It's a pain (and silly) to make this private and add every user as a
friend.
|
|
The glyph bitmap is a grayscale image that is multiplied with the
requested color provided to `Gfx::Painter::draw_glyph()` to get the
final glyph bitmap that can be blitted.
Using `Gfx::Color::multiply()` is unnecessary however: by simply taking
the destination color and copying over the glyph bitmap's alpha value,
we can prevent four multiplications and divisions per pixel.
In an artifical benchmark I wrote, this improved glyph rendering
performance by ~9%.
|
|
This is safe because:
* prediction only computes averages, or explicitly clamps for
TM_PRED / B_TM_PRED. Since the inputs are in [0, 255], so will the
outputs.
* Addition of IDCT and prediction buffer is immediately clamped back
to [0, 255]
No behavior change, and matches what both libwebp and the reference
implementation in rfc6386 do.
|
|
https://datatracker.ietf.org/doc/html/rfc6386#section-14.5 says:
"""
The summing procedure is fairly straightforward, having only a couple
of details. The prediction and residue buffers are both arrays of
16-bit signed integers. Each individual (Y, U, and V pixel) result
is calculated first as a 32-bit sum of the prediction and residue,
and is then saturated to 8-bit unsigned range (using, say, the
clamp255 function defined above) before being stored as an 8-bit
unsigned pixel value.
"""
It's IMHO not 100% clear if the clamping is supposed to happen
immediately (so that it affects prediction inputs for the next
macroblock) or later.
But vp8_dixie_idct_add() on page 173 in
https://datatracker.ietf.org/doc/html/rfc6386#section-20.8 does:
recon[0] = CLAMP_255(predict[0] + ((a1 + d1 + 4) >> 3));
So it does look like it should happen immediately.
(I'm a bit confused why the spec then says "The prediction and residue
buffers are both arrays of 16-bit signed integers", since the
prediction buffer can just be an u8 buffer now, without changing
behavior.
|
|
I accidentally inserted a bunch of code in between.
No behavior change.
|
|
The spec has that clamp at the end of
https://datatracker.ietf.org/doc/html/rfc6386#section-12.2:
The exact algorithm is as follows:
[...]
b[r][c] = clamp255(L[r]+ A[c] - P);
For the test images I'm looking at, it doesn't seem to make a
dramatic difference, but omitting it in `B_TM_PRED` did make
a dramatic difference, so add it. (Also, the spec demands it.)
|
|
`predicted_y_above` is initialized to a row of 127s, so we can just
read from it even in the first macroblock row.
No behavior change.
|
|
Each secondary partition has an independent BooleanDecoder.
Their bitstreams interleave per macroblock row, that is the first
macroblock row is read from the first decoder, the second from the
second, ..., until it wraps around again.
All partitions share a single prediction state though: The second
macroblock row (which reads coefficients off the second decoder) is
predicted using the result of decoding the frist macroblock row (which
reads coefficients off the first decoder).
So if I understand things right, in theory the coefficient reading could
be parallelized, but prediction can't be. (IDCT can also be
parallelized, but that's true with just a single partition too.)
I created the test image by running
examples/cwebp -low_memory -partitions 3 -o foo.webp \
~/src/serenity/Tests/LibGfx/test-inputs/4.webp
using a cwebp hacked up as described in #19149. Since creating
multi-partition lossy webps requires hacking up `cwebp`, they're likely
very rare in practice. (But maybe other programs using the libwebp API
create them.)
Fixes #19149.
With this, webp lossy support is complete (*) :^)
And with that, webp support is complete: Lossless, lossy, lossy with
alpha, animated lossless, animated lossy, animated lossy with alpha all
work.
(*: Loop filtering isn't implemented yet, which has a minor visual
effect on the output. But it's only visible when carefully comparing
a webp decoded without loop filtering to the same decoded with it.
But it's technically a part of the spec that's still missing.
The upsampling of UV in the YUV->RGB code is also low-quality. This
produces somewhat visible banding in practice in some images (e.g.
in the fire breather's face in 5.webp), so we should probably improve
that at some point. Our JPG decoder has the same issue.)
|
|
|
|
|
|
This could be a bit prettier, but it works :^)
|
|
|
|
This basically adds the line
u8 token = TRY(
tree_decode(decoder, COEFFICIENT_TREE,
header.coefficient_probabilities[plane][band][tricky],
last_decoded_value == DCT_0 ? 2 : 0));
and calls it once for the 16 coefficients of a discrete cosine transform
that covers a 4x4 pixel subblock.
And then it does this 24 or 25 times per macroblock, for the 4x4 Y
subblocks and the 2x2 each U and V subblocks (plus an optional Y2 block
for some macroblocks).
It then adds a whole bunch of machinery to be able to compute `plane`,
`band`, and in particular `tricky` (which depends on if the
corresponding left or above subblock has non-zero coefficients).
(It also does dequantization, and does an inverse Walsh-Hadamard
transform when needed, to end up with complete DCT coefficients
in all cases.)
|
|
Also add `vp8_short_inv_walsh4x4_c()` from the spec for the inverse
Walsh-Hadamard transform. The YUV output data must bitwise match the
behavior of the spec, so there isn't a ton of flexibility of how to
do this particular function.
|
|
Somehow my brain decided to change the name of this concept.
Not sure why, the spec consistently uses 'macroblock'.
No behavior change.
|
|
This is factored out from Color::from_string and determines the color
only from performing an ASCII case-insensitive search over the named
CSS colors.
|
|
|
|
|
|
|
|
|
|
This will contain several of the fixed data tables from the VP8 spec.
For starters, it contains the tables needed to read the frame header
in the first partition. These tables are needed to read the
probabilities of the metablock predicition modes, which in turn will
be needed to read the metablock predicition modes themselves.
|
|
|
|
The marker bit is VP9-only, so move that into a new initialize_vp9()
function.
finish_decode() is VP9-only, so rename that to finish_decode_vp9().
|
|
...and keep a forwarding header around in VP9, so we don't have to
update all references to the class there.
In time, we probably want to merge LibGfx/ImageDecoders and LibVideo
into LibMedia, but for now I need just this class for the lossy
webp decoder. So move just it over.
No behvior change.
|
|
Implied point = point created by two subsequent "off curve" points.
Fixes following issues in function that builds glyph path from points:
- If first point is "off curve" it was wrongly treated as "on curve"
which caused wrong first point position in the path.
- If both first and last points in the path are "off curve" implied
point was not created between them which caused wrong path shape in
the end of the path.
|
|
|
|
Since the color interpolation requires two pixels in the horizontal and
vertical direction to work, 1 pixel wide or high bitmaps would cause a
crash when scaling. Fix this by clamping the index into the valid range.
Fixes #16047.
|
|
We can now trust `Gfx::Rect<T>` to correctly calculate rectangle
intersections when `T = float`.
|
|
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.
|
|
Trim whitespace of the alpha component before calling
parse_first_floating_point, which doesn't handle it.
|
|
Pixels will leave the lossy decoder with alpha set to 255.
The old code would be a no-op in that case.
No observable behavior change yet, since there still is no
decoder for lossy webp.
|
|
This helps with debugging why fonts cannot be found.
|
|
This reverts commit df304401178dc4e82edccdbe6e7a7a7d12eecfe9.
This scaling type is now unused, and has issues with painting outside of
the Painter's clip-rect.
|
|
This returns the color with its alpha scaled by the opacity.
|
|
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.
|