Refactors PDFPageView_draw.
This commit is contained in:
parent
f6a8d9c4dd
commit
c9a0955c9c
@ -93,9 +93,11 @@ var PDFPageView = (function PDFPageViewClosure() {
|
|||||||
this.textLayerFactory = textLayerFactory;
|
this.textLayerFactory = textLayerFactory;
|
||||||
this.annotationLayerFactory = annotationLayerFactory;
|
this.annotationLayerFactory = annotationLayerFactory;
|
||||||
|
|
||||||
this.renderTask = null;
|
this.paintTask = null;
|
||||||
|
this.paintedViewport = null;
|
||||||
this.renderingState = RenderingStates.INITIAL;
|
this.renderingState = RenderingStates.INITIAL;
|
||||||
this.resume = null;
|
this.resume = null;
|
||||||
|
this.error = null;
|
||||||
|
|
||||||
this.onBeforeDraw = null;
|
this.onBeforeDraw = null;
|
||||||
this.onAfterDraw = null;
|
this.onAfterDraw = null;
|
||||||
@ -171,6 +173,9 @@ var PDFPageView = (function PDFPageViewClosure() {
|
|||||||
this.canvas.height = 0;
|
this.canvas.height = 0;
|
||||||
delete this.canvas;
|
delete this.canvas;
|
||||||
}
|
}
|
||||||
|
if (!currentZoomLayerNode) {
|
||||||
|
this.paintedViewport = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.loadingIconDiv = document.createElement('div');
|
this.loadingIconDiv = document.createElement('div');
|
||||||
this.loadingIconDiv.className = 'loadingIcon';
|
this.loadingIconDiv.className = 'loadingIcon';
|
||||||
@ -224,9 +229,9 @@ var PDFPageView = (function PDFPageViewClosure() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
cancelRendering: function PDFPageView_cancelRendering() {
|
cancelRendering: function PDFPageView_cancelRendering() {
|
||||||
if (this.renderTask) {
|
if (this.paintTask) {
|
||||||
this.renderTask.cancel();
|
this.paintTask.cancel();
|
||||||
this.renderTask = null;
|
this.paintTask = null;
|
||||||
}
|
}
|
||||||
this.renderingState = RenderingStates.INITIAL;
|
this.renderingState = RenderingStates.INITIAL;
|
||||||
this.resume = null;
|
this.resume = null;
|
||||||
@ -258,7 +263,8 @@ var PDFPageView = (function PDFPageViewClosure() {
|
|||||||
canvas.style.height = canvas.parentNode.style.height = div.style.height =
|
canvas.style.height = canvas.parentNode.style.height = div.style.height =
|
||||||
Math.floor(height) + 'px';
|
Math.floor(height) + 'px';
|
||||||
// The canvas may have been originally rotated, rotate relative to that.
|
// The canvas may have been originally rotated, rotate relative to that.
|
||||||
var relativeRotation = this.viewport.rotation - canvas._viewport.rotation;
|
var relativeRotation = this.viewport.rotation -
|
||||||
|
this.paintedViewport.rotation;
|
||||||
var absRotation = Math.abs(relativeRotation);
|
var absRotation = Math.abs(relativeRotation);
|
||||||
var scaleX = 1, scaleY = 1;
|
var scaleX = 1, scaleY = 1;
|
||||||
if (absRotation === 90 || absRotation === 270) {
|
if (absRotation === 90 || absRotation === 270) {
|
||||||
@ -337,6 +343,7 @@ var PDFPageView = (function PDFPageViewClosure() {
|
|||||||
|
|
||||||
this.renderingState = RenderingStates.RUNNING;
|
this.renderingState = RenderingStates.RUNNING;
|
||||||
|
|
||||||
|
var self = this;
|
||||||
var pdfPage = this.pdfPage;
|
var pdfPage = this.pdfPage;
|
||||||
var viewport = this.viewport;
|
var viewport = this.viewport;
|
||||||
var div = this.div;
|
var div = this.div;
|
||||||
@ -347,20 +354,165 @@ var PDFPageView = (function PDFPageViewClosure() {
|
|||||||
canvasWrapper.style.height = div.style.height;
|
canvasWrapper.style.height = div.style.height;
|
||||||
canvasWrapper.classList.add('canvasWrapper');
|
canvasWrapper.classList.add('canvasWrapper');
|
||||||
|
|
||||||
var canvas = document.createElement('canvas');
|
|
||||||
canvas.id = 'page' + this.id;
|
|
||||||
// Keep the canvas hidden until the first draw callback, or until drawing
|
|
||||||
// is complete when `!this.renderingQueue`, to prevent black flickering.
|
|
||||||
canvas.setAttribute('hidden', 'hidden');
|
|
||||||
var isCanvasHidden = true;
|
|
||||||
|
|
||||||
canvasWrapper.appendChild(canvas);
|
|
||||||
if (this.annotationLayer && this.annotationLayer.div) {
|
if (this.annotationLayer && this.annotationLayer.div) {
|
||||||
// annotationLayer needs to stay on top
|
// annotationLayer needs to stay on top
|
||||||
div.insertBefore(canvasWrapper, this.annotationLayer.div);
|
div.insertBefore(canvasWrapper, this.annotationLayer.div);
|
||||||
} else {
|
} else {
|
||||||
div.appendChild(canvasWrapper);
|
div.appendChild(canvasWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var textLayerDiv = null;
|
||||||
|
var textLayer = null;
|
||||||
|
if (this.textLayerFactory) {
|
||||||
|
textLayerDiv = document.createElement('div');
|
||||||
|
textLayerDiv.className = 'textLayer';
|
||||||
|
textLayerDiv.style.width = canvasWrapper.style.width;
|
||||||
|
textLayerDiv.style.height = canvasWrapper.style.height;
|
||||||
|
if (this.annotationLayer && this.annotationLayer.div) {
|
||||||
|
// annotationLayer needs to stay on top
|
||||||
|
div.insertBefore(textLayerDiv, this.annotationLayer.div);
|
||||||
|
} else {
|
||||||
|
div.appendChild(textLayerDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
textLayer = this.textLayerFactory.
|
||||||
|
createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport,
|
||||||
|
this.enhanceTextSelection);
|
||||||
|
}
|
||||||
|
this.textLayer = textLayer;
|
||||||
|
|
||||||
|
var renderContinueCallback = null;
|
||||||
|
if (this.renderingQueue) {
|
||||||
|
renderContinueCallback = function renderContinueCallback(cont) {
|
||||||
|
if (!self.renderingQueue.isHighestPriority(self)) {
|
||||||
|
self.renderingState = RenderingStates.PAUSED;
|
||||||
|
self.resume = function resumeCallback() {
|
||||||
|
self.renderingState = RenderingStates.RUNNING;
|
||||||
|
cont();
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cont();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var finishPaintTask = function finishPaintTask(error) {
|
||||||
|
// The paintTask may have been replaced by a new one, so only remove
|
||||||
|
// the reference to the paintTask if it matches the one that is
|
||||||
|
// triggering this callback.
|
||||||
|
if (paintTask === self.paintTask) {
|
||||||
|
self.paintTask = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error === 'cancelled') {
|
||||||
|
self.error = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.renderingState = RenderingStates.FINISHED;
|
||||||
|
|
||||||
|
if (self.loadingIconDiv) {
|
||||||
|
div.removeChild(self.loadingIconDiv);
|
||||||
|
delete self.loadingIconDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.zoomLayer) {
|
||||||
|
// Zeroing the width and height causes Firefox to release graphics
|
||||||
|
// resources immediately, which can greatly reduce memory consumption.
|
||||||
|
var zoomLayerCanvas = self.zoomLayer.firstChild;
|
||||||
|
zoomLayerCanvas.width = 0;
|
||||||
|
zoomLayerCanvas.height = 0;
|
||||||
|
|
||||||
|
if (div.contains(self.zoomLayer)) {
|
||||||
|
// Prevent "Node was not found" errors if the `zoomLayer` was
|
||||||
|
// already removed. This may occur intermittently if the scale
|
||||||
|
// changes many times in very quick succession.
|
||||||
|
div.removeChild(self.zoomLayer);
|
||||||
|
}
|
||||||
|
self.zoomLayer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.error = error;
|
||||||
|
self.stats = pdfPage.stats;
|
||||||
|
if (self.onAfterDraw) {
|
||||||
|
self.onAfterDraw();
|
||||||
|
}
|
||||||
|
self.eventBus.dispatch('pagerendered', {
|
||||||
|
source: self,
|
||||||
|
pageNumber: self.id,
|
||||||
|
cssTransform: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var paintTask = this.paintOnCanvas(canvasWrapper);
|
||||||
|
paintTask.onRenderContinue = renderContinueCallback;
|
||||||
|
this.paintTask = paintTask;
|
||||||
|
|
||||||
|
var resultPromise = paintTask.promise.then(function () {
|
||||||
|
finishPaintTask(null);
|
||||||
|
if (textLayer) {
|
||||||
|
pdfPage.getTextContent({
|
||||||
|
normalizeWhitespace: true,
|
||||||
|
}).then(function textContentResolved(textContent) {
|
||||||
|
textLayer.setTextContent(textContent);
|
||||||
|
textLayer.render(TEXT_LAYER_RENDER_DELAY);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, function (reason) {
|
||||||
|
finishPaintTask(reason);
|
||||||
|
throw reason;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.annotationLayerFactory) {
|
||||||
|
if (!this.annotationLayer) {
|
||||||
|
this.annotationLayer = this.annotationLayerFactory.
|
||||||
|
createAnnotationLayerBuilder(div, pdfPage,
|
||||||
|
this.renderInteractiveForms);
|
||||||
|
}
|
||||||
|
this.annotationLayer.render(this.viewport, 'display');
|
||||||
|
}
|
||||||
|
div.setAttribute('data-loaded', true);
|
||||||
|
|
||||||
|
if (this.onBeforeDraw) {
|
||||||
|
this.onBeforeDraw();
|
||||||
|
}
|
||||||
|
return resultPromise;
|
||||||
|
},
|
||||||
|
|
||||||
|
paintOnCanvas: function (canvasWrapper) {
|
||||||
|
var resolveRenderPromise, rejectRenderPromise;
|
||||||
|
var promise = new Promise(function (resolve, reject) {
|
||||||
|
resolveRenderPromise = resolve;
|
||||||
|
rejectRenderPromise = reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
var result = {
|
||||||
|
promise: promise,
|
||||||
|
onRenderContinue: function (cont) {
|
||||||
|
cont();
|
||||||
|
},
|
||||||
|
cancel: function () {
|
||||||
|
renderTask.cancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var pdfPage = this.pdfPage;
|
||||||
|
var viewport = this.viewport;
|
||||||
|
var canvas = document.createElement('canvas');
|
||||||
|
canvas.id = 'page' + this.id;
|
||||||
|
// Keep the canvas hidden until the first draw callback, or until drawing
|
||||||
|
// is complete when `!this.renderingQueue`, to prevent black flickering.
|
||||||
|
canvas.setAttribute('hidden', 'hidden');
|
||||||
|
var isCanvasHidden = true;
|
||||||
|
var showCanvas = function () {
|
||||||
|
if (isCanvasHidden) {
|
||||||
|
canvas.removeAttribute('hidden');
|
||||||
|
isCanvasHidden = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
canvasWrapper.appendChild(canvas);
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
|
|
||||||
if (typeof PDFJSDev === 'undefined' ||
|
if (typeof PDFJSDev === 'undefined' ||
|
||||||
@ -402,115 +554,9 @@ var PDFPageView = (function PDFPageViewClosure() {
|
|||||||
canvas.style.width = roundToDivide(viewport.width, sfx[1]) + 'px';
|
canvas.style.width = roundToDivide(viewport.width, sfx[1]) + 'px';
|
||||||
canvas.style.height = roundToDivide(viewport.height, sfy[1]) + 'px';
|
canvas.style.height = roundToDivide(viewport.height, sfy[1]) + 'px';
|
||||||
// Add the viewport so it's known what it was originally drawn with.
|
// Add the viewport so it's known what it was originally drawn with.
|
||||||
canvas._viewport = viewport;
|
this.paintedViewport = viewport;
|
||||||
|
|
||||||
var textLayerDiv = null;
|
|
||||||
var textLayer = null;
|
|
||||||
if (this.textLayerFactory) {
|
|
||||||
textLayerDiv = document.createElement('div');
|
|
||||||
textLayerDiv.className = 'textLayer';
|
|
||||||
textLayerDiv.style.width = canvasWrapper.style.width;
|
|
||||||
textLayerDiv.style.height = canvasWrapper.style.height;
|
|
||||||
if (this.annotationLayer && this.annotationLayer.div) {
|
|
||||||
// annotationLayer needs to stay on top
|
|
||||||
div.insertBefore(textLayerDiv, this.annotationLayer.div);
|
|
||||||
} else {
|
|
||||||
div.appendChild(textLayerDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
textLayer = this.textLayerFactory.
|
|
||||||
createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport,
|
|
||||||
this.enhanceTextSelection);
|
|
||||||
}
|
|
||||||
this.textLayer = textLayer;
|
|
||||||
|
|
||||||
var resolveRenderPromise, rejectRenderPromise;
|
|
||||||
var promise = new Promise(function (resolve, reject) {
|
|
||||||
resolveRenderPromise = resolve;
|
|
||||||
rejectRenderPromise = reject;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Rendering area
|
// Rendering area
|
||||||
|
|
||||||
var self = this;
|
|
||||||
function pageViewDrawCallback(error) {
|
|
||||||
// The renderTask may have been replaced by a new one, so only remove
|
|
||||||
// the reference to the renderTask if it matches the one that is
|
|
||||||
// triggering this callback.
|
|
||||||
if (renderTask === self.renderTask) {
|
|
||||||
self.renderTask = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error === 'cancelled') {
|
|
||||||
rejectRenderPromise(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.renderingState = RenderingStates.FINISHED;
|
|
||||||
|
|
||||||
if (isCanvasHidden) {
|
|
||||||
self.canvas.removeAttribute('hidden');
|
|
||||||
isCanvasHidden = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.loadingIconDiv) {
|
|
||||||
div.removeChild(self.loadingIconDiv);
|
|
||||||
delete self.loadingIconDiv;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.zoomLayer) {
|
|
||||||
// Zeroing the width and height causes Firefox to release graphics
|
|
||||||
// resources immediately, which can greatly reduce memory consumption.
|
|
||||||
var zoomLayerCanvas = self.zoomLayer.firstChild;
|
|
||||||
zoomLayerCanvas.width = 0;
|
|
||||||
zoomLayerCanvas.height = 0;
|
|
||||||
|
|
||||||
if (div.contains(self.zoomLayer)) {
|
|
||||||
// Prevent "Node was not found" errors if the `zoomLayer` was
|
|
||||||
// already removed. This may occur intermittently if the scale
|
|
||||||
// changes many times in very quick succession.
|
|
||||||
div.removeChild(self.zoomLayer);
|
|
||||||
}
|
|
||||||
self.zoomLayer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.error = error;
|
|
||||||
self.stats = pdfPage.stats;
|
|
||||||
if (self.onAfterDraw) {
|
|
||||||
self.onAfterDraw();
|
|
||||||
}
|
|
||||||
self.eventBus.dispatch('pagerendered', {
|
|
||||||
source: self,
|
|
||||||
pageNumber: self.id,
|
|
||||||
cssTransform: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
resolveRenderPromise(undefined);
|
|
||||||
} else {
|
|
||||||
rejectRenderPromise(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var renderContinueCallback = null;
|
|
||||||
if (this.renderingQueue) {
|
|
||||||
renderContinueCallback = function renderContinueCallback(cont) {
|
|
||||||
if (!self.renderingQueue.isHighestPriority(self)) {
|
|
||||||
self.renderingState = RenderingStates.PAUSED;
|
|
||||||
self.resume = function resumeCallback() {
|
|
||||||
self.renderingState = RenderingStates.RUNNING;
|
|
||||||
cont();
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isCanvasHidden) {
|
|
||||||
self.canvas.removeAttribute('hidden');
|
|
||||||
isCanvasHidden = false;
|
|
||||||
}
|
|
||||||
cont();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var transform = !outputScale.scaled ? null :
|
var transform = !outputScale.scaled ? null :
|
||||||
[outputScale.sx, 0, 0, outputScale.sy, 0, 0];
|
[outputScale.sx, 0, 0, outputScale.sy, 0, 0];
|
||||||
var renderContext = {
|
var renderContext = {
|
||||||
@ -520,40 +566,28 @@ var PDFPageView = (function PDFPageViewClosure() {
|
|||||||
renderInteractiveForms: this.renderInteractiveForms,
|
renderInteractiveForms: this.renderInteractiveForms,
|
||||||
// intent: 'default', // === 'display'
|
// intent: 'default', // === 'display'
|
||||||
};
|
};
|
||||||
var renderTask = this.renderTask = this.pdfPage.render(renderContext);
|
var renderTask = this.pdfPage.render(renderContext);
|
||||||
renderTask.onContinue = renderContinueCallback;
|
renderTask.onContinue = function (cont) {
|
||||||
|
showCanvas();
|
||||||
this.renderTask.promise.then(
|
if (result.onRenderContinue) {
|
||||||
function pdfPageRenderCallback() {
|
result.onRenderContinue(cont);
|
||||||
pageViewDrawCallback(null);
|
} else {
|
||||||
if (textLayer) {
|
cont();
|
||||||
self.pdfPage.getTextContent({
|
|
||||||
normalizeWhitespace: true,
|
|
||||||
}).then(function textContentResolved(textContent) {
|
|
||||||
textLayer.setTextContent(textContent);
|
|
||||||
textLayer.render(TEXT_LAYER_RENDER_DELAY);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderTask.promise.then(
|
||||||
|
function pdfPageRenderCallback() {
|
||||||
|
showCanvas();
|
||||||
|
resolveRenderPromise(undefined);
|
||||||
},
|
},
|
||||||
function pdfPageRenderError(error) {
|
function pdfPageRenderError(error) {
|
||||||
pageViewDrawCallback(error);
|
showCanvas();
|
||||||
|
rejectRenderPromise(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.annotationLayerFactory) {
|
return result;
|
||||||
if (!this.annotationLayer) {
|
|
||||||
this.annotationLayer = this.annotationLayerFactory.
|
|
||||||
createAnnotationLayerBuilder(div, this.pdfPage,
|
|
||||||
this.renderInteractiveForms);
|
|
||||||
}
|
|
||||||
this.annotationLayer.render(this.viewport, 'display');
|
|
||||||
}
|
|
||||||
div.setAttribute('data-loaded', true);
|
|
||||||
|
|
||||||
if (self.onBeforeDraw) {
|
|
||||||
self.onBeforeDraw();
|
|
||||||
}
|
|
||||||
return promise;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user