Sfoglia il codice sorgente

LibWeb: Stub (and implement) `SVGSVGElement` methods and attributes

This implements trivial functions and stubs out the rest.

Implemented:

```
[SameObject] readonly attribute SVGAnimatedLength x;
[SameObject] readonly attribute SVGAnimatedLength y;
[SameObject] readonly attribute SVGAnimatedLength width;
[SameObject] readonly attribute SVGAnimatedLength height;

undefined deselectAll();

SVGLength createSVGLength();
DOMPoint createSVGPoint();
DOMMatrix createSVGMatrix();
DOMRect createSVGRect();
SVGTransform createSVGTransform();

Element getElementById(DOMString elementId);

unsigned long suspendRedraw(unsigned long maxWaitMilliseconds);
undefined unsuspendRedraw(unsigned long suspendHandleID);
undefined unsuspendRedrawAll();
undefined forceRedraw();
```

Stubbed:

```
attribute float currentScale;
[SameObject] readonly attribute DOMPointReadOnly currentTranslate;

NodeList getIntersectionList(
  DOMRectReadOnly rect, SVGElement? referenceElement);
NodeList getEnclosureList(
  DOMRectReadOnly rect, SVGElement? referenceElement);
boolean checkIntersection(SVGElement element, DOMRectReadOnly rect);
boolean checkEnclosure(SVGElement element, DOMRectReadOnly rect);
```
MacDue 1 anno fa
parent
commit
59cd086199

+ 4 - 3
Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp

@@ -41,6 +41,7 @@ static bool is_platform_object(Type const& type)
         "CryptoKey"sv,
         "Document"sv,
         "DocumentType"sv,
+        "DOMRectReadOnly"sv,
         "EventTarget"sv,
         "FileList"sv,
         "FormData"sv,
@@ -3269,7 +3270,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
         retval = "@missing_enum_default_value@"_string;
 
     Array valid_values { @valid_enum_values@ };
-    
+
     auto found = false;
     for (auto const& value : valid_values) {
         if (value.equals_ignoring_ascii_case(retval)) {
@@ -3297,7 +3298,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
                     // 8. Return the canonical keyword for the state of attributeDefinition that contentAttributeValue corresponds to.
                     // NOTE: We run step 8 here to have a field to assign to
                     attribute_generator.append(R"~~~(
-    auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);    
+    auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
 )~~~");
 
                     // 3. Let attributeDefinition be the attribute definition of element's content attribute whose namespace is null
@@ -3326,7 +3327,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
     )~~~");
                     if (invalid_value_default.has_value()) {
                         attribute_generator.append(R"~~~(
-    
+
     if (retval.has_value()) {
         auto found = false;
         for (auto const& value : valid_values) {

+ 99 - 0
Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp

@@ -11,11 +11,13 @@
 #include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Event.h>
+#include <LibWeb/DOM/StaticNodeList.h>
 #include <LibWeb/HTML/Parser/HTMLParser.h>
 #include <LibWeb/Layout/SVGSVGBox.h>
 #include <LibWeb/SVG/AttributeNames.h>
 #include <LibWeb/SVG/SVGAnimatedRect.h>
 #include <LibWeb/SVG/SVGSVGElement.h>
+#include <LibWeb/Selection/Selection.h>
 
 namespace Web::SVG {
 
@@ -149,4 +151,101 @@ Optional<ViewBox> SVGSVGElement::view_box() const
     return {};
 }
 
+JS::NonnullGCPtr<SVGAnimatedLength> SVGSVGElement::x() const
+{
+    return svg_animated_length_for_property(CSS::PropertyID::X);
+}
+
+JS::NonnullGCPtr<SVGAnimatedLength> SVGSVGElement::y() const
+{
+    return svg_animated_length_for_property(CSS::PropertyID::Y);
+}
+
+JS::NonnullGCPtr<SVGAnimatedLength> SVGSVGElement::width() const
+{
+    return svg_animated_length_for_property(CSS::PropertyID::Width);
+}
+
+JS::NonnullGCPtr<SVGAnimatedLength> SVGSVGElement::height() const
+{
+    return svg_animated_length_for_property(CSS::PropertyID::Height);
+}
+
+float SVGSVGElement::current_scale() const
+{
+    dbgln("(STUBBED) SVGSVGElement::current_scale(). Called on: {}", debug_description());
+    return 1.0f;
+}
+
+void SVGSVGElement::set_current_scale(float)
+{
+    dbgln("(STUBBED) SVGSVGElement::set_current_scale(). Called on: {}", debug_description());
+}
+
+JS::NonnullGCPtr<Geometry::DOMPointReadOnly> SVGSVGElement::current_translate() const
+{
+    dbgln("(STUBBED) SVGSVGElement::current_translate(). Called on: {}", debug_description());
+    return Geometry::DOMPointReadOnly::create(realm());
+}
+
+JS::NonnullGCPtr<DOM::NodeList> SVGSVGElement::get_intersection_list(JS::NonnullGCPtr<Geometry::DOMRectReadOnly>, JS::GCPtr<SVGElement>) const
+{
+    dbgln("(STUBBED) SVGSVGElement::get_intersection_list(). Called on: {}", debug_description());
+    return DOM::StaticNodeList::create(realm(), {});
+}
+
+JS::NonnullGCPtr<DOM::NodeList> SVGSVGElement::get_enclosure_list(JS::NonnullGCPtr<Geometry::DOMRectReadOnly>, JS::GCPtr<SVGElement>) const
+{
+    dbgln("(STUBBED) SVGSVGElement::get_enclosure_list(). Called on: {}", debug_description());
+    return DOM::StaticNodeList::create(realm(), {});
+}
+
+bool SVGSVGElement::check_intersection(JS::NonnullGCPtr<SVGElement>, JS::NonnullGCPtr<Geometry::DOMRectReadOnly>) const
+{
+    dbgln("(STUBBED) SVGSVGElement::check_intersection(). Called on: {}", debug_description());
+    return false;
+}
+
+bool SVGSVGElement::check_enclosure(JS::NonnullGCPtr<SVGElement>, JS::NonnullGCPtr<Geometry::DOMRectReadOnly>) const
+{
+    dbgln("(STUBBED) SVGSVGElement::check_enclosure(). Called on: {}", debug_description());
+    return false;
+}
+
+void SVGSVGElement::deselect_all() const
+{
+    // This is equivalent to calling document.getSelection().removeAllRanges() on the document that this ‘svg’ element is in.
+    if (auto selection = document().get_selection())
+        selection->remove_all_ranges();
+}
+
+JS::NonnullGCPtr<SVGLength> SVGSVGElement::create_svg_length() const
+{
+    // A new, detached SVGLength object whose value is the unitless <number> 0.
+    return SVGLength::create(realm(), SVGLength::SVG_LENGTHTYPE_NUMBER, 0);
+}
+
+JS::NonnullGCPtr<Geometry::DOMPoint> SVGSVGElement::create_svg_point() const
+{
+    // A new, detached DOMPoint object whose coordinates are all 0.
+    return Geometry::DOMPoint::from_point(vm(), Geometry::DOMPointInit {});
+}
+
+JS::NonnullGCPtr<Geometry::DOMMatrix> SVGSVGElement::create_svg_matrix() const
+{
+    // A new, detached DOMMatrix object representing the identity matrix.
+    return Geometry::DOMMatrix::create(realm());
+}
+
+JS::NonnullGCPtr<Geometry::DOMRect> SVGSVGElement::create_svg_rect() const
+{
+    // A new, DOMRect object whose x, y, width and height are all 0.
+    return Geometry::DOMRect::construct_impl(realm(), 0, 0, 0, 0).release_value_but_fixme_should_propagate_errors();
+}
+
+JS::NonnullGCPtr<SVGTransform> SVGSVGElement::create_svg_transform() const
+{
+    return SVGTransform::create(realm());
+}
+
 }

+ 47 - 1
Userland/Libraries/LibWeb/SVG/SVGSVGElement.h

@@ -7,15 +7,24 @@
 #pragma once
 
 #include <LibGfx/Bitmap.h>
+#include <LibWeb/DOM/NonElementParentNode.h>
+#include <LibWeb/Geometry/DOMMatrix.h>
+#include <LibWeb/Geometry/DOMPoint.h>
 #include <LibWeb/SVG/AttributeParser.h>
+#include <LibWeb/SVG/SVGAnimatedLength.h>
 #include <LibWeb/SVG/SVGGraphicsElement.h>
+#include <LibWeb/SVG/SVGLength.h>
+#include <LibWeb/SVG/SVGTransform.h>
 #include <LibWeb/SVG/SVGViewport.h>
 #include <LibWeb/SVG/ViewBox.h>
+#include <LibWeb/WebIDL/Types.h>
 
 namespace Web::SVG {
 
 class SVGSVGElement final : public SVGGraphicsElement
-    , public SVGViewport {
+    , public SVGViewport
+    // SVGSVGElement is not strictly a NonElementParentNode, but it implements the same get_element_by_id() method.
+    , public DOM::NonElementParentNode<SVGSVGElement> {
     WEB_PLATFORM_OBJECT(SVGSVGElement, SVGGraphicsElement);
     JS_DECLARE_ALLOCATOR(SVGSVGElement);
 
@@ -34,6 +43,43 @@ public:
 
     JS::NonnullGCPtr<SVGAnimatedRect> view_box_for_bindings() { return *m_view_box_for_bindings; }
 
+    JS::NonnullGCPtr<SVGAnimatedLength> x() const;
+    JS::NonnullGCPtr<SVGAnimatedLength> y() const;
+    JS::NonnullGCPtr<SVGAnimatedLength> width() const;
+    JS::NonnullGCPtr<SVGAnimatedLength> height() const;
+
+    float current_scale() const;
+    void set_current_scale(float);
+
+    JS::NonnullGCPtr<Geometry::DOMPointReadOnly> current_translate() const;
+
+    JS::NonnullGCPtr<DOM::NodeList> get_intersection_list(JS::NonnullGCPtr<Geometry::DOMRectReadOnly> rect, JS::GCPtr<SVGElement> reference_element) const;
+    JS::NonnullGCPtr<DOM::NodeList> get_enclosure_list(JS::NonnullGCPtr<Geometry::DOMRectReadOnly> rect, JS::GCPtr<SVGElement> reference_element) const;
+    bool check_intersection(JS::NonnullGCPtr<SVGElement> element, JS::NonnullGCPtr<Geometry::DOMRectReadOnly> rect) const;
+    bool check_enclosure(JS::NonnullGCPtr<SVGElement> element, JS::NonnullGCPtr<Geometry::DOMRectReadOnly> rect) const;
+
+    void deselect_all() const;
+
+    JS::NonnullGCPtr<SVGLength> create_svg_length() const;
+    JS::NonnullGCPtr<Geometry::DOMPoint> create_svg_point() const;
+    JS::NonnullGCPtr<Geometry::DOMMatrix> create_svg_matrix() const;
+    JS::NonnullGCPtr<Geometry::DOMRect> create_svg_rect() const;
+    JS::NonnullGCPtr<SVGTransform> create_svg_transform() const;
+
+    // Deprecated methods that have no effect when called, but which are kept for compatibility reasons.
+    WebIDL::UnsignedLong suspend_redraw(WebIDL::UnsignedLong max_wait_milliseconds) const
+    {
+        (void)max_wait_milliseconds;
+        // When the suspendRedraw method is called, it must return 1.
+        return 1;
+    }
+    void unsuspend_redraw(WebIDL::UnsignedLong suspend_handle_id) const
+    {
+        (void)suspend_handle_id;
+    }
+    void unsuspend_redraw_all() const {};
+    void force_redraw() const {};
+
 private:
     SVGSVGElement(DOM::Document&, DOM::QualifiedName);
 

+ 32 - 0
Userland/Libraries/LibWeb/SVG/SVGSVGElement.idl

@@ -1,10 +1,42 @@
 #import <SVG/SVGGraphicsElement.idl>
 #import <SVG/SVGFitToViewBox.idl>
+#import <Geometry/DOMRectReadOnly.idl>
 
 // https://svgwg.org/svg2-draft/struct.html#InterfaceSVGSVGElement
 [Exposed=Window]
 interface SVGSVGElement : SVGGraphicsElement {
+  [SameObject] readonly attribute SVGAnimatedLength x;
+  [SameObject] readonly attribute SVGAnimatedLength y;
+  [SameObject] readonly attribute SVGAnimatedLength width;
+  [SameObject] readonly attribute SVGAnimatedLength height;
 
+  attribute float currentScale;
+  [SameObject] readonly attribute DOMPointReadOnly currentTranslate;
+
+  NodeList getIntersectionList(DOMRectReadOnly rect, SVGElement? referenceElement);
+  NodeList getEnclosureList(DOMRectReadOnly rect, SVGElement? referenceElement);
+  boolean checkIntersection(SVGElement element, DOMRectReadOnly rect);
+  boolean checkEnclosure(SVGElement element, DOMRectReadOnly rect);
+
+  undefined deselectAll();
+
+  // FIMXE: SVGNumber createSVGNumber();
+  SVGLength createSVGLength();
+  // FIXME: SVGAngle createSVGAngle();
+  DOMPoint createSVGPoint();
+  DOMMatrix createSVGMatrix();
+  DOMRect createSVGRect();
+  SVGTransform createSVGTransform();
+  // FIXME: SVGTransform createSVGTransformFromMatrix(optional DOMMatrix2DInit matrix = {});
+
+  Element getElementById(DOMString elementId);
+
+  // Deprecated methods that have no effect when called,
+  // but which are kept for compatibility reasons.
+  unsigned long suspendRedraw(unsigned long maxWaitMilliseconds);
+  undefined unsuspendRedraw(unsigned long suspendHandleID);
+  undefined unsuspendRedrawAll();
+  undefined forceRedraw();
 };
 
 SVGSVGElement includes SVGFitToViewBox;