From 24d741d045ba5b5296da042c65718a363a400c33 Mon Sep 17 00:00:00 2001
From: Tim van der Meij <timvandermeij@gmail.com>
Date: Sat, 26 Aug 2017 23:49:11 +0200
Subject: [PATCH 1/5] Convert `src/core/annotation.js` to ES6 syntax

---
 src/core/annotation.js | 1248 +++++++++++++++++++---------------------
 1 file changed, 584 insertions(+), 664 deletions(-)

diff --git a/src/core/annotation.js b/src/core/annotation.js
index b1320287c..f036cd571 100644
--- a/src/core/annotation.js
+++ b/src/core/annotation.js
@@ -24,12 +24,7 @@ import { ColorSpace } from './colorspace';
 import { OperatorList } from './evaluator';
 import { Stream } from './stream';
 
-/**
- * @class
- * @alias AnnotationFactory
- */
-function AnnotationFactory() {}
-AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
+class AnnotationFactory {
   /**
    * @param {XRef} xref
    * @param {Object} ref
@@ -37,19 +32,19 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
    * @param {Object} idFactory
    * @returns {Annotation}
    */
-  create: function AnnotationFactory_create(xref, ref, pdfManager, idFactory) {
-    var dict = xref.fetchIfRef(ref);
+  create(xref, ref, pdfManager, idFactory) {
+    let dict = xref.fetchIfRef(ref);
     if (!isDict(dict)) {
       return;
     }
-    var id = isRef(ref) ? ref.toString() : 'annot_' + idFactory.createObjId();
+    let id = isRef(ref) ? ref.toString() : 'annot_' + idFactory.createObjId();
 
     // Determine the annotation's subtype.
-    var subtype = dict.get('Subtype');
+    let subtype = dict.get('Subtype');
     subtype = isName(subtype) ? subtype.name : null;
 
     // Return the right annotation object based on the subtype and field type.
-    var parameters = {
+    let parameters = {
       xref,
       dict,
       ref: isRef(ref) ? ref : null,
@@ -66,7 +61,7 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
         return new TextAnnotation(parameters);
 
       case 'Widget':
-        var fieldType = Util.getInheritableProperty(dict, 'FT');
+        let fieldType = Util.getInheritableProperty(dict, 'FT');
         fieldType = isName(fieldType) ? fieldType.name : null;
 
         switch (fieldType) {
@@ -111,38 +106,38 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
         }
         return new Annotation(parameters);
     }
-  },
-};
+  }
+}
 
-var Annotation = (function AnnotationClosure() {
+function getTransformMatrix(rect, bbox, matrix) {
   // 12.5.5: Algorithm: Appearance streams
-  function getTransformMatrix(rect, bbox, matrix) {
-    var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
-    var minX = bounds[0];
-    var minY = bounds[1];
-    var maxX = bounds[2];
-    var maxY = bounds[3];
-
-    if (minX === maxX || minY === maxY) {
-      // From real-life file, bbox was [0, 0, 0, 0]. In this case,
-      // just apply the transform for rect
-      return [1, 0, 0, 1, rect[0], rect[1]];
-    }
-
-    var xRatio = (rect[2] - rect[0]) / (maxX - minX);
-    var yRatio = (rect[3] - rect[1]) / (maxY - minY);
-    return [
-      xRatio,
-      0,
-      0,
-      yRatio,
-      rect[0] - minX * xRatio,
-      rect[1] - minY * yRatio
-    ];
+  let bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
+  let minX = bounds[0];
+  let minY = bounds[1];
+  let maxX = bounds[2];
+  let maxY = bounds[3];
+
+  if (minX === maxX || minY === maxY) {
+    // From real-life file, bbox was [0, 0, 0, 0]. In this case,
+    // just apply the transform for rect
+    return [1, 0, 0, 1, rect[0], rect[1]];
   }
 
-  function Annotation(params) {
-    var dict = params.dict;
+  let xRatio = (rect[2] - rect[0]) / (maxX - minX);
+  let yRatio = (rect[3] - rect[1]) / (maxY - minY);
+  return [
+    xRatio,
+    0,
+    0,
+    yRatio,
+    rect[0] - minX * xRatio,
+    rect[1] - minY * yRatio
+  ];
+}
+
+class Annotation {
+  constructor(params) {
+    let dict = params.dict;
 
     this.setFlags(dict.get('F'));
     this.setRectangle(dict.getArray('Rect'));
@@ -151,306 +146,296 @@ var Annotation = (function AnnotationClosure() {
     this.setAppearance(dict);
 
     // Expose public properties using a data object.
-    this.data = {};
-    this.data.id = params.id;
-    this.data.subtype = params.subtype;
-    this.data.annotationFlags = this.flags;
-    this.data.rect = this.rectangle;
-    this.data.color = this.color;
-    this.data.borderStyle = this.borderStyle;
-    this.data.hasAppearance = !!this.appearance;
+    this.data = {
+      annotationFlags: this.flags,
+      borderStyle: this.borderStyle,
+      color: this.color,
+      hasAppearance: !!this.appearance,
+      id: params.id,
+      rect: this.rectangle,
+      subtype: params.subtype,
+    };
   }
 
-  Annotation.prototype = {
-    /**
-     * @private
-     */
-    _hasFlag: function Annotation_hasFlag(flags, flag) {
-      return !!(flags & flag);
-    },
-
-    /**
-     * @private
-     */
-    _isViewable: function Annotation_isViewable(flags) {
-      return !this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
-             !this._hasFlag(flags, AnnotationFlag.HIDDEN) &&
-             !this._hasFlag(flags, AnnotationFlag.NOVIEW);
-    },
-
-    /**
-     * @private
-     */
-    _isPrintable: function AnnotationFlag_isPrintable(flags) {
-      return this._hasFlag(flags, AnnotationFlag.PRINT) &&
-             !this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
-             !this._hasFlag(flags, AnnotationFlag.HIDDEN);
-    },
-
-    /**
-     * @return {boolean}
-     */
-    get viewable() {
-      if (this.flags === 0) {
-        return true;
-      }
-      return this._isViewable(this.flags);
-    },
-
-    /**
-     * @return {boolean}
-     */
-    get printable() {
-      if (this.flags === 0) {
-        return false;
-      }
-      return this._isPrintable(this.flags);
-    },
-
-    /**
-     * Set the flags.
-     *
-     * @public
-     * @memberof Annotation
-     * @param {number} flags - Unsigned 32-bit integer specifying annotation
-     *                         characteristics
-     * @see {@link shared/util.js}
-     */
-    setFlags: function Annotation_setFlags(flags) {
-      this.flags = (isInt(flags) && flags > 0) ? flags : 0;
-    },
-
-    /**
-     * Check if a provided flag is set.
-     *
-     * @public
-     * @memberof Annotation
-     * @param {number} flag - Hexadecimal representation for an annotation
-     *                        characteristic
-     * @return {boolean}
-     * @see {@link shared/util.js}
-     */
-    hasFlag: function Annotation_hasFlag(flag) {
-      return this._hasFlag(this.flags, flag);
-    },
-
-    /**
-     * Set the rectangle.
-     *
-     * @public
-     * @memberof Annotation
-     * @param {Array} rectangle - The rectangle array with exactly four entries
-     */
-    setRectangle: function Annotation_setRectangle(rectangle) {
-      if (isArray(rectangle) && rectangle.length === 4) {
-        this.rectangle = Util.normalizeRect(rectangle);
-      } else {
-        this.rectangle = [0, 0, 0, 0];
-      }
-    },
-
-    /**
-     * Set the color and take care of color space conversion.
-     *
-     * @public
-     * @memberof Annotation
-     * @param {Array} color - The color array containing either 0
-     *                        (transparent), 1 (grayscale), 3 (RGB) or
-     *                        4 (CMYK) elements
-     */
-    setColor: function Annotation_setColor(color) {
-      var rgbColor = new Uint8Array(3); // Black in RGB color space (default)
-      if (!isArray(color)) {
-        this.color = rgbColor;
-        return;
-      }
+  /**
+   * @private
+   */
+  _hasFlag(flags, flag) {
+    return !!(flags & flag);
+  }
 
-      switch (color.length) {
-        case 0: // Transparent, which we indicate with a null value
-          this.color = null;
-          break;
+  /**
+   * @private
+   */
+  _isViewable(flags) {
+    return !this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
+           !this._hasFlag(flags, AnnotationFlag.HIDDEN) &&
+           !this._hasFlag(flags, AnnotationFlag.NOVIEW);
+  }
 
-        case 1: // Convert grayscale to RGB
-          ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0);
-          this.color = rgbColor;
-          break;
+  /**
+   * @private
+   */
+  _isPrintable(flags) {
+    return this._hasFlag(flags, AnnotationFlag.PRINT) &&
+           !this._hasFlag(flags, AnnotationFlag.INVISIBLE) &&
+           !this._hasFlag(flags, AnnotationFlag.HIDDEN);
+  }
 
-        case 3: // Convert RGB percentages to RGB
-          ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0);
-          this.color = rgbColor;
-          break;
+  /**
+   * @return {boolean}
+   */
+  get viewable() {
+    if (this.flags === 0) {
+      return true;
+    }
+    return this._isViewable(this.flags);
+  }
 
-        case 4: // Convert CMYK to RGB
-          ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0);
-          this.color = rgbColor;
-          break;
+  /**
+   * @return {boolean}
+   */
+  get printable() {
+    if (this.flags === 0) {
+      return false;
+    }
+    return this._isPrintable(this.flags);
+  }
 
-        default:
-          this.color = rgbColor;
-          break;
-      }
-    },
-
-    /**
-     * Set the border style (as AnnotationBorderStyle object).
-     *
-     * @public
-     * @memberof Annotation
-     * @param {Dict} borderStyle - The border style dictionary
-     */
-    setBorderStyle: function Annotation_setBorderStyle(borderStyle) {
-      this.borderStyle = new AnnotationBorderStyle();
-      if (!isDict(borderStyle)) {
-        return;
-      }
-      if (borderStyle.has('BS')) {
-        var dict = borderStyle.get('BS');
-        var dictType = dict.get('Type');
-
-        if (!dictType || isName(dictType, 'Border')) {
-          this.borderStyle.setWidth(dict.get('W'));
-          this.borderStyle.setStyle(dict.get('S'));
-          this.borderStyle.setDashArray(dict.getArray('D'));
-        }
-      } else if (borderStyle.has('Border')) {
-        var array = borderStyle.getArray('Border');
-        if (isArray(array) && array.length >= 3) {
-          this.borderStyle.setHorizontalCornerRadius(array[0]);
-          this.borderStyle.setVerticalCornerRadius(array[1]);
-          this.borderStyle.setWidth(array[2]);
-
-          if (array.length === 4) { // Dash array available
-            this.borderStyle.setDashArray(array[3]);
-          }
+  /**
+   * Set the flags.
+   *
+   * @public
+   * @memberof Annotation
+   * @param {number} flags - Unsigned 32-bit integer specifying annotation
+   *                         characteristics
+   * @see {@link shared/util.js}
+   */
+  setFlags(flags) {
+    this.flags = (isInt(flags) && flags > 0) ? flags : 0;
+  }
+
+  /**
+   * Check if a provided flag is set.
+   *
+   * @public
+   * @memberof Annotation
+   * @param {number} flag - Hexadecimal representation for an annotation
+   *                        characteristic
+   * @return {boolean}
+   * @see {@link shared/util.js}
+   */
+  hasFlag(flag) {
+    return this._hasFlag(this.flags, flag);
+  }
+
+  /**
+   * Set the rectangle.
+   *
+   * @public
+   * @memberof Annotation
+   * @param {Array} rectangle - The rectangle array with exactly four entries
+   */
+  setRectangle(rectangle) {
+    if (isArray(rectangle) && rectangle.length === 4) {
+      this.rectangle = Util.normalizeRect(rectangle);
+    } else {
+      this.rectangle = [0, 0, 0, 0];
+    }
+  }
+
+  /**
+   * Set the color and take care of color space conversion.
+   *
+   * @public
+   * @memberof Annotation
+   * @param {Array} color - The color array containing either 0
+   *                        (transparent), 1 (grayscale), 3 (RGB) or
+   *                        4 (CMYK) elements
+   */
+  setColor(color) {
+    let rgbColor = new Uint8Array(3); // Black in RGB color space (default)
+    if (!isArray(color)) {
+      this.color = rgbColor;
+      return;
+    }
+
+    switch (color.length) {
+      case 0: // Transparent, which we indicate with a null value
+        this.color = null;
+        break;
+
+      case 1: // Convert grayscale to RGB
+        ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0);
+        this.color = rgbColor;
+        break;
+
+      case 3: // Convert RGB percentages to RGB
+        ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0);
+        this.color = rgbColor;
+        break;
+
+      case 4: // Convert CMYK to RGB
+        ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0);
+        this.color = rgbColor;
+        break;
+
+      default:
+        this.color = rgbColor;
+        break;
+    }
+  }
+
+  /**
+   * Set the border style (as AnnotationBorderStyle object).
+   *
+   * @public
+   * @memberof Annotation
+   * @param {Dict} borderStyle - The border style dictionary
+   */
+  setBorderStyle(borderStyle) {
+    this.borderStyle = new AnnotationBorderStyle();
+    if (!isDict(borderStyle)) {
+      return;
+    }
+    if (borderStyle.has('BS')) {
+      let dict = borderStyle.get('BS');
+      let dictType = dict.get('Type');
+
+      if (!dictType || isName(dictType, 'Border')) {
+        this.borderStyle.setWidth(dict.get('W'));
+        this.borderStyle.setStyle(dict.get('S'));
+        this.borderStyle.setDashArray(dict.getArray('D'));
+      }
+    } else if (borderStyle.has('Border')) {
+      let array = borderStyle.getArray('Border');
+      if (isArray(array) && array.length >= 3) {
+        this.borderStyle.setHorizontalCornerRadius(array[0]);
+        this.borderStyle.setVerticalCornerRadius(array[1]);
+        this.borderStyle.setWidth(array[2]);
+
+        if (array.length === 4) { // Dash array available
+          this.borderStyle.setDashArray(array[3]);
         }
-      } else {
-        // There are no border entries in the dictionary. According to the
-        // specification, we should draw a solid border of width 1 in that
-        // case, but Adobe Reader did not implement that part of the
-        // specification and instead draws no border at all, so we do the same.
-        // See also https://github.com/mozilla/pdf.js/issues/6179.
-        this.borderStyle.setWidth(0);
-      }
-    },
-
-    /**
-     * Set the (normal) appearance.
-     *
-     * @public
-     * @memberof Annotation
-     * @param {Dict} dict - The annotation's data dictionary
-     */
-    setAppearance: function Annotation_setAppearance(dict) {
-      this.appearance = null;
-
-      var appearanceStates = dict.get('AP');
-      if (!isDict(appearanceStates)) {
-        return;
       }
+    } else {
+      // There are no border entries in the dictionary. According to the
+      // specification, we should draw a solid border of width 1 in that
+      // case, but Adobe Reader did not implement that part of the
+      // specification and instead draws no border at all, so we do the same.
+      // See also https://github.com/mozilla/pdf.js/issues/6179.
+      this.borderStyle.setWidth(0);
+    }
+  }
 
-      // In case the normal appearance is a stream, then it is used directly.
-      var normalAppearanceState = appearanceStates.get('N');
-      if (isStream(normalAppearanceState)) {
-        this.appearance = normalAppearanceState;
-        return;
-      }
-      if (!isDict(normalAppearanceState)) {
-        return;
-      }
+  /**
+   * Set the (normal) appearance.
+   *
+   * @public
+   * @memberof Annotation
+   * @param {Dict} dict - The annotation's data dictionary
+   */
+  setAppearance(dict) {
+    this.appearance = null;
 
-      // In case the normal appearance is a dictionary, the `AS` entry provides
-      // the key of the stream in this dictionary.
-      var as = dict.get('AS');
-      if (!isName(as) || !normalAppearanceState.has(as.name)) {
-        return;
-      }
-      this.appearance = normalAppearanceState.get(as.name);
-    },
-
-    /**
-     * Prepare the annotation for working with a popup in the display layer.
-     *
-     * @private
-     * @memberof Annotation
-     * @param {Dict} dict - The annotation's data dictionary
-     */
-    _preparePopup: function Annotation_preparePopup(dict) {
-      if (!dict.has('C')) {
-        // Fall back to the default background color.
-        this.data.color = null;
-      }
+    let appearanceStates = dict.get('AP');
+    if (!isDict(appearanceStates)) {
+      return;
+    }
 
-      this.data.hasPopup = dict.has('Popup');
-      this.data.title = stringToPDFString(dict.get('T') || '');
-      this.data.contents = stringToPDFString(dict.get('Contents') || '');
-    },
+    // In case the normal appearance is a stream, then it is used directly.
+    let normalAppearanceState = appearanceStates.get('N');
+    if (isStream(normalAppearanceState)) {
+      this.appearance = normalAppearanceState;
+      return;
+    }
+    if (!isDict(normalAppearanceState)) {
+      return;
+    }
 
-    loadResources: function Annotation_loadResources(keys) {
-      return this.appearance.dict.getAsync('Resources').then((resources) => {
-        if (!resources) {
-          return;
-        }
-        let objectLoader = new ObjectLoader(resources, keys, resources.xref);
+    // In case the normal appearance is a dictionary, the `AS` entry provides
+    // the key of the stream in this dictionary.
+    let as = dict.get('AS');
+    if (!isName(as) || !normalAppearanceState.has(as.name)) {
+      return;
+    }
+    this.appearance = normalAppearanceState.get(as.name);
+  }
 
-        return objectLoader.load().then(function() {
-          return resources;
-        });
-      });
-    },
+  /**
+   * Prepare the annotation for working with a popup in the display layer.
+   *
+   * @private
+   * @memberof Annotation
+   * @param {Dict} dict - The annotation's data dictionary
+   */
+  _preparePopup(dict) {
+    if (!dict.has('C')) {
+      // Fall back to the default background color.
+      this.data.color = null;
+    }
+
+    this.data.hasPopup = dict.has('Popup');
+    this.data.title = stringToPDFString(dict.get('T') || '');
+    this.data.contents = stringToPDFString(dict.get('Contents') || '');
+  }
 
-    getOperatorList: function Annotation_getOperatorList(evaluator, task,
-                                                         renderForms) {
-      if (!this.appearance) {
-        return Promise.resolve(new OperatorList());
+  loadResources(keys) {
+    return this.appearance.dict.getAsync('Resources').then((resources) => {
+      if (!resources) {
+        return;
       }
+      let objectLoader = new ObjectLoader(resources, keys, resources.xref);
 
-      var data = this.data;
-      var appearanceDict = this.appearance.dict;
-      var resourcesPromise = this.loadResources([
-        'ExtGState',
-        'ColorSpace',
-        'Pattern',
-        'Shading',
-        'XObject',
-        'Font'
-        // ProcSet
-        // Properties
-      ]);
-      var bbox = appearanceDict.getArray('BBox') || [0, 0, 1, 1];
-      var matrix = appearanceDict.getArray('Matrix') || [1, 0, 0, 1, 0, 0];
-      var transform = getTransformMatrix(data.rect, bbox, matrix);
-
-      return resourcesPromise.then((resources) => {
-        var opList = new OperatorList();
-        opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
-        return evaluator.getOperatorList({
-          stream: this.appearance,
-          task,
-          resources,
-          operatorList: opList,
-        }).then(() => {
-          opList.addOp(OPS.endAnnotation, []);
-          this.appearance.reset();
-          return opList;
-        });
+      return objectLoader.load().then(function() {
+        return resources;
       });
-    },
-  };
+    });
+  }
+
+  getOperatorList(evaluator, task, renderForms) {
+    if (!this.appearance) {
+      return Promise.resolve(new OperatorList());
+    }
 
-  return Annotation;
-})();
+    let data = this.data;
+    let appearanceDict = this.appearance.dict;
+    let resourcesPromise = this.loadResources([
+      'ExtGState',
+      'ColorSpace',
+      'Pattern',
+      'Shading',
+      'XObject',
+      'Font',
+      // ProcSet
+      // Properties
+    ]);
+    let bbox = appearanceDict.getArray('BBox') || [0, 0, 1, 1];
+    let matrix = appearanceDict.getArray('Matrix') || [1, 0, 0, 1, 0, 0];
+    let transform = getTransformMatrix(data.rect, bbox, matrix);
+
+    return resourcesPromise.then((resources) => {
+      let opList = new OperatorList();
+      opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
+      return evaluator.getOperatorList({
+        stream: this.appearance,
+        task,
+        resources,
+        operatorList: opList,
+      }).then(() => {
+        opList.addOp(OPS.endAnnotation, []);
+        this.appearance.reset();
+        return opList;
+      });
+    });
+  }
+}
 
 /**
  * Contains all data regarding an annotation's border style.
- *
- * @class
  */
-var AnnotationBorderStyle = (function AnnotationBorderStyleClosure() {
-  /**
-   * @constructor
-   * @private
-   */
-  function AnnotationBorderStyle() {
+class AnnotationBorderStyle {
+  constructor() {
     this.width = 1;
     this.style = AnnotationBorderStyleType.SOLID;
     this.dashArray = [3];
@@ -458,132 +443,126 @@ var AnnotationBorderStyle = (function AnnotationBorderStyleClosure() {
     this.verticalCornerRadius = 0;
   }
 
-  AnnotationBorderStyle.prototype = {
-    /**
-     * Set the width.
-     *
-     * @public
-     * @memberof AnnotationBorderStyle
-     * @param {integer} width - The width
-     */
-    setWidth: function AnnotationBorderStyle_setWidth(width) {
-      if (width === (width | 0)) {
-        this.width = width;
-      }
-    },
-
-    /**
-     * Set the style.
-     *
-     * @public
-     * @memberof AnnotationBorderStyle
-     * @param {Object} style - The style object
-     * @see {@link shared/util.js}
-     */
-    setStyle: function AnnotationBorderStyle_setStyle(style) {
-      if (!style) {
-        return;
-      }
-      switch (style.name) {
-        case 'S':
-          this.style = AnnotationBorderStyleType.SOLID;
-          break;
+  /**
+   * Set the width.
+   *
+   * @public
+   * @memberof AnnotationBorderStyle
+   * @param {integer} width - The width
+   */
+  setWidth(width) {
+    if (width === (width | 0)) {
+      this.width = width;
+    }
+  }
 
-        case 'D':
-          this.style = AnnotationBorderStyleType.DASHED;
-          break;
+  /**
+   * Set the style.
+   *
+   * @public
+   * @memberof AnnotationBorderStyle
+   * @param {Object} style - The style object
+   * @see {@link shared/util.js}
+   */
+  setStyle(style) {
+    if (!style) {
+      return;
+    }
+    switch (style.name) {
+      case 'S':
+        this.style = AnnotationBorderStyleType.SOLID;
+        break;
 
-        case 'B':
-          this.style = AnnotationBorderStyleType.BEVELED;
-          break;
+      case 'D':
+        this.style = AnnotationBorderStyleType.DASHED;
+        break;
 
-        case 'I':
-          this.style = AnnotationBorderStyleType.INSET;
-          break;
+      case 'B':
+        this.style = AnnotationBorderStyleType.BEVELED;
+        break;
 
-        case 'U':
-          this.style = AnnotationBorderStyleType.UNDERLINE;
-          break;
+      case 'I':
+        this.style = AnnotationBorderStyleType.INSET;
+        break;
+
+      case 'U':
+        this.style = AnnotationBorderStyleType.UNDERLINE;
+        break;
 
-        default:
+      default:
+        break;
+    }
+  }
+
+  /**
+   * Set the dash array.
+   *
+   * @public
+   * @memberof AnnotationBorderStyle
+   * @param {Array} dashArray - The dash array with at least one element
+   */
+  setDashArray(dashArray) {
+    // We validate the dash array, but we do not use it because CSS does not
+    // allow us to change spacing of dashes. For more information, visit
+    // http://www.w3.org/TR/css3-background/#the-border-style.
+    if (isArray(dashArray) && dashArray.length > 0) {
+      // According to the PDF specification: the elements in `dashArray`
+      // shall be numbers that are nonnegative and not all equal to zero.
+      let isValid = true;
+      let allZeros = true;
+      for (let i = 0, len = dashArray.length; i < len; i++) {
+        let element = dashArray[i];
+        let validNumber = (+element >= 0);
+        if (!validNumber) {
+          isValid = false;
           break;
-      }
-    },
-
-    /**
-     * Set the dash array.
-     *
-     * @public
-     * @memberof AnnotationBorderStyle
-     * @param {Array} dashArray - The dash array with at least one element
-     */
-    setDashArray: function AnnotationBorderStyle_setDashArray(dashArray) {
-      // We validate the dash array, but we do not use it because CSS does not
-      // allow us to change spacing of dashes. For more information, visit
-      // http://www.w3.org/TR/css3-background/#the-border-style.
-      if (isArray(dashArray) && dashArray.length > 0) {
-        // According to the PDF specification: the elements in a dashArray
-        // shall be numbers that are nonnegative and not all equal to zero.
-        var isValid = true;
-        var allZeros = true;
-        for (var i = 0, len = dashArray.length; i < len; i++) {
-          var element = dashArray[i];
-          var validNumber = (+element >= 0);
-          if (!validNumber) {
-            isValid = false;
-            break;
-          } else if (element > 0) {
-            allZeros = false;
-          }
+        } else if (element > 0) {
+          allZeros = false;
         }
-        if (isValid && !allZeros) {
-          this.dashArray = dashArray;
-        } else {
-          this.width = 0; // Adobe behavior when the array is invalid.
-        }
-      } else if (dashArray) {
-        this.width = 0; // Adobe behavior when the array is invalid.
-      }
-    },
-
-    /**
-     * Set the horizontal corner radius (from a Border dictionary).
-     *
-     * @public
-     * @memberof AnnotationBorderStyle
-     * @param {integer} radius - The horizontal corner radius
-     */
-    setHorizontalCornerRadius:
-        function AnnotationBorderStyle_setHorizontalCornerRadius(radius) {
-      if (radius === (radius | 0)) {
-        this.horizontalCornerRadius = radius;
       }
-    },
-
-    /**
-     * Set the vertical corner radius (from a Border dictionary).
-     *
-     * @public
-     * @memberof AnnotationBorderStyle
-     * @param {integer} radius - The vertical corner radius
-     */
-    setVerticalCornerRadius:
-        function AnnotationBorderStyle_setVerticalCornerRadius(radius) {
-      if (radius === (radius | 0)) {
-        this.verticalCornerRadius = radius;
+      if (isValid && !allZeros) {
+        this.dashArray = dashArray;
+      } else {
+        this.width = 0; // Adobe behavior when the array is invalid.
       }
-    },
-  };
+    } else if (dashArray) {
+      this.width = 0; // Adobe behavior when the array is invalid.
+    }
+  }
 
-  return AnnotationBorderStyle;
-})();
+  /**
+   * Set the horizontal corner radius (from a Border dictionary).
+   *
+   * @public
+   * @memberof AnnotationBorderStyle
+   * @param {integer} radius - The horizontal corner radius
+   */
+  setHorizontalCornerRadius(radius) {
+    if (radius === (radius | 0)) {
+      this.horizontalCornerRadius = radius;
+    }
+  }
 
-var WidgetAnnotation = (function WidgetAnnotationClosure() {
-  function WidgetAnnotation(params) {
-    Annotation.call(this, params);
+  /**
+   * Set the vertical corner radius (from a Border dictionary).
+   *
+   * @public
+   * @memberof AnnotationBorderStyle
+   * @param {integer} radius - The vertical corner radius
+   */
+  setVerticalCornerRadius(radius) {
+    if (radius === (radius | 0)) {
+      this.verticalCornerRadius = radius;
+    }
+  }
+}
+
+class WidgetAnnotation extends Annotation {
+  constructor(params) {
+    super(params);
 
-    var dict = params.dict;
-    var data = this.data;
+    let dict = params.dict;
+    let data = this.data;
 
     data.annotationType = AnnotationType.WIDGET;
     data.fieldName = this._constructFieldName(dict);
@@ -591,7 +570,7 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() {
                                                   /* getArray = */ true);
     data.alternativeText = stringToPDFString(dict.get('TU') || '');
     data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
-    var fieldType = Util.getInheritableProperty(dict, 'FT');
+    let fieldType = Util.getInheritableProperty(dict, 'FT');
     data.fieldType = isName(fieldType) ? fieldType.name : null;
     this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
 
@@ -608,87 +587,83 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() {
     }
   }
 
-  Util.inherit(WidgetAnnotation, Annotation, {
-    /**
-     * Construct the (fully qualified) field name from the (partial) field
-     * names of the field and its ancestors.
-     *
-     * @private
-     * @memberof WidgetAnnotation
-     * @param {Dict} dict - Complete widget annotation dictionary
-     * @return {string}
-     */
-    _constructFieldName: function WidgetAnnotation_constructFieldName(dict) {
-      // Both the `Parent` and `T` fields are optional. While at least one of
-      // them should be provided, bad PDF generators may fail to do so.
-      if (!dict.has('T') && !dict.has('Parent')) {
-        warn('Unknown field name, falling back to empty field name.');
-        return '';
-      }
+  /**
+   * Construct the (fully qualified) field name from the (partial) field
+   * names of the field and its ancestors.
+   *
+   * @private
+   * @memberof WidgetAnnotation
+   * @param {Dict} dict - Complete widget annotation dictionary
+   * @return {string}
+   */
+  _constructFieldName(dict) {
+    // Both the `Parent` and `T` fields are optional. While at least one of
+    // them should be provided, bad PDF generators may fail to do so.
+    if (!dict.has('T') && !dict.has('Parent')) {
+      warn('Unknown field name, falling back to empty field name.');
+      return '';
+    }
+
+    // If no parent exists, the partial and fully qualified names are equal.
+    if (!dict.has('Parent')) {
+      return stringToPDFString(dict.get('T'));
+    }
+
+    // Form the fully qualified field name by appending the partial name to
+    // the parent's fully qualified name, separated by a period.
+    let fieldName = [];
+    if (dict.has('T')) {
+      fieldName.unshift(stringToPDFString(dict.get('T')));
+    }
 
-      // If no parent exists, the partial and fully qualified names are equal.
-      if (!dict.has('Parent')) {
-        return stringToPDFString(dict.get('T'));
+    let loopDict = dict;
+    while (loopDict.has('Parent')) {
+      loopDict = loopDict.get('Parent');
+      if (!isDict(loopDict)) {
+        // Even though it is not allowed according to the PDF specification,
+        // bad PDF generators may provide a `Parent` entry that is not a
+        // dictionary, but `null` for example (issue 8143).
+        break;
       }
 
-      // Form the fully qualified field name by appending the partial name to
-      // the parent's fully qualified name, separated by a period.
-      var fieldName = [];
-      if (dict.has('T')) {
-        fieldName.unshift(stringToPDFString(dict.get('T')));
+      if (loopDict.has('T')) {
+        fieldName.unshift(stringToPDFString(loopDict.get('T')));
       }
+    }
+    return fieldName.join('.');
+  }
 
-      var loopDict = dict;
-      while (loopDict.has('Parent')) {
-        loopDict = loopDict.get('Parent');
-        if (!isDict(loopDict)) {
-          // Even though it is not allowed according to the PDF specification,
-          // bad PDF generators may provide a `Parent` entry that is not a
-          // dictionary, but `null` for example (issue 8143).
-          break;
-        }
+  /**
+   * Check if a provided field flag is set.
+   *
+   * @public
+   * @memberof WidgetAnnotation
+   * @param {number} flag - Hexadecimal representation for an annotation
+   *                        field characteristic
+   * @return {boolean}
+   * @see {@link shared/util.js}
+   */
+  hasFieldFlag(flag) {
+    return !!(this.data.fieldFlags & flag);
+  }
+}
 
-        if (loopDict.has('T')) {
-          fieldName.unshift(stringToPDFString(loopDict.get('T')));
-        }
-      }
-      return fieldName.join('.');
-    },
-
-    /**
-     * Check if a provided field flag is set.
-     *
-     * @public
-     * @memberof WidgetAnnotation
-     * @param {number} flag - Hexadecimal representation for an annotation
-     *                        field characteristic
-     * @return {boolean}
-     * @see {@link shared/util.js}
-     */
-    hasFieldFlag: function WidgetAnnotation_hasFieldFlag(flag) {
-      return !!(this.data.fieldFlags & flag);
-    },
-  });
-
-  return WidgetAnnotation;
-})();
-
-var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
-  function TextWidgetAnnotation(params) {
-    WidgetAnnotation.call(this, params);
+class TextWidgetAnnotation extends WidgetAnnotation {
+  constructor(params) {
+    super(params);
 
     // The field value is always a string.
     this.data.fieldValue = stringToPDFString(this.data.fieldValue || '');
 
     // Determine the alignment of text in the field.
-    var alignment = Util.getInheritableProperty(params.dict, 'Q');
+    let alignment = Util.getInheritableProperty(params.dict, 'Q');
     if (!isInt(alignment) || alignment < 0 || alignment > 2) {
       alignment = null;
     }
     this.data.textAlignment = alignment;
 
     // Determine the maximum length of text in the field.
-    var maximumLength = Util.getInheritableProperty(params.dict, 'MaxLen');
+    let maximumLength = Util.getInheritableProperty(params.dict, 'MaxLen');
     if (!isInt(maximumLength) || maximumLength < 0) {
       maximumLength = null;
     }
@@ -703,47 +678,41 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
                      this.data.maxLen !== null;
   }
 
-  Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
-    getOperatorList:
-        function TextWidgetAnnotation_getOperatorList(evaluator, task,
-                                                      renderForms) {
-      var operatorList = new OperatorList();
-
-      // Do not render form elements on the canvas when interactive forms are
-      // enabled. The display layer is responsible for rendering them instead.
-      if (renderForms) {
-        return Promise.resolve(operatorList);
-      }
+  getOperatorList(evaluator, task, renderForms) {
+    let operatorList = new OperatorList();
 
-      if (this.appearance) {
-        return Annotation.prototype.getOperatorList.call(this, evaluator, task,
-                                                         renderForms);
-      }
+    // Do not render form elements on the canvas when interactive forms are
+    // enabled. The display layer is responsible for rendering them instead.
+    if (renderForms) {
+      return Promise.resolve(operatorList);
+    }
 
-      // Even if there is an appearance stream, ignore it. This is the
-      // behaviour used by Adobe Reader.
-      if (!this.data.defaultAppearance) {
-        return Promise.resolve(operatorList);
-      }
+    if (this.appearance) {
+      return Annotation.prototype.getOperatorList.call(this, evaluator, task,
+                                                       renderForms);
+    }
 
-      var stream = new Stream(stringToBytes(this.data.defaultAppearance));
-      return evaluator.getOperatorList({
-        stream,
-        task,
-        resources: this.fieldResources,
-        operatorList,
-      }).then(function () {
-        return operatorList;
-      });
-    },
-  });
+    // Even if there is an appearance stream, ignore it. This is the
+    // behaviour used by Adobe Reader.
+    if (!this.data.defaultAppearance) {
+      return Promise.resolve(operatorList);
+    }
 
-  return TextWidgetAnnotation;
-})();
+    let stream = new Stream(stringToBytes(this.data.defaultAppearance));
+    return evaluator.getOperatorList({
+      stream,
+      task,
+      resources: this.fieldResources,
+      operatorList,
+    }).then(function () {
+      return operatorList;
+    });
+  }
+}
 
-var ButtonWidgetAnnotation = (function ButtonWidgetAnnotationClosure() {
-  function ButtonWidgetAnnotation(params) {
-    WidgetAnnotation.call(this, params);
+class ButtonWidgetAnnotation extends WidgetAnnotation {
+  constructor(params) {
+    super(params);
 
     this.data.checkBox = !this.hasFieldFlag(AnnotationFieldFlag.RADIO) &&
                          !this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
@@ -761,25 +730,25 @@ var ButtonWidgetAnnotation = (function ButtonWidgetAnnotationClosure() {
 
       // The parent field's `V` entry holds a `Name` object with the appearance
       // state of whichever child field is currently in the "on" state.
-      var fieldParent = params.dict.get('Parent');
+      let fieldParent = params.dict.get('Parent');
       if (isDict(fieldParent) && fieldParent.has('V')) {
-        var fieldParentValue = fieldParent.get('V');
+        let fieldParentValue = fieldParent.get('V');
         if (isName(fieldParentValue)) {
           this.data.fieldValue = fieldParentValue.name;
         }
       }
 
       // The button's value corresponds to its appearance state.
-      var appearanceStates = params.dict.get('AP');
+      let appearanceStates = params.dict.get('AP');
       if (!isDict(appearanceStates)) {
         return;
       }
-      var normalAppearanceState = appearanceStates.get('N');
+      let normalAppearanceState = appearanceStates.get('N');
       if (!isDict(normalAppearanceState)) {
         return;
       }
-      var keys = normalAppearanceState.getKeys();
-      for (var i = 0, ii = keys.length; i < ii; i++) {
+      let keys = normalAppearanceState.getKeys();
+      for (let i = 0, ii = keys.length; i < ii; i++) {
         if (keys[i] !== 'Off') {
           this.data.buttonValue = keys[i];
           break;
@@ -788,32 +757,26 @@ var ButtonWidgetAnnotation = (function ButtonWidgetAnnotationClosure() {
     }
   }
 
-  Util.inherit(ButtonWidgetAnnotation, WidgetAnnotation, {
-    getOperatorList:
-        function ButtonWidgetAnnotation_getOperatorList(evaluator, task,
-                                                        renderForms) {
-      var operatorList = new OperatorList();
+  getOperatorList(evaluator, task, renderForms) {
+    let operatorList = new OperatorList();
 
-      // Do not render form elements on the canvas when interactive forms are
-      // enabled. The display layer is responsible for rendering them instead.
-      if (renderForms) {
-        return Promise.resolve(operatorList);
-      }
-
-      if (this.appearance) {
-        return Annotation.prototype.getOperatorList.call(this, evaluator, task,
-                                                         renderForms);
-      }
+    // Do not render form elements on the canvas when interactive forms are
+    // enabled. The display layer is responsible for rendering them instead.
+    if (renderForms) {
       return Promise.resolve(operatorList);
-    },
-  });
+    }
 
-  return ButtonWidgetAnnotation;
-})();
+    if (this.appearance) {
+      return Annotation.prototype.getOperatorList.call(this, evaluator, task,
+                                                       renderForms);
+    }
+    return Promise.resolve(operatorList);
+  }
+}
 
-var ChoiceWidgetAnnotation = (function ChoiceWidgetAnnotationClosure() {
-  function ChoiceWidgetAnnotation(params) {
-    WidgetAnnotation.call(this, params);
+class ChoiceWidgetAnnotation extends WidgetAnnotation {
+  constructor(params) {
+    super(params);
 
     // Determine the options. The options array may consist of strings or
     // arrays. If the array consists of arrays, then the first element of
@@ -826,12 +789,12 @@ var ChoiceWidgetAnnotation = (function ChoiceWidgetAnnotationClosure() {
     // inherit the options from a parent annotation (issue 8094).
     this.data.options = [];
 
-    var options = Util.getInheritableProperty(params.dict, 'Opt');
+    let options = Util.getInheritableProperty(params.dict, 'Opt');
     if (isArray(options)) {
-      var xref = params.xref;
-      for (var i = 0, ii = options.length; i < ii; i++) {
-        var option = xref.fetchIfRef(options[i]);
-        var isOptionArray = isArray(option);
+      let xref = params.xref;
+      for (let i = 0, ii = options.length; i < ii; i++) {
+        let option = xref.fetchIfRef(options[i]);
+        let isOptionArray = isArray(option);
 
         this.data.options[i] = {
           exportValue: isOptionArray ? xref.fetchIfRef(option[0]) : option,
@@ -852,31 +815,25 @@ var ChoiceWidgetAnnotation = (function ChoiceWidgetAnnotationClosure() {
     this.data.multiSelect = this.hasFieldFlag(AnnotationFieldFlag.MULTISELECT);
   }
 
-  Util.inherit(ChoiceWidgetAnnotation, WidgetAnnotation, {
-    getOperatorList:
-        function ChoiceWidgetAnnotation_getOperatorList(evaluator, task,
-                                                        renderForms) {
-      var operatorList = new OperatorList();
+  getOperatorList(evaluator, task, renderForms) {
+    let operatorList = new OperatorList();
 
-      // Do not render form elements on the canvas when interactive forms are
-      // enabled. The display layer is responsible for rendering them instead.
-      if (renderForms) {
-        return Promise.resolve(operatorList);
-      }
-
-      return Annotation.prototype.getOperatorList.call(this, evaluator, task,
-                                                       renderForms);
-    },
-  });
+    // Do not render form elements on the canvas when interactive forms are
+    // enabled. The display layer is responsible for rendering them instead.
+    if (renderForms) {
+      return Promise.resolve(operatorList);
+    }
 
-  return ChoiceWidgetAnnotation;
-})();
+    return Annotation.prototype.getOperatorList.call(this, evaluator, task,
+                                                     renderForms);
+  }
+}
 
-var TextAnnotation = (function TextAnnotationClosure() {
-  var DEFAULT_ICON_SIZE = 22; // px
+class TextAnnotation extends Annotation {
+  constructor(parameters) {
+    const DEFAULT_ICON_SIZE = 22; // px
 
-  function TextAnnotation(parameters) {
-    Annotation.call(this, parameters);
+    super(parameters);
 
     this.data.annotationType = AnnotationType.TEXT;
 
@@ -890,45 +847,36 @@ var TextAnnotation = (function TextAnnotationClosure() {
     }
     this._preparePopup(parameters.dict);
   }
+}
 
-  Util.inherit(TextAnnotation, Annotation, {});
-
-  return TextAnnotation;
-})();
+class LinkAnnotation extends Annotation {
+  constructor(params) {
+    super(params);
 
-var LinkAnnotation = (function LinkAnnotationClosure() {
-  function LinkAnnotation(params) {
-    Annotation.call(this, params);
-
-    var data = this.data;
-    data.annotationType = AnnotationType.LINK;
+    this.data.annotationType = AnnotationType.LINK;
 
     Catalog.parseDestDictionary({
       destDict: params.dict,
-      resultObj: data,
+      resultObj: this.data,
       docBaseUrl: params.pdfManager.docBaseUrl,
     });
   }
+}
 
-  Util.inherit(LinkAnnotation, Annotation, {});
-
-  return LinkAnnotation;
-})();
-
-var PopupAnnotation = (function PopupAnnotationClosure() {
-  function PopupAnnotation(parameters) {
-    Annotation.call(this, parameters);
+class PopupAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
 
     this.data.annotationType = AnnotationType.POPUP;
 
-    var dict = parameters.dict;
-    var parentItem = dict.get('Parent');
+    let dict = parameters.dict;
+    let parentItem = dict.get('Parent');
     if (!parentItem) {
       warn('Popup annotation has a missing or invalid parent annotation.');
       return;
     }
 
-    var parentSubtype = parentItem.get('Subtype');
+    let parentSubtype = parentItem.get('Subtype');
     this.data.parentType = isName(parentSubtype) ? parentSubtype.name : null;
     this.data.parentId = dict.getRaw('Parent').toString();
     this.data.title = stringToPDFString(parentItem.get('T') || '');
@@ -946,101 +894,73 @@ var PopupAnnotation = (function PopupAnnotationClosure() {
     // that is most likely a bug. Fallback to inherit the flags from the parent
     // annotation (this is consistent with the behaviour in Adobe Reader).
     if (!this.viewable) {
-      var parentFlags = parentItem.get('F');
+      let parentFlags = parentItem.get('F');
       if (this._isViewable(parentFlags)) {
         this.setFlags(parentFlags);
       }
     }
   }
+}
 
-  Util.inherit(PopupAnnotation, Annotation, {});
-
-  return PopupAnnotation;
-})();
-
-var LineAnnotation = (function LineAnnotationClosure() {
-  function LineAnnotation(parameters) {
-    Annotation.call(this, parameters);
+class LineAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
 
     this.data.annotationType = AnnotationType.LINE;
 
-    var dict = parameters.dict;
+    let dict = parameters.dict;
     this.data.lineCoordinates = Util.normalizeRect(dict.getArray('L'));
     this._preparePopup(dict);
   }
+}
 
-  Util.inherit(LineAnnotation, Annotation, {});
-
-  return LineAnnotation;
-})();
-
-var HighlightAnnotation = (function HighlightAnnotationClosure() {
-  function HighlightAnnotation(parameters) {
-    Annotation.call(this, parameters);
+class HighlightAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
 
     this.data.annotationType = AnnotationType.HIGHLIGHT;
     this._preparePopup(parameters.dict);
   }
+}
 
-  Util.inherit(HighlightAnnotation, Annotation, {});
-
-  return HighlightAnnotation;
-})();
-
-var UnderlineAnnotation = (function UnderlineAnnotationClosure() {
-  function UnderlineAnnotation(parameters) {
-    Annotation.call(this, parameters);
+class UnderlineAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
 
     this.data.annotationType = AnnotationType.UNDERLINE;
     this._preparePopup(parameters.dict);
   }
+}
 
-  Util.inherit(UnderlineAnnotation, Annotation, {});
-
-  return UnderlineAnnotation;
-})();
-
-var SquigglyAnnotation = (function SquigglyAnnotationClosure() {
-  function SquigglyAnnotation(parameters) {
-    Annotation.call(this, parameters);
+class SquigglyAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
 
     this.data.annotationType = AnnotationType.SQUIGGLY;
     this._preparePopup(parameters.dict);
   }
+}
 
-  Util.inherit(SquigglyAnnotation, Annotation, {});
-
-  return SquigglyAnnotation;
-})();
-
-var StrikeOutAnnotation = (function StrikeOutAnnotationClosure() {
-  function StrikeOutAnnotation(parameters) {
-    Annotation.call(this, parameters);
+class StrikeOutAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
 
     this.data.annotationType = AnnotationType.STRIKEOUT;
     this._preparePopup(parameters.dict);
   }
+}
 
-  Util.inherit(StrikeOutAnnotation, Annotation, {});
-
-  return StrikeOutAnnotation;
-})();
+class FileAttachmentAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
 
-var FileAttachmentAnnotation = (function FileAttachmentAnnotationClosure() {
-  function FileAttachmentAnnotation(parameters) {
-    Annotation.call(this, parameters);
-
-    var file = new FileSpec(parameters.dict.get('FS'), parameters.xref);
+    let file = new FileSpec(parameters.dict.get('FS'), parameters.xref);
 
     this.data.annotationType = AnnotationType.FILEATTACHMENT;
     this.data.file = file.serializable;
     this._preparePopup(parameters.dict);
   }
-
-  Util.inherit(FileAttachmentAnnotation, Annotation, {});
-
-  return FileAttachmentAnnotation;
-})();
+}
 
 export {
   Annotation,

From af10f8b5866a7ec6a2ae1d988271b6ff8f70f5a4 Mon Sep 17 00:00:00 2001
From: Tim van der Meij <timvandermeij@gmail.com>
Date: Sun, 27 Aug 2017 00:24:27 +0200
Subject: [PATCH 2/5] Convert `src/display/annotation_layer.js` to ES6 syntax

---
 src/display/annotation_layer.js | 1714 ++++++++++++++-----------------
 1 file changed, 773 insertions(+), 941 deletions(-)

diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js
index 7166d0d4e..0b95e10d8 100644
--- a/src/display/annotation_layer.js
+++ b/src/display/annotation_layer.js
@@ -33,19 +33,13 @@ import {
  * @property {boolean} renderInteractiveForms
  */
 
-/**
- * @class
- * @alias AnnotationElementFactory
- */
-function AnnotationElementFactory() {}
-AnnotationElementFactory.prototype =
-    /** @lends AnnotationElementFactory.prototype */ {
+class AnnotationElementFactory {
   /**
    * @param {AnnotationElementParameters} parameters
    * @returns {AnnotationElement}
    */
-  create: function AnnotationElementFactory_create(parameters) {
-    var subtype = parameters.data.annotationType;
+  create(parameters) {
+    let subtype = parameters.data.annotationType;
 
     switch (subtype) {
       case AnnotationType.LINK:
@@ -55,7 +49,7 @@ AnnotationElementFactory.prototype =
         return new TextAnnotationElement(parameters);
 
       case AnnotationType.WIDGET:
-        var fieldType = parameters.data.fieldType;
+        let fieldType = parameters.data.fieldType;
 
         switch (fieldType) {
           case 'Tx':
@@ -97,16 +91,12 @@ AnnotationElementFactory.prototype =
       default:
         return new AnnotationElement(parameters);
     }
-  },
-};
+  }
+}
 
-/**
- * @class
- * @alias AnnotationElement
- */
-var AnnotationElement = (function AnnotationElementClosure() {
-  function AnnotationElement(parameters, isRenderable, ignoreBorder) {
-    this.isRenderable = isRenderable || false;
+class AnnotationElement {
+  constructor(parameters, isRenderable = true, ignoreBorder = false) {
+    this.isRenderable = isRenderable;
     this.data = parameters.data;
     this.layer = parameters.layer;
     this.page = parameters.page;
@@ -121,610 +111,517 @@ var AnnotationElement = (function AnnotationElementClosure() {
     }
   }
 
-  AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ {
-    /**
-     * Create an empty container for the annotation's HTML element.
-     *
-     * @private
-     * @param {boolean} ignoreBorder
-     * @memberof AnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    _createContainer:
-        function AnnotationElement_createContainer(ignoreBorder) {
-      var data = this.data, page = this.page, viewport = this.viewport;
-      var container = document.createElement('section');
-      var width = data.rect[2] - data.rect[0];
-      var height = data.rect[3] - data.rect[1];
-
-      container.setAttribute('data-annotation-id', data.id);
-
-      // Do *not* modify `data.rect`, since that will corrupt the annotation
-      // position on subsequent calls to `_createContainer` (see issue 6804).
-      var rect = Util.normalizeRect([
-        data.rect[0],
-        page.view[3] - data.rect[1] + page.view[1],
-        data.rect[2],
-        page.view[3] - data.rect[3] + page.view[1]
-      ]);
-
-      CustomStyle.setProp('transform', container,
-                          'matrix(' + viewport.transform.join(',') + ')');
-      CustomStyle.setProp('transformOrigin', container,
-                          -rect[0] + 'px ' + -rect[1] + 'px');
-
-      if (!ignoreBorder && data.borderStyle.width > 0) {
-        container.style.borderWidth = data.borderStyle.width + 'px';
-        if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {
-          // Underline styles only have a bottom border, so we do not need
-          // to adjust for all borders. This yields a similar result as
-          // Adobe Acrobat/Reader.
-          width = width - 2 * data.borderStyle.width;
-          height = height - 2 * data.borderStyle.width;
-        }
-
-        var horizontalRadius = data.borderStyle.horizontalCornerRadius;
-        var verticalRadius = data.borderStyle.verticalCornerRadius;
-        if (horizontalRadius > 0 || verticalRadius > 0) {
-          var radius = horizontalRadius + 'px / ' + verticalRadius + 'px';
-          CustomStyle.setProp('borderRadius', container, radius);
-        }
+  /**
+   * Create an empty container for the annotation's HTML element.
+   *
+   * @private
+   * @param {boolean} ignoreBorder
+   * @memberof AnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  _createContainer(ignoreBorder = false) {
+    let data = this.data, page = this.page, viewport = this.viewport;
+    let container = document.createElement('section');
+    let width = data.rect[2] - data.rect[0];
+    let height = data.rect[3] - data.rect[1];
+
+    container.setAttribute('data-annotation-id', data.id);
+
+    // Do *not* modify `data.rect`, since that will corrupt the annotation
+    // position on subsequent calls to `_createContainer` (see issue 6804).
+    let rect = Util.normalizeRect([
+      data.rect[0],
+      page.view[3] - data.rect[1] + page.view[1],
+      data.rect[2],
+      page.view[3] - data.rect[3] + page.view[1]
+    ]);
+
+    CustomStyle.setProp('transform', container,
+                        'matrix(' + viewport.transform.join(',') + ')');
+    CustomStyle.setProp('transformOrigin', container,
+                        -rect[0] + 'px ' + -rect[1] + 'px');
+
+    if (!ignoreBorder && data.borderStyle.width > 0) {
+      container.style.borderWidth = data.borderStyle.width + 'px';
+      if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {
+        // Underline styles only have a bottom border, so we do not need
+        // to adjust for all borders. This yields a similar result as
+        // Adobe Acrobat/Reader.
+        width = width - 2 * data.borderStyle.width;
+        height = height - 2 * data.borderStyle.width;
+      }
 
-        switch (data.borderStyle.style) {
-          case AnnotationBorderStyleType.SOLID:
-            container.style.borderStyle = 'solid';
-            break;
+      let horizontalRadius = data.borderStyle.horizontalCornerRadius;
+      let verticalRadius = data.borderStyle.verticalCornerRadius;
+      if (horizontalRadius > 0 || verticalRadius > 0) {
+        let radius = horizontalRadius + 'px / ' + verticalRadius + 'px';
+        CustomStyle.setProp('borderRadius', container, radius);
+      }
 
-          case AnnotationBorderStyleType.DASHED:
-            container.style.borderStyle = 'dashed';
-            break;
+      switch (data.borderStyle.style) {
+        case AnnotationBorderStyleType.SOLID:
+          container.style.borderStyle = 'solid';
+          break;
 
-          case AnnotationBorderStyleType.BEVELED:
-            warn('Unimplemented border style: beveled');
-            break;
+        case AnnotationBorderStyleType.DASHED:
+          container.style.borderStyle = 'dashed';
+          break;
 
-          case AnnotationBorderStyleType.INSET:
-            warn('Unimplemented border style: inset');
-            break;
+        case AnnotationBorderStyleType.BEVELED:
+          warn('Unimplemented border style: beveled');
+          break;
 
-          case AnnotationBorderStyleType.UNDERLINE:
-            container.style.borderBottomStyle = 'solid';
-            break;
+        case AnnotationBorderStyleType.INSET:
+          warn('Unimplemented border style: inset');
+          break;
 
-          default:
-            break;
-        }
+        case AnnotationBorderStyleType.UNDERLINE:
+          container.style.borderBottomStyle = 'solid';
+          break;
 
-        if (data.color) {
-          container.style.borderColor =
-            Util.makeCssRgb(data.color[0] | 0,
-                            data.color[1] | 0,
-                            data.color[2] | 0);
-        } else {
-          // Transparent (invisible) border, so do not draw it at all.
-          container.style.borderWidth = 0;
-        }
+        default:
+          break;
       }
 
-      container.style.left = rect[0] + 'px';
-      container.style.top = rect[1] + 'px';
-
-      container.style.width = width + 'px';
-      container.style.height = height + 'px';
-
-      return container;
-    },
-
-    /**
-     * Create a popup for the annotation's HTML element. This is used for
-     * annotations that do not have a Popup entry in the dictionary, but
-     * are of a type that works with popups (such as Highlight annotations).
-     *
-     * @private
-     * @param {HTMLSectionElement} container
-     * @param {HTMLDivElement|HTMLImageElement|null} trigger
-     * @param {Object} data
-     * @memberof AnnotationElement
-     */
-    _createPopup:
-        function AnnotationElement_createPopup(container, trigger, data) {
-      // If no trigger element is specified, create it.
-      if (!trigger) {
-        trigger = document.createElement('div');
-        trigger.style.height = container.style.height;
-        trigger.style.width = container.style.width;
-        container.appendChild(trigger);
+      if (data.color) {
+        container.style.borderColor = Util.makeCssRgb(data.color[0] | 0,
+                                                      data.color[1] | 0,
+                                                      data.color[2] | 0);
+      } else {
+        // Transparent (invisible) border, so do not draw it at all.
+        container.style.borderWidth = 0;
       }
+    }
 
-      var popupElement = new PopupElement({
-        container,
-        trigger,
-        color: data.color,
-        title: data.title,
-        contents: data.contents,
-        hideWrapper: true,
-      });
-      var popup = popupElement.render();
+    container.style.left = rect[0] + 'px';
+    container.style.top = rect[1] + 'px';
 
-      // Position the popup next to the annotation's container.
-      popup.style.left = container.style.width;
+    container.style.width = width + 'px';
+    container.style.height = height + 'px';
 
-      container.appendChild(popup);
-    },
+    return container;
+  }
+
+  /**
+   * Create a popup for the annotation's HTML element. This is used for
+   * annotations that do not have a Popup entry in the dictionary, but
+   * are of a type that works with popups (such as Highlight annotations).
+   *
+   * @private
+   * @param {HTMLSectionElement} container
+   * @param {HTMLDivElement|HTMLImageElement|null} trigger
+   * @param {Object} data
+   * @memberof AnnotationElement
+   */
+  _createPopup(container, trigger, data) {
+    // If no trigger element is specified, create it.
+    if (!trigger) {
+      trigger = document.createElement('div');
+      trigger.style.height = container.style.height;
+      trigger.style.width = container.style.width;
+      container.appendChild(trigger);
+    }
 
-    /**
-     * Render the annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof AnnotationElement
-     */
-    render: function AnnotationElement_render() {
-      throw new Error('Abstract method AnnotationElement.render called');
-    },
-  };
+    let popupElement = new PopupElement({
+      container,
+      trigger,
+      color: data.color,
+      title: data.title,
+      contents: data.contents,
+      hideWrapper: true,
+    });
+    let popup = popupElement.render();
 
-  return AnnotationElement;
-})();
+    // Position the popup next to the annotation's container.
+    popup.style.left = container.style.width;
 
-/**
- * @class
- * @alias LinkAnnotationElement
- */
-var LinkAnnotationElement = (function LinkAnnotationElementClosure() {
-  function LinkAnnotationElement(parameters) {
-    AnnotationElement.call(this, parameters, true);
+    container.appendChild(popup);
   }
 
-  Util.inherit(LinkAnnotationElement, AnnotationElement, {
-    /**
-     * Render the link annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof LinkAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function LinkAnnotationElement_render() {
-      this.container.className = 'linkAnnotation';
-
-      var link = document.createElement('a');
-      addLinkAttributes(link, {
-        url: this.data.url,
-        target: (this.data.newWindow ? LinkTarget.BLANK : undefined),
-      });
+  /**
+   * Render the annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof AnnotationElement
+   */
+  render() {
+    throw new Error('Abstract method `AnnotationElement.render` called');
+  }
+}
 
-      if (!this.data.url) {
-        if (this.data.action) {
-          this._bindNamedAction(link, this.data.action);
-        } else {
-          this._bindLink(link, this.data.dest);
-        }
+class LinkAnnotationElement extends AnnotationElement {
+  /**
+   * Render the link annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof LinkAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'linkAnnotation';
+
+    let link = document.createElement('a');
+    addLinkAttributes(link, {
+      url: this.data.url,
+      target: (this.data.newWindow ? LinkTarget.BLANK : undefined),
+    });
+
+    if (!this.data.url) {
+      if (this.data.action) {
+        this._bindNamedAction(link, this.data.action);
+      } else {
+        this._bindLink(link, this.data.dest);
       }
+    }
 
-      this.container.appendChild(link);
-      return this.container;
-    },
-
-    /**
-     * Bind internal links to the link element.
-     *
-     * @private
-     * @param {Object} link
-     * @param {Object} destination
-     * @memberof LinkAnnotationElement
-     */
-    _bindLink(link, destination) {
-      link.href = this.linkService.getDestinationHash(destination);
-      link.onclick = () => {
-        if (destination) {
-          this.linkService.navigateTo(destination);
-        }
-        return false;
-      };
+    this.container.appendChild(link);
+    return this.container;
+  }
+
+  /**
+   * Bind internal links to the link element.
+   *
+   * @private
+   * @param {Object} link
+   * @param {Object} destination
+   * @memberof LinkAnnotationElement
+   */
+  _bindLink(link, destination) {
+    link.href = this.linkService.getDestinationHash(destination);
+    link.onclick = () => {
       if (destination) {
-        link.className = 'internalLink';
+        this.linkService.navigateTo(destination);
       }
-    },
-
-    /**
-     * Bind named actions to the link element.
-     *
-     * @private
-     * @param {Object} link
-     * @param {Object} action
-     * @memberof LinkAnnotationElement
-     */
-    _bindNamedAction(link, action) {
-      link.href = this.linkService.getAnchorUrl('');
-      link.onclick = () => {
-        this.linkService.executeNamedAction(action);
-        return false;
-      };
+      return false;
+    };
+    if (destination) {
       link.className = 'internalLink';
-    },
-  });
+    }
+  }
 
-  return LinkAnnotationElement;
-})();
+  /**
+   * Bind named actions to the link element.
+   *
+   * @private
+   * @param {Object} link
+   * @param {Object} action
+   * @memberof LinkAnnotationElement
+   */
+  _bindNamedAction(link, action) {
+    link.href = this.linkService.getAnchorUrl('');
+    link.onclick = () => {
+      this.linkService.executeNamedAction(action);
+      return false;
+    };
+    link.className = 'internalLink';
+  }
+}
 
-/**
- * @class
- * @alias TextAnnotationElement
- */
-var TextAnnotationElement = (function TextAnnotationElementClosure() {
-  function TextAnnotationElement(parameters) {
-    var isRenderable = !!(parameters.data.hasPopup ||
+class TextAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.hasPopup ||
                           parameters.data.title || parameters.data.contents);
-    AnnotationElement.call(this, parameters, isRenderable);
+    super(parameters, isRenderable);
   }
 
-  Util.inherit(TextAnnotationElement, AnnotationElement, {
-    /**
-     * Render the text annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof TextAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function TextAnnotationElement_render() {
-      this.container.className = 'textAnnotation';
-
-      var image = document.createElement('img');
-      image.style.height = this.container.style.height;
-      image.style.width = this.container.style.width;
-      image.src = this.imageResourcesPath + 'annotation-' +
-        this.data.name.toLowerCase() + '.svg';
-      image.alt = '[{{type}} Annotation]';
-      image.dataset.l10nId = 'text_annotation_type';
-      image.dataset.l10nArgs = JSON.stringify({ type: this.data.name, });
-
-      if (!this.data.hasPopup) {
-        this._createPopup(this.container, image, this.data);
-      }
-
-      this.container.appendChild(image);
-      return this.container;
-    },
-  });
-
-  return TextAnnotationElement;
-})();
+  /**
+   * Render the text annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof TextAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'textAnnotation';
+
+    let image = document.createElement('img');
+    image.style.height = this.container.style.height;
+    image.style.width = this.container.style.width;
+    image.src = this.imageResourcesPath + 'annotation-' +
+      this.data.name.toLowerCase() + '.svg';
+    image.alt = '[{{type}} Annotation]';
+    image.dataset.l10nId = 'text_annotation_type';
+    image.dataset.l10nArgs = JSON.stringify({ type: this.data.name, });
+
+    if (!this.data.hasPopup) {
+      this._createPopup(this.container, image, this.data);
+    }
 
-/**
- * @class
- * @alias WidgetAnnotationElement
- */
-var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
-  function WidgetAnnotationElement(parameters, isRenderable) {
-    AnnotationElement.call(this, parameters, isRenderable);
+    this.container.appendChild(image);
+    return this.container;
   }
+}
 
-  Util.inherit(WidgetAnnotationElement, AnnotationElement, {
-    /**
-     * Render the widget annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof WidgetAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function WidgetAnnotationElement_render() {
-      // Show only the container for unsupported field types.
-      return this.container;
-    },
-  });
-
-  return WidgetAnnotationElement;
-})();
-
-/**
- * @class
- * @alias TextWidgetAnnotationElement
- */
-var TextWidgetAnnotationElement = (
-    function TextWidgetAnnotationElementClosure() {
-  var TEXT_ALIGNMENT = ['left', 'center', 'right'];
+class WidgetAnnotationElement extends AnnotationElement {
+  /**
+   * Render the widget annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof WidgetAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    // Show only the container for unsupported field types.
+    return this.container;
+  }
+}
 
-  function TextWidgetAnnotationElement(parameters) {
-    var isRenderable = parameters.renderInteractiveForms ||
+class TextWidgetAnnotationElement extends WidgetAnnotationElement {
+  constructor(parameters) {
+    let isRenderable = parameters.renderInteractiveForms ||
       (!parameters.data.hasAppearance && !!parameters.data.fieldValue);
-    WidgetAnnotationElement.call(this, parameters, isRenderable);
+    super(parameters, isRenderable);
   }
 
-  Util.inherit(TextWidgetAnnotationElement, WidgetAnnotationElement, {
-    /**
-     * Render the text widget annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof TextWidgetAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function TextWidgetAnnotationElement_render() {
-      this.container.className = 'textWidgetAnnotation';
-
-      var element = null;
-      if (this.renderInteractiveForms) {
-        // NOTE: We cannot set the values using `element.value` below, since it
-        //       prevents the AnnotationLayer rasterizer in `test/driver.js`
-        //       from parsing the elements correctly for the reference tests.
-        if (this.data.multiLine) {
-          element = document.createElement('textarea');
-          element.textContent = this.data.fieldValue;
-        } else {
-          element = document.createElement('input');
-          element.type = 'text';
-          element.setAttribute('value', this.data.fieldValue);
-        }
-
-        element.disabled = this.data.readOnly;
-
-        if (this.data.maxLen !== null) {
-          element.maxLength = this.data.maxLen;
-        }
-
-        if (this.data.comb) {
-          var fieldWidth = this.data.rect[2] - this.data.rect[0];
-          var combWidth = fieldWidth / this.data.maxLen;
-
-          element.classList.add('comb');
-          element.style.letterSpacing = 'calc(' + combWidth + 'px - 1ch)';
-        }
-      } else {
-        element = document.createElement('div');
+  /**
+   * Render the text widget annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof TextWidgetAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    const TEXT_ALIGNMENT = ['left', 'center', 'right'];
+
+    this.container.className = 'textWidgetAnnotation';
+
+    let element = null;
+    if (this.renderInteractiveForms) {
+      // NOTE: We cannot set the values using `element.value` below, since it
+      //       prevents the AnnotationLayer rasterizer in `test/driver.js`
+      //       from parsing the elements correctly for the reference tests.
+      if (this.data.multiLine) {
+        element = document.createElement('textarea');
         element.textContent = this.data.fieldValue;
-        element.style.verticalAlign = 'middle';
-        element.style.display = 'table-cell';
-
-        var font = null;
-        if (this.data.fontRefName) {
-          font = this.page.commonObjs.getData(this.data.fontRefName);
-        }
-        this._setTextStyle(element, font);
+      } else {
+        element = document.createElement('input');
+        element.type = 'text';
+        element.setAttribute('value', this.data.fieldValue);
       }
 
-      if (this.data.textAlignment !== null) {
-        element.style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment];
-      }
+      element.disabled = this.data.readOnly;
 
-      this.container.appendChild(element);
-      return this.container;
-    },
-
-    /**
-     * Apply text styles to the text in the element.
-     *
-     * @private
-     * @param {HTMLDivElement} element
-     * @param {Object} font
-     * @memberof TextWidgetAnnotationElement
-     */
-    _setTextStyle:
-        function TextWidgetAnnotationElement_setTextStyle(element, font) {
-      // TODO: This duplicates some of the logic in CanvasGraphics.setFont().
-      var style = element.style;
-      style.fontSize = this.data.fontSize + 'px';
-      style.direction = (this.data.fontDirection < 0 ? 'rtl' : 'ltr');
-
-      if (!font) {
-        return;
+      if (this.data.maxLen !== null) {
+        element.maxLength = this.data.maxLen;
       }
 
-      style.fontWeight = (font.black ?
-        (font.bold ? '900' : 'bold') :
-        (font.bold ? 'bold' : 'normal'));
-      style.fontStyle = (font.italic ? 'italic' : 'normal');
+      if (this.data.comb) {
+        let fieldWidth = this.data.rect[2] - this.data.rect[0];
+        let combWidth = fieldWidth / this.data.maxLen;
 
-      // Use a reasonable default font if the font doesn't specify a fallback.
-      var fontFamily = font.loadedName ? '"' + font.loadedName + '", ' : '';
-      var fallbackName = font.fallbackName || 'Helvetica, sans-serif';
-      style.fontFamily = fontFamily + fallbackName;
-    },
-  });
+        element.classList.add('comb');
+        element.style.letterSpacing = 'calc(' + combWidth + 'px - 1ch)';
+      }
+    } else {
+      element = document.createElement('div');
+      element.textContent = this.data.fieldValue;
+      element.style.verticalAlign = 'middle';
+      element.style.display = 'table-cell';
+
+      let font = null;
+      if (this.data.fontRefName) {
+        font = this.page.commonObjs.getData(this.data.fontRefName);
+      }
+      this._setTextStyle(element, font);
+    }
 
-  return TextWidgetAnnotationElement;
-})();
+    if (this.data.textAlignment !== null) {
+      element.style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment];
+    }
 
-/**
- * @class
- * @alias CheckboxWidgetAnnotationElement
- */
-var CheckboxWidgetAnnotationElement =
-    (function CheckboxWidgetAnnotationElementClosure() {
-  function CheckboxWidgetAnnotationElement(parameters) {
-    WidgetAnnotationElement.call(this, parameters,
-                                 parameters.renderInteractiveForms);
+    this.container.appendChild(element);
+    return this.container;
   }
 
-  Util.inherit(CheckboxWidgetAnnotationElement, WidgetAnnotationElement, {
-    /**
-     * Render the checkbox widget annotation's HTML element
-     * in the empty container.
-     *
-     * @public
-     * @memberof CheckboxWidgetAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function CheckboxWidgetAnnotationElement_render() {
-      this.container.className = 'buttonWidgetAnnotation checkBox';
-
-      var element = document.createElement('input');
-      element.disabled = this.data.readOnly;
-      element.type = 'checkbox';
-      if (this.data.fieldValue && this.data.fieldValue !== 'Off') {
-        element.setAttribute('checked', true);
-      }
+  /**
+   * Apply text styles to the text in the element.
+   *
+   * @private
+   * @param {HTMLDivElement} element
+   * @param {Object} font
+   * @memberof TextWidgetAnnotationElement
+   */
+  _setTextStyle(element, font) {
+    // TODO: This duplicates some of the logic in CanvasGraphics.setFont().
+    let style = element.style;
+    style.fontSize = this.data.fontSize + 'px';
+    style.direction = (this.data.fontDirection < 0 ? 'rtl' : 'ltr');
+
+    if (!font) {
+      return;
+    }
 
-      this.container.appendChild(element);
-      return this.container;
-    },
-  });
+    style.fontWeight = (font.black ?
+      (font.bold ? '900' : 'bold') :
+      (font.bold ? 'bold' : 'normal'));
+    style.fontStyle = (font.italic ? 'italic' : 'normal');
 
-  return CheckboxWidgetAnnotationElement;
-})();
+    // Use a reasonable default font if the font doesn't specify a fallback.
+    let fontFamily = font.loadedName ? '"' + font.loadedName + '", ' : '';
+    let fallbackName = font.fallbackName || 'Helvetica, sans-serif';
+    style.fontFamily = fontFamily + fallbackName;
+  }
+}
 
-/**
- * @class
- * @alias RadioButtonWidgetAnnotationElement
- */
-var RadioButtonWidgetAnnotationElement =
-    (function RadioButtonWidgetAnnotationElementClosure() {
-  function RadioButtonWidgetAnnotationElement(parameters) {
-    WidgetAnnotationElement.call(this, parameters,
-                                 parameters.renderInteractiveForms);
+class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
+  constructor(parameters) {
+    super(parameters, parameters.renderInteractiveForms);
   }
 
-  Util.inherit(RadioButtonWidgetAnnotationElement, WidgetAnnotationElement, {
-    /**
-     * Render the radio button widget annotation's HTML element
-     * in the empty container.
-     *
-     * @public
-     * @memberof RadioButtonWidgetAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function RadioButtonWidgetAnnotationElement_render() {
-      this.container.className = 'buttonWidgetAnnotation radioButton';
-
-      var element = document.createElement('input');
-      element.disabled = this.data.readOnly;
-      element.type = 'radio';
-      element.name = this.data.fieldName;
-      if (this.data.fieldValue === this.data.buttonValue) {
-        element.setAttribute('checked', true);
-      }
+  /**
+   * Render the checkbox widget annotation's HTML element
+   * in the empty container.
+   *
+   * @public
+   * @memberof CheckboxWidgetAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'buttonWidgetAnnotation checkBox';
+
+    let element = document.createElement('input');
+    element.disabled = this.data.readOnly;
+    element.type = 'checkbox';
+    if (this.data.fieldValue && this.data.fieldValue !== 'Off') {
+      element.setAttribute('checked', true);
+    }
 
-      this.container.appendChild(element);
-      return this.container;
-    },
-  });
+    this.container.appendChild(element);
+    return this.container;
+  }
+}
 
-  return RadioButtonWidgetAnnotationElement;
-})();
+class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
+  constructor(parameters) {
+    super(parameters, parameters.renderInteractiveForms);
+  }
 
- /**
- * @class
- * @alias ChoiceWidgetAnnotationElement
- */
-var ChoiceWidgetAnnotationElement = (
-    function ChoiceWidgetAnnotationElementClosure() {
-  function ChoiceWidgetAnnotationElement(parameters) {
-    WidgetAnnotationElement.call(this, parameters,
-                                 parameters.renderInteractiveForms);
+  /**
+   * Render the radio button widget annotation's HTML element
+   * in the empty container.
+   *
+   * @public
+   * @memberof RadioButtonWidgetAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'buttonWidgetAnnotation radioButton';
+
+    let element = document.createElement('input');
+    element.disabled = this.data.readOnly;
+    element.type = 'radio';
+    element.name = this.data.fieldName;
+    if (this.data.fieldValue === this.data.buttonValue) {
+      element.setAttribute('checked', true);
+    }
+
+    this.container.appendChild(element);
+    return this.container;
   }
+}
 
-  Util.inherit(ChoiceWidgetAnnotationElement, WidgetAnnotationElement, {
-    /**
-     * Render the choice widget annotation's HTML element in the empty
-     * container.
-     *
-     * @public
-     * @memberof ChoiceWidgetAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function ChoiceWidgetAnnotationElement_render() {
-      this.container.className = 'choiceWidgetAnnotation';
-
-      var selectElement = document.createElement('select');
-      selectElement.disabled = this.data.readOnly;
-
-      if (!this.data.combo) {
-        // List boxes have a size and (optionally) multiple selection.
-        selectElement.size = this.data.options.length;
-
-        if (this.data.multiSelect) {
-          selectElement.multiple = true;
-        }
-      }
+class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
+  constructor(parameters) {
+    super(parameters, parameters.renderInteractiveForms);
+  }
 
-      // Insert the options into the choice field.
-      for (var i = 0, ii = this.data.options.length; i < ii; i++) {
-        var option = this.data.options[i];
+  /**
+   * Render the choice widget annotation's HTML element in the empty
+   * container.
+   *
+   * @public
+   * @memberof ChoiceWidgetAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'choiceWidgetAnnotation';
 
-        var optionElement = document.createElement('option');
-        optionElement.textContent = option.displayValue;
-        optionElement.value = option.exportValue;
+    let selectElement = document.createElement('select');
+    selectElement.disabled = this.data.readOnly;
 
-        if (this.data.fieldValue.indexOf(option.displayValue) >= 0) {
-          optionElement.setAttribute('selected', true);
-        }
+    if (!this.data.combo) {
+      // List boxes have a size and (optionally) multiple selection.
+      selectElement.size = this.data.options.length;
 
-        selectElement.appendChild(optionElement);
+      if (this.data.multiSelect) {
+        selectElement.multiple = true;
       }
+    }
 
-      this.container.appendChild(selectElement);
-      return this.container;
-    },
-  });
+    // Insert the options into the choice field.
+    for (let i = 0, ii = this.data.options.length; i < ii; i++) {
+      let option = this.data.options[i];
 
-  return ChoiceWidgetAnnotationElement;
-})();
+      let optionElement = document.createElement('option');
+      optionElement.textContent = option.displayValue;
+      optionElement.value = option.exportValue;
 
-/**
- * @class
- * @alias PopupAnnotationElement
- */
-var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
-  // Do not render popup annotations for parent elements with these types as
-  // they create the popups themselves (because of custom trigger divs).
-  var IGNORE_TYPES = ['Line'];
-
-  function PopupAnnotationElement(parameters) {
-    var isRenderable = !!(parameters.data.title || parameters.data.contents);
-    AnnotationElement.call(this, parameters, isRenderable);
+      if (this.data.fieldValue.indexOf(option.displayValue) >= 0) {
+        optionElement.setAttribute('selected', true);
+      }
+
+      selectElement.appendChild(optionElement);
+    }
+
+    this.container.appendChild(selectElement);
+    return this.container;
   }
+}
 
-  Util.inherit(PopupAnnotationElement, AnnotationElement, {
-    /**
-     * Render the popup annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof PopupAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function PopupAnnotationElement_render() {
-      this.container.className = 'popupAnnotation';
-
-      if (IGNORE_TYPES.indexOf(this.data.parentType) >= 0) {
-        return this.container;
-      }
+class PopupAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.title || parameters.data.contents);
+    super(parameters, isRenderable);
+  }
 
-      var selector = '[data-annotation-id="' + this.data.parentId + '"]';
-      var parentElement = this.layer.querySelector(selector);
-      if (!parentElement) {
-        return this.container;
-      }
+  /**
+   * Render the popup annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof PopupAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    // Do not render popup annotations for parent elements with these types as
+    // they create the popups themselves (because of custom trigger divs).
+    const IGNORE_TYPES = ['Line'];
 
-      var popup = new PopupElement({
-        container: this.container,
-        trigger: parentElement,
-        color: this.data.color,
-        title: this.data.title,
-        contents: this.data.contents,
-      });
+    this.container.className = 'popupAnnotation';
 
-      // Position the popup next to the parent annotation's container.
-      // PDF viewers ignore a popup annotation's rectangle.
-      var parentLeft = parseFloat(parentElement.style.left);
-      var parentWidth = parseFloat(parentElement.style.width);
-      CustomStyle.setProp('transformOrigin', this.container,
-                          -(parentLeft + parentWidth) + 'px -' +
-                          parentElement.style.top);
-      this.container.style.left = (parentLeft + parentWidth) + 'px';
+    if (IGNORE_TYPES.indexOf(this.data.parentType) >= 0) {
+      return this.container;
+    }
 
-      this.container.appendChild(popup.render());
+    let selector = '[data-annotation-id="' + this.data.parentId + '"]';
+    let parentElement = this.layer.querySelector(selector);
+    if (!parentElement) {
       return this.container;
-    },
-  });
+    }
 
-  return PopupAnnotationElement;
-})();
+    let popup = new PopupElement({
+      container: this.container,
+      trigger: parentElement,
+      color: this.data.color,
+      title: this.data.title,
+      contents: this.data.contents,
+    });
 
-/**
- * @class
- * @alias PopupElement
- */
-var PopupElement = (function PopupElementClosure() {
-  var BACKGROUND_ENLIGHT = 0.7;
+    // Position the popup next to the parent annotation's container.
+    // PDF viewers ignore a popup annotation's rectangle.
+    let parentLeft = parseFloat(parentElement.style.left);
+    let parentWidth = parseFloat(parentElement.style.width);
+    CustomStyle.setProp('transformOrigin', this.container,
+                        -(parentLeft + parentWidth) + 'px -' +
+                        parentElement.style.top);
+    this.container.style.left = (parentLeft + parentWidth) + 'px';
+
+    this.container.appendChild(popup.render());
+    return this.container;
+  }
+}
 
-  function PopupElement(parameters) {
+class PopupElement {
+  constructor(parameters) {
     this.container = parameters.container;
     this.trigger = parameters.trigger;
     this.color = parameters.color;
@@ -735,334 +632,279 @@ var PopupElement = (function PopupElementClosure() {
     this.pinned = false;
   }
 
-  PopupElement.prototype = /** @lends PopupElement.prototype */ {
-    /**
-     * Render the popup's HTML element.
-     *
-     * @public
-     * @memberof PopupElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function PopupElement_render() {
-      var wrapper = document.createElement('div');
-      wrapper.className = 'popupWrapper';
-
-      // For Popup annotations we hide the entire section because it contains
-      // only the popup. However, for Text annotations without a separate Popup
-      // annotation, we cannot hide the entire container as the image would
-      // disappear too. In that special case, hiding the wrapper suffices.
-      this.hideElement = (this.hideWrapper ? wrapper : this.container);
-      this.hideElement.setAttribute('hidden', true);
+  /**
+   * Render the popup's HTML element.
+   *
+   * @public
+   * @memberof PopupElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    const BACKGROUND_ENLIGHT = 0.7;
+
+    let wrapper = document.createElement('div');
+    wrapper.className = 'popupWrapper';
+
+    // For Popup annotations we hide the entire section because it contains
+    // only the popup. However, for Text annotations without a separate Popup
+    // annotation, we cannot hide the entire container as the image would
+    // disappear too. In that special case, hiding the wrapper suffices.
+    this.hideElement = (this.hideWrapper ? wrapper : this.container);
+    this.hideElement.setAttribute('hidden', true);
+
+    let popup = document.createElement('div');
+    popup.className = 'popup';
+
+    let color = this.color;
+    if (color) {
+      // Enlighten the color.
+      let r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0];
+      let g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1];
+      let b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2];
+      popup.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0);
+    }
 
-      var popup = document.createElement('div');
-      popup.className = 'popup';
+    let contents = this._formatContents(this.contents);
+    let title = document.createElement('h1');
+    title.textContent = this.title;
 
-      var color = this.color;
-      if (color) {
-        // Enlighten the color.
-        var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0];
-        var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1];
-        var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2];
-        popup.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0);
-      }
+    // Attach the event listeners to the trigger element.
+    this.trigger.addEventListener('click', this._toggle.bind(this));
+    this.trigger.addEventListener('mouseover', this._show.bind(this, false));
+    this.trigger.addEventListener('mouseout', this._hide.bind(this, false));
+    popup.addEventListener('click', this._hide.bind(this, true));
 
-      var contents = this._formatContents(this.contents);
-      var title = document.createElement('h1');
-      title.textContent = this.title;
-
-      // Attach the event listeners to the trigger element.
-      this.trigger.addEventListener('click', this._toggle.bind(this));
-      this.trigger.addEventListener('mouseover', this._show.bind(this, false));
-      this.trigger.addEventListener('mouseout', this._hide.bind(this, false));
-      popup.addEventListener('click', this._hide.bind(this, true));
-
-      popup.appendChild(title);
-      popup.appendChild(contents);
-      wrapper.appendChild(popup);
-      return wrapper;
-    },
-
-    /**
-     * Format the contents of the popup by adding newlines where necessary.
-     *
-     * @private
-     * @param {string} contents
-     * @memberof PopupElement
-     * @returns {HTMLParagraphElement}
-     */
-    _formatContents: function PopupElement_formatContents(contents) {
-      var p = document.createElement('p');
-      var lines = contents.split(/(?:\r\n?|\n)/);
-      for (var i = 0, ii = lines.length; i < ii; ++i) {
-        var line = lines[i];
-        p.appendChild(document.createTextNode(line));
-        if (i < (ii - 1)) {
-          p.appendChild(document.createElement('br'));
-        }
-      }
-      return p;
-    },
-
-    /**
-     * Toggle the visibility of the popup.
-     *
-     * @private
-     * @memberof PopupElement
-     */
-    _toggle: function PopupElement_toggle() {
-      if (this.pinned) {
-        this._hide(true);
-      } else {
-        this._show(true);
-      }
-    },
-
-    /**
-     * Show the popup.
-     *
-     * @private
-     * @param {boolean} pin
-     * @memberof PopupElement
-     */
-    _show: function PopupElement_show(pin) {
-      if (pin) {
-        this.pinned = true;
-      }
-      if (this.hideElement.hasAttribute('hidden')) {
-        this.hideElement.removeAttribute('hidden');
-        this.container.style.zIndex += 1;
-      }
-    },
-
-    /**
-     * Hide the popup.
-     *
-     * @private
-     * @param {boolean} unpin
-     * @memberof PopupElement
-     */
-    _hide: function PopupElement_hide(unpin) {
-      if (unpin) {
-        this.pinned = false;
-      }
-      if (!this.hideElement.hasAttribute('hidden') && !this.pinned) {
-        this.hideElement.setAttribute('hidden', true);
-        this.container.style.zIndex -= 1;
-      }
-    },
-  };
+    popup.appendChild(title);
+    popup.appendChild(contents);
+    wrapper.appendChild(popup);
+    return wrapper;
+  }
 
-  return PopupElement;
-})();
+  /**
+   * Format the contents of the popup by adding newlines where necessary.
+   *
+   * @private
+   * @param {string} contents
+   * @memberof PopupElement
+   * @returns {HTMLParagraphElement}
+   */
+  _formatContents(contents) {
+    let p = document.createElement('p');
+    let lines = contents.split(/(?:\r\n?|\n)/);
+    for (let i = 0, ii = lines.length; i < ii; ++i) {
+      let line = lines[i];
+      p.appendChild(document.createTextNode(line));
+      if (i < (ii - 1)) {
+        p.appendChild(document.createElement('br'));
+      }
+    }
+    return p;
+  }
 
-/**
- * @class
- * @alias LineAnnotationElement
- */
-var LineAnnotationElement = (function LineAnnotationElementClosure() {
-  var SVG_NS = 'http://www.w3.org/2000/svg';
+  /**
+   * Toggle the visibility of the popup.
+   *
+   * @private
+   * @memberof PopupElement
+   */
+  _toggle() {
+    if (this.pinned) {
+      this._hide(true);
+    } else {
+      this._show(true);
+    }
+  }
 
-  function LineAnnotationElement(parameters) {
-    var isRenderable = !!(parameters.data.hasPopup ||
-                          parameters.data.title || parameters.data.contents);
-    AnnotationElement.call(this, parameters, isRenderable,
-                           /* ignoreBorder = */ true);
+  /**
+   * Show the popup.
+   *
+   * @private
+   * @param {boolean} pin
+   * @memberof PopupElement
+   */
+  _show(pin = false) {
+    if (pin) {
+      this.pinned = true;
+    }
+    if (this.hideElement.hasAttribute('hidden')) {
+      this.hideElement.removeAttribute('hidden');
+      this.container.style.zIndex += 1;
+    }
   }
 
-  Util.inherit(LineAnnotationElement, AnnotationElement, {
-    /**
-     * Render the line annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof LineAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function LineAnnotationElement_render() {
-      this.container.className = 'lineAnnotation';
-
-      // Create an invisible line with the same starting and ending coordinates
-      // that acts as the trigger for the popup. Only the line itself should
-      // trigger the popup, not the entire container.
-      var data = this.data;
-      var width = data.rect[2] - data.rect[0];
-      var height = data.rect[3] - data.rect[1];
-
-      var 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);
-
-      // PDF coordinates are calculated from a bottom left origin, so transform
-      // the line coordinates to a top left origin for the SVG element.
-      var 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');
-
-      svg.appendChild(line);
-      this.container.append(svg);
-
-      // Create the popup ourselves so that we can bind it to the line instead
-      // of to the entire container (which is the default).
-      this._createPopup(this.container, line, this.data);
+  /**
+   * Hide the popup.
+   *
+   * @private
+   * @param {boolean} unpin
+   * @memberof PopupElement
+   */
+  _hide(unpin = true) {
+    if (unpin) {
+      this.pinned = false;
+    }
+    if (!this.hideElement.hasAttribute('hidden') && !this.pinned) {
+      this.hideElement.setAttribute('hidden', true);
+      this.container.style.zIndex -= 1;
+    }
+  }
+}
 
-      return this.container;
-    },
-  });
+class LineAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.hasPopup ||
+                          parameters.data.title || parameters.data.contents);
+    super(parameters, isRenderable, /* ignoreBorder = */ true);
+  }
 
-  return LineAnnotationElement;
-})();
+  /**
+   * Render the line annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof LineAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    const SVG_NS = 'http://www.w3.org/2000/svg';
+
+    this.container.className = 'lineAnnotation';
+
+    // Create an invisible line with the same starting and ending coordinates
+    // that acts as the trigger for the popup. Only the line itself should
+    // trigger the popup, not the entire container.
+    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);
+
+    // PDF coordinates are calculated from a bottom left origin, so transform
+    // the line coordinates to a top left origin for the SVG element.
+    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');
+
+    svg.appendChild(line);
+    this.container.append(svg);
+
+    // Create the popup ourselves so that we can bind it to the line instead
+    // of to the entire container (which is the default).
+    this._createPopup(this.container, line, this.data);
+
+    return this.container;
+  }
+}
 
-/**
- * @class
- * @alias HighlightAnnotationElement
- */
-var HighlightAnnotationElement = (
-    function HighlightAnnotationElementClosure() {
-  function HighlightAnnotationElement(parameters) {
-    var isRenderable = !!(parameters.data.hasPopup ||
+class HighlightAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.hasPopup ||
                           parameters.data.title || parameters.data.contents);
-    AnnotationElement.call(this, parameters, isRenderable,
-                           /* ignoreBorder = */ true);
+    super(parameters, isRenderable, /* ignoreBorder = */ true);
   }
 
-  Util.inherit(HighlightAnnotationElement, AnnotationElement, {
-    /**
-     * Render the highlight annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof HighlightAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function HighlightAnnotationElement_render() {
-      this.container.className = 'highlightAnnotation';
-
-      if (!this.data.hasPopup) {
-        this._createPopup(this.container, null, this.data);
-      }
-      return this.container;
-    },
-  });
+  /**
+   * Render the highlight annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof HighlightAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'highlightAnnotation';
 
-  return HighlightAnnotationElement;
-})();
+    if (!this.data.hasPopup) {
+      this._createPopup(this.container, null, this.data);
+    }
+    return this.container;
+  }
+}
 
-/**
- * @class
- * @alias UnderlineAnnotationElement
- */
-var UnderlineAnnotationElement = (
-    function UnderlineAnnotationElementClosure() {
-  function UnderlineAnnotationElement(parameters) {
-    var isRenderable = !!(parameters.data.hasPopup ||
+class UnderlineAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.hasPopup ||
                           parameters.data.title || parameters.data.contents);
-    AnnotationElement.call(this, parameters, isRenderable,
-                           /* ignoreBorder = */ true);
+    super(parameters, isRenderable, /* ignoreBorder = */ true);
   }
 
-  Util.inherit(UnderlineAnnotationElement, AnnotationElement, {
-    /**
-     * Render the underline annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof UnderlineAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function UnderlineAnnotationElement_render() {
-      this.container.className = 'underlineAnnotation';
-
-      if (!this.data.hasPopup) {
-        this._createPopup(this.container, null, this.data);
-      }
-      return this.container;
-    },
-  });
+  /**
+   * Render the underline annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof UnderlineAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'underlineAnnotation';
 
-  return UnderlineAnnotationElement;
-})();
+    if (!this.data.hasPopup) {
+      this._createPopup(this.container, null, this.data);
+    }
+    return this.container;
+  }
+}
 
-/**
- * @class
- * @alias SquigglyAnnotationElement
- */
-var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
-  function SquigglyAnnotationElement(parameters) {
-    var isRenderable = !!(parameters.data.hasPopup ||
+class SquigglyAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.hasPopup ||
                           parameters.data.title || parameters.data.contents);
-    AnnotationElement.call(this, parameters, isRenderable,
-                           /* ignoreBorder = */ true);
+    super(parameters, isRenderable, /* ignoreBorder = */ true);
   }
 
-  Util.inherit(SquigglyAnnotationElement, AnnotationElement, {
-    /**
-     * Render the squiggly annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof SquigglyAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function SquigglyAnnotationElement_render() {
-      this.container.className = 'squigglyAnnotation';
-
-      if (!this.data.hasPopup) {
-        this._createPopup(this.container, null, this.data);
-      }
-      return this.container;
-    },
-  });
+  /**
+   * Render the squiggly annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof SquigglyAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'squigglyAnnotation';
 
-  return SquigglyAnnotationElement;
-})();
+    if (!this.data.hasPopup) {
+      this._createPopup(this.container, null, this.data);
+    }
+    return this.container;
+  }
+}
 
-/**
- * @class
- * @alias StrikeOutAnnotationElement
- */
-var StrikeOutAnnotationElement = (
-    function StrikeOutAnnotationElementClosure() {
-  function StrikeOutAnnotationElement(parameters) {
-    var isRenderable = !!(parameters.data.hasPopup ||
+class StrikeOutAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.hasPopup ||
                           parameters.data.title || parameters.data.contents);
-    AnnotationElement.call(this, parameters, isRenderable,
-                           /* ignoreBorder = */ true);
+    super(parameters, isRenderable, /* ignoreBorder = */ true);
   }
 
-  Util.inherit(StrikeOutAnnotationElement, AnnotationElement, {
-    /**
-     * Render the strikeout annotation's HTML element in the empty container.
-     *
-     * @public
-     * @memberof StrikeOutAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function StrikeOutAnnotationElement_render() {
-      this.container.className = 'strikeoutAnnotation';
-
-      if (!this.data.hasPopup) {
-        this._createPopup(this.container, null, this.data);
-      }
-      return this.container;
-    },
-  });
+  /**
+   * Render the strikeout annotation's HTML element in the empty container.
+   *
+   * @public
+   * @memberof StrikeOutAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'strikeoutAnnotation';
 
-  return StrikeOutAnnotationElement;
-})();
+    if (!this.data.hasPopup) {
+      this._createPopup(this.container, null, this.data);
+    }
+    return this.container;
+  }
+}
 
-/**
- * @class
- * @alias FileAttachmentAnnotationElement
- */
-var FileAttachmentAnnotationElement = (
-    function FileAttachmentAnnotationElementClosure() {
-  function FileAttachmentAnnotationElement(parameters) {
-    AnnotationElement.call(this, parameters, true);
+class FileAttachmentAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    super(parameters, true);
 
-    var file = this.data.file;
+    let file = this.data.file;
     this.filename = getFilenameFromUrl(file.filename);
     this.content = file.content;
 
@@ -1073,48 +915,44 @@ var FileAttachmentAnnotationElement = (
     });
   }
 
-  Util.inherit(FileAttachmentAnnotationElement, AnnotationElement, {
-    /**
-     * Render the file attachment annotation's HTML element in the empty
-     * container.
-     *
-     * @public
-     * @memberof FileAttachmentAnnotationElement
-     * @returns {HTMLSectionElement}
-     */
-    render: function FileAttachmentAnnotationElement_render() {
-      this.container.className = 'fileAttachmentAnnotation';
-
-      var trigger = document.createElement('div');
-      trigger.style.height = this.container.style.height;
-      trigger.style.width = this.container.style.width;
-      trigger.addEventListener('dblclick', this._download.bind(this));
-
-      if (!this.data.hasPopup && (this.data.title || this.data.contents)) {
-        this._createPopup(this.container, trigger, this.data);
-      }
+  /**
+   * Render the file attachment annotation's HTML element in the empty
+   * container.
+   *
+   * @public
+   * @memberof FileAttachmentAnnotationElement
+   * @returns {HTMLSectionElement}
+   */
+  render() {
+    this.container.className = 'fileAttachmentAnnotation';
 
-      this.container.appendChild(trigger);
-      return this.container;
-    },
-
-    /**
-     * Download the file attachment associated with this annotation.
-     *
-     * @private
-     * @memberof FileAttachmentAnnotationElement
-     */
-    _download: function FileAttachmentAnnotationElement_download() {
-      if (!this.downloadManager) {
-        warn('Download cannot be started due to unavailable download manager');
-        return;
-      }
-      this.downloadManager.downloadData(this.content, this.filename, '');
-    },
-  });
+    let trigger = document.createElement('div');
+    trigger.style.height = this.container.style.height;
+    trigger.style.width = this.container.style.width;
+    trigger.addEventListener('dblclick', this._download.bind(this));
+
+    if (!this.data.hasPopup && (this.data.title || this.data.contents)) {
+      this._createPopup(this.container, trigger, this.data);
+    }
 
-  return FileAttachmentAnnotationElement;
-})();
+    this.container.appendChild(trigger);
+    return this.container;
+  }
+
+  /**
+   * Download the file attachment associated with this annotation.
+   *
+   * @private
+   * @memberof FileAttachmentAnnotationElement
+   */
+  _download() {
+    if (!this.downloadManager) {
+      warn('Download cannot be started due to unavailable download manager');
+      return;
+    }
+    this.downloadManager.downloadData(this.content, this.filename, '');
+  }
+}
 
 /**
  * @typedef {Object} AnnotationLayerParameters
@@ -1127,65 +965,59 @@ var FileAttachmentAnnotationElement = (
  * @property {boolean} renderInteractiveForms
  */
 
-/**
- * @class
- * @alias AnnotationLayer
- */
-var AnnotationLayer = (function AnnotationLayerClosure() {
-  return {
-    /**
-     * Render a new annotation layer with all annotation elements.
-     *
-     * @public
-     * @param {AnnotationLayerParameters} parameters
-     * @memberof AnnotationLayer
-     */
-    render: function AnnotationLayer_render(parameters) {
-      var annotationElementFactory = new AnnotationElementFactory();
-
-      for (var i = 0, ii = parameters.annotations.length; i < ii; i++) {
-        var data = parameters.annotations[i];
-        if (!data) {
-          continue;
-        }
-        var element = annotationElementFactory.create({
-          data,
-          layer: parameters.div,
-          page: parameters.page,
-          viewport: parameters.viewport,
-          linkService: parameters.linkService,
-          downloadManager: parameters.downloadManager,
-          imageResourcesPath: parameters.imageResourcesPath ||
-                              getDefaultSetting('imageResourcesPath'),
-          renderInteractiveForms: parameters.renderInteractiveForms || false,
-        });
-        if (element.isRenderable) {
-          parameters.div.appendChild(element.render());
-        }
+class AnnotationLayer {
+  /**
+   * Render a new annotation layer with all annotation elements.
+   *
+   * @public
+   * @param {AnnotationLayerParameters} parameters
+   * @memberof AnnotationLayer
+   */
+  static render(parameters) {
+    let annotationElementFactory = new AnnotationElementFactory();
+
+    for (let i = 0, ii = parameters.annotations.length; i < ii; i++) {
+      let data = parameters.annotations[i];
+      if (!data) {
+        continue;
       }
-    },
-
-    /**
-     * Update the annotation elements on existing annotation layer.
-     *
-     * @public
-     * @param {AnnotationLayerParameters} parameters
-     * @memberof AnnotationLayer
-     */
-    update: function AnnotationLayer_update(parameters) {
-      for (var i = 0, ii = parameters.annotations.length; i < ii; i++) {
-        var data = parameters.annotations[i];
-        var element = parameters.div.querySelector(
-          '[data-annotation-id="' + data.id + '"]');
-        if (element) {
-          CustomStyle.setProp('transform', element,
-            'matrix(' + parameters.viewport.transform.join(',') + ')');
-        }
+      let element = annotationElementFactory.create({
+        data,
+        layer: parameters.div,
+        page: parameters.page,
+        viewport: parameters.viewport,
+        linkService: parameters.linkService,
+        downloadManager: parameters.downloadManager,
+        imageResourcesPath: parameters.imageResourcesPath ||
+                            getDefaultSetting('imageResourcesPath'),
+        renderInteractiveForms: parameters.renderInteractiveForms || false,
+      });
+      if (element.isRenderable) {
+        parameters.div.appendChild(element.render());
       }
-      parameters.div.removeAttribute('hidden');
-    },
-  };
-})();
+    }
+  }
+
+  /**
+   * Update the annotation elements on existing annotation layer.
+   *
+   * @public
+   * @param {AnnotationLayerParameters} parameters
+   * @memberof AnnotationLayer
+   */
+  static update(parameters) {
+    for (let i = 0, ii = parameters.annotations.length; i < ii; i++) {
+      let data = parameters.annotations[i];
+      let element = parameters.div.querySelector(
+        '[data-annotation-id="' + data.id + '"]');
+      if (element) {
+        CustomStyle.setProp('transform', element,
+          'matrix(' + parameters.viewport.transform.join(',') + ')');
+      }
+    }
+    parameters.div.removeAttribute('hidden');
+  }
+}
 
 export {
   AnnotationLayer,

From 4f0285739403ebf30ef7be4a05c8a639d7d4edab Mon Sep 17 00:00:00 2001
From: Tim van der Meij <timvandermeij@gmail.com>
Date: Sun, 27 Aug 2017 00:30:00 +0200
Subject: [PATCH 3/5] Let the two annotation factories use static methods

This corresponds to how other factories are implemented.
---
 src/core/annotation.js          |  2 +-
 src/core/document.js            |  3 +-
 src/display/annotation_layer.js |  6 +--
 test/unit/annotation_spec.js    | 90 ++++++++++++++++-----------------
 4 files changed, 48 insertions(+), 53 deletions(-)

diff --git a/src/core/annotation.js b/src/core/annotation.js
index f036cd571..f2099a984 100644
--- a/src/core/annotation.js
+++ b/src/core/annotation.js
@@ -32,7 +32,7 @@ class AnnotationFactory {
    * @param {Object} idFactory
    * @returns {Annotation}
    */
-  create(xref, ref, pdfManager, idFactory) {
+  static create(xref, ref, pdfManager, idFactory) {
     let dict = xref.fetchIfRef(ref);
     if (!isDict(dict)) {
       return;
diff --git a/src/core/document.js b/src/core/document.js
index 0a477aa5a..6af6033e9 100644
--- a/src/core/document.js
+++ b/src/core/document.js
@@ -316,10 +316,9 @@ var Page = (function PageClosure() {
     get annotations() {
       var annotations = [];
       var annotationRefs = this.getInheritedPageProp('Annots') || [];
-      var annotationFactory = new AnnotationFactory();
       for (var i = 0, n = annotationRefs.length; i < n; ++i) {
         var annotationRef = annotationRefs[i];
-        var annotation = annotationFactory.create(this.xref, annotationRef,
+        var annotation = AnnotationFactory.create(this.xref, annotationRef,
                                                   this.pdfManager,
                                                   this.idFactory);
         if (annotation) {
diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js
index 0b95e10d8..13c15184e 100644
--- a/src/display/annotation_layer.js
+++ b/src/display/annotation_layer.js
@@ -38,7 +38,7 @@ class AnnotationElementFactory {
    * @param {AnnotationElementParameters} parameters
    * @returns {AnnotationElement}
    */
-  create(parameters) {
+  static create(parameters) {
     let subtype = parameters.data.annotationType;
 
     switch (subtype) {
@@ -974,14 +974,12 @@ class AnnotationLayer {
    * @memberof AnnotationLayer
    */
   static render(parameters) {
-    let annotationElementFactory = new AnnotationElementFactory();
-
     for (let i = 0, ii = parameters.annotations.length; i < ii; i++) {
       let data = parameters.annotations[i];
       if (!data) {
         continue;
       }
-      let element = annotationElementFactory.create({
+      let element = AnnotationElementFactory.create({
         data,
         layer: parameters.div,
         page: parameters.page,
diff --git a/test/unit/annotation_spec.js b/test/unit/annotation_spec.js
index 15975f9f0..6f54e1586 100644
--- a/test/unit/annotation_spec.js
+++ b/test/unit/annotation_spec.js
@@ -44,10 +44,9 @@ describe('annotation', function() {
   }
   IdFactoryMock.prototype = {};
 
-  var annotationFactory, pdfManagerMock, idFactoryMock;
+  var pdfManagerMock, idFactoryMock;
 
   beforeAll(function (done) {
-    annotationFactory = new AnnotationFactory();
     pdfManagerMock = new PDFManagerMock({
       docBaseUrl: null,
     });
@@ -56,7 +55,6 @@ describe('annotation', function() {
   });
 
   afterAll(function () {
-    annotationFactory = null;
     pdfManagerMock = null;
     idFactoryMock = null;
   });
@@ -72,7 +70,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -92,9 +90,9 @@ describe('annotation', function() {
         startObjId: 0,
       });
 
-      var annotation1 = annotationFactory.create(xref, annotationDict,
+      var annotation1 = AnnotationFactory.create(xref, annotationDict,
                                                  pdfManagerMock, idFactory);
-      var annotation2 = annotationFactory.create(xref, annotationDict,
+      var annotation2 = AnnotationFactory.create(xref, annotationDict,
                                                  pdfManagerMock, idFactory);
       var data1 = annotation1.data, data2 = annotation2.data;
       expect(data1.annotationType).toEqual(AnnotationType.LINK);
@@ -113,7 +111,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toBeUndefined();
@@ -298,7 +296,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -326,7 +324,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -359,7 +357,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -389,7 +387,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -418,7 +416,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -450,7 +448,7 @@ describe('annotation', function() {
         docBaseUrl: 'http://www.example.com/test/pdfs/qwerty.pdf',
       });
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManager, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -479,7 +477,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -508,7 +506,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -548,7 +546,7 @@ describe('annotation', function() {
         docBaseUrl: 'http://www.example.com/test/pdfs/qwerty.pdf',
       });
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManager, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -583,7 +581,7 @@ describe('annotation', function() {
           { ref: annotationRef, data: annotationDict, }
         ]);
 
-        var annotation = annotationFactory.create(xref, annotationRef,
+        var annotation = AnnotationFactory.create(xref, annotationRef,
                                                   pdfManagerMock,
                                                   idFactoryMock);
         var data = annotation.data;
@@ -635,7 +633,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -656,7 +654,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -679,7 +677,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, annotationRef,
+      var annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -709,7 +707,7 @@ describe('annotation', function() {
         { ref: annotationRef, data: annotationDict, }
       ]);
 
-      let annotation = annotationFactory.create(xref, annotationRef,
+      let annotation = AnnotationFactory.create(xref, annotationRef,
                                                 pdfManagerMock, idFactoryMock);
       let data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINK);
@@ -742,7 +740,7 @@ describe('annotation', function() {
         { ref: widgetRef, data: widgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, widgetRef,
+      var annotation = AnnotationFactory.create(xref, widgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -759,7 +757,7 @@ describe('annotation', function() {
         { ref: widgetRef, data: widgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, widgetRef,
+      var annotation = AnnotationFactory.create(xref, widgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -783,7 +781,7 @@ describe('annotation', function() {
         { ref: widgetRef, data: widgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, widgetRef,
+      var annotation = AnnotationFactory.create(xref, widgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -805,7 +803,7 @@ describe('annotation', function() {
         { ref: widgetRef, data: widgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, widgetRef,
+      var annotation = AnnotationFactory.create(xref, widgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -837,7 +835,7 @@ describe('annotation', function() {
         { ref: textWidgetRef, data: textWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, textWidgetRef,
+      var annotation = AnnotationFactory.create(xref, textWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -860,7 +858,7 @@ describe('annotation', function() {
         { ref: textWidgetRef, data: textWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, textWidgetRef,
+      var annotation = AnnotationFactory.create(xref, textWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -884,7 +882,7 @@ describe('annotation', function() {
         { ref: textWidgetRef, data: textWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, textWidgetRef,
+      var annotation = AnnotationFactory.create(xref, textWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -903,7 +901,7 @@ describe('annotation', function() {
         { ref: textWidgetRef, data: textWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, textWidgetRef,
+      var annotation = AnnotationFactory.create(xref, textWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -920,7 +918,7 @@ describe('annotation', function() {
         { ref: textWidgetRef, data: textWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, textWidgetRef,
+      var annotation = AnnotationFactory.create(xref, textWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -948,7 +946,7 @@ describe('annotation', function() {
           { ref: textWidgetRef, data: textWidgetDict, }
         ]);
 
-        var annotation = annotationFactory.create(xref, textWidgetRef,
+        var annotation = AnnotationFactory.create(xref, textWidgetRef,
                                                   pdfManagerMock,
                                                   idFactoryMock);
         var data = annotation.data;
@@ -989,7 +987,7 @@ describe('annotation', function() {
         { ref: buttonWidgetRef, data: buttonWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, buttonWidgetRef,
+      var annotation = AnnotationFactory.create(xref, buttonWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1018,7 +1016,7 @@ describe('annotation', function() {
         { ref: buttonWidgetRef, data: buttonWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, buttonWidgetRef,
+      var annotation = AnnotationFactory.create(xref, buttonWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1044,7 +1042,7 @@ describe('annotation', function() {
         { ref: buttonWidgetRef, data: buttonWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, buttonWidgetRef,
+      var annotation = AnnotationFactory.create(xref, buttonWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1078,7 +1076,7 @@ describe('annotation', function() {
         { ref: choiceWidgetRef, data: choiceWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, choiceWidgetRef,
+      var annotation = AnnotationFactory.create(xref, choiceWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1113,7 +1111,7 @@ describe('annotation', function() {
         { ref: optionOneRef, data: optionOneArr, },
       ]);
 
-      var annotation = annotationFactory.create(xref, choiceWidgetRef,
+      var annotation = AnnotationFactory.create(xref, choiceWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1145,7 +1143,7 @@ describe('annotation', function() {
         { ref: optionBarRef, data: optionBarStr, }
       ]);
 
-      var annotation = annotationFactory.create(xref, choiceWidgetRef,
+      var annotation = AnnotationFactory.create(xref, choiceWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1173,7 +1171,7 @@ describe('annotation', function() {
         { ref: choiceWidgetRef, data: choiceWidgetDict, },
       ]);
 
-      var annotation = annotationFactory.create(xref, choiceWidgetRef,
+      var annotation = AnnotationFactory.create(xref, choiceWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1191,7 +1189,7 @@ describe('annotation', function() {
         { ref: choiceWidgetRef, data: choiceWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, choiceWidgetRef,
+      var annotation = AnnotationFactory.create(xref, choiceWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1209,7 +1207,7 @@ describe('annotation', function() {
         { ref: choiceWidgetRef, data: choiceWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, choiceWidgetRef,
+      var annotation = AnnotationFactory.create(xref, choiceWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1223,7 +1221,7 @@ describe('annotation', function() {
         { ref: choiceWidgetRef, data: choiceWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, choiceWidgetRef,
+      var annotation = AnnotationFactory.create(xref, choiceWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1241,7 +1239,7 @@ describe('annotation', function() {
         { ref: choiceWidgetRef, data: choiceWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, choiceWidgetRef,
+      var annotation = AnnotationFactory.create(xref, choiceWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1261,7 +1259,7 @@ describe('annotation', function() {
         { ref: choiceWidgetRef, data: choiceWidgetDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, choiceWidgetRef,
+      var annotation = AnnotationFactory.create(xref, choiceWidgetRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.WIDGET);
@@ -1284,7 +1282,7 @@ describe('annotation', function() {
         { ref: lineRef, data: lineDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, lineRef, pdfManagerMock,
+      var annotation = AnnotationFactory.create(xref, lineRef, pdfManagerMock,
                                                 idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.LINE);
@@ -1337,7 +1335,7 @@ describe('annotation', function() {
       fileSpecDict.assignXref(xref);
       fileAttachmentDict.assignXref(xref);
 
-      var annotation = annotationFactory.create(xref, fileAttachmentRef,
+      var annotation = AnnotationFactory.create(xref, fileAttachmentRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.FILEATTACHMENT);
@@ -1366,7 +1364,7 @@ describe('annotation', function() {
         { ref: popupRef, data: popupDict, }
       ]);
 
-      var annotation = annotationFactory.create(xref, popupRef,
+      var annotation = AnnotationFactory.create(xref, popupRef,
                                                 pdfManagerMock, idFactoryMock);
       var data = annotation.data;
       expect(data.annotationType).toEqual(AnnotationType.POPUP);

From 2512eccbf09f33811325dcbad7efa4f4f68ccc93 Mon Sep 17 00:00:00 2001
From: Tim van der Meij <timvandermeij@gmail.com>
Date: Sun, 27 Aug 2017 00:48:02 +0200
Subject: [PATCH 4/5] Implement `getOperatorList` method in the
 `WidgetAnnotation` class to avoid duplication in subclasses

---
 src/core/annotation.js | 51 ++++++++++--------------------------------
 1 file changed, 12 insertions(+), 39 deletions(-)

diff --git a/src/core/annotation.js b/src/core/annotation.js
index f2099a984..4fca1e83b 100644
--- a/src/core/annotation.js
+++ b/src/core/annotation.js
@@ -646,6 +646,15 @@ class WidgetAnnotation extends Annotation {
   hasFieldFlag(flag) {
     return !!(this.data.fieldFlags & flag);
   }
+
+  getOperatorList(evaluator, task, renderForms) {
+    // Do not render form elements on the canvas when interactive forms are
+    // enabled. The display layer is responsible for rendering them instead.
+    if (renderForms) {
+      return Promise.resolve(new OperatorList());
+    }
+    return super.getOperatorList(evaluator, task, renderForms);
+  }
 }
 
 class TextWidgetAnnotation extends WidgetAnnotation {
@@ -679,18 +688,11 @@ class TextWidgetAnnotation extends WidgetAnnotation {
   }
 
   getOperatorList(evaluator, task, renderForms) {
-    let operatorList = new OperatorList();
-
-    // Do not render form elements on the canvas when interactive forms are
-    // enabled. The display layer is responsible for rendering them instead.
-    if (renderForms) {
-      return Promise.resolve(operatorList);
+    if (renderForms || this.appearance) {
+      return super.getOperatorList(evaluator, task, renderForms);
     }
 
-    if (this.appearance) {
-      return Annotation.prototype.getOperatorList.call(this, evaluator, task,
-                                                       renderForms);
-    }
+    let operatorList = new OperatorList();
 
     // Even if there is an appearance stream, ignore it. This is the
     // behaviour used by Adobe Reader.
@@ -756,22 +758,6 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
       }
     }
   }
-
-  getOperatorList(evaluator, task, renderForms) {
-    let operatorList = new OperatorList();
-
-    // Do not render form elements on the canvas when interactive forms are
-    // enabled. The display layer is responsible for rendering them instead.
-    if (renderForms) {
-      return Promise.resolve(operatorList);
-    }
-
-    if (this.appearance) {
-      return Annotation.prototype.getOperatorList.call(this, evaluator, task,
-                                                       renderForms);
-    }
-    return Promise.resolve(operatorList);
-  }
 }
 
 class ChoiceWidgetAnnotation extends WidgetAnnotation {
@@ -814,19 +800,6 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation {
     this.data.combo = this.hasFieldFlag(AnnotationFieldFlag.COMBO);
     this.data.multiSelect = this.hasFieldFlag(AnnotationFieldFlag.MULTISELECT);
   }
-
-  getOperatorList(evaluator, task, renderForms) {
-    let operatorList = new OperatorList();
-
-    // Do not render form elements on the canvas when interactive forms are
-    // enabled. The display layer is responsible for rendering them instead.
-    if (renderForms) {
-      return Promise.resolve(operatorList);
-    }
-
-    return Annotation.prototype.getOperatorList.call(this, evaluator, task,
-                                                     renderForms);
-  }
 }
 
 class TextAnnotation extends Annotation {

From 7787987a4bb41e88feadda4dd636599804503f08 Mon Sep 17 00:00:00 2001
From: Tim van der Meij <timvandermeij@gmail.com>
Date: Sun, 27 Aug 2017 01:07:51 +0200
Subject: [PATCH 5/5] Update `webpack` and `webpack-stream` to the latest
 version

Aside from being up-to-date, this may improve build time/size.
---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index d6df16135..c5472d91d 100644
--- a/package.json
+++ b/package.json
@@ -31,8 +31,8 @@
     "typogr": "^0.6.6",
     "uglify-js": "^2.6.1",
     "vinyl-fs": "^2.4.4",
-    "webpack": "^2.2.1",
-    "webpack-stream": "^3.2.0",
+    "webpack": "^3.5.5",
+    "webpack-stream": "^4.0.0",
     "wintersmith": "^2.0.0",
     "yargs": "^3.14.0"
   },