diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 2dda2184f02..8c3081faa78 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -46,10 +46,8 @@ set(SOURCES DOM/HTMLInputElement.cpp DOM/HTMLObjectElement.cpp DOM/HTMLLinkElement.cpp - DOM/HTMLPathElement.cpp DOM/HTMLScriptElement.cpp DOM/HTMLStyleElement.cpp - DOM/HTMLSvgElement.cpp DOM/HTMLTableElement.cpp DOM/HTMLTableCellElement.cpp DOM/HTMLTableRowElement.cpp @@ -57,7 +55,6 @@ set(SOURCES DOM/ImageData.cpp DOM/Node.cpp DOM/ParentNode.cpp - DOM/SvgContext.cpp DOM/TagNames.cpp DOM/Text.cpp DOM/Timer.cpp @@ -82,7 +79,7 @@ set(SOURCES Layout/LayoutNode.cpp Layout/LayoutPosition.cpp Layout/LayoutReplaced.cpp - Layout/LayoutSvg.cpp + Layout/LayoutSVG.cpp Layout/LayoutTable.cpp Layout/LayoutTableCell.cpp Layout/LayoutTableRow.cpp @@ -109,6 +106,12 @@ set(SOURCES Parser/ListOfActiveFormattingElements.cpp Parser/StackOfOpenElements.cpp StylePropertiesModel.cpp + SVG/SVGElement.cpp + SVG/SVGGeometryElement.cpp + SVG/SVGGraphicsElement.cpp + SVG/SVGPathElement.cpp + SVG/SVGSVGElement.cpp + SVG/TagNames.cpp URLEncoder.cpp CSS/PropertyID.h CSS/PropertyID.cpp diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index fe0e47ce17e..282531f4fb2 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include namespace Web { @@ -69,6 +70,7 @@ Document::Document(const URL& url) { HTML::AttributeNames::initialize(); HTML::TagNames::initialize(); + SVG::TagNames::initialize(); m_style_update_timer = Core::Timer::create_single_shot(0, [this] { update_style(); diff --git a/Libraries/LibWeb/DOM/ElementFactory.cpp b/Libraries/LibWeb/DOM/ElementFactory.cpp index cb980db4b4d..5349fb9fb6e 100644 --- a/Libraries/LibWeb/DOM/ElementFactory.cpp +++ b/Libraries/LibWeb/DOM/ElementFactory.cpp @@ -41,14 +41,15 @@ #include #include #include -#include #include #include -#include #include #include #include #include +#include +#include +#include namespace Web { @@ -99,10 +100,10 @@ NonnullRefPtr create_element(Document& document, const FlyString& tag_n return adopt(*new HTMLCanvasElement(document, lowercase_tag_name)); if (lowercase_tag_name == HTML::TagNames::object) return adopt(*new HTMLObjectElement(document, lowercase_tag_name)); - if (lowercase_tag_name == HTML::TagNames::svg) - return adopt(*new HTMLSvgElement(document, lowercase_tag_name)); - if (lowercase_tag_name == HTML::TagNames::path) - return adopt(*new HTMLPathElement(document, lowercase_tag_name)); + if (lowercase_tag_name == SVG::TagNames::svg) + return adopt(*new SVG::SVGSVGElement(document, lowercase_tag_name)); + if (lowercase_tag_name == SVG::TagNames::path) + return adopt(*new SVG::SVGPathElement(document, lowercase_tag_name)); return adopt(*new Element(document, lowercase_tag_name)); } diff --git a/Libraries/LibWeb/Layout/LayoutSvg.cpp b/Libraries/LibWeb/Layout/LayoutSVG.cpp similarity index 87% rename from Libraries/LibWeb/Layout/LayoutSvg.cpp rename to Libraries/LibWeb/Layout/LayoutSVG.cpp index c282e4c98ad..455151aaba1 100644 --- a/Libraries/LibWeb/Layout/LayoutSvg.cpp +++ b/Libraries/LibWeb/Layout/LayoutSVG.cpp @@ -27,16 +27,16 @@ #include #include #include -#include +#include namespace Web { -LayoutSvg::LayoutSvg(Document& document, const HTMLSvgElement& element, NonnullRefPtr style) +LayoutSVG::LayoutSVG(Document& document, const SVG::SVGSVGElement& element, NonnullRefPtr style) : LayoutReplaced(document, element, move(style)) { } -void LayoutSvg::layout(LayoutMode layout_mode) +void LayoutSVG::layout(LayoutMode layout_mode) { set_has_intrinsic_width(true); set_has_intrinsic_height(true); @@ -45,7 +45,7 @@ void LayoutSvg::layout(LayoutMode layout_mode) LayoutReplaced::layout(layout_mode); } -void LayoutSvg::paint(PaintContext& context, PaintPhase phase) +void LayoutSVG::paint(PaintContext& context, PaintPhase phase) { if (!is_visible()) return; @@ -57,7 +57,7 @@ void LayoutSvg::paint(PaintContext& context, PaintPhase phase) return; if (!node().bitmap()) - node().create_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()); diff --git a/Libraries/LibWeb/Layout/LayoutSvg.h b/Libraries/LibWeb/Layout/LayoutSVG.h similarity index 82% rename from Libraries/LibWeb/Layout/LayoutSvg.h rename to Libraries/LibWeb/Layout/LayoutSVG.h index dd5035c201d..fd72e9f22af 100644 --- a/Libraries/LibWeb/Layout/LayoutSvg.h +++ b/Libraries/LibWeb/Layout/LayoutSVG.h @@ -26,21 +26,22 @@ #pragma once -#include +#include #include +#include namespace Web { -class HTMLSvgElement; +class SVGSVGElement; -class LayoutSvg : public LayoutReplaced { +class LayoutSVG : public LayoutReplaced { public: - LayoutSvg(Document&, const HTMLSvgElement&, NonnullRefPtr); - virtual ~LayoutSvg() override = default; + LayoutSVG(Document&, const SVG::SVGSVGElement&, NonnullRefPtr); + virtual ~LayoutSVG() override = default; virtual void layout(LayoutMode = LayoutMode::Default) override; virtual void paint(PaintContext&, PaintPhase) override; - HTMLSvgElement& node() { return static_cast(LayoutReplaced::node()); } + SVG::SVGSVGElement& node() { return static_cast(LayoutReplaced::node()); } private: virtual const char* class_name() const override { return "LayoutSvg"; } diff --git a/Libraries/LibWeb/SVG/SVGElement.cpp b/Libraries/LibWeb/SVG/SVGElement.cpp new file mode 100644 index 00000000000..d351af3dd65 --- /dev/null +++ b/Libraries/LibWeb/SVG/SVGElement.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * 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 + +namespace Web::SVG { + +SVGElement::SVGElement(Document& document, const FlyString& tag_name) + : Element(document, tag_name) +{ +} + +} diff --git a/Libraries/LibWeb/DOM/SvgContext.h b/Libraries/LibWeb/SVG/SVGElement.h similarity index 66% rename from Libraries/LibWeb/DOM/SvgContext.h rename to Libraries/LibWeb/SVG/SVGElement.h index dd95a05bc77..3bd813eb4ab 100644 --- a/Libraries/LibWeb/DOM/SvgContext.h +++ b/Libraries/LibWeb/SVG/SVGElement.h @@ -26,30 +26,13 @@ #pragma once -#include -#include +#include -namespace Web { +namespace Web::SVG { -struct SvgPaintingContext { - Gfx::Color fill_color { Gfx::Color::Black }; - Gfx::Color stroke_color { Gfx::Color::Black }; - float stroke_width { 1 }; -}; - -class SvgGraphicElement { +class SVGElement : public Element { public: - virtual void paint(const SvgPaintingContext&, Gfx::Painter& painter) = 0; - void parse_attribute(const FlyString& name, const String& value); - -protected: - Gfx::Color fill_color(const SvgPaintingContext&) const; - Gfx::Color stroke_color(const SvgPaintingContext&) const; - float stroke_width(const SvgPaintingContext&) const; - - Optional m_fill_color; - Optional m_stroke_color; - Optional m_stroke_width; + SVGElement(Document&, const FlyString& tag_name); }; } diff --git a/Libraries/LibWeb/SVG/SVGGeometryElement.cpp b/Libraries/LibWeb/SVG/SVGGeometryElement.cpp new file mode 100644 index 00000000000..004af0383dd --- /dev/null +++ b/Libraries/LibWeb/SVG/SVGGeometryElement.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * 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 + +namespace Web::SVG { + +SVGGeometryElement::SVGGeometryElement(Document& document, const FlyString& tag_name) + : SVGGraphicsElement(document, tag_name) +{ +} + +} diff --git a/Libraries/LibWeb/SVG/SVGGeometryElement.h b/Libraries/LibWeb/SVG/SVGGeometryElement.h new file mode 100644 index 00000000000..7e58e0009a9 --- /dev/null +++ b/Libraries/LibWeb/SVG/SVGGeometryElement.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * 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 + +namespace Web::SVG { + +class SVGGeometryElement : public SVGGraphicsElement { +public: + SVGGeometryElement(Document& document, const FlyString& tag_name); +}; + +} diff --git a/Libraries/LibWeb/DOM/SvgContext.cpp b/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp similarity index 60% rename from Libraries/LibWeb/DOM/SvgContext.cpp rename to Libraries/LibWeb/SVG/SVGGraphicsElement.cpp index c89054f59c2..d15d5f5d7db 100644 --- a/Libraries/LibWeb/DOM/SvgContext.cpp +++ b/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp @@ -24,37 +24,37 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include +#include -namespace Web { +namespace Web::SVG { -void SvgGraphicElement::parse_attribute(const FlyString& name, const String& value) +SVGGraphicsElement::SVGGraphicsElement(Document& document, const FlyString& tag_name) + : SVGElement(document, tag_name) { - if (name == "stroke-width") { - m_stroke_width = strtof(value.characters(), nullptr); +} + +void SVGGraphicsElement::parse_attribute(const FlyString& name, const String& value) +{ + SVGElement::parse_attribute(name, value); + + if (name == "fill") { + m_fill_color = Gfx::Color::from_string(value).value_or(Color::Transparent); } else if (name == "stroke") { - auto result = Gfx::Color::from_string(value); - m_stroke_color = result.value_or(Gfx::Color::Transparent); - } else if (name == "fill") { - auto result = Gfx::Color::from_string(value); - m_fill_color = result.value_or(Gfx::Color::Transparent); + m_stroke_color = Gfx::Color::from_string(value).value_or(Color::Transparent); + } else if (name == "stroke-width") { + auto result = value.to_int(); + if (result.has_value()) + m_stroke_width = result.value(); } } -Gfx::Color SvgGraphicElement::fill_color(const SvgPaintingContext& context) const +SVGPaintingContext SVGGraphicsElement::make_painting_context_from(const SVGPaintingContext& context) { - return m_fill_color.value_or(context.fill_color); -} - -Gfx::Color SvgGraphicElement::stroke_color(const SvgPaintingContext& context) const -{ - return m_stroke_color.value_or(context.stroke_color); -} - -float SvgGraphicElement::stroke_width(const SvgPaintingContext& context) const -{ - return m_stroke_width.value_or(context.stroke_width); + 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 new file mode 100644 index 00000000000..1867c5b7a45 --- /dev/null +++ b/Libraries/LibWeb/SVG/SVGGraphicsElement.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * 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 +#include +#include +#include + +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: + SVGGraphicsElement(Document&, const FlyString& tag_name); + + 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); + +protected: + Optional m_fill_color; + Optional m_stroke_color; + Optional m_stroke_width; +}; + +} + +namespace Web { + +template<> +inline bool is(const Node& node) +{ + if (!is(node)) + return false; + + auto tag_name = to(node).tag_name(); + +#define __ENUMERATE_SVG_TAG(name) \ + if (tag_name == #name) \ + return true; + ENUMERATE_SVG_TAGS +#undef ENUMERATE_SVG_TAG + + return false; +} + +} diff --git a/Libraries/LibWeb/DOM/HTMLPathElement.cpp b/Libraries/LibWeb/SVG/SVGPathElement.cpp similarity index 96% rename from Libraries/LibWeb/DOM/HTMLPathElement.cpp rename to Libraries/LibWeb/SVG/SVGPathElement.cpp index 5280ad128d6..3ca36651344 100644 --- a/Libraries/LibWeb/DOM/HTMLPathElement.cpp +++ b/Libraries/LibWeb/SVG/SVGPathElement.cpp @@ -25,15 +25,16 @@ */ #include +#include #include #include #include -#include +#include #include //#define PATH_DEBUG -namespace Web { +namespace Web::SVG { PathDataParser::PathDataParser(const String& source) : m_source(source) @@ -269,7 +270,7 @@ void PathDataParser::parse_whitespace(bool must_match_once) matched = true; } - ASSERT(!must_match_once || matched); + ASSERT(!must_match_once || matched); } void PathDataParser::parse_comma_whitespace() @@ -326,7 +327,7 @@ float PathDataParser::parse_number() float PathDataParser::parse_flag() { auto number = parse_number(); - ASSERT(number == 0 || number == 1); + ASSERT(number == 0 || number == 1); return number; } @@ -348,8 +349,8 @@ bool PathDataParser::match_number() const return !done() && (isdigit(ch()) || ch() == '-' || ch() == '+'); } -HTMLPathElement::HTMLPathElement(Document& document, const FlyString& tag_name) - : HTMLElement(document, tag_name) +SVGPathElement::SVGPathElement(Document& document, const FlyString& tag_name) + : SVGGeometryElement(document, tag_name) { } @@ -414,16 +415,15 @@ static void print_instruction(const PathInstruction& instruction) } #endif -void HTMLPathElement::parse_attribute(const FlyString& name, const String& value) +void SVGPathElement::parse_attribute(const FlyString& name, const String& value) { - HTMLElement::parse_attribute(name, value); - SvgGraphicElement::parse_attribute(name, value); + SVGGeometryElement::parse_attribute(name, value); if (name == "d") m_instructions = PathDataParser(value).parse(); } -void HTMLPathElement::paint(const SvgPaintingContext& context, Gfx::Painter& painter) +void SVGPathElement::paint(Gfx::Painter& painter, const SVGPaintingContext& context) { Gfx::Path path; @@ -595,9 +595,8 @@ void HTMLPathElement::paint(const SvgPaintingContext& context, Gfx::Painter& pai 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(context), Gfx::Painter::WindingRule::EvenOdd); - painter.stroke_path(path, stroke_color(context), stroke_width(context)); - + 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)); } } diff --git a/Libraries/LibWeb/DOM/HTMLPathElement.h b/Libraries/LibWeb/SVG/SVGPathElement.h similarity index 87% rename from Libraries/LibWeb/DOM/HTMLPathElement.h rename to Libraries/LibWeb/SVG/SVGPathElement.h index 8a29f866e85..ad17d1780d6 100644 --- a/Libraries/LibWeb/DOM/HTMLPathElement.h +++ b/Libraries/LibWeb/SVG/SVGPathElement.h @@ -28,9 +28,9 @@ #include #include -#include +#include -namespace Web { +namespace Web::SVG { enum class PathInstructionType { Move, @@ -100,24 +100,16 @@ private: Vector m_instructions; }; -class HTMLPathElement final - : public HTMLElement - , public SvgGraphicElement { +class SVGPathElement final : public SVGGeometryElement { public: - HTMLPathElement(Document&, const FlyString& tag_name); - virtual ~HTMLPathElement() override = default; + SVGPathElement(Document&, const FlyString& tag_name); + virtual ~SVGPathElement() override = default; virtual void parse_attribute(const FlyString& name, const String& value) override; - virtual void paint(const SvgPaintingContext&, Gfx::Painter& painter) override; + virtual void paint(Gfx::Painter& painter, const SVGPaintingContext& context) override; private: Vector m_instructions; }; -template<> -inline bool is(const Node& node) -{ - return is(node) && to(node).tag_name() == HTML::TagNames::path; -} - } diff --git a/Libraries/LibWeb/DOM/HTMLSvgElement.cpp b/Libraries/LibWeb/SVG/SVGSVGElement.cpp similarity index 57% rename from Libraries/LibWeb/DOM/HTMLSvgElement.cpp rename to Libraries/LibWeb/SVG/SVGSVGElement.cpp index 53bba76f376..b801eb71d43 100644 --- a/Libraries/LibWeb/DOM/HTMLSvgElement.cpp +++ b/Libraries/LibWeb/SVG/SVGSVGElement.cpp @@ -24,47 +24,34 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include #include -#include -#include -#include +#include +#include +#include #include -namespace Web { +namespace Web::SVG { static constexpr auto max_svg_area = 16384 * 16384; -HTMLSvgElement::HTMLSvgElement(Document& document, const FlyString& tag_name) - : HTMLElement(document, tag_name) +SVGSVGElement::SVGSVGElement(Document& document, const FlyString& tag_name) + : SVGGraphicsElement(document, tag_name) { } -void HTMLSvgElement::parse_attribute(const FlyString& name, const String& value) -{ - HTMLElement::parse_attribute(name, value); - if (name == "stroke") { - m_stroke_color = Gfx::Color::from_string(value); - } else if (name == "stroke-width") { - auto result = value.to_int(); - if (result.has_value()) - m_stroke_width = result.value(); - } else if (name == "fill") { - m_fill_color = Gfx::Color::from_string(value); - } -} - -RefPtr HTMLSvgElement::create_layout_node(const StyleProperties* parent_style) +RefPtr SVGSVGElement::create_layout_node(const StyleProperties* parent_style) { 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))); + return adopt(*new LayoutSVG(document(), *this, move(style))); } -static Gfx::IntSize bitmap_size_for_canvas(const HTMLSvgElement& canvas) +static Gfx::IntSize bitmap_size_for_canvas(const SVGSVGElement& canvas) { auto width = canvas.width(); auto height = canvas.height(); @@ -83,7 +70,7 @@ static Gfx::IntSize bitmap_size_for_canvas(const HTMLSvgElement& canvas) return Gfx::IntSize(width, height); } -bool HTMLSvgElement::create_bitmap() +bool SVGSVGElement::create_bitmap_as_top_level_svg_element() { auto size = bitmap_size_for_canvas(*this); if (size.is_empty()) { @@ -95,55 +82,26 @@ bool HTMLSvgElement::create_bitmap() m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, size); Gfx::Painter painter(*m_bitmap); - paint(painter); + paint(painter, make_painting_context_from(default_painting_context)); return m_bitmap; } -SvgPaintingContext HTMLSvgElement::make_context() const -{ - SvgPaintingContext context; - - if (m_stroke_width.has_value()) - context.stroke_width = m_stroke_width.value(); - if (m_stroke_color.has_value()) - context.stroke_color = m_stroke_color.value(); - if (m_fill_color.has_value()) - context.fill_color = m_fill_color.value(); - - return context; -} - -unsigned HTMLSvgElement::width() const +unsigned SVGSVGElement::width() const { return attribute(HTML::AttributeNames::width).to_uint().value_or(300); } -unsigned HTMLSvgElement::height() const +unsigned SVGSVGElement::height() const { return attribute(HTML::AttributeNames::height).to_uint().value_or(150); } -static bool is_svg_graphic_element(const HTMLElement& element) -{ - return is(element); -} - -static SvgGraphicElement& as_svg_graphic_element(HTMLElement& element) -{ - if (is(element)) - return to(element); - ASSERT_NOT_REACHED(); -} - -void HTMLSvgElement::paint(Gfx::Painter& painter) +void SVGSVGElement::paint(Gfx::Painter& painter, const SVGPaintingContext& context) { for_each_child([&](Node& child) { - if (is(child)) { - auto& element = to(child); - if (is_svg_graphic_element(element)) { - as_svg_graphic_element(element).paint(make_context(), painter); - } + if (is(child)) { + to(child).paint(painter, make_painting_context_from(context)); } }); } diff --git a/Libraries/LibWeb/DOM/HTMLSvgElement.h b/Libraries/LibWeb/SVG/SVGSVGElement.h similarity index 71% rename from Libraries/LibWeb/DOM/HTMLSvgElement.h rename to Libraries/LibWeb/SVG/SVGSVGElement.h index 4c39fa1458b..a6bf355fed2 100644 --- a/Libraries/LibWeb/DOM/HTMLSvgElement.h +++ b/Libraries/LibWeb/SVG/SVGSVGElement.h @@ -27,40 +27,26 @@ #pragma once #include -#include -#include +#include -namespace Web { +namespace Web::SVG { -class HTMLSvgElement final : public HTMLElement { +class SVGSVGElement final : public SVGGraphicsElement { public: - HTMLSvgElement(Document&, const FlyString& tag_name); - virtual ~HTMLSvgElement() override = default; + SVGSVGElement(Document&, const FlyString& tag_name); - virtual void parse_attribute(const FlyString& name, const String& value) override; virtual RefPtr create_layout_node(const StyleProperties* parent_style) override; const RefPtr bitmap() const { return m_bitmap; } - bool create_bitmap(); - SvgPaintingContext make_context() const; + bool create_bitmap_as_top_level_svg_element(); + + virtual void paint(Gfx::Painter& painter, const SVGPaintingContext& context) override; unsigned width() const; unsigned height() const; private: - void paint(Gfx::Painter&); - RefPtr m_bitmap; - - Optional m_stroke_width; - Optional m_stroke_color; - Optional m_fill_color; }; -template<> -inline bool is(const Node& node) -{ - return is(node) && to(node).tag_name() == HTML::TagNames::svg; -} - } diff --git a/Libraries/LibWeb/SVG/TagNames.cpp b/Libraries/LibWeb/SVG/TagNames.cpp new file mode 100644 index 00000000000..0ebb623521b --- /dev/null +++ b/Libraries/LibWeb/SVG/TagNames.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * 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 + +namespace Web::SVG::TagNames { + +#define __ENUMERATE_SVG_TAG(name) FlyString name; + ENUMERATE_SVG_TAGS +#undef __ENUMERATE_SVG_TAG + +void initialize() +{ + static bool s_initialized = false; + if (s_initialized) + return; + +#define __ENUMERATE_SVG_TAG(name) name = #name; + ENUMERATE_SVG_TAGS +#undef __ENUMERATE_SVG_TAG + + s_initialized = true; +} + +} diff --git a/Libraries/LibWeb/SVG/TagNames.h b/Libraries/LibWeb/SVG/TagNames.h new file mode 100644 index 00000000000..85f74bfe3b9 --- /dev/null +++ b/Libraries/LibWeb/SVG/TagNames.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020, Matthew Olsson + * 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 + +namespace Web::SVG::TagNames { + +void initialize(); + +#define ENUMERATE_SVG_GRAPHICS_TAGS \ + __ENUMERATE_SVG_TAG(svg) \ + __ENUMERATE_SVG_TAG(path) \ + +#define ENUMERATE_SVG_TAGS \ + ENUMERATE_SVG_GRAPHICS_TAGS + +#define __ENUMERATE_SVG_TAG(name) extern FlyString name; +ENUMERATE_SVG_TAGS +#undef __ENUMERATE_SVG_TAG + +}