Built motion from commit 1020cd7.|0.0.107
[motion.git] / public / assets / plugins / angular-pdf / example / js / lib / pdf.worker.js
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
3 /* Copyright 2012 Mozilla Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 /*jshint globalstrict: false */
18 /* globals PDFJS */
19
20 // Initializing PDFJS global object (if still undefined)
21 if (typeof PDFJS === 'undefined') {
22   (typeof window !== 'undefined' ? window : this).PDFJS = {};
23 }
24
25 PDFJS.version = '1.1.159';
26 PDFJS.build = '82536f8';
27
28 (function pdfjsWrapper() {
29   // Use strict in our context only - users might not want it
30   'use strict';
31
32 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
33 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
34 /* Copyright 2012 Mozilla Foundation
35  *
36  * Licensed under the Apache License, Version 2.0 (the "License");
37  * you may not use this file except in compliance with the License.
38  * You may obtain a copy of the License at
39  *
40  *     http://www.apache.org/licenses/LICENSE-2.0
41  *
42  * Unless required by applicable law or agreed to in writing, software
43  * distributed under the License is distributed on an "AS IS" BASIS,
44  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45  * See the License for the specific language governing permissions and
46  * limitations under the License.
47  */
48 /* globals Cmd, ColorSpace, Dict, MozBlobBuilder, Name, PDFJS, Ref, URL,
49            Promise */
50
51 'use strict';
52
53 var globalScope = (typeof window === 'undefined') ? this : window;
54
55 var isWorker = (typeof window === 'undefined');
56
57 var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
58
59 var TextRenderingMode = {
60   FILL: 0,
61   STROKE: 1,
62   FILL_STROKE: 2,
63   INVISIBLE: 3,
64   FILL_ADD_TO_PATH: 4,
65   STROKE_ADD_TO_PATH: 5,
66   FILL_STROKE_ADD_TO_PATH: 6,
67   ADD_TO_PATH: 7,
68   FILL_STROKE_MASK: 3,
69   ADD_TO_PATH_FLAG: 4
70 };
71
72 var ImageKind = {
73   GRAYSCALE_1BPP: 1,
74   RGB_24BPP: 2,
75   RGBA_32BPP: 3
76 };
77
78 var AnnotationType = {
79   WIDGET: 1,
80   TEXT: 2,
81   LINK: 3
82 };
83
84 var StreamType = {
85   UNKNOWN: 0,
86   FLATE: 1,
87   LZW: 2,
88   DCT: 3,
89   JPX: 4,
90   JBIG: 5,
91   A85: 6,
92   AHX: 7,
93   CCF: 8,
94   RL: 9
95 };
96
97 var FontType = {
98   UNKNOWN: 0,
99   TYPE1: 1,
100   TYPE1C: 2,
101   CIDFONTTYPE0: 3,
102   CIDFONTTYPE0C: 4,
103   TRUETYPE: 5,
104   CIDFONTTYPE2: 6,
105   TYPE3: 7,
106   OPENTYPE: 8,
107   TYPE0: 9,
108   MMTYPE1: 10
109 };
110
111 // The global PDFJS object exposes the API
112 // In production, it will be declared outside a global wrapper
113 // In development, it will be declared here
114 if (!globalScope.PDFJS) {
115   globalScope.PDFJS = {};
116 }
117
118 globalScope.PDFJS.pdfBug = false;
119
120 PDFJS.VERBOSITY_LEVELS = {
121   errors: 0,
122   warnings: 1,
123   infos: 5
124 };
125
126 // All the possible operations for an operator list.
127 var OPS = PDFJS.OPS = {
128   // Intentionally start from 1 so it is easy to spot bad operators that will be
129   // 0's.
130   dependency: 1,
131   setLineWidth: 2,
132   setLineCap: 3,
133   setLineJoin: 4,
134   setMiterLimit: 5,
135   setDash: 6,
136   setRenderingIntent: 7,
137   setFlatness: 8,
138   setGState: 9,
139   save: 10,
140   restore: 11,
141   transform: 12,
142   moveTo: 13,
143   lineTo: 14,
144   curveTo: 15,
145   curveTo2: 16,
146   curveTo3: 17,
147   closePath: 18,
148   rectangle: 19,
149   stroke: 20,
150   closeStroke: 21,
151   fill: 22,
152   eoFill: 23,
153   fillStroke: 24,
154   eoFillStroke: 25,
155   closeFillStroke: 26,
156   closeEOFillStroke: 27,
157   endPath: 28,
158   clip: 29,
159   eoClip: 30,
160   beginText: 31,
161   endText: 32,
162   setCharSpacing: 33,
163   setWordSpacing: 34,
164   setHScale: 35,
165   setLeading: 36,
166   setFont: 37,
167   setTextRenderingMode: 38,
168   setTextRise: 39,
169   moveText: 40,
170   setLeadingMoveText: 41,
171   setTextMatrix: 42,
172   nextLine: 43,
173   showText: 44,
174   showSpacedText: 45,
175   nextLineShowText: 46,
176   nextLineSetSpacingShowText: 47,
177   setCharWidth: 48,
178   setCharWidthAndBounds: 49,
179   setStrokeColorSpace: 50,
180   setFillColorSpace: 51,
181   setStrokeColor: 52,
182   setStrokeColorN: 53,
183   setFillColor: 54,
184   setFillColorN: 55,
185   setStrokeGray: 56,
186   setFillGray: 57,
187   setStrokeRGBColor: 58,
188   setFillRGBColor: 59,
189   setStrokeCMYKColor: 60,
190   setFillCMYKColor: 61,
191   shadingFill: 62,
192   beginInlineImage: 63,
193   beginImageData: 64,
194   endInlineImage: 65,
195   paintXObject: 66,
196   markPoint: 67,
197   markPointProps: 68,
198   beginMarkedContent: 69,
199   beginMarkedContentProps: 70,
200   endMarkedContent: 71,
201   beginCompat: 72,
202   endCompat: 73,
203   paintFormXObjectBegin: 74,
204   paintFormXObjectEnd: 75,
205   beginGroup: 76,
206   endGroup: 77,
207   beginAnnotations: 78,
208   endAnnotations: 79,
209   beginAnnotation: 80,
210   endAnnotation: 81,
211   paintJpegXObject: 82,
212   paintImageMaskXObject: 83,
213   paintImageMaskXObjectGroup: 84,
214   paintImageXObject: 85,
215   paintInlineImageXObject: 86,
216   paintInlineImageXObjectGroup: 87,
217   paintImageXObjectRepeat: 88,
218   paintImageMaskXObjectRepeat: 89,
219   paintSolidColorImageMask: 90,
220   constructPath: 91
221 };
222
223 // A notice for devs. These are good for things that are helpful to devs, such
224 // as warning that Workers were disabled, which is important to devs but not
225 // end users.
226 function info(msg) {
227   if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) {
228     console.log('Info: ' + msg);
229   }
230 }
231
232 // Non-fatal warnings.
233 function warn(msg) {
234   if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) {
235     console.log('Warning: ' + msg);
236   }
237 }
238
239 // Fatal errors that should trigger the fallback UI and halt execution by
240 // throwing an exception.
241 function error(msg) {
242   if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.errors) {
243     console.log('Error: ' + msg);
244     console.log(backtrace());
245   }
246   UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
247   throw new Error(msg);
248 }
249
250 function backtrace() {
251   try {
252     throw new Error();
253   } catch (e) {
254     return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
255   }
256 }
257
258 function assert(cond, msg) {
259   if (!cond) {
260     error(msg);
261   }
262 }
263
264 var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
265   unknown: 'unknown',
266   forms: 'forms',
267   javaScript: 'javaScript',
268   smask: 'smask',
269   shadingPattern: 'shadingPattern',
270   font: 'font'
271 };
272
273 var UnsupportedManager = PDFJS.UnsupportedManager =
274   (function UnsupportedManagerClosure() {
275   var listeners = [];
276   return {
277     listen: function (cb) {
278       listeners.push(cb);
279     },
280     notify: function (featureId) {
281       warn('Unsupported feature "' + featureId + '"');
282       for (var i = 0, ii = listeners.length; i < ii; i++) {
283         listeners[i](featureId);
284       }
285     }
286   };
287 })();
288
289 // Combines two URLs. The baseUrl shall be absolute URL. If the url is an
290 // absolute URL, it will be returned as is.
291 function combineUrl(baseUrl, url) {
292   if (!url) {
293     return baseUrl;
294   }
295   if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
296     return url;
297   }
298   var i;
299   if (url.charAt(0) === '/') {
300     // absolute path
301     i = baseUrl.indexOf('://');
302     if (url.charAt(1) === '/') {
303       ++i;
304     } else {
305       i = baseUrl.indexOf('/', i + 3);
306     }
307     return baseUrl.substring(0, i) + url;
308   } else {
309     // relative path
310     var pathLength = baseUrl.length;
311     i = baseUrl.lastIndexOf('#');
312     pathLength = i >= 0 ? i : pathLength;
313     i = baseUrl.lastIndexOf('?', pathLength);
314     pathLength = i >= 0 ? i : pathLength;
315     var prefixLength = baseUrl.lastIndexOf('/', pathLength);
316     return baseUrl.substring(0, prefixLength + 1) + url;
317   }
318 }
319
320 // Validates if URL is safe and allowed, e.g. to avoid XSS.
321 function isValidUrl(url, allowRelative) {
322   if (!url) {
323     return false;
324   }
325   // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1)
326   // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
327   var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url);
328   if (!protocol) {
329     return allowRelative;
330   }
331   protocol = protocol[0].toLowerCase();
332   switch (protocol) {
333     case 'http':
334     case 'https':
335     case 'ftp':
336     case 'mailto':
337     case 'tel':
338       return true;
339     default:
340       return false;
341   }
342 }
343 PDFJS.isValidUrl = isValidUrl;
344
345 function shadow(obj, prop, value) {
346   Object.defineProperty(obj, prop, { value: value,
347                                      enumerable: true,
348                                      configurable: true,
349                                      writable: false });
350   return value;
351 }
352 PDFJS.shadow = shadow;
353
354 var PasswordResponses = PDFJS.PasswordResponses = {
355   NEED_PASSWORD: 1,
356   INCORRECT_PASSWORD: 2
357 };
358
359 var PasswordException = (function PasswordExceptionClosure() {
360   function PasswordException(msg, code) {
361     this.name = 'PasswordException';
362     this.message = msg;
363     this.code = code;
364   }
365
366   PasswordException.prototype = new Error();
367   PasswordException.constructor = PasswordException;
368
369   return PasswordException;
370 })();
371 PDFJS.PasswordException = PasswordException;
372
373 var UnknownErrorException = (function UnknownErrorExceptionClosure() {
374   function UnknownErrorException(msg, details) {
375     this.name = 'UnknownErrorException';
376     this.message = msg;
377     this.details = details;
378   }
379
380   UnknownErrorException.prototype = new Error();
381   UnknownErrorException.constructor = UnknownErrorException;
382
383   return UnknownErrorException;
384 })();
385 PDFJS.UnknownErrorException = UnknownErrorException;
386
387 var InvalidPDFException = (function InvalidPDFExceptionClosure() {
388   function InvalidPDFException(msg) {
389     this.name = 'InvalidPDFException';
390     this.message = msg;
391   }
392
393   InvalidPDFException.prototype = new Error();
394   InvalidPDFException.constructor = InvalidPDFException;
395
396   return InvalidPDFException;
397 })();
398 PDFJS.InvalidPDFException = InvalidPDFException;
399
400 var MissingPDFException = (function MissingPDFExceptionClosure() {
401   function MissingPDFException(msg) {
402     this.name = 'MissingPDFException';
403     this.message = msg;
404   }
405
406   MissingPDFException.prototype = new Error();
407   MissingPDFException.constructor = MissingPDFException;
408
409   return MissingPDFException;
410 })();
411 PDFJS.MissingPDFException = MissingPDFException;
412
413 var UnexpectedResponseException =
414     (function UnexpectedResponseExceptionClosure() {
415   function UnexpectedResponseException(msg, status) {
416     this.name = 'UnexpectedResponseException';
417     this.message = msg;
418     this.status = status;
419   }
420
421   UnexpectedResponseException.prototype = new Error();
422   UnexpectedResponseException.constructor = UnexpectedResponseException;
423
424   return UnexpectedResponseException;
425 })();
426 PDFJS.UnexpectedResponseException = UnexpectedResponseException;
427
428 var NotImplementedException = (function NotImplementedExceptionClosure() {
429   function NotImplementedException(msg) {
430     this.message = msg;
431   }
432
433   NotImplementedException.prototype = new Error();
434   NotImplementedException.prototype.name = 'NotImplementedException';
435   NotImplementedException.constructor = NotImplementedException;
436
437   return NotImplementedException;
438 })();
439
440 var MissingDataException = (function MissingDataExceptionClosure() {
441   function MissingDataException(begin, end) {
442     this.begin = begin;
443     this.end = end;
444     this.message = 'Missing data [' + begin + ', ' + end + ')';
445   }
446
447   MissingDataException.prototype = new Error();
448   MissingDataException.prototype.name = 'MissingDataException';
449   MissingDataException.constructor = MissingDataException;
450
451   return MissingDataException;
452 })();
453
454 var XRefParseException = (function XRefParseExceptionClosure() {
455   function XRefParseException(msg) {
456     this.message = msg;
457   }
458
459   XRefParseException.prototype = new Error();
460   XRefParseException.prototype.name = 'XRefParseException';
461   XRefParseException.constructor = XRefParseException;
462
463   return XRefParseException;
464 })();
465
466
467 function bytesToString(bytes) {
468   assert(bytes !== null && typeof bytes === 'object' &&
469          bytes.length !== undefined, 'Invalid argument for bytesToString');
470   var length = bytes.length;
471   var MAX_ARGUMENT_COUNT = 8192;
472   if (length < MAX_ARGUMENT_COUNT) {
473     return String.fromCharCode.apply(null, bytes);
474   }
475   var strBuf = [];
476   for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
477     var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
478     var chunk = bytes.subarray(i, chunkEnd);
479     strBuf.push(String.fromCharCode.apply(null, chunk));
480   }
481   return strBuf.join('');
482 }
483
484 function stringToBytes(str) {
485   assert(typeof str === 'string', 'Invalid argument for stringToBytes');
486   var length = str.length;
487   var bytes = new Uint8Array(length);
488   for (var i = 0; i < length; ++i) {
489     bytes[i] = str.charCodeAt(i) & 0xFF;
490   }
491   return bytes;
492 }
493
494 function string32(value) {
495   return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
496                              (value >> 8) & 0xff, value & 0xff);
497 }
498
499 function log2(x) {
500   var n = 1, i = 0;
501   while (x > n) {
502     n <<= 1;
503     i++;
504   }
505   return i;
506 }
507
508 function readInt8(data, start) {
509   return (data[start] << 24) >> 24;
510 }
511
512 function readUint16(data, offset) {
513   return (data[offset] << 8) | data[offset + 1];
514 }
515
516 function readUint32(data, offset) {
517   return ((data[offset] << 24) | (data[offset + 1] << 16) |
518          (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
519 }
520
521 // Lazy test the endianness of the platform
522 // NOTE: This will be 'true' for simulated TypedArrays
523 function isLittleEndian() {
524   var buffer8 = new Uint8Array(2);
525   buffer8[0] = 1;
526   var buffer16 = new Uint16Array(buffer8.buffer);
527   return (buffer16[0] === 1);
528 }
529
530 Object.defineProperty(PDFJS, 'isLittleEndian', {
531   configurable: true,
532   get: function PDFJS_isLittleEndian() {
533     return shadow(PDFJS, 'isLittleEndian', isLittleEndian());
534   }
535 });
536
537   // Lazy test if the userAgant support CanvasTypedArrays
538 function hasCanvasTypedArrays() {
539   var canvas = document.createElement('canvas');
540   canvas.width = canvas.height = 1;
541   var ctx = canvas.getContext('2d');
542   var imageData = ctx.createImageData(1, 1);
543   return (typeof imageData.data.buffer !== 'undefined');
544 }
545
546 Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', {
547   configurable: true,
548   get: function PDFJS_hasCanvasTypedArrays() {
549     return shadow(PDFJS, 'hasCanvasTypedArrays', hasCanvasTypedArrays());
550   }
551 });
552
553 var Uint32ArrayView = (function Uint32ArrayViewClosure() {
554
555   function Uint32ArrayView(buffer, length) {
556     this.buffer = buffer;
557     this.byteLength = buffer.length;
558     this.length = length === undefined ? (this.byteLength >> 2) : length;
559     ensureUint32ArrayViewProps(this.length);
560   }
561   Uint32ArrayView.prototype = Object.create(null);
562
563   var uint32ArrayViewSetters = 0;
564   function createUint32ArrayProp(index) {
565     return {
566       get: function () {
567         var buffer = this.buffer, offset = index << 2;
568         return (buffer[offset] | (buffer[offset + 1] << 8) |
569           (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;
570       },
571       set: function (value) {
572         var buffer = this.buffer, offset = index << 2;
573         buffer[offset] = value & 255;
574         buffer[offset + 1] = (value >> 8) & 255;
575         buffer[offset + 2] = (value >> 16) & 255;
576         buffer[offset + 3] = (value >>> 24) & 255;
577       }
578     };
579   }
580
581   function ensureUint32ArrayViewProps(length) {
582     while (uint32ArrayViewSetters < length) {
583       Object.defineProperty(Uint32ArrayView.prototype,
584         uint32ArrayViewSetters,
585         createUint32ArrayProp(uint32ArrayViewSetters));
586       uint32ArrayViewSetters++;
587     }
588   }
589
590   return Uint32ArrayView;
591 })();
592
593 var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
594
595 var Util = PDFJS.Util = (function UtilClosure() {
596   function Util() {}
597
598   var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];
599
600   // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids
601   // creating many intermediate strings.
602   Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
603     rgbBuf[1] = r;
604     rgbBuf[3] = g;
605     rgbBuf[5] = b;
606     return rgbBuf.join('');
607   };
608
609   // Concatenates two transformation matrices together and returns the result.
610   Util.transform = function Util_transform(m1, m2) {
611     return [
612       m1[0] * m2[0] + m1[2] * m2[1],
613       m1[1] * m2[0] + m1[3] * m2[1],
614       m1[0] * m2[2] + m1[2] * m2[3],
615       m1[1] * m2[2] + m1[3] * m2[3],
616       m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
617       m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
618     ];
619   };
620
621   // For 2d affine transforms
622   Util.applyTransform = function Util_applyTransform(p, m) {
623     var xt = p[0] * m[0] + p[1] * m[2] + m[4];
624     var yt = p[0] * m[1] + p[1] * m[3] + m[5];
625     return [xt, yt];
626   };
627
628   Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
629     var d = m[0] * m[3] - m[1] * m[2];
630     var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
631     var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
632     return [xt, yt];
633   };
634
635   // Applies the transform to the rectangle and finds the minimum axially
636   // aligned bounding box.
637   Util.getAxialAlignedBoundingBox =
638     function Util_getAxialAlignedBoundingBox(r, m) {
639
640     var p1 = Util.applyTransform(r, m);
641     var p2 = Util.applyTransform(r.slice(2, 4), m);
642     var p3 = Util.applyTransform([r[0], r[3]], m);
643     var p4 = Util.applyTransform([r[2], r[1]], m);
644     return [
645       Math.min(p1[0], p2[0], p3[0], p4[0]),
646       Math.min(p1[1], p2[1], p3[1], p4[1]),
647       Math.max(p1[0], p2[0], p3[0], p4[0]),
648       Math.max(p1[1], p2[1], p3[1], p4[1])
649     ];
650   };
651
652   Util.inverseTransform = function Util_inverseTransform(m) {
653     var d = m[0] * m[3] - m[1] * m[2];
654     return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
655       (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
656   };
657
658   // Apply a generic 3d matrix M on a 3-vector v:
659   //   | a b c |   | X |
660   //   | d e f | x | Y |
661   //   | g h i |   | Z |
662   // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
663   // with v as [X,Y,Z]
664   Util.apply3dTransform = function Util_apply3dTransform(m, v) {
665     return [
666       m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
667       m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
668       m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
669     ];
670   };
671
672   // This calculation uses Singular Value Decomposition.
673   // The SVD can be represented with formula A = USV. We are interested in the
674   // matrix S here because it represents the scale values.
675   Util.singularValueDecompose2dScale =
676     function Util_singularValueDecompose2dScale(m) {
677
678     var transpose = [m[0], m[2], m[1], m[3]];
679
680     // Multiply matrix m with its transpose.
681     var a = m[0] * transpose[0] + m[1] * transpose[2];
682     var b = m[0] * transpose[1] + m[1] * transpose[3];
683     var c = m[2] * transpose[0] + m[3] * transpose[2];
684     var d = m[2] * transpose[1] + m[3] * transpose[3];
685
686     // Solve the second degree polynomial to get roots.
687     var first = (a + d) / 2;
688     var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
689     var sx = first + second || 1;
690     var sy = first - second || 1;
691
692     // Scale values are the square roots of the eigenvalues.
693     return [Math.sqrt(sx), Math.sqrt(sy)];
694   };
695
696   // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
697   // For coordinate systems whose origin lies in the bottom-left, this
698   // means normalization to (BL,TR) ordering. For systems with origin in the
699   // top-left, this means (TL,BR) ordering.
700   Util.normalizeRect = function Util_normalizeRect(rect) {
701     var r = rect.slice(0); // clone rect
702     if (rect[0] > rect[2]) {
703       r[0] = rect[2];
704       r[2] = rect[0];
705     }
706     if (rect[1] > rect[3]) {
707       r[1] = rect[3];
708       r[3] = rect[1];
709     }
710     return r;
711   };
712
713   // Returns a rectangle [x1, y1, x2, y2] corresponding to the
714   // intersection of rect1 and rect2. If no intersection, returns 'false'
715   // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
716   Util.intersect = function Util_intersect(rect1, rect2) {
717     function compare(a, b) {
718       return a - b;
719     }
720
721     // Order points along the axes
722     var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
723         orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
724         result = [];
725
726     rect1 = Util.normalizeRect(rect1);
727     rect2 = Util.normalizeRect(rect2);
728
729     // X: first and second points belong to different rectangles?
730     if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
731         (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
732       // Intersection must be between second and third points
733       result[0] = orderedX[1];
734       result[2] = orderedX[2];
735     } else {
736       return false;
737     }
738
739     // Y: first and second points belong to different rectangles?
740     if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
741         (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
742       // Intersection must be between second and third points
743       result[1] = orderedY[1];
744       result[3] = orderedY[2];
745     } else {
746       return false;
747     }
748
749     return result;
750   };
751
752   Util.sign = function Util_sign(num) {
753     return num < 0 ? -1 : 1;
754   };
755
756   Util.appendToArray = function Util_appendToArray(arr1, arr2) {
757     Array.prototype.push.apply(arr1, arr2);
758   };
759
760   Util.prependToArray = function Util_prependToArray(arr1, arr2) {
761     Array.prototype.unshift.apply(arr1, arr2);
762   };
763
764   Util.extendObj = function extendObj(obj1, obj2) {
765     for (var key in obj2) {
766       obj1[key] = obj2[key];
767     }
768   };
769
770   Util.getInheritableProperty = function Util_getInheritableProperty(dict,
771                                                                      name) {
772     while (dict && !dict.has(name)) {
773       dict = dict.get('Parent');
774     }
775     if (!dict) {
776       return null;
777     }
778     return dict.get(name);
779   };
780
781   Util.inherit = function Util_inherit(sub, base, prototype) {
782     sub.prototype = Object.create(base.prototype);
783     sub.prototype.constructor = sub;
784     for (var prop in prototype) {
785       sub.prototype[prop] = prototype[prop];
786     }
787   };
788
789   Util.loadScript = function Util_loadScript(src, callback) {
790     var script = document.createElement('script');
791     var loaded = false;
792     script.setAttribute('src', src);
793     if (callback) {
794       script.onload = function() {
795         if (!loaded) {
796           callback();
797         }
798         loaded = true;
799       };
800     }
801     document.getElementsByTagName('head')[0].appendChild(script);
802   };
803
804   return Util;
805 })();
806
807 /**
808  * PDF page viewport created based on scale, rotation and offset.
809  * @class
810  * @alias PDFJS.PageViewport
811  */
812 var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
813   /**
814    * @constructor
815    * @private
816    * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
817    * @param scale {number} scale of the viewport.
818    * @param rotation {number} rotations of the viewport in degrees.
819    * @param offsetX {number} offset X
820    * @param offsetY {number} offset Y
821    * @param dontFlip {boolean} if true, axis Y will not be flipped.
822    */
823   function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
824     this.viewBox = viewBox;
825     this.scale = scale;
826     this.rotation = rotation;
827     this.offsetX = offsetX;
828     this.offsetY = offsetY;
829
830     // creating transform to convert pdf coordinate system to the normal
831     // canvas like coordinates taking in account scale and rotation
832     var centerX = (viewBox[2] + viewBox[0]) / 2;
833     var centerY = (viewBox[3] + viewBox[1]) / 2;
834     var rotateA, rotateB, rotateC, rotateD;
835     rotation = rotation % 360;
836     rotation = rotation < 0 ? rotation + 360 : rotation;
837     switch (rotation) {
838       case 180:
839         rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
840         break;
841       case 90:
842         rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
843         break;
844       case 270:
845         rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
846         break;
847       //case 0:
848       default:
849         rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
850         break;
851     }
852
853     if (dontFlip) {
854       rotateC = -rotateC; rotateD = -rotateD;
855     }
856
857     var offsetCanvasX, offsetCanvasY;
858     var width, height;
859     if (rotateA === 0) {
860       offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
861       offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
862       width = Math.abs(viewBox[3] - viewBox[1]) * scale;
863       height = Math.abs(viewBox[2] - viewBox[0]) * scale;
864     } else {
865       offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
866       offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
867       width = Math.abs(viewBox[2] - viewBox[0]) * scale;
868       height = Math.abs(viewBox[3] - viewBox[1]) * scale;
869     }
870     // creating transform for the following operations:
871     // translate(-centerX, -centerY), rotate and flip vertically,
872     // scale, and translate(offsetCanvasX, offsetCanvasY)
873     this.transform = [
874       rotateA * scale,
875       rotateB * scale,
876       rotateC * scale,
877       rotateD * scale,
878       offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
879       offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
880     ];
881
882     this.width = width;
883     this.height = height;
884     this.fontScale = scale;
885   }
886   PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
887     /**
888      * Clones viewport with additional properties.
889      * @param args {Object} (optional) If specified, may contain the 'scale' or
890      * 'rotation' properties to override the corresponding properties in
891      * the cloned viewport.
892      * @returns {PDFJS.PageViewport} Cloned viewport.
893      */
894     clone: function PageViewPort_clone(args) {
895       args = args || {};
896       var scale = 'scale' in args ? args.scale : this.scale;
897       var rotation = 'rotation' in args ? args.rotation : this.rotation;
898       return new PageViewport(this.viewBox.slice(), scale, rotation,
899                               this.offsetX, this.offsetY, args.dontFlip);
900     },
901     /**
902      * Converts PDF point to the viewport coordinates. For examples, useful for
903      * converting PDF location into canvas pixel coordinates.
904      * @param x {number} X coordinate.
905      * @param y {number} Y coordinate.
906      * @returns {Object} Object that contains 'x' and 'y' properties of the
907      * point in the viewport coordinate space.
908      * @see {@link convertToPdfPoint}
909      * @see {@link convertToViewportRectangle}
910      */
911     convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
912       return Util.applyTransform([x, y], this.transform);
913     },
914     /**
915      * Converts PDF rectangle to the viewport coordinates.
916      * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
917      * @returns {Array} Contains corresponding coordinates of the rectangle
918      * in the viewport coordinate space.
919      * @see {@link convertToViewportPoint}
920      */
921     convertToViewportRectangle:
922       function PageViewport_convertToViewportRectangle(rect) {
923       var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
924       var br = Util.applyTransform([rect[2], rect[3]], this.transform);
925       return [tl[0], tl[1], br[0], br[1]];
926     },
927     /**
928      * Converts viewport coordinates to the PDF location. For examples, useful
929      * for converting canvas pixel location into PDF one.
930      * @param x {number} X coordinate.
931      * @param y {number} Y coordinate.
932      * @returns {Object} Object that contains 'x' and 'y' properties of the
933      * point in the PDF coordinate space.
934      * @see {@link convertToViewportPoint}
935      */
936     convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
937       return Util.applyInverseTransform([x, y], this.transform);
938     }
939   };
940   return PageViewport;
941 })();
942
943 var PDFStringTranslateTable = [
944   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
945   0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
946   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
947   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
948   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
949   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
950   0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
951   0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
952   0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
953 ];
954
955 function stringToPDFString(str) {
956   var i, n = str.length, strBuf = [];
957   if (str[0] === '\xFE' && str[1] === '\xFF') {
958     // UTF16BE BOM
959     for (i = 2; i < n; i += 2) {
960       strBuf.push(String.fromCharCode(
961         (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));
962     }
963   } else {
964     for (i = 0; i < n; ++i) {
965       var code = PDFStringTranslateTable[str.charCodeAt(i)];
966       strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
967     }
968   }
969   return strBuf.join('');
970 }
971
972 function stringToUTF8String(str) {
973   return decodeURIComponent(escape(str));
974 }
975
976 function utf8StringToString(str) {
977   return unescape(encodeURIComponent(str));
978 }
979
980 function isEmptyObj(obj) {
981   for (var key in obj) {
982     return false;
983   }
984   return true;
985 }
986
987 function isBool(v) {
988   return typeof v === 'boolean';
989 }
990
991 function isInt(v) {
992   return typeof v === 'number' && ((v | 0) === v);
993 }
994
995 function isNum(v) {
996   return typeof v === 'number';
997 }
998
999 function isString(v) {
1000   return typeof v === 'string';
1001 }
1002
1003 function isName(v) {
1004   return v instanceof Name;
1005 }
1006
1007 function isCmd(v, cmd) {
1008   return v instanceof Cmd && (cmd === undefined || v.cmd === cmd);
1009 }
1010
1011 function isDict(v, type) {
1012   if (!(v instanceof Dict)) {
1013     return false;
1014   }
1015   if (!type) {
1016     return true;
1017   }
1018   var dictType = v.get('Type');
1019   return isName(dictType) && dictType.name === type;
1020 }
1021
1022 function isArray(v) {
1023   return v instanceof Array;
1024 }
1025
1026 function isStream(v) {
1027   return typeof v === 'object' && v !== null && v.getBytes !== undefined;
1028 }
1029
1030 function isArrayBuffer(v) {
1031   return typeof v === 'object' && v !== null && v.byteLength !== undefined;
1032 }
1033
1034 function isRef(v) {
1035   return v instanceof Ref;
1036 }
1037
1038 /**
1039  * Promise Capability object.
1040  *
1041  * @typedef {Object} PromiseCapability
1042  * @property {Promise} promise - A promise object.
1043  * @property {function} resolve - Fullfills the promise.
1044  * @property {function} reject - Rejects the promise.
1045  */
1046
1047 /**
1048  * Creates a promise capability object.
1049  * @alias PDFJS.createPromiseCapability
1050  *
1051  * @return {PromiseCapability} A capability object contains:
1052  * - a Promise, resolve and reject methods.
1053  */
1054 function createPromiseCapability() {
1055   var capability = {};
1056   capability.promise = new Promise(function (resolve, reject) {
1057     capability.resolve = resolve;
1058     capability.reject = reject;
1059   });
1060   return capability;
1061 }
1062
1063 PDFJS.createPromiseCapability = createPromiseCapability;
1064
1065 /**
1066  * Polyfill for Promises:
1067  * The following promise implementation tries to generally implement the
1068  * Promise/A+ spec. Some notable differences from other promise libaries are:
1069  * - There currently isn't a seperate deferred and promise object.
1070  * - Unhandled rejections eventually show an error if they aren't handled.
1071  *
1072  * Based off of the work in:
1073  * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
1074  */
1075 (function PromiseClosure() {
1076   if (globalScope.Promise) {
1077     // Promises existing in the DOM/Worker, checking presence of all/resolve
1078     if (typeof globalScope.Promise.all !== 'function') {
1079       globalScope.Promise.all = function (iterable) {
1080         var count = 0, results = [], resolve, reject;
1081         var promise = new globalScope.Promise(function (resolve_, reject_) {
1082           resolve = resolve_;
1083           reject = reject_;
1084         });
1085         iterable.forEach(function (p, i) {
1086           count++;
1087           p.then(function (result) {
1088             results[i] = result;
1089             count--;
1090             if (count === 0) {
1091               resolve(results);
1092             }
1093           }, reject);
1094         });
1095         if (count === 0) {
1096           resolve(results);
1097         }
1098         return promise;
1099       };
1100     }
1101     if (typeof globalScope.Promise.resolve !== 'function') {
1102       globalScope.Promise.resolve = function (value) {
1103         return new globalScope.Promise(function (resolve) { resolve(value); });
1104       };
1105     }
1106     if (typeof globalScope.Promise.reject !== 'function') {
1107       globalScope.Promise.reject = function (reason) {
1108         return new globalScope.Promise(function (resolve, reject) {
1109           reject(reason);
1110         });
1111       };
1112     }
1113     if (typeof globalScope.Promise.prototype.catch !== 'function') {
1114       globalScope.Promise.prototype.catch = function (onReject) {
1115         return globalScope.Promise.prototype.then(undefined, onReject);
1116       };
1117     }
1118     return;
1119   }
1120   var STATUS_PENDING = 0;
1121   var STATUS_RESOLVED = 1;
1122   var STATUS_REJECTED = 2;
1123
1124   // In an attempt to avoid silent exceptions, unhandled rejections are
1125   // tracked and if they aren't handled in a certain amount of time an
1126   // error is logged.
1127   var REJECTION_TIMEOUT = 500;
1128
1129   var HandlerManager = {
1130     handlers: [],
1131     running: false,
1132     unhandledRejections: [],
1133     pendingRejectionCheck: false,
1134
1135     scheduleHandlers: function scheduleHandlers(promise) {
1136       if (promise._status === STATUS_PENDING) {
1137         return;
1138       }
1139
1140       this.handlers = this.handlers.concat(promise._handlers);
1141       promise._handlers = [];
1142
1143       if (this.running) {
1144         return;
1145       }
1146       this.running = true;
1147
1148       setTimeout(this.runHandlers.bind(this), 0);
1149     },
1150
1151     runHandlers: function runHandlers() {
1152       var RUN_TIMEOUT = 1; // ms
1153       var timeoutAt = Date.now() + RUN_TIMEOUT;
1154       while (this.handlers.length > 0) {
1155         var handler = this.handlers.shift();
1156
1157         var nextStatus = handler.thisPromise._status;
1158         var nextValue = handler.thisPromise._value;
1159
1160         try {
1161           if (nextStatus === STATUS_RESOLVED) {
1162             if (typeof handler.onResolve === 'function') {
1163               nextValue = handler.onResolve(nextValue);
1164             }
1165           } else if (typeof handler.onReject === 'function') {
1166               nextValue = handler.onReject(nextValue);
1167               nextStatus = STATUS_RESOLVED;
1168
1169               if (handler.thisPromise._unhandledRejection) {
1170                 this.removeUnhandeledRejection(handler.thisPromise);
1171               }
1172           }
1173         } catch (ex) {
1174           nextStatus = STATUS_REJECTED;
1175           nextValue = ex;
1176         }
1177
1178         handler.nextPromise._updateStatus(nextStatus, nextValue);
1179         if (Date.now() >= timeoutAt) {
1180           break;
1181         }
1182       }
1183
1184       if (this.handlers.length > 0) {
1185         setTimeout(this.runHandlers.bind(this), 0);
1186         return;
1187       }
1188
1189       this.running = false;
1190     },
1191
1192     addUnhandledRejection: function addUnhandledRejection(promise) {
1193       this.unhandledRejections.push({
1194         promise: promise,
1195         time: Date.now()
1196       });
1197       this.scheduleRejectionCheck();
1198     },
1199
1200     removeUnhandeledRejection: function removeUnhandeledRejection(promise) {
1201       promise._unhandledRejection = false;
1202       for (var i = 0; i < this.unhandledRejections.length; i++) {
1203         if (this.unhandledRejections[i].promise === promise) {
1204           this.unhandledRejections.splice(i);
1205           i--;
1206         }
1207       }
1208     },
1209
1210     scheduleRejectionCheck: function scheduleRejectionCheck() {
1211       if (this.pendingRejectionCheck) {
1212         return;
1213       }
1214       this.pendingRejectionCheck = true;
1215       setTimeout(function rejectionCheck() {
1216         this.pendingRejectionCheck = false;
1217         var now = Date.now();
1218         for (var i = 0; i < this.unhandledRejections.length; i++) {
1219           if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {
1220             var unhandled = this.unhandledRejections[i].promise._value;
1221             var msg = 'Unhandled rejection: ' + unhandled;
1222             if (unhandled.stack) {
1223               msg += '\n' + unhandled.stack;
1224             }
1225             warn(msg);
1226             this.unhandledRejections.splice(i);
1227             i--;
1228           }
1229         }
1230         if (this.unhandledRejections.length) {
1231           this.scheduleRejectionCheck();
1232         }
1233       }.bind(this), REJECTION_TIMEOUT);
1234     }
1235   };
1236
1237   function Promise(resolver) {
1238     this._status = STATUS_PENDING;
1239     this._handlers = [];
1240     try {
1241       resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
1242     } catch (e) {
1243       this._reject(e);
1244     }
1245   }
1246   /**
1247    * Builds a promise that is resolved when all the passed in promises are
1248    * resolved.
1249    * @param {array} array of data and/or promises to wait for.
1250    * @return {Promise} New dependant promise.
1251    */
1252   Promise.all = function Promise_all(promises) {
1253     var resolveAll, rejectAll;
1254     var deferred = new Promise(function (resolve, reject) {
1255       resolveAll = resolve;
1256       rejectAll = reject;
1257     });
1258     var unresolved = promises.length;
1259     var results = [];
1260     if (unresolved === 0) {
1261       resolveAll(results);
1262       return deferred;
1263     }
1264     function reject(reason) {
1265       if (deferred._status === STATUS_REJECTED) {
1266         return;
1267       }
1268       results = [];
1269       rejectAll(reason);
1270     }
1271     for (var i = 0, ii = promises.length; i < ii; ++i) {
1272       var promise = promises[i];
1273       var resolve = (function(i) {
1274         return function(value) {
1275           if (deferred._status === STATUS_REJECTED) {
1276             return;
1277           }
1278           results[i] = value;
1279           unresolved--;
1280           if (unresolved === 0) {
1281             resolveAll(results);
1282           }
1283         };
1284       })(i);
1285       if (Promise.isPromise(promise)) {
1286         promise.then(resolve, reject);
1287       } else {
1288         resolve(promise);
1289       }
1290     }
1291     return deferred;
1292   };
1293
1294   /**
1295    * Checks if the value is likely a promise (has a 'then' function).
1296    * @return {boolean} true if value is thenable
1297    */
1298   Promise.isPromise = function Promise_isPromise(value) {
1299     return value && typeof value.then === 'function';
1300   };
1301
1302   /**
1303    * Creates resolved promise
1304    * @param value resolve value
1305    * @returns {Promise}
1306    */
1307   Promise.resolve = function Promise_resolve(value) {
1308     return new Promise(function (resolve) { resolve(value); });
1309   };
1310
1311   /**
1312    * Creates rejected promise
1313    * @param reason rejection value
1314    * @returns {Promise}
1315    */
1316   Promise.reject = function Promise_reject(reason) {
1317     return new Promise(function (resolve, reject) { reject(reason); });
1318   };
1319
1320   Promise.prototype = {
1321     _status: null,
1322     _value: null,
1323     _handlers: null,
1324     _unhandledRejection: null,
1325
1326     _updateStatus: function Promise__updateStatus(status, value) {
1327       if (this._status === STATUS_RESOLVED ||
1328           this._status === STATUS_REJECTED) {
1329         return;
1330       }
1331
1332       if (status === STATUS_RESOLVED &&
1333           Promise.isPromise(value)) {
1334         value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
1335                    this._updateStatus.bind(this, STATUS_REJECTED));
1336         return;
1337       }
1338
1339       this._status = status;
1340       this._value = value;
1341
1342       if (status === STATUS_REJECTED && this._handlers.length === 0) {
1343         this._unhandledRejection = true;
1344         HandlerManager.addUnhandledRejection(this);
1345       }
1346
1347       HandlerManager.scheduleHandlers(this);
1348     },
1349
1350     _resolve: function Promise_resolve(value) {
1351       this._updateStatus(STATUS_RESOLVED, value);
1352     },
1353
1354     _reject: function Promise_reject(reason) {
1355       this._updateStatus(STATUS_REJECTED, reason);
1356     },
1357
1358     then: function Promise_then(onResolve, onReject) {
1359       var nextPromise = new Promise(function (resolve, reject) {
1360         this.resolve = resolve;
1361         this.reject = reject;
1362       });
1363       this._handlers.push({
1364         thisPromise: this,
1365         onResolve: onResolve,
1366         onReject: onReject,
1367         nextPromise: nextPromise
1368       });
1369       HandlerManager.scheduleHandlers(this);
1370       return nextPromise;
1371     },
1372
1373     catch: function Promise_catch(onReject) {
1374       return this.then(undefined, onReject);
1375     }
1376   };
1377
1378   globalScope.Promise = Promise;
1379 })();
1380
1381 var StatTimer = (function StatTimerClosure() {
1382   function rpad(str, pad, length) {
1383     while (str.length < length) {
1384       str += pad;
1385     }
1386     return str;
1387   }
1388   function StatTimer() {
1389     this.started = {};
1390     this.times = [];
1391     this.enabled = true;
1392   }
1393   StatTimer.prototype = {
1394     time: function StatTimer_time(name) {
1395       if (!this.enabled) {
1396         return;
1397       }
1398       if (name in this.started) {
1399         warn('Timer is already running for ' + name);
1400       }
1401       this.started[name] = Date.now();
1402     },
1403     timeEnd: function StatTimer_timeEnd(name) {
1404       if (!this.enabled) {
1405         return;
1406       }
1407       if (!(name in this.started)) {
1408         warn('Timer has not been started for ' + name);
1409       }
1410       this.times.push({
1411         'name': name,
1412         'start': this.started[name],
1413         'end': Date.now()
1414       });
1415       // Remove timer from started so it can be called again.
1416       delete this.started[name];
1417     },
1418     toString: function StatTimer_toString() {
1419       var i, ii;
1420       var times = this.times;
1421       var out = '';
1422       // Find the longest name for padding purposes.
1423       var longest = 0;
1424       for (i = 0, ii = times.length; i < ii; ++i) {
1425         var name = times[i]['name'];
1426         if (name.length > longest) {
1427           longest = name.length;
1428         }
1429       }
1430       for (i = 0, ii = times.length; i < ii; ++i) {
1431         var span = times[i];
1432         var duration = span.end - span.start;
1433         out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
1434       }
1435       return out;
1436     }
1437   };
1438   return StatTimer;
1439 })();
1440
1441 PDFJS.createBlob = function createBlob(data, contentType) {
1442   if (typeof Blob !== 'undefined') {
1443     return new Blob([data], { type: contentType });
1444   }
1445   // Blob builder is deprecated in FF14 and removed in FF18.
1446   var bb = new MozBlobBuilder();
1447   bb.append(data);
1448   return bb.getBlob(contentType);
1449 };
1450
1451 PDFJS.createObjectURL = (function createObjectURLClosure() {
1452   // Blob/createObjectURL is not available, falling back to data schema.
1453   var digits =
1454     'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
1455
1456   return function createObjectURL(data, contentType) {
1457     if (!PDFJS.disableCreateObjectURL &&
1458         typeof URL !== 'undefined' && URL.createObjectURL) {
1459       var blob = PDFJS.createBlob(data, contentType);
1460       return URL.createObjectURL(blob);
1461     }
1462
1463     var buffer = 'data:' + contentType + ';base64,';
1464     for (var i = 0, ii = data.length; i < ii; i += 3) {
1465       var b1 = data[i] & 0xFF;
1466       var b2 = data[i + 1] & 0xFF;
1467       var b3 = data[i + 2] & 0xFF;
1468       var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
1469       var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
1470       var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
1471       buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
1472     }
1473     return buffer;
1474   };
1475 })();
1476
1477 function MessageHandler(name, comObj) {
1478   this.name = name;
1479   this.comObj = comObj;
1480   this.callbackIndex = 1;
1481   this.postMessageTransfers = true;
1482   var callbacksCapabilities = this.callbacksCapabilities = {};
1483   var ah = this.actionHandler = {};
1484
1485   ah['console_log'] = [function ahConsoleLog(data) {
1486     console.log.apply(console, data);
1487   }];
1488   ah['console_error'] = [function ahConsoleError(data) {
1489     console.error.apply(console, data);
1490   }];
1491   ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
1492     UnsupportedManager.notify(data);
1493   }];
1494
1495   comObj.onmessage = function messageHandlerComObjOnMessage(event) {
1496     var data = event.data;
1497     if (data.isReply) {
1498       var callbackId = data.callbackId;
1499       if (data.callbackId in callbacksCapabilities) {
1500         var callback = callbacksCapabilities[callbackId];
1501         delete callbacksCapabilities[callbackId];
1502         if ('error' in data) {
1503           callback.reject(data.error);
1504         } else {
1505           callback.resolve(data.data);
1506         }
1507       } else {
1508         error('Cannot resolve callback ' + callbackId);
1509       }
1510     } else if (data.action in ah) {
1511       var action = ah[data.action];
1512       if (data.callbackId) {
1513         Promise.resolve().then(function () {
1514           return action[0].call(action[1], data.data);
1515         }).then(function (result) {
1516           comObj.postMessage({
1517             isReply: true,
1518             callbackId: data.callbackId,
1519             data: result
1520           });
1521         }, function (reason) {
1522           comObj.postMessage({
1523             isReply: true,
1524             callbackId: data.callbackId,
1525             error: reason
1526           });
1527         });
1528       } else {
1529         action[0].call(action[1], data.data);
1530       }
1531     } else {
1532       error('Unknown action from worker: ' + data.action);
1533     }
1534   };
1535 }
1536
1537 MessageHandler.prototype = {
1538   on: function messageHandlerOn(actionName, handler, scope) {
1539     var ah = this.actionHandler;
1540     if (ah[actionName]) {
1541       error('There is already an actionName called "' + actionName + '"');
1542     }
1543     ah[actionName] = [handler, scope];
1544   },
1545   /**
1546    * Sends a message to the comObj to invoke the action with the supplied data.
1547    * @param {String} actionName Action to call.
1548    * @param {JSON} data JSON data to send.
1549    * @param {Array} [transfers] Optional list of transfers/ArrayBuffers
1550    */
1551   send: function messageHandlerSend(actionName, data, transfers) {
1552     var message = {
1553       action: actionName,
1554       data: data
1555     };
1556     this.postMessage(message, transfers);
1557   },
1558   /**
1559    * Sends a message to the comObj to invoke the action with the supplied data.
1560    * Expects that other side will callback with the response.
1561    * @param {String} actionName Action to call.
1562    * @param {JSON} data JSON data to send.
1563    * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
1564    * @returns {Promise} Promise to be resolved with response data.
1565    */
1566   sendWithPromise:
1567     function messageHandlerSendWithPromise(actionName, data, transfers) {
1568     var callbackId = this.callbackIndex++;
1569     var message = {
1570       action: actionName,
1571       data: data,
1572       callbackId: callbackId
1573     };
1574     var capability = createPromiseCapability();
1575     this.callbacksCapabilities[callbackId] = capability;
1576     try {
1577       this.postMessage(message, transfers);
1578     } catch (e) {
1579       capability.reject(e);
1580     }
1581     return capability.promise;
1582   },
1583   /**
1584    * Sends raw message to the comObj.
1585    * @private
1586    * @param message {Object} Raw message.
1587    * @param transfers List of transfers/ArrayBuffers, or undefined.
1588    */
1589   postMessage: function (message, transfers) {
1590     if (transfers && this.postMessageTransfers) {
1591       this.comObj.postMessage(message, transfers);
1592     } else {
1593       this.comObj.postMessage(message);
1594     }
1595   }
1596 };
1597
1598 function loadJpegStream(id, imageUrl, objs) {
1599   var img = new Image();
1600   img.onload = (function loadJpegStream_onloadClosure() {
1601     objs.resolve(id, img);
1602   });
1603   img.onerror = (function loadJpegStream_onerrorClosure() {
1604     objs.resolve(id, null);
1605     warn('Error during JPEG image loading');
1606   });
1607   img.src = imageUrl;
1608 }
1609
1610
1611
1612
1613 var NetworkManager = (function NetworkManagerClosure() {
1614
1615   var OK_RESPONSE = 200;
1616   var PARTIAL_CONTENT_RESPONSE = 206;
1617
1618   function NetworkManager(url, args) {
1619     this.url = url;
1620     args = args || {};
1621     this.isHttp = /^https?:/i.test(url);
1622     this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
1623     this.withCredentials = args.withCredentials || false;
1624     this.getXhr = args.getXhr ||
1625       function NetworkManager_getXhr() {
1626         return new XMLHttpRequest();
1627       };
1628
1629     this.currXhrId = 0;
1630     this.pendingRequests = {};
1631     this.loadedRequests = {};
1632   }
1633
1634   function getArrayBuffer(xhr) {
1635     var data = xhr.response;
1636     if (typeof data !== 'string') {
1637       return data;
1638     }
1639     var length = data.length;
1640     var array = new Uint8Array(length);
1641     for (var i = 0; i < length; i++) {
1642       array[i] = data.charCodeAt(i) & 0xFF;
1643     }
1644     return array.buffer;
1645   }
1646
1647   NetworkManager.prototype = {
1648     requestRange: function NetworkManager_requestRange(begin, end, listeners) {
1649       var args = {
1650         begin: begin,
1651         end: end
1652       };
1653       for (var prop in listeners) {
1654         args[prop] = listeners[prop];
1655       }
1656       return this.request(args);
1657     },
1658
1659     requestFull: function NetworkManager_requestFull(listeners) {
1660       return this.request(listeners);
1661     },
1662
1663     request: function NetworkManager_request(args) {
1664       var xhr = this.getXhr();
1665       var xhrId = this.currXhrId++;
1666       var pendingRequest = this.pendingRequests[xhrId] = {
1667         xhr: xhr
1668       };
1669
1670       xhr.open('GET', this.url);
1671       xhr.withCredentials = this.withCredentials;
1672       for (var property in this.httpHeaders) {
1673         var value = this.httpHeaders[property];
1674         if (typeof value === 'undefined') {
1675           continue;
1676         }
1677         xhr.setRequestHeader(property, value);
1678       }
1679       if (this.isHttp && 'begin' in args && 'end' in args) {
1680         var rangeStr = args.begin + '-' + (args.end - 1);
1681         xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
1682         pendingRequest.expectedStatus = 206;
1683       } else {
1684         pendingRequest.expectedStatus = 200;
1685       }
1686
1687       if (args.onProgressiveData) {
1688         // Some legacy browsers might throw an exception.
1689         try {
1690           xhr.responseType = 'moz-chunked-arraybuffer';
1691         } catch(e) {}
1692         if (xhr.responseType === 'moz-chunked-arraybuffer') {
1693           pendingRequest.onProgressiveData = args.onProgressiveData;
1694           pendingRequest.mozChunked = true;
1695         } else {
1696           xhr.responseType = 'arraybuffer';
1697         }
1698       } else {
1699         xhr.responseType = 'arraybuffer';
1700       }
1701
1702       if (args.onError) {
1703         xhr.onerror = function(evt) {
1704           args.onError(xhr.status);
1705         };
1706       }
1707       xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
1708       xhr.onprogress = this.onProgress.bind(this, xhrId);
1709
1710       pendingRequest.onHeadersReceived = args.onHeadersReceived;
1711       pendingRequest.onDone = args.onDone;
1712       pendingRequest.onError = args.onError;
1713       pendingRequest.onProgress = args.onProgress;
1714
1715       xhr.send(null);
1716
1717       return xhrId;
1718     },
1719
1720     onProgress: function NetworkManager_onProgress(xhrId, evt) {
1721       var pendingRequest = this.pendingRequests[xhrId];
1722       if (!pendingRequest) {
1723         // Maybe abortRequest was called...
1724         return;
1725       }
1726
1727       if (pendingRequest.mozChunked) {
1728         var chunk = getArrayBuffer(pendingRequest.xhr);
1729         pendingRequest.onProgressiveData(chunk);
1730       }
1731
1732       var onProgress = pendingRequest.onProgress;
1733       if (onProgress) {
1734         onProgress(evt);
1735       }
1736     },
1737
1738     onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
1739       var pendingRequest = this.pendingRequests[xhrId];
1740       if (!pendingRequest) {
1741         // Maybe abortRequest was called...
1742         return;
1743       }
1744
1745       var xhr = pendingRequest.xhr;
1746       if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
1747         pendingRequest.onHeadersReceived();
1748         delete pendingRequest.onHeadersReceived;
1749       }
1750
1751       if (xhr.readyState !== 4) {
1752         return;
1753       }
1754
1755       if (!(xhrId in this.pendingRequests)) {
1756         // The XHR request might have been aborted in onHeadersReceived()
1757         // callback, in which case we should abort request
1758         return;
1759       }
1760
1761       delete this.pendingRequests[xhrId];
1762
1763       // success status == 0 can be on ftp, file and other protocols
1764       if (xhr.status === 0 && this.isHttp) {
1765         if (pendingRequest.onError) {
1766           pendingRequest.onError(xhr.status);
1767         }
1768         return;
1769       }
1770       var xhrStatus = xhr.status || OK_RESPONSE;
1771
1772       // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2:
1773       // "A server MAY ignore the Range header". This means it's possible to
1774       // get a 200 rather than a 206 response from a range request.
1775       var ok_response_on_range_request =
1776           xhrStatus === OK_RESPONSE &&
1777           pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
1778
1779       if (!ok_response_on_range_request &&
1780           xhrStatus !== pendingRequest.expectedStatus) {
1781         if (pendingRequest.onError) {
1782           pendingRequest.onError(xhr.status);
1783         }
1784         return;
1785       }
1786
1787       this.loadedRequests[xhrId] = true;
1788
1789       var chunk = getArrayBuffer(xhr);
1790       if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
1791         var rangeHeader = xhr.getResponseHeader('Content-Range');
1792         var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
1793         var begin = parseInt(matches[1], 10);
1794         pendingRequest.onDone({
1795           begin: begin,
1796           chunk: chunk
1797         });
1798       } else if (pendingRequest.onProgressiveData) {
1799         pendingRequest.onDone(null);
1800       } else {
1801         pendingRequest.onDone({
1802           begin: 0,
1803           chunk: chunk
1804         });
1805       }
1806     },
1807
1808     hasPendingRequests: function NetworkManager_hasPendingRequests() {
1809       for (var xhrId in this.pendingRequests) {
1810         return true;
1811       }
1812       return false;
1813     },
1814
1815     getRequestXhr: function NetworkManager_getXhr(xhrId) {
1816       return this.pendingRequests[xhrId].xhr;
1817     },
1818
1819     isStreamingRequest: function NetworkManager_isStreamingRequest(xhrId) {
1820       return !!(this.pendingRequests[xhrId].onProgressiveData);
1821     },
1822
1823     isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
1824       return xhrId in this.pendingRequests;
1825     },
1826
1827     isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) {
1828       return xhrId in this.loadedRequests;
1829     },
1830
1831     abortAllRequests: function NetworkManager_abortAllRequests() {
1832       for (var xhrId in this.pendingRequests) {
1833         this.abortRequest(xhrId | 0);
1834       }
1835     },
1836
1837     abortRequest: function NetworkManager_abortRequest(xhrId) {
1838       var xhr = this.pendingRequests[xhrId].xhr;
1839       delete this.pendingRequests[xhrId];
1840       xhr.abort();
1841     }
1842   };
1843
1844   return NetworkManager;
1845 })();
1846
1847
1848 var ChunkedStream = (function ChunkedStreamClosure() {
1849   function ChunkedStream(length, chunkSize, manager) {
1850     this.bytes = new Uint8Array(length);
1851     this.start = 0;
1852     this.pos = 0;
1853     this.end = length;
1854     this.chunkSize = chunkSize;
1855     this.loadedChunks = [];
1856     this.numChunksLoaded = 0;
1857     this.numChunks = Math.ceil(length / chunkSize);
1858     this.manager = manager;
1859     this.progressiveDataLength = 0;
1860     this.lastSuccessfulEnsureByteChunk = -1;  // a single-entry cache
1861   }
1862
1863   // required methods for a stream. if a particular stream does not
1864   // implement these, an error should be thrown
1865   ChunkedStream.prototype = {
1866
1867     getMissingChunks: function ChunkedStream_getMissingChunks() {
1868       var chunks = [];
1869       for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) {
1870         if (!this.loadedChunks[chunk]) {
1871           chunks.push(chunk);
1872         }
1873       }
1874       return chunks;
1875     },
1876
1877     getBaseStreams: function ChunkedStream_getBaseStreams() {
1878       return [this];
1879     },
1880
1881     allChunksLoaded: function ChunkedStream_allChunksLoaded() {
1882       return this.numChunksLoaded === this.numChunks;
1883     },
1884
1885     onReceiveData: function ChunkedStream_onReceiveData(begin, chunk) {
1886       var end = begin + chunk.byteLength;
1887
1888       assert(begin % this.chunkSize === 0, 'Bad begin offset: ' + begin);
1889       // Using this.length is inaccurate here since this.start can be moved
1890       // See ChunkedStream.moveStart()
1891       var length = this.bytes.length;
1892       assert(end % this.chunkSize === 0 || end === length,
1893              'Bad end offset: ' + end);
1894
1895       this.bytes.set(new Uint8Array(chunk), begin);
1896       var chunkSize = this.chunkSize;
1897       var beginChunk = Math.floor(begin / chunkSize);
1898       var endChunk = Math.floor((end - 1) / chunkSize) + 1;
1899       var curChunk;
1900
1901       for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
1902         if (!this.loadedChunks[curChunk]) {
1903           this.loadedChunks[curChunk] = true;
1904           ++this.numChunksLoaded;
1905         }
1906       }
1907     },
1908
1909     onReceiveProgressiveData:
1910         function ChunkedStream_onReceiveProgressiveData(data) {
1911       var position = this.progressiveDataLength;
1912       var beginChunk = Math.floor(position / this.chunkSize);
1913
1914       this.bytes.set(new Uint8Array(data), position);
1915       position += data.byteLength;
1916       this.progressiveDataLength = position;
1917       var endChunk = position >= this.end ? this.numChunks :
1918                      Math.floor(position / this.chunkSize);
1919       var curChunk;
1920       for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
1921         if (!this.loadedChunks[curChunk]) {
1922           this.loadedChunks[curChunk] = true;
1923           ++this.numChunksLoaded;
1924         }
1925       }
1926     },
1927
1928     ensureByte: function ChunkedStream_ensureByte(pos) {
1929       var chunk = Math.floor(pos / this.chunkSize);
1930       if (chunk === this.lastSuccessfulEnsureByteChunk) {
1931         return;
1932       }
1933
1934       if (!this.loadedChunks[chunk]) {
1935         throw new MissingDataException(pos, pos + 1);
1936       }
1937       this.lastSuccessfulEnsureByteChunk = chunk;
1938     },
1939
1940     ensureRange: function ChunkedStream_ensureRange(begin, end) {
1941       if (begin >= end) {
1942         return;
1943       }
1944
1945       if (end <= this.progressiveDataLength) {
1946         return;
1947       }
1948
1949       var chunkSize = this.chunkSize;
1950       var beginChunk = Math.floor(begin / chunkSize);
1951       var endChunk = Math.floor((end - 1) / chunkSize) + 1;
1952       for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
1953         if (!this.loadedChunks[chunk]) {
1954           throw new MissingDataException(begin, end);
1955         }
1956       }
1957     },
1958
1959     nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {
1960       var chunk, n;
1961       for (chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
1962         if (!this.loadedChunks[chunk]) {
1963           return chunk;
1964         }
1965       }
1966       // Wrap around to beginning
1967       for (chunk = 0; chunk < beginChunk; ++chunk) {
1968         if (!this.loadedChunks[chunk]) {
1969           return chunk;
1970         }
1971       }
1972       return null;
1973     },
1974
1975     hasChunk: function ChunkedStream_hasChunk(chunk) {
1976       return !!this.loadedChunks[chunk];
1977     },
1978
1979     get length() {
1980       return this.end - this.start;
1981     },
1982
1983     get isEmpty() {
1984       return this.length === 0;
1985     },
1986
1987     getByte: function ChunkedStream_getByte() {
1988       var pos = this.pos;
1989       if (pos >= this.end) {
1990         return -1;
1991       }
1992       this.ensureByte(pos);
1993       return this.bytes[this.pos++];
1994     },
1995
1996     getUint16: function ChunkedStream_getUint16() {
1997       var b0 = this.getByte();
1998       var b1 = this.getByte();
1999       if (b0 === -1 || b1 === -1) {
2000         return -1;
2001       }
2002       return (b0 << 8) + b1;
2003     },
2004
2005     getInt32: function ChunkedStream_getInt32() {
2006       var b0 = this.getByte();
2007       var b1 = this.getByte();
2008       var b2 = this.getByte();
2009       var b3 = this.getByte();
2010       return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
2011     },
2012
2013     // returns subarray of original buffer
2014     // should only be read
2015     getBytes: function ChunkedStream_getBytes(length) {
2016       var bytes = this.bytes;
2017       var pos = this.pos;
2018       var strEnd = this.end;
2019
2020       if (!length) {
2021         this.ensureRange(pos, strEnd);
2022         return bytes.subarray(pos, strEnd);
2023       }
2024
2025       var end = pos + length;
2026       if (end > strEnd) {
2027         end = strEnd;
2028       }
2029       this.ensureRange(pos, end);
2030
2031       this.pos = end;
2032       return bytes.subarray(pos, end);
2033     },
2034
2035     peekByte: function ChunkedStream_peekByte() {
2036       var peekedByte = this.getByte();
2037       this.pos--;
2038       return peekedByte;
2039     },
2040
2041     peekBytes: function ChunkedStream_peekBytes(length) {
2042       var bytes = this.getBytes(length);
2043       this.pos -= bytes.length;
2044       return bytes;
2045     },
2046
2047     getByteRange: function ChunkedStream_getBytes(begin, end) {
2048       this.ensureRange(begin, end);
2049       return this.bytes.subarray(begin, end);
2050     },
2051
2052     skip: function ChunkedStream_skip(n) {
2053       if (!n) {
2054         n = 1;
2055       }
2056       this.pos += n;
2057     },
2058
2059     reset: function ChunkedStream_reset() {
2060       this.pos = this.start;
2061     },
2062
2063     moveStart: function ChunkedStream_moveStart() {
2064       this.start = this.pos;
2065     },
2066
2067     makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) {
2068       this.ensureRange(start, start + length);
2069
2070       function ChunkedStreamSubstream() {}
2071       ChunkedStreamSubstream.prototype = Object.create(this);
2072       ChunkedStreamSubstream.prototype.getMissingChunks = function() {
2073         var chunkSize = this.chunkSize;
2074         var beginChunk = Math.floor(this.start / chunkSize);
2075         var endChunk = Math.floor((this.end - 1) / chunkSize) + 1;
2076         var missingChunks = [];
2077         for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
2078           if (!this.loadedChunks[chunk]) {
2079             missingChunks.push(chunk);
2080           }
2081         }
2082         return missingChunks;
2083       };
2084       var subStream = new ChunkedStreamSubstream();
2085       subStream.pos = subStream.start = start;
2086       subStream.end = start + length || this.end;
2087       subStream.dict = dict;
2088       return subStream;
2089     },
2090
2091     isStream: true
2092   };
2093
2094   return ChunkedStream;
2095 })();
2096
2097 var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
2098
2099   function ChunkedStreamManager(length, chunkSize, url, args) {
2100     this.stream = new ChunkedStream(length, chunkSize, this);
2101     this.length = length;
2102     this.chunkSize = chunkSize;
2103     this.url = url;
2104     this.disableAutoFetch = args.disableAutoFetch;
2105     var msgHandler = this.msgHandler = args.msgHandler;
2106
2107     if (args.chunkedViewerLoading) {
2108       msgHandler.on('OnDataRange', this.onReceiveData.bind(this));
2109       msgHandler.on('OnDataProgress', this.onProgress.bind(this));
2110       this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
2111         msgHandler.send('RequestDataRange', { begin: begin, end: end });
2112       };
2113     } else {
2114
2115       var getXhr = function getXhr() {
2116         return new XMLHttpRequest();
2117       };
2118       this.networkManager = new NetworkManager(this.url, {
2119         getXhr: getXhr,
2120         httpHeaders: args.httpHeaders,
2121         withCredentials: args.withCredentials
2122       });
2123       this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
2124         this.networkManager.requestRange(begin, end, {
2125           onDone: this.onReceiveData.bind(this),
2126           onProgress: this.onProgress.bind(this)
2127         });
2128       };
2129     }
2130
2131     this.currRequestId = 0;
2132
2133     this.chunksNeededByRequest = {};
2134     this.requestsByChunk = {};
2135     this.callbacksByRequest = {};
2136     this.progressiveDataLength = 0;
2137
2138     this._loadedStreamCapability = createPromiseCapability();
2139
2140     if (args.initialData) {
2141       this.onReceiveData({chunk: args.initialData});
2142     }
2143   }
2144
2145   ChunkedStreamManager.prototype = {
2146     onLoadedStream: function ChunkedStreamManager_getLoadedStream() {
2147       return this._loadedStreamCapability.promise;
2148     },
2149
2150     // Get all the chunks that are not yet loaded and groups them into
2151     // contiguous ranges to load in as few requests as possible
2152     requestAllChunks: function ChunkedStreamManager_requestAllChunks() {
2153       var missingChunks = this.stream.getMissingChunks();
2154       this.requestChunks(missingChunks);
2155       return this._loadedStreamCapability.promise;
2156     },
2157
2158     requestChunks: function ChunkedStreamManager_requestChunks(chunks,
2159                                                                callback) {
2160       var requestId = this.currRequestId++;
2161
2162       var chunksNeeded;
2163       var i, ii;
2164       this.chunksNeededByRequest[requestId] = chunksNeeded = {};
2165       for (i = 0, ii = chunks.length; i < ii; i++) {
2166         if (!this.stream.hasChunk(chunks[i])) {
2167           chunksNeeded[chunks[i]] = true;
2168         }
2169       }
2170
2171       if (isEmptyObj(chunksNeeded)) {
2172         if (callback) {
2173           callback();
2174         }
2175         return;
2176       }
2177
2178       this.callbacksByRequest[requestId] = callback;
2179
2180       var chunksToRequest = [];
2181       for (var chunk in chunksNeeded) {
2182         chunk = chunk | 0;
2183         if (!(chunk in this.requestsByChunk)) {
2184           this.requestsByChunk[chunk] = [];
2185           chunksToRequest.push(chunk);
2186         }
2187         this.requestsByChunk[chunk].push(requestId);
2188       }
2189
2190       if (!chunksToRequest.length) {
2191         return;
2192       }
2193
2194       var groupedChunksToRequest = this.groupChunks(chunksToRequest);
2195
2196       for (i = 0; i < groupedChunksToRequest.length; ++i) {
2197         var groupedChunk = groupedChunksToRequest[i];
2198         var begin = groupedChunk.beginChunk * this.chunkSize;
2199         var end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length);
2200         this.sendRequest(begin, end);
2201       }
2202     },
2203
2204     getStream: function ChunkedStreamManager_getStream() {
2205       return this.stream;
2206     },
2207
2208     // Loads any chunks in the requested range that are not yet loaded
2209     requestRange: function ChunkedStreamManager_requestRange(
2210                       begin, end, callback) {
2211
2212       end = Math.min(end, this.length);
2213
2214       var beginChunk = this.getBeginChunk(begin);
2215       var endChunk = this.getEndChunk(end);
2216
2217       var chunks = [];
2218       for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
2219         chunks.push(chunk);
2220       }
2221
2222       this.requestChunks(chunks, callback);
2223     },
2224
2225     requestRanges: function ChunkedStreamManager_requestRanges(ranges,
2226                                                                callback) {
2227       ranges = ranges || [];
2228       var chunksToRequest = [];
2229
2230       for (var i = 0; i < ranges.length; i++) {
2231         var beginChunk = this.getBeginChunk(ranges[i].begin);
2232         var endChunk = this.getEndChunk(ranges[i].end);
2233         for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
2234           if (chunksToRequest.indexOf(chunk) < 0) {
2235             chunksToRequest.push(chunk);
2236           }
2237         }
2238       }
2239
2240       chunksToRequest.sort(function(a, b) { return a - b; });
2241       this.requestChunks(chunksToRequest, callback);
2242     },
2243
2244     // Groups a sorted array of chunks into as few continguous larger
2245     // chunks as possible
2246     groupChunks: function ChunkedStreamManager_groupChunks(chunks) {
2247       var groupedChunks = [];
2248       var beginChunk = -1;
2249       var prevChunk = -1;
2250       for (var i = 0; i < chunks.length; ++i) {
2251         var chunk = chunks[i];
2252
2253         if (beginChunk < 0) {
2254           beginChunk = chunk;
2255         }
2256
2257         if (prevChunk >= 0 && prevChunk + 1 !== chunk) {
2258           groupedChunks.push({ beginChunk: beginChunk,
2259                                endChunk: prevChunk + 1 });
2260           beginChunk = chunk;
2261         }
2262         if (i + 1 === chunks.length) {
2263           groupedChunks.push({ beginChunk: beginChunk,
2264                                endChunk: chunk + 1 });
2265         }
2266
2267         prevChunk = chunk;
2268       }
2269       return groupedChunks;
2270     },
2271
2272     onProgress: function ChunkedStreamManager_onProgress(args) {
2273       var bytesLoaded = (this.stream.numChunksLoaded * this.chunkSize +
2274                          args.loaded);
2275       this.msgHandler.send('DocProgress', {
2276         loaded: bytesLoaded,
2277         total: this.length
2278       });
2279     },
2280
2281     onReceiveData: function ChunkedStreamManager_onReceiveData(args) {
2282       var chunk = args.chunk;
2283       var isProgressive = args.begin === undefined;
2284       var begin = isProgressive ? this.progressiveDataLength : args.begin;
2285       var end = begin + chunk.byteLength;
2286
2287       var beginChunk = Math.floor(begin / this.chunkSize);
2288       var endChunk = end < this.length ? Math.floor(end / this.chunkSize) :
2289                                          Math.ceil(end / this.chunkSize);
2290
2291       if (isProgressive) {
2292         this.stream.onReceiveProgressiveData(chunk);
2293         this.progressiveDataLength = end;
2294       } else {
2295         this.stream.onReceiveData(begin, chunk);
2296       }
2297
2298       if (this.stream.allChunksLoaded()) {
2299         this._loadedStreamCapability.resolve(this.stream);
2300       }
2301
2302       var loadedRequests = [];
2303       var i, requestId;
2304       for (chunk = beginChunk; chunk < endChunk; ++chunk) {
2305         // The server might return more chunks than requested
2306         var requestIds = this.requestsByChunk[chunk] || [];
2307         delete this.requestsByChunk[chunk];
2308
2309         for (i = 0; i < requestIds.length; ++i) {
2310           requestId = requestIds[i];
2311           var chunksNeeded = this.chunksNeededByRequest[requestId];
2312           if (chunk in chunksNeeded) {
2313             delete chunksNeeded[chunk];
2314           }
2315
2316           if (!isEmptyObj(chunksNeeded)) {
2317             continue;
2318           }
2319
2320           loadedRequests.push(requestId);
2321         }
2322       }
2323
2324       // If there are no pending requests, automatically fetch the next
2325       // unfetched chunk of the PDF
2326       if (!this.disableAutoFetch && isEmptyObj(this.requestsByChunk)) {
2327         var nextEmptyChunk;
2328         if (this.stream.numChunksLoaded === 1) {
2329           // This is a special optimization so that after fetching the first
2330           // chunk, rather than fetching the second chunk, we fetch the last
2331           // chunk.
2332           var lastChunk = this.stream.numChunks - 1;
2333           if (!this.stream.hasChunk(lastChunk)) {
2334             nextEmptyChunk = lastChunk;
2335           }
2336         } else {
2337           nextEmptyChunk = this.stream.nextEmptyChunk(endChunk);
2338         }
2339         if (isInt(nextEmptyChunk)) {
2340           this.requestChunks([nextEmptyChunk]);
2341         }
2342       }
2343
2344       for (i = 0; i < loadedRequests.length; ++i) {
2345         requestId = loadedRequests[i];
2346         var callback = this.callbacksByRequest[requestId];
2347         delete this.callbacksByRequest[requestId];
2348         if (callback) {
2349           callback();
2350         }
2351       }
2352
2353       this.msgHandler.send('DocProgress', {
2354         loaded: this.stream.numChunksLoaded * this.chunkSize,
2355         total: this.length
2356       });
2357     },
2358
2359     onError: function ChunkedStreamManager_onError(err) {
2360       this._loadedStreamCapability.reject(err);
2361     },
2362
2363     getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) {
2364       var chunk = Math.floor(begin / this.chunkSize);
2365       return chunk;
2366     },
2367
2368     getEndChunk: function ChunkedStreamManager_getEndChunk(end) {
2369       if (end % this.chunkSize === 0) {
2370         return end / this.chunkSize;
2371       }
2372
2373       // 0 -> 0
2374       // 1 -> 1
2375       // 99 -> 1
2376       // 100 -> 1
2377       // 101 -> 2
2378       var chunk = Math.floor((end - 1) / this.chunkSize) + 1;
2379       return chunk;
2380     }
2381   };
2382
2383   return ChunkedStreamManager;
2384 })();
2385
2386
2387 // The maximum number of bytes fetched per range request
2388 var RANGE_CHUNK_SIZE = 65536;
2389
2390 // TODO(mack): Make use of PDFJS.Util.inherit() when it becomes available
2391 var BasePdfManager = (function BasePdfManagerClosure() {
2392   function BasePdfManager() {
2393     throw new Error('Cannot initialize BaseManagerManager');
2394   }
2395
2396   BasePdfManager.prototype = {
2397     onLoadedStream: function BasePdfManager_onLoadedStream() {
2398       throw new NotImplementedException();
2399     },
2400
2401     ensureDoc: function BasePdfManager_ensureDoc(prop, args) {
2402       return this.ensure(this.pdfDocument, prop, args);
2403     },
2404
2405     ensureXRef: function BasePdfManager_ensureXRef(prop, args) {
2406       return this.ensure(this.pdfDocument.xref, prop, args);
2407     },
2408
2409     ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) {
2410       return this.ensure(this.pdfDocument.catalog, prop, args);
2411     },
2412
2413     getPage: function BasePdfManager_pagePage(pageIndex) {
2414       return this.pdfDocument.getPage(pageIndex);
2415     },
2416
2417     cleanup: function BasePdfManager_cleanup() {
2418       return this.pdfDocument.cleanup();
2419     },
2420
2421     ensure: function BasePdfManager_ensure(obj, prop, args) {
2422       return new NotImplementedException();
2423     },
2424
2425     requestRange: function BasePdfManager_ensure(begin, end) {
2426       return new NotImplementedException();
2427     },
2428
2429     requestLoadedStream: function BasePdfManager_requestLoadedStream() {
2430       return new NotImplementedException();
2431     },
2432
2433     sendProgressiveData: function BasePdfManager_sendProgressiveData(chunk) {
2434       return new NotImplementedException();
2435     },
2436
2437     updatePassword: function BasePdfManager_updatePassword(password) {
2438       this.pdfDocument.xref.password = this.password = password;
2439       if (this._passwordChangedCapability) {
2440         this._passwordChangedCapability.resolve();
2441       }
2442     },
2443
2444     passwordChanged: function BasePdfManager_passwordChanged() {
2445       this._passwordChangedCapability = createPromiseCapability();
2446       return this._passwordChangedCapability.promise;
2447     },
2448
2449     terminate: function BasePdfManager_terminate() {
2450       return new NotImplementedException();
2451     }
2452   };
2453
2454   return BasePdfManager;
2455 })();
2456
2457 var LocalPdfManager = (function LocalPdfManagerClosure() {
2458   function LocalPdfManager(data, password) {
2459     var stream = new Stream(data);
2460     this.pdfDocument = new PDFDocument(this, stream, password);
2461     this._loadedStreamCapability = createPromiseCapability();
2462     this._loadedStreamCapability.resolve(stream);
2463   }
2464
2465   LocalPdfManager.prototype = Object.create(BasePdfManager.prototype);
2466   LocalPdfManager.prototype.constructor = LocalPdfManager;
2467
2468   LocalPdfManager.prototype.ensure =
2469       function LocalPdfManager_ensure(obj, prop, args) {
2470     return new Promise(function (resolve, reject) {
2471       try {
2472         var value = obj[prop];
2473         var result;
2474         if (typeof value === 'function') {
2475           result = value.apply(obj, args);
2476         } else {
2477           result = value;
2478         }
2479         resolve(result);
2480       } catch (e) {
2481         reject(e);
2482       }
2483     });
2484   };
2485
2486   LocalPdfManager.prototype.requestRange =
2487       function LocalPdfManager_requestRange(begin, end) {
2488     return Promise.resolve();
2489   };
2490
2491   LocalPdfManager.prototype.requestLoadedStream =
2492       function LocalPdfManager_requestLoadedStream() {
2493   };
2494
2495   LocalPdfManager.prototype.onLoadedStream =
2496       function LocalPdfManager_getLoadedStream() {
2497     return this._loadedStreamCapability.promise;
2498   };
2499
2500   LocalPdfManager.prototype.terminate =
2501       function LocalPdfManager_terminate() {
2502     return;
2503   };
2504
2505   return LocalPdfManager;
2506 })();
2507
2508 var NetworkPdfManager = (function NetworkPdfManagerClosure() {
2509   function NetworkPdfManager(args, msgHandler) {
2510
2511     this.msgHandler = msgHandler;
2512
2513     var params = {
2514       msgHandler: msgHandler,
2515       httpHeaders: args.httpHeaders,
2516       withCredentials: args.withCredentials,
2517       chunkedViewerLoading: args.chunkedViewerLoading,
2518       disableAutoFetch: args.disableAutoFetch,
2519       initialData: args.initialData
2520     };
2521     this.streamManager = new ChunkedStreamManager(args.length, RANGE_CHUNK_SIZE,
2522                                                   args.url, params);
2523
2524     this.pdfDocument = new PDFDocument(this, this.streamManager.getStream(),
2525                                     args.password);
2526   }
2527
2528   NetworkPdfManager.prototype = Object.create(BasePdfManager.prototype);
2529   NetworkPdfManager.prototype.constructor = NetworkPdfManager;
2530
2531   NetworkPdfManager.prototype.ensure =
2532       function NetworkPdfManager_ensure(obj, prop, args) {
2533     var pdfManager = this;
2534
2535     return new Promise(function (resolve, reject) {
2536       function ensureHelper() {
2537         try {
2538           var result;
2539           var value = obj[prop];
2540           if (typeof value === 'function') {
2541             result = value.apply(obj, args);
2542           } else {
2543             result = value;
2544           }
2545           resolve(result);
2546         } catch(e) {
2547           if (!(e instanceof MissingDataException)) {
2548             reject(e);
2549             return;
2550           }
2551           pdfManager.streamManager.requestRange(e.begin, e.end, ensureHelper);
2552         }
2553       }
2554
2555       ensureHelper();
2556     });
2557   };
2558
2559   NetworkPdfManager.prototype.requestRange =
2560       function NetworkPdfManager_requestRange(begin, end) {
2561     return new Promise(function (resolve) {
2562       this.streamManager.requestRange(begin, end, function() {
2563         resolve();
2564       });
2565     }.bind(this));
2566   };
2567
2568   NetworkPdfManager.prototype.requestLoadedStream =
2569       function NetworkPdfManager_requestLoadedStream() {
2570     this.streamManager.requestAllChunks();
2571   };
2572
2573   NetworkPdfManager.prototype.sendProgressiveData =
2574       function NetworkPdfManager_sendProgressiveData(chunk) {
2575     this.streamManager.onReceiveData({ chunk: chunk });
2576   };
2577
2578   NetworkPdfManager.prototype.onLoadedStream =
2579       function NetworkPdfManager_getLoadedStream() {
2580     return this.streamManager.onLoadedStream();
2581   };
2582
2583   NetworkPdfManager.prototype.terminate =
2584       function NetworkPdfManager_terminate() {
2585     this.streamManager.networkManager.abortAllRequests();
2586   };
2587
2588   return NetworkPdfManager;
2589 })();
2590
2591
2592 var Page = (function PageClosure() {
2593
2594   var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
2595
2596   function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache) {
2597     this.pdfManager = pdfManager;
2598     this.pageIndex = pageIndex;
2599     this.pageDict = pageDict;
2600     this.xref = xref;
2601     this.ref = ref;
2602     this.fontCache = fontCache;
2603     this.idCounters = {
2604       obj: 0
2605     };
2606     this.resourcesPromise = null;
2607   }
2608
2609   Page.prototype = {
2610     getPageProp: function Page_getPageProp(key) {
2611       return this.pageDict.get(key);
2612     },
2613
2614     getInheritedPageProp: function Page_inheritPageProp(key) {
2615       var dict = this.pageDict;
2616       var value = dict.get(key);
2617       while (value === undefined) {
2618         dict = dict.get('Parent');
2619         if (!dict) {
2620           break;
2621         }
2622         value = dict.get(key);
2623       }
2624       return value;
2625     },
2626
2627     get content() {
2628       return this.getPageProp('Contents');
2629     },
2630
2631     get resources() {
2632       var value = this.getInheritedPageProp('Resources');
2633       // For robustness: The spec states that a \Resources entry has to be
2634       // present, but can be empty. Some document omit it still. In this case
2635       // return an empty dictionary:
2636       if (value === undefined) {
2637         value = Dict.empty;
2638       }
2639       return shadow(this, 'resources', value);
2640     },
2641
2642     get mediaBox() {
2643       var obj = this.getInheritedPageProp('MediaBox');
2644       // Reset invalid media box to letter size.
2645       if (!isArray(obj) || obj.length !== 4) {
2646         obj = LETTER_SIZE_MEDIABOX;
2647       }
2648       return shadow(this, 'mediaBox', obj);
2649     },
2650
2651     get view() {
2652       var mediaBox = this.mediaBox;
2653       var cropBox = this.getInheritedPageProp('CropBox');
2654       if (!isArray(cropBox) || cropBox.length !== 4) {
2655         return shadow(this, 'view', mediaBox);
2656       }
2657
2658       // From the spec, 6th ed., p.963:
2659       // "The crop, bleed, trim, and art boxes should not ordinarily
2660       // extend beyond the boundaries of the media box. If they do, they are
2661       // effectively reduced to their intersection with the media box."
2662       cropBox = Util.intersect(cropBox, mediaBox);
2663       if (!cropBox) {
2664         return shadow(this, 'view', mediaBox);
2665       }
2666       return shadow(this, 'view', cropBox);
2667     },
2668
2669     get annotationRefs() {
2670       return shadow(this, 'annotationRefs',
2671                     this.getInheritedPageProp('Annots'));
2672     },
2673
2674     get rotate() {
2675       var rotate = this.getInheritedPageProp('Rotate') || 0;
2676       // Normalize rotation so it's a multiple of 90 and between 0 and 270
2677       if (rotate % 90 !== 0) {
2678         rotate = 0;
2679       } else if (rotate >= 360) {
2680         rotate = rotate % 360;
2681       } else if (rotate < 0) {
2682         // The spec doesn't cover negatives, assume its counterclockwise
2683         // rotation. The following is the other implementation of modulo.
2684         rotate = ((rotate % 360) + 360) % 360;
2685       }
2686       return shadow(this, 'rotate', rotate);
2687     },
2688
2689     getContentStream: function Page_getContentStream() {
2690       var content = this.content;
2691       var stream;
2692       if (isArray(content)) {
2693         // fetching items
2694         var xref = this.xref;
2695         var i, n = content.length;
2696         var streams = [];
2697         for (i = 0; i < n; ++i) {
2698           streams.push(xref.fetchIfRef(content[i]));
2699         }
2700         stream = new StreamsSequenceStream(streams);
2701       } else if (isStream(content)) {
2702         stream = content;
2703       } else {
2704         // replacing non-existent page content with empty one
2705         stream = new NullStream();
2706       }
2707       return stream;
2708     },
2709
2710     loadResources: function Page_loadResources(keys) {
2711       if (!this.resourcesPromise) {
2712         // TODO: add async getInheritedPageProp and remove this.
2713         this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
2714       }
2715       return this.resourcesPromise.then(function resourceSuccess() {
2716         var objectLoader = new ObjectLoader(this.resources.map,
2717                                             keys,
2718                                             this.xref);
2719         return objectLoader.load();
2720       }.bind(this));
2721     },
2722
2723     getOperatorList: function Page_getOperatorList(handler, intent) {
2724       var self = this;
2725
2726       var pdfManager = this.pdfManager;
2727       var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
2728                                                    []);
2729       var resourcesPromise = this.loadResources([
2730         'ExtGState',
2731         'ColorSpace',
2732         'Pattern',
2733         'Shading',
2734         'XObject',
2735         'Font'
2736         // ProcSet
2737         // Properties
2738       ]);
2739
2740       var partialEvaluator = new PartialEvaluator(pdfManager, this.xref,
2741                                                   handler, this.pageIndex,
2742                                                   'p' + this.pageIndex + '_',
2743                                                   this.idCounters,
2744                                                   this.fontCache);
2745
2746       var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
2747       var pageListPromise = dataPromises.then(function(data) {
2748         var contentStream = data[0];
2749         var opList = new OperatorList(intent, handler, self.pageIndex);
2750
2751         handler.send('StartRenderPage', {
2752           transparency: partialEvaluator.hasBlendModes(self.resources),
2753           pageIndex: self.pageIndex,
2754           intent: intent
2755         });
2756         return partialEvaluator.getOperatorList(contentStream, self.resources,
2757           opList).then(function () {
2758             return opList;
2759           });
2760       });
2761
2762       var annotationsPromise = pdfManager.ensure(this, 'annotations');
2763       return Promise.all([pageListPromise, annotationsPromise]).then(
2764           function(datas) {
2765         var pageOpList = datas[0];
2766         var annotations = datas[1];
2767
2768         if (annotations.length === 0) {
2769           pageOpList.flush(true);
2770           return pageOpList;
2771         }
2772
2773         var annotationsReadyPromise = Annotation.appendToOperatorList(
2774           annotations, pageOpList, pdfManager, partialEvaluator, intent);
2775         return annotationsReadyPromise.then(function () {
2776           pageOpList.flush(true);
2777           return pageOpList;
2778         });
2779       });
2780     },
2781
2782     extractTextContent: function Page_extractTextContent() {
2783       var handler = {
2784         on: function nullHandlerOn() {},
2785         send: function nullHandlerSend() {}
2786       };
2787
2788       var self = this;
2789
2790       var pdfManager = this.pdfManager;
2791       var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
2792                                                    []);
2793
2794       var resourcesPromise = this.loadResources([
2795         'ExtGState',
2796         'XObject',
2797         'Font'
2798       ]);
2799
2800       var dataPromises = Promise.all([contentStreamPromise,
2801                                       resourcesPromise]);
2802       return dataPromises.then(function(data) {
2803         var contentStream = data[0];
2804         var partialEvaluator = new PartialEvaluator(pdfManager, self.xref,
2805                                                     handler, self.pageIndex,
2806                                                     'p' + self.pageIndex + '_',
2807                                                     self.idCounters,
2808                                                     self.fontCache);
2809
2810         return partialEvaluator.getTextContent(contentStream,
2811                                                self.resources);
2812       });
2813     },
2814
2815     getAnnotationsData: function Page_getAnnotationsData() {
2816       var annotations = this.annotations;
2817       var annotationsData = [];
2818       for (var i = 0, n = annotations.length; i < n; ++i) {
2819         annotationsData.push(annotations[i].getData());
2820       }
2821       return annotationsData;
2822     },
2823
2824     get annotations() {
2825       var annotations = [];
2826       var annotationRefs = (this.annotationRefs || []);
2827       for (var i = 0, n = annotationRefs.length; i < n; ++i) {
2828         var annotationRef = annotationRefs[i];
2829         var annotation = Annotation.fromRef(this.xref, annotationRef);
2830         if (annotation) {
2831           annotations.push(annotation);
2832         }
2833       }
2834       return shadow(this, 'annotations', annotations);
2835     }
2836   };
2837
2838   return Page;
2839 })();
2840
2841 /**
2842  * The `PDFDocument` holds all the data of the PDF file. Compared to the
2843  * `PDFDoc`, this one doesn't have any job management code.
2844  * Right now there exists one PDFDocument on the main thread + one object
2845  * for each worker. If there is no worker support enabled, there are two
2846  * `PDFDocument` objects on the main thread created.
2847  */
2848 var PDFDocument = (function PDFDocumentClosure() {
2849   var FINGERPRINT_FIRST_BYTES = 1024;
2850   var EMPTY_FINGERPRINT = '\x00\x00\x00\x00\x00\x00\x00' +
2851     '\x00\x00\x00\x00\x00\x00\x00\x00\x00';
2852
2853   function PDFDocument(pdfManager, arg, password) {
2854     if (isStream(arg)) {
2855       init.call(this, pdfManager, arg, password);
2856     } else if (isArrayBuffer(arg)) {
2857       init.call(this, pdfManager, new Stream(arg), password);
2858     } else {
2859       error('PDFDocument: Unknown argument type');
2860     }
2861   }
2862
2863   function init(pdfManager, stream, password) {
2864     assert(stream.length > 0, 'stream must have data');
2865     this.pdfManager = pdfManager;
2866     this.stream = stream;
2867     var xref = new XRef(this.stream, password, pdfManager);
2868     this.xref = xref;
2869   }
2870
2871   function find(stream, needle, limit, backwards) {
2872     var pos = stream.pos;
2873     var end = stream.end;
2874     var strBuf = [];
2875     if (pos + limit > end) {
2876       limit = end - pos;
2877     }
2878     for (var n = 0; n < limit; ++n) {
2879       strBuf.push(String.fromCharCode(stream.getByte()));
2880     }
2881     var str = strBuf.join('');
2882     stream.pos = pos;
2883     var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);
2884     if (index === -1) {
2885       return false; /* not found */
2886     }
2887     stream.pos += index;
2888     return true; /* found */
2889   }
2890
2891   var DocumentInfoValidators = {
2892     get entries() {
2893       // Lazily build this since all the validation functions below are not
2894       // defined until after this file loads.
2895       return shadow(this, 'entries', {
2896         Title: isString,
2897         Author: isString,
2898         Subject: isString,
2899         Keywords: isString,
2900         Creator: isString,
2901         Producer: isString,
2902         CreationDate: isString,
2903         ModDate: isString,
2904         Trapped: isName
2905       });
2906     }
2907   };
2908
2909   PDFDocument.prototype = {
2910     parse: function PDFDocument_parse(recoveryMode) {
2911       this.setup(recoveryMode);
2912       try {
2913         // checking if AcroForm is present
2914         this.acroForm = this.catalog.catDict.get('AcroForm');
2915         if (this.acroForm) {
2916           this.xfa = this.acroForm.get('XFA');
2917           var fields = this.acroForm.get('Fields');
2918           if ((!fields || !isArray(fields) || fields.length === 0) &&
2919               !this.xfa) {
2920             // no fields and no XFA -- not a form (?)
2921             this.acroForm = null;
2922           }
2923         }
2924       } catch (ex) {
2925         info('Something wrong with AcroForm entry');
2926         this.acroForm = null;
2927       }
2928     },
2929
2930     get linearization() {
2931       var linearization = null;
2932       if (this.stream.length) {
2933         try {
2934           linearization = Linearization.create(this.stream);
2935         } catch (err) {
2936           if (err instanceof MissingDataException) {
2937             throw err;
2938           }
2939           info(err);
2940         }
2941       }
2942       // shadow the prototype getter with a data property
2943       return shadow(this, 'linearization', linearization);
2944     },
2945     get startXRef() {
2946       var stream = this.stream;
2947       var startXRef = 0;
2948       var linearization = this.linearization;
2949       if (linearization) {
2950         // Find end of first obj.
2951         stream.reset();
2952         if (find(stream, 'endobj', 1024)) {
2953           startXRef = stream.pos + 6;
2954         }
2955       } else {
2956         // Find startxref by jumping backward from the end of the file.
2957         var step = 1024;
2958         var found = false, pos = stream.end;
2959         while (!found && pos > 0) {
2960           pos -= step - 'startxref'.length;
2961           if (pos < 0) {
2962             pos = 0;
2963           }
2964           stream.pos = pos;
2965           found = find(stream, 'startxref', step, true);
2966         }
2967         if (found) {
2968           stream.skip(9);
2969           var ch;
2970           do {
2971             ch = stream.getByte();
2972           } while (Lexer.isSpace(ch));
2973           var str = '';
2974           while (ch >= 0x20 && ch <= 0x39) { // < '9'
2975             str += String.fromCharCode(ch);
2976             ch = stream.getByte();
2977           }
2978           startXRef = parseInt(str, 10);
2979           if (isNaN(startXRef)) {
2980             startXRef = 0;
2981           }
2982         }
2983       }
2984       // shadow the prototype getter with a data property
2985       return shadow(this, 'startXRef', startXRef);
2986     },
2987     get mainXRefEntriesOffset() {
2988       var mainXRefEntriesOffset = 0;
2989       var linearization = this.linearization;
2990       if (linearization) {
2991         mainXRefEntriesOffset = linearization.mainXRefEntriesOffset;
2992       }
2993       // shadow the prototype getter with a data property
2994       return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset);
2995     },
2996     // Find the header, remove leading garbage and setup the stream
2997     // starting from the header.
2998     checkHeader: function PDFDocument_checkHeader() {
2999       var stream = this.stream;
3000       stream.reset();
3001       if (find(stream, '%PDF-', 1024)) {
3002         // Found the header, trim off any garbage before it.
3003         stream.moveStart();
3004         // Reading file format version
3005         var MAX_VERSION_LENGTH = 12;
3006         var version = '', ch;
3007         while ((ch = stream.getByte()) > 0x20) { // SPACE
3008           if (version.length >= MAX_VERSION_LENGTH) {
3009             break;
3010           }
3011           version += String.fromCharCode(ch);
3012         }
3013         // removing "%PDF-"-prefix
3014         this.pdfFormatVersion = version.substring(5);
3015         return;
3016       }
3017       // May not be a PDF file, continue anyway.
3018     },
3019     parseStartXRef: function PDFDocument_parseStartXRef() {
3020       var startXRef = this.startXRef;
3021       this.xref.setStartXRef(startXRef);
3022     },
3023     setup: function PDFDocument_setup(recoveryMode) {
3024       this.xref.parse(recoveryMode);
3025       this.catalog = new Catalog(this.pdfManager, this.xref);
3026     },
3027     get numPages() {
3028       var linearization = this.linearization;
3029       var num = linearization ? linearization.numPages : this.catalog.numPages;
3030       // shadow the prototype getter
3031       return shadow(this, 'numPages', num);
3032     },
3033     get documentInfo() {
3034       var docInfo = {
3035         PDFFormatVersion: this.pdfFormatVersion,
3036         IsAcroFormPresent: !!this.acroForm,
3037         IsXFAPresent: !!this.xfa
3038       };
3039       var infoDict;
3040       try {
3041         infoDict = this.xref.trailer.get('Info');
3042       } catch (err) {
3043         info('The document information dictionary is invalid.');
3044       }
3045       if (infoDict) {
3046         var validEntries = DocumentInfoValidators.entries;
3047         // Only fill the document info with valid entries from the spec.
3048         for (var key in validEntries) {
3049           if (infoDict.has(key)) {
3050             var value = infoDict.get(key);
3051             // Make sure the value conforms to the spec.
3052             if (validEntries[key](value)) {
3053               docInfo[key] = (typeof value !== 'string' ?
3054                               value : stringToPDFString(value));
3055             } else {
3056               info('Bad value in document info for "' + key + '"');
3057             }
3058           }
3059         }
3060       }
3061       return shadow(this, 'documentInfo', docInfo);
3062     },
3063     get fingerprint() {
3064       var xref = this.xref, idArray, hash, fileID = '';
3065
3066       if (xref.trailer.has('ID')) {
3067         idArray = xref.trailer.get('ID');
3068       }
3069       if (idArray && isArray(idArray) && idArray[0] !== EMPTY_FINGERPRINT) {
3070         hash = stringToBytes(idArray[0]);
3071       } else {
3072         if (this.stream.ensureRange) {
3073           this.stream.ensureRange(0,
3074             Math.min(FINGERPRINT_FIRST_BYTES, this.stream.end));
3075         }
3076         hash = calculateMD5(this.stream.bytes.subarray(0,
3077           FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES);
3078       }
3079
3080       for (var i = 0, n = hash.length; i < n; i++) {
3081         var hex = hash[i].toString(16);
3082         fileID += hex.length === 1 ? '0' + hex : hex;
3083       }
3084
3085       return shadow(this, 'fingerprint', fileID);
3086     },
3087
3088     getPage: function PDFDocument_getPage(pageIndex) {
3089       return this.catalog.getPage(pageIndex);
3090     },
3091
3092     cleanup: function PDFDocument_cleanup() {
3093       return this.catalog.cleanup();
3094     }
3095   };
3096
3097   return PDFDocument;
3098 })();
3099
3100
3101 var Name = (function NameClosure() {
3102   function Name(name) {
3103     this.name = name;
3104   }
3105
3106   Name.prototype = {};
3107
3108   var nameCache = {};
3109
3110   Name.get = function Name_get(name) {
3111     var nameValue = nameCache[name];
3112     return (nameValue ? nameValue : (nameCache[name] = new Name(name)));
3113   };
3114
3115   return Name;
3116 })();
3117
3118 var Cmd = (function CmdClosure() {
3119   function Cmd(cmd) {
3120     this.cmd = cmd;
3121   }
3122
3123   Cmd.prototype = {};
3124
3125   var cmdCache = {};
3126
3127   Cmd.get = function Cmd_get(cmd) {
3128     var cmdValue = cmdCache[cmd];
3129     return (cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd)));
3130   };
3131
3132   return Cmd;
3133 })();
3134
3135 var Dict = (function DictClosure() {
3136   var nonSerializable = function nonSerializableClosure() {
3137     return nonSerializable; // creating closure on some variable
3138   };
3139
3140   var GETALL_DICTIONARY_TYPES_WHITELIST = {
3141     'Background': true,
3142     'ExtGState': true,
3143     'Halftone': true,
3144     'Layout': true,
3145     'Mask': true,
3146     'Pagination': true,
3147     'Printing': true
3148   };
3149
3150   function isRecursionAllowedFor(dict) {
3151     if (!isName(dict.Type)) {
3152       return true;
3153     }
3154     var dictType = dict.Type.name;
3155     return GETALL_DICTIONARY_TYPES_WHITELIST[dictType] === true;
3156   }
3157
3158   // xref is optional
3159   function Dict(xref) {
3160     // Map should only be used internally, use functions below to access.
3161     this.map = Object.create(null);
3162     this.xref = xref;
3163     this.objId = null;
3164     this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict
3165   }
3166
3167   Dict.prototype = {
3168     assignXref: function Dict_assignXref(newXref) {
3169       this.xref = newXref;
3170     },
3171
3172     // automatically dereferences Ref objects
3173     get: function Dict_get(key1, key2, key3) {
3174       var value;
3175       var xref = this.xref;
3176       if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map ||
3177           typeof key2 === 'undefined') {
3178         return xref ? xref.fetchIfRef(value) : value;
3179       }
3180       if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map ||
3181           typeof key3 === 'undefined') {
3182         return xref ? xref.fetchIfRef(value) : value;
3183       }
3184       value = this.map[key3] || null;
3185       return xref ? xref.fetchIfRef(value) : value;
3186     },
3187
3188     // Same as get(), but returns a promise and uses fetchIfRefAsync().
3189     getAsync: function Dict_getAsync(key1, key2, key3) {
3190       var value;
3191       var xref = this.xref;
3192       if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map ||
3193           typeof key2 === 'undefined') {
3194         if (xref) {
3195           return xref.fetchIfRefAsync(value);
3196         }
3197         return Promise.resolve(value);
3198       }
3199       if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map ||
3200           typeof key3 === 'undefined') {
3201         if (xref) {
3202           return xref.fetchIfRefAsync(value);
3203         }
3204         return Promise.resolve(value);
3205       }
3206       value = this.map[key3] || null;
3207       if (xref) {
3208         return xref.fetchIfRefAsync(value);
3209       }
3210       return Promise.resolve(value);
3211     },
3212
3213     // no dereferencing
3214     getRaw: function Dict_getRaw(key) {
3215       return this.map[key];
3216     },
3217
3218     // creates new map and dereferences all Refs
3219     getAll: function Dict_getAll() {
3220       var all = Object.create(null);
3221       var queue = null;
3222       var key, obj;
3223       for (key in this.map) {
3224         obj = this.get(key);
3225         if (obj instanceof Dict) {
3226           if (isRecursionAllowedFor(obj)) {
3227             (queue || (queue = [])).push({target: all, key: key, obj: obj});
3228           } else {
3229             all[key] = this.getRaw(key);
3230           }
3231         } else {
3232           all[key] = obj;
3233         }
3234       }
3235       if (!queue) {
3236         return all;
3237       }
3238
3239       // trying to take cyclic references into the account
3240       var processed = Object.create(null);
3241       while (queue.length > 0) {
3242         var item = queue.shift();
3243         var itemObj = item.obj;
3244         var objId = itemObj.objId;
3245         if (objId && objId in processed) {
3246           item.target[item.key] = processed[objId];
3247           continue;
3248         }
3249         var dereferenced = Object.create(null);
3250         for (key in itemObj.map) {
3251           obj = itemObj.get(key);
3252           if (obj instanceof Dict) {
3253             if (isRecursionAllowedFor(obj)) {
3254               queue.push({target: dereferenced, key: key, obj: obj});
3255             } else {
3256               dereferenced[key] = itemObj.getRaw(key);
3257             }
3258           } else {
3259             dereferenced[key] = obj;
3260           }
3261         }
3262         if (objId) {
3263           processed[objId] = dereferenced;
3264         }
3265         item.target[item.key] = dereferenced;
3266       }
3267       return all;
3268     },
3269
3270     getKeys: function Dict_getKeys() {
3271       return Object.keys(this.map);
3272     },
3273
3274     set: function Dict_set(key, value) {
3275       this.map[key] = value;
3276     },
3277
3278     has: function Dict_has(key) {
3279       return key in this.map;
3280     },
3281
3282     forEach: function Dict_forEach(callback) {
3283       for (var key in this.map) {
3284         callback(key, this.get(key));
3285       }
3286     }
3287   };
3288
3289   Dict.empty = new Dict(null);
3290
3291   return Dict;
3292 })();
3293
3294 var Ref = (function RefClosure() {
3295   function Ref(num, gen) {
3296     this.num = num;
3297     this.gen = gen;
3298   }
3299
3300   Ref.prototype = {
3301     toString: function Ref_toString() {
3302       // This function is hot, so we make the string as compact as possible.
3303       // |this.gen| is almost always zero, so we treat that case specially.
3304       var str = this.num + 'R';
3305       if (this.gen !== 0) {
3306         str += this.gen;
3307       }
3308       return str;
3309     }
3310   };
3311
3312   return Ref;
3313 })();
3314
3315 // The reference is identified by number and generation.
3316 // This structure stores only one instance of the reference.
3317 var RefSet = (function RefSetClosure() {
3318   function RefSet() {
3319     this.dict = {};
3320   }
3321
3322   RefSet.prototype = {
3323     has: function RefSet_has(ref) {
3324       return ref.toString() in this.dict;
3325     },
3326
3327     put: function RefSet_put(ref) {
3328       this.dict[ref.toString()] = true;
3329     },
3330
3331     remove: function RefSet_remove(ref) {
3332       delete this.dict[ref.toString()];
3333     }
3334   };
3335
3336   return RefSet;
3337 })();
3338
3339 var RefSetCache = (function RefSetCacheClosure() {
3340   function RefSetCache() {
3341     this.dict = Object.create(null);
3342   }
3343
3344   RefSetCache.prototype = {
3345     get: function RefSetCache_get(ref) {
3346       return this.dict[ref.toString()];
3347     },
3348
3349     has: function RefSetCache_has(ref) {
3350       return ref.toString() in this.dict;
3351     },
3352
3353     put: function RefSetCache_put(ref, obj) {
3354       this.dict[ref.toString()] = obj;
3355     },
3356
3357     putAlias: function RefSetCache_putAlias(ref, aliasRef) {
3358       this.dict[ref.toString()] = this.get(aliasRef);
3359     },
3360
3361     forEach: function RefSetCache_forEach(fn, thisArg) {
3362       for (var i in this.dict) {
3363         fn.call(thisArg, this.dict[i]);
3364       }
3365     },
3366
3367     clear: function RefSetCache_clear() {
3368       this.dict = Object.create(null);
3369     }
3370   };
3371
3372   return RefSetCache;
3373 })();
3374
3375 var Catalog = (function CatalogClosure() {
3376   function Catalog(pdfManager, xref) {
3377     this.pdfManager = pdfManager;
3378     this.xref = xref;
3379     this.catDict = xref.getCatalogObj();
3380     this.fontCache = new RefSetCache();
3381     assert(isDict(this.catDict),
3382       'catalog object is not a dictionary');
3383
3384     this.pagePromises = [];
3385   }
3386
3387   Catalog.prototype = {
3388     get metadata() {
3389       var streamRef = this.catDict.getRaw('Metadata');
3390       if (!isRef(streamRef)) {
3391         return shadow(this, 'metadata', null);
3392       }
3393
3394       var encryptMetadata = (!this.xref.encrypt ? false :
3395                              this.xref.encrypt.encryptMetadata);
3396
3397       var stream = this.xref.fetch(streamRef, !encryptMetadata);
3398       var metadata;
3399       if (stream && isDict(stream.dict)) {
3400         var type = stream.dict.get('Type');
3401         var subtype = stream.dict.get('Subtype');
3402
3403         if (isName(type) && isName(subtype) &&
3404             type.name === 'Metadata' && subtype.name === 'XML') {
3405           // XXX: This should examine the charset the XML document defines,
3406           // however since there are currently no real means to decode
3407           // arbitrary charsets, let's just hope that the author of the PDF
3408           // was reasonable enough to stick with the XML default charset,
3409           // which is UTF-8.
3410           try {
3411             metadata = stringToUTF8String(bytesToString(stream.getBytes()));
3412           } catch (e) {
3413             info('Skipping invalid metadata.');
3414           }
3415         }
3416       }
3417
3418       return shadow(this, 'metadata', metadata);
3419     },
3420     get toplevelPagesDict() {
3421       var pagesObj = this.catDict.get('Pages');
3422       assert(isDict(pagesObj), 'invalid top-level pages dictionary');
3423       // shadow the prototype getter
3424       return shadow(this, 'toplevelPagesDict', pagesObj);
3425     },
3426     get documentOutline() {
3427       var obj = null;
3428       try {
3429         obj = this.readDocumentOutline();
3430       } catch (ex) {
3431         if (ex instanceof MissingDataException) {
3432           throw ex;
3433         }
3434         warn('Unable to read document outline');
3435       }
3436       return shadow(this, 'documentOutline', obj);
3437     },
3438     readDocumentOutline: function Catalog_readDocumentOutline() {
3439       var xref = this.xref;
3440       var obj = this.catDict.get('Outlines');
3441       var root = { items: [] };
3442       if (isDict(obj)) {
3443         obj = obj.getRaw('First');
3444         var processed = new RefSet();
3445         if (isRef(obj)) {
3446           var queue = [{obj: obj, parent: root}];
3447           // to avoid recursion keeping track of the items
3448           // in the processed dictionary
3449           processed.put(obj);
3450           while (queue.length > 0) {
3451             var i = queue.shift();
3452             var outlineDict = xref.fetchIfRef(i.obj);
3453             if (outlineDict === null) {
3454               continue;
3455             }
3456             if (!outlineDict.has('Title')) {
3457               error('Invalid outline item');
3458             }
3459             var dest = outlineDict.get('A');
3460             if (dest) {
3461               dest = dest.get('D');
3462             } else if (outlineDict.has('Dest')) {
3463               dest = outlineDict.getRaw('Dest');
3464               if (isName(dest)) {
3465                 dest = dest.name;
3466               }
3467             }
3468             var title = outlineDict.get('Title');
3469             var outlineItem = {
3470               dest: dest,
3471               title: stringToPDFString(title),
3472               color: outlineDict.get('C') || [0, 0, 0],
3473               count: outlineDict.get('Count'),
3474               bold: !!(outlineDict.get('F') & 2),
3475               italic: !!(outlineDict.get('F') & 1),
3476               items: []
3477             };
3478             i.parent.items.push(outlineItem);
3479             obj = outlineDict.getRaw('First');
3480             if (isRef(obj) && !processed.has(obj)) {
3481               queue.push({obj: obj, parent: outlineItem});
3482               processed.put(obj);
3483             }
3484             obj = outlineDict.getRaw('Next');
3485             if (isRef(obj) && !processed.has(obj)) {
3486               queue.push({obj: obj, parent: i.parent});
3487               processed.put(obj);
3488             }
3489           }
3490         }
3491       }
3492       return (root.items.length > 0 ? root.items : null);
3493     },
3494     get numPages() {
3495       var obj = this.toplevelPagesDict.get('Count');
3496       assert(
3497         isInt(obj),
3498         'page count in top level pages object is not an integer'
3499       );
3500       // shadow the prototype getter
3501       return shadow(this, 'num', obj);
3502     },
3503     get destinations() {
3504       function fetchDestination(dest) {
3505         return isDict(dest) ? dest.get('D') : dest;
3506       }
3507
3508       var xref = this.xref;
3509       var dests = {}, nameTreeRef, nameDictionaryRef;
3510       var obj = this.catDict.get('Names');
3511       if (obj && obj.has('Dests')) {
3512         nameTreeRef = obj.getRaw('Dests');
3513       } else if (this.catDict.has('Dests')) {
3514         nameDictionaryRef = this.catDict.get('Dests');
3515       }
3516
3517       if (nameDictionaryRef) {
3518         // reading simple destination dictionary
3519         obj = nameDictionaryRef;
3520         obj.forEach(function catalogForEach(key, value) {
3521           if (!value) {
3522             return;
3523           }
3524           dests[key] = fetchDestination(value);
3525         });
3526       }
3527       if (nameTreeRef) {
3528         var nameTree = new NameTree(nameTreeRef, xref);
3529         var names = nameTree.getAll();
3530         for (var name in names) {
3531           if (!names.hasOwnProperty(name)) {
3532             continue;
3533           }
3534           dests[name] = fetchDestination(names[name]);
3535         }
3536       }
3537       return shadow(this, 'destinations', dests);
3538     },
3539     getDestination: function Catalog_getDestination(destinationId) {
3540       function fetchDestination(dest) {
3541         return isDict(dest) ? dest.get('D') : dest;
3542       }
3543
3544       var xref = this.xref;
3545       var dest, nameTreeRef, nameDictionaryRef;
3546       var obj = this.catDict.get('Names');
3547       if (obj && obj.has('Dests')) {
3548         nameTreeRef = obj.getRaw('Dests');
3549       } else if (this.catDict.has('Dests')) {
3550         nameDictionaryRef = this.catDict.get('Dests');
3551       }
3552
3553       if (nameDictionaryRef) {
3554         // reading simple destination dictionary
3555         obj = nameDictionaryRef;
3556         obj.forEach(function catalogForEach(key, value) {
3557           if (!value) {
3558             return;
3559           }
3560           if (key === destinationId) {
3561             dest = fetchDestination(value);
3562           }
3563         });
3564       }
3565       if (nameTreeRef) {
3566         var nameTree = new NameTree(nameTreeRef, xref);
3567         dest = fetchDestination(nameTree.get(destinationId));
3568       }
3569       return dest;
3570     },
3571     get attachments() {
3572       var xref = this.xref;
3573       var attachments = null, nameTreeRef;
3574       var obj = this.catDict.get('Names');
3575       if (obj) {
3576         nameTreeRef = obj.getRaw('EmbeddedFiles');
3577       }
3578
3579       if (nameTreeRef) {
3580         var nameTree = new NameTree(nameTreeRef, xref);
3581         var names = nameTree.getAll();
3582         for (var name in names) {
3583           if (!names.hasOwnProperty(name)) {
3584             continue;
3585           }
3586           var fs = new FileSpec(names[name], xref);
3587           if (!attachments) {
3588             attachments = {};
3589           }
3590           attachments[stringToPDFString(name)] = fs.serializable;
3591         }
3592       }
3593       return shadow(this, 'attachments', attachments);
3594     },
3595     get javaScript() {
3596       var xref = this.xref;
3597       var obj = this.catDict.get('Names');
3598
3599       var javaScript = [];
3600       if (obj && obj.has('JavaScript')) {
3601         var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
3602         var names = nameTree.getAll();
3603         for (var name in names) {
3604           if (!names.hasOwnProperty(name)) {
3605             continue;
3606           }
3607           // We don't really use the JavaScript right now. This code is
3608           // defensive so we don't cause errors on document load.
3609           var jsDict = names[name];
3610           if (!isDict(jsDict)) {
3611             continue;
3612           }
3613           var type = jsDict.get('S');
3614           if (!isName(type) || type.name !== 'JavaScript') {
3615             continue;
3616           }
3617           var js = jsDict.get('JS');
3618           if (!isString(js) && !isStream(js)) {
3619             continue;
3620           }
3621           if (isStream(js)) {
3622             js = bytesToString(js.getBytes());
3623           }
3624           javaScript.push(stringToPDFString(js));
3625         }
3626       }
3627
3628       // Append OpenAction actions to javaScript array
3629       var openactionDict = this.catDict.get('OpenAction');
3630       if (isDict(openactionDict)) {
3631         var objType = openactionDict.get('Type');
3632         var actionType = openactionDict.get('S');
3633         var action = openactionDict.get('N');
3634         var isPrintAction = (isName(objType) && objType.name === 'Action' &&
3635                             isName(actionType) && actionType.name === 'Named' &&
3636                             isName(action) && action.name === 'Print');
3637
3638         if (isPrintAction) {
3639           javaScript.push('print(true);');
3640         }
3641       }
3642
3643       return shadow(this, 'javaScript', javaScript);
3644     },
3645
3646     cleanup: function Catalog_cleanup() {
3647       var promises = [];
3648       this.fontCache.forEach(function (promise) {
3649         promises.push(promise);
3650       });
3651       return Promise.all(promises).then(function (translatedFonts) {
3652         for (var i = 0, ii = translatedFonts.length; i < ii; i++) {
3653           var font = translatedFonts[i].dict;
3654           delete font.translated;
3655         }
3656         this.fontCache.clear();
3657       }.bind(this));
3658     },
3659
3660     getPage: function Catalog_getPage(pageIndex) {
3661       if (!(pageIndex in this.pagePromises)) {
3662         this.pagePromises[pageIndex] = this.getPageDict(pageIndex).then(
3663           function (a) {
3664             var dict = a[0];
3665             var ref = a[1];
3666             return new Page(this.pdfManager, this.xref, pageIndex, dict, ref,
3667                             this.fontCache);
3668           }.bind(this)
3669         );
3670       }
3671       return this.pagePromises[pageIndex];
3672     },
3673
3674     getPageDict: function Catalog_getPageDict(pageIndex) {
3675       var capability = createPromiseCapability();
3676       var nodesToVisit = [this.catDict.getRaw('Pages')];
3677       var currentPageIndex = 0;
3678       var xref = this.xref;
3679       var checkAllKids = false;
3680
3681       function next() {
3682         while (nodesToVisit.length) {
3683           var currentNode = nodesToVisit.pop();
3684
3685           if (isRef(currentNode)) {
3686             xref.fetchAsync(currentNode).then(function (obj) {
3687               if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) {
3688                 if (pageIndex === currentPageIndex) {
3689                   capability.resolve([obj, currentNode]);
3690                 } else {
3691                   currentPageIndex++;
3692                   next();
3693                 }
3694                 return;
3695               }
3696               nodesToVisit.push(obj);
3697               next();
3698             }, capability.reject);
3699             return;
3700           }
3701
3702           // Must be a child page dictionary.
3703           assert(
3704             isDict(currentNode),
3705             'page dictionary kid reference points to wrong type of object'
3706           );
3707           var count = currentNode.get('Count');
3708           // If the current node doesn't have any children, avoid getting stuck
3709           // in an empty node further down in the tree (see issue5644.pdf).
3710           if (count === 0) {
3711             checkAllKids = true;
3712           }
3713           // Skip nodes where the page can't be.
3714           if (currentPageIndex + count <= pageIndex) {
3715             currentPageIndex += count;
3716             continue;
3717           }
3718
3719           var kids = currentNode.get('Kids');
3720           assert(isArray(kids), 'page dictionary kids object is not an array');
3721           if (!checkAllKids && count === kids.length) {
3722             // Nodes that don't have the page have been skipped and this is the
3723             // bottom of the tree which means the page requested must be a
3724             // descendant of this pages node. Ideally we would just resolve the
3725             // promise with the page ref here, but there is the case where more
3726             // pages nodes could link to single a page (see issue 3666 pdf). To
3727             // handle this push it back on the queue so if it is a pages node it
3728             // will be descended into.
3729             nodesToVisit = [kids[pageIndex - currentPageIndex]];
3730             currentPageIndex = pageIndex;
3731             continue;
3732           } else {
3733             for (var last = kids.length - 1; last >= 0; last--) {
3734               nodesToVisit.push(kids[last]);
3735             }
3736           }
3737         }
3738         capability.reject('Page index ' + pageIndex + ' not found.');
3739       }
3740       next();
3741       return capability.promise;
3742     },
3743
3744     getPageIndex: function Catalog_getPageIndex(ref) {
3745       // The page tree nodes have the count of all the leaves below them. To get
3746       // how many pages are before we just have to walk up the tree and keep
3747       // adding the count of siblings to the left of the node.
3748       var xref = this.xref;
3749       function pagesBeforeRef(kidRef) {
3750         var total = 0;
3751         var parentRef;
3752         return xref.fetchAsync(kidRef).then(function (node) {
3753           if (!node) {
3754             return null;
3755           }
3756           parentRef = node.getRaw('Parent');
3757           return node.getAsync('Parent');
3758         }).then(function (parent) {
3759           if (!parent) {
3760             return null;
3761           }
3762           return parent.getAsync('Kids');
3763         }).then(function (kids) {
3764           if (!kids) {
3765             return null;
3766           }
3767           var kidPromises = [];
3768           var found = false;
3769           for (var i = 0; i < kids.length; i++) {
3770             var kid = kids[i];
3771             assert(isRef(kid), 'kids must be a ref');
3772             if (kid.num === kidRef.num) {
3773               found = true;
3774               break;
3775             }
3776             kidPromises.push(xref.fetchAsync(kid).then(function (kid) {
3777               if (kid.has('Count')) {
3778                 var count = kid.get('Count');
3779                 total += count;
3780               } else { // page leaf node
3781                 total++;
3782               }
3783             }));
3784           }
3785           if (!found) {
3786             error('kid ref not found in parents kids');
3787           }
3788           return Promise.all(kidPromises).then(function () {
3789             return [total, parentRef];
3790           });
3791         });
3792       }
3793
3794       var total = 0;
3795       function next(ref) {
3796         return pagesBeforeRef(ref).then(function (args) {
3797           if (!args) {
3798             return total;
3799           }
3800           var count = args[0];
3801           var parentRef = args[1];
3802           total += count;
3803           return next(parentRef);
3804         });
3805       }
3806
3807       return next(ref);
3808     }
3809   };
3810
3811   return Catalog;
3812 })();
3813
3814 var XRef = (function XRefClosure() {
3815   function XRef(stream, password) {
3816     this.stream = stream;
3817     this.entries = [];
3818     this.xrefstms = {};
3819     // prepare the XRef cache
3820     this.cache = [];
3821     this.password = password;
3822     this.stats = {
3823       streamTypes: [],
3824       fontTypes: []
3825     };
3826   }
3827
3828   XRef.prototype = {
3829     setStartXRef: function XRef_setStartXRef(startXRef) {
3830       // Store the starting positions of xref tables as we process them
3831       // so we can recover from missing data errors
3832       this.startXRefQueue = [startXRef];
3833     },
3834
3835     parse: function XRef_parse(recoveryMode) {
3836       var trailerDict;
3837       if (!recoveryMode) {
3838         trailerDict = this.readXRef();
3839       } else {
3840         warn('Indexing all PDF objects');
3841         trailerDict = this.indexObjects();
3842       }
3843       trailerDict.assignXref(this);
3844       this.trailer = trailerDict;
3845       var encrypt = trailerDict.get('Encrypt');
3846       if (encrypt) {
3847         var ids = trailerDict.get('ID');
3848         var fileId = (ids && ids.length) ? ids[0] : '';
3849         this.encrypt = new CipherTransformFactory(encrypt, fileId,
3850                                                   this.password);
3851       }
3852
3853       // get the root dictionary (catalog) object
3854       if (!(this.root = trailerDict.get('Root'))) {
3855         error('Invalid root reference');
3856       }
3857     },
3858
3859     processXRefTable: function XRef_processXRefTable(parser) {
3860       if (!('tableState' in this)) {
3861         // Stores state of the table as we process it so we can resume
3862         // from middle of table in case of missing data error
3863         this.tableState = {
3864           entryNum: 0,
3865           streamPos: parser.lexer.stream.pos,
3866           parserBuf1: parser.buf1,
3867           parserBuf2: parser.buf2
3868         };
3869       }
3870
3871       var obj = this.readXRefTable(parser);
3872
3873       // Sanity check
3874       if (!isCmd(obj, 'trailer')) {
3875         error('Invalid XRef table: could not find trailer dictionary');
3876       }
3877       // Read trailer dictionary, e.g.
3878       // trailer
3879       //    << /Size 22
3880       //      /Root 20R
3881       //      /Info 10R
3882       //      /ID [ <81b14aafa313db63dbd6f981e49f94f4> ]
3883       //    >>
3884       // The parser goes through the entire stream << ... >> and provides
3885       // a getter interface for the key-value table
3886       var dict = parser.getObj();
3887
3888       // The pdflib PDF generator can generate a nested trailer dictionary
3889       if (!isDict(dict) && dict.dict) {
3890         dict = dict.dict;
3891       }
3892       if (!isDict(dict)) {
3893         error('Invalid XRef table: could not parse trailer dictionary');
3894       }
3895       delete this.tableState;
3896
3897       return dict;
3898     },
3899
3900     readXRefTable: function XRef_readXRefTable(parser) {
3901       // Example of cross-reference table:
3902       // xref
3903       // 0 1                    <-- subsection header (first obj #, obj count)
3904       // 0000000000 65535 f     <-- actual object (offset, generation #, f/n)
3905       // 23 2                   <-- subsection header ... and so on ...
3906       // 0000025518 00002 n
3907       // 0000025635 00000 n
3908       // trailer
3909       // ...
3910
3911       var stream = parser.lexer.stream;
3912       var tableState = this.tableState;
3913       stream.pos = tableState.streamPos;
3914       parser.buf1 = tableState.parserBuf1;
3915       parser.buf2 = tableState.parserBuf2;
3916
3917       // Outer loop is over subsection headers
3918       var obj;
3919
3920       while (true) {
3921         if (!('firstEntryNum' in tableState) || !('entryCount' in tableState)) {
3922           if (isCmd(obj = parser.getObj(), 'trailer')) {
3923             break;
3924           }
3925           tableState.firstEntryNum = obj;
3926           tableState.entryCount = parser.getObj();
3927         }
3928
3929         var first = tableState.firstEntryNum;
3930         var count = tableState.entryCount;
3931         if (!isInt(first) || !isInt(count)) {
3932           error('Invalid XRef table: wrong types in subsection header');
3933         }
3934         // Inner loop is over objects themselves
3935         for (var i = tableState.entryNum; i < count; i++) {
3936           tableState.streamPos = stream.pos;
3937           tableState.entryNum = i;
3938           tableState.parserBuf1 = parser.buf1;
3939           tableState.parserBuf2 = parser.buf2;
3940
3941           var entry = {};
3942           entry.offset = parser.getObj();
3943           entry.gen = parser.getObj();
3944           var type = parser.getObj();
3945
3946           if (isCmd(type, 'f')) {
3947             entry.free = true;
3948           } else if (isCmd(type, 'n')) {
3949             entry.uncompressed = true;
3950           }
3951
3952           // Validate entry obj
3953           if (!isInt(entry.offset) || !isInt(entry.gen) ||
3954               !(entry.free || entry.uncompressed)) {
3955             error('Invalid entry in XRef subsection: ' + first + ', ' + count);
3956           }
3957
3958           if (!this.entries[i + first]) {
3959             this.entries[i + first] = entry;
3960           }
3961         }
3962
3963         tableState.entryNum = 0;
3964         tableState.streamPos = stream.pos;
3965         tableState.parserBuf1 = parser.buf1;
3966         tableState.parserBuf2 = parser.buf2;
3967         delete tableState.firstEntryNum;
3968         delete tableState.entryCount;
3969       }
3970
3971       // Per issue 3248: hp scanners generate bad XRef
3972       if (first === 1 && this.entries[1] && this.entries[1].free) {
3973         // shifting the entries
3974         this.entries.shift();
3975       }
3976
3977       // Sanity check: as per spec, first object must be free
3978       if (this.entries[0] && !this.entries[0].free) {
3979         error('Invalid XRef table: unexpected first object');
3980       }
3981       return obj;
3982     },
3983
3984     processXRefStream: function XRef_processXRefStream(stream) {
3985       if (!('streamState' in this)) {
3986         // Stores state of the stream as we process it so we can resume
3987         // from middle of stream in case of missing data error
3988         var streamParameters = stream.dict;
3989         var byteWidths = streamParameters.get('W');
3990         var range = streamParameters.get('Index');
3991         if (!range) {
3992           range = [0, streamParameters.get('Size')];
3993         }
3994
3995         this.streamState = {
3996           entryRanges: range,
3997           byteWidths: byteWidths,
3998           entryNum: 0,
3999           streamPos: stream.pos
4000         };
4001       }
4002       this.readXRefStream(stream);
4003       delete this.streamState;
4004
4005       return stream.dict;
4006     },
4007
4008     readXRefStream: function XRef_readXRefStream(stream) {
4009       var i, j;
4010       var streamState = this.streamState;
4011       stream.pos = streamState.streamPos;
4012
4013       var byteWidths = streamState.byteWidths;
4014       var typeFieldWidth = byteWidths[0];
4015       var offsetFieldWidth = byteWidths[1];
4016       var generationFieldWidth = byteWidths[2];
4017
4018       var entryRanges = streamState.entryRanges;
4019       while (entryRanges.length > 0) {
4020         var first = entryRanges[0];
4021         var n = entryRanges[1];
4022
4023         if (!isInt(first) || !isInt(n)) {
4024           error('Invalid XRef range fields: ' + first + ', ' + n);
4025         }
4026         if (!isInt(typeFieldWidth) || !isInt(offsetFieldWidth) ||
4027             !isInt(generationFieldWidth)) {
4028           error('Invalid XRef entry fields length: ' + first + ', ' + n);
4029         }
4030         for (i = streamState.entryNum; i < n; ++i) {
4031           streamState.entryNum = i;
4032           streamState.streamPos = stream.pos;
4033
4034           var type = 0, offset = 0, generation = 0;
4035           for (j = 0; j < typeFieldWidth; ++j) {
4036             type = (type << 8) | stream.getByte();
4037           }
4038           // if type field is absent, its default value is 1
4039           if (typeFieldWidth === 0) {
4040             type = 1;
4041           }
4042           for (j = 0; j < offsetFieldWidth; ++j) {
4043             offset = (offset << 8) | stream.getByte();
4044           }
4045           for (j = 0; j < generationFieldWidth; ++j) {
4046             generation = (generation << 8) | stream.getByte();
4047           }
4048           var entry = {};
4049           entry.offset = offset;
4050           entry.gen = generation;
4051           switch (type) {
4052             case 0:
4053               entry.free = true;
4054               break;
4055             case 1:
4056               entry.uncompressed = true;
4057               break;
4058             case 2:
4059               break;
4060             default:
4061               error('Invalid XRef entry type: ' + type);
4062           }
4063           if (!this.entries[first + i]) {
4064             this.entries[first + i] = entry;
4065           }
4066         }
4067
4068         streamState.entryNum = 0;
4069         streamState.streamPos = stream.pos;
4070         entryRanges.splice(0, 2);
4071       }
4072     },
4073
4074     indexObjects: function XRef_indexObjects() {
4075       // Simple scan through the PDF content to find objects,
4076       // trailers and XRef streams.
4077       function readToken(data, offset) {
4078         var token = '', ch = data[offset];
4079         while (ch !== 13 && ch !== 10) {
4080           if (++offset >= data.length) {
4081             break;
4082           }
4083           token += String.fromCharCode(ch);
4084           ch = data[offset];
4085         }
4086         return token;
4087       }
4088       function skipUntil(data, offset, what) {
4089         var length = what.length, dataLength = data.length;
4090         var skipped = 0;
4091         // finding byte sequence
4092         while (offset < dataLength) {
4093           var i = 0;
4094           while (i < length && data[offset + i] === what[i]) {
4095             ++i;
4096           }
4097           if (i >= length) {
4098             break; // sequence found
4099           }
4100           offset++;
4101           skipped++;
4102         }
4103         return skipped;
4104       }
4105       var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
4106       var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114,
4107                                           101, 102]);
4108       var endobjBytes = new Uint8Array([101, 110, 100, 111, 98, 106]);
4109       var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
4110
4111       var stream = this.stream;
4112       stream.pos = 0;
4113       var buffer = stream.getBytes();
4114       var position = stream.start, length = buffer.length;
4115       var trailers = [], xrefStms = [];
4116       while (position < length) {
4117         var ch = buffer[position];
4118         if (ch === 32 || ch === 9 || ch === 13 || ch === 10) {
4119           ++position;
4120           continue;
4121         }
4122         if (ch === 37) { // %-comment
4123           do {
4124             ++position;
4125             if (position >= length) {
4126               break;
4127             }
4128             ch = buffer[position];
4129           } while (ch !== 13 && ch !== 10);
4130           continue;
4131         }
4132         var token = readToken(buffer, position);
4133         var m;
4134         if (token === 'xref') {
4135           position += skipUntil(buffer, position, trailerBytes);
4136           trailers.push(position);
4137           position += skipUntil(buffer, position, startxrefBytes);
4138         } else if ((m = /^(\d+)\s+(\d+)\s+obj\b/.exec(token))) {
4139           if (typeof this.entries[m[1]] === 'undefined') {
4140             this.entries[m[1]] = {
4141               offset: position,
4142               gen: m[2] | 0,
4143               uncompressed: true
4144             };
4145           }
4146           var contentLength = skipUntil(buffer, position, endobjBytes) + 7;
4147           var content = buffer.subarray(position, position + contentLength);
4148
4149           // checking XRef stream suspect
4150           // (it shall have '/XRef' and next char is not a letter)
4151           var xrefTagOffset = skipUntil(content, 0, xrefBytes);
4152           if (xrefTagOffset < contentLength &&
4153               content[xrefTagOffset + 5] < 64) {
4154             xrefStms.push(position);
4155             this.xrefstms[position] = 1; // don't read it recursively
4156           }
4157
4158           position += contentLength;
4159         } else {
4160           position += token.length + 1;
4161         }
4162       }
4163       // reading XRef streams
4164       var i, ii;
4165       for (i = 0, ii = xrefStms.length; i < ii; ++i) {
4166         this.startXRefQueue.push(xrefStms[i]);
4167         this.readXRef(/* recoveryMode */ true);
4168       }
4169       // finding main trailer
4170       var dict;
4171       for (i = 0, ii = trailers.length; i < ii; ++i) {
4172         stream.pos = trailers[i];
4173         var parser = new Parser(new Lexer(stream), true, this);
4174         var obj = parser.getObj();
4175         if (!isCmd(obj, 'trailer')) {
4176           continue;
4177         }
4178         // read the trailer dictionary
4179         if (!isDict(dict = parser.getObj())) {
4180           continue;
4181         }
4182         // taking the first one with 'ID'
4183         if (dict.has('ID')) {
4184           return dict;
4185         }
4186       }
4187       // no tailer with 'ID', taking last one (if exists)
4188       if (dict) {
4189         return dict;
4190       }
4191       // nothing helps
4192       // calling error() would reject worker with an UnknownErrorException.
4193       throw new InvalidPDFException('Invalid PDF structure');
4194     },
4195
4196     readXRef: function XRef_readXRef(recoveryMode) {
4197       var stream = this.stream;
4198
4199       try {
4200         while (this.startXRefQueue.length) {
4201           var startXRef = this.startXRefQueue[0];
4202
4203           stream.pos = startXRef + stream.start;
4204
4205           var parser = new Parser(new Lexer(stream), true, this);
4206           var obj = parser.getObj();
4207           var dict;
4208
4209           // Get dictionary
4210           if (isCmd(obj, 'xref')) {
4211             // Parse end-of-file XRef
4212             dict = this.processXRefTable(parser);
4213             if (!this.topDict) {
4214               this.topDict = dict;
4215             }
4216
4217             // Recursively get other XRefs 'XRefStm', if any
4218             obj = dict.get('XRefStm');
4219             if (isInt(obj)) {
4220               var pos = obj;
4221               // ignore previously loaded xref streams
4222               // (possible infinite recursion)
4223               if (!(pos in this.xrefstms)) {
4224                 this.xrefstms[pos] = 1;
4225                 this.startXRefQueue.push(pos);
4226               }
4227             }
4228           } else if (isInt(obj)) {
4229             // Parse in-stream XRef
4230             if (!isInt(parser.getObj()) ||
4231                 !isCmd(parser.getObj(), 'obj') ||
4232                 !isStream(obj = parser.getObj())) {
4233               error('Invalid XRef stream');
4234             }
4235             dict = this.processXRefStream(obj);
4236             if (!this.topDict) {
4237               this.topDict = dict;
4238             }
4239             if (!dict) {
4240               error('Failed to read XRef stream');
4241             }
4242           } else {
4243             error('Invalid XRef stream header');
4244           }
4245
4246           // Recursively get previous dictionary, if any
4247           obj = dict.get('Prev');
4248           if (isInt(obj)) {
4249             this.startXRefQueue.push(obj);
4250           } else if (isRef(obj)) {
4251             // The spec says Prev must not be a reference, i.e. "/Prev NNN"
4252             // This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R"
4253             this.startXRefQueue.push(obj.num);
4254           }
4255
4256           this.startXRefQueue.shift();
4257         }
4258
4259         return this.topDict;
4260       } catch (e) {
4261         if (e instanceof MissingDataException) {
4262           throw e;
4263         }
4264         info('(while reading XRef): ' + e);
4265       }
4266
4267       if (recoveryMode) {
4268         return;
4269       }
4270       throw new XRefParseException();
4271     },
4272
4273     getEntry: function XRef_getEntry(i) {
4274       var xrefEntry = this.entries[i];
4275       if (xrefEntry && !xrefEntry.free && xrefEntry.offset) {
4276         return xrefEntry;
4277       }
4278       return null;
4279     },
4280
4281     fetchIfRef: function XRef_fetchIfRef(obj) {
4282       if (!isRef(obj)) {
4283         return obj;
4284       }
4285       return this.fetch(obj);
4286     },
4287
4288     fetch: function XRef_fetch(ref, suppressEncryption) {
4289       assert(isRef(ref), 'ref object is not a reference');
4290       var num = ref.num;
4291       if (num in this.cache) {
4292         var cacheEntry = this.cache[num];
4293         return cacheEntry;
4294       }
4295
4296       var xrefEntry = this.getEntry(num);
4297
4298       // the referenced entry can be free
4299       if (xrefEntry === null) {
4300         return (this.cache[num] = null);
4301       }
4302
4303       if (xrefEntry.uncompressed) {
4304         xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
4305       } else {
4306         xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption);
4307       }
4308       if (isDict(xrefEntry)){
4309         xrefEntry.objId = ref.toString();
4310       } else if (isStream(xrefEntry)) {
4311         xrefEntry.dict.objId = ref.toString();
4312       }
4313       return xrefEntry;
4314     },
4315
4316     fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry,
4317                                                        suppressEncryption) {
4318       var gen = ref.gen;
4319       var num = ref.num;
4320       if (xrefEntry.gen !== gen) {
4321         error('inconsistent generation in XRef');
4322       }
4323       var stream = this.stream.makeSubStream(xrefEntry.offset +
4324                                              this.stream.start);
4325       var parser = new Parser(new Lexer(stream), true, this);
4326       var obj1 = parser.getObj();
4327       var obj2 = parser.getObj();
4328       var obj3 = parser.getObj();
4329       if (!isInt(obj1) || parseInt(obj1, 10) !== num ||
4330           !isInt(obj2) || parseInt(obj2, 10) !== gen ||
4331           !isCmd(obj3)) {
4332         error('bad XRef entry');
4333       }
4334       if (!isCmd(obj3, 'obj')) {
4335         // some bad PDFs use "obj1234" and really mean 1234
4336         if (obj3.cmd.indexOf('obj') === 0) {
4337           num = parseInt(obj3.cmd.substring(3), 10);
4338           if (!isNaN(num)) {
4339             return num;
4340           }
4341         }
4342         error('bad XRef entry');
4343       }
4344       if (this.encrypt && !suppressEncryption) {
4345         xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));
4346       } else {
4347         xrefEntry = parser.getObj();
4348       }
4349       if (!isStream(xrefEntry)) {
4350         this.cache[num] = xrefEntry;
4351       }
4352       return xrefEntry;
4353     },
4354
4355     fetchCompressed: function XRef_fetchCompressed(xrefEntry,
4356                                                    suppressEncryption) {
4357       var tableOffset = xrefEntry.offset;
4358       var stream = this.fetch(new Ref(tableOffset, 0));
4359       if (!isStream(stream)) {
4360         error('bad ObjStm stream');
4361       }
4362       var first = stream.dict.get('First');
4363       var n = stream.dict.get('N');
4364       if (!isInt(first) || !isInt(n)) {
4365         error('invalid first and n parameters for ObjStm stream');
4366       }
4367       var parser = new Parser(new Lexer(stream), false, this);
4368       parser.allowStreams = true;
4369       var i, entries = [], num, nums = [];
4370       // read the object numbers to populate cache
4371       for (i = 0; i < n; ++i) {
4372         num = parser.getObj();
4373         if (!isInt(num)) {
4374           error('invalid object number in the ObjStm stream: ' + num);
4375         }
4376         nums.push(num);
4377         var offset = parser.getObj();
4378         if (!isInt(offset)) {
4379           error('invalid object offset in the ObjStm stream: ' + offset);
4380         }
4381       }
4382       // read stream objects for cache
4383       for (i = 0; i < n; ++i) {
4384         entries.push(parser.getObj());
4385         num = nums[i];
4386         var entry = this.entries[num];
4387         if (entry && entry.offset === tableOffset && entry.gen === i) {
4388           this.cache[num] = entries[i];
4389         }
4390       }
4391       xrefEntry = entries[xrefEntry.gen];
4392       if (xrefEntry === undefined) {
4393         error('bad XRef entry for compressed object');
4394       }
4395       return xrefEntry;
4396     },
4397
4398     fetchIfRefAsync: function XRef_fetchIfRefAsync(obj) {
4399       if (!isRef(obj)) {
4400         return Promise.resolve(obj);
4401       }
4402       return this.fetchAsync(obj);
4403     },
4404
4405     fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) {
4406       var streamManager = this.stream.manager;
4407       var xref = this;
4408       return new Promise(function tryFetch(resolve, reject) {
4409         try {
4410           resolve(xref.fetch(ref, suppressEncryption));
4411         } catch (e) {
4412           if (e instanceof MissingDataException) {
4413             streamManager.requestRange(e.begin, e.end, function () {
4414               tryFetch(resolve, reject);
4415             });
4416             return;
4417           }
4418           reject(e);
4419         }
4420       });
4421     },
4422
4423     getCatalogObj: function XRef_getCatalogObj() {
4424       return this.root;
4425     }
4426   };
4427
4428   return XRef;
4429 })();
4430
4431 /**
4432  * A NameTree is like a Dict but has some advantageous properties, see the
4433  * spec (7.9.6) for more details.
4434  * TODO: implement all the Dict functions and make this more efficent.
4435  */
4436 var NameTree = (function NameTreeClosure() {
4437   function NameTree(root, xref) {
4438     this.root = root;
4439     this.xref = xref;
4440   }
4441
4442   NameTree.prototype = {
4443     getAll: function NameTree_getAll() {
4444       var dict = {};
4445       if (!this.root) {
4446         return dict;
4447       }
4448       var xref = this.xref;
4449       // reading name tree
4450       var processed = new RefSet();
4451       processed.put(this.root);
4452       var queue = [this.root];
4453       while (queue.length > 0) {
4454         var i, n;
4455         var obj = xref.fetchIfRef(queue.shift());
4456         if (!isDict(obj)) {
4457           continue;
4458         }
4459         if (obj.has('Kids')) {
4460           var kids = obj.get('Kids');
4461           for (i = 0, n = kids.length; i < n; i++) {
4462             var kid = kids[i];
4463             if (processed.has(kid)) {
4464               error('invalid destinations');
4465             }
4466             queue.push(kid);
4467             processed.put(kid);
4468           }
4469           continue;
4470         }
4471         var names = obj.get('Names');
4472         if (names) {
4473           for (i = 0, n = names.length; i < n; i += 2) {
4474             dict[names[i]] = xref.fetchIfRef(names[i + 1]);
4475           }
4476         }
4477       }
4478       return dict;
4479     },
4480
4481     get: function NameTree_get(destinationId) {
4482       if (!this.root) {
4483         return null;
4484       }
4485
4486       var xref = this.xref;
4487       var kidsOrNames = xref.fetchIfRef(this.root);
4488       var loopCount = 0;
4489       var MAX_NAMES_LEVELS = 10;
4490       var l, r, m;
4491
4492       // Perform a binary search to quickly find the entry that
4493       // contains the named destination we are looking for.
4494       while (kidsOrNames.has('Kids')) {
4495         loopCount++;
4496         if (loopCount > MAX_NAMES_LEVELS) {
4497           warn('Search depth limit for named destionations has been reached.');
4498           return null;
4499         }
4500
4501         var kids = kidsOrNames.get('Kids');
4502         if (!isArray(kids)) {
4503           return null;
4504         }
4505
4506         l = 0;
4507         r = kids.length - 1;
4508         while (l <= r) {
4509           m = (l + r) >> 1;
4510           var kid = xref.fetchIfRef(kids[m]);
4511           var limits = kid.get('Limits');
4512
4513           if (destinationId < limits[0]) {
4514             r = m - 1;
4515           } else if (destinationId > limits[1]) {
4516             l = m + 1;
4517           } else {
4518             kidsOrNames = xref.fetchIfRef(kids[m]);
4519             break;
4520           }
4521         }
4522         if (l > r) {
4523           return null;
4524         }
4525       }
4526
4527       // If we get here, then we have found the right entry. Now
4528       // go through the named destinations in the Named dictionary
4529       // until we find the exact destination we're looking for.
4530       var names = kidsOrNames.get('Names');
4531       if (isArray(names)) {
4532         // Perform a binary search to reduce the lookup time.
4533         l = 0;
4534         r = names.length - 2;
4535         while (l <= r) {
4536           // Check only even indices (0, 2, 4, ...) because the
4537           // odd indices contain the actual D array.
4538           m = (l + r) & ~1;
4539           if (destinationId < names[m]) {
4540             r = m - 2;
4541           } else if (destinationId > names[m]) {
4542             l = m + 2;
4543           } else {
4544             return xref.fetchIfRef(names[m + 1]);
4545           }
4546         }
4547       }
4548       return null;
4549     }
4550   };
4551   return NameTree;
4552 })();
4553
4554 /**
4555  * "A PDF file can refer to the contents of another file by using a File
4556  * Specification (PDF 1.1)", see the spec (7.11) for more details.
4557  * NOTE: Only embedded files are supported (as part of the attachments support)
4558  * TODO: support the 'URL' file system (with caching if !/V), portable
4559  * collections attributes and related files (/RF)
4560  */
4561 var FileSpec = (function FileSpecClosure() {
4562   function FileSpec(root, xref) {
4563     if (!root || !isDict(root)) {
4564       return;
4565     }
4566     this.xref = xref;
4567     this.root = root;
4568     if (root.has('FS')) {
4569       this.fs = root.get('FS');
4570     }
4571     this.description = root.has('Desc') ?
4572                          stringToPDFString(root.get('Desc')) :
4573                          '';
4574     if (root.has('RF')) {
4575       warn('Related file specifications are not supported');
4576     }
4577     this.contentAvailable = true;
4578     if (!root.has('EF')) {
4579       this.contentAvailable = false;
4580       warn('Non-embedded file specifications are not supported');
4581     }
4582   }
4583
4584   function pickPlatformItem(dict) {
4585     // Look for the filename in this order:
4586     // UF, F, Unix, Mac, DOS
4587     if (dict.has('UF')) {
4588       return dict.get('UF');
4589     } else if (dict.has('F')) {
4590       return dict.get('F');
4591     } else if (dict.has('Unix')) {
4592       return dict.get('Unix');
4593     } else if (dict.has('Mac')) {
4594       return dict.get('Mac');
4595     } else if (dict.has('DOS')) {
4596       return dict.get('DOS');
4597     } else {
4598       return null;
4599     }
4600   }
4601
4602   FileSpec.prototype = {
4603     get filename() {
4604       if (!this._filename && this.root) {
4605         var filename = pickPlatformItem(this.root) || 'unnamed';
4606         this._filename = stringToPDFString(filename).
4607           replace(/\\\\/g, '\\').
4608           replace(/\\\//g, '/').
4609           replace(/\\/g, '/');
4610       }
4611       return this._filename;
4612     },
4613     get content() {
4614       if (!this.contentAvailable) {
4615         return null;
4616       }
4617       if (!this.contentRef && this.root) {
4618         this.contentRef = pickPlatformItem(this.root.get('EF'));
4619       }
4620       var content = null;
4621       if (this.contentRef) {
4622         var xref = this.xref;
4623         var fileObj = xref.fetchIfRef(this.contentRef);
4624         if (fileObj && isStream(fileObj)) {
4625           content = fileObj.getBytes();
4626         } else {
4627           warn('Embedded file specification points to non-existing/invalid ' +
4628             'content');
4629         }
4630       } else {
4631         warn('Embedded file specification does not have a content');
4632       }
4633       return content;
4634     },
4635     get serializable() {
4636       return {
4637         filename: this.filename,
4638         content: this.content
4639       };
4640     }
4641   };
4642   return FileSpec;
4643 })();
4644
4645 /**
4646  * A helper for loading missing data in object graphs. It traverses the graph
4647  * depth first and queues up any objects that have missing data. Once it has
4648  * has traversed as many objects that are available it attempts to bundle the
4649  * missing data requests and then resume from the nodes that weren't ready.
4650  *
4651  * NOTE: It provides protection from circular references by keeping track of
4652  * of loaded references. However, you must be careful not to load any graphs
4653  * that have references to the catalog or other pages since that will cause the
4654  * entire PDF document object graph to be traversed.
4655  */
4656 var ObjectLoader = (function() {
4657   function mayHaveChildren(value) {
4658     return isRef(value) || isDict(value) || isArray(value) || isStream(value);
4659   }
4660
4661   function addChildren(node, nodesToVisit) {
4662     var value;
4663     if (isDict(node) || isStream(node)) {
4664       var map;
4665       if (isDict(node)) {
4666         map = node.map;
4667       } else {
4668         map = node.dict.map;
4669       }
4670       for (var key in map) {
4671         value = map[key];
4672         if (mayHaveChildren(value)) {
4673           nodesToVisit.push(value);
4674         }
4675       }
4676     } else if (isArray(node)) {
4677       for (var i = 0, ii = node.length; i < ii; i++) {
4678         value = node[i];
4679         if (mayHaveChildren(value)) {
4680           nodesToVisit.push(value);
4681         }
4682       }
4683     }
4684   }
4685
4686   function ObjectLoader(obj, keys, xref) {
4687     this.obj = obj;
4688     this.keys = keys;
4689     this.xref = xref;
4690     this.refSet = null;
4691   }
4692
4693   ObjectLoader.prototype = {
4694     load: function ObjectLoader_load() {
4695       var keys = this.keys;
4696       this.capability = createPromiseCapability();
4697       // Don't walk the graph if all the data is already loaded.
4698       if (!(this.xref.stream instanceof ChunkedStream) ||
4699           this.xref.stream.getMissingChunks().length === 0) {
4700         this.capability.resolve();
4701         return this.capability.promise;
4702       }
4703
4704       this.refSet = new RefSet();
4705       // Setup the initial nodes to visit.
4706       var nodesToVisit = [];
4707       for (var i = 0; i < keys.length; i++) {
4708         nodesToVisit.push(this.obj[keys[i]]);
4709       }
4710
4711       this.walk(nodesToVisit);
4712       return this.capability.promise;
4713     },
4714
4715     walk: function ObjectLoader_walk(nodesToVisit) {
4716       var nodesToRevisit = [];
4717       var pendingRequests = [];
4718       // DFS walk of the object graph.
4719       while (nodesToVisit.length) {
4720         var currentNode = nodesToVisit.pop();
4721
4722         // Only references or chunked streams can cause missing data exceptions.
4723         if (isRef(currentNode)) {
4724           // Skip nodes that have already been visited.
4725           if (this.refSet.has(currentNode)) {
4726             continue;
4727           }
4728           try {
4729             var ref = currentNode;
4730             this.refSet.put(ref);
4731             currentNode = this.xref.fetch(currentNode);
4732           } catch (e) {
4733             if (!(e instanceof MissingDataException)) {
4734               throw e;
4735             }
4736             nodesToRevisit.push(currentNode);
4737             pendingRequests.push({ begin: e.begin, end: e.end });
4738           }
4739         }
4740         if (currentNode && currentNode.getBaseStreams) {
4741           var baseStreams = currentNode.getBaseStreams();
4742           var foundMissingData = false;
4743           for (var i = 0; i < baseStreams.length; i++) {
4744             var stream = baseStreams[i];
4745             if (stream.getMissingChunks && stream.getMissingChunks().length) {
4746               foundMissingData = true;
4747               pendingRequests.push({
4748                 begin: stream.start,
4749                 end: stream.end
4750               });
4751             }
4752           }
4753           if (foundMissingData) {
4754             nodesToRevisit.push(currentNode);
4755           }
4756         }
4757
4758         addChildren(currentNode, nodesToVisit);
4759       }
4760
4761       if (pendingRequests.length) {
4762         this.xref.stream.manager.requestRanges(pendingRequests,
4763             function pendingRequestCallback() {
4764           nodesToVisit = nodesToRevisit;
4765           for (var i = 0; i < nodesToRevisit.length; i++) {
4766             var node = nodesToRevisit[i];
4767             // Remove any reference nodes from the currrent refset so they
4768             // aren't skipped when we revist them.
4769             if (isRef(node)) {
4770               this.refSet.remove(node);
4771             }
4772           }
4773           this.walk(nodesToVisit);
4774         }.bind(this));
4775         return;
4776       }
4777       // Everything is loaded.
4778       this.refSet = null;
4779       this.capability.resolve();
4780     }
4781   };
4782
4783   return ObjectLoader;
4784 })();
4785
4786
4787 var ISOAdobeCharset = [
4788   '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
4789   'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
4790   'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',
4791   'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
4792   'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',
4793   'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
4794   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
4795   'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
4796   'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
4797   'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
4798   'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
4799   'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
4800   'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
4801   'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
4802   'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
4803   'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
4804   'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde',
4805   'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
4806   'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine',
4807   'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash',
4808   'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',
4809   'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',
4810   'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',
4811   'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
4812   'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',
4813   'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',
4814   'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
4815   'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',
4816   'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',
4817   'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
4818   'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
4819   'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
4820   'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',
4821   'ugrave', 'yacute', 'ydieresis', 'zcaron'
4822 ];
4823
4824 var ExpertCharset = [
4825   '.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
4826   'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
4827   'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
4828   'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
4829   'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
4830   'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',
4831   'colon', 'semicolon', 'commasuperior', 'threequartersemdash',
4832   'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',
4833   'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
4834   'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
4835   'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
4836   'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
4837   'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
4838   'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
4839   'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
4840   'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
4841   'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',
4842   'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
4843   'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
4844   'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',
4845   'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',
4846   'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
4847   'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
4848   'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
4849   'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
4850   'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
4851   'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
4852   'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
4853   'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
4854   'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
4855   'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
4856   'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
4857   'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
4858   'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
4859   'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
4860   'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
4861   'Ydieresissmall'
4862 ];
4863
4864 var ExpertSubsetCharset = [
4865   '.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
4866   'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
4867   'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',
4868   'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
4869   'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',
4870   'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',
4871   'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',
4872   'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
4873   'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
4874   'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
4875   'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',
4876   'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',
4877   'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
4878   'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
4879   'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
4880   'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
4881   'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
4882   'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
4883   'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
4884   'periodinferior', 'commainferior'
4885 ];
4886
4887
4888 var DEFAULT_ICON_SIZE = 22; // px
4889 var SUPPORTED_TYPES = ['Link', 'Text', 'Widget'];
4890
4891 var Annotation = (function AnnotationClosure() {
4892   // 12.5.5: Algorithm: Appearance streams
4893   function getTransformMatrix(rect, bbox, matrix) {
4894     var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
4895     var minX = bounds[0];
4896     var minY = bounds[1];
4897     var maxX = bounds[2];
4898     var maxY = bounds[3];
4899
4900     if (minX === maxX || minY === maxY) {
4901       // From real-life file, bbox was [0, 0, 0, 0]. In this case,
4902       // just apply the transform for rect
4903       return [1, 0, 0, 1, rect[0], rect[1]];
4904     }
4905
4906     var xRatio = (rect[2] - rect[0]) / (maxX - minX);
4907     var yRatio = (rect[3] - rect[1]) / (maxY - minY);
4908     return [
4909       xRatio,
4910       0,
4911       0,
4912       yRatio,
4913       rect[0] - minX * xRatio,
4914       rect[1] - minY * yRatio
4915     ];
4916   }
4917
4918   function getDefaultAppearance(dict) {
4919     var appearanceState = dict.get('AP');
4920     if (!isDict(appearanceState)) {
4921       return;
4922     }
4923
4924     var appearance;
4925     var appearances = appearanceState.get('N');
4926     if (isDict(appearances)) {
4927       var as = dict.get('AS');
4928       if (as && appearances.has(as.name)) {
4929         appearance = appearances.get(as.name);
4930       }
4931     } else {
4932       appearance = appearances;
4933     }
4934     return appearance;
4935   }
4936
4937   function Annotation(params) {
4938     var dict = params.dict;
4939     var data = this.data = {};
4940
4941     data.subtype = dict.get('Subtype').name;
4942     var rect = dict.get('Rect') || [0, 0, 0, 0];
4943     data.rect = Util.normalizeRect(rect);
4944     data.annotationFlags = dict.get('F');
4945
4946     var color = dict.get('C');
4947     if (!color) {
4948       // The PDF spec does not mention how a missing color array is interpreted.
4949       // Adobe Reader seems to default to black in this case.
4950       data.color = [0, 0, 0];
4951     } else if (isArray(color)) {
4952       switch (color.length) {
4953         case 0:
4954           // Empty array denotes transparent border.
4955           data.color = null;
4956           break;
4957         case 1:
4958           // TODO: implement DeviceGray
4959           break;
4960         case 3:
4961           data.color = color;
4962           break;
4963         case 4:
4964           // TODO: implement DeviceCMYK
4965           break;
4966       }
4967     }
4968
4969     // Some types of annotations have border style dict which has more
4970     // info than the border array
4971     if (dict.has('BS')) {
4972       var borderStyle = dict.get('BS');
4973       data.borderWidth = borderStyle.has('W') ? borderStyle.get('W') : 1;
4974     } else {
4975       var borderArray = dict.get('Border') || [0, 0, 1];
4976       data.borderWidth = borderArray[2] || 0;
4977
4978       // TODO: implement proper support for annotations with line dash patterns.
4979       var dashArray = borderArray[3];
4980       if (data.borderWidth > 0 && dashArray) {
4981         if (!isArray(dashArray)) {
4982           // Ignore the border if dashArray is not actually an array,
4983           // this is consistent with the behaviour in Adobe Reader.
4984           data.borderWidth = 0;
4985         } else {
4986           var dashArrayLength = dashArray.length;
4987           if (dashArrayLength > 0) {
4988             // According to the PDF specification: the elements in a dashArray
4989             // shall be numbers that are nonnegative and not all equal to zero.
4990             var isInvalid = false;
4991             var numPositive = 0;
4992             for (var i = 0; i < dashArrayLength; i++) {
4993               var validNumber = (+dashArray[i] >= 0);
4994               if (!validNumber) {
4995                 isInvalid = true;
4996                 break;
4997               } else if (dashArray[i] > 0) {
4998                 numPositive++;
4999               }
5000             }
5001             if (isInvalid || numPositive === 0) {
5002               data.borderWidth = 0;
5003             }
5004           }
5005         }
5006       }
5007     }
5008
5009     this.appearance = getDefaultAppearance(dict);
5010     data.hasAppearance = !!this.appearance;
5011     data.id = params.ref.num;
5012   }
5013
5014   Annotation.prototype = {
5015
5016     getData: function Annotation_getData() {
5017       return this.data;
5018     },
5019
5020     isInvisible: function Annotation_isInvisible() {
5021       var data = this.data;
5022       if (data && SUPPORTED_TYPES.indexOf(data.subtype) !== -1) {
5023         return false;
5024       } else {
5025         return !!(data &&
5026                   data.annotationFlags &&            // Default: not invisible
5027                   data.annotationFlags & 0x1);       // Invisible
5028       }
5029     },
5030
5031     isViewable: function Annotation_isViewable() {
5032       var data = this.data;
5033       return !!(!this.isInvisible() &&
5034                 data &&
5035                 (!data.annotationFlags ||
5036                  !(data.annotationFlags & 0x22)) &&  // Hidden or NoView
5037                 data.rect);                          // rectangle is necessary
5038     },
5039
5040     isPrintable: function Annotation_isPrintable() {
5041       var data = this.data;
5042       return !!(!this.isInvisible() &&
5043                 data &&
5044                 data.annotationFlags &&              // Default: not printable
5045                 data.annotationFlags & 0x4 &&        // Print
5046                 !(data.annotationFlags & 0x2) &&     // Hidden
5047                 data.rect);                          // rectangle is necessary
5048     },
5049
5050     loadResources: function Annotation_loadResources(keys) {
5051       return new Promise(function (resolve, reject) {
5052         this.appearance.dict.getAsync('Resources').then(function (resources) {
5053           if (!resources) {
5054             resolve();
5055             return;
5056           }
5057           var objectLoader = new ObjectLoader(resources.map,
5058                                               keys,
5059                                               resources.xref);
5060           objectLoader.load().then(function() {
5061             resolve(resources);
5062           }, reject);
5063         }, reject);
5064       }.bind(this));
5065     },
5066
5067     getOperatorList: function Annotation_getOperatorList(evaluator) {
5068
5069       if (!this.appearance) {
5070         return Promise.resolve(new OperatorList());
5071       }
5072
5073       var data = this.data;
5074
5075       var appearanceDict = this.appearance.dict;
5076       var resourcesPromise = this.loadResources([
5077         'ExtGState',
5078         'ColorSpace',
5079         'Pattern',
5080         'Shading',
5081         'XObject',
5082         'Font'
5083         // ProcSet
5084         // Properties
5085       ]);
5086       var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
5087       var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
5088       var transform = getTransformMatrix(data.rect, bbox, matrix);
5089       var self = this;
5090
5091       return resourcesPromise.then(function(resources) {
5092           var opList = new OperatorList();
5093           opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
5094           return evaluator.getOperatorList(self.appearance, resources, opList).
5095             then(function () {
5096               opList.addOp(OPS.endAnnotation, []);
5097               self.appearance.reset();
5098               return opList;
5099             });
5100         });
5101     }
5102   };
5103
5104   Annotation.getConstructor =
5105       function Annotation_getConstructor(subtype, fieldType) {
5106
5107     if (!subtype) {
5108       return;
5109     }
5110
5111     // TODO(mack): Implement FreeText annotations
5112     if (subtype === 'Link') {
5113       return LinkAnnotation;
5114     } else if (subtype === 'Text') {
5115       return TextAnnotation;
5116     } else if (subtype === 'Widget') {
5117       if (!fieldType) {
5118         return;
5119       }
5120
5121       if (fieldType === 'Tx') {
5122         return TextWidgetAnnotation;
5123       } else {
5124         return WidgetAnnotation;
5125       }
5126     } else {
5127       return Annotation;
5128     }
5129   };
5130
5131   Annotation.fromRef = function Annotation_fromRef(xref, ref) {
5132
5133     var dict = xref.fetchIfRef(ref);
5134     if (!isDict(dict)) {
5135       return;
5136     }
5137
5138     var subtype = dict.get('Subtype');
5139     subtype = isName(subtype) ? subtype.name : '';
5140     if (!subtype) {
5141       return;
5142     }
5143
5144     var fieldType = Util.getInheritableProperty(dict, 'FT');
5145     fieldType = isName(fieldType) ? fieldType.name : '';
5146
5147     var Constructor = Annotation.getConstructor(subtype, fieldType);
5148     if (!Constructor) {
5149       return;
5150     }
5151
5152     var params = {
5153       dict: dict,
5154       ref: ref,
5155     };
5156
5157     var annotation = new Constructor(params);
5158
5159     if (annotation.isViewable() || annotation.isPrintable()) {
5160       return annotation;
5161     } else {
5162       if (SUPPORTED_TYPES.indexOf(subtype) === -1) {
5163         warn('unimplemented annotation type: ' + subtype);
5164       }
5165     }
5166   };
5167
5168   Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
5169       annotations, opList, pdfManager, partialEvaluator, intent) {
5170
5171     function reject(e) {
5172       annotationsReadyCapability.reject(e);
5173     }
5174
5175     var annotationsReadyCapability = createPromiseCapability();
5176
5177     var annotationPromises = [];
5178     for (var i = 0, n = annotations.length; i < n; ++i) {
5179       if (intent === 'display' && annotations[i].isViewable() ||
5180           intent === 'print' && annotations[i].isPrintable()) {
5181         annotationPromises.push(
5182           annotations[i].getOperatorList(partialEvaluator));
5183       }
5184     }
5185     Promise.all(annotationPromises).then(function(datas) {
5186       opList.addOp(OPS.beginAnnotations, []);
5187       for (var i = 0, n = datas.length; i < n; ++i) {
5188         var annotOpList = datas[i];
5189         opList.addOpList(annotOpList);
5190       }
5191       opList.addOp(OPS.endAnnotations, []);
5192       annotationsReadyCapability.resolve();
5193     }, reject);
5194
5195     return annotationsReadyCapability.promise;
5196   };
5197
5198   return Annotation;
5199 })();
5200
5201 var WidgetAnnotation = (function WidgetAnnotationClosure() {
5202
5203   function WidgetAnnotation(params) {
5204     Annotation.call(this, params);
5205
5206     var dict = params.dict;
5207     var data = this.data;
5208
5209     data.fieldValue = stringToPDFString(
5210       Util.getInheritableProperty(dict, 'V') || '');
5211     data.alternativeText = stringToPDFString(dict.get('TU') || '');
5212     data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
5213     var fieldType = Util.getInheritableProperty(dict, 'FT');
5214     data.fieldType = isName(fieldType) ? fieldType.name : '';
5215     data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
5216     this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
5217
5218     // Building the full field name by collecting the field and
5219     // its ancestors 'T' data and joining them using '.'.
5220     var fieldName = [];
5221     var namedItem = dict;
5222     var ref = params.ref;
5223     while (namedItem) {
5224       var parent = namedItem.get('Parent');
5225       var parentRef = namedItem.getRaw('Parent');
5226       var name = namedItem.get('T');
5227       if (name) {
5228         fieldName.unshift(stringToPDFString(name));
5229       } else if (parent && ref) {
5230         // The field name is absent, that means more than one field
5231         // with the same name may exist. Replacing the empty name
5232         // with the '`' plus index in the parent's 'Kids' array.
5233         // This is not in the PDF spec but necessary to id the
5234         // the input controls.
5235         var kids = parent.get('Kids');
5236         var j, jj;
5237         for (j = 0, jj = kids.length; j < jj; j++) {
5238           var kidRef = kids[j];
5239           if (kidRef.num === ref.num && kidRef.gen === ref.gen) {
5240             break;
5241           }
5242         }
5243         fieldName.unshift('`' + j);
5244       }
5245       namedItem = parent;
5246       ref = parentRef;
5247     }
5248     data.fullName = fieldName.join('.');
5249   }
5250
5251   var parent = Annotation.prototype;
5252   Util.inherit(WidgetAnnotation, Annotation, {
5253     isViewable: function WidgetAnnotation_isViewable() {
5254       if (this.data.fieldType === 'Sig') {
5255         warn('unimplemented annotation type: Widget signature');
5256         return false;
5257       }
5258
5259       return parent.isViewable.call(this);
5260     }
5261   });
5262
5263   return WidgetAnnotation;
5264 })();
5265
5266 var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
5267   function TextWidgetAnnotation(params) {
5268     WidgetAnnotation.call(this, params);
5269
5270     this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q');
5271     this.data.annotationType = AnnotationType.WIDGET;
5272     this.data.hasHtml = !this.data.hasAppearance && !!this.data.fieldValue;
5273   }
5274
5275   Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
5276     getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
5277       if (this.appearance) {
5278         return Annotation.prototype.getOperatorList.call(this, evaluator);
5279       }
5280
5281       var opList = new OperatorList();
5282       var data = this.data;
5283
5284       // Even if there is an appearance stream, ignore it. This is the
5285       // behaviour used by Adobe Reader.
5286       if (!data.defaultAppearance) {
5287         return Promise.resolve(opList);
5288       }
5289
5290       var stream = new Stream(stringToBytes(data.defaultAppearance));
5291       return evaluator.getOperatorList(stream, this.fieldResources, opList).
5292         then(function () {
5293           return opList;
5294         });
5295     }
5296   });
5297
5298   return TextWidgetAnnotation;
5299 })();
5300
5301 var InteractiveAnnotation = (function InteractiveAnnotationClosure() {
5302   function InteractiveAnnotation(params) {
5303     Annotation.call(this, params);
5304
5305     this.data.hasHtml = true;
5306   }
5307
5308   Util.inherit(InteractiveAnnotation, Annotation, { });
5309
5310   return InteractiveAnnotation;
5311 })();
5312
5313 var TextAnnotation = (function TextAnnotationClosure() {
5314   function TextAnnotation(params) {
5315     InteractiveAnnotation.call(this, params);
5316
5317     var dict = params.dict;
5318     var data = this.data;
5319
5320     var content = dict.get('Contents');
5321     var title = dict.get('T');
5322     data.annotationType = AnnotationType.TEXT;
5323     data.content = stringToPDFString(content || '');
5324     data.title = stringToPDFString(title || '');
5325
5326     if (data.hasAppearance) {
5327       data.name = 'NoIcon';
5328     } else {
5329       data.rect[1] = data.rect[3] - DEFAULT_ICON_SIZE;
5330       data.rect[2] = data.rect[0] + DEFAULT_ICON_SIZE;
5331       data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
5332     }
5333
5334     if (dict.has('C')) {
5335       data.hasBgColor = true;
5336     }
5337   }
5338
5339   Util.inherit(TextAnnotation, InteractiveAnnotation, { });
5340
5341   return TextAnnotation;
5342 })();
5343
5344 var LinkAnnotation = (function LinkAnnotationClosure() {
5345   function LinkAnnotation(params) {
5346     InteractiveAnnotation.call(this, params);
5347
5348     var dict = params.dict;
5349     var data = this.data;
5350     data.annotationType = AnnotationType.LINK;
5351
5352     var action = dict.get('A');
5353     if (action && isDict(action)) {
5354       var linkType = action.get('S').name;
5355       if (linkType === 'URI') {
5356         var url = action.get('URI');
5357         if (isName(url)) {
5358           // Some bad PDFs do not put parentheses around relative URLs.
5359           url = '/' + url.name;
5360         } else if (url) {
5361           url = addDefaultProtocolToUrl(url);
5362         }
5363         // TODO: pdf spec mentions urls can be relative to a Base
5364         // entry in the dictionary.
5365         if (!isValidUrl(url, false)) {
5366           url = '';
5367         }
5368         // According to ISO 32000-1:2008, section 12.6.4.7, 
5369         // URI should to be encoded in 7-bit ASCII.
5370         // Some bad PDFs may have URIs in UTF-8 encoding, see Bugzilla 1122280.
5371         try {
5372           data.url = stringToUTF8String(url);
5373         } catch (e) {
5374           // Fall back to a simple copy.
5375           data.url = url;
5376         }
5377       } else if (linkType === 'GoTo') {
5378         data.dest = action.get('D');
5379       } else if (linkType === 'GoToR') {
5380         var urlDict = action.get('F');
5381         if (isDict(urlDict)) {
5382           // We assume that the 'url' is a Filspec dictionary
5383           // and fetch the url without checking any further
5384           url = urlDict.get('F') || '';
5385         }
5386
5387         // TODO: pdf reference says that GoToR
5388         // can also have 'NewWindow' attribute
5389         if (!isValidUrl(url, false)) {
5390           url = '';
5391         }
5392         data.url = url;
5393         data.dest = action.get('D');
5394       } else if (linkType === 'Named') {
5395         data.action = action.get('N').name;
5396       } else {
5397         warn('unrecognized link type: ' + linkType);
5398       }
5399     } else if (dict.has('Dest')) {
5400       // simple destination link
5401       var dest = dict.get('Dest');
5402       data.dest = isName(dest) ? dest.name : dest;
5403     }
5404   }
5405
5406   // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
5407   function addDefaultProtocolToUrl(url) {
5408     if (url && url.indexOf('www.') === 0) {
5409       return ('http://' + url);
5410     }
5411     return url;
5412   }
5413
5414   Util.inherit(LinkAnnotation, InteractiveAnnotation, { });
5415
5416   return LinkAnnotation;
5417 })();
5418
5419
5420 var PDFFunction = (function PDFFunctionClosure() {
5421   var CONSTRUCT_SAMPLED = 0;
5422   var CONSTRUCT_INTERPOLATED = 2;
5423   var CONSTRUCT_STICHED = 3;
5424   var CONSTRUCT_POSTSCRIPT = 4;
5425
5426   return {
5427     getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
5428                                                        str) {
5429       var i, ii;
5430       var length = 1;
5431       for (i = 0, ii = size.length; i < ii; i++) {
5432         length *= size[i];
5433       }
5434       length *= outputSize;
5435
5436       var array = new Array(length);
5437       var codeSize = 0;
5438       var codeBuf = 0;
5439       // 32 is a valid bps so shifting won't work
5440       var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
5441
5442       var strBytes = str.getBytes((length * bps + 7) / 8);
5443       var strIdx = 0;
5444       for (i = 0; i < length; i++) {
5445         while (codeSize < bps) {
5446           codeBuf <<= 8;
5447           codeBuf |= strBytes[strIdx++];
5448           codeSize += 8;
5449         }
5450         codeSize -= bps;
5451         array[i] = (codeBuf >> codeSize) * sampleMul;
5452         codeBuf &= (1 << codeSize) - 1;
5453       }
5454       return array;
5455     },
5456
5457     getIR: function PDFFunction_getIR(xref, fn) {
5458       var dict = fn.dict;
5459       if (!dict) {
5460         dict = fn;
5461       }
5462
5463       var types = [this.constructSampled,
5464                    null,
5465                    this.constructInterpolated,
5466                    this.constructStiched,
5467                    this.constructPostScript];
5468
5469       var typeNum = dict.get('FunctionType');
5470       var typeFn = types[typeNum];
5471       if (!typeFn) {
5472         error('Unknown type of function');
5473       }
5474
5475       return typeFn.call(this, fn, dict, xref);
5476     },
5477
5478     fromIR: function PDFFunction_fromIR(IR) {
5479       var type = IR[0];
5480       switch (type) {
5481         case CONSTRUCT_SAMPLED:
5482           return this.constructSampledFromIR(IR);
5483         case CONSTRUCT_INTERPOLATED:
5484           return this.constructInterpolatedFromIR(IR);
5485         case CONSTRUCT_STICHED:
5486           return this.constructStichedFromIR(IR);
5487         //case CONSTRUCT_POSTSCRIPT:
5488         default:
5489           return this.constructPostScriptFromIR(IR);
5490       }
5491     },
5492
5493     parse: function PDFFunction_parse(xref, fn) {
5494       var IR = this.getIR(xref, fn);
5495       return this.fromIR(IR);
5496     },
5497
5498     parseArray: function PDFFunction_parseArray(xref, fnObj) {
5499       if (!isArray(fnObj)) {
5500         // not an array -- parsing as regular function
5501         return this.parse(xref, fnObj);
5502       }
5503
5504       var fnArray = [];
5505       for (var j = 0, jj = fnObj.length; j < jj; j++) {
5506         var obj = xref.fetchIfRef(fnObj[j]);
5507         fnArray.push(PDFFunction.parse(xref, obj));
5508       }
5509       return function (src, srcOffset, dest, destOffset) {
5510         for (var i = 0, ii = fnArray.length; i < ii; i++) {
5511           fnArray[i](src, srcOffset, dest, destOffset + i);
5512         }
5513       };
5514     },
5515
5516     constructSampled: function PDFFunction_constructSampled(str, dict) {
5517       function toMultiArray(arr) {
5518         var inputLength = arr.length;
5519         var out = [];
5520         var index = 0;
5521         for (var i = 0; i < inputLength; i += 2) {
5522           out[index] = [arr[i], arr[i + 1]];
5523           ++index;
5524         }
5525         return out;
5526       }
5527       var domain = dict.get('Domain');
5528       var range = dict.get('Range');
5529
5530       if (!domain || !range) {
5531         error('No domain or range');
5532       }
5533
5534       var inputSize = domain.length / 2;
5535       var outputSize = range.length / 2;
5536
5537       domain = toMultiArray(domain);
5538       range = toMultiArray(range);
5539
5540       var size = dict.get('Size');
5541       var bps = dict.get('BitsPerSample');
5542       var order = dict.get('Order') || 1;
5543       if (order !== 1) {
5544         // No description how cubic spline interpolation works in PDF32000:2008
5545         // As in poppler, ignoring order, linear interpolation may work as good
5546         info('No support for cubic spline interpolation: ' + order);
5547       }
5548
5549       var encode = dict.get('Encode');
5550       if (!encode) {
5551         encode = [];
5552         for (var i = 0; i < inputSize; ++i) {
5553           encode.push(0);
5554           encode.push(size[i] - 1);
5555         }
5556       }
5557       encode = toMultiArray(encode);
5558
5559       var decode = dict.get('Decode');
5560       if (!decode) {
5561         decode = range;
5562       } else {
5563         decode = toMultiArray(decode);
5564       }
5565
5566       var samples = this.getSampleArray(size, outputSize, bps, str);
5567
5568       return [
5569         CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
5570         outputSize, Math.pow(2, bps) - 1, range
5571       ];
5572     },
5573
5574     constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
5575       // See chapter 3, page 109 of the PDF reference
5576       function interpolate(x, xmin, xmax, ymin, ymax) {
5577         return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin)));
5578       }
5579
5580       return function constructSampledFromIRResult(src, srcOffset,
5581                                                    dest, destOffset) {
5582         // See chapter 3, page 110 of the PDF reference.
5583         var m = IR[1];
5584         var domain = IR[2];
5585         var encode = IR[3];
5586         var decode = IR[4];
5587         var samples = IR[5];
5588         var size = IR[6];
5589         var n = IR[7];
5590         //var mask = IR[8];
5591         var range = IR[9];
5592
5593         // Building the cube vertices: its part and sample index
5594         // http://rjwagner49.com/Mathematics/Interpolation.pdf
5595         var cubeVertices = 1 << m;
5596         var cubeN = new Float64Array(cubeVertices);
5597         var cubeVertex = new Uint32Array(cubeVertices);
5598         var i, j;
5599         for (j = 0; j < cubeVertices; j++) {
5600           cubeN[j] = 1;
5601         }
5602
5603         var k = n, pos = 1;
5604         // Map x_i to y_j for 0 <= i < m using the sampled function.
5605         for (i = 0; i < m; ++i) {
5606           // x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
5607           var domain_2i = domain[i][0];
5608           var domain_2i_1 = domain[i][1];
5609           var xi = Math.min(Math.max(src[srcOffset +i], domain_2i),
5610                             domain_2i_1);
5611
5612           // e_i = Interpolate(x_i', Domain_2i, Domain_2i+1,
5613           //                   Encode_2i, Encode_2i+1)
5614           var e = interpolate(xi, domain_2i, domain_2i_1,
5615                               encode[i][0], encode[i][1]);
5616
5617           // e_i' = min(max(e_i, 0), Size_i - 1)
5618           var size_i = size[i];
5619           e = Math.min(Math.max(e, 0), size_i - 1);
5620
5621           // Adjusting the cube: N and vertex sample index
5622           var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1;
5623           var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
5624           var n1 = e - e0; // (e - e0) / (e1 - e0);
5625           var offset0 = e0 * k;
5626           var offset1 = offset0 + k; // e1 * k
5627           for (j = 0; j < cubeVertices; j++) {
5628             if (j & pos) {
5629               cubeN[j] *= n1;
5630               cubeVertex[j] += offset1;
5631             } else {
5632               cubeN[j] *= n0;
5633               cubeVertex[j] += offset0;
5634             }
5635           }
5636
5637           k *= size_i;
5638           pos <<= 1;
5639         }
5640
5641         for (j = 0; j < n; ++j) {
5642           // Sum all cube vertices' samples portions
5643           var rj = 0;
5644           for (i = 0; i < cubeVertices; i++) {
5645             rj += samples[cubeVertex[i] + j] * cubeN[i];
5646           }
5647
5648           // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1,
5649           //                    Decode_2j, Decode_2j+1)
5650           rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
5651
5652           // y_j = min(max(r_j, range_2j), range_2j+1)
5653           dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]),
5654                                           range[j][1]);
5655         }
5656       };
5657     },
5658
5659     constructInterpolated: function PDFFunction_constructInterpolated(str,
5660                                                                       dict) {
5661       var c0 = dict.get('C0') || [0];
5662       var c1 = dict.get('C1') || [1];
5663       var n = dict.get('N');
5664
5665       if (!isArray(c0) || !isArray(c1)) {
5666         error('Illegal dictionary for interpolated function');
5667       }
5668
5669       var length = c0.length;
5670       var diff = [];
5671       for (var i = 0; i < length; ++i) {
5672         diff.push(c1[i] - c0[i]);
5673       }
5674
5675       return [CONSTRUCT_INTERPOLATED, c0, diff, n];
5676     },
5677
5678     constructInterpolatedFromIR:
5679       function PDFFunction_constructInterpolatedFromIR(IR) {
5680       var c0 = IR[1];
5681       var diff = IR[2];
5682       var n = IR[3];
5683
5684       var length = diff.length;
5685
5686       return function constructInterpolatedFromIRResult(src, srcOffset,
5687                                                         dest, destOffset) {
5688         var x = n === 1 ? src[srcOffset] : Math.pow(src[srcOffset], n);
5689
5690         for (var j = 0; j < length; ++j) {
5691           dest[destOffset + j] = c0[j] + (x * diff[j]);
5692         }
5693       };
5694     },
5695
5696     constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
5697       var domain = dict.get('Domain');
5698
5699       if (!domain) {
5700         error('No domain');
5701       }
5702
5703       var inputSize = domain.length / 2;
5704       if (inputSize !== 1) {
5705         error('Bad domain for stiched function');
5706       }
5707
5708       var fnRefs = dict.get('Functions');
5709       var fns = [];
5710       for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
5711         fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
5712       }
5713
5714       var bounds = dict.get('Bounds');
5715       var encode = dict.get('Encode');
5716
5717       return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
5718     },
5719
5720     constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
5721       var domain = IR[1];
5722       var bounds = IR[2];
5723       var encode = IR[3];
5724       var fnsIR = IR[4];
5725       var fns = [];
5726       var tmpBuf = new Float32Array(1);
5727
5728       for (var i = 0, ii = fnsIR.length; i < ii; i++) {
5729         fns.push(PDFFunction.fromIR(fnsIR[i]));
5730       }
5731
5732       return function constructStichedFromIRResult(src, srcOffset,
5733                                                    dest, destOffset) {
5734         var clip = function constructStichedFromIRClip(v, min, max) {
5735           if (v > max) {
5736             v = max;
5737           } else if (v < min) {
5738             v = min;
5739           }
5740           return v;
5741         };
5742
5743         // clip to domain
5744         var v = clip(src[srcOffset], domain[0], domain[1]);
5745         // calulate which bound the value is in
5746         for (var i = 0, ii = bounds.length; i < ii; ++i) {
5747           if (v < bounds[i]) {
5748             break;
5749           }
5750         }
5751
5752         // encode value into domain of function
5753         var dmin = domain[0];
5754         if (i > 0) {
5755           dmin = bounds[i - 1];
5756         }
5757         var dmax = domain[1];
5758         if (i < bounds.length) {
5759           dmax = bounds[i];
5760         }
5761
5762         var rmin = encode[2 * i];
5763         var rmax = encode[2 * i + 1];
5764
5765         tmpBuf[0] = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
5766
5767         // call the appropriate function
5768         fns[i](tmpBuf, 0, dest, destOffset);
5769       };
5770     },
5771
5772     constructPostScript: function PDFFunction_constructPostScript(fn, dict,
5773                                                                   xref) {
5774       var domain = dict.get('Domain');
5775       var range = dict.get('Range');
5776
5777       if (!domain) {
5778         error('No domain.');
5779       }
5780
5781       if (!range) {
5782         error('No range.');
5783       }
5784
5785       var lexer = new PostScriptLexer(fn);
5786       var parser = new PostScriptParser(lexer);
5787       var code = parser.parse();
5788
5789       return [CONSTRUCT_POSTSCRIPT, domain, range, code];
5790     },
5791
5792     constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(
5793                                           IR) {
5794       var domain = IR[1];
5795       var range = IR[2];
5796       var code = IR[3];
5797
5798       var compiled = (new PostScriptCompiler()).compile(code, domain, range);
5799       if (compiled) {
5800         // Compiled function consists of simple expressions such as addition,
5801         // subtraction, Math.max, and also contains 'var' and 'return'
5802         // statements. See the generation in the PostScriptCompiler below.
5803         /*jshint -W054 */
5804         return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);
5805       }
5806
5807       info('Unable to compile PS function');
5808
5809       var numOutputs = range.length >> 1;
5810       var numInputs = domain.length >> 1;
5811       var evaluator = new PostScriptEvaluator(code);
5812       // Cache the values for a big speed up, the cache size is limited though
5813       // since the number of possible values can be huge from a PS function.
5814       var cache = {};
5815       // The MAX_CACHE_SIZE is set to ~4x the maximum number of distinct values
5816       // seen in our tests.
5817       var MAX_CACHE_SIZE = 2048 * 4;
5818       var cache_available = MAX_CACHE_SIZE;
5819       var tmpBuf = new Float32Array(numInputs);
5820
5821       return function constructPostScriptFromIRResult(src, srcOffset,
5822                                                       dest, destOffset) {
5823         var i, value;
5824         var key = '';
5825         var input = tmpBuf;
5826         for (i = 0; i < numInputs; i++) {
5827           value = src[srcOffset + i];
5828           input[i] = value;
5829           key += value + '_';
5830         }
5831
5832         var cachedValue = cache[key];
5833         if (cachedValue !== undefined) {
5834           dest.set(cachedValue, destOffset);
5835           return;
5836         }
5837
5838         var output = new Float32Array(numOutputs);
5839         var stack = evaluator.execute(input);
5840         var stackIndex = stack.length - numOutputs;
5841         for (i = 0; i < numOutputs; i++) {
5842           value = stack[stackIndex + i];
5843           var bound = range[i * 2];
5844           if (value < bound) {
5845             value = bound;
5846           } else {
5847             bound = range[i * 2 +1];
5848             if (value > bound) {
5849               value = bound;
5850             }
5851           }
5852           output[i] = value;
5853         }
5854         if (cache_available > 0) {
5855           cache_available--;
5856           cache[key] = output;
5857         }
5858         dest.set(output, destOffset);
5859       };
5860     }
5861   };
5862 })();
5863
5864 function isPDFFunction(v) {
5865   var fnDict;
5866   if (typeof v !== 'object') {
5867     return false;
5868   } else if (isDict(v)) {
5869     fnDict = v;
5870   } else if (isStream(v)) {
5871     fnDict = v.dict;
5872   } else {
5873     return false;
5874   }
5875   return fnDict.has('FunctionType');
5876 }
5877
5878 var PostScriptStack = (function PostScriptStackClosure() {
5879   var MAX_STACK_SIZE = 100;
5880   function PostScriptStack(initialStack) {
5881     this.stack = !initialStack ? [] :
5882                  Array.prototype.slice.call(initialStack, 0);
5883   }
5884
5885   PostScriptStack.prototype = {
5886     push: function PostScriptStack_push(value) {
5887       if (this.stack.length >= MAX_STACK_SIZE) {
5888         error('PostScript function stack overflow.');
5889       }
5890       this.stack.push(value);
5891     },
5892     pop: function PostScriptStack_pop() {
5893       if (this.stack.length <= 0) {
5894         error('PostScript function stack underflow.');
5895       }
5896       return this.stack.pop();
5897     },
5898     copy: function PostScriptStack_copy(n) {
5899       if (this.stack.length + n >= MAX_STACK_SIZE) {
5900         error('PostScript function stack overflow.');
5901       }
5902       var stack = this.stack;
5903       for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {
5904         stack.push(stack[i]);
5905       }
5906     },
5907     index: function PostScriptStack_index(n) {
5908       this.push(this.stack[this.stack.length - n - 1]);
5909     },
5910     // rotate the last n stack elements p times
5911     roll: function PostScriptStack_roll(n, p) {
5912       var stack = this.stack;
5913       var l = stack.length - n;
5914       var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;
5915       for (i = l, j = r; i < j; i++, j--) {
5916         t = stack[i]; stack[i] = stack[j]; stack[j] = t;
5917       }
5918       for (i = l, j = c - 1; i < j; i++, j--) {
5919         t = stack[i]; stack[i] = stack[j]; stack[j] = t;
5920       }
5921       for (i = c, j = r; i < j; i++, j--) {
5922         t = stack[i]; stack[i] = stack[j]; stack[j] = t;
5923       }
5924     }
5925   };
5926   return PostScriptStack;
5927 })();
5928 var PostScriptEvaluator = (function PostScriptEvaluatorClosure() {
5929   function PostScriptEvaluator(operators) {
5930     this.operators = operators;
5931   }
5932   PostScriptEvaluator.prototype = {
5933     execute: function PostScriptEvaluator_execute(initialStack) {
5934       var stack = new PostScriptStack(initialStack);
5935       var counter = 0;
5936       var operators = this.operators;
5937       var length = operators.length;
5938       var operator, a, b;
5939       while (counter < length) {
5940         operator = operators[counter++];
5941         if (typeof operator === 'number') {
5942           // Operator is really an operand and should be pushed to the stack.
5943           stack.push(operator);
5944           continue;
5945         }
5946         switch (operator) {
5947           // non standard ps operators
5948           case 'jz': // jump if false
5949             b = stack.pop();
5950             a = stack.pop();
5951             if (!a) {
5952               counter = b;
5953             }
5954             break;
5955           case 'j': // jump
5956             a = stack.pop();
5957             counter = a;
5958             break;
5959
5960           // all ps operators in alphabetical order (excluding if/ifelse)
5961           case 'abs':
5962             a = stack.pop();
5963             stack.push(Math.abs(a));
5964             break;
5965           case 'add':
5966             b = stack.pop();
5967             a = stack.pop();
5968             stack.push(a + b);
5969             break;
5970           case 'and':
5971             b = stack.pop();
5972             a = stack.pop();
5973             if (isBool(a) && isBool(b)) {
5974               stack.push(a && b);
5975             } else {
5976               stack.push(a & b);
5977             }
5978             break;
5979           case 'atan':
5980             a = stack.pop();
5981             stack.push(Math.atan(a));
5982             break;
5983           case 'bitshift':
5984             b = stack.pop();
5985             a = stack.pop();
5986             if (a > 0) {
5987               stack.push(a << b);
5988             } else {
5989               stack.push(a >> b);
5990             }
5991             break;
5992           case 'ceiling':
5993             a = stack.pop();
5994             stack.push(Math.ceil(a));
5995             break;
5996           case 'copy':
5997             a = stack.pop();
5998             stack.copy(a);
5999             break;
6000           case 'cos':
6001             a = stack.pop();
6002             stack.push(Math.cos(a));
6003             break;
6004           case 'cvi':
6005             a = stack.pop() | 0;
6006             stack.push(a);
6007             break;
6008           case 'cvr':
6009             // noop
6010             break;
6011           case 'div':
6012             b = stack.pop();
6013             a = stack.pop();
6014             stack.push(a / b);
6015             break;
6016           case 'dup':
6017             stack.copy(1);
6018             break;
6019           case 'eq':
6020             b = stack.pop();
6021             a = stack.pop();
6022             stack.push(a === b);
6023             break;
6024           case 'exch':
6025             stack.roll(2, 1);
6026             break;
6027           case 'exp':
6028             b = stack.pop();
6029             a = stack.pop();
6030             stack.push(Math.pow(a, b));
6031             break;
6032           case 'false':
6033             stack.push(false);
6034             break;
6035           case 'floor':
6036             a = stack.pop();
6037             stack.push(Math.floor(a));
6038             break;
6039           case 'ge':
6040             b = stack.pop();
6041             a = stack.pop();
6042             stack.push(a >= b);
6043             break;
6044           case 'gt':
6045             b = stack.pop();
6046             a = stack.pop();
6047             stack.push(a > b);
6048             break;
6049           case 'idiv':
6050             b = stack.pop();
6051             a = stack.pop();
6052             stack.push((a / b) | 0);
6053             break;
6054           case 'index':
6055             a = stack.pop();
6056             stack.index(a);
6057             break;
6058           case 'le':
6059             b = stack.pop();
6060             a = stack.pop();
6061             stack.push(a <= b);
6062             break;
6063           case 'ln':
6064             a = stack.pop();
6065             stack.push(Math.log(a));
6066             break;
6067           case 'log':
6068             a = stack.pop();
6069             stack.push(Math.log(a) / Math.LN10);
6070             break;
6071           case 'lt':
6072             b = stack.pop();
6073             a = stack.pop();
6074             stack.push(a < b);
6075             break;
6076           case 'mod':
6077             b = stack.pop();
6078             a = stack.pop();
6079             stack.push(a % b);
6080             break;
6081           case 'mul':
6082             b = stack.pop();
6083             a = stack.pop();
6084             stack.push(a * b);
6085             break;
6086           case 'ne':
6087             b = stack.pop();
6088             a = stack.pop();
6089             stack.push(a !== b);
6090             break;
6091           case 'neg':
6092             a = stack.pop();
6093             stack.push(-a);
6094             break;
6095           case 'not':
6096             a = stack.pop();
6097             if (isBool(a)) {
6098               stack.push(!a);
6099             } else {
6100               stack.push(~a);
6101             }
6102             break;
6103           case 'or':
6104             b = stack.pop();
6105             a = stack.pop();
6106             if (isBool(a) && isBool(b)) {
6107               stack.push(a || b);
6108             } else {
6109               stack.push(a | b);
6110             }
6111             break;
6112           case 'pop':
6113             stack.pop();
6114             break;
6115           case 'roll':
6116             b = stack.pop();
6117             a = stack.pop();
6118             stack.roll(a, b);
6119             break;
6120           case 'round':
6121             a = stack.pop();
6122             stack.push(Math.round(a));
6123             break;
6124           case 'sin':
6125             a = stack.pop();
6126             stack.push(Math.sin(a));
6127             break;
6128           case 'sqrt':
6129             a = stack.pop();
6130             stack.push(Math.sqrt(a));
6131             break;
6132           case 'sub':
6133             b = stack.pop();
6134             a = stack.pop();
6135             stack.push(a - b);
6136             break;
6137           case 'true':
6138             stack.push(true);
6139             break;
6140           case 'truncate':
6141             a = stack.pop();
6142             a = a < 0 ? Math.ceil(a) : Math.floor(a);
6143             stack.push(a);
6144             break;
6145           case 'xor':
6146             b = stack.pop();
6147             a = stack.pop();
6148             if (isBool(a) && isBool(b)) {
6149               stack.push(a !== b);
6150             } else {
6151               stack.push(a ^ b);
6152             }
6153             break;
6154           default:
6155             error('Unknown operator ' + operator);
6156             break;
6157         }
6158       }
6159       return stack.stack;
6160     }
6161   };
6162   return PostScriptEvaluator;
6163 })();
6164
6165 // Most of the PDFs functions consist of simple operations such as:
6166 //   roll, exch, sub, cvr, pop, index, dup, mul, if, gt, add.
6167 //
6168 // We can compile most of such programs, and at the same moment, we can
6169 // optimize some expressions using basic math properties. Keeping track of
6170 // min/max values will allow us to avoid extra Math.min/Math.max calls.
6171 var PostScriptCompiler = (function PostScriptCompilerClosure() {
6172   function AstNode(type) {
6173     this.type = type;
6174   }
6175   AstNode.prototype.visit = function (visitor) {
6176     throw new Error('abstract method');
6177   };
6178
6179   function AstArgument(index, min, max) {
6180     AstNode.call(this, 'args');
6181     this.index = index;
6182     this.min = min;
6183     this.max = max;
6184   }
6185   AstArgument.prototype = Object.create(AstNode.prototype);
6186   AstArgument.prototype.visit = function (visitor) {
6187     visitor.visitArgument(this);
6188   };
6189
6190   function AstLiteral(number) {
6191     AstNode.call(this, 'literal');
6192     this.number = number;
6193     this.min = number;
6194     this.max = number;
6195   }
6196   AstLiteral.prototype = Object.create(AstNode.prototype);
6197   AstLiteral.prototype.visit = function (visitor) {
6198     visitor.visitLiteral(this);
6199   };
6200
6201   function AstBinaryOperation(op, arg1, arg2, min, max) {
6202     AstNode.call(this, 'binary');
6203     this.op = op;
6204     this.arg1 = arg1;
6205     this.arg2 = arg2;
6206     this.min = min;
6207     this.max = max;
6208   }
6209   AstBinaryOperation.prototype = Object.create(AstNode.prototype);
6210   AstBinaryOperation.prototype.visit = function (visitor) {
6211     visitor.visitBinaryOperation(this);
6212   };
6213
6214   function AstMin(arg, max) {
6215     AstNode.call(this, 'max');
6216     this.arg = arg;
6217     this.min = arg.min;
6218     this.max = max;
6219   }
6220   AstMin.prototype = Object.create(AstNode.prototype);
6221   AstMin.prototype.visit = function (visitor) {
6222     visitor.visitMin(this);
6223   };
6224
6225   function AstVariable(index, min, max) {
6226     AstNode.call(this, 'var');
6227     this.index = index;
6228     this.min = min;
6229     this.max = max;
6230   }
6231   AstVariable.prototype = Object.create(AstNode.prototype);
6232   AstVariable.prototype.visit = function (visitor) {
6233     visitor.visitVariable(this);
6234   };
6235
6236   function AstVariableDefinition(variable, arg) {
6237     AstNode.call(this, 'definition');
6238     this.variable = variable;
6239     this.arg = arg;
6240   }
6241   AstVariableDefinition.prototype = Object.create(AstNode.prototype);
6242   AstVariableDefinition.prototype.visit = function (visitor) {
6243     visitor.visitVariableDefinition(this);
6244   };
6245
6246   function ExpressionBuilderVisitor() {
6247     this.parts = [];
6248   }
6249   ExpressionBuilderVisitor.prototype = {
6250     visitArgument: function (arg) {
6251       this.parts.push('Math.max(', arg.min, ', Math.min(',
6252                       arg.max, ', src[srcOffset + ', arg.index, ']))');
6253     },
6254     visitVariable: function (variable) {
6255       this.parts.push('v', variable.index);
6256     },
6257     visitLiteral: function (literal) {
6258       this.parts.push(literal.number);
6259     },
6260     visitBinaryOperation: function (operation) {
6261       this.parts.push('(');
6262       operation.arg1.visit(this);
6263       this.parts.push(' ', operation.op, ' ');
6264       operation.arg2.visit(this);
6265       this.parts.push(')');
6266     },
6267     visitVariableDefinition: function (definition) {
6268       this.parts.push('var ');
6269       definition.variable.visit(this);
6270       this.parts.push(' = ');
6271       definition.arg.visit(this);
6272       this.parts.push(';');
6273     },
6274     visitMin: function (max) {
6275       this.parts.push('Math.min(');
6276       max.arg.visit(this);
6277       this.parts.push(', ', max.max, ')');
6278     },
6279     toString: function () {
6280       return this.parts.join('');
6281     }
6282   };
6283
6284   function buildAddOperation(num1, num2) {
6285     if (num2.type === 'literal' && num2.number === 0) {
6286       // optimization: second operand is 0
6287       return num1;
6288     }
6289     if (num1.type === 'literal' && num1.number === 0) {
6290       // optimization: first operand is 0
6291       return num2;
6292     }
6293     if (num2.type === 'literal' && num1.type === 'literal') {
6294       // optimization: operands operand are literals
6295       return new AstLiteral(num1.number + num2.number);
6296     }
6297     return new AstBinaryOperation('+', num1, num2,
6298                                   num1.min + num2.min, num1.max + num2.max);
6299   }
6300
6301   function buildMulOperation(num1, num2) {
6302     if (num2.type === 'literal') {
6303       // optimization: second operands is a literal...
6304       if (num2.number === 0) {
6305         return new AstLiteral(0); // and it's 0
6306       } else if (num2.number === 1) {
6307         return num1; // and it's 1
6308       } else if (num1.type === 'literal') {
6309         // ... and first operands is a literal too
6310         return new AstLiteral(num1.number * num2.number);
6311       }
6312     }
6313     if (num1.type === 'literal') {
6314       // optimization: first operands is a literal...
6315       if (num1.number === 0) {
6316         return new AstLiteral(0); // and it's 0
6317       } else if (num1.number === 1) {
6318         return num2; // and it's 1
6319       }
6320     }
6321     var min = Math.min(num1.min * num2.min, num1.min * num2.max,
6322                        num1.max * num2.min, num1.max * num2.max);
6323     var max = Math.max(num1.min * num2.min, num1.min * num2.max,
6324                        num1.max * num2.min, num1.max * num2.max);
6325     return new AstBinaryOperation('*', num1, num2, min, max);
6326   }
6327
6328   function buildSubOperation(num1, num2) {
6329     if (num2.type === 'literal') {
6330       // optimization: second operands is a literal...
6331       if (num2.number === 0) {
6332         return num1; // ... and it's 0
6333       } else if (num1.type === 'literal') {
6334         // ... and first operands is a literal too
6335         return new AstLiteral(num1.number - num2.number);
6336       }
6337     }
6338     if (num2.type === 'binary' && num2.op === '-' &&
6339       num1.type === 'literal' && num1.number === 1 &&
6340       num2.arg1.type === 'literal' && num2.arg1.number === 1) {
6341       // optimization for case: 1 - (1 - x)
6342       return num2.arg2;
6343     }
6344     return new AstBinaryOperation('-', num1, num2,
6345                                   num1.min - num2.max, num1.max - num2.min);
6346   }
6347
6348   function buildMinOperation(num1, max) {
6349     if (num1.min >= max) {
6350       // optimization: num1 min value is not less than required max
6351       return new AstLiteral(max); // just returning max
6352     } else if (num1.max <= max) {
6353       // optimization: num1 max value is not greater than required max
6354       return num1; // just returning an argument
6355     }
6356     return new AstMin(num1, max);
6357   }
6358
6359   function PostScriptCompiler() {}
6360   PostScriptCompiler.prototype = {
6361     compile: function PostScriptCompiler_compile(code, domain, range) {
6362       var stack = [];
6363       var i, ii;
6364       var instructions = [];
6365       var inputSize = domain.length >> 1, outputSize = range.length >> 1;
6366       var lastRegister = 0;
6367       var n, j, min, max;
6368       var num1, num2, ast1, ast2, tmpVar, item;
6369       for (i = 0; i < inputSize; i++) {
6370         stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1]));
6371       }
6372
6373       for (i = 0, ii = code.length; i < ii; i++) {
6374         item = code[i];
6375         if (typeof item === 'number') {
6376           stack.push(new AstLiteral(item));
6377           continue;
6378         }
6379
6380         switch (item) {
6381           case 'add':
6382             if (stack.length < 2) {
6383               return null;
6384             }
6385             num2 = stack.pop();
6386             num1 = stack.pop();
6387             stack.push(buildAddOperation(num1, num2));
6388             break;
6389           case 'cvr':
6390             if (stack.length < 1) {
6391               return null;
6392             }
6393             break;
6394           case 'mul':
6395             if (stack.length < 2) {
6396               return null;
6397             }
6398             num2 = stack.pop();
6399             num1 = stack.pop();
6400             stack.push(buildMulOperation(num1, num2));
6401             break;
6402           case 'sub':
6403             if (stack.length < 2) {
6404               return null;
6405             }
6406             num2 = stack.pop();
6407             num1 = stack.pop();
6408             stack.push(buildSubOperation(num1, num2));
6409             break;
6410           case 'exch':
6411             if (stack.length < 2) {
6412               return null;
6413             }
6414             ast1 = stack.pop(); ast2 = stack.pop();
6415             stack.push(ast1, ast2);
6416             break;
6417           case 'pop':
6418             if (stack.length < 1) {
6419               return null;
6420             }
6421             stack.pop();
6422             break;
6423           case 'index':
6424             if (stack.length < 1) {
6425               return null;
6426             }
6427             num1 = stack.pop();
6428             if (num1.type !== 'literal') {
6429               return null;
6430             }
6431             n = num1.number;
6432             if (n < 0 || (n|0) !== n || stack.length < n) {
6433               return null;
6434             }
6435             ast1 = stack[stack.length - n - 1];
6436             if (ast1.type === 'literal' || ast1.type === 'var') {
6437               stack.push(ast1);
6438               break;
6439             }
6440             tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
6441             stack[stack.length - n - 1] = tmpVar;
6442             stack.push(tmpVar);
6443             instructions.push(new AstVariableDefinition(tmpVar, ast1));
6444             break;
6445           case 'dup':
6446             if (stack.length < 1) {
6447               return null;
6448             }
6449             if (typeof code[i + 1] === 'number' && code[i + 2] === 'gt' &&
6450                 code[i + 3] === i + 7 && code[i + 4] === 'jz' &&
6451                 code[i + 5] === 'pop' && code[i + 6] === code[i + 1]) {
6452               // special case of the commands sequence for the min operation
6453               num1 = stack.pop();
6454               stack.push(buildMinOperation(num1, code[i + 1]));
6455               i += 6;
6456               break;
6457             }
6458             ast1 = stack[stack.length - 1];
6459             if (ast1.type === 'literal' || ast1.type === 'var') {
6460               // we don't have to save into intermediate variable a literal or
6461               // variable.
6462               stack.push(ast1);
6463               break;
6464             }
6465             tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
6466             stack[stack.length - 1] = tmpVar;
6467             stack.push(tmpVar);
6468             instructions.push(new AstVariableDefinition(tmpVar, ast1));
6469             break;
6470           case 'roll':
6471             if (stack.length < 2) {
6472               return null;
6473             }
6474             num2 = stack.pop();
6475             num1 = stack.pop();
6476             if (num2.type !== 'literal' || num1.type !== 'literal') {
6477               // both roll operands must be numbers
6478               return null;
6479             }
6480             j = num2.number;
6481             n = num1.number;
6482             if (n <= 0 || (n|0) !== n || (j|0) !== j || stack.length < n) {
6483               // ... and integers
6484               return null;
6485             }
6486             j = ((j % n) + n) % n;
6487             if (j === 0) {
6488               break; // just skipping -- there are nothing to rotate
6489             }
6490             Array.prototype.push.apply(stack,
6491                                        stack.splice(stack.length - n, n - j));
6492             break;
6493           default:
6494             return null; // unsupported operator
6495         }
6496       }
6497
6498       if (stack.length !== outputSize) {
6499         return null;
6500       }
6501
6502       var result = [];
6503       instructions.forEach(function (instruction) {
6504         var statementBuilder = new ExpressionBuilderVisitor();
6505         instruction.visit(statementBuilder);
6506         result.push(statementBuilder.toString());
6507       });
6508       stack.forEach(function (expr, i) {
6509         var statementBuilder = new ExpressionBuilderVisitor();
6510         expr.visit(statementBuilder);
6511         var min = range[i * 2], max = range[i * 2 + 1];
6512         var out = [statementBuilder.toString()];
6513         if (min > expr.min) {
6514           out.unshift('Math.max(', min, ', ');
6515           out.push(')');
6516         }
6517         if (max < expr.max) {
6518           out.unshift('Math.min(', max, ', ');
6519           out.push(')');
6520         }
6521         out.unshift('dest[destOffset + ', i, '] = ');
6522         out.push(';');
6523         result.push(out.join(''));
6524       });
6525       return result.join('\n');
6526     }
6527   };
6528
6529   return PostScriptCompiler;
6530 })();
6531
6532
6533 var ColorSpace = (function ColorSpaceClosure() {
6534   // Constructor should define this.numComps, this.defaultColor, this.name
6535   function ColorSpace() {
6536     error('should not call ColorSpace constructor');
6537   }
6538
6539   ColorSpace.prototype = {
6540     /**
6541      * Converts the color value to the RGB color. The color components are
6542      * located in the src array starting from the srcOffset. Returns the array
6543      * of the rgb components, each value ranging from [0,255].
6544      */
6545     getRgb: function ColorSpace_getRgb(src, srcOffset) {
6546       var rgb = new Uint8Array(3);
6547       this.getRgbItem(src, srcOffset, rgb, 0);
6548       return rgb;
6549     },
6550     /**
6551      * Converts the color value to the RGB color, similar to the getRgb method.
6552      * The result placed into the dest array starting from the destOffset.
6553      */
6554     getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,
6555                                                dest, destOffset) {
6556       error('Should not call ColorSpace.getRgbItem');
6557     },
6558     /**
6559      * Converts the specified number of the color values to the RGB colors.
6560      * The colors are located in the src array starting from the srcOffset.
6561      * The result is placed into the dest array starting from the destOffset.
6562      * The src array items shall be in [0,2^bits) range, the dest array items
6563      * will be in [0,255] range. alpha01 indicates how many alpha components
6564      * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA
6565      * array).
6566      */
6567     getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
6568                                                    dest, destOffset, bits,
6569                                                    alpha01) {
6570       error('Should not call ColorSpace.getRgbBuffer');
6571     },
6572     /**
6573      * Determines the number of bytes required to store the result of the
6574      * conversion done by the getRgbBuffer method. As in getRgbBuffer,
6575      * |alpha01| is either 0 (RGB output) or 1 (RGBA output).
6576      */
6577     getOutputLength: function ColorSpace_getOutputLength(inputLength,
6578                                                          alpha01) {
6579       error('Should not call ColorSpace.getOutputLength');
6580     },
6581     /**
6582      * Returns true if source data will be equal the result/output data.
6583      */
6584     isPassthrough: function ColorSpace_isPassthrough(bits) {
6585       return false;
6586     },
6587     /**
6588      * Fills in the RGB colors in the destination buffer.  alpha01 indicates
6589      * how many alpha components there are in the dest array; it will be either
6590      * 0 (RGB array) or 1 (RGBA array).
6591      */
6592     fillRgb: function ColorSpace_fillRgb(dest, originalWidth,
6593                                          originalHeight, width, height,
6594                                          actualHeight, bpc, comps, alpha01) {
6595       var count = originalWidth * originalHeight;
6596       var rgbBuf = null;
6597       var numComponentColors = 1 << bpc;
6598       var needsResizing = originalHeight !== height || originalWidth !== width;
6599       var i, ii;
6600
6601       if (this.isPassthrough(bpc)) {
6602         rgbBuf = comps;
6603       } else if (this.numComps === 1 && count > numComponentColors &&
6604           this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
6605         // Optimization: create a color map when there is just one component and
6606         // we are converting more colors than the size of the color map. We
6607         // don't build the map if the colorspace is gray or rgb since those
6608         // methods are faster than building a map. This mainly offers big speed
6609         // ups for indexed and alternate colorspaces.
6610         //
6611         // TODO it may be worth while to cache the color map. While running
6612         // testing I never hit a cache so I will leave that out for now (perhaps
6613         // we are reparsing colorspaces too much?).
6614         var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) :
6615                                    new Uint16Array(numComponentColors);
6616         var key;
6617         for (i = 0; i < numComponentColors; i++) {
6618           allColors[i] = i;
6619         }
6620         var colorMap = new Uint8Array(numComponentColors * 3);
6621         this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,
6622                           /* alpha01 = */ 0);
6623
6624         var destPos, rgbPos;
6625         if (!needsResizing) {
6626           // Fill in the RGB values directly into |dest|.
6627           destPos = 0;
6628           for (i = 0; i < count; ++i) {
6629             key = comps[i] * 3;
6630             dest[destPos++] = colorMap[key];
6631             dest[destPos++] = colorMap[key + 1];
6632             dest[destPos++] = colorMap[key + 2];
6633             destPos += alpha01;
6634           }
6635         } else {
6636           rgbBuf = new Uint8Array(count * 3);
6637           rgbPos = 0;
6638           for (i = 0; i < count; ++i) {
6639             key = comps[i] * 3;
6640             rgbBuf[rgbPos++] = colorMap[key];
6641             rgbBuf[rgbPos++] = colorMap[key + 1];
6642             rgbBuf[rgbPos++] = colorMap[key + 2];
6643           }
6644         }
6645       } else {
6646         if (!needsResizing) {
6647           // Fill in the RGB values directly into |dest|.
6648           this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc,
6649                             alpha01);
6650         } else {
6651           rgbBuf = new Uint8Array(count * 3);
6652           this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc,
6653                             /* alpha01 = */ 0);
6654         }
6655       }
6656
6657       if (rgbBuf) {
6658         if (needsResizing) {
6659           PDFImage.resize(rgbBuf, bpc, 3, originalWidth, originalHeight, width,
6660                           height, dest, alpha01);
6661         } else {
6662           rgbPos = 0;
6663           destPos = 0;
6664           for (i = 0, ii = width * actualHeight; i < ii; i++) {
6665             dest[destPos++] = rgbBuf[rgbPos++];
6666             dest[destPos++] = rgbBuf[rgbPos++];
6667             dest[destPos++] = rgbBuf[rgbPos++];
6668             destPos += alpha01;
6669           }
6670         }
6671       }
6672     },
6673     /**
6674      * True if the colorspace has components in the default range of [0, 1].
6675      * This should be true for all colorspaces except for lab color spaces
6676      * which are [0,100], [-128, 127], [-128, 127].
6677      */
6678     usesZeroToOneRange: true
6679   };
6680
6681   ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
6682     var IR = ColorSpace.parseToIR(cs, xref, res);
6683     if (IR instanceof AlternateCS) {
6684       return IR;
6685     }
6686     return ColorSpace.fromIR(IR);
6687   };
6688
6689   ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
6690     var name = isArray(IR) ? IR[0] : IR;
6691     var whitePoint, blackPoint, gamma;
6692
6693     switch (name) {
6694       case 'DeviceGrayCS':
6695         return this.singletons.gray;
6696       case 'DeviceRgbCS':
6697         return this.singletons.rgb;
6698       case 'DeviceCmykCS':
6699         return this.singletons.cmyk;
6700       case 'CalGrayCS':
6701         whitePoint = IR[1].WhitePoint;
6702         blackPoint = IR[1].BlackPoint;
6703         gamma = IR[1].Gamma;
6704         return new CalGrayCS(whitePoint, blackPoint, gamma);
6705       case 'CalRGBCS':
6706         whitePoint = IR[1].WhitePoint;
6707         blackPoint = IR[1].BlackPoint;
6708         gamma = IR[1].Gamma;
6709         var matrix = IR[1].Matrix;
6710         return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
6711       case 'PatternCS':
6712         var basePatternCS = IR[1];
6713         if (basePatternCS) {
6714           basePatternCS = ColorSpace.fromIR(basePatternCS);
6715         }
6716         return new PatternCS(basePatternCS);
6717       case 'IndexedCS':
6718         var baseIndexedCS = IR[1];
6719         var hiVal = IR[2];
6720         var lookup = IR[3];
6721         return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
6722       case 'AlternateCS':
6723         var numComps = IR[1];
6724         var alt = IR[2];
6725         var tintFnIR = IR[3];
6726
6727         return new AlternateCS(numComps, ColorSpace.fromIR(alt),
6728                                 PDFFunction.fromIR(tintFnIR));
6729       case 'LabCS':
6730         whitePoint = IR[1].WhitePoint;
6731         blackPoint = IR[1].BlackPoint;
6732         var range = IR[1].Range;
6733         return new LabCS(whitePoint, blackPoint, range);
6734       default:
6735         error('Unknown name ' + name);
6736     }
6737     return null;
6738   };
6739
6740   ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
6741     if (isName(cs)) {
6742       var colorSpaces = res.get('ColorSpace');
6743       if (isDict(colorSpaces)) {
6744         var refcs = colorSpaces.get(cs.name);
6745         if (refcs) {
6746           cs = refcs;
6747         }
6748       }
6749     }
6750
6751     cs = xref.fetchIfRef(cs);
6752     var mode;
6753
6754     if (isName(cs)) {
6755       mode = cs.name;
6756       this.mode = mode;
6757
6758       switch (mode) {
6759         case 'DeviceGray':
6760         case 'G':
6761           return 'DeviceGrayCS';
6762         case 'DeviceRGB':
6763         case 'RGB':
6764           return 'DeviceRgbCS';
6765         case 'DeviceCMYK':
6766         case 'CMYK':
6767           return 'DeviceCmykCS';
6768         case 'Pattern':
6769           return ['PatternCS', null];
6770         default:
6771           error('unrecognized colorspace ' + mode);
6772       }
6773     } else if (isArray(cs)) {
6774       mode = cs[0].name;
6775       this.mode = mode;
6776       var numComps, params;
6777
6778       switch (mode) {
6779         case 'DeviceGray':
6780         case 'G':
6781           return 'DeviceGrayCS';
6782         case 'DeviceRGB':
6783         case 'RGB':
6784           return 'DeviceRgbCS';
6785         case 'DeviceCMYK':
6786         case 'CMYK':
6787           return 'DeviceCmykCS';
6788         case 'CalGray':
6789           params = xref.fetchIfRef(cs[1]).getAll();
6790           return ['CalGrayCS', params];
6791         case 'CalRGB':
6792           params = xref.fetchIfRef(cs[1]).getAll();
6793           return ['CalRGBCS', params];
6794         case 'ICCBased':
6795           var stream = xref.fetchIfRef(cs[1]);
6796           var dict = stream.dict;
6797           numComps = dict.get('N');
6798           if (numComps === 1) {
6799             return 'DeviceGrayCS';
6800           } else if (numComps === 3) {
6801             return 'DeviceRgbCS';
6802           } else if (numComps === 4) {
6803             return 'DeviceCmykCS';
6804           }
6805           break;
6806         case 'Pattern':
6807           var basePatternCS = cs[1];
6808           if (basePatternCS) {
6809             basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
6810           }
6811           return ['PatternCS', basePatternCS];
6812         case 'Indexed':
6813         case 'I':
6814           var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
6815           var hiVal = cs[2] + 1;
6816           var lookup = xref.fetchIfRef(cs[3]);
6817           if (isStream(lookup)) {
6818             lookup = lookup.getBytes();
6819           }
6820           return ['IndexedCS', baseIndexedCS, hiVal, lookup];
6821         case 'Separation':
6822         case 'DeviceN':
6823           var name = cs[1];
6824           numComps = 1;
6825           if (isName(name)) {
6826             numComps = 1;
6827           } else if (isArray(name)) {
6828             numComps = name.length;
6829           }
6830           var alt = ColorSpace.parseToIR(cs[2], xref, res);
6831           var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
6832           return ['AlternateCS', numComps, alt, tintFnIR];
6833         case 'Lab':
6834           params = cs[1].getAll();
6835           return ['LabCS', params];
6836         default:
6837           error('unimplemented color space object "' + mode + '"');
6838       }
6839     } else {
6840       error('unrecognized color space object: "' + cs + '"');
6841     }
6842     return null;
6843   };
6844   /**
6845    * Checks if a decode map matches the default decode map for a color space.
6846    * This handles the general decode maps where there are two values per
6847    * component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
6848    * This does not handle Lab, Indexed, or Pattern decode maps since they are
6849    * slightly different.
6850    * @param {Array} decode Decode map (usually from an image).
6851    * @param {Number} n Number of components the color space has.
6852    */
6853   ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
6854     if (!decode) {
6855       return true;
6856     }
6857
6858     if (n * 2 !== decode.length) {
6859       warn('The decode map is not the correct length');
6860       return true;
6861     }
6862     for (var i = 0, ii = decode.length; i < ii; i += 2) {
6863       if (decode[i] !== 0 || decode[i + 1] !== 1) {
6864         return false;
6865       }
6866     }
6867     return true;
6868   };
6869
6870   ColorSpace.singletons = {
6871     get gray() {
6872       return shadow(this, 'gray', new DeviceGrayCS());
6873     },
6874     get rgb() {
6875       return shadow(this, 'rgb', new DeviceRgbCS());
6876     },
6877     get cmyk() {
6878       return shadow(this, 'cmyk', new DeviceCmykCS());
6879     }
6880   };
6881
6882   return ColorSpace;
6883 })();
6884
6885 /**
6886  * Alternate color space handles both Separation and DeviceN color spaces.  A
6887  * Separation color space is actually just a DeviceN with one color component.
6888  * Both color spaces use a tinting function to convert colors to a base color
6889  * space.
6890  */
6891 var AlternateCS = (function AlternateCSClosure() {
6892   function AlternateCS(numComps, base, tintFn) {
6893     this.name = 'Alternate';
6894     this.numComps = numComps;
6895     this.defaultColor = new Float32Array(numComps);
6896     for (var i = 0; i < numComps; ++i) {
6897       this.defaultColor[i] = 1;
6898     }
6899     this.base = base;
6900     this.tintFn = tintFn;
6901     this.tmpBuf = new Float32Array(base.numComps);
6902   }
6903
6904   AlternateCS.prototype = {
6905     getRgb: ColorSpace.prototype.getRgb,
6906     getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
6907                                                 dest, destOffset) {
6908       var tmpBuf = this.tmpBuf;
6909       this.tintFn(src, srcOffset, tmpBuf, 0);
6910       this.base.getRgbItem(tmpBuf, 0, dest, destOffset);
6911     },
6912     getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
6913                                                     dest, destOffset, bits,
6914                                                     alpha01) {
6915       var tintFn = this.tintFn;
6916       var base = this.base;
6917       var scale = 1 / ((1 << bits) - 1);
6918       var baseNumComps = base.numComps;
6919       var usesZeroToOneRange = base.usesZeroToOneRange;
6920       var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) &&
6921                           alpha01 === 0;
6922       var pos = isPassthrough ? destOffset : 0;
6923       var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
6924       var numComps = this.numComps;
6925
6926       var scaled = new Float32Array(numComps);
6927       var tinted = new Float32Array(baseNumComps);
6928       var i, j;
6929       if (usesZeroToOneRange) {
6930         for (i = 0; i < count; i++) {
6931           for (j = 0; j < numComps; j++) {
6932             scaled[j] = src[srcOffset++] * scale;
6933           }
6934           tintFn(scaled, 0, tinted, 0);
6935           for (j = 0; j < baseNumComps; j++) {
6936             baseBuf[pos++] = tinted[j] * 255;
6937           }
6938         }
6939       } else {
6940         for (i = 0; i < count; i++) {
6941           for (j = 0; j < numComps; j++) {
6942             scaled[j] = src[srcOffset++] * scale;
6943           }
6944           tintFn(scaled, 0, tinted, 0);
6945           base.getRgbItem(tinted, 0, baseBuf, pos);
6946           pos += baseNumComps;
6947         }
6948       }
6949       if (!isPassthrough) {
6950         base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
6951       }
6952     },
6953     getOutputLength: function AlternateCS_getOutputLength(inputLength,
6954                                                           alpha01) {
6955       return this.base.getOutputLength(inputLength *
6956                                        this.base.numComps / this.numComps,
6957                                        alpha01);
6958     },
6959     isPassthrough: ColorSpace.prototype.isPassthrough,
6960     fillRgb: ColorSpace.prototype.fillRgb,
6961     isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
6962       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
6963     },
6964     usesZeroToOneRange: true
6965   };
6966
6967   return AlternateCS;
6968 })();
6969
6970 var PatternCS = (function PatternCSClosure() {
6971   function PatternCS(baseCS) {
6972     this.name = 'Pattern';
6973     this.base = baseCS;
6974   }
6975   PatternCS.prototype = {};
6976
6977   return PatternCS;
6978 })();
6979
6980 var IndexedCS = (function IndexedCSClosure() {
6981   function IndexedCS(base, highVal, lookup) {
6982     this.name = 'Indexed';
6983     this.numComps = 1;
6984     this.defaultColor = new Uint8Array([0]);
6985     this.base = base;
6986     this.highVal = highVal;
6987
6988     var baseNumComps = base.numComps;
6989     var length = baseNumComps * highVal;
6990     var lookupArray;
6991
6992     if (isStream(lookup)) {
6993       lookupArray = new Uint8Array(length);
6994       var bytes = lookup.getBytes(length);
6995       lookupArray.set(bytes);
6996     } else if (isString(lookup)) {
6997       lookupArray = new Uint8Array(length);
6998       for (var i = 0; i < length; ++i) {
6999         lookupArray[i] = lookup.charCodeAt(i);
7000       }
7001     } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
7002       lookupArray = lookup;
7003     } else {
7004       error('Unrecognized lookup table: ' + lookup);
7005     }
7006     this.lookup = lookupArray;
7007   }
7008
7009   IndexedCS.prototype = {
7010     getRgb: ColorSpace.prototype.getRgb,
7011     getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
7012                                               dest, destOffset) {
7013       var numComps = this.base.numComps;
7014       var start = src[srcOffset] * numComps;
7015       this.base.getRgbItem(this.lookup, start, dest, destOffset);
7016     },
7017     getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
7018                                                   dest, destOffset, bits,
7019                                                   alpha01) {
7020       var base = this.base;
7021       var numComps = base.numComps;
7022       var outputDelta = base.getOutputLength(numComps, alpha01);
7023       var lookup = this.lookup;
7024
7025       for (var i = 0; i < count; ++i) {
7026         var lookupPos = src[srcOffset++] * numComps;
7027         base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
7028         destOffset += outputDelta;
7029       }
7030     },
7031     getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
7032       return this.base.getOutputLength(inputLength * this.base.numComps,
7033                                        alpha01);
7034     },
7035     isPassthrough: ColorSpace.prototype.isPassthrough,
7036     fillRgb: ColorSpace.prototype.fillRgb,
7037     isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
7038       // indexed color maps shouldn't be changed
7039       return true;
7040     },
7041     usesZeroToOneRange: true
7042   };
7043   return IndexedCS;
7044 })();
7045
7046 var DeviceGrayCS = (function DeviceGrayCSClosure() {
7047   function DeviceGrayCS() {
7048     this.name = 'DeviceGray';
7049     this.numComps = 1;
7050     this.defaultColor = new Float32Array([0]);
7051   }
7052
7053   DeviceGrayCS.prototype = {
7054     getRgb: ColorSpace.prototype.getRgb,
7055     getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
7056                                                  dest, destOffset) {
7057       var c = (src[srcOffset] * 255) | 0;
7058       c = c < 0 ? 0 : c > 255 ? 255 : c;
7059       dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
7060     },
7061     getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
7062                                                      dest, destOffset, bits,
7063                                                      alpha01) {
7064       var scale = 255 / ((1 << bits) - 1);
7065       var j = srcOffset, q = destOffset;
7066       for (var i = 0; i < count; ++i) {
7067         var c = (scale * src[j++]) | 0;
7068         dest[q++] = c;
7069         dest[q++] = c;
7070         dest[q++] = c;
7071         q += alpha01;
7072       }
7073     },
7074     getOutputLength: function DeviceGrayCS_getOutputLength(inputLength,
7075                                                            alpha01) {
7076       return inputLength * (3 + alpha01);
7077     },
7078     isPassthrough: ColorSpace.prototype.isPassthrough,
7079     fillRgb: ColorSpace.prototype.fillRgb,
7080     isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
7081       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7082     },
7083     usesZeroToOneRange: true
7084   };
7085   return DeviceGrayCS;
7086 })();
7087
7088 var DeviceRgbCS = (function DeviceRgbCSClosure() {
7089   function DeviceRgbCS() {
7090     this.name = 'DeviceRGB';
7091     this.numComps = 3;
7092     this.defaultColor = new Float32Array([0, 0, 0]);
7093   }
7094   DeviceRgbCS.prototype = {
7095     getRgb: ColorSpace.prototype.getRgb,
7096     getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
7097                                                 dest, destOffset) {
7098       var r = (src[srcOffset] * 255) | 0;
7099       var g = (src[srcOffset + 1] * 255) | 0;
7100       var b = (src[srcOffset + 2] * 255) | 0;
7101       dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
7102       dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
7103       dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
7104     },
7105     getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
7106                                                     dest, destOffset, bits,
7107                                                     alpha01) {
7108       if (bits === 8 && alpha01 === 0) {
7109         dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
7110         return;
7111       }
7112       var scale = 255 / ((1 << bits) - 1);
7113       var j = srcOffset, q = destOffset;
7114       for (var i = 0; i < count; ++i) {
7115         dest[q++] = (scale * src[j++]) | 0;
7116         dest[q++] = (scale * src[j++]) | 0;
7117         dest[q++] = (scale * src[j++]) | 0;
7118         q += alpha01;
7119       }
7120     },
7121     getOutputLength: function DeviceRgbCS_getOutputLength(inputLength,
7122                                                           alpha01) {
7123       return (inputLength * (3 + alpha01) / 3) | 0;
7124     },
7125     isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
7126       return bits === 8;
7127     },
7128     fillRgb: ColorSpace.prototype.fillRgb,
7129     isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
7130       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7131     },
7132     usesZeroToOneRange: true
7133   };
7134   return DeviceRgbCS;
7135 })();
7136
7137 var DeviceCmykCS = (function DeviceCmykCSClosure() {
7138   // The coefficients below was found using numerical analysis: the method of
7139   // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
7140   // where color_value is the tabular value from the table of sampled RGB colors
7141   // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
7142   // CMYK color conversion using the estimation below:
7143   //   f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
7144   function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
7145     var c = src[srcOffset + 0] * srcScale;
7146     var m = src[srcOffset + 1] * srcScale;
7147     var y = src[srcOffset + 2] * srcScale;
7148     var k = src[srcOffset + 3] * srcScale;
7149
7150     var r =
7151       (c * (-4.387332384609988 * c + 54.48615194189176 * m +
7152             18.82290502165302 * y + 212.25662451639585 * k +
7153             -285.2331026137004) +
7154        m * (1.7149763477362134 * m - 5.6096736904047315 * y +
7155             -17.873870861415444 * k - 5.497006427196366) +
7156        y * (-2.5217340131683033 * y - 21.248923337353073 * k +
7157             17.5119270841813) +
7158        k * (-21.86122147463605 * k - 189.48180835922747) + 255) | 0;
7159     var g =
7160       (c * (8.841041422036149 * c + 60.118027045597366 * m +
7161             6.871425592049007 * y + 31.159100130055922 * k +
7162             -79.2970844816548) +
7163        m * (-15.310361306967817 * m + 17.575251261109482 * y +
7164             131.35250912493976 * k - 190.9453302588951) +
7165        y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
7166        k * (-20.737325471181034 * k - 187.80453709719578) + 255) | 0;
7167     var b =
7168       (c * (0.8842522430003296 * c + 8.078677503112928 * m +
7169             30.89978309703729 * y - 0.23883238689178934 * k +
7170             -14.183576799673286) +
7171        m * (10.49593273432072 * m + 63.02378494754052 * y +
7172             50.606957656360734 * k - 112.23884253719248) +
7173        y * (0.03296041114873217 * y + 115.60384449646641 * k +
7174             -193.58209356861505) +
7175        k * (-22.33816807309886 * k - 180.12613974708367) + 255) | 0;
7176
7177     dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
7178     dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
7179     dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
7180   }
7181
7182   function DeviceCmykCS() {
7183     this.name = 'DeviceCMYK';
7184     this.numComps = 4;
7185     this.defaultColor = new Float32Array([0, 0, 0, 1]);
7186   }
7187   DeviceCmykCS.prototype = {
7188     getRgb: ColorSpace.prototype.getRgb,
7189     getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
7190                                                  dest, destOffset) {
7191       convertToRgb(src, srcOffset, 1, dest, destOffset);
7192     },
7193     getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
7194                                                      dest, destOffset, bits,
7195                                                      alpha01) {
7196       var scale = 1 / ((1 << bits) - 1);
7197       for (var i = 0; i < count; i++) {
7198         convertToRgb(src, srcOffset, scale, dest, destOffset);
7199         srcOffset += 4;
7200         destOffset += 3 + alpha01;
7201       }
7202     },
7203     getOutputLength: function DeviceCmykCS_getOutputLength(inputLength,
7204                                                            alpha01) {
7205       return (inputLength / 4 * (3 + alpha01)) | 0;
7206     },
7207     isPassthrough: ColorSpace.prototype.isPassthrough,
7208     fillRgb: ColorSpace.prototype.fillRgb,
7209     isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
7210       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7211     },
7212     usesZeroToOneRange: true
7213   };
7214
7215   return DeviceCmykCS;
7216 })();
7217
7218 //
7219 // CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245
7220 //
7221 var CalGrayCS = (function CalGrayCSClosure() {
7222   function CalGrayCS(whitePoint, blackPoint, gamma) {
7223     this.name = 'CalGray';
7224     this.numComps = 1;
7225     this.defaultColor = new Float32Array([0]);
7226
7227     if (!whitePoint) {
7228       error('WhitePoint missing - required for color space CalGray');
7229     }
7230     blackPoint = blackPoint || [0, 0, 0];
7231     gamma = gamma || 1;
7232
7233     // Translate arguments to spec variables.
7234     this.XW = whitePoint[0];
7235     this.YW = whitePoint[1];
7236     this.ZW = whitePoint[2];
7237
7238     this.XB = blackPoint[0];
7239     this.YB = blackPoint[1];
7240     this.ZB = blackPoint[2];
7241
7242     this.G = gamma;
7243
7244     // Validate variables as per spec.
7245     if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
7246       error('Invalid WhitePoint components for ' + this.name +
7247             ', no fallback available');
7248     }
7249
7250     if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
7251       info('Invalid BlackPoint for ' + this.name + ', falling back to default');
7252       this.XB = this.YB = this.ZB = 0;
7253     }
7254
7255     if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
7256       warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +
7257            ', ZB: ' + this.ZB + ', only default values are supported.');
7258     }
7259
7260     if (this.G < 1) {
7261       info('Invalid Gamma: ' + this.G + ' for ' + this.name +
7262            ', falling back to default');
7263       this.G = 1;
7264     }
7265   }
7266
7267   function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
7268     // A represents a gray component of a calibrated gray space.
7269     // A <---> AG in the spec
7270     var A = src[srcOffset] * scale;
7271     var AG = Math.pow(A, cs.G);
7272
7273     // Computes L as per spec. ( = cs.YW * AG )
7274     // Except if other than default BlackPoint values are used.
7275     var L = cs.YW * AG;
7276     // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.
7277     // Convert values to rgb range [0, 255].
7278     var val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0) | 0;
7279     dest[destOffset] = val;
7280     dest[destOffset + 1] = val;
7281     dest[destOffset + 2] = val;
7282   }
7283
7284   CalGrayCS.prototype = {
7285     getRgb: ColorSpace.prototype.getRgb,
7286     getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
7287                                               dest, destOffset) {
7288       convertToRgb(this, src, srcOffset, dest, destOffset, 1);
7289     },
7290     getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
7291                                                   dest, destOffset, bits,
7292                                                   alpha01) {
7293       var scale = 1 / ((1 << bits) - 1);
7294
7295       for (var i = 0; i < count; ++i) {
7296         convertToRgb(this, src, srcOffset, dest, destOffset, scale);
7297         srcOffset += 1;
7298         destOffset += 3 + alpha01;
7299       }
7300     },
7301     getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
7302       return inputLength * (3 + alpha01);
7303     },
7304     isPassthrough: ColorSpace.prototype.isPassthrough,
7305     fillRgb: ColorSpace.prototype.fillRgb,
7306     isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
7307       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7308     },
7309     usesZeroToOneRange: true
7310   };
7311   return CalGrayCS;
7312 })();
7313
7314 //
7315 // CalRGBCS: Based on "PDF Reference, Sixth Ed", p.247
7316 //
7317 var CalRGBCS = (function CalRGBCSClosure() {
7318
7319   // See http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html for these
7320   // matrices.
7321   var BRADFORD_SCALE_MATRIX = new Float32Array([
7322     0.8951, 0.2664, -0.1614,
7323     -0.7502, 1.7135, 0.0367,
7324     0.0389, -0.0685, 1.0296]);
7325
7326   var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([
7327     0.9869929, -0.1470543, 0.1599627,
7328     0.4323053, 0.5183603, 0.0492912,
7329     -0.0085287, 0.0400428, 0.9684867]);
7330
7331   // See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html.
7332   var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([
7333     3.2404542, -1.5371385, -0.4985314,
7334     -0.9692660, 1.8760108, 0.0415560,
7335     0.0556434, -0.2040259, 1.0572252]);
7336
7337   var FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]);
7338
7339   var tempNormalizeMatrix = new Float32Array(3);
7340   var tempConvertMatrix1 = new Float32Array(3);
7341   var tempConvertMatrix2 = new Float32Array(3);
7342
7343   var DECODE_L_CONSTANT = Math.pow(((8 + 16) / 116), 3) / 8.0;
7344
7345   function CalRGBCS(whitePoint, blackPoint, gamma, matrix) {
7346     this.name = 'CalRGB';
7347     this.numComps = 3;
7348     this.defaultColor = new Float32Array(3);
7349
7350     if (!whitePoint) {
7351       error('WhitePoint missing - required for color space CalRGB');
7352     }
7353     blackPoint = blackPoint || new Float32Array(3);
7354     gamma = gamma || new Float32Array([1, 1, 1]);
7355     matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
7356
7357     // Translate arguments to spec variables.
7358     var XW = whitePoint[0];
7359     var YW = whitePoint[1];
7360     var ZW = whitePoint[2];
7361     this.whitePoint = whitePoint;
7362
7363     var XB = blackPoint[0];
7364     var YB = blackPoint[1];
7365     var ZB = blackPoint[2];
7366     this.blackPoint = blackPoint;
7367
7368     this.GR = gamma[0];
7369     this.GG = gamma[1];
7370     this.GB = gamma[2];
7371
7372     this.MXA = matrix[0];
7373     this.MYA = matrix[1];
7374     this.MZA = matrix[2];
7375     this.MXB = matrix[3];
7376     this.MYB = matrix[4];
7377     this.MZB = matrix[5];
7378     this.MXC = matrix[6];
7379     this.MYC = matrix[7];
7380     this.MZC = matrix[8];
7381
7382     // Validate variables as per spec.
7383     if (XW < 0 || ZW < 0 || YW !== 1) {
7384       error('Invalid WhitePoint components for ' + this.name +
7385             ', no fallback available');
7386     }
7387
7388     if (XB < 0 || YB < 0 || ZB < 0) {
7389       info('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB +
7390            ', ' + ZB + '], falling back to default');
7391       this.blackPoint = new Float32Array(3);
7392     }
7393
7394     if (this.GR < 0 || this.GG < 0 || this.GB < 0) {
7395       info('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB +
7396            '] for ' + this.name + ', falling back to default');
7397       this.GR = this.GG = this.GB = 1;
7398     }
7399
7400     if (this.MXA < 0 || this.MYA < 0 || this.MZA < 0 ||
7401         this.MXB < 0 || this.MYB < 0 || this.MZB < 0 ||
7402         this.MXC < 0 || this.MYC < 0 || this.MZC < 0) {
7403       info('Invalid Matrix for ' + this.name + ' [' +
7404            this.MXA + ', ' + this.MYA + ', ' + this.MZA +
7405            this.MXB + ', ' + this.MYB + ', ' + this.MZB +
7406            this.MXC + ', ' + this.MYC + ', ' + this.MZC +
7407            '], falling back to default');
7408       this.MXA = this.MYB = this.MZC = 1;
7409       this.MXB = this.MYA = this.MZA = this.MXC = this.MYC = this.MZB = 0;
7410     }
7411   }
7412
7413   function matrixProduct(a, b, result) {
7414       result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
7415       result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2];
7416       result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2];
7417   }
7418
7419   function convertToFlat(sourceWhitePoint, LMS, result) {
7420       result[0] = LMS[0] * 1 / sourceWhitePoint[0];
7421       result[1] = LMS[1] * 1 / sourceWhitePoint[1];
7422       result[2] = LMS[2] * 1 / sourceWhitePoint[2];
7423   }
7424
7425   function convertToD65(sourceWhitePoint, LMS, result) {
7426     var D65X = 0.95047;
7427     var D65Y = 1;
7428     var D65Z = 1.08883;
7429
7430     result[0] = LMS[0] * D65X / sourceWhitePoint[0];
7431     result[1] = LMS[1] * D65Y / sourceWhitePoint[1];
7432     result[2] = LMS[2] * D65Z / sourceWhitePoint[2];
7433   }
7434
7435   function sRGBTransferFunction(color) {
7436     // See http://en.wikipedia.org/wiki/SRGB.
7437     if (color <= 0.0031308){
7438       return adjustToRange(0, 1, 12.92 * color);
7439     }
7440
7441     return adjustToRange(0, 1, (1 + 0.055) * Math.pow(color, 1 / 2.4) - 0.055);
7442   }
7443
7444   function adjustToRange(min, max, value) {
7445     return Math.max(min, Math.min(max, value));
7446   }
7447
7448   function decodeL(L) {
7449     if (L < 0) {
7450       return -decodeL(-L);
7451     }
7452
7453     if (L > 8.0) {
7454       return Math.pow(((L + 16) / 116), 3);
7455     }
7456
7457     return L * DECODE_L_CONSTANT;
7458   }
7459
7460   function compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) {
7461
7462     // In case the blackPoint is already the default blackPoint then there is
7463     // no need to do compensation.
7464     if (sourceBlackPoint[0] === 0 &&
7465         sourceBlackPoint[1] === 0 &&
7466         sourceBlackPoint[2] === 0) {
7467       result[0] = XYZ_Flat[0];
7468       result[1] = XYZ_Flat[1];
7469       result[2] = XYZ_Flat[2];
7470       return;
7471     }
7472
7473     // For the blackPoint calculation details, please see
7474     // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/
7475     // AdobeBPC.pdf.
7476     // The destination blackPoint is the default blackPoint [0, 0, 0].
7477     var zeroDecodeL = decodeL(0);
7478
7479     var X_DST = zeroDecodeL;
7480     var X_SRC = decodeL(sourceBlackPoint[0]);
7481
7482     var Y_DST = zeroDecodeL;
7483     var Y_SRC = decodeL(sourceBlackPoint[1]);
7484
7485     var Z_DST = zeroDecodeL;
7486     var Z_SRC = decodeL(sourceBlackPoint[2]);
7487
7488     var X_Scale = (1 - X_DST) / (1 - X_SRC);
7489     var X_Offset = 1 - X_Scale;
7490
7491     var Y_Scale = (1 - Y_DST) / (1 - Y_SRC);
7492     var Y_Offset = 1 - Y_Scale;
7493
7494     var Z_Scale = (1 - Z_DST) / (1 - Z_SRC);
7495     var Z_Offset = 1 - Z_Scale;
7496
7497     result[0] = XYZ_Flat[0] * X_Scale + X_Offset;
7498     result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset;
7499     result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset;
7500   }
7501
7502   function normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) {
7503
7504     // In case the whitePoint is already flat then there is no need to do
7505     // normalization.
7506     if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) {
7507       result[0] = XYZ_In[0];
7508       result[1] = XYZ_In[1];
7509       result[2] = XYZ_In[2];
7510       return;
7511     }
7512
7513     var LMS = result;
7514     matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
7515
7516     var LMS_Flat = tempNormalizeMatrix;
7517     convertToFlat(sourceWhitePoint, LMS, LMS_Flat);
7518
7519     matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result);
7520   }
7521
7522   function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) {
7523
7524     var LMS = result;
7525     matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
7526
7527     var LMS_D65 = tempNormalizeMatrix;
7528     convertToD65(sourceWhitePoint, LMS, LMS_D65);
7529
7530     matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result);
7531   }
7532
7533   function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
7534     // A, B and C represent a red, green and blue components of a calibrated
7535     // rgb space.
7536     var A = adjustToRange(0, 1, src[srcOffset] * scale);
7537     var B = adjustToRange(0, 1, src[srcOffset + 1] * scale);
7538     var C = adjustToRange(0, 1, src[srcOffset + 2] * scale);
7539
7540     // A <---> AGR in the spec
7541     // B <---> BGG in the spec
7542     // C <---> CGB in the spec
7543     var AGR = Math.pow(A, cs.GR);
7544     var BGG = Math.pow(B, cs.GG);
7545     var CGB = Math.pow(C, cs.GB);
7546
7547     // Computes intermediate variables L, M, N as per spec.
7548     // To decode X, Y, Z values map L, M, N directly to them.
7549     var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB;
7550     var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB;
7551     var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB;
7552
7553     // The following calculations are based on this document:
7554     // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/
7555     // AdobeBPC.pdf.
7556     var XYZ = tempConvertMatrix1;
7557     XYZ[0] = X;
7558     XYZ[1] = Y;
7559     XYZ[2] = Z;
7560     var XYZ_Flat = tempConvertMatrix2;
7561
7562     normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat);
7563
7564     var XYZ_Black = tempConvertMatrix1;
7565     compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black);
7566
7567     var XYZ_D65 = tempConvertMatrix2;
7568     normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65);
7569
7570     var SRGB = tempConvertMatrix1;
7571     matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB);
7572
7573     var sR = sRGBTransferFunction(SRGB[0]);
7574     var sG = sRGBTransferFunction(SRGB[1]);
7575     var sB = sRGBTransferFunction(SRGB[2]);
7576
7577     // Convert the values to rgb range [0, 255].
7578     dest[destOffset] = Math.round(sR * 255);
7579     dest[destOffset + 1] = Math.round(sG * 255);
7580     dest[destOffset + 2] = Math.round(sB * 255);
7581   }
7582
7583   CalRGBCS.prototype = {
7584     getRgb: function CalRGBCS_getRgb(src, srcOffset) {
7585       var rgb = new Uint8Array(3);
7586       this.getRgbItem(src, srcOffset, rgb, 0);
7587       return rgb;
7588     },
7589     getRgbItem: function CalRGBCS_getRgbItem(src, srcOffset,
7590                                              dest, destOffset) {
7591       convertToRgb(this, src, srcOffset, dest, destOffset, 1);
7592     },
7593     getRgbBuffer: function CalRGBCS_getRgbBuffer(src, srcOffset, count,
7594                                                  dest, destOffset, bits,
7595                                                  alpha01) {
7596       var scale = 1 / ((1 << bits) - 1);
7597
7598       for (var i = 0; i < count; ++i) {
7599         convertToRgb(this, src, srcOffset, dest, destOffset, scale);
7600         srcOffset += 3;
7601         destOffset += 3 + alpha01;
7602       }
7603     },
7604     getOutputLength: function CalRGBCS_getOutputLength(inputLength, alpha01) {
7605       return (inputLength * (3 + alpha01) / 3) | 0;
7606     },
7607     isPassthrough: ColorSpace.prototype.isPassthrough,
7608     fillRgb: ColorSpace.prototype.fillRgb,
7609     isDefaultDecode: function CalRGBCS_isDefaultDecode(decodeMap) {
7610       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7611     },
7612     usesZeroToOneRange: true
7613   };
7614   return CalRGBCS;
7615 })();
7616
7617 //
7618 // LabCS: Based on "PDF Reference, Sixth Ed", p.250
7619 //
7620 var LabCS = (function LabCSClosure() {
7621   function LabCS(whitePoint, blackPoint, range) {
7622     this.name = 'Lab';
7623     this.numComps = 3;
7624     this.defaultColor = new Float32Array([0, 0, 0]);
7625
7626     if (!whitePoint) {
7627       error('WhitePoint missing - required for color space Lab');
7628     }
7629     blackPoint = blackPoint || [0, 0, 0];
7630     range = range || [-100, 100, -100, 100];
7631
7632     // Translate args to spec variables
7633     this.XW = whitePoint[0];
7634     this.YW = whitePoint[1];
7635     this.ZW = whitePoint[2];
7636     this.amin = range[0];
7637     this.amax = range[1];
7638     this.bmin = range[2];
7639     this.bmax = range[3];
7640
7641     // These are here just for completeness - the spec doesn't offer any
7642     // formulas that use BlackPoint in Lab
7643     this.XB = blackPoint[0];
7644     this.YB = blackPoint[1];
7645     this.ZB = blackPoint[2];
7646
7647     // Validate vars as per spec
7648     if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
7649       error('Invalid WhitePoint components, no fallback available');
7650     }
7651
7652     if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
7653       info('Invalid BlackPoint, falling back to default');
7654       this.XB = this.YB = this.ZB = 0;
7655     }
7656
7657     if (this.amin > this.amax || this.bmin > this.bmax) {
7658       info('Invalid Range, falling back to defaults');
7659       this.amin = -100;
7660       this.amax = 100;
7661       this.bmin = -100;
7662       this.bmax = 100;
7663     }
7664   }
7665
7666   // Function g(x) from spec
7667   function fn_g(x) {
7668     if (x >= 6 / 29) {
7669       return x * x * x;
7670     } else {
7671       return (108 / 841) * (x - 4 / 29);
7672     }
7673   }
7674
7675   function decode(value, high1, low2, high2) {
7676     return low2 + (value) * (high2 - low2) / (high1);
7677   }
7678
7679   // If decoding is needed maxVal should be 2^bits per component - 1.
7680   function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
7681     // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]
7682     // not the usual [0, 1]. If a command like setFillColor is used the src
7683     // values will already be within the correct range. However, if we are
7684     // converting an image we have to map the values to the correct range given
7685     // above.
7686     // Ls,as,bs <---> L*,a*,b* in the spec
7687     var Ls = src[srcOffset];
7688     var as = src[srcOffset + 1];
7689     var bs = src[srcOffset + 2];
7690     if (maxVal !== false) {
7691       Ls = decode(Ls, maxVal, 0, 100);
7692       as = decode(as, maxVal, cs.amin, cs.amax);
7693       bs = decode(bs, maxVal, cs.bmin, cs.bmax);
7694     }
7695
7696     // Adjust limits of 'as' and 'bs'
7697     as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
7698     bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs;
7699
7700     // Computes intermediate variables X,Y,Z as per spec
7701     var M = (Ls + 16) / 116;
7702     var L = M + (as / 500);
7703     var N = M - (bs / 200);
7704
7705     var X = cs.XW * fn_g(L);
7706     var Y = cs.YW * fn_g(M);
7707     var Z = cs.ZW * fn_g(N);
7708
7709     var r, g, b;
7710     // Using different conversions for D50 and D65 white points,
7711     // per http://www.color.org/srgb.pdf
7712     if (cs.ZW < 1) {
7713       // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
7714       r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
7715       g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
7716       b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
7717     } else {
7718       // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
7719       r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
7720       g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
7721       b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
7722     }
7723     // clamp color values to [0,1] range then convert to [0,255] range.
7724     dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0;
7725     dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0;
7726     dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0;
7727   }
7728
7729   LabCS.prototype = {
7730     getRgb: ColorSpace.prototype.getRgb,
7731     getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
7732       convertToRgb(this, src, srcOffset, false, dest, destOffset);
7733     },
7734     getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,
7735                                               dest, destOffset, bits,
7736                                               alpha01) {
7737       var maxVal = (1 << bits) - 1;
7738       for (var i = 0; i < count; i++) {
7739         convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
7740         srcOffset += 3;
7741         destOffset += 3 + alpha01;
7742       }
7743     },
7744     getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {
7745       return (inputLength * (3 + alpha01) / 3) | 0;
7746     },
7747     isPassthrough: ColorSpace.prototype.isPassthrough,
7748     fillRgb: ColorSpace.prototype.fillRgb,
7749     isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
7750       // XXX: Decoding is handled with the lab conversion because of the strange
7751       // ranges that are used.
7752       return true;
7753     },
7754     usesZeroToOneRange: false
7755   };
7756   return LabCS;
7757 })();
7758
7759
7760 var ARCFourCipher = (function ARCFourCipherClosure() {
7761   function ARCFourCipher(key) {
7762     this.a = 0;
7763     this.b = 0;
7764     var s = new Uint8Array(256);
7765     var i, j = 0, tmp, keyLength = key.length;
7766     for (i = 0; i < 256; ++i) {
7767       s[i] = i;
7768     }
7769     for (i = 0; i < 256; ++i) {
7770       tmp = s[i];
7771       j = (j + tmp + key[i % keyLength]) & 0xFF;
7772       s[i] = s[j];
7773       s[j] = tmp;
7774     }
7775     this.s = s;
7776   }
7777
7778   ARCFourCipher.prototype = {
7779     encryptBlock: function ARCFourCipher_encryptBlock(data) {
7780       var i, n = data.length, tmp, tmp2;
7781       var a = this.a, b = this.b, s = this.s;
7782       var output = new Uint8Array(n);
7783       for (i = 0; i < n; ++i) {
7784         a = (a + 1) & 0xFF;
7785         tmp = s[a];
7786         b = (b + tmp) & 0xFF;
7787         tmp2 = s[b];
7788         s[a] = tmp2;
7789         s[b] = tmp;
7790         output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF];
7791       }
7792       this.a = a;
7793       this.b = b;
7794       return output;
7795     }
7796   };
7797   ARCFourCipher.prototype.decryptBlock = ARCFourCipher.prototype.encryptBlock;
7798
7799   return ARCFourCipher;
7800 })();
7801
7802 var calculateMD5 = (function calculateMD5Closure() {
7803   var r = new Uint8Array([
7804     7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
7805     5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
7806     4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
7807     6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);
7808
7809   var k = new Int32Array([
7810     -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
7811     -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
7812     1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
7813     643717713, -373897302, -701558691, 38016083, -660478335, -405537848,
7814     568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784,
7815     1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556,
7816     -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222,
7817     -722521979, 76029189, -640364487, -421815835, 530742520, -995338651,
7818     -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606,
7819     -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649,
7820     -145523070, -1120210379, 718787259, -343485551]);
7821
7822   function hash(data, offset, length) {
7823     var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878;
7824     // pre-processing
7825     var paddedLength = (length + 72) & ~63; // data + 9 extra bytes
7826     var padded = new Uint8Array(paddedLength);
7827     var i, j, n;
7828     for (i = 0; i < length; ++i) {
7829       padded[i] = data[offset++];
7830     }
7831     padded[i++] = 0x80;
7832     n = paddedLength - 8;
7833     while (i < n) {
7834       padded[i++] = 0;
7835     }
7836     padded[i++] = (length << 3) & 0xFF;
7837     padded[i++] = (length >> 5) & 0xFF;
7838     padded[i++] = (length >> 13) & 0xFF;
7839     padded[i++] = (length >> 21) & 0xFF;
7840     padded[i++] = (length >>> 29) & 0xFF;
7841     padded[i++] = 0;
7842     padded[i++] = 0;
7843     padded[i++] = 0;
7844     var w = new Int32Array(16);
7845     for (i = 0; i < paddedLength;) {
7846       for (j = 0; j < 16; ++j, i += 4) {
7847         w[j] = (padded[i] | (padded[i + 1] << 8) |
7848                (padded[i + 2] << 16) | (padded[i + 3] << 24));
7849       }
7850       var a = h0, b = h1, c = h2, d = h3, f, g;
7851       for (j = 0; j < 64; ++j) {
7852         if (j < 16) {
7853           f = (b & c) | ((~b) & d);
7854           g = j;
7855         } else if (j < 32) {
7856           f = (d & b) | ((~d) & c);
7857           g = (5 * j + 1) & 15;
7858         } else if (j < 48) {
7859           f = b ^ c ^ d;
7860           g = (3 * j + 5) & 15;
7861         } else {
7862           f = c ^ (b | (~d));
7863           g = (7 * j) & 15;
7864         }
7865         var tmp = d, rotateArg = (a + f + k[j] + w[g]) | 0, rotate = r[j];
7866         d = c;
7867         c = b;
7868         b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0;
7869         a = tmp;
7870       }
7871       h0 = (h0 + a) | 0;
7872       h1 = (h1 + b) | 0;
7873       h2 = (h2 + c) | 0;
7874       h3 = (h3 + d) | 0;
7875     }
7876     return new Uint8Array([
7877       h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF,
7878       h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF,
7879       h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF,
7880       h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF
7881     ]);
7882   }
7883
7884   return hash;
7885 })();
7886 var Word64 = (function Word64Closure() {
7887   function Word64(highInteger, lowInteger) {
7888     this.high = highInteger | 0;
7889     this.low = lowInteger | 0;
7890   }
7891   Word64.prototype = {
7892     and: function Word64_and(word) {
7893       this.high &= word.high;
7894       this.low &= word.low;
7895     },
7896     xor: function Word64_xor(word) {
7897      this.high ^= word.high;
7898      this.low ^= word.low;
7899     },
7900
7901     or: function Word64_or(word) {
7902       this.high |= word.high;
7903       this.low |= word.low;
7904     },
7905
7906     shiftRight: function Word64_shiftRight(places) {
7907       if (places >= 32) {
7908         this.low = (this.high >>> (places - 32)) | 0;
7909         this.high = 0;
7910       } else {
7911         this.low = (this.low >>> places) | (this.high << (32 - places));
7912         this.high = (this.high >>> places) | 0;
7913       }
7914     },
7915
7916     shiftLeft: function Word64_shiftLeft(places) {
7917       if (places >= 32) {
7918         this.high = this.low << (places - 32);
7919         this.low = 0;
7920       } else {
7921         this.high = (this.high << places) | (this.low >>> (32 - places));
7922         this.low = this.low << places;
7923       }
7924     },
7925
7926     rotateRight: function Word64_rotateRight(places) {
7927       var low, high;
7928       if (places & 32) {
7929         high = this.low;
7930         low = this.high;
7931       } else {
7932         low = this.low;
7933         high = this.high;
7934       }
7935       places &= 31;
7936       this.low = (low >>> places) | (high << (32 - places));
7937       this.high = (high >>> places) | (low << (32 - places));
7938     },
7939
7940     not: function Word64_not() {
7941       this.high = ~this.high;
7942       this.low = ~this.low;
7943     },
7944
7945     add: function Word64_add(word) {
7946       var lowAdd = (this.low >>> 0) + (word.low >>> 0);
7947       var highAdd = (this.high >>> 0) + (word.high >>> 0);
7948       if (lowAdd > 0xFFFFFFFF) {
7949         highAdd += 1;
7950       }
7951       this.low = lowAdd | 0;
7952       this.high = highAdd | 0;
7953     },
7954
7955     copyTo: function Word64_copyTo(bytes, offset) {
7956       bytes[offset] = (this.high >>> 24) & 0xFF;
7957       bytes[offset + 1] = (this.high >> 16) & 0xFF;
7958       bytes[offset + 2] = (this.high >> 8) & 0xFF;
7959       bytes[offset + 3] = this.high & 0xFF;
7960       bytes[offset + 4] = (this.low >>> 24) & 0xFF;
7961       bytes[offset + 5] = (this.low >> 16) & 0xFF;
7962       bytes[offset + 6] = (this.low >> 8) & 0xFF;
7963       bytes[offset + 7] = this.low & 0xFF;
7964     },
7965
7966     assign: function Word64_assign(word) {
7967       this.high = word.high;
7968       this.low = word.low;
7969     }
7970   };
7971   return Word64;
7972 })();
7973
7974 var calculateSHA256 = (function calculateSHA256Closure() {
7975   function rotr(x, n) {
7976     return (x >>> n) | (x << 32 - n);
7977   }
7978
7979   function ch(x, y, z) {
7980     return (x & y) ^ (~x & z);
7981   }
7982
7983   function maj(x, y, z) {
7984     return (x & y) ^ (x & z) ^ (y & z);
7985   }
7986
7987   function sigma(x) {
7988     return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
7989   }
7990
7991   function sigmaPrime(x) {
7992     return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
7993   }
7994
7995   function littleSigma(x) {
7996     return rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3;
7997   }
7998
7999   function littleSigmaPrime(x) {
8000     return rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10;
8001   }
8002
8003   var k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
8004            0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
8005            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
8006            0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
8007            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
8008            0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
8009            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
8010            0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
8011            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
8012            0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
8013            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
8014            0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
8015            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
8016            0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
8017            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
8018            0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
8019
8020   function hash(data, offset, length) {
8021     // initial hash values
8022     var h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372,
8023         h3 = 0xa54ff53a, h4 = 0x510e527f, h5 = 0x9b05688c,
8024         h6 = 0x1f83d9ab, h7 = 0x5be0cd19;
8025     // pre-processing
8026     var paddedLength = Math.ceil((length + 9) / 64) * 64;
8027     var padded = new Uint8Array(paddedLength);
8028     var i, j, n;
8029     for (i = 0; i < length; ++i) {
8030       padded[i] = data[offset++];
8031     }
8032     padded[i++] = 0x80;
8033     n = paddedLength - 8;
8034     while (i < n) {
8035       padded[i++] = 0;
8036     }
8037     padded[i++] = 0;
8038     padded[i++] = 0;
8039     padded[i++] = 0;
8040     padded[i++] = (length >>> 29) & 0xFF;
8041     padded[i++] = (length >> 21) & 0xFF;
8042     padded[i++] = (length >> 13) & 0xFF;
8043     padded[i++] = (length >> 5) & 0xFF;
8044     padded[i++] = (length << 3) & 0xFF;
8045     var w = new Uint32Array(64);
8046     // for each 512 bit block
8047     for (i = 0; i < paddedLength;) {
8048       for (j = 0; j < 16; ++j) {
8049         w[j] = (padded[i] << 24 | (padded[i + 1] << 16) |
8050                (padded[i + 2] << 8) | (padded[i + 3]));
8051         i += 4;
8052       }
8053
8054       for (j = 16; j < 64; ++j) {
8055         w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] +
8056                littleSigma(w[j - 15]) + w[j - 16] | 0;
8057       }
8058       var a = h0, b = h1, c = h2, d = h3, e = h4,
8059           f = h5, g = h6, h = h7, t1, t2;
8060       for (j = 0; j < 64; ++j) {
8061         t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j];
8062         t2 = sigma(a) + maj(a, b, c);
8063         h = g;
8064         g = f;
8065         f = e;
8066         e = (d + t1) | 0;
8067         d = c;
8068         c = b;
8069         b = a;
8070         a = (t1 + t2) | 0;
8071       }
8072       h0 = (h0 + a) | 0;
8073       h1 = (h1 + b) | 0;
8074       h2 = (h2 + c) | 0;
8075       h3 = (h3 + d) | 0;
8076       h4 = (h4 + e) | 0;
8077       h5 = (h5 + f) | 0;
8078       h6 = (h6 + g) | 0;
8079       h7 = (h7 + h) | 0;
8080     }
8081     return new Uint8Array([
8082       (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, (h0) & 0xFF,
8083       (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, (h1) & 0xFF,
8084       (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, (h2) & 0xFF,
8085       (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, (h3) & 0xFF,
8086       (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, (h4) & 0xFF,
8087       (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, (h5) & 0xFF,
8088       (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, (h6) & 0xFF,
8089       (h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, (h7) & 0xFF
8090     ]);
8091   }
8092
8093   return hash;
8094 })();
8095
8096 var calculateSHA512 = (function calculateSHA512Closure() {
8097   function ch(result, x, y, z, tmp) {
8098     result.assign(x);
8099     result.and(y);
8100     tmp.assign(x);
8101     tmp.not();
8102     tmp.and(z);
8103     result.xor(tmp);
8104   }
8105
8106   function maj(result, x, y, z, tmp) {
8107     result.assign(x);
8108     result.and(y);
8109     tmp.assign(x);
8110     tmp.and(z);
8111     result.xor(tmp);
8112     tmp.assign(y);
8113     tmp.and(z);
8114     result.xor(tmp);
8115   }
8116
8117   function sigma(result, x, tmp) {
8118     result.assign(x);
8119     result.rotateRight(28);
8120     tmp.assign(x);
8121     tmp.rotateRight(34);
8122     result.xor(tmp);
8123     tmp.assign(x);
8124     tmp.rotateRight(39);
8125     result.xor(tmp);
8126   }
8127
8128   function sigmaPrime(result, x, tmp) {
8129     result.assign(x);
8130     result.rotateRight(14);
8131     tmp.assign(x);
8132     tmp.rotateRight(18);
8133     result.xor(tmp);
8134     tmp.assign(x);
8135     tmp.rotateRight(41);
8136     result.xor(tmp);
8137   }
8138
8139   function littleSigma(result, x, tmp) {
8140     result.assign(x);
8141     result.rotateRight(1);
8142     tmp.assign(x);
8143     tmp.rotateRight(8);
8144     result.xor(tmp);
8145     tmp.assign(x);
8146     tmp.shiftRight(7);
8147     result.xor(tmp);
8148   }
8149
8150   function littleSigmaPrime(result, x, tmp) {
8151     result.assign(x);
8152     result.rotateRight(19);
8153     tmp.assign(x);
8154     tmp.rotateRight(61);
8155     result.xor(tmp);
8156     tmp.assign(x);
8157     tmp.shiftRight(6);
8158     result.xor(tmp);
8159   }
8160
8161   var k = [
8162     new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd),
8163     new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc),
8164     new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019),
8165     new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118),
8166     new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe),
8167     new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2),
8168     new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1),
8169     new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694),
8170     new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3),
8171     new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65),
8172     new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483),
8173     new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5),
8174     new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210),
8175     new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4),
8176     new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725),
8177     new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70),
8178     new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926),
8179     new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df),
8180     new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8),
8181     new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b),
8182     new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001),
8183     new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30),
8184     new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910),
8185     new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8),
8186     new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53),
8187     new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8),
8188     new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb),
8189     new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3),
8190     new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60),
8191     new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec),
8192     new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9),
8193     new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b),
8194     new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207),
8195     new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178),
8196     new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6),
8197     new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b),
8198     new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493),
8199     new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c),
8200     new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a),
8201     new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)];
8202
8203   function hash(data, offset, length, mode384) {
8204     mode384 = !!mode384;
8205     // initial hash values
8206     var h0, h1, h2, h3, h4, h5, h6, h7;
8207     if (!mode384) {
8208       h0 = new Word64(0x6a09e667, 0xf3bcc908);
8209       h1 = new Word64(0xbb67ae85, 0x84caa73b);
8210       h2 = new Word64(0x3c6ef372, 0xfe94f82b);
8211       h3 = new Word64(0xa54ff53a, 0x5f1d36f1);
8212       h4 = new Word64(0x510e527f, 0xade682d1);
8213       h5 = new Word64(0x9b05688c, 0x2b3e6c1f);
8214       h6 = new Word64(0x1f83d9ab, 0xfb41bd6b);
8215       h7 = new Word64(0x5be0cd19, 0x137e2179);
8216     }
8217     else {
8218       // SHA384 is exactly the same
8219       // except with different starting values and a trimmed result
8220       h0 = new Word64(0xcbbb9d5d, 0xc1059ed8);
8221       h1 = new Word64(0x629a292a, 0x367cd507);
8222       h2 = new Word64(0x9159015a, 0x3070dd17);
8223       h3 = new Word64(0x152fecd8, 0xf70e5939);
8224       h4 = new Word64(0x67332667, 0xffc00b31);
8225       h5 = new Word64(0x8eb44a87, 0x68581511);
8226       h6 = new Word64(0xdb0c2e0d, 0x64f98fa7);
8227       h7 = new Word64(0x47b5481d, 0xbefa4fa4);
8228     }
8229
8230     // pre-processing
8231     var paddedLength = Math.ceil((length + 17) / 128) * 128;
8232     var padded = new Uint8Array(paddedLength);
8233     var i, j, n;
8234     for (i = 0; i < length; ++i) {
8235       padded[i] = data[offset++];
8236     }
8237     padded[i++] = 0x80;
8238     n = paddedLength - 16;
8239     while (i < n) {
8240       padded[i++] = 0;
8241     }
8242     padded[i++] = 0;
8243     padded[i++] = 0;
8244     padded[i++] = 0;
8245     padded[i++] = 0;
8246     padded[i++] = 0;
8247     padded[i++] = 0;
8248     padded[i++] = 0;
8249     padded[i++] = 0;
8250     padded[i++] = 0;
8251     padded[i++] = 0;
8252     padded[i++] = 0;
8253     padded[i++] = (length >>> 29) & 0xFF;
8254     padded[i++] = (length >> 21) & 0xFF;
8255     padded[i++] = (length >> 13) & 0xFF;
8256     padded[i++] = (length >> 5) & 0xFF;
8257     padded[i++] = (length << 3) & 0xFF;
8258
8259     var w = new Array(80);
8260     for (i = 0; i < 80; i++) {
8261       w[i] = new Word64(0, 0);
8262     }
8263     var a = new Word64(0, 0), b = new Word64(0, 0), c = new Word64(0, 0);
8264     var d = new Word64(0, 0), e = new Word64(0, 0), f = new Word64(0, 0);
8265     var g = new Word64(0, 0), h = new Word64(0, 0);
8266     var t1 = new Word64(0, 0), t2 = new Word64(0, 0);
8267     var tmp1 = new Word64(0, 0), tmp2 = new Word64(0, 0), tmp3;
8268
8269     // for each 1024 bit block
8270     for (i = 0; i < paddedLength;) {
8271       for (j = 0; j < 16; ++j) {
8272         w[j].high = (padded[i] << 24) | (padded[i + 1] << 16) |
8273                     (padded[i + 2] << 8) | (padded[i + 3]);
8274         w[j].low = (padded[i + 4]) << 24 | (padded[i + 5]) << 16 |
8275                    (padded[i + 6]) << 8 | (padded[i + 7]);
8276         i += 8;
8277       }
8278       for (j = 16; j < 80; ++j) {
8279         tmp3 = w[j];
8280         littleSigmaPrime(tmp3, w[j - 2], tmp2);
8281         tmp3.add(w[j - 7]);
8282         littleSigma(tmp1, w[j - 15], tmp2);
8283         tmp3.add(tmp1);
8284         tmp3.add(w[j - 16]);
8285       }
8286
8287       a.assign(h0); b.assign(h1); c.assign(h2); d.assign(h3);
8288       e.assign(h4); f.assign(h5); g.assign(h6); h.assign(h7);
8289       for (j = 0; j < 80; ++j) {
8290         t1.assign(h);
8291         sigmaPrime(tmp1, e, tmp2);
8292         t1.add(tmp1);
8293         ch(tmp1, e, f, g, tmp2);
8294         t1.add(tmp1);
8295         t1.add(k[j]);
8296         t1.add(w[j]);
8297
8298         sigma(t2, a, tmp2);
8299         maj(tmp1, a, b, c, tmp2);
8300         t2.add(tmp1);
8301
8302         tmp3 = h;
8303         h = g;
8304         g = f;
8305         f = e;
8306         d.add(t1);
8307         e = d;
8308         d = c;
8309         c = b;
8310         b = a;
8311         tmp3.assign(t1);
8312         tmp3.add(t2);
8313         a = tmp3;
8314       }
8315       h0.add(a);
8316       h1.add(b);
8317       h2.add(c);
8318       h3.add(d);
8319       h4.add(e);
8320       h5.add(f);
8321       h6.add(g);
8322       h7.add(h);
8323     }
8324
8325     var result;
8326     if (!mode384) {
8327       result = new Uint8Array(64);
8328       h0.copyTo(result,0);
8329       h1.copyTo(result,8);
8330       h2.copyTo(result,16);
8331       h3.copyTo(result,24);
8332       h4.copyTo(result,32);
8333       h5.copyTo(result,40);
8334       h6.copyTo(result,48);
8335       h7.copyTo(result,56);
8336     }
8337     else {
8338       result = new Uint8Array(48);
8339       h0.copyTo(result,0);
8340       h1.copyTo(result,8);
8341       h2.copyTo(result,16);
8342       h3.copyTo(result,24);
8343       h4.copyTo(result,32);
8344       h5.copyTo(result,40);
8345     }
8346     return result;
8347   }
8348
8349   return hash;
8350 })();
8351 var calculateSHA384 = (function calculateSHA384Closure() {
8352   function hash(data, offset, length) {
8353     return calculateSHA512(data, offset, length, true);
8354   }
8355
8356   return hash;
8357 })();
8358 var NullCipher = (function NullCipherClosure() {
8359   function NullCipher() {
8360   }
8361
8362   NullCipher.prototype = {
8363     decryptBlock: function NullCipher_decryptBlock(data) {
8364       return data;
8365     }
8366   };
8367
8368   return NullCipher;
8369 })();
8370
8371 var AES128Cipher = (function AES128CipherClosure() {
8372   var rcon = new Uint8Array([
8373     0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
8374     0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
8375     0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
8376     0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
8377     0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
8378     0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,
8379     0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
8380     0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
8381     0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
8382     0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e,
8383     0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
8384     0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
8385     0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
8386     0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
8387     0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
8388     0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
8389     0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,
8390     0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
8391     0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
8392     0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
8393     0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
8394     0x74, 0xe8, 0xcb, 0x8d]);
8395
8396   var s = new Uint8Array([
8397     0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
8398     0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
8399     0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
8400     0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
8401     0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
8402     0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
8403     0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
8404     0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
8405     0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
8406     0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
8407     0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
8408     0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
8409     0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
8410     0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
8411     0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
8412     0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
8413     0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
8414     0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
8415     0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
8416     0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
8417     0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
8418     0xb0, 0x54, 0xbb, 0x16]);
8419
8420   var inv_s = new Uint8Array([
8421     0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
8422     0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
8423     0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
8424     0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
8425     0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
8426     0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
8427     0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
8428     0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
8429     0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
8430     0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
8431     0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
8432     0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
8433     0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
8434     0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
8435     0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
8436     0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
8437     0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
8438     0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
8439     0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
8440     0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
8441     0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
8442     0x55, 0x21, 0x0c, 0x7d]);
8443   var mixCol = new Uint8Array(256);
8444   for (var i = 0; i < 256; i++) {
8445     if (i < 128) {
8446       mixCol[i] = i << 1;
8447     } else {
8448       mixCol[i] = (i << 1) ^ 0x1b;
8449     }
8450   }
8451   var mix = new Uint32Array([
8452     0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
8453     0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
8454     0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,
8455     0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,
8456     0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,
8457     0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,
8458     0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,
8459     0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,
8460     0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,
8461     0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,
8462     0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,
8463     0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,
8464     0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,
8465     0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,
8466     0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,
8467     0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,
8468     0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,
8469     0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,
8470     0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,
8471     0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,
8472     0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,
8473     0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,
8474     0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,
8475     0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,
8476     0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,
8477     0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,
8478     0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,
8479     0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,
8480     0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,
8481     0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,
8482     0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,
8483     0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,
8484     0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,
8485     0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,
8486     0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,
8487     0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,
8488     0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,
8489     0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,
8490     0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,
8491     0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,
8492     0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,
8493     0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
8494     0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
8495
8496   function expandKey128(cipherKey) {
8497     var b = 176, result = new Uint8Array(b);
8498     result.set(cipherKey);
8499     for (var j = 16, i = 1; j < b; ++i) {
8500       // RotWord
8501       var t1 = result[j - 3], t2 = result[j - 2],
8502           t3 = result[j - 1], t4 = result[j - 4];
8503       // SubWord
8504       t1 = s[t1];
8505       t2 = s[t2];
8506       t3 = s[t3];
8507       t4 = s[t4];
8508       // Rcon
8509       t1 = t1 ^ rcon[i];
8510       for (var n = 0; n < 4; ++n) {
8511         result[j] = (t1 ^= result[j - 16]);
8512         j++;
8513         result[j] = (t2 ^= result[j - 16]);
8514         j++;
8515         result[j] = (t3 ^= result[j - 16]);
8516         j++;
8517         result[j] = (t4 ^= result[j - 16]);
8518         j++;
8519       }
8520     }
8521     return result;
8522   }
8523
8524   function decrypt128(input, key) {
8525     var state = new Uint8Array(16);
8526     state.set(input);
8527     var i, j, k;
8528     var t, u, v;
8529     // AddRoundKey
8530     for (j = 0, k = 160; j < 16; ++j, ++k) {
8531       state[j] ^= key[k];
8532     }
8533     for (i = 9; i >= 1; --i) {
8534       // InvShiftRows
8535       t = state[13];
8536       state[13] = state[9];
8537       state[9] = state[5];
8538       state[5] = state[1];
8539       state[1] = t;
8540       t = state[14];
8541       u = state[10];
8542       state[14] = state[6];
8543       state[10] = state[2];
8544       state[6] = t;
8545       state[2] = u;
8546       t = state[15];
8547       u = state[11];
8548       v = state[7];
8549       state[15] = state[3];
8550       state[11] = t;
8551       state[7] = u;
8552       state[3] = v;
8553       // InvSubBytes
8554       for (j = 0; j < 16; ++j) {
8555         state[j] = inv_s[state[j]];
8556       }
8557       // AddRoundKey
8558       for (j = 0, k = i * 16; j < 16; ++j, ++k) {
8559         state[j] ^= key[k];
8560       }
8561       // InvMixColumns
8562       for (j = 0; j < 16; j += 4) {
8563         var s0 = mix[state[j]], s1 = mix[state[j + 1]],
8564           s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
8565         t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^
8566           (s3 >>> 24) ^ (s3 << 8));
8567         state[j] = (t >>> 24) & 0xFF;
8568         state[j + 1] = (t >> 16) & 0xFF;
8569         state[j + 2] = (t >> 8) & 0xFF;
8570         state[j + 3] = t & 0xFF;
8571       }
8572     }
8573     // InvShiftRows
8574     t = state[13];
8575     state[13] = state[9];
8576     state[9] = state[5];
8577     state[5] = state[1];
8578     state[1] = t;
8579     t = state[14];
8580     u = state[10];
8581     state[14] = state[6];
8582     state[10] = state[2];
8583     state[6] = t;
8584     state[2] = u;
8585     t = state[15];
8586     u = state[11];
8587     v = state[7];
8588     state[15] = state[3];
8589     state[11] = t;
8590     state[7] = u;
8591     state[3] = v;
8592     for (j = 0; j < 16; ++j) {
8593       // InvSubBytes
8594       state[j] = inv_s[state[j]];
8595       // AddRoundKey
8596       state[j] ^= key[j];
8597     }
8598     return state;
8599   }
8600
8601   function encrypt128(input, key) {
8602     var t, u, v, k;
8603     var state = new Uint8Array(16);
8604     state.set(input);
8605     for (j = 0; j < 16; ++j) {
8606       // AddRoundKey
8607       state[j] ^= key[j];
8608     }
8609
8610     for (i = 1; i < 10; i++) {
8611       //SubBytes
8612       for (j = 0; j < 16; ++j) {
8613         state[j] = s[state[j]];
8614       }
8615       //ShiftRows
8616       v = state[1];
8617       state[1] = state[5];
8618       state[5] = state[9];
8619       state[9] = state[13];
8620       state[13] = v;
8621       v = state[2];
8622       u = state[6];
8623       state[2] = state[10];
8624       state[6] = state[14];
8625       state[10] = v;
8626       state[14] = u;
8627       v = state[3];
8628       u = state[7];
8629       t = state[11];
8630       state[3] = state[15];
8631       state[7] = v;
8632       state[11] = u;
8633       state[15] = t;
8634       //MixColumns
8635       for (var j = 0; j < 16; j += 4) {
8636         var s0 = state[j + 0], s1 = state[j + 1];
8637         var s2 = state[j + 2], s3 = state[j + 3];
8638         t = s0 ^ s1 ^ s2 ^ s3;
8639         state[j + 0] ^= t ^ mixCol[s0 ^ s1];
8640         state[j + 1] ^= t ^ mixCol[s1 ^ s2];
8641         state[j + 2] ^= t ^ mixCol[s2 ^ s3];
8642         state[j + 3] ^= t ^ mixCol[s3 ^ s0];
8643       }
8644       //AddRoundKey
8645       for (j = 0, k = i * 16; j < 16; ++j, ++k) {
8646         state[j] ^= key[k];
8647       }
8648     }
8649
8650     //SubBytes
8651     for (j = 0; j < 16; ++j) {
8652       state[j] = s[state[j]];
8653     }
8654     //ShiftRows
8655     v = state[1];
8656     state[1] = state[5];
8657     state[5] = state[9];
8658     state[9] = state[13];
8659     state[13] = v;
8660     v = state[2];
8661     u = state[6];
8662     state[2] = state[10];
8663     state[6] = state[14];
8664     state[10] = v;
8665     state[14] = u;
8666     v = state[3];
8667     u = state[7];
8668     t = state[11];
8669     state[3] = state[15];
8670     state[7] = v;
8671     state[11] = u;
8672     state[15] = t;
8673     //AddRoundKey
8674     for (j = 0, k = 160; j < 16; ++j, ++k) {
8675       state[j] ^= key[k];
8676     }
8677     return state;
8678   }
8679
8680   function AES128Cipher(key) {
8681     this.key = expandKey128(key);
8682     this.buffer = new Uint8Array(16);
8683     this.bufferPosition = 0;
8684   }
8685
8686   function decryptBlock2(data, finalize) {
8687     var i, j, ii, sourceLength = data.length,
8688         buffer = this.buffer, bufferLength = this.bufferPosition,
8689         result = [], iv = this.iv;
8690     for (i = 0; i < sourceLength; ++i) {
8691       buffer[bufferLength] = data[i];
8692       ++bufferLength;
8693       if (bufferLength < 16) {
8694         continue;
8695       }
8696       // buffer is full, decrypting
8697       var plain = decrypt128(buffer, this.key);
8698       // xor-ing the IV vector to get plain text
8699       for (j = 0; j < 16; ++j) {
8700         plain[j] ^= iv[j];
8701       }
8702       iv = buffer;
8703       result.push(plain);
8704       buffer = new Uint8Array(16);
8705       bufferLength = 0;
8706     }
8707     // saving incomplete buffer
8708     this.buffer = buffer;
8709     this.bufferLength = bufferLength;
8710     this.iv = iv;
8711     if (result.length === 0) {
8712       return new Uint8Array([]);
8713     }
8714     // combining plain text blocks into one
8715     var outputLength = 16 * result.length;
8716     if (finalize) {
8717       // undo a padding that is described in RFC 2898
8718       var lastBlock = result[result.length - 1];
8719       var psLen = lastBlock[15];
8720       if (psLen <= 16) {
8721         for (i = 15, ii = 16 - psLen; i >= ii; --i) {
8722           if (lastBlock[i] !== psLen) {
8723             // Invalid padding, assume that the block has no padding.
8724             psLen = 0;
8725             break;
8726           }
8727         }
8728         outputLength -= psLen;
8729         result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);
8730       }
8731     }
8732     var output = new Uint8Array(outputLength);
8733     for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
8734       output.set(result[i], j);
8735     }
8736     return output;
8737   }
8738
8739   AES128Cipher.prototype = {
8740     decryptBlock: function AES128Cipher_decryptBlock(data, finalize) {
8741       var i, sourceLength = data.length;
8742       var buffer = this.buffer, bufferLength = this.bufferPosition;
8743       // waiting for IV values -- they are at the start of the stream
8744       for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) {
8745         buffer[bufferLength] = data[i];
8746       }
8747       if (bufferLength < 16) {
8748         // need more data
8749         this.bufferLength = bufferLength;
8750         return new Uint8Array([]);
8751       }
8752       this.iv = buffer;
8753       this.buffer = new Uint8Array(16);
8754       this.bufferLength = 0;
8755       // starting decryption
8756       this.decryptBlock = decryptBlock2;
8757       return this.decryptBlock(data.subarray(16), finalize);
8758     },
8759     encrypt: function AES128Cipher_encrypt(data, iv) {
8760       var i, j, ii, sourceLength = data.length,
8761           buffer = this.buffer, bufferLength = this.bufferPosition,
8762           result = [];
8763       if (!iv) {
8764         iv = new Uint8Array(16);
8765       }
8766       for (i = 0; i < sourceLength; ++i) {
8767         buffer[bufferLength] = data[i];
8768         ++bufferLength;
8769         if (bufferLength < 16) {
8770           continue;
8771         }
8772         for (j = 0; j < 16; ++j) {
8773           buffer[j] ^= iv[j];
8774         }
8775
8776         // buffer is full, encrypting
8777         var cipher = encrypt128(buffer, this.key);
8778         iv = cipher;
8779         result.push(cipher);
8780         buffer = new Uint8Array(16);
8781         bufferLength = 0;
8782       }
8783       // saving incomplete buffer
8784       this.buffer = buffer;
8785       this.bufferLength = bufferLength;
8786       this.iv = iv;
8787       if (result.length === 0) {
8788         return new Uint8Array([]);
8789       }
8790       // combining plain text blocks into one
8791       var outputLength = 16 * result.length;
8792       var output = new Uint8Array(outputLength);
8793       for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
8794         output.set(result[i], j);
8795       }
8796       return output;
8797     }
8798   };
8799
8800   return AES128Cipher;
8801 })();
8802
8803 var AES256Cipher = (function AES256CipherClosure() {
8804   var rcon = new Uint8Array([
8805     0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
8806     0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
8807     0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
8808     0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
8809     0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
8810     0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,
8811     0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
8812     0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
8813     0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
8814     0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e,
8815     0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
8816     0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
8817     0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
8818     0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
8819     0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
8820     0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
8821     0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,
8822     0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
8823     0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
8824     0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
8825     0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
8826     0x74, 0xe8, 0xcb, 0x8d]);
8827
8828   var s = new Uint8Array([
8829     0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
8830     0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
8831     0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
8832     0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
8833     0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
8834     0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
8835     0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
8836     0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
8837     0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
8838     0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
8839     0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
8840     0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
8841     0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
8842     0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
8843     0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
8844     0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
8845     0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
8846     0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
8847     0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
8848     0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
8849     0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
8850     0xb0, 0x54, 0xbb, 0x16]);
8851
8852   var inv_s = new Uint8Array([
8853     0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
8854     0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
8855     0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
8856     0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
8857     0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
8858     0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
8859     0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
8860     0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
8861     0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
8862     0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
8863     0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
8864     0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
8865     0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
8866     0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
8867     0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
8868     0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
8869     0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
8870     0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
8871     0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
8872     0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
8873     0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
8874     0x55, 0x21, 0x0c, 0x7d]);
8875
8876   var mixCol = new Uint8Array(256);
8877   for (var i = 0; i < 256; i++) {
8878     if (i < 128) {
8879       mixCol[i] = i << 1;
8880     } else {
8881       mixCol[i] = (i << 1) ^ 0x1b;
8882     }
8883   }
8884   var mix = new Uint32Array([
8885     0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
8886     0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
8887     0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,
8888     0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,
8889     0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,
8890     0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,
8891     0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,
8892     0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,
8893     0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,
8894     0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,
8895     0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,
8896     0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,
8897     0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,
8898     0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,
8899     0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,
8900     0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,
8901     0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,
8902     0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,
8903     0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,
8904     0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,
8905     0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,
8906     0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,
8907     0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,
8908     0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,
8909     0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,
8910     0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,
8911     0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,
8912     0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,
8913     0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,
8914     0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,
8915     0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,
8916     0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,
8917     0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,
8918     0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,
8919     0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,
8920     0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,
8921     0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,
8922     0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,
8923     0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,
8924     0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,
8925     0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,
8926     0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
8927     0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
8928
8929   function expandKey256(cipherKey) {
8930     var b = 240, result = new Uint8Array(b);
8931     var r = 1;
8932
8933     result.set(cipherKey);
8934     for (var j = 32, i = 1; j < b; ++i) {
8935       if (j % 32 === 16) {
8936         t1 = s[t1];
8937         t2 = s[t2];
8938         t3 = s[t3];
8939         t4 = s[t4];
8940       } else if (j % 32 === 0) {
8941         // RotWord
8942         var t1 = result[j - 3], t2 = result[j - 2],
8943           t3 = result[j - 1], t4 = result[j - 4];
8944         // SubWord
8945         t1 = s[t1];
8946         t2 = s[t2];
8947         t3 = s[t3];
8948         t4 = s[t4];
8949         // Rcon
8950         t1 = t1 ^ r;
8951         if ((r <<= 1) >= 256) {
8952           r = (r ^ 0x1b) & 0xFF;
8953         }
8954       }
8955
8956       for (var n = 0; n < 4; ++n) {
8957         result[j] = (t1 ^= result[j - 32]);
8958         j++;
8959         result[j] = (t2 ^= result[j - 32]);
8960         j++;
8961         result[j] = (t3 ^= result[j - 32]);
8962         j++;
8963         result[j] = (t4 ^= result[j - 32]);
8964         j++;
8965       }
8966     }
8967     return result;
8968   }
8969
8970   function decrypt256(input, key) {
8971     var state = new Uint8Array(16);
8972     state.set(input);
8973     var i, j, k;
8974     var t, u, v;
8975     // AddRoundKey
8976     for (j = 0, k = 224; j < 16; ++j, ++k) {
8977       state[j] ^= key[k];
8978     }
8979     for (i = 13; i >= 1; --i) {
8980       // InvShiftRows
8981       t = state[13];
8982       state[13] = state[9];
8983       state[9] = state[5];
8984       state[5] = state[1];
8985       state[1] = t;
8986       t = state[14];
8987       u = state[10];
8988       state[14] = state[6];
8989       state[10] = state[2];
8990       state[6] = t;
8991       state[2] = u;
8992       t = state[15];
8993       u = state[11];
8994       v = state[7];
8995       state[15] = state[3];
8996       state[11] = t;
8997       state[7] = u;
8998       state[3] = v;
8999       // InvSubBytes
9000       for (j = 0; j < 16; ++j) {
9001         state[j] = inv_s[state[j]];
9002       }
9003       // AddRoundKey
9004       for (j = 0, k = i * 16; j < 16; ++j, ++k) {
9005         state[j] ^= key[k];
9006       }
9007       // InvMixColumns
9008       for (j = 0; j < 16; j += 4) {
9009         var s0 = mix[state[j]], s1 = mix[state[j + 1]],
9010             s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
9011         t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^
9012             (s3 >>> 24) ^ (s3 << 8));
9013         state[j] = (t >>> 24) & 0xFF;
9014         state[j + 1] = (t >> 16) & 0xFF;
9015         state[j + 2] = (t >> 8) & 0xFF;
9016         state[j + 3] = t & 0xFF;
9017       }
9018     }
9019     // InvShiftRows
9020     t = state[13];
9021     state[13] = state[9];
9022     state[9] = state[5];
9023     state[5] = state[1];
9024     state[1] = t;
9025     t = state[14];
9026     u = state[10];
9027     state[14] = state[6];
9028     state[10] = state[2];
9029     state[6] = t;
9030     state[2] = u;
9031     t = state[15];
9032     u = state[11];
9033     v = state[7];
9034     state[15] = state[3];
9035     state[11] = t;
9036     state[7] = u;
9037     state[3] = v;
9038     for (j = 0; j < 16; ++j) {
9039       // InvSubBytes
9040       state[j] = inv_s[state[j]];
9041       // AddRoundKey
9042       state[j] ^= key[j];
9043     }
9044     return state;
9045   }
9046
9047   function encrypt256(input, key) {
9048     var t, u, v, k;
9049     var state = new Uint8Array(16);
9050     state.set(input);
9051     for (j = 0; j < 16; ++j) {
9052       // AddRoundKey
9053       state[j] ^= key[j];
9054     }
9055
9056     for (i = 1; i < 14; i++) {
9057       //SubBytes
9058       for (j = 0; j < 16; ++j) {
9059         state[j] = s[state[j]];
9060       }
9061       //ShiftRows
9062       v = state[1];
9063       state[1] = state[5];
9064       state[5] = state[9];
9065       state[9] = state[13];
9066       state[13] = v;
9067       v = state[2];
9068       u = state[6];
9069       state[2] = state[10];
9070       state[6] = state[14];
9071       state[10] = v;
9072       state[14] = u;
9073       v = state[3];
9074       u = state[7];
9075       t = state[11];
9076       state[3] = state[15];
9077       state[7] = v;
9078       state[11] = u;
9079       state[15] = t;
9080       //MixColumns
9081       for (var j = 0; j < 16; j += 4) {
9082         var s0 = state[j + 0], s1 = state[j + 1];
9083         var s2 = state[j + 2], s3 = state[j + 3];
9084         t = s0 ^ s1 ^ s2 ^ s3;
9085         state[j + 0] ^= t ^ mixCol[s0 ^ s1];
9086         state[j + 1] ^= t ^ mixCol[s1 ^ s2];
9087         state[j + 2] ^= t ^ mixCol[s2 ^ s3];
9088         state[j + 3] ^= t ^ mixCol[s3 ^ s0];
9089       }
9090       //AddRoundKey
9091       for (j = 0, k = i * 16; j < 16; ++j, ++k) {
9092         state[j] ^= key[k];
9093       }
9094     }
9095
9096     //SubBytes
9097     for (j = 0; j < 16; ++j) {
9098       state[j] = s[state[j]];
9099     }
9100     //ShiftRows
9101     v = state[1];
9102     state[1] = state[5];
9103     state[5] = state[9];
9104     state[9] = state[13];
9105     state[13] = v;
9106     v = state[2];
9107     u = state[6];
9108     state[2] = state[10];
9109     state[6] = state[14];
9110     state[10] = v;
9111     state[14] = u;
9112     v = state[3];
9113     u = state[7];
9114     t = state[11];
9115     state[3] = state[15];
9116     state[7] = v;
9117     state[11] = u;
9118     state[15] = t;
9119     //AddRoundKey
9120     for (j = 0, k = 224; j < 16; ++j, ++k) {
9121       state[j] ^= key[k];
9122     }
9123
9124     return state;
9125
9126   }
9127
9128   function AES256Cipher(key) {
9129     this.key = expandKey256(key);
9130     this.buffer = new Uint8Array(16);
9131     this.bufferPosition = 0;
9132   }
9133
9134   function decryptBlock2(data, finalize) {
9135     var i, j, ii, sourceLength = data.length,
9136         buffer = this.buffer, bufferLength = this.bufferPosition,
9137         result = [], iv = this.iv;
9138
9139     for (i = 0; i < sourceLength; ++i) {
9140       buffer[bufferLength] = data[i];
9141       ++bufferLength;
9142       if (bufferLength < 16) {
9143         continue;
9144       }
9145       // buffer is full, decrypting
9146       var plain = decrypt256(buffer, this.key);
9147       // xor-ing the IV vector to get plain text
9148       for (j = 0; j < 16; ++j) {
9149         plain[j] ^= iv[j];
9150       }
9151       iv = buffer;
9152       result.push(plain);
9153       buffer = new Uint8Array(16);
9154       bufferLength = 0;
9155     }
9156     // saving incomplete buffer
9157     this.buffer = buffer;
9158     this.bufferLength = bufferLength;
9159     this.iv = iv;
9160     if (result.length === 0) {
9161       return new Uint8Array([]);
9162     }
9163     // combining plain text blocks into one
9164     var outputLength = 16 * result.length;
9165     if (finalize) {
9166       // undo a padding that is described in RFC 2898
9167       var lastBlock = result[result.length - 1];
9168       var psLen = lastBlock[15];
9169       if (psLen <= 16) {
9170         for (i = 15, ii = 16 - psLen; i >= ii; --i) {
9171           if (lastBlock[i] !== psLen) {
9172             // Invalid padding, assume that the block has no padding.
9173             psLen = 0;
9174             break;
9175           }
9176         }
9177         outputLength -= psLen;
9178         result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);
9179       }
9180     }
9181     var output = new Uint8Array(outputLength);
9182     for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
9183       output.set(result[i], j);
9184     }
9185     return output;
9186
9187   }
9188
9189   AES256Cipher.prototype = {
9190     decryptBlock: function AES256Cipher_decryptBlock(data, finalize, iv) {
9191       var i, sourceLength = data.length;
9192       var buffer = this.buffer, bufferLength = this.bufferPosition;
9193       // if not supplied an IV wait for IV values
9194       // they are at the start of the stream
9195       if (iv) {
9196         this.iv = iv;
9197       } else {
9198         for (i = 0; bufferLength < 16 &&
9199              i < sourceLength; ++i, ++bufferLength) {
9200           buffer[bufferLength] = data[i];
9201         }
9202         if (bufferLength < 16) {
9203           //need more data
9204           this.bufferLength = bufferLength;
9205           return new Uint8Array([]);
9206         }
9207         this.iv = buffer;
9208         data = data.subarray(16);
9209       }
9210       this.buffer = new Uint8Array(16);
9211       this.bufferLength = 0;
9212       // starting decryption
9213       this.decryptBlock = decryptBlock2;
9214       return this.decryptBlock(data, finalize);
9215     },
9216     encrypt: function AES256Cipher_encrypt(data, iv) {
9217       var i, j, ii, sourceLength = data.length,
9218           buffer = this.buffer, bufferLength = this.bufferPosition,
9219           result = [];
9220       if (!iv) {
9221         iv = new Uint8Array(16);
9222       }
9223       for (i = 0; i < sourceLength; ++i) {
9224         buffer[bufferLength] = data[i];
9225         ++bufferLength;
9226         if (bufferLength < 16) {
9227           continue;
9228         }
9229         for (j = 0; j < 16; ++j) {
9230           buffer[j] ^= iv[j];
9231         }
9232
9233         // buffer is full, encrypting
9234         var cipher = encrypt256(buffer, this.key);
9235         this.iv = cipher;
9236         result.push(cipher);
9237         buffer = new Uint8Array(16);
9238         bufferLength = 0;
9239       }
9240       // saving incomplete buffer
9241       this.buffer = buffer;
9242       this.bufferLength = bufferLength;
9243       this.iv = iv;
9244       if (result.length === 0) {
9245         return new Uint8Array([]);
9246       }
9247       // combining plain text blocks into one
9248       var outputLength = 16 * result.length;
9249       var output = new Uint8Array(outputLength);
9250       for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
9251         output.set(result[i], j);
9252       }
9253       return output;
9254     }
9255   };
9256
9257   return AES256Cipher;
9258 })();
9259
9260 var PDF17 = (function PDF17Closure() {
9261
9262   function compareByteArrays(array1, array2) {
9263     if (array1.length !== array2.length) {
9264       return false;
9265     }
9266     for (var i = 0; i < array1.length; i++) {
9267       if (array1[i] !== array2[i]) {
9268         return false;
9269       }
9270     }
9271     return true;
9272   }
9273
9274   function PDF17() {
9275   }
9276
9277   PDF17.prototype = {
9278     checkOwnerPassword: function PDF17_checkOwnerPassword(password,
9279                                                           ownerValidationSalt,
9280                                                           userBytes,
9281                                                           ownerPassword) {
9282       var hashData = new Uint8Array(password.length + 56);
9283       hashData.set(password, 0);
9284       hashData.set(ownerValidationSalt, password.length);
9285       hashData.set(userBytes, password.length + ownerValidationSalt.length);
9286       var result = calculateSHA256(hashData, 0, hashData.length);
9287       return compareByteArrays(result, ownerPassword);
9288     },
9289     checkUserPassword: function PDF17_checkUserPassword(password,
9290                                                         userValidationSalt,
9291                                                         userPassword) {
9292       var hashData = new Uint8Array(password.length + 8);
9293       hashData.set(password, 0);
9294       hashData.set(userValidationSalt, password.length);
9295       var result = calculateSHA256(hashData, 0, hashData.length);
9296       return compareByteArrays(result, userPassword);
9297     },
9298     getOwnerKey: function PDF17_getOwnerKey(password, ownerKeySalt, userBytes,
9299                                             ownerEncryption) {
9300       var hashData = new Uint8Array(password.length + 56);
9301       hashData.set(password, 0);
9302       hashData.set(ownerKeySalt, password.length);
9303       hashData.set(userBytes, password.length + ownerKeySalt.length);
9304       var key = calculateSHA256(hashData, 0, hashData.length);
9305       var cipher = new AES256Cipher(key);
9306       return cipher.decryptBlock(ownerEncryption,
9307                                  false,
9308                                  new Uint8Array(16));
9309
9310     },
9311     getUserKey: function PDF17_getUserKey(password, userKeySalt,
9312                                           userEncryption) {
9313       var hashData = new Uint8Array(password.length + 8);
9314       hashData.set(password, 0);
9315       hashData.set(userKeySalt, password.length);
9316       //key is the decryption key for the UE string
9317       var key = calculateSHA256(hashData, 0, hashData.length);
9318       var cipher = new AES256Cipher(key);
9319       return cipher.decryptBlock(userEncryption,
9320                                  false,
9321                                  new Uint8Array(16));
9322     }
9323   };
9324   return PDF17;
9325 })();
9326
9327 var PDF20 = (function PDF20Closure() {
9328
9329   function concatArrays(array1, array2) {
9330     var t = new Uint8Array(array1.length + array2.length);
9331     t.set(array1, 0);
9332     t.set(array2, array1.length);
9333     return t;
9334   }
9335
9336   function calculatePDF20Hash(password, input, userBytes) {
9337     //This refers to Algorithm 2.B as defined in ISO 32000-2
9338     var k = calculateSHA256(input, 0, input.length).subarray(0, 32);
9339     var e = [0];
9340     var i = 0;
9341     while (i < 64 || e[e.length - 1] > i - 32) {
9342       var arrayLength = password.length + k.length + userBytes.length;
9343
9344       var k1 = new Uint8Array(arrayLength * 64);
9345       var array = concatArrays(password, k);
9346       array = concatArrays(array, userBytes);
9347       for (var j = 0, pos = 0; j < 64; j++, pos += arrayLength) {
9348         k1.set(array, pos);
9349       }
9350       //AES128 CBC NO PADDING with
9351       //first 16 bytes of k as the key and the second 16 as the iv.
9352       var cipher = new AES128Cipher(k.subarray(0, 16));
9353       e = cipher.encrypt(k1, k.subarray(16, 32));
9354       //Now we have to take the first 16 bytes of an unsigned
9355       //big endian integer... and compute the remainder
9356       //modulo 3.... That is a fairly large number and
9357       //JavaScript isn't going to handle that well...
9358       //So we're using a trick that allows us to perform
9359       //modulo math byte by byte
9360       var remainder = 0;
9361       for (var z = 0; z < 16; z++) {
9362         remainder *= (256 % 3);
9363         remainder %= 3;
9364         remainder += ((e[z] >>> 0) % 3);
9365         remainder %= 3;
9366       }
9367       if (remainder === 0) {
9368         k = calculateSHA256(e, 0, e.length);
9369       }
9370       else if (remainder === 1) {
9371         k = calculateSHA384(e, 0, e.length);
9372       }
9373       else if (remainder === 2) {
9374         k = calculateSHA512(e, 0, e.length);
9375       }
9376       i++;
9377     }
9378     return k.subarray(0, 32);
9379   }
9380
9381   function PDF20() {
9382   }
9383
9384   function compareByteArrays(array1, array2) {
9385     if (array1.length !== array2.length) {
9386       return false;
9387     }
9388     for (var i = 0; i < array1.length; i++) {
9389       if (array1[i] !== array2[i]) {
9390         return false;
9391       }
9392     }
9393     return true;
9394   }
9395
9396   PDF20.prototype = {
9397     hash: function PDF20_hash(password, concatBytes, userBytes) {
9398       return calculatePDF20Hash(password, concatBytes, userBytes);
9399     },
9400     checkOwnerPassword: function PDF20_checkOwnerPassword(password,
9401                                                           ownerValidationSalt,
9402                                                           userBytes,
9403                                                           ownerPassword) {
9404       var hashData = new Uint8Array(password.length + 56);
9405       hashData.set(password, 0);
9406       hashData.set(ownerValidationSalt, password.length);
9407       hashData.set(userBytes, password.length + ownerValidationSalt.length);
9408       var result = calculatePDF20Hash(password, hashData, userBytes);
9409       return compareByteArrays(result, ownerPassword);
9410     },
9411     checkUserPassword: function PDF20_checkUserPassword(password,
9412                                                         userValidationSalt,
9413                                                         userPassword) {
9414       var hashData = new Uint8Array(password.length + 8);
9415       hashData.set(password, 0);
9416       hashData.set(userValidationSalt, password.length);
9417       var result = calculatePDF20Hash(password, hashData, []);
9418       return compareByteArrays(result, userPassword);
9419     },
9420     getOwnerKey: function PDF20_getOwnerKey(password, ownerKeySalt, userBytes,
9421                                             ownerEncryption) {
9422       var hashData = new Uint8Array(password.length + 56);
9423       hashData.set(password, 0);
9424       hashData.set(ownerKeySalt, password.length);
9425       hashData.set(userBytes, password.length + ownerKeySalt.length);
9426       var key = calculatePDF20Hash(password, hashData, userBytes);
9427       var cipher = new AES256Cipher(key);
9428       return cipher.decryptBlock(ownerEncryption,
9429                                  false,
9430                                  new Uint8Array(16));
9431
9432     },
9433     getUserKey: function PDF20_getUserKey(password, userKeySalt,
9434                                           userEncryption) {
9435       var hashData = new Uint8Array(password.length + 8);
9436       hashData.set(password, 0);
9437       hashData.set(userKeySalt, password.length);
9438       //key is the decryption key for the UE string
9439       var key = calculatePDF20Hash(password, hashData, []);
9440       var cipher = new AES256Cipher(key);
9441       return cipher.decryptBlock(userEncryption,
9442                                  false,
9443                                  new Uint8Array(16));
9444     }
9445   };
9446   return PDF20;
9447 })();
9448
9449 var CipherTransform = (function CipherTransformClosure() {
9450   function CipherTransform(stringCipherConstructor, streamCipherConstructor) {
9451     this.stringCipherConstructor = stringCipherConstructor;
9452     this.streamCipherConstructor = streamCipherConstructor;
9453   }
9454
9455   CipherTransform.prototype = {
9456     createStream: function CipherTransform_createStream(stream, length) {
9457       var cipher = new this.streamCipherConstructor();
9458       return new DecryptStream(stream, length,
9459         function cipherTransformDecryptStream(data, finalize) {
9460           return cipher.decryptBlock(data, finalize);
9461         }
9462       );
9463     },
9464     decryptString: function CipherTransform_decryptString(s) {
9465       var cipher = new this.stringCipherConstructor();
9466       var data = stringToBytes(s);
9467       data = cipher.decryptBlock(data, true);
9468       return bytesToString(data);
9469     }
9470   };
9471   return CipherTransform;
9472 })();
9473
9474 var CipherTransformFactory = (function CipherTransformFactoryClosure() {
9475   var defaultPasswordBytes = new Uint8Array([
9476     0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
9477     0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
9478     0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
9479     0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
9480
9481   function createEncryptionKey20(revision, password, ownerPassword,
9482                                  ownerValidationSalt, ownerKeySalt, uBytes,
9483                                  userPassword, userValidationSalt, userKeySalt,
9484                                  ownerEncryption, userEncryption, perms) {
9485     if (password) {
9486       var passwordLength = Math.min(127, password.length);
9487       password = password.subarray(0, passwordLength);
9488     } else {
9489       password = [];
9490     }
9491     var pdfAlgorithm;
9492     if (revision === 6) {
9493       pdfAlgorithm = new PDF20();
9494     } else {
9495       pdfAlgorithm = new PDF17();
9496     }
9497
9498     if (pdfAlgorithm) {
9499       if (pdfAlgorithm.checkUserPassword(password, userValidationSalt,
9500                                          userPassword)) {
9501         return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption);
9502       } else if (pdfAlgorithm.checkOwnerPassword(password, ownerValidationSalt,
9503                                                  uBytes,
9504                                                  ownerPassword)) {
9505         return pdfAlgorithm.getOwnerKey(password, ownerKeySalt, uBytes,
9506                                         ownerEncryption);
9507       }
9508     }
9509
9510     return null;
9511   }
9512
9513   function prepareKeyData(fileId, password, ownerPassword, userPassword,
9514                           flags, revision, keyLength, encryptMetadata) {
9515     var hashDataSize = 40 + ownerPassword.length + fileId.length;
9516     var hashData = new Uint8Array(hashDataSize), i = 0, j, n;
9517     if (password) {
9518       n = Math.min(32, password.length);
9519       for (; i < n; ++i) {
9520         hashData[i] = password[i];
9521       }
9522     }
9523     j = 0;
9524     while (i < 32) {
9525       hashData[i++] = defaultPasswordBytes[j++];
9526     }
9527     // as now the padded password in the hashData[0..i]
9528     for (j = 0, n = ownerPassword.length; j < n; ++j) {
9529       hashData[i++] = ownerPassword[j];
9530     }
9531     hashData[i++] = flags & 0xFF;
9532     hashData[i++] = (flags >> 8) & 0xFF;
9533     hashData[i++] = (flags >> 16) & 0xFF;
9534     hashData[i++] = (flags >>> 24) & 0xFF;
9535     for (j = 0, n = fileId.length; j < n; ++j) {
9536       hashData[i++] = fileId[j];
9537     }
9538     if (revision >= 4 && !encryptMetadata) {
9539       hashData[i++] = 0xFF;
9540       hashData[i++] = 0xFF;
9541       hashData[i++] = 0xFF;
9542       hashData[i++] = 0xFF;
9543     }
9544     var hash = calculateMD5(hashData, 0, i);
9545     var keyLengthInBytes = keyLength >> 3;
9546     if (revision >= 3) {
9547       for (j = 0; j < 50; ++j) {
9548         hash = calculateMD5(hash, 0, keyLengthInBytes);
9549       }
9550     }
9551     var encryptionKey = hash.subarray(0, keyLengthInBytes);
9552     var cipher, checkData;
9553
9554     if (revision >= 3) {
9555       for (i = 0; i < 32; ++i) {
9556         hashData[i] = defaultPasswordBytes[i];
9557       }
9558       for (j = 0, n = fileId.length; j < n; ++j) {
9559         hashData[i++] = fileId[j];
9560       }
9561       cipher = new ARCFourCipher(encryptionKey);
9562       checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
9563       n = encryptionKey.length;
9564       var derivedKey = new Uint8Array(n), k;
9565       for (j = 1; j <= 19; ++j) {
9566         for (k = 0; k < n; ++k) {
9567           derivedKey[k] = encryptionKey[k] ^ j;
9568         }
9569         cipher = new ARCFourCipher(derivedKey);
9570         checkData = cipher.encryptBlock(checkData);
9571       }
9572       for (j = 0, n = checkData.length; j < n; ++j) {
9573         if (userPassword[j] !== checkData[j]) {
9574           return null;
9575         }
9576       }
9577     } else {
9578       cipher = new ARCFourCipher(encryptionKey);
9579       checkData = cipher.encryptBlock(defaultPasswordBytes);
9580       for (j = 0, n = checkData.length; j < n; ++j) {
9581         if (userPassword[j] !== checkData[j]) {
9582           return null;
9583         }
9584       }
9585     }
9586     return encryptionKey;
9587   }
9588
9589   function decodeUserPassword(password, ownerPassword, revision, keyLength) {
9590     var hashData = new Uint8Array(32), i = 0, j, n;
9591     n = Math.min(32, password.length);
9592     for (; i < n; ++i) {
9593       hashData[i] = password[i];
9594     }
9595     j = 0;
9596     while (i < 32) {
9597       hashData[i++] = defaultPasswordBytes[j++];
9598     }
9599     var hash = calculateMD5(hashData, 0, i);
9600     var keyLengthInBytes = keyLength >> 3;
9601     if (revision >= 3) {
9602       for (j = 0; j < 50; ++j) {
9603         hash = calculateMD5(hash, 0, hash.length);
9604       }
9605     }
9606
9607     var cipher, userPassword;
9608     if (revision >= 3) {
9609       userPassword = ownerPassword;
9610       var derivedKey = new Uint8Array(keyLengthInBytes), k;
9611       for (j = 19; j >= 0; j--) {
9612         for (k = 0; k < keyLengthInBytes; ++k) {
9613           derivedKey[k] = hash[k] ^ j;
9614         }
9615         cipher = new ARCFourCipher(derivedKey);
9616         userPassword = cipher.encryptBlock(userPassword);
9617       }
9618     } else {
9619       cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes));
9620       userPassword = cipher.encryptBlock(ownerPassword);
9621     }
9622     return userPassword;
9623   }
9624
9625   var identityName = Name.get('Identity');
9626
9627   function CipherTransformFactory(dict, fileId, password) {
9628     var filter = dict.get('Filter');
9629     if (!isName(filter) || filter.name !== 'Standard') {
9630       error('unknown encryption method');
9631     }
9632     this.dict = dict;
9633     var algorithm = dict.get('V');
9634     if (!isInt(algorithm) ||
9635         (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 &&
9636         algorithm !== 5)) {
9637       error('unsupported encryption algorithm');
9638     }
9639     this.algorithm = algorithm;
9640     var keyLength = dict.get('Length') || 40;
9641     if (!isInt(keyLength) ||
9642         keyLength < 40 || (keyLength % 8) !== 0) {
9643       error('invalid key length');
9644     }
9645
9646     // prepare keys
9647     var ownerPassword = stringToBytes(dict.get('O')).subarray(0, 32);
9648     var userPassword = stringToBytes(dict.get('U')).subarray(0, 32);
9649     var flags = dict.get('P');
9650     var revision = dict.get('R');
9651     // meaningful when V is 4 or 5
9652     var encryptMetadata = ((algorithm === 4 || algorithm === 5) &&
9653                            dict.get('EncryptMetadata') !== false);
9654     this.encryptMetadata = encryptMetadata;
9655
9656     var fileIdBytes = stringToBytes(fileId);
9657     var passwordBytes;
9658     if (password) {
9659       if (revision === 6) {
9660         try {
9661           password = utf8StringToString(password);
9662         } catch (ex) {
9663           warn('CipherTransformFactory: ' +
9664                'Unable to convert UTF8 encoded password.');
9665         }
9666       }
9667       passwordBytes = stringToBytes(password);
9668     }
9669
9670     var encryptionKey;
9671     if (algorithm !== 5) {
9672       encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
9673                                      ownerPassword, userPassword, flags,
9674                                      revision, keyLength, encryptMetadata);
9675     }
9676     else {
9677       var ownerValidationSalt = stringToBytes(dict.get('O')).subarray(32, 40);
9678       var ownerKeySalt = stringToBytes(dict.get('O')).subarray(40, 48);
9679       var uBytes = stringToBytes(dict.get('U')).subarray(0, 48);
9680       var userValidationSalt = stringToBytes(dict.get('U')).subarray(32, 40);
9681       var userKeySalt = stringToBytes(dict.get('U')).subarray(40, 48);
9682       var ownerEncryption = stringToBytes(dict.get('OE'));
9683       var userEncryption = stringToBytes(dict.get('UE'));
9684       var perms = stringToBytes(dict.get('Perms'));
9685       encryptionKey =
9686         createEncryptionKey20(revision, passwordBytes,
9687           ownerPassword, ownerValidationSalt,
9688           ownerKeySalt, uBytes,
9689           userPassword, userValidationSalt,
9690           userKeySalt, ownerEncryption,
9691           userEncryption, perms);
9692     }
9693     if (!encryptionKey && !password) {
9694       throw new PasswordException('No password given',
9695                                   PasswordResponses.NEED_PASSWORD);
9696     } else if (!encryptionKey && password) {
9697       // Attempting use the password as an owner password
9698       var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword,
9699                                                revision, keyLength);
9700       encryptionKey = prepareKeyData(fileIdBytes, decodedPassword,
9701                                      ownerPassword, userPassword, flags,
9702                                      revision, keyLength, encryptMetadata);
9703     }
9704
9705     if (!encryptionKey) {
9706       throw new PasswordException('Incorrect Password',
9707                                   PasswordResponses.INCORRECT_PASSWORD);
9708     }
9709
9710     this.encryptionKey = encryptionKey;
9711
9712     if (algorithm >= 4) {
9713       this.cf = dict.get('CF');
9714       this.stmf = dict.get('StmF') || identityName;
9715       this.strf = dict.get('StrF') || identityName;
9716       this.eff = dict.get('EFF') || this.stmf;
9717     }
9718   }
9719
9720   function buildObjectKey(num, gen, encryptionKey, isAes) {
9721     var key = new Uint8Array(encryptionKey.length + 9), i, n;
9722     for (i = 0, n = encryptionKey.length; i < n; ++i) {
9723       key[i] = encryptionKey[i];
9724     }
9725     key[i++] = num & 0xFF;
9726     key[i++] = (num >> 8) & 0xFF;
9727     key[i++] = (num >> 16) & 0xFF;
9728     key[i++] = gen & 0xFF;
9729     key[i++] = (gen >> 8) & 0xFF;
9730     if (isAes) {
9731       key[i++] = 0x73;
9732       key[i++] = 0x41;
9733       key[i++] = 0x6C;
9734       key[i++] = 0x54;
9735     }
9736     var hash = calculateMD5(key, 0, i);
9737     return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
9738   }
9739
9740   function buildCipherConstructor(cf, name, num, gen, key) {
9741     var cryptFilter = cf.get(name.name);
9742     var cfm;
9743     if (cryptFilter !== null && cryptFilter !== undefined) {
9744       cfm = cryptFilter.get('CFM');
9745     }
9746     if (!cfm || cfm.name === 'None') {
9747       return function cipherTransformFactoryBuildCipherConstructorNone() {
9748         return new NullCipher();
9749       };
9750     }
9751     if ('V2' === cfm.name) {
9752       return function cipherTransformFactoryBuildCipherConstructorV2() {
9753         return new ARCFourCipher(buildObjectKey(num, gen, key, false));
9754       };
9755     }
9756     if ('AESV2' === cfm.name) {
9757       return function cipherTransformFactoryBuildCipherConstructorAESV2() {
9758         return new AES128Cipher(buildObjectKey(num, gen, key, true));
9759       };
9760     }
9761     if ('AESV3' === cfm.name) {
9762       return function cipherTransformFactoryBuildCipherConstructorAESV3() {
9763         return new AES256Cipher(key);
9764       };
9765     }
9766     error('Unknown crypto method');
9767   }
9768
9769   CipherTransformFactory.prototype = {
9770     createCipherTransform:
9771         function CipherTransformFactory_createCipherTransform(num, gen) {
9772       if (this.algorithm === 4 || this.algorithm === 5) {
9773         return new CipherTransform(
9774           buildCipherConstructor(this.cf, this.stmf,
9775                                  num, gen, this.encryptionKey),
9776           buildCipherConstructor(this.cf, this.strf,
9777                                  num, gen, this.encryptionKey));
9778       }
9779       // algorithms 1 and 2
9780       var key = buildObjectKey(num, gen, this.encryptionKey, false);
9781       var cipherConstructor = function buildCipherCipherConstructor() {
9782         return new ARCFourCipher(key);
9783       };
9784       return new CipherTransform(cipherConstructor, cipherConstructor);
9785     }
9786   };
9787
9788   return CipherTransformFactory;
9789 })();
9790
9791
9792 var PatternType = {
9793   FUNCTION_BASED: 1,
9794   AXIAL: 2,
9795   RADIAL: 3,
9796   FREE_FORM_MESH: 4,
9797   LATTICE_FORM_MESH: 5,
9798   COONS_PATCH_MESH: 6,
9799   TENSOR_PATCH_MESH: 7
9800 };
9801
9802 var Pattern = (function PatternClosure() {
9803   // Constructor should define this.getPattern
9804   function Pattern() {
9805     error('should not call Pattern constructor');
9806   }
9807
9808   Pattern.prototype = {
9809     // Input: current Canvas context
9810     // Output: the appropriate fillStyle or strokeStyle
9811     getPattern: function Pattern_getPattern(ctx) {
9812       error('Should not call Pattern.getStyle: ' + ctx);
9813     }
9814   };
9815
9816   Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref,
9817                                                        res) {
9818
9819     var dict = isStream(shading) ? shading.dict : shading;
9820     var type = dict.get('ShadingType');
9821
9822     try {
9823       switch (type) {
9824         case PatternType.AXIAL:
9825         case PatternType.RADIAL:
9826           // Both radial and axial shadings are handled by RadialAxial shading.
9827           return new Shadings.RadialAxial(dict, matrix, xref, res);
9828         case PatternType.FREE_FORM_MESH:
9829         case PatternType.LATTICE_FORM_MESH:
9830         case PatternType.COONS_PATCH_MESH:
9831         case PatternType.TENSOR_PATCH_MESH:
9832           return new Shadings.Mesh(shading, matrix, xref, res);
9833         default:
9834           throw new Error('Unknown PatternType: ' + type);
9835       }
9836     } catch (ex) {
9837       if (ex instanceof MissingDataException) {
9838         throw ex;
9839       }
9840       UnsupportedManager.notify(UNSUPPORTED_FEATURES.shadingPattern);
9841       warn(ex);
9842       return new Shadings.Dummy();
9843     }
9844   };
9845   return Pattern;
9846 })();
9847
9848 var Shadings = {};
9849
9850 // A small number to offset the first/last color stops so we can insert ones to
9851 // support extend.  Number.MIN_VALUE appears to be too small and breaks the
9852 // extend. 1e-7 works in FF but chrome seems to use an even smaller sized number
9853 // internally so we have to go bigger.
9854 Shadings.SMALL_NUMBER = 1e-2;
9855
9856 // Radial and axial shading have very similar implementations
9857 // If needed, the implementations can be broken into two classes
9858 Shadings.RadialAxial = (function RadialAxialClosure() {
9859   function RadialAxial(dict, matrix, xref, res) {
9860     this.matrix = matrix;
9861     this.coordsArr = dict.get('Coords');
9862     this.shadingType = dict.get('ShadingType');
9863     this.type = 'Pattern';
9864     var cs = dict.get('ColorSpace', 'CS');
9865     cs = ColorSpace.parse(cs, xref, res);
9866     this.cs = cs;
9867
9868     var t0 = 0.0, t1 = 1.0;
9869     if (dict.has('Domain')) {
9870       var domainArr = dict.get('Domain');
9871       t0 = domainArr[0];
9872       t1 = domainArr[1];
9873     }
9874
9875     var extendStart = false, extendEnd = false;
9876     if (dict.has('Extend')) {
9877       var extendArr = dict.get('Extend');
9878       extendStart = extendArr[0];
9879       extendEnd = extendArr[1];
9880     }
9881
9882     if (this.shadingType === PatternType.RADIAL &&
9883        (!extendStart || !extendEnd)) {
9884       // Radial gradient only currently works if either circle is fully within
9885       // the other circle.
9886       var x1 = this.coordsArr[0];
9887       var y1 = this.coordsArr[1];
9888       var r1 = this.coordsArr[2];
9889       var x2 = this.coordsArr[3];
9890       var y2 = this.coordsArr[4];
9891       var r2 = this.coordsArr[5];
9892       var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
9893       if (r1 <= r2 + distance &&
9894           r2 <= r1 + distance) {
9895         warn('Unsupported radial gradient.');
9896       }
9897     }
9898
9899     this.extendStart = extendStart;
9900     this.extendEnd = extendEnd;
9901
9902     var fnObj = dict.get('Function');
9903     var fn = PDFFunction.parseArray(xref, fnObj);
9904
9905     // 10 samples seems good enough for now, but probably won't work
9906     // if there are sharp color changes. Ideally, we would implement
9907     // the spec faithfully and add lossless optimizations.
9908     var diff = t1 - t0;
9909     var step = diff / 10;
9910
9911     var colorStops = this.colorStops = [];
9912
9913     // Protect against bad domains so we don't end up in an infinte loop below.
9914     if (t0 >= t1 || step <= 0) {
9915       // Acrobat doesn't seem to handle these cases so we'll ignore for
9916       // now.
9917       info('Bad shading domain.');
9918       return;
9919     }
9920
9921     var color = new Float32Array(cs.numComps), ratio = new Float32Array(1);
9922     var rgbColor;
9923     for (var i = t0; i <= t1; i += step) {
9924       ratio[0] = i;
9925       fn(ratio, 0, color, 0);
9926       rgbColor = cs.getRgb(color, 0);
9927       var cssColor = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
9928       colorStops.push([(i - t0) / diff, cssColor]);
9929     }
9930
9931     var background = 'transparent';
9932     if (dict.has('Background')) {
9933       rgbColor = cs.getRgb(dict.get('Background'), 0);
9934       background = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
9935     }
9936
9937     if (!extendStart) {
9938       // Insert a color stop at the front and offset the first real color stop
9939       // so it doesn't conflict with the one we insert.
9940       colorStops.unshift([0, background]);
9941       colorStops[1][0] += Shadings.SMALL_NUMBER;
9942     }
9943     if (!extendEnd) {
9944       // Same idea as above in extendStart but for the end.
9945       colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER;
9946       colorStops.push([1, background]);
9947     }
9948
9949     this.colorStops = colorStops;
9950   }
9951
9952   RadialAxial.prototype = {
9953     getIR: function RadialAxial_getIR() {
9954       var coordsArr = this.coordsArr;
9955       var shadingType = this.shadingType;
9956       var type, p0, p1, r0, r1;
9957       if (shadingType === PatternType.AXIAL) {
9958         p0 = [coordsArr[0], coordsArr[1]];
9959         p1 = [coordsArr[2], coordsArr[3]];
9960         r0 = null;
9961         r1 = null;
9962         type = 'axial';
9963       } else if (shadingType === PatternType.RADIAL) {
9964         p0 = [coordsArr[0], coordsArr[1]];
9965         p1 = [coordsArr[3], coordsArr[4]];
9966         r0 = coordsArr[2];
9967         r1 = coordsArr[5];
9968         type = 'radial';
9969       } else {
9970         error('getPattern type unknown: ' + shadingType);
9971       }
9972
9973       var matrix = this.matrix;
9974       if (matrix) {
9975         p0 = Util.applyTransform(p0, matrix);
9976         p1 = Util.applyTransform(p1, matrix);
9977       }
9978
9979       return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
9980     }
9981   };
9982
9983   return RadialAxial;
9984 })();
9985
9986 // All mesh shading. For now, they will be presented as set of the triangles
9987 // to be drawn on the canvas and rgb color for each vertex.
9988 Shadings.Mesh = (function MeshClosure() {
9989   function MeshStreamReader(stream, context) {
9990     this.stream = stream;
9991     this.context = context;
9992     this.buffer = 0;
9993     this.bufferLength = 0;
9994
9995     var numComps = context.numComps;
9996     this.tmpCompsBuf = new Float32Array(numComps);
9997     var csNumComps = context.colorSpace;
9998     this.tmpCsCompsBuf = context.colorFn ? new Float32Array(csNumComps) :
9999                                            this.tmpCompsBuf;
10000   }
10001   MeshStreamReader.prototype = {
10002     get hasData() {
10003       if (this.stream.end) {
10004         return this.stream.pos < this.stream.end;
10005       }
10006       if (this.bufferLength > 0) {
10007         return true;
10008       }
10009       var nextByte = this.stream.getByte();
10010       if (nextByte < 0) {
10011         return false;
10012       }
10013       this.buffer = nextByte;
10014       this.bufferLength = 8;
10015       return true;
10016     },
10017     readBits: function MeshStreamReader_readBits(n) {
10018       var buffer = this.buffer;
10019       var bufferLength = this.bufferLength;
10020       if (n === 32) {
10021         if (bufferLength === 0) {
10022           return ((this.stream.getByte() << 24) |
10023             (this.stream.getByte() << 16) | (this.stream.getByte() << 8) |
10024             this.stream.getByte()) >>> 0;
10025         }
10026         buffer = (buffer << 24) | (this.stream.getByte() << 16) |
10027           (this.stream.getByte() << 8) | this.stream.getByte();
10028         var nextByte = this.stream.getByte();
10029         this.buffer = nextByte & ((1 << bufferLength) - 1);
10030         return ((buffer << (8 - bufferLength)) |
10031           ((nextByte & 0xFF) >> bufferLength)) >>> 0;
10032       }
10033       if (n === 8 && bufferLength === 0) {
10034         return this.stream.getByte();
10035       }
10036       while (bufferLength < n) {
10037         buffer = (buffer << 8) | this.stream.getByte();
10038         bufferLength += 8;
10039       }
10040       bufferLength -= n;
10041       this.bufferLength = bufferLength;
10042       this.buffer = buffer & ((1 << bufferLength) - 1);
10043       return buffer >> bufferLength;
10044     },
10045     align: function MeshStreamReader_align() {
10046       this.buffer = 0;
10047       this.bufferLength = 0;
10048     },
10049     readFlag: function MeshStreamReader_readFlag() {
10050       return this.readBits(this.context.bitsPerFlag);
10051     },
10052     readCoordinate: function MeshStreamReader_readCoordinate() {
10053       var bitsPerCoordinate = this.context.bitsPerCoordinate;
10054       var xi = this.readBits(bitsPerCoordinate);
10055       var yi = this.readBits(bitsPerCoordinate);
10056       var decode = this.context.decode;
10057       var scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) :
10058         2.3283064365386963e-10; // 2 ^ -32
10059       return [
10060         xi * scale * (decode[1] - decode[0]) + decode[0],
10061         yi * scale * (decode[3] - decode[2]) + decode[2]
10062       ];
10063     },
10064     readComponents: function MeshStreamReader_readComponents() {
10065       var numComps = this.context.numComps;
10066       var bitsPerComponent = this.context.bitsPerComponent;
10067       var scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) :
10068         2.3283064365386963e-10; // 2 ^ -32
10069       var decode = this.context.decode;
10070       var components = this.tmpCompsBuf;
10071       for (var i = 0, j = 4; i < numComps; i++, j += 2) {
10072         var ci = this.readBits(bitsPerComponent);
10073         components[i] = ci * scale * (decode[j + 1] - decode[j]) + decode[j];
10074       }
10075       var color = this.tmpCsCompsBuf;
10076       if (this.context.colorFn) {
10077         this.context.colorFn(components, 0, color, 0);
10078       }
10079       return this.context.colorSpace.getRgb(color, 0);
10080     }
10081   };
10082
10083   function decodeType4Shading(mesh, reader) {
10084     var coords = mesh.coords;
10085     var colors = mesh.colors;
10086     var operators = [];
10087     var ps = []; // not maintaining cs since that will match ps
10088     var verticesLeft = 0; // assuming we have all data to start a new triangle
10089     while (reader.hasData) {
10090       var f = reader.readFlag();
10091       var coord = reader.readCoordinate();
10092       var color = reader.readComponents();
10093       if (verticesLeft === 0) { // ignoring flags if we started a triangle
10094         assert(0 <= f && f <= 2, 'Unknown type4 flag');
10095         switch (f) {
10096           case 0:
10097             verticesLeft = 3;
10098             break;
10099           case 1:
10100             ps.push(ps[ps.length - 2], ps[ps.length - 1]);
10101             verticesLeft = 1;
10102             break;
10103           case 2:
10104             ps.push(ps[ps.length - 3], ps[ps.length - 1]);
10105             verticesLeft = 1;
10106             break;
10107         }
10108         operators.push(f);
10109       }
10110       ps.push(coords.length);
10111       coords.push(coord);
10112       colors.push(color);
10113       verticesLeft--;
10114
10115       reader.align();
10116     }
10117
10118     var psPacked = new Int32Array(ps);
10119
10120     mesh.figures.push({
10121       type: 'triangles',
10122       coords: psPacked,
10123       colors: psPacked
10124     });
10125   }
10126
10127   function decodeType5Shading(mesh, reader, verticesPerRow) {
10128     var coords = mesh.coords;
10129     var colors = mesh.colors;
10130     var ps = []; // not maintaining cs since that will match ps
10131     while (reader.hasData) {
10132       var coord = reader.readCoordinate();
10133       var color = reader.readComponents();
10134       ps.push(coords.length);
10135       coords.push(coord);
10136       colors.push(color);
10137     }
10138
10139     var psPacked = new Int32Array(ps);
10140
10141     mesh.figures.push({
10142       type: 'lattice',
10143       coords: psPacked,
10144       colors: psPacked,
10145       verticesPerRow: verticesPerRow
10146     });
10147   }
10148
10149   var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3;
10150   var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20;
10151
10152   var TRIANGLE_DENSITY = 20; // count of triangles per entire mesh bounds
10153
10154   var getB = (function getBClosure() {
10155     function buildB(count) {
10156       var lut = [];
10157       for (var i = 0; i <= count; i++) {
10158         var t = i / count, t_ = 1 - t;
10159         lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_,
10160           3 * t * t * t_, t * t * t]));
10161       }
10162       return lut;
10163     }
10164     var cache = [];
10165     return function getB(count) {
10166       if (!cache[count]) {
10167         cache[count] = buildB(count);
10168       }
10169       return cache[count];
10170     };
10171   })();
10172
10173   function buildFigureFromPatch(mesh, index) {
10174     var figure = mesh.figures[index];
10175     assert(figure.type === 'patch', 'Unexpected patch mesh figure');
10176
10177     var coords = mesh.coords, colors = mesh.colors;
10178     var pi = figure.coords;
10179     var ci = figure.colors;
10180
10181     var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0],
10182                               coords[pi[12]][0], coords[pi[15]][0]);
10183     var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1],
10184                               coords[pi[12]][1], coords[pi[15]][1]);
10185     var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0],
10186                               coords[pi[12]][0], coords[pi[15]][0]);
10187     var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1],
10188                               coords[pi[12]][1], coords[pi[15]][1]);
10189     var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY /
10190                              (mesh.bounds[2] - mesh.bounds[0]));
10191     splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
10192                Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy));
10193     var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY /
10194                              (mesh.bounds[3] - mesh.bounds[1]));
10195     splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
10196                Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy));
10197
10198     var verticesPerRow = splitXBy + 1;
10199     var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow);
10200     var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow);
10201     var k = 0;
10202     var cl = new Uint8Array(3), cr = new Uint8Array(3);
10203     var c0 = colors[ci[0]], c1 = colors[ci[1]],
10204       c2 = colors[ci[2]], c3 = colors[ci[3]];
10205     var bRow = getB(splitYBy), bCol = getB(splitXBy);
10206     for (var row = 0; row <= splitYBy; row++) {
10207       cl[0] = ((c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy) | 0;
10208       cl[1] = ((c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy) | 0;
10209       cl[2] = ((c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy) | 0;
10210
10211       cr[0] = ((c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy) | 0;
10212       cr[1] = ((c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy) | 0;
10213       cr[2] = ((c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy) | 0;
10214
10215       for (var col = 0; col <= splitXBy; col++, k++) {
10216         if ((row === 0 || row === splitYBy) &&
10217             (col === 0 || col === splitXBy)) {
10218           continue;
10219         }
10220         var x = 0, y = 0;
10221         var q = 0;
10222         for (var i = 0; i <= 3; i++) {
10223           for (var j = 0; j <= 3; j++, q++) {
10224             var m = bRow[row][i] * bCol[col][j];
10225             x += coords[pi[q]][0] * m;
10226             y += coords[pi[q]][1] * m;
10227           }
10228         }
10229         figureCoords[k] = coords.length;
10230         coords.push([x, y]);
10231         figureColors[k] = colors.length;
10232         var newColor = new Uint8Array(3);
10233         newColor[0] = ((cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy) | 0;
10234         newColor[1] = ((cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy) | 0;
10235         newColor[2] = ((cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy) | 0;
10236         colors.push(newColor);
10237       }
10238     }
10239     figureCoords[0] = pi[0];
10240     figureColors[0] = ci[0];
10241     figureCoords[splitXBy] = pi[3];
10242     figureColors[splitXBy] = ci[1];
10243     figureCoords[verticesPerRow * splitYBy] = pi[12];
10244     figureColors[verticesPerRow * splitYBy] = ci[2];
10245     figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15];
10246     figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3];
10247
10248     mesh.figures[index] = {
10249       type: 'lattice',
10250       coords: figureCoords,
10251       colors: figureColors,
10252       verticesPerRow: verticesPerRow
10253     };
10254   }
10255
10256   function decodeType6Shading(mesh, reader) {
10257     // A special case of Type 7. The p11, p12, p21, p22 automatically filled
10258     var coords = mesh.coords;
10259     var colors = mesh.colors;
10260     var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33
10261     var cs = new Int32Array(4); // c00, c30, c03, c33
10262     while (reader.hasData) {
10263       var f = reader.readFlag();
10264       assert(0 <= f && f <= 3, 'Unknown type6 flag');
10265       var i, ii;
10266       var pi = coords.length;
10267       for (i = 0, ii = (f !== 0 ? 8 : 12); i < ii; i++) {
10268         coords.push(reader.readCoordinate());
10269       }
10270       var ci = colors.length;
10271       for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
10272         colors.push(reader.readComponents());
10273       }
10274       var tmp1, tmp2, tmp3, tmp4;
10275       switch (f) {
10276         case 0:
10277           ps[12] = pi + 3; ps[13] = pi + 4;  ps[14] = pi + 5;  ps[15] = pi + 6;
10278           ps[ 8] = pi + 2; /* values for 5, 6, 9, 10 are    */ ps[11] = pi + 7;
10279           ps[ 4] = pi + 1; /* calculated below              */ ps[ 7] = pi + 8;
10280           ps[ 0] = pi;     ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;
10281           cs[2] = ci + 1; cs[3] = ci + 2;
10282           cs[0] = ci;     cs[1] = ci + 3;
10283           break;
10284         case 1:
10285           tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
10286           ps[12] = pi + 5; ps[13] = pi + 4;  ps[14] = pi + 3;  ps[15] = pi + 2;
10287           ps[ 8] = pi + 6; /* values for 5, 6, 9, 10 are    */ ps[11] = pi + 1;
10288           ps[ 4] = pi + 7; /* calculated below              */ ps[ 7] = pi;
10289           ps[ 0] = tmp1;   ps[ 1] = tmp2;    ps[ 2] = tmp3;    ps[ 3] = tmp4;
10290           tmp1 = cs[2]; tmp2 = cs[3];
10291           cs[2] = ci + 1; cs[3] = ci;
10292           cs[0] = tmp1;   cs[1] = tmp2;
10293           break;
10294         case 2:
10295           ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6;   ps[15] = pi + 5;
10296           ps[ 8] = ps[11]; /* values for 5, 6, 9, 10 are    */ ps[11] = pi + 4;
10297           ps[ 4] = ps[7];  /* calculated below              */ ps[ 7] = pi + 3;
10298           ps[ 0] = ps[3];  ps[ 1] = pi;     ps[ 2] = pi + 1;   ps[ 3] = pi + 2;
10299           cs[2] = cs[3]; cs[3] = ci + 1;
10300           cs[0] = cs[1]; cs[1] = ci;
10301           break;
10302         case 3:
10303           ps[12] = ps[0];  ps[13] = ps[1];   ps[14] = ps[2];   ps[15] = ps[3];
10304           ps[ 8] = pi;     /* values for 5, 6, 9, 10 are    */ ps[11] = pi + 7;
10305           ps[ 4] = pi + 1; /* calculated below              */ ps[ 7] = pi + 6;
10306           ps[ 0] = pi + 2; ps[ 1] = pi + 3;  ps[ 2] = pi + 4;  ps[ 3] = pi + 5;
10307           cs[2] = cs[0]; cs[3] = cs[1];
10308           cs[0] = ci;    cs[1] = ci + 1;
10309           break;
10310       }
10311       // set p11, p12, p21, p22
10312       ps[5] = coords.length;
10313       coords.push([
10314         (-4 * coords[ps[0]][0] - coords[ps[15]][0] +
10315           6 * (coords[ps[4]][0] + coords[ps[1]][0]) -
10316           2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
10317           3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9,
10318         (-4 * coords[ps[0]][1] - coords[ps[15]][1] +
10319           6 * (coords[ps[4]][1] + coords[ps[1]][1]) -
10320           2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
10321           3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9
10322       ]);
10323       ps[6] = coords.length;
10324       coords.push([
10325         (-4 * coords[ps[3]][0] - coords[ps[12]][0] +
10326           6 * (coords[ps[2]][0] + coords[ps[7]][0]) -
10327           2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
10328           3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9,
10329         (-4 * coords[ps[3]][1] - coords[ps[12]][1] +
10330           6 * (coords[ps[2]][1] + coords[ps[7]][1]) -
10331           2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
10332           3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9
10333       ]);
10334       ps[9] = coords.length;
10335       coords.push([
10336         (-4 * coords[ps[12]][0] - coords[ps[3]][0] +
10337           6 * (coords[ps[8]][0] + coords[ps[13]][0]) -
10338           2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
10339           3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9,
10340         (-4 * coords[ps[12]][1] - coords[ps[3]][1] +
10341           6 * (coords[ps[8]][1] + coords[ps[13]][1]) -
10342           2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
10343           3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9
10344       ]);
10345       ps[10] = coords.length;
10346       coords.push([
10347         (-4 * coords[ps[15]][0] - coords[ps[0]][0] +
10348           6 * (coords[ps[11]][0] + coords[ps[14]][0]) -
10349           2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
10350           3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9,
10351         (-4 * coords[ps[15]][1] - coords[ps[0]][1] +
10352           6 * (coords[ps[11]][1] + coords[ps[14]][1]) -
10353           2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
10354           3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9
10355       ]);
10356       mesh.figures.push({
10357         type: 'patch',
10358         coords: new Int32Array(ps), // making copies of ps and cs
10359         colors: new Int32Array(cs)
10360       });
10361     }
10362   }
10363
10364   function decodeType7Shading(mesh, reader) {
10365     var coords = mesh.coords;
10366     var colors = mesh.colors;
10367     var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33
10368     var cs = new Int32Array(4); // c00, c30, c03, c33
10369     while (reader.hasData) {
10370       var f = reader.readFlag();
10371       assert(0 <= f && f <= 3, 'Unknown type7 flag');
10372       var i, ii;
10373       var pi = coords.length;
10374       for (i = 0, ii = (f !== 0 ? 12 : 16); i < ii; i++) {
10375         coords.push(reader.readCoordinate());
10376       }
10377       var ci = colors.length;
10378       for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
10379         colors.push(reader.readComponents());
10380       }
10381       var tmp1, tmp2, tmp3, tmp4;
10382       switch (f) {
10383         case 0:
10384           ps[12] = pi + 3; ps[13] = pi + 4;  ps[14] = pi + 5;  ps[15] = pi + 6;
10385           ps[ 8] = pi + 2; ps[ 9] = pi + 13; ps[10] = pi + 14; ps[11] = pi + 7;
10386           ps[ 4] = pi + 1; ps[ 5] = pi + 12; ps[ 6] = pi + 15; ps[ 7] = pi + 8;
10387           ps[ 0] = pi;     ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;
10388           cs[2] = ci + 1; cs[3] = ci + 2;
10389           cs[0] = ci;     cs[1] = ci + 3;
10390           break;
10391         case 1:
10392           tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
10393           ps[12] = pi + 5; ps[13] = pi + 4;  ps[14] = pi + 3;  ps[15] = pi + 2;
10394           ps[ 8] = pi + 6; ps[ 9] = pi + 11; ps[10] = pi + 10; ps[11] = pi + 1;
10395           ps[ 4] = pi + 7; ps[ 5] = pi + 8;  ps[ 6] = pi + 9;  ps[ 7] = pi;
10396           ps[ 0] = tmp1;   ps[ 1] = tmp2;    ps[ 2] = tmp3;    ps[ 3] = tmp4;
10397           tmp1 = cs[2]; tmp2 = cs[3];
10398           cs[2] = ci + 1; cs[3] = ci;
10399           cs[0] = tmp1;   cs[1] = tmp2;
10400           break;
10401         case 2:
10402           ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6;  ps[15] = pi + 5;
10403           ps[ 8] = ps[11]; ps[ 9] = pi + 8; ps[10] = pi + 11; ps[11] = pi + 4;
10404           ps[ 4] = ps[7];  ps[ 5] = pi + 9; ps[ 6] = pi + 10; ps[ 7] = pi + 3;
10405           ps[ 0] = ps[3];  ps[ 1] = pi;     ps[ 2] = pi + 1;  ps[ 3] = pi + 2;
10406           cs[2] = cs[3]; cs[3] = ci + 1;
10407           cs[0] = cs[1]; cs[1] = ci;
10408           break;
10409         case 3:
10410           ps[12] = ps[0];  ps[13] = ps[1];   ps[14] = ps[2];   ps[15] = ps[3];
10411           ps[ 8] = pi;     ps[ 9] = pi + 9;  ps[10] = pi + 8;  ps[11] = pi + 7;
10412           ps[ 4] = pi + 1; ps[ 5] = pi + 10; ps[ 6] = pi + 11; ps[ 7] = pi + 6;
10413           ps[ 0] = pi + 2; ps[ 1] = pi + 3;  ps[ 2] = pi + 4;  ps[ 3] = pi + 5;
10414           cs[2] = cs[0]; cs[3] = cs[1];
10415           cs[0] = ci;    cs[1] = ci + 1;
10416           break;
10417       }
10418       mesh.figures.push({
10419         type: 'patch',
10420         coords: new Int32Array(ps), // making copies of ps and cs
10421         colors: new Int32Array(cs)
10422       });
10423     }
10424   }
10425
10426   function updateBounds(mesh) {
10427     var minX = mesh.coords[0][0], minY = mesh.coords[0][1],
10428       maxX = minX, maxY = minY;
10429     for (var i = 1, ii = mesh.coords.length; i < ii; i++) {
10430       var x = mesh.coords[i][0], y = mesh.coords[i][1];
10431       minX = minX > x ? x : minX;
10432       minY = minY > y ? y : minY;
10433       maxX = maxX < x ? x : maxX;
10434       maxY = maxY < y ? y : maxY;
10435     }
10436     mesh.bounds = [minX, minY, maxX, maxY];
10437   }
10438
10439   function packData(mesh) {
10440     var i, ii, j, jj;
10441
10442     var coords = mesh.coords;
10443     var coordsPacked = new Float32Array(coords.length * 2);
10444     for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
10445       var xy = coords[i];
10446       coordsPacked[j++] = xy[0];
10447       coordsPacked[j++] = xy[1];
10448     }
10449     mesh.coords = coordsPacked;
10450
10451     var colors = mesh.colors;
10452     var colorsPacked = new Uint8Array(colors.length * 3);
10453     for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
10454       var c = colors[i];
10455       colorsPacked[j++] = c[0];
10456       colorsPacked[j++] = c[1];
10457       colorsPacked[j++] = c[2];
10458     }
10459     mesh.colors = colorsPacked;
10460
10461     var figures = mesh.figures;
10462     for (i = 0, ii = figures.length; i < ii; i++) {
10463       var figure = figures[i], ps = figure.coords, cs = figure.colors;
10464       for (j = 0, jj = ps.length; j < jj; j++) {
10465         ps[j] *= 2;
10466         cs[j] *= 3;
10467       }
10468     }
10469   }
10470
10471   function Mesh(stream, matrix, xref, res) {
10472     assert(isStream(stream), 'Mesh data is not a stream');
10473     var dict = stream.dict;
10474     this.matrix = matrix;
10475     this.shadingType = dict.get('ShadingType');
10476     this.type = 'Pattern';
10477     this.bbox = dict.get('BBox');
10478     var cs = dict.get('ColorSpace', 'CS');
10479     cs = ColorSpace.parse(cs, xref, res);
10480     this.cs = cs;
10481     this.background = dict.has('Background') ?
10482       cs.getRgb(dict.get('Background'), 0) : null;
10483
10484     var fnObj = dict.get('Function');
10485     var fn = fnObj ? PDFFunction.parseArray(xref, fnObj) : null;
10486
10487     this.coords = [];
10488     this.colors = [];
10489     this.figures = [];
10490
10491     var decodeContext = {
10492       bitsPerCoordinate: dict.get('BitsPerCoordinate'),
10493       bitsPerComponent: dict.get('BitsPerComponent'),
10494       bitsPerFlag: dict.get('BitsPerFlag'),
10495       decode: dict.get('Decode'),
10496       colorFn: fn,
10497       colorSpace: cs,
10498       numComps: fn ? 1 : cs.numComps
10499     };
10500     var reader = new MeshStreamReader(stream, decodeContext);
10501
10502     var patchMesh = false;
10503     switch (this.shadingType) {
10504       case PatternType.FREE_FORM_MESH:
10505         decodeType4Shading(this, reader);
10506         break;
10507       case PatternType.LATTICE_FORM_MESH:
10508         var verticesPerRow = dict.get('VerticesPerRow') | 0;
10509         assert(verticesPerRow >= 2, 'Invalid VerticesPerRow');
10510         decodeType5Shading(this, reader, verticesPerRow);
10511         break;
10512       case PatternType.COONS_PATCH_MESH:
10513         decodeType6Shading(this, reader);
10514         patchMesh = true;
10515         break;
10516       case PatternType.TENSOR_PATCH_MESH:
10517         decodeType7Shading(this, reader);
10518         patchMesh = true;
10519         break;
10520       default:
10521         error('Unsupported mesh type.');
10522         break;
10523     }
10524
10525     if (patchMesh) {
10526       // dirty bounds calculation for determining, how dense shall be triangles
10527       updateBounds(this);
10528       for (var i = 0, ii = this.figures.length; i < ii; i++) {
10529         buildFigureFromPatch(this, i);
10530       }
10531     }
10532     // calculate bounds
10533     updateBounds(this);
10534
10535     packData(this);
10536   }
10537
10538   Mesh.prototype = {
10539     getIR: function Mesh_getIR() {
10540       return ['Mesh', this.shadingType, this.coords, this.colors, this.figures,
10541         this.bounds, this.matrix, this.bbox, this.background];
10542     }
10543   };
10544
10545   return Mesh;
10546 })();
10547
10548 Shadings.Dummy = (function DummyClosure() {
10549   function Dummy() {
10550     this.type = 'Pattern';
10551   }
10552
10553   Dummy.prototype = {
10554     getIR: function Dummy_getIR() {
10555       return ['Dummy'];
10556     }
10557   };
10558   return Dummy;
10559 })();
10560
10561 function getTilingPatternIR(operatorList, dict, args) {
10562   var matrix = dict.get('Matrix');
10563   var bbox = dict.get('BBox');
10564   var xstep = dict.get('XStep');
10565   var ystep = dict.get('YStep');
10566   var paintType = dict.get('PaintType');
10567   var tilingType = dict.get('TilingType');
10568
10569   return [
10570     'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,
10571     paintType, tilingType
10572   ];
10573 }
10574
10575
10576 var PartialEvaluator = (function PartialEvaluatorClosure() {
10577   function PartialEvaluator(pdfManager, xref, handler, pageIndex,
10578                             uniquePrefix, idCounters, fontCache) {
10579     this.pdfManager = pdfManager;
10580     this.xref = xref;
10581     this.handler = handler;
10582     this.pageIndex = pageIndex;
10583     this.uniquePrefix = uniquePrefix;
10584     this.idCounters = idCounters;
10585     this.fontCache = fontCache;
10586   }
10587
10588   // Trying to minimize Date.now() usage and check every 100 time
10589   var TIME_SLOT_DURATION_MS = 20;
10590   var CHECK_TIME_EVERY = 100;
10591   function TimeSlotManager() {
10592     this.reset();
10593   }
10594   TimeSlotManager.prototype = {
10595     check: function TimeSlotManager_check() {
10596       if (++this.checked < CHECK_TIME_EVERY) {
10597         return false;
10598       }
10599       this.checked = 0;
10600       return this.endTime <= Date.now();
10601     },
10602     reset: function TimeSlotManager_reset() {
10603       this.endTime = Date.now() + TIME_SLOT_DURATION_MS;
10604       this.checked = 0;
10605     }
10606   };
10607
10608   var deferred = Promise.resolve();
10609
10610   var TILING_PATTERN = 1, SHADING_PATTERN = 2;
10611
10612   PartialEvaluator.prototype = {
10613     hasBlendModes: function PartialEvaluator_hasBlendModes(resources) {
10614       if (!isDict(resources)) {
10615         return false;
10616       }
10617
10618       var processed = Object.create(null);
10619       if (resources.objId) {
10620         processed[resources.objId] = true;
10621       }
10622
10623       var nodes = [resources];
10624       while (nodes.length) {
10625         var key;
10626         var node = nodes.shift();
10627         // First check the current resources for blend modes.
10628         var graphicStates = node.get('ExtGState');
10629         if (isDict(graphicStates)) {
10630           graphicStates = graphicStates.getAll();
10631           for (key in graphicStates) {
10632             var graphicState = graphicStates[key];
10633             var bm = graphicState['BM'];
10634             if (isName(bm) && bm.name !== 'Normal') {
10635               return true;
10636             }
10637           }
10638         }
10639         // Descend into the XObjects to look for more resources and blend modes.
10640         var xObjects = node.get('XObject');
10641         if (!isDict(xObjects)) {
10642           continue;
10643         }
10644         xObjects = xObjects.getAll();
10645         for (key in xObjects) {
10646           var xObject = xObjects[key];
10647           if (!isStream(xObject)) {
10648             continue;
10649           }
10650           if (xObject.dict.objId) {
10651             if (processed[xObject.dict.objId]) {
10652               // stream has objId and is processed already
10653               continue;
10654             }
10655             processed[xObject.dict.objId] = true;
10656           }
10657           var xResources = xObject.dict.get('Resources');
10658           // Checking objId to detect an infinite loop.
10659           if (isDict(xResources) &&
10660               (!xResources.objId || !processed[xResources.objId])) {
10661             nodes.push(xResources);
10662             if (xResources.objId) {
10663               processed[xResources.objId] = true;
10664             }
10665           }
10666         }
10667       }
10668       return false;
10669     },
10670
10671     buildFormXObject: function PartialEvaluator_buildFormXObject(resources,
10672                                                                  xobj, smask,
10673                                                                  operatorList,
10674                                                                  initialState) {
10675       var matrix = xobj.dict.get('Matrix');
10676       var bbox = xobj.dict.get('BBox');
10677       var group = xobj.dict.get('Group');
10678       if (group) {
10679         var groupOptions = {
10680           matrix: matrix,
10681           bbox: bbox,
10682           smask: smask,
10683           isolated: false,
10684           knockout: false
10685         };
10686
10687         var groupSubtype = group.get('S');
10688         var colorSpace;
10689         if (isName(groupSubtype) && groupSubtype.name === 'Transparency') {
10690           groupOptions.isolated = (group.get('I') || false);
10691           groupOptions.knockout = (group.get('K') || false);
10692           colorSpace = (group.has('CS') ?
10693             ColorSpace.parse(group.get('CS'), this.xref, resources) : null);
10694         }
10695
10696         if (smask && smask.backdrop) {
10697           colorSpace = colorSpace || ColorSpace.singletons.rgb;
10698           smask.backdrop = colorSpace.getRgb(smask.backdrop, 0);
10699         }
10700
10701         operatorList.addOp(OPS.beginGroup, [groupOptions]);
10702       }
10703
10704       operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]);
10705
10706       return this.getOperatorList(xobj,
10707         (xobj.dict.get('Resources') || resources), operatorList, initialState).
10708         then(function () {
10709           operatorList.addOp(OPS.paintFormXObjectEnd, []);
10710
10711           if (group) {
10712             operatorList.addOp(OPS.endGroup, [groupOptions]);
10713           }
10714         });
10715     },
10716
10717     buildPaintImageXObject:
10718         function PartialEvaluator_buildPaintImageXObject(resources, image,
10719                                                          inline, operatorList,
10720                                                          cacheKey, imageCache) {
10721       var self = this;
10722       var dict = image.dict;
10723       var w = dict.get('Width', 'W');
10724       var h = dict.get('Height', 'H');
10725
10726       if (!(w && isNum(w)) || !(h && isNum(h))) {
10727         warn('Image dimensions are missing, or not numbers.');
10728         return;
10729       }
10730       if (PDFJS.maxImageSize !== -1 && w * h > PDFJS.maxImageSize) {
10731         warn('Image exceeded maximum allowed size and was removed.');
10732         return;
10733       }
10734
10735       var imageMask = (dict.get('ImageMask', 'IM') || false);
10736       var imgData, args;
10737       if (imageMask) {
10738         // This depends on a tmpCanvas being filled with the
10739         // current fillStyle, such that processing the pixel
10740         // data can't be done here. Instead of creating a
10741         // complete PDFImage, only read the information needed
10742         // for later.
10743
10744         var width = dict.get('Width', 'W');
10745         var height = dict.get('Height', 'H');
10746         var bitStrideLength = (width + 7) >> 3;
10747         var imgArray = image.getBytes(bitStrideLength * height);
10748         var decode = dict.get('Decode', 'D');
10749         var inverseDecode = (!!decode && decode[0] > 0);
10750
10751         imgData = PDFImage.createMask(imgArray, width, height,
10752                                       image instanceof DecodeStream,
10753                                       inverseDecode);
10754         imgData.cached = true;
10755         args = [imgData];
10756         operatorList.addOp(OPS.paintImageMaskXObject, args);
10757         if (cacheKey) {
10758           imageCache[cacheKey] = {
10759             fn: OPS.paintImageMaskXObject,
10760             args: args
10761           };
10762         }
10763         return;
10764       }
10765
10766       var softMask = (dict.get('SMask', 'SM') || false);
10767       var mask = (dict.get('Mask') || false);
10768
10769       var SMALL_IMAGE_DIMENSIONS = 200;
10770       // Inlining small images into the queue as RGB data
10771       if (inline && !softMask && !mask && !(image instanceof JpegStream) &&
10772           (w + h) < SMALL_IMAGE_DIMENSIONS) {
10773         var imageObj = new PDFImage(this.xref, resources, image,
10774                                     inline, null, null);
10775         // We force the use of RGBA_32BPP images here, because we can't handle
10776         // any other kind.
10777         imgData = imageObj.createImageData(/* forceRGBA = */ true);
10778         operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);
10779         return;
10780       }
10781
10782       // If there is no imageMask, create the PDFImage and a lot
10783       // of image processing can be done here.
10784       var uniquePrefix = (this.uniquePrefix || '');
10785       var objId = 'img_' + uniquePrefix + (++this.idCounters.obj);
10786       operatorList.addDependency(objId);
10787       args = [objId, w, h];
10788
10789       if (!softMask && !mask && image instanceof JpegStream &&
10790           image.isNativelySupported(this.xref, resources)) {
10791         // These JPEGs don't need any more processing so we can just send it.
10792         operatorList.addOp(OPS.paintJpegXObject, args);
10793         this.handler.send('obj',
10794           [objId, this.pageIndex, 'JpegStream', image.getIR()]);
10795         return;
10796       }
10797
10798       PDFImage.buildImage(self.handler, self.xref, resources, image, inline).
10799         then(function(imageObj) {
10800           var imgData = imageObj.createImageData(/* forceRGBA = */ false);
10801           self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData],
10802             [imgData.data.buffer]);
10803         }).then(undefined, function (reason) {
10804           warn('Unable to decode image: ' + reason);
10805           self.handler.send('obj', [objId, self.pageIndex, 'Image', null]);
10806         });
10807
10808       operatorList.addOp(OPS.paintImageXObject, args);
10809       if (cacheKey) {
10810         imageCache[cacheKey] = {
10811           fn: OPS.paintImageXObject,
10812           args: args
10813         };
10814       }
10815     },
10816
10817     handleSMask: function PartialEvaluator_handleSmask(smask, resources,
10818                                                        operatorList,
10819                                                        stateManager) {
10820       var smaskContent = smask.get('G');
10821       var smaskOptions = {
10822         subtype: smask.get('S').name,
10823         backdrop: smask.get('BC')
10824       };
10825       return this.buildFormXObject(resources, smaskContent, smaskOptions,
10826                             operatorList, stateManager.state.clone());
10827     },
10828
10829     handleTilingType:
10830         function PartialEvaluator_handleTilingType(fn, args, resources,
10831                                                    pattern, patternDict,
10832                                                    operatorList) {
10833       // Create an IR of the pattern code.
10834       var tilingOpList = new OperatorList();
10835       return this.getOperatorList(pattern,
10836         (patternDict.get('Resources') || resources), tilingOpList).
10837         then(function () {
10838           // Add the dependencies to the parent operator list so they are
10839           // resolved before sub operator list is executed synchronously.
10840           operatorList.addDependencies(tilingOpList.dependencies);
10841           operatorList.addOp(fn, getTilingPatternIR({
10842             fnArray: tilingOpList.fnArray,
10843             argsArray: tilingOpList.argsArray
10844           }, patternDict, args));
10845         });
10846     },
10847
10848     handleSetFont:
10849         function PartialEvaluator_handleSetFont(resources, fontArgs, fontRef,
10850                                                 operatorList, state) {
10851       // TODO(mack): Not needed?
10852       var fontName;
10853       if (fontArgs) {
10854         fontArgs = fontArgs.slice();
10855         fontName = fontArgs[0].name;
10856       }
10857
10858       var self = this;
10859       return this.loadFont(fontName, fontRef, this.xref, resources).then(
10860           function (translated) {
10861         if (!translated.font.isType3Font) {
10862           return translated;
10863         }
10864         return translated.loadType3Data(self, resources, operatorList).then(
10865             function () {
10866           return translated;
10867         });
10868       }).then(function (translated) {
10869         state.font = translated.font;
10870         translated.send(self.handler);
10871         return translated.loadedName;
10872       });
10873     },
10874
10875     handleText: function PartialEvaluator_handleText(chars, state) {
10876       var font = state.font;
10877       var glyphs = font.charsToGlyphs(chars);
10878       var isAddToPathSet = !!(state.textRenderingMode &
10879                               TextRenderingMode.ADD_TO_PATH_FLAG);
10880       if (font.data && (isAddToPathSet || PDFJS.disableFontFace)) {
10881         var buildPath = function (fontChar) {
10882           if (!font.renderer.hasBuiltPath(fontChar)) {
10883             var path = font.renderer.getPathJs(fontChar);
10884             this.handler.send('commonobj', [
10885               font.loadedName + '_path_' + fontChar,
10886               'FontPath',
10887               path
10888             ]);
10889           }
10890         }.bind(this);
10891
10892         for (var i = 0, ii = glyphs.length; i < ii; i++) {
10893           var glyph = glyphs[i];
10894           if (glyph === null) {
10895             continue;
10896           }
10897           buildPath(glyph.fontChar);
10898
10899           // If the glyph has an accent we need to build a path for its
10900           // fontChar too, otherwise CanvasGraphics_paintChar will fail.
10901           var accent = glyph.accent;
10902           if (accent && accent.fontChar) {
10903             buildPath(accent.fontChar);
10904           }
10905         }
10906       }
10907
10908       return glyphs;
10909     },
10910
10911     setGState: function PartialEvaluator_setGState(resources, gState,
10912                                                    operatorList, xref,
10913                                                    stateManager) {
10914       // This array holds the converted/processed state data.
10915       var gStateObj = [];
10916       var gStateMap = gState.map;
10917       var self = this;
10918       var promise = Promise.resolve();
10919       for (var key in gStateMap) {
10920         var value = gStateMap[key];
10921         switch (key) {
10922           case 'Type':
10923             break;
10924           case 'LW':
10925           case 'LC':
10926           case 'LJ':
10927           case 'ML':
10928           case 'D':
10929           case 'RI':
10930           case 'FL':
10931           case 'CA':
10932           case 'ca':
10933             gStateObj.push([key, value]);
10934             break;
10935           case 'Font':
10936             promise = promise.then(function () {
10937               return self.handleSetFont(resources, null, value[0],
10938                                         operatorList, stateManager.state).
10939                 then(function (loadedName) {
10940                   operatorList.addDependency(loadedName);
10941                   gStateObj.push([key, [loadedName, value[1]]]);
10942                 });
10943             });
10944             break;
10945           case 'BM':
10946             gStateObj.push([key, value]);
10947             break;
10948           case 'SMask':
10949             if (isName(value) && value.name === 'None') {
10950               gStateObj.push([key, false]);
10951               break;
10952             }
10953             var dict = xref.fetchIfRef(value);
10954             if (isDict(dict)) {
10955               promise = promise.then(function () {
10956                 return self.handleSMask(dict, resources, operatorList,
10957                                         stateManager);
10958               });
10959               gStateObj.push([key, true]);
10960             } else {
10961               warn('Unsupported SMask type');
10962             }
10963
10964             break;
10965           // Only generate info log messages for the following since
10966           // they are unlikely to have a big impact on the rendering.
10967           case 'OP':
10968           case 'op':
10969           case 'OPM':
10970           case 'BG':
10971           case 'BG2':
10972           case 'UCR':
10973           case 'UCR2':
10974           case 'TR':
10975           case 'TR2':
10976           case 'HT':
10977           case 'SM':
10978           case 'SA':
10979           case 'AIS':
10980           case 'TK':
10981             // TODO implement these operators.
10982             info('graphic state operator ' + key);
10983             break;
10984           default:
10985             info('Unknown graphic state operator ' + key);
10986             break;
10987         }
10988       }
10989       return promise.then(function () {
10990         if (gStateObj.length >= 0) {
10991           operatorList.addOp(OPS.setGState, [gStateObj]);
10992         }
10993       });
10994     },
10995
10996     loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
10997                                                  resources) {
10998
10999       function errorFont() {
11000         return Promise.resolve(new TranslatedFont('g_font_error',
11001           new ErrorFont('Font ' + fontName + ' is not available'), font));
11002       }
11003       var fontRef;
11004       if (font) { // Loading by ref.
11005         assert(isRef(font));
11006         fontRef = font;
11007       } else { // Loading by name.
11008         var fontRes = resources.get('Font');
11009         if (fontRes) {
11010           fontRef = fontRes.getRaw(fontName);
11011         } else {
11012           warn('fontRes not available');
11013           return errorFont();
11014         }
11015       }
11016       if (!fontRef) {
11017         warn('fontRef not available');
11018         return errorFont();
11019       }
11020
11021       if (this.fontCache.has(fontRef)) {
11022         return this.fontCache.get(fontRef);
11023       }
11024
11025       font = xref.fetchIfRef(fontRef);
11026       if (!isDict(font)) {
11027         return errorFont();
11028       }
11029
11030       // We are holding font.translated references just for fontRef that are not
11031       // dictionaries (Dict). See explanation below.
11032       if (font.translated) {
11033         return font.translated;
11034       }
11035
11036       var fontCapability = createPromiseCapability();
11037
11038       var preEvaluatedFont = this.preEvaluateFont(font, xref);
11039       var descriptor = preEvaluatedFont.descriptor;
11040       var fontID = fontRef.num + '_' + fontRef.gen;
11041       if (isDict(descriptor)) {
11042         if (!descriptor.fontAliases) {
11043           descriptor.fontAliases = Object.create(null);
11044         }
11045
11046         var fontAliases = descriptor.fontAliases;
11047         var hash = preEvaluatedFont.hash;
11048         if (fontAliases[hash]) {
11049           var aliasFontRef = fontAliases[hash].aliasRef;
11050           if (aliasFontRef && this.fontCache.has(aliasFontRef)) {
11051             this.fontCache.putAlias(fontRef, aliasFontRef);
11052             return this.fontCache.get(fontRef);
11053           }
11054         }
11055
11056         if (!fontAliases[hash]) {
11057           fontAliases[hash] = {
11058             fontID: Font.getFontID()
11059           };
11060         }
11061
11062         fontAliases[hash].aliasRef = fontRef;
11063         fontID = fontAliases[hash].fontID;
11064       }
11065
11066       // Workaround for bad PDF generators that don't reference fonts
11067       // properly, i.e. by not using an object identifier.
11068       // Check if the fontRef is a Dict (as opposed to a standard object),
11069       // in which case we don't cache the font and instead reference it by
11070       // fontName in font.loadedName below.
11071       var fontRefIsDict = isDict(fontRef);
11072       if (!fontRefIsDict) {
11073         this.fontCache.put(fontRef, fontCapability.promise);
11074       }
11075
11076       // Keep track of each font we translated so the caller can
11077       // load them asynchronously before calling display on a page.
11078       font.loadedName = 'g_font_' + (fontRefIsDict ?
11079         fontName.replace(/\W/g, '') : fontID);
11080
11081       font.translated = fontCapability.promise;
11082
11083       // TODO move promises into translate font
11084       var translatedPromise;
11085       try {
11086         translatedPromise = Promise.resolve(
11087           this.translateFont(preEvaluatedFont, xref));
11088       } catch (e) {
11089         translatedPromise = Promise.reject(e);
11090       }
11091
11092       translatedPromise.then(function (translatedFont) {
11093         if (translatedFont.fontType !== undefined) {
11094           var xrefFontStats = xref.stats.fontTypes;
11095           xrefFontStats[translatedFont.fontType] = true;
11096         }
11097
11098         fontCapability.resolve(new TranslatedFont(font.loadedName,
11099           translatedFont, font));
11100       }, function (reason) {
11101         // TODO fontCapability.reject?
11102         UnsupportedManager.notify(UNSUPPORTED_FEATURES.font);
11103
11104         try {
11105           // error, but it's still nice to have font type reported
11106           var descriptor = preEvaluatedFont.descriptor;
11107           var fontFile3 = descriptor && descriptor.get('FontFile3');
11108           var subtype = fontFile3 && fontFile3.get('Subtype');
11109           var fontType = getFontType(preEvaluatedFont.type,
11110                                      subtype && subtype.name);
11111           var xrefFontStats = xref.stats.fontTypes;
11112           xrefFontStats[fontType] = true;
11113         } catch (ex) { }
11114
11115         fontCapability.resolve(new TranslatedFont(font.loadedName,
11116           new ErrorFont(reason instanceof Error ? reason.message : reason),
11117           font));
11118       });
11119       return fontCapability.promise;
11120     },
11121
11122     buildPath: function PartialEvaluator_buildPath(operatorList, fn, args) {
11123       var lastIndex = operatorList.length - 1;
11124       if (!args) {
11125         args = [];
11126       }
11127       if (lastIndex < 0 ||
11128           operatorList.fnArray[lastIndex] !== OPS.constructPath) {
11129         operatorList.addOp(OPS.constructPath, [[fn], args]);
11130       } else {
11131         var opArgs = operatorList.argsArray[lastIndex];
11132         opArgs[0].push(fn);
11133         Array.prototype.push.apply(opArgs[1], args);
11134       }
11135     },
11136
11137     handleColorN: function PartialEvaluator_handleColorN(operatorList, fn, args,
11138           cs, patterns, resources, xref) {
11139       // compile tiling patterns
11140       var patternName = args[args.length - 1];
11141       // SCN/scn applies patterns along with normal colors
11142       var pattern;
11143       if (isName(patternName) &&
11144           (pattern = patterns.get(patternName.name))) {
11145         var dict = (isStream(pattern) ? pattern.dict : pattern);
11146         var typeNum = dict.get('PatternType');
11147
11148         if (typeNum === TILING_PATTERN) {
11149           var color = cs.base ? cs.base.getRgb(args, 0) : null;
11150           return this.handleTilingType(fn, color, resources, pattern,
11151                                        dict, operatorList);
11152         } else if (typeNum === SHADING_PATTERN) {
11153           var shading = dict.get('Shading');
11154           var matrix = dict.get('Matrix');
11155           pattern = Pattern.parseShading(shading, matrix, xref, resources);
11156           operatorList.addOp(fn, pattern.getIR());
11157           return Promise.resolve();
11158         } else {
11159           return Promise.reject('Unknown PatternType: ' + typeNum);
11160         }
11161       }
11162       // TODO shall we fail here?
11163       operatorList.addOp(fn, args);
11164       return Promise.resolve();
11165     },
11166
11167     getOperatorList: function PartialEvaluator_getOperatorList(stream,
11168                                                                resources,
11169                                                                operatorList,
11170                                                                initialState) {
11171
11172       var self = this;
11173       var xref = this.xref;
11174       var imageCache = {};
11175
11176       assert(operatorList);
11177
11178       resources = (resources || Dict.empty);
11179       var xobjs = (resources.get('XObject') || Dict.empty);
11180       var patterns = (resources.get('Pattern') || Dict.empty);
11181       var stateManager = new StateManager(initialState || new EvalState());
11182       var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
11183       var timeSlotManager = new TimeSlotManager();
11184
11185       return new Promise(function next(resolve, reject) {
11186         timeSlotManager.reset();
11187         var stop, operation = {}, i, ii, cs;
11188         while (!(stop = timeSlotManager.check())) {
11189           // The arguments parsed by read() are used beyond this loop, so we
11190           // cannot reuse the same array on each iteration. Therefore we pass
11191           // in |null| as the initial value (see the comment on
11192           // EvaluatorPreprocessor_read() for why).
11193           operation.args = null;
11194           if (!(preprocessor.read(operation))) {
11195             break;
11196           }
11197           var args = operation.args;
11198           var fn = operation.fn;
11199
11200           switch (fn | 0) {
11201             case OPS.paintXObject:
11202               if (args[0].code) {
11203                 break;
11204               }
11205               // eagerly compile XForm objects
11206               var name = args[0].name;
11207               if (imageCache[name] !== undefined) {
11208                 operatorList.addOp(imageCache[name].fn, imageCache[name].args);
11209                 args = null;
11210                 continue;
11211               }
11212
11213               var xobj = xobjs.get(name);
11214               if (xobj) {
11215                 assert(isStream(xobj), 'XObject should be a stream');
11216
11217                 var type = xobj.dict.get('Subtype');
11218                 assert(isName(type),
11219                   'XObject should have a Name subtype');
11220
11221                 if (type.name === 'Form') {
11222                   stateManager.save();
11223                   return self.buildFormXObject(resources, xobj, null,
11224                                                operatorList,
11225                                                stateManager.state.clone()).
11226                     then(function () {
11227                       stateManager.restore();
11228                       next(resolve, reject);
11229                     }, reject);
11230                 } else if (type.name === 'Image') {
11231                   self.buildPaintImageXObject(resources, xobj, false,
11232                     operatorList, name, imageCache);
11233                   args = null;
11234                   continue;
11235                 } else if (type.name === 'PS') {
11236                   // PostScript XObjects are unused when viewing documents.
11237                   // See section 4.7.1 of Adobe's PDF reference.
11238                   info('Ignored XObject subtype PS');
11239                   continue;
11240                 } else {
11241                   error('Unhandled XObject subtype ' + type.name);
11242                 }
11243               }
11244               break;
11245             case OPS.setFont:
11246               var fontSize = args[1];
11247               // eagerly collect all fonts
11248               return self.handleSetFont(resources, args, null,
11249                                         operatorList, stateManager.state).
11250                 then(function (loadedName) {
11251                   operatorList.addDependency(loadedName);
11252                   operatorList.addOp(OPS.setFont, [loadedName, fontSize]);
11253                   next(resolve, reject);
11254                 }, reject);
11255             case OPS.endInlineImage:
11256               var cacheKey = args[0].cacheKey;
11257               if (cacheKey) {
11258                 var cacheEntry = imageCache[cacheKey];
11259                 if (cacheEntry !== undefined) {
11260                   operatorList.addOp(cacheEntry.fn, cacheEntry.args);
11261                   args = null;
11262                   continue;
11263                 }
11264               }
11265               self.buildPaintImageXObject(resources, args[0], true,
11266                 operatorList, cacheKey, imageCache);
11267               args = null;
11268               continue;
11269             case OPS.showText:
11270               args[0] = self.handleText(args[0], stateManager.state);
11271               break;
11272             case OPS.showSpacedText:
11273               var arr = args[0];
11274               var combinedGlyphs = [];
11275               var arrLength = arr.length;
11276               for (i = 0; i < arrLength; ++i) {
11277                 var arrItem = arr[i];
11278                 if (isString(arrItem)) {
11279                   Array.prototype.push.apply(combinedGlyphs,
11280                     self.handleText(arrItem, stateManager.state));
11281                 } else if (isNum(arrItem)) {
11282                   combinedGlyphs.push(arrItem);
11283                 }
11284               }
11285               args[0] = combinedGlyphs;
11286               fn = OPS.showText;
11287               break;
11288             case OPS.nextLineShowText:
11289               operatorList.addOp(OPS.nextLine);
11290               args[0] = self.handleText(args[0], stateManager.state);
11291               fn = OPS.showText;
11292               break;
11293             case OPS.nextLineSetSpacingShowText:
11294               operatorList.addOp(OPS.nextLine);
11295               operatorList.addOp(OPS.setWordSpacing, [args.shift()]);
11296               operatorList.addOp(OPS.setCharSpacing, [args.shift()]);
11297               args[0] = self.handleText(args[0], stateManager.state);
11298               fn = OPS.showText;
11299               break;
11300             case OPS.setTextRenderingMode:
11301               stateManager.state.textRenderingMode = args[0];
11302               break;
11303
11304             case OPS.setFillColorSpace:
11305               stateManager.state.fillColorSpace =
11306                 ColorSpace.parse(args[0], xref, resources);
11307               continue;
11308             case OPS.setStrokeColorSpace:
11309               stateManager.state.strokeColorSpace =
11310                 ColorSpace.parse(args[0], xref, resources);
11311               continue;
11312             case OPS.setFillColor:
11313               cs = stateManager.state.fillColorSpace;
11314               args = cs.getRgb(args, 0);
11315               fn = OPS.setFillRGBColor;
11316               break;
11317             case OPS.setStrokeColor:
11318               cs = stateManager.state.strokeColorSpace;
11319               args = cs.getRgb(args, 0);
11320               fn = OPS.setStrokeRGBColor;
11321               break;
11322             case OPS.setFillGray:
11323               stateManager.state.fillColorSpace = ColorSpace.singletons.gray;
11324               args = ColorSpace.singletons.gray.getRgb(args, 0);
11325               fn = OPS.setFillRGBColor;
11326               break;
11327             case OPS.setStrokeGray:
11328               stateManager.state.strokeColorSpace = ColorSpace.singletons.gray;
11329               args = ColorSpace.singletons.gray.getRgb(args, 0);
11330               fn = OPS.setStrokeRGBColor;
11331               break;
11332             case OPS.setFillCMYKColor:
11333               stateManager.state.fillColorSpace = ColorSpace.singletons.cmyk;
11334               args = ColorSpace.singletons.cmyk.getRgb(args, 0);
11335               fn = OPS.setFillRGBColor;
11336               break;
11337             case OPS.setStrokeCMYKColor:
11338               stateManager.state.strokeColorSpace = ColorSpace.singletons.cmyk;
11339               args = ColorSpace.singletons.cmyk.getRgb(args, 0);
11340               fn = OPS.setStrokeRGBColor;
11341               break;
11342             case OPS.setFillRGBColor:
11343               stateManager.state.fillColorSpace = ColorSpace.singletons.rgb;
11344               args = ColorSpace.singletons.rgb.getRgb(args, 0);
11345               break;
11346             case OPS.setStrokeRGBColor:
11347               stateManager.state.strokeColorSpace = ColorSpace.singletons.rgb;
11348               args = ColorSpace.singletons.rgb.getRgb(args, 0);
11349               break;
11350             case OPS.setFillColorN:
11351               cs = stateManager.state.fillColorSpace;
11352               if (cs.name === 'Pattern') {
11353                 return self.handleColorN(operatorList, OPS.setFillColorN,
11354                   args, cs, patterns, resources, xref).then(function() {
11355                     next(resolve, reject);
11356                   }, reject);
11357               }
11358               args = cs.getRgb(args, 0);
11359               fn = OPS.setFillRGBColor;
11360               break;
11361             case OPS.setStrokeColorN:
11362               cs = stateManager.state.strokeColorSpace;
11363               if (cs.name === 'Pattern') {
11364                 return self.handleColorN(operatorList, OPS.setStrokeColorN,
11365                   args, cs, patterns, resources, xref).then(function() {
11366                     next(resolve, reject);
11367                   }, reject);
11368               }
11369               args = cs.getRgb(args, 0);
11370               fn = OPS.setStrokeRGBColor;
11371               break;
11372
11373             case OPS.shadingFill:
11374               var shadingRes = resources.get('Shading');
11375               if (!shadingRes) {
11376                 error('No shading resource found');
11377               }
11378
11379               var shading = shadingRes.get(args[0].name);
11380               if (!shading) {
11381                 error('No shading object found');
11382               }
11383
11384               var shadingFill = Pattern.parseShading(shading, null, xref,
11385                 resources);
11386               var patternIR = shadingFill.getIR();
11387               args = [patternIR];
11388               fn = OPS.shadingFill;
11389               break;
11390             case OPS.setGState:
11391               var dictName = args[0];
11392               var extGState = resources.get('ExtGState');
11393
11394               if (!isDict(extGState) || !extGState.has(dictName.name)) {
11395                 break;
11396               }
11397
11398               var gState = extGState.get(dictName.name);
11399               return self.setGState(resources, gState, operatorList, xref,
11400                 stateManager).then(function() {
11401                   next(resolve, reject);
11402                 }, reject);
11403             case OPS.moveTo:
11404             case OPS.lineTo:
11405             case OPS.curveTo:
11406             case OPS.curveTo2:
11407             case OPS.curveTo3:
11408             case OPS.closePath:
11409               self.buildPath(operatorList, fn, args);
11410               continue;
11411             case OPS.rectangle:
11412               self.buildPath(operatorList, fn, args);
11413               continue;
11414           }
11415           operatorList.addOp(fn, args);
11416         }
11417         if (stop) {
11418           deferred.then(function () {
11419             next(resolve, reject);
11420           });
11421           return;
11422         }
11423         // Some PDFs don't close all restores inside object/form.
11424         // Closing those for them.
11425         for (i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) {
11426           operatorList.addOp(OPS.restore, []);
11427         }
11428         resolve();
11429       });
11430     },
11431
11432     getTextContent: function PartialEvaluator_getTextContent(stream, resources,
11433                                                              stateManager) {
11434
11435       stateManager = (stateManager || new StateManager(new TextState()));
11436
11437       var textContent = {
11438         items: [],
11439         styles: Object.create(null)
11440       };
11441       var bidiTexts = textContent.items;
11442       var SPACE_FACTOR = 0.3;
11443       var MULTI_SPACE_FACTOR = 1.5;
11444
11445       var self = this;
11446       var xref = this.xref;
11447
11448       resources = (xref.fetchIfRef(resources) || Dict.empty);
11449
11450       // The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
11451       var xobjs = null;
11452       var xobjsCache = {};
11453
11454       var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
11455
11456       var textState;
11457
11458       function newTextChunk() {
11459         var font = textState.font;
11460         if (!(font.loadedName in textContent.styles)) {
11461           textContent.styles[font.loadedName] = {
11462             fontFamily: font.fallbackName,
11463             ascent: font.ascent,
11464             descent: font.descent,
11465             vertical: font.vertical
11466           };
11467         }
11468         return {
11469           // |str| is initially an array which we push individual chars to, and
11470           // then runBidi() overwrites it with the final string.
11471           str: [],
11472           dir: null,
11473           width: 0,
11474           height: 0,
11475           transform: null,
11476           fontName: font.loadedName
11477         };
11478       }
11479
11480       function runBidi(textChunk) {
11481         var str = textChunk.str.join('');
11482         var bidiResult = PDFJS.bidi(str, -1, textState.font.vertical);
11483         textChunk.str = bidiResult.str;
11484         textChunk.dir = bidiResult.dir;
11485         return textChunk;
11486       }
11487
11488       function handleSetFont(fontName, fontRef) {
11489         return self.loadFont(fontName, fontRef, xref, resources).
11490           then(function (translated) {
11491             textState.font = translated.font;
11492             textState.fontMatrix = translated.font.fontMatrix ||
11493               FONT_IDENTITY_MATRIX;
11494           });
11495       }
11496
11497       function buildTextGeometry(chars, textChunk) {
11498         var font = textState.font;
11499         textChunk = textChunk || newTextChunk();
11500         if (!textChunk.transform) {
11501           // 9.4.4 Text Space Details
11502           var tsm = [textState.fontSize * textState.textHScale, 0,
11503                      0, textState.fontSize,
11504                      0, textState.textRise];
11505
11506           if (font.isType3Font &&
11507               textState.fontMatrix !== FONT_IDENTITY_MATRIX &&
11508               textState.fontSize === 1) {
11509             var glyphHeight = font.bbox[3] - font.bbox[1];
11510             if (glyphHeight > 0) {
11511               glyphHeight = glyphHeight * textState.fontMatrix[3];
11512               tsm[3] *= glyphHeight;
11513             }
11514           }
11515
11516           var trm = textChunk.transform = Util.transform(textState.ctm,
11517                                     Util.transform(textState.textMatrix, tsm));
11518           if (!font.vertical) {
11519             textChunk.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]);
11520           } else {
11521             textChunk.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]);
11522           }
11523         }
11524         var width = 0;
11525         var height = 0;
11526         var glyphs = font.charsToGlyphs(chars);
11527         var defaultVMetrics = font.defaultVMetrics;
11528         for (var i = 0; i < glyphs.length; i++) {
11529           var glyph = glyphs[i];
11530           if (!glyph) { // Previous glyph was a space.
11531             width += textState.wordSpacing * textState.textHScale;
11532             continue;
11533           }
11534           var vMetricX = null;
11535           var vMetricY = null;
11536           var glyphWidth = null;
11537           if (font.vertical) {
11538             if (glyph.vmetric) {
11539               glyphWidth = glyph.vmetric[0];
11540               vMetricX = glyph.vmetric[1];
11541               vMetricY = glyph.vmetric[2];
11542             } else {
11543               glyphWidth = glyph.width;
11544               vMetricX = glyph.width * 0.5;
11545               vMetricY = defaultVMetrics[2];
11546             }
11547           } else {
11548             glyphWidth = glyph.width;
11549           }
11550
11551           var glyphUnicode = glyph.unicode;
11552           if (NormalizedUnicodes[glyphUnicode] !== undefined) {
11553             glyphUnicode = NormalizedUnicodes[glyphUnicode];
11554           }
11555           glyphUnicode = reverseIfRtl(glyphUnicode);
11556
11557           // The following will calculate the x and y of the individual glyphs.
11558           // if (font.vertical) {
11559           //   tsm[4] -= vMetricX * Math.abs(textState.fontSize) *
11560           //             textState.fontMatrix[0];
11561           //   tsm[5] -= vMetricY * textState.fontSize *
11562           //             textState.fontMatrix[0];
11563           // }
11564           // var trm = Util.transform(textState.textMatrix, tsm);
11565           // var pt = Util.applyTransform([trm[4], trm[5]], textState.ctm);
11566           // var x = pt[0];
11567           // var y = pt[1];
11568
11569           var charSpacing = 0;
11570           if (textChunk.str.length > 0) {
11571             // Apply char spacing only when there are chars.
11572             // As a result there is only spacing between glyphs.
11573             charSpacing = textState.charSpacing;
11574           }
11575
11576           var tx = 0;
11577           var ty = 0;
11578           if (!font.vertical) {
11579             var w0 = glyphWidth * textState.fontMatrix[0];
11580             tx = (w0 * textState.fontSize + charSpacing) *
11581                  textState.textHScale;
11582             width += tx;
11583           } else {
11584             var w1 = glyphWidth * textState.fontMatrix[0];
11585             ty = w1 * textState.fontSize + charSpacing;
11586             height += ty;
11587           }
11588           textState.translateTextMatrix(tx, ty);
11589
11590           textChunk.str.push(glyphUnicode);
11591         }
11592
11593         var a = textState.textLineMatrix[0];
11594         var b = textState.textLineMatrix[1];
11595         var scaleLineX = Math.sqrt(a * a + b * b);
11596         a = textState.ctm[0];
11597         b = textState.ctm[1];
11598         var scaleCtmX = Math.sqrt(a * a + b * b);
11599         if (!font.vertical) {
11600           textChunk.width += width * scaleCtmX * scaleLineX;
11601         } else {
11602           textChunk.height += Math.abs(height * scaleCtmX * scaleLineX);
11603         }
11604         return textChunk;
11605       }
11606
11607       var timeSlotManager = new TimeSlotManager();
11608
11609       return new Promise(function next(resolve, reject) {
11610         timeSlotManager.reset();
11611         var stop, operation = {}, args = [];
11612         while (!(stop = timeSlotManager.check())) {
11613           // The arguments parsed by read() are not used beyond this loop, so
11614           // we can reuse the same array on every iteration, thus avoiding
11615           // unnecessary allocations.
11616           args.length = 0;
11617           operation.args = args;
11618           if (!(preprocessor.read(operation))) {
11619             break;
11620           }
11621           textState = stateManager.state;
11622           var fn = operation.fn;
11623           args = operation.args;
11624
11625           switch (fn | 0) {
11626             case OPS.setFont:
11627               textState.fontSize = args[1];
11628               return handleSetFont(args[0].name).then(function() {
11629                 next(resolve, reject);
11630               }, reject);
11631             case OPS.setTextRise:
11632               textState.textRise = args[0];
11633               break;
11634             case OPS.setHScale:
11635               textState.textHScale = args[0] / 100;
11636               break;
11637             case OPS.setLeading:
11638               textState.leading = args[0];
11639               break;
11640             case OPS.moveText:
11641               textState.translateTextLineMatrix(args[0], args[1]);
11642               textState.textMatrix = textState.textLineMatrix.slice();
11643               break;
11644             case OPS.setLeadingMoveText:
11645               textState.leading = -args[1];
11646               textState.translateTextLineMatrix(args[0], args[1]);
11647               textState.textMatrix = textState.textLineMatrix.slice();
11648               break;
11649             case OPS.nextLine:
11650               textState.carriageReturn();
11651               break;
11652             case OPS.setTextMatrix:
11653               textState.setTextMatrix(args[0], args[1], args[2], args[3],
11654                 args[4], args[5]);
11655               textState.setTextLineMatrix(args[0], args[1], args[2], args[3],
11656                 args[4], args[5]);
11657               break;
11658             case OPS.setCharSpacing:
11659               textState.charSpacing = args[0];
11660               break;
11661             case OPS.setWordSpacing:
11662               textState.wordSpacing = args[0];
11663               break;
11664             case OPS.beginText:
11665               textState.textMatrix = IDENTITY_MATRIX.slice();
11666               textState.textLineMatrix = IDENTITY_MATRIX.slice();
11667               break;
11668             case OPS.showSpacedText:
11669               var items = args[0];
11670               var textChunk = newTextChunk();
11671               var offset;
11672               for (var j = 0, jj = items.length; j < jj; j++) {
11673                 if (typeof items[j] === 'string') {
11674                   buildTextGeometry(items[j], textChunk);
11675                 } else {
11676                   var val = items[j] / 1000;
11677                   if (!textState.font.vertical) {
11678                     offset = -val * textState.fontSize * textState.textHScale *
11679                       textState.textMatrix[0];
11680                     textState.translateTextMatrix(offset, 0);
11681                     textChunk.width += offset;
11682                   } else {
11683                     offset = -val * textState.fontSize *
11684                       textState.textMatrix[3];
11685                     textState.translateTextMatrix(0, offset);
11686                     textChunk.height += offset;
11687                   }
11688                   if (items[j] < 0 && textState.font.spaceWidth > 0) {
11689                     var fakeSpaces = -items[j] / textState.font.spaceWidth;
11690                     if (fakeSpaces > MULTI_SPACE_FACTOR) {
11691                       fakeSpaces = Math.round(fakeSpaces);
11692                       while (fakeSpaces--) {
11693                         textChunk.str.push(' ');
11694                       }
11695                     } else if (fakeSpaces > SPACE_FACTOR) {
11696                       textChunk.str.push(' ');
11697                     }
11698                   }
11699                 }
11700               }
11701               bidiTexts.push(runBidi(textChunk));
11702               break;
11703             case OPS.showText:
11704               bidiTexts.push(runBidi(buildTextGeometry(args[0])));
11705               break;
11706             case OPS.nextLineShowText:
11707               textState.carriageReturn();
11708               bidiTexts.push(runBidi(buildTextGeometry(args[0])));
11709               break;
11710             case OPS.nextLineSetSpacingShowText:
11711               textState.wordSpacing = args[0];
11712               textState.charSpacing = args[1];
11713               textState.carriageReturn();
11714               bidiTexts.push(runBidi(buildTextGeometry(args[2])));
11715               break;
11716             case OPS.paintXObject:
11717               if (args[0].code) {
11718                 break;
11719               }
11720
11721               if (!xobjs) {
11722                 xobjs = (resources.get('XObject') || Dict.empty);
11723               }
11724
11725               var name = args[0].name;
11726               if (xobjsCache.key === name) {
11727                 if (xobjsCache.texts) {
11728                   Util.appendToArray(bidiTexts, xobjsCache.texts.items);
11729                   Util.extendObj(textContent.styles, xobjsCache.texts.styles);
11730                 }
11731                 break;
11732               }
11733
11734               var xobj = xobjs.get(name);
11735               if (!xobj) {
11736                 break;
11737               }
11738               assert(isStream(xobj), 'XObject should be a stream');
11739
11740               var type = xobj.dict.get('Subtype');
11741               assert(isName(type),
11742                 'XObject should have a Name subtype');
11743
11744               if ('Form' !== type.name) {
11745                 xobjsCache.key = name;
11746                 xobjsCache.texts = null;
11747                 break;
11748               }
11749
11750               stateManager.save();
11751               var matrix = xobj.dict.get('Matrix');
11752               if (isArray(matrix) && matrix.length === 6) {
11753                 stateManager.transform(matrix);
11754               }
11755
11756               return self.getTextContent(xobj,
11757                 xobj.dict.get('Resources') || resources, stateManager).
11758                 then(function (formTextContent) {
11759                   Util.appendToArray(bidiTexts, formTextContent.items);
11760                   Util.extendObj(textContent.styles, formTextContent.styles);
11761                   stateManager.restore();
11762
11763                   xobjsCache.key = name;
11764                   xobjsCache.texts = formTextContent;
11765
11766                   next(resolve, reject);
11767                 }, reject);
11768             case OPS.setGState:
11769               var dictName = args[0];
11770               var extGState = resources.get('ExtGState');
11771
11772               if (!isDict(extGState) || !extGState.has(dictName.name)) {
11773                 break;
11774               }
11775
11776               var gsStateMap = extGState.get(dictName.name);
11777               var gsStateFont = null;
11778               for (var key in gsStateMap) {
11779                 if (key === 'Font') {
11780                   assert(!gsStateFont);
11781                   gsStateFont = gsStateMap[key];
11782                 }
11783               }
11784               if (gsStateFont) {
11785                 textState.fontSize = gsStateFont[1];
11786                 return handleSetFont(gsStateFont[0]).then(function() {
11787                   next(resolve, reject);
11788                 }, reject);
11789               }
11790               break;
11791           } // switch
11792         } // while
11793         if (stop) {
11794           deferred.then(function () {
11795             next(resolve, reject);
11796           });
11797           return;
11798         }
11799         resolve(textContent);
11800       });
11801     },
11802
11803     extractDataStructures: function
11804       partialEvaluatorExtractDataStructures(dict, baseDict,
11805                                             xref, properties) {
11806       // 9.10.2
11807       var toUnicode = (dict.get('ToUnicode') || baseDict.get('ToUnicode'));
11808       if (toUnicode) {
11809         properties.toUnicode = this.readToUnicode(toUnicode);
11810       }
11811       if (properties.composite) {
11812         // CIDSystemInfo helps to match CID to glyphs
11813         var cidSystemInfo = dict.get('CIDSystemInfo');
11814         if (isDict(cidSystemInfo)) {
11815           properties.cidSystemInfo = {
11816             registry: cidSystemInfo.get('Registry'),
11817             ordering: cidSystemInfo.get('Ordering'),
11818             supplement: cidSystemInfo.get('Supplement')
11819           };
11820         }
11821
11822         var cidToGidMap = dict.get('CIDToGIDMap');
11823         if (isStream(cidToGidMap)) {
11824           properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
11825         }
11826       }
11827
11828       // Based on 9.6.6 of the spec the encoding can come from multiple places
11829       // and depends on the font type. The base encoding and differences are
11830       // read here, but the encoding that is actually used is chosen during
11831       // glyph mapping in the font.
11832       // TODO: Loading the built in encoding in the font would allow the
11833       // differences to be merged in here not require us to hold on to it.
11834       var differences = [];
11835       var baseEncodingName = null;
11836       var encoding;
11837       if (dict.has('Encoding')) {
11838         encoding = dict.get('Encoding');
11839         if (isDict(encoding)) {
11840           baseEncodingName = encoding.get('BaseEncoding');
11841           baseEncodingName = (isName(baseEncodingName) ?
11842                               baseEncodingName.name : null);
11843           // Load the differences between the base and original
11844           if (encoding.has('Differences')) {
11845             var diffEncoding = encoding.get('Differences');
11846             var index = 0;
11847             for (var j = 0, jj = diffEncoding.length; j < jj; j++) {
11848               var data = diffEncoding[j];
11849               if (isNum(data)) {
11850                 index = data;
11851               } else if (isName(data)) {
11852                 differences[index++] = data.name;
11853               } else if (isRef(data)) {
11854                 diffEncoding[j--] = xref.fetch(data);
11855                 continue;
11856               } else {
11857                 error('Invalid entry in \'Differences\' array: ' + data);
11858               }
11859             }
11860           }
11861         } else if (isName(encoding)) {
11862           baseEncodingName = encoding.name;
11863         } else {
11864           error('Encoding is not a Name nor a Dict');
11865         }
11866         // According to table 114 if the encoding is a named encoding it must be
11867         // one of these predefined encodings.
11868         if ((baseEncodingName !== 'MacRomanEncoding' &&
11869              baseEncodingName !== 'MacExpertEncoding' &&
11870              baseEncodingName !== 'WinAnsiEncoding')) {
11871           baseEncodingName = null;
11872         }
11873       }
11874
11875       if (baseEncodingName) {
11876         properties.defaultEncoding = Encodings[baseEncodingName].slice();
11877       } else {
11878         encoding = (properties.type === 'TrueType' ?
11879                     Encodings.WinAnsiEncoding : Encodings.StandardEncoding);
11880         // The Symbolic attribute can be misused for regular fonts
11881         // Heuristic: we have to check if the font is a standard one also
11882         if (!!(properties.flags & FontFlags.Symbolic)) {
11883           encoding = Encodings.MacRomanEncoding;
11884           if (!properties.file) {
11885             if (/Symbol/i.test(properties.name)) {
11886               encoding = Encodings.SymbolSetEncoding;
11887             } else if (/Dingbats/i.test(properties.name)) {
11888               encoding = Encodings.ZapfDingbatsEncoding;
11889             }
11890           }
11891         }
11892         properties.defaultEncoding = encoding;
11893       }
11894
11895       properties.differences = differences;
11896       properties.baseEncodingName = baseEncodingName;
11897       properties.dict = dict;
11898     },
11899
11900     readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) {
11901       var cmap, cmapObj = toUnicode;
11902       if (isName(cmapObj)) {
11903         cmap = CMapFactory.create(cmapObj,
11904           { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
11905         if (cmap instanceof IdentityCMap) {
11906           return new IdentityToUnicodeMap(0, 0xFFFF);
11907         }
11908         return new ToUnicodeMap(cmap.getMap());
11909       } else if (isStream(cmapObj)) {
11910         cmap = CMapFactory.create(cmapObj,
11911           { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
11912         if (cmap instanceof IdentityCMap) {
11913           return new IdentityToUnicodeMap(0, 0xFFFF);
11914         }
11915         cmap = cmap.getMap();
11916         // Convert UTF-16BE
11917         // NOTE: cmap can be a sparse array, so use forEach instead of for(;;)
11918         // to iterate over all keys.
11919         cmap.forEach(function(token, i) {
11920           var str = [];
11921           for (var k = 0; k < token.length; k += 2) {
11922             var w1 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);
11923             if ((w1 & 0xF800) !== 0xD800) { // w1 < 0xD800 || w1 > 0xDFFF
11924               str.push(w1);
11925               continue;
11926             }
11927             k += 2;
11928             var w2 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);
11929             str.push(((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000);
11930           }
11931           cmap[i] = String.fromCharCode.apply(String, str);
11932         });
11933         return new ToUnicodeMap(cmap);
11934       }
11935       return null;
11936     },
11937
11938     readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) {
11939       // Extract the encoding from the CIDToGIDMap
11940       var glyphsData = cidToGidStream.getBytes();
11941
11942       // Set encoding 0 to later verify the font has an encoding
11943       var result = [];
11944       for (var j = 0, jj = glyphsData.length; j < jj; j++) {
11945         var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
11946         if (glyphID === 0) {
11947           continue;
11948         }
11949         var code = j >> 1;
11950         result[code] = glyphID;
11951       }
11952       return result;
11953     },
11954
11955     extractWidths: function PartialEvaluator_extractWidths(dict, xref,
11956                                                            descriptor,
11957                                                            properties) {
11958       var glyphsWidths = [];
11959       var defaultWidth = 0;
11960       var glyphsVMetrics = [];
11961       var defaultVMetrics;
11962       var i, ii, j, jj, start, code, widths;
11963       if (properties.composite) {
11964         defaultWidth = dict.get('DW') || 1000;
11965
11966         widths = dict.get('W');
11967         if (widths) {
11968           for (i = 0, ii = widths.length; i < ii; i++) {
11969             start = widths[i++];
11970             code = xref.fetchIfRef(widths[i]);
11971             if (isArray(code)) {
11972               for (j = 0, jj = code.length; j < jj; j++) {
11973                 glyphsWidths[start++] = code[j];
11974               }
11975             } else {
11976               var width = widths[++i];
11977               for (j = start; j <= code; j++) {
11978                 glyphsWidths[j] = width;
11979               }
11980             }
11981           }
11982         }
11983
11984         if (properties.vertical) {
11985           var vmetrics = (dict.get('DW2') || [880, -1000]);
11986           defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]];
11987           vmetrics = dict.get('W2');
11988           if (vmetrics) {
11989             for (i = 0, ii = vmetrics.length; i < ii; i++) {
11990               start = vmetrics[i++];
11991               code = xref.fetchIfRef(vmetrics[i]);
11992               if (isArray(code)) {
11993                 for (j = 0, jj = code.length; j < jj; j++) {
11994                   glyphsVMetrics[start++] = [code[j++], code[j++], code[j]];
11995                 }
11996               } else {
11997                 var vmetric = [vmetrics[++i], vmetrics[++i], vmetrics[++i]];
11998                 for (j = start; j <= code; j++) {
11999                   glyphsVMetrics[j] = vmetric;
12000                 }
12001               }
12002             }
12003           }
12004         }
12005       } else {
12006         var firstChar = properties.firstChar;
12007         widths = dict.get('Widths');
12008         if (widths) {
12009           j = firstChar;
12010           for (i = 0, ii = widths.length; i < ii; i++) {
12011             glyphsWidths[j++] = widths[i];
12012           }
12013           defaultWidth = (parseFloat(descriptor.get('MissingWidth')) || 0);
12014         } else {
12015           // Trying get the BaseFont metrics (see comment above).
12016           var baseFontName = dict.get('BaseFont');
12017           if (isName(baseFontName)) {
12018             var metrics = this.getBaseFontMetrics(baseFontName.name);
12019
12020             glyphsWidths = this.buildCharCodeToWidth(metrics.widths,
12021                                                      properties);
12022             defaultWidth = metrics.defaultWidth;
12023           }
12024         }
12025       }
12026
12027       // Heuristic: detection of monospace font by checking all non-zero widths
12028       var isMonospace = true;
12029       var firstWidth = defaultWidth;
12030       for (var glyph in glyphsWidths) {
12031         var glyphWidth = glyphsWidths[glyph];
12032         if (!glyphWidth) {
12033           continue;
12034         }
12035         if (!firstWidth) {
12036           firstWidth = glyphWidth;
12037           continue;
12038         }
12039         if (firstWidth !== glyphWidth) {
12040           isMonospace = false;
12041           break;
12042         }
12043       }
12044       if (isMonospace) {
12045         properties.flags |= FontFlags.FixedPitch;
12046       }
12047
12048       properties.defaultWidth = defaultWidth;
12049       properties.widths = glyphsWidths;
12050       properties.defaultVMetrics = defaultVMetrics;
12051       properties.vmetrics = glyphsVMetrics;
12052     },
12053
12054     isSerifFont: function PartialEvaluator_isSerifFont(baseFontName) {
12055       // Simulating descriptor flags attribute
12056       var fontNameWoStyle = baseFontName.split('-')[0];
12057       return (fontNameWoStyle in serifFonts) ||
12058               (fontNameWoStyle.search(/serif/gi) !== -1);
12059     },
12060
12061     getBaseFontMetrics: function PartialEvaluator_getBaseFontMetrics(name) {
12062       var defaultWidth = 0;
12063       var widths = [];
12064       var monospace = false;
12065       var lookupName = (stdFontMap[name] || name);
12066
12067       if (!(lookupName in Metrics)) {
12068         // Use default fonts for looking up font metrics if the passed
12069         // font is not a base font
12070         if (this.isSerifFont(name)) {
12071           lookupName = 'Times-Roman';
12072         } else {
12073           lookupName = 'Helvetica';
12074         }
12075       }
12076       var glyphWidths = Metrics[lookupName];
12077
12078       if (isNum(glyphWidths)) {
12079         defaultWidth = glyphWidths;
12080         monospace = true;
12081       } else {
12082         widths = glyphWidths;
12083       }
12084
12085       return {
12086         defaultWidth: defaultWidth,
12087         monospace: monospace,
12088         widths: widths
12089       };
12090     },
12091
12092     buildCharCodeToWidth:
12093         function PartialEvaluator_bulildCharCodeToWidth(widthsByGlyphName,
12094                                                         properties) {
12095       var widths = Object.create(null);
12096       var differences = properties.differences;
12097       var encoding = properties.defaultEncoding;
12098       for (var charCode = 0; charCode < 256; charCode++) {
12099         if (charCode in differences &&
12100             widthsByGlyphName[differences[charCode]]) {
12101           widths[charCode] = widthsByGlyphName[differences[charCode]];
12102           continue;
12103         }
12104         if (charCode in encoding && widthsByGlyphName[encoding[charCode]]) {
12105           widths[charCode] = widthsByGlyphName[encoding[charCode]];
12106           continue;
12107         }
12108       }
12109       return widths;
12110     },
12111
12112     preEvaluateFont: function PartialEvaluator_preEvaluateFont(dict, xref) {
12113       var baseDict = dict;
12114       var type = dict.get('Subtype');
12115       assert(isName(type), 'invalid font Subtype');
12116
12117       var composite = false;
12118       var uint8array;
12119       if (type.name === 'Type0') {
12120         // If font is a composite
12121         //  - get the descendant font
12122         //  - set the type according to the descendant font
12123         //  - get the FontDescriptor from the descendant font
12124         var df = dict.get('DescendantFonts');
12125         if (!df) {
12126           error('Descendant fonts are not specified');
12127         }
12128         dict = (isArray(df) ? xref.fetchIfRef(df[0]) : df);
12129
12130         type = dict.get('Subtype');
12131         assert(isName(type), 'invalid font Subtype');
12132         composite = true;
12133       }
12134
12135       var descriptor = dict.get('FontDescriptor');
12136       if (descriptor) {
12137         var hash = new MurmurHash3_64();
12138         var encoding = baseDict.getRaw('Encoding');
12139         if (isName(encoding)) {
12140           hash.update(encoding.name);
12141         } else if (isRef(encoding)) {
12142           hash.update(encoding.num + '_' + encoding.gen);
12143         } else if (isDict(encoding)) {
12144           var keys = encoding.getKeys();
12145           for (var i = 0, ii = keys.length; i < ii; i++) {
12146             var entry = encoding.getRaw(keys[i]);
12147             if (isName(entry)) {
12148               hash.update(entry.name);
12149             } else if (isRef(entry)) {
12150               hash.update(entry.num + '_' + entry.gen);
12151             } else if (isArray(entry)) { // 'Differences' entry.
12152               // Ideally we should check the contents of the array, but to avoid
12153               // parsing it here and then again in |extractDataStructures|,
12154               // we only use the array length for now (fixes bug1157493.pdf).
12155               hash.update(entry.length.toString());
12156             }
12157           }
12158         }
12159
12160         var toUnicode = dict.get('ToUnicode') || baseDict.get('ToUnicode');
12161         if (isStream(toUnicode)) {
12162           var stream = toUnicode.str || toUnicode;
12163           uint8array = stream.buffer ?
12164             new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) :
12165             new Uint8Array(stream.bytes.buffer,
12166                            stream.start, stream.end - stream.start);
12167           hash.update(uint8array);
12168
12169         } else if (isName(toUnicode)) {
12170           hash.update(toUnicode.name);
12171         }
12172
12173         var widths = dict.get('Widths') || baseDict.get('Widths');
12174         if (widths) {
12175           uint8array = new Uint8Array(new Uint32Array(widths).buffer);
12176           hash.update(uint8array);
12177         }
12178       }
12179
12180       return {
12181         descriptor: descriptor,
12182         dict: dict,
12183         baseDict: baseDict,
12184         composite: composite,
12185         type: type.name,
12186         hash: hash ? hash.hexdigest() : ''
12187       };
12188     },
12189
12190     translateFont: function PartialEvaluator_translateFont(preEvaluatedFont,
12191                                                            xref) {
12192       var baseDict = preEvaluatedFont.baseDict;
12193       var dict = preEvaluatedFont.dict;
12194       var composite = preEvaluatedFont.composite;
12195       var descriptor = preEvaluatedFont.descriptor;
12196       var type = preEvaluatedFont.type;
12197       var maxCharIndex = (composite ? 0xFFFF : 0xFF);
12198       var properties;
12199
12200       if (!descriptor) {
12201         if (type === 'Type3') {
12202           // FontDescriptor is only required for Type3 fonts when the document
12203           // is a tagged pdf. Create a barbebones one to get by.
12204           descriptor = new Dict(null);
12205           descriptor.set('FontName', Name.get(type));
12206           descriptor.set('FontBBox', dict.get('FontBBox'));
12207         } else {
12208           // Before PDF 1.5 if the font was one of the base 14 fonts, having a
12209           // FontDescriptor was not required.
12210           // This case is here for compatibility.
12211           var baseFontName = dict.get('BaseFont');
12212           if (!isName(baseFontName)) {
12213             error('Base font is not specified');
12214           }
12215
12216           // Using base font name as a font name.
12217           baseFontName = baseFontName.name.replace(/[,_]/g, '-');
12218           var metrics = this.getBaseFontMetrics(baseFontName);
12219
12220           // Simulating descriptor flags attribute
12221           var fontNameWoStyle = baseFontName.split('-')[0];
12222           var flags =
12223             (this.isSerifFont(fontNameWoStyle) ? FontFlags.Serif : 0) |
12224             (metrics.monospace ? FontFlags.FixedPitch : 0) |
12225             (symbolsFonts[fontNameWoStyle] ? FontFlags.Symbolic :
12226                                              FontFlags.Nonsymbolic);
12227
12228           properties = {
12229             type: type,
12230             name: baseFontName,
12231             widths: metrics.widths,
12232             defaultWidth: metrics.defaultWidth,
12233             flags: flags,
12234             firstChar: 0,
12235             lastChar: maxCharIndex
12236           };
12237           this.extractDataStructures(dict, dict, xref, properties);
12238           properties.widths = this.buildCharCodeToWidth(metrics.widths,
12239                                                         properties);
12240           return new Font(baseFontName, null, properties);
12241         }
12242       }
12243
12244       // According to the spec if 'FontDescriptor' is declared, 'FirstChar',
12245       // 'LastChar' and 'Widths' should exist too, but some PDF encoders seem
12246       // to ignore this rule when a variant of a standart font is used.
12247       // TODO Fill the width array depending on which of the base font this is
12248       // a variant.
12249       var firstChar = (dict.get('FirstChar') || 0);
12250       var lastChar = (dict.get('LastChar') || maxCharIndex);
12251
12252       var fontName = descriptor.get('FontName');
12253       var baseFont = dict.get('BaseFont');
12254       // Some bad PDFs have a string as the font name.
12255       if (isString(fontName)) {
12256         fontName = Name.get(fontName);
12257       }
12258       if (isString(baseFont)) {
12259         baseFont = Name.get(baseFont);
12260       }
12261
12262       if (type !== 'Type3') {
12263         var fontNameStr = fontName && fontName.name;
12264         var baseFontStr = baseFont && baseFont.name;
12265         if (fontNameStr !== baseFontStr) {
12266           info('The FontDescriptor\'s FontName is "' + fontNameStr +
12267                '" but should be the same as the Font\'s BaseFont "' +
12268                baseFontStr + '"');
12269           // Workaround for cases where e.g. fontNameStr = 'Arial' and
12270           // baseFontStr = 'Arial,Bold' (needed when no font file is embedded).
12271           if (fontNameStr && baseFontStr &&
12272               baseFontStr.indexOf(fontNameStr) === 0) {
12273             fontName = baseFont;
12274           }
12275         }
12276       }
12277       fontName = (fontName || baseFont);
12278
12279       assert(isName(fontName), 'invalid font name');
12280
12281       var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
12282       if (fontFile) {
12283         if (fontFile.dict) {
12284           var subtype = fontFile.dict.get('Subtype');
12285           if (subtype) {
12286             subtype = subtype.name;
12287           }
12288           var length1 = fontFile.dict.get('Length1');
12289           var length2 = fontFile.dict.get('Length2');
12290         }
12291       }
12292
12293       properties = {
12294         type: type,
12295         name: fontName.name,
12296         subtype: subtype,
12297         file: fontFile,
12298         length1: length1,
12299         length2: length2,
12300         loadedName: baseDict.loadedName,
12301         composite: composite,
12302         wideChars: composite,
12303         fixedPitch: false,
12304         fontMatrix: (dict.get('FontMatrix') || FONT_IDENTITY_MATRIX),
12305         firstChar: firstChar || 0,
12306         lastChar: (lastChar || maxCharIndex),
12307         bbox: descriptor.get('FontBBox'),
12308         ascent: descriptor.get('Ascent'),
12309         descent: descriptor.get('Descent'),
12310         xHeight: descriptor.get('XHeight'),
12311         capHeight: descriptor.get('CapHeight'),
12312         flags: descriptor.get('Flags'),
12313         italicAngle: descriptor.get('ItalicAngle'),
12314         coded: false
12315       };
12316
12317       if (composite) {
12318         var cidEncoding = baseDict.get('Encoding');
12319         if (isName(cidEncoding)) {
12320           properties.cidEncoding = cidEncoding.name;
12321         }
12322         properties.cMap = CMapFactory.create(cidEncoding,
12323           { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
12324         properties.vertical = properties.cMap.vertical;
12325       }
12326       this.extractDataStructures(dict, baseDict, xref, properties);
12327       this.extractWidths(dict, xref, descriptor, properties);
12328
12329       if (type === 'Type3') {
12330         properties.isType3Font = true;
12331       }
12332
12333       return new Font(fontName.name, fontFile, properties);
12334     }
12335   };
12336
12337   return PartialEvaluator;
12338 })();
12339
12340 var TranslatedFont = (function TranslatedFontClosure() {
12341   function TranslatedFont(loadedName, font, dict) {
12342     this.loadedName = loadedName;
12343     this.font = font;
12344     this.dict = dict;
12345     this.type3Loaded = null;
12346     this.sent = false;
12347   }
12348   TranslatedFont.prototype = {
12349     send: function (handler) {
12350       if (this.sent) {
12351         return;
12352       }
12353       var fontData = this.font.exportData();
12354       handler.send('commonobj', [
12355         this.loadedName,
12356         'Font',
12357         fontData
12358       ]);
12359       this.sent = true;
12360     },
12361     loadType3Data: function (evaluator, resources, parentOperatorList) {
12362       assert(this.font.isType3Font);
12363
12364       if (this.type3Loaded) {
12365         return this.type3Loaded;
12366       }
12367
12368       var translatedFont = this.font;
12369       var loadCharProcsPromise = Promise.resolve();
12370       var charProcs = this.dict.get('CharProcs').getAll();
12371       var fontResources = this.dict.get('Resources') || resources;
12372       var charProcKeys = Object.keys(charProcs);
12373       var charProcOperatorList = {};
12374       for (var i = 0, n = charProcKeys.length; i < n; ++i) {
12375         loadCharProcsPromise = loadCharProcsPromise.then(function (key) {
12376           var glyphStream = charProcs[key];
12377           var operatorList = new OperatorList();
12378           return evaluator.getOperatorList(glyphStream, fontResources,
12379                                            operatorList).then(function () {
12380             charProcOperatorList[key] = operatorList.getIR();
12381
12382             // Add the dependencies to the parent operator list so they are
12383             // resolved before sub operator list is executed synchronously.
12384             parentOperatorList.addDependencies(operatorList.dependencies);
12385           }, function (reason) {
12386             warn('Type3 font resource \"' + key + '\" is not available');
12387             var operatorList = new OperatorList();
12388             charProcOperatorList[key] = operatorList.getIR();
12389           });
12390         }.bind(this, charProcKeys[i]));
12391       }
12392       this.type3Loaded = loadCharProcsPromise.then(function () {
12393         translatedFont.charProcOperatorList = charProcOperatorList;
12394       });
12395       return this.type3Loaded;
12396     }
12397   };
12398   return TranslatedFont;
12399 })();
12400
12401 var OperatorList = (function OperatorListClosure() {
12402   var CHUNK_SIZE = 1000;
12403   var CHUNK_SIZE_ABOUT = CHUNK_SIZE - 5; // close to chunk size
12404
12405   function getTransfers(queue) {
12406     var transfers = [];
12407     var fnArray = queue.fnArray, argsArray = queue.argsArray;
12408     for (var i = 0, ii = queue.length; i < ii; i++) {
12409       switch (fnArray[i]) {
12410         case OPS.paintInlineImageXObject:
12411         case OPS.paintInlineImageXObjectGroup:
12412         case OPS.paintImageMaskXObject:
12413           var arg = argsArray[i][0]; // first param in imgData
12414           if (!arg.cached) {
12415             transfers.push(arg.data.buffer);
12416           }
12417           break;
12418       }
12419     }
12420     return transfers;
12421   }
12422
12423   function OperatorList(intent, messageHandler, pageIndex) {
12424     this.messageHandler = messageHandler;
12425     this.fnArray = [];
12426     this.argsArray = [];
12427     this.dependencies = {};
12428     this.pageIndex = pageIndex;
12429     this.intent = intent;
12430   }
12431
12432   OperatorList.prototype = {
12433     get length() {
12434       return this.argsArray.length;
12435     },
12436
12437     addOp: function(fn, args) {
12438       this.fnArray.push(fn);
12439       this.argsArray.push(args);
12440       if (this.messageHandler) {
12441         if (this.fnArray.length >= CHUNK_SIZE) {
12442           this.flush();
12443         } else if (this.fnArray.length >= CHUNK_SIZE_ABOUT &&
12444                    (fn === OPS.restore || fn === OPS.endText)) {
12445           // heuristic to flush on boundary of restore or endText
12446           this.flush();
12447         }
12448       }
12449     },
12450
12451     addDependency: function(dependency) {
12452       if (dependency in this.dependencies) {
12453         return;
12454       }
12455       this.dependencies[dependency] = true;
12456       this.addOp(OPS.dependency, [dependency]);
12457     },
12458
12459     addDependencies: function(dependencies) {
12460       for (var key in dependencies) {
12461         this.addDependency(key);
12462       }
12463     },
12464
12465     addOpList: function(opList) {
12466       Util.extendObj(this.dependencies, opList.dependencies);
12467       for (var i = 0, ii = opList.length; i < ii; i++) {
12468         this.addOp(opList.fnArray[i], opList.argsArray[i]);
12469       }
12470     },
12471
12472     getIR: function() {
12473       return {
12474         fnArray: this.fnArray,
12475         argsArray: this.argsArray,
12476         length: this.length
12477       };
12478     },
12479
12480     flush: function(lastChunk) {
12481       if (this.intent !== 'oplist') {
12482         new QueueOptimizer().optimize(this);
12483       }
12484       var transfers = getTransfers(this);
12485       this.messageHandler.send('RenderPageChunk', {
12486         operatorList: {
12487           fnArray: this.fnArray,
12488           argsArray: this.argsArray,
12489           lastChunk: lastChunk,
12490           length: this.length
12491         },
12492         pageIndex: this.pageIndex,
12493         intent: this.intent
12494       }, transfers);
12495       this.dependencies = {};
12496       this.fnArray.length = 0;
12497       this.argsArray.length = 0;
12498     }
12499   };
12500
12501   return OperatorList;
12502 })();
12503
12504 var StateManager = (function StateManagerClosure() {
12505   function StateManager(initialState) {
12506     this.state = initialState;
12507     this.stateStack = [];
12508   }
12509   StateManager.prototype = {
12510     save: function () {
12511       var old = this.state;
12512       this.stateStack.push(this.state);
12513       this.state = old.clone();
12514     },
12515     restore: function () {
12516       var prev = this.stateStack.pop();
12517       if (prev) {
12518         this.state = prev;
12519       }
12520     },
12521     transform: function (args) {
12522       this.state.ctm = Util.transform(this.state.ctm, args);
12523     }
12524   };
12525   return StateManager;
12526 })();
12527
12528 var TextState = (function TextStateClosure() {
12529   function TextState() {
12530     this.ctm = new Float32Array(IDENTITY_MATRIX);
12531     this.fontSize = 0;
12532     this.font = null;
12533     this.fontMatrix = FONT_IDENTITY_MATRIX;
12534     this.textMatrix = IDENTITY_MATRIX.slice();
12535     this.textLineMatrix = IDENTITY_MATRIX.slice();
12536     this.charSpacing = 0;
12537     this.wordSpacing = 0;
12538     this.leading = 0;
12539     this.textHScale = 1;
12540     this.textRise = 0;
12541   }
12542
12543   TextState.prototype = {
12544     setTextMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
12545       var m = this.textMatrix;
12546       m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
12547     },
12548     setTextLineMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
12549       var m = this.textLineMatrix;
12550       m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
12551     },
12552     translateTextMatrix: function TextState_translateTextMatrix(x, y) {
12553       var m = this.textMatrix;
12554       m[4] = m[0] * x + m[2] * y + m[4];
12555       m[5] = m[1] * x + m[3] * y + m[5];
12556     },
12557     translateTextLineMatrix: function TextState_translateTextMatrix(x, y) {
12558       var m = this.textLineMatrix;
12559       m[4] = m[0] * x + m[2] * y + m[4];
12560       m[5] = m[1] * x + m[3] * y + m[5];
12561     },
12562     calcRenderMatrix: function TextState_calcRendeMatrix(ctm) {
12563       // 9.4.4 Text Space Details
12564       var tsm = [this.fontSize * this.textHScale, 0,
12565                 0, this.fontSize,
12566                 0, this.textRise];
12567       return Util.transform(ctm, Util.transform(this.textMatrix, tsm));
12568     },
12569     carriageReturn: function TextState_carriageReturn() {
12570       this.translateTextLineMatrix(0, -this.leading);
12571       this.textMatrix = this.textLineMatrix.slice();
12572     },
12573     clone: function TextState_clone() {
12574       var clone = Object.create(this);
12575       clone.textMatrix = this.textMatrix.slice();
12576       clone.textLineMatrix = this.textLineMatrix.slice();
12577       clone.fontMatrix = this.fontMatrix.slice();
12578       return clone;
12579     }
12580   };
12581   return TextState;
12582 })();
12583
12584 var EvalState = (function EvalStateClosure() {
12585   function EvalState() {
12586     this.ctm = new Float32Array(IDENTITY_MATRIX);
12587     this.font = null;
12588     this.textRenderingMode = TextRenderingMode.FILL;
12589     this.fillColorSpace = ColorSpace.singletons.gray;
12590     this.strokeColorSpace = ColorSpace.singletons.gray;
12591   }
12592   EvalState.prototype = {
12593     clone: function CanvasExtraState_clone() {
12594       return Object.create(this);
12595     },
12596   };
12597   return EvalState;
12598 })();
12599
12600 var EvaluatorPreprocessor = (function EvaluatorPreprocessorClosure() {
12601   // Specifies properties for each command
12602   //
12603   // If variableArgs === true: [0, `numArgs`] expected
12604   // If variableArgs === false: exactly `numArgs` expected
12605   var OP_MAP = {
12606     // Graphic state
12607     w: { id: OPS.setLineWidth, numArgs: 1, variableArgs: false },
12608     J: { id: OPS.setLineCap, numArgs: 1, variableArgs: false },
12609     j: { id: OPS.setLineJoin, numArgs: 1, variableArgs: false },
12610     M: { id: OPS.setMiterLimit, numArgs: 1, variableArgs: false },
12611     d: { id: OPS.setDash, numArgs: 2, variableArgs: false },
12612     ri: { id: OPS.setRenderingIntent, numArgs: 1, variableArgs: false },
12613     i: { id: OPS.setFlatness, numArgs: 1, variableArgs: false },
12614     gs: { id: OPS.setGState, numArgs: 1, variableArgs: false },
12615     q: { id: OPS.save, numArgs: 0, variableArgs: false },
12616     Q: { id: OPS.restore, numArgs: 0, variableArgs: false },
12617     cm: { id: OPS.transform, numArgs: 6, variableArgs: false },
12618
12619     // Path
12620     m: { id: OPS.moveTo, numArgs: 2, variableArgs: false },
12621     l: { id: OPS.lineTo, numArgs: 2, variableArgs: false },
12622     c: { id: OPS.curveTo, numArgs: 6, variableArgs: false },
12623     v: { id: OPS.curveTo2, numArgs: 4, variableArgs: false },
12624     y: { id: OPS.curveTo3, numArgs: 4, variableArgs: false },
12625     h: { id: OPS.closePath, numArgs: 0, variableArgs: false },
12626     re: { id: OPS.rectangle, numArgs: 4, variableArgs: false },
12627     S: { id: OPS.stroke, numArgs: 0, variableArgs: false },
12628     s: { id: OPS.closeStroke, numArgs: 0, variableArgs: false },
12629     f: { id: OPS.fill, numArgs: 0, variableArgs: false },
12630     F: { id: OPS.fill, numArgs: 0, variableArgs: false },
12631     'f*': { id: OPS.eoFill, numArgs: 0, variableArgs: false },
12632     B: { id: OPS.fillStroke, numArgs: 0, variableArgs: false },
12633     'B*': { id: OPS.eoFillStroke, numArgs: 0, variableArgs: false },
12634     b: { id: OPS.closeFillStroke, numArgs: 0, variableArgs: false },
12635     'b*': { id: OPS.closeEOFillStroke, numArgs: 0, variableArgs: false },
12636     n: { id: OPS.endPath, numArgs: 0, variableArgs: false },
12637
12638     // Clipping
12639     W: { id: OPS.clip, numArgs: 0, variableArgs: false },
12640     'W*': { id: OPS.eoClip, numArgs: 0, variableArgs: false },
12641
12642     // Text
12643     BT: { id: OPS.beginText, numArgs: 0, variableArgs: false },
12644     ET: { id: OPS.endText, numArgs: 0, variableArgs: false },
12645     Tc: { id: OPS.setCharSpacing, numArgs: 1, variableArgs: false },
12646     Tw: { id: OPS.setWordSpacing, numArgs: 1, variableArgs: false },
12647     Tz: { id: OPS.setHScale, numArgs: 1, variableArgs: false },
12648     TL: { id: OPS.setLeading, numArgs: 1, variableArgs: false },
12649     Tf: { id: OPS.setFont, numArgs: 2, variableArgs: false },
12650     Tr: { id: OPS.setTextRenderingMode, numArgs: 1, variableArgs: false },
12651     Ts: { id: OPS.setTextRise, numArgs: 1, variableArgs: false },
12652     Td: { id: OPS.moveText, numArgs: 2, variableArgs: false },
12653     TD: { id: OPS.setLeadingMoveText, numArgs: 2, variableArgs: false },
12654     Tm: { id: OPS.setTextMatrix, numArgs: 6, variableArgs: false },
12655     'T*': { id: OPS.nextLine, numArgs: 0, variableArgs: false },
12656     Tj: { id: OPS.showText, numArgs: 1, variableArgs: false },
12657     TJ: { id: OPS.showSpacedText, numArgs: 1, variableArgs: false },
12658     '\'': { id: OPS.nextLineShowText, numArgs: 1, variableArgs: false },
12659     '"': { id: OPS.nextLineSetSpacingShowText, numArgs: 3,
12660            variableArgs: false },
12661
12662     // Type3 fonts
12663     d0: { id: OPS.setCharWidth, numArgs: 2, variableArgs: false },
12664     d1: { id: OPS.setCharWidthAndBounds, numArgs: 6, variableArgs: false },
12665
12666     // Color
12667     CS: { id: OPS.setStrokeColorSpace, numArgs: 1, variableArgs: false },
12668     cs: { id: OPS.setFillColorSpace, numArgs: 1, variableArgs: false },
12669     SC: { id: OPS.setStrokeColor, numArgs: 4, variableArgs: true },
12670     SCN: { id: OPS.setStrokeColorN, numArgs: 33, variableArgs: true },
12671     sc: { id: OPS.setFillColor, numArgs: 4, variableArgs: true },
12672     scn: { id: OPS.setFillColorN, numArgs: 33, variableArgs: true },
12673     G: { id: OPS.setStrokeGray, numArgs: 1, variableArgs: false },
12674     g: { id: OPS.setFillGray, numArgs: 1, variableArgs: false },
12675     RG: { id: OPS.setStrokeRGBColor, numArgs: 3, variableArgs: false },
12676     rg: { id: OPS.setFillRGBColor, numArgs: 3, variableArgs: false },
12677     K: { id: OPS.setStrokeCMYKColor, numArgs: 4, variableArgs: false },
12678     k: { id: OPS.setFillCMYKColor, numArgs: 4, variableArgs: false },
12679
12680     // Shading
12681     sh: { id: OPS.shadingFill, numArgs: 1, variableArgs: false },
12682
12683     // Images
12684     BI: { id: OPS.beginInlineImage, numArgs: 0, variableArgs: false },
12685     ID: { id: OPS.beginImageData, numArgs: 0, variableArgs: false },
12686     EI: { id: OPS.endInlineImage, numArgs: 1, variableArgs: false },
12687
12688     // XObjects
12689     Do: { id: OPS.paintXObject, numArgs: 1, variableArgs: false },
12690     MP: { id: OPS.markPoint, numArgs: 1, variableArgs: false },
12691     DP: { id: OPS.markPointProps, numArgs: 2, variableArgs: false },
12692     BMC: { id: OPS.beginMarkedContent, numArgs: 1, variableArgs: false },
12693     BDC: { id: OPS.beginMarkedContentProps, numArgs: 2,
12694            variableArgs: false },
12695     EMC: { id: OPS.endMarkedContent, numArgs: 0, variableArgs: false },
12696
12697     // Compatibility
12698     BX: { id: OPS.beginCompat, numArgs: 0, variableArgs: false },
12699     EX: { id: OPS.endCompat, numArgs: 0, variableArgs: false },
12700
12701     // (reserved partial commands for the lexer)
12702     BM: null,
12703     BD: null,
12704     'true': null,
12705     fa: null,
12706     fal: null,
12707     fals: null,
12708     'false': null,
12709     nu: null,
12710     nul: null,
12711     'null': null
12712   };
12713
12714   function EvaluatorPreprocessor(stream, xref, stateManager) {
12715     // TODO(mduan): pass array of knownCommands rather than OP_MAP
12716     // dictionary
12717     this.parser = new Parser(new Lexer(stream, OP_MAP), false, xref);
12718     this.stateManager = stateManager;
12719     this.nonProcessedArgs = [];
12720   }
12721
12722   EvaluatorPreprocessor.prototype = {
12723     get savedStatesDepth() {
12724       return this.stateManager.stateStack.length;
12725     },
12726
12727     // |operation| is an object with two fields:
12728     //
12729     // - |fn| is an out param.
12730     //
12731     // - |args| is an inout param. On entry, it should have one of two values.
12732     //
12733     //   - An empty array. This indicates that the caller is providing the
12734     //     array in which the args will be stored in. The caller should use
12735     //     this value if it can reuse a single array for each call to read().
12736     //
12737     //   - |null|. This indicates that the caller needs this function to create
12738     //     the array in which any args are stored in. If there are zero args,
12739     //     this function will leave |operation.args| as |null| (thus avoiding
12740     //     allocations that would occur if we used an empty array to represent
12741     //     zero arguments). Otherwise, it will replace |null| with a new array
12742     //     containing the arguments. The caller should use this value if it
12743     //     cannot reuse an array for each call to read().
12744     //
12745     // These two modes are present because this function is very hot and so
12746     // avoiding allocations where possible is worthwhile.
12747     //
12748     read: function EvaluatorPreprocessor_read(operation) {
12749       var args = operation.args;
12750       while (true) {
12751         var obj = this.parser.getObj();
12752         if (isCmd(obj)) {
12753           var cmd = obj.cmd;
12754           // Check that the command is valid
12755           var opSpec = OP_MAP[cmd];
12756           if (!opSpec) {
12757             warn('Unknown command "' + cmd + '"');
12758             continue;
12759           }
12760
12761           var fn = opSpec.id;
12762           var numArgs = opSpec.numArgs;
12763           var argsLength = args !== null ? args.length : 0;
12764
12765           if (!opSpec.variableArgs) {
12766             // Postscript commands can be nested, e.g. /F2 /GS2 gs 5.711 Tf
12767             if (argsLength !== numArgs) {
12768               var nonProcessedArgs = this.nonProcessedArgs;
12769               while (argsLength > numArgs) {
12770                 nonProcessedArgs.push(args.shift());
12771                 argsLength--;
12772               }
12773               while (argsLength < numArgs && nonProcessedArgs.length !== 0) {
12774                 if (!args) {
12775                   args = [];
12776                 }
12777                 args.unshift(nonProcessedArgs.pop());
12778                 argsLength++;
12779               }
12780             }
12781
12782             if (argsLength < numArgs) {
12783               // If we receive too few args, it's not possible to possible
12784               // to execute the command, so skip the command
12785               info('Command ' + fn + ': because expected ' +
12786                    numArgs + ' args, but received ' + argsLength +
12787                    ' args; skipping');
12788               args = null;
12789               continue;
12790             }
12791           } else if (argsLength > numArgs) {
12792             info('Command ' + fn + ': expected [0,' + numArgs +
12793                  '] args, but received ' + argsLength + ' args');
12794           }
12795
12796           // TODO figure out how to type-check vararg functions
12797           this.preprocessCommand(fn, args);
12798
12799           operation.fn = fn;
12800           operation.args = args;
12801           return true;
12802         } else {
12803           if (isEOF(obj)) {
12804             return false; // no more commands
12805           }
12806           // argument
12807           if (obj !== null) {
12808             if (!args) {
12809               args = [];
12810             }
12811             args.push((obj instanceof Dict ? obj.getAll() : obj));
12812             assert(args.length <= 33, 'Too many arguments');
12813           }
12814         }
12815       }
12816     },
12817
12818     preprocessCommand:
12819         function EvaluatorPreprocessor_preprocessCommand(fn, args) {
12820       switch (fn | 0) {
12821         case OPS.save:
12822           this.stateManager.save();
12823           break;
12824         case OPS.restore:
12825           this.stateManager.restore();
12826           break;
12827         case OPS.transform:
12828           this.stateManager.transform(args);
12829           break;
12830       }
12831     }
12832   };
12833   return EvaluatorPreprocessor;
12834 })();
12835
12836 var QueueOptimizer = (function QueueOptimizerClosure() {
12837   function addState(parentState, pattern, fn) {
12838     var state = parentState;
12839     for (var i = 0, ii = pattern.length - 1; i < ii; i++) {
12840       var item = pattern[i];
12841       state = (state[item] || (state[item] = []));
12842     }
12843     state[pattern[pattern.length - 1]] = fn;
12844   }
12845
12846   function handlePaintSolidColorImageMask(iFirstSave, count, fnArray,
12847                                           argsArray) {
12848     // Handles special case of mainly LaTeX documents which use image masks to
12849     // draw lines with the current fill style.
12850     // 'count' groups of (save, transform, paintImageMaskXObject, restore)+
12851     // have been found at iFirstSave.
12852     var iFirstPIMXO = iFirstSave + 2;
12853     for (var i = 0; i < count; i++) {
12854       var arg = argsArray[iFirstPIMXO + 4 * i];
12855       var imageMask = arg.length === 1 && arg[0];
12856       if (imageMask && imageMask.width === 1 && imageMask.height === 1 &&
12857           (!imageMask.data.length ||
12858            (imageMask.data.length === 1 && imageMask.data[0] === 0))) {
12859         fnArray[iFirstPIMXO + 4 * i] = OPS.paintSolidColorImageMask;
12860         continue;
12861       }
12862       break;
12863     }
12864     return count - i;
12865   }
12866
12867   var InitialState = [];
12868
12869   // This replaces (save, transform, paintInlineImageXObject, restore)+
12870   // sequences with one |paintInlineImageXObjectGroup| operation.
12871   addState(InitialState,
12872     [OPS.save, OPS.transform, OPS.paintInlineImageXObject, OPS.restore],
12873     function foundInlineImageGroup(context) {
12874       var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10;
12875       var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200;
12876       var MAX_WIDTH = 1000;
12877       var IMAGE_PADDING = 1;
12878
12879       var fnArray = context.fnArray, argsArray = context.argsArray;
12880       var curr = context.iCurr;
12881       var iFirstSave = curr - 3;
12882       var iFirstTransform = curr - 2;
12883       var iFirstPIIXO = curr - 1;
12884
12885       // Look for the quartets.
12886       var i = iFirstSave + 4;
12887       var ii = fnArray.length;
12888       while (i + 3 < ii) {
12889         if (fnArray[i] !== OPS.save ||
12890             fnArray[i + 1] !== OPS.transform ||
12891             fnArray[i + 2] !== OPS.paintInlineImageXObject ||
12892             fnArray[i + 3] !== OPS.restore) {
12893           break;    // ops don't match
12894         }
12895         i += 4;
12896       }
12897
12898       // At this point, i is the index of the first op past the last valid
12899       // quartet.
12900       var count = Math.min((i - iFirstSave) / 4,
12901                            MAX_IMAGES_IN_INLINE_IMAGES_BLOCK);
12902       if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) {
12903         return i;
12904       }
12905
12906       // assuming that heights of those image is too small (~1 pixel)
12907       // packing as much as possible by lines
12908       var maxX = 0;
12909       var map = [], maxLineHeight = 0;
12910       var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING;
12911       var q;
12912       for (q = 0; q < count; q++) {
12913         var transform = argsArray[iFirstTransform + (q << 2)];
12914         var img = argsArray[iFirstPIIXO + (q << 2)][0];
12915         if (currentX + img.width > MAX_WIDTH) {
12916           // starting new line
12917           maxX = Math.max(maxX, currentX);
12918           currentY += maxLineHeight + 2 * IMAGE_PADDING;
12919           currentX = 0;
12920           maxLineHeight = 0;
12921         }
12922         map.push({
12923           transform: transform,
12924           x: currentX, y: currentY,
12925           w: img.width, h: img.height
12926         });
12927         currentX += img.width + 2 * IMAGE_PADDING;
12928         maxLineHeight = Math.max(maxLineHeight, img.height);
12929       }
12930       var imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING;
12931       var imgHeight = currentY + maxLineHeight + IMAGE_PADDING;
12932       var imgData = new Uint8Array(imgWidth * imgHeight * 4);
12933       var imgRowSize = imgWidth << 2;
12934       for (q = 0; q < count; q++) {
12935         var data = argsArray[iFirstPIIXO + (q << 2)][0].data;
12936         // Copy image by lines and extends pixels into padding.
12937         var rowSize = map[q].w << 2;
12938         var dataOffset = 0;
12939         var offset = (map[q].x + map[q].y * imgWidth) << 2;
12940         imgData.set(data.subarray(0, rowSize), offset - imgRowSize);
12941         for (var k = 0, kk = map[q].h; k < kk; k++) {
12942           imgData.set(data.subarray(dataOffset, dataOffset + rowSize), offset);
12943           dataOffset += rowSize;
12944           offset += imgRowSize;
12945         }
12946         imgData.set(data.subarray(dataOffset - rowSize, dataOffset), offset);
12947         while (offset >= 0) {
12948           data[offset - 4] = data[offset];
12949           data[offset - 3] = data[offset + 1];
12950           data[offset - 2] = data[offset + 2];
12951           data[offset - 1] = data[offset + 3];
12952           data[offset + rowSize] = data[offset + rowSize - 4];
12953           data[offset + rowSize + 1] = data[offset + rowSize - 3];
12954           data[offset + rowSize + 2] = data[offset + rowSize - 2];
12955           data[offset + rowSize + 3] = data[offset + rowSize - 1];
12956           offset -= imgRowSize;
12957         }
12958       }
12959
12960       // Replace queue items.
12961       fnArray.splice(iFirstSave, count * 4, OPS.paintInlineImageXObjectGroup);
12962       argsArray.splice(iFirstSave, count * 4,
12963         [{ width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP,
12964            data: imgData }, map]);
12965
12966       return iFirstSave + 1;
12967     });
12968
12969   // This replaces (save, transform, paintImageMaskXObject, restore)+
12970   // sequences with one |paintImageMaskXObjectGroup| or one
12971   // |paintImageMaskXObjectRepeat| operation.
12972   addState(InitialState,
12973     [OPS.save, OPS.transform, OPS.paintImageMaskXObject, OPS.restore],
12974     function foundImageMaskGroup(context) {
12975       var MIN_IMAGES_IN_MASKS_BLOCK = 10;
12976       var MAX_IMAGES_IN_MASKS_BLOCK = 100;
12977       var MAX_SAME_IMAGES_IN_MASKS_BLOCK = 1000;
12978
12979       var fnArray = context.fnArray, argsArray = context.argsArray;
12980       var curr = context.iCurr;
12981       var iFirstSave = curr - 3;
12982       var iFirstTransform = curr - 2;
12983       var iFirstPIMXO = curr - 1;
12984
12985       // Look for the quartets.
12986       var i = iFirstSave + 4;
12987       var ii = fnArray.length;
12988       while (i + 3 < ii) {
12989         if (fnArray[i] !== OPS.save ||
12990             fnArray[i + 1] !== OPS.transform ||
12991             fnArray[i + 2] !== OPS.paintImageMaskXObject ||
12992             fnArray[i + 3] !== OPS.restore) {
12993           break;    // ops don't match
12994         }
12995         i += 4;
12996       }
12997
12998       // At this point, i is the index of the first op past the last valid
12999       // quartet.
13000       var count = (i - iFirstSave) / 4;
13001       count = handlePaintSolidColorImageMask(iFirstSave, count, fnArray,
13002                                              argsArray);
13003       if (count < MIN_IMAGES_IN_MASKS_BLOCK) {
13004         return i;
13005       }
13006
13007       var q;
13008       var isSameImage = false;
13009       var iTransform, transformArgs;
13010       var firstPIMXOArg0 = argsArray[iFirstPIMXO][0];
13011       if (argsArray[iFirstTransform][1] === 0 &&
13012           argsArray[iFirstTransform][2] === 0) {
13013         isSameImage = true;
13014         var firstTransformArg0 = argsArray[iFirstTransform][0];
13015         var firstTransformArg3 = argsArray[iFirstTransform][3];
13016         iTransform = iFirstTransform + 4;
13017         var iPIMXO = iFirstPIMXO + 4;
13018         for (q = 1; q < count; q++, iTransform += 4, iPIMXO += 4) {
13019           transformArgs = argsArray[iTransform];
13020           if (argsArray[iPIMXO][0] !== firstPIMXOArg0 ||
13021               transformArgs[0] !== firstTransformArg0 ||
13022               transformArgs[1] !== 0 ||
13023               transformArgs[2] !== 0 ||
13024               transformArgs[3] !== firstTransformArg3) {
13025             if (q < MIN_IMAGES_IN_MASKS_BLOCK) {
13026               isSameImage = false;
13027             } else {
13028               count = q;
13029             }
13030             break; // different image or transform
13031           }
13032         }
13033       }
13034
13035       if (isSameImage) {
13036         count = Math.min(count, MAX_SAME_IMAGES_IN_MASKS_BLOCK);
13037         var positions = new Float32Array(count * 2);
13038         iTransform = iFirstTransform;
13039         for (q = 0; q < count; q++, iTransform += 4) {
13040           transformArgs = argsArray[iTransform];
13041           positions[(q << 1)] = transformArgs[4];
13042           positions[(q << 1) + 1] = transformArgs[5];
13043         }
13044
13045         // Replace queue items.
13046         fnArray.splice(iFirstSave, count * 4, OPS.paintImageMaskXObjectRepeat);
13047         argsArray.splice(iFirstSave, count * 4,
13048           [firstPIMXOArg0, firstTransformArg0, firstTransformArg3, positions]);
13049       } else {
13050         count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK);
13051         var images = [];
13052         for (q = 0; q < count; q++) {
13053           transformArgs = argsArray[iFirstTransform + (q << 2)];
13054           var maskParams = argsArray[iFirstPIMXO + (q << 2)][0];
13055           images.push({ data: maskParams.data, width: maskParams.width,
13056                         height: maskParams.height,
13057                         transform: transformArgs });
13058         }
13059
13060         // Replace queue items.
13061         fnArray.splice(iFirstSave, count * 4, OPS.paintImageMaskXObjectGroup);
13062         argsArray.splice(iFirstSave, count * 4, [images]);
13063       }
13064
13065       return iFirstSave + 1;
13066     });
13067
13068   // This replaces (save, transform, paintImageXObject, restore)+ sequences
13069   // with one paintImageXObjectRepeat operation, if the |transform| and
13070   // |paintImageXObjectRepeat| ops are appropriate.
13071   addState(InitialState,
13072     [OPS.save, OPS.transform, OPS.paintImageXObject, OPS.restore],
13073     function (context) {
13074       var MIN_IMAGES_IN_BLOCK = 3;
13075       var MAX_IMAGES_IN_BLOCK = 1000;
13076
13077       var fnArray = context.fnArray, argsArray = context.argsArray;
13078       var curr = context.iCurr;
13079       var iFirstSave = curr - 3;
13080       var iFirstTransform = curr - 2;
13081       var iFirstPIXO = curr - 1;
13082       var iFirstRestore = curr;
13083
13084       if (argsArray[iFirstTransform][1] !== 0 ||
13085           argsArray[iFirstTransform][2] !== 0) {
13086         return iFirstRestore + 1;   // transform has the wrong form
13087       }
13088
13089       // Look for the quartets.
13090       var firstPIXOArg0 = argsArray[iFirstPIXO][0];
13091       var firstTransformArg0 = argsArray[iFirstTransform][0];
13092       var firstTransformArg3 = argsArray[iFirstTransform][3];
13093       var i = iFirstSave + 4;
13094       var ii = fnArray.length;
13095       while (i + 3 < ii) {
13096         if (fnArray[i] !== OPS.save ||
13097             fnArray[i + 1] !== OPS.transform ||
13098             fnArray[i + 2] !== OPS.paintImageXObject ||
13099             fnArray[i + 3] !== OPS.restore) {
13100           break;    // ops don't match
13101         }
13102         if (argsArray[i + 1][0] !== firstTransformArg0 ||
13103             argsArray[i + 1][1] !== 0 ||
13104             argsArray[i + 1][2] !== 0 ||
13105             argsArray[i + 1][3] !== firstTransformArg3) {
13106           break;    // transforms don't match
13107         }
13108         if (argsArray[i + 2][0] !== firstPIXOArg0) {
13109           break;    // images don't match
13110         }
13111         i += 4;
13112       }
13113
13114       // At this point, i is the index of the first op past the last valid
13115       // quartet.
13116       var count = Math.min((i - iFirstSave) / 4, MAX_IMAGES_IN_BLOCK);
13117       if (count < MIN_IMAGES_IN_BLOCK) {
13118         return i;
13119       }
13120
13121       // Extract the (x,y) positions from all of the matching transforms.
13122       var positions = new Float32Array(count * 2);
13123       var iTransform = iFirstTransform;
13124       for (var q = 0; q < count; q++, iTransform += 4) {
13125         var transformArgs = argsArray[iTransform];
13126         positions[(q << 1)] = transformArgs[4];
13127         positions[(q << 1) + 1] = transformArgs[5];
13128       }
13129
13130       // Replace queue items.
13131       var args = [firstPIXOArg0, firstTransformArg0, firstTransformArg3,
13132                   positions];
13133       fnArray.splice(iFirstSave, count * 4, OPS.paintImageXObjectRepeat);
13134       argsArray.splice(iFirstSave, count * 4, args);
13135
13136       return iFirstSave + 1;
13137     });
13138
13139   // This replaces (beginText, setFont, setTextMatrix, showText, endText)+
13140   // sequences with (beginText, setFont, (setTextMatrix, showText)+, endText)+
13141   // sequences, if the font for each one is the same.
13142   addState(InitialState,
13143     [OPS.beginText, OPS.setFont, OPS.setTextMatrix, OPS.showText, OPS.endText],
13144     function (context) {
13145       var MIN_CHARS_IN_BLOCK = 3;
13146       var MAX_CHARS_IN_BLOCK = 1000;
13147
13148       var fnArray = context.fnArray, argsArray = context.argsArray;
13149       var curr = context.iCurr;
13150       var iFirstBeginText = curr - 4;
13151       var iFirstSetFont = curr - 3;
13152       var iFirstSetTextMatrix = curr - 2;
13153       var iFirstShowText = curr - 1;
13154       var iFirstEndText = curr;
13155
13156       // Look for the quintets.
13157       var firstSetFontArg0 = argsArray[iFirstSetFont][0];
13158       var firstSetFontArg1 = argsArray[iFirstSetFont][1];
13159       var i = iFirstBeginText + 5;
13160       var ii = fnArray.length;
13161       while (i + 4 < ii) {
13162         if (fnArray[i] !== OPS.beginText ||
13163             fnArray[i + 1] !== OPS.setFont ||
13164             fnArray[i + 2] !== OPS.setTextMatrix ||
13165             fnArray[i + 3] !== OPS.showText ||
13166             fnArray[i + 4] !== OPS.endText) {
13167           break;    // ops don't match
13168         }
13169         if (argsArray[i + 1][0] !== firstSetFontArg0 ||
13170             argsArray[i + 1][1] !== firstSetFontArg1) {
13171           break;    // fonts don't match
13172         }
13173         i += 5;
13174       }
13175
13176       // At this point, i is the index of the first op past the last valid
13177       // quintet.
13178       var count = Math.min(((i - iFirstBeginText) / 5), MAX_CHARS_IN_BLOCK);
13179       if (count < MIN_CHARS_IN_BLOCK) {
13180         return i;
13181       }
13182
13183       // If the preceding quintet is (<something>, setFont, setTextMatrix,
13184       // showText, endText), include that as well. (E.g. <something> might be
13185       // |dependency|.)
13186       var iFirst = iFirstBeginText;
13187       if (iFirstBeginText >= 4 &&
13188           fnArray[iFirstBeginText - 4] === fnArray[iFirstSetFont] &&
13189           fnArray[iFirstBeginText - 3] === fnArray[iFirstSetTextMatrix] &&
13190           fnArray[iFirstBeginText - 2] === fnArray[iFirstShowText] &&
13191           fnArray[iFirstBeginText - 1] === fnArray[iFirstEndText] &&
13192           argsArray[iFirstBeginText - 4][0] === firstSetFontArg0 &&
13193           argsArray[iFirstBeginText - 4][1] === firstSetFontArg1) {
13194         count++;
13195         iFirst -= 5;
13196       }
13197
13198       // Remove (endText, beginText, setFont) trios.
13199       var iEndText = iFirst + 4;
13200       for (var q = 1; q < count; q++) {
13201         fnArray.splice(iEndText, 3);
13202         argsArray.splice(iEndText, 3);
13203         iEndText += 2;
13204       }
13205
13206       return iEndText + 1;
13207     });
13208
13209   function QueueOptimizer() {}
13210
13211   QueueOptimizer.prototype = {
13212     optimize: function QueueOptimizer_optimize(queue) {
13213       var fnArray = queue.fnArray, argsArray = queue.argsArray;
13214       var context = {
13215         iCurr: 0,
13216         fnArray: fnArray,
13217         argsArray: argsArray
13218       };
13219       var state;
13220       var i = 0, ii = fnArray.length;
13221       while (i < ii) {
13222         state = (state || InitialState)[fnArray[i]];
13223         if (typeof state === 'function') { // we found some handler
13224           context.iCurr = i;
13225           // state() returns the index of the first non-matching op (if we
13226           // didn't match) or the first op past the modified ops (if we did
13227           // match and replace).
13228           i = state(context);
13229           state = undefined;    // reset the state machine
13230           ii = context.fnArray.length;
13231         } else {
13232           i++;
13233         }
13234       }
13235     }
13236   };
13237   return QueueOptimizer;
13238 })();
13239
13240
13241 var BUILT_IN_CMAPS = [
13242 // << Start unicode maps.
13243 'Adobe-GB1-UCS2',
13244 'Adobe-CNS1-UCS2',
13245 'Adobe-Japan1-UCS2',
13246 'Adobe-Korea1-UCS2',
13247 // >> End unicode maps.
13248 '78-EUC-H',
13249 '78-EUC-V',
13250 '78-H',
13251 '78-RKSJ-H',
13252 '78-RKSJ-V',
13253 '78-V',
13254 '78ms-RKSJ-H',
13255 '78ms-RKSJ-V',
13256 '83pv-RKSJ-H',
13257 '90ms-RKSJ-H',
13258 '90ms-RKSJ-V',
13259 '90msp-RKSJ-H',
13260 '90msp-RKSJ-V',
13261 '90pv-RKSJ-H',
13262 '90pv-RKSJ-V',
13263 'Add-H',
13264 'Add-RKSJ-H',
13265 'Add-RKSJ-V',
13266 'Add-V',
13267 'Adobe-CNS1-0',
13268 'Adobe-CNS1-1',
13269 'Adobe-CNS1-2',
13270 'Adobe-CNS1-3',
13271 'Adobe-CNS1-4',
13272 'Adobe-CNS1-5',
13273 'Adobe-CNS1-6',
13274 'Adobe-GB1-0',
13275 'Adobe-GB1-1',
13276 'Adobe-GB1-2',
13277 'Adobe-GB1-3',
13278 'Adobe-GB1-4',
13279 'Adobe-GB1-5',
13280 'Adobe-Japan1-0',
13281 'Adobe-Japan1-1',
13282 'Adobe-Japan1-2',
13283 'Adobe-Japan1-3',
13284 'Adobe-Japan1-4',
13285 'Adobe-Japan1-5',
13286 'Adobe-Japan1-6',
13287 'Adobe-Korea1-0',
13288 'Adobe-Korea1-1',
13289 'Adobe-Korea1-2',
13290 'B5-H',
13291 'B5-V',
13292 'B5pc-H',
13293 'B5pc-V',
13294 'CNS-EUC-H',
13295 'CNS-EUC-V',
13296 'CNS1-H',
13297 'CNS1-V',
13298 'CNS2-H',
13299 'CNS2-V',
13300 'ETHK-B5-H',
13301 'ETHK-B5-V',
13302 'ETen-B5-H',
13303 'ETen-B5-V',
13304 'ETenms-B5-H',
13305 'ETenms-B5-V',
13306 'EUC-H',
13307 'EUC-V',
13308 'Ext-H',
13309 'Ext-RKSJ-H',
13310 'Ext-RKSJ-V',
13311 'Ext-V',
13312 'GB-EUC-H',
13313 'GB-EUC-V',
13314 'GB-H',
13315 'GB-V',
13316 'GBK-EUC-H',
13317 'GBK-EUC-V',
13318 'GBK2K-H',
13319 'GBK2K-V',
13320 'GBKp-EUC-H',
13321 'GBKp-EUC-V',
13322 'GBT-EUC-H',
13323 'GBT-EUC-V',
13324 'GBT-H',
13325 'GBT-V',
13326 'GBTpc-EUC-H',
13327 'GBTpc-EUC-V',
13328 'GBpc-EUC-H',
13329 'GBpc-EUC-V',
13330 'H',
13331 'HKdla-B5-H',
13332 'HKdla-B5-V',
13333 'HKdlb-B5-H',
13334 'HKdlb-B5-V',
13335 'HKgccs-B5-H',
13336 'HKgccs-B5-V',
13337 'HKm314-B5-H',
13338 'HKm314-B5-V',
13339 'HKm471-B5-H',
13340 'HKm471-B5-V',
13341 'HKscs-B5-H',
13342 'HKscs-B5-V',
13343 'Hankaku',
13344 'Hiragana',
13345 'KSC-EUC-H',
13346 'KSC-EUC-V',
13347 'KSC-H',
13348 'KSC-Johab-H',
13349 'KSC-Johab-V',
13350 'KSC-V',
13351 'KSCms-UHC-H',
13352 'KSCms-UHC-HW-H',
13353 'KSCms-UHC-HW-V',
13354 'KSCms-UHC-V',
13355 'KSCpc-EUC-H',
13356 'KSCpc-EUC-V',
13357 'Katakana',
13358 'NWP-H',
13359 'NWP-V',
13360 'RKSJ-H',
13361 'RKSJ-V',
13362 'Roman',
13363 'UniCNS-UCS2-H',
13364 'UniCNS-UCS2-V',
13365 'UniCNS-UTF16-H',
13366 'UniCNS-UTF16-V',
13367 'UniCNS-UTF32-H',
13368 'UniCNS-UTF32-V',
13369 'UniCNS-UTF8-H',
13370 'UniCNS-UTF8-V',
13371 'UniGB-UCS2-H',
13372 'UniGB-UCS2-V',
13373 'UniGB-UTF16-H',
13374 'UniGB-UTF16-V',
13375 'UniGB-UTF32-H',
13376 'UniGB-UTF32-V',
13377 'UniGB-UTF8-H',
13378 'UniGB-UTF8-V',
13379 'UniJIS-UCS2-H',
13380 'UniJIS-UCS2-HW-H',
13381 'UniJIS-UCS2-HW-V',
13382 'UniJIS-UCS2-V',
13383 'UniJIS-UTF16-H',
13384 'UniJIS-UTF16-V',
13385 'UniJIS-UTF32-H',
13386 'UniJIS-UTF32-V',
13387 'UniJIS-UTF8-H',
13388 'UniJIS-UTF8-V',
13389 'UniJIS2004-UTF16-H',
13390 'UniJIS2004-UTF16-V',
13391 'UniJIS2004-UTF32-H',
13392 'UniJIS2004-UTF32-V',
13393 'UniJIS2004-UTF8-H',
13394 'UniJIS2004-UTF8-V',
13395 'UniJISPro-UCS2-HW-V',
13396 'UniJISPro-UCS2-V',
13397 'UniJISPro-UTF8-V',
13398 'UniJISX0213-UTF32-H',
13399 'UniJISX0213-UTF32-V',
13400 'UniJISX02132004-UTF32-H',
13401 'UniJISX02132004-UTF32-V',
13402 'UniKS-UCS2-H',
13403 'UniKS-UCS2-V',
13404 'UniKS-UTF16-H',
13405 'UniKS-UTF16-V',
13406 'UniKS-UTF32-H',
13407 'UniKS-UTF32-V',
13408 'UniKS-UTF8-H',
13409 'UniKS-UTF8-V',
13410 'V',
13411 'WP-Symbol'];
13412
13413 // CMap, not to be confused with TrueType's cmap.
13414 var CMap = (function CMapClosure() {
13415   function CMap(builtInCMap) {
13416     // Codespace ranges are stored as follows:
13417     // [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
13418     // where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
13419     this.codespaceRanges = [[], [], [], []];
13420     this.numCodespaceRanges = 0;
13421     // Map entries have one of two forms.
13422     // - cid chars are 16-bit unsigned integers, stored as integers.
13423     // - bf chars are variable-length byte sequences, stored as strings, with
13424     //   one byte per character.
13425     this._map = [];
13426     this.name = '';
13427     this.vertical = false;
13428     this.useCMap = null;
13429     this.builtInCMap = builtInCMap;
13430   }
13431   CMap.prototype = {
13432     addCodespaceRange: function(n, low, high) {
13433       this.codespaceRanges[n - 1].push(low, high);
13434       this.numCodespaceRanges++;
13435     },
13436
13437     mapCidRange: function(low, high, dstLow) {
13438       while (low <= high) {
13439         this._map[low++] = dstLow++;
13440       }
13441     },
13442
13443     mapBfRange: function(low, high, dstLow) {
13444       var lastByte = dstLow.length - 1;
13445       while (low <= high) {
13446         this._map[low++] = dstLow;
13447         // Only the last byte has to be incremented.
13448         dstLow = dstLow.substr(0, lastByte) +
13449                  String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
13450       }
13451     },
13452
13453     mapBfRangeToArray: function(low, high, array) {
13454       var i = 0, ii = array.length;
13455       while (low <= high && i < ii) {
13456         this._map[low] = array[i++];
13457         ++low;
13458       }
13459     },
13460
13461     // This is used for both bf and cid chars.
13462     mapOne: function(src, dst) {
13463       this._map[src] = dst;
13464     },
13465
13466     lookup: function(code) {
13467       return this._map[code];
13468     },
13469
13470     contains: function(code) {
13471       return this._map[code] !== undefined;
13472     },
13473
13474     forEach: function(callback) {
13475       // Most maps have fewer than 65536 entries, and for those we use normal
13476       // array iteration. But really sparse tables are possible -- e.g. with
13477       // indices in the *billions*. For such tables we use for..in, which isn't
13478       // ideal because it stringifies the indices for all present elements, but
13479       // it does avoid iterating over every undefined entry.
13480       var map = this._map;
13481       var length = map.length;
13482       var i;
13483       if (length <= 0x10000) {
13484         for (i = 0; i < length; i++) {
13485           if (map[i] !== undefined) {
13486             callback(i, map[i]);
13487           }
13488         }
13489       } else {
13490         for (i in this._map) {
13491           callback(i, map[i]);
13492         }
13493       }
13494     },
13495
13496     charCodeOf: function(value) {
13497       return this._map.indexOf(value);
13498     },
13499
13500     getMap: function() {
13501       return this._map;
13502     },
13503
13504     readCharCode: function(str, offset, out) {
13505       var c = 0;
13506       var codespaceRanges = this.codespaceRanges;
13507       var codespaceRangesLen = this.codespaceRanges.length;
13508       // 9.7.6.2 CMap Mapping
13509       // The code length is at most 4.
13510       for (var n = 0; n < codespaceRangesLen; n++) {
13511         c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
13512         // Check each codespace range to see if it falls within.
13513         var codespaceRange = codespaceRanges[n];
13514         for (var k = 0, kk = codespaceRange.length; k < kk;) {
13515           var low = codespaceRange[k++];
13516           var high = codespaceRange[k++];
13517           if (c >= low && c <= high) {
13518             out.charcode = c;
13519             out.length = n + 1;
13520             return;
13521           }
13522         }
13523       }
13524       out.charcode = 0;
13525       out.length = 1;
13526     },
13527
13528     get isIdentityCMap() {
13529       if (!(this.name === 'Identity-H' || this.name === 'Identity-V')) {
13530         return false;
13531       }
13532       if (this._map.length !== 0x10000) {
13533         return false;
13534       }
13535       for (var i = 0; i < 0x10000; i++) {
13536         if (this._map[i] !== i) {
13537           return false;
13538         }
13539       }
13540       return true;
13541     }
13542   };
13543   return CMap;
13544 })();
13545
13546 // A special case of CMap, where the _map array implicitly has a length of
13547 // 65536 and each element is equal to its index.
13548 var IdentityCMap = (function IdentityCMapClosure() {
13549   function IdentityCMap(vertical, n) {
13550     CMap.call(this);
13551     this.vertical = vertical;
13552     this.addCodespaceRange(n, 0, 0xffff);
13553   }
13554   Util.inherit(IdentityCMap, CMap, {});
13555
13556   IdentityCMap.prototype = {
13557     addCodespaceRange: CMap.prototype.addCodespaceRange,
13558
13559     mapCidRange: function(low, high, dstLow) {
13560       error('should not call mapCidRange');
13561     },
13562
13563     mapBfRange: function(low, high, dstLow) {
13564       error('should not call mapBfRange');
13565     },
13566
13567     mapBfRangeToArray: function(low, high, array) {
13568       error('should not call mapBfRangeToArray');
13569     },
13570
13571     mapOne: function(src, dst) {
13572       error('should not call mapCidOne');
13573     },
13574
13575     lookup: function(code) {
13576       return (isInt(code) && code <= 0xffff) ? code : undefined;
13577     },
13578
13579     contains: function(code) {
13580       return isInt(code) && code <= 0xffff;
13581     },
13582
13583     forEach: function(callback) {
13584       for (var i = 0; i <= 0xffff; i++) {
13585         callback(i, i);
13586       }
13587     },
13588
13589     charCodeOf: function(value) {
13590       return (isInt(value) && value <= 0xffff) ? value : -1;
13591     },
13592
13593     getMap: function() {
13594       // Sometimes identity maps must be instantiated, but it's rare.
13595       var map = new Array(0x10000);
13596       for (var i = 0; i <= 0xffff; i++) {
13597         map[i] = i;
13598       }
13599       return map;
13600     },
13601
13602     readCharCode: CMap.prototype.readCharCode,
13603
13604     get isIdentityCMap() {
13605       error('should not access .isIdentityCMap');
13606     }
13607   };
13608
13609   return IdentityCMap;
13610 })();
13611
13612 var BinaryCMapReader = (function BinaryCMapReaderClosure() {
13613   function fetchBinaryData(url) {
13614     var nonBinaryRequest = PDFJS.disableWorker;
13615     var request = new XMLHttpRequest();
13616     request.open('GET', url, false);
13617     if (!nonBinaryRequest) {
13618       try {
13619         request.responseType = 'arraybuffer';
13620         nonBinaryRequest = request.responseType !== 'arraybuffer';
13621       } catch (e) {
13622         nonBinaryRequest = true;
13623       }
13624     }
13625     if (nonBinaryRequest && request.overrideMimeType) {
13626       request.overrideMimeType('text/plain; charset=x-user-defined');
13627     }
13628     request.send(null);
13629     if (nonBinaryRequest ? !request.responseText : !request.response) {
13630       error('Unable to get binary cMap at: ' + url);
13631     }
13632     if (nonBinaryRequest) {
13633       var data = Array.prototype.map.call(request.responseText, function (ch) {
13634         return ch.charCodeAt(0) & 255;
13635       });
13636       return new Uint8Array(data);
13637     }
13638     return new Uint8Array(request.response);
13639   }
13640
13641   function hexToInt(a, size) {
13642     var n = 0;
13643     for (var i = 0; i <= size; i++) {
13644       n = (n << 8) | a[i];
13645     }
13646     return n >>> 0;
13647   }
13648
13649   function hexToStr(a, size) {
13650     // This code is hot. Special-case some common values to avoid creating an
13651     // object with subarray().
13652     if (size === 1) {
13653       return String.fromCharCode(a[0], a[1]);
13654     }
13655     if (size === 3) {
13656       return String.fromCharCode(a[0], a[1], a[2], a[3]);
13657     }
13658     return String.fromCharCode.apply(null, a.subarray(0, size + 1));
13659   }
13660
13661   function addHex(a, b, size) {
13662     var c = 0;
13663     for (var i = size; i >= 0; i--) {
13664       c += a[i] + b[i];
13665       a[i] = c & 255;
13666       c >>= 8;
13667     }
13668   }
13669
13670   function incHex(a, size) {
13671     var c = 1;
13672     for (var i = size; i >= 0 && c > 0; i--) {
13673       c += a[i];
13674       a[i] = c & 255;
13675       c >>= 8;
13676     }
13677   }
13678
13679   var MAX_NUM_SIZE = 16;
13680   var MAX_ENCODED_NUM_SIZE = 19; // ceil(MAX_NUM_SIZE * 7 / 8)
13681
13682   function BinaryCMapStream(data) {
13683     this.buffer = data;
13684     this.pos = 0;
13685     this.end = data.length;
13686     this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE);
13687   }
13688
13689   BinaryCMapStream.prototype = {
13690     readByte: function () {
13691       if (this.pos >= this.end) {
13692         return -1;
13693       }
13694       return this.buffer[this.pos++];
13695     },
13696     readNumber: function () {
13697       var n = 0;
13698       var last;
13699       do {
13700         var b = this.readByte();
13701         if (b < 0) {
13702           error('unexpected EOF in bcmap');
13703         }
13704         last = !(b & 0x80);
13705         n = (n << 7) | (b & 0x7F);
13706       } while (!last);
13707       return n;
13708     },
13709     readSigned: function () {
13710       var n = this.readNumber();
13711       return (n & 1) ? ~(n >>> 1) : n >>> 1;
13712     },
13713     readHex: function (num, size) {
13714       num.set(this.buffer.subarray(this.pos,
13715         this.pos + size + 1));
13716       this.pos += size + 1;
13717     },
13718     readHexNumber: function (num, size) {
13719       var last;
13720       var stack = this.tmpBuf, sp = 0;
13721       do {
13722         var b = this.readByte();
13723         if (b < 0) {
13724           error('unexpected EOF in bcmap');
13725         }
13726         last = !(b & 0x80);
13727         stack[sp++] = b & 0x7F;
13728       } while (!last);
13729       var i = size, buffer = 0, bufferSize = 0;
13730       while (i >= 0) {
13731         while (bufferSize < 8 && stack.length > 0) {
13732           buffer = (stack[--sp] << bufferSize) | buffer;
13733           bufferSize += 7;
13734         }
13735         num[i] = buffer & 255;
13736         i--;
13737         buffer >>= 8;
13738         bufferSize -= 8;
13739       }
13740     },
13741     readHexSigned: function (num, size) {
13742       this.readHexNumber(num, size);
13743       var sign = num[size] & 1 ? 255 : 0;
13744       var c = 0;
13745       for (var i = 0; i <= size; i++) {
13746         c = ((c & 1) << 8) | num[i];
13747         num[i] = (c >> 1) ^ sign;
13748       }
13749     },
13750     readString: function () {
13751       var len = this.readNumber();
13752       var s = '';
13753       for (var i = 0; i < len; i++) {
13754         s += String.fromCharCode(this.readNumber());
13755       }
13756       return s;
13757     }
13758   };
13759
13760   function processBinaryCMap(url, cMap, extend) {
13761     var data = fetchBinaryData(url);
13762     var stream = new BinaryCMapStream(data);
13763
13764     var header = stream.readByte();
13765     cMap.vertical = !!(header & 1);
13766
13767     var useCMap = null;
13768     var start = new Uint8Array(MAX_NUM_SIZE);
13769     var end = new Uint8Array(MAX_NUM_SIZE);
13770     var char = new Uint8Array(MAX_NUM_SIZE);
13771     var charCode = new Uint8Array(MAX_NUM_SIZE);
13772     var tmp = new Uint8Array(MAX_NUM_SIZE);
13773     var code;
13774
13775     var b;
13776     while ((b = stream.readByte()) >= 0) {
13777       var type = b >> 5;
13778       if (type === 7) { // metadata, e.g. comment or usecmap
13779         switch (b & 0x1F) {
13780           case 0:
13781             stream.readString(); // skipping comment
13782             break;
13783           case 1:
13784             useCMap = stream.readString();
13785             break;
13786         }
13787         continue;
13788       }
13789       var sequence = !!(b & 0x10);
13790       var dataSize = b & 15;
13791
13792       assert(dataSize + 1 <= MAX_NUM_SIZE);
13793
13794       var ucs2DataSize = 1;
13795       var subitemsCount = stream.readNumber();
13796       var i;
13797       switch (type) {
13798         case 0: // codespacerange
13799           stream.readHex(start, dataSize);
13800           stream.readHexNumber(end, dataSize);
13801           addHex(end, start, dataSize);
13802           cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
13803                                  hexToInt(end, dataSize));
13804           for (i = 1; i < subitemsCount; i++) {
13805             incHex(end, dataSize);
13806             stream.readHexNumber(start, dataSize);
13807             addHex(start, end, dataSize);
13808             stream.readHexNumber(end, dataSize);
13809             addHex(end, start, dataSize);
13810             cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
13811                                    hexToInt(end, dataSize));
13812           }
13813           break;
13814         case 1: // notdefrange
13815           stream.readHex(start, dataSize);
13816           stream.readHexNumber(end, dataSize);
13817           addHex(end, start, dataSize);
13818           code = stream.readNumber();
13819           // undefined range, skipping
13820           for (i = 1; i < subitemsCount; i++) {
13821             incHex(end, dataSize);
13822             stream.readHexNumber(start, dataSize);
13823             addHex(start, end, dataSize);
13824             stream.readHexNumber(end, dataSize);
13825             addHex(end, start, dataSize);
13826             code = stream.readNumber();
13827             // nop
13828           }
13829           break;
13830         case 2: // cidchar
13831           stream.readHex(char, dataSize);
13832           code = stream.readNumber();
13833           cMap.mapOne(hexToInt(char, dataSize), code);
13834           for (i = 1; i < subitemsCount; i++) {
13835             incHex(char, dataSize);
13836             if (!sequence) {
13837               stream.readHexNumber(tmp, dataSize);
13838               addHex(char, tmp, dataSize);
13839             }
13840             code = stream.readSigned() + (code + 1);
13841             cMap.mapOne(hexToInt(char, dataSize), code);
13842           }
13843           break;
13844         case 3: // cidrange
13845           stream.readHex(start, dataSize);
13846           stream.readHexNumber(end, dataSize);
13847           addHex(end, start, dataSize);
13848           code = stream.readNumber();
13849           cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
13850                            code);
13851           for (i = 1; i < subitemsCount; i++) {
13852             incHex(end, dataSize);
13853             if (!sequence) {
13854               stream.readHexNumber(start, dataSize);
13855               addHex(start, end, dataSize);
13856             } else {
13857               start.set(end);
13858             }
13859             stream.readHexNumber(end, dataSize);
13860             addHex(end, start, dataSize);
13861             code = stream.readNumber();
13862             cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
13863                              code);
13864           }
13865           break;
13866         case 4: // bfchar
13867           stream.readHex(char, ucs2DataSize);
13868           stream.readHex(charCode, dataSize);
13869           cMap.mapOne(hexToInt(char, ucs2DataSize),
13870                       hexToStr(charCode, dataSize));
13871           for (i = 1; i < subitemsCount; i++) {
13872             incHex(char, ucs2DataSize);
13873             if (!sequence) {
13874               stream.readHexNumber(tmp, ucs2DataSize);
13875               addHex(char, tmp, ucs2DataSize);
13876             }
13877             incHex(charCode, dataSize);
13878             stream.readHexSigned(tmp, dataSize);
13879             addHex(charCode, tmp, dataSize);
13880             cMap.mapOne(hexToInt(char, ucs2DataSize),
13881                         hexToStr(charCode, dataSize));
13882           }
13883           break;
13884         case 5: // bfrange
13885           stream.readHex(start, ucs2DataSize);
13886           stream.readHexNumber(end, ucs2DataSize);
13887           addHex(end, start, ucs2DataSize);
13888           stream.readHex(charCode, dataSize);
13889           cMap.mapBfRange(hexToInt(start, ucs2DataSize),
13890                           hexToInt(end, ucs2DataSize),
13891                           hexToStr(charCode, dataSize));
13892           for (i = 1; i < subitemsCount; i++) {
13893             incHex(end, ucs2DataSize);
13894             if (!sequence) {
13895               stream.readHexNumber(start, ucs2DataSize);
13896               addHex(start, end, ucs2DataSize);
13897             } else {
13898               start.set(end);
13899             }
13900             stream.readHexNumber(end, ucs2DataSize);
13901             addHex(end, start, ucs2DataSize);
13902             stream.readHex(charCode, dataSize);
13903             cMap.mapBfRange(hexToInt(start, ucs2DataSize),
13904                             hexToInt(end, ucs2DataSize),
13905                             hexToStr(charCode, dataSize));
13906           }
13907           break;
13908         default:
13909           error('Unknown type: ' + type);
13910           break;
13911       }
13912     }
13913
13914     if (useCMap) {
13915       extend(useCMap);
13916     }
13917     return cMap;
13918   }
13919
13920   function BinaryCMapReader() {}
13921
13922   BinaryCMapReader.prototype = {
13923     read: processBinaryCMap
13924   };
13925
13926   return BinaryCMapReader;
13927 })();
13928
13929 var CMapFactory = (function CMapFactoryClosure() {
13930   function strToInt(str) {
13931     var a = 0;
13932     for (var i = 0; i < str.length; i++) {
13933       a = (a << 8) | str.charCodeAt(i);
13934     }
13935     return a >>> 0;
13936   }
13937
13938   function expectString(obj) {
13939     if (!isString(obj)) {
13940       error('Malformed CMap: expected string.');
13941     }
13942   }
13943
13944   function expectInt(obj) {
13945     if (!isInt(obj)) {
13946       error('Malformed CMap: expected int.');
13947     }
13948   }
13949
13950   function parseBfChar(cMap, lexer) {
13951     while (true) {
13952       var obj = lexer.getObj();
13953       if (isEOF(obj)) {
13954         break;
13955       }
13956       if (isCmd(obj, 'endbfchar')) {
13957         return;
13958       }
13959       expectString(obj);
13960       var src = strToInt(obj);
13961       obj = lexer.getObj();
13962       // TODO are /dstName used?
13963       expectString(obj);
13964       var dst = obj;
13965       cMap.mapOne(src, dst);
13966     }
13967   }
13968
13969   function parseBfRange(cMap, lexer) {
13970     while (true) {
13971       var obj = lexer.getObj();
13972       if (isEOF(obj)) {
13973         break;
13974       }
13975       if (isCmd(obj, 'endbfrange')) {
13976         return;
13977       }
13978       expectString(obj);
13979       var low = strToInt(obj);
13980       obj = lexer.getObj();
13981       expectString(obj);
13982       var high = strToInt(obj);
13983       obj = lexer.getObj();
13984       if (isInt(obj) || isString(obj)) {
13985         var dstLow = isInt(obj) ? String.fromCharCode(obj) : obj;
13986         cMap.mapBfRange(low, high, dstLow);
13987       } else if (isCmd(obj, '[')) {
13988         obj = lexer.getObj();
13989         var array = [];
13990         while (!isCmd(obj, ']') && !isEOF(obj)) {
13991           array.push(obj);
13992           obj = lexer.getObj();
13993         }
13994         cMap.mapBfRangeToArray(low, high, array);
13995       } else {
13996         break;
13997       }
13998     }
13999     error('Invalid bf range.');
14000   }
14001
14002   function parseCidChar(cMap, lexer) {
14003     while (true) {
14004       var obj = lexer.getObj();
14005       if (isEOF(obj)) {
14006         break;
14007       }
14008       if (isCmd(obj, 'endcidchar')) {
14009         return;
14010       }
14011       expectString(obj);
14012       var src = strToInt(obj);
14013       obj = lexer.getObj();
14014       expectInt(obj);
14015       var dst = obj;
14016       cMap.mapOne(src, dst);
14017     }
14018   }
14019
14020   function parseCidRange(cMap, lexer) {
14021     while (true) {
14022       var obj = lexer.getObj();
14023       if (isEOF(obj)) {
14024         break;
14025       }
14026       if (isCmd(obj, 'endcidrange')) {
14027         return;
14028       }
14029       expectString(obj);
14030       var low = strToInt(obj);
14031       obj = lexer.getObj();
14032       expectString(obj);
14033       var high = strToInt(obj);
14034       obj = lexer.getObj();
14035       expectInt(obj);
14036       var dstLow = obj;
14037       cMap.mapCidRange(low, high, dstLow);
14038     }
14039   }
14040
14041   function parseCodespaceRange(cMap, lexer) {
14042     while (true) {
14043       var obj = lexer.getObj();
14044       if (isEOF(obj)) {
14045         break;
14046       }
14047       if (isCmd(obj, 'endcodespacerange')) {
14048         return;
14049       }
14050       if (!isString(obj)) {
14051         break;
14052       }
14053       var low = strToInt(obj);
14054       obj = lexer.getObj();
14055       if (!isString(obj)) {
14056         break;
14057       }
14058       var high = strToInt(obj);
14059       cMap.addCodespaceRange(obj.length, low, high);
14060     }
14061     error('Invalid codespace range.');
14062   }
14063
14064   function parseWMode(cMap, lexer) {
14065     var obj = lexer.getObj();
14066     if (isInt(obj)) {
14067       cMap.vertical = !!obj;
14068     }
14069   }
14070
14071   function parseCMapName(cMap, lexer) {
14072     var obj = lexer.getObj();
14073     if (isName(obj) && isString(obj.name)) {
14074       cMap.name = obj.name;
14075     }
14076   }
14077
14078   function parseCMap(cMap, lexer, builtInCMapParams, useCMap) {
14079     var previous;
14080     var embededUseCMap;
14081     objLoop: while (true) {
14082       var obj = lexer.getObj();
14083       if (isEOF(obj)) {
14084         break;
14085       } else if (isName(obj)) {
14086         if (obj.name === 'WMode') {
14087           parseWMode(cMap, lexer);
14088         } else if (obj.name === 'CMapName') {
14089           parseCMapName(cMap, lexer);
14090         }
14091         previous = obj;
14092       } else if (isCmd(obj)) {
14093         switch (obj.cmd) {
14094           case 'endcmap':
14095             break objLoop;
14096           case 'usecmap':
14097             if (isName(previous)) {
14098               embededUseCMap = previous.name;
14099             }
14100             break;
14101           case 'begincodespacerange':
14102             parseCodespaceRange(cMap, lexer);
14103             break;
14104           case 'beginbfchar':
14105             parseBfChar(cMap, lexer);
14106             break;
14107           case 'begincidchar':
14108             parseCidChar(cMap, lexer);
14109             break;
14110           case 'beginbfrange':
14111             parseBfRange(cMap, lexer);
14112             break;
14113           case 'begincidrange':
14114             parseCidRange(cMap, lexer);
14115             break;
14116         }
14117       }
14118     }
14119
14120     if (!useCMap && embededUseCMap) {
14121       // Load the usecmap definition from the file only if there wasn't one
14122       // specified.
14123       useCMap = embededUseCMap;
14124     }
14125     if (useCMap) {
14126       extendCMap(cMap, builtInCMapParams, useCMap);
14127     }
14128   }
14129
14130   function extendCMap(cMap, builtInCMapParams, useCMap) {
14131     cMap.useCMap = createBuiltInCMap(useCMap, builtInCMapParams);
14132     // If there aren't any code space ranges defined clone all the parent ones
14133     // into this cMap.
14134     if (cMap.numCodespaceRanges === 0) {
14135       var useCodespaceRanges = cMap.useCMap.codespaceRanges;
14136       for (var i = 0; i < useCodespaceRanges.length; i++) {
14137         cMap.codespaceRanges[i] = useCodespaceRanges[i].slice();
14138       }
14139       cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges;
14140     }
14141     // Merge the map into the current one, making sure not to override
14142     // any previously defined entries.
14143     cMap.useCMap.forEach(function(key, value) {
14144       if (!cMap.contains(key)) {
14145         cMap.mapOne(key, cMap.useCMap.lookup(key));
14146       }
14147     });
14148   }
14149
14150   function parseBinaryCMap(name, builtInCMapParams) {
14151     var url = builtInCMapParams.url + name + '.bcmap';
14152     var cMap = new CMap(true);
14153     new BinaryCMapReader().read(url, cMap, function (useCMap) {
14154       extendCMap(cMap, builtInCMapParams, useCMap);
14155     });
14156     return cMap;
14157   }
14158
14159   function createBuiltInCMap(name, builtInCMapParams) {
14160     if (name === 'Identity-H') {
14161       return new IdentityCMap(false, 2);
14162     } else if (name === 'Identity-V') {
14163       return new IdentityCMap(true, 2);
14164     }
14165     if (BUILT_IN_CMAPS.indexOf(name) === -1) {
14166       error('Unknown cMap name: ' + name);
14167     }
14168     assert(builtInCMapParams, 'built-in cMap parameters are not provided');
14169
14170     if (builtInCMapParams.packed) {
14171       return parseBinaryCMap(name, builtInCMapParams);
14172     }
14173
14174     var request = new XMLHttpRequest();
14175     var url = builtInCMapParams.url + name;
14176     request.open('GET', url, false);
14177     request.send(null);
14178     if (!request.responseText) {
14179       error('Unable to get cMap at: ' + url);
14180     }
14181     var cMap = new CMap(true);
14182     var lexer = new Lexer(new StringStream(request.responseText));
14183     parseCMap(cMap, lexer, builtInCMapParams, null);
14184     return cMap;
14185   }
14186
14187   return {
14188     create: function (encoding, builtInCMapParams, useCMap) {
14189       if (isName(encoding)) {
14190         return createBuiltInCMap(encoding.name, builtInCMapParams);
14191       } else if (isStream(encoding)) {
14192         var cMap = new CMap();
14193         var lexer = new Lexer(encoding);
14194         try {
14195           parseCMap(cMap, lexer, builtInCMapParams, useCMap);
14196         } catch (e) {
14197           warn('Invalid CMap data. ' + e);
14198         }
14199         if (cMap.isIdentityCMap) {
14200           return createBuiltInCMap(cMap.name, builtInCMapParams);
14201         }
14202         return cMap;
14203       }
14204       error('Encoding required.');
14205     }
14206   };
14207 })();
14208
14209
14210 // Unicode Private Use Area
14211 var PRIVATE_USE_OFFSET_START = 0xE000;
14212 var PRIVATE_USE_OFFSET_END = 0xF8FF;
14213 var SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = false;
14214
14215 // PDF Glyph Space Units are one Thousandth of a TextSpace Unit
14216 // except for Type 3 fonts
14217 var PDF_GLYPH_SPACE_UNITS = 1000;
14218
14219 // Hinting is currently disabled due to unknown problems on windows
14220 // in tracemonkey and various other pdfs with type1 fonts.
14221 var HINTING_ENABLED = false;
14222
14223 // Accented charactars are not displayed properly on windows, using this flag
14224 // to control analysis of seac charstrings.
14225 var SEAC_ANALYSIS_ENABLED = false;
14226
14227 var FontFlags = {
14228   FixedPitch: 1,
14229   Serif: 2,
14230   Symbolic: 4,
14231   Script: 8,
14232   Nonsymbolic: 32,
14233   Italic: 64,
14234   AllCap: 65536,
14235   SmallCap: 131072,
14236   ForceBold: 262144
14237 };
14238
14239 var Encodings = {
14240   ExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14241     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14242     'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle',
14243     'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
14244     'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
14245     'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
14246     'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
14247     'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon',
14248     'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior',
14249     'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
14250     'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior',
14251     'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior',
14252     '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '',
14253     'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
14254     'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
14255     'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
14256     'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
14257     'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
14258     'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '',
14259     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14260     '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',
14261     '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall',
14262     'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '',
14263     'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall',
14264     'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters',
14265     'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
14266     'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior',
14267     'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior',
14268     'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior',
14269     'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior',
14270     'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior',
14271     'seveninferior', 'eightinferior', 'nineinferior', 'centinferior',
14272     'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
14273     'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall',
14274     'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
14275     'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
14276     'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
14277     'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
14278     'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
14279     'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
14280     'Ydieresissmall'],
14281   MacExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
14282     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14283     'space', 'exclamsmall', 'Hungarumlautsmall', 'centoldstyle',
14284     'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
14285     'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
14286     'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle',
14287     'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
14288     'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
14289     'nineoldstyle', 'colon', 'semicolon', '', 'threequartersemdash', '',
14290     'questionsmall', '', '', '', '', 'Ethsmall', '', '', 'onequarter',
14291     'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
14292     'seveneighths', 'onethird', 'twothirds', '', '', '', '', '', '', 'ff',
14293     'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior',
14294     'Circumflexsmall', 'hypheninferior', 'Gravesmall', 'Asmall', 'Bsmall',
14295     'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',
14296     'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
14297     'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
14298     'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',
14299     'Tildesmall', '', '', 'asuperior', 'centsuperior', '', '', '', '',
14300     'Aacutesmall', 'Agravesmall', 'Acircumflexsmall', 'Adieresissmall',
14301     'Atildesmall', 'Aringsmall', 'Ccedillasmall', 'Eacutesmall', 'Egravesmall',
14302     'Ecircumflexsmall', 'Edieresissmall', 'Iacutesmall', 'Igravesmall',
14303     'Icircumflexsmall', 'Idieresissmall', 'Ntildesmall', 'Oacutesmall',
14304     'Ogravesmall', 'Ocircumflexsmall', 'Odieresissmall', 'Otildesmall',
14305     'Uacutesmall', 'Ugravesmall', 'Ucircumflexsmall', 'Udieresissmall', '',
14306     'eightsuperior', 'fourinferior', 'threeinferior', 'sixinferior',
14307     'eightinferior', 'seveninferior', 'Scaronsmall', '', 'centinferior',
14308     'twoinferior', '', 'Dieresissmall', '', 'Caronsmall', 'osuperior',
14309     'fiveinferior', '', 'commainferior', 'periodinferior', 'Yacutesmall', '',
14310     'dollarinferior', '', 'Thornsmall', '', 'nineinferior', 'zeroinferior',
14311     'Zcaronsmall', 'AEsmall', 'Oslashsmall', 'questiondownsmall',
14312     'oneinferior', 'Lslashsmall', '', '', '', '', '', '', 'Cedillasmall', '',
14313     '', '', '', '', 'OEsmall', 'figuredash', 'hyphensuperior', '', '', '', '',
14314     'exclamdownsmall', '', 'Ydieresissmall', '', 'onesuperior', 'twosuperior',
14315     'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',
14316     'sevensuperior', 'ninesuperior', 'zerosuperior', '', 'esuperior',
14317     'rsuperior', 'tsuperior', '', '', 'isuperior', 'ssuperior', 'dsuperior',
14318     '', '', '', '', '', 'lsuperior', 'Ogoneksmall', 'Brevesmall',
14319     'Macronsmall', 'bsuperior', 'nsuperior', 'msuperior', 'commasuperior',
14320     'periodsuperior', 'Dotaccentsmall', 'Ringsmall'],
14321   MacRomanEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14322     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14323     'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
14324     'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
14325     'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
14326     'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
14327     'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
14328     'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
14329     'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
14330     'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
14331     'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
14332     'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '',
14333     'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis',
14334     'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde',
14335     'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
14336     'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute',
14337     'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave',
14338     'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling',
14339     'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright',
14340     'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity',
14341     'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff',
14342     'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine',
14343     'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot',
14344     'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft',
14345     'guillemotright', 'ellipsis', 'space', 'Agrave', 'Atilde', 'Otilde', 'OE',
14346     'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft',
14347     'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction',
14348     'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl',
14349     'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand',
14350     'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute',
14351     'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple',
14352     'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex',
14353     'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut',
14354     'ogonek', 'caron'],
14355   StandardEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14356     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14357     'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
14358     'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
14359     'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
14360     'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
14361     'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
14362     'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
14363     'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
14364     'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f',
14365     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
14366     'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
14367     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14368     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown',
14369     'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
14370     'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
14371     'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl',
14372     'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase',
14373     'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
14374     'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex',
14375     'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla',
14376     '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '',
14377     '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '',
14378     '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae',
14379     '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'],
14380   WinAnsiEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14381     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14382     'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
14383     'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
14384     'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
14385     'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
14386     'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
14387     'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
14388     'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
14389     'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
14390     'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
14391     'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
14392     'bullet', 'Euro', 'bullet', 'quotesinglbase', 'florin', 'quotedblbase',
14393     'ellipsis', 'dagger', 'daggerdbl', 'circumflex', 'perthousand', 'Scaron',
14394     'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft',
14395     'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash',
14396     'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet',
14397     'zcaron', 'Ydieresis', 'space', 'exclamdown', 'cent', 'sterling',
14398     'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright',
14399     'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered',
14400     'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute',
14401     'mu', 'paragraph', 'periodcentered', 'cedilla', 'onesuperior',
14402     'ordmasculine', 'guillemotright', 'onequarter', 'onehalf', 'threequarters',
14403     'questiondown', 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', 'Adieresis',
14404     'Aring', 'AE', 'Ccedilla', 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis',
14405     'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve',
14406     'Oacute', 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash',
14407     'Ugrave', 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn',
14408     'germandbls', 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis',
14409     'aring', 'ae', 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis',
14410     'igrave', 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve',
14411     'oacute', 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash',
14412     'ugrave', 'uacute', 'ucircumflex', 'udieresis', 'yacute', 'thorn',
14413     'ydieresis'],
14414   SymbolSetEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
14415     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14416     'space', 'exclam', 'universal', 'numbersign', 'existential', 'percent',
14417     'ampersand', 'suchthat', 'parenleft', 'parenright', 'asteriskmath', 'plus',
14418     'comma', 'minus', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
14419     'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
14420     'equal', 'greater', 'question', 'congruent', 'Alpha', 'Beta', 'Chi',
14421     'Delta', 'Epsilon', 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa',
14422     'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', 'Theta', 'Rho', 'Sigma', 'Tau',
14423     'Upsilon', 'sigma1', 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft',
14424     'therefore', 'bracketright', 'perpendicular', 'underscore', 'radicalex',
14425     'alpha', 'beta', 'chi', 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota',
14426     'phi1', 'kappa', 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho',
14427     'sigma', 'tau', 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta',
14428     'braceleft', 'bar', 'braceright', 'similar', '', '', '', '', '', '', '',
14429     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14430     '', '', '', '', '', '', '', 'Euro', 'Upsilon1', 'minute', 'lessequal',
14431     'fraction', 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade',
14432     'arrowboth', 'arrowleft', 'arrowup', 'arrowright', 'arrowdown', 'degree',
14433     'plusminus', 'second', 'greaterequal', 'multiply', 'proportional',
14434     'partialdiff', 'bullet', 'divide', 'notequal', 'equivalence',
14435     'approxequal', 'ellipsis', 'arrowvertex', 'arrowhorizex', 'carriagereturn',
14436     'aleph', 'Ifraktur', 'Rfraktur', 'weierstrass', 'circlemultiply',
14437     'circleplus', 'emptyset', 'intersection', 'union', 'propersuperset',
14438     'reflexsuperset', 'notsubset', 'propersubset', 'reflexsubset', 'element',
14439     'notelement', 'angle', 'gradient', 'registerserif', 'copyrightserif',
14440     'trademarkserif', 'product', 'radical', 'dotmath', 'logicalnot',
14441     'logicaland', 'logicalor', 'arrowdblboth', 'arrowdblleft', 'arrowdblup',
14442     'arrowdblright', 'arrowdbldown', 'lozenge', 'angleleft', 'registersans',
14443     'copyrightsans', 'trademarksans', 'summation', 'parenlefttp',
14444     'parenleftex', 'parenleftbt', 'bracketlefttp', 'bracketleftex',
14445     'bracketleftbt', 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex',
14446     '', 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt',
14447     'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp',
14448     'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid',
14449     'bracerightbt'],
14450   ZapfDingbatsEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
14451     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14452     'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117',
14453     'a11', 'a12', 'a13', 'a14', 'a15', 'a16', 'a105', 'a17', 'a18', 'a19',
14454     'a20', 'a21', 'a22', 'a23', 'a24', 'a25', 'a26', 'a27', 'a28', 'a6', 'a7',
14455     'a8', 'a9', 'a10', 'a29', 'a30', 'a31', 'a32', 'a33', 'a34', 'a35', 'a36',
14456     'a37', 'a38', 'a39', 'a40', 'a41', 'a42', 'a43', 'a44', 'a45', 'a46',
14457     'a47', 'a48', 'a49', 'a50', 'a51', 'a52', 'a53', 'a54', 'a55', 'a56',
14458     'a57', 'a58', 'a59', 'a60', 'a61', 'a62', 'a63', 'a64', 'a65', 'a66',
14459     'a67', 'a68', 'a69', 'a70', 'a71', 'a72', 'a73', 'a74', 'a203', 'a75',
14460     'a204', 'a76', 'a77', 'a78', 'a79', 'a81', 'a82', 'a83', 'a84', 'a97',
14461     'a98', 'a99', 'a100', '', 'a89', 'a90', 'a93', 'a94', 'a91', 'a92', 'a205',
14462     'a85', 'a206', 'a86', 'a87', 'a88', 'a95', 'a96', '', '', '', '', '', '',
14463     '', '', '', '', '', '', '', '', '', '', '', '', '', 'a101', 'a102', 'a103',
14464     'a104', 'a106', 'a107', 'a108', 'a112', 'a111', 'a110', 'a109', 'a120',
14465     'a121', 'a122', 'a123', 'a124', 'a125', 'a126', 'a127', 'a128', 'a129',
14466     'a130', 'a131', 'a132', 'a133', 'a134', 'a135', 'a136', 'a137', 'a138',
14467     'a139', 'a140', 'a141', 'a142', 'a143', 'a144', 'a145', 'a146', 'a147',
14468     'a148', 'a149', 'a150', 'a151', 'a152', 'a153', 'a154', 'a155', 'a156',
14469     'a157', 'a158', 'a159', 'a160', 'a161', 'a163', 'a164', 'a196', 'a165',
14470     'a192', 'a166', 'a167', 'a168', 'a169', 'a170', 'a171', 'a172', 'a173',
14471     'a162', 'a174', 'a175', 'a176', 'a177', 'a178', 'a179', 'a193', 'a180',
14472     'a199', 'a181', 'a200', 'a182', '', 'a201', 'a183', 'a184', 'a197', 'a185',
14473     'a194', 'a198', 'a186', 'a195', 'a187', 'a188', 'a189', 'a190', 'a191']
14474 };
14475
14476 /**
14477  * Hold a map of decoded fonts and of the standard fourteen Type1
14478  * fonts and their acronyms.
14479  */
14480 var stdFontMap = {
14481   'ArialNarrow': 'Helvetica',
14482   'ArialNarrow-Bold': 'Helvetica-Bold',
14483   'ArialNarrow-BoldItalic': 'Helvetica-BoldOblique',
14484   'ArialNarrow-Italic': 'Helvetica-Oblique',
14485   'ArialBlack': 'Helvetica',
14486   'ArialBlack-Bold': 'Helvetica-Bold',
14487   'ArialBlack-BoldItalic': 'Helvetica-BoldOblique',
14488   'ArialBlack-Italic': 'Helvetica-Oblique',
14489   'Arial': 'Helvetica',
14490   'Arial-Bold': 'Helvetica-Bold',
14491   'Arial-BoldItalic': 'Helvetica-BoldOblique',
14492   'Arial-Italic': 'Helvetica-Oblique',
14493   'Arial-BoldItalicMT': 'Helvetica-BoldOblique',
14494   'Arial-BoldMT': 'Helvetica-Bold',
14495   'Arial-ItalicMT': 'Helvetica-Oblique',
14496   'ArialMT': 'Helvetica',
14497   'Courier-Bold': 'Courier-Bold',
14498   'Courier-BoldItalic': 'Courier-BoldOblique',
14499   'Courier-Italic': 'Courier-Oblique',
14500   'CourierNew': 'Courier',
14501   'CourierNew-Bold': 'Courier-Bold',
14502   'CourierNew-BoldItalic': 'Courier-BoldOblique',
14503   'CourierNew-Italic': 'Courier-Oblique',
14504   'CourierNewPS-BoldItalicMT': 'Courier-BoldOblique',
14505   'CourierNewPS-BoldMT': 'Courier-Bold',
14506   'CourierNewPS-ItalicMT': 'Courier-Oblique',
14507   'CourierNewPSMT': 'Courier',
14508   'Helvetica': 'Helvetica',
14509   'Helvetica-Bold': 'Helvetica-Bold',
14510   'Helvetica-BoldItalic': 'Helvetica-BoldOblique',
14511   'Helvetica-BoldOblique': 'Helvetica-BoldOblique',
14512   'Helvetica-Italic': 'Helvetica-Oblique',
14513   'Helvetica-Oblique':'Helvetica-Oblique',
14514   'Symbol-Bold': 'Symbol',
14515   'Symbol-BoldItalic': 'Symbol',
14516   'Symbol-Italic': 'Symbol',
14517   'TimesNewRoman': 'Times-Roman',
14518   'TimesNewRoman-Bold': 'Times-Bold',
14519   'TimesNewRoman-BoldItalic': 'Times-BoldItalic',
14520   'TimesNewRoman-Italic': 'Times-Italic',
14521   'TimesNewRomanPS': 'Times-Roman',
14522   'TimesNewRomanPS-Bold': 'Times-Bold',
14523   'TimesNewRomanPS-BoldItalic': 'Times-BoldItalic',
14524   'TimesNewRomanPS-BoldItalicMT': 'Times-BoldItalic',
14525   'TimesNewRomanPS-BoldMT': 'Times-Bold',
14526   'TimesNewRomanPS-Italic': 'Times-Italic',
14527   'TimesNewRomanPS-ItalicMT': 'Times-Italic',
14528   'TimesNewRomanPSMT': 'Times-Roman',
14529   'TimesNewRomanPSMT-Bold': 'Times-Bold',
14530   'TimesNewRomanPSMT-BoldItalic': 'Times-BoldItalic',
14531   'TimesNewRomanPSMT-Italic': 'Times-Italic'
14532 };
14533
14534 /**
14535  * Holds the map of the non-standard fonts that might be included as a standard
14536  * fonts without glyph data.
14537  */
14538 var nonStdFontMap = {
14539   'CenturyGothic': 'Helvetica',
14540   'CenturyGothic-Bold': 'Helvetica-Bold',
14541   'CenturyGothic-BoldItalic': 'Helvetica-BoldOblique',
14542   'CenturyGothic-Italic': 'Helvetica-Oblique',
14543   'ComicSansMS': 'Comic Sans MS',
14544   'ComicSansMS-Bold': 'Comic Sans MS-Bold',
14545   'ComicSansMS-BoldItalic': 'Comic Sans MS-BoldItalic',
14546   'ComicSansMS-Italic': 'Comic Sans MS-Italic',
14547   'LucidaConsole': 'Courier',
14548   'LucidaConsole-Bold': 'Courier-Bold',
14549   'LucidaConsole-BoldItalic': 'Courier-BoldOblique',
14550   'LucidaConsole-Italic': 'Courier-Oblique',
14551   'MS-Gothic': 'MS Gothic',
14552   'MS-Gothic-Bold': 'MS Gothic-Bold',
14553   'MS-Gothic-BoldItalic': 'MS Gothic-BoldItalic',
14554   'MS-Gothic-Italic': 'MS Gothic-Italic',
14555   'MS-Mincho': 'MS Mincho',
14556   'MS-Mincho-Bold': 'MS Mincho-Bold',
14557   'MS-Mincho-BoldItalic': 'MS Mincho-BoldItalic',
14558   'MS-Mincho-Italic': 'MS Mincho-Italic',
14559   'MS-PGothic': 'MS PGothic',
14560   'MS-PGothic-Bold': 'MS PGothic-Bold',
14561   'MS-PGothic-BoldItalic': 'MS PGothic-BoldItalic',
14562   'MS-PGothic-Italic': 'MS PGothic-Italic',
14563   'MS-PMincho': 'MS PMincho',
14564   'MS-PMincho-Bold': 'MS PMincho-Bold',
14565   'MS-PMincho-BoldItalic': 'MS PMincho-BoldItalic',
14566   'MS-PMincho-Italic': 'MS PMincho-Italic',
14567   'Wingdings': 'ZapfDingbats'
14568 };
14569
14570 var serifFonts = {
14571   'Adobe Jenson': true, 'Adobe Text': true, 'Albertus': true,
14572   'Aldus': true, 'Alexandria': true, 'Algerian': true,
14573   'American Typewriter': true, 'Antiqua': true, 'Apex': true,
14574   'Arno': true, 'Aster': true, 'Aurora': true,
14575   'Baskerville': true, 'Bell': true, 'Bembo': true,
14576   'Bembo Schoolbook': true, 'Benguiat': true, 'Berkeley Old Style': true,
14577   'Bernhard Modern': true, 'Berthold City': true, 'Bodoni': true,
14578   'Bauer Bodoni': true, 'Book Antiqua': true, 'Bookman': true,
14579   'Bordeaux Roman': true, 'Californian FB': true, 'Calisto': true,
14580   'Calvert': true, 'Capitals': true, 'Cambria': true,
14581   'Cartier': true, 'Caslon': true, 'Catull': true,
14582   'Centaur': true, 'Century Old Style': true, 'Century Schoolbook': true,
14583   'Chaparral': true, 'Charis SIL': true, 'Cheltenham': true,
14584   'Cholla Slab': true, 'Clarendon': true, 'Clearface': true,
14585   'Cochin': true, 'Colonna': true, 'Computer Modern': true,
14586   'Concrete Roman': true, 'Constantia': true, 'Cooper Black': true,
14587   'Corona': true, 'Ecotype': true, 'Egyptienne': true,
14588   'Elephant': true, 'Excelsior': true, 'Fairfield': true,
14589   'FF Scala': true, 'Folkard': true, 'Footlight': true,
14590   'FreeSerif': true, 'Friz Quadrata': true, 'Garamond': true,
14591   'Gentium': true, 'Georgia': true, 'Gloucester': true,
14592   'Goudy Old Style': true, 'Goudy Schoolbook': true, 'Goudy Pro Font': true,
14593   'Granjon': true, 'Guardian Egyptian': true, 'Heather': true,
14594   'Hercules': true, 'High Tower Text': true, 'Hiroshige': true,
14595   'Hoefler Text': true, 'Humana Serif': true, 'Imprint': true,
14596   'Ionic No. 5': true, 'Janson': true, 'Joanna': true,
14597   'Korinna': true, 'Lexicon': true, 'Liberation Serif': true,
14598   'Linux Libertine': true, 'Literaturnaya': true, 'Lucida': true,
14599   'Lucida Bright': true, 'Melior': true, 'Memphis': true,
14600   'Miller': true, 'Minion': true, 'Modern': true,
14601   'Mona Lisa': true, 'Mrs Eaves': true, 'MS Serif': true,
14602   'Museo Slab': true, 'New York': true, 'Nimbus Roman': true,
14603   'NPS Rawlinson Roadway': true, 'Palatino': true, 'Perpetua': true,
14604   'Plantin': true, 'Plantin Schoolbook': true, 'Playbill': true,
14605   'Poor Richard': true, 'Rawlinson Roadway': true, 'Renault': true,
14606   'Requiem': true, 'Rockwell': true, 'Roman': true,
14607   'Rotis Serif': true, 'Sabon': true, 'Scala': true,
14608   'Seagull': true, 'Sistina': true, 'Souvenir': true,
14609   'STIX': true, 'Stone Informal': true, 'Stone Serif': true,
14610   'Sylfaen': true, 'Times': true, 'Trajan': true,
14611   'Trinité': true, 'Trump Mediaeval': true, 'Utopia': true,
14612   'Vale Type': true, 'Bitstream Vera': true, 'Vera Serif': true,
14613   'Versailles': true, 'Wanted': true, 'Weiss': true,
14614   'Wide Latin': true, 'Windsor': true, 'XITS': true
14615 };
14616
14617 var symbolsFonts = {
14618   'Dingbats': true, 'Symbol': true, 'ZapfDingbats': true
14619 };
14620
14621 // Glyph map for well-known standard fonts. Sometimes Ghostscript uses CID fonts
14622 // but does not embed the CID to GID mapping. The mapping is incomplete for all
14623 // glyphs, but common for some set of the standard fonts.
14624 var GlyphMapForStandardFonts = {
14625   '2': 10, '3': 32, '4': 33, '5': 34, '6': 35, '7': 36, '8': 37, '9': 38,
14626   '10': 39, '11': 40, '12': 41, '13': 42, '14': 43, '15': 44, '16': 45,
14627   '17': 46, '18': 47, '19': 48, '20': 49, '21': 50, '22': 51, '23': 52,
14628   '24': 53, '25': 54, '26': 55, '27': 56, '28': 57, '29': 58, '30': 894,
14629   '31': 60, '32': 61, '33': 62, '34': 63, '35': 64, '36': 65, '37': 66,
14630   '38': 67, '39': 68, '40': 69, '41': 70, '42': 71, '43': 72, '44': 73,
14631   '45': 74, '46': 75, '47': 76, '48': 77, '49': 78, '50': 79, '51': 80,
14632   '52': 81, '53': 82, '54': 83, '55': 84, '56': 85, '57': 86, '58': 87,
14633   '59': 88, '60': 89, '61': 90, '62': 91, '63': 92, '64': 93, '65': 94,
14634   '66': 95, '67': 96, '68': 97, '69': 98, '70': 99, '71': 100, '72': 101,
14635   '73': 102, '74': 103, '75': 104, '76': 105, '77': 106, '78': 107, '79': 108,
14636   '80': 109, '81': 110, '82': 111, '83': 112, '84': 113, '85': 114, '86': 115,
14637   '87': 116, '88': 117, '89': 118, '90': 119, '91': 120, '92': 121, '93': 122,
14638   '94': 123, '95': 124, '96': 125, '97': 126, '98': 196, '99': 197, '100': 199,
14639   '101': 201, '102': 209, '103': 214, '104': 220, '105': 225, '106': 224,
14640   '107': 226, '108': 228, '109': 227, '110': 229, '111': 231, '112': 233,
14641   '113': 232, '114': 234, '115': 235, '116': 237, '117': 236, '118': 238,
14642   '119': 239, '120': 241, '121': 243, '122': 242, '123': 244, '124': 246,
14643   '125': 245, '126': 250, '127': 249, '128': 251, '129': 252, '130': 8224,
14644   '131': 176, '132': 162, '133': 163, '134': 167, '135': 8226, '136': 182,
14645   '137': 223, '138': 174, '139': 169, '140': 8482, '141': 180, '142': 168,
14646   '143': 8800, '144': 198, '145': 216, '146': 8734, '147': 177, '148': 8804,
14647   '149': 8805, '150': 165, '151': 181, '152': 8706, '153': 8721, '154': 8719,
14648   '156': 8747, '157': 170, '158': 186, '159': 8486, '160': 230, '161': 248,
14649   '162': 191, '163': 161, '164': 172, '165': 8730, '166': 402, '167': 8776,
14650   '168': 8710, '169': 171, '170': 187, '171': 8230, '210': 218, '223': 711,
14651   '224': 321, '225': 322, '227': 353, '229': 382, '234': 253, '252': 263,
14652   '253': 268, '254': 269, '258': 258, '260': 260, '261': 261, '265': 280,
14653   '266': 281, '268': 283, '269': 313, '275': 323, '276': 324, '278': 328,
14654   '284': 345, '285': 346, '286': 347, '292': 367, '295': 377, '296': 378,
14655   '298': 380, '305': 963,
14656   '306': 964, '307': 966, '308': 8215, '309': 8252, '310': 8319, '311': 8359,
14657   '312': 8592, '313': 8593, '337': 9552, '493': 1039, '494': 1040, '705': 1524,
14658   '706': 8362, '710': 64288, '711': 64298, '759': 1617, '761': 1776,
14659   '763': 1778, '775': 1652, '777': 1764, '778': 1780, '779': 1781, '780': 1782,
14660   '782': 771, '783': 64726, '786': 8363, '788': 8532, '790': 768, '791': 769,
14661   '792': 768, '795': 803, '797': 64336, '798': 64337, '799': 64342,
14662   '800': 64343, '801': 64344, '802': 64345, '803': 64362, '804': 64363,
14663   '805': 64364, '2424': 7821, '2425': 7822, '2426': 7823, '2427': 7824,
14664   '2428': 7825, '2429': 7826, '2430': 7827, '2433': 7682, '2678': 8045,
14665   '2679': 8046, '2830': 1552, '2838': 686, '2840': 751, '2842': 753,
14666   '2843': 754, '2844': 755, '2846': 757, '2856': 767, '2857': 848, '2858': 849,
14667   '2862': 853, '2863': 854, '2864': 855, '2865': 861, '2866': 862, '2906': 7460,
14668   '2908': 7462, '2909': 7463, '2910': 7464, '2912': 7466, '2913': 7467,
14669   '2914': 7468, '2916': 7470, '2917': 7471, '2918': 7472, '2920': 7474,
14670   '2921': 7475, '2922': 7476, '2924': 7478, '2925': 7479, '2926': 7480,
14671   '2928': 7482, '2929': 7483, '2930': 7484, '2932': 7486, '2933': 7487,
14672   '2934': 7488, '2936': 7490, '2937': 7491, '2938': 7492, '2940': 7494,
14673   '2941': 7495, '2942': 7496, '2944': 7498, '2946': 7500, '2948': 7502,
14674   '2950': 7504, '2951': 7505, '2952': 7506, '2954': 7508, '2955': 7509,
14675   '2956': 7510, '2958': 7512, '2959': 7513, '2960': 7514, '2962': 7516,
14676   '2963': 7517, '2964': 7518, '2966': 7520, '2967': 7521, '2968': 7522,
14677   '2970': 7524, '2971': 7525, '2972': 7526, '2974': 7528, '2975': 7529,
14678   '2976': 7530, '2978': 1537, '2979': 1538, '2980': 1539, '2982': 1549,
14679   '2983': 1551, '2984': 1552, '2986': 1554, '2987': 1555, '2988': 1556,
14680   '2990': 1623, '2991': 1624, '2995': 1775, '2999': 1791, '3002': 64290,
14681   '3003': 64291, '3004': 64292, '3006': 64294, '3007': 64295, '3008': 64296,
14682   '3011': 1900, '3014': 8223, '3015': 8244, '3017': 7532, '3018': 7533,
14683   '3019': 7534, '3075': 7590, '3076': 7591, '3079': 7594, '3080': 7595,
14684   '3083': 7598, '3084': 7599, '3087': 7602, '3088': 7603, '3091': 7606,
14685   '3092': 7607, '3095': 7610, '3096': 7611, '3099': 7614, '3100': 7615,
14686   '3103': 7618, '3104': 7619, '3107': 8337, '3108': 8338, '3116': 1884,
14687   '3119': 1885, '3120': 1885, '3123': 1886, '3124': 1886, '3127': 1887,
14688   '3128': 1887, '3131': 1888, '3132': 1888, '3135': 1889, '3136': 1889,
14689   '3139': 1890, '3140': 1890, '3143': 1891, '3144': 1891, '3147': 1892,
14690   '3148': 1892, '3153': 580, '3154': 581, '3157': 584, '3158': 585, '3161': 588,
14691   '3162': 589, '3165': 891, '3166': 892, '3169': 1274, '3170': 1275,
14692   '3173': 1278, '3174': 1279, '3181': 7622, '3182': 7623, '3282': 11799,
14693   '3316': 578, '3379': 42785, '3393': 1159, '3416': 8377
14694 };
14695
14696 // Some characters, e.g. copyrightserif, are mapped to the private use area and
14697 // might not be displayed using standard fonts. Mapping/hacking well-known chars
14698 // to the similar equivalents in the normal characters range.
14699 var SpecialPUASymbols = {
14700   '63721': 0x00A9, // copyrightsans (0xF8E9) => copyright
14701   '63193': 0x00A9, // copyrightserif (0xF6D9) => copyright
14702   '63720': 0x00AE, // registersans (0xF8E8) => registered
14703   '63194': 0x00AE, // registerserif (0xF6DA) => registered
14704   '63722': 0x2122, // trademarksans (0xF8EA) => trademark
14705   '63195': 0x2122, // trademarkserif (0xF6DB) => trademark
14706   '63729': 0x23A7, // bracelefttp (0xF8F1)
14707   '63730': 0x23A8, // braceleftmid (0xF8F2)
14708   '63731': 0x23A9, // braceleftbt (0xF8F3)
14709   '63740': 0x23AB, // bracerighttp (0xF8FC)
14710   '63741': 0x23AC, // bracerightmid (0xF8FD)
14711   '63742': 0x23AD, // bracerightbt (0xF8FE)
14712   '63726': 0x23A1, // bracketlefttp (0xF8EE)
14713   '63727': 0x23A2, // bracketleftex (0xF8EF)
14714   '63728': 0x23A3, // bracketleftbt (0xF8F0)
14715   '63737': 0x23A4, // bracketrighttp (0xF8F9)
14716   '63738': 0x23A5, // bracketrightex (0xF8FA)
14717   '63739': 0x23A6, // bracketrightbt (0xF8FB)
14718   '63723': 0x239B, // parenlefttp (0xF8EB)
14719   '63724': 0x239C, // parenleftex (0xF8EC)
14720   '63725': 0x239D, // parenleftbt (0xF8ED)
14721   '63734': 0x239E, // parenrighttp (0xF8F6)
14722   '63735': 0x239F, // parenrightex (0xF8F7)
14723   '63736': 0x23A0, // parenrightbt (0xF8F8)
14724 };
14725 function mapSpecialUnicodeValues(code) {
14726   if (code >= 0xFFF0 && code <= 0xFFFF) { // Specials unicode block.
14727     return 0;
14728   } else if (code >= 0xF600 && code <= 0xF8FF) {
14729     return (SpecialPUASymbols[code] || code);
14730   }
14731   return code;
14732 }
14733
14734 var UnicodeRanges = [
14735   { 'begin': 0x0000, 'end': 0x007F }, // Basic Latin
14736   { 'begin': 0x0080, 'end': 0x00FF }, // Latin-1 Supplement
14737   { 'begin': 0x0100, 'end': 0x017F }, // Latin Extended-A
14738   { 'begin': 0x0180, 'end': 0x024F }, // Latin Extended-B
14739   { 'begin': 0x0250, 'end': 0x02AF }, // IPA Extensions
14740   { 'begin': 0x02B0, 'end': 0x02FF }, // Spacing Modifier Letters
14741   { 'begin': 0x0300, 'end': 0x036F }, // Combining Diacritical Marks
14742   { 'begin': 0x0370, 'end': 0x03FF }, // Greek and Coptic
14743   { 'begin': 0x2C80, 'end': 0x2CFF }, // Coptic
14744   { 'begin': 0x0400, 'end': 0x04FF }, // Cyrillic
14745   { 'begin': 0x0530, 'end': 0x058F }, // Armenian
14746   { 'begin': 0x0590, 'end': 0x05FF }, // Hebrew
14747   { 'begin': 0xA500, 'end': 0xA63F }, // Vai
14748   { 'begin': 0x0600, 'end': 0x06FF }, // Arabic
14749   { 'begin': 0x07C0, 'end': 0x07FF }, // NKo
14750   { 'begin': 0x0900, 'end': 0x097F }, // Devanagari
14751   { 'begin': 0x0980, 'end': 0x09FF }, // Bengali
14752   { 'begin': 0x0A00, 'end': 0x0A7F }, // Gurmukhi
14753   { 'begin': 0x0A80, 'end': 0x0AFF }, // Gujarati
14754   { 'begin': 0x0B00, 'end': 0x0B7F }, // Oriya
14755   { 'begin': 0x0B80, 'end': 0x0BFF }, // Tamil
14756   { 'begin': 0x0C00, 'end': 0x0C7F }, // Telugu
14757   { 'begin': 0x0C80, 'end': 0x0CFF }, // Kannada
14758   { 'begin': 0x0D00, 'end': 0x0D7F }, // Malayalam
14759   { 'begin': 0x0E00, 'end': 0x0E7F }, // Thai
14760   { 'begin': 0x0E80, 'end': 0x0EFF }, // Lao
14761   { 'begin': 0x10A0, 'end': 0x10FF }, // Georgian
14762   { 'begin': 0x1B00, 'end': 0x1B7F }, // Balinese
14763   { 'begin': 0x1100, 'end': 0x11FF }, // Hangul Jamo
14764   { 'begin': 0x1E00, 'end': 0x1EFF }, // Latin Extended Additional
14765   { 'begin': 0x1F00, 'end': 0x1FFF }, // Greek Extended
14766   { 'begin': 0x2000, 'end': 0x206F }, // General Punctuation
14767   { 'begin': 0x2070, 'end': 0x209F }, // Superscripts And Subscripts
14768   { 'begin': 0x20A0, 'end': 0x20CF }, // Currency Symbol
14769   { 'begin': 0x20D0, 'end': 0x20FF }, // Combining Diacritical Marks For Symbols
14770   { 'begin': 0x2100, 'end': 0x214F }, // Letterlike Symbols
14771   { 'begin': 0x2150, 'end': 0x218F }, // Number Forms
14772   { 'begin': 0x2190, 'end': 0x21FF }, // Arrows
14773   { 'begin': 0x2200, 'end': 0x22FF }, // Mathematical Operators
14774   { 'begin': 0x2300, 'end': 0x23FF }, // Miscellaneous Technical
14775   { 'begin': 0x2400, 'end': 0x243F }, // Control Pictures
14776   { 'begin': 0x2440, 'end': 0x245F }, // Optical Character Recognition
14777   { 'begin': 0x2460, 'end': 0x24FF }, // Enclosed Alphanumerics
14778   { 'begin': 0x2500, 'end': 0x257F }, // Box Drawing
14779   { 'begin': 0x2580, 'end': 0x259F }, // Block Elements
14780   { 'begin': 0x25A0, 'end': 0x25FF }, // Geometric Shapes
14781   { 'begin': 0x2600, 'end': 0x26FF }, // Miscellaneous Symbols
14782   { 'begin': 0x2700, 'end': 0x27BF }, // Dingbats
14783   { 'begin': 0x3000, 'end': 0x303F }, // CJK Symbols And Punctuation
14784   { 'begin': 0x3040, 'end': 0x309F }, // Hiragana
14785   { 'begin': 0x30A0, 'end': 0x30FF }, // Katakana
14786   { 'begin': 0x3100, 'end': 0x312F }, // Bopomofo
14787   { 'begin': 0x3130, 'end': 0x318F }, // Hangul Compatibility Jamo
14788   { 'begin': 0xA840, 'end': 0xA87F }, // Phags-pa
14789   { 'begin': 0x3200, 'end': 0x32FF }, // Enclosed CJK Letters And Months
14790   { 'begin': 0x3300, 'end': 0x33FF }, // CJK Compatibility
14791   { 'begin': 0xAC00, 'end': 0xD7AF }, // Hangul Syllables
14792   { 'begin': 0xD800, 'end': 0xDFFF }, // Non-Plane 0 *
14793   { 'begin': 0x10900, 'end': 0x1091F }, // Phoenicia
14794   { 'begin': 0x4E00, 'end': 0x9FFF }, // CJK Unified Ideographs
14795   { 'begin': 0xE000, 'end': 0xF8FF }, // Private Use Area (plane 0)
14796   { 'begin': 0x31C0, 'end': 0x31EF }, // CJK Strokes
14797   { 'begin': 0xFB00, 'end': 0xFB4F }, // Alphabetic Presentation Forms
14798   { 'begin': 0xFB50, 'end': 0xFDFF }, // Arabic Presentation Forms-A
14799   { 'begin': 0xFE20, 'end': 0xFE2F }, // Combining Half Marks
14800   { 'begin': 0xFE10, 'end': 0xFE1F }, // Vertical Forms
14801   { 'begin': 0xFE50, 'end': 0xFE6F }, // Small Form Variants
14802   { 'begin': 0xFE70, 'end': 0xFEFF }, // Arabic Presentation Forms-B
14803   { 'begin': 0xFF00, 'end': 0xFFEF }, // Halfwidth And Fullwidth Forms
14804   { 'begin': 0xFFF0, 'end': 0xFFFF }, // Specials
14805   { 'begin': 0x0F00, 'end': 0x0FFF }, // Tibetan
14806   { 'begin': 0x0700, 'end': 0x074F }, // Syriac
14807   { 'begin': 0x0780, 'end': 0x07BF }, // Thaana
14808   { 'begin': 0x0D80, 'end': 0x0DFF }, // Sinhala
14809   { 'begin': 0x1000, 'end': 0x109F }, // Myanmar
14810   { 'begin': 0x1200, 'end': 0x137F }, // Ethiopic
14811   { 'begin': 0x13A0, 'end': 0x13FF }, // Cherokee
14812   { 'begin': 0x1400, 'end': 0x167F }, // Unified Canadian Aboriginal Syllabics
14813   { 'begin': 0x1680, 'end': 0x169F }, // Ogham
14814   { 'begin': 0x16A0, 'end': 0x16FF }, // Runic
14815   { 'begin': 0x1780, 'end': 0x17FF }, // Khmer
14816   { 'begin': 0x1800, 'end': 0x18AF }, // Mongolian
14817   { 'begin': 0x2800, 'end': 0x28FF }, // Braille Patterns
14818   { 'begin': 0xA000, 'end': 0xA48F }, // Yi Syllables
14819   { 'begin': 0x1700, 'end': 0x171F }, // Tagalog
14820   { 'begin': 0x10300, 'end': 0x1032F }, // Old Italic
14821   { 'begin': 0x10330, 'end': 0x1034F }, // Gothic
14822   { 'begin': 0x10400, 'end': 0x1044F }, // Deseret
14823   { 'begin': 0x1D000, 'end': 0x1D0FF }, // Byzantine Musical Symbols
14824   { 'begin': 0x1D400, 'end': 0x1D7FF }, // Mathematical Alphanumeric Symbols
14825   { 'begin': 0xFF000, 'end': 0xFFFFD }, // Private Use (plane 15)
14826   { 'begin': 0xFE00, 'end': 0xFE0F }, // Variation Selectors
14827   { 'begin': 0xE0000, 'end': 0xE007F }, // Tags
14828   { 'begin': 0x1900, 'end': 0x194F }, // Limbu
14829   { 'begin': 0x1950, 'end': 0x197F }, // Tai Le
14830   { 'begin': 0x1980, 'end': 0x19DF }, // New Tai Lue
14831   { 'begin': 0x1A00, 'end': 0x1A1F }, // Buginese
14832   { 'begin': 0x2C00, 'end': 0x2C5F }, // Glagolitic
14833   { 'begin': 0x2D30, 'end': 0x2D7F }, // Tifinagh
14834   { 'begin': 0x4DC0, 'end': 0x4DFF }, // Yijing Hexagram Symbols
14835   { 'begin': 0xA800, 'end': 0xA82F }, // Syloti Nagri
14836   { 'begin': 0x10000, 'end': 0x1007F }, // Linear B Syllabary
14837   { 'begin': 0x10140, 'end': 0x1018F }, // Ancient Greek Numbers
14838   { 'begin': 0x10380, 'end': 0x1039F }, // Ugaritic
14839   { 'begin': 0x103A0, 'end': 0x103DF }, // Old Persian
14840   { 'begin': 0x10450, 'end': 0x1047F }, // Shavian
14841   { 'begin': 0x10480, 'end': 0x104AF }, // Osmanya
14842   { 'begin': 0x10800, 'end': 0x1083F }, // Cypriot Syllabary
14843   { 'begin': 0x10A00, 'end': 0x10A5F }, // Kharoshthi
14844   { 'begin': 0x1D300, 'end': 0x1D35F }, // Tai Xuan Jing Symbols
14845   { 'begin': 0x12000, 'end': 0x123FF }, // Cuneiform
14846   { 'begin': 0x1D360, 'end': 0x1D37F }, // Counting Rod Numerals
14847   { 'begin': 0x1B80, 'end': 0x1BBF }, // Sundanese
14848   { 'begin': 0x1C00, 'end': 0x1C4F }, // Lepcha
14849   { 'begin': 0x1C50, 'end': 0x1C7F }, // Ol Chiki
14850   { 'begin': 0xA880, 'end': 0xA8DF }, // Saurashtra
14851   { 'begin': 0xA900, 'end': 0xA92F }, // Kayah Li
14852   { 'begin': 0xA930, 'end': 0xA95F }, // Rejang
14853   { 'begin': 0xAA00, 'end': 0xAA5F }, // Cham
14854   { 'begin': 0x10190, 'end': 0x101CF }, // Ancient Symbols
14855   { 'begin': 0x101D0, 'end': 0x101FF }, // Phaistos Disc
14856   { 'begin': 0x102A0, 'end': 0x102DF }, // Carian
14857   { 'begin': 0x1F030, 'end': 0x1F09F }  // Domino Tiles
14858 ];
14859
14860 var MacStandardGlyphOrdering = [
14861   '.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl',
14862   'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft',
14863   'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash',
14864   'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
14865   'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at',
14866   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
14867   'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft',
14868   'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b',
14869   'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
14870   'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright',
14871   'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde',
14872   'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis',
14873   'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
14874   'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve',
14875   'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex',
14876   'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet',
14877   'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute',
14878   'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal',
14879   'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi',
14880   'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash',
14881   'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin',
14882   'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis',
14883   'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash',
14884   'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright',
14885   'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency',
14886   'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered',
14887   'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex',
14888   'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex',
14889   'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute',
14890   'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron',
14891   'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron',
14892   'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar',
14893   'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply',
14894   'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter',
14895   'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla',
14896   'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat'];
14897
14898 function getUnicodeRangeFor(value) {
14899   for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) {
14900     var range = UnicodeRanges[i];
14901     if (value >= range.begin && value < range.end) {
14902       return i;
14903     }
14904   }
14905   return -1;
14906 }
14907
14908 function isRTLRangeFor(value) {
14909   var range = UnicodeRanges[13];
14910   if (value >= range.begin && value < range.end) {
14911     return true;
14912   }
14913   range = UnicodeRanges[11];
14914   if (value >= range.begin && value < range.end) {
14915     return true;
14916   }
14917   return false;
14918 }
14919
14920 // The normalization table is obtained by filtering the Unicode characters
14921 // database with <compat> entries.
14922 var NormalizedUnicodes = {
14923   '\u00A8': '\u0020\u0308',
14924   '\u00AF': '\u0020\u0304',
14925   '\u00B4': '\u0020\u0301',
14926   '\u00B5': '\u03BC',
14927   '\u00B8': '\u0020\u0327',
14928   '\u0132': '\u0049\u004A',
14929   '\u0133': '\u0069\u006A',
14930   '\u013F': '\u004C\u00B7',
14931   '\u0140': '\u006C\u00B7',
14932   '\u0149': '\u02BC\u006E',
14933   '\u017F': '\u0073',
14934   '\u01C4': '\u0044\u017D',
14935   '\u01C5': '\u0044\u017E',
14936   '\u01C6': '\u0064\u017E',
14937   '\u01C7': '\u004C\u004A',
14938   '\u01C8': '\u004C\u006A',
14939   '\u01C9': '\u006C\u006A',
14940   '\u01CA': '\u004E\u004A',
14941   '\u01CB': '\u004E\u006A',
14942   '\u01CC': '\u006E\u006A',
14943   '\u01F1': '\u0044\u005A',
14944   '\u01F2': '\u0044\u007A',
14945   '\u01F3': '\u0064\u007A',
14946   '\u02D8': '\u0020\u0306',
14947   '\u02D9': '\u0020\u0307',
14948   '\u02DA': '\u0020\u030A',
14949   '\u02DB': '\u0020\u0328',
14950   '\u02DC': '\u0020\u0303',
14951   '\u02DD': '\u0020\u030B',
14952   '\u037A': '\u0020\u0345',
14953   '\u0384': '\u0020\u0301',
14954   '\u03D0': '\u03B2',
14955   '\u03D1': '\u03B8',
14956   '\u03D2': '\u03A5',
14957   '\u03D5': '\u03C6',
14958   '\u03D6': '\u03C0',
14959   '\u03F0': '\u03BA',
14960   '\u03F1': '\u03C1',
14961   '\u03F2': '\u03C2',
14962   '\u03F4': '\u0398',
14963   '\u03F5': '\u03B5',
14964   '\u03F9': '\u03A3',
14965   '\u0587': '\u0565\u0582',
14966   '\u0675': '\u0627\u0674',
14967   '\u0676': '\u0648\u0674',
14968   '\u0677': '\u06C7\u0674',
14969   '\u0678': '\u064A\u0674',
14970   '\u0E33': '\u0E4D\u0E32',
14971   '\u0EB3': '\u0ECD\u0EB2',
14972   '\u0EDC': '\u0EAB\u0E99',
14973   '\u0EDD': '\u0EAB\u0EA1',
14974   '\u0F77': '\u0FB2\u0F81',
14975   '\u0F79': '\u0FB3\u0F81',
14976   '\u1E9A': '\u0061\u02BE',
14977   '\u1FBD': '\u0020\u0313',
14978   '\u1FBF': '\u0020\u0313',
14979   '\u1FC0': '\u0020\u0342',
14980   '\u1FFE': '\u0020\u0314',
14981   '\u2002': '\u0020',
14982   '\u2003': '\u0020',
14983   '\u2004': '\u0020',
14984   '\u2005': '\u0020',
14985   '\u2006': '\u0020',
14986   '\u2008': '\u0020',
14987   '\u2009': '\u0020',
14988   '\u200A': '\u0020',
14989   '\u2017': '\u0020\u0333',
14990   '\u2024': '\u002E',
14991   '\u2025': '\u002E\u002E',
14992   '\u2026': '\u002E\u002E\u002E',
14993   '\u2033': '\u2032\u2032',
14994   '\u2034': '\u2032\u2032\u2032',
14995   '\u2036': '\u2035\u2035',
14996   '\u2037': '\u2035\u2035\u2035',
14997   '\u203C': '\u0021\u0021',
14998   '\u203E': '\u0020\u0305',
14999   '\u2047': '\u003F\u003F',
15000   '\u2048': '\u003F\u0021',
15001   '\u2049': '\u0021\u003F',
15002   '\u2057': '\u2032\u2032\u2032\u2032',
15003   '\u205F': '\u0020',
15004   '\u20A8': '\u0052\u0073',
15005   '\u2100': '\u0061\u002F\u0063',
15006   '\u2101': '\u0061\u002F\u0073',
15007   '\u2103': '\u00B0\u0043',
15008   '\u2105': '\u0063\u002F\u006F',
15009   '\u2106': '\u0063\u002F\u0075',
15010   '\u2107': '\u0190',
15011   '\u2109': '\u00B0\u0046',
15012   '\u2116': '\u004E\u006F',
15013   '\u2121': '\u0054\u0045\u004C',
15014   '\u2135': '\u05D0',
15015   '\u2136': '\u05D1',
15016   '\u2137': '\u05D2',
15017   '\u2138': '\u05D3',
15018   '\u213B': '\u0046\u0041\u0058',
15019   '\u2160': '\u0049',
15020   '\u2161': '\u0049\u0049',
15021   '\u2162': '\u0049\u0049\u0049',
15022   '\u2163': '\u0049\u0056',
15023   '\u2164': '\u0056',
15024   '\u2165': '\u0056\u0049',
15025   '\u2166': '\u0056\u0049\u0049',
15026   '\u2167': '\u0056\u0049\u0049\u0049',
15027   '\u2168': '\u0049\u0058',
15028   '\u2169': '\u0058',
15029   '\u216A': '\u0058\u0049',
15030   '\u216B': '\u0058\u0049\u0049',
15031   '\u216C': '\u004C',
15032   '\u216D': '\u0043',
15033   '\u216E': '\u0044',
15034   '\u216F': '\u004D',
15035   '\u2170': '\u0069',
15036   '\u2171': '\u0069\u0069',
15037   '\u2172': '\u0069\u0069\u0069',
15038   '\u2173': '\u0069\u0076',
15039   '\u2174': '\u0076',
15040   '\u2175': '\u0076\u0069',
15041   '\u2176': '\u0076\u0069\u0069',
15042   '\u2177': '\u0076\u0069\u0069\u0069',
15043   '\u2178': '\u0069\u0078',
15044   '\u2179': '\u0078',
15045   '\u217A': '\u0078\u0069',
15046   '\u217B': '\u0078\u0069\u0069',
15047   '\u217C': '\u006C',
15048   '\u217D': '\u0063',
15049   '\u217E': '\u0064',
15050   '\u217F': '\u006D',
15051   '\u222C': '\u222B\u222B',
15052   '\u222D': '\u222B\u222B\u222B',
15053   '\u222F': '\u222E\u222E',
15054   '\u2230': '\u222E\u222E\u222E',
15055   '\u2474': '\u0028\u0031\u0029',
15056   '\u2475': '\u0028\u0032\u0029',
15057   '\u2476': '\u0028\u0033\u0029',
15058   '\u2477': '\u0028\u0034\u0029',
15059   '\u2478': '\u0028\u0035\u0029',
15060   '\u2479': '\u0028\u0036\u0029',
15061   '\u247A': '\u0028\u0037\u0029',
15062   '\u247B': '\u0028\u0038\u0029',
15063   '\u247C': '\u0028\u0039\u0029',
15064   '\u247D': '\u0028\u0031\u0030\u0029',
15065   '\u247E': '\u0028\u0031\u0031\u0029',
15066   '\u247F': '\u0028\u0031\u0032\u0029',
15067   '\u2480': '\u0028\u0031\u0033\u0029',
15068   '\u2481': '\u0028\u0031\u0034\u0029',
15069   '\u2482': '\u0028\u0031\u0035\u0029',
15070   '\u2483': '\u0028\u0031\u0036\u0029',
15071   '\u2484': '\u0028\u0031\u0037\u0029',
15072   '\u2485': '\u0028\u0031\u0038\u0029',
15073   '\u2486': '\u0028\u0031\u0039\u0029',
15074   '\u2487': '\u0028\u0032\u0030\u0029',
15075   '\u2488': '\u0031\u002E',
15076   '\u2489': '\u0032\u002E',
15077   '\u248A': '\u0033\u002E',
15078   '\u248B': '\u0034\u002E',
15079   '\u248C': '\u0035\u002E',
15080   '\u248D': '\u0036\u002E',
15081   '\u248E': '\u0037\u002E',
15082   '\u248F': '\u0038\u002E',
15083   '\u2490': '\u0039\u002E',
15084   '\u2491': '\u0031\u0030\u002E',
15085   '\u2492': '\u0031\u0031\u002E',
15086   '\u2493': '\u0031\u0032\u002E',
15087   '\u2494': '\u0031\u0033\u002E',
15088   '\u2495': '\u0031\u0034\u002E',
15089   '\u2496': '\u0031\u0035\u002E',
15090   '\u2497': '\u0031\u0036\u002E',
15091   '\u2498': '\u0031\u0037\u002E',
15092   '\u2499': '\u0031\u0038\u002E',
15093   '\u249A': '\u0031\u0039\u002E',
15094   '\u249B': '\u0032\u0030\u002E',
15095   '\u249C': '\u0028\u0061\u0029',
15096   '\u249D': '\u0028\u0062\u0029',
15097   '\u249E': '\u0028\u0063\u0029',
15098   '\u249F': '\u0028\u0064\u0029',
15099   '\u24A0': '\u0028\u0065\u0029',
15100   '\u24A1': '\u0028\u0066\u0029',
15101   '\u24A2': '\u0028\u0067\u0029',
15102   '\u24A3': '\u0028\u0068\u0029',
15103   '\u24A4': '\u0028\u0069\u0029',
15104   '\u24A5': '\u0028\u006A\u0029',
15105   '\u24A6': '\u0028\u006B\u0029',
15106   '\u24A7': '\u0028\u006C\u0029',
15107   '\u24A8': '\u0028\u006D\u0029',
15108   '\u24A9': '\u0028\u006E\u0029',
15109   '\u24AA': '\u0028\u006F\u0029',
15110   '\u24AB': '\u0028\u0070\u0029',
15111   '\u24AC': '\u0028\u0071\u0029',
15112   '\u24AD': '\u0028\u0072\u0029',
15113   '\u24AE': '\u0028\u0073\u0029',
15114   '\u24AF': '\u0028\u0074\u0029',
15115   '\u24B0': '\u0028\u0075\u0029',
15116   '\u24B1': '\u0028\u0076\u0029',
15117   '\u24B2': '\u0028\u0077\u0029',
15118   '\u24B3': '\u0028\u0078\u0029',
15119   '\u24B4': '\u0028\u0079\u0029',
15120   '\u24B5': '\u0028\u007A\u0029',
15121   '\u2A0C': '\u222B\u222B\u222B\u222B',
15122   '\u2A74': '\u003A\u003A\u003D',
15123   '\u2A75': '\u003D\u003D',
15124   '\u2A76': '\u003D\u003D\u003D',
15125   '\u2E9F': '\u6BCD',
15126   '\u2EF3': '\u9F9F',
15127   '\u2F00': '\u4E00',
15128   '\u2F01': '\u4E28',
15129   '\u2F02': '\u4E36',
15130   '\u2F03': '\u4E3F',
15131   '\u2F04': '\u4E59',
15132   '\u2F05': '\u4E85',
15133   '\u2F06': '\u4E8C',
15134   '\u2F07': '\u4EA0',
15135   '\u2F08': '\u4EBA',
15136   '\u2F09': '\u513F',
15137   '\u2F0A': '\u5165',
15138   '\u2F0B': '\u516B',
15139   '\u2F0C': '\u5182',
15140   '\u2F0D': '\u5196',
15141   '\u2F0E': '\u51AB',
15142   '\u2F0F': '\u51E0',
15143   '\u2F10': '\u51F5',
15144   '\u2F11': '\u5200',
15145   '\u2F12': '\u529B',
15146   '\u2F13': '\u52F9',
15147   '\u2F14': '\u5315',
15148   '\u2F15': '\u531A',
15149   '\u2F16': '\u5338',
15150   '\u2F17': '\u5341',
15151   '\u2F18': '\u535C',
15152   '\u2F19': '\u5369',
15153   '\u2F1A': '\u5382',
15154   '\u2F1B': '\u53B6',
15155   '\u2F1C': '\u53C8',
15156   '\u2F1D': '\u53E3',
15157   '\u2F1E': '\u56D7',
15158   '\u2F1F': '\u571F',
15159   '\u2F20': '\u58EB',
15160   '\u2F21': '\u5902',
15161   '\u2F22': '\u590A',
15162   '\u2F23': '\u5915',
15163   '\u2F24': '\u5927',
15164   '\u2F25': '\u5973',
15165   '\u2F26': '\u5B50',
15166   '\u2F27': '\u5B80',
15167   '\u2F28': '\u5BF8',
15168   '\u2F29': '\u5C0F',
15169   '\u2F2A': '\u5C22',
15170   '\u2F2B': '\u5C38',
15171   '\u2F2C': '\u5C6E',
15172   '\u2F2D': '\u5C71',
15173   '\u2F2E': '\u5DDB',
15174   '\u2F2F': '\u5DE5',
15175   '\u2F30': '\u5DF1',
15176   '\u2F31': '\u5DFE',
15177   '\u2F32': '\u5E72',
15178   '\u2F33': '\u5E7A',
15179   '\u2F34': '\u5E7F',
15180   '\u2F35': '\u5EF4',
15181   '\u2F36': '\u5EFE',
15182   '\u2F37': '\u5F0B',
15183   '\u2F38': '\u5F13',
15184   '\u2F39': '\u5F50',
15185   '\u2F3A': '\u5F61',
15186   '\u2F3B': '\u5F73',
15187   '\u2F3C': '\u5FC3',
15188   '\u2F3D': '\u6208',
15189   '\u2F3E': '\u6236',
15190   '\u2F3F': '\u624B',
15191   '\u2F40': '\u652F',
15192   '\u2F41': '\u6534',
15193   '\u2F42': '\u6587',
15194   '\u2F43': '\u6597',
15195   '\u2F44': '\u65A4',
15196   '\u2F45': '\u65B9',
15197   '\u2F46': '\u65E0',
15198   '\u2F47': '\u65E5',
15199   '\u2F48': '\u66F0',
15200   '\u2F49': '\u6708',
15201   '\u2F4A': '\u6728',
15202   '\u2F4B': '\u6B20',
15203   '\u2F4C': '\u6B62',
15204   '\u2F4D': '\u6B79',
15205   '\u2F4E': '\u6BB3',
15206   '\u2F4F': '\u6BCB',
15207   '\u2F50': '\u6BD4',
15208   '\u2F51': '\u6BDB',
15209   '\u2F52': '\u6C0F',
15210   '\u2F53': '\u6C14',
15211   '\u2F54': '\u6C34',
15212   '\u2F55': '\u706B',
15213   '\u2F56': '\u722A',
15214   '\u2F57': '\u7236',
15215   '\u2F58': '\u723B',
15216   '\u2F59': '\u723F',
15217   '\u2F5A': '\u7247',
15218   '\u2F5B': '\u7259',
15219   '\u2F5C': '\u725B',
15220   '\u2F5D': '\u72AC',
15221   '\u2F5E': '\u7384',
15222   '\u2F5F': '\u7389',
15223   '\u2F60': '\u74DC',
15224   '\u2F61': '\u74E6',
15225   '\u2F62': '\u7518',
15226   '\u2F63': '\u751F',
15227   '\u2F64': '\u7528',
15228   '\u2F65': '\u7530',
15229   '\u2F66': '\u758B',
15230   '\u2F67': '\u7592',
15231   '\u2F68': '\u7676',
15232   '\u2F69': '\u767D',
15233   '\u2F6A': '\u76AE',
15234   '\u2F6B': '\u76BF',
15235   '\u2F6C': '\u76EE',
15236   '\u2F6D': '\u77DB',
15237   '\u2F6E': '\u77E2',
15238   '\u2F6F': '\u77F3',
15239   '\u2F70': '\u793A',
15240   '\u2F71': '\u79B8',
15241   '\u2F72': '\u79BE',
15242   '\u2F73': '\u7A74',
15243   '\u2F74': '\u7ACB',
15244   '\u2F75': '\u7AF9',
15245   '\u2F76': '\u7C73',
15246   '\u2F77': '\u7CF8',
15247   '\u2F78': '\u7F36',
15248   '\u2F79': '\u7F51',
15249   '\u2F7A': '\u7F8A',
15250   '\u2F7B': '\u7FBD',
15251   '\u2F7C': '\u8001',
15252   '\u2F7D': '\u800C',
15253   '\u2F7E': '\u8012',
15254   '\u2F7F': '\u8033',
15255   '\u2F80': '\u807F',
15256   '\u2F81': '\u8089',
15257   '\u2F82': '\u81E3',
15258   '\u2F83': '\u81EA',
15259   '\u2F84': '\u81F3',
15260   '\u2F85': '\u81FC',
15261   '\u2F86': '\u820C',
15262   '\u2F87': '\u821B',
15263   '\u2F88': '\u821F',
15264   '\u2F89': '\u826E',
15265   '\u2F8A': '\u8272',
15266   '\u2F8B': '\u8278',
15267   '\u2F8C': '\u864D',
15268   '\u2F8D': '\u866B',
15269   '\u2F8E': '\u8840',
15270   '\u2F8F': '\u884C',
15271   '\u2F90': '\u8863',
15272   '\u2F91': '\u897E',
15273   '\u2F92': '\u898B',
15274   '\u2F93': '\u89D2',
15275   '\u2F94': '\u8A00',
15276   '\u2F95': '\u8C37',
15277   '\u2F96': '\u8C46',
15278   '\u2F97': '\u8C55',
15279   '\u2F98': '\u8C78',
15280   '\u2F99': '\u8C9D',
15281   '\u2F9A': '\u8D64',
15282   '\u2F9B': '\u8D70',
15283   '\u2F9C': '\u8DB3',
15284   '\u2F9D': '\u8EAB',
15285   '\u2F9E': '\u8ECA',
15286   '\u2F9F': '\u8F9B',
15287   '\u2FA0': '\u8FB0',
15288   '\u2FA1': '\u8FB5',
15289   '\u2FA2': '\u9091',
15290   '\u2FA3': '\u9149',
15291   '\u2FA4': '\u91C6',
15292   '\u2FA5': '\u91CC',
15293   '\u2FA6': '\u91D1',
15294   '\u2FA7': '\u9577',
15295   '\u2FA8': '\u9580',
15296   '\u2FA9': '\u961C',
15297   '\u2FAA': '\u96B6',
15298   '\u2FAB': '\u96B9',
15299   '\u2FAC': '\u96E8',
15300   '\u2FAD': '\u9751',
15301   '\u2FAE': '\u975E',
15302   '\u2FAF': '\u9762',
15303   '\u2FB0': '\u9769',
15304   '\u2FB1': '\u97CB',
15305   '\u2FB2': '\u97ED',
15306   '\u2FB3': '\u97F3',
15307   '\u2FB4': '\u9801',
15308   '\u2FB5': '\u98A8',
15309   '\u2FB6': '\u98DB',
15310   '\u2FB7': '\u98DF',
15311   '\u2FB8': '\u9996',
15312   '\u2FB9': '\u9999',
15313   '\u2FBA': '\u99AC',
15314   '\u2FBB': '\u9AA8',
15315   '\u2FBC': '\u9AD8',
15316   '\u2FBD': '\u9ADF',
15317   '\u2FBE': '\u9B25',
15318   '\u2FBF': '\u9B2F',
15319   '\u2FC0': '\u9B32',
15320   '\u2FC1': '\u9B3C',
15321   '\u2FC2': '\u9B5A',
15322   '\u2FC3': '\u9CE5',
15323   '\u2FC4': '\u9E75',
15324   '\u2FC5': '\u9E7F',
15325   '\u2FC6': '\u9EA5',
15326   '\u2FC7': '\u9EBB',
15327   '\u2FC8': '\u9EC3',
15328   '\u2FC9': '\u9ECD',
15329   '\u2FCA': '\u9ED1',
15330   '\u2FCB': '\u9EF9',
15331   '\u2FCC': '\u9EFD',
15332   '\u2FCD': '\u9F0E',
15333   '\u2FCE': '\u9F13',
15334   '\u2FCF': '\u9F20',
15335   '\u2FD0': '\u9F3B',
15336   '\u2FD1': '\u9F4A',
15337   '\u2FD2': '\u9F52',
15338   '\u2FD3': '\u9F8D',
15339   '\u2FD4': '\u9F9C',
15340   '\u2FD5': '\u9FA0',
15341   '\u3036': '\u3012',
15342   '\u3038': '\u5341',
15343   '\u3039': '\u5344',
15344   '\u303A': '\u5345',
15345   '\u309B': '\u0020\u3099',
15346   '\u309C': '\u0020\u309A',
15347   '\u3131': '\u1100',
15348   '\u3132': '\u1101',
15349   '\u3133': '\u11AA',
15350   '\u3134': '\u1102',
15351   '\u3135': '\u11AC',
15352   '\u3136': '\u11AD',
15353   '\u3137': '\u1103',
15354   '\u3138': '\u1104',
15355   '\u3139': '\u1105',
15356   '\u313A': '\u11B0',
15357   '\u313B': '\u11B1',
15358   '\u313C': '\u11B2',
15359   '\u313D': '\u11B3',
15360   '\u313E': '\u11B4',
15361   '\u313F': '\u11B5',
15362   '\u3140': '\u111A',
15363   '\u3141': '\u1106',
15364   '\u3142': '\u1107',
15365   '\u3143': '\u1108',
15366   '\u3144': '\u1121',
15367   '\u3145': '\u1109',
15368   '\u3146': '\u110A',
15369   '\u3147': '\u110B',
15370   '\u3148': '\u110C',
15371   '\u3149': '\u110D',
15372   '\u314A': '\u110E',
15373   '\u314B': '\u110F',
15374   '\u314C': '\u1110',
15375   '\u314D': '\u1111',
15376   '\u314E': '\u1112',
15377   '\u314F': '\u1161',
15378   '\u3150': '\u1162',
15379   '\u3151': '\u1163',
15380   '\u3152': '\u1164',
15381   '\u3153': '\u1165',
15382   '\u3154': '\u1166',
15383   '\u3155': '\u1167',
15384   '\u3156': '\u1168',
15385   '\u3157': '\u1169',
15386   '\u3158': '\u116A',
15387   '\u3159': '\u116B',
15388   '\u315A': '\u116C',
15389   '\u315B': '\u116D',
15390   '\u315C': '\u116E',
15391   '\u315D': '\u116F',
15392   '\u315E': '\u1170',
15393   '\u315F': '\u1171',
15394   '\u3160': '\u1172',
15395   '\u3161': '\u1173',
15396   '\u3162': '\u1174',
15397   '\u3163': '\u1175',
15398   '\u3164': '\u1160',
15399   '\u3165': '\u1114',
15400   '\u3166': '\u1115',
15401   '\u3167': '\u11C7',
15402   '\u3168': '\u11C8',
15403   '\u3169': '\u11CC',
15404   '\u316A': '\u11CE',
15405   '\u316B': '\u11D3',
15406   '\u316C': '\u11D7',
15407   '\u316D': '\u11D9',
15408   '\u316E': '\u111C',
15409   '\u316F': '\u11DD',
15410   '\u3170': '\u11DF',
15411   '\u3171': '\u111D',
15412   '\u3172': '\u111E',
15413   '\u3173': '\u1120',
15414   '\u3174': '\u1122',
15415   '\u3175': '\u1123',
15416   '\u3176': '\u1127',
15417   '\u3177': '\u1129',
15418   '\u3178': '\u112B',
15419   '\u3179': '\u112C',
15420   '\u317A': '\u112D',
15421   '\u317B': '\u112E',
15422   '\u317C': '\u112F',
15423   '\u317D': '\u1132',
15424   '\u317E': '\u1136',
15425   '\u317F': '\u1140',
15426   '\u3180': '\u1147',
15427   '\u3181': '\u114C',
15428   '\u3182': '\u11F1',
15429   '\u3183': '\u11F2',
15430   '\u3184': '\u1157',
15431   '\u3185': '\u1158',
15432   '\u3186': '\u1159',
15433   '\u3187': '\u1184',
15434   '\u3188': '\u1185',
15435   '\u3189': '\u1188',
15436   '\u318A': '\u1191',
15437   '\u318B': '\u1192',
15438   '\u318C': '\u1194',
15439   '\u318D': '\u119E',
15440   '\u318E': '\u11A1',
15441   '\u3200': '\u0028\u1100\u0029',
15442   '\u3201': '\u0028\u1102\u0029',
15443   '\u3202': '\u0028\u1103\u0029',
15444   '\u3203': '\u0028\u1105\u0029',
15445   '\u3204': '\u0028\u1106\u0029',
15446   '\u3205': '\u0028\u1107\u0029',
15447   '\u3206': '\u0028\u1109\u0029',
15448   '\u3207': '\u0028\u110B\u0029',
15449   '\u3208': '\u0028\u110C\u0029',
15450   '\u3209': '\u0028\u110E\u0029',
15451   '\u320A': '\u0028\u110F\u0029',
15452   '\u320B': '\u0028\u1110\u0029',
15453   '\u320C': '\u0028\u1111\u0029',
15454   '\u320D': '\u0028\u1112\u0029',
15455   '\u320E': '\u0028\u1100\u1161\u0029',
15456   '\u320F': '\u0028\u1102\u1161\u0029',
15457   '\u3210': '\u0028\u1103\u1161\u0029',
15458   '\u3211': '\u0028\u1105\u1161\u0029',
15459   '\u3212': '\u0028\u1106\u1161\u0029',
15460   '\u3213': '\u0028\u1107\u1161\u0029',
15461   '\u3214': '\u0028\u1109\u1161\u0029',
15462   '\u3215': '\u0028\u110B\u1161\u0029',
15463   '\u3216': '\u0028\u110C\u1161\u0029',
15464   '\u3217': '\u0028\u110E\u1161\u0029',
15465   '\u3218': '\u0028\u110F\u1161\u0029',
15466   '\u3219': '\u0028\u1110\u1161\u0029',
15467   '\u321A': '\u0028\u1111\u1161\u0029',
15468   '\u321B': '\u0028\u1112\u1161\u0029',
15469   '\u321C': '\u0028\u110C\u116E\u0029',
15470   '\u321D': '\u0028\u110B\u1169\u110C\u1165\u11AB\u0029',
15471   '\u321E': '\u0028\u110B\u1169\u1112\u116E\u0029',
15472   '\u3220': '\u0028\u4E00\u0029',
15473   '\u3221': '\u0028\u4E8C\u0029',
15474   '\u3222': '\u0028\u4E09\u0029',
15475   '\u3223': '\u0028\u56DB\u0029',
15476   '\u3224': '\u0028\u4E94\u0029',
15477   '\u3225': '\u0028\u516D\u0029',
15478   '\u3226': '\u0028\u4E03\u0029',
15479   '\u3227': '\u0028\u516B\u0029',
15480   '\u3228': '\u0028\u4E5D\u0029',
15481   '\u3229': '\u0028\u5341\u0029',
15482   '\u322A': '\u0028\u6708\u0029',
15483   '\u322B': '\u0028\u706B\u0029',
15484   '\u322C': '\u0028\u6C34\u0029',
15485   '\u322D': '\u0028\u6728\u0029',
15486   '\u322E': '\u0028\u91D1\u0029',
15487   '\u322F': '\u0028\u571F\u0029',
15488   '\u3230': '\u0028\u65E5\u0029',
15489   '\u3231': '\u0028\u682A\u0029',
15490   '\u3232': '\u0028\u6709\u0029',
15491   '\u3233': '\u0028\u793E\u0029',
15492   '\u3234': '\u0028\u540D\u0029',
15493   '\u3235': '\u0028\u7279\u0029',
15494   '\u3236': '\u0028\u8CA1\u0029',
15495   '\u3237': '\u0028\u795D\u0029',
15496   '\u3238': '\u0028\u52B4\u0029',
15497   '\u3239': '\u0028\u4EE3\u0029',
15498   '\u323A': '\u0028\u547C\u0029',
15499   '\u323B': '\u0028\u5B66\u0029',
15500   '\u323C': '\u0028\u76E3\u0029',
15501   '\u323D': '\u0028\u4F01\u0029',
15502   '\u323E': '\u0028\u8CC7\u0029',
15503   '\u323F': '\u0028\u5354\u0029',
15504   '\u3240': '\u0028\u796D\u0029',
15505   '\u3241': '\u0028\u4F11\u0029',
15506   '\u3242': '\u0028\u81EA\u0029',
15507   '\u3243': '\u0028\u81F3\u0029',
15508   '\u32C0': '\u0031\u6708',
15509   '\u32C1': '\u0032\u6708',
15510   '\u32C2': '\u0033\u6708',
15511   '\u32C3': '\u0034\u6708',
15512   '\u32C4': '\u0035\u6708',
15513   '\u32C5': '\u0036\u6708',
15514   '\u32C6': '\u0037\u6708',
15515   '\u32C7': '\u0038\u6708',
15516   '\u32C8': '\u0039\u6708',
15517   '\u32C9': '\u0031\u0030\u6708',
15518   '\u32CA': '\u0031\u0031\u6708',
15519   '\u32CB': '\u0031\u0032\u6708',
15520   '\u3358': '\u0030\u70B9',
15521   '\u3359': '\u0031\u70B9',
15522   '\u335A': '\u0032\u70B9',
15523   '\u335B': '\u0033\u70B9',
15524   '\u335C': '\u0034\u70B9',
15525   '\u335D': '\u0035\u70B9',
15526   '\u335E': '\u0036\u70B9',
15527   '\u335F': '\u0037\u70B9',
15528   '\u3360': '\u0038\u70B9',
15529   '\u3361': '\u0039\u70B9',
15530   '\u3362': '\u0031\u0030\u70B9',
15531   '\u3363': '\u0031\u0031\u70B9',
15532   '\u3364': '\u0031\u0032\u70B9',
15533   '\u3365': '\u0031\u0033\u70B9',
15534   '\u3366': '\u0031\u0034\u70B9',
15535   '\u3367': '\u0031\u0035\u70B9',
15536   '\u3368': '\u0031\u0036\u70B9',
15537   '\u3369': '\u0031\u0037\u70B9',
15538   '\u336A': '\u0031\u0038\u70B9',
15539   '\u336B': '\u0031\u0039\u70B9',
15540   '\u336C': '\u0032\u0030\u70B9',
15541   '\u336D': '\u0032\u0031\u70B9',
15542   '\u336E': '\u0032\u0032\u70B9',
15543   '\u336F': '\u0032\u0033\u70B9',
15544   '\u3370': '\u0032\u0034\u70B9',
15545   '\u33E0': '\u0031\u65E5',
15546   '\u33E1': '\u0032\u65E5',
15547   '\u33E2': '\u0033\u65E5',
15548   '\u33E3': '\u0034\u65E5',
15549   '\u33E4': '\u0035\u65E5',
15550   '\u33E5': '\u0036\u65E5',
15551   '\u33E6': '\u0037\u65E5',
15552   '\u33E7': '\u0038\u65E5',
15553   '\u33E8': '\u0039\u65E5',
15554   '\u33E9': '\u0031\u0030\u65E5',
15555   '\u33EA': '\u0031\u0031\u65E5',
15556   '\u33EB': '\u0031\u0032\u65E5',
15557   '\u33EC': '\u0031\u0033\u65E5',
15558   '\u33ED': '\u0031\u0034\u65E5',
15559   '\u33EE': '\u0031\u0035\u65E5',
15560   '\u33EF': '\u0031\u0036\u65E5',
15561   '\u33F0': '\u0031\u0037\u65E5',
15562   '\u33F1': '\u0031\u0038\u65E5',
15563   '\u33F2': '\u0031\u0039\u65E5',
15564   '\u33F3': '\u0032\u0030\u65E5',
15565   '\u33F4': '\u0032\u0031\u65E5',
15566   '\u33F5': '\u0032\u0032\u65E5',
15567   '\u33F6': '\u0032\u0033\u65E5',
15568   '\u33F7': '\u0032\u0034\u65E5',
15569   '\u33F8': '\u0032\u0035\u65E5',
15570   '\u33F9': '\u0032\u0036\u65E5',
15571   '\u33FA': '\u0032\u0037\u65E5',
15572   '\u33FB': '\u0032\u0038\u65E5',
15573   '\u33FC': '\u0032\u0039\u65E5',
15574   '\u33FD': '\u0033\u0030\u65E5',
15575   '\u33FE': '\u0033\u0031\u65E5',
15576   '\uFB00': '\u0066\u0066',
15577   '\uFB01': '\u0066\u0069',
15578   '\uFB02': '\u0066\u006C',
15579   '\uFB03': '\u0066\u0066\u0069',
15580   '\uFB04': '\u0066\u0066\u006C',
15581   '\uFB05': '\u017F\u0074',
15582   '\uFB06': '\u0073\u0074',
15583   '\uFB13': '\u0574\u0576',
15584   '\uFB14': '\u0574\u0565',
15585   '\uFB15': '\u0574\u056B',
15586   '\uFB16': '\u057E\u0576',
15587   '\uFB17': '\u0574\u056D',
15588   '\uFB4F': '\u05D0\u05DC',
15589   '\uFB50': '\u0671',
15590   '\uFB51': '\u0671',
15591   '\uFB52': '\u067B',
15592   '\uFB53': '\u067B',
15593   '\uFB54': '\u067B',
15594   '\uFB55': '\u067B',
15595   '\uFB56': '\u067E',
15596   '\uFB57': '\u067E',
15597   '\uFB58': '\u067E',
15598   '\uFB59': '\u067E',
15599   '\uFB5A': '\u0680',
15600   '\uFB5B': '\u0680',
15601   '\uFB5C': '\u0680',
15602   '\uFB5D': '\u0680',
15603   '\uFB5E': '\u067A',
15604   '\uFB5F': '\u067A',
15605   '\uFB60': '\u067A',
15606   '\uFB61': '\u067A',
15607   '\uFB62': '\u067F',
15608   '\uFB63': '\u067F',
15609   '\uFB64': '\u067F',
15610   '\uFB65': '\u067F',
15611   '\uFB66': '\u0679',
15612   '\uFB67': '\u0679',
15613   '\uFB68': '\u0679',
15614   '\uFB69': '\u0679',
15615   '\uFB6A': '\u06A4',
15616   '\uFB6B': '\u06A4',
15617   '\uFB6C': '\u06A4',
15618   '\uFB6D': '\u06A4',
15619   '\uFB6E': '\u06A6',
15620   '\uFB6F': '\u06A6',
15621   '\uFB70': '\u06A6',
15622   '\uFB71': '\u06A6',
15623   '\uFB72': '\u0684',
15624   '\uFB73': '\u0684',
15625   '\uFB74': '\u0684',
15626   '\uFB75': '\u0684',
15627   '\uFB76': '\u0683',
15628   '\uFB77': '\u0683',
15629   '\uFB78': '\u0683',
15630   '\uFB79': '\u0683',
15631   '\uFB7A': '\u0686',
15632   '\uFB7B': '\u0686',
15633   '\uFB7C': '\u0686',
15634   '\uFB7D': '\u0686',
15635   '\uFB7E': '\u0687',
15636   '\uFB7F': '\u0687',
15637   '\uFB80': '\u0687',
15638   '\uFB81': '\u0687',
15639   '\uFB82': '\u068D',
15640   '\uFB83': '\u068D',
15641   '\uFB84': '\u068C',
15642   '\uFB85': '\u068C',
15643   '\uFB86': '\u068E',
15644   '\uFB87': '\u068E',
15645   '\uFB88': '\u0688',
15646   '\uFB89': '\u0688',
15647   '\uFB8A': '\u0698',
15648   '\uFB8B': '\u0698',
15649   '\uFB8C': '\u0691',
15650   '\uFB8D': '\u0691',
15651   '\uFB8E': '\u06A9',
15652   '\uFB8F': '\u06A9',
15653   '\uFB90': '\u06A9',
15654   '\uFB91': '\u06A9',
15655   '\uFB92': '\u06AF',
15656   '\uFB93': '\u06AF',
15657   '\uFB94': '\u06AF',
15658   '\uFB95': '\u06AF',
15659   '\uFB96': '\u06B3',
15660   '\uFB97': '\u06B3',
15661   '\uFB98': '\u06B3',
15662   '\uFB99': '\u06B3',
15663   '\uFB9A': '\u06B1',
15664   '\uFB9B': '\u06B1',
15665   '\uFB9C': '\u06B1',
15666   '\uFB9D': '\u06B1',
15667   '\uFB9E': '\u06BA',
15668   '\uFB9F': '\u06BA',
15669   '\uFBA0': '\u06BB',
15670   '\uFBA1': '\u06BB',
15671   '\uFBA2': '\u06BB',
15672   '\uFBA3': '\u06BB',
15673   '\uFBA4': '\u06C0',
15674   '\uFBA5': '\u06C0',
15675   '\uFBA6': '\u06C1',
15676   '\uFBA7': '\u06C1',
15677   '\uFBA8': '\u06C1',
15678   '\uFBA9': '\u06C1',
15679   '\uFBAA': '\u06BE',
15680   '\uFBAB': '\u06BE',
15681   '\uFBAC': '\u06BE',
15682   '\uFBAD': '\u06BE',
15683   '\uFBAE': '\u06D2',
15684   '\uFBAF': '\u06D2',
15685   '\uFBB0': '\u06D3',
15686   '\uFBB1': '\u06D3',
15687   '\uFBD3': '\u06AD',
15688   '\uFBD4': '\u06AD',
15689   '\uFBD5': '\u06AD',
15690   '\uFBD6': '\u06AD',
15691   '\uFBD7': '\u06C7',
15692   '\uFBD8': '\u06C7',
15693   '\uFBD9': '\u06C6',
15694   '\uFBDA': '\u06C6',
15695   '\uFBDB': '\u06C8',
15696   '\uFBDC': '\u06C8',
15697   '\uFBDD': '\u0677',
15698   '\uFBDE': '\u06CB',
15699   '\uFBDF': '\u06CB',
15700   '\uFBE0': '\u06C5',
15701   '\uFBE1': '\u06C5',
15702   '\uFBE2': '\u06C9',
15703   '\uFBE3': '\u06C9',
15704   '\uFBE4': '\u06D0',
15705   '\uFBE5': '\u06D0',
15706   '\uFBE6': '\u06D0',
15707   '\uFBE7': '\u06D0',
15708   '\uFBE8': '\u0649',
15709   '\uFBE9': '\u0649',
15710   '\uFBEA': '\u0626\u0627',
15711   '\uFBEB': '\u0626\u0627',
15712   '\uFBEC': '\u0626\u06D5',
15713   '\uFBED': '\u0626\u06D5',
15714   '\uFBEE': '\u0626\u0648',
15715   '\uFBEF': '\u0626\u0648',
15716   '\uFBF0': '\u0626\u06C7',
15717   '\uFBF1': '\u0626\u06C7',
15718   '\uFBF2': '\u0626\u06C6',
15719   '\uFBF3': '\u0626\u06C6',
15720   '\uFBF4': '\u0626\u06C8',
15721   '\uFBF5': '\u0626\u06C8',
15722   '\uFBF6': '\u0626\u06D0',
15723   '\uFBF7': '\u0626\u06D0',
15724   '\uFBF8': '\u0626\u06D0',
15725   '\uFBF9': '\u0626\u0649',
15726   '\uFBFA': '\u0626\u0649',
15727   '\uFBFB': '\u0626\u0649',
15728   '\uFBFC': '\u06CC',
15729   '\uFBFD': '\u06CC',
15730   '\uFBFE': '\u06CC',
15731   '\uFBFF': '\u06CC',
15732   '\uFC00': '\u0626\u062C',
15733   '\uFC01': '\u0626\u062D',
15734   '\uFC02': '\u0626\u0645',
15735   '\uFC03': '\u0626\u0649',
15736   '\uFC04': '\u0626\u064A',
15737   '\uFC05': '\u0628\u062C',
15738   '\uFC06': '\u0628\u062D',
15739   '\uFC07': '\u0628\u062E',
15740   '\uFC08': '\u0628\u0645',
15741   '\uFC09': '\u0628\u0649',
15742   '\uFC0A': '\u0628\u064A',
15743   '\uFC0B': '\u062A\u062C',
15744   '\uFC0C': '\u062A\u062D',
15745   '\uFC0D': '\u062A\u062E',
15746   '\uFC0E': '\u062A\u0645',
15747   '\uFC0F': '\u062A\u0649',
15748   '\uFC10': '\u062A\u064A',
15749   '\uFC11': '\u062B\u062C',
15750   '\uFC12': '\u062B\u0645',
15751   '\uFC13': '\u062B\u0649',
15752   '\uFC14': '\u062B\u064A',
15753   '\uFC15': '\u062C\u062D',
15754   '\uFC16': '\u062C\u0645',
15755   '\uFC17': '\u062D\u062C',
15756   '\uFC18': '\u062D\u0645',
15757   '\uFC19': '\u062E\u062C',
15758   '\uFC1A': '\u062E\u062D',
15759   '\uFC1B': '\u062E\u0645',
15760   '\uFC1C': '\u0633\u062C',
15761   '\uFC1D': '\u0633\u062D',
15762   '\uFC1E': '\u0633\u062E',
15763   '\uFC1F': '\u0633\u0645',
15764   '\uFC20': '\u0635\u062D',
15765   '\uFC21': '\u0635\u0645',
15766   '\uFC22': '\u0636\u062C',
15767   '\uFC23': '\u0636\u062D',
15768   '\uFC24': '\u0636\u062E',
15769   '\uFC25': '\u0636\u0645',
15770   '\uFC26': '\u0637\u062D',
15771   '\uFC27': '\u0637\u0645',
15772   '\uFC28': '\u0638\u0645',
15773   '\uFC29': '\u0639\u062C',
15774   '\uFC2A': '\u0639\u0645',
15775   '\uFC2B': '\u063A\u062C',
15776   '\uFC2C': '\u063A\u0645',
15777   '\uFC2D': '\u0641\u062C',
15778   '\uFC2E': '\u0641\u062D',
15779   '\uFC2F': '\u0641\u062E',
15780   '\uFC30': '\u0641\u0645',
15781   '\uFC31': '\u0641\u0649',
15782   '\uFC32': '\u0641\u064A',
15783   '\uFC33': '\u0642\u062D',
15784   '\uFC34': '\u0642\u0645',
15785   '\uFC35': '\u0642\u0649',
15786   '\uFC36': '\u0642\u064A',
15787   '\uFC37': '\u0643\u0627',
15788   '\uFC38': '\u0643\u062C',
15789   '\uFC39': '\u0643\u062D',
15790   '\uFC3A': '\u0643\u062E',
15791   '\uFC3B': '\u0643\u0644',
15792   '\uFC3C': '\u0643\u0645',
15793   '\uFC3D': '\u0643\u0649',
15794   '\uFC3E': '\u0643\u064A',
15795   '\uFC3F': '\u0644\u062C',
15796   '\uFC40': '\u0644\u062D',
15797   '\uFC41': '\u0644\u062E',
15798   '\uFC42': '\u0644\u0645',
15799   '\uFC43': '\u0644\u0649',
15800   '\uFC44': '\u0644\u064A',
15801   '\uFC45': '\u0645\u062C',
15802   '\uFC46': '\u0645\u062D',
15803   '\uFC47': '\u0645\u062E',
15804   '\uFC48': '\u0645\u0645',
15805   '\uFC49': '\u0645\u0649',
15806   '\uFC4A': '\u0645\u064A',
15807   '\uFC4B': '\u0646\u062C',
15808   '\uFC4C': '\u0646\u062D',
15809   '\uFC4D': '\u0646\u062E',
15810   '\uFC4E': '\u0646\u0645',
15811   '\uFC4F': '\u0646\u0649',
15812   '\uFC50': '\u0646\u064A',
15813   '\uFC51': '\u0647\u062C',
15814   '\uFC52': '\u0647\u0645',
15815   '\uFC53': '\u0647\u0649',
15816   '\uFC54': '\u0647\u064A',
15817   '\uFC55': '\u064A\u062C',
15818   '\uFC56': '\u064A\u062D',
15819   '\uFC57': '\u064A\u062E',
15820   '\uFC58': '\u064A\u0645',
15821   '\uFC59': '\u064A\u0649',
15822   '\uFC5A': '\u064A\u064A',
15823   '\uFC5B': '\u0630\u0670',
15824   '\uFC5C': '\u0631\u0670',
15825   '\uFC5D': '\u0649\u0670',
15826   '\uFC5E': '\u0020\u064C\u0651',
15827   '\uFC5F': '\u0020\u064D\u0651',
15828   '\uFC60': '\u0020\u064E\u0651',
15829   '\uFC61': '\u0020\u064F\u0651',
15830   '\uFC62': '\u0020\u0650\u0651',
15831   '\uFC63': '\u0020\u0651\u0670',
15832   '\uFC64': '\u0626\u0631',
15833   '\uFC65': '\u0626\u0632',
15834   '\uFC66': '\u0626\u0645',
15835   '\uFC67': '\u0626\u0646',
15836   '\uFC68': '\u0626\u0649',
15837   '\uFC69': '\u0626\u064A',
15838   '\uFC6A': '\u0628\u0631',
15839   '\uFC6B': '\u0628\u0632',
15840   '\uFC6C': '\u0628\u0645',
15841   '\uFC6D': '\u0628\u0646',
15842   '\uFC6E': '\u0628\u0649',
15843   '\uFC6F': '\u0628\u064A',
15844   '\uFC70': '\u062A\u0631',
15845   '\uFC71': '\u062A\u0632',
15846   '\uFC72': '\u062A\u0645',
15847   '\uFC73': '\u062A\u0646',
15848   '\uFC74': '\u062A\u0649',
15849   '\uFC75': '\u062A\u064A',
15850   '\uFC76': '\u062B\u0631',
15851   '\uFC77': '\u062B\u0632',
15852   '\uFC78': '\u062B\u0645',
15853   '\uFC79': '\u062B\u0646',
15854   '\uFC7A': '\u062B\u0649',
15855   '\uFC7B': '\u062B\u064A',
15856   '\uFC7C': '\u0641\u0649',
15857   '\uFC7D': '\u0641\u064A',
15858   '\uFC7E': '\u0642\u0649',
15859   '\uFC7F': '\u0642\u064A',
15860   '\uFC80': '\u0643\u0627',
15861   '\uFC81': '\u0643\u0644',
15862   '\uFC82': '\u0643\u0645',
15863   '\uFC83': '\u0643\u0649',
15864   '\uFC84': '\u0643\u064A',
15865   '\uFC85': '\u0644\u0645',
15866   '\uFC86': '\u0644\u0649',
15867   '\uFC87': '\u0644\u064A',
15868   '\uFC88': '\u0645\u0627',
15869   '\uFC89': '\u0645\u0645',
15870   '\uFC8A': '\u0646\u0631',
15871   '\uFC8B': '\u0646\u0632',
15872   '\uFC8C': '\u0646\u0645',
15873   '\uFC8D': '\u0646\u0646',
15874   '\uFC8E': '\u0646\u0649',
15875   '\uFC8F': '\u0646\u064A',
15876   '\uFC90': '\u0649\u0670',
15877   '\uFC91': '\u064A\u0631',
15878   '\uFC92': '\u064A\u0632',
15879   '\uFC93': '\u064A\u0645',
15880   '\uFC94': '\u064A\u0646',
15881   '\uFC95': '\u064A\u0649',
15882   '\uFC96': '\u064A\u064A',
15883   '\uFC97': '\u0626\u062C',
15884   '\uFC98': '\u0626\u062D',
15885   '\uFC99': '\u0626\u062E',
15886   '\uFC9A': '\u0626\u0645',
15887   '\uFC9B': '\u0626\u0647',
15888   '\uFC9C': '\u0628\u062C',
15889   '\uFC9D': '\u0628\u062D',
15890   '\uFC9E': '\u0628\u062E',
15891   '\uFC9F': '\u0628\u0645',
15892   '\uFCA0': '\u0628\u0647',
15893   '\uFCA1': '\u062A\u062C',
15894   '\uFCA2': '\u062A\u062D',
15895   '\uFCA3': '\u062A\u062E',
15896   '\uFCA4': '\u062A\u0645',
15897   '\uFCA5': '\u062A\u0647',
15898   '\uFCA6': '\u062B\u0645',
15899   '\uFCA7': '\u062C\u062D',
15900   '\uFCA8': '\u062C\u0645',
15901   '\uFCA9': '\u062D\u062C',
15902   '\uFCAA': '\u062D\u0645',
15903   '\uFCAB': '\u062E\u062C',
15904   '\uFCAC': '\u062E\u0645',
15905   '\uFCAD': '\u0633\u062C',
15906   '\uFCAE': '\u0633\u062D',
15907   '\uFCAF': '\u0633\u062E',
15908   '\uFCB0': '\u0633\u0645',
15909   '\uFCB1': '\u0635\u062D',
15910   '\uFCB2': '\u0635\u062E',
15911   '\uFCB3': '\u0635\u0645',
15912   '\uFCB4': '\u0636\u062C',
15913   '\uFCB5': '\u0636\u062D',
15914   '\uFCB6': '\u0636\u062E',
15915   '\uFCB7': '\u0636\u0645',
15916   '\uFCB8': '\u0637\u062D',
15917   '\uFCB9': '\u0638\u0645',
15918   '\uFCBA': '\u0639\u062C',
15919   '\uFCBB': '\u0639\u0645',
15920   '\uFCBC': '\u063A\u062C',
15921   '\uFCBD': '\u063A\u0645',
15922   '\uFCBE': '\u0641\u062C',
15923   '\uFCBF': '\u0641\u062D',
15924   '\uFCC0': '\u0641\u062E',
15925   '\uFCC1': '\u0641\u0645',
15926   '\uFCC2': '\u0642\u062D',
15927   '\uFCC3': '\u0642\u0645',
15928   '\uFCC4': '\u0643\u062C',
15929   '\uFCC5': '\u0643\u062D',
15930   '\uFCC6': '\u0643\u062E',
15931   '\uFCC7': '\u0643\u0644',
15932   '\uFCC8': '\u0643\u0645',
15933   '\uFCC9': '\u0644\u062C',
15934   '\uFCCA': '\u0644\u062D',
15935   '\uFCCB': '\u0644\u062E',
15936   '\uFCCC': '\u0644\u0645',
15937   '\uFCCD': '\u0644\u0647',
15938   '\uFCCE': '\u0645\u062C',
15939   '\uFCCF': '\u0645\u062D',
15940   '\uFCD0': '\u0645\u062E',
15941   '\uFCD1': '\u0645\u0645',
15942   '\uFCD2': '\u0646\u062C',
15943   '\uFCD3': '\u0646\u062D',
15944   '\uFCD4': '\u0646\u062E',
15945   '\uFCD5': '\u0646\u0645',
15946   '\uFCD6': '\u0646\u0647',
15947   '\uFCD7': '\u0647\u062C',
15948   '\uFCD8': '\u0647\u0645',
15949   '\uFCD9': '\u0647\u0670',
15950   '\uFCDA': '\u064A\u062C',
15951   '\uFCDB': '\u064A\u062D',
15952   '\uFCDC': '\u064A\u062E',
15953   '\uFCDD': '\u064A\u0645',
15954   '\uFCDE': '\u064A\u0647',
15955   '\uFCDF': '\u0626\u0645',
15956   '\uFCE0': '\u0626\u0647',
15957   '\uFCE1': '\u0628\u0645',
15958   '\uFCE2': '\u0628\u0647',
15959   '\uFCE3': '\u062A\u0645',
15960   '\uFCE4': '\u062A\u0647',
15961   '\uFCE5': '\u062B\u0645',
15962   '\uFCE6': '\u062B\u0647',
15963   '\uFCE7': '\u0633\u0645',
15964   '\uFCE8': '\u0633\u0647',
15965   '\uFCE9': '\u0634\u0645',
15966   '\uFCEA': '\u0634\u0647',
15967   '\uFCEB': '\u0643\u0644',
15968   '\uFCEC': '\u0643\u0645',
15969   '\uFCED': '\u0644\u0645',
15970   '\uFCEE': '\u0646\u0645',
15971   '\uFCEF': '\u0646\u0647',
15972   '\uFCF0': '\u064A\u0645',
15973   '\uFCF1': '\u064A\u0647',
15974   '\uFCF2': '\u0640\u064E\u0651',
15975   '\uFCF3': '\u0640\u064F\u0651',
15976   '\uFCF4': '\u0640\u0650\u0651',
15977   '\uFCF5': '\u0637\u0649',
15978   '\uFCF6': '\u0637\u064A',
15979   '\uFCF7': '\u0639\u0649',
15980   '\uFCF8': '\u0639\u064A',
15981   '\uFCF9': '\u063A\u0649',
15982   '\uFCFA': '\u063A\u064A',
15983   '\uFCFB': '\u0633\u0649',
15984   '\uFCFC': '\u0633\u064A',
15985   '\uFCFD': '\u0634\u0649',
15986   '\uFCFE': '\u0634\u064A',
15987   '\uFCFF': '\u062D\u0649',
15988   '\uFD00': '\u062D\u064A',
15989   '\uFD01': '\u062C\u0649',
15990   '\uFD02': '\u062C\u064A',
15991   '\uFD03': '\u062E\u0649',
15992   '\uFD04': '\u062E\u064A',
15993   '\uFD05': '\u0635\u0649',
15994   '\uFD06': '\u0635\u064A',
15995   '\uFD07': '\u0636\u0649',
15996   '\uFD08': '\u0636\u064A',
15997   '\uFD09': '\u0634\u062C',
15998   '\uFD0A': '\u0634\u062D',
15999   '\uFD0B': '\u0634\u062E',
16000   '\uFD0C': '\u0634\u0645',
16001   '\uFD0D': '\u0634\u0631',
16002   '\uFD0E': '\u0633\u0631',
16003   '\uFD0F': '\u0635\u0631',
16004   '\uFD10': '\u0636\u0631',
16005   '\uFD11': '\u0637\u0649',
16006   '\uFD12': '\u0637\u064A',
16007   '\uFD13': '\u0639\u0649',
16008   '\uFD14': '\u0639\u064A',
16009   '\uFD15': '\u063A\u0649',
16010   '\uFD16': '\u063A\u064A',
16011   '\uFD17': '\u0633\u0649',
16012   '\uFD18': '\u0633\u064A',
16013   '\uFD19': '\u0634\u0649',
16014   '\uFD1A': '\u0634\u064A',
16015   '\uFD1B': '\u062D\u0649',
16016   '\uFD1C': '\u062D\u064A',
16017   '\uFD1D': '\u062C\u0649',
16018   '\uFD1E': '\u062C\u064A',
16019   '\uFD1F': '\u062E\u0649',
16020   '\uFD20': '\u062E\u064A',
16021   '\uFD21': '\u0635\u0649',
16022   '\uFD22': '\u0635\u064A',
16023   '\uFD23': '\u0636\u0649',
16024   '\uFD24': '\u0636\u064A',
16025   '\uFD25': '\u0634\u062C',
16026   '\uFD26': '\u0634\u062D',
16027   '\uFD27': '\u0634\u062E',
16028   '\uFD28': '\u0634\u0645',
16029   '\uFD29': '\u0634\u0631',
16030   '\uFD2A': '\u0633\u0631',
16031   '\uFD2B': '\u0635\u0631',
16032   '\uFD2C': '\u0636\u0631',
16033   '\uFD2D': '\u0634\u062C',
16034   '\uFD2E': '\u0634\u062D',
16035   '\uFD2F': '\u0634\u062E',
16036   '\uFD30': '\u0634\u0645',
16037   '\uFD31': '\u0633\u0647',
16038   '\uFD32': '\u0634\u0647',
16039   '\uFD33': '\u0637\u0645',
16040   '\uFD34': '\u0633\u062C',
16041   '\uFD35': '\u0633\u062D',
16042   '\uFD36': '\u0633\u062E',
16043   '\uFD37': '\u0634\u062C',
16044   '\uFD38': '\u0634\u062D',
16045   '\uFD39': '\u0634\u062E',
16046   '\uFD3A': '\u0637\u0645',
16047   '\uFD3B': '\u0638\u0645',
16048   '\uFD3C': '\u0627\u064B',
16049   '\uFD3D': '\u0627\u064B',
16050   '\uFD50': '\u062A\u062C\u0645',
16051   '\uFD51': '\u062A\u062D\u062C',
16052   '\uFD52': '\u062A\u062D\u062C',
16053   '\uFD53': '\u062A\u062D\u0645',
16054   '\uFD54': '\u062A\u062E\u0645',
16055   '\uFD55': '\u062A\u0645\u062C',
16056   '\uFD56': '\u062A\u0645\u062D',
16057   '\uFD57': '\u062A\u0645\u062E',
16058   '\uFD58': '\u062C\u0645\u062D',
16059   '\uFD59': '\u062C\u0645\u062D',
16060   '\uFD5A': '\u062D\u0645\u064A',
16061   '\uFD5B': '\u062D\u0645\u0649',
16062   '\uFD5C': '\u0633\u062D\u062C',
16063   '\uFD5D': '\u0633\u062C\u062D',
16064   '\uFD5E': '\u0633\u062C\u0649',
16065   '\uFD5F': '\u0633\u0645\u062D',
16066   '\uFD60': '\u0633\u0645\u062D',
16067   '\uFD61': '\u0633\u0645\u062C',
16068   '\uFD62': '\u0633\u0645\u0645',
16069   '\uFD63': '\u0633\u0645\u0645',
16070   '\uFD64': '\u0635\u062D\u062D',
16071   '\uFD65': '\u0635\u062D\u062D',
16072   '\uFD66': '\u0635\u0645\u0645',
16073   '\uFD67': '\u0634\u062D\u0645',
16074   '\uFD68': '\u0634\u062D\u0645',
16075   '\uFD69': '\u0634\u062C\u064A',
16076   '\uFD6A': '\u0634\u0645\u062E',
16077   '\uFD6B': '\u0634\u0645\u062E',
16078   '\uFD6C': '\u0634\u0645\u0645',
16079   '\uFD6D': '\u0634\u0645\u0645',
16080   '\uFD6E': '\u0636\u062D\u0649',
16081   '\uFD6F': '\u0636\u062E\u0645',
16082   '\uFD70': '\u0636\u062E\u0645',
16083   '\uFD71': '\u0637\u0645\u062D',
16084   '\uFD72': '\u0637\u0645\u062D',
16085   '\uFD73': '\u0637\u0645\u0645',
16086   '\uFD74': '\u0637\u0645\u064A',
16087   '\uFD75': '\u0639\u062C\u0645',
16088   '\uFD76': '\u0639\u0645\u0645',
16089   '\uFD77': '\u0639\u0645\u0645',
16090   '\uFD78': '\u0639\u0645\u0649',
16091   '\uFD79': '\u063A\u0645\u0645',
16092   '\uFD7A': '\u063A\u0645\u064A',
16093   '\uFD7B': '\u063A\u0645\u0649',
16094   '\uFD7C': '\u0641\u062E\u0645',
16095   '\uFD7D': '\u0641\u062E\u0645',
16096   '\uFD7E': '\u0642\u0645\u062D',
16097   '\uFD7F': '\u0642\u0645\u0645',
16098   '\uFD80': '\u0644\u062D\u0645',
16099   '\uFD81': '\u0644\u062D\u064A',
16100   '\uFD82': '\u0644\u062D\u0649',
16101   '\uFD83': '\u0644\u062C\u062C',
16102   '\uFD84': '\u0644\u062C\u062C',
16103   '\uFD85': '\u0644\u062E\u0645',
16104   '\uFD86': '\u0644\u062E\u0645',
16105   '\uFD87': '\u0644\u0645\u062D',
16106   '\uFD88': '\u0644\u0645\u062D',
16107   '\uFD89': '\u0645\u062D\u062C',
16108   '\uFD8A': '\u0645\u062D\u0645',
16109   '\uFD8B': '\u0645\u062D\u064A',
16110   '\uFD8C': '\u0645\u062C\u062D',
16111   '\uFD8D': '\u0645\u062C\u0645',
16112   '\uFD8E': '\u0645\u062E\u062C',
16113   '\uFD8F': '\u0645\u062E\u0645',
16114   '\uFD92': '\u0645\u062C\u062E',
16115   '\uFD93': '\u0647\u0645\u062C',
16116   '\uFD94': '\u0647\u0645\u0645',
16117   '\uFD95': '\u0646\u062D\u0645',
16118   '\uFD96': '\u0646\u062D\u0649',
16119   '\uFD97': '\u0646\u062C\u0645',
16120   '\uFD98': '\u0646\u062C\u0645',
16121   '\uFD99': '\u0646\u062C\u0649',
16122   '\uFD9A': '\u0646\u0645\u064A',
16123   '\uFD9B': '\u0646\u0645\u0649',
16124   '\uFD9C': '\u064A\u0645\u0645',
16125   '\uFD9D': '\u064A\u0645\u0645',
16126   '\uFD9E': '\u0628\u062E\u064A',
16127   '\uFD9F': '\u062A\u062C\u064A',
16128   '\uFDA0': '\u062A\u062C\u0649',
16129   '\uFDA1': '\u062A\u062E\u064A',
16130   '\uFDA2': '\u062A\u062E\u0649',
16131   '\uFDA3': '\u062A\u0645\u064A',
16132   '\uFDA4': '\u062A\u0645\u0649',
16133   '\uFDA5': '\u062C\u0645\u064A',
16134   '\uFDA6': '\u062C\u062D\u0649',
16135   '\uFDA7': '\u062C\u0645\u0649',
16136   '\uFDA8': '\u0633\u062E\u0649',
16137   '\uFDA9': '\u0635\u062D\u064A',
16138   '\uFDAA': '\u0634\u062D\u064A',
16139   '\uFDAB': '\u0636\u062D\u064A',
16140   '\uFDAC': '\u0644\u062C\u064A',
16141   '\uFDAD': '\u0644\u0645\u064A',
16142   '\uFDAE': '\u064A\u062D\u064A',
16143   '\uFDAF': '\u064A\u062C\u064A',
16144   '\uFDB0': '\u064A\u0645\u064A',
16145   '\uFDB1': '\u0645\u0645\u064A',
16146   '\uFDB2': '\u0642\u0645\u064A',
16147   '\uFDB3': '\u0646\u062D\u064A',
16148   '\uFDB4': '\u0642\u0645\u062D',
16149   '\uFDB5': '\u0644\u062D\u0645',
16150   '\uFDB6': '\u0639\u0645\u064A',
16151   '\uFDB7': '\u0643\u0645\u064A',
16152   '\uFDB8': '\u0646\u062C\u062D',
16153   '\uFDB9': '\u0645\u062E\u064A',
16154   '\uFDBA': '\u0644\u062C\u0645',
16155   '\uFDBB': '\u0643\u0645\u0645',
16156   '\uFDBC': '\u0644\u062C\u0645',
16157   '\uFDBD': '\u0646\u062C\u062D',
16158   '\uFDBE': '\u062C\u062D\u064A',
16159   '\uFDBF': '\u062D\u062C\u064A',
16160   '\uFDC0': '\u0645\u062C\u064A',
16161   '\uFDC1': '\u0641\u0645\u064A',
16162   '\uFDC2': '\u0628\u062D\u064A',
16163   '\uFDC3': '\u0643\u0645\u0645',
16164   '\uFDC4': '\u0639\u062C\u0645',
16165   '\uFDC5': '\u0635\u0645\u0645',
16166   '\uFDC6': '\u0633\u062E\u064A',
16167   '\uFDC7': '\u0646\u062C\u064A',
16168   '\uFE49': '\u203E',
16169   '\uFE4A': '\u203E',
16170   '\uFE4B': '\u203E',
16171   '\uFE4C': '\u203E',
16172   '\uFE4D': '\u005F',
16173   '\uFE4E': '\u005F',
16174   '\uFE4F': '\u005F',
16175   '\uFE80': '\u0621',
16176   '\uFE81': '\u0622',
16177   '\uFE82': '\u0622',
16178   '\uFE83': '\u0623',
16179   '\uFE84': '\u0623',
16180   '\uFE85': '\u0624',
16181   '\uFE86': '\u0624',
16182   '\uFE87': '\u0625',
16183   '\uFE88': '\u0625',
16184   '\uFE89': '\u0626',
16185   '\uFE8A': '\u0626',
16186   '\uFE8B': '\u0626',
16187   '\uFE8C': '\u0626',
16188   '\uFE8D': '\u0627',
16189   '\uFE8E': '\u0627',
16190   '\uFE8F': '\u0628',
16191   '\uFE90': '\u0628',
16192   '\uFE91': '\u0628',
16193   '\uFE92': '\u0628',
16194   '\uFE93': '\u0629',
16195   '\uFE94': '\u0629',
16196   '\uFE95': '\u062A',
16197   '\uFE96': '\u062A',
16198   '\uFE97': '\u062A',
16199   '\uFE98': '\u062A',
16200   '\uFE99': '\u062B',
16201   '\uFE9A': '\u062B',
16202   '\uFE9B': '\u062B',
16203   '\uFE9C': '\u062B',
16204   '\uFE9D': '\u062C',
16205   '\uFE9E': '\u062C',
16206   '\uFE9F': '\u062C',
16207   '\uFEA0': '\u062C',
16208   '\uFEA1': '\u062D',
16209   '\uFEA2': '\u062D',
16210   '\uFEA3': '\u062D',
16211   '\uFEA4': '\u062D',
16212   '\uFEA5': '\u062E',
16213   '\uFEA6': '\u062E',
16214   '\uFEA7': '\u062E',
16215   '\uFEA8': '\u062E',
16216   '\uFEA9': '\u062F',
16217   '\uFEAA': '\u062F',
16218   '\uFEAB': '\u0630',
16219   '\uFEAC': '\u0630',
16220   '\uFEAD': '\u0631',
16221   '\uFEAE': '\u0631',
16222   '\uFEAF': '\u0632',
16223   '\uFEB0': '\u0632',
16224   '\uFEB1': '\u0633',
16225   '\uFEB2': '\u0633',
16226   '\uFEB3': '\u0633',
16227   '\uFEB4': '\u0633',
16228   '\uFEB5': '\u0634',
16229   '\uFEB6': '\u0634',
16230   '\uFEB7': '\u0634',
16231   '\uFEB8': '\u0634',
16232   '\uFEB9': '\u0635',
16233   '\uFEBA': '\u0635',
16234   '\uFEBB': '\u0635',
16235   '\uFEBC': '\u0635',
16236   '\uFEBD': '\u0636',
16237   '\uFEBE': '\u0636',
16238   '\uFEBF': '\u0636',
16239   '\uFEC0': '\u0636',
16240   '\uFEC1': '\u0637',
16241   '\uFEC2': '\u0637',
16242   '\uFEC3': '\u0637',
16243   '\uFEC4': '\u0637',
16244   '\uFEC5': '\u0638',
16245   '\uFEC6': '\u0638',
16246   '\uFEC7': '\u0638',
16247   '\uFEC8': '\u0638',
16248   '\uFEC9': '\u0639',
16249   '\uFECA': '\u0639',
16250   '\uFECB': '\u0639',
16251   '\uFECC': '\u0639',
16252   '\uFECD': '\u063A',
16253   '\uFECE': '\u063A',
16254   '\uFECF': '\u063A',
16255   '\uFED0': '\u063A',
16256   '\uFED1': '\u0641',
16257   '\uFED2': '\u0641',
16258   '\uFED3': '\u0641',
16259   '\uFED4': '\u0641',
16260   '\uFED5': '\u0642',
16261   '\uFED6': '\u0642',
16262   '\uFED7': '\u0642',
16263   '\uFED8': '\u0642',
16264   '\uFED9': '\u0643',
16265   '\uFEDA': '\u0643',
16266   '\uFEDB': '\u0643',
16267   '\uFEDC': '\u0643',
16268   '\uFEDD': '\u0644',
16269   '\uFEDE': '\u0644',
16270   '\uFEDF': '\u0644',
16271   '\uFEE0': '\u0644',
16272   '\uFEE1': '\u0645',
16273   '\uFEE2': '\u0645',
16274   '\uFEE3': '\u0645',
16275   '\uFEE4': '\u0645',
16276   '\uFEE5': '\u0646',
16277   '\uFEE6': '\u0646',
16278   '\uFEE7': '\u0646',
16279   '\uFEE8': '\u0646',
16280   '\uFEE9': '\u0647',
16281   '\uFEEA': '\u0647',
16282   '\uFEEB': '\u0647',
16283   '\uFEEC': '\u0647',
16284   '\uFEED': '\u0648',
16285   '\uFEEE': '\u0648',
16286   '\uFEEF': '\u0649',
16287   '\uFEF0': '\u0649',
16288   '\uFEF1': '\u064A',
16289   '\uFEF2': '\u064A',
16290   '\uFEF3': '\u064A',
16291   '\uFEF4': '\u064A',
16292   '\uFEF5': '\u0644\u0622',
16293   '\uFEF6': '\u0644\u0622',
16294   '\uFEF7': '\u0644\u0623',
16295   '\uFEF8': '\u0644\u0623',
16296   '\uFEF9': '\u0644\u0625',
16297   '\uFEFA': '\u0644\u0625',
16298   '\uFEFB': '\u0644\u0627',
16299   '\uFEFC': '\u0644\u0627'
16300 };
16301
16302 function reverseIfRtl(chars) {
16303   var charsLength = chars.length;
16304   //reverse an arabic ligature
16305   if (charsLength <= 1 || !isRTLRangeFor(chars.charCodeAt(0))) {
16306     return chars;
16307   }
16308   var s = '';
16309   for (var ii = charsLength - 1; ii >= 0; ii--) {
16310     s += chars[ii];
16311   }
16312   return s;
16313 }
16314
16315 function adjustWidths(properties) {
16316   if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) {
16317     return;
16318   }
16319   // adjusting width to fontMatrix scale
16320   var scale = 0.001 / properties.fontMatrix[0];
16321   var glyphsWidths = properties.widths;
16322   for (var glyph in glyphsWidths) {
16323     glyphsWidths[glyph] *= scale;
16324   }
16325   properties.defaultWidth *= scale;
16326 }
16327
16328 function getFontType(type, subtype) {
16329   switch (type) {
16330     case 'Type1':
16331       return subtype === 'Type1C' ? FontType.TYPE1C : FontType.TYPE1;
16332     case 'CIDFontType0':
16333       return subtype === 'CIDFontType0C' ? FontType.CIDFONTTYPE0C :
16334         FontType.CIDFONTTYPE0;
16335     case 'OpenType':
16336       return FontType.OPENTYPE;
16337     case 'TrueType':
16338       return FontType.TRUETYPE;
16339     case 'CIDFontType2':
16340       return FontType.CIDFONTTYPE2;
16341     case 'MMType1':
16342       return FontType.MMTYPE1;
16343     case 'Type0':
16344       return FontType.TYPE0;
16345     default:
16346       return FontType.UNKNOWN;
16347   }
16348 }
16349
16350 var Glyph = (function GlyphClosure() {
16351   function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId) {
16352     this.fontChar = fontChar;
16353     this.unicode = unicode;
16354     this.accent = accent;
16355     this.width = width;
16356     this.vmetric = vmetric;
16357     this.operatorListId = operatorListId;
16358   }
16359
16360   Glyph.prototype.matchesForCache =
16361       function(fontChar, unicode, accent, width, vmetric, operatorListId) {
16362     return this.fontChar === fontChar &&
16363            this.unicode === unicode &&
16364            this.accent === accent &&
16365            this.width === width &&
16366            this.vmetric === vmetric &&
16367            this.operatorListId === operatorListId;
16368   };
16369
16370   return Glyph;
16371 })();
16372
16373 var ToUnicodeMap = (function ToUnicodeMapClosure() {
16374   function ToUnicodeMap(cmap) {
16375     // The elements of this._map can be integers or strings, depending on how
16376     // |cmap| was created.
16377     this._map = cmap;
16378   }
16379
16380   ToUnicodeMap.prototype = {
16381     get length() {
16382       return this._map.length;
16383     },
16384
16385     forEach: function(callback) {
16386       for (var charCode in this._map) {
16387         callback(charCode, this._map[charCode].charCodeAt(0));
16388       }
16389     },
16390
16391     has: function(i) {
16392       return this._map[i] !== undefined;
16393     },
16394
16395     get: function(i) {
16396       return this._map[i];
16397     },
16398
16399     charCodeOf: function(v) {
16400       return this._map.indexOf(v);
16401     }
16402   };
16403
16404   return ToUnicodeMap;
16405 })();
16406
16407 var IdentityToUnicodeMap = (function IdentityToUnicodeMapClosure() {
16408   function IdentityToUnicodeMap(firstChar, lastChar) {
16409     this.firstChar = firstChar;
16410     this.lastChar = lastChar;
16411   }
16412
16413   IdentityToUnicodeMap.prototype = {
16414     get length() {
16415       return (this.lastChar + 1) - this.firstChar;
16416     },
16417
16418     forEach: function (callback) {
16419       for (var i = this.firstChar, ii = this.lastChar; i <= ii; i++) {
16420         callback(i, i);
16421       }
16422     },
16423
16424     has: function (i) {
16425       return this.firstChar <= i && i <= this.lastChar;
16426     },
16427
16428     get: function (i) {
16429       if (this.firstChar <= i && i <= this.lastChar) {
16430         return String.fromCharCode(i);
16431       }
16432       return undefined;
16433     },
16434
16435     charCodeOf: function (v) {
16436       error('should not call .charCodeOf');
16437     }
16438   };
16439
16440   return IdentityToUnicodeMap;
16441 })();
16442
16443 var OpenTypeFileBuilder = (function OpenTypeFileBuilderClosure() {
16444   function writeInt16(dest, offset, num) {
16445     dest[offset] = (num >> 8) & 0xFF;
16446     dest[offset + 1] = num & 0xFF;
16447   }
16448
16449   function writeInt32(dest, offset, num) {
16450     dest[offset] = (num >> 24) & 0xFF;
16451     dest[offset + 1] = (num >> 16) & 0xFF;
16452     dest[offset + 2] = (num >> 8) & 0xFF;
16453     dest[offset + 3] = num & 0xFF;
16454   }
16455
16456   function writeData(dest, offset, data) {
16457     var i, ii;
16458     if (data instanceof Uint8Array) {
16459       dest.set(data, offset);
16460     } else if (typeof data === 'string') {
16461       for (i = 0, ii = data.length; i < ii; i++) {
16462         dest[offset++] = data.charCodeAt(i) & 0xFF;
16463       }
16464     } else {
16465       // treating everything else as array
16466       for (i = 0, ii = data.length; i < ii; i++) {
16467         dest[offset++] = data[i] & 0xFF;
16468       }
16469     }
16470   }
16471
16472   function OpenTypeFileBuilder(sfnt) {
16473     this.sfnt = sfnt;
16474     this.tables = Object.create(null);
16475   }
16476
16477   OpenTypeFileBuilder.getSearchParams =
16478       function OpenTypeFileBuilder_getSearchParams(entriesCount, entrySize) {
16479     var maxPower2 = 1, log2 = 0;
16480     while ((maxPower2 ^ entriesCount) > maxPower2) {
16481       maxPower2 <<= 1;
16482       log2++;
16483     }
16484     var searchRange = maxPower2 * entrySize;
16485     return {
16486       range: searchRange,
16487       entry: log2,
16488       rangeShift: entrySize * entriesCount - searchRange
16489     };
16490   };
16491
16492   var OTF_HEADER_SIZE = 12;
16493   var OTF_TABLE_ENTRY_SIZE = 16;
16494
16495   OpenTypeFileBuilder.prototype = {
16496     toArray: function OpenTypeFileBuilder_toArray() {
16497       var sfnt = this.sfnt;
16498
16499       // Tables needs to be written by ascendant alphabetic order
16500       var tables = this.tables;
16501       var tablesNames = Object.keys(tables);
16502       tablesNames.sort();
16503       var numTables = tablesNames.length;
16504
16505       var i, j, jj, table, tableName;
16506       // layout the tables data
16507       var offset = OTF_HEADER_SIZE + numTables * OTF_TABLE_ENTRY_SIZE;
16508       var tableOffsets = [offset];
16509       for (i = 0; i < numTables; i++) {
16510         table = tables[tablesNames[i]];
16511         var paddedLength = ((table.length + 3) & ~3) >>> 0;
16512         offset += paddedLength;
16513         tableOffsets.push(offset);
16514       }
16515
16516       var file = new Uint8Array(offset);
16517       // write the table data first (mostly for checksum)
16518       for (i = 0; i < numTables; i++) {
16519         table = tables[tablesNames[i]];
16520         writeData(file, tableOffsets[i], table);
16521       }
16522
16523       // sfnt version (4 bytes)
16524       if (sfnt === 'true') {
16525         // Windows hates the Mac TrueType sfnt version number
16526         sfnt = string32(0x00010000);
16527       }
16528       file[0] = sfnt.charCodeAt(0) & 0xFF;
16529       file[1] = sfnt.charCodeAt(1) & 0xFF;
16530       file[2] = sfnt.charCodeAt(2) & 0xFF;
16531       file[3] = sfnt.charCodeAt(3) & 0xFF;
16532
16533       // numTables (2 bytes)
16534       writeInt16(file, 4, numTables);
16535
16536       var searchParams = OpenTypeFileBuilder.getSearchParams(numTables, 16);
16537
16538       // searchRange (2 bytes)
16539       writeInt16(file, 6, searchParams.range);
16540       // entrySelector (2 bytes)
16541       writeInt16(file, 8, searchParams.entry);
16542       // rangeShift (2 bytes)
16543       writeInt16(file, 10, searchParams.rangeShift);
16544
16545       offset = OTF_HEADER_SIZE;
16546       // writing table entries
16547       for (i = 0; i < numTables; i++) {
16548         tableName = tablesNames[i];
16549         file[offset] = tableName.charCodeAt(0) & 0xFF;
16550         file[offset + 1] = tableName.charCodeAt(1) & 0xFF;
16551         file[offset + 2] = tableName.charCodeAt(2) & 0xFF;
16552         file[offset + 3] = tableName.charCodeAt(3) & 0xFF;
16553
16554         // checksum
16555         var checksum = 0;
16556         for (j = tableOffsets[i], jj = tableOffsets[i + 1]; j < jj; j += 4) {
16557           var quad = (file[j] << 24) + (file[j + 1] << 16) +
16558                      (file[j + 2] << 8) + file[j + 3];
16559           checksum = (checksum + quad) | 0;
16560         }
16561         writeInt32(file, offset + 4, checksum);
16562
16563         // offset
16564         writeInt32(file, offset + 8, tableOffsets[i]);
16565         // length
16566         writeInt32(file, offset + 12, tables[tableName].length);
16567
16568         offset += OTF_TABLE_ENTRY_SIZE;
16569       }
16570       return file;
16571     },
16572
16573     addTable: function OpenTypeFileBuilder_addTable(tag, data) {
16574       if (tag in this.tables) {
16575         throw new Error('Table ' + tag + ' already exists');
16576       }
16577       this.tables[tag] = data;
16578     }
16579   };
16580
16581   return OpenTypeFileBuilder;
16582 })();
16583
16584 /**
16585  * 'Font' is the class the outside world should use, it encapsulate all the font
16586  * decoding logics whatever type it is (assuming the font type is supported).
16587  *
16588  * For example to read a Type1 font and to attach it to the document:
16589  *   var type1Font = new Font("MyFontName", binaryFile, propertiesObject);
16590  *   type1Font.bind();
16591  */
16592 var Font = (function FontClosure() {
16593   function Font(name, file, properties) {
16594     var charCode, glyphName, fontChar;
16595
16596     this.name = name;
16597     this.loadedName = properties.loadedName;
16598     this.isType3Font = properties.isType3Font;
16599     this.sizes = [];
16600
16601     this.glyphCache = {};
16602
16603     var names = name.split('+');
16604     names = names.length > 1 ? names[1] : names[0];
16605     names = names.split(/[-,_]/g)[0];
16606     this.isSerifFont = !!(properties.flags & FontFlags.Serif);
16607     this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
16608     this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
16609
16610     var type = properties.type;
16611     var subtype = properties.subtype;
16612     this.type = type;
16613
16614     this.fallbackName = (this.isMonospace ? 'monospace' :
16615                          (this.isSerifFont ? 'serif' : 'sans-serif'));
16616
16617     this.differences = properties.differences;
16618     this.widths = properties.widths;
16619     this.defaultWidth = properties.defaultWidth;
16620     this.composite = properties.composite;
16621     this.wideChars = properties.wideChars;
16622     this.cMap = properties.cMap;
16623     this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS;
16624     this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS;
16625     this.fontMatrix = properties.fontMatrix;
16626     this.bbox = properties.bbox;
16627
16628     this.toUnicode = properties.toUnicode = this.buildToUnicode(properties);
16629
16630     this.toFontChar = [];
16631
16632     if (properties.type === 'Type3') {
16633       for (charCode = 0; charCode < 256; charCode++) {
16634         this.toFontChar[charCode] = (this.differences[charCode] ||
16635                                      properties.defaultEncoding[charCode]);
16636       }
16637       this.fontType = FontType.TYPE3;
16638       return;
16639     }
16640
16641     this.cidEncoding = properties.cidEncoding;
16642     this.vertical = properties.vertical;
16643     if (this.vertical) {
16644       this.vmetrics = properties.vmetrics;
16645       this.defaultVMetrics = properties.defaultVMetrics;
16646     }
16647
16648     if (!file || file.isEmpty) {
16649       if (file) {
16650         // Some bad PDF generators will include empty font files,
16651         // attempting to recover by assuming that no file exists.
16652         warn('Font file is empty in "' + name + '" (' + this.loadedName + ')');
16653       }
16654
16655       this.missingFile = true;
16656       // The file data is not specified. Trying to fix the font name
16657       // to be used with the canvas.font.
16658       var fontName = name.replace(/[,_]/g, '-');
16659       var isStandardFont = !!stdFontMap[fontName] ||
16660         !!(nonStdFontMap[fontName] && stdFontMap[nonStdFontMap[fontName]]);
16661       fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
16662
16663       this.bold = (fontName.search(/bold/gi) !== -1);
16664       this.italic = ((fontName.search(/oblique/gi) !== -1) ||
16665                      (fontName.search(/italic/gi) !== -1));
16666
16667       // Use 'name' instead of 'fontName' here because the original
16668       // name ArialBlack for example will be replaced by Helvetica.
16669       this.black = (name.search(/Black/g) !== -1);
16670
16671       // if at least one width is present, remeasure all chars when exists
16672       this.remeasure = Object.keys(this.widths).length > 0;
16673       if (isStandardFont && type === 'CIDFontType2' &&
16674           properties.cidEncoding.indexOf('Identity-') === 0) {
16675         // Standard fonts might be embedded as CID font without glyph mapping.
16676         // Building one based on GlyphMapForStandardFonts.
16677         var map = [];
16678         for (var code in GlyphMapForStandardFonts) {
16679           map[+code] = GlyphMapForStandardFonts[code];
16680         }
16681         var isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap;
16682         if (!isIdentityUnicode) {
16683           this.toUnicode.forEach(function(charCode, unicodeCharCode) {
16684             map[+charCode] = unicodeCharCode;
16685           });
16686         }
16687         this.toFontChar = map;
16688         this.toUnicode = new ToUnicodeMap(map);
16689       } else if (/Symbol/i.test(fontName)) {
16690         var symbols = Encodings.SymbolSetEncoding;
16691         for (charCode in symbols) {
16692           fontChar = GlyphsUnicode[symbols[charCode]];
16693           if (!fontChar) {
16694             continue;
16695           }
16696           this.toFontChar[charCode] = fontChar;
16697         }
16698         for (charCode in properties.differences) {
16699           fontChar = GlyphsUnicode[properties.differences[charCode]];
16700           if (!fontChar) {
16701             continue;
16702           }
16703           this.toFontChar[charCode] = fontChar;
16704         }
16705       } else if (/Dingbats/i.test(fontName)) {
16706         if (/Wingdings/i.test(name)) {
16707           warn('Wingdings font without embedded font file, ' +
16708                'falling back to the ZapfDingbats encoding.');
16709         }
16710         var dingbats = Encodings.ZapfDingbatsEncoding;
16711         for (charCode in dingbats) {
16712           fontChar = DingbatsGlyphsUnicode[dingbats[charCode]];
16713           if (!fontChar) {
16714             continue;
16715           }
16716           this.toFontChar[charCode] = fontChar;
16717         }
16718         for (charCode in properties.differences) {
16719           fontChar = DingbatsGlyphsUnicode[properties.differences[charCode]];
16720           if (!fontChar) {
16721             continue;
16722           }
16723           this.toFontChar[charCode] = fontChar;
16724         }
16725       } else if (isStandardFont) {
16726         this.toFontChar = [];
16727         for (charCode in properties.defaultEncoding) {
16728           glyphName = (properties.differences[charCode] ||
16729                        properties.defaultEncoding[charCode]);
16730           this.toFontChar[charCode] = GlyphsUnicode[glyphName];
16731         }
16732       } else {
16733         var unicodeCharCode, notCidFont = (type.indexOf('CIDFontType') === -1);
16734         this.toUnicode.forEach(function(charCode, unicodeCharCode) {
16735           if (notCidFont) {
16736             glyphName = (properties.differences[charCode] ||
16737                          properties.defaultEncoding[charCode]);
16738             unicodeCharCode = (GlyphsUnicode[glyphName] || unicodeCharCode);
16739           }
16740           this.toFontChar[charCode] = unicodeCharCode;
16741         }.bind(this));
16742       }
16743       this.loadedName = fontName.split('-')[0];
16744       this.loading = false;
16745       this.fontType = getFontType(type, subtype);
16746       return;
16747     }
16748
16749     // Some fonts might use wrong font types for Type1C or CIDFontType0C
16750     if (subtype === 'Type1C' && (type !== 'Type1' && type !== 'MMType1')) {
16751       // Some TrueType fonts by mistake claim Type1C
16752       if (isTrueTypeFile(file)) {
16753         subtype = 'TrueType';
16754       } else {
16755         type = 'Type1';
16756       }
16757     }
16758     if (subtype === 'CIDFontType0C' && type !== 'CIDFontType0') {
16759       type = 'CIDFontType0';
16760     }
16761     if (subtype === 'OpenType') {
16762       type = 'OpenType';
16763     }
16764     // Some CIDFontType0C fonts by mistake claim CIDFontType0.
16765     if (type === 'CIDFontType0') {
16766       subtype = isType1File(file) ? 'CIDFontType0' : 'CIDFontType0C';
16767     }
16768
16769     var data;
16770     switch (type) {
16771       case 'MMType1':
16772         info('MMType1 font (' + name + '), falling back to Type1.');
16773         /* falls through */
16774       case 'Type1':
16775       case 'CIDFontType0':
16776         this.mimetype = 'font/opentype';
16777
16778         var cff = (subtype === 'Type1C' || subtype === 'CIDFontType0C') ?
16779           new CFFFont(file, properties) : new Type1Font(name, file, properties);
16780
16781         adjustWidths(properties);
16782
16783         // Wrap the CFF data inside an OTF font file
16784         data = this.convert(name, cff, properties);
16785         break;
16786
16787       case 'OpenType':
16788       case 'TrueType':
16789       case 'CIDFontType2':
16790         this.mimetype = 'font/opentype';
16791
16792         // Repair the TrueType file. It is can be damaged in the point of
16793         // view of the sanitizer
16794         data = this.checkAndRepair(name, file, properties);
16795         if (this.isOpenType) {
16796           type = 'OpenType';
16797         }
16798         break;
16799
16800       default:
16801         error('Font ' + type + ' is not supported');
16802         break;
16803     }
16804
16805     this.data = data;
16806     this.fontType = getFontType(type, subtype);
16807
16808     // Transfer some properties again that could change during font conversion
16809     this.fontMatrix = properties.fontMatrix;
16810     this.widths = properties.widths;
16811     this.defaultWidth = properties.defaultWidth;
16812     this.encoding = properties.baseEncoding;
16813     this.seacMap = properties.seacMap;
16814
16815     this.loading = true;
16816   }
16817
16818   Font.getFontID = (function () {
16819     var ID = 1;
16820     return function Font_getFontID() {
16821       return String(ID++);
16822     };
16823   })();
16824
16825   function int16(b0, b1) {
16826     return (b0 << 8) + b1;
16827   }
16828
16829   function int32(b0, b1, b2, b3) {
16830     return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
16831   }
16832
16833   function string16(value) {
16834     return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
16835   }
16836
16837   function safeString16(value) {
16838     // clamp value to the 16-bit int range
16839     value = (value > 0x7FFF ? 0x7FFF : (value < -0x8000 ? -0x8000 : value));
16840     return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
16841   }
16842
16843   function isTrueTypeFile(file) {
16844     var header = file.peekBytes(4);
16845     return readUint32(header, 0) === 0x00010000;
16846   }
16847
16848   function isType1File(file) {
16849     var header = file.peekBytes(2);
16850     // All Type1 font programs must begin with the comment '%!' (0x25 + 0x21).
16851     if (header[0] === 0x25 && header[1] === 0x21) {
16852       return true;
16853     }
16854     // ... obviously some fonts violate that part of the specification,
16855     // please refer to the comment in |Type1Font| below.
16856     if (header[0] === 0x80 && header[1] === 0x01) { // pfb file header.
16857       return true;
16858     }
16859     return false;
16860   }
16861
16862   /**
16863    * Helper function for |adjustMapping|.
16864    * @return {boolean}
16865    */
16866   function isProblematicUnicodeLocation(code) {
16867     if (code <= 0x1F) { // Control chars
16868       return true;
16869     }
16870     if (code >= 0x80 && code <= 0x9F) { // Control chars
16871       return true;
16872     }
16873     if ((code >= 0x2000 && code <= 0x200F) || // General punctuation chars
16874         (code >= 0x2028 && code <= 0x202F) ||
16875         (code >= 0x2060 && code <= 0x206F)) {
16876       return true;
16877     }
16878     if (code >= 0xFFF0 && code <= 0xFFFF) { // Specials Unicode block
16879       return true;
16880     }
16881     switch (code) {
16882       case 0x7F: // Control char
16883       case 0xA0: // Non breaking space
16884       case 0xAD: // Soft hyphen
16885       case 0x0E33: // Thai character SARA AM
16886       case 0x2011: // Non breaking hyphen
16887       case 0x205F: // Medium mathematical space
16888       case 0x25CC: // Dotted circle (combining mark)
16889         return true;
16890     }
16891     return false;
16892   }
16893
16894   /**
16895    * Rebuilds the char code to glyph ID map by trying to replace the char codes
16896    * with their unicode value. It also moves char codes that are in known
16897    * problematic locations.
16898    * @return {Object} Two properties:
16899    * 'toFontChar' - maps original char codes(the value that will be read
16900    * from commands such as show text) to the char codes that will be used in the
16901    * font that we build
16902    * 'charCodeToGlyphId' - maps the new font char codes to glyph ids
16903    */
16904   function adjustMapping(charCodeToGlyphId, properties) {
16905     var toUnicode = properties.toUnicode;
16906     var isSymbolic = !!(properties.flags & FontFlags.Symbolic);
16907     var isIdentityUnicode =
16908       properties.toUnicode instanceof IdentityToUnicodeMap;
16909     var newMap = Object.create(null);
16910     var toFontChar = [];
16911     var usedFontCharCodes = [];
16912     var nextAvailableFontCharCode = PRIVATE_USE_OFFSET_START;
16913     for (var originalCharCode in charCodeToGlyphId) {
16914       originalCharCode |= 0;
16915       var glyphId = charCodeToGlyphId[originalCharCode];
16916       var fontCharCode = originalCharCode;
16917       // First try to map the value to a unicode position if a non identity map
16918       // was created.
16919       if (!isIdentityUnicode && toUnicode.has(originalCharCode)) {
16920         var unicode = toUnicode.get(fontCharCode);
16921         // TODO: Try to map ligatures to the correct spot.
16922         if (unicode.length === 1) {
16923           fontCharCode = unicode.charCodeAt(0);
16924         }
16925       }
16926       // Try to move control characters, special characters and already mapped
16927       // characters to the private use area since they will not be drawn by
16928       // canvas if left in their current position. Also, move characters if the
16929       // font was symbolic and there is only an identity unicode map since the
16930       // characters probably aren't in the correct position (fixes an issue
16931       // with firefox and thuluthfont).
16932       if ((usedFontCharCodes[fontCharCode] !== undefined ||
16933            isProblematicUnicodeLocation(fontCharCode) ||
16934            (isSymbolic && isIdentityUnicode)) &&
16935           nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END) { // Room left.
16936         // Loop to try and find a free spot in the private use area.
16937         do {
16938           fontCharCode = nextAvailableFontCharCode++;
16939
16940           if (SKIP_PRIVATE_USE_RANGE_F000_TO_F01F && fontCharCode === 0xF000) {
16941             fontCharCode = 0xF020;
16942             nextAvailableFontCharCode = fontCharCode + 1;
16943           }
16944
16945         } while (usedFontCharCodes[fontCharCode] !== undefined &&
16946                  nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END);
16947       }
16948
16949       newMap[fontCharCode] = glyphId;
16950       toFontChar[originalCharCode] = fontCharCode;
16951       usedFontCharCodes[fontCharCode] = true;
16952     }
16953     return {
16954       toFontChar: toFontChar,
16955       charCodeToGlyphId: newMap,
16956       nextAvailableFontCharCode: nextAvailableFontCharCode
16957     };
16958   }
16959
16960   function getRanges(glyphs) {
16961     // Array.sort() sorts by characters, not numerically, so convert to an
16962     // array of characters.
16963     var codes = [];
16964     for (var charCode in glyphs) {
16965       codes.push({ fontCharCode: charCode | 0, glyphId: glyphs[charCode] });
16966     }
16967     codes.sort(function fontGetRangesSort(a, b) {
16968       return a.fontCharCode - b.fontCharCode;
16969     });
16970
16971     // Split the sorted codes into ranges.
16972     var ranges = [];
16973     var length = codes.length;
16974     for (var n = 0; n < length; ) {
16975       var start = codes[n].fontCharCode;
16976       var codeIndices = [codes[n].glyphId];
16977       ++n;
16978       var end = start;
16979       while (n < length && end + 1 === codes[n].fontCharCode) {
16980         codeIndices.push(codes[n].glyphId);
16981         ++end;
16982         ++n;
16983         if (end === 0xFFFF) {
16984           break;
16985         }
16986       }
16987       ranges.push([start, end, codeIndices]);
16988     }
16989
16990     return ranges;
16991   }
16992
16993   function createCmapTable(glyphs) {
16994     var ranges = getRanges(glyphs);
16995     var numTables = ranges[ranges.length - 1][1] > 0xFFFF ? 2 : 1;
16996     var cmap = '\x00\x00' + // version
16997                string16(numTables) +  // numTables
16998                '\x00\x03' + // platformID
16999                '\x00\x01' + // encodingID
17000                string32(4 + numTables * 8); // start of the table record
17001
17002     var i, ii, j, jj;
17003     for (i = ranges.length - 1; i >= 0; --i) {
17004       if (ranges[i][0] <= 0xFFFF) { break; }
17005     }
17006     var bmpLength = i + 1;
17007
17008     if (ranges[i][0] < 0xFFFF && ranges[i][1] === 0xFFFF) {
17009       ranges[i][1] = 0xFFFE;
17010     }
17011     var trailingRangesCount = ranges[i][1] < 0xFFFF ? 1 : 0;
17012     var segCount = bmpLength + trailingRangesCount;
17013     var searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2);
17014
17015     // Fill up the 4 parallel arrays describing the segments.
17016     var startCount = '';
17017     var endCount = '';
17018     var idDeltas = '';
17019     var idRangeOffsets = '';
17020     var glyphsIds = '';
17021     var bias = 0;
17022
17023     var range, start, end, codes;
17024     for (i = 0, ii = bmpLength; i < ii; i++) {
17025       range = ranges[i];
17026       start = range[0];
17027       end = range[1];
17028       startCount += string16(start);
17029       endCount += string16(end);
17030       codes = range[2];
17031       var contiguous = true;
17032       for (j = 1, jj = codes.length; j < jj; ++j) {
17033         if (codes[j] !== codes[j - 1] + 1) {
17034           contiguous = false;
17035           break;
17036         }
17037       }
17038       if (!contiguous) {
17039         var offset = (segCount - i) * 2 + bias * 2;
17040         bias += (end - start + 1);
17041
17042         idDeltas += string16(0);
17043         idRangeOffsets += string16(offset);
17044
17045         for (j = 0, jj = codes.length; j < jj; ++j) {
17046           glyphsIds += string16(codes[j]);
17047         }
17048       } else {
17049         var startCode = codes[0];
17050
17051         idDeltas += string16((startCode - start) & 0xFFFF);
17052         idRangeOffsets += string16(0);
17053       }
17054     }
17055
17056     if (trailingRangesCount > 0) {
17057       endCount += '\xFF\xFF';
17058       startCount += '\xFF\xFF';
17059       idDeltas += '\x00\x01';
17060       idRangeOffsets += '\x00\x00';
17061     }
17062
17063     var format314 = '\x00\x00' + // language
17064                     string16(2 * segCount) +
17065                     string16(searchParams.range) +
17066                     string16(searchParams.entry) +
17067                     string16(searchParams.rangeShift) +
17068                     endCount + '\x00\x00' + startCount +
17069                     idDeltas + idRangeOffsets + glyphsIds;
17070
17071     var format31012 = '';
17072     var header31012 = '';
17073     if (numTables > 1) {
17074       cmap += '\x00\x03' + // platformID
17075               '\x00\x0A' + // encodingID
17076               string32(4 + numTables * 8 +
17077                        4 + format314.length); // start of the table record
17078       format31012 = '';
17079       for (i = 0, ii = ranges.length; i < ii; i++) {
17080         range = ranges[i];
17081         start = range[0];
17082         codes = range[2];
17083         var code = codes[0];
17084         for (j = 1, jj = codes.length; j < jj; ++j) {
17085           if (codes[j] !== codes[j - 1] + 1) {
17086             end = range[0] + j - 1;
17087             format31012 += string32(start) + // startCharCode
17088                            string32(end) + // endCharCode
17089                            string32(code); // startGlyphID
17090             start = end + 1;
17091             code = codes[j];
17092           }
17093         }
17094         format31012 += string32(start) + // startCharCode
17095                        string32(range[1]) + // endCharCode
17096                        string32(code); // startGlyphID
17097       }
17098       header31012 = '\x00\x0C' + // format
17099                     '\x00\x00' + // reserved
17100                     string32(format31012.length + 16) + // length
17101                     '\x00\x00\x00\x00' + // language
17102                     string32(format31012.length / 12); // nGroups
17103     }
17104
17105     return cmap + '\x00\x04' + // format
17106                   string16(format314.length + 4) + // length
17107                   format314 + header31012 + format31012;
17108   }
17109
17110   function validateOS2Table(os2) {
17111     var stream = new Stream(os2.data);
17112     var version = stream.getUint16();
17113     // TODO verify all OS/2 tables fields, but currently we validate only those
17114     // that give us issues
17115     stream.getBytes(60); // skipping type, misc sizes, panose, unicode ranges
17116     var selection = stream.getUint16();
17117     if (version < 4 && (selection & 0x0300)) {
17118       return false;
17119     }
17120     var firstChar = stream.getUint16();
17121     var lastChar = stream.getUint16();
17122     if (firstChar > lastChar) {
17123       return false;
17124     }
17125     stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap
17126     var usWinAscent = stream.getUint16();
17127     if (usWinAscent === 0) { // makes font unreadable by windows
17128       return false;
17129     }
17130
17131     // OS/2 appears to be valid, resetting some fields
17132     os2.data[8] = os2.data[9] = 0; // IE rejects fonts if fsType != 0
17133     return true;
17134   }
17135
17136   function createOS2Table(properties, charstrings, override) {
17137     override = override || {
17138       unitsPerEm: 0,
17139       yMax: 0,
17140       yMin: 0,
17141       ascent: 0,
17142       descent: 0
17143     };
17144
17145     var ulUnicodeRange1 = 0;
17146     var ulUnicodeRange2 = 0;
17147     var ulUnicodeRange3 = 0;
17148     var ulUnicodeRange4 = 0;
17149
17150     var firstCharIndex = null;
17151     var lastCharIndex = 0;
17152
17153     if (charstrings) {
17154       for (var code in charstrings) {
17155         code |= 0;
17156         if (firstCharIndex > code || !firstCharIndex) {
17157           firstCharIndex = code;
17158         }
17159         if (lastCharIndex < code) {
17160           lastCharIndex = code;
17161         }
17162
17163         var position = getUnicodeRangeFor(code);
17164         if (position < 32) {
17165           ulUnicodeRange1 |= 1 << position;
17166         } else if (position < 64) {
17167           ulUnicodeRange2 |= 1 << position - 32;
17168         } else if (position < 96) {
17169           ulUnicodeRange3 |= 1 << position - 64;
17170         } else if (position < 123) {
17171           ulUnicodeRange4 |= 1 << position - 96;
17172         } else {
17173           error('Unicode ranges Bits > 123 are reserved for internal usage');
17174         }
17175       }
17176     } else {
17177       // TODO
17178       firstCharIndex = 0;
17179       lastCharIndex = 255;
17180     }
17181
17182     var bbox = properties.bbox || [0, 0, 0, 0];
17183     var unitsPerEm = (override.unitsPerEm ||
17184                       1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0]);
17185
17186     // if the font units differ to the PDF glyph space units
17187     // then scale up the values
17188     var scale = (properties.ascentScaled ? 1.0 :
17189                  unitsPerEm / PDF_GLYPH_SPACE_UNITS);
17190
17191     var typoAscent = (override.ascent ||
17192                       Math.round(scale * (properties.ascent || bbox[3])));
17193     var typoDescent = (override.descent ||
17194                        Math.round(scale * (properties.descent || bbox[1])));
17195     if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) {
17196       typoDescent = -typoDescent; // fixing incorrect descent
17197     }
17198     var winAscent = override.yMax || typoAscent;
17199     var winDescent = -override.yMin || -typoDescent;
17200
17201     return '\x00\x03' + // version
17202            '\x02\x24' + // xAvgCharWidth
17203            '\x01\xF4' + // usWeightClass
17204            '\x00\x05' + // usWidthClass
17205            '\x00\x00' + // fstype (0 to let the font loads via font-face on IE)
17206            '\x02\x8A' + // ySubscriptXSize
17207            '\x02\xBB' + // ySubscriptYSize
17208            '\x00\x00' + // ySubscriptXOffset
17209            '\x00\x8C' + // ySubscriptYOffset
17210            '\x02\x8A' + // ySuperScriptXSize
17211            '\x02\xBB' + // ySuperScriptYSize
17212            '\x00\x00' + // ySuperScriptXOffset
17213            '\x01\xDF' + // ySuperScriptYOffset
17214            '\x00\x31' + // yStrikeOutSize
17215            '\x01\x02' + // yStrikeOutPosition
17216            '\x00\x00' + // sFamilyClass
17217            '\x00\x00\x06' +
17218            String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) +
17219            '\x00\x00\x00\x00\x00\x00' + // Panose
17220            string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31)
17221            string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63)
17222            string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95)
17223            string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127)
17224            '\x2A\x32\x31\x2A' + // achVendID
17225            string16(properties.italicAngle ? 1 : 0) + // fsSelection
17226            string16(firstCharIndex ||
17227                     properties.firstChar) + // usFirstCharIndex
17228            string16(lastCharIndex || properties.lastChar) +  // usLastCharIndex
17229            string16(typoAscent) + // sTypoAscender
17230            string16(typoDescent) + // sTypoDescender
17231            '\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value)
17232            string16(winAscent) + // usWinAscent
17233            string16(winDescent) + // usWinDescent
17234            '\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31)
17235            '\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63)
17236            string16(properties.xHeight) + // sxHeight
17237            string16(properties.capHeight) + // sCapHeight
17238            string16(0) + // usDefaultChar
17239            string16(firstCharIndex || properties.firstChar) + // usBreakChar
17240            '\x00\x03';  // usMaxContext
17241   }
17242
17243   function createPostTable(properties) {
17244     var angle = Math.floor(properties.italicAngle * (Math.pow(2, 16)));
17245     return ('\x00\x03\x00\x00' + // Version number
17246             string32(angle) + // italicAngle
17247             '\x00\x00' + // underlinePosition
17248             '\x00\x00' + // underlineThickness
17249             string32(properties.fixedPitch) + // isFixedPitch
17250             '\x00\x00\x00\x00' + // minMemType42
17251             '\x00\x00\x00\x00' + // maxMemType42
17252             '\x00\x00\x00\x00' + // minMemType1
17253             '\x00\x00\x00\x00');  // maxMemType1
17254   }
17255
17256   function createNameTable(name, proto) {
17257     if (!proto) {
17258       proto = [[], []]; // no strings and unicode strings
17259     }
17260
17261     var strings = [
17262       proto[0][0] || 'Original licence',  // 0.Copyright
17263       proto[0][1] || name,                // 1.Font family
17264       proto[0][2] || 'Unknown',           // 2.Font subfamily (font weight)
17265       proto[0][3] || 'uniqueID',          // 3.Unique ID
17266       proto[0][4] || name,                // 4.Full font name
17267       proto[0][5] || 'Version 0.11',      // 5.Version
17268       proto[0][6] || '',                  // 6.Postscript name
17269       proto[0][7] || 'Unknown',           // 7.Trademark
17270       proto[0][8] || 'Unknown',           // 8.Manufacturer
17271       proto[0][9] || 'Unknown'            // 9.Designer
17272     ];
17273
17274     // Mac want 1-byte per character strings while Windows want
17275     // 2-bytes per character, so duplicate the names table
17276     var stringsUnicode = [];
17277     var i, ii, j, jj, str;
17278     for (i = 0, ii = strings.length; i < ii; i++) {
17279       str = proto[1][i] || strings[i];
17280
17281       var strBufUnicode = [];
17282       for (j = 0, jj = str.length; j < jj; j++) {
17283         strBufUnicode.push(string16(str.charCodeAt(j)));
17284       }
17285       stringsUnicode.push(strBufUnicode.join(''));
17286     }
17287
17288     var names = [strings, stringsUnicode];
17289     var platforms = ['\x00\x01', '\x00\x03'];
17290     var encodings = ['\x00\x00', '\x00\x01'];
17291     var languages = ['\x00\x00', '\x04\x09'];
17292
17293     var namesRecordCount = strings.length * platforms.length;
17294     var nameTable =
17295       '\x00\x00' +                           // format
17296       string16(namesRecordCount) +           // Number of names Record
17297       string16(namesRecordCount * 12 + 6);   // Storage
17298
17299     // Build the name records field
17300     var strOffset = 0;
17301     for (i = 0, ii = platforms.length; i < ii; i++) {
17302       var strs = names[i];
17303       for (j = 0, jj = strs.length; j < jj; j++) {
17304         str = strs[j];
17305         var nameRecord =
17306           platforms[i] + // platform ID
17307           encodings[i] + // encoding ID
17308           languages[i] + // language ID
17309           string16(j) + // name ID
17310           string16(str.length) +
17311           string16(strOffset);
17312         nameTable += nameRecord;
17313         strOffset += str.length;
17314       }
17315     }
17316
17317     nameTable += strings.join('') + stringsUnicode.join('');
17318     return nameTable;
17319   }
17320
17321   Font.prototype = {
17322     name: null,
17323     font: null,
17324     mimetype: null,
17325     encoding: null,
17326     get renderer() {
17327       var renderer = FontRendererFactory.create(this);
17328       return shadow(this, 'renderer', renderer);
17329     },
17330
17331     exportData: function Font_exportData() {
17332       var data = {};
17333       for (var i in this) {
17334         if (this.hasOwnProperty(i)) {
17335           data[i] = this[i];
17336         }
17337       }
17338       return data;
17339     },
17340
17341     checkAndRepair: function Font_checkAndRepair(name, font, properties) {
17342       function readTableEntry(file) {
17343         var tag = bytesToString(file.getBytes(4));
17344
17345         var checksum = file.getInt32();
17346         var offset = file.getInt32() >>> 0;
17347         var length = file.getInt32() >>> 0;
17348
17349         // Read the table associated data
17350         var previousPosition = file.pos;
17351         file.pos = file.start ? file.start : 0;
17352         file.skip(offset);
17353         var data = file.getBytes(length);
17354         file.pos = previousPosition;
17355
17356         if (tag === 'head') {
17357           // clearing checksum adjustment
17358           data[8] = data[9] = data[10] = data[11] = 0;
17359           data[17] |= 0x20; //Set font optimized for cleartype flag
17360         }
17361
17362         return {
17363           tag: tag,
17364           checksum: checksum,
17365           length: length,
17366           offset: offset,
17367           data: data
17368         };
17369       }
17370
17371       function readOpenTypeHeader(ttf) {
17372         return {
17373           version: bytesToString(ttf.getBytes(4)),
17374           numTables: ttf.getUint16(),
17375           searchRange: ttf.getUint16(),
17376           entrySelector: ttf.getUint16(),
17377           rangeShift: ttf.getUint16()
17378         };
17379       }
17380
17381       /**
17382        * Read the appropriate subtable from the cmap according to 9.6.6.4 from
17383        * PDF spec
17384        */
17385       function readCmapTable(cmap, font, isSymbolicFont) {
17386         var segment;
17387         var start = (font.start ? font.start : 0) + cmap.offset;
17388         font.pos = start;
17389
17390         var version = font.getUint16();
17391         var numTables = font.getUint16();
17392
17393         var potentialTable;
17394         var canBreak = false;
17395         // There's an order of preference in terms of which cmap subtable to
17396         // use:
17397         // - non-symbolic fonts the preference is a 3,1 table then a 1,0 table
17398         // - symbolic fonts the preference is a 3,0 table then a 1,0 table
17399         // The following takes advantage of the fact that the tables are sorted
17400         // to work.
17401         for (var i = 0; i < numTables; i++) {
17402           var platformId = font.getUint16();
17403           var encodingId = font.getUint16();
17404           var offset = font.getInt32() >>> 0;
17405           var useTable = false;
17406
17407           if (platformId === 0 && encodingId === 0) {
17408             useTable = true;
17409             // Continue the loop since there still may be a higher priority
17410             // table.
17411           } else if (platformId === 1 && encodingId === 0) {
17412             useTable = true;
17413             // Continue the loop since there still may be a higher priority
17414             // table.
17415           } else if (platformId === 3 && encodingId === 1 &&
17416                      (!isSymbolicFont || !potentialTable)) {
17417             useTable = true;
17418             if (!isSymbolicFont) {
17419               canBreak = true;
17420             }
17421           } else if (isSymbolicFont && platformId === 3 && encodingId === 0) {
17422             useTable = true;
17423             canBreak = true;
17424           }
17425
17426           if (useTable) {
17427             potentialTable = {
17428               platformId: platformId,
17429               encodingId: encodingId,
17430               offset: offset
17431             };
17432           }
17433           if (canBreak) {
17434             break;
17435           }
17436         }
17437
17438         if (potentialTable) {
17439           font.pos = start + potentialTable.offset;
17440         }
17441         if (!potentialTable || font.peekByte() === -1) {
17442           warn('Could not find a preferred cmap table.');
17443           return {
17444             platformId: -1,
17445             encodingId: -1,
17446             mappings: [],
17447             hasShortCmap: false
17448           };
17449         }
17450
17451         var format = font.getUint16();
17452         var length = font.getUint16();
17453         var language = font.getUint16();
17454
17455         var hasShortCmap = false;
17456         var mappings = [];
17457         var j, glyphId;
17458
17459         // TODO(mack): refactor this cmap subtable reading logic out
17460         if (format === 0) {
17461           for (j = 0; j < 256; j++) {
17462             var index = font.getByte();
17463             if (!index) {
17464               continue;
17465             }
17466             mappings.push({
17467               charCode: j,
17468               glyphId: index
17469             });
17470           }
17471           hasShortCmap = true;
17472         } else if (format === 4) {
17473           // re-creating the table in format 4 since the encoding
17474           // might be changed
17475           var segCount = (font.getUint16() >> 1);
17476           font.getBytes(6); // skipping range fields
17477           var segIndex, segments = [];
17478           for (segIndex = 0; segIndex < segCount; segIndex++) {
17479             segments.push({ end: font.getUint16() });
17480           }
17481           font.getUint16();
17482           for (segIndex = 0; segIndex < segCount; segIndex++) {
17483             segments[segIndex].start = font.getUint16();
17484           }
17485
17486           for (segIndex = 0; segIndex < segCount; segIndex++) {
17487             segments[segIndex].delta = font.getUint16();
17488           }
17489
17490           var offsetsCount = 0;
17491           for (segIndex = 0; segIndex < segCount; segIndex++) {
17492             segment = segments[segIndex];
17493             var rangeOffset = font.getUint16();
17494             if (!rangeOffset) {
17495               segment.offsetIndex = -1;
17496               continue;
17497             }
17498
17499             var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
17500             segment.offsetIndex = offsetIndex;
17501             offsetsCount = Math.max(offsetsCount, offsetIndex +
17502                                     segment.end - segment.start + 1);
17503           }
17504
17505           var offsets = [];
17506           for (j = 0; j < offsetsCount; j++) {
17507             offsets.push(font.getUint16());
17508           }
17509
17510           for (segIndex = 0; segIndex < segCount; segIndex++) {
17511             segment = segments[segIndex];
17512             start = segment.start;
17513             var end = segment.end;
17514             var delta = segment.delta;
17515             offsetIndex = segment.offsetIndex;
17516
17517             for (j = start; j <= end; j++) {
17518               if (j === 0xFFFF) {
17519                 continue;
17520               }
17521
17522               glyphId = (offsetIndex < 0 ?
17523                          j : offsets[offsetIndex + j - start]);
17524               glyphId = (glyphId + delta) & 0xFFFF;
17525               if (glyphId === 0) {
17526                 continue;
17527               }
17528               mappings.push({
17529                 charCode: j,
17530                 glyphId: glyphId
17531               });
17532             }
17533           }
17534         } else if (format === 6) {
17535           // Format 6 is a 2-bytes dense mapping, which means the font data
17536           // lives glue together even if they are pretty far in the unicode
17537           // table. (This looks weird, so I can have missed something), this
17538           // works on Linux but seems to fails on Mac so let's rewrite the
17539           // cmap table to a 3-1-4 style
17540           var firstCode = font.getUint16();
17541           var entryCount = font.getUint16();
17542
17543           for (j = 0; j < entryCount; j++) {
17544             glyphId = font.getUint16();
17545             var charCode = firstCode + j;
17546
17547             mappings.push({
17548               charCode: charCode,
17549               glyphId: glyphId
17550             });
17551           }
17552         } else {
17553           error('cmap table has unsupported format: ' + format);
17554         }
17555
17556         // removing duplicate entries
17557         mappings.sort(function (a, b) {
17558           return a.charCode - b.charCode;
17559         });
17560         for (i = 1; i < mappings.length; i++) {
17561           if (mappings[i - 1].charCode === mappings[i].charCode) {
17562             mappings.splice(i, 1);
17563             i--;
17564           }
17565         }
17566
17567         return {
17568           platformId: potentialTable.platformId,
17569           encodingId: potentialTable.encodingId,
17570           mappings: mappings,
17571           hasShortCmap: hasShortCmap
17572         };
17573       }
17574
17575       function sanitizeMetrics(font, header, metrics, numGlyphs) {
17576         if (!header) {
17577           if (metrics) {
17578             metrics.data = null;
17579           }
17580           return;
17581         }
17582
17583         font.pos = (font.start ? font.start : 0) + header.offset;
17584         font.pos += header.length - 2;
17585         var numOfMetrics = font.getUint16();
17586
17587         if (numOfMetrics > numGlyphs) {
17588           info('The numOfMetrics (' + numOfMetrics + ') should not be ' +
17589                'greater than the numGlyphs (' + numGlyphs + ')');
17590           // Reduce numOfMetrics if it is greater than numGlyphs
17591           numOfMetrics = numGlyphs;
17592           header.data[34] = (numOfMetrics & 0xff00) >> 8;
17593           header.data[35] = numOfMetrics & 0x00ff;
17594         }
17595
17596         var numOfSidebearings = numGlyphs - numOfMetrics;
17597         var numMissing = numOfSidebearings -
17598           ((metrics.length - numOfMetrics * 4) >> 1);
17599
17600         if (numMissing > 0) {
17601           // For each missing glyph, we set both the width and lsb to 0 (zero).
17602           // Since we need to add two properties for each glyph, this explains
17603           // the use of |numMissing * 2| when initializing the typed array.
17604           var entries = new Uint8Array(metrics.length + numMissing * 2);
17605           entries.set(metrics.data);
17606           metrics.data = entries;
17607         }
17608       }
17609
17610       function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart,
17611                              hintsValid) {
17612         if (sourceEnd - sourceStart <= 12) {
17613           // glyph with data less than 12 is invalid one
17614           return 0;
17615         }
17616         var glyf = source.subarray(sourceStart, sourceEnd);
17617         var contoursCount = (glyf[0] << 8) | glyf[1];
17618         if (contoursCount & 0x8000) {
17619           // complex glyph, writing as is
17620           dest.set(glyf, destStart);
17621           return glyf.length;
17622         }
17623
17624         var i, j = 10, flagsCount = 0;
17625         for (i = 0; i < contoursCount; i++) {
17626           var endPoint = (glyf[j] << 8) | glyf[j + 1];
17627           flagsCount = endPoint + 1;
17628           j += 2;
17629         }
17630         // skipping instructions
17631         var instructionsStart = j;
17632         var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
17633         j += 2 + instructionsLength;
17634         var instructionsEnd = j;
17635         // validating flags
17636         var coordinatesLength = 0;
17637         for (i = 0; i < flagsCount; i++) {
17638           var flag = glyf[j++];
17639           if (flag & 0xC0) {
17640             // reserved flags must be zero, cleaning up
17641             glyf[j - 1] = flag & 0x3F;
17642           }
17643           var xyLength = ((flag & 2) ? 1 : (flag & 16) ? 0 : 2) +
17644                          ((flag & 4) ? 1 : (flag & 32) ? 0 : 2);
17645           coordinatesLength += xyLength;
17646           if (flag & 8) {
17647             var repeat = glyf[j++];
17648             i += repeat;
17649             coordinatesLength += repeat * xyLength;
17650           }
17651         }
17652         // glyph without coordinates will be rejected
17653         if (coordinatesLength === 0) {
17654           return 0;
17655         }
17656         var glyphDataLength = j + coordinatesLength;
17657         if (glyphDataLength > glyf.length) {
17658           // not enough data for coordinates
17659           return 0;
17660         }
17661         if (!hintsValid && instructionsLength > 0) {
17662           dest.set(glyf.subarray(0, instructionsStart), destStart);
17663           dest.set([0, 0], destStart + instructionsStart);
17664           dest.set(glyf.subarray(instructionsEnd, glyphDataLength),
17665                    destStart + instructionsStart + 2);
17666           glyphDataLength -= instructionsLength;
17667           if (glyf.length - glyphDataLength > 3) {
17668             glyphDataLength = (glyphDataLength + 3) & ~3;
17669           }
17670           return glyphDataLength;
17671         }
17672         if (glyf.length - glyphDataLength > 3) {
17673           // truncating and aligning to 4 bytes the long glyph data
17674           glyphDataLength = (glyphDataLength + 3) & ~3;
17675           dest.set(glyf.subarray(0, glyphDataLength), destStart);
17676           return glyphDataLength;
17677         }
17678         // glyph data is fine
17679         dest.set(glyf, destStart);
17680         return glyf.length;
17681       }
17682
17683       function sanitizeHead(head, numGlyphs, locaLength) {
17684         var data = head.data;
17685
17686         // Validate version:
17687         // Should always be 0x00010000
17688         var version = int32(data[0], data[1], data[2], data[3]);
17689         if (version >> 16 !== 1) {
17690           info('Attempting to fix invalid version in head table: ' + version);
17691           data[0] = 0;
17692           data[1] = 1;
17693           data[2] = 0;
17694           data[3] = 0;
17695         }
17696
17697         var indexToLocFormat = int16(data[50], data[51]);
17698         if (indexToLocFormat < 0 || indexToLocFormat > 1) {
17699           info('Attempting to fix invalid indexToLocFormat in head table: ' +
17700                indexToLocFormat);
17701
17702           // The value of indexToLocFormat should be 0 if the loca table
17703           // consists of short offsets, and should be 1 if the loca table
17704           // consists of long offsets.
17705           //
17706           // The number of entries in the loca table should be numGlyphs + 1.
17707           //
17708           // Using this information, we can work backwards to deduce if the
17709           // size of each offset in the loca table, and thus figure out the
17710           // appropriate value for indexToLocFormat.
17711
17712           var numGlyphsPlusOne = numGlyphs + 1;
17713           if (locaLength === numGlyphsPlusOne << 1) {
17714             // 0x0000 indicates the loca table consists of short offsets
17715             data[50] = 0;
17716             data[51] = 0;
17717           } else if (locaLength === numGlyphsPlusOne << 2) {
17718             // 0x0001 indicates the loca table consists of long offsets
17719             data[50] = 0;
17720             data[51] = 1;
17721           } else {
17722             warn('Could not fix indexToLocFormat: ' + indexToLocFormat);
17723           }
17724         }
17725       }
17726
17727       function sanitizeGlyphLocations(loca, glyf, numGlyphs,
17728                                       isGlyphLocationsLong, hintsValid,
17729                                       dupFirstEntry) {
17730         var itemSize, itemDecode, itemEncode;
17731         if (isGlyphLocationsLong) {
17732           itemSize = 4;
17733           itemDecode = function fontItemDecodeLong(data, offset) {
17734             return (data[offset] << 24) | (data[offset + 1] << 16) |
17735                    (data[offset + 2] << 8) | data[offset + 3];
17736           };
17737           itemEncode = function fontItemEncodeLong(data, offset, value) {
17738             data[offset] = (value >>> 24) & 0xFF;
17739             data[offset + 1] = (value >> 16) & 0xFF;
17740             data[offset + 2] = (value >> 8) & 0xFF;
17741             data[offset + 3] = value & 0xFF;
17742           };
17743         } else {
17744           itemSize = 2;
17745           itemDecode = function fontItemDecode(data, offset) {
17746             return (data[offset] << 9) | (data[offset + 1] << 1);
17747           };
17748           itemEncode = function fontItemEncode(data, offset, value) {
17749             data[offset] = (value >> 9) & 0xFF;
17750             data[offset + 1] = (value >> 1) & 0xFF;
17751           };
17752         }
17753         var locaData = loca.data;
17754         var locaDataSize = itemSize * (1 + numGlyphs);
17755         // is loca.data too short or long?
17756         if (locaData.length !== locaDataSize) {
17757           locaData = new Uint8Array(locaDataSize);
17758           locaData.set(loca.data.subarray(0, locaDataSize));
17759           loca.data = locaData;
17760         }
17761         // removing the invalid glyphs
17762         var oldGlyfData = glyf.data;
17763         var oldGlyfDataLength = oldGlyfData.length;
17764         var newGlyfData = new Uint8Array(oldGlyfDataLength);
17765         var startOffset = itemDecode(locaData, 0);
17766         var writeOffset = 0;
17767         var missingGlyphData = {};
17768         itemEncode(locaData, 0, writeOffset);
17769         var i, j;
17770         for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
17771           var endOffset = itemDecode(locaData, j);
17772           if (endOffset > oldGlyfDataLength &&
17773               ((oldGlyfDataLength + 3) & ~3) === endOffset) {
17774             // Aspose breaks fonts by aligning the glyphs to the qword, but not
17775             // the glyf table size, which makes last glyph out of range.
17776             endOffset = oldGlyfDataLength;
17777           }
17778           if (endOffset > oldGlyfDataLength) {
17779             // glyph end offset points outside glyf data, rejecting the glyph
17780             itemEncode(locaData, j, writeOffset);
17781             startOffset = endOffset;
17782             continue;
17783           }
17784
17785           if (startOffset === endOffset) {
17786             missingGlyphData[i] = true;
17787           }
17788
17789           var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
17790                                         newGlyfData, writeOffset, hintsValid);
17791           writeOffset += newLength;
17792           itemEncode(locaData, j, writeOffset);
17793           startOffset = endOffset;
17794         }
17795
17796         if (writeOffset === 0) {
17797           // glyf table cannot be empty -- redoing the glyf and loca tables
17798           // to have single glyph with one point
17799           var simpleGlyph = new Uint8Array(
17800             [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]);
17801           for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
17802             itemEncode(locaData, j, simpleGlyph.length);
17803           }
17804           glyf.data = simpleGlyph;
17805           return missingGlyphData;
17806         }
17807
17808         if (dupFirstEntry) {
17809           var firstEntryLength = itemDecode(locaData, itemSize);
17810           if (newGlyfData.length > firstEntryLength + writeOffset) {
17811             glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset);
17812           } else {
17813             glyf.data = new Uint8Array(firstEntryLength + writeOffset);
17814             glyf.data.set(newGlyfData.subarray(0, writeOffset));
17815           }
17816           glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset);
17817           itemEncode(loca.data, locaData.length - itemSize,
17818                      writeOffset + firstEntryLength);
17819         } else {
17820           glyf.data = newGlyfData.subarray(0, writeOffset);
17821         }
17822         return missingGlyphData;
17823       }
17824
17825       function readPostScriptTable(post, properties, maxpNumGlyphs) {
17826         var start = (font.start ? font.start : 0) + post.offset;
17827         font.pos = start;
17828
17829         var length = post.length, end = start + length;
17830         var version = font.getInt32();
17831         // skip rest to the tables
17832         font.getBytes(28);
17833
17834         var glyphNames;
17835         var valid = true;
17836         var i;
17837
17838         switch (version) {
17839           case 0x00010000:
17840             glyphNames = MacStandardGlyphOrdering;
17841             break;
17842           case 0x00020000:
17843             var numGlyphs = font.getUint16();
17844             if (numGlyphs !== maxpNumGlyphs) {
17845               valid = false;
17846               break;
17847             }
17848             var glyphNameIndexes = [];
17849             for (i = 0; i < numGlyphs; ++i) {
17850               var index = font.getUint16();
17851               if (index >= 32768) {
17852                 valid = false;
17853                 break;
17854               }
17855               glyphNameIndexes.push(index);
17856             }
17857             if (!valid) {
17858               break;
17859             }
17860             var customNames = [];
17861             var strBuf = [];
17862             while (font.pos < end) {
17863               var stringLength = font.getByte();
17864               strBuf.length = stringLength;
17865               for (i = 0; i < stringLength; ++i) {
17866                 strBuf[i] = String.fromCharCode(font.getByte());
17867               }
17868               customNames.push(strBuf.join(''));
17869             }
17870             glyphNames = [];
17871             for (i = 0; i < numGlyphs; ++i) {
17872               var j = glyphNameIndexes[i];
17873               if (j < 258) {
17874                 glyphNames.push(MacStandardGlyphOrdering[j]);
17875                 continue;
17876               }
17877               glyphNames.push(customNames[j - 258]);
17878             }
17879             break;
17880           case 0x00030000:
17881             break;
17882           default:
17883             warn('Unknown/unsupported post table version ' + version);
17884             valid = false;
17885             if (properties.defaultEncoding) {
17886               glyphNames = properties.defaultEncoding;
17887             }
17888             break;
17889         }
17890         properties.glyphNames = glyphNames;
17891         return valid;
17892       }
17893
17894       function readNameTable(nameTable) {
17895         var start = (font.start ? font.start : 0) + nameTable.offset;
17896         font.pos = start;
17897
17898         var names = [[], []];
17899         var length = nameTable.length, end = start + length;
17900         var format = font.getUint16();
17901         var FORMAT_0_HEADER_LENGTH = 6;
17902         if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) {
17903           // unsupported name table format or table "too" small
17904           return names;
17905         }
17906         var numRecords = font.getUint16();
17907         var stringsStart = font.getUint16();
17908         var records = [];
17909         var NAME_RECORD_LENGTH = 12;
17910         var i, ii;
17911
17912         for (i = 0; i < numRecords &&
17913                         font.pos + NAME_RECORD_LENGTH <= end; i++) {
17914           var r = {
17915             platform: font.getUint16(),
17916             encoding: font.getUint16(),
17917             language: font.getUint16(),
17918             name: font.getUint16(),
17919             length: font.getUint16(),
17920             offset: font.getUint16()
17921           };
17922           // using only Macintosh and Windows platform/encoding names
17923           if ((r.platform === 1 && r.encoding === 0 && r.language === 0) ||
17924               (r.platform === 3 && r.encoding === 1 && r.language === 0x409)) {
17925             records.push(r);
17926           }
17927         }
17928         for (i = 0, ii = records.length; i < ii; i++) {
17929           var record = records[i];
17930           var pos = start + stringsStart + record.offset;
17931           if (pos + record.length > end) {
17932             continue; // outside of name table, ignoring
17933           }
17934           font.pos = pos;
17935           var nameIndex = record.name;
17936           if (record.encoding) {
17937             // unicode
17938             var str = '';
17939             for (var j = 0, jj = record.length; j < jj; j += 2) {
17940               str += String.fromCharCode(font.getUint16());
17941             }
17942             names[1][nameIndex] = str;
17943           } else {
17944             names[0][nameIndex] = bytesToString(font.getBytes(record.length));
17945           }
17946         }
17947         return names;
17948       }
17949
17950       var TTOpsStackDeltas = [
17951         0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,
17952         -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,
17953         1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1,
17954         0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2,
17955         0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1,
17956         -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1,
17957         -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17958         -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1,
17959         -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2];
17960         // 0xC0-DF == -1 and 0xE0-FF == -2
17961
17962       function sanitizeTTProgram(table, ttContext) {
17963         var data = table.data;
17964         var i = 0, j, n, b, funcId, pc, lastEndf = 0, lastDeff = 0;
17965         var stack = [];
17966         var callstack = [];
17967         var functionsCalled = [];
17968         var tooComplexToFollowFunctions =
17969           ttContext.tooComplexToFollowFunctions;
17970         var inFDEF = false, ifLevel = 0, inELSE = 0;
17971         for (var ii = data.length; i < ii;) {
17972           var op = data[i++];
17973           // The TrueType instruction set docs can be found at
17974           // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html
17975           if (op === 0x40) { // NPUSHB - pushes n bytes
17976             n = data[i++];
17977             if (inFDEF || inELSE) {
17978               i += n;
17979             } else {
17980               for (j = 0; j < n; j++) {
17981                 stack.push(data[i++]);
17982               }
17983             }
17984           } else if (op === 0x41) { // NPUSHW - pushes n words
17985             n = data[i++];
17986             if (inFDEF || inELSE) {
17987               i += n * 2;
17988             } else {
17989               for (j = 0; j < n; j++) {
17990                 b = data[i++];
17991                 stack.push((b << 8) | data[i++]);
17992               }
17993             }
17994           } else if ((op & 0xF8) === 0xB0) { // PUSHB - pushes bytes
17995             n = op - 0xB0 + 1;
17996             if (inFDEF || inELSE) {
17997               i += n;
17998             } else {
17999               for (j = 0; j < n; j++) {
18000                 stack.push(data[i++]);
18001               }
18002             }
18003           } else if ((op & 0xF8) === 0xB8) { // PUSHW - pushes words
18004             n = op - 0xB8 + 1;
18005             if (inFDEF || inELSE) {
18006               i += n * 2;
18007             } else {
18008               for (j = 0; j < n; j++) {
18009                 b = data[i++];
18010                 stack.push((b << 8) | data[i++]);
18011               }
18012             }
18013           } else if (op === 0x2B && !tooComplexToFollowFunctions) { // CALL
18014             if (!inFDEF && !inELSE) {
18015               // collecting inforamtion about which functions are used
18016               funcId = stack[stack.length - 1];
18017               ttContext.functionsUsed[funcId] = true;
18018               if (funcId in ttContext.functionsStackDeltas) {
18019                 stack.length += ttContext.functionsStackDeltas[funcId];
18020               } else if (funcId in ttContext.functionsDefined &&
18021                          functionsCalled.indexOf(funcId) < 0) {
18022                 callstack.push({data: data, i: i, stackTop: stack.length - 1});
18023                 functionsCalled.push(funcId);
18024                 pc = ttContext.functionsDefined[funcId];
18025                 if (!pc) {
18026                   warn('TT: CALL non-existent function');
18027                   ttContext.hintsValid = false;
18028                   return;
18029                 }
18030                 data = pc.data;
18031                 i = pc.i;
18032               }
18033             }
18034           } else if (op === 0x2C && !tooComplexToFollowFunctions) { // FDEF
18035             if (inFDEF || inELSE) {
18036               warn('TT: nested FDEFs not allowed');
18037               tooComplexToFollowFunctions = true;
18038             }
18039             inFDEF = true;
18040             // collecting inforamtion about which functions are defined
18041             lastDeff = i;
18042             funcId = stack.pop();
18043             ttContext.functionsDefined[funcId] = {data: data, i: i};
18044           } else if (op === 0x2D) { // ENDF - end of function
18045             if (inFDEF) {
18046               inFDEF = false;
18047               lastEndf = i;
18048             } else {
18049               pc = callstack.pop();
18050               if (!pc) {
18051                 warn('TT: ENDF bad stack');
18052                 ttContext.hintsValid = false;
18053                 return;
18054               }
18055               funcId = functionsCalled.pop();
18056               data = pc.data;
18057               i = pc.i;
18058               ttContext.functionsStackDeltas[funcId] =
18059                 stack.length - pc.stackTop;
18060             }
18061           } else if (op === 0x89) { // IDEF - instruction definition
18062             if (inFDEF || inELSE) {
18063               warn('TT: nested IDEFs not allowed');
18064               tooComplexToFollowFunctions = true;
18065             }
18066             inFDEF = true;
18067             // recording it as a function to track ENDF
18068             lastDeff = i;
18069           } else if (op === 0x58) { // IF
18070             ++ifLevel;
18071           } else if (op === 0x1B) { // ELSE
18072             inELSE = ifLevel;
18073           } else if (op === 0x59) { // EIF
18074             if (inELSE === ifLevel) {
18075               inELSE = 0;
18076             }
18077             --ifLevel;
18078           } else if (op === 0x1C) { // JMPR
18079             if (!inFDEF && !inELSE) {
18080               var offset = stack[stack.length - 1];
18081               // only jumping forward to prevent infinite loop
18082               if (offset > 0) {
18083                 i += offset - 1;
18084               }
18085             }
18086           }
18087           // Adjusting stack not extactly, but just enough to get function id
18088           if (!inFDEF && !inELSE) {
18089             var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] :
18090               op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0;
18091             if (op >= 0x71 && op <= 0x75) {
18092               n = stack.pop();
18093               if (n === n) {
18094                 stackDelta = -n * 2;
18095               }
18096             }
18097             while (stackDelta < 0 && stack.length > 0) {
18098               stack.pop();
18099               stackDelta++;
18100             }
18101             while (stackDelta > 0) {
18102               stack.push(NaN); // pushing any number into stack
18103               stackDelta--;
18104             }
18105           }
18106         }
18107         ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions;
18108         var content = [data];
18109         if (i > data.length) {
18110           content.push(new Uint8Array(i - data.length));
18111         }
18112         if (lastDeff > lastEndf) {
18113           warn('TT: complementing a missing function tail');
18114           // new function definition started, but not finished
18115           // complete function by [CLEAR, ENDF]
18116           content.push(new Uint8Array([0x22, 0x2D]));
18117         }
18118         foldTTTable(table, content);
18119       }
18120
18121       function checkInvalidFunctions(ttContext, maxFunctionDefs) {
18122         if (ttContext.tooComplexToFollowFunctions) {
18123           return;
18124         }
18125         if (ttContext.functionsDefined.length > maxFunctionDefs) {
18126           warn('TT: more functions defined than expected');
18127           ttContext.hintsValid = false;
18128           return;
18129         }
18130         for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
18131           if (j > maxFunctionDefs) {
18132             warn('TT: invalid function id: ' + j);
18133             ttContext.hintsValid = false;
18134             return;
18135           }
18136           if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {
18137             warn('TT: undefined function: ' + j);
18138             ttContext.hintsValid = false;
18139             return;
18140           }
18141         }
18142       }
18143
18144       function foldTTTable(table, content) {
18145         if (content.length > 1) {
18146           // concatenating the content items
18147           var newLength = 0;
18148           var j, jj;
18149           for (j = 0, jj = content.length; j < jj; j++) {
18150             newLength += content[j].length;
18151           }
18152           newLength = (newLength + 3) & ~3;
18153           var result = new Uint8Array(newLength);
18154           var pos = 0;
18155           for (j = 0, jj = content.length; j < jj; j++) {
18156             result.set(content[j], pos);
18157             pos += content[j].length;
18158           }
18159           table.data = result;
18160           table.length = newLength;
18161         }
18162       }
18163
18164       function sanitizeTTPrograms(fpgm, prep, cvt) {
18165         var ttContext = {
18166           functionsDefined: [],
18167           functionsUsed: [],
18168           functionsStackDeltas: [],
18169           tooComplexToFollowFunctions: false,
18170           hintsValid: true
18171         };
18172         if (fpgm) {
18173           sanitizeTTProgram(fpgm, ttContext);
18174         }
18175         if (prep) {
18176           sanitizeTTProgram(prep, ttContext);
18177         }
18178         if (fpgm) {
18179           checkInvalidFunctions(ttContext, maxFunctionDefs);
18180         }
18181         if (cvt && (cvt.length & 1)) {
18182           var cvtData = new Uint8Array(cvt.length + 1);
18183           cvtData.set(cvt.data);
18184           cvt.data = cvtData;
18185         }
18186         return ttContext.hintsValid;
18187       }
18188
18189       // The following steps modify the original font data, making copy
18190       font = new Stream(new Uint8Array(font.getBytes()));
18191
18192       var VALID_TABLES = ['OS/2', 'cmap', 'head', 'hhea', 'hmtx', 'maxp',
18193         'name', 'post', 'loca', 'glyf', 'fpgm', 'prep', 'cvt ', 'CFF '];
18194
18195       var header = readOpenTypeHeader(font);
18196       var numTables = header.numTables;
18197       var cff, cffFile;
18198
18199       var tables = { 'OS/2': null, cmap: null, head: null, hhea: null,
18200                      hmtx: null, maxp: null, name: null, post: null };
18201       var table;
18202       for (var i = 0; i < numTables; i++) {
18203         table = readTableEntry(font);
18204         if (VALID_TABLES.indexOf(table.tag) < 0) {
18205           continue; // skipping table if it's not a required or optional table
18206         }
18207         if (table.length === 0) {
18208           continue; // skipping empty tables
18209         }
18210         tables[table.tag] = table;
18211       }
18212
18213       var isTrueType = !tables['CFF '];
18214       if (!isTrueType) {
18215         // OpenType font
18216         if (header.version === 'OTTO' ||
18217             !tables.head || !tables.hhea || !tables.maxp || !tables.post) {
18218           // no major tables: throwing everything at CFFFont
18219           cffFile = new Stream(tables['CFF '].data);
18220           cff = new CFFFont(cffFile, properties);
18221
18222           return this.convert(name, cff, properties);
18223         }
18224
18225         delete tables.glyf;
18226         delete tables.loca;
18227         delete tables.fpgm;
18228         delete tables.prep;
18229         delete tables['cvt '];
18230         this.isOpenType = true;
18231       } else {
18232         if (!tables.glyf || !tables.loca) {
18233           error('Required "glyf" or "loca" tables are not found');
18234         }
18235         this.isOpenType = false;
18236       }
18237
18238       if (!tables.maxp) {
18239         error('Required "maxp" table is not found');
18240       }
18241
18242       font.pos = (font.start || 0) + tables.maxp.offset;
18243       var version = font.getInt32();
18244       var numGlyphs = font.getUint16();
18245       var maxFunctionDefs = 0;
18246       if (version >= 0x00010000 && tables.maxp.length >= 22) {
18247         // maxZones can be invalid
18248         font.pos += 8;
18249         var maxZones = font.getUint16();
18250         if (maxZones > 2) { // reset to 2 if font has invalid maxZones
18251           tables.maxp.data[14] = 0;
18252           tables.maxp.data[15] = 2;
18253         }
18254         font.pos += 4;
18255         maxFunctionDefs = font.getUint16();
18256       }
18257
18258       var dupFirstEntry = false;
18259       if (properties.type === 'CIDFontType2' && properties.toUnicode &&
18260           properties.toUnicode.get(0) > '\u0000') {
18261         // oracle's defect (see 3427), duplicating first entry
18262         dupFirstEntry = true;
18263         numGlyphs++;
18264         tables.maxp.data[4] = numGlyphs >> 8;
18265         tables.maxp.data[5] = numGlyphs & 255;
18266       }
18267
18268       var hintsValid = sanitizeTTPrograms(tables.fpgm, tables.prep,
18269                                           tables['cvt '], maxFunctionDefs);
18270       if (!hintsValid) {
18271         delete tables.fpgm;
18272         delete tables.prep;
18273         delete tables['cvt '];
18274       }
18275
18276       // Ensure the hmtx table contains the advance width and
18277       // sidebearings information for numGlyphs in the maxp table
18278       sanitizeMetrics(font, tables.hhea, tables.hmtx, numGlyphs);
18279
18280       if (!tables.head) {
18281         error('Required "head" table is not found');
18282       }
18283
18284       sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0);
18285
18286       var missingGlyphs = {};
18287       if (isTrueType) {
18288         var isGlyphLocationsLong = int16(tables.head.data[50],
18289                                          tables.head.data[51]);
18290         missingGlyphs = sanitizeGlyphLocations(tables.loca, tables.glyf,
18291                                                numGlyphs, isGlyphLocationsLong,
18292                                                hintsValid, dupFirstEntry);
18293       }
18294
18295       if (!tables.hhea) {
18296         error('Required "hhea" table is not found');
18297       }
18298
18299       // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
18300       // Sometimes it's 0. That needs to be fixed
18301       if (tables.hhea.data[10] === 0 && tables.hhea.data[11] === 0) {
18302         tables.hhea.data[10] = 0xFF;
18303         tables.hhea.data[11] = 0xFF;
18304       }
18305
18306       // The 'post' table has glyphs names.
18307       if (tables.post) {
18308         var valid = readPostScriptTable(tables.post, properties, numGlyphs);
18309         if (!valid) {
18310           tables.post = null;
18311         }
18312       }
18313
18314       var charCodeToGlyphId = [], charCode, toUnicode = properties.toUnicode;
18315
18316       function hasGlyph(glyphId, charCode) {
18317         if (!missingGlyphs[glyphId]) {
18318           return true;
18319         }
18320         if (charCode >= 0 && toUnicode.has(charCode)) {
18321           return true;
18322         }
18323         return false;
18324       }
18325
18326       if (properties.type === 'CIDFontType2') {
18327         var cidToGidMap = properties.cidToGidMap || [];
18328         var isCidToGidMapEmpty = cidToGidMap.length === 0;
18329
18330         properties.cMap.forEach(function(charCode, cid) {
18331           assert(cid <= 0xffff, 'Max size of CID is 65,535');
18332           var glyphId = -1;
18333           if (isCidToGidMapEmpty) {
18334             glyphId = charCode;
18335           } else if (cidToGidMap[cid] !== undefined) {
18336             glyphId = cidToGidMap[cid];
18337           }
18338
18339           if (glyphId >= 0 && glyphId < numGlyphs &&
18340               hasGlyph(glyphId, charCode)) {
18341             charCodeToGlyphId[charCode] = glyphId;
18342           }
18343         });
18344         if (dupFirstEntry) {
18345           charCodeToGlyphId[0] = numGlyphs - 1;
18346         }
18347       } else {
18348         // Most of the following logic in this code branch is based on the
18349         // 9.6.6.4 of the PDF spec.
18350         var cmapTable = readCmapTable(tables.cmap, font, this.isSymbolicFont);
18351         var cmapPlatformId = cmapTable.platformId;
18352         var cmapEncodingId = cmapTable.encodingId;
18353         var cmapMappings = cmapTable.mappings;
18354         var cmapMappingsLength = cmapMappings.length;
18355         var hasEncoding = properties.differences.length ||
18356                           !!properties.baseEncodingName;
18357
18358         // The spec seems to imply that if the font is symbolic the encoding
18359         // should be ignored, this doesn't appear to work for 'preistabelle.pdf'
18360         // where the the font is symbolic and it has an encoding.
18361         if (hasEncoding &&
18362             (cmapPlatformId === 3 && cmapEncodingId === 1 ||
18363              cmapPlatformId === 1 && cmapEncodingId === 0) ||
18364             (cmapPlatformId === -1 && cmapEncodingId === -1 && // Temporary hack
18365              !!Encodings[properties.baseEncodingName])) {      // Temporary hack
18366           // When no preferred cmap table was found and |baseEncodingName| is
18367           // one of the predefined encodings, we seem to obtain a better
18368           // |charCodeToGlyphId| map from the code below (fixes bug 1057544).
18369           // TODO: Note that this is a hack which should be removed as soon as
18370           //       we have proper support for more exotic cmap tables.
18371
18372           var baseEncoding = [];
18373           if (properties.baseEncodingName === 'MacRomanEncoding' ||
18374               properties.baseEncodingName === 'WinAnsiEncoding') {
18375             baseEncoding = Encodings[properties.baseEncodingName];
18376           }
18377           for (charCode = 0; charCode < 256; charCode++) {
18378             var glyphName;
18379             if (this.differences && charCode in this.differences) {
18380               glyphName = this.differences[charCode];
18381             } else if (charCode in baseEncoding &&
18382                        baseEncoding[charCode] !== '') {
18383               glyphName = baseEncoding[charCode];
18384             } else {
18385               glyphName = Encodings.StandardEncoding[charCode];
18386             }
18387             if (!glyphName) {
18388               continue;
18389             }
18390             var unicodeOrCharCode;
18391             if (cmapPlatformId === 3 && cmapEncodingId === 1) {
18392               unicodeOrCharCode = GlyphsUnicode[glyphName];
18393             } else if (cmapPlatformId === 1 && cmapEncodingId === 0) {
18394               // TODO: the encoding needs to be updated with mac os table.
18395               unicodeOrCharCode = Encodings.MacRomanEncoding.indexOf(glyphName);
18396             }
18397
18398             var found = false;
18399             for (i = 0; i < cmapMappingsLength; ++i) {
18400               if (cmapMappings[i].charCode === unicodeOrCharCode &&
18401                   hasGlyph(cmapMappings[i].glyphId, unicodeOrCharCode)) {
18402                 charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
18403                 found = true;
18404                 break;
18405               }
18406             }
18407             if (!found && properties.glyphNames) {
18408               // Try to map using the post table. There are currently no known
18409               // pdfs that this fixes.
18410               var glyphId = properties.glyphNames.indexOf(glyphName);
18411               if (glyphId > 0 && hasGlyph(glyphId, -1)) {
18412                 charCodeToGlyphId[charCode] = glyphId;
18413               }
18414             }
18415           }
18416         } else if (cmapPlatformId === 0 && cmapEncodingId === 0) {
18417           // Default Unicode semantics, use the charcodes as is.
18418           for (i = 0; i < cmapMappingsLength; ++i) {
18419             charCodeToGlyphId[cmapMappings[i].charCode] =
18420               cmapMappings[i].glyphId;
18421           }
18422         } else {
18423           // For (3, 0) cmap tables:
18424           // The charcode key being stored in charCodeToGlyphId is the lower
18425           // byte of the two-byte charcodes of the cmap table since according to
18426           // the spec: 'each byte from the string shall be prepended with the
18427           // high byte of the range [of charcodes in the cmap table], to form
18428           // a two-byte character, which shall be used to select the
18429           // associated glyph description from the subtable'.
18430           //
18431           // For (1, 0) cmap tables:
18432           // 'single bytes from the string shall be used to look up the
18433           // associated glyph descriptions from the subtable'. This means
18434           // charcodes in the cmap will be single bytes, so no-op since
18435           // glyph.charCode & 0xFF === glyph.charCode
18436           for (i = 0; i < cmapMappingsLength; ++i) {
18437             charCode = cmapMappings[i].charCode & 0xFF;
18438             charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
18439           }
18440         }
18441       }
18442
18443       if (charCodeToGlyphId.length === 0) {
18444         // defines at least one glyph
18445         charCodeToGlyphId[0] = 0;
18446       }
18447
18448       // Converting glyphs and ids into font's cmap table
18449       var newMapping = adjustMapping(charCodeToGlyphId, properties);
18450       this.toFontChar = newMapping.toFontChar;
18451       tables.cmap = {
18452         tag: 'cmap',
18453         data: createCmapTable(newMapping.charCodeToGlyphId)
18454       };
18455
18456       if (!tables['OS/2'] || !validateOS2Table(tables['OS/2'])) {
18457         // extract some more font properties from the OpenType head and
18458         // hhea tables; yMin and descent value are always negative
18459         var override = {
18460           unitsPerEm: int16(tables.head.data[18], tables.head.data[19]),
18461           yMax: int16(tables.head.data[42], tables.head.data[43]),
18462           yMin: int16(tables.head.data[38], tables.head.data[39]) - 0x10000,
18463           ascent: int16(tables.hhea.data[4], tables.hhea.data[5]),
18464           descent: int16(tables.hhea.data[6], tables.hhea.data[7]) - 0x10000
18465         };
18466
18467         tables['OS/2'] = {
18468           tag: 'OS/2',
18469           data: createOS2Table(properties, newMapping.charCodeToGlyphId,
18470                                override)
18471         };
18472       }
18473
18474       // Rewrite the 'post' table if needed
18475       if (!tables.post) {
18476         tables.post = {
18477           tag: 'post',
18478           data: createPostTable(properties)
18479         };
18480       }
18481
18482       if (!isTrueType) {
18483         try {
18484           // Trying to repair CFF file
18485           cffFile = new Stream(tables['CFF '].data);
18486           var parser = new CFFParser(cffFile, properties);
18487           cff = parser.parse();
18488           var compiler = new CFFCompiler(cff);
18489           tables['CFF '].data = compiler.compile();
18490         } catch (e) {
18491           warn('Failed to compile font ' + properties.loadedName);
18492         }
18493       }
18494
18495       // Re-creating 'name' table
18496       if (!tables.name) {
18497         tables.name = {
18498           tag: 'name',
18499           data: createNameTable(this.name)
18500         };
18501       } else {
18502         // ... using existing 'name' table as prototype
18503         var namePrototype = readNameTable(tables.name);
18504         tables.name.data = createNameTable(name, namePrototype);
18505       }
18506
18507       var builder = new OpenTypeFileBuilder(header.version);
18508       for (var tableTag in tables) {
18509         builder.addTable(tableTag, tables[tableTag].data);
18510       }
18511       return builder.toArray();
18512     },
18513
18514     convert: function Font_convert(fontName, font, properties) {
18515       // TODO: Check the charstring widths to determine this.
18516       properties.fixedPitch = false;
18517
18518       var mapping = font.getGlyphMapping(properties);
18519       var newMapping = adjustMapping(mapping, properties);
18520       this.toFontChar = newMapping.toFontChar;
18521       var numGlyphs = font.numGlyphs;
18522
18523       function getCharCodes(charCodeToGlyphId, glyphId) {
18524         var charCodes = null;
18525         for (var charCode in charCodeToGlyphId) {
18526           if (glyphId === charCodeToGlyphId[charCode]) {
18527             if (!charCodes) {
18528               charCodes = [];
18529             }
18530             charCodes.push(charCode | 0);
18531           }
18532         }
18533         return charCodes;
18534       }
18535
18536       function createCharCode(charCodeToGlyphId, glyphId) {
18537         for (var charCode in charCodeToGlyphId) {
18538           if (glyphId === charCodeToGlyphId[charCode]) {
18539             return charCode | 0;
18540           }
18541         }
18542         newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] =
18543             glyphId;
18544         return newMapping.nextAvailableFontCharCode++;
18545       }
18546
18547       var seacs = font.seacs;
18548       if (SEAC_ANALYSIS_ENABLED && seacs && seacs.length) {
18549         var matrix = properties.fontMatrix || FONT_IDENTITY_MATRIX;
18550         var charset = font.getCharset();
18551         var seacMap = Object.create(null);
18552         for (var glyphId in seacs) {
18553           glyphId |= 0;
18554           var seac = seacs[glyphId];
18555           var baseGlyphName = Encodings.StandardEncoding[seac[2]];
18556           var accentGlyphName = Encodings.StandardEncoding[seac[3]];
18557           var baseGlyphId = charset.indexOf(baseGlyphName);
18558           var accentGlyphId = charset.indexOf(accentGlyphName);
18559           if (baseGlyphId < 0 || accentGlyphId < 0) {
18560             continue;
18561           }
18562           var accentOffset = {
18563             x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4],
18564             y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5]
18565           };
18566
18567           var charCodes = getCharCodes(mapping, glyphId);
18568           if (!charCodes) {
18569             // There's no point in mapping it if the char code was never mapped
18570             // to begin with.
18571             continue;
18572           }
18573           for (var i = 0, ii = charCodes.length; i < ii; i++) {
18574             var charCode = charCodes[i];
18575             // Find a fontCharCode that maps to the base and accent glyphs.
18576             // If one doesn't exists, create it.
18577             var charCodeToGlyphId = newMapping.charCodeToGlyphId;
18578             var baseFontCharCode = createCharCode(charCodeToGlyphId,
18579                                                   baseGlyphId);
18580             var accentFontCharCode = createCharCode(charCodeToGlyphId,
18581                                                     accentGlyphId);
18582             seacMap[charCode] = {
18583               baseFontCharCode: baseFontCharCode,
18584               accentFontCharCode: accentFontCharCode,
18585               accentOffset: accentOffset
18586             };
18587           }
18588         }
18589         properties.seacMap = seacMap;
18590       }
18591
18592       var unitsPerEm = 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0];
18593
18594       var builder = new OpenTypeFileBuilder('\x4F\x54\x54\x4F');
18595       // PostScript Font Program
18596       builder.addTable('CFF ', font.data);
18597       // OS/2 and Windows Specific metrics
18598       builder.addTable('OS/2', createOS2Table(properties,
18599                                               newMapping.charCodeToGlyphId));
18600       // Character to glyphs mapping
18601       builder.addTable('cmap', createCmapTable(newMapping.charCodeToGlyphId));
18602       // Font header
18603       builder.addTable('head',
18604             '\x00\x01\x00\x00' + // Version number
18605             '\x00\x00\x10\x00' + // fontRevision
18606             '\x00\x00\x00\x00' + // checksumAdjustement
18607             '\x5F\x0F\x3C\xF5' + // magicNumber
18608             '\x00\x00' + // Flags
18609             safeString16(unitsPerEm) + // unitsPerEM
18610             '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date
18611             '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date
18612             '\x00\x00' + // xMin
18613             safeString16(properties.descent) + // yMin
18614             '\x0F\xFF' + // xMax
18615             safeString16(properties.ascent) + // yMax
18616             string16(properties.italicAngle ? 2 : 0) + // macStyle
18617             '\x00\x11' + // lowestRecPPEM
18618             '\x00\x00' + // fontDirectionHint
18619             '\x00\x00' + // indexToLocFormat
18620             '\x00\x00');  // glyphDataFormat
18621
18622       // Horizontal header
18623       builder.addTable('hhea',
18624             '\x00\x01\x00\x00' + // Version number
18625             safeString16(properties.ascent) + // Typographic Ascent
18626             safeString16(properties.descent) + // Typographic Descent
18627             '\x00\x00' + // Line Gap
18628             '\xFF\xFF' + // advanceWidthMax
18629             '\x00\x00' + // minLeftSidebearing
18630             '\x00\x00' + // minRightSidebearing
18631             '\x00\x00' + // xMaxExtent
18632             safeString16(properties.capHeight) + // caretSlopeRise
18633             safeString16(Math.tan(properties.italicAngle) *
18634                          properties.xHeight) + // caretSlopeRun
18635             '\x00\x00' + // caretOffset
18636             '\x00\x00' + // -reserved-
18637             '\x00\x00' + // -reserved-
18638             '\x00\x00' + // -reserved-
18639             '\x00\x00' + // -reserved-
18640             '\x00\x00' + // metricDataFormat
18641             string16(numGlyphs)); // Number of HMetrics
18642
18643       // Horizontal metrics
18644       builder.addTable('hmtx', (function fontFieldsHmtx() {
18645           var charstrings = font.charstrings;
18646           var cffWidths = font.cff ? font.cff.widths : null;
18647           var hmtx = '\x00\x00\x00\x00'; // Fake .notdef
18648           for (var i = 1, ii = numGlyphs; i < ii; i++) {
18649             var width = 0;
18650             if (charstrings) {
18651               var charstring = charstrings[i - 1];
18652               width = 'width' in charstring ? charstring.width : 0;
18653             } else if (cffWidths) {
18654               width = Math.ceil(cffWidths[i] || 0);
18655             }
18656             hmtx += string16(width) + string16(0);
18657           }
18658           return hmtx;
18659         })());
18660
18661       // Maximum profile
18662       builder.addTable('maxp',
18663             '\x00\x00\x50\x00' + // Version number
18664             string16(numGlyphs)); // Num of glyphs
18665
18666       // Naming tables
18667       builder.addTable('name', createNameTable(fontName));
18668
18669       // PostScript informations
18670       builder.addTable('post', createPostTable(properties));
18671
18672       return builder.toArray();
18673     },
18674
18675     /**
18676      * Builds a char code to unicode map based on section 9.10 of the spec.
18677      * @param {Object} properties Font properties object.
18678      * @return {Object} A ToUnicodeMap object.
18679      */
18680     buildToUnicode: function Font_buildToUnicode(properties) {
18681       // Section 9.10.2 Mapping Character Codes to Unicode Values
18682       if (properties.toUnicode && properties.toUnicode.length !== 0) {
18683         return properties.toUnicode;
18684       }
18685       // According to the spec if the font is a simple font we should only map
18686       // to unicode if the base encoding is MacRoman, MacExpert, or WinAnsi or
18687       // the differences array only contains adobe standard or symbol set names,
18688       // in pratice it seems better to always try to create a toUnicode
18689       // map based of the default encoding.
18690       var toUnicode, charcode;
18691       if (!properties.composite /* is simple font */) {
18692         toUnicode = [];
18693         var encoding = properties.defaultEncoding.slice();
18694         var baseEncodingName = properties.baseEncodingName;
18695         // Merge in the differences array.
18696         var differences = properties.differences;
18697         for (charcode in differences) {
18698           encoding[charcode] = differences[charcode];
18699         }
18700         for (charcode in encoding) {
18701           // a) Map the character code to a character name.
18702           var glyphName = encoding[charcode];
18703           // b) Look up the character name in the Adobe Glyph List (see the
18704           //    Bibliography) to obtain the corresponding Unicode value.
18705           if (glyphName === '') {
18706             continue;
18707           } else if (GlyphsUnicode[glyphName] === undefined) {
18708             // (undocumented) c) Few heuristics to recognize unknown glyphs
18709             // NOTE: Adobe Reader does not do this step, but OSX Preview does
18710             var code = 0;
18711             switch (glyphName[0]) {
18712               case 'G': // Gxx glyph
18713                 if (glyphName.length === 3) {
18714                   code = parseInt(glyphName.substr(1), 16);
18715                 }
18716                 break;
18717               case 'g': // g00xx glyph
18718                 if (glyphName.length === 5) {
18719                   code = parseInt(glyphName.substr(1), 16);
18720                 }
18721                 break;
18722               case 'C': // Cddd glyph
18723               case 'c': // cddd glyph
18724                 if (glyphName.length >= 3) {
18725                   code = +glyphName.substr(1);
18726                 }
18727                 break;
18728             }
18729             if (code) {
18730               // If |baseEncodingName| is one the predefined encodings,
18731               // and |code| equals |charcode|, using the glyph defined in the
18732               // baseEncoding seems to yield a better |toUnicode| mapping
18733               // (fixes issue 5070).
18734               if (baseEncodingName && code === +charcode) {
18735                 var baseEncoding = Encodings[baseEncodingName];
18736                 if (baseEncoding && (glyphName = baseEncoding[charcode])) {
18737                   toUnicode[charcode] =
18738                     String.fromCharCode(GlyphsUnicode[glyphName]);
18739                   continue;
18740                 }
18741               }
18742               toUnicode[charcode] = String.fromCharCode(code);
18743             }
18744             continue;
18745           }
18746           toUnicode[charcode] = String.fromCharCode(GlyphsUnicode[glyphName]);
18747         }
18748         return new ToUnicodeMap(toUnicode);
18749       }
18750       // If the font is a composite font that uses one of the predefined CMaps
18751       // listed in Table 118 (except Identity–H and Identity–V) or whose
18752       // descendant CIDFont uses the Adobe-GB1, Adobe-CNS1, Adobe-Japan1, or
18753       // Adobe-Korea1 character collection:
18754       if (properties.composite && (
18755            (properties.cMap.builtInCMap &&
18756             !(properties.cMap instanceof IdentityCMap)) ||
18757            (properties.cidSystemInfo.registry === 'Adobe' &&
18758              (properties.cidSystemInfo.ordering === 'GB1' ||
18759               properties.cidSystemInfo.ordering === 'CNS1' ||
18760               properties.cidSystemInfo.ordering === 'Japan1' ||
18761               properties.cidSystemInfo.ordering === 'Korea1')))) {
18762         // Then:
18763         // a) Map the character code to a character identifier (CID) according
18764         // to the font’s CMap.
18765         // b) Obtain the registry and ordering of the character collection used
18766         // by the font’s CMap (for example, Adobe and Japan1) from its
18767         // CIDSystemInfo dictionary.
18768         var registry = properties.cidSystemInfo.registry;
18769         var ordering = properties.cidSystemInfo.ordering;
18770         // c) Construct a second CMap name by concatenating the registry and
18771         // ordering obtained in step (b) in the format registry–ordering–UCS2
18772         // (for example, Adobe–Japan1–UCS2).
18773         var ucs2CMapName = new Name(registry + '-' + ordering + '-UCS2');
18774         // d) Obtain the CMap with the name constructed in step (c) (available
18775         // from the ASN Web site; see the Bibliography).
18776         var ucs2CMap = CMapFactory.create(ucs2CMapName,
18777           { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
18778         var cMap = properties.cMap;
18779         toUnicode = [];
18780         cMap.forEach(function(charcode, cid) {
18781           assert(cid <= 0xffff, 'Max size of CID is 65,535');
18782           // e) Map the CID obtained in step (a) according to the CMap obtained
18783           // in step (d), producing a Unicode value.
18784           var ucs2 = ucs2CMap.lookup(cid);
18785           if (ucs2) {
18786             toUnicode[charcode] =
18787               String.fromCharCode((ucs2.charCodeAt(0) << 8) +
18788                                   ucs2.charCodeAt(1));
18789           }
18790         });
18791         return new ToUnicodeMap(toUnicode);
18792       }
18793
18794       // The viewer's choice, just use an identity map.
18795       return new IdentityToUnicodeMap(properties.firstChar,
18796                                       properties.lastChar);
18797     },
18798
18799     get spaceWidth() {
18800       if ('_shadowWidth' in this) {
18801         return this._shadowWidth;
18802       }
18803
18804       // trying to estimate space character width
18805       var possibleSpaceReplacements = ['space', 'minus', 'one', 'i'];
18806       var width;
18807       for (var i = 0, ii = possibleSpaceReplacements.length; i < ii; i++) {
18808         var glyphName = possibleSpaceReplacements[i];
18809         // if possible, getting width by glyph name
18810         if (glyphName in this.widths) {
18811           width = this.widths[glyphName];
18812           break;
18813         }
18814         var glyphUnicode = GlyphsUnicode[glyphName];
18815         // finding the charcode via unicodeToCID map
18816         var charcode = 0;
18817         if (this.composite) {
18818           if (this.cMap.contains(glyphUnicode)) {
18819             charcode = this.cMap.lookup(glyphUnicode);
18820           }
18821         }
18822         // ... via toUnicode map
18823         if (!charcode && 'toUnicode' in this) {
18824           charcode = this.toUnicode.charCodeOf(glyphUnicode);
18825         }
18826         // setting it to unicode if negative or undefined
18827         if (charcode <= 0) {
18828           charcode = glyphUnicode;
18829         }
18830         // trying to get width via charcode
18831         width = this.widths[charcode];
18832         if (width) {
18833           break; // the non-zero width found
18834         }
18835       }
18836       width = width || this.defaultWidth;
18837       // Do not shadow the property here. See discussion:
18838       // https://github.com/mozilla/pdf.js/pull/2127#discussion_r1662280
18839       this._shadowWidth = width;
18840       return width;
18841     },
18842
18843     charToGlyph: function Font_charToGlyph(charcode) {
18844       var fontCharCode, width, operatorListId;
18845
18846       var widthCode = charcode;
18847       if (this.cMap && this.cMap.contains(charcode)) {
18848         widthCode = this.cMap.lookup(charcode);
18849       }
18850       width = this.widths[widthCode];
18851       width = isNum(width) ? width : this.defaultWidth;
18852       var vmetric = this.vmetrics && this.vmetrics[widthCode];
18853
18854       var unicode = this.toUnicode.get(charcode) || charcode;
18855       if (typeof unicode === 'number') {
18856         unicode = String.fromCharCode(unicode);
18857       }
18858
18859       // First try the toFontChar map, if it's not there then try falling
18860       // back to the char code.
18861       fontCharCode = this.toFontChar[charcode] || charcode;
18862       if (this.missingFile) {
18863         fontCharCode = mapSpecialUnicodeValues(fontCharCode);
18864       }
18865
18866       if (this.isType3Font) {
18867         // Font char code in this case is actually a glyph name.
18868         operatorListId = fontCharCode;
18869       }
18870
18871       var accent = null;
18872       if (this.seacMap && this.seacMap[charcode]) {
18873         var seac = this.seacMap[charcode];
18874         fontCharCode = seac.baseFontCharCode;
18875         accent = {
18876           fontChar: String.fromCharCode(seac.accentFontCharCode),
18877           offset: seac.accentOffset
18878         };
18879       }
18880
18881       var fontChar = String.fromCharCode(fontCharCode);
18882
18883       var glyph = this.glyphCache[charcode];
18884       if (!glyph ||
18885           !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric,
18886                                  operatorListId)) {
18887         glyph = new Glyph(fontChar, unicode, accent, width, vmetric,
18888                           operatorListId);
18889         this.glyphCache[charcode] = glyph;
18890       }
18891       return glyph;
18892     },
18893
18894     charsToGlyphs: function Font_charsToGlyphs(chars) {
18895       var charsCache = this.charsCache;
18896       var glyphs, glyph, charcode;
18897
18898       // if we translated this string before, just grab it from the cache
18899       if (charsCache) {
18900         glyphs = charsCache[chars];
18901         if (glyphs) {
18902           return glyphs;
18903         }
18904       }
18905
18906       // lazily create the translation cache
18907       if (!charsCache) {
18908         charsCache = this.charsCache = Object.create(null);
18909       }
18910
18911       glyphs = [];
18912       var charsCacheKey = chars;
18913       var i = 0, ii;
18914
18915       if (this.cMap) {
18916         // composite fonts have multi-byte strings convert the string from
18917         // single-byte to multi-byte
18918         var c = {};
18919         while (i < chars.length) {
18920           this.cMap.readCharCode(chars, i, c);
18921           charcode = c.charcode;
18922           var length = c.length;
18923           i += length;
18924           glyph = this.charToGlyph(charcode);
18925           glyphs.push(glyph);
18926           // placing null after each word break charcode (ASCII SPACE)
18927           // Ignore occurences of 0x20 in multiple-byte codes.
18928           if (length === 1 && chars.charCodeAt(i - 1) === 0x20) {
18929             glyphs.push(null);
18930           }
18931         }
18932       } else {
18933         for (i = 0, ii = chars.length; i < ii; ++i) {
18934           charcode = chars.charCodeAt(i);
18935           glyph = this.charToGlyph(charcode);
18936           glyphs.push(glyph);
18937           if (charcode === 0x20) {
18938             glyphs.push(null);
18939           }
18940         }
18941       }
18942
18943       // Enter the translated string into the cache
18944       return (charsCache[charsCacheKey] = glyphs);
18945     }
18946   };
18947
18948   return Font;
18949 })();
18950
18951 var ErrorFont = (function ErrorFontClosure() {
18952   function ErrorFont(error) {
18953     this.error = error;
18954     this.loadedName = 'g_font_error';
18955     this.loading = false;
18956   }
18957
18958   ErrorFont.prototype = {
18959     charsToGlyphs: function ErrorFont_charsToGlyphs() {
18960       return [];
18961     },
18962     exportData: function ErrorFont_exportData() {
18963       return {error: this.error};
18964     }
18965   };
18966
18967   return ErrorFont;
18968 })();
18969
18970 /**
18971  * Shared logic for building a char code to glyph id mapping for Type1 and
18972  * simple CFF fonts. See section 9.6.6.2 of the spec.
18973  * @param {Object} properties Font properties object.
18974  * @param {Object} builtInEncoding The encoding contained within the actual font
18975  * data.
18976  * @param {Array} Array of glyph names where the index is the glyph ID.
18977  * @returns {Object} A char code to glyph ID map.
18978  */
18979 function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) {
18980   var charCodeToGlyphId = Object.create(null);
18981   var glyphId, charCode, baseEncoding;
18982
18983   if (properties.baseEncodingName) {
18984     // If a valid base encoding name was used, the mapping is initialized with
18985     // that.
18986     baseEncoding = Encodings[properties.baseEncodingName];
18987     for (charCode = 0; charCode < baseEncoding.length; charCode++) {
18988       glyphId = glyphNames.indexOf(baseEncoding[charCode]);
18989       if (glyphId >= 0) {
18990         charCodeToGlyphId[charCode] = glyphId;
18991       } else {
18992         charCodeToGlyphId[charCode] = 0; // notdef
18993       }
18994     }
18995   } else if (!!(properties.flags & FontFlags.Symbolic)) {
18996     // For a symbolic font the encoding should be the fonts built-in
18997     // encoding.
18998     for (charCode in builtInEncoding) {
18999       charCodeToGlyphId[charCode] = builtInEncoding[charCode];
19000     }
19001   } else {
19002     // For non-symbolic fonts that don't have a base encoding the standard
19003     // encoding should be used.
19004     baseEncoding = Encodings.StandardEncoding;
19005     for (charCode = 0; charCode < baseEncoding.length; charCode++) {
19006       glyphId = glyphNames.indexOf(baseEncoding[charCode]);
19007       if (glyphId >= 0) {
19008         charCodeToGlyphId[charCode] = glyphId;
19009       } else {
19010         charCodeToGlyphId[charCode] = 0; // notdef
19011       }
19012     }
19013   }
19014
19015   // Lastly, merge in the differences.
19016   var differences = properties.differences;
19017   if (differences) {
19018     for (charCode in differences) {
19019       var glyphName = differences[charCode];
19020       glyphId = glyphNames.indexOf(glyphName);
19021       if (glyphId >= 0) {
19022         charCodeToGlyphId[charCode] = glyphId;
19023       } else {
19024         charCodeToGlyphId[charCode] = 0; // notdef
19025       }
19026     }
19027   }
19028   return charCodeToGlyphId;
19029 }
19030
19031 /*
19032  * CharStrings are encoded following the the CharString Encoding sequence
19033  * describe in Chapter 6 of the "Adobe Type1 Font Format" specification.
19034  * The value in a byte indicates a command, a number, or subsequent bytes
19035  * that are to be interpreted in a special way.
19036  *
19037  * CharString Number Encoding:
19038  *  A CharString byte containing the values from 32 through 255 inclusive
19039  *  indicate an integer. These values are decoded in four ranges.
19040  *
19041  * 1. A CharString byte containing a value, v, between 32 and 246 inclusive,
19042  * indicate the integer v - 139. Thus, the integer values from -107 through
19043  * 107 inclusive may be encoded in single byte.
19044  *
19045  * 2. A CharString byte containing a value, v, between 247 and 250 inclusive,
19046  * indicates an integer involving the next byte, w, according to the formula:
19047  * [(v - 247) x 256] + w + 108
19048  *
19049  * 3. A CharString byte containing a value, v, between 251 and 254 inclusive,
19050  * indicates an integer involving the next byte, w, according to the formula:
19051  * -[(v - 251) * 256] - w - 108
19052  *
19053  * 4. A CharString containing the value 255 indicates that the next 4 bytes
19054  * are a two complement signed integer. The first of these bytes contains the
19055  * highest order bits, the second byte contains the next higher order bits
19056  * and the fourth byte contain the lowest order bits.
19057  *
19058  *
19059  * CharString Command Encoding:
19060  *  CharStrings commands are encoded in 1 or 2 bytes.
19061  *
19062  *  Single byte commands are encoded in 1 byte that contains a value between
19063  *  0 and 31 inclusive.
19064  *  If a command byte contains the value 12, then the value in the next byte
19065  *  indicates a command. This "escape" mechanism allows many extra commands
19066  * to be encoded and this encoding technique helps to minimize the length of
19067  * the charStrings.
19068  */
19069 var Type1CharString = (function Type1CharStringClosure() {
19070   var COMMAND_MAP = {
19071     'hstem': [1],
19072     'vstem': [3],
19073     'vmoveto': [4],
19074     'rlineto': [5],
19075     'hlineto': [6],
19076     'vlineto': [7],
19077     'rrcurveto': [8],
19078     'callsubr': [10],
19079     'flex': [12, 35],
19080     'drop' : [12, 18],
19081     'endchar': [14],
19082     'rmoveto': [21],
19083     'hmoveto': [22],
19084     'vhcurveto': [30],
19085     'hvcurveto': [31]
19086   };
19087
19088   function Type1CharString() {
19089     this.width = 0;
19090     this.lsb = 0;
19091     this.flexing = false;
19092     this.output = [];
19093     this.stack = [];
19094   }
19095
19096   Type1CharString.prototype = {
19097     convert: function Type1CharString_convert(encoded, subrs) {
19098       var count = encoded.length;
19099       var error = false;
19100       var wx, sbx, subrNumber;
19101       for (var i = 0; i < count; i++) {
19102         var value = encoded[i];
19103         if (value < 32) {
19104           if (value === 12) {
19105             value = (value << 8) + encoded[++i];
19106           }
19107           switch (value) {
19108             case 1: // hstem
19109               if (!HINTING_ENABLED) {
19110                 this.stack = [];
19111                 break;
19112               }
19113               error = this.executeCommand(2, COMMAND_MAP.hstem);
19114               break;
19115             case 3: // vstem
19116               if (!HINTING_ENABLED) {
19117                 this.stack = [];
19118                 break;
19119               }
19120               error = this.executeCommand(2, COMMAND_MAP.vstem);
19121               break;
19122             case 4: // vmoveto
19123               if (this.flexing) {
19124                 if (this.stack.length < 1) {
19125                   error = true;
19126                   break;
19127                 }
19128                 // Add the dx for flex and but also swap the values so they are
19129                 // the right order.
19130                 var dy = this.stack.pop();
19131                 this.stack.push(0, dy);
19132                 break;
19133               }
19134               error = this.executeCommand(1, COMMAND_MAP.vmoveto);
19135               break;
19136             case 5: // rlineto
19137               error = this.executeCommand(2, COMMAND_MAP.rlineto);
19138               break;
19139             case 6: // hlineto
19140               error = this.executeCommand(1, COMMAND_MAP.hlineto);
19141               break;
19142             case 7: // vlineto
19143               error = this.executeCommand(1, COMMAND_MAP.vlineto);
19144               break;
19145             case 8: // rrcurveto
19146               error = this.executeCommand(6, COMMAND_MAP.rrcurveto);
19147               break;
19148             case 9: // closepath
19149               // closepath is a Type1 command that does not take argument and is
19150               // useless in Type2 and it can simply be ignored.
19151               this.stack = [];
19152               break;
19153             case 10: // callsubr
19154               if (this.stack.length < 1) {
19155                 error = true;
19156                 break;
19157               }
19158               subrNumber = this.stack.pop();
19159               error = this.convert(subrs[subrNumber], subrs);
19160               break;
19161             case 11: // return
19162               return error;
19163             case 13: // hsbw
19164               if (this.stack.length < 2) {
19165                 error = true;
19166                 break;
19167               }
19168               // To convert to type2 we have to move the width value to the
19169               // first part of the charstring and then use hmoveto with lsb.
19170               wx = this.stack.pop();
19171               sbx = this.stack.pop();
19172               this.lsb = sbx;
19173               this.width = wx;
19174               this.stack.push(wx, sbx);
19175               error = this.executeCommand(2, COMMAND_MAP.hmoveto);
19176               break;
19177             case 14: // endchar
19178               this.output.push(COMMAND_MAP.endchar[0]);
19179               break;
19180             case 21: // rmoveto
19181               if (this.flexing) {
19182                 break;
19183               }
19184               error = this.executeCommand(2, COMMAND_MAP.rmoveto);
19185               break;
19186             case 22: // hmoveto
19187               if (this.flexing) {
19188                 // Add the dy for flex.
19189                 this.stack.push(0);
19190                 break;
19191               }
19192               error = this.executeCommand(1, COMMAND_MAP.hmoveto);
19193               break;
19194             case 30: // vhcurveto
19195               error = this.executeCommand(4, COMMAND_MAP.vhcurveto);
19196               break;
19197             case 31: // hvcurveto
19198               error = this.executeCommand(4, COMMAND_MAP.hvcurveto);
19199               break;
19200             case (12 << 8) + 0: // dotsection
19201               // dotsection is a Type1 command to specify some hinting feature
19202               // for dots that do not take a parameter and it can safely be
19203               // ignored for Type2.
19204               this.stack = [];
19205               break;
19206             case (12 << 8) + 1: // vstem3
19207               if (!HINTING_ENABLED) {
19208                 this.stack = [];
19209                 break;
19210               }
19211               // [vh]stem3 are Type1 only and Type2 supports [vh]stem with
19212               // multiple parameters, so instead of returning [vh]stem3 take a
19213               // shortcut and return [vhstem] instead.
19214               error = this.executeCommand(2, COMMAND_MAP.vstem);
19215               break;
19216             case (12 << 8) + 2: // hstem3
19217               if (!HINTING_ENABLED) {
19218                  this.stack = [];
19219                 break;
19220               }
19221               // See vstem3.
19222               error = this.executeCommand(2, COMMAND_MAP.hstem);
19223               break;
19224             case (12 << 8) + 6: // seac
19225               // seac is like type 2's special endchar but it doesn't use the
19226               // first argument asb, so remove it.
19227               if (SEAC_ANALYSIS_ENABLED) {
19228                 this.seac = this.stack.splice(-4, 4);
19229                 error = this.executeCommand(0, COMMAND_MAP.endchar);
19230               } else {
19231                 error = this.executeCommand(4, COMMAND_MAP.endchar);
19232               }
19233               break;
19234             case (12 << 8) + 7: // sbw
19235               if (this.stack.length < 4) {
19236                 error = true;
19237                 break;
19238               }
19239               // To convert to type2 we have to move the width value to the
19240               // first part of the charstring and then use rmoveto with
19241               // (dx, dy). The height argument will not be used for vmtx and
19242               // vhea tables reconstruction -- ignoring it.
19243               var wy = this.stack.pop();
19244               wx = this.stack.pop();
19245               var sby = this.stack.pop();
19246               sbx = this.stack.pop();
19247               this.lsb = sbx;
19248               this.width = wx;
19249               this.stack.push(wx, sbx, sby);
19250               error = this.executeCommand(3, COMMAND_MAP.rmoveto);
19251               break;
19252             case (12 << 8) + 12: // div
19253               if (this.stack.length < 2) {
19254                 error = true;
19255                 break;
19256               }
19257               var num2 = this.stack.pop();
19258               var num1 = this.stack.pop();
19259               this.stack.push(num1 / num2);
19260               break;
19261             case (12 << 8) + 16: // callothersubr
19262               if (this.stack.length < 2) {
19263                 error = true;
19264                 break;
19265               }
19266               subrNumber = this.stack.pop();
19267               var numArgs = this.stack.pop();
19268               if (subrNumber === 0 && numArgs === 3) {
19269                 var flexArgs = this.stack.splice(this.stack.length - 17, 17);
19270                 this.stack.push(
19271                   flexArgs[2] + flexArgs[0], // bcp1x + rpx
19272                   flexArgs[3] + flexArgs[1], // bcp1y + rpy
19273                   flexArgs[4], // bcp2x
19274                   flexArgs[5], // bcp2y
19275                   flexArgs[6], // p2x
19276                   flexArgs[7], // p2y
19277                   flexArgs[8], // bcp3x
19278                   flexArgs[9], // bcp3y
19279                   flexArgs[10], // bcp4x
19280                   flexArgs[11], // bcp4y
19281                   flexArgs[12], // p3x
19282                   flexArgs[13], // p3y
19283                   flexArgs[14] // flexDepth
19284                   // 15 = finalx unused by flex
19285                   // 16 = finaly unused by flex
19286                 );
19287                 error = this.executeCommand(13, COMMAND_MAP.flex, true);
19288                 this.flexing = false;
19289                 this.stack.push(flexArgs[15], flexArgs[16]);
19290               } else if (subrNumber === 1 && numArgs === 0) {
19291                 this.flexing = true;
19292               }
19293               break;
19294             case (12 << 8) + 17: // pop
19295               // Ignore this since it is only used with othersubr.
19296               break;
19297             case (12 << 8) + 33: // setcurrentpoint
19298               // Ignore for now.
19299               this.stack = [];
19300               break;
19301             default:
19302               warn('Unknown type 1 charstring command of "' + value + '"');
19303               break;
19304           }
19305           if (error) {
19306             break;
19307           }
19308           continue;
19309         } else if (value <= 246) {
19310           value = value - 139;
19311         } else if (value <= 250) {
19312           value = ((value - 247) * 256) + encoded[++i] + 108;
19313         } else if (value <= 254) {
19314           value = -((value - 251) * 256) - encoded[++i] - 108;
19315         } else {
19316           value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 |
19317                   (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0;
19318         }
19319         this.stack.push(value);
19320       }
19321       return error;
19322     },
19323
19324     executeCommand: function(howManyArgs, command, keepStack) {
19325       var stackLength = this.stack.length;
19326       if (howManyArgs > stackLength) {
19327         return true;
19328       }
19329       var start = stackLength - howManyArgs;
19330       for (var i = start; i < stackLength; i++) {
19331         var value = this.stack[i];
19332         if (value === (value | 0)) { // int
19333           this.output.push(28, (value >> 8) & 0xff, value & 0xff);
19334         } else { // fixed point
19335           value = (65536 * value) | 0;
19336           this.output.push(255,
19337                            (value >> 24) & 0xFF,
19338                            (value >> 16) & 0xFF,
19339                            (value >> 8) & 0xFF,
19340                            value & 0xFF);
19341         }
19342       }
19343       this.output.push.apply(this.output, command);
19344       if (keepStack) {
19345         this.stack.splice(start, howManyArgs);
19346       } else {
19347         this.stack.length = 0;
19348       }
19349       return false;
19350     }
19351   };
19352
19353   return Type1CharString;
19354 })();
19355
19356 /*
19357  * Type1Parser encapsulate the needed code for parsing a Type1 font
19358  * program. Some of its logic depends on the Type2 charstrings
19359  * structure.
19360  * Note: this doesn't really parse the font since that would require evaluation
19361  * of PostScript, but it is possible in most cases to extract what we need
19362  * without a full parse.
19363  */
19364 var Type1Parser = (function Type1ParserClosure() {
19365   /*
19366    * Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence
19367    * of Plaintext Bytes. The function took a key as a parameter which can be
19368    * for decrypting the eexec block of for decoding charStrings.
19369    */
19370   var EEXEC_ENCRYPT_KEY = 55665;
19371   var CHAR_STRS_ENCRYPT_KEY = 4330;
19372
19373   function isHexDigit(code) {
19374     return code >= 48 && code <= 57 || // '0'-'9'
19375            code >= 65 && code <= 70 || // 'A'-'F'
19376            code >= 97 && code <= 102;  // 'a'-'f'
19377   }
19378
19379   function decrypt(data, key, discardNumber) {
19380     var r = key | 0, c1 = 52845, c2 = 22719;
19381     var count = data.length;
19382     var decrypted = new Uint8Array(count);
19383     for (var i = 0; i < count; i++) {
19384       var value = data[i];
19385       decrypted[i] = value ^ (r >> 8);
19386       r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
19387     }
19388     return Array.prototype.slice.call(decrypted, discardNumber);
19389   }
19390
19391   function decryptAscii(data, key, discardNumber) {
19392     var r = key | 0, c1 = 52845, c2 = 22719;
19393     var count = data.length, maybeLength = count >>> 1;
19394     var decrypted = new Uint8Array(maybeLength);
19395     var i, j;
19396     for (i = 0, j = 0; i < count; i++) {
19397       var digit1 = data[i];
19398       if (!isHexDigit(digit1)) {
19399         continue;
19400       }
19401       i++;
19402       var digit2;
19403       while (i < count && !isHexDigit(digit2 = data[i])) {
19404         i++;
19405       }
19406       if (i < count) {
19407         var value = parseInt(String.fromCharCode(digit1, digit2), 16);
19408         decrypted[j++] = value ^ (r >> 8);
19409         r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
19410       }
19411     }
19412     return Array.prototype.slice.call(decrypted, discardNumber, j);
19413   }
19414
19415   function isSpecial(c) {
19416     return c === 0x2F || // '/'
19417            c === 0x5B || c === 0x5D || // '[', ']'
19418            c === 0x7B || c === 0x7D || // '{', '}'
19419            c === 0x28 || c === 0x29; // '(', ')'
19420   }
19421
19422   function Type1Parser(stream, encrypted) {
19423     if (encrypted) {
19424       var data = stream.getBytes();
19425       var isBinary = !(isHexDigit(data[0]) && isHexDigit(data[1]) &&
19426                        isHexDigit(data[2]) && isHexDigit(data[3]));
19427       stream = new Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) :
19428                           decryptAscii(data, EEXEC_ENCRYPT_KEY, 4));
19429     }
19430     this.stream = stream;
19431     this.nextChar();
19432   }
19433
19434   Type1Parser.prototype = {
19435     readNumberArray: function Type1Parser_readNumberArray() {
19436       this.getToken(); // read '[' or '{' (arrays can start with either)
19437       var array = [];
19438       while (true) {
19439         var token = this.getToken();
19440         if (token === null || token === ']' || token === '}') {
19441           break;
19442         }
19443         array.push(parseFloat(token || 0));
19444       }
19445       return array;
19446     },
19447
19448     readNumber: function Type1Parser_readNumber() {
19449       var token = this.getToken();
19450       return parseFloat(token || 0);
19451     },
19452
19453     readInt: function Type1Parser_readInt() {
19454       // Use '| 0' to prevent setting a double into length such as the double
19455       // does not flow into the loop variable.
19456       var token = this.getToken();
19457       return parseInt(token || 0, 10) | 0;
19458     },
19459
19460     readBoolean: function Type1Parser_readBoolean() {
19461       var token = this.getToken();
19462
19463       // Use 1 and 0 since that's what type2 charstrings use.
19464       return token === 'true' ? 1 : 0;
19465     },
19466
19467     nextChar : function Type1_nextChar() {
19468       return (this.currentChar = this.stream.getByte());
19469     },
19470
19471     getToken: function Type1Parser_getToken() {
19472       // Eat whitespace and comments.
19473       var comment = false;
19474       var ch = this.currentChar;
19475       while (true) {
19476         if (ch === -1) {
19477           return null;
19478         }
19479
19480         if (comment) {
19481           if (ch === 0x0A || ch === 0x0D) {
19482             comment = false;
19483           }
19484         } else if (ch === 0x25) { // '%'
19485           comment = true;
19486         } else if (!Lexer.isSpace(ch)) {
19487           break;
19488         }
19489         ch = this.nextChar();
19490       }
19491       if (isSpecial(ch)) {
19492         this.nextChar();
19493         return String.fromCharCode(ch);
19494       }
19495       var token = '';
19496       do {
19497         token += String.fromCharCode(ch);
19498         ch = this.nextChar();
19499       } while (ch >= 0 && !Lexer.isSpace(ch) && !isSpecial(ch));
19500       return token;
19501     },
19502
19503     /*
19504      * Returns an object containing a Subrs array and a CharStrings
19505      * array extracted from and eexec encrypted block of data
19506      */
19507     extractFontProgram: function Type1Parser_extractFontProgram() {
19508       var stream = this.stream;
19509
19510       var subrs = [], charstrings = [];
19511       var program = {
19512         subrs: [],
19513         charstrings: [],
19514         properties: {
19515           'privateData': {
19516             'lenIV': 4
19517           }
19518         }
19519       };
19520       var token, length, data, lenIV, encoded;
19521       while ((token = this.getToken()) !== null) {
19522         if (token !== '/') {
19523           continue;
19524         }
19525         token = this.getToken();
19526         switch (token) {
19527           case 'CharStrings':
19528             // The number immediately following CharStrings must be greater or
19529             // equal to the number of CharStrings.
19530             this.getToken();
19531             this.getToken(); // read in 'dict'
19532             this.getToken(); // read in 'dup'
19533             this.getToken(); // read in 'begin'
19534             while(true) {
19535               token = this.getToken();
19536               if (token === null || token === 'end') {
19537                 break;
19538               }
19539
19540               if (token !== '/') {
19541                 continue;
19542               }
19543               var glyph = this.getToken();
19544               length = this.readInt();
19545               this.getToken(); // read in 'RD' or '-|'
19546               data = stream.makeSubStream(stream.pos, length);
19547               lenIV = program.properties.privateData['lenIV'];
19548               encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);
19549               // Skip past the required space and binary data.
19550               stream.skip(length);
19551               this.nextChar();
19552               token = this.getToken(); // read in 'ND' or '|-'
19553               if (token === 'noaccess') {
19554                 this.getToken(); // read in 'def'
19555               }
19556               charstrings.push({
19557                 glyph: glyph,
19558                 encoded: encoded
19559               });
19560             }
19561             break;
19562           case 'Subrs':
19563             var num = this.readInt();
19564             this.getToken(); // read in 'array'
19565             while ((token = this.getToken()) === 'dup') {
19566               var index = this.readInt();
19567               length = this.readInt();
19568               this.getToken(); // read in 'RD' or '-|'
19569               data = stream.makeSubStream(stream.pos, length);
19570               lenIV = program.properties.privateData['lenIV'];
19571               encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);
19572               // Skip past the required space and binary data.
19573               stream.skip(length);
19574               this.nextChar();
19575               token = this.getToken(); // read in 'NP' or '|'
19576               if (token === 'noaccess') {
19577                 this.getToken(); // read in 'put'
19578               }
19579               subrs[index] = encoded;
19580             }
19581             break;
19582           case 'BlueValues':
19583           case 'OtherBlues':
19584           case 'FamilyBlues':
19585           case 'FamilyOtherBlues':
19586             var blueArray = this.readNumberArray();
19587             // *Blue* values may contain invalid data: disables reading of
19588             // those values when hinting is disabled.
19589             if (blueArray.length > 0 && (blueArray.length % 2) === 0 &&
19590                 HINTING_ENABLED) {
19591               program.properties.privateData[token] = blueArray;
19592             }
19593             break;
19594           case 'StemSnapH':
19595           case 'StemSnapV':
19596             program.properties.privateData[token] = this.readNumberArray();
19597             break;
19598           case 'StdHW':
19599           case 'StdVW':
19600             program.properties.privateData[token] =
19601               this.readNumberArray()[0];
19602             break;
19603           case 'BlueShift':
19604           case 'lenIV':
19605           case 'BlueFuzz':
19606           case 'BlueScale':
19607           case 'LanguageGroup':
19608           case 'ExpansionFactor':
19609             program.properties.privateData[token] = this.readNumber();
19610             break;
19611           case 'ForceBold':
19612             program.properties.privateData[token] = this.readBoolean();
19613             break;
19614         }
19615       }
19616
19617       for (var i = 0; i < charstrings.length; i++) {
19618         glyph = charstrings[i].glyph;
19619         encoded = charstrings[i].encoded;
19620         var charString = new Type1CharString();
19621         var error = charString.convert(encoded, subrs);
19622         var output = charString.output;
19623         if (error) {
19624           // It seems when FreeType encounters an error while evaluating a glyph
19625           // that it completely ignores the glyph so we'll mimic that behaviour
19626           // here and put an endchar to make the validator happy.
19627           output = [14];
19628         }
19629         program.charstrings.push({
19630           glyphName: glyph,
19631           charstring: output,
19632           width: charString.width,
19633           lsb: charString.lsb,
19634           seac: charString.seac
19635         });
19636       }
19637
19638       return program;
19639     },
19640
19641     extractFontHeader: function Type1Parser_extractFontHeader(properties) {
19642       var token;
19643       while ((token = this.getToken()) !== null) {
19644         if (token !== '/') {
19645           continue;
19646         }
19647         token = this.getToken();
19648         switch (token) {
19649           case 'FontMatrix':
19650             var matrix = this.readNumberArray();
19651             properties.fontMatrix = matrix;
19652             break;
19653           case 'Encoding':
19654             var encodingArg = this.getToken();
19655             var encoding;
19656             if (!/^\d+$/.test(encodingArg)) {
19657               // encoding name is specified
19658               encoding = Encodings[encodingArg];
19659             } else {
19660               encoding = [];
19661               var size = parseInt(encodingArg, 10) | 0;
19662               this.getToken(); // read in 'array'
19663
19664               for (var j = 0; j < size; j++) {
19665                 token = this.getToken();
19666                 // skipping till first dup or def (e.g. ignoring for statement)
19667                 while (token !== 'dup' && token !== 'def') {
19668                   token = this.getToken();
19669                   if (token === null) {
19670                     return; // invalid header
19671                   }
19672                 }
19673                 if (token === 'def') {
19674                   break; // read all array data
19675                 }
19676                 var index = this.readInt();
19677                 this.getToken(); // read in '/'
19678                 var glyph = this.getToken();
19679                 encoding[index] = glyph;
19680                 this.getToken(); // read the in 'put'
19681               }
19682             }
19683             properties.builtInEncoding = encoding;
19684             break;
19685           case 'FontBBox':
19686             var fontBBox = this.readNumberArray();
19687             // adjusting ascent/descent
19688             properties.ascent = fontBBox[3];
19689             properties.descent = fontBBox[1];
19690             properties.ascentScaled = true;
19691             break;
19692         }
19693       }
19694     }
19695   };
19696
19697   return Type1Parser;
19698 })();
19699
19700 /**
19701  * The CFF class takes a Type1 file and wrap it into a
19702  * 'Compact Font Format' which itself embed Type2 charstrings.
19703  */
19704 var CFFStandardStrings = [
19705   '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
19706   'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
19707   'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
19708   'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
19709   'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
19710   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
19711   'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum',
19712   'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
19713   'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
19714   'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
19715   'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
19716   'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
19717   'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
19718   'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase',
19719   'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown',
19720   'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent',
19721   'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash',
19722   'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae',
19723   'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior',
19724   'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn',
19725   'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters',
19726   'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior',
19727   'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring',
19728   'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',
19729   'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',
19730   'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',
19731   'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',
19732   'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde',
19733   'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute',
19734   'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex',
19735   'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex',
19736   'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall',
19737   'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall',
19738   'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
19739   'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle',
19740   'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle',
19741   'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior',
19742   'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior',
19743   'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior',
19744   'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
19745   'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior',
19746   'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall',
19747   'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',
19748   'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
19749   'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
19750   'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',
19751   'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',
19752   'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall',
19753   'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior',
19754   'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth',
19755   'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds',
19756   'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',
19757   'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior',
19758   'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior',
19759   'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior',
19760   'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior',
19761   'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall',
19762   'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall',
19763   'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall',
19764   'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall',
19765   'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall',
19766   'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall',
19767   'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall',
19768   'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003',
19769   'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold'
19770 ];
19771
19772 // Type1Font is also a CIDFontType0.
19773 var Type1Font = function Type1Font(name, file, properties) {
19774   // Some bad generators embed pfb file as is, we have to strip 6-byte headers.
19775   // Also, length1 and length2 might be off by 6 bytes as well.
19776   // http://www.math.ubc.ca/~cass/piscript/type1.pdf
19777   var PFB_HEADER_SIZE = 6;
19778   var headerBlockLength = properties.length1;
19779   var eexecBlockLength = properties.length2;
19780   var pfbHeader = file.peekBytes(PFB_HEADER_SIZE);
19781   var pfbHeaderPresent = pfbHeader[0] === 0x80 && pfbHeader[1] === 0x01;
19782   if (pfbHeaderPresent) {
19783     file.skip(PFB_HEADER_SIZE);
19784     headerBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) |
19785                         (pfbHeader[3] << 8) | pfbHeader[2];
19786   }
19787
19788   // Get the data block containing glyphs and subrs informations
19789   var headerBlock = new Stream(file.getBytes(headerBlockLength));
19790   var headerBlockParser = new Type1Parser(headerBlock);
19791   headerBlockParser.extractFontHeader(properties);
19792
19793   if (pfbHeaderPresent) {
19794     pfbHeader = file.getBytes(PFB_HEADER_SIZE);
19795     eexecBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) |
19796                        (pfbHeader[3] << 8) | pfbHeader[2];
19797   }
19798
19799   // Decrypt the data blocks and retrieve it's content
19800   var eexecBlock = new Stream(file.getBytes(eexecBlockLength));
19801   var eexecBlockParser = new Type1Parser(eexecBlock, true);
19802   var data = eexecBlockParser.extractFontProgram();
19803   for (var info in data.properties) {
19804     properties[info] = data.properties[info];
19805   }
19806
19807   var charstrings = data.charstrings;
19808   var type2Charstrings = this.getType2Charstrings(charstrings);
19809   var subrs = this.getType2Subrs(data.subrs);
19810
19811   this.charstrings = charstrings;
19812   this.data = this.wrap(name, type2Charstrings, this.charstrings,
19813                         subrs, properties);
19814   this.seacs = this.getSeacs(data.charstrings);
19815 };
19816
19817 Type1Font.prototype = {
19818   get numGlyphs() {
19819     return this.charstrings.length + 1;
19820   },
19821
19822   getCharset: function Type1Font_getCharset() {
19823     var charset = ['.notdef'];
19824     var charstrings = this.charstrings;
19825     for (var glyphId = 0; glyphId < charstrings.length; glyphId++) {
19826       charset.push(charstrings[glyphId].glyphName);
19827     }
19828     return charset;
19829   },
19830
19831   getGlyphMapping: function Type1Font_getGlyphMapping(properties) {
19832     var charstrings = this.charstrings;
19833     var glyphNames = ['.notdef'], glyphId;
19834     for (glyphId = 0; glyphId < charstrings.length; glyphId++) {
19835       glyphNames.push(charstrings[glyphId].glyphName);
19836     }
19837     var encoding = properties.builtInEncoding;
19838     if (encoding) {
19839       var builtInEncoding = {};
19840       for (var charCode in encoding) {
19841         glyphId = glyphNames.indexOf(encoding[charCode]);
19842         if (glyphId >= 0) {
19843           builtInEncoding[charCode] = glyphId;
19844         }
19845       }
19846     }
19847
19848     return type1FontGlyphMapping(properties, builtInEncoding, glyphNames);
19849   },
19850
19851   getSeacs: function Type1Font_getSeacs(charstrings) {
19852     var i, ii;
19853     var seacMap = [];
19854     for (i = 0, ii = charstrings.length; i < ii; i++) {
19855       var charstring = charstrings[i];
19856       if (charstring.seac) {
19857         // Offset by 1 for .notdef
19858         seacMap[i + 1] = charstring.seac;
19859       }
19860     }
19861     return seacMap;
19862   },
19863
19864   getType2Charstrings: function Type1Font_getType2Charstrings(
19865                                   type1Charstrings) {
19866     var type2Charstrings = [];
19867     for (var i = 0, ii = type1Charstrings.length; i < ii; i++) {
19868       type2Charstrings.push(type1Charstrings[i].charstring);
19869     }
19870     return type2Charstrings;
19871   },
19872
19873   getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) {
19874     var bias = 0;
19875     var count = type1Subrs.length;
19876     if (count < 1133) {
19877       bias = 107;
19878     } else if (count < 33769) {
19879       bias = 1131;
19880     } else {
19881       bias = 32768;
19882     }
19883
19884     // Add a bunch of empty subrs to deal with the Type2 bias
19885     var type2Subrs = [];
19886     var i;
19887     for (i = 0; i < bias; i++) {
19888       type2Subrs.push([0x0B]);
19889     }
19890
19891     for (i = 0; i < count; i++) {
19892       type2Subrs.push(type1Subrs[i]);
19893     }
19894
19895     return type2Subrs;
19896   },
19897
19898   wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) {
19899     var cff = new CFF();
19900     cff.header = new CFFHeader(1, 0, 4, 4);
19901
19902     cff.names = [name];
19903
19904     var topDict = new CFFTopDict();
19905     // CFF strings IDs 0...390 are predefined names, so refering
19906     // to entries in our own String INDEX starts at SID 391.
19907     topDict.setByName('version', 391);
19908     topDict.setByName('Notice', 392);
19909     topDict.setByName('FullName', 393);
19910     topDict.setByName('FamilyName', 394);
19911     topDict.setByName('Weight', 395);
19912     topDict.setByName('Encoding', null); // placeholder
19913     topDict.setByName('FontMatrix', properties.fontMatrix);
19914     topDict.setByName('FontBBox', properties.bbox);
19915     topDict.setByName('charset', null); // placeholder
19916     topDict.setByName('CharStrings', null); // placeholder
19917     topDict.setByName('Private', null); // placeholder
19918     cff.topDict = topDict;
19919
19920     var strings = new CFFStrings();
19921     strings.add('Version 0.11'); // Version
19922     strings.add('See original notice'); // Notice
19923     strings.add(name); // FullName
19924     strings.add(name); // FamilyName
19925     strings.add('Medium'); // Weight
19926     cff.strings = strings;
19927
19928     cff.globalSubrIndex = new CFFIndex();
19929
19930     var count = glyphs.length;
19931     var charsetArray = [0];
19932     var i, ii;
19933     for (i = 0; i < count; i++) {
19934       var index = CFFStandardStrings.indexOf(charstrings[i].glyphName);
19935       // TODO: Insert the string and correctly map it.  Previously it was
19936       // thought mapping names that aren't in the standard strings to .notdef
19937       // was fine, however in issue818 when mapping them all to .notdef the
19938       // adieresis glyph no longer worked.
19939       if (index === -1) {
19940         index = 0;
19941       }
19942       charsetArray.push((index >> 8) & 0xff, index & 0xff);
19943     }
19944     cff.charset = new CFFCharset(false, 0, [], charsetArray);
19945
19946     var charStringsIndex = new CFFIndex();
19947     charStringsIndex.add([0x8B, 0x0E]); // .notdef
19948     for (i = 0; i < count; i++) {
19949       charStringsIndex.add(glyphs[i]);
19950     }
19951     cff.charStrings = charStringsIndex;
19952
19953     var privateDict = new CFFPrivateDict();
19954     privateDict.setByName('Subrs', null); // placeholder
19955     var fields = [
19956       'BlueValues',
19957       'OtherBlues',
19958       'FamilyBlues',
19959       'FamilyOtherBlues',
19960       'StemSnapH',
19961       'StemSnapV',
19962       'BlueShift',
19963       'BlueFuzz',
19964       'BlueScale',
19965       'LanguageGroup',
19966       'ExpansionFactor',
19967       'ForceBold',
19968       'StdHW',
19969       'StdVW'
19970     ];
19971     for (i = 0, ii = fields.length; i < ii; i++) {
19972       var field = fields[i];
19973       if (!properties.privateData.hasOwnProperty(field)) {
19974         continue;
19975       }
19976       var value = properties.privateData[field];
19977       if (isArray(value)) {
19978         // All of the private dictionary array data in CFF must be stored as
19979         // "delta-encoded" numbers.
19980         for (var j = value.length - 1; j > 0; j--) {
19981           value[j] -= value[j - 1]; // ... difference from previous value
19982         }
19983       }
19984       privateDict.setByName(field, value);
19985     }
19986     cff.topDict.privateDict = privateDict;
19987
19988     var subrIndex = new CFFIndex();
19989     for (i = 0, ii = subrs.length; i < ii; i++) {
19990       subrIndex.add(subrs[i]);
19991     }
19992     privateDict.subrsIndex = subrIndex;
19993
19994     var compiler = new CFFCompiler(cff);
19995     return compiler.compile();
19996   }
19997 };
19998
19999 var CFFFont = (function CFFFontClosure() {
20000   function CFFFont(file, properties) {
20001     this.properties = properties;
20002
20003     var parser = new CFFParser(file, properties);
20004     this.cff = parser.parse();
20005     var compiler = new CFFCompiler(this.cff);
20006     this.seacs = this.cff.seacs;
20007     try {
20008       this.data = compiler.compile();
20009     } catch (e) {
20010       warn('Failed to compile font ' + properties.loadedName);
20011       // There may have just been an issue with the compiler, set the data
20012       // anyway and hope the font loaded.
20013       this.data = file;
20014     }
20015   }
20016
20017   CFFFont.prototype = {
20018     get numGlyphs() {
20019       return this.cff.charStrings.count;
20020     },
20021     getCharset: function CFFFont_getCharset() {
20022       return this.cff.charset.charset;
20023     },
20024     getGlyphMapping: function CFFFont_getGlyphMapping() {
20025       var cff = this.cff;
20026       var properties = this.properties;
20027       var charsets = cff.charset.charset;
20028       var charCodeToGlyphId;
20029       var glyphId;
20030
20031       if (properties.composite) {
20032         charCodeToGlyphId = Object.create(null);
20033         if (cff.isCIDFont) {
20034           // If the font is actually a CID font then we should use the charset
20035           // to map CIDs to GIDs.
20036           for (glyphId = 0; glyphId < charsets.length; glyphId++) {
20037             var cid = charsets[glyphId];
20038             var charCode = properties.cMap.charCodeOf(cid);
20039             charCodeToGlyphId[charCode] = glyphId;
20040           }
20041         } else {
20042           // If it is NOT actually a CID font then CIDs should be mapped
20043           // directly to GIDs.
20044           for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) {
20045             charCodeToGlyphId[glyphId] = glyphId;
20046           }
20047         }
20048         return charCodeToGlyphId;
20049       }
20050
20051       var encoding = cff.encoding ? cff.encoding.encoding : null;
20052       charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets);
20053       return charCodeToGlyphId;
20054     }
20055   };
20056
20057   return CFFFont;
20058 })();
20059
20060 var CFFParser = (function CFFParserClosure() {
20061   var CharstringValidationData = [
20062     null,
20063     { id: 'hstem', min: 2, stackClearing: true, stem: true },
20064     null,
20065     { id: 'vstem', min: 2, stackClearing: true, stem: true },
20066     { id: 'vmoveto', min: 1, stackClearing: true },
20067     { id: 'rlineto', min: 2, resetStack: true },
20068     { id: 'hlineto', min: 1, resetStack: true },
20069     { id: 'vlineto', min: 1, resetStack: true },
20070     { id: 'rrcurveto', min: 6, resetStack: true },
20071     null,
20072     { id: 'callsubr', min: 1, undefStack: true },
20073     { id: 'return', min: 0, undefStack: true },
20074     null, // 12
20075     null,
20076     { id: 'endchar', min: 0, stackClearing: true },
20077     null,
20078     null,
20079     null,
20080     { id: 'hstemhm', min: 2, stackClearing: true, stem: true },
20081     { id: 'hintmask', min: 0, stackClearing: true },
20082     { id: 'cntrmask', min: 0, stackClearing: true },
20083     { id: 'rmoveto', min: 2, stackClearing: true },
20084     { id: 'hmoveto', min: 1, stackClearing: true },
20085     { id: 'vstemhm', min: 2, stackClearing: true, stem: true },
20086     { id: 'rcurveline', min: 8, resetStack: true },
20087     { id: 'rlinecurve', min: 8, resetStack: true },
20088     { id: 'vvcurveto', min: 4, resetStack: true },
20089     { id: 'hhcurveto', min: 4, resetStack: true },
20090     null, // shortint
20091     { id: 'callgsubr', min: 1, undefStack: true },
20092     { id: 'vhcurveto', min: 4, resetStack: true },
20093     { id: 'hvcurveto', min: 4, resetStack: true }
20094   ];
20095   var CharstringValidationData12 = [
20096     null,
20097     null,
20098     null,
20099     { id: 'and', min: 2, stackDelta: -1 },
20100     { id: 'or', min: 2, stackDelta: -1 },
20101     { id: 'not', min: 1, stackDelta: 0 },
20102     null,
20103     null,
20104     null,
20105     { id: 'abs', min: 1, stackDelta: 0 },
20106     { id: 'add', min: 2, stackDelta: -1,
20107       stackFn: function stack_div(stack, index) {
20108         stack[index - 2] = stack[index - 2] + stack[index - 1];
20109       }
20110     },
20111     { id: 'sub', min: 2, stackDelta: -1,
20112       stackFn: function stack_div(stack, index) {
20113         stack[index - 2] = stack[index - 2] - stack[index - 1];
20114       }
20115     },
20116     { id: 'div', min: 2, stackDelta: -1,
20117       stackFn: function stack_div(stack, index) {
20118         stack[index - 2] = stack[index - 2] / stack[index - 1];
20119       }
20120     },
20121     null,
20122     { id: 'neg', min: 1, stackDelta: 0,
20123       stackFn: function stack_div(stack, index) {
20124         stack[index - 1] = -stack[index - 1];
20125       }
20126     },
20127     { id: 'eq', min: 2, stackDelta: -1 },
20128     null,
20129     null,
20130     { id: 'drop', min: 1, stackDelta: -1 },
20131     null,
20132     { id: 'put', min: 2, stackDelta: -2 },
20133     { id: 'get', min: 1, stackDelta: 0 },
20134     { id: 'ifelse', min: 4, stackDelta: -3 },
20135     { id: 'random', min: 0, stackDelta: 1 },
20136     { id: 'mul', min: 2, stackDelta: -1,
20137       stackFn: function stack_div(stack, index) {
20138         stack[index - 2] = stack[index - 2] * stack[index - 1];
20139       }
20140     },
20141     null,
20142     { id: 'sqrt', min: 1, stackDelta: 0 },
20143     { id: 'dup', min: 1, stackDelta: 1 },
20144     { id: 'exch', min: 2, stackDelta: 0 },
20145     { id: 'index', min: 2, stackDelta: 0 },
20146     { id: 'roll', min: 3, stackDelta: -2 },
20147     null,
20148     null,
20149     null,
20150     { id: 'hflex', min: 7, resetStack: true },
20151     { id: 'flex', min: 13, resetStack: true },
20152     { id: 'hflex1', min: 9, resetStack: true },
20153     { id: 'flex1', min: 11, resetStack: true }
20154   ];
20155
20156   function CFFParser(file, properties) {
20157     this.bytes = file.getBytes();
20158     this.properties = properties;
20159   }
20160   CFFParser.prototype = {
20161     parse: function CFFParser_parse() {
20162       var properties = this.properties;
20163       var cff = new CFF();
20164       this.cff = cff;
20165
20166       // The first five sections must be in order, all the others are reached
20167       // via offsets contained in one of the below.
20168       var header = this.parseHeader();
20169       var nameIndex = this.parseIndex(header.endPos);
20170       var topDictIndex = this.parseIndex(nameIndex.endPos);
20171       var stringIndex = this.parseIndex(topDictIndex.endPos);
20172       var globalSubrIndex = this.parseIndex(stringIndex.endPos);
20173
20174       var topDictParsed = this.parseDict(topDictIndex.obj.get(0));
20175       var topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings);
20176
20177       cff.header = header.obj;
20178       cff.names = this.parseNameIndex(nameIndex.obj);
20179       cff.strings = this.parseStringIndex(stringIndex.obj);
20180       cff.topDict = topDict;
20181       cff.globalSubrIndex = globalSubrIndex.obj;
20182
20183       this.parsePrivateDict(cff.topDict);
20184
20185       cff.isCIDFont = topDict.hasName('ROS');
20186
20187       var charStringOffset = topDict.getByName('CharStrings');
20188       var charStringsAndSeacs = this.parseCharStrings(charStringOffset);
20189       cff.charStrings = charStringsAndSeacs.charStrings;
20190       cff.seacs = charStringsAndSeacs.seacs;
20191       cff.widths = charStringsAndSeacs.widths;
20192
20193       var fontMatrix = topDict.getByName('FontMatrix');
20194       if (fontMatrix) {
20195         properties.fontMatrix = fontMatrix;
20196       }
20197
20198       var fontBBox = topDict.getByName('FontBBox');
20199       if (fontBBox) {
20200         // adjusting ascent/descent
20201         properties.ascent = fontBBox[3];
20202         properties.descent = fontBBox[1];
20203         properties.ascentScaled = true;
20204       }
20205
20206       var charset, encoding;
20207       if (cff.isCIDFont) {
20208         var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj;
20209         for (var i = 0, ii = fdArrayIndex.count; i < ii; ++i) {
20210           var dictRaw = fdArrayIndex.get(i);
20211           var fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw),
20212                                          cff.strings);
20213           this.parsePrivateDict(fontDict);
20214           cff.fdArray.push(fontDict);
20215         }
20216         // cid fonts don't have an encoding
20217         encoding = null;
20218         charset = this.parseCharsets(topDict.getByName('charset'),
20219                                      cff.charStrings.count, cff.strings, true);
20220         cff.fdSelect = this.parseFDSelect(topDict.getByName('FDSelect'),
20221                                              cff.charStrings.count);
20222       } else {
20223         charset = this.parseCharsets(topDict.getByName('charset'),
20224                                      cff.charStrings.count, cff.strings, false);
20225         encoding = this.parseEncoding(topDict.getByName('Encoding'),
20226                                       properties,
20227                                       cff.strings, charset.charset);
20228       }
20229       cff.charset = charset;
20230       cff.encoding = encoding;
20231
20232       return cff;
20233     },
20234     parseHeader: function CFFParser_parseHeader() {
20235       var bytes = this.bytes;
20236       var bytesLength = bytes.length;
20237       var offset = 0;
20238
20239       // Prevent an infinite loop, by checking that the offset is within the
20240       // bounds of the bytes array. Necessary in empty, or invalid, font files.
20241       while (offset < bytesLength && bytes[offset] !== 1) {
20242         ++offset;
20243       }
20244       if (offset >= bytesLength) {
20245         error('Invalid CFF header');
20246       } else if (offset !== 0) {
20247         info('cff data is shifted');
20248         bytes = bytes.subarray(offset);
20249         this.bytes = bytes;
20250       }
20251       var major = bytes[0];
20252       var minor = bytes[1];
20253       var hdrSize = bytes[2];
20254       var offSize = bytes[3];
20255       var header = new CFFHeader(major, minor, hdrSize, offSize);
20256       return { obj: header, endPos: hdrSize };
20257     },
20258     parseDict: function CFFParser_parseDict(dict) {
20259       var pos = 0;
20260
20261       function parseOperand() {
20262         var value = dict[pos++];
20263         if (value === 30) {
20264           return parseFloatOperand(pos);
20265         } else if (value === 28) {
20266           value = dict[pos++];
20267           value = ((value << 24) | (dict[pos++] << 16)) >> 16;
20268           return value;
20269         } else if (value === 29) {
20270           value = dict[pos++];
20271           value = (value << 8) | dict[pos++];
20272           value = (value << 8) | dict[pos++];
20273           value = (value << 8) | dict[pos++];
20274           return value;
20275         } else if (value >= 32 && value <= 246) {
20276           return value - 139;
20277         } else if (value >= 247 && value <= 250) {
20278           return ((value - 247) * 256) + dict[pos++] + 108;
20279         } else if (value >= 251 && value <= 254) {
20280           return -((value - 251) * 256) - dict[pos++] - 108;
20281         } else {
20282           error('255 is not a valid DICT command');
20283         }
20284         return -1;
20285       }
20286
20287       function parseFloatOperand() {
20288         var str = '';
20289         var eof = 15;
20290         var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8',
20291             '9', '.', 'E', 'E-', null, '-'];
20292         var length = dict.length;
20293         while (pos < length) {
20294           var b = dict[pos++];
20295           var b1 = b >> 4;
20296           var b2 = b & 15;
20297
20298           if (b1 === eof) {
20299             break;
20300           }
20301           str += lookup[b1];
20302
20303           if (b2 === eof) {
20304             break;
20305           }
20306           str += lookup[b2];
20307         }
20308         return parseFloat(str);
20309       }
20310
20311       var operands = [];
20312       var entries = [];
20313
20314       pos = 0;
20315       var end = dict.length;
20316       while (pos < end) {
20317         var b = dict[pos];
20318         if (b <= 21) {
20319           if (b === 12) {
20320             b = (b << 8) | dict[++pos];
20321           }
20322           entries.push([b, operands]);
20323           operands = [];
20324           ++pos;
20325         } else {
20326           operands.push(parseOperand());
20327         }
20328       }
20329       return entries;
20330     },
20331     parseIndex: function CFFParser_parseIndex(pos) {
20332       var cffIndex = new CFFIndex();
20333       var bytes = this.bytes;
20334       var count = (bytes[pos++] << 8) | bytes[pos++];
20335       var offsets = [];
20336       var end = pos;
20337       var i, ii;
20338
20339       if (count !== 0) {
20340         var offsetSize = bytes[pos++];
20341         // add 1 for offset to determine size of last object
20342         var startPos = pos + ((count + 1) * offsetSize) - 1;
20343
20344         for (i = 0, ii = count + 1; i < ii; ++i) {
20345           var offset = 0;
20346           for (var j = 0; j < offsetSize; ++j) {
20347             offset <<= 8;
20348             offset += bytes[pos++];
20349           }
20350           offsets.push(startPos + offset);
20351         }
20352         end = offsets[count];
20353       }
20354       for (i = 0, ii = offsets.length - 1; i < ii; ++i) {
20355         var offsetStart = offsets[i];
20356         var offsetEnd = offsets[i + 1];
20357         cffIndex.add(bytes.subarray(offsetStart, offsetEnd));
20358       }
20359       return {obj: cffIndex, endPos: end};
20360     },
20361     parseNameIndex: function CFFParser_parseNameIndex(index) {
20362       var names = [];
20363       for (var i = 0, ii = index.count; i < ii; ++i) {
20364         var name = index.get(i);
20365         // OTS doesn't allow names to be over 127 characters.
20366         var length = Math.min(name.length, 127);
20367         var data = [];
20368         // OTS also only permits certain characters in the name.
20369         for (var j = 0; j < length; ++j) {
20370           var c = name[j];
20371           if (j === 0 && c === 0) {
20372             data[j] = c;
20373             continue;
20374           }
20375           if ((c < 33 || c > 126) || c === 91 /* [ */ || c === 93 /* ] */ ||
20376               c === 40 /* ( */ || c === 41 /* ) */ || c === 123 /* { */ ||
20377               c === 125 /* } */ || c === 60 /* < */ || c === 62 /* > */ ||
20378               c === 47 /* / */ || c === 37 /* % */ || c === 35 /* # */) {
20379             data[j] = 95;
20380             continue;
20381           }
20382           data[j] = c;
20383         }
20384         names.push(bytesToString(data));
20385       }
20386       return names;
20387     },
20388     parseStringIndex: function CFFParser_parseStringIndex(index) {
20389       var strings = new CFFStrings();
20390       for (var i = 0, ii = index.count; i < ii; ++i) {
20391         var data = index.get(i);
20392         strings.add(bytesToString(data));
20393       }
20394       return strings;
20395     },
20396     createDict: function CFFParser_createDict(Type, dict, strings) {
20397       var cffDict = new Type(strings);
20398       for (var i = 0, ii = dict.length; i < ii; ++i) {
20399         var pair = dict[i];
20400         var key = pair[0];
20401         var value = pair[1];
20402         cffDict.setByKey(key, value);
20403       }
20404       return cffDict;
20405     },
20406     parseCharStrings: function CFFParser_parseCharStrings(charStringOffset) {
20407       var charStrings = this.parseIndex(charStringOffset).obj;
20408       var seacs = [];
20409       var widths = [];
20410       var count = charStrings.count;
20411       for (var i = 0; i < count; i++) {
20412         var charstring = charStrings.get(i);
20413
20414         var stackSize = 0;
20415         var stack = [];
20416         var undefStack = true;
20417         var hints = 0;
20418         var valid = true;
20419         var data = charstring;
20420         var length = data.length;
20421         var firstStackClearing = true;
20422         for (var j = 0; j < length;) {
20423           var value = data[j++];
20424           var validationCommand = null;
20425           if (value === 12) {
20426             var q = data[j++];
20427             if (q === 0) {
20428               // The CFF specification state that the 'dotsection' command
20429               // (12, 0) is deprecated and treated as a no-op, but all Type2
20430               // charstrings processors should support them. Unfortunately
20431               // the font sanitizer don't. As a workaround the sequence (12, 0)
20432               // is replaced by a useless (0, hmoveto).
20433               data[j - 2] = 139;
20434               data[j - 1] = 22;
20435               stackSize = 0;
20436             } else {
20437               validationCommand = CharstringValidationData12[q];
20438             }
20439           } else if (value === 28) { // number (16 bit)
20440             stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16)) >> 16;
20441             j += 2;
20442             stackSize++;
20443           } else if (value === 14) {
20444             if (stackSize >= 4) {
20445               stackSize -= 4;
20446               if (SEAC_ANALYSIS_ENABLED) {
20447                 seacs[i] = stack.slice(stackSize, stackSize + 4);
20448                 valid = false;
20449               }
20450             }
20451             validationCommand = CharstringValidationData[value];
20452           } else if (value >= 32 && value <= 246) {  // number
20453             stack[stackSize] = value - 139;
20454             stackSize++;
20455           } else if (value >= 247 && value <= 254) {  // number (+1 bytes)
20456             stack[stackSize] = (value < 251 ?
20457                                 ((value - 247) << 8) + data[j] + 108 :
20458                                 -((value - 251) << 8) - data[j] - 108);
20459             j++;
20460             stackSize++;
20461           } else if (value === 255) {  // number (32 bit)
20462             stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) |
20463                                 (data[j + 2] << 8) | data[j + 3]) / 65536;
20464             j += 4;
20465             stackSize++;
20466           } else if (value === 19 || value === 20) {
20467             hints += stackSize >> 1;
20468             j += (hints + 7) >> 3; // skipping right amount of hints flag data
20469             stackSize %= 2;
20470             validationCommand = CharstringValidationData[value];
20471           } else {
20472             validationCommand = CharstringValidationData[value];
20473           }
20474           if (validationCommand) {
20475             if (validationCommand.stem) {
20476               hints += stackSize >> 1;
20477             }
20478             if ('min' in validationCommand) {
20479               if (!undefStack && stackSize < validationCommand.min) {
20480                 warn('Not enough parameters for ' + validationCommand.id +
20481                      '; actual: ' + stackSize +
20482                      ', expected: ' + validationCommand.min);
20483                 valid = false;
20484                 break;
20485               }
20486             }
20487             if (firstStackClearing && validationCommand.stackClearing) {
20488               firstStackClearing = false;
20489               // the optional character width can be found before the first
20490               // stack-clearing command arguments
20491               stackSize -= validationCommand.min;
20492               if (stackSize >= 2 && validationCommand.stem) {
20493                 // there are even amount of arguments for stem commands
20494                 stackSize %= 2;
20495               } else if (stackSize > 1) {
20496                 warn('Found too many parameters for stack-clearing command');
20497               }
20498               if (stackSize > 0 && stack[stackSize - 1] >= 0) {
20499                 widths[i] = stack[stackSize - 1];
20500               }
20501             }
20502             if ('stackDelta' in validationCommand) {
20503               if ('stackFn' in validationCommand) {
20504                 validationCommand.stackFn(stack, stackSize);
20505               }
20506               stackSize += validationCommand.stackDelta;
20507             } else if (validationCommand.stackClearing) {
20508               stackSize = 0;
20509             } else if (validationCommand.resetStack) {
20510               stackSize = 0;
20511               undefStack = false;
20512             } else if (validationCommand.undefStack) {
20513               stackSize = 0;
20514               undefStack = true;
20515               firstStackClearing = false;
20516             }
20517           }
20518         }
20519         if (!valid) {
20520           // resetting invalid charstring to single 'endchar'
20521           charStrings.set(i, new Uint8Array([14]));
20522         }
20523       }
20524       return { charStrings: charStrings, seacs: seacs, widths: widths };
20525     },
20526     emptyPrivateDictionary:
20527       function CFFParser_emptyPrivateDictionary(parentDict) {
20528       var privateDict = this.createDict(CFFPrivateDict, [],
20529                                         parentDict.strings);
20530       parentDict.setByKey(18, [0, 0]);
20531       parentDict.privateDict = privateDict;
20532     },
20533     parsePrivateDict: function CFFParser_parsePrivateDict(parentDict) {
20534       // no private dict, do nothing
20535       if (!parentDict.hasName('Private')) {
20536         this.emptyPrivateDictionary(parentDict);
20537         return;
20538       }
20539       var privateOffset = parentDict.getByName('Private');
20540       // make sure the params are formatted correctly
20541       if (!isArray(privateOffset) || privateOffset.length !== 2) {
20542         parentDict.removeByName('Private');
20543         return;
20544       }
20545       var size = privateOffset[0];
20546       var offset = privateOffset[1];
20547       // remove empty dicts or ones that refer to invalid location
20548       if (size === 0 || offset >= this.bytes.length) {
20549         this.emptyPrivateDictionary(parentDict);
20550         return;
20551       }
20552
20553       var privateDictEnd = offset + size;
20554       var dictData = this.bytes.subarray(offset, privateDictEnd);
20555       var dict = this.parseDict(dictData);
20556       var privateDict = this.createDict(CFFPrivateDict, dict,
20557                                         parentDict.strings);
20558       parentDict.privateDict = privateDict;
20559
20560       // Parse the Subrs index also since it's relative to the private dict.
20561       if (!privateDict.getByName('Subrs')) {
20562         return;
20563       }
20564       var subrsOffset = privateDict.getByName('Subrs');
20565       var relativeOffset = offset + subrsOffset;
20566       // Validate the offset.
20567       if (subrsOffset === 0 || relativeOffset >= this.bytes.length) {
20568         this.emptyPrivateDictionary(parentDict);
20569         return;
20570       }
20571       var subrsIndex = this.parseIndex(relativeOffset);
20572       privateDict.subrsIndex = subrsIndex.obj;
20573     },
20574     parseCharsets: function CFFParser_parseCharsets(pos, length, strings, cid) {
20575       if (pos === 0) {
20576         return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE,
20577                               ISOAdobeCharset);
20578       } else if (pos === 1) {
20579         return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT,
20580                               ExpertCharset);
20581       } else if (pos === 2) {
20582         return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET,
20583                               ExpertSubsetCharset);
20584       }
20585
20586       var bytes = this.bytes;
20587       var start = pos;
20588       var format = bytes[pos++];
20589       var charset = ['.notdef'];
20590       var id, count, i;
20591
20592       // subtract 1 for the .notdef glyph
20593       length -= 1;
20594
20595       switch (format) {
20596         case 0:
20597           for (i = 0; i < length; i++) {
20598             id = (bytes[pos++] << 8) | bytes[pos++];
20599             charset.push(cid ? id : strings.get(id));
20600           }
20601           break;
20602         case 1:
20603           while (charset.length <= length) {
20604             id = (bytes[pos++] << 8) | bytes[pos++];
20605             count = bytes[pos++];
20606             for (i = 0; i <= count; i++) {
20607               charset.push(cid ? id++ : strings.get(id++));
20608             }
20609           }
20610           break;
20611         case 2:
20612           while (charset.length <= length) {
20613             id = (bytes[pos++] << 8) | bytes[pos++];
20614             count = (bytes[pos++] << 8) | bytes[pos++];
20615             for (i = 0; i <= count; i++) {
20616               charset.push(cid ? id++ : strings.get(id++));
20617             }
20618           }
20619           break;
20620         default:
20621           error('Unknown charset format');
20622       }
20623       // Raw won't be needed if we actually compile the charset.
20624       var end = pos;
20625       var raw = bytes.subarray(start, end);
20626
20627       return new CFFCharset(false, format, charset, raw);
20628     },
20629     parseEncoding: function CFFParser_parseEncoding(pos,
20630                                                     properties,
20631                                                     strings,
20632                                                     charset) {
20633       var encoding = {};
20634       var bytes = this.bytes;
20635       var predefined = false;
20636       var hasSupplement = false;
20637       var format, i, ii;
20638       var raw = null;
20639
20640       function readSupplement() {
20641         var supplementsCount = bytes[pos++];
20642         for (i = 0; i < supplementsCount; i++) {
20643           var code = bytes[pos++];
20644           var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);
20645           encoding[code] = charset.indexOf(strings.get(sid));
20646         }
20647       }
20648
20649       if (pos === 0 || pos === 1) {
20650         predefined = true;
20651         format = pos;
20652         var baseEncoding = pos ? Encodings.ExpertEncoding :
20653                                  Encodings.StandardEncoding;
20654         for (i = 0, ii = charset.length; i < ii; i++) {
20655           var index = baseEncoding.indexOf(charset[i]);
20656           if (index !== -1) {
20657             encoding[index] = i;
20658           }
20659         }
20660       } else {
20661         var dataStart = pos;
20662         format = bytes[pos++];
20663         switch (format & 0x7f) {
20664           case 0:
20665             var glyphsCount = bytes[pos++];
20666             for (i = 1; i <= glyphsCount; i++) {
20667               encoding[bytes[pos++]] = i;
20668             }
20669             break;
20670
20671           case 1:
20672             var rangesCount = bytes[pos++];
20673             var gid = 1;
20674             for (i = 0; i < rangesCount; i++) {
20675               var start = bytes[pos++];
20676               var left = bytes[pos++];
20677               for (var j = start; j <= start + left; j++) {
20678                 encoding[j] = gid++;
20679               }
20680             }
20681             break;
20682
20683           default:
20684             error('Unknow encoding format: ' + format + ' in CFF');
20685             break;
20686         }
20687         var dataEnd = pos;
20688         if (format & 0x80) {
20689           // The font sanitizer does not support CFF encoding with a
20690           // supplement, since the encoding is not really used to map
20691           // between gid to glyph, let's overwrite what is declared in
20692           // the top dictionary to let the sanitizer think the font use
20693           // StandardEncoding, that's a lie but that's ok.
20694           bytes[dataStart] &= 0x7f;
20695           readSupplement();
20696           hasSupplement = true;
20697         }
20698         raw = bytes.subarray(dataStart, dataEnd);
20699       }
20700       format = format & 0x7f;
20701       return new CFFEncoding(predefined, format, encoding, raw);
20702     },
20703     parseFDSelect: function CFFParser_parseFDSelect(pos, length) {
20704       var start = pos;
20705       var bytes = this.bytes;
20706       var format = bytes[pos++];
20707       var fdSelect = [];
20708       var i;
20709
20710       switch (format) {
20711         case 0:
20712           for (i = 0; i < length; ++i) {
20713             var id = bytes[pos++];
20714             fdSelect.push(id);
20715           }
20716           break;
20717         case 3:
20718           var rangesCount = (bytes[pos++] << 8) | bytes[pos++];
20719           for (i = 0; i < rangesCount; ++i) {
20720             var first = (bytes[pos++] << 8) | bytes[pos++];
20721             var fdIndex = bytes[pos++];
20722             var next = (bytes[pos] << 8) | bytes[pos + 1];
20723             for (var j = first; j < next; ++j) {
20724               fdSelect.push(fdIndex);
20725             }
20726           }
20727           // Advance past the sentinel(next).
20728           pos += 2;
20729           break;
20730         default:
20731           error('Unknown fdselect format ' + format);
20732           break;
20733       }
20734       var end = pos;
20735       return new CFFFDSelect(fdSelect, bytes.subarray(start, end));
20736     }
20737   };
20738   return CFFParser;
20739 })();
20740
20741 // Compact Font Format
20742 var CFF = (function CFFClosure() {
20743   function CFF() {
20744     this.header = null;
20745     this.names = [];
20746     this.topDict = null;
20747     this.strings = new CFFStrings();
20748     this.globalSubrIndex = null;
20749
20750     // The following could really be per font, but since we only have one font
20751     // store them here.
20752     this.encoding = null;
20753     this.charset = null;
20754     this.charStrings = null;
20755     this.fdArray = [];
20756     this.fdSelect = null;
20757
20758     this.isCIDFont = false;
20759   }
20760   return CFF;
20761 })();
20762
20763 var CFFHeader = (function CFFHeaderClosure() {
20764   function CFFHeader(major, minor, hdrSize, offSize) {
20765     this.major = major;
20766     this.minor = minor;
20767     this.hdrSize = hdrSize;
20768     this.offSize = offSize;
20769   }
20770   return CFFHeader;
20771 })();
20772
20773 var CFFStrings = (function CFFStringsClosure() {
20774   function CFFStrings() {
20775     this.strings = [];
20776   }
20777   CFFStrings.prototype = {
20778     get: function CFFStrings_get(index) {
20779       if (index >= 0 && index <= 390) {
20780         return CFFStandardStrings[index];
20781       }
20782       if (index - 391 <= this.strings.length) {
20783         return this.strings[index - 391];
20784       }
20785       return CFFStandardStrings[0];
20786     },
20787     add: function CFFStrings_add(value) {
20788       this.strings.push(value);
20789     },
20790     get count() {
20791       return this.strings.length;
20792     }
20793   };
20794   return CFFStrings;
20795 })();
20796
20797 var CFFIndex = (function CFFIndexClosure() {
20798   function CFFIndex() {
20799     this.objects = [];
20800     this.length = 0;
20801   }
20802   CFFIndex.prototype = {
20803     add: function CFFIndex_add(data) {
20804       this.length += data.length;
20805       this.objects.push(data);
20806     },
20807     set: function CFFIndex_set(index, data) {
20808       this.length += data.length - this.objects[index].length;
20809       this.objects[index] = data;
20810     },
20811     get: function CFFIndex_get(index) {
20812       return this.objects[index];
20813     },
20814     get count() {
20815       return this.objects.length;
20816     }
20817   };
20818   return CFFIndex;
20819 })();
20820
20821 var CFFDict = (function CFFDictClosure() {
20822   function CFFDict(tables, strings) {
20823     this.keyToNameMap = tables.keyToNameMap;
20824     this.nameToKeyMap = tables.nameToKeyMap;
20825     this.defaults = tables.defaults;
20826     this.types = tables.types;
20827     this.opcodes = tables.opcodes;
20828     this.order = tables.order;
20829     this.strings = strings;
20830     this.values = {};
20831   }
20832   CFFDict.prototype = {
20833     // value should always be an array
20834     setByKey: function CFFDict_setByKey(key, value) {
20835       if (!(key in this.keyToNameMap)) {
20836         return false;
20837       }
20838       // ignore empty values
20839       if (value.length === 0) {
20840         return true;
20841       }
20842       var type = this.types[key];
20843       // remove the array wrapping these types of values
20844       if (type === 'num' || type === 'sid' || type === 'offset') {
20845         value = value[0];
20846       }
20847       this.values[key] = value;
20848       return true;
20849     },
20850     setByName: function CFFDict_setByName(name, value) {
20851       if (!(name in this.nameToKeyMap)) {
20852         error('Invalid dictionary name "' + name + '"');
20853       }
20854       this.values[this.nameToKeyMap[name]] = value;
20855     },
20856     hasName: function CFFDict_hasName(name) {
20857       return this.nameToKeyMap[name] in this.values;
20858     },
20859     getByName: function CFFDict_getByName(name) {
20860       if (!(name in this.nameToKeyMap)) {
20861         error('Invalid dictionary name "' + name + '"');
20862       }
20863       var key = this.nameToKeyMap[name];
20864       if (!(key in this.values)) {
20865         return this.defaults[key];
20866       }
20867       return this.values[key];
20868     },
20869     removeByName: function CFFDict_removeByName(name) {
20870       delete this.values[this.nameToKeyMap[name]];
20871     }
20872   };
20873   CFFDict.createTables = function CFFDict_createTables(layout) {
20874     var tables = {
20875       keyToNameMap: {},
20876       nameToKeyMap: {},
20877       defaults: {},
20878       types: {},
20879       opcodes: {},
20880       order: []
20881     };
20882     for (var i = 0, ii = layout.length; i < ii; ++i) {
20883       var entry = layout[i];
20884       var key = isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0];
20885       tables.keyToNameMap[key] = entry[1];
20886       tables.nameToKeyMap[entry[1]] = key;
20887       tables.types[key] = entry[2];
20888       tables.defaults[key] = entry[3];
20889       tables.opcodes[key] = isArray(entry[0]) ? entry[0] : [entry[0]];
20890       tables.order.push(key);
20891     }
20892     return tables;
20893   };
20894   return CFFDict;
20895 })();
20896
20897 var CFFTopDict = (function CFFTopDictClosure() {
20898   var layout = [
20899     [[12, 30], 'ROS', ['sid', 'sid', 'num'], null],
20900     [[12, 20], 'SyntheticBase', 'num', null],
20901     [0, 'version', 'sid', null],
20902     [1, 'Notice', 'sid', null],
20903     [[12, 0], 'Copyright', 'sid', null],
20904     [2, 'FullName', 'sid', null],
20905     [3, 'FamilyName', 'sid', null],
20906     [4, 'Weight', 'sid', null],
20907     [[12, 1], 'isFixedPitch', 'num', 0],
20908     [[12, 2], 'ItalicAngle', 'num', 0],
20909     [[12, 3], 'UnderlinePosition', 'num', -100],
20910     [[12, 4], 'UnderlineThickness', 'num', 50],
20911     [[12, 5], 'PaintType', 'num', 0],
20912     [[12, 6], 'CharstringType', 'num', 2],
20913     [[12, 7], 'FontMatrix', ['num', 'num', 'num', 'num', 'num', 'num'],
20914                             [0.001, 0, 0, 0.001, 0, 0]],
20915     [13, 'UniqueID', 'num', null],
20916     [5, 'FontBBox', ['num', 'num', 'num', 'num'], [0, 0, 0, 0]],
20917     [[12, 8], 'StrokeWidth', 'num', 0],
20918     [14, 'XUID', 'array', null],
20919     [15, 'charset', 'offset', 0],
20920     [16, 'Encoding', 'offset', 0],
20921     [17, 'CharStrings', 'offset', 0],
20922     [18, 'Private', ['offset', 'offset'], null],
20923     [[12, 21], 'PostScript', 'sid', null],
20924     [[12, 22], 'BaseFontName', 'sid', null],
20925     [[12, 23], 'BaseFontBlend', 'delta', null],
20926     [[12, 31], 'CIDFontVersion', 'num', 0],
20927     [[12, 32], 'CIDFontRevision', 'num', 0],
20928     [[12, 33], 'CIDFontType', 'num', 0],
20929     [[12, 34], 'CIDCount', 'num', 8720],
20930     [[12, 35], 'UIDBase', 'num', null],
20931     // XXX: CID Fonts on DirectWrite 6.1 only seem to work if FDSelect comes
20932     // before FDArray.
20933     [[12, 37], 'FDSelect', 'offset', null],
20934     [[12, 36], 'FDArray', 'offset', null],
20935     [[12, 38], 'FontName', 'sid', null]
20936   ];
20937   var tables = null;
20938   function CFFTopDict(strings) {
20939     if (tables === null) {
20940       tables = CFFDict.createTables(layout);
20941     }
20942     CFFDict.call(this, tables, strings);
20943     this.privateDict = null;
20944   }
20945   CFFTopDict.prototype = Object.create(CFFDict.prototype);
20946   return CFFTopDict;
20947 })();
20948
20949 var CFFPrivateDict = (function CFFPrivateDictClosure() {
20950   var layout = [
20951     [6, 'BlueValues', 'delta', null],
20952     [7, 'OtherBlues', 'delta', null],
20953     [8, 'FamilyBlues', 'delta', null],
20954     [9, 'FamilyOtherBlues', 'delta', null],
20955     [[12, 9], 'BlueScale', 'num', 0.039625],
20956     [[12, 10], 'BlueShift', 'num', 7],
20957     [[12, 11], 'BlueFuzz', 'num', 1],
20958     [10, 'StdHW', 'num', null],
20959     [11, 'StdVW', 'num', null],
20960     [[12, 12], 'StemSnapH', 'delta', null],
20961     [[12, 13], 'StemSnapV', 'delta', null],
20962     [[12, 14], 'ForceBold', 'num', 0],
20963     [[12, 17], 'LanguageGroup', 'num', 0],
20964     [[12, 18], 'ExpansionFactor', 'num', 0.06],
20965     [[12, 19], 'initialRandomSeed', 'num', 0],
20966     [20, 'defaultWidthX', 'num', 0],
20967     [21, 'nominalWidthX', 'num', 0],
20968     [19, 'Subrs', 'offset', null]
20969   ];
20970   var tables = null;
20971   function CFFPrivateDict(strings) {
20972     if (tables === null) {
20973       tables = CFFDict.createTables(layout);
20974     }
20975     CFFDict.call(this, tables, strings);
20976     this.subrsIndex = null;
20977   }
20978   CFFPrivateDict.prototype = Object.create(CFFDict.prototype);
20979   return CFFPrivateDict;
20980 })();
20981
20982 var CFFCharsetPredefinedTypes = {
20983   ISO_ADOBE: 0,
20984   EXPERT: 1,
20985   EXPERT_SUBSET: 2
20986 };
20987 var CFFCharset = (function CFFCharsetClosure() {
20988   function CFFCharset(predefined, format, charset, raw) {
20989     this.predefined = predefined;
20990     this.format = format;
20991     this.charset = charset;
20992     this.raw = raw;
20993   }
20994   return CFFCharset;
20995 })();
20996
20997 var CFFEncoding = (function CFFEncodingClosure() {
20998   function CFFEncoding(predefined, format, encoding, raw) {
20999     this.predefined = predefined;
21000     this.format = format;
21001     this.encoding = encoding;
21002     this.raw = raw;
21003   }
21004   return CFFEncoding;
21005 })();
21006
21007 var CFFFDSelect = (function CFFFDSelectClosure() {
21008   function CFFFDSelect(fdSelect, raw) {
21009     this.fdSelect = fdSelect;
21010     this.raw = raw;
21011   }
21012   return CFFFDSelect;
21013 })();
21014
21015 // Helper class to keep track of where an offset is within the data and helps
21016 // filling in that offset once it's known.
21017 var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
21018   function CFFOffsetTracker() {
21019     this.offsets = {};
21020   }
21021   CFFOffsetTracker.prototype = {
21022     isTracking: function CFFOffsetTracker_isTracking(key) {
21023       return key in this.offsets;
21024     },
21025     track: function CFFOffsetTracker_track(key, location) {
21026       if (key in this.offsets) {
21027         error('Already tracking location of ' + key);
21028       }
21029       this.offsets[key] = location;
21030     },
21031     offset: function CFFOffsetTracker_offset(value) {
21032       for (var key in this.offsets) {
21033         this.offsets[key] += value;
21034       }
21035     },
21036     setEntryLocation: function CFFOffsetTracker_setEntryLocation(key,
21037                                                                  values,
21038                                                                  output) {
21039       if (!(key in this.offsets)) {
21040         error('Not tracking location of ' + key);
21041       }
21042       var data = output.data;
21043       var dataOffset = this.offsets[key];
21044       var size = 5;
21045       for (var i = 0, ii = values.length; i < ii; ++i) {
21046         var offset0 = i * size + dataOffset;
21047         var offset1 = offset0 + 1;
21048         var offset2 = offset0 + 2;
21049         var offset3 = offset0 + 3;
21050         var offset4 = offset0 + 4;
21051         // It's easy to screw up offsets so perform this sanity check.
21052         if (data[offset0] !== 0x1d || data[offset1] !== 0 ||
21053             data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0) {
21054           error('writing to an offset that is not empty');
21055         }
21056         var value = values[i];
21057         data[offset0] = 0x1d;
21058         data[offset1] = (value >> 24) & 0xFF;
21059         data[offset2] = (value >> 16) & 0xFF;
21060         data[offset3] = (value >> 8) & 0xFF;
21061         data[offset4] = value & 0xFF;
21062       }
21063     }
21064   };
21065   return CFFOffsetTracker;
21066 })();
21067
21068 // Takes a CFF and converts it to the binary representation.
21069 var CFFCompiler = (function CFFCompilerClosure() {
21070   function CFFCompiler(cff) {
21071     this.cff = cff;
21072   }
21073   CFFCompiler.prototype = {
21074     compile: function CFFCompiler_compile() {
21075       var cff = this.cff;
21076       var output = {
21077         data: [],
21078         length: 0,
21079         add: function CFFCompiler_add(data) {
21080           this.data = this.data.concat(data);
21081           this.length = this.data.length;
21082         }
21083       };
21084
21085       // Compile the five entries that must be in order.
21086       var header = this.compileHeader(cff.header);
21087       output.add(header);
21088
21089       var nameIndex = this.compileNameIndex(cff.names);
21090       output.add(nameIndex);
21091
21092       if (cff.isCIDFont) {
21093         // The spec is unclear on how font matrices should relate to each other
21094         // when there is one in the main top dict and the sub top dicts.
21095         // Windows handles this differently than linux and osx so we have to
21096         // normalize to work on all.
21097         // Rules based off of some mailing list discussions:
21098         // - If main font has a matrix and subfont doesn't, use the main matrix.
21099         // - If no main font matrix and there is a subfont matrix, use the
21100         //   subfont matrix.
21101         // - If both have matrices, concat together.
21102         // - If neither have matrices, use default.
21103         // To make this work on all platforms we move the top matrix into each
21104         // sub top dict and concat if necessary.
21105         if (cff.topDict.hasName('FontMatrix')) {
21106           var base = cff.topDict.getByName('FontMatrix');
21107           cff.topDict.removeByName('FontMatrix');
21108           for (var i = 0, ii = cff.fdArray.length; i < ii; i++) {
21109             var subDict = cff.fdArray[i];
21110             var matrix = base.slice(0);
21111             if (subDict.hasName('FontMatrix')) {
21112               matrix = Util.transform(matrix, subDict.getByName('FontMatrix'));
21113             }
21114             subDict.setByName('FontMatrix', matrix);
21115           }
21116         }
21117       }
21118
21119       var compiled = this.compileTopDicts([cff.topDict],
21120                                           output.length,
21121                                           cff.isCIDFont);
21122       output.add(compiled.output);
21123       var topDictTracker = compiled.trackers[0];
21124
21125       var stringIndex = this.compileStringIndex(cff.strings.strings);
21126       output.add(stringIndex);
21127
21128       var globalSubrIndex = this.compileIndex(cff.globalSubrIndex);
21129       output.add(globalSubrIndex);
21130
21131       // Now start on the other entries that have no specfic order.
21132       if (cff.encoding && cff.topDict.hasName('Encoding')) {
21133         if (cff.encoding.predefined) {
21134           topDictTracker.setEntryLocation('Encoding', [cff.encoding.format],
21135                                           output);
21136         } else {
21137           var encoding = this.compileEncoding(cff.encoding);
21138           topDictTracker.setEntryLocation('Encoding', [output.length], output);
21139           output.add(encoding);
21140         }
21141       }
21142
21143       if (cff.charset && cff.topDict.hasName('charset')) {
21144         if (cff.charset.predefined) {
21145           topDictTracker.setEntryLocation('charset', [cff.charset.format],
21146                                           output);
21147         } else {
21148           var charset = this.compileCharset(cff.charset);
21149           topDictTracker.setEntryLocation('charset', [output.length], output);
21150           output.add(charset);
21151         }
21152       }
21153
21154       var charStrings = this.compileCharStrings(cff.charStrings);
21155       topDictTracker.setEntryLocation('CharStrings', [output.length], output);
21156       output.add(charStrings);
21157
21158       if (cff.isCIDFont) {
21159         // For some reason FDSelect must be in front of FDArray on windows. OSX
21160         // and linux don't seem to care.
21161         topDictTracker.setEntryLocation('FDSelect', [output.length], output);
21162         var fdSelect = this.compileFDSelect(cff.fdSelect.raw);
21163         output.add(fdSelect);
21164         // It is unclear if the sub font dictionary can have CID related
21165         // dictionary keys, but the sanitizer doesn't like them so remove them.
21166         compiled = this.compileTopDicts(cff.fdArray, output.length, true);
21167         topDictTracker.setEntryLocation('FDArray', [output.length], output);
21168         output.add(compiled.output);
21169         var fontDictTrackers = compiled.trackers;
21170
21171         this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output);
21172       }
21173
21174       this.compilePrivateDicts([cff.topDict], [topDictTracker], output);
21175
21176       // If the font data ends with INDEX whose object data is zero-length,
21177       // the sanitizer will bail out. Add a dummy byte to avoid that.
21178       output.add([0]);
21179
21180       return output.data;
21181     },
21182     encodeNumber: function CFFCompiler_encodeNumber(value) {
21183       if (parseFloat(value) === parseInt(value, 10) && !isNaN(value)) { // isInt
21184         return this.encodeInteger(value);
21185       } else {
21186         return this.encodeFloat(value);
21187       }
21188     },
21189     encodeFloat: function CFFCompiler_encodeFloat(num) {
21190       var value = num.toString();
21191
21192       // rounding inaccurate doubles
21193       var m = /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(value);
21194       if (m) {
21195         var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length));
21196         value = (Math.round(num * epsilon) / epsilon).toString();
21197       }
21198
21199       var nibbles = '';
21200       var i, ii;
21201       for (i = 0, ii = value.length; i < ii; ++i) {
21202         var a = value[i];
21203         if (a === 'e') {
21204           nibbles += value[++i] === '-' ? 'c' : 'b';
21205         } else if (a === '.') {
21206           nibbles += 'a';
21207         } else if (a === '-') {
21208           nibbles += 'e';
21209         } else {
21210           nibbles += a;
21211         }
21212       }
21213       nibbles += (nibbles.length & 1) ? 'f' : 'ff';
21214       var out = [30];
21215       for (i = 0, ii = nibbles.length; i < ii; i += 2) {
21216         out.push(parseInt(nibbles.substr(i, 2), 16));
21217       }
21218       return out;
21219     },
21220     encodeInteger: function CFFCompiler_encodeInteger(value) {
21221       var code;
21222       if (value >= -107 && value <= 107) {
21223         code = [value + 139];
21224       } else if (value >= 108 && value <= 1131) {
21225         value = [value - 108];
21226         code = [(value >> 8) + 247, value & 0xFF];
21227       } else if (value >= -1131 && value <= -108) {
21228         value = -value - 108;
21229         code = [(value >> 8) + 251, value & 0xFF];
21230       } else if (value >= -32768 && value <= 32767) {
21231         code = [0x1c, (value >> 8) & 0xFF, value & 0xFF];
21232       } else {
21233         code = [0x1d,
21234                 (value >> 24) & 0xFF,
21235                 (value >> 16) & 0xFF,
21236                 (value >> 8) & 0xFF,
21237                  value & 0xFF];
21238       }
21239       return code;
21240     },
21241     compileHeader: function CFFCompiler_compileHeader(header) {
21242       return [
21243         header.major,
21244         header.minor,
21245         header.hdrSize,
21246         header.offSize
21247       ];
21248     },
21249     compileNameIndex: function CFFCompiler_compileNameIndex(names) {
21250       var nameIndex = new CFFIndex();
21251       for (var i = 0, ii = names.length; i < ii; ++i) {
21252         nameIndex.add(stringToBytes(names[i]));
21253       }
21254       return this.compileIndex(nameIndex);
21255     },
21256     compileTopDicts: function CFFCompiler_compileTopDicts(dicts,
21257                                                           length,
21258                                                           removeCidKeys) {
21259       var fontDictTrackers = [];
21260       var fdArrayIndex = new CFFIndex();
21261       for (var i = 0, ii = dicts.length; i < ii; ++i) {
21262         var fontDict = dicts[i];
21263         if (removeCidKeys) {
21264           fontDict.removeByName('CIDFontVersion');
21265           fontDict.removeByName('CIDFontRevision');
21266           fontDict.removeByName('CIDFontType');
21267           fontDict.removeByName('CIDCount');
21268           fontDict.removeByName('UIDBase');
21269         }
21270         var fontDictTracker = new CFFOffsetTracker();
21271         var fontDictData = this.compileDict(fontDict, fontDictTracker);
21272         fontDictTrackers.push(fontDictTracker);
21273         fdArrayIndex.add(fontDictData);
21274         fontDictTracker.offset(length);
21275       }
21276       fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers);
21277       return {
21278         trackers: fontDictTrackers,
21279         output: fdArrayIndex
21280       };
21281     },
21282     compilePrivateDicts: function CFFCompiler_compilePrivateDicts(dicts,
21283                                                                   trackers,
21284                                                                   output) {
21285       for (var i = 0, ii = dicts.length; i < ii; ++i) {
21286         var fontDict = dicts[i];
21287         assert(fontDict.privateDict && fontDict.hasName('Private'),
21288                'There must be an private dictionary.');
21289         var privateDict = fontDict.privateDict;
21290         var privateDictTracker = new CFFOffsetTracker();
21291         var privateDictData = this.compileDict(privateDict, privateDictTracker);
21292
21293         var outputLength = output.length;
21294         privateDictTracker.offset(outputLength);
21295         if (!privateDictData.length) {
21296           // The private dictionary was empty, set the output length to zero to
21297           // ensure the offset length isn't out of bounds in the eyes of the
21298           // sanitizer.
21299           outputLength = 0;
21300         }
21301
21302         trackers[i].setEntryLocation('Private',
21303                                      [privateDictData.length, outputLength],
21304                                      output);
21305         output.add(privateDictData);
21306
21307         if (privateDict.subrsIndex && privateDict.hasName('Subrs')) {
21308           var subrs = this.compileIndex(privateDict.subrsIndex);
21309           privateDictTracker.setEntryLocation('Subrs', [privateDictData.length],
21310                                               output);
21311           output.add(subrs);
21312         }
21313       }
21314     },
21315     compileDict: function CFFCompiler_compileDict(dict, offsetTracker) {
21316       var out = [];
21317       // The dictionary keys must be in a certain order.
21318       var order = dict.order;
21319       for (var i = 0; i < order.length; ++i) {
21320         var key = order[i];
21321         if (!(key in dict.values)) {
21322           continue;
21323         }
21324         var values = dict.values[key];
21325         var types = dict.types[key];
21326         if (!isArray(types)) {
21327           types = [types];
21328         }
21329         if (!isArray(values)) {
21330           values = [values];
21331         }
21332
21333         // Remove any empty dict values.
21334         if (values.length === 0) {
21335           continue;
21336         }
21337
21338         for (var j = 0, jj = types.length; j < jj; ++j) {
21339           var type = types[j];
21340           var value = values[j];
21341           switch (type) {
21342             case 'num':
21343             case 'sid':
21344               out = out.concat(this.encodeNumber(value));
21345               break;
21346             case 'offset':
21347               // For offsets we just insert a 32bit integer so we don't have to
21348               // deal with figuring out the length of the offset when it gets
21349               // replaced later on by the compiler.
21350               var name = dict.keyToNameMap[key];
21351               // Some offsets have the offset and the length, so just record the
21352               // position of the first one.
21353               if (!offsetTracker.isTracking(name)) {
21354                 offsetTracker.track(name, out.length);
21355               }
21356               out = out.concat([0x1d, 0, 0, 0, 0]);
21357               break;
21358             case 'array':
21359             case 'delta':
21360               out = out.concat(this.encodeNumber(value));
21361               for (var k = 1, kk = values.length; k < kk; ++k) {
21362                 out = out.concat(this.encodeNumber(values[k]));
21363               }
21364               break;
21365             default:
21366               error('Unknown data type of ' + type);
21367               break;
21368           }
21369         }
21370         out = out.concat(dict.opcodes[key]);
21371       }
21372       return out;
21373     },
21374     compileStringIndex: function CFFCompiler_compileStringIndex(strings) {
21375       var stringIndex = new CFFIndex();
21376       for (var i = 0, ii = strings.length; i < ii; ++i) {
21377         stringIndex.add(stringToBytes(strings[i]));
21378       }
21379       return this.compileIndex(stringIndex);
21380     },
21381     compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() {
21382       var globalSubrIndex = this.cff.globalSubrIndex;
21383       this.out.writeByteArray(this.compileIndex(globalSubrIndex));
21384     },
21385     compileCharStrings: function CFFCompiler_compileCharStrings(charStrings) {
21386       return this.compileIndex(charStrings);
21387     },
21388     compileCharset: function CFFCompiler_compileCharset(charset) {
21389       return this.compileTypedArray(charset.raw);
21390     },
21391     compileEncoding: function CFFCompiler_compileEncoding(encoding) {
21392       return this.compileTypedArray(encoding.raw);
21393     },
21394     compileFDSelect: function CFFCompiler_compileFDSelect(fdSelect) {
21395       return this.compileTypedArray(fdSelect);
21396     },
21397     compileTypedArray: function CFFCompiler_compileTypedArray(data) {
21398       var out = [];
21399       for (var i = 0, ii = data.length; i < ii; ++i) {
21400         out[i] = data[i];
21401       }
21402       return out;
21403     },
21404     compileIndex: function CFFCompiler_compileIndex(index, trackers) {
21405       trackers = trackers || [];
21406       var objects = index.objects;
21407       // First 2 bytes contains the number of objects contained into this index
21408       var count = objects.length;
21409
21410       // If there is no object, just create an index. This technically
21411       // should just be [0, 0] but OTS has an issue with that.
21412       if (count === 0) {
21413         return [0, 0, 0];
21414       }
21415
21416       var data = [(count >> 8) & 0xFF, count & 0xff];
21417
21418       var lastOffset = 1, i;
21419       for (i = 0; i < count; ++i) {
21420         lastOffset += objects[i].length;
21421       }
21422
21423       var offsetSize;
21424       if (lastOffset < 0x100) {
21425         offsetSize = 1;
21426       } else if (lastOffset < 0x10000) {
21427         offsetSize = 2;
21428       } else if (lastOffset < 0x1000000) {
21429         offsetSize = 3;
21430       } else {
21431         offsetSize = 4;
21432       }
21433
21434       // Next byte contains the offset size use to reference object in the file
21435       data.push(offsetSize);
21436
21437       // Add another offset after this one because we need a new offset
21438       var relativeOffset = 1;
21439       for (i = 0; i < count + 1; i++) {
21440         if (offsetSize === 1) {
21441           data.push(relativeOffset & 0xFF);
21442         } else if (offsetSize === 2) {
21443           data.push((relativeOffset >> 8) & 0xFF,
21444                      relativeOffset & 0xFF);
21445         } else if (offsetSize === 3) {
21446           data.push((relativeOffset >> 16) & 0xFF,
21447                     (relativeOffset >> 8) & 0xFF,
21448                      relativeOffset & 0xFF);
21449         } else {
21450           data.push((relativeOffset >>> 24) & 0xFF,
21451                     (relativeOffset >> 16) & 0xFF,
21452                     (relativeOffset >> 8) & 0xFF,
21453                      relativeOffset & 0xFF);
21454         }
21455
21456         if (objects[i]) {
21457           relativeOffset += objects[i].length;
21458         }
21459       }
21460
21461       for (i = 0; i < count; i++) {
21462         // Notify the tracker where the object will be offset in the data.
21463         if (trackers[i]) {
21464           trackers[i].offset(data.length);
21465         }
21466         for (var j = 0, jj = objects[i].length; j < jj; j++) {
21467           data.push(objects[i][j]);
21468         }
21469       }
21470       return data;
21471     }
21472   };
21473   return CFFCompiler;
21474 })();
21475
21476 // Workaround for seac on Windows.
21477 (function checkSeacSupport() {
21478   if (/Windows/.test(navigator.userAgent)) {
21479     SEAC_ANALYSIS_ENABLED = true;
21480   }
21481 })();
21482
21483 // Workaround for Private Use Area characters in Chrome on Windows
21484 // http://code.google.com/p/chromium/issues/detail?id=122465
21485 // https://github.com/mozilla/pdf.js/issues/1689
21486 (function checkChromeWindows() {
21487   if (/Windows.*Chrome/.test(navigator.userAgent)) {
21488     SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = true;
21489   }
21490 })();
21491
21492
21493 var FontRendererFactory = (function FontRendererFactoryClosure() {
21494   function getLong(data, offset) {
21495     return (data[offset] << 24) | (data[offset + 1] << 16) |
21496            (data[offset + 2] << 8) | data[offset + 3];
21497   }
21498
21499   function getUshort(data, offset) {
21500     return (data[offset] << 8) | data[offset + 1];
21501   }
21502
21503   function parseCmap(data, start, end) {
21504     var offset = (getUshort(data, start + 2) === 1 ?
21505                   getLong(data, start + 8) : getLong(data, start + 16));
21506     var format = getUshort(data, start + offset);
21507     var length, ranges, p, i;
21508     if (format === 4) {
21509       length = getUshort(data, start + offset + 2);
21510       var segCount = getUshort(data, start + offset + 6) >> 1;
21511       p = start + offset + 14;
21512       ranges = [];
21513       for (i = 0; i < segCount; i++, p += 2) {
21514         ranges[i] = {end: getUshort(data, p)};
21515       }
21516       p += 2;
21517       for (i = 0; i < segCount; i++, p += 2) {
21518         ranges[i].start = getUshort(data, p);
21519       }
21520       for (i = 0; i < segCount; i++, p += 2) {
21521         ranges[i].idDelta = getUshort(data, p);
21522       }
21523       for (i = 0; i < segCount; i++, p += 2) {
21524         var idOffset = getUshort(data, p);
21525         if (idOffset === 0) {
21526           continue;
21527         }
21528         ranges[i].ids = [];
21529         for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
21530           ranges[i].ids[j] = getUshort(data, p + idOffset);
21531           idOffset += 2;
21532         }
21533       }
21534       return ranges;
21535     } else if (format === 12) {
21536       length = getLong(data, start + offset + 4);
21537       var groups = getLong(data, start + offset + 12);
21538       p = start + offset + 16;
21539       ranges = [];
21540       for (i = 0; i < groups; i++) {
21541         ranges.push({
21542           start: getLong(data, p),
21543           end: getLong(data, p + 4),
21544           idDelta: getLong(data, p + 8) - getLong(data, p)
21545         });
21546         p += 12;
21547       }
21548       return ranges;
21549     }
21550     error('not supported cmap: ' + format);
21551   }
21552
21553   function parseCff(data, start, end) {
21554     var properties = {};
21555     var parser = new CFFParser(new Stream(data, start, end - start),
21556                                properties);
21557     var cff = parser.parse();
21558     return {
21559       glyphs: cff.charStrings.objects,
21560       subrs: (cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&
21561               cff.topDict.privateDict.subrsIndex.objects),
21562       gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects
21563     };
21564   }
21565
21566   function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
21567     var itemSize, itemDecode;
21568     if (isGlyphLocationsLong) {
21569       itemSize = 4;
21570       itemDecode = function fontItemDecodeLong(data, offset) {
21571         return (data[offset] << 24) | (data[offset + 1] << 16) |
21572                (data[offset + 2] << 8) | data[offset + 3];
21573       };
21574     } else {
21575       itemSize = 2;
21576       itemDecode = function fontItemDecode(data, offset) {
21577         return (data[offset] << 9) | (data[offset + 1] << 1);
21578       };
21579     }
21580     var glyphs = [];
21581     var startOffset = itemDecode(loca, 0);
21582     for (var j = itemSize; j < loca.length; j += itemSize) {
21583       var endOffset = itemDecode(loca, j);
21584       glyphs.push(glyf.subarray(startOffset, endOffset));
21585       startOffset = endOffset;
21586     }
21587     return glyphs;
21588   }
21589
21590   function lookupCmap(ranges, unicode) {
21591     var code = unicode.charCodeAt(0);
21592     var l = 0, r = ranges.length - 1;
21593     while (l < r) {
21594       var c = (l + r + 1) >> 1;
21595       if (code < ranges[c].start) {
21596         r = c - 1;
21597       } else {
21598         l = c;
21599       }
21600     }
21601     if (ranges[l].start <= code && code <= ranges[l].end) {
21602       return (ranges[l].idDelta + (ranges[l].ids ?
21603         ranges[l].ids[code - ranges[l].start] : code)) & 0xFFFF;
21604     }
21605     return 0;
21606   }
21607
21608   function compileGlyf(code, js, font) {
21609     function moveTo(x, y) {
21610       js.push('c.moveTo(' + x + ',' + y + ');');
21611     }
21612     function lineTo(x, y) {
21613       js.push('c.lineTo(' + x + ',' + y + ');');
21614     }
21615     function quadraticCurveTo(xa, ya, x, y) {
21616       js.push('c.quadraticCurveTo(' + xa + ',' + ya + ',' +
21617                                    x + ',' + y + ');');
21618     }
21619
21620     var i = 0;
21621     var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
21622     var flags;
21623     var x = 0, y = 0;
21624     i += 10;
21625     if (numberOfContours < 0) {
21626       // composite glyph
21627       do {
21628         flags = (code[i] << 8) | code[i + 1];
21629         var glyphIndex = (code[i + 2] << 8) | code[i + 3];
21630         i += 4;
21631         var arg1, arg2;
21632         if ((flags & 0x01)) {
21633           arg1 = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
21634           arg2 = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
21635           i += 4;
21636         } else {
21637           arg1 = code[i++]; arg2 = code[i++];
21638         }
21639         if ((flags & 0x02)) {
21640            x = arg1;
21641            y = arg2;
21642         } else {
21643            x = 0; y = 0; // TODO "they are points" ?
21644         }
21645         var scaleX = 1, scaleY = 1, scale01 = 0, scale10 = 0;
21646         if ((flags & 0x08)) {
21647           scaleX =
21648           scaleY = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
21649           i += 2;
21650         } else if ((flags & 0x40)) {
21651           scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
21652           scaleY = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
21653           i += 4;
21654         } else if ((flags & 0x80)) {
21655           scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
21656           scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
21657           scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;
21658           scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824;
21659           i += 8;
21660         }
21661         var subglyph = font.glyphs[glyphIndex];
21662         if (subglyph) {
21663           js.push('c.save();');
21664           js.push('c.transform(' + scaleX + ',' + scale01 + ',' +
21665                   scale10 + ',' + scaleY + ',' + x + ',' + y + ');');
21666           compileGlyf(subglyph, js, font);
21667           js.push('c.restore();');
21668         }
21669       } while ((flags & 0x20));
21670     } else {
21671       // simple glyph
21672       var endPtsOfContours = [];
21673       var j, jj;
21674       for (j = 0; j < numberOfContours; j++) {
21675         endPtsOfContours.push((code[i] << 8) | code[i + 1]);
21676         i += 2;
21677       }
21678       var instructionLength = (code[i] << 8) | code[i + 1];
21679       i += 2 + instructionLength; // skipping the instructions
21680       var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
21681       var points = [];
21682       while (points.length < numberOfPoints) {
21683         flags = code[i++];
21684         var repeat = 1;
21685         if ((flags & 0x08)) {
21686           repeat += code[i++];
21687         }
21688         while (repeat-- > 0) {
21689           points.push({flags: flags});
21690         }
21691       }
21692       for (j = 0; j < numberOfPoints; j++) {
21693         switch (points[j].flags & 0x12) {
21694           case 0x00:
21695             x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
21696             i += 2;
21697             break;
21698           case 0x02:
21699             x -= code[i++];
21700             break;
21701           case 0x12:
21702             x += code[i++];
21703             break;
21704         }
21705         points[j].x = x;
21706       }
21707       for (j = 0; j < numberOfPoints; j++) {
21708         switch (points[j].flags & 0x24) {
21709           case 0x00:
21710             y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
21711             i += 2;
21712             break;
21713           case 0x04:
21714             y -= code[i++];
21715             break;
21716           case 0x24:
21717             y += code[i++];
21718             break;
21719         }
21720         points[j].y = y;
21721       }
21722
21723       var startPoint = 0;
21724       for (i = 0; i < numberOfContours; i++) {
21725         var endPoint = endPtsOfContours[i];
21726         // contours might have implicit points, which is located in the middle
21727         // between two neighboring off-curve points
21728         var contour = points.slice(startPoint, endPoint + 1);
21729         if ((contour[0].flags & 1)) {
21730           contour.push(contour[0]); // using start point at the contour end
21731         } else if ((contour[contour.length - 1].flags & 1)) {
21732           // first is off-curve point, trying to use one from the end
21733           contour.unshift(contour[contour.length - 1]);
21734         } else {
21735           // start and end are off-curve points, creating implicit one
21736           var p = {
21737             flags: 1,
21738             x: (contour[0].x + contour[contour.length - 1].x) / 2,
21739             y: (contour[0].y + contour[contour.length - 1].y) / 2
21740           };
21741           contour.unshift(p);
21742           contour.push(p);
21743         }
21744         moveTo(contour[0].x, contour[0].y);
21745         for (j = 1, jj = contour.length; j < jj; j++) {
21746           if ((contour[j].flags & 1)) {
21747             lineTo(contour[j].x, contour[j].y);
21748           } else if ((contour[j + 1].flags & 1)){
21749             quadraticCurveTo(contour[j].x, contour[j].y,
21750                              contour[j + 1].x, contour[j + 1].y);
21751             j++;
21752           } else {
21753             quadraticCurveTo(contour[j].x, contour[j].y,
21754               (contour[j].x + contour[j + 1].x) / 2,
21755               (contour[j].y + contour[j + 1].y) / 2);
21756           }
21757         }
21758         startPoint = endPoint + 1;
21759       }
21760     }
21761   }
21762
21763   function compileCharString(code, js, font) {
21764     var stack = [];
21765     var x = 0, y = 0;
21766     var stems = 0;
21767
21768     function moveTo(x, y) {
21769       js.push('c.moveTo(' + x + ',' + y + ');');
21770     }
21771     function lineTo(x, y) {
21772       js.push('c.lineTo(' + x + ',' + y + ');');
21773     }
21774     function bezierCurveTo(x1, y1, x2, y2, x, y) {
21775       js.push('c.bezierCurveTo(' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + ',' +
21776                                    x + ',' + y + ');');
21777     }
21778
21779     function parse(code) {
21780       var i = 0;
21781       while (i < code.length) {
21782         var stackClean = false;
21783         var v = code[i++];
21784         var xa, xb, ya, yb, y1, y2, y3, n, subrCode;
21785         switch (v) {
21786           case 1: // hstem
21787             stems += stack.length >> 1;
21788             stackClean = true;
21789             break;
21790           case 3: // vstem
21791             stems += stack.length >> 1;
21792             stackClean = true;
21793             break;
21794           case 4: // vmoveto
21795             y += stack.pop();
21796             moveTo(x, y);
21797             stackClean = true;
21798             break;
21799           case 5: // rlineto
21800             while (stack.length > 0) {
21801               x += stack.shift();
21802               y += stack.shift();
21803               lineTo(x, y);
21804             }
21805             break;
21806           case 6: // hlineto
21807             while (stack.length > 0) {
21808               x += stack.shift();
21809               lineTo(x, y);
21810               if (stack.length === 0) {
21811                 break;
21812               }
21813               y += stack.shift();
21814               lineTo(x, y);
21815             }
21816             break;
21817           case 7: // vlineto
21818             while (stack.length > 0) {
21819               y += stack.shift();
21820               lineTo(x, y);
21821               if (stack.length === 0) {
21822                 break;
21823               }
21824               x += stack.shift();
21825               lineTo(x, y);
21826             }
21827             break;
21828           case 8: // rrcurveto
21829             while (stack.length > 0) {
21830               xa = x + stack.shift(); ya = y + stack.shift();
21831               xb = xa + stack.shift(); yb = ya + stack.shift();
21832               x = xb + stack.shift(); y = yb + stack.shift();
21833               bezierCurveTo(xa, ya, xb, yb, x, y);
21834             }
21835             break;
21836           case 10: // callsubr
21837             n = stack.pop() + font.subrsBias;
21838             subrCode = font.subrs[n];
21839             if (subrCode) {
21840               parse(subrCode);
21841             }
21842             break;
21843           case 11: // return
21844             return;
21845           case 12:
21846             v = code[i++];
21847             switch (v) {
21848               case 34: // flex
21849                 xa = x + stack.shift();
21850                 xb = xa + stack.shift(); y1 = y + stack.shift();
21851                 x = xb + stack.shift();
21852                 bezierCurveTo(xa, y, xb, y1, x, y1);
21853                 xa = x + stack.shift();
21854                 xb = xa + stack.shift();
21855                 x = xb + stack.shift();
21856                 bezierCurveTo(xa, y1, xb, y, x, y);
21857                 break;
21858               case 35: // flex
21859                 xa = x + stack.shift(); ya = y + stack.shift();
21860                 xb = xa + stack.shift(); yb = ya + stack.shift();
21861                 x = xb + stack.shift(); y = yb + stack.shift();
21862                 bezierCurveTo(xa, ya, xb, yb, x, y);
21863                 xa = x + stack.shift(); ya = y + stack.shift();
21864                 xb = xa + stack.shift(); yb = ya + stack.shift();
21865                 x = xb + stack.shift(); y = yb + stack.shift();
21866                 bezierCurveTo(xa, ya, xb, yb, x, y);
21867                 stack.pop(); // fd
21868                 break;
21869               case 36: // hflex1
21870                 xa = x + stack.shift(); y1 = y + stack.shift();
21871                 xb = xa + stack.shift(); y2 = y1 + stack.shift();
21872                 x = xb + stack.shift();
21873                 bezierCurveTo(xa, y1, xb, y2, x, y2);
21874                 xa = x + stack.shift();
21875                 xb = xa + stack.shift(); y3 = y2 + stack.shift();
21876                 x = xb + stack.shift();
21877                 bezierCurveTo(xa, y2, xb, y3, x, y);
21878                 break;
21879               case 37: // flex1
21880                 var x0 = x, y0 = y;
21881                 xa = x + stack.shift(); ya = y + stack.shift();
21882                 xb = xa + stack.shift(); yb = ya + stack.shift();
21883                 x = xb + stack.shift(); y = yb + stack.shift();
21884                 bezierCurveTo(xa, ya, xb, yb, x, y);
21885                 xa = x + stack.shift(); ya = y + stack.shift();
21886                 xb = xa + stack.shift(); yb = ya + stack.shift();
21887                 x = xb; y = yb;
21888                 if (Math.abs(x - x0) > Math.abs(y - y0)) {
21889                   x += stack.shift();
21890                 } else  {
21891                   y += stack.shift();
21892                 }
21893                 bezierCurveTo(xa, ya, xb, yb, x, y);
21894                 break;
21895               default:
21896                 error('unknown operator: 12 ' + v);
21897             }
21898             break;
21899           case 14: // endchar
21900             if (stack.length >= 4) {
21901               var achar = stack.pop();
21902               var bchar = stack.pop();
21903               y = stack.pop();
21904               x = stack.pop();
21905               js.push('c.save();');
21906               js.push('c.translate('+ x + ',' + y + ');');
21907               var gid = lookupCmap(font.cmap, String.fromCharCode(
21908                 font.glyphNameMap[Encodings.StandardEncoding[achar]]));
21909               compileCharString(font.glyphs[gid], js, font);
21910               js.push('c.restore();');
21911
21912               gid = lookupCmap(font.cmap, String.fromCharCode(
21913                 font.glyphNameMap[Encodings.StandardEncoding[bchar]]));
21914               compileCharString(font.glyphs[gid], js, font);
21915             }
21916             return;
21917           case 18: // hstemhm
21918             stems += stack.length >> 1;
21919             stackClean = true;
21920             break;
21921           case 19: // hintmask
21922             stems += stack.length >> 1;
21923             i += (stems + 7) >> 3;
21924             stackClean = true;
21925             break;
21926           case 20: // cntrmask
21927             stems += stack.length >> 1;
21928             i += (stems + 7) >> 3;
21929             stackClean = true;
21930             break;
21931           case 21: // rmoveto
21932             y += stack.pop();
21933             x += stack.pop();
21934             moveTo(x, y);
21935             stackClean = true;
21936             break;
21937           case 22: // hmoveto
21938             x += stack.pop();
21939             moveTo(x, y);
21940             stackClean = true;
21941             break;
21942           case 23: // vstemhm
21943             stems += stack.length >> 1;
21944             stackClean = true;
21945             break;
21946           case 24: // rcurveline
21947             while (stack.length > 2) {
21948               xa = x + stack.shift(); ya = y + stack.shift();
21949               xb = xa + stack.shift(); yb = ya + stack.shift();
21950               x = xb + stack.shift(); y = yb + stack.shift();
21951               bezierCurveTo(xa, ya, xb, yb, x, y);
21952             }
21953             x += stack.shift();
21954             y += stack.shift();
21955             lineTo(x, y);
21956             break;
21957           case 25: // rlinecurve
21958             while (stack.length > 6) {
21959               x += stack.shift();
21960               y += stack.shift();
21961               lineTo(x, y);
21962             }
21963             xa = x + stack.shift(); ya = y + stack.shift();
21964             xb = xa + stack.shift(); yb = ya + stack.shift();
21965             x = xb + stack.shift(); y = yb + stack.shift();
21966             bezierCurveTo(xa, ya, xb, yb, x, y);
21967             break;
21968           case 26: // vvcurveto
21969             if (stack.length % 2) {
21970               x += stack.shift();
21971             }
21972             while (stack.length > 0) {
21973               xa = x; ya = y + stack.shift();
21974               xb = xa + stack.shift(); yb = ya + stack.shift();
21975               x = xb; y = yb + stack.shift();
21976               bezierCurveTo(xa, ya, xb, yb, x, y);
21977             }
21978             break;
21979           case 27: // hhcurveto
21980             if (stack.length % 2) {
21981               y += stack.shift();
21982             }
21983             while (stack.length > 0) {
21984               xa = x + stack.shift(); ya = y;
21985               xb = xa + stack.shift(); yb = ya + stack.shift();
21986               x = xb + stack.shift(); y = yb;
21987               bezierCurveTo(xa, ya, xb, yb, x, y);
21988             }
21989             break;
21990           case 28:
21991             stack.push(((code[i] << 24) | (code[i + 1] << 16)) >> 16);
21992             i += 2;
21993             break;
21994           case 29: // callgsubr
21995             n = stack.pop() + font.gsubrsBias;
21996             subrCode = font.gsubrs[n];
21997             if (subrCode) {
21998               parse(subrCode);
21999             }
22000             break;
22001           case 30: // vhcurveto
22002             while (stack.length > 0) {
22003               xa = x; ya = y + stack.shift();
22004               xb = xa + stack.shift(); yb = ya + stack.shift();
22005               x = xb + stack.shift();
22006               y = yb + (stack.length === 1 ? stack.shift() : 0);
22007               bezierCurveTo(xa, ya, xb, yb, x, y);
22008               if (stack.length === 0) {
22009                 break;
22010               }
22011
22012               xa = x + stack.shift(); ya = y;
22013               xb = xa + stack.shift(); yb = ya + stack.shift();
22014               y = yb + stack.shift();
22015               x = xb + (stack.length === 1 ? stack.shift() : 0);
22016               bezierCurveTo(xa, ya, xb, yb, x, y);
22017             }
22018             break;
22019           case 31: // hvcurveto
22020             while (stack.length > 0) {
22021               xa = x + stack.shift(); ya = y;
22022               xb = xa + stack.shift(); yb = ya + stack.shift();
22023               y = yb + stack.shift();
22024               x = xb + (stack.length === 1 ? stack.shift() : 0);
22025               bezierCurveTo(xa, ya, xb, yb, x, y);
22026               if (stack.length === 0) {
22027                 break;
22028               }
22029
22030               xa = x; ya = y + stack.shift();
22031               xb = xa + stack.shift(); yb = ya + stack.shift();
22032               x = xb + stack.shift();
22033               y = yb + (stack.length === 1 ? stack.shift() : 0);
22034               bezierCurveTo(xa, ya, xb, yb, x, y);
22035             }
22036             break;
22037           default:
22038             if (v < 32) {
22039               error('unknown operator: ' + v);
22040             }
22041             if (v < 247) {
22042               stack.push(v - 139);
22043             } else if (v < 251) {
22044               stack.push((v - 247) * 256 + code[i++] + 108);
22045             } else if (v < 255) {
22046               stack.push(-(v - 251) * 256 - code[i++] - 108);
22047             } else {
22048               stack.push(((code[i] << 24) | (code[i + 1] << 16) |
22049                          (code[i + 2] << 8) | code[i + 3]) / 65536);
22050               i += 4;
22051             }
22052             break;
22053         }
22054         if (stackClean) {
22055           stack.length = 0;
22056         }
22057       }
22058     }
22059     parse(code);
22060   }
22061
22062   var noop = '';
22063
22064   function CompiledFont(fontMatrix) {
22065     this.compiledGlyphs = {};
22066     this.fontMatrix = fontMatrix;
22067   }
22068   CompiledFont.prototype = {
22069     getPathJs: function (unicode) {
22070       var gid = lookupCmap(this.cmap, unicode);
22071       var fn = this.compiledGlyphs[gid];
22072       if (!fn) {
22073         this.compiledGlyphs[gid] = fn = this.compileGlyph(this.glyphs[gid]);
22074       }
22075       return fn;
22076     },
22077
22078     compileGlyph: function (code) {
22079       if (!code || code.length === 0 || code[0] === 14) {
22080         return noop;
22081       }
22082
22083       var js = [];
22084       js.push('c.save();');
22085       js.push('c.transform(' + this.fontMatrix.join(',') + ');');
22086       js.push('c.scale(size, -size);');
22087
22088       this.compileGlyphImpl(code, js);
22089
22090       js.push('c.restore();');
22091
22092       return js.join('\n');
22093     },
22094
22095     compileGlyphImpl: function () {
22096       error('Children classes should implement this.');
22097     },
22098
22099     hasBuiltPath: function (unicode) {
22100       var gid = lookupCmap(this.cmap, unicode);
22101       return gid in this.compiledGlyphs;
22102     }
22103   };
22104
22105   function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
22106     fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];
22107     CompiledFont.call(this, fontMatrix);
22108
22109     this.glyphs = glyphs;
22110     this.cmap = cmap;
22111
22112     this.compiledGlyphs = [];
22113   }
22114
22115   Util.inherit(TrueTypeCompiled, CompiledFont, {
22116     compileGlyphImpl: function (code, js) {
22117       compileGlyf(code, js, this);
22118     }
22119   });
22120
22121   function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {
22122     fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0];
22123     CompiledFont.call(this, fontMatrix);
22124     this.glyphs = cffInfo.glyphs;
22125     this.gsubrs = cffInfo.gsubrs || [];
22126     this.subrs = cffInfo.subrs || [];
22127     this.cmap = cmap;
22128     this.glyphNameMap = glyphNameMap || GlyphsUnicode;
22129
22130     this.compiledGlyphs = [];
22131     this.gsubrsBias = (this.gsubrs.length < 1240 ?
22132                        107 : (this.gsubrs.length < 33900 ? 1131 : 32768));
22133     this.subrsBias = (this.subrs.length < 1240 ?
22134                       107 : (this.subrs.length < 33900 ? 1131 : 32768));
22135   }
22136
22137   Util.inherit(Type2Compiled, CompiledFont, {
22138     compileGlyphImpl: function (code, js) {
22139       compileCharString(code, js, this);
22140     }
22141   });
22142
22143
22144   return {
22145     create: function FontRendererFactory_create(font) {
22146       var data = new Uint8Array(font.data);
22147       var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
22148       var numTables = getUshort(data, 4);
22149       for (var i = 0, p = 12; i < numTables; i++, p += 16) {
22150         var tag = bytesToString(data.subarray(p, p + 4));
22151         var offset = getLong(data, p + 8);
22152         var length = getLong(data, p + 12);
22153         switch (tag) {
22154           case 'cmap':
22155             cmap = parseCmap(data, offset, offset + length);
22156             break;
22157           case 'glyf':
22158             glyf = data.subarray(offset, offset + length);
22159             break;
22160           case 'loca':
22161             loca = data.subarray(offset, offset + length);
22162             break;
22163           case 'head':
22164             unitsPerEm = getUshort(data, offset + 18);
22165             indexToLocFormat = getUshort(data, offset + 50);
22166             break;
22167           case 'CFF ':
22168             cff = parseCff(data, offset, offset + length);
22169             break;
22170         }
22171       }
22172
22173       if (glyf) {
22174         var fontMatrix = (!unitsPerEm ? font.fontMatrix :
22175                           [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]);
22176         return new TrueTypeCompiled(
22177           parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
22178       } else {
22179         return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
22180       }
22181     }
22182   };
22183 })();
22184
22185
22186 var GlyphsUnicode = {
22187   A: 0x0041,
22188   AE: 0x00C6,
22189   AEacute: 0x01FC,
22190   AEmacron: 0x01E2,
22191   AEsmall: 0xF7E6,
22192   Aacute: 0x00C1,
22193   Aacutesmall: 0xF7E1,
22194   Abreve: 0x0102,
22195   Abreveacute: 0x1EAE,
22196   Abrevecyrillic: 0x04D0,
22197   Abrevedotbelow: 0x1EB6,
22198   Abrevegrave: 0x1EB0,
22199   Abrevehookabove: 0x1EB2,
22200   Abrevetilde: 0x1EB4,
22201   Acaron: 0x01CD,
22202   Acircle: 0x24B6,
22203   Acircumflex: 0x00C2,
22204   Acircumflexacute: 0x1EA4,
22205   Acircumflexdotbelow: 0x1EAC,
22206   Acircumflexgrave: 0x1EA6,
22207   Acircumflexhookabove: 0x1EA8,
22208   Acircumflexsmall: 0xF7E2,
22209   Acircumflextilde: 0x1EAA,
22210   Acute: 0xF6C9,
22211   Acutesmall: 0xF7B4,
22212   Acyrillic: 0x0410,
22213   Adblgrave: 0x0200,
22214   Adieresis: 0x00C4,
22215   Adieresiscyrillic: 0x04D2,
22216   Adieresismacron: 0x01DE,
22217   Adieresissmall: 0xF7E4,
22218   Adotbelow: 0x1EA0,
22219   Adotmacron: 0x01E0,
22220   Agrave: 0x00C0,
22221   Agravesmall: 0xF7E0,
22222   Ahookabove: 0x1EA2,
22223   Aiecyrillic: 0x04D4,
22224   Ainvertedbreve: 0x0202,
22225   Alpha: 0x0391,
22226   Alphatonos: 0x0386,
22227   Amacron: 0x0100,
22228   Amonospace: 0xFF21,
22229   Aogonek: 0x0104,
22230   Aring: 0x00C5,
22231   Aringacute: 0x01FA,
22232   Aringbelow: 0x1E00,
22233   Aringsmall: 0xF7E5,
22234   Asmall: 0xF761,
22235   Atilde: 0x00C3,
22236   Atildesmall: 0xF7E3,
22237   Aybarmenian: 0x0531,
22238   B: 0x0042,
22239   Bcircle: 0x24B7,
22240   Bdotaccent: 0x1E02,
22241   Bdotbelow: 0x1E04,
22242   Becyrillic: 0x0411,
22243   Benarmenian: 0x0532,
22244   Beta: 0x0392,
22245   Bhook: 0x0181,
22246   Blinebelow: 0x1E06,
22247   Bmonospace: 0xFF22,
22248   Brevesmall: 0xF6F4,
22249   Bsmall: 0xF762,
22250   Btopbar: 0x0182,
22251   C: 0x0043,
22252   Caarmenian: 0x053E,
22253   Cacute: 0x0106,
22254   Caron: 0xF6CA,
22255   Caronsmall: 0xF6F5,
22256   Ccaron: 0x010C,
22257   Ccedilla: 0x00C7,
22258   Ccedillaacute: 0x1E08,
22259   Ccedillasmall: 0xF7E7,
22260   Ccircle: 0x24B8,
22261   Ccircumflex: 0x0108,
22262   Cdot: 0x010A,
22263   Cdotaccent: 0x010A,
22264   Cedillasmall: 0xF7B8,
22265   Chaarmenian: 0x0549,
22266   Cheabkhasiancyrillic: 0x04BC,
22267   Checyrillic: 0x0427,
22268   Chedescenderabkhasiancyrillic: 0x04BE,
22269   Chedescendercyrillic: 0x04B6,
22270   Chedieresiscyrillic: 0x04F4,
22271   Cheharmenian: 0x0543,
22272   Chekhakassiancyrillic: 0x04CB,
22273   Cheverticalstrokecyrillic: 0x04B8,
22274   Chi: 0x03A7,
22275   Chook: 0x0187,
22276   Circumflexsmall: 0xF6F6,
22277   Cmonospace: 0xFF23,
22278   Coarmenian: 0x0551,
22279   Csmall: 0xF763,
22280   D: 0x0044,
22281   DZ: 0x01F1,
22282   DZcaron: 0x01C4,
22283   Daarmenian: 0x0534,
22284   Dafrican: 0x0189,
22285   Dcaron: 0x010E,
22286   Dcedilla: 0x1E10,
22287   Dcircle: 0x24B9,
22288   Dcircumflexbelow: 0x1E12,
22289   Dcroat: 0x0110,
22290   Ddotaccent: 0x1E0A,
22291   Ddotbelow: 0x1E0C,
22292   Decyrillic: 0x0414,
22293   Deicoptic: 0x03EE,
22294   Delta: 0x2206,
22295   Deltagreek: 0x0394,
22296   Dhook: 0x018A,
22297   Dieresis: 0xF6CB,
22298   DieresisAcute: 0xF6CC,
22299   DieresisGrave: 0xF6CD,
22300   Dieresissmall: 0xF7A8,
22301   Digammagreek: 0x03DC,
22302   Djecyrillic: 0x0402,
22303   Dlinebelow: 0x1E0E,
22304   Dmonospace: 0xFF24,
22305   Dotaccentsmall: 0xF6F7,
22306   Dslash: 0x0110,
22307   Dsmall: 0xF764,
22308   Dtopbar: 0x018B,
22309   Dz: 0x01F2,
22310   Dzcaron: 0x01C5,
22311   Dzeabkhasiancyrillic: 0x04E0,
22312   Dzecyrillic: 0x0405,
22313   Dzhecyrillic: 0x040F,
22314   E: 0x0045,
22315   Eacute: 0x00C9,
22316   Eacutesmall: 0xF7E9,
22317   Ebreve: 0x0114,
22318   Ecaron: 0x011A,
22319   Ecedillabreve: 0x1E1C,
22320   Echarmenian: 0x0535,
22321   Ecircle: 0x24BA,
22322   Ecircumflex: 0x00CA,
22323   Ecircumflexacute: 0x1EBE,
22324   Ecircumflexbelow: 0x1E18,
22325   Ecircumflexdotbelow: 0x1EC6,
22326   Ecircumflexgrave: 0x1EC0,
22327   Ecircumflexhookabove: 0x1EC2,
22328   Ecircumflexsmall: 0xF7EA,
22329   Ecircumflextilde: 0x1EC4,
22330   Ecyrillic: 0x0404,
22331   Edblgrave: 0x0204,
22332   Edieresis: 0x00CB,
22333   Edieresissmall: 0xF7EB,
22334   Edot: 0x0116,
22335   Edotaccent: 0x0116,
22336   Edotbelow: 0x1EB8,
22337   Efcyrillic: 0x0424,
22338   Egrave: 0x00C8,
22339   Egravesmall: 0xF7E8,
22340   Eharmenian: 0x0537,
22341   Ehookabove: 0x1EBA,
22342   Eightroman: 0x2167,
22343   Einvertedbreve: 0x0206,
22344   Eiotifiedcyrillic: 0x0464,
22345   Elcyrillic: 0x041B,
22346   Elevenroman: 0x216A,
22347   Emacron: 0x0112,
22348   Emacronacute: 0x1E16,
22349   Emacrongrave: 0x1E14,
22350   Emcyrillic: 0x041C,
22351   Emonospace: 0xFF25,
22352   Encyrillic: 0x041D,
22353   Endescendercyrillic: 0x04A2,
22354   Eng: 0x014A,
22355   Enghecyrillic: 0x04A4,
22356   Enhookcyrillic: 0x04C7,
22357   Eogonek: 0x0118,
22358   Eopen: 0x0190,
22359   Epsilon: 0x0395,
22360   Epsilontonos: 0x0388,
22361   Ercyrillic: 0x0420,
22362   Ereversed: 0x018E,
22363   Ereversedcyrillic: 0x042D,
22364   Escyrillic: 0x0421,
22365   Esdescendercyrillic: 0x04AA,
22366   Esh: 0x01A9,
22367   Esmall: 0xF765,
22368   Eta: 0x0397,
22369   Etarmenian: 0x0538,
22370   Etatonos: 0x0389,
22371   Eth: 0x00D0,
22372   Ethsmall: 0xF7F0,
22373   Etilde: 0x1EBC,
22374   Etildebelow: 0x1E1A,
22375   Euro: 0x20AC,
22376   Ezh: 0x01B7,
22377   Ezhcaron: 0x01EE,
22378   Ezhreversed: 0x01B8,
22379   F: 0x0046,
22380   Fcircle: 0x24BB,
22381   Fdotaccent: 0x1E1E,
22382   Feharmenian: 0x0556,
22383   Feicoptic: 0x03E4,
22384   Fhook: 0x0191,
22385   Fitacyrillic: 0x0472,
22386   Fiveroman: 0x2164,
22387   Fmonospace: 0xFF26,
22388   Fourroman: 0x2163,
22389   Fsmall: 0xF766,
22390   G: 0x0047,
22391   GBsquare: 0x3387,
22392   Gacute: 0x01F4,
22393   Gamma: 0x0393,
22394   Gammaafrican: 0x0194,
22395   Gangiacoptic: 0x03EA,
22396   Gbreve: 0x011E,
22397   Gcaron: 0x01E6,
22398   Gcedilla: 0x0122,
22399   Gcircle: 0x24BC,
22400   Gcircumflex: 0x011C,
22401   Gcommaaccent: 0x0122,
22402   Gdot: 0x0120,
22403   Gdotaccent: 0x0120,
22404   Gecyrillic: 0x0413,
22405   Ghadarmenian: 0x0542,
22406   Ghemiddlehookcyrillic: 0x0494,
22407   Ghestrokecyrillic: 0x0492,
22408   Gheupturncyrillic: 0x0490,
22409   Ghook: 0x0193,
22410   Gimarmenian: 0x0533,
22411   Gjecyrillic: 0x0403,
22412   Gmacron: 0x1E20,
22413   Gmonospace: 0xFF27,
22414   Grave: 0xF6CE,
22415   Gravesmall: 0xF760,
22416   Gsmall: 0xF767,
22417   Gsmallhook: 0x029B,
22418   Gstroke: 0x01E4,
22419   H: 0x0048,
22420   H18533: 0x25CF,
22421   H18543: 0x25AA,
22422   H18551: 0x25AB,
22423   H22073: 0x25A1,
22424   HPsquare: 0x33CB,
22425   Haabkhasiancyrillic: 0x04A8,
22426   Hadescendercyrillic: 0x04B2,
22427   Hardsigncyrillic: 0x042A,
22428   Hbar: 0x0126,
22429   Hbrevebelow: 0x1E2A,
22430   Hcedilla: 0x1E28,
22431   Hcircle: 0x24BD,
22432   Hcircumflex: 0x0124,
22433   Hdieresis: 0x1E26,
22434   Hdotaccent: 0x1E22,
22435   Hdotbelow: 0x1E24,
22436   Hmonospace: 0xFF28,
22437   Hoarmenian: 0x0540,
22438   Horicoptic: 0x03E8,
22439   Hsmall: 0xF768,
22440   Hungarumlaut: 0xF6CF,
22441   Hungarumlautsmall: 0xF6F8,
22442   Hzsquare: 0x3390,
22443   I: 0x0049,
22444   IAcyrillic: 0x042F,
22445   IJ: 0x0132,
22446   IUcyrillic: 0x042E,
22447   Iacute: 0x00CD,
22448   Iacutesmall: 0xF7ED,
22449   Ibreve: 0x012C,
22450   Icaron: 0x01CF,
22451   Icircle: 0x24BE,
22452   Icircumflex: 0x00CE,
22453   Icircumflexsmall: 0xF7EE,
22454   Icyrillic: 0x0406,
22455   Idblgrave: 0x0208,
22456   Idieresis: 0x00CF,
22457   Idieresisacute: 0x1E2E,
22458   Idieresiscyrillic: 0x04E4,
22459   Idieresissmall: 0xF7EF,
22460   Idot: 0x0130,
22461   Idotaccent: 0x0130,
22462   Idotbelow: 0x1ECA,
22463   Iebrevecyrillic: 0x04D6,
22464   Iecyrillic: 0x0415,
22465   Ifraktur: 0x2111,
22466   Igrave: 0x00CC,
22467   Igravesmall: 0xF7EC,
22468   Ihookabove: 0x1EC8,
22469   Iicyrillic: 0x0418,
22470   Iinvertedbreve: 0x020A,
22471   Iishortcyrillic: 0x0419,
22472   Imacron: 0x012A,
22473   Imacroncyrillic: 0x04E2,
22474   Imonospace: 0xFF29,
22475   Iniarmenian: 0x053B,
22476   Iocyrillic: 0x0401,
22477   Iogonek: 0x012E,
22478   Iota: 0x0399,
22479   Iotaafrican: 0x0196,
22480   Iotadieresis: 0x03AA,
22481   Iotatonos: 0x038A,
22482   Ismall: 0xF769,
22483   Istroke: 0x0197,
22484   Itilde: 0x0128,
22485   Itildebelow: 0x1E2C,
22486   Izhitsacyrillic: 0x0474,
22487   Izhitsadblgravecyrillic: 0x0476,
22488   J: 0x004A,
22489   Jaarmenian: 0x0541,
22490   Jcircle: 0x24BF,
22491   Jcircumflex: 0x0134,
22492   Jecyrillic: 0x0408,
22493   Jheharmenian: 0x054B,
22494   Jmonospace: 0xFF2A,
22495   Jsmall: 0xF76A,
22496   K: 0x004B,
22497   KBsquare: 0x3385,
22498   KKsquare: 0x33CD,
22499   Kabashkircyrillic: 0x04A0,
22500   Kacute: 0x1E30,
22501   Kacyrillic: 0x041A,
22502   Kadescendercyrillic: 0x049A,
22503   Kahookcyrillic: 0x04C3,
22504   Kappa: 0x039A,
22505   Kastrokecyrillic: 0x049E,
22506   Kaverticalstrokecyrillic: 0x049C,
22507   Kcaron: 0x01E8,
22508   Kcedilla: 0x0136,
22509   Kcircle: 0x24C0,
22510   Kcommaaccent: 0x0136,
22511   Kdotbelow: 0x1E32,
22512   Keharmenian: 0x0554,
22513   Kenarmenian: 0x053F,
22514   Khacyrillic: 0x0425,
22515   Kheicoptic: 0x03E6,
22516   Khook: 0x0198,
22517   Kjecyrillic: 0x040C,
22518   Klinebelow: 0x1E34,
22519   Kmonospace: 0xFF2B,
22520   Koppacyrillic: 0x0480,
22521   Koppagreek: 0x03DE,
22522   Ksicyrillic: 0x046E,
22523   Ksmall: 0xF76B,
22524   L: 0x004C,
22525   LJ: 0x01C7,
22526   LL: 0xF6BF,
22527   Lacute: 0x0139,
22528   Lambda: 0x039B,
22529   Lcaron: 0x013D,
22530   Lcedilla: 0x013B,
22531   Lcircle: 0x24C1,
22532   Lcircumflexbelow: 0x1E3C,
22533   Lcommaaccent: 0x013B,
22534   Ldot: 0x013F,
22535   Ldotaccent: 0x013F,
22536   Ldotbelow: 0x1E36,
22537   Ldotbelowmacron: 0x1E38,
22538   Liwnarmenian: 0x053C,
22539   Lj: 0x01C8,
22540   Ljecyrillic: 0x0409,
22541   Llinebelow: 0x1E3A,
22542   Lmonospace: 0xFF2C,
22543   Lslash: 0x0141,
22544   Lslashsmall: 0xF6F9,
22545   Lsmall: 0xF76C,
22546   M: 0x004D,
22547   MBsquare: 0x3386,
22548   Macron: 0xF6D0,
22549   Macronsmall: 0xF7AF,
22550   Macute: 0x1E3E,
22551   Mcircle: 0x24C2,
22552   Mdotaccent: 0x1E40,
22553   Mdotbelow: 0x1E42,
22554   Menarmenian: 0x0544,
22555   Mmonospace: 0xFF2D,
22556   Msmall: 0xF76D,
22557   Mturned: 0x019C,
22558   Mu: 0x039C,
22559   N: 0x004E,
22560   NJ: 0x01CA,
22561   Nacute: 0x0143,
22562   Ncaron: 0x0147,
22563   Ncedilla: 0x0145,
22564   Ncircle: 0x24C3,
22565   Ncircumflexbelow: 0x1E4A,
22566   Ncommaaccent: 0x0145,
22567   Ndotaccent: 0x1E44,
22568   Ndotbelow: 0x1E46,
22569   Nhookleft: 0x019D,
22570   Nineroman: 0x2168,
22571   Nj: 0x01CB,
22572   Njecyrillic: 0x040A,
22573   Nlinebelow: 0x1E48,
22574   Nmonospace: 0xFF2E,
22575   Nowarmenian: 0x0546,
22576   Nsmall: 0xF76E,
22577   Ntilde: 0x00D1,
22578   Ntildesmall: 0xF7F1,
22579   Nu: 0x039D,
22580   O: 0x004F,
22581   OE: 0x0152,
22582   OEsmall: 0xF6FA,
22583   Oacute: 0x00D3,
22584   Oacutesmall: 0xF7F3,
22585   Obarredcyrillic: 0x04E8,
22586   Obarreddieresiscyrillic: 0x04EA,
22587   Obreve: 0x014E,
22588   Ocaron: 0x01D1,
22589   Ocenteredtilde: 0x019F,
22590   Ocircle: 0x24C4,
22591   Ocircumflex: 0x00D4,
22592   Ocircumflexacute: 0x1ED0,
22593   Ocircumflexdotbelow: 0x1ED8,
22594   Ocircumflexgrave: 0x1ED2,
22595   Ocircumflexhookabove: 0x1ED4,
22596   Ocircumflexsmall: 0xF7F4,
22597   Ocircumflextilde: 0x1ED6,
22598   Ocyrillic: 0x041E,
22599   Odblacute: 0x0150,
22600   Odblgrave: 0x020C,
22601   Odieresis: 0x00D6,
22602   Odieresiscyrillic: 0x04E6,
22603   Odieresissmall: 0xF7F6,
22604   Odotbelow: 0x1ECC,
22605   Ogoneksmall: 0xF6FB,
22606   Ograve: 0x00D2,
22607   Ogravesmall: 0xF7F2,
22608   Oharmenian: 0x0555,
22609   Ohm: 0x2126,
22610   Ohookabove: 0x1ECE,
22611   Ohorn: 0x01A0,
22612   Ohornacute: 0x1EDA,
22613   Ohorndotbelow: 0x1EE2,
22614   Ohorngrave: 0x1EDC,
22615   Ohornhookabove: 0x1EDE,
22616   Ohorntilde: 0x1EE0,
22617   Ohungarumlaut: 0x0150,
22618   Oi: 0x01A2,
22619   Oinvertedbreve: 0x020E,
22620   Omacron: 0x014C,
22621   Omacronacute: 0x1E52,
22622   Omacrongrave: 0x1E50,
22623   Omega: 0x2126,
22624   Omegacyrillic: 0x0460,
22625   Omegagreek: 0x03A9,
22626   Omegaroundcyrillic: 0x047A,
22627   Omegatitlocyrillic: 0x047C,
22628   Omegatonos: 0x038F,
22629   Omicron: 0x039F,
22630   Omicrontonos: 0x038C,
22631   Omonospace: 0xFF2F,
22632   Oneroman: 0x2160,
22633   Oogonek: 0x01EA,
22634   Oogonekmacron: 0x01EC,
22635   Oopen: 0x0186,
22636   Oslash: 0x00D8,
22637   Oslashacute: 0x01FE,
22638   Oslashsmall: 0xF7F8,
22639   Osmall: 0xF76F,
22640   Ostrokeacute: 0x01FE,
22641   Otcyrillic: 0x047E,
22642   Otilde: 0x00D5,
22643   Otildeacute: 0x1E4C,
22644   Otildedieresis: 0x1E4E,
22645   Otildesmall: 0xF7F5,
22646   P: 0x0050,
22647   Pacute: 0x1E54,
22648   Pcircle: 0x24C5,
22649   Pdotaccent: 0x1E56,
22650   Pecyrillic: 0x041F,
22651   Peharmenian: 0x054A,
22652   Pemiddlehookcyrillic: 0x04A6,
22653   Phi: 0x03A6,
22654   Phook: 0x01A4,
22655   Pi: 0x03A0,
22656   Piwrarmenian: 0x0553,
22657   Pmonospace: 0xFF30,
22658   Psi: 0x03A8,
22659   Psicyrillic: 0x0470,
22660   Psmall: 0xF770,
22661   Q: 0x0051,
22662   Qcircle: 0x24C6,
22663   Qmonospace: 0xFF31,
22664   Qsmall: 0xF771,
22665   R: 0x0052,
22666   Raarmenian: 0x054C,
22667   Racute: 0x0154,
22668   Rcaron: 0x0158,
22669   Rcedilla: 0x0156,
22670   Rcircle: 0x24C7,
22671   Rcommaaccent: 0x0156,
22672   Rdblgrave: 0x0210,
22673   Rdotaccent: 0x1E58,
22674   Rdotbelow: 0x1E5A,
22675   Rdotbelowmacron: 0x1E5C,
22676   Reharmenian: 0x0550,
22677   Rfraktur: 0x211C,
22678   Rho: 0x03A1,
22679   Ringsmall: 0xF6FC,
22680   Rinvertedbreve: 0x0212,
22681   Rlinebelow: 0x1E5E,
22682   Rmonospace: 0xFF32,
22683   Rsmall: 0xF772,
22684   Rsmallinverted: 0x0281,
22685   Rsmallinvertedsuperior: 0x02B6,
22686   S: 0x0053,
22687   SF010000: 0x250C,
22688   SF020000: 0x2514,
22689   SF030000: 0x2510,
22690   SF040000: 0x2518,
22691   SF050000: 0x253C,
22692   SF060000: 0x252C,
22693   SF070000: 0x2534,
22694   SF080000: 0x251C,
22695   SF090000: 0x2524,
22696   SF100000: 0x2500,
22697   SF110000: 0x2502,
22698   SF190000: 0x2561,
22699   SF200000: 0x2562,
22700   SF210000: 0x2556,
22701   SF220000: 0x2555,
22702   SF230000: 0x2563,
22703   SF240000: 0x2551,
22704   SF250000: 0x2557,
22705   SF260000: 0x255D,
22706   SF270000: 0x255C,
22707   SF280000: 0x255B,
22708   SF360000: 0x255E,
22709   SF370000: 0x255F,
22710   SF380000: 0x255A,
22711   SF390000: 0x2554,
22712   SF400000: 0x2569,
22713   SF410000: 0x2566,
22714   SF420000: 0x2560,
22715   SF430000: 0x2550,
22716   SF440000: 0x256C,
22717   SF450000: 0x2567,
22718   SF460000: 0x2568,
22719   SF470000: 0x2564,
22720   SF480000: 0x2565,
22721   SF490000: 0x2559,
22722   SF500000: 0x2558,
22723   SF510000: 0x2552,
22724   SF520000: 0x2553,
22725   SF530000: 0x256B,
22726   SF540000: 0x256A,
22727   Sacute: 0x015A,
22728   Sacutedotaccent: 0x1E64,
22729   Sampigreek: 0x03E0,
22730   Scaron: 0x0160,
22731   Scarondotaccent: 0x1E66,
22732   Scaronsmall: 0xF6FD,
22733   Scedilla: 0x015E,
22734   Schwa: 0x018F,
22735   Schwacyrillic: 0x04D8,
22736   Schwadieresiscyrillic: 0x04DA,
22737   Scircle: 0x24C8,
22738   Scircumflex: 0x015C,
22739   Scommaaccent: 0x0218,
22740   Sdotaccent: 0x1E60,
22741   Sdotbelow: 0x1E62,
22742   Sdotbelowdotaccent: 0x1E68,
22743   Seharmenian: 0x054D,
22744   Sevenroman: 0x2166,
22745   Shaarmenian: 0x0547,
22746   Shacyrillic: 0x0428,
22747   Shchacyrillic: 0x0429,
22748   Sheicoptic: 0x03E2,
22749   Shhacyrillic: 0x04BA,
22750   Shimacoptic: 0x03EC,
22751   Sigma: 0x03A3,
22752   Sixroman: 0x2165,
22753   Smonospace: 0xFF33,
22754   Softsigncyrillic: 0x042C,
22755   Ssmall: 0xF773,
22756   Stigmagreek: 0x03DA,
22757   T: 0x0054,
22758   Tau: 0x03A4,
22759   Tbar: 0x0166,
22760   Tcaron: 0x0164,
22761   Tcedilla: 0x0162,
22762   Tcircle: 0x24C9,
22763   Tcircumflexbelow: 0x1E70,
22764   Tcommaaccent: 0x0162,
22765   Tdotaccent: 0x1E6A,
22766   Tdotbelow: 0x1E6C,
22767   Tecyrillic: 0x0422,
22768   Tedescendercyrillic: 0x04AC,
22769   Tenroman: 0x2169,
22770   Tetsecyrillic: 0x04B4,
22771   Theta: 0x0398,
22772   Thook: 0x01AC,
22773   Thorn: 0x00DE,
22774   Thornsmall: 0xF7FE,
22775   Threeroman: 0x2162,
22776   Tildesmall: 0xF6FE,
22777   Tiwnarmenian: 0x054F,
22778   Tlinebelow: 0x1E6E,
22779   Tmonospace: 0xFF34,
22780   Toarmenian: 0x0539,
22781   Tonefive: 0x01BC,
22782   Tonesix: 0x0184,
22783   Tonetwo: 0x01A7,
22784   Tretroflexhook: 0x01AE,
22785   Tsecyrillic: 0x0426,
22786   Tshecyrillic: 0x040B,
22787   Tsmall: 0xF774,
22788   Twelveroman: 0x216B,
22789   Tworoman: 0x2161,
22790   U: 0x0055,
22791   Uacute: 0x00DA,
22792   Uacutesmall: 0xF7FA,
22793   Ubreve: 0x016C,
22794   Ucaron: 0x01D3,
22795   Ucircle: 0x24CA,
22796   Ucircumflex: 0x00DB,
22797   Ucircumflexbelow: 0x1E76,
22798   Ucircumflexsmall: 0xF7FB,
22799   Ucyrillic: 0x0423,
22800   Udblacute: 0x0170,
22801   Udblgrave: 0x0214,
22802   Udieresis: 0x00DC,
22803   Udieresisacute: 0x01D7,
22804   Udieresisbelow: 0x1E72,
22805   Udieresiscaron: 0x01D9,
22806   Udieresiscyrillic: 0x04F0,
22807   Udieresisgrave: 0x01DB,
22808   Udieresismacron: 0x01D5,
22809   Udieresissmall: 0xF7FC,
22810   Udotbelow: 0x1EE4,
22811   Ugrave: 0x00D9,
22812   Ugravesmall: 0xF7F9,
22813   Uhookabove: 0x1EE6,
22814   Uhorn: 0x01AF,
22815   Uhornacute: 0x1EE8,
22816   Uhorndotbelow: 0x1EF0,
22817   Uhorngrave: 0x1EEA,
22818   Uhornhookabove: 0x1EEC,
22819   Uhorntilde: 0x1EEE,
22820   Uhungarumlaut: 0x0170,
22821   Uhungarumlautcyrillic: 0x04F2,
22822   Uinvertedbreve: 0x0216,
22823   Ukcyrillic: 0x0478,
22824   Umacron: 0x016A,
22825   Umacroncyrillic: 0x04EE,
22826   Umacrondieresis: 0x1E7A,
22827   Umonospace: 0xFF35,
22828   Uogonek: 0x0172,
22829   Upsilon: 0x03A5,
22830   Upsilon1: 0x03D2,
22831   Upsilonacutehooksymbolgreek: 0x03D3,
22832   Upsilonafrican: 0x01B1,
22833   Upsilondieresis: 0x03AB,
22834   Upsilondieresishooksymbolgreek: 0x03D4,
22835   Upsilonhooksymbol: 0x03D2,
22836   Upsilontonos: 0x038E,
22837   Uring: 0x016E,
22838   Ushortcyrillic: 0x040E,
22839   Usmall: 0xF775,
22840   Ustraightcyrillic: 0x04AE,
22841   Ustraightstrokecyrillic: 0x04B0,
22842   Utilde: 0x0168,
22843   Utildeacute: 0x1E78,
22844   Utildebelow: 0x1E74,
22845   V: 0x0056,
22846   Vcircle: 0x24CB,
22847   Vdotbelow: 0x1E7E,
22848   Vecyrillic: 0x0412,
22849   Vewarmenian: 0x054E,
22850   Vhook: 0x01B2,
22851   Vmonospace: 0xFF36,
22852   Voarmenian: 0x0548,
22853   Vsmall: 0xF776,
22854   Vtilde: 0x1E7C,
22855   W: 0x0057,
22856   Wacute: 0x1E82,
22857   Wcircle: 0x24CC,
22858   Wcircumflex: 0x0174,
22859   Wdieresis: 0x1E84,
22860   Wdotaccent: 0x1E86,
22861   Wdotbelow: 0x1E88,
22862   Wgrave: 0x1E80,
22863   Wmonospace: 0xFF37,
22864   Wsmall: 0xF777,
22865   X: 0x0058,
22866   Xcircle: 0x24CD,
22867   Xdieresis: 0x1E8C,
22868   Xdotaccent: 0x1E8A,
22869   Xeharmenian: 0x053D,
22870   Xi: 0x039E,
22871   Xmonospace: 0xFF38,
22872   Xsmall: 0xF778,
22873   Y: 0x0059,
22874   Yacute: 0x00DD,
22875   Yacutesmall: 0xF7FD,
22876   Yatcyrillic: 0x0462,
22877   Ycircle: 0x24CE,
22878   Ycircumflex: 0x0176,
22879   Ydieresis: 0x0178,
22880   Ydieresissmall: 0xF7FF,
22881   Ydotaccent: 0x1E8E,
22882   Ydotbelow: 0x1EF4,
22883   Yericyrillic: 0x042B,
22884   Yerudieresiscyrillic: 0x04F8,
22885   Ygrave: 0x1EF2,
22886   Yhook: 0x01B3,
22887   Yhookabove: 0x1EF6,
22888   Yiarmenian: 0x0545,
22889   Yicyrillic: 0x0407,
22890   Yiwnarmenian: 0x0552,
22891   Ymonospace: 0xFF39,
22892   Ysmall: 0xF779,
22893   Ytilde: 0x1EF8,
22894   Yusbigcyrillic: 0x046A,
22895   Yusbigiotifiedcyrillic: 0x046C,
22896   Yuslittlecyrillic: 0x0466,
22897   Yuslittleiotifiedcyrillic: 0x0468,
22898   Z: 0x005A,
22899   Zaarmenian: 0x0536,
22900   Zacute: 0x0179,
22901   Zcaron: 0x017D,
22902   Zcaronsmall: 0xF6FF,
22903   Zcircle: 0x24CF,
22904   Zcircumflex: 0x1E90,
22905   Zdot: 0x017B,
22906   Zdotaccent: 0x017B,
22907   Zdotbelow: 0x1E92,
22908   Zecyrillic: 0x0417,
22909   Zedescendercyrillic: 0x0498,
22910   Zedieresiscyrillic: 0x04DE,
22911   Zeta: 0x0396,
22912   Zhearmenian: 0x053A,
22913   Zhebrevecyrillic: 0x04C1,
22914   Zhecyrillic: 0x0416,
22915   Zhedescendercyrillic: 0x0496,
22916   Zhedieresiscyrillic: 0x04DC,
22917   Zlinebelow: 0x1E94,
22918   Zmonospace: 0xFF3A,
22919   Zsmall: 0xF77A,
22920   Zstroke: 0x01B5,
22921   a: 0x0061,
22922   aabengali: 0x0986,
22923   aacute: 0x00E1,
22924   aadeva: 0x0906,
22925   aagujarati: 0x0A86,
22926   aagurmukhi: 0x0A06,
22927   aamatragurmukhi: 0x0A3E,
22928   aarusquare: 0x3303,
22929   aavowelsignbengali: 0x09BE,
22930   aavowelsigndeva: 0x093E,
22931   aavowelsigngujarati: 0x0ABE,
22932   abbreviationmarkarmenian: 0x055F,
22933   abbreviationsigndeva: 0x0970,
22934   abengali: 0x0985,
22935   abopomofo: 0x311A,
22936   abreve: 0x0103,
22937   abreveacute: 0x1EAF,
22938   abrevecyrillic: 0x04D1,
22939   abrevedotbelow: 0x1EB7,
22940   abrevegrave: 0x1EB1,
22941   abrevehookabove: 0x1EB3,
22942   abrevetilde: 0x1EB5,
22943   acaron: 0x01CE,
22944   acircle: 0x24D0,
22945   acircumflex: 0x00E2,
22946   acircumflexacute: 0x1EA5,
22947   acircumflexdotbelow: 0x1EAD,
22948   acircumflexgrave: 0x1EA7,
22949   acircumflexhookabove: 0x1EA9,
22950   acircumflextilde: 0x1EAB,
22951   acute: 0x00B4,
22952   acutebelowcmb: 0x0317,
22953   acutecmb: 0x0301,
22954   acutecomb: 0x0301,
22955   acutedeva: 0x0954,
22956   acutelowmod: 0x02CF,
22957   acutetonecmb: 0x0341,
22958   acyrillic: 0x0430,
22959   adblgrave: 0x0201,
22960   addakgurmukhi: 0x0A71,
22961   adeva: 0x0905,
22962   adieresis: 0x00E4,
22963   adieresiscyrillic: 0x04D3,
22964   adieresismacron: 0x01DF,
22965   adotbelow: 0x1EA1,
22966   adotmacron: 0x01E1,
22967   ae: 0x00E6,
22968   aeacute: 0x01FD,
22969   aekorean: 0x3150,
22970   aemacron: 0x01E3,
22971   afii00208: 0x2015,
22972   afii08941: 0x20A4,
22973   afii10017: 0x0410,
22974   afii10018: 0x0411,
22975   afii10019: 0x0412,
22976   afii10020: 0x0413,
22977   afii10021: 0x0414,
22978   afii10022: 0x0415,
22979   afii10023: 0x0401,
22980   afii10024: 0x0416,
22981   afii10025: 0x0417,
22982   afii10026: 0x0418,
22983   afii10027: 0x0419,
22984   afii10028: 0x041A,
22985   afii10029: 0x041B,
22986   afii10030: 0x041C,
22987   afii10031: 0x041D,
22988   afii10032: 0x041E,
22989   afii10033: 0x041F,
22990   afii10034: 0x0420,
22991   afii10035: 0x0421,
22992   afii10036: 0x0422,
22993   afii10037: 0x0423,
22994   afii10038: 0x0424,
22995   afii10039: 0x0425,
22996   afii10040: 0x0426,
22997   afii10041: 0x0427,
22998   afii10042: 0x0428,
22999   afii10043: 0x0429,
23000   afii10044: 0x042A,
23001   afii10045: 0x042B,
23002   afii10046: 0x042C,
23003   afii10047: 0x042D,
23004   afii10048: 0x042E,
23005   afii10049: 0x042F,
23006   afii10050: 0x0490,
23007   afii10051: 0x0402,
23008   afii10052: 0x0403,
23009   afii10053: 0x0404,
23010   afii10054: 0x0405,
23011   afii10055: 0x0406,
23012   afii10056: 0x0407,
23013   afii10057: 0x0408,
23014   afii10058: 0x0409,
23015   afii10059: 0x040A,
23016   afii10060: 0x040B,
23017   afii10061: 0x040C,
23018   afii10062: 0x040E,
23019   afii10063: 0xF6C4,
23020   afii10064: 0xF6C5,
23021   afii10065: 0x0430,
23022   afii10066: 0x0431,
23023   afii10067: 0x0432,
23024   afii10068: 0x0433,
23025   afii10069: 0x0434,
23026   afii10070: 0x0435,
23027   afii10071: 0x0451,
23028   afii10072: 0x0436,
23029   afii10073: 0x0437,
23030   afii10074: 0x0438,
23031   afii10075: 0x0439,
23032   afii10076: 0x043A,
23033   afii10077: 0x043B,
23034   afii10078: 0x043C,
23035   afii10079: 0x043D,
23036   afii10080: 0x043E,
23037   afii10081: 0x043F,
23038   afii10082: 0x0440,
23039   afii10083: 0x0441,
23040   afii10084: 0x0442,
23041   afii10085: 0x0443,
23042   afii10086: 0x0444,
23043   afii10087: 0x0445,
23044   afii10088: 0x0446,
23045   afii10089: 0x0447,
23046   afii10090: 0x0448,
23047   afii10091: 0x0449,
23048   afii10092: 0x044A,
23049   afii10093: 0x044B,
23050   afii10094: 0x044C,
23051   afii10095: 0x044D,
23052   afii10096: 0x044E,
23053   afii10097: 0x044F,
23054   afii10098: 0x0491,
23055   afii10099: 0x0452,
23056   afii10100: 0x0453,
23057   afii10101: 0x0454,
23058   afii10102: 0x0455,
23059   afii10103: 0x0456,
23060   afii10104: 0x0457,
23061   afii10105: 0x0458,
23062   afii10106: 0x0459,
23063   afii10107: 0x045A,
23064   afii10108: 0x045B,
23065   afii10109: 0x045C,
23066   afii10110: 0x045E,
23067   afii10145: 0x040F,
23068   afii10146: 0x0462,
23069   afii10147: 0x0472,
23070   afii10148: 0x0474,
23071   afii10192: 0xF6C6,
23072   afii10193: 0x045F,
23073   afii10194: 0x0463,
23074   afii10195: 0x0473,
23075   afii10196: 0x0475,
23076   afii10831: 0xF6C7,
23077   afii10832: 0xF6C8,
23078   afii10846: 0x04D9,
23079   afii299: 0x200E,
23080   afii300: 0x200F,
23081   afii301: 0x200D,
23082   afii57381: 0x066A,
23083   afii57388: 0x060C,
23084   afii57392: 0x0660,
23085   afii57393: 0x0661,
23086   afii57394: 0x0662,
23087   afii57395: 0x0663,
23088   afii57396: 0x0664,
23089   afii57397: 0x0665,
23090   afii57398: 0x0666,
23091   afii57399: 0x0667,
23092   afii57400: 0x0668,
23093   afii57401: 0x0669,
23094   afii57403: 0x061B,
23095   afii57407: 0x061F,
23096   afii57409: 0x0621,
23097   afii57410: 0x0622,
23098   afii57411: 0x0623,
23099   afii57412: 0x0624,
23100   afii57413: 0x0625,
23101   afii57414: 0x0626,
23102   afii57415: 0x0627,
23103   afii57416: 0x0628,
23104   afii57417: 0x0629,
23105   afii57418: 0x062A,
23106   afii57419: 0x062B,
23107   afii57420: 0x062C,
23108   afii57421: 0x062D,
23109   afii57422: 0x062E,
23110   afii57423: 0x062F,
23111   afii57424: 0x0630,
23112   afii57425: 0x0631,
23113   afii57426: 0x0632,
23114   afii57427: 0x0633,
23115   afii57428: 0x0634,
23116   afii57429: 0x0635,
23117   afii57430: 0x0636,
23118   afii57431: 0x0637,
23119   afii57432: 0x0638,
23120   afii57433: 0x0639,
23121   afii57434: 0x063A,
23122   afii57440: 0x0640,
23123   afii57441: 0x0641,
23124   afii57442: 0x0642,
23125   afii57443: 0x0643,
23126   afii57444: 0x0644,
23127   afii57445: 0x0645,
23128   afii57446: 0x0646,
23129   afii57448: 0x0648,
23130   afii57449: 0x0649,
23131   afii57450: 0x064A,
23132   afii57451: 0x064B,
23133   afii57452: 0x064C,
23134   afii57453: 0x064D,
23135   afii57454: 0x064E,
23136   afii57455: 0x064F,
23137   afii57456: 0x0650,
23138   afii57457: 0x0651,
23139   afii57458: 0x0652,
23140   afii57470: 0x0647,
23141   afii57505: 0x06A4,
23142   afii57506: 0x067E,
23143   afii57507: 0x0686,
23144   afii57508: 0x0698,
23145   afii57509: 0x06AF,
23146   afii57511: 0x0679,
23147   afii57512: 0x0688,
23148   afii57513: 0x0691,
23149   afii57514: 0x06BA,
23150   afii57519: 0x06D2,
23151   afii57534: 0x06D5,
23152   afii57636: 0x20AA,
23153   afii57645: 0x05BE,
23154   afii57658: 0x05C3,
23155   afii57664: 0x05D0,
23156   afii57665: 0x05D1,
23157   afii57666: 0x05D2,
23158   afii57667: 0x05D3,
23159   afii57668: 0x05D4,
23160   afii57669: 0x05D5,
23161   afii57670: 0x05D6,
23162   afii57671: 0x05D7,
23163   afii57672: 0x05D8,
23164   afii57673: 0x05D9,
23165   afii57674: 0x05DA,
23166   afii57675: 0x05DB,
23167   afii57676: 0x05DC,
23168   afii57677: 0x05DD,
23169   afii57678: 0x05DE,
23170   afii57679: 0x05DF,
23171   afii57680: 0x05E0,
23172   afii57681: 0x05E1,
23173   afii57682: 0x05E2,
23174   afii57683: 0x05E3,
23175   afii57684: 0x05E4,
23176   afii57685: 0x05E5,
23177   afii57686: 0x05E6,
23178   afii57687: 0x05E7,
23179   afii57688: 0x05E8,
23180   afii57689: 0x05E9,
23181   afii57690: 0x05EA,
23182   afii57694: 0xFB2A,
23183   afii57695: 0xFB2B,
23184   afii57700: 0xFB4B,
23185   afii57705: 0xFB1F,
23186   afii57716: 0x05F0,
23187   afii57717: 0x05F1,
23188   afii57718: 0x05F2,
23189   afii57723: 0xFB35,
23190   afii57793: 0x05B4,
23191   afii57794: 0x05B5,
23192   afii57795: 0x05B6,
23193   afii57796: 0x05BB,
23194   afii57797: 0x05B8,
23195   afii57798: 0x05B7,
23196   afii57799: 0x05B0,
23197   afii57800: 0x05B2,
23198   afii57801: 0x05B1,
23199   afii57802: 0x05B3,
23200   afii57803: 0x05C2,
23201   afii57804: 0x05C1,
23202   afii57806: 0x05B9,
23203   afii57807: 0x05BC,
23204   afii57839: 0x05BD,
23205   afii57841: 0x05BF,
23206   afii57842: 0x05C0,
23207   afii57929: 0x02BC,
23208   afii61248: 0x2105,
23209   afii61289: 0x2113,
23210   afii61352: 0x2116,
23211   afii61573: 0x202C,
23212   afii61574: 0x202D,
23213   afii61575: 0x202E,
23214   afii61664: 0x200C,
23215   afii63167: 0x066D,
23216   afii64937: 0x02BD,
23217   agrave: 0x00E0,
23218   agujarati: 0x0A85,
23219   agurmukhi: 0x0A05,
23220   ahiragana: 0x3042,
23221   ahookabove: 0x1EA3,
23222   aibengali: 0x0990,
23223   aibopomofo: 0x311E,
23224   aideva: 0x0910,
23225   aiecyrillic: 0x04D5,
23226   aigujarati: 0x0A90,
23227   aigurmukhi: 0x0A10,
23228   aimatragurmukhi: 0x0A48,
23229   ainarabic: 0x0639,
23230   ainfinalarabic: 0xFECA,
23231   aininitialarabic: 0xFECB,
23232   ainmedialarabic: 0xFECC,
23233   ainvertedbreve: 0x0203,
23234   aivowelsignbengali: 0x09C8,
23235   aivowelsigndeva: 0x0948,
23236   aivowelsigngujarati: 0x0AC8,
23237   akatakana: 0x30A2,
23238   akatakanahalfwidth: 0xFF71,
23239   akorean: 0x314F,
23240   alef: 0x05D0,
23241   alefarabic: 0x0627,
23242   alefdageshhebrew: 0xFB30,
23243   aleffinalarabic: 0xFE8E,
23244   alefhamzaabovearabic: 0x0623,
23245   alefhamzaabovefinalarabic: 0xFE84,
23246   alefhamzabelowarabic: 0x0625,
23247   alefhamzabelowfinalarabic: 0xFE88,
23248   alefhebrew: 0x05D0,
23249   aleflamedhebrew: 0xFB4F,
23250   alefmaddaabovearabic: 0x0622,
23251   alefmaddaabovefinalarabic: 0xFE82,
23252   alefmaksuraarabic: 0x0649,
23253   alefmaksurafinalarabic: 0xFEF0,
23254   alefmaksurainitialarabic: 0xFEF3,
23255   alefmaksuramedialarabic: 0xFEF4,
23256   alefpatahhebrew: 0xFB2E,
23257   alefqamatshebrew: 0xFB2F,
23258   aleph: 0x2135,
23259   allequal: 0x224C,
23260   alpha: 0x03B1,
23261   alphatonos: 0x03AC,
23262   amacron: 0x0101,
23263   amonospace: 0xFF41,
23264   ampersand: 0x0026,
23265   ampersandmonospace: 0xFF06,
23266   ampersandsmall: 0xF726,
23267   amsquare: 0x33C2,
23268   anbopomofo: 0x3122,
23269   angbopomofo: 0x3124,
23270   angbracketleft: 0x3008, // This glyph is missing from Adobe's original list.
23271   angbracketright: 0x3009, // This glyph is missing from Adobe's original list.
23272   angkhankhuthai: 0x0E5A,
23273   angle: 0x2220,
23274   anglebracketleft: 0x3008,
23275   anglebracketleftvertical: 0xFE3F,
23276   anglebracketright: 0x3009,
23277   anglebracketrightvertical: 0xFE40,
23278   angleleft: 0x2329,
23279   angleright: 0x232A,
23280   angstrom: 0x212B,
23281   anoteleia: 0x0387,
23282   anudattadeva: 0x0952,
23283   anusvarabengali: 0x0982,
23284   anusvaradeva: 0x0902,
23285   anusvaragujarati: 0x0A82,
23286   aogonek: 0x0105,
23287   apaatosquare: 0x3300,
23288   aparen: 0x249C,
23289   apostrophearmenian: 0x055A,
23290   apostrophemod: 0x02BC,
23291   apple: 0xF8FF,
23292   approaches: 0x2250,
23293   approxequal: 0x2248,
23294   approxequalorimage: 0x2252,
23295   approximatelyequal: 0x2245,
23296   araeaekorean: 0x318E,
23297   araeakorean: 0x318D,
23298   arc: 0x2312,
23299   arighthalfring: 0x1E9A,
23300   aring: 0x00E5,
23301   aringacute: 0x01FB,
23302   aringbelow: 0x1E01,
23303   arrowboth: 0x2194,
23304   arrowdashdown: 0x21E3,
23305   arrowdashleft: 0x21E0,
23306   arrowdashright: 0x21E2,
23307   arrowdashup: 0x21E1,
23308   arrowdblboth: 0x21D4,
23309   arrowdbldown: 0x21D3,
23310   arrowdblleft: 0x21D0,
23311   arrowdblright: 0x21D2,
23312   arrowdblup: 0x21D1,
23313   arrowdown: 0x2193,
23314   arrowdownleft: 0x2199,
23315   arrowdownright: 0x2198,
23316   arrowdownwhite: 0x21E9,
23317   arrowheaddownmod: 0x02C5,
23318   arrowheadleftmod: 0x02C2,
23319   arrowheadrightmod: 0x02C3,
23320   arrowheadupmod: 0x02C4,
23321   arrowhorizex: 0xF8E7,
23322   arrowleft: 0x2190,
23323   arrowleftdbl: 0x21D0,
23324   arrowleftdblstroke: 0x21CD,
23325   arrowleftoverright: 0x21C6,
23326   arrowleftwhite: 0x21E6,
23327   arrowright: 0x2192,
23328   arrowrightdblstroke: 0x21CF,
23329   arrowrightheavy: 0x279E,
23330   arrowrightoverleft: 0x21C4,
23331   arrowrightwhite: 0x21E8,
23332   arrowtableft: 0x21E4,
23333   arrowtabright: 0x21E5,
23334   arrowup: 0x2191,
23335   arrowupdn: 0x2195,
23336   arrowupdnbse: 0x21A8,
23337   arrowupdownbase: 0x21A8,
23338   arrowupleft: 0x2196,
23339   arrowupleftofdown: 0x21C5,
23340   arrowupright: 0x2197,
23341   arrowupwhite: 0x21E7,
23342   arrowvertex: 0xF8E6,
23343   asciicircum: 0x005E,
23344   asciicircummonospace: 0xFF3E,
23345   asciitilde: 0x007E,
23346   asciitildemonospace: 0xFF5E,
23347   ascript: 0x0251,
23348   ascriptturned: 0x0252,
23349   asmallhiragana: 0x3041,
23350   asmallkatakana: 0x30A1,
23351   asmallkatakanahalfwidth: 0xFF67,
23352   asterisk: 0x002A,
23353   asteriskaltonearabic: 0x066D,
23354   asteriskarabic: 0x066D,
23355   asteriskmath: 0x2217,
23356   asteriskmonospace: 0xFF0A,
23357   asterisksmall: 0xFE61,
23358   asterism: 0x2042,
23359   asuperior: 0xF6E9,
23360   asymptoticallyequal: 0x2243,
23361   at: 0x0040,
23362   atilde: 0x00E3,
23363   atmonospace: 0xFF20,
23364   atsmall: 0xFE6B,
23365   aturned: 0x0250,
23366   aubengali: 0x0994,
23367   aubopomofo: 0x3120,
23368   audeva: 0x0914,
23369   augujarati: 0x0A94,
23370   augurmukhi: 0x0A14,
23371   aulengthmarkbengali: 0x09D7,
23372   aumatragurmukhi: 0x0A4C,
23373   auvowelsignbengali: 0x09CC,
23374   auvowelsigndeva: 0x094C,
23375   auvowelsigngujarati: 0x0ACC,
23376   avagrahadeva: 0x093D,
23377   aybarmenian: 0x0561,
23378   ayin: 0x05E2,
23379   ayinaltonehebrew: 0xFB20,
23380   ayinhebrew: 0x05E2,
23381   b: 0x0062,
23382   babengali: 0x09AC,
23383   backslash: 0x005C,
23384   backslashmonospace: 0xFF3C,
23385   badeva: 0x092C,
23386   bagujarati: 0x0AAC,
23387   bagurmukhi: 0x0A2C,
23388   bahiragana: 0x3070,
23389   bahtthai: 0x0E3F,
23390   bakatakana: 0x30D0,
23391   bar: 0x007C,
23392   barmonospace: 0xFF5C,
23393   bbopomofo: 0x3105,
23394   bcircle: 0x24D1,
23395   bdotaccent: 0x1E03,
23396   bdotbelow: 0x1E05,
23397   beamedsixteenthnotes: 0x266C,
23398   because: 0x2235,
23399   becyrillic: 0x0431,
23400   beharabic: 0x0628,
23401   behfinalarabic: 0xFE90,
23402   behinitialarabic: 0xFE91,
23403   behiragana: 0x3079,
23404   behmedialarabic: 0xFE92,
23405   behmeeminitialarabic: 0xFC9F,
23406   behmeemisolatedarabic: 0xFC08,
23407   behnoonfinalarabic: 0xFC6D,
23408   bekatakana: 0x30D9,
23409   benarmenian: 0x0562,
23410   bet: 0x05D1,
23411   beta: 0x03B2,
23412   betasymbolgreek: 0x03D0,
23413   betdagesh: 0xFB31,
23414   betdageshhebrew: 0xFB31,
23415   bethebrew: 0x05D1,
23416   betrafehebrew: 0xFB4C,
23417   bhabengali: 0x09AD,
23418   bhadeva: 0x092D,
23419   bhagujarati: 0x0AAD,
23420   bhagurmukhi: 0x0A2D,
23421   bhook: 0x0253,
23422   bihiragana: 0x3073,
23423   bikatakana: 0x30D3,
23424   bilabialclick: 0x0298,
23425   bindigurmukhi: 0x0A02,
23426   birusquare: 0x3331,
23427   blackcircle: 0x25CF,
23428   blackdiamond: 0x25C6,
23429   blackdownpointingtriangle: 0x25BC,
23430   blackleftpointingpointer: 0x25C4,
23431   blackleftpointingtriangle: 0x25C0,
23432   blacklenticularbracketleft: 0x3010,
23433   blacklenticularbracketleftvertical: 0xFE3B,
23434   blacklenticularbracketright: 0x3011,
23435   blacklenticularbracketrightvertical: 0xFE3C,
23436   blacklowerlefttriangle: 0x25E3,
23437   blacklowerrighttriangle: 0x25E2,
23438   blackrectangle: 0x25AC,
23439   blackrightpointingpointer: 0x25BA,
23440   blackrightpointingtriangle: 0x25B6,
23441   blacksmallsquare: 0x25AA,
23442   blacksmilingface: 0x263B,
23443   blacksquare: 0x25A0,
23444   blackstar: 0x2605,
23445   blackupperlefttriangle: 0x25E4,
23446   blackupperrighttriangle: 0x25E5,
23447   blackuppointingsmalltriangle: 0x25B4,
23448   blackuppointingtriangle: 0x25B2,
23449   blank: 0x2423,
23450   blinebelow: 0x1E07,
23451   block: 0x2588,
23452   bmonospace: 0xFF42,
23453   bobaimaithai: 0x0E1A,
23454   bohiragana: 0x307C,
23455   bokatakana: 0x30DC,
23456   bparen: 0x249D,
23457   bqsquare: 0x33C3,
23458   braceex: 0xF8F4,
23459   braceleft: 0x007B,
23460   braceleftbt: 0xF8F3,
23461   braceleftmid: 0xF8F2,
23462   braceleftmonospace: 0xFF5B,
23463   braceleftsmall: 0xFE5B,
23464   bracelefttp: 0xF8F1,
23465   braceleftvertical: 0xFE37,
23466   braceright: 0x007D,
23467   bracerightbt: 0xF8FE,
23468   bracerightmid: 0xF8FD,
23469   bracerightmonospace: 0xFF5D,
23470   bracerightsmall: 0xFE5C,
23471   bracerighttp: 0xF8FC,
23472   bracerightvertical: 0xFE38,
23473   bracketleft: 0x005B,
23474   bracketleftbt: 0xF8F0,
23475   bracketleftex: 0xF8EF,
23476   bracketleftmonospace: 0xFF3B,
23477   bracketlefttp: 0xF8EE,
23478   bracketright: 0x005D,
23479   bracketrightbt: 0xF8FB,
23480   bracketrightex: 0xF8FA,
23481   bracketrightmonospace: 0xFF3D,
23482   bracketrighttp: 0xF8F9,
23483   breve: 0x02D8,
23484   brevebelowcmb: 0x032E,
23485   brevecmb: 0x0306,
23486   breveinvertedbelowcmb: 0x032F,
23487   breveinvertedcmb: 0x0311,
23488   breveinverteddoublecmb: 0x0361,
23489   bridgebelowcmb: 0x032A,
23490   bridgeinvertedbelowcmb: 0x033A,
23491   brokenbar: 0x00A6,
23492   bstroke: 0x0180,
23493   bsuperior: 0xF6EA,
23494   btopbar: 0x0183,
23495   buhiragana: 0x3076,
23496   bukatakana: 0x30D6,
23497   bullet: 0x2022,
23498   bulletinverse: 0x25D8,
23499   bulletoperator: 0x2219,
23500   bullseye: 0x25CE,
23501   c: 0x0063,
23502   caarmenian: 0x056E,
23503   cabengali: 0x099A,
23504   cacute: 0x0107,
23505   cadeva: 0x091A,
23506   cagujarati: 0x0A9A,
23507   cagurmukhi: 0x0A1A,
23508   calsquare: 0x3388,
23509   candrabindubengali: 0x0981,
23510   candrabinducmb: 0x0310,
23511   candrabindudeva: 0x0901,
23512   candrabindugujarati: 0x0A81,
23513   capslock: 0x21EA,
23514   careof: 0x2105,
23515   caron: 0x02C7,
23516   caronbelowcmb: 0x032C,
23517   caroncmb: 0x030C,
23518   carriagereturn: 0x21B5,
23519   cbopomofo: 0x3118,
23520   ccaron: 0x010D,
23521   ccedilla: 0x00E7,
23522   ccedillaacute: 0x1E09,
23523   ccircle: 0x24D2,
23524   ccircumflex: 0x0109,
23525   ccurl: 0x0255,
23526   cdot: 0x010B,
23527   cdotaccent: 0x010B,
23528   cdsquare: 0x33C5,
23529   cedilla: 0x00B8,
23530   cedillacmb: 0x0327,
23531   cent: 0x00A2,
23532   centigrade: 0x2103,
23533   centinferior: 0xF6DF,
23534   centmonospace: 0xFFE0,
23535   centoldstyle: 0xF7A2,
23536   centsuperior: 0xF6E0,
23537   chaarmenian: 0x0579,
23538   chabengali: 0x099B,
23539   chadeva: 0x091B,
23540   chagujarati: 0x0A9B,
23541   chagurmukhi: 0x0A1B,
23542   chbopomofo: 0x3114,
23543   cheabkhasiancyrillic: 0x04BD,
23544   checkmark: 0x2713,
23545   checyrillic: 0x0447,
23546   chedescenderabkhasiancyrillic: 0x04BF,
23547   chedescendercyrillic: 0x04B7,
23548   chedieresiscyrillic: 0x04F5,
23549   cheharmenian: 0x0573,
23550   chekhakassiancyrillic: 0x04CC,
23551   cheverticalstrokecyrillic: 0x04B9,
23552   chi: 0x03C7,
23553   chieuchacirclekorean: 0x3277,
23554   chieuchaparenkorean: 0x3217,
23555   chieuchcirclekorean: 0x3269,
23556   chieuchkorean: 0x314A,
23557   chieuchparenkorean: 0x3209,
23558   chochangthai: 0x0E0A,
23559   chochanthai: 0x0E08,
23560   chochingthai: 0x0E09,
23561   chochoethai: 0x0E0C,
23562   chook: 0x0188,
23563   cieucacirclekorean: 0x3276,
23564   cieucaparenkorean: 0x3216,
23565   cieuccirclekorean: 0x3268,
23566   cieuckorean: 0x3148,
23567   cieucparenkorean: 0x3208,
23568   cieucuparenkorean: 0x321C,
23569   circle: 0x25CB,
23570   circlecopyrt: 0x00A9, // This glyph is missing from Adobe's original list.
23571   circlemultiply: 0x2297,
23572   circleot: 0x2299,
23573   circleplus: 0x2295,
23574   circlepostalmark: 0x3036,
23575   circlewithlefthalfblack: 0x25D0,
23576   circlewithrighthalfblack: 0x25D1,
23577   circumflex: 0x02C6,
23578   circumflexbelowcmb: 0x032D,
23579   circumflexcmb: 0x0302,
23580   clear: 0x2327,
23581   clickalveolar: 0x01C2,
23582   clickdental: 0x01C0,
23583   clicklateral: 0x01C1,
23584   clickretroflex: 0x01C3,
23585   club: 0x2663,
23586   clubsuitblack: 0x2663,
23587   clubsuitwhite: 0x2667,
23588   cmcubedsquare: 0x33A4,
23589   cmonospace: 0xFF43,
23590   cmsquaredsquare: 0x33A0,
23591   coarmenian: 0x0581,
23592   colon: 0x003A,
23593   colonmonetary: 0x20A1,
23594   colonmonospace: 0xFF1A,
23595   colonsign: 0x20A1,
23596   colonsmall: 0xFE55,
23597   colontriangularhalfmod: 0x02D1,
23598   colontriangularmod: 0x02D0,
23599   comma: 0x002C,
23600   commaabovecmb: 0x0313,
23601   commaaboverightcmb: 0x0315,
23602   commaaccent: 0xF6C3,
23603   commaarabic: 0x060C,
23604   commaarmenian: 0x055D,
23605   commainferior: 0xF6E1,
23606   commamonospace: 0xFF0C,
23607   commareversedabovecmb: 0x0314,
23608   commareversedmod: 0x02BD,
23609   commasmall: 0xFE50,
23610   commasuperior: 0xF6E2,
23611   commaturnedabovecmb: 0x0312,
23612   commaturnedmod: 0x02BB,
23613   compass: 0x263C,
23614   congruent: 0x2245,
23615   contourintegral: 0x222E,
23616   control: 0x2303,
23617   controlACK: 0x0006,
23618   controlBEL: 0x0007,
23619   controlBS: 0x0008,
23620   controlCAN: 0x0018,
23621   controlCR: 0x000D,
23622   controlDC1: 0x0011,
23623   controlDC2: 0x0012,
23624   controlDC3: 0x0013,
23625   controlDC4: 0x0014,
23626   controlDEL: 0x007F,
23627   controlDLE: 0x0010,
23628   controlEM: 0x0019,
23629   controlENQ: 0x0005,
23630   controlEOT: 0x0004,
23631   controlESC: 0x001B,
23632   controlETB: 0x0017,
23633   controlETX: 0x0003,
23634   controlFF: 0x000C,
23635   controlFS: 0x001C,
23636   controlGS: 0x001D,
23637   controlHT: 0x0009,
23638   controlLF: 0x000A,
23639   controlNAK: 0x0015,
23640   controlRS: 0x001E,
23641   controlSI: 0x000F,
23642   controlSO: 0x000E,
23643   controlSOT: 0x0002,
23644   controlSTX: 0x0001,
23645   controlSUB: 0x001A,
23646   controlSYN: 0x0016,
23647   controlUS: 0x001F,
23648   controlVT: 0x000B,
23649   copyright: 0x00A9,
23650   copyrightsans: 0xF8E9,
23651   copyrightserif: 0xF6D9,
23652   cornerbracketleft: 0x300C,
23653   cornerbracketlefthalfwidth: 0xFF62,
23654   cornerbracketleftvertical: 0xFE41,
23655   cornerbracketright: 0x300D,
23656   cornerbracketrighthalfwidth: 0xFF63,
23657   cornerbracketrightvertical: 0xFE42,
23658   corporationsquare: 0x337F,
23659   cosquare: 0x33C7,
23660   coverkgsquare: 0x33C6,
23661   cparen: 0x249E,
23662   cruzeiro: 0x20A2,
23663   cstretched: 0x0297,
23664   curlyand: 0x22CF,
23665   curlyor: 0x22CE,
23666   currency: 0x00A4,
23667   cyrBreve: 0xF6D1,
23668   cyrFlex: 0xF6D2,
23669   cyrbreve: 0xF6D4,
23670   cyrflex: 0xF6D5,
23671   d: 0x0064,
23672   daarmenian: 0x0564,
23673   dabengali: 0x09A6,
23674   dadarabic: 0x0636,
23675   dadeva: 0x0926,
23676   dadfinalarabic: 0xFEBE,
23677   dadinitialarabic: 0xFEBF,
23678   dadmedialarabic: 0xFEC0,
23679   dagesh: 0x05BC,
23680   dageshhebrew: 0x05BC,
23681   dagger: 0x2020,
23682   daggerdbl: 0x2021,
23683   dagujarati: 0x0AA6,
23684   dagurmukhi: 0x0A26,
23685   dahiragana: 0x3060,
23686   dakatakana: 0x30C0,
23687   dalarabic: 0x062F,
23688   dalet: 0x05D3,
23689   daletdagesh: 0xFB33,
23690   daletdageshhebrew: 0xFB33,
23691   dalethebrew: 0x05D3,
23692   dalfinalarabic: 0xFEAA,
23693   dammaarabic: 0x064F,
23694   dammalowarabic: 0x064F,
23695   dammatanaltonearabic: 0x064C,
23696   dammatanarabic: 0x064C,
23697   danda: 0x0964,
23698   dargahebrew: 0x05A7,
23699   dargalefthebrew: 0x05A7,
23700   dasiapneumatacyrilliccmb: 0x0485,
23701   dblGrave: 0xF6D3,
23702   dblanglebracketleft: 0x300A,
23703   dblanglebracketleftvertical: 0xFE3D,
23704   dblanglebracketright: 0x300B,
23705   dblanglebracketrightvertical: 0xFE3E,
23706   dblarchinvertedbelowcmb: 0x032B,
23707   dblarrowleft: 0x21D4,
23708   dblarrowright: 0x21D2,
23709   dbldanda: 0x0965,
23710   dblgrave: 0xF6D6,
23711   dblgravecmb: 0x030F,
23712   dblintegral: 0x222C,
23713   dbllowline: 0x2017,
23714   dbllowlinecmb: 0x0333,
23715   dbloverlinecmb: 0x033F,
23716   dblprimemod: 0x02BA,
23717   dblverticalbar: 0x2016,
23718   dblverticallineabovecmb: 0x030E,
23719   dbopomofo: 0x3109,
23720   dbsquare: 0x33C8,
23721   dcaron: 0x010F,
23722   dcedilla: 0x1E11,
23723   dcircle: 0x24D3,
23724   dcircumflexbelow: 0x1E13,
23725   dcroat: 0x0111,
23726   ddabengali: 0x09A1,
23727   ddadeva: 0x0921,
23728   ddagujarati: 0x0AA1,
23729   ddagurmukhi: 0x0A21,
23730   ddalarabic: 0x0688,
23731   ddalfinalarabic: 0xFB89,
23732   dddhadeva: 0x095C,
23733   ddhabengali: 0x09A2,
23734   ddhadeva: 0x0922,
23735   ddhagujarati: 0x0AA2,
23736   ddhagurmukhi: 0x0A22,
23737   ddotaccent: 0x1E0B,
23738   ddotbelow: 0x1E0D,
23739   decimalseparatorarabic: 0x066B,
23740   decimalseparatorpersian: 0x066B,
23741   decyrillic: 0x0434,
23742   degree: 0x00B0,
23743   dehihebrew: 0x05AD,
23744   dehiragana: 0x3067,
23745   deicoptic: 0x03EF,
23746   dekatakana: 0x30C7,
23747   deleteleft: 0x232B,
23748   deleteright: 0x2326,
23749   delta: 0x03B4,
23750   deltaturned: 0x018D,
23751   denominatorminusonenumeratorbengali: 0x09F8,
23752   dezh: 0x02A4,
23753   dhabengali: 0x09A7,
23754   dhadeva: 0x0927,
23755   dhagujarati: 0x0AA7,
23756   dhagurmukhi: 0x0A27,
23757   dhook: 0x0257,
23758   dialytikatonos: 0x0385,
23759   dialytikatonoscmb: 0x0344,
23760   diamond: 0x2666,
23761   diamondsuitwhite: 0x2662,
23762   dieresis: 0x00A8,
23763   dieresisacute: 0xF6D7,
23764   dieresisbelowcmb: 0x0324,
23765   dieresiscmb: 0x0308,
23766   dieresisgrave: 0xF6D8,
23767   dieresistonos: 0x0385,
23768   dihiragana: 0x3062,
23769   dikatakana: 0x30C2,
23770   dittomark: 0x3003,
23771   divide: 0x00F7,
23772   divides: 0x2223,
23773   divisionslash: 0x2215,
23774   djecyrillic: 0x0452,
23775   dkshade: 0x2593,
23776   dlinebelow: 0x1E0F,
23777   dlsquare: 0x3397,
23778   dmacron: 0x0111,
23779   dmonospace: 0xFF44,
23780   dnblock: 0x2584,
23781   dochadathai: 0x0E0E,
23782   dodekthai: 0x0E14,
23783   dohiragana: 0x3069,
23784   dokatakana: 0x30C9,
23785   dollar: 0x0024,
23786   dollarinferior: 0xF6E3,
23787   dollarmonospace: 0xFF04,
23788   dollaroldstyle: 0xF724,
23789   dollarsmall: 0xFE69,
23790   dollarsuperior: 0xF6E4,
23791   dong: 0x20AB,
23792   dorusquare: 0x3326,
23793   dotaccent: 0x02D9,
23794   dotaccentcmb: 0x0307,
23795   dotbelowcmb: 0x0323,
23796   dotbelowcomb: 0x0323,
23797   dotkatakana: 0x30FB,
23798   dotlessi: 0x0131,
23799   dotlessj: 0xF6BE,
23800   dotlessjstrokehook: 0x0284,
23801   dotmath: 0x22C5,
23802   dottedcircle: 0x25CC,
23803   doubleyodpatah: 0xFB1F,
23804   doubleyodpatahhebrew: 0xFB1F,
23805   downtackbelowcmb: 0x031E,
23806   downtackmod: 0x02D5,
23807   dparen: 0x249F,
23808   dsuperior: 0xF6EB,
23809   dtail: 0x0256,
23810   dtopbar: 0x018C,
23811   duhiragana: 0x3065,
23812   dukatakana: 0x30C5,
23813   dz: 0x01F3,
23814   dzaltone: 0x02A3,
23815   dzcaron: 0x01C6,
23816   dzcurl: 0x02A5,
23817   dzeabkhasiancyrillic: 0x04E1,
23818   dzecyrillic: 0x0455,
23819   dzhecyrillic: 0x045F,
23820   e: 0x0065,
23821   eacute: 0x00E9,
23822   earth: 0x2641,
23823   ebengali: 0x098F,
23824   ebopomofo: 0x311C,
23825   ebreve: 0x0115,
23826   ecandradeva: 0x090D,
23827   ecandragujarati: 0x0A8D,
23828   ecandravowelsigndeva: 0x0945,
23829   ecandravowelsigngujarati: 0x0AC5,
23830   ecaron: 0x011B,
23831   ecedillabreve: 0x1E1D,
23832   echarmenian: 0x0565,
23833   echyiwnarmenian: 0x0587,
23834   ecircle: 0x24D4,
23835   ecircumflex: 0x00EA,
23836   ecircumflexacute: 0x1EBF,
23837   ecircumflexbelow: 0x1E19,
23838   ecircumflexdotbelow: 0x1EC7,
23839   ecircumflexgrave: 0x1EC1,
23840   ecircumflexhookabove: 0x1EC3,
23841   ecircumflextilde: 0x1EC5,
23842   ecyrillic: 0x0454,
23843   edblgrave: 0x0205,
23844   edeva: 0x090F,
23845   edieresis: 0x00EB,
23846   edot: 0x0117,
23847   edotaccent: 0x0117,
23848   edotbelow: 0x1EB9,
23849   eegurmukhi: 0x0A0F,
23850   eematragurmukhi: 0x0A47,
23851   efcyrillic: 0x0444,
23852   egrave: 0x00E8,
23853   egujarati: 0x0A8F,
23854   eharmenian: 0x0567,
23855   ehbopomofo: 0x311D,
23856   ehiragana: 0x3048,
23857   ehookabove: 0x1EBB,
23858   eibopomofo: 0x311F,
23859   eight: 0x0038,
23860   eightarabic: 0x0668,
23861   eightbengali: 0x09EE,
23862   eightcircle: 0x2467,
23863   eightcircleinversesansserif: 0x2791,
23864   eightdeva: 0x096E,
23865   eighteencircle: 0x2471,
23866   eighteenparen: 0x2485,
23867   eighteenperiod: 0x2499,
23868   eightgujarati: 0x0AEE,
23869   eightgurmukhi: 0x0A6E,
23870   eighthackarabic: 0x0668,
23871   eighthangzhou: 0x3028,
23872   eighthnotebeamed: 0x266B,
23873   eightideographicparen: 0x3227,
23874   eightinferior: 0x2088,
23875   eightmonospace: 0xFF18,
23876   eightoldstyle: 0xF738,
23877   eightparen: 0x247B,
23878   eightperiod: 0x248F,
23879   eightpersian: 0x06F8,
23880   eightroman: 0x2177,
23881   eightsuperior: 0x2078,
23882   eightthai: 0x0E58,
23883   einvertedbreve: 0x0207,
23884   eiotifiedcyrillic: 0x0465,
23885   ekatakana: 0x30A8,
23886   ekatakanahalfwidth: 0xFF74,
23887   ekonkargurmukhi: 0x0A74,
23888   ekorean: 0x3154,
23889   elcyrillic: 0x043B,
23890   element: 0x2208,
23891   elevencircle: 0x246A,
23892   elevenparen: 0x247E,
23893   elevenperiod: 0x2492,
23894   elevenroman: 0x217A,
23895   ellipsis: 0x2026,
23896   ellipsisvertical: 0x22EE,
23897   emacron: 0x0113,
23898   emacronacute: 0x1E17,
23899   emacrongrave: 0x1E15,
23900   emcyrillic: 0x043C,
23901   emdash: 0x2014,
23902   emdashvertical: 0xFE31,
23903   emonospace: 0xFF45,
23904   emphasismarkarmenian: 0x055B,
23905   emptyset: 0x2205,
23906   enbopomofo: 0x3123,
23907   encyrillic: 0x043D,
23908   endash: 0x2013,
23909   endashvertical: 0xFE32,
23910   endescendercyrillic: 0x04A3,
23911   eng: 0x014B,
23912   engbopomofo: 0x3125,
23913   enghecyrillic: 0x04A5,
23914   enhookcyrillic: 0x04C8,
23915   enspace: 0x2002,
23916   eogonek: 0x0119,
23917   eokorean: 0x3153,
23918   eopen: 0x025B,
23919   eopenclosed: 0x029A,
23920   eopenreversed: 0x025C,
23921   eopenreversedclosed: 0x025E,
23922   eopenreversedhook: 0x025D,
23923   eparen: 0x24A0,
23924   epsilon: 0x03B5,
23925   epsilontonos: 0x03AD,
23926   equal: 0x003D,
23927   equalmonospace: 0xFF1D,
23928   equalsmall: 0xFE66,
23929   equalsuperior: 0x207C,
23930   equivalence: 0x2261,
23931   erbopomofo: 0x3126,
23932   ercyrillic: 0x0440,
23933   ereversed: 0x0258,
23934   ereversedcyrillic: 0x044D,
23935   escyrillic: 0x0441,
23936   esdescendercyrillic: 0x04AB,
23937   esh: 0x0283,
23938   eshcurl: 0x0286,
23939   eshortdeva: 0x090E,
23940   eshortvowelsigndeva: 0x0946,
23941   eshreversedloop: 0x01AA,
23942   eshsquatreversed: 0x0285,
23943   esmallhiragana: 0x3047,
23944   esmallkatakana: 0x30A7,
23945   esmallkatakanahalfwidth: 0xFF6A,
23946   estimated: 0x212E,
23947   esuperior: 0xF6EC,
23948   eta: 0x03B7,
23949   etarmenian: 0x0568,
23950   etatonos: 0x03AE,
23951   eth: 0x00F0,
23952   etilde: 0x1EBD,
23953   etildebelow: 0x1E1B,
23954   etnahtafoukhhebrew: 0x0591,
23955   etnahtafoukhlefthebrew: 0x0591,
23956   etnahtahebrew: 0x0591,
23957   etnahtalefthebrew: 0x0591,
23958   eturned: 0x01DD,
23959   eukorean: 0x3161,
23960   euro: 0x20AC,
23961   evowelsignbengali: 0x09C7,
23962   evowelsigndeva: 0x0947,
23963   evowelsigngujarati: 0x0AC7,
23964   exclam: 0x0021,
23965   exclamarmenian: 0x055C,
23966   exclamdbl: 0x203C,
23967   exclamdown: 0x00A1,
23968   exclamdownsmall: 0xF7A1,
23969   exclammonospace: 0xFF01,
23970   exclamsmall: 0xF721,
23971   existential: 0x2203,
23972   ezh: 0x0292,
23973   ezhcaron: 0x01EF,
23974   ezhcurl: 0x0293,
23975   ezhreversed: 0x01B9,
23976   ezhtail: 0x01BA,
23977   f: 0x0066,
23978   fadeva: 0x095E,
23979   fagurmukhi: 0x0A5E,
23980   fahrenheit: 0x2109,
23981   fathaarabic: 0x064E,
23982   fathalowarabic: 0x064E,
23983   fathatanarabic: 0x064B,
23984   fbopomofo: 0x3108,
23985   fcircle: 0x24D5,
23986   fdotaccent: 0x1E1F,
23987   feharabic: 0x0641,
23988   feharmenian: 0x0586,
23989   fehfinalarabic: 0xFED2,
23990   fehinitialarabic: 0xFED3,
23991   fehmedialarabic: 0xFED4,
23992   feicoptic: 0x03E5,
23993   female: 0x2640,
23994   ff: 0xFB00,
23995   ffi: 0xFB03,
23996   ffl: 0xFB04,
23997   fi: 0xFB01,
23998   fifteencircle: 0x246E,
23999   fifteenparen: 0x2482,
24000   fifteenperiod: 0x2496,
24001   figuredash: 0x2012,
24002   filledbox: 0x25A0,
24003   filledrect: 0x25AC,
24004   finalkaf: 0x05DA,
24005   finalkafdagesh: 0xFB3A,
24006   finalkafdageshhebrew: 0xFB3A,
24007   finalkafhebrew: 0x05DA,
24008   finalmem: 0x05DD,
24009   finalmemhebrew: 0x05DD,
24010   finalnun: 0x05DF,
24011   finalnunhebrew: 0x05DF,
24012   finalpe: 0x05E3,
24013   finalpehebrew: 0x05E3,
24014   finaltsadi: 0x05E5,
24015   finaltsadihebrew: 0x05E5,
24016   firsttonechinese: 0x02C9,
24017   fisheye: 0x25C9,
24018   fitacyrillic: 0x0473,
24019   five: 0x0035,
24020   fivearabic: 0x0665,
24021   fivebengali: 0x09EB,
24022   fivecircle: 0x2464,
24023   fivecircleinversesansserif: 0x278E,
24024   fivedeva: 0x096B,
24025   fiveeighths: 0x215D,
24026   fivegujarati: 0x0AEB,
24027   fivegurmukhi: 0x0A6B,
24028   fivehackarabic: 0x0665,
24029   fivehangzhou: 0x3025,
24030   fiveideographicparen: 0x3224,
24031   fiveinferior: 0x2085,
24032   fivemonospace: 0xFF15,
24033   fiveoldstyle: 0xF735,
24034   fiveparen: 0x2478,
24035   fiveperiod: 0x248C,
24036   fivepersian: 0x06F5,
24037   fiveroman: 0x2174,
24038   fivesuperior: 0x2075,
24039   fivethai: 0x0E55,
24040   fl: 0xFB02,
24041   florin: 0x0192,
24042   fmonospace: 0xFF46,
24043   fmsquare: 0x3399,
24044   fofanthai: 0x0E1F,
24045   fofathai: 0x0E1D,
24046   fongmanthai: 0x0E4F,
24047   forall: 0x2200,
24048   four: 0x0034,
24049   fourarabic: 0x0664,
24050   fourbengali: 0x09EA,
24051   fourcircle: 0x2463,
24052   fourcircleinversesansserif: 0x278D,
24053   fourdeva: 0x096A,
24054   fourgujarati: 0x0AEA,
24055   fourgurmukhi: 0x0A6A,
24056   fourhackarabic: 0x0664,
24057   fourhangzhou: 0x3024,
24058   fourideographicparen: 0x3223,
24059   fourinferior: 0x2084,
24060   fourmonospace: 0xFF14,
24061   fournumeratorbengali: 0x09F7,
24062   fouroldstyle: 0xF734,
24063   fourparen: 0x2477,
24064   fourperiod: 0x248B,
24065   fourpersian: 0x06F4,
24066   fourroman: 0x2173,
24067   foursuperior: 0x2074,
24068   fourteencircle: 0x246D,
24069   fourteenparen: 0x2481,
24070   fourteenperiod: 0x2495,
24071   fourthai: 0x0E54,
24072   fourthtonechinese: 0x02CB,
24073   fparen: 0x24A1,
24074   fraction: 0x2044,
24075   franc: 0x20A3,
24076   g: 0x0067,
24077   gabengali: 0x0997,
24078   gacute: 0x01F5,
24079   gadeva: 0x0917,
24080   gafarabic: 0x06AF,
24081   gaffinalarabic: 0xFB93,
24082   gafinitialarabic: 0xFB94,
24083   gafmedialarabic: 0xFB95,
24084   gagujarati: 0x0A97,
24085   gagurmukhi: 0x0A17,
24086   gahiragana: 0x304C,
24087   gakatakana: 0x30AC,
24088   gamma: 0x03B3,
24089   gammalatinsmall: 0x0263,
24090   gammasuperior: 0x02E0,
24091   gangiacoptic: 0x03EB,
24092   gbopomofo: 0x310D,
24093   gbreve: 0x011F,
24094   gcaron: 0x01E7,
24095   gcedilla: 0x0123,
24096   gcircle: 0x24D6,
24097   gcircumflex: 0x011D,
24098   gcommaaccent: 0x0123,
24099   gdot: 0x0121,
24100   gdotaccent: 0x0121,
24101   gecyrillic: 0x0433,
24102   gehiragana: 0x3052,
24103   gekatakana: 0x30B2,
24104   geometricallyequal: 0x2251,
24105   gereshaccenthebrew: 0x059C,
24106   gereshhebrew: 0x05F3,
24107   gereshmuqdamhebrew: 0x059D,
24108   germandbls: 0x00DF,
24109   gershayimaccenthebrew: 0x059E,
24110   gershayimhebrew: 0x05F4,
24111   getamark: 0x3013,
24112   ghabengali: 0x0998,
24113   ghadarmenian: 0x0572,
24114   ghadeva: 0x0918,
24115   ghagujarati: 0x0A98,
24116   ghagurmukhi: 0x0A18,
24117   ghainarabic: 0x063A,
24118   ghainfinalarabic: 0xFECE,
24119   ghaininitialarabic: 0xFECF,
24120   ghainmedialarabic: 0xFED0,
24121   ghemiddlehookcyrillic: 0x0495,
24122   ghestrokecyrillic: 0x0493,
24123   gheupturncyrillic: 0x0491,
24124   ghhadeva: 0x095A,
24125   ghhagurmukhi: 0x0A5A,
24126   ghook: 0x0260,
24127   ghzsquare: 0x3393,
24128   gihiragana: 0x304E,
24129   gikatakana: 0x30AE,
24130   gimarmenian: 0x0563,
24131   gimel: 0x05D2,
24132   gimeldagesh: 0xFB32,
24133   gimeldageshhebrew: 0xFB32,
24134   gimelhebrew: 0x05D2,
24135   gjecyrillic: 0x0453,
24136   glottalinvertedstroke: 0x01BE,
24137   glottalstop: 0x0294,
24138   glottalstopinverted: 0x0296,
24139   glottalstopmod: 0x02C0,
24140   glottalstopreversed: 0x0295,
24141   glottalstopreversedmod: 0x02C1,
24142   glottalstopreversedsuperior: 0x02E4,
24143   glottalstopstroke: 0x02A1,
24144   glottalstopstrokereversed: 0x02A2,
24145   gmacron: 0x1E21,
24146   gmonospace: 0xFF47,
24147   gohiragana: 0x3054,
24148   gokatakana: 0x30B4,
24149   gparen: 0x24A2,
24150   gpasquare: 0x33AC,
24151   gradient: 0x2207,
24152   grave: 0x0060,
24153   gravebelowcmb: 0x0316,
24154   gravecmb: 0x0300,
24155   gravecomb: 0x0300,
24156   gravedeva: 0x0953,
24157   gravelowmod: 0x02CE,
24158   gravemonospace: 0xFF40,
24159   gravetonecmb: 0x0340,
24160   greater: 0x003E,
24161   greaterequal: 0x2265,
24162   greaterequalorless: 0x22DB,
24163   greatermonospace: 0xFF1E,
24164   greaterorequivalent: 0x2273,
24165   greaterorless: 0x2277,
24166   greateroverequal: 0x2267,
24167   greatersmall: 0xFE65,
24168   gscript: 0x0261,
24169   gstroke: 0x01E5,
24170   guhiragana: 0x3050,
24171   guillemotleft: 0x00AB,
24172   guillemotright: 0x00BB,
24173   guilsinglleft: 0x2039,
24174   guilsinglright: 0x203A,
24175   gukatakana: 0x30B0,
24176   guramusquare: 0x3318,
24177   gysquare: 0x33C9,
24178   h: 0x0068,
24179   haabkhasiancyrillic: 0x04A9,
24180   haaltonearabic: 0x06C1,
24181   habengali: 0x09B9,
24182   hadescendercyrillic: 0x04B3,
24183   hadeva: 0x0939,
24184   hagujarati: 0x0AB9,
24185   hagurmukhi: 0x0A39,
24186   haharabic: 0x062D,
24187   hahfinalarabic: 0xFEA2,
24188   hahinitialarabic: 0xFEA3,
24189   hahiragana: 0x306F,
24190   hahmedialarabic: 0xFEA4,
24191   haitusquare: 0x332A,
24192   hakatakana: 0x30CF,
24193   hakatakanahalfwidth: 0xFF8A,
24194   halantgurmukhi: 0x0A4D,
24195   hamzaarabic: 0x0621,
24196   hamzalowarabic: 0x0621,
24197   hangulfiller: 0x3164,
24198   hardsigncyrillic: 0x044A,
24199   harpoonleftbarbup: 0x21BC,
24200   harpoonrightbarbup: 0x21C0,
24201   hasquare: 0x33CA,
24202   hatafpatah: 0x05B2,
24203   hatafpatah16: 0x05B2,
24204   hatafpatah23: 0x05B2,
24205   hatafpatah2f: 0x05B2,
24206   hatafpatahhebrew: 0x05B2,
24207   hatafpatahnarrowhebrew: 0x05B2,
24208   hatafpatahquarterhebrew: 0x05B2,
24209   hatafpatahwidehebrew: 0x05B2,
24210   hatafqamats: 0x05B3,
24211   hatafqamats1b: 0x05B3,
24212   hatafqamats28: 0x05B3,
24213   hatafqamats34: 0x05B3,
24214   hatafqamatshebrew: 0x05B3,
24215   hatafqamatsnarrowhebrew: 0x05B3,
24216   hatafqamatsquarterhebrew: 0x05B3,
24217   hatafqamatswidehebrew: 0x05B3,
24218   hatafsegol: 0x05B1,
24219   hatafsegol17: 0x05B1,
24220   hatafsegol24: 0x05B1,
24221   hatafsegol30: 0x05B1,
24222   hatafsegolhebrew: 0x05B1,
24223   hatafsegolnarrowhebrew: 0x05B1,
24224   hatafsegolquarterhebrew: 0x05B1,
24225   hatafsegolwidehebrew: 0x05B1,
24226   hbar: 0x0127,
24227   hbopomofo: 0x310F,
24228   hbrevebelow: 0x1E2B,
24229   hcedilla: 0x1E29,
24230   hcircle: 0x24D7,
24231   hcircumflex: 0x0125,
24232   hdieresis: 0x1E27,
24233   hdotaccent: 0x1E23,
24234   hdotbelow: 0x1E25,
24235   he: 0x05D4,
24236   heart: 0x2665,
24237   heartsuitblack: 0x2665,
24238   heartsuitwhite: 0x2661,
24239   hedagesh: 0xFB34,
24240   hedageshhebrew: 0xFB34,
24241   hehaltonearabic: 0x06C1,
24242   heharabic: 0x0647,
24243   hehebrew: 0x05D4,
24244   hehfinalaltonearabic: 0xFBA7,
24245   hehfinalalttwoarabic: 0xFEEA,
24246   hehfinalarabic: 0xFEEA,
24247   hehhamzaabovefinalarabic: 0xFBA5,
24248   hehhamzaaboveisolatedarabic: 0xFBA4,
24249   hehinitialaltonearabic: 0xFBA8,
24250   hehinitialarabic: 0xFEEB,
24251   hehiragana: 0x3078,
24252   hehmedialaltonearabic: 0xFBA9,
24253   hehmedialarabic: 0xFEEC,
24254   heiseierasquare: 0x337B,
24255   hekatakana: 0x30D8,
24256   hekatakanahalfwidth: 0xFF8D,
24257   hekutaarusquare: 0x3336,
24258   henghook: 0x0267,
24259   herutusquare: 0x3339,
24260   het: 0x05D7,
24261   hethebrew: 0x05D7,
24262   hhook: 0x0266,
24263   hhooksuperior: 0x02B1,
24264   hieuhacirclekorean: 0x327B,
24265   hieuhaparenkorean: 0x321B,
24266   hieuhcirclekorean: 0x326D,
24267   hieuhkorean: 0x314E,
24268   hieuhparenkorean: 0x320D,
24269   hihiragana: 0x3072,
24270   hikatakana: 0x30D2,
24271   hikatakanahalfwidth: 0xFF8B,
24272   hiriq: 0x05B4,
24273   hiriq14: 0x05B4,
24274   hiriq21: 0x05B4,
24275   hiriq2d: 0x05B4,
24276   hiriqhebrew: 0x05B4,
24277   hiriqnarrowhebrew: 0x05B4,
24278   hiriqquarterhebrew: 0x05B4,
24279   hiriqwidehebrew: 0x05B4,
24280   hlinebelow: 0x1E96,
24281   hmonospace: 0xFF48,
24282   hoarmenian: 0x0570,
24283   hohipthai: 0x0E2B,
24284   hohiragana: 0x307B,
24285   hokatakana: 0x30DB,
24286   hokatakanahalfwidth: 0xFF8E,
24287   holam: 0x05B9,
24288   holam19: 0x05B9,
24289   holam26: 0x05B9,
24290   holam32: 0x05B9,
24291   holamhebrew: 0x05B9,
24292   holamnarrowhebrew: 0x05B9,
24293   holamquarterhebrew: 0x05B9,
24294   holamwidehebrew: 0x05B9,
24295   honokhukthai: 0x0E2E,
24296   hookabovecomb: 0x0309,
24297   hookcmb: 0x0309,
24298   hookpalatalizedbelowcmb: 0x0321,
24299   hookretroflexbelowcmb: 0x0322,
24300   hoonsquare: 0x3342,
24301   horicoptic: 0x03E9,
24302   horizontalbar: 0x2015,
24303   horncmb: 0x031B,
24304   hotsprings: 0x2668,
24305   house: 0x2302,
24306   hparen: 0x24A3,
24307   hsuperior: 0x02B0,
24308   hturned: 0x0265,
24309   huhiragana: 0x3075,
24310   huiitosquare: 0x3333,
24311   hukatakana: 0x30D5,
24312   hukatakanahalfwidth: 0xFF8C,
24313   hungarumlaut: 0x02DD,
24314   hungarumlautcmb: 0x030B,
24315   hv: 0x0195,
24316   hyphen: 0x002D,
24317   hypheninferior: 0xF6E5,
24318   hyphenmonospace: 0xFF0D,
24319   hyphensmall: 0xFE63,
24320   hyphensuperior: 0xF6E6,
24321   hyphentwo: 0x2010,
24322   i: 0x0069,
24323   iacute: 0x00ED,
24324   iacyrillic: 0x044F,
24325   ibengali: 0x0987,
24326   ibopomofo: 0x3127,
24327   ibreve: 0x012D,
24328   icaron: 0x01D0,
24329   icircle: 0x24D8,
24330   icircumflex: 0x00EE,
24331   icyrillic: 0x0456,
24332   idblgrave: 0x0209,
24333   ideographearthcircle: 0x328F,
24334   ideographfirecircle: 0x328B,
24335   ideographicallianceparen: 0x323F,
24336   ideographiccallparen: 0x323A,
24337   ideographiccentrecircle: 0x32A5,
24338   ideographicclose: 0x3006,
24339   ideographiccomma: 0x3001,
24340   ideographiccommaleft: 0xFF64,
24341   ideographiccongratulationparen: 0x3237,
24342   ideographiccorrectcircle: 0x32A3,
24343   ideographicearthparen: 0x322F,
24344   ideographicenterpriseparen: 0x323D,
24345   ideographicexcellentcircle: 0x329D,
24346   ideographicfestivalparen: 0x3240,
24347   ideographicfinancialcircle: 0x3296,
24348   ideographicfinancialparen: 0x3236,
24349   ideographicfireparen: 0x322B,
24350   ideographichaveparen: 0x3232,
24351   ideographichighcircle: 0x32A4,
24352   ideographiciterationmark: 0x3005,
24353   ideographiclaborcircle: 0x3298,
24354   ideographiclaborparen: 0x3238,
24355   ideographicleftcircle: 0x32A7,
24356   ideographiclowcircle: 0x32A6,
24357   ideographicmedicinecircle: 0x32A9,
24358   ideographicmetalparen: 0x322E,
24359   ideographicmoonparen: 0x322A,
24360   ideographicnameparen: 0x3234,
24361   ideographicperiod: 0x3002,
24362   ideographicprintcircle: 0x329E,
24363   ideographicreachparen: 0x3243,
24364   ideographicrepresentparen: 0x3239,
24365   ideographicresourceparen: 0x323E,
24366   ideographicrightcircle: 0x32A8,
24367   ideographicsecretcircle: 0x3299,
24368   ideographicselfparen: 0x3242,
24369   ideographicsocietyparen: 0x3233,
24370   ideographicspace: 0x3000,
24371   ideographicspecialparen: 0x3235,
24372   ideographicstockparen: 0x3231,
24373   ideographicstudyparen: 0x323B,
24374   ideographicsunparen: 0x3230,
24375   ideographicsuperviseparen: 0x323C,
24376   ideographicwaterparen: 0x322C,
24377   ideographicwoodparen: 0x322D,
24378   ideographiczero: 0x3007,
24379   ideographmetalcircle: 0x328E,
24380   ideographmooncircle: 0x328A,
24381   ideographnamecircle: 0x3294,
24382   ideographsuncircle: 0x3290,
24383   ideographwatercircle: 0x328C,
24384   ideographwoodcircle: 0x328D,
24385   ideva: 0x0907,
24386   idieresis: 0x00EF,
24387   idieresisacute: 0x1E2F,
24388   idieresiscyrillic: 0x04E5,
24389   idotbelow: 0x1ECB,
24390   iebrevecyrillic: 0x04D7,
24391   iecyrillic: 0x0435,
24392   ieungacirclekorean: 0x3275,
24393   ieungaparenkorean: 0x3215,
24394   ieungcirclekorean: 0x3267,
24395   ieungkorean: 0x3147,
24396   ieungparenkorean: 0x3207,
24397   igrave: 0x00EC,
24398   igujarati: 0x0A87,
24399   igurmukhi: 0x0A07,
24400   ihiragana: 0x3044,
24401   ihookabove: 0x1EC9,
24402   iibengali: 0x0988,
24403   iicyrillic: 0x0438,
24404   iideva: 0x0908,
24405   iigujarati: 0x0A88,
24406   iigurmukhi: 0x0A08,
24407   iimatragurmukhi: 0x0A40,
24408   iinvertedbreve: 0x020B,
24409   iishortcyrillic: 0x0439,
24410   iivowelsignbengali: 0x09C0,
24411   iivowelsigndeva: 0x0940,
24412   iivowelsigngujarati: 0x0AC0,
24413   ij: 0x0133,
24414   ikatakana: 0x30A4,
24415   ikatakanahalfwidth: 0xFF72,
24416   ikorean: 0x3163,
24417   ilde: 0x02DC,
24418   iluyhebrew: 0x05AC,
24419   imacron: 0x012B,
24420   imacroncyrillic: 0x04E3,
24421   imageorapproximatelyequal: 0x2253,
24422   imatragurmukhi: 0x0A3F,
24423   imonospace: 0xFF49,
24424   increment: 0x2206,
24425   infinity: 0x221E,
24426   iniarmenian: 0x056B,
24427   integral: 0x222B,
24428   integralbottom: 0x2321,
24429   integralbt: 0x2321,
24430   integralex: 0xF8F5,
24431   integraltop: 0x2320,
24432   integraltp: 0x2320,
24433   intersection: 0x2229,
24434   intisquare: 0x3305,
24435   invbullet: 0x25D8,
24436   invcircle: 0x25D9,
24437   invsmileface: 0x263B,
24438   iocyrillic: 0x0451,
24439   iogonek: 0x012F,
24440   iota: 0x03B9,
24441   iotadieresis: 0x03CA,
24442   iotadieresistonos: 0x0390,
24443   iotalatin: 0x0269,
24444   iotatonos: 0x03AF,
24445   iparen: 0x24A4,
24446   irigurmukhi: 0x0A72,
24447   ismallhiragana: 0x3043,
24448   ismallkatakana: 0x30A3,
24449   ismallkatakanahalfwidth: 0xFF68,
24450   issharbengali: 0x09FA,
24451   istroke: 0x0268,
24452   isuperior: 0xF6ED,
24453   iterationhiragana: 0x309D,
24454   iterationkatakana: 0x30FD,
24455   itilde: 0x0129,
24456   itildebelow: 0x1E2D,
24457   iubopomofo: 0x3129,
24458   iucyrillic: 0x044E,
24459   ivowelsignbengali: 0x09BF,
24460   ivowelsigndeva: 0x093F,
24461   ivowelsigngujarati: 0x0ABF,
24462   izhitsacyrillic: 0x0475,
24463   izhitsadblgravecyrillic: 0x0477,
24464   j: 0x006A,
24465   jaarmenian: 0x0571,
24466   jabengali: 0x099C,
24467   jadeva: 0x091C,
24468   jagujarati: 0x0A9C,
24469   jagurmukhi: 0x0A1C,
24470   jbopomofo: 0x3110,
24471   jcaron: 0x01F0,
24472   jcircle: 0x24D9,
24473   jcircumflex: 0x0135,
24474   jcrossedtail: 0x029D,
24475   jdotlessstroke: 0x025F,
24476   jecyrillic: 0x0458,
24477   jeemarabic: 0x062C,
24478   jeemfinalarabic: 0xFE9E,
24479   jeeminitialarabic: 0xFE9F,
24480   jeemmedialarabic: 0xFEA0,
24481   jeharabic: 0x0698,
24482   jehfinalarabic: 0xFB8B,
24483   jhabengali: 0x099D,
24484   jhadeva: 0x091D,
24485   jhagujarati: 0x0A9D,
24486   jhagurmukhi: 0x0A1D,
24487   jheharmenian: 0x057B,
24488   jis: 0x3004,
24489   jmonospace: 0xFF4A,
24490   jparen: 0x24A5,
24491   jsuperior: 0x02B2,
24492   k: 0x006B,
24493   kabashkircyrillic: 0x04A1,
24494   kabengali: 0x0995,
24495   kacute: 0x1E31,
24496   kacyrillic: 0x043A,
24497   kadescendercyrillic: 0x049B,
24498   kadeva: 0x0915,
24499   kaf: 0x05DB,
24500   kafarabic: 0x0643,
24501   kafdagesh: 0xFB3B,
24502   kafdageshhebrew: 0xFB3B,
24503   kaffinalarabic: 0xFEDA,
24504   kafhebrew: 0x05DB,
24505   kafinitialarabic: 0xFEDB,
24506   kafmedialarabic: 0xFEDC,
24507   kafrafehebrew: 0xFB4D,
24508   kagujarati: 0x0A95,
24509   kagurmukhi: 0x0A15,
24510   kahiragana: 0x304B,
24511   kahookcyrillic: 0x04C4,
24512   kakatakana: 0x30AB,
24513   kakatakanahalfwidth: 0xFF76,
24514   kappa: 0x03BA,
24515   kappasymbolgreek: 0x03F0,
24516   kapyeounmieumkorean: 0x3171,
24517   kapyeounphieuphkorean: 0x3184,
24518   kapyeounpieupkorean: 0x3178,
24519   kapyeounssangpieupkorean: 0x3179,
24520   karoriisquare: 0x330D,
24521   kashidaautoarabic: 0x0640,
24522   kashidaautonosidebearingarabic: 0x0640,
24523   kasmallkatakana: 0x30F5,
24524   kasquare: 0x3384,
24525   kasraarabic: 0x0650,
24526   kasratanarabic: 0x064D,
24527   kastrokecyrillic: 0x049F,
24528   katahiraprolongmarkhalfwidth: 0xFF70,
24529   kaverticalstrokecyrillic: 0x049D,
24530   kbopomofo: 0x310E,
24531   kcalsquare: 0x3389,
24532   kcaron: 0x01E9,
24533   kcedilla: 0x0137,
24534   kcircle: 0x24DA,
24535   kcommaaccent: 0x0137,
24536   kdotbelow: 0x1E33,
24537   keharmenian: 0x0584,
24538   kehiragana: 0x3051,
24539   kekatakana: 0x30B1,
24540   kekatakanahalfwidth: 0xFF79,
24541   kenarmenian: 0x056F,
24542   kesmallkatakana: 0x30F6,
24543   kgreenlandic: 0x0138,
24544   khabengali: 0x0996,
24545   khacyrillic: 0x0445,
24546   khadeva: 0x0916,
24547   khagujarati: 0x0A96,
24548   khagurmukhi: 0x0A16,
24549   khaharabic: 0x062E,
24550   khahfinalarabic: 0xFEA6,
24551   khahinitialarabic: 0xFEA7,
24552   khahmedialarabic: 0xFEA8,
24553   kheicoptic: 0x03E7,
24554   khhadeva: 0x0959,
24555   khhagurmukhi: 0x0A59,
24556   khieukhacirclekorean: 0x3278,
24557   khieukhaparenkorean: 0x3218,
24558   khieukhcirclekorean: 0x326A,
24559   khieukhkorean: 0x314B,
24560   khieukhparenkorean: 0x320A,
24561   khokhaithai: 0x0E02,
24562   khokhonthai: 0x0E05,
24563   khokhuatthai: 0x0E03,
24564   khokhwaithai: 0x0E04,
24565   khomutthai: 0x0E5B,
24566   khook: 0x0199,
24567   khorakhangthai: 0x0E06,
24568   khzsquare: 0x3391,
24569   kihiragana: 0x304D,
24570   kikatakana: 0x30AD,
24571   kikatakanahalfwidth: 0xFF77,
24572   kiroguramusquare: 0x3315,
24573   kiromeetorusquare: 0x3316,
24574   kirosquare: 0x3314,
24575   kiyeokacirclekorean: 0x326E,
24576   kiyeokaparenkorean: 0x320E,
24577   kiyeokcirclekorean: 0x3260,
24578   kiyeokkorean: 0x3131,
24579   kiyeokparenkorean: 0x3200,
24580   kiyeoksioskorean: 0x3133,
24581   kjecyrillic: 0x045C,
24582   klinebelow: 0x1E35,
24583   klsquare: 0x3398,
24584   kmcubedsquare: 0x33A6,
24585   kmonospace: 0xFF4B,
24586   kmsquaredsquare: 0x33A2,
24587   kohiragana: 0x3053,
24588   kohmsquare: 0x33C0,
24589   kokaithai: 0x0E01,
24590   kokatakana: 0x30B3,
24591   kokatakanahalfwidth: 0xFF7A,
24592   kooposquare: 0x331E,
24593   koppacyrillic: 0x0481,
24594   koreanstandardsymbol: 0x327F,
24595   koroniscmb: 0x0343,
24596   kparen: 0x24A6,
24597   kpasquare: 0x33AA,
24598   ksicyrillic: 0x046F,
24599   ktsquare: 0x33CF,
24600   kturned: 0x029E,
24601   kuhiragana: 0x304F,
24602   kukatakana: 0x30AF,
24603   kukatakanahalfwidth: 0xFF78,
24604   kvsquare: 0x33B8,
24605   kwsquare: 0x33BE,
24606   l: 0x006C,
24607   labengali: 0x09B2,
24608   lacute: 0x013A,
24609   ladeva: 0x0932,
24610   lagujarati: 0x0AB2,
24611   lagurmukhi: 0x0A32,
24612   lakkhangyaothai: 0x0E45,
24613   lamaleffinalarabic: 0xFEFC,
24614   lamalefhamzaabovefinalarabic: 0xFEF8,
24615   lamalefhamzaaboveisolatedarabic: 0xFEF7,
24616   lamalefhamzabelowfinalarabic: 0xFEFA,
24617   lamalefhamzabelowisolatedarabic: 0xFEF9,
24618   lamalefisolatedarabic: 0xFEFB,
24619   lamalefmaddaabovefinalarabic: 0xFEF6,
24620   lamalefmaddaaboveisolatedarabic: 0xFEF5,
24621   lamarabic: 0x0644,
24622   lambda: 0x03BB,
24623   lambdastroke: 0x019B,
24624   lamed: 0x05DC,
24625   lameddagesh: 0xFB3C,
24626   lameddageshhebrew: 0xFB3C,
24627   lamedhebrew: 0x05DC,
24628   lamfinalarabic: 0xFEDE,
24629   lamhahinitialarabic: 0xFCCA,
24630   laminitialarabic: 0xFEDF,
24631   lamjeeminitialarabic: 0xFCC9,
24632   lamkhahinitialarabic: 0xFCCB,
24633   lamlamhehisolatedarabic: 0xFDF2,
24634   lammedialarabic: 0xFEE0,
24635   lammeemhahinitialarabic: 0xFD88,
24636   lammeeminitialarabic: 0xFCCC,
24637   largecircle: 0x25EF,
24638   lbar: 0x019A,
24639   lbelt: 0x026C,
24640   lbopomofo: 0x310C,
24641   lcaron: 0x013E,
24642   lcedilla: 0x013C,
24643   lcircle: 0x24DB,
24644   lcircumflexbelow: 0x1E3D,
24645   lcommaaccent: 0x013C,
24646   ldot: 0x0140,
24647   ldotaccent: 0x0140,
24648   ldotbelow: 0x1E37,
24649   ldotbelowmacron: 0x1E39,
24650   leftangleabovecmb: 0x031A,
24651   lefttackbelowcmb: 0x0318,
24652   less: 0x003C,
24653   lessequal: 0x2264,
24654   lessequalorgreater: 0x22DA,
24655   lessmonospace: 0xFF1C,
24656   lessorequivalent: 0x2272,
24657   lessorgreater: 0x2276,
24658   lessoverequal: 0x2266,
24659   lesssmall: 0xFE64,
24660   lezh: 0x026E,
24661   lfblock: 0x258C,
24662   lhookretroflex: 0x026D,
24663   lira: 0x20A4,
24664   liwnarmenian: 0x056C,
24665   lj: 0x01C9,
24666   ljecyrillic: 0x0459,
24667   ll: 0xF6C0,
24668   lladeva: 0x0933,
24669   llagujarati: 0x0AB3,
24670   llinebelow: 0x1E3B,
24671   llladeva: 0x0934,
24672   llvocalicbengali: 0x09E1,
24673   llvocalicdeva: 0x0961,
24674   llvocalicvowelsignbengali: 0x09E3,
24675   llvocalicvowelsigndeva: 0x0963,
24676   lmiddletilde: 0x026B,
24677   lmonospace: 0xFF4C,
24678   lmsquare: 0x33D0,
24679   lochulathai: 0x0E2C,
24680   logicaland: 0x2227,
24681   logicalnot: 0x00AC,
24682   logicalnotreversed: 0x2310,
24683   logicalor: 0x2228,
24684   lolingthai: 0x0E25,
24685   longs: 0x017F,
24686   lowlinecenterline: 0xFE4E,
24687   lowlinecmb: 0x0332,
24688   lowlinedashed: 0xFE4D,
24689   lozenge: 0x25CA,
24690   lparen: 0x24A7,
24691   lslash: 0x0142,
24692   lsquare: 0x2113,
24693   lsuperior: 0xF6EE,
24694   ltshade: 0x2591,
24695   luthai: 0x0E26,
24696   lvocalicbengali: 0x098C,
24697   lvocalicdeva: 0x090C,
24698   lvocalicvowelsignbengali: 0x09E2,
24699   lvocalicvowelsigndeva: 0x0962,
24700   lxsquare: 0x33D3,
24701   m: 0x006D,
24702   mabengali: 0x09AE,
24703   macron: 0x00AF,
24704   macronbelowcmb: 0x0331,
24705   macroncmb: 0x0304,
24706   macronlowmod: 0x02CD,
24707   macronmonospace: 0xFFE3,
24708   macute: 0x1E3F,
24709   madeva: 0x092E,
24710   magujarati: 0x0AAE,
24711   magurmukhi: 0x0A2E,
24712   mahapakhhebrew: 0x05A4,
24713   mahapakhlefthebrew: 0x05A4,
24714   mahiragana: 0x307E,
24715   maichattawalowleftthai: 0xF895,
24716   maichattawalowrightthai: 0xF894,
24717   maichattawathai: 0x0E4B,
24718   maichattawaupperleftthai: 0xF893,
24719   maieklowleftthai: 0xF88C,
24720   maieklowrightthai: 0xF88B,
24721   maiekthai: 0x0E48,
24722   maiekupperleftthai: 0xF88A,
24723   maihanakatleftthai: 0xF884,
24724   maihanakatthai: 0x0E31,
24725   maitaikhuleftthai: 0xF889,
24726   maitaikhuthai: 0x0E47,
24727   maitholowleftthai: 0xF88F,
24728   maitholowrightthai: 0xF88E,
24729   maithothai: 0x0E49,
24730   maithoupperleftthai: 0xF88D,
24731   maitrilowleftthai: 0xF892,
24732   maitrilowrightthai: 0xF891,
24733   maitrithai: 0x0E4A,
24734   maitriupperleftthai: 0xF890,
24735   maiyamokthai: 0x0E46,
24736   makatakana: 0x30DE,
24737   makatakanahalfwidth: 0xFF8F,
24738   male: 0x2642,
24739   mansyonsquare: 0x3347,
24740   maqafhebrew: 0x05BE,
24741   mars: 0x2642,
24742   masoracirclehebrew: 0x05AF,
24743   masquare: 0x3383,
24744   mbopomofo: 0x3107,
24745   mbsquare: 0x33D4,
24746   mcircle: 0x24DC,
24747   mcubedsquare: 0x33A5,
24748   mdotaccent: 0x1E41,
24749   mdotbelow: 0x1E43,
24750   meemarabic: 0x0645,
24751   meemfinalarabic: 0xFEE2,
24752   meeminitialarabic: 0xFEE3,
24753   meemmedialarabic: 0xFEE4,
24754   meemmeeminitialarabic: 0xFCD1,
24755   meemmeemisolatedarabic: 0xFC48,
24756   meetorusquare: 0x334D,
24757   mehiragana: 0x3081,
24758   meizierasquare: 0x337E,
24759   mekatakana: 0x30E1,
24760   mekatakanahalfwidth: 0xFF92,
24761   mem: 0x05DE,
24762   memdagesh: 0xFB3E,
24763   memdageshhebrew: 0xFB3E,
24764   memhebrew: 0x05DE,
24765   menarmenian: 0x0574,
24766   merkhahebrew: 0x05A5,
24767   merkhakefulahebrew: 0x05A6,
24768   merkhakefulalefthebrew: 0x05A6,
24769   merkhalefthebrew: 0x05A5,
24770   mhook: 0x0271,
24771   mhzsquare: 0x3392,
24772   middledotkatakanahalfwidth: 0xFF65,
24773   middot: 0x00B7,
24774   mieumacirclekorean: 0x3272,
24775   mieumaparenkorean: 0x3212,
24776   mieumcirclekorean: 0x3264,
24777   mieumkorean: 0x3141,
24778   mieumpansioskorean: 0x3170,
24779   mieumparenkorean: 0x3204,
24780   mieumpieupkorean: 0x316E,
24781   mieumsioskorean: 0x316F,
24782   mihiragana: 0x307F,
24783   mikatakana: 0x30DF,
24784   mikatakanahalfwidth: 0xFF90,
24785   minus: 0x2212,
24786   minusbelowcmb: 0x0320,
24787   minuscircle: 0x2296,
24788   minusmod: 0x02D7,
24789   minusplus: 0x2213,
24790   minute: 0x2032,
24791   miribaarusquare: 0x334A,
24792   mirisquare: 0x3349,
24793   mlonglegturned: 0x0270,
24794   mlsquare: 0x3396,
24795   mmcubedsquare: 0x33A3,
24796   mmonospace: 0xFF4D,
24797   mmsquaredsquare: 0x339F,
24798   mohiragana: 0x3082,
24799   mohmsquare: 0x33C1,
24800   mokatakana: 0x30E2,
24801   mokatakanahalfwidth: 0xFF93,
24802   molsquare: 0x33D6,
24803   momathai: 0x0E21,
24804   moverssquare: 0x33A7,
24805   moverssquaredsquare: 0x33A8,
24806   mparen: 0x24A8,
24807   mpasquare: 0x33AB,
24808   mssquare: 0x33B3,
24809   msuperior: 0xF6EF,
24810   mturned: 0x026F,
24811   mu: 0x00B5,
24812   mu1: 0x00B5,
24813   muasquare: 0x3382,
24814   muchgreater: 0x226B,
24815   muchless: 0x226A,
24816   mufsquare: 0x338C,
24817   mugreek: 0x03BC,
24818   mugsquare: 0x338D,
24819   muhiragana: 0x3080,
24820   mukatakana: 0x30E0,
24821   mukatakanahalfwidth: 0xFF91,
24822   mulsquare: 0x3395,
24823   multiply: 0x00D7,
24824   mumsquare: 0x339B,
24825   munahhebrew: 0x05A3,
24826   munahlefthebrew: 0x05A3,
24827   musicalnote: 0x266A,
24828   musicalnotedbl: 0x266B,
24829   musicflatsign: 0x266D,
24830   musicsharpsign: 0x266F,
24831   mussquare: 0x33B2,
24832   muvsquare: 0x33B6,
24833   muwsquare: 0x33BC,
24834   mvmegasquare: 0x33B9,
24835   mvsquare: 0x33B7,
24836   mwmegasquare: 0x33BF,
24837   mwsquare: 0x33BD,
24838   n: 0x006E,
24839   nabengali: 0x09A8,
24840   nabla: 0x2207,
24841   nacute: 0x0144,
24842   nadeva: 0x0928,
24843   nagujarati: 0x0AA8,
24844   nagurmukhi: 0x0A28,
24845   nahiragana: 0x306A,
24846   nakatakana: 0x30CA,
24847   nakatakanahalfwidth: 0xFF85,
24848   napostrophe: 0x0149,
24849   nasquare: 0x3381,
24850   nbopomofo: 0x310B,
24851   nbspace: 0x00A0,
24852   ncaron: 0x0148,
24853   ncedilla: 0x0146,
24854   ncircle: 0x24DD,
24855   ncircumflexbelow: 0x1E4B,
24856   ncommaaccent: 0x0146,
24857   ndotaccent: 0x1E45,
24858   ndotbelow: 0x1E47,
24859   nehiragana: 0x306D,
24860   nekatakana: 0x30CD,
24861   nekatakanahalfwidth: 0xFF88,
24862   newsheqelsign: 0x20AA,
24863   nfsquare: 0x338B,
24864   ngabengali: 0x0999,
24865   ngadeva: 0x0919,
24866   ngagujarati: 0x0A99,
24867   ngagurmukhi: 0x0A19,
24868   ngonguthai: 0x0E07,
24869   nhiragana: 0x3093,
24870   nhookleft: 0x0272,
24871   nhookretroflex: 0x0273,
24872   nieunacirclekorean: 0x326F,
24873   nieunaparenkorean: 0x320F,
24874   nieuncieuckorean: 0x3135,
24875   nieuncirclekorean: 0x3261,
24876   nieunhieuhkorean: 0x3136,
24877   nieunkorean: 0x3134,
24878   nieunpansioskorean: 0x3168,
24879   nieunparenkorean: 0x3201,
24880   nieunsioskorean: 0x3167,
24881   nieuntikeutkorean: 0x3166,
24882   nihiragana: 0x306B,
24883   nikatakana: 0x30CB,
24884   nikatakanahalfwidth: 0xFF86,
24885   nikhahitleftthai: 0xF899,
24886   nikhahitthai: 0x0E4D,
24887   nine: 0x0039,
24888   ninearabic: 0x0669,
24889   ninebengali: 0x09EF,
24890   ninecircle: 0x2468,
24891   ninecircleinversesansserif: 0x2792,
24892   ninedeva: 0x096F,
24893   ninegujarati: 0x0AEF,
24894   ninegurmukhi: 0x0A6F,
24895   ninehackarabic: 0x0669,
24896   ninehangzhou: 0x3029,
24897   nineideographicparen: 0x3228,
24898   nineinferior: 0x2089,
24899   ninemonospace: 0xFF19,
24900   nineoldstyle: 0xF739,
24901   nineparen: 0x247C,
24902   nineperiod: 0x2490,
24903   ninepersian: 0x06F9,
24904   nineroman: 0x2178,
24905   ninesuperior: 0x2079,
24906   nineteencircle: 0x2472,
24907   nineteenparen: 0x2486,
24908   nineteenperiod: 0x249A,
24909   ninethai: 0x0E59,
24910   nj: 0x01CC,
24911   njecyrillic: 0x045A,
24912   nkatakana: 0x30F3,
24913   nkatakanahalfwidth: 0xFF9D,
24914   nlegrightlong: 0x019E,
24915   nlinebelow: 0x1E49,
24916   nmonospace: 0xFF4E,
24917   nmsquare: 0x339A,
24918   nnabengali: 0x09A3,
24919   nnadeva: 0x0923,
24920   nnagujarati: 0x0AA3,
24921   nnagurmukhi: 0x0A23,
24922   nnnadeva: 0x0929,
24923   nohiragana: 0x306E,
24924   nokatakana: 0x30CE,
24925   nokatakanahalfwidth: 0xFF89,
24926   nonbreakingspace: 0x00A0,
24927   nonenthai: 0x0E13,
24928   nonuthai: 0x0E19,
24929   noonarabic: 0x0646,
24930   noonfinalarabic: 0xFEE6,
24931   noonghunnaarabic: 0x06BA,
24932   noonghunnafinalarabic: 0xFB9F,
24933   nooninitialarabic: 0xFEE7,
24934   noonjeeminitialarabic: 0xFCD2,
24935   noonjeemisolatedarabic: 0xFC4B,
24936   noonmedialarabic: 0xFEE8,
24937   noonmeeminitialarabic: 0xFCD5,
24938   noonmeemisolatedarabic: 0xFC4E,
24939   noonnoonfinalarabic: 0xFC8D,
24940   notcontains: 0x220C,
24941   notelement: 0x2209,
24942   notelementof: 0x2209,
24943   notequal: 0x2260,
24944   notgreater: 0x226F,
24945   notgreaternorequal: 0x2271,
24946   notgreaternorless: 0x2279,
24947   notidentical: 0x2262,
24948   notless: 0x226E,
24949   notlessnorequal: 0x2270,
24950   notparallel: 0x2226,
24951   notprecedes: 0x2280,
24952   notsubset: 0x2284,
24953   notsucceeds: 0x2281,
24954   notsuperset: 0x2285,
24955   nowarmenian: 0x0576,
24956   nparen: 0x24A9,
24957   nssquare: 0x33B1,
24958   nsuperior: 0x207F,
24959   ntilde: 0x00F1,
24960   nu: 0x03BD,
24961   nuhiragana: 0x306C,
24962   nukatakana: 0x30CC,
24963   nukatakanahalfwidth: 0xFF87,
24964   nuktabengali: 0x09BC,
24965   nuktadeva: 0x093C,
24966   nuktagujarati: 0x0ABC,
24967   nuktagurmukhi: 0x0A3C,
24968   numbersign: 0x0023,
24969   numbersignmonospace: 0xFF03,
24970   numbersignsmall: 0xFE5F,
24971   numeralsigngreek: 0x0374,
24972   numeralsignlowergreek: 0x0375,
24973   numero: 0x2116,
24974   nun: 0x05E0,
24975   nundagesh: 0xFB40,
24976   nundageshhebrew: 0xFB40,
24977   nunhebrew: 0x05E0,
24978   nvsquare: 0x33B5,
24979   nwsquare: 0x33BB,
24980   nyabengali: 0x099E,
24981   nyadeva: 0x091E,
24982   nyagujarati: 0x0A9E,
24983   nyagurmukhi: 0x0A1E,
24984   o: 0x006F,
24985   oacute: 0x00F3,
24986   oangthai: 0x0E2D,
24987   obarred: 0x0275,
24988   obarredcyrillic: 0x04E9,
24989   obarreddieresiscyrillic: 0x04EB,
24990   obengali: 0x0993,
24991   obopomofo: 0x311B,
24992   obreve: 0x014F,
24993   ocandradeva: 0x0911,
24994   ocandragujarati: 0x0A91,
24995   ocandravowelsigndeva: 0x0949,
24996   ocandravowelsigngujarati: 0x0AC9,
24997   ocaron: 0x01D2,
24998   ocircle: 0x24DE,
24999   ocircumflex: 0x00F4,
25000   ocircumflexacute: 0x1ED1,
25001   ocircumflexdotbelow: 0x1ED9,
25002   ocircumflexgrave: 0x1ED3,
25003   ocircumflexhookabove: 0x1ED5,
25004   ocircumflextilde: 0x1ED7,
25005   ocyrillic: 0x043E,
25006   odblacute: 0x0151,
25007   odblgrave: 0x020D,
25008   odeva: 0x0913,
25009   odieresis: 0x00F6,
25010   odieresiscyrillic: 0x04E7,
25011   odotbelow: 0x1ECD,
25012   oe: 0x0153,
25013   oekorean: 0x315A,
25014   ogonek: 0x02DB,
25015   ogonekcmb: 0x0328,
25016   ograve: 0x00F2,
25017   ogujarati: 0x0A93,
25018   oharmenian: 0x0585,
25019   ohiragana: 0x304A,
25020   ohookabove: 0x1ECF,
25021   ohorn: 0x01A1,
25022   ohornacute: 0x1EDB,
25023   ohorndotbelow: 0x1EE3,
25024   ohorngrave: 0x1EDD,
25025   ohornhookabove: 0x1EDF,
25026   ohorntilde: 0x1EE1,
25027   ohungarumlaut: 0x0151,
25028   oi: 0x01A3,
25029   oinvertedbreve: 0x020F,
25030   okatakana: 0x30AA,
25031   okatakanahalfwidth: 0xFF75,
25032   okorean: 0x3157,
25033   olehebrew: 0x05AB,
25034   omacron: 0x014D,
25035   omacronacute: 0x1E53,
25036   omacrongrave: 0x1E51,
25037   omdeva: 0x0950,
25038   omega: 0x03C9,
25039   omega1: 0x03D6,
25040   omegacyrillic: 0x0461,
25041   omegalatinclosed: 0x0277,
25042   omegaroundcyrillic: 0x047B,
25043   omegatitlocyrillic: 0x047D,
25044   omegatonos: 0x03CE,
25045   omgujarati: 0x0AD0,
25046   omicron: 0x03BF,
25047   omicrontonos: 0x03CC,
25048   omonospace: 0xFF4F,
25049   one: 0x0031,
25050   onearabic: 0x0661,
25051   onebengali: 0x09E7,
25052   onecircle: 0x2460,
25053   onecircleinversesansserif: 0x278A,
25054   onedeva: 0x0967,
25055   onedotenleader: 0x2024,
25056   oneeighth: 0x215B,
25057   onefitted: 0xF6DC,
25058   onegujarati: 0x0AE7,
25059   onegurmukhi: 0x0A67,
25060   onehackarabic: 0x0661,
25061   onehalf: 0x00BD,
25062   onehangzhou: 0x3021,
25063   oneideographicparen: 0x3220,
25064   oneinferior: 0x2081,
25065   onemonospace: 0xFF11,
25066   onenumeratorbengali: 0x09F4,
25067   oneoldstyle: 0xF731,
25068   oneparen: 0x2474,
25069   oneperiod: 0x2488,
25070   onepersian: 0x06F1,
25071   onequarter: 0x00BC,
25072   oneroman: 0x2170,
25073   onesuperior: 0x00B9,
25074   onethai: 0x0E51,
25075   onethird: 0x2153,
25076   oogonek: 0x01EB,
25077   oogonekmacron: 0x01ED,
25078   oogurmukhi: 0x0A13,
25079   oomatragurmukhi: 0x0A4B,
25080   oopen: 0x0254,
25081   oparen: 0x24AA,
25082   openbullet: 0x25E6,
25083   option: 0x2325,
25084   ordfeminine: 0x00AA,
25085   ordmasculine: 0x00BA,
25086   orthogonal: 0x221F,
25087   oshortdeva: 0x0912,
25088   oshortvowelsigndeva: 0x094A,
25089   oslash: 0x00F8,
25090   oslashacute: 0x01FF,
25091   osmallhiragana: 0x3049,
25092   osmallkatakana: 0x30A9,
25093   osmallkatakanahalfwidth: 0xFF6B,
25094   ostrokeacute: 0x01FF,
25095   osuperior: 0xF6F0,
25096   otcyrillic: 0x047F,
25097   otilde: 0x00F5,
25098   otildeacute: 0x1E4D,
25099   otildedieresis: 0x1E4F,
25100   oubopomofo: 0x3121,
25101   overline: 0x203E,
25102   overlinecenterline: 0xFE4A,
25103   overlinecmb: 0x0305,
25104   overlinedashed: 0xFE49,
25105   overlinedblwavy: 0xFE4C,
25106   overlinewavy: 0xFE4B,
25107   overscore: 0x00AF,
25108   ovowelsignbengali: 0x09CB,
25109   ovowelsigndeva: 0x094B,
25110   ovowelsigngujarati: 0x0ACB,
25111   p: 0x0070,
25112   paampssquare: 0x3380,
25113   paasentosquare: 0x332B,
25114   pabengali: 0x09AA,
25115   pacute: 0x1E55,
25116   padeva: 0x092A,
25117   pagedown: 0x21DF,
25118   pageup: 0x21DE,
25119   pagujarati: 0x0AAA,
25120   pagurmukhi: 0x0A2A,
25121   pahiragana: 0x3071,
25122   paiyannoithai: 0x0E2F,
25123   pakatakana: 0x30D1,
25124   palatalizationcyrilliccmb: 0x0484,
25125   palochkacyrillic: 0x04C0,
25126   pansioskorean: 0x317F,
25127   paragraph: 0x00B6,
25128   parallel: 0x2225,
25129   parenleft: 0x0028,
25130   parenleftaltonearabic: 0xFD3E,
25131   parenleftbt: 0xF8ED,
25132   parenleftex: 0xF8EC,
25133   parenleftinferior: 0x208D,
25134   parenleftmonospace: 0xFF08,
25135   parenleftsmall: 0xFE59,
25136   parenleftsuperior: 0x207D,
25137   parenlefttp: 0xF8EB,
25138   parenleftvertical: 0xFE35,
25139   parenright: 0x0029,
25140   parenrightaltonearabic: 0xFD3F,
25141   parenrightbt: 0xF8F8,
25142   parenrightex: 0xF8F7,
25143   parenrightinferior: 0x208E,
25144   parenrightmonospace: 0xFF09,
25145   parenrightsmall: 0xFE5A,
25146   parenrightsuperior: 0x207E,
25147   parenrighttp: 0xF8F6,
25148   parenrightvertical: 0xFE36,
25149   partialdiff: 0x2202,
25150   paseqhebrew: 0x05C0,
25151   pashtahebrew: 0x0599,
25152   pasquare: 0x33A9,
25153   patah: 0x05B7,
25154   patah11: 0x05B7,
25155   patah1d: 0x05B7,
25156   patah2a: 0x05B7,
25157   patahhebrew: 0x05B7,
25158   patahnarrowhebrew: 0x05B7,
25159   patahquarterhebrew: 0x05B7,
25160   patahwidehebrew: 0x05B7,
25161   pazerhebrew: 0x05A1,
25162   pbopomofo: 0x3106,
25163   pcircle: 0x24DF,
25164   pdotaccent: 0x1E57,
25165   pe: 0x05E4,
25166   pecyrillic: 0x043F,
25167   pedagesh: 0xFB44,
25168   pedageshhebrew: 0xFB44,
25169   peezisquare: 0x333B,
25170   pefinaldageshhebrew: 0xFB43,
25171   peharabic: 0x067E,
25172   peharmenian: 0x057A,
25173   pehebrew: 0x05E4,
25174   pehfinalarabic: 0xFB57,
25175   pehinitialarabic: 0xFB58,
25176   pehiragana: 0x307A,
25177   pehmedialarabic: 0xFB59,
25178   pekatakana: 0x30DA,
25179   pemiddlehookcyrillic: 0x04A7,
25180   perafehebrew: 0xFB4E,
25181   percent: 0x0025,
25182   percentarabic: 0x066A,
25183   percentmonospace: 0xFF05,
25184   percentsmall: 0xFE6A,
25185   period: 0x002E,
25186   periodarmenian: 0x0589,
25187   periodcentered: 0x00B7,
25188   periodhalfwidth: 0xFF61,
25189   periodinferior: 0xF6E7,
25190   periodmonospace: 0xFF0E,
25191   periodsmall: 0xFE52,
25192   periodsuperior: 0xF6E8,
25193   perispomenigreekcmb: 0x0342,
25194   perpendicular: 0x22A5,
25195   perthousand: 0x2030,
25196   peseta: 0x20A7,
25197   pfsquare: 0x338A,
25198   phabengali: 0x09AB,
25199   phadeva: 0x092B,
25200   phagujarati: 0x0AAB,
25201   phagurmukhi: 0x0A2B,
25202   phi: 0x03C6,
25203   phi1: 0x03D5,
25204   phieuphacirclekorean: 0x327A,
25205   phieuphaparenkorean: 0x321A,
25206   phieuphcirclekorean: 0x326C,
25207   phieuphkorean: 0x314D,
25208   phieuphparenkorean: 0x320C,
25209   philatin: 0x0278,
25210   phinthuthai: 0x0E3A,
25211   phisymbolgreek: 0x03D5,
25212   phook: 0x01A5,
25213   phophanthai: 0x0E1E,
25214   phophungthai: 0x0E1C,
25215   phosamphaothai: 0x0E20,
25216   pi: 0x03C0,
25217   pieupacirclekorean: 0x3273,
25218   pieupaparenkorean: 0x3213,
25219   pieupcieuckorean: 0x3176,
25220   pieupcirclekorean: 0x3265,
25221   pieupkiyeokkorean: 0x3172,
25222   pieupkorean: 0x3142,
25223   pieupparenkorean: 0x3205,
25224   pieupsioskiyeokkorean: 0x3174,
25225   pieupsioskorean: 0x3144,
25226   pieupsiostikeutkorean: 0x3175,
25227   pieupthieuthkorean: 0x3177,
25228   pieuptikeutkorean: 0x3173,
25229   pihiragana: 0x3074,
25230   pikatakana: 0x30D4,
25231   pisymbolgreek: 0x03D6,
25232   piwrarmenian: 0x0583,
25233   plus: 0x002B,
25234   plusbelowcmb: 0x031F,
25235   pluscircle: 0x2295,
25236   plusminus: 0x00B1,
25237   plusmod: 0x02D6,
25238   plusmonospace: 0xFF0B,
25239   plussmall: 0xFE62,
25240   plussuperior: 0x207A,
25241   pmonospace: 0xFF50,
25242   pmsquare: 0x33D8,
25243   pohiragana: 0x307D,
25244   pointingindexdownwhite: 0x261F,
25245   pointingindexleftwhite: 0x261C,
25246   pointingindexrightwhite: 0x261E,
25247   pointingindexupwhite: 0x261D,
25248   pokatakana: 0x30DD,
25249   poplathai: 0x0E1B,
25250   postalmark: 0x3012,
25251   postalmarkface: 0x3020,
25252   pparen: 0x24AB,
25253   precedes: 0x227A,
25254   prescription: 0x211E,
25255   primemod: 0x02B9,
25256   primereversed: 0x2035,
25257   product: 0x220F,
25258   projective: 0x2305,
25259   prolongedkana: 0x30FC,
25260   propellor: 0x2318,
25261   propersubset: 0x2282,
25262   propersuperset: 0x2283,
25263   proportion: 0x2237,
25264   proportional: 0x221D,
25265   psi: 0x03C8,
25266   psicyrillic: 0x0471,
25267   psilipneumatacyrilliccmb: 0x0486,
25268   pssquare: 0x33B0,
25269   puhiragana: 0x3077,
25270   pukatakana: 0x30D7,
25271   pvsquare: 0x33B4,
25272   pwsquare: 0x33BA,
25273   q: 0x0071,
25274   qadeva: 0x0958,
25275   qadmahebrew: 0x05A8,
25276   qafarabic: 0x0642,
25277   qaffinalarabic: 0xFED6,
25278   qafinitialarabic: 0xFED7,
25279   qafmedialarabic: 0xFED8,
25280   qamats: 0x05B8,
25281   qamats10: 0x05B8,
25282   qamats1a: 0x05B8,
25283   qamats1c: 0x05B8,
25284   qamats27: 0x05B8,
25285   qamats29: 0x05B8,
25286   qamats33: 0x05B8,
25287   qamatsde: 0x05B8,
25288   qamatshebrew: 0x05B8,
25289   qamatsnarrowhebrew: 0x05B8,
25290   qamatsqatanhebrew: 0x05B8,
25291   qamatsqatannarrowhebrew: 0x05B8,
25292   qamatsqatanquarterhebrew: 0x05B8,
25293   qamatsqatanwidehebrew: 0x05B8,
25294   qamatsquarterhebrew: 0x05B8,
25295   qamatswidehebrew: 0x05B8,
25296   qarneyparahebrew: 0x059F,
25297   qbopomofo: 0x3111,
25298   qcircle: 0x24E0,
25299   qhook: 0x02A0,
25300   qmonospace: 0xFF51,
25301   qof: 0x05E7,
25302   qofdagesh: 0xFB47,
25303   qofdageshhebrew: 0xFB47,
25304   qofhebrew: 0x05E7,
25305   qparen: 0x24AC,
25306   quarternote: 0x2669,
25307   qubuts: 0x05BB,
25308   qubuts18: 0x05BB,
25309   qubuts25: 0x05BB,
25310   qubuts31: 0x05BB,
25311   qubutshebrew: 0x05BB,
25312   qubutsnarrowhebrew: 0x05BB,
25313   qubutsquarterhebrew: 0x05BB,
25314   qubutswidehebrew: 0x05BB,
25315   question: 0x003F,
25316   questionarabic: 0x061F,
25317   questionarmenian: 0x055E,
25318   questiondown: 0x00BF,
25319   questiondownsmall: 0xF7BF,
25320   questiongreek: 0x037E,
25321   questionmonospace: 0xFF1F,
25322   questionsmall: 0xF73F,
25323   quotedbl: 0x0022,
25324   quotedblbase: 0x201E,
25325   quotedblleft: 0x201C,
25326   quotedblmonospace: 0xFF02,
25327   quotedblprime: 0x301E,
25328   quotedblprimereversed: 0x301D,
25329   quotedblright: 0x201D,
25330   quoteleft: 0x2018,
25331   quoteleftreversed: 0x201B,
25332   quotereversed: 0x201B,
25333   quoteright: 0x2019,
25334   quoterightn: 0x0149,
25335   quotesinglbase: 0x201A,
25336   quotesingle: 0x0027,
25337   quotesinglemonospace: 0xFF07,
25338   r: 0x0072,
25339   raarmenian: 0x057C,
25340   rabengali: 0x09B0,
25341   racute: 0x0155,
25342   radeva: 0x0930,
25343   radical: 0x221A,
25344   radicalex: 0xF8E5,
25345   radoverssquare: 0x33AE,
25346   radoverssquaredsquare: 0x33AF,
25347   radsquare: 0x33AD,
25348   rafe: 0x05BF,
25349   rafehebrew: 0x05BF,
25350   ragujarati: 0x0AB0,
25351   ragurmukhi: 0x0A30,
25352   rahiragana: 0x3089,
25353   rakatakana: 0x30E9,
25354   rakatakanahalfwidth: 0xFF97,
25355   ralowerdiagonalbengali: 0x09F1,
25356   ramiddlediagonalbengali: 0x09F0,
25357   ramshorn: 0x0264,
25358   ratio: 0x2236,
25359   rbopomofo: 0x3116,
25360   rcaron: 0x0159,
25361   rcedilla: 0x0157,
25362   rcircle: 0x24E1,
25363   rcommaaccent: 0x0157,
25364   rdblgrave: 0x0211,
25365   rdotaccent: 0x1E59,
25366   rdotbelow: 0x1E5B,
25367   rdotbelowmacron: 0x1E5D,
25368   referencemark: 0x203B,
25369   reflexsubset: 0x2286,
25370   reflexsuperset: 0x2287,
25371   registered: 0x00AE,
25372   registersans: 0xF8E8,
25373   registerserif: 0xF6DA,
25374   reharabic: 0x0631,
25375   reharmenian: 0x0580,
25376   rehfinalarabic: 0xFEAE,
25377   rehiragana: 0x308C,
25378   rekatakana: 0x30EC,
25379   rekatakanahalfwidth: 0xFF9A,
25380   resh: 0x05E8,
25381   reshdageshhebrew: 0xFB48,
25382   reshhebrew: 0x05E8,
25383   reversedtilde: 0x223D,
25384   reviahebrew: 0x0597,
25385   reviamugrashhebrew: 0x0597,
25386   revlogicalnot: 0x2310,
25387   rfishhook: 0x027E,
25388   rfishhookreversed: 0x027F,
25389   rhabengali: 0x09DD,
25390   rhadeva: 0x095D,
25391   rho: 0x03C1,
25392   rhook: 0x027D,
25393   rhookturned: 0x027B,
25394   rhookturnedsuperior: 0x02B5,
25395   rhosymbolgreek: 0x03F1,
25396   rhotichookmod: 0x02DE,
25397   rieulacirclekorean: 0x3271,
25398   rieulaparenkorean: 0x3211,
25399   rieulcirclekorean: 0x3263,
25400   rieulhieuhkorean: 0x3140,
25401   rieulkiyeokkorean: 0x313A,
25402   rieulkiyeoksioskorean: 0x3169,
25403   rieulkorean: 0x3139,
25404   rieulmieumkorean: 0x313B,
25405   rieulpansioskorean: 0x316C,
25406   rieulparenkorean: 0x3203,
25407   rieulphieuphkorean: 0x313F,
25408   rieulpieupkorean: 0x313C,
25409   rieulpieupsioskorean: 0x316B,
25410   rieulsioskorean: 0x313D,
25411   rieulthieuthkorean: 0x313E,
25412   rieultikeutkorean: 0x316A,
25413   rieulyeorinhieuhkorean: 0x316D,
25414   rightangle: 0x221F,
25415   righttackbelowcmb: 0x0319,
25416   righttriangle: 0x22BF,
25417   rihiragana: 0x308A,
25418   rikatakana: 0x30EA,
25419   rikatakanahalfwidth: 0xFF98,
25420   ring: 0x02DA,
25421   ringbelowcmb: 0x0325,
25422   ringcmb: 0x030A,
25423   ringhalfleft: 0x02BF,
25424   ringhalfleftarmenian: 0x0559,
25425   ringhalfleftbelowcmb: 0x031C,
25426   ringhalfleftcentered: 0x02D3,
25427   ringhalfright: 0x02BE,
25428   ringhalfrightbelowcmb: 0x0339,
25429   ringhalfrightcentered: 0x02D2,
25430   rinvertedbreve: 0x0213,
25431   rittorusquare: 0x3351,
25432   rlinebelow: 0x1E5F,
25433   rlongleg: 0x027C,
25434   rlonglegturned: 0x027A,
25435   rmonospace: 0xFF52,
25436   rohiragana: 0x308D,
25437   rokatakana: 0x30ED,
25438   rokatakanahalfwidth: 0xFF9B,
25439   roruathai: 0x0E23,
25440   rparen: 0x24AD,
25441   rrabengali: 0x09DC,
25442   rradeva: 0x0931,
25443   rragurmukhi: 0x0A5C,
25444   rreharabic: 0x0691,
25445   rrehfinalarabic: 0xFB8D,
25446   rrvocalicbengali: 0x09E0,
25447   rrvocalicdeva: 0x0960,
25448   rrvocalicgujarati: 0x0AE0,
25449   rrvocalicvowelsignbengali: 0x09C4,
25450   rrvocalicvowelsigndeva: 0x0944,
25451   rrvocalicvowelsigngujarati: 0x0AC4,
25452   rsuperior: 0xF6F1,
25453   rtblock: 0x2590,
25454   rturned: 0x0279,
25455   rturnedsuperior: 0x02B4,
25456   ruhiragana: 0x308B,
25457   rukatakana: 0x30EB,
25458   rukatakanahalfwidth: 0xFF99,
25459   rupeemarkbengali: 0x09F2,
25460   rupeesignbengali: 0x09F3,
25461   rupiah: 0xF6DD,
25462   ruthai: 0x0E24,
25463   rvocalicbengali: 0x098B,
25464   rvocalicdeva: 0x090B,
25465   rvocalicgujarati: 0x0A8B,
25466   rvocalicvowelsignbengali: 0x09C3,
25467   rvocalicvowelsigndeva: 0x0943,
25468   rvocalicvowelsigngujarati: 0x0AC3,
25469   s: 0x0073,
25470   sabengali: 0x09B8,
25471   sacute: 0x015B,
25472   sacutedotaccent: 0x1E65,
25473   sadarabic: 0x0635,
25474   sadeva: 0x0938,
25475   sadfinalarabic: 0xFEBA,
25476   sadinitialarabic: 0xFEBB,
25477   sadmedialarabic: 0xFEBC,
25478   sagujarati: 0x0AB8,
25479   sagurmukhi: 0x0A38,
25480   sahiragana: 0x3055,
25481   sakatakana: 0x30B5,
25482   sakatakanahalfwidth: 0xFF7B,
25483   sallallahoualayhewasallamarabic: 0xFDFA,
25484   samekh: 0x05E1,
25485   samekhdagesh: 0xFB41,
25486   samekhdageshhebrew: 0xFB41,
25487   samekhhebrew: 0x05E1,
25488   saraaathai: 0x0E32,
25489   saraaethai: 0x0E41,
25490   saraaimaimalaithai: 0x0E44,
25491   saraaimaimuanthai: 0x0E43,
25492   saraamthai: 0x0E33,
25493   saraathai: 0x0E30,
25494   saraethai: 0x0E40,
25495   saraiileftthai: 0xF886,
25496   saraiithai: 0x0E35,
25497   saraileftthai: 0xF885,
25498   saraithai: 0x0E34,
25499   saraothai: 0x0E42,
25500   saraueeleftthai: 0xF888,
25501   saraueethai: 0x0E37,
25502   saraueleftthai: 0xF887,
25503   sarauethai: 0x0E36,
25504   sarauthai: 0x0E38,
25505   sarauuthai: 0x0E39,
25506   sbopomofo: 0x3119,
25507   scaron: 0x0161,
25508   scarondotaccent: 0x1E67,
25509   scedilla: 0x015F,
25510   schwa: 0x0259,
25511   schwacyrillic: 0x04D9,
25512   schwadieresiscyrillic: 0x04DB,
25513   schwahook: 0x025A,
25514   scircle: 0x24E2,
25515   scircumflex: 0x015D,
25516   scommaaccent: 0x0219,
25517   sdotaccent: 0x1E61,
25518   sdotbelow: 0x1E63,
25519   sdotbelowdotaccent: 0x1E69,
25520   seagullbelowcmb: 0x033C,
25521   second: 0x2033,
25522   secondtonechinese: 0x02CA,
25523   section: 0x00A7,
25524   seenarabic: 0x0633,
25525   seenfinalarabic: 0xFEB2,
25526   seeninitialarabic: 0xFEB3,
25527   seenmedialarabic: 0xFEB4,
25528   segol: 0x05B6,
25529   segol13: 0x05B6,
25530   segol1f: 0x05B6,
25531   segol2c: 0x05B6,
25532   segolhebrew: 0x05B6,
25533   segolnarrowhebrew: 0x05B6,
25534   segolquarterhebrew: 0x05B6,
25535   segoltahebrew: 0x0592,
25536   segolwidehebrew: 0x05B6,
25537   seharmenian: 0x057D,
25538   sehiragana: 0x305B,
25539   sekatakana: 0x30BB,
25540   sekatakanahalfwidth: 0xFF7E,
25541   semicolon: 0x003B,
25542   semicolonarabic: 0x061B,
25543   semicolonmonospace: 0xFF1B,
25544   semicolonsmall: 0xFE54,
25545   semivoicedmarkkana: 0x309C,
25546   semivoicedmarkkanahalfwidth: 0xFF9F,
25547   sentisquare: 0x3322,
25548   sentosquare: 0x3323,
25549   seven: 0x0037,
25550   sevenarabic: 0x0667,
25551   sevenbengali: 0x09ED,
25552   sevencircle: 0x2466,
25553   sevencircleinversesansserif: 0x2790,
25554   sevendeva: 0x096D,
25555   seveneighths: 0x215E,
25556   sevengujarati: 0x0AED,
25557   sevengurmukhi: 0x0A6D,
25558   sevenhackarabic: 0x0667,
25559   sevenhangzhou: 0x3027,
25560   sevenideographicparen: 0x3226,
25561   seveninferior: 0x2087,
25562   sevenmonospace: 0xFF17,
25563   sevenoldstyle: 0xF737,
25564   sevenparen: 0x247A,
25565   sevenperiod: 0x248E,
25566   sevenpersian: 0x06F7,
25567   sevenroman: 0x2176,
25568   sevensuperior: 0x2077,
25569   seventeencircle: 0x2470,
25570   seventeenparen: 0x2484,
25571   seventeenperiod: 0x2498,
25572   seventhai: 0x0E57,
25573   sfthyphen: 0x00AD,
25574   shaarmenian: 0x0577,
25575   shabengali: 0x09B6,
25576   shacyrillic: 0x0448,
25577   shaddaarabic: 0x0651,
25578   shaddadammaarabic: 0xFC61,
25579   shaddadammatanarabic: 0xFC5E,
25580   shaddafathaarabic: 0xFC60,
25581   shaddakasraarabic: 0xFC62,
25582   shaddakasratanarabic: 0xFC5F,
25583   shade: 0x2592,
25584   shadedark: 0x2593,
25585   shadelight: 0x2591,
25586   shademedium: 0x2592,
25587   shadeva: 0x0936,
25588   shagujarati: 0x0AB6,
25589   shagurmukhi: 0x0A36,
25590   shalshelethebrew: 0x0593,
25591   shbopomofo: 0x3115,
25592   shchacyrillic: 0x0449,
25593   sheenarabic: 0x0634,
25594   sheenfinalarabic: 0xFEB6,
25595   sheeninitialarabic: 0xFEB7,
25596   sheenmedialarabic: 0xFEB8,
25597   sheicoptic: 0x03E3,
25598   sheqel: 0x20AA,
25599   sheqelhebrew: 0x20AA,
25600   sheva: 0x05B0,
25601   sheva115: 0x05B0,
25602   sheva15: 0x05B0,
25603   sheva22: 0x05B0,
25604   sheva2e: 0x05B0,
25605   shevahebrew: 0x05B0,
25606   shevanarrowhebrew: 0x05B0,
25607   shevaquarterhebrew: 0x05B0,
25608   shevawidehebrew: 0x05B0,
25609   shhacyrillic: 0x04BB,
25610   shimacoptic: 0x03ED,
25611   shin: 0x05E9,
25612   shindagesh: 0xFB49,
25613   shindageshhebrew: 0xFB49,
25614   shindageshshindot: 0xFB2C,
25615   shindageshshindothebrew: 0xFB2C,
25616   shindageshsindot: 0xFB2D,
25617   shindageshsindothebrew: 0xFB2D,
25618   shindothebrew: 0x05C1,
25619   shinhebrew: 0x05E9,
25620   shinshindot: 0xFB2A,
25621   shinshindothebrew: 0xFB2A,
25622   shinsindot: 0xFB2B,
25623   shinsindothebrew: 0xFB2B,
25624   shook: 0x0282,
25625   sigma: 0x03C3,
25626   sigma1: 0x03C2,
25627   sigmafinal: 0x03C2,
25628   sigmalunatesymbolgreek: 0x03F2,
25629   sihiragana: 0x3057,
25630   sikatakana: 0x30B7,
25631   sikatakanahalfwidth: 0xFF7C,
25632   siluqhebrew: 0x05BD,
25633   siluqlefthebrew: 0x05BD,
25634   similar: 0x223C,
25635   sindothebrew: 0x05C2,
25636   siosacirclekorean: 0x3274,
25637   siosaparenkorean: 0x3214,
25638   sioscieuckorean: 0x317E,
25639   sioscirclekorean: 0x3266,
25640   sioskiyeokkorean: 0x317A,
25641   sioskorean: 0x3145,
25642   siosnieunkorean: 0x317B,
25643   siosparenkorean: 0x3206,
25644   siospieupkorean: 0x317D,
25645   siostikeutkorean: 0x317C,
25646   six: 0x0036,
25647   sixarabic: 0x0666,
25648   sixbengali: 0x09EC,
25649   sixcircle: 0x2465,
25650   sixcircleinversesansserif: 0x278F,
25651   sixdeva: 0x096C,
25652   sixgujarati: 0x0AEC,
25653   sixgurmukhi: 0x0A6C,
25654   sixhackarabic: 0x0666,
25655   sixhangzhou: 0x3026,
25656   sixideographicparen: 0x3225,
25657   sixinferior: 0x2086,
25658   sixmonospace: 0xFF16,
25659   sixoldstyle: 0xF736,
25660   sixparen: 0x2479,
25661   sixperiod: 0x248D,
25662   sixpersian: 0x06F6,
25663   sixroman: 0x2175,
25664   sixsuperior: 0x2076,
25665   sixteencircle: 0x246F,
25666   sixteencurrencydenominatorbengali: 0x09F9,
25667   sixteenparen: 0x2483,
25668   sixteenperiod: 0x2497,
25669   sixthai: 0x0E56,
25670   slash: 0x002F,
25671   slashmonospace: 0xFF0F,
25672   slong: 0x017F,
25673   slongdotaccent: 0x1E9B,
25674   smileface: 0x263A,
25675   smonospace: 0xFF53,
25676   sofpasuqhebrew: 0x05C3,
25677   softhyphen: 0x00AD,
25678   softsigncyrillic: 0x044C,
25679   sohiragana: 0x305D,
25680   sokatakana: 0x30BD,
25681   sokatakanahalfwidth: 0xFF7F,
25682   soliduslongoverlaycmb: 0x0338,
25683   solidusshortoverlaycmb: 0x0337,
25684   sorusithai: 0x0E29,
25685   sosalathai: 0x0E28,
25686   sosothai: 0x0E0B,
25687   sosuathai: 0x0E2A,
25688   space: 0x0020,
25689   spacehackarabic: 0x0020,
25690   spade: 0x2660,
25691   spadesuitblack: 0x2660,
25692   spadesuitwhite: 0x2664,
25693   sparen: 0x24AE,
25694   squarebelowcmb: 0x033B,
25695   squarecc: 0x33C4,
25696   squarecm: 0x339D,
25697   squarediagonalcrosshatchfill: 0x25A9,
25698   squarehorizontalfill: 0x25A4,
25699   squarekg: 0x338F,
25700   squarekm: 0x339E,
25701   squarekmcapital: 0x33CE,
25702   squareln: 0x33D1,
25703   squarelog: 0x33D2,
25704   squaremg: 0x338E,
25705   squaremil: 0x33D5,
25706   squaremm: 0x339C,
25707   squaremsquared: 0x33A1,
25708   squareorthogonalcrosshatchfill: 0x25A6,
25709   squareupperlefttolowerrightfill: 0x25A7,
25710   squareupperrighttolowerleftfill: 0x25A8,
25711   squareverticalfill: 0x25A5,
25712   squarewhitewithsmallblack: 0x25A3,
25713   srsquare: 0x33DB,
25714   ssabengali: 0x09B7,
25715   ssadeva: 0x0937,
25716   ssagujarati: 0x0AB7,
25717   ssangcieuckorean: 0x3149,
25718   ssanghieuhkorean: 0x3185,
25719   ssangieungkorean: 0x3180,
25720   ssangkiyeokkorean: 0x3132,
25721   ssangnieunkorean: 0x3165,
25722   ssangpieupkorean: 0x3143,
25723   ssangsioskorean: 0x3146,
25724   ssangtikeutkorean: 0x3138,
25725   ssuperior: 0xF6F2,
25726   sterling: 0x00A3,
25727   sterlingmonospace: 0xFFE1,
25728   strokelongoverlaycmb: 0x0336,
25729   strokeshortoverlaycmb: 0x0335,
25730   subset: 0x2282,
25731   subsetnotequal: 0x228A,
25732   subsetorequal: 0x2286,
25733   succeeds: 0x227B,
25734   suchthat: 0x220B,
25735   suhiragana: 0x3059,
25736   sukatakana: 0x30B9,
25737   sukatakanahalfwidth: 0xFF7D,
25738   sukunarabic: 0x0652,
25739   summation: 0x2211,
25740   sun: 0x263C,
25741   superset: 0x2283,
25742   supersetnotequal: 0x228B,
25743   supersetorequal: 0x2287,
25744   svsquare: 0x33DC,
25745   syouwaerasquare: 0x337C,
25746   t: 0x0074,
25747   tabengali: 0x09A4,
25748   tackdown: 0x22A4,
25749   tackleft: 0x22A3,
25750   tadeva: 0x0924,
25751   tagujarati: 0x0AA4,
25752   tagurmukhi: 0x0A24,
25753   taharabic: 0x0637,
25754   tahfinalarabic: 0xFEC2,
25755   tahinitialarabic: 0xFEC3,
25756   tahiragana: 0x305F,
25757   tahmedialarabic: 0xFEC4,
25758   taisyouerasquare: 0x337D,
25759   takatakana: 0x30BF,
25760   takatakanahalfwidth: 0xFF80,
25761   tatweelarabic: 0x0640,
25762   tau: 0x03C4,
25763   tav: 0x05EA,
25764   tavdages: 0xFB4A,
25765   tavdagesh: 0xFB4A,
25766   tavdageshhebrew: 0xFB4A,
25767   tavhebrew: 0x05EA,
25768   tbar: 0x0167,
25769   tbopomofo: 0x310A,
25770   tcaron: 0x0165,
25771   tccurl: 0x02A8,
25772   tcedilla: 0x0163,
25773   tcheharabic: 0x0686,
25774   tchehfinalarabic: 0xFB7B,
25775   tchehinitialarabic: 0xFB7C,
25776   tchehmedialarabic: 0xFB7D,
25777   tcircle: 0x24E3,
25778   tcircumflexbelow: 0x1E71,
25779   tcommaaccent: 0x0163,
25780   tdieresis: 0x1E97,
25781   tdotaccent: 0x1E6B,
25782   tdotbelow: 0x1E6D,
25783   tecyrillic: 0x0442,
25784   tedescendercyrillic: 0x04AD,
25785   teharabic: 0x062A,
25786   tehfinalarabic: 0xFE96,
25787   tehhahinitialarabic: 0xFCA2,
25788   tehhahisolatedarabic: 0xFC0C,
25789   tehinitialarabic: 0xFE97,
25790   tehiragana: 0x3066,
25791   tehjeeminitialarabic: 0xFCA1,
25792   tehjeemisolatedarabic: 0xFC0B,
25793   tehmarbutaarabic: 0x0629,
25794   tehmarbutafinalarabic: 0xFE94,
25795   tehmedialarabic: 0xFE98,
25796   tehmeeminitialarabic: 0xFCA4,
25797   tehmeemisolatedarabic: 0xFC0E,
25798   tehnoonfinalarabic: 0xFC73,
25799   tekatakana: 0x30C6,
25800   tekatakanahalfwidth: 0xFF83,
25801   telephone: 0x2121,
25802   telephoneblack: 0x260E,
25803   telishagedolahebrew: 0x05A0,
25804   telishaqetanahebrew: 0x05A9,
25805   tencircle: 0x2469,
25806   tenideographicparen: 0x3229,
25807   tenparen: 0x247D,
25808   tenperiod: 0x2491,
25809   tenroman: 0x2179,
25810   tesh: 0x02A7,
25811   tet: 0x05D8,
25812   tetdagesh: 0xFB38,
25813   tetdageshhebrew: 0xFB38,
25814   tethebrew: 0x05D8,
25815   tetsecyrillic: 0x04B5,
25816   tevirhebrew: 0x059B,
25817   tevirlefthebrew: 0x059B,
25818   thabengali: 0x09A5,
25819   thadeva: 0x0925,
25820   thagujarati: 0x0AA5,
25821   thagurmukhi: 0x0A25,
25822   thalarabic: 0x0630,
25823   thalfinalarabic: 0xFEAC,
25824   thanthakhatlowleftthai: 0xF898,
25825   thanthakhatlowrightthai: 0xF897,
25826   thanthakhatthai: 0x0E4C,
25827   thanthakhatupperleftthai: 0xF896,
25828   theharabic: 0x062B,
25829   thehfinalarabic: 0xFE9A,
25830   thehinitialarabic: 0xFE9B,
25831   thehmedialarabic: 0xFE9C,
25832   thereexists: 0x2203,
25833   therefore: 0x2234,
25834   theta: 0x03B8,
25835   theta1: 0x03D1,
25836   thetasymbolgreek: 0x03D1,
25837   thieuthacirclekorean: 0x3279,
25838   thieuthaparenkorean: 0x3219,
25839   thieuthcirclekorean: 0x326B,
25840   thieuthkorean: 0x314C,
25841   thieuthparenkorean: 0x320B,
25842   thirteencircle: 0x246C,
25843   thirteenparen: 0x2480,
25844   thirteenperiod: 0x2494,
25845   thonangmonthothai: 0x0E11,
25846   thook: 0x01AD,
25847   thophuthaothai: 0x0E12,
25848   thorn: 0x00FE,
25849   thothahanthai: 0x0E17,
25850   thothanthai: 0x0E10,
25851   thothongthai: 0x0E18,
25852   thothungthai: 0x0E16,
25853   thousandcyrillic: 0x0482,
25854   thousandsseparatorarabic: 0x066C,
25855   thousandsseparatorpersian: 0x066C,
25856   three: 0x0033,
25857   threearabic: 0x0663,
25858   threebengali: 0x09E9,
25859   threecircle: 0x2462,
25860   threecircleinversesansserif: 0x278C,
25861   threedeva: 0x0969,
25862   threeeighths: 0x215C,
25863   threegujarati: 0x0AE9,
25864   threegurmukhi: 0x0A69,
25865   threehackarabic: 0x0663,
25866   threehangzhou: 0x3023,
25867   threeideographicparen: 0x3222,
25868   threeinferior: 0x2083,
25869   threemonospace: 0xFF13,
25870   threenumeratorbengali: 0x09F6,
25871   threeoldstyle: 0xF733,
25872   threeparen: 0x2476,
25873   threeperiod: 0x248A,
25874   threepersian: 0x06F3,
25875   threequarters: 0x00BE,
25876   threequartersemdash: 0xF6DE,
25877   threeroman: 0x2172,
25878   threesuperior: 0x00B3,
25879   threethai: 0x0E53,
25880   thzsquare: 0x3394,
25881   tihiragana: 0x3061,
25882   tikatakana: 0x30C1,
25883   tikatakanahalfwidth: 0xFF81,
25884   tikeutacirclekorean: 0x3270,
25885   tikeutaparenkorean: 0x3210,
25886   tikeutcirclekorean: 0x3262,
25887   tikeutkorean: 0x3137,
25888   tikeutparenkorean: 0x3202,
25889   tilde: 0x02DC,
25890   tildebelowcmb: 0x0330,
25891   tildecmb: 0x0303,
25892   tildecomb: 0x0303,
25893   tildedoublecmb: 0x0360,
25894   tildeoperator: 0x223C,
25895   tildeoverlaycmb: 0x0334,
25896   tildeverticalcmb: 0x033E,
25897   timescircle: 0x2297,
25898   tipehahebrew: 0x0596,
25899   tipehalefthebrew: 0x0596,
25900   tippigurmukhi: 0x0A70,
25901   titlocyrilliccmb: 0x0483,
25902   tiwnarmenian: 0x057F,
25903   tlinebelow: 0x1E6F,
25904   tmonospace: 0xFF54,
25905   toarmenian: 0x0569,
25906   tohiragana: 0x3068,
25907   tokatakana: 0x30C8,
25908   tokatakanahalfwidth: 0xFF84,
25909   tonebarextrahighmod: 0x02E5,
25910   tonebarextralowmod: 0x02E9,
25911   tonebarhighmod: 0x02E6,
25912   tonebarlowmod: 0x02E8,
25913   tonebarmidmod: 0x02E7,
25914   tonefive: 0x01BD,
25915   tonesix: 0x0185,
25916   tonetwo: 0x01A8,
25917   tonos: 0x0384,
25918   tonsquare: 0x3327,
25919   topatakthai: 0x0E0F,
25920   tortoiseshellbracketleft: 0x3014,
25921   tortoiseshellbracketleftsmall: 0xFE5D,
25922   tortoiseshellbracketleftvertical: 0xFE39,
25923   tortoiseshellbracketright: 0x3015,
25924   tortoiseshellbracketrightsmall: 0xFE5E,
25925   tortoiseshellbracketrightvertical: 0xFE3A,
25926   totaothai: 0x0E15,
25927   tpalatalhook: 0x01AB,
25928   tparen: 0x24AF,
25929   trademark: 0x2122,
25930   trademarksans: 0xF8EA,
25931   trademarkserif: 0xF6DB,
25932   tretroflexhook: 0x0288,
25933   triagdn: 0x25BC,
25934   triaglf: 0x25C4,
25935   triagrt: 0x25BA,
25936   triagup: 0x25B2,
25937   ts: 0x02A6,
25938   tsadi: 0x05E6,
25939   tsadidagesh: 0xFB46,
25940   tsadidageshhebrew: 0xFB46,
25941   tsadihebrew: 0x05E6,
25942   tsecyrillic: 0x0446,
25943   tsere: 0x05B5,
25944   tsere12: 0x05B5,
25945   tsere1e: 0x05B5,
25946   tsere2b: 0x05B5,
25947   tserehebrew: 0x05B5,
25948   tserenarrowhebrew: 0x05B5,
25949   tserequarterhebrew: 0x05B5,
25950   tserewidehebrew: 0x05B5,
25951   tshecyrillic: 0x045B,
25952   tsuperior: 0xF6F3,
25953   ttabengali: 0x099F,
25954   ttadeva: 0x091F,
25955   ttagujarati: 0x0A9F,
25956   ttagurmukhi: 0x0A1F,
25957   tteharabic: 0x0679,
25958   ttehfinalarabic: 0xFB67,
25959   ttehinitialarabic: 0xFB68,
25960   ttehmedialarabic: 0xFB69,
25961   tthabengali: 0x09A0,
25962   tthadeva: 0x0920,
25963   tthagujarati: 0x0AA0,
25964   tthagurmukhi: 0x0A20,
25965   tturned: 0x0287,
25966   tuhiragana: 0x3064,
25967   tukatakana: 0x30C4,
25968   tukatakanahalfwidth: 0xFF82,
25969   tusmallhiragana: 0x3063,
25970   tusmallkatakana: 0x30C3,
25971   tusmallkatakanahalfwidth: 0xFF6F,
25972   twelvecircle: 0x246B,
25973   twelveparen: 0x247F,
25974   twelveperiod: 0x2493,
25975   twelveroman: 0x217B,
25976   twentycircle: 0x2473,
25977   twentyhangzhou: 0x5344,
25978   twentyparen: 0x2487,
25979   twentyperiod: 0x249B,
25980   two: 0x0032,
25981   twoarabic: 0x0662,
25982   twobengali: 0x09E8,
25983   twocircle: 0x2461,
25984   twocircleinversesansserif: 0x278B,
25985   twodeva: 0x0968,
25986   twodotenleader: 0x2025,
25987   twodotleader: 0x2025,
25988   twodotleadervertical: 0xFE30,
25989   twogujarati: 0x0AE8,
25990   twogurmukhi: 0x0A68,
25991   twohackarabic: 0x0662,
25992   twohangzhou: 0x3022,
25993   twoideographicparen: 0x3221,
25994   twoinferior: 0x2082,
25995   twomonospace: 0xFF12,
25996   twonumeratorbengali: 0x09F5,
25997   twooldstyle: 0xF732,
25998   twoparen: 0x2475,
25999   twoperiod: 0x2489,
26000   twopersian: 0x06F2,
26001   tworoman: 0x2171,
26002   twostroke: 0x01BB,
26003   twosuperior: 0x00B2,
26004   twothai: 0x0E52,
26005   twothirds: 0x2154,
26006   u: 0x0075,
26007   uacute: 0x00FA,
26008   ubar: 0x0289,
26009   ubengali: 0x0989,
26010   ubopomofo: 0x3128,
26011   ubreve: 0x016D,
26012   ucaron: 0x01D4,
26013   ucircle: 0x24E4,
26014   ucircumflex: 0x00FB,
26015   ucircumflexbelow: 0x1E77,
26016   ucyrillic: 0x0443,
26017   udattadeva: 0x0951,
26018   udblacute: 0x0171,
26019   udblgrave: 0x0215,
26020   udeva: 0x0909,
26021   udieresis: 0x00FC,
26022   udieresisacute: 0x01D8,
26023   udieresisbelow: 0x1E73,
26024   udieresiscaron: 0x01DA,
26025   udieresiscyrillic: 0x04F1,
26026   udieresisgrave: 0x01DC,
26027   udieresismacron: 0x01D6,
26028   udotbelow: 0x1EE5,
26029   ugrave: 0x00F9,
26030   ugujarati: 0x0A89,
26031   ugurmukhi: 0x0A09,
26032   uhiragana: 0x3046,
26033   uhookabove: 0x1EE7,
26034   uhorn: 0x01B0,
26035   uhornacute: 0x1EE9,
26036   uhorndotbelow: 0x1EF1,
26037   uhorngrave: 0x1EEB,
26038   uhornhookabove: 0x1EED,
26039   uhorntilde: 0x1EEF,
26040   uhungarumlaut: 0x0171,
26041   uhungarumlautcyrillic: 0x04F3,
26042   uinvertedbreve: 0x0217,
26043   ukatakana: 0x30A6,
26044   ukatakanahalfwidth: 0xFF73,
26045   ukcyrillic: 0x0479,
26046   ukorean: 0x315C,
26047   umacron: 0x016B,
26048   umacroncyrillic: 0x04EF,
26049   umacrondieresis: 0x1E7B,
26050   umatragurmukhi: 0x0A41,
26051   umonospace: 0xFF55,
26052   underscore: 0x005F,
26053   underscoredbl: 0x2017,
26054   underscoremonospace: 0xFF3F,
26055   underscorevertical: 0xFE33,
26056   underscorewavy: 0xFE4F,
26057   union: 0x222A,
26058   universal: 0x2200,
26059   uogonek: 0x0173,
26060   uparen: 0x24B0,
26061   upblock: 0x2580,
26062   upperdothebrew: 0x05C4,
26063   upsilon: 0x03C5,
26064   upsilondieresis: 0x03CB,
26065   upsilondieresistonos: 0x03B0,
26066   upsilonlatin: 0x028A,
26067   upsilontonos: 0x03CD,
26068   uptackbelowcmb: 0x031D,
26069   uptackmod: 0x02D4,
26070   uragurmukhi: 0x0A73,
26071   uring: 0x016F,
26072   ushortcyrillic: 0x045E,
26073   usmallhiragana: 0x3045,
26074   usmallkatakana: 0x30A5,
26075   usmallkatakanahalfwidth: 0xFF69,
26076   ustraightcyrillic: 0x04AF,
26077   ustraightstrokecyrillic: 0x04B1,
26078   utilde: 0x0169,
26079   utildeacute: 0x1E79,
26080   utildebelow: 0x1E75,
26081   uubengali: 0x098A,
26082   uudeva: 0x090A,
26083   uugujarati: 0x0A8A,
26084   uugurmukhi: 0x0A0A,
26085   uumatragurmukhi: 0x0A42,
26086   uuvowelsignbengali: 0x09C2,
26087   uuvowelsigndeva: 0x0942,
26088   uuvowelsigngujarati: 0x0AC2,
26089   uvowelsignbengali: 0x09C1,
26090   uvowelsigndeva: 0x0941,
26091   uvowelsigngujarati: 0x0AC1,
26092   v: 0x0076,
26093   vadeva: 0x0935,
26094   vagujarati: 0x0AB5,
26095   vagurmukhi: 0x0A35,
26096   vakatakana: 0x30F7,
26097   vav: 0x05D5,
26098   vavdagesh: 0xFB35,
26099   vavdagesh65: 0xFB35,
26100   vavdageshhebrew: 0xFB35,
26101   vavhebrew: 0x05D5,
26102   vavholam: 0xFB4B,
26103   vavholamhebrew: 0xFB4B,
26104   vavvavhebrew: 0x05F0,
26105   vavyodhebrew: 0x05F1,
26106   vcircle: 0x24E5,
26107   vdotbelow: 0x1E7F,
26108   vecyrillic: 0x0432,
26109   veharabic: 0x06A4,
26110   vehfinalarabic: 0xFB6B,
26111   vehinitialarabic: 0xFB6C,
26112   vehmedialarabic: 0xFB6D,
26113   vekatakana: 0x30F9,
26114   venus: 0x2640,
26115   verticalbar: 0x007C,
26116   verticallineabovecmb: 0x030D,
26117   verticallinebelowcmb: 0x0329,
26118   verticallinelowmod: 0x02CC,
26119   verticallinemod: 0x02C8,
26120   vewarmenian: 0x057E,
26121   vhook: 0x028B,
26122   vikatakana: 0x30F8,
26123   viramabengali: 0x09CD,
26124   viramadeva: 0x094D,
26125   viramagujarati: 0x0ACD,
26126   visargabengali: 0x0983,
26127   visargadeva: 0x0903,
26128   visargagujarati: 0x0A83,
26129   vmonospace: 0xFF56,
26130   voarmenian: 0x0578,
26131   voicediterationhiragana: 0x309E,
26132   voicediterationkatakana: 0x30FE,
26133   voicedmarkkana: 0x309B,
26134   voicedmarkkanahalfwidth: 0xFF9E,
26135   vokatakana: 0x30FA,
26136   vparen: 0x24B1,
26137   vtilde: 0x1E7D,
26138   vturned: 0x028C,
26139   vuhiragana: 0x3094,
26140   vukatakana: 0x30F4,
26141   w: 0x0077,
26142   wacute: 0x1E83,
26143   waekorean: 0x3159,
26144   wahiragana: 0x308F,
26145   wakatakana: 0x30EF,
26146   wakatakanahalfwidth: 0xFF9C,
26147   wakorean: 0x3158,
26148   wasmallhiragana: 0x308E,
26149   wasmallkatakana: 0x30EE,
26150   wattosquare: 0x3357,
26151   wavedash: 0x301C,
26152   wavyunderscorevertical: 0xFE34,
26153   wawarabic: 0x0648,
26154   wawfinalarabic: 0xFEEE,
26155   wawhamzaabovearabic: 0x0624,
26156   wawhamzaabovefinalarabic: 0xFE86,
26157   wbsquare: 0x33DD,
26158   wcircle: 0x24E6,
26159   wcircumflex: 0x0175,
26160   wdieresis: 0x1E85,
26161   wdotaccent: 0x1E87,
26162   wdotbelow: 0x1E89,
26163   wehiragana: 0x3091,
26164   weierstrass: 0x2118,
26165   wekatakana: 0x30F1,
26166   wekorean: 0x315E,
26167   weokorean: 0x315D,
26168   wgrave: 0x1E81,
26169   whitebullet: 0x25E6,
26170   whitecircle: 0x25CB,
26171   whitecircleinverse: 0x25D9,
26172   whitecornerbracketleft: 0x300E,
26173   whitecornerbracketleftvertical: 0xFE43,
26174   whitecornerbracketright: 0x300F,
26175   whitecornerbracketrightvertical: 0xFE44,
26176   whitediamond: 0x25C7,
26177   whitediamondcontainingblacksmalldiamond: 0x25C8,
26178   whitedownpointingsmalltriangle: 0x25BF,
26179   whitedownpointingtriangle: 0x25BD,
26180   whiteleftpointingsmalltriangle: 0x25C3,
26181   whiteleftpointingtriangle: 0x25C1,
26182   whitelenticularbracketleft: 0x3016,
26183   whitelenticularbracketright: 0x3017,
26184   whiterightpointingsmalltriangle: 0x25B9,
26185   whiterightpointingtriangle: 0x25B7,
26186   whitesmallsquare: 0x25AB,
26187   whitesmilingface: 0x263A,
26188   whitesquare: 0x25A1,
26189   whitestar: 0x2606,
26190   whitetelephone: 0x260F,
26191   whitetortoiseshellbracketleft: 0x3018,
26192   whitetortoiseshellbracketright: 0x3019,
26193   whiteuppointingsmalltriangle: 0x25B5,
26194   whiteuppointingtriangle: 0x25B3,
26195   wihiragana: 0x3090,
26196   wikatakana: 0x30F0,
26197   wikorean: 0x315F,
26198   wmonospace: 0xFF57,
26199   wohiragana: 0x3092,
26200   wokatakana: 0x30F2,
26201   wokatakanahalfwidth: 0xFF66,
26202   won: 0x20A9,
26203   wonmonospace: 0xFFE6,
26204   wowaenthai: 0x0E27,
26205   wparen: 0x24B2,
26206   wring: 0x1E98,
26207   wsuperior: 0x02B7,
26208   wturned: 0x028D,
26209   wynn: 0x01BF,
26210   x: 0x0078,
26211   xabovecmb: 0x033D,
26212   xbopomofo: 0x3112,
26213   xcircle: 0x24E7,
26214   xdieresis: 0x1E8D,
26215   xdotaccent: 0x1E8B,
26216   xeharmenian: 0x056D,
26217   xi: 0x03BE,
26218   xmonospace: 0xFF58,
26219   xparen: 0x24B3,
26220   xsuperior: 0x02E3,
26221   y: 0x0079,
26222   yaadosquare: 0x334E,
26223   yabengali: 0x09AF,
26224   yacute: 0x00FD,
26225   yadeva: 0x092F,
26226   yaekorean: 0x3152,
26227   yagujarati: 0x0AAF,
26228   yagurmukhi: 0x0A2F,
26229   yahiragana: 0x3084,
26230   yakatakana: 0x30E4,
26231   yakatakanahalfwidth: 0xFF94,
26232   yakorean: 0x3151,
26233   yamakkanthai: 0x0E4E,
26234   yasmallhiragana: 0x3083,
26235   yasmallkatakana: 0x30E3,
26236   yasmallkatakanahalfwidth: 0xFF6C,
26237   yatcyrillic: 0x0463,
26238   ycircle: 0x24E8,
26239   ycircumflex: 0x0177,
26240   ydieresis: 0x00FF,
26241   ydotaccent: 0x1E8F,
26242   ydotbelow: 0x1EF5,
26243   yeharabic: 0x064A,
26244   yehbarreearabic: 0x06D2,
26245   yehbarreefinalarabic: 0xFBAF,
26246   yehfinalarabic: 0xFEF2,
26247   yehhamzaabovearabic: 0x0626,
26248   yehhamzaabovefinalarabic: 0xFE8A,
26249   yehhamzaaboveinitialarabic: 0xFE8B,
26250   yehhamzaabovemedialarabic: 0xFE8C,
26251   yehinitialarabic: 0xFEF3,
26252   yehmedialarabic: 0xFEF4,
26253   yehmeeminitialarabic: 0xFCDD,
26254   yehmeemisolatedarabic: 0xFC58,
26255   yehnoonfinalarabic: 0xFC94,
26256   yehthreedotsbelowarabic: 0x06D1,
26257   yekorean: 0x3156,
26258   yen: 0x00A5,
26259   yenmonospace: 0xFFE5,
26260   yeokorean: 0x3155,
26261   yeorinhieuhkorean: 0x3186,
26262   yerahbenyomohebrew: 0x05AA,
26263   yerahbenyomolefthebrew: 0x05AA,
26264   yericyrillic: 0x044B,
26265   yerudieresiscyrillic: 0x04F9,
26266   yesieungkorean: 0x3181,
26267   yesieungpansioskorean: 0x3183,
26268   yesieungsioskorean: 0x3182,
26269   yetivhebrew: 0x059A,
26270   ygrave: 0x1EF3,
26271   yhook: 0x01B4,
26272   yhookabove: 0x1EF7,
26273   yiarmenian: 0x0575,
26274   yicyrillic: 0x0457,
26275   yikorean: 0x3162,
26276   yinyang: 0x262F,
26277   yiwnarmenian: 0x0582,
26278   ymonospace: 0xFF59,
26279   yod: 0x05D9,
26280   yoddagesh: 0xFB39,
26281   yoddageshhebrew: 0xFB39,
26282   yodhebrew: 0x05D9,
26283   yodyodhebrew: 0x05F2,
26284   yodyodpatahhebrew: 0xFB1F,
26285   yohiragana: 0x3088,
26286   yoikorean: 0x3189,
26287   yokatakana: 0x30E8,
26288   yokatakanahalfwidth: 0xFF96,
26289   yokorean: 0x315B,
26290   yosmallhiragana: 0x3087,
26291   yosmallkatakana: 0x30E7,
26292   yosmallkatakanahalfwidth: 0xFF6E,
26293   yotgreek: 0x03F3,
26294   yoyaekorean: 0x3188,
26295   yoyakorean: 0x3187,
26296   yoyakthai: 0x0E22,
26297   yoyingthai: 0x0E0D,
26298   yparen: 0x24B4,
26299   ypogegrammeni: 0x037A,
26300   ypogegrammenigreekcmb: 0x0345,
26301   yr: 0x01A6,
26302   yring: 0x1E99,
26303   ysuperior: 0x02B8,
26304   ytilde: 0x1EF9,
26305   yturned: 0x028E,
26306   yuhiragana: 0x3086,
26307   yuikorean: 0x318C,
26308   yukatakana: 0x30E6,
26309   yukatakanahalfwidth: 0xFF95,
26310   yukorean: 0x3160,
26311   yusbigcyrillic: 0x046B,
26312   yusbigiotifiedcyrillic: 0x046D,
26313   yuslittlecyrillic: 0x0467,
26314   yuslittleiotifiedcyrillic: 0x0469,
26315   yusmallhiragana: 0x3085,
26316   yusmallkatakana: 0x30E5,
26317   yusmallkatakanahalfwidth: 0xFF6D,
26318   yuyekorean: 0x318B,
26319   yuyeokorean: 0x318A,
26320   yyabengali: 0x09DF,
26321   yyadeva: 0x095F,
26322   z: 0x007A,
26323   zaarmenian: 0x0566,
26324   zacute: 0x017A,
26325   zadeva: 0x095B,
26326   zagurmukhi: 0x0A5B,
26327   zaharabic: 0x0638,
26328   zahfinalarabic: 0xFEC6,
26329   zahinitialarabic: 0xFEC7,
26330   zahiragana: 0x3056,
26331   zahmedialarabic: 0xFEC8,
26332   zainarabic: 0x0632,
26333   zainfinalarabic: 0xFEB0,
26334   zakatakana: 0x30B6,
26335   zaqefgadolhebrew: 0x0595,
26336   zaqefqatanhebrew: 0x0594,
26337   zarqahebrew: 0x0598,
26338   zayin: 0x05D6,
26339   zayindagesh: 0xFB36,
26340   zayindageshhebrew: 0xFB36,
26341   zayinhebrew: 0x05D6,
26342   zbopomofo: 0x3117,
26343   zcaron: 0x017E,
26344   zcircle: 0x24E9,
26345   zcircumflex: 0x1E91,
26346   zcurl: 0x0291,
26347   zdot: 0x017C,
26348   zdotaccent: 0x017C,
26349   zdotbelow: 0x1E93,
26350   zecyrillic: 0x0437,
26351   zedescendercyrillic: 0x0499,
26352   zedieresiscyrillic: 0x04DF,
26353   zehiragana: 0x305C,
26354   zekatakana: 0x30BC,
26355   zero: 0x0030,
26356   zeroarabic: 0x0660,
26357   zerobengali: 0x09E6,
26358   zerodeva: 0x0966,
26359   zerogujarati: 0x0AE6,
26360   zerogurmukhi: 0x0A66,
26361   zerohackarabic: 0x0660,
26362   zeroinferior: 0x2080,
26363   zeromonospace: 0xFF10,
26364   zerooldstyle: 0xF730,
26365   zeropersian: 0x06F0,
26366   zerosuperior: 0x2070,
26367   zerothai: 0x0E50,
26368   zerowidthjoiner: 0xFEFF,
26369   zerowidthnonjoiner: 0x200C,
26370   zerowidthspace: 0x200B,
26371   zeta: 0x03B6,
26372   zhbopomofo: 0x3113,
26373   zhearmenian: 0x056A,
26374   zhebrevecyrillic: 0x04C2,
26375   zhecyrillic: 0x0436,
26376   zhedescendercyrillic: 0x0497,
26377   zhedieresiscyrillic: 0x04DD,
26378   zihiragana: 0x3058,
26379   zikatakana: 0x30B8,
26380   zinorhebrew: 0x05AE,
26381   zlinebelow: 0x1E95,
26382   zmonospace: 0xFF5A,
26383   zohiragana: 0x305E,
26384   zokatakana: 0x30BE,
26385   zparen: 0x24B5,
26386   zretroflexhook: 0x0290,
26387   zstroke: 0x01B6,
26388   zuhiragana: 0x305A,
26389   zukatakana: 0x30BA,
26390   '.notdef': 0x0000
26391 };
26392
26393 var DingbatsGlyphsUnicode = {
26394   space: 0x0020,
26395   a1: 0x2701,
26396   a2: 0x2702,
26397   a202: 0x2703,
26398   a3: 0x2704,
26399   a4: 0x260E,
26400   a5: 0x2706,
26401   a119: 0x2707,
26402   a118: 0x2708,
26403   a117: 0x2709,
26404   a11: 0x261B,
26405   a12: 0x261E,
26406   a13: 0x270C,
26407   a14: 0x270D,
26408   a15: 0x270E,
26409   a16: 0x270F,
26410   a105: 0x2710,
26411   a17: 0x2711,
26412   a18: 0x2712,
26413   a19: 0x2713,
26414   a20: 0x2714,
26415   a21: 0x2715,
26416   a22: 0x2716,
26417   a23: 0x2717,
26418   a24: 0x2718,
26419   a25: 0x2719,
26420   a26: 0x271A,
26421   a27: 0x271B,
26422   a28: 0x271C,
26423   a6: 0x271D,
26424   a7: 0x271E,
26425   a8: 0x271F,
26426   a9: 0x2720,
26427   a10: 0x2721,
26428   a29: 0x2722,
26429   a30: 0x2723,
26430   a31: 0x2724,
26431   a32: 0x2725,
26432   a33: 0x2726,
26433   a34: 0x2727,
26434   a35: 0x2605,
26435   a36: 0x2729,
26436   a37: 0x272A,
26437   a38: 0x272B,
26438   a39: 0x272C,
26439   a40: 0x272D,
26440   a41: 0x272E,
26441   a42: 0x272F,
26442   a43: 0x2730,
26443   a44: 0x2731,
26444   a45: 0x2732,
26445   a46: 0x2733,
26446   a47: 0x2734,
26447   a48: 0x2735,
26448   a49: 0x2736,
26449   a50: 0x2737,
26450   a51: 0x2738,
26451   a52: 0x2739,
26452   a53: 0x273A,
26453   a54: 0x273B,
26454   a55: 0x273C,
26455   a56: 0x273D,
26456   a57: 0x273E,
26457   a58: 0x273F,
26458   a59: 0x2740,
26459   a60: 0x2741,
26460   a61: 0x2742,
26461   a62: 0x2743,
26462   a63: 0x2744,
26463   a64: 0x2745,
26464   a65: 0x2746,
26465   a66: 0x2747,
26466   a67: 0x2748,
26467   a68: 0x2749,
26468   a69: 0x274A,
26469   a70: 0x274B,
26470   a71: 0x25CF,
26471   a72: 0x274D,
26472   a73: 0x25A0,
26473   a74: 0x274F,
26474   a203: 0x2750,
26475   a75: 0x2751,
26476   a204: 0x2752,
26477   a76: 0x25B2,
26478   a77: 0x25BC,
26479   a78: 0x25C6,
26480   a79: 0x2756,
26481   a81: 0x25D7,
26482   a82: 0x2758,
26483   a83: 0x2759,
26484   a84: 0x275A,
26485   a97: 0x275B,
26486   a98: 0x275C,
26487   a99: 0x275D,
26488   a100: 0x275E,
26489   a101: 0x2761,
26490   a102: 0x2762,
26491   a103: 0x2763,
26492   a104: 0x2764,
26493   a106: 0x2765,
26494   a107: 0x2766,
26495   a108: 0x2767,
26496   a112: 0x2663,
26497   a111: 0x2666,
26498   a110: 0x2665,
26499   a109: 0x2660,
26500   a120: 0x2460,
26501   a121: 0x2461,
26502   a122: 0x2462,
26503   a123: 0x2463,
26504   a124: 0x2464,
26505   a125: 0x2465,
26506   a126: 0x2466,
26507   a127: 0x2467,
26508   a128: 0x2468,
26509   a129: 0x2469,
26510   a130: 0x2776,
26511   a131: 0x2777,
26512   a132: 0x2778,
26513   a133: 0x2779,
26514   a134: 0x277A,
26515   a135: 0x277B,
26516   a136: 0x277C,
26517   a137: 0x277D,
26518   a138: 0x277E,
26519   a139: 0x277F,
26520   a140: 0x2780,
26521   a141: 0x2781,
26522   a142: 0x2782,
26523   a143: 0x2783,
26524   a144: 0x2784,
26525   a145: 0x2785,
26526   a146: 0x2786,
26527   a147: 0x2787,
26528   a148: 0x2788,
26529   a149: 0x2789,
26530   a150: 0x278A,
26531   a151: 0x278B,
26532   a152: 0x278C,
26533   a153: 0x278D,
26534   a154: 0x278E,
26535   a155: 0x278F,
26536   a156: 0x2790,
26537   a157: 0x2791,
26538   a158: 0x2792,
26539   a159: 0x2793,
26540   a160: 0x2794,
26541   a161: 0x2192,
26542   a163: 0x2194,
26543   a164: 0x2195,
26544   a196: 0x2798,
26545   a165: 0x2799,
26546   a192: 0x279A,
26547   a166: 0x279B,
26548   a167: 0x279C,
26549   a168: 0x279D,
26550   a169: 0x279E,
26551   a170: 0x279F,
26552   a171: 0x27A0,
26553   a172: 0x27A1,
26554   a173: 0x27A2,
26555   a162: 0x27A3,
26556   a174: 0x27A4,
26557   a175: 0x27A5,
26558   a176: 0x27A6,
26559   a177: 0x27A7,
26560   a178: 0x27A8,
26561   a179: 0x27A9,
26562   a193: 0x27AA,
26563   a180: 0x27AB,
26564   a199: 0x27AC,
26565   a181: 0x27AD,
26566   a200: 0x27AE,
26567   a182: 0x27AF,
26568   a201: 0x27B1,
26569   a183: 0x27B2,
26570   a184: 0x27B3,
26571   a197: 0x27B4,
26572   a185: 0x27B5,
26573   a194: 0x27B6,
26574   a198: 0x27B7,
26575   a186: 0x27B8,
26576   a195: 0x27B9,
26577   a187: 0x27BA,
26578   a188: 0x27BB,
26579   a189: 0x27BC,
26580   a190: 0x27BD,
26581   a191: 0x27BE,
26582   a89: 0x2768, // 0xF8D7
26583   a90: 0x2769, // 0xF8D8
26584   a93: 0x276A, // 0xF8D9
26585   a94: 0x276B, // 0xF8DA
26586   a91: 0x276C, // 0xF8DB
26587   a92: 0x276D, // 0xF8DC
26588   a205: 0x276E, // 0xF8DD
26589   a85: 0x276F, // 0xF8DE
26590   a206: 0x2770, // 0xF8DF
26591   a86: 0x2771, // 0xF8E0
26592   a87: 0x2772, // 0xF8E1
26593   a88: 0x2773, // 0xF8E2
26594   a95: 0x2774, // 0xF8E3
26595   a96: 0x2775, // 0xF8E4
26596   '.notdef': 0x0000
26597 };
26598
26599
26600 var PDFImage = (function PDFImageClosure() {
26601   /**
26602    * Decode the image in the main thread if it supported. Resovles the promise
26603    * when the image data is ready.
26604    */
26605   function handleImageData(handler, xref, res, image) {
26606     if (image instanceof JpegStream && image.isNativelyDecodable(xref, res)) {
26607       // For natively supported jpegs send them to the main thread for decoding.
26608       var dict = image.dict;
26609       var colorSpace = dict.get('ColorSpace', 'CS');
26610       colorSpace = ColorSpace.parse(colorSpace, xref, res);
26611       var numComps = colorSpace.numComps;
26612       var decodePromise = handler.sendWithPromise('JpegDecode',
26613                                                   [image.getIR(), numComps]);
26614       return decodePromise.then(function (message) {
26615         var data = message.data;
26616         return new Stream(data, 0, data.length, image.dict);
26617       });
26618     } else {
26619       return Promise.resolve(image);
26620     }
26621   }
26622
26623   /**
26624    * Decode and clamp a value. The formula is different from the spec because we
26625    * don't decode to float range [0,1], we decode it in the [0,max] range.
26626    */
26627   function decodeAndClamp(value, addend, coefficient, max) {
26628     value = addend + value * coefficient;
26629     // Clamp the value to the range
26630     return (value < 0 ? 0 : (value > max ? max : value));
26631   }
26632
26633   function PDFImage(xref, res, image, inline, smask, mask, isMask) {
26634     this.image = image;
26635     var dict = image.dict;
26636     if (dict.has('Filter')) {
26637       var filter = dict.get('Filter').name;
26638       if (filter === 'JPXDecode') {
26639         var jpxImage = new JpxImage();
26640         jpxImage.parseImageProperties(image.stream);
26641         image.stream.reset();
26642         image.bitsPerComponent = jpxImage.bitsPerComponent;
26643         image.numComps = jpxImage.componentsCount;
26644       } else if (filter === 'JBIG2Decode') {
26645         image.bitsPerComponent = 1;
26646         image.numComps = 1;
26647       }
26648     }
26649     // TODO cache rendered images?
26650
26651     this.width = dict.get('Width', 'W');
26652     this.height = dict.get('Height', 'H');
26653
26654     if (this.width < 1 || this.height < 1) {
26655       error('Invalid image width: ' + this.width + ' or height: ' +
26656             this.height);
26657     }
26658
26659     this.interpolate = dict.get('Interpolate', 'I') || false;
26660     this.imageMask = dict.get('ImageMask', 'IM') || false;
26661     this.matte = dict.get('Matte') || false;
26662
26663     var bitsPerComponent = image.bitsPerComponent;
26664     if (!bitsPerComponent) {
26665       bitsPerComponent = dict.get('BitsPerComponent', 'BPC');
26666       if (!bitsPerComponent) {
26667         if (this.imageMask) {
26668           bitsPerComponent = 1;
26669         } else {
26670           error('Bits per component missing in image: ' + this.imageMask);
26671         }
26672       }
26673     }
26674     this.bpc = bitsPerComponent;
26675
26676     if (!this.imageMask) {
26677       var colorSpace = dict.get('ColorSpace', 'CS');
26678       if (!colorSpace) {
26679         info('JPX images (which do not require color spaces)');
26680         switch (image.numComps) {
26681           case 1:
26682             colorSpace = Name.get('DeviceGray');
26683             break;
26684           case 3:
26685             colorSpace = Name.get('DeviceRGB');
26686             break;
26687           case 4:
26688             colorSpace = Name.get('DeviceCMYK');
26689             break;
26690           default:
26691             error('JPX images with ' + this.numComps +
26692                   ' color components not supported.');
26693         }
26694       }
26695       this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
26696       this.numComps = this.colorSpace.numComps;
26697     }
26698
26699     this.decode = dict.get('Decode', 'D');
26700     this.needsDecode = false;
26701     if (this.decode &&
26702         ((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) ||
26703          (isMask && !ColorSpace.isDefaultDecode(this.decode, 1)))) {
26704       this.needsDecode = true;
26705       // Do some preprocessing to avoid more math.
26706       var max = (1 << bitsPerComponent) - 1;
26707       this.decodeCoefficients = [];
26708       this.decodeAddends = [];
26709       for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
26710         var dmin = this.decode[i];
26711         var dmax = this.decode[i + 1];
26712         this.decodeCoefficients[j] = dmax - dmin;
26713         this.decodeAddends[j] = max * dmin;
26714       }
26715     }
26716
26717     if (smask) {
26718       this.smask = new PDFImage(xref, res, smask, false);
26719     } else if (mask) {
26720       if (isStream(mask)) {
26721         this.mask = new PDFImage(xref, res, mask, false, null, null, true);
26722       } else {
26723         // Color key mask (just an array).
26724         this.mask = mask;
26725       }
26726     }
26727   }
26728   /**
26729    * Handles processing of image data and returns the Promise that is resolved
26730    * with a PDFImage when the image is ready to be used.
26731    */
26732   PDFImage.buildImage = function PDFImage_buildImage(handler, xref,
26733                                                      res, image, inline) {
26734     var imagePromise = handleImageData(handler, xref, res, image);
26735     var smaskPromise;
26736     var maskPromise;
26737
26738     var smask = image.dict.get('SMask');
26739     var mask = image.dict.get('Mask');
26740
26741     if (smask) {
26742       smaskPromise = handleImageData(handler, xref, res, smask);
26743       maskPromise = Promise.resolve(null);
26744     } else {
26745       smaskPromise = Promise.resolve(null);
26746       if (mask) {
26747         if (isStream(mask)) {
26748           maskPromise = handleImageData(handler, xref, res, mask);
26749         } else if (isArray(mask)) {
26750           maskPromise = Promise.resolve(mask);
26751         } else {
26752           warn('Unsupported mask format.');
26753           maskPromise = Promise.resolve(null);
26754         }
26755       } else {
26756         maskPromise = Promise.resolve(null);
26757       }
26758     }
26759     return Promise.all([imagePromise, smaskPromise, maskPromise]).then(
26760       function(results) {
26761         var imageData = results[0];
26762         var smaskData = results[1];
26763         var maskData = results[2];
26764         return new PDFImage(xref, res, imageData, inline, smaskData, maskData);
26765       });
26766   };
26767
26768   /**
26769    * Resize an image using the nearest neighbor algorithm. Currently only
26770    * supports one and three component images.
26771    * @param {TypedArray} pixels The original image with one component.
26772    * @param {Number} bpc Number of bits per component.
26773    * @param {Number} components Number of color components, 1 or 3 is supported.
26774    * @param {Number} w1 Original width.
26775    * @param {Number} h1 Original height.
26776    * @param {Number} w2 New width.
26777    * @param {Number} h2 New height.
26778    * @param {TypedArray} dest (Optional) The destination buffer.
26779    * @param {Number} alpha01 (Optional) Size reserved for the alpha channel.
26780    * @return {TypedArray} Resized image data.
26781    */
26782   PDFImage.resize = function PDFImage_resize(pixels, bpc, components,
26783                                              w1, h1, w2, h2, dest, alpha01) {
26784
26785     if (components !== 1 && components !== 3) {
26786       error('Unsupported component count for resizing.');
26787     }
26788
26789     var length = w2 * h2 * components;
26790     var temp = dest ? dest : (bpc <= 8 ? new Uint8Array(length) :
26791         (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
26792     var xRatio = w1 / w2;
26793     var yRatio = h1 / h2;
26794     var i, j, py, newIndex = 0, oldIndex;
26795     var xScaled = new Uint16Array(w2);
26796     var w1Scanline = w1 * components;
26797     if (alpha01 !== 1) {
26798       alpha01 = 0;
26799     }
26800
26801     for (j = 0; j < w2; j++) {
26802       xScaled[j] = Math.floor(j * xRatio) * components;
26803     }
26804
26805     if (components === 1) {
26806       for (i = 0; i < h2; i++) {
26807         py = Math.floor(i * yRatio) * w1Scanline;
26808         for (j = 0; j < w2; j++) {
26809           oldIndex = py + xScaled[j];
26810           temp[newIndex++] = pixels[oldIndex];
26811         }
26812       }
26813     } else if (components === 3) {
26814       for (i = 0; i < h2; i++) {
26815         py = Math.floor(i * yRatio) * w1Scanline;
26816         for (j = 0; j < w2; j++) {
26817           oldIndex = py + xScaled[j];
26818           temp[newIndex++] = pixels[oldIndex++];
26819           temp[newIndex++] = pixels[oldIndex++];
26820           temp[newIndex++] = pixels[oldIndex++];
26821           newIndex += alpha01;
26822         }
26823       }
26824     }
26825     return temp;
26826   };
26827
26828   PDFImage.createMask =
26829       function PDFImage_createMask(imgArray, width, height,
26830                                    imageIsFromDecodeStream, inverseDecode) {
26831
26832     // |imgArray| might not contain full data for every pixel of the mask, so
26833     // we need to distinguish between |computedLength| and |actualLength|.
26834     // In particular, if inverseDecode is true, then the array we return must
26835     // have a length of |computedLength|.
26836
26837     var computedLength = ((width + 7) >> 3) * height;
26838     var actualLength = imgArray.byteLength;
26839     var haveFullData = computedLength === actualLength;
26840     var data, i;
26841
26842     if (imageIsFromDecodeStream && (!inverseDecode || haveFullData)) {
26843       // imgArray came from a DecodeStream and its data is in an appropriate
26844       // form, so we can just transfer it.
26845       data = imgArray;
26846     } else if (!inverseDecode) {
26847       data = new Uint8Array(actualLength);
26848       data.set(imgArray);
26849     } else {
26850       data = new Uint8Array(computedLength);
26851       data.set(imgArray);
26852       for (i = actualLength; i < computedLength; i++) {
26853         data[i] = 0xff;
26854       }
26855     }
26856
26857     // If necessary, invert the original mask data (but not any extra we might
26858     // have added above). It's safe to modify the array -- whether it's the
26859     // original or a copy, we're about to transfer it anyway, so nothing else
26860     // in this thread can be relying on its contents.
26861     if (inverseDecode) {
26862       for (i = 0; i < actualLength; i++) {
26863         data[i] = ~data[i];
26864       }
26865     }
26866
26867     return {data: data, width: width, height: height};
26868   };
26869
26870   PDFImage.prototype = {
26871     get drawWidth() {
26872       return Math.max(this.width,
26873                       this.smask && this.smask.width || 0,
26874                       this.mask && this.mask.width || 0);
26875     },
26876
26877     get drawHeight() {
26878       return Math.max(this.height,
26879                       this.smask && this.smask.height || 0,
26880                       this.mask && this.mask.height || 0);
26881     },
26882
26883     decodeBuffer: function PDFImage_decodeBuffer(buffer) {
26884       var bpc = this.bpc;
26885       var numComps = this.numComps;
26886
26887       var decodeAddends = this.decodeAddends;
26888       var decodeCoefficients = this.decodeCoefficients;
26889       var max = (1 << bpc) - 1;
26890       var i, ii;
26891
26892       if (bpc === 1) {
26893         // If the buffer needed decode that means it just needs to be inverted.
26894         for (i = 0, ii = buffer.length; i < ii; i++) {
26895           buffer[i] = +!(buffer[i]);
26896         }
26897         return;
26898       }
26899       var index = 0;
26900       for (i = 0, ii = this.width * this.height; i < ii; i++) {
26901         for (var j = 0; j < numComps; j++) {
26902           buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j],
26903                                          decodeCoefficients[j], max);
26904           index++;
26905         }
26906       }
26907     },
26908
26909     getComponents: function PDFImage_getComponents(buffer) {
26910       var bpc = this.bpc;
26911
26912       // This image doesn't require any extra work.
26913       if (bpc === 8) {
26914         return buffer;
26915       }
26916
26917       var width = this.width;
26918       var height = this.height;
26919       var numComps = this.numComps;
26920
26921       var length = width * height * numComps;
26922       var bufferPos = 0;
26923       var output = (bpc <= 8 ? new Uint8Array(length) :
26924         (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
26925       var rowComps = width * numComps;
26926
26927       var max = (1 << bpc) - 1;
26928       var i = 0, ii, buf;
26929
26930       if (bpc === 1) {
26931         // Optimization for reading 1 bpc images.
26932         var mask, loop1End, loop2End;
26933         for (var j = 0; j < height; j++) {
26934           loop1End = i + (rowComps & ~7);
26935           loop2End = i + rowComps;
26936
26937           // unroll loop for all full bytes
26938           while (i < loop1End) {
26939             buf = buffer[bufferPos++];
26940             output[i] = (buf >> 7) & 1;
26941             output[i + 1] = (buf >> 6) & 1;
26942             output[i + 2] = (buf >> 5) & 1;
26943             output[i + 3] = (buf >> 4) & 1;
26944             output[i + 4] = (buf >> 3) & 1;
26945             output[i + 5] = (buf >> 2) & 1;
26946             output[i + 6] = (buf >> 1) & 1;
26947             output[i + 7] = buf & 1;
26948             i += 8;
26949           }
26950
26951           // handle remaing bits
26952           if (i < loop2End) {
26953             buf = buffer[bufferPos++];
26954             mask = 128;
26955             while (i < loop2End) {
26956               output[i++] = +!!(buf & mask);
26957               mask >>= 1;
26958             }
26959           }
26960         }
26961       } else {
26962         // The general case that handles all other bpc values.
26963         var bits = 0;
26964         buf = 0;
26965         for (i = 0, ii = length; i < ii; ++i) {
26966           if (i % rowComps === 0) {
26967             buf = 0;
26968             bits = 0;
26969           }
26970
26971           while (bits < bpc) {
26972             buf = (buf << 8) | buffer[bufferPos++];
26973             bits += 8;
26974           }
26975
26976           var remainingBits = bits - bpc;
26977           var value = buf >> remainingBits;
26978           output[i] = (value < 0 ? 0 : (value > max ? max : value));
26979           buf = buf & ((1 << remainingBits) - 1);
26980           bits = remainingBits;
26981         }
26982       }
26983       return output;
26984     },
26985
26986     fillOpacity: function PDFImage_fillOpacity(rgbaBuf, width, height,
26987                                                actualHeight, image) {
26988       var smask = this.smask;
26989       var mask = this.mask;
26990       var alphaBuf, sw, sh, i, ii, j;
26991
26992       if (smask) {
26993         sw = smask.width;
26994         sh = smask.height;
26995         alphaBuf = new Uint8Array(sw * sh);
26996         smask.fillGrayBuffer(alphaBuf);
26997         if (sw !== width || sh !== height) {
26998           alphaBuf = PDFImage.resize(alphaBuf, smask.bpc, 1, sw, sh, width,
26999                                      height);
27000         }
27001       } else if (mask) {
27002         if (mask instanceof PDFImage) {
27003           sw = mask.width;
27004           sh = mask.height;
27005           alphaBuf = new Uint8Array(sw * sh);
27006           mask.numComps = 1;
27007           mask.fillGrayBuffer(alphaBuf);
27008
27009           // Need to invert values in rgbaBuf
27010           for (i = 0, ii = sw * sh; i < ii; ++i) {
27011             alphaBuf[i] = 255 - alphaBuf[i];
27012           }
27013
27014           if (sw !== width || sh !== height) {
27015             alphaBuf = PDFImage.resize(alphaBuf, mask.bpc, 1, sw, sh, width,
27016                                        height);
27017           }
27018         } else if (isArray(mask)) {
27019           // Color key mask: if any of the compontents are outside the range
27020           // then they should be painted.
27021           alphaBuf = new Uint8Array(width * height);
27022           var numComps = this.numComps;
27023           for (i = 0, ii = width * height; i < ii; ++i) {
27024             var opacity = 0;
27025             var imageOffset = i * numComps;
27026             for (j = 0; j < numComps; ++j) {
27027               var color = image[imageOffset + j];
27028               var maskOffset = j * 2;
27029               if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
27030                 opacity = 255;
27031                 break;
27032               }
27033             }
27034             alphaBuf[i] = opacity;
27035           }
27036         } else {
27037           error('Unknown mask format.');
27038         }
27039       }
27040
27041       if (alphaBuf) {
27042         for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
27043           rgbaBuf[j] = alphaBuf[i];
27044         }
27045       } else {
27046         // No mask.
27047         for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
27048           rgbaBuf[j] = 255;
27049         }
27050       }
27051     },
27052
27053     undoPreblend: function PDFImage_undoPreblend(buffer, width, height) {
27054       var matte = this.smask && this.smask.matte;
27055       if (!matte) {
27056         return;
27057       }
27058       var matteRgb = this.colorSpace.getRgb(matte, 0);
27059       var matteR = matteRgb[0];
27060       var matteG = matteRgb[1];
27061       var matteB = matteRgb[2];
27062       var length = width * height * 4;
27063       var r, g, b;
27064       for (var i = 0; i < length; i += 4) {
27065         var alpha = buffer[i + 3];
27066         if (alpha === 0) {
27067           // according formula we have to get Infinity in all components
27068           // making it white (typical paper color) should be okay
27069           buffer[i] = 255;
27070           buffer[i + 1] = 255;
27071           buffer[i + 2] = 255;
27072           continue;
27073         }
27074         var k = 255 / alpha;
27075         r = (buffer[i] - matteR) * k + matteR;
27076         g = (buffer[i + 1] - matteG) * k + matteG;
27077         b = (buffer[i + 2] - matteB) * k + matteB;
27078         buffer[i] = r <= 0 ? 0 : r >= 255 ? 255 : r | 0;
27079         buffer[i + 1] = g <= 0 ? 0 : g >= 255 ? 255 : g | 0;
27080         buffer[i + 2] = b <= 0 ? 0 : b >= 255 ? 255 : b | 0;
27081       }
27082     },
27083
27084     createImageData: function PDFImage_createImageData(forceRGBA) {
27085       var drawWidth = this.drawWidth;
27086       var drawHeight = this.drawHeight;
27087       var imgData = { // other fields are filled in below
27088         width: drawWidth,
27089         height: drawHeight
27090       };
27091
27092       var numComps = this.numComps;
27093       var originalWidth = this.width;
27094       var originalHeight = this.height;
27095       var bpc = this.bpc;
27096
27097       // Rows start at byte boundary.
27098       var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
27099       var imgArray;
27100
27101       if (!forceRGBA) {
27102         // If it is a 1-bit-per-pixel grayscale (i.e. black-and-white) image
27103         // without any complications, we pass a same-sized copy to the main
27104         // thread rather than expanding by 32x to RGBA form. This saves *lots*
27105         // of memory for many scanned documents. It's also much faster.
27106         //
27107         // Similarly, if it is a 24-bit-per pixel RGB image without any
27108         // complications, we avoid expanding by 1.333x to RGBA form.
27109         var kind;
27110         if (this.colorSpace.name === 'DeviceGray' && bpc === 1) {
27111           kind = ImageKind.GRAYSCALE_1BPP;
27112         } else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8 &&
27113                    !this.needsDecode) {
27114           kind = ImageKind.RGB_24BPP;
27115         }
27116         if (kind && !this.smask && !this.mask &&
27117             drawWidth === originalWidth && drawHeight === originalHeight) {
27118           imgData.kind = kind;
27119
27120           imgArray = this.getImageBytes(originalHeight * rowBytes);
27121           // If imgArray came from a DecodeStream, we're safe to transfer it
27122           // (and thus neuter it) because it will constitute the entire
27123           // DecodeStream's data.  But if it came from a Stream, we need to
27124           // copy it because it'll only be a portion of the Stream's data, and
27125           // the rest will be read later on.
27126           if (this.image instanceof DecodeStream) {
27127             imgData.data = imgArray;
27128           } else {
27129             var newArray = new Uint8Array(imgArray.length);
27130             newArray.set(imgArray);
27131             imgData.data = newArray;
27132           }
27133           if (this.needsDecode) {
27134             // Invert the buffer (which must be grayscale if we reached here).
27135             assert(kind === ImageKind.GRAYSCALE_1BPP);
27136             var buffer = imgData.data;
27137             for (var i = 0, ii = buffer.length; i < ii; i++) {
27138               buffer[i] ^= 0xff;
27139             }
27140           }
27141           return imgData;
27142         }
27143         if (this.image instanceof JpegStream && !this.smask && !this.mask) {
27144           imgData.kind = ImageKind.RGB_24BPP;
27145           imgData.data = this.getImageBytes(originalHeight * rowBytes,
27146                                             drawWidth, drawHeight, true);
27147           return imgData;
27148         }
27149       }
27150
27151       imgArray = this.getImageBytes(originalHeight * rowBytes);
27152       // imgArray can be incomplete (e.g. after CCITT fax encoding).
27153       var actualHeight = 0 | (imgArray.length / rowBytes *
27154                          drawHeight / originalHeight);
27155
27156       var comps = this.getComponents(imgArray);
27157
27158       // If opacity data is present, use RGBA_32BPP form. Otherwise, use the
27159       // more compact RGB_24BPP form if allowable.
27160       var alpha01, maybeUndoPreblend;
27161       if (!forceRGBA && !this.smask && !this.mask) {
27162         imgData.kind = ImageKind.RGB_24BPP;
27163         imgData.data = new Uint8Array(drawWidth * drawHeight * 3);
27164         alpha01 = 0;
27165         maybeUndoPreblend = false;
27166       } else {
27167         imgData.kind = ImageKind.RGBA_32BPP;
27168         imgData.data = new Uint8Array(drawWidth * drawHeight * 4);
27169         alpha01 = 1;
27170         maybeUndoPreblend = true;
27171
27172         // Color key masking (opacity) must be performed before decoding.
27173         this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight,
27174                          comps);
27175       }
27176
27177       if (this.needsDecode) {
27178         this.decodeBuffer(comps);
27179       }
27180       this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight,
27181                               drawWidth, drawHeight, actualHeight, bpc, comps,
27182                               alpha01);
27183       if (maybeUndoPreblend) {
27184         this.undoPreblend(imgData.data, drawWidth, actualHeight);
27185       }
27186
27187       return imgData;
27188     },
27189
27190     fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {
27191       var numComps = this.numComps;
27192       if (numComps !== 1) {
27193         error('Reading gray scale from a color image: ' + numComps);
27194       }
27195
27196       var width = this.width;
27197       var height = this.height;
27198       var bpc = this.bpc;
27199
27200       // rows start at byte boundary
27201       var rowBytes = (width * numComps * bpc + 7) >> 3;
27202       var imgArray = this.getImageBytes(height * rowBytes);
27203
27204       var comps = this.getComponents(imgArray);
27205       var i, length;
27206
27207       if (bpc === 1) {
27208         // inline decoding (= inversion) for 1 bpc images
27209         length = width * height;
27210         if (this.needsDecode) {
27211           // invert and scale to {0, 255}
27212           for (i = 0; i < length; ++i) {
27213             buffer[i] = (comps[i] - 1) & 255;
27214           }
27215         } else {
27216           // scale to {0, 255}
27217           for (i = 0; i < length; ++i) {
27218             buffer[i] = (-comps[i]) & 255;
27219           }
27220         }
27221         return;
27222       }
27223
27224       if (this.needsDecode) {
27225         this.decodeBuffer(comps);
27226       }
27227       length = width * height;
27228       // we aren't using a colorspace so we need to scale the value
27229       var scale = 255 / ((1 << bpc) - 1);
27230       for (i = 0; i < length; ++i) {
27231         buffer[i] = (scale * comps[i]) | 0;
27232       }
27233     },
27234
27235     getImageBytes: function PDFImage_getImageBytes(length,
27236                                                    drawWidth, drawHeight,
27237                                                    forceRGB) {
27238       this.image.reset();
27239       this.image.drawWidth = drawWidth || this.width;
27240       this.image.drawHeight = drawHeight || this.height;
27241       this.image.forceRGB = !!forceRGB;
27242       return this.image.getBytes(length);
27243     }
27244   };
27245   return PDFImage;
27246 })();
27247
27248
27249 // The Metrics object contains glyph widths (in glyph space units).
27250 // As per PDF spec, for most fonts (Type 3 being an exception) a glyph
27251 // space unit corresponds to 1/1000th of text space unit.
27252 var Metrics = {
27253   'Courier': 600,
27254   'Courier-Bold': 600,
27255   'Courier-BoldOblique': 600,
27256   'Courier-Oblique': 600,
27257   'Helvetica' : {
27258     'space': 278,
27259     'exclam': 278,
27260     'quotedbl': 355,
27261     'numbersign': 556,
27262     'dollar': 556,
27263     'percent': 889,
27264     'ampersand': 667,
27265     'quoteright': 222,
27266     'parenleft': 333,
27267     'parenright': 333,
27268     'asterisk': 389,
27269     'plus': 584,
27270     'comma': 278,
27271     'hyphen': 333,
27272     'period': 278,
27273     'slash': 278,
27274     'zero': 556,
27275     'one': 556,
27276     'two': 556,
27277     'three': 556,
27278     'four': 556,
27279     'five': 556,
27280     'six': 556,
27281     'seven': 556,
27282     'eight': 556,
27283     'nine': 556,
27284     'colon': 278,
27285     'semicolon': 278,
27286     'less': 584,
27287     'equal': 584,
27288     'greater': 584,
27289     'question': 556,
27290     'at': 1015,
27291     'A': 667,
27292     'B': 667,
27293     'C': 722,
27294     'D': 722,
27295     'E': 667,
27296     'F': 611,
27297     'G': 778,
27298     'H': 722,
27299     'I': 278,
27300     'J': 500,
27301     'K': 667,
27302     'L': 556,
27303     'M': 833,
27304     'N': 722,
27305     'O': 778,
27306     'P': 667,
27307     'Q': 778,
27308     'R': 722,
27309     'S': 667,
27310     'T': 611,
27311     'U': 722,
27312     'V': 667,
27313     'W': 944,
27314     'X': 667,
27315     'Y': 667,
27316     'Z': 611,
27317     'bracketleft': 278,
27318     'backslash': 278,
27319     'bracketright': 278,
27320     'asciicircum': 469,
27321     'underscore': 556,
27322     'quoteleft': 222,
27323     'a': 556,
27324     'b': 556,
27325     'c': 500,
27326     'd': 556,
27327     'e': 556,
27328     'f': 278,
27329     'g': 556,
27330     'h': 556,
27331     'i': 222,
27332     'j': 222,
27333     'k': 500,
27334     'l': 222,
27335     'm': 833,
27336     'n': 556,
27337     'o': 556,
27338     'p': 556,
27339     'q': 556,
27340     'r': 333,
27341     's': 500,
27342     't': 278,
27343     'u': 556,
27344     'v': 500,
27345     'w': 722,
27346     'x': 500,
27347     'y': 500,
27348     'z': 500,
27349     'braceleft': 334,
27350     'bar': 260,
27351     'braceright': 334,
27352     'asciitilde': 584,
27353     'exclamdown': 333,
27354     'cent': 556,
27355     'sterling': 556,
27356     'fraction': 167,
27357     'yen': 556,
27358     'florin': 556,
27359     'section': 556,
27360     'currency': 556,
27361     'quotesingle': 191,
27362     'quotedblleft': 333,
27363     'guillemotleft': 556,
27364     'guilsinglleft': 333,
27365     'guilsinglright': 333,
27366     'fi': 500,
27367     'fl': 500,
27368     'endash': 556,
27369     'dagger': 556,
27370     'daggerdbl': 556,
27371     'periodcentered': 278,
27372     'paragraph': 537,
27373     'bullet': 350,
27374     'quotesinglbase': 222,
27375     'quotedblbase': 333,
27376     'quotedblright': 333,
27377     'guillemotright': 556,
27378     'ellipsis': 1000,
27379     'perthousand': 1000,
27380     'questiondown': 611,
27381     'grave': 333,
27382     'acute': 333,
27383     'circumflex': 333,
27384     'tilde': 333,
27385     'macron': 333,
27386     'breve': 333,
27387     'dotaccent': 333,
27388     'dieresis': 333,
27389     'ring': 333,
27390     'cedilla': 333,
27391     'hungarumlaut': 333,
27392     'ogonek': 333,
27393     'caron': 333,
27394     'emdash': 1000,
27395     'AE': 1000,
27396     'ordfeminine': 370,
27397     'Lslash': 556,
27398     'Oslash': 778,
27399     'OE': 1000,
27400     'ordmasculine': 365,
27401     'ae': 889,
27402     'dotlessi': 278,
27403     'lslash': 222,
27404     'oslash': 611,
27405     'oe': 944,
27406     'germandbls': 611,
27407     'Idieresis': 278,
27408     'eacute': 556,
27409     'abreve': 556,
27410     'uhungarumlaut': 556,
27411     'ecaron': 556,
27412     'Ydieresis': 667,
27413     'divide': 584,
27414     'Yacute': 667,
27415     'Acircumflex': 667,
27416     'aacute': 556,
27417     'Ucircumflex': 722,
27418     'yacute': 500,
27419     'scommaaccent': 500,
27420     'ecircumflex': 556,
27421     'Uring': 722,
27422     'Udieresis': 722,
27423     'aogonek': 556,
27424     'Uacute': 722,
27425     'uogonek': 556,
27426     'Edieresis': 667,
27427     'Dcroat': 722,
27428     'commaaccent': 250,
27429     'copyright': 737,
27430     'Emacron': 667,
27431     'ccaron': 500,
27432     'aring': 556,
27433     'Ncommaaccent': 722,
27434     'lacute': 222,
27435     'agrave': 556,
27436     'Tcommaaccent': 611,
27437     'Cacute': 722,
27438     'atilde': 556,
27439     'Edotaccent': 667,
27440     'scaron': 500,
27441     'scedilla': 500,
27442     'iacute': 278,
27443     'lozenge': 471,
27444     'Rcaron': 722,
27445     'Gcommaaccent': 778,
27446     'ucircumflex': 556,
27447     'acircumflex': 556,
27448     'Amacron': 667,
27449     'rcaron': 333,
27450     'ccedilla': 500,
27451     'Zdotaccent': 611,
27452     'Thorn': 667,
27453     'Omacron': 778,
27454     'Racute': 722,
27455     'Sacute': 667,
27456     'dcaron': 643,
27457     'Umacron': 722,
27458     'uring': 556,
27459     'threesuperior': 333,
27460     'Ograve': 778,
27461     'Agrave': 667,
27462     'Abreve': 667,
27463     'multiply': 584,
27464     'uacute': 556,
27465     'Tcaron': 611,
27466     'partialdiff': 476,
27467     'ydieresis': 500,
27468     'Nacute': 722,
27469     'icircumflex': 278,
27470     'Ecircumflex': 667,
27471     'adieresis': 556,
27472     'edieresis': 556,
27473     'cacute': 500,
27474     'nacute': 556,
27475     'umacron': 556,
27476     'Ncaron': 722,
27477     'Iacute': 278,
27478     'plusminus': 584,
27479     'brokenbar': 260,
27480     'registered': 737,
27481     'Gbreve': 778,
27482     'Idotaccent': 278,
27483     'summation': 600,
27484     'Egrave': 667,
27485     'racute': 333,
27486     'omacron': 556,
27487     'Zacute': 611,
27488     'Zcaron': 611,
27489     'greaterequal': 549,
27490     'Eth': 722,
27491     'Ccedilla': 722,
27492     'lcommaaccent': 222,
27493     'tcaron': 317,
27494     'eogonek': 556,
27495     'Uogonek': 722,
27496     'Aacute': 667,
27497     'Adieresis': 667,
27498     'egrave': 556,
27499     'zacute': 500,
27500     'iogonek': 222,
27501     'Oacute': 778,
27502     'oacute': 556,
27503     'amacron': 556,
27504     'sacute': 500,
27505     'idieresis': 278,
27506     'Ocircumflex': 778,
27507     'Ugrave': 722,
27508     'Delta': 612,
27509     'thorn': 556,
27510     'twosuperior': 333,
27511     'Odieresis': 778,
27512     'mu': 556,
27513     'igrave': 278,
27514     'ohungarumlaut': 556,
27515     'Eogonek': 667,
27516     'dcroat': 556,
27517     'threequarters': 834,
27518     'Scedilla': 667,
27519     'lcaron': 299,
27520     'Kcommaaccent': 667,
27521     'Lacute': 556,
27522     'trademark': 1000,
27523     'edotaccent': 556,
27524     'Igrave': 278,
27525     'Imacron': 278,
27526     'Lcaron': 556,
27527     'onehalf': 834,
27528     'lessequal': 549,
27529     'ocircumflex': 556,
27530     'ntilde': 556,
27531     'Uhungarumlaut': 722,
27532     'Eacute': 667,
27533     'emacron': 556,
27534     'gbreve': 556,
27535     'onequarter': 834,
27536     'Scaron': 667,
27537     'Scommaaccent': 667,
27538     'Ohungarumlaut': 778,
27539     'degree': 400,
27540     'ograve': 556,
27541     'Ccaron': 722,
27542     'ugrave': 556,
27543     'radical': 453,
27544     'Dcaron': 722,
27545     'rcommaaccent': 333,
27546     'Ntilde': 722,
27547     'otilde': 556,
27548     'Rcommaaccent': 722,
27549     'Lcommaaccent': 556,
27550     'Atilde': 667,
27551     'Aogonek': 667,
27552     'Aring': 667,
27553     'Otilde': 778,
27554     'zdotaccent': 500,
27555     'Ecaron': 667,
27556     'Iogonek': 278,
27557     'kcommaaccent': 500,
27558     'minus': 584,
27559     'Icircumflex': 278,
27560     'ncaron': 556,
27561     'tcommaaccent': 278,
27562     'logicalnot': 584,
27563     'odieresis': 556,
27564     'udieresis': 556,
27565     'notequal': 549,
27566     'gcommaaccent': 556,
27567     'eth': 556,
27568     'zcaron': 500,
27569     'ncommaaccent': 556,
27570     'onesuperior': 333,
27571     'imacron': 278,
27572     'Euro': 556
27573   },
27574   'Helvetica-Bold': {
27575     'space': 278,
27576     'exclam': 333,
27577     'quotedbl': 474,
27578     'numbersign': 556,
27579     'dollar': 556,
27580     'percent': 889,
27581     'ampersand': 722,
27582     'quoteright': 278,
27583     'parenleft': 333,
27584     'parenright': 333,
27585     'asterisk': 389,
27586     'plus': 584,
27587     'comma': 278,
27588     'hyphen': 333,
27589     'period': 278,
27590     'slash': 278,
27591     'zero': 556,
27592     'one': 556,
27593     'two': 556,
27594     'three': 556,
27595     'four': 556,
27596     'five': 556,
27597     'six': 556,
27598     'seven': 556,
27599     'eight': 556,
27600     'nine': 556,
27601     'colon': 333,
27602     'semicolon': 333,
27603     'less': 584,
27604     'equal': 584,
27605     'greater': 584,
27606     'question': 611,
27607     'at': 975,
27608     'A': 722,
27609     'B': 722,
27610     'C': 722,
27611     'D': 722,
27612     'E': 667,
27613     'F': 611,
27614     'G': 778,
27615     'H': 722,
27616     'I': 278,
27617     'J': 556,
27618     'K': 722,
27619     'L': 611,
27620     'M': 833,
27621     'N': 722,
27622     'O': 778,
27623     'P': 667,
27624     'Q': 778,
27625     'R': 722,
27626     'S': 667,
27627     'T': 611,
27628     'U': 722,
27629     'V': 667,
27630     'W': 944,
27631     'X': 667,
27632     'Y': 667,
27633     'Z': 611,
27634     'bracketleft': 333,
27635     'backslash': 278,
27636     'bracketright': 333,
27637     'asciicircum': 584,
27638     'underscore': 556,
27639     'quoteleft': 278,
27640     'a': 556,
27641     'b': 611,
27642     'c': 556,
27643     'd': 611,
27644     'e': 556,
27645     'f': 333,
27646     'g': 611,
27647     'h': 611,
27648     'i': 278,
27649     'j': 278,
27650     'k': 556,
27651     'l': 278,
27652     'm': 889,
27653     'n': 611,
27654     'o': 611,
27655     'p': 611,
27656     'q': 611,
27657     'r': 389,
27658     's': 556,
27659     't': 333,
27660     'u': 611,
27661     'v': 556,
27662     'w': 778,
27663     'x': 556,
27664     'y': 556,
27665     'z': 500,
27666     'braceleft': 389,
27667     'bar': 280,
27668     'braceright': 389,
27669     'asciitilde': 584,
27670     'exclamdown': 333,
27671     'cent': 556,
27672     'sterling': 556,
27673     'fraction': 167,
27674     'yen': 556,
27675     'florin': 556,
27676     'section': 556,
27677     'currency': 556,
27678     'quotesingle': 238,
27679     'quotedblleft': 500,
27680     'guillemotleft': 556,
27681     'guilsinglleft': 333,
27682     'guilsinglright': 333,
27683     'fi': 611,
27684     'fl': 611,
27685     'endash': 556,
27686     'dagger': 556,
27687     'daggerdbl': 556,
27688     'periodcentered': 278,
27689     'paragraph': 556,
27690     'bullet': 350,
27691     'quotesinglbase': 278,
27692     'quotedblbase': 500,
27693     'quotedblright': 500,
27694     'guillemotright': 556,
27695     'ellipsis': 1000,
27696     'perthousand': 1000,
27697     'questiondown': 611,
27698     'grave': 333,
27699     'acute': 333,
27700     'circumflex': 333,
27701     'tilde': 333,
27702     'macron': 333,
27703     'breve': 333,
27704     'dotaccent': 333,
27705     'dieresis': 333,
27706     'ring': 333,
27707     'cedilla': 333,
27708     'hungarumlaut': 333,
27709     'ogonek': 333,
27710     'caron': 333,
27711     'emdash': 1000,
27712     'AE': 1000,
27713     'ordfeminine': 370,
27714     'Lslash': 611,
27715     'Oslash': 778,
27716     'OE': 1000,
27717     'ordmasculine': 365,
27718     'ae': 889,
27719     'dotlessi': 278,
27720     'lslash': 278,
27721     'oslash': 611,
27722     'oe': 944,
27723     'germandbls': 611,
27724     'Idieresis': 278,
27725     'eacute': 556,
27726     'abreve': 556,
27727     'uhungarumlaut': 611,
27728     'ecaron': 556,
27729     'Ydieresis': 667,
27730     'divide': 584,
27731     'Yacute': 667,
27732     'Acircumflex': 722,
27733     'aacute': 556,
27734     'Ucircumflex': 722,
27735     'yacute': 556,
27736     'scommaaccent': 556,
27737     'ecircumflex': 556,
27738     'Uring': 722,
27739     'Udieresis': 722,
27740     'aogonek': 556,
27741     'Uacute': 722,
27742     'uogonek': 611,
27743     'Edieresis': 667,
27744     'Dcroat': 722,
27745     'commaaccent': 250,
27746     'copyright': 737,
27747     'Emacron': 667,
27748     'ccaron': 556,
27749     'aring': 556,
27750     'Ncommaaccent': 722,
27751     'lacute': 278,
27752     'agrave': 556,
27753     'Tcommaaccent': 611,
27754     'Cacute': 722,
27755     'atilde': 556,
27756     'Edotaccent': 667,
27757     'scaron': 556,
27758     'scedilla': 556,
27759     'iacute': 278,
27760     'lozenge': 494,
27761     'Rcaron': 722,
27762     'Gcommaaccent': 778,
27763     'ucircumflex': 611,
27764     'acircumflex': 556,
27765     'Amacron': 722,
27766     'rcaron': 389,
27767     'ccedilla': 556,
27768     'Zdotaccent': 611,
27769     'Thorn': 667,
27770     'Omacron': 778,
27771     'Racute': 722,
27772     'Sacute': 667,
27773     'dcaron': 743,
27774     'Umacron': 722,
27775     'uring': 611,
27776     'threesuperior': 333,
27777     'Ograve': 778,
27778     'Agrave': 722,
27779     'Abreve': 722,
27780     'multiply': 584,
27781     'uacute': 611,
27782     'Tcaron': 611,
27783     'partialdiff': 494,
27784     'ydieresis': 556,
27785     'Nacute': 722,
27786     'icircumflex': 278,
27787     'Ecircumflex': 667,
27788     'adieresis': 556,
27789     'edieresis': 556,
27790     'cacute': 556,
27791     'nacute': 611,
27792     'umacron': 611,
27793     'Ncaron': 722,
27794     'Iacute': 278,
27795     'plusminus': 584,
27796     'brokenbar': 280,
27797     'registered': 737,
27798     'Gbreve': 778,
27799     'Idotaccent': 278,
27800     'summation': 600,
27801     'Egrave': 667,
27802     'racute': 389,
27803     'omacron': 611,
27804     'Zacute': 611,
27805     'Zcaron': 611,
27806     'greaterequal': 549,
27807     'Eth': 722,
27808     'Ccedilla': 722,
27809     'lcommaaccent': 278,
27810     'tcaron': 389,
27811     'eogonek': 556,
27812     'Uogonek': 722,
27813     'Aacute': 722,
27814     'Adieresis': 722,
27815     'egrave': 556,
27816     'zacute': 500,
27817     'iogonek': 278,
27818     'Oacute': 778,
27819     'oacute': 611,
27820     'amacron': 556,
27821     'sacute': 556,
27822     'idieresis': 278,
27823     'Ocircumflex': 778,
27824     'Ugrave': 722,
27825     'Delta': 612,
27826     'thorn': 611,
27827     'twosuperior': 333,
27828     'Odieresis': 778,
27829     'mu': 611,
27830     'igrave': 278,
27831     'ohungarumlaut': 611,
27832     'Eogonek': 667,
27833     'dcroat': 611,
27834     'threequarters': 834,
27835     'Scedilla': 667,
27836     'lcaron': 400,
27837     'Kcommaaccent': 722,
27838     'Lacute': 611,
27839     'trademark': 1000,
27840     'edotaccent': 556,
27841     'Igrave': 278,
27842     'Imacron': 278,
27843     'Lcaron': 611,
27844     'onehalf': 834,
27845     'lessequal': 549,
27846     'ocircumflex': 611,
27847     'ntilde': 611,
27848     'Uhungarumlaut': 722,
27849     'Eacute': 667,
27850     'emacron': 556,
27851     'gbreve': 611,
27852     'onequarter': 834,
27853     'Scaron': 667,
27854     'Scommaaccent': 667,
27855     'Ohungarumlaut': 778,
27856     'degree': 400,
27857     'ograve': 611,
27858     'Ccaron': 722,
27859     'ugrave': 611,
27860     'radical': 549,
27861     'Dcaron': 722,
27862     'rcommaaccent': 389,
27863     'Ntilde': 722,
27864     'otilde': 611,
27865     'Rcommaaccent': 722,
27866     'Lcommaaccent': 611,
27867     'Atilde': 722,
27868     'Aogonek': 722,
27869     'Aring': 722,
27870     'Otilde': 778,
27871     'zdotaccent': 500,
27872     'Ecaron': 667,
27873     'Iogonek': 278,
27874     'kcommaaccent': 556,
27875     'minus': 584,
27876     'Icircumflex': 278,
27877     'ncaron': 611,
27878     'tcommaaccent': 333,
27879     'logicalnot': 584,
27880     'odieresis': 611,
27881     'udieresis': 611,
27882     'notequal': 549,
27883     'gcommaaccent': 611,
27884     'eth': 611,
27885     'zcaron': 500,
27886     'ncommaaccent': 611,
27887     'onesuperior': 333,
27888     'imacron': 278,
27889     'Euro': 556
27890   },
27891   'Helvetica-BoldOblique': {
27892     'space': 278,
27893     'exclam': 333,
27894     'quotedbl': 474,
27895     'numbersign': 556,
27896     'dollar': 556,
27897     'percent': 889,
27898     'ampersand': 722,
27899     'quoteright': 278,
27900     'parenleft': 333,
27901     'parenright': 333,
27902     'asterisk': 389,
27903     'plus': 584,
27904     'comma': 278,
27905     'hyphen': 333,
27906     'period': 278,
27907     'slash': 278,
27908     'zero': 556,
27909     'one': 556,
27910     'two': 556,
27911     'three': 556,
27912     'four': 556,
27913     'five': 556,
27914     'six': 556,
27915     'seven': 556,
27916     'eight': 556,
27917     'nine': 556,
27918     'colon': 333,
27919     'semicolon': 333,
27920     'less': 584,
27921     'equal': 584,
27922     'greater': 584,
27923     'question': 611,
27924     'at': 975,
27925     'A': 722,
27926     'B': 722,
27927     'C': 722,
27928     'D': 722,
27929     'E': 667,
27930     'F': 611,
27931     'G': 778,
27932     'H': 722,
27933     'I': 278,
27934     'J': 556,
27935     'K': 722,
27936     'L': 611,
27937     'M': 833,
27938     'N': 722,
27939     'O': 778,
27940     'P': 667,
27941     'Q': 778,
27942     'R': 722,
27943     'S': 667,
27944     'T': 611,
27945     'U': 722,
27946     'V': 667,
27947     'W': 944,
27948     'X': 667,
27949     'Y': 667,
27950     'Z': 611,
27951     'bracketleft': 333,
27952     'backslash': 278,
27953     'bracketright': 333,
27954     'asciicircum': 584,
27955     'underscore': 556,
27956     'quoteleft': 278,
27957     'a': 556,
27958     'b': 611,
27959     'c': 556,
27960     'd': 611,
27961     'e': 556,
27962     'f': 333,
27963     'g': 611,
27964     'h': 611,
27965     'i': 278,
27966     'j': 278,
27967     'k': 556,
27968     'l': 278,
27969     'm': 889,
27970     'n': 611,
27971     'o': 611,
27972     'p': 611,
27973     'q': 611,
27974     'r': 389,
27975     's': 556,
27976     't': 333,
27977     'u': 611,
27978     'v': 556,
27979     'w': 778,
27980     'x': 556,
27981     'y': 556,
27982     'z': 500,
27983     'braceleft': 389,
27984     'bar': 280,
27985     'braceright': 389,
27986     'asciitilde': 584,
27987     'exclamdown': 333,
27988     'cent': 556,
27989     'sterling': 556,
27990     'fraction': 167,
27991     'yen': 556,
27992     'florin': 556,
27993     'section': 556,
27994     'currency': 556,
27995     'quotesingle': 238,
27996     'quotedblleft': 500,
27997     'guillemotleft': 556,
27998     'guilsinglleft': 333,
27999     'guilsinglright': 333,
28000     'fi': 611,
28001     'fl': 611,
28002     'endash': 556,
28003     'dagger': 556,
28004     'daggerdbl': 556,
28005     'periodcentered': 278,
28006     'paragraph': 556,
28007     'bullet': 350,
28008     'quotesinglbase': 278,
28009     'quotedblbase': 500,
28010     'quotedblright': 500,
28011     'guillemotright': 556,
28012     'ellipsis': 1000,
28013     'perthousand': 1000,
28014     'questiondown': 611,
28015     'grave': 333,
28016     'acute': 333,
28017     'circumflex': 333,
28018     'tilde': 333,
28019     'macron': 333,
28020     'breve': 333,
28021     'dotaccent': 333,
28022     'dieresis': 333,
28023     'ring': 333,
28024     'cedilla': 333,
28025     'hungarumlaut': 333,
28026     'ogonek': 333,
28027     'caron': 333,
28028     'emdash': 1000,
28029     'AE': 1000,
28030     'ordfeminine': 370,
28031     'Lslash': 611,
28032     'Oslash': 778,
28033     'OE': 1000,
28034     'ordmasculine': 365,
28035     'ae': 889,
28036     'dotlessi': 278,
28037     'lslash': 278,
28038     'oslash': 611,
28039     'oe': 944,
28040     'germandbls': 611,
28041     'Idieresis': 278,
28042     'eacute': 556,
28043     'abreve': 556,
28044     'uhungarumlaut': 611,
28045     'ecaron': 556,
28046     'Ydieresis': 667,
28047     'divide': 584,
28048     'Yacute': 667,
28049     'Acircumflex': 722,
28050     'aacute': 556,
28051     'Ucircumflex': 722,
28052     'yacute': 556,
28053     'scommaaccent': 556,
28054     'ecircumflex': 556,
28055     'Uring': 722,
28056     'Udieresis': 722,
28057     'aogonek': 556,
28058     'Uacute': 722,
28059     'uogonek': 611,
28060     'Edieresis': 667,
28061     'Dcroat': 722,
28062     'commaaccent': 250,
28063     'copyright': 737,
28064     'Emacron': 667,
28065     'ccaron': 556,
28066     'aring': 556,
28067     'Ncommaaccent': 722,
28068     'lacute': 278,
28069     'agrave': 556,
28070     'Tcommaaccent': 611,
28071     'Cacute': 722,
28072     'atilde': 556,
28073     'Edotaccent': 667,
28074     'scaron': 556,
28075     'scedilla': 556,
28076     'iacute': 278,
28077     'lozenge': 494,
28078     'Rcaron': 722,
28079     'Gcommaaccent': 778,
28080     'ucircumflex': 611,
28081     'acircumflex': 556,
28082     'Amacron': 722,
28083     'rcaron': 389,
28084     'ccedilla': 556,
28085     'Zdotaccent': 611,
28086     'Thorn': 667,
28087     'Omacron': 778,
28088     'Racute': 722,
28089     'Sacute': 667,
28090     'dcaron': 743,
28091     'Umacron': 722,
28092     'uring': 611,
28093     'threesuperior': 333,
28094     'Ograve': 778,
28095     'Agrave': 722,
28096     'Abreve': 722,
28097     'multiply': 584,
28098     'uacute': 611,
28099     'Tcaron': 611,
28100     'partialdiff': 494,
28101     'ydieresis': 556,
28102     'Nacute': 722,
28103     'icircumflex': 278,
28104     'Ecircumflex': 667,
28105     'adieresis': 556,
28106     'edieresis': 556,
28107     'cacute': 556,
28108     'nacute': 611,
28109     'umacron': 611,
28110     'Ncaron': 722,
28111     'Iacute': 278,
28112     'plusminus': 584,
28113     'brokenbar': 280,
28114     'registered': 737,
28115     'Gbreve': 778,
28116     'Idotaccent': 278,
28117     'summation': 600,
28118     'Egrave': 667,
28119     'racute': 389,
28120     'omacron': 611,
28121     'Zacute': 611,
28122     'Zcaron': 611,
28123     'greaterequal': 549,
28124     'Eth': 722,
28125     'Ccedilla': 722,
28126     'lcommaaccent': 278,
28127     'tcaron': 389,
28128     'eogonek': 556,
28129     'Uogonek': 722,
28130     'Aacute': 722,
28131     'Adieresis': 722,
28132     'egrave': 556,
28133     'zacute': 500,
28134     'iogonek': 278,
28135     'Oacute': 778,
28136     'oacute': 611,
28137     'amacron': 556,
28138     'sacute': 556,
28139     'idieresis': 278,
28140     'Ocircumflex': 778,
28141     'Ugrave': 722,
28142     'Delta': 612,
28143     'thorn': 611,
28144     'twosuperior': 333,
28145     'Odieresis': 778,
28146     'mu': 611,
28147     'igrave': 278,
28148     'ohungarumlaut': 611,
28149     'Eogonek': 667,
28150     'dcroat': 611,
28151     'threequarters': 834,
28152     'Scedilla': 667,
28153     'lcaron': 400,
28154     'Kcommaaccent': 722,
28155     'Lacute': 611,
28156     'trademark': 1000,
28157     'edotaccent': 556,
28158     'Igrave': 278,
28159     'Imacron': 278,
28160     'Lcaron': 611,
28161     'onehalf': 834,
28162     'lessequal': 549,
28163     'ocircumflex': 611,
28164     'ntilde': 611,
28165     'Uhungarumlaut': 722,
28166     'Eacute': 667,
28167     'emacron': 556,
28168     'gbreve': 611,
28169     'onequarter': 834,
28170     'Scaron': 667,
28171     'Scommaaccent': 667,
28172     'Ohungarumlaut': 778,
28173     'degree': 400,
28174     'ograve': 611,
28175     'Ccaron': 722,
28176     'ugrave': 611,
28177     'radical': 549,
28178     'Dcaron': 722,
28179     'rcommaaccent': 389,
28180     'Ntilde': 722,
28181     'otilde': 611,
28182     'Rcommaaccent': 722,
28183     'Lcommaaccent': 611,
28184     'Atilde': 722,
28185     'Aogonek': 722,
28186     'Aring': 722,
28187     'Otilde': 778,
28188     'zdotaccent': 500,
28189     'Ecaron': 667,
28190     'Iogonek': 278,
28191     'kcommaaccent': 556,
28192     'minus': 584,
28193     'Icircumflex': 278,
28194     'ncaron': 611,
28195     'tcommaaccent': 333,
28196     'logicalnot': 584,
28197     'odieresis': 611,
28198     'udieresis': 611,
28199     'notequal': 549,
28200     'gcommaaccent': 611,
28201     'eth': 611,
28202     'zcaron': 500,
28203     'ncommaaccent': 611,
28204     'onesuperior': 333,
28205     'imacron': 278,
28206     'Euro': 556
28207   },
28208   'Helvetica-Oblique' : {
28209     'space': 278,
28210     'exclam': 278,
28211     'quotedbl': 355,
28212     'numbersign': 556,
28213     'dollar': 556,
28214     'percent': 889,
28215     'ampersand': 667,
28216     'quoteright': 222,
28217     'parenleft': 333,
28218     'parenright': 333,
28219     'asterisk': 389,
28220     'plus': 584,
28221     'comma': 278,
28222     'hyphen': 333,
28223     'period': 278,
28224     'slash': 278,
28225     'zero': 556,
28226     'one': 556,
28227     'two': 556,
28228     'three': 556,
28229     'four': 556,
28230     'five': 556,
28231     'six': 556,
28232     'seven': 556,
28233     'eight': 556,
28234     'nine': 556,
28235     'colon': 278,
28236     'semicolon': 278,
28237     'less': 584,
28238     'equal': 584,
28239     'greater': 584,
28240     'question': 556,
28241     'at': 1015,
28242     'A': 667,
28243     'B': 667,
28244     'C': 722,
28245     'D': 722,
28246     'E': 667,
28247     'F': 611,
28248     'G': 778,
28249     'H': 722,
28250     'I': 278,
28251     'J': 500,
28252     'K': 667,
28253     'L': 556,
28254     'M': 833,
28255     'N': 722,
28256     'O': 778,
28257     'P': 667,
28258     'Q': 778,
28259     'R': 722,
28260     'S': 667,
28261     'T': 611,
28262     'U': 722,
28263     'V': 667,
28264     'W': 944,
28265     'X': 667,
28266     'Y': 667,
28267     'Z': 611,
28268     'bracketleft': 278,
28269     'backslash': 278,
28270     'bracketright': 278,
28271     'asciicircum': 469,
28272     'underscore': 556,
28273     'quoteleft': 222,
28274     'a': 556,
28275     'b': 556,
28276     'c': 500,
28277     'd': 556,
28278     'e': 556,
28279     'f': 278,
28280     'g': 556,
28281     'h': 556,
28282     'i': 222,
28283     'j': 222,
28284     'k': 500,
28285     'l': 222,
28286     'm': 833,
28287     'n': 556,
28288     'o': 556,
28289     'p': 556,
28290     'q': 556,
28291     'r': 333,
28292     's': 500,
28293     't': 278,
28294     'u': 556,
28295     'v': 500,
28296     'w': 722,
28297     'x': 500,
28298     'y': 500,
28299     'z': 500,
28300     'braceleft': 334,
28301     'bar': 260,
28302     'braceright': 334,
28303     'asciitilde': 584,
28304     'exclamdown': 333,
28305     'cent': 556,
28306     'sterling': 556,
28307     'fraction': 167,
28308     'yen': 556,
28309     'florin': 556,
28310     'section': 556,
28311     'currency': 556,
28312     'quotesingle': 191,
28313     'quotedblleft': 333,
28314     'guillemotleft': 556,
28315     'guilsinglleft': 333,
28316     'guilsinglright': 333,
28317     'fi': 500,
28318     'fl': 500,
28319     'endash': 556,
28320     'dagger': 556,
28321     'daggerdbl': 556,
28322     'periodcentered': 278,
28323     'paragraph': 537,
28324     'bullet': 350,
28325     'quotesinglbase': 222,
28326     'quotedblbase': 333,
28327     'quotedblright': 333,
28328     'guillemotright': 556,
28329     'ellipsis': 1000,
28330     'perthousand': 1000,
28331     'questiondown': 611,
28332     'grave': 333,
28333     'acute': 333,
28334     'circumflex': 333,
28335     'tilde': 333,
28336     'macron': 333,
28337     'breve': 333,
28338     'dotaccent': 333,
28339     'dieresis': 333,
28340     'ring': 333,
28341     'cedilla': 333,
28342     'hungarumlaut': 333,
28343     'ogonek': 333,
28344     'caron': 333,
28345     'emdash': 1000,
28346     'AE': 1000,
28347     'ordfeminine': 370,
28348     'Lslash': 556,
28349     'Oslash': 778,
28350     'OE': 1000,
28351     'ordmasculine': 365,
28352     'ae': 889,
28353     'dotlessi': 278,
28354     'lslash': 222,
28355     'oslash': 611,
28356     'oe': 944,
28357     'germandbls': 611,
28358     'Idieresis': 278,
28359     'eacute': 556,
28360     'abreve': 556,
28361     'uhungarumlaut': 556,
28362     'ecaron': 556,
28363     'Ydieresis': 667,
28364     'divide': 584,
28365     'Yacute': 667,
28366     'Acircumflex': 667,
28367     'aacute': 556,
28368     'Ucircumflex': 722,
28369     'yacute': 500,
28370     'scommaaccent': 500,
28371     'ecircumflex': 556,
28372     'Uring': 722,
28373     'Udieresis': 722,
28374     'aogonek': 556,
28375     'Uacute': 722,
28376     'uogonek': 556,
28377     'Edieresis': 667,
28378     'Dcroat': 722,
28379     'commaaccent': 250,
28380     'copyright': 737,
28381     'Emacron': 667,
28382     'ccaron': 500,
28383     'aring': 556,
28384     'Ncommaaccent': 722,
28385     'lacute': 222,
28386     'agrave': 556,
28387     'Tcommaaccent': 611,
28388     'Cacute': 722,
28389     'atilde': 556,
28390     'Edotaccent': 667,
28391     'scaron': 500,
28392     'scedilla': 500,
28393     'iacute': 278,
28394     'lozenge': 471,
28395     'Rcaron': 722,
28396     'Gcommaaccent': 778,
28397     'ucircumflex': 556,
28398     'acircumflex': 556,
28399     'Amacron': 667,
28400     'rcaron': 333,
28401     'ccedilla': 500,
28402     'Zdotaccent': 611,
28403     'Thorn': 667,
28404     'Omacron': 778,
28405     'Racute': 722,
28406     'Sacute': 667,
28407     'dcaron': 643,
28408     'Umacron': 722,
28409     'uring': 556,
28410     'threesuperior': 333,
28411     'Ograve': 778,
28412     'Agrave': 667,
28413     'Abreve': 667,
28414     'multiply': 584,
28415     'uacute': 556,
28416     'Tcaron': 611,
28417     'partialdiff': 476,
28418     'ydieresis': 500,
28419     'Nacute': 722,
28420     'icircumflex': 278,
28421     'Ecircumflex': 667,
28422     'adieresis': 556,
28423     'edieresis': 556,
28424     'cacute': 500,
28425     'nacute': 556,
28426     'umacron': 556,
28427     'Ncaron': 722,
28428     'Iacute': 278,
28429     'plusminus': 584,
28430     'brokenbar': 260,
28431     'registered': 737,
28432     'Gbreve': 778,
28433     'Idotaccent': 278,
28434     'summation': 600,
28435     'Egrave': 667,
28436     'racute': 333,
28437     'omacron': 556,
28438     'Zacute': 611,
28439     'Zcaron': 611,
28440     'greaterequal': 549,
28441     'Eth': 722,
28442     'Ccedilla': 722,
28443     'lcommaaccent': 222,
28444     'tcaron': 317,
28445     'eogonek': 556,
28446     'Uogonek': 722,
28447     'Aacute': 667,
28448     'Adieresis': 667,
28449     'egrave': 556,
28450     'zacute': 500,
28451     'iogonek': 222,
28452     'Oacute': 778,
28453     'oacute': 556,
28454     'amacron': 556,
28455     'sacute': 500,
28456     'idieresis': 278,
28457     'Ocircumflex': 778,
28458     'Ugrave': 722,
28459     'Delta': 612,
28460     'thorn': 556,
28461     'twosuperior': 333,
28462     'Odieresis': 778,
28463     'mu': 556,
28464     'igrave': 278,
28465     'ohungarumlaut': 556,
28466     'Eogonek': 667,
28467     'dcroat': 556,
28468     'threequarters': 834,
28469     'Scedilla': 667,
28470     'lcaron': 299,
28471     'Kcommaaccent': 667,
28472     'Lacute': 556,
28473     'trademark': 1000,
28474     'edotaccent': 556,
28475     'Igrave': 278,
28476     'Imacron': 278,
28477     'Lcaron': 556,
28478     'onehalf': 834,
28479     'lessequal': 549,
28480     'ocircumflex': 556,
28481     'ntilde': 556,
28482     'Uhungarumlaut': 722,
28483     'Eacute': 667,
28484     'emacron': 556,
28485     'gbreve': 556,
28486     'onequarter': 834,
28487     'Scaron': 667,
28488     'Scommaaccent': 667,
28489     'Ohungarumlaut': 778,
28490     'degree': 400,
28491     'ograve': 556,
28492     'Ccaron': 722,
28493     'ugrave': 556,
28494     'radical': 453,
28495     'Dcaron': 722,
28496     'rcommaaccent': 333,
28497     'Ntilde': 722,
28498     'otilde': 556,
28499     'Rcommaaccent': 722,
28500     'Lcommaaccent': 556,
28501     'Atilde': 667,
28502     'Aogonek': 667,
28503     'Aring': 667,
28504     'Otilde': 778,
28505     'zdotaccent': 500,
28506     'Ecaron': 667,
28507     'Iogonek': 278,
28508     'kcommaaccent': 500,
28509     'minus': 584,
28510     'Icircumflex': 278,
28511     'ncaron': 556,
28512     'tcommaaccent': 278,
28513     'logicalnot': 584,
28514     'odieresis': 556,
28515     'udieresis': 556,
28516     'notequal': 549,
28517     'gcommaaccent': 556,
28518     'eth': 556,
28519     'zcaron': 500,
28520     'ncommaaccent': 556,
28521     'onesuperior': 333,
28522     'imacron': 278,
28523     'Euro': 556
28524   },
28525   'Symbol': {
28526     'space': 250,
28527     'exclam': 333,
28528     'universal': 713,
28529     'numbersign': 500,
28530     'existential': 549,
28531     'percent': 833,
28532     'ampersand': 778,
28533     'suchthat': 439,
28534     'parenleft': 333,
28535     'parenright': 333,
28536     'asteriskmath': 500,
28537     'plus': 549,
28538     'comma': 250,
28539     'minus': 549,
28540     'period': 250,
28541     'slash': 278,
28542     'zero': 500,
28543     'one': 500,
28544     'two': 500,
28545     'three': 500,
28546     'four': 500,
28547     'five': 500,
28548     'six': 500,
28549     'seven': 500,
28550     'eight': 500,
28551     'nine': 500,
28552     'colon': 278,
28553     'semicolon': 278,
28554     'less': 549,
28555     'equal': 549,
28556     'greater': 549,
28557     'question': 444,
28558     'congruent': 549,
28559     'Alpha': 722,
28560     'Beta': 667,
28561     'Chi': 722,
28562     'Delta': 612,
28563     'Epsilon': 611,
28564     'Phi': 763,
28565     'Gamma': 603,
28566     'Eta': 722,
28567     'Iota': 333,
28568     'theta1': 631,
28569     'Kappa': 722,
28570     'Lambda': 686,
28571     'Mu': 889,
28572     'Nu': 722,
28573     'Omicron': 722,
28574     'Pi': 768,
28575     'Theta': 741,
28576     'Rho': 556,
28577     'Sigma': 592,
28578     'Tau': 611,
28579     'Upsilon': 690,
28580     'sigma1': 439,
28581     'Omega': 768,
28582     'Xi': 645,
28583     'Psi': 795,
28584     'Zeta': 611,
28585     'bracketleft': 333,
28586     'therefore': 863,
28587     'bracketright': 333,
28588     'perpendicular': 658,
28589     'underscore': 500,
28590     'radicalex': 500,
28591     'alpha': 631,
28592     'beta': 549,
28593     'chi': 549,
28594     'delta': 494,
28595     'epsilon': 439,
28596     'phi': 521,
28597     'gamma': 411,
28598     'eta': 603,
28599     'iota': 329,
28600     'phi1': 603,
28601     'kappa': 549,
28602     'lambda': 549,
28603     'mu': 576,
28604     'nu': 521,
28605     'omicron': 549,
28606     'pi': 549,
28607     'theta': 521,
28608     'rho': 549,
28609     'sigma': 603,
28610     'tau': 439,
28611     'upsilon': 576,
28612     'omega1': 713,
28613     'omega': 686,
28614     'xi': 493,
28615     'psi': 686,
28616     'zeta': 494,
28617     'braceleft': 480,
28618     'bar': 200,
28619     'braceright': 480,
28620     'similar': 549,
28621     'Euro': 750,
28622     'Upsilon1': 620,
28623     'minute': 247,
28624     'lessequal': 549,
28625     'fraction': 167,
28626     'infinity': 713,
28627     'florin': 500,
28628     'club': 753,
28629     'diamond': 753,
28630     'heart': 753,
28631     'spade': 753,
28632     'arrowboth': 1042,
28633     'arrowleft': 987,
28634     'arrowup': 603,
28635     'arrowright': 987,
28636     'arrowdown': 603,
28637     'degree': 400,
28638     'plusminus': 549,
28639     'second': 411,
28640     'greaterequal': 549,
28641     'multiply': 549,
28642     'proportional': 713,
28643     'partialdiff': 494,
28644     'bullet': 460,
28645     'divide': 549,
28646     'notequal': 549,
28647     'equivalence': 549,
28648     'approxequal': 549,
28649     'ellipsis': 1000,
28650     'arrowvertex': 603,
28651     'arrowhorizex': 1000,
28652     'carriagereturn': 658,
28653     'aleph': 823,
28654     'Ifraktur': 686,
28655     'Rfraktur': 795,
28656     'weierstrass': 987,
28657     'circlemultiply': 768,
28658     'circleplus': 768,
28659     'emptyset': 823,
28660     'intersection': 768,
28661     'union': 768,
28662     'propersuperset': 713,
28663     'reflexsuperset': 713,
28664     'notsubset': 713,
28665     'propersubset': 713,
28666     'reflexsubset': 713,
28667     'element': 713,
28668     'notelement': 713,
28669     'angle': 768,
28670     'gradient': 713,
28671     'registerserif': 790,
28672     'copyrightserif': 790,
28673     'trademarkserif': 890,
28674     'product': 823,
28675     'radical': 549,
28676     'dotmath': 250,
28677     'logicalnot': 713,
28678     'logicaland': 603,
28679     'logicalor': 603,
28680     'arrowdblboth': 1042,
28681     'arrowdblleft': 987,
28682     'arrowdblup': 603,
28683     'arrowdblright': 987,
28684     'arrowdbldown': 603,
28685     'lozenge': 494,
28686     'angleleft': 329,
28687     'registersans': 790,
28688     'copyrightsans': 790,
28689     'trademarksans': 786,
28690     'summation': 713,
28691     'parenlefttp': 384,
28692     'parenleftex': 384,
28693     'parenleftbt': 384,
28694     'bracketlefttp': 384,
28695     'bracketleftex': 384,
28696     'bracketleftbt': 384,
28697     'bracelefttp': 494,
28698     'braceleftmid': 494,
28699     'braceleftbt': 494,
28700     'braceex': 494,
28701     'angleright': 329,
28702     'integral': 274,
28703     'integraltp': 686,
28704     'integralex': 686,
28705     'integralbt': 686,
28706     'parenrighttp': 384,
28707     'parenrightex': 384,
28708     'parenrightbt': 384,
28709     'bracketrighttp': 384,
28710     'bracketrightex': 384,
28711     'bracketrightbt': 384,
28712     'bracerighttp': 494,
28713     'bracerightmid': 494,
28714     'bracerightbt': 494,
28715     'apple': 790
28716   },
28717   'Times-Roman': {
28718     'space': 250,
28719     'exclam': 333,
28720     'quotedbl': 408,
28721     'numbersign': 500,
28722     'dollar': 500,
28723     'percent': 833,
28724     'ampersand': 778,
28725     'quoteright': 333,
28726     'parenleft': 333,
28727     'parenright': 333,
28728     'asterisk': 500,
28729     'plus': 564,
28730     'comma': 250,
28731     'hyphen': 333,
28732     'period': 250,
28733     'slash': 278,
28734     'zero': 500,
28735     'one': 500,
28736     'two': 500,
28737     'three': 500,
28738     'four': 500,
28739     'five': 500,
28740     'six': 500,
28741     'seven': 500,
28742     'eight': 500,
28743     'nine': 500,
28744     'colon': 278,
28745     'semicolon': 278,
28746     'less': 564,
28747     'equal': 564,
28748     'greater': 564,
28749     'question': 444,
28750     'at': 921,
28751     'A': 722,
28752     'B': 667,
28753     'C': 667,
28754     'D': 722,
28755     'E': 611,
28756     'F': 556,
28757     'G': 722,
28758     'H': 722,
28759     'I': 333,
28760     'J': 389,
28761     'K': 722,
28762     'L': 611,
28763     'M': 889,
28764     'N': 722,
28765     'O': 722,
28766     'P': 556,
28767     'Q': 722,
28768     'R': 667,
28769     'S': 556,
28770     'T': 611,
28771     'U': 722,
28772     'V': 722,
28773     'W': 944,
28774     'X': 722,
28775     'Y': 722,
28776     'Z': 611,
28777     'bracketleft': 333,
28778     'backslash': 278,
28779     'bracketright': 333,
28780     'asciicircum': 469,
28781     'underscore': 500,
28782     'quoteleft': 333,
28783     'a': 444,
28784     'b': 500,
28785     'c': 444,
28786     'd': 500,
28787     'e': 444,
28788     'f': 333,
28789     'g': 500,
28790     'h': 500,
28791     'i': 278,
28792     'j': 278,
28793     'k': 500,
28794     'l': 278,
28795     'm': 778,
28796     'n': 500,
28797     'o': 500,
28798     'p': 500,
28799     'q': 500,
28800     'r': 333,
28801     's': 389,
28802     't': 278,
28803     'u': 500,
28804     'v': 500,
28805     'w': 722,
28806     'x': 500,
28807     'y': 500,
28808     'z': 444,
28809     'braceleft': 480,
28810     'bar': 200,
28811     'braceright': 480,
28812     'asciitilde': 541,
28813     'exclamdown': 333,
28814     'cent': 500,
28815     'sterling': 500,
28816     'fraction': 167,
28817     'yen': 500,
28818     'florin': 500,
28819     'section': 500,
28820     'currency': 500,
28821     'quotesingle': 180,
28822     'quotedblleft': 444,
28823     'guillemotleft': 500,
28824     'guilsinglleft': 333,
28825     'guilsinglright': 333,
28826     'fi': 556,
28827     'fl': 556,
28828     'endash': 500,
28829     'dagger': 500,
28830     'daggerdbl': 500,
28831     'periodcentered': 250,
28832     'paragraph': 453,
28833     'bullet': 350,
28834     'quotesinglbase': 333,
28835     'quotedblbase': 444,
28836     'quotedblright': 444,
28837     'guillemotright': 500,
28838     'ellipsis': 1000,
28839     'perthousand': 1000,
28840     'questiondown': 444,
28841     'grave': 333,
28842     'acute': 333,
28843     'circumflex': 333,
28844     'tilde': 333,
28845     'macron': 333,
28846     'breve': 333,
28847     'dotaccent': 333,
28848     'dieresis': 333,
28849     'ring': 333,
28850     'cedilla': 333,
28851     'hungarumlaut': 333,
28852     'ogonek': 333,
28853     'caron': 333,
28854     'emdash': 1000,
28855     'AE': 889,
28856     'ordfeminine': 276,
28857     'Lslash': 611,
28858     'Oslash': 722,
28859     'OE': 889,
28860     'ordmasculine': 310,
28861     'ae': 667,
28862     'dotlessi': 278,
28863     'lslash': 278,
28864     'oslash': 500,
28865     'oe': 722,
28866     'germandbls': 500,
28867     'Idieresis': 333,
28868     'eacute': 444,
28869     'abreve': 444,
28870     'uhungarumlaut': 500,
28871     'ecaron': 444,
28872     'Ydieresis': 722,
28873     'divide': 564,
28874     'Yacute': 722,
28875     'Acircumflex': 722,
28876     'aacute': 444,
28877     'Ucircumflex': 722,
28878     'yacute': 500,
28879     'scommaaccent': 389,
28880     'ecircumflex': 444,
28881     'Uring': 722,
28882     'Udieresis': 722,
28883     'aogonek': 444,
28884     'Uacute': 722,
28885     'uogonek': 500,
28886     'Edieresis': 611,
28887     'Dcroat': 722,
28888     'commaaccent': 250,
28889     'copyright': 760,
28890     'Emacron': 611,
28891     'ccaron': 444,
28892     'aring': 444,
28893     'Ncommaaccent': 722,
28894     'lacute': 278,
28895     'agrave': 444,
28896     'Tcommaaccent': 611,
28897     'Cacute': 667,
28898     'atilde': 444,
28899     'Edotaccent': 611,
28900     'scaron': 389,
28901     'scedilla': 389,
28902     'iacute': 278,
28903     'lozenge': 471,
28904     'Rcaron': 667,
28905     'Gcommaaccent': 722,
28906     'ucircumflex': 500,
28907     'acircumflex': 444,
28908     'Amacron': 722,
28909     'rcaron': 333,
28910     'ccedilla': 444,
28911     'Zdotaccent': 611,
28912     'Thorn': 556,
28913     'Omacron': 722,
28914     'Racute': 667,
28915     'Sacute': 556,
28916     'dcaron': 588,
28917     'Umacron': 722,
28918     'uring': 500,
28919     'threesuperior': 300,
28920     'Ograve': 722,
28921     'Agrave': 722,
28922     'Abreve': 722,
28923     'multiply': 564,
28924     'uacute': 500,
28925     'Tcaron': 611,
28926     'partialdiff': 476,
28927     'ydieresis': 500,
28928     'Nacute': 722,
28929     'icircumflex': 278,
28930     'Ecircumflex': 611,
28931     'adieresis': 444,
28932     'edieresis': 444,
28933     'cacute': 444,
28934     'nacute': 500,
28935     'umacron': 500,
28936     'Ncaron': 722,
28937     'Iacute': 333,
28938     'plusminus': 564,
28939     'brokenbar': 200,
28940     'registered': 760,
28941     'Gbreve': 722,
28942     'Idotaccent': 333,
28943     'summation': 600,
28944     'Egrave': 611,
28945     'racute': 333,
28946     'omacron': 500,
28947     'Zacute': 611,
28948     'Zcaron': 611,
28949     'greaterequal': 549,
28950     'Eth': 722,
28951     'Ccedilla': 667,
28952     'lcommaaccent': 278,
28953     'tcaron': 326,
28954     'eogonek': 444,
28955     'Uogonek': 722,
28956     'Aacute': 722,
28957     'Adieresis': 722,
28958     'egrave': 444,
28959     'zacute': 444,
28960     'iogonek': 278,
28961     'Oacute': 722,
28962     'oacute': 500,
28963     'amacron': 444,
28964     'sacute': 389,
28965     'idieresis': 278,
28966     'Ocircumflex': 722,
28967     'Ugrave': 722,
28968     'Delta': 612,
28969     'thorn': 500,
28970     'twosuperior': 300,
28971     'Odieresis': 722,
28972     'mu': 500,
28973     'igrave': 278,
28974     'ohungarumlaut': 500,
28975     'Eogonek': 611,
28976     'dcroat': 500,
28977     'threequarters': 750,
28978     'Scedilla': 556,
28979     'lcaron': 344,
28980     'Kcommaaccent': 722,
28981     'Lacute': 611,
28982     'trademark': 980,
28983     'edotaccent': 444,
28984     'Igrave': 333,
28985     'Imacron': 333,
28986     'Lcaron': 611,
28987     'onehalf': 750,
28988     'lessequal': 549,
28989     'ocircumflex': 500,
28990     'ntilde': 500,
28991     'Uhungarumlaut': 722,
28992     'Eacute': 611,
28993     'emacron': 444,
28994     'gbreve': 500,
28995     'onequarter': 750,
28996     'Scaron': 556,
28997     'Scommaaccent': 556,
28998     'Ohungarumlaut': 722,
28999     'degree': 400,
29000     'ograve': 500,
29001     'Ccaron': 667,
29002     'ugrave': 500,
29003     'radical': 453,
29004     'Dcaron': 722,
29005     'rcommaaccent': 333,
29006     'Ntilde': 722,
29007     'otilde': 500,
29008     'Rcommaaccent': 667,
29009     'Lcommaaccent': 611,
29010     'Atilde': 722,
29011     'Aogonek': 722,
29012     'Aring': 722,
29013     'Otilde': 722,
29014     'zdotaccent': 444,
29015     'Ecaron': 611,
29016     'Iogonek': 333,
29017     'kcommaaccent': 500,
29018     'minus': 564,
29019     'Icircumflex': 333,
29020     'ncaron': 500,
29021     'tcommaaccent': 278,
29022     'logicalnot': 564,
29023     'odieresis': 500,
29024     'udieresis': 500,
29025     'notequal': 549,
29026     'gcommaaccent': 500,
29027     'eth': 500,
29028     'zcaron': 444,
29029     'ncommaaccent': 500,
29030     'onesuperior': 300,
29031     'imacron': 278,
29032     'Euro': 500
29033   },
29034   'Times-Bold': {
29035     'space': 250,
29036     'exclam': 333,
29037     'quotedbl': 555,
29038     'numbersign': 500,
29039     'dollar': 500,
29040     'percent': 1000,
29041     'ampersand': 833,
29042     'quoteright': 333,
29043     'parenleft': 333,
29044     'parenright': 333,
29045     'asterisk': 500,
29046     'plus': 570,
29047     'comma': 250,
29048     'hyphen': 333,
29049     'period': 250,
29050     'slash': 278,
29051     'zero': 500,
29052     'one': 500,
29053     'two': 500,
29054     'three': 500,
29055     'four': 500,
29056     'five': 500,
29057     'six': 500,
29058     'seven': 500,
29059     'eight': 500,
29060     'nine': 500,
29061     'colon': 333,
29062     'semicolon': 333,
29063     'less': 570,
29064     'equal': 570,
29065     'greater': 570,
29066     'question': 500,
29067     'at': 930,
29068     'A': 722,
29069     'B': 667,
29070     'C': 722,
29071     'D': 722,
29072     'E': 667,
29073     'F': 611,
29074     'G': 778,
29075     'H': 778,
29076     'I': 389,
29077     'J': 500,
29078     'K': 778,
29079     'L': 667,
29080     'M': 944,
29081     'N': 722,
29082     'O': 778,
29083     'P': 611,
29084     'Q': 778,
29085     'R': 722,
29086     'S': 556,
29087     'T': 667,
29088     'U': 722,
29089     'V': 722,
29090     'W': 1000,
29091     'X': 722,
29092     'Y': 722,
29093     'Z': 667,
29094     'bracketleft': 333,
29095     'backslash': 278,
29096     'bracketright': 333,
29097     'asciicircum': 581,
29098     'underscore': 500,
29099     'quoteleft': 333,
29100     'a': 500,
29101     'b': 556,
29102     'c': 444,
29103     'd': 556,
29104     'e': 444,
29105     'f': 333,
29106     'g': 500,
29107     'h': 556,
29108     'i': 278,
29109     'j': 333,
29110     'k': 556,
29111     'l': 278,
29112     'm': 833,
29113     'n': 556,
29114     'o': 500,
29115     'p': 556,
29116     'q': 556,
29117     'r': 444,
29118     's': 389,
29119     't': 333,
29120     'u': 556,
29121     'v': 500,
29122     'w': 722,
29123     'x': 500,
29124     'y': 500,
29125     'z': 444,
29126     'braceleft': 394,
29127     'bar': 220,
29128     'braceright': 394,
29129     'asciitilde': 520,
29130     'exclamdown': 333,
29131     'cent': 500,
29132     'sterling': 500,
29133     'fraction': 167,
29134     'yen': 500,
29135     'florin': 500,
29136     'section': 500,
29137     'currency': 500,
29138     'quotesingle': 278,
29139     'quotedblleft': 500,
29140     'guillemotleft': 500,
29141     'guilsinglleft': 333,
29142     'guilsinglright': 333,
29143     'fi': 556,
29144     'fl': 556,
29145     'endash': 500,
29146     'dagger': 500,
29147     'daggerdbl': 500,
29148     'periodcentered': 250,
29149     'paragraph': 540,
29150     'bullet': 350,
29151     'quotesinglbase': 333,
29152     'quotedblbase': 500,
29153     'quotedblright': 500,
29154     'guillemotright': 500,
29155     'ellipsis': 1000,
29156     'perthousand': 1000,
29157     'questiondown': 500,
29158     'grave': 333,
29159     'acute': 333,
29160     'circumflex': 333,
29161     'tilde': 333,
29162     'macron': 333,
29163     'breve': 333,
29164     'dotaccent': 333,
29165     'dieresis': 333,
29166     'ring': 333,
29167     'cedilla': 333,
29168     'hungarumlaut': 333,
29169     'ogonek': 333,
29170     'caron': 333,
29171     'emdash': 1000,
29172     'AE': 1000,
29173     'ordfeminine': 300,
29174     'Lslash': 667,
29175     'Oslash': 778,
29176     'OE': 1000,
29177     'ordmasculine': 330,
29178     'ae': 722,
29179     'dotlessi': 278,
29180     'lslash': 278,
29181     'oslash': 500,
29182     'oe': 722,
29183     'germandbls': 556,
29184     'Idieresis': 389,
29185     'eacute': 444,
29186     'abreve': 500,
29187     'uhungarumlaut': 556,
29188     'ecaron': 444,
29189     'Ydieresis': 722,
29190     'divide': 570,
29191     'Yacute': 722,
29192     'Acircumflex': 722,
29193     'aacute': 500,
29194     'Ucircumflex': 722,
29195     'yacute': 500,
29196     'scommaaccent': 389,
29197     'ecircumflex': 444,
29198     'Uring': 722,
29199     'Udieresis': 722,
29200     'aogonek': 500,
29201     'Uacute': 722,
29202     'uogonek': 556,
29203     'Edieresis': 667,
29204     'Dcroat': 722,
29205     'commaaccent': 250,
29206     'copyright': 747,
29207     'Emacron': 667,
29208     'ccaron': 444,
29209     'aring': 500,
29210     'Ncommaaccent': 722,
29211     'lacute': 278,
29212     'agrave': 500,
29213     'Tcommaaccent': 667,
29214     'Cacute': 722,
29215     'atilde': 500,
29216     'Edotaccent': 667,
29217     'scaron': 389,
29218     'scedilla': 389,
29219     'iacute': 278,
29220     'lozenge': 494,
29221     'Rcaron': 722,
29222     'Gcommaaccent': 778,
29223     'ucircumflex': 556,
29224     'acircumflex': 500,
29225     'Amacron': 722,
29226     'rcaron': 444,
29227     'ccedilla': 444,
29228     'Zdotaccent': 667,
29229     'Thorn': 611,
29230     'Omacron': 778,
29231     'Racute': 722,
29232     'Sacute': 556,
29233     'dcaron': 672,
29234     'Umacron': 722,
29235     'uring': 556,
29236     'threesuperior': 300,
29237     'Ograve': 778,
29238     'Agrave': 722,
29239     'Abreve': 722,
29240     'multiply': 570,
29241     'uacute': 556,
29242     'Tcaron': 667,
29243     'partialdiff': 494,
29244     'ydieresis': 500,
29245     'Nacute': 722,
29246     'icircumflex': 278,
29247     'Ecircumflex': 667,
29248     'adieresis': 500,
29249     'edieresis': 444,
29250     'cacute': 444,
29251     'nacute': 556,
29252     'umacron': 556,
29253     'Ncaron': 722,
29254     'Iacute': 389,
29255     'plusminus': 570,
29256     'brokenbar': 220,
29257     'registered': 747,
29258     'Gbreve': 778,
29259     'Idotaccent': 389,
29260     'summation': 600,
29261     'Egrave': 667,
29262     'racute': 444,
29263     'omacron': 500,
29264     'Zacute': 667,
29265     'Zcaron': 667,
29266     'greaterequal': 549,
29267     'Eth': 722,
29268     'Ccedilla': 722,
29269     'lcommaaccent': 278,
29270     'tcaron': 416,
29271     'eogonek': 444,
29272     'Uogonek': 722,
29273     'Aacute': 722,
29274     'Adieresis': 722,
29275     'egrave': 444,
29276     'zacute': 444,
29277     'iogonek': 278,
29278     'Oacute': 778,
29279     'oacute': 500,
29280     'amacron': 500,
29281     'sacute': 389,
29282     'idieresis': 278,
29283     'Ocircumflex': 778,
29284     'Ugrave': 722,
29285     'Delta': 612,
29286     'thorn': 556,
29287     'twosuperior': 300,
29288     'Odieresis': 778,
29289     'mu': 556,
29290     'igrave': 278,
29291     'ohungarumlaut': 500,
29292     'Eogonek': 667,
29293     'dcroat': 556,
29294     'threequarters': 750,
29295     'Scedilla': 556,
29296     'lcaron': 394,
29297     'Kcommaaccent': 778,
29298     'Lacute': 667,
29299     'trademark': 1000,
29300     'edotaccent': 444,
29301     'Igrave': 389,
29302     'Imacron': 389,
29303     'Lcaron': 667,
29304     'onehalf': 750,
29305     'lessequal': 549,
29306     'ocircumflex': 500,
29307     'ntilde': 556,
29308     'Uhungarumlaut': 722,
29309     'Eacute': 667,
29310     'emacron': 444,
29311     'gbreve': 500,
29312     'onequarter': 750,
29313     'Scaron': 556,
29314     'Scommaaccent': 556,
29315     'Ohungarumlaut': 778,
29316     'degree': 400,
29317     'ograve': 500,
29318     'Ccaron': 722,
29319     'ugrave': 556,
29320     'radical': 549,
29321     'Dcaron': 722,
29322     'rcommaaccent': 444,
29323     'Ntilde': 722,
29324     'otilde': 500,
29325     'Rcommaaccent': 722,
29326     'Lcommaaccent': 667,
29327     'Atilde': 722,
29328     'Aogonek': 722,
29329     'Aring': 722,
29330     'Otilde': 778,
29331     'zdotaccent': 444,
29332     'Ecaron': 667,
29333     'Iogonek': 389,
29334     'kcommaaccent': 556,
29335     'minus': 570,
29336     'Icircumflex': 389,
29337     'ncaron': 556,
29338     'tcommaaccent': 333,
29339     'logicalnot': 570,
29340     'odieresis': 500,
29341     'udieresis': 556,
29342     'notequal': 549,
29343     'gcommaaccent': 500,
29344     'eth': 500,
29345     'zcaron': 444,
29346     'ncommaaccent': 556,
29347     'onesuperior': 300,
29348     'imacron': 278,
29349     'Euro': 500
29350   },
29351   'Times-BoldItalic': {
29352     'space': 250,
29353     'exclam': 389,
29354     'quotedbl': 555,
29355     'numbersign': 500,
29356     'dollar': 500,
29357     'percent': 833,
29358     'ampersand': 778,
29359     'quoteright': 333,
29360     'parenleft': 333,
29361     'parenright': 333,
29362     'asterisk': 500,
29363     'plus': 570,
29364     'comma': 250,
29365     'hyphen': 333,
29366     'period': 250,
29367     'slash': 278,
29368     'zero': 500,
29369     'one': 500,
29370     'two': 500,
29371     'three': 500,
29372     'four': 500,
29373     'five': 500,
29374     'six': 500,
29375     'seven': 500,
29376     'eight': 500,
29377     'nine': 500,
29378     'colon': 333,
29379     'semicolon': 333,
29380     'less': 570,
29381     'equal': 570,
29382     'greater': 570,
29383     'question': 500,
29384     'at': 832,
29385     'A': 667,
29386     'B': 667,
29387     'C': 667,
29388     'D': 722,
29389     'E': 667,
29390     'F': 667,
29391     'G': 722,
29392     'H': 778,
29393     'I': 389,
29394     'J': 500,
29395     'K': 667,
29396     'L': 611,
29397     'M': 889,
29398     'N': 722,
29399     'O': 722,
29400     'P': 611,
29401     'Q': 722,
29402     'R': 667,
29403     'S': 556,
29404     'T': 611,
29405     'U': 722,
29406     'V': 667,
29407     'W': 889,
29408     'X': 667,
29409     'Y': 611,
29410     'Z': 611,
29411     'bracketleft': 333,
29412     'backslash': 278,
29413     'bracketright': 333,
29414     'asciicircum': 570,
29415     'underscore': 500,
29416     'quoteleft': 333,
29417     'a': 500,
29418     'b': 500,
29419     'c': 444,
29420     'd': 500,
29421     'e': 444,
29422     'f': 333,
29423     'g': 500,
29424     'h': 556,
29425     'i': 278,
29426     'j': 278,
29427     'k': 500,
29428     'l': 278,
29429     'm': 778,
29430     'n': 556,
29431     'o': 500,
29432     'p': 500,
29433     'q': 500,
29434     'r': 389,
29435     's': 389,
29436     't': 278,
29437     'u': 556,
29438     'v': 444,
29439     'w': 667,
29440     'x': 500,
29441     'y': 444,
29442     'z': 389,
29443     'braceleft': 348,
29444     'bar': 220,
29445     'braceright': 348,
29446     'asciitilde': 570,
29447     'exclamdown': 389,
29448     'cent': 500,
29449     'sterling': 500,
29450     'fraction': 167,
29451     'yen': 500,
29452     'florin': 500,
29453     'section': 500,
29454     'currency': 500,
29455     'quotesingle': 278,
29456     'quotedblleft': 500,
29457     'guillemotleft': 500,
29458     'guilsinglleft': 333,
29459     'guilsinglright': 333,
29460     'fi': 556,
29461     'fl': 556,
29462     'endash': 500,
29463     'dagger': 500,
29464     'daggerdbl': 500,
29465     'periodcentered': 250,
29466     'paragraph': 500,
29467     'bullet': 350,
29468     'quotesinglbase': 333,
29469     'quotedblbase': 500,
29470     'quotedblright': 500,
29471     'guillemotright': 500,
29472     'ellipsis': 1000,
29473     'perthousand': 1000,
29474     'questiondown': 500,
29475     'grave': 333,
29476     'acute': 333,
29477     'circumflex': 333,
29478     'tilde': 333,
29479     'macron': 333,
29480     'breve': 333,
29481     'dotaccent': 333,
29482     'dieresis': 333,
29483     'ring': 333,
29484     'cedilla': 333,
29485     'hungarumlaut': 333,
29486     'ogonek': 333,
29487     'caron': 333,
29488     'emdash': 1000,
29489     'AE': 944,
29490     'ordfeminine': 266,
29491     'Lslash': 611,
29492     'Oslash': 722,
29493     'OE': 944,
29494     'ordmasculine': 300,
29495     'ae': 722,
29496     'dotlessi': 278,
29497     'lslash': 278,
29498     'oslash': 500,
29499     'oe': 722,
29500     'germandbls': 500,
29501     'Idieresis': 389,
29502     'eacute': 444,
29503     'abreve': 500,
29504     'uhungarumlaut': 556,
29505     'ecaron': 444,
29506     'Ydieresis': 611,
29507     'divide': 570,
29508     'Yacute': 611,
29509     'Acircumflex': 667,
29510     'aacute': 500,
29511     'Ucircumflex': 722,
29512     'yacute': 444,
29513     'scommaaccent': 389,
29514     'ecircumflex': 444,
29515     'Uring': 722,
29516     'Udieresis': 722,
29517     'aogonek': 500,
29518     'Uacute': 722,
29519     'uogonek': 556,
29520     'Edieresis': 667,
29521     'Dcroat': 722,
29522     'commaaccent': 250,
29523     'copyright': 747,
29524     'Emacron': 667,
29525     'ccaron': 444,
29526     'aring': 500,
29527     'Ncommaaccent': 722,
29528     'lacute': 278,
29529     'agrave': 500,
29530     'Tcommaaccent': 611,
29531     'Cacute': 667,
29532     'atilde': 500,
29533     'Edotaccent': 667,
29534     'scaron': 389,
29535     'scedilla': 389,
29536     'iacute': 278,
29537     'lozenge': 494,
29538     'Rcaron': 667,
29539     'Gcommaaccent': 722,
29540     'ucircumflex': 556,
29541     'acircumflex': 500,
29542     'Amacron': 667,
29543     'rcaron': 389,
29544     'ccedilla': 444,
29545     'Zdotaccent': 611,
29546     'Thorn': 611,
29547     'Omacron': 722,
29548     'Racute': 667,
29549     'Sacute': 556,
29550     'dcaron': 608,
29551     'Umacron': 722,
29552     'uring': 556,
29553     'threesuperior': 300,
29554     'Ograve': 722,
29555     'Agrave': 667,
29556     'Abreve': 667,
29557     'multiply': 570,
29558     'uacute': 556,
29559     'Tcaron': 611,
29560     'partialdiff': 494,
29561     'ydieresis': 444,
29562     'Nacute': 722,
29563     'icircumflex': 278,
29564     'Ecircumflex': 667,
29565     'adieresis': 500,
29566     'edieresis': 444,
29567     'cacute': 444,
29568     'nacute': 556,
29569     'umacron': 556,
29570     'Ncaron': 722,
29571     'Iacute': 389,
29572     'plusminus': 570,
29573     'brokenbar': 220,
29574     'registered': 747,
29575     'Gbreve': 722,
29576     'Idotaccent': 389,
29577     'summation': 600,
29578     'Egrave': 667,
29579     'racute': 389,
29580     'omacron': 500,
29581     'Zacute': 611,
29582     'Zcaron': 611,
29583     'greaterequal': 549,
29584     'Eth': 722,
29585     'Ccedilla': 667,
29586     'lcommaaccent': 278,
29587     'tcaron': 366,
29588     'eogonek': 444,
29589     'Uogonek': 722,
29590     'Aacute': 667,
29591     'Adieresis': 667,
29592     'egrave': 444,
29593     'zacute': 389,
29594     'iogonek': 278,
29595     'Oacute': 722,
29596     'oacute': 500,
29597     'amacron': 500,
29598     'sacute': 389,
29599     'idieresis': 278,
29600     'Ocircumflex': 722,
29601     'Ugrave': 722,
29602     'Delta': 612,
29603     'thorn': 500,
29604     'twosuperior': 300,
29605     'Odieresis': 722,
29606     'mu': 576,
29607     'igrave': 278,
29608     'ohungarumlaut': 500,
29609     'Eogonek': 667,
29610     'dcroat': 500,
29611     'threequarters': 750,
29612     'Scedilla': 556,
29613     'lcaron': 382,
29614     'Kcommaaccent': 667,
29615     'Lacute': 611,
29616     'trademark': 1000,
29617     'edotaccent': 444,
29618     'Igrave': 389,
29619     'Imacron': 389,
29620     'Lcaron': 611,
29621     'onehalf': 750,
29622     'lessequal': 549,
29623     'ocircumflex': 500,
29624     'ntilde': 556,
29625     'Uhungarumlaut': 722,
29626     'Eacute': 667,
29627     'emacron': 444,
29628     'gbreve': 500,
29629     'onequarter': 750,
29630     'Scaron': 556,
29631     'Scommaaccent': 556,
29632     'Ohungarumlaut': 722,
29633     'degree': 400,
29634     'ograve': 500,
29635     'Ccaron': 667,
29636     'ugrave': 556,
29637     'radical': 549,
29638     'Dcaron': 722,
29639     'rcommaaccent': 389,
29640     'Ntilde': 722,
29641     'otilde': 500,
29642     'Rcommaaccent': 667,
29643     'Lcommaaccent': 611,
29644     'Atilde': 667,
29645     'Aogonek': 667,
29646     'Aring': 667,
29647     'Otilde': 722,
29648     'zdotaccent': 389,
29649     'Ecaron': 667,
29650     'Iogonek': 389,
29651     'kcommaaccent': 500,
29652     'minus': 606,
29653     'Icircumflex': 389,
29654     'ncaron': 556,
29655     'tcommaaccent': 278,
29656     'logicalnot': 606,
29657     'odieresis': 500,
29658     'udieresis': 556,
29659     'notequal': 549,
29660     'gcommaaccent': 500,
29661     'eth': 500,
29662     'zcaron': 389,
29663     'ncommaaccent': 556,
29664     'onesuperior': 300,
29665     'imacron': 278,
29666     'Euro': 500
29667   },
29668   'Times-Italic': {
29669     'space': 250,
29670     'exclam': 333,
29671     'quotedbl': 420,
29672     'numbersign': 500,
29673     'dollar': 500,
29674     'percent': 833,
29675     'ampersand': 778,
29676     'quoteright': 333,
29677     'parenleft': 333,
29678     'parenright': 333,
29679     'asterisk': 500,
29680     'plus': 675,
29681     'comma': 250,
29682     'hyphen': 333,
29683     'period': 250,
29684     'slash': 278,
29685     'zero': 500,
29686     'one': 500,
29687     'two': 500,
29688     'three': 500,
29689     'four': 500,
29690     'five': 500,
29691     'six': 500,
29692     'seven': 500,
29693     'eight': 500,
29694     'nine': 500,
29695     'colon': 333,
29696     'semicolon': 333,
29697     'less': 675,
29698     'equal': 675,
29699     'greater': 675,
29700     'question': 500,
29701     'at': 920,
29702     'A': 611,
29703     'B': 611,
29704     'C': 667,
29705     'D': 722,
29706     'E': 611,
29707     'F': 611,
29708     'G': 722,
29709     'H': 722,
29710     'I': 333,
29711     'J': 444,
29712     'K': 667,
29713     'L': 556,
29714     'M': 833,
29715     'N': 667,
29716     'O': 722,
29717     'P': 611,
29718     'Q': 722,
29719     'R': 611,
29720     'S': 500,
29721     'T': 556,
29722     'U': 722,
29723     'V': 611,
29724     'W': 833,
29725     'X': 611,
29726     'Y': 556,
29727     'Z': 556,
29728     'bracketleft': 389,
29729     'backslash': 278,
29730     'bracketright': 389,
29731     'asciicircum': 422,
29732     'underscore': 500,
29733     'quoteleft': 333,
29734     'a': 500,
29735     'b': 500,
29736     'c': 444,
29737     'd': 500,
29738     'e': 444,
29739     'f': 278,
29740     'g': 500,
29741     'h': 500,
29742     'i': 278,
29743     'j': 278,
29744     'k': 444,
29745     'l': 278,
29746     'm': 722,
29747     'n': 500,
29748     'o': 500,
29749     'p': 500,
29750     'q': 500,
29751     'r': 389,
29752     's': 389,
29753     't': 278,
29754     'u': 500,
29755     'v': 444,
29756     'w': 667,
29757     'x': 444,
29758     'y': 444,
29759     'z': 389,
29760     'braceleft': 400,
29761     'bar': 275,
29762     'braceright': 400,
29763     'asciitilde': 541,
29764     'exclamdown': 389,
29765     'cent': 500,
29766     'sterling': 500,
29767     'fraction': 167,
29768     'yen': 500,
29769     'florin': 500,
29770     'section': 500,
29771     'currency': 500,
29772     'quotesingle': 214,
29773     'quotedblleft': 556,
29774     'guillemotleft': 500,
29775     'guilsinglleft': 333,
29776     'guilsinglright': 333,
29777     'fi': 500,
29778     'fl': 500,
29779     'endash': 500,
29780     'dagger': 500,
29781     'daggerdbl': 500,
29782     'periodcentered': 250,
29783     'paragraph': 523,
29784     'bullet': 350,
29785     'quotesinglbase': 333,
29786     'quotedblbase': 556,
29787     'quotedblright': 556,
29788     'guillemotright': 500,
29789     'ellipsis': 889,
29790     'perthousand': 1000,
29791     'questiondown': 500,
29792     'grave': 333,
29793     'acute': 333,
29794     'circumflex': 333,
29795     'tilde': 333,
29796     'macron': 333,
29797     'breve': 333,
29798     'dotaccent': 333,
29799     'dieresis': 333,
29800     'ring': 333,
29801     'cedilla': 333,
29802     'hungarumlaut': 333,
29803     'ogonek': 333,
29804     'caron': 333,
29805     'emdash': 889,
29806     'AE': 889,
29807     'ordfeminine': 276,
29808     'Lslash': 556,
29809     'Oslash': 722,
29810     'OE': 944,
29811     'ordmasculine': 310,
29812     'ae': 667,
29813     'dotlessi': 278,
29814     'lslash': 278,
29815     'oslash': 500,
29816     'oe': 667,
29817     'germandbls': 500,
29818     'Idieresis': 333,
29819     'eacute': 444,
29820     'abreve': 500,
29821     'uhungarumlaut': 500,
29822     'ecaron': 444,
29823     'Ydieresis': 556,
29824     'divide': 675,
29825     'Yacute': 556,
29826     'Acircumflex': 611,
29827     'aacute': 500,
29828     'Ucircumflex': 722,
29829     'yacute': 444,
29830     'scommaaccent': 389,
29831     'ecircumflex': 444,
29832     'Uring': 722,
29833     'Udieresis': 722,
29834     'aogonek': 500,
29835     'Uacute': 722,
29836     'uogonek': 500,
29837     'Edieresis': 611,
29838     'Dcroat': 722,
29839     'commaaccent': 250,
29840     'copyright': 760,
29841     'Emacron': 611,
29842     'ccaron': 444,
29843     'aring': 500,
29844     'Ncommaaccent': 667,
29845     'lacute': 278,
29846     'agrave': 500,
29847     'Tcommaaccent': 556,
29848     'Cacute': 667,
29849     'atilde': 500,
29850     'Edotaccent': 611,
29851     'scaron': 389,
29852     'scedilla': 389,
29853     'iacute': 278,
29854     'lozenge': 471,
29855     'Rcaron': 611,
29856     'Gcommaaccent': 722,
29857     'ucircumflex': 500,
29858     'acircumflex': 500,
29859     'Amacron': 611,
29860     'rcaron': 389,
29861     'ccedilla': 444,
29862     'Zdotaccent': 556,
29863     'Thorn': 611,
29864     'Omacron': 722,
29865     'Racute': 611,
29866     'Sacute': 500,
29867     'dcaron': 544,
29868     'Umacron': 722,
29869     'uring': 500,
29870     'threesuperior': 300,
29871     'Ograve': 722,
29872     'Agrave': 611,
29873     'Abreve': 611,
29874     'multiply': 675,
29875     'uacute': 500,
29876     'Tcaron': 556,
29877     'partialdiff': 476,
29878     'ydieresis': 444,
29879     'Nacute': 667,
29880     'icircumflex': 278,
29881     'Ecircumflex': 611,
29882     'adieresis': 500,
29883     'edieresis': 444,
29884     'cacute': 444,
29885     'nacute': 500,
29886     'umacron': 500,
29887     'Ncaron': 667,
29888     'Iacute': 333,
29889     'plusminus': 675,
29890     'brokenbar': 275,
29891     'registered': 760,
29892     'Gbreve': 722,
29893     'Idotaccent': 333,
29894     'summation': 600,
29895     'Egrave': 611,
29896     'racute': 389,
29897     'omacron': 500,
29898     'Zacute': 556,
29899     'Zcaron': 556,
29900     'greaterequal': 549,
29901     'Eth': 722,
29902     'Ccedilla': 667,
29903     'lcommaaccent': 278,
29904     'tcaron': 300,
29905     'eogonek': 444,
29906     'Uogonek': 722,
29907     'Aacute': 611,
29908     'Adieresis': 611,
29909     'egrave': 444,
29910     'zacute': 389,
29911     'iogonek': 278,
29912     'Oacute': 722,
29913     'oacute': 500,
29914     'amacron': 500,
29915     'sacute': 389,
29916     'idieresis': 278,
29917     'Ocircumflex': 722,
29918     'Ugrave': 722,
29919     'Delta': 612,
29920     'thorn': 500,
29921     'twosuperior': 300,
29922     'Odieresis': 722,
29923     'mu': 500,
29924     'igrave': 278,
29925     'ohungarumlaut': 500,
29926     'Eogonek': 611,
29927     'dcroat': 500,
29928     'threequarters': 750,
29929     'Scedilla': 500,
29930     'lcaron': 300,
29931     'Kcommaaccent': 667,
29932     'Lacute': 556,
29933     'trademark': 980,
29934     'edotaccent': 444,
29935     'Igrave': 333,
29936     'Imacron': 333,
29937     'Lcaron': 611,
29938     'onehalf': 750,
29939     'lessequal': 549,
29940     'ocircumflex': 500,
29941     'ntilde': 500,
29942     'Uhungarumlaut': 722,
29943     'Eacute': 611,
29944     'emacron': 444,
29945     'gbreve': 500,
29946     'onequarter': 750,
29947     'Scaron': 500,
29948     'Scommaaccent': 500,
29949     'Ohungarumlaut': 722,
29950     'degree': 400,
29951     'ograve': 500,
29952     'Ccaron': 667,
29953     'ugrave': 500,
29954     'radical': 453,
29955     'Dcaron': 722,
29956     'rcommaaccent': 389,
29957     'Ntilde': 667,
29958     'otilde': 500,
29959     'Rcommaaccent': 611,
29960     'Lcommaaccent': 556,
29961     'Atilde': 611,
29962     'Aogonek': 611,
29963     'Aring': 611,
29964     'Otilde': 722,
29965     'zdotaccent': 389,
29966     'Ecaron': 611,
29967     'Iogonek': 333,
29968     'kcommaaccent': 444,
29969     'minus': 675,
29970     'Icircumflex': 333,
29971     'ncaron': 500,
29972     'tcommaaccent': 278,
29973     'logicalnot': 675,
29974     'odieresis': 500,
29975     'udieresis': 500,
29976     'notequal': 549,
29977     'gcommaaccent': 500,
29978     'eth': 500,
29979     'zcaron': 389,
29980     'ncommaaccent': 500,
29981     'onesuperior': 300,
29982     'imacron': 278,
29983     'Euro': 500
29984   },
29985   'ZapfDingbats': {
29986     'space': 278,
29987     'a1': 974,
29988     'a2': 961,
29989     'a202': 974,
29990     'a3': 980,
29991     'a4': 719,
29992     'a5': 789,
29993     'a119': 790,
29994     'a118': 791,
29995     'a117': 690,
29996     'a11': 960,
29997     'a12': 939,
29998     'a13': 549,
29999     'a14': 855,
30000     'a15': 911,
30001     'a16': 933,
30002     'a105': 911,
30003     'a17': 945,
30004     'a18': 974,
30005     'a19': 755,
30006     'a20': 846,
30007     'a21': 762,
30008     'a22': 761,
30009     'a23': 571,
30010     'a24': 677,
30011     'a25': 763,
30012     'a26': 760,
30013     'a27': 759,
30014     'a28': 754,
30015     'a6': 494,
30016     'a7': 552,
30017     'a8': 537,
30018     'a9': 577,
30019     'a10': 692,
30020     'a29': 786,
30021     'a30': 788,
30022     'a31': 788,
30023     'a32': 790,
30024     'a33': 793,
30025     'a34': 794,
30026     'a35': 816,
30027     'a36': 823,
30028     'a37': 789,
30029     'a38': 841,
30030     'a39': 823,
30031     'a40': 833,
30032     'a41': 816,
30033     'a42': 831,
30034     'a43': 923,
30035     'a44': 744,
30036     'a45': 723,
30037     'a46': 749,
30038     'a47': 790,
30039     'a48': 792,
30040     'a49': 695,
30041     'a50': 776,
30042     'a51': 768,
30043     'a52': 792,
30044     'a53': 759,
30045     'a54': 707,
30046     'a55': 708,
30047     'a56': 682,
30048     'a57': 701,
30049     'a58': 826,
30050     'a59': 815,
30051     'a60': 789,
30052     'a61': 789,
30053     'a62': 707,
30054     'a63': 687,
30055     'a64': 696,
30056     'a65': 689,
30057     'a66': 786,
30058     'a67': 787,
30059     'a68': 713,
30060     'a69': 791,
30061     'a70': 785,
30062     'a71': 791,
30063     'a72': 873,
30064     'a73': 761,
30065     'a74': 762,
30066     'a203': 762,
30067     'a75': 759,
30068     'a204': 759,
30069     'a76': 892,
30070     'a77': 892,
30071     'a78': 788,
30072     'a79': 784,
30073     'a81': 438,
30074     'a82': 138,
30075     'a83': 277,
30076     'a84': 415,
30077     'a97': 392,
30078     'a98': 392,
30079     'a99': 668,
30080     'a100': 668,
30081     'a89': 390,
30082     'a90': 390,
30083     'a93': 317,
30084     'a94': 317,
30085     'a91': 276,
30086     'a92': 276,
30087     'a205': 509,
30088     'a85': 509,
30089     'a206': 410,
30090     'a86': 410,
30091     'a87': 234,
30092     'a88': 234,
30093     'a95': 334,
30094     'a96': 334,
30095     'a101': 732,
30096     'a102': 544,
30097     'a103': 544,
30098     'a104': 910,
30099     'a106': 667,
30100     'a107': 760,
30101     'a108': 760,
30102     'a112': 776,
30103     'a111': 595,
30104     'a110': 694,
30105     'a109': 626,
30106     'a120': 788,
30107     'a121': 788,
30108     'a122': 788,
30109     'a123': 788,
30110     'a124': 788,
30111     'a125': 788,
30112     'a126': 788,
30113     'a127': 788,
30114     'a128': 788,
30115     'a129': 788,
30116     'a130': 788,
30117     'a131': 788,
30118     'a132': 788,
30119     'a133': 788,
30120     'a134': 788,
30121     'a135': 788,
30122     'a136': 788,
30123     'a137': 788,
30124     'a138': 788,
30125     'a139': 788,
30126     'a140': 788,
30127     'a141': 788,
30128     'a142': 788,
30129     'a143': 788,
30130     'a144': 788,
30131     'a145': 788,
30132     'a146': 788,
30133     'a147': 788,
30134     'a148': 788,
30135     'a149': 788,
30136     'a150': 788,
30137     'a151': 788,
30138     'a152': 788,
30139     'a153': 788,
30140     'a154': 788,
30141     'a155': 788,
30142     'a156': 788,
30143     'a157': 788,
30144     'a158': 788,
30145     'a159': 788,
30146     'a160': 894,
30147     'a161': 838,
30148     'a163': 1016,
30149     'a164': 458,
30150     'a196': 748,
30151     'a165': 924,
30152     'a192': 748,
30153     'a166': 918,
30154     'a167': 927,
30155     'a168': 928,
30156     'a169': 928,
30157     'a170': 834,
30158     'a171': 873,
30159     'a172': 828,
30160     'a173': 924,
30161     'a162': 924,
30162     'a174': 917,
30163     'a175': 930,
30164     'a176': 931,
30165     'a177': 463,
30166     'a178': 883,
30167     'a179': 836,
30168     'a193': 836,
30169     'a180': 867,
30170     'a199': 867,
30171     'a181': 696,
30172     'a200': 696,
30173     'a182': 874,
30174     'a201': 874,
30175     'a183': 760,
30176     'a184': 946,
30177     'a197': 771,
30178     'a185': 865,
30179     'a194': 771,
30180     'a198': 888,
30181     'a186': 967,
30182     'a195': 888,
30183     'a187': 831,
30184     'a188': 873,
30185     'a189': 927,
30186     'a190': 970,
30187     'a191': 918
30188   }
30189 };
30190
30191
30192 var EOF = {};
30193
30194 function isEOF(v) {
30195   return (v === EOF);
30196 }
30197
30198 var MAX_LENGTH_TO_CACHE = 1000;
30199
30200 var Parser = (function ParserClosure() {
30201   function Parser(lexer, allowStreams, xref) {
30202     this.lexer = lexer;
30203     this.allowStreams = allowStreams;
30204     this.xref = xref;
30205     this.imageCache = {};
30206     this.refill();
30207   }
30208
30209   Parser.prototype = {
30210     refill: function Parser_refill() {
30211       this.buf1 = this.lexer.getObj();
30212       this.buf2 = this.lexer.getObj();
30213     },
30214     shift: function Parser_shift() {
30215       if (isCmd(this.buf2, 'ID')) {
30216         this.buf1 = this.buf2;
30217         this.buf2 = null;
30218       } else {
30219         this.buf1 = this.buf2;
30220         this.buf2 = this.lexer.getObj();
30221       }
30222     },
30223     getObj: function Parser_getObj(cipherTransform) {
30224       var buf1 = this.buf1;
30225       this.shift();
30226
30227       if (buf1 instanceof Cmd) {
30228         switch (buf1.cmd) {
30229           case 'BI': // inline image
30230             return this.makeInlineImage(cipherTransform);
30231           case '[': // array
30232             var array = [];
30233             while (!isCmd(this.buf1, ']') && !isEOF(this.buf1)) {
30234               array.push(this.getObj(cipherTransform));
30235             }
30236             if (isEOF(this.buf1)) {
30237               error('End of file inside array');
30238             }
30239             this.shift();
30240             return array;
30241           case '<<': // dictionary or stream
30242             var dict = new Dict(this.xref);
30243             while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
30244               if (!isName(this.buf1)) {
30245                 info('Malformed dictionary: key must be a name object');
30246                 this.shift();
30247                 continue;
30248               }
30249
30250               var key = this.buf1.name;
30251               this.shift();
30252               if (isEOF(this.buf1)) {
30253                 break;
30254               }
30255               dict.set(key, this.getObj(cipherTransform));
30256             }
30257             if (isEOF(this.buf1)) {
30258               error('End of file inside dictionary');
30259             }
30260
30261             // Stream objects are not allowed inside content streams or
30262             // object streams.
30263             if (isCmd(this.buf2, 'stream')) {
30264               return (this.allowStreams ?
30265                       this.makeStream(dict, cipherTransform) : dict);
30266             }
30267             this.shift();
30268             return dict;
30269           default: // simple object
30270             return buf1;
30271         }
30272       }
30273
30274       if (isInt(buf1)) { // indirect reference or integer
30275         var num = buf1;
30276         if (isInt(this.buf1) && isCmd(this.buf2, 'R')) {
30277           var ref = new Ref(num, this.buf1);
30278           this.shift();
30279           this.shift();
30280           return ref;
30281         }
30282         return num;
30283       }
30284
30285       if (isString(buf1)) { // string
30286         var str = buf1;
30287         if (cipherTransform) {
30288           str = cipherTransform.decryptString(str);
30289         }
30290         return str;
30291       }
30292
30293       // simple object
30294       return buf1;
30295     },
30296     /**
30297      * Find the end of the stream by searching for the /EI\s/.
30298      * @returns {number} The inline stream length.
30299      */
30300     findDefaultInlineStreamEnd:
30301         function Parser_findDefaultInlineStreamEnd(stream) {
30302       var E = 0x45, I = 0x49, SPACE = 0x20, LF = 0xA, CR = 0xD;
30303       var startPos = stream.pos, state = 0, ch, i, n, followingBytes;
30304       while ((ch = stream.getByte()) !== -1) {
30305         if (state === 0) {
30306           state = (ch === E) ? 1 : 0;
30307         } else if (state === 1) {
30308           state = (ch === I) ? 2 : 0;
30309         } else {
30310           assert(state === 2);
30311           if (ch === SPACE || ch === LF || ch === CR) {
30312             // Let's check the next five bytes are ASCII... just be sure.
30313             n = 5;
30314             followingBytes = stream.peekBytes(n);
30315             for (i = 0; i < n; i++) {
30316               ch = followingBytes[i];
30317               if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7F)) {
30318                 // Not a LF, CR, SPACE or any visible ASCII character, i.e.
30319                 // it's binary stuff. Resetting the state.
30320                 state = 0;
30321                 break;
30322               }
30323             }
30324             if (state === 2) {
30325               break;  // Finished!
30326             }
30327           } else {
30328             state = 0;
30329           }
30330         }
30331       }
30332       return ((stream.pos - 4) - startPos);
30333     },
30334     /**
30335      * Find the EOI (end-of-image) marker 0xFFD9 of the stream.
30336      * @returns {number} The inline stream length.
30337      */
30338     findDCTDecodeInlineStreamEnd:
30339         function Parser_findDCTDecodeInlineStreamEnd(stream) {
30340       var startPos = stream.pos, foundEOI = false, b, markerLength, length;
30341       while ((b = stream.getByte()) !== -1) {
30342         if (b !== 0xFF) { // Not a valid marker.
30343           continue;
30344         }
30345         switch (stream.getByte()) {
30346           case 0x00: // Byte stuffing.
30347             // 0xFF00 appears to be a very common byte sequence in JPEG images.
30348             break;
30349
30350           case 0xFF: // Fill byte.
30351             // Avoid skipping a valid marker, resetting the stream position.
30352             stream.skip(-1);
30353             break;
30354
30355           case 0xD9: // EOI
30356             foundEOI = true;
30357             break;
30358
30359           case 0xC0: // SOF0
30360           case 0xC1: // SOF1
30361           case 0xC2: // SOF2
30362           case 0xC3: // SOF3
30363
30364           case 0xC5: // SOF5
30365           case 0xC6: // SOF6
30366           case 0xC7: // SOF7
30367
30368           case 0xC9: // SOF9
30369           case 0xCA: // SOF10
30370           case 0xCB: // SOF11
30371
30372           case 0xCD: // SOF13
30373           case 0xCE: // SOF14
30374           case 0xCF: // SOF15
30375
30376           case 0xC4: // DHT
30377           case 0xCC: // DAC
30378
30379           case 0xDA: // SOS
30380           case 0xDB: // DQT
30381           case 0xDC: // DNL
30382           case 0xDD: // DRI
30383           case 0xDE: // DHP
30384           case 0xDF: // EXP
30385
30386           case 0xE0: // APP0
30387           case 0xE1: // APP1
30388           case 0xE2: // APP2
30389           case 0xE3: // APP3
30390           case 0xE4: // APP4
30391           case 0xE5: // APP5
30392           case 0xE6: // APP6
30393           case 0xE7: // APP7
30394           case 0xE8: // APP8
30395           case 0xE9: // APP9
30396           case 0xEA: // APP10
30397           case 0xEB: // APP11
30398           case 0xEC: // APP12
30399           case 0xED: // APP13
30400           case 0xEE: // APP14
30401           case 0xEF: // APP15
30402
30403           case 0xFE: // COM
30404             // The marker should be followed by the length of the segment.
30405             markerLength = stream.getUint16();
30406             if (markerLength > 2) {
30407               // |markerLength| contains the byte length of the marker segment,
30408               // including its own length (2 bytes) and excluding the marker.
30409               stream.skip(markerLength - 2); // Jump to the next marker.
30410             } else {
30411               // The marker length is invalid, resetting the stream position.
30412               stream.skip(-2);
30413             }
30414             break;
30415         }
30416         if (foundEOI) {
30417           break;
30418         }
30419       }
30420       length = stream.pos - startPos;
30421       if (b === -1) {
30422         warn('Inline DCTDecode image stream: ' +
30423              'EOI marker not found, searching for /EI/ instead.');
30424         stream.skip(-length); // Reset the stream position.
30425         return this.findDefaultInlineStreamEnd(stream);
30426       }
30427       this.inlineStreamSkipEI(stream);
30428       return length;
30429     },
30430     /**
30431      * Find the EOD (end-of-data) marker '~>' (i.e. TILDE + GT) of the stream.
30432      * @returns {number} The inline stream length.
30433      */
30434     findASCII85DecodeInlineStreamEnd:
30435         function Parser_findASCII85DecodeInlineStreamEnd(stream) {
30436       var TILDE = 0x7E, GT = 0x3E;
30437       var startPos = stream.pos, ch, length;
30438       while ((ch = stream.getByte()) !== -1) {
30439         if (ch === TILDE && stream.peekByte() === GT) {
30440           stream.skip();
30441           break;
30442         }
30443       }
30444       length = stream.pos - startPos;
30445       if (ch === -1) {
30446         warn('Inline ASCII85Decode image stream: ' +
30447              'EOD marker not found, searching for /EI/ instead.');
30448         stream.skip(-length); // Reset the stream position.
30449         return this.findDefaultInlineStreamEnd(stream);
30450       }
30451       this.inlineStreamSkipEI(stream);
30452       return length;
30453     },
30454     /**
30455      * Find the EOD (end-of-data) marker '>' (i.e. GT) of the stream.
30456      * @returns {number} The inline stream length.
30457      */
30458     findASCIIHexDecodeInlineStreamEnd:
30459         function Parser_findASCIIHexDecodeInlineStreamEnd(stream) {
30460       var GT = 0x3E;
30461       var startPos = stream.pos, ch, length;
30462       while ((ch = stream.getByte()) !== -1) {
30463         if (ch === GT) {
30464           break;
30465         }
30466       }
30467       length = stream.pos - startPos;
30468       if (ch === -1) {
30469         warn('Inline ASCIIHexDecode image stream: ' +
30470              'EOD marker not found, searching for /EI/ instead.');
30471         stream.skip(-length); // Reset the stream position.
30472         return this.findDefaultInlineStreamEnd(stream);
30473       }
30474       this.inlineStreamSkipEI(stream);
30475       return length;
30476     },
30477     /**
30478      * Skip over the /EI/ for streams where we search for an EOD marker.
30479      */
30480     inlineStreamSkipEI: function Parser_inlineStreamSkipEI(stream) {
30481       var E = 0x45, I = 0x49;
30482       var state = 0, ch;
30483       while ((ch = stream.getByte()) !== -1) {
30484         if (state === 0) {
30485           state = (ch === E) ? 1 : 0;
30486         } else if (state === 1) {
30487           state = (ch === I) ? 2 : 0;
30488         } else if (state === 2) {
30489           break;
30490         }
30491       }
30492     },
30493     makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
30494       var lexer = this.lexer;
30495       var stream = lexer.stream;
30496
30497       // Parse dictionary.
30498       var dict = new Dict(null);
30499       while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
30500         if (!isName(this.buf1)) {
30501           error('Dictionary key must be a name object');
30502         }
30503         var key = this.buf1.name;
30504         this.shift();
30505         if (isEOF(this.buf1)) {
30506           break;
30507         }
30508         dict.set(key, this.getObj(cipherTransform));
30509       }
30510
30511       // Extract the name of the first (i.e. the current) image filter.
30512       var filter = this.fetchIfRef(dict.get('Filter', 'F')), filterName;
30513       if (isName(filter)) {
30514         filterName = filter.name;
30515       } else if (isArray(filter) && isName(filter[0])) {
30516         filterName = filter[0].name;
30517       }
30518
30519       // Parse image stream.
30520       var startPos = stream.pos, length, i, ii;
30521       if (filterName === 'DCTDecode' || filterName === 'DCT') {
30522         length = this.findDCTDecodeInlineStreamEnd(stream);
30523       } else if (filterName === 'ASCII85Decide' || filterName === 'A85') {
30524         length = this.findASCII85DecodeInlineStreamEnd(stream);
30525       } else if (filterName === 'ASCIIHexDecode' || filterName === 'AHx') {
30526         length = this.findASCIIHexDecodeInlineStreamEnd(stream);
30527       } else {
30528         length = this.findDefaultInlineStreamEnd(stream);
30529       }
30530       var imageStream = stream.makeSubStream(startPos, length, dict);
30531
30532       // Cache all images below the MAX_LENGTH_TO_CACHE threshold by their
30533       // adler32 checksum.
30534       var adler32;
30535       if (length < MAX_LENGTH_TO_CACHE) {
30536         var imageBytes = imageStream.getBytes();
30537         imageStream.reset();
30538
30539         var a = 1;
30540         var b = 0;
30541         for (i = 0, ii = imageBytes.length; i < ii; ++i) {
30542           // No modulo required in the loop if imageBytes.length < 5552.
30543           a += imageBytes[i] & 0xff;
30544           b += a;
30545         }
30546         adler32 = ((b % 65521) << 16) | (a % 65521);
30547
30548         if (this.imageCache.adler32 === adler32) {
30549           this.buf2 = Cmd.get('EI');
30550           this.shift();
30551
30552           this.imageCache[adler32].reset();
30553           return this.imageCache[adler32];
30554         }
30555       }
30556
30557       if (cipherTransform) {
30558         imageStream = cipherTransform.createStream(imageStream, length);
30559       }
30560
30561       imageStream = this.filter(imageStream, dict, length);
30562       imageStream.dict = dict;
30563       if (adler32 !== undefined) {
30564         imageStream.cacheKey = 'inline_' + length + '_' + adler32;
30565         this.imageCache[adler32] = imageStream;
30566       }
30567
30568       this.buf2 = Cmd.get('EI');
30569       this.shift();
30570
30571       return imageStream;
30572     },
30573     fetchIfRef: function Parser_fetchIfRef(obj) {
30574       // not relying on the xref.fetchIfRef -- xref might not be set
30575       return (isRef(obj) ? this.xref.fetch(obj) : obj);
30576     },
30577     makeStream: function Parser_makeStream(dict, cipherTransform) {
30578       var lexer = this.lexer;
30579       var stream = lexer.stream;
30580
30581       // get stream start position
30582       lexer.skipToNextLine();
30583       var pos = stream.pos - 1;
30584
30585       // get length
30586       var length = this.fetchIfRef(dict.get('Length'));
30587       if (!isInt(length)) {
30588         info('Bad ' + length + ' attribute in stream');
30589         length = 0;
30590       }
30591
30592       // skip over the stream data
30593       stream.pos = pos + length;
30594       lexer.nextChar();
30595
30596       this.shift(); // '>>'
30597       this.shift(); // 'stream'
30598       if (!isCmd(this.buf1, 'endstream')) {
30599         // bad stream length, scanning for endstream
30600         stream.pos = pos;
30601         var SCAN_BLOCK_SIZE = 2048;
30602         var ENDSTREAM_SIGNATURE_LENGTH = 9;
30603         var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65,
30604                                    0x61, 0x6D];
30605         var skipped = 0, found = false, i, j;
30606         while (stream.pos < stream.end) {
30607           var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE);
30608           var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH;
30609           if (scanLength <= 0) {
30610             break;
30611           }
30612           found = false;
30613           for (i = 0, j = 0; i < scanLength; i++) {
30614             var b = scanBytes[i];
30615             if (b !== ENDSTREAM_SIGNATURE[j]) {
30616               i -= j;
30617               j = 0;
30618             } else {
30619               j++;
30620               if (j >= ENDSTREAM_SIGNATURE_LENGTH) {
30621                 i++;
30622                 found = true;
30623                 break;
30624               }
30625             }
30626           }
30627           if (found) {
30628             skipped += i - ENDSTREAM_SIGNATURE_LENGTH;
30629             stream.pos += i - ENDSTREAM_SIGNATURE_LENGTH;
30630             break;
30631           }
30632           skipped += scanLength;
30633           stream.pos += scanLength;
30634         }
30635         if (!found) {
30636           error('Missing endstream');
30637         }
30638         length = skipped;
30639
30640         lexer.nextChar();
30641         this.shift();
30642         this.shift();
30643       }
30644       this.shift(); // 'endstream'
30645
30646       stream = stream.makeSubStream(pos, length, dict);
30647       if (cipherTransform) {
30648         stream = cipherTransform.createStream(stream, length);
30649       }
30650       stream = this.filter(stream, dict, length);
30651       stream.dict = dict;
30652       return stream;
30653     },
30654     filter: function Parser_filter(stream, dict, length) {
30655       var filter = this.fetchIfRef(dict.get('Filter', 'F'));
30656       var params = this.fetchIfRef(dict.get('DecodeParms', 'DP'));
30657       if (isName(filter)) {
30658         return this.makeFilter(stream, filter.name, length, params);
30659       }
30660
30661       var maybeLength = length;
30662       if (isArray(filter)) {
30663         var filterArray = filter;
30664         var paramsArray = params;
30665         for (var i = 0, ii = filterArray.length; i < ii; ++i) {
30666           filter = filterArray[i];
30667           if (!isName(filter)) {
30668             error('Bad filter name: ' + filter);
30669           }
30670
30671           params = null;
30672           if (isArray(paramsArray) && (i in paramsArray)) {
30673             params = paramsArray[i];
30674           }
30675           stream = this.makeFilter(stream, filter.name, maybeLength, params);
30676           // after the first stream the length variable is invalid
30677           maybeLength = null;
30678         }
30679       }
30680       return stream;
30681     },
30682     makeFilter: function Parser_makeFilter(stream, name, maybeLength, params) {
30683       if (stream.dict.get('Length') === 0) {
30684         return new NullStream(stream);
30685       }
30686       try {
30687         if (params) {
30688           params = this.fetchIfRef(params);
30689         }
30690         var xrefStreamStats = this.xref.stats.streamTypes;
30691         if (name === 'FlateDecode' || name === 'Fl') {
30692           xrefStreamStats[StreamType.FLATE] = true;
30693           if (params) {
30694             return new PredictorStream(new FlateStream(stream, maybeLength),
30695                                        maybeLength, params);
30696           }
30697           return new FlateStream(stream, maybeLength);
30698         }
30699         if (name === 'LZWDecode' || name === 'LZW') {
30700           xrefStreamStats[StreamType.LZW] = true;
30701           var earlyChange = 1;
30702           if (params) {
30703             if (params.has('EarlyChange')) {
30704               earlyChange = params.get('EarlyChange');
30705             }
30706             return new PredictorStream(
30707               new LZWStream(stream, maybeLength, earlyChange),
30708               maybeLength, params);
30709           }
30710           return new LZWStream(stream, maybeLength, earlyChange);
30711         }
30712         if (name === 'DCTDecode' || name === 'DCT') {
30713           xrefStreamStats[StreamType.DCT] = true;
30714           return new JpegStream(stream, maybeLength, stream.dict, this.xref);
30715         }
30716         if (name === 'JPXDecode' || name === 'JPX') {
30717           xrefStreamStats[StreamType.JPX] = true;
30718           return new JpxStream(stream, maybeLength, stream.dict);
30719         }
30720         if (name === 'ASCII85Decode' || name === 'A85') {
30721           xrefStreamStats[StreamType.A85] = true;
30722           return new Ascii85Stream(stream, maybeLength);
30723         }
30724         if (name === 'ASCIIHexDecode' || name === 'AHx') {
30725           xrefStreamStats[StreamType.AHX] = true;
30726           return new AsciiHexStream(stream, maybeLength);
30727         }
30728         if (name === 'CCITTFaxDecode' || name === 'CCF') {
30729           xrefStreamStats[StreamType.CCF] = true;
30730           return new CCITTFaxStream(stream, maybeLength, params);
30731         }
30732         if (name === 'RunLengthDecode' || name === 'RL') {
30733           xrefStreamStats[StreamType.RL] = true;
30734           return new RunLengthStream(stream, maybeLength);
30735         }
30736         if (name === 'JBIG2Decode') {
30737           xrefStreamStats[StreamType.JBIG] = true;
30738           return new Jbig2Stream(stream, maybeLength, stream.dict);
30739         }
30740         warn('filter "' + name + '" not supported yet');
30741         return stream;
30742       } catch (ex) {
30743         if (ex instanceof MissingDataException) {
30744           throw ex;
30745         }
30746         warn('Invalid stream: \"' + ex + '\"');
30747         return new NullStream(stream);
30748       }
30749     }
30750   };
30751
30752   return Parser;
30753 })();
30754
30755 var Lexer = (function LexerClosure() {
30756   function Lexer(stream, knownCommands) {
30757     this.stream = stream;
30758     this.nextChar();
30759
30760     // While lexing, we build up many strings one char at a time. Using += for
30761     // this can result in lots of garbage strings. It's better to build an
30762     // array of single-char strings and then join() them together at the end.
30763     // And reusing a single array (i.e. |this.strBuf|) over and over for this
30764     // purpose uses less memory than using a new array for each string.
30765     this.strBuf = [];
30766
30767     // The PDFs might have "glued" commands with other commands, operands or
30768     // literals, e.g. "q1". The knownCommands is a dictionary of the valid
30769     // commands and their prefixes. The prefixes are built the following way:
30770     // if there a command that is a prefix of the other valid command or
30771     // literal (e.g. 'f' and 'false') the following prefixes must be included,
30772     // 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no
30773     // other commands or literals as a prefix. The knowCommands is optional.
30774     this.knownCommands = knownCommands;
30775   }
30776
30777   Lexer.isSpace = function Lexer_isSpace(ch) {
30778     // Space is one of the following characters: SPACE, TAB, CR or LF.
30779     return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A);
30780   };
30781
30782   // A '1' in this array means the character is white space. A '1' or
30783   // '2' means the character ends a name or command.
30784   var specialChars = [
30785     1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
30786     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
30787     1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
30788     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
30789     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
30790     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
30791     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
30792     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
30793     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
30794     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
30795     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
30796     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
30797     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
30798     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
30799     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
30800     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  // fx
30801   ];
30802
30803   function toHexDigit(ch) {
30804     if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
30805       return ch & 0x0F;
30806     }
30807     if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {
30808       // 'A'-'F', 'a'-'f'
30809       return (ch & 0x0F) + 9;
30810     }
30811     return -1;
30812   }
30813
30814   Lexer.prototype = {
30815     nextChar: function Lexer_nextChar() {
30816       return (this.currentChar = this.stream.getByte());
30817     },
30818     peekChar: function Lexer_peekChar() {
30819       return this.stream.peekByte();
30820     },
30821     getNumber: function Lexer_getNumber() {
30822       var ch = this.currentChar;
30823       var eNotation = false;
30824       var divideBy = 0; // different from 0 if it's a floating point value
30825       var sign = 1;
30826
30827       if (ch === 0x2D) { // '-'
30828         sign = -1;
30829         ch = this.nextChar();
30830       } else if (ch === 0x2B) { // '+'
30831         ch = this.nextChar();
30832       }
30833       if (ch === 0x2E) { // '.'
30834         divideBy = 10;
30835         ch = this.nextChar();
30836       }
30837       if (ch < 0x30 || ch > 0x39) { // '0' - '9'
30838         error('Invalid number: ' + String.fromCharCode(ch));
30839         return 0;
30840       }
30841
30842       var baseValue = ch - 0x30; // '0'
30843       var powerValue = 0;
30844       var powerValueSign = 1;
30845
30846       while ((ch = this.nextChar()) >= 0) {
30847         if (0x30 <= ch && ch <= 0x39) { // '0' - '9'
30848           var currentDigit = ch - 0x30; // '0'
30849           if (eNotation) { // We are after an 'e' or 'E'
30850             powerValue = powerValue * 10 + currentDigit;
30851           } else {
30852             if (divideBy !== 0) { // We are after a point
30853               divideBy *= 10;
30854             }
30855             baseValue = baseValue * 10 + currentDigit;
30856           }
30857         } else if (ch === 0x2E) { // '.'
30858           if (divideBy === 0) {
30859             divideBy = 1;
30860           } else {
30861             // A number can have only one '.'
30862             break;
30863           }
30864         } else if (ch === 0x2D) { // '-'
30865           // ignore minus signs in the middle of numbers to match
30866           // Adobe's behavior
30867           warn('Badly formated number');
30868         } else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
30869           // 'E' can be either a scientific notation or the beginning of a new
30870           // operator
30871           ch = this.peekChar();
30872           if (ch === 0x2B || ch === 0x2D) { // '+', '-'
30873             powerValueSign = (ch === 0x2D) ? -1 : 1;
30874             this.nextChar(); // Consume the sign character
30875           } else if (ch < 0x30 || ch > 0x39) { // '0' - '9'
30876             // The 'E' must be the beginning of a new operator
30877             break;
30878           }
30879           eNotation = true;
30880         } else {
30881           // the last character doesn't belong to us
30882           break;
30883         }
30884       }
30885
30886       if (divideBy !== 0) {
30887         baseValue /= divideBy;
30888       }
30889       if (eNotation) {
30890         baseValue *= Math.pow(10, powerValueSign * powerValue);
30891       }
30892       return sign * baseValue;
30893     },
30894     getString: function Lexer_getString() {
30895       var numParen = 1;
30896       var done = false;
30897       var strBuf = this.strBuf;
30898       strBuf.length = 0;
30899
30900       var ch = this.nextChar();
30901       while (true) {
30902         var charBuffered = false;
30903         switch (ch | 0) {
30904           case -1:
30905             warn('Unterminated string');
30906             done = true;
30907             break;
30908           case 0x28: // '('
30909             ++numParen;
30910             strBuf.push('(');
30911             break;
30912           case 0x29: // ')'
30913             if (--numParen === 0) {
30914               this.nextChar(); // consume strings ')'
30915               done = true;
30916             } else {
30917               strBuf.push(')');
30918             }
30919             break;
30920           case 0x5C: // '\\'
30921             ch = this.nextChar();
30922             switch (ch) {
30923               case -1:
30924                 warn('Unterminated string');
30925                 done = true;
30926                 break;
30927               case 0x6E: // 'n'
30928                 strBuf.push('\n');
30929                 break;
30930               case 0x72: // 'r'
30931                 strBuf.push('\r');
30932                 break;
30933               case 0x74: // 't'
30934                 strBuf.push('\t');
30935                 break;
30936               case 0x62: // 'b'
30937                 strBuf.push('\b');
30938                 break;
30939               case 0x66: // 'f'
30940                 strBuf.push('\f');
30941                 break;
30942               case 0x5C: // '\'
30943               case 0x28: // '('
30944               case 0x29: // ')'
30945                 strBuf.push(String.fromCharCode(ch));
30946                 break;
30947               case 0x30: case 0x31: case 0x32: case 0x33: // '0'-'3'
30948               case 0x34: case 0x35: case 0x36: case 0x37: // '4'-'7'
30949                 var x = ch & 0x0F;
30950                 ch = this.nextChar();
30951                 charBuffered = true;
30952                 if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'
30953                   x = (x << 3) + (ch & 0x0F);
30954                   ch = this.nextChar();
30955                   if (ch >= 0x30 && ch <= 0x37) {  // '0'-'7'
30956                     charBuffered = false;
30957                     x = (x << 3) + (ch & 0x0F);
30958                   }
30959                 }
30960                 strBuf.push(String.fromCharCode(x));
30961                 break;
30962               case 0x0D: // CR
30963                 if (this.peekChar() === 0x0A) { // LF
30964                   this.nextChar();
30965                 }
30966                 break;
30967               case 0x0A: // LF
30968                 break;
30969               default:
30970                 strBuf.push(String.fromCharCode(ch));
30971                 break;
30972             }
30973             break;
30974           default:
30975             strBuf.push(String.fromCharCode(ch));
30976             break;
30977         }
30978         if (done) {
30979           break;
30980         }
30981         if (!charBuffered) {
30982           ch = this.nextChar();
30983         }
30984       }
30985       return strBuf.join('');
30986     },
30987     getName: function Lexer_getName() {
30988       var ch;
30989       var strBuf = this.strBuf;
30990       strBuf.length = 0;
30991       while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
30992         if (ch === 0x23) { // '#'
30993           ch = this.nextChar();
30994           var x = toHexDigit(ch);
30995           if (x !== -1) {
30996             var x2 = toHexDigit(this.nextChar());
30997             if (x2 === -1) {
30998               error('Illegal digit in hex char in name: ' + x2);
30999             }
31000             strBuf.push(String.fromCharCode((x << 4) | x2));
31001           } else {
31002             strBuf.push('#', String.fromCharCode(ch));
31003           }
31004         } else {
31005           strBuf.push(String.fromCharCode(ch));
31006         }
31007       }
31008       if (strBuf.length > 128) {
31009         error('Warning: name token is longer than allowed by the spec: ' +
31010               strBuf.length);
31011       }
31012       return Name.get(strBuf.join(''));
31013     },
31014     getHexString: function Lexer_getHexString() {
31015       var strBuf = this.strBuf;
31016       strBuf.length = 0;
31017       var ch = this.currentChar;
31018       var isFirstHex = true;
31019       var firstDigit;
31020       var secondDigit;
31021       while (true) {
31022         if (ch < 0) {
31023           warn('Unterminated hex string');
31024           break;
31025         } else if (ch === 0x3E) { // '>'
31026           this.nextChar();
31027           break;
31028         } else if (specialChars[ch] === 1) {
31029           ch = this.nextChar();
31030           continue;
31031         } else {
31032           if (isFirstHex) {
31033             firstDigit = toHexDigit(ch);
31034             if (firstDigit === -1) {
31035               warn('Ignoring invalid character "' + ch + '" in hex string');
31036               ch = this.nextChar();
31037               continue;
31038             }
31039           } else {
31040             secondDigit = toHexDigit(ch);
31041             if (secondDigit === -1) {
31042               warn('Ignoring invalid character "' + ch + '" in hex string');
31043               ch = this.nextChar();
31044               continue;
31045             }
31046             strBuf.push(String.fromCharCode((firstDigit << 4) | secondDigit));
31047           }
31048           isFirstHex = !isFirstHex;
31049           ch = this.nextChar();
31050         }
31051       }
31052       return strBuf.join('');
31053     },
31054     getObj: function Lexer_getObj() {
31055       // skip whitespace and comments
31056       var comment = false;
31057       var ch = this.currentChar;
31058       while (true) {
31059         if (ch < 0) {
31060           return EOF;
31061         }
31062         if (comment) {
31063           if (ch === 0x0A || ch === 0x0D) { // LF, CR
31064             comment = false;
31065           }
31066         } else if (ch === 0x25) { // '%'
31067           comment = true;
31068         } else if (specialChars[ch] !== 1) {
31069           break;
31070         }
31071         ch = this.nextChar();
31072       }
31073
31074       // start reading token
31075       switch (ch | 0) {
31076         case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
31077         case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
31078         case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
31079           return this.getNumber();
31080         case 0x28: // '('
31081           return this.getString();
31082         case 0x2F: // '/'
31083           return this.getName();
31084         // array punctuation
31085         case 0x5B: // '['
31086           this.nextChar();
31087           return Cmd.get('[');
31088         case 0x5D: // ']'
31089           this.nextChar();
31090           return Cmd.get(']');
31091         // hex string or dict punctuation
31092         case 0x3C: // '<'
31093           ch = this.nextChar();
31094           if (ch === 0x3C) {
31095             // dict punctuation
31096             this.nextChar();
31097             return Cmd.get('<<');
31098           }
31099           return this.getHexString();
31100         // dict punctuation
31101         case 0x3E: // '>'
31102           ch = this.nextChar();
31103           if (ch === 0x3E) {
31104             this.nextChar();
31105             return Cmd.get('>>');
31106           }
31107           return Cmd.get('>');
31108         case 0x7B: // '{'
31109           this.nextChar();
31110           return Cmd.get('{');
31111         case 0x7D: // '}'
31112           this.nextChar();
31113           return Cmd.get('}');
31114         case 0x29: // ')'
31115           error('Illegal character: ' + ch);
31116           break;
31117       }
31118
31119       // command
31120       var str = String.fromCharCode(ch);
31121       var knownCommands = this.knownCommands;
31122       var knownCommandFound = knownCommands && knownCommands[str] !== undefined;
31123       while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
31124         // stop if known command is found and next character does not make
31125         // the str a command
31126         var possibleCommand = str + String.fromCharCode(ch);
31127         if (knownCommandFound && knownCommands[possibleCommand] === undefined) {
31128           break;
31129         }
31130         if (str.length === 128) {
31131           error('Command token too long: ' + str.length);
31132         }
31133         str = possibleCommand;
31134         knownCommandFound = knownCommands && knownCommands[str] !== undefined;
31135       }
31136       if (str === 'true') {
31137         return true;
31138       }
31139       if (str === 'false') {
31140         return false;
31141       }
31142       if (str === 'null') {
31143         return null;
31144       }
31145       return Cmd.get(str);
31146     },
31147     skipToNextLine: function Lexer_skipToNextLine() {
31148       var ch = this.currentChar;
31149       while (ch >= 0) {
31150         if (ch === 0x0D) { // CR
31151           ch = this.nextChar();
31152           if (ch === 0x0A) { // LF
31153             this.nextChar();
31154           }
31155           break;
31156         } else if (ch === 0x0A) { // LF
31157           this.nextChar();
31158           break;
31159         }
31160         ch = this.nextChar();
31161       }
31162     }
31163   };
31164
31165   return Lexer;
31166 })();
31167
31168 var Linearization = {
31169   create: function LinearizationCreate(stream) {
31170     function getInt(name, allowZeroValue) {
31171       var obj = linDict.get(name);
31172       if (isInt(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) {
31173         return obj;
31174       }
31175       throw new Error('The "' + name + '" parameter in the linearization ' +
31176                       'dictionary is invalid.');
31177     }
31178     function getHints() {
31179       var hints = linDict.get('H'), hintsLength, item;
31180       if (isArray(hints) &&
31181           ((hintsLength = hints.length) === 2 || hintsLength === 4)) {
31182         for (var index = 0; index < hintsLength; index++) {
31183           if (!(isInt(item = hints[index]) && item > 0)) {
31184             throw new Error('Hint (' + index +
31185                             ') in the linearization dictionary is invalid.');
31186           }
31187         }
31188         return hints;
31189       }
31190       throw new Error('Hint array in the linearization dictionary is invalid.');
31191     }
31192     var parser = new Parser(new Lexer(stream), false, null);
31193     var obj1 = parser.getObj();
31194     var obj2 = parser.getObj();
31195     var obj3 = parser.getObj();
31196     var linDict = parser.getObj();
31197     var obj, length;
31198     if (!(isInt(obj1) && isInt(obj2) && isCmd(obj3, 'obj') && isDict(linDict) &&
31199           isNum(obj = linDict.get('Linearized')) && obj > 0)) {
31200       return null; // No valid linearization dictionary found.
31201     } else if ((length = getInt('L')) !== stream.length) {
31202       throw new Error('The "L" parameter in the linearization dictionary ' +
31203                       'does not equal the stream length.');
31204     }
31205     return {
31206       length: length,
31207       hints: getHints(),
31208       objectNumberFirst: getInt('O'),
31209       endFirst: getInt('E'),
31210       numPages: getInt('N'),
31211       mainXRefEntriesOffset: getInt('T'),
31212       pageFirst: (linDict.has('P') ? getInt('P', true) : 0)
31213     };
31214   }
31215 };
31216
31217
31218 var PostScriptParser = (function PostScriptParserClosure() {
31219   function PostScriptParser(lexer) {
31220     this.lexer = lexer;
31221     this.operators = [];
31222     this.token = null;
31223     this.prev = null;
31224   }
31225   PostScriptParser.prototype = {
31226     nextToken: function PostScriptParser_nextToken() {
31227       this.prev = this.token;
31228       this.token = this.lexer.getToken();
31229     },
31230     accept: function PostScriptParser_accept(type) {
31231       if (this.token.type === type) {
31232         this.nextToken();
31233         return true;
31234       }
31235       return false;
31236     },
31237     expect: function PostScriptParser_expect(type) {
31238       if (this.accept(type)) {
31239         return true;
31240       }
31241       error('Unexpected symbol: found ' + this.token.type + ' expected ' +
31242         type + '.');
31243     },
31244     parse: function PostScriptParser_parse() {
31245       this.nextToken();
31246       this.expect(PostScriptTokenTypes.LBRACE);
31247       this.parseBlock();
31248       this.expect(PostScriptTokenTypes.RBRACE);
31249       return this.operators;
31250     },
31251     parseBlock: function PostScriptParser_parseBlock() {
31252       while (true) {
31253         if (this.accept(PostScriptTokenTypes.NUMBER)) {
31254           this.operators.push(this.prev.value);
31255         } else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
31256           this.operators.push(this.prev.value);
31257         } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
31258           this.parseCondition();
31259         } else {
31260           return;
31261         }
31262       }
31263     },
31264     parseCondition: function PostScriptParser_parseCondition() {
31265       // Add two place holders that will be updated later
31266       var conditionLocation = this.operators.length;
31267       this.operators.push(null, null);
31268
31269       this.parseBlock();
31270       this.expect(PostScriptTokenTypes.RBRACE);
31271       if (this.accept(PostScriptTokenTypes.IF)) {
31272         // The true block is right after the 'if' so it just falls through on
31273         // true else it jumps and skips the true block.
31274         this.operators[conditionLocation] = this.operators.length;
31275         this.operators[conditionLocation + 1] = 'jz';
31276       } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
31277         var jumpLocation = this.operators.length;
31278         this.operators.push(null, null);
31279         var endOfTrue = this.operators.length;
31280         this.parseBlock();
31281         this.expect(PostScriptTokenTypes.RBRACE);
31282         this.expect(PostScriptTokenTypes.IFELSE);
31283         // The jump is added at the end of the true block to skip the false
31284         // block.
31285         this.operators[jumpLocation] = this.operators.length;
31286         this.operators[jumpLocation + 1] = 'j';
31287
31288         this.operators[conditionLocation] = endOfTrue;
31289         this.operators[conditionLocation + 1] = 'jz';
31290       } else {
31291         error('PS Function: error parsing conditional.');
31292       }
31293     }
31294   };
31295   return PostScriptParser;
31296 })();
31297
31298 var PostScriptTokenTypes = {
31299   LBRACE: 0,
31300   RBRACE: 1,
31301   NUMBER: 2,
31302   OPERATOR: 3,
31303   IF: 4,
31304   IFELSE: 5
31305 };
31306
31307 var PostScriptToken = (function PostScriptTokenClosure() {
31308   function PostScriptToken(type, value) {
31309     this.type = type;
31310     this.value = value;
31311   }
31312
31313   var opCache = {};
31314
31315   PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
31316     var opValue = opCache[op];
31317     if (opValue) {
31318       return opValue;
31319     }
31320     return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
31321   };
31322
31323   PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE,
31324     '{');
31325   PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE,
31326     '}');
31327   PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
31328   PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE,
31329     'IFELSE');
31330   return PostScriptToken;
31331 })();
31332
31333 var PostScriptLexer = (function PostScriptLexerClosure() {
31334   function PostScriptLexer(stream) {
31335     this.stream = stream;
31336     this.nextChar();
31337
31338     this.strBuf = [];
31339   }
31340   PostScriptLexer.prototype = {
31341     nextChar: function PostScriptLexer_nextChar() {
31342       return (this.currentChar = this.stream.getByte());
31343     },
31344     getToken: function PostScriptLexer_getToken() {
31345       var comment = false;
31346       var ch = this.currentChar;
31347
31348       // skip comments
31349       while (true) {
31350         if (ch < 0) {
31351           return EOF;
31352         }
31353
31354         if (comment) {
31355           if (ch === 0x0A || ch === 0x0D) {
31356             comment = false;
31357           }
31358         } else if (ch === 0x25) { // '%'
31359           comment = true;
31360         } else if (!Lexer.isSpace(ch)) {
31361           break;
31362         }
31363         ch = this.nextChar();
31364       }
31365       switch (ch | 0) {
31366         case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
31367         case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
31368         case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
31369           return new PostScriptToken(PostScriptTokenTypes.NUMBER,
31370                                      this.getNumber());
31371         case 0x7B: // '{'
31372           this.nextChar();
31373           return PostScriptToken.LBRACE;
31374         case 0x7D: // '}'
31375           this.nextChar();
31376           return PostScriptToken.RBRACE;
31377       }
31378       // operator
31379       var strBuf = this.strBuf;
31380       strBuf.length = 0;
31381       strBuf[0] = String.fromCharCode(ch);
31382
31383       while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z'
31384              ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) {
31385         strBuf.push(String.fromCharCode(ch));
31386       }
31387       var str = strBuf.join('');
31388       switch (str.toLowerCase()) {
31389         case 'if':
31390           return PostScriptToken.IF;
31391         case 'ifelse':
31392           return PostScriptToken.IFELSE;
31393         default:
31394           return PostScriptToken.getOperator(str);
31395       }
31396     },
31397     getNumber: function PostScriptLexer_getNumber() {
31398       var ch = this.currentChar;
31399       var strBuf = this.strBuf;
31400       strBuf.length = 0;
31401       strBuf[0] = String.fromCharCode(ch);
31402
31403       while ((ch = this.nextChar()) >= 0) {
31404         if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9'
31405             ch === 0x2D || ch === 0x2E) { // '-', '.'
31406           strBuf.push(String.fromCharCode(ch));
31407         } else {
31408           break;
31409         }
31410       }
31411       var value = parseFloat(strBuf.join(''));
31412       if (isNaN(value)) {
31413         error('Invalid floating point number: ' + value);
31414       }
31415       return value;
31416     }
31417   };
31418   return PostScriptLexer;
31419 })();
31420
31421
31422 var Stream = (function StreamClosure() {
31423   function Stream(arrayBuffer, start, length, dict) {
31424     this.bytes = (arrayBuffer instanceof Uint8Array ?
31425                   arrayBuffer : new Uint8Array(arrayBuffer));
31426     this.start = start || 0;
31427     this.pos = this.start;
31428     this.end = (start + length) || this.bytes.length;
31429     this.dict = dict;
31430   }
31431
31432   // required methods for a stream. if a particular stream does not
31433   // implement these, an error should be thrown
31434   Stream.prototype = {
31435     get length() {
31436       return this.end - this.start;
31437     },
31438     get isEmpty() {
31439       return this.length === 0;
31440     },
31441     getByte: function Stream_getByte() {
31442       if (this.pos >= this.end) {
31443         return -1;
31444       }
31445       return this.bytes[this.pos++];
31446     },
31447     getUint16: function Stream_getUint16() {
31448       var b0 = this.getByte();
31449       var b1 = this.getByte();
31450       if (b0 === -1 || b1 === -1) {
31451         return -1;
31452       }
31453       return (b0 << 8) + b1;
31454     },
31455     getInt32: function Stream_getInt32() {
31456       var b0 = this.getByte();
31457       var b1 = this.getByte();
31458       var b2 = this.getByte();
31459       var b3 = this.getByte();
31460       return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
31461     },
31462     // returns subarray of original buffer
31463     // should only be read
31464     getBytes: function Stream_getBytes(length) {
31465       var bytes = this.bytes;
31466       var pos = this.pos;
31467       var strEnd = this.end;
31468
31469       if (!length) {
31470         return bytes.subarray(pos, strEnd);
31471       }
31472       var end = pos + length;
31473       if (end > strEnd) {
31474         end = strEnd;
31475       }
31476       this.pos = end;
31477       return bytes.subarray(pos, end);
31478     },
31479     peekByte: function Stream_peekByte() {
31480       var peekedByte = this.getByte();
31481       this.pos--;
31482       return peekedByte;
31483     },
31484     peekBytes: function Stream_peekBytes(length) {
31485       var bytes = this.getBytes(length);
31486       this.pos -= bytes.length;
31487       return bytes;
31488     },
31489     skip: function Stream_skip(n) {
31490       if (!n) {
31491         n = 1;
31492       }
31493       this.pos += n;
31494     },
31495     reset: function Stream_reset() {
31496       this.pos = this.start;
31497     },
31498     moveStart: function Stream_moveStart() {
31499       this.start = this.pos;
31500     },
31501     makeSubStream: function Stream_makeSubStream(start, length, dict) {
31502       return new Stream(this.bytes.buffer, start, length, dict);
31503     },
31504     isStream: true
31505   };
31506
31507   return Stream;
31508 })();
31509
31510 var StringStream = (function StringStreamClosure() {
31511   function StringStream(str) {
31512     var length = str.length;
31513     var bytes = new Uint8Array(length);
31514     for (var n = 0; n < length; ++n) {
31515       bytes[n] = str.charCodeAt(n);
31516     }
31517     Stream.call(this, bytes);
31518   }
31519
31520   StringStream.prototype = Stream.prototype;
31521
31522   return StringStream;
31523 })();
31524
31525 // super class for the decoding streams
31526 var DecodeStream = (function DecodeStreamClosure() {
31527   // Lots of DecodeStreams are created whose buffers are never used.  For these
31528   // we share a single empty buffer. This is (a) space-efficient and (b) avoids
31529   // having special cases that would be required if we used |null| for an empty
31530   // buffer.
31531   var emptyBuffer = new Uint8Array(0);
31532
31533   function DecodeStream(maybeMinBufferLength) {
31534     this.pos = 0;
31535     this.bufferLength = 0;
31536     this.eof = false;
31537     this.buffer = emptyBuffer;
31538     this.minBufferLength = 512;
31539     if (maybeMinBufferLength) {
31540       // Compute the first power of two that is as big as maybeMinBufferLength.
31541       while (this.minBufferLength < maybeMinBufferLength) {
31542         this.minBufferLength *= 2;
31543       }
31544     }
31545   }
31546
31547   DecodeStream.prototype = {
31548     get isEmpty() {
31549       while (!this.eof && this.bufferLength === 0) {
31550         this.readBlock();
31551       }
31552       return this.bufferLength === 0;
31553     },
31554     ensureBuffer: function DecodeStream_ensureBuffer(requested) {
31555       var buffer = this.buffer;
31556       if (requested <= buffer.byteLength) {
31557         return buffer;
31558       }
31559       var size = this.minBufferLength;
31560       while (size < requested) {
31561         size *= 2;
31562       }
31563       var buffer2 = new Uint8Array(size);
31564       buffer2.set(buffer);
31565       return (this.buffer = buffer2);
31566     },
31567     getByte: function DecodeStream_getByte() {
31568       var pos = this.pos;
31569       while (this.bufferLength <= pos) {
31570         if (this.eof) {
31571           return -1;
31572         }
31573         this.readBlock();
31574       }
31575       return this.buffer[this.pos++];
31576     },
31577     getUint16: function DecodeStream_getUint16() {
31578       var b0 = this.getByte();
31579       var b1 = this.getByte();
31580       if (b0 === -1 || b1 === -1) {
31581         return -1;
31582       }
31583       return (b0 << 8) + b1;
31584     },
31585     getInt32: function DecodeStream_getInt32() {
31586       var b0 = this.getByte();
31587       var b1 = this.getByte();
31588       var b2 = this.getByte();
31589       var b3 = this.getByte();
31590       return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
31591     },
31592     getBytes: function DecodeStream_getBytes(length) {
31593       var end, pos = this.pos;
31594
31595       if (length) {
31596         this.ensureBuffer(pos + length);
31597         end = pos + length;
31598
31599         while (!this.eof && this.bufferLength < end) {
31600           this.readBlock();
31601         }
31602         var bufEnd = this.bufferLength;
31603         if (end > bufEnd) {
31604           end = bufEnd;
31605         }
31606       } else {
31607         while (!this.eof) {
31608           this.readBlock();
31609         }
31610         end = this.bufferLength;
31611       }
31612
31613       this.pos = end;
31614       return this.buffer.subarray(pos, end);
31615     },
31616     peekByte: function DecodeStream_peekByte() {
31617       var peekedByte = this.getByte();
31618       this.pos--;
31619       return peekedByte;
31620     },
31621     peekBytes: function DecodeStream_peekBytes(length) {
31622       var bytes = this.getBytes(length);
31623       this.pos -= bytes.length;
31624       return bytes;
31625     },
31626     makeSubStream: function DecodeStream_makeSubStream(start, length, dict) {
31627       var end = start + length;
31628       while (this.bufferLength <= end && !this.eof) {
31629         this.readBlock();
31630       }
31631       return new Stream(this.buffer, start, length, dict);
31632     },
31633     skip: function DecodeStream_skip(n) {
31634       if (!n) {
31635         n = 1;
31636       }
31637       this.pos += n;
31638     },
31639     reset: function DecodeStream_reset() {
31640       this.pos = 0;
31641     },
31642     getBaseStreams: function DecodeStream_getBaseStreams() {
31643       if (this.str && this.str.getBaseStreams) {
31644         return this.str.getBaseStreams();
31645       }
31646       return [];
31647     }
31648   };
31649
31650   return DecodeStream;
31651 })();
31652
31653 var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
31654   function StreamsSequenceStream(streams) {
31655     this.streams = streams;
31656     DecodeStream.call(this, /* maybeLength = */ null);
31657   }
31658
31659   StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype);
31660
31661   StreamsSequenceStream.prototype.readBlock =
31662       function streamSequenceStreamReadBlock() {
31663
31664     var streams = this.streams;
31665     if (streams.length === 0) {
31666       this.eof = true;
31667       return;
31668     }
31669     var stream = streams.shift();
31670     var chunk = stream.getBytes();
31671     var bufferLength = this.bufferLength;
31672     var newLength = bufferLength + chunk.length;
31673     var buffer = this.ensureBuffer(newLength);
31674     buffer.set(chunk, bufferLength);
31675     this.bufferLength = newLength;
31676   };
31677
31678   StreamsSequenceStream.prototype.getBaseStreams =
31679     function StreamsSequenceStream_getBaseStreams() {
31680
31681     var baseStreams = [];
31682     for (var i = 0, ii = this.streams.length; i < ii; i++) {
31683       var stream = this.streams[i];
31684       if (stream.getBaseStreams) {
31685         Util.appendToArray(baseStreams, stream.getBaseStreams());
31686       }
31687     }
31688     return baseStreams;
31689   };
31690
31691   return StreamsSequenceStream;
31692 })();
31693
31694 var FlateStream = (function FlateStreamClosure() {
31695   var codeLenCodeMap = new Int32Array([
31696     16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
31697   ]);
31698
31699   var lengthDecode = new Int32Array([
31700     0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
31701     0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
31702     0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,
31703     0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
31704   ]);
31705
31706   var distDecode = new Int32Array([
31707     0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
31708     0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
31709     0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,
31710     0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
31711   ]);
31712
31713   var fixedLitCodeTab = [new Int32Array([
31714     0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
31715     0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
31716     0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,
31717     0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,
31718     0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,
31719     0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,
31720     0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,
31721     0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,
31722     0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,
31723     0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,
31724     0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,
31725     0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,
31726     0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,
31727     0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,
31728     0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,
31729     0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,
31730     0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,
31731     0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,
31732     0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,
31733     0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,
31734     0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,
31735     0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,
31736     0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,
31737     0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,
31738     0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,
31739     0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,
31740     0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,
31741     0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,
31742     0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,
31743     0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,
31744     0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,
31745     0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,
31746     0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,
31747     0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,
31748     0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,
31749     0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,
31750     0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,
31751     0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,
31752     0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,
31753     0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,
31754     0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,
31755     0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,
31756     0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,
31757     0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,
31758     0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,
31759     0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,
31760     0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,
31761     0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,
31762     0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,
31763     0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,
31764     0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,
31765     0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,
31766     0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,
31767     0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,
31768     0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,
31769     0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,
31770     0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,
31771     0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,
31772     0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,
31773     0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7,
31774     0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,
31775     0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,
31776     0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,
31777     0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
31778   ]), 9];
31779
31780   var fixedDistCodeTab = [new Int32Array([
31781     0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
31782     0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
31783     0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,
31784     0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
31785   ]), 5];
31786
31787   function FlateStream(str, maybeLength) {
31788     this.str = str;
31789     this.dict = str.dict;
31790
31791     var cmf = str.getByte();
31792     var flg = str.getByte();
31793     if (cmf === -1 || flg === -1) {
31794       error('Invalid header in flate stream: ' + cmf + ', ' + flg);
31795     }
31796     if ((cmf & 0x0f) !== 0x08) {
31797       error('Unknown compression method in flate stream: ' + cmf + ', ' + flg);
31798     }
31799     if ((((cmf << 8) + flg) % 31) !== 0) {
31800       error('Bad FCHECK in flate stream: ' + cmf + ', ' + flg);
31801     }
31802     if (flg & 0x20) {
31803       error('FDICT bit set in flate stream: ' + cmf + ', ' + flg);
31804     }
31805
31806     this.codeSize = 0;
31807     this.codeBuf = 0;
31808
31809     DecodeStream.call(this, maybeLength);
31810   }
31811
31812   FlateStream.prototype = Object.create(DecodeStream.prototype);
31813
31814   FlateStream.prototype.getBits = function FlateStream_getBits(bits) {
31815     var str = this.str;
31816     var codeSize = this.codeSize;
31817     var codeBuf = this.codeBuf;
31818
31819     var b;
31820     while (codeSize < bits) {
31821       if ((b = str.getByte()) === -1) {
31822         error('Bad encoding in flate stream');
31823       }
31824       codeBuf |= b << codeSize;
31825       codeSize += 8;
31826     }
31827     b = codeBuf & ((1 << bits) - 1);
31828     this.codeBuf = codeBuf >> bits;
31829     this.codeSize = codeSize -= bits;
31830
31831     return b;
31832   };
31833
31834   FlateStream.prototype.getCode = function FlateStream_getCode(table) {
31835     var str = this.str;
31836     var codes = table[0];
31837     var maxLen = table[1];
31838     var codeSize = this.codeSize;
31839     var codeBuf = this.codeBuf;
31840
31841     var b;
31842     while (codeSize < maxLen) {
31843       if ((b = str.getByte()) === -1) {
31844         // premature end of stream. code might however still be valid.
31845         // codeSize < codeLen check below guards against incomplete codeVal.
31846         break;
31847       }
31848       codeBuf |= (b << codeSize);
31849       codeSize += 8;
31850     }
31851     var code = codes[codeBuf & ((1 << maxLen) - 1)];
31852     var codeLen = code >> 16;
31853     var codeVal = code & 0xffff;
31854     if (codeLen < 1 || codeSize < codeLen) {
31855       error('Bad encoding in flate stream');
31856     }
31857     this.codeBuf = (codeBuf >> codeLen);
31858     this.codeSize = (codeSize - codeLen);
31859     return codeVal;
31860   };
31861
31862   FlateStream.prototype.generateHuffmanTable =
31863       function flateStreamGenerateHuffmanTable(lengths) {
31864     var n = lengths.length;
31865
31866     // find max code length
31867     var maxLen = 0;
31868     var i;
31869     for (i = 0; i < n; ++i) {
31870       if (lengths[i] > maxLen) {
31871         maxLen = lengths[i];
31872       }
31873     }
31874
31875     // build the table
31876     var size = 1 << maxLen;
31877     var codes = new Int32Array(size);
31878     for (var len = 1, code = 0, skip = 2;
31879          len <= maxLen;
31880          ++len, code <<= 1, skip <<= 1) {
31881       for (var val = 0; val < n; ++val) {
31882         if (lengths[val] === len) {
31883           // bit-reverse the code
31884           var code2 = 0;
31885           var t = code;
31886           for (i = 0; i < len; ++i) {
31887             code2 = (code2 << 1) | (t & 1);
31888             t >>= 1;
31889           }
31890
31891           // fill the table entries
31892           for (i = code2; i < size; i += skip) {
31893             codes[i] = (len << 16) | val;
31894           }
31895           ++code;
31896         }
31897       }
31898     }
31899
31900     return [codes, maxLen];
31901   };
31902
31903   FlateStream.prototype.readBlock = function FlateStream_readBlock() {
31904     var buffer, len;
31905     var str = this.str;
31906     // read block header
31907     var hdr = this.getBits(3);
31908     if (hdr & 1) {
31909       this.eof = true;
31910     }
31911     hdr >>= 1;
31912
31913     if (hdr === 0) { // uncompressed block
31914       var b;
31915
31916       if ((b = str.getByte()) === -1) {
31917         error('Bad block header in flate stream');
31918       }
31919       var blockLen = b;
31920       if ((b = str.getByte()) === -1) {
31921         error('Bad block header in flate stream');
31922       }
31923       blockLen |= (b << 8);
31924       if ((b = str.getByte()) === -1) {
31925         error('Bad block header in flate stream');
31926       }
31927       var check = b;
31928       if ((b = str.getByte()) === -1) {
31929         error('Bad block header in flate stream');
31930       }
31931       check |= (b << 8);
31932       if (check !== (~blockLen & 0xffff) &&
31933           (blockLen !== 0 || check !== 0)) {
31934         // Ignoring error for bad "empty" block (see issue 1277)
31935         error('Bad uncompressed block length in flate stream');
31936       }
31937
31938       this.codeBuf = 0;
31939       this.codeSize = 0;
31940
31941       var bufferLength = this.bufferLength;
31942       buffer = this.ensureBuffer(bufferLength + blockLen);
31943       var end = bufferLength + blockLen;
31944       this.bufferLength = end;
31945       if (blockLen === 0) {
31946         if (str.peekByte() === -1) {
31947           this.eof = true;
31948         }
31949       } else {
31950         for (var n = bufferLength; n < end; ++n) {
31951           if ((b = str.getByte()) === -1) {
31952             this.eof = true;
31953             break;
31954           }
31955           buffer[n] = b;
31956         }
31957       }
31958       return;
31959     }
31960
31961     var litCodeTable;
31962     var distCodeTable;
31963     if (hdr === 1) { // compressed block, fixed codes
31964       litCodeTable = fixedLitCodeTab;
31965       distCodeTable = fixedDistCodeTab;
31966     } else if (hdr === 2) { // compressed block, dynamic codes
31967       var numLitCodes = this.getBits(5) + 257;
31968       var numDistCodes = this.getBits(5) + 1;
31969       var numCodeLenCodes = this.getBits(4) + 4;
31970
31971       // build the code lengths code table
31972       var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length);
31973
31974       var i;
31975       for (i = 0; i < numCodeLenCodes; ++i) {
31976         codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3);
31977       }
31978       var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
31979
31980       // build the literal and distance code tables
31981       len = 0;
31982       i = 0;
31983       var codes = numLitCodes + numDistCodes;
31984       var codeLengths = new Uint8Array(codes);
31985       var bitsLength, bitsOffset, what;
31986       while (i < codes) {
31987         var code = this.getCode(codeLenCodeTab);
31988         if (code === 16) {
31989           bitsLength = 2; bitsOffset = 3; what = len;
31990         } else if (code === 17) {
31991           bitsLength = 3; bitsOffset = 3; what = (len = 0);
31992         } else if (code === 18) {
31993           bitsLength = 7; bitsOffset = 11; what = (len = 0);
31994         } else {
31995           codeLengths[i++] = len = code;
31996           continue;
31997         }
31998
31999         var repeatLength = this.getBits(bitsLength) + bitsOffset;
32000         while (repeatLength-- > 0) {
32001           codeLengths[i++] = what;
32002         }
32003       }
32004
32005       litCodeTable =
32006         this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes));
32007       distCodeTable =
32008         this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes));
32009     } else {
32010       error('Unknown block type in flate stream');
32011     }
32012
32013     buffer = this.buffer;
32014     var limit = buffer ? buffer.length : 0;
32015     var pos = this.bufferLength;
32016     while (true) {
32017       var code1 = this.getCode(litCodeTable);
32018       if (code1 < 256) {
32019         if (pos + 1 >= limit) {
32020           buffer = this.ensureBuffer(pos + 1);
32021           limit = buffer.length;
32022         }
32023         buffer[pos++] = code1;
32024         continue;
32025       }
32026       if (code1 === 256) {
32027         this.bufferLength = pos;
32028         return;
32029       }
32030       code1 -= 257;
32031       code1 = lengthDecode[code1];
32032       var code2 = code1 >> 16;
32033       if (code2 > 0) {
32034         code2 = this.getBits(code2);
32035       }
32036       len = (code1 & 0xffff) + code2;
32037       code1 = this.getCode(distCodeTable);
32038       code1 = distDecode[code1];
32039       code2 = code1 >> 16;
32040       if (code2 > 0) {
32041         code2 = this.getBits(code2);
32042       }
32043       var dist = (code1 & 0xffff) + code2;
32044       if (pos + len >= limit) {
32045         buffer = this.ensureBuffer(pos + len);
32046         limit = buffer.length;
32047       }
32048       for (var k = 0; k < len; ++k, ++pos) {
32049         buffer[pos] = buffer[pos - dist];
32050       }
32051     }
32052   };
32053
32054   return FlateStream;
32055 })();
32056
32057 var PredictorStream = (function PredictorStreamClosure() {
32058   function PredictorStream(str, maybeLength, params) {
32059     var predictor = this.predictor = params.get('Predictor') || 1;
32060
32061     if (predictor <= 1) {
32062       return str; // no prediction
32063     }
32064     if (predictor !== 2 && (predictor < 10 || predictor > 15)) {
32065       error('Unsupported predictor: ' + predictor);
32066     }
32067
32068     if (predictor === 2) {
32069       this.readBlock = this.readBlockTiff;
32070     } else {
32071       this.readBlock = this.readBlockPng;
32072     }
32073
32074     this.str = str;
32075     this.dict = str.dict;
32076
32077     var colors = this.colors = params.get('Colors') || 1;
32078     var bits = this.bits = params.get('BitsPerComponent') || 8;
32079     var columns = this.columns = params.get('Columns') || 1;
32080
32081     this.pixBytes = (colors * bits + 7) >> 3;
32082     this.rowBytes = (columns * colors * bits + 7) >> 3;
32083
32084     DecodeStream.call(this, maybeLength);
32085     return this;
32086   }
32087
32088   PredictorStream.prototype = Object.create(DecodeStream.prototype);
32089
32090   PredictorStream.prototype.readBlockTiff =
32091       function predictorStreamReadBlockTiff() {
32092     var rowBytes = this.rowBytes;
32093
32094     var bufferLength = this.bufferLength;
32095     var buffer = this.ensureBuffer(bufferLength + rowBytes);
32096
32097     var bits = this.bits;
32098     var colors = this.colors;
32099
32100     var rawBytes = this.str.getBytes(rowBytes);
32101     this.eof = !rawBytes.length;
32102     if (this.eof) {
32103       return;
32104     }
32105
32106     var inbuf = 0, outbuf = 0;
32107     var inbits = 0, outbits = 0;
32108     var pos = bufferLength;
32109     var i;
32110
32111     if (bits === 1) {
32112       for (i = 0; i < rowBytes; ++i) {
32113         var c = rawBytes[i];
32114         inbuf = (inbuf << 8) | c;
32115         // bitwise addition is exclusive or
32116         // first shift inbuf and then add
32117         buffer[pos++] = (c ^ (inbuf >> colors)) & 0xFF;
32118         // truncate inbuf (assumes colors < 16)
32119         inbuf &= 0xFFFF;
32120       }
32121     } else if (bits === 8) {
32122       for (i = 0; i < colors; ++i) {
32123         buffer[pos++] = rawBytes[i];
32124       }
32125       for (; i < rowBytes; ++i) {
32126         buffer[pos] = buffer[pos - colors] + rawBytes[i];
32127         pos++;
32128       }
32129     } else {
32130       var compArray = new Uint8Array(colors + 1);
32131       var bitMask = (1 << bits) - 1;
32132       var j = 0, k = bufferLength;
32133       var columns = this.columns;
32134       for (i = 0; i < columns; ++i) {
32135         for (var kk = 0; kk < colors; ++kk) {
32136           if (inbits < bits) {
32137             inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);
32138             inbits += 8;
32139           }
32140           compArray[kk] = (compArray[kk] +
32141                            (inbuf >> (inbits - bits))) & bitMask;
32142           inbits -= bits;
32143           outbuf = (outbuf << bits) | compArray[kk];
32144           outbits += bits;
32145           if (outbits >= 8) {
32146             buffer[k++] = (outbuf >> (outbits - 8)) & 0xFF;
32147             outbits -= 8;
32148           }
32149         }
32150       }
32151       if (outbits > 0) {
32152         buffer[k++] = (outbuf << (8 - outbits)) +
32153                       (inbuf & ((1 << (8 - outbits)) - 1));
32154       }
32155     }
32156     this.bufferLength += rowBytes;
32157   };
32158
32159   PredictorStream.prototype.readBlockPng =
32160       function predictorStreamReadBlockPng() {
32161
32162     var rowBytes = this.rowBytes;
32163     var pixBytes = this.pixBytes;
32164
32165     var predictor = this.str.getByte();
32166     var rawBytes = this.str.getBytes(rowBytes);
32167     this.eof = !rawBytes.length;
32168     if (this.eof) {
32169       return;
32170     }
32171
32172     var bufferLength = this.bufferLength;
32173     var buffer = this.ensureBuffer(bufferLength + rowBytes);
32174
32175     var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
32176     if (prevRow.length === 0) {
32177       prevRow = new Uint8Array(rowBytes);
32178     }
32179
32180     var i, j = bufferLength, up, c;
32181     switch (predictor) {
32182       case 0:
32183         for (i = 0; i < rowBytes; ++i) {
32184           buffer[j++] = rawBytes[i];
32185         }
32186         break;
32187       case 1:
32188         for (i = 0; i < pixBytes; ++i) {
32189           buffer[j++] = rawBytes[i];
32190         }
32191         for (; i < rowBytes; ++i) {
32192           buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xFF;
32193           j++;
32194         }
32195         break;
32196       case 2:
32197         for (i = 0; i < rowBytes; ++i) {
32198           buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF;
32199         }
32200         break;
32201       case 3:
32202         for (i = 0; i < pixBytes; ++i) {
32203           buffer[j++] = (prevRow[i] >> 1) + rawBytes[i];
32204         }
32205         for (; i < rowBytes; ++i) {
32206           buffer[j] = (((prevRow[i] + buffer[j - pixBytes]) >> 1) +
32207                            rawBytes[i]) & 0xFF;
32208           j++;
32209         }
32210         break;
32211       case 4:
32212         // we need to save the up left pixels values. the simplest way
32213         // is to create a new buffer
32214         for (i = 0; i < pixBytes; ++i) {
32215           up = prevRow[i];
32216           c = rawBytes[i];
32217           buffer[j++] = up + c;
32218         }
32219         for (; i < rowBytes; ++i) {
32220           up = prevRow[i];
32221           var upLeft = prevRow[i - pixBytes];
32222           var left = buffer[j - pixBytes];
32223           var p = left + up - upLeft;
32224
32225           var pa = p - left;
32226           if (pa < 0) {
32227             pa = -pa;
32228           }
32229           var pb = p - up;
32230           if (pb < 0) {
32231             pb = -pb;
32232           }
32233           var pc = p - upLeft;
32234           if (pc < 0) {
32235             pc = -pc;
32236           }
32237
32238           c = rawBytes[i];
32239           if (pa <= pb && pa <= pc) {
32240             buffer[j++] = left + c;
32241           } else if (pb <= pc) {
32242             buffer[j++] = up + c;
32243           } else {
32244             buffer[j++] = upLeft + c;
32245           }
32246         }
32247         break;
32248       default:
32249         error('Unsupported predictor: ' + predictor);
32250     }
32251     this.bufferLength += rowBytes;
32252   };
32253
32254   return PredictorStream;
32255 })();
32256
32257 /**
32258  * Depending on the type of JPEG a JpegStream is handled in different ways. For
32259  * JPEG's that are supported natively such as DeviceGray and DeviceRGB the image
32260  * data is stored and then loaded by the browser.  For unsupported JPEG's we use
32261  * a library to decode these images and the stream behaves like all the other
32262  * DecodeStreams.
32263  */
32264 var JpegStream = (function JpegStreamClosure() {
32265   function JpegStream(stream, maybeLength, dict, xref) {
32266     // Some images may contain 'junk' before the SOI (start-of-image) marker.
32267     // Note: this seems to mainly affect inline images.
32268     var ch;
32269     while ((ch = stream.getByte()) !== -1) {
32270       if (ch === 0xFF) { // Find the first byte of the SOI marker (0xFFD8).
32271         stream.skip(-1); // Reset the stream position to the SOI.
32272         break;
32273       }
32274     }
32275     this.stream = stream;
32276     this.maybeLength = maybeLength;
32277     this.dict = dict;
32278
32279     DecodeStream.call(this, maybeLength);
32280   }
32281
32282   JpegStream.prototype = Object.create(DecodeStream.prototype);
32283
32284   Object.defineProperty(JpegStream.prototype, 'bytes', {
32285     get: function JpegStream_bytes() {
32286       // If this.maybeLength is null, we'll get the entire stream.
32287       return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
32288     },
32289     configurable: true
32290   });
32291
32292   JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
32293     if (this.bufferLength) {
32294       return;
32295     }
32296     try {
32297       var jpegImage = new JpegImage();
32298
32299       // checking if values needs to be transformed before conversion
32300       if (this.forceRGB && this.dict && isArray(this.dict.get('Decode'))) {
32301         var decodeArr = this.dict.get('Decode');
32302         var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
32303         var decodeArrLength = decodeArr.length;
32304         var transform = new Int32Array(decodeArrLength);
32305         var transformNeeded = false;
32306         var maxValue = (1 << bitsPerComponent) - 1;
32307         for (var i = 0; i < decodeArrLength; i += 2) {
32308           transform[i] = ((decodeArr[i + 1] - decodeArr[i]) * 256) | 0;
32309           transform[i + 1] = (decodeArr[i] * maxValue) | 0;
32310           if (transform[i] !== 256 || transform[i + 1] !== 0) {
32311             transformNeeded = true;
32312           }
32313         }
32314         if (transformNeeded) {
32315           jpegImage.decodeTransform = transform;
32316         }
32317       }
32318
32319       jpegImage.parse(this.bytes);
32320       var data = jpegImage.getData(this.drawWidth, this.drawHeight,
32321                                    this.forceRGB);
32322       this.buffer = data;
32323       this.bufferLength = data.length;
32324       this.eof = true;
32325     } catch (e) {
32326       error('JPEG error: ' + e);
32327     }
32328   };
32329
32330   JpegStream.prototype.getBytes = function JpegStream_getBytes(length) {
32331     this.ensureBuffer();
32332     return this.buffer;
32333   };
32334
32335   JpegStream.prototype.getIR = function JpegStream_getIR() {
32336     return PDFJS.createObjectURL(this.bytes, 'image/jpeg');
32337   };
32338   /**
32339    * Checks if the image can be decoded and displayed by the browser without any
32340    * further processing such as color space conversions.
32341    */
32342   JpegStream.prototype.isNativelySupported =
32343       function JpegStream_isNativelySupported(xref, res) {
32344     var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
32345     return cs.name === 'DeviceGray' || cs.name === 'DeviceRGB';
32346   };
32347   /**
32348    * Checks if the image can be decoded by the browser.
32349    */
32350   JpegStream.prototype.isNativelyDecodable =
32351       function JpegStream_isNativelyDecodable(xref, res) {
32352     var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
32353     var numComps = cs.numComps;
32354     return numComps === 1 || numComps === 3;
32355   };
32356
32357   return JpegStream;
32358 })();
32359
32360 /**
32361  * For JPEG 2000's we use a library to decode these images and
32362  * the stream behaves like all the other DecodeStreams.
32363  */
32364 var JpxStream = (function JpxStreamClosure() {
32365   function JpxStream(stream, maybeLength, dict) {
32366     this.stream = stream;
32367     this.maybeLength = maybeLength;
32368     this.dict = dict;
32369
32370     DecodeStream.call(this, maybeLength);
32371   }
32372
32373   JpxStream.prototype = Object.create(DecodeStream.prototype);
32374
32375   Object.defineProperty(JpxStream.prototype, 'bytes', {
32376     get: function JpxStream_bytes() {
32377       // If this.maybeLength is null, we'll get the entire stream.
32378       return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
32379     },
32380     configurable: true
32381   });
32382
32383   JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {
32384     if (this.bufferLength) {
32385       return;
32386     }
32387
32388     var jpxImage = new JpxImage();
32389     jpxImage.parse(this.bytes);
32390
32391     var width = jpxImage.width;
32392     var height = jpxImage.height;
32393     var componentsCount = jpxImage.componentsCount;
32394     var tileCount = jpxImage.tiles.length;
32395     if (tileCount === 1) {
32396       this.buffer = jpxImage.tiles[0].items;
32397     } else {
32398       var data = new Uint8Array(width * height * componentsCount);
32399
32400       for (var k = 0; k < tileCount; k++) {
32401         var tileComponents = jpxImage.tiles[k];
32402         var tileWidth = tileComponents.width;
32403         var tileHeight = tileComponents.height;
32404         var tileLeft = tileComponents.left;
32405         var tileTop = tileComponents.top;
32406
32407         var src = tileComponents.items;
32408         var srcPosition = 0;
32409         var dataPosition = (width * tileTop + tileLeft) * componentsCount;
32410         var imgRowSize = width * componentsCount;
32411         var tileRowSize = tileWidth * componentsCount;
32412
32413         for (var j = 0; j < tileHeight; j++) {
32414           var rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);
32415           data.set(rowBytes, dataPosition);
32416           srcPosition += tileRowSize;
32417           dataPosition += imgRowSize;
32418         }
32419       }
32420       this.buffer = data;
32421     }
32422     this.bufferLength = this.buffer.length;
32423     this.eof = true;
32424   };
32425
32426   return JpxStream;
32427 })();
32428
32429 /**
32430  * For JBIG2's we use a library to decode these images and
32431  * the stream behaves like all the other DecodeStreams.
32432  */
32433 var Jbig2Stream = (function Jbig2StreamClosure() {
32434   function Jbig2Stream(stream, maybeLength, dict) {
32435     this.stream = stream;
32436     this.maybeLength = maybeLength;
32437     this.dict = dict;
32438
32439     DecodeStream.call(this, maybeLength);
32440   }
32441
32442   Jbig2Stream.prototype = Object.create(DecodeStream.prototype);
32443
32444   Object.defineProperty(Jbig2Stream.prototype, 'bytes', {
32445     get: function Jbig2Stream_bytes() {
32446       // If this.maybeLength is null, we'll get the entire stream.
32447       return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
32448     },
32449     configurable: true
32450   });
32451
32452   Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) {
32453     if (this.bufferLength) {
32454       return;
32455     }
32456
32457     var jbig2Image = new Jbig2Image();
32458
32459     var chunks = [], xref = this.dict.xref;
32460     var decodeParams = xref.fetchIfRef(this.dict.get('DecodeParms'));
32461
32462     // According to the PDF specification, DecodeParms can be either
32463     // a dictionary, or an array whose elements are dictionaries.
32464     if (isArray(decodeParams)) {
32465       if (decodeParams.length > 1) {
32466         warn('JBIG2 - \'DecodeParms\' array with multiple elements ' +
32467              'not supported.');
32468       }
32469       decodeParams = xref.fetchIfRef(decodeParams[0]);
32470     }
32471     if (decodeParams && decodeParams.has('JBIG2Globals')) {
32472       var globalsStream = decodeParams.get('JBIG2Globals');
32473       var globals = globalsStream.getBytes();
32474       chunks.push({data: globals, start: 0, end: globals.length});
32475     }
32476     chunks.push({data: this.bytes, start: 0, end: this.bytes.length});
32477     var data = jbig2Image.parseChunks(chunks);
32478     var dataLength = data.length;
32479
32480     // JBIG2 had black as 1 and white as 0, inverting the colors
32481     for (var i = 0; i < dataLength; i++) {
32482       data[i] ^= 0xFF;
32483     }
32484
32485     this.buffer = data;
32486     this.bufferLength = dataLength;
32487     this.eof = true;
32488   };
32489
32490   return Jbig2Stream;
32491 })();
32492
32493 var DecryptStream = (function DecryptStreamClosure() {
32494   function DecryptStream(str, maybeLength, decrypt) {
32495     this.str = str;
32496     this.dict = str.dict;
32497     this.decrypt = decrypt;
32498     this.nextChunk = null;
32499     this.initialized = false;
32500
32501     DecodeStream.call(this, maybeLength);
32502   }
32503
32504   var chunkSize = 512;
32505
32506   DecryptStream.prototype = Object.create(DecodeStream.prototype);
32507
32508   DecryptStream.prototype.readBlock = function DecryptStream_readBlock() {
32509     var chunk;
32510     if (this.initialized) {
32511       chunk = this.nextChunk;
32512     } else {
32513       chunk = this.str.getBytes(chunkSize);
32514       this.initialized = true;
32515     }
32516     if (!chunk || chunk.length === 0) {
32517       this.eof = true;
32518       return;
32519     }
32520     this.nextChunk = this.str.getBytes(chunkSize);
32521     var hasMoreData = this.nextChunk && this.nextChunk.length > 0;
32522
32523     var decrypt = this.decrypt;
32524     chunk = decrypt(chunk, !hasMoreData);
32525
32526     var bufferLength = this.bufferLength;
32527     var i, n = chunk.length;
32528     var buffer = this.ensureBuffer(bufferLength + n);
32529     for (i = 0; i < n; i++) {
32530       buffer[bufferLength++] = chunk[i];
32531     }
32532     this.bufferLength = bufferLength;
32533   };
32534
32535   return DecryptStream;
32536 })();
32537
32538 var Ascii85Stream = (function Ascii85StreamClosure() {
32539   function Ascii85Stream(str, maybeLength) {
32540     this.str = str;
32541     this.dict = str.dict;
32542     this.input = new Uint8Array(5);
32543
32544     // Most streams increase in size when decoded, but Ascii85 streams
32545     // typically shrink by ~20%.
32546     if (maybeLength) {
32547       maybeLength = 0.8 * maybeLength;
32548     }
32549     DecodeStream.call(this, maybeLength);
32550   }
32551
32552   Ascii85Stream.prototype = Object.create(DecodeStream.prototype);
32553
32554   Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() {
32555     var TILDA_CHAR = 0x7E; // '~'
32556     var Z_LOWER_CHAR = 0x7A; // 'z'
32557     var EOF = -1;
32558
32559     var str = this.str;
32560
32561     var c = str.getByte();
32562     while (Lexer.isSpace(c)) {
32563       c = str.getByte();
32564     }
32565
32566     if (c === EOF || c === TILDA_CHAR) {
32567       this.eof = true;
32568       return;
32569     }
32570
32571     var bufferLength = this.bufferLength, buffer;
32572     var i;
32573
32574     // special code for z
32575     if (c === Z_LOWER_CHAR) {
32576       buffer = this.ensureBuffer(bufferLength + 4);
32577       for (i = 0; i < 4; ++i) {
32578         buffer[bufferLength + i] = 0;
32579       }
32580       this.bufferLength += 4;
32581     } else {
32582       var input = this.input;
32583       input[0] = c;
32584       for (i = 1; i < 5; ++i) {
32585         c = str.getByte();
32586         while (Lexer.isSpace(c)) {
32587           c = str.getByte();
32588         }
32589
32590         input[i] = c;
32591
32592         if (c === EOF || c === TILDA_CHAR) {
32593           break;
32594         }
32595       }
32596       buffer = this.ensureBuffer(bufferLength + i - 1);
32597       this.bufferLength += i - 1;
32598
32599       // partial ending;
32600       if (i < 5) {
32601         for (; i < 5; ++i) {
32602           input[i] = 0x21 + 84;
32603         }
32604         this.eof = true;
32605       }
32606       var t = 0;
32607       for (i = 0; i < 5; ++i) {
32608         t = t * 85 + (input[i] - 0x21);
32609       }
32610
32611       for (i = 3; i >= 0; --i) {
32612         buffer[bufferLength + i] = t & 0xFF;
32613         t >>= 8;
32614       }
32615     }
32616   };
32617
32618   return Ascii85Stream;
32619 })();
32620
32621 var AsciiHexStream = (function AsciiHexStreamClosure() {
32622   function AsciiHexStream(str, maybeLength) {
32623     this.str = str;
32624     this.dict = str.dict;
32625
32626     this.firstDigit = -1;
32627
32628     // Most streams increase in size when decoded, but AsciiHex streams shrink
32629     // by 50%.
32630     if (maybeLength) {
32631       maybeLength = 0.5 * maybeLength;
32632     }
32633     DecodeStream.call(this, maybeLength);
32634   }
32635
32636   AsciiHexStream.prototype = Object.create(DecodeStream.prototype);
32637
32638   AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() {
32639     var UPSTREAM_BLOCK_SIZE = 8000;
32640     var bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE);
32641     if (!bytes.length) {
32642       this.eof = true;
32643       return;
32644     }
32645
32646     var maxDecodeLength = (bytes.length + 1) >> 1;
32647     var buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength);
32648     var bufferLength = this.bufferLength;
32649
32650     var firstDigit = this.firstDigit;
32651     for (var i = 0, ii = bytes.length; i < ii; i++) {
32652       var ch = bytes[i], digit;
32653       if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
32654         digit = ch & 0x0F;
32655       } else if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {
32656         // 'A'-'Z', 'a'-'z'
32657         digit = (ch & 0x0F) + 9;
32658       } else if (ch === 0x3E) { // '>'
32659         this.eof = true;
32660         break;
32661       } else { // probably whitespace
32662         continue; // ignoring
32663       }
32664       if (firstDigit < 0) {
32665         firstDigit = digit;
32666       } else {
32667         buffer[bufferLength++] = (firstDigit << 4) | digit;
32668         firstDigit = -1;
32669       }
32670     }
32671     if (firstDigit >= 0 && this.eof) {
32672       // incomplete byte
32673       buffer[bufferLength++] = (firstDigit << 4);
32674       firstDigit = -1;
32675     }
32676     this.firstDigit = firstDigit;
32677     this.bufferLength = bufferLength;
32678   };
32679
32680   return AsciiHexStream;
32681 })();
32682
32683 var RunLengthStream = (function RunLengthStreamClosure() {
32684   function RunLengthStream(str, maybeLength) {
32685     this.str = str;
32686     this.dict = str.dict;
32687
32688     DecodeStream.call(this, maybeLength);
32689   }
32690
32691   RunLengthStream.prototype = Object.create(DecodeStream.prototype);
32692
32693   RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() {
32694     // The repeatHeader has following format. The first byte defines type of run
32695     // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes
32696     // (in addition to the second byte from the header), n = 129 through 255 -
32697     // duplicate the second byte from the header (257 - n) times, n = 128 - end.
32698     var repeatHeader = this.str.getBytes(2);
32699     if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] === 128) {
32700       this.eof = true;
32701       return;
32702     }
32703
32704     var buffer;
32705     var bufferLength = this.bufferLength;
32706     var n = repeatHeader[0];
32707     if (n < 128) {
32708       // copy n bytes
32709       buffer = this.ensureBuffer(bufferLength + n + 1);
32710       buffer[bufferLength++] = repeatHeader[1];
32711       if (n > 0) {
32712         var source = this.str.getBytes(n);
32713         buffer.set(source, bufferLength);
32714         bufferLength += n;
32715       }
32716     } else {
32717       n = 257 - n;
32718       var b = repeatHeader[1];
32719       buffer = this.ensureBuffer(bufferLength + n + 1);
32720       for (var i = 0; i < n; i++) {
32721         buffer[bufferLength++] = b;
32722       }
32723     }
32724     this.bufferLength = bufferLength;
32725   };
32726
32727   return RunLengthStream;
32728 })();
32729
32730 var CCITTFaxStream = (function CCITTFaxStreamClosure() {
32731
32732   var ccittEOL = -2;
32733   var twoDimPass = 0;
32734   var twoDimHoriz = 1;
32735   var twoDimVert0 = 2;
32736   var twoDimVertR1 = 3;
32737   var twoDimVertL1 = 4;
32738   var twoDimVertR2 = 5;
32739   var twoDimVertL2 = 6;
32740   var twoDimVertR3 = 7;
32741   var twoDimVertL3 = 8;
32742
32743   var twoDimTable = [
32744     [-1, -1], [-1, -1],                   // 000000x
32745     [7, twoDimVertL3],                    // 0000010
32746     [7, twoDimVertR3],                    // 0000011
32747     [6, twoDimVertL2], [6, twoDimVertL2], // 000010x
32748     [6, twoDimVertR2], [6, twoDimVertR2], // 000011x
32749     [4, twoDimPass], [4, twoDimPass],     // 0001xxx
32750     [4, twoDimPass], [4, twoDimPass],
32751     [4, twoDimPass], [4, twoDimPass],
32752     [4, twoDimPass], [4, twoDimPass],
32753     [3, twoDimHoriz], [3, twoDimHoriz],   // 001xxxx
32754     [3, twoDimHoriz], [3, twoDimHoriz],
32755     [3, twoDimHoriz], [3, twoDimHoriz],
32756     [3, twoDimHoriz], [3, twoDimHoriz],
32757     [3, twoDimHoriz], [3, twoDimHoriz],
32758     [3, twoDimHoriz], [3, twoDimHoriz],
32759     [3, twoDimHoriz], [3, twoDimHoriz],
32760     [3, twoDimHoriz], [3, twoDimHoriz],
32761     [3, twoDimVertL1], [3, twoDimVertL1], // 010xxxx
32762     [3, twoDimVertL1], [3, twoDimVertL1],
32763     [3, twoDimVertL1], [3, twoDimVertL1],
32764     [3, twoDimVertL1], [3, twoDimVertL1],
32765     [3, twoDimVertL1], [3, twoDimVertL1],
32766     [3, twoDimVertL1], [3, twoDimVertL1],
32767     [3, twoDimVertL1], [3, twoDimVertL1],
32768     [3, twoDimVertL1], [3, twoDimVertL1],
32769     [3, twoDimVertR1], [3, twoDimVertR1], // 011xxxx
32770     [3, twoDimVertR1], [3, twoDimVertR1],
32771     [3, twoDimVertR1], [3, twoDimVertR1],
32772     [3, twoDimVertR1], [3, twoDimVertR1],
32773     [3, twoDimVertR1], [3, twoDimVertR1],
32774     [3, twoDimVertR1], [3, twoDimVertR1],
32775     [3, twoDimVertR1], [3, twoDimVertR1],
32776     [3, twoDimVertR1], [3, twoDimVertR1],
32777     [1, twoDimVert0], [1, twoDimVert0],   // 1xxxxxx
32778     [1, twoDimVert0], [1, twoDimVert0],
32779     [1, twoDimVert0], [1, twoDimVert0],
32780     [1, twoDimVert0], [1, twoDimVert0],
32781     [1, twoDimVert0], [1, twoDimVert0],
32782     [1, twoDimVert0], [1, twoDimVert0],
32783     [1, twoDimVert0], [1, twoDimVert0],
32784     [1, twoDimVert0], [1, twoDimVert0],
32785     [1, twoDimVert0], [1, twoDimVert0],
32786     [1, twoDimVert0], [1, twoDimVert0],
32787     [1, twoDimVert0], [1, twoDimVert0],
32788     [1, twoDimVert0], [1, twoDimVert0],
32789     [1, twoDimVert0], [1, twoDimVert0],
32790     [1, twoDimVert0], [1, twoDimVert0],
32791     [1, twoDimVert0], [1, twoDimVert0],
32792     [1, twoDimVert0], [1, twoDimVert0],
32793     [1, twoDimVert0], [1, twoDimVert0],
32794     [1, twoDimVert0], [1, twoDimVert0],
32795     [1, twoDimVert0], [1, twoDimVert0],
32796     [1, twoDimVert0], [1, twoDimVert0],
32797     [1, twoDimVert0], [1, twoDimVert0],
32798     [1, twoDimVert0], [1, twoDimVert0],
32799     [1, twoDimVert0], [1, twoDimVert0],
32800     [1, twoDimVert0], [1, twoDimVert0],
32801     [1, twoDimVert0], [1, twoDimVert0],
32802     [1, twoDimVert0], [1, twoDimVert0],
32803     [1, twoDimVert0], [1, twoDimVert0],
32804     [1, twoDimVert0], [1, twoDimVert0],
32805     [1, twoDimVert0], [1, twoDimVert0],
32806     [1, twoDimVert0], [1, twoDimVert0],
32807     [1, twoDimVert0], [1, twoDimVert0],
32808     [1, twoDimVert0], [1, twoDimVert0]
32809   ];
32810
32811   var whiteTable1 = [
32812     [-1, -1],                               // 00000
32813     [12, ccittEOL],                         // 00001
32814     [-1, -1], [-1, -1],                     // 0001x
32815     [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 001xx
32816     [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 010xx
32817     [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 011xx
32818     [11, 1792], [11, 1792],                 // 1000x
32819     [12, 1984],                             // 10010
32820     [12, 2048],                             // 10011
32821     [12, 2112],                             // 10100
32822     [12, 2176],                             // 10101
32823     [12, 2240],                             // 10110
32824     [12, 2304],                             // 10111
32825     [11, 1856], [11, 1856],                 // 1100x
32826     [11, 1920], [11, 1920],                 // 1101x
32827     [12, 2368],                             // 11100
32828     [12, 2432],                             // 11101
32829     [12, 2496],                             // 11110
32830     [12, 2560]                              // 11111
32831   ];
32832
32833   var whiteTable2 = [
32834     [-1, -1], [-1, -1], [-1, -1], [-1, -1],     // 0000000xx
32835     [8, 29], [8, 29],                           // 00000010x
32836     [8, 30], [8, 30],                           // 00000011x
32837     [8, 45], [8, 45],                           // 00000100x
32838     [8, 46], [8, 46],                           // 00000101x
32839     [7, 22], [7, 22], [7, 22], [7, 22],         // 0000011xx
32840     [7, 23], [7, 23], [7, 23], [7, 23],         // 0000100xx
32841     [8, 47], [8, 47],                           // 00001010x
32842     [8, 48], [8, 48],                           // 00001011x
32843     [6, 13], [6, 13], [6, 13], [6, 13],         // 000011xxx
32844     [6, 13], [6, 13], [6, 13], [6, 13],
32845     [7, 20], [7, 20], [7, 20], [7, 20],         // 0001000xx
32846     [8, 33], [8, 33],                           // 00010010x
32847     [8, 34], [8, 34],                           // 00010011x
32848     [8, 35], [8, 35],                           // 00010100x
32849     [8, 36], [8, 36],                           // 00010101x
32850     [8, 37], [8, 37],                           // 00010110x
32851     [8, 38], [8, 38],                           // 00010111x
32852     [7, 19], [7, 19], [7, 19], [7, 19],         // 0001100xx
32853     [8, 31], [8, 31],                           // 00011010x
32854     [8, 32], [8, 32],                           // 00011011x
32855     [6, 1], [6, 1], [6, 1], [6, 1],             // 000111xxx
32856     [6, 1], [6, 1], [6, 1], [6, 1],
32857     [6, 12], [6, 12], [6, 12], [6, 12],         // 001000xxx
32858     [6, 12], [6, 12], [6, 12], [6, 12],
32859     [8, 53], [8, 53],                           // 00100100x
32860     [8, 54], [8, 54],                           // 00100101x
32861     [7, 26], [7, 26], [7, 26], [7, 26],         // 0010011xx
32862     [8, 39], [8, 39],                           // 00101000x
32863     [8, 40], [8, 40],                           // 00101001x
32864     [8, 41], [8, 41],                           // 00101010x
32865     [8, 42], [8, 42],                           // 00101011x
32866     [8, 43], [8, 43],                           // 00101100x
32867     [8, 44], [8, 44],                           // 00101101x
32868     [7, 21], [7, 21], [7, 21], [7, 21],         // 0010111xx
32869     [7, 28], [7, 28], [7, 28], [7, 28],         // 0011000xx
32870     [8, 61], [8, 61],                           // 00110010x
32871     [8, 62], [8, 62],                           // 00110011x
32872     [8, 63], [8, 63],                           // 00110100x
32873     [8, 0], [8, 0],                             // 00110101x
32874     [8, 320], [8, 320],                         // 00110110x
32875     [8, 384], [8, 384],                         // 00110111x
32876     [5, 10], [5, 10], [5, 10], [5, 10],         // 00111xxxx
32877     [5, 10], [5, 10], [5, 10], [5, 10],
32878     [5, 10], [5, 10], [5, 10], [5, 10],
32879     [5, 10], [5, 10], [5, 10], [5, 10],
32880     [5, 11], [5, 11], [5, 11], [5, 11],         // 01000xxxx
32881     [5, 11], [5, 11], [5, 11], [5, 11],
32882     [5, 11], [5, 11], [5, 11], [5, 11],
32883     [5, 11], [5, 11], [5, 11], [5, 11],
32884     [7, 27], [7, 27], [7, 27], [7, 27],         // 0100100xx
32885     [8, 59], [8, 59],                           // 01001010x
32886     [8, 60], [8, 60],                           // 01001011x
32887     [9, 1472],                                  // 010011000
32888     [9, 1536],                                  // 010011001
32889     [9, 1600],                                  // 010011010
32890     [9, 1728],                                  // 010011011
32891     [7, 18], [7, 18], [7, 18], [7, 18],         // 0100111xx
32892     [7, 24], [7, 24], [7, 24], [7, 24],         // 0101000xx
32893     [8, 49], [8, 49],                           // 01010010x
32894     [8, 50], [8, 50],                           // 01010011x
32895     [8, 51], [8, 51],                           // 01010100x
32896     [8, 52], [8, 52],                           // 01010101x
32897     [7, 25], [7, 25], [7, 25], [7, 25],         // 0101011xx
32898     [8, 55], [8, 55],                           // 01011000x
32899     [8, 56], [8, 56],                           // 01011001x
32900     [8, 57], [8, 57],                           // 01011010x
32901     [8, 58], [8, 58],                           // 01011011x
32902     [6, 192], [6, 192], [6, 192], [6, 192],     // 010111xxx
32903     [6, 192], [6, 192], [6, 192], [6, 192],
32904     [6, 1664], [6, 1664], [6, 1664], [6, 1664], // 011000xxx
32905     [6, 1664], [6, 1664], [6, 1664], [6, 1664],
32906     [8, 448], [8, 448],                         // 01100100x
32907     [8, 512], [8, 512],                         // 01100101x
32908     [9, 704],                                   // 011001100
32909     [9, 768],                                   // 011001101
32910     [8, 640], [8, 640],                         // 01100111x
32911     [8, 576], [8, 576],                         // 01101000x
32912     [9, 832],                                   // 011010010
32913     [9, 896],                                   // 011010011
32914     [9, 960],                                   // 011010100
32915     [9, 1024],                                  // 011010101
32916     [9, 1088],                                  // 011010110
32917     [9, 1152],                                  // 011010111
32918     [9, 1216],                                  // 011011000
32919     [9, 1280],                                  // 011011001
32920     [9, 1344],                                  // 011011010
32921     [9, 1408],                                  // 011011011
32922     [7, 256], [7, 256], [7, 256], [7, 256],     // 0110111xx
32923     [4, 2], [4, 2], [4, 2], [4, 2],             // 0111xxxxx
32924     [4, 2], [4, 2], [4, 2], [4, 2],
32925     [4, 2], [4, 2], [4, 2], [4, 2],
32926     [4, 2], [4, 2], [4, 2], [4, 2],
32927     [4, 2], [4, 2], [4, 2], [4, 2],
32928     [4, 2], [4, 2], [4, 2], [4, 2],
32929     [4, 2], [4, 2], [4, 2], [4, 2],
32930     [4, 2], [4, 2], [4, 2], [4, 2],
32931     [4, 3], [4, 3], [4, 3], [4, 3],             // 1000xxxxx
32932     [4, 3], [4, 3], [4, 3], [4, 3],
32933     [4, 3], [4, 3], [4, 3], [4, 3],
32934     [4, 3], [4, 3], [4, 3], [4, 3],
32935     [4, 3], [4, 3], [4, 3], [4, 3],
32936     [4, 3], [4, 3], [4, 3], [4, 3],
32937     [4, 3], [4, 3], [4, 3], [4, 3],
32938     [4, 3], [4, 3], [4, 3], [4, 3],
32939     [5, 128], [5, 128], [5, 128], [5, 128],     // 10010xxxx
32940     [5, 128], [5, 128], [5, 128], [5, 128],
32941     [5, 128], [5, 128], [5, 128], [5, 128],
32942     [5, 128], [5, 128], [5, 128], [5, 128],
32943     [5, 8], [5, 8], [5, 8], [5, 8],             // 10011xxxx
32944     [5, 8], [5, 8], [5, 8], [5, 8],
32945     [5, 8], [5, 8], [5, 8], [5, 8],
32946     [5, 8], [5, 8], [5, 8], [5, 8],
32947     [5, 9], [5, 9], [5, 9], [5, 9],             // 10100xxxx
32948     [5, 9], [5, 9], [5, 9], [5, 9],
32949     [5, 9], [5, 9], [5, 9], [5, 9],
32950     [5, 9], [5, 9], [5, 9], [5, 9],
32951     [6, 16], [6, 16], [6, 16], [6, 16],         // 101010xxx
32952     [6, 16], [6, 16], [6, 16], [6, 16],
32953     [6, 17], [6, 17], [6, 17], [6, 17],         // 101011xxx
32954     [6, 17], [6, 17], [6, 17], [6, 17],
32955     [4, 4], [4, 4], [4, 4], [4, 4],             // 1011xxxxx
32956     [4, 4], [4, 4], [4, 4], [4, 4],
32957     [4, 4], [4, 4], [4, 4], [4, 4],
32958     [4, 4], [4, 4], [4, 4], [4, 4],
32959     [4, 4], [4, 4], [4, 4], [4, 4],
32960     [4, 4], [4, 4], [4, 4], [4, 4],
32961     [4, 4], [4, 4], [4, 4], [4, 4],
32962     [4, 4], [4, 4], [4, 4], [4, 4],
32963     [4, 5], [4, 5], [4, 5], [4, 5],             // 1100xxxxx
32964     [4, 5], [4, 5], [4, 5], [4, 5],
32965     [4, 5], [4, 5], [4, 5], [4, 5],
32966     [4, 5], [4, 5], [4, 5], [4, 5],
32967     [4, 5], [4, 5], [4, 5], [4, 5],
32968     [4, 5], [4, 5], [4, 5], [4, 5],
32969     [4, 5], [4, 5], [4, 5], [4, 5],
32970     [4, 5], [4, 5], [4, 5], [4, 5],
32971     [6, 14], [6, 14], [6, 14], [6, 14],         // 110100xxx
32972     [6, 14], [6, 14], [6, 14], [6, 14],
32973     [6, 15], [6, 15], [6, 15], [6, 15],         // 110101xxx
32974     [6, 15], [6, 15], [6, 15], [6, 15],
32975     [5, 64], [5, 64], [5, 64], [5, 64],         // 11011xxxx
32976     [5, 64], [5, 64], [5, 64], [5, 64],
32977     [5, 64], [5, 64], [5, 64], [5, 64],
32978     [5, 64], [5, 64], [5, 64], [5, 64],
32979     [4, 6], [4, 6], [4, 6], [4, 6],             // 1110xxxxx
32980     [4, 6], [4, 6], [4, 6], [4, 6],
32981     [4, 6], [4, 6], [4, 6], [4, 6],
32982     [4, 6], [4, 6], [4, 6], [4, 6],
32983     [4, 6], [4, 6], [4, 6], [4, 6],
32984     [4, 6], [4, 6], [4, 6], [4, 6],
32985     [4, 6], [4, 6], [4, 6], [4, 6],
32986     [4, 6], [4, 6], [4, 6], [4, 6],
32987     [4, 7], [4, 7], [4, 7], [4, 7],             // 1111xxxxx
32988     [4, 7], [4, 7], [4, 7], [4, 7],
32989     [4, 7], [4, 7], [4, 7], [4, 7],
32990     [4, 7], [4, 7], [4, 7], [4, 7],
32991     [4, 7], [4, 7], [4, 7], [4, 7],
32992     [4, 7], [4, 7], [4, 7], [4, 7],
32993     [4, 7], [4, 7], [4, 7], [4, 7],
32994     [4, 7], [4, 7], [4, 7], [4, 7]
32995   ];
32996
32997   var blackTable1 = [
32998     [-1, -1], [-1, -1],                             // 000000000000x
32999     [12, ccittEOL], [12, ccittEOL],                 // 000000000001x
33000     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000001xx
33001     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000010xx
33002     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000011xx
33003     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000100xx
33004     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000101xx
33005     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000110xx
33006     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000111xx
33007     [11, 1792], [11, 1792], [11, 1792], [11, 1792], // 00000001000xx
33008     [12, 1984], [12, 1984],                         // 000000010010x
33009     [12, 2048], [12, 2048],                         // 000000010011x
33010     [12, 2112], [12, 2112],                         // 000000010100x
33011     [12, 2176], [12, 2176],                         // 000000010101x
33012     [12, 2240], [12, 2240],                         // 000000010110x
33013     [12, 2304], [12, 2304],                         // 000000010111x
33014     [11, 1856], [11, 1856], [11, 1856], [11, 1856], // 00000001100xx
33015     [11, 1920], [11, 1920], [11, 1920], [11, 1920], // 00000001101xx
33016     [12, 2368], [12, 2368],                         // 000000011100x
33017     [12, 2432], [12, 2432],                         // 000000011101x
33018     [12, 2496], [12, 2496],                         // 000000011110x
33019     [12, 2560], [12, 2560],                         // 000000011111x
33020     [10, 18], [10, 18], [10, 18], [10, 18],         // 0000001000xxx
33021     [10, 18], [10, 18], [10, 18], [10, 18],
33022     [12, 52], [12, 52],                             // 000000100100x
33023     [13, 640],                                      // 0000001001010
33024     [13, 704],                                      // 0000001001011
33025     [13, 768],                                      // 0000001001100
33026     [13, 832],                                      // 0000001001101
33027     [12, 55], [12, 55],                             // 000000100111x
33028     [12, 56], [12, 56],                             // 000000101000x
33029     [13, 1280],                                     // 0000001010010
33030     [13, 1344],                                     // 0000001010011
33031     [13, 1408],                                     // 0000001010100
33032     [13, 1472],                                     // 0000001010101
33033     [12, 59], [12, 59],                             // 000000101011x
33034     [12, 60], [12, 60],                             // 000000101100x
33035     [13, 1536],                                     // 0000001011010
33036     [13, 1600],                                     // 0000001011011
33037     [11, 24], [11, 24], [11, 24], [11, 24],         // 00000010111xx
33038     [11, 25], [11, 25], [11, 25], [11, 25],         // 00000011000xx
33039     [13, 1664],                                     // 0000001100100
33040     [13, 1728],                                     // 0000001100101
33041     [12, 320], [12, 320],                           // 000000110011x
33042     [12, 384], [12, 384],                           // 000000110100x
33043     [12, 448], [12, 448],                           // 000000110101x
33044     [13, 512],                                      // 0000001101100
33045     [13, 576],                                      // 0000001101101
33046     [12, 53], [12, 53],                             // 000000110111x
33047     [12, 54], [12, 54],                             // 000000111000x
33048     [13, 896],                                      // 0000001110010
33049     [13, 960],                                      // 0000001110011
33050     [13, 1024],                                     // 0000001110100
33051     [13, 1088],                                     // 0000001110101
33052     [13, 1152],                                     // 0000001110110
33053     [13, 1216],                                     // 0000001110111
33054     [10, 64], [10, 64], [10, 64], [10, 64],         // 0000001111xxx
33055     [10, 64], [10, 64], [10, 64], [10, 64]
33056   ];
33057
33058   var blackTable2 = [
33059     [8, 13], [8, 13], [8, 13], [8, 13],     // 00000100xxxx
33060     [8, 13], [8, 13], [8, 13], [8, 13],
33061     [8, 13], [8, 13], [8, 13], [8, 13],
33062     [8, 13], [8, 13], [8, 13], [8, 13],
33063     [11, 23], [11, 23],                     // 00000101000x
33064     [12, 50],                               // 000001010010
33065     [12, 51],                               // 000001010011
33066     [12, 44],                               // 000001010100
33067     [12, 45],                               // 000001010101
33068     [12, 46],                               // 000001010110
33069     [12, 47],                               // 000001010111
33070     [12, 57],                               // 000001011000
33071     [12, 58],                               // 000001011001
33072     [12, 61],                               // 000001011010
33073     [12, 256],                              // 000001011011
33074     [10, 16], [10, 16], [10, 16], [10, 16], // 0000010111xx
33075     [10, 17], [10, 17], [10, 17], [10, 17], // 0000011000xx
33076     [12, 48],                               // 000001100100
33077     [12, 49],                               // 000001100101
33078     [12, 62],                               // 000001100110
33079     [12, 63],                               // 000001100111
33080     [12, 30],                               // 000001101000
33081     [12, 31],                               // 000001101001
33082     [12, 32],                               // 000001101010
33083     [12, 33],                               // 000001101011
33084     [12, 40],                               // 000001101100
33085     [12, 41],                               // 000001101101
33086     [11, 22], [11, 22],                     // 00000110111x
33087     [8, 14], [8, 14], [8, 14], [8, 14],     // 00000111xxxx
33088     [8, 14], [8, 14], [8, 14], [8, 14],
33089     [8, 14], [8, 14], [8, 14], [8, 14],
33090     [8, 14], [8, 14], [8, 14], [8, 14],
33091     [7, 10], [7, 10], [7, 10], [7, 10],     // 0000100xxxxx
33092     [7, 10], [7, 10], [7, 10], [7, 10],
33093     [7, 10], [7, 10], [7, 10], [7, 10],
33094     [7, 10], [7, 10], [7, 10], [7, 10],
33095     [7, 10], [7, 10], [7, 10], [7, 10],
33096     [7, 10], [7, 10], [7, 10], [7, 10],
33097     [7, 10], [7, 10], [7, 10], [7, 10],
33098     [7, 10], [7, 10], [7, 10], [7, 10],
33099     [7, 11], [7, 11], [7, 11], [7, 11],     // 0000101xxxxx
33100     [7, 11], [7, 11], [7, 11], [7, 11],
33101     [7, 11], [7, 11], [7, 11], [7, 11],
33102     [7, 11], [7, 11], [7, 11], [7, 11],
33103     [7, 11], [7, 11], [7, 11], [7, 11],
33104     [7, 11], [7, 11], [7, 11], [7, 11],
33105     [7, 11], [7, 11], [7, 11], [7, 11],
33106     [7, 11], [7, 11], [7, 11], [7, 11],
33107     [9, 15], [9, 15], [9, 15], [9, 15],     // 000011000xxx
33108     [9, 15], [9, 15], [9, 15], [9, 15],
33109     [12, 128],                              // 000011001000
33110     [12, 192],                              // 000011001001
33111     [12, 26],                               // 000011001010
33112     [12, 27],                               // 000011001011
33113     [12, 28],                               // 000011001100
33114     [12, 29],                               // 000011001101
33115     [11, 19], [11, 19],                     // 00001100111x
33116     [11, 20], [11, 20],                     // 00001101000x
33117     [12, 34],                               // 000011010010
33118     [12, 35],                               // 000011010011
33119     [12, 36],                               // 000011010100
33120     [12, 37],                               // 000011010101
33121     [12, 38],                               // 000011010110
33122     [12, 39],                               // 000011010111
33123     [11, 21], [11, 21],                     // 00001101100x
33124     [12, 42],                               // 000011011010
33125     [12, 43],                               // 000011011011
33126     [10, 0], [10, 0], [10, 0], [10, 0],     // 0000110111xx
33127     [7, 12], [7, 12], [7, 12], [7, 12],     // 0000111xxxxx
33128     [7, 12], [7, 12], [7, 12], [7, 12],
33129     [7, 12], [7, 12], [7, 12], [7, 12],
33130     [7, 12], [7, 12], [7, 12], [7, 12],
33131     [7, 12], [7, 12], [7, 12], [7, 12],
33132     [7, 12], [7, 12], [7, 12], [7, 12],
33133     [7, 12], [7, 12], [7, 12], [7, 12],
33134     [7, 12], [7, 12], [7, 12], [7, 12]
33135   ];
33136
33137   var blackTable3 = [
33138     [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000xx
33139     [6, 9],                                 // 000100
33140     [6, 8],                                 // 000101
33141     [5, 7], [5, 7],                         // 00011x
33142     [4, 6], [4, 6], [4, 6], [4, 6],         // 0010xx
33143     [4, 5], [4, 5], [4, 5], [4, 5],         // 0011xx
33144     [3, 1], [3, 1], [3, 1], [3, 1],         // 010xxx
33145     [3, 1], [3, 1], [3, 1], [3, 1],
33146     [3, 4], [3, 4], [3, 4], [3, 4],         // 011xxx
33147     [3, 4], [3, 4], [3, 4], [3, 4],
33148     [2, 3], [2, 3], [2, 3], [2, 3],         // 10xxxx
33149     [2, 3], [2, 3], [2, 3], [2, 3],
33150     [2, 3], [2, 3], [2, 3], [2, 3],
33151     [2, 3], [2, 3], [2, 3], [2, 3],
33152     [2, 2], [2, 2], [2, 2], [2, 2],         // 11xxxx
33153     [2, 2], [2, 2], [2, 2], [2, 2],
33154     [2, 2], [2, 2], [2, 2], [2, 2],
33155     [2, 2], [2, 2], [2, 2], [2, 2]
33156   ];
33157
33158   function CCITTFaxStream(str, maybeLength, params) {
33159     this.str = str;
33160     this.dict = str.dict;
33161
33162     params = params || Dict.empty;
33163
33164     this.encoding = params.get('K') || 0;
33165     this.eoline = params.get('EndOfLine') || false;
33166     this.byteAlign = params.get('EncodedByteAlign') || false;
33167     this.columns = params.get('Columns') || 1728;
33168     this.rows = params.get('Rows') || 0;
33169     var eoblock = params.get('EndOfBlock');
33170     if (eoblock === null || eoblock === undefined) {
33171       eoblock = true;
33172     }
33173     this.eoblock = eoblock;
33174     this.black = params.get('BlackIs1') || false;
33175
33176     this.codingLine = new Uint32Array(this.columns + 1);
33177     this.refLine = new Uint32Array(this.columns + 2);
33178
33179     this.codingLine[0] = this.columns;
33180     this.codingPos = 0;
33181
33182     this.row = 0;
33183     this.nextLine2D = this.encoding < 0;
33184     this.inputBits = 0;
33185     this.inputBuf = 0;
33186     this.outputBits = 0;
33187
33188     var code1;
33189     while ((code1 = this.lookBits(12)) === 0) {
33190       this.eatBits(1);
33191     }
33192     if (code1 === 1) {
33193       this.eatBits(12);
33194     }
33195     if (this.encoding > 0) {
33196       this.nextLine2D = !this.lookBits(1);
33197       this.eatBits(1);
33198     }
33199
33200     DecodeStream.call(this, maybeLength);
33201   }
33202
33203   CCITTFaxStream.prototype = Object.create(DecodeStream.prototype);
33204
33205   CCITTFaxStream.prototype.readBlock = function CCITTFaxStream_readBlock() {
33206     while (!this.eof) {
33207       var c = this.lookChar();
33208       this.ensureBuffer(this.bufferLength + 1);
33209       this.buffer[this.bufferLength++] = c;
33210     }
33211   };
33212
33213   CCITTFaxStream.prototype.addPixels =
33214       function ccittFaxStreamAddPixels(a1, blackPixels) {
33215     var codingLine = this.codingLine;
33216     var codingPos = this.codingPos;
33217
33218     if (a1 > codingLine[codingPos]) {
33219       if (a1 > this.columns) {
33220         info('row is wrong length');
33221         this.err = true;
33222         a1 = this.columns;
33223       }
33224       if ((codingPos & 1) ^ blackPixels) {
33225         ++codingPos;
33226       }
33227
33228       codingLine[codingPos] = a1;
33229     }
33230     this.codingPos = codingPos;
33231   };
33232
33233   CCITTFaxStream.prototype.addPixelsNeg =
33234       function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {
33235     var codingLine = this.codingLine;
33236     var codingPos = this.codingPos;
33237
33238     if (a1 > codingLine[codingPos]) {
33239       if (a1 > this.columns) {
33240         info('row is wrong length');
33241         this.err = true;
33242         a1 = this.columns;
33243       }
33244       if ((codingPos & 1) ^ blackPixels) {
33245         ++codingPos;
33246       }
33247
33248       codingLine[codingPos] = a1;
33249     } else if (a1 < codingLine[codingPos]) {
33250       if (a1 < 0) {
33251         info('invalid code');
33252         this.err = true;
33253         a1 = 0;
33254       }
33255       while (codingPos > 0 && a1 < codingLine[codingPos - 1]) {
33256         --codingPos;
33257       }
33258       codingLine[codingPos] = a1;
33259     }
33260
33261     this.codingPos = codingPos;
33262   };
33263
33264   CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() {
33265     var refLine = this.refLine;
33266     var codingLine = this.codingLine;
33267     var columns = this.columns;
33268
33269     var refPos, blackPixels, bits, i;
33270
33271     if (this.outputBits === 0) {
33272       if (this.eof) {
33273         return null;
33274       }
33275       this.err = false;
33276
33277       var code1, code2, code3;
33278       if (this.nextLine2D) {
33279         for (i = 0; codingLine[i] < columns; ++i) {
33280           refLine[i] = codingLine[i];
33281         }
33282         refLine[i++] = columns;
33283         refLine[i] = columns;
33284         codingLine[0] = 0;
33285         this.codingPos = 0;
33286         refPos = 0;
33287         blackPixels = 0;
33288
33289         while (codingLine[this.codingPos] < columns) {
33290           code1 = this.getTwoDimCode();
33291           switch (code1) {
33292             case twoDimPass:
33293               this.addPixels(refLine[refPos + 1], blackPixels);
33294               if (refLine[refPos + 1] < columns) {
33295                 refPos += 2;
33296               }
33297               break;
33298             case twoDimHoriz:
33299               code1 = code2 = 0;
33300               if (blackPixels) {
33301                 do {
33302                   code1 += (code3 = this.getBlackCode());
33303                 } while (code3 >= 64);
33304                 do {
33305                   code2 += (code3 = this.getWhiteCode());
33306                 } while (code3 >= 64);
33307               } else {
33308                 do {
33309                   code1 += (code3 = this.getWhiteCode());
33310                 } while (code3 >= 64);
33311                 do {
33312                   code2 += (code3 = this.getBlackCode());
33313                 } while (code3 >= 64);
33314               }
33315               this.addPixels(codingLine[this.codingPos] +
33316                              code1, blackPixels);
33317               if (codingLine[this.codingPos] < columns) {
33318                 this.addPixels(codingLine[this.codingPos] + code2,
33319                                blackPixels ^ 1);
33320               }
33321               while (refLine[refPos] <= codingLine[this.codingPos] &&
33322                      refLine[refPos] < columns) {
33323                 refPos += 2;
33324               }
33325               break;
33326             case twoDimVertR3:
33327               this.addPixels(refLine[refPos] + 3, blackPixels);
33328               blackPixels ^= 1;
33329               if (codingLine[this.codingPos] < columns) {
33330                 ++refPos;
33331                 while (refLine[refPos] <= codingLine[this.codingPos] &&
33332                        refLine[refPos] < columns) {
33333                   refPos += 2;
33334                 }
33335               }
33336               break;
33337             case twoDimVertR2:
33338               this.addPixels(refLine[refPos] + 2, blackPixels);
33339               blackPixels ^= 1;
33340               if (codingLine[this.codingPos] < columns) {
33341                 ++refPos;
33342                 while (refLine[refPos] <= codingLine[this.codingPos] &&
33343                        refLine[refPos] < columns) {
33344                   refPos += 2;
33345                 }
33346               }
33347               break;
33348             case twoDimVertR1:
33349               this.addPixels(refLine[refPos] + 1, blackPixels);
33350               blackPixels ^= 1;
33351               if (codingLine[this.codingPos] < columns) {
33352                 ++refPos;
33353                 while (refLine[refPos] <= codingLine[this.codingPos] &&
33354                        refLine[refPos] < columns) {
33355                   refPos += 2;
33356                 }
33357               }
33358               break;
33359             case twoDimVert0:
33360               this.addPixels(refLine[refPos], blackPixels);
33361               blackPixels ^= 1;
33362               if (codingLine[this.codingPos] < columns) {
33363                 ++refPos;
33364                 while (refLine[refPos] <= codingLine[this.codingPos] &&
33365                        refLine[refPos] < columns) {
33366                   refPos += 2;
33367                 }
33368               }
33369               break;
33370             case twoDimVertL3:
33371               this.addPixelsNeg(refLine[refPos] - 3, blackPixels);
33372               blackPixels ^= 1;
33373               if (codingLine[this.codingPos] < columns) {
33374                 if (refPos > 0) {
33375                   --refPos;
33376                 } else {
33377                   ++refPos;
33378                 }
33379                 while (refLine[refPos] <= codingLine[this.codingPos] &&
33380                        refLine[refPos] < columns) {
33381                   refPos += 2;
33382                 }
33383               }
33384               break;
33385             case twoDimVertL2:
33386               this.addPixelsNeg(refLine[refPos] - 2, blackPixels);
33387               blackPixels ^= 1;
33388               if (codingLine[this.codingPos] < columns) {
33389                 if (refPos > 0) {
33390                   --refPos;
33391                 } else {
33392                   ++refPos;
33393                 }
33394                 while (refLine[refPos] <= codingLine[this.codingPos] &&
33395                        refLine[refPos] < columns) {
33396                   refPos += 2;
33397                 }
33398               }
33399               break;
33400             case twoDimVertL1:
33401               this.addPixelsNeg(refLine[refPos] - 1, blackPixels);
33402               blackPixels ^= 1;
33403               if (codingLine[this.codingPos] < columns) {
33404                 if (refPos > 0) {
33405                   --refPos;
33406                 } else {
33407                   ++refPos;
33408                 }
33409                 while (refLine[refPos] <= codingLine[this.codingPos] &&
33410                        refLine[refPos] < columns) {
33411                   refPos += 2;
33412                 }
33413               }
33414               break;
33415             case EOF:
33416               this.addPixels(columns, 0);
33417               this.eof = true;
33418               break;
33419             default:
33420               info('bad 2d code');
33421               this.addPixels(columns, 0);
33422               this.err = true;
33423           }
33424         }
33425       } else {
33426         codingLine[0] = 0;
33427         this.codingPos = 0;
33428         blackPixels = 0;
33429         while (codingLine[this.codingPos] < columns) {
33430           code1 = 0;
33431           if (blackPixels) {
33432             do {
33433               code1 += (code3 = this.getBlackCode());
33434             } while (code3 >= 64);
33435           } else {
33436             do {
33437               code1 += (code3 = this.getWhiteCode());
33438             } while (code3 >= 64);
33439           }
33440           this.addPixels(codingLine[this.codingPos] + code1, blackPixels);
33441           blackPixels ^= 1;
33442         }
33443       }
33444
33445       var gotEOL = false;
33446
33447       if (this.byteAlign) {
33448         this.inputBits &= ~7;
33449       }
33450
33451       if (!this.eoblock && this.row === this.rows - 1) {
33452         this.eof = true;
33453       } else {
33454         code1 = this.lookBits(12);
33455         if (this.eoline) {
33456           while (code1 !== EOF && code1 !== 1) {
33457             this.eatBits(1);
33458             code1 = this.lookBits(12);
33459           }
33460         } else {
33461           while (code1 === 0) {
33462             this.eatBits(1);
33463             code1 = this.lookBits(12);
33464           }
33465         }
33466         if (code1 === 1) {
33467           this.eatBits(12);
33468           gotEOL = true;
33469         } else if (code1 === EOF) {
33470           this.eof = true;
33471         }
33472       }
33473
33474       if (!this.eof && this.encoding > 0) {
33475         this.nextLine2D = !this.lookBits(1);
33476         this.eatBits(1);
33477       }
33478
33479       if (this.eoblock && gotEOL && this.byteAlign) {
33480         code1 = this.lookBits(12);
33481         if (code1 === 1) {
33482           this.eatBits(12);
33483           if (this.encoding > 0) {
33484             this.lookBits(1);
33485             this.eatBits(1);
33486           }
33487           if (this.encoding >= 0) {
33488             for (i = 0; i < 4; ++i) {
33489               code1 = this.lookBits(12);
33490               if (code1 !== 1) {
33491                 info('bad rtc code: ' + code1);
33492               }
33493               this.eatBits(12);
33494               if (this.encoding > 0) {
33495                 this.lookBits(1);
33496                 this.eatBits(1);
33497               }
33498             }
33499           }
33500           this.eof = true;
33501         }
33502       } else if (this.err && this.eoline) {
33503         while (true) {
33504           code1 = this.lookBits(13);
33505           if (code1 === EOF) {
33506             this.eof = true;
33507             return null;
33508           }
33509           if ((code1 >> 1) === 1) {
33510             break;
33511           }
33512           this.eatBits(1);
33513         }
33514         this.eatBits(12);
33515         if (this.encoding > 0) {
33516           this.eatBits(1);
33517           this.nextLine2D = !(code1 & 1);
33518         }
33519       }
33520
33521       if (codingLine[0] > 0) {
33522         this.outputBits = codingLine[this.codingPos = 0];
33523       } else {
33524         this.outputBits = codingLine[this.codingPos = 1];
33525       }
33526       this.row++;
33527     }
33528
33529     var c;
33530     if (this.outputBits >= 8) {
33531       c = (this.codingPos & 1) ? 0 : 0xFF;
33532       this.outputBits -= 8;
33533       if (this.outputBits === 0 && codingLine[this.codingPos] < columns) {
33534         this.codingPos++;
33535         this.outputBits = (codingLine[this.codingPos] -
33536                            codingLine[this.codingPos - 1]);
33537       }
33538     } else {
33539       bits = 8;
33540       c = 0;
33541       do {
33542         if (this.outputBits > bits) {
33543           c <<= bits;
33544           if (!(this.codingPos & 1)) {
33545             c |= 0xFF >> (8 - bits);
33546           }
33547           this.outputBits -= bits;
33548           bits = 0;
33549         } else {
33550           c <<= this.outputBits;
33551           if (!(this.codingPos & 1)) {
33552             c |= 0xFF >> (8 - this.outputBits);
33553           }
33554           bits -= this.outputBits;
33555           this.outputBits = 0;
33556           if (codingLine[this.codingPos] < columns) {
33557             this.codingPos++;
33558             this.outputBits = (codingLine[this.codingPos] -
33559                                codingLine[this.codingPos - 1]);
33560           } else if (bits > 0) {
33561             c <<= bits;
33562             bits = 0;
33563           }
33564         }
33565       } while (bits);
33566     }
33567     if (this.black) {
33568       c ^= 0xFF;
33569     }
33570     return c;
33571   };
33572
33573   // This functions returns the code found from the table.
33574   // The start and end parameters set the boundaries for searching the table.
33575   // The limit parameter is optional. Function returns an array with three
33576   // values. The first array element indicates whether a valid code is being
33577   // returned. The second array element is the actual code. The third array
33578   // element indicates whether EOF was reached.
33579   CCITTFaxStream.prototype.findTableCode =
33580       function ccittFaxStreamFindTableCode(start, end, table, limit) {
33581
33582     var limitValue = limit || 0;
33583     for (var i = start; i <= end; ++i) {
33584       var code = this.lookBits(i);
33585       if (code === EOF) {
33586         return [true, 1, false];
33587       }
33588       if (i < end) {
33589         code <<= end - i;
33590       }
33591       if (!limitValue || code >= limitValue) {
33592         var p = table[code - limitValue];
33593         if (p[0] === i) {
33594           this.eatBits(i);
33595           return [true, p[1], true];
33596         }
33597       }
33598     }
33599     return [false, 0, false];
33600   };
33601
33602   CCITTFaxStream.prototype.getTwoDimCode =
33603       function ccittFaxStreamGetTwoDimCode() {
33604
33605     var code = 0;
33606     var p;
33607     if (this.eoblock) {
33608       code = this.lookBits(7);
33609       p = twoDimTable[code];
33610       if (p && p[0] > 0) {
33611         this.eatBits(p[0]);
33612         return p[1];
33613       }
33614     } else {
33615       var result = this.findTableCode(1, 7, twoDimTable);
33616       if (result[0] && result[2]) {
33617         return result[1];
33618       }
33619     }
33620     info('Bad two dim code');
33621     return EOF;
33622   };
33623
33624   CCITTFaxStream.prototype.getWhiteCode =
33625       function ccittFaxStreamGetWhiteCode() {
33626
33627     var code = 0;
33628     var p;
33629     if (this.eoblock) {
33630       code = this.lookBits(12);
33631       if (code === EOF) {
33632         return 1;
33633       }
33634
33635       if ((code >> 5) === 0) {
33636         p = whiteTable1[code];
33637       } else {
33638         p = whiteTable2[code >> 3];
33639       }
33640
33641       if (p[0] > 0) {
33642         this.eatBits(p[0]);
33643         return p[1];
33644       }
33645     } else {
33646       var result = this.findTableCode(1, 9, whiteTable2);
33647       if (result[0]) {
33648         return result[1];
33649       }
33650
33651       result = this.findTableCode(11, 12, whiteTable1);
33652       if (result[0]) {
33653         return result[1];
33654       }
33655     }
33656     info('bad white code');
33657     this.eatBits(1);
33658     return 1;
33659   };
33660
33661   CCITTFaxStream.prototype.getBlackCode =
33662       function ccittFaxStreamGetBlackCode() {
33663
33664     var code, p;
33665     if (this.eoblock) {
33666       code = this.lookBits(13);
33667       if (code === EOF) {
33668         return 1;
33669       }
33670       if ((code >> 7) === 0) {
33671         p = blackTable1[code];
33672       } else if ((code >> 9) === 0 && (code >> 7) !== 0) {
33673         p = blackTable2[(code >> 1) - 64];
33674       } else {
33675         p = blackTable3[code >> 7];
33676       }
33677
33678       if (p[0] > 0) {
33679         this.eatBits(p[0]);
33680         return p[1];
33681       }
33682     } else {
33683       var result = this.findTableCode(2, 6, blackTable3);
33684       if (result[0]) {
33685         return result[1];
33686       }
33687
33688       result = this.findTableCode(7, 12, blackTable2, 64);
33689       if (result[0]) {
33690         return result[1];
33691       }
33692
33693       result = this.findTableCode(10, 13, blackTable1);
33694       if (result[0]) {
33695         return result[1];
33696       }
33697     }
33698     info('bad black code');
33699     this.eatBits(1);
33700     return 1;
33701   };
33702
33703   CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) {
33704     var c;
33705     while (this.inputBits < n) {
33706       if ((c = this.str.getByte()) === -1) {
33707         if (this.inputBits === 0) {
33708           return EOF;
33709         }
33710         return ((this.inputBuf << (n - this.inputBits)) &
33711                 (0xFFFF >> (16 - n)));
33712       }
33713       this.inputBuf = (this.inputBuf << 8) + c;
33714       this.inputBits += 8;
33715     }
33716     return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n));
33717   };
33718
33719   CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) {
33720     if ((this.inputBits -= n) < 0) {
33721       this.inputBits = 0;
33722     }
33723   };
33724
33725   return CCITTFaxStream;
33726 })();
33727
33728 var LZWStream = (function LZWStreamClosure() {
33729   function LZWStream(str, maybeLength, earlyChange) {
33730     this.str = str;
33731     this.dict = str.dict;
33732     this.cachedData = 0;
33733     this.bitsCached = 0;
33734
33735     var maxLzwDictionarySize = 4096;
33736     var lzwState = {
33737       earlyChange: earlyChange,
33738       codeLength: 9,
33739       nextCode: 258,
33740       dictionaryValues: new Uint8Array(maxLzwDictionarySize),
33741       dictionaryLengths: new Uint16Array(maxLzwDictionarySize),
33742       dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize),
33743       currentSequence: new Uint8Array(maxLzwDictionarySize),
33744       currentSequenceLength: 0
33745     };
33746     for (var i = 0; i < 256; ++i) {
33747       lzwState.dictionaryValues[i] = i;
33748       lzwState.dictionaryLengths[i] = 1;
33749     }
33750     this.lzwState = lzwState;
33751
33752     DecodeStream.call(this, maybeLength);
33753   }
33754
33755   LZWStream.prototype = Object.create(DecodeStream.prototype);
33756
33757   LZWStream.prototype.readBits = function LZWStream_readBits(n) {
33758     var bitsCached = this.bitsCached;
33759     var cachedData = this.cachedData;
33760     while (bitsCached < n) {
33761       var c = this.str.getByte();
33762       if (c === -1) {
33763         this.eof = true;
33764         return null;
33765       }
33766       cachedData = (cachedData << 8) | c;
33767       bitsCached += 8;
33768     }
33769     this.bitsCached = (bitsCached -= n);
33770     this.cachedData = cachedData;
33771     this.lastCode = null;
33772     return (cachedData >>> bitsCached) & ((1 << n) - 1);
33773   };
33774
33775   LZWStream.prototype.readBlock = function LZWStream_readBlock() {
33776     var blockSize = 512;
33777     var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize;
33778     var i, j, q;
33779
33780     var lzwState = this.lzwState;
33781     if (!lzwState) {
33782       return; // eof was found
33783     }
33784
33785     var earlyChange = lzwState.earlyChange;
33786     var nextCode = lzwState.nextCode;
33787     var dictionaryValues = lzwState.dictionaryValues;
33788     var dictionaryLengths = lzwState.dictionaryLengths;
33789     var dictionaryPrevCodes = lzwState.dictionaryPrevCodes;
33790     var codeLength = lzwState.codeLength;
33791     var prevCode = lzwState.prevCode;
33792     var currentSequence = lzwState.currentSequence;
33793     var currentSequenceLength = lzwState.currentSequenceLength;
33794
33795     var decodedLength = 0;
33796     var currentBufferLength = this.bufferLength;
33797     var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
33798
33799     for (i = 0; i < blockSize; i++) {
33800       var code = this.readBits(codeLength);
33801       var hasPrev = currentSequenceLength > 0;
33802       if (code < 256) {
33803         currentSequence[0] = code;
33804         currentSequenceLength = 1;
33805       } else if (code >= 258) {
33806         if (code < nextCode) {
33807           currentSequenceLength = dictionaryLengths[code];
33808           for (j = currentSequenceLength - 1, q = code; j >= 0; j--) {
33809             currentSequence[j] = dictionaryValues[q];
33810             q = dictionaryPrevCodes[q];
33811           }
33812         } else {
33813           currentSequence[currentSequenceLength++] = currentSequence[0];
33814         }
33815       } else if (code === 256) {
33816         codeLength = 9;
33817         nextCode = 258;
33818         currentSequenceLength = 0;
33819         continue;
33820       } else {
33821         this.eof = true;
33822         delete this.lzwState;
33823         break;
33824       }
33825
33826       if (hasPrev) {
33827         dictionaryPrevCodes[nextCode] = prevCode;
33828         dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1;
33829         dictionaryValues[nextCode] = currentSequence[0];
33830         nextCode++;
33831         codeLength = (nextCode + earlyChange) & (nextCode + earlyChange - 1) ?
33832           codeLength : Math.min(Math.log(nextCode + earlyChange) /
33833           0.6931471805599453 + 1, 12) | 0;
33834       }
33835       prevCode = code;
33836
33837       decodedLength += currentSequenceLength;
33838       if (estimatedDecodedSize < decodedLength) {
33839         do {
33840           estimatedDecodedSize += decodedSizeDelta;
33841         } while (estimatedDecodedSize < decodedLength);
33842         buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
33843       }
33844       for (j = 0; j < currentSequenceLength; j++) {
33845         buffer[currentBufferLength++] = currentSequence[j];
33846       }
33847     }
33848     lzwState.nextCode = nextCode;
33849     lzwState.codeLength = codeLength;
33850     lzwState.prevCode = prevCode;
33851     lzwState.currentSequenceLength = currentSequenceLength;
33852
33853     this.bufferLength = currentBufferLength;
33854   };
33855
33856   return LZWStream;
33857 })();
33858
33859 var NullStream = (function NullStreamClosure() {
33860   function NullStream() {
33861     Stream.call(this, new Uint8Array(0));
33862   }
33863
33864   NullStream.prototype = Stream.prototype;
33865
33866   return NullStream;
33867 })();
33868
33869
33870 var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
33871   setup: function wphSetup(handler) {
33872     var pdfManager;
33873
33874     function loadDocument(recoveryMode) {
33875       var loadDocumentCapability = createPromiseCapability();
33876
33877       var parseSuccess = function parseSuccess() {
33878         var numPagesPromise = pdfManager.ensureDoc('numPages');
33879         var fingerprintPromise = pdfManager.ensureDoc('fingerprint');
33880         var encryptedPromise = pdfManager.ensureXRef('encrypt');
33881         Promise.all([numPagesPromise, fingerprintPromise,
33882                      encryptedPromise]).then(function onDocReady(results) {
33883           var doc = {
33884             numPages: results[0],
33885             fingerprint: results[1],
33886             encrypted: !!results[2],
33887           };
33888           loadDocumentCapability.resolve(doc);
33889         },
33890         parseFailure);
33891       };
33892
33893       var parseFailure = function parseFailure(e) {
33894         loadDocumentCapability.reject(e);
33895       };
33896
33897       pdfManager.ensureDoc('checkHeader', []).then(function() {
33898         pdfManager.ensureDoc('parseStartXRef', []).then(function() {
33899           pdfManager.ensureDoc('parse', [recoveryMode]).then(
33900             parseSuccess, parseFailure);
33901         }, parseFailure);
33902       }, parseFailure);
33903
33904       return loadDocumentCapability.promise;
33905     }
33906
33907     function getPdfManager(data) {
33908       var pdfManagerCapability = createPromiseCapability();
33909
33910       var source = data.source;
33911       var disableRange = data.disableRange;
33912       if (source.data) {
33913         try {
33914           pdfManager = new LocalPdfManager(source.data, source.password);
33915           pdfManagerCapability.resolve();
33916         } catch (ex) {
33917           pdfManagerCapability.reject(ex);
33918         }
33919         return pdfManagerCapability.promise;
33920       } else if (source.chunkedViewerLoading) {
33921         try {
33922           pdfManager = new NetworkPdfManager(source, handler);
33923           pdfManagerCapability.resolve();
33924         } catch (ex) {
33925           pdfManagerCapability.reject(ex);
33926         }
33927         return pdfManagerCapability.promise;
33928       }
33929
33930       var networkManager = new NetworkManager(source.url, {
33931         httpHeaders: source.httpHeaders,
33932         withCredentials: source.withCredentials
33933       });
33934       var cachedChunks = [];
33935       var fullRequestXhrId = networkManager.requestFull({
33936         onHeadersReceived: function onHeadersReceived() {
33937           if (disableRange) {
33938             return;
33939           }
33940
33941           var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId);
33942           if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') {
33943             return;
33944           }
33945
33946           var contentEncoding =
33947             fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity';
33948           if (contentEncoding !== 'identity') {
33949             return;
33950           }
33951
33952           var length = fullRequestXhr.getResponseHeader('Content-Length');
33953           length = parseInt(length, 10);
33954           if (!isInt(length)) {
33955             return;
33956           }
33957           source.length = length;
33958           if (length <= 2 * RANGE_CHUNK_SIZE) {
33959             // The file size is smaller than the size of two chunks, so it does
33960             // not make any sense to abort the request and retry with a range
33961             // request.
33962             return;
33963           }
33964
33965           if (networkManager.isStreamingRequest(fullRequestXhrId)) {
33966             // We can continue fetching when progressive loading is enabled,
33967             // and we don't need the autoFetch feature.
33968             source.disableAutoFetch = true;
33969           } else {
33970             // NOTE: by cancelling the full request, and then issuing range
33971             // requests, there will be an issue for sites where you can only
33972             // request the pdf once. However, if this is the case, then the
33973             // server should not be returning that it can support range
33974             // requests.
33975             networkManager.abortRequest(fullRequestXhrId);
33976           }
33977
33978           try {
33979             pdfManager = new NetworkPdfManager(source, handler);
33980             pdfManagerCapability.resolve(pdfManager);
33981           } catch (ex) {
33982             pdfManagerCapability.reject(ex);
33983           }
33984         },
33985
33986         onProgressiveData: source.disableStream ? null :
33987             function onProgressiveData(chunk) {
33988           if (!pdfManager) {
33989             cachedChunks.push(chunk);
33990             return;
33991           }
33992           pdfManager.sendProgressiveData(chunk);
33993         },
33994
33995         onDone: function onDone(args) {
33996           if (pdfManager) {
33997             return; // already processed
33998           }
33999
34000           var pdfFile;
34001           if (args === null) {
34002             // TODO add some streaming manager, e.g. for unknown length files.
34003             // The data was returned in the onProgressiveData, combining...
34004             var pdfFileLength = 0, pos = 0;
34005             cachedChunks.forEach(function (chunk) {
34006               pdfFileLength += chunk.byteLength;
34007             });
34008             if (source.length && pdfFileLength !== source.length) {
34009               warn('reported HTTP length is different from actual');
34010             }
34011             var pdfFileArray = new Uint8Array(pdfFileLength);
34012             cachedChunks.forEach(function (chunk) {
34013               pdfFileArray.set(new Uint8Array(chunk), pos);
34014               pos += chunk.byteLength;
34015             });
34016             pdfFile = pdfFileArray.buffer;
34017           } else {
34018             pdfFile = args.chunk;
34019           }
34020
34021           // the data is array, instantiating directly from it
34022           try {
34023             pdfManager = new LocalPdfManager(pdfFile, source.password);
34024             pdfManagerCapability.resolve();
34025           } catch (ex) {
34026             pdfManagerCapability.reject(ex);
34027           }
34028         },
34029
34030         onError: function onError(status) {
34031           var exception;
34032           if (status === 404) {
34033             exception = new MissingPDFException('Missing PDF "' +
34034                                                 source.url + '".');
34035             handler.send('MissingPDF', exception);
34036           } else {
34037             exception = new UnexpectedResponseException(
34038               'Unexpected server response (' + status +
34039               ') while retrieving PDF "' + source.url + '".', status);
34040             handler.send('UnexpectedResponse', exception);
34041           }
34042         },
34043
34044         onProgress: function onProgress(evt) {
34045           handler.send('DocProgress', {
34046             loaded: evt.loaded,
34047             total: evt.lengthComputable ? evt.total : source.length
34048           });
34049         }
34050       });
34051
34052       return pdfManagerCapability.promise;
34053     }
34054
34055     handler.on('test', function wphSetupTest(data) {
34056       // check if Uint8Array can be sent to worker
34057       if (!(data instanceof Uint8Array)) {
34058         handler.send('test', false);
34059         return;
34060       }
34061       // making sure postMessage transfers are working
34062       var supportTransfers = data[0] === 255;
34063       handler.postMessageTransfers = supportTransfers;
34064       // check if the response property is supported by xhr
34065       var xhr = new XMLHttpRequest();
34066       var responseExists = 'response' in xhr;
34067       // check if the property is actually implemented
34068       try {
34069         var dummy = xhr.responseType;
34070       } catch (e) {
34071         responseExists = false;
34072       }
34073       if (!responseExists) {
34074         handler.send('test', false);
34075         return;
34076       }
34077       handler.send('test', {
34078         supportTypedArray: true,
34079         supportTransfers: supportTransfers
34080       });
34081     });
34082
34083     handler.on('GetDocRequest', function wphSetupDoc(data) {
34084
34085       var onSuccess = function(doc) {
34086         handler.send('GetDoc', { pdfInfo: doc });
34087       };
34088
34089       var onFailure = function(e) {
34090         if (e instanceof PasswordException) {
34091           if (e.code === PasswordResponses.NEED_PASSWORD) {
34092             handler.send('NeedPassword', e);
34093           } else if (e.code === PasswordResponses.INCORRECT_PASSWORD) {
34094             handler.send('IncorrectPassword', e);
34095           }
34096         } else if (e instanceof InvalidPDFException) {
34097           handler.send('InvalidPDF', e);
34098         } else if (e instanceof MissingPDFException) {
34099           handler.send('MissingPDF', e);
34100         } else if (e instanceof UnexpectedResponseException) {
34101           handler.send('UnexpectedResponse', e);
34102         } else {
34103           handler.send('UnknownError',
34104                        new UnknownErrorException(e.message, e.toString()));
34105         }
34106       };
34107
34108       PDFJS.maxImageSize = data.maxImageSize === undefined ?
34109                            -1 : data.maxImageSize;
34110       PDFJS.disableFontFace = data.disableFontFace;
34111       PDFJS.disableCreateObjectURL = data.disableCreateObjectURL;
34112       PDFJS.verbosity = data.verbosity;
34113       PDFJS.cMapUrl = data.cMapUrl === undefined ?
34114                            null : data.cMapUrl;
34115       PDFJS.cMapPacked = data.cMapPacked === true;
34116
34117       getPdfManager(data).then(function () {
34118         handler.send('PDFManagerReady', null);
34119         pdfManager.onLoadedStream().then(function(stream) {
34120           handler.send('DataLoaded', { length: stream.bytes.byteLength });
34121         });
34122       }).then(function pdfManagerReady() {
34123         loadDocument(false).then(onSuccess, function loadFailure(ex) {
34124           // Try again with recoveryMode == true
34125           if (!(ex instanceof XRefParseException)) {
34126             if (ex instanceof PasswordException) {
34127               // after password exception prepare to receive a new password
34128               // to repeat loading
34129               pdfManager.passwordChanged().then(pdfManagerReady);
34130             }
34131
34132             onFailure(ex);
34133             return;
34134           }
34135
34136           pdfManager.requestLoadedStream();
34137           pdfManager.onLoadedStream().then(function() {
34138             loadDocument(true).then(onSuccess, onFailure);
34139           });
34140         }, onFailure);
34141       }, onFailure);
34142     });
34143
34144     handler.on('GetPage', function wphSetupGetPage(data) {
34145       return pdfManager.getPage(data.pageIndex).then(function(page) {
34146         var rotatePromise = pdfManager.ensure(page, 'rotate');
34147         var refPromise = pdfManager.ensure(page, 'ref');
34148         var viewPromise = pdfManager.ensure(page, 'view');
34149
34150         return Promise.all([rotatePromise, refPromise, viewPromise]).then(
34151             function(results) {
34152           return {
34153             rotate: results[0],
34154             ref: results[1],
34155             view: results[2]
34156           };
34157         });
34158       });
34159     });
34160
34161     handler.on('GetPageIndex', function wphSetupGetPageIndex(data) {
34162       var ref = new Ref(data.ref.num, data.ref.gen);
34163       var catalog = pdfManager.pdfDocument.catalog;
34164       return catalog.getPageIndex(ref);
34165     });
34166
34167     handler.on('GetDestinations',
34168       function wphSetupGetDestinations(data) {
34169         return pdfManager.ensureCatalog('destinations');
34170       }
34171     );
34172
34173     handler.on('GetDestination',
34174       function wphSetupGetDestination(data) {
34175         return pdfManager.ensureCatalog('getDestination', [ data.id ]);
34176       }
34177     );
34178
34179     handler.on('GetAttachments',
34180       function wphSetupGetAttachments(data) {
34181         return pdfManager.ensureCatalog('attachments');
34182       }
34183     );
34184
34185     handler.on('GetJavaScript',
34186       function wphSetupGetJavaScript(data) {
34187         return pdfManager.ensureCatalog('javaScript');
34188       }
34189     );
34190
34191     handler.on('GetOutline',
34192       function wphSetupGetOutline(data) {
34193         return pdfManager.ensureCatalog('documentOutline');
34194       }
34195     );
34196
34197     handler.on('GetMetadata',
34198       function wphSetupGetMetadata(data) {
34199         return Promise.all([pdfManager.ensureDoc('documentInfo'),
34200                             pdfManager.ensureCatalog('metadata')]);
34201       }
34202     );
34203
34204     handler.on('GetData', function wphSetupGetData(data) {
34205       pdfManager.requestLoadedStream();
34206       return pdfManager.onLoadedStream().then(function(stream) {
34207         return stream.bytes;
34208       });
34209     });
34210
34211     handler.on('GetStats',
34212       function wphSetupGetStats(data) {
34213         return pdfManager.pdfDocument.xref.stats;
34214       }
34215     );
34216
34217     handler.on('UpdatePassword', function wphSetupUpdatePassword(data) {
34218       pdfManager.updatePassword(data);
34219     });
34220
34221     handler.on('GetAnnotations', function wphSetupGetAnnotations(data) {
34222       return pdfManager.getPage(data.pageIndex).then(function(page) {
34223         return pdfManager.ensure(page, 'getAnnotationsData', []);
34224       });
34225     });
34226
34227     handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
34228       pdfManager.getPage(data.pageIndex).then(function(page) {
34229
34230         var pageNum = data.pageIndex + 1;
34231         var start = Date.now();
34232         // Pre compile the pdf page and fetch the fonts/images.
34233         page.getOperatorList(handler, data.intent).then(function(operatorList) {
34234
34235           info('page=' + pageNum + ' - getOperatorList: time=' +
34236                (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length);
34237
34238         }, function(e) {
34239
34240           var minimumStackMessage =
34241             'worker.js: while trying to getPage() and getOperatorList()';
34242
34243           var wrappedException;
34244
34245           // Turn the error into an obj that can be serialized
34246           if (typeof e === 'string') {
34247             wrappedException = {
34248               message: e,
34249               stack: minimumStackMessage
34250             };
34251           } else if (typeof e === 'object') {
34252             wrappedException = {
34253               message: e.message || e.toString(),
34254               stack: e.stack || minimumStackMessage
34255             };
34256           } else {
34257             wrappedException = {
34258               message: 'Unknown exception type: ' + (typeof e),
34259               stack: minimumStackMessage
34260             };
34261           }
34262
34263           handler.send('PageError', {
34264             pageNum: pageNum,
34265             error: wrappedException,
34266             intent: data.intent
34267           });
34268         });
34269       });
34270     }, this);
34271
34272     handler.on('GetTextContent', function wphExtractText(data) {
34273       return pdfManager.getPage(data.pageIndex).then(function(page) {
34274         var pageNum = data.pageIndex + 1;
34275         var start = Date.now();
34276         return page.extractTextContent().then(function(textContent) {
34277           info('text indexing: page=' + pageNum + ' - time=' +
34278                (Date.now() - start) + 'ms');
34279           return textContent;
34280         });
34281       });
34282     });
34283
34284     handler.on('Cleanup', function wphCleanup(data) {
34285       return pdfManager.cleanup();
34286     });
34287
34288     handler.on('Terminate', function wphTerminate(data) {
34289       pdfManager.terminate();
34290     });
34291   }
34292 };
34293
34294 var consoleTimer = {};
34295
34296 var workerConsole = {
34297   log: function log() {
34298     var args = Array.prototype.slice.call(arguments);
34299     globalScope.postMessage({
34300       action: 'console_log',
34301       data: args
34302     });
34303   },
34304
34305   error: function error() {
34306     var args = Array.prototype.slice.call(arguments);
34307     globalScope.postMessage({
34308       action: 'console_error',
34309       data: args
34310     });
34311     throw 'pdf.js execution error';
34312   },
34313
34314   time: function time(name) {
34315     consoleTimer[name] = Date.now();
34316   },
34317
34318   timeEnd: function timeEnd(name) {
34319     var time = consoleTimer[name];
34320     if (!time) {
34321       error('Unknown timer name ' + name);
34322     }
34323     this.log('Timer:', name, Date.now() - time);
34324   }
34325 };
34326
34327
34328 // Worker thread?
34329 if (typeof window === 'undefined') {
34330   if (!('console' in globalScope)) {
34331     globalScope.console = workerConsole;
34332   }
34333
34334   // Listen for unsupported features so we can pass them on to the main thread.
34335   PDFJS.UnsupportedManager.listen(function (msg) {
34336     globalScope.postMessage({
34337       action: '_unsupported_feature',
34338       data: msg
34339     });
34340   });
34341
34342   var handler = new MessageHandler('worker_processor', this);
34343   WorkerMessageHandler.setup(handler);
34344 }
34345
34346
34347 /* This class implements the QM Coder decoding as defined in
34348  *   JPEG 2000 Part I Final Committee Draft Version 1.0
34349  *   Annex C.3 Arithmetic decoding procedure
34350  * available at http://www.jpeg.org/public/fcd15444-1.pdf
34351  *
34352  * The arithmetic decoder is used in conjunction with context models to decode
34353  * JPEG2000 and JBIG2 streams.
34354  */
34355 var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
34356   // Table C-2
34357   var QeTable = [
34358     {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
34359     {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
34360     {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0},
34361     {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0},
34362     {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0},
34363     {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0},
34364     {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1},
34365     {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0},
34366     {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0},
34367     {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0},
34368     {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0},
34369     {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0},
34370     {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0},
34371     {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0},
34372     {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1},
34373     {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0},
34374     {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0},
34375     {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0},
34376     {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0},
34377     {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0},
34378     {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0},
34379     {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0},
34380     {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0},
34381     {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0},
34382     {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0},
34383     {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0},
34384     {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0},
34385     {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0},
34386     {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0},
34387     {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0},
34388     {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0},
34389     {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0},
34390     {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0},
34391     {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0},
34392     {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0},
34393     {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0},
34394     {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0},
34395     {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0},
34396     {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0},
34397     {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0},
34398     {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0},
34399     {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0},
34400     {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0},
34401     {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0},
34402     {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0},
34403     {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0},
34404     {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0}
34405   ];
34406
34407   // C.3.5 Initialisation of the decoder (INITDEC)
34408   function ArithmeticDecoder(data, start, end) {
34409     this.data = data;
34410     this.bp = start;
34411     this.dataEnd = end;
34412
34413     this.chigh = data[start];
34414     this.clow = 0;
34415
34416     this.byteIn();
34417
34418     this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
34419     this.clow = (this.clow << 7) & 0xFFFF;
34420     this.ct -= 7;
34421     this.a = 0x8000;
34422   }
34423
34424   ArithmeticDecoder.prototype = {
34425     // C.3.4 Compressed data input (BYTEIN)
34426     byteIn: function ArithmeticDecoder_byteIn() {
34427       var data = this.data;
34428       var bp = this.bp;
34429       if (data[bp] === 0xFF) {
34430         var b1 = data[bp + 1];
34431         if (b1 > 0x8F) {
34432           this.clow += 0xFF00;
34433           this.ct = 8;
34434         } else {
34435           bp++;
34436           this.clow += (data[bp] << 9);
34437           this.ct = 7;
34438           this.bp = bp;
34439         }
34440       } else {
34441         bp++;
34442         this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
34443         this.ct = 8;
34444         this.bp = bp;
34445       }
34446       if (this.clow > 0xFFFF) {
34447         this.chigh += (this.clow >> 16);
34448         this.clow &= 0xFFFF;
34449       }
34450     },
34451     // C.3.2 Decoding a decision (DECODE)
34452     readBit: function ArithmeticDecoder_readBit(contexts, pos) {
34453       // contexts are packed into 1 byte:
34454       // highest 7 bits carry cx.index, lowest bit carries cx.mps
34455       var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1;
34456       var qeTableIcx = QeTable[cx_index];
34457       var qeIcx = qeTableIcx.qe;
34458       var d;
34459       var a = this.a - qeIcx;
34460
34461       if (this.chigh < qeIcx) {
34462         // exchangeLps
34463         if (a < qeIcx) {
34464           a = qeIcx;
34465           d = cx_mps;
34466           cx_index = qeTableIcx.nmps;
34467         } else {
34468           a = qeIcx;
34469           d = 1 ^ cx_mps;
34470           if (qeTableIcx.switchFlag === 1) {
34471             cx_mps = d;
34472           }
34473           cx_index = qeTableIcx.nlps;
34474         }
34475       } else {
34476         this.chigh -= qeIcx;
34477         if ((a & 0x8000) !== 0) {
34478           this.a = a;
34479           return cx_mps;
34480         }
34481         // exchangeMps
34482         if (a < qeIcx) {
34483           d = 1 ^ cx_mps;
34484           if (qeTableIcx.switchFlag === 1) {
34485             cx_mps = d;
34486           }
34487           cx_index = qeTableIcx.nlps;
34488         } else {
34489           d = cx_mps;
34490           cx_index = qeTableIcx.nmps;
34491         }
34492       }
34493       // C.3.3 renormD;
34494       do {
34495         if (this.ct === 0) {
34496           this.byteIn();
34497         }
34498
34499         a <<= 1;
34500         this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
34501         this.clow = (this.clow << 1) & 0xFFFF;
34502         this.ct--;
34503       } while ((a & 0x8000) === 0);
34504       this.a = a;
34505
34506       contexts[pos] = cx_index << 1 | cx_mps;
34507       return d;
34508     }
34509   };
34510
34511   return ArithmeticDecoder;
34512 })();
34513
34514
34515 var JpegImage = (function jpegImage() {
34516   var dctZigZag = new Uint8Array([
34517      0,
34518      1,  8,
34519     16,  9,  2,
34520      3, 10, 17, 24,
34521     32, 25, 18, 11, 4,
34522      5, 12, 19, 26, 33, 40,
34523     48, 41, 34, 27, 20, 13,  6,
34524      7, 14, 21, 28, 35, 42, 49, 56,
34525     57, 50, 43, 36, 29, 22, 15,
34526     23, 30, 37, 44, 51, 58,
34527     59, 52, 45, 38, 31,
34528     39, 46, 53, 60,
34529     61, 54, 47,
34530     55, 62,
34531     63
34532   ]);
34533
34534   var dctCos1  =  4017;   // cos(pi/16)
34535   var dctSin1  =   799;   // sin(pi/16)
34536   var dctCos3  =  3406;   // cos(3*pi/16)
34537   var dctSin3  =  2276;   // sin(3*pi/16)
34538   var dctCos6  =  1567;   // cos(6*pi/16)
34539   var dctSin6  =  3784;   // sin(6*pi/16)
34540   var dctSqrt2 =  5793;   // sqrt(2)
34541   var dctSqrt1d2 = 2896;  // sqrt(2) / 2
34542
34543   function constructor() {
34544   }
34545
34546   function buildHuffmanTable(codeLengths, values) {
34547     var k = 0, code = [], i, j, length = 16;
34548     while (length > 0 && !codeLengths[length - 1]) {
34549       length--;
34550     }
34551     code.push({children: [], index: 0});
34552     var p = code[0], q;
34553     for (i = 0; i < length; i++) {
34554       for (j = 0; j < codeLengths[i]; j++) {
34555         p = code.pop();
34556         p.children[p.index] = values[k];
34557         while (p.index > 0) {
34558           p = code.pop();
34559         }
34560         p.index++;
34561         code.push(p);
34562         while (code.length <= i) {
34563           code.push(q = {children: [], index: 0});
34564           p.children[p.index] = q.children;
34565           p = q;
34566         }
34567         k++;
34568       }
34569       if (i + 1 < length) {
34570         // p here points to last code
34571         code.push(q = {children: [], index: 0});
34572         p.children[p.index] = q.children;
34573         p = q;
34574       }
34575     }
34576     return code[0].children;
34577   }
34578
34579   function getBlockBufferOffset(component, row, col) {
34580     return 64 * ((component.blocksPerLine + 1) * row + col);
34581   }
34582
34583   function decodeScan(data, offset, frame, components, resetInterval,
34584                       spectralStart, spectralEnd, successivePrev, successive) {
34585     var precision = frame.precision;
34586     var samplesPerLine = frame.samplesPerLine;
34587     var scanLines = frame.scanLines;
34588     var mcusPerLine = frame.mcusPerLine;
34589     var progressive = frame.progressive;
34590     var maxH = frame.maxH, maxV = frame.maxV;
34591
34592     var startOffset = offset, bitsData = 0, bitsCount = 0;
34593
34594     function readBit() {
34595       if (bitsCount > 0) {
34596         bitsCount--;
34597         return (bitsData >> bitsCount) & 1;
34598       }
34599       bitsData = data[offset++];
34600       if (bitsData === 0xFF) {
34601         var nextByte = data[offset++];
34602         if (nextByte) {
34603           throw 'unexpected marker: ' +
34604             ((bitsData << 8) | nextByte).toString(16);
34605         }
34606         // unstuff 0
34607       }
34608       bitsCount = 7;
34609       return bitsData >>> 7;
34610     }
34611
34612     function decodeHuffman(tree) {
34613       var node = tree;
34614       while (true) {
34615         node = node[readBit()];
34616         if (typeof node === 'number') {
34617           return node;
34618         }
34619         if (typeof node !== 'object') {
34620           throw 'invalid huffman sequence';
34621         }
34622       }
34623     }
34624
34625     function receive(length) {
34626       var n = 0;
34627       while (length > 0) {
34628         n = (n << 1) | readBit();
34629         length--;
34630       }
34631       return n;
34632     }
34633
34634     function receiveAndExtend(length) {
34635       if (length === 1) {
34636         return readBit() === 1 ? 1 : -1;
34637       }
34638       var n = receive(length);
34639       if (n >= 1 << (length - 1)) {
34640         return n;
34641       }
34642       return n + (-1 << length) + 1;
34643     }
34644
34645     function decodeBaseline(component, offset) {
34646       var t = decodeHuffman(component.huffmanTableDC);
34647       var diff = t === 0 ? 0 : receiveAndExtend(t);
34648       component.blockData[offset] = (component.pred += diff);
34649       var k = 1;
34650       while (k < 64) {
34651         var rs = decodeHuffman(component.huffmanTableAC);
34652         var s = rs & 15, r = rs >> 4;
34653         if (s === 0) {
34654           if (r < 15) {
34655             break;
34656           }
34657           k += 16;
34658           continue;
34659         }
34660         k += r;
34661         var z = dctZigZag[k];
34662         component.blockData[offset + z] = receiveAndExtend(s);
34663         k++;
34664       }
34665     }
34666
34667     function decodeDCFirst(component, offset) {
34668       var t = decodeHuffman(component.huffmanTableDC);
34669       var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
34670       component.blockData[offset] = (component.pred += diff);
34671     }
34672
34673     function decodeDCSuccessive(component, offset) {
34674       component.blockData[offset] |= readBit() << successive;
34675     }
34676
34677     var eobrun = 0;
34678     function decodeACFirst(component, offset) {
34679       if (eobrun > 0) {
34680         eobrun--;
34681         return;
34682       }
34683       var k = spectralStart, e = spectralEnd;
34684       while (k <= e) {
34685         var rs = decodeHuffman(component.huffmanTableAC);
34686         var s = rs & 15, r = rs >> 4;
34687         if (s === 0) {
34688           if (r < 15) {
34689             eobrun = receive(r) + (1 << r) - 1;
34690             break;
34691           }
34692           k += 16;
34693           continue;
34694         }
34695         k += r;
34696         var z = dctZigZag[k];
34697         component.blockData[offset + z] =
34698           receiveAndExtend(s) * (1 << successive);
34699         k++;
34700       }
34701     }
34702
34703     var successiveACState = 0, successiveACNextValue;
34704     function decodeACSuccessive(component, offset) {
34705       var k = spectralStart;
34706       var e = spectralEnd;
34707       var r = 0;
34708       var s;
34709       var rs;
34710       while (k <= e) {
34711         var z = dctZigZag[k];
34712         switch (successiveACState) {
34713         case 0: // initial state
34714           rs = decodeHuffman(component.huffmanTableAC);
34715           s = rs & 15;
34716           r = rs >> 4;
34717           if (s === 0) {
34718             if (r < 15) {
34719               eobrun = receive(r) + (1 << r);
34720               successiveACState = 4;
34721             } else {
34722               r = 16;
34723               successiveACState = 1;
34724             }
34725           } else {
34726             if (s !== 1) {
34727               throw 'invalid ACn encoding';
34728             }
34729             successiveACNextValue = receiveAndExtend(s);
34730             successiveACState = r ? 2 : 3;
34731           }
34732           continue;
34733         case 1: // skipping r zero items
34734         case 2:
34735           if (component.blockData[offset + z]) {
34736             component.blockData[offset + z] += (readBit() << successive);
34737           } else {
34738             r--;
34739             if (r === 0) {
34740               successiveACState = successiveACState === 2 ? 3 : 0;
34741             }
34742           }
34743           break;
34744         case 3: // set value for a zero item
34745           if (component.blockData[offset + z]) {
34746             component.blockData[offset + z] += (readBit() << successive);
34747           } else {
34748             component.blockData[offset + z] =
34749               successiveACNextValue << successive;
34750             successiveACState = 0;
34751           }
34752           break;
34753         case 4: // eob
34754           if (component.blockData[offset + z]) {
34755             component.blockData[offset + z] += (readBit() << successive);
34756           }
34757           break;
34758         }
34759         k++;
34760       }
34761       if (successiveACState === 4) {
34762         eobrun--;
34763         if (eobrun === 0) {
34764           successiveACState = 0;
34765         }
34766       }
34767     }
34768
34769     function decodeMcu(component, decode, mcu, row, col) {
34770       var mcuRow = (mcu / mcusPerLine) | 0;
34771       var mcuCol = mcu % mcusPerLine;
34772       var blockRow = mcuRow * component.v + row;
34773       var blockCol = mcuCol * component.h + col;
34774       var offset = getBlockBufferOffset(component, blockRow, blockCol);
34775       decode(component, offset);
34776     }
34777
34778     function decodeBlock(component, decode, mcu) {
34779       var blockRow = (mcu / component.blocksPerLine) | 0;
34780       var blockCol = mcu % component.blocksPerLine;
34781       var offset = getBlockBufferOffset(component, blockRow, blockCol);
34782       decode(component, offset);
34783     }
34784
34785     var componentsLength = components.length;
34786     var component, i, j, k, n;
34787     var decodeFn;
34788     if (progressive) {
34789       if (spectralStart === 0) {
34790         decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
34791       } else {
34792         decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
34793       }
34794     } else {
34795       decodeFn = decodeBaseline;
34796     }
34797
34798     var mcu = 0, marker;
34799     var mcuExpected;
34800     if (componentsLength === 1) {
34801       mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
34802     } else {
34803       mcuExpected = mcusPerLine * frame.mcusPerColumn;
34804     }
34805     if (!resetInterval) {
34806       resetInterval = mcuExpected;
34807     }
34808
34809     var h, v;
34810     while (mcu < mcuExpected) {
34811       // reset interval stuff
34812       for (i = 0; i < componentsLength; i++) {
34813         components[i].pred = 0;
34814       }
34815       eobrun = 0;
34816
34817       if (componentsLength === 1) {
34818         component = components[0];
34819         for (n = 0; n < resetInterval; n++) {
34820           decodeBlock(component, decodeFn, mcu);
34821           mcu++;
34822         }
34823       } else {
34824         for (n = 0; n < resetInterval; n++) {
34825           for (i = 0; i < componentsLength; i++) {
34826             component = components[i];
34827             h = component.h;
34828             v = component.v;
34829             for (j = 0; j < v; j++) {
34830               for (k = 0; k < h; k++) {
34831                 decodeMcu(component, decodeFn, mcu, j, k);
34832               }
34833             }
34834           }
34835           mcu++;
34836         }
34837       }
34838
34839       // find marker
34840       bitsCount = 0;
34841       marker = (data[offset] << 8) | data[offset + 1];
34842       if (marker <= 0xFF00) {
34843         throw 'marker was not found';
34844       }
34845
34846       if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
34847         offset += 2;
34848       } else {
34849         break;
34850       }
34851     }
34852
34853     return offset - startOffset;
34854   }
34855
34856   // A port of poppler's IDCT method which in turn is taken from:
34857   //   Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
34858   //   'Practical Fast 1-D DCT Algorithms with 11 Multiplications',
34859   //   IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
34860   //   988-991.
34861   function quantizeAndInverse(component, blockBufferOffset, p) {
34862     var qt = component.quantizationTable, blockData = component.blockData;
34863     var v0, v1, v2, v3, v4, v5, v6, v7;
34864     var p0, p1, p2, p3, p4, p5, p6, p7;
34865     var t;
34866
34867     // inverse DCT on rows
34868     for (var row = 0; row < 64; row += 8) {
34869       // gather block data
34870       p0 = blockData[blockBufferOffset + row];
34871       p1 = blockData[blockBufferOffset + row + 1];
34872       p2 = blockData[blockBufferOffset + row + 2];
34873       p3 = blockData[blockBufferOffset + row + 3];
34874       p4 = blockData[blockBufferOffset + row + 4];
34875       p5 = blockData[blockBufferOffset + row + 5];
34876       p6 = blockData[blockBufferOffset + row + 6];
34877       p7 = blockData[blockBufferOffset + row + 7];
34878
34879       // dequant p0
34880       p0 *= qt[row];
34881
34882       // check for all-zero AC coefficients
34883       if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
34884         t = (dctSqrt2 * p0 + 512) >> 10;
34885         p[row] = t;
34886         p[row + 1] = t;
34887         p[row + 2] = t;
34888         p[row + 3] = t;
34889         p[row + 4] = t;
34890         p[row + 5] = t;
34891         p[row + 6] = t;
34892         p[row + 7] = t;
34893         continue;
34894       }
34895       // dequant p1 ... p7
34896       p1 *= qt[row + 1];
34897       p2 *= qt[row + 2];
34898       p3 *= qt[row + 3];
34899       p4 *= qt[row + 4];
34900       p5 *= qt[row + 5];
34901       p6 *= qt[row + 6];
34902       p7 *= qt[row + 7];
34903
34904       // stage 4
34905       v0 = (dctSqrt2 * p0 + 128) >> 8;
34906       v1 = (dctSqrt2 * p4 + 128) >> 8;
34907       v2 = p2;
34908       v3 = p6;
34909       v4 = (dctSqrt1d2 * (p1 - p7) + 128) >> 8;
34910       v7 = (dctSqrt1d2 * (p1 + p7) + 128) >> 8;
34911       v5 = p3 << 4;
34912       v6 = p5 << 4;
34913
34914       // stage 3
34915       v0 = (v0 + v1 + 1) >> 1;
34916       v1 = v0 - v1;
34917       t  = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
34918       v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
34919       v3 = t;
34920       v4 = (v4 + v6 + 1) >> 1;
34921       v6 = v4 - v6;
34922       v7 = (v7 + v5 + 1) >> 1;
34923       v5 = v7 - v5;
34924
34925       // stage 2
34926       v0 = (v0 + v3 + 1) >> 1;
34927       v3 = v0 - v3;
34928       v1 = (v1 + v2 + 1) >> 1;
34929       v2 = v1 - v2;
34930       t  = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
34931       v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
34932       v7 = t;
34933       t  = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
34934       v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
34935       v6 = t;
34936
34937       // stage 1
34938       p[row] = v0 + v7;
34939       p[row + 7] = v0 - v7;
34940       p[row + 1] = v1 + v6;
34941       p[row + 6] = v1 - v6;
34942       p[row + 2] = v2 + v5;
34943       p[row + 5] = v2 - v5;
34944       p[row + 3] = v3 + v4;
34945       p[row + 4] = v3 - v4;
34946     }
34947
34948     // inverse DCT on columns
34949     for (var col = 0; col < 8; ++col) {
34950       p0 = p[col];
34951       p1 = p[col +  8];
34952       p2 = p[col + 16];
34953       p3 = p[col + 24];
34954       p4 = p[col + 32];
34955       p5 = p[col + 40];
34956       p6 = p[col + 48];
34957       p7 = p[col + 56];
34958
34959       // check for all-zero AC coefficients
34960       if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
34961         t = (dctSqrt2 * p0 + 8192) >> 14;
34962         // convert to 8 bit
34963         t = (t < -2040) ? 0 : (t >= 2024) ? 255 : (t + 2056) >> 4;
34964         blockData[blockBufferOffset + col] = t;
34965         blockData[blockBufferOffset + col +  8] = t;
34966         blockData[blockBufferOffset + col + 16] = t;
34967         blockData[blockBufferOffset + col + 24] = t;
34968         blockData[blockBufferOffset + col + 32] = t;
34969         blockData[blockBufferOffset + col + 40] = t;
34970         blockData[blockBufferOffset + col + 48] = t;
34971         blockData[blockBufferOffset + col + 56] = t;
34972         continue;
34973       }
34974
34975       // stage 4
34976       v0 = (dctSqrt2 * p0 + 2048) >> 12;
34977       v1 = (dctSqrt2 * p4 + 2048) >> 12;
34978       v2 = p2;
34979       v3 = p6;
34980       v4 = (dctSqrt1d2 * (p1 - p7) + 2048) >> 12;
34981       v7 = (dctSqrt1d2 * (p1 + p7) + 2048) >> 12;
34982       v5 = p3;
34983       v6 = p5;
34984
34985       // stage 3
34986       // Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when
34987       // converting to UInt8 range later.
34988       v0 = ((v0 + v1 + 1) >> 1) + 4112;
34989       v1 = v0 - v1;
34990       t  = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
34991       v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
34992       v3 = t;
34993       v4 = (v4 + v6 + 1) >> 1;
34994       v6 = v4 - v6;
34995       v7 = (v7 + v5 + 1) >> 1;
34996       v5 = v7 - v5;
34997
34998       // stage 2
34999       v0 = (v0 + v3 + 1) >> 1;
35000       v3 = v0 - v3;
35001       v1 = (v1 + v2 + 1) >> 1;
35002       v2 = v1 - v2;
35003       t  = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
35004       v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
35005       v7 = t;
35006       t  = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
35007       v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
35008       v6 = t;
35009
35010       // stage 1
35011       p0 = v0 + v7;
35012       p7 = v0 - v7;
35013       p1 = v1 + v6;
35014       p6 = v1 - v6;
35015       p2 = v2 + v5;
35016       p5 = v2 - v5;
35017       p3 = v3 + v4;
35018       p4 = v3 - v4;
35019
35020       // convert to 8-bit integers
35021       p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? 255 : p0 >> 4;
35022       p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? 255 : p1 >> 4;
35023       p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? 255 : p2 >> 4;
35024       p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? 255 : p3 >> 4;
35025       p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? 255 : p4 >> 4;
35026       p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? 255 : p5 >> 4;
35027       p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? 255 : p6 >> 4;
35028       p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? 255 : p7 >> 4;
35029
35030       // store block data
35031       blockData[blockBufferOffset + col] = p0;
35032       blockData[blockBufferOffset + col +  8] = p1;
35033       blockData[blockBufferOffset + col + 16] = p2;
35034       blockData[blockBufferOffset + col + 24] = p3;
35035       blockData[blockBufferOffset + col + 32] = p4;
35036       blockData[blockBufferOffset + col + 40] = p5;
35037       blockData[blockBufferOffset + col + 48] = p6;
35038       blockData[blockBufferOffset + col + 56] = p7;
35039     }
35040   }
35041
35042   function buildComponentData(frame, component) {
35043     var blocksPerLine = component.blocksPerLine;
35044     var blocksPerColumn = component.blocksPerColumn;
35045     var computationBuffer = new Int16Array(64);
35046
35047     for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
35048       for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
35049         var offset = getBlockBufferOffset(component, blockRow, blockCol);
35050         quantizeAndInverse(component, offset, computationBuffer);
35051       }
35052     }
35053     return component.blockData;
35054   }
35055
35056   function clamp0to255(a) {
35057     return a <= 0 ? 0 : a >= 255 ? 255 : a;
35058   }
35059
35060   constructor.prototype = {
35061     parse: function parse(data) {
35062
35063       function readUint16() {
35064         var value = (data[offset] << 8) | data[offset + 1];
35065         offset += 2;
35066         return value;
35067       }
35068
35069       function readDataBlock() {
35070         var length = readUint16();
35071         var array = data.subarray(offset, offset + length - 2);
35072         offset += array.length;
35073         return array;
35074       }
35075
35076       function prepareComponents(frame) {
35077         var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);
35078         var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
35079         for (var i = 0; i < frame.components.length; i++) {
35080           component = frame.components[i];
35081           var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) *
35082                                         component.h / frame.maxH);
35083           var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines  / 8) *
35084                                           component.v / frame.maxV);
35085           var blocksPerLineForMcu = mcusPerLine * component.h;
35086           var blocksPerColumnForMcu = mcusPerColumn * component.v;
35087
35088           var blocksBufferSize = 64 * blocksPerColumnForMcu *
35089                                       (blocksPerLineForMcu + 1);
35090           component.blockData = new Int16Array(blocksBufferSize);
35091           component.blocksPerLine = blocksPerLine;
35092           component.blocksPerColumn = blocksPerColumn;
35093         }
35094         frame.mcusPerLine = mcusPerLine;
35095         frame.mcusPerColumn = mcusPerColumn;
35096       }
35097
35098       var offset = 0, length = data.length;
35099       var jfif = null;
35100       var adobe = null;
35101       var pixels = null;
35102       var frame, resetInterval;
35103       var quantizationTables = [];
35104       var huffmanTablesAC = [], huffmanTablesDC = [];
35105       var fileMarker = readUint16();
35106       if (fileMarker !== 0xFFD8) { // SOI (Start of Image)
35107         throw 'SOI not found';
35108       }
35109
35110       fileMarker = readUint16();
35111       while (fileMarker !== 0xFFD9) { // EOI (End of image)
35112         var i, j, l;
35113         switch(fileMarker) {
35114           case 0xFFE0: // APP0 (Application Specific)
35115           case 0xFFE1: // APP1
35116           case 0xFFE2: // APP2
35117           case 0xFFE3: // APP3
35118           case 0xFFE4: // APP4
35119           case 0xFFE5: // APP5
35120           case 0xFFE6: // APP6
35121           case 0xFFE7: // APP7
35122           case 0xFFE8: // APP8
35123           case 0xFFE9: // APP9
35124           case 0xFFEA: // APP10
35125           case 0xFFEB: // APP11
35126           case 0xFFEC: // APP12
35127           case 0xFFED: // APP13
35128           case 0xFFEE: // APP14
35129           case 0xFFEF: // APP15
35130           case 0xFFFE: // COM (Comment)
35131             var appData = readDataBlock();
35132
35133             if (fileMarker === 0xFFE0) {
35134               if (appData[0] === 0x4A && appData[1] === 0x46 &&
35135                   appData[2] === 0x49 && appData[3] === 0x46 &&
35136                   appData[4] === 0) { // 'JFIF\x00'
35137                 jfif = {
35138                   version: { major: appData[5], minor: appData[6] },
35139                   densityUnits: appData[7],
35140                   xDensity: (appData[8] << 8) | appData[9],
35141                   yDensity: (appData[10] << 8) | appData[11],
35142                   thumbWidth: appData[12],
35143                   thumbHeight: appData[13],
35144                   thumbData: appData.subarray(14, 14 +
35145                                               3 * appData[12] * appData[13])
35146                 };
35147               }
35148             }
35149             // TODO APP1 - Exif
35150             if (fileMarker === 0xFFEE) {
35151               if (appData[0] === 0x41 && appData[1] === 0x64 &&
35152                   appData[2] === 0x6F && appData[3] === 0x62 &&
35153                   appData[4] === 0x65) { // 'Adobe'
35154                 adobe = {
35155                   version: (appData[5] << 8) | appData[6],
35156                   flags0: (appData[7] << 8) | appData[8],
35157                   flags1: (appData[9] << 8) | appData[10],
35158                   transformCode: appData[11]
35159                 };
35160               }
35161             }
35162             break;
35163
35164           case 0xFFDB: // DQT (Define Quantization Tables)
35165             var quantizationTablesLength = readUint16();
35166             var quantizationTablesEnd = quantizationTablesLength + offset - 2;
35167             var z;
35168             while (offset < quantizationTablesEnd) {
35169               var quantizationTableSpec = data[offset++];
35170               var tableData = new Uint16Array(64);
35171               if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
35172                 for (j = 0; j < 64; j++) {
35173                   z = dctZigZag[j];
35174                   tableData[z] = data[offset++];
35175                 }
35176               } else if ((quantizationTableSpec >> 4) === 1) { //16 bit
35177                 for (j = 0; j < 64; j++) {
35178                   z = dctZigZag[j];
35179                   tableData[z] = readUint16();
35180                 }
35181               } else {
35182                 throw 'DQT: invalid table spec';
35183               }
35184               quantizationTables[quantizationTableSpec & 15] = tableData;
35185             }
35186             break;
35187
35188           case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
35189           case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)
35190           case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
35191             if (frame) {
35192               throw 'Only single frame JPEGs supported';
35193             }
35194             readUint16(); // skip data length
35195             frame = {};
35196             frame.extended = (fileMarker === 0xFFC1);
35197             frame.progressive = (fileMarker === 0xFFC2);
35198             frame.precision = data[offset++];
35199             frame.scanLines = readUint16();
35200             frame.samplesPerLine = readUint16();
35201             frame.components = [];
35202             frame.componentIds = {};
35203             var componentsCount = data[offset++], componentId;
35204             var maxH = 0, maxV = 0;
35205             for (i = 0; i < componentsCount; i++) {
35206               componentId = data[offset];
35207               var h = data[offset + 1] >> 4;
35208               var v = data[offset + 1] & 15;
35209               if (maxH < h) {
35210                 maxH = h;
35211               }
35212               if (maxV < v) {
35213                 maxV = v;
35214               }
35215               var qId = data[offset + 2];
35216               l = frame.components.push({
35217                 h: h,
35218                 v: v,
35219                 quantizationTable: quantizationTables[qId]
35220               });
35221               frame.componentIds[componentId] = l - 1;
35222               offset += 3;
35223             }
35224             frame.maxH = maxH;
35225             frame.maxV = maxV;
35226             prepareComponents(frame);
35227             break;
35228
35229           case 0xFFC4: // DHT (Define Huffman Tables)
35230             var huffmanLength = readUint16();
35231             for (i = 2; i < huffmanLength;) {
35232               var huffmanTableSpec = data[offset++];
35233               var codeLengths = new Uint8Array(16);
35234               var codeLengthSum = 0;
35235               for (j = 0; j < 16; j++, offset++) {
35236                 codeLengthSum += (codeLengths[j] = data[offset]);
35237               }
35238               var huffmanValues = new Uint8Array(codeLengthSum);
35239               for (j = 0; j < codeLengthSum; j++, offset++) {
35240                 huffmanValues[j] = data[offset];
35241               }
35242               i += 17 + codeLengthSum;
35243
35244               ((huffmanTableSpec >> 4) === 0 ?
35245                 huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
35246                 buildHuffmanTable(codeLengths, huffmanValues);
35247             }
35248             break;
35249
35250           case 0xFFDD: // DRI (Define Restart Interval)
35251             readUint16(); // skip data length
35252             resetInterval = readUint16();
35253             break;
35254
35255           case 0xFFDA: // SOS (Start of Scan)
35256             var scanLength = readUint16();
35257             var selectorsCount = data[offset++];
35258             var components = [], component;
35259             for (i = 0; i < selectorsCount; i++) {
35260               var componentIndex = frame.componentIds[data[offset++]];
35261               component = frame.components[componentIndex];
35262               var tableSpec = data[offset++];
35263               component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
35264               component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
35265               components.push(component);
35266             }
35267             var spectralStart = data[offset++];
35268             var spectralEnd = data[offset++];
35269             var successiveApproximation = data[offset++];
35270             var processed = decodeScan(data, offset,
35271               frame, components, resetInterval,
35272               spectralStart, spectralEnd,
35273               successiveApproximation >> 4, successiveApproximation & 15);
35274             offset += processed;
35275             break;
35276
35277           case 0xFFFF: // Fill bytes
35278             if (data[offset] !== 0xFF) { // Avoid skipping a valid marker.
35279               offset--;
35280             }
35281             break;
35282
35283           default:
35284             if (data[offset - 3] === 0xFF &&
35285                 data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
35286               // could be incorrect encoding -- last 0xFF byte of the previous
35287               // block was eaten by the encoder
35288               offset -= 3;
35289               break;
35290             }
35291             throw 'unknown JPEG marker ' + fileMarker.toString(16);
35292         }
35293         fileMarker = readUint16();
35294       }
35295
35296       this.width = frame.samplesPerLine;
35297       this.height = frame.scanLines;
35298       this.jfif = jfif;
35299       this.adobe = adobe;
35300       this.components = [];
35301       for (i = 0; i < frame.components.length; i++) {
35302         component = frame.components[i];
35303         this.components.push({
35304           output: buildComponentData(frame, component),
35305           scaleX: component.h / frame.maxH,
35306           scaleY: component.v / frame.maxV,
35307           blocksPerLine: component.blocksPerLine,
35308           blocksPerColumn: component.blocksPerColumn
35309         });
35310       }
35311       this.numComponents = this.components.length;
35312     },
35313
35314     _getLinearizedBlockData: function getLinearizedBlockData(width, height) {
35315       var scaleX = this.width / width, scaleY = this.height / height;
35316
35317       var component, componentScaleX, componentScaleY, blocksPerScanline;
35318       var x, y, i, j, k;
35319       var index;
35320       var offset = 0;
35321       var output;
35322       var numComponents = this.components.length;
35323       var dataLength = width * height * numComponents;
35324       var data = new Uint8Array(dataLength);
35325       var xScaleBlockOffset = new Uint32Array(width);
35326       var mask3LSB = 0xfffffff8; // used to clear the 3 LSBs
35327
35328       for (i = 0; i < numComponents; i++) {
35329         component = this.components[i];
35330         componentScaleX = component.scaleX * scaleX;
35331         componentScaleY = component.scaleY * scaleY;
35332         offset = i;
35333         output = component.output;
35334         blocksPerScanline = (component.blocksPerLine + 1) << 3;
35335         // precalculate the xScaleBlockOffset
35336         for (x = 0; x < width; x++) {
35337           j = 0 | (x * componentScaleX);
35338           xScaleBlockOffset[x] = ((j & mask3LSB) << 3) | (j & 7);
35339         }
35340         // linearize the blocks of the component
35341         for (y = 0; y < height; y++) {
35342           j = 0 | (y * componentScaleY);
35343           index = blocksPerScanline * (j & mask3LSB) | ((j & 7) << 3);
35344           for (x = 0; x < width; x++) {
35345             data[offset] = output[index + xScaleBlockOffset[x]];
35346             offset += numComponents;
35347           }
35348         }
35349       }
35350
35351       // decodeTransform contains pairs of multiplier (-256..256) and additive
35352       var transform = this.decodeTransform;
35353       if (transform) {
35354         for (i = 0; i < dataLength;) {
35355           for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
35356             data[i] = ((data[i] * transform[k]) >> 8) + transform[k + 1];
35357           }
35358         }
35359       }
35360       return data;
35361     },
35362
35363     _isColorConversionNeeded: function isColorConversionNeeded() {
35364       if (this.adobe && this.adobe.transformCode) {
35365         // The adobe transform marker overrides any previous setting
35366         return true;
35367       } else if (this.numComponents === 3) {
35368         return true;
35369       } else {
35370         return false;
35371       }
35372     },
35373
35374     _convertYccToRgb: function convertYccToRgb(data) {
35375       var Y, Cb, Cr;
35376       for (var i = 0, length = data.length; i < length; i += 3) {
35377         Y  = data[i    ];
35378         Cb = data[i + 1];
35379         Cr = data[i + 2];
35380         data[i    ] = clamp0to255(Y - 179.456 + 1.402 * Cr);
35381         data[i + 1] = clamp0to255(Y + 135.459 - 0.344 * Cb - 0.714 * Cr);
35382         data[i + 2] = clamp0to255(Y - 226.816 + 1.772 * Cb);
35383       }
35384       return data;
35385     },
35386
35387     _convertYcckToRgb: function convertYcckToRgb(data) {
35388       var Y, Cb, Cr, k;
35389       var offset = 0;
35390       for (var i = 0, length = data.length; i < length; i += 4) {
35391         Y  = data[i];
35392         Cb = data[i + 1];
35393         Cr = data[i + 2];
35394         k = data[i + 3];
35395
35396         var r = -122.67195406894 +
35397           Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr -
35398                 5.4080610064599e-5 * Y + 0.00048449797120281 * k -
35399                 0.154362151871126) +
35400           Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y -
35401                 0.00477271405408747 * k + 1.53380253221734) +
35402           Y * (0.000961250184130688 * Y - 0.00266257332283933 * k +
35403                0.48357088451265) +
35404           k * (-0.000336197177618394 * k + 0.484791561490776);
35405
35406         var g = 107.268039397724 +
35407           Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr +
35408                 0.000659397001245577 * Y + 0.000426105652938837 * k -
35409                 0.176491792462875) +
35410           Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y +
35411                 0.000770482631801132 * k - 0.151051492775562) +
35412           Y * (0.00126935368114843 * Y - 0.00265090189010898 * k +
35413                0.25802910206845) +
35414           k * (-0.000318913117588328 * k - 0.213742400323665);
35415
35416         var b = -20.810012546947 +
35417           Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr +
35418                 0.0020741088115012 * Y - 0.00288260236853442 * k +
35419                 0.814272968359295) +
35420           Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y +
35421                 0.000560833691242812 * k - 0.195152027534049) +
35422           Y * (0.00174418132927582 * Y - 0.00255243321439347 * k +
35423                0.116935020465145) +
35424           k * (-0.000343531996510555 * k + 0.24165260232407);
35425
35426         data[offset++] = clamp0to255(r);
35427         data[offset++] = clamp0to255(g);
35428         data[offset++] = clamp0to255(b);
35429       }
35430       return data;
35431     },
35432
35433     _convertYcckToCmyk: function convertYcckToCmyk(data) {
35434       var Y, Cb, Cr;
35435       for (var i = 0, length = data.length; i < length; i += 4) {
35436         Y  = data[i];
35437         Cb = data[i + 1];
35438         Cr = data[i + 2];
35439         data[i    ] = clamp0to255(434.456 - Y - 1.402 * Cr);
35440         data[i + 1] = clamp0to255(119.541 - Y + 0.344 * Cb + 0.714 * Cr);
35441         data[i + 2] = clamp0to255(481.816 - Y - 1.772 * Cb);
35442         // K in data[i + 3] is unchanged
35443       }
35444       return data;
35445     },
35446
35447     _convertCmykToRgb: function convertCmykToRgb(data) {
35448       var c, m, y, k;
35449       var offset = 0;
35450       var min = -255 * 255 * 255;
35451       var scale = 1 / 255 / 255;
35452       for (var i = 0, length = data.length; i < length; i += 4) {
35453         c = data[i];
35454         m = data[i + 1];
35455         y = data[i + 2];
35456         k = data[i + 3];
35457
35458         var r =
35459           c * (-4.387332384609988 * c + 54.48615194189176 * m +
35460                18.82290502165302 * y + 212.25662451639585 * k -
35461                72734.4411664936) +
35462           m * (1.7149763477362134 * m - 5.6096736904047315 * y -
35463                17.873870861415444 * k - 1401.7366389350734) +
35464           y * (-2.5217340131683033 * y - 21.248923337353073 * k +
35465                4465.541406466231) -
35466           k * (21.86122147463605 * k + 48317.86113160301);
35467         var g =
35468           c * (8.841041422036149 * c + 60.118027045597366 * m +
35469                6.871425592049007 * y + 31.159100130055922 * k -
35470                20220.756542821975) +
35471           m * (-15.310361306967817 * m + 17.575251261109482 * y +
35472                131.35250912493976 * k - 48691.05921601825) +
35473           y * (4.444339102852739 * y + 9.8632861493405 * k -
35474                6341.191035517494) -
35475           k * (20.737325471181034 * k + 47890.15695978492);
35476         var b =
35477           c * (0.8842522430003296 * c + 8.078677503112928 * m +
35478                30.89978309703729 * y - 0.23883238689178934 * k -
35479                3616.812083916688) +
35480           m * (10.49593273432072 * m + 63.02378494754052 * y +
35481                50.606957656360734 * k - 28620.90484698408) +
35482           y * (0.03296041114873217 * y + 115.60384449646641 * k -
35483                49363.43385999684) -
35484           k * (22.33816807309886 * k + 45932.16563550634);
35485
35486         data[offset++] = r >= 0 ? 255 : r <= min ? 0 : 255 + r * scale | 0;
35487         data[offset++] = g >= 0 ? 255 : g <= min ? 0 : 255 + g * scale | 0;
35488         data[offset++] = b >= 0 ? 255 : b <= min ? 0 : 255 + b * scale | 0;
35489       }
35490       return data;
35491     },
35492
35493     getData: function getData(width, height, forceRGBoutput) {
35494       if (this.numComponents > 4) {
35495         throw 'Unsupported color mode';
35496       }
35497       // type of data: Uint8Array(width * height * numComponents)
35498       var data = this._getLinearizedBlockData(width, height);
35499
35500       if (this.numComponents === 3) {
35501         return this._convertYccToRgb(data);
35502       } else if (this.numComponents === 4) {
35503         if (this._isColorConversionNeeded()) {
35504           if (forceRGBoutput) {
35505             return this._convertYcckToRgb(data);
35506           } else {
35507             return this._convertYcckToCmyk(data);
35508           }
35509         } else if (forceRGBoutput) {
35510           return this._convertCmykToRgb(data);
35511         }
35512       }
35513       return data;
35514     }
35515   };
35516
35517   return constructor;
35518 })();
35519
35520
35521 var JpxImage = (function JpxImageClosure() {
35522   // Table E.1
35523   var SubbandsGainLog2 = {
35524     'LL': 0,
35525     'LH': 1,
35526     'HL': 1,
35527     'HH': 2
35528   };
35529   function JpxImage() {
35530     this.failOnCorruptedImage = false;
35531   }
35532   JpxImage.prototype = {
35533     parse: function JpxImage_parse(data) {
35534
35535       var head = readUint16(data, 0);
35536       // No box header, immediate start of codestream (SOC)
35537       if (head === 0xFF4F) {
35538         this.parseCodestream(data, 0, data.length);
35539         return;
35540       }
35541
35542       var position = 0, length = data.length;
35543       while (position < length) {
35544         var headerSize = 8;
35545         var lbox = readUint32(data, position);
35546         var tbox = readUint32(data, position + 4);
35547         position += headerSize;
35548         if (lbox === 1) {
35549           // XLBox: read UInt64 according to spec.
35550           // JavaScript's int precision of 53 bit should be sufficient here.
35551           lbox = readUint32(data, position) * 4294967296 +
35552                  readUint32(data, position + 4);
35553           position += 8;
35554           headerSize += 8;
35555         }
35556         if (lbox === 0) {
35557           lbox = length - position + headerSize;
35558         }
35559         if (lbox < headerSize) {
35560           throw new Error('JPX Error: Invalid box field size');
35561         }
35562         var dataLength = lbox - headerSize;
35563         var jumpDataLength = true;
35564         switch (tbox) {
35565           case 0x6A703268: // 'jp2h'
35566             jumpDataLength = false; // parsing child boxes
35567             break;
35568           case 0x636F6C72: // 'colr'
35569             // Colorspaces are not used, the CS from the PDF is used.
35570             var method = data[position];
35571             var precedence = data[position + 1];
35572             var approximation = data[position + 2];
35573             if (method === 1) {
35574               // enumerated colorspace
35575               var colorspace = readUint32(data, position + 3);
35576               switch (colorspace) {
35577                 case 16: // this indicates a sRGB colorspace
35578                 case 17: // this indicates a grayscale colorspace
35579                 case 18: // this indicates a YUV colorspace
35580                   break;
35581                 default:
35582                   warn('Unknown colorspace ' + colorspace);
35583                   break;
35584               }
35585             } else if (method === 2) {
35586               info('ICC profile not supported');
35587             }
35588             break;
35589           case 0x6A703263: // 'jp2c'
35590             this.parseCodestream(data, position, position + dataLength);
35591             break;
35592           case 0x6A502020: // 'jP\024\024'
35593             if (0x0d0a870a !== readUint32(data, position)) {
35594               warn('Invalid JP2 signature');
35595             }
35596             break;
35597           // The following header types are valid but currently not used:
35598           case 0x6A501A1A: // 'jP\032\032'
35599           case 0x66747970: // 'ftyp'
35600           case 0x72726571: // 'rreq'
35601           case 0x72657320: // 'res '
35602           case 0x69686472: // 'ihdr'
35603             break;
35604           default:
35605             var headerType = String.fromCharCode((tbox >> 24) & 0xFF,
35606                                                  (tbox >> 16) & 0xFF,
35607                                                  (tbox >> 8) & 0xFF,
35608                                                  tbox & 0xFF);
35609             warn('Unsupported header type ' + tbox + ' (' + headerType + ')');
35610             break;
35611         }
35612         if (jumpDataLength) {
35613           position += dataLength;
35614         }
35615       }
35616     },
35617     parseImageProperties: function JpxImage_parseImageProperties(stream) {
35618       var newByte = stream.getByte();
35619       while (newByte >= 0) {
35620         var oldByte = newByte;
35621         newByte = stream.getByte();
35622         var code = (oldByte << 8) | newByte;
35623         // Image and tile size (SIZ)
35624         if (code === 0xFF51) {
35625           stream.skip(4);
35626           var Xsiz = stream.getInt32() >>> 0; // Byte 4
35627           var Ysiz = stream.getInt32() >>> 0; // Byte 8
35628           var XOsiz = stream.getInt32() >>> 0; // Byte 12
35629           var YOsiz = stream.getInt32() >>> 0; // Byte 16
35630           stream.skip(16);
35631           var Csiz = stream.getUint16(); // Byte 36
35632           this.width = Xsiz - XOsiz;
35633           this.height = Ysiz - YOsiz;
35634           this.componentsCount = Csiz;
35635           // Results are always returned as Uint8Arrays
35636           this.bitsPerComponent = 8;
35637           return;
35638         }
35639       }
35640       throw new Error('JPX Error: No size marker found in JPX stream');
35641     },
35642     parseCodestream: function JpxImage_parseCodestream(data, start, end) {
35643       var context = {};
35644       try {
35645         var doNotRecover = false;
35646         var position = start;
35647         while (position + 1 < end) {
35648           var code = readUint16(data, position);
35649           position += 2;
35650
35651           var length = 0, j, sqcd, spqcds, spqcdSize, scalarExpounded, tile;
35652           switch (code) {
35653             case 0xFF4F: // Start of codestream (SOC)
35654               context.mainHeader = true;
35655               break;
35656             case 0xFFD9: // End of codestream (EOC)
35657               break;
35658             case 0xFF51: // Image and tile size (SIZ)
35659               length = readUint16(data, position);
35660               var siz = {};
35661               siz.Xsiz = readUint32(data, position + 4);
35662               siz.Ysiz = readUint32(data, position + 8);
35663               siz.XOsiz = readUint32(data, position + 12);
35664               siz.YOsiz = readUint32(data, position + 16);
35665               siz.XTsiz = readUint32(data, position + 20);
35666               siz.YTsiz = readUint32(data, position + 24);
35667               siz.XTOsiz = readUint32(data, position + 28);
35668               siz.YTOsiz = readUint32(data, position + 32);
35669               var componentsCount = readUint16(data, position + 36);
35670               siz.Csiz = componentsCount;
35671               var components = [];
35672               j = position + 38;
35673               for (var i = 0; i < componentsCount; i++) {
35674                 var component = {
35675                   precision: (data[j] & 0x7F) + 1,
35676                   isSigned: !!(data[j] & 0x80),
35677                   XRsiz: data[j + 1],
35678                   YRsiz: data[j + 1]
35679                 };
35680                 calculateComponentDimensions(component, siz);
35681                 components.push(component);
35682               }
35683               context.SIZ = siz;
35684               context.components = components;
35685               calculateTileGrids(context, components);
35686               context.QCC = [];
35687               context.COC = [];
35688               break;
35689             case 0xFF5C: // Quantization default (QCD)
35690               length = readUint16(data, position);
35691               var qcd = {};
35692               j = position + 2;
35693               sqcd = data[j++];
35694               switch (sqcd & 0x1F) {
35695                 case 0:
35696                   spqcdSize = 8;
35697                   scalarExpounded = true;
35698                   break;
35699                 case 1:
35700                   spqcdSize = 16;
35701                   scalarExpounded = false;
35702                   break;
35703                 case 2:
35704                   spqcdSize = 16;
35705                   scalarExpounded = true;
35706                   break;
35707                 default:
35708                   throw new Error('JPX Error: Invalid SQcd value ' + sqcd);
35709               }
35710               qcd.noQuantization = (spqcdSize === 8);
35711               qcd.scalarExpounded = scalarExpounded;
35712               qcd.guardBits = sqcd >> 5;
35713               spqcds = [];
35714               while (j < length + position) {
35715                 var spqcd = {};
35716                 if (spqcdSize === 8) {
35717                   spqcd.epsilon = data[j++] >> 3;
35718                   spqcd.mu = 0;
35719                 } else {
35720                   spqcd.epsilon = data[j] >> 3;
35721                   spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
35722                   j += 2;
35723                 }
35724                 spqcds.push(spqcd);
35725               }
35726               qcd.SPqcds = spqcds;
35727               if (context.mainHeader) {
35728                 context.QCD = qcd;
35729               } else {
35730                 context.currentTile.QCD = qcd;
35731                 context.currentTile.QCC = [];
35732               }
35733               break;
35734             case 0xFF5D: // Quantization component (QCC)
35735               length = readUint16(data, position);
35736               var qcc = {};
35737               j = position + 2;
35738               var cqcc;
35739               if (context.SIZ.Csiz < 257) {
35740                 cqcc = data[j++];
35741               } else {
35742                 cqcc = readUint16(data, j);
35743                 j += 2;
35744               }
35745               sqcd = data[j++];
35746               switch (sqcd & 0x1F) {
35747                 case 0:
35748                   spqcdSize = 8;
35749                   scalarExpounded = true;
35750                   break;
35751                 case 1:
35752                   spqcdSize = 16;
35753                   scalarExpounded = false;
35754                   break;
35755                 case 2:
35756                   spqcdSize = 16;
35757                   scalarExpounded = true;
35758                   break;
35759                 default:
35760                   throw new Error('JPX Error: Invalid SQcd value ' + sqcd);
35761               }
35762               qcc.noQuantization = (spqcdSize === 8);
35763               qcc.scalarExpounded = scalarExpounded;
35764               qcc.guardBits = sqcd >> 5;
35765               spqcds = [];
35766               while (j < (length + position)) {
35767                 spqcd = {};
35768                 if (spqcdSize === 8) {
35769                   spqcd.epsilon = data[j++] >> 3;
35770                   spqcd.mu = 0;
35771                 } else {
35772                   spqcd.epsilon = data[j] >> 3;
35773                   spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
35774                   j += 2;
35775                 }
35776                 spqcds.push(spqcd);
35777               }
35778               qcc.SPqcds = spqcds;
35779               if (context.mainHeader) {
35780                 context.QCC[cqcc] = qcc;
35781               } else {
35782                 context.currentTile.QCC[cqcc] = qcc;
35783               }
35784               break;
35785             case 0xFF52: // Coding style default (COD)
35786               length = readUint16(data, position);
35787               var cod = {};
35788               j = position + 2;
35789               var scod = data[j++];
35790               cod.entropyCoderWithCustomPrecincts = !!(scod & 1);
35791               cod.sopMarkerUsed = !!(scod & 2);
35792               cod.ephMarkerUsed = !!(scod & 4);
35793               cod.progressionOrder = data[j++];
35794               cod.layersCount = readUint16(data, j);
35795               j += 2;
35796               cod.multipleComponentTransform = data[j++];
35797
35798               cod.decompositionLevelsCount = data[j++];
35799               cod.xcb = (data[j++] & 0xF) + 2;
35800               cod.ycb = (data[j++] & 0xF) + 2;
35801               var blockStyle = data[j++];
35802               cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1);
35803               cod.resetContextProbabilities = !!(blockStyle & 2);
35804               cod.terminationOnEachCodingPass = !!(blockStyle & 4);
35805               cod.verticalyStripe = !!(blockStyle & 8);
35806               cod.predictableTermination = !!(blockStyle & 16);
35807               cod.segmentationSymbolUsed = !!(blockStyle & 32);
35808               cod.reversibleTransformation = data[j++];
35809               if (cod.entropyCoderWithCustomPrecincts) {
35810                 var precinctsSizes = [];
35811                 while (j < length + position) {
35812                   var precinctsSize = data[j++];
35813                   precinctsSizes.push({
35814                     PPx: precinctsSize & 0xF,
35815                     PPy: precinctsSize >> 4
35816                   });
35817                 }
35818                 cod.precinctsSizes = precinctsSizes;
35819               }
35820               var unsupported = [];
35821               if (cod.selectiveArithmeticCodingBypass) {
35822                 unsupported.push('selectiveArithmeticCodingBypass');
35823               }
35824               if (cod.resetContextProbabilities) {
35825                 unsupported.push('resetContextProbabilities');
35826               }
35827               if (cod.terminationOnEachCodingPass) {
35828                 unsupported.push('terminationOnEachCodingPass');
35829               }
35830               if (cod.verticalyStripe) {
35831                 unsupported.push('verticalyStripe');
35832               }
35833               if (cod.predictableTermination) {
35834                 unsupported.push('predictableTermination');
35835               }
35836               if (unsupported.length > 0) {
35837                 doNotRecover = true;
35838                 throw new Error('JPX Error: Unsupported COD options (' +
35839                                 unsupported.join(', ') + ')');
35840               }
35841               if (context.mainHeader) {
35842                 context.COD = cod;
35843               } else {
35844                 context.currentTile.COD = cod;
35845                 context.currentTile.COC = [];
35846               }
35847               break;
35848             case 0xFF90: // Start of tile-part (SOT)
35849               length = readUint16(data, position);
35850               tile = {};
35851               tile.index = readUint16(data, position + 2);
35852               tile.length = readUint32(data, position + 4);
35853               tile.dataEnd = tile.length + position - 2;
35854               tile.partIndex = data[position + 8];
35855               tile.partsCount = data[position + 9];
35856
35857               context.mainHeader = false;
35858               if (tile.partIndex === 0) {
35859                 // reset component specific settings
35860                 tile.COD = context.COD;
35861                 tile.COC = context.COC.slice(0); // clone of the global COC
35862                 tile.QCD = context.QCD;
35863                 tile.QCC = context.QCC.slice(0); // clone of the global COC
35864               }
35865               context.currentTile = tile;
35866               break;
35867             case 0xFF93: // Start of data (SOD)
35868               tile = context.currentTile;
35869               if (tile.partIndex === 0) {
35870                 initializeTile(context, tile.index);
35871                 buildPackets(context);
35872               }
35873
35874               // moving to the end of the data
35875               length = tile.dataEnd - position;
35876               parseTilePackets(context, data, position, length);
35877               break;
35878             case 0xFF55: // Tile-part lengths, main header (TLM)
35879             case 0xFF57: // Packet length, main header (PLM)
35880             case 0xFF58: // Packet length, tile-part header (PLT)
35881             case 0xFF64: // Comment (COM)
35882               length = readUint16(data, position);
35883               // skipping content
35884               break;
35885             case 0xFF53: // Coding style component (COC)
35886               throw new Error('JPX Error: Codestream code 0xFF53 (COC) is ' +
35887                               'not implemented');
35888             default:
35889               throw new Error('JPX Error: Unknown codestream code: ' +
35890                               code.toString(16));
35891           }
35892           position += length;
35893         }
35894       } catch (e) {
35895         if (doNotRecover || this.failOnCorruptedImage) {
35896           throw e;
35897         } else {
35898           warn('Trying to recover from ' + e.message);
35899         }
35900       }
35901       this.tiles = transformComponents(context);
35902       this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;
35903       this.height = context.SIZ.Ysiz - context.SIZ.YOsiz;
35904       this.componentsCount = context.SIZ.Csiz;
35905     }
35906   };
35907   function calculateComponentDimensions(component, siz) {
35908     // Section B.2 Component mapping
35909     component.x0 = Math.ceil(siz.XOsiz / component.XRsiz);
35910     component.x1 = Math.ceil(siz.Xsiz / component.XRsiz);
35911     component.y0 = Math.ceil(siz.YOsiz / component.YRsiz);
35912     component.y1 = Math.ceil(siz.Ysiz / component.YRsiz);
35913     component.width = component.x1 - component.x0;
35914     component.height = component.y1 - component.y0;
35915   }
35916   function calculateTileGrids(context, components) {
35917     var siz = context.SIZ;
35918     // Section B.3 Division into tile and tile-components
35919     var tile, tiles = [];
35920     var numXtiles = Math.ceil((siz.Xsiz - siz.XTOsiz) / siz.XTsiz);
35921     var numYtiles = Math.ceil((siz.Ysiz - siz.YTOsiz) / siz.YTsiz);
35922     for (var q = 0; q < numYtiles; q++) {
35923       for (var p = 0; p < numXtiles; p++) {
35924         tile = {};
35925         tile.tx0 = Math.max(siz.XTOsiz + p * siz.XTsiz, siz.XOsiz);
35926         tile.ty0 = Math.max(siz.YTOsiz + q * siz.YTsiz, siz.YOsiz);
35927         tile.tx1 = Math.min(siz.XTOsiz + (p + 1) * siz.XTsiz, siz.Xsiz);
35928         tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz);
35929         tile.width = tile.tx1 - tile.tx0;
35930         tile.height = tile.ty1 - tile.ty0;
35931         tile.components = [];
35932         tiles.push(tile);
35933       }
35934     }
35935     context.tiles = tiles;
35936
35937     var componentsCount = siz.Csiz;
35938     for (var i = 0, ii = componentsCount; i < ii; i++) {
35939       var component = components[i];
35940       for (var j = 0, jj = tiles.length; j < jj; j++) {
35941         var tileComponent = {};
35942         tile = tiles[j];
35943         tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
35944         tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
35945         tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
35946         tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz);
35947         tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0;
35948         tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0;
35949         tile.components[i] = tileComponent;
35950       }
35951     }
35952   }
35953   function getBlocksDimensions(context, component, r) {
35954     var codOrCoc = component.codingStyleParameters;
35955     var result = {};
35956     if (!codOrCoc.entropyCoderWithCustomPrecincts) {
35957       result.PPx = 15;
35958       result.PPy = 15;
35959     } else {
35960       result.PPx = codOrCoc.precinctsSizes[r].PPx;
35961       result.PPy = codOrCoc.precinctsSizes[r].PPy;
35962     }
35963     // calculate codeblock size as described in section B.7
35964     result.xcb_ = (r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) :
35965                    Math.min(codOrCoc.xcb, result.PPx));
35966     result.ycb_ = (r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) :
35967                    Math.min(codOrCoc.ycb, result.PPy));
35968     return result;
35969   }
35970   function buildPrecincts(context, resolution, dimensions) {
35971     // Section B.6 Division resolution to precincts
35972     var precinctWidth = 1 << dimensions.PPx;
35973     var precinctHeight = 1 << dimensions.PPy;
35974     // Jasper introduces codeblock groups for mapping each subband codeblocks
35975     // to precincts. Precinct partition divides a resolution according to width
35976     // and height parameters. The subband that belongs to the resolution level
35977     // has a different size than the level, unless it is the zero resolution.
35978
35979     // From Jasper documentation: jpeg2000.pdf, section K: Tier-2 coding:
35980     // The precinct partitioning for a particular subband is derived from a
35981     // partitioning of its parent LL band (i.e., the LL band at the next higher
35982     // resolution level)... The LL band associated with each resolution level is
35983     // divided into precincts... Each of the resulting precinct regions is then
35984     // mapped into its child subbands (if any) at the next lower resolution
35985     // level. This is accomplished by using the coordinate transformation
35986     // (u, v) = (ceil(x/2), ceil(y/2)) where (x, y) and (u, v) are the
35987     // coordinates of a point in the LL band and child subband, respectively.
35988     var isZeroRes = resolution.resLevel === 0;
35989     var precinctWidthInSubband = 1 << (dimensions.PPx + (isZeroRes ? 0 : -1));
35990     var precinctHeightInSubband = 1 << (dimensions.PPy + (isZeroRes ? 0 : -1));
35991     var numprecinctswide = (resolution.trx1 > resolution.trx0 ?
35992       Math.ceil(resolution.trx1 / precinctWidth) -
35993       Math.floor(resolution.trx0 / precinctWidth) : 0);
35994     var numprecinctshigh = (resolution.try1 > resolution.try0 ?
35995       Math.ceil(resolution.try1 / precinctHeight) -
35996       Math.floor(resolution.try0 / precinctHeight) : 0);
35997     var numprecincts = numprecinctswide * numprecinctshigh;
35998
35999     resolution.precinctParameters = {
36000       precinctWidth: precinctWidth,
36001       precinctHeight: precinctHeight,
36002       numprecinctswide: numprecinctswide,
36003       numprecinctshigh: numprecinctshigh,
36004       numprecincts: numprecincts,
36005       precinctWidthInSubband: precinctWidthInSubband,
36006       precinctHeightInSubband: precinctHeightInSubband
36007     };
36008   }
36009   function buildCodeblocks(context, subband, dimensions) {
36010     // Section B.7 Division sub-band into code-blocks
36011     var xcb_ = dimensions.xcb_;
36012     var ycb_ = dimensions.ycb_;
36013     var codeblockWidth = 1 << xcb_;
36014     var codeblockHeight = 1 << ycb_;
36015     var cbx0 = subband.tbx0 >> xcb_;
36016     var cby0 = subband.tby0 >> ycb_;
36017     var cbx1 = (subband.tbx1 + codeblockWidth - 1) >> xcb_;
36018     var cby1 = (subband.tby1 + codeblockHeight - 1) >> ycb_;
36019     var precinctParameters = subband.resolution.precinctParameters;
36020     var codeblocks = [];
36021     var precincts = [];
36022     var i, j, codeblock, precinctNumber;
36023     for (j = cby0; j < cby1; j++) {
36024       for (i = cbx0; i < cbx1; i++) {
36025         codeblock = {
36026           cbx: i,
36027           cby: j,
36028           tbx0: codeblockWidth * i,
36029           tby0: codeblockHeight * j,
36030           tbx1: codeblockWidth * (i + 1),
36031           tby1: codeblockHeight * (j + 1)
36032         };
36033
36034         codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0);
36035         codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0);
36036         codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1);
36037         codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1);
36038
36039         // Calculate precinct number for this codeblock, codeblock position
36040         // should be relative to its subband, use actual dimension and position
36041         // See comment about codeblock group width and height
36042         var pi = Math.floor((codeblock.tbx0_ - subband.tbx0) /
36043           precinctParameters.precinctWidthInSubband);
36044         var pj = Math.floor((codeblock.tby0_ - subband.tby0) /
36045           precinctParameters.precinctHeightInSubband);
36046         precinctNumber = pi + (pj * precinctParameters.numprecinctswide);
36047
36048         codeblock.precinctNumber = precinctNumber;
36049         codeblock.subbandType = subband.type;
36050         codeblock.Lblock = 3;
36051
36052         if (codeblock.tbx1_ <= codeblock.tbx0_ ||
36053             codeblock.tby1_ <= codeblock.tby0_) {
36054           continue;
36055         }
36056         codeblocks.push(codeblock);
36057         // building precinct for the sub-band
36058         var precinct = precincts[precinctNumber];
36059         if (precinct !== undefined) {
36060           if (i < precinct.cbxMin) {
36061             precinct.cbxMin = i;
36062           } else if (i > precinct.cbxMax) {
36063             precinct.cbxMax = i;
36064           }
36065           if (j < precinct.cbyMin) {
36066             precinct.cbxMin = j;
36067           } else if (j > precinct.cbyMax) {
36068             precinct.cbyMax = j;
36069           }
36070         } else {
36071           precincts[precinctNumber] = precinct = {
36072             cbxMin: i,
36073             cbyMin: j,
36074             cbxMax: i,
36075             cbyMax: j
36076           };
36077         }
36078         codeblock.precinct = precinct;
36079       }
36080     }
36081     subband.codeblockParameters = {
36082       codeblockWidth: xcb_,
36083       codeblockHeight: ycb_,
36084       numcodeblockwide: cbx1 - cbx0 + 1,
36085       numcodeblockhigh: cby1 - cby0 + 1
36086     };
36087     subband.codeblocks = codeblocks;
36088     subband.precincts = precincts;
36089   }
36090   function createPacket(resolution, precinctNumber, layerNumber) {
36091     var precinctCodeblocks = [];
36092     // Section B.10.8 Order of info in packet
36093     var subbands = resolution.subbands;
36094     // sub-bands already ordered in 'LL', 'HL', 'LH', and 'HH' sequence
36095     for (var i = 0, ii = subbands.length; i < ii; i++) {
36096       var subband = subbands[i];
36097       var codeblocks = subband.codeblocks;
36098       for (var j = 0, jj = codeblocks.length; j < jj; j++) {
36099         var codeblock = codeblocks[j];
36100         if (codeblock.precinctNumber !== precinctNumber) {
36101           continue;
36102         }
36103         precinctCodeblocks.push(codeblock);
36104       }
36105     }
36106     return {
36107       layerNumber: layerNumber,
36108       codeblocks: precinctCodeblocks
36109     };
36110   }
36111   function LayerResolutionComponentPositionIterator(context) {
36112     var siz = context.SIZ;
36113     var tileIndex = context.currentTile.index;
36114     var tile = context.tiles[tileIndex];
36115     var layersCount = tile.codingStyleDefaultParameters.layersCount;
36116     var componentsCount = siz.Csiz;
36117     var maxDecompositionLevelsCount = 0;
36118     for (var q = 0; q < componentsCount; q++) {
36119       maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
36120         tile.components[q].codingStyleParameters.decompositionLevelsCount);
36121     }
36122
36123     var l = 0, r = 0, i = 0, k = 0;
36124
36125     this.nextPacket = function JpxImage_nextPacket() {
36126       // Section B.12.1.1 Layer-resolution-component-position
36127       for (; l < layersCount; l++) {
36128         for (; r <= maxDecompositionLevelsCount; r++) {
36129           for (; i < componentsCount; i++) {
36130             var component = tile.components[i];
36131             if (r > component.codingStyleParameters.decompositionLevelsCount) {
36132               continue;
36133             }
36134
36135             var resolution = component.resolutions[r];
36136             var numprecincts = resolution.precinctParameters.numprecincts;
36137             for (; k < numprecincts;) {
36138               var packet = createPacket(resolution, k, l);
36139               k++;
36140               return packet;
36141             }
36142             k = 0;
36143           }
36144           i = 0;
36145         }
36146         r = 0;
36147       }
36148       throw new Error('JPX Error: Out of packets');
36149     };
36150   }
36151   function ResolutionLayerComponentPositionIterator(context) {
36152     var siz = context.SIZ;
36153     var tileIndex = context.currentTile.index;
36154     var tile = context.tiles[tileIndex];
36155     var layersCount = tile.codingStyleDefaultParameters.layersCount;
36156     var componentsCount = siz.Csiz;
36157     var maxDecompositionLevelsCount = 0;
36158     for (var q = 0; q < componentsCount; q++) {
36159       maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
36160         tile.components[q].codingStyleParameters.decompositionLevelsCount);
36161     }
36162
36163     var r = 0, l = 0, i = 0, k = 0;
36164
36165     this.nextPacket = function JpxImage_nextPacket() {
36166       // Section B.12.1.2 Resolution-layer-component-position
36167       for (; r <= maxDecompositionLevelsCount; r++) {
36168         for (; l < layersCount; l++) {
36169           for (; i < componentsCount; i++) {
36170             var component = tile.components[i];
36171             if (r > component.codingStyleParameters.decompositionLevelsCount) {
36172               continue;
36173             }
36174
36175             var resolution = component.resolutions[r];
36176             var numprecincts = resolution.precinctParameters.numprecincts;
36177             for (; k < numprecincts;) {
36178               var packet = createPacket(resolution, k, l);
36179               k++;
36180               return packet;
36181             }
36182             k = 0;
36183           }
36184           i = 0;
36185         }
36186         l = 0;
36187       }
36188       throw new Error('JPX Error: Out of packets');
36189     };
36190   }
36191   function ResolutionPositionComponentLayerIterator(context) {
36192     var siz = context.SIZ;
36193     var tileIndex = context.currentTile.index;
36194     var tile = context.tiles[tileIndex];
36195     var layersCount = tile.codingStyleDefaultParameters.layersCount;
36196     var componentsCount = siz.Csiz;
36197     var l, r, c, p;
36198     var maxDecompositionLevelsCount = 0;
36199     for (c = 0; c < componentsCount; c++) {
36200       var component = tile.components[c];
36201       maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
36202         component.codingStyleParameters.decompositionLevelsCount);
36203     }
36204     var maxNumPrecinctsInLevel = new Int32Array(
36205       maxDecompositionLevelsCount + 1);
36206     for (r = 0; r <= maxDecompositionLevelsCount; ++r) {
36207       var maxNumPrecincts = 0;
36208       for (c = 0; c < componentsCount; ++c) {
36209         var resolutions = tile.components[c].resolutions;
36210         if (r < resolutions.length) {
36211           maxNumPrecincts = Math.max(maxNumPrecincts,
36212             resolutions[r].precinctParameters.numprecincts);
36213         }
36214       }
36215       maxNumPrecinctsInLevel[r] = maxNumPrecincts;
36216     }
36217     l = 0;
36218     r = 0;
36219     c = 0;
36220     p = 0;
36221
36222     this.nextPacket = function JpxImage_nextPacket() {
36223       // Section B.12.1.3 Resolution-position-component-layer
36224       for (; r <= maxDecompositionLevelsCount; r++) {
36225         for (; p < maxNumPrecinctsInLevel[r]; p++) {
36226           for (; c < componentsCount; c++) {
36227             var component = tile.components[c];
36228             if (r > component.codingStyleParameters.decompositionLevelsCount) {
36229               continue;
36230             }
36231             var resolution = component.resolutions[r];
36232             var numprecincts = resolution.precinctParameters.numprecincts;
36233             if (p >= numprecincts) {
36234               continue;
36235             }
36236             for (; l < layersCount;) {
36237               var packet = createPacket(resolution, p, l);
36238               l++;
36239               return packet;
36240             }
36241             l = 0;
36242           }
36243           c = 0;
36244         }
36245         p = 0;
36246       }
36247       throw new Error('JPX Error: Out of packets');
36248     };
36249   }
36250   function PositionComponentResolutionLayerIterator(context) {
36251     var siz = context.SIZ;
36252     var tileIndex = context.currentTile.index;
36253     var tile = context.tiles[tileIndex];
36254     var layersCount = tile.codingStyleDefaultParameters.layersCount;
36255     var componentsCount = siz.Csiz;
36256     var precinctsSizes = getPrecinctSizesInImageScale(tile);
36257     var precinctsIterationSizes = precinctsSizes;
36258     var l = 0, r = 0, c = 0, px = 0, py = 0;
36259
36260     this.nextPacket = function JpxImage_nextPacket() {
36261       // Section B.12.1.4 Position-component-resolution-layer
36262       for (; py < precinctsIterationSizes.maxNumHigh; py++) {
36263         for (; px < precinctsIterationSizes.maxNumWide; px++) {
36264           for (; c < componentsCount; c++) {
36265             var component = tile.components[c];
36266             var decompositionLevelsCount =
36267               component.codingStyleParameters.decompositionLevelsCount;
36268             for (; r <= decompositionLevelsCount; r++) {
36269               var resolution = component.resolutions[r];
36270               var sizeInImageScale =
36271                 precinctsSizes.components[c].resolutions[r];
36272               var k = getPrecinctIndexIfExist(
36273                 px,
36274                 py,
36275                 sizeInImageScale,
36276                 precinctsIterationSizes,
36277                 resolution);
36278               if (k === null) {
36279                 continue;
36280               }
36281               for (; l < layersCount;) {
36282                 var packet = createPacket(resolution, k, l);
36283                 l++;
36284                 return packet;
36285               }
36286               l = 0;
36287             }
36288             r = 0;
36289           }
36290           c = 0;
36291         }
36292         px = 0;
36293       }
36294       throw new Error('JPX Error: Out of packets');
36295     };
36296   }
36297   function ComponentPositionResolutionLayerIterator(context) {
36298     var siz = context.SIZ;
36299     var tileIndex = context.currentTile.index;
36300     var tile = context.tiles[tileIndex];
36301     var layersCount = tile.codingStyleDefaultParameters.layersCount;
36302     var componentsCount = siz.Csiz;
36303     var precinctsSizes = getPrecinctSizesInImageScale(tile);
36304     var l = 0, r = 0, c = 0, px = 0, py = 0;
36305
36306     this.nextPacket = function JpxImage_nextPacket() {
36307       // Section B.12.1.5 Component-position-resolution-layer
36308       for (; c < componentsCount; ++c) {
36309         var component = tile.components[c];
36310         var precinctsIterationSizes = precinctsSizes.components[c];
36311         var decompositionLevelsCount =
36312           component.codingStyleParameters.decompositionLevelsCount;
36313         for (; py < precinctsIterationSizes.maxNumHigh; py++) {
36314           for (; px < precinctsIterationSizes.maxNumWide; px++) {
36315             for (; r <= decompositionLevelsCount; r++) {
36316               var resolution = component.resolutions[r];
36317               var sizeInImageScale = precinctsIterationSizes.resolutions[r];
36318               var k = getPrecinctIndexIfExist(
36319                 px,
36320                 py,
36321                 sizeInImageScale,
36322                 precinctsIterationSizes,
36323                 resolution);
36324               if (k === null) {
36325                 continue;
36326               }
36327               for (; l < layersCount;) {
36328                 var packet = createPacket(resolution, k, l);
36329                 l++;
36330                 return packet;
36331               }
36332               l = 0;
36333             }
36334             r = 0;
36335           }
36336           px = 0;
36337         }
36338         py = 0;
36339       }
36340       throw new Error('JPX Error: Out of packets');
36341     };
36342   }
36343   function getPrecinctIndexIfExist(
36344     pxIndex, pyIndex, sizeInImageScale, precinctIterationSizes, resolution) {
36345     var posX = pxIndex * precinctIterationSizes.minWidth;
36346     var posY = pyIndex * precinctIterationSizes.minHeight;
36347     if (posX % sizeInImageScale.width !== 0 ||
36348         posY % sizeInImageScale.height !== 0) {
36349       return null;
36350     }
36351     var startPrecinctRowIndex =
36352       (posY / sizeInImageScale.width) *
36353       resolution.precinctParameters.numprecinctswide;
36354     return (posX / sizeInImageScale.height) + startPrecinctRowIndex;
36355   }
36356   function getPrecinctSizesInImageScale(tile) {
36357     var componentsCount = tile.components.length;
36358     var minWidth = Number.MAX_VALUE;
36359     var minHeight = Number.MAX_VALUE;
36360     var maxNumWide = 0;
36361     var maxNumHigh = 0;
36362     var sizePerComponent = new Array(componentsCount);
36363     for (var c = 0; c < componentsCount; c++) {
36364       var component = tile.components[c];
36365       var decompositionLevelsCount =
36366         component.codingStyleParameters.decompositionLevelsCount;
36367       var sizePerResolution = new Array(decompositionLevelsCount + 1);
36368       var minWidthCurrentComponent = Number.MAX_VALUE;
36369       var minHeightCurrentComponent = Number.MAX_VALUE;
36370       var maxNumWideCurrentComponent = 0;
36371       var maxNumHighCurrentComponent = 0;
36372       var scale = 1;
36373       for (var r = decompositionLevelsCount; r >= 0; --r) {
36374         var resolution = component.resolutions[r];
36375         var widthCurrentResolution =
36376           scale * resolution.precinctParameters.precinctWidth;
36377         var heightCurrentResolution =
36378           scale * resolution.precinctParameters.precinctHeight;
36379         minWidthCurrentComponent = Math.min(
36380           minWidthCurrentComponent,
36381           widthCurrentResolution);
36382         minHeightCurrentComponent = Math.min(
36383           minHeightCurrentComponent,
36384           heightCurrentResolution);
36385         maxNumWideCurrentComponent = Math.max(maxNumWideCurrentComponent,
36386           resolution.precinctParameters.numprecinctswide);
36387         maxNumHighCurrentComponent = Math.max(maxNumHighCurrentComponent,
36388           resolution.precinctParameters.numprecinctshigh);
36389         sizePerResolution[r] = {
36390           width: widthCurrentResolution,
36391           height: heightCurrentResolution
36392         };
36393         scale <<= 1;
36394       }
36395       minWidth = Math.min(minWidth, minWidthCurrentComponent);
36396       minHeight = Math.min(minHeight, minHeightCurrentComponent);
36397       maxNumWide = Math.max(maxNumWide, maxNumWideCurrentComponent);
36398       maxNumHigh = Math.max(maxNumHigh, maxNumHighCurrentComponent);
36399       sizePerComponent[c] = {
36400         resolutions: sizePerResolution,
36401         minWidth: minWidthCurrentComponent,
36402         minHeight: minHeightCurrentComponent,
36403         maxNumWide: maxNumWideCurrentComponent,
36404         maxNumHigh: maxNumHighCurrentComponent
36405       };
36406     }
36407     return {
36408       components: sizePerComponent,
36409       minWidth: minWidth,
36410       minHeight: minHeight,
36411       maxNumWide: maxNumWide,
36412       maxNumHigh: maxNumHigh
36413     };
36414   }
36415   function buildPackets(context) {
36416     var siz = context.SIZ;
36417     var tileIndex = context.currentTile.index;
36418     var tile = context.tiles[tileIndex];
36419     var componentsCount = siz.Csiz;
36420     // Creating resolutions and sub-bands for each component
36421     for (var c = 0; c < componentsCount; c++) {
36422       var component = tile.components[c];
36423       var decompositionLevelsCount =
36424         component.codingStyleParameters.decompositionLevelsCount;
36425       // Section B.5 Resolution levels and sub-bands
36426       var resolutions = [];
36427       var subbands = [];
36428       for (var r = 0; r <= decompositionLevelsCount; r++) {
36429         var blocksDimensions = getBlocksDimensions(context, component, r);
36430         var resolution = {};
36431         var scale = 1 << (decompositionLevelsCount - r);
36432         resolution.trx0 = Math.ceil(component.tcx0 / scale);
36433         resolution.try0 = Math.ceil(component.tcy0 / scale);
36434         resolution.trx1 = Math.ceil(component.tcx1 / scale);
36435         resolution.try1 = Math.ceil(component.tcy1 / scale);
36436         resolution.resLevel = r;
36437         buildPrecincts(context, resolution, blocksDimensions);
36438         resolutions.push(resolution);
36439
36440         var subband;
36441         if (r === 0) {
36442           // one sub-band (LL) with last decomposition
36443           subband = {};
36444           subband.type = 'LL';
36445           subband.tbx0 = Math.ceil(component.tcx0 / scale);
36446           subband.tby0 = Math.ceil(component.tcy0 / scale);
36447           subband.tbx1 = Math.ceil(component.tcx1 / scale);
36448           subband.tby1 = Math.ceil(component.tcy1 / scale);
36449           subband.resolution = resolution;
36450           buildCodeblocks(context, subband, blocksDimensions);
36451           subbands.push(subband);
36452           resolution.subbands = [subband];
36453         } else {
36454           var bscale = 1 << (decompositionLevelsCount - r + 1);
36455           var resolutionSubbands = [];
36456           // three sub-bands (HL, LH and HH) with rest of decompositions
36457           subband = {};
36458           subband.type = 'HL';
36459           subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
36460           subband.tby0 = Math.ceil(component.tcy0 / bscale);
36461           subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
36462           subband.tby1 = Math.ceil(component.tcy1 / bscale);
36463           subband.resolution = resolution;
36464           buildCodeblocks(context, subband, blocksDimensions);
36465           subbands.push(subband);
36466           resolutionSubbands.push(subband);
36467
36468           subband = {};
36469           subband.type = 'LH';
36470           subband.tbx0 = Math.ceil(component.tcx0 / bscale);
36471           subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
36472           subband.tbx1 = Math.ceil(component.tcx1 / bscale);
36473           subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
36474           subband.resolution = resolution;
36475           buildCodeblocks(context, subband, blocksDimensions);
36476           subbands.push(subband);
36477           resolutionSubbands.push(subband);
36478
36479           subband = {};
36480           subband.type = 'HH';
36481           subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
36482           subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
36483           subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
36484           subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
36485           subband.resolution = resolution;
36486           buildCodeblocks(context, subband, blocksDimensions);
36487           subbands.push(subband);
36488           resolutionSubbands.push(subband);
36489
36490           resolution.subbands = resolutionSubbands;
36491         }
36492       }
36493       component.resolutions = resolutions;
36494       component.subbands = subbands;
36495     }
36496     // Generate the packets sequence
36497     var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
36498     switch (progressionOrder) {
36499       case 0:
36500         tile.packetsIterator =
36501           new LayerResolutionComponentPositionIterator(context);
36502         break;
36503       case 1:
36504         tile.packetsIterator =
36505           new ResolutionLayerComponentPositionIterator(context);
36506         break;
36507       case 2:
36508         tile.packetsIterator =
36509           new ResolutionPositionComponentLayerIterator(context);
36510         break;
36511       case 3:
36512         tile.packetsIterator =
36513           new PositionComponentResolutionLayerIterator(context);
36514         break;
36515       case 4:
36516         tile.packetsIterator =
36517           new ComponentPositionResolutionLayerIterator(context);
36518         break;
36519       default:
36520         throw new Error('JPX Error: Unsupported progression order ' +
36521                         progressionOrder);
36522     }
36523   }
36524   function parseTilePackets(context, data, offset, dataLength) {
36525     var position = 0;
36526     var buffer, bufferSize = 0, skipNextBit = false;
36527     function readBits(count) {
36528       while (bufferSize < count) {
36529         var b = data[offset + position];
36530         position++;
36531         if (skipNextBit) {
36532           buffer = (buffer << 7) | b;
36533           bufferSize += 7;
36534           skipNextBit = false;
36535         } else {
36536           buffer = (buffer << 8) | b;
36537           bufferSize += 8;
36538         }
36539         if (b === 0xFF) {
36540           skipNextBit = true;
36541         }
36542       }
36543       bufferSize -= count;
36544       return (buffer >>> bufferSize) & ((1 << count) - 1);
36545     }
36546     function skipMarkerIfEqual(value) {
36547       if (data[offset + position - 1] === 0xFF &&
36548           data[offset + position] === value) {
36549         skipBytes(1);
36550         return true;
36551       } else if (data[offset + position] === 0xFF &&
36552                  data[offset + position + 1] === value) {
36553         skipBytes(2);
36554         return true;
36555       }
36556       return false;
36557     }
36558     function skipBytes(count) {
36559       position += count;
36560     }
36561     function alignToByte() {
36562       bufferSize = 0;
36563       if (skipNextBit) {
36564         position++;
36565         skipNextBit = false;
36566       }
36567     }
36568     function readCodingpasses() {
36569       if (readBits(1) === 0) {
36570         return 1;
36571       }
36572       if (readBits(1) === 0) {
36573         return 2;
36574       }
36575       var value = readBits(2);
36576       if (value < 3) {
36577         return value + 3;
36578       }
36579       value = readBits(5);
36580       if (value < 31) {
36581         return value + 6;
36582       }
36583       value = readBits(7);
36584       return value + 37;
36585     }
36586     var tileIndex = context.currentTile.index;
36587     var tile = context.tiles[tileIndex];
36588     var sopMarkerUsed = context.COD.sopMarkerUsed;
36589     var ephMarkerUsed = context.COD.ephMarkerUsed;
36590     var packetsIterator = tile.packetsIterator;
36591     while (position < dataLength) {
36592       alignToByte();
36593       if (sopMarkerUsed && skipMarkerIfEqual(0x91)) {
36594         // Skip also marker segment length and packet sequence ID
36595         skipBytes(4);
36596       }
36597       var packet = packetsIterator.nextPacket();
36598       if (!readBits(1)) {
36599         continue;
36600       }
36601       var layerNumber = packet.layerNumber;
36602       var queue = [], codeblock;
36603       for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {
36604         codeblock = packet.codeblocks[i];
36605         var precinct = codeblock.precinct;
36606         var codeblockColumn = codeblock.cbx - precinct.cbxMin;
36607         var codeblockRow = codeblock.cby - precinct.cbyMin;
36608         var codeblockIncluded = false;
36609         var firstTimeInclusion = false;
36610         var valueReady;
36611         if (codeblock['included'] !== undefined) {
36612           codeblockIncluded = !!readBits(1);
36613         } else {
36614           // reading inclusion tree
36615           precinct = codeblock.precinct;
36616           var inclusionTree, zeroBitPlanesTree;
36617           if (precinct['inclusionTree'] !== undefined) {
36618             inclusionTree = precinct.inclusionTree;
36619           } else {
36620             // building inclusion and zero bit-planes trees
36621             var width = precinct.cbxMax - precinct.cbxMin + 1;
36622             var height = precinct.cbyMax - precinct.cbyMin + 1;
36623             inclusionTree = new InclusionTree(width, height, layerNumber);
36624             zeroBitPlanesTree = new TagTree(width, height);
36625             precinct.inclusionTree = inclusionTree;
36626             precinct.zeroBitPlanesTree = zeroBitPlanesTree;
36627           }
36628
36629           if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {
36630             while (true) {
36631               if (readBits(1)) {
36632                 valueReady = !inclusionTree.nextLevel();
36633                 if (valueReady) {
36634                   codeblock.included = true;
36635                   codeblockIncluded = firstTimeInclusion = true;
36636                   break;
36637                 }
36638               } else {
36639                 inclusionTree.incrementValue(layerNumber);
36640                 break;
36641               }
36642             }
36643           }
36644         }
36645         if (!codeblockIncluded) {
36646           continue;
36647         }
36648         if (firstTimeInclusion) {
36649           zeroBitPlanesTree = precinct.zeroBitPlanesTree;
36650           zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);
36651           while (true) {
36652             if (readBits(1)) {
36653               valueReady = !zeroBitPlanesTree.nextLevel();
36654               if (valueReady) {
36655                 break;
36656               }
36657             } else {
36658               zeroBitPlanesTree.incrementValue();
36659             }
36660           }
36661           codeblock.zeroBitPlanes = zeroBitPlanesTree.value;
36662         }
36663         var codingpasses = readCodingpasses();
36664         while (readBits(1)) {
36665           codeblock.Lblock++;
36666         }
36667         var codingpassesLog2 = log2(codingpasses);
36668         // rounding down log2
36669         var bits = ((codingpasses < (1 << codingpassesLog2)) ?
36670           codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock;
36671         var codedDataLength = readBits(bits);
36672         queue.push({
36673           codeblock: codeblock,
36674           codingpasses: codingpasses,
36675           dataLength: codedDataLength
36676         });
36677       }
36678       alignToByte();
36679       if (ephMarkerUsed) {
36680         skipMarkerIfEqual(0x92);
36681       }
36682       while (queue.length > 0) {
36683         var packetItem = queue.shift();
36684         codeblock = packetItem.codeblock;
36685         if (codeblock['data'] === undefined) {
36686           codeblock.data = [];
36687         }
36688         codeblock.data.push({
36689           data: data,
36690           start: offset + position,
36691           end: offset + position + packetItem.dataLength,
36692           codingpasses: packetItem.codingpasses
36693         });
36694         position += packetItem.dataLength;
36695       }
36696     }
36697     return position;
36698   }
36699   function copyCoefficients(coefficients, levelWidth, levelHeight, subband,
36700                             delta, mb, reversible, segmentationSymbolUsed) {
36701     var x0 = subband.tbx0;
36702     var y0 = subband.tby0;
36703     var width = subband.tbx1 - subband.tbx0;
36704     var codeblocks = subband.codeblocks;
36705     var right = subband.type.charAt(0) === 'H' ? 1 : 0;
36706     var bottom = subband.type.charAt(1) === 'H' ? levelWidth : 0;
36707
36708     for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
36709       var codeblock = codeblocks[i];
36710       var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
36711       var blockHeight = codeblock.tby1_ - codeblock.tby0_;
36712       if (blockWidth === 0 || blockHeight === 0) {
36713         continue;
36714       }
36715       if (codeblock['data'] === undefined) {
36716         continue;
36717       }
36718
36719       var bitModel, currentCodingpassType;
36720       bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
36721                               codeblock.zeroBitPlanes, mb);
36722       currentCodingpassType = 2; // first bit plane starts from cleanup
36723
36724       // collect data
36725       var data = codeblock.data, totalLength = 0, codingpasses = 0;
36726       var j, jj, dataItem;
36727       for (j = 0, jj = data.length; j < jj; j++) {
36728         dataItem = data[j];
36729         totalLength += dataItem.end - dataItem.start;
36730         codingpasses += dataItem.codingpasses;
36731       }
36732       var encodedData = new Uint8Array(totalLength);
36733       var position = 0;
36734       for (j = 0, jj = data.length; j < jj; j++) {
36735         dataItem = data[j];
36736         var chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
36737         encodedData.set(chunk, position);
36738         position += chunk.length;
36739       }
36740       // decoding the item
36741       var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
36742       bitModel.setDecoder(decoder);
36743
36744       for (j = 0; j < codingpasses; j++) {
36745         switch (currentCodingpassType) {
36746           case 0:
36747             bitModel.runSignificancePropogationPass();
36748             break;
36749           case 1:
36750             bitModel.runMagnitudeRefinementPass();
36751             break;
36752           case 2:
36753             bitModel.runCleanupPass();
36754             if (segmentationSymbolUsed) {
36755               bitModel.checkSegmentationSymbol();
36756             }
36757             break;
36758         }
36759         currentCodingpassType = (currentCodingpassType + 1) % 3;
36760       }
36761
36762       var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;
36763       var sign = bitModel.coefficentsSign;
36764       var magnitude = bitModel.coefficentsMagnitude;
36765       var bitsDecoded = bitModel.bitsDecoded;
36766       var magnitudeCorrection = reversible ? 0 : 0.5;
36767       var k, n, nb;
36768       position = 0;
36769       // Do the interleaving of Section F.3.3 here, so we do not need
36770       // to copy later. LL level is not interleaved, just copied.
36771       var interleave = (subband.type !== 'LL');
36772       for (j = 0; j < blockHeight; j++) {
36773         var row = (offset / width) | 0; // row in the non-interleaved subband
36774         var levelOffset = 2 * row * (levelWidth - width) + right + bottom;
36775         for (k = 0; k < blockWidth; k++) {
36776           n = magnitude[position];
36777           if (n !== 0) {
36778             n = (n + magnitudeCorrection) * delta;
36779             if (sign[position] !== 0) {
36780               n = -n;
36781             }
36782             nb = bitsDecoded[position];
36783             var pos = interleave ? (levelOffset + (offset << 1)) : offset;
36784             if (reversible && (nb >= mb)) {
36785               coefficients[pos] = n;
36786             } else {
36787               coefficients[pos] = n * (1 << (mb - nb));
36788             }
36789           }
36790           offset++;
36791           position++;
36792         }
36793         offset += width - blockWidth;
36794       }
36795     }
36796   }
36797   function transformTile(context, tile, c) {
36798     var component = tile.components[c];
36799     var codingStyleParameters = component.codingStyleParameters;
36800     var quantizationParameters = component.quantizationParameters;
36801     var decompositionLevelsCount =
36802       codingStyleParameters.decompositionLevelsCount;
36803     var spqcds = quantizationParameters.SPqcds;
36804     var scalarExpounded = quantizationParameters.scalarExpounded;
36805     var guardBits = quantizationParameters.guardBits;
36806     var segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed;
36807     var precision = context.components[c].precision;
36808
36809     var reversible = codingStyleParameters.reversibleTransformation;
36810     var transform = (reversible ? new ReversibleTransform() :
36811                                   new IrreversibleTransform());
36812
36813     var subbandCoefficients = [];
36814     var b = 0;
36815     for (var i = 0; i <= decompositionLevelsCount; i++) {
36816       var resolution = component.resolutions[i];
36817
36818       var width = resolution.trx1 - resolution.trx0;
36819       var height = resolution.try1 - resolution.try0;
36820       // Allocate space for the whole sublevel.
36821       var coefficients = new Float32Array(width * height);
36822
36823       for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
36824         var mu, epsilon;
36825         if (!scalarExpounded) {
36826           // formula E-5
36827           mu = spqcds[0].mu;
36828           epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0);
36829         } else {
36830           mu = spqcds[b].mu;
36831           epsilon = spqcds[b].epsilon;
36832           b++;
36833         }
36834
36835         var subband = resolution.subbands[j];
36836         var gainLog2 = SubbandsGainLog2[subband.type];
36837
36838         // calulate quantization coefficient (Section E.1.1.1)
36839         var delta = (reversible ? 1 :
36840           Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048));
36841         var mb = (guardBits + epsilon - 1);
36842
36843         // In the first resolution level, copyCoefficients will fill the
36844         // whole array with coefficients. In the succeding passes,
36845         // copyCoefficients will consecutively fill in the values that belong
36846         // to the interleaved positions of the HL, LH, and HH coefficients.
36847         // The LL coefficients will then be interleaved in Transform.iterate().
36848         copyCoefficients(coefficients, width, height, subband, delta, mb,
36849                          reversible, segmentationSymbolUsed);
36850       }
36851       subbandCoefficients.push({
36852         width: width,
36853         height: height,
36854         items: coefficients
36855       });
36856     }
36857
36858     var result = transform.calculate(subbandCoefficients,
36859                                      component.tcx0, component.tcy0);
36860     return {
36861       left: component.tcx0,
36862       top: component.tcy0,
36863       width: result.width,
36864       height: result.height,
36865       items: result.items
36866     };
36867   }
36868   function transformComponents(context) {
36869     var siz = context.SIZ;
36870     var components = context.components;
36871     var componentsCount = siz.Csiz;
36872     var resultImages = [];
36873     for (var i = 0, ii = context.tiles.length; i < ii; i++) {
36874       var tile = context.tiles[i];
36875       var transformedTiles = [];
36876       var c;
36877       for (c = 0; c < componentsCount; c++) {
36878         transformedTiles[c] = transformTile(context, tile, c);
36879       }
36880       var tile0 = transformedTiles[0];
36881       var out = new Uint8Array(tile0.items.length * componentsCount);
36882       var result = {
36883         left: tile0.left,
36884         top: tile0.top,
36885         width: tile0.width,
36886         height: tile0.height,
36887         items: out
36888       };
36889
36890       // Section G.2.2 Inverse multi component transform
36891       var shift, offset, max, min, maxK;
36892       var pos = 0, j, jj, y0, y1, y2, r, g, b, k, val;
36893       if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
36894         var fourComponents = componentsCount === 4;
36895         var y0items = transformedTiles[0].items;
36896         var y1items = transformedTiles[1].items;
36897         var y2items = transformedTiles[2].items;
36898         var y3items = fourComponents ? transformedTiles[3].items : null;
36899
36900         // HACK: The multiple component transform formulas below assume that
36901         // all components have the same precision. With this in mind, we
36902         // compute shift and offset only once.
36903         shift = components[0].precision - 8;
36904         offset = (128 << shift) + 0.5;
36905         max = 255 * (1 << shift);
36906         maxK = max * 0.5;
36907         min = -maxK;
36908
36909         var component0 = tile.components[0];
36910         var alpha01 = componentsCount - 3;
36911         jj = y0items.length;
36912         if (!component0.codingStyleParameters.reversibleTransformation) {
36913           // inverse irreversible multiple component transform
36914           for (j = 0; j < jj; j++, pos += alpha01) {
36915             y0 = y0items[j] + offset;
36916             y1 = y1items[j];
36917             y2 = y2items[j];
36918             r = y0 + 1.402 * y2;
36919             g = y0 - 0.34413 * y1 - 0.71414 * y2;
36920             b = y0 + 1.772 * y1;
36921             out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
36922             out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
36923             out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
36924           }
36925         } else {
36926           // inverse reversible multiple component transform
36927           for (j = 0; j < jj; j++, pos += alpha01) {
36928             y0 = y0items[j] + offset;
36929             y1 = y1items[j];
36930             y2 = y2items[j];
36931             g = y0 - ((y2 + y1) >> 2);
36932             r = g + y2;
36933             b = g + y1;
36934             out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
36935             out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
36936             out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
36937           }
36938         }
36939         if (fourComponents) {
36940           for (j = 0, pos = 3; j < jj; j++, pos += 4) {
36941             k = y3items[j];
36942             out[pos] = k <= min ? 0 : k >= maxK ? 255 : (k + offset) >> shift;
36943           }
36944         }
36945       } else { // no multi-component transform
36946         for (c = 0; c < componentsCount; c++) {
36947           var items = transformedTiles[c].items;
36948           shift = components[c].precision - 8;
36949           offset = (128 << shift) + 0.5;
36950           max = (127.5 * (1 << shift));
36951           min = -max;
36952           for (pos = c, j = 0, jj = items.length; j < jj; j++) {
36953             val = items[j];
36954             out[pos] = val <= min ? 0 :
36955                        val >= max ? 255 : (val + offset) >> shift;
36956             pos += componentsCount;
36957           }
36958         }
36959       }
36960       resultImages.push(result);
36961     }
36962     return resultImages;
36963   }
36964   function initializeTile(context, tileIndex) {
36965     var siz = context.SIZ;
36966     var componentsCount = siz.Csiz;
36967     var tile = context.tiles[tileIndex];
36968     for (var c = 0; c < componentsCount; c++) {
36969       var component = tile.components[c];
36970       var qcdOrQcc = (context.currentTile.QCC[c] !== undefined ?
36971         context.currentTile.QCC[c] : context.currentTile.QCD);
36972       component.quantizationParameters = qcdOrQcc;
36973       var codOrCoc = (context.currentTile.COC[c] !== undefined  ?
36974         context.currentTile.COC[c] : context.currentTile.COD);
36975       component.codingStyleParameters = codOrCoc;
36976     }
36977     tile.codingStyleDefaultParameters = context.currentTile.COD;
36978   }
36979
36980   // Section B.10.2 Tag trees
36981   var TagTree = (function TagTreeClosure() {
36982     function TagTree(width, height) {
36983       var levelsLength = log2(Math.max(width, height)) + 1;
36984       this.levels = [];
36985       for (var i = 0; i < levelsLength; i++) {
36986         var level = {
36987           width: width,
36988           height: height,
36989           items: []
36990         };
36991         this.levels.push(level);
36992         width = Math.ceil(width / 2);
36993         height = Math.ceil(height / 2);
36994       }
36995     }
36996     TagTree.prototype = {
36997       reset: function TagTree_reset(i, j) {
36998         var currentLevel = 0, value = 0, level;
36999         while (currentLevel < this.levels.length) {
37000           level = this.levels[currentLevel];
37001           var index = i + j * level.width;
37002           if (level.items[index] !== undefined) {
37003             value = level.items[index];
37004             break;
37005           }
37006           level.index = index;
37007           i >>= 1;
37008           j >>= 1;
37009           currentLevel++;
37010         }
37011         currentLevel--;
37012         level = this.levels[currentLevel];
37013         level.items[level.index] = value;
37014         this.currentLevel = currentLevel;
37015         delete this.value;
37016       },
37017       incrementValue: function TagTree_incrementValue() {
37018         var level = this.levels[this.currentLevel];
37019         level.items[level.index]++;
37020       },
37021       nextLevel: function TagTree_nextLevel() {
37022         var currentLevel = this.currentLevel;
37023         var level = this.levels[currentLevel];
37024         var value = level.items[level.index];
37025         currentLevel--;
37026         if (currentLevel < 0) {
37027           this.value = value;
37028           return false;
37029         }
37030
37031         this.currentLevel = currentLevel;
37032         level = this.levels[currentLevel];
37033         level.items[level.index] = value;
37034         return true;
37035       }
37036     };
37037     return TagTree;
37038   })();
37039
37040   var InclusionTree = (function InclusionTreeClosure() {
37041     function InclusionTree(width, height,  defaultValue) {
37042       var levelsLength = log2(Math.max(width, height)) + 1;
37043       this.levels = [];
37044       for (var i = 0; i < levelsLength; i++) {
37045         var items = new Uint8Array(width * height);
37046         for (var j = 0, jj = items.length; j < jj; j++) {
37047           items[j] = defaultValue;
37048         }
37049
37050         var level = {
37051           width: width,
37052           height: height,
37053           items: items
37054         };
37055         this.levels.push(level);
37056
37057         width = Math.ceil(width / 2);
37058         height = Math.ceil(height / 2);
37059       }
37060     }
37061     InclusionTree.prototype = {
37062       reset: function InclusionTree_reset(i, j, stopValue) {
37063         var currentLevel = 0;
37064         while (currentLevel < this.levels.length) {
37065           var level = this.levels[currentLevel];
37066           var index = i + j * level.width;
37067           level.index = index;
37068           var value = level.items[index];
37069
37070           if (value === 0xFF) {
37071             break;
37072           }
37073
37074           if (value > stopValue) {
37075             this.currentLevel = currentLevel;
37076             // already know about this one, propagating the value to top levels
37077             this.propagateValues();
37078             return false;
37079           }
37080
37081           i >>= 1;
37082           j >>= 1;
37083           currentLevel++;
37084         }
37085         this.currentLevel = currentLevel - 1;
37086         return true;
37087       },
37088       incrementValue: function InclusionTree_incrementValue(stopValue) {
37089         var level = this.levels[this.currentLevel];
37090         level.items[level.index] = stopValue + 1;
37091         this.propagateValues();
37092       },
37093       propagateValues: function InclusionTree_propagateValues() {
37094         var levelIndex = this.currentLevel;
37095         var level = this.levels[levelIndex];
37096         var currentValue = level.items[level.index];
37097         while (--levelIndex >= 0) {
37098           level = this.levels[levelIndex];
37099           level.items[level.index] = currentValue;
37100         }
37101       },
37102       nextLevel: function InclusionTree_nextLevel() {
37103         var currentLevel = this.currentLevel;
37104         var level = this.levels[currentLevel];
37105         var value = level.items[level.index];
37106         level.items[level.index] = 0xFF;
37107         currentLevel--;
37108         if (currentLevel < 0) {
37109           return false;
37110         }
37111
37112         this.currentLevel = currentLevel;
37113         level = this.levels[currentLevel];
37114         level.items[level.index] = value;
37115         return true;
37116       }
37117     };
37118     return InclusionTree;
37119   })();
37120
37121   // Section D. Coefficient bit modeling
37122   var BitModel = (function BitModelClosure() {
37123     var UNIFORM_CONTEXT = 17;
37124     var RUNLENGTH_CONTEXT = 18;
37125     // Table D-1
37126     // The index is binary presentation: 0dddvvhh, ddd - sum of Di (0..4),
37127     // vv - sum of Vi (0..2), and hh - sum of Hi (0..2)
37128     var LLAndLHContextsLabel = new Uint8Array([
37129       0, 5, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 1, 6, 8, 0, 3, 7, 8, 0, 4,
37130       7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6,
37131       8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8
37132     ]);
37133     var HLContextLabel = new Uint8Array([
37134       0, 3, 4, 0, 5, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 3, 4, 0, 6, 7, 7, 0, 8,
37135       8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3,
37136       4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8
37137     ]);
37138     var HHContextLabel = new Uint8Array([
37139       0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5,
37140       5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8,
37141       8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8
37142     ]);
37143
37144     function BitModel(width, height, subband, zeroBitPlanes, mb) {
37145       this.width = width;
37146       this.height = height;
37147
37148       this.contextLabelTable = (subband === 'HH' ? HHContextLabel :
37149         (subband === 'HL' ? HLContextLabel : LLAndLHContextsLabel));
37150
37151       var coefficientCount = width * height;
37152
37153       // coefficients outside the encoding region treated as insignificant
37154       // add border state cells for significanceState
37155       this.neighborsSignificance = new Uint8Array(coefficientCount);
37156       this.coefficentsSign = new Uint8Array(coefficientCount);
37157       this.coefficentsMagnitude = mb > 14 ? new Uint32Array(coefficientCount) :
37158                                   mb > 6 ? new Uint16Array(coefficientCount) :
37159                                   new Uint8Array(coefficientCount);
37160       this.processingFlags = new Uint8Array(coefficientCount);
37161
37162       var bitsDecoded = new Uint8Array(coefficientCount);
37163       if (zeroBitPlanes !== 0) {
37164         for (var i = 0; i < coefficientCount; i++) {
37165           bitsDecoded[i] = zeroBitPlanes;
37166         }
37167       }
37168       this.bitsDecoded = bitsDecoded;
37169
37170       this.reset();
37171     }
37172
37173     BitModel.prototype = {
37174       setDecoder: function BitModel_setDecoder(decoder) {
37175         this.decoder = decoder;
37176       },
37177       reset: function BitModel_reset() {
37178         // We have 17 contexts that are accessed via context labels,
37179         // plus the uniform and runlength context.
37180         this.contexts = new Int8Array(19);
37181
37182         // Contexts are packed into 1 byte:
37183         // highest 7 bits carry the index, lowest bit carries mps
37184         this.contexts[0] = (4 << 1) | 0;
37185         this.contexts[UNIFORM_CONTEXT] = (46 << 1) | 0;
37186         this.contexts[RUNLENGTH_CONTEXT] = (3 << 1) | 0;
37187       },
37188       setNeighborsSignificance:
37189         function BitModel_setNeighborsSignificance(row, column, index) {
37190         var neighborsSignificance = this.neighborsSignificance;
37191         var width = this.width, height = this.height;
37192         var left = (column > 0);
37193         var right = (column + 1 < width);
37194         var i;
37195
37196         if (row > 0) {
37197           i = index - width;
37198           if (left) {
37199             neighborsSignificance[i - 1] += 0x10;
37200           }
37201           if (right) {
37202             neighborsSignificance[i + 1] += 0x10;
37203           }
37204           neighborsSignificance[i] += 0x04;
37205         }
37206
37207         if (row + 1 < height) {
37208           i = index + width;
37209           if (left) {
37210             neighborsSignificance[i - 1] += 0x10;
37211           }
37212           if (right) {
37213             neighborsSignificance[i + 1] += 0x10;
37214           }
37215           neighborsSignificance[i] += 0x04;
37216         }
37217
37218         if (left) {
37219           neighborsSignificance[index - 1] += 0x01;
37220         }
37221         if (right) {
37222           neighborsSignificance[index + 1] += 0x01;
37223         }
37224         neighborsSignificance[index] |= 0x80;
37225       },
37226       runSignificancePropogationPass:
37227         function BitModel_runSignificancePropogationPass() {
37228         var decoder = this.decoder;
37229         var width = this.width, height = this.height;
37230         var coefficentsMagnitude = this.coefficentsMagnitude;
37231         var coefficentsSign = this.coefficentsSign;
37232         var neighborsSignificance = this.neighborsSignificance;
37233         var processingFlags = this.processingFlags;
37234         var contexts = this.contexts;
37235         var labels = this.contextLabelTable;
37236         var bitsDecoded = this.bitsDecoded;
37237         var processedInverseMask = ~1;
37238         var processedMask = 1;
37239         var firstMagnitudeBitMask = 2;
37240
37241         for (var i0 = 0; i0 < height; i0 += 4) {
37242           for (var j = 0; j < width; j++) {
37243             var index = i0 * width + j;
37244             for (var i1 = 0; i1 < 4; i1++, index += width) {
37245               var i = i0 + i1;
37246               if (i >= height) {
37247                 break;
37248               }
37249               // clear processed flag first
37250               processingFlags[index] &= processedInverseMask;
37251
37252               if (coefficentsMagnitude[index] ||
37253                   !neighborsSignificance[index]) {
37254                 continue;
37255               }
37256
37257               var contextLabel = labels[neighborsSignificance[index]];
37258               var decision = decoder.readBit(contexts, contextLabel);
37259               if (decision) {
37260                 var sign = this.decodeSignBit(i, j, index);
37261                 coefficentsSign[index] = sign;
37262                 coefficentsMagnitude[index] = 1;
37263                 this.setNeighborsSignificance(i, j, index);
37264                 processingFlags[index] |= firstMagnitudeBitMask;
37265               }
37266               bitsDecoded[index]++;
37267               processingFlags[index] |= processedMask;
37268             }
37269           }
37270         }
37271       },
37272       decodeSignBit: function BitModel_decodeSignBit(row, column, index) {
37273         var width = this.width, height = this.height;
37274         var coefficentsMagnitude = this.coefficentsMagnitude;
37275         var coefficentsSign = this.coefficentsSign;
37276         var contribution, sign0, sign1, significance1;
37277         var contextLabel, decoded;
37278
37279         // calculate horizontal contribution
37280         significance1 = (column > 0 && coefficentsMagnitude[index - 1] !== 0);
37281         if (column + 1 < width && coefficentsMagnitude[index + 1] !== 0) {
37282           sign1 = coefficentsSign[index + 1];
37283           if (significance1) {
37284             sign0 = coefficentsSign[index - 1];
37285             contribution = 1 - sign1 - sign0;
37286           } else {
37287             contribution = 1 - sign1 - sign1;
37288           }
37289         } else if (significance1) {
37290           sign0 = coefficentsSign[index - 1];
37291           contribution = 1 - sign0 - sign0;
37292         } else {
37293           contribution = 0;
37294         }
37295         var horizontalContribution = 3 * contribution;
37296
37297         // calculate vertical contribution and combine with the horizontal
37298         significance1 = (row > 0 && coefficentsMagnitude[index - width] !== 0);
37299         if (row + 1 < height && coefficentsMagnitude[index + width] !== 0) {
37300           sign1 = coefficentsSign[index + width];
37301           if (significance1) {
37302             sign0 = coefficentsSign[index - width];
37303             contribution = 1 - sign1 - sign0 + horizontalContribution;
37304           } else {
37305             contribution = 1 - sign1 - sign1 + horizontalContribution;
37306           }
37307         } else if (significance1) {
37308           sign0 = coefficentsSign[index - width];
37309           contribution = 1 - sign0 - sign0 + horizontalContribution;
37310         } else {
37311           contribution = horizontalContribution;
37312         }
37313
37314         if (contribution >= 0) {
37315           contextLabel = 9 + contribution;
37316           decoded = this.decoder.readBit(this.contexts, contextLabel);
37317         } else {
37318           contextLabel = 9 - contribution;
37319           decoded = this.decoder.readBit(this.contexts, contextLabel) ^ 1;
37320         }
37321         return decoded;
37322       },
37323       runMagnitudeRefinementPass:
37324         function BitModel_runMagnitudeRefinementPass() {
37325         var decoder = this.decoder;
37326         var width = this.width, height = this.height;
37327         var coefficentsMagnitude = this.coefficentsMagnitude;
37328         var neighborsSignificance = this.neighborsSignificance;
37329         var contexts = this.contexts;
37330         var bitsDecoded = this.bitsDecoded;
37331         var processingFlags = this.processingFlags;
37332         var processedMask = 1;
37333         var firstMagnitudeBitMask = 2;
37334         var length = width * height;
37335         var width4 = width * 4;
37336
37337         for (var index0 = 0, indexNext; index0 < length; index0 = indexNext) {
37338           indexNext = Math.min(length, index0 + width4);
37339           for (var j = 0; j < width; j++) {
37340             for (var index = index0 + j; index < indexNext; index += width) {
37341
37342               // significant but not those that have just become
37343               if (!coefficentsMagnitude[index] ||
37344                 (processingFlags[index] & processedMask) !== 0) {
37345                 continue;
37346               }
37347
37348               var contextLabel = 16;
37349               if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) {
37350                 processingFlags[index] ^= firstMagnitudeBitMask;
37351                 // first refinement
37352                var significance = neighborsSignificance[index] & 127;
37353                contextLabel = significance === 0 ? 15 : 14;
37354               }
37355
37356               var bit = decoder.readBit(contexts, contextLabel);
37357               coefficentsMagnitude[index] =
37358                 (coefficentsMagnitude[index] << 1) | bit;
37359               bitsDecoded[index]++;
37360               processingFlags[index] |= processedMask;
37361             }
37362           }
37363         }
37364       },
37365       runCleanupPass: function BitModel_runCleanupPass() {
37366         var decoder = this.decoder;
37367         var width = this.width, height = this.height;
37368         var neighborsSignificance = this.neighborsSignificance;
37369         var coefficentsMagnitude = this.coefficentsMagnitude;
37370         var coefficentsSign = this.coefficentsSign;
37371         var contexts = this.contexts;
37372         var labels = this.contextLabelTable;
37373         var bitsDecoded = this.bitsDecoded;
37374         var processingFlags = this.processingFlags;
37375         var processedMask = 1;
37376         var firstMagnitudeBitMask = 2;
37377         var oneRowDown = width;
37378         var twoRowsDown = width * 2;
37379         var threeRowsDown = width * 3;
37380         var iNext;
37381         for (var i0 = 0; i0 < height; i0 = iNext) {
37382           iNext = Math.min(i0 + 4, height);
37383           var indexBase = i0 * width;
37384           var checkAllEmpty = i0 + 3 < height;
37385           for (var j = 0; j < width; j++) {
37386             var index0 = indexBase + j;
37387             // using the property: labels[neighborsSignificance[index]] === 0
37388             // when neighborsSignificance[index] === 0
37389             var allEmpty = (checkAllEmpty &&
37390               processingFlags[index0] === 0 &&
37391               processingFlags[index0 + oneRowDown] === 0 &&
37392               processingFlags[index0 + twoRowsDown] === 0 &&
37393               processingFlags[index0 + threeRowsDown] === 0 &&
37394               neighborsSignificance[index0] === 0 &&
37395               neighborsSignificance[index0 + oneRowDown] === 0 &&
37396               neighborsSignificance[index0 + twoRowsDown] === 0 &&
37397               neighborsSignificance[index0 + threeRowsDown] === 0);
37398             var i1 = 0, index = index0;
37399             var i = i0, sign;
37400             if (allEmpty) {
37401               var hasSignificantCoefficent =
37402                 decoder.readBit(contexts, RUNLENGTH_CONTEXT);
37403               if (!hasSignificantCoefficent) {
37404                 bitsDecoded[index0]++;
37405                 bitsDecoded[index0 + oneRowDown]++;
37406                 bitsDecoded[index0 + twoRowsDown]++;
37407                 bitsDecoded[index0 + threeRowsDown]++;
37408                 continue; // next column
37409               }
37410               i1 = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |
37411                     decoder.readBit(contexts, UNIFORM_CONTEXT);
37412               if (i1 !== 0) {
37413                 i = i0 + i1;
37414                 index += i1 * width;
37415               }
37416
37417               sign = this.decodeSignBit(i, j, index);
37418               coefficentsSign[index] = sign;
37419               coefficentsMagnitude[index] = 1;
37420               this.setNeighborsSignificance(i, j, index);
37421               processingFlags[index] |= firstMagnitudeBitMask;
37422
37423               index = index0;
37424               for (var i2 = i0; i2 <= i; i2++, index += width) {
37425                 bitsDecoded[index]++;
37426               }
37427
37428               i1++;
37429             }
37430             for (i = i0 + i1; i < iNext; i++, index += width) {
37431               if (coefficentsMagnitude[index] ||
37432                 (processingFlags[index] & processedMask) !== 0) {
37433                 continue;
37434               }
37435
37436               var contextLabel = labels[neighborsSignificance[index]];
37437               var decision = decoder.readBit(contexts, contextLabel);
37438               if (decision === 1) {
37439                 sign = this.decodeSignBit(i, j, index);
37440                 coefficentsSign[index] = sign;
37441                 coefficentsMagnitude[index] = 1;
37442                 this.setNeighborsSignificance(i, j, index);
37443                 processingFlags[index] |= firstMagnitudeBitMask;
37444               }
37445               bitsDecoded[index]++;
37446             }
37447           }
37448         }
37449       },
37450       checkSegmentationSymbol: function BitModel_checkSegmentationSymbol() {
37451         var decoder = this.decoder;
37452         var contexts = this.contexts;
37453         var symbol = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 3) |
37454                      (decoder.readBit(contexts, UNIFORM_CONTEXT) << 2) |
37455                      (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |
37456                       decoder.readBit(contexts, UNIFORM_CONTEXT);
37457         if (symbol !== 0xA) {
37458           throw new Error('JPX Error: Invalid segmentation symbol');
37459         }
37460       }
37461     };
37462
37463     return BitModel;
37464   })();
37465
37466   // Section F, Discrete wavelet transformation
37467   var Transform = (function TransformClosure() {
37468     function Transform() {}
37469
37470     Transform.prototype.calculate =
37471       function transformCalculate(subbands, u0, v0) {
37472       var ll = subbands[0];
37473       for (var i = 1, ii = subbands.length; i < ii; i++) {
37474         ll = this.iterate(ll, subbands[i], u0, v0);
37475       }
37476       return ll;
37477     };
37478     Transform.prototype.extend = function extend(buffer, offset, size) {
37479       // Section F.3.7 extending... using max extension of 4
37480       var i1 = offset - 1, j1 = offset + 1;
37481       var i2 = offset + size - 2, j2 = offset + size;
37482       buffer[i1--] = buffer[j1++];
37483       buffer[j2++] = buffer[i2--];
37484       buffer[i1--] = buffer[j1++];
37485       buffer[j2++] = buffer[i2--];
37486       buffer[i1--] = buffer[j1++];
37487       buffer[j2++] = buffer[i2--];
37488       buffer[i1] = buffer[j1];
37489       buffer[j2] = buffer[i2];
37490     };
37491     Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh,
37492                                                              u0, v0) {
37493       var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
37494       var width = hl_lh_hh.width;
37495       var height = hl_lh_hh.height;
37496       var items = hl_lh_hh.items;
37497       var i, j, k, l, u, v;
37498
37499       // Interleave LL according to Section F.3.3
37500       for (k = 0, i = 0; i < llHeight; i++) {
37501         l = i * 2 * width;
37502         for (j = 0; j < llWidth; j++, k++, l += 2) {
37503           items[l] = llItems[k];
37504         }
37505       }
37506       // The LL band is not needed anymore.
37507       llItems = ll.items = null;
37508
37509       var bufferPadding = 4;
37510       var rowBuffer = new Float32Array(width + 2 * bufferPadding);
37511
37512       // Section F.3.4 HOR_SR
37513       if (width === 1) {
37514         // if width = 1, when u0 even keep items as is, when odd divide by 2
37515         if ((u0 & 1) !== 0) {
37516           for (v = 0, k = 0; v < height; v++, k += width) {
37517             items[k] *= 0.5;
37518           }
37519         }
37520       } else {
37521         for (v = 0, k = 0; v < height; v++, k += width) {
37522           rowBuffer.set(items.subarray(k, k + width), bufferPadding);
37523
37524           this.extend(rowBuffer, bufferPadding, width);
37525           this.filter(rowBuffer, bufferPadding, width);
37526
37527           items.set(
37528             rowBuffer.subarray(bufferPadding, bufferPadding + width),
37529             k);
37530         }
37531       }
37532
37533       // Accesses to the items array can take long, because it may not fit into
37534       // CPU cache and has to be fetched from main memory. Since subsequent
37535       // accesses to the items array are not local when reading columns, we
37536       // have a cache miss every time. To reduce cache misses, get up to
37537       // 'numBuffers' items at a time and store them into the individual
37538       // buffers. The colBuffers should be small enough to fit into CPU cache.
37539       var numBuffers = 16;
37540       var colBuffers = [];
37541       for (i = 0; i < numBuffers; i++) {
37542         colBuffers.push(new Float32Array(height + 2 * bufferPadding));
37543       }
37544       var b, currentBuffer = 0;
37545       ll = bufferPadding + height;
37546
37547       // Section F.3.5 VER_SR
37548       if (height === 1) {
37549           // if height = 1, when v0 even keep items as is, when odd divide by 2
37550         if ((v0 & 1) !== 0) {
37551           for (u = 0; u < width; u++) {
37552             items[u] *= 0.5;
37553           }
37554         }
37555       } else {
37556         for (u = 0; u < width; u++) {
37557           // if we ran out of buffers, copy several image columns at once
37558           if (currentBuffer === 0) {
37559             numBuffers = Math.min(width - u, numBuffers);
37560             for (k = u, l = bufferPadding; l < ll; k += width, l++) {
37561               for (b = 0; b < numBuffers; b++) {
37562                 colBuffers[b][l] = items[k + b];
37563               }
37564             }
37565             currentBuffer = numBuffers;
37566           }
37567
37568           currentBuffer--;
37569           var buffer = colBuffers[currentBuffer];
37570           this.extend(buffer, bufferPadding, height);
37571           this.filter(buffer, bufferPadding, height);
37572
37573           // If this is last buffer in this group of buffers, flush all buffers.
37574           if (currentBuffer === 0) {
37575             k = u - numBuffers + 1;
37576             for (l = bufferPadding; l < ll; k += width, l++) {
37577               for (b = 0; b < numBuffers; b++) {
37578                 items[k + b] = colBuffers[b][l];
37579               }
37580             }
37581           }
37582         }
37583       }
37584
37585       return {
37586         width: width,
37587         height: height,
37588         items: items
37589       };
37590     };
37591     return Transform;
37592   })();
37593
37594   // Section 3.8.2 Irreversible 9-7 filter
37595   var IrreversibleTransform = (function IrreversibleTransformClosure() {
37596     function IrreversibleTransform() {
37597       Transform.call(this);
37598     }
37599
37600     IrreversibleTransform.prototype = Object.create(Transform.prototype);
37601     IrreversibleTransform.prototype.filter =
37602       function irreversibleTransformFilter(x, offset, length) {
37603       var len = length >> 1;
37604       offset = offset | 0;
37605       var j, n, current, next;
37606
37607       var alpha = -1.586134342059924;
37608       var beta = -0.052980118572961;
37609       var gamma = 0.882911075530934;
37610       var delta = 0.443506852043971;
37611       var K = 1.230174104914001;
37612       var K_ = 1 / K;
37613
37614       // step 1 is combined with step 3
37615
37616       // step 2
37617       j = offset - 3;
37618       for (n = len + 4; n--; j += 2) {
37619         x[j] *= K_;
37620       }
37621
37622       // step 1 & 3
37623       j = offset - 2;
37624       current = delta * x[j -1];
37625       for (n = len + 3; n--; j += 2) {
37626         next = delta * x[j + 1];
37627         x[j] = K * x[j] - current - next;
37628         if (n--) {
37629           j += 2;
37630           current = delta * x[j + 1];
37631           x[j] = K * x[j] - current - next;
37632         } else {
37633           break;
37634         }
37635       }
37636
37637       // step 4
37638       j = offset - 1;
37639       current = gamma * x[j - 1];
37640       for (n = len + 2; n--; j += 2) {
37641         next = gamma * x[j + 1];
37642         x[j] -= current + next;
37643         if (n--) {
37644           j += 2;
37645           current = gamma * x[j + 1];
37646           x[j] -= current + next;
37647         } else {
37648           break;
37649         }
37650       }
37651
37652       // step 5
37653       j = offset;
37654       current = beta * x[j - 1];
37655       for (n = len + 1; n--; j += 2) {
37656         next = beta * x[j + 1];
37657         x[j] -= current + next;
37658         if (n--) {
37659           j += 2;
37660           current = beta * x[j + 1];
37661           x[j] -= current + next;
37662         } else {
37663           break;
37664         }
37665       }
37666
37667       // step 6
37668       if (len !== 0) {
37669         j = offset + 1;
37670         current = alpha * x[j - 1];
37671         for (n = len; n--; j += 2) {
37672           next = alpha * x[j + 1];
37673           x[j] -= current + next;
37674           if (n--) {
37675             j += 2;
37676             current = alpha * x[j + 1];
37677             x[j] -= current + next;
37678           } else {
37679             break;
37680           }
37681         }
37682       }
37683     };
37684
37685     return IrreversibleTransform;
37686   })();
37687
37688   // Section 3.8.1 Reversible 5-3 filter
37689   var ReversibleTransform = (function ReversibleTransformClosure() {
37690     function ReversibleTransform() {
37691       Transform.call(this);
37692     }
37693
37694     ReversibleTransform.prototype = Object.create(Transform.prototype);
37695     ReversibleTransform.prototype.filter =
37696       function reversibleTransformFilter(x, offset, length) {
37697       var len = length >> 1;
37698       offset = offset | 0;
37699       var j, n;
37700
37701       for (j = offset, n = len + 1; n--; j += 2) {
37702         x[j] -= (x[j - 1] + x[j + 1] + 2) >> 2;
37703       }
37704
37705       for (j = offset + 1, n = len; n--; j += 2) {
37706         x[j] += (x[j - 1] + x[j + 1]) >> 1;
37707       }
37708     };
37709
37710     return ReversibleTransform;
37711   })();
37712
37713   return JpxImage;
37714 })();
37715
37716
37717 var Jbig2Image = (function Jbig2ImageClosure() {
37718   // Utility data structures
37719   function ContextCache() {}
37720
37721   ContextCache.prototype = {
37722     getContexts: function(id) {
37723       if (id in this) {
37724         return this[id];
37725       }
37726       return (this[id] = new Int8Array(1 << 16));
37727     }
37728   };
37729
37730   function DecodingContext(data, start, end) {
37731     this.data = data;
37732     this.start = start;
37733     this.end = end;
37734   }
37735
37736   DecodingContext.prototype = {
37737     get decoder() {
37738       var decoder = new ArithmeticDecoder(this.data, this.start, this.end);
37739       return shadow(this, 'decoder', decoder);
37740     },
37741     get contextCache() {
37742       var cache = new ContextCache();
37743       return shadow(this, 'contextCache', cache);
37744     }
37745   };
37746
37747   // Annex A. Arithmetic Integer Decoding Procedure
37748   // A.2 Procedure for decoding values
37749   function decodeInteger(contextCache, procedure, decoder) {
37750     var contexts = contextCache.getContexts(procedure);
37751     var prev = 1;
37752
37753     function readBits(length) {
37754       var v = 0;
37755       for (var i = 0; i < length; i++) {
37756         var bit = decoder.readBit(contexts, prev);
37757         prev = (prev < 256 ? (prev << 1) | bit :
37758                 (((prev << 1) | bit) & 511) | 256);
37759         v = (v << 1) | bit;
37760       }
37761       return v >>> 0;
37762     }
37763
37764     var sign = readBits(1);
37765     var value = readBits(1) ?
37766                   (readBits(1) ?
37767                     (readBits(1) ?
37768                       (readBits(1) ?
37769                         (readBits(1) ?
37770                           (readBits(32) + 4436) :
37771                         readBits(12) + 340) :
37772                       readBits(8) + 84) :
37773                     readBits(6) + 20) :
37774                   readBits(4) + 4) :
37775                 readBits(2);
37776     return (sign === 0 ? value : (value > 0 ? -value : null));
37777   }
37778
37779   // A.3 The IAID decoding procedure
37780   function decodeIAID(contextCache, decoder, codeLength) {
37781     var contexts = contextCache.getContexts('IAID');
37782
37783     var prev = 1;
37784     for (var i = 0; i < codeLength; i++) {
37785       var bit = decoder.readBit(contexts, prev);
37786       prev = (prev << 1) | bit;
37787     }
37788     if (codeLength < 31) {
37789       return prev & ((1 << codeLength) - 1);
37790     }
37791     return prev & 0x7FFFFFFF;
37792   }
37793
37794   // 7.3 Segment types
37795   var SegmentTypes = [
37796     'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null,
37797     'ImmediateTextRegion', 'ImmediateLosslessTextRegion', null, null, null,
37798     null, null, null, null, null, 'patternDictionary', null, null, null,
37799     'IntermediateHalftoneRegion', null, 'ImmediateHalftoneRegion',
37800     'ImmediateLosslessHalftoneRegion', null, null, null, null, null, null, null,
37801     null, null, null, null, null, 'IntermediateGenericRegion', null,
37802     'ImmediateGenericRegion', 'ImmediateLosslessGenericRegion',
37803     'IntermediateGenericRefinementRegion', null,
37804     'ImmediateGenericRefinementRegion',
37805     'ImmediateLosslessGenericRefinementRegion', null, null, null, null,
37806     'PageInformation', 'EndOfPage', 'EndOfStripe', 'EndOfFile', 'Profiles',
37807     'Tables', null, null, null, null, null, null, null, null,
37808     'Extension'
37809   ];
37810
37811   var CodingTemplates = [
37812     [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
37813      {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: 2, y: -1},
37814      {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
37815     [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: 2, y: -2},
37816      {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1},
37817      {x: 2, y: -1}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
37818     [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
37819      {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -2, y: 0},
37820      {x: -1, y: 0}],
37821     [{x: -3, y: -1}, {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1},
37822      {x: 1, y: -1}, {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}]
37823   ];
37824
37825   var RefinementTemplates = [
37826     {
37827       coding: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
37828       reference: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}, {x: 0, y: 0},
37829                   {x: 1, y: 0}, {x: -1, y: 1}, {x: 0, y: 1}, {x: 1, y: 1}]
37830     },
37831     {
37832       coding: [{x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
37833       reference: [{x: 0, y: -1}, {x: -1, y: 0}, {x: 0, y: 0}, {x: 1, y: 0},
37834                   {x: 0, y: 1}, {x: 1, y: 1}]
37835     }
37836   ];
37837
37838   // See 6.2.5.7 Decoding the bitmap.
37839   var ReusedContexts = [
37840     0x9B25, // 10011 0110010 0101
37841     0x0795, // 0011 110010 101
37842     0x00E5, // 001 11001 01
37843     0x0195  // 011001 0101
37844   ];
37845
37846   var RefinementReusedContexts = [
37847     0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)
37848     0x0008  // '0000' + '001000'
37849   ];
37850
37851   function decodeBitmapTemplate0(width, height, decodingContext) {
37852     var decoder = decodingContext.decoder;
37853     var contexts = decodingContext.contextCache.getContexts('GB');
37854     var contextLabel, i, j, pixel, row, row1, row2, bitmap = [];
37855
37856     // ...ooooo....
37857     // ..ooooooo... Context template for current pixel (X)
37858     // .ooooX...... (concatenate values of 'o'-pixels to get contextLabel)
37859     var OLD_PIXEL_MASK = 0x7BF7; // 01111 0111111 0111
37860
37861     for (i = 0; i < height; i++) {
37862       row = bitmap[i] = new Uint8Array(width);
37863       row1 = (i < 1) ? row : bitmap[i - 1];
37864       row2 = (i < 2) ? row : bitmap[i - 2];
37865
37866       // At the beginning of each row:
37867       // Fill contextLabel with pixels that are above/right of (X)
37868       contextLabel = (row2[0] << 13) | (row2[1] << 12) | (row2[2] << 11) |
37869                      (row1[0] << 7) | (row1[1] << 6) | (row1[2] << 5) |
37870                      (row1[3] << 4);
37871
37872       for (j = 0; j < width; j++) {
37873         row[j] = pixel = decoder.readBit(contexts, contextLabel);
37874
37875         // At each pixel: Clear contextLabel pixels that are shifted
37876         // out of the context, then add new ones.
37877         contextLabel = ((contextLabel & OLD_PIXEL_MASK) << 1) |
37878                        (j + 3 < width ? row2[j + 3] << 11 : 0) |
37879                        (j + 4 < width ? row1[j + 4] << 4 : 0) | pixel;
37880       }
37881     }
37882
37883     return bitmap;
37884   }
37885
37886   // 6.2 Generic Region Decoding Procedure
37887   function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
37888                         decodingContext) {
37889     if (mmr) {
37890       error('JBIG2 error: MMR encoding is not supported');
37891     }
37892
37893     // Use optimized version for the most common case
37894     if (templateIndex === 0 && !skip && !prediction && at.length === 4 &&
37895         at[0].x === 3 && at[0].y === -1 && at[1].x === -3 && at[1].y === -1 &&
37896         at[2].x === 2 && at[2].y === -2 && at[3].x === -2 && at[3].y === -2) {
37897       return decodeBitmapTemplate0(width, height, decodingContext);
37898     }
37899
37900     var useskip = !!skip;
37901     var template = CodingTemplates[templateIndex].concat(at);
37902
37903     // Sorting is non-standard, and it is not required. But sorting increases
37904     // the number of template bits that can be reused from the previous
37905     // contextLabel in the main loop.
37906     template.sort(function (a, b) {
37907       return (a.y - b.y) || (a.x - b.x);
37908     });
37909
37910     var templateLength = template.length;
37911     var templateX = new Int8Array(templateLength);
37912     var templateY = new Int8Array(templateLength);
37913     var changingTemplateEntries = [];
37914     var reuseMask = 0, minX = 0, maxX = 0, minY = 0;
37915     var c, k;
37916
37917     for (k = 0; k < templateLength; k++) {
37918       templateX[k] = template[k].x;
37919       templateY[k] = template[k].y;
37920       minX = Math.min(minX, template[k].x);
37921       maxX = Math.max(maxX, template[k].x);
37922       minY = Math.min(minY, template[k].y);
37923       // Check if the template pixel appears in two consecutive context labels,
37924       // so it can be reused. Otherwise, we add it to the list of changing
37925       // template entries.
37926       if (k < templateLength - 1 &&
37927           template[k].y === template[k + 1].y &&
37928           template[k].x === template[k + 1].x - 1) {
37929         reuseMask |= 1 << (templateLength - 1 - k);
37930       } else {
37931         changingTemplateEntries.push(k);
37932       }
37933     }
37934     var changingEntriesLength = changingTemplateEntries.length;
37935
37936     var changingTemplateX = new Int8Array(changingEntriesLength);
37937     var changingTemplateY = new Int8Array(changingEntriesLength);
37938     var changingTemplateBit = new Uint16Array(changingEntriesLength);
37939     for (c = 0; c < changingEntriesLength; c++) {
37940       k = changingTemplateEntries[c];
37941       changingTemplateX[c] = template[k].x;
37942       changingTemplateY[c] = template[k].y;
37943       changingTemplateBit[c] = 1 << (templateLength - 1 - k);
37944     }
37945
37946     // Get the safe bounding box edges from the width, height, minX, maxX, minY
37947     var sbb_left = -minX;
37948     var sbb_top = -minY;
37949     var sbb_right = width - maxX;
37950
37951     var pseudoPixelContext = ReusedContexts[templateIndex];
37952     var row = new Uint8Array(width);
37953     var bitmap = [];
37954
37955     var decoder = decodingContext.decoder;
37956     var contexts = decodingContext.contextCache.getContexts('GB');
37957
37958     var ltp = 0, j, i0, j0, contextLabel = 0, bit, shift;
37959     for (var i = 0; i < height; i++) {
37960       if (prediction) {
37961         var sltp = decoder.readBit(contexts, pseudoPixelContext);
37962         ltp ^= sltp;
37963         if (ltp) {
37964           bitmap.push(row); // duplicate previous row
37965           continue;
37966         }
37967       }
37968       row = new Uint8Array(row);
37969       bitmap.push(row);
37970       for (j = 0; j < width; j++) {
37971         if (useskip && skip[i][j]) {
37972           row[j] = 0;
37973           continue;
37974         }
37975         // Are we in the middle of a scanline, so we can reuse contextLabel
37976         // bits?
37977         if (j >= sbb_left && j < sbb_right && i >= sbb_top) {
37978           // If yes, we can just shift the bits that are reusable and only
37979           // fetch the remaining ones.
37980           contextLabel = (contextLabel << 1) & reuseMask;
37981           for (k = 0; k < changingEntriesLength; k++) {
37982             i0 = i + changingTemplateY[k];
37983             j0 = j + changingTemplateX[k];
37984             bit = bitmap[i0][j0];
37985             if (bit) {
37986               bit = changingTemplateBit[k];
37987               contextLabel |= bit;
37988             }
37989           }
37990         } else {
37991           // compute the contextLabel from scratch
37992           contextLabel = 0;
37993           shift = templateLength - 1;
37994           for (k = 0; k < templateLength; k++, shift--) {
37995             j0 = j + templateX[k];
37996             if (j0 >= 0 && j0 < width) {
37997               i0 = i + templateY[k];
37998               if (i0 >= 0) {
37999                 bit = bitmap[i0][j0];
38000                 if (bit) {
38001                   contextLabel |= bit << shift;
38002                 }
38003               }
38004             }
38005           }
38006         }
38007         var pixel = decoder.readBit(contexts, contextLabel);
38008         row[j] = pixel;
38009       }
38010     }
38011     return bitmap;
38012   }
38013
38014   // 6.3.2 Generic Refinement Region Decoding Procedure
38015   function decodeRefinement(width, height, templateIndex, referenceBitmap,
38016                             offsetX, offsetY, prediction, at,
38017                             decodingContext) {
38018     var codingTemplate = RefinementTemplates[templateIndex].coding;
38019     if (templateIndex === 0) {
38020       codingTemplate = codingTemplate.concat([at[0]]);
38021     }
38022     var codingTemplateLength = codingTemplate.length;
38023     var codingTemplateX = new Int32Array(codingTemplateLength);
38024     var codingTemplateY = new Int32Array(codingTemplateLength);
38025     var k;
38026     for (k = 0; k < codingTemplateLength; k++) {
38027       codingTemplateX[k] = codingTemplate[k].x;
38028       codingTemplateY[k] = codingTemplate[k].y;
38029     }
38030
38031     var referenceTemplate = RefinementTemplates[templateIndex].reference;
38032     if (templateIndex === 0) {
38033       referenceTemplate = referenceTemplate.concat([at[1]]);
38034     }
38035     var referenceTemplateLength = referenceTemplate.length;
38036     var referenceTemplateX = new Int32Array(referenceTemplateLength);
38037     var referenceTemplateY = new Int32Array(referenceTemplateLength);
38038     for (k = 0; k < referenceTemplateLength; k++) {
38039       referenceTemplateX[k] = referenceTemplate[k].x;
38040       referenceTemplateY[k] = referenceTemplate[k].y;
38041     }
38042     var referenceWidth = referenceBitmap[0].length;
38043     var referenceHeight = referenceBitmap.length;
38044
38045     var pseudoPixelContext = RefinementReusedContexts[templateIndex];
38046     var bitmap = [];
38047
38048     var decoder = decodingContext.decoder;
38049     var contexts = decodingContext.contextCache.getContexts('GR');
38050
38051     var ltp = 0;
38052     for (var i = 0; i < height; i++) {
38053       if (prediction) {
38054         var sltp = decoder.readBit(contexts, pseudoPixelContext);
38055         ltp ^= sltp;
38056         if (ltp) {
38057           error('JBIG2 error: prediction is not supported');
38058         }
38059       }
38060       var row = new Uint8Array(width);
38061       bitmap.push(row);
38062       for (var j = 0; j < width; j++) {
38063         var i0, j0;
38064         var contextLabel = 0;
38065         for (k = 0; k < codingTemplateLength; k++) {
38066           i0 = i + codingTemplateY[k];
38067           j0 = j + codingTemplateX[k];
38068           if (i0 < 0 || j0 < 0 || j0 >= width) {
38069             contextLabel <<= 1; // out of bound pixel
38070           } else {
38071             contextLabel = (contextLabel << 1) | bitmap[i0][j0];
38072           }
38073         }
38074         for (k = 0; k < referenceTemplateLength; k++) {
38075           i0 = i + referenceTemplateY[k] + offsetY;
38076           j0 = j + referenceTemplateX[k] + offsetX;
38077           if (i0 < 0 || i0 >= referenceHeight || j0 < 0 ||
38078               j0 >= referenceWidth) {
38079             contextLabel <<= 1; // out of bound pixel
38080           } else {
38081             contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
38082           }
38083         }
38084         var pixel = decoder.readBit(contexts, contextLabel);
38085         row[j] = pixel;
38086       }
38087     }
38088
38089     return bitmap;
38090   }
38091
38092   // 6.5.5 Decoding the symbol dictionary
38093   function decodeSymbolDictionary(huffman, refinement, symbols,
38094                                   numberOfNewSymbols, numberOfExportedSymbols,
38095                                   huffmanTables, templateIndex, at,
38096                                   refinementTemplateIndex, refinementAt,
38097                                   decodingContext) {
38098     if (huffman) {
38099       error('JBIG2 error: huffman is not supported');
38100     }
38101
38102     var newSymbols = [];
38103     var currentHeight = 0;
38104     var symbolCodeLength = log2(symbols.length + numberOfNewSymbols);
38105
38106     var decoder = decodingContext.decoder;
38107     var contextCache = decodingContext.contextCache;
38108
38109     while (newSymbols.length < numberOfNewSymbols) {
38110       var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); // 6.5.6
38111       currentHeight += deltaHeight;
38112       var currentWidth = 0;
38113       var totalWidth = 0;
38114       while (true) {
38115         var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7
38116         if (deltaWidth === null) {
38117           break; // OOB
38118         }
38119         currentWidth += deltaWidth;
38120         totalWidth += currentWidth;
38121         var bitmap;
38122         if (refinement) {
38123           // 6.5.8.2 Refinement/aggregate-coded symbol bitmap
38124           var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);
38125           if (numberOfInstances > 1) {
38126             bitmap = decodeTextRegion(huffman, refinement,
38127                                       currentWidth, currentHeight, 0,
38128                                       numberOfInstances, 1, //strip size
38129                                       symbols.concat(newSymbols),
38130                                       symbolCodeLength,
38131                                       0, //transposed
38132                                       0, //ds offset
38133                                       1, //top left 7.4.3.1.1
38134                                       0, //OR operator
38135                                       huffmanTables,
38136                                       refinementTemplateIndex, refinementAt,
38137                                       decodingContext);
38138           } else {
38139             var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
38140             var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
38141             var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
38142             var symbol = (symbolId < symbols.length ? symbols[symbolId] :
38143                           newSymbols[symbolId - symbols.length]);
38144             bitmap = decodeRefinement(currentWidth, currentHeight,
38145             refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,
38146             decodingContext);
38147           }
38148         } else {
38149           // 6.5.8.1 Direct-coded symbol bitmap
38150           bitmap = decodeBitmap(false, currentWidth, currentHeight,
38151             templateIndex, false, null, at, decodingContext);
38152         }
38153         newSymbols.push(bitmap);
38154       }
38155     }
38156     // 6.5.10 Exported symbols
38157     var exportedSymbols = [];
38158     var flags = [], currentFlag = false;
38159     var totalSymbolsLength = symbols.length + numberOfNewSymbols;
38160     while (flags.length < totalSymbolsLength) {
38161       var runLength = decodeInteger(contextCache, 'IAEX', decoder);
38162       while (runLength--) {
38163         flags.push(currentFlag);
38164       }
38165       currentFlag = !currentFlag;
38166     }
38167     for (var i = 0, ii = symbols.length; i < ii; i++) {
38168       if (flags[i]) {
38169         exportedSymbols.push(symbols[i]);
38170       }
38171     }
38172     for (var j = 0; j < numberOfNewSymbols; i++, j++) {
38173       if (flags[i]) {
38174         exportedSymbols.push(newSymbols[j]);
38175       }
38176     }
38177     return exportedSymbols;
38178   }
38179
38180   function decodeTextRegion(huffman, refinement, width, height,
38181                             defaultPixelValue, numberOfSymbolInstances,
38182                             stripSize, inputSymbols, symbolCodeLength,
38183                             transposed, dsOffset, referenceCorner,
38184                             combinationOperator, huffmanTables,
38185                             refinementTemplateIndex, refinementAt,
38186                             decodingContext) {
38187     if (huffman) {
38188       error('JBIG2 error: huffman is not supported');
38189     }
38190
38191     // Prepare bitmap
38192     var bitmap = [];
38193     var i, row;
38194     for (i = 0; i < height; i++) {
38195       row = new Uint8Array(width);
38196       if (defaultPixelValue) {
38197         for (var j = 0; j < width; j++) {
38198           row[j] = defaultPixelValue;
38199         }
38200       }
38201       bitmap.push(row);
38202     }
38203
38204     var decoder = decodingContext.decoder;
38205     var contextCache = decodingContext.contextCache;
38206     var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
38207     var firstS = 0;
38208     i = 0;
38209     while (i < numberOfSymbolInstances) {
38210       var deltaT = decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
38211       stripT += deltaT;
38212
38213       var deltaFirstS = decodeInteger(contextCache, 'IAFS', decoder); // 6.4.7
38214       firstS += deltaFirstS;
38215       var currentS = firstS;
38216       do {
38217         var currentT = (stripSize === 1 ? 0 :
38218                         decodeInteger(contextCache, 'IAIT', decoder)); // 6.4.9
38219         var t = stripSize * stripT + currentT;
38220         var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
38221         var applyRefinement = (refinement &&
38222                                decodeInteger(contextCache, 'IARI', decoder));
38223         var symbolBitmap = inputSymbols[symbolId];
38224         var symbolWidth = symbolBitmap[0].length;
38225         var symbolHeight = symbolBitmap.length;
38226         if (applyRefinement) {
38227           var rdw = decodeInteger(contextCache, 'IARDW', decoder); // 6.4.11.1
38228           var rdh = decodeInteger(contextCache, 'IARDH', decoder); // 6.4.11.2
38229           var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
38230           var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
38231           symbolWidth += rdw;
38232           symbolHeight += rdh;
38233           symbolBitmap = decodeRefinement(symbolWidth, symbolHeight,
38234             refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx,
38235             (rdh >> 1) + rdy, false, refinementAt,
38236             decodingContext);
38237         }
38238         var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);
38239         var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);
38240         var s2, t2, symbolRow;
38241         if (transposed) {
38242           // Place Symbol Bitmap from T1,S1
38243           for (s2 = 0; s2 < symbolHeight; s2++) {
38244             row = bitmap[offsetS + s2];
38245             if (!row) {
38246               continue;
38247             }
38248             symbolRow = symbolBitmap[s2];
38249             // To ignore Parts of Symbol bitmap which goes
38250             // outside bitmap region
38251             var maxWidth = Math.min(width - offsetT, symbolWidth);
38252             switch (combinationOperator) {
38253               case 0: // OR
38254                 for (t2 = 0; t2 < maxWidth; t2++) {
38255                   row[offsetT + t2] |= symbolRow[t2];
38256                 }
38257                 break;
38258               case 2: // XOR
38259                 for (t2 = 0; t2 < maxWidth; t2++) {
38260                   row[offsetT + t2] ^= symbolRow[t2];
38261                 }
38262                 break;
38263               default:
38264                 error('JBIG2 error: operator ' + combinationOperator +
38265                       ' is not supported');
38266             }
38267           }
38268           currentS += symbolHeight - 1;
38269         } else {
38270           for (t2 = 0; t2 < symbolHeight; t2++) {
38271             row = bitmap[offsetT + t2];
38272             if (!row) {
38273               continue;
38274             }
38275             symbolRow = symbolBitmap[t2];
38276             switch (combinationOperator) {
38277               case 0: // OR
38278                 for (s2 = 0; s2 < symbolWidth; s2++) {
38279                   row[offsetS + s2] |= symbolRow[s2];
38280                 }
38281                 break;
38282               case 2: // XOR
38283                 for (s2 = 0; s2 < symbolWidth; s2++) {
38284                   row[offsetS + s2] ^= symbolRow[s2];
38285                 }
38286                 break;
38287               default:
38288                 error('JBIG2 error: operator ' + combinationOperator +
38289                       ' is not supported');
38290             }
38291           }
38292           currentS += symbolWidth - 1;
38293         }
38294         i++;
38295         var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8
38296         if (deltaS === null) {
38297           break; // OOB
38298         }
38299         currentS += deltaS + dsOffset;
38300       } while (true);
38301     }
38302     return bitmap;
38303   }
38304
38305   function readSegmentHeader(data, start) {
38306     var segmentHeader = {};
38307     segmentHeader.number = readUint32(data, start);
38308     var flags = data[start + 4];
38309     var segmentType = flags & 0x3F;
38310     if (!SegmentTypes[segmentType]) {
38311       error('JBIG2 error: invalid segment type: ' + segmentType);
38312     }
38313     segmentHeader.type = segmentType;
38314     segmentHeader.typeName = SegmentTypes[segmentType];
38315     segmentHeader.deferredNonRetain = !!(flags & 0x80);
38316
38317     var pageAssociationFieldSize = !!(flags & 0x40);
38318     var referredFlags = data[start + 5];
38319     var referredToCount = (referredFlags >> 5) & 7;
38320     var retainBits = [referredFlags & 31];
38321     var position = start + 6;
38322     if (referredFlags === 7) {
38323       referredToCount = readUint32(data, position - 1) & 0x1FFFFFFF;
38324       position += 3;
38325       var bytes = (referredToCount + 7) >> 3;
38326       retainBits[0] = data[position++];
38327       while (--bytes > 0) {
38328         retainBits.push(data[position++]);
38329       }
38330     } else if (referredFlags === 5 || referredFlags === 6) {
38331       error('JBIG2 error: invalid referred-to flags');
38332     }
38333
38334     segmentHeader.retainBits = retainBits;
38335     var referredToSegmentNumberSize = (segmentHeader.number <= 256 ? 1 :
38336       (segmentHeader.number <= 65536 ? 2 : 4));
38337     var referredTo = [];
38338     var i, ii;
38339     for (i = 0; i < referredToCount; i++) {
38340       var number = (referredToSegmentNumberSize === 1 ? data[position] :
38341         (referredToSegmentNumberSize === 2 ? readUint16(data, position) :
38342         readUint32(data, position)));
38343       referredTo.push(number);
38344       position += referredToSegmentNumberSize;
38345     }
38346     segmentHeader.referredTo = referredTo;
38347     if (!pageAssociationFieldSize) {
38348       segmentHeader.pageAssociation = data[position++];
38349     } else {
38350       segmentHeader.pageAssociation = readUint32(data, position);
38351       position += 4;
38352     }
38353     segmentHeader.length = readUint32(data, position);
38354     position += 4;
38355
38356     if (segmentHeader.length === 0xFFFFFFFF) {
38357       // 7.2.7 Segment data length, unknown segment length
38358       if (segmentType === 38) { // ImmediateGenericRegion
38359         var genericRegionInfo = readRegionSegmentInformation(data, position);
38360         var genericRegionSegmentFlags = data[position +
38361           RegionSegmentInformationFieldLength];
38362         var genericRegionMmr = !!(genericRegionSegmentFlags & 1);
38363         // searching for the segment end
38364         var searchPatternLength = 6;
38365         var searchPattern = new Uint8Array(searchPatternLength);
38366         if (!genericRegionMmr) {
38367           searchPattern[0] = 0xFF;
38368           searchPattern[1] = 0xAC;
38369         }
38370         searchPattern[2] = (genericRegionInfo.height >>> 24) & 0xFF;
38371         searchPattern[3] = (genericRegionInfo.height >> 16) & 0xFF;
38372         searchPattern[4] = (genericRegionInfo.height >> 8) & 0xFF;
38373         searchPattern[5] = genericRegionInfo.height & 0xFF;
38374         for (i = position, ii = data.length; i < ii; i++) {
38375           var j = 0;
38376           while (j < searchPatternLength && searchPattern[j] === data[i + j]) {
38377             j++;
38378           }
38379           if (j === searchPatternLength) {
38380             segmentHeader.length = i + searchPatternLength;
38381             break;
38382           }
38383         }
38384         if (segmentHeader.length === 0xFFFFFFFF) {
38385           error('JBIG2 error: segment end was not found');
38386         }
38387       } else {
38388         error('JBIG2 error: invalid unknown segment length');
38389       }
38390     }
38391     segmentHeader.headerEnd = position;
38392     return segmentHeader;
38393   }
38394
38395   function readSegments(header, data, start, end) {
38396     var segments = [];
38397     var position = start;
38398     while (position < end) {
38399       var segmentHeader = readSegmentHeader(data, position);
38400       position = segmentHeader.headerEnd;
38401       var segment = {
38402         header: segmentHeader,
38403         data: data
38404       };
38405       if (!header.randomAccess) {
38406         segment.start = position;
38407         position += segmentHeader.length;
38408         segment.end = position;
38409       }
38410       segments.push(segment);
38411       if (segmentHeader.type === 51) {
38412         break; // end of file is found
38413       }
38414     }
38415     if (header.randomAccess) {
38416       for (var i = 0, ii = segments.length; i < ii; i++) {
38417         segments[i].start = position;
38418         position += segments[i].header.length;
38419         segments[i].end = position;
38420       }
38421     }
38422     return segments;
38423   }
38424
38425   // 7.4.1 Region segment information field
38426   function readRegionSegmentInformation(data, start) {
38427     return {
38428       width: readUint32(data, start),
38429       height: readUint32(data, start + 4),
38430       x: readUint32(data, start + 8),
38431       y: readUint32(data, start + 12),
38432       combinationOperator: data[start + 16] & 7
38433     };
38434   }
38435   var RegionSegmentInformationFieldLength = 17;
38436
38437   function processSegment(segment, visitor) {
38438     var header = segment.header;
38439
38440     var data = segment.data, position = segment.start, end = segment.end;
38441     var args, at, i, atLength;
38442     switch (header.type) {
38443       case 0: // SymbolDictionary
38444         // 7.4.2 Symbol dictionary segment syntax
38445         var dictionary = {};
38446         var dictionaryFlags = readUint16(data, position); // 7.4.2.1.1
38447         dictionary.huffman = !!(dictionaryFlags & 1);
38448         dictionary.refinement = !!(dictionaryFlags & 2);
38449         dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3;
38450         dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3;
38451         dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1;
38452         dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1;
38453         dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256);
38454         dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512);
38455         dictionary.template = (dictionaryFlags >> 10) & 3;
38456         dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;
38457         position += 2;
38458         if (!dictionary.huffman) {
38459           atLength = dictionary.template === 0 ? 4 : 1;
38460           at = [];
38461           for (i = 0; i < atLength; i++) {
38462             at.push({
38463               x: readInt8(data, position),
38464               y: readInt8(data, position + 1)
38465             });
38466             position += 2;
38467           }
38468           dictionary.at = at;
38469         }
38470         if (dictionary.refinement && !dictionary.refinementTemplate) {
38471           at = [];
38472           for (i = 0; i < 2; i++) {
38473             at.push({
38474               x: readInt8(data, position),
38475               y: readInt8(data, position + 1)
38476             });
38477             position += 2;
38478           }
38479           dictionary.refinementAt = at;
38480         }
38481         dictionary.numberOfExportedSymbols = readUint32(data, position);
38482         position += 4;
38483         dictionary.numberOfNewSymbols = readUint32(data, position);
38484         position += 4;
38485         args = [dictionary, header.number, header.referredTo,
38486                 data, position, end];
38487         break;
38488       case 6: // ImmediateTextRegion
38489       case 7: // ImmediateLosslessTextRegion
38490         var textRegion = {};
38491         textRegion.info = readRegionSegmentInformation(data, position);
38492         position += RegionSegmentInformationFieldLength;
38493         var textRegionSegmentFlags = readUint16(data, position);
38494         position += 2;
38495         textRegion.huffman = !!(textRegionSegmentFlags & 1);
38496         textRegion.refinement = !!(textRegionSegmentFlags & 2);
38497         textRegion.stripSize = 1 << ((textRegionSegmentFlags >> 2) & 3);
38498         textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3;
38499         textRegion.transposed = !!(textRegionSegmentFlags & 64);
38500         textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3;
38501         textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1;
38502         textRegion.dsOffset = (textRegionSegmentFlags << 17) >> 27;
38503         textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1;
38504         if (textRegion.huffman) {
38505           var textRegionHuffmanFlags = readUint16(data, position);
38506           position += 2;
38507           textRegion.huffmanFS = (textRegionHuffmanFlags) & 3;
38508           textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3;
38509           textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3;
38510           textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3;
38511           textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3;
38512           textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3;
38513           textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3;
38514           textRegion.huffmanRefinementSizeSelector =
38515             !!(textRegionHuffmanFlags & 14);
38516         }
38517         if (textRegion.refinement && !textRegion.refinementTemplate) {
38518           at = [];
38519           for (i = 0; i < 2; i++) {
38520             at.push({
38521               x: readInt8(data, position),
38522               y: readInt8(data, position + 1)
38523             });
38524             position += 2;
38525           }
38526           textRegion.refinementAt = at;
38527         }
38528         textRegion.numberOfSymbolInstances = readUint32(data, position);
38529         position += 4;
38530         // TODO 7.4.3.1.7 Symbol ID Huffman table decoding
38531         if (textRegion.huffman) {
38532           error('JBIG2 error: huffman is not supported');
38533         }
38534         args = [textRegion, header.referredTo, data, position, end];
38535         break;
38536       case 38: // ImmediateGenericRegion
38537       case 39: // ImmediateLosslessGenericRegion
38538         var genericRegion = {};
38539         genericRegion.info = readRegionSegmentInformation(data, position);
38540         position += RegionSegmentInformationFieldLength;
38541         var genericRegionSegmentFlags = data[position++];
38542         genericRegion.mmr = !!(genericRegionSegmentFlags & 1);
38543         genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;
38544         genericRegion.prediction = !!(genericRegionSegmentFlags & 8);
38545         if (!genericRegion.mmr) {
38546           atLength = genericRegion.template === 0 ? 4 : 1;
38547           at = [];
38548           for (i = 0; i < atLength; i++) {
38549             at.push({
38550               x: readInt8(data, position),
38551               y: readInt8(data, position + 1)
38552             });
38553             position += 2;
38554           }
38555           genericRegion.at = at;
38556         }
38557         args = [genericRegion, data, position, end];
38558         break;
38559       case 48: // PageInformation
38560         var pageInfo = {
38561           width: readUint32(data, position),
38562           height: readUint32(data, position + 4),
38563           resolutionX: readUint32(data, position + 8),
38564           resolutionY: readUint32(data, position + 12)
38565         };
38566         if (pageInfo.height === 0xFFFFFFFF) {
38567           delete pageInfo.height;
38568         }
38569         var pageSegmentFlags = data[position + 16];
38570         var pageStripingInformatiom = readUint16(data, position + 17);
38571         pageInfo.lossless = !!(pageSegmentFlags & 1);
38572         pageInfo.refinement = !!(pageSegmentFlags & 2);
38573         pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1;
38574         pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3;
38575         pageInfo.requiresBuffer = !!(pageSegmentFlags & 32);
38576         pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64);
38577         args = [pageInfo];
38578         break;
38579       case 49: // EndOfPage
38580         break;
38581       case 50: // EndOfStripe
38582         break;
38583       case 51: // EndOfFile
38584         break;
38585       case 62: // 7.4.15 defines 2 extension types which
38586                // are comments and can be ignored.
38587         break;
38588       default:
38589         error('JBIG2 error: segment type ' + header.typeName + '(' +
38590               header.type + ') is not implemented');
38591     }
38592     var callbackName = 'on' + header.typeName;
38593     if (callbackName in visitor) {
38594       visitor[callbackName].apply(visitor, args);
38595     }
38596   }
38597
38598   function processSegments(segments, visitor) {
38599     for (var i = 0, ii = segments.length; i < ii; i++) {
38600       processSegment(segments[i], visitor);
38601     }
38602   }
38603
38604   function parseJbig2(data, start, end) {
38605     var position = start;
38606     if (data[position] !== 0x97 || data[position + 1] !== 0x4A ||
38607         data[position + 2] !== 0x42 || data[position + 3] !== 0x32 ||
38608         data[position + 4] !== 0x0D || data[position + 5] !== 0x0A ||
38609         data[position + 6] !== 0x1A || data[position + 7] !== 0x0A) {
38610       error('JBIG2 error: invalid header');
38611     }
38612     var header = {};
38613     position += 8;
38614     var flags = data[position++];
38615     header.randomAccess = !(flags & 1);
38616     if (!(flags & 2)) {
38617       header.numberOfPages = readUint32(data, position);
38618       position += 4;
38619     }
38620     var segments = readSegments(header, data, position, end);
38621     error('Not implemented');
38622     // processSegments(segments, new SimpleSegmentVisitor());
38623   }
38624
38625   function parseJbig2Chunks(chunks) {
38626     var visitor = new SimpleSegmentVisitor();
38627     for (var i = 0, ii = chunks.length; i < ii; i++) {
38628       var chunk = chunks[i];
38629       var segments = readSegments({}, chunk.data, chunk.start, chunk.end);
38630       processSegments(segments, visitor);
38631     }
38632     return visitor.buffer;
38633   }
38634
38635   function SimpleSegmentVisitor() {}
38636
38637   SimpleSegmentVisitor.prototype = {
38638     onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) {
38639       this.currentPageInfo = info;
38640       var rowSize = (info.width + 7) >> 3;
38641       var buffer = new Uint8Array(rowSize * info.height);
38642       // The contents of ArrayBuffers are initialized to 0.
38643       // Fill the buffer with 0xFF only if info.defaultPixelValue is set
38644       if (info.defaultPixelValue) {
38645         for (var i = 0, ii = buffer.length; i < ii; i++) {
38646           buffer[i] = 0xFF;
38647         }
38648       }
38649       this.buffer = buffer;
38650     },
38651     drawBitmap: function SimpleSegmentVisitor_drawBitmap(regionInfo, bitmap) {
38652       var pageInfo = this.currentPageInfo;
38653       var width = regionInfo.width, height = regionInfo.height;
38654       var rowSize = (pageInfo.width + 7) >> 3;
38655       var combinationOperator = pageInfo.combinationOperatorOverride ?
38656         regionInfo.combinationOperator : pageInfo.combinationOperator;
38657       var buffer = this.buffer;
38658       var mask0 =  128 >> (regionInfo.x & 7);
38659       var offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3);
38660       var i, j, mask, offset;
38661       switch (combinationOperator) {
38662         case 0: // OR
38663           for (i = 0; i < height; i++) {
38664             mask = mask0;
38665             offset = offset0;
38666             for (j = 0; j < width; j++) {
38667               if (bitmap[i][j]) {
38668                 buffer[offset] |= mask;
38669               }
38670               mask >>= 1;
38671               if (!mask) {
38672                 mask = 128;
38673                 offset++;
38674               }
38675             }
38676             offset0 += rowSize;
38677           }
38678         break;
38679         case 2: // XOR
38680           for (i = 0; i < height; i++) {
38681             mask = mask0;
38682             offset = offset0;
38683             for (j = 0; j < width; j++) {
38684               if (bitmap[i][j]) {
38685                 buffer[offset] ^= mask;
38686               }
38687               mask >>= 1;
38688               if (!mask) {
38689                 mask = 128;
38690                 offset++;
38691               }
38692             }
38693             offset0 += rowSize;
38694           }
38695           break;
38696         default:
38697           error('JBIG2 error: operator ' + combinationOperator +
38698                 ' is not supported');
38699       }
38700     },
38701     onImmediateGenericRegion:
38702       function SimpleSegmentVisitor_onImmediateGenericRegion(region, data,
38703                                                              start, end) {
38704       var regionInfo = region.info;
38705       var decodingContext = new DecodingContext(data, start, end);
38706       var bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height,
38707                                 region.template, region.prediction, null,
38708                                 region.at, decodingContext);
38709       this.drawBitmap(regionInfo, bitmap);
38710     },
38711     onImmediateLosslessGenericRegion:
38712       function SimpleSegmentVisitor_onImmediateLosslessGenericRegion() {
38713       this.onImmediateGenericRegion.apply(this, arguments);
38714     },
38715     onSymbolDictionary:
38716       function SimpleSegmentVisitor_onSymbolDictionary(dictionary,
38717                                                        currentSegment,
38718                                                        referredSegments,
38719                                                        data, start, end) {
38720       var huffmanTables;
38721       if (dictionary.huffman) {
38722         error('JBIG2 error: huffman is not supported');
38723       }
38724
38725       // Combines exported symbols from all referred segments
38726       var symbols = this.symbols;
38727       if (!symbols) {
38728         this.symbols = symbols = {};
38729       }
38730
38731       var inputSymbols = [];
38732       for (var i = 0, ii = referredSegments.length; i < ii; i++) {
38733         inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
38734       }
38735
38736       var decodingContext = new DecodingContext(data, start, end);
38737       symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman,
38738         dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols,
38739         dictionary.numberOfExportedSymbols, huffmanTables,
38740         dictionary.template, dictionary.at,
38741         dictionary.refinementTemplate, dictionary.refinementAt,
38742         decodingContext);
38743     },
38744     onImmediateTextRegion:
38745       function SimpleSegmentVisitor_onImmediateTextRegion(region,
38746                                                           referredSegments,
38747                                                           data, start, end) {
38748       var regionInfo = region.info;
38749       var huffmanTables;
38750
38751       // Combines exported symbols from all referred segments
38752       var symbols = this.symbols;
38753       var inputSymbols = [];
38754       for (var i = 0, ii = referredSegments.length; i < ii; i++) {
38755         inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
38756       }
38757       var symbolCodeLength = log2(inputSymbols.length);
38758
38759       var decodingContext = new DecodingContext(data, start, end);
38760       var bitmap = decodeTextRegion(region.huffman, region.refinement,
38761         regionInfo.width, regionInfo.height, region.defaultPixelValue,
38762         region.numberOfSymbolInstances, region.stripSize, inputSymbols,
38763         symbolCodeLength, region.transposed, region.dsOffset,
38764         region.referenceCorner, region.combinationOperator, huffmanTables,
38765         region.refinementTemplate, region.refinementAt, decodingContext);
38766       this.drawBitmap(regionInfo, bitmap);
38767     },
38768     onImmediateLosslessTextRegion:
38769       function SimpleSegmentVisitor_onImmediateLosslessTextRegion() {
38770       this.onImmediateTextRegion.apply(this, arguments);
38771     }
38772   };
38773
38774   function Jbig2Image() {}
38775
38776   Jbig2Image.prototype = {
38777     parseChunks: function Jbig2Image_parseChunks(chunks) {
38778       return parseJbig2Chunks(chunks);
38779     }
38780   };
38781
38782   return Jbig2Image;
38783 })();
38784
38785
38786 var bidi = PDFJS.bidi = (function bidiClosure() {
38787   // Character types for symbols from 0000 to 00FF.
38788   var baseTypes = [
38789     'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S', 'WS',
38790     'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
38791     'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET', 'ET', 'ET', 'ON',
38792     'ON', 'ON', 'ON', 'ON', 'ON', 'CS', 'ON', 'CS', 'ON', 'EN', 'EN', 'EN',
38793     'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'ON', 'ON', 'ON', 'ON', 'ON',
38794     'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38795     'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON',
38796     'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38797     'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38798     'L', 'ON', 'ON', 'ON', 'ON', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN',
38799     'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
38800     'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
38801     'BN', 'CS', 'ON', 'ET', 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON',
38802     'ON', 'ON', 'ON', 'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON',
38803     'EN', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38804     'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38805     'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38806     'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38807     'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
38808   ];
38809
38810   // Character types for symbols from 0600 to 06FF
38811   var arabicTypes = [
38812     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38813     'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL',
38814     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38815     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38816     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38817     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38818     'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
38819     'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL',
38820     'AL', 'AL', 'AL', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN',
38821     'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL', 'AL', 'AL',
38822     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38823     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38824     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38825     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38826     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38827     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38828     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38829     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38830     'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
38831     'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'ON', 'NSM',
38832     'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38833     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL'
38834   ];
38835
38836   function isOdd(i) {
38837     return (i & 1) !== 0;
38838   }
38839
38840   function isEven(i) {
38841     return (i & 1) === 0;
38842   }
38843
38844   function findUnequal(arr, start, value) {
38845     for (var j = start, jj = arr.length; j < jj; ++j) {
38846       if (arr[j] !== value) {
38847         return j;
38848       }
38849     }
38850     return j;
38851   }
38852
38853   function setValues(arr, start, end, value) {
38854     for (var j = start; j < end; ++j) {
38855       arr[j] = value;
38856     }
38857   }
38858
38859   function reverseValues(arr, start, end) {
38860     for (var i = start, j = end - 1; i < j; ++i, --j) {
38861       var temp = arr[i];
38862       arr[i] = arr[j];
38863       arr[j] = temp;
38864     }
38865   }
38866
38867   function createBidiText(str, isLTR, vertical) {
38868     return {
38869       str: str,
38870       dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl'))
38871     };
38872   }
38873
38874   // These are used in bidi(), which is called frequently. We re-use them on
38875   // each call to avoid unnecessary allocations.
38876   var chars = [];
38877   var types = [];
38878
38879   function bidi(str, startLevel, vertical) {
38880     var isLTR = true;
38881     var strLength = str.length;
38882     if (strLength === 0 || vertical) {
38883       return createBidiText(str, isLTR, vertical);
38884     }
38885
38886     // Get types and fill arrays
38887     chars.length = strLength;
38888     types.length = strLength;
38889     var numBidi = 0;
38890
38891     var i, ii;
38892     for (i = 0; i < strLength; ++i) {
38893       chars[i] = str.charAt(i);
38894
38895       var charCode = str.charCodeAt(i);
38896       var charType = 'L';
38897       if (charCode <= 0x00ff) {
38898         charType = baseTypes[charCode];
38899       } else if (0x0590 <= charCode && charCode <= 0x05f4) {
38900         charType = 'R';
38901       } else if (0x0600 <= charCode && charCode <= 0x06ff) {
38902         charType = arabicTypes[charCode & 0xff];
38903       } else if (0x0700 <= charCode && charCode <= 0x08AC) {
38904         charType = 'AL';
38905       }
38906       if (charType === 'R' || charType === 'AL' || charType === 'AN') {
38907         numBidi++;
38908       }
38909       types[i] = charType;
38910     }
38911
38912     // Detect the bidi method
38913     // - If there are no rtl characters then no bidi needed
38914     // - If less than 30% chars are rtl then string is primarily ltr
38915     // - If more than 30% chars are rtl then string is primarily rtl
38916     if (numBidi === 0) {
38917       isLTR = true;
38918       return createBidiText(str, isLTR);
38919     }
38920
38921     if (startLevel === -1) {
38922       if ((strLength / numBidi) < 0.3) {
38923         isLTR = true;
38924         startLevel = 0;
38925       } else {
38926         isLTR = false;
38927         startLevel = 1;
38928       }
38929     }
38930
38931     var levels = [];
38932     for (i = 0; i < strLength; ++i) {
38933       levels[i] = startLevel;
38934     }
38935
38936     /*
38937      X1-X10: skip most of this, since we are NOT doing the embeddings.
38938      */
38939     var e = (isOdd(startLevel) ? 'R' : 'L');
38940     var sor = e;
38941     var eor = sor;
38942
38943     /*
38944      W1. Examine each non-spacing mark (NSM) in the level run, and change the
38945      type of the NSM to the type of the previous character. If the NSM is at the
38946      start of the level run, it will get the type of sor.
38947      */
38948     var lastType = sor;
38949     for (i = 0; i < strLength; ++i) {
38950       if (types[i] === 'NSM') {
38951         types[i] = lastType;
38952       } else {
38953         lastType = types[i];
38954       }
38955     }
38956
38957     /*
38958      W2. Search backwards from each instance of a European number until the
38959      first strong type (R, L, AL, or sor) is found.  If an AL is found, change
38960      the type of the European number to Arabic number.
38961      */
38962     lastType = sor;
38963     var t;
38964     for (i = 0; i < strLength; ++i) {
38965       t = types[i];
38966       if (t === 'EN') {
38967         types[i] = (lastType === 'AL') ? 'AN' : 'EN';
38968       } else if (t === 'R' || t === 'L' || t === 'AL') {
38969         lastType = t;
38970       }
38971     }
38972
38973     /*
38974      W3. Change all ALs to R.
38975      */
38976     for (i = 0; i < strLength; ++i) {
38977       t = types[i];
38978       if (t === 'AL') {
38979         types[i] = 'R';
38980       }
38981     }
38982
38983     /*
38984      W4. A single European separator between two European numbers changes to a
38985      European number. A single common separator between two numbers of the same
38986      type changes to that type:
38987      */
38988     for (i = 1; i < strLength - 1; ++i) {
38989       if (types[i] === 'ES' && types[i - 1] === 'EN' && types[i + 1] === 'EN') {
38990         types[i] = 'EN';
38991       }
38992       if (types[i] === 'CS' &&
38993           (types[i - 1] === 'EN' || types[i - 1] === 'AN') &&
38994           types[i + 1] === types[i - 1]) {
38995         types[i] = types[i - 1];
38996       }
38997     }
38998
38999     /*
39000      W5. A sequence of European terminators adjacent to European numbers changes
39001      to all European numbers:
39002      */
39003     for (i = 0; i < strLength; ++i) {
39004       if (types[i] === 'EN') {
39005         // do before
39006         var j;
39007         for (j = i - 1; j >= 0; --j) {
39008           if (types[j] !== 'ET') {
39009             break;
39010           }
39011           types[j] = 'EN';
39012         }
39013         // do after
39014         for (j = i + 1; j < strLength; --j) {
39015           if (types[j] !== 'ET') {
39016             break;
39017           }
39018           types[j] = 'EN';
39019         }
39020       }
39021     }
39022
39023     /*
39024      W6. Otherwise, separators and terminators change to Other Neutral:
39025      */
39026     for (i = 0; i < strLength; ++i) {
39027       t = types[i];
39028       if (t === 'WS' || t === 'ES' || t === 'ET' || t === 'CS') {
39029         types[i] = 'ON';
39030       }
39031     }
39032
39033     /*
39034      W7. Search backwards from each instance of a European number until the
39035      first strong type (R, L, or sor) is found. If an L is found,  then change
39036      the type of the European number to L.
39037      */
39038     lastType = sor;
39039     for (i = 0; i < strLength; ++i) {
39040       t = types[i];
39041       if (t === 'EN') {
39042         types[i] = ((lastType === 'L') ? 'L' : 'EN');
39043       } else if (t === 'R' || t === 'L') {
39044         lastType = t;
39045       }
39046     }
39047
39048     /*
39049      N1. A sequence of neutrals takes the direction of the surrounding strong
39050      text if the text on both sides has the same direction. European and Arabic
39051      numbers are treated as though they were R. Start-of-level-run (sor) and
39052      end-of-level-run (eor) are used at level run boundaries.
39053      */
39054     for (i = 0; i < strLength; ++i) {
39055       if (types[i] === 'ON') {
39056         var end = findUnequal(types, i + 1, 'ON');
39057         var before = sor;
39058         if (i > 0) {
39059           before = types[i - 1];
39060         }
39061
39062         var after = eor;
39063         if (end + 1 < strLength) {
39064           after = types[end + 1];
39065         }
39066         if (before !== 'L') {
39067           before = 'R';
39068         }
39069         if (after !== 'L') {
39070           after = 'R';
39071         }
39072         if (before === after) {
39073           setValues(types, i, end, before);
39074         }
39075         i = end - 1; // reset to end (-1 so next iteration is ok)
39076       }
39077     }
39078
39079     /*
39080      N2. Any remaining neutrals take the embedding direction.
39081      */
39082     for (i = 0; i < strLength; ++i) {
39083       if (types[i] === 'ON') {
39084         types[i] = e;
39085       }
39086     }
39087
39088     /*
39089      I1. For all characters with an even (left-to-right) embedding direction,
39090      those of type R go up one level and those of type AN or EN go up two
39091      levels.
39092      I2. For all characters with an odd (right-to-left) embedding direction,
39093      those of type L, EN or AN go up one level.
39094      */
39095     for (i = 0; i < strLength; ++i) {
39096       t = types[i];
39097       if (isEven(levels[i])) {
39098         if (t === 'R') {
39099           levels[i] += 1;
39100         } else if (t === 'AN' || t === 'EN') {
39101           levels[i] += 2;
39102         }
39103       } else { // isOdd
39104         if (t === 'L' || t === 'AN' || t === 'EN') {
39105           levels[i] += 1;
39106         }
39107       }
39108     }
39109
39110     /*
39111      L1. On each line, reset the embedding level of the following characters to
39112      the paragraph embedding level:
39113
39114      segment separators,
39115      paragraph separators,
39116      any sequence of whitespace characters preceding a segment separator or
39117      paragraph separator, and any sequence of white space characters at the end
39118      of the line.
39119      */
39120
39121     // don't bother as text is only single line
39122
39123     /*
39124      L2. From the highest level found in the text to the lowest odd level on
39125      each line, reverse any contiguous sequence of characters that are at that
39126      level or higher.
39127      */
39128
39129     // find highest level & lowest odd level
39130     var highestLevel = -1;
39131     var lowestOddLevel = 99;
39132     var level;
39133     for (i = 0, ii = levels.length; i < ii; ++i) {
39134       level = levels[i];
39135       if (highestLevel < level) {
39136         highestLevel = level;
39137       }
39138       if (lowestOddLevel > level && isOdd(level)) {
39139         lowestOddLevel = level;
39140       }
39141     }
39142
39143     // now reverse between those limits
39144     for (level = highestLevel; level >= lowestOddLevel; --level) {
39145       // find segments to reverse
39146       var start = -1;
39147       for (i = 0, ii = levels.length; i < ii; ++i) {
39148         if (levels[i] < level) {
39149           if (start >= 0) {
39150             reverseValues(chars, start, i);
39151             start = -1;
39152           }
39153         } else if (start < 0) {
39154           start = i;
39155         }
39156       }
39157       if (start >= 0) {
39158         reverseValues(chars, start, levels.length);
39159       }
39160     }
39161
39162     /*
39163      L3. Combining marks applied to a right-to-left base character will at this
39164      point precede their base character. If the rendering engine expects them to
39165      follow the base characters in the final display process, then the ordering
39166      of the marks and the base character must be reversed.
39167      */
39168
39169     // don't bother for now
39170
39171     /*
39172      L4. A character that possesses the mirrored property as specified by
39173      Section 4.7, Mirrored, must be depicted by a mirrored glyph if the resolved
39174      directionality of that character is R.
39175      */
39176
39177     // don't mirror as characters are already mirrored in the pdf
39178
39179     // Finally, return string
39180     var result = '';
39181     for (i = 0, ii = chars.length; i < ii; ++i) {
39182       var ch = chars[i];
39183       if (ch !== '<' && ch !== '>') {
39184         result += ch;
39185       }
39186     }
39187     return createBidiText(result, isLTR);
39188   }
39189
39190   return bidi;
39191 })();
39192
39193 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
39194 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
39195
39196 /* Copyright 2014 Opera Software ASA
39197  *
39198  * Licensed under the Apache License, Version 2.0 (the "License");
39199  * you may not use this file except in compliance with the License.
39200  * You may obtain a copy of the License at
39201  *
39202  *     http://www.apache.org/licenses/LICENSE-2.0
39203  *
39204  * Unless required by applicable law or agreed to in writing, software
39205  * distributed under the License is distributed on an "AS IS" BASIS,
39206  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39207  * See the License for the specific language governing permissions and
39208  * limitations under the License.
39209  *
39210  *
39211  * Based on https://code.google.com/p/smhasher/wiki/MurmurHash3.
39212  * Hashes roughly 100 KB per millisecond on i7 3.4 GHz.
39213  */
39214 /* globals Uint32ArrayView */
39215
39216 'use strict';
39217
39218 var MurmurHash3_64 = (function MurmurHash3_64Closure (seed) {
39219   // Workaround for missing math precison in JS.
39220   var MASK_HIGH = 0xffff0000;
39221   var MASK_LOW = 0xffff;
39222
39223   function MurmurHash3_64 (seed) {
39224     var SEED = 0xc3d2e1f0;
39225     this.h1 = seed ? seed & 0xffffffff : SEED;
39226     this.h2 = seed ? seed & 0xffffffff : SEED;
39227   }
39228
39229   var alwaysUseUint32ArrayView = false;
39230   // old webkits have issues with non-aligned arrays
39231   try {
39232     new Uint32Array(new Uint8Array(5).buffer, 0, 1);
39233   } catch (e) {
39234     alwaysUseUint32ArrayView = true;
39235   }
39236
39237   MurmurHash3_64.prototype = {
39238     update: function MurmurHash3_64_update(input) {
39239       var useUint32ArrayView = alwaysUseUint32ArrayView;
39240       var i;
39241       if (typeof input === 'string') {
39242         var data = new Uint8Array(input.length * 2);
39243         var length = 0;
39244         for (i = 0; i < input.length; i++) {
39245           var code = input.charCodeAt(i);
39246           if (code <= 0xff) {
39247             data[length++] = code;
39248           }
39249           else {
39250             data[length++] = code >>> 8;
39251             data[length++] = code & 0xff;
39252           }
39253         }
39254       } else if (input instanceof Uint8Array) {
39255         data = input;
39256         length = data.length;
39257       } else if (typeof input === 'object' && ('length' in input)) {
39258         // processing regular arrays as well, e.g. for IE9
39259         data = input;
39260         length = data.length;
39261         useUint32ArrayView = true;
39262       } else {
39263         throw new Error('Wrong data format in MurmurHash3_64_update. ' +
39264                         'Input must be a string or array.');
39265       }
39266
39267       var blockCounts = length >> 2;
39268       var tailLength = length - blockCounts * 4;
39269       // we don't care about endianness here
39270       var dataUint32 = useUint32ArrayView ?
39271         new Uint32ArrayView(data, blockCounts) :
39272         new Uint32Array(data.buffer, 0, blockCounts);
39273       var k1 = 0;
39274       var k2 = 0;
39275       var h1 = this.h1;
39276       var h2 = this.h2;
39277       var C1 = 0xcc9e2d51;
39278       var C2 = 0x1b873593;
39279       var C1_LOW = C1 & MASK_LOW;
39280       var C2_LOW = C2 & MASK_LOW;
39281
39282       for (i = 0; i < blockCounts; i++) {
39283         if (i & 1) {
39284           k1 = dataUint32[i];
39285           k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
39286           k1 = k1 << 15 | k1 >>> 17;
39287           k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
39288           h1 ^= k1;
39289           h1 = h1 << 13 | h1 >>> 19;
39290           h1 = h1 * 5 + 0xe6546b64;
39291         } else {
39292           k2 = dataUint32[i];
39293           k2 = (k2 * C1 & MASK_HIGH) | (k2 * C1_LOW & MASK_LOW);
39294           k2 = k2 << 15 | k2 >>> 17;
39295           k2 = (k2 * C2 & MASK_HIGH) | (k2 * C2_LOW & MASK_LOW);
39296           h2 ^= k2;
39297           h2 = h2 << 13 | h2 >>> 19;
39298           h2 = h2 * 5 + 0xe6546b64;
39299         }
39300       }
39301
39302       k1 = 0;
39303
39304       switch (tailLength) {
39305         case 3:
39306           k1 ^= data[blockCounts * 4 + 2] << 16;
39307           /* falls through */
39308         case 2:
39309           k1 ^= data[blockCounts * 4 + 1] << 8;
39310           /* falls through */
39311         case 1:
39312           k1 ^= data[blockCounts * 4];
39313           /* falls through */
39314         k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
39315         k1 = k1 << 15 | k1 >>> 17;
39316         k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
39317         if (blockCounts & 1) {
39318           h1 ^= k1;
39319         } else {
39320           h2 ^= k1;
39321         }
39322       }
39323
39324       this.h1 = h1;
39325       this.h2 = h2;
39326       return this;
39327     },
39328
39329     hexdigest: function MurmurHash3_64_hexdigest () {
39330       var h1 = this.h1;
39331       var h2 = this.h2;
39332
39333       h1 ^= h2 >>> 1;
39334       h1 = (h1 * 0xed558ccd & MASK_HIGH) | (h1 * 0x8ccd & MASK_LOW);
39335       h2 = (h2 * 0xff51afd7 & MASK_HIGH) |
39336            (((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16);
39337       h1 ^= h2 >>> 1;
39338       h1 = (h1 * 0x1a85ec53 & MASK_HIGH) | (h1 * 0xec53 & MASK_LOW);
39339       h2 = (h2 * 0xc4ceb9fe & MASK_HIGH) |
39340            (((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16);
39341       h1 ^= h2 >>> 1;
39342
39343       for (var i = 0, arr = [h1, h2], str = ''; i < arr.length; i++) {
39344         var hex = (arr[i] >>> 0).toString(16);
39345         while (hex.length < 8) {
39346           hex = '0' + hex;
39347         }
39348         str += hex;
39349       }
39350
39351       return str;
39352     }
39353   };
39354
39355   return MurmurHash3_64;
39356 })();
39357
39358
39359 }).call((typeof window === 'undefined') ? this : window);
39360
39361 if (!PDFJS.workerSrc && typeof document !== 'undefined') {
39362   // workerSrc is not set -- using last script url to define default location
39363   PDFJS.workerSrc = (function () {
39364     'use strict';
39365     var scriptTagContainer = document.body ||
39366                              document.getElementsByTagName('head')[0];
39367     var pdfjsSrc = scriptTagContainer.lastChild.src;
39368     return pdfjsSrc && pdfjsSrc.replace(/\.js$/i, '.worker.js');
39369   })();
39370 }
39371
39372