LibGfx: Fix winding order of segments on elliptical arcs

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 commit is contained in:
MacDue 2023-05-31 23:49:16 +01:00 committed by Andreas Kling
parent 48fa8f97d3
commit 6685656d2d
Notes: sideshowbarker 2024-07-16 22:51:10 +09:00

View File

@ -2323,10 +2323,12 @@ void Painter::for_each_line_segment_on_elliptical_arc(FloatPoint p1, FloatPoint
auto start = p1;
auto end = p2;
bool start_swapped = false;
if (theta_delta < 0) {
swap(start, end);
theta_1 = theta_1 + theta_delta;
theta_delta = fabsf(theta_delta);
start_swapped = true;
}
auto relative_start = start - center;
@ -2351,6 +2353,13 @@ void Painter::for_each_line_segment_on_elliptical_arc(FloatPoint p1, FloatPoint
p.set_y(original_x * sin_x_axis + original_y * cos_x_axis);
};
auto emit_point = [&](auto p0, auto p1) {
// NOTE: If we swap the start/end we must swap the emitted points, so correct winding orders can be calculated.
if (start_swapped)
swap(p0, p1);
callback(p0, p1);
};
for (float theta = theta_1; theta <= theta_1 + theta_delta; theta += theta_step) {
float s, c;
AK::sincos(theta, s, c);
@ -2358,12 +2367,12 @@ void Painter::for_each_line_segment_on_elliptical_arc(FloatPoint p1, FloatPoint
next_point.set_y(b * s);
rotate_point(next_point);
callback(current_point + center, next_point + center);
emit_point(current_point + center, next_point + center);
current_point = next_point;
}
callback(current_point + center, end);
emit_point(current_point + center, end);
}
// static