1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:37:35 +00:00

LibWeb: Implement SVG S (SmoothCurve) commands

These were being parsed, but skipped when rendering. With this fix, the
SVG on discord's invite screen looks pretty nice! :^)
This commit is contained in:
Sam Atkins 2022-02-06 20:45:52 +00:00 committed by Andreas Kling
parent dc7e73a0b7
commit bf178e0196

View file

@ -462,6 +462,7 @@ Gfx::Path& SVGPathElement::get_path()
return m_path.value();
Gfx::Path path;
PathInstructionType last_instruction = PathInstructionType::Invalid;
for (auto& instruction : m_instructions) {
// If the first path element uses relative coordinates, we treat them as absolute by making them relative to (0, 0).
@ -548,7 +549,8 @@ Gfx::Path& SVGPathElement::get_path()
case PathInstructionType::SmoothQuadraticBezierCurve: {
clear_last_control_point = false;
if (m_previous_control_point.is_null()) {
if (m_previous_control_point.is_null()
|| ((last_instruction != PathInstructionType::QuadraticBezierCurve) && (last_instruction != PathInstructionType::SmoothQuadraticBezierCurve))) {
m_previous_control_point = last_point;
}
@ -569,6 +571,8 @@ Gfx::Path& SVGPathElement::get_path()
}
case PathInstructionType::Curve: {
clear_last_control_point = false;
Gfx::FloatPoint c1 = { data[0], data[1] };
Gfx::FloatPoint c2 = { data[2], data[3] };
Gfx::FloatPoint p2 = { data[4], data[5] };
@ -578,13 +582,34 @@ Gfx::Path& SVGPathElement::get_path()
c2 += last_point;
}
path.cubic_bezier_curve_to(c1, c2, p2);
m_previous_control_point = c2;
break;
}
case PathInstructionType::SmoothCurve:
// Instead of crashing the browser every time we come across an SVG
// with these path instructions, let's just skip them
continue;
case PathInstructionType::SmoothCurve: {
clear_last_control_point = false;
if (m_previous_control_point.is_null()
|| ((last_instruction != PathInstructionType::Curve) && (last_instruction != PathInstructionType::SmoothCurve))) {
m_previous_control_point = last_point;
}
auto reflected_previous_control_x = last_point.dx_relative_to(m_previous_control_point);
auto reflected_previous_control_y = last_point.dy_relative_to(m_previous_control_point);
Gfx::FloatPoint c1 = Gfx::FloatPoint { reflected_previous_control_x, reflected_previous_control_y };
Gfx::FloatPoint c2 = { data[0], data[1] };
Gfx::FloatPoint p2 = { data[2], data[3] };
if (!absolute) {
p2 += last_point;
c1 += last_point;
c2 += last_point;
}
path.cubic_bezier_curve_to(c1, c2, p2);
m_previous_control_point = c2;
break;
}
case PathInstructionType::Invalid:
VERIFY_NOT_REACHED();
}
@ -592,6 +617,7 @@ Gfx::Path& SVGPathElement::get_path()
if (clear_last_control_point) {
m_previous_control_point = Gfx::FloatPoint {};
}
last_instruction = instruction.type;
}
m_path = path;