Merge pull request #6021 from timvandermeij/test-driver

Refactor the test driver
This commit is contained in:
Jonas Jenwald 2015-05-26 21:01:13 +02:00
commit 39d2103063
2 changed files with 455 additions and 433 deletions

View File

@ -18,438 +18,458 @@
'use strict'; 'use strict';
/* var WAITING_TIME = 100; // ms
* A Test Driver for PDF.js var PDF_TO_CSS_UNITS = 96.0 / 72.0;
/**
* @class
*/ */
(function DriverClosure() { var NullTextLayerBuilder = (function NullTextLayerBuilderClosure() {
/**
* @constructs NullTextLayerBuilder
*/
function NullTextLayerBuilder() {}
PDFJS.enableStats = true; NullTextLayerBuilder.prototype = {
PDFJS.cMapUrl = '../external/bcmaps/'; beginLayout: function NullTextLayerBuilder_BeginLayout() {},
PDFJS.cMapPacked = true; endLayout: function NullTextLayerBuilder_EndLayout() {},
appendText: function NullTextLayerBuilder_AppendText() {}
};
var appPath, masterMode, browser, canvas, dummyCanvas, currentTaskIdx, return NullTextLayerBuilder;
manifest, stdout; })();
var inFlightRequests = 0;
// Chrome for Windows locks during testing on low end machines /**
var letItCooldown = /Windows.*?Chrom/i.test(navigator.userAgent); * @class
*/
function queryParams() { var SimpleTextLayerBuilder = (function SimpleTextLayerBuilderClosure() {
var qs = window.location.search.substring(1); /**
var kvs = qs.split('&'); * @constructs SimpleTextLayerBuilder
var params = { }; */
for (var i = 0; i < kvs.length; ++i) { function SimpleTextLayerBuilder(ctx, viewport) {
var kv = kvs[i].split('='); this.ctx = ctx;
params[unescape(kv[0])] = unescape(kv[1]); this.viewport = viewport;
this.textCounter = 0;
} }
return params;
}
window.load = function load() { SimpleTextLayerBuilder.prototype = {
var params = queryParams(); appendText: function SimpleTextLayerBuilder_AppendText(geom, styles) {
browser = params.browser; var style = styles[geom.fontName];
var manifestFile = params.manifestFile; var ctx = this.ctx, viewport = this.viewport;
appPath = params.path; var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
masterMode = params.masterMode === 'True'; var angle = Math.atan2(tx[1], tx[0]);
var delay = params.delay || 0; var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
var fontAscent = (style.ascent ? style.ascent * fontHeight :
(style.descent ? (1 + style.descent) * fontHeight : fontHeight));
canvas = document.createElement('canvas'); ctx.save();
stdout = document.getElementById('stdout'); ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.fillStyle = 'yellow';
ctx.translate(tx[4] + (fontAscent * Math.sin(angle)),
tx[5] - (fontAscent * Math.cos(angle)));
ctx.rotate(angle);
ctx.rect(0, 0, geom.width * viewport.scale, geom.height * viewport.scale);
ctx.stroke();
ctx.fill();
ctx.restore();
ctx.font = fontHeight + 'px ' + style.fontFamily;
ctx.fillStyle = 'black';
ctx.fillText(geom.str, tx[4], tx[5]);
info('User Agent: ' + navigator.userAgent); this.textCounter++;
log('load...\n'); },
log('Harness thinks this browser is "' + browser + '" with path "' + setTextContent:
appPath + '"\n'); function SimpleTextLayerBuilder_SetTextContent(textContent) {
log('Fetching manifest "' + manifestFile + '"... '); this.ctx.save();
var textItems = textContent.items;
var r = new XMLHttpRequest(); for (var i = 0, ii = textItems.length; i < ii; i++) {
r.open('GET', manifestFile, false); this.appendText(textItems[i], textContent.styles);
r.onreadystatechange = function loadOnreadystatechange(e) { }
if (r.readyState === 4) { this.ctx.restore();
log('done\n');
manifest = JSON.parse(r.responseText);
currentTaskIdx = 0;
nextTask();
} }
}; };
if (delay) {
log('\nDelaying for ' + delay + 'ms...\n');
}
// When gathering the stats the numbers seem to be more reliable if the
// browser is given more time to startup.
setTimeout(function() {
r.send(null);
}, delay);
};
function cleanup(callback) { return SimpleTextLayerBuilder;
// Clear out all the stylesheets since a new one is created for each font. })();
while (document.styleSheets.length > 0) {
var styleSheet = document.styleSheets[0]; /**
while (styleSheet.cssRules.length > 0) { * @typedef {Object} DriverOptions
styleSheet.deleteRule(0); * @property {HTMLSpanElement} inflight - Field displaying the number of
} * inflight requests.
var ownerNode = styleSheet.ownerNode; * @property {HTMLInputElement} disableScrolling - Checkbox to disable
ownerNode.parentNode.removeChild(ownerNode); * automatic scrolling of the output container.
} * @property {HTMLPreElement} output - Container for all output messages.
var guard = document.getElementById('content-end'); * @property {HTMLDivElement} end - Container for a completion message.
var body = document.body; */
while (body.lastChild !== guard) {
body.removeChild(body.lastChild); /**
* @class
*/
var Driver = (function DriverClosure() {
/**
* @constructs Driver
* @param {DriverOptions} options
*/
function Driver(options) {
// Configure the global PDFJS object
PDFJS.workerSrc = '../src/worker_loader.js';
PDFJS.cMapPacked = true;
PDFJS.cMapUrl = '../external/bcmaps/';
PDFJS.enableStats = true;
// Set the passed options
this.inflight = options.inflight;
this.disableScrolling = options.disableScrolling;
this.output = options.output;
this.end = options.end;
// Set parameters from the query string
var parameters = this._getQueryStringParameters();
this.browser = parameters.browser;
this.manifestFile = parameters.manifestFile;
this.appPath = parameters.path;
this.delay = (parameters.delay | 0) || 0;
this.inFlightRequests = 0;
// Create a working canvas
this.canvas = document.createElement('canvas');
} }
// Wipe out the link to the pdfdoc so it can be GC'ed. Driver.prototype = {
for (var i = 0; i < manifest.length; i++) { _getQueryStringParameters: function Driver_getQueryStringParameters() {
if (manifest[i].pdfDoc) { var queryString = window.location.search.substring(1);
manifest[i].pdfDoc.destroy(); var values = queryString.split('&');
delete manifest[i].pdfDoc; var parameters = {};
} for (var i = 0, ii = values.length; i < ii; i++) {
} var value = values[i].split('=');
if (letItCooldown) { parameters[unescape(value[0])] = unescape(value[1]);
setTimeout(callback, 500); }
} else { return parameters;
callback(); },
}
}
function exceptionToString(e) { run: function Driver_run() {
if (typeof e !== 'object') { var self = this;
return String(e);
}
if (!('message' in e)) {
return JSON.stringify(e);
}
return e.message + ('stack' in e ? ' at ' + e.stack.split('\n')[0] : '');
}
function nextTask() { this._info('User agent: ' + navigator.userAgent);
cleanup(continueNextTask); this._log('Harness thinks this browser is "' + this.browser +
} '" with path "' + this.appPath + '"\n');
this._log('Fetching manifest "' + this.manifestFile + '"... ');
function continueNextTask() { var r = new XMLHttpRequest();
if (currentTaskIdx === manifest.length) { r.open('GET', this.manifestFile, false);
done(); r.onreadystatechange = function() {
return; if (r.readyState === 4) {
} self._log('done\n');
var task = manifest[currentTaskIdx]; self.manifest = JSON.parse(r.responseText);
task.round = 0; self.currentTask = 0;
task.stats = {times: []}; self._nextTask();
log('Loading file "' + task.file + '"\n');
var absoluteUrl = combineUrl(window.location.href, task.file);
var failure;
function continuation() {
task.pageNum = task.firstPage || 1;
nextPage(task, failure);
}
PDFJS.disableRange = task.disableRange;
PDFJS.disableAutoFetch = !task.enableAutoFetch;
try {
var promise = PDFJS.getDocument({
url: absoluteUrl,
password: task.password
});
promise.then(function(doc) {
task.pdfDoc = doc;
continuation();
}, function(e) {
failure = 'load PDF doc : ' + e;
continuation();
});
return;
} catch (e) {
failure = 'load PDF doc : ' + exceptionToString(e);
}
continuation();
}
function getLastPageNum(task) {
if (!task.pdfDoc) {
return task.firstPage || 1;
}
var lastPageNum = task.lastPage || 0;
if (!lastPageNum || lastPageNum > task.pdfDoc.numPages) {
lastPageNum = task.pdfDoc.numPages;
}
return lastPageNum;
}
function isLastPage(task) {
return task.pageNum > getLastPageNum(task);
}
function canvasToDataURL() {
return canvas.toDataURL('image/png');
}
function NullTextLayerBuilder() {
}
NullTextLayerBuilder.prototype = {
beginLayout: function NullTextLayerBuilder_BeginLayout() {},
endLayout: function NullTextLayerBuilder_EndLayout() {},
appendText: function NullTextLayerBuilder_AppendText() {}
};
function SimpleTextLayerBuilder(ctx, viewport) {
this.ctx = ctx;
this.viewport = viewport;
this.textCounter = 0;
}
SimpleTextLayerBuilder.prototype = {
appendText: function SimpleTextLayerBuilder_AppendText(geom, styles) {
var style = styles[geom.fontName];
var ctx = this.ctx, viewport = this.viewport;
var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
var angle = Math.atan2(tx[1], tx[0]);
var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
var fontAscent = (style.ascent ? style.ascent * fontHeight :
(style.descent ? (1 + style.descent) * fontHeight : fontHeight));
ctx.save();
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.fillStyle = 'yellow';
ctx.translate(tx[4] + (fontAscent * Math.sin(angle)),
tx[5] - (fontAscent * Math.cos(angle)));
ctx.rotate(angle);
ctx.rect(0, 0, geom.width * viewport.scale, geom.height * viewport.scale);
ctx.stroke();
ctx.fill();
ctx.restore();
ctx.font = fontHeight + 'px ' + style.fontFamily;
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; i < textItems.length; i++) {
this.appendText(textItems[i], textContent.styles);
}
this.ctx.restore();
}
};
function nextPage(task, loadError) {
var failure = loadError || '';
if (!task.pdfDoc) {
sendTaskResult(canvasToDataURL(), task, failure, function () {
log('done' + (failure ? ' (failed !: ' + failure + ')' : '') + '\n');
++currentTaskIdx;
nextTask();
});
return;
}
if (isLastPage(task)) {
if (++task.round < task.rounds) {
log(' Round ' + (1 + task.round) + '\n');
task.pageNum = task.firstPage || 1;
} else {
++currentTaskIdx;
nextTask();
return;
}
}
if (task.skipPages && task.skipPages.indexOf(task.pageNum) >= 0) {
log(' skipping page ' + task.pageNum + '/' + task.pdfDoc.numPages +
'... ');
// empty the canvas
canvas.width = 1;
canvas.height = 1;
clear(canvas.getContext('2d'));
snapshotCurrentPage(task, '');
return;
}
if (!failure) {
try {
log(' loading page ' + task.pageNum + '/' + task.pdfDoc.numPages +
'... ');
var ctx = canvas.getContext('2d');
task.pdfDoc.getPage(task.pageNum).then(function(page) {
var pdfToCssUnitsCoef = 96.0 / 72.0;
var viewport = page.getViewport(pdfToCssUnitsCoef);
canvas.width = viewport.width;
canvas.height = viewport.height;
clear(ctx);
var drawContext, textLayerBuilder;
var resolveInitPromise;
var initPromise = new Promise(function (resolve) {
resolveInitPromise = resolve;
});
if (task.type === 'text') {
// using dummy canvas for pdf context drawing operations
if (!dummyCanvas) {
dummyCanvas = document.createElement('canvas');
}
drawContext = dummyCanvas.getContext('2d');
// ... text builder will draw its content on the test canvas
textLayerBuilder = new SimpleTextLayerBuilder(ctx, viewport);
page.getTextContent().then(function(textContent) {
textLayerBuilder.setTextContent(textContent);
resolveInitPromise();
});
} else {
drawContext = ctx;
textLayerBuilder = new NullTextLayerBuilder();
resolveInitPromise();
} }
var renderContext = { };
canvasContext: drawContext, if (this.delay > 0) {
viewport: viewport this._log('\nDelaying for ' + this.delay + ' ms...\n');
}; }
var completeRender = (function(error) { // When gathering the stats the numbers seem to be more reliable
page.destroy(); // if the browser is given more time to start.
task.stats = page.stats; setTimeout(function() {
page.stats = new StatTimer(); r.send(null);
snapshotCurrentPage(task, error); }, this.delay);
},
_nextTask: function Driver_nextTask() {
var self = this;
var failure = '';
this._cleanup();
if (this.currentTask === this.manifest.length) {
this._done();
return;
}
var task = this.manifest[this.currentTask];
task.round = 0;
task.pageNum = task.firstPage || 1;
task.stats = { times: [] };
this._log('Loading file "' + task.file + '"\n');
var absoluteUrl = combineUrl(window.location.href, task.file);
PDFJS.disableRange = task.disableRange;
PDFJS.disableAutoFetch = !task.enableAutoFetch;
try {
PDFJS.getDocument({
url: absoluteUrl,
password: task.password
}).then(function(doc) {
task.pdfDoc = doc;
self._nextPage(task, failure);
}, function(e) {
failure = 'Loading PDF document: ' + e;
self._nextPage(task, failure);
}); });
initPromise.then(function () { return;
page.render(renderContext).promise.then(function() { } catch (e) {
completeRender(false); failure = 'Loading PDF document: ' + this._exceptionToString(e);
}
this._nextPage(task, failure);
},
_cleanup: function Driver_cleanup() {
// Clear out all the stylesheets since a new one is created for each font.
while (document.styleSheets.length > 0) {
var styleSheet = document.styleSheets[0];
while (styleSheet.cssRules.length > 0) {
styleSheet.deleteRule(0);
}
var ownerNode = styleSheet.ownerNode;
ownerNode.parentNode.removeChild(ownerNode);
}
var body = document.body;
while (body.lastChild !== this.end) {
body.removeChild(body.lastChild);
}
// Wipe out the link to the pdfdoc so it can be GC'ed.
for (var i = 0; i < this.manifest.length; i++) {
if (this.manifest[i].pdfDoc) {
this.manifest[i].pdfDoc.destroy();
delete this.manifest[i].pdfDoc;
}
}
},
_exceptionToString: function Driver_exceptionToString(e) {
if (typeof e !== 'object') {
return String(e);
}
if (!('message' in e)) {
return JSON.stringify(e);
}
return e.message + ('stack' in e ? ' at ' + e.stack.split('\n')[0] : '');
},
_getLastPageNumber: function Driver_getLastPageNumber(task) {
if (!task.pdfDoc) {
return task.firstPage || 1;
}
var lastPageNumber = task.lastPage || 0;
if (!lastPageNumber || lastPageNumber > task.pdfDoc.numPages) {
lastPageNumber = task.pdfDoc.numPages;
}
return lastPageNumber;
},
_nextPage: function Driver_nextPage(task, loadError) {
var self = this;
var failure = loadError || '';
if (!task.pdfDoc) {
var dataUrl = this.canvas.toDataURL('image/png');
this._sendResult(dataUrl, task, failure, function () {
self._log('done' + (failure ? ' (failed !: ' + failure + ')' : '') +
'\n');
self.currentTask++;
self._nextTask();
});
return;
}
if (task.pageNum > this._getLastPageNumber(task)) {
if (++task.round < task.rounds) {
this._log(' Round ' + (1 + task.round) + '\n');
task.pageNum = task.firstPage || 1;
} else {
this.currentTask++;
this._nextTask();
return;
}
}
if (task.skipPages && task.skipPages.indexOf(task.pageNum) >= 0) {
this._log(' Skipping page ' + task.pageNum + '/' +
task.pdfDoc.numPages + '... ');
// Empty the canvas
this.canvas.width = 1;
this.canvas.height = 1;
this._clearCanvas();
this._snapshot(task, '');
return;
}
if (!failure) {
try {
this._log(' Loading page ' + task.pageNum + '/' +
task.pdfDoc.numPages + '... ');
var ctx = this.canvas.getContext('2d');
task.pdfDoc.getPage(task.pageNum).then(function(page) {
var viewport = page.getViewport(PDF_TO_CSS_UNITS);
self.canvas.width = viewport.width;
self.canvas.height = viewport.height;
self._clearCanvas();
var drawContext, textLayerBuilder;
var resolveInitPromise;
var initPromise = new Promise(function (resolve) {
resolveInitPromise = resolve;
});
if (task.type === 'text') {
// Using a dummy canvas for PDF context drawing operations
if (!self.dummyCanvas) {
self.dummyCanvas = document.createElement('canvas');
}
drawContext = self.dummyCanvas.getContext('2d');
// The text builder will draw its content on the test canvas
textLayerBuilder = new SimpleTextLayerBuilder(ctx, viewport);
page.getTextContent().then(function(textContent) {
textLayerBuilder.setTextContent(textContent);
resolveInitPromise();
});
} else {
drawContext = ctx;
textLayerBuilder = new NullTextLayerBuilder();
resolveInitPromise();
}
var renderContext = {
canvasContext: drawContext,
viewport: viewport
};
var completeRender = (function(error) {
page.destroy();
task.stats = page.stats;
page.stats = new StatTimer();
self._snapshot(task, error);
});
initPromise.then(function () {
page.render(renderContext).promise.then(function() {
completeRender(false);
},
function(error) {
completeRender('render : ' + error);
});
});
}, },
function(error) { function(error) {
completeRender('render : ' + error); self._snapshot(task, 'render : ' + error);
}); });
}); } catch (e) {
}, failure = 'page setup : ' + this._exceptionToString(e);
function(error) { this._snapshot(task, failure);
snapshotCurrentPage(task, 'render : ' + error);
});
} catch (e) {
failure = 'page setup : ' + exceptionToString(e);
snapshotCurrentPage(task, failure);
}
}
}
function snapshotCurrentPage(task, failure) {
log('done, snapshotting... ');
sendTaskResult(canvasToDataURL(), task, failure, function () {
log('done' + (failure ? ' (failed !: ' + failure + ')' : '') + '\n');
++task.pageNum;
nextPage(task);
});
}
function sendQuitRequest(cb) {
var r = new XMLHttpRequest();
r.open('POST', '/tellMeToQuit?path=' + escape(appPath), false);
r.onreadystatechange = function sendQuitRequestOnreadystatechange(e) {
if (r.readyState === 4) {
if (cb) {
cb();
}
}
};
r.send(null);
}
function quitApp() {
log('Done !');
document.body.innerHTML = 'Tests are finished. <h1>CLOSE ME!</h1>' +
document.body.innerHTML;
sendQuitRequest(function () {
window.close();
});
}
function done() {
if (inFlightRequests > 0) {
document.getElementById('inFlightCount').innerHTML = inFlightRequests;
setTimeout(done, 100);
} else {
setTimeout(quitApp, 100);
}
}
function sendTaskResult(snapshot, task, failure, callback) {
var result = JSON.stringify({
browser: browser,
id: task.id,
numPages: task.pdfDoc ?
(task.lastPage || task.pdfDoc.numPages) : 0,
lastPageNum: getLastPageNum(task),
failure: failure,
file: task.file,
round: task.round,
page: task.pageNum,
snapshot: snapshot,
stats: task.stats.times
});
send('/submit_task_results', result, callback);
}
function send(url, message, callback) {
var r = new XMLHttpRequest();
// (The POST URI is ignored atm.)
r.open('POST', url, true);
r.setRequestHeader('Content-Type', 'application/json');
r.onreadystatechange = function sendTaskResultOnreadystatechange(e) {
if (r.readyState === 4) {
inFlightRequests--;
// Retry until successful
if (r.status !== 200) {
setTimeout(function() {
send(url, message);
});
}
if (callback) {
if (letItCooldown) {
setTimeout(callback, 100);
} else {
callback();
} }
} }
},
_clearCanvas: function Driver_clearCanvas() {
var ctx = this.canvas.getContext('2d');
ctx.beginPath();
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
_snapshot: function Driver_snapshot(task, failure) {
var self = this;
this._log('Snapshotting... ');
var dataUrl = this.canvas.toDataURL('image/png');
this._sendResult(dataUrl, task, failure, function () {
self._log('done' + (failure ? ' (failed !: ' + failure + ')' : '') +
'\n');
task.pageNum++;
self._nextPage(task);
});
},
_quit: function Driver_quit() {
this._log('Done !');
this.end.textContent = 'Tests finished. Close this window!';
// Send the quit request
var r = new XMLHttpRequest();
r.open('POST', '/tellMeToQuit?path=' + escape(this.appPath), false);
r.onreadystatechange = function(e) {
if (r.readyState === 4) {
window.close();
}
};
r.send(null);
},
_info: function Driver_info(message) {
this._send('/info', JSON.stringify({
browser: this.browser,
message: message
}));
},
_log: function Driver_log(message) {
// Using insertAdjacentHTML yields a large performance gain and
// reduces runtime significantly.
if (this.output.insertAdjacentHTML) {
this.output.insertAdjacentHTML('BeforeEnd', message);
} else {
this.output.textContent += message;
}
if (message.lastIndexOf('\n') >= 0 && !this.disableScrolling.checked) {
// Scroll to the bottom of the page
this.output.scrollTop = this.output.scrollHeight;
}
},
_done: function Driver_done() {
if (this.inFlightRequests > 0) {
this.inflight.textContent = this.inFlightRequests;
setTimeout(this._done(), WAITING_TIME);
} else {
setTimeout(this._quit(), WAITING_TIME);
}
},
_sendResult: function Driver_sendResult(snapshot, task, failure,
callback) {
var result = JSON.stringify({
browser: this.browser,
id: task.id,
numPages: task.pdfDoc ?
(task.lastPage || task.pdfDoc.numPages) : 0,
lastPageNum: this._getLastPageNumber(task),
failure: failure,
file: task.file,
round: task.round,
page: task.pageNum,
snapshot: snapshot,
stats: task.stats.times
});
this._send('/submit_task_results', result, callback);
},
_send: function Driver_send(url, message, callback) {
var self = this;
var r = new XMLHttpRequest();
r.open('POST', url, true);
r.setRequestHeader('Content-Type', 'application/json');
r.onreadystatechange = function(e) {
if (r.readyState === 4) {
self.inFlightRequests--;
// Retry until successful
if (r.status !== 200) {
setTimeout(function() {
self._send(url, message);
});
}
if (callback) {
callback();
}
}
};
this.inflight.textContent = this.inFlightRequests++;
r.send(message);
} }
}; };
document.getElementById('inFlightCount').innerHTML = inFlightRequests++;
r.send(message);
}
function info(message) { return Driver;
send('/info', JSON.stringify({ })();
browser: browser,
message: message
}));
}
function clear(ctx) {
ctx.beginPath();
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
/* Auto-scroll if the scrollbar is near the bottom, otherwise do nothing. */
function checkScrolling() {
if ((stdout.scrollHeight - stdout.scrollTop) <= stdout.offsetHeight) {
stdout.scrollTop = stdout.scrollHeight;
}
}
function log(str) {
if (stdout.insertAdjacentHTML) {
stdout.insertAdjacentHTML('BeforeEnd', str);
} else {
stdout.innerHTML += str;
}
if (str.lastIndexOf('\n') >= 0) {
checkScrolling();
}
}
})(); // DriverClosure

View File

@ -1,6 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- <!--
Copyright 2012 Mozilla Foundation Copyright 2015 Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -14,34 +14,36 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<html> <html>
<head> <head>
<title>pdf.js test slave</title> <title>PDF.js test slave</title>
<style type="text/css"></style> <meta charset="utf-8">
<script src="/src/shared/util.js"></script> <script src="../src/shared/util.js"></script>
<script src="/src/display/api.js"></script> <script src="../src/display/api.js"></script>
<script src="/src/display/metadata.js"></script> <script src="../src/display/metadata.js"></script>
<script src="/src/display/canvas.js"></script> <script src="../src/display/canvas.js"></script>
<script src="/src/display/webgl.js"></script> <script src="../src/display/webgl.js"></script>
<script src="/src/display/pattern_helper.js"></script> <script src="../src/display/pattern_helper.js"></script>
<script src="/src/display/font_loader.js"></script> <script src="../src/display/font_loader.js"></script>
<script src="/src/display/annotation_helper.js"></script> <script src="../src/display/annotation_helper.js"></script>
<script src="driver.js"></script> <script src="driver.js"></script>
<script>
PDFJS.workerSrc = '/src/worker_loader.js';
</script>
</head> </head>
<body> <body>
<pre style="width:800px; height:800px; overflow:scroll;" id="stdout"></pre> <p>Inflight requests: <span id="inflight"></span></p>
<p>Inflight requests: <span id="inFlightCount"></span></p> <p>
<div id="content-end"></div> <input type="checkbox" id="disableScrolling">
<label for="disableScrolling">Disable automatic scrolling</label>
<script> </p>
'use strict'; <pre id="output" style="max-height: 800px; overflow-y: scroll;"></pre>
load(); <div id="end"></div>
</script>
</body> </body>
<script>
var driver = new Driver({
disableScrolling: document.getElementById('disableScrolling'),
inflight: document.getElementById('inflight'),
output: document.getElementById('output'),
end: document.getElementById('end')
});
driver.run();
</script>
</html> </html>