1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 22:27:42 +00:00

LibWeb: SVG: implement SmoothQuadraticBezierCurve

For this we need to track the control point of the previous command and
calculate a new control point based on it.
This commit is contained in:
Simon Danner 2020-09-07 22:58:47 +02:00 committed by Andreas Kling
parent 772fcba814
commit 9648bf4ada
2 changed files with 41 additions and 2 deletions

View file

@ -448,6 +448,8 @@ void SVGPathElement::paint(Gfx::Painter& painter, const SVGPaintingContext& cont
print_instruction(instruction); print_instruction(instruction);
#endif #endif
bool clear_last_control_point = true;
switch (instruction.type) { switch (instruction.type) {
case PathInstructionType::Move: { case PathInstructionType::Move: {
Gfx::FloatPoint point = { data[0], data[1] }; Gfx::FloatPoint point = { data[0], data[1] };
@ -580,27 +582,62 @@ void SVGPathElement::paint(Gfx::Painter& painter, const SVGPaintingContext& cont
break; break;
} }
case PathInstructionType::QuadraticBezierCurve: { case PathInstructionType::QuadraticBezierCurve: {
clear_last_control_point = false;
Gfx::FloatPoint through = { data[0], data[1] }; Gfx::FloatPoint through = { data[0], data[1] };
Gfx::FloatPoint point = { data[2], data[3] }; Gfx::FloatPoint point = { data[2], data[3] };
if (absolute) { if (absolute) {
path.quadratic_bezier_curve_to(through, point); path.quadratic_bezier_curve_to(through, point);
m_previous_control_point = through;
} else { } else {
ASSERT(!path.segments().is_empty()); ASSERT(!path.segments().is_empty());
auto last_point = path.segments().last().point(); auto last_point = path.segments().last().point();
path.quadratic_bezier_curve_to(through + last_point, point + last_point); auto control_point = through + last_point;
path.quadratic_bezier_curve_to(control_point, point + last_point);
m_previous_control_point = control_point;
} }
break; break;
} }
case PathInstructionType::SmoothQuadraticBezierCurve: {
clear_last_control_point = false;
ASSERT(!path.segments().is_empty());
auto last_point = path.segments().last().point();
if (m_previous_control_point.is_null()) {
m_previous_control_point = last_point;
}
auto dx_end_control = last_point.dx_relative_to(m_previous_control_point);
auto dy_end_control = last_point.dy_relative_to(m_previous_control_point);
auto control_point = Gfx::FloatPoint {last_point.x() + dx_end_control, last_point.y() + dy_end_control};
Gfx::FloatPoint end_point = {data[0], data[1]};
if (absolute) {
path.quadratic_bezier_curve_to(control_point, end_point);
}
else {
path.quadratic_bezier_curve_to(control_point, end_point + last_point);
}
m_previous_control_point = control_point;
break;
}
case PathInstructionType::Curve: case PathInstructionType::Curve:
case PathInstructionType::SmoothCurve: case PathInstructionType::SmoothCurve:
case PathInstructionType::SmoothQuadraticBezierCurve:
// Instead of crashing the browser every time we come across an SVG // Instead of crashing the browser every time we come across an SVG
// with these path instructions, let's just skip them // with these path instructions, let's just skip them
continue; continue;
case PathInstructionType::Invalid: case PathInstructionType::Invalid:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
if (clear_last_control_point) {
m_previous_control_point = Gfx::FloatPoint {};
}
} }
// We need to fill the path before applying the stroke, however the filled // We need to fill the path before applying the stroke, however the filled

View file

@ -112,6 +112,8 @@ public:
private: private:
Vector<PathInstruction> m_instructions; Vector<PathInstruction> m_instructions;
Gfx::FloatPoint m_previous_control_point = {};
}; };
} }