mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-07-29 10:27:21 +02:00
Add an abstract BasePDFStream class, that all the old IPDFStream implementations inherit from
Given that there's no less than *five* different, but very similar, implementations this helps reduce code duplication and simplifies maintenance. Also, spotted during rebasing, pass the `enableHWA` option "correctly" (i.e. as part of the existing `transportParams`) to the `WorkerTransport`-class to keep the constructor simpler.
This commit is contained in:
parent
a80f10ff1a
commit
4a8fb4dde1
@ -272,17 +272,17 @@ class ChunkedStreamManager {
|
|||||||
|
|
||||||
_requestsByChunk = new Map();
|
_requestsByChunk = new Map();
|
||||||
|
|
||||||
constructor(pdfNetworkStream, args) {
|
constructor(pdfStream, args) {
|
||||||
this.length = args.length;
|
this.length = args.length;
|
||||||
this.chunkSize = args.rangeChunkSize;
|
this.chunkSize = args.rangeChunkSize;
|
||||||
this.stream = new ChunkedStream(this.length, this.chunkSize, this);
|
this.stream = new ChunkedStream(this.length, this.chunkSize, this);
|
||||||
this.pdfNetworkStream = pdfNetworkStream;
|
this.pdfStream = pdfStream;
|
||||||
this.disableAutoFetch = args.disableAutoFetch;
|
this.disableAutoFetch = args.disableAutoFetch;
|
||||||
this.msgHandler = args.msgHandler;
|
this.msgHandler = args.msgHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendRequest(begin, end) {
|
sendRequest(begin, end) {
|
||||||
const rangeReader = this.pdfNetworkStream.getRangeReader(begin, end);
|
const rangeReader = this.pdfStream.getRangeReader(begin, end);
|
||||||
|
|
||||||
let chunks = [];
|
let chunks = [];
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -530,7 +530,7 @@ class ChunkedStreamManager {
|
|||||||
|
|
||||||
abort(reason) {
|
abort(reason) {
|
||||||
this.aborted = true;
|
this.aborted = true;
|
||||||
this.pdfNetworkStream?.cancelAllRequests(reason);
|
this.pdfStream?.cancelAllRequests(reason);
|
||||||
|
|
||||||
for (const capability of this._promisesByRequest.values()) {
|
for (const capability of this._promisesByRequest.values()) {
|
||||||
capability.reject(reason);
|
capability.reject(reason);
|
||||||
|
|||||||
@ -219,23 +219,23 @@ class WorkerMessageHandler {
|
|||||||
|
|
||||||
return new LocalPdfManager(pdfManagerArgs);
|
return new LocalPdfManager(pdfManagerArgs);
|
||||||
}
|
}
|
||||||
const pdfStream = new PDFWorkerStream(handler),
|
const pdfStream = new PDFWorkerStream({ msgHandler: handler }),
|
||||||
fullRequest = pdfStream.getFullReader();
|
fullReader = pdfStream.getFullReader();
|
||||||
|
|
||||||
const pdfManagerCapability = Promise.withResolvers();
|
const pdfManagerCapability = Promise.withResolvers();
|
||||||
let newPdfManager,
|
let newPdfManager,
|
||||||
cachedChunks = [],
|
cachedChunks = [],
|
||||||
loaded = 0;
|
loaded = 0;
|
||||||
|
|
||||||
fullRequest.headersReady
|
fullReader.headersReady
|
||||||
.then(function () {
|
.then(function () {
|
||||||
if (!fullRequest.isRangeSupported) {
|
if (!fullReader.isRangeSupported) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pdfManagerArgs.source = pdfStream;
|
pdfManagerArgs.source = pdfStream;
|
||||||
pdfManagerArgs.length = fullRequest.contentLength;
|
pdfManagerArgs.length = fullReader.contentLength;
|
||||||
// We don't need auto-fetch when streaming is enabled.
|
// We don't need auto-fetch when streaming is enabled.
|
||||||
pdfManagerArgs.disableAutoFetch ||= fullRequest.isStreamingSupported;
|
pdfManagerArgs.disableAutoFetch ||= fullReader.isStreamingSupported;
|
||||||
|
|
||||||
newPdfManager = new NetworkPdfManager(pdfManagerArgs);
|
newPdfManager = new NetworkPdfManager(pdfManagerArgs);
|
||||||
// There may be a chance that `newPdfManager` is not initialized for
|
// There may be a chance that `newPdfManager` is not initialized for
|
||||||
@ -282,10 +282,10 @@ class WorkerMessageHandler {
|
|||||||
}
|
}
|
||||||
loaded += value.byteLength;
|
loaded += value.byteLength;
|
||||||
|
|
||||||
if (!fullRequest.isStreamingSupported) {
|
if (!fullReader.isStreamingSupported) {
|
||||||
handler.send("DocProgress", {
|
handler.send("DocProgress", {
|
||||||
loaded,
|
loaded,
|
||||||
total: Math.max(loaded, fullRequest.contentLength || 0),
|
total: Math.max(loaded, fullReader.contentLength || 0),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,12 +294,12 @@ class WorkerMessageHandler {
|
|||||||
} else {
|
} else {
|
||||||
cachedChunks.push(value);
|
cachedChunks.push(value);
|
||||||
}
|
}
|
||||||
fullRequest.read().then(readChunk, reject);
|
fullReader.read().then(readChunk, reject);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e);
|
reject(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fullRequest.read().then(readChunk, reject);
|
fullReader.read().then(readChunk, reject);
|
||||||
}).catch(function (e) {
|
}).catch(function (e) {
|
||||||
pdfManagerCapability.reject(e);
|
pdfManagerCapability.reject(e);
|
||||||
cancelXHRs = null;
|
cancelXHRs = null;
|
||||||
|
|||||||
@ -13,55 +13,28 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { assert } from "../shared/util.js";
|
import { BasePDFStream } from "../shared/base_pdf_stream.js";
|
||||||
|
|
||||||
/** @implements {IPDFStream} */
|
class PDFWorkerStream extends BasePDFStream {
|
||||||
class PDFWorkerStream {
|
constructor(source) {
|
||||||
constructor(msgHandler) {
|
super(source, PDFWorkerStreamReader, PDFWorkerStreamRangeReader);
|
||||||
this._msgHandler = msgHandler;
|
|
||||||
this._contentLength = null;
|
|
||||||
this._fullRequestReader = null;
|
|
||||||
this._rangeRequestReaders = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
getFullReader() {
|
|
||||||
assert(
|
|
||||||
!this._fullRequestReader,
|
|
||||||
"PDFWorkerStream.getFullReader can only be called once."
|
|
||||||
);
|
|
||||||
this._fullRequestReader = new PDFWorkerStreamReader(this._msgHandler);
|
|
||||||
return this._fullRequestReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRangeReader(begin, end) {
|
|
||||||
const reader = new PDFWorkerStreamRangeReader(begin, end, this._msgHandler);
|
|
||||||
this._rangeRequestReaders.push(reader);
|
|
||||||
return reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelAllRequests(reason) {
|
|
||||||
this._fullRequestReader?.cancel(reason);
|
|
||||||
|
|
||||||
for (const reader of this._rangeRequestReaders.slice(0)) {
|
|
||||||
reader.cancel(reason);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @implements {IPDFStreamReader} */
|
/** @implements {IPDFStreamReader} */
|
||||||
class PDFWorkerStreamReader {
|
class PDFWorkerStreamReader {
|
||||||
constructor(msgHandler) {
|
constructor(stream) {
|
||||||
this._msgHandler = msgHandler;
|
const { msgHandler } = stream._source;
|
||||||
this.onProgress = null;
|
this.onProgress = null;
|
||||||
|
|
||||||
this._contentLength = null;
|
this._contentLength = null;
|
||||||
this._isRangeSupported = false;
|
this._isRangeSupported = false;
|
||||||
this._isStreamingSupported = false;
|
this._isStreamingSupported = false;
|
||||||
|
|
||||||
const readableStream = this._msgHandler.sendWithStream("GetReader");
|
const readableStream = msgHandler.sendWithStream("GetReader");
|
||||||
this._reader = readableStream.getReader();
|
this._reader = readableStream.getReader();
|
||||||
|
|
||||||
this._headersReady = this._msgHandler
|
this._headersReady = msgHandler
|
||||||
.sendWithPromise("ReaderHeadersReady")
|
.sendWithPromise("ReaderHeadersReady")
|
||||||
.then(data => {
|
.then(data => {
|
||||||
this._isStreamingSupported = data.isStreamingSupported;
|
this._isStreamingSupported = data.isStreamingSupported;
|
||||||
@ -103,10 +76,10 @@ class PDFWorkerStreamReader {
|
|||||||
|
|
||||||
/** @implements {IPDFStreamRangeReader} */
|
/** @implements {IPDFStreamRangeReader} */
|
||||||
class PDFWorkerStreamRangeReader {
|
class PDFWorkerStreamRangeReader {
|
||||||
constructor(begin, end, msgHandler) {
|
constructor(stream, begin, end) {
|
||||||
this._msgHandler = msgHandler;
|
const { msgHandler } = stream._source;
|
||||||
|
|
||||||
const readableStream = this._msgHandler.sendWithStream("GetRangeReader", {
|
const readableStream = msgHandler.sendWithStream("GetRangeReader", {
|
||||||
begin,
|
begin,
|
||||||
end,
|
end,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -440,6 +440,7 @@ function getDocument(src = {}) {
|
|||||||
ownerDocument,
|
ownerDocument,
|
||||||
pdfBug,
|
pdfBug,
|
||||||
styleElement,
|
styleElement,
|
||||||
|
enableHWA,
|
||||||
loadingParams: {
|
loadingParams: {
|
||||||
disableAutoFetch,
|
disableAutoFetch,
|
||||||
enableXfa,
|
enableXfa,
|
||||||
@ -463,7 +464,8 @@ function getDocument(src = {}) {
|
|||||||
|
|
||||||
let networkStream;
|
let networkStream;
|
||||||
if (rangeTransport) {
|
if (rangeTransport) {
|
||||||
networkStream = new PDFDataTransportStream(rangeTransport, {
|
networkStream = new PDFDataTransportStream({
|
||||||
|
pdfDataRangeTransport: rangeTransport,
|
||||||
disableRange,
|
disableRange,
|
||||||
disableStream,
|
disableStream,
|
||||||
});
|
});
|
||||||
@ -508,8 +510,7 @@ function getDocument(src = {}) {
|
|||||||
task,
|
task,
|
||||||
networkStream,
|
networkStream,
|
||||||
transportParams,
|
transportParams,
|
||||||
transportFactory,
|
transportFactory
|
||||||
enableHWA
|
|
||||||
);
|
);
|
||||||
task._transport = transport;
|
task._transport = transport;
|
||||||
messageHandler.send("Ready", null);
|
messageHandler.send("Ready", null);
|
||||||
@ -2391,8 +2392,16 @@ class PDFWorker {
|
|||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
class WorkerTransport {
|
class WorkerTransport {
|
||||||
|
downloadInfoCapability = Promise.withResolvers();
|
||||||
|
|
||||||
|
#fullReader = null;
|
||||||
|
|
||||||
|
#lastProgress = null;
|
||||||
|
|
||||||
#methodPromises = new Map();
|
#methodPromises = new Map();
|
||||||
|
|
||||||
|
#networkStream = null;
|
||||||
|
|
||||||
#pageCache = new Map();
|
#pageCache = new Map();
|
||||||
|
|
||||||
#pagePromises = new Map();
|
#pagePromises = new Map();
|
||||||
@ -2403,21 +2412,17 @@ class WorkerTransport {
|
|||||||
|
|
||||||
#pagesMapper = PagesMapper.instance;
|
#pagesMapper = PagesMapper.instance;
|
||||||
|
|
||||||
constructor(
|
constructor(messageHandler, loadingTask, networkStream, params, factory) {
|
||||||
messageHandler,
|
|
||||||
loadingTask,
|
|
||||||
networkStream,
|
|
||||||
params,
|
|
||||||
factory,
|
|
||||||
enableHWA
|
|
||||||
) {
|
|
||||||
this.messageHandler = messageHandler;
|
this.messageHandler = messageHandler;
|
||||||
this.loadingTask = loadingTask;
|
this.loadingTask = loadingTask;
|
||||||
|
this.#networkStream = networkStream;
|
||||||
|
|
||||||
this.commonObjs = new PDFObjects();
|
this.commonObjs = new PDFObjects();
|
||||||
this.fontLoader = new FontLoader({
|
this.fontLoader = new FontLoader({
|
||||||
ownerDocument: params.ownerDocument,
|
ownerDocument: params.ownerDocument,
|
||||||
styleElement: params.styleElement,
|
styleElement: params.styleElement,
|
||||||
});
|
});
|
||||||
|
this.enableHWA = params.enableHWA;
|
||||||
this.loadingParams = params.loadingParams;
|
this.loadingParams = params.loadingParams;
|
||||||
this._params = params;
|
this._params = params;
|
||||||
|
|
||||||
@ -2430,12 +2435,6 @@ class WorkerTransport {
|
|||||||
this.destroyed = false;
|
this.destroyed = false;
|
||||||
this.destroyCapability = null;
|
this.destroyCapability = null;
|
||||||
|
|
||||||
this._networkStream = networkStream;
|
|
||||||
this._fullReader = null;
|
|
||||||
this._lastProgress = null;
|
|
||||||
this.downloadInfoCapability = Promise.withResolvers();
|
|
||||||
this.enableHWA = enableHWA;
|
|
||||||
|
|
||||||
this.setupMessageHandler();
|
this.setupMessageHandler();
|
||||||
|
|
||||||
this.#pagesMapper.addListener(this.#updateCaches.bind(this));
|
this.#pagesMapper.addListener(this.#updateCaches.bind(this));
|
||||||
@ -2604,7 +2603,7 @@ class WorkerTransport {
|
|||||||
this.filterFactory.destroy();
|
this.filterFactory.destroy();
|
||||||
TextLayer.cleanup();
|
TextLayer.cleanup();
|
||||||
|
|
||||||
this._networkStream?.cancelAllRequests(
|
this.#networkStream?.cancelAllRequests(
|
||||||
new AbortException("Worker was terminated.")
|
new AbortException("Worker was terminated.")
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2621,18 +2620,18 @@ class WorkerTransport {
|
|||||||
|
|
||||||
messageHandler.on("GetReader", (data, sink) => {
|
messageHandler.on("GetReader", (data, sink) => {
|
||||||
assert(
|
assert(
|
||||||
this._networkStream,
|
this.#networkStream,
|
||||||
"GetReader - no `IPDFStream` instance available."
|
"GetReader - no `BasePDFStream` instance available."
|
||||||
);
|
);
|
||||||
this._fullReader = this._networkStream.getFullReader();
|
this.#fullReader = this.#networkStream.getFullReader();
|
||||||
this._fullReader.onProgress = evt => {
|
this.#fullReader.onProgress = evt => {
|
||||||
this._lastProgress = {
|
this.#lastProgress = {
|
||||||
loaded: evt.loaded,
|
loaded: evt.loaded,
|
||||||
total: evt.total,
|
total: evt.total,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
sink.onPull = () => {
|
sink.onPull = () => {
|
||||||
this._fullReader
|
this.#fullReader
|
||||||
.read()
|
.read()
|
||||||
.then(function ({ value, done }) {
|
.then(function ({ value, done }) {
|
||||||
if (done) {
|
if (done) {
|
||||||
@ -2653,7 +2652,7 @@ class WorkerTransport {
|
|||||||
};
|
};
|
||||||
|
|
||||||
sink.onCancel = reason => {
|
sink.onCancel = reason => {
|
||||||
this._fullReader.cancel(reason);
|
this.#fullReader.cancel(reason);
|
||||||
|
|
||||||
sink.ready.catch(readyReason => {
|
sink.ready.catch(readyReason => {
|
||||||
if (this.destroyed) {
|
if (this.destroyed) {
|
||||||
@ -2665,18 +2664,18 @@ class WorkerTransport {
|
|||||||
});
|
});
|
||||||
|
|
||||||
messageHandler.on("ReaderHeadersReady", async data => {
|
messageHandler.on("ReaderHeadersReady", async data => {
|
||||||
await this._fullReader.headersReady;
|
await this.#fullReader.headersReady;
|
||||||
|
|
||||||
const { isStreamingSupported, isRangeSupported, contentLength } =
|
const { isStreamingSupported, isRangeSupported, contentLength } =
|
||||||
this._fullReader;
|
this.#fullReader;
|
||||||
|
|
||||||
// If stream or range are disabled, it's our only way to report
|
// If stream or range are disabled, it's our only way to report
|
||||||
// loading progress.
|
// loading progress.
|
||||||
if (!isStreamingSupported || !isRangeSupported) {
|
if (!isStreamingSupported || !isRangeSupported) {
|
||||||
if (this._lastProgress) {
|
if (this.#lastProgress) {
|
||||||
loadingTask.onProgress?.(this._lastProgress);
|
loadingTask.onProgress?.(this.#lastProgress);
|
||||||
}
|
}
|
||||||
this._fullReader.onProgress = evt => {
|
this.#fullReader.onProgress = evt => {
|
||||||
loadingTask.onProgress?.({
|
loadingTask.onProgress?.({
|
||||||
loaded: evt.loaded,
|
loaded: evt.loaded,
|
||||||
total: evt.total,
|
total: evt.total,
|
||||||
@ -2689,16 +2688,16 @@ class WorkerTransport {
|
|||||||
|
|
||||||
messageHandler.on("GetRangeReader", (data, sink) => {
|
messageHandler.on("GetRangeReader", (data, sink) => {
|
||||||
assert(
|
assert(
|
||||||
this._networkStream,
|
this.#networkStream,
|
||||||
"GetRangeReader - no `IPDFStream` instance available."
|
"GetRangeReader - no `BasePDFStream` instance available."
|
||||||
);
|
);
|
||||||
const rangeReader = this._networkStream.getRangeReader(
|
const rangeReader = this.#networkStream.getRangeReader(
|
||||||
data.begin,
|
data.begin,
|
||||||
data.end
|
data.end
|
||||||
);
|
);
|
||||||
|
|
||||||
// When streaming is enabled, it's possible that the data requested here
|
// When streaming is enabled, it's possible that the data requested here
|
||||||
// has already been fetched via the `_fullRequestReader` implementation.
|
// has already been fetched via the `#fullReader` implementation.
|
||||||
// However, given that the PDF data is loaded asynchronously on the
|
// However, given that the PDF data is loaded asynchronously on the
|
||||||
// main-thread and then sent via `postMessage` to the worker-thread,
|
// main-thread and then sent via `postMessage` to the worker-thread,
|
||||||
// it may not have been available during parsing (hence the attempt to
|
// it may not have been available during parsing (hence the attempt to
|
||||||
@ -2706,7 +2705,7 @@ class WorkerTransport {
|
|||||||
//
|
//
|
||||||
// To avoid wasting time and resources here, we'll thus *not* dispatch
|
// To avoid wasting time and resources here, we'll thus *not* dispatch
|
||||||
// range requests if the data was already loaded but has not been sent to
|
// range requests if the data was already loaded but has not been sent to
|
||||||
// the worker-thread yet (which will happen via the `_fullRequestReader`).
|
// the worker-thread yet (which will happen via the `#fullReader`).
|
||||||
if (!rangeReader) {
|
if (!rangeReader) {
|
||||||
sink.close();
|
sink.close();
|
||||||
return;
|
return;
|
||||||
@ -2950,7 +2949,7 @@ class WorkerTransport {
|
|||||||
isPureXfa: !!this._htmlForXfa,
|
isPureXfa: !!this._htmlForXfa,
|
||||||
numPages: this._numPages,
|
numPages: this._numPages,
|
||||||
annotationStorage: map,
|
annotationStorage: map,
|
||||||
filename: this._fullReader?.filename ?? null,
|
filename: this.#fullReader?.filename ?? null,
|
||||||
},
|
},
|
||||||
transfer
|
transfer
|
||||||
)
|
)
|
||||||
@ -3118,8 +3117,8 @@ class WorkerTransport {
|
|||||||
.then(results => ({
|
.then(results => ({
|
||||||
info: results[0],
|
info: results[0],
|
||||||
metadata: results[1] ? new Metadata(results[1]) : null,
|
metadata: results[1] ? new Metadata(results[1]) : null,
|
||||||
contentDispositionFilename: this._fullReader?.filename ?? null,
|
contentDispositionFilename: this.#fullReader?.filename ?? null,
|
||||||
contentLength: this._fullReader?.contentLength ?? null,
|
contentLength: this.#fullReader?.contentLength ?? null,
|
||||||
hasStructTree: results[2],
|
hasStructTree: results[2],
|
||||||
}));
|
}));
|
||||||
this.#methodPromises.set(name, promise);
|
this.#methodPromises.set(name, promise);
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AbortException, assert, warn } from "../shared/util.js";
|
import { AbortException, warn } from "../shared/util.js";
|
||||||
import {
|
import {
|
||||||
createHeaders,
|
createHeaders,
|
||||||
createResponseError,
|
createResponseError,
|
||||||
@ -22,6 +22,7 @@ import {
|
|||||||
validateRangeRequestCapabilities,
|
validateRangeRequestCapabilities,
|
||||||
validateResponseStatus,
|
validateResponseStatus,
|
||||||
} from "./network_utils.js";
|
} from "./network_utils.js";
|
||||||
|
import { BasePDFStream } from "../shared/base_pdf_stream.js";
|
||||||
|
|
||||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
|
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -51,47 +52,13 @@ function getArrayBuffer(val) {
|
|||||||
return new Uint8Array(val).buffer;
|
return new Uint8Array(val).buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @implements {IPDFStream} */
|
class PDFFetchStream extends BasePDFStream {
|
||||||
class PDFFetchStream {
|
|
||||||
_responseOrigin = null;
|
_responseOrigin = null;
|
||||||
|
|
||||||
constructor(source) {
|
constructor(source) {
|
||||||
this.source = source;
|
super(source, PDFFetchStreamReader, PDFFetchStreamRangeReader);
|
||||||
this.isHttp = /^https?:/i.test(source.url);
|
this.isHttp = /^https?:/i.test(source.url);
|
||||||
this.headers = createHeaders(this.isHttp, source.httpHeaders);
|
this.headers = createHeaders(this.isHttp, source.httpHeaders);
|
||||||
|
|
||||||
this._fullRequestReader = null;
|
|
||||||
this._rangeRequestReaders = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
get _progressiveDataLength() {
|
|
||||||
return this._fullRequestReader?._loaded ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFullReader() {
|
|
||||||
assert(
|
|
||||||
!this._fullRequestReader,
|
|
||||||
"PDFFetchStream.getFullReader can only be called once."
|
|
||||||
);
|
|
||||||
this._fullRequestReader = new PDFFetchStreamReader(this);
|
|
||||||
return this._fullRequestReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRangeReader(begin, end) {
|
|
||||||
if (end <= this._progressiveDataLength) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const reader = new PDFFetchStreamRangeReader(this, begin, end);
|
|
||||||
this._rangeRequestReaders.push(reader);
|
|
||||||
return reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelAllRequests(reason) {
|
|
||||||
this._fullRequestReader?.cancel(reason);
|
|
||||||
|
|
||||||
for (const reader of this._rangeRequestReaders.slice(0)) {
|
|
||||||
reader.cancel(reason);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +69,7 @@ class PDFFetchStreamReader {
|
|||||||
this._reader = null;
|
this._reader = null;
|
||||||
this._loaded = 0;
|
this._loaded = 0;
|
||||||
this._filename = null;
|
this._filename = null;
|
||||||
const source = stream.source;
|
const source = stream._source;
|
||||||
this._withCredentials = source.withCredentials || false;
|
this._withCredentials = source.withCredentials || false;
|
||||||
this._contentLength = source.length;
|
this._contentLength = source.length;
|
||||||
this._headersCapability = Promise.withResolvers();
|
this._headersCapability = Promise.withResolvers();
|
||||||
@ -205,7 +172,7 @@ class PDFFetchStreamRangeReader {
|
|||||||
constructor(stream, begin, end) {
|
constructor(stream, begin, end) {
|
||||||
this._stream = stream;
|
this._stream = stream;
|
||||||
this._reader = null;
|
this._reader = null;
|
||||||
const source = stream.source;
|
const source = stream._source;
|
||||||
this._withCredentials = source.withCredentials || false;
|
this._withCredentials = source.withCredentials || false;
|
||||||
this._readCapability = Promise.withResolvers();
|
this._readCapability = Promise.withResolvers();
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import {
|
|||||||
getResponseOrigin,
|
getResponseOrigin,
|
||||||
validateRangeRequestCapabilities,
|
validateRangeRequestCapabilities,
|
||||||
} from "./network_utils.js";
|
} from "./network_utils.js";
|
||||||
|
import { BasePDFStream } from "../shared/base_pdf_stream.js";
|
||||||
|
|
||||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
|
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -35,18 +36,13 @@ function getArrayBuffer(val) {
|
|||||||
return typeof val !== "string" ? val : stringToBytes(val).buffer;
|
return typeof val !== "string" ? val : stringToBytes(val).buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @implements {IPDFStream} */
|
class PDFNetworkStream extends BasePDFStream {
|
||||||
class PDFNetworkStream {
|
|
||||||
#pendingRequests = new WeakMap();
|
#pendingRequests = new WeakMap();
|
||||||
|
|
||||||
_fullRequestReader = null;
|
|
||||||
|
|
||||||
_rangeRequestReaders = [];
|
|
||||||
|
|
||||||
_responseOrigin = null;
|
_responseOrigin = null;
|
||||||
|
|
||||||
constructor(source) {
|
constructor(source) {
|
||||||
this._source = source;
|
super(source, PDFNetworkStreamFullReader, PDFNetworkStreamRangeReader);
|
||||||
this.url = source.url;
|
this.url = source.url;
|
||||||
this.isHttp = /^https?:/i.test(this.url);
|
this.isHttp = /^https?:/i.test(this.url);
|
||||||
this.headers = createHeaders(this.isHttp, source.httpHeaders);
|
this.headers = createHeaders(this.isHttp, source.httpHeaders);
|
||||||
@ -160,38 +156,18 @@ class PDFNetworkStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getFullReader() {
|
|
||||||
assert(
|
|
||||||
!this._fullRequestReader,
|
|
||||||
"PDFNetworkStream.getFullReader can only be called once."
|
|
||||||
);
|
|
||||||
this._fullRequestReader = new PDFNetworkStreamFullRequestReader(this);
|
|
||||||
return this._fullRequestReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRangeReader(begin, end) {
|
getRangeReader(begin, end) {
|
||||||
const reader = new PDFNetworkStreamRangeRequestReader(this, begin, end);
|
const reader = super.getRangeReader(begin, end);
|
||||||
reader.onClosed = () => {
|
|
||||||
const i = this._rangeRequestReaders.indexOf(reader);
|
|
||||||
if (i >= 0) {
|
|
||||||
this._rangeRequestReaders.splice(i, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this._rangeRequestReaders.push(reader);
|
|
||||||
return reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelAllRequests(reason) {
|
if (reader) {
|
||||||
this._fullRequestReader?.cancel(reason);
|
reader.onClosed = () => this._rangeReaders.delete(reader);
|
||||||
|
|
||||||
for (const reader of this._rangeRequestReaders.slice(0)) {
|
|
||||||
reader.cancel(reason);
|
|
||||||
}
|
}
|
||||||
|
return reader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @implements {IPDFStreamReader} */
|
/** @implements {IPDFStreamReader} */
|
||||||
class PDFNetworkStreamFullRequestReader {
|
class PDFNetworkStreamFullReader {
|
||||||
constructor(stream) {
|
constructor(stream) {
|
||||||
this._stream = stream;
|
this._stream = stream;
|
||||||
const { disableRange, length, rangeChunkSize } = stream._source;
|
const { disableRange, length, rangeChunkSize } = stream._source;
|
||||||
@ -355,7 +331,7 @@ class PDFNetworkStreamFullRequestReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @implements {IPDFStreamRangeReader} */
|
/** @implements {IPDFStreamRangeReader} */
|
||||||
class PDFNetworkStreamRangeRequestReader {
|
class PDFNetworkStreamRangeReader {
|
||||||
onClosed = null;
|
onClosed = null;
|
||||||
|
|
||||||
constructor(stream, begin, end) {
|
constructor(stream, begin, end) {
|
||||||
@ -398,7 +374,7 @@ class PDFNetworkStreamRangeRequestReader {
|
|||||||
requestCapability.resolve({ value: undefined, done: true });
|
requestCapability.resolve({ value: undefined, done: true });
|
||||||
}
|
}
|
||||||
this._requests.length = 0;
|
this._requests.length = 0;
|
||||||
this.onClosed?.(this);
|
this.onClosed?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onError(status) {
|
_onError(status) {
|
||||||
@ -435,7 +411,7 @@ class PDFNetworkStreamRangeRequestReader {
|
|||||||
this._requests.length = 0;
|
this._requests.length = 0;
|
||||||
|
|
||||||
this._stream._abortRequest(this._requestXhr);
|
this._stream._abortRequest(this._requestXhr);
|
||||||
this.onClosed?.(this);
|
this.onClosed?.();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
/* globals process */
|
/* globals process */
|
||||||
|
|
||||||
import { AbortException, assert, warn } from "../shared/util.js";
|
import { AbortException, assert, warn } from "../shared/util.js";
|
||||||
|
import { BasePDFStream } from "../shared/base_pdf_stream.js";
|
||||||
import { createResponseError } from "./network_utils.js";
|
import { createResponseError } from "./network_utils.js";
|
||||||
|
|
||||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
|
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
|
||||||
@ -60,47 +61,14 @@ function getArrayBuffer(val) {
|
|||||||
return new Uint8Array(val).buffer;
|
return new Uint8Array(val).buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
class PDFNodeStream {
|
class PDFNodeStream extends BasePDFStream {
|
||||||
constructor(source) {
|
constructor(source) {
|
||||||
this.source = source;
|
super(source, PDFNodeStreamFsFullReader, PDFNodeStreamFsRangeReader);
|
||||||
this.url = parseUrlOrPath(source.url);
|
this.url = parseUrlOrPath(source.url);
|
||||||
assert(
|
assert(
|
||||||
this.url.protocol === "file:",
|
this.url.protocol === "file:",
|
||||||
"PDFNodeStream only supports file:// URLs."
|
"PDFNodeStream only supports file:// URLs."
|
||||||
);
|
);
|
||||||
|
|
||||||
this._fullRequestReader = null;
|
|
||||||
this._rangeRequestReaders = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
get _progressiveDataLength() {
|
|
||||||
return this._fullRequestReader?._loaded ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFullReader() {
|
|
||||||
assert(
|
|
||||||
!this._fullRequestReader,
|
|
||||||
"PDFNodeStream.getFullReader can only be called once."
|
|
||||||
);
|
|
||||||
this._fullRequestReader = new PDFNodeStreamFsFullReader(this);
|
|
||||||
return this._fullRequestReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRangeReader(begin, end) {
|
|
||||||
if (end <= this._progressiveDataLength) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const rangeReader = new PDFNodeStreamFsRangeReader(this, begin, end);
|
|
||||||
this._rangeRequestReaders.push(rangeReader);
|
|
||||||
return rangeReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelAllRequests(reason) {
|
|
||||||
this._fullRequestReader?.cancel(reason);
|
|
||||||
|
|
||||||
for (const reader of this._rangeRequestReaders.slice(0)) {
|
|
||||||
reader.cancel(reason);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +79,7 @@ class PDFNodeStreamFsFullReader {
|
|||||||
|
|
||||||
constructor(stream) {
|
constructor(stream) {
|
||||||
this.onProgress = null;
|
this.onProgress = null;
|
||||||
const source = stream.source;
|
const source = stream._source;
|
||||||
this._contentLength = source.length; // optional
|
this._contentLength = source.length; // optional
|
||||||
this._loaded = 0;
|
this._loaded = 0;
|
||||||
this._filename = null;
|
this._filename = null;
|
||||||
|
|||||||
@ -13,39 +13,42 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @typedef {import("../interfaces").IPDFStream} IPDFStream */
|
|
||||||
/** @typedef {import("../interfaces").IPDFStreamReader} IPDFStreamReader */
|
/** @typedef {import("../interfaces").IPDFStreamReader} IPDFStreamReader */
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
/** @typedef {import("../interfaces").IPDFStreamRangeReader} IPDFStreamRangeReader */
|
/** @typedef {import("../interfaces").IPDFStreamRangeReader} IPDFStreamRangeReader */
|
||||||
|
|
||||||
import { assert } from "../shared/util.js";
|
import { assert } from "../shared/util.js";
|
||||||
|
import { BasePDFStream } from "../shared/base_pdf_stream.js";
|
||||||
import { isPdfFile } from "./display_utils.js";
|
import { isPdfFile } from "./display_utils.js";
|
||||||
|
|
||||||
/** @implements {IPDFStream} */
|
function getArrayBuffer(val) {
|
||||||
class PDFDataTransportStream {
|
// Prevent any possible issues by only transferring a Uint8Array that
|
||||||
constructor(
|
// completely "utilizes" its underlying ArrayBuffer.
|
||||||
pdfDataRangeTransport,
|
return val instanceof Uint8Array && val.byteLength === val.buffer.byteLength
|
||||||
{ disableRange = false, disableStream = false }
|
? val.buffer
|
||||||
) {
|
: new Uint8Array(val).buffer;
|
||||||
assert(
|
}
|
||||||
pdfDataRangeTransport,
|
|
||||||
'PDFDataTransportStream - missing required "pdfDataRangeTransport" argument.'
|
class PDFDataTransportStream extends BasePDFStream {
|
||||||
|
_pdfDataRangeTransport = null;
|
||||||
|
|
||||||
|
_queuedChunks = [];
|
||||||
|
|
||||||
|
constructor(source) {
|
||||||
|
super(
|
||||||
|
source,
|
||||||
|
PDFDataTransportStreamReader,
|
||||||
|
PDFDataTransportStreamRangeReader
|
||||||
);
|
);
|
||||||
|
const { pdfDataRangeTransport, disableRange, disableStream } = source;
|
||||||
const { length, initialData, progressiveDone, contentDispositionFilename } =
|
const { length, initialData, progressiveDone, contentDispositionFilename } =
|
||||||
pdfDataRangeTransport;
|
pdfDataRangeTransport;
|
||||||
|
|
||||||
this._queuedChunks = [];
|
|
||||||
this._progressiveDone = progressiveDone;
|
this._progressiveDone = progressiveDone;
|
||||||
this._contentDispositionFilename = contentDispositionFilename;
|
this._contentDispositionFilename = contentDispositionFilename;
|
||||||
|
|
||||||
if (initialData?.length > 0) {
|
if (initialData?.length > 0) {
|
||||||
// Prevent any possible issues by only transferring a Uint8Array that
|
const buffer = getArrayBuffer(initialData);
|
||||||
// completely "utilizes" its underlying ArrayBuffer.
|
|
||||||
const buffer =
|
|
||||||
initialData instanceof Uint8Array &&
|
|
||||||
initialData.byteLength === initialData.buffer.byteLength
|
|
||||||
? initialData.buffer
|
|
||||||
: new Uint8Array(initialData).buffer;
|
|
||||||
this._queuedChunks.push(buffer);
|
this._queuedChunks.push(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,139 +57,89 @@ class PDFDataTransportStream {
|
|||||||
this._isRangeSupported = !disableRange;
|
this._isRangeSupported = !disableRange;
|
||||||
this._contentLength = length;
|
this._contentLength = length;
|
||||||
|
|
||||||
this._fullRequestReader = null;
|
|
||||||
this._rangeReaders = [];
|
|
||||||
|
|
||||||
pdfDataRangeTransport.addRangeListener((begin, chunk) => {
|
pdfDataRangeTransport.addRangeListener((begin, chunk) => {
|
||||||
this._onReceiveData({ begin, chunk });
|
this.#onReceiveData(begin, chunk);
|
||||||
});
|
});
|
||||||
|
|
||||||
pdfDataRangeTransport.addProgressListener((loaded, total) => {
|
pdfDataRangeTransport.addProgressListener((loaded, total) => {
|
||||||
this._onProgress({ loaded, total });
|
if (total !== undefined) {
|
||||||
|
this._fullReader?.onProgress?.({ loaded, total });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pdfDataRangeTransport.addProgressiveReadListener(chunk => {
|
pdfDataRangeTransport.addProgressiveReadListener(chunk => {
|
||||||
this._onReceiveData({ chunk });
|
this.#onReceiveData(/* begin = */ undefined, chunk);
|
||||||
});
|
});
|
||||||
|
|
||||||
pdfDataRangeTransport.addProgressiveDoneListener(() => {
|
pdfDataRangeTransport.addProgressiveDoneListener(() => {
|
||||||
this._onProgressiveDone();
|
this._fullReader?.progressiveDone();
|
||||||
|
this._progressiveDone = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
pdfDataRangeTransport.transportReady();
|
pdfDataRangeTransport.transportReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onReceiveData({ begin, chunk }) {
|
#onReceiveData(begin, chunk) {
|
||||||
// Prevent any possible issues by only transferring a Uint8Array that
|
const buffer = getArrayBuffer(chunk);
|
||||||
// completely "utilizes" its underlying ArrayBuffer.
|
|
||||||
const buffer =
|
|
||||||
chunk instanceof Uint8Array &&
|
|
||||||
chunk.byteLength === chunk.buffer.byteLength
|
|
||||||
? chunk.buffer
|
|
||||||
: new Uint8Array(chunk).buffer;
|
|
||||||
|
|
||||||
if (begin === undefined) {
|
if (begin === undefined) {
|
||||||
if (this._fullRequestReader) {
|
if (this._fullReader) {
|
||||||
this._fullRequestReader._enqueue(buffer);
|
this._fullReader._enqueue(buffer);
|
||||||
} else {
|
} else {
|
||||||
this._queuedChunks.push(buffer);
|
this._queuedChunks.push(buffer);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const found = this._rangeReaders.some(function (rangeReader) {
|
const rangeReader = this._rangeReaders
|
||||||
if (rangeReader._begin !== begin) {
|
.keys()
|
||||||
return false;
|
.find(r => r._begin === begin);
|
||||||
}
|
|
||||||
rangeReader._enqueue(buffer);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
assert(
|
assert(
|
||||||
found,
|
rangeReader,
|
||||||
"_onReceiveData - no `PDFDataTransportStreamRangeReader` instance found."
|
"#onReceiveData - no `PDFDataTransportStreamRangeReader` instance found."
|
||||||
);
|
);
|
||||||
}
|
rangeReader._enqueue(buffer);
|
||||||
}
|
|
||||||
|
|
||||||
get _progressiveDataLength() {
|
|
||||||
return this._fullRequestReader?._loaded ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_onProgress(evt) {
|
|
||||||
if (evt.total !== undefined) {
|
|
||||||
this._fullRequestReader?.onProgress?.({
|
|
||||||
loaded: evt.loaded,
|
|
||||||
total: evt.total,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_onProgressiveDone() {
|
|
||||||
this._fullRequestReader?.progressiveDone();
|
|
||||||
this._progressiveDone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_removeRangeReader(reader) {
|
|
||||||
const i = this._rangeReaders.indexOf(reader);
|
|
||||||
if (i >= 0) {
|
|
||||||
this._rangeReaders.splice(i, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getFullReader() {
|
getFullReader() {
|
||||||
assert(
|
const reader = super.getFullReader();
|
||||||
!this._fullRequestReader,
|
|
||||||
"PDFDataTransportStream.getFullReader can only be called once."
|
|
||||||
);
|
|
||||||
const queuedChunks = this._queuedChunks;
|
|
||||||
this._queuedChunks = null;
|
this._queuedChunks = null;
|
||||||
return new PDFDataTransportStreamReader(
|
return reader;
|
||||||
this,
|
|
||||||
queuedChunks,
|
|
||||||
this._progressiveDone,
|
|
||||||
this._contentDispositionFilename
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRangeReader(begin, end) {
|
getRangeReader(begin, end) {
|
||||||
if (end <= this._progressiveDataLength) {
|
const reader = super.getRangeReader(begin, end);
|
||||||
return null;
|
|
||||||
|
if (reader) {
|
||||||
|
reader.onDone = () => this._rangeReaders.delete(reader);
|
||||||
|
|
||||||
|
this._pdfDataRangeTransport.requestDataRange(begin, end);
|
||||||
}
|
}
|
||||||
const reader = new PDFDataTransportStreamRangeReader(this, begin, end);
|
|
||||||
this._pdfDataRangeTransport.requestDataRange(begin, end);
|
|
||||||
this._rangeReaders.push(reader);
|
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelAllRequests(reason) {
|
cancelAllRequests(reason) {
|
||||||
this._fullRequestReader?.cancel(reason);
|
super.cancelAllRequests(reason);
|
||||||
|
|
||||||
for (const reader of this._rangeReaders.slice(0)) {
|
|
||||||
reader.cancel(reason);
|
|
||||||
}
|
|
||||||
this._pdfDataRangeTransport.abort();
|
this._pdfDataRangeTransport.abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @implements {IPDFStreamReader} */
|
/** @implements {IPDFStreamReader} */
|
||||||
class PDFDataTransportStreamReader {
|
class PDFDataTransportStreamReader {
|
||||||
constructor(
|
constructor(stream) {
|
||||||
stream,
|
|
||||||
queuedChunks,
|
|
||||||
progressiveDone = false,
|
|
||||||
contentDispositionFilename = null
|
|
||||||
) {
|
|
||||||
this._stream = stream;
|
this._stream = stream;
|
||||||
this._done = progressiveDone || false;
|
this._done = stream._progressiveDone || false;
|
||||||
this._filename = isPdfFile(contentDispositionFilename)
|
this._filename = isPdfFile(stream._contentDispositionFilename)
|
||||||
? contentDispositionFilename
|
? stream._contentDispositionFilename
|
||||||
: null;
|
: null;
|
||||||
this._queuedChunks = queuedChunks || [];
|
this._queuedChunks = stream._queuedChunks || [];
|
||||||
this._loaded = 0;
|
this._loaded = 0;
|
||||||
for (const chunk of this._queuedChunks) {
|
for (const chunk of this._queuedChunks) {
|
||||||
this._loaded += chunk.byteLength;
|
this._loaded += chunk.byteLength;
|
||||||
}
|
}
|
||||||
this._requests = [];
|
this._requests = [];
|
||||||
this._headersReady = Promise.resolve();
|
this._headersReady = Promise.resolve();
|
||||||
stream._fullRequestReader = this;
|
|
||||||
|
|
||||||
this.onProgress = null;
|
this.onProgress = null;
|
||||||
}
|
}
|
||||||
@ -255,6 +208,8 @@ class PDFDataTransportStreamReader {
|
|||||||
|
|
||||||
/** @implements {IPDFStreamRangeReader} */
|
/** @implements {IPDFStreamRangeReader} */
|
||||||
class PDFDataTransportStreamRangeReader {
|
class PDFDataTransportStreamRangeReader {
|
||||||
|
onDone = null;
|
||||||
|
|
||||||
constructor(stream, begin, end) {
|
constructor(stream, begin, end) {
|
||||||
this._stream = stream;
|
this._stream = stream;
|
||||||
this._begin = begin;
|
this._begin = begin;
|
||||||
@ -279,7 +234,7 @@ class PDFDataTransportStreamRangeReader {
|
|||||||
this._requests.length = 0;
|
this._requests.length = 0;
|
||||||
}
|
}
|
||||||
this._done = true;
|
this._done = true;
|
||||||
this._stream._removeRangeReader(this);
|
this.onDone?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
async read() {
|
async read() {
|
||||||
@ -302,7 +257,7 @@ class PDFDataTransportStreamRangeReader {
|
|||||||
requestCapability.resolve({ value: undefined, done: true });
|
requestCapability.resolve({ value: undefined, done: true });
|
||||||
}
|
}
|
||||||
this._requests.length = 0;
|
this._requests.length = 0;
|
||||||
this._stream._removeRangeReader(this);
|
this.onDone?.();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,40 +13,83 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { assert, unreachable } from "./util.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that represents PDF data transport. If possible, it allows
|
* Interface that represents PDF data transport. If possible, it allows
|
||||||
* progressively load entire or fragment of the PDF binary data.
|
* progressively load entire or fragment of the PDF binary data.
|
||||||
*
|
|
||||||
* @interface
|
|
||||||
*/
|
*/
|
||||||
class IPDFStream {
|
class BasePDFStream {
|
||||||
|
#PDFStreamReader = null;
|
||||||
|
|
||||||
|
#PDFStreamRangeReader = null;
|
||||||
|
|
||||||
|
_fullReader = null;
|
||||||
|
|
||||||
|
_rangeReaders = new Set();
|
||||||
|
|
||||||
|
_source = null;
|
||||||
|
|
||||||
|
constructor(source, PDFStreamReader, PDFStreamRangeReader) {
|
||||||
|
if (
|
||||||
|
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
|
||||||
|
this.constructor === BasePDFStream
|
||||||
|
) {
|
||||||
|
unreachable("Cannot initialize BasePDFStream.");
|
||||||
|
}
|
||||||
|
this._source = source;
|
||||||
|
|
||||||
|
this.#PDFStreamReader = PDFStreamReader;
|
||||||
|
this.#PDFStreamRangeReader = PDFStreamRangeReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
get _progressiveDataLength() {
|
||||||
|
return this._fullReader?._loaded ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a reader for the entire PDF data.
|
* Gets a reader for the entire PDF data.
|
||||||
* @returns {IPDFStreamReader}
|
* @returns {BasePDFStreamReader}
|
||||||
*/
|
*/
|
||||||
getFullReader() {
|
getFullReader() {
|
||||||
return null;
|
assert(
|
||||||
|
!this._fullReader,
|
||||||
|
"BasePDFStream.getFullReader can only be called once."
|
||||||
|
);
|
||||||
|
return (this._fullReader = new this.#PDFStreamReader(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a reader for the range of the PDF data.
|
* Gets a reader for the range of the PDF data.
|
||||||
*
|
*
|
||||||
* NOTE: Currently this method is only expected to be invoked *after*
|
* NOTE: Currently this method is only expected to be invoked *after*
|
||||||
* the `IPDFStreamReader.prototype.headersReady` promise has resolved.
|
* the `BasePDFStreamReader.prototype.headersReady` promise has resolved.
|
||||||
*
|
*
|
||||||
* @param {number} begin - the start offset of the data.
|
* @param {number} begin - the start offset of the data.
|
||||||
* @param {number} end - the end offset of the data.
|
* @param {number} end - the end offset of the data.
|
||||||
* @returns {IPDFStreamRangeReader}
|
* @returns {BasePDFStreamRangeReader}
|
||||||
*/
|
*/
|
||||||
getRangeReader(begin, end) {
|
getRangeReader(begin, end) {
|
||||||
return null;
|
if (end <= this._progressiveDataLength) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const reader = new this.#PDFStreamRangeReader(this, begin, end);
|
||||||
|
this._rangeReaders.add(reader);
|
||||||
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels all opened reader and closes all their opened requests.
|
* Cancels all opened reader and closes all their opened requests.
|
||||||
* @param {Object} reason - the reason for cancelling
|
* @param {Object} reason - the reason for cancelling
|
||||||
*/
|
*/
|
||||||
cancelAllRequests(reason) {}
|
cancelAllRequests(reason) {
|
||||||
|
this._fullReader?.cancel(reason);
|
||||||
|
|
||||||
|
// Always create a copy of the rangeReaders.
|
||||||
|
for (const reader of new Set(this._rangeReaders)) {
|
||||||
|
reader.cancel(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -152,4 +195,4 @@ class IPDFStreamRangeReader {
|
|||||||
cancel(reason) {}
|
cancel(reason) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { IPDFStream, IPDFStreamRangeReader, IPDFStreamReader };
|
export { BasePDFStream, IPDFStreamRangeReader, IPDFStreamReader };
|
||||||
@ -16,8 +16,7 @@
|
|||||||
import { AbortException, isNodeJS } from "../../src/shared/util.js";
|
import { AbortException, isNodeJS } from "../../src/shared/util.js";
|
||||||
import { getCrossOriginHostname, TestPdfsServer } from "./test_utils.js";
|
import { getCrossOriginHostname, TestPdfsServer } from "./test_utils.js";
|
||||||
|
|
||||||
// Common tests to verify behavior across implementations of the IPDFStream
|
// Common tests to verify behavior across `BasePDFStream` implementations:
|
||||||
// interface:
|
|
||||||
// - PDFNetworkStream by network_spec.js
|
// - PDFNetworkStream by network_spec.js
|
||||||
// - PDFFetchStream by fetch_stream_spec.js
|
// - PDFFetchStream by fetch_stream_spec.js
|
||||||
async function testCrossOriginRedirects({
|
async function testCrossOriginRedirects({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user