summaryrefslogtreecommitdiff
path: root/Libraries/LibWeb
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-04-15 12:12:19 +0200
committerAndreas Kling <kling@serenityos.org>2020-04-15 12:29:21 +0200
commit3f698db85dadb5e984bce6efc6d29ab5ed6b183a (patch)
treec02d639194ec11fa31c169c4b3a3a6784420ceb3 /Libraries/LibWeb
parent228ace854c2c5bca7646d12789b240594ea94111 (diff)
downloadserenity-3f698db85dadb5e984bce6efc6d29ab5ed6b183a.zip
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! :^)
Diffstat (limited to 'Libraries/LibWeb')
-rw-r--r--Libraries/LibWeb/Bindings/HTMLCanvasElementWrapper.cpp4
-rw-r--r--Libraries/LibWeb/DOM/CanvasRenderingContext2D.cpp7
-rw-r--r--Libraries/LibWeb/DOM/HTMLCanvasElement.cpp42
-rw-r--r--Libraries/LibWeb/DOM/HTMLCanvasElement.h10
-rw-r--r--Libraries/LibWeb/Layout/LayoutCanvas.cpp4
5 files changed, 49 insertions, 18 deletions
diff --git a/Libraries/LibWeb/Bindings/HTMLCanvasElementWrapper.cpp b/Libraries/LibWeb/Bindings/HTMLCanvasElementWrapper.cpp
index b6f584df76..193ec65901 100644
--- a/Libraries/LibWeb/Bindings/HTMLCanvasElementWrapper.cpp
+++ b/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 {};
}
diff --git a/Libraries/LibWeb/DOM/CanvasRenderingContext2D.cpp b/Libraries/LibWeb/DOM/CanvasRenderingContext2D.cpp
index a9282a4061..92c8b3d68c 100644
--- a/Libraries/LibWeb/DOM/CanvasRenderingContext2D.cpp
+++ b/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());
}
}
diff --git a/Libraries/LibWeb/DOM/HTMLCanvasElement.cpp b/Libraries/LibWeb/DOM/HTMLCanvasElement.cpp
index efade12919..c33f257e94 100644
--- a/Libraries/LibWeb/DOM/HTMLCanvasElement.cpp
+++ b/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;
}
}
diff --git a/Libraries/LibWeb/DOM/HTMLCanvasElement.h b/Libraries/LibWeb/DOM/HTMLCanvasElement.h
index 7ac9e9195f..fb1c9d141a 100644
--- a/Libraries/LibWeb/DOM/HTMLCanvasElement.h
+++ b/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");
}
-
}
diff --git a/Libraries/LibWeb/Layout/LayoutCanvas.cpp b/Libraries/LibWeb/Layout/LayoutCanvas.cpp
index 39b81f8454..deb316ea49 100644
--- a/Libraries/LibWeb/Layout/LayoutCanvas.cpp
+++ b/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();
}