diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2020-10-05 16:14:36 -0700 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-10-10 23:28:41 +0200 |
commit | 455ce0b9c3b88d06758ee0c66d2e6039c0d9cec8 (patch) | |
tree | 12d322c4d1e6dd67c282d40e10597c9342c7e5bb /Libraries/LibWeb/Layout | |
parent | f2055bb509ec2580ca93a2886faeca92c79cf4d3 (diff) | |
download | serenity-455ce0b9c3b88d06758ee0c66d2e6039c0d9cec8.zip |
LibWeb: Create LayoutNodes for each SVG element
This brings the SVG API closer to the rest of LibWeb
Diffstat (limited to 'Libraries/LibWeb/Layout')
-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 |
8 files changed, 369 insertions, 27 deletions
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"; } +}; + +} |