Bug 1398810 - Update pdf.js to version 1.9.554. r=bdahl
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 11 Sep 2017 10:37:45 -0400
changeset 662402 1ef55343a4e988b27633479a8a8f8d9dac2a233b
parent 662401 f13d106fc6789dc775808929d263272aaf75975b
child 662403 ab8c75e0d4220a3218c79e963a3ffc455ba05419
push id79074
push userbmo:mstriemer@mozilla.com
push dateMon, 11 Sep 2017 17:17:14 +0000
reviewersbdahl
bugs1398810
milestone57.0a1
Bug 1398810 - Update pdf.js to version 1.9.554. r=bdahl
browser/extensions/pdfjs/README.mozilla
browser/extensions/pdfjs/content/build/pdf.js
browser/extensions/pdfjs/content/build/pdf.worker.js
browser/extensions/pdfjs/content/web/viewer.css
browser/extensions/pdfjs/content/web/viewer.js
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.9.530
+Current extension version is: 1.9.554
 
-Taken from upstream commit: d1089a28
+Taken from upstream commit: ba219965
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -1457,27 +1457,28 @@ exports.unreachable = unreachable;
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.DOMCMapReaderFactory = exports.DOMCanvasFactory = exports.DEFAULT_LINK_REL = exports.getDefaultSetting = exports.LinkTarget = exports.getFilenameFromUrl = exports.isValidUrl = exports.isExternalLinkTargetSet = exports.addLinkAttributes = exports.RenderingCancelledException = exports.CustomStyle = undefined;
+exports.DOMSVGFactory = exports.DOMCMapReaderFactory = exports.DOMCanvasFactory = exports.DEFAULT_LINK_REL = exports.getDefaultSetting = exports.LinkTarget = exports.getFilenameFromUrl = exports.isValidUrl = exports.isExternalLinkTargetSet = exports.addLinkAttributes = exports.RenderingCancelledException = exports.CustomStyle = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
 var _global_scope = __w_pdfjs_require__(2);
 
 var _global_scope2 = _interopRequireDefault(_global_scope);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-var DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
+const DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
+const SVG_NS = 'http://www.w3.org/2000/svg';
 class DOMCanvasFactory {
   create(width, height) {
     if (width <= 0 || height <= 0) {
       throw new Error('invalid canvas size');
     }
     let canvas = document.createElement('canvas');
     let context = canvas.getContext('2d');
     canvas.width = width;
@@ -1543,16 +1544,32 @@ class DOMCMapReaderFactory {
           }
         }
         reject(new Error('Unable to load ' + (this.isCompressed ? 'binary ' : '') + 'CMap at: ' + url));
       };
       request.send(null);
     });
   }
 }
+class DOMSVGFactory {
+  create(width, height) {
+    (0, _util.assert)(width > 0 && height > 0, 'Invalid SVG dimensions');
+    let svg = document.createElementNS(SVG_NS, 'svg:svg');
+    svg.setAttribute('version', '1.1');
+    svg.setAttribute('width', width + 'px');
+    svg.setAttribute('height', height + 'px');
+    svg.setAttribute('preserveAspectRatio', 'none');
+    svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
+    return svg;
+  }
+  createElement(type) {
+    (0, _util.assert)(typeof type === 'string', 'Invalid SVG element type');
+    return document.createElementNS(SVG_NS, type);
+  }
+}
 var CustomStyle = function CustomStyleClosure() {
   var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
   var _cache = Object.create(null);
   function CustomStyle() {}
   CustomStyle.getProp = function get(propName, element) {
     if (arguments.length === 1 && typeof _cache[propName] === 'string') {
       return _cache[propName];
     }
@@ -1703,16 +1720,17 @@ exports.addLinkAttributes = addLinkAttri
 exports.isExternalLinkTargetSet = isExternalLinkTargetSet;
 exports.isValidUrl = isValidUrl;
 exports.getFilenameFromUrl = getFilenameFromUrl;
 exports.LinkTarget = LinkTarget;
 exports.getDefaultSetting = getDefaultSetting;
 exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL;
 exports.DOMCanvasFactory = DOMCanvasFactory;
 exports.DOMCMapReaderFactory = DOMCMapReaderFactory;
+exports.DOMSVGFactory = DOMSVGFactory;
 
 /***/ }),
 /* 2 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
@@ -1758,16 +1776,20 @@ class AnnotationElementFactory {
           case 'Ch':
             return new ChoiceWidgetAnnotationElement(parameters);
         }
         return new WidgetAnnotationElement(parameters);
       case _util.AnnotationType.POPUP:
         return new PopupAnnotationElement(parameters);
       case _util.AnnotationType.LINE:
         return new LineAnnotationElement(parameters);
+      case _util.AnnotationType.SQUARE:
+        return new SquareAnnotationElement(parameters);
+      case _util.AnnotationType.CIRCLE:
+        return new CircleAnnotationElement(parameters);
       case _util.AnnotationType.HIGHLIGHT:
         return new HighlightAnnotationElement(parameters);
       case _util.AnnotationType.UNDERLINE:
         return new UnderlineAnnotationElement(parameters);
       case _util.AnnotationType.SQUIGGLY:
         return new SquigglyAnnotationElement(parameters);
       case _util.AnnotationType.STRIKEOUT:
         return new StrikeOutAnnotationElement(parameters);
@@ -1784,16 +1806,17 @@ class AnnotationElement {
     this.data = parameters.data;
     this.layer = parameters.layer;
     this.page = parameters.page;
     this.viewport = parameters.viewport;
     this.linkService = parameters.linkService;
     this.downloadManager = parameters.downloadManager;
     this.imageResourcesPath = parameters.imageResourcesPath;
     this.renderInteractiveForms = parameters.renderInteractiveForms;
+    this.svgFactory = parameters.svgFactory;
     if (isRenderable) {
       this.container = this._createContainer(ignoreBorder);
     }
   }
   _createContainer(ignoreBorder = false) {
     let data = this.data,
         page = this.page,
         viewport = this.viewport;
@@ -1867,17 +1890,18 @@ class AnnotationElement {
     container.appendChild(popup);
   }
   render() {
     throw new Error('Abstract method `AnnotationElement.render` called');
   }
 }
 class LinkAnnotationElement extends AnnotationElement {
   constructor(parameters) {
-    super(parameters, true);
+    let isRenderable = !!(parameters.data.url || parameters.data.dest || parameters.data.action);
+    super(parameters, isRenderable);
   }
   render() {
     this.container.className = 'linkAnnotation';
     let link = document.createElement('a');
     (0, _dom_utils.addLinkAttributes)(link, {
       url: this.data.url,
       target: this.data.newWindow ? _dom_utils.LinkTarget.BLANK : undefined
     });
@@ -2059,17 +2083,17 @@ class ChoiceWidgetAnnotationElement exte
   }
 }
 class PopupAnnotationElement extends AnnotationElement {
   constructor(parameters) {
     let isRenderable = !!(parameters.data.title || parameters.data.contents);
     super(parameters, isRenderable);
   }
   render() {
-    const IGNORE_TYPES = ['Line'];
+    const IGNORE_TYPES = ['Line', 'Square', 'Circle'];
     this.container.className = 'popupAnnotation';
     if (IGNORE_TYPES.indexOf(this.data.parentType) >= 0) {
       return this.container;
     }
     let selector = '[data-annotation-id="' + this.data.parentId + '"]';
     let parentElement = this.layer.querySelector(selector);
     if (!parentElement) {
       return this.container;
@@ -2165,37 +2189,83 @@ class PopupElement {
   }
 }
 class LineAnnotationElement extends AnnotationElement {
   constructor(parameters) {
     let isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
     super(parameters, isRenderable, true);
   }
   render() {
-    const SVG_NS = 'http://www.w3.org/2000/svg';
     this.container.className = 'lineAnnotation';
     let data = this.data;
     let width = data.rect[2] - data.rect[0];
     let height = data.rect[3] - data.rect[1];
-    let svg = document.createElementNS(SVG_NS, 'svg:svg');
-    svg.setAttributeNS(null, 'version', '1.1');
-    svg.setAttributeNS(null, 'width', width + 'px');
-    svg.setAttributeNS(null, 'height', height + 'px');
-    svg.setAttributeNS(null, 'preserveAspectRatio', 'none');
-    svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);
-    let line = document.createElementNS(SVG_NS, 'svg:line');
-    line.setAttributeNS(null, 'x1', data.rect[2] - data.lineCoordinates[0]);
-    line.setAttributeNS(null, 'y1', data.rect[3] - data.lineCoordinates[1]);
-    line.setAttributeNS(null, 'x2', data.rect[2] - data.lineCoordinates[2]);
-    line.setAttributeNS(null, 'y2', data.rect[3] - data.lineCoordinates[3]);
-    line.setAttributeNS(null, 'stroke-width', data.borderStyle.width);
-    line.setAttributeNS(null, 'stroke', 'transparent');
+    let svg = this.svgFactory.create(width, height);
+    let line = this.svgFactory.createElement('svg:line');
+    line.setAttribute('x1', data.rect[2] - data.lineCoordinates[0]);
+    line.setAttribute('y1', data.rect[3] - data.lineCoordinates[1]);
+    line.setAttribute('x2', data.rect[2] - data.lineCoordinates[2]);
+    line.setAttribute('y2', data.rect[3] - data.lineCoordinates[3]);
+    line.setAttribute('stroke-width', data.borderStyle.width);
+    line.setAttribute('stroke', 'transparent');
     svg.appendChild(line);
     this.container.append(svg);
-    this._createPopup(this.container, line, this.data);
+    this._createPopup(this.container, line, data);
+    return this.container;
+  }
+}
+class SquareAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
+    super(parameters, isRenderable, true);
+  }
+  render() {
+    this.container.className = 'squareAnnotation';
+    let data = this.data;
+    let width = data.rect[2] - data.rect[0];
+    let height = data.rect[3] - data.rect[1];
+    let svg = this.svgFactory.create(width, height);
+    let borderWidth = data.borderStyle.width;
+    let square = this.svgFactory.createElement('svg:rect');
+    square.setAttribute('x', borderWidth / 2);
+    square.setAttribute('y', borderWidth / 2);
+    square.setAttribute('width', width - borderWidth);
+    square.setAttribute('height', height - borderWidth);
+    square.setAttribute('stroke-width', borderWidth);
+    square.setAttribute('stroke', 'transparent');
+    square.setAttribute('fill', 'none');
+    svg.appendChild(square);
+    this.container.append(svg);
+    this._createPopup(this.container, square, data);
+    return this.container;
+  }
+}
+class CircleAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
+    super(parameters, isRenderable, true);
+  }
+  render() {
+    this.container.className = 'circleAnnotation';
+    let data = this.data;
+    let width = data.rect[2] - data.rect[0];
+    let height = data.rect[3] - data.rect[1];
+    let svg = this.svgFactory.create(width, height);
+    let borderWidth = data.borderStyle.width;
+    let circle = this.svgFactory.createElement('svg:ellipse');
+    circle.setAttribute('cx', width / 2);
+    circle.setAttribute('cy', height / 2);
+    circle.setAttribute('rx', width / 2 - borderWidth / 2);
+    circle.setAttribute('ry', height / 2 - borderWidth / 2);
+    circle.setAttribute('stroke-width', borderWidth);
+    circle.setAttribute('stroke', 'transparent');
+    circle.setAttribute('fill', 'none');
+    svg.appendChild(circle);
+    this.container.append(svg);
+    this._createPopup(this.container, circle, data);
     return this.container;
   }
 }
 class HighlightAnnotationElement extends AnnotationElement {
   constructor(parameters) {
     let isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
     super(parameters, isRenderable, true);
   }
@@ -2288,17 +2358,18 @@ class AnnotationLayer {
       let element = AnnotationElementFactory.create({
         data,
         layer: parameters.div,
         page: parameters.page,
         viewport: parameters.viewport,
         linkService: parameters.linkService,
         downloadManager: parameters.downloadManager,
         imageResourcesPath: parameters.imageResourcesPath || (0, _dom_utils.getDefaultSetting)('imageResourcesPath'),
-        renderInteractiveForms: parameters.renderInteractiveForms || false
+        renderInteractiveForms: parameters.renderInteractiveForms || false,
+        svgFactory: new _dom_utils.DOMSVGFactory()
       });
       if (element.isRenderable) {
         parameters.div.appendChild(element.render());
       }
     }
   }
   static update(parameters) {
     for (let i = 0, ii = parameters.annotations.length; i < ii; i++) {
@@ -3781,18 +3852,18 @@ var _UnsupportedManager = function Unsup
       for (var i = 0, ii = listeners.length; i < ii; i++) {
         listeners[i](featureId);
       }
     }
   };
 }();
 var version, build;
 {
-  exports.version = version = '1.9.530';
-  exports.build = build = 'd1089a28';
+  exports.version = version = '1.9.554';
+  exports.build = build = 'ba219965';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
@@ -3809,16 +3880,18 @@ exports.build = build;
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.SVGGraphics = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
+var _dom_utils = __w_pdfjs_require__(1);
+
 var SVGGraphics = function () {
   throw new Error('Not implemented: SVGGraphics');
 };
 ;
 exports.SVGGraphics = SVGGraphics;
 
 /***/ }),
 /* 6 */
@@ -4838,18 +4911,18 @@ var _svg = __w_pdfjs_require__(5);
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 var isWorker = typeof window === 'undefined';
 if (!_global_scope2.default.PDFJS) {
   _global_scope2.default.PDFJS = {};
 }
 var PDFJS = _global_scope2.default.PDFJS;
 {
-  PDFJS.version = '1.9.530';
-  PDFJS.build = 'd1089a28';
+  PDFJS.version = '1.9.554';
+  PDFJS.build = 'ba219965';
 }
 PDFJS.pdfBug = false;
 if (PDFJS.verbosity !== undefined) {
   (0, _util.setVerbosityLevel)(PDFJS.verbosity);
 }
 delete PDFJS.verbosity;
 Object.defineProperty(PDFJS, 'verbosity', {
   get() {
@@ -10405,18 +10478,18 @@ exports.PDFDataTransportStream = PDFData
 
 /***/ }),
 /* 15 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.9.530';
-var pdfjsBuild = 'd1089a28';
+var pdfjsVersion = '1.9.554';
+var pdfjsBuild = 'ba219965';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
 var pdfjsDisplayGlobal = __w_pdfjs_require__(9);
 var pdfjsDisplayAPI = __w_pdfjs_require__(4);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(6);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(3);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
 var pdfjsDisplaySVG = __w_pdfjs_require__(5);
 ;
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -10726,17 +10726,17 @@ var PostScriptCompiler = function PostSc
             if (stack.length < 1) {
               return null;
             }
             num1 = stack.pop();
             if (num1.type !== 'literal') {
               return null;
             }
             n = num1.number;
-            if (n < 0 || (n | 0) !== n || stack.length < n) {
+            if (n < 0 || !Number.isInteger(n) || stack.length < n) {
               return null;
             }
             ast1 = stack[stack.length - n - 1];
             if (ast1.type === 'literal' || ast1.type === 'var') {
               stack.push(ast1);
               break;
             }
             tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
@@ -10770,17 +10770,17 @@ var PostScriptCompiler = function PostSc
             }
             num2 = stack.pop();
             num1 = stack.pop();
             if (num2.type !== 'literal' || num1.type !== 'literal') {
               return null;
             }
             j = num2.number;
             n = num1.number;
-            if (n <= 0 || (n | 0) !== n || (j | 0) !== j || stack.length < n) {
+            if (n <= 0 || !Number.isInteger(n) || !Number.isInteger(j) || stack.length < n) {
               return null;
             }
             j = (j % n + n) % n;
             if (j === 0) {
               break;
             }
             Array.prototype.push.apply(stack, stack.splice(stack.length - n, n - j));
             break;
@@ -27345,16 +27345,20 @@ class AnnotationFactory {
             return new ChoiceWidgetAnnotation(parameters);
         }
         (0, _util.warn)('Unimplemented widget field type "' + fieldType + '", ' + 'falling back to base field type.');
         return new WidgetAnnotation(parameters);
       case 'Popup':
         return new PopupAnnotation(parameters);
       case 'Line':
         return new LineAnnotation(parameters);
+      case 'Square':
+        return new SquareAnnotation(parameters);
+      case 'Circle':
+        return new CircleAnnotation(parameters);
       case 'Highlight':
         return new HighlightAnnotation(parameters);
       case 'Underline':
         return new UnderlineAnnotation(parameters);
       case 'Squiggly':
         return new SquigglyAnnotation(parameters);
       case 'StrikeOut':
         return new StrikeOutAnnotation(parameters);
@@ -27558,17 +27562,17 @@ class AnnotationBorderStyle {
   constructor() {
     this.width = 1;
     this.style = _util.AnnotationBorderStyleType.SOLID;
     this.dashArray = [3];
     this.horizontalCornerRadius = 0;
     this.verticalCornerRadius = 0;
   }
   setWidth(width) {
-    if (width === (width | 0)) {
+    if (Number.isInteger(width)) {
       this.width = width;
     }
   }
   setStyle(style) {
     if (!style) {
       return;
     }
     switch (style.name) {
@@ -27610,22 +27614,22 @@ class AnnotationBorderStyle {
       } else {
         this.width = 0;
       }
     } else if (dashArray) {
       this.width = 0;
     }
   }
   setHorizontalCornerRadius(radius) {
-    if (radius === (radius | 0)) {
+    if (Number.isInteger(radius)) {
       this.horizontalCornerRadius = radius;
     }
   }
   setVerticalCornerRadius(radius) {
-    if (radius === (radius | 0)) {
+    if (Number.isInteger(radius)) {
       this.verticalCornerRadius = radius;
     }
   }
 }
 class WidgetAnnotation extends Annotation {
   constructor(params) {
     super(params);
     let dict = params.dict;
@@ -27837,16 +27841,30 @@ class LineAnnotation extends Annotation 
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.LINE;
     let dict = parameters.dict;
     this.data.lineCoordinates = _util.Util.normalizeRect(dict.getArray('L'));
     this._preparePopup(dict);
   }
 }
+class SquareAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
+    this.data.annotationType = _util.AnnotationType.SQUARE;
+    this._preparePopup(parameters.dict);
+  }
+}
+class CircleAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
+    this.data.annotationType = _util.AnnotationType.CIRCLE;
+    this._preparePopup(parameters.dict);
+  }
+}
 class HighlightAnnotation extends Annotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.HIGHLIGHT;
     this._preparePopup(parameters.dict);
   }
 }
 class UnderlineAnnotation extends Annotation {
@@ -39683,17 +39701,17 @@ var Type1CharString = function Type1Char
     executeCommand(howManyArgs, command, keepStack) {
       var stackLength = this.stack.length;
       if (howManyArgs > stackLength) {
         return true;
       }
       var start = stackLength - howManyArgs;
       for (var i = start; i < stackLength; i++) {
         var value = this.stack[i];
-        if (value === (value | 0)) {
+        if (Number.isInteger(value)) {
           this.output.push(28, value >> 8 & 0xff, value & 0xff);
         } else {
           value = 65536 * value | 0;
           this.output.push(255, value >> 24 & 0xFF, value >> 16 & 0xFF, value >> 8 & 0xFF, value & 0xFF);
         }
       }
       this.output.push.apply(this.output, command);
       if (keepStack) {
@@ -40003,18 +40021,18 @@ exports.Type1Parser = Type1Parser;
 
 /***/ }),
 /* 35 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.9.530';
-var pdfjsBuild = 'd1089a28';
+var pdfjsVersion = '1.9.554';
+var pdfjsBuild = 'ba219965';
 var pdfjsCoreWorker = __w_pdfjs_require__(17);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 36 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -234,16 +234,18 @@
   padding-top: 0.2em;
 }
 
 .annotationLayer .highlightAnnotation,
 .annotationLayer .underlineAnnotation,
 .annotationLayer .squigglyAnnotation,
 .annotationLayer .strikeoutAnnotation,
 .annotationLayer .lineAnnotation svg line,
+.annotationLayer .squareAnnotation svg rect,
+.annotationLayer .circleAnnotation svg ellipse,
 .annotationLayer .fileAttachmentAnnotation {
   cursor: pointer;
 }
 
 .pdfViewer .canvasWrapper {
   overflow: hidden;
 }
 
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -86,17 +86,17 @@
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.waitOnEventOrTimeout = exports.WaitOnType = exports.localized = exports.animationStarted = exports.normalizeWheelEventDelta = exports.binarySearchFirstItem = exports.watchScroll = exports.scrollIntoView = exports.getOutputScale = exports.approximateFraction = exports.roundToDivide = exports.getVisibleElements = exports.parseQueryString = exports.noContextMenuHandler = exports.getPDFFileNameFromURL = exports.ProgressBar = exports.EventBus = exports.NullL10n = exports.mozL10n = exports.RendererType = exports.cloneObj = exports.VERTICAL_PADDING = exports.SCROLLBAR_PADDING = exports.MAX_AUTO_SCALE = exports.UNKNOWN_SCALE = exports.MAX_SCALE = exports.MIN_SCALE = exports.DEFAULT_SCALE = exports.DEFAULT_SCALE_VALUE = exports.CSS_UNITS = undefined;
+exports.waitOnEventOrTimeout = exports.WaitOnType = exports.localized = exports.animationStarted = exports.normalizeWheelEventDelta = exports.binarySearchFirstItem = exports.watchScroll = exports.scrollIntoView = exports.getOutputScale = exports.approximateFraction = exports.roundToDivide = exports.getVisibleElements = exports.parseQueryString = exports.noContextMenuHandler = exports.getPDFFileNameFromURL = exports.ProgressBar = exports.EventBus = exports.NullL10n = exports.mozL10n = exports.RendererType = exports.cloneObj = exports.isValidRotation = exports.VERTICAL_PADDING = exports.SCROLLBAR_PADDING = exports.MAX_AUTO_SCALE = exports.UNKNOWN_SCALE = exports.MAX_SCALE = exports.MIN_SCALE = exports.DEFAULT_SCALE = exports.DEFAULT_SCALE_VALUE = exports.CSS_UNITS = undefined;
 
 var _pdfjsLib = __webpack_require__(1);
 
 const CSS_UNITS = 96.0 / 72.0;
 const DEFAULT_SCALE_VALUE = 'auto';
 const DEFAULT_SCALE = 1.0;
 const MIN_SCALE = 0.25;
 const MAX_SCALE = 10.0;
@@ -368,16 +368,19 @@ function normalizeWheelEventDelta(evt) {
   const MOUSE_LINES_PER_PAGE = 30;
   if (evt.deltaMode === MOUSE_DOM_DELTA_PIXEL_MODE) {
     delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE;
   } else if (evt.deltaMode === MOUSE_DOM_DELTA_LINE_MODE) {
     delta /= MOUSE_LINES_PER_PAGE;
   }
   return delta;
 }
+function isValidRotation(angle) {
+  return Number.isInteger(angle) && angle % 90 === 0;
+}
 function cloneObj(obj) {
   let result = Object.create(null);
   for (let i in obj) {
     if (Object.prototype.hasOwnProperty.call(obj, i)) {
       result[i] = obj[i];
     }
   }
   return result;
@@ -511,16 +514,17 @@ exports.CSS_UNITS = CSS_UNITS;
 exports.DEFAULT_SCALE_VALUE = DEFAULT_SCALE_VALUE;
 exports.DEFAULT_SCALE = DEFAULT_SCALE;
 exports.MIN_SCALE = MIN_SCALE;
 exports.MAX_SCALE = MAX_SCALE;
 exports.UNKNOWN_SCALE = UNKNOWN_SCALE;
 exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE;
 exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING;
 exports.VERTICAL_PADDING = VERTICAL_PADDING;
+exports.isValidRotation = isValidRotation;
 exports.cloneObj = cloneObj;
 exports.RendererType = RendererType;
 exports.mozL10n = mozL10n;
 exports.NullL10n = NullL10n;
 exports.EventBus = EventBus;
 exports.ProgressBar = ProgressBar;
 exports.getPDFFileNameFromURL = getPDFFileNameFromURL;
 exports.noContextMenuHandler = noContextMenuHandler;
@@ -1406,48 +1410,56 @@ let PDFViewerApplication = {
     pdfThumbnailViewer.setDocument(pdfDocument);
     firstPagePromise.then(pdfPage => {
       this.loadingBar.setWidth(this.appConfig.viewerContainer);
       if (!_pdfjsLib.PDFJS.disableHistory && !this.isViewerEmbedded) {
         let resetHistory = !this.viewerPrefs['showPreviousViewOnLoad'];
         this.pdfHistory.initialize(id, resetHistory);
         if (this.pdfHistory.initialBookmark) {
           this.initialBookmark = this.pdfHistory.initialBookmark;
+          this.initialRotation = this.pdfHistory.initialRotation;
         }
       }
       let initialParams = {
         bookmark: null,
         hash: null
       };
       let storePromise = store.getMultiple({
         exists: false,
         page: '1',
         zoom: _ui_utils.DEFAULT_SCALE_VALUE,
         scrollLeft: '0',
         scrollTop: '0',
+        rotation: null,
         sidebarView: _pdf_sidebar.SidebarView.NONE
       }).catch(() => {});
       Promise.all([storePromise, pageModePromise]).then(([values = {}, pageMode]) => {
         let hash = this.viewerPrefs['defaultZoomValue'] ? 'zoom=' + this.viewerPrefs['defaultZoomValue'] : null;
+        let rotation = null;
         let sidebarView = this.viewerPrefs['sidebarViewOnLoad'];
         if (values.exists && this.viewerPrefs['showPreviousViewOnLoad']) {
           hash = 'page=' + values.page + '&zoom=' + (this.viewerPrefs['defaultZoomValue'] || values.zoom) + ',' + values.scrollLeft + ',' + values.scrollTop;
+          rotation = parseInt(values.rotation, 10);
           sidebarView = sidebarView || values.sidebarView | 0;
         }
         if (pageMode && !this.viewerPrefs['disablePageMode']) {
           sidebarView = sidebarView || apiPageModeToSidebarView(pageMode);
         }
         return {
           hash,
+          rotation,
           sidebarView
         };
-      }).then(({ hash, sidebarView }) => {
+      }).then(({ hash, rotation, sidebarView }) => {
         initialParams.bookmark = this.initialBookmark;
         initialParams.hash = hash;
-        this.setInitialView(hash, { sidebarView });
+        this.setInitialView(hash, {
+          rotation,
+          sidebarView
+        });
         if (!this.isViewerEmbedded) {
           pdfViewer.focus();
         }
         return pagesPromise;
       }).then(() => {
         if (!initialParams.bookmark && !initialParams.hash) {
           return;
         }
@@ -1548,23 +1560,31 @@ let PDFViewerApplication = {
       this.externalServices.reportTelemetry({
         type: 'documentInfo',
         version: versionId,
         generator: generatorId,
         formType
       });
     });
   },
-  setInitialView(storedHash, { sidebarView } = {}) {
+  setInitialView(storedHash, { rotation, sidebarView } = {}) {
+    let setRotation = angle => {
+      if ((0, _ui_utils.isValidRotation)(angle)) {
+        this.pdfViewer.pagesRotation = angle;
+      }
+    };
     this.isInitialViewSet = true;
     this.pdfSidebar.setInitialView(sidebarView);
     if (this.initialBookmark) {
+      setRotation(this.initialRotation);
+      delete this.initialRotation;
       this.pdfLinkService.setHash(this.initialBookmark);
       this.initialBookmark = null;
     } else if (storedHash) {
+      setRotation(rotation);
       this.pdfLinkService.setHash(storedHash);
     }
     this.toolbar.setPageNumber(this.pdfViewer.currentPageNumber, this.pdfViewer.currentPageLabel);
     this.secondaryToolbar.setPageNumber(this.pdfViewer.currentPageNumber);
     if (!this.pdfViewer.currentScaleValue) {
       this.pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE;
     }
   },
@@ -1613,23 +1633,18 @@ let PDFViewerApplication = {
       this.printService = null;
     }
     this.forceRendering();
   },
   rotatePages(delta) {
     if (!this.pdfDocument) {
       return;
     }
-    let { pdfViewer, pdfThumbnailViewer } = this;
-    let pageNumber = pdfViewer.currentPageNumber;
-    let newRotation = (pdfViewer.pagesRotation + 360 + delta) % 360;
-    pdfViewer.pagesRotation = newRotation;
-    pdfThumbnailViewer.pagesRotation = newRotation;
-    this.forceRendering();
-    pdfViewer.currentPageNumber = pageNumber;
+    let newRotation = (this.pdfViewer.pagesRotation + 360 + delta) % 360;
+    this.pdfViewer.pagesRotation = newRotation;
   },
   requestPresentationMode() {
     if (!this.pdfPresentationMode) {
       return;
     }
     this.pdfPresentationMode.request();
   },
   bindEvents() {
@@ -1640,16 +1655,17 @@ let PDFViewerApplication = {
     eventBus.on('hashchange', webViewerHashchange);
     eventBus.on('beforeprint', _boundEvents.beforePrint);
     eventBus.on('afterprint', _boundEvents.afterPrint);
     eventBus.on('pagerendered', webViewerPageRendered);
     eventBus.on('textlayerrendered', webViewerTextLayerRendered);
     eventBus.on('updateviewarea', webViewerUpdateViewarea);
     eventBus.on('pagechanging', webViewerPageChanging);
     eventBus.on('scalechanging', webViewerScaleChanging);
+    eventBus.on('rotationchanging', webViewerRotationChanging);
     eventBus.on('sidebarviewchanged', webViewerSidebarViewChanged);
     eventBus.on('pagemode', webViewerPageMode);
     eventBus.on('namedaction', webViewerNamedAction);
     eventBus.on('presentationmodechanged', webViewerPresentationModeChanged);
     eventBus.on('presentationmode', webViewerPresentationMode);
     eventBus.on('openfile', webViewerOpenFile);
     eventBus.on('print', webViewerPrint);
     eventBus.on('download', webViewerDownload);
@@ -1695,16 +1711,17 @@ let PDFViewerApplication = {
     eventBus.off('hashchange', webViewerHashchange);
     eventBus.off('beforeprint', _boundEvents.beforePrint);
     eventBus.off('afterprint', _boundEvents.afterPrint);
     eventBus.off('pagerendered', webViewerPageRendered);
     eventBus.off('textlayerrendered', webViewerTextLayerRendered);
     eventBus.off('updateviewarea', webViewerUpdateViewarea);
     eventBus.off('pagechanging', webViewerPageChanging);
     eventBus.off('scalechanging', webViewerScaleChanging);
+    eventBus.off('rotationchanging', webViewerRotationChanging);
     eventBus.off('sidebarviewchanged', webViewerSidebarViewChanged);
     eventBus.off('pagemode', webViewerPageMode);
     eventBus.off('namedaction', webViewerNamedAction);
     eventBus.off('presentationmodechanged', webViewerPresentationModeChanged);
     eventBus.off('presentationmode', webViewerPresentationMode);
     eventBus.off('openfile', webViewerOpenFile);
     eventBus.off('print', webViewerPrint);
     eventBus.off('download', webViewerDownload);
@@ -1949,17 +1966,18 @@ function webViewerUpdateViewarea(evt) {
   let location = evt.location,
       store = PDFViewerApplication.store;
   if (store && PDFViewerApplication.isInitialViewSet) {
     store.setMultiple({
       'exists': true,
       'page': location.pageNumber,
       'zoom': location.scale,
       'scrollLeft': location.left,
-      'scrollTop': location.top
+      'scrollTop': location.top,
+      'rotation': location.rotation
     }).catch(function () {});
   }
   let href = PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams);
   PDFViewerApplication.appConfig.toolbar.viewBookmark.href = href;
   PDFViewerApplication.appConfig.secondaryToolbar.viewBookmarkButton.href = href;
   let currentPage = PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1);
   let loading = currentPage.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED;
   PDFViewerApplication.toolbar.updateLoadingIndicatorState(loading);
@@ -2059,16 +2077,21 @@ function webViewerFindFromUrlHash(evt) {
     highlightAll: true,
     findPrevious: false
   });
 }
 function webViewerScaleChanging(evt) {
   PDFViewerApplication.toolbar.setPageScale(evt.presetValue, evt.scale);
   PDFViewerApplication.pdfViewer.update();
 }
+function webViewerRotationChanging(evt) {
+  PDFViewerApplication.pdfThumbnailViewer.pagesRotation = evt.pagesRotation;
+  PDFViewerApplication.forceRendering();
+  PDFViewerApplication.pdfViewer.currentPageNumber = evt.pageNumber;
+}
 function webViewerPageChanging(evt) {
   let page = evt.pageNumber;
   PDFViewerApplication.toolbar.setPageNumber(page, evt.pageLabel || null);
   PDFViewerApplication.secondaryToolbar.setPageNumber(page);
   if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {
     PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page);
   }
   if (_pdfjsLib.PDFJS.pdfBug && Stats.enabled) {
@@ -2394,16 +2417,22 @@ class PDFLinkService {
     return this.pdfDocument ? this.pdfDocument.numPages : 0;
   }
   get page() {
     return this.pdfViewer.currentPageNumber;
   }
   set page(value) {
     this.pdfViewer.currentPageNumber = value;
   }
+  get rotation() {
+    return this.pdfViewer.pagesRotation;
+  }
+  set rotation(value) {
+    this.pdfViewer.pagesRotation = value;
+  }
   navigateTo(dest) {
     let goToDestination = ({ namedDest, explicitDest }) => {
       let destRef = explicitDest[0],
           pageNumber;
       if (destRef instanceof Object) {
         pageNumber = this._cachedPageNumber(destRef);
         if (pageNumber === null) {
           this.pdfDocument.getPageIndex(destRef).then(pageIndex => {
@@ -2412,17 +2441,17 @@ class PDFLinkService {
               namedDest,
               explicitDest
             });
           }).catch(() => {
             console.error(`PDFLinkService.navigateTo: "${destRef}" is not ` + `a valid page reference, for dest="${dest}".`);
           });
           return;
         }
-      } else if ((destRef | 0) === destRef) {
+      } else if (Number.isInteger(destRef)) {
         pageNumber = destRef + 1;
       } else {
         console.error(`PDFLinkService.navigateTo: "${destRef}" is not ` + `a valid destination reference, for dest="${dest}".`);
         return;
       }
       if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {
         console.error(`PDFLinkService.navigateTo: "${pageNumber}" is not ` + `a valid page number, for dest="${dest}".`);
         return;
@@ -2603,17 +2632,17 @@ function isValidExplicitDestination(dest
     return false;
   }
   let destLength = dest.length,
       allowNull = true;
   if (destLength < 2) {
     return false;
   }
   let page = dest[0];
-  if (!(typeof page === 'object' && typeof page.num === 'number' && (page.num | 0) === page.num && typeof page.gen === 'number' && (page.gen | 0) === page.gen) && !(typeof page === 'number' && (page | 0) === page && page >= 0)) {
+  if (!(typeof page === 'object' && Number.isInteger(page.num) && Number.isInteger(page.gen)) && !(Number.isInteger(page) && page >= 0)) {
     return false;
   }
   let zoom = dest[1];
   if (!(typeof zoom === 'object' && typeof zoom.name === 'string')) {
     return false;
   }
   switch (zoom.name) {
     case 'XYZ':
@@ -2649,16 +2678,20 @@ function isValidExplicitDestination(dest
   }
   return true;
 }
 class SimpleLinkService {
   get page() {
     return 0;
   }
   set page(value) {}
+  get rotation() {
+    return 0;
+  }
+  set rotation(value) {}
   navigateTo(dest) {}
   getDestinationHash(dest) {
     return '#';
   }
   getAnchorUrl(hash) {
     return '#';
   }
   setHash(hash) {}
@@ -3239,100 +3272,96 @@ exports.FirefoxCom = exports.DownloadMan
 
 var _pdfjsLib = __webpack_require__(1);
 
 var _preferences = __webpack_require__(26);
 
 var _app = __webpack_require__(4);
 
 ;
-var FirefoxCom = function FirefoxComClosure() {
+let FirefoxCom = function FirefoxComClosure() {
   return {
     requestSync(action, data) {
-      var request = document.createTextNode('');
+      let request = document.createTextNode('');
       document.documentElement.appendChild(request);
-      var sender = document.createEvent('CustomEvent');
+      let sender = document.createEvent('CustomEvent');
       sender.initCustomEvent('pdf.js.message', true, false, {
         action,
         data,
         sync: true
       });
       request.dispatchEvent(sender);
-      var response = sender.detail.response;
+      let response = sender.detail.response;
       document.documentElement.removeChild(request);
       return response;
     },
     request(action, data, callback) {
-      var request = document.createTextNode('');
+      let request = document.createTextNode('');
       if (callback) {
         document.addEventListener('pdf.js.response', function listener(event) {
-          var node = event.target;
-          var response = event.detail.response;
+          let node = event.target;
+          let response = event.detail.response;
           document.documentElement.removeChild(node);
           document.removeEventListener('pdf.js.response', listener);
           return callback(response);
         });
       }
       document.documentElement.appendChild(request);
-      var sender = document.createEvent('CustomEvent');
+      let sender = document.createEvent('CustomEvent');
       sender.initCustomEvent('pdf.js.message', true, false, {
         action,
         data,
         sync: false,
         responseExpected: !!callback
       });
       return request.dispatchEvent(sender);
     }
   };
 }();
-var DownloadManager = function DownloadManagerClosure() {
-  function DownloadManager() {}
-  DownloadManager.prototype = {
-    downloadUrl: function DownloadManager_downloadUrl(url, filename) {
-      FirefoxCom.request('download', {
-        originalUrl: url,
-        filename
-      });
-    },
-    downloadData: function DownloadManager_downloadData(data, filename, contentType) {
-      var blobUrl = (0, _pdfjsLib.createObjectURL)(data, contentType, false);
-      FirefoxCom.request('download', {
-        blobUrl,
-        originalUrl: blobUrl,
-        filename,
-        isAttachment: true
-      });
-    },
-    download: function DownloadManager_download(blob, url, filename) {
-      let blobUrl = window.URL.createObjectURL(blob);
-      let onResponse = err => {
-        if (err && this.onerror) {
-          this.onerror(err);
-        }
-        window.URL.revokeObjectURL(blobUrl);
-      };
-      FirefoxCom.request('download', {
-        blobUrl,
-        originalUrl: url,
-        filename
-      }, onResponse);
-    }
-  };
-  return DownloadManager;
-}();
+class DownloadManager {
+  downloadUrl(url, filename) {
+    FirefoxCom.request('download', {
+      originalUrl: url,
+      filename
+    });
+  }
+  downloadData(data, filename, contentType) {
+    let blobUrl = (0, _pdfjsLib.createObjectURL)(data, contentType, false);
+    FirefoxCom.request('download', {
+      blobUrl,
+      originalUrl: blobUrl,
+      filename,
+      isAttachment: true
+    });
+  }
+  download(blob, url, filename) {
+    let blobUrl = URL.createObjectURL(blob);
+    let onResponse = err => {
+      if (err && this.onerror) {
+        this.onerror(err);
+      }
+      URL.revokeObjectURL(blobUrl);
+    };
+    FirefoxCom.request('download', {
+      blobUrl,
+      originalUrl: url,
+      filename
+    }, onResponse);
+  }
+}
 class FirefoxPreferences extends _preferences.BasePreferences {
   _writeToStorage(prefObj) {
     return new Promise(function (resolve) {
       FirefoxCom.request('setPreferences', prefObj, resolve);
     });
   }
   _readFromStorage(prefObj) {
     return new Promise(function (resolve) {
       FirefoxCom.request('getPreferences', prefObj, function (prefStr) {
-        var readPrefs = JSON.parse(prefStr);
+        let readPrefs = JSON.parse(prefStr);
         resolve(readPrefs);
       });
     });
   }
 }
 class MozL10n {
   constructor(mozL10n) {
     this.mozL10n = mozL10n;
@@ -3344,32 +3373,32 @@ class MozL10n {
     return Promise.resolve(this.mozL10n.get(property, args, fallback));
   }
   translate(element) {
     this.mozL10n.translate(element);
     return Promise.resolve();
   }
 }
 (function listenFindEvents() {
-  var events = ['find', 'findagain', 'findhighlightallchange', 'findcasesensitivitychange'];
-  var handleEvent = function (evt) {
+  const events = ['find', 'findagain', 'findhighlightallchange', 'findcasesensitivitychange'];
+  let handleEvent = function (evt) {
     if (!_app.PDFViewerApplication.initialized) {
       return;
     }
     _app.PDFViewerApplication.eventBus.dispatch('find', {
       source: window,
       type: evt.type.substring('find'.length),
       query: evt.detail.query,
       phraseSearch: true,
       caseSensitive: !!evt.detail.caseSensitive,
       highlightAll: !!evt.detail.highlightAll,
       findPrevious: !!evt.detail.findPrevious
     });
   };
-  for (var i = 0, len = events.length; i < len; i++) {
+  for (let i = 0, len = events.length; i < len; i++) {
     window.addEventListener(events[i], handleEvent);
   }
 })();
 function FirefoxComDataRangeTransport(length, initialData) {
   _pdfjsLib.PDFDataRangeTransport.call(this, length, initialData);
 }
 FirefoxComDataRangeTransport.prototype = Object.create(_pdfjsLib.PDFDataRangeTransport.prototype);
 FirefoxComDataRangeTransport.prototype.requestDataRange = function FirefoxComDataRangeTransport_requestDataRange(begin, end) {
@@ -3381,23 +3410,23 @@ FirefoxComDataRangeTransport.prototype.r
 FirefoxComDataRangeTransport.prototype.abort = function FirefoxComDataRangeTransport_abort() {
   FirefoxCom.requestSync('abortLoading', null);
 };
 _app.PDFViewerApplication.externalServices = {
   updateFindControlState(data) {
     FirefoxCom.request('updateFindControlState', data);
   },
   initPassiveLoading(callbacks) {
-    var pdfDataRangeTransport;
+    let pdfDataRangeTransport;
     window.addEventListener('message', function windowMessage(e) {
       if (e.source !== null) {
         console.warn('Rejected untrusted message from ' + e.origin);
         return;
       }
-      var args = e.data;
+      let args = e.data;
       if (typeof args !== 'object' || !('pdfjsLoadAction' in args)) {
         return;
       }
       switch (args.pdfjsLoadAction) {
         case 'supportsRangedLoading':
           pdfDataRangeTransport = new FirefoxComDataRangeTransport(args.length, args.data);
           callbacks.onOpenWithTransport(args.pdfUrl, args.length, pdfDataRangeTransport);
           break;
@@ -3432,33 +3461,33 @@ FirefoxComDataRangeTransport.prototype.a
   },
   createDownloadManager() {
     return new DownloadManager();
   },
   createPreferences() {
     return new FirefoxPreferences();
   },
   createL10n() {
-    var mozL10n = document.mozL10n;
+    let mozL10n = document.mozL10n;
     return new MozL10n(mozL10n);
   },
   get supportsIntegratedFind() {
-    var support = FirefoxCom.requestSync('supportsIntegratedFind');
+    let support = FirefoxCom.requestSync('supportsIntegratedFind');
     return (0, _pdfjsLib.shadow)(this, 'supportsIntegratedFind', support);
   },
   get supportsDocumentFonts() {
-    var support = FirefoxCom.requestSync('supportsDocumentFonts');
+    let support = FirefoxCom.requestSync('supportsDocumentFonts');
     return (0, _pdfjsLib.shadow)(this, 'supportsDocumentFonts', support);
   },
   get supportsDocumentColors() {
-    var support = FirefoxCom.requestSync('supportsDocumentColors');
+    let support = FirefoxCom.requestSync('supportsDocumentColors');
     return (0, _pdfjsLib.shadow)(this, 'supportsDocumentColors', support);
   },
   get supportedMouseWheelZoomModifierKeys() {
-    var support = FirefoxCom.requestSync('supportedMouseWheelZoomModifierKeys');
+    let support = FirefoxCom.requestSync('supportedMouseWheelZoomModifierKeys');
     return (0, _pdfjsLib.shadow)(this, 'supportedMouseWheelZoomModifierKeys', support);
   }
 };
 document.mozL10n.setExternalLocalizerServices({
   getLocale() {
     return FirefoxCom.requestSync('getLocale', null);
   },
   getStrings(key) {
@@ -4411,38 +4440,40 @@ Object.defineProperty(exports, "__esModu
 exports.isDestsEqual = exports.PDFHistory = undefined;
 
 var _ui_utils = __webpack_require__(0);
 
 var _dom_events = __webpack_require__(2);
 
 const HASH_CHANGE_TIMEOUT = 1000;
 const POSITION_UPDATED_THRESHOLD = 50;
-const UPDATE_VIEWAREA_TIMEOUT = 2000;
+const UPDATE_VIEWAREA_TIMEOUT = 1000;
 function getCurrentHash() {
   return document.location.hash;
 }
 function parseCurrentHash(linkService) {
   let hash = unescape(getCurrentHash()).substring(1);
   let params = (0, _ui_utils.parseQueryString)(hash);
   let page = params.page | 0;
   if (!(Number.isInteger(page) && page > 0 && page <= linkService.pagesCount)) {
     page = null;
   }
   return {
     hash,
-    page
+    page,
+    rotation: linkService.rotation
   };
 }
 class PDFHistory {
   constructor({ linkService, eventBus }) {
     this.linkService = linkService;
     this.eventBus = eventBus || (0, _dom_events.getGlobalEventBus)();
     this.initialized = false;
     this.initialBookmark = null;
+    this.initialRotation = null;
     this._boundEvents = Object.create(null);
     this._isViewerInPresentationMode = false;
     this._isPagesLoaded = false;
     this.eventBus.on('presentationmodechanged', evt => {
       this._isViewerInPresentationMode = evt.active || evt.switchInProgress;
     });
     this.eventBus.on('pagesloaded', evt => {
       this._isPagesLoaded = !!evt.pagesCount;
@@ -4456,37 +4487,42 @@ class PDFHistory {
     let reInitialized = this.initialized && this.fingerprint !== fingerprint;
     this.fingerprint = fingerprint;
     if (!this.initialized) {
       this._bindEvents();
     }
     let state = window.history.state;
     this.initialized = true;
     this.initialBookmark = null;
+    this.initialRotation = null;
     this._popStateInProgress = false;
     this._blockHashChange = 0;
     this._currentHash = getCurrentHash();
     this._numPositionUpdates = 0;
     this._currentUid = this._uid = 0;
     this._destination = null;
     this._position = null;
     if (!this._isValidState(state) || resetHistory) {
-      let { hash, page } = parseCurrentHash(this.linkService);
+      let { hash, page, rotation } = parseCurrentHash(this.linkService);
       if (!hash || reInitialized || resetHistory) {
         this._pushOrReplaceState(null, true);
         return;
       }
       this._pushOrReplaceState({
         hash,
-        page
+        page,
+        rotation
       }, true);
       return;
     }
     let destination = state.destination;
     this._updateInternalState(destination, state.uid, true);
+    if (destination.rotation !== undefined) {
+      this.initialRotation = destination.rotation;
+    }
     if (destination.dest) {
       this.initialBookmark = JSON.stringify(destination.dest);
       this._destination.page = null;
     } else if (destination.hash) {
       this.initialBookmark = destination.hash;
     } else if (destination.page) {
       this.initialBookmark = `page=${destination.page}`;
     }
@@ -4511,18 +4547,25 @@ class PDFHistory {
       forceReplace = true;
     }
     if (this._popStateInProgress && !forceReplace) {
       return;
     }
     this._pushOrReplaceState({
       dest: explicitDest,
       hash,
-      page: pageNumber
+      page: pageNumber,
+      rotation: this.linkService.rotation
     }, forceReplace);
+    if (!this._popStateInProgress) {
+      this._popStateInProgress = true;
+      Promise.resolve().then(() => {
+        this._popStateInProgress = false;
+      });
+    }
   }
   pushCurrentPosition() {
     if (!this.initialized || this._popStateInProgress) {
       return;
     }
     this._tryPushCurrentPosition();
   }
   back() {
@@ -4603,33 +4646,38 @@ class PDFHistory {
       return false;
     }
     if (state.destination === null || typeof state.destination !== 'object') {
       return false;
     }
     return true;
   }
   _updateInternalState(destination, uid, removeTemporary = false) {
+    if (this._updateViewareaTimeout) {
+      clearTimeout(this._updateViewareaTimeout);
+      this._updateViewareaTimeout = null;
+    }
     if (removeTemporary && destination && destination.temporary) {
       delete destination.temporary;
     }
     this._destination = destination;
     this._currentUid = uid;
     this._uid = this._currentUid + 1;
     this._numPositionUpdates = 0;
   }
   _updateViewarea({ location }) {
     if (this._updateViewareaTimeout) {
       clearTimeout(this._updateViewareaTimeout);
       this._updateViewareaTimeout = null;
     }
     this._position = {
       hash: this._isViewerInPresentationMode ? `page=${location.pageNumber}` : location.pdfOpenParams.substring(1),
       page: this.linkService.page,
-      first: location.pageNumber
+      first: location.pageNumber,
+      rotation: location.rotation
     };
     if (this._popStateInProgress) {
       return;
     }
     if (POSITION_UPDATED_THRESHOLD > 0 && this._isPagesLoaded && this._destination && !this._destination.page) {
       this._numPositionUpdates++;
     }
     if (UPDATE_VIEWAREA_TIMEOUT > 0) {
@@ -4642,20 +4690,21 @@ class PDFHistory {
     }
   }
   _popState({ state }) {
     let newHash = getCurrentHash(),
         hashChanged = this._currentHash !== newHash;
     this._currentHash = newHash;
     if (!state || false) {
       this._currentUid = this._uid;
-      let { hash, page } = parseCurrentHash(this.linkService);
+      let { hash, page, rotation } = parseCurrentHash(this.linkService);
       this._pushOrReplaceState({
         hash,
-        page
+        page,
+        rotation
       }, true);
       return;
     }
     if (!this._isValidState(state)) {
       return;
     }
     this._popStateInProgress = true;
     if (hashChanged) {
@@ -4663,34 +4712,21 @@ class PDFHistory {
       (0, _ui_utils.waitOnEventOrTimeout)({
         target: window,
         name: 'hashchange',
         delay: HASH_CHANGE_TIMEOUT
       }).then(() => {
         this._blockHashChange--;
       });
     }
-    if (state.uid < this._currentUid && this._position && this._destination) {
-      let shouldGoBack = false;
-      if (this._destination.temporary) {
-        this._pushOrReplaceState(this._position);
-        shouldGoBack = true;
-      } else if (this._destination.page && this._destination.page !== this._position.first && this._destination.page !== this._position.page) {
-        this._pushOrReplaceState(this._destination);
-        this._pushOrReplaceState(this._position);
-        shouldGoBack = true;
-      }
-      if (shouldGoBack) {
-        this._currentUid = state.uid;
-        window.history.back();
-        return;
-      }
-    }
     let destination = state.destination;
     this._updateInternalState(destination, state.uid, true);
+    if ((0, _ui_utils.isValidRotation)(destination.rotation)) {
+      this.linkService.rotation = destination.rotation;
+    }
     if (destination.dest) {
       this.linkService.navigateTo(destination.dest);
     } else if (destination.hash) {
       this.linkService.setHash(destination.hash);
     } else if (destination.page) {
       this.linkService.page = destination.page;
     }
     Promise.resolve().then(() => {
@@ -6314,22 +6350,25 @@ class PDFThumbnailViewer {
         (0, _ui_utils.scrollIntoView)(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN });
       }
     }
   }
   get pagesRotation() {
     return this._pagesRotation;
   }
   set pagesRotation(rotation) {
-    if (!(typeof rotation === 'number' && rotation % 90 === 0)) {
+    if (!(0, _ui_utils.isValidRotation)(rotation)) {
       throw new Error('Invalid thumbnails rotation angle.');
     }
     if (!this.pdfDocument) {
       return;
     }
+    if (this._pagesRotation === rotation) {
+      return;
+    }
     this._pagesRotation = rotation;
     for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
       this._thumbnails[i].update(rotation);
     }
   }
   cleanup() {
     _pdf_thumbnail_view.PDFThumbnailView.cleanup();
   }
@@ -6526,17 +6565,17 @@ class PDFViewer {
   }
   get pageViewsReady() {
     return this._pageViewsReady;
   }
   get currentPageNumber() {
     return this._currentPageNumber;
   }
   set currentPageNumber(val) {
-    if ((val | 0) !== val) {
+    if (!Number.isInteger(val)) {
       throw new Error('Invalid page number.');
     }
     if (!this.pdfDocument) {
       return;
     }
     this._setCurrentPageNumber(val, true);
   }
   _setCurrentPageNumber(val, resetCurrentPageView = false) {
@@ -6595,28 +6634,39 @@ class PDFViewer {
       return;
     }
     this._setScale(val, false);
   }
   get pagesRotation() {
     return this._pagesRotation;
   }
   set pagesRotation(rotation) {
-    if (!(typeof rotation === 'number' && rotation % 90 === 0)) {
+    if (!(0, _ui_utils.isValidRotation)(rotation)) {
       throw new Error('Invalid pages rotation angle.');
     }
     if (!this.pdfDocument) {
       return;
     }
+    if (this._pagesRotation === rotation) {
+      return;
+    }
     this._pagesRotation = rotation;
+    let pageNumber = this._currentPageNumber;
     for (let i = 0, ii = this._pages.length; i < ii; i++) {
       let pageView = this._pages[i];
       pageView.update(pageView.scale, rotation);
     }
-    this._setScale(this._currentScaleValue, true);
+    if (this._currentScaleValue) {
+      this._setScale(this._currentScaleValue, true);
+    }
+    this.eventBus.dispatch('rotationchanging', {
+      source: this,
+      pagesRotation: rotation,
+      pageNumber
+    });
     if (this.defaultRenderingQueue) {
       this.update();
     }
   }
   setDocument(pdfDocument) {
     if (this.pdfDocument) {
       this._cancelRendering();
       this._resetView();
@@ -6935,16 +6985,17 @@ class PDFViewer {
     let intLeft = Math.round(topLeft[0]);
     let intTop = Math.round(topLeft[1]);
     pdfOpenParams += ',' + intLeft + ',' + intTop;
     this._location = {
       pageNumber,
       scale: normalizedScaleValue,
       top: intTop,
       left: intLeft,
+      rotation: this._pagesRotation,
       pdfOpenParams
     };
   }
   update() {
     let visible = this._getVisiblePages();
     let visiblePages = visible.views;
     if (visiblePages.length === 0) {
       return;
@@ -7215,17 +7266,17 @@ class BasePreferences {
       var defaultType = typeof this.defaults[name];
       if (valueType !== defaultType) {
         if (valueType === 'number' && defaultType === 'string') {
           value = value.toString();
         } else {
           throw new Error(`Set preference: "${value}" is a ${valueType}, ` + `expected a ${defaultType}.`);
         }
       } else {
-        if (valueType === 'number' && (value | 0) !== value) {
+        if (valueType === 'number' && !Number.isInteger(value)) {
           throw new Error(`Set preference: "${value}" must be an integer.`);
         }
       }
       this.prefs[name] = value;
       return this._writeToStorage(this.prefs);
     });
   }
   get(name) {