From b700b773846360e6f522c6f5f2cce962c6ed706b Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Thu, 5 Feb 2026 11:47:26 +0100 Subject: [PATCH] Set canvas size on addPage and don't destroy PDF surface on width/height change --- CHANGELOG.md | 1 + src/Canvas.cc | 8 +++++--- src/CanvasRenderingContext2d.cc | 2 +- src/backend/Backend.cc | 14 +++++++++++--- src/backend/Backend.h | 3 +++ src/backend/PdfBackend.cc | 4 ++++ src/backend/PdfBackend.h | 1 + 7 files changed, 26 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d42554576..db4de5d52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ project adheres to [Semantic Versioning](http://semver.org/). ### Added ### Fixed * Fix dangling env pointer in image MIME data cleanup (#2550) +* Set canvas size on addPage and don't destroy PDF surface on width/height change (#2538) 3.2.1 ================== diff --git a/src/Canvas.cc b/src/Canvas.cc index bc790add5..9f83b6642 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -671,7 +671,7 @@ str_value(Napi::Maybe maybe, const char *fallback, bool can_be_numb return strdup(fallback); } } - + return NULL; } @@ -907,8 +907,10 @@ Canvas::resurface(Napi::Object This) { Napi::Value context; if (This.Get("context").UnwrapTo(&context) && context.IsObject()) { - backend()->destroySurface(); - backend()->ensureSurface(); + if (backend()->getName() != "pdf") { + backend()->destroySurface(); + backend()->ensureSurface(); + } // Reset context Context2d *context2d = Context2d::Unwrap(context.As()); cairo_t *prev = context2d->context(); diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 3f52c1fdd..cda1b29f1 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -763,7 +763,7 @@ Context2d::AddPage(const Napi::CallbackInfo& info) { int height = info[1].ToNumber().UnwrapOr(zero).Int32Value(); if (width < 1) width = canvas()->getWidth(); if (height < 1) height = canvas()->getHeight(); - cairo_pdf_surface_set_size(canvas()->surface(), width, height); + canvas()->backend()->setSize(width, height); } /* diff --git a/src/backend/Backend.cc b/src/backend/Backend.cc index 4607fb646..49b799899 100644 --- a/src/backend/Backend.cc +++ b/src/backend/Backend.cc @@ -29,8 +29,7 @@ int Backend::getWidth() } void Backend::setWidth(int width_) { - this->destroySurface(); - this->width = width_; + setSize(width_, height); } int Backend::getHeight() @@ -39,8 +38,17 @@ int Backend::getHeight() } void Backend::setHeight(int height_) { + setSize(width, height_); +} + +void Backend::setSize(int width_, int height_) { + width = width_; + height = height_; + resetSurface(); +} + +void Backend::resetSurface() { this->destroySurface(); - this->height = height_; } bool Backend::isSurfaceValid() { diff --git a/src/backend/Backend.h b/src/backend/Backend.h index d51eb7601..54395c9d8 100644 --- a/src/backend/Backend.h +++ b/src/backend/Backend.h @@ -28,6 +28,7 @@ class Backend virtual cairo_surface_t* ensureSurface() = 0; virtual void destroySurface() = 0; + virtual void resetSurface(); DLL_PUBLIC std::string getName(); @@ -37,6 +38,8 @@ class Backend DLL_PUBLIC int getHeight(); virtual void setHeight(int height); + void setSize(int width, int height); + // Overridden by ImageBackend. SVG and PDF thus always return INVALID. virtual cairo_format_t getFormat() { return CAIRO_FORMAT_INVALID; diff --git a/src/backend/PdfBackend.cc b/src/backend/PdfBackend.cc index 4eb46168c..5e8133e57 100644 --- a/src/backend/PdfBackend.cc +++ b/src/backend/PdfBackend.cc @@ -31,6 +31,10 @@ void PdfBackend::destroySurface() { } } +void PdfBackend::resetSurface() { + cairo_pdf_surface_set_size(ensureSurface(), width, height); +} + void PdfBackend::Initialize(Napi::Object target) { Napi::Env env = target.Env(); diff --git a/src/backend/PdfBackend.h b/src/backend/PdfBackend.h index 6ae8415c8..879b0aaee 100644 --- a/src/backend/PdfBackend.h +++ b/src/backend/PdfBackend.h @@ -9,6 +9,7 @@ class PdfBackend : public Napi::ObjectWrap, public Backend private: cairo_surface_t* ensureSurface(); void destroySurface(); + void resetSurface(); cairo_surface_t* surface = nullptr; public: