diff --git a/src/canvas.js b/src/canvas.js index 4797bab46..3fd55b45d 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -257,8 +257,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height); // Move the media left-top corner to the (0,0) canvas position this.ctx.translate(-mediaBox.x, -mediaBox.y); - this.textDivs = []; - this.textLayerQueue = []; + + if (this.textLayer) + this.textLayer.beginLayout(); }, executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR, @@ -322,27 +323,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { endDrawing: function canvasGraphicsEndDrawing() { this.ctx.restore(); - var textLayer = this.textLayer; - if (!textLayer) - return; - - var self = this; - var textDivs = this.textDivs; - this.textLayerTimer = setInterval(function renderTextLayer() { - if (textDivs.length === 0) { - clearInterval(self.textLayerTimer); - return; - } - var textDiv = textDivs.shift(); - if (textDiv.dataset.textLength > 1) { // avoid div by zero - textLayer.appendChild(textDiv); - // Adjust div width (via letterSpacing) to match canvas text - // Due to the .offsetWidth calls, this is slow - textDiv.style.letterSpacing = - ((textDiv.dataset.canvasWidth - textDiv.offsetWidth) / - (textDiv.dataset.textLength - 1)) + 'px'; - } - }, 0); + if (this.textLayer) + this.textLayer.endLayout(); }, // Graphics state @@ -634,24 +616,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { return geometry; }, - pushTextDivs: function canvasGraphicsPushTextDivs(text) { - var div = document.createElement('div'); - var fontSize = this.current.fontSize; - - // vScale and hScale already contain the scaling to pixel units - // as mozCurrentTransform reflects ctx.scale() changes - // (see beginDrawing()) - var fontHeight = fontSize * text.geom.vScale; - div.dataset.canvasWidth = text.canvasWidth * text.geom.hScale; - - div.style.fontSize = fontHeight + 'px'; - div.style.fontFamily = this.current.font.loadedName || 'sans-serif'; - div.style.left = text.geom.x + 'px'; - div.style.top = (text.geom.y - fontHeight) + 'px'; - div.innerHTML = text.str; - div.dataset.textLength = text.length; - this.textDivs.push(div); - }, showText: function canvasGraphicsShowText(str, skipTextSelection) { var ctx = this.ctx; var current = this.current; @@ -751,7 +715,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { width += charWidth; - text.str += glyph.unicode === ' ' ? ' ' : glyph.unicode; + text.str += glyph.unicode === ' ' ? '\u00A0' : glyph.unicode; text.length++; text.canvasWidth += charWidth; } @@ -760,7 +724,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { } if (textSelection) - this.pushTextDivs(text); + this.textLayer.appendText(text, font.loadedName, fontSize); return text; }, @@ -803,7 +767,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { if (e < 0 && text.geom.spaceWidth > 0) { // avoid div by zero var numFakeSpaces = Math.round(-e / text.geom.spaceWidth); if (numFakeSpaces > 0) { - text.str += ' '; + text.str += '\u00A0'; text.length++; } } @@ -813,7 +777,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { if (textSelection) { if (shownText.str === ' ') { - text.str += ' '; + text.str += '\u00A0'; } else { text.str += shownText.str; } @@ -826,7 +790,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { } if (textSelection) - this.pushTextDivs(text); + this.textLayer.appendText(text, font.loadedName, fontSize); }, nextLineShowText: function canvasGraphicsNextLineShowText(text) { this.nextLine(); diff --git a/test/driver.js b/test/driver.js index 64fceee90..85d25658a 100644 --- a/test/driver.js +++ b/test/driver.js @@ -165,9 +165,14 @@ function nextPage(task, loadError) { canvas.height = pageHeight * pdfToCssUnitsCoef; clear(ctx); - // using non-attached to the document div to test + // using the text layer builder that does nothing to test // text layer creation operations - var textLayer = document.createElement('div'); + var textLayerBuilder = { + beginLayout: function nullTextLayerBuilderBeginLayout() {}, + endLayout: function nullTextLayerBuilderEndLayout() {}, + appendText: function nullTextLayerBuilderAppendText(text, fontName, + fontSize) {} + }; page.startRendering( ctx, @@ -177,7 +182,7 @@ function nextPage(task, loadError) { failureMessage = 'render : ' + error.message; snapshotCurrentPage(task, failureMessage); }, - textLayer + textLayerBuilder ); } catch (e) { failure = 'page setup : ' + e.toString(); diff --git a/web/viewer.js b/web/viewer.js index f561ed12e..6065a2f68 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -798,7 +798,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight, cache.push(this); callback(); - }).bind(this), textLayer + }).bind(this), new TextLayerBuilder(textLayer) ); setupAnnotations(this.content, this.scale); @@ -931,6 +931,53 @@ var DocumentOutlineView = function documentOutlineView(outline) { } }; +var TextLayerBuilder = function textLayerBuilder(textLayerDiv) { + this.textLayerDiv = textLayerDiv; + + this.beginLayout = function textLayerBuilderBeginLayout() { + this.textDivs = []; + this.textLayerQueue = []; + }; + + this.endLayout = function textLayerBuilderEndLayout() { + var self = this; + var textDivs = this.textDivs; + var textLayerDiv = this.textLayerDiv; + this.textLayerTimer = setInterval(function renderTextLayer() { + if (textDivs.length === 0) { + clearInterval(self.textLayerTimer); + return; + } + var textDiv = textDivs.shift(); + if (textDiv.dataset.textLength >= 1) { // avoid div by zero + textLayerDiv.appendChild(textDiv); + // Adjust div width (via letterSpacing) to match canvas text + // Due to the .offsetWidth calls, this is slow + textDiv.style.letterSpacing = + ((textDiv.dataset.canvasWidth - textDiv.offsetWidth) / + (textDiv.dataset.textLength - 1)) + 'px'; + } + }, 0); + }; + + this.appendText = function textLayerBuilderAppendText(text, + fontName, fontSize) { + var textDiv = document.createElement('div'); + + // vScale and hScale already contain the scaling to pixel units + var fontHeight = fontSize * text.geom.vScale; + textDiv.dataset.canvasWidth = text.canvasWidth * text.geom.hScale; + + textDiv.style.fontSize = fontHeight + 'px'; + textDiv.style.fontFamily = fontName || 'sans-serif'; + textDiv.style.left = text.geom.x + 'px'; + textDiv.style.top = (text.geom.y - fontHeight) + 'px'; + textDiv.textContent = text.str; + textDiv.dataset.textLength = text.length; + this.textDivs.push(textDiv); + }; +}; + window.addEventListener('load', function webViewerLoad(evt) { var params = document.location.search.substring(1).split('&'); for (var i = 0; i < params.length; i++) {