summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGfx
AgeCommit message (Collapse)Author
2023-06-04LibGfx: Fix adding active edges in filled path rasterizerMacDue
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!
2023-06-04LibGfx: Simplify segmentizing pathsMacDue
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).
2023-06-02LibGfx/JPEG: Use `Error` to propagate errorsLucas CHOLLET
This patch removes a long time remnant of the pre-`AK::Error` era.
2023-06-01WebP/Lossy: Allow negative values from segment adjustment tooNico Weber
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).
2023-06-01WebP/Lossy: Clamp negative quantization indices to zeroNico Weber
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.
2023-06-01WebP: Remove nonsensical commentNico Weber
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.
2023-06-01WebP/Lossy: Add a missing clampNico Weber
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.
2023-06-01WebP/Lossy: Add `const` annotations to functions in Tables.hNico Weber
No behavior change.
2023-06-01WebP/Lossy: Reduce size of MacroblockMetadata from 80 to 20 bytesNico Weber
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.
2023-06-01LibGfx: Do not use divisions when calculating font subpixel offsetsJelle Raaijmakers
No functional or performance changes; they were probably already optimized away by the compiler.
2023-06-01LibGfx: Remove SSE version of `Color::blend()`Jelle Raaijmakers
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.
2023-06-01LibGfx: Optimize `Painter::blit_filtered()`Jelle Raaijmakers
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%.
2023-06-01LibGfx: Multiply alpha channels for vector fonts, when necessaryAndi Gallo
When the background color has an alpha < 255, we can't copy over the pixel alpha.
2023-06-01LibGfx: Fix winding order of segments on elliptical arcsMacDue
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.
2023-06-01LibGfx: Implement new antialiased filled path rasterizerMacDue
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.
2023-06-01LibGfx: Make PaintStyle::paint() a public functionMacDue
It's a pain (and silly) to make this private and add every user as a friend.
2023-06-01LibGfx: Improve glyph rendering speed for vector fontsJelle Raaijmakers
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%.
2023-05-31WebP/Lossy: Use 8-bit buffers for prediction and YUV dataNico Weber
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.
2023-05-31WebP/Lossy: Clamp right after summing IDCT output, instead of laterNico Weber
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.
2023-05-31WebP/Lossy: Move two enums closer to the struct that uses themNico Weber
I accidentally inserted a bunch of code in between. No behavior change.
2023-05-31WebP/Lossy: Add a missing clamp() in `TM_PRED` predictionNico Weber
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.)
2023-05-31WebP/Lossy: Remove an unnecessary branchNico Weber
`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.
2023-05-31WebP/Lossy: Add support for images with more than one partitionNico Weber
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.)
2023-05-30WebP/Lossy: Tweak some commentsNico Weber
2023-05-30WebP/Lossy: Check that file contains enough data for first partitionNico Weber
2023-05-29WebP/Lossy: Implement prediction and inverse DCTNico Weber
This could be a bit prettier, but it works :^)
2023-05-29WebP/Lossy: Add function for inverse 4x4 DCT from specNico Weber
2023-05-29WebP/Lossy: Implement macroblock coefficient decodingNico Weber
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.)
2023-05-29WebP/Lossy: Add static data needed for decoding coefficientsNico Weber
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.
2023-05-28WebP/Lossy: It's 'macroblock', not 'metablock'Nico Weber
Somehow my brain decided to change the name of this concept. Not sure why, the spec consistently uses 'macroblock'. No behavior change.
2023-05-28LibGfx: Add Color::from_named_css_color_stringShannon Booth
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.
2023-05-27WebP/Lossy: Variable naming fix for constants from last pull requestNico Weber
2023-05-27WebP/Lossy: Add code to read macroblock metadataNico Weber
2023-05-27WebP/Lossy: Add static data tables for reading macroblock metadataNico Weber
2023-05-27WebP/Lossy: Add code to read the frame header in the first partitionNico Weber
2023-05-27WebP/Lossy: Add WebPLoaderLossyTables.hNico Weber
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.
2023-05-27WebP/Lossy: Add a comment with a summary of the file formatNico Weber
2023-05-27LibGfx+LibVideo: Make BooleanDecoder usable for both VP8 and VP9Nico Weber
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().
2023-05-27LibGfx+LibVideo: Move VP9/BooleanDecoder to LibGfx/ImageFormatsNico Weber
...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.
2023-05-26LibGfx: Fix glyph render to create implied points in start/end of pathAliaksandr Kalenik
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.
2023-05-24WebP/Lossy: Validate show_frame and version when reading headerNico Weber
2023-05-24LibGfx: Prevent out of bounds access when scaling small BitmapsDarius Arnold
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.
2023-05-23LibGfx: Get rid of `Gfx::Rect<float>` area workaround in `Painter`Jelle Raaijmakers
We can now trust `Gfx::Rect<T>` to correctly calculate rectangle intersections when `T = float`.
2023-05-23LibGfx+Everywhere: Change `Gfx::Rect` to be endpoint exclusiveJelle Raaijmakers
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.
2023-05-23LibGfx: Fix parsing of rgba valuesAndi Gallo
Trim whitespace of the alpha component before calling parse_first_floating_point, which doesn't handle it.
2023-05-22WebP: Let ALPH replace alpha channel instead of augmenting itNico Weber
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.
2023-05-22LibGfx: Add search path to debug output in `FontDatabase`Jelle Raaijmakers
This helps with debugging why fonts cannot be found.
2023-05-22Revert "LibGfx: Add NearestFractional scaling type to painter"Sam Atkins
This reverts commit df304401178dc4e82edccdbe6e7a7a7d12eecfe9. This scaling type is now unused, and has issues with painting outside of the Painter's clip-rect.
2023-05-20LibGfx: Add Color::with_opacity(float opacity)MacDue
This returns the color with its alpha scaled by the opacity.
2023-05-19LibGfx: Remove clip check in `Painter::do_draw_scaled_bitmap`Jelle Raaijmakers
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.