diff options
author | Andreas Kling <kling@serenityos.org> | 2020-04-15 12:12:19 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-15 12:29:21 +0200 |
commit | 3f698db85dadb5e984bce6efc6d29ab5ed6b183a (patch) | |
tree | c02d639194ec11fa31c169c4b3a3a6784420ceb3 /Libraries/LibWeb | |
parent | 228ace854c2c5bca7646d12789b240594ea94111 (diff) | |
download | serenity-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.cpp | 4 | ||||
-rw-r--r-- | Libraries/LibWeb/DOM/CanvasRenderingContext2D.cpp | 7 | ||||
-rw-r--r-- | Libraries/LibWeb/DOM/HTMLCanvasElement.cpp | 42 | ||||
-rw-r--r-- | Libraries/LibWeb/DOM/HTMLCanvasElement.h | 10 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutCanvas.cpp | 4 |
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(); } |