mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 03:57:40 +00:00
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! :^)
This commit is contained in:
parent
228ace854c
commit
3f698db85d
5 changed files with 49 additions and 18 deletions
|
@ -85,14 +85,14 @@ JS::Value HTMLCanvasElementWrapper::get_context(JS::Interpreter& interpreter)
|
||||||
JS::Value HTMLCanvasElementWrapper::width_getter(JS::Interpreter& interpreter)
|
JS::Value HTMLCanvasElementWrapper::width_getter(JS::Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
if (auto* impl = impl_from(interpreter))
|
if (auto* impl = impl_from(interpreter))
|
||||||
return JS::Value(impl->preferred_width());
|
return JS::Value(impl->requested_width());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Value HTMLCanvasElementWrapper::height_getter(JS::Interpreter& interpreter)
|
JS::Value HTMLCanvasElementWrapper::height_getter(JS::Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
if (auto* impl = impl_from(interpreter))
|
if (auto* impl = impl_from(interpreter))
|
||||||
return JS::Value(impl->preferred_height());
|
return JS::Value(impl->requested_height());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,12 @@ OwnPtr<Gfx::Painter> CanvasRenderingContext2D::painter()
|
||||||
if (!m_element)
|
if (!m_element)
|
||||||
return nullptr;
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
|
|
||||||
namespace Web {
|
namespace Web {
|
||||||
|
|
||||||
|
static constexpr auto max_canvas_area = 16384 * 16384;
|
||||||
|
|
||||||
HTMLCanvasElement::HTMLCanvasElement(Document& document, const FlyString& tag_name)
|
HTMLCanvasElement::HTMLCanvasElement(Document& document, const FlyString& tag_name)
|
||||||
: HTMLElement(document, 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;
|
bool ok = false;
|
||||||
int width = attribute("width").to_int(ok);
|
unsigned width = attribute("width").to_int(ok);
|
||||||
if (ok)
|
if (ok)
|
||||||
return width;
|
return width;
|
||||||
|
|
||||||
return 300;
|
return 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
int HTMLCanvasElement::preferred_height() const
|
int HTMLCanvasElement::requested_height() const
|
||||||
{
|
{
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
int height = attribute("height").to_int(ok);
|
unsigned height = attribute("height").to_int(ok);
|
||||||
if (ok)
|
if (ok)
|
||||||
return height;
|
return height;
|
||||||
|
|
||||||
|
@ -79,12 +81,36 @@ CanvasRenderingContext2D* HTMLCanvasElement::get_context(String type)
|
||||||
return m_context;
|
return m_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
Gfx::Bitmap& HTMLCanvasElement::ensure_bitmap()
|
static Gfx::Size bitmap_size_for_canvas(const HTMLCanvasElement& canvas)
|
||||||
{
|
{
|
||||||
if (!m_bitmap || m_bitmap->size() != Gfx::Size(preferred_width(), preferred_height())) {
|
int width = canvas.requested_width();
|
||||||
m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, { preferred_width(), preferred_height() });
|
int height = canvas.requested_height();
|
||||||
|
if (width < 0 || height < 0) {
|
||||||
|
dbg() << "Refusing to create canvas with negative size";
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
return *m_bitmap;
|
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()
|
||||||
|
{
|
||||||
|
auto size = bitmap_size_for_canvas(*this);
|
||||||
|
if (size.is_empty()) {
|
||||||
|
m_bitmap = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_bitmap || m_bitmap->size() != size)
|
||||||
|
m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, size);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,14 +41,15 @@ public:
|
||||||
HTMLCanvasElement(Document&, const FlyString& tag_name);
|
HTMLCanvasElement(Document&, const FlyString& tag_name);
|
||||||
virtual ~HTMLCanvasElement() override;
|
virtual ~HTMLCanvasElement() override;
|
||||||
|
|
||||||
int preferred_width() const;
|
|
||||||
int preferred_height() const;
|
|
||||||
|
|
||||||
const Gfx::Bitmap* bitmap() const { return m_bitmap; }
|
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);
|
CanvasRenderingContext2D* get_context(String type);
|
||||||
|
|
||||||
|
int requested_width() const;
|
||||||
|
int requested_height() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) const override;
|
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");
|
return is<Element>(node) && to<Element>(node).tag_name().equals_ignoring_case("canvas");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,8 @@ LayoutCanvas::~LayoutCanvas()
|
||||||
|
|
||||||
void LayoutCanvas::layout()
|
void LayoutCanvas::layout()
|
||||||
{
|
{
|
||||||
rect().set_width(node().preferred_width());
|
rect().set_width(node().requested_width());
|
||||||
rect().set_height(node().preferred_height());
|
rect().set_height(node().requested_height());
|
||||||
LayoutReplaced::layout();
|
LayoutReplaced::layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue