Преглед изворни кода

LibWeb: Limit the maximum size of <canvas> bitmap buffers

We will no longer create bitmap buffers for canvases that exceed a
total area of (16384 * 16384) pixels. This matches what some other
browser do.

Thanks to @itamar8910 for finding this! :^)
Andreas Kling пре 5 година
родитељ
комит
3f698db85d

+ 2 - 2
Libraries/LibWeb/Bindings/HTMLCanvasElementWrapper.cpp

@@ -85,14 +85,14 @@ JS::Value HTMLCanvasElementWrapper::get_context(JS::Interpreter& interpreter)
 JS::Value HTMLCanvasElementWrapper::width_getter(JS::Interpreter& interpreter)
 {
     if (auto* impl = impl_from(interpreter))
-        return JS::Value(impl->preferred_width());
+        return JS::Value(impl->requested_width());
     return {};
 }
 
 JS::Value HTMLCanvasElementWrapper::height_getter(JS::Interpreter& interpreter)
 {
     if (auto* impl = impl_from(interpreter))
-        return JS::Value(impl->preferred_height());
+        return JS::Value(impl->requested_height());
     return {};
 }
 

+ 6 - 1
Libraries/LibWeb/DOM/CanvasRenderingContext2D.cpp

@@ -126,7 +126,12 @@ OwnPtr<Gfx::Painter> CanvasRenderingContext2D::painter()
     if (!m_element)
         return nullptr;
 
-    return make<Gfx::Painter>(m_element->ensure_bitmap());
+    if (!m_element->bitmap()) {
+        if (!m_element->create_bitmap())
+            return nullptr;
+    }
+
+    return make<Gfx::Painter>(*m_element->bitmap());
 }
 
 }

+ 34 - 8
Libraries/LibWeb/DOM/HTMLCanvasElement.cpp

@@ -33,6 +33,8 @@
 
 namespace Web {
 
+static constexpr auto max_canvas_area = 16384 * 16384;
+
 HTMLCanvasElement::HTMLCanvasElement(Document& document, const FlyString& tag_name)
     : HTMLElement(document, tag_name)
 {
@@ -42,20 +44,20 @@ HTMLCanvasElement::~HTMLCanvasElement()
 {
 }
 
-int HTMLCanvasElement::preferred_width() const
+int HTMLCanvasElement::requested_width() const
 {
     bool ok = false;
-    int width = attribute("width").to_int(ok);
+    unsigned width = attribute("width").to_int(ok);
     if (ok)
         return width;
 
     return 300;
 }
 
-int HTMLCanvasElement::preferred_height() const
+int HTMLCanvasElement::requested_height() const
 {
     bool ok = false;
-    int height = attribute("height").to_int(ok);
+    unsigned height = attribute("height").to_int(ok);
     if (ok)
         return height;
 
@@ -79,12 +81,36 @@ CanvasRenderingContext2D* HTMLCanvasElement::get_context(String type)
     return m_context;
 }
 
-Gfx::Bitmap& HTMLCanvasElement::ensure_bitmap()
+static Gfx::Size bitmap_size_for_canvas(const HTMLCanvasElement& canvas)
+{
+    int width = canvas.requested_width();
+    int height = canvas.requested_height();
+    if (width < 0 || height < 0) {
+        dbg() << "Refusing to create canvas with negative size";
+        return {};
+    }
+    int area = 0;
+    if (__builtin_mul_overflow(width, height, &area)) {
+        dbg() << "Refusing to create " << width << "x" << height << " canvas (overflow)";
+        return {};
+    }
+    if (area > max_canvas_area) {
+        dbg() << "Refusing to create " << width << "x" << height << " canvas (exceeds maximum size)";
+        return {};
+    }
+    return { width, height };
+}
+
+bool HTMLCanvasElement::create_bitmap()
 {
-    if (!m_bitmap || m_bitmap->size() != Gfx::Size(preferred_width(), preferred_height())) {
-        m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, { preferred_width(), preferred_height() });
+    auto size = bitmap_size_for_canvas(*this);
+    if (size.is_empty()) {
+        m_bitmap = nullptr;
+        return false;
     }
-    return *m_bitmap;
+    if (!m_bitmap || m_bitmap->size() != size)
+        m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, size);
+    return true;
 }
 
 }

+ 5 - 5
Libraries/LibWeb/DOM/HTMLCanvasElement.h

@@ -41,14 +41,15 @@ public:
     HTMLCanvasElement(Document&, const FlyString& tag_name);
     virtual ~HTMLCanvasElement() override;
 
-    int preferred_width() const;
-    int preferred_height() const;
-
     const Gfx::Bitmap* bitmap() const { return m_bitmap; }
-    Gfx::Bitmap& ensure_bitmap();
+    Gfx::Bitmap* bitmap() { return m_bitmap; }
+    bool create_bitmap();
 
     CanvasRenderingContext2D* get_context(String type);
 
+    int requested_width() const;
+    int requested_height() const;
+
 private:
     virtual RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) const override;
 
@@ -62,5 +63,4 @@ inline bool is<HTMLCanvasElement>(const Node& node)
     return is<Element>(node) && to<Element>(node).tag_name().equals_ignoring_case("canvas");
 }
 
-
 }

+ 2 - 2
Libraries/LibWeb/Layout/LayoutCanvas.cpp

@@ -42,8 +42,8 @@ LayoutCanvas::~LayoutCanvas()
 
 void LayoutCanvas::layout()
 {
-    rect().set_width(node().preferred_width());
-    rect().set_height(node().preferred_height());
+    rect().set_width(node().requested_width());
+    rect().set_height(node().requested_height());
     LayoutReplaced::layout();
 }