浏览代码

LibWeb: Implement SVGAnimatedString

Luke Wilde 1 年之前
父节点
当前提交
ddf601830a

+ 1 - 0
Meta/gn/secondary/Userland/Libraries/LibWeb/SVG/BUILD.gn

@@ -6,6 +6,7 @@ source_set("SVG") {
     "AttributeParser.cpp",
     "SVGAnimatedLength.cpp",
     "SVGAnimatedNumber.cpp",
+    "SVGAnimatedString.cpp",
     "SVGCircleElement.cpp",
     "SVGClipPathElement.cpp",
     "SVGDecodedImageData.cpp",

+ 1 - 0
Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni

@@ -243,6 +243,7 @@ standard_idl_files = [
   "//Userland/Libraries/LibWeb/Streams/WritableStreamDefaultWriter.idl",
   "//Userland/Libraries/LibWeb/SVG/SVGAnimatedLength.idl",
   "//Userland/Libraries/LibWeb/SVG/SVGAnimatedNumber.idl",
+  "//Userland/Libraries/LibWeb/SVG/SVGAnimatedString.idl",
   "//Userland/Libraries/LibWeb/SVG/SVGCircleElement.idl",
   "//Userland/Libraries/LibWeb/SVG/SVGClipPathElement.idl",
   "//Userland/Libraries/LibWeb/SVG/SVGDefsElement.idl",

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

@@ -557,6 +557,7 @@ set(SOURCES
     SVG/AttributeParser.cpp
     SVG/SVGAnimatedLength.cpp
     SVG/SVGAnimatedNumber.cpp
+    SVG/SVGAnimatedString.cpp
     SVG/SVGClipPathElement.cpp
     SVG/SVGDecodedImageData.cpp
     SVG/SVGDefsElement.cpp

+ 87 - 0
Userland/Libraries/LibWeb/SVG/SVGAnimatedString.cpp

@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Heap/Heap.h>
+#include <LibJS/Runtime/Realm.h>
+#include <LibWeb/Bindings/Intrinsics.h>
+#include <LibWeb/SVG/SVGAnimatedString.h>
+#include <LibWeb/SVG/SVGElement.h>
+
+namespace Web::SVG {
+
+JS_DEFINE_ALLOCATOR(SVGAnimatedString);
+
+JS::NonnullGCPtr<SVGAnimatedString> SVGAnimatedString::create(JS::Realm& realm, JS::NonnullGCPtr<SVGElement> element, FlyString reflected_attribute, Optional<FlyString> deprecated_reflected_attribute, Optional<FlyString> initial_value)
+{
+    return realm.heap().allocate<SVGAnimatedString>(realm, realm, element, move(reflected_attribute), move(deprecated_reflected_attribute), move(initial_value));
+}
+
+SVGAnimatedString::SVGAnimatedString(JS::Realm& realm, JS::NonnullGCPtr<SVGElement> element, FlyString reflected_attribute, Optional<FlyString> deprecated_reflected_attribute, Optional<FlyString> initial_value)
+    : Bindings::PlatformObject(realm)
+    , m_element(element)
+    , m_reflected_attribute(move(reflected_attribute))
+    , m_deprecated_reflected_attribute(move(deprecated_reflected_attribute))
+    , m_initial_value(move(initial_value))
+{
+}
+
+SVGAnimatedString::~SVGAnimatedString() = default;
+
+void SVGAnimatedString::initialize(JS::Realm& realm)
+{
+    Base::initialize(realm);
+    set_prototype(&Bindings::ensure_web_prototype<Bindings::SVGAnimatedStringPrototype>(realm, "SVGAnimatedString"_fly_string));
+}
+
+void SVGAnimatedString::visit_edges(Cell::Visitor& visitor)
+{
+    Base::visit_edges(visitor);
+    visitor.visit(m_element);
+}
+
+// https://svgwg.org/svg2-draft/types.html#__svg__SVGAnimatedString__baseVal
+String SVGAnimatedString::base_val() const
+{
+    // On getting baseVal or animVal, the following steps are run:
+    // 1. If the reflected attribute is not present, then:
+    if (!m_element->has_attribute(m_reflected_attribute)) {
+        // 1. If the SVGAnimatedString object is defined to additionally reflect a second, deprecated attribute,
+        //    and that attribute is present, then return its value.
+        if (m_deprecated_reflected_attribute.has_value()) {
+            if (auto attribute = m_element->get_attribute(m_deprecated_reflected_attribute.value()); attribute.has_value())
+                return attribute.release_value();
+        }
+
+        // 2. Otherwise, if the reflected attribute has an initial value, then return it.
+        if (m_initial_value.has_value())
+            return m_initial_value.value().to_string();
+
+        // 3. Otherwise, return the empty string.
+        return {};
+    }
+
+    // 2. Otherwise, the reflected attribute is present. Return its value.
+    return m_element->attribute(m_reflected_attribute).value();
+}
+
+// https://svgwg.org/svg2-draft/types.html#__svg__SVGAnimatedString__baseVal
+void SVGAnimatedString::set_base_val(String const& base_val)
+{
+    // 1. If the reflected attribute is not present, the SVGAnimatedString object is defined to additionally reflect
+    //    a second, deprecated attribute, and that deprecated attribute is present, then set that deprecated attribute
+    //    to the specified value.
+    if (!m_element->has_attribute(m_reflected_attribute)
+        && m_deprecated_reflected_attribute.has_value()
+        && m_element->has_attribute(m_deprecated_reflected_attribute.value())) {
+        MUST(m_element->set_attribute(m_deprecated_reflected_attribute.value(), base_val));
+        return;
+    }
+
+    // 2. Otherwise, set the reflected attribute to the specified value.
+    MUST(m_element->set_attribute(m_reflected_attribute, base_val));
+}
+
+}

+ 38 - 0
Userland/Libraries/LibWeb/SVG/SVGAnimatedString.h

@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/FlyString.h>
+#include <LibWeb/Bindings/PlatformObject.h>
+
+namespace Web::SVG {
+
+// https://svgwg.org/svg2-draft/types.html#InterfaceSVGAnimatedString
+class SVGAnimatedString final : public Bindings::PlatformObject {
+    WEB_PLATFORM_OBJECT(SVGAnimatedString, Bindings::PlatformObject);
+    JS_DECLARE_ALLOCATOR(SVGAnimatedString);
+
+public:
+    [[nodiscard]] static JS::NonnullGCPtr<SVGAnimatedString> create(JS::Realm&, JS::NonnullGCPtr<SVGElement> element, FlyString reflected_attribute, Optional<FlyString> deprecated_reflected_attribute = {}, Optional<FlyString> initial_value = {});
+    virtual ~SVGAnimatedString() override;
+
+    String base_val() const;
+    void set_base_val(String const& base_val);
+
+private:
+    SVGAnimatedString(JS::Realm&, JS::NonnullGCPtr<SVGElement> element, FlyString reflected_attribute, Optional<FlyString> deprecated_reflected_attribute, Optional<FlyString> initial_value);
+
+    virtual void initialize(JS::Realm&) override;
+    virtual void visit_edges(Cell::Visitor&) override;
+
+    JS::NonnullGCPtr<SVGElement> m_element;
+    FlyString m_reflected_attribute;
+    Optional<FlyString> m_deprecated_reflected_attribute;
+    Optional<FlyString> m_initial_value;
+};
+
+}

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

@@ -0,0 +1,6 @@
+// https://svgwg.org/svg2-draft/types.html#InterfaceSVGAnimatedString
+[Exposed=Window]
+interface SVGAnimatedString {
+                                      attribute DOMString baseVal;
+    [ImplementedAs=base_val] readonly attribute DOMString animVal;
+};

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

@@ -228,6 +228,7 @@ libweb_js_bindings(Streams/WritableStreamDefaultController)
 libweb_js_bindings(Streams/WritableStreamDefaultWriter)
 libweb_js_bindings(SVG/SVGAnimatedLength)
 libweb_js_bindings(SVG/SVGAnimatedNumber)
+libweb_js_bindings(SVG/SVGAnimatedString)
 libweb_js_bindings(SVG/SVGClipPathElement)
 libweb_js_bindings(SVG/SVGDefsElement)
 libweb_js_bindings(SVG/SVGElement)