diff --git a/Userland/Libraries/LibWeb/SVG/SVGPathElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGPathElement.cpp index 110eed7b3e..03530a8110 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGPathElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGPathElement.cpp @@ -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;