From a52c8334f53f3552485b5a4db89df1b1b62180ce Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Tue, 21 Apr 2026 22:23:28 +0200 Subject: [PATCH] Avoid to add outlines having a deleted page which leads to clone a useless page (bug 2033908) --- src/core/editor/pdf_editor.js | 7 ++++-- test/pdfs/.gitignore | 1 + test/pdfs/outline_goto_action.pdf | Bin 0 -> 1061 bytes test/unit/api_spec.js | 35 ++++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 test/pdfs/outline_goto_action.pdf diff --git a/src/core/editor/pdf_editor.js b/src/core/editor/pdf_editor.js index 51f5b5faf..5c2288920 100644 --- a/src/core/editor/pdf_editor.js +++ b/src/core/editor/pdf_editor.js @@ -1452,9 +1452,12 @@ class PDFEditor { result.push({ ...item, // When the item's own destination is invalid (but it has surviving - // children), clear the destination so the output item is a plain - // container rather than a broken link. + // children), clear the destination and rawDict so the output item is + // a plain container rather than a broken link. Clearing rawDict + // prevents #setOutlineItemDest from cloning a GoTo action that + // references a deleted page via its D array. dest: hasValidOwnDest ? item.dest : null, + rawDict: hasValidOwnDest ? item.rawDict : null, items: filteredChildren, _documentData: documentData, }); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 1bd14c54d..d591829ed 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -886,6 +886,7 @@ !outlines_se.pdf !radial_gradients.pdf !outlines_for_editor.pdf +!outline_goto_action.pdf !mesh_shading_empty.pdf !acroform_calculation_order.pdf !extractPages_null_in_array.pdf diff --git a/test/pdfs/outline_goto_action.pdf b/test/pdfs/outline_goto_action.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6cbc020c686c20bc349d4605ce8c1a1308cc1f82 GIT binary patch literal 1061 zcmb_bOHRWu5CyTb#2sc+2^QeEshc7pBxor}6j4fd6$?X52?{Yvj8r%aXW|BM5LV3C zO;XY=S+wzF-kZ;RZjA@SJ+U9L*3b9PCle5WxqD)Vhrp+AFB*7XS(TbO@Ufcf0@|1` z0eHA*-kK=vwnpuSNizF^!7CKyqes7_MQ+ORt#dGc8uKJ~p z6Ln%1FbgnW9!ThQ+PB!N$tX|J*3U>Xny}7aVwK=A>E#u1tQjP!SB#}x^uWF^=QWrs8=Y@ry8> + // "Child" /Dest [page2Ref /FitH 0] + const loadingTask = getDocument( + buildGetDocumentParams("outline_goto_action.pdf") + ); + const pdfDoc = await loadingTask.promise; + const data = await pdfDoc.extractPages([ + { document: null, includePages: [1] }, + ]); + await loadingTask.destroy(); + + const newLoadingTask = getDocument(data); + const newPdfDoc = await newLoadingTask.promise; + expect(newPdfDoc.numPages).toEqual(1); + + const outline = await newPdfDoc.getOutline(); + expect(Array.isArray(outline)).toEqual(true); + expect(outline.length).toEqual(1); + + // "Parent" is kept as a plain container (dest cleared, no action). + const parent = outline[0]; + expect(parent.title).toEqual("Parent"); + expect(parent.dest).toEqual(null); + expect(parent.items.length).toEqual(1); + + // "Child" keeps its explicit dest pointing to the (only) kept page. + const child = parent.items[0]; + expect(child.title).toEqual("Child"); + expect(Array.isArray(child.dest)).toEqual(true); + + await newLoadingTask.destroy(); + }); }); describe("extract pages with null values in arrays", function () {