Skip to content

Commit

Permalink
Add support for "GoToE" actions with destinations (issue 17056)
Browse files Browse the repository at this point in the history
This shouldn't be very common in practice, since "GoToE" actions themselves seem quite uncommon; see PR 15537.
  • Loading branch information
Snuffleupagus committed Oct 3, 2023
1 parent 59d94b5 commit e3820c8
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 19 deletions.
37 changes: 24 additions & 13 deletions src/core/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ function fetchDestination(dest) {
return Array.isArray(dest) ? dest : null;
}

function fetchRemoteDest(action) {
let dest = action.get("D");
if (dest) {
if (dest instanceof Name) {
dest = dest.name;
}
if (typeof dest === "string") {
return stringToPDFString(dest);
} else if (Array.isArray(dest)) {
return JSON.stringify(dest);
}
}
return null;
}

class Catalog {
constructor(pdfManager, xref) {
this.pdfManager = pdfManager;
Expand Down Expand Up @@ -1514,19 +1529,9 @@ class Catalog {
}

// NOTE: the destination is relative to the *remote* document.
let remoteDest = action.get("D");
if (remoteDest) {
if (remoteDest instanceof Name) {
remoteDest = remoteDest.name;
}
if (typeof url === "string") {
const baseUrl = url.split("#")[0];
if (typeof remoteDest === "string") {
url = baseUrl + "#" + remoteDest;
} else if (Array.isArray(remoteDest)) {
url = baseUrl + "#" + JSON.stringify(remoteDest);
}
}
const remoteDest = fetchRemoteDest(action);
if (remoteDest && typeof url === "string") {
url = /* baseUrl = */ url.split("#")[0] + "#" + remoteDest;
}
// The 'NewWindow' property, equal to `LinkTarget.BLANK`.
const newWindow = action.get("NewWindow");
Expand All @@ -1550,6 +1555,12 @@ class Catalog {

if (attachment) {
resultObj.attachment = attachment;

// NOTE: the destination is relative to the *attachment*.
const attachmentDest = fetchRemoteDest(action);
if (remoteDest) {
resultObj.attachmentDest = attachmentDest;
}
} else {
warn(`parseDestDictionary - unimplemented "GoToE" action.`);
}
Expand Down
8 changes: 5 additions & 3 deletions src/display/annotation_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ class LinkAnnotationElement extends AnnotationElement {
this._bindNamedAction(link, data.action);
isBound = true;
} else if (data.attachment) {
this._bindAttachment(link, data.attachment);
this.#bindAttachment(link, data.attachment, data.attachmentDest);
isBound = true;
} else if (data.setOCGState) {
this.#bindSetOCGState(link, data.setOCGState);
Expand Down Expand Up @@ -793,14 +793,16 @@ class LinkAnnotationElement extends AnnotationElement {
* Bind attachments to the link element.
* @param {Object} link
* @param {Object} attachment
* @param {str} [dest]
*/
_bindAttachment(link, attachment) {
#bindAttachment(link, attachment, dest = null) {
link.href = this.linkService.getAnchorUrl("");
link.onclick = () => {
this.downloadManager?.openOrDownloadData(
this.container,
attachment.content,
attachment.filename
attachment.filename,
dest
);
return false;
};
Expand Down
1 change: 1 addition & 0 deletions test/pdfs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
!issue7439.pdf
!issue7847_radial.pdf
!issue8844.pdf
!issue17056.pdf
!issue14953.pdf
!issue15367.pdf
!issue15372.pdf
Expand Down
Binary file added test/pdfs/issue17056.pdf
Binary file not shown.
23 changes: 23 additions & 0 deletions test/unit/api_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2855,6 +2855,29 @@ describe("api", function () {
expect(content instanceof Uint8Array).toEqual(true);
expect(content.length).toEqual(4508);

expect(annotations[0].attachmentDest).toEqual('[-1,{"name":"Fit"}]');

await loadingTask.destroy();
});

it("gets annotations containing GoToE action with destination (issue 17056)", async function () {
const loadingTask = getDocument(buildGetDocumentParams("issue17056.pdf"));
const pdfDoc = await loadingTask.promise;
const pdfPage = await pdfDoc.getPage(1);

const annotations = await pdfPage.getAnnotations();
expect(annotations.length).toEqual(30);

const { annotationType, attachment, attachmentDest } = annotations[0];
expect(annotationType).toEqual(AnnotationType.LINK);

const { filename, content } = attachment;
expect(filename).toEqual("destination-doc.pdf");
expect(content instanceof Uint8Array).toEqual(true);
expect(content.length).toEqual(10305);

expect(attachmentDest).toEqual('[0,{"name":"Fit"}]');

await loadingTask.destroy();
});

Expand Down
5 changes: 4 additions & 1 deletion web/download_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class DownloadManager {
/**
* @returns {boolean} Indicating if the data was opened.
*/
openOrDownloadData(element, data, filename) {
openOrDownloadData(element, data, filename, dest = null) {
const isPdfData = isPdfFile(filename);
const contentType = isPdfData ? "application/pdf" : "";

Expand All @@ -93,6 +93,9 @@ class DownloadManager {
"?file=" +
encodeURIComponent(blobUrl + "#" + filename);
}
if (dest) {
viewerUrl += `#${dest}`;
}

try {
window.open(viewerUrl);
Expand Down
7 changes: 5 additions & 2 deletions web/firefoxcom.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class DownloadManager {
/**
* @returns {boolean} Indicating if the data was opened.
*/
openOrDownloadData(element, data, filename) {
openOrDownloadData(element, data, filename, dest = null) {
const isPdfData = isPdfFile(filename);
const contentType = isPdfData ? "application/pdf" : "";

Expand All @@ -143,7 +143,10 @@ class DownloadManager {
this.#openBlobUrls.set(element, blobUrl);
}
// Let Firefox's content handler catch the URL and display the PDF.
const viewerUrl = blobUrl + "#filename=" + encodeURIComponent(filename);
let viewerUrl = blobUrl + "?filename=" + encodeURIComponent(filename);
if (dest) {
viewerUrl += `#${dest}`;
}

try {
window.open(viewerUrl);
Expand Down

0 comments on commit e3820c8

Please sign in to comment.