Browse Source

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)
MacDue 2 năm trước cách đây
mục cha
commit
0e12503586

+ 2 - 0
Userland/Libraries/LibWeb/CMakeLists.txt

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

+ 2 - 2
Userland/Libraries/LibWeb/DOM/ElementFactory.cpp

@@ -99,7 +99,7 @@
 #include <LibWeb/SVG/SVGStopElement.h>
 #include <LibWeb/SVG/SVGStyleElement.h>
 #include <LibWeb/SVG/SVGSymbolElement.h>
-#include <LibWeb/SVG/SVGTextContentElement.h>
+#include <LibWeb/SVG/SVGTextElement.h>
 #include <LibWeb/SVG/SVGTitleElement.h>
 #include <LibWeb/SVG/SVGUseElement.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)
         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)));
+        return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGTextElement>(realm, document, move(qualified_name)));
     if (local_name == SVG::TagNames::title)
         return MUST_OR_THROW_OOM(realm.heap().allocate<SVG::SVGTitleElement>(realm, document, move(qualified_name)));
     if (local_name == SVG::TagNames::use)

+ 1 - 1
Userland/Libraries/LibWeb/Layout/SVGTextBox.cpp

@@ -10,7 +10,7 @@
 
 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)
 {
 }

+ 4 - 4
Userland/Libraries/LibWeb/Layout/SVGTextBox.h

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

+ 0 - 25
Userland/Libraries/LibWeb/SVG/SVGTextContentElement.cpp

@@ -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
 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());
 }
 
-Gfx::FloatPoint SVGTextContentElement::get_offset() const
-{
-    return { m_x + m_dx, m_y + m_dy };
-}
-
 }

+ 0 - 12
Userland/Libraries/LibWeb/SVG/SVGTextContentElement.h

@@ -17,26 +17,14 @@ class SVGTextContentElement : public SVGGraphicsElement {
     WEB_PLATFORM_OBJECT(SVGTextContentElement, SVGGraphicsElement);
 
 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;
 
-    Gfx::FloatPoint get_offset() const;
-
     Optional<TextAnchor> text_anchor() const;
 
 protected:
     SVGTextContentElement(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 };
 };
 
 }

+ 17 - 1
Userland/Libraries/LibWeb/SVG/SVGTextContentElement.idl

@@ -1,8 +1,24 @@
 #import <SVG/SVGGraphicsElement.idl>
 
+// https://svgwg.org/svg2-draft/text.html#InterfaceSVGTextContentElement
 [Exposed=Window]
 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);
 };

+ 30 - 0
Userland/Libraries/LibWeb/SVG/SVGTextElement.cpp

@@ -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));
+}
+
+}

+ 27 - 0
Userland/Libraries/LibWeb/SVG/SVGTextElement.h

@@ -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;
+};
+
+}

+ 6 - 0
Userland/Libraries/LibWeb/SVG/SVGTextElement.idl

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

+ 53 - 0
Userland/Libraries/LibWeb/SVG/SVGTextPositioningElement.cpp

@@ -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 };
+}
+
+}

+ 40 - 0
Userland/Libraries/LibWeb/SVG/SVGTextPositioningElement.h

@@ -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 };
+};
+
+}

+ 11 - 0
Userland/Libraries/LibWeb/SVG/SVGTextPositioningElement.idl

@@ -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;
+};

+ 2 - 0
Userland/Libraries/LibWeb/idl_files.cmake

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