diff --git a/images/buttons.png b/images/buttons.png index 682212660..3357b47d6 100644 Binary files a/images/buttons.png and b/images/buttons.png differ diff --git a/images/source/FileButton.psd.zip b/images/source/FileButton.psd.zip new file mode 100644 index 000000000..1f2b51cee Binary files /dev/null and b/images/source/FileButton.psd.zip differ diff --git a/multi-page-viewer.css b/multi-page-viewer.css index f9a7837b1..7f4701022 100644 --- a/multi-page-viewer.css +++ b/multi-page-viewer.css @@ -84,7 +84,7 @@ span { background-color: #eee; border-bottom: 1px solid #666; padding: 4px 0px 0px 8px; - position:fixed; + position: fixed; left: 0px; top: 0px; height: 40px; @@ -136,10 +136,61 @@ span { background: url('images/buttons.png') no-repeat -28px 0px; } +#openFileButton { + background: url('images/buttons.png') no-repeat -56px -23px; + cursor: default; + display: inline-block; + float: left; + margin: 0px 0px 0px 3px; + width: 29px; + height: 23px; +} + +#openFileButton.down { + background: url('images/buttons.png') no-repeat -56px -46px; +} + +#openFileButton.disabled { + background: url('images/buttons.png') no-repeat -56px 0px; +} + +#fileInput { + display: none; +} + #pageNumber { text-align: right; } +#sidebar { + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + width: 150px; + top: 62px; + bottom: 18px; + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + -moz-border-radius-topright: 8px; + -moz-border-radius-bottomright: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-border-bottom-right-radius: 8px; +} + +#sidebarScrollView { + position: absolute; + overflow: hidden; + overflow-y: auto; + top: 40px; + right: 10px; + bottom: 10px; + left: 10px; +} + +#sidebarContentView { + height: auto; + width: 100px; +} + #viewer { margin: 44px 0px 0px; padding: 8px 0px; diff --git a/multi-page-viewer.html b/multi-page-viewer.html index 4e15cf4f8..ffbdfe707 100644 --- a/multi-page-viewer.html +++ b/multi-page-viewer.html @@ -33,7 +33,19 @@ Zoom + + + + Open File + +
diff --git a/multi-page-viewer.js b/multi-page-viewer.js index 9d9cec702..baad7809e 100644 --- a/multi-page-viewer.js +++ b/multi-page-viewer.js @@ -12,6 +12,7 @@ var PDFViewer = { nextPageButton: null, pageNumberInput: null, scaleSelect: null, + fileInput: null, willJumpToPage: false, @@ -215,7 +216,7 @@ var PDFViewer = { } }, - open: function(url) { + openURL: function(url) { PDFViewer.url = url; document.title = url; @@ -231,26 +232,35 @@ var PDFViewer = { req.responseArrayBuffer || req.response; - PDFViewer.pdf = new PDFDoc(new Stream(data)); - PDFViewer.numberOfPages = PDFViewer.pdf.numPages; - document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); - - for (var i = 1; i <= PDFViewer.numberOfPages; i++) { - PDFViewer.createPage(i); - } - - if (PDFViewer.numberOfPages > 0) { - PDFViewer.drawPage(1); - } - - PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? - 'disabled' : ''; - PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? - 'disabled' : ''; + PDFViewer.readPDF(data); } }; req.send(null); + }, + + readPDF: function(data) { + while (PDFViewer.element.hasChildNodes()) { + PDFViewer.element.removeChild(PDFViewer.element.firstChild); + } + + PDFViewer.pdf = new PDFDoc(new Stream(data)); + PDFViewer.numberOfPages = PDFViewer.pdf.numPages; + document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString(); + + for (var i = 1; i <= PDFViewer.numberOfPages; i++) { + PDFViewer.createPage(i); + } + + if (PDFViewer.numberOfPages > 0) { + PDFViewer.drawPage(1); + document.location.hash = 1; + } + + PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? + 'disabled' : ''; + PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? + 'disabled' : ''; } }; @@ -354,11 +364,63 @@ window.onload = function() { PDFViewer.scaleSelect.onchange = function(evt) { PDFViewer.changeScale(parseInt(this.value)); }; + + if (window.File && window.FileReader && window.FileList && window.Blob) { + var openFileButton = document.getElementById('openFileButton'); + openFileButton.onclick = function(evt) { + if (this.className.indexOf('disabled') === -1) { + PDFViewer.fileInput.click(); + } + }; + openFileButton.onmousedown = function(evt) { + if (this.className.indexOf('disabled') === -1) { + this.className = 'down'; + } + }; + openFileButton.onmouseup = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + openFileButton.onmouseout = function(evt) { + this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; + }; + + PDFViewer.fileInput = document.getElementById('fileInput'); + PDFViewer.fileInput.onchange = function(evt) { + var files = evt.target.files; + + if (files.length > 0) { + var file = files[0]; + var fileReader = new FileReader(); + + document.title = file.name; + + // Read the local file into a Uint8Array. + fileReader.onload = function(evt) { + var data = evt.target.result; + var buffer = new ArrayBuffer(data.length); + var uint8Array = new Uint8Array(buffer); + + for (var i = 0; i < data.length; i++) { + uint8Array[i] = data.charCodeAt(i); + } + + PDFViewer.readPDF(uint8Array); + }; + + // Read as a binary string since "readAsArrayBuffer" is not yet + // implemented in Firefox. + fileReader.readAsBinaryString(file); + } + }; + PDFViewer.fileInput.value = null; + } else { + document.getElementById('fileWrapper').style.display = 'none'; + } PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber; PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0; - PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url); + PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url); window.onscroll = function(evt) { var lastPagesDrawn = PDFViewer.lastPagesDrawn; diff --git a/pdf.js b/pdf.js index 1b751b5a4..297bd38f1 100644 --- a/pdf.js +++ b/pdf.js @@ -792,6 +792,9 @@ var Dict = (function() { get2: function(key1, key2) { return this.get(key1) || this.get(key2); }, + get3: function(key1, key2, key3) { + return this.get(key1) || this.get(key2) || this.get(key3); + }, has: function(key) { return key in this.map; }, @@ -2263,7 +2266,7 @@ var CanvasGraphics = (function() { assertWellFormed(IsName(fontName), "invalid font name"); fontName = fontName.name.replace("+", "_"); - var fontFile = descriptor.get2("FontFile", "FontFile2"); + var fontFile = descriptor.get3("FontFile", "FontFile2", "FontFile3"); if (!fontFile) error("FontFile not found for font: " + fontName); fontFile = xref.fetchIfRef(fontFile); @@ -2629,7 +2632,7 @@ var CanvasGraphics = (function() { setWordSpacing: function(spacing) { TODO("word spacing"); }, - setHSpacing: function(scale) { + setHScale: function(scale) { TODO("horizontal text scale"); }, setLeading: function(leading) { diff --git a/test.py b/test.py index 46d30fef5..dae723b8a 100644 --- a/test.py +++ b/test.py @@ -1,7 +1,10 @@ -import json, os, sys, subprocess +import json, os, sys, subprocess, urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer +from urlparse import urlparse ANAL = True +DEFAULT_MANIFEST_FILE = 'test_manifest.json' +REFDIR = 'ref' VERBOSE = False MIMEs = { @@ -34,8 +37,11 @@ class PDFTestHandler(BaseHTTPRequestHandler): BaseHTTPRequestHandler.log_request(code, size) def do_GET(self): + url = urlparse(self.path) + # Ignore query string + path, _ = url.path, url.query cwd = os.getcwd() - path = os.path.abspath(os.path.realpath(cwd + os.sep + self.path)) + path = os.path.abspath(os.path.realpath(cwd + os.sep + path)) cwd = os.path.abspath(cwd) prefix = os.path.commonprefix(( path, cwd )) _, ext = os.path.splitext(path) @@ -69,19 +75,21 @@ class PDFTestHandler(BaseHTTPRequestHandler): self.end_headers() result = json.loads(self.rfile.read(numBytes)) - browser = 'firefox4' - id, failure, round, page, snapshot = result['id'], result['failure'], result['round'], result['page'], result['snapshot'] + browser, id, failure, round, page, snapshot = result['browser'], result['id'], result['failure'], result['round'], result['page'], result['snapshot'] taskResults = State.taskResults[browser][id] - taskResults[round][page - 1] = Result(snapshot, failure) + taskResults[round].append(Result(snapshot, failure)) + assert len(taskResults[round]) == page if result['taskDone']: check(State.manifest[id], taskResults, browser) + # Please oh please GC this ... + del State.taskResults[browser][id] State.remaining -= 1 State.done = (0 == State.remaining) -def set_up(): +def set_up(manifestFile): # Only serve files from a pdf.js clone assert not ANAL or os.path.isfile('pdf.js') and os.path.isdir('.git') @@ -90,10 +98,27 @@ def set_up(): #'chrome12', 'chrome13', 'firefox5', 'firefox6','opera11' ): if os.access(b, os.R_OK | os.X_OK) ] - mf = open('test_manifest.json') + mf = open(manifestFile) manifestList = json.load(mf) mf.close() + for item in manifestList: + f, isLink = item['file'], item.get('link', False) + if isLink and not os.access(f, os.R_OK): + linkFile = open(f +'.link') + link = linkFile.read() + linkFile.close() + + sys.stdout.write('Downloading '+ link +' to '+ f +' ...') + sys.stdout.flush() + response = urllib2.urlopen(link) + + out = open(f, 'w') + out.write(response.read()) + out.close() + + print 'done' + for b in testBrowsers: State.taskResults[b] = { } for item in manifestList: @@ -101,15 +126,16 @@ def set_up(): State.manifest[id] = item taskResults = [ ] for r in xrange(rounds): - taskResults.append([ None ] * 100) + taskResults.append([ ]) State.taskResults[b][id] = taskResults State.remaining = len(manifestList) for b in testBrowsers: print 'Launching', b + qs = 'browser='+ b +'&manifestFile='+ manifestFile subprocess.Popen(( os.path.abspath(os.path.realpath(b)), - 'http://localhost:8080/test_slave.html' )) + 'http://localhost:8080/test_slave.html?'+ qs)) def check(task, results, browser): @@ -129,7 +155,7 @@ def check(task, results, browser): return kind = task['type'] - if '==' == kind: + if 'eq' == kind: checkEq(task, results, browser) elif 'fbf' == kind: checkFBF(task, results, browser) @@ -140,23 +166,42 @@ def check(task, results, browser): def checkEq(task, results, browser): - print ' !!! [TODO: == tests] !!!' - print 'TEST-PASS | == test', task['id'], '| in', browser + pfx = os.path.join(REFDIR, sys.platform, browser, task['id']) + results = results[0] + passed = True + for page in xrange(len(results)): + ref = None + try: + path = os.path.join(pfx, str(page + 1)) + f = open(path) + ref = f.read() + f.close() + except IOError, ioe: + continue + + snapshot = results[page] + if ref != snapshot: + print 'TEST-UNEXPECTED-FAIL | eq', task['id'], '| in', browser, '| rendering of page', page + 1, '!= reference rendering' + passed = False + if passed: + print 'TEST-PASS | eq test', task['id'], '| in', browser -printed = [False] def checkFBF(task, results, browser): round0, round1 = results[0], results[1] assert len(round0) == len(round1) + passed = True for page in xrange(len(round1)): r0Page, r1Page = round0[page], round1[page] if r0Page is None: break if r0Page.snapshot != r1Page.snapshot: print 'TEST-UNEXPECTED-FAIL | forward-back-forward test', task['id'], '| in', browser, '| first rendering of page', page + 1, '!= second' - print 'TEST-PASS | forward-back-forward test', task['id'], '| in', browser + passed = False + if passed: + print 'TEST-PASS | forward-back-forward test', task['id'], '| in', browser def checkLoad(task, results, browser): @@ -165,11 +210,12 @@ def checkLoad(task, results, browser): print 'TEST-PASS | load test', task['id'], '| in', browser -def main(): - set_up() +def main(args): + manifestFile = args[0] if len(args) == 1 else DEFAULT_MANIFEST_FILE + set_up(manifestFile) server = HTTPServer(('127.0.0.1', 8080), PDFTestHandler) while not State.done: server.handle_request() if __name__ == '__main__': - main() + main(sys.argv[1:]) diff --git a/test_manifest.json b/test_manifest.json index 2f45a026c..036b7aafc 100644 --- a/test_manifest.json +++ b/test_manifest.json @@ -1,8 +1,8 @@ [ - { "id": "tracemonkey-==", + { "id": "tracemonkey-eq", "file": "tests/tracemonkey.pdf", "rounds": 1, - "type": "==" + "type": "eq" }, { "id": "tracemonkey-fbf", "file": "tests/tracemonkey.pdf", @@ -13,5 +13,11 @@ "file": "tests/canvas.pdf", "rounds": 1, "type": "load" + }, + { "id": "pdfspec-load", + "file": "tests/pdf.pdf", + "link": true, + "rounds": 1, + "type": "load" } ] diff --git a/test_slave.html b/test_slave.html index c560d90d0..cff9b3f7d 100644 --- a/test_slave.html +++ b/test_slave.html @@ -5,9 +5,24 @@