1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 18:28:12 +00:00

LibWeb: Refactor SVG files into their own directory; follow spec layout

This commit is contained in:
Matthew Olsson 2020-07-23 09:44:42 -07:00 committed by Andreas Kling
parent 2e73082203
commit b1299f972c
17 changed files with 386 additions and 172 deletions

View file

@ -46,10 +46,8 @@ set(SOURCES
DOM/HTMLInputElement.cpp DOM/HTMLInputElement.cpp
DOM/HTMLObjectElement.cpp DOM/HTMLObjectElement.cpp
DOM/HTMLLinkElement.cpp DOM/HTMLLinkElement.cpp
DOM/HTMLPathElement.cpp
DOM/HTMLScriptElement.cpp DOM/HTMLScriptElement.cpp
DOM/HTMLStyleElement.cpp DOM/HTMLStyleElement.cpp
DOM/HTMLSvgElement.cpp
DOM/HTMLTableElement.cpp DOM/HTMLTableElement.cpp
DOM/HTMLTableCellElement.cpp DOM/HTMLTableCellElement.cpp
DOM/HTMLTableRowElement.cpp DOM/HTMLTableRowElement.cpp
@ -57,7 +55,6 @@ set(SOURCES
DOM/ImageData.cpp DOM/ImageData.cpp
DOM/Node.cpp DOM/Node.cpp
DOM/ParentNode.cpp DOM/ParentNode.cpp
DOM/SvgContext.cpp
DOM/TagNames.cpp DOM/TagNames.cpp
DOM/Text.cpp DOM/Text.cpp
DOM/Timer.cpp DOM/Timer.cpp
@ -82,7 +79,7 @@ set(SOURCES
Layout/LayoutNode.cpp Layout/LayoutNode.cpp
Layout/LayoutPosition.cpp Layout/LayoutPosition.cpp
Layout/LayoutReplaced.cpp Layout/LayoutReplaced.cpp
Layout/LayoutSvg.cpp Layout/LayoutSVG.cpp
Layout/LayoutTable.cpp Layout/LayoutTable.cpp
Layout/LayoutTableCell.cpp Layout/LayoutTableCell.cpp
Layout/LayoutTableRow.cpp Layout/LayoutTableRow.cpp
@ -109,6 +106,12 @@ set(SOURCES
Parser/ListOfActiveFormattingElements.cpp Parser/ListOfActiveFormattingElements.cpp
Parser/StackOfOpenElements.cpp Parser/StackOfOpenElements.cpp
StylePropertiesModel.cpp StylePropertiesModel.cpp
SVG/SVGElement.cpp
SVG/SVGGeometryElement.cpp
SVG/SVGGraphicsElement.cpp
SVG/SVGPathElement.cpp
SVG/SVGSVGElement.cpp
SVG/TagNames.cpp
URLEncoder.cpp URLEncoder.cpp
CSS/PropertyID.h CSS/PropertyID.h
CSS/PropertyID.cpp CSS/PropertyID.cpp

View file

@ -56,6 +56,7 @@
#include <LibWeb/Origin.h> #include <LibWeb/Origin.h>
#include <LibWeb/PageView.h> #include <LibWeb/PageView.h>
#include <LibWeb/Parser/CSSParser.h> #include <LibWeb/Parser/CSSParser.h>
#include <LibWeb/SVG/TagNames.h>
#include <stdio.h> #include <stdio.h>
namespace Web { namespace Web {
@ -69,6 +70,7 @@ Document::Document(const URL& url)
{ {
HTML::AttributeNames::initialize(); HTML::AttributeNames::initialize();
HTML::TagNames::initialize(); HTML::TagNames::initialize();
SVG::TagNames::initialize();
m_style_update_timer = Core::Timer::create_single_shot(0, [this] { m_style_update_timer = Core::Timer::create_single_shot(0, [this] {
update_style(); update_style();

View file

@ -41,14 +41,15 @@
#include <LibWeb/DOM/HTMLInputElement.h> #include <LibWeb/DOM/HTMLInputElement.h>
#include <LibWeb/DOM/HTMLLinkElement.h> #include <LibWeb/DOM/HTMLLinkElement.h>
#include <LibWeb/DOM/HTMLObjectElement.h> #include <LibWeb/DOM/HTMLObjectElement.h>
#include <LibWeb/DOM/HTMLPathElement.h>
#include <LibWeb/DOM/HTMLScriptElement.h> #include <LibWeb/DOM/HTMLScriptElement.h>
#include <LibWeb/DOM/HTMLStyleElement.h> #include <LibWeb/DOM/HTMLStyleElement.h>
#include <LibWeb/DOM/HTMLSvgElement.h>
#include <LibWeb/DOM/HTMLTableCellElement.h> #include <LibWeb/DOM/HTMLTableCellElement.h>
#include <LibWeb/DOM/HTMLTableElement.h> #include <LibWeb/DOM/HTMLTableElement.h>
#include <LibWeb/DOM/HTMLTableRowElement.h> #include <LibWeb/DOM/HTMLTableRowElement.h>
#include <LibWeb/DOM/HTMLTitleElement.h> #include <LibWeb/DOM/HTMLTitleElement.h>
#include <LibWeb/SVG/SVGPathElement.h>
#include <LibWeb/SVG/SVGSVGElement.h>
#include <LibWeb/SVG/TagNames.h>
namespace Web { namespace Web {
@ -99,10 +100,10 @@ NonnullRefPtr<Element> create_element(Document& document, const FlyString& tag_n
return adopt(*new HTMLCanvasElement(document, lowercase_tag_name)); return adopt(*new HTMLCanvasElement(document, lowercase_tag_name));
if (lowercase_tag_name == HTML::TagNames::object) if (lowercase_tag_name == HTML::TagNames::object)
return adopt(*new HTMLObjectElement(document, lowercase_tag_name)); return adopt(*new HTMLObjectElement(document, lowercase_tag_name));
if (lowercase_tag_name == HTML::TagNames::svg) if (lowercase_tag_name == SVG::TagNames::svg)
return adopt(*new HTMLSvgElement(document, lowercase_tag_name)); return adopt(*new SVG::SVGSVGElement(document, lowercase_tag_name));
if (lowercase_tag_name == HTML::TagNames::path) if (lowercase_tag_name == SVG::TagNames::path)
return adopt(*new HTMLPathElement(document, lowercase_tag_name)); return adopt(*new SVG::SVGPathElement(document, lowercase_tag_name));
return adopt(*new Element(document, lowercase_tag_name)); return adopt(*new Element(document, lowercase_tag_name));
} }

View file

@ -27,16 +27,16 @@
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibGfx/Font.h> #include <LibGfx/Font.h>
#include <LibGfx/StylePainter.h> #include <LibGfx/StylePainter.h>
#include <LibWeb/Layout/LayoutSvg.h> #include <LibWeb/Layout/LayoutSVG.h>
namespace Web { namespace Web {
LayoutSvg::LayoutSvg(Document& document, const HTMLSvgElement& element, NonnullRefPtr<StyleProperties> style) LayoutSVG::LayoutSVG(Document& document, const SVG::SVGSVGElement& element, NonnullRefPtr<StyleProperties> style)
: LayoutReplaced(document, element, move(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_width(true);
set_has_intrinsic_height(true); set_has_intrinsic_height(true);
@ -45,7 +45,7 @@ void LayoutSvg::layout(LayoutMode layout_mode)
LayoutReplaced::layout(layout_mode); LayoutReplaced::layout(layout_mode);
} }
void LayoutSvg::paint(PaintContext& context, PaintPhase phase) void LayoutSVG::paint(PaintContext& context, PaintPhase phase)
{ {
if (!is_visible()) if (!is_visible())
return; return;
@ -57,7 +57,7 @@ void LayoutSvg::paint(PaintContext& context, PaintPhase phase)
return; return;
if (!node().bitmap()) if (!node().bitmap())
node().create_bitmap(); node().create_bitmap_as_top_level_svg_element();
ASSERT(node().bitmap()); ASSERT(node().bitmap());
context.painter().draw_scaled_bitmap(enclosing_int_rect(absolute_rect()), *node().bitmap(), node().bitmap()->rect()); context.painter().draw_scaled_bitmap(enclosing_int_rect(absolute_rect()), *node().bitmap(), node().bitmap()->rect());

View file

@ -26,21 +26,22 @@
#pragma once #pragma once
#include <LibWeb/DOM/HTMLSvgElement.h> #include <LibWeb/SVG/SVGSVGElement.h>
#include <LibWeb/Layout/LayoutReplaced.h> #include <LibWeb/Layout/LayoutReplaced.h>
#include <LibWeb/SVG/SVGSVGElement.h>
namespace Web { namespace Web {
class HTMLSvgElement; class SVGSVGElement;
class LayoutSvg : public LayoutReplaced { class LayoutSVG : public LayoutReplaced {
public: public:
LayoutSvg(Document&, const HTMLSvgElement&, NonnullRefPtr<StyleProperties>); LayoutSVG(Document&, const SVG::SVGSVGElement&, NonnullRefPtr<StyleProperties>);
virtual ~LayoutSvg() override = default; virtual ~LayoutSVG() override = default;
virtual void layout(LayoutMode = LayoutMode::Default) override; virtual void layout(LayoutMode = LayoutMode::Default) override;
virtual void paint(PaintContext&, PaintPhase) override; virtual void paint(PaintContext&, PaintPhase) override;
HTMLSvgElement& node() { return static_cast<HTMLSvgElement&>(LayoutReplaced::node()); } SVG::SVGSVGElement& node() { return static_cast<SVG::SVGSVGElement&>(LayoutReplaced::node()); }
private: private:
virtual const char* class_name() const override { return "LayoutSvg"; } virtual const char* class_name() const override { return "LayoutSvg"; }

View file

@ -0,0 +1,36 @@
/*
* 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/SVG/SVGElement.h>
namespace Web::SVG {
SVGElement::SVGElement(Document& document, const FlyString& tag_name)
: Element(document, tag_name)
{
}
}

View file

@ -26,30 +26,13 @@
#pragma once #pragma once
#include <LibGfx/Color.h> #include <LibWeb/DOM/Element.h>
#include <LibGfx/Painter.h>
namespace Web { namespace Web::SVG {
struct SvgPaintingContext { class SVGElement : public Element {
Gfx::Color fill_color { Gfx::Color::Black };
Gfx::Color stroke_color { Gfx::Color::Black };
float stroke_width { 1 };
};
class SvgGraphicElement {
public: public:
virtual void paint(const SvgPaintingContext&, Gfx::Painter& painter) = 0; SVGElement(Document&, const FlyString& tag_name);
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<Gfx::Color> m_fill_color;
Optional<Gfx::Color> m_stroke_color;
Optional<float> m_stroke_width;
}; };
} }

View file

@ -0,0 +1,36 @@
/*
* 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/SVG/SVGGeometryElement.h>
namespace Web::SVG {
SVGGeometryElement::SVGGeometryElement(Document& document, const FlyString& tag_name)
: SVGGraphicsElement(document, tag_name)
{
}
}

View file

@ -0,0 +1,38 @@
/*
* 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/SVG/SVGGraphicsElement.h>
namespace Web::SVG {
class SVGGeometryElement : public SVGGraphicsElement {
public:
SVGGeometryElement(Document& document, const FlyString& tag_name);
};
}

View file

@ -24,37 +24,37 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <AK/FlyString.h> #include <LibWeb/SVG/SVGGraphicsElement.h>
#include <LibWeb/DOM/SvgContext.h>
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") { } else if (name == "stroke") {
auto result = Gfx::Color::from_string(value); m_stroke_color = Gfx::Color::from_string(value).value_or(Color::Transparent);
m_stroke_color = result.value_or(Gfx::Color::Transparent); } else if (name == "stroke-width") {
} else if (name == "fill") { auto result = value.to_int();
auto result = Gfx::Color::from_string(value); if (result.has_value())
m_fill_color = result.value_or(Gfx::Color::Transparent); 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); return SVGPaintingContext {
} m_fill_color.value_or(context.fill_color),
m_stroke_color.value_or(context.stroke_color),
Gfx::Color SvgGraphicElement::stroke_color(const SvgPaintingContext& context) const m_stroke_width.value_or(context.stroke_width),
{ };
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);
} }
} }

View file

@ -0,0 +1,85 @@
/*
* 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 <LibGfx/Path.h>
#include <LibWeb/DOM/Node.h>
#include <LibWeb/SVG/SVGElement.h>
#include <LibWeb/SVG/TagNames.h>
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<Gfx::Color> m_fill_color;
Optional<Gfx::Color> m_stroke_color;
Optional<float> m_stroke_width;
};
}
namespace Web {
template<>
inline bool is<SVG::SVGGraphicsElement>(const Node& node)
{
if (!is<Element>(node))
return false;
auto tag_name = to<Element>(node).tag_name();
#define __ENUMERATE_SVG_TAG(name) \
if (tag_name == #name) \
return true;
ENUMERATE_SVG_TAGS
#undef ENUMERATE_SVG_TAG
return false;
}
}

View file

@ -25,15 +25,16 @@
*/ */
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibGfx/Painter.h>
#include <LibGfx/Path.h> #include <LibGfx/Path.h>
#include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Event.h> #include <LibWeb/DOM/Event.h>
#include <LibWeb/DOM/HTMLPathElement.h> #include <LibWeb/SVG/SVGPathElement.h>
#include <ctype.h> #include <ctype.h>
//#define PATH_DEBUG //#define PATH_DEBUG
namespace Web { namespace Web::SVG {
PathDataParser::PathDataParser(const String& source) PathDataParser::PathDataParser(const String& source)
: m_source(source) : m_source(source)
@ -269,7 +270,7 @@ void PathDataParser::parse_whitespace(bool must_match_once)
matched = true; matched = true;
} }
ASSERT(!must_match_once || matched); ASSERT(!must_match_once || matched);
} }
void PathDataParser::parse_comma_whitespace() void PathDataParser::parse_comma_whitespace()
@ -326,7 +327,7 @@ float PathDataParser::parse_number()
float PathDataParser::parse_flag() float PathDataParser::parse_flag()
{ {
auto number = parse_number(); auto number = parse_number();
ASSERT(number == 0 || number == 1); ASSERT(number == 0 || number == 1);
return number; return number;
} }
@ -348,8 +349,8 @@ bool PathDataParser::match_number() const
return !done() && (isdigit(ch()) || ch() == '-' || ch() == '+'); return !done() && (isdigit(ch()) || ch() == '-' || ch() == '+');
} }
HTMLPathElement::HTMLPathElement(Document& document, const FlyString& tag_name) SVGPathElement::SVGPathElement(Document& document, const FlyString& tag_name)
: HTMLElement(document, tag_name) : SVGGeometryElement(document, tag_name)
{ {
} }
@ -414,16 +415,15 @@ static void print_instruction(const PathInstruction& instruction)
} }
#endif #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); SVGGeometryElement::parse_attribute(name, value);
SvgGraphicElement::parse_attribute(name, value);
if (name == "d") if (name == "d")
m_instructions = PathDataParser(value).parse(); 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; Gfx::Path path;
@ -595,9 +595,8 @@ void HTMLPathElement::paint(const SvgPaintingContext& context, Gfx::Painter& pai
closed_path.close(); closed_path.close();
// Fills are computed as though all paths are closed (https://svgwg.org/svg2-draft/painting.html#FillProperties) // 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.fill_path(closed_path, m_fill_color.value_or(context.fill_color), Gfx::Painter::WindingRule::EvenOdd);
painter.stroke_path(path, stroke_color(context), stroke_width(context)); painter.stroke_path(path, m_stroke_color.value_or(context.stroke_color), m_stroke_width.value_or(context.stroke_width));
} }
} }

View file

@ -28,9 +28,9 @@
#include <LibGfx/Bitmap.h> #include <LibGfx/Bitmap.h>
#include <LibWeb/DOM/HTMLElement.h> #include <LibWeb/DOM/HTMLElement.h>
#include <LibWeb/DOM/SvgContext.h> #include <LibWeb/SVG/SVGGeometryElement.h>
namespace Web { namespace Web::SVG {
enum class PathInstructionType { enum class PathInstructionType {
Move, Move,
@ -100,24 +100,16 @@ private:
Vector<PathInstruction> m_instructions; Vector<PathInstruction> m_instructions;
}; };
class HTMLPathElement final class SVGPathElement final : public SVGGeometryElement {
: public HTMLElement
, public SvgGraphicElement {
public: public:
HTMLPathElement(Document&, const FlyString& tag_name); SVGPathElement(Document&, const FlyString& tag_name);
virtual ~HTMLPathElement() override = default; virtual ~SVGPathElement() override = default;
virtual void parse_attribute(const FlyString& name, const String& value) override; 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: private:
Vector<PathInstruction> m_instructions; Vector<PathInstruction> m_instructions;
}; };
template<>
inline bool is<HTMLPathElement>(const Node& node)
{
return is<Element>(node) && to<Element>(node).tag_name() == HTML::TagNames::path;
}
} }

View file

@ -24,47 +24,34 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <LibGfx/Painter.h>
#include <LibGfx/Path.h> #include <LibGfx/Path.h>
#include <LibWeb/CSS/StyleResolver.h> #include <LibWeb/CSS/StyleResolver.h>
#include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Event.h> #include <LibWeb/DOM/Event.h>
#include <LibWeb/DOM/HTMLPathElement.h> #include <LibWeb/SVG/SVGPathElement.h>
#include <LibWeb/DOM/HTMLSvgElement.h> #include <LibWeb/SVG/SVGSVGElement.h>
#include <LibWeb/Layout/LayoutSvg.h> #include <LibWeb/Layout/LayoutSVG.h>
#include <ctype.h> #include <ctype.h>
namespace Web { namespace Web::SVG {
static constexpr auto max_svg_area = 16384 * 16384; static constexpr auto max_svg_area = 16384 * 16384;
HTMLSvgElement::HTMLSvgElement(Document& document, const FlyString& tag_name) SVGSVGElement::SVGSVGElement(Document& document, const FlyString& tag_name)
: HTMLElement(document, tag_name) : SVGGraphicsElement(document, tag_name)
{ {
} }
void HTMLSvgElement::parse_attribute(const FlyString& name, const String& value) RefPtr<LayoutNode> SVGSVGElement::create_layout_node(const StyleProperties* parent_style)
{
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<LayoutNode> HTMLSvgElement::create_layout_node(const StyleProperties* parent_style)
{ {
auto style = document().style_resolver().resolve_style(*this, parent_style); auto style = document().style_resolver().resolve_style(*this, parent_style);
if (style->display() == CSS::Display::None) if (style->display() == CSS::Display::None)
return nullptr; 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 width = canvas.width();
auto height = canvas.height(); auto height = canvas.height();
@ -83,7 +70,7 @@ static Gfx::IntSize bitmap_size_for_canvas(const HTMLSvgElement& canvas)
return Gfx::IntSize(width, height); 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); auto size = bitmap_size_for_canvas(*this);
if (size.is_empty()) { if (size.is_empty()) {
@ -95,55 +82,26 @@ bool HTMLSvgElement::create_bitmap()
m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, size); m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, size);
Gfx::Painter painter(*m_bitmap); Gfx::Painter painter(*m_bitmap);
paint(painter); paint(painter, make_painting_context_from(default_painting_context));
return m_bitmap; return m_bitmap;
} }
SvgPaintingContext HTMLSvgElement::make_context() const unsigned SVGSVGElement::width() 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
{ {
return attribute(HTML::AttributeNames::width).to_uint().value_or(300); 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); return attribute(HTML::AttributeNames::height).to_uint().value_or(150);
} }
static bool is_svg_graphic_element(const HTMLElement& element) void SVGSVGElement::paint(Gfx::Painter& painter, const SVGPaintingContext& context)
{
return is<HTMLPathElement>(element);
}
static SvgGraphicElement& as_svg_graphic_element(HTMLElement& element)
{
if (is<HTMLPathElement>(element))
return to<HTMLPathElement>(element);
ASSERT_NOT_REACHED();
}
void HTMLSvgElement::paint(Gfx::Painter& painter)
{ {
for_each_child([&](Node& child) { for_each_child([&](Node& child) {
if (is<HTMLElement>(child)) { if (is<SVGGraphicsElement>(child)) {
auto& element = to<HTMLElement>(child); to<SVGGraphicsElement>(child).paint(painter, make_painting_context_from(context));
if (is_svg_graphic_element(element)) {
as_svg_graphic_element(element).paint(make_context(), painter);
}
} }
}); });
} }

View file

@ -27,40 +27,26 @@
#pragma once #pragma once
#include <LibGfx/Bitmap.h> #include <LibGfx/Bitmap.h>
#include <LibWeb/DOM/HTMLElement.h> #include <LibWeb/SVG/SVGGraphicsElement.h>
#include <LibWeb/DOM/SvgContext.h>
namespace Web { namespace Web::SVG {
class HTMLSvgElement final : public HTMLElement { class SVGSVGElement final : public SVGGraphicsElement {
public: public:
HTMLSvgElement(Document&, const FlyString& tag_name); SVGSVGElement(Document&, const FlyString& tag_name);
virtual ~HTMLSvgElement() override = default;
virtual void parse_attribute(const FlyString& name, const String& value) override;
virtual RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) override; virtual RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) override;
const RefPtr<Gfx::Bitmap> bitmap() const { return m_bitmap; } const RefPtr<Gfx::Bitmap> bitmap() const { return m_bitmap; }
bool create_bitmap(); bool create_bitmap_as_top_level_svg_element();
SvgPaintingContext make_context() const;
virtual void paint(Gfx::Painter& painter, const SVGPaintingContext& context) override;
unsigned width() const; unsigned width() const;
unsigned height() const; unsigned height() const;
private: private:
void paint(Gfx::Painter&);
RefPtr<Gfx::Bitmap> m_bitmap; RefPtr<Gfx::Bitmap> m_bitmap;
Optional<float> m_stroke_width;
Optional<Color> m_stroke_color;
Optional<Color> m_fill_color;
}; };
template<>
inline bool is<HTMLSvgElement>(const Node& node)
{
return is<Element>(node) && to<Element>(node).tag_name() == HTML::TagNames::svg;
}
} }

View file

@ -0,0 +1,48 @@
/*
* 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/SVG/TagNames.h>
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;
}
}

View file

@ -0,0 +1,46 @@
/*
* 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 <AK/FlyString.h>
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
}