Browse Source

Better "text" testing.

Yury Delendik 10 years ago
parent
commit
bd7f121c83
  1. 180
      test/driver.js
  2. 6
      test/test_manifest.json
  3. 38
      test/text_layer_test.css
  4. 22
      web/viewer.css

180
test/driver.js

@ -22,80 +22,71 @@ var PDF_TO_CSS_UNITS = 96.0 / 72.0;
/** /**
* @class * @class
*/ */
var NullTextLayerBuilder = (function NullTextLayerBuilderClosure() { var rasterizeTextLayer = (function rasterizeTextLayerClosure() {
/** var SVG_NS = 'http://www.w3.org/2000/svg';
* @constructs NullTextLayerBuilder
*/ var textLayerStylePromise = null;
function NullTextLayerBuilder() {} function getTextLayerStyle() {
if (textLayerStylePromise) {
NullTextLayerBuilder.prototype = { return textLayerStylePromise;
beginLayout: function NullTextLayerBuilder_BeginLayout() {}, }
endLayout: function NullTextLayerBuilder_EndLayout() {}, textLayerStylePromise = new Promise(function (resolve) {
appendText: function NullTextLayerBuilder_AppendText() {} var xhr = new XMLHttpRequest();
xhr.open('GET', './text_layer_test.css');
xhr.onload = function () {
resolve(xhr.responseText);
}; };
xhr.send(null);
return NullTextLayerBuilder; });
})(); return textLayerStylePromise;
}
/**
* @class function rasterizeTextLayer(ctx, viewport, textContent) {
*/ return new Promise(function (resolve) {
var SimpleTextLayerBuilder = (function SimpleTextLayerBuilderClosure() { // Building SVG with size of the viewport.
/** var svg = document.createElementNS(SVG_NS, 'svg:svg');
* @constructs SimpleTextLayerBuilder svg.setAttribute('width', viewport.width + 'px');
*/ svg.setAttribute('height', viewport.height + 'px');
function SimpleTextLayerBuilder(ctx, viewport) { // items are transformed to have 1px font size
this.ctx = ctx; svg.setAttribute('font-size', 1);
this.viewport = viewport;
this.textCounter = 0; // Adding element to host our HTML (style + text layer div).
var foreignObject = document.createElementNS(SVG_NS, 'svg:foreignObject');
// clear canvas foreignObject.setAttribute('x', '0');
ctx.save(); foreignObject.setAttribute('y', '0');
ctx.fillStyle = 'rgb(255,255,255)'; foreignObject.setAttribute('width', viewport.width + 'px');
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); foreignObject.setAttribute('height', viewport.height + 'px');
ctx.restore(); var style = document.createElement('style');
} var stylePromise = getTextLayerStyle();
foreignObject.appendChild(style);
SimpleTextLayerBuilder.prototype = { var div = document.createElement('div');
appendText: function SimpleTextLayerBuilder_AppendText(geom, styles) { div.className = 'textLayer';
var style = styles[geom.fontName]; foreignObject.appendChild(div);
var ctx = this.ctx, viewport = this.viewport;
var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform); // Rendering text layer as HTML.
var angle = Math.atan2(tx[1], tx[0]); var task = PDFJS.renderTextLayer({
var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3])); textContent: textContent,
var fontAscent = (style.ascent ? style.ascent * fontHeight : container: div,
(style.descent ? (1 + style.descent) * fontHeight : fontHeight)); viewport: viewport
});
ctx.save(); Promise.all([stylePromise, task.promise]).then(function (results) {
ctx.beginPath(); style.textContent = results[0];
ctx.strokeStyle = 'red'; svg.appendChild(foreignObject);
ctx.fillStyle = 'yellow';
ctx.translate(tx[4] + (fontAscent * Math.sin(angle)), // We need to have UTF-8 encoded XML.
tx[5] - (fontAscent * Math.cos(angle))); var svg_xml = unescape(encodeURIComponent(
ctx.rotate(angle); (new XMLSerializer()).serializeToString(svg)));
ctx.rect(0, 0, geom.width * viewport.scale, geom.height * viewport.scale); var img = new Image();
ctx.stroke(); img.src = 'data:image/svg+xml;base64,' + btoa(svg_xml);
ctx.fill(); img.onload = function () {
ctx.restore(); ctx.drawImage(img, 0, 0);
ctx.font = fontHeight + 'px ' + style.fontFamily; resolve();
ctx.fillStyle = 'black';
ctx.fillText(geom.str, tx[4], tx[5]);
this.textCounter++;
},
setTextContent:
function SimpleTextLayerBuilder_SetTextContent(textContent) {
this.ctx.save();
var textItems = textContent.items;
for (var i = 0, ii = textItems.length; i < ii; i++) {
this.appendText(textItems[i], textContent.styles);
}
this.ctx.restore();
}
}; };
});
});
}
return SimpleTextLayerBuilder; return rasterizeTextLayer;
})(); })();
/** /**
@ -328,35 +319,44 @@ var Driver = (function DriverClosure() {
self.canvas.height = viewport.height; self.canvas.height = viewport.height;
self._clearCanvas(); self._clearCanvas();
var drawContext, textLayerBuilder; var textLayerCanvas;
var resolveInitPromise; var initPromise;
var initPromise = new Promise(function (resolve) {
resolveInitPromise = resolve;
});
if (task.type === 'text') { if (task.type === 'text') {
// Using a dummy canvas for PDF context drawing operations // Using a dummy canvas for PDF context drawing operations
if (!self.dummyCanvas) { textLayerCanvas = self.textLayerCanvas;
self.dummyCanvas = document.createElement('canvas'); if (!textLayerCanvas) {
} textLayerCanvas = document.createElement('canvas');
drawContext = self.dummyCanvas.getContext('2d'); self.textLayerCanvas = textLayerCanvas;
}
textLayerCanvas.width = viewport.width;
textLayerCanvas.height = viewport.height;
var textLayerContext = textLayerCanvas.getContext('2d');
textLayerContext.clearRect(0, 0,
textLayerCanvas.width, textLayerCanvas.height);
// The text builder will draw its content on the test canvas // The text builder will draw its content on the test canvas
textLayerBuilder = new SimpleTextLayerBuilder(ctx, viewport); initPromise = page.getTextContent().then(function(textContent) {
return rasterizeTextLayer(textLayerContext, viewport,
page.getTextContent().then(function(textContent) { textContent);
textLayerBuilder.setTextContent(textContent);
resolveInitPromise();
}); });
} else { } else {
drawContext = ctx; textLayerCanvas = null;
textLayerBuilder = new NullTextLayerBuilder(); initPromise = Promise.resolve();
resolveInitPromise();
} }
var renderContext = { var renderContext = {
canvasContext: drawContext, canvasContext: ctx,
viewport: viewport viewport: viewport
}; };
var completeRender = (function(error) { var completeRender = (function(error) {
page.destroy(); // if text layer is present, compose it on top of the page
if (textLayerCanvas) {
ctx.save();
ctx.globalCompositeOperation = 'screen';
ctx.fillStyle = 'rgb(128, 255, 128)'; // making it green
ctx.fillRect(0, 0, viewport.width, viewport.height);
ctx.restore();
ctx.drawImage(textLayerCanvas, 0, 0);
}
page.cleanup();
task.stats = page.stats; task.stats = page.stats;
page.stats = new StatTimer(); page.stats = new StatTimer();
self._snapshot(task, error); self._snapshot(task, error);

6
test/test_manifest.json

@ -323,12 +323,6 @@
"lastPage": 1, "lastPage": 1,
"about": "The same file as issue2337." "about": "The same file as issue2337."
}, },
{ "id": "thuluthfont-text",
"file": "pdfs/ThuluthFeatures.pdf",
"md5": "b7e18bf7a3d6a9c82aefa12d721072fc",
"rounds": 1,
"type": "text"
},
{ "id": "freeculture", { "id": "freeculture",
"file": "pdfs/freeculture.pdf", "file": "pdfs/freeculture.pdf",
"md5": "dcdf3a8268e6a18938a42d5149efcfca", "md5": "dcdf3a8268e6a18938a42d5149efcfca",

38
test/text_layer_test.css

@ -0,0 +1,38 @@
/* 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.
*/
/* Used in 'text' tests */
.textLayer {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.textLayer > div {
position: absolute;
white-space: pre;
-webkit-transform-origin: 0% 0%;
-moz-transform-origin: 0% 0%;
-o-transform-origin: 0% 0%;
-ms-transform-origin: 0% 0%;
transform-origin: 0% 0%;
border: solid 1px rgba(255, 0, 0, 0.5);
background-color: rgba(255, 255, 32, 0.1);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}

22
web/viewer.css

@ -1515,7 +1515,27 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
font-size: 10px; font-size: 10px;
} }
#viewer.textLayer-visible .textLayer > div, #viewer.textLayer-visible .textLayer {
opacity: 1.0;
}
#viewer.textLayer-visible .canvasWrapper {
background-color: rgb(128,255,128);
}
#viewer.textLayer-visible .canvasWrapper canvas {
mix-blend-mode: screen;
}
#viewer.textLayer-visible .textLayer > div {
background-color: rgba(255, 255, 0, 0.1);
color: black;
border: solid 1px rgba(255, 0, 0, 0.5);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#viewer.textLayer-hover .textLayer > div:hover { #viewer.textLayer-hover .textLayer > div:hover {
background-color: white; background-color: white;
color: black; color: black;

Loading…
Cancel
Save