diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 0e79a2caa9f..395b5dd89b7 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -522,6 +522,7 @@ set(SOURCES SVG/SVGRadialGradientElement.cpp SVG/SVGSVGElement.cpp SVG/SVGStopElement.cpp + SVG/SVGSymbolElement.cpp SVG/SVGTextContentElement.cpp SVG/SVGUseElement.cpp SVG/TagNames.cpp diff --git a/Userland/Libraries/LibWeb/DOM/ElementFactory.cpp b/Userland/Libraries/LibWeb/DOM/ElementFactory.cpp index 00e2802f9c1..c8bb809813d 100644 --- a/Userland/Libraries/LibWeb/DOM/ElementFactory.cpp +++ b/Userland/Libraries/LibWeb/DOM/ElementFactory.cpp @@ -97,6 +97,7 @@ #include #include #include +#include #include #include #include @@ -454,6 +455,8 @@ static WebIDL::ExceptionOr> create_svg_element(JS::Re return MUST_OR_THROW_OOM(realm.heap().allocate(realm, document, move(qualified_name))); if (local_name == SVG::TagNames::stop) return MUST_OR_THROW_OOM(realm.heap().allocate(realm, document, move(qualified_name))); + if (local_name == SVG::TagNames::symbol) + return MUST_OR_THROW_OOM(realm.heap().allocate(realm, document, move(qualified_name))); if (local_name == SVG::TagNames::text) return MUST_OR_THROW_OOM(realm.heap().allocate(realm, document, move(qualified_name))); if (local_name == SVG::TagNames::use) diff --git a/Userland/Libraries/LibWeb/SVG/SVGSymbolElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGSymbolElement.cpp new file mode 100644 index 00000000000..5306a248c57 --- /dev/null +++ b/Userland/Libraries/LibWeb/SVG/SVGSymbolElement.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023, Preston Taylor <95388976+PrestonLTaylor@users.noreply.github.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Web::SVG { + +SVGSymbolElement::SVGSymbolElement(DOM::Document& document, DOM::QualifiedName qualified_name) + : SVGGraphicsElement(document, qualified_name) +{ +} + +JS::ThrowCompletionOr SVGSymbolElement::initialize(JS::Realm& realm) +{ + MUST_OR_THROW_OOM(Base::initialize(realm)); + set_prototype(&Bindings::ensure_web_prototype(realm, "SVGSymbolElement")); + + return {}; +} + +// https://svgwg.org/svg2-draft/struct.html#SymbolNotes +void SVGSymbolElement::apply_presentational_hints(CSS::StyleProperties& style) const +{ + // The user agent style sheet sets the overflow property for ‘symbol’ elements to hidden. + auto hidden = CSS::IdentifierStyleValue::create(CSS::ValueID::Hidden).release_value_but_fixme_should_propagate_errors(); + style.set_property(CSS::PropertyID::Overflow, CSS::OverflowStyleValue::create(hidden, hidden).release_value_but_fixme_should_propagate_errors()); + + if (is_direct_child_of_use_shadow_tree()) { + // The generated instance of a ‘symbol’ that is the direct referenced element of a ‘use’ element must always have a computed value of inline for the display property. + style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::Inline)).release_value_but_fixme_should_propagate_errors()); + } else { + // FIXME: When we have a DefaultSVG.css then use https://svgwg.org/svg2-draft/styling.html#UAStyleSheet instead. + // The user agent must set the display property on the ‘symbol’ element to none, as part of the user agent style sheet, + // and this declaration must have importance over any other CSS rule or presentation attribute. + style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)).release_value_but_fixme_should_propagate_errors()); + } + + // TODO: Parse viewBox and apply it in SVGGraphicsElement/SVGGraphicsPaintable +} + +bool SVGSymbolElement::is_direct_child_of_use_shadow_tree() const +{ + auto maybe_shadow_root = parent(); + if (!is(maybe_shadow_root)) { + return false; + } + + auto host = static_cast(*maybe_shadow_root).host(); + return is(host); +} + +} diff --git a/Userland/Libraries/LibWeb/SVG/SVGSymbolElement.h b/Userland/Libraries/LibWeb/SVG/SVGSymbolElement.h new file mode 100644 index 00000000000..3b571d43979 --- /dev/null +++ b/Userland/Libraries/LibWeb/SVG/SVGSymbolElement.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023, Preston Taylor <95388976+PrestonLTaylor@users.noreply.github.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::SVG { + +class SVGSymbolElement final : public SVGGraphicsElement { + WEB_PLATFORM_OBJECT(SVGSymbolElement, SVGGraphicsElement); + +public: + virtual ~SVGSymbolElement() override = default; + + void apply_presentational_hints(CSS::StyleProperties& style) const override; + +private: + SVGSymbolElement(DOM::Document&, DOM::QualifiedName); + + virtual JS::ThrowCompletionOr initialize(JS::Realm&) override; + + bool is_direct_child_of_use_shadow_tree() const; +}; + +} diff --git a/Userland/Libraries/LibWeb/SVG/SVGSymbolElement.idl b/Userland/Libraries/LibWeb/SVG/SVGSymbolElement.idl new file mode 100644 index 00000000000..52f33386a68 --- /dev/null +++ b/Userland/Libraries/LibWeb/SVG/SVGSymbolElement.idl @@ -0,0 +1,9 @@ +#import + +// https://svgwg.org/svg2-draft/struct.html#InterfaceSVGSymbolElement +[Exposed=Window] +interface SVGSymbolElement : SVGGraphicsElement { + +}; + +// FIXME: SVGSymbolElement includes SVGFitToViewBox; diff --git a/Userland/Libraries/LibWeb/SVG/TagNames.h b/Userland/Libraries/LibWeb/SVG/TagNames.h index 9034987c817..36887a0d4be 100644 --- a/Userland/Libraries/LibWeb/SVG/TagNames.h +++ b/Userland/Libraries/LibWeb/SVG/TagNames.h @@ -33,6 +33,7 @@ namespace Web::SVG::TagNames { __ENUMERATE_SVG_TAG(radialGradient) \ __ENUMERATE_SVG_TAG(script) \ __ENUMERATE_SVG_TAG(stop) \ + __ENUMERATE_SVG_TAG(symbol) \ __ENUMERATE_SVG_TAG(title) \ __ENUMERATE_SVG_TAG(use) diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index 53a5076bbb2..ad69a5a78ad 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -211,6 +211,7 @@ libweb_js_bindings(SVG/SVGRadialGradientElement) libweb_js_bindings(SVG/SVGRectElement) libweb_js_bindings(SVG/SVGSVGElement) libweb_js_bindings(SVG/SVGStopElement) +libweb_js_bindings(SVG/SVGSymbolElement) libweb_js_bindings(SVG/SVGTextContentElement) libweb_js_bindings(SVG/SVGUseElement) libweb_js_bindings(Selection/Selection)