Bug 1342274 - Update pdf.js to version 1.7.312. r=bdahl
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 23 Feb 2017 19:22:10 -0500
changeset 373688 856b3b317f5560d539107b426fbd5b7ef622eb34
parent 373687 7b7dddb3428ea51a413acc095eb6459345a752fc
child 373689 04086e001c8fe171a46482accfb36048f3c5cb4b
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbdahl
bugs1342274
milestone54.0a1
Bug 1342274 - Update pdf.js to version 1.7.312. r=bdahl
browser/extensions/pdfjs/README.mozilla
browser/extensions/pdfjs/content/build/pdf.js
browser/extensions/pdfjs/content/build/pdf.worker.js
browser/extensions/pdfjs/content/web/viewer.js
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,3 +1,3 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.7.297
+Current extension version is: 1.7.312
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -216,16 +216,21 @@ var FontType = {
  TYPE0: 9,
  MMTYPE1: 10
 };
 var VERBOSITY_LEVELS = {
  errors: 0,
  warnings: 1,
  infos: 5
 };
+var CMapCompressionType = {
+ NONE: 0,
+ BINARY: 1,
+ STREAM: 2
+};
 var OPS = {
  dependency: 1,
  setLineWidth: 2,
  setLineCap: 3,
  setLineJoin: 4,
  setMiterLimit: 5,
  setDash: 6,
  setRenderingIntent: 7,
@@ -1161,16 +1166,22 @@ function isArray(v) {
  return v instanceof Array;
 }
 function isArrayBuffer(v) {
  return typeof v === 'object' && v !== null && v.byteLength !== undefined;
 }
 function isSpace(ch) {
  return ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A;
 }
+function isNodeJS() {
+ if (typeof __pdfjsdev_webpack__ === 'undefined') {
+  return typeof process === 'object' && process + '' === '[object process]';
+ }
+ return false;
+}
 function createPromiseCapability() {
  var capability = {};
  capability.promise = new Promise(function (resolve, reject) {
   capability.resolve = resolve;
   capability.reject = reject;
  });
  return capability;
 }
@@ -1433,16 +1444,17 @@ exports.OPS = OPS;
 exports.VERBOSITY_LEVELS = VERBOSITY_LEVELS;
 exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES;
 exports.AnnotationBorderStyleType = AnnotationBorderStyleType;
 exports.AnnotationFieldFlag = AnnotationFieldFlag;
 exports.AnnotationFlag = AnnotationFlag;
 exports.AnnotationType = AnnotationType;
 exports.FontType = FontType;
 exports.ImageKind = ImageKind;
+exports.CMapCompressionType = CMapCompressionType;
 exports.InvalidPDFException = InvalidPDFException;
 exports.MessageHandler = MessageHandler;
 exports.MissingDataException = MissingDataException;
 exports.MissingPDFException = MissingPDFException;
 exports.NotImplementedException = NotImplementedException;
 exports.PageViewport = PageViewport;
 exports.PasswordException = PasswordException;
 exports.PasswordResponses = PasswordResponses;
@@ -1469,16 +1481,17 @@ exports.info = info;
 exports.isArray = isArray;
 exports.isArrayBuffer = isArrayBuffer;
 exports.isBool = isBool;
 exports.isEmptyObj = isEmptyObj;
 exports.isInt = isInt;
 exports.isNum = isNum;
 exports.isString = isString;
 exports.isSpace = isSpace;
+exports.isNodeJS = isNodeJS;
 exports.isSameOrigin = isSameOrigin;
 exports.createValidAbsoluteUrl = createValidAbsoluteUrl;
 exports.isLittleEndian = isLittleEndian;
 exports.isEvalSupported = isEvalSupported;
 exports.loadJpegStream = loadJpegStream;
 exports.log2 = log2;
 exports.readInt8 = readInt8;
 exports.readUint16 = readUint16;
@@ -1501,16 +1514,18 @@ exports.warn = warn;
 "use strict";
 
 var sharedUtil = __w_pdfjs_require__(0);
 var assert = sharedUtil.assert;
 var removeNullCharacters = sharedUtil.removeNullCharacters;
 var warn = sharedUtil.warn;
 var deprecated = sharedUtil.deprecated;
 var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl;
+var stringToBytes = sharedUtil.stringToBytes;
+var CMapCompressionType = sharedUtil.CMapCompressionType;
 var DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
 function DOMCanvasFactory() {
 }
 DOMCanvasFactory.prototype = {
  create: function DOMCanvasFactory_create(width, height) {
   assert(width > 0 && height > 0, 'invalid canvas size');
   var canvas = document.createElement('canvas');
   var context = canvas.getContext('2d');
@@ -1530,16 +1545,58 @@ DOMCanvasFactory.prototype = {
  destroy: function DOMCanvasFactory_destroy(canvasAndContextPair) {
   assert(canvasAndContextPair.canvas, 'canvas is not specified');
   canvasAndContextPair.canvas.width = 0;
   canvasAndContextPair.canvas.height = 0;
   canvasAndContextPair.canvas = null;
   canvasAndContextPair.context = null;
  }
 };
+var DOMCMapReaderFactory = function DOMCMapReaderFactoryClosure() {
+ function DOMCMapReaderFactory(params) {
+  this.baseUrl = params.baseUrl || null;
+  this.isCompressed = params.isCompressed || false;
+ }
+ DOMCMapReaderFactory.prototype = {
+  fetch: function (params) {
+   if (!params.name) {
+    return Promise.reject(new Error('CMap name must be specified.'));
+   }
+   return new Promise(function (resolve, reject) {
+    var url = this.baseUrl + params.name;
+    var request = new XMLHttpRequest();
+    if (this.isCompressed) {
+     url += '.bcmap';
+     request.responseType = 'arraybuffer';
+    }
+    request.onreadystatechange = function () {
+     if (request.readyState === XMLHttpRequest.DONE && (request.status === 200 || request.status === 0)) {
+      var data;
+      if (this.isCompressed && request.response) {
+       data = new Uint8Array(request.response);
+      } else if (!this.isCompressed && request.responseText) {
+       data = stringToBytes(request.responseText);
+      }
+      if (data) {
+       resolve({
+        cMapData: data,
+        compressionType: this.isCompressed ? CMapCompressionType.BINARY : CMapCompressionType.NONE
+       });
+       return;
+      }
+      reject(new Error('Unable to load ' + (this.isCompressed ? 'binary' : '') + ' CMap at: ' + url));
+     }
+    }.bind(this);
+    request.open('GET', url, true);
+    request.send(null);
+   }.bind(this));
+  }
+ };
+ return DOMCMapReaderFactory;
+}();
 var CustomStyle = function CustomStyleClosure() {
  var prefixes = [
   'ms',
   'Moz',
   'Webkit',
   'O'
  ];
  var _cache = Object.create(null);
@@ -1689,16 +1746,17 @@ exports.addLinkAttributes = addLinkAttri
 exports.isExternalLinkTargetSet = isExternalLinkTargetSet;
 exports.isValidUrl = isValidUrl;
 exports.getFilenameFromUrl = getFilenameFromUrl;
 exports.LinkTarget = LinkTarget;
 exports.hasCanvasTypedArrays = hasCanvasTypedArrays;
 exports.getDefaultSetting = getDefaultSetting;
 exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL;
 exports.DOMCanvasFactory = DOMCanvasFactory;
+exports.DOMCMapReaderFactory = DOMCMapReaderFactory;
 
 /***/ }),
 /* 2 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 var sharedUtil = __w_pdfjs_require__(0);
@@ -2353,16 +2411,17 @@ var stringToBytes = sharedUtil.stringToB
 var globalScope = sharedUtil.globalScope;
 var warn = sharedUtil.warn;
 var FontFaceObject = displayFontLoader.FontFaceObject;
 var FontLoader = displayFontLoader.FontLoader;
 var CanvasGraphics = displayCanvas.CanvasGraphics;
 var Metadata = displayMetadata.Metadata;
 var getDefaultSetting = displayDOMUtils.getDefaultSetting;
 var DOMCanvasFactory = displayDOMUtils.DOMCanvasFactory;
+var DOMCMapReaderFactory = displayDOMUtils.DOMCMapReaderFactory;
 var DEFAULT_RANGE_CHUNK_SIZE = 65536;
 var isWorkerDisabled = false;
 var workerSrc;
 var isPostMessageTransfersDisabled = false;
 var pdfjsFilePath = null;
 var fakeWorkerFilesLoader = null;
 var useRequireEnsure = false;
 function getDocument(src, pdfDataRangeTransport, passwordCallback, progressCallback) {
@@ -2426,31 +2485,32 @@ function getDocument(src, pdfDataRangeTr
     error('Invalid PDF binary data: either typed array, string or ' + 'array-like object is expected in the data property.');
    }
    continue;
   }
   params[key] = source[key];
  }
  params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE;
  params.disableNativeImageDecoder = params.disableNativeImageDecoder === true;
+ var CMapReaderFactory = params.CMapReaderFactory || DOMCMapReaderFactory;
  if (!worker) {
   worker = new PDFWorker();
   task._worker = worker;
  }
  var docId = task.docId;
  worker.promise.then(function () {
   if (task.destroyed) {
    throw new Error('Loading aborted');
   }
   return _fetchDocument(worker, params, rangeTransport, docId).then(function (workerId) {
    if (task.destroyed) {
     throw new Error('Loading aborted');
    }
    var messageHandler = new MessageHandler(docId, workerId, worker.port);
-   var transport = new WorkerTransport(messageHandler, task, rangeTransport);
+   var transport = new WorkerTransport(messageHandler, task, rangeTransport, CMapReaderFactory);
    task._transport = transport;
    messageHandler.send('Ready', null);
   });
  }).catch(task._capability.reject);
  return task;
 }
 function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
  if (worker.destroyed) {
@@ -2463,18 +2523,16 @@ function _fetchDocument(worker, source, 
   source.length = pdfDataRangeTransport.length;
   source.initialData = pdfDataRangeTransport.initialData;
  }
  return worker.messageHandler.sendWithPromise('GetDocRequest', {
   docId: docId,
   source: source,
   disableRange: getDefaultSetting('disableRange'),
   maxImageSize: getDefaultSetting('maxImageSize'),
-  cMapUrl: getDefaultSetting('cMapUrl'),
-  cMapPacked: getDefaultSetting('cMapPacked'),
   disableFontFace: getDefaultSetting('disableFontFace'),
   disableCreateObjectURL: getDefaultSetting('disableCreateObjectURL'),
   postMessageTransfers: getDefaultSetting('postMessageTransfers') && !isPostMessageTransfersDisabled,
   docBaseUrl: source.docBaseUrl,
   disableNativeImageDecoder: source.disableNativeImageDecoder
  }).then(function (workerId) {
   if (worker.destroyed) {
    throw new Error('Worker was destroyed');
@@ -3076,22 +3134,26 @@ var PDFWorker = function PDFWorkerClosur
     this._messageHandler.destroy();
     this._messageHandler = null;
    }
   }
  };
  return PDFWorker;
 }();
 var WorkerTransport = function WorkerTransportClosure() {
- function WorkerTransport(messageHandler, loadingTask, pdfDataRangeTransport) {
+ function WorkerTransport(messageHandler, loadingTask, pdfDataRangeTransport, CMapReaderFactory) {
   this.messageHandler = messageHandler;
   this.loadingTask = loadingTask;
   this.pdfDataRangeTransport = pdfDataRangeTransport;
   this.commonObjs = new PDFObjects();
   this.fontLoader = new FontLoader(loadingTask.docId);
+  this.CMapReaderFactory = new CMapReaderFactory({
+   baseUrl: getDefaultSetting('cMapUrl'),
+   isCompressed: getDefaultSetting('cMapPacked')
+  });
   this.destroyed = false;
   this.destroyCapability = null;
   this._passwordCapability = null;
   this.pageCache = [];
   this.pagePromises = [];
   this.downloadInfoCapability = createPromiseCapability();
   this.setupMessageHandler();
  }
@@ -3366,16 +3428,22 @@ var WorkerTransport = function WorkerTra
       });
      };
      img.onerror = function () {
       reject(new Error('JpegDecode failed to load image'));
      };
      img.src = imageUrl;
     });
    }, this);
+   messageHandler.on('FetchBuiltInCMap', function (data) {
+    if (this.destroyed) {
+     return Promise.reject(new Error('Worker was destroyed'));
+    }
+    return this.CMapReaderFactory.fetch({ name: data.name });
+   }, this);
   },
   getData: function WorkerTransport_getData() {
    return this.messageHandler.sendWithPromise('GetData', null);
   },
   getPage: function WorkerTransport_getPage(pageNumber, capability) {
    if (!isInt(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) {
     return Promise.reject(new Error('Invalid page request'));
    }
@@ -3627,18 +3695,18 @@ var _UnsupportedManager = function Unsup
   },
   notify: function (featureId) {
    for (var i = 0, ii = listeners.length; i < ii; i++) {
     listeners[i](featureId);
    }
   }
  };
 }();
-exports.version = '1.7.297';
-exports.build = '425ad309';
+exports.version = '1.7.312';
+exports.build = 'cada411a';
 exports.getDocument = getDocument;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports._UnsupportedManager = _UnsupportedManager;
 
 /***/ }),
@@ -4645,18 +4713,18 @@ var deprecated = sharedUtil.deprecated;
 var warn = sharedUtil.warn;
 var LinkTarget = displayDOMUtils.LinkTarget;
 var DEFAULT_LINK_REL = displayDOMUtils.DEFAULT_LINK_REL;
 var isWorker = typeof window === 'undefined';
 if (!globalScope.PDFJS) {
  globalScope.PDFJS = {};
 }
 var PDFJS = globalScope.PDFJS;
-PDFJS.version = '1.7.297';
-PDFJS.build = '425ad309';
+PDFJS.version = '1.7.312';
+PDFJS.build = 'cada411a';
 PDFJS.pdfBug = false;
 if (PDFJS.verbosity !== undefined) {
  sharedUtil.setVerbosityLevel(PDFJS.verbosity);
 }
 delete PDFJS.verbosity;
 Object.defineProperty(PDFJS, 'verbosity', {
  get: function () {
   return sharedUtil.getVerbosityLevel();
@@ -7138,18 +7206,18 @@ exports.getShadingPatternFromIR = getSha
 exports.TilingPattern = TilingPattern;
 
 /***/ }),
 /* 13 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
-var pdfjsVersion = '1.7.297';
-var pdfjsBuild = '425ad309';
+var pdfjsVersion = '1.7.312';
+var pdfjsBuild = 'cada411a';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
 var pdfjsDisplayGlobal = __w_pdfjs_require__(8);
 var pdfjsDisplayAPI = __w_pdfjs_require__(3);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(5);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(2);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
 var pdfjsDisplaySVG = __w_pdfjs_require__(4);
 exports.PDFJS = pdfjsDisplayGlobal.PDFJS;
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -216,16 +216,21 @@ var FontType = {
  TYPE0: 9,
  MMTYPE1: 10
 };
 var VERBOSITY_LEVELS = {
  errors: 0,
  warnings: 1,
  infos: 5
 };
+var CMapCompressionType = {
+ NONE: 0,
+ BINARY: 1,
+ STREAM: 2
+};
 var OPS = {
  dependency: 1,
  setLineWidth: 2,
  setLineCap: 3,
  setLineJoin: 4,
  setMiterLimit: 5,
  setDash: 6,
  setRenderingIntent: 7,
@@ -1161,16 +1166,22 @@ function isArray(v) {
  return v instanceof Array;
 }
 function isArrayBuffer(v) {
  return typeof v === 'object' && v !== null && v.byteLength !== undefined;
 }
 function isSpace(ch) {
  return ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A;
 }
+function isNodeJS() {
+ if (typeof __pdfjsdev_webpack__ === 'undefined') {
+  return typeof process === 'object' && process + '' === '[object process]';
+ }
+ return false;
+}
 function createPromiseCapability() {
  var capability = {};
  capability.promise = new Promise(function (resolve, reject) {
   capability.resolve = resolve;
   capability.reject = reject;
  });
  return capability;
 }
@@ -1433,16 +1444,17 @@ exports.OPS = OPS;
 exports.VERBOSITY_LEVELS = VERBOSITY_LEVELS;
 exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES;
 exports.AnnotationBorderStyleType = AnnotationBorderStyleType;
 exports.AnnotationFieldFlag = AnnotationFieldFlag;
 exports.AnnotationFlag = AnnotationFlag;
 exports.AnnotationType = AnnotationType;
 exports.FontType = FontType;
 exports.ImageKind = ImageKind;
+exports.CMapCompressionType = CMapCompressionType;
 exports.InvalidPDFException = InvalidPDFException;
 exports.MessageHandler = MessageHandler;
 exports.MissingDataException = MissingDataException;
 exports.MissingPDFException = MissingPDFException;
 exports.NotImplementedException = NotImplementedException;
 exports.PageViewport = PageViewport;
 exports.PasswordException = PasswordException;
 exports.PasswordResponses = PasswordResponses;
@@ -1469,16 +1481,17 @@ exports.info = info;
 exports.isArray = isArray;
 exports.isArrayBuffer = isArrayBuffer;
 exports.isBool = isBool;
 exports.isEmptyObj = isEmptyObj;
 exports.isInt = isInt;
 exports.isNum = isNum;
 exports.isString = isString;
 exports.isSpace = isSpace;
+exports.isNodeJS = isNodeJS;
 exports.isSameOrigin = isSameOrigin;
 exports.createValidAbsoluteUrl = createValidAbsoluteUrl;
 exports.isLittleEndian = isLittleEndian;
 exports.isEvalSupported = isEvalSupported;
 exports.loadJpegStream = loadJpegStream;
 exports.log2 = log2;
 exports.readInt8 = readInt8;
 exports.readUint16 = readUint16;
@@ -24782,16 +24795,17 @@ var coreStandardFonts = __w_pdfjs_requir
 var coreUnicode = __w_pdfjs_require__(16);
 var coreGlyphList = __w_pdfjs_require__(7);
 var FONT_IDENTITY_MATRIX = sharedUtil.FONT_IDENTITY_MATRIX;
 var IDENTITY_MATRIX = sharedUtil.IDENTITY_MATRIX;
 var UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES;
 var ImageKind = sharedUtil.ImageKind;
 var OPS = sharedUtil.OPS;
 var TextRenderingMode = sharedUtil.TextRenderingMode;
+var CMapCompressionType = sharedUtil.CMapCompressionType;
 var Util = sharedUtil.Util;
 var assert = sharedUtil.assert;
 var createPromiseCapability = sharedUtil.createPromiseCapability;
 var error = sharedUtil.error;
 var info = sharedUtil.info;
 var isArray = sharedUtil.isArray;
 var isNum = sharedUtil.isNum;
 var isString = sharedUtil.isString;
@@ -24840,20 +24854,16 @@ var getNormalizedUnicodes = coreUnicode.
 var reverseIfRtl = coreUnicode.reverseIfRtl;
 var getUnicodeForGlyph = coreUnicode.getUnicodeForGlyph;
 var getGlyphsUnicode = coreGlyphList.getGlyphsUnicode;
 var PartialEvaluator = function PartialEvaluatorClosure() {
  var DefaultPartialEvaluatorOptions = {
   forceDataSchema: false,
   maxImageSize: -1,
   disableFontFace: false,
-  cMapOptions: {
-   url: null,
-   packed: false
-  },
   disableNativeImageDecoder: false
  };
  function NativeImageDecoder(xref, resources, handler, forceDataSchema) {
   this.xref = xref;
   this.resources = resources;
   this.handler = handler;
   this.forceDataSchema = forceDataSchema;
  }
@@ -24887,24 +24897,37 @@ var PartialEvaluator = function PartialE
  NativeImageDecoder.isDecodable = function NativeImageDecoder_isDecodable(image, xref, res) {
   var dict = image.dict;
   if (dict.has('DecodeParms') || dict.has('DP')) {
    return false;
   }
   var cs = ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res);
   return (cs.numComps === 1 || cs.numComps === 3) && cs.isDefaultDecode(dict.getArray('Decode', 'D'));
  };
- function PartialEvaluator(pdfManager, xref, handler, pageIndex, idFactory, fontCache, options) {
+ function PartialEvaluator(pdfManager, xref, handler, pageIndex, idFactory, fontCache, builtInCMapCache, options) {
   this.pdfManager = pdfManager;
   this.xref = xref;
   this.handler = handler;
   this.pageIndex = pageIndex;
   this.idFactory = idFactory;
   this.fontCache = fontCache;
+  this.builtInCMapCache = builtInCMapCache;
   this.options = options || DefaultPartialEvaluatorOptions;
+  this.fetchBuiltInCMap = function (name) {
+   var cachedCMap = builtInCMapCache[name];
+   if (cachedCMap) {
+    return Promise.resolve(cachedCMap);
+   }
+   return handler.sendWithPromise('FetchBuiltInCMap', { name: name }).then(function (data) {
+    if (data.compressionType !== CMapCompressionType.NONE) {
+     builtInCMapCache[name] = data;
+    }
+    return data;
+   });
+  };
  }
  var TIME_SLOT_DURATION_MS = 20;
  var CHECK_TIME_EVERY = 100;
  function TimeSlotManager() {
   this.reset();
  }
  TimeSlotManager.prototype = {
   check: function TimeSlotManager_check() {
@@ -26231,17 +26254,21 @@ var PartialEvaluator = function PartialE
      toUnicode[charcode] = String.fromCharCode(glyphsUnicodeMap[glyphName]);
     }
     return Promise.resolve(new ToUnicodeMap(toUnicode));
    }
    if (properties.composite && (properties.cMap.builtInCMap && !(properties.cMap instanceof IdentityCMap) || properties.cidSystemInfo.registry === 'Adobe' && (properties.cidSystemInfo.ordering === 'GB1' || properties.cidSystemInfo.ordering === 'CNS1' || properties.cidSystemInfo.ordering === 'Japan1' || properties.cidSystemInfo.ordering === 'Korea1'))) {
     var registry = properties.cidSystemInfo.registry;
     var ordering = properties.cidSystemInfo.ordering;
     var ucs2CMapName = Name.get(registry + '-' + ordering + '-UCS2');
-    return CMapFactory.create(ucs2CMapName, this.options.cMapOptions, null).then(function (ucs2CMap) {
+    return CMapFactory.create({
+     encoding: ucs2CMapName,
+     fetchBuiltInCMap: this.fetchBuiltInCMap,
+     useCMap: null
+    }).then(function (ucs2CMap) {
      var cMap = properties.cMap;
      toUnicode = [];
      cMap.forEach(function (charcode, cid) {
       assert(cid <= 0xffff, 'Max size of CID is 65,535');
       var ucs2 = ucs2CMap.lookup(cid);
       if (ucs2) {
        toUnicode[charcode] = String.fromCharCode((ucs2.charCodeAt(0) << 8) + ucs2.charCodeAt(1));
       }
@@ -26249,24 +26276,32 @@ var PartialEvaluator = function PartialE
      return new ToUnicodeMap(toUnicode);
     });
    }
    return Promise.resolve(new IdentityToUnicodeMap(properties.firstChar, properties.lastChar));
   },
   readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) {
    var cmapObj = toUnicode;
    if (isName(cmapObj)) {
-    return CMapFactory.create(cmapObj, this.options.cMapOptions, null).then(function (cmap) {
+    return CMapFactory.create({
+     encoding: cmapObj,
+     fetchBuiltInCMap: this.fetchBuiltInCMap,
+     useCMap: null
+    }).then(function (cmap) {
      if (cmap instanceof IdentityCMap) {
       return new IdentityToUnicodeMap(0, 0xFFFF);
      }
      return new ToUnicodeMap(cmap.getMap());
     });
    } else if (isStream(cmapObj)) {
-    return CMapFactory.create(cmapObj, this.options.cMapOptions, null).then(function (cmap) {
+    return CMapFactory.create({
+     encoding: cmapObj,
+     fetchBuiltInCMap: this.fetchBuiltInCMap,
+     useCMap: null
+    }).then(function (cmap) {
      if (cmap instanceof IdentityCMap) {
       return new IdentityToUnicodeMap(0, 0xFFFF);
      }
      var map = new Array(cmap.length);
      cmap.forEach(function (charCode, token) {
       var str = [];
       for (var k = 0; k < token.length; k += 2) {
        var w1 = token.charCodeAt(k) << 8 | token.charCodeAt(k + 1);
@@ -26519,17 +26554,16 @@ var PartialEvaluator = function PartialE
   },
   translateFont: function PartialEvaluator_translateFont(preEvaluatedFont, xref) {
    var baseDict = preEvaluatedFont.baseDict;
    var dict = preEvaluatedFont.dict;
    var composite = preEvaluatedFont.composite;
    var descriptor = preEvaluatedFont.descriptor;
    var type = preEvaluatedFont.type;
    var maxCharIndex = composite ? 0xFFFF : 0xFF;
-   var cMapOptions = this.options.cMapOptions;
    var properties;
    if (!descriptor) {
     if (type === 'Type3') {
      descriptor = new Dict(null);
      descriptor.set('FontName', Name.get(type));
      descriptor.set('FontBBox', dict.getArray('FontBBox'));
     } else {
      var baseFontName = dict.get('BaseFont');
@@ -26614,17 +26648,21 @@ var PartialEvaluator = function PartialE
     coded: false
    };
    var cMapPromise;
    if (composite) {
     var cidEncoding = baseDict.get('Encoding');
     if (isName(cidEncoding)) {
      properties.cidEncoding = cidEncoding.name;
     }
-    cMapPromise = CMapFactory.create(cidEncoding, cMapOptions, null).then(function (cMap) {
+    cMapPromise = CMapFactory.create({
+     encoding: cidEncoding,
+     fetchBuiltInCMap: this.fetchBuiltInCMap,
+     useCMap: null
+    }).then(function (cMap) {
      properties.cMap = cMap;
      properties.vertical = properties.cMap.vertical;
     });
    } else {
     cMapPromise = Promise.resolve(undefined);
    }
    return cMapPromise.then(function () {
     return this.extractDataStructures(dict, baseDict, xref, properties);
@@ -29867,16 +29905,17 @@ var Parser = coreParser.Parser;
 var ChunkedStream = coreChunkedStream.ChunkedStream;
 var ColorSpace = coreColorSpace.ColorSpace;
 var Catalog = function CatalogClosure() {
  function Catalog(pdfManager, xref, pageFactory) {
   this.pdfManager = pdfManager;
   this.xref = xref;
   this.catDict = xref.getCatalogObj();
   this.fontCache = new RefSetCache();
+  this.builtInCMapCache = Object.create(null);
   assert(isDict(this.catDict), 'catalog object is not a dictionary');
   this.pageFactory = pageFactory;
   this.pagePromises = [];
  }
  Catalog.prototype = {
   get metadata() {
    var streamRef = this.catDict.getRaw('Metadata');
    if (!isRef(streamRef)) {
@@ -30181,24 +30220,25 @@ var Catalog = function CatalogClosure() 
     promises.push(promise);
    });
    return Promise.all(promises).then(function (translatedFonts) {
     for (var i = 0, ii = translatedFonts.length; i < ii; i++) {
      var font = translatedFonts[i].dict;
      delete font.translated;
     }
     this.fontCache.clear();
+    this.builtInCMapCache = Object.create(null);
    }.bind(this));
   },
   getPage: function Catalog_getPage(pageIndex) {
    if (!(pageIndex in this.pagePromises)) {
     this.pagePromises[pageIndex] = this.getPageDict(pageIndex).then(function (a) {
      var dict = a[0];
      var ref = a[1];
-     return this.pageFactory.createPage(pageIndex, dict, ref, this.fontCache);
+     return this.pageFactory.createPage(pageIndex, dict, ref, this.fontCache, this.builtInCMapCache);
     }.bind(this));
    }
    return this.pagePromises[pageIndex];
   },
   getPageDict: function Catalog_getPageDict(pageIndex) {
    var capability = createPromiseCapability();
    var nodesToVisit = [this.catDict.getRaw('Pages')];
    var currentPageIndex = 0;
@@ -33921,16 +33961,17 @@ var XRefParseException = sharedUtil.XRef
 var arrayByteLength = sharedUtil.arrayByteLength;
 var arraysToBytes = sharedUtil.arraysToBytes;
 var assert = sharedUtil.assert;
 var createPromiseCapability = sharedUtil.createPromiseCapability;
 var error = sharedUtil.error;
 var info = sharedUtil.info;
 var warn = sharedUtil.warn;
 var setVerbosityLevel = sharedUtil.setVerbosityLevel;
+var isNodeJS = sharedUtil.isNodeJS;
 var Ref = corePrimitives.Ref;
 var LocalPdfManager = corePdfManager.LocalPdfManager;
 var NetworkPdfManager = corePdfManager.NetworkPdfManager;
 var globalScope = sharedUtil.globalScope;
 var WorkerTask = function WorkerTaskClosure() {
  function WorkerTask(name) {
   this.name = name;
   this.terminated = false;
@@ -34398,25 +34439,20 @@ var WorkerMessageHandler = {
      pdfManager.requestLoadedStream();
      pdfManager.onLoadedStream().then(function () {
       ensureNotTerminated();
       loadDocument(true).then(onSuccess, onFailure);
      });
     }, onFailure);
    }
    ensureNotTerminated();
-   var cMapOptions = {
-    url: data.cMapUrl === undefined ? null : data.cMapUrl,
-    packed: data.cMapPacked === true
-   };
    var evaluatorOptions = {
     forceDataSchema: data.disableCreateObjectURL,
     maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize,
     disableFontFace: data.disableFontFace,
-    cMapOptions: cMapOptions,
     disableNativeImageDecoder: data.disableNativeImageDecoder
    };
    getPdfManager(data, evaluatorOptions).then(function (newPdfManager) {
     if (terminated) {
      newPdfManager.terminate();
      throw new Error('Worker was terminated');
     }
     pdfManager = newPdfManager;
@@ -34583,22 +34619,16 @@ var WorkerMessageHandler = {
   return workerHandlerName;
  }
 };
 function initializeWorker() {
  var handler = new MessageHandler('worker', 'main', self);
  WorkerMessageHandler.setup(handler, self);
  handler.send('ready', null);
 }
-function isNodeJS() {
- if (typeof __pdfjsdev_webpack__ === 'undefined') {
-  return typeof process === 'object' && process + '' === '[object process]';
- }
- return false;
-}
 if (typeof window === 'undefined' && !isNodeJS()) {
  initializeWorker();
 }
 exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
 exports.WorkerTask = WorkerTask;
 exports.WorkerMessageHandler = WorkerMessageHandler;
 
 /***/ }),
@@ -36575,21 +36605,22 @@ var coreStream = __w_pdfjs_require__(2);
 var coreParser = __w_pdfjs_require__(5);
 var Util = sharedUtil.Util;
 var assert = sharedUtil.assert;
 var warn = sharedUtil.warn;
 var error = sharedUtil.error;
 var isInt = sharedUtil.isInt;
 var isString = sharedUtil.isString;
 var MissingDataException = sharedUtil.MissingDataException;
+var CMapCompressionType = sharedUtil.CMapCompressionType;
 var isEOF = corePrimitives.isEOF;
 var isName = corePrimitives.isName;
 var isCmd = corePrimitives.isCmd;
 var isStream = corePrimitives.isStream;
-var StringStream = coreStream.StringStream;
+var Stream = coreStream.Stream;
 var Lexer = coreParser.Lexer;
 var BUILT_IN_CMAPS = [
  'Adobe-GB1-UCS2',
  'Adobe-CNS1-UCS2',
  'Adobe-Japan1-UCS2',
  'Adobe-Korea1-UCS2',
  '78-EUC-H',
  '78-EUC-V',
@@ -36914,33 +36945,16 @@ var IdentityCMap = function IdentityCMap
   },
   get isIdentityCMap() {
    error('should not access .isIdentityCMap');
   }
  };
  return IdentityCMap;
 }();
 var BinaryCMapReader = function BinaryCMapReaderClosure() {
- function fetchBinaryData(url) {
-  return new Promise(function (resolve, reject) {
-   var request = new XMLHttpRequest();
-   request.open('GET', url, true);
-   request.responseType = 'arraybuffer';
-   request.onreadystatechange = function () {
-    if (request.readyState === XMLHttpRequest.DONE) {
-     if (!request.response || request.status !== 200 && request.status !== 0) {
-      reject(new Error('Unable to get binary cMap at: ' + url));
-     } else {
-      resolve(new Uint8Array(request.response));
-     }
-    }
-   };
-   request.send(null);
-  });
- }
  function hexToInt(a, size) {
   var n = 0;
   for (var i = 0; i <= size; i++) {
    n = n << 8 | a[i];
   }
   return n >>> 0;
  }
  function hexToStr(a, size) {
@@ -37040,18 +37054,18 @@ var BinaryCMapReader = function BinaryCM
    var len = this.readNumber();
    var s = '';
    for (var i = 0; i < len; i++) {
     s += String.fromCharCode(this.readNumber());
    }
    return s;
   }
  };
- function processBinaryCMap(url, cMap, extend) {
-  return fetchBinaryData(url).then(function (data) {
+ function processBinaryCMap(data, cMap, extend) {
+  return new Promise(function (resolve, reject) {
    var stream = new BinaryCMapStream(data);
    var header = stream.readByte();
    cMap.vertical = !!(header & 1);
    var useCMap = null;
    var start = new Uint8Array(MAX_NUM_SIZE);
    var end = new Uint8Array(MAX_NUM_SIZE);
    var char = new Uint8Array(MAX_NUM_SIZE);
    var charCode = new Uint8Array(MAX_NUM_SIZE);
@@ -37172,29 +37186,30 @@ var BinaryCMapReader = function BinaryCM
       }
       stream.readHexNumber(end, ucs2DataSize);
       addHex(end, start, ucs2DataSize);
       stream.readHex(charCode, dataSize);
       cMap.mapBfRange(hexToInt(start, ucs2DataSize), hexToInt(end, ucs2DataSize), hexToStr(charCode, dataSize));
      }
      break;
     default:
-     error('Unknown type: ' + type);
-     break;
+     reject(new Error('processBinaryCMap: Unknown type: ' + type));
+     return;
     }
    }
    if (useCMap) {
-    return extend(useCMap);
-   }
-   return cMap;
+    resolve(extend(useCMap));
+    return;
+   }
+   resolve(cMap);
   });
  }
  function BinaryCMapReader() {
  }
- BinaryCMapReader.prototype = { read: processBinaryCMap };
+ BinaryCMapReader.prototype = { process: processBinaryCMap };
  return BinaryCMapReader;
 }();
 var CMapFactory = function CMapFactoryClosure() {
  function strToInt(str) {
   var a = 0;
   for (var i = 0; i < str.length; i++) {
    a = a << 8 | str.charCodeAt(i);
   }
@@ -37325,17 +37340,17 @@ var CMapFactory = function CMapFactoryCl
   }
  }
  function parseCMapName(cMap, lexer) {
   var obj = lexer.getObj();
   if (isName(obj) && isString(obj.name)) {
    cMap.name = obj.name;
   }
  }
- function parseCMap(cMap, lexer, builtInCMapParams, useCMap) {
+ function parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap) {
   var previous;
   var embededUseCMap;
   objLoop:
    while (true) {
     try {
      var obj = lexer.getObj();
      if (isEOF(obj)) {
       break;
@@ -37379,88 +37394,74 @@ var CMapFactory = function CMapFactoryCl
      warn('Invalid cMap data: ' + ex);
      continue;
     }
    }
   if (!useCMap && embededUseCMap) {
    useCMap = embededUseCMap;
   }
   if (useCMap) {
-   return extendCMap(cMap, builtInCMapParams, useCMap);
+   return extendCMap(cMap, fetchBuiltInCMap, useCMap);
   }
   return Promise.resolve(cMap);
  }
- function extendCMap(cMap, builtInCMapParams, useCMap) {
-  return createBuiltInCMap(useCMap, builtInCMapParams).then(function (newCMap) {
+ function extendCMap(cMap, fetchBuiltInCMap, useCMap) {
+  return createBuiltInCMap(useCMap, fetchBuiltInCMap).then(function (newCMap) {
    cMap.useCMap = newCMap;
    if (cMap.numCodespaceRanges === 0) {
     var useCodespaceRanges = cMap.useCMap.codespaceRanges;
     for (var i = 0; i < useCodespaceRanges.length; i++) {
      cMap.codespaceRanges[i] = useCodespaceRanges[i].slice();
     }
     cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges;
    }
    cMap.useCMap.forEach(function (key, value) {
     if (!cMap.contains(key)) {
      cMap.mapOne(key, cMap.useCMap.lookup(key));
     }
    });
    return cMap;
   });
  }
- function parseBinaryCMap(name, builtInCMapParams) {
-  var url = builtInCMapParams.url + name + '.bcmap';
-  var cMap = new CMap(true);
-  return new BinaryCMapReader().read(url, cMap, function (useCMap) {
-   return extendCMap(cMap, builtInCMapParams, useCMap);
-  });
- }
- function createBuiltInCMap(name, builtInCMapParams) {
+ function createBuiltInCMap(name, fetchBuiltInCMap) {
   if (name === 'Identity-H') {
    return Promise.resolve(new IdentityCMap(false, 2));
   } else if (name === 'Identity-V') {
    return Promise.resolve(new IdentityCMap(true, 2));
   }
   if (BUILT_IN_CMAPS.indexOf(name) === -1) {
    return Promise.reject(new Error('Unknown cMap name: ' + name));
   }
-  assert(builtInCMapParams, 'built-in cMap parameters are not provided');
-  if (builtInCMapParams.packed) {
-   return parseBinaryCMap(name, builtInCMapParams);
-  }
-  return new Promise(function (resolve, reject) {
-   var url = builtInCMapParams.url + name;
-   var request = new XMLHttpRequest();
-   request.onreadystatechange = function () {
-    if (request.readyState === XMLHttpRequest.DONE) {
-     if (request.status === 200 || request.status === 0) {
-      var cMap = new CMap(true);
-      var lexer = new Lexer(new StringStream(request.responseText));
-      parseCMap(cMap, lexer, builtInCMapParams, null).then(function (parsedCMap) {
-       resolve(parsedCMap);
-      });
-     } else {
-      reject(new Error('Unable to get cMap at: ' + url));
-     }
-    }
-   };
-   request.open('GET', url, true);
-   request.send(null);
+  assert(fetchBuiltInCMap, 'Built-in CMap parameters are not provided.');
+  return fetchBuiltInCMap(name).then(function (data) {
+   var cMapData = data.cMapData, compressionType = data.compressionType;
+   var cMap = new CMap(true);
+   if (compressionType === CMapCompressionType.BINARY) {
+    return new BinaryCMapReader().process(cMapData, cMap, function (useCMap) {
+     return extendCMap(cMap, fetchBuiltInCMap, useCMap);
+    });
+   }
+   assert(compressionType === CMapCompressionType.NONE, 'TODO: Only BINARY/NONE CMap compression is currently supported.');
+   var lexer = new Lexer(new Stream(cMapData));
+   return parseCMap(cMap, lexer, fetchBuiltInCMap, null);
   });
  }
  return {
-  create: function (encoding, builtInCMapParams, useCMap) {
+  create: function (params) {
+   var encoding = params.encoding;
+   var fetchBuiltInCMap = params.fetchBuiltInCMap;
+   var useCMap = params.useCMap;
    if (isName(encoding)) {
-    return createBuiltInCMap(encoding.name, builtInCMapParams);
+    return createBuiltInCMap(encoding.name, fetchBuiltInCMap);
    } else if (isStream(encoding)) {
     var cMap = new CMap();
     var lexer = new Lexer(encoding);
-    return parseCMap(cMap, lexer, builtInCMapParams, useCMap).then(function (parsedCMap) {
+    return parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap).then(function (parsedCMap) {
      if (parsedCMap.isIdentityCMap) {
-      return createBuiltInCMap(parsedCMap.name, builtInCMapParams);
+      return createBuiltInCMap(parsedCMap.name, fetchBuiltInCMap);
      }
      return parsedCMap;
     });
    }
    return Promise.reject(new Error('Encoding required.'));
   }
  };
 }();
@@ -37515,23 +37516,24 @@ var AnnotationFactory = coreAnnotation.A
 var Page = function PageClosure() {
  var DEFAULT_USER_UNIT = 1.0;
  var LETTER_SIZE_MEDIABOX = [
   0,
   0,
   612,
   792
  ];
- function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache) {
+ function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache, builtInCMapCache) {
   this.pdfManager = pdfManager;
   this.pageIndex = pageIndex;
   this.pageDict = pageDict;
   this.xref = xref;
   this.ref = ref;
   this.fontCache = fontCache;
+  this.builtInCMapCache = builtInCMapCache;
   this.evaluatorOptions = pdfManager.evaluatorOptions;
   this.resourcesPromise = null;
   var uniquePrefix = 'p' + this.pageIndex + '_';
   var idCounters = { obj: 0 };
   this.idFactory = {
    createObjId: function () {
     return uniquePrefix + ++idCounters.obj;
    }
@@ -37647,17 +37649,17 @@ var Page = function PageClosure() {
    var resourcesPromise = this.loadResources([
     'ExtGState',
     'ColorSpace',
     'Pattern',
     'Shading',
     'XObject',
     'Font'
    ]);
-   var partialEvaluator = new PartialEvaluator(pdfManager, this.xref, handler, this.pageIndex, this.idFactory, this.fontCache, this.evaluatorOptions);
+   var partialEvaluator = new PartialEvaluator(pdfManager, this.xref, handler, this.pageIndex, this.idFactory, this.fontCache, this.builtInCMapCache, this.evaluatorOptions);
    var dataPromises = Promise.all([
     contentStreamPromise,
     resourcesPromise
    ]);
    var pageListPromise = dataPromises.then(function (data) {
     var contentStream = data[0];
     var opList = new OperatorList(intent, handler, self.pageIndex);
     handler.send('StartRenderPage', {
@@ -37703,17 +37705,17 @@ var Page = function PageClosure() {
     'Font'
    ]);
    var dataPromises = Promise.all([
     contentStreamPromise,
     resourcesPromise
    ]);
    return dataPromises.then(function (data) {
     var contentStream = data[0];
-    var partialEvaluator = new PartialEvaluator(pdfManager, self.xref, handler, self.pageIndex, self.idFactory, self.fontCache, self.evaluatorOptions);
+    var partialEvaluator = new PartialEvaluator(pdfManager, self.xref, handler, self.pageIndex, self.idFactory, self.fontCache, self.builtInCMapCache, self.evaluatorOptions);
     return partialEvaluator.getTextContent(contentStream, task, self.resources, null, normalizeWhitespace, combineTextItems);
    });
   },
   getAnnotationsData: function Page_getAnnotationsData(intent) {
    var annotations = this.annotations;
    var annotationsData = [];
    for (var i = 0, n = annotations.length; i < n; ++i) {
     if (intent) {
@@ -37896,18 +37898,18 @@ var PDFDocument = function PDFDocumentCl
   parseStartXRef: function PDFDocument_parseStartXRef() {
    var startXRef = this.startXRef;
    this.xref.setStartXRef(startXRef);
   },
   setup: function PDFDocument_setup(recoveryMode) {
    this.xref.parse(recoveryMode);
    var self = this;
    var pageFactory = {
-    createPage: function (pageIndex, dict, ref, fontCache) {
-     return new Page(self.pdfManager, self.xref, pageIndex, dict, ref, fontCache);
+    createPage: function (pageIndex, dict, ref, fontCache, builtInCMapCache) {
+     return new Page(self.pdfManager, self.xref, pageIndex, dict, ref, fontCache, builtInCMapCache);
     }
    };
    this.catalog = new Catalog(this.pdfManager, this.xref, pageFactory);
   },
   get numPages() {
    var linearization = this.linearization;
    var num = linearization ? linearization.numPages : this.catalog.numPages;
    return shadow(this, 'numPages', num);
@@ -49169,17 +49171,17 @@ var Type1Parser = function Type1ParserCl
 exports.Type1Parser = Type1Parser;
 
 /***/ }),
 /* 35 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
-var pdfjsVersion = '1.7.297';
-var pdfjsBuild = '425ad309';
+var pdfjsVersion = '1.7.312';
+var pdfjsBuild = 'cada411a';
 var pdfjsCoreWorker = __w_pdfjs_require__(17);
 ;
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ })
 /******/ ]);
 });
\ No newline at end of file
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -316,31 +316,34 @@ function getVisibleElements(scrollEl, vi
   first: first,
   last: last,
   views: visible
  };
 }
 function noContextMenuHandler(e) {
  e.preventDefault();
 }
-function getPDFFileNameFromURL(url) {
- var reURI = /^(?:([^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
+function getPDFFileNameFromURL(url, defaultFilename) {
+ if (typeof defaultFilename === 'undefined') {
+  defaultFilename = 'document.pdf';
+ }
+ var reURI = /^(?:(?:[^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
  var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
  var splitURI = reURI.exec(url);
  var suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]);
  if (suggestedFilename) {
   suggestedFilename = suggestedFilename[0];
   if (suggestedFilename.indexOf('%') !== -1) {
    try {
     suggestedFilename = reFilename.exec(decodeURIComponent(suggestedFilename))[0];
    } catch (e) {
    }
   }
  }
- return suggestedFilename || 'document.pdf';
+ return suggestedFilename || defaultFilename;
 }
 function normalizeWheelEventDelta(evt) {
  var delta = Math.sqrt(evt.deltaX * evt.deltaX + evt.deltaY * evt.deltaY);
  var angle = Math.atan2(evt.deltaY, evt.deltaX);
  if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) {
   delta = -delta;
  }
  var MOUSE_DOM_DELTA_PIXEL_MODE = 0;
@@ -1143,21 +1146,25 @@ var PDFViewerApplication = {
    onProgress: function (loaded, total) {
     PDFViewerApplication.progress(loaded / total);
    }
   });
  },
  setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
   this.url = url;
   this.baseUrl = url.split('#')[0];
-  try {
-   this.setTitle(decodeURIComponent(pdfjsLib.getFilenameFromUrl(url)) || url);
-  } catch (e) {
-   this.setTitle(url);
-  }
+  var title = getPDFFileNameFromURL(url, '');
+  if (!title) {
+   try {
+    title = decodeURIComponent(pdfjsLib.getFilenameFromUrl(url)) || url;
+   } catch (e) {
+    title = url;
+   }
+  }
+  this.setTitle(title);
  },
  setTitle: function pdfViewSetTitle(title) {
   if (this.isViewerEmbedded) {
    return;
   }
   document.title = title;
  },
  close: function pdfViewClose() {
@@ -1246,17 +1253,17 @@ var PDFViewerApplication = {
    throw new Error(loadingErrorMessage);
   });
  },
  download: function pdfViewDownload() {
   function downloadByUrl() {
    downloadManager.downloadUrl(url, filename);
   }
   var url = this.baseUrl;
-  var filename = getPDFFileNameFromURL(url);
+  var filename = getPDFFileNameFromURL(this.url);
   var downloadManager = this.downloadManager;
   downloadManager.onerror = function (err) {
    PDFViewerApplication.error('PDF failed to download.');
   };
   if (!this.pdfDocument) {
    downloadByUrl();
    return;
   }
@@ -3891,16 +3898,28 @@ var PDFAttachmentViewer = function PDFAt
   },
   _dispatchEvent: function PDFAttachmentViewer_dispatchEvent(attachmentsCount) {
    this.eventBus.dispatch('attachmentsloaded', {
     source: this,
     attachmentsCount: attachmentsCount
    });
    this._renderedCapability.resolve();
   },
+  _bindPdfLink: function PDFAttachmentViewer_bindPdfLink(button, content, filename) {
+   var blobUrl;
+   button.onclick = function () {
+    if (!blobUrl) {
+     blobUrl = pdfjsLib.createObjectURL(content, 'application/pdf', pdfjsLib.PDFJS.disableCreateObjectURL);
+    }
+    var viewerUrl;
+    viewerUrl = blobUrl + '?' + encodeURIComponent(filename);
+    window.open(viewerUrl);
+    return false;
+   };
+  },
   _bindLink: function PDFAttachmentViewer_bindLink(button, content, filename) {
    button.onclick = function downloadFile(e) {
     this.downloadManager.downloadData(content, filename, '');
     return false;
    }.bind(this);
   },
   render: function PDFAttachmentViewer_render(params) {
    params = params || {};
@@ -3917,21 +3936,26 @@ var PDFAttachmentViewer = function PDFAt
    }
    var names = Object.keys(attachments).sort(function (a, b) {
     return a.toLowerCase().localeCompare(b.toLowerCase());
    });
    attachmentsCount = names.length;
    for (var i = 0; i < attachmentsCount; i++) {
     var item = attachments[names[i]];
     var filename = pdfjsLib.getFilenameFromUrl(item.filename);
+    filename = pdfjsLib.removeNullCharacters(filename);
     var div = document.createElement('div');
     div.className = 'attachmentsItem';
     var button = document.createElement('button');
-    this._bindLink(button, item.content, filename);
-    button.textContent = pdfjsLib.removeNullCharacters(filename);
+    button.textContent = filename;
+    if (/\.pdf$/i.test(filename)) {
+     this._bindPdfLink(button, item.content, filename);
+    } else {
+     this._bindLink(button, item.content, filename);
+    }
     div.appendChild(button);
     this.container.appendChild(div);
    }
    this._dispatchEvent(attachmentsCount);
   },
   _appendAttachment: function PDFAttachmentViewer_appendAttachment(item) {
    this._renderedCapability.promise.then(function (id, filename, content) {
     var attachments = this.attachments;