Browse Source

[api-minor] Add support for relative URLs, in both annotations and the outline, by adding a `docBaseUrl` parameter to `PDFJS.getDocument` (bug 766086)

Note that in `FIREFOX/MOZCENTRAL/CHROME` builds of the standard viewer the `docBaseUrl` parameter will be set by default, since in that case it makes sense to use the current URL as a base.
For the `GENERIC` viewer, or the API itself, it doesn't make sense to try and set the `docBaseUrl` by default. However, custom deployments/implementations may still find the parameter useful.
Jonas Jenwald 9 years ago
parent
commit
d284cfd5eb
  1. 5
      src/core/annotation.js
  2. 1
      src/core/document.js
  3. 6
      src/core/obj.js
  4. 24
      src/core/pdf_manager.js
  5. 7
      src/core/worker.js
  6. 4
      src/display/api.js
  7. 1
      test/pdfs/.gitignore
  8. 85
      test/pdfs/bug766086.pdf
  9. 128
      test/unit/annotation_layer_spec.js
  10. 62
      test/unit/api_spec.js
  11. 28
      web/app.js

5
src/core/annotation.js

@ -64,11 +64,12 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
/** /**
* @param {XRef} xref * @param {XRef} xref
* @param {Object} ref * @param {Object} ref
* @param {PDFManager} pdfManager
* @param {string} uniquePrefix * @param {string} uniquePrefix
* @param {Object} idCounters * @param {Object} idCounters
* @returns {Annotation} * @returns {Annotation}
*/ */
create: function AnnotationFactory_create(xref, ref, create: function AnnotationFactory_create(xref, ref, pdfManager,
uniquePrefix, idCounters) { uniquePrefix, idCounters) {
var dict = xref.fetchIfRef(ref); var dict = xref.fetchIfRef(ref);
if (!isDict(dict)) { if (!isDict(dict)) {
@ -88,6 +89,7 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
ref: isRef(ref) ? ref : null, ref: isRef(ref) ? ref : null,
subtype: subtype, subtype: subtype,
id: id, id: id,
pdfManager: pdfManager,
}; };
switch (subtype) { switch (subtype) {
@ -846,6 +848,7 @@ var LinkAnnotation = (function LinkAnnotationClosure() {
Catalog.parseDestDictionary({ Catalog.parseDestDictionary({
destDict: params.dict, destDict: params.dict,
resultObj: data, resultObj: data,
docBaseUrl: params.pdfManager.docBaseUrl,
}); });
} }

1
src/core/document.js

@ -329,6 +329,7 @@ var Page = (function PageClosure() {
for (var i = 0, n = annotationRefs.length; i < n; ++i) { for (var i = 0, n = annotationRefs.length; i < n; ++i) {
var annotationRef = annotationRefs[i]; var annotationRef = annotationRefs[i];
var annotation = annotationFactory.create(this.xref, annotationRef, var annotation = annotationFactory.create(this.xref, annotationRef,
this.pdfManager,
this.uniquePrefix, this.uniquePrefix,
this.idCounters); this.idCounters);
if (annotation) { if (annotation) {

6
src/core/obj.js

@ -157,6 +157,7 @@ var Catalog = (function CatalogClosure() {
Catalog.parseDestDictionary({ Catalog.parseDestDictionary({
destDict: outlineDict, destDict: outlineDict,
resultObj: data, resultObj: data,
docBaseUrl: this.pdfManager.docBaseUrl,
}); });
var title = outlineDict.get('Title'); var title = outlineDict.get('Title');
var flags = outlineDict.get('F') || 0; var flags = outlineDict.get('F') || 0;
@ -590,6 +591,8 @@ var Catalog = (function CatalogClosure() {
* @param {Dict} destDict - The dictionary containing the destination. * @param {Dict} destDict - The dictionary containing the destination.
* @param {Object} resultObj - The object where the parsed destination * @param {Object} resultObj - The object where the parsed destination
* properties will be placed. * properties will be placed.
* @param {string} docBaseUrl - (optional) The document base URL that is used
* when attempting to recover valid absolute URLs from relative ones.
*/ */
Catalog.parseDestDictionary = function Catalog_parseDestDictionary(params) { Catalog.parseDestDictionary = function Catalog_parseDestDictionary(params) {
// Lets URLs beginning with 'www.' default to using the 'http://' protocol. // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
@ -619,6 +622,7 @@ var Catalog = (function CatalogClosure() {
warn('Catalog_parseDestDictionary: "resultObj" must be an object.'); warn('Catalog_parseDestDictionary: "resultObj" must be an object.');
return; return;
} }
var docBaseUrl = params.docBaseUrl || null;
var action = destDict.get('A'), url, dest; var action = destDict.get('A'), url, dest;
if (isDict(action)) { if (isDict(action)) {
@ -694,7 +698,7 @@ var Catalog = (function CatalogClosure() {
if (isString(url)) { if (isString(url)) {
url = tryConvertUrlEncoding(url); url = tryConvertUrlEncoding(url);
var absoluteUrl = createValidAbsoluteUrl(url); var absoluteUrl = createValidAbsoluteUrl(url, docBaseUrl);
if (absoluteUrl) { if (absoluteUrl) {
resultObj.url = absoluteUrl.href; resultObj.url = absoluteUrl.href;
} }

24
src/core/pdf_manager.js

@ -31,6 +31,9 @@
}(this, function (exports, sharedUtil, coreStream, coreChunkedStream, }(this, function (exports, sharedUtil, coreStream, coreChunkedStream,
coreDocument) { coreDocument) {
var warn = sharedUtil.warn;
var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl;
var shadow = sharedUtil.shadow;
var NotImplementedException = sharedUtil.NotImplementedException; var NotImplementedException = sharedUtil.NotImplementedException;
var MissingDataException = sharedUtil.MissingDataException; var MissingDataException = sharedUtil.MissingDataException;
var createPromiseCapability = sharedUtil.createPromiseCapability; var createPromiseCapability = sharedUtil.createPromiseCapability;
@ -49,6 +52,19 @@ var BasePdfManager = (function BasePdfManagerClosure() {
return this._docId; return this._docId;
}, },
get docBaseUrl() {
var docBaseUrl = null;
if (this._docBaseUrl) {
var absoluteUrl = createValidAbsoluteUrl(this._docBaseUrl);
if (absoluteUrl) {
docBaseUrl = absoluteUrl.href;
} else {
warn('Invalid absolute docBaseUrl: "' + this._docBaseUrl + '".');
}
}
return shadow(this, 'docBaseUrl', docBaseUrl);
},
onLoadedStream: function BasePdfManager_onLoadedStream() { onLoadedStream: function BasePdfManager_onLoadedStream() {
throw new NotImplementedException(); throw new NotImplementedException();
}, },
@ -110,8 +126,10 @@ var BasePdfManager = (function BasePdfManagerClosure() {
})(); })();
var LocalPdfManager = (function LocalPdfManagerClosure() { var LocalPdfManager = (function LocalPdfManagerClosure() {
function LocalPdfManager(docId, data, password, evaluatorOptions) { function LocalPdfManager(docId, data, password, evaluatorOptions,
docBaseUrl) {
this._docId = docId; this._docId = docId;
this._docBaseUrl = docBaseUrl;
this.evaluatorOptions = evaluatorOptions; this.evaluatorOptions = evaluatorOptions;
var stream = new Stream(data); var stream = new Stream(data);
this.pdfDocument = new PDFDocument(this, stream, password); this.pdfDocument = new PDFDocument(this, stream, password);
@ -158,8 +176,10 @@ var LocalPdfManager = (function LocalPdfManagerClosure() {
})(); })();
var NetworkPdfManager = (function NetworkPdfManagerClosure() { var NetworkPdfManager = (function NetworkPdfManagerClosure() {
function NetworkPdfManager(docId, pdfNetworkStream, args, evaluatorOptions) { function NetworkPdfManager(docId, pdfNetworkStream, args, evaluatorOptions,
docBaseUrl) {
this._docId = docId; this._docId = docId;
this._docBaseUrl = docBaseUrl;
this.msgHandler = args.msgHandler; this.msgHandler = args.msgHandler;
this.evaluatorOptions = evaluatorOptions; this.evaluatorOptions = evaluatorOptions;

7
src/core/worker.js

@ -480,6 +480,7 @@ var WorkerMessageHandler = {
var WorkerTasks = []; var WorkerTasks = [];
var docId = docParams.docId; var docId = docParams.docId;
var docBaseUrl = docParams.docBaseUrl;
var workerHandlerName = docParams.docId + '_worker'; var workerHandlerName = docParams.docId + '_worker';
var handler = new MessageHandler(workerHandlerName, docId, port); var handler = new MessageHandler(workerHandlerName, docId, port);
@ -544,7 +545,7 @@ var WorkerMessageHandler = {
if (source.data) { if (source.data) {
try { try {
pdfManager = new LocalPdfManager(docId, source.data, source.password, pdfManager = new LocalPdfManager(docId, source.data, source.password,
evaluatorOptions); evaluatorOptions, docBaseUrl);
pdfManagerCapability.resolve(pdfManager); pdfManagerCapability.resolve(pdfManager);
} catch (ex) { } catch (ex) {
pdfManagerCapability.reject(ex); pdfManagerCapability.reject(ex);
@ -593,7 +594,7 @@ var WorkerMessageHandler = {
length: fullRequest.contentLength, length: fullRequest.contentLength,
disableAutoFetch: disableAutoFetch, disableAutoFetch: disableAutoFetch,
rangeChunkSize: source.rangeChunkSize rangeChunkSize: source.rangeChunkSize
}, evaluatorOptions); }, evaluatorOptions, docBaseUrl);
pdfManagerCapability.resolve(pdfManager); pdfManagerCapability.resolve(pdfManager);
cancelXHRs = null; cancelXHRs = null;
}).catch(function (reason) { }).catch(function (reason) {
@ -610,7 +611,7 @@ var WorkerMessageHandler = {
// the data is array, instantiating directly from it // the data is array, instantiating directly from it
try { try {
pdfManager = new LocalPdfManager(docId, pdfFile, source.password, pdfManager = new LocalPdfManager(docId, pdfFile, source.password,
evaluatorOptions); evaluatorOptions, docBaseUrl);
pdfManagerCapability.resolve(pdfManager); pdfManagerCapability.resolve(pdfManager);
} catch (ex) { } catch (ex) {
pdfManagerCapability.reject(ex); pdfManagerCapability.reject(ex);

4
src/display/api.js

@ -129,6 +129,9 @@ if (typeof PDFJSDev !== 'undefined' &&
* 2^16 = 65536. * 2^16 = 65536.
* @property {PDFWorker} worker - The worker that will be used for the loading * @property {PDFWorker} worker - The worker that will be used for the loading
* and parsing of the PDF data. * and parsing of the PDF data.
* @property {string} docBaseUrl - (optional) The base URL of the document,
* used when attempting to recover valid absolute URLs for annotations, and
* outline items, that (incorrectly) only specify relative URLs.
*/ */
/** /**
@ -301,6 +304,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
disableCreateObjectURL: getDefaultSetting('disableCreateObjectURL'), disableCreateObjectURL: getDefaultSetting('disableCreateObjectURL'),
postMessageTransfers: getDefaultSetting('postMessageTransfers') && postMessageTransfers: getDefaultSetting('postMessageTransfers') &&
!isPostMessageTransfersDisabled, !isPostMessageTransfersDisabled,
docBaseUrl: source.docBaseUrl,
}).then(function (workerId) { }).then(function (workerId) {
if (worker.destroyed) { if (worker.destroyed) {
throw new Error('Worker was destroyed'); throw new Error('Worker was destroyed');

1
test/pdfs/.gitignore vendored

@ -46,6 +46,7 @@
!arial_unicode_ab_cidfont.pdf !arial_unicode_ab_cidfont.pdf
!arial_unicode_en_cidfont.pdf !arial_unicode_en_cidfont.pdf
!asciihexdecode.pdf !asciihexdecode.pdf
!bug766086.pdf
!bug793632.pdf !bug793632.pdf
!bug1020858.pdf !bug1020858.pdf
!bug1050040.pdf !bug1050040.pdf

85
test/pdfs/bug766086.pdf

@ -0,0 +1,85 @@
%PDF-1.7
%âãÏÓ
1 0 obj
<<
/Pages 2 0 R
/Type /Catalog
>>
endobj
2 0 obj
<<
/Kids [3 0 R]
/Count 1
/Type /Pages
>>
endobj
3 0 obj
<<
/Parent 2 0 R
/Annots [4 0 R]
/MediaBox [0 0 200 50]
/Resources
<<
/Font
<<
/F1 5 0 R
>>
>>
/Contents 6 0 R
/Type /Page
>>
endobj
4 0 obj
<<
/Border [0 0 1]
/Subtype /Link
/C [1 0 0]
/A
<<
/F (../../0021/002156/215675E.pdf)
/D (15)
/Type /Action
/S /GoToR
>>
/Type /Annot
/Rect [5 10 190 40]
>>
endobj
5 0 obj
<<
/BaseFont /Times-Roman
/Subtype /Type1
/Encoding /WinAnsiEncoding
/Type /Font
>>
endobj
6 0 obj
<<
/Length 58
>>
stream
BT
10 20 TD
/F1 16 Tf
(Bug 766086 - relative links) Tj
ET
endstream
endobj xref
0 7
0000000000 65535 f
0000000015 00000 n
0000000066 00000 n
0000000125 00000 n
0000000270 00000 n
0000000445 00000 n
0000000546 00000 n
trailer
<<
/Root 1 0 R
/Size 7
>>
startxref
656
%%EOF

128
test/unit/annotation_layer_spec.js

@ -27,15 +27,24 @@ describe('Annotation layer', function() {
}, },
}; };
var annotationFactory; function PDFManagerMock(params) {
this.docBaseUrl = params.docBaseUrl || null;
}
PDFManagerMock.prototype = {};
var annotationFactory, pdfManagerMock;
beforeAll(function (done) { beforeAll(function (done) {
annotationFactory = new AnnotationFactory(); annotationFactory = new AnnotationFactory();
pdfManagerMock = new PDFManagerMock({
docBaseUrl: null,
});
done(); done();
}); });
afterAll(function () { afterAll(function () {
annotationFactory = null; annotationFactory = null;
pdfManagerMock = null;
}); });
describe('AnnotationFactory', function () { describe('AnnotationFactory', function () {
@ -49,7 +58,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -66,8 +76,10 @@ describe('Annotation layer', function() {
var uniquePrefix = 'p0_', idCounters = { obj: 0, }; var uniquePrefix = 'p0_', idCounters = { obj: 0, };
var annotation1 = annotationFactory.create(xref, annotationDict, var annotation1 = annotationFactory.create(xref, annotationDict,
pdfManagerMock,
uniquePrefix, idCounters); uniquePrefix, idCounters);
var annotation2 = annotationFactory.create(xref, annotationDict, var annotation2 = annotationFactory.create(xref, annotationDict,
pdfManagerMock,
uniquePrefix, idCounters); uniquePrefix, idCounters);
var data1 = annotation1.data, data2 = annotation2.data; var data1 = annotation1.data, data2 = annotation2.data;
expect(data1.annotationType).toEqual(AnnotationType.LINK); expect(data1.annotationType).toEqual(AnnotationType.LINK);
@ -86,7 +98,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toBeUndefined(); expect(data.annotationType).toBeUndefined();
}); });
@ -270,7 +283,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -297,7 +311,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -329,7 +344,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -356,7 +372,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -384,7 +401,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -394,6 +412,38 @@ describe('Annotation layer', function() {
expect(data.newWindow).toEqual(true); expect(data.newWindow).toEqual(true);
}); });
it('should correctly parse a GoToR action, containing a relative URL, ' +
'with the "docBaseUrl" parameter specified', function() {
var actionDict = new Dict();
actionDict.set('Type', Name.get('Action'));
actionDict.set('S', Name.get('GoToR'));
actionDict.set('F', '../../0013/001346/134685E.pdf');
actionDict.set('D', '4.3');
var annotationDict = new Dict();
annotationDict.set('Type', Name.get('Annot'));
annotationDict.set('Subtype', Name.get('Link'));
annotationDict.set('A', actionDict);
var annotationRef = new Ref(489, 0);
var xref = new XRefMock([
{ ref: annotationRef, data: annotationDict, }
]);
var pdfManager = new PDFManagerMock({
docBaseUrl: 'http://www.example.com/test/pdfs/qwerty.pdf',
});
var annotation = annotationFactory.create(xref, annotationRef,
pdfManager);
var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK);
expect(data.url).toEqual(
'http://www.example.com/0013/001346/134685E.pdf#4.3');
expect(data.unsafeUrl).toEqual('../../0013/001346/134685E.pdf#4.3');
expect(data.dest).toBeUndefined();
});
it('should correctly parse a GoToR action, with named destination', it('should correctly parse a GoToR action, with named destination',
function() { function() {
var actionDict = new Dict(); var actionDict = new Dict();
@ -412,7 +462,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -441,7 +492,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -469,7 +521,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -489,7 +542,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -511,7 +565,8 @@ describe('Annotation layer', function() {
{ ref: annotationRef, data: annotationDict, } { ref: annotationRef, data: annotationDict, }
]); ]);
var annotation = annotationFactory.create(xref, annotationRef); var annotation = annotationFactory.create(xref, annotationRef,
pdfManagerMock);
var data = annotation.data; var data = annotation.data;
expect(data.annotationType).toEqual(AnnotationType.LINK); expect(data.annotationType).toEqual(AnnotationType.LINK);
@ -545,7 +600,8 @@ describe('Annotation layer', function() {
{ ref: textWidgetRef, data: textWidgetDict, } { ref: textWidgetRef, data: textWidgetDict, }
]); ]);
var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef); var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef,
pdfManagerMock);
expect(textWidgetAnnotation.data.textAlignment).toEqual(null); expect(textWidgetAnnotation.data.textAlignment).toEqual(null);
expect(textWidgetAnnotation.data.maxLen).toEqual(null); expect(textWidgetAnnotation.data.maxLen).toEqual(null);
expect(textWidgetAnnotation.data.readOnly).toEqual(false); expect(textWidgetAnnotation.data.readOnly).toEqual(false);
@ -564,7 +620,8 @@ describe('Annotation layer', function() {
{ ref: textWidgetRef, data: textWidgetDict, } { ref: textWidgetRef, data: textWidgetDict, }
]); ]);
var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef); var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef,
pdfManagerMock);
expect(textWidgetAnnotation.data.textAlignment).toEqual(null); expect(textWidgetAnnotation.data.textAlignment).toEqual(null);
expect(textWidgetAnnotation.data.maxLen).toEqual(null); expect(textWidgetAnnotation.data.maxLen).toEqual(null);
expect(textWidgetAnnotation.data.readOnly).toEqual(false); expect(textWidgetAnnotation.data.readOnly).toEqual(false);
@ -584,7 +641,8 @@ describe('Annotation layer', function() {
{ ref: textWidgetRef, data: textWidgetDict, } { ref: textWidgetRef, data: textWidgetDict, }
]); ]);
var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef); var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef,
pdfManagerMock);
expect(textWidgetAnnotation.data.textAlignment).toEqual(1); expect(textWidgetAnnotation.data.textAlignment).toEqual(1);
expect(textWidgetAnnotation.data.maxLen).toEqual(20); expect(textWidgetAnnotation.data.maxLen).toEqual(20);
expect(textWidgetAnnotation.data.readOnly).toEqual(true); expect(textWidgetAnnotation.data.readOnly).toEqual(true);
@ -599,7 +657,8 @@ describe('Annotation layer', function() {
{ ref: textWidgetRef, data: textWidgetDict, } { ref: textWidgetRef, data: textWidgetDict, }
]); ]);
var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef); var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef,
pdfManagerMock);
expect(textWidgetAnnotation.data.comb).toEqual(false); expect(textWidgetAnnotation.data.comb).toEqual(false);
}); });
@ -612,7 +671,8 @@ describe('Annotation layer', function() {
{ ref: textWidgetRef, data: textWidgetDict, } { ref: textWidgetRef, data: textWidgetDict, }
]); ]);
var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef); var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef,
pdfManagerMock);
expect(textWidgetAnnotation.data.comb).toEqual(true); expect(textWidgetAnnotation.data.comb).toEqual(true);
}); });
@ -636,9 +696,8 @@ describe('Annotation layer', function() {
{ ref: textWidgetRef, data: textWidgetDict, } { ref: textWidgetRef, data: textWidgetDict, }
]); ]);
var textWidgetAnnotation = annotationFactory.create(xref, var textWidgetAnnotation = annotationFactory.create(xref, textWidgetRef,
textWidgetRef); pdfManagerMock);
var valid = (invalidFieldFlags.length === 0); var valid = (invalidFieldFlags.length === 0);
expect(textWidgetAnnotation.data.comb).toEqual(valid); expect(textWidgetAnnotation.data.comb).toEqual(valid);
@ -673,7 +732,8 @@ describe('Annotation layer', function() {
]); ]);
var choiceWidgetAnnotation = annotationFactory.create(xref, var choiceWidgetAnnotation = annotationFactory.create(xref,
choiceWidgetRef); choiceWidgetRef,
pdfManagerMock);
var data = choiceWidgetAnnotation.data; var data = choiceWidgetAnnotation.data;
expect(data.annotationType).toEqual(AnnotationType.WIDGET); expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.options).toEqual([]); expect(data.options).toEqual([]);
@ -700,7 +760,8 @@ describe('Annotation layer', function() {
]); ]);
var choiceWidgetAnnotation = annotationFactory.create(xref, var choiceWidgetAnnotation = annotationFactory.create(xref,
choiceWidgetRef); choiceWidgetRef,
pdfManagerMock);
var data = choiceWidgetAnnotation.data; var data = choiceWidgetAnnotation.data;
expect(data.annotationType).toEqual(AnnotationType.WIDGET); expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.options).toEqual(expected); expect(data.options).toEqual(expected);
@ -727,7 +788,8 @@ describe('Annotation layer', function() {
]); ]);
var choiceWidgetAnnotation = annotationFactory.create(xref, var choiceWidgetAnnotation = annotationFactory.create(xref,
choiceWidgetRef); choiceWidgetRef,
pdfManagerMock);
var data = choiceWidgetAnnotation.data; var data = choiceWidgetAnnotation.data;
expect(data.annotationType).toEqual(AnnotationType.WIDGET); expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.options).toEqual(expected); expect(data.options).toEqual(expected);
@ -744,7 +806,8 @@ describe('Annotation layer', function() {
]); ]);
var choiceWidgetAnnotation = annotationFactory.create(xref, var choiceWidgetAnnotation = annotationFactory.create(xref,
choiceWidgetRef); choiceWidgetRef,
pdfManagerMock);
var data = choiceWidgetAnnotation.data; var data = choiceWidgetAnnotation.data;
expect(data.annotationType).toEqual(AnnotationType.WIDGET); expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.fieldValue).toEqual(fieldValue); expect(data.fieldValue).toEqual(fieldValue);
@ -761,7 +824,8 @@ describe('Annotation layer', function() {
]); ]);
var choiceWidgetAnnotation = annotationFactory.create(xref, var choiceWidgetAnnotation = annotationFactory.create(xref,
choiceWidgetRef); choiceWidgetRef,
pdfManagerMock);
var data = choiceWidgetAnnotation.data; var data = choiceWidgetAnnotation.data;
expect(data.annotationType).toEqual(AnnotationType.WIDGET); expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.fieldValue).toEqual([fieldValue]); expect(data.fieldValue).toEqual([fieldValue]);
@ -774,7 +838,8 @@ describe('Annotation layer', function() {
]); ]);
var choiceWidgetAnnotation = annotationFactory.create(xref, var choiceWidgetAnnotation = annotationFactory.create(xref,
choiceWidgetRef); choiceWidgetRef,
pdfManagerMock);
var data = choiceWidgetAnnotation.data; var data = choiceWidgetAnnotation.data;
expect(data.annotationType).toEqual(AnnotationType.WIDGET); expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.readOnly).toEqual(false); expect(data.readOnly).toEqual(false);
@ -791,7 +856,8 @@ describe('Annotation layer', function() {
]); ]);
var choiceWidgetAnnotation = annotationFactory.create(xref, var choiceWidgetAnnotation = annotationFactory.create(xref,
choiceWidgetRef); choiceWidgetRef,
pdfManagerMock);
var data = choiceWidgetAnnotation.data; var data = choiceWidgetAnnotation.data;
expect(data.annotationType).toEqual(AnnotationType.WIDGET); expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.readOnly).toEqual(false); expect(data.readOnly).toEqual(false);
@ -810,7 +876,8 @@ describe('Annotation layer', function() {
]); ]);
var choiceWidgetAnnotation = annotationFactory.create(xref, var choiceWidgetAnnotation = annotationFactory.create(xref,
choiceWidgetRef); choiceWidgetRef,
pdfManagerMock);
var data = choiceWidgetAnnotation.data; var data = choiceWidgetAnnotation.data;
expect(data.annotationType).toEqual(AnnotationType.WIDGET); expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.readOnly).toEqual(true); expect(data.readOnly).toEqual(true);
@ -869,7 +936,8 @@ describe('Annotation layer', function() {
{ ref: popupRef, data: popupDict, } { ref: popupRef, data: popupDict, }
]); ]);
var popupAnnotation = annotationFactory.create(xref, popupRef); var popupAnnotation = annotationFactory.create(xref, popupRef,
pdfManagerMock);
var data = popupAnnotation.data; var data = popupAnnotation.data;
expect(data.annotationType).toEqual(AnnotationType.POPUP); expect(data.annotationType).toEqual(AnnotationType.POPUP);

62
test/unit/api_spec.js

@ -789,6 +789,68 @@ describe('api', function() {
done.fail(reason); done.fail(reason);
}); });
}); });
it('gets annotations containing relative URLs (bug 766086)',
function (done) {
var url = new URL('../pdfs/bug766086.pdf', window.location).href;
var defaultLoadingTask = PDFJS.getDocument(url);
var defaultPromise = defaultLoadingTask.promise.then(function (pdfDoc) {
return pdfDoc.getPage(1).then(function (pdfPage) {
return pdfPage.getAnnotations();
});
});
var docBaseUrlLoadingTask = PDFJS.getDocument({
url: url,
docBaseUrl: 'http://www.example.com/test/pdfs/qwerty.pdf',
});
var docBaseUrlPromise = docBaseUrlLoadingTask.promise.then(
function (pdfDoc) {
return pdfDoc.getPage(1).then(function (pdfPage) {
return pdfPage.getAnnotations();
});
});
var invalidDocBaseUrlLoadingTask = PDFJS.getDocument({
url: url,
docBaseUrl: 'qwerty.pdf',
});
var invalidDocBaseUrlPromise = invalidDocBaseUrlLoadingTask.promise.then(
function (pdfDoc) {
return pdfDoc.getPage(1).then(function (pdfPage) {
return pdfPage.getAnnotations();
});
});
Promise.all([defaultPromise, docBaseUrlPromise,
invalidDocBaseUrlPromise]).then(function (data) {
var defaultAnnotations = data[0];
var docBaseUrlAnnotations = data[1];
var invalidDocBaseUrlAnnotations = data[2];
expect(defaultAnnotations[0].url).toBeUndefined();
expect(defaultAnnotations[0].unsafeUrl).toEqual(
'../../0021/002156/215675E.pdf#nameddest=15');
expect(docBaseUrlAnnotations[0].url).toEqual(
'http://www.example.com/0021/002156/215675E.pdf#nameddest=15');
expect(docBaseUrlAnnotations[0].unsafeUrl).toEqual(
'../../0021/002156/215675E.pdf#nameddest=15');
expect(invalidDocBaseUrlAnnotations[0].url).toBeUndefined();
expect(invalidDocBaseUrlAnnotations[0].unsafeUrl).toEqual(
'../../0021/002156/215675E.pdf#nameddest=15');
defaultLoadingTask.destroy();
docBaseUrlLoadingTask.destroy();
invalidDocBaseUrlLoadingTask.destroy();
done();
}).catch(function (reason) {
done.fail(reason);
});
});
it('gets text content', function (done) { it('gets text content', function (done) {
var defaultPromise = page.getTextContent(); var defaultPromise = page.getTextContent();
var parametersPromise = page.getTextContent({ var parametersPromise = page.getTextContent({

28
web/app.js

@ -180,6 +180,7 @@ var PDFViewerApplication = {
preferenceDefaultZoomValue: '', preferenceDefaultZoomValue: '',
isViewerEmbedded: (window.parent !== window), isViewerEmbedded: (window.parent !== window),
url: '', url: '',
baseUrl: '',
externalServices: DefaultExernalServices, externalServices: DefaultExernalServices,
// called once when the document is loaded // called once when the document is loaded
@ -522,6 +523,7 @@ var PDFViewerApplication = {
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) { setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
this.url = url; this.url = url;
this.baseUrl = url.split('#')[0];
try { try {
this.setTitle(decodeURIComponent( this.setTitle(decodeURIComponent(
pdfjsLib.getFilenameFromUrl(url)) || url); pdfjsLib.getFilenameFromUrl(url)) || url);
@ -614,6 +616,11 @@ var PDFViewerApplication = {
this.setTitleUsingUrl(file.originalUrl); this.setTitleUsingUrl(file.originalUrl);
parameters.url = file.url; parameters.url = file.url;
} }
if (typeof PDFJSDev !== 'undefined' &&
PDFJSDev.test('FIREFOX || MOZCENTRAL || CHROME')) {
parameters.docBaseUrl = this.baseUrl;
}
if (args) { if (args) {
for (var prop in args) { for (var prop in args) {
parameters[prop] = args[prop]; parameters[prop] = args[prop];
@ -682,7 +689,7 @@ var PDFViewerApplication = {
downloadManager.downloadUrl(url, filename); downloadManager.downloadUrl(url, filename);
} }
var url = this.url.split('#')[0]; var url = this.baseUrl;
var filename = getPDFFileNameFromURL(url); var filename = getPDFFileNameFromURL(url);
var downloadManager = this.downloadManager; var downloadManager = this.downloadManager;
downloadManager.onerror = function (err) { downloadManager.onerror = function (err) {
@ -719,14 +726,15 @@ var PDFViewerApplication = {
return; return;
} }
this.fellback = true; this.fellback = true;
var url = this.url.split('#')[0]; this.externalServices.fallback({
this.externalServices.fallback({ featureId: featureId, url: url }, featureId: featureId,
function response(download) { url: this.baseUrl,
if (!download) { }, function response(download) {
return; if (!download) {
} return;
PDFViewerApplication.download(); }
}); PDFViewerApplication.download();
});
} }
}, },
@ -856,7 +864,7 @@ var PDFViewerApplication = {
if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) { if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
baseDocumentUrl = null; baseDocumentUrl = null;
} else if (PDFJSDev.test('FIREFOX || MOZCENTRAL')) { } else if (PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
baseDocumentUrl = this.url.split('#')[0]; baseDocumentUrl = this.baseUrl;
} else if (PDFJSDev.test('CHROME')) { } else if (PDFJSDev.test('CHROME')) {
baseDocumentUrl = location.href.split('#')[0]; baseDocumentUrl = location.href.split('#')[0];
} }

Loading…
Cancel
Save