LibWeb: Implement the <symbol> SVG element

This commit is contained in:
PrestonLTaylor 2023-05-31 00:50:12 +01:00 committed by Andreas Kling
parent c7c3043aa2
commit aa691c22d4
Notes: sideshowbarker 2024-07-17 02:37:08 +09:00
7 changed files with 106 additions and 0 deletions

View file

@ -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

View file

@ -97,6 +97,7 @@
#include <LibWeb/SVG/SVGRectElement.h>
#include <LibWeb/SVG/SVGSVGElement.h>
#include <LibWeb/SVG/SVGStopElement.h>
#include <LibWeb/SVG/SVGSymbolElement.h>
#include <LibWeb/SVG/SVGTextContentElement.h>
#include <LibWeb/SVG/SVGUseElement.h>
#include <LibWeb/SVG/TagNames.h>
@ -454,6 +455,8 @@ static WebIDL::ExceptionOr<JS::GCPtr<SVG::SVGElement>> create_svg_element(JS::Re
return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGGElement>(realm, document, move(qualified_name)));
if (local_name == SVG::TagNames::stop)
return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGStopElement>(realm, document, move(qualified_name)));
if (local_name == SVG::TagNames::symbol)
return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGSymbolElement>(realm, document, move(qualified_name)));
if (local_name == SVG::TagNames::text)
return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGTextContentElement>(realm, document, move(qualified_name)));
if (local_name == SVG::TagNames::use)

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023, Preston Taylor <95388976+PrestonLTaylor@users.noreply.github.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/CSS/StyleProperties.h>
#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
#include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h>
#include <LibWeb/CSS/StyleValues/OverflowStyleValue.h>
#include <LibWeb/DOM/ShadowRoot.h>
#include <LibWeb/SVG/SVGSymbolElement.h>
#include <LibWeb/SVG/SVGUseElement.h>
namespace Web::SVG {
SVGSymbolElement::SVGSymbolElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: SVGGraphicsElement(document, qualified_name)
{
}
JS::ThrowCompletionOr<void> SVGSymbolElement::initialize(JS::Realm& realm)
{
MUST_OR_THROW_OOM(Base::initialize(realm));
set_prototype(&Bindings::ensure_web_prototype<Bindings::SVGSymbolElementPrototype>(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<DOM::ShadowRoot>(maybe_shadow_root)) {
return false;
}
auto host = static_cast<const DOM::ShadowRoot&>(*maybe_shadow_root).host();
return is<SVGUseElement>(host);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2023, Preston Taylor <95388976+PrestonLTaylor@users.noreply.github.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/SVG/SVGGraphicsElement.h>
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<void> initialize(JS::Realm&) override;
bool is_direct_child_of_use_shadow_tree() const;
};
}

View file

@ -0,0 +1,9 @@
#import <SVG/SVGGraphicsElement.idl>
// https://svgwg.org/svg2-draft/struct.html#InterfaceSVGSymbolElement
[Exposed=Window]
interface SVGSymbolElement : SVGGraphicsElement {
};
// FIXME: SVGSymbolElement includes SVGFitToViewBox;

View file

@ -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)

View file

@ -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)