Load built-in CMap files using the Fetch API when possible
This commit is contained in:
parent
df7756d2a4
commit
cbc07f985b
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
assert, CMapCompressionType, removeNullCharacters, stringToBytes,
|
assert, CMapCompressionType, removeNullCharacters, stringToBytes,
|
||||||
unreachable, Util, warn
|
unreachable, URL, Util, warn
|
||||||
} from '../shared/util';
|
} from '../shared/util';
|
||||||
|
|
||||||
const DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
|
const DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
|
||||||
@ -66,19 +66,41 @@ class DOMCMapReaderFactory {
|
|||||||
this.isCompressed = isCompressed;
|
this.isCompressed = isCompressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch({ name, }) {
|
async fetch({ name, }) {
|
||||||
if (!this.baseUrl) {
|
if (!this.baseUrl) {
|
||||||
return Promise.reject(new Error(
|
throw new Error(
|
||||||
'The CMap "baseUrl" parameter must be specified, ensure that ' +
|
'The CMap "baseUrl" parameter must be specified, ensure that ' +
|
||||||
'the "cMapUrl" and "cMapPacked" API parameters are provided.'));
|
'the "cMapUrl" and "cMapPacked" API parameters are provided.');
|
||||||
}
|
}
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return Promise.reject(new Error('CMap name must be specified.'));
|
throw new Error('CMap name must be specified.');
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
const url = this.baseUrl + name + (this.isCompressed ? '.bcmap' : '');
|
||||||
let url = this.baseUrl + name + (this.isCompressed ? '.bcmap' : '');
|
const compressionType = (this.isCompressed ? CMapCompressionType.BINARY :
|
||||||
|
CMapCompressionType.NONE);
|
||||||
|
|
||||||
let request = new XMLHttpRequest();
|
if ((typeof PDFJSDev !== 'undefined' && PDFJSDev.test('MOZCENTRAL')) ||
|
||||||
|
(isFetchSupported() && isValidFetchUrl(url, document.baseURI))) {
|
||||||
|
return fetch(url).then(async (response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(response.statusText);
|
||||||
|
}
|
||||||
|
let cMapData;
|
||||||
|
if (this.isCompressed) {
|
||||||
|
cMapData = new Uint8Array(await response.arrayBuffer());
|
||||||
|
} else {
|
||||||
|
cMapData = stringToBytes(await response.text());
|
||||||
|
}
|
||||||
|
return { cMapData, compressionType, };
|
||||||
|
}).catch((reason) => {
|
||||||
|
throw new Error(`Unable to load ${this.isCompressed ? 'binary ' : ''}` +
|
||||||
|
`CMap at: ${url}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Fetch API is not supported.
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const request = new XMLHttpRequest();
|
||||||
request.open('GET', url, true);
|
request.open('GET', url, true);
|
||||||
|
|
||||||
if (this.isCompressed) {
|
if (this.isCompressed) {
|
||||||
@ -89,27 +111,24 @@ class DOMCMapReaderFactory {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (request.status === 200 || request.status === 0) {
|
if (request.status === 200 || request.status === 0) {
|
||||||
let data;
|
let cMapData;
|
||||||
if (this.isCompressed && request.response) {
|
if (this.isCompressed && request.response) {
|
||||||
data = new Uint8Array(request.response);
|
cMapData = new Uint8Array(request.response);
|
||||||
} else if (!this.isCompressed && request.responseText) {
|
} else if (!this.isCompressed && request.responseText) {
|
||||||
data = stringToBytes(request.responseText);
|
cMapData = stringToBytes(request.responseText);
|
||||||
}
|
}
|
||||||
if (data) {
|
if (cMapData) {
|
||||||
resolve({
|
resolve({ cMapData, compressionType, });
|
||||||
cMapData: data,
|
|
||||||
compressionType: this.isCompressed ?
|
|
||||||
CMapCompressionType.BINARY : CMapCompressionType.NONE,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reject(new Error('Unable to load ' +
|
reject(new Error(request.statusText));
|
||||||
(this.isCompressed ? 'binary ' : '') +
|
|
||||||
'CMap at: ' + url));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
request.send(null);
|
request.send(null);
|
||||||
|
}).catch((reason) => {
|
||||||
|
throw new Error(`Unable to load ${this.isCompressed ? 'binary ' : ''}` +
|
||||||
|
`CMap at: ${url}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -428,6 +447,23 @@ class DummyStatTimer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isFetchSupported() {
|
||||||
|
return (typeof fetch !== 'undefined' &&
|
||||||
|
typeof Response !== 'undefined' && 'body' in Response.prototype &&
|
||||||
|
// eslint-disable-next-line no-restricted-globals
|
||||||
|
typeof ReadableStream !== 'undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValidFetchUrl(url, baseUrl) {
|
||||||
|
try {
|
||||||
|
const { protocol, } = baseUrl ? new URL(url, baseUrl) : new URL(url);
|
||||||
|
// The Fetch API only supports the http/https protocols, and not file/ftp.
|
||||||
|
return (protocol === 'http:' || protocol === 'https:');
|
||||||
|
} catch (ex) {
|
||||||
|
return false; // `new URL()` will throw on incorrect data.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadScript(src) {
|
function loadScript(src) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let script = document.createElement('script');
|
let script = document.createElement('script');
|
||||||
@ -453,5 +489,6 @@ export {
|
|||||||
DOMSVGFactory,
|
DOMSVGFactory,
|
||||||
StatTimer,
|
StatTimer,
|
||||||
DummyStatTimer,
|
DummyStatTimer,
|
||||||
|
isFetchSupported,
|
||||||
loadScript,
|
loadScript,
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
/* eslint-disable no-unused-vars, no-restricted-globals */
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -37,8 +37,7 @@ if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
|
|||||||
pdfjsDisplayAPI.setPDFNetworkStreamFactory((params) => {
|
pdfjsDisplayAPI.setPDFNetworkStreamFactory((params) => {
|
||||||
return new PDFNodeStream(params);
|
return new PDFNodeStream(params);
|
||||||
});
|
});
|
||||||
} else if (typeof Response !== 'undefined' && 'body' in Response.prototype &&
|
} else if (pdfjsDisplayDisplayUtils.isFetchSupported()) {
|
||||||
typeof ReadableStream !== 'undefined') {
|
|
||||||
let PDFFetchStream = require('./display/fetch_stream.js').PDFFetchStream;
|
let PDFFetchStream = require('./display/fetch_stream.js').PDFFetchStream;
|
||||||
pdfjsDisplayAPI.setPDFNetworkStreamFactory((params) => {
|
pdfjsDisplayAPI.setPDFNetworkStreamFactory((params) => {
|
||||||
return new PDFFetchStream(params);
|
return new PDFFetchStream(params);
|
||||||
@ -65,8 +64,8 @@ if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (typeof Response !== 'undefined' && 'body' in Response.prototype &&
|
if (pdfjsDisplayDisplayUtils.isFetchSupported() &&
|
||||||
typeof ReadableStream !== 'undefined' && isChromeWithFetchCredentials()) {
|
isChromeWithFetchCredentials()) {
|
||||||
PDFFetchStream = require('./display/fetch_stream.js').PDFFetchStream;
|
PDFFetchStream = require('./display/fetch_stream.js').PDFFetchStream;
|
||||||
}
|
}
|
||||||
pdfjsDisplayAPI.setPDFNetworkStreamFactory((params) => {
|
pdfjsDisplayAPI.setPDFNetworkStreamFactory((params) => {
|
||||||
|
@ -99,32 +99,31 @@ class NodeCMapReaderFactory {
|
|||||||
this.isCompressed = isCompressed;
|
this.isCompressed = isCompressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch({ name, }) {
|
async fetch({ name, }) {
|
||||||
if (!this.baseUrl) {
|
if (!this.baseUrl) {
|
||||||
return Promise.reject(new Error(
|
throw new Error(
|
||||||
'The CMap "baseUrl" parameter must be specified, ensure that ' +
|
'The CMap "baseUrl" parameter must be specified, ensure that ' +
|
||||||
'the "cMapUrl" and "cMapPacked" API parameters are provided.'));
|
'the "cMapUrl" and "cMapPacked" API parameters are provided.');
|
||||||
}
|
}
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return Promise.reject(new Error('CMap name must be specified.'));
|
throw new Error('CMap name must be specified.');
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
const url = this.baseUrl + name + (this.isCompressed ? '.bcmap' : '');
|
||||||
let url = this.baseUrl + name + (this.isCompressed ? '.bcmap' : '');
|
const compressionType = (this.isCompressed ? CMapCompressionType.BINARY :
|
||||||
|
CMapCompressionType.NONE);
|
||||||
|
|
||||||
let fs = require('fs');
|
return new Promise((resolve, reject) => {
|
||||||
|
const fs = require('fs');
|
||||||
fs.readFile(url, (error, data) => {
|
fs.readFile(url, (error, data) => {
|
||||||
if (error || !data) {
|
if (error || !data) {
|
||||||
reject(new Error('Unable to load ' +
|
reject(new Error(error));
|
||||||
(this.isCompressed ? 'binary ' : '') +
|
|
||||||
'CMap at: ' + url));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resolve({
|
resolve({ cMapData: new Uint8Array(data), compressionType, });
|
||||||
cMapData: new Uint8Array(data),
|
|
||||||
compressionType: this.isCompressed ?
|
|
||||||
CMapCompressionType.BINARY : CMapCompressionType.NONE,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
}).catch((reason) => {
|
||||||
|
throw new Error(`Unable to load ${this.isCompressed ? 'binary ' : ''}` +
|
||||||
|
`CMap at: ${url}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user