diff --git a/Base/res/html/misc/svg.html b/Base/res/html/misc/svg.html index d3ad1fdfc6..e49d24d56a 100644 --- a/Base/res/html/misc/svg.html +++ b/Base/res/html/misc/svg.html @@ -50,6 +50,12 @@ + + + + + + diff --git a/Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp b/Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp index 34262a384a..6e37cc5d37 100644 --- a/Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp +++ b/Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp @@ -83,6 +83,7 @@ #include #include #include +#include #include #include #include @@ -159,6 +160,7 @@ #include #include #include +#include #include #include #include @@ -315,6 +317,8 @@ NodeWrapper* wrap(JS::GlobalObject& global_object, DOM::Node& node) return static_cast(wrap_impl(global_object, verify_cast(node))); if (is(node)) return static_cast(wrap_impl(global_object, verify_cast(node))); + if (is(node)) + return static_cast(wrap_impl(global_object, verify_cast(node))); if (is(node)) return static_cast(wrap_impl(global_object, verify_cast(node))); if (is(node)) diff --git a/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h b/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h index 6ebd37f30c..88da06aea9 100644 --- a/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h +++ b/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h @@ -251,6 +251,8 @@ #include #include #include +#include +#include #include #include #include @@ -437,6 +439,7 @@ ADD_WINDOW_OBJECT_INTERFACE(SubtleCrypto) \ ADD_WINDOW_OBJECT_INTERFACE(SVGElement) \ ADD_WINDOW_OBJECT_INTERFACE(SVGCircleElement) \ + ADD_WINDOW_OBJECT_INTERFACE(SVGEllipseElement) \ ADD_WINDOW_OBJECT_INTERFACE(SVGGeometryElement) \ ADD_WINDOW_OBJECT_INTERFACE(SVGGraphicsElement) \ ADD_WINDOW_OBJECT_INTERFACE(SVGPathElement) \ diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 5447a8068d..36654b378f 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -272,6 +272,7 @@ set(SOURCES SVG/SVGGraphicsElement.cpp SVG/SVGPathElement.cpp SVG/SVGCircleElement.cpp + SVG/SVGEllipseElement.cpp SVG/SVGRectElement.cpp SVG/SVGSVGElement.cpp SVG/TagNames.cpp @@ -515,6 +516,7 @@ libweb_js_wrapper(SVG/SVGElement) libweb_js_wrapper(SVG/SVGGeometryElement) libweb_js_wrapper(SVG/SVGGraphicsElement) libweb_js_wrapper(SVG/SVGCircleElement) +libweb_js_wrapper(SVG/SVGEllipseElement) libweb_js_wrapper(SVG/SVGPathElement) libweb_js_wrapper(SVG/SVGRectElement) libweb_js_wrapper(SVG/SVGSVGElement) diff --git a/Userland/Libraries/LibWeb/DOM/ElementFactory.cpp b/Userland/Libraries/LibWeb/DOM/ElementFactory.cpp index 02e587b4a1..54b562e54e 100644 --- a/Userland/Libraries/LibWeb/DOM/ElementFactory.cpp +++ b/Userland/Libraries/LibWeb/DOM/ElementFactory.cpp @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -238,6 +239,8 @@ NonnullRefPtr create_element(Document& document, const FlyString& tag_n return adopt_ref(*new SVG::SVGSVGElement(document, move(qualified_name))); if (lowercase_tag_name == SVG::TagNames::circle) return adopt_ref(*new SVG::SVGCircleElement(document, move(qualified_name))); + if (lowercase_tag_name == SVG::TagNames::ellipse) + return adopt_ref(*new SVG::SVGEllipseElement(document, move(qualified_name))); if (lowercase_tag_name == SVG::TagNames::path) return adopt_ref(*new SVG::SVGPathElement(document, move(qualified_name))); if (lowercase_tag_name == SVG::TagNames::rect) diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 4bc2bd98db..cee4b495e7 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -246,6 +246,7 @@ class ResizeObserver; namespace Web::SVG { class SVGCircleElement; class SVGElement; +class SVGEllipseElement; class SVGGeometryElement; class SVGGraphicsElement; class SVGPathElement; @@ -453,6 +454,7 @@ class SubmitEventWrapper; class SubtleCryptoWrapper; class SVGCircleElementWrapper; class SVGElementWrapper; +class SVGEllipseElementWrapper; class SVGGeometryElementWrapper; class SVGGraphicsElementWrapper; class SVGPathElementWrapper; diff --git a/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.cpp new file mode 100644 index 0000000000..4e2a43bbfd --- /dev/null +++ b/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "SVGEllipseElement.h" +#include +#include + +namespace Web::SVG { + +SVGEllipseElement::SVGEllipseElement(DOM::Document& document, QualifiedName qualified_name) + : SVGGeometryElement(document, qualified_name) +{ +} + +void SVGEllipseElement::parse_attribute(FlyString const& name, String const& value) +{ + SVGGeometryElement::parse_attribute(name, value); + + if (name == SVG::AttributeNames::cx) { + m_center_x = AttributeParser::parse_coordinate(value); + m_path.clear(); + } else if (name == SVG::AttributeNames::cy) { + m_center_y = AttributeParser::parse_coordinate(value); + m_path.clear(); + } else if (name == SVG::AttributeNames::rx) { + m_radius_x = AttributeParser::parse_positive_length(value); + m_path.clear(); + } else if (name == SVG::AttributeNames::ry) { + m_radius_y = AttributeParser::parse_positive_length(value); + m_path.clear(); + } +} + +Gfx::Path& SVGEllipseElement::get_path() +{ + if (m_path.has_value()) + return m_path.value(); + + float rx = m_radius_x.value_or(0); + float ry = m_radius_y.value_or(0); + float cx = m_center_x.value_or(0); + float cy = m_center_y.value_or(0); + Gfx::Path path; + + // A computed value of zero for either dimension, or a computed value of auto for both dimensions, disables rendering of the element. + if (rx == 0 || ry == 0) { + m_path = move(path); + return m_path.value(); + } + + Gfx::FloatPoint radii = { rx, ry }; + double x_axis_rotation = 0; + bool large_arc = false; + bool sweep = true; // Note: Spec says it should be false, but it's wrong. https://github.com/w3c/svgwg/issues/765 + + // 1. A move-to command to the point cx+rx,cy; + path.move_to({ cx + rx, cy }); + + // 2. arc to cx,cy+ry; + path.elliptical_arc_to({ cx, cy + ry }, radii, x_axis_rotation, large_arc, sweep); + + // 3. arc to cx-rx,cy; + path.elliptical_arc_to({ cx - rx, cy }, radii, x_axis_rotation, large_arc, sweep); + + // 4. arc to cx,cy-ry; + path.elliptical_arc_to({ cx, cy - ry }, radii, x_axis_rotation, large_arc, sweep); + + // 5. arc with a segment-completing close path operation. + path.elliptical_arc_to({ cx + rx, cy }, radii, x_axis_rotation, large_arc, sweep); + + m_path = move(path); + return m_path.value(); +} + +} diff --git a/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.h b/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.h new file mode 100644 index 0000000000..4c262cb1e9 --- /dev/null +++ b/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::SVG { + +class SVGEllipseElement final : public SVGGeometryElement { +public: + using WrapperType = Bindings::SVGEllipseElementWrapper; + + SVGEllipseElement(DOM::Document&, QualifiedName); + virtual ~SVGEllipseElement() override = default; + + virtual void parse_attribute(FlyString const& name, String const& value) override; + + virtual Gfx::Path& get_path() override; + +private: + Optional m_path; + + Optional m_center_x; + Optional m_center_y; + Optional m_radius_x; + Optional m_radius_y; +}; + +} diff --git a/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.idl b/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.idl new file mode 100644 index 0000000000..876435ca05 --- /dev/null +++ b/Userland/Libraries/LibWeb/SVG/SVGEllipseElement.idl @@ -0,0 +1,7 @@ +[Exposed=Window] +interface SVGEllipseElement : SVGGeometryElement { + // [SameObject] readonly attribute SVGAnimatedLength cx; + // [SameObject] readonly attribute SVGAnimatedLength cy; + // [SameObject] readonly attribute SVGAnimatedLength rx; + // [SameObject] readonly attribute SVGAnimatedLength ry; +}; diff --git a/Userland/Libraries/LibWeb/SVG/TagNames.h b/Userland/Libraries/LibWeb/SVG/TagNames.h index ef4065ae71..79ad440643 100644 --- a/Userland/Libraries/LibWeb/SVG/TagNames.h +++ b/Userland/Libraries/LibWeb/SVG/TagNames.h @@ -12,6 +12,7 @@ namespace Web::SVG::TagNames { #define ENUMERATE_SVG_GRAPHICS_TAGS \ __ENUMERATE_SVG_TAG(circle) \ + __ENUMERATE_SVG_TAG(ellipse) \ __ENUMERATE_SVG_TAG(g) \ __ENUMERATE_SVG_TAG(path) \ __ENUMERATE_SVG_TAG(rect) \