-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Description
Environment
- jsPDF version: 3.0.3
- nodejs: 20.19.0
- OS: Linux ubuntu 24
Description
When restoring a RenderTarget
(e.g., after creating a FormObject), the internal reference API.internal.pages
is not updated to reflect the restored pages
array.
This results in a desynchronization between the internal rendering context and the public API (doc.internal.pages
), which causes incorrect behavior in plugins or custom rendering logic that relies on the internal API.
Minimal code example
const doc = new jsPDF();
const pages1 = doc.internal.pages;
doc.beginFormObject( 0, 0, doc.internal.pageSize.width, context.internal.pageSize.height, context.Matrix( 1, 0, 0, 1, 0, 0 ) );
doc.endFormObject("myFormObject");
doc.addPage( "a4", "landscape" );
const pages2 = doc.internal.pages );
console.log( pages1, pages2, pages1 === pages2 );
Expected behavior
After restoring the previous render target,
API.internal.pages
should be updated to reference the restored pages
array,
so that the public and internal contexts stay in sync.
Actual behavior
API.internal.pages
continues pointing to the old pages
array created before beginFormObject()
.
This leads to inconsistencies when interacting with doc.internal.pages
or plugins that use it.
Suspected cause
In RenderTarget.prototype.restore()
(see snippet below),
the pages
variable is reassigned,
but the internal API references (API.internal.pages
) is not updated:
Lines 5722 to 5733 in 463b199
RenderTarget.prototype.restore = function() { | |
page = this.page; | |
currentPage = this.currentPage; | |
pagesContext = this.pagesContext; | |
pages = this.pages; | |
pageX = this.x; | |
pageY = this.y; | |
pageMatrix = this.matrix; | |
setPageWidthWithoutScaling(currentPage, this.width); | |
setPageHeightWithoutScaling(currentPage, this.height); | |
outputDestination = this.outputDestination; | |
}; |
Suggested fix
Rebind API.internal.pages
after restoring the render target:
RenderTarget.prototype.restore = function() {
page = this.page;
currentPage = this.currentPage;
pagesContext = this.pagesContext;
API.internal.pages = pages = this.pages;
pageX = this.x;
pageY = this.y;
pageMatrix = this.matrix;
setPageWidthWithoutScaling(currentPage, this.width);
setPageHeightWithoutScaling(currentPage, this.height);
outputDestination = this.outputDestination;
};
Why this matters
- Keeps the internal and public state consistent.
- Prevents plugins and internal tools that use
API.internal.pages
from breaking after a render target restore. - Maintains predictable document behavior when working with FormObjects or custom render targets.
PS: Generated by chatgpt and edited by a Human