From 130aff12b16f6ab0fb2832b9e6deb5fe5721ea9d Mon Sep 17 00:00:00 2001 From: MacDue Date: Sun, 5 May 2024 13:09:21 +0100 Subject: [PATCH] LibWeb: Fix null layout node dereference in SVGMaskable This makes sure `get_mask_type_of_svg()` finds the mask or clipPath by looking at its child layout nodes. Previously, it went via the DOM node of the mask or clipPath, which is not always correct as there is not a 1-to-1 mapping from mask DOM node to SVGMaskBox (or SVGClipBox). Fixes #24186 --- .../Libraries/LibWeb/Painting/SVGMaskable.cpp | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibWeb/Painting/SVGMaskable.cpp b/Userland/Libraries/LibWeb/Painting/SVGMaskable.cpp index 978673758cb..36fdab85138 100644 --- a/Userland/Libraries/LibWeb/Painting/SVGMaskable.cpp +++ b/Userland/Libraries/LibWeb/Painting/SVGMaskable.cpp @@ -15,14 +15,30 @@ namespace Web::Painting { +template +static T const* first_child_layout_node_of_type(SVG::SVGGraphicsElement const& graphics_element) +{ + return graphics_element.layout_node()->first_child_of_type(); +} + +static auto get_mask_box(SVG::SVGGraphicsElement const& graphics_element) +{ + return first_child_layout_node_of_type(graphics_element); +} + +static auto get_clip_box(SVG::SVGGraphicsElement const& graphics_element) +{ + return first_child_layout_node_of_type(graphics_element); +} + Optional SVGMaskable::get_masking_area_of_svg() const { auto const& graphics_element = verify_cast(*dom_node_of_svg()); Optional masking_area = {}; - if (auto* mask_box = graphics_element.layout_node()->first_child_of_type()) { + if (auto* mask_box = get_mask_box(graphics_element)) { masking_area = mask_box->dom_node().resolve_masking_area(mask_box->paintable_box()->absolute_border_box_rect()); } - if (auto* clip_box = graphics_element.layout_node()->first_child_of_type()) { + if (auto* clip_box = get_clip_box(graphics_element)) { // This is a bit ad-hoc, but if we have both a mask and a clip-path, intersect the two areas to find the masking area. auto clip_area = clip_box->paintable_box()->absolute_border_box_rect(); if (masking_area.has_value()) @@ -48,9 +64,9 @@ static Gfx::Bitmap::MaskKind mask_type_to_gfx_mask_kind(CSS::MaskType mask_type) Optional SVGMaskable::get_mask_type_of_svg() const { auto const& graphics_element = verify_cast(*dom_node_of_svg()); - if (auto mask = graphics_element.mask()) - return mask_type_to_gfx_mask_kind(mask->layout_node()->computed_values().mask_type()); - if (graphics_element.clip_path()) + if (auto* mask_box = get_mask_box(graphics_element)) + return mask_type_to_gfx_mask_kind(mask_box->computed_values().mask_type()); + if (get_clip_box(graphics_element)) return Gfx::Bitmap::MaskKind::Alpha; return {}; } @@ -77,11 +93,11 @@ RefPtr SVGMaskable::calculate_mask_of_svg(PaintContext& context, CS return mask_bitmap; }; RefPtr mask_bitmap = {}; - if (auto* mask_box = graphics_element.layout_node()->first_child_of_type()) { + if (auto* mask_box = get_mask_box(graphics_element)) { auto& mask_paintable = static_cast(*mask_box->paintable()); mask_bitmap = paint_mask_or_clip(mask_paintable); } - if (auto* clip_box = graphics_element.layout_node()->first_child_of_type()) { + if (auto* clip_box = get_clip_box(graphics_element)) { auto& clip_paintable = static_cast(*clip_box->paintable()); auto clip_bitmap = paint_mask_or_clip(clip_paintable); // Combine the clip-path with the mask (if present).