mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibWeb: Repeat shader for repeating linear gradient
We implemented repeating linear gradients by expanding a vector of color stops until the entire range was covered. This is both a bit wasteful and caused Skia to draw corrupted gradients to screen whenever the total amount of color stops and positions exceeded 127. Instead of doing that, use the original color stops for the shader and repeat it instead of clamping it. We need to do a bit of math to project positions correctly, but after that the shader repeats itself nicely. While we're here, calculate the gradient's length and the center point as floats instead of ints, yielding a slight but noticeable improvement in gradient rendering (see the diff on the zig zag pattern in css-gradients.html for an example of this).
This commit is contained in:
parent
8af6da64a6
commit
f8c4043460
|
|
@ -399,41 +399,39 @@ static SkGradientShader::Interpolation to_skia_interpolation(CSS::InterpolationM
|
|||
void DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& command)
|
||||
{
|
||||
auto const& linear_gradient_data = command.linear_gradient_data;
|
||||
auto color_stop_list = linear_gradient_data.color_stops.list;
|
||||
auto const& color_stop_list = linear_gradient_data.color_stops.list;
|
||||
auto const& repeat_length = linear_gradient_data.color_stops.repeat_length;
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
if (repeat_length.has_value())
|
||||
color_stop_list = expand_repeat_length(color_stop_list, *repeat_length);
|
||||
|
||||
auto stops_with_replaced_transition_hints = replace_transition_hints_with_normal_color_stops(color_stop_list);
|
||||
|
||||
Vector<SkColor4f> colors;
|
||||
Vector<SkScalar> positions;
|
||||
auto const first_position = repeat_length.has_value() ? stops_with_replaced_transition_hints.first().position : 0.f;
|
||||
for (size_t stop_index = 0; stop_index < stops_with_replaced_transition_hints.size(); stop_index++) {
|
||||
auto const& stop = stops_with_replaced_transition_hints[stop_index];
|
||||
if (stop_index > 0 && stop == stops_with_replaced_transition_hints[stop_index - 1])
|
||||
continue;
|
||||
|
||||
colors.append(to_skia_color4f(stop.color));
|
||||
positions.append(stop.position);
|
||||
positions.append((stop.position - first_position) / repeat_length.value_or(1));
|
||||
}
|
||||
|
||||
auto const& rect = command.gradient_rect;
|
||||
auto length = calculate_gradient_length<int>(rect.size(), linear_gradient_data.gradient_angle);
|
||||
auto bottom = rect.center().translated(0, -length / 2);
|
||||
auto top = rect.center().translated(0, length / 2);
|
||||
auto rect = command.gradient_rect.to_type<float>();
|
||||
auto length = calculate_gradient_length<float>(rect.size(), linear_gradient_data.gradient_angle);
|
||||
|
||||
Array points {
|
||||
to_skia_point(top),
|
||||
to_skia_point(bottom),
|
||||
};
|
||||
// Starting and ending points before rotation (0deg / "to top")
|
||||
auto rect_center = rect.center();
|
||||
auto start = rect_center.translated(0, (.5f - first_position) * length);
|
||||
auto end = start.translated(0, repeat_length.value_or(1) * -length);
|
||||
Array const points { to_skia_point(start), to_skia_point(end) };
|
||||
|
||||
auto center = to_skia_rect(rect).center();
|
||||
SkMatrix matrix;
|
||||
matrix.setRotate(linear_gradient_data.gradient_angle, center.x(), center.y());
|
||||
matrix.setRotate(linear_gradient_data.gradient_angle, rect_center.x(), rect_center.y());
|
||||
|
||||
auto color_space = SkColorSpace::MakeSRGB();
|
||||
auto interpolation = to_skia_interpolation(linear_gradient_data.interpolation_method);
|
||||
auto shader = SkGradientShader::MakeLinear(points.data(), colors.data(), color_space, positions.data(), positions.size(), SkTileMode::kClamp, interpolation, &matrix);
|
||||
auto shader = SkGradientShader::MakeLinear(points.data(), colors.data(), color_space, positions.data(), positions.size(), SkTileMode::kRepeat, interpolation, &matrix);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setDither(true);
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 247 KiB After Width: | Height: | Size: 244 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 444 KiB After Width: | Height: | Size: 425 KiB |
|
|
@ -1,11 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="match" href="../expected/css-background-clip-text-ref.html" />
|
||||
<meta name="fuzzy" content="maxDifference=0-3;totalPixels=0-25969">
|
||||
<title>Document</title>
|
||||
<meta name="fuzzy" content="maxDifference=0-3;totalPixels=0-25811">
|
||||
|
||||
<style>
|
||||
html {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="match" href="../expected/css-gradients-ref.html" />
|
||||
<meta name="fuzzy" content="maxDifference=0-63;totalPixels=0-215">
|
||||
<meta name="fuzzy" content="maxDifference=0-63;totalPixels=0-167">
|
||||
<style>
|
||||
body {
|
||||
background-color: white;
|
||||
|
|
@ -145,6 +145,10 @@
|
|||
background-image: -webkit-repeating-linear-gradient(left, red 10%, blue 30%);
|
||||
}
|
||||
|
||||
.grad-repeat-4 {
|
||||
background-image: repeating-linear-gradient(to bottom, blue 0 2px, red 2px 4px);
|
||||
}
|
||||
|
||||
.grad-double-position {
|
||||
background-image: linear-gradient(to right, red 20%, orange 20% 40%, yellow 40% 60%, green 60% 80%, blue 80%)
|
||||
}
|
||||
|
|
@ -246,6 +250,7 @@
|
|||
<div class="box grad-conic-6"></div>
|
||||
<div class="box grad-conic-repeat-1"></div>
|
||||
<div class="box grad-conic-repeat-2"></div>
|
||||
<div class="box grad-repeat-4"></div>
|
||||
</section>
|
||||
<section class="rects">
|
||||
<div class="rect grad-7"></div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user