2015-04-28 00:25:32 +09:00
|
|
|
/* Copyright 2015 Mozilla Foundation
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2017-04-17 07:48:45 +09:00
|
|
|
import { getGlobalEventBus } from './dom_events';
|
2017-04-15 00:32:36 +09:00
|
|
|
import { parseQueryString } from './ui_utils';
|
2016-04-09 02:34:27 +09:00
|
|
|
|
2016-04-26 07:57:15 +09:00
|
|
|
/**
|
|
|
|
* @typedef {Object} PDFLinkServiceOptions
|
|
|
|
* @property {EventBus} eventBus - The application event bus.
|
2018-02-13 22:03:52 +09:00
|
|
|
* @property {number} externalLinkTarget - (optional) Specifies the `target`
|
|
|
|
* attribute for external links. Must use one of the values from {LinkTarget}.
|
|
|
|
* Defaults to using no target.
|
|
|
|
* @property {string} externalLinkRel - (optional) Specifies the `rel` attribute
|
|
|
|
* for external links. Defaults to stripping the referrer.
|
2016-04-26 07:57:15 +09:00
|
|
|
*/
|
|
|
|
|
2015-04-28 00:25:32 +09:00
|
|
|
/**
|
|
|
|
* Performs navigation functions inside PDF, such as opening specified page,
|
|
|
|
* or destination.
|
|
|
|
* @implements {IPDFLinkService}
|
|
|
|
*/
|
2017-07-14 23:30:25 +09:00
|
|
|
class PDFLinkService {
|
2015-04-28 00:25:32 +09:00
|
|
|
/**
|
2016-04-26 07:57:15 +09:00
|
|
|
* @param {PDFLinkServiceOptions} options
|
2015-04-28 00:25:32 +09:00
|
|
|
*/
|
2018-02-13 22:03:52 +09:00
|
|
|
constructor({ eventBus, externalLinkTarget = null,
|
|
|
|
externalLinkRel = null, } = {}) {
|
2017-07-14 23:30:25 +09:00
|
|
|
this.eventBus = eventBus || getGlobalEventBus();
|
2018-02-13 22:03:52 +09:00
|
|
|
this.externalLinkTarget = externalLinkTarget;
|
|
|
|
this.externalLinkRel = externalLinkRel;
|
|
|
|
|
2015-04-28 00:25:32 +09:00
|
|
|
this.baseUrl = null;
|
|
|
|
this.pdfDocument = null;
|
|
|
|
this.pdfViewer = null;
|
|
|
|
this.pdfHistory = null;
|
|
|
|
|
|
|
|
this._pagesRefCache = null;
|
|
|
|
}
|
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
setDocument(pdfDocument, baseUrl) {
|
|
|
|
this.baseUrl = baseUrl;
|
|
|
|
this.pdfDocument = pdfDocument;
|
|
|
|
this._pagesRefCache = Object.create(null);
|
|
|
|
}
|
2016-10-23 01:08:25 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
setViewer(pdfViewer) {
|
|
|
|
this.pdfViewer = pdfViewer;
|
|
|
|
}
|
2015-04-28 00:25:32 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
setHistory(pdfHistory) {
|
|
|
|
this.pdfHistory = pdfHistory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
get pagesCount() {
|
|
|
|
return this.pdfDocument ? this.pdfDocument.numPages : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
get page() {
|
|
|
|
return this.pdfViewer.currentPageNumber;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} value
|
|
|
|
*/
|
|
|
|
set page(value) {
|
|
|
|
this.pdfViewer.currentPageNumber = value;
|
|
|
|
}
|
|
|
|
|
2017-08-21 18:56:49 +09:00
|
|
|
/**
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
get rotation() {
|
|
|
|
return this.pdfViewer.pagesRotation;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} value
|
|
|
|
*/
|
|
|
|
set rotation(value) {
|
|
|
|
this.pdfViewer.pagesRotation = value;
|
|
|
|
}
|
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param {string|Array} dest - The named, or explicit, PDF destination.
|
|
|
|
*/
|
|
|
|
navigateTo(dest) {
|
|
|
|
let goToDestination = ({ namedDest, explicitDest, }) => {
|
|
|
|
// Dest array looks like that: <page-ref> </XYZ|/FitXXX> <args..>
|
|
|
|
let destRef = explicitDest[0], pageNumber;
|
|
|
|
|
|
|
|
if (destRef instanceof Object) {
|
|
|
|
pageNumber = this._cachedPageNumber(destRef);
|
|
|
|
|
|
|
|
if (pageNumber === null) {
|
|
|
|
// Fetch the page reference if it's not yet available. This could
|
|
|
|
// only occur during loading, before all pages have been resolved.
|
|
|
|
this.pdfDocument.getPageIndex(destRef).then((pageIndex) => {
|
|
|
|
this.cachePageRef(pageIndex + 1, destRef);
|
|
|
|
goToDestination({ namedDest, explicitDest, });
|
|
|
|
}).catch(() => {
|
|
|
|
console.error(`PDFLinkService.navigateTo: "${destRef}" is not ` +
|
|
|
|
`a valid page reference, for dest="${dest}".`);
|
2017-05-16 20:20:30 +09:00
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2017-09-03 20:08:50 +09:00
|
|
|
} else if (Number.isInteger(destRef)) {
|
2017-07-14 23:30:25 +09:00
|
|
|
pageNumber = destRef + 1;
|
|
|
|
} else {
|
|
|
|
console.error(`PDFLinkService.navigateTo: "${destRef}" is not ` +
|
|
|
|
`a valid destination reference, for dest="${dest}".`);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {
|
|
|
|
console.error(`PDFLinkService.navigateTo: "${pageNumber}" is not ` +
|
|
|
|
`a valid page number, for dest="${dest}".`);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Re-write `PDFHistory` from scratch
This patch completely re-implements `PDFHistory` to get rid of various bugs currently present, and to hopefully make maintenance slightly easier. Most of the interface is similar to the existing one, but it should be somewhat simplified.
The new implementation should be more robust against failure, compared to the old one. Previously, it was too easy to end up in a state which basically caused the browser history to lock-up, preventing the user from navigating back/forward. (In the new implementation, the browser history should not be updated rather than breaking if things go wrong.)
Given that the code has to deal with various edge-cases, it's still not as simple as I would have liked, but it should now be somewhat easier to deal with.
The main source of complication in the code is actually that we allow the user to change the hash of a already loaded document (we'll no longer try to navigate back-and-forth in this case, since the next commit contains a workaround).
In the new code, there's also *a lot* more comments (perhaps too many?) to attempt to explain the logic. This is something that the old implementation was serverly lacking, which is a one of the reasons why it was so difficult to maintain.
One particular thing to note is that the new code uses the `pagehide` event rather than `beforeunload`, since the latter seems to be a bad idea based on https://bugzilla.mozilla.org/show_bug.cgi?id=1336763.
2017-07-16 20:39:39 +09:00
|
|
|
if (this.pdfHistory) {
|
|
|
|
// Update the browser history before scrolling the new destination into
|
|
|
|
// view, to be able to accurately capture the current document position.
|
|
|
|
this.pdfHistory.pushCurrentPosition();
|
|
|
|
this.pdfHistory.push({ namedDest, explicitDest, pageNumber, });
|
|
|
|
}
|
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
this.pdfViewer.scrollPageIntoView({
|
|
|
|
pageNumber,
|
|
|
|
destArray: explicitDest,
|
2015-04-28 00:25:32 +09:00
|
|
|
});
|
2017-07-14 23:30:25 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
new Promise((resolve, reject) => {
|
2015-04-28 00:25:32 +09:00
|
|
|
if (typeof dest === 'string') {
|
2017-07-14 23:30:25 +09:00
|
|
|
this.pdfDocument.getDestination(dest).then((destArray) => {
|
|
|
|
resolve({
|
|
|
|
namedDest: dest,
|
|
|
|
explicitDest: destArray,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return;
|
2015-04-28 00:25:32 +09:00
|
|
|
}
|
2017-07-14 23:30:25 +09:00
|
|
|
resolve({
|
|
|
|
namedDest: '',
|
|
|
|
explicitDest: dest,
|
|
|
|
});
|
|
|
|
}).then((data) => {
|
2018-07-09 20:11:35 +09:00
|
|
|
if (!Array.isArray(data.explicitDest)) {
|
2017-07-14 23:30:25 +09:00
|
|
|
console.error(`PDFLinkService.navigateTo: "${data.explicitDest}" is` +
|
|
|
|
` not a valid destination array, for dest="${dest}".`);
|
|
|
|
return;
|
2015-04-28 00:25:32 +09:00
|
|
|
}
|
2017-07-14 23:30:25 +09:00
|
|
|
goToDestination(data);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {string|Array} dest - The PDF destination object.
|
|
|
|
* @returns {string} The hyperlink to the PDF object.
|
|
|
|
*/
|
|
|
|
getDestinationHash(dest) {
|
|
|
|
if (typeof dest === 'string') {
|
|
|
|
return this.getAnchorUrl('#' + escape(dest));
|
|
|
|
}
|
2018-07-09 20:11:35 +09:00
|
|
|
if (Array.isArray(dest)) {
|
2017-07-14 23:30:25 +09:00
|
|
|
let str = JSON.stringify(dest);
|
|
|
|
return this.getAnchorUrl('#' + escape(str));
|
|
|
|
}
|
|
|
|
return this.getAnchorUrl('');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prefix the full url on anchor links to make sure that links are resolved
|
|
|
|
* relative to the current URL instead of the one defined in <base href>.
|
|
|
|
* @param {String} anchor The anchor hash, including the #.
|
|
|
|
* @returns {string} The hyperlink to the PDF object.
|
|
|
|
*/
|
|
|
|
getAnchorUrl(anchor) {
|
|
|
|
return (this.baseUrl || '') + anchor;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {string} hash
|
|
|
|
*/
|
|
|
|
setHash(hash) {
|
|
|
|
let pageNumber, dest;
|
2018-02-11 01:06:03 +09:00
|
|
|
if (hash.includes('=')) {
|
2017-07-14 23:30:25 +09:00
|
|
|
let params = parseQueryString(hash);
|
|
|
|
if ('search' in params) {
|
|
|
|
this.eventBus.dispatch('findfromurlhash', {
|
|
|
|
source: this,
|
|
|
|
query: params['search'].replace(/"/g, ''),
|
|
|
|
phraseSearch: (params['phrase'] === 'true'),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// borrowing syntax from "Parameters for Opening PDF Files"
|
|
|
|
if ('nameddest' in params) {
|
|
|
|
this.navigateTo(params.nameddest);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ('page' in params) {
|
|
|
|
pageNumber = (params.page | 0) || 1;
|
|
|
|
}
|
|
|
|
if ('zoom' in params) {
|
|
|
|
// Build the destination array.
|
|
|
|
let zoomArgs = params.zoom.split(','); // scale,left,top
|
|
|
|
let zoomArg = zoomArgs[0];
|
|
|
|
let zoomArgNumber = parseFloat(zoomArg);
|
|
|
|
|
2018-02-11 01:06:03 +09:00
|
|
|
if (!zoomArg.includes('Fit')) {
|
2017-07-14 23:30:25 +09:00
|
|
|
// If the zoomArg is a number, it has to get divided by 100. If it's
|
|
|
|
// a string, it should stay as it is.
|
|
|
|
dest = [null, { name: 'XYZ', },
|
|
|
|
zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null,
|
|
|
|
zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null,
|
|
|
|
(zoomArgNumber ? zoomArgNumber / 100 : zoomArg)];
|
|
|
|
} else {
|
|
|
|
if (zoomArg === 'Fit' || zoomArg === 'FitB') {
|
|
|
|
dest = [null, { name: zoomArg, }];
|
|
|
|
} else if ((zoomArg === 'FitH' || zoomArg === 'FitBH') ||
|
|
|
|
(zoomArg === 'FitV' || zoomArg === 'FitBV')) {
|
|
|
|
dest = [null, { name: zoomArg, },
|
|
|
|
zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null];
|
|
|
|
} else if (zoomArg === 'FitR') {
|
|
|
|
if (zoomArgs.length !== 5) {
|
|
|
|
console.error(
|
|
|
|
'PDFLinkService.setHash: Not enough parameters for "FitR".');
|
2015-04-28 00:25:32 +09:00
|
|
|
} else {
|
2017-07-14 23:30:25 +09:00
|
|
|
dest = [null, { name: zoomArg, },
|
|
|
|
(zoomArgs[1] | 0), (zoomArgs[2] | 0),
|
|
|
|
(zoomArgs[3] | 0), (zoomArgs[4] | 0)];
|
2015-04-28 00:25:32 +09:00
|
|
|
}
|
2017-07-14 23:30:25 +09:00
|
|
|
} else {
|
|
|
|
console.error(`PDFLinkService.setHash: "${zoomArg}" is not ` +
|
|
|
|
'a valid zoom value.');
|
2015-04-28 00:25:32 +09:00
|
|
|
}
|
|
|
|
}
|
2017-07-14 23:30:25 +09:00
|
|
|
}
|
|
|
|
if (dest) {
|
|
|
|
this.pdfViewer.scrollPageIntoView({
|
|
|
|
pageNumber: pageNumber || this.page,
|
|
|
|
destArray: dest,
|
|
|
|
allowNegativeOffset: true,
|
|
|
|
});
|
|
|
|
} else if (pageNumber) {
|
|
|
|
this.page = pageNumber; // simple page
|
|
|
|
}
|
|
|
|
if ('pagemode' in params) {
|
|
|
|
this.eventBus.dispatch('pagemode', {
|
|
|
|
source: this,
|
|
|
|
mode: params.pagemode,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else { // Named (or explicit) destination.
|
|
|
|
dest = unescape(hash);
|
|
|
|
try {
|
|
|
|
dest = JSON.parse(dest);
|
2016-10-23 05:57:27 +09:00
|
|
|
|
2018-07-09 20:11:35 +09:00
|
|
|
if (!Array.isArray(dest)) {
|
2017-07-14 23:30:25 +09:00
|
|
|
// Avoid incorrectly rejecting a valid named destination, such as
|
|
|
|
// e.g. "4.3" or "true", because `JSON.parse` converted its type.
|
|
|
|
dest = dest.toString();
|
|
|
|
}
|
|
|
|
} catch (ex) {}
|
[api-minor] Let `LinkAnnotation`/`PDFLinkService_getDestinationHash` return a stringified version of the destination array for explicit destinations
Currently for explicit destinations, compared to named destinations, we manually try to build a hash that often times is a quite poor representation of the *actual* destination. (Currently this only, kind of, works for `\XYZ` destinations.)
For PDF files using explicit destinations, this can make it difficult/impossible to obtain a link to a specific section of the document through the URL.
Note that in practice most PDF files, especially newer ones, use named destinations and these are thus unnaffected by this patch.
This patch also fixes an existing issue in `PDFLinkService_getDestinationHash`, where a named destination consisting of only a number would not be handled correctly.
With the added, and already existing, type checks in place for destinations, I really don't think that this patch exposes any "sensitive" internal destination code not already accessible through normal hash parameters.
*Please note:* Just trying to improve the algorithm that generates the hash is unfortunately not possible in general, since there are a number of cases where it will simply never work well.
- First of all, note that `getDestinationHash` currently relies on the `_pagesRefCache`, hence it's possible that the hash returned is empty during e.g. ranged/streamed loading of a PDF file.
- Second of all, the currently computed hash is actually dependent on the document rotation. With named destinations, the fetched internal destination array is rotational invariant (as it should be), but this will not hold in general for the hash. We can easily avoid this issue by using a stringified destination array.
- Third of all, note that according to the PDF specification[1], `GoToR` destinations may actually contain explicit destination arrays. Since we cannot really construct a hash in `annotation.js`, we currently have no good way to support those. Even though this case seems *very* rare in practice (I've not actually seen such a PDF file), it's in the specification, and this patch allows us to support that for "free".
---
[1] http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G11.1951685
2016-05-15 19:12:47 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
if (typeof dest === 'string' || isValidExplicitDestination(dest)) {
|
|
|
|
this.navigateTo(dest);
|
|
|
|
return;
|
2015-04-28 00:25:32 +09:00
|
|
|
}
|
2017-07-14 23:30:25 +09:00
|
|
|
console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not ` +
|
|
|
|
'a valid destination.');
|
|
|
|
}
|
|
|
|
}
|
2015-04-28 00:25:32 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param {string} action
|
|
|
|
*/
|
|
|
|
executeNamedAction(action) {
|
|
|
|
// See PDF reference, table 8.45 - Named action
|
|
|
|
switch (action) {
|
|
|
|
case 'GoBack':
|
|
|
|
if (this.pdfHistory) {
|
|
|
|
this.pdfHistory.back();
|
|
|
|
}
|
|
|
|
break;
|
2015-04-28 00:25:32 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
case 'GoForward':
|
|
|
|
if (this.pdfHistory) {
|
|
|
|
this.pdfHistory.forward();
|
[api-minor] Let `LinkAnnotation`/`PDFLinkService_getDestinationHash` return a stringified version of the destination array for explicit destinations
Currently for explicit destinations, compared to named destinations, we manually try to build a hash that often times is a quite poor representation of the *actual* destination. (Currently this only, kind of, works for `\XYZ` destinations.)
For PDF files using explicit destinations, this can make it difficult/impossible to obtain a link to a specific section of the document through the URL.
Note that in practice most PDF files, especially newer ones, use named destinations and these are thus unnaffected by this patch.
This patch also fixes an existing issue in `PDFLinkService_getDestinationHash`, where a named destination consisting of only a number would not be handled correctly.
With the added, and already existing, type checks in place for destinations, I really don't think that this patch exposes any "sensitive" internal destination code not already accessible through normal hash parameters.
*Please note:* Just trying to improve the algorithm that generates the hash is unfortunately not possible in general, since there are a number of cases where it will simply never work well.
- First of all, note that `getDestinationHash` currently relies on the `_pagesRefCache`, hence it's possible that the hash returned is empty during e.g. ranged/streamed loading of a PDF file.
- Second of all, the currently computed hash is actually dependent on the document rotation. With named destinations, the fetched internal destination array is rotational invariant (as it should be), but this will not hold in general for the hash. We can easily avoid this issue by using a stringified destination array.
- Third of all, note that according to the PDF specification[1], `GoToR` destinations may actually contain explicit destination arrays. Since we cannot really construct a hash in `annotation.js`, we currently have no good way to support those. Even though this case seems *very* rare in practice (I've not actually seen such a PDF file), it's in the specification, and this patch allows us to support that for "free".
---
[1] http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G11.1951685
2016-05-15 19:12:47 +09:00
|
|
|
}
|
|
|
|
break;
|
2017-07-14 23:30:25 +09:00
|
|
|
|
|
|
|
case 'NextPage':
|
|
|
|
if (this.page < this.pagesCount) {
|
|
|
|
this.page++;
|
[api-minor] Let `LinkAnnotation`/`PDFLinkService_getDestinationHash` return a stringified version of the destination array for explicit destinations
Currently for explicit destinations, compared to named destinations, we manually try to build a hash that often times is a quite poor representation of the *actual* destination. (Currently this only, kind of, works for `\XYZ` destinations.)
For PDF files using explicit destinations, this can make it difficult/impossible to obtain a link to a specific section of the document through the URL.
Note that in practice most PDF files, especially newer ones, use named destinations and these are thus unnaffected by this patch.
This patch also fixes an existing issue in `PDFLinkService_getDestinationHash`, where a named destination consisting of only a number would not be handled correctly.
With the added, and already existing, type checks in place for destinations, I really don't think that this patch exposes any "sensitive" internal destination code not already accessible through normal hash parameters.
*Please note:* Just trying to improve the algorithm that generates the hash is unfortunately not possible in general, since there are a number of cases where it will simply never work well.
- First of all, note that `getDestinationHash` currently relies on the `_pagesRefCache`, hence it's possible that the hash returned is empty during e.g. ranged/streamed loading of a PDF file.
- Second of all, the currently computed hash is actually dependent on the document rotation. With named destinations, the fetched internal destination array is rotational invariant (as it should be), but this will not hold in general for the hash. We can easily avoid this issue by using a stringified destination array.
- Third of all, note that according to the PDF specification[1], `GoToR` destinations may actually contain explicit destination arrays. Since we cannot really construct a hash in `annotation.js`, we currently have no good way to support those. Even though this case seems *very* rare in practice (I've not actually seen such a PDF file), it's in the specification, and this patch allows us to support that for "free".
---
[1] http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G11.1951685
2016-05-15 19:12:47 +09:00
|
|
|
}
|
|
|
|
break;
|
2017-07-14 23:30:25 +09:00
|
|
|
|
|
|
|
case 'PrevPage':
|
|
|
|
if (this.page > 1) {
|
|
|
|
this.page--;
|
[api-minor] Let `LinkAnnotation`/`PDFLinkService_getDestinationHash` return a stringified version of the destination array for explicit destinations
Currently for explicit destinations, compared to named destinations, we manually try to build a hash that often times is a quite poor representation of the *actual* destination. (Currently this only, kind of, works for `\XYZ` destinations.)
For PDF files using explicit destinations, this can make it difficult/impossible to obtain a link to a specific section of the document through the URL.
Note that in practice most PDF files, especially newer ones, use named destinations and these are thus unnaffected by this patch.
This patch also fixes an existing issue in `PDFLinkService_getDestinationHash`, where a named destination consisting of only a number would not be handled correctly.
With the added, and already existing, type checks in place for destinations, I really don't think that this patch exposes any "sensitive" internal destination code not already accessible through normal hash parameters.
*Please note:* Just trying to improve the algorithm that generates the hash is unfortunately not possible in general, since there are a number of cases where it will simply never work well.
- First of all, note that `getDestinationHash` currently relies on the `_pagesRefCache`, hence it's possible that the hash returned is empty during e.g. ranged/streamed loading of a PDF file.
- Second of all, the currently computed hash is actually dependent on the document rotation. With named destinations, the fetched internal destination array is rotational invariant (as it should be), but this will not hold in general for the hash. We can easily avoid this issue by using a stringified destination array.
- Third of all, note that according to the PDF specification[1], `GoToR` destinations may actually contain explicit destination arrays. Since we cannot really construct a hash in `annotation.js`, we currently have no good way to support those. Even though this case seems *very* rare in practice (I've not actually seen such a PDF file), it's in the specification, and this patch allows us to support that for "free".
---
[1] http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G11.1951685
2016-05-15 19:12:47 +09:00
|
|
|
}
|
|
|
|
break;
|
2017-07-14 23:30:25 +09:00
|
|
|
|
|
|
|
case 'LastPage':
|
|
|
|
this.page = this.pagesCount;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'FirstPage':
|
|
|
|
this.page = 1;
|
|
|
|
break;
|
|
|
|
|
[api-minor] Let `LinkAnnotation`/`PDFLinkService_getDestinationHash` return a stringified version of the destination array for explicit destinations
Currently for explicit destinations, compared to named destinations, we manually try to build a hash that often times is a quite poor representation of the *actual* destination. (Currently this only, kind of, works for `\XYZ` destinations.)
For PDF files using explicit destinations, this can make it difficult/impossible to obtain a link to a specific section of the document through the URL.
Note that in practice most PDF files, especially newer ones, use named destinations and these are thus unnaffected by this patch.
This patch also fixes an existing issue in `PDFLinkService_getDestinationHash`, where a named destination consisting of only a number would not be handled correctly.
With the added, and already existing, type checks in place for destinations, I really don't think that this patch exposes any "sensitive" internal destination code not already accessible through normal hash parameters.
*Please note:* Just trying to improve the algorithm that generates the hash is unfortunately not possible in general, since there are a number of cases where it will simply never work well.
- First of all, note that `getDestinationHash` currently relies on the `_pagesRefCache`, hence it's possible that the hash returned is empty during e.g. ranged/streamed loading of a PDF file.
- Second of all, the currently computed hash is actually dependent on the document rotation. With named destinations, the fetched internal destination array is rotational invariant (as it should be), but this will not hold in general for the hash. We can easily avoid this issue by using a stringified destination array.
- Third of all, note that according to the PDF specification[1], `GoToR` destinations may actually contain explicit destination arrays. Since we cannot really construct a hash in `annotation.js`, we currently have no good way to support those. Even though this case seems *very* rare in practice (I've not actually seen such a PDF file), it's in the specification, and this patch allows us to support that for "free".
---
[1] http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G11.1951685
2016-05-15 19:12:47 +09:00
|
|
|
default:
|
2017-07-14 23:30:25 +09:00
|
|
|
break; // No action according to spec
|
[api-minor] Let `LinkAnnotation`/`PDFLinkService_getDestinationHash` return a stringified version of the destination array for explicit destinations
Currently for explicit destinations, compared to named destinations, we manually try to build a hash that often times is a quite poor representation of the *actual* destination. (Currently this only, kind of, works for `\XYZ` destinations.)
For PDF files using explicit destinations, this can make it difficult/impossible to obtain a link to a specific section of the document through the URL.
Note that in practice most PDF files, especially newer ones, use named destinations and these are thus unnaffected by this patch.
This patch also fixes an existing issue in `PDFLinkService_getDestinationHash`, where a named destination consisting of only a number would not be handled correctly.
With the added, and already existing, type checks in place for destinations, I really don't think that this patch exposes any "sensitive" internal destination code not already accessible through normal hash parameters.
*Please note:* Just trying to improve the algorithm that generates the hash is unfortunately not possible in general, since there are a number of cases where it will simply never work well.
- First of all, note that `getDestinationHash` currently relies on the `_pagesRefCache`, hence it's possible that the hash returned is empty during e.g. ranged/streamed loading of a PDF file.
- Second of all, the currently computed hash is actually dependent on the document rotation. With named destinations, the fetched internal destination array is rotational invariant (as it should be), but this will not hold in general for the hash. We can easily avoid this issue by using a stringified destination array.
- Third of all, note that according to the PDF specification[1], `GoToR` destinations may actually contain explicit destination arrays. Since we cannot really construct a hash in `annotation.js`, we currently have no good way to support those. Even though this case seems *very* rare in practice (I've not actually seen such a PDF file), it's in the specification, and this patch allows us to support that for "free".
---
[1] http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G11.1951685
2016-05-15 19:12:47 +09:00
|
|
|
}
|
2017-07-14 23:30:25 +09:00
|
|
|
|
|
|
|
this.eventBus.dispatch('namedaction', {
|
|
|
|
source: this,
|
|
|
|
action,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {Object} params
|
|
|
|
*/
|
|
|
|
onFileAttachmentAnnotation({ id, filename, content, }) {
|
|
|
|
this.eventBus.dispatch('fileattachmentannotation', {
|
|
|
|
source: this,
|
|
|
|
id,
|
|
|
|
filename,
|
|
|
|
content,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} pageNum - page number.
|
|
|
|
* @param {Object} pageRef - reference to the page.
|
|
|
|
*/
|
|
|
|
cachePageRef(pageNum, pageRef) {
|
2018-03-12 22:00:37 +09:00
|
|
|
if (!pageRef) {
|
|
|
|
return;
|
|
|
|
}
|
2017-07-14 23:30:25 +09:00
|
|
|
let refStr = pageRef.num + ' ' + pageRef.gen + ' R';
|
|
|
|
this._pagesRefCache[refStr] = pageNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
_cachedPageNumber(pageRef) {
|
|
|
|
let refStr = pageRef.num + ' ' + pageRef.gen + ' R';
|
|
|
|
return (this._pagesRefCache && this._pagesRefCache[refStr]) || null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function isValidExplicitDestination(dest) {
|
2018-07-09 20:11:35 +09:00
|
|
|
if (!Array.isArray(dest)) {
|
2017-07-14 23:30:25 +09:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
let destLength = dest.length, allowNull = true;
|
|
|
|
if (destLength < 2) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
let page = dest[0];
|
|
|
|
if (!(typeof page === 'object' &&
|
2017-09-03 20:08:50 +09:00
|
|
|
Number.isInteger(page.num) && Number.isInteger(page.gen)) &&
|
|
|
|
!(Number.isInteger(page) && page >= 0)) {
|
2017-07-14 23:30:25 +09:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
let zoom = dest[1];
|
|
|
|
if (!(typeof zoom === 'object' && typeof zoom.name === 'string')) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
switch (zoom.name) {
|
|
|
|
case 'XYZ':
|
|
|
|
if (destLength !== 5) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'Fit':
|
|
|
|
case 'FitB':
|
|
|
|
return destLength === 2;
|
|
|
|
case 'FitH':
|
|
|
|
case 'FitBH':
|
|
|
|
case 'FitV':
|
|
|
|
case 'FitBV':
|
|
|
|
if (destLength !== 3) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'FitR':
|
|
|
|
if (destLength !== 6) {
|
[api-minor] Let `LinkAnnotation`/`PDFLinkService_getDestinationHash` return a stringified version of the destination array for explicit destinations
Currently for explicit destinations, compared to named destinations, we manually try to build a hash that often times is a quite poor representation of the *actual* destination. (Currently this only, kind of, works for `\XYZ` destinations.)
For PDF files using explicit destinations, this can make it difficult/impossible to obtain a link to a specific section of the document through the URL.
Note that in practice most PDF files, especially newer ones, use named destinations and these are thus unnaffected by this patch.
This patch also fixes an existing issue in `PDFLinkService_getDestinationHash`, where a named destination consisting of only a number would not be handled correctly.
With the added, and already existing, type checks in place for destinations, I really don't think that this patch exposes any "sensitive" internal destination code not already accessible through normal hash parameters.
*Please note:* Just trying to improve the algorithm that generates the hash is unfortunately not possible in general, since there are a number of cases where it will simply never work well.
- First of all, note that `getDestinationHash` currently relies on the `_pagesRefCache`, hence it's possible that the hash returned is empty during e.g. ranged/streamed loading of a PDF file.
- Second of all, the currently computed hash is actually dependent on the document rotation. With named destinations, the fetched internal destination array is rotational invariant (as it should be), but this will not hold in general for the hash. We can easily avoid this issue by using a stringified destination array.
- Third of all, note that according to the PDF specification[1], `GoToR` destinations may actually contain explicit destination arrays. Since we cannot really construct a hash in `annotation.js`, we currently have no good way to support those. Even though this case seems *very* rare in practice (I've not actually seen such a PDF file), it's in the specification, and this patch allows us to support that for "free".
---
[1] http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G11.1951685
2016-05-15 19:12:47 +09:00
|
|
|
return false;
|
|
|
|
}
|
2017-07-14 23:30:25 +09:00
|
|
|
allowNull = false;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (let i = 2; i < destLength; i++) {
|
|
|
|
let param = dest[i];
|
|
|
|
if (!(typeof param === 'number' || (allowNull && param === null))) {
|
|
|
|
return false;
|
[api-minor] Let `LinkAnnotation`/`PDFLinkService_getDestinationHash` return a stringified version of the destination array for explicit destinations
Currently for explicit destinations, compared to named destinations, we manually try to build a hash that often times is a quite poor representation of the *actual* destination. (Currently this only, kind of, works for `\XYZ` destinations.)
For PDF files using explicit destinations, this can make it difficult/impossible to obtain a link to a specific section of the document through the URL.
Note that in practice most PDF files, especially newer ones, use named destinations and these are thus unnaffected by this patch.
This patch also fixes an existing issue in `PDFLinkService_getDestinationHash`, where a named destination consisting of only a number would not be handled correctly.
With the added, and already existing, type checks in place for destinations, I really don't think that this patch exposes any "sensitive" internal destination code not already accessible through normal hash parameters.
*Please note:* Just trying to improve the algorithm that generates the hash is unfortunately not possible in general, since there are a number of cases where it will simply never work well.
- First of all, note that `getDestinationHash` currently relies on the `_pagesRefCache`, hence it's possible that the hash returned is empty during e.g. ranged/streamed loading of a PDF file.
- Second of all, the currently computed hash is actually dependent on the document rotation. With named destinations, the fetched internal destination array is rotational invariant (as it should be), but this will not hold in general for the hash. We can easily avoid this issue by using a stringified destination array.
- Third of all, note that according to the PDF specification[1], `GoToR` destinations may actually contain explicit destination arrays. Since we cannot really construct a hash in `annotation.js`, we currently have no good way to support those. Even though this case seems *very* rare in practice (I've not actually seen such a PDF file), it's in the specification, and this patch allows us to support that for "free".
---
[1] http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G11.1951685
2016-05-15 19:12:47 +09:00
|
|
|
}
|
|
|
|
}
|
2017-07-14 23:30:25 +09:00
|
|
|
return true;
|
|
|
|
}
|
[api-minor] Let `LinkAnnotation`/`PDFLinkService_getDestinationHash` return a stringified version of the destination array for explicit destinations
Currently for explicit destinations, compared to named destinations, we manually try to build a hash that often times is a quite poor representation of the *actual* destination. (Currently this only, kind of, works for `\XYZ` destinations.)
For PDF files using explicit destinations, this can make it difficult/impossible to obtain a link to a specific section of the document through the URL.
Note that in practice most PDF files, especially newer ones, use named destinations and these are thus unnaffected by this patch.
This patch also fixes an existing issue in `PDFLinkService_getDestinationHash`, where a named destination consisting of only a number would not be handled correctly.
With the added, and already existing, type checks in place for destinations, I really don't think that this patch exposes any "sensitive" internal destination code not already accessible through normal hash parameters.
*Please note:* Just trying to improve the algorithm that generates the hash is unfortunately not possible in general, since there are a number of cases where it will simply never work well.
- First of all, note that `getDestinationHash` currently relies on the `_pagesRefCache`, hence it's possible that the hash returned is empty during e.g. ranged/streamed loading of a PDF file.
- Second of all, the currently computed hash is actually dependent on the document rotation. With named destinations, the fetched internal destination array is rotational invariant (as it should be), but this will not hold in general for the hash. We can easily avoid this issue by using a stringified destination array.
- Third of all, note that according to the PDF specification[1], `GoToR` destinations may actually contain explicit destination arrays. Since we cannot really construct a hash in `annotation.js`, we currently have no good way to support those. Even though this case seems *very* rare in practice (I've not actually seen such a PDF file), it's in the specification, and this patch allows us to support that for "free".
---
[1] http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G11.1951685
2016-05-15 19:12:47 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
class SimpleLinkService {
|
2018-02-13 22:03:52 +09:00
|
|
|
constructor() {
|
|
|
|
this.externalLinkTarget = null;
|
|
|
|
this.externalLinkRel = null;
|
|
|
|
}
|
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
get page() {
|
|
|
|
return 0;
|
|
|
|
}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param {number} value
|
|
|
|
*/
|
|
|
|
set page(value) {}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-08-21 18:56:49 +09:00
|
|
|
/**
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
get rotation() {
|
|
|
|
return 0;
|
|
|
|
}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-08-21 18:56:49 +09:00
|
|
|
/**
|
|
|
|
* @param {number} value
|
|
|
|
*/
|
|
|
|
set rotation(value) {}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param dest - The PDF destination object.
|
|
|
|
*/
|
|
|
|
navigateTo(dest) {}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param dest - The PDF destination object.
|
|
|
|
* @returns {string} The hyperlink to the PDF object.
|
|
|
|
*/
|
|
|
|
getDestinationHash(dest) {
|
|
|
|
return '#';
|
|
|
|
}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param hash - The PDF parameters/hash.
|
|
|
|
* @returns {string} The hyperlink to the PDF object.
|
|
|
|
*/
|
|
|
|
getAnchorUrl(hash) {
|
|
|
|
return '#';
|
|
|
|
}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param {string} hash
|
|
|
|
*/
|
|
|
|
setHash(hash) {}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param {string} action
|
|
|
|
*/
|
|
|
|
executeNamedAction(action) {}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param {Object} params
|
|
|
|
*/
|
|
|
|
onFileAttachmentAnnotation({ id, filename, content, }) {}
|
2017-10-29 19:41:13 +09:00
|
|
|
|
2017-07-14 23:30:25 +09:00
|
|
|
/**
|
|
|
|
* @param {number} pageNum - page number.
|
|
|
|
* @param {Object} pageRef - reference to the page.
|
|
|
|
*/
|
|
|
|
cachePageRef(pageNum, pageRef) {}
|
|
|
|
}
|
2016-04-09 02:34:27 +09:00
|
|
|
|
2017-03-28 08:07:27 +09:00
|
|
|
export {
|
|
|
|
PDFLinkService,
|
|
|
|
SimpleLinkService,
|
|
|
|
};
|