LibWeb: Handle gradient repeating as defined in the spec in Skia painter
Couple fixes found by reading the spec: - Repeating should also happen in negative direction, so the whole [0, 1] is covered. - Leftmost and rightmost stops should be clamped to [0, 1] range if needed, because Skia ignores everything outside of this range.
This commit is contained in:
parent
8c8310f0bd
commit
dadf82f2a2
Notes:
sideshowbarker
2024-07-17 00:13:51 +09:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/LadybirdBrowser/ladybird/commit/dadf82f2a2 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/668
1 changed files with 41 additions and 14 deletions
|
@ -583,22 +583,49 @@ static ColorStopList replace_transition_hints_with_normal_color_stops(ColorStopL
|
|||
|
||||
static ColorStopList expand_repeat_length(ColorStopList const& color_stop_list, float repeat_length)
|
||||
{
|
||||
ColorStopList color_stop_list_with_expanded_repeat;
|
||||
size_t repeat_count = 0;
|
||||
while (true) {
|
||||
for (auto stop : color_stop_list) {
|
||||
stop.position += repeat_length * repeat_count;
|
||||
if (stop.position > 1.0f)
|
||||
return color_stop_list_with_expanded_repeat;
|
||||
color_stop_list_with_expanded_repeat.append(stop);
|
||||
}
|
||||
repeat_count++;
|
||||
if (repeat_count > 1000) {
|
||||
// Crash instead of being stuck in infinite loop
|
||||
VERIFY_NOT_REACHED();
|
||||
// https://drafts.csswg.org/css-images/#repeating-gradients
|
||||
// When rendered, however, the color-stops are repeated infinitely in both directions, with their
|
||||
// positions shifted by multiples of the difference between the last specified color-stop’s position
|
||||
// and the first specified color-stop’s position. For example, repeating-linear-gradient(red 10px, blue 50px)
|
||||
// is equivalent to linear-gradient(..., red -30px, blue 10px, red 10px, blue 50px, red 50px, blue 90px, ...).
|
||||
|
||||
auto first_stop_position = color_stop_list.first().position;
|
||||
int const negative_repeat_count = AK::ceil(first_stop_position / repeat_length);
|
||||
int const positive_repeat_count = AK::ceil((1.0f - first_stop_position) / repeat_length);
|
||||
|
||||
ColorStopList color_stop_list_with_expanded_repeat = color_stop_list;
|
||||
|
||||
auto get_color_between_stops = [](float position, auto const& current_stop, auto const& previous_stop) {
|
||||
auto distance_between_stops = current_stop.position - previous_stop.position;
|
||||
auto percentage = (position - previous_stop.position) / distance_between_stops;
|
||||
return previous_stop.color.interpolate(current_stop.color, percentage);
|
||||
};
|
||||
|
||||
for (auto repeat_count = 1; repeat_count <= negative_repeat_count; repeat_count++) {
|
||||
for (auto stop : color_stop_list.in_reverse()) {
|
||||
stop.position += repeat_length * static_cast<float>(-repeat_count);
|
||||
if (stop.position < 0) {
|
||||
stop.color = get_color_between_stops(0.0f, stop, color_stop_list_with_expanded_repeat.first());
|
||||
color_stop_list_with_expanded_repeat.prepend(stop);
|
||||
break;
|
||||
}
|
||||
color_stop_list_with_expanded_repeat.prepend(stop);
|
||||
}
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
|
||||
for (auto repeat_count = 0; repeat_count < positive_repeat_count; repeat_count++) {
|
||||
for (auto stop : color_stop_list) {
|
||||
stop.position += repeat_length * static_cast<float>(repeat_count);
|
||||
if (stop.position > 1) {
|
||||
stop.color = get_color_between_stops(1.0f, stop, color_stop_list_with_expanded_repeat.last());
|
||||
color_stop_list_with_expanded_repeat.append(stop);
|
||||
break;
|
||||
}
|
||||
color_stop_list_with_expanded_repeat.append(stop);
|
||||
}
|
||||
}
|
||||
|
||||
return color_stop_list_with_expanded_repeat;
|
||||
}
|
||||
|
||||
CommandResult DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& command)
|
||||
|
|
Loading…
Add table
Reference in a new issue