[Pkg-javascript-commits] [pdf.js] 30/115: Move text layer building logic into src/display/text_layer.js
David Prévot
taffit at moszumanska.debian.org
Wed Dec 16 20:03:11 UTC 2015
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository pdf.js.
commit 56ccaea99b966e788793eacfac4acae42bf3141c
Author: Yury Delendik <ydelendik at mozilla.com>
Date: Tue Nov 10 09:45:03 2015 -0600
Move text layer building logic into src/display/text_layer.js
---
examples/acroforms/index.html | 1 +
examples/helloworld/index.html | 1 +
make.js | 1 +
src/display/text_layer.js | 237 +++++++++++++++++++++++++++++++++++++++++
test/font/font_test.html | 1 +
test/test_slave.html | 1 +
test/unit/unit_test.html | 1 +
web/text_layer_builder.js | 168 +++++------------------------
web/viewer.html | 1 +
9 files changed, 268 insertions(+), 144 deletions(-)
diff --git a/examples/acroforms/index.html b/examples/acroforms/index.html
index 1936ae1..d6c644f 100644
--- a/examples/acroforms/index.html
+++ b/examples/acroforms/index.html
@@ -13,6 +13,7 @@
<script src="../../src/display/font_loader.js"></script>
<script src="../../src/display/dom_utils.js"></script>
<script src="../../src/display/annotation_helper.js"></script>
+ <script src="../../src/display/text_layer.js"></script>
<script>
// Specify the main script used to create a new PDF.JS web worker.
diff --git a/examples/helloworld/index.html b/examples/helloworld/index.html
index 9f79d54..b113164 100644
--- a/examples/helloworld/index.html
+++ b/examples/helloworld/index.html
@@ -13,6 +13,7 @@
<script src="../../src/display/font_loader.js"></script>
<script src="../../src/display/dom_utils.js"></script>
<script src="../../src/display/annotation_helper.js"></script>
+ <script src="../../src/display/text_layer.js"></script>
<script>
// Specify the main script used to create a new PDF.JS web worker.
diff --git a/make.js b/make.js
index 5b4e206..72f0f3f 100644
--- a/make.js
+++ b/make.js
@@ -532,6 +532,7 @@ target.bundle = function(args) {
'display/font_loader.js',
'display/dom_utils.js',
'display/annotation_helper.js',
+ 'display/text_layer.js',
'display/svg.js'
]);
diff --git a/src/display/text_layer.js b/src/display/text_layer.js
new file mode 100644
index 0000000..576853e
--- /dev/null
+++ b/src/display/text_layer.js
@@ -0,0 +1,237 @@
+/* Copyright 2015 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* globals PDFJS, createPromiseCapability */
+
+'use strict';
+
+/**
+ * Text layer render parameters.
+ *
+ * @typedef {Object} TextLayerRenderParameters
+ * @property {TextContent} textContent - Text content to render (the object is
+ * returned by the page's getTextContent() method).
+ * @property {HTMLElement} container - HTML element that will contain text runs.
+ * @property {PDFJS.PageViewport} viewport - The target viewport to properly
+ * layout the text runs.
+ * @property {Array} textDivs - (optional) HTML elements that are correspond
+ * the text items of the textContent input. This is output and shall be
+ * initially be set to empty array.
+ * @property {number} timeout - (optional) Delay in milliseconds before
+ * rendering of the text runs occurs.
+ */
+var renderTextLayer = (function renderTextLayerClosure() {
+ var MAX_TEXT_DIVS_TO_RENDER = 100000;
+
+ var NonWhitespaceRegexp = /\S/;
+
+ function isAllWhitespace(str) {
+ return !NonWhitespaceRegexp.test(str);
+ }
+
+ function appendText(textDivs, viewport, geom, styles) {
+ var style = styles[geom.fontName];
+ var textDiv = document.createElement('div');
+ textDivs.push(textDiv);
+ if (isAllWhitespace(geom.str)) {
+ textDiv.dataset.isWhitespace = true;
+ return;
+ }
+ var tx = PDFJS.Util.transform(viewport.transform, geom.transform);
+ var angle = Math.atan2(tx[1], tx[0]);
+ if (style.vertical) {
+ angle += Math.PI / 2;
+ }
+ var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
+ var fontAscent = fontHeight;
+ if (style.ascent) {
+ fontAscent = style.ascent * fontAscent;
+ } else if (style.descent) {
+ fontAscent = (1 + style.descent) * fontAscent;
+ }
+
+ var left;
+ var top;
+ if (angle === 0) {
+ left = tx[4];
+ top = tx[5] - fontAscent;
+ } else {
+ left = tx[4] + (fontAscent * Math.sin(angle));
+ top = tx[5] - (fontAscent * Math.cos(angle));
+ }
+ textDiv.style.left = left + 'px';
+ textDiv.style.top = top + 'px';
+ textDiv.style.fontSize = fontHeight + 'px';
+ textDiv.style.fontFamily = style.fontFamily;
+
+ textDiv.textContent = geom.str;
+ // |fontName| is only used by the Font Inspector. This test will succeed
+ // when e.g. the Font Inspector is off but the Stepper is on, but it's
+ // not worth the effort to do a more accurate test.
+ if (PDFJS.pdfBug) {
+ textDiv.dataset.fontName = geom.fontName;
+ }
+ // Storing into dataset will convert number into string.
+ if (angle !== 0) {
+ textDiv.dataset.angle = angle * (180 / Math.PI);
+ }
+ // We don't bother scaling single-char text divs, because it has very
+ // little effect on text highlighting. This makes scrolling on docs with
+ // lots of such divs a lot faster.
+ if (geom.str.length > 1) {
+ if (style.vertical) {
+ textDiv.dataset.canvasWidth = geom.height * viewport.scale;
+ } else {
+ textDiv.dataset.canvasWidth = geom.width * viewport.scale;
+ }
+ }
+ }
+
+ function render(task) {
+ if (task._canceled) {
+ return;
+ }
+ var textLayerFrag = task._container;
+ var textDivs = task._textDivs;
+ var capability = task._capability;
+ var textDivsLength = textDivs.length;
+
+ // No point in rendering many divs as it would make the browser
+ // unusable even after the divs are rendered.
+ if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {
+ capability.resolve();
+ return;
+ }
+
+ var canvas = document.createElement('canvas');
+//#if MOZCENTRAL || FIREFOX || GENERIC
+ canvas.mozOpaque = true;
+//#endif
+ var ctx = canvas.getContext('2d', {alpha: false});
+
+ var lastFontSize;
+ var lastFontFamily;
+ for (var i = 0; i < textDivsLength; i++) {
+ var textDiv = textDivs[i];
+ if (textDiv.dataset.isWhitespace !== undefined) {
+ continue;
+ }
+
+ var fontSize = textDiv.style.fontSize;
+ var fontFamily = textDiv.style.fontFamily;
+
+ // Only build font string and set to context if different from last.
+ if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
+ ctx.font = fontSize + ' ' + fontFamily;
+ lastFontSize = fontSize;
+ lastFontFamily = fontFamily;
+ }
+
+ var width = ctx.measureText(textDiv.textContent).width;
+ if (width > 0) {
+ textLayerFrag.appendChild(textDiv);
+ var transform;
+ if (textDiv.dataset.canvasWidth !== undefined) {
+ // Dataset values come of type string.
+ var textScale = textDiv.dataset.canvasWidth / width;
+ transform = 'scaleX(' + textScale + ')';
+ } else {
+ transform = '';
+ }
+ var rotation = textDiv.dataset.angle;
+ if (rotation) {
+ transform = 'rotate(' + rotation + 'deg) ' + transform;
+ }
+ if (transform) {
+ PDFJS.CustomStyle.setProp('transform' , textDiv, transform);
+ }
+ }
+ }
+ capability.resolve();
+ }
+
+ /**
+ * Text layer rendering task.
+ *
+ * @param {TextContent} textContent
+ * @param {HTMLElement} container
+ * @param {PDFJS.PageViewport} viewport
+ * @param {Array} textDivs
+ * @private
+ */
+ function TextLayerRenderTask(textContent, container, viewport, textDivs) {
+ this._textContent = textContent;
+ this._container = container;
+ this._viewport = viewport;
+ textDivs = textDivs || [];
+ this._textDivs = textDivs;
+ this._canceled = false;
+ this._capability = createPromiseCapability();
+ this._renderTimer = null;
+ }
+ TextLayerRenderTask.prototype = {
+ get promise() {
+ return this._capability.promise;
+ },
+
+ cancel: function TextLayer_cancel() {
+ this._canceled = true;
+ if (this._renderTimer !== null) {
+ clearTimeout(this._renderTimer);
+ this._renderTimer = null;
+ }
+ this._capability.reject('canceled');
+ },
+
+ _render: function TextLayer_render(timeout) {
+ var textItems = this._textContent.items;
+ var styles = this._textContent.styles;
+ var textDivs = this._textDivs;
+ var viewport = this._viewport;
+ for (var i = 0, len = textItems.length; i < len; i++) {
+ appendText(textDivs, viewport, textItems[i], styles);
+ }
+
+ if (!timeout) { // Render right away
+ render(this);
+ } else { // Schedule
+ var self = this;
+ this._renderTimer = setTimeout(function() {
+ render(self);
+ self._renderTimer = null;
+ }, timeout);
+ }
+ }
+ };
+
+
+ /**
+ * Starts rendering of the text layer.
+ *
+ * @param {TextLayerRenderParameters} renderParameters
+ * @returns {TextLayerRenderTask}
+ */
+ function renderTextLayer(renderParameters) {
+ var task = new TextLayerRenderTask(renderParameters.textContent,
+ renderParameters.container,
+ renderParameters.viewport,
+ renderParameters.textDivs);
+ task._render(renderParameters.timeout);
+ return task;
+ }
+
+ return renderTextLayer;
+})();
+
+PDFJS.renderTextLayer = renderTextLayer;
diff --git a/test/font/font_test.html b/test/font/font_test.html
index 4869002..0f52cbd 100644
--- a/test/font/font_test.html
+++ b/test/font/font_test.html
@@ -37,6 +37,7 @@
<script src="../../src/core/ps_parser.js"></script>
<script src="../../src/display/pattern_helper.js"></script>
<script src="../../src/display/annotation_helper.js"></script>
+ <script src="../../src/display/text_layer.js"></script>
<script src="../../src/core/stream.js"></script>
<script src="../../src/core/worker.js"></script>
<script src="../../src/display/metadata.js"></script>
diff --git a/test/test_slave.html b/test/test_slave.html
index 3677b4e..7236914 100644
--- a/test/test_slave.html
+++ b/test/test_slave.html
@@ -27,6 +27,7 @@ limitations under the License.
<script src="../src/display/font_loader.js"></script>
<script src="../src/display/dom_utils.js"></script>
<script src="../src/display/annotation_helper.js"></script>
+ <script src="../src/display/text_layer.js"></script>
<script src="driver.js"></script>
</head>
<body>
diff --git a/test/unit/unit_test.html b/test/unit/unit_test.html
index 687bd52..fcce65d 100644
--- a/test/unit/unit_test.html
+++ b/test/unit/unit_test.html
@@ -38,6 +38,7 @@
<script src="../../src/display/font_loader.js"></script>
<script src="../../src/display/dom_utils.js"></script>
<script src="../../src/display/annotation_helper.js"></script>
+ <script src="../../src/display/text_layer.js"></script>
<script src="../../src/core/stream.js"></script>
<script src="../../src/core/worker.js"></script>
<script src="../../src/display/metadata.js"></script>
diff --git a/web/text_layer_builder.js b/web/text_layer_builder.js
index 805498d..6ef8736 100644
--- a/web/text_layer_builder.js
+++ b/web/text_layer_builder.js
@@ -16,14 +16,6 @@
'use strict';
-var MAX_TEXT_DIVS_TO_RENDER = 100000;
-
-var NonWhitespaceRegexp = /\S/;
-
-function isAllWhitespace(str) {
- return !NonWhitespaceRegexp.test(str);
-}
-
/**
* @typedef {Object} TextLayerBuilderOptions
* @property {HTMLDivElement} textLayerDiv - The text layer container.
@@ -50,6 +42,7 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
this.viewport = options.viewport;
this.textDivs = [];
this.findController = options.findController || null;
+ this.textLayerRenderTask = null;
this._bindMouse();
}
@@ -68,67 +61,6 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
this.textLayerDiv.dispatchEvent(event);
},
- renderLayer: function TextLayerBuilder_renderLayer() {
- var textLayerFrag = document.createDocumentFragment();
- var textDivs = this.textDivs;
- var textDivsLength = textDivs.length;
- var canvas = document.createElement('canvas');
-//#if MOZCENTRAL || FIREFOX || GENERIC
- canvas.mozOpaque = true;
-//#endif
- var ctx = canvas.getContext('2d', {alpha: false});
-
- // No point in rendering many divs as it would make the browser
- // unusable even after the divs are rendered.
- if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {
- this._finishRendering();
- return;
- }
-
- var lastFontSize;
- var lastFontFamily;
- for (var i = 0; i < textDivsLength; i++) {
- var textDiv = textDivs[i];
- if (textDiv.dataset.isWhitespace !== undefined) {
- continue;
- }
-
- var fontSize = textDiv.style.fontSize;
- var fontFamily = textDiv.style.fontFamily;
-
- // Only build font string and set to context if different from last.
- if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
- ctx.font = fontSize + ' ' + fontFamily;
- lastFontSize = fontSize;
- lastFontFamily = fontFamily;
- }
-
- var width = ctx.measureText(textDiv.textContent).width;
- if (width > 0) {
- textLayerFrag.appendChild(textDiv);
- var transform;
- if (textDiv.dataset.canvasWidth !== undefined) {
- // Dataset values come of type string.
- var textScale = textDiv.dataset.canvasWidth / width;
- transform = 'scaleX(' + textScale + ')';
- } else {
- transform = '';
- }
- var rotation = textDiv.dataset.angle;
- if (rotation) {
- transform = 'rotate(' + rotation + 'deg) ' + transform;
- }
- if (transform) {
- PDFJS.CustomStyle.setProp('transform' , textDiv, transform);
- }
- }
- }
-
- this.textLayerDiv.appendChild(textLayerFrag);
- this._finishRendering();
- this.updateMatches();
- },
-
/**
* Renders the text layer.
* @param {number} timeout (optional) if specified, the rendering waits
@@ -139,87 +71,35 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
return;
}
- if (this.renderTimer) {
- clearTimeout(this.renderTimer);
- this.renderTimer = null;
- }
-
- if (!timeout) { // Render right away
- this.renderLayer();
- } else { // Schedule
- var self = this;
- this.renderTimer = setTimeout(function() {
- self.renderLayer();
- self.renderTimer = null;
- }, timeout);
+ if (this.textLayerRenderTask) {
+ this.textLayerRenderTask.cancel();
+ this.textLayerRenderTask = null;
}
- },
- appendText: function TextLayerBuilder_appendText(geom, styles) {
- var style = styles[geom.fontName];
- var textDiv = document.createElement('div');
- this.textDivs.push(textDiv);
- if (isAllWhitespace(geom.str)) {
- textDiv.dataset.isWhitespace = true;
- return;
- }
- var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
- var angle = Math.atan2(tx[1], tx[0]);
- if (style.vertical) {
- angle += Math.PI / 2;
- }
- var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
- var fontAscent = fontHeight;
- if (style.ascent) {
- fontAscent = style.ascent * fontAscent;
- } else if (style.descent) {
- fontAscent = (1 + style.descent) * fontAscent;
- }
-
- var left;
- var top;
- if (angle === 0) {
- left = tx[4];
- top = tx[5] - fontAscent;
- } else {
- left = tx[4] + (fontAscent * Math.sin(angle));
- top = tx[5] - (fontAscent * Math.cos(angle));
- }
- textDiv.style.left = left + 'px';
- textDiv.style.top = top + 'px';
- textDiv.style.fontSize = fontHeight + 'px';
- textDiv.style.fontFamily = style.fontFamily;
-
- textDiv.textContent = geom.str;
- // |fontName| is only used by the Font Inspector. This test will succeed
- // when e.g. the Font Inspector is off but the Stepper is on, but it's
- // not worth the effort to do a more accurate test.
- if (PDFJS.pdfBug) {
- textDiv.dataset.fontName = geom.fontName;
- }
- // Storing into dataset will convert number into string.
- if (angle !== 0) {
- textDiv.dataset.angle = angle * (180 / Math.PI);
- }
- // We don't bother scaling single-char text divs, because it has very
- // little effect on text highlighting. This makes scrolling on docs with
- // lots of such divs a lot faster.
- if (geom.str.length > 1) {
- if (style.vertical) {
- textDiv.dataset.canvasWidth = geom.height * this.viewport.scale;
- } else {
- textDiv.dataset.canvasWidth = geom.width * this.viewport.scale;
- }
- }
+ this.textDivs = [];
+ var textLayerFrag = document.createDocumentFragment();
+ this.textLayerRenderTask = PDFJS.renderTextLayer({
+ textContent: this.textContent,
+ container: textLayerFrag,
+ viewport: this.viewport,
+ textDivs: this.textDivs,
+ timeout: timeout
+ });
+ this.textLayerRenderTask.promise.then(function () {
+ this.textLayerDiv.appendChild(textLayerFrag);
+ this._finishRendering();
+ this.updateMatches();
+ }.bind(this), function (reason) {
+ // canceled or failed to render text layer -- skipping errors
+ });
},
setTextContent: function TextLayerBuilder_setTextContent(textContent) {
- this.textContent = textContent;
-
- var textItems = textContent.items;
- for (var i = 0, len = textItems.length; i < len; i++) {
- this.appendText(textItems[i], textContent.styles);
+ if (this.textLayerRenderTask) {
+ this.textLayerRenderTask.cancel();
+ this.textLayerRenderTask = null;
}
+ this.textContent = textContent;
this.divContentDone = true;
},
diff --git a/web/viewer.html b/web/viewer.html
index 217d3f2..dbbaece 100644
--- a/web/viewer.html
+++ b/web/viewer.html
@@ -62,6 +62,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<script src="../src/display/font_loader.js"></script>
<script src="../src/display/dom_utils.js"></script>
<script src="../src/display/annotation_helper.js"></script>
+ <script src="../src/display/text_layer.js"></script>
<script>PDFJS.workerSrc = '../src/worker_loader.js';</script>
<!--#endif-->
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/pdf.js.git
More information about the Pkg-javascript-commits
mailing list