diff --git a/test/driver.js b/test/driver.js index 88be8a7ff..5ffe5561c 100644 --- a/test/driver.js +++ b/test/driver.js @@ -18,438 +18,458 @@ 'use strict'; -/* - * A Test Driver for PDF.js +var WAITING_TIME = 100; // ms +var PDF_TO_CSS_UNITS = 96.0 / 72.0; + +/** + * @class */ -(function DriverClosure() { +var NullTextLayerBuilder = (function NullTextLayerBuilderClosure() { + /** + * @constructs NullTextLayerBuilder + */ + function NullTextLayerBuilder() {} -PDFJS.enableStats = true; -PDFJS.cMapUrl = '../external/bcmaps/'; -PDFJS.cMapPacked = true; + NullTextLayerBuilder.prototype = { + beginLayout: function NullTextLayerBuilder_BeginLayout() {}, + endLayout: function NullTextLayerBuilder_EndLayout() {}, + appendText: function NullTextLayerBuilder_AppendText() {} + }; -var appPath, masterMode, browser, canvas, dummyCanvas, currentTaskIdx, - manifest, stdout; -var inFlightRequests = 0; + return NullTextLayerBuilder; +})(); -// Chrome for Windows locks during testing on low end machines -var letItCooldown = /Windows.*?Chrom/i.test(navigator.userAgent); - -function queryParams() { - var qs = window.location.search.substring(1); - var kvs = qs.split('&'); - var params = { }; - for (var i = 0; i < kvs.length; ++i) { - var kv = kvs[i].split('='); - params[unescape(kv[0])] = unescape(kv[1]); +/** + * @class + */ +var SimpleTextLayerBuilder = (function SimpleTextLayerBuilderClosure() { + /** + * @constructs SimpleTextLayerBuilder + */ + function SimpleTextLayerBuilder(ctx, viewport) { + this.ctx = ctx; + this.viewport = viewport; + this.textCounter = 0; } - return params; -} -window.load = function load() { - var params = queryParams(); - browser = params.browser; - var manifestFile = params.manifestFile; - appPath = params.path; - masterMode = params.masterMode === 'True'; - var delay = params.delay || 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)); - canvas = document.createElement('canvas'); - stdout = document.getElementById('stdout'); + 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]); - info('User Agent: ' + navigator.userAgent); - log('load...\n'); + this.textCounter++; + }, - log('Harness thinks this browser is "' + browser + '" with path "' + - appPath + '"\n'); - log('Fetching manifest "' + manifestFile + '"... '); - - var r = new XMLHttpRequest(); - r.open('GET', manifestFile, false); - r.onreadystatechange = function loadOnreadystatechange(e) { - if (r.readyState === 4) { - log('done\n'); - manifest = JSON.parse(r.responseText); - currentTaskIdx = 0; - nextTask(); + 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(); } }; - 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) { - // 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 guard = document.getElementById('content-end'); - var body = document.body; - while (body.lastChild !== guard) { - body.removeChild(body.lastChild); + return SimpleTextLayerBuilder; +})(); + +/** + * @typedef {Object} DriverOptions + * @property {HTMLSpanElement} inflight - Field displaying the number of + * inflight requests. + * @property {HTMLInputElement} disableScrolling - Checkbox to disable + * automatic scrolling of the output container. + * @property {HTMLPreElement} output - Container for all output messages. + * @property {HTMLDivElement} end - Container for a completion message. + */ + +/** + * @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. - for (var i = 0; i < manifest.length; i++) { - if (manifest[i].pdfDoc) { - manifest[i].pdfDoc.destroy(); - delete manifest[i].pdfDoc; - } - } - if (letItCooldown) { - setTimeout(callback, 500); - } else { - callback(); - } -} + Driver.prototype = { + _getQueryStringParameters: function Driver_getQueryStringParameters() { + var queryString = window.location.search.substring(1); + var values = queryString.split('&'); + var parameters = {}; + for (var i = 0, ii = values.length; i < ii; i++) { + var value = values[i].split('='); + parameters[unescape(value[0])] = unescape(value[1]); + } + return parameters; + }, -function 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] : ''); -} + run: function Driver_run() { + var self = this; -function nextTask() { - cleanup(continueNextTask); -} + this._info('User agent: ' + navigator.userAgent); + this._log('Harness thinks this browser is "' + this.browser + + '" with path "' + this.appPath + '"\n'); + this._log('Fetching manifest "' + this.manifestFile + '"... '); -function continueNextTask() { - if (currentTaskIdx === manifest.length) { - done(); - return; - } - var task = manifest[currentTaskIdx]; - task.round = 0; - task.stats = {times: []}; - - 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 r = new XMLHttpRequest(); + r.open('GET', this.manifestFile, false); + r.onreadystatechange = function() { + if (r.readyState === 4) { + self._log('done\n'); + self.manifest = JSON.parse(r.responseText); + self.currentTask = 0; + self._nextTask(); } - var renderContext = { - canvasContext: drawContext, - viewport: viewport - }; - var completeRender = (function(error) { - page.destroy(); - task.stats = page.stats; - page.stats = new StatTimer(); - snapshotCurrentPage(task, error); + }; + if (this.delay > 0) { + this._log('\nDelaying for ' + this.delay + ' ms...\n'); + } + // When gathering the stats the numbers seem to be more reliable + // if the browser is given more time to start. + setTimeout(function() { + r.send(null); + }, 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 () { - page.render(renderContext).promise.then(function() { - completeRender(false); + return; + } catch (e) { + 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) { - completeRender('render : ' + error); + self._snapshot(task, 'render : ' + error); }); - }); - }, - function(error) { - 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.

CLOSE ME!

' + - 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(); + } catch (e) { + failure = 'page setup : ' + this._exceptionToString(e); + this._snapshot(task, failure); } } + }, + + _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) { - 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 + return Driver; +})(); diff --git a/test/test_slave.html b/test/test_slave.html index 83a7abedd..8a78e978b 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -1,6 +1,6 @@ - - pdf.js test slave - - - - - - - - - + PDF.js test slave + + + + + + + + + - - - -

-    

Inflight requests:

-
- - +

Inflight requests:

+

+ + +

+

+    
+