diff --git a/pdf.js b/pdf.js index 2d05295c1..82cfb4c81 100644 --- a/pdf.js +++ b/pdf.js @@ -1,4 +1,4 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ 'use strict'; @@ -18,6 +18,16 @@ function warn(msg) { log('Warning: ' + msg); } +function backtrace() { + var stackStr; + try { + throw new Error(); + } catch (e) { + stackStr = e.stack; + } + return stackStr.split('\n').slice(1).join('\n'); +} + function error(msg) { log(backtrace()); throw new Error(msg); @@ -44,23 +54,13 @@ function assertWellFormed(cond, msg) { malformed(msg); } -function backtrace() { - var stackStr; - try { - throw new Error(); - } catch (e) { - stackStr = e.stack; - } - return stackStr.split('\n').slice(1).join('\n'); -} - function shadow(obj, prop, value) { try { Object.defineProperty(obj, prop, { value: value, enumerable: true, configurable: true, writable: false }); - } catch(e) { + } catch (e) { obj.__defineGetter__(prop, function() { return value; }); @@ -185,7 +185,7 @@ var DecodeStream = (function() { var buffer2 = new Uint8Array(size); for (var i = 0; i < current; ++i) buffer2[i] = buffer[i]; - return this.buffer = buffer2; + return (this.buffer = buffer2); }, getByte: function decodestream_getByte() { var pos = this.pos; @@ -197,11 +197,11 @@ var DecodeStream = (function() { return this.buffer[this.pos++]; }, getBytes: function decodestream_getBytes(length) { - var pos = this.pos; + var end, pos = this.pos; if (length) { this.ensureBuffer(pos + length); - var end = pos + length; + end = pos + length; while (!this.eof && this.bufferLength < end) this.readBlock(); @@ -213,7 +213,7 @@ var DecodeStream = (function() { while (!this.eof) this.readBlock(); - var end = this.bufferLength; + end = this.bufferLength; // checking if bufferLength is still 0 then // the buffer has to be initialized @@ -265,7 +265,7 @@ var FakeStream = (function() { function constructor(stream) { this.dict = stream.dict; DecodeStream.call(this); - }; + } constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlock = function() { @@ -276,11 +276,11 @@ var FakeStream = (function() { }; constructor.prototype.getBytes = function(length) { - var pos = this.pos; + var end, pos = this.pos; if (length) { this.ensureBuffer(pos + length); - var end = pos + length; + end = pos + length; while (!this.eof && this.bufferLength < end) this.readBlock(); @@ -290,7 +290,7 @@ var FakeStream = (function() { end = bufEnd; } else { this.eof = true; - var end = this.bufferLength; + end = this.bufferLength; } this.pos = end; @@ -532,8 +532,8 @@ var FlateStream = (function() { constructor.prototype.readBlock = function() { function repeat(stream, array, len, offset, what) { - var repeat = stream.getBits(len) + offset; - while (repeat-- > 0) + var repeatLength = stream.getBits(len) + offset; + while (repeatLength-- > 0) array[i++] = what; } @@ -821,8 +821,8 @@ var PredictorStream = (function() { currentRow[i] = up + c; else currentRow[i] = upLeft + c; - break; } + break; default: error('Unsupported predictor: ' + predictor); break; @@ -1621,6 +1621,7 @@ var CCITTFaxStream = (function() { this.err = false; + var code1, code2, code3; if (this.nextLine2D) { for (var i = 0; codingLine[i] < columns; ++i) refLine[i] = codingLine[i]; @@ -1633,7 +1634,7 @@ var CCITTFaxStream = (function() { blackPixels = 0; while (codingLine[this.codingPos] < columns) { - var code1 = this.getTwoDimCode(); + code1 = this.getTwoDimCode(); switch (code1) { case twoDimPass: this.addPixels(refLine[refPos + 1], blackPixels); @@ -1641,9 +1642,8 @@ var CCITTFaxStream = (function() { refPos += 2; break; case twoDimHoriz: - var code1 = 0, code2 = 0; + code1 = code2 = 0; if (blackPixels) { - var code3; do { code1 += (code3 = this.getBlackCode()); } while (code3 >= 64); @@ -1651,7 +1651,6 @@ var CCITTFaxStream = (function() { code2 += (code3 = this.getWhiteCode()); } while (code3 >= 64); } else { - var code3; do { code1 += (code3 = this.getWhiteCode()); } while (code3 >= 64); @@ -1831,7 +1830,6 @@ var CCITTFaxStream = (function() { this.eof = true; } } else if (this.err && this.eoline) { - var code1; while (true) { code1 = this.lookBits(13); if (code1 == EOF) { @@ -2058,7 +2056,7 @@ var CCITTFaxStream = (function() { constructor.prototype.eatBits = function(n) { if ((this.inputBits -= n) < 0) this.inputBits = 0; - } + }; return constructor; })(); @@ -2361,7 +2359,7 @@ var Lexer = (function() { constructor.isSpace = function(ch) { return ch == ' ' || ch == '\t'; - } + }; // A '1' in this array means the character is white space. A '1' or // '2' means the character ends a name or command. @@ -2403,7 +2401,7 @@ var Lexer = (function() { var floating = false; var str = ch; var stream = this.stream; - do { + for (;;) { ch = stream.lookChar(); if (ch == '.' && !floating) { str += ch; @@ -2421,7 +2419,7 @@ var Lexer = (function() { break; } stream.skip(); - } while (true); + } var value = parseFloat(str); if (isNaN(value)) error('Invalid floating point number: ' + value); @@ -2434,7 +2432,8 @@ var Lexer = (function() { var stream = this.stream; var ch; do { - switch (ch = stream.getChar()) { + ch = stream.getChar(); + switch (ch) { case undefined: warn('Unterminated string'); done = true; @@ -2451,7 +2450,8 @@ var Lexer = (function() { } break; case '\\': - switch (ch = stream.getChar()) { + ch = stream.getChar(); + switch (ch) { case undefined: warn('Unterminated string'); done = true; @@ -2541,7 +2541,7 @@ var Lexer = (function() { getHexString: function(ch) { var str = ''; var stream = this.stream; - while (1) { + for (;;) { ch = stream.getChar(); if (ch == '>') { break; @@ -2804,7 +2804,7 @@ var Parser = (function() { if (xref) length = xref.fetchIfRef(length); if (!IsInt(length)) { - error('Bad ' + Length + ' attribute in stream'); + error('Bad ' + length + ' attribute in stream'); length = 0; } @@ -3162,7 +3162,7 @@ var XRef = (function() { if (!IsCmd(obj3, 'obj')) { // some bad pdfs use "obj1234" and really mean 1234 if (obj3.cmd.indexOf('obj') == 0) { - var num = parseInt(obj3.cmd.substring(3)); + num = parseInt(obj3.cmd.substring(3)); if (!isNaN(num)) return num; } @@ -3192,7 +3192,7 @@ var XRef = (function() { var i, entries = [], nums = []; // read the object numbers to populate cache for (i = 0; i < n; ++i) { - var num = parser.getObj(); + num = parser.getObj(); if (!IsInt(num)) { error('invalid object number in the ObjStm stream: ' + num); } @@ -3378,15 +3378,15 @@ var Page = (function() { rotatePoint: function(x, y) { var rotate = this.rotate; switch (rotate) { - default: - case 0: - return {x: x, y: this.height - y}; case 180: return {x: this.width - x, y: y}; case 90: return {x: this.width - y, y: this.height - x}; case 270: return {x: y, y: x}; + case 0: + default: + return {x: x, y: this.height - y}; } }, getLinks: function() { @@ -3548,7 +3548,7 @@ var Catalog = (function() { } }, get destinations() { - function fetchDestination(ref) { + function fetchDestination(xref, ref) { var dest = xref.fetchIfRef(ref); return IsDict(dest) ? dest.get('D') : dest; } @@ -3566,7 +3566,7 @@ var Catalog = (function() { obj = xref.fetchIfRef(nameDictionaryRef); obj.forEach(function(key, value) { if (!value) return; - dests[key] = fetchDestination(value); + dests[key] = fetchDestination(xref, value); }); } if (nameTreeRef) { @@ -3590,7 +3590,7 @@ var Catalog = (function() { } var names = obj.get('Names'); for (i = 0, n = names.length; i < n; i += 2) { - dests[names[i]] = fetchDestination(names[i + 1]); + dests[names[i]] = fetchDestination(xref, names[i + 1]); } } } @@ -4177,7 +4177,7 @@ var PartialEvaluator = (function() { return function(gfx) { for (var i = 0, length = argsArray.length; i < length; i++) gfx[fnArray[i]].apply(gfx, argsArray[i]); - } + }; }, translateFont: function(fontDict, xref, resources) { @@ -4268,11 +4268,11 @@ var PartialEvaluator = (function() { } else if (IsName(encoding)) { baseEncoding = Encodings[encoding.name].slice(); } else { - error("Encoding is not a Name nor a Dict"); + error('Encoding is not a Name nor a Dict'); } } - var fontType = subType.name; + var fontType = subType.name; if (!baseEncoding) { switch (fontType) { case 'TrueType': @@ -4310,11 +4310,11 @@ var PartialEvaluator = (function() { if (!isDisplayable(index)) glyphsMap[glyph] = encodingMap[i] += kCmapGlyphOffset; - } } - if (fontType == 'TrueType' && fontDict.has('ToUnicode') && differences) { + if (fontType == 'TrueType' && fontDict.has('ToUnicode') && + differences) { var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode')); if (IsName(cmapObj)) { error('ToUnicode file cmap translation not implemented'); @@ -4813,8 +4813,8 @@ var CanvasGraphics = (function() { size = (size <= kRasterizerMin) ? size * kScalePrecision : size; - var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') - : (fontObj.bold ? 'bold' : 'normal'); + var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') : + (fontObj.bold ? 'bold' : 'normal'); var italic = fontObj.italic ? 'italic' : 'normal'; var rule = italic + ' ' + bold + ' ' + size + 'px "' + name + '"'; @@ -5226,7 +5226,7 @@ var CanvasGraphics = (function() { })(); var Util = (function() { - function constructor() {}; + function constructor() {} constructor.makeCssRgb = function makergb(r, g, b) { var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0; return 'rgb(' + ri + ',' + gi + ',' + bi + ')'; @@ -5249,7 +5249,7 @@ var ColorSpace = (function() { // Constructor should define this.numComps, this.defaultColor, this.name function constructor() { error('should not call ColorSpace constructor'); - }; + } constructor.prototype = { // Input: array of size numComps representing color component values @@ -5284,18 +5284,14 @@ var ColorSpace = (function() { case 'DeviceGray': case 'G': return new DeviceGrayCS(); - break; case 'DeviceRGB': case 'RGB': return new DeviceRgbCS(); - break; case 'DeviceCMYK': case 'CMYK': return new DeviceCmykCS(); - break; case 'Pattern': return new PatternCS(null); - break; default: error('unrecognized colorspace ' + mode); } @@ -5307,30 +5303,25 @@ var ColorSpace = (function() { case 'DeviceGray': case 'G': return new DeviceGrayCS(); - break; case 'DeviceRGB': case 'RGB': return new DeviceRgbCS(); - break; case 'DeviceCMYK': case 'CMYK': return new DeviceCmykCS(); - break; case 'CalGray': return new DeviceGrayCS(); - break; case 'CalRGB': return new DeviceRgbCS(); - break; case 'ICCBased': var stream = xref.fetchIfRef(cs[1]); var dict = stream.dict; var numComps = dict.get('N'); if (numComps == 1) return new DeviceGrayCS(); - else if (numComps == 3) + if (numComps == 3) return new DeviceRgbCS(); - else if (numComps == 4) + if (numComps == 4) return new DeviceCmykCS(); break; case 'Pattern': @@ -5338,19 +5329,16 @@ var ColorSpace = (function() { if (baseCS) baseCS = ColorSpace.parse(baseCS, xref, res); return new PatternCS(baseCS); - break; case 'Indexed': var base = ColorSpace.parse(cs[1], xref, res); var hiVal = cs[2] + 1; var lookup = xref.fetchIfRef(cs[3]); return new IndexedCS(base, hiVal, lookup); - break; case 'Separation': var name = cs[1]; var alt = ColorSpace.parse(cs[2], xref, res); var tintFn = new PDFFunction(xref, xref.fetchIfRef(cs[3])); return new SeparationCS(alt, tintFn); - break; case 'Lab': case 'DeviceN': default: @@ -5440,7 +5428,7 @@ var IndexedCS = (function() { constructor.prototype = { getRgb: function indexcs_getRgb(color) { - var numComps = base.numComps; + var numComps = this.base.numComps; var start = color[0] * numComps; var c = []; @@ -5476,7 +5464,7 @@ var DeviceGrayCS = (function() { this.name = 'DeviceGray'; this.numComps = 1; this.defaultColor = [0]; - }; + } constructor.prototype = { getRgb: function graycs_getRgb(color) { @@ -5611,7 +5599,7 @@ var Pattern = (function() { // Constructor should define this.getPattern function constructor() { error('should not call Pattern constructor'); - }; + } constructor.prototype = { // Input: current Canvas context @@ -5675,14 +5663,14 @@ var Pattern = (function() { default: return new DummyShading(); } - } + }; return constructor; })(); var DummyShading = (function() { function constructor() { this.type = 'Pattern'; - }; + } constructor.prototype = { getPattern: function dummy_getpattern() { return 'hotpink'; @@ -5712,13 +5700,15 @@ var RadialAxialShading = (function() { var t0 = 0.0, t1 = 1.0; if (dict.has('Domain')) { var domainArr = dict.get('Domain'); - t0 = domainArr[0], t1 = domainArr[1]; + t0 = domainArr[0]; + t1 = domainArr[1]; } var extendStart = false, extendEnd = false; if (dict.has('Extend')) { var extendArr = dict.get('Extend'); - extendStart = extendArr[0], extendEnd = extendArr[1]; + extendStart = extendArr[0]; + extendEnd = extendArr[1]; TODO('Support extend'); } @@ -5747,7 +5737,7 @@ var RadialAxialShading = (function() { } this.colorStops = colorStops; - }; + } constructor.prototype = { getPattern: function() { @@ -5812,7 +5802,7 @@ var TilingPattern = (function() { var e = m[4] * tm[0] + m[5] * tm[2] + tm[4]; var f = m[4] * tm[1] + m[5] * tm[3] + tm[5]; return [a, b, c, d, e, f]; - }; + } TODO('TilingType'); @@ -5884,7 +5874,7 @@ var TilingPattern = (function() { graphics.execute(code, xref, res); this.canvas = tmpCanvas; - }; + } constructor.prototype = { getPattern: function tiling_getPattern() { @@ -5963,7 +5953,7 @@ var PDFImage = (function() { } else if (smask) { this.smask = new PDFImage(xref, res, smask); } - }; + } constructor.prototype = { getComponents: function getComponents(buffer, decodeMap) { @@ -6138,7 +6128,7 @@ var PDFFunction = (function() { error('Unknown type of function'); typeFn.call(this, fn, dict, xref); - }; + } constructor.prototype = { constructSampled: function(str, dict) { @@ -6184,7 +6174,7 @@ var PDFFunction = (function() { else if (v < min) v = min; return v; - } + }; if (inputSize != args.length) error('Incorrect number of arguments: ' + inputSize + ' != ' + @@ -6234,7 +6224,7 @@ var PDFFunction = (function() { } return output; - } + }; }, getSampleArray: function(size, outputSize, bps, str) { var length = 1; @@ -6282,7 +6272,7 @@ var PDFFunction = (function() { out.push(c0[j] + (x^n * diff[i])); return out; - } + }; }, constructStiched: function(fn, dict, xref) { var domain = dict.get('Domain'); @@ -6310,7 +6300,7 @@ var PDFFunction = (function() { else if (v < min) v = min; return v; - } + }; // clip to domain var v = clip(args[0], domain[0], domain[1]); @@ -6335,11 +6325,13 @@ var PDFFunction = (function() { // call the appropropriate function return fns[i].func([v2]); - } + }; }, constructPostScript: function() { TODO('unhandled type of function'); - this.func = function() { return [255, 105, 180]; } + this.func = function() { + return [255, 105, 180]; + }; } }; diff --git a/web/images/zoom-in.svg b/web/images/zoom-in.svg new file mode 100644 index 000000000..6eaed4481 --- /dev/null +++ b/web/images/zoom-in.svg @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Add + 2006-01-04 + + + Andreas Nilsson + + + http://tango-project.org + + + add + plus + + + + + + + + + + + + + + + + + + diff --git a/web/images/zoom-out.svg b/web/images/zoom-out.svg new file mode 100644 index 000000000..5f109a05c --- /dev/null +++ b/web/images/zoom-out.svg @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Remove + 2006-01-04 + + + Andreas Nilsson + + + http://tango-project.org + + + remove + delete + + + + + + + + + + + + + + + + + diff --git a/web/viewer.css b/web/viewer.css index a8578eb7e..d1f725a02 100755 --- a/web/viewer.css +++ b/web/viewer.css @@ -21,6 +21,8 @@ body { height: 40px; width: 100%; z-index: 1; + white-space:nowrap; + overflow: hidden; } .separator { @@ -109,13 +111,23 @@ span#info { } .thumbnail { - width: 104px; + width: 134px; height: 134px; - background-color: white; margin-top: 5px; margin-bottom: 5px; margin-left:auto; margin-right:auto; + line-height: 134px; + text-align: center; +} + +.thumbnail:not([data-loaded]) { + background-color: gray; +} + +.thumbnail > canvas { + vertical-align: middle; + display: inline-block; } #outlineScrollView { @@ -220,6 +232,14 @@ canvas { -webkit-box-shadow: 0px 2px 10px #ff0; } +#pageWidthOption { + border-top: 1px solid black; +} + +#customScaleOption { + display: none; +} + /* === Printed media overrides === */ @media print { #sidebar { diff --git a/web/viewer.html b/web/viewer.html index e02b3b9a1..d37270661 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -33,13 +33,25 @@
- + + + + + + + + +
diff --git a/web/viewer.js b/web/viewer.js index d57e47045..811cfcbcc 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -4,8 +4,10 @@ 'use strict'; var kDefaultURL = 'compressed.tracemonkey-pldi-09.pdf'; -var kDefaultScale = 150; +var kDefaultScale = 1.5; +var kDefaultScaleDelta = 1.1; var kCacheSize = 20; +var kCssUnits = 96.0 / 72.0; var Cache = function(size) { var data = []; @@ -21,12 +23,13 @@ var cache = new Cache(kCacheSize); var PDFView = { pages: [], thumbnails: [], + currentScale: kDefaultScale, - set scale(val) { + setScale: function(val, resetAutoSettings) { var pages = this.pages; - var cssUnits = 96.0 / 72.0; for (var i = 0; i < pages.length; i++) - pages[i].update(val / 100 * cssUnits); + pages[i].update(val * kCssUnits); + this.currentScale = val; if (document.location.hash == '#' + this.page) this.pages[this.page - 1].draw(); @@ -35,10 +38,42 @@ var PDFView = { document.location.hash = this.page; var event = document.createEvent('UIEvents'); - event.initUIEvent('scalechange', false, false, window, val); + event.initUIEvent('scalechange', false, false, window, 0); + event.scale = val; + event.resetAutoSettings = resetAutoSettings; window.dispatchEvent(event); }, + parseScale: function(value) { + if ('custom' == value) + return; + + var scale = parseFloat(value); + if (scale) { + this.setScale(scale, true); + return; + } + + var currentPage = this.pages[this.page - 1]; + var scrollbarPadding = 40; + var pageWidthScale = (window.innerWidth - scrollbarPadding) / + currentPage.width / kCssUnits; + var pageHeightScale = (window.innerHeight - scrollbarPadding) / + currentPage.height / kCssUnits; + if ('page-width' == value) + this.setScale(pageWidthScale); + else if ('page-fit' == value) + this.setScale(Math.min(pageWidthScale, pageHeightScale)); + }, + + zoomIn: function() { + this.setScale(this.currentScale * kDefaultScaleDelta, true); + }, + + zoomOut: function() { + this.setScale(this.currentScale / kDefaultScaleDelta, true); + }, + set page(val) { var pages = this.pages; var input = document.getElementById('pageNumber'); @@ -123,12 +158,13 @@ var PDFView = { var page = pdf.getPage(i); pages.push(new PageView(container, page, i, page.width, page.height, page.stats, this.navigateTo.bind(this))); - thumbnails.push(new ThumbnailView(sidebar, pages[i - 1])); + thumbnails.push(new ThumbnailView(sidebar, pages[i - 1], + page.width / page.height)); var pageRef = page.ref; pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i; } - this.scale = (scale || kDefaultScale); + this.setScale(scale || kDefaultScale, true); this.page = parseInt(document.location.hash.substring(1)) || 1; this.pagesRefMap = pagesRefMap; this.destinations = pdf.catalog.destinations; @@ -273,7 +309,7 @@ var PageView = function(container, content, id, width, height, }; }; -var ThumbnailView = function(container, page) { +var ThumbnailView = function(container, page, pageRatio) { var anchor = document.createElement('a'); anchor.href = '#' + page.id; @@ -292,8 +328,13 @@ var ThumbnailView = function(container, page) { canvas.id = 'thumbnail' + page.id; canvas.mozOpaque = true; - canvas.width = 104; - canvas.height = 134; + var maxThumbSize = 134; + canvas.width = pageRatio >= 1 ? maxThumbSize : + maxThumbSize * pageRatio; + canvas.height = pageRatio <= 1 ? maxThumbSize : + maxThumbSize / pageRatio; + + div.setAttribute('data-loaded', true); div.appendChild(canvas); var ctx = canvas.getContext('2d'); @@ -349,7 +390,7 @@ window.addEventListener('load', function(evt) { params[unescape(param[0])] = unescape(param[1]); } - PDFView.open(params.file || kDefaultURL, parseInt(params.scale)); + PDFView.open(params.file || kDefaultURL, parseFloat(params.scale)); if (!window.File || !window.FileReader || !window.FileList || !window.Blob) document.getElementById('fileInput').style.display = 'none'; @@ -361,7 +402,7 @@ window.addEventListener('pdfloaded', function(evt) { PDFView.load(evt.detail); }, true); -window.addEventListener('scroll', function onscroll(evt) { +function updateViewarea() { var visiblePages = PDFView.getVisiblePages(); for (var i = 0; i < visiblePages.length; i++) { var page = visiblePages[i]; @@ -379,8 +420,19 @@ window.addEventListener('scroll', function onscroll(evt) { PDFView.page = lastPage.id; else if (currentId < firstPage.id) PDFView.page = firstPage.id; +} + +window.addEventListener('scroll', function onscroll(evt) { + updateViewarea(); }, true); +window.addEventListener('resize', function onscroll(evt) { + if (document.getElementById('pageWidthOption').selected || + document.getElementById('pageFitOption').selected) + PDFView.parseScale(document.getElementById('scaleSelect').value); + updateViewarea(); +}); + window.addEventListener('hashchange', function(evt) { PDFView.page = PDFView.page; }); @@ -426,13 +478,36 @@ window.addEventListener('transitionend', function(evt) { }, 500); }, true); - window.addEventListener('scalechange', function scalechange(evt) { + var customScaleOption = document.getElementById('customScaleOption'); + customScaleOption.selected = false; + + if (!evt.resetAutoSettings && + (document.getElementById('pageWidthOption').selected || + document.getElementById('pageFitOption').selected)) { + updateViewarea(); + return; + } + var options = document.getElementById('scaleSelect').options; + var predefinedValueFound = false; + var value = '' + evt.scale; for (var i = 0; i < options.length; i++) { var option = options[i]; - option.selected = (option.value == evt.detail); + if (option.value != value) { + option.selected = false; + continue; + } + option.selected = true; + predefinedValueFound = true; + } + + if (!predefinedValueFound) { + customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%'; + customScaleOption.selected = true; } + + updateViewarea(); }, true); window.addEventListener('pagechange', function pagechange(evt) { @@ -442,3 +517,20 @@ window.addEventListener('pagechange', function pagechange(evt) { document.getElementById('previous').disabled = (page == 1); document.getElementById('next').disabled = (page == PDFView.pages.length); }, true); + +window.addEventListener('keydown', function keydown(evt) { + switch(evt.keyCode) { + case 61: // FF/Mac '=' + case 107: // FF '+' and '=' + case 187: // Chrome '+' + PDFView.zoomIn(); + break; + case 109: // FF '-' + case 189: // Chrome '-' + PDFView.zoomOut(); + break; + case 48: // '0' + PDFView.setScale(kDefaultScale, true); + break; + } +});