diff options
-rw-r--r-- | Libraries/LibWeb/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutSVG.cpp | 32 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutSVG.h | 10 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutSVGGraphics.cpp | 59 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutSVGGraphics.h | 47 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutSVGPath.cpp | 88 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutSVGPath.h | 47 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutSVGSVG.cpp | 63 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutSVGSVG.h | 50 | ||||
-rw-r--r-- | Libraries/LibWeb/SVG/SVGContext.h | 7 | ||||
-rw-r--r-- | Libraries/LibWeb/SVG/SVGGraphicsElement.cpp | 9 | ||||
-rw-r--r-- | Libraries/LibWeb/SVG/SVGGraphicsElement.h | 18 | ||||
-rw-r--r-- | Libraries/LibWeb/SVG/SVGPathElement.cpp | 25 | ||||
-rw-r--r-- | Libraries/LibWeb/SVG/SVGPathElement.h | 6 | ||||
-rw-r--r-- | Libraries/LibWeb/SVG/SVGSVGElement.cpp | 51 | ||||
-rw-r--r-- | Libraries/LibWeb/SVG/SVGSVGElement.h | 5 |
16 files changed, 400 insertions, 120 deletions
diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 54f8208f98..309daabf70 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -148,6 +148,9 @@ set(SOURCES Layout/LayoutPosition.cpp Layout/LayoutReplaced.cpp Layout/LayoutSVG.cpp + Layout/LayoutSVGGraphics.cpp + Layout/LayoutSVGPath.cpp + Layout/LayoutSVGSVG.cpp Layout/LayoutTable.cpp Layout/LayoutTableCell.cpp Layout/LayoutTableRow.cpp diff --git a/Libraries/LibWeb/Layout/LayoutSVG.cpp b/Libraries/LibWeb/Layout/LayoutSVG.cpp index beac60417b..b5ea0e63a9 100644 --- a/Libraries/LibWeb/Layout/LayoutSVG.cpp +++ b/Libraries/LibWeb/Layout/LayoutSVG.cpp @@ -31,37 +31,25 @@ namespace Web { -LayoutSVG::LayoutSVG(DOM::Document& document, SVG::SVGSVGElement& element, NonnullRefPtr<CSS::StyleProperties> style) +LayoutSVG::LayoutSVG(DOM::Document& document, SVG::SVGElement& element, NonnullRefPtr<CSS::StyleProperties> style) : LayoutReplaced(document, element, move(style)) { } -void LayoutSVG::layout(LayoutMode layout_mode) +void LayoutSVG::before_children_paint(PaintContext& context, LayoutNode::PaintPhase phase) { - set_has_intrinsic_width(true); - set_has_intrinsic_height(true); - set_intrinsic_width(node().width()); - set_intrinsic_height(node().height()); - LayoutReplaced::layout(layout_mode); + LayoutNode::before_children_paint(context, phase); + if (phase != LayoutNode::PaintPhase::Foreground) + return; + context.svg_context().save(); } -void LayoutSVG::paint(PaintContext& context, PaintPhase phase) +void LayoutSVG::after_children_paint(PaintContext& context, LayoutNode::PaintPhase phase) { - if (!is_visible()) + LayoutNode::after_children_paint(context, phase); + if (phase != LayoutNode::PaintPhase::Foreground) return; - - LayoutReplaced::paint(context, phase); - - if (phase == PaintPhase::Foreground) { - if (!context.viewport_rect().intersects(enclosing_int_rect(absolute_rect()))) - return; - - if (!node().bitmap()) - node().create_bitmap_as_top_level_svg_element(); - - ASSERT(node().bitmap()); - context.painter().draw_scaled_bitmap(enclosing_int_rect(absolute_rect()), *node().bitmap(), node().bitmap()->rect()); - } + context.svg_context().restore(); } } diff --git a/Libraries/LibWeb/Layout/LayoutSVG.h b/Libraries/LibWeb/Layout/LayoutSVG.h index d5deb38f6e..3ae7ae9cb4 100644 --- a/Libraries/LibWeb/Layout/LayoutSVG.h +++ b/Libraries/LibWeb/Layout/LayoutSVG.h @@ -27,18 +27,18 @@ #pragma once #include <LibWeb/Layout/LayoutReplaced.h> -#include <LibWeb/SVG/SVGSVGElement.h> +#include <LibWeb/SVG/SVGElement.h> +#include <LibWeb/SVG/SVGGraphicsElement.h> namespace Web { class LayoutSVG : public LayoutReplaced { public: - LayoutSVG(DOM::Document&, SVG::SVGSVGElement&, NonnullRefPtr<CSS::StyleProperties>); + LayoutSVG(DOM::Document&, SVG::SVGElement&, NonnullRefPtr<CSS::StyleProperties>); virtual ~LayoutSVG() override = default; - virtual void layout(LayoutMode = LayoutMode::Default) override; - virtual void paint(PaintContext&, PaintPhase) override; - SVG::SVGSVGElement& node() { return static_cast<SVG::SVGSVGElement&>(LayoutReplaced::node()); } + virtual void before_children_paint(PaintContext& context, PaintPhase phase) override; + virtual void after_children_paint(PaintContext& context, PaintPhase phase) override; private: virtual const char* class_name() const override { return "LayoutSVG"; } diff --git a/Libraries/LibWeb/Layout/LayoutSVGGraphics.cpp b/Libraries/LibWeb/Layout/LayoutSVGGraphics.cpp new file mode 100644 index 0000000000..91d3c9e9b7 --- /dev/null +++ b/Libraries/LibWeb/Layout/LayoutSVGGraphics.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <LibWeb/Layout/LayoutSVGGraphics.h> + +namespace Web { + +LayoutSVGGraphics::LayoutSVGGraphics(DOM::Document& document, SVG::SVGGraphicsElement& element, NonnullRefPtr<CSS::StyleProperties> properties) + : LayoutSVG(document, element, properties) +{ +} + +void LayoutSVGGraphics::before_children_paint(PaintContext& context, LayoutNode::PaintPhase phase) +{ + LayoutSVG::before_children_paint(context, phase); + if (phase != LayoutNode::PaintPhase::Foreground) + return; + + auto& graphics_element = downcast<SVG::SVGGraphicsElement>(node()); + + if (graphics_element.fill_color().has_value()) + context.svg_context().set_fill_color(graphics_element.fill_color().value()); + if (graphics_element.stroke_color().has_value()) + context.svg_context().set_stroke_color(graphics_element.stroke_color().value()); + if (graphics_element.stroke_width().has_value()) + context.svg_context().set_stroke_width(graphics_element.stroke_width().value()); +} + +void LayoutSVGGraphics::layout(LayoutNode::LayoutMode mode) +{ + LayoutReplaced::layout(mode); + + for_each_child([&](auto& child) { child.layout(mode); }); +} + +} diff --git a/Libraries/LibWeb/Layout/LayoutSVGGraphics.h b/Libraries/LibWeb/Layout/LayoutSVGGraphics.h new file mode 100644 index 0000000000..36cdd8e025 --- /dev/null +++ b/Libraries/LibWeb/Layout/LayoutSVGGraphics.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <LibWeb/Layout/LayoutSVG.h> +#include <LibWeb/SVG/SVGElement.h> +#include <LibWeb/SVG/SVGGraphicsElement.h> + +namespace Web { + +class LayoutSVGGraphics : public LayoutSVG { +public: + LayoutSVGGraphics(DOM::Document&, SVG::SVGGraphicsElement&, NonnullRefPtr<CSS::StyleProperties>); + virtual ~LayoutSVGGraphics() override = default; + + virtual void layout(LayoutMode mode) override; + virtual void before_children_paint(PaintContext& context, LayoutNode::PaintPhase phase) override; + +private: + virtual const char* class_name() const override { return "LayoutSVGGraphics"; } +}; + +} diff --git a/Libraries/LibWeb/Layout/LayoutSVGPath.cpp b/Libraries/LibWeb/Layout/LayoutSVGPath.cpp new file mode 100644 index 0000000000..2d6e554f8a --- /dev/null +++ b/Libraries/LibWeb/Layout/LayoutSVGPath.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <LibGfx/Painter.h> +#include <LibWeb/Layout/LayoutSVGPath.h> +#include <LibWeb/SVG/SVGPathElement.h> + +namespace Web { + +LayoutSVGPath::LayoutSVGPath(DOM::Document& document, SVG::SVGPathElement& element, NonnullRefPtr<CSS::StyleProperties> properties) + : LayoutSVGGraphics(document, element, properties) +{ +} + +void LayoutSVGPath::layout(LayoutNode::LayoutMode mode) +{ + auto& bounding_box = node().get_path().bounding_box(); + set_has_intrinsic_width(true); + set_has_intrinsic_height(true); + set_intrinsic_width(bounding_box.width()); + set_intrinsic_height(bounding_box.height()); + set_offset(bounding_box.top_left()); + LayoutSVGGraphics::layout(mode); +} + +void LayoutSVGPath::paint(PaintContext& context, LayoutNode::PaintPhase phase) +{ + if (!is_visible()) + return; + + LayoutSVGGraphics::paint(context, phase); + + if (phase != LayoutNode::PaintPhase::Foreground) + return; + + auto& path_element = node(); + auto& path = path_element.get_path(); + + // 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) + auto& painter = context.painter(); + auto& svg_context = context.svg_context(); + + auto offset = (absolute_position() - effective_offset()).to_type<int>(); + + painter.translate(offset); + + painter.fill_path( + closed_path, + path_element.fill_color().value_or(svg_context.fill_color()), + Gfx::Painter::WindingRule::EvenOdd); + painter.stroke_path( + path, + path_element.stroke_color().value_or(svg_context.stroke_color()), + path_element.stroke_width().value_or(svg_context.stroke_width())); + + painter.translate(-offset); +} + +} diff --git a/Libraries/LibWeb/Layout/LayoutSVGPath.h b/Libraries/LibWeb/Layout/LayoutSVGPath.h new file mode 100644 index 0000000000..a8ed8c725c --- /dev/null +++ b/Libraries/LibWeb/Layout/LayoutSVGPath.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <LibWeb/Layout/LayoutSVGGraphics.h> + +namespace Web { + +class LayoutSVGPath final : public LayoutSVGGraphics { +public: + LayoutSVGPath(DOM::Document&, SVG::SVGPathElement&, NonnullRefPtr<CSS::StyleProperties>); + virtual ~LayoutSVGPath() override = default; + + SVG::SVGPathElement& node() { return downcast<SVG::SVGPathElement>(LayoutSVGGraphics::node()); } + + void layout(LayoutMode mode) override; + void paint(PaintContext& context, PaintPhase phase) override; + +private: + virtual const char* class_name() const override { return "LayoutSVGPath"; } +}; + +} diff --git a/Libraries/LibWeb/Layout/LayoutSVGSVG.cpp b/Libraries/LibWeb/Layout/LayoutSVGSVG.cpp new file mode 100644 index 0000000000..c67fac9320 --- /dev/null +++ b/Libraries/LibWeb/Layout/LayoutSVGSVG.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <LibWeb/Layout/LayoutSVGSVG.h> + +namespace Web { + +LayoutSVGSVG::LayoutSVGSVG(DOM::Document& document, SVG::SVGSVGElement& element, NonnullRefPtr<CSS::StyleProperties> properties) + : LayoutSVGGraphics(document, element, properties) +{ +} + +void LayoutSVGSVG::layout(LayoutMode layout_mode) +{ + set_has_intrinsic_width(true); + set_has_intrinsic_height(true); + set_intrinsic_width(node().width()); + set_intrinsic_height(node().height()); + LayoutSVGGraphics::layout(layout_mode); +} + +void LayoutSVGSVG::before_children_paint(PaintContext& context, LayoutNode::PaintPhase phase) +{ + if (phase != LayoutNode::PaintPhase::Foreground) + return; + + if (!context.has_svg_context()) + context.set_svg_context(SVGContext()); + + LayoutSVGGraphics::before_children_paint(context, phase); +} + +void LayoutSVGSVG::after_children_paint(PaintContext& context, LayoutNode::PaintPhase phase) +{ + LayoutSVGGraphics::after_children_paint(context, phase); + if (phase != LayoutNode::PaintPhase::Foreground) + return; +} + +} diff --git a/Libraries/LibWeb/Layout/LayoutSVGSVG.h b/Libraries/LibWeb/Layout/LayoutSVGSVG.h new file mode 100644 index 0000000000..ed0aae5328 --- /dev/null +++ b/Libraries/LibWeb/Layout/LayoutSVGSVG.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <LibWeb/Layout/LayoutSVGGraphics.h> +#include <LibWeb/SVG/SVGSVGElement.h> + +namespace Web { + +class LayoutSVGSVG final : public LayoutSVGGraphics { +public: + LayoutSVGSVG(DOM::Document&, SVG::SVGSVGElement&, NonnullRefPtr<CSS::StyleProperties>); + ~LayoutSVGSVG() override = default; + + SVG::SVGSVGElement& node() { return downcast<SVG::SVGSVGElement>(LayoutSVGGraphics::node()); } + + void layout(LayoutMode = LayoutMode::Default) override; + + void before_children_paint(PaintContext& context, LayoutNode::PaintPhase phase) override; + void after_children_paint(PaintContext& context, PaintPhase phase) override; + +private: + const char* class_name() const override { return "LayoutSVGSVG"; } +}; + +} diff --git a/Libraries/LibWeb/SVG/SVGContext.h b/Libraries/LibWeb/SVG/SVGContext.h index 5dfa282322..ec7fe72eff 100644 --- a/Libraries/LibWeb/SVG/SVGContext.h +++ b/Libraries/LibWeb/SVG/SVGContext.h @@ -32,7 +32,7 @@ class SVGContext { public: SVGContext() { - push_state(); + m_states.append(State()); } const Gfx::Color& fill_color() const { return state().fill_color; } @@ -43,9 +43,8 @@ public: void set_stroke_color(Gfx::Color color) { state().stroke_color = color; } void set_stroke_width(float width) { state().stroke_width = width; } - void push_state() { m_states.append(State()); } - - void pop_state() { m_states.take_last(); } + void save() { m_states.append(m_states.last()); } + void restore() { m_states.take_last(); } private: struct State { diff --git a/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp b/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp index 8844abc0dd..1e7556d693 100644 --- a/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp +++ b/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp @@ -48,13 +48,4 @@ void SVGGraphicsElement::parse_attribute(const FlyString& name, const String& va } } -SVGPaintingContext SVGGraphicsElement::make_painting_context_from(const SVGPaintingContext& context) -{ - return SVGPaintingContext { - m_fill_color.value_or(context.fill_color), - m_stroke_color.value_or(context.stroke_color), - m_stroke_width.value_or(context.stroke_width), - }; -} - } diff --git a/Libraries/LibWeb/SVG/SVGGraphicsElement.h b/Libraries/LibWeb/SVG/SVGGraphicsElement.h index c100ce91ce..413ca16001 100644 --- a/Libraries/LibWeb/SVG/SVGGraphicsElement.h +++ b/Libraries/LibWeb/SVG/SVGGraphicsElement.h @@ -33,18 +33,6 @@ namespace Web::SVG { -struct SVGPaintingContext { - Gfx::Color fill_color; - Gfx::Color stroke_color; - float stroke_width; -}; - -static const SVGPaintingContext default_painting_context = { - Gfx::Color::Black, - Gfx::Color::Black, - 1.0f -}; - class SVGGraphicsElement : public SVGElement { public: using WrapperType = Bindings::SVGGraphicsElementWrapper; @@ -53,9 +41,9 @@ public: virtual void parse_attribute(const FlyString& name, const String& value) override; - virtual void paint(Gfx::Painter& painter, const SVGPaintingContext& context) = 0; - - SVGPaintingContext make_painting_context_from(const SVGPaintingContext& context); + const Optional<Gfx::Color>& fill_color() const { return m_fill_color; } + const Optional<Gfx::Color>& stroke_color() const { return m_stroke_color; } + const Optional<float>& stroke_width() const { return m_stroke_width; } protected: Optional<Gfx::Color> m_fill_color; diff --git a/Libraries/LibWeb/SVG/SVGPathElement.cpp b/Libraries/LibWeb/SVG/SVGPathElement.cpp index 0bcbc218a0..add1460cd7 100644 --- a/Libraries/LibWeb/SVG/SVGPathElement.cpp +++ b/Libraries/LibWeb/SVG/SVGPathElement.cpp @@ -29,6 +29,7 @@ #include <LibGfx/Path.h> #include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Event.h> +#include <LibWeb/Layout/LayoutSVGPath.h> #include <LibWeb/SVG/SVGPathElement.h> #include <ctype.h> @@ -429,6 +430,14 @@ SVGPathElement::SVGPathElement(DOM::Document& document, const FlyString& tag_nam { } +RefPtr<LayoutNode> SVGPathElement::create_layout_node(const CSS::StyleProperties* parent_style) +{ + auto style = document().style_resolver().resolve_style(*this, parent_style); + if (style->display() == CSS::Display::None) + return nullptr; + return adopt(*new LayoutSVGPath(document(), *this, move(style))); +} + void SVGPathElement::parse_attribute(const FlyString& name, const String& value) { SVGGeometryElement::parse_attribute(name, value); @@ -437,8 +446,11 @@ void SVGPathElement::parse_attribute(const FlyString& name, const String& value) m_instructions = PathDataParser(value).parse(); } -void SVGPathElement::paint(Gfx::Painter& painter, const SVGPaintingContext& context) +Gfx::Path& SVGPathElement::get_path() { + if (m_path.has_value()) + return m_path.value(); + Gfx::Path path; for (auto& instruction : m_instructions) { @@ -640,15 +652,8 @@ void SVGPathElement::paint(Gfx::Painter& painter, const SVGPaintingContext& cont } } - // 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, m_fill_color.value_or(context.fill_color), Gfx::Painter::WindingRule::EvenOdd); - painter.stroke_path(path, m_stroke_color.value_or(context.stroke_color), m_stroke_width.value_or(context.stroke_width)); + m_path = path; + return m_path.value(); } } diff --git a/Libraries/LibWeb/SVG/SVGPathElement.h b/Libraries/LibWeb/SVG/SVGPathElement.h index 887d37e52f..d08d197472 100644 --- a/Libraries/LibWeb/SVG/SVGPathElement.h +++ b/Libraries/LibWeb/SVG/SVGPathElement.h @@ -109,12 +109,16 @@ public: SVGPathElement(DOM::Document&, const FlyString& tag_name); virtual ~SVGPathElement() override = default; + virtual RefPtr<LayoutNode> create_layout_node(const CSS::StyleProperties* parent_style) override; + virtual void parse_attribute(const FlyString& name, const String& value) override; - virtual void paint(Gfx::Painter& painter, const SVGPaintingContext& context) override; + + Gfx::Path& get_path(); private: Vector<PathInstruction> m_instructions; Gfx::FloatPoint m_previous_control_point = {}; + Optional<Gfx::Path> m_path; }; } diff --git a/Libraries/LibWeb/SVG/SVGSVGElement.cpp b/Libraries/LibWeb/SVG/SVGSVGElement.cpp index a7391b889e..c22099c60e 100644 --- a/Libraries/LibWeb/SVG/SVGSVGElement.cpp +++ b/Libraries/LibWeb/SVG/SVGSVGElement.cpp @@ -28,15 +28,13 @@ #include <LibWeb/CSS/StyleResolver.h> #include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Event.h> -#include <LibWeb/Layout/LayoutSVG.h> +#include <LibWeb/Layout/LayoutSVGSVG.h> #include <LibWeb/SVG/SVGPathElement.h> #include <LibWeb/SVG/SVGSVGElement.h> #include <ctype.h> namespace Web::SVG { -static constexpr auto max_svg_area = 16384 * 16384; - SVGSVGElement::SVGSVGElement(DOM::Document& document, const FlyString& tag_name) : SVGGraphicsElement(document, tag_name) { @@ -47,43 +45,7 @@ RefPtr<LayoutNode> SVGSVGElement::create_layout_node(const CSS::StyleProperties* auto style = document().style_resolver().resolve_style(*this, parent_style); if (style->display() == CSS::Display::None) return nullptr; - return adopt(*new LayoutSVG(document(), *this, move(style))); -} - -static Gfx::IntSize bitmap_size_for_canvas(const SVGSVGElement& canvas) -{ - auto width = canvas.width(); - auto height = canvas.height(); - - Checked<size_t> area = width; - area *= height; - - if (area.has_overflow()) { - dbg() << "Refusing to create " << width << "x" << height << " svg (overflow)"; - return {}; - } - if (area.value() > max_svg_area) { - dbg() << "Refusing to create " << width << "x" << height << " svg (exceeds maximum size)"; - return {}; - } - return Gfx::IntSize(width, height); -} - -bool SVGSVGElement::create_bitmap_as_top_level_svg_element() -{ - auto size = bitmap_size_for_canvas(*this); - if (size.is_empty()) { - m_bitmap = nullptr; - return false; - } - - if (!m_bitmap || m_bitmap->size() != size) - m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, size); - - Gfx::Painter painter(*m_bitmap); - paint(painter, make_painting_context_from(default_painting_context)); - - return m_bitmap; + return adopt(*new LayoutSVGSVG(document(), *this, move(style))); } unsigned SVGSVGElement::width() const @@ -96,13 +58,4 @@ unsigned SVGSVGElement::height() const return attribute(HTML::AttributeNames::height).to_uint().value_or(150); } -void SVGSVGElement::paint(Gfx::Painter& painter, const SVGPaintingContext& context) -{ - for_each_child([&](Node& child) { - if (is<SVGGraphicsElement>(child)) { - downcast<SVGGraphicsElement>(child).paint(painter, make_painting_context_from(context)); - } - }); -} - } diff --git a/Libraries/LibWeb/SVG/SVGSVGElement.h b/Libraries/LibWeb/SVG/SVGSVGElement.h index 2f0915fb77..a4e3e46553 100644 --- a/Libraries/LibWeb/SVG/SVGSVGElement.h +++ b/Libraries/LibWeb/SVG/SVGSVGElement.h @@ -39,11 +39,6 @@ public: virtual RefPtr<LayoutNode> create_layout_node(const CSS::StyleProperties* parent_style) override; - const RefPtr<Gfx::Bitmap> bitmap() const { return m_bitmap; } - bool create_bitmap_as_top_level_svg_element(); - - virtual void paint(Gfx::Painter& painter, const SVGPaintingContext& context) override; - unsigned width() const; unsigned height() const; |