diff options
author | MacDue <macdue@dueutil.tech> | 2023-04-11 00:18:28 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-04-12 07:40:22 +0200 |
commit | ba6272a0a0e2dceccc9f1378d3c4f47d9aaea6d6 (patch) | |
tree | 8f160734a6f8c3c65a72783c3242ccdabc445e23 /Userland | |
parent | ba7383d28ff6431d65485fd38c136da26c25c029 (diff) | |
download | serenity-ba6272a0a0e2dceccc9f1378d3c4f47d9aaea6d6.zip |
LibWeb: Don't try to paint SVG elements transformed to zero size
Otherwise, the Gfx::Painter will get choked up on NaNs and start
infinitely splitting paths till it OOMs.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp | 19 |
3 files changed, 18 insertions, 11 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp b/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp index c67d547aaa..486378826f 100644 --- a/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp +++ b/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp @@ -25,7 +25,7 @@ CSSPixelPoint SVGGeometryBox::viewbox_origin() const return { svg_box->view_box().value().min_x, svg_box->view_box().value().min_y }; } -Gfx::AffineTransform SVGGeometryBox::layout_transform() const +Optional<Gfx::AffineTransform> SVGGeometryBox::layout_transform() const { auto& geometry_element = dom_node(); auto transform = geometry_element.get_transform(); @@ -37,9 +37,12 @@ Gfx::AffineTransform SVGGeometryBox::layout_transform() const // Note: SVGFormattingContext has already done the scaling based on the viewbox, // we now have to derive what it was from the original bounding box size. // FIXME: It would be nice if we could store the transform from layout somewhere, so we don't have to solve for it here. + auto original_bounding_box = Gfx::AffineTransform {}.translate(-origin).multiply(transform).map(const_cast<SVG::SVGGeometryElement&>(geometry_element).get_path().bounding_box()); + // If the transform (or path) results in a empty box we can't display this. + if (original_bounding_box.is_empty()) + return {}; auto scaled_width = paint_box()->content_width().value(); auto scaled_height = paint_box()->content_height().value(); - auto original_bounding_box = Gfx::AffineTransform {}.translate(-origin).multiply(transform).map(const_cast<SVG::SVGGeometryElement&>(geometry_element).get_path().bounding_box()); scaling = min(scaled_width / original_bounding_box.width(), scaled_height / original_bounding_box.height()); auto scaled_bounding_box = original_bounding_box.scaled(scaling, scaling); paint_offset = (paint_box()->absolute_rect().location() - svg_box->paint_box()->absolute_rect().location()).to_type<float>() - scaled_bounding_box.location(); diff --git a/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h b/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h index c24b809d9b..42b177d0fa 100644 --- a/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h +++ b/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h @@ -6,6 +6,7 @@ #pragma once +#include <AK/Optional.h> #include <LibWeb/Layout/SVGGraphicsBox.h> #include <LibWeb/SVG/SVGGeometryElement.h> @@ -21,7 +22,7 @@ public: SVG::SVGGeometryElement& dom_node() { return static_cast<SVG::SVGGeometryElement&>(SVGGraphicsBox::dom_node()); } SVG::SVGGeometryElement const& dom_node() const { return static_cast<SVG::SVGGeometryElement const&>(SVGGraphicsBox::dom_node()); } - Gfx::AffineTransform layout_transform() const; + Optional<Gfx::AffineTransform> layout_transform() const; virtual JS::GCPtr<Painting::Paintable> create_paintable() const override; diff --git a/Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp b/Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp index e0238659e9..07aa283de4 100644 --- a/Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp @@ -33,10 +33,12 @@ Optional<HitTestResult> SVGGeometryPaintable::hit_test(CSSPixelPoint position, H if (!result.has_value()) return {}; auto& geometry_element = layout_box().dom_node(); - auto transformed_bounding_box = layout_box().layout_transform().map_to_quad( - const_cast<SVG::SVGGeometryElement&>(geometry_element).get_path().bounding_box()); - if (!transformed_bounding_box.contains(position.to_type<float>())) - return {}; + if (auto transform = layout_box().layout_transform(); transform.has_value()) { + auto transformed_bounding_box = transform->map_to_quad( + const_cast<SVG::SVGGeometryElement&>(geometry_element).get_path().bounding_box()); + if (!transformed_bounding_box.contains(position.to_type<float>())) + return {}; + } return result; } @@ -56,6 +58,7 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const auto& svg_context = context.svg_context(); // FIXME: This should not be trucated to an int. + Gfx::PainterStateSaver save_painter { context.painter() }; auto offset = context.floored_device_point(svg_context.svg_element_position()).to_type<int>().to_type<float>(); painter.translate(offset); @@ -65,7 +68,10 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const context.painter().add_clip_rect(context.enclosing_device_rect(absolute_rect()).to_type<int>()); auto css_scale = context.device_pixels_per_css_pixel(); - Gfx::Path path = const_cast<SVG::SVGGeometryElement&>(geometry_element).get_path().copy_transformed(Gfx::AffineTransform {}.scale(css_scale, css_scale).multiply(layout_box().layout_transform())); + auto transform = layout_box().layout_transform(); + if (!transform.has_value()) + return; + Gfx::Path path = const_cast<SVG::SVGGeometryElement&>(geometry_element).get_path().copy_transformed(Gfx::AffineTransform {}.scale(css_scale, css_scale).multiply(*transform)); 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 @@ -87,9 +93,6 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const stroke_color, geometry_element.stroke_width().value_or(svg_context.stroke_width()) * context.device_pixels_per_css_pixel()); } - - painter.translate(-offset); - context.painter().clear_clip_rect(); } } |