Changeset 73616 in spip-zone


Ignore:
Timestamp:
Jun 15, 2013, 6:25:54 PM (6 years ago)
Author:
joseph@…
Message:

Mise à jour de PDF.js au commit mozilla-pdf.js-a2678c5 (GitHub?)

Location:
_plugins_/pdfjs
Files:
24 added
37 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/pdfjs/lib/pdfjs/build/pdf.js

    r69558 r73616  
    1717
    1818var PDFJS = {};
    19 PDFJS.version = '0.7.131';
    20 PDFJS.build = 'c53fa62';
     19PDFJS.version = '0.8.243';
     20PDFJS.build = 'a2678c5';
    2121
    2222(function pdfjsWrapper() {
     
    4141 */
    4242
     43// NOTE: Be careful what goes in this file, as it is also used from the context
     44// of the addon. So using warn/error in here will break the addon.
     45
    4346'use strict';
     47
     48
     49
     50var NetworkManager = (function NetworkManagerClosure() {
     51
     52  var OK_RESPONSE = 200;
     53  var PARTIAL_CONTENT_RESPONSE = 206;
     54
     55  function NetworkManager(url, args) {
     56    this.url = url;
     57    args = args || {};
     58    this.httpHeaders = args.httpHeaders || {};
     59    this.getXhr = args.getXhr ||
     60      function NetworkManager_getXhr() {
     61        return new XMLHttpRequest();
     62      };
     63
     64    this.currXhrId = 0;
     65    this.pendingRequests = {};
     66    this.loadedRequests = {};
     67  }
     68
     69  function getArrayBuffer(xhr) {
     70    var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
     71                xhr.responseArrayBuffer || xhr.response);
     72    if (typeof data !== 'string') {
     73      return data;
     74    }
     75    var length = data.length;
     76    var buffer = new Uint8Array(length);
     77    for (var i = 0; i < length; i++) {
     78      buffer[i] = data.charCodeAt(i) & 0xFF;
     79    }
     80    return buffer;
     81  }
     82
     83  NetworkManager.prototype = {
     84    requestRange: function NetworkManager_requestRange(begin, end, listeners) {
     85      var args = {
     86        begin: begin,
     87        end: end
     88      };
     89      for (var prop in listeners) {
     90        args[prop] = listeners[prop];
     91      }
     92      return this.request(args);
     93    },
     94
     95    requestFull: function NetworkManager_requestRange(listeners) {
     96      return this.request(listeners);
     97    },
     98
     99    request: function NetworkManager_requestRange(args) {
     100      var xhr = this.getXhr();
     101      var xhrId = this.currXhrId++;
     102      var pendingRequest = this.pendingRequests[xhrId] = {
     103        xhr: xhr
     104      };
     105
     106      xhr.open('GET', this.url);
     107      for (var property in this.httpHeaders) {
     108        var value = this.httpHeaders[property];
     109        if (typeof value === 'undefined') {
     110          continue;
     111        }
     112        xhr.setRequestHeader(property, value);
     113      }
     114      if ('begin' in args && 'end' in args) {
     115        var rangeStr = args.begin + '-' + (args.end - 1);
     116        xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
     117        pendingRequest.expectedStatus = 206;
     118      } else {
     119        pendingRequest.expectedStatus = 200;
     120      }
     121
     122      xhr.mozResponseType = xhr.responseType = 'arraybuffer';
     123
     124      if (args.onProgress) {
     125        xhr.onprogress = args.onProgress;
     126      }
     127      if (args.onError) {
     128        xhr.onerror = function(evt) {
     129          args.onError(xhr.status);
     130        };
     131      }
     132      xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
     133
     134      pendingRequest.onHeadersReceived = args.onHeadersReceived;
     135      pendingRequest.onDone = args.onDone;
     136      pendingRequest.onError = args.onError;
     137
     138      xhr.send(null);
     139
     140      return xhrId;
     141    },
     142
     143    onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
     144      var pendingRequest = this.pendingRequests[xhrId];
     145      if (!pendingRequest) {
     146        // Maybe abortRequest was called...
     147        return;
     148      }
     149
     150      var xhr = pendingRequest.xhr;
     151      if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
     152        pendingRequest.onHeadersReceived();
     153        delete pendingRequest.onHeadersReceived;
     154      }
     155
     156      if (xhr.readyState !== 4) {
     157        return;
     158      }
     159
     160      if (!(xhrId in this.pendingRequests)) {
     161        // The XHR request might have been aborted in onHeadersReceived()
     162        // callback, in which case we should abort request
     163        return;
     164      }
     165
     166      delete this.pendingRequests[xhrId];
     167
     168      // success status == 0 can be on ftp, file and other protocols
     169      if (xhr.status === 0 && /^https?:/i.test(this.url)) {
     170        if (pendingRequest.onError) {
     171          pendingRequest.onError(xhr.status);
     172        }
     173        return;
     174      }
     175      var xhrStatus = xhr.status || OK_RESPONSE;
     176
     177      // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2:
     178      // "A server MAY ignore the Range header". This means it's possible to
     179      // get a 200 rather than a 206 response from a range request.
     180      var ok_response_on_range_request =
     181          xhrStatus === OK_RESPONSE &&
     182          pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
     183
     184      if (!ok_response_on_range_request &&
     185          xhrStatus !== pendingRequest.expectedStatus) {
     186        if (pendingRequest.onError) {
     187          pendingRequest.onError(xhr.status);
     188        }
     189        return;
     190      }
     191
     192      this.loadedRequests[xhrId] = true;
     193
     194      var chunk = getArrayBuffer(xhr);
     195      if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
     196        var rangeHeader = xhr.getResponseHeader('Content-Range');
     197        var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
     198        var begin = parseInt(matches[1], 10);
     199        pendingRequest.onDone({
     200          begin: begin,
     201          chunk: chunk
     202        });
     203      } else {
     204        pendingRequest.onDone({
     205          begin: 0,
     206          chunk: chunk
     207        });
     208      }
     209    },
     210
     211    hasPendingRequests: function NetworkManager_hasPendingRequests() {
     212      for (var xhrId in this.pendingRequests) {
     213        return true;
     214      }
     215      return false;
     216    },
     217
     218    getRequestXhr: function NetworkManager_getXhr(xhrId) {
     219      return this.pendingRequests[xhrId].xhr;
     220    },
     221
     222    isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
     223      return xhrId in this.pendingRequests;
     224    },
     225
     226    isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) {
     227      return xhrId in this.loadedRequests;
     228    },
     229
     230    abortAllRequests: function NetworkManager_abortAllRequests() {
     231      for (var xhrId in this.pendingRequests) {
     232        this.abortRequest(xhrId | 0);
     233      }
     234    },
     235
     236    abortRequest: function NetworkManager_abortRequest(xhrId) {
     237      var xhr = this.pendingRequests[xhrId].xhr;
     238      delete this.pendingRequests[xhrId];
     239      xhr.abort();
     240    }
     241  };
     242
     243  return NetworkManager;
     244})();
     245
     246
     247
     248var ChunkedStream = (function ChunkedStreamClosure() {
     249  function ChunkedStream(length, chunkSize, manager) {
     250    this.bytes = new Uint8Array(length);
     251    this.start = 0;
     252    this.pos = 0;
     253    this.end = length;
     254    this.chunkSize = chunkSize;
     255    this.loadedChunks = [];
     256    this.numChunksLoaded = 0;
     257    this.numChunks = Math.ceil(length / chunkSize);
     258    this.manager = manager;
     259  }
     260
     261  // required methods for a stream. if a particular stream does not
     262  // implement these, an error should be thrown
     263  ChunkedStream.prototype = {
     264
     265    getMissingChunks: function ChunkedStream_getMissingChunks() {
     266      var chunks = [];
     267      for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) {
     268        if (!(chunk in this.loadedChunks)) {
     269          chunks.push(chunk);
     270        }
     271      }
     272      return chunks;
     273    },
     274
     275    allChunksLoaded: function ChunkedStream_allChunksLoaded() {
     276      return this.numChunksLoaded === this.numChunks;
     277    },
     278
     279    onReceiveData: function(begin, chunk) {
     280      var end = begin + chunk.byteLength;
     281
     282      assert(begin % this.chunkSize === 0, 'Bad begin offset: ' + begin);
     283      // Using this.length is inaccurate here since this.start can be moved
     284      // See ChunkedStream.moveStart()
     285      var length = this.bytes.length;
     286      assert(end % this.chunkSize === 0 || end === length,
     287        'Bad end offset: ' + end);
     288
     289      this.bytes.set(new Uint8Array(chunk), begin);
     290      var chunkSize = this.chunkSize;
     291      var beginChunk = Math.floor(begin / chunkSize);
     292      var endChunk = Math.floor((end - 1) / chunkSize) + 1;
     293
     294      for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
     295        if (!(chunk in this.loadedChunks)) {
     296          this.loadedChunks[chunk] = true;
     297          ++this.numChunksLoaded;
     298        }
     299      }
     300    },
     301
     302    ensureRange: function ChunkedStream_ensureRange(begin, end) {
     303      if (begin >= end) {
     304        return;
     305      }
     306
     307      var chunkSize = this.chunkSize;
     308      var beginChunk = Math.floor(begin / chunkSize);
     309      var endChunk = Math.floor((end - 1) / chunkSize) + 1;
     310      for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
     311        if (!(chunk in this.loadedChunks)) {
     312          throw new MissingDataException(begin, end);
     313        }
     314      }
     315    },
     316
     317    nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {
     318      for (var chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
     319        if (!(chunk in this.loadedChunks)) {
     320          return chunk;
     321        }
     322      }
     323      // Wrap around to beginning
     324      for (var chunk = 0; chunk < beginChunk; ++chunk) {
     325        if (!(chunk in this.loadedChunks)) {
     326          return chunk;
     327        }
     328      }
     329      return null;
     330    },
     331
     332    hasChunk: function ChunkedStream_hasChunk(chunk) {
     333      return chunk in this.loadedChunks;
     334    },
     335
     336    get length() {
     337      return this.end - this.start;
     338    },
     339
     340    getByte: function ChunkedStream_getByte() {
     341      var pos = this.pos;
     342      if (pos >= this.end) {
     343        return null;
     344      }
     345      this.ensureRange(pos, pos + 1);
     346      return this.bytes[this.pos++];
     347    },
     348
     349    // returns subarray of original buffer
     350    // should only be read
     351    getBytes: function ChunkedStream_getBytes(length) {
     352      var bytes = this.bytes;
     353      var pos = this.pos;
     354      var strEnd = this.end;
     355
     356      if (!length) {
     357        this.ensureRange(pos, strEnd);
     358        return bytes.subarray(pos, strEnd);
     359      }
     360
     361      var end = pos + length;
     362      if (end > strEnd)
     363        end = strEnd;
     364      this.ensureRange(pos, end);
     365
     366      this.pos = end;
     367      return bytes.subarray(pos, end);
     368    },
     369
     370    getByteRange: function ChunkedStream_getBytes(begin, end) {
     371      this.ensureRange(begin, end);
     372      return this.bytes.subarray(begin, end);
     373    },
     374
     375    lookChar: function ChunkedStream_lookChar() {
     376      var pos = this.pos;
     377      if (pos >= this.end)
     378        return null;
     379      this.ensureRange(pos, pos + 1);
     380      return String.fromCharCode(this.bytes[pos]);
     381    },
     382
     383    getChar: function ChunkedStream_getChar() {
     384      var pos = this.pos;
     385      if (pos >= this.end)
     386        return null;
     387      this.ensureRange(pos, pos + 1);
     388      return String.fromCharCode(this.bytes[this.pos++]);
     389    },
     390
     391    skip: function ChunkedStream_skip(n) {
     392      if (!n)
     393        n = 1;
     394      this.pos += n;
     395    },
     396
     397    reset: function ChunkedStream_reset() {
     398      this.pos = this.start;
     399    },
     400
     401    moveStart: function ChunkedStream_moveStart() {
     402      this.start = this.pos;
     403    },
     404
     405    makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) {
     406      function ChunkedStreamSubstream() {}
     407      ChunkedStreamSubstream.prototype = Object.create(this);
     408      ChunkedStreamSubstream.prototype.getMissingChunks = function() {
     409        var chunkSize = this.chunkSize;
     410        var beginChunk = Math.floor(this.start / chunkSize);
     411        var endChunk = Math.floor((this.end - 1) / chunkSize) + 1;
     412        var missingChunks = [];
     413        for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
     414          if (!(chunk in this.loadedChunks)) {
     415            missingChunks.push(chunk);
     416          }
     417        }
     418        return missingChunks;
     419      };
     420      var subStream = new ChunkedStreamSubstream();
     421      subStream.pos = subStream.start = start;
     422      subStream.end = start + length || this.end;
     423      subStream.dict = dict;
     424      return subStream;
     425    },
     426
     427    isStream: true
     428  };
     429
     430  return ChunkedStream;
     431})();
     432
     433var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
     434
     435  function ChunkedStreamManager(length, chunkSize, url, args) {
     436    var self = this;
     437    this.stream = new ChunkedStream(length, chunkSize, this);
     438    this.length = length;
     439    this.chunkSize = chunkSize;
     440    this.url = url;
     441    this.disableAutoFetch = args.disableAutoFetch;
     442    var msgHandler = this.msgHandler = args.msgHandler;
     443
     444    if (args.chunkedViewerLoading) {
     445      msgHandler.on('OnDataRange', this.onReceiveData.bind(this));
     446      msgHandler.on('OnDataProgress', this.onProgress.bind(this));
     447      this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
     448        msgHandler.send('RequestDataRange', { begin: begin, end: end });
     449      };
     450    } else {
     451
     452      var getXhr = function getXhr() {
     453        return new XMLHttpRequest();
     454      };
     455      this.networkManager = new NetworkManager(this.url, {
     456        getXhr: getXhr,
     457        httpHeaders: args.httpHeaders
     458      });
     459      this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
     460        this.networkManager.requestRange(begin, end, {
     461          onDone: this.onReceiveData.bind(this),
     462          onProgress: this.onProgress.bind(this)
     463        });
     464      };
     465    }
     466
     467    this.currRequestId = 0;
     468
     469    this.chunksNeededByRequest = {};
     470    this.requestsByChunk = {};
     471    this.callbacksByRequest = {};
     472
     473    this.loadedStream = new Promise();
     474  }
     475
     476  ChunkedStreamManager.prototype = {
     477
     478    onLoadedStream: function ChunkedStreamManager_getLoadedStream() {
     479      return this.loadedStream;
     480    },
     481
     482    // Get all the chunks that are not yet loaded and groups them into
     483    // contiguous ranges to load in as few requests as possible
     484    requestAllChunks: function ChunkedStreamManager_requestAllChunks() {
     485      var missingChunks = this.stream.getMissingChunks();
     486      this.requestChunks(missingChunks);
     487      return this.loadedStream;
     488    },
     489
     490    requestChunks: function ChunkedStreamManager_requestChunks(chunks,
     491                                                               callback) {
     492      var requestId = this.currRequestId++;
     493
     494      var chunksNeeded;
     495      this.chunksNeededByRequest[requestId] = chunksNeeded = {};
     496      for (var i = 0, ii = chunks.length; i < ii; i++) {
     497        if (!this.stream.hasChunk(chunks[i])) {
     498          chunksNeeded[chunks[i]] = true;
     499        }
     500      }
     501
     502      if (isEmptyObj(chunksNeeded)) {
     503        if (callback) {
     504          callback();
     505        }
     506        return;
     507      }
     508
     509      this.callbacksByRequest[requestId] = callback;
     510
     511      var chunksToRequest = [];
     512      for (var chunk in chunksNeeded) {
     513        chunk = chunk | 0;
     514        if (!(chunk in this.requestsByChunk)) {
     515          this.requestsByChunk[chunk] = [];
     516          chunksToRequest.push(chunk);
     517        }
     518        this.requestsByChunk[chunk].push(requestId);
     519      }
     520
     521      if (!chunksToRequest.length) {
     522        return;
     523      }
     524
     525      var groupedChunksToRequest = this.groupChunks(chunksToRequest);
     526
     527      for (var i = 0; i < groupedChunksToRequest.length; ++i) {
     528        var groupedChunk = groupedChunksToRequest[i];
     529        var begin = groupedChunk.beginChunk * this.chunkSize;
     530        var end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length);
     531        this.sendRequest(begin, end);
     532      }
     533    },
     534
     535    getStream: function ChunkedStreamManager_getStream() {
     536      return this.stream;
     537    },
     538
     539    // Loads any chunks in the requested range that are not yet loaded
     540    requestRange: function ChunkedStreamManager_requestRange(
     541                      begin, end, callback) {
     542
     543      end = Math.min(end, this.length);
     544
     545      var beginChunk = this.getBeginChunk(begin);
     546      var endChunk = this.getEndChunk(end);
     547
     548      var chunks = [];
     549      for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
     550        chunks.push(chunk);
     551      }
     552
     553      this.requestChunks(chunks, callback);
     554    },
     555
     556    requestRanges: function ChunkedStreamManager_requestRanges(ranges,
     557                                                               callback) {
     558      ranges = ranges || [];
     559      var chunksToRequest = [];
     560
     561      for (var i = 0; i < ranges.length; i++) {
     562        var beginChunk = this.getBeginChunk(ranges[i].begin);
     563        var endChunk = this.getEndChunk(ranges[i].end);
     564        for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
     565          if (chunksToRequest.indexOf(chunk) < 0) {
     566            chunksToRequest.push(chunk);
     567          }
     568        }
     569      }
     570
     571      chunksToRequest.sort(function(a, b) { return a - b; });
     572      this.requestChunks(chunksToRequest, callback);
     573    },
     574
     575    // Groups a sorted array of chunks into as few continguous larger
     576    // chunks as possible
     577    groupChunks: function ChunkedStreamManager_groupChunks(chunks) {
     578      var groupedChunks = [];
     579      var beginChunk;
     580      var prevChunk;
     581      for (var i = 0; i < chunks.length; ++i) {
     582        var chunk = chunks[i];
     583
     584        if (!beginChunk) {
     585          beginChunk = chunk;
     586        }
     587
     588        if (prevChunk && prevChunk + 1 !== chunk) {
     589          groupedChunks.push({
     590            beginChunk: beginChunk, endChunk: prevChunk + 1});
     591          beginChunk = chunk;
     592        }
     593        if (i + 1 === chunks.length) {
     594          groupedChunks.push({
     595            beginChunk: beginChunk, endChunk: chunk + 1});
     596        }
     597
     598        prevChunk = chunk;
     599      }
     600      return groupedChunks;
     601    },
     602
     603    onProgress: function ChunkedStreamManager_onProgress(args) {
     604      var bytesLoaded = this.stream.numChunksLoaded * this.chunkSize +
     605                        args.loaded;
     606      this.msgHandler.send('DocProgress', {
     607        loaded: bytesLoaded,
     608        total: this.length
     609      });
     610    },
     611
     612    onReceiveData: function ChunkedStreamManager_onReceiveData(args) {
     613      var chunk = args.chunk;
     614      var begin = args.begin;
     615      var end = begin + chunk.byteLength;
     616
     617      var beginChunk = this.getBeginChunk(begin);
     618      var endChunk = this.getEndChunk(end);
     619
     620      this.stream.onReceiveData(begin, chunk);
     621      if (this.stream.allChunksLoaded()) {
     622        this.loadedStream.resolve(this.stream);
     623      }
     624
     625      var loadedRequests = [];
     626      for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
     627
     628        // The server might return more chunks than requested
     629        var requestIds = this.requestsByChunk[chunk] || [];
     630        delete this.requestsByChunk[chunk];
     631
     632        for (var i = 0; i < requestIds.length; ++i) {
     633          var requestId = requestIds[i];
     634          var chunksNeeded = this.chunksNeededByRequest[requestId];
     635          if (chunk in chunksNeeded) {
     636            delete chunksNeeded[chunk];
     637          }
     638
     639          if (!isEmptyObj(chunksNeeded)) {
     640            continue;
     641          }
     642
     643          loadedRequests.push(requestId);
     644        }
     645      }
     646
     647      // If there are no pending requests, automatically fetch the next
     648      // unfetched chunk of the PDF
     649      if (!this.disableAutoFetch && isEmptyObj(this.requestsByChunk)) {
     650        var nextEmptyChunk;
     651        if (this.stream.numChunksLoaded === 1) {
     652          // This is a special optimization so that after fetching the first
     653          // chunk, rather than fetching the second chunk, we fetch the last
     654          // chunk.
     655          var lastChunk = this.stream.numChunks - 1;
     656          if (!this.stream.hasChunk(lastChunk)) {
     657            nextEmptyChunk = lastChunk;
     658          }
     659        } else {
     660          nextEmptyChunk = this.stream.nextEmptyChunk(endChunk);
     661        }
     662        if (isInt(nextEmptyChunk)) {
     663          this.requestChunks([nextEmptyChunk]);
     664        }
     665      }
     666
     667      for (var i = 0; i < loadedRequests.length; ++i) {
     668        var requestId = loadedRequests[i];
     669        var callback = this.callbacksByRequest[requestId];
     670        delete this.callbacksByRequest[requestId];
     671        if (callback) {
     672          callback();
     673        }
     674      }
     675
     676      this.msgHandler.send('DocProgress', {
     677        loaded: this.stream.numChunksLoaded * this.chunkSize,
     678        total: this.length
     679      });
     680    },
     681
     682    getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) {
     683      var chunk = Math.floor(begin / this.chunkSize);
     684      return chunk;
     685    },
     686
     687    getEndChunk: function ChunkedStreamManager_getEndChunk(end) {
     688      if (end % this.chunkSize === 0) {
     689        return end / this.chunkSize;
     690      }
     691
     692      // 0 -> 0
     693      // 1 -> 1
     694      // 99 -> 1
     695      // 100 -> 1
     696      // 101 -> 2
     697      var chunk = Math.floor((end - 1) / this.chunkSize) + 1;
     698      return chunk;
     699    }
     700  };
     701
     702  return ChunkedStreamManager;
     703})();
     704
     705
     706
     707// TODO(mack): Make use of PDFJS.Util.inherit() when it becomes available
     708var BasePdfManager = (function BasePdfManagerClosure() {
     709  function BasePdfManager() {
     710    throw new Error('Cannot initialize BaseManagerManager');
     711  }
     712
     713  BasePdfManager.prototype = {
     714    onLoadedStream: function BasePdfManager_onLoadedStream() {
     715      throw new NotImplementedException();
     716    },
     717
     718    ensureModel: function BasePdfManager_ensureModel(prop, args) {
     719      return this.ensure(this.pdfModel, prop, args);
     720    },
     721
     722    ensureXRef: function BasePdfManager_ensureXRef(prop, args) {
     723      return this.ensure(this.pdfModel.xref, prop, args);
     724    },
     725
     726    ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) {
     727      return this.ensure(this.pdfModel.catalog, prop, args);
     728    },
     729
     730    getPage: function BasePdfManager_pagePage(pageIndex) {
     731      return this.pdfModel.getPage(pageIndex);
     732    },
     733
     734    ensure: function BasePdfManager_ensure(obj, prop, args) {
     735      return new NotImplementedException();
     736    },
     737
     738    requestRange: function BasePdfManager_ensure(begin, end) {
     739      return new NotImplementedException();
     740    },
     741
     742    requestLoadedStream: function BasePdfManager_requestLoadedStream() {
     743      return new NotImplementedException();
     744    },
     745
     746    updatePassword: function BasePdfManager_updatePassword(password) {
     747      this.pdfModel.xref.password = this.password = password;
     748      if (this.passwordChangedPromise) {
     749        this.passwordChangedPromise.resolve();
     750      }
     751    }
     752  };
     753
     754  return BasePdfManager;
     755})();
     756
     757var LocalPdfManager = (function LocalPdfManagerClosure() {
     758  function LocalPdfManager(data, password) {
     759    var stream = new Stream(data);
     760    this.pdfModel = new PDFDocument(this, stream, password);
     761    this.loadedStream = new Promise();
     762    this.loadedStream.resolve(stream);
     763  }
     764
     765  LocalPdfManager.prototype = Object.create(BasePdfManager.prototype);
     766  LocalPdfManager.prototype.constructor = LocalPdfManager;
     767
     768  LocalPdfManager.prototype.ensure =
     769      function LocalPdfManager_ensure(obj, prop, args) {
     770    var promise = new Promise();
     771    try {
     772      var value = obj[prop];
     773      var result;
     774      if (typeof(value) === 'function') {
     775        result = value.apply(obj, args);
     776      } else {
     777        result = value;
     778      }
     779      promise.resolve(result);
     780    } catch (e) {
     781      console.log(e.stack);
     782      promise.reject(e);
     783    }
     784    return promise;
     785  };
     786
     787  LocalPdfManager.prototype.requestRange =
     788      function LocalPdfManager_requestRange(begin, end) {
     789    var promise = new Promise();
     790    promise.resolve();
     791    return promise;
     792  };
     793
     794  LocalPdfManager.prototype.requestLoadedStream =
     795      function LocalPdfManager_requestLoadedStream() {
     796  };
     797
     798  LocalPdfManager.prototype.onLoadedStream =
     799      function LocalPdfManager_getLoadedStream() {
     800    return this.loadedStream;
     801  };
     802
     803  return LocalPdfManager;
     804})();
     805
     806var NetworkPdfManager = (function NetworkPdfManagerClosure() {
     807
     808  var CHUNK_SIZE = 65536;
     809
     810  function NetworkPdfManager(args, msgHandler) {
     811
     812    this.msgHandler = msgHandler;
     813
     814    var params = {
     815      msgHandler: msgHandler,
     816      httpHeaders: args.httpHeaders,
     817      chunkedViewerLoading: args.chunkedViewerLoading,
     818      disableAutoFetch: args.disableAutoFetch
     819    };
     820    this.streamManager = new ChunkedStreamManager(args.length, CHUNK_SIZE,
     821                                                  args.url, params);
     822
     823    this.pdfModel = new PDFDocument(this, this.streamManager.getStream(),
     824                                    args.password);
     825  }
     826
     827  NetworkPdfManager.prototype = Object.create(BasePdfManager.prototype);
     828  NetworkPdfManager.prototype.constructor = NetworkPdfManager;
     829
     830  NetworkPdfManager.prototype.ensure =
     831      function NetworkPdfManager_ensure(obj, prop, args) {
     832    var promise = new Promise();
     833    this.ensureHelper(promise, obj, prop, args);
     834    return promise;
     835  };
     836
     837  NetworkPdfManager.prototype.ensureHelper =
     838      function NetworkPdfManager_ensureHelper(promise, obj, prop, args) {
     839    try {
     840      var result;
     841      var value = obj[prop];
     842      if (typeof(value) === 'function') {
     843        result = value.apply(obj, args);
     844      } else {
     845        result = value;
     846      }
     847      promise.resolve(result);
     848    } catch(e) {
     849      if (!(e instanceof MissingDataException)) {
     850        console.log(e.stack);
     851        promise.reject(e);
     852        return;
     853      }
     854
     855      this.streamManager.requestRange(e.begin, e.end, function() {
     856        this.ensureHelper(promise, obj, prop, args);
     857      }.bind(this));
     858    }
     859  };
     860
     861  NetworkPdfManager.prototype.requestRange =
     862      function NetworkPdfManager_requestRange(begin, end) {
     863    var promise = new Promise();
     864    this.streamManager.requestRange(begin, end, function() {
     865      promise.resolve();
     866    });
     867    return promise;
     868  };
     869
     870  NetworkPdfManager.prototype.requestLoadedStream =
     871      function NetworkPdfManager_requestLoadedStream() {
     872    this.streamManager.requestAllChunks();
     873  };
     874
     875  NetworkPdfManager.prototype.onLoadedStream =
     876      function NetworkPdfManager_getLoadedStream() {
     877    return this.streamManager.onLoadedStream();
     878  };
     879
     880  return NetworkPdfManager;
     881})();
     882
     883
    44884
    45885var globalScope = (typeof window === 'undefined') ? this : window;
     
    57897}
    58898
    59 // getPdf()
    60 // Convenience function to perform binary Ajax GET
    61 // Usage: getPdf('http://...', callback)
    62 //        getPdf({
    63 //                 url:String ,
    64 //                 [,progress:Function, error:Function]
    65 //               },
    66 //               callback)
    67 function getPdf(arg, callback) {
    68   var params = arg;
    69   if (typeof arg === 'string')
    70     params = { url: arg };
    71   var xhr = new XMLHttpRequest();
    72   xhr.open('GET', params.url);
    73 
    74   var headers = params.headers;
    75   if (headers) {
    76     for (var property in headers) {
    77       if (typeof headers[property] === 'undefined')
    78         continue;
    79 
    80       xhr.setRequestHeader(property, params.headers[property]);
    81     }
    82   }
    83 
    84   xhr.mozResponseType = xhr.responseType = 'arraybuffer';
    85 
    86   var protocol = params.url.substring(0, params.url.indexOf(':') + 1);
    87   xhr.expected = (protocol === 'http:' || protocol === 'https:') ? 200 : 0;
    88 
    89   if ('progress' in params)
    90     xhr.onprogress = params.progress || undefined;
    91 
    92   var calledErrorBack = false;
    93 
    94   if ('error' in params) {
    95     xhr.onerror = function errorBack() {
    96       if (!calledErrorBack) {
    97         calledErrorBack = true;
    98         params.error();
    99       }
    100     }
    101   }
    102 
    103   xhr.onreadystatechange = function getPdfOnreadystatechange(e) {
    104     if (xhr.readyState === 4) {
    105       if (xhr.status === xhr.expected) {
    106         var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
    107                     xhr.responseArrayBuffer || xhr.response);
    108         callback(data);
    109       } else if (params.error && !calledErrorBack) {
    110         calledErrorBack = true;
    111         params.error(e);
    112       }
    113     }
    114   };
    115   xhr.send(null);
    116 }
    117 globalScope.PDFJS.getPdf = getPdf;
    118899globalScope.PDFJS.pdfBug = false;
    119900
     901
    120902var Page = (function PageClosure() {
    121   function Page(xref, pageIndex, pageDict, ref) {
     903
     904  function Page(pdfManager, xref, pageIndex, pageDict, ref) {
     905    this.pdfManager = pdfManager;
    122906    this.pageIndex = pageIndex;
    123907    this.pageDict = pageDict;
    124908    this.xref = xref;
    125909    this.ref = ref;
    126 
    127     this.displayReadyPromise = null;
     910    this.idCounters = {
     911      font: 0,
     912      obj: 0
     913    };
     914    this.resourcesPromise = null;
    128915  }
    129916
     
    144931    },
    145932    get content() {
    146       return shadow(this, 'content', this.getPageProp('Contents'));
     933      return this.getPageProp('Contents');
    147934    },
    148935    get resources() {
     
    172959      return shadow(this, 'view', cropBox);
    173960    },
    174     get annotations() {
    175       return shadow(this, 'annotations', this.inheritPageProp('Annots'));
     961    get annotationRefs() {
     962      return shadow(this, 'annotationRefs', this.inheritPageProp('Annots'));
    176963    },
    177964    get rotate() {
    178965      var rotate = this.inheritPageProp('Rotate') || 0;
    179966      // Normalize rotation so it's a multiple of 90 and between 0 and 270
    180       if (rotate % 90 != 0) {
     967      if (rotate % 90 !== 0) {
    181968        rotate = 0;
    182969      } else if (rotate >= 360) {
     
    191978    getContentStream: function Page_getContentStream() {
    192979      var content = this.content;
     980      var stream;
    193981      if (isArray(content)) {
    194982        // fetching items
     
    198986        for (i = 0; i < n; ++i)
    199987          streams.push(xref.fetchIfRef(content[i]));
    200         content = new StreamsSequenceStream(streams);
     988        stream = new StreamsSequenceStream(streams);
    201989      } else if (isStream(content)) {
    202         content.reset();
    203       } else if (!content) {
     990        stream = content;
     991      } else {
    204992        // replacing non-existent page content with empty one
    205         content = new NullStream();
    206       }
    207       return content;
    208     },
    209     getOperatorList: function Page_getOperatorList(handler, dependency) {
    210       var xref = this.xref;
    211       var contentStream = this.getContentStream();
    212       var resources = this.resources;
    213       var pe = this.pe = new PartialEvaluator(
    214                                 xref, handler, this.pageIndex,
    215                                 'p' + this.pageIndex + '_');
    216 
    217       var list = pe.getOperatorList(contentStream, resources, dependency);
    218       pe.optimizeQueue(list);
    219       return list;
     993        stream = new NullStream();
     994      }
     995      return stream;
     996    },
     997    loadResources: function(keys) {
     998      if (!this.resourcesPromise) {
     999        // TODO: add async inheritPageProp and remove this.
     1000        this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
     1001      }
     1002      var promise = new Promise();
     1003      this.resourcesPromise.then(function resourceSuccess() {
     1004        var objectLoader = new ObjectLoader(this.resources.map,
     1005                                            keys,
     1006                                            this.xref);
     1007        objectLoader.load().then(function objectLoaderSuccess() {
     1008          promise.resolve();
     1009        });
     1010      }.bind(this));
     1011      return promise;
     1012    },
     1013    getOperatorList: function Page_getOperatorList(handler) {
     1014      var self = this;
     1015      var promise = new Promise();
     1016
     1017      function reject(e) {
     1018        promise.reject(e);
     1019      }
     1020
     1021      var pageListPromise = new Promise();
     1022
     1023      var pdfManager = this.pdfManager;
     1024      var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
     1025                                                   []);
     1026      var resourcesPromise = this.loadResources([
     1027        'ExtGState',
     1028        'ColorSpace',
     1029        'Pattern',
     1030        'Shading',
     1031        'XObject',
     1032        'Font',
     1033        // ProcSet
     1034        // Properties
     1035      ]);
     1036
     1037      var partialEvaluator = new PartialEvaluator(
     1038            pdfManager, this.xref, handler,
     1039            this.pageIndex, 'p' + this.pageIndex + '_',
     1040            this.idCounters);
     1041
     1042      var dataPromises = Promise.all(
     1043          [contentStreamPromise, resourcesPromise], reject);
     1044      dataPromises.then(function(data) {
     1045        var contentStream = data[0];
     1046
     1047        partialEvaluator.getOperatorList(contentStream, self.resources).then(
     1048          function(data) {
     1049            pageListPromise.resolve(data);
     1050          },
     1051          reject
     1052        );
     1053      });
     1054
     1055      var annotationsPromise = pdfManager.ensure(this, 'annotations');
     1056      Promise.all([pageListPromise, annotationsPromise]).then(function(datas) {
     1057        var pageData = datas[0];
     1058        var pageQueue = pageData.queue;
     1059        var annotations = datas[1];
     1060
     1061        if (annotations.length === 0) {
     1062          PartialEvaluator.optimizeQueue(pageQueue);
     1063          promise.resolve(pageData);
     1064          return;
     1065        }
     1066
     1067        var dependencies = pageData.dependencies;
     1068        var annotationsReadyPromise = Annotation.appendToOperatorList(
     1069          annotations, pageQueue, pdfManager, dependencies, partialEvaluator);
     1070        annotationsReadyPromise.then(function () {
     1071          PartialEvaluator.optimizeQueue(pageQueue);
     1072
     1073          promise.resolve(pageData);
     1074        }, reject);
     1075      }, reject);
     1076
     1077      return promise;
    2201078    },
    2211079    extractTextContent: function Page_extractTextContent() {
     
    2251083      };
    2261084
    227       var xref = this.xref;
    228       var contentStream = this.getContentStream();
    229       var resources = xref.fetchIfRef(this.resources);
    230 
    231       var pe = new PartialEvaluator(
    232                      xref, handler, this.pageIndex,
    233                      'p' + this.pageIndex + '_');
    234       return pe.getTextContent(contentStream, resources);
    235     },
    236     getLinks: function Page_getLinks() {
    237       var links = [];
    238       var annotations = this.getAnnotations();
    239       var i, n = annotations.length;
    240       for (i = 0; i < n; ++i) {
    241         if (annotations[i].type != 'Link')
    242           continue;
    243         links.push(annotations[i]);
    244       }
    245       return links;
    246     },
    247     getAnnotations: function Page_getAnnotations() {
    248       var xref = this.xref;
    249       function getInheritableProperty(annotation, name) {
    250         var item = annotation;
    251         while (item && !item.has(name)) {
    252           item = item.get('Parent');
     1085      var self = this;
     1086
     1087      var textContentPromise = new Promise();
     1088
     1089      var pdfManager = this.pdfManager;
     1090      var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
     1091                                                   []);
     1092
     1093      var resourcesPromise = this.loadResources([
     1094        'ExtGState',
     1095        'XObject',
     1096        'Font'
     1097      ]);
     1098
     1099      var dataPromises = Promise.all([contentStreamPromise,
     1100                                      resourcesPromise]);
     1101      dataPromises.then(function(data) {
     1102        var contentStream = data[0];
     1103        var partialEvaluator = new PartialEvaluator(
     1104              pdfManager, self.xref, handler,
     1105              self.pageIndex, 'p' + self.pageIndex + '_',
     1106              self.idCounters);
     1107
     1108        partialEvaluator.getTextContent(
     1109            contentStream, self.resources).then(function(bidiTexts) {
     1110          textContentPromise.resolve({
     1111            bidiTexts: bidiTexts
     1112          });
     1113        });
     1114      });
     1115
     1116      return textContentPromise;
     1117    },
     1118
     1119    getAnnotationsData: function Page_getAnnotationsData() {
     1120      var annotations = this.annotations;
     1121      var annotationsData = [];
     1122      for (var i = 0, n = annotations.length; i < n; ++i) {
     1123        annotationsData.push(annotations[i].getData());
     1124      }
     1125      return annotationsData;
     1126    },
     1127
     1128    get annotations() {
     1129      var annotations = [];
     1130      var annotationRefs = this.annotationRefs || [];
     1131      for (var i = 0, n = annotationRefs.length; i < n; ++i) {
     1132        var annotationRef = annotationRefs[i];
     1133        var annotation = Annotation.fromRef(this.xref, annotationRef);
     1134        if (annotation) {
     1135          annotations.push(annotation);
    2531136        }
    254         if (!item)
    255           return null;
    256         return item.get(name);
    257       }
    258       function isValidUrl(url) {
    259         if (!url)
    260           return false;
    261         var colon = url.indexOf(':');
    262         if (colon < 0)
    263           return false;
    264         var protocol = url.substr(0, colon);
    265         switch (protocol) {
    266           case 'http':
    267           case 'https':
    268           case 'ftp':
    269           case 'mailto':
    270             return true;
    271           default:
    272             return false;
    273         }
    274       }
    275 
    276       var annotations = this.annotations || [];
    277       var i, n = annotations.length;
    278       var items = [];
    279       for (i = 0; i < n; ++i) {
    280         var annotationRef = annotations[i];
    281         var annotation = xref.fetch(annotationRef);
    282         if (!isDict(annotation))
    283           continue;
    284         var subtype = annotation.get('Subtype');
    285         if (!isName(subtype))
    286           continue;
    287         var rect = annotation.get('Rect');
    288 
    289         var item = {};
    290         item.type = subtype.name;
    291         item.rect = rect;
    292         switch (subtype.name) {
    293           case 'Link':
    294             var a = annotation.get('A');
    295             if (a) {
    296               switch (a.get('S').name) {
    297                 case 'URI':
    298                   var url = a.get('URI');
    299                   // TODO: pdf spec mentions urls can be relative to a Base
    300                   // entry in the dictionary.
    301                   if (!isValidUrl(url))
    302                     url = '';
    303                   item.url = url;
    304                   break;
    305                 case 'GoTo':
    306                   item.dest = a.get('D');
    307                   break;
    308                 case 'GoToR':
    309                   var url = a.get('F');
    310                   if (isDict(url)) {
    311                     // We assume that the 'url' is a Filspec dictionary
    312                     // and fetch the url without checking any further
    313                     url = url.get('F') || '';
    314                   }
    315 
    316                   // TODO: pdf reference says that GoToR
    317                   // can also have 'NewWindow' attribute
    318                   if (!isValidUrl(url))
    319                     url = '';
    320                   item.url = url;
    321                   item.dest = a.get('D');
    322                   break;
    323                 default:
    324                   TODO('unrecognized link type: ' + a.get('S').name);
    325               }
    326             } else if (annotation.has('Dest')) {
    327               // simple destination link
    328               var dest = annotation.get('Dest');
    329               item.dest = isName(dest) ? dest.name : dest;
    330             }
    331             break;
    332           case 'Widget':
    333             var fieldType = getInheritableProperty(annotation, 'FT');
    334             if (!isName(fieldType))
    335               break;
    336             item.fieldType = fieldType.name;
    337             // Building the full field name by collecting the field and
    338             // its ancestors 'T' properties and joining them using '.'.
    339             var fieldName = [];
    340             var namedItem = annotation, ref = annotationRef;
    341             while (namedItem) {
    342               var parent = namedItem.get('Parent');
    343               var parentRef = namedItem.getRaw('Parent');
    344               var name = namedItem.get('T');
    345               if (name) {
    346                 fieldName.unshift(stringToPDFString(name));
    347               } else {
    348                 // The field name is absent, that means more than one field
    349                 // with the same name may exist. Replacing the empty name
    350                 // with the '`' plus index in the parent's 'Kids' array.
    351                 // This is not in the PDF spec but necessary to id the
    352                 // the input controls.
    353                 var kids = parent.get('Kids');
    354                 var j, jj;
    355                 for (j = 0, jj = kids.length; j < jj; j++) {
    356                   var kidRef = kids[j];
    357                   if (kidRef.num == ref.num && kidRef.gen == ref.gen)
    358                     break;
    359                 }
    360                 fieldName.unshift('`' + j);
    361               }
    362               namedItem = parent;
    363               ref = parentRef;
    364             }
    365             item.fullName = fieldName.join('.');
    366             var alternativeText = stringToPDFString(annotation.get('TU') || '');
    367             item.alternativeText = alternativeText;
    368             var da = getInheritableProperty(annotation, 'DA') || '';
    369             var m = /([\d\.]+)\sTf/.exec(da);
    370             if (m)
    371               item.fontSize = parseFloat(m[1]);
    372             item.textAlignment = getInheritableProperty(annotation, 'Q');
    373             item.flags = getInheritableProperty(annotation, 'Ff') || 0;
    374             break;
    375           case 'Text':
    376             var content = annotation.get('Contents');
    377             var title = annotation.get('T');
    378             item.content = stringToPDFString(content || '');
    379             item.title = stringToPDFString(title || '');
    380             item.name = !annotation.has('Name') ? 'Note' :
    381               annotation.get('Name').name;
    382             break;
    383           default:
    384             TODO('unimplemented annotation type: ' + subtype.name);
    385             break;
    386         }
    387         items.push(item);
    388       }
    389       return items;
     1137      }
     1138      return shadow(this, 'annotations', annotations);
    3901139    }
    3911140  };
     
    4021151 */
    4031152var PDFDocument = (function PDFDocumentClosure() {
    404   function PDFDocument(arg, password) {
     1153  function PDFDocument(pdfManager, arg, password) {
    4051154    if (isStream(arg))
    406       init.call(this, arg, password);
     1155      init.call(this, pdfManager, arg, password);
    4071156    else if (isArrayBuffer(arg))
    408       init.call(this, new Stream(arg), password);
     1157      init.call(this, pdfManager, new Stream(arg), password);
    4091158    else
    4101159      error('PDFDocument: Unknown argument type');
    4111160  }
    4121161
    413   function init(stream, password) {
     1162  function init(pdfManager, stream, password) {
    4141163    assertWellFormed(stream.length > 0, 'stream must have data');
     1164    this.pdfManager = pdfManager;
    4151165    this.stream = stream;
    416     this.setup(password);
    417     this.acroForm = this.catalog.catDict.get('AcroForm');
     1166    var xref = new XRef(this.stream, password, pdfManager);
     1167    this.xref = xref;
    4181168  }
    4191169
     
    4531203
    4541204  PDFDocument.prototype = {
     1205    parse: function PDFDocument_parse(recoveryMode) {
     1206      this.setup(recoveryMode);
     1207      this.acroForm = this.catalog.catDict.get('AcroForm');
     1208    },
     1209
    4551210    get linearization() {
    4561211      var length = this.stream.length;
     
    4591214        try {
    4601215          linearization = new Linearization(this.stream);
    461           if (linearization.length != length)
     1216          if (linearization.length != length) {
    4621217            linearization = false;
     1218          }
    4631219        } catch (err) {
    464           warn('The linearization data is not available ' +
    465                'or unreadable pdf data is found');
     1220          if (err instanceof MissingDataException) {
     1221            throw err;
     1222          }
     1223
     1224          info('The linearization data is not available ' +
     1225               'or unreadable PDF data is found');
    4661226          linearization = false;
    4671227        }
     
    5401300      // May not be a PDF file, continue anyway.
    5411301    },
    542     setup: function PDFDocument_setup(password) {
    543       this.checkHeader();
    544       var xref = new XRef(this.stream,
    545                           this.startXRef,
    546                           this.mainXRefEntriesOffset,
    547                           password);
    548       this.xref = xref;
    549       this.catalog = new Catalog(xref);
     1302    parseStartXRef: function PDFDocument_parseStartXRef() {
     1303      var startXRef = this.startXRef;
     1304      this.xref.setStartXRef(startXRef);
     1305    },
     1306    setup: function PDFDocument_setup(recoveryMode) {
     1307      this.xref.parse(recoveryMode);
     1308      this.catalog = new Catalog(this.pdfManager, this.xref);
    5501309    },
    5511310    get numPages() {
     
    5551314      return shadow(this, 'numPages', num);
    5561315    },
    557     getDocumentInfo: function PDFDocument_getDocumentInfo() {
     1316    get documentInfo() {
    5581317      var docInfo = {
    559         PDFFormatVersion: this.pdfFormatVersion
     1318        PDFFormatVersion: this.pdfFormatVersion,
     1319        IsAcroFormPresent: !!this.acroForm
    5601320      };
    5611321      if (this.xref.trailer.has('Info')) {
     
    5771337        }
    5781338      }
    579       return shadow(this, 'getDocumentInfo', docInfo);
    580     },
    581     getFingerprint: function PDFDocument_getFingerprint() {
     1339      return shadow(this, 'documentInfo', docInfo);
     1340    },
     1341    get fingerprint() {
    5821342      var xref = this.xref, fileID;
    5831343      if (xref.trailer.has('ID')) {
     
    5981358      }
    5991359
    600       return shadow(this, 'getFingerprint', fileID);
    601     },
    602     getPage: function PDFDocument_getPage(n) {
    603       return this.catalog.getPage(n);
     1360      return shadow(this, 'fingerprint', fileID);
     1361    },
     1362
     1363    traversePages: function PDFDocument_traversePages() {
     1364      this.catalog.traversePages();
     1365    },
     1366
     1367    getPage: function PDFDocument_getPage(pageIndex) {
     1368      return this.catalog.getPage(pageIndex);
    6041369    }
    6051370  };
     
    7301495}
    7311496
     1497var PasswordResponses = PDFJS.PasswordResponses = {
     1498  NEED_PASSWORD: 1,
     1499  INCORRECT_PASSWORD: 2
     1500};
     1501
    7321502var PasswordException = (function PasswordExceptionClosure() {
    7331503  function PasswordException(msg, code) {
     
    7791549  return MissingPDFException;
    7801550})();
     1551
     1552var NotImplementedException = (function NotImplementedExceptionClosure() {
     1553  function NotImplementedException(msg) {
     1554    this.message = msg;
     1555  }
     1556
     1557  NotImplementedException.prototype = new Error();
     1558  NotImplementedException.prototype.name = 'NotImplementedException';
     1559  NotImplementedException.constructor = NotImplementedException;
     1560
     1561  return NotImplementedException;
     1562})();
     1563
     1564var MissingDataException = (function MissingDataExceptionClosure() {
     1565  function MissingDataException(begin, end) {
     1566    this.begin = begin;
     1567    this.end = end;
     1568    this.message = 'Missing data [begin, end)';
     1569  }
     1570
     1571  MissingDataException.prototype = new Error();
     1572  MissingDataException.prototype.name = 'MissingDataException';
     1573  MissingDataException.constructor = MissingDataException;
     1574
     1575  return MissingDataException;
     1576})();
     1577
     1578var XRefParseException = (function XRefParseExceptionClosure() {
     1579  function XRefParseException(msg) {
     1580    this.message = msg;
     1581  }
     1582
     1583  XRefParseException.prototype = new Error();
     1584  XRefParseException.prototype.name = 'XRefParseException';
     1585  XRefParseException.constructor = XRefParseException;
     1586
     1587  return XRefParseException;
     1588})();
     1589
    7811590
    7821591function bytesToString(bytes) {
     
    8141623  };
    8151624
     1625  // Concatenates two transformation matrices together and returns the result.
     1626  Util.transform = function Util_transform(m1, m2) {
     1627    return [
     1628      m1[0] * m2[0] + m1[2] * m2[1],
     1629      m1[1] * m2[0] + m1[3] * m2[1],
     1630      m1[0] * m2[2] + m1[2] * m2[3],
     1631      m1[1] * m2[2] + m1[3] * m2[3],
     1632      m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
     1633      m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
     1634    ];
     1635  };
     1636
    8161637  // For 2d affine transforms
    8171638  Util.applyTransform = function Util_applyTransform(p, m) {
     
    8261647    var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
    8271648    return [xt, yt];
     1649  };
     1650
     1651  // Applies the transform to the rectangle and finds the minimum axially
     1652  // aligned bounding box.
     1653  Util.getAxialAlignedBoundingBox =
     1654    function Util_getAxialAlignedBoundingBox(r, m) {
     1655
     1656    var p1 = Util.applyTransform(r, m);
     1657    var p2 = Util.applyTransform(r.slice(2, 4), m);
     1658    var p3 = Util.applyTransform([r[0], r[3]], m);
     1659    var p4 = Util.applyTransform([r[2], r[1]], m);
     1660    return [
     1661      Math.min(p1[0], p2[0], p3[0], p4[0]),
     1662      Math.min(p1[1], p2[1], p3[1], p4[1]),
     1663      Math.max(p1[0], p2[0], p3[0], p4[0]),
     1664      Math.max(p1[1], p2[1], p3[1], p4[1])
     1665    ];
    8281666  };
    8291667
     
    8461684      m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
    8471685    ];
    848   }
     1686  };
     1687
     1688  // This calculation uses Singular Value Decomposition.
     1689  // The SVD can be represented with formula A = USV. We are interested in the
     1690  // matrix S here because it represents the scale values.
     1691  Util.singularValueDecompose2dScale =
     1692    function Util_singularValueDecompose2dScale(m) {
     1693
     1694    var transpose = [m[0], m[2], m[1], m[3]];
     1695
     1696    // Multiply matrix m with its transpose.
     1697    var a = m[0] * transpose[0] + m[1] * transpose[2];
     1698    var b = m[0] * transpose[1] + m[1] * transpose[3];
     1699    var c = m[2] * transpose[0] + m[3] * transpose[2];
     1700    var d = m[2] * transpose[1] + m[3] * transpose[3];
     1701
     1702    // Solve the second degree polynomial to get roots.
     1703    var first = (a + d) / 2;
     1704    var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
     1705    var sx = first + second || 1;
     1706    var sy = first - second || 1;
     1707
     1708    // Scale values are the square roots of the eigenvalues.
     1709    return [Math.sqrt(sx), Math.sqrt(sy)];
     1710  };
    8491711
    8501712  // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
     
    8631725    }
    8641726    return r;
    865   }
     1727  };
    8661728
    8671729  // Returns a rectangle [x1, y1, x2, y2] corresponding to the
     
    8711733    function compare(a, b) {
    8721734      return a - b;
    873     };
     1735    }
    8741736
    8751737    // Order points along the axes
     
    9081770  };
    9091771
     1772  // TODO(mack): Rename appendToArray
     1773  Util.concatenateToArray = function concatenateToArray(arr1, arr2) {
     1774    Array.prototype.push.apply(arr1, arr2);
     1775  };
     1776
     1777  Util.prependToArray = function concatenateToArray(arr1, arr2) {
     1778    Array.prototype.unshift.apply(arr1, arr2);
     1779  };
     1780
     1781  Util.extendObj = function extendObj(obj1, obj2) {
     1782    for (var key in obj2) {
     1783      obj1[key] = obj2[key];
     1784    }
     1785  };
     1786
     1787  Util.getInheritableProperty = function Util_getInheritableProperty(dict,
     1788                                                                     name) {
     1789    while (dict && !dict.has(name)) {
     1790      dict = dict.get('Parent');
     1791    }
     1792    if (!dict) {
     1793      return null;
     1794    }
     1795    return dict.get(name);
     1796  };
     1797
     1798  Util.inherit = function Util_inherit(sub, base, prototype) {
     1799    sub.prototype = Object.create(base.prototype);
     1800    sub.prototype.constructor = sub;
     1801    for (var prop in prototype) {
     1802      sub.prototype[prop] = prototype[prop];
     1803    }
     1804  };
     1805
    9101806  return Util;
    9111807})();
    9121808
    9131809var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
    914   function PageViewport(viewBox, scale, rotate, offsetX, offsetY) {
     1810  function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
     1811    this.viewBox = viewBox;
     1812    this.scale = scale;
     1813    this.rotation = rotation;
     1814    this.offsetX = offsetX;
     1815    this.offsetY = offsetY;
     1816
    9151817    // creating transform to convert pdf coordinate system to the normal
    9161818    // canvas like coordinates taking in account scale and rotation
     
    9181820    var centerY = (viewBox[3] + viewBox[1]) / 2;
    9191821    var rotateA, rotateB, rotateC, rotateD;
    920     switch (rotate % 360) {
    921       case -180:
     1822    rotation = rotation % 360;
     1823    rotation = rotation < 0 ? rotation + 360 : rotation;
     1824    switch (rotation) {
    9221825      case 180:
    9231826        rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
    9241827        break;
    925       case -270:
    9261828      case 90:
    9271829        rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
    9281830        break;
    929       case -90:
    9301831      case 270:
    9311832        rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
    9321833        break;
    933       case 360:
    934       case 0:
     1834      //case 0:
    9351835      default:
    9361836        rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
    9371837        break;
    9381838    }
     1839
     1840    if (dontFlip) {
     1841      rotateC = -rotateC; rotateD = -rotateD;
     1842    }
     1843
    9391844    var offsetCanvasX, offsetCanvasY;
    9401845    var width, height;
    941     if (rotateA == 0) {
     1846    if (rotateA === 0) {
    9421847      offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
    9431848      offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
     
    9621867    ];
    9631868
    964     this.offsetX = offsetX;
    965     this.offsetY = offsetY;
    9661869    this.width = width;
    9671870    this.height = height;
     
    9691872  }
    9701873  PageViewport.prototype = {
     1874    clone: function PageViewPort_clone(args) {
     1875      args = args || {};
     1876      var scale = 'scale' in args ? args.scale : this.scale;
     1877      var rotation = 'rotation' in args ? args.rotation : this.rotation;
     1878      return new PageViewport(this.viewBox.slice(), scale, rotation,
     1879                              this.offsetX, this.offsetY, args.dontFlip);
     1880    },
    9711881    convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
    9721882      return Util.applyTransform([x, y], this.transform);
     
    10171927}
    10181928
     1929function isEmptyObj(obj) {
     1930  for (var key in obj) {
     1931    return false;
     1932  }
     1933  return true;
     1934}
     1935
    10191936function isBool(v) {
    10201937  return typeof v == 'boolean';
     
    10611978
    10621979function isStream(v) {
    1063   return typeof v == 'object' && v != null && ('getChar' in v);
     1980  return typeof v == 'object' && v !== null && v !== undefined &&
     1981         ('getChar' in v);
    10641982}
    10651983
    10661984function isArrayBuffer(v) {
    1067   return typeof v == 'object' && v != null && ('byteLength' in v);
     1985  return typeof v == 'object' && v !== null && v !== undefined &&
     1986         ('byteLength' in v);
    10681987}
    10691988
     
    10862005
    10872006/**
    1088  * 'Promise' object.
    1089  * Each object that is stored in PDFObjects is based on a Promise object that
    1090  * contains the status of the object and the data. There migth be situations,
    1091  * where a function want to use the value of an object, but it isn't ready at
    1092  * that time. To get a notification, once the object is ready to be used, s.o.
    1093  * can add a callback using the `then` method on the promise that then calls
    1094  * the callback once the object gets resolved.
    1095  * A promise can get resolved only once and only once the data of the promise
    1096  * can be set. If any of these happens twice or the data is required before
    1097  * it was set, an exception is throw.
     2007 * The following promise implementation tries to generally implment the
     2008 * Promise/A+ spec. Some notable differences from other promise libaries are:
     2009 * - There currently isn't a seperate deferred and promise object.
     2010 * - Unhandled rejections eventually show an error if they aren't handled.
     2011 *
     2012 * Based off of the work in:
     2013 * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
    10982014 */
    10992015var Promise = PDFJS.Promise = (function PromiseClosure() {
    1100   var EMPTY_PROMISE = {};
    1101 
    1102   /**
    1103    * If `data` is passed in this constructor, the promise is created resolved.
    1104    * If there isn't data, it isn't resolved at the beginning.
    1105    */
    1106   function Promise(name, data) {
    1107     this.name = name;
    1108     this.isRejected = false;
    1109     this.error = null;
    1110     this.exception = null;
    1111     // If you build a promise and pass in some data it's already resolved.
    1112     if (data != null) {
    1113       this.isResolved = true;
    1114       this._data = data;
    1115       this.hasData = true;
    1116     } else {
    1117       this.isResolved = false;
    1118       this._data = EMPTY_PROMISE;
     2016  var STATUS_PENDING = 0;
     2017  var STATUS_RESOLVED = 1;
     2018  var STATUS_REJECTED = 2;
     2019
     2020  // In an attempt to avoid silent exceptions, unhandled rejections are
     2021  // tracked and if they aren't handled in a certain amount of time an
     2022  // error is logged.
     2023  var REJECTION_TIMEOUT = 500;
     2024
     2025  var HandlerManager = {
     2026    handlers: [],
     2027    running: false,
     2028    unhandledRejections: [],
     2029    pendingRejectionCheck: false,
     2030
     2031    scheduleHandlers: function scheduleHandlers(promise) {
     2032      if (promise._status == STATUS_PENDING) {
     2033        return;
     2034      }
     2035
     2036      this.handlers = this.handlers.concat(promise._handlers);
     2037      promise._handlers = [];
     2038
     2039      if (this.running) {
     2040        return;
     2041      }
     2042      this.running = true;
     2043
     2044      setTimeout(this.runHandlers.bind(this), 0);
     2045    },
     2046
     2047    runHandlers: function runHandlers() {
     2048      while (this.handlers.length > 0) {
     2049        var handler = this.handlers.shift();
     2050
     2051        var nextStatus = handler.thisPromise._status;
     2052        var nextValue = handler.thisPromise._value;
     2053
     2054        try {
     2055          if (nextStatus === STATUS_RESOLVED) {
     2056            if (typeof(handler.onResolve) == 'function') {
     2057              nextValue = handler.onResolve(nextValue);
     2058            }
     2059          } else if (typeof(handler.onReject) === 'function') {
     2060              nextValue = handler.onReject(nextValue);
     2061              nextStatus = STATUS_RESOLVED;
     2062
     2063              if (handler.thisPromise._unhandledRejection) {
     2064                this.removeUnhandeledRejection(handler.thisPromise);
     2065              }
     2066          }
     2067        } catch (ex) {
     2068          nextStatus = STATUS_REJECTED;
     2069          nextValue = ex;
     2070        }
     2071
     2072        handler.nextPromise._updateStatus(nextStatus, nextValue);
     2073      }
     2074
     2075      this.running = false;
     2076    },
     2077
     2078    addUnhandledRejection: function addUnhandledRejection(promise) {
     2079      this.unhandledRejections.push({
     2080        promise: promise,
     2081        time: Date.now()
     2082      });
     2083      this.scheduleRejectionCheck();
     2084    },
     2085
     2086    removeUnhandeledRejection: function removeUnhandeledRejection(promise) {
     2087      promise._unhandledRejection = false;
     2088      for (var i = 0; i < this.unhandledRejections.length; i++) {
     2089        if (this.unhandledRejections[i].promise === promise) {
     2090          this.unhandledRejections.splice(i);
     2091          i--;
     2092        }
     2093      }
     2094    },
     2095
     2096    scheduleRejectionCheck: function scheduleRejectionCheck() {
     2097      if (this.pendingRejectionCheck) {
     2098        return;
     2099      }
     2100      this.pendingRejectionCheck = true;
     2101      setTimeout(function rejectionCheck() {
     2102        this.pendingRejectionCheck = false;
     2103        var now = Date.now();
     2104        for (var i = 0; i < this.unhandledRejections.length; i++) {
     2105          if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {
     2106            console.error('Unhandled rejection: ' +
     2107                          this.unhandledRejections[i].promise._value);
     2108            this.unhandledRejections.splice(i);
     2109            i--;
     2110          }
     2111        }
     2112        if (this.unhandledRejections.length) {
     2113          this.scheduleRejectionCheck();
     2114        }
     2115      }.bind(this), REJECTION_TIMEOUT);
    11192116    }
    1120     this.callbacks = [];
    1121     this.errbacks = [];
    1122     this.progressbacks = [];
    11232117  };
     2118
     2119  function Promise() {
     2120    this._status = STATUS_PENDING;
     2121    this._handlers = [];
     2122  }
    11242123  /**
    11252124   * Builds a promise that is resolved when all the passed in promises are
     
    11362135      return deferred;
    11372136    }
     2137    function reject(reason) {
     2138      if (deferred._status === STATUS_REJECTED) {
     2139        return;
     2140      }
     2141      results = [];
     2142      deferred.reject(reason);
     2143    }
    11382144    for (var i = 0, ii = promises.length; i < ii; ++i) {
    11392145      var promise = promises[i];
    11402146      promise.then((function(i) {
    11412147        return function(value) {
     2148          if (deferred._status === STATUS_REJECTED) {
     2149            return;
     2150          }
    11422151          results[i] = value;
    11432152          unresolved--;
     
    11452154            deferred.resolve(results);
    11462155        };
    1147       })(i));
     2156      })(i), reject);
    11482157    }
    11492158    return deferred;
    11502159  };
     2160
    11512161  Promise.prototype = {
    1152     hasData: false,
    1153 
    1154     set data(value) {
    1155       if (value === undefined) {
     2162    _status: null,
     2163    _value: null,
     2164    _handlers: null,
     2165    _unhandledRejection: null,
     2166
     2167    _updateStatus: function Promise__updateStatus(status, value) {
     2168      if (this._status === STATUS_RESOLVED ||
     2169          this._status === STATUS_REJECTED) {
    11562170        return;
    11572171      }
    1158       if (this._data !== EMPTY_PROMISE) {
    1159         error('Promise ' + this.name +
    1160               ': Cannot set the data of a promise twice');
    1161       }
    1162       this._data = value;
    1163       this.hasData = true;
    1164 
    1165       if (this.onDataCallback) {
    1166         this.onDataCallback(value);
    1167       }
    1168     },
    1169 
    1170     get data() {
    1171       if (this._data === EMPTY_PROMISE) {
    1172         error('Promise ' + this.name + ': Cannot get data that isn\'t set');
    1173       }
    1174       return this._data;
    1175     },
    1176 
    1177     onData: function Promise_onData(callback) {
    1178       if (this._data !== EMPTY_PROMISE) {
    1179         callback(this._data);
    1180       } else {
    1181         this.onDataCallback = callback;
    1182       }
    1183     },
    1184 
    1185     resolve: function Promise_resolve(data) {
    1186       if (this.isResolved) {
    1187         error('A Promise can be resolved only once ' + this.name);
    1188       }
    1189       if (this.isRejected) {
    1190         error('The Promise was already rejected ' + this.name);
    1191       }
    1192 
    1193       this.isResolved = true;
    1194       this.data = (typeof data !== 'undefined') ? data : null;
    1195       var callbacks = this.callbacks;
    1196 
    1197       for (var i = 0, ii = callbacks.length; i < ii; i++) {
    1198         callbacks[i].call(null, data);
    1199       }
    1200     },
    1201 
    1202     progress: function Promise_progress(data) {
    1203       var callbacks = this.progressbacks;
    1204       for (var i = 0, ii = callbacks.length; i < ii; i++) {
    1205         callbacks[i].call(null, data);
    1206       }
    1207     },
    1208 
    1209     reject: function Promise_reject(reason, exception) {
    1210       if (this.isRejected) {
    1211         error('A Promise can be rejected only once ' + this.name);
    1212       }
    1213       if (this.isResolved) {
    1214         error('The Promise was already resolved ' + this.name);
    1215       }
    1216 
    1217       this.isRejected = true;
    1218       this.error = reason || null;
    1219       this.exception = exception || null;
    1220       var errbacks = this.errbacks;
    1221 
    1222       for (var i = 0, ii = errbacks.length; i < ii; i++) {
    1223         errbacks[i].call(null, reason, exception);
    1224       }
    1225     },
    1226 
    1227     then: function Promise_then(callback, errback, progressback) {
    1228       if (!callback) {
    1229         error('Requiring callback' + this.name);
    1230       }
    1231 
    1232       // If the promise is already resolved, call the callback directly.
    1233       if (this.isResolved) {
    1234         var data = this.data;
    1235         callback.call(null, data);
    1236       } else if (this.isRejected && errback) {
    1237         var error = this.error;
    1238         var exception = this.exception;
    1239         errback.call(null, error, exception);
    1240       } else {
    1241         this.callbacks.push(callback);
    1242         if (errback)
    1243           this.errbacks.push(errback);
    1244       }
    1245 
    1246       if (progressback)
    1247         this.progressbacks.push(progressback);
     2172
     2173      if (status == STATUS_RESOLVED &&
     2174          value && typeof(value.then) === 'function') {
     2175        value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
     2176                   this._updateStatus.bind(this, STATUS_REJECTED));
     2177        return;
     2178      }
     2179
     2180      this._status = status;
     2181      this._value = value;
     2182
     2183      if (status === STATUS_REJECTED && this._handlers.length === 0) {
     2184        this._unhandledRejection = true;
     2185        HandlerManager.addUnhandledRejection(this);
     2186      }
     2187
     2188      HandlerManager.scheduleHandlers(this);
     2189    },
     2190
     2191    get isResolved() {
     2192      return this._status === STATUS_RESOLVED;
     2193    },
     2194
     2195    get isRejected() {
     2196      return this._status === STATUS_REJECTED;
     2197    },
     2198
     2199    resolve: function Promise_resolve(value) {
     2200      this._updateStatus(STATUS_RESOLVED, value);
     2201    },
     2202
     2203    reject: function Promise_reject(reason) {
     2204      this._updateStatus(STATUS_REJECTED, reason);
     2205    },
     2206
     2207    then: function Promise_then(onResolve, onReject) {
     2208      var nextPromise = new Promise();
     2209      this._handlers.push({
     2210        thisPromise: this,
     2211        onResolve: onResolve,
     2212        onReject: onReject,
     2213        nextPromise: nextPromise
     2214      });
     2215      HandlerManager.scheduleHandlers(this);
     2216      return nextPromise;
    12482217    }
    12492218  };
     
    13292298 *  - password - For decrypting password-protected PDFs.
    13302299 *
     2300 * @param {object} pdfDataRangeTransport is optional. It is used if you want
     2301 * to manually serve range requests for data in the PDF. See viewer.js for
     2302 * an example of pdfDataRangeTransport's interface.
     2303 *
     2304 * @param {function} passwordCallback is optional. It is used to request a
     2305 * password if wrong or no password was provided. The callback receives two
     2306 * parameters: function that needs to be called with new password and reason
     2307 * (see {PasswordResponses}).
     2308 *
    13312309 * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object.
    13322310 */
    1333 PDFJS.getDocument = function getDocument(source) {
     2311PDFJS.getDocument = function getDocument(source,
     2312                                         pdfDataRangeTransport,
     2313                                         passwordCallback,
     2314                                         progressCallback) {
    13342315  var workerInitializedPromise, workerReadyPromise, transport;
    13352316
     
    13582339  workerInitializedPromise = new PDFJS.Promise();
    13592340  workerReadyPromise = new PDFJS.Promise();
    1360   transport = new WorkerTransport(workerInitializedPromise, workerReadyPromise);
     2341  transport = new WorkerTransport(workerInitializedPromise,
     2342      workerReadyPromise, pdfDataRangeTransport, progressCallback);
    13612343  workerInitializedPromise.then(function transportInitialized() {
     2344    transport.passwordCallback = passwordCallback;
    13622345    transport.fetchDocument(params);
    13632346  });
     
    14082391     */
    14092392    getDestinations: function PDFDocumentProxy_getDestinations() {
     2393      return this.transport.getDestinations();
     2394    },
     2395    /**
     2396     * @return {Promise} A promise that is resolved with an array of all the
     2397     * JavaScript strings in the name tree.
     2398     */
     2399    getJavaScript: function PDFDocumentProxy_getDestinations() {
    14102400      var promise = new PDFJS.Promise();
    1411       var destinations = this.pdfInfo.destinations;
    1412       promise.resolve(destinations);
     2401      var js = this.pdfInfo.javaScript;
     2402      promise.resolve(js);
    14132403      return promise;
    14142404    },
     
    14642454      return promise;
    14652455    },
     2456    /**
     2457     * @return {Promise} A promise that is resolved when the document's data
     2458     * is loaded
     2459     */
     2460    dataLoaded: function PDFDocumentProxy_dataLoaded() {
     2461      return this.transport.dataLoaded();
     2462    },
    14662463    destroy: function PDFDocumentProxy_destroy() {
    14672464      this.transport.destroy();
     
    15412538     *   textLayer(optional): An object that has beginLayout, endLayout, and
    15422539     *                        appendText functions.,
     2540     *   imageLayer(optional): An object that has beginLayout, endLayout and
     2541     *                         appendImage functions.,
    15432542     *   continueCallback(optional): A function that will be called each time
    15442543     *                               the rendering is paused.  To continue
     
    15802579        else
    15812580          promise.resolve();
    1582       };
     2581      }
    15832582      var continueCallback = params.continueCallback;
    15842583
     
    15922591
    15932592          var gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
    1594             this.objs, params.textLayer);
     2593            this.objs, params.textLayer, params.imageLayer);
    15952594          try {
    15962595            this.display(gfx, params.viewport, complete, continueCallback);
     
    16152614      this.operatorList = operatorList;
    16162615
    1617       var displayContinuation = function pageDisplayContinuation() {
    1618         // Always defer call to display() to work around bug in
    1619         // Firefox error reporting from XHR callbacks.
    1620         setTimeout(function pageSetTimeout() {
    1621           self.displayReadyPromise.resolve();
    1622         });
    1623       };
    1624 
    16252616      this.ensureFonts(fonts,
    16262617        function pageStartRenderingFromOperatorListEnsureFonts() {
    1627           displayContinuation();
     2618          self.displayReadyPromise.resolve();
    16282619        }
    16292620      );
     
    16662657      stats.time('Rendering');
    16672658
    1668       gfx.beginDrawing(viewport);
     2659      var operatorList = this.operatorList;
     2660      gfx.beginDrawing(viewport, operatorList.transparency);
    16692661
    16702662      var startIdx = 0;
    1671       var length = this.operatorList.fnArray.length;
    1672       var operatorList = this.operatorList;
     2663      var length = operatorList.fnArray.length;
    16732664      var stepper = null;
    16742665      if (PDFJS.pdfBug && 'StepperManager' in globalScope &&
     
    16812672      var continueWrapper;
    16822673      if (continueCallback)
    1683         continueWrapper = function() { continueCallback(next); }
     2674        continueWrapper = function() { continueCallback(next); };
    16842675      else
    16852676        continueWrapper = next;
     
    17442735 */
    17452736var WorkerTransport = (function WorkerTransportClosure() {
    1746   function WorkerTransport(workerInitializedPromise, workerReadyPromise) {
     2737  function WorkerTransport(workerInitializedPromise, workerReadyPromise,
     2738      pdfDataRangeTransport, progressCallback) {
     2739    this.pdfDataRangeTransport = pdfDataRangeTransport;
     2740
    17472741    this.workerReadyPromise = workerReadyPromise;
     2742    this.progressCallback = progressCallback;
    17482743    this.commonObjs = new PDFObjects();
    17492744
     
    17512746    this.pagePromises = [];
    17522747    this.embeddedFontsUsed = false;
     2748
     2749    this.passwordCallback = null;
    17532750
    17542751    // If worker support isn't disabled explicit and the browser has worker
     
    17982795  WorkerTransport.prototype = {
    17992796    destroy: function WorkerTransport_destroy() {
    1800       if (this.worker)
    1801         this.worker.terminate();
    1802 
    18032797      this.pageCache = [];
    18042798      this.pagePromises = [];
     2799      var self = this;
     2800      this.messageHandler.send('Terminate', null, function () {
     2801        if (self.worker) {
     2802          self.worker.terminate();
     2803        }
     2804      });
    18052805    },
    18062806    setupFakeWorker: function WorkerTransport_setupFakeWorker() {
     
    18262826      this.messageHandler = messageHandler;
    18272827
     2828      function updatePassword(password) {
     2829        messageHandler.send('UpdatePassword', password);
     2830      }
     2831
     2832      var pdfDataRangeTransport = this.pdfDataRangeTransport;
     2833      if (pdfDataRangeTransport) {
     2834        pdfDataRangeTransport.addRangeListener(function(begin, chunk) {
     2835          messageHandler.send('OnDataRange', {
     2836            begin: begin,
     2837            chunk: chunk
     2838          });
     2839        });
     2840
     2841        pdfDataRangeTransport.addProgressListener(function(loaded) {
     2842          messageHandler.send('OnDataProgress', {
     2843            loaded: loaded
     2844          });
     2845        });
     2846
     2847        messageHandler.on('RequestDataRange',
     2848          function transportDataRange(data) {
     2849            pdfDataRangeTransport.requestDataRange(data.begin, data.end);
     2850          }, this);
     2851      }
     2852
    18282853      messageHandler.on('GetDoc', function transportDoc(data) {
    18292854        var pdfInfo = data.pdfInfo;
     
    18342859
    18352860      messageHandler.on('NeedPassword', function transportPassword(data) {
     2861        if (this.passwordCallback) {
     2862          return this.passwordCallback(updatePassword,
     2863                                       PasswordResponses.NEED_PASSWORD);
     2864        }
    18362865        this.workerReadyPromise.reject(data.exception.message, data.exception);
    18372866      }, this);
    18382867
    18392868      messageHandler.on('IncorrectPassword', function transportBadPass(data) {
     2869        if (this.passwordCallback) {
     2870          return this.passwordCallback(updatePassword,
     2871                                       PasswordResponses.INCORRECT_PASSWORD);
     2872        }
    18402873        this.workerReadyPromise.reject(data.exception.message, data.exception);
    18412874      }, this);
     
    19292962
    19302963      messageHandler.on('DocProgress', function transportDocProgress(data) {
    1931         this.workerReadyPromise.progress({
     2964        this.progressCallback({
    19322965          loaded: data.loaded,
    19332966          total: data.total
     
    19843017
    19853018    fetchDocument: function WorkerTransport_fetchDocument(source) {
    1986       this.messageHandler.send('GetDocRequest', {source: source});
     3019      source.disableAutoFetch = PDFJS.disableAutoFetch;
     3020      source.chunkedViewerLoading = !!this.pdfDataRangeTransport;
     3021      this.messageHandler.send('GetDocRequest', {
     3022        source: source,
     3023        disableRange: PDFJS.disableRange
     3024      });
    19873025    },
    19883026
     
    19913029        promise.resolve(data);
    19923030      });
     3031    },
     3032
     3033    dataLoaded: function WorkerTransport_dataLoaded() {
     3034      var promise = new PDFJS.Promise();
     3035      this.messageHandler.send('DataLoaded', null, function(args) {
     3036        promise.resolve(args);
     3037      });
     3038      return promise;
    19933039    },
    19943040
     
    20063052      this.messageHandler.send('GetAnnotationsRequest',
    20073053        { pageIndex: pageIndex });
     3054    },
     3055
     3056    getDestinations: function WorkerTransport_getDestinations() {
     3057      var promise = new PDFJS.Promise();
     3058      this.messageHandler.send('GetDestinations', null,
     3059        function transportDestinations(destinations) {
     3060          promise.resolve(destinations);
     3061        }
     3062      );
     3063      return promise;
    20083064    }
    20093065  };
     
    20253081  FILL_STROKE_ADD_TO_PATH: 6,
    20263082  ADD_TO_PATH: 7,
     3083  FILL_STROKE_MASK: 3,
    20273084  ADD_TO_PATH_FLAG: 4
    20283085};
    20293086
    20303087// Minimal font size that would be used during canvas fillText operations.
    2031 var MIN_FONT_SIZE = 1;
     3088var MIN_FONT_SIZE = 16;
     3089
     3090var COMPILE_TYPE3_GLYPHS = true;
    20323091
    20333092function createScratchCanvas(width, height) {
     
    20503109    ctx._originalTranslate = ctx.translate;
    20513110    ctx._originalTransform = ctx.transform;
     3111    ctx._originalSetTransform = ctx.setTransform;
    20523112
    20533113    ctx._transformMatrix = [ctx._scaleX, 0, 0, ctx._scaleY, 0, 0];
     
    21313191    };
    21323192
     3193    ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) {
     3194      this._transformMatrix = [a, b, c, d, e, f];
     3195
     3196      ctx._originalSetTransform(a, b, c, d, e, f);
     3197    };
     3198
    21333199    ctx.rotate = function ctxRotate(angle) {
    21343200      var cosValue = Math.cos(angle);
     
    21483214    };
    21493215  }
     3216}
     3217
     3218var CachedCanvases = (function CachedCanvasesClosure() {
     3219  var cache = {};
     3220  return {
     3221    getCanvas: function CachedCanvases_getCanvas(id, width, height) {
     3222      var canvas;
     3223      if (id in cache) {
     3224        canvas = cache[id];
     3225        canvas.width = width;
     3226        canvas.height = height;
     3227        // reset canvas transform for emulated mozCurrentTransform, if needed
     3228        canvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);
     3229      } else {
     3230        canvas = createScratchCanvas(width, height);
     3231        cache[id] = canvas;
     3232      }
     3233      return canvas;
     3234    },
     3235    clear: function () {
     3236      cache = {};
     3237    }
     3238  };
     3239})();
     3240
     3241function compileType3Glyph(imgData) {
     3242  var POINT_TO_PROCESS_LIMIT = 1000;
     3243
     3244  var width = imgData.width, height = imgData.height;
     3245  var i, j, j0, width1 = width + 1;
     3246  var points = new Uint8Array(width1 * (height + 1));
     3247  var POINT_TYPES =
     3248      new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);
     3249  // finding iteresting points: every point is located between mask pixels,
     3250  // so there will be points of the (width + 1)x(height + 1) grid. Every point
     3251  // will have flags assigned based on neighboring mask pixels:
     3252  //   4 | 8
     3253  //   --P--
     3254  //   2 | 1
     3255  // We are interested only in points with the flags:
     3256  //   - outside corners: 1, 2, 4, 8;
     3257  //   - inside corners: 7, 11, 13, 14;
     3258  //   - and, intersections: 5, 10.
     3259  var pos = 3, data = imgData.data, lineSize = width * 4, count = 0;
     3260  if (data[3] !== 0) {
     3261    points[0] = 1;
     3262    ++count;
     3263  }
     3264  for (j = 1; j < width; j++) {
     3265    if (data[pos] !== data[pos + 4]) {
     3266      points[j] = data[pos] ? 2 : 1;
     3267      ++count;
     3268    }
     3269    pos += 4;
     3270  }
     3271  if (data[pos] !== 0) {
     3272    points[j] = 2;
     3273    ++count;
     3274  }
     3275  pos += 4;
     3276  for (i = 1; i < height; i++) {
     3277    j0 = i * width1;
     3278    if (data[pos - lineSize] !== data[pos]) {
     3279      points[j0] = data[pos] ? 1 : 8;
     3280      ++count;
     3281    }
     3282    // 'sum' is the position of the current pixel configuration in the 'TYPES'
     3283    // array (in order 8-1-2-4, so we can use '>>2' to shift the column).
     3284    var sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0);
     3285    for (j = 1; j < width; j++) {
     3286      sum = (sum >> 2) + (data[pos + 4] ? 4 : 0) +
     3287            (data[pos - lineSize + 4] ? 8 : 0);
     3288      if (POINT_TYPES[sum]) {
     3289        points[j0 + j] = POINT_TYPES[sum];
     3290        ++count;
     3291      }
     3292      pos += 4;
     3293    }
     3294    if (data[pos - lineSize] !== data[pos]) {
     3295      points[j0 + j] = data[pos] ? 2 : 4;
     3296      ++count;
     3297    }
     3298    pos += 4;
     3299
     3300    if (count > POINT_TO_PROCESS_LIMIT) {
     3301      return null;
     3302    }
     3303  }
     3304
     3305  pos -= lineSize;
     3306  j0 = i * width1;
     3307  if (data[pos] !== 0) {
     3308    points[j0] = 8;
     3309    ++count;
     3310  }
     3311  for (j = 1; j < width; j++) {
     3312    if (data[pos] !== data[pos + 4]) {
     3313      points[j0 + j] = data[pos] ? 4 : 8;
     3314      ++count;
     3315    }
     3316    pos += 4;
     3317  }
     3318  if (data[pos] !== 0) {
     3319    points[j0 + j] = 4;
     3320    ++count;
     3321  }
     3322  if (count > POINT_TO_PROCESS_LIMIT) {
     3323    return null;
     3324  }
     3325
     3326  // building outlines
     3327  var steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);
     3328  var outlines = [];
     3329  for (i = 0; count && i <= height; i++) {
     3330    var p = i * width1;
     3331    var end = p + width;
     3332    while (p < end && !points[p]) {
     3333      p++;
     3334    }
     3335    if (p === end) {
     3336      continue;
     3337    }
     3338    var coords = [p % width1, i];
     3339
     3340    var type = points[p], p0 = p, pp;
     3341    do {
     3342      var step = steps[type];
     3343      do { p += step; } while (!points[p]);
     3344     
     3345      pp = points[p];
     3346      if (pp !== 5 && pp !== 10) {
     3347        // set new direction
     3348        type = pp;
     3349        // delete mark
     3350        points[p] = 0;
     3351      } else { // type is 5 or 10, ie, a crossing
     3352        // set new direction
     3353        type = pp & ((0x33 * type) >> 4);
     3354        // set new type for "future hit"
     3355        points[p] &= (type >> 2 | type << 2);
     3356      }
     3357
     3358      coords.push(p % width1);
     3359      coords.push((p / width1) | 0);
     3360      --count;
     3361    } while (p0 !== p);
     3362    outlines.push(coords);
     3363    --i;
     3364  }
     3365
     3366  var drawOutline = function(c) {
     3367    c.save();
     3368    // the path shall be painted in [0..1]x[0..1] space
     3369    c.scale(1 / width, -1 / height);
     3370    c.translate(0, -height);
     3371    c.beginPath();
     3372    for (var i = 0, ii = outlines.length; i < ii; i++) {
     3373      var o = outlines[i];
     3374      c.moveTo(o[0], o[1]);
     3375      for (var j = 2, jj = o.length; j < jj; j += 2) {
     3376        c.lineTo(o[j], o[j+1]);
     3377      }
     3378    }
     3379    c.fill();
     3380    c.beginPath();
     3381    c.restore();
     3382  };
     3383 
     3384  return drawOutline;
    21503385}
    21513386
     
    22073442  var EXECUTION_TIME = 15;
    22083443
    2209   function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer) {
     3444  function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer, imageLayer) {
    22103445    this.ctx = canvasCtx;
    22113446    this.current = new CanvasExtraState();
    22123447    this.stateStack = [];
    22133448    this.pendingClip = null;
     3449    this.pendingEOFill = false;
    22143450    this.res = null;
    22153451    this.xobjs = null;
     
    22173453    this.objs = objs;
    22183454    this.textLayer = textLayer;
     3455    this.imageLayer = imageLayer;
     3456    this.groupStack = [];
     3457    this.processingType3 = null;
    22193458    if (canvasCtx) {
    22203459      addContextCurrentTransform(canvasCtx);
     
    22223461  }
    22233462
    2224   function applyStencilMask(imgArray, width, height, inverseDecode, buffer) {
    2225     var imgArrayPos = 0;
    2226     var i, j, mask, buf;
    2227     // removing making non-masked pixels transparent
    2228     var bufferPos = 3; // alpha component offset
    2229     for (i = 0; i < height; i++) {
    2230       mask = 0;
    2231       for (j = 0; j < width; j++) {
    2232         if (!mask) {
    2233           buf = imgArray[imgArrayPos++];
    2234           mask = 128;
    2235         }
    2236         if (!(buf & mask) == inverseDecode) {
    2237           buffer[bufferPos] = 0;
    2238         }
    2239         bufferPos += 4;
    2240         mask >>= 1;
    2241       }
     3463  function putBinaryImageData(ctx, imgData) {
     3464    if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) {
     3465      ctx.putImageData(imgData, 0, 0);
     3466      return;
    22423467    }
    2243   }
    2244 
    2245   function putBinaryImageData(ctx, data, w, h) {
    2246     var tmpImgData = 'createImageData' in ctx ? ctx.createImageData(w, h) :
    2247       ctx.getImageData(0, 0, w, h);
    2248 
     3468
     3469    var tmpImgData = ctx.createImageData(imgData.width, imgData.height);
     3470
     3471    var data = imgData.data;
    22493472    var tmpImgDataPixels = tmpImgData.data;
    22503473    if ('set' in tmpImgDataPixels)
     
    22593482  }
    22603483
    2261   function prescaleImage(pixels, width, height, widthScale, heightScale) {
    2262     pixels = new Uint8Array(pixels); // creating a copy
    2263     while (widthScale > 2 || heightScale > 2) {
    2264       if (heightScale > 2) {
    2265         // scaling image twice vertically
    2266         var rowSize = width * 4;
    2267         var k = 0, l = 0;
    2268         for (var i = 0; i < height - 1; i += 2) {
    2269           for (var j = 0; j < width; j++) {
    2270             var alpha1 = pixels[k + 3], alpha2 = pixels[k + 3 + rowSize];
    2271             if (alpha1 === alpha2) {
    2272               pixels[l] = (pixels[k] + pixels[k + rowSize]) >> 1;
    2273               pixels[l + 1] = (pixels[k + 1] + pixels[k + 1 + rowSize]) >> 1;
    2274               pixels[l + 2] = (pixels[k + 2] + pixels[k + 2 + rowSize]) >> 1;
    2275               pixels[l + 3] = alpha1;
    2276             } else if (alpha1 < alpha2) {
    2277               var d = 256 - alpha2 + alpha1;
    2278               pixels[l] = (pixels[k] * d + (pixels[k + rowSize] << 8)) >> 9;
    2279               pixels[l + 1] = (pixels[k + 1] * d +
    2280                               (pixels[k + 1 + rowSize] << 8)) >> 9;
    2281               pixels[l + 2] = (pixels[k + 2] * d +
    2282                               (pixels[k + 2 + rowSize] << 8)) >> 9;
    2283               pixels[l + 3] = alpha2;
    2284             } else {
    2285               var d = 256 - alpha1 + alpha2;
    2286               pixels[l] = ((pixels[k] << 8) + pixels[k + rowSize] * d) >> 9;
    2287               pixels[l + 1] = ((pixels[k + 1] << 8) +
    2288                               pixels[k + 1 + rowSize] * d) >> 9;
    2289               pixels[l + 2] = ((pixels[k + 2] << 8) +
    2290                               pixels[k + 2 + rowSize] * d) >> 9;
    2291               pixels[l + 3] = alpha1;
    2292             }
    2293             k += 4; l += 4;
    2294           }
    2295           k += rowSize;
    2296         }
    2297         if (height & 1) {
    2298           for (var i = 0; i < rowSize; i++) {
    2299             pixels[l++] = pixels[k++];
    2300           }
    2301         }
    2302         height = (height + 1) >> 1;
    2303         heightScale /= 2;
    2304       }
    2305       if (widthScale > 2) {
    2306         // scaling image twice horizontally
    2307         var k = 0, l = 0;
    2308         for (var i = 0; i < height; i++) {
    2309           for (var j = 0; j < width - 1; j += 2) {
    2310             var alpha1 = pixels[k + 3], alpha2 = pixels[k + 7];
    2311             if (alpha1 === alpha2) {
    2312               pixels[l] = (pixels[k] + pixels[k + 4]) >> 1;
    2313               pixels[l + 1] = (pixels[k + 1] + pixels[k + 5]) >> 1;
    2314               pixels[l + 2] = (pixels[k + 2] + pixels[k + 6]) >> 1;
    2315               pixels[l + 3] = alpha1;
    2316             } else if (alpha1 < alpha2) {
    2317               var d = 256 - alpha2 + alpha1;
    2318               pixels[l] = (pixels[k] * d + (pixels[k + 4] << 8)) >> 9;
    2319               pixels[l + 1] = (pixels[k + 1] * d + (pixels[k + 5] << 8)) >> 9;
    2320               pixels[l + 2] = (pixels[k + 2] * d + (pixels[k + 6] << 8)) >> 9;
    2321               pixels[l + 3] = alpha2;
    2322             } else {
    2323               var d = 256 - alpha1 + alpha2;
    2324               pixels[l] = ((pixels[k] << 8) + pixels[k + 4] * d) >> 9;
    2325               pixels[l + 1] = ((pixels[k + 1] << 8) + pixels[k + 5] * d) >> 9;
    2326               pixels[l + 2] = ((pixels[k + 2] << 8) + pixels[k + 6] * d) >> 9;
    2327               pixels[l + 3] = alpha1;
    2328             }
    2329             k += 8; l += 4;
    2330           }
    2331           if (width & 1) {
    2332             pixels[l++] = pixels[k++];
    2333             pixels[l++] = pixels[k++];
    2334             pixels[l++] = pixels[k++];
    2335             pixels[l++] = pixels[k++];
    2336           }
    2337         }
    2338         width = (width + 1) >> 1;
    2339         widthScale /= 2;
     3484  function copyCtxState(sourceCtx, destCtx) {
     3485    var properties = ['strokeStyle', 'fillStyle', 'fillRule', 'globalAlpha',
     3486                      'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
     3487                      'globalCompositeOperation', 'font'];
     3488    for (var i = 0, ii = properties.length; i < ii; i++) {
     3489      var property = properties[i];
     3490      if (property in sourceCtx) {
     3491        destCtx[property] = sourceCtx[property];
    23403492      }
    23413493    }
    2342 
    2343     var tmpCanvas = createScratchCanvas(width, height);
    2344     var tmpCtx = tmpCanvas.getContext('2d');
    2345     putBinaryImageData(tmpCtx, pixels.subarray(0, width * height * 4),
    2346                                width, height);
    2347 
    2348     return tmpCanvas;
     3494    if ('setLineDash' in sourceCtx) {
     3495      destCtx.setLineDash(sourceCtx.getLineDash());
     3496      destCtx.lineDashOffset =  sourceCtx.lineDashOffset;
     3497    } else if ('mozDash' in sourceCtx) {
     3498      destCtx.mozDash = sourceCtx.mozDash;
     3499      destCtx.mozDashOffset = sourceCtx.mozDashOffset;
     3500    }
    23493501  }
    23503502
     
    23873539    },
    23883540
    2389     beginDrawing: function CanvasGraphics_beginDrawing(viewport) {
     3541    beginDrawing: function CanvasGraphics_beginDrawing(viewport, transparency) {
     3542      // For pdfs that use blend modes we have to clear the canvas else certain
     3543      // blend modes can look wrong since we'd be blending with a white
     3544      // backdrop. The problem with a transparent backdrop though is we then
     3545      // don't get sub pixel anti aliasing on text, so we fill with white if
     3546      // we can.
     3547      var width = this.ctx.canvas.width;
     3548      var height = this.ctx.canvas.height;
     3549      if (transparency) {
     3550        this.ctx.clearRect(0, 0, width, height);
     3551      } else {
     3552        this.ctx.mozOpaque = true;
     3553        this.ctx.save();
     3554        this.ctx.fillStyle = 'rgb(255, 255, 255)';
     3555        this.ctx.fillRect(0, 0, width, height);
     3556        this.ctx.restore();
     3557      }
     3558
    23903559      var transform = viewport.transform;
    23913560      this.ctx.save();
    23923561      this.ctx.transform.apply(this.ctx, transform);
    23933562
    2394       if (this.textLayer)
     3563      if (this.textLayer) {
    23953564        this.textLayer.beginLayout();
     3565      }
     3566      if (this.imageLayer) {
     3567        this.imageLayer.beginLayout();
     3568      }
    23963569    },
    23973570
     
    24693642    endDrawing: function CanvasGraphics_endDrawing() {
    24703643      this.ctx.restore();
    2471 
    2472       if (this.textLayer)
     3644      CachedCanvases.clear();
     3645
     3646      if (this.textLayer) {
    24733647        this.textLayer.endLayout();
     3648      }
     3649      if (this.imageLayer) {
     3650        this.imageLayer.endLayout();
     3651      }
    24743652    },
    24753653
     
    25453723            this.ctx.globalAlpha = state[1];
    25463724            break;
     3725          case 'BM':
     3726            if (value && value.name && (value.name !== 'Normal')) {
     3727              var mode = value.name.replace(/([A-Z])/g,
     3728                function(c) {
     3729                  return '-' + c.toLowerCase();
     3730                }
     3731              ).substring(1);
     3732              this.ctx.globalCompositeOperation = mode;
     3733              if (this.ctx.globalCompositeOperation !== mode) {
     3734                warn('globalCompositeOperation "' + mode +
     3735                     '" is not supported');
     3736              }
     3737            } else {
     3738              this.ctx.globalCompositeOperation = 'source-over';
     3739            }
     3740            break;
    25473741        }
    25483742      }
     
    25553749    },
    25563750    restore: function CanvasGraphics_restore() {
    2557       if ('textClipLayers' in this) {
    2558         this.completeTextClipping();
    2559       }
    2560 
    25613751      var prev = this.stateStack.pop();
    25623752      if (prev) {
     
    26303820      var ctx = this.ctx;
    26313821      var fillColor = this.current.fillColor;
     3822      var needRestore = false;
    26323823
    26333824      if (fillColor && fillColor.hasOwnProperty('type') &&
     
    26353826        ctx.save();
    26363827        ctx.fillStyle = fillColor.getPattern(ctx);
    2637         ctx.fill();
     3828        needRestore = true;
     3829      }
     3830
     3831      if (this.pendingEOFill) {
     3832        if ('mozFillRule' in this.ctx) {
     3833          this.ctx.mozFillRule = 'evenodd';
     3834          this.ctx.fill();
     3835          this.ctx.mozFillRule = 'nonzero';
     3836        } else {
     3837          try {
     3838            this.ctx.fill('evenodd');
     3839          } catch (ex) {
     3840            // shouldn't really happen, but browsers might think differently
     3841            this.ctx.fill();
     3842          }
     3843        }
     3844        this.pendingEOFill = false;
     3845      } else {
     3846        this.ctx.fill();
     3847      }
     3848
     3849      if (needRestore) {
    26383850        ctx.restore();
    2639       } else {
    2640         ctx.fill();
    2641       }
    2642       if (consumePath)
     3851      }
     3852      if (consumePath) {
    26433853        this.consumePath();
     3854      }
    26443855    },
    26453856    eoFill: function CanvasGraphics_eoFill() {
    2646       var savedFillRule = this.setEOFillRule();
     3857      this.pendingEOFill = true;
    26473858      this.fill();
    2648       this.restoreFillRule(savedFillRule);
    26493859    },
    26503860    fillStroke: function CanvasGraphics_fillStroke() {
     
    26553865    },
    26563866    eoFillStroke: function CanvasGraphics_eoFillStroke() {
    2657       var savedFillRule = this.setEOFillRule();
     3867      this.pendingEOFill = true;
    26583868      this.fillStroke();
    2659       this.restoreFillRule(savedFillRule);
    26603869    },
    26613870    closeFillStroke: function CanvasGraphics_closeFillStroke() {
     
    26643873    },
    26653874    closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() {
    2666       var savedFillRule = this.setEOFillRule();
     3875      this.pendingEOFill = true;
    26673876      this.closePath();
    26683877      this.fillStroke();
    2669       this.restoreFillRule(savedFillRule);
    26703878    },
    26713879    endPath: function CanvasGraphics_endPath() {
     
    26883896    },
    26893897    endText: function CanvasGraphics_endText() {
    2690       if ('textClipLayers' in this) {
    2691         this.swapImageForTextClipping();
    2692       }
    2693     },
    2694     getCurrentTextClipping: function CanvasGraphics_getCurrentTextClipping() {
     3898      if (!('pendingTextPaths' in this)) {
     3899        this.ctx.beginPath();
     3900        return;
     3901      }
     3902      var paths = this.pendingTextPaths;
    26953903      var ctx = this.ctx;
    2696       var transform = ctx.mozCurrentTransform;
    2697       if ('textClipLayers' in this) {
    2698         // we need to reset only font and transform
    2699         var maskCtx = this.textClipLayers.maskCtx;
    2700         maskCtx.setTransform.apply(maskCtx, transform);
    2701         maskCtx.font = ctx.font;
    2702         return maskCtx;
    2703       }
    2704 
    2705       var canvasWidth = ctx.canvas.width;
    2706       var canvasHeight = ctx.canvas.height;
    2707       // keeping track of the text clipping of the separate canvas
    2708       var maskCanvas = createScratchCanvas(canvasWidth, canvasHeight);
    2709       var maskCtx = maskCanvas.getContext('2d');
    2710       maskCtx.setTransform.apply(maskCtx, transform);
    2711       maskCtx.font = ctx.font;
    2712       var textClipLayers = {
    2713         maskCanvas: maskCanvas,
    2714         maskCtx: maskCtx
    2715       };
    2716       this.textClipLayers = textClipLayers;
    2717       return maskCtx;
    2718     },
    2719     swapImageForTextClipping:
    2720       function CanvasGraphics_swapImageForTextClipping() {
    2721       var ctx = this.ctx;
    2722       var canvasWidth = ctx.canvas.width;
    2723       var canvasHeight = ctx.canvas.height;
    2724       // saving current image content and clearing whole canvas
     3904
    27253905      ctx.save();
    2726       ctx.setTransform(1, 0, 0, 1, 0, 0);
    2727       var data = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
    2728       this.textClipLayers.imageData = data;
    2729       ctx.clearRect(0, 0, canvasWidth, canvasHeight);
     3906      ctx.beginPath();
     3907      for (var i = 0; i < paths.length; i++) {
     3908        var path = paths[i];
     3909        ctx.setTransform.apply(ctx, path.transform);
     3910        ctx.translate(path.x, path.y);
     3911        path.addToPath(ctx, path.fontSize);
     3912      }
    27303913      ctx.restore();
    2731     },
    2732     completeTextClipping: function CanvasGraphics_completeTextClipping() {
    2733       var ctx = this.ctx;
    2734       // applying mask to the image (result is saved in maskCanvas)
    2735       var maskCtx = this.textClipLayers.maskCtx;
    2736       maskCtx.setTransform(1, 0, 0, 1, 0, 0);
    2737       maskCtx.globalCompositeOperation = 'source-in';
    2738       maskCtx.drawImage(ctx.canvas, 0, 0);
    2739 
    2740       // restoring image data and applying the result of masked drawing
    2741       ctx.save();
    2742       ctx.setTransform(1, 0, 0, 1, 0, 0);
    2743       ctx.putImageData(this.textClipLayers.imageData, 0, 0);
    2744       ctx.drawImage(this.textClipLayers.maskCanvas, 0, 0);
    2745       ctx.restore();
    2746 
    2747       delete this.textClipLayers;
     3914      ctx.clip();
     3915      ctx.beginPath();
     3916      delete this.pendingTextPaths;
    27483917    },
    27493918    setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {
     
    28614030      geometry.fontSize = this.current.fontSize;
    28624031      return geometry;
     4032    },
     4033
     4034    paintChar: function (character, x, y) {
     4035      var ctx = this.ctx;
     4036      var current = this.current;
     4037      var font = current.font;
     4038      var fontSize = current.fontSize / current.fontSizeScale;
     4039      var textRenderingMode = current.textRenderingMode;
     4040      var fillStrokeMode = textRenderingMode &
     4041        TextRenderingMode.FILL_STROKE_MASK;
     4042      var isAddToPathSet = !!(textRenderingMode &
     4043        TextRenderingMode.ADD_TO_PATH_FLAG);
     4044
     4045      var addToPath;
     4046      if (font.disableFontFace || isAddToPathSet) {
     4047        addToPath = font.renderer.getPathGenerator(character);
     4048      }
     4049
     4050      if (font.disableFontFace) {
     4051        ctx.save();
     4052        ctx.translate(x, y);
     4053        ctx.beginPath();
     4054        addToPath(ctx, fontSize);
     4055        if (fillStrokeMode === TextRenderingMode.FILL ||
     4056            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
     4057          ctx.fill();
     4058        }
     4059        if (fillStrokeMode === TextRenderingMode.STROKE ||
     4060            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
     4061          ctx.stroke();
     4062        }
     4063        ctx.restore();
     4064      } else {
     4065        if (fillStrokeMode === TextRenderingMode.FILL ||
     4066            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
     4067          ctx.fillText(character, x, y);
     4068        }
     4069        if (fillStrokeMode === TextRenderingMode.STROKE ||
     4070            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
     4071          ctx.strokeText(character, x, y);
     4072        }
     4073      }
     4074
     4075      if (isAddToPathSet) {
     4076        var paths = this.pendingTextPaths || (this.pendingTextPaths = []);
     4077        paths.push({
     4078          transform: ctx.mozCurrentTransform,
     4079          x: x,
     4080          y: y,
     4081          fontSize: fontSize,
     4082          addToPath: addToPath
     4083        });
     4084      }
    28634085    },
    28644086
     
    28784100      var geom;
    28794101      var textSelection = textLayer && !skipTextSelection ? true : false;
    2880       var textRenderingMode = current.textRenderingMode;
    28814102      var canvasWidth = 0.0;
     4103      var vertical = font.vertical;
     4104      var defaultVMetrics = font.defaultVMetrics;
    28824105
    28834106      // Type3 fonts - each glyph is a "mini-PDF"
     
    29054128          }
    29064129
     4130          this.processingType3 = glyph;
    29074131          this.save();
    29084132          ctx.scale(fontSize, fontSize);
     
    29214145        }
    29224146        ctx.restore();
     4147        this.processingType3 = null;
    29234148      } else {
    29244149        ctx.save();
     
    29284153        var a1 = current.textMatrix[0], b1 = current.textMatrix[1];
    29294154        var scale = Math.sqrt(a1 * a1 + b1 * b1);
    2930         if (scale == 0 || lineWidth == 0)
     4155        if (scale === 0 || lineWidth === 0)
    29314156          lineWidth = this.getSinglePixelWidth();
    29324157        else
     
    29524177          }
    29534178
     4179          var restoreNeeded = false;
    29544180          var character = glyph.fontChar;
    2955           var charWidth = glyph.width * fontSize * current.fontMatrix[0] +
     4181          var vmetric = glyph.vmetric || defaultVMetrics;
     4182          if (vertical) {
     4183            var vx = glyph.vmetric ? vmetric[1] : glyph.width * 0.5;
     4184            vx = -vx * fontSize * current.fontMatrix[0];
     4185            var vy = vmetric[2] * fontSize * current.fontMatrix[0];
     4186          }
     4187          var width = vmetric ? -vmetric[0] : glyph.width;
     4188          var charWidth = width * fontSize * current.fontMatrix[0] +
    29564189                          charSpacing * current.fontDirection;
    2957 
     4190          var accent = glyph.accent;
     4191
     4192          var scaledX, scaledY, scaledAccentX, scaledAccentY;
    29584193          if (!glyph.disabled) {
    2959             var scaledX = x / fontSizeScale;
    2960             switch (textRenderingMode) {
    2961               default: // other unsupported rendering modes
    2962               case TextRenderingMode.FILL:
    2963               case TextRenderingMode.FILL_ADD_TO_PATH:
    2964                 ctx.fillText(character, scaledX, 0);
    2965                 break;
    2966               case TextRenderingMode.STROKE:
    2967               case TextRenderingMode.STROKE_ADD_TO_PATH:
    2968                 ctx.strokeText(character, scaledX, 0);
    2969                 break;
    2970               case TextRenderingMode.FILL_STROKE:
    2971               case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
    2972                 ctx.fillText(character, scaledX, 0);
    2973                 ctx.strokeText(character, scaledX, 0);
    2974                 break;
    2975               case TextRenderingMode.INVISIBLE:
    2976               case TextRenderingMode.ADD_TO_PATH:
    2977                 break;
     4194            if (vertical) {
     4195              scaledX = vx / fontSizeScale;
     4196              scaledY = (x + vy) / fontSizeScale;
     4197            } else {
     4198              scaledX = x / fontSizeScale;
     4199              scaledY = 0;
    29784200            }
    2979             if (textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG) {
    2980               var clipCtx = this.getCurrentTextClipping();
    2981               clipCtx.fillText(character, scaledX, 0);
     4201
     4202            if (font.remeasure && width > 0) {
     4203              // some standard fonts may not have the exact width, trying to
     4204              // rescale per character
     4205              var measuredWidth = ctx.measureText(character).width * 1000 /
     4206                current.fontSize * current.fontSizeScale;
     4207              var characterScaleX = width / measuredWidth;
     4208              restoreNeeded = true;
     4209              ctx.save();
     4210              ctx.scale(characterScaleX, 1);
     4211              scaledX /= characterScaleX;
     4212              if (accent) {
     4213                scaledAccentX /= characterScaleX;
     4214              }
     4215            }
     4216
     4217            this.paintChar(character, scaledX, scaledY);
     4218            if (accent) {
     4219              scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
     4220              scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
     4221              this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
    29824222            }
    29834223          }
     
    29864226
    29874227          canvasWidth += charWidth;
     4228
     4229          if (restoreNeeded) {
     4230            ctx.restore();
     4231          }
    29884232        }
    2989         current.x += x * textHScale;
     4233        if (vertical) {
     4234          current.y -= x * textHScale;
     4235        } else {
     4236          current.x += x * textHScale;
     4237        }
    29904238        ctx.restore();
    29914239      }
     
    29934241      if (textSelection) {
    29944242        geom.canvasWidth = canvasWidth;
     4243        if (vertical) {
     4244          var vmetric = font.defaultVMetrics;
     4245          geom.x += vmetric[1] * fontSize * current.fontMatrix[0] /
     4246                    fontSizeScale * geom.hScale;
     4247          geom.y += vmetric[2] * fontSize * current.fontMatrix[0] /
     4248                    fontSizeScale * geom.vScale;
     4249        }
    29954250        this.textLayer.appendText(geom);
    29964251      }
     
    30034258      var font = current.font;
    30044259      var fontSize = current.fontSize;
    3005       var textHScale = current.textHScale * (current.fontMatrix && !font.coded ?
    3006         current.fontMatrix[0] : FONT_IDENTITY_MATRIX[0]) *
    3007         current.fontDirection;
     4260      // TJ array's number is independent from fontMatrix
     4261      var textHScale = current.textHScale * 0.001 * current.fontDirection;
    30084262      var arrLength = arr.length;
    30094263      var textLayer = this.textLayer;
     
    30114265      var canvasWidth = 0.0;
    30124266      var textSelection = textLayer ? true : false;
     4267      var vertical = font.vertical;
     4268      var spacingAccumulator = 0;
    30134269
    30144270      if (textSelection) {
     
    30234279        if (isNum(e)) {
    30244280          var spacingLength = -e * fontSize * textHScale;
    3025           current.x += spacingLength;
     4281          if (vertical) {
     4282            current.y += spacingLength;
     4283          } else {
     4284            current.x += spacingLength;
     4285          }
    30264286
    30274287          if (textSelection)
    3028             canvasWidth += spacingLength;
     4288            spacingAccumulator += spacingLength;
    30294289        } else if (isString(e)) {
    30304290          var shownCanvasWidth = this.showText(e, true);
    30314291
    3032           if (textSelection)
    3033             canvasWidth += shownCanvasWidth;
     4292          if (textSelection) {
     4293            canvasWidth += spacingAccumulator + shownCanvasWidth;
     4294            spacingAccumulator = 0;
     4295          }
    30344296        } else {
    30354297          error('TJ array element ' + e + ' is not string or num');
     
    30394301      if (textSelection) {
    30404302        geom.canvasWidth = canvasWidth;
     4303        if (vertical) {
     4304          var fontSizeScale = current.fontSizeScale;
     4305          var vmetric = font.defaultVMetrics;
     4306          geom.x += vmetric[1] * fontSize * current.fontMatrix[0] /
     4307                    fontSizeScale * geom.hScale;
     4308          geom.y += vmetric[2] * fontSize * current.fontMatrix[0] /
     4309                    fontSizeScale * geom.vScale;
     4310        }
    30414311        this.textLayer.appendText(geom);
    30424312      }
     
    30974367          color = base.getRgb(args, 0);
    30984368        }
    3099         var pattern = new TilingPattern(IR, color, this.ctx, this.objs);
     4369        var pattern = new TilingPattern(IR, color, this.ctx, this.objs,
     4370                                        this.commonObjs);
    31004371      } else if (IR[0] == 'RadialAxial' || IR[0] == 'Dummy') {
    31014372        var pattern = Pattern.shadingFromIR(IR);
     
    32544525    },
    32554526
     4527    beginGroup: function CanvasGraphics_beginGroup(group) {
     4528      this.save();
     4529      var currentCtx = this.ctx;
     4530      // TODO non-isolated groups - according to Rik at adobe non-isolated
     4531      // group results aren't usually that different and they even have tools
     4532      // that ignore this setting. Notes from Rik on implmenting:
     4533      // - When you encounter an transparency group, create a new canvas with
     4534      // the dimensions of the bbox
     4535      // - copy the content from the previous canvas to the new canvas
     4536      // - draw as usual
     4537      // - remove the backdrop alpha:
     4538      // alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha
     4539      // value of your transparency group and 'alphaBackdrop' the alpha of the
     4540      // backdrop
     4541      // - remove background color:
     4542      // colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)
     4543      if (!group.isolated) {
     4544        info('TODO: Support non-isolated groups.');
     4545      }
     4546
     4547      // TODO knockout - supposedly possible with the clever use of compositing
     4548      // modes.
     4549      if (group.knockout) {
     4550        TODO('Support knockout groups.');
     4551      }
     4552
     4553      var currentTransform = currentCtx.mozCurrentTransform;
     4554      if (group.matrix) {
     4555        currentCtx.transform.apply(currentCtx, group.matrix);
     4556      }
     4557      assert(group.bbox, 'Bounding box is required.');
     4558
     4559      // Based on the current transform figure out how big the bounding box
     4560      // will actually be.
     4561      var bounds = Util.getAxialAlignedBoundingBox(
     4562                    group.bbox,
     4563                    currentCtx.mozCurrentTransform);
     4564      // Use ceil in case we're between sizes so we don't create canvas that is
     4565      // too small and make the canvas at least 1x1 pixels.
     4566      var drawnWidth = Math.max(Math.ceil(bounds[2] - bounds[0]), 1);
     4567      var drawnHeight = Math.max(Math.ceil(bounds[3] - bounds[1]), 1);
     4568
     4569      var scratchCanvas = createScratchCanvas(drawnWidth, drawnHeight);
     4570      var groupCtx = scratchCanvas.getContext('2d');
     4571      addContextCurrentTransform(groupCtx);
     4572      // Since we created a new canvas that is just the size of the bounding box
     4573      // we have to translate the group ctx.
     4574      var offsetX = bounds[0];
     4575      var offsetY = bounds[1];
     4576      groupCtx.translate(-offsetX, -offsetY);
     4577      groupCtx.transform.apply(groupCtx, currentTransform);
     4578
     4579      // Setup the current ctx so when the group is popped we draw it the right
     4580      // location.
     4581      currentCtx.setTransform(1, 0, 0, 1, 0, 0);
     4582      currentCtx.translate(offsetX, offsetY);
     4583
     4584      // The transparency group inherits all off the current graphics state
     4585      // except the blend mode, soft mask, and alpha constants.
     4586      copyCtxState(currentCtx, groupCtx);
     4587      this.ctx = groupCtx;
     4588      this.setGState([
     4589        ['SMask', 'None'],
     4590        ['BM', 'Normal'],
     4591        ['ca', 1],
     4592        ['CA', 1]
     4593      ]);
     4594      this.groupStack.push(currentCtx);
     4595    },
     4596
     4597    endGroup: function CanvasGraphics_endGroup(group) {
     4598      var groupCtx = this.ctx;
     4599      this.ctx = this.groupStack.pop();
     4600      // Turn off image smoothing to avoid sub pixel interpolation which can
     4601      // look kind of blurry for some pdfs.
     4602      if ('imageSmoothingEnabled' in this.ctx) {
     4603        this.ctx.imageSmoothingEnabled = false;
     4604      } else {
     4605        this.ctx.mozImageSmoothingEnabled = false;
     4606      }
     4607      this.ctx.drawImage(groupCtx.canvas, 0, 0);
     4608      this.restore();
     4609    },
     4610
     4611    beginAnnotations: function CanvasGraphics_beginAnnotations() {
     4612      this.save();
     4613      this.current = new CanvasExtraState();
     4614    },
     4615
     4616    endAnnotations: function CanvasGraphics_endAnnotations() {
     4617      this.restore();
     4618    },
     4619
     4620    beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform,
     4621                                                             matrix) {
     4622      this.save();
     4623
     4624      if (rect && isArray(rect) && 4 == rect.length) {
     4625        var width = rect[2] - rect[0];
     4626        var height = rect[3] - rect[1];
     4627        this.rectangle(rect[0], rect[1], width, height);
     4628        this.clip();
     4629        this.endPath();
     4630      }
     4631
     4632      this.transform.apply(this, transform);
     4633      this.transform.apply(this, matrix);
     4634    },
     4635
     4636    endAnnotation: function CanvasGraphics_endAnnotation() {
     4637      this.restore();
     4638    },
     4639
    32564640    paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
    32574641      var domImage = this.objs.get(objId);
     
    32684652      ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,
    32694653                    0, -h, w, h);
    3270 
     4654      if (this.imageLayer) {
     4655        var currentTransform = ctx.mozCurrentTransformInverse;
     4656        var position = this.getCanvasPosition(0, 0);
     4657        this.imageLayer.appendImage({
     4658          objId: objId,
     4659          left: position[0],
     4660          top: position[1],
     4661          width: w / currentTransform[0],
     4662          height: h / currentTransform[3]
     4663        });
     4664      }
    32714665      this.restore();
    32724666    },
    32734667
    3274     paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(
    3275                              imgArray, inverseDecode, width, height) {
     4668    paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) {
    32764669      var ctx = this.ctx;
    3277       var tmpCanvas = createScratchCanvas(width, height);
    3278       var tmpCtx = tmpCanvas.getContext('2d');
     4670      var width = img.width, height = img.height;
     4671
     4672      var glyph = this.processingType3;
     4673
     4674      if (COMPILE_TYPE3_GLYPHS && glyph && !('compiled' in glyph)) {
     4675        var MAX_SIZE_TO_COMPILE = 1000;
     4676        if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) {
     4677          glyph.compiled =
     4678            compileType3Glyph({data: img.data, width: width, height: height});
     4679        } else {
     4680          glyph.compiled = null;
     4681        }
     4682      }
     4683
     4684      if (glyph && glyph.compiled) {
     4685        glyph.compiled(ctx);
     4686        return;
     4687      }
     4688
     4689      var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
     4690      var maskCtx = maskCanvas.getContext('2d');
     4691      maskCtx.save();
     4692
     4693      putBinaryImageData(maskCtx, img);
     4694
     4695      maskCtx.globalCompositeOperation = 'source-in';
    32794696
    32804697      var fillColor = this.current.fillColor;
    3281       tmpCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
     4698      maskCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
    32824699                          fillColor.type === 'Pattern') ?
    3283                           fillColor.getPattern(tmpCtx) : fillColor;
    3284       tmpCtx.fillRect(0, 0, width, height);
    3285 
    3286       var imgData = tmpCtx.getImageData(0, 0, width, height);
    3287       var pixels = imgData.data;
    3288 
    3289       applyStencilMask(imgArray, width, height, inverseDecode, pixels);
    3290 
    3291       this.paintInlineImageXObject(imgData);
     4700                          fillColor.getPattern(maskCtx) : fillColor;
     4701      maskCtx.fillRect(0, 0, width, height);
     4702
     4703      maskCtx.restore();
     4704
     4705      this.paintInlineImageXObject(maskCanvas);
    32924706    },
    32934707
     
    32954709      function CanvasGraphics_paintImageMaskXObjectGroup(images) {
    32964710      var ctx = this.ctx;
    3297       var tmpCanvasWidth = 0, tmpCanvasHeight = 0, tmpCanvas, tmpCtx;
     4711
    32984712      for (var i = 0, ii = images.length; i < ii; i++) {
    32994713        var image = images[i];
    3300         var w = image.width, h = image.height;
    3301         if (w > tmpCanvasWidth || h > tmpCanvasHeight) {
    3302           tmpCanvasWidth = Math.max(w, tmpCanvasWidth);
    3303           tmpCanvasHeight = Math.max(h, tmpCanvasHeight);
    3304           tmpCanvas = createScratchCanvas(tmpCanvasWidth, tmpCanvasHeight);
    3305           tmpCtx = tmpCanvas.getContext('2d');
    3306 
    3307           var fillColor = this.current.fillColor;
    3308           tmpCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
    3309                               fillColor.type === 'Pattern') ?
    3310                               fillColor.getPattern(tmpCtx) : fillColor;
    3311         }
    3312         tmpCtx.fillRect(0, 0, w, h);
    3313 
    3314         var imgData = tmpCtx.getImageData(0, 0, w, h);
    3315         var pixels = imgData.data;
    3316 
    3317         applyStencilMask(image.data, w, h, image.inverseDecode, pixels);
    3318 
    3319         tmpCtx.putImageData(imgData, 0, 0);
     4714        var width = image.width, height = image.height;
     4715
     4716        var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
     4717        var maskCtx = maskCanvas.getContext('2d');
     4718        maskCtx.save();
     4719
     4720        putBinaryImageData(maskCtx, image);
     4721
     4722        maskCtx.globalCompositeOperation = 'source-in';
     4723
     4724        var fillColor = this.current.fillColor;
     4725        maskCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
     4726                            fillColor.type === 'Pattern') ?
     4727                            fillColor.getPattern(maskCtx) : fillColor;
     4728        maskCtx.fillRect(0, 0, width, height);
     4729
     4730        maskCtx.restore();
    33204731
    33214732        ctx.save();
    33224733        ctx.transform.apply(ctx, image.transform);
    33234734        ctx.scale(1, -1);
    3324         ctx.drawImage(tmpCanvas, 0, 0, w, h,
     4735        ctx.drawImage(maskCanvas, 0, 0, width, height,
    33254736                      0, -1, 1, 1);
    33264737        ctx.restore();
     
    33414752      var height = imgData.height;
    33424753      var ctx = this.ctx;
     4754
    33434755      this.save();
    33444756      // scale the image to the unit square
     
    33464758
    33474759      var currentTransform = ctx.mozCurrentTransformInverse;
    3348       var widthScale = Math.max(Math.abs(currentTransform[0]), 1);
    3349       var heightScale = Math.max(Math.abs(currentTransform[3]), 1);
    3350       var tmpCanvas = createScratchCanvas(width, height);
    3351       var tmpCtx = tmpCanvas.getContext('2d');
    3352 
    3353       if (widthScale > 2 || heightScale > 2) {
    3354         // canvas does not resize well large images to small -- using simple
    3355         // algorithm to perform pre-scaling
    3356         tmpCanvas = prescaleImage(imgData.data,
    3357                                  width, height,
    3358                                  widthScale, heightScale);
    3359         ctx.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height,
    3360                                  0, -height, width, height);
     4760      var a = currentTransform[0], b = currentTransform[1];
     4761      var widthScale = Math.max(Math.sqrt(a * a + b * b), 1);
     4762      var c = currentTransform[2], d = currentTransform[3];
     4763      var heightScale = Math.max(Math.sqrt(c * c + d * d), 1);
     4764
     4765      var imgToPaint;
     4766      if (imgData instanceof HTMLElement) {
     4767        imgToPaint = imgData;
    33614768      } else {
    3362         if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) {
    3363           tmpCtx.putImageData(imgData, 0, 0);
    3364         } else {
    3365           putBinaryImageData(tmpCtx, imgData.data, width, height);
     4769        var tmpCanvas = CachedCanvases.getCanvas('inlineImage', width, height);
     4770        var tmpCtx = tmpCanvas.getContext('2d');
     4771        putBinaryImageData(tmpCtx, imgData);
     4772        imgToPaint = tmpCanvas;
     4773      }
     4774
     4775      var paintWidth = width, paintHeight = height;
     4776      var tmpCanvasId = 'prescale1';
     4777      // Vertial or horizontal scaling shall not be more than 2 to not loose the
     4778      // pixels during drawImage operation, painting on the temporary canvas(es)
     4779      // that are twice smaller in size
     4780      while ((widthScale > 2 && paintWidth > 1) ||
     4781             (heightScale > 2 && paintHeight > 1)) {
     4782        var newWidth = paintWidth, newHeight = paintHeight;
     4783        if (widthScale > 2 && paintWidth > 1) {
     4784          newWidth = Math.ceil(paintWidth / 2);
     4785          widthScale /= paintWidth / newWidth;
    33664786        }
    3367         ctx.drawImage(tmpCanvas, 0, -height);
     4787        if (heightScale > 2 && paintHeight > 1) {
     4788          newHeight = Math.ceil(paintHeight / 2);
     4789          heightScale /= paintHeight / newHeight;
     4790        }
     4791        var tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId,
     4792                                                 newWidth, newHeight);
     4793        tmpCtx = tmpCanvas.getContext('2d');
     4794        tmpCtx.clearRect(0, 0, newWidth, newHeight);
     4795        tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
     4796                                     0, 0, newWidth, newHeight);
     4797        imgToPaint = tmpCanvas;
     4798        paintWidth = newWidth;
     4799        paintHeight = newHeight;
     4800        tmpCanvasId = tmpCanvasId === 'prescale1' ? 'prescale2' : 'prescale1';
     4801      }
     4802      ctx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
     4803                                0, -height, width, height);
     4804
     4805      if (this.imageLayer) {
     4806        var position = this.getCanvasPosition(0, -height);
     4807        this.imageLayer.appendImage({
     4808          imgData: imgData,
     4809          left: position[0],
     4810          top: position[1],
     4811          width: width / currentTransform[0],
     4812          height: height / currentTransform[3]
     4813        });
    33684814      }
    33694815      this.restore();
     
    33764822      var h = imgData.height;
    33774823
    3378       var tmpCanvas = createScratchCanvas(w, h);
     4824      var tmpCanvas = CachedCanvases.getCanvas('inlineImage', w, h);
    33794825      var tmpCtx = tmpCanvas.getContext('2d');
    3380       putBinaryImageData(tmpCtx, imgData.data, w, h);
     4826      putBinaryImageData(tmpCtx, imgData);
    33814827
    33824828      for (var i = 0, ii = map.length; i < ii; i++) {
     
    33874833        ctx.drawImage(tmpCanvas, entry.x, entry.y, entry.w, entry.h,
    33884834                      0, -1, 1, 1);
     4835        if (this.imageLayer) {
     4836          var position = this.getCanvasPosition(entry.x, entry.y);
     4837          this.imageLayer.appendImage({
     4838            imgData: imgData,
     4839            left: position[0],
     4840            top: position[1],
     4841            width: w,
     4842            height: h
     4843          });
     4844        }
    33894845        ctx.restore();
    33904846      }
     
    34134869
    34144870    beginCompat: function CanvasGraphics_beginCompat() {
    3415       TODO('ignore undefined operators (should we do that anyway?)');
     4871      // TODO ignore undefined operators (should we do that anyway?)
    34164872    },
    34174873    endCompat: function CanvasGraphics_endCompat() {
    3418       TODO('stop ignoring undefined operators');
     4874      // TODO stop ignoring undefined operators
    34194875    },
    34204876
     
    34234879    consumePath: function CanvasGraphics_consumePath() {
    34244880      if (this.pendingClip) {
    3425         var savedFillRule = null;
    3426         if (this.pendingClip == EO_CLIP)
    3427           savedFillRule = this.setEOFillRule();
    3428 
    3429         this.ctx.clip();
    3430 
     4881        if (this.pendingClip == EO_CLIP) {
     4882          if ('mozFillRule' in this.ctx) {
     4883            this.ctx.mozFillRule = 'evenodd';
     4884            this.ctx.clip();
     4885            this.ctx.mozFillRule = 'nonzero';
     4886          } else {
     4887            try {
     4888              this.ctx.clip('evenodd');
     4889            } catch (ex) {
     4890              // shouldn't really happen, but browsers might think differently
     4891              this.ctx.clip();
     4892            }
     4893          }
     4894        } else {
     4895          this.ctx.clip();
     4896        }
    34314897        this.pendingClip = null;
    3432         if (savedFillRule !== null)
    3433           this.restoreFillRule(savedFillRule);
    34344898      }
    34354899      this.ctx.beginPath();
    3436     },
    3437     // We generally keep the canvas context set for
    3438     // nonzero-winding, and just set evenodd for the operations
    3439     // that need them.
    3440     setEOFillRule: function CanvasGraphics_setEOFillRule() {
    3441       var savedFillRule = this.ctx.mozFillRule;
    3442       this.ctx.mozFillRule = 'evenodd';
    3443       return savedFillRule;
    3444     },
    3445     restoreFillRule: function CanvasGraphics_restoreFillRule(rule) {
    3446       this.ctx.mozFillRule = rule;
    34474900    },
    34484901    getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
     
    34524905        (inverse[0] * inverse[0] + inverse[1] * inverse[1]),
    34534906        (inverse[2] * inverse[2] + inverse[3] * inverse[3])));
     4907    },
     4908    getCanvasPosition: function CanvasGraphics_getCanvasPosition(x, y) {
     4909        var transform = this.ctx.mozCurrentTransform;
     4910        return [
     4911          transform[0] * x + transform[2] * y + transform[4],
     4912          transform[1] * x + transform[3] * y + transform[5]
     4913        ];
    34544914    }
    34554915  };
     
    34914951
    34924952var Dict = (function DictClosure() {
     4953  var nonSerializable = function nonSerializableClosure() {
     4954    return nonSerializable; // creating closure on some variable
     4955  };
     4956
    34934957  // xref is optional
    34944958  function Dict(xref) {
    34954959    // Map should only be used internally, use functions below to access.
    3496     var map = Object.create(null);
    3497 
    3498     this.assignXref = function Dict_assignXref(newXref) {
    3499       xref = newXref;
    3500     };
     4960    this.map = Object.create(null);
     4961    this.xref = xref;
     4962    this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict
     4963  }
     4964
     4965  Dict.prototype = {
     4966    assignXref: function Dict_assignXref(newXref) {
     4967      this.xref = newXref;
     4968    },
    35014969
    35024970    // automatically dereferences Ref objects
    3503     this.get = function Dict_get(key1, key2, key3) {
     4971    get: function Dict_get(key1, key2, key3) {
    35044972      var value;
    3505       if (typeof (value = map[key1]) != 'undefined' || key1 in map ||
     4973      var xref = this.xref;
     4974      if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map ||
    35064975          typeof key2 == 'undefined') {
    35074976        return xref ? xref.fetchIfRef(value) : value;
    35084977      }
    3509       if (typeof (value = map[key2]) != 'undefined' || key2 in map ||
     4978      if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map ||
    35104979          typeof key3 == 'undefined') {
    35114980        return xref ? xref.fetchIfRef(value) : value;
    35124981      }
    3513       value = map[key3] || null;
     4982      value = this.map[key3] || null;
    35144983      return xref ? xref.fetchIfRef(value) : value;
    3515     };
     4984    },
     4985
     4986    // Same as get(), but returns a promise and uses fetchIfRefAsync().
     4987    getAsync: function Dict_getAsync(key1, key2, key3) {
     4988      var value;
     4989      var promise;
     4990      var xref = this.xref;
     4991      if (typeof (value = this.map[key1]) !== undefined || key1 in this.map ||
     4992          typeof key2 === undefined) {
     4993        if (xref) {
     4994          return xref.fetchIfRefAsync(value);
     4995        }
     4996        promise = new Promise();
     4997        promise.resolve(value);
     4998        return promise;
     4999      }
     5000      if (typeof (value = this.map[key2]) !== undefined || key2 in this.map ||
     5001          typeof key3 === undefined) {
     5002        if (xref) {
     5003          return xref.fetchIfRefAsync(value);
     5004        }
     5005        promise = new Promise();
     5006        promise.resolve(value);
     5007        return promise;
     5008      }
     5009      value = this.map[key3] || null;
     5010      if (xref) {
     5011        return xref.fetchIfRefAsync(value);
     5012      }
     5013      promise = new Promise();
     5014      promise.resolve(value);
     5015      return promise;
     5016    },
    35165017
    35175018    // no dereferencing
    3518     this.getRaw = function Dict_getRaw(key) {
    3519       return map[key];
    3520     };
     5019    getRaw: function Dict_getRaw(key) {
     5020      return this.map[key];
     5021    },
    35215022
    35225023    // creates new map and dereferences all Refs
    3523     this.getAll = function Dict_getAll() {
     5024    getAll: function Dict_getAll() {
    35245025      var all = {};
    3525       for (var key in map) {
     5026      for (var key in this.map) {
    35265027        var obj = this.get(key);
    35275028        all[key] = obj instanceof Dict ? obj.getAll() : obj;
    35285029      }
    35295030      return all;
    3530     };
    3531 
    3532     this.set = function Dict_set(key, value) {
    3533       map[key] = value;
    3534     };
    3535 
    3536     this.has = function Dict_has(key) {
    3537       return key in map;
    3538     };
    3539 
    3540     this.forEach = function Dict_forEach(callback) {
    3541       for (var key in map) {
     5031    },
     5032
     5033    set: function Dict_set(key, value) {
     5034      this.map[key] = value;
     5035    },
     5036
     5037    has: function Dict_has(key) {
     5038      return key in this.map;
     5039    },
     5040
     5041    forEach: function Dict_forEach(callback) {
     5042      for (var key in this.map) {
    35425043        callback(key, this.get(key));
    35435044      }
    3544     };
     5045    }
    35455046  };
    35465047
     
    35685069  RefSet.prototype = {
    35695070    has: function RefSet_has(ref) {
    3570       return !!this.dict['R' + ref.num + '.' + ref.gen];
     5071      return ('R' + ref.num + '.' + ref.gen) in this.dict;
    35715072    },
    35725073
    35735074    put: function RefSet_put(ref) {
    3574       this.dict['R' + ref.num + '.' + ref.gen] = ref;
     5075      this.dict['R' + ref.num + '.' + ref.gen] = true;
     5076    },
     5077
     5078    remove: function RefSet_remove(ref) {
     5079      delete this.dict['R' + ref.num + '.' + ref.gen];
    35755080    }
    35765081  };
     
    35805085
    35815086var Catalog = (function CatalogClosure() {
    3582   function Catalog(xref) {
     5087  function Catalog(pdfManager, xref) {
     5088    this.pdfManager = pdfManager;
    35835089    this.xref = xref;
    3584     var obj = xref.getCatalogObj();
    3585     assertWellFormed(isDict(obj), 'catalog object is not a dictionary');
    3586     this.catDict = obj;
     5090    this.catDict = xref.getCatalogObj();
     5091    assertWellFormed(isDict(this.catDict),
     5092      'catalog object is not a dictionary');
     5093
     5094    // Stores state as we traverse the pages catalog so that we can resume
     5095    // parsing if an exception is thrown
     5096    this.traversePagesQueue = [{
     5097      pagesDict: this.toplevelPagesDict,
     5098      posInKids: 0
     5099    }];
     5100    this.pagePromises = [];
     5101    this.currPageIndex = 0;
    35875102  }
    35885103
     
    36885203      return shadow(this, 'num', obj);
    36895204    },
    3690     traverseKids: function Catalog_traverseKids(pagesDict) {
    3691       var pageCache = this.pageCache;
    3692       var kids = pagesDict.get('Kids');
    3693       assertWellFormed(isArray(kids),
    3694                        'page dictionary kids object is not an array');
    3695       for (var i = 0, ii = kids.length; i < ii; ++i) {
    3696         var kid = kids[i];
    3697         assertWellFormed(isRef(kid),
    3698                         'page dictionary kid is not a reference');
    3699         var obj = this.xref.fetch(kid);
    3700         if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) {
    3701           pageCache.push(new Page(this.xref, pageCache.length, obj, kid));
    3702         } else { // must be a child page dictionary
    3703           assertWellFormed(
    3704             isDict(obj),
    3705             'page dictionary kid reference points to wrong type of object'
    3706           );
    3707           this.traverseKids(obj);
    3708         }
    3709       }
    3710     },
    37115205    get destinations() {
    37125206      function fetchDestination(dest) {
     
    37315225      }
    37325226      if (nameTreeRef) {
    3733         // reading name tree
    3734         var processed = new RefSet();
    3735         processed.put(nameTreeRef);
    3736         var queue = [nameTreeRef];
    3737         while (queue.length > 0) {
    3738           var i, n;
    3739           obj = xref.fetch(queue.shift());
    3740           if (obj.has('Kids')) {
    3741             var kids = obj.get('Kids');
    3742             for (i = 0, n = kids.length; i < n; i++) {
    3743               var kid = kids[i];
    3744               if (processed.has(kid))
    3745                 error('invalid destinations');
    3746               queue.push(kid);
    3747               processed.put(kid);
    3748             }
     5227        var nameTree = new NameTree(nameTreeRef, xref);
     5228        var names = nameTree.getAll();
     5229        for (var name in names) {
     5230          if (!names.hasOwnProperty(name)) {
    37495231            continue;
    37505232          }
    3751           var names = obj.get('Names');
    3752           if (names) {
    3753             for (i = 0, n = names.length; i < n; i += 2) {
    3754               dests[names[i]] = fetchDestination(xref.fetchIfRef(names[i + 1]));
    3755             }
     5233          dests[name] = fetchDestination(names[name]);
     5234        }
     5235      }
     5236      return shadow(this, 'destinations', dests);
     5237    },
     5238    get javaScript() {
     5239      var xref = this.xref;
     5240      var obj = this.catDict.get('Names');
     5241
     5242      var javaScript = [];
     5243      if (obj && obj.has('JavaScript')) {
     5244        var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
     5245        var names = nameTree.getAll();
     5246        for (var name in names) {
     5247          if (!names.hasOwnProperty(name)) {
     5248            continue;
    37565249          }
     5250          // We don't really use the JavaScript right now so this code is
     5251          // defensive so we don't cause errors on document load.
     5252          var jsDict = names[name];
     5253          if (!isDict(jsDict)) {
     5254            continue;
     5255          }
     5256          var type = jsDict.get('S');
     5257          if (!isName(type) || type.name !== 'JavaScript') {
     5258            continue;
     5259          }
     5260          var js = jsDict.get('JS');
     5261          if (!isString(js) && !isStream(js)) {
     5262            continue;
     5263          }
     5264          if (isStream(js)) {
     5265            js = bytesToString(js.getBytes());
     5266          }
     5267          javaScript.push(stringToPDFString(js));
    37575268        }
    37585269      }
    3759       return shadow(this, 'destinations', dests);
    3760     },
    3761     getPage: function Catalog_getPage(n) {
    3762       var pageCache = this.pageCache;
    3763       if (!pageCache) {
    3764         pageCache = this.pageCache = [];
    3765         this.traverseKids(this.toplevelPagesDict);
    3766       }
    3767       return this.pageCache[n - 1];
     5270      return shadow(this, 'javaScript', javaScript);
     5271    },
     5272
     5273    getPage: function Catalog_getPage(pageIndex) {
     5274      if (!(pageIndex in this.pagePromises)) {
     5275        this.pagePromises[pageIndex] = new Promise();
     5276      }
     5277      return this.pagePromises[pageIndex];
     5278    },
     5279
     5280    // Traverses pages in DFS order so that pages are processed in increasing
     5281    // order
     5282    traversePages: function Catalog_traversePages() {
     5283      var queue = this.traversePagesQueue;
     5284      while (queue.length) {
     5285        var queueItem = queue[queue.length - 1];
     5286        var pagesDict = queueItem.pagesDict;
     5287
     5288        var kids = pagesDict.get('Kids');
     5289        assert(isArray(kids), 'page dictionary kids object is not an array');
     5290        if (queueItem.posInKids >= kids.length) {
     5291          queue.pop();
     5292          continue;
     5293        }
     5294        var kidRef = kids[queueItem.posInKids];
     5295        assert(isRef(kidRef), 'page dictionary kid is not a reference');
     5296
     5297        var kid = this.xref.fetch(kidRef);
     5298        if (isDict(kid, 'Page') || (isDict(kid) && !kid.has('Kids'))) {
     5299          var pageIndex = this.currPageIndex++;
     5300          var page = new Page(this.pdfManager, this.xref, pageIndex, kid,
     5301                              kidRef);
     5302          if (!(pageIndex in this.pagePromises)) {
     5303            this.pagePromises[pageIndex] = new Promise();
     5304          }
     5305          this.pagePromises[pageIndex].resolve(page);
     5306
     5307        } else { // must be a child page dictionary
     5308          assert(
     5309            isDict(kid),
     5310            'page dictionary kid reference points to wrong type of object'
     5311          );
     5312
     5313          queue.push({
     5314            pagesDict: kid,
     5315            posInKids: 0
     5316          });
     5317        }
     5318        ++queueItem.posInKids;
     5319      }
    37685320    }
    37695321  };
     
    37735325
    37745326var XRef = (function XRefClosure() {
    3775   function XRef(stream, startXRef, mainXRefEntriesOffset, password) {
     5327  function XRef(stream, password) {
     5328
    37765329    this.stream = stream;
    37775330    this.entries = [];
    37785331    this.xrefstms = {};
    3779     var trailerDict = this.readXRef(startXRef);
    3780     trailerDict.assignXref(this);
    3781     this.trailer = trailerDict;
    37825332    // prepare the XRef cache
    37835333    this.cache = [];
    3784 
    3785     var encrypt = trailerDict.get('Encrypt');
    3786     if (encrypt) {
    3787       var ids = trailerDict.get('ID');
    3788       var fileId = (ids && ids.length) ? ids[0] : '';
    3789       this.encrypt = new CipherTransformFactory(encrypt, fileId, password);
    3790     }
    3791 
    3792     // get the root dictionary (catalog) object
    3793     if (!(this.root = trailerDict.get('Root')))
    3794       error('Invalid root reference');
     5334    this.password = password;
    37955335  }
    37965336
    37975337  XRef.prototype = {
    3798     readXRefTable: function XRef_readXRefTable(parser) {
    3799       // Example of cross-reference table:
    3800       // xref
    3801       // 0 1                    <-- subsection header (first obj #, obj count)
    3802       // 0000000000 65535 f     <-- actual object (offset, generation #, f/n)
    3803       // 23 2                   <-- subsection header ... and so on ...
    3804       // 0000025518 00002 n
    3805       // 0000025635 00000 n
    3806       // trailer
    3807       // ...
    3808 
    3809       // Outer loop is over subsection headers
    3810       var obj;
    3811       while (!isCmd(obj = parser.getObj(), 'trailer')) {
    3812         var first = obj,
    3813             count = parser.getObj();
    3814 
    3815         if (!isInt(first) || !isInt(count))
    3816           error('Invalid XRef table: wrong types in subsection header');
    3817 
    3818         // Inner loop is over objects themselves
    3819         for (var i = 0; i < count; i++) {
    3820           var entry = {};
    3821           entry.offset = parser.getObj();
    3822           entry.gen = parser.getObj();
    3823           var type = parser.getObj();
    3824 
    3825           if (isCmd(type, 'f'))
    3826             entry.free = true;
    3827           else if (isCmd(type, 'n'))
    3828             entry.uncompressed = true;
    3829 
    3830           // Validate entry obj
    3831           if (!isInt(entry.offset) || !isInt(entry.gen) ||
    3832               !(entry.free || entry.uncompressed)) {
    3833             error('Invalid entry in XRef subsection: ' + first + ', ' + count);
    3834           }
    3835 
    3836           if (!this.entries[i + first])
    3837             this.entries[i + first] = entry;
    3838         }
    3839       }
    3840 
    3841       // Sanity check: as per spec, first object must be free
    3842       if (this.entries[0] && !this.entries[0].free)
    3843         error('Invalid XRef table: unexpected first object');
     5338    setStartXRef: function XRef_setStartXRef(startXRef) {
     5339      // Store the starting positions of xref tables as we process them
     5340      // so we can recover from missing data errors
     5341      this.startXRefQueue = [startXRef];
     5342    },
     5343
     5344    parse: function XRef_parse(recoveryMode) {
     5345      var trailerDict;
     5346      if (!recoveryMode) {
     5347        trailerDict = this.readXRef();
     5348      } else {
     5349        warn('Indexing all PDF objects');
     5350        trailerDict = this.indexObjects();
     5351      }
     5352      trailerDict.assignXref(this);
     5353      this.trailer = trailerDict;
     5354      var encrypt = trailerDict.get('Encrypt');
     5355      if (encrypt) {
     5356        var ids = trailerDict.get('ID');
     5357        var fileId = (ids && ids.length) ? ids[0] : '';
     5358        this.encrypt = new CipherTransformFactory(
     5359            encrypt, fileId, this.password);
     5360      }
     5361
     5362      // get the root dictionary (catalog) object
     5363      if (!(this.root = trailerDict.get('Root'))) {
     5364        error('Invalid root reference');
     5365      }
     5366    },
     5367
     5368    processXRefTable: function XRef_processXRefTable(parser) {
     5369      if (!('tableState' in this)) {
     5370        // Stores state of the table as we process it so we can resume
     5371        // from middle of table in case of missing data error
     5372        this.tableState = {
     5373          entryNum: 0,
     5374          streamPos: parser.lexer.stream.pos,
     5375          parserBuf1: parser.buf1,
     5376          parserBuf2: parser.buf2
     5377        };
     5378      }
     5379
     5380      var obj = this.readXRefTable(parser);
    38445381
    38455382      // Sanity check
     
    38605397        error('Invalid XRef table: could not parse trailer dictionary');
    38615398
     5399      delete this.tableState;
     5400
    38625401      return dict;
    38635402    },
     5403
     5404    readXRefTable: function XRef_readXRefTable(parser) {
     5405      // Example of cross-reference table:
     5406      // xref
     5407      // 0 1                    <-- subsection header (first obj #, obj count)
     5408      // 0000000000 65535 f     <-- actual object (offset, generation #, f/n)
     5409      // 23 2                   <-- subsection header ... and so on ...
     5410      // 0000025518 00002 n
     5411      // 0000025635 00000 n
     5412      // trailer
     5413      // ...
     5414
     5415      var stream = parser.lexer.stream;
     5416      var tableState = this.tableState;
     5417      stream.pos = tableState.streamPos;
     5418      parser.buf1 = tableState.parserBuf1;
     5419      parser.buf2 = tableState.parserBuf2;
     5420
     5421      // Outer loop is over subsection headers
     5422      var obj;
     5423
     5424      while (true) {
     5425        if (!('firstEntryNum' in tableState) || !('entryCount' in tableState)) {
     5426          if (isCmd(obj = parser.getObj(), 'trailer')) {
     5427            break;
     5428          }
     5429          tableState.firstEntryNum = obj;
     5430          tableState.entryCount = parser.getObj();
     5431        }
     5432
     5433        var first = tableState.firstEntryNum;
     5434        var count = tableState.entryCount;
     5435        if (!isInt(first) || !isInt(count))
     5436          error('Invalid XRef table: wrong types in subsection header');
     5437
     5438        // Inner loop is over objects themselves
     5439        for (var i = tableState.entryNum; i < count; i++) {
     5440          tableState.streamPos = stream.pos;
     5441          tableState.entryNum = i;
     5442          tableState.parserBuf1 = parser.buf1;
     5443          tableState.parserBuf2 = parser.buf2;
     5444
     5445          var entry = {};
     5446          entry.offset = parser.getObj();
     5447          entry.gen = parser.getObj();
     5448          var type = parser.getObj();
     5449
     5450          if (isCmd(type, 'f'))
     5451            entry.free = true;
     5452          else if (isCmd(type, 'n'))
     5453            entry.uncompressed = true;
     5454
     5455          // Validate entry obj
     5456          if (!isInt(entry.offset) || !isInt(entry.gen) ||
     5457              !(entry.free || entry.uncompressed)) {
     5458            console.log(entry.offset, entry.gen, entry.free,
     5459                entry.uncompressed);
     5460            error('Invalid entry in XRef subsection: ' + first + ', ' + count);
     5461          }
     5462
     5463          if (!this.entries[i + first])
     5464            this.entries[i + first] = entry;
     5465        }
     5466
     5467        tableState.entryNum = 0;
     5468        tableState.streamPos = stream.pos;
     5469        tableState.parserBuf1 = parser.buf1;
     5470        tableState.parserBuf2 = parser.buf2;
     5471        delete tableState.firstEntryNum;
     5472        delete tableState.entryCount;
     5473      }
     5474
     5475      // Sanity check: as per spec, first object must be free
     5476      if (this.entries[0] && !this.entries[0].free)
     5477        error('Invalid XRef table: unexpected first object');
     5478
     5479      return obj;
     5480    },
     5481
     5482    processXRefStream: function XRef_processXRefStream(stream) {
     5483      if (!('streamState' in this)) {
     5484        // Stores state of the stream as we process it so we can resume
     5485        // from middle of stream in case of missing data error
     5486        var streamParameters = stream.dict;
     5487        var byteWidths = streamParameters.get('W');
     5488        var range = streamParameters.get('Index');
     5489        if (!range) {
     5490          range = [0, streamParameters.get('Size')];
     5491        }
     5492
     5493        this.streamState = {
     5494          entryRanges: range,
     5495          byteWidths: byteWidths,
     5496          entryNum: 0,
     5497          streamPos: stream.pos
     5498        };
     5499      }
     5500      this.readXRefStream(stream);
     5501      delete this.streamState;
     5502
     5503      return stream.dict;
     5504    },
     5505
    38645506    readXRefStream: function XRef_readXRefStream(stream) {
    3865       var streamParameters = stream.parameters;
    3866       var byteWidths = streamParameters.get('W');
    3867       var range = streamParameters.get('Index');
    3868       if (!range)
    3869         range = [0, streamParameters.get('Size')];
    38705507      var i, j;
    3871       while (range.length > 0) {
    3872         var first = range[0], n = range[1];
     5508      var streamState = this.streamState;
     5509      stream.pos = streamState.streamPos;
     5510
     5511      var byteWidths = streamState.byteWidths;
     5512      var typeFieldWidth = byteWidths[0];
     5513      var offsetFieldWidth = byteWidths[1];
     5514      var generationFieldWidth = byteWidths[2];
     5515
     5516      var entryRanges = streamState.entryRanges;
     5517      while (entryRanges.length > 0) {
     5518
     5519        var first = entryRanges[0];
     5520        var n = entryRanges[1];
     5521
    38735522        if (!isInt(first) || !isInt(n))
    38745523          error('Invalid XRef range fields: ' + first + ', ' + n);
    3875         var typeFieldWidth = byteWidths[0];
    3876         var offsetFieldWidth = byteWidths[1];
    3877         var generationFieldWidth = byteWidths[2];
     5524
    38785525        if (!isInt(typeFieldWidth) || !isInt(offsetFieldWidth) ||
    38795526            !isInt(generationFieldWidth)) {
    38805527          error('Invalid XRef entry fields length: ' + first + ', ' + n);
    38815528        }
    3882         for (i = 0; i < n; ++i) {
     5529        for (i = streamState.entryNum; i < n; ++i) {
     5530          streamState.entryNum = i;
     5531          streamState.streamPos = stream.pos;
     5532
    38835533          var type = 0, offset = 0, generation = 0;
    38845534          for (j = 0; j < typeFieldWidth; ++j)
    38855535            type = (type << 8) | stream.getByte();
    38865536          // if type field is absent, its default value = 1
    3887           if (typeFieldWidth == 0)
     5537          if (typeFieldWidth === 0)
    38885538            type = 1;
    38895539          for (j = 0; j < offsetFieldWidth; ++j)
     
    39095559            this.entries[first + i] = entry;
    39105560        }
    3911         range.splice(0, 2);
    3912       }
    3913       return streamParameters;
     5561
     5562        streamState.entryNum = 0;
     5563        streamState.streamPos = stream.pos;
     5564        entryRanges.splice(0, 2);
     5565      }
    39145566    },
    39155567    indexObjects: function XRef_indexObjects() {
     
    39995651      // reading XRef streams
    40005652      for (var i = 0, ii = xrefStms.length; i < ii; ++i) {
    4001           this.readXRef(xrefStms[i], true);
     5653        this.startXRefQueue.push(xrefStms[i]);
     5654        this.readXRef(/* recoveryMode */ true);
    40025655      }
    40035656      // finding main trailer
     
    40235676      throw new InvalidPDFException('Invalid PDF structure');
    40245677    },
    4025     readXRef: function XRef_readXRef(startXRef, recoveryMode) {
     5678
     5679    readXRef: function XRef_readXRef(recoveryMode) {
    40265680      var stream = this.stream;
    4027       stream.pos = startXRef;
    40285681
    40295682      try {
    4030         var parser = new Parser(new Lexer(stream), true, null);
    4031         var obj = parser.getObj();
    4032         var dict;
    4033 
    4034         // Get dictionary
    4035         if (isCmd(obj, 'xref')) {
    4036           // Parse end-of-file XRef
    4037           dict = this.readXRefTable(parser);
    4038 
    4039           // Recursively get other XRefs 'XRefStm', if any
    4040           obj = dict.get('XRefStm');
     5683        while (this.startXRefQueue.length) {
     5684          var startXRef = this.startXRefQueue[0];
     5685
     5686          stream.pos = startXRef;
     5687
     5688          var parser = new Parser(new Lexer(stream), true, null);
     5689          var obj = parser.getObj();
     5690          var dict;
     5691
     5692          // Get dictionary
     5693          if (isCmd(obj, 'xref')) {
     5694
     5695            // Parse end-of-file XRef
     5696            dict = this.processXRefTable(parser);
     5697            if (!this.topDict) {
     5698              this.topDict = dict;
     5699            }
     5700
     5701            // Recursively get other XRefs 'XRefStm', if any
     5702            obj = dict.get('XRefStm');
     5703            if (isInt(obj)) {
     5704              var pos = obj;
     5705              // ignore previously loaded xref streams
     5706              // (possible infinite recursion)
     5707              if (!(pos in this.xrefstms)) {
     5708                this.xrefstms[pos] = 1;
     5709                this.startXRefQueue.push(pos);
     5710              }
     5711            }
     5712          } else if (isInt(obj)) {
     5713
     5714            // Parse in-stream XRef
     5715            if (!isInt(parser.getObj()) ||
     5716                !isCmd(parser.getObj(), 'obj') ||
     5717                !isStream(obj = parser.getObj())) {
     5718              error('Invalid XRef stream');
     5719            }
     5720            dict = this.processXRefStream(obj);
     5721            if (!this.topDict) {
     5722              this.topDict = dict;
     5723            }
     5724
     5725            if (!dict)
     5726              error('Failed to read XRef stream');
     5727          }
     5728
     5729          // Recursively get previous dictionary, if any
     5730          obj = dict.get('Prev');
    40415731          if (isInt(obj)) {
    4042             var pos = obj;
    4043             // ignore previously loaded xref streams
    4044             // (possible infinite recursion)
    4045             if (!(pos in this.xrefstms)) {
    4046               this.xrefstms[pos] = 1;
    4047               this.readXRef(pos);
    4048             }
     5732            this.startXRefQueue.push(obj);
     5733          } else if (isRef(obj)) {
     5734            // The spec says Prev must not be a reference, i.e. "/Prev NNN"
     5735            // This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R"
     5736            this.startXRefQueue.push(obj.num);
    40495737          }
    4050         } else if (isInt(obj)) {
    4051           // Parse in-stream XRef
    4052           if (!isInt(parser.getObj()) ||
    4053               !isCmd(parser.getObj(), 'obj') ||
    4054               !isStream(obj = parser.getObj())) {
    4055             error('Invalid XRef stream');
    4056           }
    4057           dict = this.readXRefStream(obj);
    4058           if (!dict)
    4059             error('Failed to read XRef stream');
     5738
     5739          this.startXRefQueue.shift();
    40605740        }
    40615741
    4062         // Recursively get previous dictionary, if any
    4063         obj = dict.get('Prev');
    4064         if (isInt(obj))
    4065           this.readXRef(obj, recoveryMode);
    4066         else if (isRef(obj)) {
    4067           // The spec says Prev must not be a reference, i.e. "/Prev NNN"
    4068           // This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R"
    4069           this.readXRef(obj.num, recoveryMode);
     5742        return this.topDict;
     5743      } catch (e) {
     5744        if (e instanceof MissingDataException) {
     5745          throw e;
    40705746        }
    4071 
    4072         return dict;
    4073       } catch (e) {
    40745747        log('(while reading XRef): ' + e);
    40755748      }
     
    40775750      if (recoveryMode)
    40785751        return;
    4079 
    4080       warn('Indexing all PDF objects');
    4081       return this.indexObjects();
    4082     },
     5752      throw new XRefParseException();
     5753    },
     5754
    40835755    getEntry: function XRef_getEntry(i) {
    40845756      var e = this.entries[i];
     
    40955767      assertWellFormed(isRef(ref), 'ref object is not a reference');
    40965768      var num = ref.num;
    4097       if (num in this.cache)
    4098         return this.cache[num];
    4099 
    4100       var e = this.getEntry(num);
     5769      var e;
     5770      if (num in this.cache) {
     5771        e = this.cache[num];
     5772        if (e instanceof Stream) {
     5773          return e.makeSubStream(e.start, e.length, e.dict);
     5774        }
     5775        return e;
     5776      }
     5777
     5778      e = this.getEntry(num);
    41015779
    41025780      // the referenced entry can be free
     
    41215799        if (!isCmd(obj3, 'obj')) {
    41225800          // some bad pdfs use "obj1234" and really mean 1234
    4123           if (obj3.cmd.indexOf('obj') == 0) {
     5801          if (obj3.cmd.indexOf('obj') === 0) {
    41245802            num = parseInt(obj3.cmd.substring(3), 10);
    41255803            if (!isNaN(num))
     
    41405818          e = parser.getObj();
    41415819        }
    4142         // Don't cache streams since they are mutable (except images).
    4143         if (!isStream(e) || e instanceof JpegStream)
     5820        if (!isStream(e) || e instanceof JpegStream) {
    41445821          this.cache[num] = e;
     5822        } else if (e instanceof Stream) {
     5823          e = e.makeSubStream(e.start, e.length, e.dict);
     5824          this.cache[num] = e;
     5825        } else if ('readBlock' in e) {
     5826          e.getBytes();
     5827          e = e.makeSubStream(0, e.bufferLength, e.dict);
     5828          this.cache[num] = e;
     5829        }
    41455830        return e;
    41465831      }
     
    41515836      if (!isStream(stream))
    41525837        error('bad ObjStm stream');
    4153       var first = stream.parameters.get('First');
    4154       var n = stream.parameters.get('N');
     5838      var first = stream.dict.get('First');
     5839      var n = stream.dict.get('N');
    41555840      if (!isInt(first) || !isInt(n)) {
    41565841        error('invalid first and n parameters for ObjStm stream');
     
    41865871      return e;
    41875872    },
     5873    fetchIfRefAsync: function XRef_fetchIfRefAsync(obj) {
     5874      if (!isRef(obj)) {
     5875        var promise = new Promise();
     5876        promise.resolve(obj);
     5877        return promise;
     5878      }
     5879      return this.fetchAsync(obj);
     5880    },
     5881    fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) {
     5882      var promise = new Promise();
     5883      var tryFetch = function (promise) {
     5884        try {
     5885          promise.resolve(this.fetch(ref, suppressEncryption));
     5886        } catch (e) {
     5887          if (e instanceof MissingDataException) {
     5888            this.stream.manager.requestRange(e.begin, e.end, tryFetch);
     5889            return;
     5890          }
     5891          promise.reject(e);
     5892        }
     5893      }.bind(this, promise);
     5894      tryFetch();
     5895      return promise;
     5896    },
    41885897    getCatalogObj: function XRef_getCatalogObj() {
    41895898      return this.root;
     
    41925901
    41935902  return XRef;
     5903})();
     5904
     5905/**
     5906 * A NameTree is like a Dict but has some adventagous properties, see the spec
     5907 * (7.9.6) for more details.
     5908 * TODO: implement all the Dict functions and make this more efficent.
     5909 */
     5910var NameTree = (function NameTreeClosure() {
     5911  function NameTree(root, xref) {
     5912    this.root = root;
     5913    this.xref = xref;
     5914  }
     5915
     5916  NameTree.prototype = {
     5917    getAll: function NameTree_getAll() {
     5918      var dict = {};
     5919      if (!this.root) {
     5920        return dict;
     5921      }
     5922      var xref = this.xref;
     5923      // reading name tree
     5924      var processed = new RefSet();
     5925      processed.put(this.root);
     5926      var queue = [this.root];
     5927      while (queue.length > 0) {
     5928        var i, n;
     5929        var obj = xref.fetchIfRef(queue.shift());
     5930        if (!isDict(obj)) {
     5931          continue;
     5932        }
     5933        if (obj.has('Kids')) {
     5934          var kids = obj.get('Kids');
     5935          for (i = 0, n = kids.length; i < n; i++) {
     5936            var kid = kids[i];
     5937            if (processed.has(kid))
     5938              error('invalid destinations');
     5939            queue.push(kid);
     5940            processed.put(kid);
     5941          }
     5942          continue;
     5943        }
     5944        var names = obj.get('Names');
     5945        if (names) {
     5946          for (i = 0, n = names.length; i < n; i += 2) {
     5947            dict[names[i]] = xref.fetchIfRef(names[i + 1]);
     5948          }
     5949        }
     5950      }
     5951      return dict;
     5952    }
     5953  };
     5954  return NameTree;
    41945955})();
    41955956
     
    42085969    /**
    42095970     * Internal function.
    4210      * Ensures there is an object defined for `objId`. Stores `data` on the
    4211      * object *if* it is created.
     5971     * Ensures there is an object defined for `objId`.
    42125972     */
    4213     ensureObj: function PDFObjects_ensureObj(objId, data) {
     5973    ensureObj: function PDFObjects_ensureObj(objId) {
    42145974      if (this.objs[objId])
    42155975        return this.objs[objId];
    4216       return this.objs[objId] = new Promise(objId, data);
     5976
     5977      var obj = {
     5978        promise: new Promise(objId),
     5979        data: null,
     5980        resolved: false
     5981      };
     5982      this.objs[objId] = obj;
     5983
     5984      return obj;
    42175985    },
    42185986
     
    42305998      // not required to be resolved right now
    42315999      if (callback) {
    4232         this.ensureObj(objId).then(callback);
     6000        this.ensureObj(objId).promise.then(callback);
    42336001        return null;
    42346002      }
     
    42406008      // If there isn't an object yet or the object isn't resolved, then the
    42416009      // data isn't ready yet!
    4242       if (!obj || !obj.isResolved)
     6010      if (!obj || !obj.resolved)
    42436011        error('Requesting object that isn\'t resolved yet ' + objId);
    42446012
     
    42506018     */
    42516019    resolve: function PDFObjects_resolve(objId, data) {
    4252       var objs = this.objs;
    4253 
    4254       // In case there is a promise already on this object, just resolve it.
    4255       if (objs[objId]) {
    4256         objs[objId].resolve(data);
    4257       } else {
    4258         this.ensureObj(objId, data);
    4259       }
    4260     },
    4261 
    4262     onData: function PDFObjects_onData(objId, callback) {
    4263       this.ensureObj(objId).onData(callback);
     6020      var obj = this.ensureObj(objId);
     6021
     6022      obj.resolved = true;
     6023      obj.data = data;
     6024      obj.promise.resolve(data);
    42646025    },
    42656026
    42666027    isResolved: function PDFObjects_isResolved(objId) {
    42676028      var objs = this.objs;
     6029
    42686030      if (!objs[objId]) {
    42696031        return false;
    42706032      } else {
    4271         return objs[objId].isResolved;
     6033        return objs[objId].resolved;
    42726034      }
    42736035    },
    42746036
    42756037    hasData: function PDFObjects_hasData(objId) {
    4276       var objs = this.objs;
    4277       if (!objs[objId]) {
    4278         return false;
    4279       } else {
    4280         return objs[objId].hasData;
    4281       }
     6038      return this.isResolved(objId);
    42826039    },
    42836040
     
    42876044    getData: function PDFObjects_getData(objId) {
    42886045      var objs = this.objs;
    4289       if (!objs[objId] || !objs[objId].hasData) {
     6046      if (!objs[objId] || !objs[objId].resolved) {
    42906047        return null;
    42916048      } else {
    42926049        return objs[objId].data;
    42936050      }
    4294     },
    4295 
    4296     /**
    4297      * Sets the data of an object but *doesn't* resolve it.
    4298      */
    4299     setData: function PDFObjects_setData(objId, data) {
    4300       // Watchout! If you call `this.ensureObj(objId, data)` you're going to
    4301       // create a *resolved* promise which shouldn't be the case!
    4302       this.ensureObj(objId).data = data;
    43036051    },
    43046052
     
    43106058})();
    43116059
     6060/**
     6061 * A helper for loading missing data in object graphs. It traverses the graph
     6062 * depth first and queues up any objects that have missing data. Once it has
     6063 * has traversed as many objects that are available it attempts to bundle the
     6064 * missing data requests and then resume from the nodes that weren't ready.
     6065 *
     6066 * NOTE: It provides protection from circular references by keeping track of
     6067 * of loaded references. However, you must be careful not to load any graphs
     6068 * that have references to the catalog or other pages since that will cause the
     6069 * entire PDF document object graph to be traversed.
     6070 */
     6071var ObjectLoader = (function() {
     6072
     6073  function mayHaveChildren(value) {
     6074    return isRef(value) || isDict(value) || isArray(value) || isStream(value);
     6075  }
     6076
     6077  function addChildren(node, nodesToVisit) {
     6078    if (isDict(node) || isStream(node)) {
     6079      var map;
     6080      if (isDict(node)) {
     6081        map = node.map;
     6082      } else {
     6083        map = node.dict.map;
     6084      }
     6085      for (var key in map) {
     6086        var value = map[key];
     6087        if (mayHaveChildren(value)) {
     6088          nodesToVisit.push(value);
     6089        }
     6090      }
     6091    } else if (isArray(node)) {
     6092      for (var i = 0, ii = node.length; i < ii; i++) {
     6093        var value = node[i];
     6094        if (mayHaveChildren(value)) {
     6095          nodesToVisit.push(value);
     6096        }
     6097      }
     6098    }
     6099  }
     6100
     6101  function ObjectLoader(obj, keys, xref) {
     6102    this.obj = obj;
     6103    this.keys = keys;
     6104    this.xref = xref;
     6105    this.refSet = null;
     6106  }
     6107
     6108  ObjectLoader.prototype = {
     6109
     6110    load: function ObjectLoader_load() {
     6111      var keys = this.keys;
     6112      this.promise = new Promise();
     6113      // Don't walk the graph if all the data is already loaded.
     6114      if (!(this.xref.stream instanceof ChunkedStream) ||
     6115          this.xref.stream.getMissingChunks().length === 0) {
     6116        this.promise.resolve();
     6117        return this.promise;
     6118      }
     6119
     6120      this.refSet = new RefSet();
     6121      // Setup the initial nodes to visit.
     6122      var nodesToVisit = [];
     6123      for (var i = 0; i < keys.length; i++) {
     6124        nodesToVisit.push(this.obj[keys[i]]);
     6125      }
     6126
     6127      this.walk(nodesToVisit);
     6128      return this.promise;
     6129    },
     6130
     6131    walk: function ObjectLoader_walk(nodesToVisit) {
     6132      var nodesToRevisit = [];
     6133      var pendingRequests = [];
     6134      // DFS walk of the object graph.
     6135      while (nodesToVisit.length) {
     6136        var currentNode = nodesToVisit.pop();
     6137
     6138        // Only references or chunked streams can cause missing data exceptions.
     6139        if (isRef(currentNode)) {
     6140          // Skip nodes that have already been visited.
     6141          if (this.refSet.has(currentNode)) {
     6142            continue;
     6143          }
     6144          try {
     6145            var ref = currentNode;
     6146            this.refSet.put(ref);
     6147            currentNode = this.xref.fetch(currentNode);
     6148          } catch (e) {
     6149            if (!(e instanceof MissingDataException)) {
     6150              throw e;
     6151            }
     6152            nodesToRevisit.push(currentNode);
     6153            pendingRequests.push({ begin: e.begin, end: e.end });
     6154          }
     6155        }
     6156        if (currentNode instanceof ChunkedStream &&
     6157            currentNode.getMissingChunks().length) {
     6158          nodesToRevisit.push(currentNode);
     6159          pendingRequests.push({
     6160            begin: currentNode.start,
     6161            end: currentNode.end
     6162          });
     6163        }
     6164
     6165        addChildren(currentNode, nodesToVisit);
     6166      }
     6167
     6168      if (pendingRequests.length) {
     6169        this.xref.stream.manager.requestRanges(pendingRequests,
     6170            function pendingRequestCallback() {
     6171          nodesToVisit = nodesToRevisit;
     6172          for (var i = 0; i < nodesToRevisit.length; i++) {
     6173            var node = nodesToRevisit[i];
     6174            // Remove any reference nodes from the currrent refset so they
     6175            // aren't skipped when we revist them.
     6176            if (isRef(node)) {
     6177              this.refSet.remove(node);
     6178            }
     6179          }
     6180          this.walk(nodesToVisit);
     6181        }.bind(this));
     6182        return;
     6183      }
     6184      // Everything is loaded.
     6185      this.refSet = null;
     6186      this.promise.resolve();
     6187    }
     6188
     6189  };
     6190
     6191  return ObjectLoader;
     6192})();
     6193
     6194
     6195
     6196
     6197var Annotation = (function AnnotationClosure() {
     6198  // 12.5.5: Algorithm: Appearance streams
     6199  function getTransformMatrix(rect, bbox, matrix) {
     6200    var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
     6201    var minX = bounds[0];
     6202    var minY = bounds[1];
     6203    var maxX = bounds[2];
     6204    var maxY = bounds[3];
     6205
     6206    if (minX === maxX || minY === maxY) {
     6207      // From real-life file, bbox was [0, 0, 0, 0]. In this case,
     6208      // just apply the transform for rect
     6209      return [1, 0, 0, 1, rect[0], rect[1]];
     6210    }
     6211
     6212    var xRatio = (rect[2] - rect[0]) / (maxX - minX);
     6213    var yRatio = (rect[3] - rect[1]) / (maxY - minY);
     6214    return [
     6215      xRatio,
     6216      0,
     6217      0,
     6218      yRatio,
     6219      rect[0] - minX * xRatio,
     6220      rect[1] - minY * yRatio
     6221    ];
     6222  }
     6223
     6224  function getDefaultAppearance(dict) {
     6225    var appearanceState = dict.get('AP');
     6226    if (!isDict(appearanceState)) {
     6227      return;
     6228    }
     6229
     6230    var appearance;
     6231    var appearances = appearanceState.get('N');
     6232    if (isDict(appearances)) {
     6233      var as = dict.get('AS');
     6234      if (as && appearances.has(as.name)) {
     6235        appearance = appearances.get(as.name);
     6236      }
     6237    } else {
     6238      appearance = appearances;
     6239    }
     6240    return appearance;
     6241  }
     6242
     6243  function Annotation(params) {
     6244    if (params.data) {
     6245      this.data = params.data;
     6246      return;
     6247    }
     6248
     6249    var dict = params.dict;
     6250    var data = this.data = {};
     6251
     6252    data.subtype = dict.get('Subtype').name;
     6253    var rect = dict.get('Rect');
     6254    data.rect = Util.normalizeRect(rect);
     6255    data.annotationFlags = dict.get('F');
     6256
     6257    var color = dict.get('C');
     6258    if (isArray(color) && color.length === 3) {
     6259      // TODO(mack): currently only supporting rgb; need support different
     6260      // colorspaces
     6261      data.color = color;
     6262    } else {
     6263      data.color = [0, 0, 0];
     6264    }
     6265
     6266    // Some types of annotations have border style dict which has more
     6267    // info than the border array
     6268    if (dict.has('BS')) {
     6269      var borderStyle = dict.get('BS');
     6270      data.borderWidth = borderStyle.has('W') ? borderStyle.get('W') : 1;
     6271    } else {
     6272      var borderArray = dict.get('Border') || [0, 0, 1];
     6273      data.borderWidth = borderArray[2];
     6274    }
     6275
     6276    this.appearance = getDefaultAppearance(dict);
     6277  }
     6278
     6279  Annotation.prototype = {
     6280
     6281    getData: function Annotation_getData() {
     6282      return this.data;
     6283    },
     6284
     6285    hasHtml: function Annotation_hasHtml() {
     6286      return false;
     6287    },
     6288
     6289    getHtmlElement: function Annotation_getHtmlElement(commonObjs) {
     6290      throw new NotImplementedException(
     6291        'getHtmlElement() should be implemented in subclass');
     6292    },
     6293
     6294    // TODO(mack): Remove this, it's not really that helpful.
     6295    getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect) {
     6296      assert(!isWorker,
     6297        'getEmptyContainer() should be called from main thread');
     6298
     6299      rect = rect || this.data.rect;
     6300      var element = document.createElement(tagName);
     6301      element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
     6302      element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
     6303      return element;
     6304    },
     6305
     6306    isViewable: function Annotation_isViewable() {
     6307      var data = this.data;
     6308      return !!(
     6309        data &&
     6310        (!data.annotationFlags ||
     6311         !(data.annotationFlags & 0x22)) && // Hidden or NoView
     6312        data.rect                            // rectangle is nessessary
     6313      );
     6314    },
     6315
     6316    loadResources: function(keys) {
     6317      var promise = new Promise();
     6318      this.appearance.dict.getAsync('Resources').then(function(resources) {
     6319        var objectLoader = new ObjectLoader(resources.map,
     6320                                            keys,
     6321                                            resources.xref);
     6322        objectLoader.load().then(function() {
     6323          promise.resolve(resources);
     6324        });
     6325      }.bind(this));
     6326
     6327      return promise;
     6328    },
     6329
     6330    getOperatorList: function Annotation_getToOperatorList(evaluator) {
     6331
     6332      var promise = new Promise();
     6333
     6334      if (!this.appearance) {
     6335        promise.resolve({
     6336          queue: {
     6337            fnArray: [],
     6338            argsArray: []
     6339          },
     6340          dependency: {}
     6341        });
     6342        return promise;
     6343      }
     6344
     6345      var data = this.data;
     6346
     6347      var appearanceDict = this.appearance.dict;
     6348      var resourcesPromise = this.loadResources([
     6349        'ExtGState',
     6350        'ColorSpace',
     6351        'Pattern',
     6352        'Shading',
     6353        'XObject',
     6354        'Font'
     6355        // ProcSet
     6356        // Properties
     6357      ]);
     6358      var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
     6359      var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
     6360      var transform = getTransformMatrix(data.rect, bbox, matrix);
     6361
     6362      var border = data.border;
     6363
     6364      resourcesPromise.then(function(resources) {
     6365        var listPromise = evaluator.getOperatorList(this.appearance, resources);
     6366        listPromise.then(function(appearanceStreamData) {
     6367          var fnArray = appearanceStreamData.queue.fnArray;
     6368          var argsArray = appearanceStreamData.queue.argsArray;
     6369
     6370          fnArray.unshift('beginAnnotation');
     6371          argsArray.unshift([data.rect, transform, matrix]);
     6372
     6373          fnArray.push('endAnnotation');
     6374          argsArray.push([]);
     6375
     6376          promise.resolve(appearanceStreamData);
     6377        });
     6378      }.bind(this));
     6379
     6380      return promise;
     6381    }
     6382  };
     6383
     6384  Annotation.getConstructor =
     6385      function Annotation_getConstructor(subtype, fieldType) {
     6386
     6387    if (!subtype) {
     6388      return;
     6389    }
     6390
     6391    // TODO(mack): Implement FreeText annotations
     6392    if (subtype === 'Link') {
     6393      return LinkAnnotation;
     6394    } else if (subtype === 'Text') {
     6395      return TextAnnotation;
     6396    } else if (subtype === 'Widget') {
     6397      if (!fieldType) {
     6398        return;
     6399      }
     6400
     6401      if (fieldType === 'Tx') {
     6402        return TextWidgetAnnotation;
     6403      } else {
     6404        return WidgetAnnotation;
     6405      }
     6406    } else {
     6407      return Annotation;
     6408    }
     6409  };
     6410
     6411  // TODO(mack): Support loading annotation from data
     6412  Annotation.fromData = function Annotation_fromData(data) {
     6413    var subtype = data.subtype;
     6414    var fieldType = data.fieldType;
     6415    var Constructor = Annotation.getConstructor(subtype, fieldType);
     6416    if (Constructor) {
     6417      return new Constructor({ data: data });
     6418    }
     6419  };
     6420
     6421  Annotation.fromRef = function Annotation_fromRef(xref, ref) {
     6422
     6423    var dict = xref.fetchIfRef(ref);
     6424    if (!isDict(dict)) {
     6425      return;
     6426    }
     6427
     6428    var subtype = dict.get('Subtype');
     6429    subtype = isName(subtype) ? subtype.name : '';
     6430    if (!subtype) {
     6431      return;
     6432    }
     6433
     6434    var fieldType = Util.getInheritableProperty(dict, 'FT');
     6435    fieldType = isName(fieldType) ? fieldType.name : '';
     6436
     6437    var Constructor = Annotation.getConstructor(subtype, fieldType);
     6438    if (!Constructor) {
     6439      return;
     6440    }
     6441
     6442    var params = {
     6443      dict: dict,
     6444      ref: ref,
     6445    };
     6446
     6447    var annotation = new Constructor(params);
     6448
     6449    if (annotation.isViewable()) {
     6450      return annotation;
     6451    } else {
     6452      TODO('unimplemented annotation type: ' + subtype);
     6453    }
     6454  };
     6455
     6456  Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
     6457      annotations, pageQueue, pdfManager, dependencies, partialEvaluator) {
     6458
     6459    function reject(e) {
     6460      annotationsReadyPromise.reject(e);
     6461    }
     6462
     6463    var annotationsReadyPromise = new Promise();
     6464
     6465    var annotationPromises = [];
     6466    for (var i = 0, n = annotations.length; i < n; ++i) {
     6467      annotationPromises.push(annotations[i].getOperatorList(partialEvaluator));
     6468    }
     6469
     6470    Promise.all(annotationPromises).then(function(datas) {
     6471      var fnArray = pageQueue.fnArray;
     6472      var argsArray = pageQueue.argsArray;
     6473      fnArray.push('beginAnnotations');
     6474      argsArray.push([]);
     6475      for (var i = 0, n = datas.length; i < n; ++i) {
     6476        var annotationData = datas[i];
     6477        var annotationQueue = annotationData.queue;
     6478        Util.concatenateToArray(fnArray, annotationQueue.fnArray);
     6479        Util.concatenateToArray(argsArray, annotationQueue.argsArray);
     6480        Util.extendObj(dependencies, annotationData.dependencies);
     6481      }
     6482      fnArray.push('endAnnotations');
     6483      argsArray.push([]);
     6484
     6485      annotationsReadyPromise.resolve();
     6486    }, reject);
     6487
     6488    return annotationsReadyPromise;
     6489  };
     6490
     6491  return Annotation;
     6492})();
     6493PDFJS.Annotation = Annotation;
     6494
     6495
     6496var WidgetAnnotation = (function WidgetAnnotationClosure() {
     6497
     6498  function WidgetAnnotation(params) {
     6499    Annotation.call(this, params);
     6500
     6501    if (params.data) {
     6502      return;
     6503    }
     6504
     6505    var dict = params.dict;
     6506    var data = this.data;
     6507
     6508    data.fieldValue = stringToPDFString(
     6509      Util.getInheritableProperty(dict, 'V') || '');
     6510    data.alternativeText = stringToPDFString(dict.get('TU') || '');
     6511    data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
     6512    var fieldType = Util.getInheritableProperty(dict, 'FT');
     6513    data.fieldType = isName(fieldType) ? fieldType.name : '';
     6514    data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
     6515    this.fieldResources = Util.getInheritableProperty(dict, 'DR') || new Dict();
     6516
     6517    // Building the full field name by collecting the field and
     6518    // its ancestors 'T' data and joining them using '.'.
     6519    var fieldName = [];
     6520    var namedItem = dict;
     6521    var ref = params.ref;
     6522    while (namedItem) {
     6523      var parent = namedItem.get('Parent');
     6524      var parentRef = namedItem.getRaw('Parent');
     6525      var name = namedItem.get('T');
     6526      if (name) {
     6527        fieldName.unshift(stringToPDFString(name));
     6528      } else {
     6529        // The field name is absent, that means more than one field
     6530        // with the same name may exist. Replacing the empty name
     6531        // with the '`' plus index in the parent's 'Kids' array.
     6532        // This is not in the PDF spec but necessary to id the
     6533        // the input controls.
     6534        var kids = parent.get('Kids');
     6535        var j, jj;
     6536        for (j = 0, jj = kids.length; j < jj; j++) {
     6537          var kidRef = kids[j];
     6538          if (kidRef.num == ref.num && kidRef.gen == ref.gen)
     6539            break;
     6540        }
     6541        fieldName.unshift('`' + j);
     6542      }
     6543      namedItem = parent;
     6544      ref = parentRef;
     6545    }
     6546    data.fullName = fieldName.join('.');
     6547  }
     6548
     6549  var parent = Annotation.prototype;
     6550  Util.inherit(WidgetAnnotation, Annotation, {
     6551    isViewable: function WidgetAnnotation_isViewable() {
     6552      if (this.data.fieldType === 'Sig') {
     6553        TODO('unimplemented annotation type: Widget signature');
     6554        return false;
     6555      }
     6556
     6557      return parent.isViewable.call(this);
     6558    }
     6559  });
     6560
     6561  return WidgetAnnotation;
     6562})();
     6563
     6564var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
     6565  function TextWidgetAnnotation(params) {
     6566    WidgetAnnotation.call(this, params);
     6567
     6568    if (params.data) {
     6569      return;
     6570    }
     6571
     6572    this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q');
     6573  }
     6574
     6575  // TODO(mack): This dupes some of the logic in CanvasGraphics.setFont()
     6576  function setTextStyles(element, item, fontObj) {
     6577
     6578    var style = element.style;
     6579    style.fontSize = item.fontSize + 'px';
     6580    style.direction = item.fontDirection < 0 ? 'rtl': 'ltr';
     6581
     6582    if (!fontObj) {
     6583      return;
     6584    }
     6585
     6586    style.fontWeight = fontObj.black ?
     6587                            (fontObj.bold ? 'bolder' : 'bold') :
     6588                            (fontObj.bold ? 'bold' : 'normal');
     6589    style.fontStyle = fontObj.italic ? 'italic' : 'normal';
     6590
     6591    var fontName = fontObj.loadedName;
     6592    var fontFamily = fontName ? '"' + fontName + '", ' : '';
     6593    // Use a reasonable default font if the font doesn't specify a fallback
     6594    var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif';
     6595    style.fontFamily = fontFamily + fallbackName;
     6596  }
     6597
     6598
     6599  var parent = WidgetAnnotation.prototype;
     6600  Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
     6601    hasHtml: function TextWidgetAnnotation_hasHtml() {
     6602      return !!this.data.fieldValue;
     6603    },
     6604
     6605    getHtmlElement: function TextWidgetAnnotation_getHtmlElement(commonObjs) {
     6606      assert(!isWorker, 'getHtmlElement() shall be called from main thread');
     6607
     6608      var item = this.data;
     6609
     6610      var element = this.getEmptyContainer('div');
     6611      element.style.display = 'table';
     6612
     6613      var content = document.createElement('div');
     6614      content.textContent = item.fieldValue;
     6615      var textAlignment = item.textAlignment;
     6616      content.style.textAlign = ['left', 'center', 'right'][textAlignment];
     6617      content.style.verticalAlign = 'middle';
     6618      content.style.display = 'table-cell';
     6619
     6620      var fontObj = item.fontRefName ?
     6621                    commonObjs.getData(item.fontRefName) : null;
     6622      var cssRules = setTextStyles(content, item, fontObj);
     6623
     6624      element.appendChild(content);
     6625
     6626      return element;
     6627    },
     6628
     6629    getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
     6630
     6631
     6632      var promise = new Promise();
     6633      var data = this.data;
     6634
     6635      // Even if there is an appearance stream, ignore it. This is the
     6636      // behaviour used by Adobe Reader.
     6637
     6638      var defaultAppearance = data.defaultAppearance;
     6639      if (!defaultAppearance) {
     6640        promise.resolve({
     6641          queue: {
     6642            fnArray: [],
     6643            argsArray: []
     6644          },
     6645          dependency: {}
     6646        });
     6647        return promise;
     6648      }
     6649
     6650      // Include any font resources found in the default appearance
     6651
     6652      var stream = new Stream(stringToBytes(defaultAppearance));
     6653      var listPromise = evaluator.getOperatorList(stream, this.fieldResources);
     6654      listPromise.then(function(appearanceStreamData) {
     6655        var appearanceFnArray = appearanceStreamData.queue.fnArray;
     6656        var appearanceArgsArray = appearanceStreamData.queue.argsArray;
     6657        var fnArray = [];
     6658        var argsArray = [];
     6659
     6660        // TODO(mack): Add support for stroke color
     6661        data.rgb = [0, 0, 0];
     6662        for (var i = 0, n = fnArray.length; i < n; ++i) {
     6663          var fnName = appearanceFnArray[i];
     6664          var args = appearanceArgsArray[i];
     6665          if (fnName === 'dependency') {
     6666            var dependency = args[i];
     6667            if (dependency.indexOf('g_font_') === 0) {
     6668              data.fontRefName = dependency;
     6669            }
     6670            fnArray.push(fnName);
     6671            argsArray.push(args);
     6672          } else if (fnName === 'setFont') {
     6673            data.fontRefName = args[0];
     6674            var size = args[1];
     6675            if (size < 0) {
     6676              data.fontDirection = -1;
     6677              data.fontSize = -size;
     6678            } else {
     6679              data.fontDirection = 1;
     6680              data.fontSize = size;
     6681            }
     6682          } else if (fnName === 'setFillRGBColor') {
     6683            data.rgb = args;
     6684          } else if (fnName === 'setFillGray') {
     6685            var rgbValue = args[0] * 255;
     6686            data.rgb = [rgbValue, rgbValue, rgbValue];
     6687          }
     6688        }
     6689        promise.resolve({
     6690          queue: {
     6691            fnArray: fnArray,
     6692            argsArray: argsArray
     6693          },
     6694          dependency: {}
     6695        });
     6696
     6697      });
     6698
     6699      return promise;
     6700    }
     6701  });
     6702
     6703  return TextWidgetAnnotation;
     6704})();
     6705
     6706var TextAnnotation = (function TextAnnotationClosure() {
     6707  function TextAnnotation(params) {
     6708    Annotation.call(this, params);
     6709
     6710    if (params.data) {
     6711      return;
     6712    }
     6713
     6714    var dict = params.dict;
     6715    var data = this.data;
     6716
     6717    var content = dict.get('Contents');
     6718    var title = dict.get('T');
     6719    data.content = stringToPDFString(content || '');
     6720    data.title = stringToPDFString(title || '');
     6721    data.name = !dict.has('Name') ? 'Note' : dict.get('Name').name;
     6722  }
     6723
     6724  var ANNOT_MIN_SIZE = 10;
     6725  var IMAGE_DIR = './images/';
     6726
     6727  Util.inherit(TextAnnotation, Annotation, {
     6728
     6729    getOperatorList: function TextAnnotation_getOperatorList(evaluator) {
     6730      var promise = new Promise();
     6731      promise.resolve({
     6732        queue: {
     6733          fnArray: [],
     6734          argsArray: []
     6735        },
     6736        dependency: {}
     6737      });
     6738      return promise;
     6739    },
     6740
     6741    hasHtml: function TextAnnotation_hasHtml() {
     6742      return true;
     6743    },
     6744
     6745    getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) {
     6746      assert(!isWorker, 'getHtmlElement() shall be called from main thread');
     6747
     6748      var item = this.data;
     6749      var rect = item.rect;
     6750
     6751      // sanity check because of OOo-generated PDFs
     6752      if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
     6753        rect[3] = rect[1] + ANNOT_MIN_SIZE;
     6754      }
     6755      if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
     6756        rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
     6757      }
     6758
     6759      var container = this.getEmptyContainer('section', rect);
     6760      container.className = 'annotText';
     6761
     6762      var image = document.createElement('img');
     6763      image.style.width = container.style.width;
     6764      image.style.height = container.style.height;
     6765      var iconName = item.name;
     6766      image.src = IMAGE_DIR + 'annotation-' +
     6767        iconName.toLowerCase() + '.svg';
     6768      image.alt = '[{{type}} Annotation]';
     6769      image.dataset.l10nId = 'text_annotation_type';
     6770      image.dataset.l10nArgs = JSON.stringify({type: iconName});
     6771      var content = document.createElement('div');
     6772      content.setAttribute('hidden', true);
     6773      var title = document.createElement('h1');
     6774      var text = document.createElement('p');
     6775      content.style.left = Math.floor(rect[2] - rect[0]) + 'px';
     6776      content.style.top = '0px';
     6777      title.textContent = item.title;
     6778
     6779      if (!item.content && !item.title) {
     6780        content.setAttribute('hidden', true);
     6781      } else {
     6782        var e = document.createElement('span');
     6783        var lines = item.content.split(/(?:\r\n?|\n)/);
     6784        for (var i = 0, ii = lines.length; i < ii; ++i) {
     6785          var line = lines[i];
     6786          e.appendChild(document.createTextNode(line));
     6787          if (i < (ii - 1))
     6788            e.appendChild(document.createElement('br'));
     6789        }
     6790        text.appendChild(e);
     6791        image.addEventListener('mouseover', function annotationImageOver() {
     6792          container.style.zIndex += 1;
     6793          content.removeAttribute('hidden');
     6794        }, false);
     6795
     6796        image.addEventListener('mouseout', function annotationImageOut() {
     6797          container.style.zIndex -= 1;
     6798          content.setAttribute('hidden', true);
     6799        }, false);
     6800      }
     6801
     6802      content.appendChild(title);
     6803      content.appendChild(text);
     6804      container.appendChild(image);
     6805      container.appendChild(content);
     6806
     6807      return container;
     6808    }
     6809  });
     6810
     6811  return TextAnnotation;
     6812})();
     6813
     6814var LinkAnnotation = (function LinkAnnotationClosure() {
     6815  function isValidUrl(url) {
     6816    if (!url)
     6817      return false;
     6818    var colon = url.indexOf(':');
     6819    if (colon < 0)
     6820      return false;
     6821    var protocol = url.substr(0, colon);
     6822    switch (protocol) {
     6823      case 'http':
     6824      case 'https':
     6825      case 'ftp':
     6826      case 'mailto':
     6827        return true;
     6828      default:
     6829        return false;
     6830    }
     6831  }
     6832
     6833  function LinkAnnotation(params) {
     6834    Annotation.call(this, params);
     6835
     6836    if (params.data) {
     6837      return;
     6838    }
     6839
     6840    var dict = params.dict;
     6841    var data = this.data;
     6842
     6843    var action = dict.get('A');
     6844    if (action) {
     6845      var linkType = action.get('S').name;
     6846      if (linkType === 'URI') {
     6847        var url = action.get('URI');
     6848        // TODO: pdf spec mentions urls can be relative to a Base
     6849        // entry in the dictionary.
     6850        if (!isValidUrl(url)) {
     6851          url = '';
     6852        }
     6853        data.url = url;
     6854      } else if (linkType === 'GoTo') {
     6855        data.dest = action.get('D');
     6856      } else if (linkType === 'GoToR') {
     6857        var urlDict = action.get('F');
     6858        if (isDict(urlDict)) {
     6859          // We assume that the 'url' is a Filspec dictionary
     6860          // and fetch the url without checking any further
     6861          url = urlDict.get('F') || '';
     6862        }
     6863
     6864        // TODO: pdf reference says that GoToR
     6865        // can also have 'NewWindow' attribute
     6866        if (!isValidUrl(url)) {
     6867          url = '';
     6868        }
     6869        data.url = url;
     6870        data.dest = action.get('D');
     6871      } else {
     6872        TODO('unrecognized link type: ' + linkType);
     6873      }
     6874    } else if (dict.has('Dest')) {
     6875      // simple destination link
     6876      var dest = dict.get('Dest');
     6877      data.dest = isName(dest) ? dest.name : dest;
     6878    }
     6879  }
     6880
     6881  Util.inherit(LinkAnnotation, Annotation, {
     6882    hasOperatorList: function LinkAnnotation_hasOperatorList() {
     6883      return false;
     6884    },
     6885
     6886    hasHtml: function LinkAnnotation_hasHtml() {
     6887      return true;
     6888    },
     6889
     6890    getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) {
     6891      var rect = this.data.rect;
     6892      var element = document.createElement('a');
     6893      var borderWidth = this.data.borderWidth;
     6894
     6895      element.style.borderWidth = borderWidth + 'px';
     6896      var color = this.data.color;
     6897      var rgb = [];
     6898      for (var i = 0; i < 3; ++i) {
     6899        rgb[i] = Math.round(color[i] * 255);
     6900      }
     6901      element.style.borderColor = Util.makeCssRgb(rgb);
     6902      element.style.borderStyle = 'solid';
     6903
     6904      var width = rect[2] - rect[0] - 2 * borderWidth;
     6905      var height = rect[3] - rect[1] - 2 * borderWidth;
     6906      element.style.width = width + 'px';
     6907      element.style.height = height + 'px';
     6908
     6909      element.href = this.data.url || '';
     6910      return element;
     6911    }
     6912  });
     6913
     6914  return LinkAnnotation;
     6915})();
    43126916
    43136917
     
    43756979        case CONSTRUCT_STICHED:
    43766980          return this.constructStichedFromIR(IR);
    4377         case CONSTRUCT_POSTSCRIPT:
     6981        //case CONSTRUCT_POSTSCRIPT:
    43786982        default:
    43796983          return this.constructPostScriptFromIR(IR);
     
    45287132
    45297133        return y;
    4530       }
     7134      };
    45317135    },
    45327136
     
    45657169        return out;
    45667170
    4567       }
     7171      };
    45687172    },
    45697173
     
    1227514879        return src.subarray(srcOffset);
    1227614880      }
    12277       var destLength = this.getOutputLength(count * this.numComps);
    12278       var dest = new Uint8Array(destLength);
     14881      var dest = new Uint8Array(count * 3);
     14882      var numComponentColors = 1 << bits;
     14883      // Optimization: create a color map when there is just one component and
     14884      // we are converting more colors than the size of the color map. We
     14885      // don't build the map if the colorspace is gray or rgb since those
     14886      // methods are faster than building a map. This mainly offers big speed
     14887      // ups for indexed and alternate colorspaces.
     14888      if (this.numComps === 1 && count > numComponentColors &&
     14889          this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
     14890        // TODO it may be worth while to cache the color map. While running
     14891        // testing I never hit a cache so I will leave that out for now (perhaps
     14892        // we are reparsing colorspaces too much?).
     14893        var allColors = bits <= 8 ? new Uint8Array(numComponentColors) :
     14894                                    new Uint16Array(numComponentColors);
     14895        for (var i = 0; i < numComponentColors; i++) {
     14896          allColors[i] = i;
     14897        }
     14898        var colorMap = new Uint8Array(numComponentColors * 3);
     14899        this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bits);
     14900
     14901        var destOffset = 0;
     14902        for (var i = 0; i < count; ++i) {
     14903          var key = src[srcOffset++] * 3;
     14904          dest[destOffset++] = colorMap[key];
     14905          dest[destOffset++] = colorMap[key + 1];
     14906          dest[destOffset++] = colorMap[key + 2];
     14907        }
     14908        return dest;
     14909      }
    1227914910      this.getRgbBuffer(src, srcOffset, count, dest, 0, bits);
    1228014911      return dest;
    12281     }
     14912    },
     14913    /**
     14914     * True if the colorspace has components in the default range of [0, 1].
     14915     * This should be true for all colorspaces except for lab color spaces
     14916     * which are [0,100], [-128, 127], [-128, 127].
     14917     */
     14918    usesZeroToOneRange: true
    1228214919  };
    1228314920
     
    1244315080    }
    1244415081    for (var i = 0, ii = decode.length; i < ii; i += 2) {
    12445       if (decode[i] != 0 || decode[i + 1] != 1)
     15082      if (decode[i] !== 0 || decode[i + 1] != 1)
    1244615083        return false;
    1244715084    }
     
    1249115128      var scale = 1 / ((1 << bits) - 1);
    1249215129      var baseNumComps = base.numComps;
    12493       var isGetRgbBufferSupported = 'getRgbBuffer' in base;
    12494       var isPassthrough = base.isPassthrough(8) || !isGetRgbBufferSupported;
     15130      var usesZeroToOneRange = base.usesZeroToOneRange;
     15131      var isPassthrough = base.isPassthrough(8) || !usesZeroToOneRange;
    1249515132      var pos = isPassthrough ? destOffset : 0;
    1249615133      var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
     
    1250315140        }
    1250415141        var tinted = tintFn(scaled);
    12505         if (isGetRgbBufferSupported) {
     15142        if (usesZeroToOneRange) {
    1250615143          for (var j = 0; j < baseNumComps; j++) {
    1250715144            baseBuf[pos++] = tinted[j] * 255;
     
    1252415161    isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
    1252515162      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
    12526     }
     15163    },
     15164    usesZeroToOneRange: true
    1252715165  };
    1252815166
     
    1256015198      for (var i = 0; i < length; ++i)
    1256115199        lookupArray[i] = lookup.charCodeAt(i);
    12562     } else if (lookup instanceof Uint8Array) {
     15200    } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
    1256315201      lookupArray = lookup;
    1256415202    } else {
     
    1260115239      // indexed color maps shouldn't be changed
    1260215240      return true;
    12603     }
     15241    },
     15242    usesZeroToOneRange: true
    1260415243  };
    1260515244  return IndexedCS;
     
    1264315282    isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
    1264415283      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
    12645     }
     15284    },
     15285    usesZeroToOneRange: true
    1264615286  };
    1264715287  return DeviceGrayCS;
     
    1266215302    getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
    1266315303                                                dest, destOffset) {
    12664       var r = src[srcOffset] * 255;
    12665       var g = src[srcOffset + 1] * 255;
    12666       var b = src[srcOffset + 2] * 255;
     15304      var r = (src[srcOffset] * 255) | 0;
     15305      var g = (src[srcOffset + 1] * 255) | 0;
     15306      var b = (src[srcOffset + 2] * 255) | 0;
    1266715307      dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
    1266815308      dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
     
    1267915319      var j = srcOffset, q = destOffset;
    1268015320      for (var i = 0; i < length; ++i) {
    12681         dest[q++] = (scale * input[j++]) | 0;
     15321        dest[q++] = (scale * src[j++]) | 0;
    1268215322      }
    1268315323    },
     
    1269115331    isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
    1269215332      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
    12693     }
     15333    },
     15334    usesZeroToOneRange: true
    1269415335  };
    1269515336  return DeviceRgbCS;
     
    1269715338
    1269815339var DeviceCmykCS = (function DeviceCmykCSClosure() {
    12699   // Sampled RGB colors from CMYK US Web Coated (SWOP) colorspace
    12700   var lut = new Uint8Array([
    12701     255, 255, 254, 221, 222, 223, 191, 193, 195, 161, 163, 166, 133, 136, 138,
    12702     105, 107, 109, 75, 75, 77, 35, 31, 32, 255, 252, 224, 226, 220, 198, 195,
    12703     191, 173, 164, 162, 147, 136, 134, 122, 107, 106, 96, 75, 74, 66, 33, 29,
    12704     24, 255, 249, 197, 229, 218, 174, 198, 190, 153, 166, 160, 129, 138, 133,
    12705     107, 108, 104, 83, 76, 73, 56, 33, 28, 15, 255, 247, 168, 232, 216, 149,
    12706     200, 188, 130, 168, 158, 110, 139, 131, 90, 110, 103, 70, 77, 72, 45, 32,
    12707     27, 4, 255, 245, 140, 234, 214, 124, 202, 186, 108, 170, 157, 91, 140, 130,
    12708     74, 110, 102, 56, 77, 71, 33, 31, 27, 0, 255, 243, 107, 235, 212, 95, 203,
    12709     184, 83, 171, 155, 69, 141, 129, 55, 111, 101, 40, 77, 70, 19, 29, 26, 0,
    12710     255, 241, 64, 237, 211, 59, 204, 183, 52, 171, 154, 42, 142, 128, 31, 111,
    12711     100, 16, 77, 69, 0, 27, 26, 0, 255, 240, 0, 238, 209, 0, 205, 182, 3, 172,
    12712     153, 0, 142, 127, 0, 112, 100, 0, 77, 69, 0, 26, 25, 0, 251, 225, 236, 218,
    12713     196, 207, 189, 171, 181, 160, 144, 154, 133, 120, 128, 105, 94, 101, 74, 64,
    12714     70, 35, 21, 25, 255, 222, 208, 222, 195, 184, 192, 169, 161, 162, 143, 136,
    12715     135, 118, 113, 106, 92, 88, 75, 63, 60, 34, 20, 17, 255, 220, 184, 225, 193,
    12716     162, 195, 168, 142, 164, 142, 120, 136, 117, 99, 107, 91, 77, 75, 62, 50,
    12717     33, 20, 8, 255, 218, 157, 227, 191, 139, 197, 166, 121, 165, 140, 102, 137,
    12718     116, 84, 108, 90, 64, 76, 61, 40, 32, 19, 0, 255, 216, 132, 229, 189, 116,
    12719     198, 165, 101, 167, 139, 85, 138, 115, 69, 109, 89, 51, 76, 61, 28, 31, 18,
    12720     0, 255, 214, 102, 230, 188, 90, 199, 163, 78, 167, 138, 65, 139, 114, 51,
    12721     109, 89, 35, 76, 60, 14, 29, 18, 0, 255, 213, 65, 232, 186, 58, 200, 162,
    12722     50, 168, 136, 39, 139, 113, 28, 110, 88, 12, 76, 60, 0, 27, 18, 0, 255, 212,
    12723     8, 232, 185, 13, 201, 161, 11, 169, 136, 3, 139, 112, 0, 110, 87, 0, 76, 59,
    12724     0, 26, 18, 0, 248, 197, 219, 216, 172, 192, 187, 150, 168, 158, 126, 143,
    12725     132, 104, 119, 104, 81, 93, 74, 54, 64, 35, 10, 19, 251, 195, 193, 219, 171,
    12726     171, 190, 149, 150, 161, 125, 127, 133, 103, 105, 106, 80, 81, 75, 53, 54,
    12727     34, 10, 10, 254, 193, 171, 221, 169, 151, 192, 148, 132, 162, 124, 112, 134,
    12728     102, 92, 106, 79, 70, 75, 52, 45, 34, 9, 1, 255, 191, 147, 223, 168, 130,
    12729     193, 146, 113, 163, 123, 95, 135, 101, 77, 107, 78, 58, 75, 52, 35, 32, 9,
    12730     0, 255, 190, 124, 225, 166, 109, 195, 145, 95, 164, 122, 79, 136, 100, 63,
    12731     107, 77, 46, 76, 51, 24, 31, 9, 0, 255, 188, 97, 226, 165, 85, 196, 143, 74,
    12732     165, 121, 60, 137, 99, 47, 108, 77, 31, 75, 51, 10, 29, 9, 0, 255, 187, 64,
    12733     227, 164, 56, 196, 142, 48, 165, 120, 37, 137, 98, 25, 108, 76, 9, 75, 50,
    12734     0, 28, 9, 0, 255, 186, 23, 228, 163, 21, 197, 142, 15, 166, 119, 5, 137, 98,
    12735     0, 108, 76, 0, 75, 50, 0, 27, 8, 0, 245, 168, 201, 214, 147, 177, 186, 128,
    12736     155, 157, 107, 131, 131, 88, 109, 104, 67, 85, 74, 42, 57, 35, 0, 12, 248,
    12737     166, 178, 216, 146, 157, 188, 127, 138, 159, 107, 116, 132, 87, 96, 105, 66,
    12738     74, 74, 41, 48, 35, 0, 3, 250, 165, 158, 218, 145, 139, 189, 126, 122, 160,
    12739     106, 103, 133, 86, 84, 105, 66, 64, 75, 41, 39, 33, 0, 0, 252, 164, 136,
    12740     220, 144, 120, 190, 125, 104, 161, 105, 87, 134, 86, 71, 106, 65, 52, 75,
    12741     41, 29, 32, 0, 0, 253, 162, 115, 221, 142, 101, 191, 124, 88, 161, 104, 72,
    12742     134, 85, 58, 106, 64, 41, 75, 40, 19, 31, 0, 0, 254, 161, 91, 222, 141, 80,
    12743     192, 123, 68, 162, 103, 55, 134, 84, 42, 106, 64, 26, 75, 40, 6, 29, 0, 0,
    12744     255, 160, 62, 223, 140, 54, 193, 122, 45, 162, 102, 34, 135, 83, 22, 106,
    12745     63, 5, 74, 40, 0, 28, 0, 0, 255, 159, 29, 223, 140, 25, 193, 121, 18, 163,
    12746     101, 7, 135, 83, 0, 107, 63, 0, 74, 40, 0, 28, 0, 0, 243, 142, 185, 212,
    12747     123, 163, 184, 107, 142, 156, 89, 120, 130, 72, 100, 104, 53, 77, 74, 29,
    12748     51, 35, 0, 4, 245, 140, 164, 214, 123, 145, 186, 106, 127, 157, 89, 107,
    12749     131, 72, 88, 104, 53, 67, 74, 29, 42, 34, 0, 0, 247, 139, 146, 215, 122,
    12750     129, 187, 106, 112, 158, 88, 94, 132, 71, 77, 104, 53, 57, 74, 29, 33, 33,
    12751     0, 0, 248, 138, 126, 217, 121, 111, 188, 105, 96, 159, 87, 80, 132, 70, 64,
    12752     105, 52, 47, 74, 29, 24, 31, 0, 0, 249, 137, 107, 218, 120, 94, 189, 104,
    12753     81, 159, 86, 66, 132, 70, 52, 105, 52, 36, 74, 29, 15, 30, 0, 0, 250, 136,
    12754     85, 218, 119, 74, 189, 103, 63, 160, 86, 51, 133, 69, 38, 105, 51, 22, 74,
    12755     29, 2, 29, 0, 0, 251, 135, 59, 219, 118, 51, 190, 102, 42, 160, 85, 31, 133,
    12756     69, 19, 105, 51, 3, 74, 29, 0, 29, 0, 0, 252, 134, 31, 219, 118, 26, 190,
    12757     102, 19, 160, 85, 7, 133, 69, 0, 105, 51, 0, 73, 29, 0, 28, 0, 0, 240, 113,
    12758     169, 210, 98, 149, 183, 84, 130, 155, 69, 110, 129, 54, 90, 103, 37, 70, 74,
    12759     11, 44, 32, 0, 1, 242, 111, 150, 212, 97, 132, 184, 84, 116, 156, 69, 97,
    12760     130, 54, 79, 103, 37, 60, 74, 12, 36, 31, 0, 0, 244, 111, 134, 213, 97, 118,
    12761     185, 83, 102, 157, 68, 86, 130, 54, 69, 104, 37, 51, 74, 13, 28, 30, 0, 0,
    12762     245, 110, 116, 214, 96, 102, 186, 83, 88, 157, 68, 73, 131, 53, 58, 104, 37,
    12763     41, 74, 14, 19, 29, 0, 0, 246, 110, 98, 215, 96, 86, 186, 82, 74, 157, 67,
    12764     60, 131, 53, 46, 104, 37, 30, 73, 14, 10, 28, 0, 0, 247, 109, 79, 215, 95,
    12765     69, 187, 82, 58, 158, 67, 46, 131, 53, 33, 104, 37, 18, 73, 15, 1, 28, 0, 0,
    12766     247, 108, 56, 216, 95, 48, 187, 82, 40, 158, 67, 29, 131, 53, 16, 104, 37,
    12767     0, 73, 15, 0, 27, 0, 0, 248, 108, 32, 216, 94, 27, 187, 81, 20, 158, 67, 8,
    12768     131, 53, 0, 104, 37, 0, 72, 16, 0, 27, 0, 0, 238, 78, 154, 208, 66, 135,
    12769     181, 55, 118, 154, 43, 99, 129, 30, 81, 103, 12, 62, 74, 0, 38, 27, 0, 0,
    12770     240, 77, 136, 210, 66, 120, 183, 56, 105, 155, 43, 88, 129, 30, 71, 103, 13,
    12771     53, 73, 0, 29, 26, 0, 0, 241, 77, 122, 211, 66, 107, 183, 56, 93, 155, 44,
    12772     77, 129, 31, 62, 103, 14, 44, 73, 0, 23, 26, 0, 0, 242, 77, 106, 211, 66,
    12773     92, 184, 56, 80, 155, 44, 65, 129, 31, 51, 103, 15, 35, 73, 0, 14, 25, 0, 0,
    12774     243, 77, 90, 212, 66, 79, 184, 56, 67, 156, 44, 54, 129, 32, 41, 103, 16,
    12775     25, 73, 0, 6, 25, 0, 0, 243, 77, 73, 213, 66, 63, 184, 56, 53, 156, 44, 41,
    12776     130, 32, 28, 103, 17, 13, 72, 0, 0, 25, 0, 0, 244, 77, 53, 213, 67, 45, 185,
    12777     56, 37, 156, 45, 26, 130, 33, 13, 103, 18, 0, 72, 0, 0, 25, 0, 0, 244, 77,
    12778     33, 213, 67, 28, 185, 57, 21, 156, 45, 9, 130, 33, 0, 103, 19, 0, 72, 0, 0,
    12779     24, 0, 0, 237, 13, 138, 207, 4, 122, 180, 0, 106, 153, 0, 89, 128, 0, 72,
    12780     102, 0, 54, 73, 0, 31, 21, 0, 0, 238, 16, 123, 208, 6, 108, 181, 0, 94, 154,
    12781     0, 78, 128, 0, 63, 102, 0, 46, 72, 0, 24, 21, 0, 0, 239, 20, 110, 209, 11,
    12782     96, 181, 1, 83, 154, 0, 69, 128, 0, 54, 102, 0, 38, 72, 0, 17, 22, 0, 0,
    12783     239, 23, 96, 209, 15, 84, 182, 5, 72, 154, 0, 58, 128, 0, 45, 102, 0, 29,
    12784     72, 0, 9, 22, 0, 0, 240, 26, 82, 210, 19, 71, 182, 10, 60, 154, 0, 48, 128,
    12785     0, 35, 102, 0, 20, 72, 0, 3, 22, 0, 0, 241, 27, 67, 210, 21, 58, 182, 14,
    12786     48, 154, 3, 37, 128, 0, 24, 102, 0, 8, 71, 0, 0, 22, 0, 0, 241, 29, 50, 210,
    12787     23, 42, 183, 17, 34, 154, 6, 23, 129, 0, 10, 102, 0, 0, 71, 0, 0, 22, 0, 0,
    12788     241, 30, 34, 211, 25, 28, 183, 19, 21, 155, 9, 10, 129, 0, 0, 102, 0, 0, 71,
    12789     0, 0, 22, 0, 0, 211, 239, 252, 184, 210, 221, 160, 183, 194, 135, 155, 164,
    12790     111, 128, 137, 87, 101, 109, 59, 70, 76, 22, 28, 32, 218, 237, 223, 190,
    12791     208, 196, 165, 181, 172, 139, 153, 146, 114, 127, 121, 89, 100, 95, 61, 69,
    12792     66, 21, 27, 25, 223, 235, 196, 195, 206, 174, 169, 179, 152, 142, 151, 129,
    12793     117, 126, 107, 91, 99, 83, 62, 68, 56, 20, 26, 17, 227, 232, 168, 198, 204,
    12794     149, 171, 177, 130, 144, 150, 110, 119, 124, 91, 93, 98, 70, 63, 68, 46, 20,
    12795     25, 6, 231, 230, 142, 201, 202, 125, 174, 176, 109, 146, 148, 92, 120, 123,
    12796     75, 94, 97, 57, 63, 67, 35, 19, 25, 0, 234, 229, 112, 203, 200, 98, 176,
    12797     174, 86, 147, 147, 71, 121, 122, 57, 94, 96, 42, 64, 66, 21, 17, 24, 0, 236,
    12798     227, 75, 205, 199, 66, 177, 173, 57, 148, 146, 47, 122, 121, 35, 95, 95, 21,
    12799     64, 65, 2, 14, 24, 0, 238, 226, 32, 207, 198, 30, 178, 172, 25, 149, 145,
    12800     17, 123, 120, 6, 95, 94, 0, 64, 65, 0, 11, 24, 0, 211, 211, 233, 184, 186,
    12801     206, 160, 162, 180, 135, 137, 153, 112, 113, 127, 88, 89, 100, 61, 60, 70,
    12802     23, 18, 26, 217, 209, 207, 190, 184, 183, 165, 161, 160, 139, 136, 136, 115,
    12803     112, 113, 90, 88, 88, 62, 59, 60, 23, 17, 19, 221, 208, 183, 193, 183, 162,
    12804     167, 159, 142, 141, 134, 120, 116, 111, 99, 91, 87, 77, 62, 59, 51, 22, 17,
    12805     10, 224, 206, 158, 196, 181, 139, 170, 157, 122, 143, 133, 103, 118, 110,
    12806     84, 92, 86, 64, 63, 58, 40, 22, 16, 0, 227, 204, 133, 198, 179, 118, 172,
    12807     156, 102, 144, 132, 86, 119, 109, 70, 93, 85, 52, 64, 57, 30, 20, 16, 0,
    12808     230, 203, 106, 200, 178, 93, 173, 155, 81, 145, 130, 67, 120, 108, 53, 94,
    12809     84, 37, 64, 57, 17, 17, 16, 0, 232, 201, 73, 202, 177, 64, 175, 154, 55,
    12810     146, 129, 44, 121, 107, 33, 94, 83, 18, 64, 56, 0, 15, 16, 0, 233, 201, 38,
    12811     203, 176, 32, 175, 153, 27, 147, 129, 18, 121, 106, 6, 94, 83, 0, 64, 56, 0,
    12812     13, 16, 0, 210, 186, 216, 184, 163, 191, 160, 143, 167, 136, 120, 142, 112,
    12813     99, 118, 88, 77, 93, 61, 50, 64, 24, 6, 21, 215, 184, 192, 189, 162, 170,
    12814     164, 141, 149, 138, 119, 126, 115, 98, 104, 90, 76, 81, 62, 50, 54, 24, 6,
    12815     12, 219, 183, 171, 192, 161, 151, 166, 140, 132, 140, 118, 112, 116, 97, 92,
    12816     91, 75, 71, 63, 49, 46, 23, 6, 3, 222, 181, 148, 194, 159, 130, 168, 139,
    12817     114, 142, 117, 95, 117, 96, 78, 92, 74, 59, 63, 49, 36, 22, 6, 0, 224, 180,
    12818     125, 196, 158, 110, 170, 138, 96, 143, 116, 80, 118, 95, 64, 92, 74, 47, 64,
    12819     48, 25, 20, 6, 0, 226, 178, 100, 197, 157, 88, 171, 136, 76, 144, 115, 62,
    12820     119, 94, 49, 93, 73, 33, 64, 48, 13, 18, 6, 0, 228, 177, 71, 199, 156, 62,
    12821     172, 135, 52, 144, 114, 41, 119, 94, 30, 93, 72, 14, 64, 47, 0, 16, 6, 0,
    12822     229, 177, 40, 200, 155, 34, 173, 135, 27, 145, 113, 18, 120, 93, 5, 93, 72,
    12823     0, 63, 47, 0, 15, 6, 0, 210, 159, 199, 184, 140, 176, 160, 122, 154, 136,
    12824     102, 131, 113, 84, 108, 89, 64, 85, 62, 39, 57, 25, 0, 14, 214, 158, 177,
    12825     188, 139, 157, 163, 121, 137, 138, 102, 116, 114, 83, 96, 90, 63, 74, 63,
    12826     38, 48, 25, 0, 5, 217, 157, 158, 190, 138, 139, 165, 120, 122, 139, 101,
    12827     103, 115, 82, 84, 91, 62, 64, 63, 38, 40, 23, 0, 0, 219, 156, 137, 192, 137,
    12828     120, 167, 119, 105, 140, 100, 88, 116, 82, 71, 91, 62, 53, 63, 38, 30, 22,
    12829     0, 0, 221, 155, 116, 193, 136, 102, 168, 118, 89, 141, 99, 73, 117, 81, 59,
    12830     92, 61, 42, 63, 38, 21, 20, 0, 0, 223, 153, 94, 195, 135, 82, 169, 117, 70,
    12831     142, 98, 57, 117, 80, 44, 92, 61, 29, 63, 37, 8, 18, 0, 0, 224, 153, 68,
    12832     196, 134, 58, 170, 116, 49, 143, 97, 38, 118, 80, 26, 92, 60, 11, 63, 37, 0,
    12833     17, 0, 0, 225, 152, 41, 197, 133, 34, 170, 116, 27, 143, 97, 17, 118, 79, 4,
    12834     92, 60, 0, 63, 37, 0, 16, 0, 0, 209, 134, 183, 183, 118, 162, 160, 102, 142,
    12835     136, 85, 120, 113, 69, 100, 89, 50, 77, 62, 26, 51, 23, 0, 6, 213, 133, 163,
    12836     187, 117, 144, 163, 102, 126, 137, 85, 107, 114, 68, 88, 90, 50, 67, 63, 26,
    12837     43, 22, 0, 1, 215, 133, 146, 188, 116, 129, 164, 101, 112, 139, 84, 94, 115,
    12838     68, 77, 91, 50, 58, 63, 27, 34, 20, 0, 0, 217, 132, 127, 190, 116, 111, 165,
    12839     100, 97, 139, 84, 81, 116, 67, 65, 91, 49, 48, 63, 27, 25, 19, 0, 0, 219,
    12840     131, 108, 191, 115, 95, 166, 100, 82, 140, 83, 68, 116, 67, 53, 91, 49, 37,
    12841     63, 27, 17, 17, 0, 0, 220, 130, 88, 192, 114, 76, 167, 99, 65, 141, 82, 53,
    12842     116, 66, 40, 91, 49, 24, 63, 27, 5, 16, 0, 0, 221, 129, 64, 193, 113, 55,
    12843     168, 98, 46, 141, 82, 35, 117, 66, 23, 91, 49, 7, 63, 27, 0, 14, 0, 0, 222,
    12844     129, 41, 194, 113, 34, 168, 98, 26, 141, 81, 16, 117, 66, 3, 92, 48, 0, 62,
    12845     27, 0, 13, 0, 0, 209, 108, 168, 183, 94, 148, 160, 81, 130, 135, 66, 110,
    12846     113, 51, 91, 89, 35, 70, 63, 8, 45, 18, 0, 1, 212, 107, 150, 186, 94, 132,
    12847     162, 81, 116, 137, 66, 97, 114, 52, 80, 90, 35, 60, 63, 9, 37, 16, 0, 0,
    12848     214, 107, 134, 187, 93, 118, 163, 80, 103, 138, 66, 86, 114, 51, 70, 90, 35,
    12849     52, 63, 10, 29, 15, 0, 0, 215, 106, 117, 188, 93, 103, 164, 80, 89, 138, 66,
    12850     74, 115, 51, 59, 90, 35, 42, 63, 11, 21, 13, 0, 0, 216, 106, 100, 189, 92,
    12851     88, 164, 79, 75, 139, 65, 62, 115, 51, 48, 91, 35, 32, 63, 12, 12, 12, 0, 0,
    12852     217, 105, 82, 190, 92, 71, 165, 79, 60, 139, 65, 48, 115, 51, 35, 91, 35,
    12853     20, 62, 13, 3, 11, 0, 0, 218, 105, 61, 191, 92, 52, 166, 79, 43, 140, 65,
    12854     32, 116, 51, 20, 91, 35, 3, 62, 14, 0, 10, 0, 0, 219, 104, 41, 192, 91, 34,
    12855     166, 78, 26, 140, 65, 15, 116, 51, 2, 91, 35, 0, 62, 14, 0, 10, 0, 0, 208,
    12856     76, 153, 183, 65, 135, 159, 54, 118, 135, 42, 99, 113, 29, 82, 89, 10, 62,
    12857     62, 0, 38, 10, 0, 0, 211, 76, 137, 185, 65, 121, 161, 55, 105, 136, 43, 88,
    12858     114, 30, 72, 90, 12, 54, 63, 0, 31, 9, 0, 0, 212, 76, 122, 186, 66, 108,
    12859     162, 55, 94, 137, 43, 78, 114, 30, 63, 90, 13, 45, 62, 0, 24, 9, 0, 0, 213,
    12860     76, 107, 187, 66, 94, 162, 55, 81, 137, 43, 67, 114, 31, 52, 90, 15, 36, 62,
    12861     0, 16, 8, 0, 0, 214, 76, 92, 188, 66, 80, 163, 55, 69, 138, 44, 56, 114, 31,
    12862     42, 90, 16, 27, 62, 0, 8, 8, 0, 0, 215, 76, 76, 188, 66, 65, 164, 55, 55,
    12863     138, 44, 43, 114, 32, 31, 90, 16, 16, 62, 0, 1, 7, 0, 0, 216, 76, 57, 189,
    12864     66, 49, 164, 56, 40, 138, 44, 29, 115, 32, 16, 90, 17, 1, 61, 0, 0, 7, 0, 0,
    12865     217, 76, 40, 190, 66, 33, 164, 56, 25, 138, 44, 14, 114, 33, 1, 90, 18, 0,
    12866     61, 0, 0, 7, 0, 0, 207, 26, 139, 182, 16, 122, 159, 3, 106, 135, 0, 89, 113,
    12867     0, 73, 89, 0, 55, 62, 0, 32, 4, 0, 0, 210, 27, 124, 184, 18, 109, 160, 7,
    12868     95, 136, 0, 79, 113, 0, 64, 90, 0, 47, 62, 0, 25, 4, 0, 0, 211, 30, 111,
    12869     185, 21, 98, 161, 11, 84, 136, 0, 70, 113, 0, 55, 90, 0, 39, 62, 0, 18, 4,
    12870     0, 0, 212, 32, 98, 185, 24, 85, 161, 15, 73, 136, 2, 60, 113, 0, 46, 90, 0,
    12871     30, 61, 0, 11, 4, 0, 0, 213, 34, 85, 186, 26, 73, 162, 17, 62, 137, 5, 50,
    12872     113, 0, 37, 89, 0, 22, 61, 0, 5, 4, 0, 0, 213, 35, 70, 187, 27, 60, 162, 19,
    12873     50, 137, 8, 39, 114, 0, 26, 89, 0, 11, 61, 0, 0, 4, 0, 0, 214, 35, 54, 187,
    12874     29, 45, 163, 21, 37, 137, 11, 26, 114, 0, 13, 89, 0, 0, 60, 0, 0, 4, 0, 0,
    12875     214, 35, 40, 188, 29, 32, 163, 22, 24, 137, 12, 13, 114, 0, 0, 89, 0, 0, 60,
    12876     0, 0, 4, 0, 0, 169, 226, 249, 148, 199, 219, 129, 173, 192, 108, 147, 163,
    12877     88, 122, 136, 68, 96, 108, 43, 66, 76, 4, 25, 33, 178, 224, 221, 156, 197,
    12878     195, 136, 172, 171, 114, 145, 145, 93, 121, 120, 71, 95, 95, 46, 65, 66, 4,
    12879     24, 25, 185, 222, 196, 162, 195, 173, 140, 170, 151, 117, 144, 128, 96, 119,
    12880     106, 74, 94, 83, 47, 65, 57, 4, 24, 18, 190, 220, 169, 166, 193, 149, 144,
    12881     168, 130, 120, 142, 110, 99, 118, 91, 76, 93, 70, 49, 64, 46, 3, 23, 8, 195,
    12882     218, 143, 170, 191, 126, 147, 167, 110, 123, 141, 93, 100, 117, 76, 77, 92,
    12883     58, 50, 63, 36, 3, 23, 0, 199, 216, 115, 173, 190, 101, 149, 165, 88, 125,
    12884     140, 74, 102, 116, 59, 78, 91, 43, 51, 63, 23, 0, 23, 0, 202, 215, 83, 176,
    12885     189, 72, 152, 164, 62, 126, 138, 51, 103, 115, 39, 79, 90, 25, 51, 62, 6, 0,
    12886     22, 0, 204, 214, 50, 178, 188, 43, 153, 163, 37, 127, 138, 28, 104, 114, 18,
    12887     80, 89, 3, 51, 62, 0, 0, 22, 0, 172, 200, 231, 152, 176, 204, 132, 154, 178,
    12888     111, 130, 152, 91, 108, 126, 70, 84, 100, 46, 57, 70, 9, 15, 27, 180, 198,
    12889     205, 158, 175, 182, 138, 153, 159, 116, 129, 135, 95, 107, 112, 73, 83, 88,
    12890     48, 56, 60, 8, 15, 20, 186, 197, 182, 163, 173, 161, 141, 151, 141, 119,
    12891     128, 119, 97, 106, 99, 75, 82, 77, 49, 55, 51, 8, 14, 11, 190, 195, 158,
    12892     166, 172, 139, 144, 150, 122, 121, 127, 103, 99, 105, 84, 77, 81, 65, 50,
    12893     55, 41, 8, 14, 2, 194, 193, 135, 169, 170, 119, 147, 148, 103, 123, 125, 87,
    12894     101, 104, 70, 78, 81, 53, 51, 54, 31, 5, 14, 0, 197, 192, 109, 172, 169, 96,
    12895     149, 147, 83, 124, 124, 69, 102, 103, 55, 79, 80, 39, 51, 54, 19, 2, 14, 0,
    12896     200, 191, 80, 174, 168, 69, 150, 146, 59, 126, 123, 48, 103, 102, 36, 79,
    12897     79, 22, 52, 53, 2, 0, 14, 0, 202, 190, 51, 176, 167, 43, 152, 145, 36, 127,
    12898     123, 27, 103, 101, 16, 80, 79, 1, 52, 53, 0, 0, 14, 0, 175, 176, 215, 154,
    12899     156, 190, 134, 136, 166, 113, 115, 141, 93, 94, 118, 72, 73, 93, 48, 47, 64,
    12900     12, 2, 22, 182, 175, 191, 160, 154, 169, 139, 135, 148, 117, 114, 126, 96,
    12901     94, 104, 75, 72, 81, 50, 47, 55, 12, 3, 14, 186, 174, 170, 163, 153, 151,
    12902     142, 134, 132, 119, 113, 111, 98, 93, 92, 76, 71, 71, 51, 46, 46, 11, 3, 5,
    12903     190, 172, 148, 166, 152, 130, 144, 132, 114, 121, 112, 96, 100, 92, 78, 77,
    12904     71, 59, 51, 46, 36, 9, 4, 0, 192, 171, 127, 169, 151, 111, 146, 131, 97,
    12905     123, 111, 81, 101, 91, 65, 78, 70, 48, 52, 45, 26, 6, 4, 0, 195, 170, 103,
    12906     171, 150, 90, 148, 130, 78, 124, 110, 64, 102, 90, 51, 79, 70, 35, 52, 45,
    12907     15, 3, 5, 0, 198, 169, 76, 173, 149, 66, 149, 129, 56, 125, 109, 45, 103,
    12908     89, 33, 79, 69, 18, 52, 45, 0, 1, 5, 0, 199, 168, 51, 174, 148, 43, 150,
    12909     129, 35, 126, 108, 26, 103, 89, 14, 80, 69, 0, 52, 45, 0, 0, 5, 0, 177, 151,
    12910     198, 156, 134, 175, 136, 117, 153, 115, 98, 130, 95, 80, 108, 74, 60, 85,
    12911     50, 36, 58, 11, 0, 15, 183, 150, 176, 161, 133, 156, 140, 116, 137, 118, 97,
    12912     116, 97, 79, 96, 76, 60, 74, 51, 36, 49, 11, 0, 6, 186, 150, 158, 163, 132,
    12913     139, 142, 115, 122, 120, 97, 103, 99, 79, 84, 77, 59, 64, 52, 36, 41, 9, 0,
    12914     1, 189, 148, 137, 166, 131, 121, 144, 114, 105, 121, 96, 88, 100, 78, 72,
    12915     78, 59, 54, 52, 36, 31, 7, 0, 0, 191, 147, 118, 168, 130, 103, 145, 113, 90,
    12916     122, 95, 75, 101, 77, 60, 78, 59, 43, 52, 35, 22, 5, 0, 0, 193, 147, 97,
    12917     169, 129, 84, 147, 112, 72, 123, 94, 59, 101, 77, 46, 79, 58, 31, 52, 35,
    12918     11, 4, 0, 0, 195, 146, 73, 171, 128, 62, 148, 111, 53, 124, 93, 41, 102, 76,
    12919     30, 79, 58, 15, 52, 35, 0, 3, 0, 0, 197, 145, 50, 172, 128, 42, 149, 111,
    12920     34, 125, 93, 24, 102, 76, 12, 79, 57, 0, 52, 35, 0, 2, 0, 0, 179, 128, 183,
    12921     157, 113, 162, 137, 98, 142, 116, 82, 120, 96, 66, 100, 75, 48, 78, 51, 24,
    12922     52, 5, 0, 8, 183, 128, 163, 161, 113, 144, 140, 98, 126, 119, 81, 107, 98,
    12923     65, 88, 76, 48, 68, 52, 24, 43, 6, 0, 1, 186, 127, 146, 163, 112, 129, 142,
    12924     97, 112, 120, 81, 95, 99, 65, 77, 77, 47, 58, 52, 24, 35, 4, 0, 0, 188, 126,
    12925     128, 165, 111, 112, 144, 96, 97, 121, 80, 81, 100, 65, 66, 78, 47, 48, 53,
    12926     24, 26, 3, 0, 0, 190, 126, 110, 167, 110, 96, 145, 96, 83, 122, 80, 69, 101,
    12927     64, 54, 78, 47, 38, 52, 25, 18, 2, 0, 0, 192, 125, 90, 168, 110, 79, 146,
    12928     95, 67, 123, 79, 54, 101, 64, 42, 79, 47, 26, 52, 25, 7, 2, 0, 0, 194, 124,
    12929     69, 170, 109, 59, 147, 95, 49, 123, 79, 38, 101, 63, 26, 79, 47, 11, 52, 25,
    12930     0, 1, 0, 0, 195, 124, 49, 171, 109, 40, 148, 94, 32, 124, 78, 22, 102, 63,
    12931     9, 79, 46, 0, 52, 25, 0, 1, 0, 0, 180, 104, 168, 158, 91, 148, 138, 78, 130,
    12932     117, 64, 110, 97, 49, 91, 76, 33, 70, 52, 7, 46, 2, 0, 1, 184, 103, 150,
    12933     162, 91, 133, 141, 78, 116, 119, 64, 98, 99, 50, 80, 77, 33, 61, 52, 8, 37,
    12934     2, 0, 0, 186, 103, 135, 163, 90, 119, 142, 78, 103, 120, 64, 87, 99, 50, 70,
    12935     78, 33, 52, 52, 10, 30, 1, 0, 0, 188, 103, 118, 165, 90, 103, 143, 77, 90,
    12936     121, 63, 75, 100, 49, 60, 78, 33, 43, 52, 11, 22, 1, 0, 0, 189, 102, 102,
    12937     166, 89, 89, 144, 77, 76, 121, 63, 63, 100, 49, 49, 78, 34, 33, 52, 12, 14,
    12938     0, 0, 0, 191, 102, 84, 167, 89, 73, 145, 77, 62, 122, 63, 50, 101, 49, 37,
    12939     78, 34, 22, 52, 13, 4, 0, 0, 0, 192, 101, 65, 168, 89, 55, 146, 76, 46, 123,
    12940     63, 35, 101, 49, 23, 78, 34, 7, 51, 13, 0, 0, 0, 0, 193, 101, 48, 169, 88,
    12941     39, 146, 76, 31, 123, 63, 20, 101, 49, 8, 78, 34, 0, 51, 14, 0, 0, 0, 0,
    12942     181, 75, 154, 159, 64, 136, 139, 54, 118, 118, 41, 100, 98, 28, 82, 77, 8,
    12943     63, 51, 0, 39, 0, 0, 0, 184, 75, 137, 162, 65, 121, 141, 54, 106, 119, 42,
    12944     89, 99, 29, 72, 77, 11, 54, 52, 0, 32, 0, 0, 0, 186, 75, 123, 163, 65, 109,
    12945     142, 54, 94, 120, 43, 79, 99, 30, 63, 78, 12, 46, 52, 0, 25, 0, 0, 0, 187,
    12946     76, 108, 164, 65, 95, 143, 55, 82, 121, 43, 68, 100, 31, 54, 78, 14, 37, 52,
    12947     0, 17, 0, 0, 0, 188, 76, 94, 165, 65, 82, 144, 55, 70, 121, 43, 57, 100, 31,
    12948     44, 78, 15, 28, 51, 0, 9, 0, 0, 0, 189, 75, 78, 166, 65, 68, 144, 55, 57,
    12949     121, 43, 45, 100, 31, 33, 78, 16, 18, 51, 0, 2, 0, 0, 0, 190, 75, 61, 167,
    12950     65, 52, 145, 55, 42, 122, 44, 31, 100, 32, 19, 78, 16, 4, 51, 0, 0, 0, 0, 0,
    12951     191, 75, 46, 168, 65, 37, 145, 55, 29, 122, 44, 18, 100, 32, 5, 78, 17, 0,
    12952     50, 0, 0, 0, 0, 0, 181, 35, 140, 160, 24, 123, 140, 12, 107, 118, 0, 90, 98,
    12953     0, 74, 77, 0, 56, 51, 0, 33, 0, 0, 0, 184, 34, 125, 162, 26, 110, 141, 15,
    12954     96, 120, 1, 80, 99, 0, 65, 78, 0, 48, 51, 0, 26, 0, 0, 0, 186, 36, 113, 163,
    12955     27, 99, 142, 18, 86, 120, 5, 71, 99, 0, 57, 78, 0, 40, 51, 0, 20, 0, 0, 0,
    12956     187, 38, 99, 164, 30, 87, 142, 21, 74, 120, 8, 61, 99, 0, 48, 78, 0, 32, 51,
    12957     0, 12, 0, 0, 0, 187, 39, 87, 164, 31, 75, 143, 22, 64, 120, 11, 51, 100, 0,
    12958     39, 78, 0, 24, 51, 0, 6, 0, 0, 0, 188, 40, 73, 165, 32, 62, 143, 24, 52,
    12959     121, 13, 40, 100, 0, 28, 78, 0, 14, 51, 0, 0, 0, 0, 0, 189, 40, 58, 166, 33,
    12960     48, 144, 25, 39, 121, 15, 28, 100, 1, 16, 78, 0, 2, 50, 0, 0, 0, 0, 0, 190,
    12961     40, 45, 166, 34, 36, 144, 26, 27, 121, 16, 17, 100, 3, 3, 77, 0, 0, 49, 0,
    12962     0, 0, 0, 0, 120, 213, 247, 106, 188, 217, 92, 164, 190, 76, 139, 162, 60,
    12963     115, 135, 43, 91, 107, 21, 62, 76, 0, 22, 34, 134, 211, 219, 118, 186, 193,
    12964     102, 162, 169, 84, 138, 144, 67, 114, 120, 49, 90, 95, 26, 62, 66, 0, 22,
    12965     26, 143, 209, 195, 125, 184, 172, 108, 161, 151, 90, 136, 128, 72, 113, 106,
    12966     53, 89, 83, 29, 61, 57, 0, 22, 19, 150, 207, 169, 131, 182, 149, 113, 159,
    12967     130, 94, 135, 110, 76, 112, 91, 56, 88, 71, 31, 60, 47, 0, 21, 9, 156, 205,
    12968     145, 136, 181, 127, 117, 158, 111, 97, 133, 94, 78, 111, 77, 58, 87, 59, 33,
    12969     60, 37, 0, 21, 0, 161, 204, 118, 141, 179, 104, 121, 156, 90, 100, 132, 75,
    12970     81, 110, 61, 60, 86, 45, 35, 59, 25, 0, 21, 0, 165, 203, 89, 144, 178, 77,
    12971     124, 155, 67, 102, 131, 55, 82, 109, 43, 62, 85, 29, 36, 59, 10, 0, 21, 0,
    12972     169, 202, 62, 147, 178, 53, 126, 155, 45, 104, 131, 36, 84, 108, 25, 62, 85,
    12973     11, 36, 58, 0, 0, 21, 0, 129, 189, 229, 114, 167, 202, 99, 146, 177, 83,
    12974     124, 151, 67, 102, 126, 49, 79, 99, 28, 53, 70, 0, 12, 28, 140, 188, 204,
    12975     124, 166, 180, 107, 145, 158, 89, 123, 134, 72, 101, 111, 54, 79, 88, 31,
    12976     53, 60, 0, 12, 21, 148, 186, 182, 130, 164, 161, 112, 144, 141, 93, 121,
    12977     119, 76, 100, 99, 56, 78, 77, 33, 52, 51, 0, 12, 13, 153, 184, 158, 134,
    12978     163, 140, 116, 142, 122, 97, 120, 103, 78, 99, 85, 59, 77, 65, 35, 52, 42,
    12979     0, 12, 3, 158, 183, 136, 138, 161, 120, 119, 141, 104, 99, 119, 87, 80, 98,
    12980     71, 60, 77, 54, 36, 51, 32, 0, 12, 0, 162, 182, 112, 142, 160, 98, 122, 140,
    12981     85, 102, 118, 70, 82, 97, 56, 62, 76, 41, 37, 51, 21, 0, 11, 0, 166, 181,
    12982     85, 145, 159, 74, 125, 139, 63, 103, 117, 51, 84, 97, 39, 63, 75, 25, 37,
    12983     51, 6, 0, 11, 0, 168, 180, 60, 147, 158, 51, 126, 138, 43, 105, 116, 34, 85,
    12984     96, 23, 64, 75, 8, 38, 50, 0, 0, 11, 0, 136, 167, 213, 120, 148, 188, 105,
    12985     129, 165, 88, 109, 140, 71, 90, 117, 54, 69, 92, 32, 44, 64, 0, 2, 23, 145,
    12986     166, 190, 128, 147, 168, 111, 128, 147, 93, 108, 125, 75, 89, 104, 57, 68,
    12987     81, 34, 44, 55, 0, 2, 15, 151, 165, 170, 133, 146, 150, 115, 127, 131, 96,
    12988     107, 111, 78, 88, 92, 59, 68, 71, 36, 43, 46, 0, 2, 6, 155, 163, 148, 136,
    12989     144, 131, 118, 126, 114, 99, 106, 96, 80, 87, 79, 61, 67, 60, 37, 43, 37, 0,
    12990     2, 0, 159, 162, 128, 140, 143, 112, 121, 125, 97, 101, 105, 82, 82, 87, 66,
    12991     62, 67, 49, 38, 43, 27, 0, 2, 0, 163, 161, 105, 142, 142, 92, 123, 124, 80,
    12992     103, 104, 66, 83, 86, 52, 63, 66, 37, 39, 43, 17, 0, 2, 0, 166, 160, 81,
    12993     145, 141, 70, 125, 123, 59, 104, 104, 48, 84, 85, 36, 64, 66, 21, 39, 42, 2,
    12994     0, 1, 0, 168, 160, 59, 147, 141, 50, 126, 122, 41, 105, 103, 32, 85, 85, 20,
    12995     64, 65, 6, 39, 42, 0, 0, 1, 0, 142, 144, 197, 125, 128, 174, 109, 111, 153,
    12996     92, 93, 130, 75, 76, 108, 57, 57, 85, 36, 33, 58, 0, 0, 16, 149, 143, 176,
    12997     131, 127, 156, 114, 110, 136, 96, 93, 116, 78, 75, 96, 60, 57, 74, 37, 33,
    12998     49, 0, 0, 7, 153, 142, 157, 135, 126, 139, 117, 110, 122, 98, 92, 103, 80,
    12999     75, 84, 61, 56, 65, 38, 33, 41, 0, 0, 1, 157, 142, 138, 138, 125, 121, 120,
    13000     109, 106, 100, 91, 89, 82, 74, 72, 62, 56, 54, 39, 33, 32, 0, 0, 0, 160,
    13001     141, 119, 140, 124, 105, 122, 108, 91, 102, 91, 76, 83, 74, 61, 63, 56, 44,
    13002     40, 33, 23, 0, 0, 0, 163, 140, 99, 143, 123, 86, 124, 107, 74, 103, 90, 61,
    13003     84, 73, 48, 64, 55, 32, 40, 33, 13, 0, 0, 0, 165, 139, 77, 145, 122, 66,
    13004     125, 107, 56, 104, 89, 44, 85, 73, 33, 65, 55, 18, 40, 33, 1, 0, 0, 0, 167,
    13005     139, 57, 146, 122, 48, 126, 106, 39, 105, 89, 29, 86, 72, 18, 65, 55, 3, 40,
    13006     33, 0, 0, 0, 0, 146, 123, 182, 129, 108, 161, 113, 94, 141, 95, 78, 120, 78,
    13007     62, 99, 60, 45, 78, 38, 21, 52, 0, 0, 9, 152, 122, 163, 134, 108, 144, 117,
    13008     94, 126, 98, 78, 107, 80, 62, 88, 61, 45, 68, 39, 22, 44, 0, 0, 1, 156, 122,
    13009     146, 137, 107, 129, 119, 93, 113, 100, 77, 95, 82, 62, 78, 63, 45, 59, 40,
    13010     22, 36, 0, 0, 0, 158, 121, 128, 139, 107, 113, 121, 92, 98, 101, 77, 82, 83,
    13011     62, 66, 64, 45, 49, 40, 23, 27, 0, 0, 0, 161, 120, 111, 141, 106, 97, 122,
    13012     92, 84, 103, 77, 70, 84, 62, 56, 64, 45, 40, 40, 23, 19, 0, 0, 0, 163, 120,
    13013     93, 143, 105, 81, 124, 91, 69, 104, 76, 56, 85, 61, 43, 65, 45, 28, 40, 24,
    13014     9, 0, 0, 0, 165, 119, 73, 145, 105, 62, 125, 91, 52, 105, 76, 41, 85, 61,
    13015     29, 65, 44, 15, 40, 24, 0, 0, 0, 0, 166, 119, 55, 146, 104, 46, 126, 90, 37,
    13016     105, 75, 27, 86, 61, 15, 65, 44, 0, 40, 24, 0, 0, 0, 0, 150, 100, 168, 132,
    13017     88, 148, 115, 75, 130, 97, 61, 110, 80, 47, 91, 62, 30, 71, 39, 7, 46, 0, 0,
    13018     2, 154, 100, 150, 136, 88, 133, 119, 75, 116, 100, 61, 98, 82, 47, 81, 63,
    13019     31, 62, 40, 9, 38, 0, 0, 0, 157, 100, 135, 138, 87, 119, 120, 75, 104, 101,
    13020     61, 87, 83, 48, 71, 64, 31, 53, 40, 10, 31, 0, 0, 0, 159, 99, 119, 140, 87,
    13021     104, 122, 75, 91, 102, 61, 75, 84, 48, 61, 64, 32, 44, 40, 11, 23, 0, 0, 0,
    13022     161, 99, 104, 141, 87, 90, 123, 74, 78, 103, 61, 64, 84, 48, 50, 65, 32, 35,
    13023     40, 12, 15, 0, 0, 0, 163, 99, 87, 143, 86, 75, 124, 74, 64, 104, 61, 52, 85,
    13024     47, 39, 65, 32, 24, 40, 13, 6, 0, 0, 0, 164, 98, 69, 144, 86, 58, 125, 74,
    13025     49, 104, 61, 38, 85, 47, 26, 65, 32, 11, 40, 13, 0, 0, 0, 0, 166, 98, 53,
    13026     145, 86, 44, 126, 74, 35, 105, 60, 25, 86, 47, 13, 65, 32, 0, 40, 14, 0, 0,
    13027     0, 0, 152, 75, 154, 134, 64, 136, 117, 53, 119, 99, 41, 101, 82, 27, 83, 63,
    13028     7, 64, 39, 0, 40, 0, 0, 0, 156, 74, 138, 138, 64, 122, 120, 53, 106, 101,
    13029     41, 90, 83, 28, 73, 64, 10, 55, 40, 0, 33, 0, 0, 0, 158, 74, 124, 139, 64,
    13030     110, 121, 54, 95, 102, 42, 80, 84, 29, 64, 65, 12, 47, 41, 0, 26, 0, 0, 0,
    13031     160, 75, 110, 140, 64, 96, 122, 54, 83, 103, 42, 69, 84, 30, 55, 65, 13, 39,
    13032     41, 0, 18, 0, 0, 0, 161, 75, 96, 142, 64, 83, 123, 54, 71, 103, 43, 58, 85,
    13033     30, 45, 65, 14, 30, 41, 0, 11, 0, 0, 0, 163, 75, 81, 143, 64, 70, 124, 54,
    13034     59, 104, 43, 47, 85, 31, 35, 65, 15, 20, 41, 0, 3, 0, 0, 0, 164, 74, 65,
    13035     144, 64, 55, 125, 54, 45, 104, 43, 34, 85, 31, 22, 66, 16, 7, 41, 0, 0, 0,
    13036     0, 0, 165, 74, 51, 145, 64, 42, 125, 54, 33, 105, 43, 22, 86, 32, 10, 65,
    13037     17, 0, 40, 0, 0, 0, 0, 0, 154, 41, 142, 136, 30, 124, 119, 19, 108, 101, 3,
    13038