mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 12:38:12 +00:00
LibWeb: Let Paintable perform the painting
This patch adds a bunch of Paintable subclasses, each corresponding to the Layout::Node subclasses that had a paint() override. All painting logic is moved from layout nodes into their corresponding paintables. Paintables are now created by asking a Layout::Box to produce one: static NonnullOwnPtr<Paintable> Layout::Box::create_paintable() Note that inline nodes still have their painting logic. Since they are not boxes, and all paintables have a corresponding box, we'll need to come up with some other solution for them.
This commit is contained in:
parent
f6497b64ac
commit
02b316fd5c
64 changed files with 1307 additions and 602 deletions
|
@ -19,99 +19,6 @@ SVGGeometryBox::SVGGeometryBox(DOM::Document& document, SVG::SVGGeometryElement&
|
|||
{
|
||||
}
|
||||
|
||||
void SVGGeometryBox::paint(PaintContext& context, Painting::PaintPhase phase)
|
||||
{
|
||||
if (!is_visible())
|
||||
return;
|
||||
|
||||
SVGGraphicsBox::paint(context, phase);
|
||||
|
||||
if (phase != Painting::PaintPhase::Foreground)
|
||||
return;
|
||||
|
||||
auto& geometry_element = dom_node();
|
||||
|
||||
Gfx::AntiAliasingPainter painter { context.painter() };
|
||||
auto& svg_context = context.svg_context();
|
||||
|
||||
auto offset = svg_context.svg_element_position();
|
||||
painter.translate(offset);
|
||||
|
||||
SVG::SVGSVGElement* svg_element = geometry_element.first_ancestor_of_type<SVG::SVGSVGElement>();
|
||||
auto maybe_view_box = svg_element->view_box();
|
||||
|
||||
context.painter().add_clip_rect(enclosing_int_rect(m_paint_box->absolute_rect()));
|
||||
|
||||
Gfx::Path path = geometry_element.get_path();
|
||||
|
||||
if (maybe_view_box.has_value()) {
|
||||
Gfx::Path new_path;
|
||||
auto scaling = viewbox_scaling();
|
||||
auto origin = viewbox_origin();
|
||||
|
||||
auto transform_point = [&scaling, &origin](Gfx::FloatPoint const& point) -> Gfx::FloatPoint {
|
||||
auto new_point = point;
|
||||
new_point.translate_by({ -origin.x(), -origin.y() });
|
||||
new_point.scale_by(scaling);
|
||||
return new_point;
|
||||
};
|
||||
|
||||
for (auto& segment : path.segments()) {
|
||||
switch (segment.type()) {
|
||||
case Gfx::Segment::Type::Invalid:
|
||||
break;
|
||||
case Gfx::Segment::Type::MoveTo:
|
||||
new_path.move_to(transform_point(segment.point()));
|
||||
break;
|
||||
case Gfx::Segment::Type::LineTo:
|
||||
new_path.line_to(transform_point(segment.point()));
|
||||
break;
|
||||
case Gfx::Segment::Type::QuadraticBezierCurveTo: {
|
||||
auto& quadratic_bezier_segment = static_cast<Gfx::QuadraticBezierCurveSegment const&>(segment);
|
||||
new_path.quadratic_bezier_curve_to(transform_point(quadratic_bezier_segment.through()), transform_point(quadratic_bezier_segment.point()));
|
||||
break;
|
||||
}
|
||||
case Gfx::Segment::Type::CubicBezierCurveTo: {
|
||||
auto& cubic_bezier_segment = static_cast<Gfx::CubicBezierCurveSegment const&>(segment);
|
||||
new_path.cubic_bezier_curve_to(transform_point(cubic_bezier_segment.through_0()), transform_point(cubic_bezier_segment.through_1()), transform_point(cubic_bezier_segment.point()));
|
||||
break;
|
||||
}
|
||||
case Gfx::Segment::Type::EllipticalArcTo: {
|
||||
auto& elliptical_arc_segment = static_cast<Gfx::EllipticalArcSegment const&>(segment);
|
||||
new_path.elliptical_arc_to(transform_point(elliptical_arc_segment.point()), elliptical_arc_segment.radii().scaled(scaling, scaling), elliptical_arc_segment.x_axis_rotation(), false, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path = new_path;
|
||||
}
|
||||
|
||||
if (auto fill_color = geometry_element.fill_color().value_or(svg_context.fill_color()); fill_color.alpha() > 0) {
|
||||
// We need to fill the path before applying the stroke, however the filled
|
||||
// path must be closed, whereas the stroke path may not necessary be closed.
|
||||
// Copy the path and close it for filling, but use the previous path for stroke
|
||||
auto closed_path = path;
|
||||
closed_path.close();
|
||||
|
||||
// Fills are computed as though all paths are closed (https://svgwg.org/svg2-draft/painting.html#FillProperties)
|
||||
painter.fill_path(
|
||||
closed_path,
|
||||
fill_color,
|
||||
Gfx::Painter::WindingRule::EvenOdd);
|
||||
}
|
||||
|
||||
if (auto stroke_color = geometry_element.stroke_color().value_or(svg_context.stroke_color()); stroke_color.alpha() > 0) {
|
||||
painter.stroke_path(
|
||||
path,
|
||||
stroke_color,
|
||||
geometry_element.stroke_width().value_or(svg_context.stroke_width()));
|
||||
}
|
||||
|
||||
painter.translate(-offset);
|
||||
context.painter().clear_clip_rect();
|
||||
}
|
||||
|
||||
float SVGGeometryBox::viewbox_scaling() const
|
||||
{
|
||||
auto* svg_box = dom_node().first_ancestor_of_type<SVG::SVGSVGElement>();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue