1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 21:27:35 +00:00

LibWeb: Split SVGTextContentElement into spec defined subclasses

As part of this move properties/methods to the correct subclass
(position related properties go under SVGTextPositioningElement).

SVG text element hierarchy:

  SVGTextContentElement
           ^- SVGTextPositioningElement
                     ^- SVGTextElement
                     ^- SVGTSpanElement
           ^- SVGTextPathElement (TODO)
           ^- SVGTRefElement (TODO)
This commit is contained in:
MacDue 2023-07-22 19:24:55 +01:00 committed by Andreas Kling
parent 77e6dbab33
commit 0e12503586
14 changed files with 195 additions and 45 deletions

View file

@ -550,6 +550,8 @@ set(SOURCES
SVG/SVGStyleElement.cpp SVG/SVGStyleElement.cpp
SVG/SVGSymbolElement.cpp SVG/SVGSymbolElement.cpp
SVG/SVGTextContentElement.cpp SVG/SVGTextContentElement.cpp
SVG/SVGTextElement.cpp
SVG/SVGTextPositioningElement.cpp
SVG/SVGTitleElement.cpp SVG/SVGTitleElement.cpp
SVG/SVGUseElement.cpp SVG/SVGUseElement.cpp
SVG/TagNames.cpp SVG/TagNames.cpp

View file

@ -99,7 +99,7 @@
#include <LibWeb/SVG/SVGStopElement.h> #include <LibWeb/SVG/SVGStopElement.h>
#include <LibWeb/SVG/SVGStyleElement.h> #include <LibWeb/SVG/SVGStyleElement.h>
#include <LibWeb/SVG/SVGSymbolElement.h> #include <LibWeb/SVG/SVGSymbolElement.h>
#include <LibWeb/SVG/SVGTextContentElement.h> #include <LibWeb/SVG/SVGTextElement.h>
#include <LibWeb/SVG/SVGTitleElement.h> #include <LibWeb/SVG/SVGTitleElement.h>
#include <LibWeb/SVG/SVGUseElement.h> #include <LibWeb/SVG/SVGUseElement.h>
#include <LibWeb/SVG/TagNames.h> #include <LibWeb/SVG/TagNames.h>
@ -462,7 +462,7 @@ static WebIDL::ExceptionOr<JS::GCPtr<SVG::SVGElement>> create_svg_element(JS::Re
if (local_name == SVG::TagNames::symbol) if (local_name == SVG::TagNames::symbol)
return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGSymbolElement>(realm, document, move(qualified_name))); return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGSymbolElement>(realm, document, move(qualified_name)));
if (local_name == SVG::TagNames::text) if (local_name == SVG::TagNames::text)
return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGTextContentElement>(realm, document, move(qualified_name))); return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGTextElement>(realm, document, move(qualified_name)));
if (local_name == SVG::TagNames::title) if (local_name == SVG::TagNames::title)
return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGTitleElement>(realm, document, move(qualified_name))); return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGTitleElement>(realm, document, move(qualified_name)));
if (local_name == SVG::TagNames::use) if (local_name == SVG::TagNames::use)

View file

@ -10,7 +10,7 @@
namespace Web::Layout { namespace Web::Layout {
SVGTextBox::SVGTextBox(DOM::Document& document, SVG::SVGTextContentElement& element, NonnullRefPtr<CSS::StyleProperties> properties) SVGTextBox::SVGTextBox(DOM::Document& document, SVG::SVGTextPositioningElement& element, NonnullRefPtr<CSS::StyleProperties> properties)
: SVGGraphicsBox(document, element, properties) : SVGGraphicsBox(document, element, properties)
{ {
} }

View file

@ -8,7 +8,7 @@
#include <AK/Optional.h> #include <AK/Optional.h>
#include <LibWeb/Layout/SVGGraphicsBox.h> #include <LibWeb/Layout/SVGGraphicsBox.h>
#include <LibWeb/SVG/SVGTextContentElement.h> #include <LibWeb/SVG/SVGTextPositioningElement.h>
namespace Web::Layout { namespace Web::Layout {
@ -16,11 +16,11 @@ class SVGTextBox final : public SVGGraphicsBox {
JS_CELL(SVGTextBox, SVGGraphicsBox); JS_CELL(SVGTextBox, SVGGraphicsBox);
public: public:
SVGTextBox(DOM::Document&, SVG::SVGTextContentElement&, NonnullRefPtr<CSS::StyleProperties>); SVGTextBox(DOM::Document&, SVG::SVGTextPositioningElement&, NonnullRefPtr<CSS::StyleProperties>);
virtual ~SVGTextBox() override = default; virtual ~SVGTextBox() override = default;
SVG::SVGTextContentElement& dom_node() { return static_cast<SVG::SVGTextContentElement&>(SVGGraphicsBox::dom_node()); } SVG::SVGTextPositioningElement& dom_node() { return static_cast<SVG::SVGTextPositioningElement&>(SVGGraphicsBox::dom_node()); }
SVG::SVGTextContentElement const& dom_node() const { return static_cast<SVG::SVGTextContentElement const&>(SVGGraphicsBox::dom_node()); } SVG::SVGTextPositioningElement const& dom_node() const { return static_cast<SVG::SVGTextPositioningElement const&>(SVGGraphicsBox::dom_node()); }
Optional<Gfx::AffineTransform> layout_transform() const; Optional<Gfx::AffineTransform> layout_transform() const;

View file

@ -47,26 +47,6 @@ Optional<TextAnchor> SVGTextContentElement::text_anchor() const
} }
} }
void SVGTextContentElement::attribute_changed(DeprecatedFlyString const& name, DeprecatedString const& value)
{
SVGGraphicsElement::attribute_changed(name, value);
if (name == SVG::AttributeNames::x) {
m_x = AttributeParser::parse_coordinate(value).value_or(m_x);
} else if (name == SVG::AttributeNames::y) {
m_y = AttributeParser::parse_coordinate(value).value_or(m_y);
} else if (name == SVG::AttributeNames::dx) {
m_dx = AttributeParser::parse_coordinate(value).value_or(m_dx);
} else if (name == SVG::AttributeNames::dy) {
m_dy = AttributeParser::parse_coordinate(value).value_or(m_dy);
}
}
JS::GCPtr<Layout::Node> SVGTextContentElement::create_layout_node(NonnullRefPtr<CSS::StyleProperties> style)
{
return heap().allocate_without_realm<Layout::SVGTextBox>(document(), *this, move(style));
}
// https://svgwg.org/svg2-draft/text.html#__svg__SVGTextContentElement__getNumberOfChars // https://svgwg.org/svg2-draft/text.html#__svg__SVGTextContentElement__getNumberOfChars
WebIDL::ExceptionOr<int> SVGTextContentElement::get_number_of_chars() const WebIDL::ExceptionOr<int> SVGTextContentElement::get_number_of_chars() const
{ {
@ -74,9 +54,4 @@ WebIDL::ExceptionOr<int> SVGTextContentElement::get_number_of_chars() const
return static_cast<int>(chars.size()); return static_cast<int>(chars.size());
} }
Gfx::FloatPoint SVGTextContentElement::get_offset() const
{
return { m_x + m_dx, m_y + m_dy };
}
} }

View file

@ -17,26 +17,14 @@ class SVGTextContentElement : public SVGGraphicsElement {
WEB_PLATFORM_OBJECT(SVGTextContentElement, SVGGraphicsElement); WEB_PLATFORM_OBJECT(SVGTextContentElement, SVGGraphicsElement);
public: public:
virtual JS::GCPtr<Layout::Node> create_layout_node(NonnullRefPtr<CSS::StyleProperties>) override;
virtual void attribute_changed(DeprecatedFlyString const& name, DeprecatedString const& value) override;
WebIDL::ExceptionOr<int> get_number_of_chars() const; WebIDL::ExceptionOr<int> get_number_of_chars() const;
Gfx::FloatPoint get_offset() const;
Optional<TextAnchor> text_anchor() const; Optional<TextAnchor> text_anchor() const;
protected: protected:
SVGTextContentElement(DOM::Document&, DOM::QualifiedName); SVGTextContentElement(DOM::Document&, DOM::QualifiedName);
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
private:
float m_x { 0 };
float m_y { 0 };
float m_dx { 0 };
float m_dy { 0 };
}; };
} }

View file

@ -1,8 +1,24 @@
#import <SVG/SVGGraphicsElement.idl> #import <SVG/SVGGraphicsElement.idl>
// https://svgwg.org/svg2-draft/text.html#InterfaceSVGTextContentElement
[Exposed=Window] [Exposed=Window]
interface SVGTextContentElement : SVGGraphicsElement { interface SVGTextContentElement : SVGGraphicsElement {
long getNumberOfChars(); // lengthAdjust Types
const unsigned short LENGTHADJUST_UNKNOWN = 0;
const unsigned short LENGTHADJUST_SPACING = 1;
const unsigned short LENGTHADJUST_SPACINGANDGLYPHS = 2;
// FIXME: [SameObject] readonly attribute SVGAnimatedLength textLength;
// FIXME:[SameObject] readonly attribute SVGAnimatedEnumeration lengthAdjust;
long getNumberOfChars();
// FIXME: float getComputedTextLength();
// FIXME: float getSubStringLength(unsigned long charnum, unsigned long nchars);
// FIXME: DOMPoint getStartPositionOfChar(unsigned long charnum);
// FIXME: DOMPoint getEndPositionOfChar(unsigned long charnum);
// FIXME: DOMRect getExtentOfChar(unsigned long charnum);
// FIXME: float getRotationOfChar(unsigned long charnum);
// FIXME: long getCharNumAtPosition(optional DOMPointInit point = {});
// FIXME: undefined selectSubString(unsigned long charnum, unsigned long nchars);
}; };

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Layout/SVGTextBox.h>
#include <LibWeb/SVG/SVGTextElement.h>
namespace Web::SVG {
SVGTextElement::SVGTextElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: SVGTextPositioningElement(document, move(qualified_name))
{
}
JS::ThrowCompletionOr<void> SVGTextElement::initialize(JS::Realm& realm)
{
MUST_OR_THROW_OOM(Base::initialize(realm));
set_prototype(&Bindings::ensure_web_prototype<Bindings::SVGTextElementPrototype>(realm, "SVGTextElement"));
return {};
}
JS::GCPtr<Layout::Node> SVGTextElement::create_layout_node(NonnullRefPtr<CSS::StyleProperties> style)
{
return heap().allocate_without_realm<Layout::SVGTextBox>(document(), *this, move(style));
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/SVG/SVGTextPositioningElement.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::SVG {
// https://svgwg.org/svg2-draft/text.html#InterfaceSVGTextElement
class SVGTextElement : public SVGTextPositioningElement {
WEB_PLATFORM_OBJECT(SVGTextElement, SVGTextPositioningElement);
public:
virtual JS::GCPtr<Layout::Node> create_layout_node(NonnullRefPtr<CSS::StyleProperties>) override;
protected:
SVGTextElement(DOM::Document&, DOM::QualifiedName);
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
};
}

View file

@ -0,0 +1,6 @@
#import <SVG/SVGTextPositioningElement.idl>
// https://svgwg.org/svg2-draft/text.html#InterfaceSVGTextElement
[Exposed=Window]
interface SVGTextElement : SVGTextPositioningElement {
};

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Utf16View.h>
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/Utf16String.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/SVG/AttributeNames.h>
#include <LibWeb/SVG/AttributeParser.h>
#include <LibWeb/SVG/SVGGeometryElement.h>
#include <LibWeb/SVG/SVGTextPositioningElement.h>
namespace Web::SVG {
SVGTextPositioningElement::SVGTextPositioningElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: SVGTextContentElement(document, move(qualified_name))
{
}
JS::ThrowCompletionOr<void> SVGTextPositioningElement::initialize(JS::Realm& realm)
{
MUST_OR_THROW_OOM(Base::initialize(realm));
set_prototype(&Bindings::ensure_web_prototype<Bindings::SVGTextPositioningElementPrototype>(realm, "SVGTextPositioningElement"));
return {};
}
void SVGTextPositioningElement::attribute_changed(DeprecatedFlyString const& name, DeprecatedString const& value)
{
SVGGraphicsElement::attribute_changed(name, value);
if (name == SVG::AttributeNames::x) {
m_x = AttributeParser::parse_coordinate(value).value_or(m_x);
} else if (name == SVG::AttributeNames::y) {
m_y = AttributeParser::parse_coordinate(value).value_or(m_y);
} else if (name == SVG::AttributeNames::dx) {
m_dx = AttributeParser::parse_coordinate(value).value_or(m_dx);
} else if (name == SVG::AttributeNames::dy) {
m_dy = AttributeParser::parse_coordinate(value).value_or(m_dy);
}
}
Gfx::FloatPoint SVGTextPositioningElement::get_offset() const
{
return { m_x + m_dx, m_y + m_dy };
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/SVG/SVGTextContentElement.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::SVG {
// https://svgwg.org/svg2-draft/text.html#InterfaceSVGTextPositioningElement
class SVGTextPositioningElement : public SVGTextContentElement {
WEB_PLATFORM_OBJECT(SVGTextPositioningElement, SVGTextContentElement);
public:
virtual void attribute_changed(DeprecatedFlyString const& name, DeprecatedString const& value) override;
Gfx::FloatPoint get_offset() const;
JS::NonnullGCPtr<SVGAnimatedLength> x() const;
JS::NonnullGCPtr<SVGAnimatedLength> y() const;
JS::NonnullGCPtr<SVGAnimatedLength> dx() const;
JS::NonnullGCPtr<SVGAnimatedLength> dy() const;
protected:
SVGTextPositioningElement(DOM::Document&, DOM::QualifiedName);
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
private:
float m_x { 0 };
float m_y { 0 };
float m_dx { 0 };
float m_dy { 0 };
};
}

View file

@ -0,0 +1,11 @@
#import <SVG/SVGTextContentElement.idl>
// https://svgwg.org/svg2-draft/text.html#InterfaceSVGTextPositioningElement
[Exposed=Window]
interface SVGTextPositioningElement : SVGTextContentElement {
// FIXME: [SameObject] readonly attribute SVGAnimatedLengthList x;
// FIXME: [SameObject] readonly attribute SVGAnimatedLengthList y;
// FIXME: [SameObject] readonly attribute SVGAnimatedLengthList dx;
// FIXME: [SameObject] readonly attribute SVGAnimatedLengthList dy;
// FIXME: [SameObject] readonly attribute SVGAnimatedNumberList rotate;
};

View file

@ -225,6 +225,8 @@ libweb_js_bindings(SVG/SVGStopElement)
libweb_js_bindings(SVG/SVGStyleElement) libweb_js_bindings(SVG/SVGStyleElement)
libweb_js_bindings(SVG/SVGSymbolElement) libweb_js_bindings(SVG/SVGSymbolElement)
libweb_js_bindings(SVG/SVGTextContentElement) libweb_js_bindings(SVG/SVGTextContentElement)
libweb_js_bindings(SVG/SVGTextElement)
libweb_js_bindings(SVG/SVGTextPositioningElement)
libweb_js_bindings(SVG/SVGTitleElement) libweb_js_bindings(SVG/SVGTitleElement)
libweb_js_bindings(SVG/SVGUseElement) libweb_js_bindings(SVG/SVGUseElement)
libweb_js_bindings(Selection/Selection) libweb_js_bindings(Selection/Selection)