From 868591554285c4577372b4a1478cf987aed76d15 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Thu, 24 Nov 2011 12:53:11 -0600 Subject: [PATCH 1/4] Re-using the pages as thumbnails --- web/viewer.js | 58 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index bfb3a4303..c8b830431 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -193,6 +193,13 @@ var PDFView = { }, load: function pdfViewLoad(data, scale) { + function bindOnAfterDraw(pageView, thumbnailView) { + // when page is painted, using the image as thumbnail base + pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() { + thumbnailView.setImage(pageView.canvas); + }; + } + var loadingIndicator = document.getElementById('loading'); loadingIndicator.setAttribute('hidden', 'true'); @@ -219,10 +226,14 @@ var PDFView = { var thumbnails = this.thumbnails = []; for (var i = 1; i <= pagesCount; i++) { var page = pdf.getPage(i); - pages.push(new PageView(container, page, i, page.width, page.height, - page.stats, this.navigateTo.bind(this))); - thumbnails.push(new ThumbnailView(sidebar, page, i, - page.width / page.height)); + var pageView = new PageView(container, page, i, page.width, page.height, + page.stats, this.navigateTo.bind(this)); + var thumbnailView = new ThumbnailView(sidebar, page, i, + page.width / page.height); + bindOnAfterDraw(pageView, thumbnailView); + + pages.push(pageView); + thumbnails.push(thumbnailView); var pageRef = page.ref; pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i; } @@ -360,6 +371,8 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight, while (div.hasChildNodes()) div.removeChild(div.lastChild); div.removeAttribute('data-loaded'); + + delete this.canvas; }; function setupLinks(content, scale) { @@ -474,6 +487,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight, canvas.id = 'page' + this.id; canvas.mozOpaque = true; div.appendChild(canvas); + this.canvas = canvas; var scale = this.scale; canvas.width = pageWidth * scale; @@ -487,7 +501,11 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight, ctx.translate(-this.x * scale, -this.y * scale); stats.begin = Date.now(); - this.content.startRendering(ctx, this.updateStats); + this.content.startRendering(ctx, (function pageViewDrawCallback() { + this.updateStats(); + if (this.onAfterDraw) + this.onAfterDraw(); + }).bind(this)); setupLinks(this.content, this.scale); div.setAttribute('data-loaded', true); @@ -518,10 +536,9 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) { anchor.appendChild(div); container.appendChild(anchor); - this.draw = function thumbnailViewDraw() { - if (div.hasChildNodes()) - return; + this.hasImage = false; + function getPageDrawContext() { var canvas = document.createElement('canvas'); canvas.id = 'thumbnail' + id; canvas.mozOpaque = true; @@ -549,7 +566,28 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) { div.style.height = (view.height * scaleY) + 'px'; div.style.lineHeight = (view.height * scaleY) + 'px'; + return ctx; + } + + this.draw = function thumbnailViewDraw() { + if (this.hasImage) + return; + + var ctx = getPageDrawContext(); page.startRendering(ctx, function thumbnailViewDrawStartRendering() {}); + + this.hasImage = true; + }; + + this.setImage = function thumbnailViewSetImage(img) { + if (this.hasImage) + return; + + var ctx = getPageDrawContext(); + ctx.drawImage(img, 0, 0, img.width, img.height, + 0, 0, ctx.canvas.width, ctx.canvas.height); + + this.hasImage = true; }; }; @@ -687,6 +725,10 @@ window.addEventListener('transitionend', function webViewerTransitionend(evt) { var container = document.getElementById('sidebarView'); container._interval = window.setInterval(function interval() { + // skipping the thumbnails with set images + while (pageIndex < pagesCount && PDFView.thumbnails[pageIndex].hasImage) + pageIndex++; + if (pageIndex >= pagesCount) { window.clearInterval(container._interval); return; From a30f0ff848beb8d205c9e4c061973f5955181f79 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Tue, 22 Nov 2011 21:00:04 +0100 Subject: [PATCH 2/4] Implement ctx.mozCurrentTransform and ctx.mozCurrentTransformInverse shim --- src/canvas.js | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ src/pattern.js | 2 + 2 files changed, 111 insertions(+) diff --git a/src/canvas.js b/src/canvas.js index 9b3ed0ba9..d9c60f416 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -59,6 +59,111 @@ function ScratchCanvas(width, height) { return canvas; } +function addCtxCurrentTransform(ctx) { + // If the context doesn't expose a `mozCurrentTransform`, add a JS based on. + if (!ctx.mozCurrentTransform) { + // Store the original context + ctx._originalSave = ctx.save; + ctx._originalRestore = ctx.restore; + ctx._originalRotate = ctx.rotate; + ctx._originalScale = ctx.scale; + ctx._originalTranslate = ctx.translate; + ctx._originalTransform = ctx.transform; + + ctx._transformMatrix = [1, 0, 0, 1, 0, 0]; + ctx._transformStack = []; + + ctx.__defineGetter__('mozCurrentTransform', function getCurrentTransform() { + return this._transformMatrix; + }); + + ctx.__defineGetter__('mozCurrentTransformInverse', + function getCurrentTransformInverse() { + // Calculation done using WolframAlpha: + // http://www.wolframalpha.com/input/? + // i=Inverse+{{a%2C+c%2C+e}%2C+{b%2C+d%2C+f}%2C+{0%2C+0%2C+1}} + + var m = this._transformMatrix; + var a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5]; + + return [ + d / (a * d - b * c), + b / (b * c - a * d), + c / (b * c - a * d), + a / (a * d - b * c), + (d * e - c * f) / (b * c - a * d), + (b * e - a * f) / (a * d - b * c) + ]; + } + ); + + ctx.save = function ctxSave() { + var old = this._transformMatrix; + this._transformStack.push(old); + this._transformMatrix = old.slice(0, 6); + + this._originalSave(); + }; + + ctx.restore = function ctxRestore() { + var prev = this._transformStack.pop(); + if (prev) { + this._transformMatrix = prev; + this._originalRestore(); + } + } + + ctx.translate = function ctxTranslate(x, y) { + var m = this._transformMatrix; + m[4] = m[0] * x + m[2] * y + m[4]; + m[5] = m[1] * x + m[3] * y + m[5]; + + this._originalTranslate(x, y); + } + + ctx.scale = function ctxScale(x, y) { + var m = this._transformMatrix; + m[0] = m[0] * x; + m[1] = m[1] * x; + m[2] = m[2] * y; + m[3] = m[3] * y; + + this._originalScale(x, y); + } + + ctx.transform = function ctxTransform(a, b, c, d, e, f) { + var m = this._transformMatrix; + this._transformMatrix = [ + m[0] * a + m[2] * b, + m[1] * a + m[3] * b, + m[0] * c + m[2] * d, + m[1] * c + m[3] * d, + m[0] * e + m[2] * f + m[4], + m[1] * e + m[3] * f + m[5] + ]; + + ctx._originalTransform(a, b, c, d, e, f); + } + + ctx.rotate = function ctxRotate(angle) { + var cosValue = Math.cos(angle); + var sinValue = Math.sin(angle); + + var m = this._transformMatrix; + this._transformMatrix = [ + m[0] * cosValue + m[2] * sinValue, + m[1] * cosValue + m[3] * sinValue, + m[0] * (-sinValue) + m[2] * cosValue, + m[1] * (-sinValue) + m[3] * cosValue, + m[4], + m[5] + ]; + + this._originalRotate(angle); + } + } +} + var CanvasGraphics = (function canvasGraphics() { // Defines the time the executeIRQueue is going to be executing // before it stops and shedules a continue of execution. @@ -77,6 +182,10 @@ var CanvasGraphics = (function canvasGraphics() { this.xobjs = null; this.ScratchCanvas = ScratchCanvas; this.objs = objs; + + if (canvasCtx) { + addCtxCurrentTransform(canvasCtx); + } } var LINE_CAP_STYLES = ['butt', 'round', 'square']; diff --git a/src/pattern.js b/src/pattern.js index 72d13d896..c565e8b7f 100644 --- a/src/pattern.js +++ b/src/pattern.js @@ -217,6 +217,8 @@ var TilingPattern = (function tilingPattern() { // set the new canvas element context as the graphics context var tmpCtx = tmpCanvas.getContext('2d'); + addCtxCurrentTransform(tmpCtx); + var graphics = new CanvasGraphics(tmpCtx, objs); switch (paintType) { From 36e618c373f718320faa0540536263a7c37068f9 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Sun, 27 Nov 2011 09:22:08 +0100 Subject: [PATCH 3/4] Address Yury's review comments + remove call to addCtxCurrentTransform in pattern.js as the contet is added during the CanvasGraphics constructor already --- src/canvas.js | 41 +++++++++++++++++++++++------------------ src/pattern.js | 2 -- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/canvas.js b/src/canvas.js index d9c60f416..035651b0f 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -59,7 +59,7 @@ function ScratchCanvas(width, height) { return canvas; } -function addCtxCurrentTransform(ctx) { +function addContextCurrentTransform(ctx) { // If the context doesn't expose a `mozCurrentTransform`, add a JS based on. if (!ctx.mozCurrentTransform) { // Store the original context @@ -73,12 +73,14 @@ function addCtxCurrentTransform(ctx) { ctx._transformMatrix = [1, 0, 0, 1, 0, 0]; ctx._transformStack = []; - ctx.__defineGetter__('mozCurrentTransform', function getCurrentTransform() { - return this._transformMatrix; + Object.defineProperty(ctx, 'mozCurrentTransform', { + get: function getCurrentTransform() { + return this._transformMatrix; + } }); - ctx.__defineGetter__('mozCurrentTransformInverse', - function getCurrentTransformInverse() { + Object.defineProperty(ctx, 'mozCurrentTransformInverse', { + get: function getCurrentTransformInverse() { // Calculation done using WolframAlpha: // http://www.wolframalpha.com/input/? // i=Inverse+{{a%2C+c%2C+e}%2C+{b%2C+d%2C+f}%2C+{0%2C+0%2C+1}} @@ -86,16 +88,19 @@ function addCtxCurrentTransform(ctx) { var m = this._transformMatrix; var a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5]; + var ad_bc = a * d - b * c; + var bc_ad = b * c - a * d; + return [ - d / (a * d - b * c), - b / (b * c - a * d), - c / (b * c - a * d), - a / (a * d - b * c), - (d * e - c * f) / (b * c - a * d), - (b * e - a * f) / (a * d - b * c) + d / ad_bc, + b / bc_ad, + c / bc_ad, + a / ad_bc, + (d * e - c * f) / bc_ad, + (b * e - a * f) / ad_bc ]; } - ); + }); ctx.save = function ctxSave() { var old = this._transformMatrix; @@ -111,7 +116,7 @@ function addCtxCurrentTransform(ctx) { this._transformMatrix = prev; this._originalRestore(); } - } + }; ctx.translate = function ctxTranslate(x, y) { var m = this._transformMatrix; @@ -119,7 +124,7 @@ function addCtxCurrentTransform(ctx) { m[5] = m[1] * x + m[3] * y + m[5]; this._originalTranslate(x, y); - } + }; ctx.scale = function ctxScale(x, y) { var m = this._transformMatrix; @@ -129,7 +134,7 @@ function addCtxCurrentTransform(ctx) { m[3] = m[3] * y; this._originalScale(x, y); - } + }; ctx.transform = function ctxTransform(a, b, c, d, e, f) { var m = this._transformMatrix; @@ -143,7 +148,7 @@ function addCtxCurrentTransform(ctx) { ]; ctx._originalTransform(a, b, c, d, e, f); - } + }; ctx.rotate = function ctxRotate(angle) { var cosValue = Math.cos(angle); @@ -160,7 +165,7 @@ function addCtxCurrentTransform(ctx) { ]; this._originalRotate(angle); - } + }; } } @@ -184,7 +189,7 @@ var CanvasGraphics = (function canvasGraphics() { this.objs = objs; if (canvasCtx) { - addCtxCurrentTransform(canvasCtx); + addContextCurrentTransform(canvasCtx); } } diff --git a/src/pattern.js b/src/pattern.js index c565e8b7f..72d13d896 100644 --- a/src/pattern.js +++ b/src/pattern.js @@ -217,8 +217,6 @@ var TilingPattern = (function tilingPattern() { // set the new canvas element context as the graphics context var tmpCtx = tmpCanvas.getContext('2d'); - addCtxCurrentTransform(tmpCtx); - var graphics = new CanvasGraphics(tmpCtx, objs); switch (paintType) { From 8991cfad83768f3d73152ccf8ad1c59c595afa53 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Sun, 27 Nov 2011 20:54:25 +0100 Subject: [PATCH 4/4] Check after each executed command if execution took too long already --- src/canvas.js | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/canvas.js b/src/canvas.js index 9b3ed0ba9..780a96c9b 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -64,10 +64,6 @@ var CanvasGraphics = (function canvasGraphics() { // before it stops and shedules a continue of execution. var kExecutionTime = 50; - // Number of IR commands to execute before checking - // if we execute longer then `kExecutionTime`. - var kExecutionTimeCheck = 500; - function constructor(canvasCtx, objs) { this.ctx = canvasCtx; this.current = new CanvasExtraState(); @@ -112,31 +108,33 @@ var CanvasGraphics = (function canvasGraphics() { var i = executionStartIdx || 0; var argsArrayLen = argsArray.length; + // Sometimes the IRQueue to execute is empty. + if (argsArrayLen == i) { + return i; + } + var executionEndIdx; var startTime = Date.now(); var objs = this.objs; - do { - executionEndIdx = Math.min(argsArrayLen, i + kExecutionTimeCheck); + while (true) { + if (fnArray[i] !== 'dependency') { + this[fnArray[i]].apply(this, argsArray[i]); + } else { + var deps = argsArray[i]; + for (var n = 0, nn = deps.length; n < nn; n++) { + var depObjId = deps[n]; - for (i; i < executionEndIdx; i++) { - if (fnArray[i] !== 'dependency') { - this[fnArray[i]].apply(this, argsArray[i]); - } else { - var deps = argsArray[i]; - for (var n = 0, nn = deps.length; n < nn; n++) { - var depObjId = deps[n]; - - // If the promise isn't resolved yet, add the continueCallback - // to the promise and bail out. - if (!objs.isResolved(depObjId)) { - objs.get(depObjId, continueCallback); - return i; - } + // If the promise isn't resolved yet, add the continueCallback + // to the promise and bail out. + if (!objs.isResolved(depObjId)) { + objs.get(depObjId, continueCallback); + return i; } } } + i++; // If the entire IRQueue was executed, stop as were done. if (i == argsArrayLen) { @@ -153,7 +151,7 @@ var CanvasGraphics = (function canvasGraphics() { // If the IRQueue isn't executed completly yet OR the execution time // was short enough, do another execution round. - } while (true); + } }, endDrawing: function canvasGraphicsEndDrawing() {