ソースを参照

LibWeb: Make SVGImageElement part of CanvasImageSource union

This is very janky at the moment but it also more correct. :^)
Andreas Kling 10 ヶ月 前
コミット
cd0e4a49b8

+ 3 - 0
Tests/LibWeb/Text/expected/canvas/pattern-from-image.txt

@@ -0,0 +1,3 @@
+null
+null
+PASS (didn't throw!)

+ 12 - 0
Tests/LibWeb/Text/input/canvas/pattern-from-image.html

@@ -0,0 +1,12 @@
+<script src="../include.js"></script>
+<script>
+    test(() => {
+        let canvas = document.createElement("canvas");
+        let ctx = canvas.getContext("2d");
+        let img = document.createElement("img");
+        println(ctx.createPattern(img, 'repeat'));
+        img = document.createElementNS("http://www.w3.org/2000/svg", "image");
+        println(ctx.createPattern(img, 'repeat'));
+        println("PASS (didn't throw!)");
+    });
+</script>

+ 1 - 0
Userland/Libraries/LibWeb/Forward.h

@@ -707,6 +707,7 @@ class SVGEllipseElement;
 class SVGForeignObjectElement;
 class SVGGeometryElement;
 class SVGGraphicsElement;
+class SVGImageElement;
 class SVGLength;
 class SVGLineElement;
 class SVGMaskElement;

+ 21 - 9
Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.cpp

@@ -6,20 +6,32 @@
 
 #include <LibWeb/HTML/Canvas/CanvasDrawImage.h>
 #include <LibWeb/HTML/ImageBitmap.h>
+#include <LibWeb/SVG/SVGImageElement.h>
 
 namespace Web::HTML {
 
 static void default_source_size(CanvasImageSource const& image, float& source_width, float& source_height)
 {
-    image.visit([&source_width, &source_height](auto const& source) {
-        if (source->bitmap()) {
-            source_width = source->bitmap()->width();
-            source_height = source->bitmap()->height();
-        } else {
-            source_width = source->width();
-            source_height = source->height();
-        }
-    });
+    image.visit(
+        [&source_width, &source_height](JS::Handle<SVG::SVGImageElement> const& source) {
+            if (source->bitmap()) {
+                source_width = source->bitmap()->width();
+                source_height = source->bitmap()->height();
+            } else {
+                // FIXME: This is very janky and not correct.
+                source_width = source->width()->anim_val()->value();
+                source_height = source->height()->anim_val()->value();
+            }
+        },
+        [&source_width, &source_height](auto const& source) {
+            if (source->bitmap()) {
+                source_width = source->bitmap()->width();
+                source_height = source->bitmap()->height();
+            } else {
+                source_width = source->width();
+                source_height = source->height();
+            }
+        });
 }
 
 WebIDL::ExceptionOr<void> CanvasDrawImage::draw_image(Web::HTML::CanvasImageSource const& image, float destination_x, float destination_y)

+ 1 - 1
Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.h

@@ -15,7 +15,7 @@ namespace Web::HTML {
 
 // https://html.spec.whatwg.org/multipage/canvas.html#canvasimagesource
 // NOTE: This is the Variant created by the IDL wrapper generator, and needs to be updated accordingly.
-using CanvasImageSource = Variant<JS::Handle<HTMLImageElement>, JS::Handle<HTMLCanvasElement>, JS::Handle<ImageBitmap>>;
+using CanvasImageSource = Variant<JS::Handle<HTMLImageElement>, JS::Handle<SVG::SVGImageElement>, JS::Handle<HTMLCanvasElement>, JS::Handle<ImageBitmap>>;
 
 // https://html.spec.whatwg.org/multipage/canvas.html#canvasdrawimage
 class CanvasDrawImage {

+ 2 - 0
Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.idl

@@ -1,8 +1,10 @@
 #import <HTML/HTMLCanvasElement.idl>
 #import <HTML/HTMLImageElement.idl>
 #import <HTML/ImageBitmap.idl>
+#import <SVG/SVGImageElement.idl>
 
 typedef (HTMLImageElement or
+         SVGImageElement or
 // FIXME: We should use HTMLOrSVGImageElement instead of HTMLImageElement
 // FIXME: HTMLVideoElement or
          HTMLCanvasElement or

+ 1 - 2
Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.idl

@@ -10,6 +10,5 @@ interface mixin CanvasFillStrokeStyles {
     CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1);
     CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
     CanvasGradient createConicGradient(double startAngle, double x, double y);
-    // FIXME: 'image' should be a CanvasImageSource
-    CanvasPattern? createPattern((HTMLImageElement or HTMLCanvasElement) image, [LegacyNullToEmptyString] DOMString repetition);
+    CanvasPattern? createPattern(CanvasImageSource image, [LegacyNullToEmptyString] DOMString repetition);
 };

+ 1 - 0
Userland/Libraries/LibWeb/HTML/CanvasPattern.cpp

@@ -10,6 +10,7 @@
 #include <LibWeb/HTML/CanvasPattern.h>
 #include <LibWeb/HTML/CanvasRenderingContext2D.h>
 #include <LibWeb/HTML/ImageBitmap.h>
+#include <LibWeb/SVG/SVGImageElement.h>
 
 namespace Web::HTML {
 

+ 18 - 0
Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp

@@ -24,6 +24,7 @@
 #include <LibWeb/Layout/TextNode.h>
 #include <LibWeb/Painting/Paintable.h>
 #include <LibWeb/Platform/FontPlugin.h>
+#include <LibWeb/SVG/SVGImageElement.h>
 #include <LibWeb/WebIDL/ExceptionOr.h>
 
 namespace Web::HTML {
@@ -572,6 +573,19 @@ WebIDL::ExceptionOr<CanvasImageSourceUsability> check_usability_of_image(CanvasI
                 return { CanvasImageSourceUsability::Bad };
             return Optional<CanvasImageSourceUsability> {};
         },
+        // FIXME: Don't duplicate this for HTMLImageElement and SVGImageElement.
+        [](JS::Handle<SVG::SVGImageElement> const& image_element) -> WebIDL::ExceptionOr<Optional<CanvasImageSourceUsability>> {
+            // FIXME: If image's current request's state is broken, then throw an "InvalidStateError" DOMException.
+
+            // If image is not fully decodable, then return bad.
+            if (!image_element->bitmap())
+                return { CanvasImageSourceUsability::Bad };
+
+            // If image has an intrinsic width or intrinsic height (or both) equal to zero, then return bad.
+            if (image_element->bitmap()->width() == 0 || image_element->bitmap()->height() == 0)
+                return { CanvasImageSourceUsability::Bad };
+            return Optional<CanvasImageSourceUsability> {};
+        },
 
         // FIXME: HTMLVideoElement
         // If image's readyState attribute is either HAVE_NOTHING or HAVE_METADATA, then return bad.
@@ -609,6 +623,10 @@ bool image_is_not_origin_clean(CanvasImageSource const& image)
             // FIXME: image's current request's image data is CORS-cross-origin.
             return false;
         },
+        [](JS::Handle<SVG::SVGImageElement> const&) {
+            // FIXME: image's current request's image data is CORS-cross-origin.
+            return false;
+        },
 
         // FIXME: HTMLVideoElement
         // image's media data is CORS-cross-origin.

+ 9 - 0
Userland/Libraries/LibWeb/SVG/SVGImageElement.h

@@ -29,6 +29,15 @@ public:
 
     Gfx::Rect<CSSPixels> bounding_box() const;
 
+    // FIXME: This is a hack for images used as CanvasImageSource. Do something more elegant.
+    RefPtr<Gfx::Bitmap> bitmap() const
+    {
+        auto bitmap = current_image_bitmap();
+        if (!bitmap)
+            return nullptr;
+        return bitmap->bitmap();
+    }
+
     // ^Layout::ImageProvider
     virtual bool is_image_available() const override;
     virtual Optional<CSSPixels> intrinsic_width() const override;