-
Couldn't load subscription status.
- 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.pagesfrom 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