PluginProbe
Ebook Store / 6.25
Ebook Store v6.25
6.25 6.24 6.23 6.22 6.21 6.20 trunk
ebook-store / includes / ViewerJS / pdf.worker.js

pdf.worker.js in Ebook Store 6.25, at includes/ViewerJS/pdf.worker.js

39,354 lines 1.2 MB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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.114';
26 PDFJS.build = '3fd44fd';
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 //#if !(FIREFOX || MOZCENTRAL || B2G || CHROME)
538 //// Lazy test if the userAgant support CanvasTypedArrays
539 function hasCanvasTypedArrays() {
540 var canvas = document.createElement('canvas');
541 canvas.width = canvas.height = 1;
542 var ctx = canvas.getContext('2d');
543 var imageData = ctx.createImageData(1, 1);
544 return (typeof imageData.data.buffer !== 'undefined');
545 }
546
547 Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', {
548 configurable: true,
549 get: function PDFJS_hasCanvasTypedArrays() {
550 return shadow(PDFJS, 'hasCanvasTypedArrays', hasCanvasTypedArrays());
551 }
552 });
553
554 var Uint32ArrayView = (function Uint32ArrayViewClosure() {
555
556 function Uint32ArrayView(buffer, length) {
557 this.buffer = buffer;
558 this.byteLength = buffer.length;
559 this.length = length === undefined ? (this.byteLength >> 2) : length;
560 ensureUint32ArrayViewProps(this.length);
561 }
562 Uint32ArrayView.prototype = Object.create(null);
563
564 var uint32ArrayViewSetters = 0;
565 function createUint32ArrayProp(index) {
566 return {
567 get: function () {
568 var buffer = this.buffer, offset = index << 2;
569 return (buffer[offset] | (buffer[offset + 1] << 8) |
570 (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;
571 },
572 set: function (value) {
573 var buffer = this.buffer, offset = index << 2;
574 buffer[offset] = value & 255;
575 buffer[offset + 1] = (value >> 8) & 255;
576 buffer[offset + 2] = (value >> 16) & 255;
577 buffer[offset + 3] = (value >>> 24) & 255;
578 }
579 };
580 }
581
582 function ensureUint32ArrayViewProps(length) {
583 while (uint32ArrayViewSetters < length) {
584 Object.defineProperty(Uint32ArrayView.prototype,
585 uint32ArrayViewSetters,
586 createUint32ArrayProp(uint32ArrayViewSetters));
587 uint32ArrayViewSetters++;
588 }
589 }
590
591 return Uint32ArrayView;
592 })();
593 //#else
594 //PDFJS.hasCanvasTypedArrays = true;
595 //#endif
596
597 var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
598
599 var Util = PDFJS.Util = (function UtilClosure() {
600 function Util() {}
601
602 var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];
603
604 // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids
605 // creating many intermediate strings.
606 Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
607 rgbBuf[1] = r;
608 rgbBuf[3] = g;
609 rgbBuf[5] = b;
610 return rgbBuf.join('');
611 };
612
613 // Concatenates two transformation matrices together and returns the result.
614 Util.transform = function Util_transform(m1, m2) {
615 return [
616 m1[0] * m2[0] + m1[2] * m2[1],
617 m1[1] * m2[0] + m1[3] * m2[1],
618 m1[0] * m2[2] + m1[2] * m2[3],
619 m1[1] * m2[2] + m1[3] * m2[3],
620 m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
621 m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
622 ];
623 };
624
625 // For 2d affine transforms
626 Util.applyTransform = function Util_applyTransform(p, m) {
627 var xt = p[0] * m[0] + p[1] * m[2] + m[4];
628 var yt = p[0] * m[1] + p[1] * m[3] + m[5];
629 return [xt, yt];
630 };
631
632 Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
633 var d = m[0] * m[3] - m[1] * m[2];
634 var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
635 var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
636 return [xt, yt];
637 };
638
639 // Applies the transform to the rectangle and finds the minimum axially
640 // aligned bounding box.
641 Util.getAxialAlignedBoundingBox =
642 function Util_getAxialAlignedBoundingBox(r, m) {
643
644 var p1 = Util.applyTransform(r, m);
645 var p2 = Util.applyTransform(r.slice(2, 4), m);
646 var p3 = Util.applyTransform([r[0], r[3]], m);
647 var p4 = Util.applyTransform([r[2], r[1]], m);
648 return [
649 Math.min(p1[0], p2[0], p3[0], p4[0]),
650 Math.min(p1[1], p2[1], p3[1], p4[1]),
651 Math.max(p1[0], p2[0], p3[0], p4[0]),
652 Math.max(p1[1], p2[1], p3[1], p4[1])
653 ];
654 };
655
656 Util.inverseTransform = function Util_inverseTransform(m) {
657 var d = m[0] * m[3] - m[1] * m[2];
658 return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
659 (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
660 };
661
662 // Apply a generic 3d matrix M on a 3-vector v:
663 // | a b c | | X |
664 // | d e f | x | Y |
665 // | g h i | | Z |
666 // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
667 // with v as [X,Y,Z]
668 Util.apply3dTransform = function Util_apply3dTransform(m, v) {
669 return [
670 m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
671 m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
672 m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
673 ];
674 };
675
676 // This calculation uses Singular Value Decomposition.
677 // The SVD can be represented with formula A = USV. We are interested in the
678 // matrix S here because it represents the scale values.
679 Util.singularValueDecompose2dScale =
680 function Util_singularValueDecompose2dScale(m) {
681
682 var transpose = [m[0], m[2], m[1], m[3]];
683
684 // Multiply matrix m with its transpose.
685 var a = m[0] * transpose[0] + m[1] * transpose[2];
686 var b = m[0] * transpose[1] + m[1] * transpose[3];
687 var c = m[2] * transpose[0] + m[3] * transpose[2];
688 var d = m[2] * transpose[1] + m[3] * transpose[3];
689
690 // Solve the second degree polynomial to get roots.
691 var first = (a + d) / 2;
692 var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
693 var sx = first + second || 1;
694 var sy = first - second || 1;
695
696 // Scale values are the square roots of the eigenvalues.
697 return [Math.sqrt(sx), Math.sqrt(sy)];
698 };
699
700 // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
701 // For coordinate systems whose origin lies in the bottom-left, this
702 // means normalization to (BL,TR) ordering. For systems with origin in the
703 // top-left, this means (TL,BR) ordering.
704 Util.normalizeRect = function Util_normalizeRect(rect) {
705 var r = rect.slice(0); // clone rect
706 if (rect[0] > rect[2]) {
707 r[0] = rect[2];
708 r[2] = rect[0];
709 }
710 if (rect[1] > rect[3]) {
711 r[1] = rect[3];
712 r[3] = rect[1];
713 }
714 return r;
715 };
716
717 // Returns a rectangle [x1, y1, x2, y2] corresponding to the
718 // intersection of rect1 and rect2. If no intersection, returns 'false'
719 // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
720 Util.intersect = function Util_intersect(rect1, rect2) {
721 function compare(a, b) {
722 return a - b;
723 }
724
725 // Order points along the axes
726 var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
727 orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
728 result = [];
729
730 rect1 = Util.normalizeRect(rect1);
731 rect2 = Util.normalizeRect(rect2);
732
733 // X: first and second points belong to different rectangles?
734 if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
735 (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
736 // Intersection must be between second and third points
737 result[0] = orderedX[1];
738 result[2] = orderedX[2];
739 } else {
740 return false;
741 }
742
743 // Y: first and second points belong to different rectangles?
744 if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
745 (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
746 // Intersection must be between second and third points
747 result[1] = orderedY[1];
748 result[3] = orderedY[2];
749 } else {
750 return false;
751 }
752
753 return result;
754 };
755
756 Util.sign = function Util_sign(num) {
757 return num < 0 ? -1 : 1;
758 };
759
760 Util.appendToArray = function Util_appendToArray(arr1, arr2) {
761 Array.prototype.push.apply(arr1, arr2);
762 };
763
764 Util.prependToArray = function Util_prependToArray(arr1, arr2) {
765 Array.prototype.unshift.apply(arr1, arr2);
766 };
767
768 Util.extendObj = function extendObj(obj1, obj2) {
769 for (var key in obj2) {
770 obj1[key] = obj2[key];
771 }
772 };
773
774 Util.getInheritableProperty = function Util_getInheritableProperty(dict,
775 name) {
776 while (dict && !dict.has(name)) {
777 dict = dict.get('Parent');
778 }
779 if (!dict) {
780 return null;
781 }
782 return dict.get(name);
783 };
784
785 Util.inherit = function Util_inherit(sub, base, prototype) {
786 sub.prototype = Object.create(base.prototype);
787 sub.prototype.constructor = sub;
788 for (var prop in prototype) {
789 sub.prototype[prop] = prototype[prop];
790 }
791 };
792
793 Util.loadScript = function Util_loadScript(src, callback) {
794 var script = document.createElement('script');
795 var loaded = false;
796 script.setAttribute('src', src);
797 if (callback) {
798 script.onload = function() {
799 if (!loaded) {
800 callback();
801 }
802 loaded = true;
803 };
804 }
805 document.getElementsByTagName('head')[0].appendChild(script);
806 };
807
808 return Util;
809 })();
810
811 /**
812 * PDF page viewport created based on scale, rotation and offset.
813 * @class
814 * @alias PDFJS.PageViewport
815 */
816 var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
817 /**
818 * @constructor
819 * @private
820 * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
821 * @param scale {number} scale of the viewport.
822 * @param rotation {number} rotations of the viewport in degrees.
823 * @param offsetX {number} offset X
824 * @param offsetY {number} offset Y
825 * @param dontFlip {boolean} if true, axis Y will not be flipped.
826 */
827 function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
828 this.viewBox = viewBox;
829 this.scale = scale;
830 this.rotation = rotation;
831 this.offsetX = offsetX;
832 this.offsetY = offsetY;
833
834 // creating transform to convert pdf coordinate system to the normal
835 // canvas like coordinates taking in account scale and rotation
836 var centerX = (viewBox[2] + viewBox[0]) / 2;
837 var centerY = (viewBox[3] + viewBox[1]) / 2;
838 var rotateA, rotateB, rotateC, rotateD;
839 rotation = rotation % 360;
840 rotation = rotation < 0 ? rotation + 360 : rotation;
841 switch (rotation) {
842 case 180:
843 rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
844 break;
845 case 90:
846 rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
847 break;
848 case 270:
849 rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
850 break;
851 //case 0:
852 default:
853 rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
854 break;
855 }
856
857 if (dontFlip) {
858 rotateC = -rotateC; rotateD = -rotateD;
859 }
860
861 var offsetCanvasX, offsetCanvasY;
862 var width, height;
863 if (rotateA === 0) {
864 offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
865 offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
866 width = Math.abs(viewBox[3] - viewBox[1]) * scale;
867 height = Math.abs(viewBox[2] - viewBox[0]) * scale;
868 } else {
869 offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
870 offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
871 width = Math.abs(viewBox[2] - viewBox[0]) * scale;
872 height = Math.abs(viewBox[3] - viewBox[1]) * scale;
873 }
874 // creating transform for the following operations:
875 // translate(-centerX, -centerY), rotate and flip vertically,
876 // scale, and translate(offsetCanvasX, offsetCanvasY)
877 this.transform = [
878 rotateA * scale,
879 rotateB * scale,
880 rotateC * scale,
881 rotateD * scale,
882 offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
883 offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
884 ];
885
886 this.width = width;
887 this.height = height;
888 this.fontScale = scale;
889 }
890 PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
891 /**
892 * Clones viewport with additional properties.
893 * @param args {Object} (optional) If specified, may contain the 'scale' or
894 * 'rotation' properties to override the corresponding properties in
895 * the cloned viewport.
896 * @returns {PDFJS.PageViewport} Cloned viewport.
897 */
898 clone: function PageViewPort_clone(args) {
899 args = args || {};
900 var scale = 'scale' in args ? args.scale : this.scale;
901 var rotation = 'rotation' in args ? args.rotation : this.rotation;
902 return new PageViewport(this.viewBox.slice(), scale, rotation,
903 this.offsetX, this.offsetY, args.dontFlip);
904 },
905 /**
906 * Converts PDF point to the viewport coordinates. For examples, useful for
907 * converting PDF location into canvas pixel coordinates.
908 * @param x {number} X coordinate.
909 * @param y {number} Y coordinate.
910 * @returns {Object} Object that contains 'x' and 'y' properties of the
911 * point in the viewport coordinate space.
912 * @see {@link convertToPdfPoint}
913 * @see {@link convertToViewportRectangle}
914 */
915 convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
916 return Util.applyTransform([x, y], this.transform);
917 },
918 /**
919 * Converts PDF rectangle to the viewport coordinates.
920 * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
921 * @returns {Array} Contains corresponding coordinates of the rectangle
922 * in the viewport coordinate space.
923 * @see {@link convertToViewportPoint}
924 */
925 convertToViewportRectangle:
926 function PageViewport_convertToViewportRectangle(rect) {
927 var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
928 var br = Util.applyTransform([rect[2], rect[3]], this.transform);
929 return [tl[0], tl[1], br[0], br[1]];
930 },
931 /**
932 * Converts viewport coordinates to the PDF location. For examples, useful
933 * for converting canvas pixel location into PDF one.
934 * @param x {number} X coordinate.
935 * @param y {number} Y coordinate.
936 * @returns {Object} Object that contains 'x' and 'y' properties of the
937 * point in the PDF coordinate space.
938 * @see {@link convertToViewportPoint}
939 */
940 convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
941 return Util.applyInverseTransform([x, y], this.transform);
942 }
943 };
944 return PageViewport;
945 })();
946
947 var PDFStringTranslateTable = [
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,
949 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
950 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,
951 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,
952 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,
953 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
954 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
955 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
956 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
957 ];
958
959 function stringToPDFString(str) {
960 var i, n = str.length, strBuf = [];
961 if (str[0] === '\xFE' && str[1] === '\xFF') {
962 // UTF16BE BOM
963 for (i = 2; i < n; i += 2) {
964 strBuf.push(String.fromCharCode(
965 (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));
966 }
967 } else {
968 for (i = 0; i < n; ++i) {
969 var code = PDFStringTranslateTable[str.charCodeAt(i)];
970 strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
971 }
972 }
973 return strBuf.join('');
974 }
975
976 function stringToUTF8String(str) {
977 return decodeURIComponent(escape(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 //#if !MOZCENTRAL
1121 var STATUS_PENDING = 0;
1122 var STATUS_RESOLVED = 1;
1123 var STATUS_REJECTED = 2;
1124
1125 // In an attempt to avoid silent exceptions, unhandled rejections are
1126 // tracked and if they aren't handled in a certain amount of time an
1127 // error is logged.
1128 var REJECTION_TIMEOUT = 500;
1129
1130 var HandlerManager = {
1131 handlers: [],
1132 running: false,
1133 unhandledRejections: [],
1134 pendingRejectionCheck: false,
1135
1136 scheduleHandlers: function scheduleHandlers(promise) {
1137 if (promise._status === STATUS_PENDING) {
1138 return;
1139 }
1140
1141 this.handlers = this.handlers.concat(promise._handlers);
1142 promise._handlers = [];
1143
1144 if (this.running) {
1145 return;
1146 }
1147 this.running = true;
1148
1149 setTimeout(this.runHandlers.bind(this), 0);
1150 },
1151
1152 runHandlers: function runHandlers() {
1153 var RUN_TIMEOUT = 1; // ms
1154 var timeoutAt = Date.now() + RUN_TIMEOUT;
1155 while (this.handlers.length > 0) {
1156 var handler = this.handlers.shift();
1157
1158 var nextStatus = handler.thisPromise._status;
1159 var nextValue = handler.thisPromise._value;
1160
1161 try {
1162 if (nextStatus === STATUS_RESOLVED) {
1163 if (typeof handler.onResolve === 'function') {
1164 nextValue = handler.onResolve(nextValue);
1165 }
1166 } else if (typeof handler.onReject === 'function') {
1167 nextValue = handler.onReject(nextValue);
1168 nextStatus = STATUS_RESOLVED;
1169
1170 if (handler.thisPromise._unhandledRejection) {
1171 this.removeUnhandeledRejection(handler.thisPromise);
1172 }
1173 }
1174 } catch (ex) {
1175 nextStatus = STATUS_REJECTED;
1176 nextValue = ex;
1177 }
1178
1179 handler.nextPromise._updateStatus(nextStatus, nextValue);
1180 if (Date.now() >= timeoutAt) {
1181 break;
1182 }
1183 }
1184
1185 if (this.handlers.length > 0) {
1186 setTimeout(this.runHandlers.bind(this), 0);
1187 return;
1188 }
1189
1190 this.running = false;
1191 },
1192
1193 addUnhandledRejection: function addUnhandledRejection(promise) {
1194 this.unhandledRejections.push({
1195 promise: promise,
1196 time: Date.now()
1197 });
1198 this.scheduleRejectionCheck();
1199 },
1200
1201 removeUnhandeledRejection: function removeUnhandeledRejection(promise) {
1202 promise._unhandledRejection = false;
1203 for (var i = 0; i < this.unhandledRejections.length; i++) {
1204 if (this.unhandledRejections[i].promise === promise) {
1205 this.unhandledRejections.splice(i);
1206 i--;
1207 }
1208 }
1209 },
1210
1211 scheduleRejectionCheck: function scheduleRejectionCheck() {
1212 if (this.pendingRejectionCheck) {
1213 return;
1214 }
1215 this.pendingRejectionCheck = true;
1216 setTimeout(function rejectionCheck() {
1217 this.pendingRejectionCheck = false;
1218 var now = Date.now();
1219 for (var i = 0; i < this.unhandledRejections.length; i++) {
1220 if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {
1221 var unhandled = this.unhandledRejections[i].promise._value;
1222 var msg = 'Unhandled rejection: ' + unhandled;
1223 if (unhandled.stack) {
1224 msg += '\n' + unhandled.stack;
1225 }
1226 warn(msg);
1227 this.unhandledRejections.splice(i);
1228 i--;
1229 }
1230 }
1231 if (this.unhandledRejections.length) {
1232 this.scheduleRejectionCheck();
1233 }
1234 }.bind(this), REJECTION_TIMEOUT);
1235 }
1236 };
1237
1238 function Promise(resolver) {
1239 this._status = STATUS_PENDING;
1240 this._handlers = [];
1241 try {
1242 resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
1243 } catch (e) {
1244 this._reject(e);
1245 }
1246 }
1247 /**
1248 * Builds a promise that is resolved when all the passed in promises are
1249 * resolved.
1250 * @param {array} array of data and/or promises to wait for.
1251 * @return {Promise} New dependant promise.
1252 */
1253 Promise.all = function Promise_all(promises) {
1254 var resolveAll, rejectAll;
1255 var deferred = new Promise(function (resolve, reject) {
1256 resolveAll = resolve;
1257 rejectAll = reject;
1258 });
1259 var unresolved = promises.length;
1260 var results = [];
1261 if (unresolved === 0) {
1262 resolveAll(results);
1263 return deferred;
1264 }
1265 function reject(reason) {
1266 if (deferred._status === STATUS_REJECTED) {
1267 return;
1268 }
1269 results = [];
1270 rejectAll(reason);
1271 }
1272 for (var i = 0, ii = promises.length; i < ii; ++i) {
1273 var promise = promises[i];
1274 var resolve = (function(i) {
1275 return function(value) {
1276 if (deferred._status === STATUS_REJECTED) {
1277 return;
1278 }
1279 results[i] = value;
1280 unresolved--;
1281 if (unresolved === 0) {
1282 resolveAll(results);
1283 }
1284 };
1285 })(i);
1286 if (Promise.isPromise(promise)) {
1287 promise.then(resolve, reject);
1288 } else {
1289 resolve(promise);
1290 }
1291 }
1292 return deferred;
1293 };
1294
1295 /**
1296 * Checks if the value is likely a promise (has a 'then' function).
1297 * @return {boolean} true if value is thenable
1298 */
1299 Promise.isPromise = function Promise_isPromise(value) {
1300 return value && typeof value.then === 'function';
1301 };
1302
1303 /**
1304 * Creates resolved promise
1305 * @param value resolve value
1306 * @returns {Promise}
1307 */
1308 Promise.resolve = function Promise_resolve(value) {
1309 return new Promise(function (resolve) { resolve(value); });
1310 };
1311
1312 /**
1313 * Creates rejected promise
1314 * @param reason rejection value
1315 * @returns {Promise}
1316 */
1317 Promise.reject = function Promise_reject(reason) {
1318 return new Promise(function (resolve, reject) { reject(reason); });
1319 };
1320
1321 Promise.prototype = {
1322 _status: null,
1323 _value: null,
1324 _handlers: null,
1325 _unhandledRejection: null,
1326
1327 _updateStatus: function Promise__updateStatus(status, value) {
1328 if (this._status === STATUS_RESOLVED ||
1329 this._status === STATUS_REJECTED) {
1330 return;
1331 }
1332
1333 if (status === STATUS_RESOLVED &&
1334 Promise.isPromise(value)) {
1335 value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
1336 this._updateStatus.bind(this, STATUS_REJECTED));
1337 return;
1338 }
1339
1340 this._status = status;
1341 this._value = value;
1342
1343 if (status === STATUS_REJECTED && this._handlers.length === 0) {
1344 this._unhandledRejection = true;
1345 HandlerManager.addUnhandledRejection(this);
1346 }
1347
1348 HandlerManager.scheduleHandlers(this);
1349 },
1350
1351 _resolve: function Promise_resolve(value) {
1352 this._updateStatus(STATUS_RESOLVED, value);
1353 },
1354
1355 _reject: function Promise_reject(reason) {
1356 this._updateStatus(STATUS_REJECTED, reason);
1357 },
1358
1359 then: function Promise_then(onResolve, onReject) {
1360 var nextPromise = new Promise(function (resolve, reject) {
1361 this.resolve = resolve;
1362 this.reject = reject;
1363 });
1364 this._handlers.push({
1365 thisPromise: this,
1366 onResolve: onResolve,
1367 onReject: onReject,
1368 nextPromise: nextPromise
1369 });
1370 HandlerManager.scheduleHandlers(this);
1371 return nextPromise;
1372 },
1373
1374 catch: function Promise_catch(onReject) {
1375 return this.then(undefined, onReject);
1376 }
1377 };
1378
1379 globalScope.Promise = Promise;
1380 //#else
1381 //throw new Error('DOM Promise is not present');
1382 //#endif
1383 })();
1384
1385 var StatTimer = (function StatTimerClosure() {
1386 function rpad(str, pad, length) {
1387 while (str.length < length) {
1388 str += pad;
1389 }
1390 return str;
1391 }
1392 function StatTimer() {
1393 this.started = {};
1394 this.times = [];
1395 this.enabled = true;
1396 }
1397 StatTimer.prototype = {
1398 time: function StatTimer_time(name) {
1399 if (!this.enabled) {
1400 return;
1401 }
1402 if (name in this.started) {
1403 warn('Timer is already running for ' + name);
1404 }
1405 this.started[name] = Date.now();
1406 },
1407 timeEnd: function StatTimer_timeEnd(name) {
1408 if (!this.enabled) {
1409 return;
1410 }
1411 if (!(name in this.started)) {
1412 warn('Timer has not been started for ' + name);
1413 }
1414 this.times.push({
1415 'name': name,
1416 'start': this.started[name],
1417 'end': Date.now()
1418 });
1419 // Remove timer from started so it can be called again.
1420 delete this.started[name];
1421 },
1422 toString: function StatTimer_toString() {
1423 var i, ii;
1424 var times = this.times;
1425 var out = '';
1426 // Find the longest name for padding purposes.
1427 var longest = 0;
1428 for (i = 0, ii = times.length; i < ii; ++i) {
1429 var name = times[i]['name'];
1430 if (name.length > longest) {
1431 longest = name.length;
1432 }
1433 }
1434 for (i = 0, ii = times.length; i < ii; ++i) {
1435 var span = times[i];
1436 var duration = span.end - span.start;
1437 out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
1438 }
1439 return out;
1440 }
1441 };
1442 return StatTimer;
1443 })();
1444
1445 PDFJS.createBlob = function createBlob(data, contentType) {
1446 if (typeof Blob !== 'undefined') {
1447 return new Blob([data], { type: contentType });
1448 }
1449 // Blob builder is deprecated in FF14 and removed in FF18.
1450 var bb = new MozBlobBuilder();
1451 bb.append(data);
1452 return bb.getBlob(contentType);
1453 };
1454
1455 PDFJS.createObjectURL = (function createObjectURLClosure() {
1456 // Blob/createObjectURL is not available, falling back to data schema.
1457 var digits =
1458 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
1459
1460 return function createObjectURL(data, contentType) {
1461 if (!PDFJS.disableCreateObjectURL &&
1462 typeof URL !== 'undefined' && URL.createObjectURL) {
1463 var blob = PDFJS.createBlob(data, contentType);
1464 return URL.createObjectURL(blob);
1465 }
1466
1467 var buffer = 'data:' + contentType + ';base64,';
1468 for (var i = 0, ii = data.length; i < ii; i += 3) {
1469 var b1 = data[i] & 0xFF;
1470 var b2 = data[i + 1] & 0xFF;
1471 var b3 = data[i + 2] & 0xFF;
1472 var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
1473 var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
1474 var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
1475 buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
1476 }
1477 return buffer;
1478 };
1479 })();
1480
1481 function MessageHandler(name, comObj) {
1482 this.name = name;
1483 this.comObj = comObj;
1484 this.callbackIndex = 1;
1485 this.postMessageTransfers = true;
1486 var callbacksCapabilities = this.callbacksCapabilities = {};
1487 var ah = this.actionHandler = {};
1488
1489 ah['console_log'] = [function ahConsoleLog(data) {
1490 console.log.apply(console, data);
1491 }];
1492 ah['console_error'] = [function ahConsoleError(data) {
1493 console.error.apply(console, data);
1494 }];
1495 ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
1496 UnsupportedManager.notify(data);
1497 }];
1498
1499 comObj.onmessage = function messageHandlerComObjOnMessage(event) {
1500 var data = event.data;
1501 if (data.isReply) {
1502 var callbackId = data.callbackId;
1503 if (data.callbackId in callbacksCapabilities) {
1504 var callback = callbacksCapabilities[callbackId];
1505 delete callbacksCapabilities[callbackId];
1506 if ('error' in data) {
1507 callback.reject(data.error);
1508 } else {
1509 callback.resolve(data.data);
1510 }
1511 } else {
1512 error('Cannot resolve callback ' + callbackId);
1513 }
1514 } else if (data.action in ah) {
1515 var action = ah[data.action];
1516 if (data.callbackId) {
1517 Promise.resolve().then(function () {
1518 return action[0].call(action[1], data.data);
1519 }).then(function (result) {
1520 comObj.postMessage({
1521 isReply: true,
1522 callbackId: data.callbackId,
1523 data: result
1524 });
1525 }, function (reason) {
1526 comObj.postMessage({
1527 isReply: true,
1528 callbackId: data.callbackId,
1529 error: reason
1530 });
1531 });
1532 } else {
1533 action[0].call(action[1], data.data);
1534 }
1535 } else {
1536 error('Unknown action from worker: ' + data.action);
1537 }
1538 };
1539 }
1540
1541 MessageHandler.prototype = {
1542 on: function messageHandlerOn(actionName, handler, scope) {
1543 var ah = this.actionHandler;
1544 if (ah[actionName]) {
1545 error('There is already an actionName called "' + actionName + '"');
1546 }
1547 ah[actionName] = [handler, scope];
1548 },
1549 /**
1550 * Sends a message to the comObj to invoke the action with the supplied data.
1551 * @param {String} actionName Action to call.
1552 * @param {JSON} data JSON data to send.
1553 * @param {Array} [transfers] Optional list of transfers/ArrayBuffers
1554 */
1555 send: function messageHandlerSend(actionName, data, transfers) {
1556 var message = {
1557 action: actionName,
1558 data: data
1559 };
1560 this.postMessage(message, transfers);
1561 },
1562 /**
1563 * Sends a message to the comObj to invoke the action with the supplied data.
1564 * Expects that other side will callback with the response.
1565 * @param {String} actionName Action to call.
1566 * @param {JSON} data JSON data to send.
1567 * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
1568 * @returns {Promise} Promise to be resolved with response data.
1569 */
1570 sendWithPromise:
1571 function messageHandlerSendWithPromise(actionName, data, transfers) {
1572 var callbackId = this.callbackIndex++;
1573 var message = {
1574 action: actionName,
1575 data: data,
1576 callbackId: callbackId
1577 };
1578 var capability = createPromiseCapability();
1579 this.callbacksCapabilities[callbackId] = capability;
1580 try {
1581 this.postMessage(message, transfers);
1582 } catch (e) {
1583 capability.reject(e);
1584 }
1585 return capability.promise;
1586 },
1587 /**
1588 * Sends raw message to the comObj.
1589 * @private
1590 * @param message {Object} Raw message.
1591 * @param transfers List of transfers/ArrayBuffers, or undefined.
1592 */
1593 postMessage: function (message, transfers) {
1594 if (transfers && this.postMessageTransfers) {
1595 this.comObj.postMessage(message, transfers);
1596 } else {
1597 this.comObj.postMessage(message);
1598 }
1599 }
1600 };
1601
1602 function loadJpegStream(id, imageUrl, objs) {
1603 var img = new Image();
1604 img.onload = (function loadJpegStream_onloadClosure() {
1605 objs.resolve(id, img);
1606 });
1607 img.onerror = (function loadJpegStream_onerrorClosure() {
1608 objs.resolve(id, null);
1609 warn('Error during JPEG image loading');
1610 });
1611 img.src = imageUrl;
1612 }
1613
1614
1615
1616 //#if (FIREFOX || MOZCENTRAL)
1617 //
1618 //Components.utils.import('resource://gre/modules/Services.jsm');
1619 //
1620 //var EXPORTED_SYMBOLS = ['NetworkManager'];
1621 //
1622 //var console = {
1623 // log: function console_log(aMsg) {
1624 // var msg = 'network.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
1625 // Services.console.logStringMessage(msg);
1626 // // TODO(mack): dump() doesn't seem to work here...
1627 // dump(msg + '\n');
1628 // }
1629 //}
1630 //#endif
1631
1632 var NetworkManager = (function NetworkManagerClosure() {
1633
1634 var OK_RESPONSE = 200;
1635 var PARTIAL_CONTENT_RESPONSE = 206;
1636
1637 function NetworkManager(url, args) {
1638 this.url = url;
1639 args = args || {};
1640 this.isHttp = /^https?:/i.test(url);
1641 this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
1642 this.withCredentials = args.withCredentials || false;
1643 this.getXhr = args.getXhr ||
1644 function NetworkManager_getXhr() {
1645 //#if B2G
1646 // return new XMLHttpRequest({ mozSystem: true });
1647 //#else
1648 return new XMLHttpRequest();
1649 //#endif
1650 };
1651
1652 this.currXhrId = 0;
1653 this.pendingRequests = {};
1654 this.loadedRequests = {};
1655 }
1656
1657 function getArrayBuffer(xhr) {
1658 var data = xhr.response;
1659 if (typeof data !== 'string') {
1660 return data;
1661 }
1662 var length = data.length;
1663 var array = new Uint8Array(length);
1664 for (var i = 0; i < length; i++) {
1665 array[i] = data.charCodeAt(i) & 0xFF;
1666 }
1667 return array.buffer;
1668 }
1669
1670 NetworkManager.prototype = {
1671 requestRange: function NetworkManager_requestRange(begin, end, listeners) {
1672 var args = {
1673 begin: begin,
1674 end: end
1675 };
1676 for (var prop in listeners) {
1677 args[prop] = listeners[prop];
1678 }
1679 return this.request(args);
1680 },
1681
1682 requestFull: function NetworkManager_requestFull(listeners) {
1683 return this.request(listeners);
1684 },
1685
1686 request: function NetworkManager_request(args) {
1687 var xhr = this.getXhr();
1688 var xhrId = this.currXhrId++;
1689 var pendingRequest = this.pendingRequests[xhrId] = {
1690 xhr: xhr
1691 };
1692
1693 xhr.open('GET', this.url);
1694 xhr.withCredentials = this.withCredentials;
1695 for (var property in this.httpHeaders) {
1696 var value = this.httpHeaders[property];
1697 if (typeof value === 'undefined') {
1698 continue;
1699 }
1700 xhr.setRequestHeader(property, value);
1701 }
1702 if (this.isHttp && 'begin' in args && 'end' in args) {
1703 var rangeStr = args.begin + '-' + (args.end - 1);
1704 xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
1705 pendingRequest.expectedStatus = 206;
1706 } else {
1707 pendingRequest.expectedStatus = 200;
1708 }
1709
1710 if (args.onProgressiveData) {
1711 // Some legacy browsers might throw an exception.
1712 try {
1713 xhr.responseType = 'moz-chunked-arraybuffer';
1714 } catch(e) {}
1715 if (xhr.responseType === 'moz-chunked-arraybuffer') {
1716 pendingRequest.onProgressiveData = args.onProgressiveData;
1717 pendingRequest.mozChunked = true;
1718 } else {
1719 xhr.responseType = 'arraybuffer';
1720 }
1721 } else {
1722 xhr.responseType = 'arraybuffer';
1723 }
1724
1725 if (args.onError) {
1726 xhr.onerror = function(evt) {
1727 args.onError(xhr.status);
1728 };
1729 }
1730 xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
1731 xhr.onprogress = this.onProgress.bind(this, xhrId);
1732
1733 pendingRequest.onHeadersReceived = args.onHeadersReceived;
1734 pendingRequest.onDone = args.onDone;
1735 pendingRequest.onError = args.onError;
1736 pendingRequest.onProgress = args.onProgress;
1737
1738 xhr.send(null);
1739
1740 return xhrId;
1741 },
1742
1743 onProgress: function NetworkManager_onProgress(xhrId, evt) {
1744 var pendingRequest = this.pendingRequests[xhrId];
1745 if (!pendingRequest) {
1746 // Maybe abortRequest was called...
1747 return;
1748 }
1749
1750 if (pendingRequest.mozChunked) {
1751 var chunk = getArrayBuffer(pendingRequest.xhr);
1752 pendingRequest.onProgressiveData(chunk);
1753 }
1754
1755 var onProgress = pendingRequest.onProgress;
1756 if (onProgress) {
1757 onProgress(evt);
1758 }
1759 },
1760
1761 onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
1762 var pendingRequest = this.pendingRequests[xhrId];
1763 if (!pendingRequest) {
1764 // Maybe abortRequest was called...
1765 return;
1766 }
1767
1768 var xhr = pendingRequest.xhr;
1769 if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
1770 pendingRequest.onHeadersReceived();
1771 delete pendingRequest.onHeadersReceived;
1772 }
1773
1774 if (xhr.readyState !== 4) {
1775 return;
1776 }
1777
1778 if (!(xhrId in this.pendingRequests)) {
1779 // The XHR request might have been aborted in onHeadersReceived()
1780 // callback, in which case we should abort request
1781 return;
1782 }
1783
1784 delete this.pendingRequests[xhrId];
1785
1786 // success status == 0 can be on ftp, file and other protocols
1787 if (xhr.status === 0 && this.isHttp) {
1788 if (pendingRequest.onError) {
1789 pendingRequest.onError(xhr.status);
1790 }
1791 return;
1792 }
1793 var xhrStatus = xhr.status || OK_RESPONSE;
1794
1795 // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2:
1796 // "A server MAY ignore the Range header". This means it's possible to
1797 // get a 200 rather than a 206 response from a range request.
1798 var ok_response_on_range_request =
1799 xhrStatus === OK_RESPONSE &&
1800 pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
1801
1802 if (!ok_response_on_range_request &&
1803 xhrStatus !== pendingRequest.expectedStatus) {
1804 if (pendingRequest.onError) {
1805 pendingRequest.onError(xhr.status);
1806 }
1807 return;
1808 }
1809
1810 this.loadedRequests[xhrId] = true;
1811
1812 var chunk = getArrayBuffer(xhr);
1813 if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
1814 var rangeHeader = xhr.getResponseHeader('Content-Range');
1815 var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
1816 var begin = parseInt(matches[1], 10);
1817 pendingRequest.onDone({
1818 begin: begin,
1819 chunk: chunk
1820 });
1821 } else if (pendingRequest.onProgressiveData) {
1822 pendingRequest.onDone(null);
1823 } else {
1824 pendingRequest.onDone({
1825 begin: 0,
1826 chunk: chunk
1827 });
1828 }
1829 },
1830
1831 hasPendingRequests: function NetworkManager_hasPendingRequests() {
1832 for (var xhrId in this.pendingRequests) {
1833 return true;
1834 }
1835 return false;
1836 },
1837
1838 getRequestXhr: function NetworkManager_getXhr(xhrId) {
1839 return this.pendingRequests[xhrId].xhr;
1840 },
1841
1842 isStreamingRequest: function NetworkManager_isStreamingRequest(xhrId) {
1843 return !!(this.pendingRequests[xhrId].onProgressiveData);
1844 },
1845
1846 isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
1847 return xhrId in this.pendingRequests;
1848 },
1849
1850 isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) {
1851 return xhrId in this.loadedRequests;
1852 },
1853
1854 abortAllRequests: function NetworkManager_abortAllRequests() {
1855 for (var xhrId in this.pendingRequests) {
1856 this.abortRequest(xhrId | 0);
1857 }
1858 },
1859
1860 abortRequest: function NetworkManager_abortRequest(xhrId) {
1861 var xhr = this.pendingRequests[xhrId].xhr;
1862 delete this.pendingRequests[xhrId];
1863 xhr.abort();
1864 }
1865 };
1866
1867 return NetworkManager;
1868 })();
1869
1870
1871 var ChunkedStream = (function ChunkedStreamClosure() {
1872 function ChunkedStream(length, chunkSize, manager) {
1873 this.bytes = new Uint8Array(length);
1874 this.start = 0;
1875 this.pos = 0;
1876 this.end = length;
1877 this.chunkSize = chunkSize;
1878 this.loadedChunks = [];
1879 this.numChunksLoaded = 0;
1880 this.numChunks = Math.ceil(length / chunkSize);
1881 this.manager = manager;
1882 this.progressiveDataLength = 0;
1883 this.lastSuccessfulEnsureByteChunk = -1; // a single-entry cache
1884 }
1885
1886 // required methods for a stream. if a particular stream does not
1887 // implement these, an error should be thrown
1888 ChunkedStream.prototype = {
1889
1890 getMissingChunks: function ChunkedStream_getMissingChunks() {
1891 var chunks = [];
1892 for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) {
1893 if (!this.loadedChunks[chunk]) {
1894 chunks.push(chunk);
1895 }
1896 }
1897 return chunks;
1898 },
1899
1900 getBaseStreams: function ChunkedStream_getBaseStreams() {
1901 return [this];
1902 },
1903
1904 allChunksLoaded: function ChunkedStream_allChunksLoaded() {
1905 return this.numChunksLoaded === this.numChunks;
1906 },
1907
1908 onReceiveData: function ChunkedStream_onReceiveData(begin, chunk) {
1909 var end = begin + chunk.byteLength;
1910
1911 assert(begin % this.chunkSize === 0, 'Bad begin offset: ' + begin);
1912 // Using this.length is inaccurate here since this.start can be moved
1913 // See ChunkedStream.moveStart()
1914 var length = this.bytes.length;
1915 assert(end % this.chunkSize === 0 || end === length,
1916 'Bad end offset: ' + end);
1917
1918 this.bytes.set(new Uint8Array(chunk), begin);
1919 var chunkSize = this.chunkSize;
1920 var beginChunk = Math.floor(begin / chunkSize);
1921 var endChunk = Math.floor((end - 1) / chunkSize) + 1;
1922 var curChunk;
1923
1924 for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
1925 if (!this.loadedChunks[curChunk]) {
1926 this.loadedChunks[curChunk] = true;
1927 ++this.numChunksLoaded;
1928 }
1929 }
1930 },
1931
1932 onReceiveProgressiveData:
1933 function ChunkedStream_onReceiveProgressiveData(data) {
1934 var position = this.progressiveDataLength;
1935 var beginChunk = Math.floor(position / this.chunkSize);
1936
1937 this.bytes.set(new Uint8Array(data), position);
1938 position += data.byteLength;
1939 this.progressiveDataLength = position;
1940 var endChunk = position >= this.end ? this.numChunks :
1941 Math.floor(position / this.chunkSize);
1942 var curChunk;
1943 for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
1944 if (!this.loadedChunks[curChunk]) {
1945 this.loadedChunks[curChunk] = true;
1946 ++this.numChunksLoaded;
1947 }
1948 }
1949 },
1950
1951 ensureByte: function ChunkedStream_ensureByte(pos) {
1952 var chunk = Math.floor(pos / this.chunkSize);
1953 if (chunk === this.lastSuccessfulEnsureByteChunk) {
1954 return;
1955 }
1956
1957 if (!this.loadedChunks[chunk]) {
1958 throw new MissingDataException(pos, pos + 1);
1959 }
1960 this.lastSuccessfulEnsureByteChunk = chunk;
1961 },
1962
1963 ensureRange: function ChunkedStream_ensureRange(begin, end) {
1964 if (begin >= end) {
1965 return;
1966 }
1967
1968 if (end <= this.progressiveDataLength) {
1969 return;
1970 }
1971
1972 var chunkSize = this.chunkSize;
1973 var beginChunk = Math.floor(begin / chunkSize);
1974 var endChunk = Math.floor((end - 1) / chunkSize) + 1;
1975 for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
1976 if (!this.loadedChunks[chunk]) {
1977 throw new MissingDataException(begin, end);
1978 }
1979 }
1980 },
1981
1982 nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {
1983 var chunk, n;
1984 for (chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
1985 if (!this.loadedChunks[chunk]) {
1986 return chunk;
1987 }
1988 }
1989 // Wrap around to beginning
1990 for (chunk = 0; chunk < beginChunk; ++chunk) {
1991 if (!this.loadedChunks[chunk]) {
1992 return chunk;
1993 }
1994 }
1995 return null;
1996 },
1997
1998 hasChunk: function ChunkedStream_hasChunk(chunk) {
1999 return !!this.loadedChunks[chunk];
2000 },
2001
2002 get length() {
2003 return this.end - this.start;
2004 },
2005
2006 get isEmpty() {
2007 return this.length === 0;
2008 },
2009
2010 getByte: function ChunkedStream_getByte() {
2011 var pos = this.pos;
2012 if (pos >= this.end) {
2013 return -1;
2014 }
2015 this.ensureByte(pos);
2016 return this.bytes[this.pos++];
2017 },
2018
2019 getUint16: function ChunkedStream_getUint16() {
2020 var b0 = this.getByte();
2021 var b1 = this.getByte();
2022 if (b0 === -1 || b1 === -1) {
2023 return -1;
2024 }
2025 return (b0 << 8) + b1;
2026 },
2027
2028 getInt32: function ChunkedStream_getInt32() {
2029 var b0 = this.getByte();
2030 var b1 = this.getByte();
2031 var b2 = this.getByte();
2032 var b3 = this.getByte();
2033 return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
2034 },
2035
2036 // returns subarray of original buffer
2037 // should only be read
2038 getBytes: function ChunkedStream_getBytes(length) {
2039 var bytes = this.bytes;
2040 var pos = this.pos;
2041 var strEnd = this.end;
2042
2043 if (!length) {
2044 this.ensureRange(pos, strEnd);
2045 return bytes.subarray(pos, strEnd);
2046 }
2047
2048 var end = pos + length;
2049 if (end > strEnd) {
2050 end = strEnd;
2051 }
2052 this.ensureRange(pos, end);
2053
2054 this.pos = end;
2055 return bytes.subarray(pos, end);
2056 },
2057
2058 peekByte: function ChunkedStream_peekByte() {
2059 var peekedByte = this.getByte();
2060 this.pos--;
2061 return peekedByte;
2062 },
2063
2064 peekBytes: function ChunkedStream_peekBytes(length) {
2065 var bytes = this.getBytes(length);
2066 this.pos -= bytes.length;
2067 return bytes;
2068 },
2069
2070 getByteRange: function ChunkedStream_getBytes(begin, end) {
2071 this.ensureRange(begin, end);
2072 return this.bytes.subarray(begin, end);
2073 },
2074
2075 skip: function ChunkedStream_skip(n) {
2076 if (!n) {
2077 n = 1;
2078 }
2079 this.pos += n;
2080 },
2081
2082 reset: function ChunkedStream_reset() {
2083 this.pos = this.start;
2084 },
2085
2086 moveStart: function ChunkedStream_moveStart() {
2087 this.start = this.pos;
2088 },
2089
2090 makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) {
2091 this.ensureRange(start, start + length);
2092
2093 function ChunkedStreamSubstream() {}
2094 ChunkedStreamSubstream.prototype = Object.create(this);
2095 ChunkedStreamSubstream.prototype.getMissingChunks = function() {
2096 var chunkSize = this.chunkSize;
2097 var beginChunk = Math.floor(this.start / chunkSize);
2098 var endChunk = Math.floor((this.end - 1) / chunkSize) + 1;
2099 var missingChunks = [];
2100 for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
2101 if (!this.loadedChunks[chunk]) {
2102 missingChunks.push(chunk);
2103 }
2104 }
2105 return missingChunks;
2106 };
2107 var subStream = new ChunkedStreamSubstream();
2108 subStream.pos = subStream.start = start;
2109 subStream.end = start + length || this.end;
2110 subStream.dict = dict;
2111 return subStream;
2112 },
2113
2114 isStream: true
2115 };
2116
2117 return ChunkedStream;
2118 })();
2119
2120 var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
2121
2122 function ChunkedStreamManager(length, chunkSize, url, args) {
2123 this.stream = new ChunkedStream(length, chunkSize, this);
2124 this.length = length;
2125 this.chunkSize = chunkSize;
2126 this.url = url;
2127 this.disableAutoFetch = args.disableAutoFetch;
2128 var msgHandler = this.msgHandler = args.msgHandler;
2129
2130 if (args.chunkedViewerLoading) {
2131 msgHandler.on('OnDataRange', this.onReceiveData.bind(this));
2132 msgHandler.on('OnDataProgress', this.onProgress.bind(this));
2133 this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
2134 msgHandler.send('RequestDataRange', { begin: begin, end: end });
2135 };
2136 } else {
2137
2138 var getXhr = function getXhr() {
2139 //#if B2G
2140 // return new XMLHttpRequest({ mozSystem: true });
2141 //#else
2142 return new XMLHttpRequest();
2143 //#endif
2144 };
2145 this.networkManager = new NetworkManager(this.url, {
2146 getXhr: getXhr,
2147 httpHeaders: args.httpHeaders,
2148 withCredentials: args.withCredentials
2149 });
2150 this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
2151 this.networkManager.requestRange(begin, end, {
2152 onDone: this.onReceiveData.bind(this),
2153 onProgress: this.onProgress.bind(this)
2154 });
2155 };
2156 }
2157
2158 this.currRequestId = 0;
2159
2160 this.chunksNeededByRequest = {};
2161 this.requestsByChunk = {};
2162 this.callbacksByRequest = {};
2163 this.progressiveDataLength = 0;
2164
2165 this._loadedStreamCapability = createPromiseCapability();
2166
2167 if (args.initialData) {
2168 this.onReceiveData({chunk: args.initialData});
2169 }
2170 }
2171
2172 ChunkedStreamManager.prototype = {
2173 onLoadedStream: function ChunkedStreamManager_getLoadedStream() {
2174 return this._loadedStreamCapability.promise;
2175 },
2176
2177 // Get all the chunks that are not yet loaded and groups them into
2178 // contiguous ranges to load in as few requests as possible
2179 requestAllChunks: function ChunkedStreamManager_requestAllChunks() {
2180 var missingChunks = this.stream.getMissingChunks();
2181 this.requestChunks(missingChunks);
2182 return this._loadedStreamCapability.promise;
2183 },
2184
2185 requestChunks: function ChunkedStreamManager_requestChunks(chunks,
2186 callback) {
2187 var requestId = this.currRequestId++;
2188
2189 var chunksNeeded;
2190 var i, ii;
2191 this.chunksNeededByRequest[requestId] = chunksNeeded = {};
2192 for (i = 0, ii = chunks.length; i < ii; i++) {
2193 if (!this.stream.hasChunk(chunks[i])) {
2194 chunksNeeded[chunks[i]] = true;
2195 }
2196 }
2197
2198 if (isEmptyObj(chunksNeeded)) {
2199 if (callback) {
2200 callback();
2201 }
2202 return;
2203 }
2204
2205 this.callbacksByRequest[requestId] = callback;
2206
2207 var chunksToRequest = [];
2208 for (var chunk in chunksNeeded) {
2209 chunk = chunk | 0;
2210 if (!(chunk in this.requestsByChunk)) {
2211 this.requestsByChunk[chunk] = [];
2212 chunksToRequest.push(chunk);
2213 }
2214 this.requestsByChunk[chunk].push(requestId);
2215 }
2216
2217 if (!chunksToRequest.length) {
2218 return;
2219 }
2220
2221 var groupedChunksToRequest = this.groupChunks(chunksToRequest);
2222
2223 for (i = 0; i < groupedChunksToRequest.length; ++i) {
2224 var groupedChunk = groupedChunksToRequest[i];
2225 var begin = groupedChunk.beginChunk * this.chunkSize;
2226 var end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length);
2227 this.sendRequest(begin, end);
2228 }
2229 },
2230
2231 getStream: function ChunkedStreamManager_getStream() {
2232 return this.stream;
2233 },
2234
2235 // Loads any chunks in the requested range that are not yet loaded
2236 requestRange: function ChunkedStreamManager_requestRange(
2237 begin, end, callback) {
2238
2239 end = Math.min(end, this.length);
2240
2241 var beginChunk = this.getBeginChunk(begin);
2242 var endChunk = this.getEndChunk(end);
2243
2244 var chunks = [];
2245 for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
2246 chunks.push(chunk);
2247 }
2248
2249 this.requestChunks(chunks, callback);
2250 },
2251
2252 requestRanges: function ChunkedStreamManager_requestRanges(ranges,
2253 callback) {
2254 ranges = ranges || [];
2255 var chunksToRequest = [];
2256
2257 for (var i = 0; i < ranges.length; i++) {
2258 var beginChunk = this.getBeginChunk(ranges[i].begin);
2259 var endChunk = this.getEndChunk(ranges[i].end);
2260 for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
2261 if (chunksToRequest.indexOf(chunk) < 0) {
2262 chunksToRequest.push(chunk);
2263 }
2264 }
2265 }
2266
2267 chunksToRequest.sort(function(a, b) { return a - b; });
2268 this.requestChunks(chunksToRequest, callback);
2269 },
2270
2271 // Groups a sorted array of chunks into as few continguous larger
2272 // chunks as possible
2273 groupChunks: function ChunkedStreamManager_groupChunks(chunks) {
2274 var groupedChunks = [];
2275 var beginChunk = -1;
2276 var prevChunk = -1;
2277 for (var i = 0; i < chunks.length; ++i) {
2278 var chunk = chunks[i];
2279
2280 if (beginChunk < 0) {
2281 beginChunk = chunk;
2282 }
2283
2284 if (prevChunk >= 0 && prevChunk + 1 !== chunk) {
2285 groupedChunks.push({ beginChunk: beginChunk,
2286 endChunk: prevChunk + 1 });
2287 beginChunk = chunk;
2288 }
2289 if (i + 1 === chunks.length) {
2290 groupedChunks.push({ beginChunk: beginChunk,
2291 endChunk: chunk + 1 });
2292 }
2293
2294 prevChunk = chunk;
2295 }
2296 return groupedChunks;
2297 },
2298
2299 onProgress: function ChunkedStreamManager_onProgress(args) {
2300 var bytesLoaded = (this.stream.numChunksLoaded * this.chunkSize +
2301 args.loaded);
2302 this.msgHandler.send('DocProgress', {
2303 loaded: bytesLoaded,
2304 total: this.length
2305 });
2306 },
2307
2308 onReceiveData: function ChunkedStreamManager_onReceiveData(args) {
2309 var chunk = args.chunk;
2310 var isProgressive = args.begin === undefined;
2311 var begin = isProgressive ? this.progressiveDataLength : args.begin;
2312 var end = begin + chunk.byteLength;
2313
2314 var beginChunk = Math.floor(begin / this.chunkSize);
2315 var endChunk = end < this.length ? Math.floor(end / this.chunkSize) :
2316 Math.ceil(end / this.chunkSize);
2317
2318 if (isProgressive) {
2319 this.stream.onReceiveProgressiveData(chunk);
2320 this.progressiveDataLength = end;
2321 } else {
2322 this.stream.onReceiveData(begin, chunk);
2323 }
2324
2325 if (this.stream.allChunksLoaded()) {
2326 this._loadedStreamCapability.resolve(this.stream);
2327 }
2328
2329 var loadedRequests = [];
2330 var i, requestId;
2331 for (chunk = beginChunk; chunk < endChunk; ++chunk) {
2332 // The server might return more chunks than requested
2333 var requestIds = this.requestsByChunk[chunk] || [];
2334 delete this.requestsByChunk[chunk];
2335
2336 for (i = 0; i < requestIds.length; ++i) {
2337 requestId = requestIds[i];
2338 var chunksNeeded = this.chunksNeededByRequest[requestId];
2339 if (chunk in chunksNeeded) {
2340 delete chunksNeeded[chunk];
2341 }
2342
2343 if (!isEmptyObj(chunksNeeded)) {
2344 continue;
2345 }
2346
2347 loadedRequests.push(requestId);
2348 }
2349 }
2350
2351 // If there are no pending requests, automatically fetch the next
2352 // unfetched chunk of the PDF
2353 if (!this.disableAutoFetch && isEmptyObj(this.requestsByChunk)) {
2354 var nextEmptyChunk;
2355 if (this.stream.numChunksLoaded === 1) {
2356 // This is a special optimization so that after fetching the first
2357 // chunk, rather than fetching the second chunk, we fetch the last
2358 // chunk.
2359 var lastChunk = this.stream.numChunks - 1;
2360 if (!this.stream.hasChunk(lastChunk)) {
2361 nextEmptyChunk = lastChunk;
2362 }
2363 } else {
2364 nextEmptyChunk = this.stream.nextEmptyChunk(endChunk);
2365 }
2366 if (isInt(nextEmptyChunk)) {
2367 this.requestChunks([nextEmptyChunk]);
2368 }
2369 }
2370
2371 for (i = 0; i < loadedRequests.length; ++i) {
2372 requestId = loadedRequests[i];
2373 var callback = this.callbacksByRequest[requestId];
2374 delete this.callbacksByRequest[requestId];
2375 if (callback) {
2376 callback();
2377 }
2378 }
2379
2380 this.msgHandler.send('DocProgress', {
2381 loaded: this.stream.numChunksLoaded * this.chunkSize,
2382 total: this.length
2383 });
2384 },
2385
2386 onError: function ChunkedStreamManager_onError(err) {
2387 this._loadedStreamCapability.reject(err);
2388 },
2389
2390 getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) {
2391 var chunk = Math.floor(begin / this.chunkSize);
2392 return chunk;
2393 },
2394
2395 getEndChunk: function ChunkedStreamManager_getEndChunk(end) {
2396 if (end % this.chunkSize === 0) {
2397 return end / this.chunkSize;
2398 }
2399
2400 // 0 -> 0
2401 // 1 -> 1
2402 // 99 -> 1
2403 // 100 -> 1
2404 // 101 -> 2
2405 var chunk = Math.floor((end - 1) / this.chunkSize) + 1;
2406 return chunk;
2407 }
2408 };
2409
2410 return ChunkedStreamManager;
2411 })();
2412
2413
2414 // The maximum number of bytes fetched per range request
2415 var RANGE_CHUNK_SIZE = 65536;
2416
2417 // TODO(mack): Make use of PDFJS.Util.inherit() when it becomes available
2418 var BasePdfManager = (function BasePdfManagerClosure() {
2419 function BasePdfManager() {
2420 throw new Error('Cannot initialize BaseManagerManager');
2421 }
2422
2423 BasePdfManager.prototype = {
2424 onLoadedStream: function BasePdfManager_onLoadedStream() {
2425 throw new NotImplementedException();
2426 },
2427
2428 ensureDoc: function BasePdfManager_ensureDoc(prop, args) {
2429 return this.ensure(this.pdfDocument, prop, args);
2430 },
2431
2432 ensureXRef: function BasePdfManager_ensureXRef(prop, args) {
2433 return this.ensure(this.pdfDocument.xref, prop, args);
2434 },
2435
2436 ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) {
2437 return this.ensure(this.pdfDocument.catalog, prop, args);
2438 },
2439
2440 getPage: function BasePdfManager_pagePage(pageIndex) {
2441 return this.pdfDocument.getPage(pageIndex);
2442 },
2443
2444 cleanup: function BasePdfManager_cleanup() {
2445 return this.pdfDocument.cleanup();
2446 },
2447
2448 ensure: function BasePdfManager_ensure(obj, prop, args) {
2449 return new NotImplementedException();
2450 },
2451
2452 requestRange: function BasePdfManager_ensure(begin, end) {
2453 return new NotImplementedException();
2454 },
2455
2456 requestLoadedStream: function BasePdfManager_requestLoadedStream() {
2457 return new NotImplementedException();
2458 },
2459
2460 sendProgressiveData: function BasePdfManager_sendProgressiveData(chunk) {
2461 return new NotImplementedException();
2462 },
2463
2464 updatePassword: function BasePdfManager_updatePassword(password) {
2465 this.pdfDocument.xref.password = this.password = password;
2466 if (this._passwordChangedCapability) {
2467 this._passwordChangedCapability.resolve();
2468 }
2469 },
2470
2471 passwordChanged: function BasePdfManager_passwordChanged() {
2472 this._passwordChangedCapability = createPromiseCapability();
2473 return this._passwordChangedCapability.promise;
2474 },
2475
2476 terminate: function BasePdfManager_terminate() {
2477 return new NotImplementedException();
2478 }
2479 };
2480
2481 return BasePdfManager;
2482 })();
2483
2484 var LocalPdfManager = (function LocalPdfManagerClosure() {
2485 function LocalPdfManager(data, password) {
2486 var stream = new Stream(data);
2487 this.pdfDocument = new PDFDocument(this, stream, password);
2488 this._loadedStreamCapability = createPromiseCapability();
2489 this._loadedStreamCapability.resolve(stream);
2490 }
2491
2492 LocalPdfManager.prototype = Object.create(BasePdfManager.prototype);
2493 LocalPdfManager.prototype.constructor = LocalPdfManager;
2494
2495 LocalPdfManager.prototype.ensure =
2496 function LocalPdfManager_ensure(obj, prop, args) {
2497 return new Promise(function (resolve, reject) {
2498 try {
2499 var value = obj[prop];
2500 var result;
2501 if (typeof value === 'function') {
2502 result = value.apply(obj, args);
2503 } else {
2504 result = value;
2505 }
2506 resolve(result);
2507 } catch (e) {
2508 reject(e);
2509 }
2510 });
2511 };
2512
2513 LocalPdfManager.prototype.requestRange =
2514 function LocalPdfManager_requestRange(begin, end) {
2515 return Promise.resolve();
2516 };
2517
2518 LocalPdfManager.prototype.requestLoadedStream =
2519 function LocalPdfManager_requestLoadedStream() {
2520 };
2521
2522 LocalPdfManager.prototype.onLoadedStream =
2523 function LocalPdfManager_getLoadedStream() {
2524 return this._loadedStreamCapability.promise;
2525 };
2526
2527 LocalPdfManager.prototype.terminate =
2528 function LocalPdfManager_terminate() {
2529 return;
2530 };
2531
2532 return LocalPdfManager;
2533 })();
2534
2535 var NetworkPdfManager = (function NetworkPdfManagerClosure() {
2536 function NetworkPdfManager(args, msgHandler) {
2537
2538 this.msgHandler = msgHandler;
2539
2540 var params = {
2541 msgHandler: msgHandler,
2542 httpHeaders: args.httpHeaders,
2543 withCredentials: args.withCredentials,
2544 chunkedViewerLoading: args.chunkedViewerLoading,
2545 disableAutoFetch: args.disableAutoFetch,
2546 initialData: args.initialData
2547 };
2548 this.streamManager = new ChunkedStreamManager(args.length, RANGE_CHUNK_SIZE,
2549 args.url, params);
2550
2551 this.pdfDocument = new PDFDocument(this, this.streamManager.getStream(),
2552 args.password);
2553 }
2554
2555 NetworkPdfManager.prototype = Object.create(BasePdfManager.prototype);
2556 NetworkPdfManager.prototype.constructor = NetworkPdfManager;
2557
2558 NetworkPdfManager.prototype.ensure =
2559 function NetworkPdfManager_ensure(obj, prop, args) {
2560 var pdfManager = this;
2561
2562 return new Promise(function (resolve, reject) {
2563 function ensureHelper() {
2564 try {
2565 var result;
2566 var value = obj[prop];
2567 if (typeof value === 'function') {
2568 result = value.apply(obj, args);
2569 } else {
2570 result = value;
2571 }
2572 resolve(result);
2573 } catch(e) {
2574 if (!(e instanceof MissingDataException)) {
2575 reject(e);
2576 return;
2577 }
2578 pdfManager.streamManager.requestRange(e.begin, e.end, ensureHelper);
2579 }
2580 }
2581
2582 ensureHelper();
2583 });
2584 };
2585
2586 NetworkPdfManager.prototype.requestRange =
2587 function NetworkPdfManager_requestRange(begin, end) {
2588 return new Promise(function (resolve) {
2589 this.streamManager.requestRange(begin, end, function() {
2590 resolve();
2591 });
2592 }.bind(this));
2593 };
2594
2595 NetworkPdfManager.prototype.requestLoadedStream =
2596 function NetworkPdfManager_requestLoadedStream() {
2597 this.streamManager.requestAllChunks();
2598 };
2599
2600 NetworkPdfManager.prototype.sendProgressiveData =
2601 function NetworkPdfManager_sendProgressiveData(chunk) {
2602 this.streamManager.onReceiveData({ chunk: chunk });
2603 };
2604
2605 NetworkPdfManager.prototype.onLoadedStream =
2606 function NetworkPdfManager_getLoadedStream() {
2607 return this.streamManager.onLoadedStream();
2608 };
2609
2610 NetworkPdfManager.prototype.terminate =
2611 function NetworkPdfManager_terminate() {
2612 this.streamManager.networkManager.abortAllRequests();
2613 };
2614
2615 return NetworkPdfManager;
2616 })();
2617
2618
2619 var Page = (function PageClosure() {
2620
2621 var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
2622
2623 function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache) {
2624 this.pdfManager = pdfManager;
2625 this.pageIndex = pageIndex;
2626 this.pageDict = pageDict;
2627 this.xref = xref;
2628 this.ref = ref;
2629 this.fontCache = fontCache;
2630 this.idCounters = {
2631 obj: 0
2632 };
2633 this.resourcesPromise = null;
2634 }
2635
2636 Page.prototype = {
2637 getPageProp: function Page_getPageProp(key) {
2638 return this.pageDict.get(key);
2639 },
2640
2641 getInheritedPageProp: function Page_inheritPageProp(key) {
2642 var dict = this.pageDict;
2643 var value = dict.get(key);
2644 while (value === undefined) {
2645 dict = dict.get('Parent');
2646 if (!dict) {
2647 break;
2648 }
2649 value = dict.get(key);
2650 }
2651 return value;
2652 },
2653
2654 get content() {
2655 return this.getPageProp('Contents');
2656 },
2657
2658 get resources() {
2659 var value = this.getInheritedPageProp('Resources');
2660 // For robustness: The spec states that a \Resources entry has to be
2661 // present, but can be empty. Some document omit it still. In this case
2662 // return an empty dictionary:
2663 if (value === undefined) {
2664 value = Dict.empty;
2665 }
2666 return shadow(this, 'resources', value);
2667 },
2668
2669 get mediaBox() {
2670 var obj = this.getInheritedPageProp('MediaBox');
2671 // Reset invalid media box to letter size.
2672 if (!isArray(obj) || obj.length !== 4) {
2673 obj = LETTER_SIZE_MEDIABOX;
2674 }
2675 return shadow(this, 'mediaBox', obj);
2676 },
2677
2678 get view() {
2679 var mediaBox = this.mediaBox;
2680 var cropBox = this.getInheritedPageProp('CropBox');
2681 if (!isArray(cropBox) || cropBox.length !== 4) {
2682 return shadow(this, 'view', mediaBox);
2683 }
2684
2685 // From the spec, 6th ed., p.963:
2686 // "The crop, bleed, trim, and art boxes should not ordinarily
2687 // extend beyond the boundaries of the media box. If they do, they are
2688 // effectively reduced to their intersection with the media box."
2689 cropBox = Util.intersect(cropBox, mediaBox);
2690 if (!cropBox) {
2691 return shadow(this, 'view', mediaBox);
2692 }
2693 return shadow(this, 'view', cropBox);
2694 },
2695
2696 get annotationRefs() {
2697 return shadow(this, 'annotationRefs',
2698 this.getInheritedPageProp('Annots'));
2699 },
2700
2701 get rotate() {
2702 var rotate = this.getInheritedPageProp('Rotate') || 0;
2703 // Normalize rotation so it's a multiple of 90 and between 0 and 270
2704 if (rotate % 90 !== 0) {
2705 rotate = 0;
2706 } else if (rotate >= 360) {
2707 rotate = rotate % 360;
2708 } else if (rotate < 0) {
2709 // The spec doesn't cover negatives, assume its counterclockwise
2710 // rotation. The following is the other implementation of modulo.
2711 rotate = ((rotate % 360) + 360) % 360;
2712 }
2713 return shadow(this, 'rotate', rotate);
2714 },
2715
2716 getContentStream: function Page_getContentStream() {
2717 var content = this.content;
2718 var stream;
2719 if (isArray(content)) {
2720 // fetching items
2721 var xref = this.xref;
2722 var i, n = content.length;
2723 var streams = [];
2724 for (i = 0; i < n; ++i) {
2725 streams.push(xref.fetchIfRef(content[i]));
2726 }
2727 stream = new StreamsSequenceStream(streams);
2728 } else if (isStream(content)) {
2729 stream = content;
2730 } else {
2731 // replacing non-existent page content with empty one
2732 stream = new NullStream();
2733 }
2734 return stream;
2735 },
2736
2737 loadResources: function Page_loadResources(keys) {
2738 if (!this.resourcesPromise) {
2739 // TODO: add async getInheritedPageProp and remove this.
2740 this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
2741 }
2742 return this.resourcesPromise.then(function resourceSuccess() {
2743 var objectLoader = new ObjectLoader(this.resources.map,
2744 keys,
2745 this.xref);
2746 return objectLoader.load();
2747 }.bind(this));
2748 },
2749
2750 getOperatorList: function Page_getOperatorList(handler, intent) {
2751 var self = this;
2752
2753 var pdfManager = this.pdfManager;
2754 var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
2755 []);
2756 var resourcesPromise = this.loadResources([
2757 'ExtGState',
2758 'ColorSpace',
2759 'Pattern',
2760 'Shading',
2761 'XObject',
2762 'Font'
2763 // ProcSet
2764 // Properties
2765 ]);
2766
2767 var partialEvaluator = new PartialEvaluator(pdfManager, this.xref,
2768 handler, this.pageIndex,
2769 'p' + this.pageIndex + '_',
2770 this.idCounters,
2771 this.fontCache);
2772
2773 var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
2774 var pageListPromise = dataPromises.then(function(data) {
2775 var contentStream = data[0];
2776 var opList = new OperatorList(intent, handler, self.pageIndex);
2777
2778 handler.send('StartRenderPage', {
2779 transparency: partialEvaluator.hasBlendModes(self.resources),
2780 pageIndex: self.pageIndex,
2781 intent: intent
2782 });
2783 return partialEvaluator.getOperatorList(contentStream, self.resources,
2784 opList).then(function () {
2785 return opList;
2786 });
2787 });
2788
2789 var annotationsPromise = pdfManager.ensure(this, 'annotations');
2790 return Promise.all([pageListPromise, annotationsPromise]).then(
2791 function(datas) {
2792 var pageOpList = datas[0];
2793 var annotations = datas[1];
2794
2795 if (annotations.length === 0) {
2796 pageOpList.flush(true);
2797 return pageOpList;
2798 }
2799
2800 var annotationsReadyPromise = Annotation.appendToOperatorList(
2801 annotations, pageOpList, pdfManager, partialEvaluator, intent);
2802 return annotationsReadyPromise.then(function () {
2803 pageOpList.flush(true);
2804 return pageOpList;
2805 });
2806 });
2807 },
2808
2809 extractTextContent: function Page_extractTextContent() {
2810 var handler = {
2811 on: function nullHandlerOn() {},
2812 send: function nullHandlerSend() {}
2813 };
2814
2815 var self = this;
2816
2817 var pdfManager = this.pdfManager;
2818 var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
2819 []);
2820
2821 var resourcesPromise = this.loadResources([
2822 'ExtGState',
2823 'XObject',
2824 'Font'
2825 ]);
2826
2827 var dataPromises = Promise.all([contentStreamPromise,
2828 resourcesPromise]);
2829 return dataPromises.then(function(data) {
2830 var contentStream = data[0];
2831 var partialEvaluator = new PartialEvaluator(pdfManager, self.xref,
2832 handler, self.pageIndex,
2833 'p' + self.pageIndex + '_',
2834 self.idCounters,
2835 self.fontCache);
2836
2837 return partialEvaluator.getTextContent(contentStream,
2838 self.resources);
2839 });
2840 },
2841
2842 getAnnotationsData: function Page_getAnnotationsData() {
2843 var annotations = this.annotations;
2844 var annotationsData = [];
2845 for (var i = 0, n = annotations.length; i < n; ++i) {
2846 annotationsData.push(annotations[i].getData());
2847 }
2848 return annotationsData;
2849 },
2850
2851 get annotations() {
2852 var annotations = [];
2853 var annotationRefs = (this.annotationRefs || []);
2854 for (var i = 0, n = annotationRefs.length; i < n; ++i) {
2855 var annotationRef = annotationRefs[i];
2856 var annotation = Annotation.fromRef(this.xref, annotationRef);
2857 if (annotation) {
2858 annotations.push(annotation);
2859 }
2860 }
2861 return shadow(this, 'annotations', annotations);
2862 }
2863 };
2864
2865 return Page;
2866 })();
2867
2868 /**
2869 * The `PDFDocument` holds all the data of the PDF file. Compared to the
2870 * `PDFDoc`, this one doesn't have any job management code.
2871 * Right now there exists one PDFDocument on the main thread + one object
2872 * for each worker. If there is no worker support enabled, there are two
2873 * `PDFDocument` objects on the main thread created.
2874 */
2875 var PDFDocument = (function PDFDocumentClosure() {
2876 var FINGERPRINT_FIRST_BYTES = 1024;
2877 var EMPTY_FINGERPRINT = '\x00\x00\x00\x00\x00\x00\x00' +
2878 '\x00\x00\x00\x00\x00\x00\x00\x00\x00';
2879
2880 function PDFDocument(pdfManager, arg, password) {
2881 if (isStream(arg)) {
2882 init.call(this, pdfManager, arg, password);
2883 } else if (isArrayBuffer(arg)) {
2884 init.call(this, pdfManager, new Stream(arg), password);
2885 } else {
2886 error('PDFDocument: Unknown argument type');
2887 }
2888 }
2889
2890 function init(pdfManager, stream, password) {
2891 assert(stream.length > 0, 'stream must have data');
2892 this.pdfManager = pdfManager;
2893 this.stream = stream;
2894 var xref = new XRef(this.stream, password, pdfManager);
2895 this.xref = xref;
2896 }
2897
2898 function find(stream, needle, limit, backwards) {
2899 var pos = stream.pos;
2900 var end = stream.end;
2901 var strBuf = [];
2902 if (pos + limit > end) {
2903 limit = end - pos;
2904 }
2905 for (var n = 0; n < limit; ++n) {
2906 strBuf.push(String.fromCharCode(stream.getByte()));
2907 }
2908 var str = strBuf.join('');
2909 stream.pos = pos;
2910 var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);
2911 if (index === -1) {
2912 return false; /* not found */
2913 }
2914 stream.pos += index;
2915 return true; /* found */
2916 }
2917
2918 var DocumentInfoValidators = {
2919 get entries() {
2920 // Lazily build this since all the validation functions below are not
2921 // defined until after this file loads.
2922 return shadow(this, 'entries', {
2923 Title: isString,
2924 Author: isString,
2925 Subject: isString,
2926 Keywords: isString,
2927 Creator: isString,
2928 Producer: isString,
2929 CreationDate: isString,
2930 ModDate: isString,
2931 Trapped: isName
2932 });
2933 }
2934 };
2935
2936 PDFDocument.prototype = {
2937 parse: function PDFDocument_parse(recoveryMode) {
2938 this.setup(recoveryMode);
2939 try {
2940 // checking if AcroForm is present
2941 this.acroForm = this.catalog.catDict.get('AcroForm');
2942 if (this.acroForm) {
2943 this.xfa = this.acroForm.get('XFA');
2944 var fields = this.acroForm.get('Fields');
2945 if ((!fields || !isArray(fields) || fields.length === 0) &&
2946 !this.xfa) {
2947 // no fields and no XFA -- not a form (?)
2948 this.acroForm = null;
2949 }
2950 }
2951 } catch (ex) {
2952 info('Something wrong with AcroForm entry');
2953 this.acroForm = null;
2954 }
2955 },
2956
2957 get linearization() {
2958 var linearization = null;
2959 if (this.stream.length) {
2960 try {
2961 linearization = Linearization.create(this.stream);
2962 } catch (err) {
2963 if (err instanceof MissingDataException) {
2964 throw err;
2965 }
2966 info(err);
2967 }
2968 }
2969 // shadow the prototype getter with a data property
2970 return shadow(this, 'linearization', linearization);
2971 },
2972 get startXRef() {
2973 var stream = this.stream;
2974 var startXRef = 0;
2975 var linearization = this.linearization;
2976 if (linearization) {
2977 // Find end of first obj.
2978 stream.reset();
2979 if (find(stream, 'endobj', 1024)) {
2980 startXRef = stream.pos + 6;
2981 }
2982 } else {
2983 // Find startxref by jumping backward from the end of the file.
2984 var step = 1024;
2985 var found = false, pos = stream.end;
2986 while (!found && pos > 0) {
2987 pos -= step - 'startxref'.length;
2988 if (pos < 0) {
2989 pos = 0;
2990 }
2991 stream.pos = pos;
2992 found = find(stream, 'startxref', step, true);
2993 }
2994 if (found) {
2995 stream.skip(9);
2996 var ch;
2997 do {
2998 ch = stream.getByte();
2999 } while (Lexer.isSpace(ch));
3000 var str = '';
3001 while (ch >= 0x20 && ch <= 0x39) { // < '9'
3002 str += String.fromCharCode(ch);
3003 ch = stream.getByte();
3004 }
3005 startXRef = parseInt(str, 10);
3006 if (isNaN(startXRef)) {
3007 startXRef = 0;
3008 }
3009 }
3010 }
3011 // shadow the prototype getter with a data property
3012 return shadow(this, 'startXRef', startXRef);
3013 },
3014 get mainXRefEntriesOffset() {
3015 var mainXRefEntriesOffset = 0;
3016 var linearization = this.linearization;
3017 if (linearization) {
3018 mainXRefEntriesOffset = linearization.mainXRefEntriesOffset;
3019 }
3020 // shadow the prototype getter with a data property
3021 return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset);
3022 },
3023 // Find the header, remove leading garbage and setup the stream
3024 // starting from the header.
3025 checkHeader: function PDFDocument_checkHeader() {
3026 var stream = this.stream;
3027 stream.reset();
3028 if (find(stream, '%PDF-', 1024)) {
3029 // Found the header, trim off any garbage before it.
3030 stream.moveStart();
3031 // Reading file format version
3032 var MAX_VERSION_LENGTH = 12;
3033 var version = '', ch;
3034 while ((ch = stream.getByte()) > 0x20) { // SPACE
3035 if (version.length >= MAX_VERSION_LENGTH) {
3036 break;
3037 }
3038 version += String.fromCharCode(ch);
3039 }
3040 // removing "%PDF-"-prefix
3041 this.pdfFormatVersion = version.substring(5);
3042 return;
3043 }
3044 // May not be a PDF file, continue anyway.
3045 },
3046 parseStartXRef: function PDFDocument_parseStartXRef() {
3047 var startXRef = this.startXRef;
3048 this.xref.setStartXRef(startXRef);
3049 },
3050 setup: function PDFDocument_setup(recoveryMode) {
3051 this.xref.parse(recoveryMode);
3052 this.catalog = new Catalog(this.pdfManager, this.xref);
3053 },
3054 get numPages() {
3055 var linearization = this.linearization;
3056 var num = linearization ? linearization.numPages : this.catalog.numPages;
3057 // shadow the prototype getter
3058 return shadow(this, 'numPages', num);
3059 },
3060 get documentInfo() {
3061 var docInfo = {
3062 PDFFormatVersion: this.pdfFormatVersion,
3063 IsAcroFormPresent: !!this.acroForm,
3064 IsXFAPresent: !!this.xfa
3065 };
3066 var infoDict;
3067 try {
3068 infoDict = this.xref.trailer.get('Info');
3069 } catch (err) {
3070 info('The document information dictionary is invalid.');
3071 }
3072 if (infoDict) {
3073 var validEntries = DocumentInfoValidators.entries;
3074 // Only fill the document info with valid entries from the spec.
3075 for (var key in validEntries) {
3076 if (infoDict.has(key)) {
3077 var value = infoDict.get(key);
3078 // Make sure the value conforms to the spec.
3079 if (validEntries[key](value)) {
3080 docInfo[key] = (typeof value !== 'string' ?
3081 value : stringToPDFString(value));
3082 } else {
3083 info('Bad value in document info for "' + key + '"');
3084 }
3085 }
3086 }
3087 }
3088 return shadow(this, 'documentInfo', docInfo);
3089 },
3090 get fingerprint() {
3091 var xref = this.xref, idArray, hash, fileID = '';
3092
3093 if (xref.trailer.has('ID')) {
3094 idArray = xref.trailer.get('ID');
3095 }
3096 if (idArray && isArray(idArray) && idArray[0] !== EMPTY_FINGERPRINT) {
3097 hash = stringToBytes(idArray[0]);
3098 } else {
3099 if (this.stream.ensureRange) {
3100 this.stream.ensureRange(0,
3101 Math.min(FINGERPRINT_FIRST_BYTES, this.stream.end));
3102 }
3103 hash = calculateMD5(this.stream.bytes.subarray(0,
3104 FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES);
3105 }
3106
3107 for (var i = 0, n = hash.length; i < n; i++) {
3108 var hex = hash[i].toString(16);
3109 fileID += hex.length === 1 ? '0' + hex : hex;
3110 }
3111
3112 return shadow(this, 'fingerprint', fileID);
3113 },
3114
3115 getPage: function PDFDocument_getPage(pageIndex) {
3116 return this.catalog.getPage(pageIndex);
3117 },
3118
3119 cleanup: function PDFDocument_cleanup() {
3120 return this.catalog.cleanup();
3121 }
3122 };
3123
3124 return PDFDocument;
3125 })();
3126
3127
3128 var Name = (function NameClosure() {
3129 function Name(name) {
3130 this.name = name;
3131 }
3132
3133 Name.prototype = {};
3134
3135 var nameCache = {};
3136
3137 Name.get = function Name_get(name) {
3138 var nameValue = nameCache[name];
3139 return (nameValue ? nameValue : (nameCache[name] = new Name(name)));
3140 };
3141
3142 return Name;
3143 })();
3144
3145 var Cmd = (function CmdClosure() {
3146 function Cmd(cmd) {
3147 this.cmd = cmd;
3148 }
3149
3150 Cmd.prototype = {};
3151
3152 var cmdCache = {};
3153
3154 Cmd.get = function Cmd_get(cmd) {
3155 var cmdValue = cmdCache[cmd];
3156 return (cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd)));
3157 };
3158
3159 return Cmd;
3160 })();
3161
3162 var Dict = (function DictClosure() {
3163 var nonSerializable = function nonSerializableClosure() {
3164 return nonSerializable; // creating closure on some variable
3165 };
3166
3167 var GETALL_DICTIONARY_TYPES_WHITELIST = {
3168 'Background': true,
3169 'ExtGState': true,
3170 'Halftone': true,
3171 'Layout': true,
3172 'Mask': true,
3173 'Pagination': true,
3174 'Printing': true
3175 };
3176
3177 function isRecursionAllowedFor(dict) {
3178 if (!isName(dict.Type)) {
3179 return true;
3180 }
3181 var dictType = dict.Type.name;
3182 return GETALL_DICTIONARY_TYPES_WHITELIST[dictType] === true;
3183 }
3184
3185 // xref is optional
3186 function Dict(xref) {
3187 // Map should only be used internally, use functions below to access.
3188 this.map = Object.create(null);
3189 this.xref = xref;
3190 this.objId = null;
3191 this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict
3192 }
3193
3194 Dict.prototype = {
3195 assignXref: function Dict_assignXref(newXref) {
3196 this.xref = newXref;
3197 },
3198
3199 // automatically dereferences Ref objects
3200 get: function Dict_get(key1, key2, key3) {
3201 var value;
3202 var xref = this.xref;
3203 if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map ||
3204 typeof key2 === 'undefined') {
3205 return xref ? xref.fetchIfRef(value) : value;
3206 }
3207 if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map ||
3208 typeof key3 === 'undefined') {
3209 return xref ? xref.fetchIfRef(value) : value;
3210 }
3211 value = this.map[key3] || null;
3212 return xref ? xref.fetchIfRef(value) : value;
3213 },
3214
3215 // Same as get(), but returns a promise and uses fetchIfRefAsync().
3216 getAsync: function Dict_getAsync(key1, key2, key3) {
3217 var value;
3218 var xref = this.xref;
3219 if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map ||
3220 typeof key2 === 'undefined') {
3221 if (xref) {
3222 return xref.fetchIfRefAsync(value);
3223 }
3224 return Promise.resolve(value);
3225 }
3226 if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map ||
3227 typeof key3 === 'undefined') {
3228 if (xref) {
3229 return xref.fetchIfRefAsync(value);
3230 }
3231 return Promise.resolve(value);
3232 }
3233 value = this.map[key3] || null;
3234 if (xref) {
3235 return xref.fetchIfRefAsync(value);
3236 }
3237 return Promise.resolve(value);
3238 },
3239
3240 // no dereferencing
3241 getRaw: function Dict_getRaw(key) {
3242 return this.map[key];
3243 },
3244
3245 // creates new map and dereferences all Refs
3246 getAll: function Dict_getAll() {
3247 var all = Object.create(null);
3248 var queue = null;
3249 var key, obj;
3250 for (key in this.map) {
3251 obj = this.get(key);
3252 if (obj instanceof Dict) {
3253 if (isRecursionAllowedFor(obj)) {
3254 (queue || (queue = [])).push({target: all, key: key, obj: obj});
3255 } else {
3256 all[key] = this.getRaw(key);
3257 }
3258 } else {
3259 all[key] = obj;
3260 }
3261 }
3262 if (!queue) {
3263 return all;
3264 }
3265
3266 // trying to take cyclic references into the account
3267 var processed = Object.create(null);
3268 while (queue.length > 0) {
3269 var item = queue.shift();
3270 var itemObj = item.obj;
3271 var objId = itemObj.objId;
3272 if (objId && objId in processed) {
3273 item.target[item.key] = processed[objId];
3274 continue;
3275 }
3276 var dereferenced = Object.create(null);
3277 for (key in itemObj.map) {
3278 obj = itemObj.get(key);
3279 if (obj instanceof Dict) {
3280 if (isRecursionAllowedFor(obj)) {
3281 queue.push({target: dereferenced, key: key, obj: obj});
3282 } else {
3283 dereferenced[key] = itemObj.getRaw(key);
3284 }
3285 } else {
3286 dereferenced[key] = obj;
3287 }
3288 }
3289 if (objId) {
3290 processed[objId] = dereferenced;
3291 }
3292 item.target[item.key] = dereferenced;
3293 }
3294 return all;
3295 },
3296
3297 getKeys: function Dict_getKeys() {
3298 return Object.keys(this.map);
3299 },
3300
3301 set: function Dict_set(key, value) {
3302 this.map[key] = value;
3303 },
3304
3305 has: function Dict_has(key) {
3306 return key in this.map;
3307 },
3308
3309 forEach: function Dict_forEach(callback) {
3310 for (var key in this.map) {
3311 callback(key, this.get(key));
3312 }
3313 }
3314 };
3315
3316 Dict.empty = new Dict(null);
3317
3318 return Dict;
3319 })();
3320
3321 var Ref = (function RefClosure() {
3322 function Ref(num, gen) {
3323 this.num = num;
3324 this.gen = gen;
3325 }
3326
3327 Ref.prototype = {
3328 toString: function Ref_toString() {
3329 // This function is hot, so we make the string as compact as possible.
3330 // |this.gen| is almost always zero, so we treat that case specially.
3331 var str = this.num + 'R';
3332 if (this.gen !== 0) {
3333 str += this.gen;
3334 }
3335 return str;
3336 }
3337 };
3338
3339 return Ref;
3340 })();
3341
3342 // The reference is identified by number and generation.
3343 // This structure stores only one instance of the reference.
3344 var RefSet = (function RefSetClosure() {
3345 function RefSet() {
3346 this.dict = {};
3347 }
3348
3349 RefSet.prototype = {
3350 has: function RefSet_has(ref) {
3351 return ref.toString() in this.dict;
3352 },
3353
3354 put: function RefSet_put(ref) {
3355 this.dict[ref.toString()] = true;
3356 },
3357
3358 remove: function RefSet_remove(ref) {
3359 delete this.dict[ref.toString()];
3360 }
3361 };
3362
3363 return RefSet;
3364 })();
3365
3366 var RefSetCache = (function RefSetCacheClosure() {
3367 function RefSetCache() {
3368 this.dict = Object.create(null);
3369 }
3370
3371 RefSetCache.prototype = {
3372 get: function RefSetCache_get(ref) {
3373 return this.dict[ref.toString()];
3374 },
3375
3376 has: function RefSetCache_has(ref) {
3377 return ref.toString() in this.dict;
3378 },
3379
3380 put: function RefSetCache_put(ref, obj) {
3381 this.dict[ref.toString()] = obj;
3382 },
3383
3384 putAlias: function RefSetCache_putAlias(ref, aliasRef) {
3385 this.dict[ref.toString()] = this.get(aliasRef);
3386 },
3387
3388 forEach: function RefSetCache_forEach(fn, thisArg) {
3389 for (var i in this.dict) {
3390 fn.call(thisArg, this.dict[i]);
3391 }
3392 },
3393
3394 clear: function RefSetCache_clear() {
3395 this.dict = Object.create(null);
3396 }
3397 };
3398
3399 return RefSetCache;
3400 })();
3401
3402 var Catalog = (function CatalogClosure() {
3403 function Catalog(pdfManager, xref) {
3404 this.pdfManager = pdfManager;
3405 this.xref = xref;
3406 this.catDict = xref.getCatalogObj();
3407 this.fontCache = new RefSetCache();
3408 assert(isDict(this.catDict),
3409 'catalog object is not a dictionary');
3410
3411 this.pagePromises = [];
3412 }
3413
3414 Catalog.prototype = {
3415 get metadata() {
3416 var streamRef = this.catDict.getRaw('Metadata');
3417 if (!isRef(streamRef)) {
3418 return shadow(this, 'metadata', null);
3419 }
3420
3421 var encryptMetadata = (!this.xref.encrypt ? false :
3422 this.xref.encrypt.encryptMetadata);
3423
3424 var stream = this.xref.fetch(streamRef, !encryptMetadata);
3425 var metadata;
3426 if (stream && isDict(stream.dict)) {
3427 var type = stream.dict.get('Type');
3428 var subtype = stream.dict.get('Subtype');
3429
3430 if (isName(type) && isName(subtype) &&
3431 type.name === 'Metadata' && subtype.name === 'XML') {
3432 // XXX: This should examine the charset the XML document defines,
3433 // however since there are currently no real means to decode
3434 // arbitrary charsets, let's just hope that the author of the PDF
3435 // was reasonable enough to stick with the XML default charset,
3436 // which is UTF-8.
3437 try {
3438 metadata = stringToUTF8String(bytesToString(stream.getBytes()));
3439 } catch (e) {
3440 info('Skipping invalid metadata.');
3441 }
3442 }
3443 }
3444
3445 return shadow(this, 'metadata', metadata);
3446 },
3447 get toplevelPagesDict() {
3448 var pagesObj = this.catDict.get('Pages');
3449 assert(isDict(pagesObj), 'invalid top-level pages dictionary');
3450 // shadow the prototype getter
3451 return shadow(this, 'toplevelPagesDict', pagesObj);
3452 },
3453 get documentOutline() {
3454 var obj = null;
3455 try {
3456 obj = this.readDocumentOutline();
3457 } catch (ex) {
3458 if (ex instanceof MissingDataException) {
3459 throw ex;
3460 }
3461 warn('Unable to read document outline');
3462 }
3463 return shadow(this, 'documentOutline', obj);
3464 },
3465 readDocumentOutline: function Catalog_readDocumentOutline() {
3466 var xref = this.xref;
3467 var obj = this.catDict.get('Outlines');
3468 var root = { items: [] };
3469 if (isDict(obj)) {
3470 obj = obj.getRaw('First');
3471 var processed = new RefSet();
3472 if (isRef(obj)) {
3473 var queue = [{obj: obj, parent: root}];
3474 // to avoid recursion keeping track of the items
3475 // in the processed dictionary
3476 processed.put(obj);
3477 while (queue.length > 0) {
3478 var i = queue.shift();
3479 var outlineDict = xref.fetchIfRef(i.obj);
3480 if (outlineDict === null) {
3481 continue;
3482 }
3483 if (!outlineDict.has('Title')) {
3484 error('Invalid outline item');
3485 }
3486 var dest = outlineDict.get('A');
3487 if (dest) {
3488 dest = dest.get('D');
3489 } else if (outlineDict.has('Dest')) {
3490 dest = outlineDict.getRaw('Dest');
3491 if (isName(dest)) {
3492 dest = dest.name;
3493 }
3494 }
3495 var title = outlineDict.get('Title');
3496 var outlineItem = {
3497 dest: dest,
3498 title: stringToPDFString(title),
3499 color: outlineDict.get('C') || [0, 0, 0],
3500 count: outlineDict.get('Count'),
3501 bold: !!(outlineDict.get('F') & 2),
3502 italic: !!(outlineDict.get('F') & 1),
3503 items: []
3504 };
3505 i.parent.items.push(outlineItem);
3506 obj = outlineDict.getRaw('First');
3507 if (isRef(obj) && !processed.has(obj)) {
3508 queue.push({obj: obj, parent: outlineItem});
3509 processed.put(obj);
3510 }
3511 obj = outlineDict.getRaw('Next');
3512 if (isRef(obj) && !processed.has(obj)) {
3513 queue.push({obj: obj, parent: i.parent});
3514 processed.put(obj);
3515 }
3516 }
3517 }
3518 }
3519 return (root.items.length > 0 ? root.items : null);
3520 },
3521 get numPages() {
3522 var obj = this.toplevelPagesDict.get('Count');
3523 assert(
3524 isInt(obj),
3525 'page count in top level pages object is not an integer'
3526 );
3527 // shadow the prototype getter
3528 return shadow(this, 'num', obj);
3529 },
3530 get destinations() {
3531 function fetchDestination(dest) {
3532 return isDict(dest) ? dest.get('D') : dest;
3533 }
3534
3535 var xref = this.xref;
3536 var dests = {}, nameTreeRef, nameDictionaryRef;
3537 var obj = this.catDict.get('Names');
3538 if (obj && obj.has('Dests')) {
3539 nameTreeRef = obj.getRaw('Dests');
3540 } else if (this.catDict.has('Dests')) {
3541 nameDictionaryRef = this.catDict.get('Dests');
3542 }
3543
3544 if (nameDictionaryRef) {
3545 // reading simple destination dictionary
3546 obj = nameDictionaryRef;
3547 obj.forEach(function catalogForEach(key, value) {
3548 if (!value) {
3549 return;
3550 }
3551 dests[key] = fetchDestination(value);
3552 });
3553 }
3554 if (nameTreeRef) {
3555 var nameTree = new NameTree(nameTreeRef, xref);
3556 var names = nameTree.getAll();
3557 for (var name in names) {
3558 if (!names.hasOwnProperty(name)) {
3559 continue;
3560 }
3561 dests[name] = fetchDestination(names[name]);
3562 }
3563 }
3564 return shadow(this, 'destinations', dests);
3565 },
3566 getDestination: function Catalog_getDestination(destinationId) {
3567 function fetchDestination(dest) {
3568 return isDict(dest) ? dest.get('D') : dest;
3569 }
3570
3571 var xref = this.xref;
3572 var dest, nameTreeRef, nameDictionaryRef;
3573 var obj = this.catDict.get('Names');
3574 if (obj && obj.has('Dests')) {
3575 nameTreeRef = obj.getRaw('Dests');
3576 } else if (this.catDict.has('Dests')) {
3577 nameDictionaryRef = this.catDict.get('Dests');
3578 }
3579
3580 if (nameDictionaryRef) {
3581 // reading simple destination dictionary
3582 obj = nameDictionaryRef;
3583 obj.forEach(function catalogForEach(key, value) {
3584 if (!value) {
3585 return;
3586 }
3587 if (key === destinationId) {
3588 dest = fetchDestination(value);
3589 }
3590 });
3591 }
3592 if (nameTreeRef) {
3593 var nameTree = new NameTree(nameTreeRef, xref);
3594 dest = fetchDestination(nameTree.get(destinationId));
3595 }
3596 return dest;
3597 },
3598 get attachments() {
3599 var xref = this.xref;
3600 var attachments = null, nameTreeRef;
3601 var obj = this.catDict.get('Names');
3602 if (obj) {
3603 nameTreeRef = obj.getRaw('EmbeddedFiles');
3604 }
3605
3606 if (nameTreeRef) {
3607 var nameTree = new NameTree(nameTreeRef, xref);
3608 var names = nameTree.getAll();
3609 for (var name in names) {
3610 if (!names.hasOwnProperty(name)) {
3611 continue;
3612 }
3613 var fs = new FileSpec(names[name], xref);
3614 if (!attachments) {
3615 attachments = {};
3616 }
3617 attachments[stringToPDFString(name)] = fs.serializable;
3618 }
3619 }
3620 return shadow(this, 'attachments', attachments);
3621 },
3622 get javaScript() {
3623 var xref = this.xref;
3624 var obj = this.catDict.get('Names');
3625
3626 var javaScript = [];
3627 if (obj && obj.has('JavaScript')) {
3628 var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
3629 var names = nameTree.getAll();
3630 for (var name in names) {
3631 if (!names.hasOwnProperty(name)) {
3632 continue;
3633 }
3634 // We don't really use the JavaScript right now. This code is
3635 // defensive so we don't cause errors on document load.
3636 var jsDict = names[name];
3637 if (!isDict(jsDict)) {
3638 continue;
3639 }
3640 var type = jsDict.get('S');
3641 if (!isName(type) || type.name !== 'JavaScript') {
3642 continue;
3643 }
3644 var js = jsDict.get('JS');
3645 if (!isString(js) && !isStream(js)) {
3646 continue;
3647 }
3648 if (isStream(js)) {
3649 js = bytesToString(js.getBytes());
3650 }
3651 javaScript.push(stringToPDFString(js));
3652 }
3653 }
3654
3655 // Append OpenAction actions to javaScript array
3656 var openactionDict = this.catDict.get('OpenAction');
3657 if (isDict(openactionDict)) {
3658 var objType = openactionDict.get('Type');
3659 var actionType = openactionDict.get('S');
3660 var action = openactionDict.get('N');
3661 var isPrintAction = (isName(objType) && objType.name === 'Action' &&
3662 isName(actionType) && actionType.name === 'Named' &&
3663 isName(action) && action.name === 'Print');
3664
3665 if (isPrintAction) {
3666 javaScript.push('print(true);');
3667 }
3668 }
3669
3670 return shadow(this, 'javaScript', javaScript);
3671 },
3672
3673 cleanup: function Catalog_cleanup() {
3674 var promises = [];
3675 this.fontCache.forEach(function (promise) {
3676 promises.push(promise);
3677 });
3678 return Promise.all(promises).then(function (translatedFonts) {
3679 for (var i = 0, ii = translatedFonts.length; i < ii; i++) {
3680 var font = translatedFonts[i].dict;
3681 delete font.translated;
3682 }
3683 this.fontCache.clear();
3684 }.bind(this));
3685 },
3686
3687 getPage: function Catalog_getPage(pageIndex) {
3688 if (!(pageIndex in this.pagePromises)) {
3689 this.pagePromises[pageIndex] = this.getPageDict(pageIndex).then(
3690 function (a) {
3691 var dict = a[0];
3692 var ref = a[1];
3693 return new Page(this.pdfManager, this.xref, pageIndex, dict, ref,
3694 this.fontCache);
3695 }.bind(this)
3696 );
3697 }
3698 return this.pagePromises[pageIndex];
3699 },
3700
3701 getPageDict: function Catalog_getPageDict(pageIndex) {
3702 var capability = createPromiseCapability();
3703 var nodesToVisit = [this.catDict.getRaw('Pages')];
3704 var currentPageIndex = 0;
3705 var xref = this.xref;
3706 var checkAllKids = false;
3707
3708 function next() {
3709 while (nodesToVisit.length) {
3710 var currentNode = nodesToVisit.pop();
3711
3712 if (isRef(currentNode)) {
3713 xref.fetchAsync(currentNode).then(function (obj) {
3714 if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) {
3715 if (pageIndex === currentPageIndex) {
3716 capability.resolve([obj, currentNode]);
3717 } else {
3718 currentPageIndex++;
3719 next();
3720 }
3721 return;
3722 }
3723 nodesToVisit.push(obj);
3724 next();
3725 }, capability.reject);
3726 return;
3727 }
3728
3729 // Must be a child page dictionary.
3730 assert(
3731 isDict(currentNode),
3732 'page dictionary kid reference points to wrong type of object'
3733 );
3734 var count = currentNode.get('Count');
3735 // If the current node doesn't have any children, avoid getting stuck
3736 // in an empty node further down in the tree (see issue5644.pdf).
3737 if (count === 0) {
3738 checkAllKids = true;
3739 }
3740 // Skip nodes where the page can't be.
3741 if (currentPageIndex + count <= pageIndex) {
3742 currentPageIndex += count;
3743 continue;
3744 }
3745
3746 var kids = currentNode.get('Kids');
3747 assert(isArray(kids), 'page dictionary kids object is not an array');
3748 if (!checkAllKids && count === kids.length) {
3749 // Nodes that don't have the page have been skipped and this is the
3750 // bottom of the tree which means the page requested must be a
3751 // descendant of this pages node. Ideally we would just resolve the
3752 // promise with the page ref here, but there is the case where more
3753 // pages nodes could link to single a page (see issue 3666 pdf). To
3754 // handle this push it back on the queue so if it is a pages node it
3755 // will be descended into.
3756 nodesToVisit = [kids[pageIndex - currentPageIndex]];
3757 currentPageIndex = pageIndex;
3758 continue;
3759 } else {
3760 for (var last = kids.length - 1; last >= 0; last--) {
3761 nodesToVisit.push(kids[last]);
3762 }
3763 }
3764 }
3765 capability.reject('Page index ' + pageIndex + ' not found.');
3766 }
3767 next();
3768 return capability.promise;
3769 },
3770
3771 getPageIndex: function Catalog_getPageIndex(ref) {
3772 // The page tree nodes have the count of all the leaves below them. To get
3773 // how many pages are before we just have to walk up the tree and keep
3774 // adding the count of siblings to the left of the node.
3775 var xref = this.xref;
3776 function pagesBeforeRef(kidRef) {
3777 var total = 0;
3778 var parentRef;
3779 return xref.fetchAsync(kidRef).then(function (node) {
3780 if (!node) {
3781 return null;
3782 }
3783 parentRef = node.getRaw('Parent');
3784 return node.getAsync('Parent');
3785 }).then(function (parent) {
3786 if (!parent) {
3787 return null;
3788 }
3789 return parent.getAsync('Kids');
3790 }).then(function (kids) {
3791 if (!kids) {
3792 return null;
3793 }
3794 var kidPromises = [];
3795 var found = false;
3796 for (var i = 0; i < kids.length; i++) {
3797 var kid = kids[i];
3798 assert(isRef(kid), 'kids must be a ref');
3799 if (kid.num === kidRef.num) {
3800 found = true;
3801 break;
3802 }
3803 kidPromises.push(xref.fetchAsync(kid).then(function (kid) {
3804 if (kid.has('Count')) {
3805 var count = kid.get('Count');
3806 total += count;
3807 } else { // page leaf node
3808 total++;
3809 }
3810 }));
3811 }
3812 if (!found) {
3813 error('kid ref not found in parents kids');
3814 }
3815 return Promise.all(kidPromises).then(function () {
3816 return [total, parentRef];
3817 });
3818 });
3819 }
3820
3821 var total = 0;
3822 function next(ref) {
3823 return pagesBeforeRef(ref).then(function (args) {
3824 if (!args) {
3825 return total;
3826 }
3827 var count = args[0];
3828 var parentRef = args[1];
3829 total += count;
3830 return next(parentRef);
3831 });
3832 }
3833
3834 return next(ref);
3835 }
3836 };
3837
3838 return Catalog;
3839 })();
3840
3841 var XRef = (function XRefClosure() {
3842 function XRef(stream, password) {
3843 this.stream = stream;
3844 this.entries = [];
3845 this.xrefstms = {};
3846 // prepare the XRef cache
3847 this.cache = [];
3848 this.password = password;
3849 this.stats = {
3850 streamTypes: [],
3851 fontTypes: []
3852 };
3853 }
3854
3855 XRef.prototype = {
3856 setStartXRef: function XRef_setStartXRef(startXRef) {
3857 // Store the starting positions of xref tables as we process them
3858 // so we can recover from missing data errors
3859 this.startXRefQueue = [startXRef];
3860 },
3861
3862 parse: function XRef_parse(recoveryMode) {
3863 var trailerDict;
3864 if (!recoveryMode) {
3865 trailerDict = this.readXRef();
3866 } else {
3867 warn('Indexing all PDF objects');
3868 trailerDict = this.indexObjects();
3869 }
3870 trailerDict.assignXref(this);
3871 this.trailer = trailerDict;
3872 var encrypt = trailerDict.get('Encrypt');
3873 if (encrypt) {
3874 var ids = trailerDict.get('ID');
3875 var fileId = (ids && ids.length) ? ids[0] : '';
3876 this.encrypt = new CipherTransformFactory(encrypt, fileId,
3877 this.password);
3878 }
3879
3880 // get the root dictionary (catalog) object
3881 if (!(this.root = trailerDict.get('Root'))) {
3882 error('Invalid root reference');
3883 }
3884 },
3885
3886 processXRefTable: function XRef_processXRefTable(parser) {
3887 if (!('tableState' in this)) {
3888 // Stores state of the table as we process it so we can resume
3889 // from middle of table in case of missing data error
3890 this.tableState = {
3891 entryNum: 0,
3892 streamPos: parser.lexer.stream.pos,
3893 parserBuf1: parser.buf1,
3894 parserBuf2: parser.buf2
3895 };
3896 }
3897
3898 var obj = this.readXRefTable(parser);
3899
3900 // Sanity check
3901 if (!isCmd(obj, 'trailer')) {
3902 error('Invalid XRef table: could not find trailer dictionary');
3903 }
3904 // Read trailer dictionary, e.g.
3905 // trailer
3906 // << /Size 22
3907 // /Root 20R
3908 // /Info 10R
3909 // /ID [ <81b14aafa313db63dbd6f981e49f94f4> ]
3910 // >>
3911 // The parser goes through the entire stream << ... >> and provides
3912 // a getter interface for the key-value table
3913 var dict = parser.getObj();
3914
3915 // The pdflib PDF generator can generate a nested trailer dictionary
3916 if (!isDict(dict) && dict.dict) {
3917 dict = dict.dict;
3918 }
3919 if (!isDict(dict)) {
3920 error('Invalid XRef table: could not parse trailer dictionary');
3921 }
3922 delete this.tableState;
3923
3924 return dict;
3925 },
3926
3927 readXRefTable: function XRef_readXRefTable(parser) {
3928 // Example of cross-reference table:
3929 // xref
3930 // 0 1 <-- subsection header (first obj #, obj count)
3931 // 0000000000 65535 f <-- actual object (offset, generation #, f/n)
3932 // 23 2 <-- subsection header ... and so on ...
3933 // 0000025518 00002 n
3934 // 0000025635 00000 n
3935 // trailer
3936 // ...
3937
3938 var stream = parser.lexer.stream;
3939 var tableState = this.tableState;
3940 stream.pos = tableState.streamPos;
3941 parser.buf1 = tableState.parserBuf1;
3942 parser.buf2 = tableState.parserBuf2;
3943
3944 // Outer loop is over subsection headers
3945 var obj;
3946
3947 while (true) {
3948 if (!('firstEntryNum' in tableState) || !('entryCount' in tableState)) {
3949 if (isCmd(obj = parser.getObj(), 'trailer')) {
3950 break;
3951 }
3952 tableState.firstEntryNum = obj;
3953 tableState.entryCount = parser.getObj();
3954 }
3955
3956 var first = tableState.firstEntryNum;
3957 var count = tableState.entryCount;
3958 if (!isInt(first) || !isInt(count)) {
3959 error('Invalid XRef table: wrong types in subsection header');
3960 }
3961 // Inner loop is over objects themselves
3962 for (var i = tableState.entryNum; i < count; i++) {
3963 tableState.streamPos = stream.pos;
3964 tableState.entryNum = i;
3965 tableState.parserBuf1 = parser.buf1;
3966 tableState.parserBuf2 = parser.buf2;
3967
3968 var entry = {};
3969 entry.offset = parser.getObj();
3970 entry.gen = parser.getObj();
3971 var type = parser.getObj();
3972
3973 if (isCmd(type, 'f')) {
3974 entry.free = true;
3975 } else if (isCmd(type, 'n')) {
3976 entry.uncompressed = true;
3977 }
3978
3979 // Validate entry obj
3980 if (!isInt(entry.offset) || !isInt(entry.gen) ||
3981 !(entry.free || entry.uncompressed)) {
3982 error('Invalid entry in XRef subsection: ' + first + ', ' + count);
3983 }
3984
3985 if (!this.entries[i + first]) {
3986 this.entries[i + first] = entry;
3987 }
3988 }
3989
3990 tableState.entryNum = 0;
3991 tableState.streamPos = stream.pos;
3992 tableState.parserBuf1 = parser.buf1;
3993 tableState.parserBuf2 = parser.buf2;
3994 delete tableState.firstEntryNum;
3995 delete tableState.entryCount;
3996 }
3997
3998 // Per issue 3248: hp scanners generate bad XRef
3999 if (first === 1 && this.entries[1] && this.entries[1].free) {
4000 // shifting the entries
4001 this.entries.shift();
4002 }
4003
4004 // Sanity check: as per spec, first object must be free
4005 if (this.entries[0] && !this.entries[0].free) {
4006 error('Invalid XRef table: unexpected first object');
4007 }
4008 return obj;
4009 },
4010
4011 processXRefStream: function XRef_processXRefStream(stream) {
4012 if (!('streamState' in this)) {
4013 // Stores state of the stream as we process it so we can resume
4014 // from middle of stream in case of missing data error
4015 var streamParameters = stream.dict;
4016 var byteWidths = streamParameters.get('W');
4017 var range = streamParameters.get('Index');
4018 if (!range) {
4019 range = [0, streamParameters.get('Size')];
4020 }
4021
4022 this.streamState = {
4023 entryRanges: range,
4024 byteWidths: byteWidths,
4025 entryNum: 0,
4026 streamPos: stream.pos
4027 };
4028 }
4029 this.readXRefStream(stream);
4030 delete this.streamState;
4031
4032 return stream.dict;
4033 },
4034
4035 readXRefStream: function XRef_readXRefStream(stream) {
4036 var i, j;
4037 var streamState = this.streamState;
4038 stream.pos = streamState.streamPos;
4039
4040 var byteWidths = streamState.byteWidths;
4041 var typeFieldWidth = byteWidths[0];
4042 var offsetFieldWidth = byteWidths[1];
4043 var generationFieldWidth = byteWidths[2];
4044
4045 var entryRanges = streamState.entryRanges;
4046 while (entryRanges.length > 0) {
4047 var first = entryRanges[0];
4048 var n = entryRanges[1];
4049
4050 if (!isInt(first) || !isInt(n)) {
4051 error('Invalid XRef range fields: ' + first + ', ' + n);
4052 }
4053 if (!isInt(typeFieldWidth) || !isInt(offsetFieldWidth) ||
4054 !isInt(generationFieldWidth)) {
4055 error('Invalid XRef entry fields length: ' + first + ', ' + n);
4056 }
4057 for (i = streamState.entryNum; i < n; ++i) {
4058 streamState.entryNum = i;
4059 streamState.streamPos = stream.pos;
4060
4061 var type = 0, offset = 0, generation = 0;
4062 for (j = 0; j < typeFieldWidth; ++j) {
4063 type = (type << 8) | stream.getByte();
4064 }
4065 // if type field is absent, its default value is 1
4066 if (typeFieldWidth === 0) {
4067 type = 1;
4068 }
4069 for (j = 0; j < offsetFieldWidth; ++j) {
4070 offset = (offset << 8) | stream.getByte();
4071 }
4072 for (j = 0; j < generationFieldWidth; ++j) {
4073 generation = (generation << 8) | stream.getByte();
4074 }
4075 var entry = {};
4076 entry.offset = offset;
4077 entry.gen = generation;
4078 switch (type) {
4079 case 0:
4080 entry.free = true;
4081 break;
4082 case 1:
4083 entry.uncompressed = true;
4084 break;
4085 case 2:
4086 break;
4087 default:
4088 error('Invalid XRef entry type: ' + type);
4089 }
4090 if (!this.entries[first + i]) {
4091 this.entries[first + i] = entry;
4092 }
4093 }
4094
4095 streamState.entryNum = 0;
4096 streamState.streamPos = stream.pos;
4097 entryRanges.splice(0, 2);
4098 }
4099 },
4100
4101 indexObjects: function XRef_indexObjects() {
4102 // Simple scan through the PDF content to find objects,
4103 // trailers and XRef streams.
4104 function readToken(data, offset) {
4105 var token = '', ch = data[offset];
4106 while (ch !== 13 && ch !== 10) {
4107 if (++offset >= data.length) {
4108 break;
4109 }
4110 token += String.fromCharCode(ch);
4111 ch = data[offset];
4112 }
4113 return token;
4114 }
4115 function skipUntil(data, offset, what) {
4116 var length = what.length, dataLength = data.length;
4117 var skipped = 0;
4118 // finding byte sequence
4119 while (offset < dataLength) {
4120 var i = 0;
4121 while (i < length && data[offset + i] === what[i]) {
4122 ++i;
4123 }
4124 if (i >= length) {
4125 break; // sequence found
4126 }
4127 offset++;
4128 skipped++;
4129 }
4130 return skipped;
4131 }
4132 var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
4133 var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114,
4134 101, 102]);
4135 var endobjBytes = new Uint8Array([101, 110, 100, 111, 98, 106]);
4136 var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
4137
4138 var stream = this.stream;
4139 stream.pos = 0;
4140 var buffer = stream.getBytes();
4141 var position = stream.start, length = buffer.length;
4142 var trailers = [], xrefStms = [];
4143 while (position < length) {
4144 var ch = buffer[position];
4145 if (ch === 32 || ch === 9 || ch === 13 || ch === 10) {
4146 ++position;
4147 continue;
4148 }
4149 if (ch === 37) { // %-comment
4150 do {
4151 ++position;
4152 if (position >= length) {
4153 break;
4154 }
4155 ch = buffer[position];
4156 } while (ch !== 13 && ch !== 10);
4157 continue;
4158 }
4159 var token = readToken(buffer, position);
4160 var m;
4161 if (token === 'xref') {
4162 position += skipUntil(buffer, position, trailerBytes);
4163 trailers.push(position);
4164 position += skipUntil(buffer, position, startxrefBytes);
4165 } else if ((m = /^(\d+)\s+(\d+)\s+obj\b/.exec(token))) {
4166 this.entries[m[1]] = {
4167 offset: position,
4168 gen: m[2] | 0,
4169 uncompressed: true
4170 };
4171
4172 var contentLength = skipUntil(buffer, position, endobjBytes) + 7;
4173 var content = buffer.subarray(position, position + contentLength);
4174
4175 // checking XRef stream suspect
4176 // (it shall have '/XRef' and next char is not a letter)
4177 var xrefTagOffset = skipUntil(content, 0, xrefBytes);
4178 if (xrefTagOffset < contentLength &&
4179 content[xrefTagOffset + 5] < 64) {
4180 xrefStms.push(position);
4181 this.xrefstms[position] = 1; // don't read it recursively
4182 }
4183
4184 position += contentLength;
4185 } else {
4186 position += token.length + 1;
4187 }
4188 }
4189 // reading XRef streams
4190 var i, ii;
4191 for (i = 0, ii = xrefStms.length; i < ii; ++i) {
4192 this.startXRefQueue.push(xrefStms[i]);
4193 this.readXRef(/* recoveryMode */ true);
4194 }
4195 // finding main trailer
4196 var dict;
4197 for (i = 0, ii = trailers.length; i < ii; ++i) {
4198 stream.pos = trailers[i];
4199 var parser = new Parser(new Lexer(stream), true, this);
4200 var obj = parser.getObj();
4201 if (!isCmd(obj, 'trailer')) {
4202 continue;
4203 }
4204 // read the trailer dictionary
4205 if (!isDict(dict = parser.getObj())) {
4206 continue;
4207 }
4208 // taking the first one with 'ID'
4209 if (dict.has('ID')) {
4210 return dict;
4211 }
4212 }
4213 // no tailer with 'ID', taking last one (if exists)
4214 if (dict) {
4215 return dict;
4216 }
4217 // nothing helps
4218 // calling error() would reject worker with an UnknownErrorException.
4219 throw new InvalidPDFException('Invalid PDF structure');
4220 },
4221
4222 readXRef: function XRef_readXRef(recoveryMode) {
4223 var stream = this.stream;
4224
4225 try {
4226 while (this.startXRefQueue.length) {
4227 var startXRef = this.startXRefQueue[0];
4228
4229 stream.pos = startXRef + stream.start;
4230
4231 var parser = new Parser(new Lexer(stream), true, this);
4232 var obj = parser.getObj();
4233 var dict;
4234
4235 // Get dictionary
4236 if (isCmd(obj, 'xref')) {
4237 // Parse end-of-file XRef
4238 dict = this.processXRefTable(parser);
4239 if (!this.topDict) {
4240 this.topDict = dict;
4241 }
4242
4243 // Recursively get other XRefs 'XRefStm', if any
4244 obj = dict.get('XRefStm');
4245 if (isInt(obj)) {
4246 var pos = obj;
4247 // ignore previously loaded xref streams
4248 // (possible infinite recursion)
4249 if (!(pos in this.xrefstms)) {
4250 this.xrefstms[pos] = 1;
4251 this.startXRefQueue.push(pos);
4252 }
4253 }
4254 } else if (isInt(obj)) {
4255 // Parse in-stream XRef
4256 if (!isInt(parser.getObj()) ||
4257 !isCmd(parser.getObj(), 'obj') ||
4258 !isStream(obj = parser.getObj())) {
4259 error('Invalid XRef stream');
4260 }
4261 dict = this.processXRefStream(obj);
4262 if (!this.topDict) {
4263 this.topDict = dict;
4264 }
4265 if (!dict) {
4266 error('Failed to read XRef stream');
4267 }
4268 } else {
4269 error('Invalid XRef stream header');
4270 }
4271
4272 // Recursively get previous dictionary, if any
4273 obj = dict.get('Prev');
4274 if (isInt(obj)) {
4275 this.startXRefQueue.push(obj);
4276 } else if (isRef(obj)) {
4277 // The spec says Prev must not be a reference, i.e. "/Prev NNN"
4278 // This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R"
4279 this.startXRefQueue.push(obj.num);
4280 }
4281
4282 this.startXRefQueue.shift();
4283 }
4284
4285 return this.topDict;
4286 } catch (e) {
4287 if (e instanceof MissingDataException) {
4288 throw e;
4289 }
4290 info('(while reading XRef): ' + e);
4291 }
4292
4293 if (recoveryMode) {
4294 return;
4295 }
4296 throw new XRefParseException();
4297 },
4298
4299 getEntry: function XRef_getEntry(i) {
4300 var xrefEntry = this.entries[i];
4301 if (xrefEntry && !xrefEntry.free && xrefEntry.offset) {
4302 return xrefEntry;
4303 }
4304 return null;
4305 },
4306
4307 fetchIfRef: function XRef_fetchIfRef(obj) {
4308 if (!isRef(obj)) {
4309 return obj;
4310 }
4311 return this.fetch(obj);
4312 },
4313
4314 fetch: function XRef_fetch(ref, suppressEncryption) {
4315 assert(isRef(ref), 'ref object is not a reference');
4316 var num = ref.num;
4317 if (num in this.cache) {
4318 var cacheEntry = this.cache[num];
4319 return cacheEntry;
4320 }
4321
4322 var xrefEntry = this.getEntry(num);
4323
4324 // the referenced entry can be free
4325 if (xrefEntry === null) {
4326 return (this.cache[num] = null);
4327 }
4328
4329 if (xrefEntry.uncompressed) {
4330 xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
4331 } else {
4332 xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption);
4333 }
4334 if (isDict(xrefEntry)){
4335 xrefEntry.objId = ref.toString();
4336 } else if (isStream(xrefEntry)) {
4337 xrefEntry.dict.objId = ref.toString();
4338 }
4339 return xrefEntry;
4340 },
4341
4342 fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry,
4343 suppressEncryption) {
4344 var gen = ref.gen;
4345 var num = ref.num;
4346 if (xrefEntry.gen !== gen) {
4347 error('inconsistent generation in XRef');
4348 }
4349 var stream = this.stream.makeSubStream(xrefEntry.offset +
4350 this.stream.start);
4351 var parser = new Parser(new Lexer(stream), true, this);
4352 var obj1 = parser.getObj();
4353 var obj2 = parser.getObj();
4354 var obj3 = parser.getObj();
4355 if (!isInt(obj1) || parseInt(obj1, 10) !== num ||
4356 !isInt(obj2) || parseInt(obj2, 10) !== gen ||
4357 !isCmd(obj3)) {
4358 error('bad XRef entry');
4359 }
4360 if (!isCmd(obj3, 'obj')) {
4361 // some bad PDFs use "obj1234" and really mean 1234
4362 if (obj3.cmd.indexOf('obj') === 0) {
4363 num = parseInt(obj3.cmd.substring(3), 10);
4364 if (!isNaN(num)) {
4365 return num;
4366 }
4367 }
4368 error('bad XRef entry');
4369 }
4370 if (this.encrypt && !suppressEncryption) {
4371 xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));
4372 } else {
4373 xrefEntry = parser.getObj();
4374 }
4375 if (!isStream(xrefEntry)) {
4376 this.cache[num] = xrefEntry;
4377 }
4378 return xrefEntry;
4379 },
4380
4381 fetchCompressed: function XRef_fetchCompressed(xrefEntry,
4382 suppressEncryption) {
4383 var tableOffset = xrefEntry.offset;
4384 var stream = this.fetch(new Ref(tableOffset, 0));
4385 if (!isStream(stream)) {
4386 error('bad ObjStm stream');
4387 }
4388 var first = stream.dict.get('First');
4389 var n = stream.dict.get('N');
4390 if (!isInt(first) || !isInt(n)) {
4391 error('invalid first and n parameters for ObjStm stream');
4392 }
4393 var parser = new Parser(new Lexer(stream), false, this);
4394 parser.allowStreams = true;
4395 var i, entries = [], num, nums = [];
4396 // read the object numbers to populate cache
4397 for (i = 0; i < n; ++i) {
4398 num = parser.getObj();
4399 if (!isInt(num)) {
4400 error('invalid object number in the ObjStm stream: ' + num);
4401 }
4402 nums.push(num);
4403 var offset = parser.getObj();
4404 if (!isInt(offset)) {
4405 error('invalid object offset in the ObjStm stream: ' + offset);
4406 }
4407 }
4408 // read stream objects for cache
4409 for (i = 0; i < n; ++i) {
4410 entries.push(parser.getObj());
4411 num = nums[i];
4412 var entry = this.entries[num];
4413 if (entry && entry.offset === tableOffset && entry.gen === i) {
4414 this.cache[num] = entries[i];
4415 }
4416 }
4417 xrefEntry = entries[xrefEntry.gen];
4418 if (xrefEntry === undefined) {
4419 error('bad XRef entry for compressed object');
4420 }
4421 return xrefEntry;
4422 },
4423
4424 fetchIfRefAsync: function XRef_fetchIfRefAsync(obj) {
4425 if (!isRef(obj)) {
4426 return Promise.resolve(obj);
4427 }
4428 return this.fetchAsync(obj);
4429 },
4430
4431 fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) {
4432 var streamManager = this.stream.manager;
4433 var xref = this;
4434 return new Promise(function tryFetch(resolve, reject) {
4435 try {
4436 resolve(xref.fetch(ref, suppressEncryption));
4437 } catch (e) {
4438 if (e instanceof MissingDataException) {
4439 streamManager.requestRange(e.begin, e.end, function () {
4440 tryFetch(resolve, reject);
4441 });
4442 return;
4443 }
4444 reject(e);
4445 }
4446 });
4447 },
4448
4449 getCatalogObj: function XRef_getCatalogObj() {
4450 return this.root;
4451 }
4452 };
4453
4454 return XRef;
4455 })();
4456
4457 /**
4458 * A NameTree is like a Dict but has some advantageous properties, see the
4459 * spec (7.9.6) for more details.
4460 * TODO: implement all the Dict functions and make this more efficent.
4461 */
4462 var NameTree = (function NameTreeClosure() {
4463 function NameTree(root, xref) {
4464 this.root = root;
4465 this.xref = xref;
4466 }
4467
4468 NameTree.prototype = {
4469 getAll: function NameTree_getAll() {
4470 var dict = {};
4471 if (!this.root) {
4472 return dict;
4473 }
4474 var xref = this.xref;
4475 // reading name tree
4476 var processed = new RefSet();
4477 processed.put(this.root);
4478 var queue = [this.root];
4479 while (queue.length > 0) {
4480 var i, n;
4481 var obj = xref.fetchIfRef(queue.shift());
4482 if (!isDict(obj)) {
4483 continue;
4484 }
4485 if (obj.has('Kids')) {
4486 var kids = obj.get('Kids');
4487 for (i = 0, n = kids.length; i < n; i++) {
4488 var kid = kids[i];
4489 if (processed.has(kid)) {
4490 error('invalid destinations');
4491 }
4492 queue.push(kid);
4493 processed.put(kid);
4494 }
4495 continue;
4496 }
4497 var names = obj.get('Names');
4498 if (names) {
4499 for (i = 0, n = names.length; i < n; i += 2) {
4500 dict[names[i]] = xref.fetchIfRef(names[i + 1]);
4501 }
4502 }
4503 }
4504 return dict;
4505 },
4506
4507 get: function NameTree_get(destinationId) {
4508 if (!this.root) {
4509 return null;
4510 }
4511
4512 var xref = this.xref;
4513 var kidsOrNames = xref.fetchIfRef(this.root);
4514 var loopCount = 0;
4515 var MAX_NAMES_LEVELS = 10;
4516 var l, r, m;
4517
4518 // Perform a binary search to quickly find the entry that
4519 // contains the named destination we are looking for.
4520 while (kidsOrNames.has('Kids')) {
4521 loopCount++;
4522 if (loopCount > MAX_NAMES_LEVELS) {
4523 warn('Search depth limit for named destionations has been reached.');
4524 return null;
4525 }
4526
4527 var kids = kidsOrNames.get('Kids');
4528 if (!isArray(kids)) {
4529 return null;
4530 }
4531
4532 l = 0;
4533 r = kids.length - 1;
4534 while (l <= r) {
4535 m = (l + r) >> 1;
4536 var kid = xref.fetchIfRef(kids[m]);
4537 var limits = kid.get('Limits');
4538
4539 if (destinationId < limits[0]) {
4540 r = m - 1;
4541 } else if (destinationId > limits[1]) {
4542 l = m + 1;
4543 } else {
4544 kidsOrNames = xref.fetchIfRef(kids[m]);
4545 break;
4546 }
4547 }
4548 if (l > r) {
4549 return null;
4550 }
4551 }
4552
4553 // If we get here, then we have found the right entry. Now
4554 // go through the named destinations in the Named dictionary
4555 // until we find the exact destination we're looking for.
4556 var names = kidsOrNames.get('Names');
4557 if (isArray(names)) {
4558 // Perform a binary search to reduce the lookup time.
4559 l = 0;
4560 r = names.length - 2;
4561 while (l <= r) {
4562 // Check only even indices (0, 2, 4, ...) because the
4563 // odd indices contain the actual D array.
4564 m = (l + r) & ~1;
4565 if (destinationId < names[m]) {
4566 r = m - 2;
4567 } else if (destinationId > names[m]) {
4568 l = m + 2;
4569 } else {
4570 return xref.fetchIfRef(names[m + 1]);
4571 }
4572 }
4573 }
4574 return null;
4575 }
4576 };
4577 return NameTree;
4578 })();
4579
4580 /**
4581 * "A PDF file can refer to the contents of another file by using a File
4582 * Specification (PDF 1.1)", see the spec (7.11) for more details.
4583 * NOTE: Only embedded files are supported (as part of the attachments support)
4584 * TODO: support the 'URL' file system (with caching if !/V), portable
4585 * collections attributes and related files (/RF)
4586 */
4587 var FileSpec = (function FileSpecClosure() {
4588 function FileSpec(root, xref) {
4589 if (!root || !isDict(root)) {
4590 return;
4591 }
4592 this.xref = xref;
4593 this.root = root;
4594 if (root.has('FS')) {
4595 this.fs = root.get('FS');
4596 }
4597 this.description = root.has('Desc') ?
4598 stringToPDFString(root.get('Desc')) :
4599 '';
4600 if (root.has('RF')) {
4601 warn('Related file specifications are not supported');
4602 }
4603 this.contentAvailable = true;
4604 if (!root.has('EF')) {
4605 this.contentAvailable = false;
4606 warn('Non-embedded file specifications are not supported');
4607 }
4608 }
4609
4610 function pickPlatformItem(dict) {
4611 // Look for the filename in this order:
4612 // UF, F, Unix, Mac, DOS
4613 if (dict.has('UF')) {
4614 return dict.get('UF');
4615 } else if (dict.has('F')) {
4616 return dict.get('F');
4617 } else if (dict.has('Unix')) {
4618 return dict.get('Unix');
4619 } else if (dict.has('Mac')) {
4620 return dict.get('Mac');
4621 } else if (dict.has('DOS')) {
4622 return dict.get('DOS');
4623 } else {
4624 return null;
4625 }
4626 }
4627
4628 FileSpec.prototype = {
4629 get filename() {
4630 if (!this._filename && this.root) {
4631 var filename = pickPlatformItem(this.root) || 'unnamed';
4632 this._filename = stringToPDFString(filename).
4633 replace(/\\\\/g, '\\').
4634 replace(/\\\//g, '/').
4635 replace(/\\/g, '/');
4636 }
4637 return this._filename;
4638 },
4639 get content() {
4640 if (!this.contentAvailable) {
4641 return null;
4642 }
4643 if (!this.contentRef && this.root) {
4644 this.contentRef = pickPlatformItem(this.root.get('EF'));
4645 }
4646 var content = null;
4647 if (this.contentRef) {
4648 var xref = this.xref;
4649 var fileObj = xref.fetchIfRef(this.contentRef);
4650 if (fileObj && isStream(fileObj)) {
4651 content = fileObj.getBytes();
4652 } else {
4653 warn('Embedded file specification points to non-existing/invalid ' +
4654 'content');
4655 }
4656 } else {
4657 warn('Embedded file specification does not have a content');
4658 }
4659 return content;
4660 },
4661 get serializable() {
4662 return {
4663 filename: this.filename,
4664 content: this.content
4665 };
4666 }
4667 };
4668 return FileSpec;
4669 })();
4670
4671 /**
4672 * A helper for loading missing data in object graphs. It traverses the graph
4673 * depth first and queues up any objects that have missing data. Once it has
4674 * has traversed as many objects that are available it attempts to bundle the
4675 * missing data requests and then resume from the nodes that weren't ready.
4676 *
4677 * NOTE: It provides protection from circular references by keeping track of
4678 * of loaded references. However, you must be careful not to load any graphs
4679 * that have references to the catalog or other pages since that will cause the
4680 * entire PDF document object graph to be traversed.
4681 */
4682 var ObjectLoader = (function() {
4683 function mayHaveChildren(value) {
4684 return isRef(value) || isDict(value) || isArray(value) || isStream(value);
4685 }
4686
4687 function addChildren(node, nodesToVisit) {
4688 var value;
4689 if (isDict(node) || isStream(node)) {
4690 var map;
4691 if (isDict(node)) {
4692 map = node.map;
4693 } else {
4694 map = node.dict.map;
4695 }
4696 for (var key in map) {
4697 value = map[key];
4698 if (mayHaveChildren(value)) {
4699 nodesToVisit.push(value);
4700 }
4701 }
4702 } else if (isArray(node)) {
4703 for (var i = 0, ii = node.length; i < ii; i++) {
4704 value = node[i];
4705 if (mayHaveChildren(value)) {
4706 nodesToVisit.push(value);
4707 }
4708 }
4709 }
4710 }
4711
4712 function ObjectLoader(obj, keys, xref) {
4713 this.obj = obj;
4714 this.keys = keys;
4715 this.xref = xref;
4716 this.refSet = null;
4717 }
4718
4719 ObjectLoader.prototype = {
4720 load: function ObjectLoader_load() {
4721 var keys = this.keys;
4722 this.capability = createPromiseCapability();
4723 // Don't walk the graph if all the data is already loaded.
4724 if (!(this.xref.stream instanceof ChunkedStream) ||
4725 this.xref.stream.getMissingChunks().length === 0) {
4726 this.capability.resolve();
4727 return this.capability.promise;
4728 }
4729
4730 this.refSet = new RefSet();
4731 // Setup the initial nodes to visit.
4732 var nodesToVisit = [];
4733 for (var i = 0; i < keys.length; i++) {
4734 nodesToVisit.push(this.obj[keys[i]]);
4735 }
4736
4737 this.walk(nodesToVisit);
4738 return this.capability.promise;
4739 },
4740
4741 walk: function ObjectLoader_walk(nodesToVisit) {
4742 var nodesToRevisit = [];
4743 var pendingRequests = [];
4744 // DFS walk of the object graph.
4745 while (nodesToVisit.length) {
4746 var currentNode = nodesToVisit.pop();
4747
4748 // Only references or chunked streams can cause missing data exceptions.
4749 if (isRef(currentNode)) {
4750 // Skip nodes that have already been visited.
4751 if (this.refSet.has(currentNode)) {
4752 continue;
4753 }
4754 try {
4755 var ref = currentNode;
4756 this.refSet.put(ref);
4757 currentNode = this.xref.fetch(currentNode);
4758 } catch (e) {
4759 if (!(e instanceof MissingDataException)) {
4760 throw e;
4761 }
4762 nodesToRevisit.push(currentNode);
4763 pendingRequests.push({ begin: e.begin, end: e.end });
4764 }
4765 }
4766 if (currentNode && currentNode.getBaseStreams) {
4767 var baseStreams = currentNode.getBaseStreams();
4768 var foundMissingData = false;
4769 for (var i = 0; i < baseStreams.length; i++) {
4770 var stream = baseStreams[i];
4771 if (stream.getMissingChunks && stream.getMissingChunks().length) {
4772 foundMissingData = true;
4773 pendingRequests.push({
4774 begin: stream.start,
4775 end: stream.end
4776 });
4777 }
4778 }
4779 if (foundMissingData) {
4780 nodesToRevisit.push(currentNode);
4781 }
4782 }
4783
4784 addChildren(currentNode, nodesToVisit);
4785 }
4786
4787 if (pendingRequests.length) {
4788 this.xref.stream.manager.requestRanges(pendingRequests,
4789 function pendingRequestCallback() {
4790 nodesToVisit = nodesToRevisit;
4791 for (var i = 0; i < nodesToRevisit.length; i++) {
4792 var node = nodesToRevisit[i];
4793 // Remove any reference nodes from the currrent refset so they
4794 // aren't skipped when we revist them.
4795 if (isRef(node)) {
4796 this.refSet.remove(node);
4797 }
4798 }
4799 this.walk(nodesToVisit);
4800 }.bind(this));
4801 return;
4802 }
4803 // Everything is loaded.
4804 this.refSet = null;
4805 this.capability.resolve();
4806 }
4807 };
4808
4809 return ObjectLoader;
4810 })();
4811
4812
4813 var ISOAdobeCharset = [
4814 '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
4815 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
4816 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',
4817 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
4818 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',
4819 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
4820 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
4821 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
4822 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
4823 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
4824 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
4825 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
4826 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
4827 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
4828 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
4829 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
4830 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde',
4831 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
4832 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine',
4833 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash',
4834 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',
4835 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',
4836 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',
4837 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
4838 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',
4839 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',
4840 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
4841 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',
4842 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',
4843 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
4844 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
4845 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
4846 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',
4847 'ugrave', 'yacute', 'ydieresis', 'zcaron'
4848 ];
4849
4850 var ExpertCharset = [
4851 '.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
4852 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
4853 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
4854 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
4855 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
4856 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',
4857 'colon', 'semicolon', 'commasuperior', 'threequartersemdash',
4858 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',
4859 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
4860 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
4861 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
4862 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
4863 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
4864 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
4865 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
4866 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
4867 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',
4868 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
4869 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
4870 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',
4871 'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',
4872 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
4873 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
4874 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
4875 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
4876 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
4877 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
4878 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
4879 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
4880 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
4881 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
4882 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
4883 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
4884 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
4885 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
4886 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
4887 'Ydieresissmall'
4888 ];
4889
4890 var ExpertSubsetCharset = [
4891 '.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
4892 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
4893 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',
4894 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
4895 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',
4896 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',
4897 'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',
4898 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
4899 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
4900 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
4901 'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',
4902 'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',
4903 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
4904 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
4905 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
4906 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
4907 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
4908 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
4909 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
4910 'periodinferior', 'commainferior'
4911 ];
4912
4913
4914 var DEFAULT_ICON_SIZE = 22; // px
4915 var SUPPORTED_TYPES = ['Link', 'Text', 'Widget'];
4916
4917 var Annotation = (function AnnotationClosure() {
4918 // 12.5.5: Algorithm: Appearance streams
4919 function getTransformMatrix(rect, bbox, matrix) {
4920 var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
4921 var minX = bounds[0];
4922 var minY = bounds[1];
4923 var maxX = bounds[2];
4924 var maxY = bounds[3];
4925
4926 if (minX === maxX || minY === maxY) {
4927 // From real-life file, bbox was [0, 0, 0, 0]. In this case,
4928 // just apply the transform for rect
4929 return [1, 0, 0, 1, rect[0], rect[1]];
4930 }
4931
4932 var xRatio = (rect[2] - rect[0]) / (maxX - minX);
4933 var yRatio = (rect[3] - rect[1]) / (maxY - minY);
4934 return [
4935 xRatio,
4936 0,
4937 0,
4938 yRatio,
4939 rect[0] - minX * xRatio,
4940 rect[1] - minY * yRatio
4941 ];
4942 }
4943
4944 function getDefaultAppearance(dict) {
4945 var appearanceState = dict.get('AP');
4946 if (!isDict(appearanceState)) {
4947 return;
4948 }
4949
4950 var appearance;
4951 var appearances = appearanceState.get('N');
4952 if (isDict(appearances)) {
4953 var as = dict.get('AS');
4954 if (as && appearances.has(as.name)) {
4955 appearance = appearances.get(as.name);
4956 }
4957 } else {
4958 appearance = appearances;
4959 }
4960 return appearance;
4961 }
4962
4963 function Annotation(params) {
4964 var dict = params.dict;
4965 var data = this.data = {};
4966
4967 data.subtype = dict.get('Subtype').name;
4968 var rect = dict.get('Rect') || [0, 0, 0, 0];
4969 data.rect = Util.normalizeRect(rect);
4970 data.annotationFlags = dict.get('F');
4971
4972 var color = dict.get('C');
4973 if (!color) {
4974 // The PDF spec does not mention how a missing color array is interpreted.
4975 // Adobe Reader seems to default to black in this case.
4976 data.color = [0, 0, 0];
4977 } else if (isArray(color)) {
4978 switch (color.length) {
4979 case 0:
4980 // Empty array denotes transparent border.
4981 data.color = null;
4982 break;
4983 case 1:
4984 // TODO: implement DeviceGray
4985 break;
4986 case 3:
4987 data.color = color;
4988 break;
4989 case 4:
4990 // TODO: implement DeviceCMYK
4991 break;
4992 }
4993 }
4994
4995 // Some types of annotations have border style dict which has more
4996 // info than the border array
4997 if (dict.has('BS')) {
4998 var borderStyle = dict.get('BS');
4999 data.borderWidth = borderStyle.has('W') ? borderStyle.get('W') : 1;
5000 } else {
5001 var borderArray = dict.get('Border') || [0, 0, 1];
5002 data.borderWidth = borderArray[2] || 0;
5003
5004 // TODO: implement proper support for annotations with line dash patterns.
5005 var dashArray = borderArray[3];
5006 if (data.borderWidth > 0 && dashArray) {
5007 if (!isArray(dashArray)) {
5008 // Ignore the border if dashArray is not actually an array,
5009 // this is consistent with the behaviour in Adobe Reader.
5010 data.borderWidth = 0;
5011 } else {
5012 var dashArrayLength = dashArray.length;
5013 if (dashArrayLength > 0) {
5014 // According to the PDF specification: the elements in a dashArray
5015 // shall be numbers that are nonnegative and not all equal to zero.
5016 var isInvalid = false;
5017 var numPositive = 0;
5018 for (var i = 0; i < dashArrayLength; i++) {
5019 var validNumber = (+dashArray[i] >= 0);
5020 if (!validNumber) {
5021 isInvalid = true;
5022 break;
5023 } else if (dashArray[i] > 0) {
5024 numPositive++;
5025 }
5026 }
5027 if (isInvalid || numPositive === 0) {
5028 data.borderWidth = 0;
5029 }
5030 }
5031 }
5032 }
5033 }
5034
5035 this.appearance = getDefaultAppearance(dict);
5036 data.hasAppearance = !!this.appearance;
5037 data.id = params.ref.num;
5038 }
5039
5040 Annotation.prototype = {
5041
5042 getData: function Annotation_getData() {
5043 return this.data;
5044 },
5045
5046 isInvisible: function Annotation_isInvisible() {
5047 var data = this.data;
5048 if (data && SUPPORTED_TYPES.indexOf(data.subtype) !== -1) {
5049 return false;
5050 } else {
5051 return !!(data &&
5052 data.annotationFlags && // Default: not invisible
5053 data.annotationFlags & 0x1); // Invisible
5054 }
5055 },
5056
5057 isViewable: function Annotation_isViewable() {
5058 var data = this.data;
5059 return !!(!this.isInvisible() &&
5060 data &&
5061 (!data.annotationFlags ||
5062 !(data.annotationFlags & 0x22)) && // Hidden or NoView
5063 data.rect); // rectangle is necessary
5064 },
5065
5066 isPrintable: function Annotation_isPrintable() {
5067 var data = this.data;
5068 return !!(!this.isInvisible() &&
5069 data &&
5070 data.annotationFlags && // Default: not printable
5071 data.annotationFlags & 0x4 && // Print
5072 !(data.annotationFlags & 0x2) && // Hidden
5073 data.rect); // rectangle is necessary
5074 },
5075
5076 loadResources: function Annotation_loadResources(keys) {
5077 return new Promise(function (resolve, reject) {
5078 this.appearance.dict.getAsync('Resources').then(function (resources) {
5079 if (!resources) {
5080 resolve();
5081 return;
5082 }
5083 var objectLoader = new ObjectLoader(resources.map,
5084 keys,
5085 resources.xref);
5086 objectLoader.load().then(function() {
5087 resolve(resources);
5088 }, reject);
5089 }, reject);
5090 }.bind(this));
5091 },
5092
5093 getOperatorList: function Annotation_getOperatorList(evaluator) {
5094
5095 if (!this.appearance) {
5096 return Promise.resolve(new OperatorList());
5097 }
5098
5099 var data = this.data;
5100
5101 var appearanceDict = this.appearance.dict;
5102 var resourcesPromise = this.loadResources([
5103 'ExtGState',
5104 'ColorSpace',
5105 'Pattern',
5106 'Shading',
5107 'XObject',
5108 'Font'
5109 // ProcSet
5110 // Properties
5111 ]);
5112 var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
5113 var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
5114 var transform = getTransformMatrix(data.rect, bbox, matrix);
5115 var self = this;
5116
5117 return resourcesPromise.then(function(resources) {
5118 var opList = new OperatorList();
5119 opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
5120 return evaluator.getOperatorList(self.appearance, resources, opList).
5121 then(function () {
5122 opList.addOp(OPS.endAnnotation, []);
5123 self.appearance.reset();
5124 return opList;
5125 });
5126 });
5127 }
5128 };
5129
5130 Annotation.getConstructor =
5131 function Annotation_getConstructor(subtype, fieldType) {
5132
5133 if (!subtype) {
5134 return;
5135 }
5136
5137 // TODO(mack): Implement FreeText annotations
5138 if (subtype === 'Link') {
5139 return LinkAnnotation;
5140 } else if (subtype === 'Text') {
5141 return TextAnnotation;
5142 } else if (subtype === 'Widget') {
5143 if (!fieldType) {
5144 return;
5145 }
5146
5147 if (fieldType === 'Tx') {
5148 return TextWidgetAnnotation;
5149 } else {
5150 return WidgetAnnotation;
5151 }
5152 } else {
5153 return Annotation;
5154 }
5155 };
5156
5157 Annotation.fromRef = function Annotation_fromRef(xref, ref) {
5158
5159 var dict = xref.fetchIfRef(ref);
5160 if (!isDict(dict)) {
5161 return;
5162 }
5163
5164 var subtype = dict.get('Subtype');
5165 subtype = isName(subtype) ? subtype.name : '';
5166 if (!subtype) {
5167 return;
5168 }
5169
5170 var fieldType = Util.getInheritableProperty(dict, 'FT');
5171 fieldType = isName(fieldType) ? fieldType.name : '';
5172
5173 var Constructor = Annotation.getConstructor(subtype, fieldType);
5174 if (!Constructor) {
5175 return;
5176 }
5177
5178 var params = {
5179 dict: dict,
5180 ref: ref,
5181 };
5182
5183 var annotation = new Constructor(params);
5184
5185 if (annotation.isViewable() || annotation.isPrintable()) {
5186 return annotation;
5187 } else {
5188 if (SUPPORTED_TYPES.indexOf(subtype) === -1) {
5189 warn('unimplemented annotation type: ' + subtype);
5190 }
5191 }
5192 };
5193
5194 Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
5195 annotations, opList, pdfManager, partialEvaluator, intent) {
5196
5197 function reject(e) {
5198 annotationsReadyCapability.reject(e);
5199 }
5200
5201 var annotationsReadyCapability = createPromiseCapability();
5202
5203 var annotationPromises = [];
5204 for (var i = 0, n = annotations.length; i < n; ++i) {
5205 if (intent === 'display' && annotations[i].isViewable() ||
5206 intent === 'print' && annotations[i].isPrintable()) {
5207 annotationPromises.push(
5208 annotations[i].getOperatorList(partialEvaluator));
5209 }
5210 }
5211 Promise.all(annotationPromises).then(function(datas) {
5212 opList.addOp(OPS.beginAnnotations, []);
5213 for (var i = 0, n = datas.length; i < n; ++i) {
5214 var annotOpList = datas[i];
5215 opList.addOpList(annotOpList);
5216 }
5217 opList.addOp(OPS.endAnnotations, []);
5218 annotationsReadyCapability.resolve();
5219 }, reject);
5220
5221 return annotationsReadyCapability.promise;
5222 };
5223
5224 return Annotation;
5225 })();
5226
5227 var WidgetAnnotation = (function WidgetAnnotationClosure() {
5228
5229 function WidgetAnnotation(params) {
5230 Annotation.call(this, params);
5231
5232 var dict = params.dict;
5233 var data = this.data;
5234
5235 data.fieldValue = stringToPDFString(
5236 Util.getInheritableProperty(dict, 'V') || '');
5237 data.alternativeText = stringToPDFString(dict.get('TU') || '');
5238 data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
5239 var fieldType = Util.getInheritableProperty(dict, 'FT');
5240 data.fieldType = isName(fieldType) ? fieldType.name : '';
5241 data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
5242 this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
5243
5244 // Building the full field name by collecting the field and
5245 // its ancestors 'T' data and joining them using '.'.
5246 var fieldName = [];
5247 var namedItem = dict;
5248 var ref = params.ref;
5249 while (namedItem) {
5250 var parent = namedItem.get('Parent');
5251 var parentRef = namedItem.getRaw('Parent');
5252 var name = namedItem.get('T');
5253 if (name) {
5254 fieldName.unshift(stringToPDFString(name));
5255 } else if (parent && ref) {
5256 // The field name is absent, that means more than one field
5257 // with the same name may exist. Replacing the empty name
5258 // with the '`' plus index in the parent's 'Kids' array.
5259 // This is not in the PDF spec but necessary to id the
5260 // the input controls.
5261 var kids = parent.get('Kids');
5262 var j, jj;
5263 for (j = 0, jj = kids.length; j < jj; j++) {
5264 var kidRef = kids[j];
5265 if (kidRef.num === ref.num && kidRef.gen === ref.gen) {
5266 break;
5267 }
5268 }
5269 fieldName.unshift('`' + j);
5270 }
5271 namedItem = parent;
5272 ref = parentRef;
5273 }
5274 data.fullName = fieldName.join('.');
5275 }
5276
5277 var parent = Annotation.prototype;
5278 Util.inherit(WidgetAnnotation, Annotation, {
5279 isViewable: function WidgetAnnotation_isViewable() {
5280 if (this.data.fieldType === 'Sig') {
5281 warn('unimplemented annotation type: Widget signature');
5282 return false;
5283 }
5284
5285 return parent.isViewable.call(this);
5286 }
5287 });
5288
5289 return WidgetAnnotation;
5290 })();
5291
5292 var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
5293 function TextWidgetAnnotation(params) {
5294 WidgetAnnotation.call(this, params);
5295
5296 this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q');
5297 this.data.annotationType = AnnotationType.WIDGET;
5298 this.data.hasHtml = !this.data.hasAppearance && !!this.data.fieldValue;
5299 }
5300
5301 Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
5302 getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
5303 if (this.appearance) {
5304 return Annotation.prototype.getOperatorList.call(this, evaluator);
5305 }
5306
5307 var opList = new OperatorList();
5308 var data = this.data;
5309
5310 // Even if there is an appearance stream, ignore it. This is the
5311 // behaviour used by Adobe Reader.
5312 if (!data.defaultAppearance) {
5313 return Promise.resolve(opList);
5314 }
5315
5316 var stream = new Stream(stringToBytes(data.defaultAppearance));
5317 return evaluator.getOperatorList(stream, this.fieldResources, opList).
5318 then(function () {
5319 return opList;
5320 });
5321 }
5322 });
5323
5324 return TextWidgetAnnotation;
5325 })();
5326
5327 var InteractiveAnnotation = (function InteractiveAnnotationClosure() {
5328 function InteractiveAnnotation(params) {
5329 Annotation.call(this, params);
5330
5331 this.data.hasHtml = true;
5332 }
5333
5334 Util.inherit(InteractiveAnnotation, Annotation, { });
5335
5336 return InteractiveAnnotation;
5337 })();
5338
5339 var TextAnnotation = (function TextAnnotationClosure() {
5340 function TextAnnotation(params) {
5341 InteractiveAnnotation.call(this, params);
5342
5343 var dict = params.dict;
5344 var data = this.data;
5345
5346 var content = dict.get('Contents');
5347 var title = dict.get('T');
5348 data.annotationType = AnnotationType.TEXT;
5349 data.content = stringToPDFString(content || '');
5350 data.title = stringToPDFString(title || '');
5351
5352 if (data.hasAppearance) {
5353 data.name = 'NoIcon';
5354 } else {
5355 data.rect[1] = data.rect[3] - DEFAULT_ICON_SIZE;
5356 data.rect[2] = data.rect[0] + DEFAULT_ICON_SIZE;
5357 data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
5358 }
5359
5360 if (dict.has('C')) {
5361 data.hasBgColor = true;
5362 }
5363 }
5364
5365 Util.inherit(TextAnnotation, InteractiveAnnotation, { });
5366
5367 return TextAnnotation;
5368 })();
5369
5370 var LinkAnnotation = (function LinkAnnotationClosure() {
5371 function LinkAnnotation(params) {
5372 InteractiveAnnotation.call(this, params);
5373
5374 var dict = params.dict;
5375 var data = this.data;
5376 data.annotationType = AnnotationType.LINK;
5377
5378 var action = dict.get('A');
5379 if (action && isDict(action)) {
5380 var linkType = action.get('S').name;
5381 if (linkType === 'URI') {
5382 var url = action.get('URI');
5383 if (isName(url)) {
5384 // Some bad PDFs do not put parentheses around relative URLs.
5385 url = '/' + url.name;
5386 } else if (url) {
5387 url = addDefaultProtocolToUrl(url);
5388 }
5389 // TODO: pdf spec mentions urls can be relative to a Base
5390 // entry in the dictionary.
5391 if (!isValidUrl(url, false)) {
5392 url = '';
5393 }
5394 data.url = url;
5395 } else if (linkType === 'GoTo') {
5396 data.dest = action.get('D');
5397 } else if (linkType === 'GoToR') {
5398 var urlDict = action.get('F');
5399 if (isDict(urlDict)) {
5400 // We assume that the 'url' is a Filspec dictionary
5401 // and fetch the url without checking any further
5402 url = urlDict.get('F') || '';
5403 }
5404
5405 // TODO: pdf reference says that GoToR
5406 // can also have 'NewWindow' attribute
5407 if (!isValidUrl(url, false)) {
5408 url = '';
5409 }
5410 data.url = url;
5411 data.dest = action.get('D');
5412 } else if (linkType === 'Named') {
5413 data.action = action.get('N').name;
5414 } else {
5415 warn('unrecognized link type: ' + linkType);
5416 }
5417 } else if (dict.has('Dest')) {
5418 // simple destination link
5419 var dest = dict.get('Dest');
5420 data.dest = isName(dest) ? dest.name : dest;
5421 }
5422 }
5423
5424 // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
5425 function addDefaultProtocolToUrl(url) {
5426 if (url && url.indexOf('www.') === 0) {
5427 return ('http://' + url);
5428 }
5429 return url;
5430 }
5431
5432 Util.inherit(LinkAnnotation, InteractiveAnnotation, { });
5433
5434 return LinkAnnotation;
5435 })();
5436
5437
5438 var PDFFunction = (function PDFFunctionClosure() {
5439 var CONSTRUCT_SAMPLED = 0;
5440 var CONSTRUCT_INTERPOLATED = 2;
5441 var CONSTRUCT_STICHED = 3;
5442 var CONSTRUCT_POSTSCRIPT = 4;
5443
5444 return {
5445 getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
5446 str) {
5447 var i, ii;
5448 var length = 1;
5449 for (i = 0, ii = size.length; i < ii; i++) {
5450 length *= size[i];
5451 }
5452 length *= outputSize;
5453
5454 var array = new Array(length);
5455 var codeSize = 0;
5456 var codeBuf = 0;
5457 // 32 is a valid bps so shifting won't work
5458 var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
5459
5460 var strBytes = str.getBytes((length * bps + 7) / 8);
5461 var strIdx = 0;
5462 for (i = 0; i < length; i++) {
5463 while (codeSize < bps) {
5464 codeBuf <<= 8;
5465 codeBuf |= strBytes[strIdx++];
5466 codeSize += 8;
5467 }
5468 codeSize -= bps;
5469 array[i] = (codeBuf >> codeSize) * sampleMul;
5470 codeBuf &= (1 << codeSize) - 1;
5471 }
5472 return array;
5473 },
5474
5475 getIR: function PDFFunction_getIR(xref, fn) {
5476 var dict = fn.dict;
5477 if (!dict) {
5478 dict = fn;
5479 }
5480
5481 var types = [this.constructSampled,
5482 null,
5483 this.constructInterpolated,
5484 this.constructStiched,
5485 this.constructPostScript];
5486
5487 var typeNum = dict.get('FunctionType');
5488 var typeFn = types[typeNum];
5489 if (!typeFn) {
5490 error('Unknown type of function');
5491 }
5492
5493 return typeFn.call(this, fn, dict, xref);
5494 },
5495
5496 fromIR: function PDFFunction_fromIR(IR) {
5497 var type = IR[0];
5498 switch (type) {
5499 case CONSTRUCT_SAMPLED:
5500 return this.constructSampledFromIR(IR);
5501 case CONSTRUCT_INTERPOLATED:
5502 return this.constructInterpolatedFromIR(IR);
5503 case CONSTRUCT_STICHED:
5504 return this.constructStichedFromIR(IR);
5505 //case CONSTRUCT_POSTSCRIPT:
5506 default:
5507 return this.constructPostScriptFromIR(IR);
5508 }
5509 },
5510
5511 parse: function PDFFunction_parse(xref, fn) {
5512 var IR = this.getIR(xref, fn);
5513 return this.fromIR(IR);
5514 },
5515
5516 parseArray: function PDFFunction_parseArray(xref, fnObj) {
5517 if (!isArray(fnObj)) {
5518 // not an array -- parsing as regular function
5519 return this.parse(xref, fnObj);
5520 }
5521
5522 var fnArray = [];
5523 for (var j = 0, jj = fnObj.length; j < jj; j++) {
5524 var obj = xref.fetchIfRef(fnObj[j]);
5525 fnArray.push(PDFFunction.parse(xref, obj));
5526 }
5527 return function (src, srcOffset, dest, destOffset) {
5528 for (var i = 0, ii = fnArray.length; i < ii; i++) {
5529 fnArray[i](src, srcOffset, dest, destOffset + i);
5530 }
5531 };
5532 },
5533
5534 constructSampled: function PDFFunction_constructSampled(str, dict) {
5535 function toMultiArray(arr) {
5536 var inputLength = arr.length;
5537 var out = [];
5538 var index = 0;
5539 for (var i = 0; i < inputLength; i += 2) {
5540 out[index] = [arr[i], arr[i + 1]];
5541 ++index;
5542 }
5543 return out;
5544 }
5545 var domain = dict.get('Domain');
5546 var range = dict.get('Range');
5547
5548 if (!domain || !range) {
5549 error('No domain or range');
5550 }
5551
5552 var inputSize = domain.length / 2;
5553 var outputSize = range.length / 2;
5554
5555 domain = toMultiArray(domain);
5556 range = toMultiArray(range);
5557
5558 var size = dict.get('Size');
5559 var bps = dict.get('BitsPerSample');
5560 var order = dict.get('Order') || 1;
5561 if (order !== 1) {
5562 // No description how cubic spline interpolation works in PDF32000:2008
5563 // As in poppler, ignoring order, linear interpolation may work as good
5564 info('No support for cubic spline interpolation: ' + order);
5565 }
5566
5567 var encode = dict.get('Encode');
5568 if (!encode) {
5569 encode = [];
5570 for (var i = 0; i < inputSize; ++i) {
5571 encode.push(0);
5572 encode.push(size[i] - 1);
5573 }
5574 }
5575 encode = toMultiArray(encode);
5576
5577 var decode = dict.get('Decode');
5578 if (!decode) {
5579 decode = range;
5580 } else {
5581 decode = toMultiArray(decode);
5582 }
5583
5584 var samples = this.getSampleArray(size, outputSize, bps, str);
5585
5586 return [
5587 CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
5588 outputSize, Math.pow(2, bps) - 1, range
5589 ];
5590 },
5591
5592 constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
5593 // See chapter 3, page 109 of the PDF reference
5594 function interpolate(x, xmin, xmax, ymin, ymax) {
5595 return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin)));
5596 }
5597
5598 return function constructSampledFromIRResult(src, srcOffset,
5599 dest, destOffset) {
5600 // See chapter 3, page 110 of the PDF reference.
5601 var m = IR[1];
5602 var domain = IR[2];
5603 var encode = IR[3];
5604 var decode = IR[4];
5605 var samples = IR[5];
5606 var size = IR[6];
5607 var n = IR[7];
5608 //var mask = IR[8];
5609 var range = IR[9];
5610
5611 // Building the cube vertices: its part and sample index
5612 // http://rjwagner49.com/Mathematics/Interpolation.pdf
5613 var cubeVertices = 1 << m;
5614 var cubeN = new Float64Array(cubeVertices);
5615 var cubeVertex = new Uint32Array(cubeVertices);
5616 var i, j;
5617 for (j = 0; j < cubeVertices; j++) {
5618 cubeN[j] = 1;
5619 }
5620
5621 var k = n, pos = 1;
5622 // Map x_i to y_j for 0 <= i < m using the sampled function.
5623 for (i = 0; i < m; ++i) {
5624 // x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
5625 var domain_2i = domain[i][0];
5626 var domain_2i_1 = domain[i][1];
5627 var xi = Math.min(Math.max(src[srcOffset +i], domain_2i),
5628 domain_2i_1);
5629
5630 // e_i = Interpolate(x_i', Domain_2i, Domain_2i+1,
5631 // Encode_2i, Encode_2i+1)
5632 var e = interpolate(xi, domain_2i, domain_2i_1,
5633 encode[i][0], encode[i][1]);
5634
5635 // e_i' = min(max(e_i, 0), Size_i - 1)
5636 var size_i = size[i];
5637 e = Math.min(Math.max(e, 0), size_i - 1);
5638
5639 // Adjusting the cube: N and vertex sample index
5640 var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1;
5641 var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
5642 var n1 = e - e0; // (e - e0) / (e1 - e0);
5643 var offset0 = e0 * k;
5644 var offset1 = offset0 + k; // e1 * k
5645 for (j = 0; j < cubeVertices; j++) {
5646 if (j & pos) {
5647 cubeN[j] *= n1;
5648 cubeVertex[j] += offset1;
5649 } else {
5650 cubeN[j] *= n0;
5651 cubeVertex[j] += offset0;
5652 }
5653 }
5654
5655 k *= size_i;
5656 pos <<= 1;
5657 }
5658
5659 for (j = 0; j < n; ++j) {
5660 // Sum all cube vertices' samples portions
5661 var rj = 0;
5662 for (i = 0; i < cubeVertices; i++) {
5663 rj += samples[cubeVertex[i] + j] * cubeN[i];
5664 }
5665
5666 // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1,
5667 // Decode_2j, Decode_2j+1)
5668 rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
5669
5670 // y_j = min(max(r_j, range_2j), range_2j+1)
5671 dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]),
5672 range[j][1]);
5673 }
5674 };
5675 },
5676
5677 constructInterpolated: function PDFFunction_constructInterpolated(str,
5678 dict) {
5679 var c0 = dict.get('C0') || [0];
5680 var c1 = dict.get('C1') || [1];
5681 var n = dict.get('N');
5682
5683 if (!isArray(c0) || !isArray(c1)) {
5684 error('Illegal dictionary for interpolated function');
5685 }
5686
5687 var length = c0.length;
5688 var diff = [];
5689 for (var i = 0; i < length; ++i) {
5690 diff.push(c1[i] - c0[i]);
5691 }
5692
5693 return [CONSTRUCT_INTERPOLATED, c0, diff, n];
5694 },
5695
5696 constructInterpolatedFromIR:
5697 function PDFFunction_constructInterpolatedFromIR(IR) {
5698 var c0 = IR[1];
5699 var diff = IR[2];
5700 var n = IR[3];
5701
5702 var length = diff.length;
5703
5704 return function constructInterpolatedFromIRResult(src, srcOffset,
5705 dest, destOffset) {
5706 var x = n === 1 ? src[srcOffset] : Math.pow(src[srcOffset], n);
5707
5708 for (var j = 0; j < length; ++j) {
5709 dest[destOffset + j] = c0[j] + (x * diff[j]);
5710 }
5711 };
5712 },
5713
5714 constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
5715 var domain = dict.get('Domain');
5716
5717 if (!domain) {
5718 error('No domain');
5719 }
5720
5721 var inputSize = domain.length / 2;
5722 if (inputSize !== 1) {
5723 error('Bad domain for stiched function');
5724 }
5725
5726 var fnRefs = dict.get('Functions');
5727 var fns = [];
5728 for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
5729 fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
5730 }
5731
5732 var bounds = dict.get('Bounds');
5733 var encode = dict.get('Encode');
5734
5735 return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
5736 },
5737
5738 constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
5739 var domain = IR[1];
5740 var bounds = IR[2];
5741 var encode = IR[3];
5742 var fnsIR = IR[4];
5743 var fns = [];
5744 var tmpBuf = new Float32Array(1);
5745
5746 for (var i = 0, ii = fnsIR.length; i < ii; i++) {
5747 fns.push(PDFFunction.fromIR(fnsIR[i]));
5748 }
5749
5750 return function constructStichedFromIRResult(src, srcOffset,
5751 dest, destOffset) {
5752 var clip = function constructStichedFromIRClip(v, min, max) {
5753 if (v > max) {
5754 v = max;
5755 } else if (v < min) {
5756 v = min;
5757 }
5758 return v;
5759 };
5760
5761 // clip to domain
5762 var v = clip(src[srcOffset], domain[0], domain[1]);
5763 // calulate which bound the value is in
5764 for (var i = 0, ii = bounds.length; i < ii; ++i) {
5765 if (v < bounds[i]) {
5766 break;
5767 }
5768 }
5769
5770 // encode value into domain of function
5771 var dmin = domain[0];
5772 if (i > 0) {
5773 dmin = bounds[i - 1];
5774 }
5775 var dmax = domain[1];
5776 if (i < bounds.length) {
5777 dmax = bounds[i];
5778 }
5779
5780 var rmin = encode[2 * i];
5781 var rmax = encode[2 * i + 1];
5782
5783 tmpBuf[0] = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
5784
5785 // call the appropriate function
5786 fns[i](tmpBuf, 0, dest, destOffset);
5787 };
5788 },
5789
5790 constructPostScript: function PDFFunction_constructPostScript(fn, dict,
5791 xref) {
5792 var domain = dict.get('Domain');
5793 var range = dict.get('Range');
5794
5795 if (!domain) {
5796 error('No domain.');
5797 }
5798
5799 if (!range) {
5800 error('No range.');
5801 }
5802
5803 var lexer = new PostScriptLexer(fn);
5804 var parser = new PostScriptParser(lexer);
5805 var code = parser.parse();
5806
5807 return [CONSTRUCT_POSTSCRIPT, domain, range, code];
5808 },
5809
5810 constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(
5811 IR) {
5812 var domain = IR[1];
5813 var range = IR[2];
5814 var code = IR[3];
5815
5816 var compiled = (new PostScriptCompiler()).compile(code, domain, range);
5817 if (compiled) {
5818 // Compiled function consists of simple expressions such as addition,
5819 // subtraction, Math.max, and also contains 'var' and 'return'
5820 // statements. See the generation in the PostScriptCompiler below.
5821 /*jshint -W054 */
5822 return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);
5823 }
5824
5825 info('Unable to compile PS function');
5826
5827 var numOutputs = range.length >> 1;
5828 var numInputs = domain.length >> 1;
5829 var evaluator = new PostScriptEvaluator(code);
5830 // Cache the values for a big speed up, the cache size is limited though
5831 // since the number of possible values can be huge from a PS function.
5832 var cache = {};
5833 // The MAX_CACHE_SIZE is set to ~4x the maximum number of distinct values
5834 // seen in our tests.
5835 var MAX_CACHE_SIZE = 2048 * 4;
5836 var cache_available = MAX_CACHE_SIZE;
5837 var tmpBuf = new Float32Array(numInputs);
5838
5839 return function constructPostScriptFromIRResult(src, srcOffset,
5840 dest, destOffset) {
5841 var i, value;
5842 var key = '';
5843 var input = tmpBuf;
5844 for (i = 0; i < numInputs; i++) {
5845 value = src[srcOffset + i];
5846 input[i] = value;
5847 key += value + '_';
5848 }
5849
5850 var cachedValue = cache[key];
5851 if (cachedValue !== undefined) {
5852 dest.set(cachedValue, destOffset);
5853 return;
5854 }
5855
5856 var output = new Float32Array(numOutputs);
5857 var stack = evaluator.execute(input);
5858 var stackIndex = stack.length - numOutputs;
5859 for (i = 0; i < numOutputs; i++) {
5860 value = stack[stackIndex + i];
5861 var bound = range[i * 2];
5862 if (value < bound) {
5863 value = bound;
5864 } else {
5865 bound = range[i * 2 +1];
5866 if (value > bound) {
5867 value = bound;
5868 }
5869 }
5870 output[i] = value;
5871 }
5872 if (cache_available > 0) {
5873 cache_available--;
5874 cache[key] = output;
5875 }
5876 dest.set(output, destOffset);
5877 };
5878 }
5879 };
5880 })();
5881
5882 function isPDFFunction(v) {
5883 var fnDict;
5884 if (typeof v !== 'object') {
5885 return false;
5886 } else if (isDict(v)) {
5887 fnDict = v;
5888 } else if (isStream(v)) {
5889 fnDict = v.dict;
5890 } else {
5891 return false;
5892 }
5893 return fnDict.has('FunctionType');
5894 }
5895
5896 var PostScriptStack = (function PostScriptStackClosure() {
5897 var MAX_STACK_SIZE = 100;
5898 function PostScriptStack(initialStack) {
5899 this.stack = !initialStack ? [] :
5900 Array.prototype.slice.call(initialStack, 0);
5901 }
5902
5903 PostScriptStack.prototype = {
5904 push: function PostScriptStack_push(value) {
5905 if (this.stack.length >= MAX_STACK_SIZE) {
5906 error('PostScript function stack overflow.');
5907 }
5908 this.stack.push(value);
5909 },
5910 pop: function PostScriptStack_pop() {
5911 if (this.stack.length <= 0) {
5912 error('PostScript function stack underflow.');
5913 }
5914 return this.stack.pop();
5915 },
5916 copy: function PostScriptStack_copy(n) {
5917 if (this.stack.length + n >= MAX_STACK_SIZE) {
5918 error('PostScript function stack overflow.');
5919 }
5920 var stack = this.stack;
5921 for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {
5922 stack.push(stack[i]);
5923 }
5924 },
5925 index: function PostScriptStack_index(n) {
5926 this.push(this.stack[this.stack.length - n - 1]);
5927 },
5928 // rotate the last n stack elements p times
5929 roll: function PostScriptStack_roll(n, p) {
5930 var stack = this.stack;
5931 var l = stack.length - n;
5932 var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;
5933 for (i = l, j = r; i < j; i++, j--) {
5934 t = stack[i]; stack[i] = stack[j]; stack[j] = t;
5935 }
5936 for (i = l, j = c - 1; i < j; i++, j--) {
5937 t = stack[i]; stack[i] = stack[j]; stack[j] = t;
5938 }
5939 for (i = c, j = r; i < j; i++, j--) {
5940 t = stack[i]; stack[i] = stack[j]; stack[j] = t;
5941 }
5942 }
5943 };
5944 return PostScriptStack;
5945 })();
5946 var PostScriptEvaluator = (function PostScriptEvaluatorClosure() {
5947 function PostScriptEvaluator(operators) {
5948 this.operators = operators;
5949 }
5950 PostScriptEvaluator.prototype = {
5951 execute: function PostScriptEvaluator_execute(initialStack) {
5952 var stack = new PostScriptStack(initialStack);
5953 var counter = 0;
5954 var operators = this.operators;
5955 var length = operators.length;
5956 var operator, a, b;
5957 while (counter < length) {
5958 operator = operators[counter++];
5959 if (typeof operator === 'number') {
5960 // Operator is really an operand and should be pushed to the stack.
5961 stack.push(operator);
5962 continue;
5963 }
5964 switch (operator) {
5965 // non standard ps operators
5966 case 'jz': // jump if false
5967 b = stack.pop();
5968 a = stack.pop();
5969 if (!a) {
5970 counter = b;
5971 }
5972 break;
5973 case 'j': // jump
5974 a = stack.pop();
5975 counter = a;
5976 break;
5977
5978 // all ps operators in alphabetical order (excluding if/ifelse)
5979 case 'abs':
5980 a = stack.pop();
5981 stack.push(Math.abs(a));
5982 break;
5983 case 'add':
5984 b = stack.pop();
5985 a = stack.pop();
5986 stack.push(a + b);
5987 break;
5988 case 'and':
5989 b = stack.pop();
5990 a = stack.pop();
5991 if (isBool(a) && isBool(b)) {
5992 stack.push(a && b);
5993 } else {
5994 stack.push(a & b);
5995 }
5996 break;
5997 case 'atan':
5998 a = stack.pop();
5999 stack.push(Math.atan(a));
6000 break;
6001 case 'bitshift':
6002 b = stack.pop();
6003 a = stack.pop();
6004 if (a > 0) {
6005 stack.push(a << b);
6006 } else {
6007 stack.push(a >> b);
6008 }
6009 break;
6010 case 'ceiling':
6011 a = stack.pop();
6012 stack.push(Math.ceil(a));
6013 break;
6014 case 'copy':
6015 a = stack.pop();
6016 stack.copy(a);
6017 break;
6018 case 'cos':
6019 a = stack.pop();
6020 stack.push(Math.cos(a));
6021 break;
6022 case 'cvi':
6023 a = stack.pop() | 0;
6024 stack.push(a);
6025 break;
6026 case 'cvr':
6027 // noop
6028 break;
6029 case 'div':
6030 b = stack.pop();
6031 a = stack.pop();
6032 stack.push(a / b);
6033 break;
6034 case 'dup':
6035 stack.copy(1);
6036 break;
6037 case 'eq':
6038 b = stack.pop();
6039 a = stack.pop();
6040 stack.push(a === b);
6041 break;
6042 case 'exch':
6043 stack.roll(2, 1);
6044 break;
6045 case 'exp':
6046 b = stack.pop();
6047 a = stack.pop();
6048 stack.push(Math.pow(a, b));
6049 break;
6050 case 'false':
6051 stack.push(false);
6052 break;
6053 case 'floor':
6054 a = stack.pop();
6055 stack.push(Math.floor(a));
6056 break;
6057 case 'ge':
6058 b = stack.pop();
6059 a = stack.pop();
6060 stack.push(a >= b);
6061 break;
6062 case 'gt':
6063 b = stack.pop();
6064 a = stack.pop();
6065 stack.push(a > b);
6066 break;
6067 case 'idiv':
6068 b = stack.pop();
6069 a = stack.pop();
6070 stack.push((a / b) | 0);
6071 break;
6072 case 'index':
6073 a = stack.pop();
6074 stack.index(a);
6075 break;
6076 case 'le':
6077 b = stack.pop();
6078 a = stack.pop();
6079 stack.push(a <= b);
6080 break;
6081 case 'ln':
6082 a = stack.pop();
6083 stack.push(Math.log(a));
6084 break;
6085 case 'log':
6086 a = stack.pop();
6087 stack.push(Math.log(a) / Math.LN10);
6088 break;
6089 case 'lt':
6090 b = stack.pop();
6091 a = stack.pop();
6092 stack.push(a < b);
6093 break;
6094 case 'mod':
6095 b = stack.pop();
6096 a = stack.pop();
6097 stack.push(a % b);
6098 break;
6099 case 'mul':
6100 b = stack.pop();
6101 a = stack.pop();
6102 stack.push(a * b);
6103 break;
6104 case 'ne':
6105 b = stack.pop();
6106 a = stack.pop();
6107 stack.push(a !== b);
6108 break;
6109 case 'neg':
6110 a = stack.pop();
6111 stack.push(-a);
6112 break;
6113 case 'not':
6114 a = stack.pop();
6115 if (isBool(a)) {
6116 stack.push(!a);
6117 } else {
6118 stack.push(~a);
6119 }
6120 break;
6121 case 'or':
6122 b = stack.pop();
6123 a = stack.pop();
6124 if (isBool(a) && isBool(b)) {
6125 stack.push(a || b);
6126 } else {
6127 stack.push(a | b);
6128 }
6129 break;
6130 case 'pop':
6131 stack.pop();
6132 break;
6133 case 'roll':
6134 b = stack.pop();
6135 a = stack.pop();
6136 stack.roll(a, b);
6137 break;
6138 case 'round':
6139 a = stack.pop();
6140 stack.push(Math.round(a));
6141 break;
6142 case 'sin':
6143 a = stack.pop();
6144 stack.push(Math.sin(a));
6145 break;
6146 case 'sqrt':
6147 a = stack.pop();
6148 stack.push(Math.sqrt(a));
6149 break;
6150 case 'sub':
6151 b = stack.pop();
6152 a = stack.pop();
6153 stack.push(a - b);
6154 break;
6155 case 'true':
6156 stack.push(true);
6157 break;
6158 case 'truncate':
6159 a = stack.pop();
6160 a = a < 0 ? Math.ceil(a) : Math.floor(a);
6161 stack.push(a);
6162 break;
6163 case 'xor':
6164 b = stack.pop();
6165 a = stack.pop();
6166 if (isBool(a) && isBool(b)) {
6167 stack.push(a !== b);
6168 } else {
6169 stack.push(a ^ b);
6170 }
6171 break;
6172 default:
6173 error('Unknown operator ' + operator);
6174 break;
6175 }
6176 }
6177 return stack.stack;
6178 }
6179 };
6180 return PostScriptEvaluator;
6181 })();
6182
6183 // Most of the PDFs functions consist of simple operations such as:
6184 // roll, exch, sub, cvr, pop, index, dup, mul, if, gt, add.
6185 //
6186 // We can compile most of such programs, and at the same moment, we can
6187 // optimize some expressions using basic math properties. Keeping track of
6188 // min/max values will allow us to avoid extra Math.min/Math.max calls.
6189 var PostScriptCompiler = (function PostScriptCompilerClosure() {
6190 function AstNode(type) {
6191 this.type = type;
6192 }
6193 AstNode.prototype.visit = function (visitor) {
6194 throw new Error('abstract method');
6195 };
6196
6197 function AstArgument(index, min, max) {
6198 AstNode.call(this, 'args');
6199 this.index = index;
6200 this.min = min;
6201 this.max = max;
6202 }
6203 AstArgument.prototype = Object.create(AstNode.prototype);
6204 AstArgument.prototype.visit = function (visitor) {
6205 visitor.visitArgument(this);
6206 };
6207
6208 function AstLiteral(number) {
6209 AstNode.call(this, 'literal');
6210 this.number = number;
6211 this.min = number;
6212 this.max = number;
6213 }
6214 AstLiteral.prototype = Object.create(AstNode.prototype);
6215 AstLiteral.prototype.visit = function (visitor) {
6216 visitor.visitLiteral(this);
6217 };
6218
6219 function AstBinaryOperation(op, arg1, arg2, min, max) {
6220 AstNode.call(this, 'binary');
6221 this.op = op;
6222 this.arg1 = arg1;
6223 this.arg2 = arg2;
6224 this.min = min;
6225 this.max = max;
6226 }
6227 AstBinaryOperation.prototype = Object.create(AstNode.prototype);
6228 AstBinaryOperation.prototype.visit = function (visitor) {
6229 visitor.visitBinaryOperation(this);
6230 };
6231
6232 function AstMin(arg, max) {
6233 AstNode.call(this, 'max');
6234 this.arg = arg;
6235 this.min = arg.min;
6236 this.max = max;
6237 }
6238 AstMin.prototype = Object.create(AstNode.prototype);
6239 AstMin.prototype.visit = function (visitor) {
6240 visitor.visitMin(this);
6241 };
6242
6243 function AstVariable(index, min, max) {
6244 AstNode.call(this, 'var');
6245 this.index = index;
6246 this.min = min;
6247 this.max = max;
6248 }
6249 AstVariable.prototype = Object.create(AstNode.prototype);
6250 AstVariable.prototype.visit = function (visitor) {
6251 visitor.visitVariable(this);
6252 };
6253
6254 function AstVariableDefinition(variable, arg) {
6255 AstNode.call(this, 'definition');
6256 this.variable = variable;
6257 this.arg = arg;
6258 }
6259 AstVariableDefinition.prototype = Object.create(AstNode.prototype);
6260 AstVariableDefinition.prototype.visit = function (visitor) {
6261 visitor.visitVariableDefinition(this);
6262 };
6263
6264 function ExpressionBuilderVisitor() {
6265 this.parts = [];
6266 }
6267 ExpressionBuilderVisitor.prototype = {
6268 visitArgument: function (arg) {
6269 this.parts.push('Math.max(', arg.min, ', Math.min(',
6270 arg.max, ', src[srcOffset + ', arg.index, ']))');
6271 },
6272 visitVariable: function (variable) {
6273 this.parts.push('v', variable.index);
6274 },
6275 visitLiteral: function (literal) {
6276 this.parts.push(literal.number);
6277 },
6278 visitBinaryOperation: function (operation) {
6279 this.parts.push('(');
6280 operation.arg1.visit(this);
6281 this.parts.push(' ', operation.op, ' ');
6282 operation.arg2.visit(this);
6283 this.parts.push(')');
6284 },
6285 visitVariableDefinition: function (definition) {
6286 this.parts.push('var ');
6287 definition.variable.visit(this);
6288 this.parts.push(' = ');
6289 definition.arg.visit(this);
6290 this.parts.push(';');
6291 },
6292 visitMin: function (max) {
6293 this.parts.push('Math.min(');
6294 max.arg.visit(this);
6295 this.parts.push(', ', max.max, ')');
6296 },
6297 toString: function () {
6298 return this.parts.join('');
6299 }
6300 };
6301
6302 function buildAddOperation(num1, num2) {
6303 if (num2.type === 'literal' && num2.number === 0) {
6304 // optimization: second operand is 0
6305 return num1;
6306 }
6307 if (num1.type === 'literal' && num1.number === 0) {
6308 // optimization: first operand is 0
6309 return num2;
6310 }
6311 if (num2.type === 'literal' && num1.type === 'literal') {
6312 // optimization: operands operand are literals
6313 return new AstLiteral(num1.number + num2.number);
6314 }
6315 return new AstBinaryOperation('+', num1, num2,
6316 num1.min + num2.min, num1.max + num2.max);
6317 }
6318
6319 function buildMulOperation(num1, num2) {
6320 if (num2.type === 'literal') {
6321 // optimization: second operands is a literal...
6322 if (num2.number === 0) {
6323 return new AstLiteral(0); // and it's 0
6324 } else if (num2.number === 1) {
6325 return num1; // and it's 1
6326 } else if (num1.type === 'literal') {
6327 // ... and first operands is a literal too
6328 return new AstLiteral(num1.number * num2.number);
6329 }
6330 }
6331 if (num1.type === 'literal') {
6332 // optimization: first operands is a literal...
6333 if (num1.number === 0) {
6334 return new AstLiteral(0); // and it's 0
6335 } else if (num1.number === 1) {
6336 return num2; // and it's 1
6337 }
6338 }
6339 var min = Math.min(num1.min * num2.min, num1.min * num2.max,
6340 num1.max * num2.min, num1.max * num2.max);
6341 var max = Math.max(num1.min * num2.min, num1.min * num2.max,
6342 num1.max * num2.min, num1.max * num2.max);
6343 return new AstBinaryOperation('*', num1, num2, min, max);
6344 }
6345
6346 function buildSubOperation(num1, num2) {
6347 if (num2.type === 'literal') {
6348 // optimization: second operands is a literal...
6349 if (num2.number === 0) {
6350 return num1; // ... and it's 0
6351 } else if (num1.type === 'literal') {
6352 // ... and first operands is a literal too
6353 return new AstLiteral(num1.number - num2.number);
6354 }
6355 }
6356 if (num2.type === 'binary' && num2.op === '-' &&
6357 num1.type === 'literal' && num1.number === 1 &&
6358 num2.arg1.type === 'literal' && num2.arg1.number === 1) {
6359 // optimization for case: 1 - (1 - x)
6360 return num2.arg2;
6361 }
6362 return new AstBinaryOperation('-', num1, num2,
6363 num1.min - num2.max, num1.max - num2.min);
6364 }
6365
6366 function buildMinOperation(num1, max) {
6367 if (num1.min >= max) {
6368 // optimization: num1 min value is not less than required max
6369 return new AstLiteral(max); // just returning max
6370 } else if (num1.max <= max) {
6371 // optimization: num1 max value is not greater than required max
6372 return num1; // just returning an argument
6373 }
6374 return new AstMin(num1, max);
6375 }
6376
6377 function PostScriptCompiler() {}
6378 PostScriptCompiler.prototype = {
6379 compile: function PostScriptCompiler_compile(code, domain, range) {
6380 var stack = [];
6381 var i, ii;
6382 var instructions = [];
6383 var inputSize = domain.length >> 1, outputSize = range.length >> 1;
6384 var lastRegister = 0;
6385 var n, j, min, max;
6386 var num1, num2, ast1, ast2, tmpVar, item;
6387 for (i = 0; i < inputSize; i++) {
6388 stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1]));
6389 }
6390
6391 for (i = 0, ii = code.length; i < ii; i++) {
6392 item = code[i];
6393 if (typeof item === 'number') {
6394 stack.push(new AstLiteral(item));
6395 continue;
6396 }
6397
6398 switch (item) {
6399 case 'add':
6400 if (stack.length < 2) {
6401 return null;
6402 }
6403 num2 = stack.pop();
6404 num1 = stack.pop();
6405 stack.push(buildAddOperation(num1, num2));
6406 break;
6407 case 'cvr':
6408 if (stack.length < 1) {
6409 return null;
6410 }
6411 break;
6412 case 'mul':
6413 if (stack.length < 2) {
6414 return null;
6415 }
6416 num2 = stack.pop();
6417 num1 = stack.pop();
6418 stack.push(buildMulOperation(num1, num2));
6419 break;
6420 case 'sub':
6421 if (stack.length < 2) {
6422 return null;
6423 }
6424 num2 = stack.pop();
6425 num1 = stack.pop();
6426 stack.push(buildSubOperation(num1, num2));
6427 break;
6428 case 'exch':
6429 if (stack.length < 2) {
6430 return null;
6431 }
6432 ast1 = stack.pop(); ast2 = stack.pop();
6433 stack.push(ast1, ast2);
6434 break;
6435 case 'pop':
6436 if (stack.length < 1) {
6437 return null;
6438 }
6439 stack.pop();
6440 break;
6441 case 'index':
6442 if (stack.length < 1) {
6443 return null;
6444 }
6445 num1 = stack.pop();
6446 if (num1.type !== 'literal') {
6447 return null;
6448 }
6449 n = num1.number;
6450 if (n < 0 || (n|0) !== n || stack.length < n) {
6451 return null;
6452 }
6453 ast1 = stack[stack.length - n - 1];
6454 if (ast1.type === 'literal' || ast1.type === 'var') {
6455 stack.push(ast1);
6456 break;
6457 }
6458 tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
6459 stack[stack.length - n - 1] = tmpVar;
6460 stack.push(tmpVar);
6461 instructions.push(new AstVariableDefinition(tmpVar, ast1));
6462 break;
6463 case 'dup':
6464 if (stack.length < 1) {
6465 return null;
6466 }
6467 if (typeof code[i + 1] === 'number' && code[i + 2] === 'gt' &&
6468 code[i + 3] === i + 7 && code[i + 4] === 'jz' &&
6469 code[i + 5] === 'pop' && code[i + 6] === code[i + 1]) {
6470 // special case of the commands sequence for the min operation
6471 num1 = stack.pop();
6472 stack.push(buildMinOperation(num1, code[i + 1]));
6473 i += 6;
6474 break;
6475 }
6476 ast1 = stack[stack.length - 1];
6477 if (ast1.type === 'literal' || ast1.type === 'var') {
6478 // we don't have to save into intermediate variable a literal or
6479 // variable.
6480 stack.push(ast1);
6481 break;
6482 }
6483 tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
6484 stack[stack.length - 1] = tmpVar;
6485 stack.push(tmpVar);
6486 instructions.push(new AstVariableDefinition(tmpVar, ast1));
6487 break;
6488 case 'roll':
6489 if (stack.length < 2) {
6490 return null;
6491 }
6492 num2 = stack.pop();
6493 num1 = stack.pop();
6494 if (num2.type !== 'literal' || num1.type !== 'literal') {
6495 // both roll operands must be numbers
6496 return null;
6497 }
6498 j = num2.number;
6499 n = num1.number;
6500 if (n <= 0 || (n|0) !== n || (j|0) !== j || stack.length < n) {
6501 // ... and integers
6502 return null;
6503 }
6504 j = ((j % n) + n) % n;
6505 if (j === 0) {
6506 break; // just skipping -- there are nothing to rotate
6507 }
6508 Array.prototype.push.apply(stack,
6509 stack.splice(stack.length - n, n - j));
6510 break;
6511 default:
6512 return null; // unsupported operator
6513 }
6514 }
6515
6516 if (stack.length !== outputSize) {
6517 return null;
6518 }
6519
6520 var result = [];
6521 instructions.forEach(function (instruction) {
6522 var statementBuilder = new ExpressionBuilderVisitor();
6523 instruction.visit(statementBuilder);
6524 result.push(statementBuilder.toString());
6525 });
6526 stack.forEach(function (expr, i) {
6527 var statementBuilder = new ExpressionBuilderVisitor();
6528 expr.visit(statementBuilder);
6529 var min = range[i * 2], max = range[i * 2 + 1];
6530 var out = [statementBuilder.toString()];
6531 if (min > expr.min) {
6532 out.unshift('Math.max(', min, ', ');
6533 out.push(')');
6534 }
6535 if (max < expr.max) {
6536 out.unshift('Math.min(', max, ', ');
6537 out.push(')');
6538 }
6539 out.unshift('dest[destOffset + ', i, '] = ');
6540 out.push(';');
6541 result.push(out.join(''));
6542 });
6543 return result.join('\n');
6544 }
6545 };
6546
6547 return PostScriptCompiler;
6548 })();
6549
6550
6551 var ColorSpace = (function ColorSpaceClosure() {
6552 // Constructor should define this.numComps, this.defaultColor, this.name
6553 function ColorSpace() {
6554 error('should not call ColorSpace constructor');
6555 }
6556
6557 ColorSpace.prototype = {
6558 /**
6559 * Converts the color value to the RGB color. The color components are
6560 * located in the src array starting from the srcOffset. Returns the array
6561 * of the rgb components, each value ranging from [0,255].
6562 */
6563 getRgb: function ColorSpace_getRgb(src, srcOffset) {
6564 var rgb = new Uint8Array(3);
6565 this.getRgbItem(src, srcOffset, rgb, 0);
6566 return rgb;
6567 },
6568 /**
6569 * Converts the color value to the RGB color, similar to the getRgb method.
6570 * The result placed into the dest array starting from the destOffset.
6571 */
6572 getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,
6573 dest, destOffset) {
6574 error('Should not call ColorSpace.getRgbItem');
6575 },
6576 /**
6577 * Converts the specified number of the color values to the RGB colors.
6578 * The colors are located in the src array starting from the srcOffset.
6579 * The result is placed into the dest array starting from the destOffset.
6580 * The src array items shall be in [0,2^bits) range, the dest array items
6581 * will be in [0,255] range. alpha01 indicates how many alpha components
6582 * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA
6583 * array).
6584 */
6585 getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
6586 dest, destOffset, bits,
6587 alpha01) {
6588 error('Should not call ColorSpace.getRgbBuffer');
6589 },
6590 /**
6591 * Determines the number of bytes required to store the result of the
6592 * conversion done by the getRgbBuffer method. As in getRgbBuffer,
6593 * |alpha01| is either 0 (RGB output) or 1 (RGBA output).
6594 */
6595 getOutputLength: function ColorSpace_getOutputLength(inputLength,
6596 alpha01) {
6597 error('Should not call ColorSpace.getOutputLength');
6598 },
6599 /**
6600 * Returns true if source data will be equal the result/output data.
6601 */
6602 isPassthrough: function ColorSpace_isPassthrough(bits) {
6603 return false;
6604 },
6605 /**
6606 * Fills in the RGB colors in the destination buffer. alpha01 indicates
6607 * how many alpha components there are in the dest array; it will be either
6608 * 0 (RGB array) or 1 (RGBA array).
6609 */
6610 fillRgb: function ColorSpace_fillRgb(dest, originalWidth,
6611 originalHeight, width, height,
6612 actualHeight, bpc, comps, alpha01) {
6613 var count = originalWidth * originalHeight;
6614 var rgbBuf = null;
6615 var numComponentColors = 1 << bpc;
6616 var needsResizing = originalHeight !== height || originalWidth !== width;
6617 var i, ii;
6618
6619 if (this.isPassthrough(bpc)) {
6620 rgbBuf = comps;
6621 } else if (this.numComps === 1 && count > numComponentColors &&
6622 this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
6623 // Optimization: create a color map when there is just one component and
6624 // we are converting more colors than the size of the color map. We
6625 // don't build the map if the colorspace is gray or rgb since those
6626 // methods are faster than building a map. This mainly offers big speed
6627 // ups for indexed and alternate colorspaces.
6628 //
6629 // TODO it may be worth while to cache the color map. While running
6630 // testing I never hit a cache so I will leave that out for now (perhaps
6631 // we are reparsing colorspaces too much?).
6632 var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) :
6633 new Uint16Array(numComponentColors);
6634 var key;
6635 for (i = 0; i < numComponentColors; i++) {
6636 allColors[i] = i;
6637 }
6638 var colorMap = new Uint8Array(numComponentColors * 3);
6639 this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,
6640 /* alpha01 = */ 0);
6641
6642 var destPos, rgbPos;
6643 if (!needsResizing) {
6644 // Fill in the RGB values directly into |dest|.
6645 destPos = 0;
6646 for (i = 0; i < count; ++i) {
6647 key = comps[i] * 3;
6648 dest[destPos++] = colorMap[key];
6649 dest[destPos++] = colorMap[key + 1];
6650 dest[destPos++] = colorMap[key + 2];
6651 destPos += alpha01;
6652 }
6653 } else {
6654 rgbBuf = new Uint8Array(count * 3);
6655 rgbPos = 0;
6656 for (i = 0; i < count; ++i) {
6657 key = comps[i] * 3;
6658 rgbBuf[rgbPos++] = colorMap[key];
6659 rgbBuf[rgbPos++] = colorMap[key + 1];
6660 rgbBuf[rgbPos++] = colorMap[key + 2];
6661 }
6662 }
6663 } else {
6664 if (!needsResizing) {
6665 // Fill in the RGB values directly into |dest|.
6666 this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc,
6667 alpha01);
6668 } else {
6669 rgbBuf = new Uint8Array(count * 3);
6670 this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc,
6671 /* alpha01 = */ 0);
6672 }
6673 }
6674
6675 if (rgbBuf) {
6676 if (needsResizing) {
6677 PDFImage.resize(rgbBuf, bpc, 3, originalWidth, originalHeight, width,
6678 height, dest, alpha01);
6679 } else {
6680 rgbPos = 0;
6681 destPos = 0;
6682 for (i = 0, ii = width * actualHeight; i < ii; i++) {
6683 dest[destPos++] = rgbBuf[rgbPos++];
6684 dest[destPos++] = rgbBuf[rgbPos++];
6685 dest[destPos++] = rgbBuf[rgbPos++];
6686 destPos += alpha01;
6687 }
6688 }
6689 }
6690 },
6691 /**
6692 * True if the colorspace has components in the default range of [0, 1].
6693 * This should be true for all colorspaces except for lab color spaces
6694 * which are [0,100], [-128, 127], [-128, 127].
6695 */
6696 usesZeroToOneRange: true
6697 };
6698
6699 ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
6700 var IR = ColorSpace.parseToIR(cs, xref, res);
6701 if (IR instanceof AlternateCS) {
6702 return IR;
6703 }
6704 return ColorSpace.fromIR(IR);
6705 };
6706
6707 ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
6708 var name = isArray(IR) ? IR[0] : IR;
6709 var whitePoint, blackPoint, gamma;
6710
6711 switch (name) {
6712 case 'DeviceGrayCS':
6713 return this.singletons.gray;
6714 case 'DeviceRgbCS':
6715 return this.singletons.rgb;
6716 case 'DeviceCmykCS':
6717 return this.singletons.cmyk;
6718 case 'CalGrayCS':
6719 whitePoint = IR[1].WhitePoint;
6720 blackPoint = IR[1].BlackPoint;
6721 gamma = IR[1].Gamma;
6722 return new CalGrayCS(whitePoint, blackPoint, gamma);
6723 case 'CalRGBCS':
6724 whitePoint = IR[1].WhitePoint;
6725 blackPoint = IR[1].BlackPoint;
6726 gamma = IR[1].Gamma;
6727 var matrix = IR[1].Matrix;
6728 return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
6729 case 'PatternCS':
6730 var basePatternCS = IR[1];
6731 if (basePatternCS) {
6732 basePatternCS = ColorSpace.fromIR(basePatternCS);
6733 }
6734 return new PatternCS(basePatternCS);
6735 case 'IndexedCS':
6736 var baseIndexedCS = IR[1];
6737 var hiVal = IR[2];
6738 var lookup = IR[3];
6739 return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
6740 case 'AlternateCS':
6741 var numComps = IR[1];
6742 var alt = IR[2];
6743 var tintFnIR = IR[3];
6744
6745 return new AlternateCS(numComps, ColorSpace.fromIR(alt),
6746 PDFFunction.fromIR(tintFnIR));
6747 case 'LabCS':
6748 whitePoint = IR[1].WhitePoint;
6749 blackPoint = IR[1].BlackPoint;
6750 var range = IR[1].Range;
6751 return new LabCS(whitePoint, blackPoint, range);
6752 default:
6753 error('Unknown name ' + name);
6754 }
6755 return null;
6756 };
6757
6758 ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
6759 if (isName(cs)) {
6760 var colorSpaces = res.get('ColorSpace');
6761 if (isDict(colorSpaces)) {
6762 var refcs = colorSpaces.get(cs.name);
6763 if (refcs) {
6764 cs = refcs;
6765 }
6766 }
6767 }
6768
6769 cs = xref.fetchIfRef(cs);
6770 var mode;
6771
6772 if (isName(cs)) {
6773 mode = cs.name;
6774 this.mode = mode;
6775
6776 switch (mode) {
6777 case 'DeviceGray':
6778 case 'G':
6779 return 'DeviceGrayCS';
6780 case 'DeviceRGB':
6781 case 'RGB':
6782 return 'DeviceRgbCS';
6783 case 'DeviceCMYK':
6784 case 'CMYK':
6785 return 'DeviceCmykCS';
6786 case 'Pattern':
6787 return ['PatternCS', null];
6788 default:
6789 error('unrecognized colorspace ' + mode);
6790 }
6791 } else if (isArray(cs)) {
6792 mode = cs[0].name;
6793 this.mode = mode;
6794 var numComps, params;
6795
6796 switch (mode) {
6797 case 'DeviceGray':
6798 case 'G':
6799 return 'DeviceGrayCS';
6800 case 'DeviceRGB':
6801 case 'RGB':
6802 return 'DeviceRgbCS';
6803 case 'DeviceCMYK':
6804 case 'CMYK':
6805 return 'DeviceCmykCS';
6806 case 'CalGray':
6807 params = xref.fetchIfRef(cs[1]).getAll();
6808 return ['CalGrayCS', params];
6809 case 'CalRGB':
6810 params = xref.fetchIfRef(cs[1]).getAll();
6811 return ['CalRGBCS', params];
6812 case 'ICCBased':
6813 var stream = xref.fetchIfRef(cs[1]);
6814 var dict = stream.dict;
6815 numComps = dict.get('N');
6816 if (numComps === 1) {
6817 return 'DeviceGrayCS';
6818 } else if (numComps === 3) {
6819 return 'DeviceRgbCS';
6820 } else if (numComps === 4) {
6821 return 'DeviceCmykCS';
6822 }
6823 break;
6824 case 'Pattern':
6825 var basePatternCS = cs[1];
6826 if (basePatternCS) {
6827 basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
6828 }
6829 return ['PatternCS', basePatternCS];
6830 case 'Indexed':
6831 case 'I':
6832 var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
6833 var hiVal = cs[2] + 1;
6834 var lookup = xref.fetchIfRef(cs[3]);
6835 if (isStream(lookup)) {
6836 lookup = lookup.getBytes();
6837 }
6838 return ['IndexedCS', baseIndexedCS, hiVal, lookup];
6839 case 'Separation':
6840 case 'DeviceN':
6841 var name = cs[1];
6842 numComps = 1;
6843 if (isName(name)) {
6844 numComps = 1;
6845 } else if (isArray(name)) {
6846 numComps = name.length;
6847 }
6848 var alt = ColorSpace.parseToIR(cs[2], xref, res);
6849 var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
6850 return ['AlternateCS', numComps, alt, tintFnIR];
6851 case 'Lab':
6852 params = cs[1].getAll();
6853 return ['LabCS', params];
6854 default:
6855 error('unimplemented color space object "' + mode + '"');
6856 }
6857 } else {
6858 error('unrecognized color space object: "' + cs + '"');
6859 }
6860 return null;
6861 };
6862 /**
6863 * Checks if a decode map matches the default decode map for a color space.
6864 * This handles the general decode maps where there are two values per
6865 * component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
6866 * This does not handle Lab, Indexed, or Pattern decode maps since they are
6867 * slightly different.
6868 * @param {Array} decode Decode map (usually from an image).
6869 * @param {Number} n Number of components the color space has.
6870 */
6871 ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
6872 if (!decode) {
6873 return true;
6874 }
6875
6876 if (n * 2 !== decode.length) {
6877 warn('The decode map is not the correct length');
6878 return true;
6879 }
6880 for (var i = 0, ii = decode.length; i < ii; i += 2) {
6881 if (decode[i] !== 0 || decode[i + 1] !== 1) {
6882 return false;
6883 }
6884 }
6885 return true;
6886 };
6887
6888 ColorSpace.singletons = {
6889 get gray() {
6890 return shadow(this, 'gray', new DeviceGrayCS());
6891 },
6892 get rgb() {
6893 return shadow(this, 'rgb', new DeviceRgbCS());
6894 },
6895 get cmyk() {
6896 return shadow(this, 'cmyk', new DeviceCmykCS());
6897 }
6898 };
6899
6900 return ColorSpace;
6901 })();
6902
6903 /**
6904 * Alternate color space handles both Separation and DeviceN color spaces. A
6905 * Separation color space is actually just a DeviceN with one color component.
6906 * Both color spaces use a tinting function to convert colors to a base color
6907 * space.
6908 */
6909 var AlternateCS = (function AlternateCSClosure() {
6910 function AlternateCS(numComps, base, tintFn) {
6911 this.name = 'Alternate';
6912 this.numComps = numComps;
6913 this.defaultColor = new Float32Array(numComps);
6914 for (var i = 0; i < numComps; ++i) {
6915 this.defaultColor[i] = 1;
6916 }
6917 this.base = base;
6918 this.tintFn = tintFn;
6919 this.tmpBuf = new Float32Array(base.numComps);
6920 }
6921
6922 AlternateCS.prototype = {
6923 getRgb: ColorSpace.prototype.getRgb,
6924 getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
6925 dest, destOffset) {
6926 var tmpBuf = this.tmpBuf;
6927 this.tintFn(src, srcOffset, tmpBuf, 0);
6928 this.base.getRgbItem(tmpBuf, 0, dest, destOffset);
6929 },
6930 getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
6931 dest, destOffset, bits,
6932 alpha01) {
6933 var tintFn = this.tintFn;
6934 var base = this.base;
6935 var scale = 1 / ((1 << bits) - 1);
6936 var baseNumComps = base.numComps;
6937 var usesZeroToOneRange = base.usesZeroToOneRange;
6938 var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) &&
6939 alpha01 === 0;
6940 var pos = isPassthrough ? destOffset : 0;
6941 var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
6942 var numComps = this.numComps;
6943
6944 var scaled = new Float32Array(numComps);
6945 var tinted = new Float32Array(baseNumComps);
6946 var i, j;
6947 if (usesZeroToOneRange) {
6948 for (i = 0; i < count; i++) {
6949 for (j = 0; j < numComps; j++) {
6950 scaled[j] = src[srcOffset++] * scale;
6951 }
6952 tintFn(scaled, 0, tinted, 0);
6953 for (j = 0; j < baseNumComps; j++) {
6954 baseBuf[pos++] = tinted[j] * 255;
6955 }
6956 }
6957 } else {
6958 for (i = 0; i < count; i++) {
6959 for (j = 0; j < numComps; j++) {
6960 scaled[j] = src[srcOffset++] * scale;
6961 }
6962 tintFn(scaled, 0, tinted, 0);
6963 base.getRgbItem(tinted, 0, baseBuf, pos);
6964 pos += baseNumComps;
6965 }
6966 }
6967 if (!isPassthrough) {
6968 base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
6969 }
6970 },
6971 getOutputLength: function AlternateCS_getOutputLength(inputLength,
6972 alpha01) {
6973 return this.base.getOutputLength(inputLength *
6974 this.base.numComps / this.numComps,
6975 alpha01);
6976 },
6977 isPassthrough: ColorSpace.prototype.isPassthrough,
6978 fillRgb: ColorSpace.prototype.fillRgb,
6979 isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
6980 return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
6981 },
6982 usesZeroToOneRange: true
6983 };
6984
6985 return AlternateCS;
6986 })();
6987
6988 var PatternCS = (function PatternCSClosure() {
6989 function PatternCS(baseCS) {
6990 this.name = 'Pattern';
6991 this.base = baseCS;
6992 }
6993 PatternCS.prototype = {};
6994
6995 return PatternCS;
6996 })();
6997
6998 var IndexedCS = (function IndexedCSClosure() {
6999 function IndexedCS(base, highVal, lookup) {
7000 this.name = 'Indexed';
7001 this.numComps = 1;
7002 this.defaultColor = new Uint8Array([0]);
7003 this.base = base;
7004 this.highVal = highVal;
7005
7006 var baseNumComps = base.numComps;
7007 var length = baseNumComps * highVal;
7008 var lookupArray;
7009
7010 if (isStream(lookup)) {
7011 lookupArray = new Uint8Array(length);
7012 var bytes = lookup.getBytes(length);
7013 lookupArray.set(bytes);
7014 } else if (isString(lookup)) {
7015 lookupArray = new Uint8Array(length);
7016 for (var i = 0; i < length; ++i) {
7017 lookupArray[i] = lookup.charCodeAt(i);
7018 }
7019 } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
7020 lookupArray = lookup;
7021 } else {
7022 error('Unrecognized lookup table: ' + lookup);
7023 }
7024 this.lookup = lookupArray;
7025 }
7026
7027 IndexedCS.prototype = {
7028 getRgb: ColorSpace.prototype.getRgb,
7029 getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
7030 dest, destOffset) {
7031 var numComps = this.base.numComps;
7032 var start = src[srcOffset] * numComps;
7033 this.base.getRgbItem(this.lookup, start, dest, destOffset);
7034 },
7035 getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
7036 dest, destOffset, bits,
7037 alpha01) {
7038 var base = this.base;
7039 var numComps = base.numComps;
7040 var outputDelta = base.getOutputLength(numComps, alpha01);
7041 var lookup = this.lookup;
7042
7043 for (var i = 0; i < count; ++i) {
7044 var lookupPos = src[srcOffset++] * numComps;
7045 base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
7046 destOffset += outputDelta;
7047 }
7048 },
7049 getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
7050 return this.base.getOutputLength(inputLength * this.base.numComps,
7051 alpha01);
7052 },
7053 isPassthrough: ColorSpace.prototype.isPassthrough,
7054 fillRgb: ColorSpace.prototype.fillRgb,
7055 isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
7056 // indexed color maps shouldn't be changed
7057 return true;
7058 },
7059 usesZeroToOneRange: true
7060 };
7061 return IndexedCS;
7062 })();
7063
7064 var DeviceGrayCS = (function DeviceGrayCSClosure() {
7065 function DeviceGrayCS() {
7066 this.name = 'DeviceGray';
7067 this.numComps = 1;
7068 this.defaultColor = new Float32Array([0]);
7069 }
7070
7071 DeviceGrayCS.prototype = {
7072 getRgb: ColorSpace.prototype.getRgb,
7073 getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
7074 dest, destOffset) {
7075 var c = (src[srcOffset] * 255) | 0;
7076 c = c < 0 ? 0 : c > 255 ? 255 : c;
7077 dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
7078 },
7079 getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
7080 dest, destOffset, bits,
7081 alpha01) {
7082 var scale = 255 / ((1 << bits) - 1);
7083 var j = srcOffset, q = destOffset;
7084 for (var i = 0; i < count; ++i) {
7085 var c = (scale * src[j++]) | 0;
7086 dest[q++] = c;
7087 dest[q++] = c;
7088 dest[q++] = c;
7089 q += alpha01;
7090 }
7091 },
7092 getOutputLength: function DeviceGrayCS_getOutputLength(inputLength,
7093 alpha01) {
7094 return inputLength * (3 + alpha01);
7095 },
7096 isPassthrough: ColorSpace.prototype.isPassthrough,
7097 fillRgb: ColorSpace.prototype.fillRgb,
7098 isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
7099 return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7100 },
7101 usesZeroToOneRange: true
7102 };
7103 return DeviceGrayCS;
7104 })();
7105
7106 var DeviceRgbCS = (function DeviceRgbCSClosure() {
7107 function DeviceRgbCS() {
7108 this.name = 'DeviceRGB';
7109 this.numComps = 3;
7110 this.defaultColor = new Float32Array([0, 0, 0]);
7111 }
7112 DeviceRgbCS.prototype = {
7113 getRgb: ColorSpace.prototype.getRgb,
7114 getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
7115 dest, destOffset) {
7116 var r = (src[srcOffset] * 255) | 0;
7117 var g = (src[srcOffset + 1] * 255) | 0;
7118 var b = (src[srcOffset + 2] * 255) | 0;
7119 dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
7120 dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
7121 dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
7122 },
7123 getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
7124 dest, destOffset, bits,
7125 alpha01) {
7126 if (bits === 8 && alpha01 === 0) {
7127 dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
7128 return;
7129 }
7130 var scale = 255 / ((1 << bits) - 1);
7131 var j = srcOffset, q = destOffset;
7132 for (var i = 0; i < count; ++i) {
7133 dest[q++] = (scale * src[j++]) | 0;
7134 dest[q++] = (scale * src[j++]) | 0;
7135 dest[q++] = (scale * src[j++]) | 0;
7136 q += alpha01;
7137 }
7138 },
7139 getOutputLength: function DeviceRgbCS_getOutputLength(inputLength,
7140 alpha01) {
7141 return (inputLength * (3 + alpha01) / 3) | 0;
7142 },
7143 isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
7144 return bits === 8;
7145 },
7146 fillRgb: ColorSpace.prototype.fillRgb,
7147 isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
7148 return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7149 },
7150 usesZeroToOneRange: true
7151 };
7152 return DeviceRgbCS;
7153 })();
7154
7155 var DeviceCmykCS = (function DeviceCmykCSClosure() {
7156 // The coefficients below was found using numerical analysis: the method of
7157 // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
7158 // where color_value is the tabular value from the table of sampled RGB colors
7159 // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
7160 // CMYK color conversion using the estimation below:
7161 // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
7162 function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
7163 var c = src[srcOffset + 0] * srcScale;
7164 var m = src[srcOffset + 1] * srcScale;
7165 var y = src[srcOffset + 2] * srcScale;
7166 var k = src[srcOffset + 3] * srcScale;
7167
7168 var r =
7169 (c * (-4.387332384609988 * c + 54.48615194189176 * m +
7170 18.82290502165302 * y + 212.25662451639585 * k +
7171 -285.2331026137004) +
7172 m * (1.7149763477362134 * m - 5.6096736904047315 * y +
7173 -17.873870861415444 * k - 5.497006427196366) +
7174 y * (-2.5217340131683033 * y - 21.248923337353073 * k +
7175 17.5119270841813) +
7176 k * (-21.86122147463605 * k - 189.48180835922747) + 255) | 0;
7177 var g =
7178 (c * (8.841041422036149 * c + 60.118027045597366 * m +
7179 6.871425592049007 * y + 31.159100130055922 * k +
7180 -79.2970844816548) +
7181 m * (-15.310361306967817 * m + 17.575251261109482 * y +
7182 131.35250912493976 * k - 190.9453302588951) +
7183 y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
7184 k * (-20.737325471181034 * k - 187.80453709719578) + 255) | 0;
7185 var b =
7186 (c * (0.8842522430003296 * c + 8.078677503112928 * m +
7187 30.89978309703729 * y - 0.23883238689178934 * k +
7188 -14.183576799673286) +
7189 m * (10.49593273432072 * m + 63.02378494754052 * y +
7190 50.606957656360734 * k - 112.23884253719248) +
7191 y * (0.03296041114873217 * y + 115.60384449646641 * k +
7192 -193.58209356861505) +
7193 k * (-22.33816807309886 * k - 180.12613974708367) + 255) | 0;
7194
7195 dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
7196 dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
7197 dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
7198 }
7199
7200 function DeviceCmykCS() {
7201 this.name = 'DeviceCMYK';
7202 this.numComps = 4;
7203 this.defaultColor = new Float32Array([0, 0, 0, 1]);
7204 }
7205 DeviceCmykCS.prototype = {
7206 getRgb: ColorSpace.prototype.getRgb,
7207 getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
7208 dest, destOffset) {
7209 convertToRgb(src, srcOffset, 1, dest, destOffset);
7210 },
7211 getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
7212 dest, destOffset, bits,
7213 alpha01) {
7214 var scale = 1 / ((1 << bits) - 1);
7215 for (var i = 0; i < count; i++) {
7216 convertToRgb(src, srcOffset, scale, dest, destOffset);
7217 srcOffset += 4;
7218 destOffset += 3 + alpha01;
7219 }
7220 },
7221 getOutputLength: function DeviceCmykCS_getOutputLength(inputLength,
7222 alpha01) {
7223 return (inputLength / 4 * (3 + alpha01)) | 0;
7224 },
7225 isPassthrough: ColorSpace.prototype.isPassthrough,
7226 fillRgb: ColorSpace.prototype.fillRgb,
7227 isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
7228 return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7229 },
7230 usesZeroToOneRange: true
7231 };
7232
7233 return DeviceCmykCS;
7234 })();
7235
7236 //
7237 // CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245
7238 //
7239 var CalGrayCS = (function CalGrayCSClosure() {
7240 function CalGrayCS(whitePoint, blackPoint, gamma) {
7241 this.name = 'CalGray';
7242 this.numComps = 1;
7243 this.defaultColor = new Float32Array([0]);
7244
7245 if (!whitePoint) {
7246 error('WhitePoint missing - required for color space CalGray');
7247 }
7248 blackPoint = blackPoint || [0, 0, 0];
7249 gamma = gamma || 1;
7250
7251 // Translate arguments to spec variables.
7252 this.XW = whitePoint[0];
7253 this.YW = whitePoint[1];
7254 this.ZW = whitePoint[2];
7255
7256 this.XB = blackPoint[0];
7257 this.YB = blackPoint[1];
7258 this.ZB = blackPoint[2];
7259
7260 this.G = gamma;
7261
7262 // Validate variables as per spec.
7263 if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
7264 error('Invalid WhitePoint components for ' + this.name +
7265 ', no fallback available');
7266 }
7267
7268 if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
7269 info('Invalid BlackPoint for ' + this.name + ', falling back to default');
7270 this.XB = this.YB = this.ZB = 0;
7271 }
7272
7273 if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
7274 warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +
7275 ', ZB: ' + this.ZB + ', only default values are supported.');
7276 }
7277
7278 if (this.G < 1) {
7279 info('Invalid Gamma: ' + this.G + ' for ' + this.name +
7280 ', falling back to default');
7281 this.G = 1;
7282 }
7283 }
7284
7285 function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
7286 // A represents a gray component of a calibrated gray space.
7287 // A <---> AG in the spec
7288 var A = src[srcOffset] * scale;
7289 var AG = Math.pow(A, cs.G);
7290
7291 // Computes L as per spec. ( = cs.YW * AG )
7292 // Except if other than default BlackPoint values are used.
7293 var L = cs.YW * AG;
7294 // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.
7295 // Convert values to rgb range [0, 255].
7296 var val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0) | 0;
7297 dest[destOffset] = val;
7298 dest[destOffset + 1] = val;
7299 dest[destOffset + 2] = val;
7300 }
7301
7302 CalGrayCS.prototype = {
7303 getRgb: ColorSpace.prototype.getRgb,
7304 getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
7305 dest, destOffset) {
7306 convertToRgb(this, src, srcOffset, dest, destOffset, 1);
7307 },
7308 getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
7309 dest, destOffset, bits,
7310 alpha01) {
7311 var scale = 1 / ((1 << bits) - 1);
7312
7313 for (var i = 0; i < count; ++i) {
7314 convertToRgb(this, src, srcOffset, dest, destOffset, scale);
7315 srcOffset += 1;
7316 destOffset += 3 + alpha01;
7317 }
7318 },
7319 getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
7320 return inputLength * (3 + alpha01);
7321 },
7322 isPassthrough: ColorSpace.prototype.isPassthrough,
7323 fillRgb: ColorSpace.prototype.fillRgb,
7324 isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
7325 return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7326 },
7327 usesZeroToOneRange: true
7328 };
7329 return CalGrayCS;
7330 })();
7331
7332 //
7333 // CalRGBCS: Based on "PDF Reference, Sixth Ed", p.247
7334 //
7335 var CalRGBCS = (function CalRGBCSClosure() {
7336
7337 // See http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html for these
7338 // matrices.
7339 var BRADFORD_SCALE_MATRIX = new Float32Array([
7340 0.8951, 0.2664, -0.1614,
7341 -0.7502, 1.7135, 0.0367,
7342 0.0389, -0.0685, 1.0296]);
7343
7344 var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([
7345 0.9869929, -0.1470543, 0.1599627,
7346 0.4323053, 0.5183603, 0.0492912,
7347 -0.0085287, 0.0400428, 0.9684867]);
7348
7349 // See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html.
7350 var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([
7351 3.2404542, -1.5371385, -0.4985314,
7352 -0.9692660, 1.8760108, 0.0415560,
7353 0.0556434, -0.2040259, 1.0572252]);
7354
7355 var FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]);
7356
7357 var tempNormalizeMatrix = new Float32Array(3);
7358 var tempConvertMatrix1 = new Float32Array(3);
7359 var tempConvertMatrix2 = new Float32Array(3);
7360
7361 var DECODE_L_CONSTANT = Math.pow(((8 + 16) / 116), 3) / 8.0;
7362
7363 function CalRGBCS(whitePoint, blackPoint, gamma, matrix) {
7364 this.name = 'CalRGB';
7365 this.numComps = 3;
7366 this.defaultColor = new Float32Array(3);
7367
7368 if (!whitePoint) {
7369 error('WhitePoint missing - required for color space CalRGB');
7370 }
7371 blackPoint = blackPoint || new Float32Array(3);
7372 gamma = gamma || new Float32Array([1, 1, 1]);
7373 matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
7374
7375 // Translate arguments to spec variables.
7376 var XW = whitePoint[0];
7377 var YW = whitePoint[1];
7378 var ZW = whitePoint[2];
7379 this.whitePoint = whitePoint;
7380
7381 var XB = blackPoint[0];
7382 var YB = blackPoint[1];
7383 var ZB = blackPoint[2];
7384 this.blackPoint = blackPoint;
7385
7386 this.GR = gamma[0];
7387 this.GG = gamma[1];
7388 this.GB = gamma[2];
7389
7390 this.MXA = matrix[0];
7391 this.MYA = matrix[1];
7392 this.MZA = matrix[2];
7393 this.MXB = matrix[3];
7394 this.MYB = matrix[4];
7395 this.MZB = matrix[5];
7396 this.MXC = matrix[6];
7397 this.MYC = matrix[7];
7398 this.MZC = matrix[8];
7399
7400 // Validate variables as per spec.
7401 if (XW < 0 || ZW < 0 || YW !== 1) {
7402 error('Invalid WhitePoint components for ' + this.name +
7403 ', no fallback available');
7404 }
7405
7406 if (XB < 0 || YB < 0 || ZB < 0) {
7407 info('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB +
7408 ', ' + ZB + '], falling back to default');
7409 this.blackPoint = new Float32Array(3);
7410 }
7411
7412 if (this.GR < 0 || this.GG < 0 || this.GB < 0) {
7413 info('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB +
7414 '] for ' + this.name + ', falling back to default');
7415 this.GR = this.GG = this.GB = 1;
7416 }
7417
7418 if (this.MXA < 0 || this.MYA < 0 || this.MZA < 0 ||
7419 this.MXB < 0 || this.MYB < 0 || this.MZB < 0 ||
7420 this.MXC < 0 || this.MYC < 0 || this.MZC < 0) {
7421 info('Invalid Matrix for ' + this.name + ' [' +
7422 this.MXA + ', ' + this.MYA + ', ' + this.MZA +
7423 this.MXB + ', ' + this.MYB + ', ' + this.MZB +
7424 this.MXC + ', ' + this.MYC + ', ' + this.MZC +
7425 '], falling back to default');
7426 this.MXA = this.MYB = this.MZC = 1;
7427 this.MXB = this.MYA = this.MZA = this.MXC = this.MYC = this.MZB = 0;
7428 }
7429 }
7430
7431 function matrixProduct(a, b, result) {
7432 result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
7433 result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2];
7434 result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2];
7435 }
7436
7437 function convertToFlat(sourceWhitePoint, LMS, result) {
7438 result[0] = LMS[0] * 1 / sourceWhitePoint[0];
7439 result[1] = LMS[1] * 1 / sourceWhitePoint[1];
7440 result[2] = LMS[2] * 1 / sourceWhitePoint[2];
7441 }
7442
7443 function convertToD65(sourceWhitePoint, LMS, result) {
7444 var D65X = 0.95047;
7445 var D65Y = 1;
7446 var D65Z = 1.08883;
7447
7448 result[0] = LMS[0] * D65X / sourceWhitePoint[0];
7449 result[1] = LMS[1] * D65Y / sourceWhitePoint[1];
7450 result[2] = LMS[2] * D65Z / sourceWhitePoint[2];
7451 }
7452
7453 function sRGBTransferFunction(color) {
7454 // See http://en.wikipedia.org/wiki/SRGB.
7455 if (color <= 0.0031308){
7456 return adjustToRange(0, 1, 12.92 * color);
7457 }
7458
7459 return adjustToRange(0, 1, (1 + 0.055) * Math.pow(color, 1 / 2.4) - 0.055);
7460 }
7461
7462 function adjustToRange(min, max, value) {
7463 return Math.max(min, Math.min(max, value));
7464 }
7465
7466 function decodeL(L) {
7467 if (L < 0) {
7468 return -decodeL(-L);
7469 }
7470
7471 if (L > 8.0) {
7472 return Math.pow(((L + 16) / 116), 3);
7473 }
7474
7475 return L * DECODE_L_CONSTANT;
7476 }
7477
7478 function compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) {
7479
7480 // In case the blackPoint is already the default blackPoint then there is
7481 // no need to do compensation.
7482 if (sourceBlackPoint[0] === 0 &&
7483 sourceBlackPoint[1] === 0 &&
7484 sourceBlackPoint[2] === 0) {
7485 result[0] = XYZ_Flat[0];
7486 result[1] = XYZ_Flat[1];
7487 result[2] = XYZ_Flat[2];
7488 return;
7489 }
7490
7491 // For the blackPoint calculation details, please see
7492 // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/
7493 // AdobeBPC.pdf.
7494 // The destination blackPoint is the default blackPoint [0, 0, 0].
7495 var zeroDecodeL = decodeL(0);
7496
7497 var X_DST = zeroDecodeL;
7498 var X_SRC = decodeL(sourceBlackPoint[0]);
7499
7500 var Y_DST = zeroDecodeL;
7501 var Y_SRC = decodeL(sourceBlackPoint[1]);
7502
7503 var Z_DST = zeroDecodeL;
7504 var Z_SRC = decodeL(sourceBlackPoint[2]);
7505
7506 var X_Scale = (1 - X_DST) / (1 - X_SRC);
7507 var X_Offset = 1 - X_Scale;
7508
7509 var Y_Scale = (1 - Y_DST) / (1 - Y_SRC);
7510 var Y_Offset = 1 - Y_Scale;
7511
7512 var Z_Scale = (1 - Z_DST) / (1 - Z_SRC);
7513 var Z_Offset = 1 - Z_Scale;
7514
7515 result[0] = XYZ_Flat[0] * X_Scale + X_Offset;
7516 result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset;
7517 result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset;
7518 }
7519
7520 function normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) {
7521
7522 // In case the whitePoint is already flat then there is no need to do
7523 // normalization.
7524 if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) {
7525 result[0] = XYZ_In[0];
7526 result[1] = XYZ_In[1];
7527 result[2] = XYZ_In[2];
7528 return;
7529 }
7530
7531 var LMS = result;
7532 matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
7533
7534 var LMS_Flat = tempNormalizeMatrix;
7535 convertToFlat(sourceWhitePoint, LMS, LMS_Flat);
7536
7537 matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result);
7538 }
7539
7540 function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) {
7541
7542 var LMS = result;
7543 matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
7544
7545 var LMS_D65 = tempNormalizeMatrix;
7546 convertToD65(sourceWhitePoint, LMS, LMS_D65);
7547
7548 matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result);
7549 }
7550
7551 function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
7552 // A, B and C represent a red, green and blue components of a calibrated
7553 // rgb space.
7554 var A = adjustToRange(0, 1, src[srcOffset] * scale);
7555 var B = adjustToRange(0, 1, src[srcOffset + 1] * scale);
7556 var C = adjustToRange(0, 1, src[srcOffset + 2] * scale);
7557
7558 // A <---> AGR in the spec
7559 // B <---> BGG in the spec
7560 // C <---> CGB in the spec
7561 var AGR = Math.pow(A, cs.GR);
7562 var BGG = Math.pow(B, cs.GG);
7563 var CGB = Math.pow(C, cs.GB);
7564
7565 // Computes intermediate variables L, M, N as per spec.
7566 // To decode X, Y, Z values map L, M, N directly to them.
7567 var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB;
7568 var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB;
7569 var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB;
7570
7571 // The following calculations are based on this document:
7572 // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/
7573 // AdobeBPC.pdf.
7574 var XYZ = tempConvertMatrix1;
7575 XYZ[0] = X;
7576 XYZ[1] = Y;
7577 XYZ[2] = Z;
7578 var XYZ_Flat = tempConvertMatrix2;
7579
7580 normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat);
7581
7582 var XYZ_Black = tempConvertMatrix1;
7583 compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black);
7584
7585 var XYZ_D65 = tempConvertMatrix2;
7586 normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65);
7587
7588 var SRGB = tempConvertMatrix1;
7589 matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB);
7590
7591 var sR = sRGBTransferFunction(SRGB[0]);
7592 var sG = sRGBTransferFunction(SRGB[1]);
7593 var sB = sRGBTransferFunction(SRGB[2]);
7594
7595 // Convert the values to rgb range [0, 255].
7596 dest[destOffset] = Math.round(sR * 255);
7597 dest[destOffset + 1] = Math.round(sG * 255);
7598 dest[destOffset + 2] = Math.round(sB * 255);
7599 }
7600
7601 CalRGBCS.prototype = {
7602 getRgb: function CalRGBCS_getRgb(src, srcOffset) {
7603 var rgb = new Uint8Array(3);
7604 this.getRgbItem(src, srcOffset, rgb, 0);
7605 return rgb;
7606 },
7607 getRgbItem: function CalRGBCS_getRgbItem(src, srcOffset,
7608 dest, destOffset) {
7609 convertToRgb(this, src, srcOffset, dest, destOffset, 1);
7610 },
7611 getRgbBuffer: function CalRGBCS_getRgbBuffer(src, srcOffset, count,
7612 dest, destOffset, bits,
7613 alpha01) {
7614 var scale = 1 / ((1 << bits) - 1);
7615
7616 for (var i = 0; i < count; ++i) {
7617 convertToRgb(this, src, srcOffset, dest, destOffset, scale);
7618 srcOffset += 3;
7619 destOffset += 3 + alpha01;
7620 }
7621 },
7622 getOutputLength: function CalRGBCS_getOutputLength(inputLength, alpha01) {
7623 return (inputLength * (3 + alpha01) / 3) | 0;
7624 },
7625 isPassthrough: ColorSpace.prototype.isPassthrough,
7626 fillRgb: ColorSpace.prototype.fillRgb,
7627 isDefaultDecode: function CalRGBCS_isDefaultDecode(decodeMap) {
7628 return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
7629 },
7630 usesZeroToOneRange: true
7631 };
7632 return CalRGBCS;
7633 })();
7634
7635 //
7636 // LabCS: Based on "PDF Reference, Sixth Ed", p.250
7637 //
7638 var LabCS = (function LabCSClosure() {
7639 function LabCS(whitePoint, blackPoint, range) {
7640 this.name = 'Lab';
7641 this.numComps = 3;
7642 this.defaultColor = new Float32Array([0, 0, 0]);
7643
7644 if (!whitePoint) {
7645 error('WhitePoint missing - required for color space Lab');
7646 }
7647 blackPoint = blackPoint || [0, 0, 0];
7648 range = range || [-100, 100, -100, 100];
7649
7650 // Translate args to spec variables
7651 this.XW = whitePoint[0];
7652 this.YW = whitePoint[1];
7653 this.ZW = whitePoint[2];
7654 this.amin = range[0];
7655 this.amax = range[1];
7656 this.bmin = range[2];
7657 this.bmax = range[3];
7658
7659 // These are here just for completeness - the spec doesn't offer any
7660 // formulas that use BlackPoint in Lab
7661 this.XB = blackPoint[0];
7662 this.YB = blackPoint[1];
7663 this.ZB = blackPoint[2];
7664
7665 // Validate vars as per spec
7666 if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
7667 error('Invalid WhitePoint components, no fallback available');
7668 }
7669
7670 if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
7671 info('Invalid BlackPoint, falling back to default');
7672 this.XB = this.YB = this.ZB = 0;
7673 }
7674
7675 if (this.amin > this.amax || this.bmin > this.bmax) {
7676 info('Invalid Range, falling back to defaults');
7677 this.amin = -100;
7678 this.amax = 100;
7679 this.bmin = -100;
7680 this.bmax = 100;
7681 }
7682 }
7683
7684 // Function g(x) from spec
7685 function fn_g(x) {
7686 if (x >= 6 / 29) {
7687 return x * x * x;
7688 } else {
7689 return (108 / 841) * (x - 4 / 29);
7690 }
7691 }
7692
7693 function decode(value, high1, low2, high2) {
7694 return low2 + (value) * (high2 - low2) / (high1);
7695 }
7696
7697 // If decoding is needed maxVal should be 2^bits per component - 1.
7698 function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
7699 // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]
7700 // not the usual [0, 1]. If a command like setFillColor is used the src
7701 // values will already be within the correct range. However, if we are
7702 // converting an image we have to map the values to the correct range given
7703 // above.
7704 // Ls,as,bs <---> L*,a*,b* in the spec
7705 var Ls = src[srcOffset];
7706 var as = src[srcOffset + 1];
7707 var bs = src[srcOffset + 2];
7708 if (maxVal !== false) {
7709 Ls = decode(Ls, maxVal, 0, 100);
7710 as = decode(as, maxVal, cs.amin, cs.amax);
7711 bs = decode(bs, maxVal, cs.bmin, cs.bmax);
7712 }
7713
7714 // Adjust limits of 'as' and 'bs'
7715 as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
7716 bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs;
7717
7718 // Computes intermediate variables X,Y,Z as per spec
7719 var M = (Ls + 16) / 116;
7720 var L = M + (as / 500);
7721 var N = M - (bs / 200);
7722
7723 var X = cs.XW * fn_g(L);
7724 var Y = cs.YW * fn_g(M);
7725 var Z = cs.ZW * fn_g(N);
7726
7727 var r, g, b;
7728 // Using different conversions for D50 and D65 white points,
7729 // per http://www.color.org/srgb.pdf
7730 if (cs.ZW < 1) {
7731 // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
7732 r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
7733 g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
7734 b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
7735 } else {
7736 // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
7737 r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
7738 g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
7739 b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
7740 }
7741 // clamp color values to [0,1] range then convert to [0,255] range.
7742 dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0;
7743 dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0;
7744 dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0;
7745 }
7746
7747 LabCS.prototype = {
7748 getRgb: ColorSpace.prototype.getRgb,
7749 getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
7750 convertToRgb(this, src, srcOffset, false, dest, destOffset);
7751 },
7752 getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,
7753 dest, destOffset, bits,
7754 alpha01) {
7755 var maxVal = (1 << bits) - 1;
7756 for (var i = 0; i < count; i++) {
7757 convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
7758 srcOffset += 3;
7759 destOffset += 3 + alpha01;
7760 }
7761 },
7762 getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {
7763 return (inputLength * (3 + alpha01) / 3) | 0;
7764 },
7765 isPassthrough: ColorSpace.prototype.isPassthrough,
7766 fillRgb: ColorSpace.prototype.fillRgb,
7767 isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
7768 // XXX: Decoding is handled with the lab conversion because of the strange
7769 // ranges that are used.
7770 return true;
7771 },
7772 usesZeroToOneRange: false
7773 };
7774 return LabCS;
7775 })();
7776
7777
7778 var ARCFourCipher = (function ARCFourCipherClosure() {
7779 function ARCFourCipher(key) {
7780 this.a = 0;
7781 this.b = 0;
7782 var s = new Uint8Array(256);
7783 var i, j = 0, tmp, keyLength = key.length;
7784 for (i = 0; i < 256; ++i) {
7785 s[i] = i;
7786 }
7787 for (i = 0; i < 256; ++i) {
7788 tmp = s[i];
7789 j = (j + tmp + key[i % keyLength]) & 0xFF;
7790 s[i] = s[j];
7791 s[j] = tmp;
7792 }
7793 this.s = s;
7794 }
7795
7796 ARCFourCipher.prototype = {
7797 encryptBlock: function ARCFourCipher_encryptBlock(data) {
7798 var i, n = data.length, tmp, tmp2;
7799 var a = this.a, b = this.b, s = this.s;
7800 var output = new Uint8Array(n);
7801 for (i = 0; i < n; ++i) {
7802 a = (a + 1) & 0xFF;
7803 tmp = s[a];
7804 b = (b + tmp) & 0xFF;
7805 tmp2 = s[b];
7806 s[a] = tmp2;
7807 s[b] = tmp;
7808 output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF];
7809 }
7810 this.a = a;
7811 this.b = b;
7812 return output;
7813 }
7814 };
7815 ARCFourCipher.prototype.decryptBlock = ARCFourCipher.prototype.encryptBlock;
7816
7817 return ARCFourCipher;
7818 })();
7819
7820 var calculateMD5 = (function calculateMD5Closure() {
7821 var r = new Uint8Array([
7822 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
7823 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
7824 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
7825 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);
7826
7827 var k = new Int32Array([
7828 -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
7829 -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
7830 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
7831 643717713, -373897302, -701558691, 38016083, -660478335, -405537848,
7832 568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784,
7833 1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556,
7834 -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222,
7835 -722521979, 76029189, -640364487, -421815835, 530742520, -995338651,
7836 -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606,
7837 -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649,
7838 -145523070, -1120210379, 718787259, -343485551]);
7839
7840 function hash(data, offset, length) {
7841 var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878;
7842 // pre-processing
7843 var paddedLength = (length + 72) & ~63; // data + 9 extra bytes
7844 var padded = new Uint8Array(paddedLength);
7845 var i, j, n;
7846 for (i = 0; i < length; ++i) {
7847 padded[i] = data[offset++];
7848 }
7849 padded[i++] = 0x80;
7850 n = paddedLength - 8;
7851 while (i < n) {
7852 padded[i++] = 0;
7853 }
7854 padded[i++] = (length << 3) & 0xFF;
7855 padded[i++] = (length >> 5) & 0xFF;
7856 padded[i++] = (length >> 13) & 0xFF;
7857 padded[i++] = (length >> 21) & 0xFF;
7858 padded[i++] = (length >>> 29) & 0xFF;
7859 padded[i++] = 0;
7860 padded[i++] = 0;
7861 padded[i++] = 0;
7862 var w = new Int32Array(16);
7863 for (i = 0; i < paddedLength;) {
7864 for (j = 0; j < 16; ++j, i += 4) {
7865 w[j] = (padded[i] | (padded[i + 1] << 8) |
7866 (padded[i + 2] << 16) | (padded[i + 3] << 24));
7867 }
7868 var a = h0, b = h1, c = h2, d = h3, f, g;
7869 for (j = 0; j < 64; ++j) {
7870 if (j < 16) {
7871 f = (b & c) | ((~b) & d);
7872 g = j;
7873 } else if (j < 32) {
7874 f = (d & b) | ((~d) & c);
7875 g = (5 * j + 1) & 15;
7876 } else if (j < 48) {
7877 f = b ^ c ^ d;
7878 g = (3 * j + 5) & 15;
7879 } else {
7880 f = c ^ (b | (~d));
7881 g = (7 * j) & 15;
7882 }
7883 var tmp = d, rotateArg = (a + f + k[j] + w[g]) | 0, rotate = r[j];
7884 d = c;
7885 c = b;
7886 b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0;
7887 a = tmp;
7888 }
7889 h0 = (h0 + a) | 0;
7890 h1 = (h1 + b) | 0;
7891 h2 = (h2 + c) | 0;
7892 h3 = (h3 + d) | 0;
7893 }
7894 return new Uint8Array([
7895 h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF,
7896 h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF,
7897 h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF,
7898 h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF
7899 ]);
7900 }
7901
7902 return hash;
7903 })();
7904 var Word64 = (function Word64Closure() {
7905 function Word64(highInteger, lowInteger) {
7906 this.high = highInteger | 0;
7907 this.low = lowInteger | 0;
7908 }
7909 Word64.prototype = {
7910 and: function Word64_and(word) {
7911 this.high &= word.high;
7912 this.low &= word.low;
7913 },
7914 xor: function Word64_xor(word) {
7915 this.high ^= word.high;
7916 this.low ^= word.low;
7917 },
7918
7919 or: function Word64_or(word) {
7920 this.high |= word.high;
7921 this.low |= word.low;
7922 },
7923
7924 shiftRight: function Word64_shiftRight(places) {
7925 if (places >= 32) {
7926 this.low = (this.high >>> (places - 32)) | 0;
7927 this.high = 0;
7928 } else {
7929 this.low = (this.low >>> places) | (this.high << (32 - places));
7930 this.high = (this.high >>> places) | 0;
7931 }
7932 },
7933
7934 shiftLeft: function Word64_shiftLeft(places) {
7935 if (places >= 32) {
7936 this.high = this.low << (places - 32);
7937 this.low = 0;
7938 } else {
7939 this.high = (this.high << places) | (this.low >>> (32 - places));
7940 this.low = this.low << places;
7941 }
7942 },
7943
7944 rotateRight: function Word64_rotateRight(places) {
7945 var low, high;
7946 if (places & 32) {
7947 high = this.low;
7948 low = this.high;
7949 } else {
7950 low = this.low;
7951 high = this.high;
7952 }
7953 places &= 31;
7954 this.low = (low >>> places) | (high << (32 - places));
7955 this.high = (high >>> places) | (low << (32 - places));
7956 },
7957
7958 not: function Word64_not() {
7959 this.high = ~this.high;
7960 this.low = ~this.low;
7961 },
7962
7963 add: function Word64_add(word) {
7964 var lowAdd = (this.low >>> 0) + (word.low >>> 0);
7965 var highAdd = (this.high >>> 0) + (word.high >>> 0);
7966 if (lowAdd > 0xFFFFFFFF) {
7967 highAdd += 1;
7968 }
7969 this.low = lowAdd | 0;
7970 this.high = highAdd | 0;
7971 },
7972
7973 copyTo: function Word64_copyTo(bytes, offset) {
7974 bytes[offset] = (this.high >>> 24) & 0xFF;
7975 bytes[offset + 1] = (this.high >> 16) & 0xFF;
7976 bytes[offset + 2] = (this.high >> 8) & 0xFF;
7977 bytes[offset + 3] = this.high & 0xFF;
7978 bytes[offset + 4] = (this.low >>> 24) & 0xFF;
7979 bytes[offset + 5] = (this.low >> 16) & 0xFF;
7980 bytes[offset + 6] = (this.low >> 8) & 0xFF;
7981 bytes[offset + 7] = this.low & 0xFF;
7982 },
7983
7984 assign: function Word64_assign(word) {
7985 this.high = word.high;
7986 this.low = word.low;
7987 }
7988 };
7989 return Word64;
7990 })();
7991
7992 var calculateSHA256 = (function calculateSHA256Closure() {
7993 function rotr(x, n) {
7994 return (x >>> n) | (x << 32 - n);
7995 }
7996
7997 function ch(x, y, z) {
7998 return (x & y) ^ (~x & z);
7999 }
8000
8001 function maj(x, y, z) {
8002 return (x & y) ^ (x & z) ^ (y & z);
8003 }
8004
8005 function sigma(x) {
8006 return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
8007 }
8008
8009 function sigmaPrime(x) {
8010 return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
8011 }
8012
8013 function littleSigma(x) {
8014 return rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3;
8015 }
8016
8017 function littleSigmaPrime(x) {
8018 return rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10;
8019 }
8020
8021 var k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
8022 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
8023 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
8024 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
8025 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
8026 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
8027 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
8028 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
8029 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
8030 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
8031 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
8032 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
8033 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
8034 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
8035 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
8036 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
8037
8038 function hash(data, offset, length) {
8039 // initial hash values
8040 var h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372,
8041 h3 = 0xa54ff53a, h4 = 0x510e527f, h5 = 0x9b05688c,
8042 h6 = 0x1f83d9ab, h7 = 0x5be0cd19;
8043 // pre-processing
8044 var paddedLength = Math.ceil((length + 9) / 64) * 64;
8045 var padded = new Uint8Array(paddedLength);
8046 var i, j, n;
8047 for (i = 0; i < length; ++i) {
8048 padded[i] = data[offset++];
8049 }
8050 padded[i++] = 0x80;
8051 n = paddedLength - 8;
8052 while (i < n) {
8053 padded[i++] = 0;
8054 }
8055 padded[i++] = 0;
8056 padded[i++] = 0;
8057 padded[i++] = 0;
8058 padded[i++] = (length >>> 29) & 0xFF;
8059 padded[i++] = (length >> 21) & 0xFF;
8060 padded[i++] = (length >> 13) & 0xFF;
8061 padded[i++] = (length >> 5) & 0xFF;
8062 padded[i++] = (length << 3) & 0xFF;
8063 var w = new Uint32Array(64);
8064 // for each 512 bit block
8065 for (i = 0; i < paddedLength;) {
8066 for (j = 0; j < 16; ++j) {
8067 w[j] = (padded[i] << 24 | (padded[i + 1] << 16) |
8068 (padded[i + 2] << 8) | (padded[i + 3]));
8069 i += 4;
8070 }
8071
8072 for (j = 16; j < 64; ++j) {
8073 w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] +
8074 littleSigma(w[j - 15]) + w[j - 16] | 0;
8075 }
8076 var a = h0, b = h1, c = h2, d = h3, e = h4,
8077 f = h5, g = h6, h = h7, t1, t2;
8078 for (j = 0; j < 64; ++j) {
8079 t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j];
8080 t2 = sigma(a) + maj(a, b, c);
8081 h = g;
8082 g = f;
8083 f = e;
8084 e = (d + t1) | 0;
8085 d = c;
8086 c = b;
8087 b = a;
8088 a = (t1 + t2) | 0;
8089 }
8090 h0 = (h0 + a) | 0;
8091 h1 = (h1 + b) | 0;
8092 h2 = (h2 + c) | 0;
8093 h3 = (h3 + d) | 0;
8094 h4 = (h4 + e) | 0;
8095 h5 = (h5 + f) | 0;
8096 h6 = (h6 + g) | 0;
8097 h7 = (h7 + h) | 0;
8098 }
8099 return new Uint8Array([
8100 (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, (h0) & 0xFF,
8101 (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, (h1) & 0xFF,
8102 (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, (h2) & 0xFF,
8103 (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, (h3) & 0xFF,
8104 (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, (h4) & 0xFF,
8105 (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, (h5) & 0xFF,
8106 (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, (h6) & 0xFF,
8107 (h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, (h7) & 0xFF
8108 ]);
8109 }
8110
8111 return hash;
8112 })();
8113
8114 var calculateSHA512 = (function calculateSHA512Closure() {
8115 function ch(result, x, y, z, tmp) {
8116 result.assign(x);
8117 result.and(y);
8118 tmp.assign(x);
8119 tmp.not();
8120 tmp.and(z);
8121 result.xor(tmp);
8122 }
8123
8124 function maj(result, x, y, z, tmp) {
8125 result.assign(x);
8126 result.and(y);
8127 tmp.assign(x);
8128 tmp.and(z);
8129 result.xor(tmp);
8130 tmp.assign(y);
8131 tmp.and(z);
8132 result.xor(tmp);
8133 }
8134
8135 function sigma(result, x, tmp) {
8136 result.assign(x);
8137 result.rotateRight(28);
8138 tmp.assign(x);
8139 tmp.rotateRight(34);
8140 result.xor(tmp);
8141 tmp.assign(x);
8142 tmp.rotateRight(39);
8143 result.xor(tmp);
8144 }
8145
8146 function sigmaPrime(result, x, tmp) {
8147 result.assign(x);
8148 result.rotateRight(14);
8149 tmp.assign(x);
8150 tmp.rotateRight(18);
8151 result.xor(tmp);
8152 tmp.assign(x);
8153 tmp.rotateRight(41);
8154 result.xor(tmp);
8155 }
8156
8157 function littleSigma(result, x, tmp) {
8158 result.assign(x);
8159 result.rotateRight(1);
8160 tmp.assign(x);
8161 tmp.rotateRight(8);
8162 result.xor(tmp);
8163 tmp.assign(x);
8164 tmp.shiftRight(7);
8165 result.xor(tmp);
8166 }
8167
8168 function littleSigmaPrime(result, x, tmp) {
8169 result.assign(x);
8170 result.rotateRight(19);
8171 tmp.assign(x);
8172 tmp.rotateRight(61);
8173 result.xor(tmp);
8174 tmp.assign(x);
8175 tmp.shiftRight(6);
8176 result.xor(tmp);
8177 }
8178
8179 var k = [
8180 new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd),
8181 new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc),
8182 new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019),
8183 new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118),
8184 new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe),
8185 new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2),
8186 new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1),
8187 new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694),
8188 new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3),
8189 new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65),
8190 new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483),
8191 new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5),
8192 new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210),
8193 new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4),
8194 new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725),
8195 new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70),
8196 new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926),
8197 new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df),
8198 new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8),
8199 new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b),
8200 new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001),
8201 new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30),
8202 new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910),
8203 new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8),
8204 new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53),
8205 new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8),
8206 new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb),
8207 new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3),
8208 new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60),
8209 new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec),
8210 new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9),
8211 new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b),
8212 new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207),
8213 new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178),
8214 new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6),
8215 new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b),
8216 new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493),
8217 new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c),
8218 new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a),
8219 new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)];
8220
8221 function hash(data, offset, length, mode384) {
8222 mode384 = !!mode384;
8223 // initial hash values
8224 var h0, h1, h2, h3, h4, h5, h6, h7;
8225 if (!mode384) {
8226 h0 = new Word64(0x6a09e667, 0xf3bcc908);
8227 h1 = new Word64(0xbb67ae85, 0x84caa73b);
8228 h2 = new Word64(0x3c6ef372, 0xfe94f82b);
8229 h3 = new Word64(0xa54ff53a, 0x5f1d36f1);
8230 h4 = new Word64(0x510e527f, 0xade682d1);
8231 h5 = new Word64(0x9b05688c, 0x2b3e6c1f);
8232 h6 = new Word64(0x1f83d9ab, 0xfb41bd6b);
8233 h7 = new Word64(0x5be0cd19, 0x137e2179);
8234 }
8235 else {
8236 // SHA384 is exactly the same
8237 // except with different starting values and a trimmed result
8238 h0 = new Word64(0xcbbb9d5d, 0xc1059ed8);
8239 h1 = new Word64(0x629a292a, 0x367cd507);
8240 h2 = new Word64(0x9159015a, 0x3070dd17);
8241 h3 = new Word64(0x152fecd8, 0xf70e5939);
8242 h4 = new Word64(0x67332667, 0xffc00b31);
8243 h5 = new Word64(0x8eb44a87, 0x68581511);
8244 h6 = new Word64(0xdb0c2e0d, 0x64f98fa7);
8245 h7 = new Word64(0x47b5481d, 0xbefa4fa4);
8246 }
8247
8248 // pre-processing
8249 var paddedLength = Math.ceil((length + 17) / 128) * 128;
8250 var padded = new Uint8Array(paddedLength);
8251 var i, j, n;
8252 for (i = 0; i < length; ++i) {
8253 padded[i] = data[offset++];
8254 }
8255 padded[i++] = 0x80;
8256 n = paddedLength - 16;
8257 while (i < n) {
8258 padded[i++] = 0;
8259 }
8260 padded[i++] = 0;
8261 padded[i++] = 0;
8262 padded[i++] = 0;
8263 padded[i++] = 0;
8264 padded[i++] = 0;
8265 padded[i++] = 0;
8266 padded[i++] = 0;
8267 padded[i++] = 0;
8268 padded[i++] = 0;
8269 padded[i++] = 0;
8270 padded[i++] = 0;
8271 padded[i++] = (length >>> 29) & 0xFF;
8272 padded[i++] = (length >> 21) & 0xFF;
8273 padded[i++] = (length >> 13) & 0xFF;
8274 padded[i++] = (length >> 5) & 0xFF;
8275 padded[i++] = (length << 3) & 0xFF;
8276
8277 var w = new Array(80);
8278 for (i = 0; i < 80; i++) {
8279 w[i] = new Word64(0, 0);
8280 }
8281 var a = new Word64(0, 0), b = new Word64(0, 0), c = new Word64(0, 0);
8282 var d = new Word64(0, 0), e = new Word64(0, 0), f = new Word64(0, 0);
8283 var g = new Word64(0, 0), h = new Word64(0, 0);
8284 var t1 = new Word64(0, 0), t2 = new Word64(0, 0);
8285 var tmp1 = new Word64(0, 0), tmp2 = new Word64(0, 0), tmp3;
8286
8287 // for each 1024 bit block
8288 for (i = 0; i < paddedLength;) {
8289 for (j = 0; j < 16; ++j) {
8290 w[j].high = (padded[i] << 24) | (padded[i + 1] << 16) |
8291 (padded[i + 2] << 8) | (padded[i + 3]);
8292 w[j].low = (padded[i + 4]) << 24 | (padded[i + 5]) << 16 |
8293 (padded[i + 6]) << 8 | (padded[i + 7]);
8294 i += 8;
8295 }
8296 for (j = 16; j < 80; ++j) {
8297 tmp3 = w[j];
8298 littleSigmaPrime(tmp3, w[j - 2], tmp2);
8299 tmp3.add(w[j - 7]);
8300 littleSigma(tmp1, w[j - 15], tmp2);
8301 tmp3.add(tmp1);
8302 tmp3.add(w[j - 16]);
8303 }
8304
8305 a.assign(h0); b.assign(h1); c.assign(h2); d.assign(h3);
8306 e.assign(h4); f.assign(h5); g.assign(h6); h.assign(h7);
8307 for (j = 0; j < 80; ++j) {
8308 t1.assign(h);
8309 sigmaPrime(tmp1, e, tmp2);
8310 t1.add(tmp1);
8311 ch(tmp1, e, f, g, tmp2);
8312 t1.add(tmp1);
8313 t1.add(k[j]);
8314 t1.add(w[j]);
8315
8316 sigma(t2, a, tmp2);
8317 maj(tmp1, a, b, c, tmp2);
8318 t2.add(tmp1);
8319
8320 tmp3 = h;
8321 h = g;
8322 g = f;
8323 f = e;
8324 d.add(t1);
8325 e = d;
8326 d = c;
8327 c = b;
8328 b = a;
8329 tmp3.assign(t1);
8330 tmp3.add(t2);
8331 a = tmp3;
8332 }
8333 h0.add(a);
8334 h1.add(b);
8335 h2.add(c);
8336 h3.add(d);
8337 h4.add(e);
8338 h5.add(f);
8339 h6.add(g);
8340 h7.add(h);
8341 }
8342
8343 var result;
8344 if (!mode384) {
8345 result = new Uint8Array(64);
8346 h0.copyTo(result,0);
8347 h1.copyTo(result,8);
8348 h2.copyTo(result,16);
8349 h3.copyTo(result,24);
8350 h4.copyTo(result,32);
8351 h5.copyTo(result,40);
8352 h6.copyTo(result,48);
8353 h7.copyTo(result,56);
8354 }
8355 else {
8356 result = new Uint8Array(48);
8357 h0.copyTo(result,0);
8358 h1.copyTo(result,8);
8359 h2.copyTo(result,16);
8360 h3.copyTo(result,24);
8361 h4.copyTo(result,32);
8362 h5.copyTo(result,40);
8363 }
8364 return result;
8365 }
8366
8367 return hash;
8368 })();
8369 var calculateSHA384 = (function calculateSHA384Closure() {
8370 function hash(data, offset, length) {
8371 return calculateSHA512(data, offset, length, true);
8372 }
8373
8374 return hash;
8375 })();
8376 var NullCipher = (function NullCipherClosure() {
8377 function NullCipher() {
8378 }
8379
8380 NullCipher.prototype = {
8381 decryptBlock: function NullCipher_decryptBlock(data) {
8382 return data;
8383 }
8384 };
8385
8386 return NullCipher;
8387 })();
8388
8389 var AES128Cipher = (function AES128CipherClosure() {
8390 var rcon = new Uint8Array([
8391 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
8392 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
8393 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
8394 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
8395 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
8396 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,
8397 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
8398 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
8399 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
8400 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e,
8401 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
8402 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
8403 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
8404 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
8405 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
8406 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
8407 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,
8408 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
8409 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
8410 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
8411 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
8412 0x74, 0xe8, 0xcb, 0x8d]);
8413
8414 var s = new Uint8Array([
8415 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
8416 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
8417 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
8418 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
8419 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
8420 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
8421 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
8422 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
8423 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
8424 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
8425 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
8426 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
8427 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
8428 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
8429 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
8430 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
8431 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
8432 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
8433 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
8434 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
8435 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
8436 0xb0, 0x54, 0xbb, 0x16]);
8437
8438 var inv_s = new Uint8Array([
8439 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
8440 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
8441 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
8442 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
8443 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
8444 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
8445 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
8446 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
8447 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
8448 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
8449 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
8450 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
8451 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
8452 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
8453 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
8454 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
8455 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
8456 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
8457 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
8458 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
8459 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
8460 0x55, 0x21, 0x0c, 0x7d]);
8461 var mixCol = new Uint8Array(256);
8462 for (var i = 0; i < 256; i++) {
8463 if (i < 128) {
8464 mixCol[i] = i << 1;
8465 } else {
8466 mixCol[i] = (i << 1) ^ 0x1b;
8467 }
8468 }
8469 var mix = new Uint32Array([
8470 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
8471 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
8472 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,
8473 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,
8474 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,
8475 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,
8476 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,
8477 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,
8478 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,
8479 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,
8480 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,
8481 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,
8482 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,
8483 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,
8484 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,
8485 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,
8486 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,
8487 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,
8488 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,
8489 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,
8490 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,
8491 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,
8492 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,
8493 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,
8494 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,
8495 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,
8496 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,
8497 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,
8498 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,
8499 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,
8500 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,
8501 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,
8502 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,
8503 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,
8504 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,
8505 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,
8506 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,
8507 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,
8508 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,
8509 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,
8510 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,
8511 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
8512 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
8513
8514 function expandKey128(cipherKey) {
8515 var b = 176, result = new Uint8Array(b);
8516 result.set(cipherKey);
8517 for (var j = 16, i = 1; j < b; ++i) {
8518 // RotWord
8519 var t1 = result[j - 3], t2 = result[j - 2],
8520 t3 = result[j - 1], t4 = result[j - 4];
8521 // SubWord
8522 t1 = s[t1];
8523 t2 = s[t2];
8524 t3 = s[t3];
8525 t4 = s[t4];
8526 // Rcon
8527 t1 = t1 ^ rcon[i];
8528 for (var n = 0; n < 4; ++n) {
8529 result[j] = (t1 ^= result[j - 16]);
8530 j++;
8531 result[j] = (t2 ^= result[j - 16]);
8532 j++;
8533 result[j] = (t3 ^= result[j - 16]);
8534 j++;
8535 result[j] = (t4 ^= result[j - 16]);
8536 j++;
8537 }
8538 }
8539 return result;
8540 }
8541
8542 function decrypt128(input, key) {
8543 var state = new Uint8Array(16);
8544 state.set(input);
8545 var i, j, k;
8546 var t, u, v;
8547 // AddRoundKey
8548 for (j = 0, k = 160; j < 16; ++j, ++k) {
8549 state[j] ^= key[k];
8550 }
8551 for (i = 9; i >= 1; --i) {
8552 // InvShiftRows
8553 t = state[13];
8554 state[13] = state[9];
8555 state[9] = state[5];
8556 state[5] = state[1];
8557 state[1] = t;
8558 t = state[14];
8559 u = state[10];
8560 state[14] = state[6];
8561 state[10] = state[2];
8562 state[6] = t;
8563 state[2] = u;
8564 t = state[15];
8565 u = state[11];
8566 v = state[7];
8567 state[15] = state[3];
8568 state[11] = t;
8569 state[7] = u;
8570 state[3] = v;
8571 // InvSubBytes
8572 for (j = 0; j < 16; ++j) {
8573 state[j] = inv_s[state[j]];
8574 }
8575 // AddRoundKey
8576 for (j = 0, k = i * 16; j < 16; ++j, ++k) {
8577 state[j] ^= key[k];
8578 }
8579 // InvMixColumns
8580 for (j = 0; j < 16; j += 4) {
8581 var s0 = mix[state[j]], s1 = mix[state[j + 1]],
8582 s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
8583 t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^
8584 (s3 >>> 24) ^ (s3 << 8));
8585 state[j] = (t >>> 24) & 0xFF;
8586 state[j + 1] = (t >> 16) & 0xFF;
8587 state[j + 2] = (t >> 8) & 0xFF;
8588 state[j + 3] = t & 0xFF;
8589 }
8590 }
8591 // InvShiftRows
8592 t = state[13];
8593 state[13] = state[9];
8594 state[9] = state[5];
8595 state[5] = state[1];
8596 state[1] = t;
8597 t = state[14];
8598 u = state[10];
8599 state[14] = state[6];
8600 state[10] = state[2];
8601 state[6] = t;
8602 state[2] = u;
8603 t = state[15];
8604 u = state[11];
8605 v = state[7];
8606 state[15] = state[3];
8607 state[11] = t;
8608 state[7] = u;
8609 state[3] = v;
8610 for (j = 0; j < 16; ++j) {
8611 // InvSubBytes
8612 state[j] = inv_s[state[j]];
8613 // AddRoundKey
8614 state[j] ^= key[j];
8615 }
8616 return state;
8617 }
8618
8619 function encrypt128(input, key) {
8620 var t, u, v, k;
8621 var state = new Uint8Array(16);
8622 state.set(input);
8623 for (j = 0; j < 16; ++j) {
8624 // AddRoundKey
8625 state[j] ^= key[j];
8626 }
8627
8628 for (i = 1; i < 10; i++) {
8629 //SubBytes
8630 for (j = 0; j < 16; ++j) {
8631 state[j] = s[state[j]];
8632 }
8633 //ShiftRows
8634 v = state[1];
8635 state[1] = state[5];
8636 state[5] = state[9];
8637 state[9] = state[13];
8638 state[13] = v;
8639 v = state[2];
8640 u = state[6];
8641 state[2] = state[10];
8642 state[6] = state[14];
8643 state[10] = v;
8644 state[14] = u;
8645 v = state[3];
8646 u = state[7];
8647 t = state[11];
8648 state[3] = state[15];
8649 state[7] = v;
8650 state[11] = u;
8651 state[15] = t;
8652 //MixColumns
8653 for (var j = 0; j < 16; j += 4) {
8654 var s0 = state[j + 0], s1 = state[j + 1];
8655 var s2 = state[j + 2], s3 = state[j + 3];
8656 t = s0 ^ s1 ^ s2 ^ s3;
8657 state[j + 0] ^= t ^ mixCol[s0 ^ s1];
8658 state[j + 1] ^= t ^ mixCol[s1 ^ s2];
8659 state[j + 2] ^= t ^ mixCol[s2 ^ s3];
8660 state[j + 3] ^= t ^ mixCol[s3 ^ s0];
8661 }
8662 //AddRoundKey
8663 for (j = 0, k = i * 16; j < 16; ++j, ++k) {
8664 state[j] ^= key[k];
8665 }
8666 }
8667
8668 //SubBytes
8669 for (j = 0; j < 16; ++j) {
8670 state[j] = s[state[j]];
8671 }
8672 //ShiftRows
8673 v = state[1];
8674 state[1] = state[5];
8675 state[5] = state[9];
8676 state[9] = state[13];
8677 state[13] = v;
8678 v = state[2];
8679 u = state[6];
8680 state[2] = state[10];
8681 state[6] = state[14];
8682 state[10] = v;
8683 state[14] = u;
8684 v = state[3];
8685 u = state[7];
8686 t = state[11];
8687 state[3] = state[15];
8688 state[7] = v;
8689 state[11] = u;
8690 state[15] = t;
8691 //AddRoundKey
8692 for (j = 0, k = 160; j < 16; ++j, ++k) {
8693 state[j] ^= key[k];
8694 }
8695 return state;
8696 }
8697
8698 function AES128Cipher(key) {
8699 this.key = expandKey128(key);
8700 this.buffer = new Uint8Array(16);
8701 this.bufferPosition = 0;
8702 }
8703
8704 function decryptBlock2(data, finalize) {
8705 var i, j, ii, sourceLength = data.length,
8706 buffer = this.buffer, bufferLength = this.bufferPosition,
8707 result = [], iv = this.iv;
8708 for (i = 0; i < sourceLength; ++i) {
8709 buffer[bufferLength] = data[i];
8710 ++bufferLength;
8711 if (bufferLength < 16) {
8712 continue;
8713 }
8714 // buffer is full, decrypting
8715 var plain = decrypt128(buffer, this.key);
8716 // xor-ing the IV vector to get plain text
8717 for (j = 0; j < 16; ++j) {
8718 plain[j] ^= iv[j];
8719 }
8720 iv = buffer;
8721 result.push(plain);
8722 buffer = new Uint8Array(16);
8723 bufferLength = 0;
8724 }
8725 // saving incomplete buffer
8726 this.buffer = buffer;
8727 this.bufferLength = bufferLength;
8728 this.iv = iv;
8729 if (result.length === 0) {
8730 return new Uint8Array([]);
8731 }
8732 // combining plain text blocks into one
8733 var outputLength = 16 * result.length;
8734 if (finalize) {
8735 // undo a padding that is described in RFC 2898
8736 var lastBlock = result[result.length - 1];
8737 var psLen = lastBlock[15];
8738 if (psLen <= 16) {
8739 for (i = 15, ii = 16 - psLen; i >= ii; --i) {
8740 if (lastBlock[i] !== psLen) {
8741 // Invalid padding, assume that the block has no padding.
8742 psLen = 0;
8743 break;
8744 }
8745 }
8746 outputLength -= psLen;
8747 result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);
8748 }
8749 }
8750 var output = new Uint8Array(outputLength);
8751 for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
8752 output.set(result[i], j);
8753 }
8754 return output;
8755 }
8756
8757 AES128Cipher.prototype = {
8758 decryptBlock: function AES128Cipher_decryptBlock(data, finalize) {
8759 var i, sourceLength = data.length;
8760 var buffer = this.buffer, bufferLength = this.bufferPosition;
8761 // waiting for IV values -- they are at the start of the stream
8762 for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) {
8763 buffer[bufferLength] = data[i];
8764 }
8765 if (bufferLength < 16) {
8766 // need more data
8767 this.bufferLength = bufferLength;
8768 return new Uint8Array([]);
8769 }
8770 this.iv = buffer;
8771 this.buffer = new Uint8Array(16);
8772 this.bufferLength = 0;
8773 // starting decryption
8774 this.decryptBlock = decryptBlock2;
8775 return this.decryptBlock(data.subarray(16), finalize);
8776 },
8777 encrypt: function AES128Cipher_encrypt(data, iv) {
8778 var i, j, ii, sourceLength = data.length,
8779 buffer = this.buffer, bufferLength = this.bufferPosition,
8780 result = [];
8781 if (!iv) {
8782 iv = new Uint8Array(16);
8783 }
8784 for (i = 0; i < sourceLength; ++i) {
8785 buffer[bufferLength] = data[i];
8786 ++bufferLength;
8787 if (bufferLength < 16) {
8788 continue;
8789 }
8790 for (j = 0; j < 16; ++j) {
8791 buffer[j] ^= iv[j];
8792 }
8793
8794 // buffer is full, encrypting
8795 var cipher = encrypt128(buffer, this.key);
8796 iv = cipher;
8797 result.push(cipher);
8798 buffer = new Uint8Array(16);
8799 bufferLength = 0;
8800 }
8801 // saving incomplete buffer
8802 this.buffer = buffer;
8803 this.bufferLength = bufferLength;
8804 this.iv = iv;
8805 if (result.length === 0) {
8806 return new Uint8Array([]);
8807 }
8808 // combining plain text blocks into one
8809 var outputLength = 16 * result.length;
8810 var output = new Uint8Array(outputLength);
8811 for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
8812 output.set(result[i], j);
8813 }
8814 return output;
8815 }
8816 };
8817
8818 return AES128Cipher;
8819 })();
8820
8821 var AES256Cipher = (function AES256CipherClosure() {
8822 var rcon = new Uint8Array([
8823 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
8824 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
8825 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
8826 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
8827 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
8828 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,
8829 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
8830 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
8831 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
8832 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e,
8833 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
8834 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
8835 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
8836 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
8837 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
8838 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
8839 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,
8840 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
8841 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
8842 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
8843 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
8844 0x74, 0xe8, 0xcb, 0x8d]);
8845
8846 var s = new Uint8Array([
8847 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
8848 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
8849 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
8850 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
8851 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
8852 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
8853 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
8854 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
8855 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
8856 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
8857 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
8858 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
8859 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
8860 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
8861 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
8862 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
8863 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
8864 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
8865 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
8866 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
8867 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
8868 0xb0, 0x54, 0xbb, 0x16]);
8869
8870 var inv_s = new Uint8Array([
8871 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
8872 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
8873 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
8874 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
8875 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
8876 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
8877 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
8878 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
8879 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
8880 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
8881 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
8882 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
8883 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
8884 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
8885 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
8886 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
8887 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
8888 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
8889 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
8890 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
8891 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
8892 0x55, 0x21, 0x0c, 0x7d]);
8893
8894 var mixCol = new Uint8Array(256);
8895 for (var i = 0; i < 256; i++) {
8896 if (i < 128) {
8897 mixCol[i] = i << 1;
8898 } else {
8899 mixCol[i] = (i << 1) ^ 0x1b;
8900 }
8901 }
8902 var mix = new Uint32Array([
8903 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
8904 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
8905 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,
8906 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,
8907 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,
8908 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,
8909 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,
8910 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,
8911 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,
8912 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,
8913 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,
8914 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,
8915 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,
8916 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,
8917 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,
8918 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,
8919 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,
8920 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,
8921 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,
8922 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,
8923 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,
8924 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,
8925 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,
8926 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,
8927 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,
8928 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,
8929 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,
8930 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,
8931 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,
8932 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,
8933 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,
8934 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,
8935 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,
8936 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,
8937 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,
8938 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,
8939 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,
8940 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,
8941 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,
8942 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,
8943 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,
8944 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
8945 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
8946
8947 function expandKey256(cipherKey) {
8948 var b = 240, result = new Uint8Array(b);
8949 var r = 1;
8950
8951 result.set(cipherKey);
8952 for (var j = 32, i = 1; j < b; ++i) {
8953 if (j % 32 === 16) {
8954 t1 = s[t1];
8955 t2 = s[t2];
8956 t3 = s[t3];
8957 t4 = s[t4];
8958 } else if (j % 32 === 0) {
8959 // RotWord
8960 var t1 = result[j - 3], t2 = result[j - 2],
8961 t3 = result[j - 1], t4 = result[j - 4];
8962 // SubWord
8963 t1 = s[t1];
8964 t2 = s[t2];
8965 t3 = s[t3];
8966 t4 = s[t4];
8967 // Rcon
8968 t1 = t1 ^ r;
8969 if ((r <<= 1) >= 256) {
8970 r = (r ^ 0x1b) & 0xFF;
8971 }
8972 }
8973
8974 for (var n = 0; n < 4; ++n) {
8975 result[j] = (t1 ^= result[j - 32]);
8976 j++;
8977 result[j] = (t2 ^= result[j - 32]);
8978 j++;
8979 result[j] = (t3 ^= result[j - 32]);
8980 j++;
8981 result[j] = (t4 ^= result[j - 32]);
8982 j++;
8983 }
8984 }
8985 return result;
8986 }
8987
8988 function decrypt256(input, key) {
8989 var state = new Uint8Array(16);
8990 state.set(input);
8991 var i, j, k;
8992 var t, u, v;
8993 // AddRoundKey
8994 for (j = 0, k = 224; j < 16; ++j, ++k) {
8995 state[j] ^= key[k];
8996 }
8997 for (i = 13; i >= 1; --i) {
8998 // InvShiftRows
8999 t = state[13];
9000 state[13] = state[9];
9001 state[9] = state[5];
9002 state[5] = state[1];
9003 state[1] = t;
9004 t = state[14];
9005 u = state[10];
9006 state[14] = state[6];
9007 state[10] = state[2];
9008 state[6] = t;
9009 state[2] = u;
9010 t = state[15];
9011 u = state[11];
9012 v = state[7];
9013 state[15] = state[3];
9014 state[11] = t;
9015 state[7] = u;
9016 state[3] = v;
9017 // InvSubBytes
9018 for (j = 0; j < 16; ++j) {
9019 state[j] = inv_s[state[j]];
9020 }
9021 // AddRoundKey
9022 for (j = 0, k = i * 16; j < 16; ++j, ++k) {
9023 state[j] ^= key[k];
9024 }
9025 // InvMixColumns
9026 for (j = 0; j < 16; j += 4) {
9027 var s0 = mix[state[j]], s1 = mix[state[j + 1]],
9028 s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
9029 t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^
9030 (s3 >>> 24) ^ (s3 << 8));
9031 state[j] = (t >>> 24) & 0xFF;
9032 state[j + 1] = (t >> 16) & 0xFF;
9033 state[j + 2] = (t >> 8) & 0xFF;
9034 state[j + 3] = t & 0xFF;
9035 }
9036 }
9037 // InvShiftRows
9038 t = state[13];
9039 state[13] = state[9];
9040 state[9] = state[5];
9041 state[5] = state[1];
9042 state[1] = t;
9043 t = state[14];
9044 u = state[10];
9045 state[14] = state[6];
9046 state[10] = state[2];
9047 state[6] = t;
9048 state[2] = u;
9049 t = state[15];
9050 u = state[11];
9051 v = state[7];
9052 state[15] = state[3];
9053 state[11] = t;
9054 state[7] = u;
9055 state[3] = v;
9056 for (j = 0; j < 16; ++j) {
9057 // InvSubBytes
9058 state[j] = inv_s[state[j]];
9059 // AddRoundKey
9060 state[j] ^= key[j];
9061 }
9062 return state;
9063 }
9064
9065 function encrypt256(input, key) {
9066 var t, u, v, k;
9067 var state = new Uint8Array(16);
9068 state.set(input);
9069 for (j = 0; j < 16; ++j) {
9070 // AddRoundKey
9071 state[j] ^= key[j];
9072 }
9073
9074 for (i = 1; i < 14; i++) {
9075 //SubBytes
9076 for (j = 0; j < 16; ++j) {
9077 state[j] = s[state[j]];
9078 }
9079 //ShiftRows
9080 v = state[1];
9081 state[1] = state[5];
9082 state[5] = state[9];
9083 state[9] = state[13];
9084 state[13] = v;
9085 v = state[2];
9086 u = state[6];
9087 state[2] = state[10];
9088 state[6] = state[14];
9089 state[10] = v;
9090 state[14] = u;
9091 v = state[3];
9092 u = state[7];
9093 t = state[11];
9094 state[3] = state[15];
9095 state[7] = v;
9096 state[11] = u;
9097 state[15] = t;
9098 //MixColumns
9099 for (var j = 0; j < 16; j += 4) {
9100 var s0 = state[j + 0], s1 = state[j + 1];
9101 var s2 = state[j + 2], s3 = state[j + 3];
9102 t = s0 ^ s1 ^ s2 ^ s3;
9103 state[j + 0] ^= t ^ mixCol[s0 ^ s1];
9104 state[j + 1] ^= t ^ mixCol[s1 ^ s2];
9105 state[j + 2] ^= t ^ mixCol[s2 ^ s3];
9106 state[j + 3] ^= t ^ mixCol[s3 ^ s0];
9107 }
9108 //AddRoundKey
9109 for (j = 0, k = i * 16; j < 16; ++j, ++k) {
9110 state[j] ^= key[k];
9111 }
9112 }
9113
9114 //SubBytes
9115 for (j = 0; j < 16; ++j) {
9116 state[j] = s[state[j]];
9117 }
9118 //ShiftRows
9119 v = state[1];
9120 state[1] = state[5];
9121 state[5] = state[9];
9122 state[9] = state[13];
9123 state[13] = v;
9124 v = state[2];
9125 u = state[6];
9126 state[2] = state[10];
9127 state[6] = state[14];
9128 state[10] = v;
9129 state[14] = u;
9130 v = state[3];
9131 u = state[7];
9132 t = state[11];
9133 state[3] = state[15];
9134 state[7] = v;
9135 state[11] = u;
9136 state[15] = t;
9137 //AddRoundKey
9138 for (j = 0, k = 224; j < 16; ++j, ++k) {
9139 state[j] ^= key[k];
9140 }
9141
9142 return state;
9143
9144 }
9145
9146 function AES256Cipher(key) {
9147 this.key = expandKey256(key);
9148 this.buffer = new Uint8Array(16);
9149 this.bufferPosition = 0;
9150 }
9151
9152 function decryptBlock2(data, finalize) {
9153 var i, j, ii, sourceLength = data.length,
9154 buffer = this.buffer, bufferLength = this.bufferPosition,
9155 result = [], iv = this.iv;
9156
9157 for (i = 0; i < sourceLength; ++i) {
9158 buffer[bufferLength] = data[i];
9159 ++bufferLength;
9160 if (bufferLength < 16) {
9161 continue;
9162 }
9163 // buffer is full, decrypting
9164 var plain = decrypt256(buffer, this.key);
9165 // xor-ing the IV vector to get plain text
9166 for (j = 0; j < 16; ++j) {
9167 plain[j] ^= iv[j];
9168 }
9169 iv = buffer;
9170 result.push(plain);
9171 buffer = new Uint8Array(16);
9172 bufferLength = 0;
9173 }
9174 // saving incomplete buffer
9175 this.buffer = buffer;
9176 this.bufferLength = bufferLength;
9177 this.iv = iv;
9178 if (result.length === 0) {
9179 return new Uint8Array([]);
9180 }
9181 // combining plain text blocks into one
9182 var outputLength = 16 * result.length;
9183 if (finalize) {
9184 // undo a padding that is described in RFC 2898
9185 var lastBlock = result[result.length - 1];
9186 var psLen = lastBlock[15];
9187 if (psLen <= 16) {
9188 for (i = 15, ii = 16 - psLen; i >= ii; --i) {
9189 if (lastBlock[i] !== psLen) {
9190 // Invalid padding, assume that the block has no padding.
9191 psLen = 0;
9192 break;
9193 }
9194 }
9195 outputLength -= psLen;
9196 result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);
9197 }
9198 }
9199 var output = new Uint8Array(outputLength);
9200 for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
9201 output.set(result[i], j);
9202 }
9203 return output;
9204
9205 }
9206
9207 AES256Cipher.prototype = {
9208 decryptBlock: function AES256Cipher_decryptBlock(data, finalize, iv) {
9209 var i, sourceLength = data.length;
9210 var buffer = this.buffer, bufferLength = this.bufferPosition;
9211 // if not supplied an IV wait for IV values
9212 // they are at the start of the stream
9213 if (iv) {
9214 this.iv = iv;
9215 } else {
9216 for (i = 0; bufferLength < 16 &&
9217 i < sourceLength; ++i, ++bufferLength) {
9218 buffer[bufferLength] = data[i];
9219 }
9220 if (bufferLength < 16) {
9221 //need more data
9222 this.bufferLength = bufferLength;
9223 return new Uint8Array([]);
9224 }
9225 this.iv = buffer;
9226 data = data.subarray(16);
9227 }
9228 this.buffer = new Uint8Array(16);
9229 this.bufferLength = 0;
9230 // starting decryption
9231 this.decryptBlock = decryptBlock2;
9232 return this.decryptBlock(data, finalize);
9233 },
9234 encrypt: function AES256Cipher_encrypt(data, iv) {
9235 var i, j, ii, sourceLength = data.length,
9236 buffer = this.buffer, bufferLength = this.bufferPosition,
9237 result = [];
9238 if (!iv) {
9239 iv = new Uint8Array(16);
9240 }
9241 for (i = 0; i < sourceLength; ++i) {
9242 buffer[bufferLength] = data[i];
9243 ++bufferLength;
9244 if (bufferLength < 16) {
9245 continue;
9246 }
9247 for (j = 0; j < 16; ++j) {
9248 buffer[j] ^= iv[j];
9249 }
9250
9251 // buffer is full, encrypting
9252 var cipher = encrypt256(buffer, this.key);
9253 this.iv = cipher;
9254 result.push(cipher);
9255 buffer = new Uint8Array(16);
9256 bufferLength = 0;
9257 }
9258 // saving incomplete buffer
9259 this.buffer = buffer;
9260 this.bufferLength = bufferLength;
9261 this.iv = iv;
9262 if (result.length === 0) {
9263 return new Uint8Array([]);
9264 }
9265 // combining plain text blocks into one
9266 var outputLength = 16 * result.length;
9267 var output = new Uint8Array(outputLength);
9268 for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
9269 output.set(result[i], j);
9270 }
9271 return output;
9272 }
9273 };
9274
9275 return AES256Cipher;
9276 })();
9277
9278 var PDF17 = (function PDF17Closure() {
9279
9280 function compareByteArrays(array1, array2) {
9281 if (array1.length !== array2.length) {
9282 return false;
9283 }
9284 for (var i = 0; i < array1.length; i++) {
9285 if (array1[i] !== array2[i]) {
9286 return false;
9287 }
9288 }
9289 return true;
9290 }
9291
9292 function PDF17() {
9293 }
9294
9295 PDF17.prototype = {
9296 checkOwnerPassword: function PDF17_checkOwnerPassword(password,
9297 ownerValidationSalt,
9298 userBytes,
9299 ownerPassword) {
9300 var hashData = new Uint8Array(password.length + 56);
9301 hashData.set(password, 0);
9302 hashData.set(ownerValidationSalt, password.length);
9303 hashData.set(userBytes, password.length + ownerValidationSalt.length);
9304 var result = calculateSHA256(hashData, 0, hashData.length);
9305 return compareByteArrays(result, ownerPassword);
9306 },
9307 checkUserPassword: function PDF17_checkUserPassword(password,
9308 userValidationSalt,
9309 userPassword) {
9310 var hashData = new Uint8Array(password.length + 8);
9311 hashData.set(password, 0);
9312 hashData.set(userValidationSalt, password.length);
9313 var result = calculateSHA256(hashData, 0, hashData.length);
9314 return compareByteArrays(result, userPassword);
9315 },
9316 getOwnerKey: function PDF17_getOwnerKey(password, ownerKeySalt, userBytes,
9317 ownerEncryption) {
9318 var hashData = new Uint8Array(password.length + 56);
9319 hashData.set(password, 0);
9320 hashData.set(ownerKeySalt, password.length);
9321 hashData.set(userBytes, password.length + ownerKeySalt.length);
9322 var key = calculateSHA256(hashData, 0, hashData.length);
9323 var cipher = new AES256Cipher(key);
9324 return cipher.decryptBlock(ownerEncryption,
9325 false,
9326 new Uint8Array(16));
9327
9328 },
9329 getUserKey: function PDF17_getUserKey(password, userKeySalt,
9330 userEncryption) {
9331 var hashData = new Uint8Array(password.length + 8);
9332 hashData.set(password, 0);
9333 hashData.set(userKeySalt, password.length);
9334 //key is the decryption key for the UE string
9335 var key = calculateSHA256(hashData, 0, hashData.length);
9336 var cipher = new AES256Cipher(key);
9337 return cipher.decryptBlock(userEncryption,
9338 false,
9339 new Uint8Array(16));
9340 }
9341 };
9342 return PDF17;
9343 })();
9344
9345 var PDF20 = (function PDF20Closure() {
9346
9347 function concatArrays(array1, array2) {
9348 var t = new Uint8Array(array1.length + array2.length);
9349 t.set(array1, 0);
9350 t.set(array2, array1.length);
9351 return t;
9352 }
9353
9354 function calculatePDF20Hash(password, input, userBytes) {
9355 //This refers to Algorithm 2.B as defined in ISO 32000-2
9356 var k = calculateSHA256(input, 0, input.length).subarray(0, 32);
9357 var e = [0];
9358 var i = 0;
9359 while (i < 64 || e[e.length - 1] > i - 32) {
9360 var arrayLength = password.length + k.length + userBytes.length;
9361
9362 var k1 = new Uint8Array(arrayLength * 64);
9363 var array = concatArrays(password, k);
9364 array = concatArrays(array, userBytes);
9365 for (var j = 0, pos = 0; j < 64; j++, pos += arrayLength) {
9366 k1.set(array, pos);
9367 }
9368 //AES128 CBC NO PADDING with
9369 //first 16 bytes of k as the key and the second 16 as the iv.
9370 var cipher = new AES128Cipher(k.subarray(0, 16));
9371 e = cipher.encrypt(k1, k.subarray(16, 32));
9372 //Now we have to take the first 16 bytes of an unsigned
9373 //big endian integer... and compute the remainder
9374 //modulo 3.... That is a fairly large number and
9375 //JavaScript isn't going to handle that well...
9376 //So we're using a trick that allows us to perform
9377 //modulo math byte by byte
9378 var remainder = 0;
9379 for (var z = 0; z < 16; z++) {
9380 remainder *= (256 % 3);
9381 remainder %= 3;
9382 remainder += ((e[z] >>> 0) % 3);
9383 remainder %= 3;
9384 }
9385 if (remainder === 0) {
9386 k = calculateSHA256(e, 0, e.length);
9387 }
9388 else if (remainder === 1) {
9389 k = calculateSHA384(e, 0, e.length);
9390 }
9391 else if (remainder === 2) {
9392 k = calculateSHA512(e, 0, e.length);
9393 }
9394 i++;
9395 }
9396 return k.subarray(0, 32);
9397 }
9398
9399 function PDF20() {
9400 }
9401
9402 function compareByteArrays(array1, array2) {
9403 if (array1.length !== array2.length) {
9404 return false;
9405 }
9406 for (var i = 0; i < array1.length; i++) {
9407 if (array1[i] !== array2[i]) {
9408 return false;
9409 }
9410 }
9411 return true;
9412 }
9413
9414 PDF20.prototype = {
9415 hash: function PDF20_hash(password, concatBytes, userBytes) {
9416 return calculatePDF20Hash(password, concatBytes, userBytes);
9417 },
9418 checkOwnerPassword: function PDF20_checkOwnerPassword(password,
9419 ownerValidationSalt,
9420 userBytes,
9421 ownerPassword) {
9422 var hashData = new Uint8Array(password.length + 56);
9423 hashData.set(password, 0);
9424 hashData.set(ownerValidationSalt, password.length);
9425 hashData.set(userBytes, password.length + ownerValidationSalt.length);
9426 var result = calculatePDF20Hash(password, hashData, userBytes);
9427 return compareByteArrays(result, ownerPassword);
9428 },
9429 checkUserPassword: function PDF20_checkUserPassword(password,
9430 userValidationSalt,
9431 userPassword) {
9432 var hashData = new Uint8Array(password.length + 8);
9433 hashData.set(password, 0);
9434 hashData.set(userValidationSalt, password.length);
9435 var result = calculatePDF20Hash(password, hashData, []);
9436 return compareByteArrays(result, userPassword);
9437 },
9438 getOwnerKey: function PDF20_getOwnerKey(password, ownerKeySalt, userBytes,
9439 ownerEncryption) {
9440 var hashData = new Uint8Array(password.length + 56);
9441 hashData.set(password, 0);
9442 hashData.set(ownerKeySalt, password.length);
9443 hashData.set(userBytes, password.length + ownerKeySalt.length);
9444 var key = calculatePDF20Hash(password, hashData, userBytes);
9445 var cipher = new AES256Cipher(key);
9446 return cipher.decryptBlock(ownerEncryption,
9447 false,
9448 new Uint8Array(16));
9449
9450 },
9451 getUserKey: function PDF20_getUserKey(password, userKeySalt,
9452 userEncryption) {
9453 var hashData = new Uint8Array(password.length + 8);
9454 hashData.set(password, 0);
9455 hashData.set(userKeySalt, password.length);
9456 //key is the decryption key for the UE string
9457 var key = calculatePDF20Hash(password, hashData, []);
9458 var cipher = new AES256Cipher(key);
9459 return cipher.decryptBlock(userEncryption,
9460 false,
9461 new Uint8Array(16));
9462 }
9463 };
9464 return PDF20;
9465 })();
9466
9467 var CipherTransform = (function CipherTransformClosure() {
9468 function CipherTransform(stringCipherConstructor, streamCipherConstructor) {
9469 this.stringCipherConstructor = stringCipherConstructor;
9470 this.streamCipherConstructor = streamCipherConstructor;
9471 }
9472
9473 CipherTransform.prototype = {
9474 createStream: function CipherTransform_createStream(stream, length) {
9475 var cipher = new this.streamCipherConstructor();
9476 return new DecryptStream(stream, length,
9477 function cipherTransformDecryptStream(data, finalize) {
9478 return cipher.decryptBlock(data, finalize);
9479 }
9480 );
9481 },
9482 decryptString: function CipherTransform_decryptString(s) {
9483 var cipher = new this.stringCipherConstructor();
9484 var data = stringToBytes(s);
9485 data = cipher.decryptBlock(data, true);
9486 return bytesToString(data);
9487 }
9488 };
9489 return CipherTransform;
9490 })();
9491
9492 var CipherTransformFactory = (function CipherTransformFactoryClosure() {
9493 var defaultPasswordBytes = new Uint8Array([
9494 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
9495 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
9496 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
9497 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
9498
9499 function createEncryptionKey20(revision, password, ownerPassword,
9500 ownerValidationSalt, ownerKeySalt, uBytes,
9501 userPassword, userValidationSalt, userKeySalt,
9502 ownerEncryption, userEncryption, perms) {
9503 if (password) {
9504 var passwordLength = Math.min(127, password.length);
9505 password = password.subarray(0, passwordLength);
9506 } else {
9507 password = [];
9508 }
9509 var pdfAlgorithm;
9510 if (revision === 6) {
9511 pdfAlgorithm = new PDF20();
9512 } else {
9513 pdfAlgorithm = new PDF17();
9514 }
9515
9516 if (pdfAlgorithm) {
9517 if (pdfAlgorithm.checkUserPassword(password, userValidationSalt,
9518 userPassword)) {
9519 return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption);
9520 } else if (pdfAlgorithm.checkOwnerPassword(password, ownerValidationSalt,
9521 uBytes,
9522 ownerPassword)) {
9523 return pdfAlgorithm.getOwnerKey(password, ownerKeySalt, uBytes,
9524 ownerEncryption);
9525 }
9526 }
9527
9528 return null;
9529 }
9530
9531 function prepareKeyData(fileId, password, ownerPassword, userPassword,
9532 flags, revision, keyLength, encryptMetadata) {
9533 var hashDataSize = 40 + ownerPassword.length + fileId.length;
9534 var hashData = new Uint8Array(hashDataSize), i = 0, j, n;
9535 if (password) {
9536 n = Math.min(32, password.length);
9537 for (; i < n; ++i) {
9538 hashData[i] = password[i];
9539 }
9540 }
9541 j = 0;
9542 while (i < 32) {
9543 hashData[i++] = defaultPasswordBytes[j++];
9544 }
9545 // as now the padded password in the hashData[0..i]
9546 for (j = 0, n = ownerPassword.length; j < n; ++j) {
9547 hashData[i++] = ownerPassword[j];
9548 }
9549 hashData[i++] = flags & 0xFF;
9550 hashData[i++] = (flags >> 8) & 0xFF;
9551 hashData[i++] = (flags >> 16) & 0xFF;
9552 hashData[i++] = (flags >>> 24) & 0xFF;
9553 for (j = 0, n = fileId.length; j < n; ++j) {
9554 hashData[i++] = fileId[j];
9555 }
9556 if (revision >= 4 && !encryptMetadata) {
9557 hashData[i++] = 0xFF;
9558 hashData[i++] = 0xFF;
9559 hashData[i++] = 0xFF;
9560 hashData[i++] = 0xFF;
9561 }
9562 var hash = calculateMD5(hashData, 0, i);
9563 var keyLengthInBytes = keyLength >> 3;
9564 if (revision >= 3) {
9565 for (j = 0; j < 50; ++j) {
9566 hash = calculateMD5(hash, 0, keyLengthInBytes);
9567 }
9568 }
9569 var encryptionKey = hash.subarray(0, keyLengthInBytes);
9570 var cipher, checkData;
9571
9572 if (revision >= 3) {
9573 for (i = 0; i < 32; ++i) {
9574 hashData[i] = defaultPasswordBytes[i];
9575 }
9576 for (j = 0, n = fileId.length; j < n; ++j) {
9577 hashData[i++] = fileId[j];
9578 }
9579 cipher = new ARCFourCipher(encryptionKey);
9580 checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
9581 n = encryptionKey.length;
9582 var derivedKey = new Uint8Array(n), k;
9583 for (j = 1; j <= 19; ++j) {
9584 for (k = 0; k < n; ++k) {
9585 derivedKey[k] = encryptionKey[k] ^ j;
9586 }
9587 cipher = new ARCFourCipher(derivedKey);
9588 checkData = cipher.encryptBlock(checkData);
9589 }
9590 for (j = 0, n = checkData.length; j < n; ++j) {
9591 if (userPassword[j] !== checkData[j]) {
9592 return null;
9593 }
9594 }
9595 } else {
9596 cipher = new ARCFourCipher(encryptionKey);
9597 checkData = cipher.encryptBlock(defaultPasswordBytes);
9598 for (j = 0, n = checkData.length; j < n; ++j) {
9599 if (userPassword[j] !== checkData[j]) {
9600 return null;
9601 }
9602 }
9603 }
9604 return encryptionKey;
9605 }
9606
9607 function decodeUserPassword(password, ownerPassword, revision, keyLength) {
9608 var hashData = new Uint8Array(32), i = 0, j, n;
9609 n = Math.min(32, password.length);
9610 for (; i < n; ++i) {
9611 hashData[i] = password[i];
9612 }
9613 j = 0;
9614 while (i < 32) {
9615 hashData[i++] = defaultPasswordBytes[j++];
9616 }
9617 var hash = calculateMD5(hashData, 0, i);
9618 var keyLengthInBytes = keyLength >> 3;
9619 if (revision >= 3) {
9620 for (j = 0; j < 50; ++j) {
9621 hash = calculateMD5(hash, 0, hash.length);
9622 }
9623 }
9624
9625 var cipher, userPassword;
9626 if (revision >= 3) {
9627 userPassword = ownerPassword;
9628 var derivedKey = new Uint8Array(keyLengthInBytes), k;
9629 for (j = 19; j >= 0; j--) {
9630 for (k = 0; k < keyLengthInBytes; ++k) {
9631 derivedKey[k] = hash[k] ^ j;
9632 }
9633 cipher = new ARCFourCipher(derivedKey);
9634 userPassword = cipher.encryptBlock(userPassword);
9635 }
9636 } else {
9637 cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes));
9638 userPassword = cipher.encryptBlock(ownerPassword);
9639 }
9640 return userPassword;
9641 }
9642
9643 var identityName = Name.get('Identity');
9644
9645 function CipherTransformFactory(dict, fileId, password) {
9646 var filter = dict.get('Filter');
9647 if (!isName(filter) || filter.name !== 'Standard') {
9648 error('unknown encryption method');
9649 }
9650 this.dict = dict;
9651 var algorithm = dict.get('V');
9652 if (!isInt(algorithm) ||
9653 (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 &&
9654 algorithm !== 5)) {
9655 error('unsupported encryption algorithm');
9656 }
9657 this.algorithm = algorithm;
9658 var keyLength = dict.get('Length') || 40;
9659 if (!isInt(keyLength) ||
9660 keyLength < 40 || (keyLength % 8) !== 0) {
9661 error('invalid key length');
9662 }
9663
9664 // prepare keys
9665 var ownerPassword = stringToBytes(dict.get('O')).subarray(0, 32);
9666 var userPassword = stringToBytes(dict.get('U')).subarray(0, 32);
9667 var flags = dict.get('P');
9668 var revision = dict.get('R');
9669 // meaningful when V is 4 or 5
9670 var encryptMetadata = ((algorithm === 4 || algorithm === 5) &&
9671 dict.get('EncryptMetadata') !== false);
9672 this.encryptMetadata = encryptMetadata;
9673
9674 var fileIdBytes = stringToBytes(fileId);
9675 var passwordBytes;
9676 if (password) {
9677 passwordBytes = stringToBytes(password);
9678 }
9679
9680 var encryptionKey;
9681 if (algorithm !== 5) {
9682 encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
9683 ownerPassword, userPassword, flags,
9684 revision, keyLength, encryptMetadata);
9685 }
9686 else {
9687 var ownerValidationSalt = stringToBytes(dict.get('O')).subarray(32, 40);
9688 var ownerKeySalt = stringToBytes(dict.get('O')).subarray(40, 48);
9689 var uBytes = stringToBytes(dict.get('U')).subarray(0, 48);
9690 var userValidationSalt = stringToBytes(dict.get('U')).subarray(32, 40);
9691 var userKeySalt = stringToBytes(dict.get('U')).subarray(40, 48);
9692 var ownerEncryption = stringToBytes(dict.get('OE'));
9693 var userEncryption = stringToBytes(dict.get('UE'));
9694 var perms = stringToBytes(dict.get('Perms'));
9695 encryptionKey =
9696 createEncryptionKey20(revision, passwordBytes,
9697 ownerPassword, ownerValidationSalt,
9698 ownerKeySalt, uBytes,
9699 userPassword, userValidationSalt,
9700 userKeySalt, ownerEncryption,
9701 userEncryption, perms);
9702 }
9703 if (!encryptionKey && !password) {
9704 throw new PasswordException('No password given',
9705 PasswordResponses.NEED_PASSWORD);
9706 } else if (!encryptionKey && password) {
9707 // Attempting use the password as an owner password
9708 var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword,
9709 revision, keyLength);
9710 encryptionKey = prepareKeyData(fileIdBytes, decodedPassword,
9711 ownerPassword, userPassword, flags,
9712 revision, keyLength, encryptMetadata);
9713 }
9714
9715 if (!encryptionKey) {
9716 throw new PasswordException('Incorrect Password',
9717 PasswordResponses.INCORRECT_PASSWORD);
9718 }
9719
9720 this.encryptionKey = encryptionKey;
9721
9722 if (algorithm >= 4) {
9723 this.cf = dict.get('CF');
9724 this.stmf = dict.get('StmF') || identityName;
9725 this.strf = dict.get('StrF') || identityName;
9726 this.eff = dict.get('EFF') || this.stmf;
9727 }
9728 }
9729
9730 function buildObjectKey(num, gen, encryptionKey, isAes) {
9731 var key = new Uint8Array(encryptionKey.length + 9), i, n;
9732 for (i = 0, n = encryptionKey.length; i < n; ++i) {
9733 key[i] = encryptionKey[i];
9734 }
9735 key[i++] = num & 0xFF;
9736 key[i++] = (num >> 8) & 0xFF;
9737 key[i++] = (num >> 16) & 0xFF;
9738 key[i++] = gen & 0xFF;
9739 key[i++] = (gen >> 8) & 0xFF;
9740 if (isAes) {
9741 key[i++] = 0x73;
9742 key[i++] = 0x41;
9743 key[i++] = 0x6C;
9744 key[i++] = 0x54;
9745 }
9746 var hash = calculateMD5(key, 0, i);
9747 return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
9748 }
9749
9750 function buildCipherConstructor(cf, name, num, gen, key) {
9751 var cryptFilter = cf.get(name.name);
9752 var cfm;
9753 if (cryptFilter !== null && cryptFilter !== undefined) {
9754 cfm = cryptFilter.get('CFM');
9755 }
9756 if (!cfm || cfm.name === 'None') {
9757 return function cipherTransformFactoryBuildCipherConstructorNone() {
9758 return new NullCipher();
9759 };
9760 }
9761 if ('V2' === cfm.name) {
9762 return function cipherTransformFactoryBuildCipherConstructorV2() {
9763 return new ARCFourCipher(buildObjectKey(num, gen, key, false));
9764 };
9765 }
9766 if ('AESV2' === cfm.name) {
9767 return function cipherTransformFactoryBuildCipherConstructorAESV2() {
9768 return new AES128Cipher(buildObjectKey(num, gen, key, true));
9769 };
9770 }
9771 if ('AESV3' === cfm.name) {
9772 return function cipherTransformFactoryBuildCipherConstructorAESV3() {
9773 return new AES256Cipher(key);
9774 };
9775 }
9776 error('Unknown crypto method');
9777 }
9778
9779 CipherTransformFactory.prototype = {
9780 createCipherTransform:
9781 function CipherTransformFactory_createCipherTransform(num, gen) {
9782 if (this.algorithm === 4 || this.algorithm === 5) {
9783 return new CipherTransform(
9784 buildCipherConstructor(this.cf, this.stmf,
9785 num, gen, this.encryptionKey),
9786 buildCipherConstructor(this.cf, this.strf,
9787 num, gen, this.encryptionKey));
9788 }
9789 // algorithms 1 and 2
9790 var key = buildObjectKey(num, gen, this.encryptionKey, false);
9791 var cipherConstructor = function buildCipherCipherConstructor() {
9792 return new ARCFourCipher(key);
9793 };
9794 return new CipherTransform(cipherConstructor, cipherConstructor);
9795 }
9796 };
9797
9798 return CipherTransformFactory;
9799 })();
9800
9801
9802 var PatternType = {
9803 FUNCTION_BASED: 1,
9804 AXIAL: 2,
9805 RADIAL: 3,
9806 FREE_FORM_MESH: 4,
9807 LATTICE_FORM_MESH: 5,
9808 COONS_PATCH_MESH: 6,
9809 TENSOR_PATCH_MESH: 7
9810 };
9811
9812 var Pattern = (function PatternClosure() {
9813 // Constructor should define this.getPattern
9814 function Pattern() {
9815 error('should not call Pattern constructor');
9816 }
9817
9818 Pattern.prototype = {
9819 // Input: current Canvas context
9820 // Output: the appropriate fillStyle or strokeStyle
9821 getPattern: function Pattern_getPattern(ctx) {
9822 error('Should not call Pattern.getStyle: ' + ctx);
9823 }
9824 };
9825
9826 Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref,
9827 res) {
9828
9829 var dict = isStream(shading) ? shading.dict : shading;
9830 var type = dict.get('ShadingType');
9831
9832 try {
9833 switch (type) {
9834 case PatternType.AXIAL:
9835 case PatternType.RADIAL:
9836 // Both radial and axial shadings are handled by RadialAxial shading.
9837 return new Shadings.RadialAxial(dict, matrix, xref, res);
9838 case PatternType.FREE_FORM_MESH:
9839 case PatternType.LATTICE_FORM_MESH:
9840 case PatternType.COONS_PATCH_MESH:
9841 case PatternType.TENSOR_PATCH_MESH:
9842 return new Shadings.Mesh(shading, matrix, xref, res);
9843 default:
9844 throw new Error('Unknown PatternType: ' + type);
9845 }
9846 } catch (ex) {
9847 if (ex instanceof MissingDataException) {
9848 throw ex;
9849 }
9850 UnsupportedManager.notify(UNSUPPORTED_FEATURES.shadingPattern);
9851 warn(ex);
9852 return new Shadings.Dummy();
9853 }
9854 };
9855 return Pattern;
9856 })();
9857
9858 var Shadings = {};
9859
9860 // A small number to offset the first/last color stops so we can insert ones to
9861 // support extend. Number.MIN_VALUE appears to be too small and breaks the
9862 // extend. 1e-7 works in FF but chrome seems to use an even smaller sized number
9863 // internally so we have to go bigger.
9864 Shadings.SMALL_NUMBER = 1e-2;
9865
9866 // Radial and axial shading have very similar implementations
9867 // If needed, the implementations can be broken into two classes
9868 Shadings.RadialAxial = (function RadialAxialClosure() {
9869 function RadialAxial(dict, matrix, xref, res) {
9870 this.matrix = matrix;
9871 this.coordsArr = dict.get('Coords');
9872 this.shadingType = dict.get('ShadingType');
9873 this.type = 'Pattern';
9874 var cs = dict.get('ColorSpace', 'CS');
9875 cs = ColorSpace.parse(cs, xref, res);
9876 this.cs = cs;
9877
9878 var t0 = 0.0, t1 = 1.0;
9879 if (dict.has('Domain')) {
9880 var domainArr = dict.get('Domain');
9881 t0 = domainArr[0];
9882 t1 = domainArr[1];
9883 }
9884
9885 var extendStart = false, extendEnd = false;
9886 if (dict.has('Extend')) {
9887 var extendArr = dict.get('Extend');
9888 extendStart = extendArr[0];
9889 extendEnd = extendArr[1];
9890 }
9891
9892 if (this.shadingType === PatternType.RADIAL &&
9893 (!extendStart || !extendEnd)) {
9894 // Radial gradient only currently works if either circle is fully within
9895 // the other circle.
9896 var x1 = this.coordsArr[0];
9897 var y1 = this.coordsArr[1];
9898 var r1 = this.coordsArr[2];
9899 var x2 = this.coordsArr[3];
9900 var y2 = this.coordsArr[4];
9901 var r2 = this.coordsArr[5];
9902 var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
9903 if (r1 <= r2 + distance &&
9904 r2 <= r1 + distance) {
9905 warn('Unsupported radial gradient.');
9906 }
9907 }
9908
9909 this.extendStart = extendStart;
9910 this.extendEnd = extendEnd;
9911
9912 var fnObj = dict.get('Function');
9913 var fn = PDFFunction.parseArray(xref, fnObj);
9914
9915 // 10 samples seems good enough for now, but probably won't work
9916 // if there are sharp color changes. Ideally, we would implement
9917 // the spec faithfully and add lossless optimizations.
9918 var diff = t1 - t0;
9919 var step = diff / 10;
9920
9921 var colorStops = this.colorStops = [];
9922
9923 // Protect against bad domains so we don't end up in an infinte loop below.
9924 if (t0 >= t1 || step <= 0) {
9925 // Acrobat doesn't seem to handle these cases so we'll ignore for
9926 // now.
9927 info('Bad shading domain.');
9928 return;
9929 }
9930
9931 var color = new Float32Array(cs.numComps), ratio = new Float32Array(1);
9932 var rgbColor;
9933 for (var i = t0; i <= t1; i += step) {
9934 ratio[0] = i;
9935 fn(ratio, 0, color, 0);
9936 rgbColor = cs.getRgb(color, 0);
9937 var cssColor = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
9938 colorStops.push([(i - t0) / diff, cssColor]);
9939 }
9940
9941 var background = 'transparent';
9942 if (dict.has('Background')) {
9943 rgbColor = cs.getRgb(dict.get('Background'), 0);
9944 background = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
9945 }
9946
9947 if (!extendStart) {
9948 // Insert a color stop at the front and offset the first real color stop
9949 // so it doesn't conflict with the one we insert.
9950 colorStops.unshift([0, background]);
9951 colorStops[1][0] += Shadings.SMALL_NUMBER;
9952 }
9953 if (!extendEnd) {
9954 // Same idea as above in extendStart but for the end.
9955 colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER;
9956 colorStops.push([1, background]);
9957 }
9958
9959 this.colorStops = colorStops;
9960 }
9961
9962 RadialAxial.prototype = {
9963 getIR: function RadialAxial_getIR() {
9964 var coordsArr = this.coordsArr;
9965 var shadingType = this.shadingType;
9966 var type, p0, p1, r0, r1;
9967 if (shadingType === PatternType.AXIAL) {
9968 p0 = [coordsArr[0], coordsArr[1]];
9969 p1 = [coordsArr[2], coordsArr[3]];
9970 r0 = null;
9971 r1 = null;
9972 type = 'axial';
9973 } else if (shadingType === PatternType.RADIAL) {
9974 p0 = [coordsArr[0], coordsArr[1]];
9975 p1 = [coordsArr[3], coordsArr[4]];
9976 r0 = coordsArr[2];
9977 r1 = coordsArr[5];
9978 type = 'radial';
9979 } else {
9980 error('getPattern type unknown: ' + shadingType);
9981 }
9982
9983 var matrix = this.matrix;
9984 if (matrix) {
9985 p0 = Util.applyTransform(p0, matrix);
9986 p1 = Util.applyTransform(p1, matrix);
9987 }
9988
9989 return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
9990 }
9991 };
9992
9993 return RadialAxial;
9994 })();
9995
9996 // All mesh shading. For now, they will be presented as set of the triangles
9997 // to be drawn on the canvas and rgb color for each vertex.
9998 Shadings.Mesh = (function MeshClosure() {
9999 function MeshStreamReader(stream, context) {
10000 this.stream = stream;
10001 this.context = context;
10002 this.buffer = 0;
10003 this.bufferLength = 0;
10004
10005 var numComps = context.numComps;
10006 this.tmpCompsBuf = new Float32Array(numComps);
10007 var csNumComps = context.colorSpace;
10008 this.tmpCsCompsBuf = context.colorFn ? new Float32Array(csNumComps) :
10009 this.tmpCompsBuf;
10010 }
10011 MeshStreamReader.prototype = {
10012 get hasData() {
10013 if (this.stream.end) {
10014 return this.stream.pos < this.stream.end;
10015 }
10016 if (this.bufferLength > 0) {
10017 return true;
10018 }
10019 var nextByte = this.stream.getByte();
10020 if (nextByte < 0) {
10021 return false;
10022 }
10023 this.buffer = nextByte;
10024 this.bufferLength = 8;
10025 return true;
10026 },
10027 readBits: function MeshStreamReader_readBits(n) {
10028 var buffer = this.buffer;
10029 var bufferLength = this.bufferLength;
10030 if (n === 32) {
10031 if (bufferLength === 0) {
10032 return ((this.stream.getByte() << 24) |
10033 (this.stream.getByte() << 16) | (this.stream.getByte() << 8) |
10034 this.stream.getByte()) >>> 0;
10035 }
10036 buffer = (buffer << 24) | (this.stream.getByte() << 16) |
10037 (this.stream.getByte() << 8) | this.stream.getByte();
10038 var nextByte = this.stream.getByte();
10039 this.buffer = nextByte & ((1 << bufferLength) - 1);
10040 return ((buffer << (8 - bufferLength)) |
10041 ((nextByte & 0xFF) >> bufferLength)) >>> 0;
10042 }
10043 if (n === 8 && bufferLength === 0) {
10044 return this.stream.getByte();
10045 }
10046 while (bufferLength < n) {
10047 buffer = (buffer << 8) | this.stream.getByte();
10048 bufferLength += 8;
10049 }
10050 bufferLength -= n;
10051 this.bufferLength = bufferLength;
10052 this.buffer = buffer & ((1 << bufferLength) - 1);
10053 return buffer >> bufferLength;
10054 },
10055 align: function MeshStreamReader_align() {
10056 this.buffer = 0;
10057 this.bufferLength = 0;
10058 },
10059 readFlag: function MeshStreamReader_readFlag() {
10060 return this.readBits(this.context.bitsPerFlag);
10061 },
10062 readCoordinate: function MeshStreamReader_readCoordinate() {
10063 var bitsPerCoordinate = this.context.bitsPerCoordinate;
10064 var xi = this.readBits(bitsPerCoordinate);
10065 var yi = this.readBits(bitsPerCoordinate);
10066 var decode = this.context.decode;
10067 var scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) :
10068 2.3283064365386963e-10; // 2 ^ -32
10069 return [
10070 xi * scale * (decode[1] - decode[0]) + decode[0],
10071 yi * scale * (decode[3] - decode[2]) + decode[2]
10072 ];
10073 },
10074 readComponents: function MeshStreamReader_readComponents() {
10075 var numComps = this.context.numComps;
10076 var bitsPerComponent = this.context.bitsPerComponent;
10077 var scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) :
10078 2.3283064365386963e-10; // 2 ^ -32
10079 var decode = this.context.decode;
10080 var components = this.tmpCompsBuf;
10081 for (var i = 0, j = 4; i < numComps; i++, j += 2) {
10082 var ci = this.readBits(bitsPerComponent);
10083 components[i] = ci * scale * (decode[j + 1] - decode[j]) + decode[j];
10084 }
10085 var color = this.tmpCsCompsBuf;
10086 if (this.context.colorFn) {
10087 this.context.colorFn(components, 0, color, 0);
10088 }
10089 return this.context.colorSpace.getRgb(color, 0);
10090 }
10091 };
10092
10093 function decodeType4Shading(mesh, reader) {
10094 var coords = mesh.coords;
10095 var colors = mesh.colors;
10096 var operators = [];
10097 var ps = []; // not maintaining cs since that will match ps
10098 var verticesLeft = 0; // assuming we have all data to start a new triangle
10099 while (reader.hasData) {
10100 var f = reader.readFlag();
10101 var coord = reader.readCoordinate();
10102 var color = reader.readComponents();
10103 if (verticesLeft === 0) { // ignoring flags if we started a triangle
10104 assert(0 <= f && f <= 2, 'Unknown type4 flag');
10105 switch (f) {
10106 case 0:
10107 verticesLeft = 3;
10108 break;
10109 case 1:
10110 ps.push(ps[ps.length - 2], ps[ps.length - 1]);
10111 verticesLeft = 1;
10112 break;
10113 case 2:
10114 ps.push(ps[ps.length - 3], ps[ps.length - 1]);
10115 verticesLeft = 1;
10116 break;
10117 }
10118 operators.push(f);
10119 }
10120 ps.push(coords.length);
10121 coords.push(coord);
10122 colors.push(color);
10123 verticesLeft--;
10124
10125 reader.align();
10126 }
10127
10128 var psPacked = new Int32Array(ps);
10129
10130 mesh.figures.push({
10131 type: 'triangles',
10132 coords: psPacked,
10133 colors: psPacked
10134 });
10135 }
10136
10137 function decodeType5Shading(mesh, reader, verticesPerRow) {
10138 var coords = mesh.coords;
10139 var colors = mesh.colors;
10140 var ps = []; // not maintaining cs since that will match ps
10141 while (reader.hasData) {
10142 var coord = reader.readCoordinate();
10143 var color = reader.readComponents();
10144 ps.push(coords.length);
10145 coords.push(coord);
10146 colors.push(color);
10147 }
10148
10149 var psPacked = new Int32Array(ps);
10150
10151 mesh.figures.push({
10152 type: 'lattice',
10153 coords: psPacked,
10154 colors: psPacked,
10155 verticesPerRow: verticesPerRow
10156 });
10157 }
10158
10159 var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3;
10160 var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20;
10161
10162 var TRIANGLE_DENSITY = 20; // count of triangles per entire mesh bounds
10163
10164 var getB = (function getBClosure() {
10165 function buildB(count) {
10166 var lut = [];
10167 for (var i = 0; i <= count; i++) {
10168 var t = i / count, t_ = 1 - t;
10169 lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_,
10170 3 * t * t * t_, t * t * t]));
10171 }
10172 return lut;
10173 }
10174 var cache = [];
10175 return function getB(count) {
10176 if (!cache[count]) {
10177 cache[count] = buildB(count);
10178 }
10179 return cache[count];
10180 };
10181 })();
10182
10183 function buildFigureFromPatch(mesh, index) {
10184 var figure = mesh.figures[index];
10185 assert(figure.type === 'patch', 'Unexpected patch mesh figure');
10186
10187 var coords = mesh.coords, colors = mesh.colors;
10188 var pi = figure.coords;
10189 var ci = figure.colors;
10190
10191 var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0],
10192 coords[pi[12]][0], coords[pi[15]][0]);
10193 var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1],
10194 coords[pi[12]][1], coords[pi[15]][1]);
10195 var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0],
10196 coords[pi[12]][0], coords[pi[15]][0]);
10197 var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1],
10198 coords[pi[12]][1], coords[pi[15]][1]);
10199 var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY /
10200 (mesh.bounds[2] - mesh.bounds[0]));
10201 splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
10202 Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy));
10203 var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY /
10204 (mesh.bounds[3] - mesh.bounds[1]));
10205 splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
10206 Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy));
10207
10208 var verticesPerRow = splitXBy + 1;
10209 var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow);
10210 var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow);
10211 var k = 0;
10212 var cl = new Uint8Array(3), cr = new Uint8Array(3);
10213 var c0 = colors[ci[0]], c1 = colors[ci[1]],
10214 c2 = colors[ci[2]], c3 = colors[ci[3]];
10215 var bRow = getB(splitYBy), bCol = getB(splitXBy);
10216 for (var row = 0; row <= splitYBy; row++) {
10217 cl[0] = ((c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy) | 0;
10218 cl[1] = ((c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy) | 0;
10219 cl[2] = ((c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy) | 0;
10220
10221 cr[0] = ((c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy) | 0;
10222 cr[1] = ((c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy) | 0;
10223 cr[2] = ((c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy) | 0;
10224
10225 for (var col = 0; col <= splitXBy; col++, k++) {
10226 if ((row === 0 || row === splitYBy) &&
10227 (col === 0 || col === splitXBy)) {
10228 continue;
10229 }
10230 var x = 0, y = 0;
10231 var q = 0;
10232 for (var i = 0; i <= 3; i++) {
10233 for (var j = 0; j <= 3; j++, q++) {
10234 var m = bRow[row][i] * bCol[col][j];
10235 x += coords[pi[q]][0] * m;
10236 y += coords[pi[q]][1] * m;
10237 }
10238 }
10239 figureCoords[k] = coords.length;
10240 coords.push([x, y]);
10241 figureColors[k] = colors.length;
10242 var newColor = new Uint8Array(3);
10243 newColor[0] = ((cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy) | 0;
10244 newColor[1] = ((cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy) | 0;
10245 newColor[2] = ((cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy) | 0;
10246 colors.push(newColor);
10247 }
10248 }
10249 figureCoords[0] = pi[0];
10250 figureColors[0] = ci[0];
10251 figureCoords[splitXBy] = pi[3];
10252 figureColors[splitXBy] = ci[1];
10253 figureCoords[verticesPerRow * splitYBy] = pi[12];
10254 figureColors[verticesPerRow * splitYBy] = ci[2];
10255 figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15];
10256 figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3];
10257
10258 mesh.figures[index] = {
10259 type: 'lattice',
10260 coords: figureCoords,
10261 colors: figureColors,
10262 verticesPerRow: verticesPerRow
10263 };
10264 }
10265
10266 function decodeType6Shading(mesh, reader) {
10267 // A special case of Type 7. The p11, p12, p21, p22 automatically filled
10268 var coords = mesh.coords;
10269 var colors = mesh.colors;
10270 var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33
10271 var cs = new Int32Array(4); // c00, c30, c03, c33
10272 while (reader.hasData) {
10273 var f = reader.readFlag();
10274 assert(0 <= f && f <= 3, 'Unknown type6 flag');
10275 var i, ii;
10276 var pi = coords.length;
10277 for (i = 0, ii = (f !== 0 ? 8 : 12); i < ii; i++) {
10278 coords.push(reader.readCoordinate());
10279 }
10280 var ci = colors.length;
10281 for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
10282 colors.push(reader.readComponents());
10283 }
10284 var tmp1, tmp2, tmp3, tmp4;
10285 switch (f) {
10286 case 0:
10287 ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;
10288 ps[ 8] = pi + 2; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7;
10289 ps[ 4] = pi + 1; /* calculated below */ ps[ 7] = pi + 8;
10290 ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;
10291 cs[2] = ci + 1; cs[3] = ci + 2;
10292 cs[0] = ci; cs[1] = ci + 3;
10293 break;
10294 case 1:
10295 tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
10296 ps[12] = pi + 5; ps[13] = pi + 4; ps[14] = pi + 3; ps[15] = pi + 2;
10297 ps[ 8] = pi + 6; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 1;
10298 ps[ 4] = pi + 7; /* calculated below */ ps[ 7] = pi;
10299 ps[ 0] = tmp1; ps[ 1] = tmp2; ps[ 2] = tmp3; ps[ 3] = tmp4;
10300 tmp1 = cs[2]; tmp2 = cs[3];
10301 cs[2] = ci + 1; cs[3] = ci;
10302 cs[0] = tmp1; cs[1] = tmp2;
10303 break;
10304 case 2:
10305 ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6; ps[15] = pi + 5;
10306 ps[ 8] = ps[11]; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 4;
10307 ps[ 4] = ps[7]; /* calculated below */ ps[ 7] = pi + 3;
10308 ps[ 0] = ps[3]; ps[ 1] = pi; ps[ 2] = pi + 1; ps[ 3] = pi + 2;
10309 cs[2] = cs[3]; cs[3] = ci + 1;
10310 cs[0] = cs[1]; cs[1] = ci;
10311 break;
10312 case 3:
10313 ps[12] = ps[0]; ps[13] = ps[1]; ps[14] = ps[2]; ps[15] = ps[3];
10314 ps[ 8] = pi; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7;
10315 ps[ 4] = pi + 1; /* calculated below */ ps[ 7] = pi + 6;
10316 ps[ 0] = pi + 2; ps[ 1] = pi + 3; ps[ 2] = pi + 4; ps[ 3] = pi + 5;
10317 cs[2] = cs[0]; cs[3] = cs[1];
10318 cs[0] = ci; cs[1] = ci + 1;
10319 break;
10320 }
10321 // set p11, p12, p21, p22
10322 ps[5] = coords.length;
10323 coords.push([
10324 (-4 * coords[ps[0]][0] - coords[ps[15]][0] +
10325 6 * (coords[ps[4]][0] + coords[ps[1]][0]) -
10326 2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
10327 3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9,
10328 (-4 * coords[ps[0]][1] - coords[ps[15]][1] +
10329 6 * (coords[ps[4]][1] + coords[ps[1]][1]) -
10330 2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
10331 3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9
10332 ]);
10333 ps[6] = coords.length;
10334 coords.push([
10335 (-4 * coords[ps[3]][0] - coords[ps[12]][0] +
10336 6 * (coords[ps[2]][0] + coords[ps[7]][0]) -
10337 2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
10338 3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9,
10339 (-4 * coords[ps[3]][1] - coords[ps[12]][1] +
10340 6 * (coords[ps[2]][1] + coords[ps[7]][1]) -
10341 2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
10342 3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9
10343 ]);
10344 ps[9] = coords.length;
10345 coords.push([
10346 (-4 * coords[ps[12]][0] - coords[ps[3]][0] +
10347 6 * (coords[ps[8]][0] + coords[ps[13]][0]) -
10348 2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
10349 3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9,
10350 (-4 * coords[ps[12]][1] - coords[ps[3]][1] +
10351 6 * (coords[ps[8]][1] + coords[ps[13]][1]) -
10352 2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
10353 3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9
10354 ]);
10355 ps[10] = coords.length;
10356 coords.push([
10357 (-4 * coords[ps[15]][0] - coords[ps[0]][0] +
10358 6 * (coords[ps[11]][0] + coords[ps[14]][0]) -
10359 2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
10360 3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9,
10361 (-4 * coords[ps[15]][1] - coords[ps[0]][1] +
10362 6 * (coords[ps[11]][1] + coords[ps[14]][1]) -
10363 2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
10364 3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9
10365 ]);
10366 mesh.figures.push({
10367 type: 'patch',
10368 coords: new Int32Array(ps), // making copies of ps and cs
10369 colors: new Int32Array(cs)
10370 });
10371 }
10372 }
10373
10374 function decodeType7Shading(mesh, reader) {
10375 var coords = mesh.coords;
10376 var colors = mesh.colors;
10377 var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33
10378 var cs = new Int32Array(4); // c00, c30, c03, c33
10379 while (reader.hasData) {
10380 var f = reader.readFlag();
10381 assert(0 <= f && f <= 3, 'Unknown type7 flag');
10382 var i, ii;
10383 var pi = coords.length;
10384 for (i = 0, ii = (f !== 0 ? 12 : 16); i < ii; i++) {
10385 coords.push(reader.readCoordinate());
10386 }
10387 var ci = colors.length;
10388 for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
10389 colors.push(reader.readComponents());
10390 }
10391 var tmp1, tmp2, tmp3, tmp4;
10392 switch (f) {
10393 case 0:
10394 ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;
10395 ps[ 8] = pi + 2; ps[ 9] = pi + 13; ps[10] = pi + 14; ps[11] = pi + 7;
10396 ps[ 4] = pi + 1; ps[ 5] = pi + 12; ps[ 6] = pi + 15; ps[ 7] = pi + 8;
10397 ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;
10398 cs[2] = ci + 1; cs[3] = ci + 2;
10399 cs[0] = ci; cs[1] = ci + 3;
10400 break;
10401 case 1:
10402 tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
10403 ps[12] = pi + 5; ps[13] = pi + 4; ps[14] = pi + 3; ps[15] = pi + 2;
10404 ps[ 8] = pi + 6; ps[ 9] = pi + 11; ps[10] = pi + 10; ps[11] = pi + 1;
10405 ps[ 4] = pi + 7; ps[ 5] = pi + 8; ps[ 6] = pi + 9; ps[ 7] = pi;
10406 ps[ 0] = tmp1; ps[ 1] = tmp2; ps[ 2] = tmp3; ps[ 3] = tmp4;
10407 tmp1 = cs[2]; tmp2 = cs[3];
10408 cs[2] = ci + 1; cs[3] = ci;
10409 cs[0] = tmp1; cs[1] = tmp2;
10410 break;
10411 case 2:
10412 ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6; ps[15] = pi + 5;
10413 ps[ 8] = ps[11]; ps[ 9] = pi + 8; ps[10] = pi + 11; ps[11] = pi + 4;
10414 ps[ 4] = ps[7]; ps[ 5] = pi + 9; ps[ 6] = pi + 10; ps[ 7] = pi + 3;
10415 ps[ 0] = ps[3]; ps[ 1] = pi; ps[ 2] = pi + 1; ps[ 3] = pi + 2;
10416 cs[2] = cs[3]; cs[3] = ci + 1;
10417 cs[0] = cs[1]; cs[1] = ci;
10418 break;
10419 case 3:
10420 ps[12] = ps[0]; ps[13] = ps[1]; ps[14] = ps[2]; ps[15] = ps[3];
10421 ps[ 8] = pi; ps[ 9] = pi + 9; ps[10] = pi + 8; ps[11] = pi + 7;
10422 ps[ 4] = pi + 1; ps[ 5] = pi + 10; ps[ 6] = pi + 11; ps[ 7] = pi + 6;
10423 ps[ 0] = pi + 2; ps[ 1] = pi + 3; ps[ 2] = pi + 4; ps[ 3] = pi + 5;
10424 cs[2] = cs[0]; cs[3] = cs[1];
10425 cs[0] = ci; cs[1] = ci + 1;
10426 break;
10427 }
10428 mesh.figures.push({
10429 type: 'patch',
10430 coords: new Int32Array(ps), // making copies of ps and cs
10431 colors: new Int32Array(cs)
10432 });
10433 }
10434 }
10435
10436 function updateBounds(mesh) {
10437 var minX = mesh.coords[0][0], minY = mesh.coords[0][1],
10438 maxX = minX, maxY = minY;
10439 for (var i = 1, ii = mesh.coords.length; i < ii; i++) {
10440 var x = mesh.coords[i][0], y = mesh.coords[i][1];
10441 minX = minX > x ? x : minX;
10442 minY = minY > y ? y : minY;
10443 maxX = maxX < x ? x : maxX;
10444 maxY = maxY < y ? y : maxY;
10445 }
10446 mesh.bounds = [minX, minY, maxX, maxY];
10447 }
10448
10449 function packData(mesh) {
10450 var i, ii, j, jj;
10451
10452 var coords = mesh.coords;
10453 var coordsPacked = new Float32Array(coords.length * 2);
10454 for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
10455 var xy = coords[i];
10456 coordsPacked[j++] = xy[0];
10457 coordsPacked[j++] = xy[1];
10458 }
10459 mesh.coords = coordsPacked;
10460
10461 var colors = mesh.colors;
10462 var colorsPacked = new Uint8Array(colors.length * 3);
10463 for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
10464 var c = colors[i];
10465 colorsPacked[j++] = c[0];
10466 colorsPacked[j++] = c[1];
10467 colorsPacked[j++] = c[2];
10468 }
10469 mesh.colors = colorsPacked;
10470
10471 var figures = mesh.figures;
10472 for (i = 0, ii = figures.length; i < ii; i++) {
10473 var figure = figures[i], ps = figure.coords, cs = figure.colors;
10474 for (j = 0, jj = ps.length; j < jj; j++) {
10475 ps[j] *= 2;
10476 cs[j] *= 3;
10477 }
10478 }
10479 }
10480
10481 function Mesh(stream, matrix, xref, res) {
10482 assert(isStream(stream), 'Mesh data is not a stream');
10483 var dict = stream.dict;
10484 this.matrix = matrix;
10485 this.shadingType = dict.get('ShadingType');
10486 this.type = 'Pattern';
10487 this.bbox = dict.get('BBox');
10488 var cs = dict.get('ColorSpace', 'CS');
10489 cs = ColorSpace.parse(cs, xref, res);
10490 this.cs = cs;
10491 this.background = dict.has('Background') ?
10492 cs.getRgb(dict.get('Background'), 0) : null;
10493
10494 var fnObj = dict.get('Function');
10495 var fn = fnObj ? PDFFunction.parseArray(xref, fnObj) : null;
10496
10497 this.coords = [];
10498 this.colors = [];
10499 this.figures = [];
10500
10501 var decodeContext = {
10502 bitsPerCoordinate: dict.get('BitsPerCoordinate'),
10503 bitsPerComponent: dict.get('BitsPerComponent'),
10504 bitsPerFlag: dict.get('BitsPerFlag'),
10505 decode: dict.get('Decode'),
10506 colorFn: fn,
10507 colorSpace: cs,
10508 numComps: fn ? 1 : cs.numComps
10509 };
10510 var reader = new MeshStreamReader(stream, decodeContext);
10511
10512 var patchMesh = false;
10513 switch (this.shadingType) {
10514 case PatternType.FREE_FORM_MESH:
10515 decodeType4Shading(this, reader);
10516 break;
10517 case PatternType.LATTICE_FORM_MESH:
10518 var verticesPerRow = dict.get('VerticesPerRow') | 0;
10519 assert(verticesPerRow >= 2, 'Invalid VerticesPerRow');
10520 decodeType5Shading(this, reader, verticesPerRow);
10521 break;
10522 case PatternType.COONS_PATCH_MESH:
10523 decodeType6Shading(this, reader);
10524 patchMesh = true;
10525 break;
10526 case PatternType.TENSOR_PATCH_MESH:
10527 decodeType7Shading(this, reader);
10528 patchMesh = true;
10529 break;
10530 default:
10531 error('Unsupported mesh type.');
10532 break;
10533 }
10534
10535 if (patchMesh) {
10536 // dirty bounds calculation for determining, how dense shall be triangles
10537 updateBounds(this);
10538 for (var i = 0, ii = this.figures.length; i < ii; i++) {
10539 buildFigureFromPatch(this, i);
10540 }
10541 }
10542 // calculate bounds
10543 updateBounds(this);
10544
10545 packData(this);
10546 }
10547
10548 Mesh.prototype = {
10549 getIR: function Mesh_getIR() {
10550 return ['Mesh', this.shadingType, this.coords, this.colors, this.figures,
10551 this.bounds, this.matrix, this.bbox, this.background];
10552 }
10553 };
10554
10555 return Mesh;
10556 })();
10557
10558 Shadings.Dummy = (function DummyClosure() {
10559 function Dummy() {
10560 this.type = 'Pattern';
10561 }
10562
10563 Dummy.prototype = {
10564 getIR: function Dummy_getIR() {
10565 return ['Dummy'];
10566 }
10567 };
10568 return Dummy;
10569 })();
10570
10571 function getTilingPatternIR(operatorList, dict, args) {
10572 var matrix = dict.get('Matrix');
10573 var bbox = dict.get('BBox');
10574 var xstep = dict.get('XStep');
10575 var ystep = dict.get('YStep');
10576 var paintType = dict.get('PaintType');
10577 var tilingType = dict.get('TilingType');
10578
10579 return [
10580 'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,
10581 paintType, tilingType
10582 ];
10583 }
10584
10585
10586 var PartialEvaluator = (function PartialEvaluatorClosure() {
10587 function PartialEvaluator(pdfManager, xref, handler, pageIndex,
10588 uniquePrefix, idCounters, fontCache) {
10589 this.pdfManager = pdfManager;
10590 this.xref = xref;
10591 this.handler = handler;
10592 this.pageIndex = pageIndex;
10593 this.uniquePrefix = uniquePrefix;
10594 this.idCounters = idCounters;
10595 this.fontCache = fontCache;
10596 }
10597
10598 // Trying to minimize Date.now() usage and check every 100 time
10599 var TIME_SLOT_DURATION_MS = 20;
10600 var CHECK_TIME_EVERY = 100;
10601 function TimeSlotManager() {
10602 this.reset();
10603 }
10604 TimeSlotManager.prototype = {
10605 check: function TimeSlotManager_check() {
10606 if (++this.checked < CHECK_TIME_EVERY) {
10607 return false;
10608 }
10609 this.checked = 0;
10610 return this.endTime <= Date.now();
10611 },
10612 reset: function TimeSlotManager_reset() {
10613 this.endTime = Date.now() + TIME_SLOT_DURATION_MS;
10614 this.checked = 0;
10615 }
10616 };
10617
10618 var deferred = Promise.resolve();
10619
10620 var TILING_PATTERN = 1, SHADING_PATTERN = 2;
10621
10622 PartialEvaluator.prototype = {
10623 hasBlendModes: function PartialEvaluator_hasBlendModes(resources) {
10624 if (!isDict(resources)) {
10625 return false;
10626 }
10627
10628 var processed = Object.create(null);
10629 if (resources.objId) {
10630 processed[resources.objId] = true;
10631 }
10632
10633 var nodes = [resources];
10634 while (nodes.length) {
10635 var key;
10636 var node = nodes.shift();
10637 // First check the current resources for blend modes.
10638 var graphicStates = node.get('ExtGState');
10639 if (isDict(graphicStates)) {
10640 graphicStates = graphicStates.getAll();
10641 for (key in graphicStates) {
10642 var graphicState = graphicStates[key];
10643 var bm = graphicState['BM'];
10644 if (isName(bm) && bm.name !== 'Normal') {
10645 return true;
10646 }
10647 }
10648 }
10649 // Descend into the XObjects to look for more resources and blend modes.
10650 var xObjects = node.get('XObject');
10651 if (!isDict(xObjects)) {
10652 continue;
10653 }
10654 xObjects = xObjects.getAll();
10655 for (key in xObjects) {
10656 var xObject = xObjects[key];
10657 if (!isStream(xObject)) {
10658 continue;
10659 }
10660 if (xObject.dict.objId) {
10661 if (processed[xObject.dict.objId]) {
10662 // stream has objId and is processed already
10663 continue;
10664 }
10665 processed[xObject.dict.objId] = true;
10666 }
10667 var xResources = xObject.dict.get('Resources');
10668 // Checking objId to detect an infinite loop.
10669 if (isDict(xResources) &&
10670 (!xResources.objId || !processed[xResources.objId])) {
10671 nodes.push(xResources);
10672 if (xResources.objId) {
10673 processed[xResources.objId] = true;
10674 }
10675 }
10676 }
10677 }
10678 return false;
10679 },
10680
10681 buildFormXObject: function PartialEvaluator_buildFormXObject(resources,
10682 xobj, smask,
10683 operatorList,
10684 initialState) {
10685 var matrix = xobj.dict.get('Matrix');
10686 var bbox = xobj.dict.get('BBox');
10687 var group = xobj.dict.get('Group');
10688 if (group) {
10689 var groupOptions = {
10690 matrix: matrix,
10691 bbox: bbox,
10692 smask: smask,
10693 isolated: false,
10694 knockout: false
10695 };
10696
10697 var groupSubtype = group.get('S');
10698 var colorSpace;
10699 if (isName(groupSubtype) && groupSubtype.name === 'Transparency') {
10700 groupOptions.isolated = (group.get('I') || false);
10701 groupOptions.knockout = (group.get('K') || false);
10702 colorSpace = (group.has('CS') ?
10703 ColorSpace.parse(group.get('CS'), this.xref, resources) : null);
10704 }
10705
10706 if (smask && smask.backdrop) {
10707 colorSpace = colorSpace || ColorSpace.singletons.rgb;
10708 smask.backdrop = colorSpace.getRgb(smask.backdrop, 0);
10709 }
10710
10711 operatorList.addOp(OPS.beginGroup, [groupOptions]);
10712 }
10713
10714 operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]);
10715
10716 return this.getOperatorList(xobj,
10717 (xobj.dict.get('Resources') || resources), operatorList, initialState).
10718 then(function () {
10719 operatorList.addOp(OPS.paintFormXObjectEnd, []);
10720
10721 if (group) {
10722 operatorList.addOp(OPS.endGroup, [groupOptions]);
10723 }
10724 });
10725 },
10726
10727 buildPaintImageXObject:
10728 function PartialEvaluator_buildPaintImageXObject(resources, image,
10729 inline, operatorList,
10730 cacheKey, imageCache) {
10731 var self = this;
10732 var dict = image.dict;
10733 var w = dict.get('Width', 'W');
10734 var h = dict.get('Height', 'H');
10735
10736 if (!(w && isNum(w)) || !(h && isNum(h))) {
10737 warn('Image dimensions are missing, or not numbers.');
10738 return;
10739 }
10740 if (PDFJS.maxImageSize !== -1 && w * h > PDFJS.maxImageSize) {
10741 warn('Image exceeded maximum allowed size and was removed.');
10742 return;
10743 }
10744
10745 var imageMask = (dict.get('ImageMask', 'IM') || false);
10746 var imgData, args;
10747 if (imageMask) {
10748 // This depends on a tmpCanvas being filled with the
10749 // current fillStyle, such that processing the pixel
10750 // data can't be done here. Instead of creating a
10751 // complete PDFImage, only read the information needed
10752 // for later.
10753
10754 var width = dict.get('Width', 'W');
10755 var height = dict.get('Height', 'H');
10756 var bitStrideLength = (width + 7) >> 3;
10757 var imgArray = image.getBytes(bitStrideLength * height);
10758 var decode = dict.get('Decode', 'D');
10759 var inverseDecode = (!!decode && decode[0] > 0);
10760
10761 imgData = PDFImage.createMask(imgArray, width, height,
10762 image instanceof DecodeStream,
10763 inverseDecode);
10764 imgData.cached = true;
10765 args = [imgData];
10766 operatorList.addOp(OPS.paintImageMaskXObject, args);
10767 if (cacheKey) {
10768 imageCache[cacheKey] = {
10769 fn: OPS.paintImageMaskXObject,
10770 args: args
10771 };
10772 }
10773 return;
10774 }
10775
10776 var softMask = (dict.get('SMask', 'SM') || false);
10777 var mask = (dict.get('Mask') || false);
10778
10779 var SMALL_IMAGE_DIMENSIONS = 200;
10780 // Inlining small images into the queue as RGB data
10781 if (inline && !softMask && !mask && !(image instanceof JpegStream) &&
10782 (w + h) < SMALL_IMAGE_DIMENSIONS) {
10783 var imageObj = new PDFImage(this.xref, resources, image,
10784 inline, null, null);
10785 // We force the use of RGBA_32BPP images here, because we can't handle
10786 // any other kind.
10787 imgData = imageObj.createImageData(/* forceRGBA = */ true);
10788 operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);
10789 return;
10790 }
10791
10792 // If there is no imageMask, create the PDFImage and a lot
10793 // of image processing can be done here.
10794 var uniquePrefix = (this.uniquePrefix || '');
10795 var objId = 'img_' + uniquePrefix + (++this.idCounters.obj);
10796 operatorList.addDependency(objId);
10797 args = [objId, w, h];
10798
10799 if (!softMask && !mask && image instanceof JpegStream &&
10800 image.isNativelySupported(this.xref, resources)) {
10801 // These JPEGs don't need any more processing so we can just send it.
10802 operatorList.addOp(OPS.paintJpegXObject, args);
10803 this.handler.send('obj',
10804 [objId, this.pageIndex, 'JpegStream', image.getIR()]);
10805 return;
10806 }
10807
10808 PDFImage.buildImage(self.handler, self.xref, resources, image, inline).
10809 then(function(imageObj) {
10810 var imgData = imageObj.createImageData(/* forceRGBA = */ false);
10811 self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData],
10812 [imgData.data.buffer]);
10813 }).then(undefined, function (reason) {
10814 warn('Unable to decode image: ' + reason);
10815 self.handler.send('obj', [objId, self.pageIndex, 'Image', null]);
10816 });
10817
10818 operatorList.addOp(OPS.paintImageXObject, args);
10819 if (cacheKey) {
10820 imageCache[cacheKey] = {
10821 fn: OPS.paintImageXObject,
10822 args: args
10823 };
10824 }
10825 },
10826
10827 handleSMask: function PartialEvaluator_handleSmask(smask, resources,
10828 operatorList,
10829 stateManager) {
10830 var smaskContent = smask.get('G');
10831 var smaskOptions = {
10832 subtype: smask.get('S').name,
10833 backdrop: smask.get('BC')
10834 };
10835 return this.buildFormXObject(resources, smaskContent, smaskOptions,
10836 operatorList, stateManager.state.clone());
10837 },
10838
10839 handleTilingType:
10840 function PartialEvaluator_handleTilingType(fn, args, resources,
10841 pattern, patternDict,
10842 operatorList) {
10843 // Create an IR of the pattern code.
10844 var tilingOpList = new OperatorList();
10845 return this.getOperatorList(pattern,
10846 (patternDict.get('Resources') || resources), tilingOpList).
10847 then(function () {
10848 // Add the dependencies to the parent operator list so they are
10849 // resolved before sub operator list is executed synchronously.
10850 operatorList.addDependencies(tilingOpList.dependencies);
10851 operatorList.addOp(fn, getTilingPatternIR({
10852 fnArray: tilingOpList.fnArray,
10853 argsArray: tilingOpList.argsArray
10854 }, patternDict, args));
10855 });
10856 },
10857
10858 handleSetFont:
10859 function PartialEvaluator_handleSetFont(resources, fontArgs, fontRef,
10860 operatorList, state) {
10861 // TODO(mack): Not needed?
10862 var fontName;
10863 if (fontArgs) {
10864 fontArgs = fontArgs.slice();
10865 fontName = fontArgs[0].name;
10866 }
10867
10868 var self = this;
10869 return this.loadFont(fontName, fontRef, this.xref, resources).then(
10870 function (translated) {
10871 if (!translated.font.isType3Font) {
10872 return translated;
10873 }
10874 return translated.loadType3Data(self, resources, operatorList).then(
10875 function () {
10876 return translated;
10877 });
10878 }).then(function (translated) {
10879 state.font = translated.font;
10880 translated.send(self.handler);
10881 return translated.loadedName;
10882 });
10883 },
10884
10885 handleText: function PartialEvaluator_handleText(chars, state) {
10886 var font = state.font;
10887 var glyphs = font.charsToGlyphs(chars);
10888 var isAddToPathSet = !!(state.textRenderingMode &
10889 TextRenderingMode.ADD_TO_PATH_FLAG);
10890 if (font.data && (isAddToPathSet || PDFJS.disableFontFace)) {
10891 var buildPath = function (fontChar) {
10892 if (!font.renderer.hasBuiltPath(fontChar)) {
10893 var path = font.renderer.getPathJs(fontChar);
10894 this.handler.send('commonobj', [
10895 font.loadedName + '_path_' + fontChar,
10896 'FontPath',
10897 path
10898 ]);
10899 }
10900 }.bind(this);
10901
10902 for (var i = 0, ii = glyphs.length; i < ii; i++) {
10903 var glyph = glyphs[i];
10904 if (glyph === null) {
10905 continue;
10906 }
10907 buildPath(glyph.fontChar);
10908
10909 // If the glyph has an accent we need to build a path for its
10910 // fontChar too, otherwise CanvasGraphics_paintChar will fail.
10911 var accent = glyph.accent;
10912 if (accent && accent.fontChar) {
10913 buildPath(accent.fontChar);
10914 }
10915 }
10916 }
10917
10918 return glyphs;
10919 },
10920
10921 setGState: function PartialEvaluator_setGState(resources, gState,
10922 operatorList, xref,
10923 stateManager) {
10924 // This array holds the converted/processed state data.
10925 var gStateObj = [];
10926 var gStateMap = gState.map;
10927 var self = this;
10928 var promise = Promise.resolve();
10929 for (var key in gStateMap) {
10930 var value = gStateMap[key];
10931 switch (key) {
10932 case 'Type':
10933 break;
10934 case 'LW':
10935 case 'LC':
10936 case 'LJ':
10937 case 'ML':
10938 case 'D':
10939 case 'RI':
10940 case 'FL':
10941 case 'CA':
10942 case 'ca':
10943 gStateObj.push([key, value]);
10944 break;
10945 case 'Font':
10946 promise = promise.then(function () {
10947 return self.handleSetFont(resources, null, value[0],
10948 operatorList, stateManager.state).
10949 then(function (loadedName) {
10950 operatorList.addDependency(loadedName);
10951 gStateObj.push([key, [loadedName, value[1]]]);
10952 });
10953 });
10954 break;
10955 case 'BM':
10956 gStateObj.push([key, value]);
10957 break;
10958 case 'SMask':
10959 if (isName(value) && value.name === 'None') {
10960 gStateObj.push([key, false]);
10961 break;
10962 }
10963 var dict = xref.fetchIfRef(value);
10964 if (isDict(dict)) {
10965 promise = promise.then(function () {
10966 return self.handleSMask(dict, resources, operatorList,
10967 stateManager);
10968 });
10969 gStateObj.push([key, true]);
10970 } else {
10971 warn('Unsupported SMask type');
10972 }
10973
10974 break;
10975 // Only generate info log messages for the following since
10976 // they are unlikely to have a big impact on the rendering.
10977 case 'OP':
10978 case 'op':
10979 case 'OPM':
10980 case 'BG':
10981 case 'BG2':
10982 case 'UCR':
10983 case 'UCR2':
10984 case 'TR':
10985 case 'TR2':
10986 case 'HT':
10987 case 'SM':
10988 case 'SA':
10989 case 'AIS':
10990 case 'TK':
10991 // TODO implement these operators.
10992 info('graphic state operator ' + key);
10993 break;
10994 default:
10995 info('Unknown graphic state operator ' + key);
10996 break;
10997 }
10998 }
10999 return promise.then(function () {
11000 if (gStateObj.length >= 0) {
11001 operatorList.addOp(OPS.setGState, [gStateObj]);
11002 }
11003 });
11004 },
11005
11006 loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
11007 resources) {
11008
11009 function errorFont() {
11010 return Promise.resolve(new TranslatedFont('g_font_error',
11011 new ErrorFont('Font ' + fontName + ' is not available'), font));
11012 }
11013 var fontRef;
11014 if (font) { // Loading by ref.
11015 assert(isRef(font));
11016 fontRef = font;
11017 } else { // Loading by name.
11018 var fontRes = resources.get('Font');
11019 if (fontRes) {
11020 fontRef = fontRes.getRaw(fontName);
11021 } else {
11022 warn('fontRes not available');
11023 return errorFont();
11024 }
11025 }
11026 if (!fontRef) {
11027 warn('fontRef not available');
11028 return errorFont();
11029 }
11030
11031 if (this.fontCache.has(fontRef)) {
11032 return this.fontCache.get(fontRef);
11033 }
11034
11035 font = xref.fetchIfRef(fontRef);
11036 if (!isDict(font)) {
11037 return errorFont();
11038 }
11039
11040 // We are holding font.translated references just for fontRef that are not
11041 // dictionaries (Dict). See explanation below.
11042 if (font.translated) {
11043 return font.translated;
11044 }
11045
11046 var fontCapability = createPromiseCapability();
11047
11048 var preEvaluatedFont = this.preEvaluateFont(font, xref);
11049 var descriptor = preEvaluatedFont.descriptor;
11050 var fontID = fontRef.num + '_' + fontRef.gen;
11051 if (isDict(descriptor)) {
11052 if (!descriptor.fontAliases) {
11053 descriptor.fontAliases = Object.create(null);
11054 }
11055
11056 var fontAliases = descriptor.fontAliases;
11057 var hash = preEvaluatedFont.hash;
11058 if (fontAliases[hash]) {
11059 var aliasFontRef = fontAliases[hash].aliasRef;
11060 if (aliasFontRef && this.fontCache.has(aliasFontRef)) {
11061 this.fontCache.putAlias(fontRef, aliasFontRef);
11062 return this.fontCache.get(fontRef);
11063 }
11064 }
11065
11066 if (!fontAliases[hash]) {
11067 fontAliases[hash] = {
11068 fontID: Font.getFontID()
11069 };
11070 }
11071
11072 fontAliases[hash].aliasRef = fontRef;
11073 fontID = fontAliases[hash].fontID;
11074 }
11075
11076 // Workaround for bad PDF generators that don't reference fonts
11077 // properly, i.e. by not using an object identifier.
11078 // Check if the fontRef is a Dict (as opposed to a standard object),
11079 // in which case we don't cache the font and instead reference it by
11080 // fontName in font.loadedName below.
11081 var fontRefIsDict = isDict(fontRef);
11082 if (!fontRefIsDict) {
11083 this.fontCache.put(fontRef, fontCapability.promise);
11084 }
11085
11086 // Keep track of each font we translated so the caller can
11087 // load them asynchronously before calling display on a page.
11088 font.loadedName = 'g_font_' + (fontRefIsDict ?
11089 fontName.replace(/\W/g, '') : fontID);
11090
11091 font.translated = fontCapability.promise;
11092
11093 // TODO move promises into translate font
11094 var translatedPromise;
11095 try {
11096 translatedPromise = Promise.resolve(
11097 this.translateFont(preEvaluatedFont, xref));
11098 } catch (e) {
11099 translatedPromise = Promise.reject(e);
11100 }
11101
11102 translatedPromise.then(function (translatedFont) {
11103 if (translatedFont.fontType !== undefined) {
11104 var xrefFontStats = xref.stats.fontTypes;
11105 xrefFontStats[translatedFont.fontType] = true;
11106 }
11107
11108 fontCapability.resolve(new TranslatedFont(font.loadedName,
11109 translatedFont, font));
11110 }, function (reason) {
11111 // TODO fontCapability.reject?
11112 UnsupportedManager.notify(UNSUPPORTED_FEATURES.font);
11113
11114 try {
11115 // error, but it's still nice to have font type reported
11116 var descriptor = preEvaluatedFont.descriptor;
11117 var fontFile3 = descriptor && descriptor.get('FontFile3');
11118 var subtype = fontFile3 && fontFile3.get('Subtype');
11119 var fontType = getFontType(preEvaluatedFont.type,
11120 subtype && subtype.name);
11121 var xrefFontStats = xref.stats.fontTypes;
11122 xrefFontStats[fontType] = true;
11123 } catch (ex) { }
11124
11125 fontCapability.resolve(new TranslatedFont(font.loadedName,
11126 new ErrorFont(reason instanceof Error ? reason.message : reason),
11127 font));
11128 });
11129 return fontCapability.promise;
11130 },
11131
11132 buildPath: function PartialEvaluator_buildPath(operatorList, fn, args) {
11133 var lastIndex = operatorList.length - 1;
11134 if (!args) {
11135 args = [];
11136 }
11137 if (lastIndex < 0 ||
11138 operatorList.fnArray[lastIndex] !== OPS.constructPath) {
11139 operatorList.addOp(OPS.constructPath, [[fn], args]);
11140 } else {
11141 var opArgs = operatorList.argsArray[lastIndex];
11142 opArgs[0].push(fn);
11143 Array.prototype.push.apply(opArgs[1], args);
11144 }
11145 },
11146
11147 handleColorN: function PartialEvaluator_handleColorN(operatorList, fn, args,
11148 cs, patterns, resources, xref) {
11149 // compile tiling patterns
11150 var patternName = args[args.length - 1];
11151 // SCN/scn applies patterns along with normal colors
11152 var pattern;
11153 if (isName(patternName) &&
11154 (pattern = patterns.get(patternName.name))) {
11155 var dict = (isStream(pattern) ? pattern.dict : pattern);
11156 var typeNum = dict.get('PatternType');
11157
11158 if (typeNum === TILING_PATTERN) {
11159 var color = cs.base ? cs.base.getRgb(args, 0) : null;
11160 return this.handleTilingType(fn, color, resources, pattern,
11161 dict, operatorList);
11162 } else if (typeNum === SHADING_PATTERN) {
11163 var shading = dict.get('Shading');
11164 var matrix = dict.get('Matrix');
11165 pattern = Pattern.parseShading(shading, matrix, xref, resources);
11166 operatorList.addOp(fn, pattern.getIR());
11167 return Promise.resolve();
11168 } else {
11169 return Promise.reject('Unknown PatternType: ' + typeNum);
11170 }
11171 }
11172 // TODO shall we fail here?
11173 operatorList.addOp(fn, args);
11174 return Promise.resolve();
11175 },
11176
11177 getOperatorList: function PartialEvaluator_getOperatorList(stream,
11178 resources,
11179 operatorList,
11180 initialState) {
11181
11182 var self = this;
11183 var xref = this.xref;
11184 var imageCache = {};
11185
11186 assert(operatorList);
11187
11188 resources = (resources || Dict.empty);
11189 var xobjs = (resources.get('XObject') || Dict.empty);
11190 var patterns = (resources.get('Pattern') || Dict.empty);
11191 var stateManager = new StateManager(initialState || new EvalState());
11192 var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
11193 var timeSlotManager = new TimeSlotManager();
11194
11195 return new Promise(function next(resolve, reject) {
11196 timeSlotManager.reset();
11197 var stop, operation = {}, i, ii, cs;
11198 while (!(stop = timeSlotManager.check())) {
11199 // The arguments parsed by read() are used beyond this loop, so we
11200 // cannot reuse the same array on each iteration. Therefore we pass
11201 // in |null| as the initial value (see the comment on
11202 // EvaluatorPreprocessor_read() for why).
11203 operation.args = null;
11204 if (!(preprocessor.read(operation))) {
11205 break;
11206 }
11207 var args = operation.args;
11208 var fn = operation.fn;
11209
11210 switch (fn | 0) {
11211 case OPS.paintXObject:
11212 if (args[0].code) {
11213 break;
11214 }
11215 // eagerly compile XForm objects
11216 var name = args[0].name;
11217 if (imageCache[name] !== undefined) {
11218 operatorList.addOp(imageCache[name].fn, imageCache[name].args);
11219 args = null;
11220 continue;
11221 }
11222
11223 var xobj = xobjs.get(name);
11224 if (xobj) {
11225 assert(isStream(xobj), 'XObject should be a stream');
11226
11227 var type = xobj.dict.get('Subtype');
11228 assert(isName(type),
11229 'XObject should have a Name subtype');
11230
11231 if (type.name === 'Form') {
11232 stateManager.save();
11233 return self.buildFormXObject(resources, xobj, null,
11234 operatorList,
11235 stateManager.state.clone()).
11236 then(function () {
11237 stateManager.restore();
11238 next(resolve, reject);
11239 }, reject);
11240 } else if (type.name === 'Image') {
11241 self.buildPaintImageXObject(resources, xobj, false,
11242 operatorList, name, imageCache);
11243 args = null;
11244 continue;
11245 } else if (type.name === 'PS') {
11246 // PostScript XObjects are unused when viewing documents.
11247 // See section 4.7.1 of Adobe's PDF reference.
11248 info('Ignored XObject subtype PS');
11249 continue;
11250 } else {
11251 error('Unhandled XObject subtype ' + type.name);
11252 }
11253 }
11254 break;
11255 case OPS.setFont:
11256 var fontSize = args[1];
11257 // eagerly collect all fonts
11258 return self.handleSetFont(resources, args, null,
11259 operatorList, stateManager.state).
11260 then(function (loadedName) {
11261 operatorList.addDependency(loadedName);
11262 operatorList.addOp(OPS.setFont, [loadedName, fontSize]);
11263 next(resolve, reject);
11264 }, reject);
11265 case OPS.endInlineImage:
11266 var cacheKey = args[0].cacheKey;
11267 if (cacheKey) {
11268 var cacheEntry = imageCache[cacheKey];
11269 if (cacheEntry !== undefined) {
11270 operatorList.addOp(cacheEntry.fn, cacheEntry.args);
11271 args = null;
11272 continue;
11273 }
11274 }
11275 self.buildPaintImageXObject(resources, args[0], true,
11276 operatorList, cacheKey, imageCache);
11277 args = null;
11278 continue;
11279 case OPS.showText:
11280 args[0] = self.handleText(args[0], stateManager.state);
11281 break;
11282 case OPS.showSpacedText:
11283 var arr = args[0];
11284 var combinedGlyphs = [];
11285 var arrLength = arr.length;
11286 for (i = 0; i < arrLength; ++i) {
11287 var arrItem = arr[i];
11288 if (isString(arrItem)) {
11289 Array.prototype.push.apply(combinedGlyphs,
11290 self.handleText(arrItem, stateManager.state));
11291 } else if (isNum(arrItem)) {
11292 combinedGlyphs.push(arrItem);
11293 }
11294 }
11295 args[0] = combinedGlyphs;
11296 fn = OPS.showText;
11297 break;
11298 case OPS.nextLineShowText:
11299 operatorList.addOp(OPS.nextLine);
11300 args[0] = self.handleText(args[0], stateManager.state);
11301 fn = OPS.showText;
11302 break;
11303 case OPS.nextLineSetSpacingShowText:
11304 operatorList.addOp(OPS.nextLine);
11305 operatorList.addOp(OPS.setWordSpacing, [args.shift()]);
11306 operatorList.addOp(OPS.setCharSpacing, [args.shift()]);
11307 args[0] = self.handleText(args[0], stateManager.state);
11308 fn = OPS.showText;
11309 break;
11310 case OPS.setTextRenderingMode:
11311 stateManager.state.textRenderingMode = args[0];
11312 break;
11313
11314 case OPS.setFillColorSpace:
11315 stateManager.state.fillColorSpace =
11316 ColorSpace.parse(args[0], xref, resources);
11317 continue;
11318 case OPS.setStrokeColorSpace:
11319 stateManager.state.strokeColorSpace =
11320 ColorSpace.parse(args[0], xref, resources);
11321 continue;
11322 case OPS.setFillColor:
11323 cs = stateManager.state.fillColorSpace;
11324 args = cs.getRgb(args, 0);
11325 fn = OPS.setFillRGBColor;
11326 break;
11327 case OPS.setStrokeColor:
11328 cs = stateManager.state.strokeColorSpace;
11329 args = cs.getRgb(args, 0);
11330 fn = OPS.setStrokeRGBColor;
11331 break;
11332 case OPS.setFillGray:
11333 stateManager.state.fillColorSpace = ColorSpace.singletons.gray;
11334 args = ColorSpace.singletons.gray.getRgb(args, 0);
11335 fn = OPS.setFillRGBColor;
11336 break;
11337 case OPS.setStrokeGray:
11338 stateManager.state.strokeColorSpace = ColorSpace.singletons.gray;
11339 args = ColorSpace.singletons.gray.getRgb(args, 0);
11340 fn = OPS.setStrokeRGBColor;
11341 break;
11342 case OPS.setFillCMYKColor:
11343 stateManager.state.fillColorSpace = ColorSpace.singletons.cmyk;
11344 args = ColorSpace.singletons.cmyk.getRgb(args, 0);
11345 fn = OPS.setFillRGBColor;
11346 break;
11347 case OPS.setStrokeCMYKColor:
11348 stateManager.state.strokeColorSpace = ColorSpace.singletons.cmyk;
11349 args = ColorSpace.singletons.cmyk.getRgb(args, 0);
11350 fn = OPS.setStrokeRGBColor;
11351 break;
11352 case OPS.setFillRGBColor:
11353 stateManager.state.fillColorSpace = ColorSpace.singletons.rgb;
11354 args = ColorSpace.singletons.rgb.getRgb(args, 0);
11355 break;
11356 case OPS.setStrokeRGBColor:
11357 stateManager.state.strokeColorSpace = ColorSpace.singletons.rgb;
11358 args = ColorSpace.singletons.rgb.getRgb(args, 0);
11359 break;
11360 case OPS.setFillColorN:
11361 cs = stateManager.state.fillColorSpace;
11362 if (cs.name === 'Pattern') {
11363 return self.handleColorN(operatorList, OPS.setFillColorN,
11364 args, cs, patterns, resources, xref).then(function() {
11365 next(resolve, reject);
11366 }, reject);
11367 }
11368 args = cs.getRgb(args, 0);
11369 fn = OPS.setFillRGBColor;
11370 break;
11371 case OPS.setStrokeColorN:
11372 cs = stateManager.state.strokeColorSpace;
11373 if (cs.name === 'Pattern') {
11374 return self.handleColorN(operatorList, OPS.setStrokeColorN,
11375 args, cs, patterns, resources, xref).then(function() {
11376 next(resolve, reject);
11377 }, reject);
11378 }
11379 args = cs.getRgb(args, 0);
11380 fn = OPS.setStrokeRGBColor;
11381 break;
11382
11383 case OPS.shadingFill:
11384 var shadingRes = resources.get('Shading');
11385 if (!shadingRes) {
11386 error('No shading resource found');
11387 }
11388
11389 var shading = shadingRes.get(args[0].name);
11390 if (!shading) {
11391 error('No shading object found');
11392 }
11393
11394 var shadingFill = Pattern.parseShading(shading, null, xref,
11395 resources);
11396 var patternIR = shadingFill.getIR();
11397 args = [patternIR];
11398 fn = OPS.shadingFill;
11399 break;
11400 case OPS.setGState:
11401 var dictName = args[0];
11402 var extGState = resources.get('ExtGState');
11403
11404 if (!isDict(extGState) || !extGState.has(dictName.name)) {
11405 break;
11406 }
11407
11408 var gState = extGState.get(dictName.name);
11409 return self.setGState(resources, gState, operatorList, xref,
11410 stateManager).then(function() {
11411 next(resolve, reject);
11412 }, reject);
11413 case OPS.moveTo:
11414 case OPS.lineTo:
11415 case OPS.curveTo:
11416 case OPS.curveTo2:
11417 case OPS.curveTo3:
11418 case OPS.closePath:
11419 self.buildPath(operatorList, fn, args);
11420 continue;
11421 case OPS.rectangle:
11422 self.buildPath(operatorList, fn, args);
11423 continue;
11424 }
11425 operatorList.addOp(fn, args);
11426 }
11427 if (stop) {
11428 deferred.then(function () {
11429 next(resolve, reject);
11430 });
11431 return;
11432 }
11433 // Some PDFs don't close all restores inside object/form.
11434 // Closing those for them.
11435 for (i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) {
11436 operatorList.addOp(OPS.restore, []);
11437 }
11438 resolve();
11439 });
11440 },
11441
11442 getTextContent: function PartialEvaluator_getTextContent(stream, resources,
11443 stateManager) {
11444
11445 stateManager = (stateManager || new StateManager(new TextState()));
11446
11447 var textContent = {
11448 items: [],
11449 styles: Object.create(null)
11450 };
11451 var bidiTexts = textContent.items;
11452 var SPACE_FACTOR = 0.3;
11453 var MULTI_SPACE_FACTOR = 1.5;
11454
11455 var self = this;
11456 var xref = this.xref;
11457
11458 resources = (xref.fetchIfRef(resources) || Dict.empty);
11459
11460 // The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
11461 var xobjs = null;
11462 var xobjsCache = {};
11463
11464 var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
11465
11466 var textState;
11467
11468 function newTextChunk() {
11469 var font = textState.font;
11470 if (!(font.loadedName in textContent.styles)) {
11471 textContent.styles[font.loadedName] = {
11472 fontFamily: font.fallbackName,
11473 ascent: font.ascent,
11474 descent: font.descent,
11475 vertical: font.vertical
11476 };
11477 }
11478 return {
11479 // |str| is initially an array which we push individual chars to, and
11480 // then runBidi() overwrites it with the final string.
11481 str: [],
11482 dir: null,
11483 width: 0,
11484 height: 0,
11485 transform: null,
11486 fontName: font.loadedName
11487 };
11488 }
11489
11490 function runBidi(textChunk) {
11491 var str = textChunk.str.join('');
11492 var bidiResult = PDFJS.bidi(str, -1, textState.font.vertical);
11493 textChunk.str = bidiResult.str;
11494 textChunk.dir = bidiResult.dir;
11495 return textChunk;
11496 }
11497
11498 function handleSetFont(fontName, fontRef) {
11499 return self.loadFont(fontName, fontRef, xref, resources).
11500 then(function (translated) {
11501 textState.font = translated.font;
11502 textState.fontMatrix = translated.font.fontMatrix ||
11503 FONT_IDENTITY_MATRIX;
11504 });
11505 }
11506
11507 function buildTextGeometry(chars, textChunk) {
11508 var font = textState.font;
11509 textChunk = textChunk || newTextChunk();
11510 if (!textChunk.transform) {
11511 // 9.4.4 Text Space Details
11512 var tsm = [textState.fontSize * textState.textHScale, 0,
11513 0, textState.fontSize,
11514 0, textState.textRise];
11515 var trm = textChunk.transform = Util.transform(textState.ctm,
11516 Util.transform(textState.textMatrix, tsm));
11517 if (!font.vertical) {
11518 textChunk.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]);
11519 } else {
11520 textChunk.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]);
11521 }
11522 }
11523 var width = 0;
11524 var height = 0;
11525 var glyphs = font.charsToGlyphs(chars);
11526 var defaultVMetrics = font.defaultVMetrics;
11527 for (var i = 0; i < glyphs.length; i++) {
11528 var glyph = glyphs[i];
11529 if (!glyph) { // Previous glyph was a space.
11530 width += textState.wordSpacing * textState.textHScale;
11531 continue;
11532 }
11533 var vMetricX = null;
11534 var vMetricY = null;
11535 var glyphWidth = null;
11536 if (font.vertical) {
11537 if (glyph.vmetric) {
11538 glyphWidth = glyph.vmetric[0];
11539 vMetricX = glyph.vmetric[1];
11540 vMetricY = glyph.vmetric[2];
11541 } else {
11542 glyphWidth = glyph.width;
11543 vMetricX = glyph.width * 0.5;
11544 vMetricY = defaultVMetrics[2];
11545 }
11546 } else {
11547 glyphWidth = glyph.width;
11548 }
11549
11550 var glyphUnicode = glyph.unicode;
11551 if (NormalizedUnicodes[glyphUnicode] !== undefined) {
11552 glyphUnicode = NormalizedUnicodes[glyphUnicode];
11553 }
11554 glyphUnicode = reverseIfRtl(glyphUnicode);
11555
11556 // The following will calculate the x and y of the individual glyphs.
11557 // if (font.vertical) {
11558 // tsm[4] -= vMetricX * Math.abs(textState.fontSize) *
11559 // textState.fontMatrix[0];
11560 // tsm[5] -= vMetricY * textState.fontSize *
11561 // textState.fontMatrix[0];
11562 // }
11563 // var trm = Util.transform(textState.textMatrix, tsm);
11564 // var pt = Util.applyTransform([trm[4], trm[5]], textState.ctm);
11565 // var x = pt[0];
11566 // var y = pt[1];
11567
11568 var tx = 0;
11569 var ty = 0;
11570 if (!font.vertical) {
11571 var w0 = glyphWidth * textState.fontMatrix[0];
11572 tx = (w0 * textState.fontSize + textState.charSpacing) *
11573 textState.textHScale;
11574 width += tx;
11575 } else {
11576 var w1 = glyphWidth * textState.fontMatrix[0];
11577 ty = w1 * textState.fontSize + textState.charSpacing;
11578 height += ty;
11579 }
11580 textState.translateTextMatrix(tx, ty);
11581
11582 textChunk.str.push(glyphUnicode);
11583 }
11584
11585 var a = textState.textLineMatrix[0];
11586 var b = textState.textLineMatrix[1];
11587 var scaleLineX = Math.sqrt(a * a + b * b);
11588 a = textState.ctm[0];
11589 b = textState.ctm[1];
11590 var scaleCtmX = Math.sqrt(a * a + b * b);
11591 if (!font.vertical) {
11592 textChunk.width += width * scaleCtmX * scaleLineX;
11593 } else {
11594 textChunk.height += Math.abs(height * scaleCtmX * scaleLineX);
11595 }
11596 return textChunk;
11597 }
11598
11599 var timeSlotManager = new TimeSlotManager();
11600
11601 return new Promise(function next(resolve, reject) {
11602 timeSlotManager.reset();
11603 var stop, operation = {}, args = [];
11604 while (!(stop = timeSlotManager.check())) {
11605 // The arguments parsed by read() are not used beyond this loop, so
11606 // we can reuse the same array on every iteration, thus avoiding
11607 // unnecessary allocations.
11608 args.length = 0;
11609 operation.args = args;
11610 if (!(preprocessor.read(operation))) {
11611 break;
11612 }
11613 textState = stateManager.state;
11614 var fn = operation.fn;
11615 args = operation.args;
11616
11617 switch (fn | 0) {
11618 case OPS.setFont:
11619 textState.fontSize = args[1];
11620 return handleSetFont(args[0].name).then(function() {
11621 next(resolve, reject);
11622 }, reject);
11623 case OPS.setTextRise:
11624 textState.textRise = args[0];
11625 break;
11626 case OPS.setHScale:
11627 textState.textHScale = args[0] / 100;
11628 break;
11629 case OPS.setLeading:
11630 textState.leading = args[0];
11631 break;
11632 case OPS.moveText:
11633 textState.translateTextLineMatrix(args[0], args[1]);
11634 textState.textMatrix = textState.textLineMatrix.slice();
11635 break;
11636 case OPS.setLeadingMoveText:
11637 textState.leading = -args[1];
11638 textState.translateTextLineMatrix(args[0], args[1]);
11639 textState.textMatrix = textState.textLineMatrix.slice();
11640 break;
11641 case OPS.nextLine:
11642 textState.carriageReturn();
11643 break;
11644 case OPS.setTextMatrix:
11645 textState.setTextMatrix(args[0], args[1], args[2], args[3],
11646 args[4], args[5]);
11647 textState.setTextLineMatrix(args[0], args[1], args[2], args[3],
11648 args[4], args[5]);
11649 break;
11650 case OPS.setCharSpacing:
11651 textState.charSpacing = args[0];
11652 break;
11653 case OPS.setWordSpacing:
11654 textState.wordSpacing = args[0];
11655 break;
11656 case OPS.beginText:
11657 textState.textMatrix = IDENTITY_MATRIX.slice();
11658 textState.textLineMatrix = IDENTITY_MATRIX.slice();
11659 break;
11660 case OPS.showSpacedText:
11661 var items = args[0];
11662 var textChunk = newTextChunk();
11663 var offset;
11664 for (var j = 0, jj = items.length; j < jj; j++) {
11665 if (typeof items[j] === 'string') {
11666 buildTextGeometry(items[j], textChunk);
11667 } else {
11668 var val = items[j] / 1000;
11669 if (!textState.font.vertical) {
11670 offset = -val * textState.fontSize * textState.textHScale *
11671 textState.textMatrix[0];
11672 textState.translateTextMatrix(offset, 0);
11673 textChunk.width += offset;
11674 } else {
11675 offset = -val * textState.fontSize *
11676 textState.textMatrix[3];
11677 textState.translateTextMatrix(0, offset);
11678 textChunk.height += offset;
11679 }
11680 if (items[j] < 0 && textState.font.spaceWidth > 0) {
11681 var fakeSpaces = -items[j] / textState.font.spaceWidth;
11682 if (fakeSpaces > MULTI_SPACE_FACTOR) {
11683 fakeSpaces = Math.round(fakeSpaces);
11684 while (fakeSpaces--) {
11685 textChunk.str.push(' ');
11686 }
11687 } else if (fakeSpaces > SPACE_FACTOR) {
11688 textChunk.str.push(' ');
11689 }
11690 }
11691 }
11692 }
11693 bidiTexts.push(runBidi(textChunk));
11694 break;
11695 case OPS.showText:
11696 bidiTexts.push(runBidi(buildTextGeometry(args[0])));
11697 break;
11698 case OPS.nextLineShowText:
11699 textState.carriageReturn();
11700 bidiTexts.push(runBidi(buildTextGeometry(args[0])));
11701 break;
11702 case OPS.nextLineSetSpacingShowText:
11703 textState.wordSpacing = args[0];
11704 textState.charSpacing = args[1];
11705 textState.carriageReturn();
11706 bidiTexts.push(runBidi(buildTextGeometry(args[2])));
11707 break;
11708 case OPS.paintXObject:
11709 if (args[0].code) {
11710 break;
11711 }
11712
11713 if (!xobjs) {
11714 xobjs = (resources.get('XObject') || Dict.empty);
11715 }
11716
11717 var name = args[0].name;
11718 if (xobjsCache.key === name) {
11719 if (xobjsCache.texts) {
11720 Util.appendToArray(bidiTexts, xobjsCache.texts.items);
11721 Util.extendObj(textContent.styles, xobjsCache.texts.styles);
11722 }
11723 break;
11724 }
11725
11726 var xobj = xobjs.get(name);
11727 if (!xobj) {
11728 break;
11729 }
11730 assert(isStream(xobj), 'XObject should be a stream');
11731
11732 var type = xobj.dict.get('Subtype');
11733 assert(isName(type),
11734 'XObject should have a Name subtype');
11735
11736 if ('Form' !== type.name) {
11737 xobjsCache.key = name;
11738 xobjsCache.texts = null;
11739 break;
11740 }
11741
11742 stateManager.save();
11743 var matrix = xobj.dict.get('Matrix');
11744 if (isArray(matrix) && matrix.length === 6) {
11745 stateManager.transform(matrix);
11746 }
11747
11748 return self.getTextContent(xobj,
11749 xobj.dict.get('Resources') || resources, stateManager).
11750 then(function (formTextContent) {
11751 Util.appendToArray(bidiTexts, formTextContent.items);
11752 Util.extendObj(textContent.styles, formTextContent.styles);
11753 stateManager.restore();
11754
11755 xobjsCache.key = name;
11756 xobjsCache.texts = formTextContent;
11757
11758 next(resolve, reject);
11759 }, reject);
11760 case OPS.setGState:
11761 var dictName = args[0];
11762 var extGState = resources.get('ExtGState');
11763
11764 if (!isDict(extGState) || !extGState.has(dictName.name)) {
11765 break;
11766 }
11767
11768 var gsStateMap = extGState.get(dictName.name);
11769 var gsStateFont = null;
11770 for (var key in gsStateMap) {
11771 if (key === 'Font') {
11772 assert(!gsStateFont);
11773 gsStateFont = gsStateMap[key];
11774 }
11775 }
11776 if (gsStateFont) {
11777 textState.fontSize = gsStateFont[1];
11778 return handleSetFont(gsStateFont[0]).then(function() {
11779 next(resolve, reject);
11780 }, reject);
11781 }
11782 break;
11783 } // switch
11784 } // while
11785 if (stop) {
11786 deferred.then(function () {
11787 next(resolve, reject);
11788 });
11789 return;
11790 }
11791 resolve(textContent);
11792 });
11793 },
11794
11795 extractDataStructures: function
11796 partialEvaluatorExtractDataStructures(dict, baseDict,
11797 xref, properties) {
11798 // 9.10.2
11799 var toUnicode = (dict.get('ToUnicode') || baseDict.get('ToUnicode'));
11800 if (toUnicode) {
11801 properties.toUnicode = this.readToUnicode(toUnicode);
11802 }
11803 if (properties.composite) {
11804 // CIDSystemInfo helps to match CID to glyphs
11805 var cidSystemInfo = dict.get('CIDSystemInfo');
11806 if (isDict(cidSystemInfo)) {
11807 properties.cidSystemInfo = {
11808 registry: cidSystemInfo.get('Registry'),
11809 ordering: cidSystemInfo.get('Ordering'),
11810 supplement: cidSystemInfo.get('Supplement')
11811 };
11812 }
11813
11814 var cidToGidMap = dict.get('CIDToGIDMap');
11815 if (isStream(cidToGidMap)) {
11816 properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
11817 }
11818 }
11819
11820 // Based on 9.6.6 of the spec the encoding can come from multiple places
11821 // and depends on the font type. The base encoding and differences are
11822 // read here, but the encoding that is actually used is chosen during
11823 // glyph mapping in the font.
11824 // TODO: Loading the built in encoding in the font would allow the
11825 // differences to be merged in here not require us to hold on to it.
11826 var differences = [];
11827 var baseEncodingName = null;
11828 var encoding;
11829 if (dict.has('Encoding')) {
11830 encoding = dict.get('Encoding');
11831 if (isDict(encoding)) {
11832 baseEncodingName = encoding.get('BaseEncoding');
11833 baseEncodingName = (isName(baseEncodingName) ?
11834 baseEncodingName.name : null);
11835 // Load the differences between the base and original
11836 if (encoding.has('Differences')) {
11837 var diffEncoding = encoding.get('Differences');
11838 var index = 0;
11839 for (var j = 0, jj = diffEncoding.length; j < jj; j++) {
11840 var data = diffEncoding[j];
11841 if (isNum(data)) {
11842 index = data;
11843 } else {
11844 differences[index++] = data.name;
11845 }
11846 }
11847 }
11848 } else if (isName(encoding)) {
11849 baseEncodingName = encoding.name;
11850 } else {
11851 error('Encoding is not a Name nor a Dict');
11852 }
11853 // According to table 114 if the encoding is a named encoding it must be
11854 // one of these predefined encodings.
11855 if ((baseEncodingName !== 'MacRomanEncoding' &&
11856 baseEncodingName !== 'MacExpertEncoding' &&
11857 baseEncodingName !== 'WinAnsiEncoding')) {
11858 baseEncodingName = null;
11859 }
11860 }
11861
11862 if (baseEncodingName) {
11863 properties.defaultEncoding = Encodings[baseEncodingName].slice();
11864 } else {
11865 encoding = (properties.type === 'TrueType' ?
11866 Encodings.WinAnsiEncoding : Encodings.StandardEncoding);
11867 // The Symbolic attribute can be misused for regular fonts
11868 // Heuristic: we have to check if the font is a standard one also
11869 if (!!(properties.flags & FontFlags.Symbolic)) {
11870 encoding = Encodings.MacRomanEncoding;
11871 if (!properties.file) {
11872 if (/Symbol/i.test(properties.name)) {
11873 encoding = Encodings.SymbolSetEncoding;
11874 } else if (/Dingbats/i.test(properties.name)) {
11875 encoding = Encodings.ZapfDingbatsEncoding;
11876 }
11877 }
11878 }
11879 properties.defaultEncoding = encoding;
11880 }
11881
11882 properties.differences = differences;
11883 properties.baseEncodingName = baseEncodingName;
11884 properties.dict = dict;
11885 },
11886
11887 readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) {
11888 var cmap, cmapObj = toUnicode;
11889 if (isName(cmapObj)) {
11890 cmap = CMapFactory.create(cmapObj,
11891 { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
11892 if (cmap instanceof IdentityCMap) {
11893 return new IdentityToUnicodeMap(0, 0xFFFF);
11894 }
11895 return new ToUnicodeMap(cmap.getMap());
11896 } else if (isStream(cmapObj)) {
11897 cmap = CMapFactory.create(cmapObj,
11898 { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
11899 if (cmap instanceof IdentityCMap) {
11900 return new IdentityToUnicodeMap(0, 0xFFFF);
11901 }
11902 cmap = cmap.getMap();
11903 // Convert UTF-16BE
11904 // NOTE: cmap can be a sparse array, so use forEach instead of for(;;)
11905 // to iterate over all keys.
11906 cmap.forEach(function(token, i) {
11907 var str = [];
11908 for (var k = 0; k < token.length; k += 2) {
11909 var w1 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);
11910 if ((w1 & 0xF800) !== 0xD800) { // w1 < 0xD800 || w1 > 0xDFFF
11911 str.push(w1);
11912 continue;
11913 }
11914 k += 2;
11915 var w2 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);
11916 str.push(((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000);
11917 }
11918 cmap[i] = String.fromCharCode.apply(String, str);
11919 });
11920 return new ToUnicodeMap(cmap);
11921 }
11922 return null;
11923 },
11924
11925 readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) {
11926 // Extract the encoding from the CIDToGIDMap
11927 var glyphsData = cidToGidStream.getBytes();
11928
11929 // Set encoding 0 to later verify the font has an encoding
11930 var result = [];
11931 for (var j = 0, jj = glyphsData.length; j < jj; j++) {
11932 var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
11933 if (glyphID === 0) {
11934 continue;
11935 }
11936 var code = j >> 1;
11937 result[code] = glyphID;
11938 }
11939 return result;
11940 },
11941
11942 extractWidths: function PartialEvaluator_extractWidths(dict, xref,
11943 descriptor,
11944 properties) {
11945 var glyphsWidths = [];
11946 var defaultWidth = 0;
11947 var glyphsVMetrics = [];
11948 var defaultVMetrics;
11949 var i, ii, j, jj, start, code, widths;
11950 if (properties.composite) {
11951 defaultWidth = dict.get('DW') || 1000;
11952
11953 widths = dict.get('W');
11954 if (widths) {
11955 for (i = 0, ii = widths.length; i < ii; i++) {
11956 start = widths[i++];
11957 code = xref.fetchIfRef(widths[i]);
11958 if (isArray(code)) {
11959 for (j = 0, jj = code.length; j < jj; j++) {
11960 glyphsWidths[start++] = code[j];
11961 }
11962 } else {
11963 var width = widths[++i];
11964 for (j = start; j <= code; j++) {
11965 glyphsWidths[j] = width;
11966 }
11967 }
11968 }
11969 }
11970
11971 if (properties.vertical) {
11972 var vmetrics = (dict.get('DW2') || [880, -1000]);
11973 defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]];
11974 vmetrics = dict.get('W2');
11975 if (vmetrics) {
11976 for (i = 0, ii = vmetrics.length; i < ii; i++) {
11977 start = vmetrics[i++];
11978 code = xref.fetchIfRef(vmetrics[i]);
11979 if (isArray(code)) {
11980 for (j = 0, jj = code.length; j < jj; j++) {
11981 glyphsVMetrics[start++] = [code[j++], code[j++], code[j]];
11982 }
11983 } else {
11984 var vmetric = [vmetrics[++i], vmetrics[++i], vmetrics[++i]];
11985 for (j = start; j <= code; j++) {
11986 glyphsVMetrics[j] = vmetric;
11987 }
11988 }
11989 }
11990 }
11991 }
11992 } else {
11993 var firstChar = properties.firstChar;
11994 widths = dict.get('Widths');
11995 if (widths) {
11996 j = firstChar;
11997 for (i = 0, ii = widths.length; i < ii; i++) {
11998 glyphsWidths[j++] = widths[i];
11999 }
12000 defaultWidth = (parseFloat(descriptor.get('MissingWidth')) || 0);
12001 } else {
12002 // Trying get the BaseFont metrics (see comment above).
12003 var baseFontName = dict.get('BaseFont');
12004 if (isName(baseFontName)) {
12005 var metrics = this.getBaseFontMetrics(baseFontName.name);
12006
12007 glyphsWidths = this.buildCharCodeToWidth(metrics.widths,
12008 properties);
12009 defaultWidth = metrics.defaultWidth;
12010 }
12011 }
12012 }
12013
12014 // Heuristic: detection of monospace font by checking all non-zero widths
12015 var isMonospace = true;
12016 var firstWidth = defaultWidth;
12017 for (var glyph in glyphsWidths) {
12018 var glyphWidth = glyphsWidths[glyph];
12019 if (!glyphWidth) {
12020 continue;
12021 }
12022 if (!firstWidth) {
12023 firstWidth = glyphWidth;
12024 continue;
12025 }
12026 if (firstWidth !== glyphWidth) {
12027 isMonospace = false;
12028 break;
12029 }
12030 }
12031 if (isMonospace) {
12032 properties.flags |= FontFlags.FixedPitch;
12033 }
12034
12035 properties.defaultWidth = defaultWidth;
12036 properties.widths = glyphsWidths;
12037 properties.defaultVMetrics = defaultVMetrics;
12038 properties.vmetrics = glyphsVMetrics;
12039 },
12040
12041 isSerifFont: function PartialEvaluator_isSerifFont(baseFontName) {
12042 // Simulating descriptor flags attribute
12043 var fontNameWoStyle = baseFontName.split('-')[0];
12044 return (fontNameWoStyle in serifFonts) ||
12045 (fontNameWoStyle.search(/serif/gi) !== -1);
12046 },
12047
12048 getBaseFontMetrics: function PartialEvaluator_getBaseFontMetrics(name) {
12049 var defaultWidth = 0;
12050 var widths = [];
12051 var monospace = false;
12052 var lookupName = (stdFontMap[name] || name);
12053
12054 if (!(lookupName in Metrics)) {
12055 // Use default fonts for looking up font metrics if the passed
12056 // font is not a base font
12057 if (this.isSerifFont(name)) {
12058 lookupName = 'Times-Roman';
12059 } else {
12060 lookupName = 'Helvetica';
12061 }
12062 }
12063 var glyphWidths = Metrics[lookupName];
12064
12065 if (isNum(glyphWidths)) {
12066 defaultWidth = glyphWidths;
12067 monospace = true;
12068 } else {
12069 widths = glyphWidths;
12070 }
12071
12072 return {
12073 defaultWidth: defaultWidth,
12074 monospace: monospace,
12075 widths: widths
12076 };
12077 },
12078
12079 buildCharCodeToWidth:
12080 function PartialEvaluator_bulildCharCodeToWidth(widthsByGlyphName,
12081 properties) {
12082 var widths = Object.create(null);
12083 var differences = properties.differences;
12084 var encoding = properties.defaultEncoding;
12085 for (var charCode = 0; charCode < 256; charCode++) {
12086 if (charCode in differences &&
12087 widthsByGlyphName[differences[charCode]]) {
12088 widths[charCode] = widthsByGlyphName[differences[charCode]];
12089 continue;
12090 }
12091 if (charCode in encoding && widthsByGlyphName[encoding[charCode]]) {
12092 widths[charCode] = widthsByGlyphName[encoding[charCode]];
12093 continue;
12094 }
12095 }
12096 return widths;
12097 },
12098
12099 preEvaluateFont: function PartialEvaluator_preEvaluateFont(dict, xref) {
12100 var baseDict = dict;
12101 var type = dict.get('Subtype');
12102 assert(isName(type), 'invalid font Subtype');
12103
12104 var composite = false;
12105 var uint8array;
12106 if (type.name === 'Type0') {
12107 // If font is a composite
12108 // - get the descendant font
12109 // - set the type according to the descendant font
12110 // - get the FontDescriptor from the descendant font
12111 var df = dict.get('DescendantFonts');
12112 if (!df) {
12113 error('Descendant fonts are not specified');
12114 }
12115 dict = (isArray(df) ? xref.fetchIfRef(df[0]) : df);
12116
12117 type = dict.get('Subtype');
12118 assert(isName(type), 'invalid font Subtype');
12119 composite = true;
12120 }
12121
12122 var descriptor = dict.get('FontDescriptor');
12123 if (descriptor) {
12124 var hash = new MurmurHash3_64();
12125 var encoding = baseDict.getRaw('Encoding');
12126 if (isName(encoding)) {
12127 hash.update(encoding.name);
12128 } else if (isRef(encoding)) {
12129 hash.update(encoding.num + '_' + encoding.gen);
12130 } else if (isDict(encoding)) {
12131 var keys = encoding.getKeys();
12132 for (var i = 0, ii = keys.length; i < ii; i++) {
12133 var entry = encoding.getRaw(keys[i]);
12134 if (isName(entry)) {
12135 hash.update(entry.name);
12136 } else if (isRef(entry)) {
12137 hash.update(entry.num + '_' + entry.gen);
12138 } else if (isArray(entry)) { // 'Differences' entry.
12139 // Ideally we should check the contents of the array, but to avoid
12140 // parsing it here and then again in |extractDataStructures|,
12141 // we only use the array length for now (fixes bug1157493.pdf).
12142 hash.update(entry.length.toString());
12143 }
12144 }
12145 }
12146
12147 var toUnicode = dict.get('ToUnicode') || baseDict.get('ToUnicode');
12148 if (isStream(toUnicode)) {
12149 var stream = toUnicode.str || toUnicode;
12150 uint8array = stream.buffer ?
12151 new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) :
12152 new Uint8Array(stream.bytes.buffer,
12153 stream.start, stream.end - stream.start);
12154 hash.update(uint8array);
12155
12156 } else if (isName(toUnicode)) {
12157 hash.update(toUnicode.name);
12158 }
12159
12160 var widths = dict.get('Widths') || baseDict.get('Widths');
12161 if (widths) {
12162 uint8array = new Uint8Array(new Uint32Array(widths).buffer);
12163 hash.update(uint8array);
12164 }
12165 }
12166
12167 return {
12168 descriptor: descriptor,
12169 dict: dict,
12170 baseDict: baseDict,
12171 composite: composite,
12172 type: type.name,
12173 hash: hash ? hash.hexdigest() : ''
12174 };
12175 },
12176
12177 translateFont: function PartialEvaluator_translateFont(preEvaluatedFont,
12178 xref) {
12179 var baseDict = preEvaluatedFont.baseDict;
12180 var dict = preEvaluatedFont.dict;
12181 var composite = preEvaluatedFont.composite;
12182 var descriptor = preEvaluatedFont.descriptor;
12183 var type = preEvaluatedFont.type;
12184 var maxCharIndex = (composite ? 0xFFFF : 0xFF);
12185 var properties;
12186
12187 if (!descriptor) {
12188 if (type === 'Type3') {
12189 // FontDescriptor is only required for Type3 fonts when the document
12190 // is a tagged pdf. Create a barbebones one to get by.
12191 descriptor = new Dict(null);
12192 descriptor.set('FontName', Name.get(type));
12193 } else {
12194 // Before PDF 1.5 if the font was one of the base 14 fonts, having a
12195 // FontDescriptor was not required.
12196 // This case is here for compatibility.
12197 var baseFontName = dict.get('BaseFont');
12198 if (!isName(baseFontName)) {
12199 error('Base font is not specified');
12200 }
12201
12202 // Using base font name as a font name.
12203 baseFontName = baseFontName.name.replace(/[,_]/g, '-');
12204 var metrics = this.getBaseFontMetrics(baseFontName);
12205
12206 // Simulating descriptor flags attribute
12207 var fontNameWoStyle = baseFontName.split('-')[0];
12208 var flags =
12209 (this.isSerifFont(fontNameWoStyle) ? FontFlags.Serif : 0) |
12210 (metrics.monospace ? FontFlags.FixedPitch : 0) |
12211 (symbolsFonts[fontNameWoStyle] ? FontFlags.Symbolic :
12212 FontFlags.Nonsymbolic);
12213
12214 properties = {
12215 type: type,
12216 name: baseFontName,
12217 widths: metrics.widths,
12218 defaultWidth: metrics.defaultWidth,
12219 flags: flags,
12220 firstChar: 0,
12221 lastChar: maxCharIndex
12222 };
12223 this.extractDataStructures(dict, dict, xref, properties);
12224 properties.widths = this.buildCharCodeToWidth(metrics.widths,
12225 properties);
12226 return new Font(baseFontName, null, properties);
12227 }
12228 }
12229
12230 // According to the spec if 'FontDescriptor' is declared, 'FirstChar',
12231 // 'LastChar' and 'Widths' should exist too, but some PDF encoders seem
12232 // to ignore this rule when a variant of a standart font is used.
12233 // TODO Fill the width array depending on which of the base font this is
12234 // a variant.
12235 var firstChar = (dict.get('FirstChar') || 0);
12236 var lastChar = (dict.get('LastChar') || maxCharIndex);
12237
12238 var fontName = descriptor.get('FontName');
12239 var baseFont = dict.get('BaseFont');
12240 // Some bad PDFs have a string as the font name.
12241 if (isString(fontName)) {
12242 fontName = Name.get(fontName);
12243 }
12244 if (isString(baseFont)) {
12245 baseFont = Name.get(baseFont);
12246 }
12247
12248 if (type !== 'Type3') {
12249 var fontNameStr = fontName && fontName.name;
12250 var baseFontStr = baseFont && baseFont.name;
12251 if (fontNameStr !== baseFontStr) {
12252 info('The FontDescriptor\'s FontName is "' + fontNameStr +
12253 '" but should be the same as the Font\'s BaseFont "' +
12254 baseFontStr + '"');
12255 // Workaround for cases where e.g. fontNameStr = 'Arial' and
12256 // baseFontStr = 'Arial,Bold' (needed when no font file is embedded).
12257 if (fontNameStr && baseFontStr &&
12258 baseFontStr.indexOf(fontNameStr) === 0) {
12259 fontName = baseFont;
12260 }
12261 }
12262 }
12263 fontName = (fontName || baseFont);
12264
12265 assert(isName(fontName), 'invalid font name');
12266
12267 var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
12268 if (fontFile) {
12269 if (fontFile.dict) {
12270 var subtype = fontFile.dict.get('Subtype');
12271 if (subtype) {
12272 subtype = subtype.name;
12273 }
12274 var length1 = fontFile.dict.get('Length1');
12275 var length2 = fontFile.dict.get('Length2');
12276 }
12277 }
12278
12279 properties = {
12280 type: type,
12281 name: fontName.name,
12282 subtype: subtype,
12283 file: fontFile,
12284 length1: length1,
12285 length2: length2,
12286 loadedName: baseDict.loadedName,
12287 composite: composite,
12288 wideChars: composite,
12289 fixedPitch: false,
12290 fontMatrix: (dict.get('FontMatrix') || FONT_IDENTITY_MATRIX),
12291 firstChar: firstChar || 0,
12292 lastChar: (lastChar || maxCharIndex),
12293 bbox: descriptor.get('FontBBox'),
12294 ascent: descriptor.get('Ascent'),
12295 descent: descriptor.get('Descent'),
12296 xHeight: descriptor.get('XHeight'),
12297 capHeight: descriptor.get('CapHeight'),
12298 flags: descriptor.get('Flags'),
12299 italicAngle: descriptor.get('ItalicAngle'),
12300 coded: false
12301 };
12302
12303 if (composite) {
12304 var cidEncoding = baseDict.get('Encoding');
12305 if (isName(cidEncoding)) {
12306 properties.cidEncoding = cidEncoding.name;
12307 }
12308 properties.cMap = CMapFactory.create(cidEncoding,
12309 { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
12310 properties.vertical = properties.cMap.vertical;
12311 }
12312 this.extractDataStructures(dict, baseDict, xref, properties);
12313 this.extractWidths(dict, xref, descriptor, properties);
12314
12315 if (type === 'Type3') {
12316 properties.isType3Font = true;
12317 }
12318
12319 return new Font(fontName.name, fontFile, properties);
12320 }
12321 };
12322
12323 return PartialEvaluator;
12324 })();
12325
12326 var TranslatedFont = (function TranslatedFontClosure() {
12327 function TranslatedFont(loadedName, font, dict) {
12328 this.loadedName = loadedName;
12329 this.font = font;
12330 this.dict = dict;
12331 this.type3Loaded = null;
12332 this.sent = false;
12333 }
12334 TranslatedFont.prototype = {
12335 send: function (handler) {
12336 if (this.sent) {
12337 return;
12338 }
12339 var fontData = this.font.exportData();
12340 handler.send('commonobj', [
12341 this.loadedName,
12342 'Font',
12343 fontData
12344 ]);
12345 this.sent = true;
12346 },
12347 loadType3Data: function (evaluator, resources, parentOperatorList) {
12348 assert(this.font.isType3Font);
12349
12350 if (this.type3Loaded) {
12351 return this.type3Loaded;
12352 }
12353
12354 var translatedFont = this.font;
12355 var loadCharProcsPromise = Promise.resolve();
12356 var charProcs = this.dict.get('CharProcs').getAll();
12357 var fontResources = this.dict.get('Resources') || resources;
12358 var charProcKeys = Object.keys(charProcs);
12359 var charProcOperatorList = {};
12360 for (var i = 0, n = charProcKeys.length; i < n; ++i) {
12361 loadCharProcsPromise = loadCharProcsPromise.then(function (key) {
12362 var glyphStream = charProcs[key];
12363 var operatorList = new OperatorList();
12364 return evaluator.getOperatorList(glyphStream, fontResources,
12365 operatorList).then(function () {
12366 charProcOperatorList[key] = operatorList.getIR();
12367
12368 // Add the dependencies to the parent operator list so they are
12369 // resolved before sub operator list is executed synchronously.
12370 parentOperatorList.addDependencies(operatorList.dependencies);
12371 }, function (reason) {
12372 warn('Type3 font resource \"' + key + '\" is not available');
12373 var operatorList = new OperatorList();
12374 charProcOperatorList[key] = operatorList.getIR();
12375 });
12376 }.bind(this, charProcKeys[i]));
12377 }
12378 this.type3Loaded = loadCharProcsPromise.then(function () {
12379 translatedFont.charProcOperatorList = charProcOperatorList;
12380 });
12381 return this.type3Loaded;
12382 }
12383 };
12384 return TranslatedFont;
12385 })();
12386
12387 var OperatorList = (function OperatorListClosure() {
12388 var CHUNK_SIZE = 1000;
12389 var CHUNK_SIZE_ABOUT = CHUNK_SIZE - 5; // close to chunk size
12390
12391 function getTransfers(queue) {
12392 var transfers = [];
12393 var fnArray = queue.fnArray, argsArray = queue.argsArray;
12394 for (var i = 0, ii = queue.length; i < ii; i++) {
12395 switch (fnArray[i]) {
12396 case OPS.paintInlineImageXObject:
12397 case OPS.paintInlineImageXObjectGroup:
12398 case OPS.paintImageMaskXObject:
12399 var arg = argsArray[i][0]; // first param in imgData
12400 if (!arg.cached) {
12401 transfers.push(arg.data.buffer);
12402 }
12403 break;
12404 }
12405 }
12406 return transfers;
12407 }
12408
12409 function OperatorList(intent, messageHandler, pageIndex) {
12410 this.messageHandler = messageHandler;
12411 this.fnArray = [];
12412 this.argsArray = [];
12413 this.dependencies = {};
12414 this.pageIndex = pageIndex;
12415 this.intent = intent;
12416 }
12417
12418 OperatorList.prototype = {
12419 get length() {
12420 return this.argsArray.length;
12421 },
12422
12423 addOp: function(fn, args) {
12424 this.fnArray.push(fn);
12425 this.argsArray.push(args);
12426 if (this.messageHandler) {
12427 if (this.fnArray.length >= CHUNK_SIZE) {
12428 this.flush();
12429 } else if (this.fnArray.length >= CHUNK_SIZE_ABOUT &&
12430 (fn === OPS.restore || fn === OPS.endText)) {
12431 // heuristic to flush on boundary of restore or endText
12432 this.flush();
12433 }
12434 }
12435 },
12436
12437 addDependency: function(dependency) {
12438 if (dependency in this.dependencies) {
12439 return;
12440 }
12441 this.dependencies[dependency] = true;
12442 this.addOp(OPS.dependency, [dependency]);
12443 },
12444
12445 addDependencies: function(dependencies) {
12446 for (var key in dependencies) {
12447 this.addDependency(key);
12448 }
12449 },
12450
12451 addOpList: function(opList) {
12452 Util.extendObj(this.dependencies, opList.dependencies);
12453 for (var i = 0, ii = opList.length; i < ii; i++) {
12454 this.addOp(opList.fnArray[i], opList.argsArray[i]);
12455 }
12456 },
12457
12458 getIR: function() {
12459 return {
12460 fnArray: this.fnArray,
12461 argsArray: this.argsArray,
12462 length: this.length
12463 };
12464 },
12465
12466 flush: function(lastChunk) {
12467 if (this.intent !== 'oplist') {
12468 new QueueOptimizer().optimize(this);
12469 }
12470 var transfers = getTransfers(this);
12471 this.messageHandler.send('RenderPageChunk', {
12472 operatorList: {
12473 fnArray: this.fnArray,
12474 argsArray: this.argsArray,
12475 lastChunk: lastChunk,
12476 length: this.length
12477 },
12478 pageIndex: this.pageIndex,
12479 intent: this.intent
12480 }, transfers);
12481 this.dependencies = {};
12482 this.fnArray.length = 0;
12483 this.argsArray.length = 0;
12484 }
12485 };
12486
12487 return OperatorList;
12488 })();
12489
12490 var StateManager = (function StateManagerClosure() {
12491 function StateManager(initialState) {
12492 this.state = initialState;
12493 this.stateStack = [];
12494 }
12495 StateManager.prototype = {
12496 save: function () {
12497 var old = this.state;
12498 this.stateStack.push(this.state);
12499 this.state = old.clone();
12500 },
12501 restore: function () {
12502 var prev = this.stateStack.pop();
12503 if (prev) {
12504 this.state = prev;
12505 }
12506 },
12507 transform: function (args) {
12508 this.state.ctm = Util.transform(this.state.ctm, args);
12509 }
12510 };
12511 return StateManager;
12512 })();
12513
12514 var TextState = (function TextStateClosure() {
12515 function TextState() {
12516 this.ctm = new Float32Array(IDENTITY_MATRIX);
12517 this.fontSize = 0;
12518 this.font = null;
12519 this.fontMatrix = FONT_IDENTITY_MATRIX;
12520 this.textMatrix = IDENTITY_MATRIX.slice();
12521 this.textLineMatrix = IDENTITY_MATRIX.slice();
12522 this.charSpacing = 0;
12523 this.wordSpacing = 0;
12524 this.leading = 0;
12525 this.textHScale = 1;
12526 this.textRise = 0;
12527 }
12528
12529 TextState.prototype = {
12530 setTextMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
12531 var m = this.textMatrix;
12532 m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
12533 },
12534 setTextLineMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
12535 var m = this.textLineMatrix;
12536 m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
12537 },
12538 translateTextMatrix: function TextState_translateTextMatrix(x, y) {
12539 var m = this.textMatrix;
12540 m[4] = m[0] * x + m[2] * y + m[4];
12541 m[5] = m[1] * x + m[3] * y + m[5];
12542 },
12543 translateTextLineMatrix: function TextState_translateTextMatrix(x, y) {
12544 var m = this.textLineMatrix;
12545 m[4] = m[0] * x + m[2] * y + m[4];
12546 m[5] = m[1] * x + m[3] * y + m[5];
12547 },
12548 calcRenderMatrix: function TextState_calcRendeMatrix(ctm) {
12549 // 9.4.4 Text Space Details
12550 var tsm = [this.fontSize * this.textHScale, 0,
12551 0, this.fontSize,
12552 0, this.textRise];
12553 return Util.transform(ctm, Util.transform(this.textMatrix, tsm));
12554 },
12555 carriageReturn: function TextState_carriageReturn() {
12556 this.translateTextLineMatrix(0, -this.leading);
12557 this.textMatrix = this.textLineMatrix.slice();
12558 },
12559 clone: function TextState_clone() {
12560 var clone = Object.create(this);
12561 clone.textMatrix = this.textMatrix.slice();
12562 clone.textLineMatrix = this.textLineMatrix.slice();
12563 clone.fontMatrix = this.fontMatrix.slice();
12564 return clone;
12565 }
12566 };
12567 return TextState;
12568 })();
12569
12570 var EvalState = (function EvalStateClosure() {
12571 function EvalState() {
12572 this.ctm = new Float32Array(IDENTITY_MATRIX);
12573 this.font = null;
12574 this.textRenderingMode = TextRenderingMode.FILL;
12575 this.fillColorSpace = ColorSpace.singletons.gray;
12576 this.strokeColorSpace = ColorSpace.singletons.gray;
12577 }
12578 EvalState.prototype = {
12579 clone: function CanvasExtraState_clone() {
12580 return Object.create(this);
12581 },
12582 };
12583 return EvalState;
12584 })();
12585
12586 var EvaluatorPreprocessor = (function EvaluatorPreprocessorClosure() {
12587 // Specifies properties for each command
12588 //
12589 // If variableArgs === true: [0, `numArgs`] expected
12590 // If variableArgs === false: exactly `numArgs` expected
12591 var OP_MAP = {
12592 // Graphic state
12593 w: { id: OPS.setLineWidth, numArgs: 1, variableArgs: false },
12594 J: { id: OPS.setLineCap, numArgs: 1, variableArgs: false },
12595 j: { id: OPS.setLineJoin, numArgs: 1, variableArgs: false },
12596 M: { id: OPS.setMiterLimit, numArgs: 1, variableArgs: false },
12597 d: { id: OPS.setDash, numArgs: 2, variableArgs: false },
12598 ri: { id: OPS.setRenderingIntent, numArgs: 1, variableArgs: false },
12599 i: { id: OPS.setFlatness, numArgs: 1, variableArgs: false },
12600 gs: { id: OPS.setGState, numArgs: 1, variableArgs: false },
12601 q: { id: OPS.save, numArgs: 0, variableArgs: false },
12602 Q: { id: OPS.restore, numArgs: 0, variableArgs: false },
12603 cm: { id: OPS.transform, numArgs: 6, variableArgs: false },
12604
12605 // Path
12606 m: { id: OPS.moveTo, numArgs: 2, variableArgs: false },
12607 l: { id: OPS.lineTo, numArgs: 2, variableArgs: false },
12608 c: { id: OPS.curveTo, numArgs: 6, variableArgs: false },
12609 v: { id: OPS.curveTo2, numArgs: 4, variableArgs: false },
12610 y: { id: OPS.curveTo3, numArgs: 4, variableArgs: false },
12611 h: { id: OPS.closePath, numArgs: 0, variableArgs: false },
12612 re: { id: OPS.rectangle, numArgs: 4, variableArgs: false },
12613 S: { id: OPS.stroke, numArgs: 0, variableArgs: false },
12614 s: { id: OPS.closeStroke, numArgs: 0, variableArgs: false },
12615 f: { id: OPS.fill, numArgs: 0, variableArgs: false },
12616 F: { id: OPS.fill, numArgs: 0, variableArgs: false },
12617 'f*': { id: OPS.eoFill, numArgs: 0, variableArgs: false },
12618 B: { id: OPS.fillStroke, numArgs: 0, variableArgs: false },
12619 'B*': { id: OPS.eoFillStroke, numArgs: 0, variableArgs: false },
12620 b: { id: OPS.closeFillStroke, numArgs: 0, variableArgs: false },
12621 'b*': { id: OPS.closeEOFillStroke, numArgs: 0, variableArgs: false },
12622 n: { id: OPS.endPath, numArgs: 0, variableArgs: false },
12623
12624 // Clipping
12625 W: { id: OPS.clip, numArgs: 0, variableArgs: false },
12626 'W*': { id: OPS.eoClip, numArgs: 0, variableArgs: false },
12627
12628 // Text
12629 BT: { id: OPS.beginText, numArgs: 0, variableArgs: false },
12630 ET: { id: OPS.endText, numArgs: 0, variableArgs: false },
12631 Tc: { id: OPS.setCharSpacing, numArgs: 1, variableArgs: false },
12632 Tw: { id: OPS.setWordSpacing, numArgs: 1, variableArgs: false },
12633 Tz: { id: OPS.setHScale, numArgs: 1, variableArgs: false },
12634 TL: { id: OPS.setLeading, numArgs: 1, variableArgs: false },
12635 Tf: { id: OPS.setFont, numArgs: 2, variableArgs: false },
12636 Tr: { id: OPS.setTextRenderingMode, numArgs: 1, variableArgs: false },
12637 Ts: { id: OPS.setTextRise, numArgs: 1, variableArgs: false },
12638 Td: { id: OPS.moveText, numArgs: 2, variableArgs: false },
12639 TD: { id: OPS.setLeadingMoveText, numArgs: 2, variableArgs: false },
12640 Tm: { id: OPS.setTextMatrix, numArgs: 6, variableArgs: false },
12641 'T*': { id: OPS.nextLine, numArgs: 0, variableArgs: false },
12642 Tj: { id: OPS.showText, numArgs: 1, variableArgs: false },
12643 TJ: { id: OPS.showSpacedText, numArgs: 1, variableArgs: false },
12644 '\'': { id: OPS.nextLineShowText, numArgs: 1, variableArgs: false },
12645 '"': { id: OPS.nextLineSetSpacingShowText, numArgs: 3,
12646 variableArgs: false },
12647
12648 // Type3 fonts
12649 d0: { id: OPS.setCharWidth, numArgs: 2, variableArgs: false },
12650 d1: { id: OPS.setCharWidthAndBounds, numArgs: 6, variableArgs: false },
12651
12652 // Color
12653 CS: { id: OPS.setStrokeColorSpace, numArgs: 1, variableArgs: false },
12654 cs: { id: OPS.setFillColorSpace, numArgs: 1, variableArgs: false },
12655 SC: { id: OPS.setStrokeColor, numArgs: 4, variableArgs: true },
12656 SCN: { id: OPS.setStrokeColorN, numArgs: 33, variableArgs: true },
12657 sc: { id: OPS.setFillColor, numArgs: 4, variableArgs: true },
12658 scn: { id: OPS.setFillColorN, numArgs: 33, variableArgs: true },
12659 G: { id: OPS.setStrokeGray, numArgs: 1, variableArgs: false },
12660 g: { id: OPS.setFillGray, numArgs: 1, variableArgs: false },
12661 RG: { id: OPS.setStrokeRGBColor, numArgs: 3, variableArgs: false },
12662 rg: { id: OPS.setFillRGBColor, numArgs: 3, variableArgs: false },
12663 K: { id: OPS.setStrokeCMYKColor, numArgs: 4, variableArgs: false },
12664 k: { id: OPS.setFillCMYKColor, numArgs: 4, variableArgs: false },
12665
12666 // Shading
12667 sh: { id: OPS.shadingFill, numArgs: 1, variableArgs: false },
12668
12669 // Images
12670 BI: { id: OPS.beginInlineImage, numArgs: 0, variableArgs: false },
12671 ID: { id: OPS.beginImageData, numArgs: 0, variableArgs: false },
12672 EI: { id: OPS.endInlineImage, numArgs: 1, variableArgs: false },
12673
12674 // XObjects
12675 Do: { id: OPS.paintXObject, numArgs: 1, variableArgs: false },
12676 MP: { id: OPS.markPoint, numArgs: 1, variableArgs: false },
12677 DP: { id: OPS.markPointProps, numArgs: 2, variableArgs: false },
12678 BMC: { id: OPS.beginMarkedContent, numArgs: 1, variableArgs: false },
12679 BDC: { id: OPS.beginMarkedContentProps, numArgs: 2,
12680 variableArgs: false },
12681 EMC: { id: OPS.endMarkedContent, numArgs: 0, variableArgs: false },
12682
12683 // Compatibility
12684 BX: { id: OPS.beginCompat, numArgs: 0, variableArgs: false },
12685 EX: { id: OPS.endCompat, numArgs: 0, variableArgs: false },
12686
12687 // (reserved partial commands for the lexer)
12688 BM: null,
12689 BD: null,
12690 'true': null,
12691 fa: null,
12692 fal: null,
12693 fals: null,
12694 'false': null,
12695 nu: null,
12696 nul: null,
12697 'null': null
12698 };
12699
12700 function EvaluatorPreprocessor(stream, xref, stateManager) {
12701 // TODO(mduan): pass array of knownCommands rather than OP_MAP
12702 // dictionary
12703 this.parser = new Parser(new Lexer(stream, OP_MAP), false, xref);
12704 this.stateManager = stateManager;
12705 this.nonProcessedArgs = [];
12706 }
12707
12708 EvaluatorPreprocessor.prototype = {
12709 get savedStatesDepth() {
12710 return this.stateManager.stateStack.length;
12711 },
12712
12713 // |operation| is an object with two fields:
12714 //
12715 // - |fn| is an out param.
12716 //
12717 // - |args| is an inout param. On entry, it should have one of two values.
12718 //
12719 // - An empty array. This indicates that the caller is providing the
12720 // array in which the args will be stored in. The caller should use
12721 // this value if it can reuse a single array for each call to read().
12722 //
12723 // - |null|. This indicates that the caller needs this function to create
12724 // the array in which any args are stored in. If there are zero args,
12725 // this function will leave |operation.args| as |null| (thus avoiding
12726 // allocations that would occur if we used an empty array to represent
12727 // zero arguments). Otherwise, it will replace |null| with a new array
12728 // containing the arguments. The caller should use this value if it
12729 // cannot reuse an array for each call to read().
12730 //
12731 // These two modes are present because this function is very hot and so
12732 // avoiding allocations where possible is worthwhile.
12733 //
12734 read: function EvaluatorPreprocessor_read(operation) {
12735 var args = operation.args;
12736 while (true) {
12737 var obj = this.parser.getObj();
12738 if (isCmd(obj)) {
12739 var cmd = obj.cmd;
12740 // Check that the command is valid
12741 var opSpec = OP_MAP[cmd];
12742 if (!opSpec) {
12743 warn('Unknown command "' + cmd + '"');
12744 continue;
12745 }
12746
12747 var fn = opSpec.id;
12748 var numArgs = opSpec.numArgs;
12749 var argsLength = args !== null ? args.length : 0;
12750
12751 if (!opSpec.variableArgs) {
12752 // Postscript commands can be nested, e.g. /F2 /GS2 gs 5.711 Tf
12753 if (argsLength !== numArgs) {
12754 var nonProcessedArgs = this.nonProcessedArgs;
12755 while (argsLength > numArgs) {
12756 nonProcessedArgs.push(args.shift());
12757 argsLength--;
12758 }
12759 while (argsLength < numArgs && nonProcessedArgs.length !== 0) {
12760 if (!args) {
12761 args = [];
12762 }
12763 args.unshift(nonProcessedArgs.pop());
12764 argsLength++;
12765 }
12766 }
12767
12768 if (argsLength < numArgs) {
12769 // If we receive too few args, it's not possible to possible
12770 // to execute the command, so skip the command
12771 info('Command ' + fn + ': because expected ' +
12772 numArgs + ' args, but received ' + argsLength +
12773 ' args; skipping');
12774 args = null;
12775 continue;
12776 }
12777 } else if (argsLength > numArgs) {
12778 info('Command ' + fn + ': expected [0,' + numArgs +
12779 '] args, but received ' + argsLength + ' args');
12780 }
12781
12782 // TODO figure out how to type-check vararg functions
12783 this.preprocessCommand(fn, args);
12784
12785 operation.fn = fn;
12786 operation.args = args;
12787 return true;
12788 } else {
12789 if (isEOF(obj)) {
12790 return false; // no more commands
12791 }
12792 // argument
12793 if (obj !== null) {
12794 if (!args) {
12795 args = [];
12796 }
12797 args.push((obj instanceof Dict ? obj.getAll() : obj));
12798 assert(args.length <= 33, 'Too many arguments');
12799 }
12800 }
12801 }
12802 },
12803
12804 preprocessCommand:
12805 function EvaluatorPreprocessor_preprocessCommand(fn, args) {
12806 switch (fn | 0) {
12807 case OPS.save:
12808 this.stateManager.save();
12809 break;
12810 case OPS.restore:
12811 this.stateManager.restore();
12812 break;
12813 case OPS.transform:
12814 this.stateManager.transform(args);
12815 break;
12816 }
12817 }
12818 };
12819 return EvaluatorPreprocessor;
12820 })();
12821
12822 var QueueOptimizer = (function QueueOptimizerClosure() {
12823 function addState(parentState, pattern, fn) {
12824 var state = parentState;
12825 for (var i = 0, ii = pattern.length - 1; i < ii; i++) {
12826 var item = pattern[i];
12827 state = (state[item] || (state[item] = []));
12828 }
12829 state[pattern[pattern.length - 1]] = fn;
12830 }
12831
12832 function handlePaintSolidColorImageMask(iFirstSave, count, fnArray,
12833 argsArray) {
12834 // Handles special case of mainly LaTeX documents which use image masks to
12835 // draw lines with the current fill style.
12836 // 'count' groups of (save, transform, paintImageMaskXObject, restore)+
12837 // have been found at iFirstSave.
12838 var iFirstPIMXO = iFirstSave + 2;
12839 for (var i = 0; i < count; i++) {
12840 var arg = argsArray[iFirstPIMXO + 4 * i];
12841 var imageMask = arg.length === 1 && arg[0];
12842 if (imageMask && imageMask.width === 1 && imageMask.height === 1 &&
12843 (!imageMask.data.length ||
12844 (imageMask.data.length === 1 && imageMask.data[0] === 0))) {
12845 fnArray[iFirstPIMXO + 4 * i] = OPS.paintSolidColorImageMask;
12846 continue;
12847 }
12848 break;
12849 }
12850 return count - i;
12851 }
12852
12853 var InitialState = [];
12854
12855 // This replaces (save, transform, paintInlineImageXObject, restore)+
12856 // sequences with one |paintInlineImageXObjectGroup| operation.
12857 addState(InitialState,
12858 [OPS.save, OPS.transform, OPS.paintInlineImageXObject, OPS.restore],
12859 function foundInlineImageGroup(context) {
12860 var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10;
12861 var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200;
12862 var MAX_WIDTH = 1000;
12863 var IMAGE_PADDING = 1;
12864
12865 var fnArray = context.fnArray, argsArray = context.argsArray;
12866 var curr = context.iCurr;
12867 var iFirstSave = curr - 3;
12868 var iFirstTransform = curr - 2;
12869 var iFirstPIIXO = curr - 1;
12870
12871 // Look for the quartets.
12872 var i = iFirstSave + 4;
12873 var ii = fnArray.length;
12874 while (i + 3 < ii) {
12875 if (fnArray[i] !== OPS.save ||
12876 fnArray[i + 1] !== OPS.transform ||
12877 fnArray[i + 2] !== OPS.paintInlineImageXObject ||
12878 fnArray[i + 3] !== OPS.restore) {
12879 break; // ops don't match
12880 }
12881 i += 4;
12882 }
12883
12884 // At this point, i is the index of the first op past the last valid
12885 // quartet.
12886 var count = Math.min((i - iFirstSave) / 4,
12887 MAX_IMAGES_IN_INLINE_IMAGES_BLOCK);
12888 if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) {
12889 return i;
12890 }
12891
12892 // assuming that heights of those image is too small (~1 pixel)
12893 // packing as much as possible by lines
12894 var maxX = 0;
12895 var map = [], maxLineHeight = 0;
12896 var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING;
12897 var q;
12898 for (q = 0; q < count; q++) {
12899 var transform = argsArray[iFirstTransform + (q << 2)];
12900 var img = argsArray[iFirstPIIXO + (q << 2)][0];
12901 if (currentX + img.width > MAX_WIDTH) {
12902 // starting new line
12903 maxX = Math.max(maxX, currentX);
12904 currentY += maxLineHeight + 2 * IMAGE_PADDING;
12905 currentX = 0;
12906 maxLineHeight = 0;
12907 }
12908 map.push({
12909 transform: transform,
12910 x: currentX, y: currentY,
12911 w: img.width, h: img.height
12912 });
12913 currentX += img.width + 2 * IMAGE_PADDING;
12914 maxLineHeight = Math.max(maxLineHeight, img.height);
12915 }
12916 var imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING;
12917 var imgHeight = currentY + maxLineHeight + IMAGE_PADDING;
12918 var imgData = new Uint8Array(imgWidth * imgHeight * 4);
12919 var imgRowSize = imgWidth << 2;
12920 for (q = 0; q < count; q++) {
12921 var data = argsArray[iFirstPIIXO + (q << 2)][0].data;
12922 // Copy image by lines and extends pixels into padding.
12923 var rowSize = map[q].w << 2;
12924 var dataOffset = 0;
12925 var offset = (map[q].x + map[q].y * imgWidth) << 2;
12926 imgData.set(data.subarray(0, rowSize), offset - imgRowSize);
12927 for (var k = 0, kk = map[q].h; k < kk; k++) {
12928 imgData.set(data.subarray(dataOffset, dataOffset + rowSize), offset);
12929 dataOffset += rowSize;
12930 offset += imgRowSize;
12931 }
12932 imgData.set(data.subarray(dataOffset - rowSize, dataOffset), offset);
12933 while (offset >= 0) {
12934 data[offset - 4] = data[offset];
12935 data[offset - 3] = data[offset + 1];
12936 data[offset - 2] = data[offset + 2];
12937 data[offset - 1] = data[offset + 3];
12938 data[offset + rowSize] = data[offset + rowSize - 4];
12939 data[offset + rowSize + 1] = data[offset + rowSize - 3];
12940 data[offset + rowSize + 2] = data[offset + rowSize - 2];
12941 data[offset + rowSize + 3] = data[offset + rowSize - 1];
12942 offset -= imgRowSize;
12943 }
12944 }
12945
12946 // Replace queue items.
12947 fnArray.splice(iFirstSave, count * 4, OPS.paintInlineImageXObjectGroup);
12948 argsArray.splice(iFirstSave, count * 4,
12949 [{ width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP,
12950 data: imgData }, map]);
12951
12952 return iFirstSave + 1;
12953 });
12954
12955 // This replaces (save, transform, paintImageMaskXObject, restore)+
12956 // sequences with one |paintImageMaskXObjectGroup| or one
12957 // |paintImageMaskXObjectRepeat| operation.
12958 addState(InitialState,
12959 [OPS.save, OPS.transform, OPS.paintImageMaskXObject, OPS.restore],
12960 function foundImageMaskGroup(context) {
12961 var MIN_IMAGES_IN_MASKS_BLOCK = 10;
12962 var MAX_IMAGES_IN_MASKS_BLOCK = 100;
12963 var MAX_SAME_IMAGES_IN_MASKS_BLOCK = 1000;
12964
12965 var fnArray = context.fnArray, argsArray = context.argsArray;
12966 var curr = context.iCurr;
12967 var iFirstSave = curr - 3;
12968 var iFirstTransform = curr - 2;
12969 var iFirstPIMXO = curr - 1;
12970
12971 // Look for the quartets.
12972 var i = iFirstSave + 4;
12973 var ii = fnArray.length;
12974 while (i + 3 < ii) {
12975 if (fnArray[i] !== OPS.save ||
12976 fnArray[i + 1] !== OPS.transform ||
12977 fnArray[i + 2] !== OPS.paintImageMaskXObject ||
12978 fnArray[i + 3] !== OPS.restore) {
12979 break; // ops don't match
12980 }
12981 i += 4;
12982 }
12983
12984 // At this point, i is the index of the first op past the last valid
12985 // quartet.
12986 var count = (i - iFirstSave) / 4;
12987 count = handlePaintSolidColorImageMask(iFirstSave, count, fnArray,
12988 argsArray);
12989 if (count < MIN_IMAGES_IN_MASKS_BLOCK) {
12990 return i;
12991 }
12992
12993 var q;
12994 var isSameImage = false;
12995 var iTransform, transformArgs;
12996 var firstPIMXOArg0 = argsArray[iFirstPIMXO][0];
12997 if (argsArray[iFirstTransform][1] === 0 &&
12998 argsArray[iFirstTransform][2] === 0) {
12999 isSameImage = true;
13000 var firstTransformArg0 = argsArray[iFirstTransform][0];
13001 var firstTransformArg3 = argsArray[iFirstTransform][3];
13002 iTransform = iFirstTransform + 4;
13003 var iPIMXO = iFirstPIMXO + 4;
13004 for (q = 1; q < count; q++, iTransform += 4, iPIMXO += 4) {
13005 transformArgs = argsArray[iTransform];
13006 if (argsArray[iPIMXO][0] !== firstPIMXOArg0 ||
13007 transformArgs[0] !== firstTransformArg0 ||
13008 transformArgs[1] !== 0 ||
13009 transformArgs[2] !== 0 ||
13010 transformArgs[3] !== firstTransformArg3) {
13011 if (q < MIN_IMAGES_IN_MASKS_BLOCK) {
13012 isSameImage = false;
13013 } else {
13014 count = q;
13015 }
13016 break; // different image or transform
13017 }
13018 }
13019 }
13020
13021 if (isSameImage) {
13022 count = Math.min(count, MAX_SAME_IMAGES_IN_MASKS_BLOCK);
13023 var positions = new Float32Array(count * 2);
13024 iTransform = iFirstTransform;
13025 for (q = 0; q < count; q++, iTransform += 4) {
13026 transformArgs = argsArray[iTransform];
13027 positions[(q << 1)] = transformArgs[4];
13028 positions[(q << 1) + 1] = transformArgs[5];
13029 }
13030
13031 // Replace queue items.
13032 fnArray.splice(iFirstSave, count * 4, OPS.paintImageMaskXObjectRepeat);
13033 argsArray.splice(iFirstSave, count * 4,
13034 [firstPIMXOArg0, firstTransformArg0, firstTransformArg3, positions]);
13035 } else {
13036 count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK);
13037 var images = [];
13038 for (q = 0; q < count; q++) {
13039 transformArgs = argsArray[iFirstTransform + (q << 2)];
13040 var maskParams = argsArray[iFirstPIMXO + (q << 2)][0];
13041 images.push({ data: maskParams.data, width: maskParams.width,
13042 height: maskParams.height,
13043 transform: transformArgs });
13044 }
13045
13046 // Replace queue items.
13047 fnArray.splice(iFirstSave, count * 4, OPS.paintImageMaskXObjectGroup);
13048 argsArray.splice(iFirstSave, count * 4, [images]);
13049 }
13050
13051 return iFirstSave + 1;
13052 });
13053
13054 // This replaces (save, transform, paintImageXObject, restore)+ sequences
13055 // with one paintImageXObjectRepeat operation, if the |transform| and
13056 // |paintImageXObjectRepeat| ops are appropriate.
13057 addState(InitialState,
13058 [OPS.save, OPS.transform, OPS.paintImageXObject, OPS.restore],
13059 function (context) {
13060 var MIN_IMAGES_IN_BLOCK = 3;
13061 var MAX_IMAGES_IN_BLOCK = 1000;
13062
13063 var fnArray = context.fnArray, argsArray = context.argsArray;
13064 var curr = context.iCurr;
13065 var iFirstSave = curr - 3;
13066 var iFirstTransform = curr - 2;
13067 var iFirstPIXO = curr - 1;
13068 var iFirstRestore = curr;
13069
13070 if (argsArray[iFirstTransform][1] !== 0 ||
13071 argsArray[iFirstTransform][2] !== 0) {
13072 return iFirstRestore + 1; // transform has the wrong form
13073 }
13074
13075 // Look for the quartets.
13076 var firstPIXOArg0 = argsArray[iFirstPIXO][0];
13077 var firstTransformArg0 = argsArray[iFirstTransform][0];
13078 var firstTransformArg3 = argsArray[iFirstTransform][3];
13079 var i = iFirstSave + 4;
13080 var ii = fnArray.length;
13081 while (i + 3 < ii) {
13082 if (fnArray[i] !== OPS.save ||
13083 fnArray[i + 1] !== OPS.transform ||
13084 fnArray[i + 2] !== OPS.paintImageXObject ||
13085 fnArray[i + 3] !== OPS.restore) {
13086 break; // ops don't match
13087 }
13088 if (argsArray[i + 1][0] !== firstTransformArg0 ||
13089 argsArray[i + 1][1] !== 0 ||
13090 argsArray[i + 1][2] !== 0 ||
13091 argsArray[i + 1][3] !== firstTransformArg3) {
13092 break; // transforms don't match
13093 }
13094 if (argsArray[i + 2][0] !== firstPIXOArg0) {
13095 break; // images don't match
13096 }
13097 i += 4;
13098 }
13099
13100 // At this point, i is the index of the first op past the last valid
13101 // quartet.
13102 var count = Math.min((i - iFirstSave) / 4, MAX_IMAGES_IN_BLOCK);
13103 if (count < MIN_IMAGES_IN_BLOCK) {
13104 return i;
13105 }
13106
13107 // Extract the (x,y) positions from all of the matching transforms.
13108 var positions = new Float32Array(count * 2);
13109 var iTransform = iFirstTransform;
13110 for (var q = 0; q < count; q++, iTransform += 4) {
13111 var transformArgs = argsArray[iTransform];
13112 positions[(q << 1)] = transformArgs[4];
13113 positions[(q << 1) + 1] = transformArgs[5];
13114 }
13115
13116 // Replace queue items.
13117 var args = [firstPIXOArg0, firstTransformArg0, firstTransformArg3,
13118 positions];
13119 fnArray.splice(iFirstSave, count * 4, OPS.paintImageXObjectRepeat);
13120 argsArray.splice(iFirstSave, count * 4, args);
13121
13122 return iFirstSave + 1;
13123 });
13124
13125 // This replaces (beginText, setFont, setTextMatrix, showText, endText)+
13126 // sequences with (beginText, setFont, (setTextMatrix, showText)+, endText)+
13127 // sequences, if the font for each one is the same.
13128 addState(InitialState,
13129 [OPS.beginText, OPS.setFont, OPS.setTextMatrix, OPS.showText, OPS.endText],
13130 function (context) {
13131 var MIN_CHARS_IN_BLOCK = 3;
13132 var MAX_CHARS_IN_BLOCK = 1000;
13133
13134 var fnArray = context.fnArray, argsArray = context.argsArray;
13135 var curr = context.iCurr;
13136 var iFirstBeginText = curr - 4;
13137 var iFirstSetFont = curr - 3;
13138 var iFirstSetTextMatrix = curr - 2;
13139 var iFirstShowText = curr - 1;
13140 var iFirstEndText = curr;
13141
13142 // Look for the quintets.
13143 var firstSetFontArg0 = argsArray[iFirstSetFont][0];
13144 var firstSetFontArg1 = argsArray[iFirstSetFont][1];
13145 var i = iFirstBeginText + 5;
13146 var ii = fnArray.length;
13147 while (i + 4 < ii) {
13148 if (fnArray[i] !== OPS.beginText ||
13149 fnArray[i + 1] !== OPS.setFont ||
13150 fnArray[i + 2] !== OPS.setTextMatrix ||
13151 fnArray[i + 3] !== OPS.showText ||
13152 fnArray[i + 4] !== OPS.endText) {
13153 break; // ops don't match
13154 }
13155 if (argsArray[i + 1][0] !== firstSetFontArg0 ||
13156 argsArray[i + 1][1] !== firstSetFontArg1) {
13157 break; // fonts don't match
13158 }
13159 i += 5;
13160 }
13161
13162 // At this point, i is the index of the first op past the last valid
13163 // quintet.
13164 var count = Math.min(((i - iFirstBeginText) / 5), MAX_CHARS_IN_BLOCK);
13165 if (count < MIN_CHARS_IN_BLOCK) {
13166 return i;
13167 }
13168
13169 // If the preceding quintet is (<something>, setFont, setTextMatrix,
13170 // showText, endText), include that as well. (E.g. <something> might be
13171 // |dependency|.)
13172 var iFirst = iFirstBeginText;
13173 if (iFirstBeginText >= 4 &&
13174 fnArray[iFirstBeginText - 4] === fnArray[iFirstSetFont] &&
13175 fnArray[iFirstBeginText - 3] === fnArray[iFirstSetTextMatrix] &&
13176 fnArray[iFirstBeginText - 2] === fnArray[iFirstShowText] &&
13177 fnArray[iFirstBeginText - 1] === fnArray[iFirstEndText] &&
13178 argsArray[iFirstBeginText - 4][0] === firstSetFontArg0 &&
13179 argsArray[iFirstBeginText - 4][1] === firstSetFontArg1) {
13180 count++;
13181 iFirst -= 5;
13182 }
13183
13184 // Remove (endText, beginText, setFont) trios.
13185 var iEndText = iFirst + 4;
13186 for (var q = 1; q < count; q++) {
13187 fnArray.splice(iEndText, 3);
13188 argsArray.splice(iEndText, 3);
13189 iEndText += 2;
13190 }
13191
13192 return iEndText + 1;
13193 });
13194
13195 function QueueOptimizer() {}
13196
13197 QueueOptimizer.prototype = {
13198 optimize: function QueueOptimizer_optimize(queue) {
13199 var fnArray = queue.fnArray, argsArray = queue.argsArray;
13200 var context = {
13201 iCurr: 0,
13202 fnArray: fnArray,
13203 argsArray: argsArray
13204 };
13205 var state;
13206 var i = 0, ii = fnArray.length;
13207 while (i < ii) {
13208 state = (state || InitialState)[fnArray[i]];
13209 if (typeof state === 'function') { // we found some handler
13210 context.iCurr = i;
13211 // state() returns the index of the first non-matching op (if we
13212 // didn't match) or the first op past the modified ops (if we did
13213 // match and replace).
13214 i = state(context);
13215 state = undefined; // reset the state machine
13216 ii = context.fnArray.length;
13217 } else {
13218 i++;
13219 }
13220 }
13221 }
13222 };
13223 return QueueOptimizer;
13224 })();
13225
13226
13227 var BUILT_IN_CMAPS = [
13228 // << Start unicode maps.
13229 'Adobe-GB1-UCS2',
13230 'Adobe-CNS1-UCS2',
13231 'Adobe-Japan1-UCS2',
13232 'Adobe-Korea1-UCS2',
13233 // >> End unicode maps.
13234 '78-EUC-H',
13235 '78-EUC-V',
13236 '78-H',
13237 '78-RKSJ-H',
13238 '78-RKSJ-V',
13239 '78-V',
13240 '78ms-RKSJ-H',
13241 '78ms-RKSJ-V',
13242 '83pv-RKSJ-H',
13243 '90ms-RKSJ-H',
13244 '90ms-RKSJ-V',
13245 '90msp-RKSJ-H',
13246 '90msp-RKSJ-V',
13247 '90pv-RKSJ-H',
13248 '90pv-RKSJ-V',
13249 'Add-H',
13250 'Add-RKSJ-H',
13251 'Add-RKSJ-V',
13252 'Add-V',
13253 'Adobe-CNS1-0',
13254 'Adobe-CNS1-1',
13255 'Adobe-CNS1-2',
13256 'Adobe-CNS1-3',
13257 'Adobe-CNS1-4',
13258 'Adobe-CNS1-5',
13259 'Adobe-CNS1-6',
13260 'Adobe-GB1-0',
13261 'Adobe-GB1-1',
13262 'Adobe-GB1-2',
13263 'Adobe-GB1-3',
13264 'Adobe-GB1-4',
13265 'Adobe-GB1-5',
13266 'Adobe-Japan1-0',
13267 'Adobe-Japan1-1',
13268 'Adobe-Japan1-2',
13269 'Adobe-Japan1-3',
13270 'Adobe-Japan1-4',
13271 'Adobe-Japan1-5',
13272 'Adobe-Japan1-6',
13273 'Adobe-Korea1-0',
13274 'Adobe-Korea1-1',
13275 'Adobe-Korea1-2',
13276 'B5-H',
13277 'B5-V',
13278 'B5pc-H',
13279 'B5pc-V',
13280 'CNS-EUC-H',
13281 'CNS-EUC-V',
13282 'CNS1-H',
13283 'CNS1-V',
13284 'CNS2-H',
13285 'CNS2-V',
13286 'ETHK-B5-H',
13287 'ETHK-B5-V',
13288 'ETen-B5-H',
13289 'ETen-B5-V',
13290 'ETenms-B5-H',
13291 'ETenms-B5-V',
13292 'EUC-H',
13293 'EUC-V',
13294 'Ext-H',
13295 'Ext-RKSJ-H',
13296 'Ext-RKSJ-V',
13297 'Ext-V',
13298 'GB-EUC-H',
13299 'GB-EUC-V',
13300 'GB-H',
13301 'GB-V',
13302 'GBK-EUC-H',
13303 'GBK-EUC-V',
13304 'GBK2K-H',
13305 'GBK2K-V',
13306 'GBKp-EUC-H',
13307 'GBKp-EUC-V',
13308 'GBT-EUC-H',
13309 'GBT-EUC-V',
13310 'GBT-H',
13311 'GBT-V',
13312 'GBTpc-EUC-H',
13313 'GBTpc-EUC-V',
13314 'GBpc-EUC-H',
13315 'GBpc-EUC-V',
13316 'H',
13317 'HKdla-B5-H',
13318 'HKdla-B5-V',
13319 'HKdlb-B5-H',
13320 'HKdlb-B5-V',
13321 'HKgccs-B5-H',
13322 'HKgccs-B5-V',
13323 'HKm314-B5-H',
13324 'HKm314-B5-V',
13325 'HKm471-B5-H',
13326 'HKm471-B5-V',
13327 'HKscs-B5-H',
13328 'HKscs-B5-V',
13329 'Hankaku',
13330 'Hiragana',
13331 'KSC-EUC-H',
13332 'KSC-EUC-V',
13333 'KSC-H',
13334 'KSC-Johab-H',
13335 'KSC-Johab-V',
13336 'KSC-V',
13337 'KSCms-UHC-H',
13338 'KSCms-UHC-HW-H',
13339 'KSCms-UHC-HW-V',
13340 'KSCms-UHC-V',
13341 'KSCpc-EUC-H',
13342 'KSCpc-EUC-V',
13343 'Katakana',
13344 'NWP-H',
13345 'NWP-V',
13346 'RKSJ-H',
13347 'RKSJ-V',
13348 'Roman',
13349 'UniCNS-UCS2-H',
13350 'UniCNS-UCS2-V',
13351 'UniCNS-UTF16-H',
13352 'UniCNS-UTF16-V',
13353 'UniCNS-UTF32-H',
13354 'UniCNS-UTF32-V',
13355 'UniCNS-UTF8-H',
13356 'UniCNS-UTF8-V',
13357 'UniGB-UCS2-H',
13358 'UniGB-UCS2-V',
13359 'UniGB-UTF16-H',
13360 'UniGB-UTF16-V',
13361 'UniGB-UTF32-H',
13362 'UniGB-UTF32-V',
13363 'UniGB-UTF8-H',
13364 'UniGB-UTF8-V',
13365 'UniJIS-UCS2-H',
13366 'UniJIS-UCS2-HW-H',
13367 'UniJIS-UCS2-HW-V',
13368 'UniJIS-UCS2-V',
13369 'UniJIS-UTF16-H',
13370 'UniJIS-UTF16-V',
13371 'UniJIS-UTF32-H',
13372 'UniJIS-UTF32-V',
13373 'UniJIS-UTF8-H',
13374 'UniJIS-UTF8-V',
13375 'UniJIS2004-UTF16-H',
13376 'UniJIS2004-UTF16-V',
13377 'UniJIS2004-UTF32-H',
13378 'UniJIS2004-UTF32-V',
13379 'UniJIS2004-UTF8-H',
13380 'UniJIS2004-UTF8-V',
13381 'UniJISPro-UCS2-HW-V',
13382 'UniJISPro-UCS2-V',
13383 'UniJISPro-UTF8-V',
13384 'UniJISX0213-UTF32-H',
13385 'UniJISX0213-UTF32-V',
13386 'UniJISX02132004-UTF32-H',
13387 'UniJISX02132004-UTF32-V',
13388 'UniKS-UCS2-H',
13389 'UniKS-UCS2-V',
13390 'UniKS-UTF16-H',
13391 'UniKS-UTF16-V',
13392 'UniKS-UTF32-H',
13393 'UniKS-UTF32-V',
13394 'UniKS-UTF8-H',
13395 'UniKS-UTF8-V',
13396 'V',
13397 'WP-Symbol'];
13398
13399 // CMap, not to be confused with TrueType's cmap.
13400 var CMap = (function CMapClosure() {
13401 function CMap(builtInCMap) {
13402 // Codespace ranges are stored as follows:
13403 // [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
13404 // where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
13405 this.codespaceRanges = [[], [], [], []];
13406 this.numCodespaceRanges = 0;
13407 // Map entries have one of two forms.
13408 // - cid chars are 16-bit unsigned integers, stored as integers.
13409 // - bf chars are variable-length byte sequences, stored as strings, with
13410 // one byte per character.
13411 this._map = [];
13412 this.name = '';
13413 this.vertical = false;
13414 this.useCMap = null;
13415 this.builtInCMap = builtInCMap;
13416 }
13417 CMap.prototype = {
13418 addCodespaceRange: function(n, low, high) {
13419 this.codespaceRanges[n - 1].push(low, high);
13420 this.numCodespaceRanges++;
13421 },
13422
13423 mapCidRange: function(low, high, dstLow) {
13424 while (low <= high) {
13425 this._map[low++] = dstLow++;
13426 }
13427 },
13428
13429 mapBfRange: function(low, high, dstLow) {
13430 var lastByte = dstLow.length - 1;
13431 while (low <= high) {
13432 this._map[low++] = dstLow;
13433 // Only the last byte has to be incremented.
13434 dstLow = dstLow.substr(0, lastByte) +
13435 String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
13436 }
13437 },
13438
13439 mapBfRangeToArray: function(low, high, array) {
13440 var i = 0, ii = array.length;
13441 while (low <= high && i < ii) {
13442 this._map[low] = array[i++];
13443 ++low;
13444 }
13445 },
13446
13447 // This is used for both bf and cid chars.
13448 mapOne: function(src, dst) {
13449 this._map[src] = dst;
13450 },
13451
13452 lookup: function(code) {
13453 return this._map[code];
13454 },
13455
13456 contains: function(code) {
13457 return this._map[code] !== undefined;
13458 },
13459
13460 forEach: function(callback) {
13461 // Most maps have fewer than 65536 entries, and for those we use normal
13462 // array iteration. But really sparse tables are possible -- e.g. with
13463 // indices in the *billions*. For such tables we use for..in, which isn't
13464 // ideal because it stringifies the indices for all present elements, but
13465 // it does avoid iterating over every undefined entry.
13466 var map = this._map;
13467 var length = map.length;
13468 var i;
13469 if (length <= 0x10000) {
13470 for (i = 0; i < length; i++) {
13471 if (map[i] !== undefined) {
13472 callback(i, map[i]);
13473 }
13474 }
13475 } else {
13476 for (i in this._map) {
13477 callback(i, map[i]);
13478 }
13479 }
13480 },
13481
13482 charCodeOf: function(value) {
13483 return this._map.indexOf(value);
13484 },
13485
13486 getMap: function() {
13487 return this._map;
13488 },
13489
13490 readCharCode: function(str, offset, out) {
13491 var c = 0;
13492 var codespaceRanges = this.codespaceRanges;
13493 var codespaceRangesLen = this.codespaceRanges.length;
13494 // 9.7.6.2 CMap Mapping
13495 // The code length is at most 4.
13496 for (var n = 0; n < codespaceRangesLen; n++) {
13497 c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
13498 // Check each codespace range to see if it falls within.
13499 var codespaceRange = codespaceRanges[n];
13500 for (var k = 0, kk = codespaceRange.length; k < kk;) {
13501 var low = codespaceRange[k++];
13502 var high = codespaceRange[k++];
13503 if (c >= low && c <= high) {
13504 out.charcode = c;
13505 out.length = n + 1;
13506 return;
13507 }
13508 }
13509 }
13510 out.charcode = 0;
13511 out.length = 1;
13512 },
13513
13514 get isIdentityCMap() {
13515 if (!(this.name === 'Identity-H' || this.name === 'Identity-V')) {
13516 return false;
13517 }
13518 if (this._map.length !== 0x10000) {
13519 return false;
13520 }
13521 for (var i = 0; i < 0x10000; i++) {
13522 if (this._map[i] !== i) {
13523 return false;
13524 }
13525 }
13526 return true;
13527 }
13528 };
13529 return CMap;
13530 })();
13531
13532 // A special case of CMap, where the _map array implicitly has a length of
13533 // 65536 and each element is equal to its index.
13534 var IdentityCMap = (function IdentityCMapClosure() {
13535 function IdentityCMap(vertical, n) {
13536 CMap.call(this);
13537 this.vertical = vertical;
13538 this.addCodespaceRange(n, 0, 0xffff);
13539 }
13540 Util.inherit(IdentityCMap, CMap, {});
13541
13542 IdentityCMap.prototype = {
13543 addCodespaceRange: CMap.prototype.addCodespaceRange,
13544
13545 mapCidRange: function(low, high, dstLow) {
13546 error('should not call mapCidRange');
13547 },
13548
13549 mapBfRange: function(low, high, dstLow) {
13550 error('should not call mapBfRange');
13551 },
13552
13553 mapBfRangeToArray: function(low, high, array) {
13554 error('should not call mapBfRangeToArray');
13555 },
13556
13557 mapOne: function(src, dst) {
13558 error('should not call mapCidOne');
13559 },
13560
13561 lookup: function(code) {
13562 return (isInt(code) && code <= 0xffff) ? code : undefined;
13563 },
13564
13565 contains: function(code) {
13566 return isInt(code) && code <= 0xffff;
13567 },
13568
13569 forEach: function(callback) {
13570 for (var i = 0; i <= 0xffff; i++) {
13571 callback(i, i);
13572 }
13573 },
13574
13575 charCodeOf: function(value) {
13576 return (isInt(value) && value <= 0xffff) ? value : -1;
13577 },
13578
13579 getMap: function() {
13580 // Sometimes identity maps must be instantiated, but it's rare.
13581 var map = new Array(0x10000);
13582 for (var i = 0; i <= 0xffff; i++) {
13583 map[i] = i;
13584 }
13585 return map;
13586 },
13587
13588 readCharCode: CMap.prototype.readCharCode,
13589
13590 get isIdentityCMap() {
13591 error('should not access .isIdentityCMap');
13592 }
13593 };
13594
13595 return IdentityCMap;
13596 })();
13597
13598 var BinaryCMapReader = (function BinaryCMapReaderClosure() {
13599 function fetchBinaryData(url) {
13600 var nonBinaryRequest = PDFJS.disableWorker;
13601 var request = new XMLHttpRequest();
13602 request.open('GET', url, false);
13603 if (!nonBinaryRequest) {
13604 try {
13605 request.responseType = 'arraybuffer';
13606 nonBinaryRequest = request.responseType !== 'arraybuffer';
13607 } catch (e) {
13608 nonBinaryRequest = true;
13609 }
13610 }
13611 if (nonBinaryRequest && request.overrideMimeType) {
13612 request.overrideMimeType('text/plain; charset=x-user-defined');
13613 }
13614 request.send(null);
13615 if (nonBinaryRequest ? !request.responseText : !request.response) {
13616 error('Unable to get binary cMap at: ' + url);
13617 }
13618 if (nonBinaryRequest) {
13619 var data = Array.prototype.map.call(request.responseText, function (ch) {
13620 return ch.charCodeAt(0) & 255;
13621 });
13622 return new Uint8Array(data);
13623 }
13624 return new Uint8Array(request.response);
13625 }
13626
13627 function hexToInt(a, size) {
13628 var n = 0;
13629 for (var i = 0; i <= size; i++) {
13630 n = (n << 8) | a[i];
13631 }
13632 return n >>> 0;
13633 }
13634
13635 function hexToStr(a, size) {
13636 // This code is hot. Special-case some common values to avoid creating an
13637 // object with subarray().
13638 if (size === 1) {
13639 return String.fromCharCode(a[0], a[1]);
13640 }
13641 if (size === 3) {
13642 return String.fromCharCode(a[0], a[1], a[2], a[3]);
13643 }
13644 return String.fromCharCode.apply(null, a.subarray(0, size + 1));
13645 }
13646
13647 function addHex(a, b, size) {
13648 var c = 0;
13649 for (var i = size; i >= 0; i--) {
13650 c += a[i] + b[i];
13651 a[i] = c & 255;
13652 c >>= 8;
13653 }
13654 }
13655
13656 function incHex(a, size) {
13657 var c = 1;
13658 for (var i = size; i >= 0 && c > 0; i--) {
13659 c += a[i];
13660 a[i] = c & 255;
13661 c >>= 8;
13662 }
13663 }
13664
13665 var MAX_NUM_SIZE = 16;
13666 var MAX_ENCODED_NUM_SIZE = 19; // ceil(MAX_NUM_SIZE * 7 / 8)
13667
13668 function BinaryCMapStream(data) {
13669 this.buffer = data;
13670 this.pos = 0;
13671 this.end = data.length;
13672 this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE);
13673 }
13674
13675 BinaryCMapStream.prototype = {
13676 readByte: function () {
13677 if (this.pos >= this.end) {
13678 return -1;
13679 }
13680 return this.buffer[this.pos++];
13681 },
13682 readNumber: function () {
13683 var n = 0;
13684 var last;
13685 do {
13686 var b = this.readByte();
13687 if (b < 0) {
13688 error('unexpected EOF in bcmap');
13689 }
13690 last = !(b & 0x80);
13691 n = (n << 7) | (b & 0x7F);
13692 } while (!last);
13693 return n;
13694 },
13695 readSigned: function () {
13696 var n = this.readNumber();
13697 return (n & 1) ? ~(n >>> 1) : n >>> 1;
13698 },
13699 readHex: function (num, size) {
13700 num.set(this.buffer.subarray(this.pos,
13701 this.pos + size + 1));
13702 this.pos += size + 1;
13703 },
13704 readHexNumber: function (num, size) {
13705 var last;
13706 var stack = this.tmpBuf, sp = 0;
13707 do {
13708 var b = this.readByte();
13709 if (b < 0) {
13710 error('unexpected EOF in bcmap');
13711 }
13712 last = !(b & 0x80);
13713 stack[sp++] = b & 0x7F;
13714 } while (!last);
13715 var i = size, buffer = 0, bufferSize = 0;
13716 while (i >= 0) {
13717 while (bufferSize < 8 && stack.length > 0) {
13718 buffer = (stack[--sp] << bufferSize) | buffer;
13719 bufferSize += 7;
13720 }
13721 num[i] = buffer & 255;
13722 i--;
13723 buffer >>= 8;
13724 bufferSize -= 8;
13725 }
13726 },
13727 readHexSigned: function (num, size) {
13728 this.readHexNumber(num, size);
13729 var sign = num[size] & 1 ? 255 : 0;
13730 var c = 0;
13731 for (var i = 0; i <= size; i++) {
13732 c = ((c & 1) << 8) | num[i];
13733 num[i] = (c >> 1) ^ sign;
13734 }
13735 },
13736 readString: function () {
13737 var len = this.readNumber();
13738 var s = '';
13739 for (var i = 0; i < len; i++) {
13740 s += String.fromCharCode(this.readNumber());
13741 }
13742 return s;
13743 }
13744 };
13745
13746 function processBinaryCMap(url, cMap, extend) {
13747 var data = fetchBinaryData(url);
13748 var stream = new BinaryCMapStream(data);
13749
13750 var header = stream.readByte();
13751 cMap.vertical = !!(header & 1);
13752
13753 var useCMap = null;
13754 var start = new Uint8Array(MAX_NUM_SIZE);
13755 var end = new Uint8Array(MAX_NUM_SIZE);
13756 var char = new Uint8Array(MAX_NUM_SIZE);
13757 var charCode = new Uint8Array(MAX_NUM_SIZE);
13758 var tmp = new Uint8Array(MAX_NUM_SIZE);
13759 var code;
13760
13761 var b;
13762 while ((b = stream.readByte()) >= 0) {
13763 var type = b >> 5;
13764 if (type === 7) { // metadata, e.g. comment or usecmap
13765 switch (b & 0x1F) {
13766 case 0:
13767 stream.readString(); // skipping comment
13768 break;
13769 case 1:
13770 useCMap = stream.readString();
13771 break;
13772 }
13773 continue;
13774 }
13775 var sequence = !!(b & 0x10);
13776 var dataSize = b & 15;
13777
13778 assert(dataSize + 1 <= MAX_NUM_SIZE);
13779
13780 var ucs2DataSize = 1;
13781 var subitemsCount = stream.readNumber();
13782 var i;
13783 switch (type) {
13784 case 0: // codespacerange
13785 stream.readHex(start, dataSize);
13786 stream.readHexNumber(end, dataSize);
13787 addHex(end, start, dataSize);
13788 cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
13789 hexToInt(end, dataSize));
13790 for (i = 1; i < subitemsCount; i++) {
13791 incHex(end, dataSize);
13792 stream.readHexNumber(start, dataSize);
13793 addHex(start, end, dataSize);
13794 stream.readHexNumber(end, dataSize);
13795 addHex(end, start, dataSize);
13796 cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
13797 hexToInt(end, dataSize));
13798 }
13799 break;
13800 case 1: // notdefrange
13801 stream.readHex(start, dataSize);
13802 stream.readHexNumber(end, dataSize);
13803 addHex(end, start, dataSize);
13804 code = stream.readNumber();
13805 // undefined range, skipping
13806 for (i = 1; i < subitemsCount; i++) {
13807 incHex(end, dataSize);
13808 stream.readHexNumber(start, dataSize);
13809 addHex(start, end, dataSize);
13810 stream.readHexNumber(end, dataSize);
13811 addHex(end, start, dataSize);
13812 code = stream.readNumber();
13813 // nop
13814 }
13815 break;
13816 case 2: // cidchar
13817 stream.readHex(char, dataSize);
13818 code = stream.readNumber();
13819 cMap.mapOne(hexToInt(char, dataSize), code);
13820 for (i = 1; i < subitemsCount; i++) {
13821 incHex(char, dataSize);
13822 if (!sequence) {
13823 stream.readHexNumber(tmp, dataSize);
13824 addHex(char, tmp, dataSize);
13825 }
13826 code = stream.readSigned() + (code + 1);
13827 cMap.mapOne(hexToInt(char, dataSize), code);
13828 }
13829 break;
13830 case 3: // cidrange
13831 stream.readHex(start, dataSize);
13832 stream.readHexNumber(end, dataSize);
13833 addHex(end, start, dataSize);
13834 code = stream.readNumber();
13835 cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
13836 code);
13837 for (i = 1; i < subitemsCount; i++) {
13838 incHex(end, dataSize);
13839 if (!sequence) {
13840 stream.readHexNumber(start, dataSize);
13841 addHex(start, end, dataSize);
13842 } else {
13843 start.set(end);
13844 }
13845 stream.readHexNumber(end, dataSize);
13846 addHex(end, start, dataSize);
13847 code = stream.readNumber();
13848 cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
13849 code);
13850 }
13851 break;
13852 case 4: // bfchar
13853 stream.readHex(char, ucs2DataSize);
13854 stream.readHex(charCode, dataSize);
13855 cMap.mapOne(hexToInt(char, ucs2DataSize),
13856 hexToStr(charCode, dataSize));
13857 for (i = 1; i < subitemsCount; i++) {
13858 incHex(char, ucs2DataSize);
13859 if (!sequence) {
13860 stream.readHexNumber(tmp, ucs2DataSize);
13861 addHex(char, tmp, ucs2DataSize);
13862 }
13863 incHex(charCode, dataSize);
13864 stream.readHexSigned(tmp, dataSize);
13865 addHex(charCode, tmp, dataSize);
13866 cMap.mapOne(hexToInt(char, ucs2DataSize),
13867 hexToStr(charCode, dataSize));
13868 }
13869 break;
13870 case 5: // bfrange
13871 stream.readHex(start, ucs2DataSize);
13872 stream.readHexNumber(end, ucs2DataSize);
13873 addHex(end, start, ucs2DataSize);
13874 stream.readHex(charCode, dataSize);
13875 cMap.mapBfRange(hexToInt(start, ucs2DataSize),
13876 hexToInt(end, ucs2DataSize),
13877 hexToStr(charCode, dataSize));
13878 for (i = 1; i < subitemsCount; i++) {
13879 incHex(end, ucs2DataSize);
13880 if (!sequence) {
13881 stream.readHexNumber(start, ucs2DataSize);
13882 addHex(start, end, ucs2DataSize);
13883 } else {
13884 start.set(end);
13885 }
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 }
13893 break;
13894 default:
13895 error('Unknown type: ' + type);
13896 break;
13897 }
13898 }
13899
13900 if (useCMap) {
13901 extend(useCMap);
13902 }
13903 return cMap;
13904 }
13905
13906 function BinaryCMapReader() {}
13907
13908 BinaryCMapReader.prototype = {
13909 read: processBinaryCMap
13910 };
13911
13912 return BinaryCMapReader;
13913 })();
13914
13915 var CMapFactory = (function CMapFactoryClosure() {
13916 function strToInt(str) {
13917 var a = 0;
13918 for (var i = 0; i < str.length; i++) {
13919 a = (a << 8) | str.charCodeAt(i);
13920 }
13921 return a >>> 0;
13922 }
13923
13924 function expectString(obj) {
13925 if (!isString(obj)) {
13926 error('Malformed CMap: expected string.');
13927 }
13928 }
13929
13930 function expectInt(obj) {
13931 if (!isInt(obj)) {
13932 error('Malformed CMap: expected int.');
13933 }
13934 }
13935
13936 function parseBfChar(cMap, lexer) {
13937 while (true) {
13938 var obj = lexer.getObj();
13939 if (isEOF(obj)) {
13940 break;
13941 }
13942 if (isCmd(obj, 'endbfchar')) {
13943 return;
13944 }
13945 expectString(obj);
13946 var src = strToInt(obj);
13947 obj = lexer.getObj();
13948 // TODO are /dstName used?
13949 expectString(obj);
13950 var dst = obj;
13951 cMap.mapOne(src, dst);
13952 }
13953 }
13954
13955 function parseBfRange(cMap, lexer) {
13956 while (true) {
13957 var obj = lexer.getObj();
13958 if (isEOF(obj)) {
13959 break;
13960 }
13961 if (isCmd(obj, 'endbfrange')) {
13962 return;
13963 }
13964 expectString(obj);
13965 var low = strToInt(obj);
13966 obj = lexer.getObj();
13967 expectString(obj);
13968 var high = strToInt(obj);
13969 obj = lexer.getObj();
13970 if (isInt(obj) || isString(obj)) {
13971 var dstLow = isInt(obj) ? String.fromCharCode(obj) : obj;
13972 cMap.mapBfRange(low, high, dstLow);
13973 } else if (isCmd(obj, '[')) {
13974 obj = lexer.getObj();
13975 var array = [];
13976 while (!isCmd(obj, ']') && !isEOF(obj)) {
13977 array.push(obj);
13978 obj = lexer.getObj();
13979 }
13980 cMap.mapBfRangeToArray(low, high, array);
13981 } else {
13982 break;
13983 }
13984 }
13985 error('Invalid bf range.');
13986 }
13987
13988 function parseCidChar(cMap, lexer) {
13989 while (true) {
13990 var obj = lexer.getObj();
13991 if (isEOF(obj)) {
13992 break;
13993 }
13994 if (isCmd(obj, 'endcidchar')) {
13995 return;
13996 }
13997 expectString(obj);
13998 var src = strToInt(obj);
13999 obj = lexer.getObj();
14000 expectInt(obj);
14001 var dst = obj;
14002 cMap.mapOne(src, dst);
14003 }
14004 }
14005
14006 function parseCidRange(cMap, lexer) {
14007 while (true) {
14008 var obj = lexer.getObj();
14009 if (isEOF(obj)) {
14010 break;
14011 }
14012 if (isCmd(obj, 'endcidrange')) {
14013 return;
14014 }
14015 expectString(obj);
14016 var low = strToInt(obj);
14017 obj = lexer.getObj();
14018 expectString(obj);
14019 var high = strToInt(obj);
14020 obj = lexer.getObj();
14021 expectInt(obj);
14022 var dstLow = obj;
14023 cMap.mapCidRange(low, high, dstLow);
14024 }
14025 }
14026
14027 function parseCodespaceRange(cMap, lexer) {
14028 while (true) {
14029 var obj = lexer.getObj();
14030 if (isEOF(obj)) {
14031 break;
14032 }
14033 if (isCmd(obj, 'endcodespacerange')) {
14034 return;
14035 }
14036 if (!isString(obj)) {
14037 break;
14038 }
14039 var low = strToInt(obj);
14040 obj = lexer.getObj();
14041 if (!isString(obj)) {
14042 break;
14043 }
14044 var high = strToInt(obj);
14045 cMap.addCodespaceRange(obj.length, low, high);
14046 }
14047 error('Invalid codespace range.');
14048 }
14049
14050 function parseWMode(cMap, lexer) {
14051 var obj = lexer.getObj();
14052 if (isInt(obj)) {
14053 cMap.vertical = !!obj;
14054 }
14055 }
14056
14057 function parseCMapName(cMap, lexer) {
14058 var obj = lexer.getObj();
14059 if (isName(obj) && isString(obj.name)) {
14060 cMap.name = obj.name;
14061 }
14062 }
14063
14064 function parseCMap(cMap, lexer, builtInCMapParams, useCMap) {
14065 var previous;
14066 var embededUseCMap;
14067 objLoop: while (true) {
14068 var obj = lexer.getObj();
14069 if (isEOF(obj)) {
14070 break;
14071 } else if (isName(obj)) {
14072 if (obj.name === 'WMode') {
14073 parseWMode(cMap, lexer);
14074 } else if (obj.name === 'CMapName') {
14075 parseCMapName(cMap, lexer);
14076 }
14077 previous = obj;
14078 } else if (isCmd(obj)) {
14079 switch (obj.cmd) {
14080 case 'endcmap':
14081 break objLoop;
14082 case 'usecmap':
14083 if (isName(previous)) {
14084 embededUseCMap = previous.name;
14085 }
14086 break;
14087 case 'begincodespacerange':
14088 parseCodespaceRange(cMap, lexer);
14089 break;
14090 case 'beginbfchar':
14091 parseBfChar(cMap, lexer);
14092 break;
14093 case 'begincidchar':
14094 parseCidChar(cMap, lexer);
14095 break;
14096 case 'beginbfrange':
14097 parseBfRange(cMap, lexer);
14098 break;
14099 case 'begincidrange':
14100 parseCidRange(cMap, lexer);
14101 break;
14102 }
14103 }
14104 }
14105
14106 if (!useCMap && embededUseCMap) {
14107 // Load the usecmap definition from the file only if there wasn't one
14108 // specified.
14109 useCMap = embededUseCMap;
14110 }
14111 if (useCMap) {
14112 extendCMap(cMap, builtInCMapParams, useCMap);
14113 }
14114 }
14115
14116 function extendCMap(cMap, builtInCMapParams, useCMap) {
14117 cMap.useCMap = createBuiltInCMap(useCMap, builtInCMapParams);
14118 // If there aren't any code space ranges defined clone all the parent ones
14119 // into this cMap.
14120 if (cMap.numCodespaceRanges === 0) {
14121 var useCodespaceRanges = cMap.useCMap.codespaceRanges;
14122 for (var i = 0; i < useCodespaceRanges.length; i++) {
14123 cMap.codespaceRanges[i] = useCodespaceRanges[i].slice();
14124 }
14125 cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges;
14126 }
14127 // Merge the map into the current one, making sure not to override
14128 // any previously defined entries.
14129 cMap.useCMap.forEach(function(key, value) {
14130 if (!cMap.contains(key)) {
14131 cMap.mapOne(key, cMap.useCMap.lookup(key));
14132 }
14133 });
14134 }
14135
14136 function parseBinaryCMap(name, builtInCMapParams) {
14137 var url = builtInCMapParams.url + name + '.bcmap';
14138 var cMap = new CMap(true);
14139 new BinaryCMapReader().read(url, cMap, function (useCMap) {
14140 extendCMap(cMap, builtInCMapParams, useCMap);
14141 });
14142 return cMap;
14143 }
14144
14145 function createBuiltInCMap(name, builtInCMapParams) {
14146 if (name === 'Identity-H') {
14147 return new IdentityCMap(false, 2);
14148 } else if (name === 'Identity-V') {
14149 return new IdentityCMap(true, 2);
14150 }
14151 if (BUILT_IN_CMAPS.indexOf(name) === -1) {
14152 error('Unknown cMap name: ' + name);
14153 }
14154 assert(builtInCMapParams, 'built-in cMap parameters are not provided');
14155
14156 if (builtInCMapParams.packed) {
14157 return parseBinaryCMap(name, builtInCMapParams);
14158 }
14159
14160 var request = new XMLHttpRequest();
14161 var url = builtInCMapParams.url + name;
14162 request.open('GET', url, false);
14163 request.send(null);
14164 if (!request.responseText) {
14165 error('Unable to get cMap at: ' + url);
14166 }
14167 var cMap = new CMap(true);
14168 var lexer = new Lexer(new StringStream(request.responseText));
14169 parseCMap(cMap, lexer, builtInCMapParams, null);
14170 return cMap;
14171 }
14172
14173 return {
14174 create: function (encoding, builtInCMapParams, useCMap) {
14175 if (isName(encoding)) {
14176 return createBuiltInCMap(encoding.name, builtInCMapParams);
14177 } else if (isStream(encoding)) {
14178 var cMap = new CMap();
14179 var lexer = new Lexer(encoding);
14180 try {
14181 parseCMap(cMap, lexer, builtInCMapParams, useCMap);
14182 } catch (e) {
14183 warn('Invalid CMap data. ' + e);
14184 }
14185 if (cMap.isIdentityCMap) {
14186 return createBuiltInCMap(cMap.name, builtInCMapParams);
14187 }
14188 return cMap;
14189 }
14190 error('Encoding required.');
14191 }
14192 };
14193 })();
14194
14195
14196 // Unicode Private Use Area
14197 var PRIVATE_USE_OFFSET_START = 0xE000;
14198 var PRIVATE_USE_OFFSET_END = 0xF8FF;
14199 var SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = false;
14200
14201 // PDF Glyph Space Units are one Thousandth of a TextSpace Unit
14202 // except for Type 3 fonts
14203 var PDF_GLYPH_SPACE_UNITS = 1000;
14204
14205 // Hinting is currently disabled due to unknown problems on windows
14206 // in tracemonkey and various other pdfs with type1 fonts.
14207 var HINTING_ENABLED = false;
14208
14209 // Accented charactars are not displayed properly on windows, using this flag
14210 // to control analysis of seac charstrings.
14211 var SEAC_ANALYSIS_ENABLED = false;
14212
14213 var FontFlags = {
14214 FixedPitch: 1,
14215 Serif: 2,
14216 Symbolic: 4,
14217 Script: 8,
14218 Nonsymbolic: 32,
14219 Italic: 64,
14220 AllCap: 65536,
14221 SmallCap: 131072,
14222 ForceBold: 262144
14223 };
14224
14225 var Encodings = {
14226 ExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14227 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14228 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle',
14229 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
14230 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
14231 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
14232 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
14233 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon',
14234 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior',
14235 'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
14236 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior',
14237 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior',
14238 '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '',
14239 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
14240 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
14241 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
14242 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
14243 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
14244 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '',
14245 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14246 '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',
14247 '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall',
14248 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '',
14249 'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall',
14250 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters',
14251 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
14252 'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior',
14253 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior',
14254 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior',
14255 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior',
14256 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior',
14257 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior',
14258 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
14259 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall',
14260 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
14261 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
14262 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
14263 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
14264 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
14265 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
14266 'Ydieresissmall'],
14267 MacExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
14268 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14269 'space', 'exclamsmall', 'Hungarumlautsmall', 'centoldstyle',
14270 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
14271 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
14272 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle',
14273 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
14274 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
14275 'nineoldstyle', 'colon', 'semicolon', '', 'threequartersemdash', '',
14276 'questionsmall', '', '', '', '', 'Ethsmall', '', '', 'onequarter',
14277 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
14278 'seveneighths', 'onethird', 'twothirds', '', '', '', '', '', '', 'ff',
14279 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior',
14280 'Circumflexsmall', 'hypheninferior', 'Gravesmall', 'Asmall', 'Bsmall',
14281 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',
14282 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
14283 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
14284 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',
14285 'Tildesmall', '', '', 'asuperior', 'centsuperior', '', '', '', '',
14286 'Aacutesmall', 'Agravesmall', 'Acircumflexsmall', 'Adieresissmall',
14287 'Atildesmall', 'Aringsmall', 'Ccedillasmall', 'Eacutesmall', 'Egravesmall',
14288 'Ecircumflexsmall', 'Edieresissmall', 'Iacutesmall', 'Igravesmall',
14289 'Icircumflexsmall', 'Idieresissmall', 'Ntildesmall', 'Oacutesmall',
14290 'Ogravesmall', 'Ocircumflexsmall', 'Odieresissmall', 'Otildesmall',
14291 'Uacutesmall', 'Ugravesmall', 'Ucircumflexsmall', 'Udieresissmall', '',
14292 'eightsuperior', 'fourinferior', 'threeinferior', 'sixinferior',
14293 'eightinferior', 'seveninferior', 'Scaronsmall', '', 'centinferior',
14294 'twoinferior', '', 'Dieresissmall', '', 'Caronsmall', 'osuperior',
14295 'fiveinferior', '', 'commainferior', 'periodinferior', 'Yacutesmall', '',
14296 'dollarinferior', '', 'Thornsmall', '', 'nineinferior', 'zeroinferior',
14297 'Zcaronsmall', 'AEsmall', 'Oslashsmall', 'questiondownsmall',
14298 'oneinferior', 'Lslashsmall', '', '', '', '', '', '', 'Cedillasmall', '',
14299 '', '', '', '', 'OEsmall', 'figuredash', 'hyphensuperior', '', '', '', '',
14300 'exclamdownsmall', '', 'Ydieresissmall', '', 'onesuperior', 'twosuperior',
14301 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',
14302 'sevensuperior', 'ninesuperior', 'zerosuperior', '', 'esuperior',
14303 'rsuperior', 'tsuperior', '', '', 'isuperior', 'ssuperior', 'dsuperior',
14304 '', '', '', '', '', 'lsuperior', 'Ogoneksmall', 'Brevesmall',
14305 'Macronsmall', 'bsuperior', 'nsuperior', 'msuperior', 'commasuperior',
14306 'periodsuperior', 'Dotaccentsmall', 'Ringsmall'],
14307 MacRomanEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14308 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14309 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
14310 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
14311 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
14312 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
14313 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
14314 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
14315 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
14316 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
14317 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
14318 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '',
14319 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis',
14320 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde',
14321 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
14322 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute',
14323 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave',
14324 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling',
14325 'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright',
14326 'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity',
14327 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff',
14328 'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine',
14329 'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot',
14330 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft',
14331 'guillemotright', 'ellipsis', 'space', 'Agrave', 'Atilde', 'Otilde', 'OE',
14332 'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft',
14333 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction',
14334 'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl',
14335 'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand',
14336 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute',
14337 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple',
14338 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex',
14339 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut',
14340 'ogonek', 'caron'],
14341 StandardEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14342 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14343 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
14344 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
14345 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
14346 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
14347 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
14348 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
14349 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
14350 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f',
14351 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
14352 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
14353 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14354 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown',
14355 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
14356 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
14357 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl',
14358 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase',
14359 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
14360 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex',
14361 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla',
14362 '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '',
14363 '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '',
14364 '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae',
14365 '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'],
14366 WinAnsiEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14367 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14368 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
14369 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
14370 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
14371 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
14372 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
14373 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
14374 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
14375 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
14376 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
14377 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
14378 'bullet', 'Euro', 'bullet', 'quotesinglbase', 'florin', 'quotedblbase',
14379 'ellipsis', 'dagger', 'daggerdbl', 'circumflex', 'perthousand', 'Scaron',
14380 'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft',
14381 'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash',
14382 'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet',
14383 'zcaron', 'Ydieresis', 'space', 'exclamdown', 'cent', 'sterling',
14384 'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright',
14385 'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered',
14386 'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute',
14387 'mu', 'paragraph', 'periodcentered', 'cedilla', 'onesuperior',
14388 'ordmasculine', 'guillemotright', 'onequarter', 'onehalf', 'threequarters',
14389 'questiondown', 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', 'Adieresis',
14390 'Aring', 'AE', 'Ccedilla', 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis',
14391 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve',
14392 'Oacute', 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash',
14393 'Ugrave', 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn',
14394 'germandbls', 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis',
14395 'aring', 'ae', 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis',
14396 'igrave', 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve',
14397 'oacute', 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash',
14398 'ugrave', 'uacute', 'ucircumflex', 'udieresis', 'yacute', 'thorn',
14399 'ydieresis'],
14400 SymbolSetEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
14401 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14402 'space', 'exclam', 'universal', 'numbersign', 'existential', 'percent',
14403 'ampersand', 'suchthat', 'parenleft', 'parenright', 'asteriskmath', 'plus',
14404 'comma', 'minus', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
14405 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
14406 'equal', 'greater', 'question', 'congruent', 'Alpha', 'Beta', 'Chi',
14407 'Delta', 'Epsilon', 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa',
14408 'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', 'Theta', 'Rho', 'Sigma', 'Tau',
14409 'Upsilon', 'sigma1', 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft',
14410 'therefore', 'bracketright', 'perpendicular', 'underscore', 'radicalex',
14411 'alpha', 'beta', 'chi', 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota',
14412 'phi1', 'kappa', 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho',
14413 'sigma', 'tau', 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta',
14414 'braceleft', 'bar', 'braceright', 'similar', '', '', '', '', '', '', '',
14415 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14416 '', '', '', '', '', '', '', 'Euro', 'Upsilon1', 'minute', 'lessequal',
14417 'fraction', 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade',
14418 'arrowboth', 'arrowleft', 'arrowup', 'arrowright', 'arrowdown', 'degree',
14419 'plusminus', 'second', 'greaterequal', 'multiply', 'proportional',
14420 'partialdiff', 'bullet', 'divide', 'notequal', 'equivalence',
14421 'approxequal', 'ellipsis', 'arrowvertex', 'arrowhorizex', 'carriagereturn',
14422 'aleph', 'Ifraktur', 'Rfraktur', 'weierstrass', 'circlemultiply',
14423 'circleplus', 'emptyset', 'intersection', 'union', 'propersuperset',
14424 'reflexsuperset', 'notsubset', 'propersubset', 'reflexsubset', 'element',
14425 'notelement', 'angle', 'gradient', 'registerserif', 'copyrightserif',
14426 'trademarkserif', 'product', 'radical', 'dotmath', 'logicalnot',
14427 'logicaland', 'logicalor', 'arrowdblboth', 'arrowdblleft', 'arrowdblup',
14428 'arrowdblright', 'arrowdbldown', 'lozenge', 'angleleft', 'registersans',
14429 'copyrightsans', 'trademarksans', 'summation', 'parenlefttp',
14430 'parenleftex', 'parenleftbt', 'bracketlefttp', 'bracketleftex',
14431 'bracketleftbt', 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex',
14432 '', 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt',
14433 'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp',
14434 'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid',
14435 'bracerightbt'],
14436 ZapfDingbatsEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
14437 '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
14438 'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117',
14439 'a11', 'a12', 'a13', 'a14', 'a15', 'a16', 'a105', 'a17', 'a18', 'a19',
14440 'a20', 'a21', 'a22', 'a23', 'a24', 'a25', 'a26', 'a27', 'a28', 'a6', 'a7',
14441 'a8', 'a9', 'a10', 'a29', 'a30', 'a31', 'a32', 'a33', 'a34', 'a35', 'a36',
14442 'a37', 'a38', 'a39', 'a40', 'a41', 'a42', 'a43', 'a44', 'a45', 'a46',
14443 'a47', 'a48', 'a49', 'a50', 'a51', 'a52', 'a53', 'a54', 'a55', 'a56',
14444 'a57', 'a58', 'a59', 'a60', 'a61', 'a62', 'a63', 'a64', 'a65', 'a66',
14445 'a67', 'a68', 'a69', 'a70', 'a71', 'a72', 'a73', 'a74', 'a203', 'a75',
14446 'a204', 'a76', 'a77', 'a78', 'a79', 'a81', 'a82', 'a83', 'a84', 'a97',
14447 'a98', 'a99', 'a100', '', 'a89', 'a90', 'a93', 'a94', 'a91', 'a92', 'a205',
14448 'a85', 'a206', 'a86', 'a87', 'a88', 'a95', 'a96', '', '', '', '', '', '',
14449 '', '', '', '', '', '', '', '', '', '', '', '', '', 'a101', 'a102', 'a103',
14450 'a104', 'a106', 'a107', 'a108', 'a112', 'a111', 'a110', 'a109', 'a120',
14451 'a121', 'a122', 'a123', 'a124', 'a125', 'a126', 'a127', 'a128', 'a129',
14452 'a130', 'a131', 'a132', 'a133', 'a134', 'a135', 'a136', 'a137', 'a138',
14453 'a139', 'a140', 'a141', 'a142', 'a143', 'a144', 'a145', 'a146', 'a147',
14454 'a148', 'a149', 'a150', 'a151', 'a152', 'a153', 'a154', 'a155', 'a156',
14455 'a157', 'a158', 'a159', 'a160', 'a161', 'a163', 'a164', 'a196', 'a165',
14456 'a192', 'a166', 'a167', 'a168', 'a169', 'a170', 'a171', 'a172', 'a173',
14457 'a162', 'a174', 'a175', 'a176', 'a177', 'a178', 'a179', 'a193', 'a180',
14458 'a199', 'a181', 'a200', 'a182', '', 'a201', 'a183', 'a184', 'a197', 'a185',
14459 'a194', 'a198', 'a186', 'a195', 'a187', 'a188', 'a189', 'a190', 'a191']
14460 };
14461
14462 /**
14463 * Hold a map of decoded fonts and of the standard fourteen Type1
14464 * fonts and their acronyms.
14465 */
14466 var stdFontMap = {
14467 'ArialNarrow': 'Helvetica',
14468 'ArialNarrow-Bold': 'Helvetica-Bold',
14469 'ArialNarrow-BoldItalic': 'Helvetica-BoldOblique',
14470 'ArialNarrow-Italic': 'Helvetica-Oblique',
14471 'ArialBlack': 'Helvetica',
14472 'ArialBlack-Bold': 'Helvetica-Bold',
14473 'ArialBlack-BoldItalic': 'Helvetica-BoldOblique',
14474 'ArialBlack-Italic': 'Helvetica-Oblique',
14475 'Arial': 'Helvetica',
14476 'Arial-Bold': 'Helvetica-Bold',
14477 'Arial-BoldItalic': 'Helvetica-BoldOblique',
14478 'Arial-Italic': 'Helvetica-Oblique',
14479 'Arial-BoldItalicMT': 'Helvetica-BoldOblique',
14480 'Arial-BoldMT': 'Helvetica-Bold',
14481 'Arial-ItalicMT': 'Helvetica-Oblique',
14482 'ArialMT': 'Helvetica',
14483 'Courier-Bold': 'Courier-Bold',
14484 'Courier-BoldItalic': 'Courier-BoldOblique',
14485 'Courier-Italic': 'Courier-Oblique',
14486 'CourierNew': 'Courier',
14487 'CourierNew-Bold': 'Courier-Bold',
14488 'CourierNew-BoldItalic': 'Courier-BoldOblique',
14489 'CourierNew-Italic': 'Courier-Oblique',
14490 'CourierNewPS-BoldItalicMT': 'Courier-BoldOblique',
14491 'CourierNewPS-BoldMT': 'Courier-Bold',
14492 'CourierNewPS-ItalicMT': 'Courier-Oblique',
14493 'CourierNewPSMT': 'Courier',
14494 'Helvetica': 'Helvetica',
14495 'Helvetica-Bold': 'Helvetica-Bold',
14496 'Helvetica-BoldItalic': 'Helvetica-BoldOblique',
14497 'Helvetica-BoldOblique': 'Helvetica-BoldOblique',
14498 'Helvetica-Italic': 'Helvetica-Oblique',
14499 'Helvetica-Oblique':'Helvetica-Oblique',
14500 'Symbol-Bold': 'Symbol',
14501 'Symbol-BoldItalic': 'Symbol',
14502 'Symbol-Italic': 'Symbol',
14503 'TimesNewRoman': 'Times-Roman',
14504 'TimesNewRoman-Bold': 'Times-Bold',
14505 'TimesNewRoman-BoldItalic': 'Times-BoldItalic',
14506 'TimesNewRoman-Italic': 'Times-Italic',
14507 'TimesNewRomanPS': 'Times-Roman',
14508 'TimesNewRomanPS-Bold': 'Times-Bold',
14509 'TimesNewRomanPS-BoldItalic': 'Times-BoldItalic',
14510 'TimesNewRomanPS-BoldItalicMT': 'Times-BoldItalic',
14511 'TimesNewRomanPS-BoldMT': 'Times-Bold',
14512 'TimesNewRomanPS-Italic': 'Times-Italic',
14513 'TimesNewRomanPS-ItalicMT': 'Times-Italic',
14514 'TimesNewRomanPSMT': 'Times-Roman',
14515 'TimesNewRomanPSMT-Bold': 'Times-Bold',
14516 'TimesNewRomanPSMT-BoldItalic': 'Times-BoldItalic',
14517 'TimesNewRomanPSMT-Italic': 'Times-Italic'
14518 };
14519
14520 /**
14521 * Holds the map of the non-standard fonts that might be included as a standard
14522 * fonts without glyph data.
14523 */
14524 var nonStdFontMap = {
14525 'CenturyGothic': 'Helvetica',
14526 'CenturyGothic-Bold': 'Helvetica-Bold',
14527 'CenturyGothic-BoldItalic': 'Helvetica-BoldOblique',
14528 'CenturyGothic-Italic': 'Helvetica-Oblique',
14529 'ComicSansMS': 'Comic Sans MS',
14530 'ComicSansMS-Bold': 'Comic Sans MS-Bold',
14531 'ComicSansMS-BoldItalic': 'Comic Sans MS-BoldItalic',
14532 'ComicSansMS-Italic': 'Comic Sans MS-Italic',
14533 'LucidaConsole': 'Courier',
14534 'LucidaConsole-Bold': 'Courier-Bold',
14535 'LucidaConsole-BoldItalic': 'Courier-BoldOblique',
14536 'LucidaConsole-Italic': 'Courier-Oblique',
14537 'MS-Gothic': 'MS Gothic',
14538 'MS-Gothic-Bold': 'MS Gothic-Bold',
14539 'MS-Gothic-BoldItalic': 'MS Gothic-BoldItalic',
14540 'MS-Gothic-Italic': 'MS Gothic-Italic',
14541 'MS-Mincho': 'MS Mincho',
14542 'MS-Mincho-Bold': 'MS Mincho-Bold',
14543 'MS-Mincho-BoldItalic': 'MS Mincho-BoldItalic',
14544 'MS-Mincho-Italic': 'MS Mincho-Italic',
14545 'MS-PGothic': 'MS PGothic',
14546 'MS-PGothic-Bold': 'MS PGothic-Bold',
14547 'MS-PGothic-BoldItalic': 'MS PGothic-BoldItalic',
14548 'MS-PGothic-Italic': 'MS PGothic-Italic',
14549 'MS-PMincho': 'MS PMincho',
14550 'MS-PMincho-Bold': 'MS PMincho-Bold',
14551 'MS-PMincho-BoldItalic': 'MS PMincho-BoldItalic',
14552 'MS-PMincho-Italic': 'MS PMincho-Italic',
14553 'Wingdings': 'ZapfDingbats'
14554 };
14555
14556 var serifFonts = {
14557 'Adobe Jenson': true, 'Adobe Text': true, 'Albertus': true,
14558 'Aldus': true, 'Alexandria': true, 'Algerian': true,
14559 'American Typewriter': true, 'Antiqua': true, 'Apex': true,
14560 'Arno': true, 'Aster': true, 'Aurora': true,
14561 'Baskerville': true, 'Bell': true, 'Bembo': true,
14562 'Bembo Schoolbook': true, 'Benguiat': true, 'Berkeley Old Style': true,
14563 'Bernhard Modern': true, 'Berthold City': true, 'Bodoni': true,
14564 'Bauer Bodoni': true, 'Book Antiqua': true, 'Bookman': true,
14565 'Bordeaux Roman': true, 'Californian FB': true, 'Calisto': true,
14566 'Calvert': true, 'Capitals': true, 'Cambria': true,
14567 'Cartier': true, 'Caslon': true, 'Catull': true,
14568 'Centaur': true, 'Century Old Style': true, 'Century Schoolbook': true,
14569 'Chaparral': true, 'Charis SIL': true, 'Cheltenham': true,
14570 'Cholla Slab': true, 'Clarendon': true, 'Clearface': true,
14571 'Cochin': true, 'Colonna': true, 'Computer Modern': true,
14572 'Concrete Roman': true, 'Constantia': true, 'Cooper Black': true,
14573 'Corona': true, 'Ecotype': true, 'Egyptienne': true,
14574 'Elephant': true, 'Excelsior': true, 'Fairfield': true,
14575 'FF Scala': true, 'Folkard': true, 'Footlight': true,
14576 'FreeSerif': true, 'Friz Quadrata': true, 'Garamond': true,
14577 'Gentium': true, 'Georgia': true, 'Gloucester': true,
14578 'Goudy Old Style': true, 'Goudy Schoolbook': true, 'Goudy Pro Font': true,
14579 'Granjon': true, 'Guardian Egyptian': true, 'Heather': true,
14580 'Hercules': true, 'High Tower Text': true, 'Hiroshige': true,
14581 'Hoefler Text': true, 'Humana Serif': true, 'Imprint': true,
14582 'Ionic No. 5': true, 'Janson': true, 'Joanna': true,
14583 'Korinna': true, 'Lexicon': true, 'Liberation Serif': true,
14584 'Linux Libertine': true, 'Literaturnaya': true, 'Lucida': true,
14585 'Lucida Bright': true, 'Melior': true, 'Memphis': true,
14586 'Miller': true, 'Minion': true, 'Modern': true,
14587 'Mona Lisa': true, 'Mrs Eaves': true, 'MS Serif': true,
14588 'Museo Slab': true, 'New York': true, 'Nimbus Roman': true,
14589 'NPS Rawlinson Roadway': true, 'Palatino': true, 'Perpetua': true,
14590 'Plantin': true, 'Plantin Schoolbook': true, 'Playbill': true,
14591 'Poor Richard': true, 'Rawlinson Roadway': true, 'Renault': true,
14592 'Requiem': true, 'Rockwell': true, 'Roman': true,
14593 'Rotis Serif': true, 'Sabon': true, 'Scala': true,
14594 'Seagull': true, 'Sistina': true, 'Souvenir': true,
14595 'STIX': true, 'Stone Informal': true, 'Stone Serif': true,
14596 'Sylfaen': true, 'Times': true, 'Trajan': true,
14597 'Trinité': true, 'Trump Mediaeval': true, 'Utopia': true,
14598 'Vale Type': true, 'Bitstream Vera': true, 'Vera Serif': true,
14599 'Versailles': true, 'Wanted': true, 'Weiss': true,
14600 'Wide Latin': true, 'Windsor': true, 'XITS': true
14601 };
14602
14603 var symbolsFonts = {
14604 'Dingbats': true, 'Symbol': true, 'ZapfDingbats': true
14605 };
14606
14607 // Glyph map for well-known standard fonts. Sometimes Ghostscript uses CID fonts
14608 // but does not embed the CID to GID mapping. The mapping is incomplete for all
14609 // glyphs, but common for some set of the standard fonts.
14610 var GlyphMapForStandardFonts = {
14611 '2': 10, '3': 32, '4': 33, '5': 34, '6': 35, '7': 36, '8': 37, '9': 38,
14612 '10': 39, '11': 40, '12': 41, '13': 42, '14': 43, '15': 44, '16': 45,
14613 '17': 46, '18': 47, '19': 48, '20': 49, '21': 50, '22': 51, '23': 52,
14614 '24': 53, '25': 54, '26': 55, '27': 56, '28': 57, '29': 58, '30': 894,
14615 '31': 60, '32': 61, '33': 62, '34': 63, '35': 64, '36': 65, '37': 66,
14616 '38': 67, '39': 68, '40': 69, '41': 70, '42': 71, '43': 72, '44': 73,
14617 '45': 74, '46': 75, '47': 76, '48': 77, '49': 78, '50': 79, '51': 80,
14618 '52': 81, '53': 82, '54': 83, '55': 84, '56': 85, '57': 86, '58': 87,
14619 '59': 88, '60': 89, '61': 90, '62': 91, '63': 92, '64': 93, '65': 94,
14620 '66': 95, '67': 96, '68': 97, '69': 98, '70': 99, '71': 100, '72': 101,
14621 '73': 102, '74': 103, '75': 104, '76': 105, '77': 106, '78': 107, '79': 108,
14622 '80': 109, '81': 110, '82': 111, '83': 112, '84': 113, '85': 114, '86': 115,
14623 '87': 116, '88': 117, '89': 118, '90': 119, '91': 120, '92': 121, '93': 122,
14624 '94': 123, '95': 124, '96': 125, '97': 126, '98': 196, '99': 197, '100': 199,
14625 '101': 201, '102': 209, '103': 214, '104': 220, '105': 225, '106': 224,
14626 '107': 226, '108': 228, '109': 227, '110': 229, '111': 231, '112': 233,
14627 '113': 232, '114': 234, '115': 235, '116': 237, '117': 236, '118': 238,
14628 '119': 239, '120': 241, '121': 243, '122': 242, '123': 244, '124': 246,
14629 '125': 245, '126': 250, '127': 249, '128': 251, '129': 252, '130': 8224,
14630 '131': 176, '132': 162, '133': 163, '134': 167, '135': 8226, '136': 182,
14631 '137': 223, '138': 174, '139': 169, '140': 8482, '141': 180, '142': 168,
14632 '143': 8800, '144': 198, '145': 216, '146': 8734, '147': 177, '148': 8804,
14633 '149': 8805, '150': 165, '151': 181, '152': 8706, '153': 8721, '154': 8719,
14634 '156': 8747, '157': 170, '158': 186, '159': 8486, '160': 230, '161': 248,
14635 '162': 191, '163': 161, '164': 172, '165': 8730, '166': 402, '167': 8776,
14636 '168': 8710, '169': 171, '170': 187, '171': 8230, '210': 218, '223': 711,
14637 '224': 321, '225': 322, '227': 353, '229': 382, '234': 253, '252': 263,
14638 '253': 268, '254': 269, '258': 258, '260': 260, '261': 261, '265': 280,
14639 '266': 281, '268': 283, '269': 313, '275': 323, '276': 324, '278': 328,
14640 '284': 345, '285': 346, '286': 347, '292': 367, '295': 377, '296': 378,
14641 '298': 380, '305': 963,
14642 '306': 964, '307': 966, '308': 8215, '309': 8252, '310': 8319, '311': 8359,
14643 '312': 8592, '313': 8593, '337': 9552, '493': 1039, '494': 1040, '705': 1524,
14644 '706': 8362, '710': 64288, '711': 64298, '759': 1617, '761': 1776,
14645 '763': 1778, '775': 1652, '777': 1764, '778': 1780, '779': 1781, '780': 1782,
14646 '782': 771, '783': 64726, '786': 8363, '788': 8532, '790': 768, '791': 769,
14647 '792': 768, '795': 803, '797': 64336, '798': 64337, '799': 64342,
14648 '800': 64343, '801': 64344, '802': 64345, '803': 64362, '804': 64363,
14649 '805': 64364, '2424': 7821, '2425': 7822, '2426': 7823, '2427': 7824,
14650 '2428': 7825, '2429': 7826, '2430': 7827, '2433': 7682, '2678': 8045,
14651 '2679': 8046, '2830': 1552, '2838': 686, '2840': 751, '2842': 753,
14652 '2843': 754, '2844': 755, '2846': 757, '2856': 767, '2857': 848, '2858': 849,
14653 '2862': 853, '2863': 854, '2864': 855, '2865': 861, '2866': 862, '2906': 7460,
14654 '2908': 7462, '2909': 7463, '2910': 7464, '2912': 7466, '2913': 7467,
14655 '2914': 7468, '2916': 7470, '2917': 7471, '2918': 7472, '2920': 7474,
14656 '2921': 7475, '2922': 7476, '2924': 7478, '2925': 7479, '2926': 7480,
14657 '2928': 7482, '2929': 7483, '2930': 7484, '2932': 7486, '2933': 7487,
14658 '2934': 7488, '2936': 7490, '2937': 7491, '2938': 7492, '2940': 7494,
14659 '2941': 7495, '2942': 7496, '2944': 7498, '2946': 7500, '2948': 7502,
14660 '2950': 7504, '2951': 7505, '2952': 7506, '2954': 7508, '2955': 7509,
14661 '2956': 7510, '2958': 7512, '2959': 7513, '2960': 7514, '2962': 7516,
14662 '2963': 7517, '2964': 7518, '2966': 7520, '2967': 7521, '2968': 7522,
14663 '2970': 7524, '2971': 7525, '2972': 7526, '2974': 7528, '2975': 7529,
14664 '2976': 7530, '2978': 1537, '2979': 1538, '2980': 1539, '2982': 1549,
14665 '2983': 1551, '2984': 1552, '2986': 1554, '2987': 1555, '2988': 1556,
14666 '2990': 1623, '2991': 1624, '2995': 1775, '2999': 1791, '3002': 64290,
14667 '3003': 64291, '3004': 64292, '3006': 64294, '3007': 64295, '3008': 64296,
14668 '3011': 1900, '3014': 8223, '3015': 8244, '3017': 7532, '3018': 7533,
14669 '3019': 7534, '3075': 7590, '3076': 7591, '3079': 7594, '3080': 7595,
14670 '3083': 7598, '3084': 7599, '3087': 7602, '3088': 7603, '3091': 7606,
14671 '3092': 7607, '3095': 7610, '3096': 7611, '3099': 7614, '3100': 7615,
14672 '3103': 7618, '3104': 7619, '3107': 8337, '3108': 8338, '3116': 1884,
14673 '3119': 1885, '3120': 1885, '3123': 1886, '3124': 1886, '3127': 1887,
14674 '3128': 1887, '3131': 1888, '3132': 1888, '3135': 1889, '3136': 1889,
14675 '3139': 1890, '3140': 1890, '3143': 1891, '3144': 1891, '3147': 1892,
14676 '3148': 1892, '3153': 580, '3154': 581, '3157': 584, '3158': 585, '3161': 588,
14677 '3162': 589, '3165': 891, '3166': 892, '3169': 1274, '3170': 1275,
14678 '3173': 1278, '3174': 1279, '3181': 7622, '3182': 7623, '3282': 11799,
14679 '3316': 578, '3379': 42785, '3393': 1159, '3416': 8377
14680 };
14681
14682 // Some characters, e.g. copyrightserif, are mapped to the private use area and
14683 // might not be displayed using standard fonts. Mapping/hacking well-known chars
14684 // to the similar equivalents in the normal characters range.
14685 var SpecialPUASymbols = {
14686 '63721': 0x00A9, // copyrightsans (0xF8E9) => copyright
14687 '63193': 0x00A9, // copyrightserif (0xF6D9) => copyright
14688 '63720': 0x00AE, // registersans (0xF8E8) => registered
14689 '63194': 0x00AE, // registerserif (0xF6DA) => registered
14690 '63722': 0x2122, // trademarksans (0xF8EA) => trademark
14691 '63195': 0x2122, // trademarkserif (0xF6DB) => trademark
14692 '63729': 0x23A7, // bracelefttp (0xF8F1)
14693 '63730': 0x23A8, // braceleftmid (0xF8F2)
14694 '63731': 0x23A9, // braceleftbt (0xF8F3)
14695 '63740': 0x23AB, // bracerighttp (0xF8FC)
14696 '63741': 0x23AC, // bracerightmid (0xF8FD)
14697 '63742': 0x23AD, // bracerightbt (0xF8FE)
14698 '63726': 0x23A1, // bracketlefttp (0xF8EE)
14699 '63727': 0x23A2, // bracketleftex (0xF8EF)
14700 '63728': 0x23A3, // bracketleftbt (0xF8F0)
14701 '63737': 0x23A4, // bracketrighttp (0xF8F9)
14702 '63738': 0x23A5, // bracketrightex (0xF8FA)
14703 '63739': 0x23A6, // bracketrightbt (0xF8FB)
14704 '63723': 0x239B, // parenlefttp (0xF8EB)
14705 '63724': 0x239C, // parenleftex (0xF8EC)
14706 '63725': 0x239D, // parenleftbt (0xF8ED)
14707 '63734': 0x239E, // parenrighttp (0xF8F6)
14708 '63735': 0x239F, // parenrightex (0xF8F7)
14709 '63736': 0x23A0, // parenrightbt (0xF8F8)
14710 };
14711 function mapSpecialUnicodeValues(code) {
14712 if (code >= 0xFFF0 && code <= 0xFFFF) { // Specials unicode block.
14713 return 0;
14714 } else if (code >= 0xF600 && code <= 0xF8FF) {
14715 return (SpecialPUASymbols[code] || code);
14716 }
14717 return code;
14718 }
14719
14720 var UnicodeRanges = [
14721 { 'begin': 0x0000, 'end': 0x007F }, // Basic Latin
14722 { 'begin': 0x0080, 'end': 0x00FF }, // Latin-1 Supplement
14723 { 'begin': 0x0100, 'end': 0x017F }, // Latin Extended-A
14724 { 'begin': 0x0180, 'end': 0x024F }, // Latin Extended-B
14725 { 'begin': 0x0250, 'end': 0x02AF }, // IPA Extensions
14726 { 'begin': 0x02B0, 'end': 0x02FF }, // Spacing Modifier Letters
14727 { 'begin': 0x0300, 'end': 0x036F }, // Combining Diacritical Marks
14728 { 'begin': 0x0370, 'end': 0x03FF }, // Greek and Coptic
14729 { 'begin': 0x2C80, 'end': 0x2CFF }, // Coptic
14730 { 'begin': 0x0400, 'end': 0x04FF }, // Cyrillic
14731 { 'begin': 0x0530, 'end': 0x058F }, // Armenian
14732 { 'begin': 0x0590, 'end': 0x05FF }, // Hebrew
14733 { 'begin': 0xA500, 'end': 0xA63F }, // Vai
14734 { 'begin': 0x0600, 'end': 0x06FF }, // Arabic
14735 { 'begin': 0x07C0, 'end': 0x07FF }, // NKo
14736 { 'begin': 0x0900, 'end': 0x097F }, // Devanagari
14737 { 'begin': 0x0980, 'end': 0x09FF }, // Bengali
14738 { 'begin': 0x0A00, 'end': 0x0A7F }, // Gurmukhi
14739 { 'begin': 0x0A80, 'end': 0x0AFF }, // Gujarati
14740 { 'begin': 0x0B00, 'end': 0x0B7F }, // Oriya
14741 { 'begin': 0x0B80, 'end': 0x0BFF }, // Tamil
14742 { 'begin': 0x0C00, 'end': 0x0C7F }, // Telugu
14743 { 'begin': 0x0C80, 'end': 0x0CFF }, // Kannada
14744 { 'begin': 0x0D00, 'end': 0x0D7F }, // Malayalam
14745 { 'begin': 0x0E00, 'end': 0x0E7F }, // Thai
14746 { 'begin': 0x0E80, 'end': 0x0EFF }, // Lao
14747 { 'begin': 0x10A0, 'end': 0x10FF }, // Georgian
14748 { 'begin': 0x1B00, 'end': 0x1B7F }, // Balinese
14749 { 'begin': 0x1100, 'end': 0x11FF }, // Hangul Jamo
14750 { 'begin': 0x1E00, 'end': 0x1EFF }, // Latin Extended Additional
14751 { 'begin': 0x1F00, 'end': 0x1FFF }, // Greek Extended
14752 { 'begin': 0x2000, 'end': 0x206F }, // General Punctuation
14753 { 'begin': 0x2070, 'end': 0x209F }, // Superscripts And Subscripts
14754 { 'begin': 0x20A0, 'end': 0x20CF }, // Currency Symbol
14755 { 'begin': 0x20D0, 'end': 0x20FF }, // Combining Diacritical Marks For Symbols
14756 { 'begin': 0x2100, 'end': 0x214F }, // Letterlike Symbols
14757 { 'begin': 0x2150, 'end': 0x218F }, // Number Forms
14758 { 'begin': 0x2190, 'end': 0x21FF }, // Arrows
14759 { 'begin': 0x2200, 'end': 0x22FF }, // Mathematical Operators
14760 { 'begin': 0x2300, 'end': 0x23FF }, // Miscellaneous Technical
14761 { 'begin': 0x2400, 'end': 0x243F }, // Control Pictures
14762 { 'begin': 0x2440, 'end': 0x245F }, // Optical Character Recognition
14763 { 'begin': 0x2460, 'end': 0x24FF }, // Enclosed Alphanumerics
14764 { 'begin': 0x2500, 'end': 0x257F }, // Box Drawing
14765 { 'begin': 0x2580, 'end': 0x259F }, // Block Elements
14766 { 'begin': 0x25A0, 'end': 0x25FF }, // Geometric Shapes
14767 { 'begin': 0x2600, 'end': 0x26FF }, // Miscellaneous Symbols
14768 { 'begin': 0x2700, 'end': 0x27BF }, // Dingbats
14769 { 'begin': 0x3000, 'end': 0x303F }, // CJK Symbols And Punctuation
14770 { 'begin': 0x3040, 'end': 0x309F }, // Hiragana
14771 { 'begin': 0x30A0, 'end': 0x30FF }, // Katakana
14772 { 'begin': 0x3100, 'end': 0x312F }, // Bopomofo
14773 { 'begin': 0x3130, 'end': 0x318F }, // Hangul Compatibility Jamo
14774 { 'begin': 0xA840, 'end': 0xA87F }, // Phags-pa
14775 { 'begin': 0x3200, 'end': 0x32FF }, // Enclosed CJK Letters And Months
14776 { 'begin': 0x3300, 'end': 0x33FF }, // CJK Compatibility
14777 { 'begin': 0xAC00, 'end': 0xD7AF }, // Hangul Syllables
14778 { 'begin': 0xD800, 'end': 0xDFFF }, // Non-Plane 0 *
14779 { 'begin': 0x10900, 'end': 0x1091F }, // Phoenicia
14780 { 'begin': 0x4E00, 'end': 0x9FFF }, // CJK Unified Ideographs
14781 { 'begin': 0xE000, 'end': 0xF8FF }, // Private Use Area (plane 0)
14782 { 'begin': 0x31C0, 'end': 0x31EF }, // CJK Strokes
14783 { 'begin': 0xFB00, 'end': 0xFB4F }, // Alphabetic Presentation Forms
14784 { 'begin': 0xFB50, 'end': 0xFDFF }, // Arabic Presentation Forms-A
14785 { 'begin': 0xFE20, 'end': 0xFE2F }, // Combining Half Marks
14786 { 'begin': 0xFE10, 'end': 0xFE1F }, // Vertical Forms
14787 { 'begin': 0xFE50, 'end': 0xFE6F }, // Small Form Variants
14788 { 'begin': 0xFE70, 'end': 0xFEFF }, // Arabic Presentation Forms-B
14789 { 'begin': 0xFF00, 'end': 0xFFEF }, // Halfwidth And Fullwidth Forms
14790 { 'begin': 0xFFF0, 'end': 0xFFFF }, // Specials
14791 { 'begin': 0x0F00, 'end': 0x0FFF }, // Tibetan
14792 { 'begin': 0x0700, 'end': 0x074F }, // Syriac
14793 { 'begin': 0x0780, 'end': 0x07BF }, // Thaana
14794 { 'begin': 0x0D80, 'end': 0x0DFF }, // Sinhala
14795 { 'begin': 0x1000, 'end': 0x109F }, // Myanmar
14796 { 'begin': 0x1200, 'end': 0x137F }, // Ethiopic
14797 { 'begin': 0x13A0, 'end': 0x13FF }, // Cherokee
14798 { 'begin': 0x1400, 'end': 0x167F }, // Unified Canadian Aboriginal Syllabics
14799 { 'begin': 0x1680, 'end': 0x169F }, // Ogham
14800 { 'begin': 0x16A0, 'end': 0x16FF }, // Runic
14801 { 'begin': 0x1780, 'end': 0x17FF }, // Khmer
14802 { 'begin': 0x1800, 'end': 0x18AF }, // Mongolian
14803 { 'begin': 0x2800, 'end': 0x28FF }, // Braille Patterns
14804 { 'begin': 0xA000, 'end': 0xA48F }, // Yi Syllables
14805 { 'begin': 0x1700, 'end': 0x171F }, // Tagalog
14806 { 'begin': 0x10300, 'end': 0x1032F }, // Old Italic
14807 { 'begin': 0x10330, 'end': 0x1034F }, // Gothic
14808 { 'begin': 0x10400, 'end': 0x1044F }, // Deseret
14809 { 'begin': 0x1D000, 'end': 0x1D0FF }, // Byzantine Musical Symbols
14810 { 'begin': 0x1D400, 'end': 0x1D7FF }, // Mathematical Alphanumeric Symbols
14811 { 'begin': 0xFF000, 'end': 0xFFFFD }, // Private Use (plane 15)
14812 { 'begin': 0xFE00, 'end': 0xFE0F }, // Variation Selectors
14813 { 'begin': 0xE0000, 'end': 0xE007F }, // Tags
14814 { 'begin': 0x1900, 'end': 0x194F }, // Limbu
14815 { 'begin': 0x1950, 'end': 0x197F }, // Tai Le
14816 { 'begin': 0x1980, 'end': 0x19DF }, // New Tai Lue
14817 { 'begin': 0x1A00, 'end': 0x1A1F }, // Buginese
14818 { 'begin': 0x2C00, 'end': 0x2C5F }, // Glagolitic
14819 { 'begin': 0x2D30, 'end': 0x2D7F }, // Tifinagh
14820 { 'begin': 0x4DC0, 'end': 0x4DFF }, // Yijing Hexagram Symbols
14821 { 'begin': 0xA800, 'end': 0xA82F }, // Syloti Nagri
14822 { 'begin': 0x10000, 'end': 0x1007F }, // Linear B Syllabary
14823 { 'begin': 0x10140, 'end': 0x1018F }, // Ancient Greek Numbers
14824 { 'begin': 0x10380, 'end': 0x1039F }, // Ugaritic
14825 { 'begin': 0x103A0, 'end': 0x103DF }, // Old Persian
14826 { 'begin': 0x10450, 'end': 0x1047F }, // Shavian
14827 { 'begin': 0x10480, 'end': 0x104AF }, // Osmanya
14828 { 'begin': 0x10800, 'end': 0x1083F }, // Cypriot Syllabary
14829 { 'begin': 0x10A00, 'end': 0x10A5F }, // Kharoshthi
14830 { 'begin': 0x1D300, 'end': 0x1D35F }, // Tai Xuan Jing Symbols
14831 { 'begin': 0x12000, 'end': 0x123FF }, // Cuneiform
14832 { 'begin': 0x1D360, 'end': 0x1D37F }, // Counting Rod Numerals
14833 { 'begin': 0x1B80, 'end': 0x1BBF }, // Sundanese
14834 { 'begin': 0x1C00, 'end': 0x1C4F }, // Lepcha
14835 { 'begin': 0x1C50, 'end': 0x1C7F }, // Ol Chiki
14836 { 'begin': 0xA880, 'end': 0xA8DF }, // Saurashtra
14837 { 'begin': 0xA900, 'end': 0xA92F }, // Kayah Li
14838 { 'begin': 0xA930, 'end': 0xA95F }, // Rejang
14839 { 'begin': 0xAA00, 'end': 0xAA5F }, // Cham
14840 { 'begin': 0x10190, 'end': 0x101CF }, // Ancient Symbols
14841 { 'begin': 0x101D0, 'end': 0x101FF }, // Phaistos Disc
14842 { 'begin': 0x102A0, 'end': 0x102DF }, // Carian
14843 { 'begin': 0x1F030, 'end': 0x1F09F } // Domino Tiles
14844 ];
14845
14846 var MacStandardGlyphOrdering = [
14847 '.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl',
14848 'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft',
14849 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash',
14850 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
14851 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at',
14852 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
14853 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft',
14854 'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b',
14855 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
14856 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright',
14857 'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde',
14858 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis',
14859 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
14860 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve',
14861 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex',
14862 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet',
14863 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute',
14864 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal',
14865 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi',
14866 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash',
14867 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin',
14868 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis',
14869 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash',
14870 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright',
14871 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency',
14872 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered',
14873 'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex',
14874 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex',
14875 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute',
14876 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron',
14877 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron',
14878 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar',
14879 'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply',
14880 'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter',
14881 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla',
14882 'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat'];
14883
14884 function getUnicodeRangeFor(value) {
14885 for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) {
14886 var range = UnicodeRanges[i];
14887 if (value >= range.begin && value < range.end) {
14888 return i;
14889 }
14890 }
14891 return -1;
14892 }
14893
14894 function isRTLRangeFor(value) {
14895 var range = UnicodeRanges[13];
14896 if (value >= range.begin && value < range.end) {
14897 return true;
14898 }
14899 range = UnicodeRanges[11];
14900 if (value >= range.begin && value < range.end) {
14901 return true;
14902 }
14903 return false;
14904 }
14905
14906 // The normalization table is obtained by filtering the Unicode characters
14907 // database with <compat> entries.
14908 var NormalizedUnicodes = {
14909 '\u00A8': '\u0020\u0308',
14910 '\u00AF': '\u0020\u0304',
14911 '\u00B4': '\u0020\u0301',
14912 '\u00B5': '\u03BC',
14913 '\u00B8': '\u0020\u0327',
14914 '\u0132': '\u0049\u004A',
14915 '\u0133': '\u0069\u006A',
14916 '\u013F': '\u004C\u00B7',
14917 '\u0140': '\u006C\u00B7',
14918 '\u0149': '\u02BC\u006E',
14919 '\u017F': '\u0073',
14920 '\u01C4': '\u0044\u017D',
14921 '\u01C5': '\u0044\u017E',
14922 '\u01C6': '\u0064\u017E',
14923 '\u01C7': '\u004C\u004A',
14924 '\u01C8': '\u004C\u006A',
14925 '\u01C9': '\u006C\u006A',
14926 '\u01CA': '\u004E\u004A',
14927 '\u01CB': '\u004E\u006A',
14928 '\u01CC': '\u006E\u006A',
14929 '\u01F1': '\u0044\u005A',
14930 '\u01F2': '\u0044\u007A',
14931 '\u01F3': '\u0064\u007A',
14932 '\u02D8': '\u0020\u0306',
14933 '\u02D9': '\u0020\u0307',
14934 '\u02DA': '\u0020\u030A',
14935 '\u02DB': '\u0020\u0328',
14936 '\u02DC': '\u0020\u0303',
14937 '\u02DD': '\u0020\u030B',
14938 '\u037A': '\u0020\u0345',
14939 '\u0384': '\u0020\u0301',
14940 '\u03D0': '\u03B2',
14941 '\u03D1': '\u03B8',
14942 '\u03D2': '\u03A5',
14943 '\u03D5': '\u03C6',
14944 '\u03D6': '\u03C0',
14945 '\u03F0': '\u03BA',
14946 '\u03F1': '\u03C1',
14947 '\u03F2': '\u03C2',
14948 '\u03F4': '\u0398',
14949 '\u03F5': '\u03B5',
14950 '\u03F9': '\u03A3',
14951 '\u0587': '\u0565\u0582',
14952 '\u0675': '\u0627\u0674',
14953 '\u0676': '\u0648\u0674',
14954 '\u0677': '\u06C7\u0674',
14955 '\u0678': '\u064A\u0674',
14956 '\u0E33': '\u0E4D\u0E32',
14957 '\u0EB3': '\u0ECD\u0EB2',
14958 '\u0EDC': '\u0EAB\u0E99',
14959 '\u0EDD': '\u0EAB\u0EA1',
14960 '\u0F77': '\u0FB2\u0F81',
14961 '\u0F79': '\u0FB3\u0F81',
14962 '\u1E9A': '\u0061\u02BE',
14963 '\u1FBD': '\u0020\u0313',
14964 '\u1FBF': '\u0020\u0313',
14965 '\u1FC0': '\u0020\u0342',
14966 '\u1FFE': '\u0020\u0314',
14967 '\u2002': '\u0020',
14968 '\u2003': '\u0020',
14969 '\u2004': '\u0020',
14970 '\u2005': '\u0020',
14971 '\u2006': '\u0020',
14972 '\u2008': '\u0020',
14973 '\u2009': '\u0020',
14974 '\u200A': '\u0020',
14975 '\u2017': '\u0020\u0333',
14976 '\u2024': '\u002E',
14977 '\u2025': '\u002E\u002E',
14978 '\u2026': '\u002E\u002E\u002E',
14979 '\u2033': '\u2032\u2032',
14980 '\u2034': '\u2032\u2032\u2032',
14981 '\u2036': '\u2035\u2035',
14982 '\u2037': '\u2035\u2035\u2035',
14983 '\u203C': '\u0021\u0021',
14984 '\u203E': '\u0020\u0305',
14985 '\u2047': '\u003F\u003F',
14986 '\u2048': '\u003F\u0021',
14987 '\u2049': '\u0021\u003F',
14988 '\u2057': '\u2032\u2032\u2032\u2032',
14989 '\u205F': '\u0020',
14990 '\u20A8': '\u0052\u0073',
14991 '\u2100': '\u0061\u002F\u0063',
14992 '\u2101': '\u0061\u002F\u0073',
14993 '\u2103': '\u00B0\u0043',
14994 '\u2105': '\u0063\u002F\u006F',
14995 '\u2106': '\u0063\u002F\u0075',
14996 '\u2107': '\u0190',
14997 '\u2109': '\u00B0\u0046',
14998 '\u2116': '\u004E\u006F',
14999 '\u2121': '\u0054\u0045\u004C',
15000 '\u2135': '\u05D0',
15001 '\u2136': '\u05D1',
15002 '\u2137': '\u05D2',
15003 '\u2138': '\u05D3',
15004 '\u213B': '\u0046\u0041\u0058',
15005 '\u2160': '\u0049',
15006 '\u2161': '\u0049\u0049',
15007 '\u2162': '\u0049\u0049\u0049',
15008 '\u2163': '\u0049\u0056',
15009 '\u2164': '\u0056',
15010 '\u2165': '\u0056\u0049',
15011 '\u2166': '\u0056\u0049\u0049',
15012 '\u2167': '\u0056\u0049\u0049\u0049',
15013 '\u2168': '\u0049\u0058',
15014 '\u2169': '\u0058',
15015 '\u216A': '\u0058\u0049',
15016 '\u216B': '\u0058\u0049\u0049',
15017 '\u216C': '\u004C',
15018 '\u216D': '\u0043',
15019 '\u216E': '\u0044',
15020 '\u216F': '\u004D',
15021 '\u2170': '\u0069',
15022 '\u2171': '\u0069\u0069',
15023 '\u2172': '\u0069\u0069\u0069',
15024 '\u2173': '\u0069\u0076',
15025 '\u2174': '\u0076',
15026 '\u2175': '\u0076\u0069',
15027 '\u2176': '\u0076\u0069\u0069',
15028 '\u2177': '\u0076\u0069\u0069\u0069',
15029 '\u2178': '\u0069\u0078',
15030 '\u2179': '\u0078',
15031 '\u217A': '\u0078\u0069',
15032 '\u217B': '\u0078\u0069\u0069',
15033 '\u217C': '\u006C',
15034 '\u217D': '\u0063',
15035 '\u217E': '\u0064',
15036 '\u217F': '\u006D',
15037 '\u222C': '\u222B\u222B',
15038 '\u222D': '\u222B\u222B\u222B',
15039 '\u222F': '\u222E\u222E',
15040 '\u2230': '\u222E\u222E\u222E',
15041 '\u2474': '\u0028\u0031\u0029',
15042 '\u2475': '\u0028\u0032\u0029',
15043 '\u2476': '\u0028\u0033\u0029',
15044 '\u2477': '\u0028\u0034\u0029',
15045 '\u2478': '\u0028\u0035\u0029',
15046 '\u2479': '\u0028\u0036\u0029',
15047 '\u247A': '\u0028\u0037\u0029',
15048 '\u247B': '\u0028\u0038\u0029',
15049 '\u247C': '\u0028\u0039\u0029',
15050 '\u247D': '\u0028\u0031\u0030\u0029',
15051 '\u247E': '\u0028\u0031\u0031\u0029',
15052 '\u247F': '\u0028\u0031\u0032\u0029',
15053 '\u2480': '\u0028\u0031\u0033\u0029',
15054 '\u2481': '\u0028\u0031\u0034\u0029',
15055 '\u2482': '\u0028\u0031\u0035\u0029',
15056 '\u2483': '\u0028\u0031\u0036\u0029',
15057 '\u2484': '\u0028\u0031\u0037\u0029',
15058 '\u2485': '\u0028\u0031\u0038\u0029',
15059 '\u2486': '\u0028\u0031\u0039\u0029',
15060 '\u2487': '\u0028\u0032\u0030\u0029',
15061 '\u2488': '\u0031\u002E',
15062 '\u2489': '\u0032\u002E',
15063 '\u248A': '\u0033\u002E',
15064 '\u248B': '\u0034\u002E',
15065 '\u248C': '\u0035\u002E',
15066 '\u248D': '\u0036\u002E',
15067 '\u248E': '\u0037\u002E',
15068 '\u248F': '\u0038\u002E',
15069 '\u2490': '\u0039\u002E',
15070 '\u2491': '\u0031\u0030\u002E',
15071 '\u2492': '\u0031\u0031\u002E',
15072 '\u2493': '\u0031\u0032\u002E',
15073 '\u2494': '\u0031\u0033\u002E',
15074 '\u2495': '\u0031\u0034\u002E',
15075 '\u2496': '\u0031\u0035\u002E',
15076 '\u2497': '\u0031\u0036\u002E',
15077 '\u2498': '\u0031\u0037\u002E',
15078 '\u2499': '\u0031\u0038\u002E',
15079 '\u249A': '\u0031\u0039\u002E',
15080 '\u249B': '\u0032\u0030\u002E',
15081 '\u249C': '\u0028\u0061\u0029',
15082 '\u249D': '\u0028\u0062\u0029',
15083 '\u249E': '\u0028\u0063\u0029',
15084 '\u249F': '\u0028\u0064\u0029',
15085 '\u24A0': '\u0028\u0065\u0029',
15086 '\u24A1': '\u0028\u0066\u0029',
15087 '\u24A2': '\u0028\u0067\u0029',
15088 '\u24A3': '\u0028\u0068\u0029',
15089 '\u24A4': '\u0028\u0069\u0029',
15090 '\u24A5': '\u0028\u006A\u0029',
15091 '\u24A6': '\u0028\u006B\u0029',
15092 '\u24A7': '\u0028\u006C\u0029',
15093 '\u24A8': '\u0028\u006D\u0029',
15094 '\u24A9': '\u0028\u006E\u0029',
15095 '\u24AA': '\u0028\u006F\u0029',
15096 '\u24AB': '\u0028\u0070\u0029',
15097 '\u24AC': '\u0028\u0071\u0029',
15098 '\u24AD': '\u0028\u0072\u0029',
15099 '\u24AE': '\u0028\u0073\u0029',
15100 '\u24AF': '\u0028\u0074\u0029',
15101 '\u24B0': '\u0028\u0075\u0029',
15102 '\u24B1': '\u0028\u0076\u0029',
15103 '\u24B2': '\u0028\u0077\u0029',
15104 '\u24B3': '\u0028\u0078\u0029',
15105 '\u24B4': '\u0028\u0079\u0029',
15106 '\u24B5': '\u0028\u007A\u0029',
15107 '\u2A0C': '\u222B\u222B\u222B\u222B',
15108 '\u2A74': '\u003A\u003A\u003D',
15109 '\u2A75': '\u003D\u003D',
15110 '\u2A76': '\u003D\u003D\u003D',
15111 '\u2E9F': '\u6BCD',
15112 '\u2EF3': '\u9F9F',
15113 '\u2F00': '\u4E00',
15114 '\u2F01': '\u4E28',
15115 '\u2F02': '\u4E36',
15116 '\u2F03': '\u4E3F',
15117 '\u2F04': '\u4E59',
15118 '\u2F05': '\u4E85',
15119 '\u2F06': '\u4E8C',
15120 '\u2F07': '\u4EA0',
15121 '\u2F08': '\u4EBA',
15122 '\u2F09': '\u513F',
15123 '\u2F0A': '\u5165',
15124 '\u2F0B': '\u516B',
15125 '\u2F0C': '\u5182',
15126 '\u2F0D': '\u5196',
15127 '\u2F0E': '\u51AB',
15128 '\u2F0F': '\u51E0',
15129 '\u2F10': '\u51F5',
15130 '\u2F11': '\u5200',
15131 '\u2F12': '\u529B',
15132 '\u2F13': '\u52F9',
15133 '\u2F14': '\u5315',
15134 '\u2F15': '\u531A',
15135 '\u2F16': '\u5338',
15136 '\u2F17': '\u5341',
15137 '\u2F18': '\u535C',
15138 '\u2F19': '\u5369',
15139 '\u2F1A': '\u5382',
15140 '\u2F1B': '\u53B6',
15141 '\u2F1C': '\u53C8',
15142 '\u2F1D': '\u53E3',
15143 '\u2F1E': '\u56D7',
15144 '\u2F1F': '\u571F',
15145 '\u2F20': '\u58EB',
15146 '\u2F21': '\u5902',
15147 '\u2F22': '\u590A',
15148 '\u2F23': '\u5915',
15149 '\u2F24': '\u5927',
15150 '\u2F25': '\u5973',
15151 '\u2F26': '\u5B50',
15152 '\u2F27': '\u5B80',
15153 '\u2F28': '\u5BF8',
15154 '\u2F29': '\u5C0F',
15155 '\u2F2A': '\u5C22',
15156 '\u2F2B': '\u5C38',
15157 '\u2F2C': '\u5C6E',
15158 '\u2F2D': '\u5C71',
15159 '\u2F2E': '\u5DDB',
15160 '\u2F2F': '\u5DE5',
15161 '\u2F30': '\u5DF1',
15162 '\u2F31': '\u5DFE',
15163 '\u2F32': '\u5E72',
15164 '\u2F33': '\u5E7A',
15165 '\u2F34': '\u5E7F',
15166 '\u2F35': '\u5EF4',
15167 '\u2F36': '\u5EFE',
15168 '\u2F37': '\u5F0B',
15169 '\u2F38': '\u5F13',
15170 '\u2F39': '\u5F50',
15171 '\u2F3A': '\u5F61',
15172 '\u2F3B': '\u5F73',
15173 '\u2F3C': '\u5FC3',
15174 '\u2F3D': '\u6208',
15175 '\u2F3E': '\u6236',
15176 '\u2F3F': '\u624B',
15177 '\u2F40': '\u652F',
15178 '\u2F41': '\u6534',
15179 '\u2F42': '\u6587',
15180 '\u2F43': '\u6597',
15181 '\u2F44': '\u65A4',
15182 '\u2F45': '\u65B9',
15183 '\u2F46': '\u65E0',
15184 '\u2F47': '\u65E5',
15185 '\u2F48': '\u66F0',
15186 '\u2F49': '\u6708',
15187 '\u2F4A': '\u6728',
15188 '\u2F4B': '\u6B20',
15189 '\u2F4C': '\u6B62',
15190 '\u2F4D': '\u6B79',
15191 '\u2F4E': '\u6BB3',
15192 '\u2F4F': '\u6BCB',
15193 '\u2F50': '\u6BD4',
15194 '\u2F51': '\u6BDB',
15195 '\u2F52': '\u6C0F',
15196 '\u2F53': '\u6C14',
15197 '\u2F54': '\u6C34',
15198 '\u2F55': '\u706B',
15199 '\u2F56': '\u722A',
15200 '\u2F57': '\u7236',
15201 '\u2F58': '\u723B',
15202 '\u2F59': '\u723F',
15203 '\u2F5A': '\u7247',
15204 '\u2F5B': '\u7259',
15205 '\u2F5C': '\u725B',
15206 '\u2F5D': '\u72AC',
15207 '\u2F5E': '\u7384',
15208 '\u2F5F': '\u7389',
15209 '\u2F60': '\u74DC',
15210 '\u2F61': '\u74E6',
15211 '\u2F62': '\u7518',
15212 '\u2F63': '\u751F',
15213 '\u2F64': '\u7528',
15214 '\u2F65': '\u7530',
15215 '\u2F66': '\u758B',
15216 '\u2F67': '\u7592',
15217 '\u2F68': '\u7676',
15218 '\u2F69': '\u767D',
15219 '\u2F6A': '\u76AE',
15220 '\u2F6B': '\u76BF',
15221 '\u2F6C': '\u76EE',
15222 '\u2F6D': '\u77DB',
15223 '\u2F6E': '\u77E2',
15224 '\u2F6F': '\u77F3',
15225 '\u2F70': '\u793A',
15226 '\u2F71': '\u79B8',
15227 '\u2F72': '\u79BE',
15228 '\u2F73': '\u7A74',
15229 '\u2F74': '\u7ACB',
15230 '\u2F75': '\u7AF9',
15231 '\u2F76': '\u7C73',
15232 '\u2F77': '\u7CF8',
15233 '\u2F78': '\u7F36',
15234 '\u2F79': '\u7F51',
15235 '\u2F7A': '\u7F8A',
15236 '\u2F7B': '\u7FBD',
15237 '\u2F7C': '\u8001',
15238 '\u2F7D': '\u800C',
15239 '\u2F7E': '\u8012',
15240 '\u2F7F': '\u8033',
15241 '\u2F80': '\u807F',
15242 '\u2F81': '\u8089',
15243 '\u2F82': '\u81E3',
15244 '\u2F83': '\u81EA',
15245 '\u2F84': '\u81F3',
15246 '\u2F85': '\u81FC',
15247 '\u2F86': '\u820C',
15248 '\u2F87': '\u821B',
15249 '\u2F88': '\u821F',
15250 '\u2F89': '\u826E',
15251 '\u2F8A': '\u8272',
15252 '\u2F8B': '\u8278',
15253 '\u2F8C': '\u864D',
15254 '\u2F8D': '\u866B',
15255 '\u2F8E': '\u8840',
15256 '\u2F8F': '\u884C',
15257 '\u2F90': '\u8863',
15258 '\u2F91': '\u897E',
15259 '\u2F92': '\u898B',
15260 '\u2F93': '\u89D2',
15261 '\u2F94': '\u8A00',
15262 '\u2F95': '\u8C37',
15263 '\u2F96': '\u8C46',
15264 '\u2F97': '\u8C55',
15265 '\u2F98': '\u8C78',
15266 '\u2F99': '\u8C9D',
15267 '\u2F9A': '\u8D64',
15268 '\u2F9B': '\u8D70',
15269 '\u2F9C': '\u8DB3',
15270 '\u2F9D': '\u8EAB',
15271 '\u2F9E': '\u8ECA',
15272 '\u2F9F': '\u8F9B',
15273 '\u2FA0': '\u8FB0',
15274 '\u2FA1': '\u8FB5',
15275 '\u2FA2': '\u9091',
15276 '\u2FA3': '\u9149',
15277 '\u2FA4': '\u91C6',
15278 '\u2FA5': '\u91CC',
15279 '\u2FA6': '\u91D1',
15280 '\u2FA7': '\u9577',
15281 '\u2FA8': '\u9580',
15282 '\u2FA9': '\u961C',
15283 '\u2FAA': '\u96B6',
15284 '\u2FAB': '\u96B9',
15285 '\u2FAC': '\u96E8',
15286 '\u2FAD': '\u9751',
15287 '\u2FAE': '\u975E',
15288 '\u2FAF': '\u9762',
15289 '\u2FB0': '\u9769',
15290 '\u2FB1': '\u97CB',
15291 '\u2FB2': '\u97ED',
15292 '\u2FB3': '\u97F3',
15293 '\u2FB4': '\u9801',
15294 '\u2FB5': '\u98A8',
15295 '\u2FB6': '\u98DB',
15296 '\u2FB7': '\u98DF',
15297 '\u2FB8': '\u9996',
15298 '\u2FB9': '\u9999',
15299 '\u2FBA': '\u99AC',
15300 '\u2FBB': '\u9AA8',
15301 '\u2FBC': '\u9AD8',
15302 '\u2FBD': '\u9ADF',
15303 '\u2FBE': '\u9B25',
15304 '\u2FBF': '\u9B2F',
15305 '\u2FC0': '\u9B32',
15306 '\u2FC1': '\u9B3C',
15307 '\u2FC2': '\u9B5A',
15308 '\u2FC3': '\u9CE5',
15309 '\u2FC4': '\u9E75',
15310 '\u2FC5': '\u9E7F',
15311 '\u2FC6': '\u9EA5',
15312 '\u2FC7': '\u9EBB',
15313 '\u2FC8': '\u9EC3',
15314 '\u2FC9': '\u9ECD',
15315 '\u2FCA': '\u9ED1',
15316 '\u2FCB': '\u9EF9',
15317 '\u2FCC': '\u9EFD',
15318 '\u2FCD': '\u9F0E',
15319 '\u2FCE': '\u9F13',
15320 '\u2FCF': '\u9F20',
15321 '\u2FD0': '\u9F3B',
15322 '\u2FD1': '\u9F4A',
15323 '\u2FD2': '\u9F52',
15324 '\u2FD3': '\u9F8D',
15325 '\u2FD4': '\u9F9C',
15326 '\u2FD5': '\u9FA0',
15327 '\u3036': '\u3012',
15328 '\u3038': '\u5341',
15329 '\u3039': '\u5344',
15330 '\u303A': '\u5345',
15331 '\u309B': '\u0020\u3099',
15332 '\u309C': '\u0020\u309A',
15333 '\u3131': '\u1100',
15334 '\u3132': '\u1101',
15335 '\u3133': '\u11AA',
15336 '\u3134': '\u1102',
15337 '\u3135': '\u11AC',
15338 '\u3136': '\u11AD',
15339 '\u3137': '\u1103',
15340 '\u3138': '\u1104',
15341 '\u3139': '\u1105',
15342 '\u313A': '\u11B0',
15343 '\u313B': '\u11B1',
15344 '\u313C': '\u11B2',
15345 '\u313D': '\u11B3',
15346 '\u313E': '\u11B4',
15347 '\u313F': '\u11B5',
15348 '\u3140': '\u111A',
15349 '\u3141': '\u1106',
15350 '\u3142': '\u1107',
15351 '\u3143': '\u1108',
15352 '\u3144': '\u1121',
15353 '\u3145': '\u1109',
15354 '\u3146': '\u110A',
15355 '\u3147': '\u110B',
15356 '\u3148': '\u110C',
15357 '\u3149': '\u110D',
15358 '\u314A': '\u110E',
15359 '\u314B': '\u110F',
15360 '\u314C': '\u1110',
15361 '\u314D': '\u1111',
15362 '\u314E': '\u1112',
15363 '\u314F': '\u1161',
15364 '\u3150': '\u1162',
15365 '\u3151': '\u1163',
15366 '\u3152': '\u1164',
15367 '\u3153': '\u1165',
15368 '\u3154': '\u1166',
15369 '\u3155': '\u1167',
15370 '\u3156': '\u1168',
15371 '\u3157': '\u1169',
15372 '\u3158': '\u116A',
15373 '\u3159': '\u116B',
15374 '\u315A': '\u116C',
15375 '\u315B': '\u116D',
15376 '\u315C': '\u116E',
15377 '\u315D': '\u116F',
15378 '\u315E': '\u1170',
15379 '\u315F': '\u1171',
15380 '\u3160': '\u1172',
15381 '\u3161': '\u1173',
15382 '\u3162': '\u1174',
15383 '\u3163': '\u1175',
15384 '\u3164': '\u1160',
15385 '\u3165': '\u1114',
15386 '\u3166': '\u1115',
15387 '\u3167': '\u11C7',
15388 '\u3168': '\u11C8',
15389 '\u3169': '\u11CC',
15390 '\u316A': '\u11CE',
15391 '\u316B': '\u11D3',
15392 '\u316C': '\u11D7',
15393 '\u316D': '\u11D9',
15394 '\u316E': '\u111C',
15395 '\u316F': '\u11DD',
15396 '\u3170': '\u11DF',
15397 '\u3171': '\u111D',
15398 '\u3172': '\u111E',
15399 '\u3173': '\u1120',
15400 '\u3174': '\u1122',
15401 '\u3175': '\u1123',
15402 '\u3176': '\u1127',
15403 '\u3177': '\u1129',
15404 '\u3178': '\u112B',
15405 '\u3179': '\u112C',
15406 '\u317A': '\u112D',
15407 '\u317B': '\u112E',
15408 '\u317C': '\u112F',
15409 '\u317D': '\u1132',
15410 '\u317E': '\u1136',
15411 '\u317F': '\u1140',
15412 '\u3180': '\u1147',
15413 '\u3181': '\u114C',
15414 '\u3182': '\u11F1',
15415 '\u3183': '\u11F2',
15416 '\u3184': '\u1157',
15417 '\u3185': '\u1158',
15418 '\u3186': '\u1159',
15419 '\u3187': '\u1184',
15420 '\u3188': '\u1185',
15421 '\u3189': '\u1188',
15422 '\u318A': '\u1191',
15423 '\u318B': '\u1192',
15424 '\u318C': '\u1194',
15425 '\u318D': '\u119E',
15426 '\u318E': '\u11A1',
15427 '\u3200': '\u0028\u1100\u0029',
15428 '\u3201': '\u0028\u1102\u0029',
15429 '\u3202': '\u0028\u1103\u0029',
15430 '\u3203': '\u0028\u1105\u0029',
15431 '\u3204': '\u0028\u1106\u0029',
15432 '\u3205': '\u0028\u1107\u0029',
15433 '\u3206': '\u0028\u1109\u0029',
15434 '\u3207': '\u0028\u110B\u0029',
15435 '\u3208': '\u0028\u110C\u0029',
15436 '\u3209': '\u0028\u110E\u0029',
15437 '\u320A': '\u0028\u110F\u0029',
15438 '\u320B': '\u0028\u1110\u0029',
15439 '\u320C': '\u0028\u1111\u0029',
15440 '\u320D': '\u0028\u1112\u0029',
15441 '\u320E': '\u0028\u1100\u1161\u0029',
15442 '\u320F': '\u0028\u1102\u1161\u0029',
15443 '\u3210': '\u0028\u1103\u1161\u0029',
15444 '\u3211': '\u0028\u1105\u1161\u0029',
15445 '\u3212': '\u0028\u1106\u1161\u0029',
15446 '\u3213': '\u0028\u1107\u1161\u0029',
15447 '\u3214': '\u0028\u1109\u1161\u0029',
15448 '\u3215': '\u0028\u110B\u1161\u0029',
15449 '\u3216': '\u0028\u110C\u1161\u0029',
15450 '\u3217': '\u0028\u110E\u1161\u0029',
15451 '\u3218': '\u0028\u110F\u1161\u0029',
15452 '\u3219': '\u0028\u1110\u1161\u0029',
15453 '\u321A': '\u0028\u1111\u1161\u0029',
15454 '\u321B': '\u0028\u1112\u1161\u0029',
15455 '\u321C': '\u0028\u110C\u116E\u0029',
15456 '\u321D': '\u0028\u110B\u1169\u110C\u1165\u11AB\u0029',
15457 '\u321E': '\u0028\u110B\u1169\u1112\u116E\u0029',
15458 '\u3220': '\u0028\u4E00\u0029',
15459 '\u3221': '\u0028\u4E8C\u0029',
15460 '\u3222': '\u0028\u4E09\u0029',
15461 '\u3223': '\u0028\u56DB\u0029',
15462 '\u3224': '\u0028\u4E94\u0029',
15463 '\u3225': '\u0028\u516D\u0029',
15464 '\u3226': '\u0028\u4E03\u0029',
15465 '\u3227': '\u0028\u516B\u0029',
15466 '\u3228': '\u0028\u4E5D\u0029',
15467 '\u3229': '\u0028\u5341\u0029',
15468 '\u322A': '\u0028\u6708\u0029',
15469 '\u322B': '\u0028\u706B\u0029',
15470 '\u322C': '\u0028\u6C34\u0029',
15471 '\u322D': '\u0028\u6728\u0029',
15472 '\u322E': '\u0028\u91D1\u0029',
15473 '\u322F': '\u0028\u571F\u0029',
15474 '\u3230': '\u0028\u65E5\u0029',
15475 '\u3231': '\u0028\u682A\u0029',
15476 '\u3232': '\u0028\u6709\u0029',
15477 '\u3233': '\u0028\u793E\u0029',
15478 '\u3234': '\u0028\u540D\u0029',
15479 '\u3235': '\u0028\u7279\u0029',
15480 '\u3236': '\u0028\u8CA1\u0029',
15481 '\u3237': '\u0028\u795D\u0029',
15482 '\u3238': '\u0028\u52B4\u0029',
15483 '\u3239': '\u0028\u4EE3\u0029',
15484 '\u323A': '\u0028\u547C\u0029',
15485 '\u323B': '\u0028\u5B66\u0029',
15486 '\u323C': '\u0028\u76E3\u0029',
15487 '\u323D': '\u0028\u4F01\u0029',
15488 '\u323E': '\u0028\u8CC7\u0029',
15489 '\u323F': '\u0028\u5354\u0029',
15490 '\u3240': '\u0028\u796D\u0029',
15491 '\u3241': '\u0028\u4F11\u0029',
15492 '\u3242': '\u0028\u81EA\u0029',
15493 '\u3243': '\u0028\u81F3\u0029',
15494 '\u32C0': '\u0031\u6708',
15495 '\u32C1': '\u0032\u6708',
15496 '\u32C2': '\u0033\u6708',
15497 '\u32C3': '\u0034\u6708',
15498 '\u32C4': '\u0035\u6708',
15499 '\u32C5': '\u0036\u6708',
15500 '\u32C6': '\u0037\u6708',
15501 '\u32C7': '\u0038\u6708',
15502 '\u32C8': '\u0039\u6708',
15503 '\u32C9': '\u0031\u0030\u6708',
15504 '\u32CA': '\u0031\u0031\u6708',
15505 '\u32CB': '\u0031\u0032\u6708',
15506 '\u3358': '\u0030\u70B9',
15507 '\u3359': '\u0031\u70B9',
15508 '\u335A': '\u0032\u70B9',
15509 '\u335B': '\u0033\u70B9',
15510 '\u335C': '\u0034\u70B9',
15511 '\u335D': '\u0035\u70B9',
15512 '\u335E': '\u0036\u70B9',
15513 '\u335F': '\u0037\u70B9',
15514 '\u3360': '\u0038\u70B9',
15515 '\u3361': '\u0039\u70B9',
15516 '\u3362': '\u0031\u0030\u70B9',
15517 '\u3363': '\u0031\u0031\u70B9',
15518 '\u3364': '\u0031\u0032\u70B9',
15519 '\u3365': '\u0031\u0033\u70B9',
15520 '\u3366': '\u0031\u0034\u70B9',
15521 '\u3367': '\u0031\u0035\u70B9',
15522 '\u3368': '\u0031\u0036\u70B9',
15523 '\u3369': '\u0031\u0037\u70B9',
15524 '\u336A': '\u0031\u0038\u70B9',
15525 '\u336B': '\u0031\u0039\u70B9',
15526 '\u336C': '\u0032\u0030\u70B9',
15527 '\u336D': '\u0032\u0031\u70B9',
15528 '\u336E': '\u0032\u0032\u70B9',
15529 '\u336F': '\u0032\u0033\u70B9',
15530 '\u3370': '\u0032\u0034\u70B9',
15531 '\u33E0': '\u0031\u65E5',
15532 '\u33E1': '\u0032\u65E5',
15533 '\u33E2': '\u0033\u65E5',
15534 '\u33E3': '\u0034\u65E5',
15535 '\u33E4': '\u0035\u65E5',
15536 '\u33E5': '\u0036\u65E5',
15537 '\u33E6': '\u0037\u65E5',
15538 '\u33E7': '\u0038\u65E5',
15539 '\u33E8': '\u0039\u65E5',
15540 '\u33E9': '\u0031\u0030\u65E5',
15541 '\u33EA': '\u0031\u0031\u65E5',
15542 '\u33EB': '\u0031\u0032\u65E5',
15543 '\u33EC': '\u0031\u0033\u65E5',
15544 '\u33ED': '\u0031\u0034\u65E5',
15545 '\u33EE': '\u0031\u0035\u65E5',
15546 '\u33EF': '\u0031\u0036\u65E5',
15547 '\u33F0': '\u0031\u0037\u65E5',
15548 '\u33F1': '\u0031\u0038\u65E5',
15549 '\u33F2': '\u0031\u0039\u65E5',
15550 '\u33F3': '\u0032\u0030\u65E5',
15551 '\u33F4': '\u0032\u0031\u65E5',
15552 '\u33F5': '\u0032\u0032\u65E5',
15553 '\u33F6': '\u0032\u0033\u65E5',
15554 '\u33F7': '\u0032\u0034\u65E5',
15555 '\u33F8': '\u0032\u0035\u65E5',
15556 '\u33F9': '\u0032\u0036\u65E5',
15557 '\u33FA': '\u0032\u0037\u65E5',
15558 '\u33FB': '\u0032\u0038\u65E5',
15559 '\u33FC': '\u0032\u0039\u65E5',
15560 '\u33FD': '\u0033\u0030\u65E5',
15561 '\u33FE': '\u0033\u0031\u65E5',
15562 '\uFB00': '\u0066\u0066',
15563 '\uFB01': '\u0066\u0069',
15564 '\uFB02': '\u0066\u006C',
15565 '\uFB03': '\u0066\u0066\u0069',
15566 '\uFB04': '\u0066\u0066\u006C',
15567 '\uFB05': '\u017F\u0074',
15568 '\uFB06': '\u0073\u0074',
15569 '\uFB13': '\u0574\u0576',
15570 '\uFB14': '\u0574\u0565',
15571 '\uFB15': '\u0574\u056B',
15572 '\uFB16': '\u057E\u0576',
15573 '\uFB17': '\u0574\u056D',
15574 '\uFB4F': '\u05D0\u05DC',
15575 '\uFB50': '\u0671',
15576 '\uFB51': '\u0671',
15577 '\uFB52': '\u067B',
15578 '\uFB53': '\u067B',
15579 '\uFB54': '\u067B',
15580 '\uFB55': '\u067B',
15581 '\uFB56': '\u067E',
15582 '\uFB57': '\u067E',
15583 '\uFB58': '\u067E',
15584 '\uFB59': '\u067E',
15585 '\uFB5A': '\u0680',
15586 '\uFB5B': '\u0680',
15587 '\uFB5C': '\u0680',
15588 '\uFB5D': '\u0680',
15589 '\uFB5E': '\u067A',
15590 '\uFB5F': '\u067A',
15591 '\uFB60': '\u067A',
15592 '\uFB61': '\u067A',
15593 '\uFB62': '\u067F',
15594 '\uFB63': '\u067F',
15595 '\uFB64': '\u067F',
15596 '\uFB65': '\u067F',
15597 '\uFB66': '\u0679',
15598 '\uFB67': '\u0679',
15599 '\uFB68': '\u0679',
15600 '\uFB69': '\u0679',
15601 '\uFB6A': '\u06A4',
15602 '\uFB6B': '\u06A4',
15603 '\uFB6C': '\u06A4',
15604 '\uFB6D': '\u06A4',
15605 '\uFB6E': '\u06A6',
15606 '\uFB6F': '\u06A6',
15607 '\uFB70': '\u06A6',
15608 '\uFB71': '\u06A6',
15609 '\uFB72': '\u0684',
15610 '\uFB73': '\u0684',
15611 '\uFB74': '\u0684',
15612 '\uFB75': '\u0684',
15613 '\uFB76': '\u0683',
15614 '\uFB77': '\u0683',
15615 '\uFB78': '\u0683',
15616 '\uFB79': '\u0683',
15617 '\uFB7A': '\u0686',
15618 '\uFB7B': '\u0686',
15619 '\uFB7C': '\u0686',
15620 '\uFB7D': '\u0686',
15621 '\uFB7E': '\u0687',
15622 '\uFB7F': '\u0687',
15623 '\uFB80': '\u0687',
15624 '\uFB81': '\u0687',
15625 '\uFB82': '\u068D',
15626 '\uFB83': '\u068D',
15627 '\uFB84': '\u068C',
15628 '\uFB85': '\u068C',
15629 '\uFB86': '\u068E',
15630 '\uFB87': '\u068E',
15631 '\uFB88': '\u0688',
15632 '\uFB89': '\u0688',
15633 '\uFB8A': '\u0698',
15634 '\uFB8B': '\u0698',
15635 '\uFB8C': '\u0691',
15636 '\uFB8D': '\u0691',
15637 '\uFB8E': '\u06A9',
15638 '\uFB8F': '\u06A9',
15639 '\uFB90': '\u06A9',
15640 '\uFB91': '\u06A9',
15641 '\uFB92': '\u06AF',
15642 '\uFB93': '\u06AF',
15643 '\uFB94': '\u06AF',
15644 '\uFB95': '\u06AF',
15645 '\uFB96': '\u06B3',
15646 '\uFB97': '\u06B3',
15647 '\uFB98': '\u06B3',
15648 '\uFB99': '\u06B3',
15649 '\uFB9A': '\u06B1',
15650 '\uFB9B': '\u06B1',
15651 '\uFB9C': '\u06B1',
15652 '\uFB9D': '\u06B1',
15653 '\uFB9E': '\u06BA',
15654 '\uFB9F': '\u06BA',
15655 '\uFBA0': '\u06BB',
15656 '\uFBA1': '\u06BB',
15657 '\uFBA2': '\u06BB',
15658 '\uFBA3': '\u06BB',
15659 '\uFBA4': '\u06C0',
15660 '\uFBA5': '\u06C0',
15661 '\uFBA6': '\u06C1',
15662 '\uFBA7': '\u06C1',
15663 '\uFBA8': '\u06C1',
15664 '\uFBA9': '\u06C1',
15665 '\uFBAA': '\u06BE',
15666 '\uFBAB': '\u06BE',
15667 '\uFBAC': '\u06BE',
15668 '\uFBAD': '\u06BE',
15669 '\uFBAE': '\u06D2',
15670 '\uFBAF': '\u06D2',
15671 '\uFBB0': '\u06D3',
15672 '\uFBB1': '\u06D3',
15673 '\uFBD3': '\u06AD',
15674 '\uFBD4': '\u06AD',
15675 '\uFBD5': '\u06AD',
15676 '\uFBD6': '\u06AD',
15677 '\uFBD7': '\u06C7',
15678 '\uFBD8': '\u06C7',
15679 '\uFBD9': '\u06C6',
15680 '\uFBDA': '\u06C6',
15681 '\uFBDB': '\u06C8',
15682 '\uFBDC': '\u06C8',
15683 '\uFBDD': '\u0677',
15684 '\uFBDE': '\u06CB',
15685 '\uFBDF': '\u06CB',
15686 '\uFBE0': '\u06C5',
15687 '\uFBE1': '\u06C5',
15688 '\uFBE2': '\u06C9',
15689 '\uFBE3': '\u06C9',
15690 '\uFBE4': '\u06D0',
15691 '\uFBE5': '\u06D0',
15692 '\uFBE6': '\u06D0',
15693 '\uFBE7': '\u06D0',
15694 '\uFBE8': '\u0649',
15695 '\uFBE9': '\u0649',
15696 '\uFBEA': '\u0626\u0627',
15697 '\uFBEB': '\u0626\u0627',
15698 '\uFBEC': '\u0626\u06D5',
15699 '\uFBED': '\u0626\u06D5',
15700 '\uFBEE': '\u0626\u0648',
15701 '\uFBEF': '\u0626\u0648',
15702 '\uFBF0': '\u0626\u06C7',
15703 '\uFBF1': '\u0626\u06C7',
15704 '\uFBF2': '\u0626\u06C6',
15705 '\uFBF3': '\u0626\u06C6',
15706 '\uFBF4': '\u0626\u06C8',
15707 '\uFBF5': '\u0626\u06C8',
15708 '\uFBF6': '\u0626\u06D0',
15709 '\uFBF7': '\u0626\u06D0',
15710 '\uFBF8': '\u0626\u06D0',
15711 '\uFBF9': '\u0626\u0649',
15712 '\uFBFA': '\u0626\u0649',
15713 '\uFBFB': '\u0626\u0649',
15714 '\uFBFC': '\u06CC',
15715 '\uFBFD': '\u06CC',
15716 '\uFBFE': '\u06CC',
15717 '\uFBFF': '\u06CC',
15718 '\uFC00': '\u0626\u062C',
15719 '\uFC01': '\u0626\u062D',
15720 '\uFC02': '\u0626\u0645',
15721 '\uFC03': '\u0626\u0649',
15722 '\uFC04': '\u0626\u064A',
15723 '\uFC05': '\u0628\u062C',
15724 '\uFC06': '\u0628\u062D',
15725 '\uFC07': '\u0628\u062E',
15726 '\uFC08': '\u0628\u0645',
15727 '\uFC09': '\u0628\u0649',
15728 '\uFC0A': '\u0628\u064A',
15729 '\uFC0B': '\u062A\u062C',
15730 '\uFC0C': '\u062A\u062D',
15731 '\uFC0D': '\u062A\u062E',
15732 '\uFC0E': '\u062A\u0645',
15733 '\uFC0F': '\u062A\u0649',
15734 '\uFC10': '\u062A\u064A',
15735 '\uFC11': '\u062B\u062C',
15736 '\uFC12': '\u062B\u0645',
15737 '\uFC13': '\u062B\u0649',
15738 '\uFC14': '\u062B\u064A',
15739 '\uFC15': '\u062C\u062D',
15740 '\uFC16': '\u062C\u0645',
15741 '\uFC17': '\u062D\u062C',
15742 '\uFC18': '\u062D\u0645',
15743 '\uFC19': '\u062E\u062C',
15744 '\uFC1A': '\u062E\u062D',
15745 '\uFC1B': '\u062E\u0645',
15746 '\uFC1C': '\u0633\u062C',
15747 '\uFC1D': '\u0633\u062D',
15748 '\uFC1E': '\u0633\u062E',
15749 '\uFC1F': '\u0633\u0645',
15750 '\uFC20': '\u0635\u062D',
15751 '\uFC21': '\u0635\u0645',
15752 '\uFC22': '\u0636\u062C',
15753 '\uFC23': '\u0636\u062D',
15754 '\uFC24': '\u0636\u062E',
15755 '\uFC25': '\u0636\u0645',
15756 '\uFC26': '\u0637\u062D',
15757 '\uFC27': '\u0637\u0645',
15758 '\uFC28': '\u0638\u0645',
15759 '\uFC29': '\u0639\u062C',
15760 '\uFC2A': '\u0639\u0645',
15761 '\uFC2B': '\u063A\u062C',
15762 '\uFC2C': '\u063A\u0645',
15763 '\uFC2D': '\u0641\u062C',
15764 '\uFC2E': '\u0641\u062D',
15765 '\uFC2F': '\u0641\u062E',
15766 '\uFC30': '\u0641\u0645',
15767 '\uFC31': '\u0641\u0649',
15768 '\uFC32': '\u0641\u064A',
15769 '\uFC33': '\u0642\u062D',
15770 '\uFC34': '\u0642\u0645',
15771 '\uFC35': '\u0642\u0649',
15772 '\uFC36': '\u0642\u064A',
15773 '\uFC37': '\u0643\u0627',
15774 '\uFC38': '\u0643\u062C',
15775 '\uFC39': '\u0643\u062D',
15776 '\uFC3A': '\u0643\u062E',
15777 '\uFC3B': '\u0643\u0644',
15778 '\uFC3C': '\u0643\u0645',
15779 '\uFC3D': '\u0643\u0649',
15780 '\uFC3E': '\u0643\u064A',
15781 '\uFC3F': '\u0644\u062C',
15782 '\uFC40': '\u0644\u062D',
15783 '\uFC41': '\u0644\u062E',
15784 '\uFC42': '\u0644\u0645',
15785 '\uFC43': '\u0644\u0649',
15786 '\uFC44': '\u0644\u064A',
15787 '\uFC45': '\u0645\u062C',
15788 '\uFC46': '\u0645\u062D',
15789 '\uFC47': '\u0645\u062E',
15790 '\uFC48': '\u0645\u0645',
15791 '\uFC49': '\u0645\u0649',
15792 '\uFC4A': '\u0645\u064A',
15793 '\uFC4B': '\u0646\u062C',
15794 '\uFC4C': '\u0646\u062D',
15795 '\uFC4D': '\u0646\u062E',
15796 '\uFC4E': '\u0646\u0645',
15797 '\uFC4F': '\u0646\u0649',
15798 '\uFC50': '\u0646\u064A',
15799 '\uFC51': '\u0647\u062C',
15800 '\uFC52': '\u0647\u0645',
15801 '\uFC53': '\u0647\u0649',
15802 '\uFC54': '\u0647\u064A',
15803 '\uFC55': '\u064A\u062C',
15804 '\uFC56': '\u064A\u062D',
15805 '\uFC57': '\u064A\u062E',
15806 '\uFC58': '\u064A\u0645',
15807 '\uFC59': '\u064A\u0649',
15808 '\uFC5A': '\u064A\u064A',
15809 '\uFC5B': '\u0630\u0670',
15810 '\uFC5C': '\u0631\u0670',
15811 '\uFC5D': '\u0649\u0670',
15812 '\uFC5E': '\u0020\u064C\u0651',
15813 '\uFC5F': '\u0020\u064D\u0651',
15814 '\uFC60': '\u0020\u064E\u0651',
15815 '\uFC61': '\u0020\u064F\u0651',
15816 '\uFC62': '\u0020\u0650\u0651',
15817 '\uFC63': '\u0020\u0651\u0670',
15818 '\uFC64': '\u0626\u0631',
15819 '\uFC65': '\u0626\u0632',
15820 '\uFC66': '\u0626\u0645',
15821 '\uFC67': '\u0626\u0646',
15822 '\uFC68': '\u0626\u0649',
15823 '\uFC69': '\u0626\u064A',
15824 '\uFC6A': '\u0628\u0631',
15825 '\uFC6B': '\u0628\u0632',
15826 '\uFC6C': '\u0628\u0645',
15827 '\uFC6D': '\u0628\u0646',
15828 '\uFC6E': '\u0628\u0649',
15829 '\uFC6F': '\u0628\u064A',
15830 '\uFC70': '\u062A\u0631',
15831 '\uFC71': '\u062A\u0632',
15832 '\uFC72': '\u062A\u0645',
15833 '\uFC73': '\u062A\u0646',
15834 '\uFC74': '\u062A\u0649',
15835 '\uFC75': '\u062A\u064A',
15836 '\uFC76': '\u062B\u0631',
15837 '\uFC77': '\u062B\u0632',
15838 '\uFC78': '\u062B\u0645',
15839 '\uFC79': '\u062B\u0646',
15840 '\uFC7A': '\u062B\u0649',
15841 '\uFC7B': '\u062B\u064A',
15842 '\uFC7C': '\u0641\u0649',
15843 '\uFC7D': '\u0641\u064A',
15844 '\uFC7E': '\u0642\u0649',
15845 '\uFC7F': '\u0642\u064A',
15846 '\uFC80': '\u0643\u0627',
15847 '\uFC81': '\u0643\u0644',
15848 '\uFC82': '\u0643\u0645',
15849 '\uFC83': '\u0643\u0649',
15850 '\uFC84': '\u0643\u064A',
15851 '\uFC85': '\u0644\u0645',
15852 '\uFC86': '\u0644\u0649',
15853 '\uFC87': '\u0644\u064A',
15854 '\uFC88': '\u0645\u0627',
15855 '\uFC89': '\u0645\u0645',
15856 '\uFC8A': '\u0646\u0631',
15857 '\uFC8B': '\u0646\u0632',
15858 '\uFC8C': '\u0646\u0645',
15859 '\uFC8D': '\u0646\u0646',
15860 '\uFC8E': '\u0646\u0649',
15861 '\uFC8F': '\u0646\u064A',
15862 '\uFC90': '\u0649\u0670',
15863 '\uFC91': '\u064A\u0631',
15864 '\uFC92': '\u064A\u0632',
15865 '\uFC93': '\u064A\u0645',
15866 '\uFC94': '\u064A\u0646',
15867 '\uFC95': '\u064A\u0649',
15868 '\uFC96': '\u064A\u064A',
15869 '\uFC97': '\u0626\u062C',
15870 '\uFC98': '\u0626\u062D',
15871 '\uFC99': '\u0626\u062E',
15872 '\uFC9A': '\u0626\u0645',
15873 '\uFC9B': '\u0626\u0647',
15874 '\uFC9C': '\u0628\u062C',
15875 '\uFC9D': '\u0628\u062D',
15876 '\uFC9E': '\u0628\u062E',
15877 '\uFC9F': '\u0628\u0645',
15878 '\uFCA0': '\u0628\u0647',
15879 '\uFCA1': '\u062A\u062C',
15880 '\uFCA2': '\u062A\u062D',
15881 '\uFCA3': '\u062A\u062E',
15882 '\uFCA4': '\u062A\u0645',
15883 '\uFCA5': '\u062A\u0647',
15884 '\uFCA6': '\u062B\u0645',
15885 '\uFCA7': '\u062C\u062D',
15886 '\uFCA8': '\u062C\u0645',
15887 '\uFCA9': '\u062D\u062C',
15888 '\uFCAA': '\u062D\u0645',
15889 '\uFCAB': '\u062E\u062C',
15890 '\uFCAC': '\u062E\u0645',
15891 '\uFCAD': '\u0633\u062C',
15892 '\uFCAE': '\u0633\u062D',
15893 '\uFCAF': '\u0633\u062E',
15894 '\uFCB0': '\u0633\u0645',
15895 '\uFCB1': '\u0635\u062D',
15896 '\uFCB2': '\u0635\u062E',
15897 '\uFCB3': '\u0635\u0645',
15898 '\uFCB4': '\u0636\u062C',
15899 '\uFCB5': '\u0636\u062D',
15900 '\uFCB6': '\u0636\u062E',
15901 '\uFCB7': '\u0636\u0645',
15902 '\uFCB8': '\u0637\u062D',
15903 '\uFCB9': '\u0638\u0645',
15904 '\uFCBA': '\u0639\u062C',
15905 '\uFCBB': '\u0639\u0645',
15906 '\uFCBC': '\u063A\u062C',
15907 '\uFCBD': '\u063A\u0645',
15908 '\uFCBE': '\u0641\u062C',
15909 '\uFCBF': '\u0641\u062D',
15910 '\uFCC0': '\u0641\u062E',
15911 '\uFCC1': '\u0641\u0645',
15912 '\uFCC2': '\u0642\u062D',
15913 '\uFCC3': '\u0642\u0645',
15914 '\uFCC4': '\u0643\u062C',
15915 '\uFCC5': '\u0643\u062D',
15916 '\uFCC6': '\u0643\u062E',
15917 '\uFCC7': '\u0643\u0644',
15918 '\uFCC8': '\u0643\u0645',
15919 '\uFCC9': '\u0644\u062C',
15920 '\uFCCA': '\u0644\u062D',
15921 '\uFCCB': '\u0644\u062E',
15922 '\uFCCC': '\u0644\u0645',
15923 '\uFCCD': '\u0644\u0647',
15924 '\uFCCE': '\u0645\u062C',
15925 '\uFCCF': '\u0645\u062D',
15926 '\uFCD0': '\u0645\u062E',
15927 '\uFCD1': '\u0645\u0645',
15928 '\uFCD2': '\u0646\u062C',
15929 '\uFCD3': '\u0646\u062D',
15930 '\uFCD4': '\u0646\u062E',
15931 '\uFCD5': '\u0646\u0645',
15932 '\uFCD6': '\u0646\u0647',
15933 '\uFCD7': '\u0647\u062C',
15934 '\uFCD8': '\u0647\u0645',
15935 '\uFCD9': '\u0647\u0670',
15936 '\uFCDA': '\u064A\u062C',
15937 '\uFCDB': '\u064A\u062D',
15938 '\uFCDC': '\u064A\u062E',
15939 '\uFCDD': '\u064A\u0645',
15940 '\uFCDE': '\u064A\u0647',
15941 '\uFCDF': '\u0626\u0645',
15942 '\uFCE0': '\u0626\u0647',
15943 '\uFCE1': '\u0628\u0645',
15944 '\uFCE2': '\u0628\u0647',
15945 '\uFCE3': '\u062A\u0645',
15946 '\uFCE4': '\u062A\u0647',
15947 '\uFCE5': '\u062B\u0645',
15948 '\uFCE6': '\u062B\u0647',
15949 '\uFCE7': '\u0633\u0645',
15950 '\uFCE8': '\u0633\u0647',
15951 '\uFCE9': '\u0634\u0645',
15952 '\uFCEA': '\u0634\u0647',
15953 '\uFCEB': '\u0643\u0644',
15954 '\uFCEC': '\u0643\u0645',
15955 '\uFCED': '\u0644\u0645',
15956 '\uFCEE': '\u0646\u0645',
15957 '\uFCEF': '\u0646\u0647',
15958 '\uFCF0': '\u064A\u0645',
15959 '\uFCF1': '\u064A\u0647',
15960 '\uFCF2': '\u0640\u064E\u0651',
15961 '\uFCF3': '\u0640\u064F\u0651',
15962 '\uFCF4': '\u0640\u0650\u0651',
15963 '\uFCF5': '\u0637\u0649',
15964 '\uFCF6': '\u0637\u064A',
15965 '\uFCF7': '\u0639\u0649',
15966 '\uFCF8': '\u0639\u064A',
15967 '\uFCF9': '\u063A\u0649',
15968 '\uFCFA': '\u063A\u064A',
15969 '\uFCFB': '\u0633\u0649',
15970 '\uFCFC': '\u0633\u064A',
15971 '\uFCFD': '\u0634\u0649',
15972 '\uFCFE': '\u0634\u064A',
15973 '\uFCFF': '\u062D\u0649',
15974 '\uFD00': '\u062D\u064A',
15975 '\uFD01': '\u062C\u0649',
15976 '\uFD02': '\u062C\u064A',
15977 '\uFD03': '\u062E\u0649',
15978 '\uFD04': '\u062E\u064A',
15979 '\uFD05': '\u0635\u0649',
15980 '\uFD06': '\u0635\u064A',
15981 '\uFD07': '\u0636\u0649',
15982 '\uFD08': '\u0636\u064A',
15983 '\uFD09': '\u0634\u062C',
15984 '\uFD0A': '\u0634\u062D',
15985 '\uFD0B': '\u0634\u062E',
15986 '\uFD0C': '\u0634\u0645',
15987 '\uFD0D': '\u0634\u0631',
15988 '\uFD0E': '\u0633\u0631',
15989 '\uFD0F': '\u0635\u0631',
15990 '\uFD10': '\u0636\u0631',
15991 '\uFD11': '\u0637\u0649',
15992 '\uFD12': '\u0637\u064A',
15993 '\uFD13': '\u0639\u0649',
15994 '\uFD14': '\u0639\u064A',
15995 '\uFD15': '\u063A\u0649',
15996 '\uFD16': '\u063A\u064A',
15997 '\uFD17': '\u0633\u0649',
15998 '\uFD18': '\u0633\u064A',
15999 '\uFD19': '\u0634\u0649',
16000 '\uFD1A': '\u0634\u064A',
16001 '\uFD1B': '\u062D\u0649',
16002 '\uFD1C': '\u062D\u064A',
16003 '\uFD1D': '\u062C\u0649',
16004 '\uFD1E': '\u062C\u064A',
16005 '\uFD1F': '\u062E\u0649',
16006 '\uFD20': '\u062E\u064A',
16007 '\uFD21': '\u0635\u0649',
16008 '\uFD22': '\u0635\u064A',
16009 '\uFD23': '\u0636\u0649',
16010 '\uFD24': '\u0636\u064A',
16011 '\uFD25': '\u0634\u062C',
16012 '\uFD26': '\u0634\u062D',
16013 '\uFD27': '\u0634\u062E',
16014 '\uFD28': '\u0634\u0645',
16015 '\uFD29': '\u0634\u0631',
16016 '\uFD2A': '\u0633\u0631',
16017 '\uFD2B': '\u0635\u0631',
16018 '\uFD2C': '\u0636\u0631',
16019 '\uFD2D': '\u0634\u062C',
16020 '\uFD2E': '\u0634\u062D',
16021 '\uFD2F': '\u0634\u062E',
16022 '\uFD30': '\u0634\u0645',
16023 '\uFD31': '\u0633\u0647',
16024 '\uFD32': '\u0634\u0647',
16025 '\uFD33': '\u0637\u0645',
16026 '\uFD34': '\u0633\u062C',
16027 '\uFD35': '\u0633\u062D',
16028 '\uFD36': '\u0633\u062E',
16029 '\uFD37': '\u0634\u062C',
16030 '\uFD38': '\u0634\u062D',
16031 '\uFD39': '\u0634\u062E',
16032 '\uFD3A': '\u0637\u0645',
16033 '\uFD3B': '\u0638\u0645',
16034 '\uFD3C': '\u0627\u064B',
16035 '\uFD3D': '\u0627\u064B',
16036 '\uFD50': '\u062A\u062C\u0645',
16037 '\uFD51': '\u062A\u062D\u062C',
16038 '\uFD52': '\u062A\u062D\u062C',
16039 '\uFD53': '\u062A\u062D\u0645',
16040 '\uFD54': '\u062A\u062E\u0645',
16041 '\uFD55': '\u062A\u0645\u062C',
16042 '\uFD56': '\u062A\u0645\u062D',
16043 '\uFD57': '\u062A\u0645\u062E',
16044 '\uFD58': '\u062C\u0645\u062D',
16045 '\uFD59': '\u062C\u0645\u062D',
16046 '\uFD5A': '\u062D\u0645\u064A',
16047 '\uFD5B': '\u062D\u0645\u0649',
16048 '\uFD5C': '\u0633\u062D\u062C',
16049 '\uFD5D': '\u0633\u062C\u062D',
16050 '\uFD5E': '\u0633\u062C\u0649',
16051 '\uFD5F': '\u0633\u0645\u062D',
16052 '\uFD60': '\u0633\u0645\u062D',
16053 '\uFD61': '\u0633\u0645\u062C',
16054 '\uFD62': '\u0633\u0645\u0645',
16055 '\uFD63': '\u0633\u0645\u0645',
16056 '\uFD64': '\u0635\u062D\u062D',
16057 '\uFD65': '\u0635\u062D\u062D',
16058 '\uFD66': '\u0635\u0645\u0645',
16059 '\uFD67': '\u0634\u062D\u0645',
16060 '\uFD68': '\u0634\u062D\u0645',
16061 '\uFD69': '\u0634\u062C\u064A',
16062 '\uFD6A': '\u0634\u0645\u062E',
16063 '\uFD6B': '\u0634\u0645\u062E',
16064 '\uFD6C': '\u0634\u0645\u0645',
16065 '\uFD6D': '\u0634\u0645\u0645',
16066 '\uFD6E': '\u0636\u062D\u0649',
16067 '\uFD6F': '\u0636\u062E\u0645',
16068 '\uFD70': '\u0636\u062E\u0645',
16069 '\uFD71': '\u0637\u0645\u062D',
16070 '\uFD72': '\u0637\u0645\u062D',
16071 '\uFD73': '\u0637\u0645\u0645',
16072 '\uFD74': '\u0637\u0645\u064A',
16073 '\uFD75': '\u0639\u062C\u0645',
16074 '\uFD76': '\u0639\u0645\u0645',
16075 '\uFD77': '\u0639\u0645\u0645',
16076 '\uFD78': '\u0639\u0645\u0649',
16077 '\uFD79': '\u063A\u0645\u0645',
16078 '\uFD7A': '\u063A\u0645\u064A',
16079 '\uFD7B': '\u063A\u0645\u0649',
16080 '\uFD7C': '\u0641\u062E\u0645',
16081 '\uFD7D': '\u0641\u062E\u0645',
16082 '\uFD7E': '\u0642\u0645\u062D',
16083 '\uFD7F': '\u0642\u0645\u0645',
16084 '\uFD80': '\u0644\u062D\u0645',
16085 '\uFD81': '\u0644\u062D\u064A',
16086 '\uFD82': '\u0644\u062D\u0649',
16087 '\uFD83': '\u0644\u062C\u062C',
16088 '\uFD84': '\u0644\u062C\u062C',
16089 '\uFD85': '\u0644\u062E\u0645',
16090 '\uFD86': '\u0644\u062E\u0645',
16091 '\uFD87': '\u0644\u0645\u062D',
16092 '\uFD88': '\u0644\u0645\u062D',
16093 '\uFD89': '\u0645\u062D\u062C',
16094 '\uFD8A': '\u0645\u062D\u0645',
16095 '\uFD8B': '\u0645\u062D\u064A',
16096 '\uFD8C': '\u0645\u062C\u062D',
16097 '\uFD8D': '\u0645\u062C\u0645',
16098 '\uFD8E': '\u0645\u062E\u062C',
16099 '\uFD8F': '\u0645\u062E\u0645',
16100 '\uFD92': '\u0645\u062C\u062E',
16101 '\uFD93': '\u0647\u0645\u062C',
16102 '\uFD94': '\u0647\u0645\u0645',
16103 '\uFD95': '\u0646\u062D\u0645',
16104 '\uFD96': '\u0646\u062D\u0649',
16105 '\uFD97': '\u0646\u062C\u0645',
16106 '\uFD98': '\u0646\u062C\u0645',
16107 '\uFD99': '\u0646\u062C\u0649',
16108 '\uFD9A': '\u0646\u0645\u064A',
16109 '\uFD9B': '\u0646\u0645\u0649',
16110 '\uFD9C': '\u064A\u0645\u0645',
16111 '\uFD9D': '\u064A\u0645\u0645',
16112 '\uFD9E': '\u0628\u062E\u064A',
16113 '\uFD9F': '\u062A\u062C\u064A',
16114 '\uFDA0': '\u062A\u062C\u0649',
16115 '\uFDA1': '\u062A\u062E\u064A',
16116 '\uFDA2': '\u062A\u062E\u0649',
16117 '\uFDA3': '\u062A\u0645\u064A',
16118 '\uFDA4': '\u062A\u0645\u0649',
16119 '\uFDA5': '\u062C\u0645\u064A',
16120 '\uFDA6': '\u062C\u062D\u0649',
16121 '\uFDA7': '\u062C\u0645\u0649',
16122 '\uFDA8': '\u0633\u062E\u0649',
16123 '\uFDA9': '\u0635\u062D\u064A',
16124 '\uFDAA': '\u0634\u062D\u064A',
16125 '\uFDAB': '\u0636\u062D\u064A',
16126 '\uFDAC': '\u0644\u062C\u064A',
16127 '\uFDAD': '\u0644\u0645\u064A',
16128 '\uFDAE': '\u064A\u062D\u064A',
16129 '\uFDAF': '\u064A\u062C\u064A',
16130 '\uFDB0': '\u064A\u0645\u064A',
16131 '\uFDB1': '\u0645\u0645\u064A',
16132 '\uFDB2': '\u0642\u0645\u064A',
16133 '\uFDB3': '\u0646\u062D\u064A',
16134 '\uFDB4': '\u0642\u0645\u062D',
16135 '\uFDB5': '\u0644\u062D\u0645',
16136 '\uFDB6': '\u0639\u0645\u064A',
16137 '\uFDB7': '\u0643\u0645\u064A',
16138 '\uFDB8': '\u0646\u062C\u062D',
16139 '\uFDB9': '\u0645\u062E\u064A',
16140 '\uFDBA': '\u0644\u062C\u0645',
16141 '\uFDBB': '\u0643\u0645\u0645',
16142 '\uFDBC': '\u0644\u062C\u0645',
16143 '\uFDBD': '\u0646\u062C\u062D',
16144 '\uFDBE': '\u062C\u062D\u064A',
16145 '\uFDBF': '\u062D\u062C\u064A',
16146 '\uFDC0': '\u0645\u062C\u064A',
16147 '\uFDC1': '\u0641\u0645\u064A',
16148 '\uFDC2': '\u0628\u062D\u064A',
16149 '\uFDC3': '\u0643\u0645\u0645',
16150 '\uFDC4': '\u0639\u062C\u0645',
16151 '\uFDC5': '\u0635\u0645\u0645',
16152 '\uFDC6': '\u0633\u062E\u064A',
16153 '\uFDC7': '\u0646\u062C\u064A',
16154 '\uFE49': '\u203E',
16155 '\uFE4A': '\u203E',
16156 '\uFE4B': '\u203E',
16157 '\uFE4C': '\u203E',
16158 '\uFE4D': '\u005F',
16159 '\uFE4E': '\u005F',
16160 '\uFE4F': '\u005F',
16161 '\uFE80': '\u0621',
16162 '\uFE81': '\u0622',
16163 '\uFE82': '\u0622',
16164 '\uFE83': '\u0623',
16165 '\uFE84': '\u0623',
16166 '\uFE85': '\u0624',
16167 '\uFE86': '\u0624',
16168 '\uFE87': '\u0625',
16169 '\uFE88': '\u0625',
16170 '\uFE89': '\u0626',
16171 '\uFE8A': '\u0626',
16172 '\uFE8B': '\u0626',
16173 '\uFE8C': '\u0626',
16174 '\uFE8D': '\u0627',
16175 '\uFE8E': '\u0627',
16176 '\uFE8F': '\u0628',
16177 '\uFE90': '\u0628',
16178 '\uFE91': '\u0628',
16179 '\uFE92': '\u0628',
16180 '\uFE93': '\u0629',
16181 '\uFE94': '\u0629',
16182 '\uFE95': '\u062A',
16183 '\uFE96': '\u062A',
16184 '\uFE97': '\u062A',
16185 '\uFE98': '\u062A',
16186 '\uFE99': '\u062B',
16187 '\uFE9A': '\u062B',
16188 '\uFE9B': '\u062B',
16189 '\uFE9C': '\u062B',
16190 '\uFE9D': '\u062C',
16191 '\uFE9E': '\u062C',
16192 '\uFE9F': '\u062C',
16193 '\uFEA0': '\u062C',
16194 '\uFEA1': '\u062D',
16195 '\uFEA2': '\u062D',
16196 '\uFEA3': '\u062D',
16197 '\uFEA4': '\u062D',
16198 '\uFEA5': '\u062E',
16199 '\uFEA6': '\u062E',
16200 '\uFEA7': '\u062E',
16201 '\uFEA8': '\u062E',
16202 '\uFEA9': '\u062F',
16203 '\uFEAA': '\u062F',
16204 '\uFEAB': '\u0630',
16205 '\uFEAC': '\u0630',
16206 '\uFEAD': '\u0631',
16207 '\uFEAE': '\u0631',
16208 '\uFEAF': '\u0632',
16209 '\uFEB0': '\u0632',
16210 '\uFEB1': '\u0633',
16211 '\uFEB2': '\u0633',
16212 '\uFEB3': '\u0633',
16213 '\uFEB4': '\u0633',
16214 '\uFEB5': '\u0634',
16215 '\uFEB6': '\u0634',
16216 '\uFEB7': '\u0634',
16217 '\uFEB8': '\u0634',
16218 '\uFEB9': '\u0635',
16219 '\uFEBA': '\u0635',
16220 '\uFEBB': '\u0635',
16221 '\uFEBC': '\u0635',
16222 '\uFEBD': '\u0636',
16223 '\uFEBE': '\u0636',
16224 '\uFEBF': '\u0636',
16225 '\uFEC0': '\u0636',
16226 '\uFEC1': '\u0637',
16227 '\uFEC2': '\u0637',
16228 '\uFEC3': '\u0637',
16229 '\uFEC4': '\u0637',
16230 '\uFEC5': '\u0638',
16231 '\uFEC6': '\u0638',
16232 '\uFEC7': '\u0638',
16233 '\uFEC8': '\u0638',
16234 '\uFEC9': '\u0639',
16235 '\uFECA': '\u0639',
16236 '\uFECB': '\u0639',
16237 '\uFECC': '\u0639',
16238 '\uFECD': '\u063A',
16239 '\uFECE': '\u063A',
16240 '\uFECF': '\u063A',
16241 '\uFED0': '\u063A',
16242 '\uFED1': '\u0641',
16243 '\uFED2': '\u0641',
16244 '\uFED3': '\u0641',
16245 '\uFED4': '\u0641',
16246 '\uFED5': '\u0642',
16247 '\uFED6': '\u0642',
16248 '\uFED7': '\u0642',
16249 '\uFED8': '\u0642',
16250 '\uFED9': '\u0643',
16251 '\uFEDA': '\u0643',
16252 '\uFEDB': '\u0643',
16253 '\uFEDC': '\u0643',
16254 '\uFEDD': '\u0644',
16255 '\uFEDE': '\u0644',
16256 '\uFEDF': '\u0644',
16257 '\uFEE0': '\u0644',
16258 '\uFEE1': '\u0645',
16259 '\uFEE2': '\u0645',
16260 '\uFEE3': '\u0645',
16261 '\uFEE4': '\u0645',
16262 '\uFEE5': '\u0646',
16263 '\uFEE6': '\u0646',
16264 '\uFEE7': '\u0646',
16265 '\uFEE8': '\u0646',
16266 '\uFEE9': '\u0647',
16267 '\uFEEA': '\u0647',
16268 '\uFEEB': '\u0647',
16269 '\uFEEC': '\u0647',
16270 '\uFEED': '\u0648',
16271 '\uFEEE': '\u0648',
16272 '\uFEEF': '\u0649',
16273 '\uFEF0': '\u0649',
16274 '\uFEF1': '\u064A',
16275 '\uFEF2': '\u064A',
16276 '\uFEF3': '\u064A',
16277 '\uFEF4': '\u064A',
16278 '\uFEF5': '\u0644\u0622',
16279 '\uFEF6': '\u0644\u0622',
16280 '\uFEF7': '\u0644\u0623',
16281 '\uFEF8': '\u0644\u0623',
16282 '\uFEF9': '\u0644\u0625',
16283 '\uFEFA': '\u0644\u0625',
16284 '\uFEFB': '\u0644\u0627',
16285 '\uFEFC': '\u0644\u0627'
16286 };
16287
16288 function reverseIfRtl(chars) {
16289 var charsLength = chars.length;
16290 //reverse an arabic ligature
16291 if (charsLength <= 1 || !isRTLRangeFor(chars.charCodeAt(0))) {
16292 return chars;
16293 }
16294 var s = '';
16295 for (var ii = charsLength - 1; ii >= 0; ii--) {
16296 s += chars[ii];
16297 }
16298 return s;
16299 }
16300
16301 function adjustWidths(properties) {
16302 if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) {
16303 return;
16304 }
16305 // adjusting width to fontMatrix scale
16306 var scale = 0.001 / properties.fontMatrix[0];
16307 var glyphsWidths = properties.widths;
16308 for (var glyph in glyphsWidths) {
16309 glyphsWidths[glyph] *= scale;
16310 }
16311 properties.defaultWidth *= scale;
16312 }
16313
16314 function getFontType(type, subtype) {
16315 switch (type) {
16316 case 'Type1':
16317 return subtype === 'Type1C' ? FontType.TYPE1C : FontType.TYPE1;
16318 case 'CIDFontType0':
16319 return subtype === 'CIDFontType0C' ? FontType.CIDFONTTYPE0C :
16320 FontType.CIDFONTTYPE0;
16321 case 'OpenType':
16322 return FontType.OPENTYPE;
16323 case 'TrueType':
16324 return FontType.TRUETYPE;
16325 case 'CIDFontType2':
16326 return FontType.CIDFONTTYPE2;
16327 case 'MMType1':
16328 return FontType.MMTYPE1;
16329 case 'Type0':
16330 return FontType.TYPE0;
16331 default:
16332 return FontType.UNKNOWN;
16333 }
16334 }
16335
16336 var Glyph = (function GlyphClosure() {
16337 function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId) {
16338 this.fontChar = fontChar;
16339 this.unicode = unicode;
16340 this.accent = accent;
16341 this.width = width;
16342 this.vmetric = vmetric;
16343 this.operatorListId = operatorListId;
16344 }
16345
16346 Glyph.prototype.matchesForCache =
16347 function(fontChar, unicode, accent, width, vmetric, operatorListId) {
16348 return this.fontChar === fontChar &&
16349 this.unicode === unicode &&
16350 this.accent === accent &&
16351 this.width === width &&
16352 this.vmetric === vmetric &&
16353 this.operatorListId === operatorListId;
16354 };
16355
16356 return Glyph;
16357 })();
16358
16359 var ToUnicodeMap = (function ToUnicodeMapClosure() {
16360 function ToUnicodeMap(cmap) {
16361 // The elements of this._map can be integers or strings, depending on how
16362 // |cmap| was created.
16363 this._map = cmap;
16364 }
16365
16366 ToUnicodeMap.prototype = {
16367 get length() {
16368 return this._map.length;
16369 },
16370
16371 forEach: function(callback) {
16372 for (var charCode in this._map) {
16373 callback(charCode, this._map[charCode].charCodeAt(0));
16374 }
16375 },
16376
16377 has: function(i) {
16378 return this._map[i] !== undefined;
16379 },
16380
16381 get: function(i) {
16382 return this._map[i];
16383 },
16384
16385 charCodeOf: function(v) {
16386 return this._map.indexOf(v);
16387 }
16388 };
16389
16390 return ToUnicodeMap;
16391 })();
16392
16393 var IdentityToUnicodeMap = (function IdentityToUnicodeMapClosure() {
16394 function IdentityToUnicodeMap(firstChar, lastChar) {
16395 this.firstChar = firstChar;
16396 this.lastChar = lastChar;
16397 }
16398
16399 IdentityToUnicodeMap.prototype = {
16400 get length() {
16401 return (this.lastChar + 1) - this.firstChar;
16402 },
16403
16404 forEach: function (callback) {
16405 for (var i = this.firstChar, ii = this.lastChar; i <= ii; i++) {
16406 callback(i, i);
16407 }
16408 },
16409
16410 has: function (i) {
16411 return this.firstChar <= i && i <= this.lastChar;
16412 },
16413
16414 get: function (i) {
16415 if (this.firstChar <= i && i <= this.lastChar) {
16416 return String.fromCharCode(i);
16417 }
16418 return undefined;
16419 },
16420
16421 charCodeOf: function (v) {
16422 error('should not call .charCodeOf');
16423 }
16424 };
16425
16426 return IdentityToUnicodeMap;
16427 })();
16428
16429 var OpenTypeFileBuilder = (function OpenTypeFileBuilderClosure() {
16430 function writeInt16(dest, offset, num) {
16431 dest[offset] = (num >> 8) & 0xFF;
16432 dest[offset + 1] = num & 0xFF;
16433 }
16434
16435 function writeInt32(dest, offset, num) {
16436 dest[offset] = (num >> 24) & 0xFF;
16437 dest[offset + 1] = (num >> 16) & 0xFF;
16438 dest[offset + 2] = (num >> 8) & 0xFF;
16439 dest[offset + 3] = num & 0xFF;
16440 }
16441
16442 function writeData(dest, offset, data) {
16443 var i, ii;
16444 if (data instanceof Uint8Array) {
16445 dest.set(data, offset);
16446 } else if (typeof data === 'string') {
16447 for (i = 0, ii = data.length; i < ii; i++) {
16448 dest[offset++] = data.charCodeAt(i) & 0xFF;
16449 }
16450 } else {
16451 // treating everything else as array
16452 for (i = 0, ii = data.length; i < ii; i++) {
16453 dest[offset++] = data[i] & 0xFF;
16454 }
16455 }
16456 }
16457
16458 function OpenTypeFileBuilder(sfnt) {
16459 this.sfnt = sfnt;
16460 this.tables = Object.create(null);
16461 }
16462
16463 OpenTypeFileBuilder.getSearchParams =
16464 function OpenTypeFileBuilder_getSearchParams(entriesCount, entrySize) {
16465 var maxPower2 = 1, log2 = 0;
16466 while ((maxPower2 ^ entriesCount) > maxPower2) {
16467 maxPower2 <<= 1;
16468 log2++;
16469 }
16470 var searchRange = maxPower2 * entrySize;
16471 return {
16472 range: searchRange,
16473 entry: log2,
16474 rangeShift: entrySize * entriesCount - searchRange
16475 };
16476 };
16477
16478 var OTF_HEADER_SIZE = 12;
16479 var OTF_TABLE_ENTRY_SIZE = 16;
16480
16481 OpenTypeFileBuilder.prototype = {
16482 toArray: function OpenTypeFileBuilder_toArray() {
16483 var sfnt = this.sfnt;
16484
16485 // Tables needs to be written by ascendant alphabetic order
16486 var tables = this.tables;
16487 var tablesNames = Object.keys(tables);
16488 tablesNames.sort();
16489 var numTables = tablesNames.length;
16490
16491 var i, j, jj, table, tableName;
16492 // layout the tables data
16493 var offset = OTF_HEADER_SIZE + numTables * OTF_TABLE_ENTRY_SIZE;
16494 var tableOffsets = [offset];
16495 for (i = 0; i < numTables; i++) {
16496 table = tables[tablesNames[i]];
16497 var paddedLength = ((table.length + 3) & ~3) >>> 0;
16498 offset += paddedLength;
16499 tableOffsets.push(offset);
16500 }
16501
16502 var file = new Uint8Array(offset);
16503 // write the table data first (mostly for checksum)
16504 for (i = 0; i < numTables; i++) {
16505 table = tables[tablesNames[i]];
16506 writeData(file, tableOffsets[i], table);
16507 }
16508
16509 // sfnt version (4 bytes)
16510 if (sfnt === 'true') {
16511 // Windows hates the Mac TrueType sfnt version number
16512 sfnt = string32(0x00010000);
16513 }
16514 file[0] = sfnt.charCodeAt(0) & 0xFF;
16515 file[1] = sfnt.charCodeAt(1) & 0xFF;
16516 file[2] = sfnt.charCodeAt(2) & 0xFF;
16517 file[3] = sfnt.charCodeAt(3) & 0xFF;
16518
16519 // numTables (2 bytes)
16520 writeInt16(file, 4, numTables);
16521
16522 var searchParams = OpenTypeFileBuilder.getSearchParams(numTables, 16);
16523
16524 // searchRange (2 bytes)
16525 writeInt16(file, 6, searchParams.range);
16526 // entrySelector (2 bytes)
16527 writeInt16(file, 8, searchParams.entry);
16528 // rangeShift (2 bytes)
16529 writeInt16(file, 10, searchParams.rangeShift);
16530
16531 offset = OTF_HEADER_SIZE;
16532 // writing table entries
16533 for (i = 0; i < numTables; i++) {
16534 tableName = tablesNames[i];
16535 file[offset] = tableName.charCodeAt(0) & 0xFF;
16536 file[offset + 1] = tableName.charCodeAt(1) & 0xFF;
16537 file[offset + 2] = tableName.charCodeAt(2) & 0xFF;
16538 file[offset + 3] = tableName.charCodeAt(3) & 0xFF;
16539
16540 // checksum
16541 var checksum = 0;
16542 for (j = tableOffsets[i], jj = tableOffsets[i + 1]; j < jj; j += 4) {
16543 var quad = (file[j] << 24) + (file[j + 1] << 16) +
16544 (file[j + 2] << 8) + file[j + 3];
16545 checksum = (checksum + quad) | 0;
16546 }
16547 writeInt32(file, offset + 4, checksum);
16548
16549 // offset
16550 writeInt32(file, offset + 8, tableOffsets[i]);
16551 // length
16552 writeInt32(file, offset + 12, tables[tableName].length);
16553
16554 offset += OTF_TABLE_ENTRY_SIZE;
16555 }
16556 return file;
16557 },
16558
16559 addTable: function OpenTypeFileBuilder_addTable(tag, data) {
16560 if (tag in this.tables) {
16561 throw new Error('Table ' + tag + ' already exists');
16562 }
16563 this.tables[tag] = data;
16564 }
16565 };
16566
16567 return OpenTypeFileBuilder;
16568 })();
16569
16570 /**
16571 * 'Font' is the class the outside world should use, it encapsulate all the font
16572 * decoding logics whatever type it is (assuming the font type is supported).
16573 *
16574 * For example to read a Type1 font and to attach it to the document:
16575 * var type1Font = new Font("MyFontName", binaryFile, propertiesObject);
16576 * type1Font.bind();
16577 */
16578 var Font = (function FontClosure() {
16579 function Font(name, file, properties) {
16580 var charCode, glyphName, fontChar;
16581
16582 this.name = name;
16583 this.loadedName = properties.loadedName;
16584 this.isType3Font = properties.isType3Font;
16585 this.sizes = [];
16586
16587 this.glyphCache = {};
16588
16589 var names = name.split('+');
16590 names = names.length > 1 ? names[1] : names[0];
16591 names = names.split(/[-,_]/g)[0];
16592 this.isSerifFont = !!(properties.flags & FontFlags.Serif);
16593 this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
16594 this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
16595
16596 var type = properties.type;
16597 var subtype = properties.subtype;
16598 this.type = type;
16599
16600 this.fallbackName = (this.isMonospace ? 'monospace' :
16601 (this.isSerifFont ? 'serif' : 'sans-serif'));
16602
16603 this.differences = properties.differences;
16604 this.widths = properties.widths;
16605 this.defaultWidth = properties.defaultWidth;
16606 this.composite = properties.composite;
16607 this.wideChars = properties.wideChars;
16608 this.cMap = properties.cMap;
16609 this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS;
16610 this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS;
16611 this.fontMatrix = properties.fontMatrix;
16612
16613 this.toUnicode = properties.toUnicode = this.buildToUnicode(properties);
16614
16615 this.toFontChar = [];
16616
16617 if (properties.type === 'Type3') {
16618 for (charCode = 0; charCode < 256; charCode++) {
16619 this.toFontChar[charCode] = (this.differences[charCode] ||
16620 properties.defaultEncoding[charCode]);
16621 }
16622 this.fontType = FontType.TYPE3;
16623 return;
16624 }
16625
16626 this.cidEncoding = properties.cidEncoding;
16627 this.vertical = properties.vertical;
16628 if (this.vertical) {
16629 this.vmetrics = properties.vmetrics;
16630 this.defaultVMetrics = properties.defaultVMetrics;
16631 }
16632
16633 if (!file || file.isEmpty) {
16634 if (file) {
16635 // Some bad PDF generators will include empty font files,
16636 // attempting to recover by assuming that no file exists.
16637 warn('Font file is empty in "' + name + '" (' + this.loadedName + ')');
16638 }
16639
16640 this.missingFile = true;
16641 // The file data is not specified. Trying to fix the font name
16642 // to be used with the canvas.font.
16643 var fontName = name.replace(/[,_]/g, '-');
16644 var isStandardFont = !!stdFontMap[fontName] ||
16645 !!(nonStdFontMap[fontName] && stdFontMap[nonStdFontMap[fontName]]);
16646 fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
16647
16648 this.bold = (fontName.search(/bold/gi) !== -1);
16649 this.italic = ((fontName.search(/oblique/gi) !== -1) ||
16650 (fontName.search(/italic/gi) !== -1));
16651
16652 // Use 'name' instead of 'fontName' here because the original
16653 // name ArialBlack for example will be replaced by Helvetica.
16654 this.black = (name.search(/Black/g) !== -1);
16655
16656 // if at least one width is present, remeasure all chars when exists
16657 this.remeasure = Object.keys(this.widths).length > 0;
16658 if (isStandardFont && type === 'CIDFontType2' &&
16659 properties.cidEncoding.indexOf('Identity-') === 0) {
16660 // Standard fonts might be embedded as CID font without glyph mapping.
16661 // Building one based on GlyphMapForStandardFonts.
16662 var map = [];
16663 for (var code in GlyphMapForStandardFonts) {
16664 map[+code] = GlyphMapForStandardFonts[code];
16665 }
16666 var isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap;
16667 if (!isIdentityUnicode) {
16668 this.toUnicode.forEach(function(charCode, unicodeCharCode) {
16669 map[+charCode] = unicodeCharCode;
16670 });
16671 }
16672 this.toFontChar = map;
16673 this.toUnicode = new ToUnicodeMap(map);
16674 } else if (/Symbol/i.test(fontName)) {
16675 var symbols = Encodings.SymbolSetEncoding;
16676 for (charCode in symbols) {
16677 fontChar = GlyphsUnicode[symbols[charCode]];
16678 if (!fontChar) {
16679 continue;
16680 }
16681 this.toFontChar[charCode] = fontChar;
16682 }
16683 for (charCode in properties.differences) {
16684 fontChar = GlyphsUnicode[properties.differences[charCode]];
16685 if (!fontChar) {
16686 continue;
16687 }
16688 this.toFontChar[charCode] = fontChar;
16689 }
16690 } else if (/Dingbats/i.test(fontName)) {
16691 if (/Wingdings/i.test(name)) {
16692 warn('Wingdings font without embedded font file, ' +
16693 'falling back to the ZapfDingbats encoding.');
16694 }
16695 var dingbats = Encodings.ZapfDingbatsEncoding;
16696 for (charCode in dingbats) {
16697 fontChar = DingbatsGlyphsUnicode[dingbats[charCode]];
16698 if (!fontChar) {
16699 continue;
16700 }
16701 this.toFontChar[charCode] = fontChar;
16702 }
16703 for (charCode in properties.differences) {
16704 fontChar = DingbatsGlyphsUnicode[properties.differences[charCode]];
16705 if (!fontChar) {
16706 continue;
16707 }
16708 this.toFontChar[charCode] = fontChar;
16709 }
16710 } else if (isStandardFont) {
16711 this.toFontChar = [];
16712 for (charCode in properties.defaultEncoding) {
16713 glyphName = (properties.differences[charCode] ||
16714 properties.defaultEncoding[charCode]);
16715 this.toFontChar[charCode] = GlyphsUnicode[glyphName];
16716 }
16717 } else {
16718 var unicodeCharCode, notCidFont = (type.indexOf('CIDFontType') === -1);
16719 this.toUnicode.forEach(function(charCode, unicodeCharCode) {
16720 if (notCidFont) {
16721 glyphName = (properties.differences[charCode] ||
16722 properties.defaultEncoding[charCode]);
16723 unicodeCharCode = (GlyphsUnicode[glyphName] || unicodeCharCode);
16724 }
16725 this.toFontChar[charCode] = unicodeCharCode;
16726 }.bind(this));
16727 }
16728 this.loadedName = fontName.split('-')[0];
16729 this.loading = false;
16730 this.fontType = getFontType(type, subtype);
16731 return;
16732 }
16733
16734 // Some fonts might use wrong font types for Type1C or CIDFontType0C
16735 if (subtype === 'Type1C' && (type !== 'Type1' && type !== 'MMType1')) {
16736 // Some TrueType fonts by mistake claim Type1C
16737 if (isTrueTypeFile(file)) {
16738 subtype = 'TrueType';
16739 } else {
16740 type = 'Type1';
16741 }
16742 }
16743 if (subtype === 'CIDFontType0C' && type !== 'CIDFontType0') {
16744 type = 'CIDFontType0';
16745 }
16746 if (subtype === 'OpenType') {
16747 type = 'OpenType';
16748 }
16749 // Some CIDFontType0C fonts by mistake claim CIDFontType0.
16750 if (type === 'CIDFontType0') {
16751 subtype = isType1File(file) ? 'CIDFontType0' : 'CIDFontType0C';
16752 }
16753
16754 var data;
16755 switch (type) {
16756 case 'MMType1':
16757 info('MMType1 font (' + name + '), falling back to Type1.');
16758 /* falls through */
16759 case 'Type1':
16760 case 'CIDFontType0':
16761 this.mimetype = 'font/opentype';
16762
16763 var cff = (subtype === 'Type1C' || subtype === 'CIDFontType0C') ?
16764 new CFFFont(file, properties) : new Type1Font(name, file, properties);
16765
16766 adjustWidths(properties);
16767
16768 // Wrap the CFF data inside an OTF font file
16769 data = this.convert(name, cff, properties);
16770 break;
16771
16772 case 'OpenType':
16773 case 'TrueType':
16774 case 'CIDFontType2':
16775 this.mimetype = 'font/opentype';
16776
16777 // Repair the TrueType file. It is can be damaged in the point of
16778 // view of the sanitizer
16779 data = this.checkAndRepair(name, file, properties);
16780 if (this.isOpenType) {
16781 type = 'OpenType';
16782 }
16783 break;
16784
16785 default:
16786 error('Font ' + type + ' is not supported');
16787 break;
16788 }
16789
16790 this.data = data;
16791 this.fontType = getFontType(type, subtype);
16792
16793 // Transfer some properties again that could change during font conversion
16794 this.fontMatrix = properties.fontMatrix;
16795 this.widths = properties.widths;
16796 this.defaultWidth = properties.defaultWidth;
16797 this.encoding = properties.baseEncoding;
16798 this.seacMap = properties.seacMap;
16799
16800 this.loading = true;
16801 }
16802
16803 Font.getFontID = (function () {
16804 var ID = 1;
16805 return function Font_getFontID() {
16806 return String(ID++);
16807 };
16808 })();
16809
16810 function int16(b0, b1) {
16811 return (b0 << 8) + b1;
16812 }
16813
16814 function int32(b0, b1, b2, b3) {
16815 return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
16816 }
16817
16818 function string16(value) {
16819 return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
16820 }
16821
16822 function safeString16(value) {
16823 // clamp value to the 16-bit int range
16824 value = (value > 0x7FFF ? 0x7FFF : (value < -0x8000 ? -0x8000 : value));
16825 return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
16826 }
16827
16828 function isTrueTypeFile(file) {
16829 var header = file.peekBytes(4);
16830 return readUint32(header, 0) === 0x00010000;
16831 }
16832
16833 function isType1File(file) {
16834 var header = file.peekBytes(2);
16835 // All Type1 font programs must begin with the comment '%!' (0x25 + 0x21).
16836 if (header[0] === 0x25 && header[1] === 0x21) {
16837 return true;
16838 }
16839 // ... obviously some fonts violate that part of the specification,
16840 // please refer to the comment in |Type1Font| below.
16841 if (header[0] === 0x80 && header[1] === 0x01) { // pfb file header.
16842 return true;
16843 }
16844 return false;
16845 }
16846
16847 /**
16848 * Helper function for |adjustMapping|.
16849 * @return {boolean}
16850 */
16851 function isProblematicUnicodeLocation(code) {
16852 if (code <= 0x1F) { // Control chars
16853 return true;
16854 }
16855 if (code >= 0x80 && code <= 0x9F) { // Control chars
16856 return true;
16857 }
16858 if ((code >= 0x2000 && code <= 0x200F) || // General punctuation chars
16859 (code >= 0x2028 && code <= 0x202F) ||
16860 (code >= 0x2060 && code <= 0x206F)) {
16861 return true;
16862 }
16863 if (code >= 0xFFF0 && code <= 0xFFFF) { // Specials Unicode block
16864 return true;
16865 }
16866 switch (code) {
16867 case 0x7F: // Control char
16868 case 0xA0: // Non breaking space
16869 case 0xAD: // Soft hyphen
16870 case 0x0E33: // Thai character SARA AM
16871 case 0x2011: // Non breaking hyphen
16872 case 0x205F: // Medium mathematical space
16873 case 0x25CC: // Dotted circle (combining mark)
16874 return true;
16875 }
16876 return false;
16877 }
16878
16879 /**
16880 * Rebuilds the char code to glyph ID map by trying to replace the char codes
16881 * with their unicode value. It also moves char codes that are in known
16882 * problematic locations.
16883 * @return {Object} Two properties:
16884 * 'toFontChar' - maps original char codes(the value that will be read
16885 * from commands such as show text) to the char codes that will be used in the
16886 * font that we build
16887 * 'charCodeToGlyphId' - maps the new font char codes to glyph ids
16888 */
16889 function adjustMapping(charCodeToGlyphId, properties) {
16890 var toUnicode = properties.toUnicode;
16891 var isSymbolic = !!(properties.flags & FontFlags.Symbolic);
16892 var isIdentityUnicode =
16893 properties.toUnicode instanceof IdentityToUnicodeMap;
16894 var newMap = Object.create(null);
16895 var toFontChar = [];
16896 var usedFontCharCodes = [];
16897 var nextAvailableFontCharCode = PRIVATE_USE_OFFSET_START;
16898 for (var originalCharCode in charCodeToGlyphId) {
16899 originalCharCode |= 0;
16900 var glyphId = charCodeToGlyphId[originalCharCode];
16901 var fontCharCode = originalCharCode;
16902 // First try to map the value to a unicode position if a non identity map
16903 // was created.
16904 if (!isIdentityUnicode && toUnicode.has(originalCharCode)) {
16905 var unicode = toUnicode.get(fontCharCode);
16906 // TODO: Try to map ligatures to the correct spot.
16907 if (unicode.length === 1) {
16908 fontCharCode = unicode.charCodeAt(0);
16909 }
16910 }
16911 // Try to move control characters, special characters and already mapped
16912 // characters to the private use area since they will not be drawn by
16913 // canvas if left in their current position. Also, move characters if the
16914 // font was symbolic and there is only an identity unicode map since the
16915 // characters probably aren't in the correct position (fixes an issue
16916 // with firefox and thuluthfont).
16917 if ((usedFontCharCodes[fontCharCode] !== undefined ||
16918 isProblematicUnicodeLocation(fontCharCode) ||
16919 (isSymbolic && isIdentityUnicode)) &&
16920 nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END) { // Room left.
16921 // Loop to try and find a free spot in the private use area.
16922 do {
16923 fontCharCode = nextAvailableFontCharCode++;
16924
16925 if (SKIP_PRIVATE_USE_RANGE_F000_TO_F01F && fontCharCode === 0xF000) {
16926 fontCharCode = 0xF020;
16927 nextAvailableFontCharCode = fontCharCode + 1;
16928 }
16929
16930 } while (usedFontCharCodes[fontCharCode] !== undefined &&
16931 nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END);
16932 }
16933
16934 newMap[fontCharCode] = glyphId;
16935 toFontChar[originalCharCode] = fontCharCode;
16936 usedFontCharCodes[fontCharCode] = true;
16937 }
16938 return {
16939 toFontChar: toFontChar,
16940 charCodeToGlyphId: newMap,
16941 nextAvailableFontCharCode: nextAvailableFontCharCode
16942 };
16943 }
16944
16945 function getRanges(glyphs) {
16946 // Array.sort() sorts by characters, not numerically, so convert to an
16947 // array of characters.
16948 var codes = [];
16949 for (var charCode in glyphs) {
16950 codes.push({ fontCharCode: charCode | 0, glyphId: glyphs[charCode] });
16951 }
16952 codes.sort(function fontGetRangesSort(a, b) {
16953 return a.fontCharCode - b.fontCharCode;
16954 });
16955
16956 // Split the sorted codes into ranges.
16957 var ranges = [];
16958 var length = codes.length;
16959 for (var n = 0; n < length; ) {
16960 var start = codes[n].fontCharCode;
16961 var codeIndices = [codes[n].glyphId];
16962 ++n;
16963 var end = start;
16964 while (n < length && end + 1 === codes[n].fontCharCode) {
16965 codeIndices.push(codes[n].glyphId);
16966 ++end;
16967 ++n;
16968 if (end === 0xFFFF) {
16969 break;
16970 }
16971 }
16972 ranges.push([start, end, codeIndices]);
16973 }
16974
16975 return ranges;
16976 }
16977
16978 function createCmapTable(glyphs) {
16979 var ranges = getRanges(glyphs);
16980 var numTables = ranges[ranges.length - 1][1] > 0xFFFF ? 2 : 1;
16981 var cmap = '\x00\x00' + // version
16982 string16(numTables) + // numTables
16983 '\x00\x03' + // platformID
16984 '\x00\x01' + // encodingID
16985 string32(4 + numTables * 8); // start of the table record
16986
16987 var i, ii, j, jj;
16988 for (i = ranges.length - 1; i >= 0; --i) {
16989 if (ranges[i][0] <= 0xFFFF) { break; }
16990 }
16991 var bmpLength = i + 1;
16992
16993 if (ranges[i][0] < 0xFFFF && ranges[i][1] === 0xFFFF) {
16994 ranges[i][1] = 0xFFFE;
16995 }
16996 var trailingRangesCount = ranges[i][1] < 0xFFFF ? 1 : 0;
16997 var segCount = bmpLength + trailingRangesCount;
16998 var searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2);
16999
17000 // Fill up the 4 parallel arrays describing the segments.
17001 var startCount = '';
17002 var endCount = '';
17003 var idDeltas = '';
17004 var idRangeOffsets = '';
17005 var glyphsIds = '';
17006 var bias = 0;
17007
17008 var range, start, end, codes;
17009 for (i = 0, ii = bmpLength; i < ii; i++) {
17010 range = ranges[i];
17011 start = range[0];
17012 end = range[1];
17013 startCount += string16(start);
17014 endCount += string16(end);
17015 codes = range[2];
17016 var contiguous = true;
17017 for (j = 1, jj = codes.length; j < jj; ++j) {
17018 if (codes[j] !== codes[j - 1] + 1) {
17019 contiguous = false;
17020 break;
17021 }
17022 }
17023 if (!contiguous) {
17024 var offset = (segCount - i) * 2 + bias * 2;
17025 bias += (end - start + 1);
17026
17027 idDeltas += string16(0);
17028 idRangeOffsets += string16(offset);
17029
17030 for (j = 0, jj = codes.length; j < jj; ++j) {
17031 glyphsIds += string16(codes[j]);
17032 }
17033 } else {
17034 var startCode = codes[0];
17035
17036 idDeltas += string16((startCode - start) & 0xFFFF);
17037 idRangeOffsets += string16(0);
17038 }
17039 }
17040
17041 if (trailingRangesCount > 0) {
17042 endCount += '\xFF\xFF';
17043 startCount += '\xFF\xFF';
17044 idDeltas += '\x00\x01';
17045 idRangeOffsets += '\x00\x00';
17046 }
17047
17048 var format314 = '\x00\x00' + // language
17049 string16(2 * segCount) +
17050 string16(searchParams.range) +
17051 string16(searchParams.entry) +
17052 string16(searchParams.rangeShift) +
17053 endCount + '\x00\x00' + startCount +
17054 idDeltas + idRangeOffsets + glyphsIds;
17055
17056 var format31012 = '';
17057 var header31012 = '';
17058 if (numTables > 1) {
17059 cmap += '\x00\x03' + // platformID
17060 '\x00\x0A' + // encodingID
17061 string32(4 + numTables * 8 +
17062 4 + format314.length); // start of the table record
17063 format31012 = '';
17064 for (i = 0, ii = ranges.length; i < ii; i++) {
17065 range = ranges[i];
17066 start = range[0];
17067 codes = range[2];
17068 var code = codes[0];
17069 for (j = 1, jj = codes.length; j < jj; ++j) {
17070 if (codes[j] !== codes[j - 1] + 1) {
17071 end = range[0] + j - 1;
17072 format31012 += string32(start) + // startCharCode
17073 string32(end) + // endCharCode
17074 string32(code); // startGlyphID
17075 start = end + 1;
17076 code = codes[j];
17077 }
17078 }
17079 format31012 += string32(start) + // startCharCode
17080 string32(range[1]) + // endCharCode
17081 string32(code); // startGlyphID
17082 }
17083 header31012 = '\x00\x0C' + // format
17084 '\x00\x00' + // reserved
17085 string32(format31012.length + 16) + // length
17086 '\x00\x00\x00\x00' + // language
17087 string32(format31012.length / 12); // nGroups
17088 }
17089
17090 return cmap + '\x00\x04' + // format
17091 string16(format314.length + 4) + // length
17092 format314 + header31012 + format31012;
17093 }
17094
17095 function validateOS2Table(os2) {
17096 var stream = new Stream(os2.data);
17097 var version = stream.getUint16();
17098 // TODO verify all OS/2 tables fields, but currently we validate only those
17099 // that give us issues
17100 stream.getBytes(60); // skipping type, misc sizes, panose, unicode ranges
17101 var selection = stream.getUint16();
17102 if (version < 4 && (selection & 0x0300)) {
17103 return false;
17104 }
17105 var firstChar = stream.getUint16();
17106 var lastChar = stream.getUint16();
17107 if (firstChar > lastChar) {
17108 return false;
17109 }
17110 stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap
17111 var usWinAscent = stream.getUint16();
17112 if (usWinAscent === 0) { // makes font unreadable by windows
17113 return false;
17114 }
17115
17116 // OS/2 appears to be valid, resetting some fields
17117 os2.data[8] = os2.data[9] = 0; // IE rejects fonts if fsType != 0
17118 return true;
17119 }
17120
17121 function createOS2Table(properties, charstrings, override) {
17122 override = override || {
17123 unitsPerEm: 0,
17124 yMax: 0,
17125 yMin: 0,
17126 ascent: 0,
17127 descent: 0
17128 };
17129
17130 var ulUnicodeRange1 = 0;
17131 var ulUnicodeRange2 = 0;
17132 var ulUnicodeRange3 = 0;
17133 var ulUnicodeRange4 = 0;
17134
17135 var firstCharIndex = null;
17136 var lastCharIndex = 0;
17137
17138 if (charstrings) {
17139 for (var code in charstrings) {
17140 code |= 0;
17141 if (firstCharIndex > code || !firstCharIndex) {
17142 firstCharIndex = code;
17143 }
17144 if (lastCharIndex < code) {
17145 lastCharIndex = code;
17146 }
17147
17148 var position = getUnicodeRangeFor(code);
17149 if (position < 32) {
17150 ulUnicodeRange1 |= 1 << position;
17151 } else if (position < 64) {
17152 ulUnicodeRange2 |= 1 << position - 32;
17153 } else if (position < 96) {
17154 ulUnicodeRange3 |= 1 << position - 64;
17155 } else if (position < 123) {
17156 ulUnicodeRange4 |= 1 << position - 96;
17157 } else {
17158 error('Unicode ranges Bits > 123 are reserved for internal usage');
17159 }
17160 }
17161 } else {
17162 // TODO
17163 firstCharIndex = 0;
17164 lastCharIndex = 255;
17165 }
17166
17167 var bbox = properties.bbox || [0, 0, 0, 0];
17168 var unitsPerEm = (override.unitsPerEm ||
17169 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0]);
17170
17171 // if the font units differ to the PDF glyph space units
17172 // then scale up the values
17173 var scale = (properties.ascentScaled ? 1.0 :
17174 unitsPerEm / PDF_GLYPH_SPACE_UNITS);
17175
17176 var typoAscent = (override.ascent ||
17177 Math.round(scale * (properties.ascent || bbox[3])));
17178 var typoDescent = (override.descent ||
17179 Math.round(scale * (properties.descent || bbox[1])));
17180 if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) {
17181 typoDescent = -typoDescent; // fixing incorrect descent
17182 }
17183 var winAscent = override.yMax || typoAscent;
17184 var winDescent = -override.yMin || -typoDescent;
17185
17186 return '\x00\x03' + // version
17187 '\x02\x24' + // xAvgCharWidth
17188 '\x01\xF4' + // usWeightClass
17189 '\x00\x05' + // usWidthClass
17190 '\x00\x00' + // fstype (0 to let the font loads via font-face on IE)
17191 '\x02\x8A' + // ySubscriptXSize
17192 '\x02\xBB' + // ySubscriptYSize
17193 '\x00\x00' + // ySubscriptXOffset
17194 '\x00\x8C' + // ySubscriptYOffset
17195 '\x02\x8A' + // ySuperScriptXSize
17196 '\x02\xBB' + // ySuperScriptYSize
17197 '\x00\x00' + // ySuperScriptXOffset
17198 '\x01\xDF' + // ySuperScriptYOffset
17199 '\x00\x31' + // yStrikeOutSize
17200 '\x01\x02' + // yStrikeOutPosition
17201 '\x00\x00' + // sFamilyClass
17202 '\x00\x00\x06' +
17203 String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) +
17204 '\x00\x00\x00\x00\x00\x00' + // Panose
17205 string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31)
17206 string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63)
17207 string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95)
17208 string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127)
17209 '\x2A\x32\x31\x2A' + // achVendID
17210 string16(properties.italicAngle ? 1 : 0) + // fsSelection
17211 string16(firstCharIndex ||
17212 properties.firstChar) + // usFirstCharIndex
17213 string16(lastCharIndex || properties.lastChar) + // usLastCharIndex
17214 string16(typoAscent) + // sTypoAscender
17215 string16(typoDescent) + // sTypoDescender
17216 '\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value)
17217 string16(winAscent) + // usWinAscent
17218 string16(winDescent) + // usWinDescent
17219 '\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31)
17220 '\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63)
17221 string16(properties.xHeight) + // sxHeight
17222 string16(properties.capHeight) + // sCapHeight
17223 string16(0) + // usDefaultChar
17224 string16(firstCharIndex || properties.firstChar) + // usBreakChar
17225 '\x00\x03'; // usMaxContext
17226 }
17227
17228 function createPostTable(properties) {
17229 var angle = Math.floor(properties.italicAngle * (Math.pow(2, 16)));
17230 return ('\x00\x03\x00\x00' + // Version number
17231 string32(angle) + // italicAngle
17232 '\x00\x00' + // underlinePosition
17233 '\x00\x00' + // underlineThickness
17234 string32(properties.fixedPitch) + // isFixedPitch
17235 '\x00\x00\x00\x00' + // minMemType42
17236 '\x00\x00\x00\x00' + // maxMemType42
17237 '\x00\x00\x00\x00' + // minMemType1
17238 '\x00\x00\x00\x00'); // maxMemType1
17239 }
17240
17241 function createNameTable(name, proto) {
17242 if (!proto) {
17243 proto = [[], []]; // no strings and unicode strings
17244 }
17245
17246 var strings = [
17247 proto[0][0] || 'Original licence', // 0.Copyright
17248 proto[0][1] || name, // 1.Font family
17249 proto[0][2] || 'Unknown', // 2.Font subfamily (font weight)
17250 proto[0][3] || 'uniqueID', // 3.Unique ID
17251 proto[0][4] || name, // 4.Full font name
17252 proto[0][5] || 'Version 0.11', // 5.Version
17253 proto[0][6] || '', // 6.Postscript name
17254 proto[0][7] || 'Unknown', // 7.Trademark
17255 proto[0][8] || 'Unknown', // 8.Manufacturer
17256 proto[0][9] || 'Unknown' // 9.Designer
17257 ];
17258
17259 // Mac want 1-byte per character strings while Windows want
17260 // 2-bytes per character, so duplicate the names table
17261 var stringsUnicode = [];
17262 var i, ii, j, jj, str;
17263 for (i = 0, ii = strings.length; i < ii; i++) {
17264 str = proto[1][i] || strings[i];
17265
17266 var strBufUnicode = [];
17267 for (j = 0, jj = str.length; j < jj; j++) {
17268 strBufUnicode.push(string16(str.charCodeAt(j)));
17269 }
17270 stringsUnicode.push(strBufUnicode.join(''));
17271 }
17272
17273 var names = [strings, stringsUnicode];
17274 var platforms = ['\x00\x01', '\x00\x03'];
17275 var encodings = ['\x00\x00', '\x00\x01'];
17276 var languages = ['\x00\x00', '\x04\x09'];
17277
17278 var namesRecordCount = strings.length * platforms.length;
17279 var nameTable =
17280 '\x00\x00' + // format
17281 string16(namesRecordCount) + // Number of names Record
17282 string16(namesRecordCount * 12 + 6); // Storage
17283
17284 // Build the name records field
17285 var strOffset = 0;
17286 for (i = 0, ii = platforms.length; i < ii; i++) {
17287 var strs = names[i];
17288 for (j = 0, jj = strs.length; j < jj; j++) {
17289 str = strs[j];
17290 var nameRecord =
17291 platforms[i] + // platform ID
17292 encodings[i] + // encoding ID
17293 languages[i] + // language ID
17294 string16(j) + // name ID
17295 string16(str.length) +
17296 string16(strOffset);
17297 nameTable += nameRecord;
17298 strOffset += str.length;
17299 }
17300 }
17301
17302 nameTable += strings.join('') + stringsUnicode.join('');
17303 return nameTable;
17304 }
17305
17306 Font.prototype = {
17307 name: null,
17308 font: null,
17309 mimetype: null,
17310 encoding: null,
17311 get renderer() {
17312 var renderer = FontRendererFactory.create(this);
17313 return shadow(this, 'renderer', renderer);
17314 },
17315
17316 exportData: function Font_exportData() {
17317 var data = {};
17318 for (var i in this) {
17319 if (this.hasOwnProperty(i)) {
17320 data[i] = this[i];
17321 }
17322 }
17323 return data;
17324 },
17325
17326 checkAndRepair: function Font_checkAndRepair(name, font, properties) {
17327 function readTableEntry(file) {
17328 var tag = bytesToString(file.getBytes(4));
17329
17330 var checksum = file.getInt32();
17331 var offset = file.getInt32() >>> 0;
17332 var length = file.getInt32() >>> 0;
17333
17334 // Read the table associated data
17335 var previousPosition = file.pos;
17336 file.pos = file.start ? file.start : 0;
17337 file.skip(offset);
17338 var data = file.getBytes(length);
17339 file.pos = previousPosition;
17340
17341 if (tag === 'head') {
17342 // clearing checksum adjustment
17343 data[8] = data[9] = data[10] = data[11] = 0;
17344 data[17] |= 0x20; //Set font optimized for cleartype flag
17345 }
17346
17347 return {
17348 tag: tag,
17349 checksum: checksum,
17350 length: length,
17351 offset: offset,
17352 data: data
17353 };
17354 }
17355
17356 function readOpenTypeHeader(ttf) {
17357 return {
17358 version: bytesToString(ttf.getBytes(4)),
17359 numTables: ttf.getUint16(),
17360 searchRange: ttf.getUint16(),
17361 entrySelector: ttf.getUint16(),
17362 rangeShift: ttf.getUint16()
17363 };
17364 }
17365
17366 /**
17367 * Read the appropriate subtable from the cmap according to 9.6.6.4 from
17368 * PDF spec
17369 */
17370 function readCmapTable(cmap, font, isSymbolicFont) {
17371 var segment;
17372 var start = (font.start ? font.start : 0) + cmap.offset;
17373 font.pos = start;
17374
17375 var version = font.getUint16();
17376 var numTables = font.getUint16();
17377
17378 var potentialTable;
17379 var canBreak = false;
17380 // There's an order of preference in terms of which cmap subtable to
17381 // use:
17382 // - non-symbolic fonts the preference is a 3,1 table then a 1,0 table
17383 // - symbolic fonts the preference is a 3,0 table then a 1,0 table
17384 // The following takes advantage of the fact that the tables are sorted
17385 // to work.
17386 for (var i = 0; i < numTables; i++) {
17387 var platformId = font.getUint16();
17388 var encodingId = font.getUint16();
17389 var offset = font.getInt32() >>> 0;
17390 var useTable = false;
17391
17392 if (platformId === 0 && encodingId === 0) {
17393 useTable = true;
17394 // Continue the loop since there still may be a higher priority
17395 // table.
17396 } else if (platformId === 1 && encodingId === 0) {
17397 useTable = true;
17398 // Continue the loop since there still may be a higher priority
17399 // table.
17400 } else if (platformId === 3 && encodingId === 1 &&
17401 (!isSymbolicFont || !potentialTable)) {
17402 useTable = true;
17403 if (!isSymbolicFont) {
17404 canBreak = true;
17405 }
17406 } else if (isSymbolicFont && platformId === 3 && encodingId === 0) {
17407 useTable = true;
17408 canBreak = true;
17409 }
17410
17411 if (useTable) {
17412 potentialTable = {
17413 platformId: platformId,
17414 encodingId: encodingId,
17415 offset: offset
17416 };
17417 }
17418 if (canBreak) {
17419 break;
17420 }
17421 }
17422
17423 if (!potentialTable) {
17424 warn('Could not find a preferred cmap table.');
17425 return {
17426 platformId: -1,
17427 encodingId: -1,
17428 mappings: [],
17429 hasShortCmap: false
17430 };
17431 }
17432
17433 font.pos = start + potentialTable.offset;
17434 var format = font.getUint16();
17435 var length = font.getUint16();
17436 var language = font.getUint16();
17437
17438 var hasShortCmap = false;
17439 var mappings = [];
17440 var j, glyphId;
17441
17442 // TODO(mack): refactor this cmap subtable reading logic out
17443 if (format === 0) {
17444 for (j = 0; j < 256; j++) {
17445 var index = font.getByte();
17446 if (!index) {
17447 continue;
17448 }
17449 mappings.push({
17450 charCode: j,
17451 glyphId: index
17452 });
17453 }
17454 hasShortCmap = true;
17455 } else if (format === 4) {
17456 // re-creating the table in format 4 since the encoding
17457 // might be changed
17458 var segCount = (font.getUint16() >> 1);
17459 font.getBytes(6); // skipping range fields
17460 var segIndex, segments = [];
17461 for (segIndex = 0; segIndex < segCount; segIndex++) {
17462 segments.push({ end: font.getUint16() });
17463 }
17464 font.getUint16();
17465 for (segIndex = 0; segIndex < segCount; segIndex++) {
17466 segments[segIndex].start = font.getUint16();
17467 }
17468
17469 for (segIndex = 0; segIndex < segCount; segIndex++) {
17470 segments[segIndex].delta = font.getUint16();
17471 }
17472
17473 var offsetsCount = 0;
17474 for (segIndex = 0; segIndex < segCount; segIndex++) {
17475 segment = segments[segIndex];
17476 var rangeOffset = font.getUint16();
17477 if (!rangeOffset) {
17478 segment.offsetIndex = -1;
17479 continue;
17480 }
17481
17482 var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
17483 segment.offsetIndex = offsetIndex;
17484 offsetsCount = Math.max(offsetsCount, offsetIndex +
17485 segment.end - segment.start + 1);
17486 }
17487
17488 var offsets = [];
17489 for (j = 0; j < offsetsCount; j++) {
17490 offsets.push(font.getUint16());
17491 }
17492
17493 for (segIndex = 0; segIndex < segCount; segIndex++) {
17494 segment = segments[segIndex];
17495 start = segment.start;
17496 var end = segment.end;
17497 var delta = segment.delta;
17498 offsetIndex = segment.offsetIndex;
17499
17500 for (j = start; j <= end; j++) {
17501 if (j === 0xFFFF) {
17502 continue;
17503 }
17504
17505 glyphId = (offsetIndex < 0 ?
17506 j : offsets[offsetIndex + j - start]);
17507 glyphId = (glyphId + delta) & 0xFFFF;
17508 if (glyphId === 0) {
17509 continue;
17510 }
17511 mappings.push({
17512 charCode: j,
17513 glyphId: glyphId
17514 });
17515 }
17516 }
17517 } else if (format === 6) {
17518 // Format 6 is a 2-bytes dense mapping, which means the font data
17519 // lives glue together even if they are pretty far in the unicode
17520 // table. (This looks weird, so I can have missed something), this
17521 // works on Linux but seems to fails on Mac so let's rewrite the
17522 // cmap table to a 3-1-4 style
17523 var firstCode = font.getUint16();
17524 var entryCount = font.getUint16();
17525
17526 for (j = 0; j < entryCount; j++) {
17527 glyphId = font.getUint16();
17528 var charCode = firstCode + j;
17529
17530 mappings.push({
17531 charCode: charCode,
17532 glyphId: glyphId
17533 });
17534 }
17535 } else {
17536 error('cmap table has unsupported format: ' + format);
17537 }
17538
17539 // removing duplicate entries
17540 mappings.sort(function (a, b) {
17541 return a.charCode - b.charCode;
17542 });
17543 for (i = 1; i < mappings.length; i++) {
17544 if (mappings[i - 1].charCode === mappings[i].charCode) {
17545 mappings.splice(i, 1);
17546 i--;
17547 }
17548 }
17549
17550 return {
17551 platformId: potentialTable.platformId,
17552 encodingId: potentialTable.encodingId,
17553 mappings: mappings,
17554 hasShortCmap: hasShortCmap
17555 };
17556 }
17557
17558 function sanitizeMetrics(font, header, metrics, numGlyphs) {
17559 if (!header) {
17560 if (metrics) {
17561 metrics.data = null;
17562 }
17563 return;
17564 }
17565
17566 font.pos = (font.start ? font.start : 0) + header.offset;
17567 font.pos += header.length - 2;
17568 var numOfMetrics = font.getUint16();
17569
17570 if (numOfMetrics > numGlyphs) {
17571 info('The numOfMetrics (' + numOfMetrics + ') should not be ' +
17572 'greater than the numGlyphs (' + numGlyphs + ')');
17573 // Reduce numOfMetrics if it is greater than numGlyphs
17574 numOfMetrics = numGlyphs;
17575 header.data[34] = (numOfMetrics & 0xff00) >> 8;
17576 header.data[35] = numOfMetrics & 0x00ff;
17577 }
17578
17579 var numOfSidebearings = numGlyphs - numOfMetrics;
17580 var numMissing = numOfSidebearings -
17581 ((metrics.length - numOfMetrics * 4) >> 1);
17582
17583 if (numMissing > 0) {
17584 // For each missing glyph, we set both the width and lsb to 0 (zero).
17585 // Since we need to add two properties for each glyph, this explains
17586 // the use of |numMissing * 2| when initializing the typed array.
17587 var entries = new Uint8Array(metrics.length + numMissing * 2);
17588 entries.set(metrics.data);
17589 metrics.data = entries;
17590 }
17591 }
17592
17593 function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart,
17594 hintsValid) {
17595 if (sourceEnd - sourceStart <= 12) {
17596 // glyph with data less than 12 is invalid one
17597 return 0;
17598 }
17599 var glyf = source.subarray(sourceStart, sourceEnd);
17600 var contoursCount = (glyf[0] << 8) | glyf[1];
17601 if (contoursCount & 0x8000) {
17602 // complex glyph, writing as is
17603 dest.set(glyf, destStart);
17604 return glyf.length;
17605 }
17606
17607 var i, j = 10, flagsCount = 0;
17608 for (i = 0; i < contoursCount; i++) {
17609 var endPoint = (glyf[j] << 8) | glyf[j + 1];
17610 flagsCount = endPoint + 1;
17611 j += 2;
17612 }
17613 // skipping instructions
17614 var instructionsStart = j;
17615 var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
17616 j += 2 + instructionsLength;
17617 var instructionsEnd = j;
17618 // validating flags
17619 var coordinatesLength = 0;
17620 for (i = 0; i < flagsCount; i++) {
17621 var flag = glyf[j++];
17622 if (flag & 0xC0) {
17623 // reserved flags must be zero, cleaning up
17624 glyf[j - 1] = flag & 0x3F;
17625 }
17626 var xyLength = ((flag & 2) ? 1 : (flag & 16) ? 0 : 2) +
17627 ((flag & 4) ? 1 : (flag & 32) ? 0 : 2);
17628 coordinatesLength += xyLength;
17629 if (flag & 8) {
17630 var repeat = glyf[j++];
17631 i += repeat;
17632 coordinatesLength += repeat * xyLength;
17633 }
17634 }
17635 // glyph without coordinates will be rejected
17636 if (coordinatesLength === 0) {
17637 return 0;
17638 }
17639 var glyphDataLength = j + coordinatesLength;
17640 if (glyphDataLength > glyf.length) {
17641 // not enough data for coordinates
17642 return 0;
17643 }
17644 if (!hintsValid && instructionsLength > 0) {
17645 dest.set(glyf.subarray(0, instructionsStart), destStart);
17646 dest.set([0, 0], destStart + instructionsStart);
17647 dest.set(glyf.subarray(instructionsEnd, glyphDataLength),
17648 destStart + instructionsStart + 2);
17649 glyphDataLength -= instructionsLength;
17650 if (glyf.length - glyphDataLength > 3) {
17651 glyphDataLength = (glyphDataLength + 3) & ~3;
17652 }
17653 return glyphDataLength;
17654 }
17655 if (glyf.length - glyphDataLength > 3) {
17656 // truncating and aligning to 4 bytes the long glyph data
17657 glyphDataLength = (glyphDataLength + 3) & ~3;
17658 dest.set(glyf.subarray(0, glyphDataLength), destStart);
17659 return glyphDataLength;
17660 }
17661 // glyph data is fine
17662 dest.set(glyf, destStart);
17663 return glyf.length;
17664 }
17665
17666 function sanitizeHead(head, numGlyphs, locaLength) {
17667 var data = head.data;
17668
17669 // Validate version:
17670 // Should always be 0x00010000
17671 var version = int32(data[0], data[1], data[2], data[3]);
17672 if (version >> 16 !== 1) {
17673 info('Attempting to fix invalid version in head table: ' + version);
17674 data[0] = 0;
17675 data[1] = 1;
17676 data[2] = 0;
17677 data[3] = 0;
17678 }
17679
17680 var indexToLocFormat = int16(data[50], data[51]);
17681 if (indexToLocFormat < 0 || indexToLocFormat > 1) {
17682 info('Attempting to fix invalid indexToLocFormat in head table: ' +
17683 indexToLocFormat);
17684
17685 // The value of indexToLocFormat should be 0 if the loca table
17686 // consists of short offsets, and should be 1 if the loca table
17687 // consists of long offsets.
17688 //
17689 // The number of entries in the loca table should be numGlyphs + 1.
17690 //
17691 // Using this information, we can work backwards to deduce if the
17692 // size of each offset in the loca table, and thus figure out the
17693 // appropriate value for indexToLocFormat.
17694
17695 var numGlyphsPlusOne = numGlyphs + 1;
17696 if (locaLength === numGlyphsPlusOne << 1) {
17697 // 0x0000 indicates the loca table consists of short offsets
17698 data[50] = 0;
17699 data[51] = 0;
17700 } else if (locaLength === numGlyphsPlusOne << 2) {
17701 // 0x0001 indicates the loca table consists of long offsets
17702 data[50] = 0;
17703 data[51] = 1;
17704 } else {
17705 warn('Could not fix indexToLocFormat: ' + indexToLocFormat);
17706 }
17707 }
17708 }
17709
17710 function sanitizeGlyphLocations(loca, glyf, numGlyphs,
17711 isGlyphLocationsLong, hintsValid,
17712 dupFirstEntry) {
17713 var itemSize, itemDecode, itemEncode;
17714 if (isGlyphLocationsLong) {
17715 itemSize = 4;
17716 itemDecode = function fontItemDecodeLong(data, offset) {
17717 return (data[offset] << 24) | (data[offset + 1] << 16) |
17718 (data[offset + 2] << 8) | data[offset + 3];
17719 };
17720 itemEncode = function fontItemEncodeLong(data, offset, value) {
17721 data[offset] = (value >>> 24) & 0xFF;
17722 data[offset + 1] = (value >> 16) & 0xFF;
17723 data[offset + 2] = (value >> 8) & 0xFF;
17724 data[offset + 3] = value & 0xFF;
17725 };
17726 } else {
17727 itemSize = 2;
17728 itemDecode = function fontItemDecode(data, offset) {
17729 return (data[offset] << 9) | (data[offset + 1] << 1);
17730 };
17731 itemEncode = function fontItemEncode(data, offset, value) {
17732 data[offset] = (value >> 9) & 0xFF;
17733 data[offset + 1] = (value >> 1) & 0xFF;
17734 };
17735 }
17736 var locaData = loca.data;
17737 var locaDataSize = itemSize * (1 + numGlyphs);
17738 // is loca.data too short or long?
17739 if (locaData.length !== locaDataSize) {
17740 locaData = new Uint8Array(locaDataSize);
17741 locaData.set(loca.data.subarray(0, locaDataSize));
17742 loca.data = locaData;
17743 }
17744 // removing the invalid glyphs
17745 var oldGlyfData = glyf.data;
17746 var oldGlyfDataLength = oldGlyfData.length;
17747 var newGlyfData = new Uint8Array(oldGlyfDataLength);
17748 var startOffset = itemDecode(locaData, 0);
17749 var writeOffset = 0;
17750 var missingGlyphData = {};
17751 itemEncode(locaData, 0, writeOffset);
17752 var i, j;
17753 for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
17754 var endOffset = itemDecode(locaData, j);
17755 if (endOffset > oldGlyfDataLength &&
17756 ((oldGlyfDataLength + 3) & ~3) === endOffset) {
17757 // Aspose breaks fonts by aligning the glyphs to the qword, but not
17758 // the glyf table size, which makes last glyph out of range.
17759 endOffset = oldGlyfDataLength;
17760 }
17761 if (endOffset > oldGlyfDataLength) {
17762 // glyph end offset points outside glyf data, rejecting the glyph
17763 itemEncode(locaData, j, writeOffset);
17764 startOffset = endOffset;
17765 continue;
17766 }
17767
17768 if (startOffset === endOffset) {
17769 missingGlyphData[i] = true;
17770 }
17771
17772 var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
17773 newGlyfData, writeOffset, hintsValid);
17774 writeOffset += newLength;
17775 itemEncode(locaData, j, writeOffset);
17776 startOffset = endOffset;
17777 }
17778
17779 if (writeOffset === 0) {
17780 // glyf table cannot be empty -- redoing the glyf and loca tables
17781 // to have single glyph with one point
17782 var simpleGlyph = new Uint8Array(
17783 [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]);
17784 for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
17785 itemEncode(locaData, j, simpleGlyph.length);
17786 }
17787 glyf.data = simpleGlyph;
17788 return missingGlyphData;
17789 }
17790
17791 if (dupFirstEntry) {
17792 var firstEntryLength = itemDecode(locaData, itemSize);
17793 if (newGlyfData.length > firstEntryLength + writeOffset) {
17794 glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset);
17795 } else {
17796 glyf.data = new Uint8Array(firstEntryLength + writeOffset);
17797 glyf.data.set(newGlyfData.subarray(0, writeOffset));
17798 }
17799 glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset);
17800 itemEncode(loca.data, locaData.length - itemSize,
17801 writeOffset + firstEntryLength);
17802 } else {
17803 glyf.data = newGlyfData.subarray(0, writeOffset);
17804 }
17805 return missingGlyphData;
17806 }
17807
17808 function readPostScriptTable(post, properties, maxpNumGlyphs) {
17809 var start = (font.start ? font.start : 0) + post.offset;
17810 font.pos = start;
17811
17812 var length = post.length, end = start + length;
17813 var version = font.getInt32();
17814 // skip rest to the tables
17815 font.getBytes(28);
17816
17817 var glyphNames;
17818 var valid = true;
17819 var i;
17820
17821 switch (version) {
17822 case 0x00010000:
17823 glyphNames = MacStandardGlyphOrdering;
17824 break;
17825 case 0x00020000:
17826 var numGlyphs = font.getUint16();
17827 if (numGlyphs !== maxpNumGlyphs) {
17828 valid = false;
17829 break;
17830 }
17831 var glyphNameIndexes = [];
17832 for (i = 0; i < numGlyphs; ++i) {
17833 var index = font.getUint16();
17834 if (index >= 32768) {
17835 valid = false;
17836 break;
17837 }
17838 glyphNameIndexes.push(index);
17839 }
17840 if (!valid) {
17841 break;
17842 }
17843 var customNames = [];
17844 var strBuf = [];
17845 while (font.pos < end) {
17846 var stringLength = font.getByte();
17847 strBuf.length = stringLength;
17848 for (i = 0; i < stringLength; ++i) {
17849 strBuf[i] = String.fromCharCode(font.getByte());
17850 }
17851 customNames.push(strBuf.join(''));
17852 }
17853 glyphNames = [];
17854 for (i = 0; i < numGlyphs; ++i) {
17855 var j = glyphNameIndexes[i];
17856 if (j < 258) {
17857 glyphNames.push(MacStandardGlyphOrdering[j]);
17858 continue;
17859 }
17860 glyphNames.push(customNames[j - 258]);
17861 }
17862 break;
17863 case 0x00030000:
17864 break;
17865 default:
17866 warn('Unknown/unsupported post table version ' + version);
17867 valid = false;
17868 break;
17869 }
17870 properties.glyphNames = glyphNames;
17871 return valid;
17872 }
17873
17874 function readNameTable(nameTable) {
17875 var start = (font.start ? font.start : 0) + nameTable.offset;
17876 font.pos = start;
17877
17878 var names = [[], []];
17879 var length = nameTable.length, end = start + length;
17880 var format = font.getUint16();
17881 var FORMAT_0_HEADER_LENGTH = 6;
17882 if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) {
17883 // unsupported name table format or table "too" small
17884 return names;
17885 }
17886 var numRecords = font.getUint16();
17887 var stringsStart = font.getUint16();
17888 var records = [];
17889 var NAME_RECORD_LENGTH = 12;
17890 var i, ii;
17891
17892 for (i = 0; i < numRecords &&
17893 font.pos + NAME_RECORD_LENGTH <= end; i++) {
17894 var r = {
17895 platform: font.getUint16(),
17896 encoding: font.getUint16(),
17897 language: font.getUint16(),
17898 name: font.getUint16(),
17899 length: font.getUint16(),
17900 offset: font.getUint16()
17901 };
17902 // using only Macintosh and Windows platform/encoding names
17903 if ((r.platform === 1 && r.encoding === 0 && r.language === 0) ||
17904 (r.platform === 3 && r.encoding === 1 && r.language === 0x409)) {
17905 records.push(r);
17906 }
17907 }
17908 for (i = 0, ii = records.length; i < ii; i++) {
17909 var record = records[i];
17910 var pos = start + stringsStart + record.offset;
17911 if (pos + record.length > end) {
17912 continue; // outside of name table, ignoring
17913 }
17914 font.pos = pos;
17915 var nameIndex = record.name;
17916 if (record.encoding) {
17917 // unicode
17918 var str = '';
17919 for (var j = 0, jj = record.length; j < jj; j += 2) {
17920 str += String.fromCharCode(font.getUint16());
17921 }
17922 names[1][nameIndex] = str;
17923 } else {
17924 names[0][nameIndex] = bytesToString(font.getBytes(record.length));
17925 }
17926 }
17927 return names;
17928 }
17929
17930 var TTOpsStackDeltas = [
17931 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,
17932 -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,
17933 1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1,
17934 0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2,
17935 0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1,
17936 -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1,
17937 -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17938 -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1,
17939 -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2];
17940 // 0xC0-DF == -1 and 0xE0-FF == -2
17941
17942 function sanitizeTTProgram(table, ttContext) {
17943 var data = table.data;
17944 var i = 0, j, n, b, funcId, pc, lastEndf = 0, lastDeff = 0;
17945 var stack = [];
17946 var callstack = [];
17947 var functionsCalled = [];
17948 var tooComplexToFollowFunctions =
17949 ttContext.tooComplexToFollowFunctions;
17950 var inFDEF = false, ifLevel = 0, inELSE = 0;
17951 for (var ii = data.length; i < ii;) {
17952 var op = data[i++];
17953 // The TrueType instruction set docs can be found at
17954 // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html
17955 if (op === 0x40) { // NPUSHB - pushes n bytes
17956 n = data[i++];
17957 if (inFDEF || inELSE) {
17958 i += n;
17959 } else {
17960 for (j = 0; j < n; j++) {
17961 stack.push(data[i++]);
17962 }
17963 }
17964 } else if (op === 0x41) { // NPUSHW - pushes n words
17965 n = data[i++];
17966 if (inFDEF || inELSE) {
17967 i += n * 2;
17968 } else {
17969 for (j = 0; j < n; j++) {
17970 b = data[i++];
17971 stack.push((b << 8) | data[i++]);
17972 }
17973 }
17974 } else if ((op & 0xF8) === 0xB0) { // PUSHB - pushes bytes
17975 n = op - 0xB0 + 1;
17976 if (inFDEF || inELSE) {
17977 i += n;
17978 } else {
17979 for (j = 0; j < n; j++) {
17980 stack.push(data[i++]);
17981 }
17982 }
17983 } else if ((op & 0xF8) === 0xB8) { // PUSHW - pushes words
17984 n = op - 0xB8 + 1;
17985 if (inFDEF || inELSE) {
17986 i += n * 2;
17987 } else {
17988 for (j = 0; j < n; j++) {
17989 b = data[i++];
17990 stack.push((b << 8) | data[i++]);
17991 }
17992 }
17993 } else if (op === 0x2B && !tooComplexToFollowFunctions) { // CALL
17994 if (!inFDEF && !inELSE) {
17995 // collecting inforamtion about which functions are used
17996 funcId = stack[stack.length - 1];
17997 ttContext.functionsUsed[funcId] = true;
17998 if (funcId in ttContext.functionsStackDeltas) {
17999 stack.length += ttContext.functionsStackDeltas[funcId];
18000 } else if (funcId in ttContext.functionsDefined &&
18001 functionsCalled.indexOf(funcId) < 0) {
18002 callstack.push({data: data, i: i, stackTop: stack.length - 1});
18003 functionsCalled.push(funcId);
18004 pc = ttContext.functionsDefined[funcId];
18005 if (!pc) {
18006 warn('TT: CALL non-existent function');
18007 ttContext.hintsValid = false;
18008 return;
18009 }
18010 data = pc.data;
18011 i = pc.i;
18012 }
18013 }
18014 } else if (op === 0x2C && !tooComplexToFollowFunctions) { // FDEF
18015 if (inFDEF || inELSE) {
18016 warn('TT: nested FDEFs not allowed');
18017 tooComplexToFollowFunctions = true;
18018 }
18019 inFDEF = true;
18020 // collecting inforamtion about which functions are defined
18021 lastDeff = i;
18022 funcId = stack.pop();
18023 ttContext.functionsDefined[funcId] = {data: data, i: i};
18024 } else if (op === 0x2D) { // ENDF - end of function
18025 if (inFDEF) {
18026 inFDEF = false;
18027 lastEndf = i;
18028 } else {
18029 pc = callstack.pop();
18030 if (!pc) {
18031 warn('TT: ENDF bad stack');
18032 ttContext.hintsValid = false;
18033 return;
18034 }
18035 funcId = functionsCalled.pop();
18036 data = pc.data;
18037 i = pc.i;
18038 ttContext.functionsStackDeltas[funcId] =
18039 stack.length - pc.stackTop;
18040 }
18041 } else if (op === 0x89) { // IDEF - instruction definition
18042 if (inFDEF || inELSE) {
18043 warn('TT: nested IDEFs not allowed');
18044 tooComplexToFollowFunctions = true;
18045 }
18046 inFDEF = true;
18047 // recording it as a function to track ENDF
18048 lastDeff = i;
18049 } else if (op === 0x58) { // IF
18050 ++ifLevel;
18051 } else if (op === 0x1B) { // ELSE
18052 inELSE = ifLevel;
18053 } else if (op === 0x59) { // EIF
18054 if (inELSE === ifLevel) {
18055 inELSE = 0;
18056 }
18057 --ifLevel;
18058 } else if (op === 0x1C) { // JMPR
18059 if (!inFDEF && !inELSE) {
18060 var offset = stack[stack.length - 1];
18061 // only jumping forward to prevent infinite loop
18062 if (offset > 0) {
18063 i += offset - 1;
18064 }
18065 }
18066 }
18067 // Adjusting stack not extactly, but just enough to get function id
18068 if (!inFDEF && !inELSE) {
18069 var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] :
18070 op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0;
18071 if (op >= 0x71 && op <= 0x75) {
18072 n = stack.pop();
18073 if (n === n) {
18074 stackDelta = -n * 2;
18075 }
18076 }
18077 while (stackDelta < 0 && stack.length > 0) {
18078 stack.pop();
18079 stackDelta++;
18080 }
18081 while (stackDelta > 0) {
18082 stack.push(NaN); // pushing any number into stack
18083 stackDelta--;
18084 }
18085 }
18086 }
18087 ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions;
18088 var content = [data];
18089 if (i > data.length) {
18090 content.push(new Uint8Array(i - data.length));
18091 }
18092 if (lastDeff > lastEndf) {
18093 warn('TT: complementing a missing function tail');
18094 // new function definition started, but not finished
18095 // complete function by [CLEAR, ENDF]
18096 content.push(new Uint8Array([0x22, 0x2D]));
18097 }
18098 foldTTTable(table, content);
18099 }
18100
18101 function checkInvalidFunctions(ttContext, maxFunctionDefs) {
18102 if (ttContext.tooComplexToFollowFunctions) {
18103 return;
18104 }
18105 if (ttContext.functionsDefined.length > maxFunctionDefs) {
18106 warn('TT: more functions defined than expected');
18107 ttContext.hintsValid = false;
18108 return;
18109 }
18110 for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
18111 if (j > maxFunctionDefs) {
18112 warn('TT: invalid function id: ' + j);
18113 ttContext.hintsValid = false;
18114 return;
18115 }
18116 if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {
18117 warn('TT: undefined function: ' + j);
18118 ttContext.hintsValid = false;
18119 return;
18120 }
18121 }
18122 }
18123
18124 function foldTTTable(table, content) {
18125 if (content.length > 1) {
18126 // concatenating the content items
18127 var newLength = 0;
18128 var j, jj;
18129 for (j = 0, jj = content.length; j < jj; j++) {
18130 newLength += content[j].length;
18131 }
18132 newLength = (newLength + 3) & ~3;
18133 var result = new Uint8Array(newLength);
18134 var pos = 0;
18135 for (j = 0, jj = content.length; j < jj; j++) {
18136 result.set(content[j], pos);
18137 pos += content[j].length;
18138 }
18139 table.data = result;
18140 table.length = newLength;
18141 }
18142 }
18143
18144 function sanitizeTTPrograms(fpgm, prep, cvt) {
18145 var ttContext = {
18146 functionsDefined: [],
18147 functionsUsed: [],
18148 functionsStackDeltas: [],
18149 tooComplexToFollowFunctions: false,
18150 hintsValid: true
18151 };
18152 if (fpgm) {
18153 sanitizeTTProgram(fpgm, ttContext);
18154 }
18155 if (prep) {
18156 sanitizeTTProgram(prep, ttContext);
18157 }
18158 if (fpgm) {
18159 checkInvalidFunctions(ttContext, maxFunctionDefs);
18160 }
18161 if (cvt && (cvt.length & 1)) {
18162 var cvtData = new Uint8Array(cvt.length + 1);
18163 cvtData.set(cvt.data);
18164 cvt.data = cvtData;
18165 }
18166 return ttContext.hintsValid;
18167 }
18168
18169 // The following steps modify the original font data, making copy
18170 font = new Stream(new Uint8Array(font.getBytes()));
18171
18172 var VALID_TABLES = ['OS/2', 'cmap', 'head', 'hhea', 'hmtx', 'maxp',
18173 'name', 'post', 'loca', 'glyf', 'fpgm', 'prep', 'cvt ', 'CFF '];
18174
18175 var header = readOpenTypeHeader(font);
18176 var numTables = header.numTables;
18177 var cff, cffFile;
18178
18179 var tables = { 'OS/2': null, cmap: null, head: null, hhea: null,
18180 hmtx: null, maxp: null, name: null, post: null };
18181 var table;
18182 for (var i = 0; i < numTables; i++) {
18183 table = readTableEntry(font);
18184 if (VALID_TABLES.indexOf(table.tag) < 0) {
18185 continue; // skipping table if it's not a required or optional table
18186 }
18187 if (table.length === 0) {
18188 continue; // skipping empty tables
18189 }
18190 tables[table.tag] = table;
18191 }
18192
18193 var isTrueType = !tables['CFF '];
18194 if (!isTrueType) {
18195 // OpenType font
18196 if (header.version === 'OTTO' ||
18197 !tables.head || !tables.hhea || !tables.maxp || !tables.post) {
18198 // no major tables: throwing everything at CFFFont
18199 cffFile = new Stream(tables['CFF '].data);
18200 cff = new CFFFont(cffFile, properties);
18201
18202 return this.convert(name, cff, properties);
18203 }
18204
18205 delete tables.glyf;
18206 delete tables.loca;
18207 delete tables.fpgm;
18208 delete tables.prep;
18209 delete tables['cvt '];
18210 this.isOpenType = true;
18211 } else {
18212 if (!tables.glyf || !tables.loca) {
18213 error('Required "glyf" or "loca" tables are not found');
18214 }
18215 this.isOpenType = false;
18216 }
18217
18218 if (!tables.maxp) {
18219 error('Required "maxp" table is not found');
18220 }
18221
18222 font.pos = (font.start || 0) + tables.maxp.offset;
18223 var version = font.getInt32();
18224 var numGlyphs = font.getUint16();
18225 var maxFunctionDefs = 0;
18226 if (version >= 0x00010000 && tables.maxp.length >= 22) {
18227 // maxZones can be invalid
18228 font.pos += 8;
18229 var maxZones = font.getUint16();
18230 if (maxZones > 2) { // reset to 2 if font has invalid maxZones
18231 tables.maxp.data[14] = 0;
18232 tables.maxp.data[15] = 2;
18233 }
18234 font.pos += 4;
18235 maxFunctionDefs = font.getUint16();
18236 }
18237
18238 var dupFirstEntry = false;
18239 if (properties.type === 'CIDFontType2' && properties.toUnicode &&
18240 properties.toUnicode.get(0) > '\u0000') {
18241 // oracle's defect (see 3427), duplicating first entry
18242 dupFirstEntry = true;
18243 numGlyphs++;
18244 tables.maxp.data[4] = numGlyphs >> 8;
18245 tables.maxp.data[5] = numGlyphs & 255;
18246 }
18247
18248 var hintsValid = sanitizeTTPrograms(tables.fpgm, tables.prep,
18249 tables['cvt '], maxFunctionDefs);
18250 if (!hintsValid) {
18251 delete tables.fpgm;
18252 delete tables.prep;
18253 delete tables['cvt '];
18254 }
18255
18256 // Ensure the hmtx table contains the advance width and
18257 // sidebearings information for numGlyphs in the maxp table
18258 sanitizeMetrics(font, tables.hhea, tables.hmtx, numGlyphs);
18259
18260 if (!tables.head) {
18261 error('Required "head" table is not found');
18262 }
18263
18264 sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0);
18265
18266 var missingGlyphs = {};
18267 if (isTrueType) {
18268 var isGlyphLocationsLong = int16(tables.head.data[50],
18269 tables.head.data[51]);
18270 missingGlyphs = sanitizeGlyphLocations(tables.loca, tables.glyf,
18271 numGlyphs, isGlyphLocationsLong,
18272 hintsValid, dupFirstEntry);
18273 }
18274
18275 if (!tables.hhea) {
18276 error('Required "hhea" table is not found');
18277 }
18278
18279 // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
18280 // Sometimes it's 0. That needs to be fixed
18281 if (tables.hhea.data[10] === 0 && tables.hhea.data[11] === 0) {
18282 tables.hhea.data[10] = 0xFF;
18283 tables.hhea.data[11] = 0xFF;
18284 }
18285
18286 // The 'post' table has glyphs names.
18287 if (tables.post) {
18288 var valid = readPostScriptTable(tables.post, properties, numGlyphs);
18289 if (!valid) {
18290 tables.post = null;
18291 }
18292 }
18293
18294 var charCodeToGlyphId = [], charCode, toUnicode = properties.toUnicode;
18295
18296 function hasGlyph(glyphId, charCode) {
18297 if (!missingGlyphs[glyphId]) {
18298 return true;
18299 }
18300 if (charCode >= 0 && toUnicode.has(charCode)) {
18301 return true;
18302 }
18303 return false;
18304 }
18305
18306 if (properties.type === 'CIDFontType2') {
18307 var cidToGidMap = properties.cidToGidMap || [];
18308 var isCidToGidMapEmpty = cidToGidMap.length === 0;
18309
18310 properties.cMap.forEach(function(charCode, cid) {
18311 assert(cid <= 0xffff, 'Max size of CID is 65,535');
18312 var glyphId = -1;
18313 if (isCidToGidMapEmpty) {
18314 glyphId = charCode;
18315 } else if (cidToGidMap[cid] !== undefined) {
18316 glyphId = cidToGidMap[cid];
18317 }
18318
18319 if (glyphId >= 0 && glyphId < numGlyphs &&
18320 hasGlyph(glyphId, charCode)) {
18321 charCodeToGlyphId[charCode] = glyphId;
18322 }
18323 });
18324 if (dupFirstEntry) {
18325 charCodeToGlyphId[0] = numGlyphs - 1;
18326 }
18327 } else {
18328 // Most of the following logic in this code branch is based on the
18329 // 9.6.6.4 of the PDF spec.
18330 var cmapTable = readCmapTable(tables.cmap, font, this.isSymbolicFont);
18331 var cmapPlatformId = cmapTable.platformId;
18332 var cmapEncodingId = cmapTable.encodingId;
18333 var cmapMappings = cmapTable.mappings;
18334 var cmapMappingsLength = cmapMappings.length;
18335 var hasEncoding = properties.differences.length ||
18336 !!properties.baseEncodingName;
18337
18338 // The spec seems to imply that if the font is symbolic the encoding
18339 // should be ignored, this doesn't appear to work for 'preistabelle.pdf'
18340 // where the the font is symbolic and it has an encoding.
18341 if (hasEncoding &&
18342 (cmapPlatformId === 3 && cmapEncodingId === 1 ||
18343 cmapPlatformId === 1 && cmapEncodingId === 0) ||
18344 (cmapPlatformId === -1 && cmapEncodingId === -1 && // Temporary hack
18345 !!Encodings[properties.baseEncodingName])) { // Temporary hack
18346 // When no preferred cmap table was found and |baseEncodingName| is
18347 // one of the predefined encodings, we seem to obtain a better
18348 // |charCodeToGlyphId| map from the code below (fixes bug 1057544).
18349 // TODO: Note that this is a hack which should be removed as soon as
18350 // we have proper support for more exotic cmap tables.
18351
18352 var baseEncoding = [];
18353 if (properties.baseEncodingName === 'MacRomanEncoding' ||
18354 properties.baseEncodingName === 'WinAnsiEncoding') {
18355 baseEncoding = Encodings[properties.baseEncodingName];
18356 }
18357 for (charCode = 0; charCode < 256; charCode++) {
18358 var glyphName;
18359 if (this.differences && charCode in this.differences) {
18360 glyphName = this.differences[charCode];
18361 } else if (charCode in baseEncoding &&
18362 baseEncoding[charCode] !== '') {
18363 glyphName = baseEncoding[charCode];
18364 } else {
18365 glyphName = Encodings.StandardEncoding[charCode];
18366 }
18367 if (!glyphName) {
18368 continue;
18369 }
18370 var unicodeOrCharCode;
18371 if (cmapPlatformId === 3 && cmapEncodingId === 1) {
18372 unicodeOrCharCode = GlyphsUnicode[glyphName];
18373 } else if (cmapPlatformId === 1 && cmapEncodingId === 0) {
18374 // TODO: the encoding needs to be updated with mac os table.
18375 unicodeOrCharCode = Encodings.MacRomanEncoding.indexOf(glyphName);
18376 }
18377
18378 var found = false;
18379 for (i = 0; i < cmapMappingsLength; ++i) {
18380 if (cmapMappings[i].charCode === unicodeOrCharCode &&
18381 hasGlyph(cmapMappings[i].glyphId, unicodeOrCharCode)) {
18382 charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
18383 found = true;
18384 break;
18385 }
18386 }
18387 if (!found && properties.glyphNames) {
18388 // Try to map using the post table. There are currently no known
18389 // pdfs that this fixes.
18390 var glyphId = properties.glyphNames.indexOf(glyphName);
18391 if (glyphId > 0 && hasGlyph(glyphId, -1)) {
18392 charCodeToGlyphId[charCode] = glyphId;
18393 }
18394 }
18395 }
18396 } else if (cmapPlatformId === 0 && cmapEncodingId === 0) {
18397 // Default Unicode semantics, use the charcodes as is.
18398 for (i = 0; i < cmapMappingsLength; ++i) {
18399 charCodeToGlyphId[cmapMappings[i].charCode] =
18400 cmapMappings[i].glyphId;
18401 }
18402 } else {
18403 // For (3, 0) cmap tables:
18404 // The charcode key being stored in charCodeToGlyphId is the lower
18405 // byte of the two-byte charcodes of the cmap table since according to
18406 // the spec: 'each byte from the string shall be prepended with the
18407 // high byte of the range [of charcodes in the cmap table], to form
18408 // a two-byte character, which shall be used to select the
18409 // associated glyph description from the subtable'.
18410 //
18411 // For (1, 0) cmap tables:
18412 // 'single bytes from the string shall be used to look up the
18413 // associated glyph descriptions from the subtable'. This means
18414 // charcodes in the cmap will be single bytes, so no-op since
18415 // glyph.charCode & 0xFF === glyph.charCode
18416 for (i = 0; i < cmapMappingsLength; ++i) {
18417 charCode = cmapMappings[i].charCode & 0xFF;
18418 charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
18419 }
18420 }
18421 }
18422
18423 if (charCodeToGlyphId.length === 0) {
18424 // defines at least one glyph
18425 charCodeToGlyphId[0] = 0;
18426 }
18427
18428 // Converting glyphs and ids into font's cmap table
18429 var newMapping = adjustMapping(charCodeToGlyphId, properties);
18430 this.toFontChar = newMapping.toFontChar;
18431 tables.cmap = {
18432 tag: 'cmap',
18433 data: createCmapTable(newMapping.charCodeToGlyphId)
18434 };
18435
18436 if (!tables['OS/2'] || !validateOS2Table(tables['OS/2'])) {
18437 // extract some more font properties from the OpenType head and
18438 // hhea tables; yMin and descent value are always negative
18439 var override = {
18440 unitsPerEm: int16(tables.head.data[18], tables.head.data[19]),
18441 yMax: int16(tables.head.data[42], tables.head.data[43]),
18442 yMin: int16(tables.head.data[38], tables.head.data[39]) - 0x10000,
18443 ascent: int16(tables.hhea.data[4], tables.hhea.data[5]),
18444 descent: int16(tables.hhea.data[6], tables.hhea.data[7]) - 0x10000
18445 };
18446
18447 tables['OS/2'] = {
18448 tag: 'OS/2',
18449 data: createOS2Table(properties, newMapping.charCodeToGlyphId,
18450 override)
18451 };
18452 }
18453
18454 // Rewrite the 'post' table if needed
18455 if (!tables.post) {
18456 tables.post = {
18457 tag: 'post',
18458 data: createPostTable(properties)
18459 };
18460 }
18461
18462 if (!isTrueType) {
18463 try {
18464 // Trying to repair CFF file
18465 cffFile = new Stream(tables['CFF '].data);
18466 var parser = new CFFParser(cffFile, properties);
18467 cff = parser.parse();
18468 var compiler = new CFFCompiler(cff);
18469 tables['CFF '].data = compiler.compile();
18470 } catch (e) {
18471 warn('Failed to compile font ' + properties.loadedName);
18472 }
18473 }
18474
18475 // Re-creating 'name' table
18476 if (!tables.name) {
18477 tables.name = {
18478 tag: 'name',
18479 data: createNameTable(this.name)
18480 };
18481 } else {
18482 // ... using existing 'name' table as prototype
18483 var namePrototype = readNameTable(tables.name);
18484 tables.name.data = createNameTable(name, namePrototype);
18485 }
18486
18487 var builder = new OpenTypeFileBuilder(header.version);
18488 for (var tableTag in tables) {
18489 builder.addTable(tableTag, tables[tableTag].data);
18490 }
18491 return builder.toArray();
18492 },
18493
18494 convert: function Font_convert(fontName, font, properties) {
18495 // TODO: Check the charstring widths to determine this.
18496 properties.fixedPitch = false;
18497
18498 var mapping = font.getGlyphMapping(properties);
18499 var newMapping = adjustMapping(mapping, properties);
18500 this.toFontChar = newMapping.toFontChar;
18501 var numGlyphs = font.numGlyphs;
18502
18503 function getCharCodes(charCodeToGlyphId, glyphId) {
18504 var charCodes = null;
18505 for (var charCode in charCodeToGlyphId) {
18506 if (glyphId === charCodeToGlyphId[charCode]) {
18507 if (!charCodes) {
18508 charCodes = [];
18509 }
18510 charCodes.push(charCode | 0);
18511 }
18512 }
18513 return charCodes;
18514 }
18515
18516 function createCharCode(charCodeToGlyphId, glyphId) {
18517 for (var charCode in charCodeToGlyphId) {
18518 if (glyphId === charCodeToGlyphId[charCode]) {
18519 return charCode | 0;
18520 }
18521 }
18522 newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] =
18523 glyphId;
18524 return newMapping.nextAvailableFontCharCode++;
18525 }
18526
18527 var seacs = font.seacs;
18528 if (SEAC_ANALYSIS_ENABLED && seacs && seacs.length) {
18529 var matrix = properties.fontMatrix || FONT_IDENTITY_MATRIX;
18530 var charset = font.getCharset();
18531 var seacMap = Object.create(null);
18532 for (var glyphId in seacs) {
18533 glyphId |= 0;
18534 var seac = seacs[glyphId];
18535 var baseGlyphName = Encodings.StandardEncoding[seac[2]];
18536 var accentGlyphName = Encodings.StandardEncoding[seac[3]];
18537 var baseGlyphId = charset.indexOf(baseGlyphName);
18538 var accentGlyphId = charset.indexOf(accentGlyphName);
18539 if (baseGlyphId < 0 || accentGlyphId < 0) {
18540 continue;
18541 }
18542 var accentOffset = {
18543 x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4],
18544 y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5]
18545 };
18546
18547 var charCodes = getCharCodes(mapping, glyphId);
18548 if (!charCodes) {
18549 // There's no point in mapping it if the char code was never mapped
18550 // to begin with.
18551 continue;
18552 }
18553 for (var i = 0, ii = charCodes.length; i < ii; i++) {
18554 var charCode = charCodes[i];
18555 // Find a fontCharCode that maps to the base and accent glyphs.
18556 // If one doesn't exists, create it.
18557 var charCodeToGlyphId = newMapping.charCodeToGlyphId;
18558 var baseFontCharCode = createCharCode(charCodeToGlyphId,
18559 baseGlyphId);
18560 var accentFontCharCode = createCharCode(charCodeToGlyphId,
18561 accentGlyphId);
18562 seacMap[charCode] = {
18563 baseFontCharCode: baseFontCharCode,
18564 accentFontCharCode: accentFontCharCode,
18565 accentOffset: accentOffset
18566 };
18567 }
18568 }
18569 properties.seacMap = seacMap;
18570 }
18571
18572 var unitsPerEm = 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0];
18573
18574 var builder = new OpenTypeFileBuilder('\x4F\x54\x54\x4F');
18575 // PostScript Font Program
18576 builder.addTable('CFF ', font.data);
18577 // OS/2 and Windows Specific metrics
18578 builder.addTable('OS/2', createOS2Table(properties,
18579 newMapping.charCodeToGlyphId));
18580 // Character to glyphs mapping
18581 builder.addTable('cmap', createCmapTable(newMapping.charCodeToGlyphId));
18582 // Font header
18583 builder.addTable('head',
18584 '\x00\x01\x00\x00' + // Version number
18585 '\x00\x00\x10\x00' + // fontRevision
18586 '\x00\x00\x00\x00' + // checksumAdjustement
18587 '\x5F\x0F\x3C\xF5' + // magicNumber
18588 '\x00\x00' + // Flags
18589 safeString16(unitsPerEm) + // unitsPerEM
18590 '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date
18591 '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date
18592 '\x00\x00' + // xMin
18593 safeString16(properties.descent) + // yMin
18594 '\x0F\xFF' + // xMax
18595 safeString16(properties.ascent) + // yMax
18596 string16(properties.italicAngle ? 2 : 0) + // macStyle
18597 '\x00\x11' + // lowestRecPPEM
18598 '\x00\x00' + // fontDirectionHint
18599 '\x00\x00' + // indexToLocFormat
18600 '\x00\x00'); // glyphDataFormat
18601
18602 // Horizontal header
18603 builder.addTable('hhea',
18604 '\x00\x01\x00\x00' + // Version number
18605 safeString16(properties.ascent) + // Typographic Ascent
18606 safeString16(properties.descent) + // Typographic Descent
18607 '\x00\x00' + // Line Gap
18608 '\xFF\xFF' + // advanceWidthMax
18609 '\x00\x00' + // minLeftSidebearing
18610 '\x00\x00' + // minRightSidebearing
18611 '\x00\x00' + // xMaxExtent
18612 safeString16(properties.capHeight) + // caretSlopeRise
18613 safeString16(Math.tan(properties.italicAngle) *
18614 properties.xHeight) + // caretSlopeRun
18615 '\x00\x00' + // caretOffset
18616 '\x00\x00' + // -reserved-
18617 '\x00\x00' + // -reserved-
18618 '\x00\x00' + // -reserved-
18619 '\x00\x00' + // -reserved-
18620 '\x00\x00' + // metricDataFormat
18621 string16(numGlyphs)); // Number of HMetrics
18622
18623 // Horizontal metrics
18624 builder.addTable('hmtx', (function fontFieldsHmtx() {
18625 var charstrings = font.charstrings;
18626 var cffWidths = font.cff ? font.cff.widths : null;
18627 var hmtx = '\x00\x00\x00\x00'; // Fake .notdef
18628 for (var i = 1, ii = numGlyphs; i < ii; i++) {
18629 var width = 0;
18630 if (charstrings) {
18631 var charstring = charstrings[i - 1];
18632 width = 'width' in charstring ? charstring.width : 0;
18633 } else if (cffWidths) {
18634 width = Math.ceil(cffWidths[i] || 0);
18635 }
18636 hmtx += string16(width) + string16(0);
18637 }
18638 return hmtx;
18639 })());
18640
18641 // Maximum profile
18642 builder.addTable('maxp',
18643 '\x00\x00\x50\x00' + // Version number
18644 string16(numGlyphs)); // Num of glyphs
18645
18646 // Naming tables
18647 builder.addTable('name', createNameTable(fontName));
18648
18649 // PostScript informations
18650 builder.addTable('post', createPostTable(properties));
18651
18652 return builder.toArray();
18653 },
18654
18655 /**
18656 * Builds a char code to unicode map based on section 9.10 of the spec.
18657 * @param {Object} properties Font properties object.
18658 * @return {Object} A ToUnicodeMap object.
18659 */
18660 buildToUnicode: function Font_buildToUnicode(properties) {
18661 // Section 9.10.2 Mapping Character Codes to Unicode Values
18662 if (properties.toUnicode && properties.toUnicode.length !== 0) {
18663 return properties.toUnicode;
18664 }
18665 // According to the spec if the font is a simple font we should only map
18666 // to unicode if the base encoding is MacRoman, MacExpert, or WinAnsi or
18667 // the differences array only contains adobe standard or symbol set names,
18668 // in pratice it seems better to always try to create a toUnicode
18669 // map based of the default encoding.
18670 var toUnicode, charcode;
18671 if (!properties.composite /* is simple font */) {
18672 toUnicode = [];
18673 var encoding = properties.defaultEncoding.slice();
18674 var baseEncodingName = properties.baseEncodingName;
18675 // Merge in the differences array.
18676 var differences = properties.differences;
18677 for (charcode in differences) {
18678 encoding[charcode] = differences[charcode];
18679 }
18680 for (charcode in encoding) {
18681 // a) Map the character code to a character name.
18682 var glyphName = encoding[charcode];
18683 // b) Look up the character name in the Adobe Glyph List (see the
18684 // Bibliography) to obtain the corresponding Unicode value.
18685 if (glyphName === '') {
18686 continue;
18687 } else if (GlyphsUnicode[glyphName] === undefined) {
18688 // (undocumented) c) Few heuristics to recognize unknown glyphs
18689 // NOTE: Adobe Reader does not do this step, but OSX Preview does
18690 var code = 0;
18691 switch (glyphName[0]) {
18692 case 'G': // Gxx glyph
18693 if (glyphName.length === 3) {
18694 code = parseInt(glyphName.substr(1), 16);
18695 }
18696 break;
18697 case 'g': // g00xx glyph
18698 if (glyphName.length === 5) {
18699 code = parseInt(glyphName.substr(1), 16);
18700 }
18701 break;
18702 case 'C': // Cddd glyph
18703 case 'c': // cddd glyph
18704 if (glyphName.length >= 3) {
18705 code = +glyphName.substr(1);
18706 }
18707 break;
18708 }
18709 if (code) {
18710 // If |baseEncodingName| is one the predefined encodings,
18711 // and |code| equals |charcode|, using the glyph defined in the
18712 // baseEncoding seems to yield a better |toUnicode| mapping
18713 // (fixes issue 5070).
18714 if (baseEncodingName && code === +charcode) {
18715 var baseEncoding = Encodings[baseEncodingName];
18716 if (baseEncoding && (glyphName = baseEncoding[charcode])) {
18717 toUnicode[charcode] =
18718 String.fromCharCode(GlyphsUnicode[glyphName]);
18719 continue;
18720 }
18721 }
18722 toUnicode[charcode] = String.fromCharCode(code);
18723 }
18724 continue;
18725 }
18726 toUnicode[charcode] = String.fromCharCode(GlyphsUnicode[glyphName]);
18727 }
18728 return new ToUnicodeMap(toUnicode);
18729 }
18730 // If the font is a composite font that uses one of the predefined CMaps
18731 // listed in Table 118 (except Identity–H and Identity–V) or whose
18732 // descendant CIDFont uses the Adobe-GB1, Adobe-CNS1, Adobe-Japan1, or
18733 // Adobe-Korea1 character collection:
18734 if (properties.composite && (
18735 (properties.cMap.builtInCMap &&
18736 !(properties.cMap instanceof IdentityCMap)) ||
18737 (properties.cidSystemInfo.registry === 'Adobe' &&
18738 (properties.cidSystemInfo.ordering === 'GB1' ||
18739 properties.cidSystemInfo.ordering === 'CNS1' ||
18740 properties.cidSystemInfo.ordering === 'Japan1' ||
18741 properties.cidSystemInfo.ordering === 'Korea1')))) {
18742 // Then:
18743 // a) Map the character code to a character identifier (CID) according
18744 // to the font’s CMap.
18745 // b) Obtain the registry and ordering of the character collection used
18746 // by the font’s CMap (for example, Adobe and Japan1) from its
18747 // CIDSystemInfo dictionary.
18748 var registry = properties.cidSystemInfo.registry;
18749 var ordering = properties.cidSystemInfo.ordering;
18750 // c) Construct a second CMap name by concatenating the registry and
18751 // ordering obtained in step (b) in the format registry–ordering–UCS2
18752 // (for example, Adobe–Japan1–UCS2).
18753 var ucs2CMapName = new Name(registry + '-' + ordering + '-UCS2');
18754 // d) Obtain the CMap with the name constructed in step (c) (available
18755 // from the ASN Web site; see the Bibliography).
18756 var ucs2CMap = CMapFactory.create(ucs2CMapName,
18757 { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
18758 var cMap = properties.cMap;
18759 toUnicode = [];
18760 cMap.forEach(function(charcode, cid) {
18761 assert(cid <= 0xffff, 'Max size of CID is 65,535');
18762 // e) Map the CID obtained in step (a) according to the CMap obtained
18763 // in step (d), producing a Unicode value.
18764 var ucs2 = ucs2CMap.lookup(cid);
18765 if (ucs2) {
18766 toUnicode[charcode] =
18767 String.fromCharCode((ucs2.charCodeAt(0) << 8) +
18768 ucs2.charCodeAt(1));
18769 }
18770 });
18771 return new ToUnicodeMap(toUnicode);
18772 }
18773
18774 // The viewer's choice, just use an identity map.
18775 return new IdentityToUnicodeMap(properties.firstChar,
18776 properties.lastChar);
18777 },
18778
18779 get spaceWidth() {
18780 if ('_shadowWidth' in this) {
18781 return this._shadowWidth;
18782 }
18783
18784 // trying to estimate space character width
18785 var possibleSpaceReplacements = ['space', 'minus', 'one', 'i'];
18786 var width;
18787 for (var i = 0, ii = possibleSpaceReplacements.length; i < ii; i++) {
18788 var glyphName = possibleSpaceReplacements[i];
18789 // if possible, getting width by glyph name
18790 if (glyphName in this.widths) {
18791 width = this.widths[glyphName];
18792 break;
18793 }
18794 var glyphUnicode = GlyphsUnicode[glyphName];
18795 // finding the charcode via unicodeToCID map
18796 var charcode = 0;
18797 if (this.composite) {
18798 if (this.cMap.contains(glyphUnicode)) {
18799 charcode = this.cMap.lookup(glyphUnicode);
18800 }
18801 }
18802 // ... via toUnicode map
18803 if (!charcode && 'toUnicode' in this) {
18804 charcode = this.toUnicode.charCodeOf(glyphUnicode);
18805 }
18806 // setting it to unicode if negative or undefined
18807 if (charcode <= 0) {
18808 charcode = glyphUnicode;
18809 }
18810 // trying to get width via charcode
18811 width = this.widths[charcode];
18812 if (width) {
18813 break; // the non-zero width found
18814 }
18815 }
18816 width = width || this.defaultWidth;
18817 // Do not shadow the property here. See discussion:
18818 // https://github.com/mozilla/pdf.js/pull/2127#discussion_r1662280
18819 this._shadowWidth = width;
18820 return width;
18821 },
18822
18823 charToGlyph: function Font_charToGlyph(charcode) {
18824 var fontCharCode, width, operatorListId;
18825
18826 var widthCode = charcode;
18827 if (this.cMap && this.cMap.contains(charcode)) {
18828 widthCode = this.cMap.lookup(charcode);
18829 }
18830 width = this.widths[widthCode];
18831 width = isNum(width) ? width : this.defaultWidth;
18832 var vmetric = this.vmetrics && this.vmetrics[widthCode];
18833
18834 var unicode = this.toUnicode.get(charcode) || charcode;
18835 if (typeof unicode === 'number') {
18836 unicode = String.fromCharCode(unicode);
18837 }
18838
18839 // First try the toFontChar map, if it's not there then try falling
18840 // back to the char code.
18841 fontCharCode = this.toFontChar[charcode] || charcode;
18842 if (this.missingFile) {
18843 fontCharCode = mapSpecialUnicodeValues(fontCharCode);
18844 }
18845
18846 if (this.isType3Font) {
18847 // Font char code in this case is actually a glyph name.
18848 operatorListId = fontCharCode;
18849 }
18850
18851 var accent = null;
18852 if (this.seacMap && this.seacMap[charcode]) {
18853 var seac = this.seacMap[charcode];
18854 fontCharCode = seac.baseFontCharCode;
18855 accent = {
18856 fontChar: String.fromCharCode(seac.accentFontCharCode),
18857 offset: seac.accentOffset
18858 };
18859 }
18860
18861 var fontChar = String.fromCharCode(fontCharCode);
18862
18863 var glyph = this.glyphCache[charcode];
18864 if (!glyph ||
18865 !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric,
18866 operatorListId)) {
18867 glyph = new Glyph(fontChar, unicode, accent, width, vmetric,
18868 operatorListId);
18869 this.glyphCache[charcode] = glyph;
18870 }
18871 return glyph;
18872 },
18873
18874 charsToGlyphs: function Font_charsToGlyphs(chars) {
18875 var charsCache = this.charsCache;
18876 var glyphs, glyph, charcode;
18877
18878 // if we translated this string before, just grab it from the cache
18879 if (charsCache) {
18880 glyphs = charsCache[chars];
18881 if (glyphs) {
18882 return glyphs;
18883 }
18884 }
18885
18886 // lazily create the translation cache
18887 if (!charsCache) {
18888 charsCache = this.charsCache = Object.create(null);
18889 }
18890
18891 glyphs = [];
18892 var charsCacheKey = chars;
18893 var i = 0, ii;
18894
18895 if (this.cMap) {
18896 // composite fonts have multi-byte strings convert the string from
18897 // single-byte to multi-byte
18898 var c = {};
18899 while (i < chars.length) {
18900 this.cMap.readCharCode(chars, i, c);
18901 charcode = c.charcode;
18902 var length = c.length;
18903 i += length;
18904 glyph = this.charToGlyph(charcode);
18905 glyphs.push(glyph);
18906 // placing null after each word break charcode (ASCII SPACE)
18907 // Ignore occurences of 0x20 in multiple-byte codes.
18908 if (length === 1 && chars.charCodeAt(i - 1) === 0x20) {
18909 glyphs.push(null);
18910 }
18911 }
18912 } else {
18913 for (i = 0, ii = chars.length; i < ii; ++i) {
18914 charcode = chars.charCodeAt(i);
18915 glyph = this.charToGlyph(charcode);
18916 glyphs.push(glyph);
18917 if (charcode === 0x20) {
18918 glyphs.push(null);
18919 }
18920 }
18921 }
18922
18923 // Enter the translated string into the cache
18924 return (charsCache[charsCacheKey] = glyphs);
18925 }
18926 };
18927
18928 return Font;
18929 })();
18930
18931 var ErrorFont = (function ErrorFontClosure() {
18932 function ErrorFont(error) {
18933 this.error = error;
18934 this.loadedName = 'g_font_error';
18935 this.loading = false;
18936 }
18937
18938 ErrorFont.prototype = {
18939 charsToGlyphs: function ErrorFont_charsToGlyphs() {
18940 return [];
18941 },
18942 exportData: function ErrorFont_exportData() {
18943 return {error: this.error};
18944 }
18945 };
18946
18947 return ErrorFont;
18948 })();
18949
18950 /**
18951 * Shared logic for building a char code to glyph id mapping for Type1 and
18952 * simple CFF fonts. See section 9.6.6.2 of the spec.
18953 * @param {Object} properties Font properties object.
18954 * @param {Object} builtInEncoding The encoding contained within the actual font
18955 * data.
18956 * @param {Array} Array of glyph names where the index is the glyph ID.
18957 * @returns {Object} A char code to glyph ID map.
18958 */
18959 function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) {
18960 var charCodeToGlyphId = Object.create(null);
18961 var glyphId, charCode, baseEncoding;
18962
18963 if (properties.baseEncodingName) {
18964 // If a valid base encoding name was used, the mapping is initialized with
18965 // that.
18966 baseEncoding = Encodings[properties.baseEncodingName];
18967 for (charCode = 0; charCode < baseEncoding.length; charCode++) {
18968 glyphId = glyphNames.indexOf(baseEncoding[charCode]);
18969 if (glyphId >= 0) {
18970 charCodeToGlyphId[charCode] = glyphId;
18971 } else {
18972 charCodeToGlyphId[charCode] = 0; // notdef
18973 }
18974 }
18975 } else if (!!(properties.flags & FontFlags.Symbolic)) {
18976 // For a symbolic font the encoding should be the fonts built-in
18977 // encoding.
18978 for (charCode in builtInEncoding) {
18979 charCodeToGlyphId[charCode] = builtInEncoding[charCode];
18980 }
18981 } else {
18982 // For non-symbolic fonts that don't have a base encoding the standard
18983 // encoding should be used.
18984 baseEncoding = Encodings.StandardEncoding;
18985 for (charCode = 0; charCode < baseEncoding.length; charCode++) {
18986 glyphId = glyphNames.indexOf(baseEncoding[charCode]);
18987 if (glyphId >= 0) {
18988 charCodeToGlyphId[charCode] = glyphId;
18989 } else {
18990 charCodeToGlyphId[charCode] = 0; // notdef
18991 }
18992 }
18993 }
18994
18995 // Lastly, merge in the differences.
18996 var differences = properties.differences;
18997 if (differences) {
18998 for (charCode in differences) {
18999 var glyphName = differences[charCode];
19000 glyphId = glyphNames.indexOf(glyphName);
19001 if (glyphId >= 0) {
19002 charCodeToGlyphId[charCode] = glyphId;
19003 } else {
19004 charCodeToGlyphId[charCode] = 0; // notdef
19005 }
19006 }
19007 }
19008 return charCodeToGlyphId;
19009 }
19010
19011 /*
19012 * CharStrings are encoded following the the CharString Encoding sequence
19013 * describe in Chapter 6 of the "Adobe Type1 Font Format" specification.
19014 * The value in a byte indicates a command, a number, or subsequent bytes
19015 * that are to be interpreted in a special way.
19016 *
19017 * CharString Number Encoding:
19018 * A CharString byte containing the values from 32 through 255 inclusive
19019 * indicate an integer. These values are decoded in four ranges.
19020 *
19021 * 1. A CharString byte containing a value, v, between 32 and 246 inclusive,
19022 * indicate the integer v - 139. Thus, the integer values from -107 through
19023 * 107 inclusive may be encoded in single byte.
19024 *
19025 * 2. A CharString byte containing a value, v, between 247 and 250 inclusive,
19026 * indicates an integer involving the next byte, w, according to the formula:
19027 * [(v - 247) x 256] + w + 108
19028 *
19029 * 3. A CharString byte containing a value, v, between 251 and 254 inclusive,
19030 * indicates an integer involving the next byte, w, according to the formula:
19031 * -[(v - 251) * 256] - w - 108
19032 *
19033 * 4. A CharString containing the value 255 indicates that the next 4 bytes
19034 * are a two complement signed integer. The first of these bytes contains the
19035 * highest order bits, the second byte contains the next higher order bits
19036 * and the fourth byte contain the lowest order bits.
19037 *
19038 *
19039 * CharString Command Encoding:
19040 * CharStrings commands are encoded in 1 or 2 bytes.
19041 *
19042 * Single byte commands are encoded in 1 byte that contains a value between
19043 * 0 and 31 inclusive.
19044 * If a command byte contains the value 12, then the value in the next byte
19045 * indicates a command. This "escape" mechanism allows many extra commands
19046 * to be encoded and this encoding technique helps to minimize the length of
19047 * the charStrings.
19048 */
19049 var Type1CharString = (function Type1CharStringClosure() {
19050 var COMMAND_MAP = {
19051 'hstem': [1],
19052 'vstem': [3],
19053 'vmoveto': [4],
19054 'rlineto': [5],
19055 'hlineto': [6],
19056 'vlineto': [7],
19057 'rrcurveto': [8],
19058 'callsubr': [10],
19059 'flex': [12, 35],
19060 'drop' : [12, 18],
19061 'endchar': [14],
19062 'rmoveto': [21],
19063 'hmoveto': [22],
19064 'vhcurveto': [30],
19065 'hvcurveto': [31]
19066 };
19067
19068 function Type1CharString() {
19069 this.width = 0;
19070 this.lsb = 0;
19071 this.flexing = false;
19072 this.output = [];
19073 this.stack = [];
19074 }
19075
19076 Type1CharString.prototype = {
19077 convert: function Type1CharString_convert(encoded, subrs) {
19078 var count = encoded.length;
19079 var error = false;
19080 var wx, sbx, subrNumber;
19081 for (var i = 0; i < count; i++) {
19082 var value = encoded[i];
19083 if (value < 32) {
19084 if (value === 12) {
19085 value = (value << 8) + encoded[++i];
19086 }
19087 switch (value) {
19088 case 1: // hstem
19089 if (!HINTING_ENABLED) {
19090 this.stack = [];
19091 break;
19092 }
19093 error = this.executeCommand(2, COMMAND_MAP.hstem);
19094 break;
19095 case 3: // vstem
19096 if (!HINTING_ENABLED) {
19097 this.stack = [];
19098 break;
19099 }
19100 error = this.executeCommand(2, COMMAND_MAP.vstem);
19101 break;
19102 case 4: // vmoveto
19103 if (this.flexing) {
19104 if (this.stack.length < 1) {
19105 error = true;
19106 break;
19107 }
19108 // Add the dx for flex and but also swap the values so they are
19109 // the right order.
19110 var dy = this.stack.pop();
19111 this.stack.push(0, dy);
19112 break;
19113 }
19114 error = this.executeCommand(1, COMMAND_MAP.vmoveto);
19115 break;
19116 case 5: // rlineto
19117 error = this.executeCommand(2, COMMAND_MAP.rlineto);
19118 break;
19119 case 6: // hlineto
19120 error = this.executeCommand(1, COMMAND_MAP.hlineto);
19121 break;
19122 case 7: // vlineto
19123 error = this.executeCommand(1, COMMAND_MAP.vlineto);
19124 break;
19125 case 8: // rrcurveto
19126 error = this.executeCommand(6, COMMAND_MAP.rrcurveto);
19127 break;
19128 case 9: // closepath
19129 // closepath is a Type1 command that does not take argument and is
19130 // useless in Type2 and it can simply be ignored.
19131 this.stack = [];
19132 break;
19133 case 10: // callsubr
19134 if (this.stack.length < 1) {
19135 error = true;
19136 break;
19137 }
19138 subrNumber = this.stack.pop();
19139 error = this.convert(subrs[subrNumber], subrs);
19140 break;
19141 case 11: // return
19142 return error;
19143 case 13: // hsbw
19144 if (this.stack.length < 2) {
19145 error = true;
19146 break;
19147 }
19148 // To convert to type2 we have to move the width value to the
19149 // first part of the charstring and then use hmoveto with lsb.
19150 wx = this.stack.pop();
19151 sbx = this.stack.pop();
19152 this.lsb = sbx;
19153 this.width = wx;
19154 this.stack.push(wx, sbx);
19155 error = this.executeCommand(2, COMMAND_MAP.hmoveto);
19156 break;
19157 case 14: // endchar
19158 this.output.push(COMMAND_MAP.endchar[0]);
19159 break;
19160 case 21: // rmoveto
19161 if (this.flexing) {
19162 break;
19163 }
19164 error = this.executeCommand(2, COMMAND_MAP.rmoveto);
19165 break;
19166 case 22: // hmoveto
19167 if (this.flexing) {
19168 // Add the dy for flex.
19169 this.stack.push(0);
19170 break;
19171 }
19172 error = this.executeCommand(1, COMMAND_MAP.hmoveto);
19173 break;
19174 case 30: // vhcurveto
19175 error = this.executeCommand(4, COMMAND_MAP.vhcurveto);
19176 break;
19177 case 31: // hvcurveto
19178 error = this.executeCommand(4, COMMAND_MAP.hvcurveto);
19179 break;
19180 case (12 << 8) + 0: // dotsection
19181 // dotsection is a Type1 command to specify some hinting feature
19182 // for dots that do not take a parameter and it can safely be
19183 // ignored for Type2.
19184 this.stack = [];
19185 break;
19186 case (12 << 8) + 1: // vstem3
19187 if (!HINTING_ENABLED) {
19188 this.stack = [];
19189 break;
19190 }
19191 // [vh]stem3 are Type1 only and Type2 supports [vh]stem with
19192 // multiple parameters, so instead of returning [vh]stem3 take a
19193 // shortcut and return [vhstem] instead.
19194 error = this.executeCommand(2, COMMAND_MAP.vstem);
19195 break;
19196 case (12 << 8) + 2: // hstem3
19197 if (!HINTING_ENABLED) {
19198 this.stack = [];
19199 break;
19200 }
19201 // See vstem3.
19202 error = this.executeCommand(2, COMMAND_MAP.hstem);
19203 break;
19204 case (12 << 8) + 6: // seac
19205 // seac is like type 2's special endchar but it doesn't use the
19206 // first argument asb, so remove it.
19207 if (SEAC_ANALYSIS_ENABLED) {
19208 this.seac = this.stack.splice(-4, 4);
19209 error = this.executeCommand(0, COMMAND_MAP.endchar);
19210 } else {
19211 error = this.executeCommand(4, COMMAND_MAP.endchar);
19212 }
19213 break;
19214 case (12 << 8) + 7: // sbw
19215 if (this.stack.length < 4) {
19216 error = true;
19217 break;
19218 }
19219 // To convert to type2 we have to move the width value to the
19220 // first part of the charstring and then use rmoveto with
19221 // (dx, dy). The height argument will not be used for vmtx and
19222 // vhea tables reconstruction -- ignoring it.
19223 var wy = this.stack.pop();
19224 wx = this.stack.pop();
19225 var sby = this.stack.pop();
19226 sbx = this.stack.pop();
19227 this.lsb = sbx;
19228 this.width = wx;
19229 this.stack.push(wx, sbx, sby);
19230 error = this.executeCommand(3, COMMAND_MAP.rmoveto);
19231 break;
19232 case (12 << 8) + 12: // div
19233 if (this.stack.length < 2) {
19234 error = true;
19235 break;
19236 }
19237 var num2 = this.stack.pop();
19238 var num1 = this.stack.pop();
19239 this.stack.push(num1 / num2);
19240 break;
19241 case (12 << 8) + 16: // callothersubr
19242 if (this.stack.length < 2) {
19243 error = true;
19244 break;
19245 }
19246 subrNumber = this.stack.pop();
19247 var numArgs = this.stack.pop();
19248 if (subrNumber === 0 && numArgs === 3) {
19249 var flexArgs = this.stack.splice(this.stack.length - 17, 17);
19250 this.stack.push(
19251 flexArgs[2] + flexArgs[0], // bcp1x + rpx
19252 flexArgs[3] + flexArgs[1], // bcp1y + rpy
19253 flexArgs[4], // bcp2x
19254 flexArgs[5], // bcp2y
19255 flexArgs[6], // p2x
19256 flexArgs[7], // p2y
19257 flexArgs[8], // bcp3x
19258 flexArgs[9], // bcp3y
19259 flexArgs[10], // bcp4x
19260 flexArgs[11], // bcp4y
19261 flexArgs[12], // p3x
19262 flexArgs[13], // p3y
19263 flexArgs[14] // flexDepth
19264 // 15 = finalx unused by flex
19265 // 16 = finaly unused by flex
19266 );
19267 error = this.executeCommand(13, COMMAND_MAP.flex, true);
19268 this.flexing = false;
19269 this.stack.push(flexArgs[15], flexArgs[16]);
19270 } else if (subrNumber === 1 && numArgs === 0) {
19271 this.flexing = true;
19272 }
19273 break;
19274 case (12 << 8) + 17: // pop
19275 // Ignore this since it is only used with othersubr.
19276 break;
19277 case (12 << 8) + 33: // setcurrentpoint
19278 // Ignore for now.
19279 this.stack = [];
19280 break;
19281 default:
19282 warn('Unknown type 1 charstring command of "' + value + '"');
19283 break;
19284 }
19285 if (error) {
19286 break;
19287 }
19288 continue;
19289 } else if (value <= 246) {
19290 value = value - 139;
19291 } else if (value <= 250) {
19292 value = ((value - 247) * 256) + encoded[++i] + 108;
19293 } else if (value <= 254) {
19294 value = -((value - 251) * 256) - encoded[++i] - 108;
19295 } else {
19296 value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 |
19297 (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0;
19298 }
19299 this.stack.push(value);
19300 }
19301 return error;
19302 },
19303
19304 executeCommand: function(howManyArgs, command, keepStack) {
19305 var stackLength = this.stack.length;
19306 if (howManyArgs > stackLength) {
19307 return true;
19308 }
19309 var start = stackLength - howManyArgs;
19310 for (var i = start; i < stackLength; i++) {
19311 var value = this.stack[i];
19312 if (value === (value | 0)) { // int
19313 this.output.push(28, (value >> 8) & 0xff, value & 0xff);
19314 } else { // fixed point
19315 value = (65536 * value) | 0;
19316 this.output.push(255,
19317 (value >> 24) & 0xFF,
19318 (value >> 16) & 0xFF,
19319 (value >> 8) & 0xFF,
19320 value & 0xFF);
19321 }
19322 }
19323 this.output.push.apply(this.output, command);
19324 if (keepStack) {
19325 this.stack.splice(start, howManyArgs);
19326 } else {
19327 this.stack.length = 0;
19328 }
19329 return false;
19330 }
19331 };
19332
19333 return Type1CharString;
19334 })();
19335
19336 /*
19337 * Type1Parser encapsulate the needed code for parsing a Type1 font
19338 * program. Some of its logic depends on the Type2 charstrings
19339 * structure.
19340 * Note: this doesn't really parse the font since that would require evaluation
19341 * of PostScript, but it is possible in most cases to extract what we need
19342 * without a full parse.
19343 */
19344 var Type1Parser = (function Type1ParserClosure() {
19345 /*
19346 * Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence
19347 * of Plaintext Bytes. The function took a key as a parameter which can be
19348 * for decrypting the eexec block of for decoding charStrings.
19349 */
19350 var EEXEC_ENCRYPT_KEY = 55665;
19351 var CHAR_STRS_ENCRYPT_KEY = 4330;
19352
19353 function isHexDigit(code) {
19354 return code >= 48 && code <= 57 || // '0'-'9'
19355 code >= 65 && code <= 70 || // 'A'-'F'
19356 code >= 97 && code <= 102; // 'a'-'f'
19357 }
19358
19359 function decrypt(data, key, discardNumber) {
19360 var r = key | 0, c1 = 52845, c2 = 22719;
19361 var count = data.length;
19362 var decrypted = new Uint8Array(count);
19363 for (var i = 0; i < count; i++) {
19364 var value = data[i];
19365 decrypted[i] = value ^ (r >> 8);
19366 r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
19367 }
19368 return Array.prototype.slice.call(decrypted, discardNumber);
19369 }
19370
19371 function decryptAscii(data, key, discardNumber) {
19372 var r = key | 0, c1 = 52845, c2 = 22719;
19373 var count = data.length, maybeLength = count >>> 1;
19374 var decrypted = new Uint8Array(maybeLength);
19375 var i, j;
19376 for (i = 0, j = 0; i < count; i++) {
19377 var digit1 = data[i];
19378 if (!isHexDigit(digit1)) {
19379 continue;
19380 }
19381 i++;
19382 var digit2;
19383 while (i < count && !isHexDigit(digit2 = data[i])) {
19384 i++;
19385 }
19386 if (i < count) {
19387 var value = parseInt(String.fromCharCode(digit1, digit2), 16);
19388 decrypted[j++] = value ^ (r >> 8);
19389 r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
19390 }
19391 }
19392 return Array.prototype.slice.call(decrypted, discardNumber, j);
19393 }
19394
19395 function isSpecial(c) {
19396 return c === 0x2F || // '/'
19397 c === 0x5B || c === 0x5D || // '[', ']'
19398 c === 0x7B || c === 0x7D || // '{', '}'
19399 c === 0x28 || c === 0x29; // '(', ')'
19400 }
19401
19402 function Type1Parser(stream, encrypted) {
19403 if (encrypted) {
19404 var data = stream.getBytes();
19405 var isBinary = !(isHexDigit(data[0]) && isHexDigit(data[1]) &&
19406 isHexDigit(data[2]) && isHexDigit(data[3]));
19407 stream = new Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) :
19408 decryptAscii(data, EEXEC_ENCRYPT_KEY, 4));
19409 }
19410 this.stream = stream;
19411 this.nextChar();
19412 }
19413
19414 Type1Parser.prototype = {
19415 readNumberArray: function Type1Parser_readNumberArray() {
19416 this.getToken(); // read '[' or '{' (arrays can start with either)
19417 var array = [];
19418 while (true) {
19419 var token = this.getToken();
19420 if (token === null || token === ']' || token === '}') {
19421 break;
19422 }
19423 array.push(parseFloat(token || 0));
19424 }
19425 return array;
19426 },
19427
19428 readNumber: function Type1Parser_readNumber() {
19429 var token = this.getToken();
19430 return parseFloat(token || 0);
19431 },
19432
19433 readInt: function Type1Parser_readInt() {
19434 // Use '| 0' to prevent setting a double into length such as the double
19435 // does not flow into the loop variable.
19436 var token = this.getToken();
19437 return parseInt(token || 0, 10) | 0;
19438 },
19439
19440 readBoolean: function Type1Parser_readBoolean() {
19441 var token = this.getToken();
19442
19443 // Use 1 and 0 since that's what type2 charstrings use.
19444 return token === 'true' ? 1 : 0;
19445 },
19446
19447 nextChar : function Type1_nextChar() {
19448 return (this.currentChar = this.stream.getByte());
19449 },
19450
19451 getToken: function Type1Parser_getToken() {
19452 // Eat whitespace and comments.
19453 var comment = false;
19454 var ch = this.currentChar;
19455 while (true) {
19456 if (ch === -1) {
19457 return null;
19458 }
19459
19460 if (comment) {
19461 if (ch === 0x0A || ch === 0x0D) {
19462 comment = false;
19463 }
19464 } else if (ch === 0x25) { // '%'
19465 comment = true;
19466 } else if (!Lexer.isSpace(ch)) {
19467 break;
19468 }
19469 ch = this.nextChar();
19470 }
19471 if (isSpecial(ch)) {
19472 this.nextChar();
19473 return String.fromCharCode(ch);
19474 }
19475 var token = '';
19476 do {
19477 token += String.fromCharCode(ch);
19478 ch = this.nextChar();
19479 } while (ch >= 0 && !Lexer.isSpace(ch) && !isSpecial(ch));
19480 return token;
19481 },
19482
19483 /*
19484 * Returns an object containing a Subrs array and a CharStrings
19485 * array extracted from and eexec encrypted block of data
19486 */
19487 extractFontProgram: function Type1Parser_extractFontProgram() {
19488 var stream = this.stream;
19489
19490 var subrs = [], charstrings = [];
19491 var program = {
19492 subrs: [],
19493 charstrings: [],
19494 properties: {
19495 'privateData': {
19496 'lenIV': 4
19497 }
19498 }
19499 };
19500 var token, length, data, lenIV, encoded;
19501 while ((token = this.getToken()) !== null) {
19502 if (token !== '/') {
19503 continue;
19504 }
19505 token = this.getToken();
19506 switch (token) {
19507 case 'CharStrings':
19508 // The number immediately following CharStrings must be greater or
19509 // equal to the number of CharStrings.
19510 this.getToken();
19511 this.getToken(); // read in 'dict'
19512 this.getToken(); // read in 'dup'
19513 this.getToken(); // read in 'begin'
19514 while(true) {
19515 token = this.getToken();
19516 if (token === null || token === 'end') {
19517 break;
19518 }
19519
19520 if (token !== '/') {
19521 continue;
19522 }
19523 var glyph = this.getToken();
19524 length = this.readInt();
19525 this.getToken(); // read in 'RD' or '-|'
19526 data = stream.makeSubStream(stream.pos, length);
19527 lenIV = program.properties.privateData['lenIV'];
19528 encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);
19529 // Skip past the required space and binary data.
19530 stream.skip(length);
19531 this.nextChar();
19532 token = this.getToken(); // read in 'ND' or '|-'
19533 if (token === 'noaccess') {
19534 this.getToken(); // read in 'def'
19535 }
19536 charstrings.push({
19537 glyph: glyph,
19538 encoded: encoded
19539 });
19540 }
19541 break;
19542 case 'Subrs':
19543 var num = this.readInt();
19544 this.getToken(); // read in 'array'
19545 while ((token = this.getToken()) === 'dup') {
19546 var index = this.readInt();
19547 length = this.readInt();
19548 this.getToken(); // read in 'RD' or '-|'
19549 data = stream.makeSubStream(stream.pos, length);
19550 lenIV = program.properties.privateData['lenIV'];
19551 encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);
19552 // Skip past the required space and binary data.
19553 stream.skip(length);
19554 this.nextChar();
19555 token = this.getToken(); // read in 'NP' or '|'
19556 if (token === 'noaccess') {
19557 this.getToken(); // read in 'put'
19558 }
19559 subrs[index] = encoded;
19560 }
19561 break;
19562 case 'BlueValues':
19563 case 'OtherBlues':
19564 case 'FamilyBlues':
19565 case 'FamilyOtherBlues':
19566 var blueArray = this.readNumberArray();
19567 // *Blue* values may contain invalid data: disables reading of
19568 // those values when hinting is disabled.
19569 if (blueArray.length > 0 && (blueArray.length % 2) === 0 &&
19570 HINTING_ENABLED) {
19571 program.properties.privateData[token] = blueArray;
19572 }
19573 break;
19574 case 'StemSnapH':
19575 case 'StemSnapV':
19576 program.properties.privateData[token] = this.readNumberArray();
19577 break;
19578 case 'StdHW':
19579 case 'StdVW':
19580 program.properties.privateData[token] =
19581 this.readNumberArray()[0];
19582 break;
19583 case 'BlueShift':
19584 case 'lenIV':
19585 case 'BlueFuzz':
19586 case 'BlueScale':
19587 case 'LanguageGroup':
19588 case 'ExpansionFactor':
19589 program.properties.privateData[token] = this.readNumber();
19590 break;
19591 case 'ForceBold':
19592 program.properties.privateData[token] = this.readBoolean();
19593 break;
19594 }
19595 }
19596
19597 for (var i = 0; i < charstrings.length; i++) {
19598 glyph = charstrings[i].glyph;
19599 encoded = charstrings[i].encoded;
19600 var charString = new Type1CharString();
19601 var error = charString.convert(encoded, subrs);
19602 var output = charString.output;
19603 if (error) {
19604 // It seems when FreeType encounters an error while evaluating a glyph
19605 // that it completely ignores the glyph so we'll mimic that behaviour
19606 // here and put an endchar to make the validator happy.
19607 output = [14];
19608 }
19609 program.charstrings.push({
19610 glyphName: glyph,
19611 charstring: output,
19612 width: charString.width,
19613 lsb: charString.lsb,
19614 seac: charString.seac
19615 });
19616 }
19617
19618 return program;
19619 },
19620
19621 extractFontHeader: function Type1Parser_extractFontHeader(properties) {
19622 var token;
19623 while ((token = this.getToken()) !== null) {
19624 if (token !== '/') {
19625 continue;
19626 }
19627 token = this.getToken();
19628 switch (token) {
19629 case 'FontMatrix':
19630 var matrix = this.readNumberArray();
19631 properties.fontMatrix = matrix;
19632 break;
19633 case 'Encoding':
19634 var encodingArg = this.getToken();
19635 var encoding;
19636 if (!/^\d+$/.test(encodingArg)) {
19637 // encoding name is specified
19638 encoding = Encodings[encodingArg];
19639 } else {
19640 encoding = [];
19641 var size = parseInt(encodingArg, 10) | 0;
19642 this.getToken(); // read in 'array'
19643
19644 for (var j = 0; j < size; j++) {
19645 token = this.getToken();
19646 // skipping till first dup or def (e.g. ignoring for statement)
19647 while (token !== 'dup' && token !== 'def') {
19648 token = this.getToken();
19649 if (token === null) {
19650 return; // invalid header
19651 }
19652 }
19653 if (token === 'def') {
19654 break; // read all array data
19655 }
19656 var index = this.readInt();
19657 this.getToken(); // read in '/'
19658 var glyph = this.getToken();
19659 encoding[index] = glyph;
19660 this.getToken(); // read the in 'put'
19661 }
19662 }
19663 properties.builtInEncoding = encoding;
19664 break;
19665 case 'FontBBox':
19666 var fontBBox = this.readNumberArray();
19667 // adjusting ascent/descent
19668 properties.ascent = fontBBox[3];
19669 properties.descent = fontBBox[1];
19670 properties.ascentScaled = true;
19671 break;
19672 }
19673 }
19674 }
19675 };
19676
19677 return Type1Parser;
19678 })();
19679
19680 /**
19681 * The CFF class takes a Type1 file and wrap it into a
19682 * 'Compact Font Format' which itself embed Type2 charstrings.
19683 */
19684 var CFFStandardStrings = [
19685 '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
19686 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
19687 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
19688 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
19689 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
19690 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
19691 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum',
19692 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
19693 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
19694 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
19695 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
19696 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
19697 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
19698 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase',
19699 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown',
19700 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent',
19701 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash',
19702 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae',
19703 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior',
19704 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn',
19705 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters',
19706 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior',
19707 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring',
19708 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',
19709 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',
19710 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',
19711 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',
19712 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde',
19713 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute',
19714 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex',
19715 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex',
19716 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall',
19717 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall',
19718 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
19719 'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle',
19720 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle',
19721 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior',
19722 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior',
19723 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior',
19724 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
19725 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior',
19726 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall',
19727 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',
19728 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
19729 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
19730 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',
19731 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',
19732 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall',
19733 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior',
19734 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth',
19735 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds',
19736 'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',
19737 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior',
19738 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior',
19739 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior',
19740 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior',
19741 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall',
19742 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall',
19743 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall',
19744 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall',
19745 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall',
19746 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall',
19747 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall',
19748 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003',
19749 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold'
19750 ];
19751
19752 // Type1Font is also a CIDFontType0.
19753 var Type1Font = function Type1Font(name, file, properties) {
19754 // Some bad generators embed pfb file as is, we have to strip 6-byte headers.
19755 // Also, length1 and length2 might be off by 6 bytes as well.
19756 // http://www.math.ubc.ca/~cass/piscript/type1.pdf
19757 var PFB_HEADER_SIZE = 6;
19758 var headerBlockLength = properties.length1;
19759 var eexecBlockLength = properties.length2;
19760 var pfbHeader = file.peekBytes(PFB_HEADER_SIZE);
19761 var pfbHeaderPresent = pfbHeader[0] === 0x80 && pfbHeader[1] === 0x01;
19762 if (pfbHeaderPresent) {
19763 file.skip(PFB_HEADER_SIZE);
19764 headerBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) |
19765 (pfbHeader[3] << 8) | pfbHeader[2];
19766 }
19767
19768 // Get the data block containing glyphs and subrs informations
19769 var headerBlock = new Stream(file.getBytes(headerBlockLength));
19770 var headerBlockParser = new Type1Parser(headerBlock);
19771 headerBlockParser.extractFontHeader(properties);
19772
19773 if (pfbHeaderPresent) {
19774 pfbHeader = file.getBytes(PFB_HEADER_SIZE);
19775 eexecBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) |
19776 (pfbHeader[3] << 8) | pfbHeader[2];
19777 }
19778
19779 // Decrypt the data blocks and retrieve it's content
19780 var eexecBlock = new Stream(file.getBytes(eexecBlockLength));
19781 var eexecBlockParser = new Type1Parser(eexecBlock, true);
19782 var data = eexecBlockParser.extractFontProgram();
19783 for (var info in data.properties) {
19784 properties[info] = data.properties[info];
19785 }
19786
19787 var charstrings = data.charstrings;
19788 var type2Charstrings = this.getType2Charstrings(charstrings);
19789 var subrs = this.getType2Subrs(data.subrs);
19790
19791 this.charstrings = charstrings;
19792 this.data = this.wrap(name, type2Charstrings, this.charstrings,
19793 subrs, properties);
19794 this.seacs = this.getSeacs(data.charstrings);
19795 };
19796
19797 Type1Font.prototype = {
19798 get numGlyphs() {
19799 return this.charstrings.length + 1;
19800 },
19801
19802 getCharset: function Type1Font_getCharset() {
19803 var charset = ['.notdef'];
19804 var charstrings = this.charstrings;
19805 for (var glyphId = 0; glyphId < charstrings.length; glyphId++) {
19806 charset.push(charstrings[glyphId].glyphName);
19807 }
19808 return charset;
19809 },
19810
19811 getGlyphMapping: function Type1Font_getGlyphMapping(properties) {
19812 var charstrings = this.charstrings;
19813 var glyphNames = ['.notdef'], glyphId;
19814 for (glyphId = 0; glyphId < charstrings.length; glyphId++) {
19815 glyphNames.push(charstrings[glyphId].glyphName);
19816 }
19817 var encoding = properties.builtInEncoding;
19818 if (encoding) {
19819 var builtInEncoding = {};
19820 for (var charCode in encoding) {
19821 glyphId = glyphNames.indexOf(encoding[charCode]);
19822 if (glyphId >= 0) {
19823 builtInEncoding[charCode] = glyphId;
19824 }
19825 }
19826 }
19827
19828 return type1FontGlyphMapping(properties, builtInEncoding, glyphNames);
19829 },
19830
19831 getSeacs: function Type1Font_getSeacs(charstrings) {
19832 var i, ii;
19833 var seacMap = [];
19834 for (i = 0, ii = charstrings.length; i < ii; i++) {
19835 var charstring = charstrings[i];
19836 if (charstring.seac) {
19837 // Offset by 1 for .notdef
19838 seacMap[i + 1] = charstring.seac;
19839 }
19840 }
19841 return seacMap;
19842 },
19843
19844 getType2Charstrings: function Type1Font_getType2Charstrings(
19845 type1Charstrings) {
19846 var type2Charstrings = [];
19847 for (var i = 0, ii = type1Charstrings.length; i < ii; i++) {
19848 type2Charstrings.push(type1Charstrings[i].charstring);
19849 }
19850 return type2Charstrings;
19851 },
19852
19853 getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) {
19854 var bias = 0;
19855 var count = type1Subrs.length;
19856 if (count < 1133) {
19857 bias = 107;
19858 } else if (count < 33769) {
19859 bias = 1131;
19860 } else {
19861 bias = 32768;
19862 }
19863
19864 // Add a bunch of empty subrs to deal with the Type2 bias
19865 var type2Subrs = [];
19866 var i;
19867 for (i = 0; i < bias; i++) {
19868 type2Subrs.push([0x0B]);
19869 }
19870
19871 for (i = 0; i < count; i++) {
19872 type2Subrs.push(type1Subrs[i]);
19873 }
19874
19875 return type2Subrs;
19876 },
19877
19878 wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) {
19879 var cff = new CFF();
19880 cff.header = new CFFHeader(1, 0, 4, 4);
19881
19882 cff.names = [name];
19883
19884 var topDict = new CFFTopDict();
19885 // CFF strings IDs 0...390 are predefined names, so refering
19886 // to entries in our own String INDEX starts at SID 391.
19887 topDict.setByName('version', 391);
19888 topDict.setByName('Notice', 392);
19889 topDict.setByName('FullName', 393);
19890 topDict.setByName('FamilyName', 394);
19891 topDict.setByName('Weight', 395);
19892 topDict.setByName('Encoding', null); // placeholder
19893 topDict.setByName('FontMatrix', properties.fontMatrix);
19894 topDict.setByName('FontBBox', properties.bbox);
19895 topDict.setByName('charset', null); // placeholder
19896 topDict.setByName('CharStrings', null); // placeholder
19897 topDict.setByName('Private', null); // placeholder
19898 cff.topDict = topDict;
19899
19900 var strings = new CFFStrings();
19901 strings.add('Version 0.11'); // Version
19902 strings.add('See original notice'); // Notice
19903 strings.add(name); // FullName
19904 strings.add(name); // FamilyName
19905 strings.add('Medium'); // Weight
19906 cff.strings = strings;
19907
19908 cff.globalSubrIndex = new CFFIndex();
19909
19910 var count = glyphs.length;
19911 var charsetArray = [0];
19912 var i, ii;
19913 for (i = 0; i < count; i++) {
19914 var index = CFFStandardStrings.indexOf(charstrings[i].glyphName);
19915 // TODO: Insert the string and correctly map it. Previously it was
19916 // thought mapping names that aren't in the standard strings to .notdef
19917 // was fine, however in issue818 when mapping them all to .notdef the
19918 // adieresis glyph no longer worked.
19919 if (index === -1) {
19920 index = 0;
19921 }
19922 charsetArray.push((index >> 8) & 0xff, index & 0xff);
19923 }
19924 cff.charset = new CFFCharset(false, 0, [], charsetArray);
19925
19926 var charStringsIndex = new CFFIndex();
19927 charStringsIndex.add([0x8B, 0x0E]); // .notdef
19928 for (i = 0; i < count; i++) {
19929 charStringsIndex.add(glyphs[i]);
19930 }
19931 cff.charStrings = charStringsIndex;
19932
19933 var privateDict = new CFFPrivateDict();
19934 privateDict.setByName('Subrs', null); // placeholder
19935 var fields = [
19936 'BlueValues',
19937 'OtherBlues',
19938 'FamilyBlues',
19939 'FamilyOtherBlues',
19940 'StemSnapH',
19941 'StemSnapV',
19942 'BlueShift',
19943 'BlueFuzz',
19944 'BlueScale',
19945 'LanguageGroup',
19946 'ExpansionFactor',
19947 'ForceBold',
19948 'StdHW',
19949 'StdVW'
19950 ];
19951 for (i = 0, ii = fields.length; i < ii; i++) {
19952 var field = fields[i];
19953 if (!properties.privateData.hasOwnProperty(field)) {
19954 continue;
19955 }
19956 var value = properties.privateData[field];
19957 if (isArray(value)) {
19958 // All of the private dictionary array data in CFF must be stored as
19959 // "delta-encoded" numbers.
19960 for (var j = value.length - 1; j > 0; j--) {
19961 value[j] -= value[j - 1]; // ... difference from previous value
19962 }
19963 }
19964 privateDict.setByName(field, value);
19965 }
19966 cff.topDict.privateDict = privateDict;
19967
19968 var subrIndex = new CFFIndex();
19969 for (i = 0, ii = subrs.length; i < ii; i++) {
19970 subrIndex.add(subrs[i]);
19971 }
19972 privateDict.subrsIndex = subrIndex;
19973
19974 var compiler = new CFFCompiler(cff);
19975 return compiler.compile();
19976 }
19977 };
19978
19979 var CFFFont = (function CFFFontClosure() {
19980 function CFFFont(file, properties) {
19981 this.properties = properties;
19982
19983 var parser = new CFFParser(file, properties);
19984 this.cff = parser.parse();
19985 var compiler = new CFFCompiler(this.cff);
19986 this.seacs = this.cff.seacs;
19987 try {
19988 this.data = compiler.compile();
19989 } catch (e) {
19990 warn('Failed to compile font ' + properties.loadedName);
19991 // There may have just been an issue with the compiler, set the data
19992 // anyway and hope the font loaded.
19993 this.data = file;
19994 }
19995 }
19996
19997 CFFFont.prototype = {
19998 get numGlyphs() {
19999 return this.cff.charStrings.count;
20000 },
20001 getCharset: function CFFFont_getCharset() {
20002 return this.cff.charset.charset;
20003 },
20004 getGlyphMapping: function CFFFont_getGlyphMapping() {
20005 var cff = this.cff;
20006 var properties = this.properties;
20007 var charsets = cff.charset.charset;
20008 var charCodeToGlyphId;
20009 var glyphId;
20010
20011 if (properties.composite) {
20012 charCodeToGlyphId = Object.create(null);
20013 if (cff.isCIDFont) {
20014 // If the font is actually a CID font then we should use the charset
20015 // to map CIDs to GIDs.
20016 for (glyphId = 0; glyphId < charsets.length; glyphId++) {
20017 var cid = charsets[glyphId];
20018 var charCode = properties.cMap.charCodeOf(cid);
20019 charCodeToGlyphId[charCode] = glyphId;
20020 }
20021 } else {
20022 // If it is NOT actually a CID font then CIDs should be mapped
20023 // directly to GIDs.
20024 for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) {
20025 charCodeToGlyphId[glyphId] = glyphId;
20026 }
20027 }
20028 return charCodeToGlyphId;
20029 }
20030
20031 var encoding = cff.encoding ? cff.encoding.encoding : null;
20032 charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets);
20033 return charCodeToGlyphId;
20034 }
20035 };
20036
20037 return CFFFont;
20038 })();
20039
20040 var CFFParser = (function CFFParserClosure() {
20041 var CharstringValidationData = [
20042 null,
20043 { id: 'hstem', min: 2, stackClearing: true, stem: true },
20044 null,
20045 { id: 'vstem', min: 2, stackClearing: true, stem: true },
20046 { id: 'vmoveto', min: 1, stackClearing: true },
20047 { id: 'rlineto', min: 2, resetStack: true },
20048 { id: 'hlineto', min: 1, resetStack: true },
20049 { id: 'vlineto', min: 1, resetStack: true },
20050 { id: 'rrcurveto', min: 6, resetStack: true },
20051 null,
20052 { id: 'callsubr', min: 1, undefStack: true },
20053 { id: 'return', min: 0, undefStack: true },
20054 null, // 12
20055 null,
20056 { id: 'endchar', min: 0, stackClearing: true },
20057 null,
20058 null,
20059 null,
20060 { id: 'hstemhm', min: 2, stackClearing: true, stem: true },
20061 { id: 'hintmask', min: 0, stackClearing: true },
20062 { id: 'cntrmask', min: 0, stackClearing: true },
20063 { id: 'rmoveto', min: 2, stackClearing: true },
20064 { id: 'hmoveto', min: 1, stackClearing: true },
20065 { id: 'vstemhm', min: 2, stackClearing: true, stem: true },
20066 { id: 'rcurveline', min: 8, resetStack: true },
20067 { id: 'rlinecurve', min: 8, resetStack: true },
20068 { id: 'vvcurveto', min: 4, resetStack: true },
20069 { id: 'hhcurveto', min: 4, resetStack: true },
20070 null, // shortint
20071 { id: 'callgsubr', min: 1, undefStack: true },
20072 { id: 'vhcurveto', min: 4, resetStack: true },
20073 { id: 'hvcurveto', min: 4, resetStack: true }
20074 ];
20075 var CharstringValidationData12 = [
20076 null,
20077 null,
20078 null,
20079 { id: 'and', min: 2, stackDelta: -1 },
20080 { id: 'or', min: 2, stackDelta: -1 },
20081 { id: 'not', min: 1, stackDelta: 0 },
20082 null,
20083 null,
20084 null,
20085 { id: 'abs', min: 1, stackDelta: 0 },
20086 { id: 'add', min: 2, stackDelta: -1,
20087 stackFn: function stack_div(stack, index) {
20088 stack[index - 2] = stack[index - 2] + stack[index - 1];
20089 }
20090 },
20091 { id: 'sub', min: 2, stackDelta: -1,
20092 stackFn: function stack_div(stack, index) {
20093 stack[index - 2] = stack[index - 2] - stack[index - 1];
20094 }
20095 },
20096 { id: 'div', min: 2, stackDelta: -1,
20097 stackFn: function stack_div(stack, index) {
20098 stack[index - 2] = stack[index - 2] / stack[index - 1];
20099 }
20100 },
20101 null,
20102 { id: 'neg', min: 1, stackDelta: 0,
20103 stackFn: function stack_div(stack, index) {
20104 stack[index - 1] = -stack[index - 1];
20105 }
20106 },
20107 { id: 'eq', min: 2, stackDelta: -1 },
20108 null,
20109 null,
20110 { id: 'drop', min: 1, stackDelta: -1 },
20111 null,
20112 { id: 'put', min: 2, stackDelta: -2 },
20113 { id: 'get', min: 1, stackDelta: 0 },
20114 { id: 'ifelse', min: 4, stackDelta: -3 },
20115 { id: 'random', min: 0, stackDelta: 1 },
20116 { id: 'mul', 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: 'sqrt', min: 1, stackDelta: 0 },
20123 { id: 'dup', min: 1, stackDelta: 1 },
20124 { id: 'exch', min: 2, stackDelta: 0 },
20125 { id: 'index', min: 2, stackDelta: 0 },
20126 { id: 'roll', min: 3, stackDelta: -2 },
20127 null,
20128 null,
20129 null,
20130 { id: 'hflex', min: 7, resetStack: true },
20131 { id: 'flex', min: 13, resetStack: true },
20132 { id: 'hflex1', min: 9, resetStack: true },
20133 { id: 'flex1', min: 11, resetStack: true }
20134 ];
20135
20136 function CFFParser(file, properties) {
20137 this.bytes = file.getBytes();
20138 this.properties = properties;
20139 }
20140 CFFParser.prototype = {
20141 parse: function CFFParser_parse() {
20142 var properties = this.properties;
20143 var cff = new CFF();
20144 this.cff = cff;
20145
20146 // The first five sections must be in order, all the others are reached
20147 // via offsets contained in one of the below.
20148 var header = this.parseHeader();
20149 var nameIndex = this.parseIndex(header.endPos);
20150 var topDictIndex = this.parseIndex(nameIndex.endPos);
20151 var stringIndex = this.parseIndex(topDictIndex.endPos);
20152 var globalSubrIndex = this.parseIndex(stringIndex.endPos);
20153
20154 var topDictParsed = this.parseDict(topDictIndex.obj.get(0));
20155 var topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings);
20156
20157 cff.header = header.obj;
20158 cff.names = this.parseNameIndex(nameIndex.obj);
20159 cff.strings = this.parseStringIndex(stringIndex.obj);
20160 cff.topDict = topDict;
20161 cff.globalSubrIndex = globalSubrIndex.obj;
20162
20163 this.parsePrivateDict(cff.topDict);
20164
20165 cff.isCIDFont = topDict.hasName('ROS');
20166
20167 var charStringOffset = topDict.getByName('CharStrings');
20168 var charStringsAndSeacs = this.parseCharStrings(charStringOffset);
20169 cff.charStrings = charStringsAndSeacs.charStrings;
20170 cff.seacs = charStringsAndSeacs.seacs;
20171 cff.widths = charStringsAndSeacs.widths;
20172
20173 var fontMatrix = topDict.getByName('FontMatrix');
20174 if (fontMatrix) {
20175 properties.fontMatrix = fontMatrix;
20176 }
20177
20178 var fontBBox = topDict.getByName('FontBBox');
20179 if (fontBBox) {
20180 // adjusting ascent/descent
20181 properties.ascent = fontBBox[3];
20182 properties.descent = fontBBox[1];
20183 properties.ascentScaled = true;
20184 }
20185
20186 var charset, encoding;
20187 if (cff.isCIDFont) {
20188 var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj;
20189 for (var i = 0, ii = fdArrayIndex.count; i < ii; ++i) {
20190 var dictRaw = fdArrayIndex.get(i);
20191 var fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw),
20192 cff.strings);
20193 this.parsePrivateDict(fontDict);
20194 cff.fdArray.push(fontDict);
20195 }
20196 // cid fonts don't have an encoding
20197 encoding = null;
20198 charset = this.parseCharsets(topDict.getByName('charset'),
20199 cff.charStrings.count, cff.strings, true);
20200 cff.fdSelect = this.parseFDSelect(topDict.getByName('FDSelect'),
20201 cff.charStrings.count);
20202 } else {
20203 charset = this.parseCharsets(topDict.getByName('charset'),
20204 cff.charStrings.count, cff.strings, false);
20205 encoding = this.parseEncoding(topDict.getByName('Encoding'),
20206 properties,
20207 cff.strings, charset.charset);
20208 }
20209 cff.charset = charset;
20210 cff.encoding = encoding;
20211
20212 return cff;
20213 },
20214 parseHeader: function CFFParser_parseHeader() {
20215 var bytes = this.bytes;
20216 var bytesLength = bytes.length;
20217 var offset = 0;
20218
20219 // Prevent an infinite loop, by checking that the offset is within the
20220 // bounds of the bytes array. Necessary in empty, or invalid, font files.
20221 while (offset < bytesLength && bytes[offset] !== 1) {
20222 ++offset;
20223 }
20224 if (offset >= bytesLength) {
20225 error('Invalid CFF header');
20226 } else if (offset !== 0) {
20227 info('cff data is shifted');
20228 bytes = bytes.subarray(offset);
20229 this.bytes = bytes;
20230 }
20231 var major = bytes[0];
20232 var minor = bytes[1];
20233 var hdrSize = bytes[2];
20234 var offSize = bytes[3];
20235 var header = new CFFHeader(major, minor, hdrSize, offSize);
20236 return { obj: header, endPos: hdrSize };
20237 },
20238 parseDict: function CFFParser_parseDict(dict) {
20239 var pos = 0;
20240
20241 function parseOperand() {
20242 var value = dict[pos++];
20243 if (value === 30) {
20244 return parseFloatOperand(pos);
20245 } else if (value === 28) {
20246 value = dict[pos++];
20247 value = ((value << 24) | (dict[pos++] << 16)) >> 16;
20248 return value;
20249 } else if (value === 29) {
20250 value = dict[pos++];
20251 value = (value << 8) | dict[pos++];
20252 value = (value << 8) | dict[pos++];
20253 value = (value << 8) | dict[pos++];
20254 return value;
20255 } else if (value >= 32 && value <= 246) {
20256 return value - 139;
20257 } else if (value >= 247 && value <= 250) {
20258 return ((value - 247) * 256) + dict[pos++] + 108;
20259 } else if (value >= 251 && value <= 254) {
20260 return -((value - 251) * 256) - dict[pos++] - 108;
20261 } else {
20262 error('255 is not a valid DICT command');
20263 }
20264 return -1;
20265 }
20266
20267 function parseFloatOperand() {
20268 var str = '';
20269 var eof = 15;
20270 var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8',
20271 '9', '.', 'E', 'E-', null, '-'];
20272 var length = dict.length;
20273 while (pos < length) {
20274 var b = dict[pos++];
20275 var b1 = b >> 4;
20276 var b2 = b & 15;
20277
20278 if (b1 === eof) {
20279 break;
20280 }
20281 str += lookup[b1];
20282
20283 if (b2 === eof) {
20284 break;
20285 }
20286 str += lookup[b2];
20287 }
20288 return parseFloat(str);
20289 }
20290
20291 var operands = [];
20292 var entries = [];
20293
20294 pos = 0;
20295 var end = dict.length;
20296 while (pos < end) {
20297 var b = dict[pos];
20298 if (b <= 21) {
20299 if (b === 12) {
20300 b = (b << 8) | dict[++pos];
20301 }
20302 entries.push([b, operands]);
20303 operands = [];
20304 ++pos;
20305 } else {
20306 operands.push(parseOperand());
20307 }
20308 }
20309 return entries;
20310 },
20311 parseIndex: function CFFParser_parseIndex(pos) {
20312 var cffIndex = new CFFIndex();
20313 var bytes = this.bytes;
20314 var count = (bytes[pos++] << 8) | bytes[pos++];
20315 var offsets = [];
20316 var end = pos;
20317 var i, ii;
20318
20319 if (count !== 0) {
20320 var offsetSize = bytes[pos++];
20321 // add 1 for offset to determine size of last object
20322 var startPos = pos + ((count + 1) * offsetSize) - 1;
20323
20324 for (i = 0, ii = count + 1; i < ii; ++i) {
20325 var offset = 0;
20326 for (var j = 0; j < offsetSize; ++j) {
20327 offset <<= 8;
20328 offset += bytes[pos++];
20329 }
20330 offsets.push(startPos + offset);
20331 }
20332 end = offsets[count];
20333 }
20334 for (i = 0, ii = offsets.length - 1; i < ii; ++i) {
20335 var offsetStart = offsets[i];
20336 var offsetEnd = offsets[i + 1];
20337 cffIndex.add(bytes.subarray(offsetStart, offsetEnd));
20338 }
20339 return {obj: cffIndex, endPos: end};
20340 },
20341 parseNameIndex: function CFFParser_parseNameIndex(index) {
20342 var names = [];
20343 for (var i = 0, ii = index.count; i < ii; ++i) {
20344 var name = index.get(i);
20345 // OTS doesn't allow names to be over 127 characters.
20346 var length = Math.min(name.length, 127);
20347 var data = [];
20348 // OTS also only permits certain characters in the name.
20349 for (var j = 0; j < length; ++j) {
20350 var c = name[j];
20351 if (j === 0 && c === 0) {
20352 data[j] = c;
20353 continue;
20354 }
20355 if ((c < 33 || c > 126) || c === 91 /* [ */ || c === 93 /* ] */ ||
20356 c === 40 /* ( */ || c === 41 /* ) */ || c === 123 /* { */ ||
20357 c === 125 /* } */ || c === 60 /* < */ || c === 62 /* > */ ||
20358 c === 47 /* / */ || c === 37 /* % */ || c === 35 /* # */) {
20359 data[j] = 95;
20360 continue;
20361 }
20362 data[j] = c;
20363 }
20364 names.push(bytesToString(data));
20365 }
20366 return names;
20367 },
20368 parseStringIndex: function CFFParser_parseStringIndex(index) {
20369 var strings = new CFFStrings();
20370 for (var i = 0, ii = index.count; i < ii; ++i) {
20371 var data = index.get(i);
20372 strings.add(bytesToString(data));
20373 }
20374 return strings;
20375 },
20376 createDict: function CFFParser_createDict(Type, dict, strings) {
20377 var cffDict = new Type(strings);
20378 for (var i = 0, ii = dict.length; i < ii; ++i) {
20379 var pair = dict[i];
20380 var key = pair[0];
20381 var value = pair[1];
20382 cffDict.setByKey(key, value);
20383 }
20384 return cffDict;
20385 },
20386 parseCharStrings: function CFFParser_parseCharStrings(charStringOffset) {
20387 var charStrings = this.parseIndex(charStringOffset).obj;
20388 var seacs = [];
20389 var widths = [];
20390 var count = charStrings.count;
20391 for (var i = 0; i < count; i++) {
20392 var charstring = charStrings.get(i);
20393
20394 var stackSize = 0;
20395 var stack = [];
20396 var undefStack = true;
20397 var hints = 0;
20398 var valid = true;
20399 var data = charstring;
20400 var length = data.length;
20401 var firstStackClearing = true;
20402 for (var j = 0; j < length;) {
20403 var value = data[j++];
20404 var validationCommand = null;
20405 if (value === 12) {
20406 var q = data[j++];
20407 if (q === 0) {
20408 // The CFF specification state that the 'dotsection' command
20409 // (12, 0) is deprecated and treated as a no-op, but all Type2
20410 // charstrings processors should support them. Unfortunately
20411 // the font sanitizer don't. As a workaround the sequence (12, 0)
20412 // is replaced by a useless (0, hmoveto).
20413 data[j - 2] = 139;
20414 data[j - 1] = 22;
20415 stackSize = 0;
20416 } else {
20417 validationCommand = CharstringValidationData12[q];
20418 }
20419 } else if (value === 28) { // number (16 bit)
20420 stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16)) >> 16;
20421 j += 2;
20422 stackSize++;
20423 } else if (value === 14) {
20424 if (stackSize >= 4) {
20425 stackSize -= 4;
20426 if (SEAC_ANALYSIS_ENABLED) {
20427 seacs[i] = stack.slice(stackSize, stackSize + 4);
20428 valid = false;
20429 }
20430 }
20431 validationCommand = CharstringValidationData[value];
20432 } else if (value >= 32 && value <= 246) { // number
20433 stack[stackSize] = value - 139;
20434 stackSize++;
20435 } else if (value >= 247 && value <= 254) { // number (+1 bytes)
20436 stack[stackSize] = (value < 251 ?
20437 ((value - 247) << 8) + data[j] + 108 :
20438 -((value - 251) << 8) - data[j] - 108);
20439 j++;
20440 stackSize++;
20441 } else if (value === 255) { // number (32 bit)
20442 stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) |
20443 (data[j + 2] << 8) | data[j + 3]) / 65536;
20444 j += 4;
20445 stackSize++;
20446 } else if (value === 19 || value === 20) {
20447 hints += stackSize >> 1;
20448 j += (hints + 7) >> 3; // skipping right amount of hints flag data
20449 stackSize %= 2;
20450 validationCommand = CharstringValidationData[value];
20451 } else {
20452 validationCommand = CharstringValidationData[value];
20453 }
20454 if (validationCommand) {
20455 if (validationCommand.stem) {
20456 hints += stackSize >> 1;
20457 }
20458 if ('min' in validationCommand) {
20459 if (!undefStack && stackSize < validationCommand.min) {
20460 warn('Not enough parameters for ' + validationCommand.id +
20461 '; actual: ' + stackSize +
20462 ', expected: ' + validationCommand.min);
20463 valid = false;
20464 break;
20465 }
20466 }
20467 if (firstStackClearing && validationCommand.stackClearing) {
20468 firstStackClearing = false;
20469 // the optional character width can be found before the first
20470 // stack-clearing command arguments
20471 stackSize -= validationCommand.min;
20472 if (stackSize >= 2 && validationCommand.stem) {
20473 // there are even amount of arguments for stem commands
20474 stackSize %= 2;
20475 } else if (stackSize > 1) {
20476 warn('Found too many parameters for stack-clearing command');
20477 }
20478 if (stackSize > 0 && stack[stackSize - 1] >= 0) {
20479 widths[i] = stack[stackSize - 1];
20480 }
20481 }
20482 if ('stackDelta' in validationCommand) {
20483 if ('stackFn' in validationCommand) {
20484 validationCommand.stackFn(stack, stackSize);
20485 }
20486 stackSize += validationCommand.stackDelta;
20487 } else if (validationCommand.stackClearing) {
20488 stackSize = 0;
20489 } else if (validationCommand.resetStack) {
20490 stackSize = 0;
20491 undefStack = false;
20492 } else if (validationCommand.undefStack) {
20493 stackSize = 0;
20494 undefStack = true;
20495 firstStackClearing = false;
20496 }
20497 }
20498 }
20499 if (!valid) {
20500 // resetting invalid charstring to single 'endchar'
20501 charStrings.set(i, new Uint8Array([14]));
20502 }
20503 }
20504 return { charStrings: charStrings, seacs: seacs, widths: widths };
20505 },
20506 emptyPrivateDictionary:
20507 function CFFParser_emptyPrivateDictionary(parentDict) {
20508 var privateDict = this.createDict(CFFPrivateDict, [],
20509 parentDict.strings);
20510 parentDict.setByKey(18, [0, 0]);
20511 parentDict.privateDict = privateDict;
20512 },
20513 parsePrivateDict: function CFFParser_parsePrivateDict(parentDict) {
20514 // no private dict, do nothing
20515 if (!parentDict.hasName('Private')) {
20516 this.emptyPrivateDictionary(parentDict);
20517 return;
20518 }
20519 var privateOffset = parentDict.getByName('Private');
20520 // make sure the params are formatted correctly
20521 if (!isArray(privateOffset) || privateOffset.length !== 2) {
20522 parentDict.removeByName('Private');
20523 return;
20524 }
20525 var size = privateOffset[0];
20526 var offset = privateOffset[1];
20527 // remove empty dicts or ones that refer to invalid location
20528 if (size === 0 || offset >= this.bytes.length) {
20529 this.emptyPrivateDictionary(parentDict);
20530 return;
20531 }
20532
20533 var privateDictEnd = offset + size;
20534 var dictData = this.bytes.subarray(offset, privateDictEnd);
20535 var dict = this.parseDict(dictData);
20536 var privateDict = this.createDict(CFFPrivateDict, dict,
20537 parentDict.strings);
20538 parentDict.privateDict = privateDict;
20539
20540 // Parse the Subrs index also since it's relative to the private dict.
20541 if (!privateDict.getByName('Subrs')) {
20542 return;
20543 }
20544 var subrsOffset = privateDict.getByName('Subrs');
20545 var relativeOffset = offset + subrsOffset;
20546 // Validate the offset.
20547 if (subrsOffset === 0 || relativeOffset >= this.bytes.length) {
20548 this.emptyPrivateDictionary(parentDict);
20549 return;
20550 }
20551 var subrsIndex = this.parseIndex(relativeOffset);
20552 privateDict.subrsIndex = subrsIndex.obj;
20553 },
20554 parseCharsets: function CFFParser_parseCharsets(pos, length, strings, cid) {
20555 if (pos === 0) {
20556 return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE,
20557 ISOAdobeCharset);
20558 } else if (pos === 1) {
20559 return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT,
20560 ExpertCharset);
20561 } else if (pos === 2) {
20562 return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET,
20563 ExpertSubsetCharset);
20564 }
20565
20566 var bytes = this.bytes;
20567 var start = pos;
20568 var format = bytes[pos++];
20569 var charset = ['.notdef'];
20570 var id, count, i;
20571
20572 // subtract 1 for the .notdef glyph
20573 length -= 1;
20574
20575 switch (format) {
20576 case 0:
20577 for (i = 0; i < length; i++) {
20578 id = (bytes[pos++] << 8) | bytes[pos++];
20579 charset.push(cid ? id : strings.get(id));
20580 }
20581 break;
20582 case 1:
20583 while (charset.length <= length) {
20584 id = (bytes[pos++] << 8) | bytes[pos++];
20585 count = bytes[pos++];
20586 for (i = 0; i <= count; i++) {
20587 charset.push(cid ? id++ : strings.get(id++));
20588 }
20589 }
20590 break;
20591 case 2:
20592 while (charset.length <= length) {
20593 id = (bytes[pos++] << 8) | bytes[pos++];
20594 count = (bytes[pos++] << 8) | bytes[pos++];
20595 for (i = 0; i <= count; i++) {
20596 charset.push(cid ? id++ : strings.get(id++));
20597 }
20598 }
20599 break;
20600 default:
20601 error('Unknown charset format');
20602 }
20603 // Raw won't be needed if we actually compile the charset.
20604 var end = pos;
20605 var raw = bytes.subarray(start, end);
20606
20607 return new CFFCharset(false, format, charset, raw);
20608 },
20609 parseEncoding: function CFFParser_parseEncoding(pos,
20610 properties,
20611 strings,
20612 charset) {
20613 var encoding = {};
20614 var bytes = this.bytes;
20615 var predefined = false;
20616 var hasSupplement = false;
20617 var format, i, ii;
20618 var raw = null;
20619
20620 function readSupplement() {
20621 var supplementsCount = bytes[pos++];
20622 for (i = 0; i < supplementsCount; i++) {
20623 var code = bytes[pos++];
20624 var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);
20625 encoding[code] = charset.indexOf(strings.get(sid));
20626 }
20627 }
20628
20629 if (pos === 0 || pos === 1) {
20630 predefined = true;
20631 format = pos;
20632 var baseEncoding = pos ? Encodings.ExpertEncoding :
20633 Encodings.StandardEncoding;
20634 for (i = 0, ii = charset.length; i < ii; i++) {
20635 var index = baseEncoding.indexOf(charset[i]);
20636 if (index !== -1) {
20637 encoding[index] = i;
20638 }
20639 }
20640 } else {
20641 var dataStart = pos;
20642 format = bytes[pos++];
20643 switch (format & 0x7f) {
20644 case 0:
20645 var glyphsCount = bytes[pos++];
20646 for (i = 1; i <= glyphsCount; i++) {
20647 encoding[bytes[pos++]] = i;
20648 }
20649 break;
20650
20651 case 1:
20652 var rangesCount = bytes[pos++];
20653 var gid = 1;
20654 for (i = 0; i < rangesCount; i++) {
20655 var start = bytes[pos++];
20656 var left = bytes[pos++];
20657 for (var j = start; j <= start + left; j++) {
20658 encoding[j] = gid++;
20659 }
20660 }
20661 break;
20662
20663 default:
20664 error('Unknow encoding format: ' + format + ' in CFF');
20665 break;
20666 }
20667 var dataEnd = pos;
20668 if (format & 0x80) {
20669 // The font sanitizer does not support CFF encoding with a
20670 // supplement, since the encoding is not really used to map
20671 // between gid to glyph, let's overwrite what is declared in
20672 // the top dictionary to let the sanitizer think the font use
20673 // StandardEncoding, that's a lie but that's ok.
20674 bytes[dataStart] &= 0x7f;
20675 readSupplement();
20676 hasSupplement = true;
20677 }
20678 raw = bytes.subarray(dataStart, dataEnd);
20679 }
20680 format = format & 0x7f;
20681 return new CFFEncoding(predefined, format, encoding, raw);
20682 },
20683 parseFDSelect: function CFFParser_parseFDSelect(pos, length) {
20684 var start = pos;
20685 var bytes = this.bytes;
20686 var format = bytes[pos++];
20687 var fdSelect = [];
20688 var i;
20689
20690 switch (format) {
20691 case 0:
20692 for (i = 0; i < length; ++i) {
20693 var id = bytes[pos++];
20694 fdSelect.push(id);
20695 }
20696 break;
20697 case 3:
20698 var rangesCount = (bytes[pos++] << 8) | bytes[pos++];
20699 for (i = 0; i < rangesCount; ++i) {
20700 var first = (bytes[pos++] << 8) | bytes[pos++];
20701 var fdIndex = bytes[pos++];
20702 var next = (bytes[pos] << 8) | bytes[pos + 1];
20703 for (var j = first; j < next; ++j) {
20704 fdSelect.push(fdIndex);
20705 }
20706 }
20707 // Advance past the sentinel(next).
20708 pos += 2;
20709 break;
20710 default:
20711 error('Unknown fdselect format ' + format);
20712 break;
20713 }
20714 var end = pos;
20715 return new CFFFDSelect(fdSelect, bytes.subarray(start, end));
20716 }
20717 };
20718 return CFFParser;
20719 })();
20720
20721 // Compact Font Format
20722 var CFF = (function CFFClosure() {
20723 function CFF() {
20724 this.header = null;
20725 this.names = [];
20726 this.topDict = null;
20727 this.strings = new CFFStrings();
20728 this.globalSubrIndex = null;
20729
20730 // The following could really be per font, but since we only have one font
20731 // store them here.
20732 this.encoding = null;
20733 this.charset = null;
20734 this.charStrings = null;
20735 this.fdArray = [];
20736 this.fdSelect = null;
20737
20738 this.isCIDFont = false;
20739 }
20740 return CFF;
20741 })();
20742
20743 var CFFHeader = (function CFFHeaderClosure() {
20744 function CFFHeader(major, minor, hdrSize, offSize) {
20745 this.major = major;
20746 this.minor = minor;
20747 this.hdrSize = hdrSize;
20748 this.offSize = offSize;
20749 }
20750 return CFFHeader;
20751 })();
20752
20753 var CFFStrings = (function CFFStringsClosure() {
20754 function CFFStrings() {
20755 this.strings = [];
20756 }
20757 CFFStrings.prototype = {
20758 get: function CFFStrings_get(index) {
20759 if (index >= 0 && index <= 390) {
20760 return CFFStandardStrings[index];
20761 }
20762 if (index - 391 <= this.strings.length) {
20763 return this.strings[index - 391];
20764 }
20765 return CFFStandardStrings[0];
20766 },
20767 add: function CFFStrings_add(value) {
20768 this.strings.push(value);
20769 },
20770 get count() {
20771 return this.strings.length;
20772 }
20773 };
20774 return CFFStrings;
20775 })();
20776
20777 var CFFIndex = (function CFFIndexClosure() {
20778 function CFFIndex() {
20779 this.objects = [];
20780 this.length = 0;
20781 }
20782 CFFIndex.prototype = {
20783 add: function CFFIndex_add(data) {
20784 this.length += data.length;
20785 this.objects.push(data);
20786 },
20787 set: function CFFIndex_set(index, data) {
20788 this.length += data.length - this.objects[index].length;
20789 this.objects[index] = data;
20790 },
20791 get: function CFFIndex_get(index) {
20792 return this.objects[index];
20793 },
20794 get count() {
20795 return this.objects.length;
20796 }
20797 };
20798 return CFFIndex;
20799 })();
20800
20801 var CFFDict = (function CFFDictClosure() {
20802 function CFFDict(tables, strings) {
20803 this.keyToNameMap = tables.keyToNameMap;
20804 this.nameToKeyMap = tables.nameToKeyMap;
20805 this.defaults = tables.defaults;
20806 this.types = tables.types;
20807 this.opcodes = tables.opcodes;
20808 this.order = tables.order;
20809 this.strings = strings;
20810 this.values = {};
20811 }
20812 CFFDict.prototype = {
20813 // value should always be an array
20814 setByKey: function CFFDict_setByKey(key, value) {
20815 if (!(key in this.keyToNameMap)) {
20816 return false;
20817 }
20818 // ignore empty values
20819 if (value.length === 0) {
20820 return true;
20821 }
20822 var type = this.types[key];
20823 // remove the array wrapping these types of values
20824 if (type === 'num' || type === 'sid' || type === 'offset') {
20825 value = value[0];
20826 }
20827 this.values[key] = value;
20828 return true;
20829 },
20830 setByName: function CFFDict_setByName(name, value) {
20831 if (!(name in this.nameToKeyMap)) {
20832 error('Invalid dictionary name "' + name + '"');
20833 }
20834 this.values[this.nameToKeyMap[name]] = value;
20835 },
20836 hasName: function CFFDict_hasName(name) {
20837 return this.nameToKeyMap[name] in this.values;
20838 },
20839 getByName: function CFFDict_getByName(name) {
20840 if (!(name in this.nameToKeyMap)) {
20841 error('Invalid dictionary name "' + name + '"');
20842 }
20843 var key = this.nameToKeyMap[name];
20844 if (!(key in this.values)) {
20845 return this.defaults[key];
20846 }
20847 return this.values[key];
20848 },
20849 removeByName: function CFFDict_removeByName(name) {
20850 delete this.values[this.nameToKeyMap[name]];
20851 }
20852 };
20853 CFFDict.createTables = function CFFDict_createTables(layout) {
20854 var tables = {
20855 keyToNameMap: {},
20856 nameToKeyMap: {},
20857 defaults: {},
20858 types: {},
20859 opcodes: {},
20860 order: []
20861 };
20862 for (var i = 0, ii = layout.length; i < ii; ++i) {
20863 var entry = layout[i];
20864 var key = isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0];
20865 tables.keyToNameMap[key] = entry[1];
20866 tables.nameToKeyMap[entry[1]] = key;
20867 tables.types[key] = entry[2];
20868 tables.defaults[key] = entry[3];
20869 tables.opcodes[key] = isArray(entry[0]) ? entry[0] : [entry[0]];
20870 tables.order.push(key);
20871 }
20872 return tables;
20873 };
20874 return CFFDict;
20875 })();
20876
20877 var CFFTopDict = (function CFFTopDictClosure() {
20878 var layout = [
20879 [[12, 30], 'ROS', ['sid', 'sid', 'num'], null],
20880 [[12, 20], 'SyntheticBase', 'num', null],
20881 [0, 'version', 'sid', null],
20882 [1, 'Notice', 'sid', null],
20883 [[12, 0], 'Copyright', 'sid', null],
20884 [2, 'FullName', 'sid', null],
20885 [3, 'FamilyName', 'sid', null],
20886 [4, 'Weight', 'sid', null],
20887 [[12, 1], 'isFixedPitch', 'num', 0],
20888 [[12, 2], 'ItalicAngle', 'num', 0],
20889 [[12, 3], 'UnderlinePosition', 'num', -100],
20890 [[12, 4], 'UnderlineThickness', 'num', 50],
20891 [[12, 5], 'PaintType', 'num', 0],
20892 [[12, 6], 'CharstringType', 'num', 2],
20893 [[12, 7], 'FontMatrix', ['num', 'num', 'num', 'num', 'num', 'num'],
20894 [0.001, 0, 0, 0.001, 0, 0]],
20895 [13, 'UniqueID', 'num', null],
20896 [5, 'FontBBox', ['num', 'num', 'num', 'num'], [0, 0, 0, 0]],
20897 [[12, 8], 'StrokeWidth', 'num', 0],
20898 [14, 'XUID', 'array', null],
20899 [15, 'charset', 'offset', 0],
20900 [16, 'Encoding', 'offset', 0],
20901 [17, 'CharStrings', 'offset', 0],
20902 [18, 'Private', ['offset', 'offset'], null],
20903 [[12, 21], 'PostScript', 'sid', null],
20904 [[12, 22], 'BaseFontName', 'sid', null],
20905 [[12, 23], 'BaseFontBlend', 'delta', null],
20906 [[12, 31], 'CIDFontVersion', 'num', 0],
20907 [[12, 32], 'CIDFontRevision', 'num', 0],
20908 [[12, 33], 'CIDFontType', 'num', 0],
20909 [[12, 34], 'CIDCount', 'num', 8720],
20910 [[12, 35], 'UIDBase', 'num', null],
20911 // XXX: CID Fonts on DirectWrite 6.1 only seem to work if FDSelect comes
20912 // before FDArray.
20913 [[12, 37], 'FDSelect', 'offset', null],
20914 [[12, 36], 'FDArray', 'offset', null],
20915 [[12, 38], 'FontName', 'sid', null]
20916 ];
20917 var tables = null;
20918 function CFFTopDict(strings) {
20919 if (tables === null) {
20920 tables = CFFDict.createTables(layout);
20921 }
20922 CFFDict.call(this, tables, strings);
20923 this.privateDict = null;
20924 }
20925 CFFTopDict.prototype = Object.create(CFFDict.prototype);
20926 return CFFTopDict;
20927 })();
20928
20929 var CFFPrivateDict = (function CFFPrivateDictClosure() {
20930 var layout = [
20931 [6, 'BlueValues', 'delta', null],
20932 [7, 'OtherBlues', 'delta', null],
20933 [8, 'FamilyBlues', 'delta', null],
20934 [9, 'FamilyOtherBlues', 'delta', null],
20935 [[12, 9], 'BlueScale', 'num', 0.039625],
20936 [[12, 10], 'BlueShift', 'num', 7],
20937 [[12, 11], 'BlueFuzz', 'num', 1],
20938 [10, 'StdHW', 'num', null],
20939 [11, 'StdVW', 'num', null],
20940 [[12, 12], 'StemSnapH', 'delta', null],
20941 [[12, 13], 'StemSnapV', 'delta', null],
20942 [[12, 14], 'ForceBold', 'num', 0],
20943 [[12, 17], 'LanguageGroup', 'num', 0],
20944 [[12, 18], 'ExpansionFactor', 'num', 0.06],
20945 [[12, 19], 'initialRandomSeed', 'num', 0],
20946 [20, 'defaultWidthX', 'num', 0],
20947 [21, 'nominalWidthX', 'num', 0],
20948 [19, 'Subrs', 'offset', null]
20949 ];
20950 var tables = null;
20951 function CFFPrivateDict(strings) {
20952 if (tables === null) {
20953 tables = CFFDict.createTables(layout);
20954 }
20955 CFFDict.call(this, tables, strings);
20956 this.subrsIndex = null;
20957 }
20958 CFFPrivateDict.prototype = Object.create(CFFDict.prototype);
20959 return CFFPrivateDict;
20960 })();
20961
20962 var CFFCharsetPredefinedTypes = {
20963 ISO_ADOBE: 0,
20964 EXPERT: 1,
20965 EXPERT_SUBSET: 2
20966 };
20967 var CFFCharset = (function CFFCharsetClosure() {
20968 function CFFCharset(predefined, format, charset, raw) {
20969 this.predefined = predefined;
20970 this.format = format;
20971 this.charset = charset;
20972 this.raw = raw;
20973 }
20974 return CFFCharset;
20975 })();
20976
20977 var CFFEncoding = (function CFFEncodingClosure() {
20978 function CFFEncoding(predefined, format, encoding, raw) {
20979 this.predefined = predefined;
20980 this.format = format;
20981 this.encoding = encoding;
20982 this.raw = raw;
20983 }
20984 return CFFEncoding;
20985 })();
20986
20987 var CFFFDSelect = (function CFFFDSelectClosure() {
20988 function CFFFDSelect(fdSelect, raw) {
20989 this.fdSelect = fdSelect;
20990 this.raw = raw;
20991 }
20992 return CFFFDSelect;
20993 })();
20994
20995 // Helper class to keep track of where an offset is within the data and helps
20996 // filling in that offset once it's known.
20997 var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
20998 function CFFOffsetTracker() {
20999 this.offsets = {};
21000 }
21001 CFFOffsetTracker.prototype = {
21002 isTracking: function CFFOffsetTracker_isTracking(key) {
21003 return key in this.offsets;
21004 },
21005 track: function CFFOffsetTracker_track(key, location) {
21006 if (key in this.offsets) {
21007 error('Already tracking location of ' + key);
21008 }
21009 this.offsets[key] = location;
21010 },
21011 offset: function CFFOffsetTracker_offset(value) {
21012 for (var key in this.offsets) {
21013 this.offsets[key] += value;
21014 }
21015 },
21016 setEntryLocation: function CFFOffsetTracker_setEntryLocation(key,
21017 values,
21018 output) {
21019 if (!(key in this.offsets)) {
21020 error('Not tracking location of ' + key);
21021 }
21022 var data = output.data;
21023 var dataOffset = this.offsets[key];
21024 var size = 5;
21025 for (var i = 0, ii = values.length; i < ii; ++i) {
21026 var offset0 = i * size + dataOffset;
21027 var offset1 = offset0 + 1;
21028 var offset2 = offset0 + 2;
21029 var offset3 = offset0 + 3;
21030 var offset4 = offset0 + 4;
21031 // It's easy to screw up offsets so perform this sanity check.
21032 if (data[offset0] !== 0x1d || data[offset1] !== 0 ||
21033 data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0) {
21034 error('writing to an offset that is not empty');
21035 }
21036 var value = values[i];
21037 data[offset0] = 0x1d;
21038 data[offset1] = (value >> 24) & 0xFF;
21039 data[offset2] = (value >> 16) & 0xFF;
21040 data[offset3] = (value >> 8) & 0xFF;
21041 data[offset4] = value & 0xFF;
21042 }
21043 }
21044 };
21045 return CFFOffsetTracker;
21046 })();
21047
21048 // Takes a CFF and converts it to the binary representation.
21049 var CFFCompiler = (function CFFCompilerClosure() {
21050 function CFFCompiler(cff) {
21051 this.cff = cff;
21052 }
21053 CFFCompiler.prototype = {
21054 compile: function CFFCompiler_compile() {
21055 var cff = this.cff;
21056 var output = {
21057 data: [],
21058 length: 0,
21059 add: function CFFCompiler_add(data) {
21060 this.data = this.data.concat(data);
21061 this.length = this.data.length;
21062 }
21063 };
21064
21065 // Compile the five entries that must be in order.
21066 var header = this.compileHeader(cff.header);
21067 output.add(header);
21068
21069 var nameIndex = this.compileNameIndex(cff.names);
21070 output.add(nameIndex);
21071
21072 if (cff.isCIDFont) {
21073 // The spec is unclear on how font matrices should relate to each other
21074 // when there is one in the main top dict and the sub top dicts.
21075 // Windows handles this differently than linux and osx so we have to
21076 // normalize to work on all.
21077 // Rules based off of some mailing list discussions:
21078 // - If main font has a matrix and subfont doesn't, use the main matrix.
21079 // - If no main font matrix and there is a subfont matrix, use the
21080 // subfont matrix.
21081 // - If both have matrices, concat together.
21082 // - If neither have matrices, use default.
21083 // To make this work on all platforms we move the top matrix into each
21084 // sub top dict and concat if necessary.
21085 if (cff.topDict.hasName('FontMatrix')) {
21086 var base = cff.topDict.getByName('FontMatrix');
21087 cff.topDict.removeByName('FontMatrix');
21088 for (var i = 0, ii = cff.fdArray.length; i < ii; i++) {
21089 var subDict = cff.fdArray[i];
21090 var matrix = base.slice(0);
21091 if (subDict.hasName('FontMatrix')) {
21092 matrix = Util.transform(matrix, subDict.getByName('FontMatrix'));
21093 }
21094 subDict.setByName('FontMatrix', matrix);
21095 }
21096 }
21097 }
21098
21099 var compiled = this.compileTopDicts([cff.topDict],
21100 output.length,
21101 cff.isCIDFont);
21102 output.add(compiled.output);
21103 var topDictTracker = compiled.trackers[0];
21104
21105 var stringIndex = this.compileStringIndex(cff.strings.strings);
21106 output.add(stringIndex);
21107
21108 var globalSubrIndex = this.compileIndex(cff.globalSubrIndex);
21109 output.add(globalSubrIndex);
21110
21111 // Now start on the other entries that have no specfic order.
21112 if (cff.encoding && cff.topDict.hasName('Encoding')) {
21113 if (cff.encoding.predefined) {
21114 topDictTracker.setEntryLocation('Encoding', [cff.encoding.format],
21115 output);
21116 } else {
21117 var encoding = this.compileEncoding(cff.encoding);
21118 topDictTracker.setEntryLocation('Encoding', [output.length], output);
21119 output.add(encoding);
21120 }
21121 }
21122
21123 if (cff.charset && cff.topDict.hasName('charset')) {
21124 if (cff.charset.predefined) {
21125 topDictTracker.setEntryLocation('charset', [cff.charset.format],
21126 output);
21127 } else {
21128 var charset = this.compileCharset(cff.charset);
21129 topDictTracker.setEntryLocation('charset', [output.length], output);
21130 output.add(charset);
21131 }
21132 }
21133
21134 var charStrings = this.compileCharStrings(cff.charStrings);
21135 topDictTracker.setEntryLocation('CharStrings', [output.length], output);
21136 output.add(charStrings);
21137
21138 if (cff.isCIDFont) {
21139 // For some reason FDSelect must be in front of FDArray on windows. OSX
21140 // and linux don't seem to care.
21141 topDictTracker.setEntryLocation('FDSelect', [output.length], output);
21142 var fdSelect = this.compileFDSelect(cff.fdSelect.raw);
21143 output.add(fdSelect);
21144 // It is unclear if the sub font dictionary can have CID related
21145 // dictionary keys, but the sanitizer doesn't like them so remove them.
21146 compiled = this.compileTopDicts(cff.fdArray, output.length, true);
21147 topDictTracker.setEntryLocation('FDArray', [output.length], output);
21148 output.add(compiled.output);
21149 var fontDictTrackers = compiled.trackers;
21150
21151 this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output);
21152 }
21153
21154 this.compilePrivateDicts([cff.topDict], [topDictTracker], output);
21155
21156 // If the font data ends with INDEX whose object data is zero-length,
21157 // the sanitizer will bail out. Add a dummy byte to avoid that.
21158 output.add([0]);
21159
21160 return output.data;
21161 },
21162 encodeNumber: function CFFCompiler_encodeNumber(value) {
21163 if (parseFloat(value) === parseInt(value, 10) && !isNaN(value)) { // isInt
21164 return this.encodeInteger(value);
21165 } else {
21166 return this.encodeFloat(value);
21167 }
21168 },
21169 encodeFloat: function CFFCompiler_encodeFloat(num) {
21170 var value = num.toString();
21171
21172 // rounding inaccurate doubles
21173 var m = /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(value);
21174 if (m) {
21175 var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length));
21176 value = (Math.round(num * epsilon) / epsilon).toString();
21177 }
21178
21179 var nibbles = '';
21180 var i, ii;
21181 for (i = 0, ii = value.length; i < ii; ++i) {
21182 var a = value[i];
21183 if (a === 'e') {
21184 nibbles += value[++i] === '-' ? 'c' : 'b';
21185 } else if (a === '.') {
21186 nibbles += 'a';
21187 } else if (a === '-') {
21188 nibbles += 'e';
21189 } else {
21190 nibbles += a;
21191 }
21192 }
21193 nibbles += (nibbles.length & 1) ? 'f' : 'ff';
21194 var out = [30];
21195 for (i = 0, ii = nibbles.length; i < ii; i += 2) {
21196 out.push(parseInt(nibbles.substr(i, 2), 16));
21197 }
21198 return out;
21199 },
21200 encodeInteger: function CFFCompiler_encodeInteger(value) {
21201 var code;
21202 if (value >= -107 && value <= 107) {
21203 code = [value + 139];
21204 } else if (value >= 108 && value <= 1131) {
21205 value = [value - 108];
21206 code = [(value >> 8) + 247, value & 0xFF];
21207 } else if (value >= -1131 && value <= -108) {
21208 value = -value - 108;
21209 code = [(value >> 8) + 251, value & 0xFF];
21210 } else if (value >= -32768 && value <= 32767) {
21211 code = [0x1c, (value >> 8) & 0xFF, value & 0xFF];
21212 } else {
21213 code = [0x1d,
21214 (value >> 24) & 0xFF,
21215 (value >> 16) & 0xFF,
21216 (value >> 8) & 0xFF,
21217 value & 0xFF];
21218 }
21219 return code;
21220 },
21221 compileHeader: function CFFCompiler_compileHeader(header) {
21222 return [
21223 header.major,
21224 header.minor,
21225 header.hdrSize,
21226 header.offSize
21227 ];
21228 },
21229 compileNameIndex: function CFFCompiler_compileNameIndex(names) {
21230 var nameIndex = new CFFIndex();
21231 for (var i = 0, ii = names.length; i < ii; ++i) {
21232 nameIndex.add(stringToBytes(names[i]));
21233 }
21234 return this.compileIndex(nameIndex);
21235 },
21236 compileTopDicts: function CFFCompiler_compileTopDicts(dicts,
21237 length,
21238 removeCidKeys) {
21239 var fontDictTrackers = [];
21240 var fdArrayIndex = new CFFIndex();
21241 for (var i = 0, ii = dicts.length; i < ii; ++i) {
21242 var fontDict = dicts[i];
21243 if (removeCidKeys) {
21244 fontDict.removeByName('CIDFontVersion');
21245 fontDict.removeByName('CIDFontRevision');
21246 fontDict.removeByName('CIDFontType');
21247 fontDict.removeByName('CIDCount');
21248 fontDict.removeByName('UIDBase');
21249 }
21250 var fontDictTracker = new CFFOffsetTracker();
21251 var fontDictData = this.compileDict(fontDict, fontDictTracker);
21252 fontDictTrackers.push(fontDictTracker);
21253 fdArrayIndex.add(fontDictData);
21254 fontDictTracker.offset(length);
21255 }
21256 fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers);
21257 return {
21258 trackers: fontDictTrackers,
21259 output: fdArrayIndex
21260 };
21261 },
21262 compilePrivateDicts: function CFFCompiler_compilePrivateDicts(dicts,
21263 trackers,
21264 output) {
21265 for (var i = 0, ii = dicts.length; i < ii; ++i) {
21266 var fontDict = dicts[i];
21267 assert(fontDict.privateDict && fontDict.hasName('Private'),
21268 'There must be an private dictionary.');
21269 var privateDict = fontDict.privateDict;
21270 var privateDictTracker = new CFFOffsetTracker();
21271 var privateDictData = this.compileDict(privateDict, privateDictTracker);
21272
21273 var outputLength = output.length;
21274 privateDictTracker.offset(outputLength);
21275 if (!privateDictData.length) {
21276 // The private dictionary was empty, set the output length to zero to
21277 // ensure the offset length isn't out of bounds in the eyes of the
21278 // sanitizer.
21279 outputLength = 0;
21280 }
21281
21282 trackers[i].setEntryLocation('Private',
21283 [privateDictData.length, outputLength],
21284 output);
21285 output.add(privateDictData);
21286
21287 if (privateDict.subrsIndex && privateDict.hasName('Subrs')) {
21288 var subrs = this.compileIndex(privateDict.subrsIndex);
21289 privateDictTracker.setEntryLocation('Subrs', [privateDictData.length],
21290 output);
21291 output.add(subrs);
21292 }
21293 }
21294 },
21295 compileDict: function CFFCompiler_compileDict(dict, offsetTracker) {
21296 var out = [];
21297 // The dictionary keys must be in a certain order.
21298 var order = dict.order;
21299 for (var i = 0; i < order.length; ++i) {
21300 var key = order[i];
21301 if (!(key in dict.values)) {
21302 continue;
21303 }
21304 var values = dict.values[key];
21305 var types = dict.types[key];
21306 if (!isArray(types)) {
21307 types = [types];
21308 }
21309 if (!isArray(values)) {
21310 values = [values];
21311 }
21312
21313 // Remove any empty dict values.
21314 if (values.length === 0) {
21315 continue;
21316 }
21317
21318 for (var j = 0, jj = types.length; j < jj; ++j) {
21319 var type = types[j];
21320 var value = values[j];
21321 switch (type) {
21322 case 'num':
21323 case 'sid':
21324 out = out.concat(this.encodeNumber(value));
21325 break;
21326 case 'offset':
21327 // For offsets we just insert a 32bit integer so we don't have to
21328 // deal with figuring out the length of the offset when it gets
21329 // replaced later on by the compiler.
21330 var name = dict.keyToNameMap[key];
21331 // Some offsets have the offset and the length, so just record the
21332 // position of the first one.
21333 if (!offsetTracker.isTracking(name)) {
21334 offsetTracker.track(name, out.length);
21335 }
21336 out = out.concat([0x1d, 0, 0, 0, 0]);
21337 break;
21338 case 'array':
21339 case 'delta':
21340 out = out.concat(this.encodeNumber(value));
21341 for (var k = 1, kk = values.length; k < kk; ++k) {
21342 out = out.concat(this.encodeNumber(values[k]));
21343 }
21344 break;
21345 default:
21346 error('Unknown data type of ' + type);
21347 break;
21348 }
21349 }
21350 out = out.concat(dict.opcodes[key]);
21351 }
21352 return out;
21353 },
21354 compileStringIndex: function CFFCompiler_compileStringIndex(strings) {
21355 var stringIndex = new CFFIndex();
21356 for (var i = 0, ii = strings.length; i < ii; ++i) {
21357 stringIndex.add(stringToBytes(strings[i]));
21358 }
21359 return this.compileIndex(stringIndex);
21360 },
21361 compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() {
21362 var globalSubrIndex = this.cff.globalSubrIndex;
21363 this.out.writeByteArray(this.compileIndex(globalSubrIndex));
21364 },
21365 compileCharStrings: function CFFCompiler_compileCharStrings(charStrings) {
21366 return this.compileIndex(charStrings);
21367 },
21368 compileCharset: function CFFCompiler_compileCharset(charset) {
21369 return this.compileTypedArray(charset.raw);
21370 },
21371 compileEncoding: function CFFCompiler_compileEncoding(encoding) {
21372 return this.compileTypedArray(encoding.raw);
21373 },
21374 compileFDSelect: function CFFCompiler_compileFDSelect(fdSelect) {
21375 return this.compileTypedArray(fdSelect);
21376 },
21377 compileTypedArray: function CFFCompiler_compileTypedArray(data) {
21378 var out = [];
21379 for (var i = 0, ii = data.length; i < ii; ++i) {
21380 out[i] = data[i];
21381 }
21382 return out;
21383 },
21384 compileIndex: function CFFCompiler_compileIndex(index, trackers) {
21385 trackers = trackers || [];
21386 var objects = index.objects;
21387 // First 2 bytes contains the number of objects contained into this index
21388 var count = objects.length;
21389
21390 // If there is no object, just create an index. This technically
21391 // should just be [0, 0] but OTS has an issue with that.
21392 if (count === 0) {
21393 return [0, 0, 0];
21394 }
21395
21396 var data = [(count >> 8) & 0xFF, count & 0xff];
21397
21398 var lastOffset = 1, i;
21399 for (i = 0; i < count; ++i) {
21400 lastOffset += objects[i].length;
21401 }
21402
21403 var offsetSize;
21404 if (lastOffset < 0x100) {
21405 offsetSize = 1;
21406 } else if (lastOffset < 0x10000) {
21407 offsetSize = 2;
21408 } else if (lastOffset < 0x1000000) {
21409 offsetSize = 3;
21410 } else {
21411 offsetSize = 4;
21412 }
21413
21414 // Next byte contains the offset size use to reference object in the file
21415 data.push(offsetSize);
21416
21417 // Add another offset after this one because we need a new offset
21418 var relativeOffset = 1;
21419 for (i = 0; i < count + 1; i++) {
21420 if (offsetSize === 1) {
21421 data.push(relativeOffset & 0xFF);
21422 } else if (offsetSize === 2) {
21423 data.push((relativeOffset >> 8) & 0xFF,
21424 relativeOffset & 0xFF);
21425 } else if (offsetSize === 3) {
21426 data.push((relativeOffset >> 16) & 0xFF,
21427 (relativeOffset >> 8) & 0xFF,
21428 relativeOffset & 0xFF);
21429 } else {
21430 data.push((relativeOffset >>> 24) & 0xFF,
21431 (relativeOffset >> 16) & 0xFF,
21432 (relativeOffset >> 8) & 0xFF,
21433 relativeOffset & 0xFF);
21434 }
21435
21436 if (objects[i]) {
21437 relativeOffset += objects[i].length;
21438 }
21439 }
21440
21441 for (i = 0; i < count; i++) {
21442 // Notify the tracker where the object will be offset in the data.
21443 if (trackers[i]) {
21444 trackers[i].offset(data.length);
21445 }
21446 for (var j = 0, jj = objects[i].length; j < jj; j++) {
21447 data.push(objects[i][j]);
21448 }
21449 }
21450 return data;
21451 }
21452 };
21453 return CFFCompiler;
21454 })();
21455
21456 // Workaround for seac on Windows.
21457 (function checkSeacSupport() {
21458 if (/Windows/.test(navigator.userAgent)) {
21459 SEAC_ANALYSIS_ENABLED = true;
21460 }
21461 })();
21462
21463 // Workaround for Private Use Area characters in Chrome on Windows
21464 // http://code.google.com/p/chromium/issues/detail?id=122465
21465 // https://github.com/mozilla/pdf.js/issues/1689
21466 (function checkChromeWindows() {
21467 if (/Windows.*Chrome/.test(navigator.userAgent)) {
21468 SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = true;
21469 }
21470 })();
21471
21472
21473 var FontRendererFactory = (function FontRendererFactoryClosure() {
21474 function getLong(data, offset) {
21475 return (data[offset] << 24) | (data[offset + 1] << 16) |
21476 (data[offset + 2] << 8) | data[offset + 3];
21477 }
21478
21479 function getUshort(data, offset) {
21480 return (data[offset] << 8) | data[offset + 1];
21481 }
21482
21483 function parseCmap(data, start, end) {
21484 var offset = (getUshort(data, start + 2) === 1 ?
21485 getLong(data, start + 8) : getLong(data, start + 16));
21486 var format = getUshort(data, start + offset);
21487 var length, ranges, p, i;
21488 if (format === 4) {
21489 length = getUshort(data, start + offset + 2);
21490 var segCount = getUshort(data, start + offset + 6) >> 1;
21491 p = start + offset + 14;
21492 ranges = [];
21493 for (i = 0; i < segCount; i++, p += 2) {
21494 ranges[i] = {end: getUshort(data, p)};
21495 }
21496 p += 2;
21497 for (i = 0; i < segCount; i++, p += 2) {
21498 ranges[i].start = getUshort(data, p);
21499 }
21500 for (i = 0; i < segCount; i++, p += 2) {
21501 ranges[i].idDelta = getUshort(data, p);
21502 }
21503 for (i = 0; i < segCount; i++, p += 2) {
21504 var idOffset = getUshort(data, p);
21505 if (idOffset === 0) {
21506 continue;
21507 }
21508 ranges[i].ids = [];
21509 for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
21510 ranges[i].ids[j] = getUshort(data, p + idOffset);
21511 idOffset += 2;
21512 }
21513 }
21514 return ranges;
21515 } else if (format === 12) {
21516 length = getLong(data, start + offset + 4);
21517 var groups = getLong(data, start + offset + 12);
21518 p = start + offset + 16;
21519 ranges = [];
21520 for (i = 0; i < groups; i++) {
21521 ranges.push({
21522 start: getLong(data, p),
21523 end: getLong(data, p + 4),
21524 idDelta: getLong(data, p + 8) - getLong(data, p)
21525 });
21526 p += 12;
21527 }
21528 return ranges;
21529 }
21530 error('not supported cmap: ' + format);
21531 }
21532
21533 function parseCff(data, start, end) {
21534 var properties = {};
21535 var parser = new CFFParser(new Stream(data, start, end - start),
21536 properties);
21537 var cff = parser.parse();
21538 return {
21539 glyphs: cff.charStrings.objects,
21540 subrs: (cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&
21541 cff.topDict.privateDict.subrsIndex.objects),
21542 gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects
21543 };
21544 }
21545
21546 function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
21547 var itemSize, itemDecode;
21548 if (isGlyphLocationsLong) {
21549 itemSize = 4;
21550 itemDecode = function fontItemDecodeLong(data, offset) {
21551 return (data[offset] << 24) | (data[offset + 1] << 16) |
21552 (data[offset + 2] << 8) | data[offset + 3];
21553 };
21554 } else {
21555 itemSize = 2;
21556 itemDecode = function fontItemDecode(data, offset) {
21557 return (data[offset] << 9) | (data[offset + 1] << 1);
21558 };
21559 }
21560 var glyphs = [];
21561 var startOffset = itemDecode(loca, 0);
21562 for (var j = itemSize; j < loca.length; j += itemSize) {
21563 var endOffset = itemDecode(loca, j);
21564 glyphs.push(glyf.subarray(startOffset, endOffset));
21565 startOffset = endOffset;
21566 }
21567 return glyphs;
21568 }
21569
21570 function lookupCmap(ranges, unicode) {
21571 var code = unicode.charCodeAt(0);
21572 var l = 0, r = ranges.length - 1;
21573 while (l < r) {
21574 var c = (l + r + 1) >> 1;
21575 if (code < ranges[c].start) {
21576 r = c - 1;
21577 } else {
21578 l = c;
21579 }
21580 }
21581 if (ranges[l].start <= code && code <= ranges[l].end) {
21582 return (ranges[l].idDelta + (ranges[l].ids ?
21583 ranges[l].ids[code - ranges[l].start] : code)) & 0xFFFF;
21584 }
21585 return 0;
21586 }
21587
21588 function compileGlyf(code, js, font) {
21589 function moveTo(x, y) {
21590 js.push('c.moveTo(' + x + ',' + y + ');');
21591 }
21592 function lineTo(x, y) {
21593 js.push('c.lineTo(' + x + ',' + y + ');');
21594 }
21595 function quadraticCurveTo(xa, ya, x, y) {
21596 js.push('c.quadraticCurveTo(' + xa + ',' + ya + ',' +
21597 x + ',' + y + ');');
21598 }
21599
21600 var i = 0;
21601 var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
21602 var flags;
21603 var x = 0, y = 0;
21604 i += 10;
21605 if (numberOfContours < 0) {
21606 // composite glyph
21607 do {
21608 flags = (code[i] << 8) | code[i + 1];
21609 var glyphIndex = (code[i + 2] << 8) | code[i + 3];
21610 i += 4;
21611 var arg1, arg2;
21612 if ((flags & 0x01)) {
21613 arg1 = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
21614 arg2 = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
21615 i += 4;
21616 } else {
21617 arg1 = code[i++]; arg2 = code[i++];
21618 }
21619 if ((flags & 0x02)) {
21620 x = arg1;
21621 y = arg2;
21622 } else {
21623 x = 0; y = 0; // TODO "they are points" ?
21624 }
21625 var scaleX = 1, scaleY = 1, scale01 = 0, scale10 = 0;
21626 if ((flags & 0x08)) {
21627 scaleX =
21628 scaleY = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
21629 i += 2;
21630 } else if ((flags & 0x40)) {
21631 scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
21632 scaleY = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
21633 i += 4;
21634 } else if ((flags & 0x80)) {
21635 scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
21636 scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
21637 scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;
21638 scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824;
21639 i += 8;
21640 }
21641 var subglyph = font.glyphs[glyphIndex];
21642 if (subglyph) {
21643 js.push('c.save();');
21644 js.push('c.transform(' + scaleX + ',' + scale01 + ',' +
21645 scale10 + ',' + scaleY + ',' + x + ',' + y + ');');
21646 compileGlyf(subglyph, js, font);
21647 js.push('c.restore();');
21648 }
21649 } while ((flags & 0x20));
21650 } else {
21651 // simple glyph
21652 var endPtsOfContours = [];
21653 var j, jj;
21654 for (j = 0; j < numberOfContours; j++) {
21655 endPtsOfContours.push((code[i] << 8) | code[i + 1]);
21656 i += 2;
21657 }
21658 var instructionLength = (code[i] << 8) | code[i + 1];
21659 i += 2 + instructionLength; // skipping the instructions
21660 var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
21661 var points = [];
21662 while (points.length < numberOfPoints) {
21663 flags = code[i++];
21664 var repeat = 1;
21665 if ((flags & 0x08)) {
21666 repeat += code[i++];
21667 }
21668 while (repeat-- > 0) {
21669 points.push({flags: flags});
21670 }
21671 }
21672 for (j = 0; j < numberOfPoints; j++) {
21673 switch (points[j].flags & 0x12) {
21674 case 0x00:
21675 x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
21676 i += 2;
21677 break;
21678 case 0x02:
21679 x -= code[i++];
21680 break;
21681 case 0x12:
21682 x += code[i++];
21683 break;
21684 }
21685 points[j].x = x;
21686 }
21687 for (j = 0; j < numberOfPoints; j++) {
21688 switch (points[j].flags & 0x24) {
21689 case 0x00:
21690 y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
21691 i += 2;
21692 break;
21693 case 0x04:
21694 y -= code[i++];
21695 break;
21696 case 0x24:
21697 y += code[i++];
21698 break;
21699 }
21700 points[j].y = y;
21701 }
21702
21703 var startPoint = 0;
21704 for (i = 0; i < numberOfContours; i++) {
21705 var endPoint = endPtsOfContours[i];
21706 // contours might have implicit points, which is located in the middle
21707 // between two neighboring off-curve points
21708 var contour = points.slice(startPoint, endPoint + 1);
21709 if ((contour[0].flags & 1)) {
21710 contour.push(contour[0]); // using start point at the contour end
21711 } else if ((contour[contour.length - 1].flags & 1)) {
21712 // first is off-curve point, trying to use one from the end
21713 contour.unshift(contour[contour.length - 1]);
21714 } else {
21715 // start and end are off-curve points, creating implicit one
21716 var p = {
21717 flags: 1,
21718 x: (contour[0].x + contour[contour.length - 1].x) / 2,
21719 y: (contour[0].y + contour[contour.length - 1].y) / 2
21720 };
21721 contour.unshift(p);
21722 contour.push(p);
21723 }
21724 moveTo(contour[0].x, contour[0].y);
21725 for (j = 1, jj = contour.length; j < jj; j++) {
21726 if ((contour[j].flags & 1)) {
21727 lineTo(contour[j].x, contour[j].y);
21728 } else if ((contour[j + 1].flags & 1)){
21729 quadraticCurveTo(contour[j].x, contour[j].y,
21730 contour[j + 1].x, contour[j + 1].y);
21731 j++;
21732 } else {
21733 quadraticCurveTo(contour[j].x, contour[j].y,
21734 (contour[j].x + contour[j + 1].x) / 2,
21735 (contour[j].y + contour[j + 1].y) / 2);
21736 }
21737 }
21738 startPoint = endPoint + 1;
21739 }
21740 }
21741 }
21742
21743 function compileCharString(code, js, font) {
21744 var stack = [];
21745 var x = 0, y = 0;
21746 var stems = 0;
21747
21748 function moveTo(x, y) {
21749 js.push('c.moveTo(' + x + ',' + y + ');');
21750 }
21751 function lineTo(x, y) {
21752 js.push('c.lineTo(' + x + ',' + y + ');');
21753 }
21754 function bezierCurveTo(x1, y1, x2, y2, x, y) {
21755 js.push('c.bezierCurveTo(' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + ',' +
21756 x + ',' + y + ');');
21757 }
21758
21759 function parse(code) {
21760 var i = 0;
21761 while (i < code.length) {
21762 var stackClean = false;
21763 var v = code[i++];
21764 var xa, xb, ya, yb, y1, y2, y3, n, subrCode;
21765 switch (v) {
21766 case 1: // hstem
21767 stems += stack.length >> 1;
21768 stackClean = true;
21769 break;
21770 case 3: // vstem
21771 stems += stack.length >> 1;
21772 stackClean = true;
21773 break;
21774 case 4: // vmoveto
21775 y += stack.pop();
21776 moveTo(x, y);
21777 stackClean = true;
21778 break;
21779 case 5: // rlineto
21780 while (stack.length > 0) {
21781 x += stack.shift();
21782 y += stack.shift();
21783 lineTo(x, y);
21784 }
21785 break;
21786 case 6: // hlineto
21787 while (stack.length > 0) {
21788 x += stack.shift();
21789 lineTo(x, y);
21790 if (stack.length === 0) {
21791 break;
21792 }
21793 y += stack.shift();
21794 lineTo(x, y);
21795 }
21796 break;
21797 case 7: // vlineto
21798 while (stack.length > 0) {
21799 y += stack.shift();
21800 lineTo(x, y);
21801 if (stack.length === 0) {
21802 break;
21803 }
21804 x += stack.shift();
21805 lineTo(x, y);
21806 }
21807 break;
21808 case 8: // rrcurveto
21809 while (stack.length > 0) {
21810 xa = x + stack.shift(); ya = y + stack.shift();
21811 xb = xa + stack.shift(); yb = ya + stack.shift();
21812 x = xb + stack.shift(); y = yb + stack.shift();
21813 bezierCurveTo(xa, ya, xb, yb, x, y);
21814 }
21815 break;
21816 case 10: // callsubr
21817 n = stack.pop() + font.subrsBias;
21818 subrCode = font.subrs[n];
21819 if (subrCode) {
21820 parse(subrCode);
21821 }
21822 break;
21823 case 11: // return
21824 return;
21825 case 12:
21826 v = code[i++];
21827 switch (v) {
21828 case 34: // flex
21829 xa = x + stack.shift();
21830 xb = xa + stack.shift(); y1 = y + stack.shift();
21831 x = xb + stack.shift();
21832 bezierCurveTo(xa, y, xb, y1, x, y1);
21833 xa = x + stack.shift();
21834 xb = xa + stack.shift();
21835 x = xb + stack.shift();
21836 bezierCurveTo(xa, y1, xb, y, x, y);
21837 break;
21838 case 35: // flex
21839 xa = x + stack.shift(); ya = y + stack.shift();
21840 xb = xa + stack.shift(); yb = ya + stack.shift();
21841 x = xb + stack.shift(); y = yb + stack.shift();
21842 bezierCurveTo(xa, ya, xb, yb, x, y);
21843 xa = x + stack.shift(); ya = y + stack.shift();
21844 xb = xa + stack.shift(); yb = ya + stack.shift();
21845 x = xb + stack.shift(); y = yb + stack.shift();
21846 bezierCurveTo(xa, ya, xb, yb, x, y);
21847 stack.pop(); // fd
21848 break;
21849 case 36: // hflex1
21850 xa = x + stack.shift(); y1 = y + stack.shift();
21851 xb = xa + stack.shift(); y2 = y1 + stack.shift();
21852 x = xb + stack.shift();
21853 bezierCurveTo(xa, y1, xb, y2, x, y2);
21854 xa = x + stack.shift();
21855 xb = xa + stack.shift(); y3 = y2 + stack.shift();
21856 x = xb + stack.shift();
21857 bezierCurveTo(xa, y2, xb, y3, x, y);
21858 break;
21859 case 37: // flex1
21860 var x0 = x, y0 = y;
21861 xa = x + stack.shift(); ya = y + stack.shift();
21862 xb = xa + stack.shift(); yb = ya + stack.shift();
21863 x = xb + stack.shift(); y = yb + stack.shift();
21864 bezierCurveTo(xa, ya, xb, yb, x, y);
21865 xa = x + stack.shift(); ya = y + stack.shift();
21866 xb = xa + stack.shift(); yb = ya + stack.shift();
21867 x = xb; y = yb;
21868 if (Math.abs(x - x0) > Math.abs(y - y0)) {
21869 x += stack.shift();
21870 } else {
21871 y += stack.shift();
21872 }
21873 bezierCurveTo(xa, ya, xb, yb, x, y);
21874 break;
21875 default:
21876 error('unknown operator: 12 ' + v);
21877 }
21878 break;
21879 case 14: // endchar
21880 if (stack.length >= 4) {
21881 var achar = stack.pop();
21882 var bchar = stack.pop();
21883 y = stack.pop();
21884 x = stack.pop();
21885 js.push('c.save();');
21886 js.push('c.translate('+ x + ',' + y + ');');
21887 var gid = lookupCmap(font.cmap, String.fromCharCode(
21888 font.glyphNameMap[Encodings.StandardEncoding[achar]]));
21889 compileCharString(font.glyphs[gid], js, font);
21890 js.push('c.restore();');
21891
21892 gid = lookupCmap(font.cmap, String.fromCharCode(
21893 font.glyphNameMap[Encodings.StandardEncoding[bchar]]));
21894 compileCharString(font.glyphs[gid], js, font);
21895 }
21896 return;
21897 case 18: // hstemhm
21898 stems += stack.length >> 1;
21899 stackClean = true;
21900 break;
21901 case 19: // hintmask
21902 stems += stack.length >> 1;
21903 i += (stems + 7) >> 3;
21904 stackClean = true;
21905 break;
21906 case 20: // cntrmask
21907 stems += stack.length >> 1;
21908 i += (stems + 7) >> 3;
21909 stackClean = true;
21910 break;
21911 case 21: // rmoveto
21912 y += stack.pop();
21913 x += stack.pop();
21914 moveTo(x, y);
21915 stackClean = true;
21916 break;
21917 case 22: // hmoveto
21918 x += stack.pop();
21919 moveTo(x, y);
21920 stackClean = true;
21921 break;
21922 case 23: // vstemhm
21923 stems += stack.length >> 1;
21924 stackClean = true;
21925 break;
21926 case 24: // rcurveline
21927 while (stack.length > 2) {
21928 xa = x + stack.shift(); ya = y + stack.shift();
21929 xb = xa + stack.shift(); yb = ya + stack.shift();
21930 x = xb + stack.shift(); y = yb + stack.shift();
21931 bezierCurveTo(xa, ya, xb, yb, x, y);
21932 }
21933 x += stack.shift();
21934 y += stack.shift();
21935 lineTo(x, y);
21936 break;
21937 case 25: // rlinecurve
21938 while (stack.length > 6) {
21939 x += stack.shift();
21940 y += stack.shift();
21941 lineTo(x, y);
21942 }
21943 xa = x + stack.shift(); ya = y + stack.shift();
21944 xb = xa + stack.shift(); yb = ya + stack.shift();
21945 x = xb + stack.shift(); y = yb + stack.shift();
21946 bezierCurveTo(xa, ya, xb, yb, x, y);
21947 break;
21948 case 26: // vvcurveto
21949 if (stack.length % 2) {
21950 x += stack.shift();
21951 }
21952 while (stack.length > 0) {
21953 xa = x; ya = y + stack.shift();
21954 xb = xa + stack.shift(); yb = ya + stack.shift();
21955 x = xb; y = yb + stack.shift();
21956 bezierCurveTo(xa, ya, xb, yb, x, y);
21957 }
21958 break;
21959 case 27: // hhcurveto
21960 if (stack.length % 2) {
21961 y += stack.shift();
21962 }
21963 while (stack.length > 0) {
21964 xa = x + stack.shift(); ya = y;
21965 xb = xa + stack.shift(); yb = ya + stack.shift();
21966 x = xb + stack.shift(); y = yb;
21967 bezierCurveTo(xa, ya, xb, yb, x, y);
21968 }
21969 break;
21970 case 28:
21971 stack.push(((code[i] << 24) | (code[i + 1] << 16)) >> 16);
21972 i += 2;
21973 break;
21974 case 29: // callgsubr
21975 n = stack.pop() + font.gsubrsBias;
21976 subrCode = font.gsubrs[n];
21977 if (subrCode) {
21978 parse(subrCode);
21979 }
21980 break;
21981 case 30: // vhcurveto
21982 while (stack.length > 0) {
21983 xa = x; ya = y + stack.shift();
21984 xb = xa + stack.shift(); yb = ya + stack.shift();
21985 x = xb + stack.shift();
21986 y = yb + (stack.length === 1 ? stack.shift() : 0);
21987 bezierCurveTo(xa, ya, xb, yb, x, y);
21988 if (stack.length === 0) {
21989 break;
21990 }
21991
21992 xa = x + stack.shift(); ya = y;
21993 xb = xa + stack.shift(); yb = ya + stack.shift();
21994 y = yb + stack.shift();
21995 x = xb + (stack.length === 1 ? stack.shift() : 0);
21996 bezierCurveTo(xa, ya, xb, yb, x, y);
21997 }
21998 break;
21999 case 31: // hvcurveto
22000 while (stack.length > 0) {
22001 xa = x + stack.shift(); ya = y;
22002 xb = xa + stack.shift(); yb = ya + stack.shift();
22003 y = yb + stack.shift();
22004 x = xb + (stack.length === 1 ? stack.shift() : 0);
22005 bezierCurveTo(xa, ya, xb, yb, x, y);
22006 if (stack.length === 0) {
22007 break;
22008 }
22009
22010 xa = x; ya = y + stack.shift();
22011 xb = xa + stack.shift(); yb = ya + stack.shift();
22012 x = xb + stack.shift();
22013 y = yb + (stack.length === 1 ? stack.shift() : 0);
22014 bezierCurveTo(xa, ya, xb, yb, x, y);
22015 }
22016 break;
22017 default:
22018 if (v < 32) {
22019 error('unknown operator: ' + v);
22020 }
22021 if (v < 247) {
22022 stack.push(v - 139);
22023 } else if (v < 251) {
22024 stack.push((v - 247) * 256 + code[i++] + 108);
22025 } else if (v < 255) {
22026 stack.push(-(v - 251) * 256 - code[i++] - 108);
22027 } else {
22028 stack.push(((code[i] << 24) | (code[i + 1] << 16) |
22029 (code[i + 2] << 8) | code[i + 3]) / 65536);
22030 i += 4;
22031 }
22032 break;
22033 }
22034 if (stackClean) {
22035 stack.length = 0;
22036 }
22037 }
22038 }
22039 parse(code);
22040 }
22041
22042 var noop = '';
22043
22044 function CompiledFont(fontMatrix) {
22045 this.compiledGlyphs = {};
22046 this.fontMatrix = fontMatrix;
22047 }
22048 CompiledFont.prototype = {
22049 getPathJs: function (unicode) {
22050 var gid = lookupCmap(this.cmap, unicode);
22051 var fn = this.compiledGlyphs[gid];
22052 if (!fn) {
22053 this.compiledGlyphs[gid] = fn = this.compileGlyph(this.glyphs[gid]);
22054 }
22055 return fn;
22056 },
22057
22058 compileGlyph: function (code) {
22059 if (!code || code.length === 0 || code[0] === 14) {
22060 return noop;
22061 }
22062
22063 var js = [];
22064 js.push('c.save();');
22065 js.push('c.transform(' + this.fontMatrix.join(',') + ');');
22066 js.push('c.scale(size, -size);');
22067
22068 this.compileGlyphImpl(code, js);
22069
22070 js.push('c.restore();');
22071
22072 return js.join('\n');
22073 },
22074
22075 compileGlyphImpl: function () {
22076 error('Children classes should implement this.');
22077 },
22078
22079 hasBuiltPath: function (unicode) {
22080 var gid = lookupCmap(this.cmap, unicode);
22081 return gid in this.compiledGlyphs;
22082 }
22083 };
22084
22085 function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
22086 fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];
22087 CompiledFont.call(this, fontMatrix);
22088
22089 this.glyphs = glyphs;
22090 this.cmap = cmap;
22091
22092 this.compiledGlyphs = [];
22093 }
22094
22095 Util.inherit(TrueTypeCompiled, CompiledFont, {
22096 compileGlyphImpl: function (code, js) {
22097 compileGlyf(code, js, this);
22098 }
22099 });
22100
22101 function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {
22102 fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0];
22103 CompiledFont.call(this, fontMatrix);
22104 this.glyphs = cffInfo.glyphs;
22105 this.gsubrs = cffInfo.gsubrs || [];
22106 this.subrs = cffInfo.subrs || [];
22107 this.cmap = cmap;
22108 this.glyphNameMap = glyphNameMap || GlyphsUnicode;
22109
22110 this.compiledGlyphs = [];
22111 this.gsubrsBias = (this.gsubrs.length < 1240 ?
22112 107 : (this.gsubrs.length < 33900 ? 1131 : 32768));
22113 this.subrsBias = (this.subrs.length < 1240 ?
22114 107 : (this.subrs.length < 33900 ? 1131 : 32768));
22115 }
22116
22117 Util.inherit(Type2Compiled, CompiledFont, {
22118 compileGlyphImpl: function (code, js) {
22119 compileCharString(code, js, this);
22120 }
22121 });
22122
22123
22124 return {
22125 create: function FontRendererFactory_create(font) {
22126 var data = new Uint8Array(font.data);
22127 var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
22128 var numTables = getUshort(data, 4);
22129 for (var i = 0, p = 12; i < numTables; i++, p += 16) {
22130 var tag = bytesToString(data.subarray(p, p + 4));
22131 var offset = getLong(data, p + 8);
22132 var length = getLong(data, p + 12);
22133 switch (tag) {
22134 case 'cmap':
22135 cmap = parseCmap(data, offset, offset + length);
22136 break;
22137 case 'glyf':
22138 glyf = data.subarray(offset, offset + length);
22139 break;
22140 case 'loca':
22141 loca = data.subarray(offset, offset + length);
22142 break;
22143 case 'head':
22144 unitsPerEm = getUshort(data, offset + 18);
22145 indexToLocFormat = getUshort(data, offset + 50);
22146 break;
22147 case 'CFF ':
22148 cff = parseCff(data, offset, offset + length);
22149 break;
22150 }
22151 }
22152
22153 if (glyf) {
22154 var fontMatrix = (!unitsPerEm ? font.fontMatrix :
22155 [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]);
22156 return new TrueTypeCompiled(
22157 parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
22158 } else {
22159 return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
22160 }
22161 }
22162 };
22163 })();
22164
22165
22166 var GlyphsUnicode = {
22167 A: 0x0041,
22168 AE: 0x00C6,
22169 AEacute: 0x01FC,
22170 AEmacron: 0x01E2,
22171 AEsmall: 0xF7E6,
22172 Aacute: 0x00C1,
22173 Aacutesmall: 0xF7E1,
22174 Abreve: 0x0102,
22175 Abreveacute: 0x1EAE,
22176 Abrevecyrillic: 0x04D0,
22177 Abrevedotbelow: 0x1EB6,
22178 Abrevegrave: 0x1EB0,
22179 Abrevehookabove: 0x1EB2,
22180 Abrevetilde: 0x1EB4,
22181 Acaron: 0x01CD,
22182 Acircle: 0x24B6,
22183 Acircumflex: 0x00C2,
22184 Acircumflexacute: 0x1EA4,
22185 Acircumflexdotbelow: 0x1EAC,
22186 Acircumflexgrave: 0x1EA6,
22187 Acircumflexhookabove: 0x1EA8,
22188 Acircumflexsmall: 0xF7E2,
22189 Acircumflextilde: 0x1EAA,
22190 Acute: 0xF6C9,
22191 Acutesmall: 0xF7B4,
22192 Acyrillic: 0x0410,
22193 Adblgrave: 0x0200,
22194 Adieresis: 0x00C4,
22195 Adieresiscyrillic: 0x04D2,
22196 Adieresismacron: 0x01DE,
22197 Adieresissmall: 0xF7E4,
22198 Adotbelow: 0x1EA0,
22199 Adotmacron: 0x01E0,
22200 Agrave: 0x00C0,
22201 Agravesmall: 0xF7E0,
22202 Ahookabove: 0x1EA2,
22203 Aiecyrillic: 0x04D4,
22204 Ainvertedbreve: 0x0202,
22205 Alpha: 0x0391,
22206 Alphatonos: 0x0386,
22207 Amacron: 0x0100,
22208 Amonospace: 0xFF21,
22209 Aogonek: 0x0104,
22210 Aring: 0x00C5,
22211 Aringacute: 0x01FA,
22212 Aringbelow: 0x1E00,
22213 Aringsmall: 0xF7E5,
22214 Asmall: 0xF761,
22215 Atilde: 0x00C3,
22216 Atildesmall: 0xF7E3,
22217 Aybarmenian: 0x0531,
22218 B: 0x0042,
22219 Bcircle: 0x24B7,
22220 Bdotaccent: 0x1E02,
22221 Bdotbelow: 0x1E04,
22222 Becyrillic: 0x0411,
22223 Benarmenian: 0x0532,
22224 Beta: 0x0392,
22225 Bhook: 0x0181,
22226 Blinebelow: 0x1E06,
22227 Bmonospace: 0xFF22,
22228 Brevesmall: 0xF6F4,
22229 Bsmall: 0xF762,
22230 Btopbar: 0x0182,
22231 C: 0x0043,
22232 Caarmenian: 0x053E,
22233 Cacute: 0x0106,
22234 Caron: 0xF6CA,
22235 Caronsmall: 0xF6F5,
22236 Ccaron: 0x010C,
22237 Ccedilla: 0x00C7,
22238 Ccedillaacute: 0x1E08,
22239 Ccedillasmall: 0xF7E7,
22240 Ccircle: 0x24B8,
22241 Ccircumflex: 0x0108,
22242 Cdot: 0x010A,
22243 Cdotaccent: 0x010A,
22244 Cedillasmall: 0xF7B8,
22245 Chaarmenian: 0x0549,
22246 Cheabkhasiancyrillic: 0x04BC,
22247 Checyrillic: 0x0427,
22248 Chedescenderabkhasiancyrillic: 0x04BE,
22249 Chedescendercyrillic: 0x04B6,
22250 Chedieresiscyrillic: 0x04F4,
22251 Cheharmenian: 0x0543,
22252 Chekhakassiancyrillic: 0x04CB,
22253 Cheverticalstrokecyrillic: 0x04B8,
22254 Chi: 0x03A7,
22255 Chook: 0x0187,
22256 Circumflexsmall: 0xF6F6,
22257 Cmonospace: 0xFF23,
22258 Coarmenian: 0x0551,
22259 Csmall: 0xF763,
22260 D: 0x0044,
22261 DZ: 0x01F1,
22262 DZcaron: 0x01C4,
22263 Daarmenian: 0x0534,
22264 Dafrican: 0x0189,
22265 Dcaron: 0x010E,
22266 Dcedilla: 0x1E10,
22267 Dcircle: 0x24B9,
22268 Dcircumflexbelow: 0x1E12,
22269 Dcroat: 0x0110,
22270 Ddotaccent: 0x1E0A,
22271 Ddotbelow: 0x1E0C,
22272 Decyrillic: 0x0414,
22273 Deicoptic: 0x03EE,
22274 Delta: 0x2206,
22275 Deltagreek: 0x0394,
22276 Dhook: 0x018A,
22277 Dieresis: 0xF6CB,
22278 DieresisAcute: 0xF6CC,
22279 DieresisGrave: 0xF6CD,
22280 Dieresissmall: 0xF7A8,
22281 Digammagreek: 0x03DC,
22282 Djecyrillic: 0x0402,
22283 Dlinebelow: 0x1E0E,
22284 Dmonospace: 0xFF24,
22285 Dotaccentsmall: 0xF6F7,
22286 Dslash: 0x0110,
22287 Dsmall: 0xF764,
22288 Dtopbar: 0x018B,
22289 Dz: 0x01F2,
22290 Dzcaron: 0x01C5,
22291 Dzeabkhasiancyrillic: 0x04E0,
22292 Dzecyrillic: 0x0405,
22293 Dzhecyrillic: 0x040F,
22294 E: 0x0045,
22295 Eacute: 0x00C9,
22296 Eacutesmall: 0xF7E9,
22297 Ebreve: 0x0114,
22298 Ecaron: 0x011A,
22299 Ecedillabreve: 0x1E1C,
22300 Echarmenian: 0x0535,
22301 Ecircle: 0x24BA,
22302 Ecircumflex: 0x00CA,
22303 Ecircumflexacute: 0x1EBE,
22304 Ecircumflexbelow: 0x1E18,
22305 Ecircumflexdotbelow: 0x1EC6,
22306 Ecircumflexgrave: 0x1EC0,
22307 Ecircumflexhookabove: 0x1EC2,
22308 Ecircumflexsmall: 0xF7EA,
22309 Ecircumflextilde: 0x1EC4,
22310 Ecyrillic: 0x0404,
22311 Edblgrave: 0x0204,
22312 Edieresis: 0x00CB,
22313 Edieresissmall: 0xF7EB,
22314 Edot: 0x0116,
22315 Edotaccent: 0x0116,
22316 Edotbelow: 0x1EB8,
22317 Efcyrillic: 0x0424,
22318 Egrave: 0x00C8,
22319 Egravesmall: 0xF7E8,
22320 Eharmenian: 0x0537,
22321 Ehookabove: 0x1EBA,
22322 Eightroman: 0x2167,
22323 Einvertedbreve: 0x0206,
22324 Eiotifiedcyrillic: 0x0464,
22325 Elcyrillic: 0x041B,
22326 Elevenroman: 0x216A,
22327 Emacron: 0x0112,
22328 Emacronacute: 0x1E16,
22329 Emacrongrave: 0x1E14,
22330 Emcyrillic: 0x041C,
22331 Emonospace: 0xFF25,
22332 Encyrillic: 0x041D,
22333 Endescendercyrillic: 0x04A2,
22334 Eng: 0x014A,
22335 Enghecyrillic: 0x04A4,
22336 Enhookcyrillic: 0x04C7,
22337 Eogonek: 0x0118,
22338 Eopen: 0x0190,
22339 Epsilon: 0x0395,
22340 Epsilontonos: 0x0388,
22341 Ercyrillic: 0x0420,
22342 Ereversed: 0x018E,
22343 Ereversedcyrillic: 0x042D,
22344 Escyrillic: 0x0421,
22345 Esdescendercyrillic: 0x04AA,
22346 Esh: 0x01A9,
22347 Esmall: 0xF765,
22348 Eta: 0x0397,
22349 Etarmenian: 0x0538,
22350 Etatonos: 0x0389,
22351 Eth: 0x00D0,
22352 Ethsmall: 0xF7F0,
22353 Etilde: 0x1EBC,
22354 Etildebelow: 0x1E1A,
22355 Euro: 0x20AC,
22356 Ezh: 0x01B7,
22357 Ezhcaron: 0x01EE,
22358 Ezhreversed: 0x01B8,
22359 F: 0x0046,
22360 Fcircle: 0x24BB,
22361 Fdotaccent: 0x1E1E,
22362 Feharmenian: 0x0556,
22363 Feicoptic: 0x03E4,
22364 Fhook: 0x0191,
22365 Fitacyrillic: 0x0472,
22366 Fiveroman: 0x2164,
22367 Fmonospace: 0xFF26,
22368 Fourroman: 0x2163,
22369 Fsmall: 0xF766,
22370 G: 0x0047,
22371 GBsquare: 0x3387,
22372 Gacute: 0x01F4,
22373 Gamma: 0x0393,
22374 Gammaafrican: 0x0194,
22375 Gangiacoptic: 0x03EA,
22376 Gbreve: 0x011E,
22377 Gcaron: 0x01E6,
22378 Gcedilla: 0x0122,
22379 Gcircle: 0x24BC,
22380 Gcircumflex: 0x011C,
22381 Gcommaaccent: 0x0122,
22382 Gdot: 0x0120,
22383 Gdotaccent: 0x0120,
22384 Gecyrillic: 0x0413,
22385 Ghadarmenian: 0x0542,
22386 Ghemiddlehookcyrillic: 0x0494,
22387 Ghestrokecyrillic: 0x0492,
22388 Gheupturncyrillic: 0x0490,
22389 Ghook: 0x0193,
22390 Gimarmenian: 0x0533,
22391 Gjecyrillic: 0x0403,
22392 Gmacron: 0x1E20,
22393 Gmonospace: 0xFF27,
22394 Grave: 0xF6CE,
22395 Gravesmall: 0xF760,
22396 Gsmall: 0xF767,
22397 Gsmallhook: 0x029B,
22398 Gstroke: 0x01E4,
22399 H: 0x0048,
22400 H18533: 0x25CF,
22401 H18543: 0x25AA,
22402 H18551: 0x25AB,
22403 H22073: 0x25A1,
22404 HPsquare: 0x33CB,
22405 Haabkhasiancyrillic: 0x04A8,
22406 Hadescendercyrillic: 0x04B2,
22407 Hardsigncyrillic: 0x042A,
22408 Hbar: 0x0126,
22409 Hbrevebelow: 0x1E2A,
22410 Hcedilla: 0x1E28,
22411 Hcircle: 0x24BD,
22412 Hcircumflex: 0x0124,
22413 Hdieresis: 0x1E26,
22414 Hdotaccent: 0x1E22,
22415 Hdotbelow: 0x1E24,
22416 Hmonospace: 0xFF28,
22417 Hoarmenian: 0x0540,
22418 Horicoptic: 0x03E8,
22419 Hsmall: 0xF768,
22420 Hungarumlaut: 0xF6CF,
22421 Hungarumlautsmall: 0xF6F8,
22422 Hzsquare: 0x3390,
22423 I: 0x0049,
22424 IAcyrillic: 0x042F,
22425 IJ: 0x0132,
22426 IUcyrillic: 0x042E,
22427 Iacute: 0x00CD,
22428 Iacutesmall: 0xF7ED,
22429 Ibreve: 0x012C,
22430 Icaron: 0x01CF,
22431 Icircle: 0x24BE,
22432 Icircumflex: 0x00CE,
22433 Icircumflexsmall: 0xF7EE,
22434 Icyrillic: 0x0406,
22435 Idblgrave: 0x0208,
22436 Idieresis: 0x00CF,
22437 Idieresisacute: 0x1E2E,
22438 Idieresiscyrillic: 0x04E4,
22439 Idieresissmall: 0xF7EF,
22440 Idot: 0x0130,
22441 Idotaccent: 0x0130,
22442 Idotbelow: 0x1ECA,
22443 Iebrevecyrillic: 0x04D6,
22444 Iecyrillic: 0x0415,
22445 Ifraktur: 0x2111,
22446 Igrave: 0x00CC,
22447 Igravesmall: 0xF7EC,
22448 Ihookabove: 0x1EC8,
22449 Iicyrillic: 0x0418,
22450 Iinvertedbreve: 0x020A,
22451 Iishortcyrillic: 0x0419,
22452 Imacron: 0x012A,
22453 Imacroncyrillic: 0x04E2,
22454 Imonospace: 0xFF29,
22455 Iniarmenian: 0x053B,
22456 Iocyrillic: 0x0401,
22457 Iogonek: 0x012E,
22458 Iota: 0x0399,
22459 Iotaafrican: 0x0196,
22460 Iotadieresis: 0x03AA,
22461 Iotatonos: 0x038A,
22462 Ismall: 0xF769,
22463 Istroke: 0x0197,
22464 Itilde: 0x0128,
22465 Itildebelow: 0x1E2C,
22466 Izhitsacyrillic: 0x0474,
22467 Izhitsadblgravecyrillic: 0x0476,
22468 J: 0x004A,
22469 Jaarmenian: 0x0541,
22470 Jcircle: 0x24BF,
22471 Jcircumflex: 0x0134,
22472 Jecyrillic: 0x0408,
22473 Jheharmenian: 0x054B,
22474 Jmonospace: 0xFF2A,
22475 Jsmall: 0xF76A,
22476 K: 0x004B,
22477 KBsquare: 0x3385,
22478 KKsquare: 0x33CD,
22479 Kabashkircyrillic: 0x04A0,
22480 Kacute: 0x1E30,
22481 Kacyrillic: 0x041A,
22482 Kadescendercyrillic: 0x049A,
22483 Kahookcyrillic: 0x04C3,
22484 Kappa: 0x039A,
22485 Kastrokecyrillic: 0x049E,
22486 Kaverticalstrokecyrillic: 0x049C,
22487 Kcaron: 0x01E8,
22488 Kcedilla: 0x0136,
22489 Kcircle: 0x24C0,
22490 Kcommaaccent: 0x0136,
22491 Kdotbelow: 0x1E32,
22492 Keharmenian: 0x0554,
22493 Kenarmenian: 0x053F,
22494 Khacyrillic: 0x0425,
22495 Kheicoptic: 0x03E6,
22496 Khook: 0x0198,
22497 Kjecyrillic: 0x040C,
22498 Klinebelow: 0x1E34,
22499 Kmonospace: 0xFF2B,
22500 Koppacyrillic: 0x0480,
22501 Koppagreek: 0x03DE,
22502 Ksicyrillic: 0x046E,
22503 Ksmall: 0xF76B,
22504 L: 0x004C,
22505 LJ: 0x01C7,
22506 LL: 0xF6BF,
22507 Lacute: 0x0139,
22508 Lambda: 0x039B,
22509 Lcaron: 0x013D,
22510 Lcedilla: 0x013B,
22511 Lcircle: 0x24C1,
22512 Lcircumflexbelow: 0x1E3C,
22513 Lcommaaccent: 0x013B,
22514 Ldot: 0x013F,
22515 Ldotaccent: 0x013F,
22516 Ldotbelow: 0x1E36,
22517 Ldotbelowmacron: 0x1E38,
22518 Liwnarmenian: 0x053C,
22519 Lj: 0x01C8,
22520 Ljecyrillic: 0x0409,
22521 Llinebelow: 0x1E3A,
22522 Lmonospace: 0xFF2C,
22523 Lslash: 0x0141,
22524 Lslashsmall: 0xF6F9,
22525 Lsmall: 0xF76C,
22526 M: 0x004D,
22527 MBsquare: 0x3386,
22528 Macron: 0xF6D0,
22529 Macronsmall: 0xF7AF,
22530 Macute: 0x1E3E,
22531 Mcircle: 0x24C2,
22532 Mdotaccent: 0x1E40,
22533 Mdotbelow: 0x1E42,
22534 Menarmenian: 0x0544,
22535 Mmonospace: 0xFF2D,
22536 Msmall: 0xF76D,
22537 Mturned: 0x019C,
22538 Mu: 0x039C,
22539 N: 0x004E,
22540 NJ: 0x01CA,
22541 Nacute: 0x0143,
22542 Ncaron: 0x0147,
22543 Ncedilla: 0x0145,
22544 Ncircle: 0x24C3,
22545 Ncircumflexbelow: 0x1E4A,
22546 Ncommaaccent: 0x0145,
22547 Ndotaccent: 0x1E44,
22548 Ndotbelow: 0x1E46,
22549 Nhookleft: 0x019D,
22550 Nineroman: 0x2168,
22551 Nj: 0x01CB,
22552 Njecyrillic: 0x040A,
22553 Nlinebelow: 0x1E48,
22554 Nmonospace: 0xFF2E,
22555 Nowarmenian: 0x0546,
22556 Nsmall: 0xF76E,
22557 Ntilde: 0x00D1,
22558 Ntildesmall: 0xF7F1,
22559 Nu: 0x039D,
22560 O: 0x004F,
22561 OE: 0x0152,
22562 OEsmall: 0xF6FA,
22563 Oacute: 0x00D3,
22564 Oacutesmall: 0xF7F3,
22565 Obarredcyrillic: 0x04E8,
22566 Obarreddieresiscyrillic: 0x04EA,
22567 Obreve: 0x014E,
22568 Ocaron: 0x01D1,
22569 Ocenteredtilde: 0x019F,
22570 Ocircle: 0x24C4,
22571 Ocircumflex: 0x00D4,
22572 Ocircumflexacute: 0x1ED0,
22573 Ocircumflexdotbelow: 0x1ED8,
22574 Ocircumflexgrave: 0x1ED2,
22575 Ocircumflexhookabove: 0x1ED4,
22576 Ocircumflexsmall: 0xF7F4,
22577 Ocircumflextilde: 0x1ED6,
22578 Ocyrillic: 0x041E,
22579 Odblacute: 0x0150,
22580 Odblgrave: 0x020C,
22581 Odieresis: 0x00D6,
22582 Odieresiscyrillic: 0x04E6,
22583 Odieresissmall: 0xF7F6,
22584 Odotbelow: 0x1ECC,
22585 Ogoneksmall: 0xF6FB,
22586 Ograve: 0x00D2,
22587 Ogravesmall: 0xF7F2,
22588 Oharmenian: 0x0555,
22589 Ohm: 0x2126,
22590 Ohookabove: 0x1ECE,
22591 Ohorn: 0x01A0,
22592 Ohornacute: 0x1EDA,
22593 Ohorndotbelow: 0x1EE2,
22594 Ohorngrave: 0x1EDC,
22595 Ohornhookabove: 0x1EDE,
22596 Ohorntilde: 0x1EE0,
22597 Ohungarumlaut: 0x0150,
22598 Oi: 0x01A2,
22599 Oinvertedbreve: 0x020E,
22600 Omacron: 0x014C,
22601 Omacronacute: 0x1E52,
22602 Omacrongrave: 0x1E50,
22603 Omega: 0x2126,
22604 Omegacyrillic: 0x0460,
22605 Omegagreek: 0x03A9,
22606 Omegaroundcyrillic: 0x047A,
22607 Omegatitlocyrillic: 0x047C,
22608 Omegatonos: 0x038F,
22609 Omicron: 0x039F,
22610 Omicrontonos: 0x038C,
22611 Omonospace: 0xFF2F,
22612 Oneroman: 0x2160,
22613 Oogonek: 0x01EA,
22614 Oogonekmacron: 0x01EC,
22615 Oopen: 0x0186,
22616 Oslash: 0x00D8,
22617 Oslashacute: 0x01FE,
22618 Oslashsmall: 0xF7F8,
22619 Osmall: 0xF76F,
22620 Ostrokeacute: 0x01FE,
22621 Otcyrillic: 0x047E,
22622 Otilde: 0x00D5,
22623 Otildeacute: 0x1E4C,
22624 Otildedieresis: 0x1E4E,
22625 Otildesmall: 0xF7F5,
22626 P: 0x0050,
22627 Pacute: 0x1E54,
22628 Pcircle: 0x24C5,
22629 Pdotaccent: 0x1E56,
22630 Pecyrillic: 0x041F,
22631 Peharmenian: 0x054A,
22632 Pemiddlehookcyrillic: 0x04A6,
22633 Phi: 0x03A6,
22634 Phook: 0x01A4,
22635 Pi: 0x03A0,
22636 Piwrarmenian: 0x0553,
22637 Pmonospace: 0xFF30,
22638 Psi: 0x03A8,
22639 Psicyrillic: 0x0470,
22640 Psmall: 0xF770,
22641 Q: 0x0051,
22642 Qcircle: 0x24C6,
22643 Qmonospace: 0xFF31,
22644 Qsmall: 0xF771,
22645 R: 0x0052,
22646 Raarmenian: 0x054C,
22647 Racute: 0x0154,
22648 Rcaron: 0x0158,
22649 Rcedilla: 0x0156,
22650 Rcircle: 0x24C7,
22651 Rcommaaccent: 0x0156,
22652 Rdblgrave: 0x0210,
22653 Rdotaccent: 0x1E58,
22654 Rdotbelow: 0x1E5A,
22655 Rdotbelowmacron: 0x1E5C,
22656 Reharmenian: 0x0550,
22657 Rfraktur: 0x211C,
22658 Rho: 0x03A1,
22659 Ringsmall: 0xF6FC,
22660 Rinvertedbreve: 0x0212,
22661 Rlinebelow: 0x1E5E,
22662 Rmonospace: 0xFF32,
22663 Rsmall: 0xF772,
22664 Rsmallinverted: 0x0281,
22665 Rsmallinvertedsuperior: 0x02B6,
22666 S: 0x0053,
22667 SF010000: 0x250C,
22668 SF020000: 0x2514,
22669 SF030000: 0x2510,
22670 SF040000: 0x2518,
22671 SF050000: 0x253C,
22672 SF060000: 0x252C,
22673 SF070000: 0x2534,
22674 SF080000: 0x251C,
22675 SF090000: 0x2524,
22676 SF100000: 0x2500,
22677 SF110000: 0x2502,
22678 SF190000: 0x2561,
22679 SF200000: 0x2562,
22680 SF210000: 0x2556,
22681 SF220000: 0x2555,
22682 SF230000: 0x2563,
22683 SF240000: 0x2551,
22684 SF250000: 0x2557,
22685 SF260000: 0x255D,
22686 SF270000: 0x255C,
22687 SF280000: 0x255B,
22688 SF360000: 0x255E,
22689 SF370000: 0x255F,
22690 SF380000: 0x255A,
22691 SF390000: 0x2554,
22692 SF400000: 0x2569,
22693 SF410000: 0x2566,
22694 SF420000: 0x2560,
22695 SF430000: 0x2550,
22696 SF440000: 0x256C,
22697 SF450000: 0x2567,
22698 SF460000: 0x2568,
22699 SF470000: 0x2564,
22700 SF480000: 0x2565,
22701 SF490000: 0x2559,
22702 SF500000: 0x2558,
22703 SF510000: 0x2552,
22704 SF520000: 0x2553,
22705 SF530000: 0x256B,
22706 SF540000: 0x256A,
22707 Sacute: 0x015A,
22708 Sacutedotaccent: 0x1E64,
22709 Sampigreek: 0x03E0,
22710 Scaron: 0x0160,
22711 Scarondotaccent: 0x1E66,
22712 Scaronsmall: 0xF6FD,
22713 Scedilla: 0x015E,
22714 Schwa: 0x018F,
22715 Schwacyrillic: 0x04D8,
22716 Schwadieresiscyrillic: 0x04DA,
22717 Scircle: 0x24C8,
22718 Scircumflex: 0x015C,
22719 Scommaaccent: 0x0218,
22720 Sdotaccent: 0x1E60,
22721 Sdotbelow: 0x1E62,
22722 Sdotbelowdotaccent: 0x1E68,
22723 Seharmenian: 0x054D,
22724 Sevenroman: 0x2166,
22725 Shaarmenian: 0x0547,
22726 Shacyrillic: 0x0428,
22727 Shchacyrillic: 0x0429,
22728 Sheicoptic: 0x03E2,
22729 Shhacyrillic: 0x04BA,
22730 Shimacoptic: 0x03EC,
22731 Sigma: 0x03A3,
22732 Sixroman: 0x2165,
22733 Smonospace: 0xFF33,
22734 Softsigncyrillic: 0x042C,
22735 Ssmall: 0xF773,
22736 Stigmagreek: 0x03DA,
22737 T: 0x0054,
22738 Tau: 0x03A4,
22739 Tbar: 0x0166,
22740 Tcaron: 0x0164,
22741 Tcedilla: 0x0162,
22742 Tcircle: 0x24C9,
22743 Tcircumflexbelow: 0x1E70,
22744 Tcommaaccent: 0x0162,
22745 Tdotaccent: 0x1E6A,
22746 Tdotbelow: 0x1E6C,
22747 Tecyrillic: 0x0422,
22748 Tedescendercyrillic: 0x04AC,
22749 Tenroman: 0x2169,
22750 Tetsecyrillic: 0x04B4,
22751 Theta: 0x0398,
22752 Thook: 0x01AC,
22753 Thorn: 0x00DE,
22754 Thornsmall: 0xF7FE,
22755 Threeroman: 0x2162,
22756 Tildesmall: 0xF6FE,
22757 Tiwnarmenian: 0x054F,
22758 Tlinebelow: 0x1E6E,
22759 Tmonospace: 0xFF34,
22760 Toarmenian: 0x0539,
22761 Tonefive: 0x01BC,
22762 Tonesix: 0x0184,
22763 Tonetwo: 0x01A7,
22764 Tretroflexhook: 0x01AE,
22765 Tsecyrillic: 0x0426,
22766 Tshecyrillic: 0x040B,
22767 Tsmall: 0xF774,
22768 Twelveroman: 0x216B,
22769 Tworoman: 0x2161,
22770 U: 0x0055,
22771 Uacute: 0x00DA,
22772 Uacutesmall: 0xF7FA,
22773 Ubreve: 0x016C,
22774 Ucaron: 0x01D3,
22775 Ucircle: 0x24CA,
22776 Ucircumflex: 0x00DB,
22777 Ucircumflexbelow: 0x1E76,
22778 Ucircumflexsmall: 0xF7FB,
22779 Ucyrillic: 0x0423,
22780 Udblacute: 0x0170,
22781 Udblgrave: 0x0214,
22782 Udieresis: 0x00DC,
22783 Udieresisacute: 0x01D7,
22784 Udieresisbelow: 0x1E72,
22785 Udieresiscaron: 0x01D9,
22786 Udieresiscyrillic: 0x04F0,
22787 Udieresisgrave: 0x01DB,
22788 Udieresismacron: 0x01D5,
22789 Udieresissmall: 0xF7FC,
22790 Udotbelow: 0x1EE4,
22791 Ugrave: 0x00D9,
22792 Ugravesmall: 0xF7F9,
22793 Uhookabove: 0x1EE6,
22794 Uhorn: 0x01AF,
22795 Uhornacute: 0x1EE8,
22796 Uhorndotbelow: 0x1EF0,
22797 Uhorngrave: 0x1EEA,
22798 Uhornhookabove: 0x1EEC,
22799 Uhorntilde: 0x1EEE,
22800 Uhungarumlaut: 0x0170,
22801 Uhungarumlautcyrillic: 0x04F2,
22802 Uinvertedbreve: 0x0216,
22803 Ukcyrillic: 0x0478,
22804 Umacron: 0x016A,
22805 Umacroncyrillic: 0x04EE,
22806 Umacrondieresis: 0x1E7A,
22807 Umonospace: 0xFF35,
22808 Uogonek: 0x0172,
22809 Upsilon: 0x03A5,
22810 Upsilon1: 0x03D2,
22811 Upsilonacutehooksymbolgreek: 0x03D3,
22812 Upsilonafrican: 0x01B1,
22813 Upsilondieresis: 0x03AB,
22814 Upsilondieresishooksymbolgreek: 0x03D4,
22815 Upsilonhooksymbol: 0x03D2,
22816 Upsilontonos: 0x038E,
22817 Uring: 0x016E,
22818 Ushortcyrillic: 0x040E,
22819 Usmall: 0xF775,
22820 Ustraightcyrillic: 0x04AE,
22821 Ustraightstrokecyrillic: 0x04B0,
22822 Utilde: 0x0168,
22823 Utildeacute: 0x1E78,
22824 Utildebelow: 0x1E74,
22825 V: 0x0056,
22826 Vcircle: 0x24CB,
22827 Vdotbelow: 0x1E7E,
22828 Vecyrillic: 0x0412,
22829 Vewarmenian: 0x054E,
22830 Vhook: 0x01B2,
22831 Vmonospace: 0xFF36,
22832 Voarmenian: 0x0548,
22833 Vsmall: 0xF776,
22834 Vtilde: 0x1E7C,
22835 W: 0x0057,
22836 Wacute: 0x1E82,
22837 Wcircle: 0x24CC,
22838 Wcircumflex: 0x0174,
22839 Wdieresis: 0x1E84,
22840 Wdotaccent: 0x1E86,
22841 Wdotbelow: 0x1E88,
22842 Wgrave: 0x1E80,
22843 Wmonospace: 0xFF37,
22844 Wsmall: 0xF777,
22845 X: 0x0058,
22846 Xcircle: 0x24CD,
22847 Xdieresis: 0x1E8C,
22848 Xdotaccent: 0x1E8A,
22849 Xeharmenian: 0x053D,
22850 Xi: 0x039E,
22851 Xmonospace: 0xFF38,
22852 Xsmall: 0xF778,
22853 Y: 0x0059,
22854 Yacute: 0x00DD,
22855 Yacutesmall: 0xF7FD,
22856 Yatcyrillic: 0x0462,
22857 Ycircle: 0x24CE,
22858 Ycircumflex: 0x0176,
22859 Ydieresis: 0x0178,
22860 Ydieresissmall: 0xF7FF,
22861 Ydotaccent: 0x1E8E,
22862 Ydotbelow: 0x1EF4,
22863 Yericyrillic: 0x042B,
22864 Yerudieresiscyrillic: 0x04F8,
22865 Ygrave: 0x1EF2,
22866 Yhook: 0x01B3,
22867 Yhookabove: 0x1EF6,
22868 Yiarmenian: 0x0545,
22869 Yicyrillic: 0x0407,
22870 Yiwnarmenian: 0x0552,
22871 Ymonospace: 0xFF39,
22872 Ysmall: 0xF779,
22873 Ytilde: 0x1EF8,
22874 Yusbigcyrillic: 0x046A,
22875 Yusbigiotifiedcyrillic: 0x046C,
22876 Yuslittlecyrillic: 0x0466,
22877 Yuslittleiotifiedcyrillic: 0x0468,
22878 Z: 0x005A,
22879 Zaarmenian: 0x0536,
22880 Zacute: 0x0179,
22881 Zcaron: 0x017D,
22882 Zcaronsmall: 0xF6FF,
22883 Zcircle: 0x24CF,
22884 Zcircumflex: 0x1E90,
22885 Zdot: 0x017B,
22886 Zdotaccent: 0x017B,
22887 Zdotbelow: 0x1E92,
22888 Zecyrillic: 0x0417,
22889 Zedescendercyrillic: 0x0498,
22890 Zedieresiscyrillic: 0x04DE,
22891 Zeta: 0x0396,
22892 Zhearmenian: 0x053A,
22893 Zhebrevecyrillic: 0x04C1,
22894 Zhecyrillic: 0x0416,
22895 Zhedescendercyrillic: 0x0496,
22896 Zhedieresiscyrillic: 0x04DC,
22897 Zlinebelow: 0x1E94,
22898 Zmonospace: 0xFF3A,
22899 Zsmall: 0xF77A,
22900 Zstroke: 0x01B5,
22901 a: 0x0061,
22902 aabengali: 0x0986,
22903 aacute: 0x00E1,
22904 aadeva: 0x0906,
22905 aagujarati: 0x0A86,
22906 aagurmukhi: 0x0A06,
22907 aamatragurmukhi: 0x0A3E,
22908 aarusquare: 0x3303,
22909 aavowelsignbengali: 0x09BE,
22910 aavowelsigndeva: 0x093E,
22911 aavowelsigngujarati: 0x0ABE,
22912 abbreviationmarkarmenian: 0x055F,
22913 abbreviationsigndeva: 0x0970,
22914 abengali: 0x0985,
22915 abopomofo: 0x311A,
22916 abreve: 0x0103,
22917 abreveacute: 0x1EAF,
22918 abrevecyrillic: 0x04D1,
22919 abrevedotbelow: 0x1EB7,
22920 abrevegrave: 0x1EB1,
22921 abrevehookabove: 0x1EB3,
22922 abrevetilde: 0x1EB5,
22923 acaron: 0x01CE,
22924 acircle: 0x24D0,
22925 acircumflex: 0x00E2,
22926 acircumflexacute: 0x1EA5,
22927 acircumflexdotbelow: 0x1EAD,
22928 acircumflexgrave: 0x1EA7,
22929 acircumflexhookabove: 0x1EA9,
22930 acircumflextilde: 0x1EAB,
22931 acute: 0x00B4,
22932 acutebelowcmb: 0x0317,
22933 acutecmb: 0x0301,
22934 acutecomb: 0x0301,
22935 acutedeva: 0x0954,
22936 acutelowmod: 0x02CF,
22937 acutetonecmb: 0x0341,
22938 acyrillic: 0x0430,
22939 adblgrave: 0x0201,
22940 addakgurmukhi: 0x0A71,
22941 adeva: 0x0905,
22942 adieresis: 0x00E4,
22943 adieresiscyrillic: 0x04D3,
22944 adieresismacron: 0x01DF,
22945 adotbelow: 0x1EA1,
22946 adotmacron: 0x01E1,
22947 ae: 0x00E6,
22948 aeacute: 0x01FD,
22949 aekorean: 0x3150,
22950 aemacron: 0x01E3,
22951 afii00208: 0x2015,
22952 afii08941: 0x20A4,
22953 afii10017: 0x0410,
22954 afii10018: 0x0411,
22955 afii10019: 0x0412,
22956 afii10020: 0x0413,
22957 afii10021: 0x0414,
22958 afii10022: 0x0415,
22959 afii10023: 0x0401,
22960 afii10024: 0x0416,
22961 afii10025: 0x0417,
22962 afii10026: 0x0418,
22963 afii10027: 0x0419,
22964 afii10028: 0x041A,
22965 afii10029: 0x041B,
22966 afii10030: 0x041C,
22967 afii10031: 0x041D,
22968 afii10032: 0x041E,
22969 afii10033: 0x041F,
22970 afii10034: 0x0420,
22971 afii10035: 0x0421,
22972 afii10036: 0x0422,
22973 afii10037: 0x0423,
22974 afii10038: 0x0424,
22975 afii10039: 0x0425,
22976 afii10040: 0x0426,
22977 afii10041: 0x0427,
22978 afii10042: 0x0428,
22979 afii10043: 0x0429,
22980 afii10044: 0x042A,
22981 afii10045: 0x042B,
22982 afii10046: 0x042C,
22983 afii10047: 0x042D,
22984 afii10048: 0x042E,
22985 afii10049: 0x042F,
22986 afii10050: 0x0490,
22987 afii10051: 0x0402,
22988 afii10052: 0x0403,
22989 afii10053: 0x0404,
22990 afii10054: 0x0405,
22991 afii10055: 0x0406,
22992 afii10056: 0x0407,
22993 afii10057: 0x0408,
22994 afii10058: 0x0409,
22995 afii10059: 0x040A,
22996 afii10060: 0x040B,
22997 afii10061: 0x040C,
22998 afii10062: 0x040E,
22999 afii10063: 0xF6C4,
23000 afii10064: 0xF6C5,
23001 afii10065: 0x0430,
23002 afii10066: 0x0431,
23003 afii10067: 0x0432,
23004 afii10068: 0x0433,
23005 afii10069: 0x0434,
23006 afii10070: 0x0435,
23007 afii10071: 0x0451,
23008 afii10072: 0x0436,
23009 afii10073: 0x0437,
23010 afii10074: 0x0438,
23011 afii10075: 0x0439,
23012 afii10076: 0x043A,
23013 afii10077: 0x043B,
23014 afii10078: 0x043C,
23015 afii10079: 0x043D,
23016 afii10080: 0x043E,
23017 afii10081: 0x043F,
23018 afii10082: 0x0440,
23019 afii10083: 0x0441,
23020 afii10084: 0x0442,
23021 afii10085: 0x0443,
23022 afii10086: 0x0444,
23023 afii10087: 0x0445,
23024 afii10088: 0x0446,
23025 afii10089: 0x0447,
23026 afii10090: 0x0448,
23027 afii10091: 0x0449,
23028 afii10092: 0x044A,
23029 afii10093: 0x044B,
23030 afii10094: 0x044C,
23031 afii10095: 0x044D,
23032 afii10096: 0x044E,
23033 afii10097: 0x044F,
23034 afii10098: 0x0491,
23035 afii10099: 0x0452,
23036 afii10100: 0x0453,
23037 afii10101: 0x0454,
23038 afii10102: 0x0455,
23039 afii10103: 0x0456,
23040 afii10104: 0x0457,
23041 afii10105: 0x0458,
23042 afii10106: 0x0459,
23043 afii10107: 0x045A,
23044 afii10108: 0x045B,
23045 afii10109: 0x045C,
23046 afii10110: 0x045E,
23047 afii10145: 0x040F,
23048 afii10146: 0x0462,
23049 afii10147: 0x0472,
23050 afii10148: 0x0474,
23051 afii10192: 0xF6C6,
23052 afii10193: 0x045F,
23053 afii10194: 0x0463,
23054 afii10195: 0x0473,
23055 afii10196: 0x0475,
23056 afii10831: 0xF6C7,
23057 afii10832: 0xF6C8,
23058 afii10846: 0x04D9,
23059 afii299: 0x200E,
23060 afii300: 0x200F,
23061 afii301: 0x200D,
23062 afii57381: 0x066A,
23063 afii57388: 0x060C,
23064 afii57392: 0x0660,
23065 afii57393: 0x0661,
23066 afii57394: 0x0662,
23067 afii57395: 0x0663,
23068 afii57396: 0x0664,
23069 afii57397: 0x0665,
23070 afii57398: 0x0666,
23071 afii57399: 0x0667,
23072 afii57400: 0x0668,
23073 afii57401: 0x0669,
23074 afii57403: 0x061B,
23075 afii57407: 0x061F,
23076 afii57409: 0x0621,
23077 afii57410: 0x0622,
23078 afii57411: 0x0623,
23079 afii57412: 0x0624,
23080 afii57413: 0x0625,
23081 afii57414: 0x0626,
23082 afii57415: 0x0627,
23083 afii57416: 0x0628,
23084 afii57417: 0x0629,
23085 afii57418: 0x062A,
23086 afii57419: 0x062B,
23087 afii57420: 0x062C,
23088 afii57421: 0x062D,
23089 afii57422: 0x062E,
23090 afii57423: 0x062F,
23091 afii57424: 0x0630,
23092 afii57425: 0x0631,
23093 afii57426: 0x0632,
23094 afii57427: 0x0633,
23095 afii57428: 0x0634,
23096 afii57429: 0x0635,
23097 afii57430: 0x0636,
23098 afii57431: 0x0637,
23099 afii57432: 0x0638,
23100 afii57433: 0x0639,
23101 afii57434: 0x063A,
23102 afii57440: 0x0640,
23103 afii57441: 0x0641,
23104 afii57442: 0x0642,
23105 afii57443: 0x0643,
23106 afii57444: 0x0644,
23107 afii57445: 0x0645,
23108 afii57446: 0x0646,
23109 afii57448: 0x0648,
23110 afii57449: 0x0649,
23111 afii57450: 0x064A,
23112 afii57451: 0x064B,
23113 afii57452: 0x064C,
23114 afii57453: 0x064D,
23115 afii57454: 0x064E,
23116 afii57455: 0x064F,
23117 afii57456: 0x0650,
23118 afii57457: 0x0651,
23119 afii57458: 0x0652,
23120 afii57470: 0x0647,
23121 afii57505: 0x06A4,
23122 afii57506: 0x067E,
23123 afii57507: 0x0686,
23124 afii57508: 0x0698,
23125 afii57509: 0x06AF,
23126 afii57511: 0x0679,
23127 afii57512: 0x0688,
23128 afii57513: 0x0691,
23129 afii57514: 0x06BA,
23130 afii57519: 0x06D2,
23131 afii57534: 0x06D5,
23132 afii57636: 0x20AA,
23133 afii57645: 0x05BE,
23134 afii57658: 0x05C3,
23135 afii57664: 0x05D0,
23136 afii57665: 0x05D1,
23137 afii57666: 0x05D2,
23138 afii57667: 0x05D3,
23139 afii57668: 0x05D4,
23140 afii57669: 0x05D5,
23141 afii57670: 0x05D6,
23142 afii57671: 0x05D7,
23143 afii57672: 0x05D8,
23144 afii57673: 0x05D9,
23145 afii57674: 0x05DA,
23146 afii57675: 0x05DB,
23147 afii57676: 0x05DC,
23148 afii57677: 0x05DD,
23149 afii57678: 0x05DE,
23150 afii57679: 0x05DF,
23151 afii57680: 0x05E0,
23152 afii57681: 0x05E1,
23153 afii57682: 0x05E2,
23154 afii57683: 0x05E3,
23155 afii57684: 0x05E4,
23156 afii57685: 0x05E5,
23157 afii57686: 0x05E6,
23158 afii57687: 0x05E7,
23159 afii57688: 0x05E8,
23160 afii57689: 0x05E9,
23161 afii57690: 0x05EA,
23162 afii57694: 0xFB2A,
23163 afii57695: 0xFB2B,
23164 afii57700: 0xFB4B,
23165 afii57705: 0xFB1F,
23166 afii57716: 0x05F0,
23167 afii57717: 0x05F1,
23168 afii57718: 0x05F2,
23169 afii57723: 0xFB35,
23170 afii57793: 0x05B4,
23171 afii57794: 0x05B5,
23172 afii57795: 0x05B6,
23173 afii57796: 0x05BB,
23174 afii57797: 0x05B8,
23175 afii57798: 0x05B7,
23176 afii57799: 0x05B0,
23177 afii57800: 0x05B2,
23178 afii57801: 0x05B1,
23179 afii57802: 0x05B3,
23180 afii57803: 0x05C2,
23181 afii57804: 0x05C1,
23182 afii57806: 0x05B9,
23183 afii57807: 0x05BC,
23184 afii57839: 0x05BD,
23185 afii57841: 0x05BF,
23186 afii57842: 0x05C0,
23187 afii57929: 0x02BC,
23188 afii61248: 0x2105,
23189 afii61289: 0x2113,
23190 afii61352: 0x2116,
23191 afii61573: 0x202C,
23192 afii61574: 0x202D,
23193 afii61575: 0x202E,
23194 afii61664: 0x200C,
23195 afii63167: 0x066D,
23196 afii64937: 0x02BD,
23197 agrave: 0x00E0,
23198 agujarati: 0x0A85,
23199 agurmukhi: 0x0A05,
23200 ahiragana: 0x3042,
23201 ahookabove: 0x1EA3,
23202 aibengali: 0x0990,
23203 aibopomofo: 0x311E,
23204 aideva: 0x0910,
23205 aiecyrillic: 0x04D5,
23206 aigujarati: 0x0A90,
23207 aigurmukhi: 0x0A10,
23208 aimatragurmukhi: 0x0A48,
23209 ainarabic: 0x0639,
23210 ainfinalarabic: 0xFECA,
23211 aininitialarabic: 0xFECB,
23212 ainmedialarabic: 0xFECC,
23213 ainvertedbreve: 0x0203,
23214 aivowelsignbengali: 0x09C8,
23215 aivowelsigndeva: 0x0948,
23216 aivowelsigngujarati: 0x0AC8,
23217 akatakana: 0x30A2,
23218 akatakanahalfwidth: 0xFF71,
23219 akorean: 0x314F,
23220 alef: 0x05D0,
23221 alefarabic: 0x0627,
23222 alefdageshhebrew: 0xFB30,
23223 aleffinalarabic: 0xFE8E,
23224 alefhamzaabovearabic: 0x0623,
23225 alefhamzaabovefinalarabic: 0xFE84,
23226 alefhamzabelowarabic: 0x0625,
23227 alefhamzabelowfinalarabic: 0xFE88,
23228 alefhebrew: 0x05D0,
23229 aleflamedhebrew: 0xFB4F,
23230 alefmaddaabovearabic: 0x0622,
23231 alefmaddaabovefinalarabic: 0xFE82,
23232 alefmaksuraarabic: 0x0649,
23233 alefmaksurafinalarabic: 0xFEF0,
23234 alefmaksurainitialarabic: 0xFEF3,
23235 alefmaksuramedialarabic: 0xFEF4,
23236 alefpatahhebrew: 0xFB2E,
23237 alefqamatshebrew: 0xFB2F,
23238 aleph: 0x2135,
23239 allequal: 0x224C,
23240 alpha: 0x03B1,
23241 alphatonos: 0x03AC,
23242 amacron: 0x0101,
23243 amonospace: 0xFF41,
23244 ampersand: 0x0026,
23245 ampersandmonospace: 0xFF06,
23246 ampersandsmall: 0xF726,
23247 amsquare: 0x33C2,
23248 anbopomofo: 0x3122,
23249 angbopomofo: 0x3124,
23250 angbracketleft: 0x3008, // This glyph is missing from Adobe's original list.
23251 angbracketright: 0x3009, // This glyph is missing from Adobe's original list.
23252 angkhankhuthai: 0x0E5A,
23253 angle: 0x2220,
23254 anglebracketleft: 0x3008,
23255 anglebracketleftvertical: 0xFE3F,
23256 anglebracketright: 0x3009,
23257 anglebracketrightvertical: 0xFE40,
23258 angleleft: 0x2329,
23259 angleright: 0x232A,
23260 angstrom: 0x212B,
23261 anoteleia: 0x0387,
23262 anudattadeva: 0x0952,
23263 anusvarabengali: 0x0982,
23264 anusvaradeva: 0x0902,
23265 anusvaragujarati: 0x0A82,
23266 aogonek: 0x0105,
23267 apaatosquare: 0x3300,
23268 aparen: 0x249C,
23269 apostrophearmenian: 0x055A,
23270 apostrophemod: 0x02BC,
23271 apple: 0xF8FF,
23272 approaches: 0x2250,
23273 approxequal: 0x2248,
23274 approxequalorimage: 0x2252,
23275 approximatelyequal: 0x2245,
23276 araeaekorean: 0x318E,
23277 araeakorean: 0x318D,
23278 arc: 0x2312,
23279 arighthalfring: 0x1E9A,
23280 aring: 0x00E5,
23281 aringacute: 0x01FB,
23282 aringbelow: 0x1E01,
23283 arrowboth: 0x2194,
23284 arrowdashdown: 0x21E3,
23285 arrowdashleft: 0x21E0,
23286 arrowdashright: 0x21E2,
23287 arrowdashup: 0x21E1,
23288 arrowdblboth: 0x21D4,
23289 arrowdbldown: 0x21D3,
23290 arrowdblleft: 0x21D0,
23291 arrowdblright: 0x21D2,
23292 arrowdblup: 0x21D1,
23293 arrowdown: 0x2193,
23294 arrowdownleft: 0x2199,
23295 arrowdownright: 0x2198,
23296 arrowdownwhite: 0x21E9,
23297 arrowheaddownmod: 0x02C5,
23298 arrowheadleftmod: 0x02C2,
23299 arrowheadrightmod: 0x02C3,
23300 arrowheadupmod: 0x02C4,
23301 arrowhorizex: 0xF8E7,
23302 arrowleft: 0x2190,
23303 arrowleftdbl: 0x21D0,
23304 arrowleftdblstroke: 0x21CD,
23305 arrowleftoverright: 0x21C6,
23306 arrowleftwhite: 0x21E6,
23307 arrowright: 0x2192,
23308 arrowrightdblstroke: 0x21CF,
23309 arrowrightheavy: 0x279E,
23310 arrowrightoverleft: 0x21C4,
23311 arrowrightwhite: 0x21E8,
23312 arrowtableft: 0x21E4,
23313 arrowtabright: 0x21E5,
23314 arrowup: 0x2191,
23315 arrowupdn: 0x2195,
23316 arrowupdnbse: 0x21A8,
23317 arrowupdownbase: 0x21A8,
23318 arrowupleft: 0x2196,
23319 arrowupleftofdown: 0x21C5,
23320 arrowupright: 0x2197,
23321 arrowupwhite: 0x21E7,
23322 arrowvertex: 0xF8E6,
23323 asciicircum: 0x005E,
23324 asciicircummonospace: 0xFF3E,
23325 asciitilde: 0x007E,
23326 asciitildemonospace: 0xFF5E,
23327 ascript: 0x0251,
23328 ascriptturned: 0x0252,
23329 asmallhiragana: 0x3041,
23330 asmallkatakana: 0x30A1,
23331 asmallkatakanahalfwidth: 0xFF67,
23332 asterisk: 0x002A,
23333 asteriskaltonearabic: 0x066D,
23334 asteriskarabic: 0x066D,
23335 asteriskmath: 0x2217,
23336 asteriskmonospace: 0xFF0A,
23337 asterisksmall: 0xFE61,
23338 asterism: 0x2042,
23339 asuperior: 0xF6E9,
23340 asymptoticallyequal: 0x2243,
23341 at: 0x0040,
23342 atilde: 0x00E3,
23343 atmonospace: 0xFF20,
23344 atsmall: 0xFE6B,
23345 aturned: 0x0250,
23346 aubengali: 0x0994,
23347 aubopomofo: 0x3120,
23348 audeva: 0x0914,
23349 augujarati: 0x0A94,
23350 augurmukhi: 0x0A14,
23351 aulengthmarkbengali: 0x09D7,
23352 aumatragurmukhi: 0x0A4C,
23353 auvowelsignbengali: 0x09CC,
23354 auvowelsigndeva: 0x094C,
23355 auvowelsigngujarati: 0x0ACC,
23356 avagrahadeva: 0x093D,
23357 aybarmenian: 0x0561,
23358 ayin: 0x05E2,
23359 ayinaltonehebrew: 0xFB20,
23360 ayinhebrew: 0x05E2,
23361 b: 0x0062,
23362 babengali: 0x09AC,
23363 backslash: 0x005C,
23364 backslashmonospace: 0xFF3C,
23365 badeva: 0x092C,
23366 bagujarati: 0x0AAC,
23367 bagurmukhi: 0x0A2C,
23368 bahiragana: 0x3070,
23369 bahtthai: 0x0E3F,
23370 bakatakana: 0x30D0,
23371 bar: 0x007C,
23372 barmonospace: 0xFF5C,
23373 bbopomofo: 0x3105,
23374 bcircle: 0x24D1,
23375 bdotaccent: 0x1E03,
23376 bdotbelow: 0x1E05,
23377 beamedsixteenthnotes: 0x266C,
23378 because: 0x2235,
23379 becyrillic: 0x0431,
23380 beharabic: 0x0628,
23381 behfinalarabic: 0xFE90,
23382 behinitialarabic: 0xFE91,
23383 behiragana: 0x3079,
23384 behmedialarabic: 0xFE92,
23385 behmeeminitialarabic: 0xFC9F,
23386 behmeemisolatedarabic: 0xFC08,
23387 behnoonfinalarabic: 0xFC6D,
23388 bekatakana: 0x30D9,
23389 benarmenian: 0x0562,
23390 bet: 0x05D1,
23391 beta: 0x03B2,
23392 betasymbolgreek: 0x03D0,
23393 betdagesh: 0xFB31,
23394 betdageshhebrew: 0xFB31,
23395 bethebrew: 0x05D1,
23396 betrafehebrew: 0xFB4C,
23397 bhabengali: 0x09AD,
23398 bhadeva: 0x092D,
23399 bhagujarati: 0x0AAD,
23400 bhagurmukhi: 0x0A2D,
23401 bhook: 0x0253,
23402 bihiragana: 0x3073,
23403 bikatakana: 0x30D3,
23404 bilabialclick: 0x0298,
23405 bindigurmukhi: 0x0A02,
23406 birusquare: 0x3331,
23407 blackcircle: 0x25CF,
23408 blackdiamond: 0x25C6,
23409 blackdownpointingtriangle: 0x25BC,
23410 blackleftpointingpointer: 0x25C4,
23411 blackleftpointingtriangle: 0x25C0,
23412 blacklenticularbracketleft: 0x3010,
23413 blacklenticularbracketleftvertical: 0xFE3B,
23414 blacklenticularbracketright: 0x3011,
23415 blacklenticularbracketrightvertical: 0xFE3C,
23416 blacklowerlefttriangle: 0x25E3,
23417 blacklowerrighttriangle: 0x25E2,
23418 blackrectangle: 0x25AC,
23419 blackrightpointingpointer: 0x25BA,
23420 blackrightpointingtriangle: 0x25B6,
23421 blacksmallsquare: 0x25AA,
23422 blacksmilingface: 0x263B,
23423 blacksquare: 0x25A0,
23424 blackstar: 0x2605,
23425 blackupperlefttriangle: 0x25E4,
23426 blackupperrighttriangle: 0x25E5,
23427 blackuppointingsmalltriangle: 0x25B4,
23428 blackuppointingtriangle: 0x25B2,
23429 blank: 0x2423,
23430 blinebelow: 0x1E07,
23431 block: 0x2588,
23432 bmonospace: 0xFF42,
23433 bobaimaithai: 0x0E1A,
23434 bohiragana: 0x307C,
23435 bokatakana: 0x30DC,
23436 bparen: 0x249D,
23437 bqsquare: 0x33C3,
23438 braceex: 0xF8F4,
23439 braceleft: 0x007B,
23440 braceleftbt: 0xF8F3,
23441 braceleftmid: 0xF8F2,
23442 braceleftmonospace: 0xFF5B,
23443 braceleftsmall: 0xFE5B,
23444 bracelefttp: 0xF8F1,
23445 braceleftvertical: 0xFE37,
23446 braceright: 0x007D,
23447 bracerightbt: 0xF8FE,
23448 bracerightmid: 0xF8FD,
23449 bracerightmonospace: 0xFF5D,
23450 bracerightsmall: 0xFE5C,
23451 bracerighttp: 0xF8FC,
23452 bracerightvertical: 0xFE38,
23453 bracketleft: 0x005B,
23454 bracketleftbt: 0xF8F0,
23455 bracketleftex: 0xF8EF,
23456 bracketleftmonospace: 0xFF3B,
23457 bracketlefttp: 0xF8EE,
23458 bracketright: 0x005D,
23459 bracketrightbt: 0xF8FB,
23460 bracketrightex: 0xF8FA,
23461 bracketrightmonospace: 0xFF3D,
23462 bracketrighttp: 0xF8F9,
23463 breve: 0x02D8,
23464 brevebelowcmb: 0x032E,
23465 brevecmb: 0x0306,
23466 breveinvertedbelowcmb: 0x032F,
23467 breveinvertedcmb: 0x0311,
23468 breveinverteddoublecmb: 0x0361,
23469 bridgebelowcmb: 0x032A,
23470 bridgeinvertedbelowcmb: 0x033A,
23471 brokenbar: 0x00A6,
23472 bstroke: 0x0180,
23473 bsuperior: 0xF6EA,
23474 btopbar: 0x0183,
23475 buhiragana: 0x3076,
23476 bukatakana: 0x30D6,
23477 bullet: 0x2022,
23478 bulletinverse: 0x25D8,
23479 bulletoperator: 0x2219,
23480 bullseye: 0x25CE,
23481 c: 0x0063,
23482 caarmenian: 0x056E,
23483 cabengali: 0x099A,
23484 cacute: 0x0107,
23485 cadeva: 0x091A,
23486 cagujarati: 0x0A9A,
23487 cagurmukhi: 0x0A1A,
23488 calsquare: 0x3388,
23489 candrabindubengali: 0x0981,
23490 candrabinducmb: 0x0310,
23491 candrabindudeva: 0x0901,
23492 candrabindugujarati: 0x0A81,
23493 capslock: 0x21EA,
23494 careof: 0x2105,
23495 caron: 0x02C7,
23496 caronbelowcmb: 0x032C,
23497 caroncmb: 0x030C,
23498 carriagereturn: 0x21B5,
23499 cbopomofo: 0x3118,
23500 ccaron: 0x010D,
23501 ccedilla: 0x00E7,
23502 ccedillaacute: 0x1E09,
23503 ccircle: 0x24D2,
23504 ccircumflex: 0x0109,
23505 ccurl: 0x0255,
23506 cdot: 0x010B,
23507 cdotaccent: 0x010B,
23508 cdsquare: 0x33C5,
23509 cedilla: 0x00B8,
23510 cedillacmb: 0x0327,
23511 cent: 0x00A2,
23512 centigrade: 0x2103,
23513 centinferior: 0xF6DF,
23514 centmonospace: 0xFFE0,
23515 centoldstyle: 0xF7A2,
23516 centsuperior: 0xF6E0,
23517 chaarmenian: 0x0579,
23518 chabengali: 0x099B,
23519 chadeva: 0x091B,
23520 chagujarati: 0x0A9B,
23521 chagurmukhi: 0x0A1B,
23522 chbopomofo: 0x3114,
23523 cheabkhasiancyrillic: 0x04BD,
23524 checkmark: 0x2713,
23525 checyrillic: 0x0447,
23526 chedescenderabkhasiancyrillic: 0x04BF,
23527 chedescendercyrillic: 0x04B7,
23528 chedieresiscyrillic: 0x04F5,
23529 cheharmenian: 0x0573,
23530 chekhakassiancyrillic: 0x04CC,
23531 cheverticalstrokecyrillic: 0x04B9,
23532 chi: 0x03C7,
23533 chieuchacirclekorean: 0x3277,
23534 chieuchaparenkorean: 0x3217,
23535 chieuchcirclekorean: 0x3269,
23536 chieuchkorean: 0x314A,
23537 chieuchparenkorean: 0x3209,
23538 chochangthai: 0x0E0A,
23539 chochanthai: 0x0E08,
23540 chochingthai: 0x0E09,
23541 chochoethai: 0x0E0C,
23542 chook: 0x0188,
23543 cieucacirclekorean: 0x3276,
23544 cieucaparenkorean: 0x3216,
23545 cieuccirclekorean: 0x3268,
23546 cieuckorean: 0x3148,
23547 cieucparenkorean: 0x3208,
23548 cieucuparenkorean: 0x321C,
23549 circle: 0x25CB,
23550 circlecopyrt: 0x00A9, // This glyph is missing from Adobe's original list.
23551 circlemultiply: 0x2297,
23552 circleot: 0x2299,
23553 circleplus: 0x2295,
23554 circlepostalmark: 0x3036,
23555 circlewithlefthalfblack: 0x25D0,
23556 circlewithrighthalfblack: 0x25D1,
23557 circumflex: 0x02C6,
23558 circumflexbelowcmb: 0x032D,
23559 circumflexcmb: 0x0302,
23560 clear: 0x2327,
23561 clickalveolar: 0x01C2,
23562 clickdental: 0x01C0,
23563 clicklateral: 0x01C1,
23564 clickretroflex: 0x01C3,
23565 club: 0x2663,
23566 clubsuitblack: 0x2663,
23567 clubsuitwhite: 0x2667,
23568 cmcubedsquare: 0x33A4,
23569 cmonospace: 0xFF43,
23570 cmsquaredsquare: 0x33A0,
23571 coarmenian: 0x0581,
23572 colon: 0x003A,
23573 colonmonetary: 0x20A1,
23574 colonmonospace: 0xFF1A,
23575 colonsign: 0x20A1,
23576 colonsmall: 0xFE55,
23577 colontriangularhalfmod: 0x02D1,
23578 colontriangularmod: 0x02D0,
23579 comma: 0x002C,
23580 commaabovecmb: 0x0313,
23581 commaaboverightcmb: 0x0315,
23582 commaaccent: 0xF6C3,
23583 commaarabic: 0x060C,
23584 commaarmenian: 0x055D,
23585 commainferior: 0xF6E1,
23586 commamonospace: 0xFF0C,
23587 commareversedabovecmb: 0x0314,
23588 commareversedmod: 0x02BD,
23589 commasmall: 0xFE50,
23590 commasuperior: 0xF6E2,
23591 commaturnedabovecmb: 0x0312,
23592 commaturnedmod: 0x02BB,
23593 compass: 0x263C,
23594 congruent: 0x2245,
23595 contourintegral: 0x222E,
23596 control: 0x2303,
23597 controlACK: 0x0006,
23598 controlBEL: 0x0007,
23599 controlBS: 0x0008,
23600 controlCAN: 0x0018,
23601 controlCR: 0x000D,
23602 controlDC1: 0x0011,
23603 controlDC2: 0x0012,
23604 controlDC3: 0x0013,
23605 controlDC4: 0x0014,
23606 controlDEL: 0x007F,
23607 controlDLE: 0x0010,
23608 controlEM: 0x0019,
23609 controlENQ: 0x0005,
23610 controlEOT: 0x0004,
23611 controlESC: 0x001B,
23612 controlETB: 0x0017,
23613 controlETX: 0x0003,
23614 controlFF: 0x000C,
23615 controlFS: 0x001C,
23616 controlGS: 0x001D,
23617 controlHT: 0x0009,
23618 controlLF: 0x000A,
23619 controlNAK: 0x0015,
23620 controlRS: 0x001E,
23621 controlSI: 0x000F,
23622 controlSO: 0x000E,
23623 controlSOT: 0x0002,
23624 controlSTX: 0x0001,
23625 controlSUB: 0x001A,
23626 controlSYN: 0x0016,
23627 controlUS: 0x001F,
23628 controlVT: 0x000B,
23629 copyright: 0x00A9,
23630 copyrightsans: 0xF8E9,
23631 copyrightserif: 0xF6D9,
23632 cornerbracketleft: 0x300C,
23633 cornerbracketlefthalfwidth: 0xFF62,
23634 cornerbracketleftvertical: 0xFE41,
23635 cornerbracketright: 0x300D,
23636 cornerbracketrighthalfwidth: 0xFF63,
23637 cornerbracketrightvertical: 0xFE42,
23638 corporationsquare: 0x337F,
23639 cosquare: 0x33C7,
23640 coverkgsquare: 0x33C6,
23641 cparen: 0x249E,
23642 cruzeiro: 0x20A2,
23643 cstretched: 0x0297,
23644 curlyand: 0x22CF,
23645 curlyor: 0x22CE,
23646 currency: 0x00A4,
23647 cyrBreve: 0xF6D1,
23648 cyrFlex: 0xF6D2,
23649 cyrbreve: 0xF6D4,
23650 cyrflex: 0xF6D5,
23651 d: 0x0064,
23652 daarmenian: 0x0564,
23653 dabengali: 0x09A6,
23654 dadarabic: 0x0636,
23655 dadeva: 0x0926,
23656 dadfinalarabic: 0xFEBE,
23657 dadinitialarabic: 0xFEBF,
23658 dadmedialarabic: 0xFEC0,
23659 dagesh: 0x05BC,
23660 dageshhebrew: 0x05BC,
23661 dagger: 0x2020,
23662 daggerdbl: 0x2021,
23663 dagujarati: 0x0AA6,
23664 dagurmukhi: 0x0A26,
23665 dahiragana: 0x3060,
23666 dakatakana: 0x30C0,
23667 dalarabic: 0x062F,
23668 dalet: 0x05D3,
23669 daletdagesh: 0xFB33,
23670 daletdageshhebrew: 0xFB33,
23671 dalethebrew: 0x05D3,
23672 dalfinalarabic: 0xFEAA,
23673 dammaarabic: 0x064F,
23674 dammalowarabic: 0x064F,
23675 dammatanaltonearabic: 0x064C,
23676 dammatanarabic: 0x064C,
23677 danda: 0x0964,
23678 dargahebrew: 0x05A7,
23679 dargalefthebrew: 0x05A7,
23680 dasiapneumatacyrilliccmb: 0x0485,
23681 dblGrave: 0xF6D3,
23682 dblanglebracketleft: 0x300A,
23683 dblanglebracketleftvertical: 0xFE3D,
23684 dblanglebracketright: 0x300B,
23685 dblanglebracketrightvertical: 0xFE3E,
23686 dblarchinvertedbelowcmb: 0x032B,
23687 dblarrowleft: 0x21D4,
23688 dblarrowright: 0x21D2,
23689 dbldanda: 0x0965,
23690 dblgrave: 0xF6D6,
23691 dblgravecmb: 0x030F,
23692 dblintegral: 0x222C,
23693 dbllowline: 0x2017,
23694 dbllowlinecmb: 0x0333,
23695 dbloverlinecmb: 0x033F,
23696 dblprimemod: 0x02BA,
23697 dblverticalbar: 0x2016,
23698 dblverticallineabovecmb: 0x030E,
23699 dbopomofo: 0x3109,
23700 dbsquare: 0x33C8,
23701 dcaron: 0x010F,
23702 dcedilla: 0x1E11,
23703 dcircle: 0x24D3,
23704 dcircumflexbelow: 0x1E13,
23705 dcroat: 0x0111,
23706 ddabengali: 0x09A1,
23707 ddadeva: 0x0921,
23708 ddagujarati: 0x0AA1,
23709 ddagurmukhi: 0x0A21,
23710 ddalarabic: 0x0688,
23711 ddalfinalarabic: 0xFB89,
23712 dddhadeva: 0x095C,
23713 ddhabengali: 0x09A2,
23714 ddhadeva: 0x0922,
23715 ddhagujarati: 0x0AA2,
23716 ddhagurmukhi: 0x0A22,
23717 ddotaccent: 0x1E0B,
23718 ddotbelow: 0x1E0D,
23719 decimalseparatorarabic: 0x066B,
23720 decimalseparatorpersian: 0x066B,
23721 decyrillic: 0x0434,
23722 degree: 0x00B0,
23723 dehihebrew: 0x05AD,
23724 dehiragana: 0x3067,
23725 deicoptic: 0x03EF,
23726 dekatakana: 0x30C7,
23727 deleteleft: 0x232B,
23728 deleteright: 0x2326,
23729 delta: 0x03B4,
23730 deltaturned: 0x018D,
23731 denominatorminusonenumeratorbengali: 0x09F8,
23732 dezh: 0x02A4,
23733 dhabengali: 0x09A7,
23734 dhadeva: 0x0927,
23735 dhagujarati: 0x0AA7,
23736 dhagurmukhi: 0x0A27,
23737 dhook: 0x0257,
23738 dialytikatonos: 0x0385,
23739 dialytikatonoscmb: 0x0344,
23740 diamond: 0x2666,
23741 diamondsuitwhite: 0x2662,
23742 dieresis: 0x00A8,
23743 dieresisacute: 0xF6D7,
23744 dieresisbelowcmb: 0x0324,
23745 dieresiscmb: 0x0308,
23746 dieresisgrave: 0xF6D8,
23747 dieresistonos: 0x0385,
23748 dihiragana: 0x3062,
23749 dikatakana: 0x30C2,
23750 dittomark: 0x3003,
23751 divide: 0x00F7,
23752 divides: 0x2223,
23753 divisionslash: 0x2215,
23754 djecyrillic: 0x0452,
23755 dkshade: 0x2593,
23756 dlinebelow: 0x1E0F,
23757 dlsquare: 0x3397,
23758 dmacron: 0x0111,
23759 dmonospace: 0xFF44,
23760 dnblock: 0x2584,
23761 dochadathai: 0x0E0E,
23762 dodekthai: 0x0E14,
23763 dohiragana: 0x3069,
23764 dokatakana: 0x30C9,
23765 dollar: 0x0024,
23766 dollarinferior: 0xF6E3,
23767 dollarmonospace: 0xFF04,
23768 dollaroldstyle: 0xF724,
23769 dollarsmall: 0xFE69,
23770 dollarsuperior: 0xF6E4,
23771 dong: 0x20AB,
23772 dorusquare: 0x3326,
23773 dotaccent: 0x02D9,
23774 dotaccentcmb: 0x0307,
23775 dotbelowcmb: 0x0323,
23776 dotbelowcomb: 0x0323,
23777 dotkatakana: 0x30FB,
23778 dotlessi: 0x0131,
23779 dotlessj: 0xF6BE,
23780 dotlessjstrokehook: 0x0284,
23781 dotmath: 0x22C5,
23782 dottedcircle: 0x25CC,
23783 doubleyodpatah: 0xFB1F,
23784 doubleyodpatahhebrew: 0xFB1F,
23785 downtackbelowcmb: 0x031E,
23786 downtackmod: 0x02D5,
23787 dparen: 0x249F,
23788 dsuperior: 0xF6EB,
23789 dtail: 0x0256,
23790 dtopbar: 0x018C,
23791 duhiragana: 0x3065,
23792 dukatakana: 0x30C5,
23793 dz: 0x01F3,
23794 dzaltone: 0x02A3,
23795 dzcaron: 0x01C6,
23796 dzcurl: 0x02A5,
23797 dzeabkhasiancyrillic: 0x04E1,
23798 dzecyrillic: 0x0455,
23799 dzhecyrillic: 0x045F,
23800 e: 0x0065,
23801 eacute: 0x00E9,
23802 earth: 0x2641,
23803 ebengali: 0x098F,
23804 ebopomofo: 0x311C,
23805 ebreve: 0x0115,
23806 ecandradeva: 0x090D,
23807 ecandragujarati: 0x0A8D,
23808 ecandravowelsigndeva: 0x0945,
23809 ecandravowelsigngujarati: 0x0AC5,
23810 ecaron: 0x011B,
23811 ecedillabreve: 0x1E1D,
23812 echarmenian: 0x0565,
23813 echyiwnarmenian: 0x0587,
23814 ecircle: 0x24D4,
23815 ecircumflex: 0x00EA,
23816 ecircumflexacute: 0x1EBF,
23817 ecircumflexbelow: 0x1E19,
23818 ecircumflexdotbelow: 0x1EC7,
23819 ecircumflexgrave: 0x1EC1,
23820 ecircumflexhookabove: 0x1EC3,
23821 ecircumflextilde: 0x1EC5,
23822 ecyrillic: 0x0454,
23823 edblgrave: 0x0205,
23824 edeva: 0x090F,
23825 edieresis: 0x00EB,
23826 edot: 0x0117,
23827 edotaccent: 0x0117,
23828 edotbelow: 0x1EB9,
23829 eegurmukhi: 0x0A0F,
23830 eematragurmukhi: 0x0A47,
23831 efcyrillic: 0x0444,
23832 egrave: 0x00E8,
23833 egujarati: 0x0A8F,
23834 eharmenian: 0x0567,
23835 ehbopomofo: 0x311D,
23836 ehiragana: 0x3048,
23837 ehookabove: 0x1EBB,
23838 eibopomofo: 0x311F,
23839 eight: 0x0038,
23840 eightarabic: 0x0668,
23841 eightbengali: 0x09EE,
23842 eightcircle: 0x2467,
23843 eightcircleinversesansserif: 0x2791,
23844 eightdeva: 0x096E,
23845 eighteencircle: 0x2471,
23846 eighteenparen: 0x2485,
23847 eighteenperiod: 0x2499,
23848 eightgujarati: 0x0AEE,
23849 eightgurmukhi: 0x0A6E,
23850 eighthackarabic: 0x0668,
23851 eighthangzhou: 0x3028,
23852 eighthnotebeamed: 0x266B,
23853 eightideographicparen: 0x3227,
23854 eightinferior: 0x2088,
23855 eightmonospace: 0xFF18,
23856 eightoldstyle: 0xF738,
23857 eightparen: 0x247B,
23858 eightperiod: 0x248F,
23859 eightpersian: 0x06F8,
23860 eightroman: 0x2177,
23861 eightsuperior: 0x2078,
23862 eightthai: 0x0E58,
23863 einvertedbreve: 0x0207,
23864 eiotifiedcyrillic: 0x0465,
23865 ekatakana: 0x30A8,
23866 ekatakanahalfwidth: 0xFF74,
23867 ekonkargurmukhi: 0x0A74,
23868 ekorean: 0x3154,
23869 elcyrillic: 0x043B,
23870 element: 0x2208,
23871 elevencircle: 0x246A,
23872 elevenparen: 0x247E,
23873 elevenperiod: 0x2492,
23874 elevenroman: 0x217A,
23875 ellipsis: 0x2026,
23876 ellipsisvertical: 0x22EE,
23877 emacron: 0x0113,
23878 emacronacute: 0x1E17,
23879 emacrongrave: 0x1E15,
23880 emcyrillic: 0x043C,
23881 emdash: 0x2014,
23882 emdashvertical: 0xFE31,
23883 emonospace: 0xFF45,
23884 emphasismarkarmenian: 0x055B,
23885 emptyset: 0x2205,
23886 enbopomofo: 0x3123,
23887 encyrillic: 0x043D,
23888 endash: 0x2013,
23889 endashvertical: 0xFE32,
23890 endescendercyrillic: 0x04A3,
23891 eng: 0x014B,
23892 engbopomofo: 0x3125,
23893 enghecyrillic: 0x04A5,
23894 enhookcyrillic: 0x04C8,
23895 enspace: 0x2002,
23896 eogonek: 0x0119,
23897 eokorean: 0x3153,
23898 eopen: 0x025B,
23899 eopenclosed: 0x029A,
23900 eopenreversed: 0x025C,
23901 eopenreversedclosed: 0x025E,
23902 eopenreversedhook: 0x025D,
23903 eparen: 0x24A0,
23904 epsilon: 0x03B5,
23905 epsilontonos: 0x03AD,
23906 equal: 0x003D,
23907 equalmonospace: 0xFF1D,
23908 equalsmall: 0xFE66,
23909 equalsuperior: 0x207C,
23910 equivalence: 0x2261,
23911 erbopomofo: 0x3126,
23912 ercyrillic: 0x0440,
23913 ereversed: 0x0258,
23914 ereversedcyrillic: 0x044D,
23915 escyrillic: 0x0441,
23916 esdescendercyrillic: 0x04AB,
23917 esh: 0x0283,
23918 eshcurl: 0x0286,
23919 eshortdeva: 0x090E,
23920 eshortvowelsigndeva: 0x0946,
23921 eshreversedloop: 0x01AA,
23922 eshsquatreversed: 0x0285,
23923 esmallhiragana: 0x3047,
23924 esmallkatakana: 0x30A7,
23925 esmallkatakanahalfwidth: 0xFF6A,
23926 estimated: 0x212E,
23927 esuperior: 0xF6EC,
23928 eta: 0x03B7,
23929 etarmenian: 0x0568,
23930 etatonos: 0x03AE,
23931 eth: 0x00F0,
23932 etilde: 0x1EBD,
23933 etildebelow: 0x1E1B,
23934 etnahtafoukhhebrew: 0x0591,
23935 etnahtafoukhlefthebrew: 0x0591,
23936 etnahtahebrew: 0x0591,
23937 etnahtalefthebrew: 0x0591,
23938 eturned: 0x01DD,
23939 eukorean: 0x3161,
23940 euro: 0x20AC,
23941 evowelsignbengali: 0x09C7,
23942 evowelsigndeva: 0x0947,
23943 evowelsigngujarati: 0x0AC7,
23944 exclam: 0x0021,
23945 exclamarmenian: 0x055C,
23946 exclamdbl: 0x203C,
23947 exclamdown: 0x00A1,
23948 exclamdownsmall: 0xF7A1,
23949 exclammonospace: 0xFF01,
23950 exclamsmall: 0xF721,
23951 existential: 0x2203,
23952 ezh: 0x0292,
23953 ezhcaron: 0x01EF,
23954 ezhcurl: 0x0293,
23955 ezhreversed: 0x01B9,
23956 ezhtail: 0x01BA,
23957 f: 0x0066,
23958 fadeva: 0x095E,
23959 fagurmukhi: 0x0A5E,
23960 fahrenheit: 0x2109,
23961 fathaarabic: 0x064E,
23962 fathalowarabic: 0x064E,
23963 fathatanarabic: 0x064B,
23964 fbopomofo: 0x3108,
23965 fcircle: 0x24D5,
23966 fdotaccent: 0x1E1F,
23967 feharabic: 0x0641,
23968 feharmenian: 0x0586,
23969 fehfinalarabic: 0xFED2,
23970 fehinitialarabic: 0xFED3,
23971 fehmedialarabic: 0xFED4,
23972 feicoptic: 0x03E5,
23973 female: 0x2640,
23974 ff: 0xFB00,
23975 ffi: 0xFB03,
23976 ffl: 0xFB04,
23977 fi: 0xFB01,
23978 fifteencircle: 0x246E,
23979 fifteenparen: 0x2482,
23980 fifteenperiod: 0x2496,
23981 figuredash: 0x2012,
23982 filledbox: 0x25A0,
23983 filledrect: 0x25AC,
23984 finalkaf: 0x05DA,
23985 finalkafdagesh: 0xFB3A,
23986 finalkafdageshhebrew: 0xFB3A,
23987 finalkafhebrew: 0x05DA,
23988 finalmem: 0x05DD,
23989 finalmemhebrew: 0x05DD,
23990 finalnun: 0x05DF,
23991 finalnunhebrew: 0x05DF,
23992 finalpe: 0x05E3,
23993 finalpehebrew: 0x05E3,
23994 finaltsadi: 0x05E5,
23995 finaltsadihebrew: 0x05E5,
23996 firsttonechinese: 0x02C9,
23997 fisheye: 0x25C9,
23998 fitacyrillic: 0x0473,
23999 five: 0x0035,
24000 fivearabic: 0x0665,
24001 fivebengali: 0x09EB,
24002 fivecircle: 0x2464,
24003 fivecircleinversesansserif: 0x278E,
24004 fivedeva: 0x096B,
24005 fiveeighths: 0x215D,
24006 fivegujarati: 0x0AEB,
24007 fivegurmukhi: 0x0A6B,
24008 fivehackarabic: 0x0665,
24009 fivehangzhou: 0x3025,
24010 fiveideographicparen: 0x3224,
24011 fiveinferior: 0x2085,
24012 fivemonospace: 0xFF15,
24013 fiveoldstyle: 0xF735,
24014 fiveparen: 0x2478,
24015 fiveperiod: 0x248C,
24016 fivepersian: 0x06F5,
24017 fiveroman: 0x2174,
24018 fivesuperior: 0x2075,
24019 fivethai: 0x0E55,
24020 fl: 0xFB02,
24021 florin: 0x0192,
24022 fmonospace: 0xFF46,
24023 fmsquare: 0x3399,
24024 fofanthai: 0x0E1F,
24025 fofathai: 0x0E1D,
24026 fongmanthai: 0x0E4F,
24027 forall: 0x2200,
24028 four: 0x0034,
24029 fourarabic: 0x0664,
24030 fourbengali: 0x09EA,
24031 fourcircle: 0x2463,
24032 fourcircleinversesansserif: 0x278D,
24033 fourdeva: 0x096A,
24034 fourgujarati: 0x0AEA,
24035 fourgurmukhi: 0x0A6A,
24036 fourhackarabic: 0x0664,
24037 fourhangzhou: 0x3024,
24038 fourideographicparen: 0x3223,
24039 fourinferior: 0x2084,
24040 fourmonospace: 0xFF14,
24041 fournumeratorbengali: 0x09F7,
24042 fouroldstyle: 0xF734,
24043 fourparen: 0x2477,
24044 fourperiod: 0x248B,
24045 fourpersian: 0x06F4,
24046 fourroman: 0x2173,
24047 foursuperior: 0x2074,
24048 fourteencircle: 0x246D,
24049 fourteenparen: 0x2481,
24050 fourteenperiod: 0x2495,
24051 fourthai: 0x0E54,
24052 fourthtonechinese: 0x02CB,
24053 fparen: 0x24A1,
24054 fraction: 0x2044,
24055 franc: 0x20A3,
24056 g: 0x0067,
24057 gabengali: 0x0997,
24058 gacute: 0x01F5,
24059 gadeva: 0x0917,
24060 gafarabic: 0x06AF,
24061 gaffinalarabic: 0xFB93,
24062 gafinitialarabic: 0xFB94,
24063 gafmedialarabic: 0xFB95,
24064 gagujarati: 0x0A97,
24065 gagurmukhi: 0x0A17,
24066 gahiragana: 0x304C,
24067 gakatakana: 0x30AC,
24068 gamma: 0x03B3,
24069 gammalatinsmall: 0x0263,
24070 gammasuperior: 0x02E0,
24071 gangiacoptic: 0x03EB,
24072 gbopomofo: 0x310D,
24073 gbreve: 0x011F,
24074 gcaron: 0x01E7,
24075 gcedilla: 0x0123,
24076 gcircle: 0x24D6,
24077 gcircumflex: 0x011D,
24078 gcommaaccent: 0x0123,
24079 gdot: 0x0121,
24080 gdotaccent: 0x0121,
24081 gecyrillic: 0x0433,
24082 gehiragana: 0x3052,
24083 gekatakana: 0x30B2,
24084 geometricallyequal: 0x2251,
24085 gereshaccenthebrew: 0x059C,
24086 gereshhebrew: 0x05F3,
24087 gereshmuqdamhebrew: 0x059D,
24088 germandbls: 0x00DF,
24089 gershayimaccenthebrew: 0x059E,
24090 gershayimhebrew: 0x05F4,
24091 getamark: 0x3013,
24092 ghabengali: 0x0998,
24093 ghadarmenian: 0x0572,
24094 ghadeva: 0x0918,
24095 ghagujarati: 0x0A98,
24096 ghagurmukhi: 0x0A18,
24097 ghainarabic: 0x063A,
24098 ghainfinalarabic: 0xFECE,
24099 ghaininitialarabic: 0xFECF,
24100 ghainmedialarabic: 0xFED0,
24101 ghemiddlehookcyrillic: 0x0495,
24102 ghestrokecyrillic: 0x0493,
24103 gheupturncyrillic: 0x0491,
24104 ghhadeva: 0x095A,
24105 ghhagurmukhi: 0x0A5A,
24106 ghook: 0x0260,
24107 ghzsquare: 0x3393,
24108 gihiragana: 0x304E,
24109 gikatakana: 0x30AE,
24110 gimarmenian: 0x0563,
24111 gimel: 0x05D2,
24112 gimeldagesh: 0xFB32,
24113 gimeldageshhebrew: 0xFB32,
24114 gimelhebrew: 0x05D2,
24115 gjecyrillic: 0x0453,
24116 glottalinvertedstroke: 0x01BE,
24117 glottalstop: 0x0294,
24118 glottalstopinverted: 0x0296,
24119 glottalstopmod: 0x02C0,
24120 glottalstopreversed: 0x0295,
24121 glottalstopreversedmod: 0x02C1,
24122 glottalstopreversedsuperior: 0x02E4,
24123 glottalstopstroke: 0x02A1,
24124 glottalstopstrokereversed: 0x02A2,
24125 gmacron: 0x1E21,
24126 gmonospace: 0xFF47,
24127 gohiragana: 0x3054,
24128 gokatakana: 0x30B4,
24129 gparen: 0x24A2,
24130 gpasquare: 0x33AC,
24131 gradient: 0x2207,
24132 grave: 0x0060,
24133 gravebelowcmb: 0x0316,
24134 gravecmb: 0x0300,
24135 gravecomb: 0x0300,
24136 gravedeva: 0x0953,
24137 gravelowmod: 0x02CE,
24138 gravemonospace: 0xFF40,
24139 gravetonecmb: 0x0340,
24140 greater: 0x003E,
24141 greaterequal: 0x2265,
24142 greaterequalorless: 0x22DB,
24143 greatermonospace: 0xFF1E,
24144 greaterorequivalent: 0x2273,
24145 greaterorless: 0x2277,
24146 greateroverequal: 0x2267,
24147 greatersmall: 0xFE65,
24148 gscript: 0x0261,
24149 gstroke: 0x01E5,
24150 guhiragana: 0x3050,
24151 guillemotleft: 0x00AB,
24152 guillemotright: 0x00BB,
24153 guilsinglleft: 0x2039,
24154 guilsinglright: 0x203A,
24155 gukatakana: 0x30B0,
24156 guramusquare: 0x3318,
24157 gysquare: 0x33C9,
24158 h: 0x0068,
24159 haabkhasiancyrillic: 0x04A9,
24160 haaltonearabic: 0x06C1,
24161 habengali: 0x09B9,
24162 hadescendercyrillic: 0x04B3,
24163 hadeva: 0x0939,
24164 hagujarati: 0x0AB9,
24165 hagurmukhi: 0x0A39,
24166 haharabic: 0x062D,
24167 hahfinalarabic: 0xFEA2,
24168 hahinitialarabic: 0xFEA3,
24169 hahiragana: 0x306F,
24170 hahmedialarabic: 0xFEA4,
24171 haitusquare: 0x332A,
24172 hakatakana: 0x30CF,
24173 hakatakanahalfwidth: 0xFF8A,
24174 halantgurmukhi: 0x0A4D,
24175 hamzaarabic: 0x0621,
24176 hamzalowarabic: 0x0621,
24177 hangulfiller: 0x3164,
24178 hardsigncyrillic: 0x044A,
24179 harpoonleftbarbup: 0x21BC,
24180 harpoonrightbarbup: 0x21C0,
24181 hasquare: 0x33CA,
24182 hatafpatah: 0x05B2,
24183 hatafpatah16: 0x05B2,
24184 hatafpatah23: 0x05B2,
24185 hatafpatah2f: 0x05B2,
24186 hatafpatahhebrew: 0x05B2,
24187 hatafpatahnarrowhebrew: 0x05B2,
24188 hatafpatahquarterhebrew: 0x05B2,
24189 hatafpatahwidehebrew: 0x05B2,
24190 hatafqamats: 0x05B3,
24191 hatafqamats1b: 0x05B3,
24192 hatafqamats28: 0x05B3,
24193 hatafqamats34: 0x05B3,
24194 hatafqamatshebrew: 0x05B3,
24195 hatafqamatsnarrowhebrew: 0x05B3,
24196 hatafqamatsquarterhebrew: 0x05B3,
24197 hatafqamatswidehebrew: 0x05B3,
24198 hatafsegol: 0x05B1,
24199 hatafsegol17: 0x05B1,
24200 hatafsegol24: 0x05B1,
24201 hatafsegol30: 0x05B1,
24202 hatafsegolhebrew: 0x05B1,
24203 hatafsegolnarrowhebrew: 0x05B1,
24204 hatafsegolquarterhebrew: 0x05B1,
24205 hatafsegolwidehebrew: 0x05B1,
24206 hbar: 0x0127,
24207 hbopomofo: 0x310F,
24208 hbrevebelow: 0x1E2B,
24209 hcedilla: 0x1E29,
24210 hcircle: 0x24D7,
24211 hcircumflex: 0x0125,
24212 hdieresis: 0x1E27,
24213 hdotaccent: 0x1E23,
24214 hdotbelow: 0x1E25,
24215 he: 0x05D4,
24216 heart: 0x2665,
24217 heartsuitblack: 0x2665,
24218 heartsuitwhite: 0x2661,
24219 hedagesh: 0xFB34,
24220 hedageshhebrew: 0xFB34,
24221 hehaltonearabic: 0x06C1,
24222 heharabic: 0x0647,
24223 hehebrew: 0x05D4,
24224 hehfinalaltonearabic: 0xFBA7,
24225 hehfinalalttwoarabic: 0xFEEA,
24226 hehfinalarabic: 0xFEEA,
24227 hehhamzaabovefinalarabic: 0xFBA5,
24228 hehhamzaaboveisolatedarabic: 0xFBA4,
24229 hehinitialaltonearabic: 0xFBA8,
24230 hehinitialarabic: 0xFEEB,
24231 hehiragana: 0x3078,
24232 hehmedialaltonearabic: 0xFBA9,
24233 hehmedialarabic: 0xFEEC,
24234 heiseierasquare: 0x337B,
24235 hekatakana: 0x30D8,
24236 hekatakanahalfwidth: 0xFF8D,
24237 hekutaarusquare: 0x3336,
24238 henghook: 0x0267,
24239 herutusquare: 0x3339,
24240 het: 0x05D7,
24241 hethebrew: 0x05D7,
24242 hhook: 0x0266,
24243 hhooksuperior: 0x02B1,
24244 hieuhacirclekorean: 0x327B,
24245 hieuhaparenkorean: 0x321B,
24246 hieuhcirclekorean: 0x326D,
24247 hieuhkorean: 0x314E,
24248 hieuhparenkorean: 0x320D,
24249 hihiragana: 0x3072,
24250 hikatakana: 0x30D2,
24251 hikatakanahalfwidth: 0xFF8B,
24252 hiriq: 0x05B4,
24253 hiriq14: 0x05B4,
24254 hiriq21: 0x05B4,
24255 hiriq2d: 0x05B4,
24256 hiriqhebrew: 0x05B4,
24257 hiriqnarrowhebrew: 0x05B4,
24258 hiriqquarterhebrew: 0x05B4,
24259 hiriqwidehebrew: 0x05B4,
24260 hlinebelow: 0x1E96,
24261 hmonospace: 0xFF48,
24262 hoarmenian: 0x0570,
24263 hohipthai: 0x0E2B,
24264 hohiragana: 0x307B,
24265 hokatakana: 0x30DB,
24266 hokatakanahalfwidth: 0xFF8E,
24267 holam: 0x05B9,
24268 holam19: 0x05B9,
24269 holam26: 0x05B9,
24270 holam32: 0x05B9,
24271 holamhebrew: 0x05B9,
24272 holamnarrowhebrew: 0x05B9,
24273 holamquarterhebrew: 0x05B9,
24274 holamwidehebrew: 0x05B9,
24275 honokhukthai: 0x0E2E,
24276 hookabovecomb: 0x0309,
24277 hookcmb: 0x0309,
24278 hookpalatalizedbelowcmb: 0x0321,
24279 hookretroflexbelowcmb: 0x0322,
24280 hoonsquare: 0x3342,
24281 horicoptic: 0x03E9,
24282 horizontalbar: 0x2015,
24283 horncmb: 0x031B,
24284 hotsprings: 0x2668,
24285 house: 0x2302,
24286 hparen: 0x24A3,
24287 hsuperior: 0x02B0,
24288 hturned: 0x0265,
24289 huhiragana: 0x3075,
24290 huiitosquare: 0x3333,
24291 hukatakana: 0x30D5,
24292 hukatakanahalfwidth: 0xFF8C,
24293 hungarumlaut: 0x02DD,
24294 hungarumlautcmb: 0x030B,
24295 hv: 0x0195,
24296 hyphen: 0x002D,
24297 hypheninferior: 0xF6E5,
24298 hyphenmonospace: 0xFF0D,
24299 hyphensmall: 0xFE63,
24300 hyphensuperior: 0xF6E6,
24301 hyphentwo: 0x2010,
24302 i: 0x0069,
24303 iacute: 0x00ED,
24304 iacyrillic: 0x044F,
24305 ibengali: 0x0987,
24306 ibopomofo: 0x3127,
24307 ibreve: 0x012D,
24308 icaron: 0x01D0,
24309 icircle: 0x24D8,
24310 icircumflex: 0x00EE,
24311 icyrillic: 0x0456,
24312 idblgrave: 0x0209,
24313 ideographearthcircle: 0x328F,
24314 ideographfirecircle: 0x328B,
24315 ideographicallianceparen: 0x323F,
24316 ideographiccallparen: 0x323A,
24317 ideographiccentrecircle: 0x32A5,
24318 ideographicclose: 0x3006,
24319 ideographiccomma: 0x3001,
24320 ideographiccommaleft: 0xFF64,
24321 ideographiccongratulationparen: 0x3237,
24322 ideographiccorrectcircle: 0x32A3,
24323 ideographicearthparen: 0x322F,
24324 ideographicenterpriseparen: 0x323D,
24325 ideographicexcellentcircle: 0x329D,
24326 ideographicfestivalparen: 0x3240,
24327 ideographicfinancialcircle: 0x3296,
24328 ideographicfinancialparen: 0x3236,
24329 ideographicfireparen: 0x322B,
24330 ideographichaveparen: 0x3232,
24331 ideographichighcircle: 0x32A4,
24332 ideographiciterationmark: 0x3005,
24333 ideographiclaborcircle: 0x3298,
24334 ideographiclaborparen: 0x3238,
24335 ideographicleftcircle: 0x32A7,
24336 ideographiclowcircle: 0x32A6,
24337 ideographicmedicinecircle: 0x32A9,
24338 ideographicmetalparen: 0x322E,
24339 ideographicmoonparen: 0x322A,
24340 ideographicnameparen: 0x3234,
24341 ideographicperiod: 0x3002,
24342 ideographicprintcircle: 0x329E,
24343 ideographicreachparen: 0x3243,
24344 ideographicrepresentparen: 0x3239,
24345 ideographicresourceparen: 0x323E,
24346 ideographicrightcircle: 0x32A8,
24347 ideographicsecretcircle: 0x3299,
24348 ideographicselfparen: 0x3242,
24349 ideographicsocietyparen: 0x3233,
24350 ideographicspace: 0x3000,
24351 ideographicspecialparen: 0x3235,
24352 ideographicstockparen: 0x3231,
24353 ideographicstudyparen: 0x323B,
24354 ideographicsunparen: 0x3230,
24355 ideographicsuperviseparen: 0x323C,
24356 ideographicwaterparen: 0x322C,
24357 ideographicwoodparen: 0x322D,
24358 ideographiczero: 0x3007,
24359 ideographmetalcircle: 0x328E,
24360 ideographmooncircle: 0x328A,
24361 ideographnamecircle: 0x3294,
24362 ideographsuncircle: 0x3290,
24363 ideographwatercircle: 0x328C,
24364 ideographwoodcircle: 0x328D,
24365 ideva: 0x0907,
24366 idieresis: 0x00EF,
24367 idieresisacute: 0x1E2F,
24368 idieresiscyrillic: 0x04E5,
24369 idotbelow: 0x1ECB,
24370 iebrevecyrillic: 0x04D7,
24371 iecyrillic: 0x0435,
24372 ieungacirclekorean: 0x3275,
24373 ieungaparenkorean: 0x3215,
24374 ieungcirclekorean: 0x3267,
24375 ieungkorean: 0x3147,
24376 ieungparenkorean: 0x3207,
24377 igrave: 0x00EC,
24378 igujarati: 0x0A87,
24379 igurmukhi: 0x0A07,
24380 ihiragana: 0x3044,
24381 ihookabove: 0x1EC9,
24382 iibengali: 0x0988,
24383 iicyrillic: 0x0438,
24384 iideva: 0x0908,
24385 iigujarati: 0x0A88,
24386 iigurmukhi: 0x0A08,
24387 iimatragurmukhi: 0x0A40,
24388 iinvertedbreve: 0x020B,
24389 iishortcyrillic: 0x0439,
24390 iivowelsignbengali: 0x09C0,
24391 iivowelsigndeva: 0x0940,
24392 iivowelsigngujarati: 0x0AC0,
24393 ij: 0x0133,
24394 ikatakana: 0x30A4,
24395 ikatakanahalfwidth: 0xFF72,
24396 ikorean: 0x3163,
24397 ilde: 0x02DC,
24398 iluyhebrew: 0x05AC,
24399 imacron: 0x012B,
24400 imacroncyrillic: 0x04E3,
24401 imageorapproximatelyequal: 0x2253,
24402 imatragurmukhi: 0x0A3F,
24403 imonospace: 0xFF49,
24404 increment: 0x2206,
24405 infinity: 0x221E,
24406 iniarmenian: 0x056B,
24407 integral: 0x222B,
24408 integralbottom: 0x2321,
24409 integralbt: 0x2321,
24410 integralex: 0xF8F5,
24411 integraltop: 0x2320,
24412 integraltp: 0x2320,
24413 intersection: 0x2229,
24414 intisquare: 0x3305,
24415 invbullet: 0x25D8,
24416 invcircle: 0x25D9,
24417 invsmileface: 0x263B,
24418 iocyrillic: 0x0451,
24419 iogonek: 0x012F,
24420 iota: 0x03B9,
24421 iotadieresis: 0x03CA,
24422 iotadieresistonos: 0x0390,
24423 iotalatin: 0x0269,
24424 iotatonos: 0x03AF,
24425 iparen: 0x24A4,
24426 irigurmukhi: 0x0A72,
24427 ismallhiragana: 0x3043,
24428 ismallkatakana: 0x30A3,
24429 ismallkatakanahalfwidth: 0xFF68,
24430 issharbengali: 0x09FA,
24431 istroke: 0x0268,
24432 isuperior: 0xF6ED,
24433 iterationhiragana: 0x309D,
24434 iterationkatakana: 0x30FD,
24435 itilde: 0x0129,
24436 itildebelow: 0x1E2D,
24437 iubopomofo: 0x3129,
24438 iucyrillic: 0x044E,
24439 ivowelsignbengali: 0x09BF,
24440 ivowelsigndeva: 0x093F,
24441 ivowelsigngujarati: 0x0ABF,
24442 izhitsacyrillic: 0x0475,
24443 izhitsadblgravecyrillic: 0x0477,
24444 j: 0x006A,
24445 jaarmenian: 0x0571,
24446 jabengali: 0x099C,
24447 jadeva: 0x091C,
24448 jagujarati: 0x0A9C,
24449 jagurmukhi: 0x0A1C,
24450 jbopomofo: 0x3110,
24451 jcaron: 0x01F0,
24452 jcircle: 0x24D9,
24453 jcircumflex: 0x0135,
24454 jcrossedtail: 0x029D,
24455 jdotlessstroke: 0x025F,
24456 jecyrillic: 0x0458,
24457 jeemarabic: 0x062C,
24458 jeemfinalarabic: 0xFE9E,
24459 jeeminitialarabic: 0xFE9F,
24460 jeemmedialarabic: 0xFEA0,
24461 jeharabic: 0x0698,
24462 jehfinalarabic: 0xFB8B,
24463 jhabengali: 0x099D,
24464 jhadeva: 0x091D,
24465 jhagujarati: 0x0A9D,
24466 jhagurmukhi: 0x0A1D,
24467 jheharmenian: 0x057B,
24468 jis: 0x3004,
24469 jmonospace: 0xFF4A,
24470 jparen: 0x24A5,
24471 jsuperior: 0x02B2,
24472 k: 0x006B,
24473 kabashkircyrillic: 0x04A1,
24474 kabengali: 0x0995,
24475 kacute: 0x1E31,
24476 kacyrillic: 0x043A,
24477 kadescendercyrillic: 0x049B,
24478 kadeva: 0x0915,
24479 kaf: 0x05DB,
24480 kafarabic: 0x0643,
24481 kafdagesh: 0xFB3B,
24482 kafdageshhebrew: 0xFB3B,
24483 kaffinalarabic: 0xFEDA,
24484 kafhebrew: 0x05DB,
24485 kafinitialarabic: 0xFEDB,
24486 kafmedialarabic: 0xFEDC,
24487 kafrafehebrew: 0xFB4D,
24488 kagujarati: 0x0A95,
24489 kagurmukhi: 0x0A15,
24490 kahiragana: 0x304B,
24491 kahookcyrillic: 0x04C4,
24492 kakatakana: 0x30AB,
24493 kakatakanahalfwidth: 0xFF76,
24494 kappa: 0x03BA,
24495 kappasymbolgreek: 0x03F0,
24496 kapyeounmieumkorean: 0x3171,
24497 kapyeounphieuphkorean: 0x3184,
24498 kapyeounpieupkorean: 0x3178,
24499 kapyeounssangpieupkorean: 0x3179,
24500 karoriisquare: 0x330D,
24501 kashidaautoarabic: 0x0640,
24502 kashidaautonosidebearingarabic: 0x0640,
24503 kasmallkatakana: 0x30F5,
24504 kasquare: 0x3384,
24505 kasraarabic: 0x0650,
24506 kasratanarabic: 0x064D,
24507 kastrokecyrillic: 0x049F,
24508 katahiraprolongmarkhalfwidth: 0xFF70,
24509 kaverticalstrokecyrillic: 0x049D,
24510 kbopomofo: 0x310E,
24511 kcalsquare: 0x3389,
24512 kcaron: 0x01E9,
24513 kcedilla: 0x0137,
24514 kcircle: 0x24DA,
24515 kcommaaccent: 0x0137,
24516 kdotbelow: 0x1E33,
24517 keharmenian: 0x0584,
24518 kehiragana: 0x3051,
24519 kekatakana: 0x30B1,
24520 kekatakanahalfwidth: 0xFF79,
24521 kenarmenian: 0x056F,
24522 kesmallkatakana: 0x30F6,
24523 kgreenlandic: 0x0138,
24524 khabengali: 0x0996,
24525 khacyrillic: 0x0445,
24526 khadeva: 0x0916,
24527 khagujarati: 0x0A96,
24528 khagurmukhi: 0x0A16,
24529 khaharabic: 0x062E,
24530 khahfinalarabic: 0xFEA6,
24531 khahinitialarabic: 0xFEA7,
24532 khahmedialarabic: 0xFEA8,
24533 kheicoptic: 0x03E7,
24534 khhadeva: 0x0959,
24535 khhagurmukhi: 0x0A59,
24536 khieukhacirclekorean: 0x3278,
24537 khieukhaparenkorean: 0x3218,
24538 khieukhcirclekorean: 0x326A,
24539 khieukhkorean: 0x314B,
24540 khieukhparenkorean: 0x320A,
24541 khokhaithai: 0x0E02,
24542 khokhonthai: 0x0E05,
24543 khokhuatthai: 0x0E03,
24544 khokhwaithai: 0x0E04,
24545 khomutthai: 0x0E5B,
24546 khook: 0x0199,
24547 khorakhangthai: 0x0E06,
24548 khzsquare: 0x3391,
24549 kihiragana: 0x304D,
24550 kikatakana: 0x30AD,
24551 kikatakanahalfwidth: 0xFF77,
24552 kiroguramusquare: 0x3315,
24553 kiromeetorusquare: 0x3316,
24554 kirosquare: 0x3314,
24555 kiyeokacirclekorean: 0x326E,
24556 kiyeokaparenkorean: 0x320E,
24557 kiyeokcirclekorean: 0x3260,
24558 kiyeokkorean: 0x3131,
24559 kiyeokparenkorean: 0x3200,
24560 kiyeoksioskorean: 0x3133,
24561 kjecyrillic: 0x045C,
24562 klinebelow: 0x1E35,
24563 klsquare: 0x3398,
24564 kmcubedsquare: 0x33A6,
24565 kmonospace: 0xFF4B,
24566 kmsquaredsquare: 0x33A2,
24567 kohiragana: 0x3053,
24568 kohmsquare: 0x33C0,
24569 kokaithai: 0x0E01,
24570 kokatakana: 0x30B3,
24571 kokatakanahalfwidth: 0xFF7A,
24572 kooposquare: 0x331E,
24573 koppacyrillic: 0x0481,
24574 koreanstandardsymbol: 0x327F,
24575 koroniscmb: 0x0343,
24576 kparen: 0x24A6,
24577 kpasquare: 0x33AA,
24578 ksicyrillic: 0x046F,
24579 ktsquare: 0x33CF,
24580 kturned: 0x029E,
24581 kuhiragana: 0x304F,
24582 kukatakana: 0x30AF,
24583 kukatakanahalfwidth: 0xFF78,
24584 kvsquare: 0x33B8,
24585 kwsquare: 0x33BE,
24586 l: 0x006C,
24587 labengali: 0x09B2,
24588 lacute: 0x013A,
24589 ladeva: 0x0932,
24590 lagujarati: 0x0AB2,
24591 lagurmukhi: 0x0A32,
24592 lakkhangyaothai: 0x0E45,
24593 lamaleffinalarabic: 0xFEFC,
24594 lamalefhamzaabovefinalarabic: 0xFEF8,
24595 lamalefhamzaaboveisolatedarabic: 0xFEF7,
24596 lamalefhamzabelowfinalarabic: 0xFEFA,
24597 lamalefhamzabelowisolatedarabic: 0xFEF9,
24598 lamalefisolatedarabic: 0xFEFB,
24599 lamalefmaddaabovefinalarabic: 0xFEF6,
24600 lamalefmaddaaboveisolatedarabic: 0xFEF5,
24601 lamarabic: 0x0644,
24602 lambda: 0x03BB,
24603 lambdastroke: 0x019B,
24604 lamed: 0x05DC,
24605 lameddagesh: 0xFB3C,
24606 lameddageshhebrew: 0xFB3C,
24607 lamedhebrew: 0x05DC,
24608 lamfinalarabic: 0xFEDE,
24609 lamhahinitialarabic: 0xFCCA,
24610 laminitialarabic: 0xFEDF,
24611 lamjeeminitialarabic: 0xFCC9,
24612 lamkhahinitialarabic: 0xFCCB,
24613 lamlamhehisolatedarabic: 0xFDF2,
24614 lammedialarabic: 0xFEE0,
24615 lammeemhahinitialarabic: 0xFD88,
24616 lammeeminitialarabic: 0xFCCC,
24617 largecircle: 0x25EF,
24618 lbar: 0x019A,
24619 lbelt: 0x026C,
24620 lbopomofo: 0x310C,
24621 lcaron: 0x013E,
24622 lcedilla: 0x013C,
24623 lcircle: 0x24DB,
24624 lcircumflexbelow: 0x1E3D,
24625 lcommaaccent: 0x013C,
24626 ldot: 0x0140,
24627 ldotaccent: 0x0140,
24628 ldotbelow: 0x1E37,
24629 ldotbelowmacron: 0x1E39,
24630 leftangleabovecmb: 0x031A,
24631 lefttackbelowcmb: 0x0318,
24632 less: 0x003C,
24633 lessequal: 0x2264,
24634 lessequalorgreater: 0x22DA,
24635 lessmonospace: 0xFF1C,
24636 lessorequivalent: 0x2272,
24637 lessorgreater: 0x2276,
24638 lessoverequal: 0x2266,
24639 lesssmall: 0xFE64,
24640 lezh: 0x026E,
24641 lfblock: 0x258C,
24642 lhookretroflex: 0x026D,
24643 lira: 0x20A4,
24644 liwnarmenian: 0x056C,
24645 lj: 0x01C9,
24646 ljecyrillic: 0x0459,
24647 ll: 0xF6C0,
24648 lladeva: 0x0933,
24649 llagujarati: 0x0AB3,
24650 llinebelow: 0x1E3B,
24651 llladeva: 0x0934,
24652 llvocalicbengali: 0x09E1,
24653 llvocalicdeva: 0x0961,
24654 llvocalicvowelsignbengali: 0x09E3,
24655 llvocalicvowelsigndeva: 0x0963,
24656 lmiddletilde: 0x026B,
24657 lmonospace: 0xFF4C,
24658 lmsquare: 0x33D0,
24659 lochulathai: 0x0E2C,
24660 logicaland: 0x2227,
24661 logicalnot: 0x00AC,
24662 logicalnotreversed: 0x2310,
24663 logicalor: 0x2228,
24664 lolingthai: 0x0E25,
24665 longs: 0x017F,
24666 lowlinecenterline: 0xFE4E,
24667 lowlinecmb: 0x0332,
24668 lowlinedashed: 0xFE4D,
24669 lozenge: 0x25CA,
24670 lparen: 0x24A7,
24671 lslash: 0x0142,
24672 lsquare: 0x2113,
24673 lsuperior: 0xF6EE,
24674 ltshade: 0x2591,
24675 luthai: 0x0E26,
24676 lvocalicbengali: 0x098C,
24677 lvocalicdeva: 0x090C,
24678 lvocalicvowelsignbengali: 0x09E2,
24679 lvocalicvowelsigndeva: 0x0962,
24680 lxsquare: 0x33D3,
24681 m: 0x006D,
24682 mabengali: 0x09AE,
24683 macron: 0x00AF,
24684 macronbelowcmb: 0x0331,
24685 macroncmb: 0x0304,
24686 macronlowmod: 0x02CD,
24687 macronmonospace: 0xFFE3,
24688 macute: 0x1E3F,
24689 madeva: 0x092E,
24690 magujarati: 0x0AAE,
24691 magurmukhi: 0x0A2E,
24692 mahapakhhebrew: 0x05A4,
24693 mahapakhlefthebrew: 0x05A4,
24694 mahiragana: 0x307E,
24695 maichattawalowleftthai: 0xF895,
24696 maichattawalowrightthai: 0xF894,
24697 maichattawathai: 0x0E4B,
24698 maichattawaupperleftthai: 0xF893,
24699 maieklowleftthai: 0xF88C,
24700 maieklowrightthai: 0xF88B,
24701 maiekthai: 0x0E48,
24702 maiekupperleftthai: 0xF88A,
24703 maihanakatleftthai: 0xF884,
24704 maihanakatthai: 0x0E31,
24705 maitaikhuleftthai: 0xF889,
24706 maitaikhuthai: 0x0E47,
24707 maitholowleftthai: 0xF88F,
24708 maitholowrightthai: 0xF88E,
24709 maithothai: 0x0E49,
24710 maithoupperleftthai: 0xF88D,
24711 maitrilowleftthai: 0xF892,
24712 maitrilowrightthai: 0xF891,
24713 maitrithai: 0x0E4A,
24714 maitriupperleftthai: 0xF890,
24715 maiyamokthai: 0x0E46,
24716 makatakana: 0x30DE,
24717 makatakanahalfwidth: 0xFF8F,
24718 male: 0x2642,
24719 mansyonsquare: 0x3347,
24720 maqafhebrew: 0x05BE,
24721 mars: 0x2642,
24722 masoracirclehebrew: 0x05AF,
24723 masquare: 0x3383,
24724 mbopomofo: 0x3107,
24725 mbsquare: 0x33D4,
24726 mcircle: 0x24DC,
24727 mcubedsquare: 0x33A5,
24728 mdotaccent: 0x1E41,
24729 mdotbelow: 0x1E43,
24730 meemarabic: 0x0645,
24731 meemfinalarabic: 0xFEE2,
24732 meeminitialarabic: 0xFEE3,
24733 meemmedialarabic: 0xFEE4,
24734 meemmeeminitialarabic: 0xFCD1,
24735 meemmeemisolatedarabic: 0xFC48,
24736 meetorusquare: 0x334D,
24737 mehiragana: 0x3081,
24738 meizierasquare: 0x337E,
24739 mekatakana: 0x30E1,
24740 mekatakanahalfwidth: 0xFF92,
24741 mem: 0x05DE,
24742 memdagesh: 0xFB3E,
24743 memdageshhebrew: 0xFB3E,
24744 memhebrew: 0x05DE,
24745 menarmenian: 0x0574,
24746 merkhahebrew: 0x05A5,
24747 merkhakefulahebrew: 0x05A6,
24748 merkhakefulalefthebrew: 0x05A6,
24749 merkhalefthebrew: 0x05A5,
24750 mhook: 0x0271,
24751 mhzsquare: 0x3392,
24752 middledotkatakanahalfwidth: 0xFF65,
24753 middot: 0x00B7,
24754 mieumacirclekorean: 0x3272,
24755 mieumaparenkorean: 0x3212,
24756 mieumcirclekorean: 0x3264,
24757 mieumkorean: 0x3141,
24758 mieumpansioskorean: 0x3170,
24759 mieumparenkorean: 0x3204,
24760 mieumpieupkorean: 0x316E,
24761 mieumsioskorean: 0x316F,
24762 mihiragana: 0x307F,
24763 mikatakana: 0x30DF,
24764 mikatakanahalfwidth: 0xFF90,
24765 minus: 0x2212,
24766 minusbelowcmb: 0x0320,
24767 minuscircle: 0x2296,
24768 minusmod: 0x02D7,
24769 minusplus: 0x2213,
24770 minute: 0x2032,
24771 miribaarusquare: 0x334A,
24772 mirisquare: 0x3349,
24773 mlonglegturned: 0x0270,
24774 mlsquare: 0x3396,
24775 mmcubedsquare: 0x33A3,
24776 mmonospace: 0xFF4D,
24777 mmsquaredsquare: 0x339F,
24778 mohiragana: 0x3082,
24779 mohmsquare: 0x33C1,
24780 mokatakana: 0x30E2,
24781 mokatakanahalfwidth: 0xFF93,
24782 molsquare: 0x33D6,
24783 momathai: 0x0E21,
24784 moverssquare: 0x33A7,
24785 moverssquaredsquare: 0x33A8,
24786 mparen: 0x24A8,
24787 mpasquare: 0x33AB,
24788 mssquare: 0x33B3,
24789 msuperior: 0xF6EF,
24790 mturned: 0x026F,
24791 mu: 0x00B5,
24792 mu1: 0x00B5,
24793 muasquare: 0x3382,
24794 muchgreater: 0x226B,
24795 muchless: 0x226A,
24796 mufsquare: 0x338C,
24797 mugreek: 0x03BC,
24798 mugsquare: 0x338D,
24799 muhiragana: 0x3080,
24800 mukatakana: 0x30E0,
24801 mukatakanahalfwidth: 0xFF91,
24802 mulsquare: 0x3395,
24803 multiply: 0x00D7,
24804 mumsquare: 0x339B,
24805 munahhebrew: 0x05A3,
24806 munahlefthebrew: 0x05A3,
24807 musicalnote: 0x266A,
24808 musicalnotedbl: 0x266B,
24809 musicflatsign: 0x266D,
24810 musicsharpsign: 0x266F,
24811 mussquare: 0x33B2,
24812 muvsquare: 0x33B6,
24813 muwsquare: 0x33BC,
24814 mvmegasquare: 0x33B9,
24815 mvsquare: 0x33B7,
24816 mwmegasquare: 0x33BF,
24817 mwsquare: 0x33BD,
24818 n: 0x006E,
24819 nabengali: 0x09A8,
24820 nabla: 0x2207,
24821 nacute: 0x0144,
24822 nadeva: 0x0928,
24823 nagujarati: 0x0AA8,
24824 nagurmukhi: 0x0A28,
24825 nahiragana: 0x306A,
24826 nakatakana: 0x30CA,
24827 nakatakanahalfwidth: 0xFF85,
24828 napostrophe: 0x0149,
24829 nasquare: 0x3381,
24830 nbopomofo: 0x310B,
24831 nbspace: 0x00A0,
24832 ncaron: 0x0148,
24833 ncedilla: 0x0146,
24834 ncircle: 0x24DD,
24835 ncircumflexbelow: 0x1E4B,
24836 ncommaaccent: 0x0146,
24837 ndotaccent: 0x1E45,
24838 ndotbelow: 0x1E47,
24839 nehiragana: 0x306D,
24840 nekatakana: 0x30CD,
24841 nekatakanahalfwidth: 0xFF88,
24842 newsheqelsign: 0x20AA,
24843 nfsquare: 0x338B,
24844 ngabengali: 0x0999,
24845 ngadeva: 0x0919,
24846 ngagujarati: 0x0A99,
24847 ngagurmukhi: 0x0A19,
24848 ngonguthai: 0x0E07,
24849 nhiragana: 0x3093,
24850 nhookleft: 0x0272,
24851 nhookretroflex: 0x0273,
24852 nieunacirclekorean: 0x326F,
24853 nieunaparenkorean: 0x320F,
24854 nieuncieuckorean: 0x3135,
24855 nieuncirclekorean: 0x3261,
24856 nieunhieuhkorean: 0x3136,
24857 nieunkorean: 0x3134,
24858 nieunpansioskorean: 0x3168,
24859 nieunparenkorean: 0x3201,
24860 nieunsioskorean: 0x3167,
24861 nieuntikeutkorean: 0x3166,
24862 nihiragana: 0x306B,
24863 nikatakana: 0x30CB,
24864 nikatakanahalfwidth: 0xFF86,
24865 nikhahitleftthai: 0xF899,
24866 nikhahitthai: 0x0E4D,
24867 nine: 0x0039,
24868 ninearabic: 0x0669,
24869 ninebengali: 0x09EF,
24870 ninecircle: 0x2468,
24871 ninecircleinversesansserif: 0x2792,
24872 ninedeva: 0x096F,
24873 ninegujarati: 0x0AEF,
24874 ninegurmukhi: 0x0A6F,
24875 ninehackarabic: 0x0669,
24876 ninehangzhou: 0x3029,
24877 nineideographicparen: 0x3228,
24878 nineinferior: 0x2089,
24879 ninemonospace: 0xFF19,
24880 nineoldstyle: 0xF739,
24881 nineparen: 0x247C,
24882 nineperiod: 0x2490,
24883 ninepersian: 0x06F9,
24884 nineroman: 0x2178,
24885 ninesuperior: 0x2079,
24886 nineteencircle: 0x2472,
24887 nineteenparen: 0x2486,
24888 nineteenperiod: 0x249A,
24889 ninethai: 0x0E59,
24890 nj: 0x01CC,
24891 njecyrillic: 0x045A,
24892 nkatakana: 0x30F3,
24893 nkatakanahalfwidth: 0xFF9D,
24894 nlegrightlong: 0x019E,
24895 nlinebelow: 0x1E49,
24896 nmonospace: 0xFF4E,
24897 nmsquare: 0x339A,
24898 nnabengali: 0x09A3,
24899 nnadeva: 0x0923,
24900 nnagujarati: 0x0AA3,
24901 nnagurmukhi: 0x0A23,
24902 nnnadeva: 0x0929,
24903 nohiragana: 0x306E,
24904 nokatakana: 0x30CE,
24905 nokatakanahalfwidth: 0xFF89,
24906 nonbreakingspace: 0x00A0,
24907 nonenthai: 0x0E13,
24908 nonuthai: 0x0E19,
24909 noonarabic: 0x0646,
24910 noonfinalarabic: 0xFEE6,
24911 noonghunnaarabic: 0x06BA,
24912 noonghunnafinalarabic: 0xFB9F,
24913 nooninitialarabic: 0xFEE7,
24914 noonjeeminitialarabic: 0xFCD2,
24915 noonjeemisolatedarabic: 0xFC4B,
24916 noonmedialarabic: 0xFEE8,
24917 noonmeeminitialarabic: 0xFCD5,
24918 noonmeemisolatedarabic: 0xFC4E,
24919 noonnoonfinalarabic: 0xFC8D,
24920 notcontains: 0x220C,
24921 notelement: 0x2209,
24922 notelementof: 0x2209,
24923 notequal: 0x2260,
24924 notgreater: 0x226F,
24925 notgreaternorequal: 0x2271,
24926 notgreaternorless: 0x2279,
24927 notidentical: 0x2262,
24928 notless: 0x226E,
24929 notlessnorequal: 0x2270,
24930 notparallel: 0x2226,
24931 notprecedes: 0x2280,
24932 notsubset: 0x2284,
24933 notsucceeds: 0x2281,
24934 notsuperset: 0x2285,
24935 nowarmenian: 0x0576,
24936 nparen: 0x24A9,
24937 nssquare: 0x33B1,
24938 nsuperior: 0x207F,
24939 ntilde: 0x00F1,
24940 nu: 0x03BD,
24941 nuhiragana: 0x306C,
24942 nukatakana: 0x30CC,
24943 nukatakanahalfwidth: 0xFF87,
24944 nuktabengali: 0x09BC,
24945 nuktadeva: 0x093C,
24946 nuktagujarati: 0x0ABC,
24947 nuktagurmukhi: 0x0A3C,
24948 numbersign: 0x0023,
24949 numbersignmonospace: 0xFF03,
24950 numbersignsmall: 0xFE5F,
24951 numeralsigngreek: 0x0374,
24952 numeralsignlowergreek: 0x0375,
24953 numero: 0x2116,
24954 nun: 0x05E0,
24955 nundagesh: 0xFB40,
24956 nundageshhebrew: 0xFB40,
24957 nunhebrew: 0x05E0,
24958 nvsquare: 0x33B5,
24959 nwsquare: 0x33BB,
24960 nyabengali: 0x099E,
24961 nyadeva: 0x091E,
24962 nyagujarati: 0x0A9E,
24963 nyagurmukhi: 0x0A1E,
24964 o: 0x006F,
24965 oacute: 0x00F3,
24966 oangthai: 0x0E2D,
24967 obarred: 0x0275,
24968 obarredcyrillic: 0x04E9,
24969 obarreddieresiscyrillic: 0x04EB,
24970 obengali: 0x0993,
24971 obopomofo: 0x311B,
24972 obreve: 0x014F,
24973 ocandradeva: 0x0911,
24974 ocandragujarati: 0x0A91,
24975 ocandravowelsigndeva: 0x0949,
24976 ocandravowelsigngujarati: 0x0AC9,
24977 ocaron: 0x01D2,
24978 ocircle: 0x24DE,
24979 ocircumflex: 0x00F4,
24980 ocircumflexacute: 0x1ED1,
24981 ocircumflexdotbelow: 0x1ED9,
24982 ocircumflexgrave: 0x1ED3,
24983 ocircumflexhookabove: 0x1ED5,
24984 ocircumflextilde: 0x1ED7,
24985 ocyrillic: 0x043E,
24986 odblacute: 0x0151,
24987 odblgrave: 0x020D,
24988 odeva: 0x0913,
24989 odieresis: 0x00F6,
24990 odieresiscyrillic: 0x04E7,
24991 odotbelow: 0x1ECD,
24992 oe: 0x0153,
24993 oekorean: 0x315A,
24994 ogonek: 0x02DB,
24995 ogonekcmb: 0x0328,
24996 ograve: 0x00F2,
24997 ogujarati: 0x0A93,
24998 oharmenian: 0x0585,
24999 ohiragana: 0x304A,
25000 ohookabove: 0x1ECF,
25001 ohorn: 0x01A1,
25002 ohornacute: 0x1EDB,
25003 ohorndotbelow: 0x1EE3,
25004 ohorngrave: 0x1EDD,
25005 ohornhookabove: 0x1EDF,
25006 ohorntilde: 0x1EE1,
25007 ohungarumlaut: 0x0151,
25008 oi: 0x01A3,
25009 oinvertedbreve: 0x020F,
25010 okatakana: 0x30AA,
25011 okatakanahalfwidth: 0xFF75,
25012 okorean: 0x3157,
25013 olehebrew: 0x05AB,
25014 omacron: 0x014D,
25015 omacronacute: 0x1E53,
25016 omacrongrave: 0x1E51,
25017 omdeva: 0x0950,
25018 omega: 0x03C9,
25019 omega1: 0x03D6,
25020 omegacyrillic: 0x0461,
25021 omegalatinclosed: 0x0277,
25022 omegaroundcyrillic: 0x047B,
25023 omegatitlocyrillic: 0x047D,
25024 omegatonos: 0x03CE,
25025 omgujarati: 0x0AD0,
25026 omicron: 0x03BF,
25027 omicrontonos: 0x03CC,
25028 omonospace: 0xFF4F,
25029 one: 0x0031,
25030 onearabic: 0x0661,
25031 onebengali: 0x09E7,
25032 onecircle: 0x2460,
25033 onecircleinversesansserif: 0x278A,
25034 onedeva: 0x0967,
25035 onedotenleader: 0x2024,
25036 oneeighth: 0x215B,
25037 onefitted: 0xF6DC,
25038 onegujarati: 0x0AE7,
25039 onegurmukhi: 0x0A67,
25040 onehackarabic: 0x0661,
25041 onehalf: 0x00BD,
25042 onehangzhou: 0x3021,
25043 oneideographicparen: 0x3220,
25044 oneinferior: 0x2081,
25045 onemonospace: 0xFF11,
25046 onenumeratorbengali: 0x09F4,
25047 oneoldstyle: 0xF731,
25048 oneparen: 0x2474,
25049 oneperiod: 0x2488,
25050 onepersian: 0x06F1,
25051 onequarter: 0x00BC,
25052 oneroman: 0x2170,
25053 onesuperior: 0x00B9,
25054 onethai: 0x0E51,
25055 onethird: 0x2153,
25056 oogonek: 0x01EB,
25057 oogonekmacron: 0x01ED,
25058 oogurmukhi: 0x0A13,
25059 oomatragurmukhi: 0x0A4B,
25060 oopen: 0x0254,
25061 oparen: 0x24AA,
25062 openbullet: 0x25E6,
25063 option: 0x2325,
25064 ordfeminine: 0x00AA,
25065 ordmasculine: 0x00BA,
25066 orthogonal: 0x221F,
25067 oshortdeva: 0x0912,
25068 oshortvowelsigndeva: 0x094A,
25069 oslash: 0x00F8,
25070 oslashacute: 0x01FF,
25071 osmallhiragana: 0x3049,
25072 osmallkatakana: 0x30A9,
25073 osmallkatakanahalfwidth: 0xFF6B,
25074 ostrokeacute: 0x01FF,
25075 osuperior: 0xF6F0,
25076 otcyrillic: 0x047F,
25077 otilde: 0x00F5,
25078 otildeacute: 0x1E4D,
25079 otildedieresis: 0x1E4F,
25080 oubopomofo: 0x3121,
25081 overline: 0x203E,
25082 overlinecenterline: 0xFE4A,
25083 overlinecmb: 0x0305,
25084 overlinedashed: 0xFE49,
25085 overlinedblwavy: 0xFE4C,
25086 overlinewavy: 0xFE4B,
25087 overscore: 0x00AF,
25088 ovowelsignbengali: 0x09CB,
25089 ovowelsigndeva: 0x094B,
25090 ovowelsigngujarati: 0x0ACB,
25091 p: 0x0070,
25092 paampssquare: 0x3380,
25093 paasentosquare: 0x332B,
25094 pabengali: 0x09AA,
25095 pacute: 0x1E55,
25096 padeva: 0x092A,
25097 pagedown: 0x21DF,
25098 pageup: 0x21DE,
25099 pagujarati: 0x0AAA,
25100 pagurmukhi: 0x0A2A,
25101 pahiragana: 0x3071,
25102 paiyannoithai: 0x0E2F,
25103 pakatakana: 0x30D1,
25104 palatalizationcyrilliccmb: 0x0484,
25105 palochkacyrillic: 0x04C0,
25106 pansioskorean: 0x317F,
25107 paragraph: 0x00B6,
25108 parallel: 0x2225,
25109 parenleft: 0x0028,
25110 parenleftaltonearabic: 0xFD3E,
25111 parenleftbt: 0xF8ED,
25112 parenleftex: 0xF8EC,
25113 parenleftinferior: 0x208D,
25114 parenleftmonospace: 0xFF08,
25115 parenleftsmall: 0xFE59,
25116 parenleftsuperior: 0x207D,
25117 parenlefttp: 0xF8EB,
25118 parenleftvertical: 0xFE35,
25119 parenright: 0x0029,
25120 parenrightaltonearabic: 0xFD3F,
25121 parenrightbt: 0xF8F8,
25122 parenrightex: 0xF8F7,
25123 parenrightinferior: 0x208E,
25124 parenrightmonospace: 0xFF09,
25125 parenrightsmall: 0xFE5A,
25126 parenrightsuperior: 0x207E,
25127 parenrighttp: 0xF8F6,
25128 parenrightvertical: 0xFE36,
25129 partialdiff: 0x2202,
25130 paseqhebrew: 0x05C0,
25131 pashtahebrew: 0x0599,
25132 pasquare: 0x33A9,
25133 patah: 0x05B7,
25134 patah11: 0x05B7,
25135 patah1d: 0x05B7,
25136 patah2a: 0x05B7,
25137 patahhebrew: 0x05B7,
25138 patahnarrowhebrew: 0x05B7,
25139 patahquarterhebrew: 0x05B7,
25140 patahwidehebrew: 0x05B7,
25141 pazerhebrew: 0x05A1,
25142 pbopomofo: 0x3106,
25143 pcircle: 0x24DF,
25144 pdotaccent: 0x1E57,
25145 pe: 0x05E4,
25146 pecyrillic: 0x043F,
25147 pedagesh: 0xFB44,
25148 pedageshhebrew: 0xFB44,
25149 peezisquare: 0x333B,
25150 pefinaldageshhebrew: 0xFB43,
25151 peharabic: 0x067E,
25152 peharmenian: 0x057A,
25153 pehebrew: 0x05E4,
25154 pehfinalarabic: 0xFB57,
25155 pehinitialarabic: 0xFB58,
25156 pehiragana: 0x307A,
25157 pehmedialarabic: 0xFB59,
25158 pekatakana: 0x30DA,
25159 pemiddlehookcyrillic: 0x04A7,
25160 perafehebrew: 0xFB4E,
25161 percent: 0x0025,
25162 percentarabic: 0x066A,
25163 percentmonospace: 0xFF05,
25164 percentsmall: 0xFE6A,
25165 period: 0x002E,
25166 periodarmenian: 0x0589,
25167 periodcentered: 0x00B7,
25168 periodhalfwidth: 0xFF61,
25169 periodinferior: 0xF6E7,
25170 periodmonospace: 0xFF0E,
25171 periodsmall: 0xFE52,
25172 periodsuperior: 0xF6E8,
25173 perispomenigreekcmb: 0x0342,
25174 perpendicular: 0x22A5,
25175 perthousand: 0x2030,
25176 peseta: 0x20A7,
25177 pfsquare: 0x338A,
25178 phabengali: 0x09AB,
25179 phadeva: 0x092B,
25180 phagujarati: 0x0AAB,
25181 phagurmukhi: 0x0A2B,
25182 phi: 0x03C6,
25183 phi1: 0x03D5,
25184 phieuphacirclekorean: 0x327A,
25185 phieuphaparenkorean: 0x321A,
25186 phieuphcirclekorean: 0x326C,
25187 phieuphkorean: 0x314D,
25188 phieuphparenkorean: 0x320C,
25189 philatin: 0x0278,
25190 phinthuthai: 0x0E3A,
25191 phisymbolgreek: 0x03D5,
25192 phook: 0x01A5,
25193 phophanthai: 0x0E1E,
25194 phophungthai: 0x0E1C,
25195 phosamphaothai: 0x0E20,
25196 pi: 0x03C0,
25197 pieupacirclekorean: 0x3273,
25198 pieupaparenkorean: 0x3213,
25199 pieupcieuckorean: 0x3176,
25200 pieupcirclekorean: 0x3265,
25201 pieupkiyeokkorean: 0x3172,
25202 pieupkorean: 0x3142,
25203 pieupparenkorean: 0x3205,
25204 pieupsioskiyeokkorean: 0x3174,
25205 pieupsioskorean: 0x3144,
25206 pieupsiostikeutkorean: 0x3175,
25207 pieupthieuthkorean: 0x3177,
25208 pieuptikeutkorean: 0x3173,
25209 pihiragana: 0x3074,
25210 pikatakana: 0x30D4,
25211 pisymbolgreek: 0x03D6,
25212 piwrarmenian: 0x0583,
25213 plus: 0x002B,
25214 plusbelowcmb: 0x031F,
25215 pluscircle: 0x2295,
25216 plusminus: 0x00B1,
25217 plusmod: 0x02D6,
25218 plusmonospace: 0xFF0B,
25219 plussmall: 0xFE62,
25220 plussuperior: 0x207A,
25221 pmonospace: 0xFF50,
25222 pmsquare: 0x33D8,
25223 pohiragana: 0x307D,
25224 pointingindexdownwhite: 0x261F,
25225 pointingindexleftwhite: 0x261C,
25226 pointingindexrightwhite: 0x261E,
25227 pointingindexupwhite: 0x261D,
25228 pokatakana: 0x30DD,
25229 poplathai: 0x0E1B,
25230 postalmark: 0x3012,
25231 postalmarkface: 0x3020,
25232 pparen: 0x24AB,
25233 precedes: 0x227A,
25234 prescription: 0x211E,
25235 primemod: 0x02B9,
25236 primereversed: 0x2035,
25237 product: 0x220F,
25238 projective: 0x2305,
25239 prolongedkana: 0x30FC,
25240 propellor: 0x2318,
25241 propersubset: 0x2282,
25242 propersuperset: 0x2283,
25243 proportion: 0x2237,
25244 proportional: 0x221D,
25245 psi: 0x03C8,
25246 psicyrillic: 0x0471,
25247 psilipneumatacyrilliccmb: 0x0486,
25248 pssquare: 0x33B0,
25249 puhiragana: 0x3077,
25250 pukatakana: 0x30D7,
25251 pvsquare: 0x33B4,
25252 pwsquare: 0x33BA,
25253 q: 0x0071,
25254 qadeva: 0x0958,
25255 qadmahebrew: 0x05A8,
25256 qafarabic: 0x0642,
25257 qaffinalarabic: 0xFED6,
25258 qafinitialarabic: 0xFED7,
25259 qafmedialarabic: 0xFED8,
25260 qamats: 0x05B8,
25261 qamats10: 0x05B8,
25262 qamats1a: 0x05B8,
25263 qamats1c: 0x05B8,
25264 qamats27: 0x05B8,
25265 qamats29: 0x05B8,
25266 qamats33: 0x05B8,
25267 qamatsde: 0x05B8,
25268 qamatshebrew: 0x05B8,
25269 qamatsnarrowhebrew: 0x05B8,
25270 qamatsqatanhebrew: 0x05B8,
25271 qamatsqatannarrowhebrew: 0x05B8,
25272 qamatsqatanquarterhebrew: 0x05B8,
25273 qamatsqatanwidehebrew: 0x05B8,
25274 qamatsquarterhebrew: 0x05B8,
25275 qamatswidehebrew: 0x05B8,
25276 qarneyparahebrew: 0x059F,
25277 qbopomofo: 0x3111,
25278 qcircle: 0x24E0,
25279 qhook: 0x02A0,
25280 qmonospace: 0xFF51,
25281 qof: 0x05E7,
25282 qofdagesh: 0xFB47,
25283 qofdageshhebrew: 0xFB47,
25284 qofhebrew: 0x05E7,
25285 qparen: 0x24AC,
25286 quarternote: 0x2669,
25287 qubuts: 0x05BB,
25288 qubuts18: 0x05BB,
25289 qubuts25: 0x05BB,
25290 qubuts31: 0x05BB,
25291 qubutshebrew: 0x05BB,
25292 qubutsnarrowhebrew: 0x05BB,
25293 qubutsquarterhebrew: 0x05BB,
25294 qubutswidehebrew: 0x05BB,
25295 question: 0x003F,
25296 questionarabic: 0x061F,
25297 questionarmenian: 0x055E,
25298 questiondown: 0x00BF,
25299 questiondownsmall: 0xF7BF,
25300 questiongreek: 0x037E,
25301 questionmonospace: 0xFF1F,
25302 questionsmall: 0xF73F,
25303 quotedbl: 0x0022,
25304 quotedblbase: 0x201E,
25305 quotedblleft: 0x201C,
25306 quotedblmonospace: 0xFF02,
25307 quotedblprime: 0x301E,
25308 quotedblprimereversed: 0x301D,
25309 quotedblright: 0x201D,
25310 quoteleft: 0x2018,
25311 quoteleftreversed: 0x201B,
25312 quotereversed: 0x201B,
25313 quoteright: 0x2019,
25314 quoterightn: 0x0149,
25315 quotesinglbase: 0x201A,
25316 quotesingle: 0x0027,
25317 quotesinglemonospace: 0xFF07,
25318 r: 0x0072,
25319 raarmenian: 0x057C,
25320 rabengali: 0x09B0,
25321 racute: 0x0155,
25322 radeva: 0x0930,
25323 radical: 0x221A,
25324 radicalex: 0xF8E5,
25325 radoverssquare: 0x33AE,
25326 radoverssquaredsquare: 0x33AF,
25327 radsquare: 0x33AD,
25328 rafe: 0x05BF,
25329 rafehebrew: 0x05BF,
25330 ragujarati: 0x0AB0,
25331 ragurmukhi: 0x0A30,
25332 rahiragana: 0x3089,
25333 rakatakana: 0x30E9,
25334 rakatakanahalfwidth: 0xFF97,
25335 ralowerdiagonalbengali: 0x09F1,
25336 ramiddlediagonalbengali: 0x09F0,
25337 ramshorn: 0x0264,
25338 ratio: 0x2236,
25339 rbopomofo: 0x3116,
25340 rcaron: 0x0159,
25341 rcedilla: 0x0157,
25342 rcircle: 0x24E1,
25343 rcommaaccent: 0x0157,
25344 rdblgrave: 0x0211,
25345 rdotaccent: 0x1E59,
25346 rdotbelow: 0x1E5B,
25347 rdotbelowmacron: 0x1E5D,
25348 referencemark: 0x203B,
25349 reflexsubset: 0x2286,
25350 reflexsuperset: 0x2287,
25351 registered: 0x00AE,
25352 registersans: 0xF8E8,
25353 registerserif: 0xF6DA,
25354 reharabic: 0x0631,
25355 reharmenian: 0x0580,
25356 rehfinalarabic: 0xFEAE,
25357 rehiragana: 0x308C,
25358 rekatakana: 0x30EC,
25359 rekatakanahalfwidth: 0xFF9A,
25360 resh: 0x05E8,
25361 reshdageshhebrew: 0xFB48,
25362 reshhebrew: 0x05E8,
25363 reversedtilde: 0x223D,
25364 reviahebrew: 0x0597,
25365 reviamugrashhebrew: 0x0597,
25366 revlogicalnot: 0x2310,
25367 rfishhook: 0x027E,
25368 rfishhookreversed: 0x027F,
25369 rhabengali: 0x09DD,
25370 rhadeva: 0x095D,
25371 rho: 0x03C1,
25372 rhook: 0x027D,
25373 rhookturned: 0x027B,
25374 rhookturnedsuperior: 0x02B5,
25375 rhosymbolgreek: 0x03F1,
25376 rhotichookmod: 0x02DE,
25377 rieulacirclekorean: 0x3271,
25378 rieulaparenkorean: 0x3211,
25379 rieulcirclekorean: 0x3263,
25380 rieulhieuhkorean: 0x3140,
25381 rieulkiyeokkorean: 0x313A,
25382 rieulkiyeoksioskorean: 0x3169,
25383 rieulkorean: 0x3139,
25384 rieulmieumkorean: 0x313B,
25385 rieulpansioskorean: 0x316C,
25386 rieulparenkorean: 0x3203,
25387 rieulphieuphkorean: 0x313F,
25388 rieulpieupkorean: 0x313C,
25389 rieulpieupsioskorean: 0x316B,
25390 rieulsioskorean: 0x313D,
25391 rieulthieuthkorean: 0x313E,
25392 rieultikeutkorean: 0x316A,
25393 rieulyeorinhieuhkorean: 0x316D,
25394 rightangle: 0x221F,
25395 righttackbelowcmb: 0x0319,
25396 righttriangle: 0x22BF,
25397 rihiragana: 0x308A,
25398 rikatakana: 0x30EA,
25399 rikatakanahalfwidth: 0xFF98,
25400 ring: 0x02DA,
25401 ringbelowcmb: 0x0325,
25402 ringcmb: 0x030A,
25403 ringhalfleft: 0x02BF,
25404 ringhalfleftarmenian: 0x0559,
25405 ringhalfleftbelowcmb: 0x031C,
25406 ringhalfleftcentered: 0x02D3,
25407 ringhalfright: 0x02BE,
25408 ringhalfrightbelowcmb: 0x0339,
25409 ringhalfrightcentered: 0x02D2,
25410 rinvertedbreve: 0x0213,
25411 rittorusquare: 0x3351,
25412 rlinebelow: 0x1E5F,
25413 rlongleg: 0x027C,
25414 rlonglegturned: 0x027A,
25415 rmonospace: 0xFF52,
25416 rohiragana: 0x308D,
25417 rokatakana: 0x30ED,
25418 rokatakanahalfwidth: 0xFF9B,
25419 roruathai: 0x0E23,
25420 rparen: 0x24AD,
25421 rrabengali: 0x09DC,
25422 rradeva: 0x0931,
25423 rragurmukhi: 0x0A5C,
25424 rreharabic: 0x0691,
25425 rrehfinalarabic: 0xFB8D,
25426 rrvocalicbengali: 0x09E0,
25427 rrvocalicdeva: 0x0960,
25428 rrvocalicgujarati: 0x0AE0,
25429 rrvocalicvowelsignbengali: 0x09C4,
25430 rrvocalicvowelsigndeva: 0x0944,
25431 rrvocalicvowelsigngujarati: 0x0AC4,
25432 rsuperior: 0xF6F1,
25433 rtblock: 0x2590,
25434 rturned: 0x0279,
25435 rturnedsuperior: 0x02B4,
25436 ruhiragana: 0x308B,
25437 rukatakana: 0x30EB,
25438 rukatakanahalfwidth: 0xFF99,
25439 rupeemarkbengali: 0x09F2,
25440 rupeesignbengali: 0x09F3,
25441 rupiah: 0xF6DD,
25442 ruthai: 0x0E24,
25443 rvocalicbengali: 0x098B,
25444 rvocalicdeva: 0x090B,
25445 rvocalicgujarati: 0x0A8B,
25446 rvocalicvowelsignbengali: 0x09C3,
25447 rvocalicvowelsigndeva: 0x0943,
25448 rvocalicvowelsigngujarati: 0x0AC3,
25449 s: 0x0073,
25450 sabengali: 0x09B8,
25451 sacute: 0x015B,
25452 sacutedotaccent: 0x1E65,
25453 sadarabic: 0x0635,
25454 sadeva: 0x0938,
25455 sadfinalarabic: 0xFEBA,
25456 sadinitialarabic: 0xFEBB,
25457 sadmedialarabic: 0xFEBC,
25458 sagujarati: 0x0AB8,
25459 sagurmukhi: 0x0A38,
25460 sahiragana: 0x3055,
25461 sakatakana: 0x30B5,
25462 sakatakanahalfwidth: 0xFF7B,
25463 sallallahoualayhewasallamarabic: 0xFDFA,
25464 samekh: 0x05E1,
25465 samekhdagesh: 0xFB41,
25466 samekhdageshhebrew: 0xFB41,
25467 samekhhebrew: 0x05E1,
25468 saraaathai: 0x0E32,
25469 saraaethai: 0x0E41,
25470 saraaimaimalaithai: 0x0E44,
25471 saraaimaimuanthai: 0x0E43,
25472 saraamthai: 0x0E33,
25473 saraathai: 0x0E30,
25474 saraethai: 0x0E40,
25475 saraiileftthai: 0xF886,
25476 saraiithai: 0x0E35,
25477 saraileftthai: 0xF885,
25478 saraithai: 0x0E34,
25479 saraothai: 0x0E42,
25480 saraueeleftthai: 0xF888,
25481 saraueethai: 0x0E37,
25482 saraueleftthai: 0xF887,
25483 sarauethai: 0x0E36,
25484 sarauthai: 0x0E38,
25485 sarauuthai: 0x0E39,
25486 sbopomofo: 0x3119,
25487 scaron: 0x0161,
25488 scarondotaccent: 0x1E67,
25489 scedilla: 0x015F,
25490 schwa: 0x0259,
25491 schwacyrillic: 0x04D9,
25492 schwadieresiscyrillic: 0x04DB,
25493 schwahook: 0x025A,
25494 scircle: 0x24E2,
25495 scircumflex: 0x015D,
25496 scommaaccent: 0x0219,
25497 sdotaccent: 0x1E61,
25498 sdotbelow: 0x1E63,
25499 sdotbelowdotaccent: 0x1E69,
25500 seagullbelowcmb: 0x033C,
25501 second: 0x2033,
25502 secondtonechinese: 0x02CA,
25503 section: 0x00A7,
25504 seenarabic: 0x0633,
25505 seenfinalarabic: 0xFEB2,
25506 seeninitialarabic: 0xFEB3,
25507 seenmedialarabic: 0xFEB4,
25508 segol: 0x05B6,
25509 segol13: 0x05B6,
25510 segol1f: 0x05B6,
25511 segol2c: 0x05B6,
25512 segolhebrew: 0x05B6,
25513 segolnarrowhebrew: 0x05B6,
25514 segolquarterhebrew: 0x05B6,
25515 segoltahebrew: 0x0592,
25516 segolwidehebrew: 0x05B6,
25517 seharmenian: 0x057D,
25518 sehiragana: 0x305B,
25519 sekatakana: 0x30BB,
25520 sekatakanahalfwidth: 0xFF7E,
25521 semicolon: 0x003B,
25522 semicolonarabic: 0x061B,
25523 semicolonmonospace: 0xFF1B,
25524 semicolonsmall: 0xFE54,
25525 semivoicedmarkkana: 0x309C,
25526 semivoicedmarkkanahalfwidth: 0xFF9F,
25527 sentisquare: 0x3322,
25528 sentosquare: 0x3323,
25529 seven: 0x0037,
25530 sevenarabic: 0x0667,
25531 sevenbengali: 0x09ED,
25532 sevencircle: 0x2466,
25533 sevencircleinversesansserif: 0x2790,
25534 sevendeva: 0x096D,
25535 seveneighths: 0x215E,
25536 sevengujarati: 0x0AED,
25537 sevengurmukhi: 0x0A6D,
25538 sevenhackarabic: 0x0667,
25539 sevenhangzhou: 0x3027,
25540 sevenideographicparen: 0x3226,
25541 seveninferior: 0x2087,
25542 sevenmonospace: 0xFF17,
25543 sevenoldstyle: 0xF737,
25544 sevenparen: 0x247A,
25545 sevenperiod: 0x248E,
25546 sevenpersian: 0x06F7,
25547 sevenroman: 0x2176,
25548 sevensuperior: 0x2077,
25549 seventeencircle: 0x2470,
25550 seventeenparen: 0x2484,
25551 seventeenperiod: 0x2498,
25552 seventhai: 0x0E57,
25553 sfthyphen: 0x00AD,
25554 shaarmenian: 0x0577,
25555 shabengali: 0x09B6,
25556 shacyrillic: 0x0448,
25557 shaddaarabic: 0x0651,
25558 shaddadammaarabic: 0xFC61,
25559 shaddadammatanarabic: 0xFC5E,
25560 shaddafathaarabic: 0xFC60,
25561 shaddakasraarabic: 0xFC62,
25562 shaddakasratanarabic: 0xFC5F,
25563 shade: 0x2592,
25564 shadedark: 0x2593,
25565 shadelight: 0x2591,
25566 shademedium: 0x2592,
25567 shadeva: 0x0936,
25568 shagujarati: 0x0AB6,
25569 shagurmukhi: 0x0A36,
25570 shalshelethebrew: 0x0593,
25571 shbopomofo: 0x3115,
25572 shchacyrillic: 0x0449,
25573 sheenarabic: 0x0634,
25574 sheenfinalarabic: 0xFEB6,
25575 sheeninitialarabic: 0xFEB7,
25576 sheenmedialarabic: 0xFEB8,
25577 sheicoptic: 0x03E3,
25578 sheqel: 0x20AA,
25579 sheqelhebrew: 0x20AA,
25580 sheva: 0x05B0,
25581 sheva115: 0x05B0,
25582 sheva15: 0x05B0,
25583 sheva22: 0x05B0,
25584 sheva2e: 0x05B0,
25585 shevahebrew: 0x05B0,
25586 shevanarrowhebrew: 0x05B0,
25587 shevaquarterhebrew: 0x05B0,
25588 shevawidehebrew: 0x05B0,
25589 shhacyrillic: 0x04BB,
25590 shimacoptic: 0x03ED,
25591 shin: 0x05E9,
25592 shindagesh: 0xFB49,
25593 shindageshhebrew: 0xFB49,
25594 shindageshshindot: 0xFB2C,
25595 shindageshshindothebrew: 0xFB2C,
25596 shindageshsindot: 0xFB2D,
25597 shindageshsindothebrew: 0xFB2D,
25598 shindothebrew: 0x05C1,
25599 shinhebrew: 0x05E9,
25600 shinshindot: 0xFB2A,
25601 shinshindothebrew: 0xFB2A,
25602 shinsindot: 0xFB2B,
25603 shinsindothebrew: 0xFB2B,
25604 shook: 0x0282,
25605 sigma: 0x03C3,
25606 sigma1: 0x03C2,
25607 sigmafinal: 0x03C2,
25608 sigmalunatesymbolgreek: 0x03F2,
25609 sihiragana: 0x3057,
25610 sikatakana: 0x30B7,
25611 sikatakanahalfwidth: 0xFF7C,
25612 siluqhebrew: 0x05BD,
25613 siluqlefthebrew: 0x05BD,
25614 similar: 0x223C,
25615 sindothebrew: 0x05C2,
25616 siosacirclekorean: 0x3274,
25617 siosaparenkorean: 0x3214,
25618 sioscieuckorean: 0x317E,
25619 sioscirclekorean: 0x3266,
25620 sioskiyeokkorean: 0x317A,
25621 sioskorean: 0x3145,
25622 siosnieunkorean: 0x317B,
25623 siosparenkorean: 0x3206,
25624 siospieupkorean: 0x317D,
25625 siostikeutkorean: 0x317C,
25626 six: 0x0036,
25627 sixarabic: 0x0666,
25628 sixbengali: 0x09EC,
25629 sixcircle: 0x2465,
25630 sixcircleinversesansserif: 0x278F,
25631 sixdeva: 0x096C,
25632 sixgujarati: 0x0AEC,
25633 sixgurmukhi: 0x0A6C,
25634 sixhackarabic: 0x0666,
25635 sixhangzhou: 0x3026,
25636 sixideographicparen: 0x3225,
25637 sixinferior: 0x2086,
25638 sixmonospace: 0xFF16,
25639 sixoldstyle: 0xF736,
25640 sixparen: 0x2479,
25641 sixperiod: 0x248D,
25642 sixpersian: 0x06F6,
25643 sixroman: 0x2175,
25644 sixsuperior: 0x2076,
25645 sixteencircle: 0x246F,
25646 sixteencurrencydenominatorbengali: 0x09F9,
25647 sixteenparen: 0x2483,
25648 sixteenperiod: 0x2497,
25649 sixthai: 0x0E56,
25650 slash: 0x002F,
25651 slashmonospace: 0xFF0F,
25652 slong: 0x017F,
25653 slongdotaccent: 0x1E9B,
25654 smileface: 0x263A,
25655 smonospace: 0xFF53,
25656 sofpasuqhebrew: 0x05C3,
25657 softhyphen: 0x00AD,
25658 softsigncyrillic: 0x044C,
25659 sohiragana: 0x305D,
25660 sokatakana: 0x30BD,
25661 sokatakanahalfwidth: 0xFF7F,
25662 soliduslongoverlaycmb: 0x0338,
25663 solidusshortoverlaycmb: 0x0337,
25664 sorusithai: 0x0E29,
25665 sosalathai: 0x0E28,
25666 sosothai: 0x0E0B,
25667 sosuathai: 0x0E2A,
25668 space: 0x0020,
25669 spacehackarabic: 0x0020,
25670 spade: 0x2660,
25671 spadesuitblack: 0x2660,
25672 spadesuitwhite: 0x2664,
25673 sparen: 0x24AE,
25674 squarebelowcmb: 0x033B,
25675 squarecc: 0x33C4,
25676 squarecm: 0x339D,
25677 squarediagonalcrosshatchfill: 0x25A9,
25678 squarehorizontalfill: 0x25A4,
25679 squarekg: 0x338F,
25680 squarekm: 0x339E,
25681 squarekmcapital: 0x33CE,
25682 squareln: 0x33D1,
25683 squarelog: 0x33D2,
25684 squaremg: 0x338E,
25685 squaremil: 0x33D5,
25686 squaremm: 0x339C,
25687 squaremsquared: 0x33A1,
25688 squareorthogonalcrosshatchfill: 0x25A6,
25689 squareupperlefttolowerrightfill: 0x25A7,
25690 squareupperrighttolowerleftfill: 0x25A8,
25691 squareverticalfill: 0x25A5,
25692 squarewhitewithsmallblack: 0x25A3,
25693 srsquare: 0x33DB,
25694 ssabengali: 0x09B7,
25695 ssadeva: 0x0937,
25696 ssagujarati: 0x0AB7,
25697 ssangcieuckorean: 0x3149,
25698 ssanghieuhkorean: 0x3185,
25699 ssangieungkorean: 0x3180,
25700 ssangkiyeokkorean: 0x3132,
25701 ssangnieunkorean: 0x3165,
25702 ssangpieupkorean: 0x3143,
25703 ssangsioskorean: 0x3146,
25704 ssangtikeutkorean: 0x3138,
25705 ssuperior: 0xF6F2,
25706 sterling: 0x00A3,
25707 sterlingmonospace: 0xFFE1,
25708 strokelongoverlaycmb: 0x0336,
25709 strokeshortoverlaycmb: 0x0335,
25710 subset: 0x2282,
25711 subsetnotequal: 0x228A,
25712 subsetorequal: 0x2286,
25713 succeeds: 0x227B,
25714 suchthat: 0x220B,
25715 suhiragana: 0x3059,
25716 sukatakana: 0x30B9,
25717 sukatakanahalfwidth: 0xFF7D,
25718 sukunarabic: 0x0652,
25719 summation: 0x2211,
25720 sun: 0x263C,
25721 superset: 0x2283,
25722 supersetnotequal: 0x228B,
25723 supersetorequal: 0x2287,
25724 svsquare: 0x33DC,
25725 syouwaerasquare: 0x337C,
25726 t: 0x0074,
25727 tabengali: 0x09A4,
25728 tackdown: 0x22A4,
25729 tackleft: 0x22A3,
25730 tadeva: 0x0924,
25731 tagujarati: 0x0AA4,
25732 tagurmukhi: 0x0A24,
25733 taharabic: 0x0637,
25734 tahfinalarabic: 0xFEC2,
25735 tahinitialarabic: 0xFEC3,
25736 tahiragana: 0x305F,
25737 tahmedialarabic: 0xFEC4,
25738 taisyouerasquare: 0x337D,
25739 takatakana: 0x30BF,
25740 takatakanahalfwidth: 0xFF80,
25741 tatweelarabic: 0x0640,
25742 tau: 0x03C4,
25743 tav: 0x05EA,
25744 tavdages: 0xFB4A,
25745 tavdagesh: 0xFB4A,
25746 tavdageshhebrew: 0xFB4A,
25747 tavhebrew: 0x05EA,
25748 tbar: 0x0167,
25749 tbopomofo: 0x310A,
25750 tcaron: 0x0165,
25751 tccurl: 0x02A8,
25752 tcedilla: 0x0163,
25753 tcheharabic: 0x0686,
25754 tchehfinalarabic: 0xFB7B,
25755 tchehinitialarabic: 0xFB7C,
25756 tchehmedialarabic: 0xFB7D,
25757 tcircle: 0x24E3,
25758 tcircumflexbelow: 0x1E71,
25759 tcommaaccent: 0x0163,
25760 tdieresis: 0x1E97,
25761 tdotaccent: 0x1E6B,
25762 tdotbelow: 0x1E6D,
25763 tecyrillic: 0x0442,
25764 tedescendercyrillic: 0x04AD,
25765 teharabic: 0x062A,
25766 tehfinalarabic: 0xFE96,
25767 tehhahinitialarabic: 0xFCA2,
25768 tehhahisolatedarabic: 0xFC0C,
25769 tehinitialarabic: 0xFE97,
25770 tehiragana: 0x3066,
25771 tehjeeminitialarabic: 0xFCA1,
25772 tehjeemisolatedarabic: 0xFC0B,
25773 tehmarbutaarabic: 0x0629,
25774 tehmarbutafinalarabic: 0xFE94,
25775 tehmedialarabic: 0xFE98,
25776 tehmeeminitialarabic: 0xFCA4,
25777 tehmeemisolatedarabic: 0xFC0E,
25778 tehnoonfinalarabic: 0xFC73,
25779 tekatakana: 0x30C6,
25780 tekatakanahalfwidth: 0xFF83,
25781 telephone: 0x2121,
25782 telephoneblack: 0x260E,
25783 telishagedolahebrew: 0x05A0,
25784 telishaqetanahebrew: 0x05A9,
25785 tencircle: 0x2469,
25786 tenideographicparen: 0x3229,
25787 tenparen: 0x247D,
25788 tenperiod: 0x2491,
25789 tenroman: 0x2179,
25790 tesh: 0x02A7,
25791 tet: 0x05D8,
25792 tetdagesh: 0xFB38,
25793 tetdageshhebrew: 0xFB38,
25794 tethebrew: 0x05D8,
25795 tetsecyrillic: 0x04B5,
25796 tevirhebrew: 0x059B,
25797 tevirlefthebrew: 0x059B,
25798 thabengali: 0x09A5,
25799 thadeva: 0x0925,
25800 thagujarati: 0x0AA5,
25801 thagurmukhi: 0x0A25,
25802 thalarabic: 0x0630,
25803 thalfinalarabic: 0xFEAC,
25804 thanthakhatlowleftthai: 0xF898,
25805 thanthakhatlowrightthai: 0xF897,
25806 thanthakhatthai: 0x0E4C,
25807 thanthakhatupperleftthai: 0xF896,
25808 theharabic: 0x062B,
25809 thehfinalarabic: 0xFE9A,
25810 thehinitialarabic: 0xFE9B,
25811 thehmedialarabic: 0xFE9C,
25812 thereexists: 0x2203,
25813 therefore: 0x2234,
25814 theta: 0x03B8,
25815 theta1: 0x03D1,
25816 thetasymbolgreek: 0x03D1,
25817 thieuthacirclekorean: 0x3279,
25818 thieuthaparenkorean: 0x3219,
25819 thieuthcirclekorean: 0x326B,
25820 thieuthkorean: 0x314C,
25821 thieuthparenkorean: 0x320B,
25822 thirteencircle: 0x246C,
25823 thirteenparen: 0x2480,
25824 thirteenperiod: 0x2494,
25825 thonangmonthothai: 0x0E11,
25826 thook: 0x01AD,
25827 thophuthaothai: 0x0E12,
25828 thorn: 0x00FE,
25829 thothahanthai: 0x0E17,
25830 thothanthai: 0x0E10,
25831 thothongthai: 0x0E18,
25832 thothungthai: 0x0E16,
25833 thousandcyrillic: 0x0482,
25834 thousandsseparatorarabic: 0x066C,
25835 thousandsseparatorpersian: 0x066C,
25836 three: 0x0033,
25837 threearabic: 0x0663,
25838 threebengali: 0x09E9,
25839 threecircle: 0x2462,
25840 threecircleinversesansserif: 0x278C,
25841 threedeva: 0x0969,
25842 threeeighths: 0x215C,
25843 threegujarati: 0x0AE9,
25844 threegurmukhi: 0x0A69,
25845 threehackarabic: 0x0663,
25846 threehangzhou: 0x3023,
25847 threeideographicparen: 0x3222,
25848 threeinferior: 0x2083,
25849 threemonospace: 0xFF13,
25850 threenumeratorbengali: 0x09F6,
25851 threeoldstyle: 0xF733,
25852 threeparen: 0x2476,
25853 threeperiod: 0x248A,
25854 threepersian: 0x06F3,
25855 threequarters: 0x00BE,
25856 threequartersemdash: 0xF6DE,
25857 threeroman: 0x2172,
25858 threesuperior: 0x00B3,
25859 threethai: 0x0E53,
25860 thzsquare: 0x3394,
25861 tihiragana: 0x3061,
25862 tikatakana: 0x30C1,
25863 tikatakanahalfwidth: 0xFF81,
25864 tikeutacirclekorean: 0x3270,
25865 tikeutaparenkorean: 0x3210,
25866 tikeutcirclekorean: 0x3262,
25867 tikeutkorean: 0x3137,
25868 tikeutparenkorean: 0x3202,
25869 tilde: 0x02DC,
25870 tildebelowcmb: 0x0330,
25871 tildecmb: 0x0303,
25872 tildecomb: 0x0303,
25873 tildedoublecmb: 0x0360,
25874 tildeoperator: 0x223C,
25875 tildeoverlaycmb: 0x0334,
25876 tildeverticalcmb: 0x033E,
25877 timescircle: 0x2297,
25878 tipehahebrew: 0x0596,
25879 tipehalefthebrew: 0x0596,
25880 tippigurmukhi: 0x0A70,
25881 titlocyrilliccmb: 0x0483,
25882 tiwnarmenian: 0x057F,
25883 tlinebelow: 0x1E6F,
25884 tmonospace: 0xFF54,
25885 toarmenian: 0x0569,
25886 tohiragana: 0x3068,
25887 tokatakana: 0x30C8,
25888 tokatakanahalfwidth: 0xFF84,
25889 tonebarextrahighmod: 0x02E5,
25890 tonebarextralowmod: 0x02E9,
25891 tonebarhighmod: 0x02E6,
25892 tonebarlowmod: 0x02E8,
25893 tonebarmidmod: 0x02E7,
25894 tonefive: 0x01BD,
25895 tonesix: 0x0185,
25896 tonetwo: 0x01A8,
25897 tonos: 0x0384,
25898 tonsquare: 0x3327,
25899 topatakthai: 0x0E0F,
25900 tortoiseshellbracketleft: 0x3014,
25901 tortoiseshellbracketleftsmall: 0xFE5D,
25902 tortoiseshellbracketleftvertical: 0xFE39,
25903 tortoiseshellbracketright: 0x3015,
25904 tortoiseshellbracketrightsmall: 0xFE5E,
25905 tortoiseshellbracketrightvertical: 0xFE3A,
25906 totaothai: 0x0E15,
25907 tpalatalhook: 0x01AB,
25908 tparen: 0x24AF,
25909 trademark: 0x2122,
25910 trademarksans: 0xF8EA,
25911 trademarkserif: 0xF6DB,
25912 tretroflexhook: 0x0288,
25913 triagdn: 0x25BC,
25914 triaglf: 0x25C4,
25915 triagrt: 0x25BA,
25916 triagup: 0x25B2,
25917 ts: 0x02A6,
25918 tsadi: 0x05E6,
25919 tsadidagesh: 0xFB46,
25920 tsadidageshhebrew: 0xFB46,
25921 tsadihebrew: 0x05E6,
25922 tsecyrillic: 0x0446,
25923 tsere: 0x05B5,
25924 tsere12: 0x05B5,
25925 tsere1e: 0x05B5,
25926 tsere2b: 0x05B5,
25927 tserehebrew: 0x05B5,
25928 tserenarrowhebrew: 0x05B5,
25929 tserequarterhebrew: 0x05B5,
25930 tserewidehebrew: 0x05B5,
25931 tshecyrillic: 0x045B,
25932 tsuperior: 0xF6F3,
25933 ttabengali: 0x099F,
25934 ttadeva: 0x091F,
25935 ttagujarati: 0x0A9F,
25936 ttagurmukhi: 0x0A1F,
25937 tteharabic: 0x0679,
25938 ttehfinalarabic: 0xFB67,
25939 ttehinitialarabic: 0xFB68,
25940 ttehmedialarabic: 0xFB69,
25941 tthabengali: 0x09A0,
25942 tthadeva: 0x0920,
25943 tthagujarati: 0x0AA0,
25944 tthagurmukhi: 0x0A20,
25945 tturned: 0x0287,
25946 tuhiragana: 0x3064,
25947 tukatakana: 0x30C4,
25948 tukatakanahalfwidth: 0xFF82,
25949 tusmallhiragana: 0x3063,
25950 tusmallkatakana: 0x30C3,
25951 tusmallkatakanahalfwidth: 0xFF6F,
25952 twelvecircle: 0x246B,
25953 twelveparen: 0x247F,
25954 twelveperiod: 0x2493,
25955 twelveroman: 0x217B,
25956 twentycircle: 0x2473,
25957 twentyhangzhou: 0x5344,
25958 twentyparen: 0x2487,
25959 twentyperiod: 0x249B,
25960 two: 0x0032,
25961 twoarabic: 0x0662,
25962 twobengali: 0x09E8,
25963 twocircle: 0x2461,
25964 twocircleinversesansserif: 0x278B,
25965 twodeva: 0x0968,
25966 twodotenleader: 0x2025,
25967 twodotleader: 0x2025,
25968 twodotleadervertical: 0xFE30,
25969 twogujarati: 0x0AE8,
25970 twogurmukhi: 0x0A68,
25971 twohackarabic: 0x0662,
25972 twohangzhou: 0x3022,
25973 twoideographicparen: 0x3221,
25974 twoinferior: 0x2082,
25975 twomonospace: 0xFF12,
25976 twonumeratorbengali: 0x09F5,
25977 twooldstyle: 0xF732,
25978 twoparen: 0x2475,
25979 twoperiod: 0x2489,
25980 twopersian: 0x06F2,
25981 tworoman: 0x2171,
25982 twostroke: 0x01BB,
25983 twosuperior: 0x00B2,
25984 twothai: 0x0E52,
25985 twothirds: 0x2154,
25986 u: 0x0075,
25987 uacute: 0x00FA,
25988 ubar: 0x0289,
25989 ubengali: 0x0989,
25990 ubopomofo: 0x3128,
25991 ubreve: 0x016D,
25992 ucaron: 0x01D4,
25993 ucircle: 0x24E4,
25994 ucircumflex: 0x00FB,
25995 ucircumflexbelow: 0x1E77,
25996 ucyrillic: 0x0443,
25997 udattadeva: 0x0951,
25998 udblacute: 0x0171,
25999 udblgrave: 0x0215,
26000 udeva: 0x0909,
26001 udieresis: 0x00FC,
26002 udieresisacute: 0x01D8,
26003 udieresisbelow: 0x1E73,
26004 udieresiscaron: 0x01DA,
26005 udieresiscyrillic: 0x04F1,
26006 udieresisgrave: 0x01DC,
26007 udieresismacron: 0x01D6,
26008 udotbelow: 0x1EE5,
26009 ugrave: 0x00F9,
26010 ugujarati: 0x0A89,
26011 ugurmukhi: 0x0A09,
26012 uhiragana: 0x3046,
26013 uhookabove: 0x1EE7,
26014 uhorn: 0x01B0,
26015 uhornacute: 0x1EE9,
26016 uhorndotbelow: 0x1EF1,
26017 uhorngrave: 0x1EEB,
26018 uhornhookabove: 0x1EED,
26019 uhorntilde: 0x1EEF,
26020 uhungarumlaut: 0x0171,
26021 uhungarumlautcyrillic: 0x04F3,
26022 uinvertedbreve: 0x0217,
26023 ukatakana: 0x30A6,
26024 ukatakanahalfwidth: 0xFF73,
26025 ukcyrillic: 0x0479,
26026 ukorean: 0x315C,
26027 umacron: 0x016B,
26028 umacroncyrillic: 0x04EF,
26029 umacrondieresis: 0x1E7B,
26030 umatragurmukhi: 0x0A41,
26031 umonospace: 0xFF55,
26032 underscore: 0x005F,
26033 underscoredbl: 0x2017,
26034 underscoremonospace: 0xFF3F,
26035 underscorevertical: 0xFE33,
26036 underscorewavy: 0xFE4F,
26037 union: 0x222A,
26038 universal: 0x2200,
26039 uogonek: 0x0173,
26040 uparen: 0x24B0,
26041 upblock: 0x2580,
26042 upperdothebrew: 0x05C4,
26043 upsilon: 0x03C5,
26044 upsilondieresis: 0x03CB,
26045 upsilondieresistonos: 0x03B0,
26046 upsilonlatin: 0x028A,
26047 upsilontonos: 0x03CD,
26048 uptackbelowcmb: 0x031D,
26049 uptackmod: 0x02D4,
26050 uragurmukhi: 0x0A73,
26051 uring: 0x016F,
26052 ushortcyrillic: 0x045E,
26053 usmallhiragana: 0x3045,
26054 usmallkatakana: 0x30A5,
26055 usmallkatakanahalfwidth: 0xFF69,
26056 ustraightcyrillic: 0x04AF,
26057 ustraightstrokecyrillic: 0x04B1,
26058 utilde: 0x0169,
26059 utildeacute: 0x1E79,
26060 utildebelow: 0x1E75,
26061 uubengali: 0x098A,
26062 uudeva: 0x090A,
26063 uugujarati: 0x0A8A,
26064 uugurmukhi: 0x0A0A,
26065 uumatragurmukhi: 0x0A42,
26066 uuvowelsignbengali: 0x09C2,
26067 uuvowelsigndeva: 0x0942,
26068 uuvowelsigngujarati: 0x0AC2,
26069 uvowelsignbengali: 0x09C1,
26070 uvowelsigndeva: 0x0941,
26071 uvowelsigngujarati: 0x0AC1,
26072 v: 0x0076,
26073 vadeva: 0x0935,
26074 vagujarati: 0x0AB5,
26075 vagurmukhi: 0x0A35,
26076 vakatakana: 0x30F7,
26077 vav: 0x05D5,
26078 vavdagesh: 0xFB35,
26079 vavdagesh65: 0xFB35,
26080 vavdageshhebrew: 0xFB35,
26081 vavhebrew: 0x05D5,
26082 vavholam: 0xFB4B,
26083 vavholamhebrew: 0xFB4B,
26084 vavvavhebrew: 0x05F0,
26085 vavyodhebrew: 0x05F1,
26086 vcircle: 0x24E5,
26087 vdotbelow: 0x1E7F,
26088 vecyrillic: 0x0432,
26089 veharabic: 0x06A4,
26090 vehfinalarabic: 0xFB6B,
26091 vehinitialarabic: 0xFB6C,
26092 vehmedialarabic: 0xFB6D,
26093 vekatakana: 0x30F9,
26094 venus: 0x2640,
26095 verticalbar: 0x007C,
26096 verticallineabovecmb: 0x030D,
26097 verticallinebelowcmb: 0x0329,
26098 verticallinelowmod: 0x02CC,
26099 verticallinemod: 0x02C8,
26100 vewarmenian: 0x057E,
26101 vhook: 0x028B,
26102 vikatakana: 0x30F8,
26103 viramabengali: 0x09CD,
26104 viramadeva: 0x094D,
26105 viramagujarati: 0x0ACD,
26106 visargabengali: 0x0983,
26107 visargadeva: 0x0903,
26108 visargagujarati: 0x0A83,
26109 vmonospace: 0xFF56,
26110 voarmenian: 0x0578,
26111 voicediterationhiragana: 0x309E,
26112 voicediterationkatakana: 0x30FE,
26113 voicedmarkkana: 0x309B,
26114 voicedmarkkanahalfwidth: 0xFF9E,
26115 vokatakana: 0x30FA,
26116 vparen: 0x24B1,
26117 vtilde: 0x1E7D,
26118 vturned: 0x028C,
26119 vuhiragana: 0x3094,
26120 vukatakana: 0x30F4,
26121 w: 0x0077,
26122 wacute: 0x1E83,
26123 waekorean: 0x3159,
26124 wahiragana: 0x308F,
26125 wakatakana: 0x30EF,
26126 wakatakanahalfwidth: 0xFF9C,
26127 wakorean: 0x3158,
26128 wasmallhiragana: 0x308E,
26129 wasmallkatakana: 0x30EE,
26130 wattosquare: 0x3357,
26131 wavedash: 0x301C,
26132 wavyunderscorevertical: 0xFE34,
26133 wawarabic: 0x0648,
26134 wawfinalarabic: 0xFEEE,
26135 wawhamzaabovearabic: 0x0624,
26136 wawhamzaabovefinalarabic: 0xFE86,
26137 wbsquare: 0x33DD,
26138 wcircle: 0x24E6,
26139 wcircumflex: 0x0175,
26140 wdieresis: 0x1E85,
26141 wdotaccent: 0x1E87,
26142 wdotbelow: 0x1E89,
26143 wehiragana: 0x3091,
26144 weierstrass: 0x2118,
26145 wekatakana: 0x30F1,
26146 wekorean: 0x315E,
26147 weokorean: 0x315D,
26148 wgrave: 0x1E81,
26149 whitebullet: 0x25E6,
26150 whitecircle: 0x25CB,
26151 whitecircleinverse: 0x25D9,
26152 whitecornerbracketleft: 0x300E,
26153 whitecornerbracketleftvertical: 0xFE43,
26154 whitecornerbracketright: 0x300F,
26155 whitecornerbracketrightvertical: 0xFE44,
26156 whitediamond: 0x25C7,
26157 whitediamondcontainingblacksmalldiamond: 0x25C8,
26158 whitedownpointingsmalltriangle: 0x25BF,
26159 whitedownpointingtriangle: 0x25BD,
26160 whiteleftpointingsmalltriangle: 0x25C3,
26161 whiteleftpointingtriangle: 0x25C1,
26162 whitelenticularbracketleft: 0x3016,
26163 whitelenticularbracketright: 0x3017,
26164 whiterightpointingsmalltriangle: 0x25B9,
26165 whiterightpointingtriangle: 0x25B7,
26166 whitesmallsquare: 0x25AB,
26167 whitesmilingface: 0x263A,
26168 whitesquare: 0x25A1,
26169 whitestar: 0x2606,
26170 whitetelephone: 0x260F,
26171 whitetortoiseshellbracketleft: 0x3018,
26172 whitetortoiseshellbracketright: 0x3019,
26173 whiteuppointingsmalltriangle: 0x25B5,
26174 whiteuppointingtriangle: 0x25B3,
26175 wihiragana: 0x3090,
26176 wikatakana: 0x30F0,
26177 wikorean: 0x315F,
26178 wmonospace: 0xFF57,
26179 wohiragana: 0x3092,
26180 wokatakana: 0x30F2,
26181 wokatakanahalfwidth: 0xFF66,
26182 won: 0x20A9,
26183 wonmonospace: 0xFFE6,
26184 wowaenthai: 0x0E27,
26185 wparen: 0x24B2,
26186 wring: 0x1E98,
26187 wsuperior: 0x02B7,
26188 wturned: 0x028D,
26189 wynn: 0x01BF,
26190 x: 0x0078,
26191 xabovecmb: 0x033D,
26192 xbopomofo: 0x3112,
26193 xcircle: 0x24E7,
26194 xdieresis: 0x1E8D,
26195 xdotaccent: 0x1E8B,
26196 xeharmenian: 0x056D,
26197 xi: 0x03BE,
26198 xmonospace: 0xFF58,
26199 xparen: 0x24B3,
26200 xsuperior: 0x02E3,
26201 y: 0x0079,
26202 yaadosquare: 0x334E,
26203 yabengali: 0x09AF,
26204 yacute: 0x00FD,
26205 yadeva: 0x092F,
26206 yaekorean: 0x3152,
26207 yagujarati: 0x0AAF,
26208 yagurmukhi: 0x0A2F,
26209 yahiragana: 0x3084,
26210 yakatakana: 0x30E4,
26211 yakatakanahalfwidth: 0xFF94,
26212 yakorean: 0x3151,
26213 yamakkanthai: 0x0E4E,
26214 yasmallhiragana: 0x3083,
26215 yasmallkatakana: 0x30E3,
26216 yasmallkatakanahalfwidth: 0xFF6C,
26217 yatcyrillic: 0x0463,
26218 ycircle: 0x24E8,
26219 ycircumflex: 0x0177,
26220 ydieresis: 0x00FF,
26221 ydotaccent: 0x1E8F,
26222 ydotbelow: 0x1EF5,
26223 yeharabic: 0x064A,
26224 yehbarreearabic: 0x06D2,
26225 yehbarreefinalarabic: 0xFBAF,
26226 yehfinalarabic: 0xFEF2,
26227 yehhamzaabovearabic: 0x0626,
26228 yehhamzaabovefinalarabic: 0xFE8A,
26229 yehhamzaaboveinitialarabic: 0xFE8B,
26230 yehhamzaabovemedialarabic: 0xFE8C,
26231 yehinitialarabic: 0xFEF3,
26232 yehmedialarabic: 0xFEF4,
26233 yehmeeminitialarabic: 0xFCDD,
26234 yehmeemisolatedarabic: 0xFC58,
26235 yehnoonfinalarabic: 0xFC94,
26236 yehthreedotsbelowarabic: 0x06D1,
26237 yekorean: 0x3156,
26238 yen: 0x00A5,
26239 yenmonospace: 0xFFE5,
26240 yeokorean: 0x3155,
26241 yeorinhieuhkorean: 0x3186,
26242 yerahbenyomohebrew: 0x05AA,
26243 yerahbenyomolefthebrew: 0x05AA,
26244 yericyrillic: 0x044B,
26245 yerudieresiscyrillic: 0x04F9,
26246 yesieungkorean: 0x3181,
26247 yesieungpansioskorean: 0x3183,
26248 yesieungsioskorean: 0x3182,
26249 yetivhebrew: 0x059A,
26250 ygrave: 0x1EF3,
26251 yhook: 0x01B4,
26252 yhookabove: 0x1EF7,
26253 yiarmenian: 0x0575,
26254 yicyrillic: 0x0457,
26255 yikorean: 0x3162,
26256 yinyang: 0x262F,
26257 yiwnarmenian: 0x0582,
26258 ymonospace: 0xFF59,
26259 yod: 0x05D9,
26260 yoddagesh: 0xFB39,
26261 yoddageshhebrew: 0xFB39,
26262 yodhebrew: 0x05D9,
26263 yodyodhebrew: 0x05F2,
26264 yodyodpatahhebrew: 0xFB1F,
26265 yohiragana: 0x3088,
26266 yoikorean: 0x3189,
26267 yokatakana: 0x30E8,
26268 yokatakanahalfwidth: 0xFF96,
26269 yokorean: 0x315B,
26270 yosmallhiragana: 0x3087,
26271 yosmallkatakana: 0x30E7,
26272 yosmallkatakanahalfwidth: 0xFF6E,
26273 yotgreek: 0x03F3,
26274 yoyaekorean: 0x3188,
26275 yoyakorean: 0x3187,
26276 yoyakthai: 0x0E22,
26277 yoyingthai: 0x0E0D,
26278 yparen: 0x24B4,
26279 ypogegrammeni: 0x037A,
26280 ypogegrammenigreekcmb: 0x0345,
26281 yr: 0x01A6,
26282 yring: 0x1E99,
26283 ysuperior: 0x02B8,
26284 ytilde: 0x1EF9,
26285 yturned: 0x028E,
26286 yuhiragana: 0x3086,
26287 yuikorean: 0x318C,
26288 yukatakana: 0x30E6,
26289 yukatakanahalfwidth: 0xFF95,
26290 yukorean: 0x3160,
26291 yusbigcyrillic: 0x046B,
26292 yusbigiotifiedcyrillic: 0x046D,
26293 yuslittlecyrillic: 0x0467,
26294 yuslittleiotifiedcyrillic: 0x0469,
26295 yusmallhiragana: 0x3085,
26296 yusmallkatakana: 0x30E5,
26297 yusmallkatakanahalfwidth: 0xFF6D,
26298 yuyekorean: 0x318B,
26299 yuyeokorean: 0x318A,
26300 yyabengali: 0x09DF,
26301 yyadeva: 0x095F,
26302 z: 0x007A,
26303 zaarmenian: 0x0566,
26304 zacute: 0x017A,
26305 zadeva: 0x095B,
26306 zagurmukhi: 0x0A5B,
26307 zaharabic: 0x0638,
26308 zahfinalarabic: 0xFEC6,
26309 zahinitialarabic: 0xFEC7,
26310 zahiragana: 0x3056,
26311 zahmedialarabic: 0xFEC8,
26312 zainarabic: 0x0632,
26313 zainfinalarabic: 0xFEB0,
26314 zakatakana: 0x30B6,
26315 zaqefgadolhebrew: 0x0595,
26316 zaqefqatanhebrew: 0x0594,
26317 zarqahebrew: 0x0598,
26318 zayin: 0x05D6,
26319 zayindagesh: 0xFB36,
26320 zayindageshhebrew: 0xFB36,
26321 zayinhebrew: 0x05D6,
26322 zbopomofo: 0x3117,
26323 zcaron: 0x017E,
26324 zcircle: 0x24E9,
26325 zcircumflex: 0x1E91,
26326 zcurl: 0x0291,
26327 zdot: 0x017C,
26328 zdotaccent: 0x017C,
26329 zdotbelow: 0x1E93,
26330 zecyrillic: 0x0437,
26331 zedescendercyrillic: 0x0499,
26332 zedieresiscyrillic: 0x04DF,
26333 zehiragana: 0x305C,
26334 zekatakana: 0x30BC,
26335 zero: 0x0030,
26336 zeroarabic: 0x0660,
26337 zerobengali: 0x09E6,
26338 zerodeva: 0x0966,
26339 zerogujarati: 0x0AE6,
26340 zerogurmukhi: 0x0A66,
26341 zerohackarabic: 0x0660,
26342 zeroinferior: 0x2080,
26343 zeromonospace: 0xFF10,
26344 zerooldstyle: 0xF730,
26345 zeropersian: 0x06F0,
26346 zerosuperior: 0x2070,
26347 zerothai: 0x0E50,
26348 zerowidthjoiner: 0xFEFF,
26349 zerowidthnonjoiner: 0x200C,
26350 zerowidthspace: 0x200B,
26351 zeta: 0x03B6,
26352 zhbopomofo: 0x3113,
26353 zhearmenian: 0x056A,
26354 zhebrevecyrillic: 0x04C2,
26355 zhecyrillic: 0x0436,
26356 zhedescendercyrillic: 0x0497,
26357 zhedieresiscyrillic: 0x04DD,
26358 zihiragana: 0x3058,
26359 zikatakana: 0x30B8,
26360 zinorhebrew: 0x05AE,
26361 zlinebelow: 0x1E95,
26362 zmonospace: 0xFF5A,
26363 zohiragana: 0x305E,
26364 zokatakana: 0x30BE,
26365 zparen: 0x24B5,
26366 zretroflexhook: 0x0290,
26367 zstroke: 0x01B6,
26368 zuhiragana: 0x305A,
26369 zukatakana: 0x30BA,
26370 '.notdef': 0x0000
26371 };
26372
26373 var DingbatsGlyphsUnicode = {
26374 space: 0x0020,
26375 a1: 0x2701,
26376 a2: 0x2702,
26377 a202: 0x2703,
26378 a3: 0x2704,
26379 a4: 0x260E,
26380 a5: 0x2706,
26381 a119: 0x2707,
26382 a118: 0x2708,
26383 a117: 0x2709,
26384 a11: 0x261B,
26385 a12: 0x261E,
26386 a13: 0x270C,
26387 a14: 0x270D,
26388 a15: 0x270E,
26389 a16: 0x270F,
26390 a105: 0x2710,
26391 a17: 0x2711,
26392 a18: 0x2712,
26393 a19: 0x2713,
26394 a20: 0x2714,
26395 a21: 0x2715,
26396 a22: 0x2716,
26397 a23: 0x2717,
26398 a24: 0x2718,
26399 a25: 0x2719,
26400 a26: 0x271A,
26401 a27: 0x271B,
26402 a28: 0x271C,
26403 a6: 0x271D,
26404 a7: 0x271E,
26405 a8: 0x271F,
26406 a9: 0x2720,
26407 a10: 0x2721,
26408 a29: 0x2722,
26409 a30: 0x2723,
26410 a31: 0x2724,
26411 a32: 0x2725,
26412 a33: 0x2726,
26413 a34: 0x2727,
26414 a35: 0x2605,
26415 a36: 0x2729,
26416 a37: 0x272A,
26417 a38: 0x272B,
26418 a39: 0x272C,
26419 a40: 0x272D,
26420 a41: 0x272E,
26421 a42: 0x272F,
26422 a43: 0x2730,
26423 a44: 0x2731,
26424 a45: 0x2732,
26425 a46: 0x2733,
26426 a47: 0x2734,
26427 a48: 0x2735,
26428 a49: 0x2736,
26429 a50: 0x2737,
26430 a51: 0x2738,
26431 a52: 0x2739,
26432 a53: 0x273A,
26433 a54: 0x273B,
26434 a55: 0x273C,
26435 a56: 0x273D,
26436 a57: 0x273E,
26437 a58: 0x273F,
26438 a59: 0x2740,
26439 a60: 0x2741,
26440 a61: 0x2742,
26441 a62: 0x2743,
26442 a63: 0x2744,
26443 a64: 0x2745,
26444 a65: 0x2746,
26445 a66: 0x2747,
26446 a67: 0x2748,
26447 a68: 0x2749,
26448 a69: 0x274A,
26449 a70: 0x274B,
26450 a71: 0x25CF,
26451 a72: 0x274D,
26452 a73: 0x25A0,
26453 a74: 0x274F,
26454 a203: 0x2750,
26455 a75: 0x2751,
26456 a204: 0x2752,
26457 a76: 0x25B2,
26458 a77: 0x25BC,
26459 a78: 0x25C6,
26460 a79: 0x2756,
26461 a81: 0x25D7,
26462 a82: 0x2758,
26463 a83: 0x2759,
26464 a84: 0x275A,
26465 a97: 0x275B,
26466 a98: 0x275C,
26467 a99: 0x275D,
26468 a100: 0x275E,
26469 a101: 0x2761,
26470 a102: 0x2762,
26471 a103: 0x2763,
26472 a104: 0x2764,
26473 a106: 0x2765,
26474 a107: 0x2766,
26475 a108: 0x2767,
26476 a112: 0x2663,
26477 a111: 0x2666,
26478 a110: 0x2665,
26479 a109: 0x2660,
26480 a120: 0x2460,
26481 a121: 0x2461,
26482 a122: 0x2462,
26483 a123: 0x2463,
26484 a124: 0x2464,
26485 a125: 0x2465,
26486 a126: 0x2466,
26487 a127: 0x2467,
26488 a128: 0x2468,
26489 a129: 0x2469,
26490 a130: 0x2776,
26491 a131: 0x2777,
26492 a132: 0x2778,
26493 a133: 0x2779,
26494 a134: 0x277A,
26495 a135: 0x277B,
26496 a136: 0x277C,
26497 a137: 0x277D,
26498 a138: 0x277E,
26499 a139: 0x277F,
26500 a140: 0x2780,
26501 a141: 0x2781,
26502 a142: 0x2782,
26503 a143: 0x2783,
26504 a144: 0x2784,
26505 a145: 0x2785,
26506 a146: 0x2786,
26507 a147: 0x2787,
26508 a148: 0x2788,
26509 a149: 0x2789,
26510 a150: 0x278A,
26511 a151: 0x278B,
26512 a152: 0x278C,
26513 a153: 0x278D,
26514 a154: 0x278E,
26515 a155: 0x278F,
26516 a156: 0x2790,
26517 a157: 0x2791,
26518 a158: 0x2792,
26519 a159: 0x2793,
26520 a160: 0x2794,
26521 a161: 0x2192,
26522 a163: 0x2194,
26523 a164: 0x2195,
26524 a196: 0x2798,
26525 a165: 0x2799,
26526 a192: 0x279A,
26527 a166: 0x279B,
26528 a167: 0x279C,
26529 a168: 0x279D,
26530 a169: 0x279E,
26531 a170: 0x279F,
26532 a171: 0x27A0,
26533 a172: 0x27A1,
26534 a173: 0x27A2,
26535 a162: 0x27A3,
26536 a174: 0x27A4,
26537 a175: 0x27A5,
26538 a176: 0x27A6,
26539 a177: 0x27A7,
26540 a178: 0x27A8,
26541 a179: 0x27A9,
26542 a193: 0x27AA,
26543 a180: 0x27AB,
26544 a199: 0x27AC,
26545 a181: 0x27AD,
26546 a200: 0x27AE,
26547 a182: 0x27AF,
26548 a201: 0x27B1,
26549 a183: 0x27B2,
26550 a184: 0x27B3,
26551 a197: 0x27B4,
26552 a185: 0x27B5,
26553 a194: 0x27B6,
26554 a198: 0x27B7,
26555 a186: 0x27B8,
26556 a195: 0x27B9,
26557 a187: 0x27BA,
26558 a188: 0x27BB,
26559 a189: 0x27BC,
26560 a190: 0x27BD,
26561 a191: 0x27BE,
26562 a89: 0x2768, // 0xF8D7
26563 a90: 0x2769, // 0xF8D8
26564 a93: 0x276A, // 0xF8D9
26565 a94: 0x276B, // 0xF8DA
26566 a91: 0x276C, // 0xF8DB
26567 a92: 0x276D, // 0xF8DC
26568 a205: 0x276E, // 0xF8DD
26569 a85: 0x276F, // 0xF8DE
26570 a206: 0x2770, // 0xF8DF
26571 a86: 0x2771, // 0xF8E0
26572 a87: 0x2772, // 0xF8E1
26573 a88: 0x2773, // 0xF8E2
26574 a95: 0x2774, // 0xF8E3
26575 a96: 0x2775, // 0xF8E4
26576 '.notdef': 0x0000
26577 };
26578
26579
26580 var PDFImage = (function PDFImageClosure() {
26581 /**
26582 * Decode the image in the main thread if it supported. Resovles the promise
26583 * when the image data is ready.
26584 */
26585 function handleImageData(handler, xref, res, image) {
26586 if (image instanceof JpegStream && image.isNativelyDecodable(xref, res)) {
26587 // For natively supported jpegs send them to the main thread for decoding.
26588 var dict = image.dict;
26589 var colorSpace = dict.get('ColorSpace', 'CS');
26590 colorSpace = ColorSpace.parse(colorSpace, xref, res);
26591 var numComps = colorSpace.numComps;
26592 var decodePromise = handler.sendWithPromise('JpegDecode',
26593 [image.getIR(), numComps]);
26594 return decodePromise.then(function (message) {
26595 var data = message.data;
26596 return new Stream(data, 0, data.length, image.dict);
26597 });
26598 } else {
26599 return Promise.resolve(image);
26600 }
26601 }
26602
26603 /**
26604 * Decode and clamp a value. The formula is different from the spec because we
26605 * don't decode to float range [0,1], we decode it in the [0,max] range.
26606 */
26607 function decodeAndClamp(value, addend, coefficient, max) {
26608 value = addend + value * coefficient;
26609 // Clamp the value to the range
26610 return (value < 0 ? 0 : (value > max ? max : value));
26611 }
26612
26613 function PDFImage(xref, res, image, inline, smask, mask, isMask) {
26614 this.image = image;
26615 var dict = image.dict;
26616 if (dict.has('Filter')) {
26617 var filter = dict.get('Filter').name;
26618 if (filter === 'JPXDecode') {
26619 var jpxImage = new JpxImage();
26620 jpxImage.parseImageProperties(image.stream);
26621 image.stream.reset();
26622 image.bitsPerComponent = jpxImage.bitsPerComponent;
26623 image.numComps = jpxImage.componentsCount;
26624 } else if (filter === 'JBIG2Decode') {
26625 image.bitsPerComponent = 1;
26626 image.numComps = 1;
26627 }
26628 }
26629 // TODO cache rendered images?
26630
26631 this.width = dict.get('Width', 'W');
26632 this.height = dict.get('Height', 'H');
26633
26634 if (this.width < 1 || this.height < 1) {
26635 error('Invalid image width: ' + this.width + ' or height: ' +
26636 this.height);
26637 }
26638
26639 this.interpolate = dict.get('Interpolate', 'I') || false;
26640 this.imageMask = dict.get('ImageMask', 'IM') || false;
26641 this.matte = dict.get('Matte') || false;
26642
26643 var bitsPerComponent = image.bitsPerComponent;
26644 if (!bitsPerComponent) {
26645 bitsPerComponent = dict.get('BitsPerComponent', 'BPC');
26646 if (!bitsPerComponent) {
26647 if (this.imageMask) {
26648 bitsPerComponent = 1;
26649 } else {
26650 error('Bits per component missing in image: ' + this.imageMask);
26651 }
26652 }
26653 }
26654 this.bpc = bitsPerComponent;
26655
26656 if (!this.imageMask) {
26657 var colorSpace = dict.get('ColorSpace', 'CS');
26658 if (!colorSpace) {
26659 info('JPX images (which do not require color spaces)');
26660 switch (image.numComps) {
26661 case 1:
26662 colorSpace = Name.get('DeviceGray');
26663 break;
26664 case 3:
26665 colorSpace = Name.get('DeviceRGB');
26666 break;
26667 case 4:
26668 colorSpace = Name.get('DeviceCMYK');
26669 break;
26670 default:
26671 error('JPX images with ' + this.numComps +
26672 ' color components not supported.');
26673 }
26674 }
26675 this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
26676 this.numComps = this.colorSpace.numComps;
26677 }
26678
26679 this.decode = dict.get('Decode', 'D');
26680 this.needsDecode = false;
26681 if (this.decode &&
26682 ((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) ||
26683 (isMask && !ColorSpace.isDefaultDecode(this.decode, 1)))) {
26684 this.needsDecode = true;
26685 // Do some preprocessing to avoid more math.
26686 var max = (1 << bitsPerComponent) - 1;
26687 this.decodeCoefficients = [];
26688 this.decodeAddends = [];
26689 for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
26690 var dmin = this.decode[i];
26691 var dmax = this.decode[i + 1];
26692 this.decodeCoefficients[j] = dmax - dmin;
26693 this.decodeAddends[j] = max * dmin;
26694 }
26695 }
26696
26697 if (smask) {
26698 this.smask = new PDFImage(xref, res, smask, false);
26699 } else if (mask) {
26700 if (isStream(mask)) {
26701 this.mask = new PDFImage(xref, res, mask, false, null, null, true);
26702 } else {
26703 // Color key mask (just an array).
26704 this.mask = mask;
26705 }
26706 }
26707 }
26708 /**
26709 * Handles processing of image data and returns the Promise that is resolved
26710 * with a PDFImage when the image is ready to be used.
26711 */
26712 PDFImage.buildImage = function PDFImage_buildImage(handler, xref,
26713 res, image, inline) {
26714 var imagePromise = handleImageData(handler, xref, res, image);
26715 var smaskPromise;
26716 var maskPromise;
26717
26718 var smask = image.dict.get('SMask');
26719 var mask = image.dict.get('Mask');
26720
26721 if (smask) {
26722 smaskPromise = handleImageData(handler, xref, res, smask);
26723 maskPromise = Promise.resolve(null);
26724 } else {
26725 smaskPromise = Promise.resolve(null);
26726 if (mask) {
26727 if (isStream(mask)) {
26728 maskPromise = handleImageData(handler, xref, res, mask);
26729 } else if (isArray(mask)) {
26730 maskPromise = Promise.resolve(mask);
26731 } else {
26732 warn('Unsupported mask format.');
26733 maskPromise = Promise.resolve(null);
26734 }
26735 } else {
26736 maskPromise = Promise.resolve(null);
26737 }
26738 }
26739 return Promise.all([imagePromise, smaskPromise, maskPromise]).then(
26740 function(results) {
26741 var imageData = results[0];
26742 var smaskData = results[1];
26743 var maskData = results[2];
26744 return new PDFImage(xref, res, imageData, inline, smaskData, maskData);
26745 });
26746 };
26747
26748 /**
26749 * Resize an image using the nearest neighbor algorithm. Currently only
26750 * supports one and three component images.
26751 * @param {TypedArray} pixels The original image with one component.
26752 * @param {Number} bpc Number of bits per component.
26753 * @param {Number} components Number of color components, 1 or 3 is supported.
26754 * @param {Number} w1 Original width.
26755 * @param {Number} h1 Original height.
26756 * @param {Number} w2 New width.
26757 * @param {Number} h2 New height.
26758 * @param {TypedArray} dest (Optional) The destination buffer.
26759 * @param {Number} alpha01 (Optional) Size reserved for the alpha channel.
26760 * @return {TypedArray} Resized image data.
26761 */
26762 PDFImage.resize = function PDFImage_resize(pixels, bpc, components,
26763 w1, h1, w2, h2, dest, alpha01) {
26764
26765 if (components !== 1 && components !== 3) {
26766 error('Unsupported component count for resizing.');
26767 }
26768
26769 var length = w2 * h2 * components;
26770 var temp = dest ? dest : (bpc <= 8 ? new Uint8Array(length) :
26771 (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
26772 var xRatio = w1 / w2;
26773 var yRatio = h1 / h2;
26774 var i, j, py, newIndex = 0, oldIndex;
26775 var xScaled = new Uint16Array(w2);
26776 var w1Scanline = w1 * components;
26777 if (alpha01 !== 1) {
26778 alpha01 = 0;
26779 }
26780
26781 for (j = 0; j < w2; j++) {
26782 xScaled[j] = Math.floor(j * xRatio) * components;
26783 }
26784
26785 if (components === 1) {
26786 for (i = 0; i < h2; i++) {
26787 py = Math.floor(i * yRatio) * w1Scanline;
26788 for (j = 0; j < w2; j++) {
26789 oldIndex = py + xScaled[j];
26790 temp[newIndex++] = pixels[oldIndex];
26791 }
26792 }
26793 } else if (components === 3) {
26794 for (i = 0; i < h2; i++) {
26795 py = Math.floor(i * yRatio) * w1Scanline;
26796 for (j = 0; j < w2; j++) {
26797 oldIndex = py + xScaled[j];
26798 temp[newIndex++] = pixels[oldIndex++];
26799 temp[newIndex++] = pixels[oldIndex++];
26800 temp[newIndex++] = pixels[oldIndex++];
26801 newIndex += alpha01;
26802 }
26803 }
26804 }
26805 return temp;
26806 };
26807
26808 PDFImage.createMask =
26809 function PDFImage_createMask(imgArray, width, height,
26810 imageIsFromDecodeStream, inverseDecode) {
26811
26812 // |imgArray| might not contain full data for every pixel of the mask, so
26813 // we need to distinguish between |computedLength| and |actualLength|.
26814 // In particular, if inverseDecode is true, then the array we return must
26815 // have a length of |computedLength|.
26816
26817 var computedLength = ((width + 7) >> 3) * height;
26818 var actualLength = imgArray.byteLength;
26819 var haveFullData = computedLength === actualLength;
26820 var data, i;
26821
26822 if (imageIsFromDecodeStream && (!inverseDecode || haveFullData)) {
26823 // imgArray came from a DecodeStream and its data is in an appropriate
26824 // form, so we can just transfer it.
26825 data = imgArray;
26826 } else if (!inverseDecode) {
26827 data = new Uint8Array(actualLength);
26828 data.set(imgArray);
26829 } else {
26830 data = new Uint8Array(computedLength);
26831 data.set(imgArray);
26832 for (i = actualLength; i < computedLength; i++) {
26833 data[i] = 0xff;
26834 }
26835 }
26836
26837 // If necessary, invert the original mask data (but not any extra we might
26838 // have added above). It's safe to modify the array -- whether it's the
26839 // original or a copy, we're about to transfer it anyway, so nothing else
26840 // in this thread can be relying on its contents.
26841 if (inverseDecode) {
26842 for (i = 0; i < actualLength; i++) {
26843 data[i] = ~data[i];
26844 }
26845 }
26846
26847 return {data: data, width: width, height: height};
26848 };
26849
26850 PDFImage.prototype = {
26851 get drawWidth() {
26852 return Math.max(this.width,
26853 this.smask && this.smask.width || 0,
26854 this.mask && this.mask.width || 0);
26855 },
26856
26857 get drawHeight() {
26858 return Math.max(this.height,
26859 this.smask && this.smask.height || 0,
26860 this.mask && this.mask.height || 0);
26861 },
26862
26863 decodeBuffer: function PDFImage_decodeBuffer(buffer) {
26864 var bpc = this.bpc;
26865 var numComps = this.numComps;
26866
26867 var decodeAddends = this.decodeAddends;
26868 var decodeCoefficients = this.decodeCoefficients;
26869 var max = (1 << bpc) - 1;
26870 var i, ii;
26871
26872 if (bpc === 1) {
26873 // If the buffer needed decode that means it just needs to be inverted.
26874 for (i = 0, ii = buffer.length; i < ii; i++) {
26875 buffer[i] = +!(buffer[i]);
26876 }
26877 return;
26878 }
26879 var index = 0;
26880 for (i = 0, ii = this.width * this.height; i < ii; i++) {
26881 for (var j = 0; j < numComps; j++) {
26882 buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j],
26883 decodeCoefficients[j], max);
26884 index++;
26885 }
26886 }
26887 },
26888
26889 getComponents: function PDFImage_getComponents(buffer) {
26890 var bpc = this.bpc;
26891
26892 // This image doesn't require any extra work.
26893 if (bpc === 8) {
26894 return buffer;
26895 }
26896
26897 var width = this.width;
26898 var height = this.height;
26899 var numComps = this.numComps;
26900
26901 var length = width * height * numComps;
26902 var bufferPos = 0;
26903 var output = (bpc <= 8 ? new Uint8Array(length) :
26904 (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
26905 var rowComps = width * numComps;
26906
26907 var max = (1 << bpc) - 1;
26908 var i = 0, ii, buf;
26909
26910 if (bpc === 1) {
26911 // Optimization for reading 1 bpc images.
26912 var mask, loop1End, loop2End;
26913 for (var j = 0; j < height; j++) {
26914 loop1End = i + (rowComps & ~7);
26915 loop2End = i + rowComps;
26916
26917 // unroll loop for all full bytes
26918 while (i < loop1End) {
26919 buf = buffer[bufferPos++];
26920 output[i] = (buf >> 7) & 1;
26921 output[i + 1] = (buf >> 6) & 1;
26922 output[i + 2] = (buf >> 5) & 1;
26923 output[i + 3] = (buf >> 4) & 1;
26924 output[i + 4] = (buf >> 3) & 1;
26925 output[i + 5] = (buf >> 2) & 1;
26926 output[i + 6] = (buf >> 1) & 1;
26927 output[i + 7] = buf & 1;
26928 i += 8;
26929 }
26930
26931 // handle remaing bits
26932 if (i < loop2End) {
26933 buf = buffer[bufferPos++];
26934 mask = 128;
26935 while (i < loop2End) {
26936 output[i++] = +!!(buf & mask);
26937 mask >>= 1;
26938 }
26939 }
26940 }
26941 } else {
26942 // The general case that handles all other bpc values.
26943 var bits = 0;
26944 buf = 0;
26945 for (i = 0, ii = length; i < ii; ++i) {
26946 if (i % rowComps === 0) {
26947 buf = 0;
26948 bits = 0;
26949 }
26950
26951 while (bits < bpc) {
26952 buf = (buf << 8) | buffer[bufferPos++];
26953 bits += 8;
26954 }
26955
26956 var remainingBits = bits - bpc;
26957 var value = buf >> remainingBits;
26958 output[i] = (value < 0 ? 0 : (value > max ? max : value));
26959 buf = buf & ((1 << remainingBits) - 1);
26960 bits = remainingBits;
26961 }
26962 }
26963 return output;
26964 },
26965
26966 fillOpacity: function PDFImage_fillOpacity(rgbaBuf, width, height,
26967 actualHeight, image) {
26968 var smask = this.smask;
26969 var mask = this.mask;
26970 var alphaBuf, sw, sh, i, ii, j;
26971
26972 if (smask) {
26973 sw = smask.width;
26974 sh = smask.height;
26975 alphaBuf = new Uint8Array(sw * sh);
26976 smask.fillGrayBuffer(alphaBuf);
26977 if (sw !== width || sh !== height) {
26978 alphaBuf = PDFImage.resize(alphaBuf, smask.bpc, 1, sw, sh, width,
26979 height);
26980 }
26981 } else if (mask) {
26982 if (mask instanceof PDFImage) {
26983 sw = mask.width;
26984 sh = mask.height;
26985 alphaBuf = new Uint8Array(sw * sh);
26986 mask.numComps = 1;
26987 mask.fillGrayBuffer(alphaBuf);
26988
26989 // Need to invert values in rgbaBuf
26990 for (i = 0, ii = sw * sh; i < ii; ++i) {
26991 alphaBuf[i] = 255 - alphaBuf[i];
26992 }
26993
26994 if (sw !== width || sh !== height) {
26995 alphaBuf = PDFImage.resize(alphaBuf, mask.bpc, 1, sw, sh, width,
26996 height);
26997 }
26998 } else if (isArray(mask)) {
26999 // Color key mask: if any of the compontents are outside the range
27000 // then they should be painted.
27001 alphaBuf = new Uint8Array(width * height);
27002 var numComps = this.numComps;
27003 for (i = 0, ii = width * height; i < ii; ++i) {
27004 var opacity = 0;
27005 var imageOffset = i * numComps;
27006 for (j = 0; j < numComps; ++j) {
27007 var color = image[imageOffset + j];
27008 var maskOffset = j * 2;
27009 if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
27010 opacity = 255;
27011 break;
27012 }
27013 }
27014 alphaBuf[i] = opacity;
27015 }
27016 } else {
27017 error('Unknown mask format.');
27018 }
27019 }
27020
27021 if (alphaBuf) {
27022 for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
27023 rgbaBuf[j] = alphaBuf[i];
27024 }
27025 } else {
27026 // No mask.
27027 for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
27028 rgbaBuf[j] = 255;
27029 }
27030 }
27031 },
27032
27033 undoPreblend: function PDFImage_undoPreblend(buffer, width, height) {
27034 var matte = this.smask && this.smask.matte;
27035 if (!matte) {
27036 return;
27037 }
27038 var matteRgb = this.colorSpace.getRgb(matte, 0);
27039 var matteR = matteRgb[0];
27040 var matteG = matteRgb[1];
27041 var matteB = matteRgb[2];
27042 var length = width * height * 4;
27043 var r, g, b;
27044 for (var i = 0; i < length; i += 4) {
27045 var alpha = buffer[i + 3];
27046 if (alpha === 0) {
27047 // according formula we have to get Infinity in all components
27048 // making it white (typical paper color) should be okay
27049 buffer[i] = 255;
27050 buffer[i + 1] = 255;
27051 buffer[i + 2] = 255;
27052 continue;
27053 }
27054 var k = 255 / alpha;
27055 r = (buffer[i] - matteR) * k + matteR;
27056 g = (buffer[i + 1] - matteG) * k + matteG;
27057 b = (buffer[i + 2] - matteB) * k + matteB;
27058 buffer[i] = r <= 0 ? 0 : r >= 255 ? 255 : r | 0;
27059 buffer[i + 1] = g <= 0 ? 0 : g >= 255 ? 255 : g | 0;
27060 buffer[i + 2] = b <= 0 ? 0 : b >= 255 ? 255 : b | 0;
27061 }
27062 },
27063
27064 createImageData: function PDFImage_createImageData(forceRGBA) {
27065 var drawWidth = this.drawWidth;
27066 var drawHeight = this.drawHeight;
27067 var imgData = { // other fields are filled in below
27068 width: drawWidth,
27069 height: drawHeight
27070 };
27071
27072 var numComps = this.numComps;
27073 var originalWidth = this.width;
27074 var originalHeight = this.height;
27075 var bpc = this.bpc;
27076
27077 // Rows start at byte boundary.
27078 var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
27079 var imgArray;
27080
27081 if (!forceRGBA) {
27082 // If it is a 1-bit-per-pixel grayscale (i.e. black-and-white) image
27083 // without any complications, we pass a same-sized copy to the main
27084 // thread rather than expanding by 32x to RGBA form. This saves *lots*
27085 // of memory for many scanned documents. It's also much faster.
27086 //
27087 // Similarly, if it is a 24-bit-per pixel RGB image without any
27088 // complications, we avoid expanding by 1.333x to RGBA form.
27089 var kind;
27090 if (this.colorSpace.name === 'DeviceGray' && bpc === 1) {
27091 kind = ImageKind.GRAYSCALE_1BPP;
27092 } else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8 &&
27093 !this.needsDecode) {
27094 kind = ImageKind.RGB_24BPP;
27095 }
27096 if (kind && !this.smask && !this.mask &&
27097 drawWidth === originalWidth && drawHeight === originalHeight) {
27098 imgData.kind = kind;
27099
27100 imgArray = this.getImageBytes(originalHeight * rowBytes);
27101 // If imgArray came from a DecodeStream, we're safe to transfer it
27102 // (and thus neuter it) because it will constitute the entire
27103 // DecodeStream's data. But if it came from a Stream, we need to
27104 // copy it because it'll only be a portion of the Stream's data, and
27105 // the rest will be read later on.
27106 if (this.image instanceof DecodeStream) {
27107 imgData.data = imgArray;
27108 } else {
27109 var newArray = new Uint8Array(imgArray.length);
27110 newArray.set(imgArray);
27111 imgData.data = newArray;
27112 }
27113 if (this.needsDecode) {
27114 // Invert the buffer (which must be grayscale if we reached here).
27115 assert(kind === ImageKind.GRAYSCALE_1BPP);
27116 var buffer = imgData.data;
27117 for (var i = 0, ii = buffer.length; i < ii; i++) {
27118 buffer[i] ^= 0xff;
27119 }
27120 }
27121 return imgData;
27122 }
27123 if (this.image instanceof JpegStream && !this.smask && !this.mask) {
27124 imgData.kind = ImageKind.RGB_24BPP;
27125 imgData.data = this.getImageBytes(originalHeight * rowBytes,
27126 drawWidth, drawHeight, true);
27127 return imgData;
27128 }
27129 }
27130
27131 imgArray = this.getImageBytes(originalHeight * rowBytes);
27132 // imgArray can be incomplete (e.g. after CCITT fax encoding).
27133 var actualHeight = 0 | (imgArray.length / rowBytes *
27134 drawHeight / originalHeight);
27135
27136 var comps = this.getComponents(imgArray);
27137
27138 // If opacity data is present, use RGBA_32BPP form. Otherwise, use the
27139 // more compact RGB_24BPP form if allowable.
27140 var alpha01, maybeUndoPreblend;
27141 if (!forceRGBA && !this.smask && !this.mask) {
27142 imgData.kind = ImageKind.RGB_24BPP;
27143 imgData.data = new Uint8Array(drawWidth * drawHeight * 3);
27144 alpha01 = 0;
27145 maybeUndoPreblend = false;
27146 } else {
27147 imgData.kind = ImageKind.RGBA_32BPP;
27148 imgData.data = new Uint8Array(drawWidth * drawHeight * 4);
27149 alpha01 = 1;
27150 maybeUndoPreblend = true;
27151
27152 // Color key masking (opacity) must be performed before decoding.
27153 this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight,
27154 comps);
27155 }
27156
27157 if (this.needsDecode) {
27158 this.decodeBuffer(comps);
27159 }
27160 this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight,
27161 drawWidth, drawHeight, actualHeight, bpc, comps,
27162 alpha01);
27163 if (maybeUndoPreblend) {
27164 this.undoPreblend(imgData.data, drawWidth, actualHeight);
27165 }
27166
27167 return imgData;
27168 },
27169
27170 fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {
27171 var numComps = this.numComps;
27172 if (numComps !== 1) {
27173 error('Reading gray scale from a color image: ' + numComps);
27174 }
27175
27176 var width = this.width;
27177 var height = this.height;
27178 var bpc = this.bpc;
27179
27180 // rows start at byte boundary
27181 var rowBytes = (width * numComps * bpc + 7) >> 3;
27182 var imgArray = this.getImageBytes(height * rowBytes);
27183
27184 var comps = this.getComponents(imgArray);
27185 var i, length;
27186
27187 if (bpc === 1) {
27188 // inline decoding (= inversion) for 1 bpc images
27189 length = width * height;
27190 if (this.needsDecode) {
27191 // invert and scale to {0, 255}
27192 for (i = 0; i < length; ++i) {
27193 buffer[i] = (comps[i] - 1) & 255;
27194 }
27195 } else {
27196 // scale to {0, 255}
27197 for (i = 0; i < length; ++i) {
27198 buffer[i] = (-comps[i]) & 255;
27199 }
27200 }
27201 return;
27202 }
27203
27204 if (this.needsDecode) {
27205 this.decodeBuffer(comps);
27206 }
27207 length = width * height;
27208 // we aren't using a colorspace so we need to scale the value
27209 var scale = 255 / ((1 << bpc) - 1);
27210 for (i = 0; i < length; ++i) {
27211 buffer[i] = (scale * comps[i]) | 0;
27212 }
27213 },
27214
27215 getImageBytes: function PDFImage_getImageBytes(length,
27216 drawWidth, drawHeight,
27217 forceRGB) {
27218 this.image.reset();
27219 this.image.drawWidth = drawWidth || this.width;
27220 this.image.drawHeight = drawHeight || this.height;
27221 this.image.forceRGB = !!forceRGB;
27222 return this.image.getBytes(length);
27223 }
27224 };
27225 return PDFImage;
27226 })();
27227
27228
27229 // The Metrics object contains glyph widths (in glyph space units).
27230 // As per PDF spec, for most fonts (Type 3 being an exception) a glyph
27231 // space unit corresponds to 1/1000th of text space unit.
27232 var Metrics = {
27233 'Courier': 600,
27234 'Courier-Bold': 600,
27235 'Courier-BoldOblique': 600,
27236 'Courier-Oblique': 600,
27237 'Helvetica' : {
27238 'space': 278,
27239 'exclam': 278,
27240 'quotedbl': 355,
27241 'numbersign': 556,
27242 'dollar': 556,
27243 'percent': 889,
27244 'ampersand': 667,
27245 'quoteright': 222,
27246 'parenleft': 333,
27247 'parenright': 333,
27248 'asterisk': 389,
27249 'plus': 584,
27250 'comma': 278,
27251 'hyphen': 333,
27252 'period': 278,
27253 'slash': 278,
27254 'zero': 556,
27255 'one': 556,
27256 'two': 556,
27257 'three': 556,
27258 'four': 556,
27259 'five': 556,
27260 'six': 556,
27261 'seven': 556,
27262 'eight': 556,
27263 'nine': 556,
27264 'colon': 278,
27265 'semicolon': 278,
27266 'less': 584,
27267 'equal': 584,
27268 'greater': 584,
27269 'question': 556,
27270 'at': 1015,
27271 'A': 667,
27272 'B': 667,
27273 'C': 722,
27274 'D': 722,
27275 'E': 667,
27276 'F': 611,
27277 'G': 778,
27278 'H': 722,
27279 'I': 278,
27280 'J': 500,
27281 'K': 667,
27282 'L': 556,
27283 'M': 833,
27284 'N': 722,
27285 'O': 778,
27286 'P': 667,
27287 'Q': 778,
27288 'R': 722,
27289 'S': 667,
27290 'T': 611,
27291 'U': 722,
27292 'V': 667,
27293 'W': 944,
27294 'X': 667,
27295 'Y': 667,
27296 'Z': 611,
27297 'bracketleft': 278,
27298 'backslash': 278,
27299 'bracketright': 278,
27300 'asciicircum': 469,
27301 'underscore': 556,
27302 'quoteleft': 222,
27303 'a': 556,
27304 'b': 556,
27305 'c': 500,
27306 'd': 556,
27307 'e': 556,
27308 'f': 278,
27309 'g': 556,
27310 'h': 556,
27311 'i': 222,
27312 'j': 222,
27313 'k': 500,
27314 'l': 222,
27315 'm': 833,
27316 'n': 556,
27317 'o': 556,
27318 'p': 556,
27319 'q': 556,
27320 'r': 333,
27321 's': 500,
27322 't': 278,
27323 'u': 556,
27324 'v': 500,
27325 'w': 722,
27326 'x': 500,
27327 'y': 500,
27328 'z': 500,
27329 'braceleft': 334,
27330 'bar': 260,
27331 'braceright': 334,
27332 'asciitilde': 584,
27333 'exclamdown': 333,
27334 'cent': 556,
27335 'sterling': 556,
27336 'fraction': 167,
27337 'yen': 556,
27338 'florin': 556,
27339 'section': 556,
27340 'currency': 556,
27341 'quotesingle': 191,
27342 'quotedblleft': 333,
27343 'guillemotleft': 556,
27344 'guilsinglleft': 333,
27345 'guilsinglright': 333,
27346 'fi': 500,
27347 'fl': 500,
27348 'endash': 556,
27349 'dagger': 556,
27350 'daggerdbl': 556,
27351 'periodcentered': 278,
27352 'paragraph': 537,
27353 'bullet': 350,
27354 'quotesinglbase': 222,
27355 'quotedblbase': 333,
27356 'quotedblright': 333,
27357 'guillemotright': 556,
27358 'ellipsis': 1000,
27359 'perthousand': 1000,
27360 'questiondown': 611,
27361 'grave': 333,
27362 'acute': 333,
27363 'circumflex': 333,
27364 'tilde': 333,
27365 'macron': 333,
27366 'breve': 333,
27367 'dotaccent': 333,
27368 'dieresis': 333,
27369 'ring': 333,
27370 'cedilla': 333,
27371 'hungarumlaut': 333,
27372 'ogonek': 333,
27373 'caron': 333,
27374 'emdash': 1000,
27375 'AE': 1000,
27376 'ordfeminine': 370,
27377 'Lslash': 556,
27378 'Oslash': 778,
27379 'OE': 1000,
27380 'ordmasculine': 365,
27381 'ae': 889,
27382 'dotlessi': 278,
27383 'lslash': 222,
27384 'oslash': 611,
27385 'oe': 944,
27386 'germandbls': 611,
27387 'Idieresis': 278,
27388 'eacute': 556,
27389 'abreve': 556,
27390 'uhungarumlaut': 556,
27391 'ecaron': 556,
27392 'Ydieresis': 667,
27393 'divide': 584,
27394 'Yacute': 667,
27395 'Acircumflex': 667,
27396 'aacute': 556,
27397 'Ucircumflex': 722,
27398 'yacute': 500,
27399 'scommaaccent': 500,
27400 'ecircumflex': 556,
27401 'Uring': 722,
27402 'Udieresis': 722,
27403 'aogonek': 556,
27404 'Uacute': 722,
27405 'uogonek': 556,
27406 'Edieresis': 667,
27407 'Dcroat': 722,
27408 'commaaccent': 250,
27409 'copyright': 737,
27410 'Emacron': 667,
27411 'ccaron': 500,
27412 'aring': 556,
27413 'Ncommaaccent': 722,
27414 'lacute': 222,
27415 'agrave': 556,
27416 'Tcommaaccent': 611,
27417 'Cacute': 722,
27418 'atilde': 556,
27419 'Edotaccent': 667,
27420 'scaron': 500,
27421 'scedilla': 500,
27422 'iacute': 278,
27423 'lozenge': 471,
27424 'Rcaron': 722,
27425 'Gcommaaccent': 778,
27426 'ucircumflex': 556,
27427 'acircumflex': 556,
27428 'Amacron': 667,
27429 'rcaron': 333,
27430 'ccedilla': 500,
27431 'Zdotaccent': 611,
27432 'Thorn': 667,
27433 'Omacron': 778,
27434 'Racute': 722,
27435 'Sacute': 667,
27436 'dcaron': 643,
27437 'Umacron': 722,
27438 'uring': 556,
27439 'threesuperior': 333,
27440 'Ograve': 778,
27441 'Agrave': 667,
27442 'Abreve': 667,
27443 'multiply': 584,
27444 'uacute': 556,
27445 'Tcaron': 611,
27446 'partialdiff': 476,
27447 'ydieresis': 500,
27448 'Nacute': 722,
27449 'icircumflex': 278,
27450 'Ecircumflex': 667,
27451 'adieresis': 556,
27452 'edieresis': 556,
27453 'cacute': 500,
27454 'nacute': 556,
27455 'umacron': 556,
27456 'Ncaron': 722,
27457 'Iacute': 278,
27458 'plusminus': 584,
27459 'brokenbar': 260,
27460 'registered': 737,
27461 'Gbreve': 778,
27462 'Idotaccent': 278,
27463 'summation': 600,
27464 'Egrave': 667,
27465 'racute': 333,
27466 'omacron': 556,
27467 'Zacute': 611,
27468 'Zcaron': 611,
27469 'greaterequal': 549,
27470 'Eth': 722,
27471 'Ccedilla': 722,
27472 'lcommaaccent': 222,
27473 'tcaron': 317,
27474 'eogonek': 556,
27475 'Uogonek': 722,
27476 'Aacute': 667,
27477 'Adieresis': 667,
27478 'egrave': 556,
27479 'zacute': 500,
27480 'iogonek': 222,
27481 'Oacute': 778,
27482 'oacute': 556,
27483 'amacron': 556,
27484 'sacute': 500,
27485 'idieresis': 278,
27486 'Ocircumflex': 778,
27487 'Ugrave': 722,
27488 'Delta': 612,
27489 'thorn': 556,
27490 'twosuperior': 333,
27491 'Odieresis': 778,
27492 'mu': 556,
27493 'igrave': 278,
27494 'ohungarumlaut': 556,
27495 'Eogonek': 667,
27496 'dcroat': 556,
27497 'threequarters': 834,
27498 'Scedilla': 667,
27499 'lcaron': 299,
27500 'Kcommaaccent': 667,
27501 'Lacute': 556,
27502 'trademark': 1000,
27503 'edotaccent': 556,
27504 'Igrave': 278,
27505 'Imacron': 278,
27506 'Lcaron': 556,
27507 'onehalf': 834,
27508 'lessequal': 549,
27509 'ocircumflex': 556,
27510 'ntilde': 556,
27511 'Uhungarumlaut': 722,
27512 'Eacute': 667,
27513 'emacron': 556,
27514 'gbreve': 556,
27515 'onequarter': 834,
27516 'Scaron': 667,
27517 'Scommaaccent': 667,
27518 'Ohungarumlaut': 778,
27519 'degree': 400,
27520 'ograve': 556,
27521 'Ccaron': 722,
27522 'ugrave': 556,
27523 'radical': 453,
27524 'Dcaron': 722,
27525 'rcommaaccent': 333,
27526 'Ntilde': 722,
27527 'otilde': 556,
27528 'Rcommaaccent': 722,
27529 'Lcommaaccent': 556,
27530 'Atilde': 667,
27531 'Aogonek': 667,
27532 'Aring': 667,
27533 'Otilde': 778,
27534 'zdotaccent': 500,
27535 'Ecaron': 667,
27536 'Iogonek': 278,
27537 'kcommaaccent': 500,
27538 'minus': 584,
27539 'Icircumflex': 278,
27540 'ncaron': 556,
27541 'tcommaaccent': 278,
27542 'logicalnot': 584,
27543 'odieresis': 556,
27544 'udieresis': 556,
27545 'notequal': 549,
27546 'gcommaaccent': 556,
27547 'eth': 556,
27548 'zcaron': 500,
27549 'ncommaaccent': 556,
27550 'onesuperior': 333,
27551 'imacron': 278,
27552 'Euro': 556
27553 },
27554 'Helvetica-Bold': {
27555 'space': 278,
27556 'exclam': 333,
27557 'quotedbl': 474,
27558 'numbersign': 556,
27559 'dollar': 556,
27560 'percent': 889,
27561 'ampersand': 722,
27562 'quoteright': 278,
27563 'parenleft': 333,
27564 'parenright': 333,
27565 'asterisk': 389,
27566 'plus': 584,
27567 'comma': 278,
27568 'hyphen': 333,
27569 'period': 278,
27570 'slash': 278,
27571 'zero': 556,
27572 'one': 556,
27573 'two': 556,
27574 'three': 556,
27575 'four': 556,
27576 'five': 556,
27577 'six': 556,
27578 'seven': 556,
27579 'eight': 556,
27580 'nine': 556,
27581 'colon': 333,
27582 'semicolon': 333,
27583 'less': 584,
27584 'equal': 584,
27585 'greater': 584,
27586 'question': 611,
27587 'at': 975,
27588 'A': 722,
27589 'B': 722,
27590 'C': 722,
27591 'D': 722,
27592 'E': 667,
27593 'F': 611,
27594 'G': 778,
27595 'H': 722,
27596 'I': 278,
27597 'J': 556,
27598 'K': 722,
27599 'L': 611,
27600 'M': 833,
27601 'N': 722,
27602 'O': 778,
27603 'P': 667,
27604 'Q': 778,
27605 'R': 722,
27606 'S': 667,
27607 'T': 611,
27608 'U': 722,
27609 'V': 667,
27610 'W': 944,
27611 'X': 667,
27612 'Y': 667,
27613 'Z': 611,
27614 'bracketleft': 333,
27615 'backslash': 278,
27616 'bracketright': 333,
27617 'asciicircum': 584,
27618 'underscore': 556,
27619 'quoteleft': 278,
27620 'a': 556,
27621 'b': 611,
27622 'c': 556,
27623 'd': 611,
27624 'e': 556,
27625 'f': 333,
27626 'g': 611,
27627 'h': 611,
27628 'i': 278,
27629 'j': 278,
27630 'k': 556,
27631 'l': 278,
27632 'm': 889,
27633 'n': 611,
27634 'o': 611,
27635 'p': 611,
27636 'q': 611,
27637 'r': 389,
27638 's': 556,
27639 't': 333,
27640 'u': 611,
27641 'v': 556,
27642 'w': 778,
27643 'x': 556,
27644 'y': 556,
27645 'z': 500,
27646 'braceleft': 389,
27647 'bar': 280,
27648 'braceright': 389,
27649 'asciitilde': 584,
27650 'exclamdown': 333,
27651 'cent': 556,
27652 'sterling': 556,
27653 'fraction': 167,
27654 'yen': 556,
27655 'florin': 556,
27656 'section': 556,
27657 'currency': 556,
27658 'quotesingle': 238,
27659 'quotedblleft': 500,
27660 'guillemotleft': 556,
27661 'guilsinglleft': 333,
27662 'guilsinglright': 333,
27663 'fi': 611,
27664 'fl': 611,
27665 'endash': 556,
27666 'dagger': 556,
27667 'daggerdbl': 556,
27668 'periodcentered': 278,
27669 'paragraph': 556,
27670 'bullet': 350,
27671 'quotesinglbase': 278,
27672 'quotedblbase': 500,
27673 'quotedblright': 500,
27674 'guillemotright': 556,
27675 'ellipsis': 1000,
27676 'perthousand': 1000,
27677 'questiondown': 611,
27678 'grave': 333,
27679 'acute': 333,
27680 'circumflex': 333,
27681 'tilde': 333,
27682 'macron': 333,
27683 'breve': 333,
27684 'dotaccent': 333,
27685 'dieresis': 333,
27686 'ring': 333,
27687 'cedilla': 333,
27688 'hungarumlaut': 333,
27689 'ogonek': 333,
27690 'caron': 333,
27691 'emdash': 1000,
27692 'AE': 1000,
27693 'ordfeminine': 370,
27694 'Lslash': 611,
27695 'Oslash': 778,
27696 'OE': 1000,
27697 'ordmasculine': 365,
27698 'ae': 889,
27699 'dotlessi': 278,
27700 'lslash': 278,
27701 'oslash': 611,
27702 'oe': 944,
27703 'germandbls': 611,
27704 'Idieresis': 278,
27705 'eacute': 556,
27706 'abreve': 556,
27707 'uhungarumlaut': 611,
27708 'ecaron': 556,
27709 'Ydieresis': 667,
27710 'divide': 584,
27711 'Yacute': 667,
27712 'Acircumflex': 722,
27713 'aacute': 556,
27714 'Ucircumflex': 722,
27715 'yacute': 556,
27716 'scommaaccent': 556,
27717 'ecircumflex': 556,
27718 'Uring': 722,
27719 'Udieresis': 722,
27720 'aogonek': 556,
27721 'Uacute': 722,
27722 'uogonek': 611,
27723 'Edieresis': 667,
27724 'Dcroat': 722,
27725 'commaaccent': 250,
27726 'copyright': 737,
27727 'Emacron': 667,
27728 'ccaron': 556,
27729 'aring': 556,
27730 'Ncommaaccent': 722,
27731 'lacute': 278,
27732 'agrave': 556,
27733 'Tcommaaccent': 611,
27734 'Cacute': 722,
27735 'atilde': 556,
27736 'Edotaccent': 667,
27737 'scaron': 556,
27738 'scedilla': 556,
27739 'iacute': 278,
27740 'lozenge': 494,
27741 'Rcaron': 722,
27742 'Gcommaaccent': 778,
27743 'ucircumflex': 611,
27744 'acircumflex': 556,
27745 'Amacron': 722,
27746 'rcaron': 389,
27747 'ccedilla': 556,
27748 'Zdotaccent': 611,
27749 'Thorn': 667,
27750 'Omacron': 778,
27751 'Racute': 722,
27752 'Sacute': 667,
27753 'dcaron': 743,
27754 'Umacron': 722,
27755 'uring': 611,
27756 'threesuperior': 333,
27757 'Ograve': 778,
27758 'Agrave': 722,
27759 'Abreve': 722,
27760 'multiply': 584,
27761 'uacute': 611,
27762 'Tcaron': 611,
27763 'partialdiff': 494,
27764 'ydieresis': 556,
27765 'Nacute': 722,
27766 'icircumflex': 278,
27767 'Ecircumflex': 667,
27768 'adieresis': 556,
27769 'edieresis': 556,
27770 'cacute': 556,
27771 'nacute': 611,
27772 'umacron': 611,
27773 'Ncaron': 722,
27774 'Iacute': 278,
27775 'plusminus': 584,
27776 'brokenbar': 280,
27777 'registered': 737,
27778 'Gbreve': 778,
27779 'Idotaccent': 278,
27780 'summation': 600,
27781 'Egrave': 667,
27782 'racute': 389,
27783 'omacron': 611,
27784 'Zacute': 611,
27785 'Zcaron': 611,
27786 'greaterequal': 549,
27787 'Eth': 722,
27788 'Ccedilla': 722,
27789 'lcommaaccent': 278,
27790 'tcaron': 389,
27791 'eogonek': 556,
27792 'Uogonek': 722,
27793 'Aacute': 722,
27794 'Adieresis': 722,
27795 'egrave': 556,
27796 'zacute': 500,
27797 'iogonek': 278,
27798 'Oacute': 778,
27799 'oacute': 611,
27800 'amacron': 556,
27801 'sacute': 556,
27802 'idieresis': 278,
27803 'Ocircumflex': 778,
27804 'Ugrave': 722,
27805 'Delta': 612,
27806 'thorn': 611,
27807 'twosuperior': 333,
27808 'Odieresis': 778,
27809 'mu': 611,
27810 'igrave': 278,
27811 'ohungarumlaut': 611,
27812 'Eogonek': 667,
27813 'dcroat': 611,
27814 'threequarters': 834,
27815 'Scedilla': 667,
27816 'lcaron': 400,
27817 'Kcommaaccent': 722,
27818 'Lacute': 611,
27819 'trademark': 1000,
27820 'edotaccent': 556,
27821 'Igrave': 278,
27822 'Imacron': 278,
27823 'Lcaron': 611,
27824 'onehalf': 834,
27825 'lessequal': 549,
27826 'ocircumflex': 611,
27827 'ntilde': 611,
27828 'Uhungarumlaut': 722,
27829 'Eacute': 667,
27830 'emacron': 556,
27831 'gbreve': 611,
27832 'onequarter': 834,
27833 'Scaron': 667,
27834 'Scommaaccent': 667,
27835 'Ohungarumlaut': 778,
27836 'degree': 400,
27837 'ograve': 611,
27838 'Ccaron': 722,
27839 'ugrave': 611,
27840 'radical': 549,
27841 'Dcaron': 722,
27842 'rcommaaccent': 389,
27843 'Ntilde': 722,
27844 'otilde': 611,
27845 'Rcommaaccent': 722,
27846 'Lcommaaccent': 611,
27847 'Atilde': 722,
27848 'Aogonek': 722,
27849 'Aring': 722,
27850 'Otilde': 778,
27851 'zdotaccent': 500,
27852 'Ecaron': 667,
27853 'Iogonek': 278,
27854 'kcommaaccent': 556,
27855 'minus': 584,
27856 'Icircumflex': 278,
27857 'ncaron': 611,
27858 'tcommaaccent': 333,
27859 'logicalnot': 584,
27860 'odieresis': 611,
27861 'udieresis': 611,
27862 'notequal': 549,
27863 'gcommaaccent': 611,
27864 'eth': 611,
27865 'zcaron': 500,
27866 'ncommaaccent': 611,
27867 'onesuperior': 333,
27868 'imacron': 278,
27869 'Euro': 556
27870 },
27871 'Helvetica-BoldOblique': {
27872 'space': 278,
27873 'exclam': 333,
27874 'quotedbl': 474,
27875 'numbersign': 556,
27876 'dollar': 556,
27877 'percent': 889,
27878 'ampersand': 722,
27879 'quoteright': 278,
27880 'parenleft': 333,
27881 'parenright': 333,
27882 'asterisk': 389,
27883 'plus': 584,
27884 'comma': 278,
27885 'hyphen': 333,
27886 'period': 278,
27887 'slash': 278,
27888 'zero': 556,
27889 'one': 556,
27890 'two': 556,
27891 'three': 556,
27892 'four': 556,
27893 'five': 556,
27894 'six': 556,
27895 'seven': 556,
27896 'eight': 556,
27897 'nine': 556,
27898 'colon': 333,
27899 'semicolon': 333,
27900 'less': 584,
27901 'equal': 584,
27902 'greater': 584,
27903 'question': 611,
27904 'at': 975,
27905 'A': 722,
27906 'B': 722,
27907 'C': 722,
27908 'D': 722,
27909 'E': 667,
27910 'F': 611,
27911 'G': 778,
27912 'H': 722,
27913 'I': 278,
27914 'J': 556,
27915 'K': 722,
27916 'L': 611,
27917 'M': 833,
27918 'N': 722,
27919 'O': 778,
27920 'P': 667,
27921 'Q': 778,
27922 'R': 722,
27923 'S': 667,
27924 'T': 611,
27925 'U': 722,
27926 'V': 667,
27927 'W': 944,
27928 'X': 667,
27929 'Y': 667,
27930 'Z': 611,
27931 'bracketleft': 333,
27932 'backslash': 278,
27933 'bracketright': 333,
27934 'asciicircum': 584,
27935 'underscore': 556,
27936 'quoteleft': 278,
27937 'a': 556,
27938 'b': 611,
27939 'c': 556,
27940 'd': 611,
27941 'e': 556,
27942 'f': 333,
27943 'g': 611,
27944 'h': 611,
27945 'i': 278,
27946 'j': 278,
27947 'k': 556,
27948 'l': 278,
27949 'm': 889,
27950 'n': 611,
27951 'o': 611,
27952 'p': 611,
27953 'q': 611,
27954 'r': 389,
27955 's': 556,
27956 't': 333,
27957 'u': 611,
27958 'v': 556,
27959 'w': 778,
27960 'x': 556,
27961 'y': 556,
27962 'z': 500,
27963 'braceleft': 389,
27964 'bar': 280,
27965 'braceright': 389,
27966 'asciitilde': 584,
27967 'exclamdown': 333,
27968 'cent': 556,
27969 'sterling': 556,
27970 'fraction': 167,
27971 'yen': 556,
27972 'florin': 556,
27973 'section': 556,
27974 'currency': 556,
27975 'quotesingle': 238,
27976 'quotedblleft': 500,
27977 'guillemotleft': 556,
27978 'guilsinglleft': 333,
27979 'guilsinglright': 333,
27980 'fi': 611,
27981 'fl': 611,
27982 'endash': 556,
27983 'dagger': 556,
27984 'daggerdbl': 556,
27985 'periodcentered': 278,
27986 'paragraph': 556,
27987 'bullet': 350,
27988 'quotesinglbase': 278,
27989 'quotedblbase': 500,
27990 'quotedblright': 500,
27991 'guillemotright': 556,
27992 'ellipsis': 1000,
27993 'perthousand': 1000,
27994 'questiondown': 611,
27995 'grave': 333,
27996 'acute': 333,
27997 'circumflex': 333,
27998 'tilde': 333,
27999 'macron': 333,
28000 'breve': 333,
28001 'dotaccent': 333,
28002 'dieresis': 333,
28003 'ring': 333,
28004 'cedilla': 333,
28005 'hungarumlaut': 333,
28006 'ogonek': 333,
28007 'caron': 333,
28008 'emdash': 1000,
28009 'AE': 1000,
28010 'ordfeminine': 370,
28011 'Lslash': 611,
28012 'Oslash': 778,
28013 'OE': 1000,
28014 'ordmasculine': 365,
28015 'ae': 889,
28016 'dotlessi': 278,
28017 'lslash': 278,
28018 'oslash': 611,
28019 'oe': 944,
28020 'germandbls': 611,
28021 'Idieresis': 278,
28022 'eacute': 556,
28023 'abreve': 556,
28024 'uhungarumlaut': 611,
28025 'ecaron': 556,
28026 'Ydieresis': 667,
28027 'divide': 584,
28028 'Yacute': 667,
28029 'Acircumflex': 722,
28030 'aacute': 556,
28031 'Ucircumflex': 722,
28032 'yacute': 556,
28033 'scommaaccent': 556,
28034 'ecircumflex': 556,
28035 'Uring': 722,
28036 'Udieresis': 722,
28037 'aogonek': 556,
28038 'Uacute': 722,
28039 'uogonek': 611,
28040 'Edieresis': 667,
28041 'Dcroat': 722,
28042 'commaaccent': 250,
28043 'copyright': 737,
28044 'Emacron': 667,
28045 'ccaron': 556,
28046 'aring': 556,
28047 'Ncommaaccent': 722,
28048 'lacute': 278,
28049 'agrave': 556,
28050 'Tcommaaccent': 611,
28051 'Cacute': 722,
28052 'atilde': 556,
28053 'Edotaccent': 667,
28054 'scaron': 556,
28055 'scedilla': 556,
28056 'iacute': 278,
28057 'lozenge': 494,
28058 'Rcaron': 722,
28059 'Gcommaaccent': 778,
28060 'ucircumflex': 611,
28061 'acircumflex': 556,
28062 'Amacron': 722,
28063 'rcaron': 389,
28064 'ccedilla': 556,
28065 'Zdotaccent': 611,
28066 'Thorn': 667,
28067 'Omacron': 778,
28068 'Racute': 722,
28069 'Sacute': 667,
28070 'dcaron': 743,
28071 'Umacron': 722,
28072 'uring': 611,
28073 'threesuperior': 333,
28074 'Ograve': 778,
28075 'Agrave': 722,
28076 'Abreve': 722,
28077 'multiply': 584,
28078 'uacute': 611,
28079 'Tcaron': 611,
28080 'partialdiff': 494,
28081 'ydieresis': 556,
28082 'Nacute': 722,
28083 'icircumflex': 278,
28084 'Ecircumflex': 667,
28085 'adieresis': 556,
28086 'edieresis': 556,
28087 'cacute': 556,
28088 'nacute': 611,
28089 'umacron': 611,
28090 'Ncaron': 722,
28091 'Iacute': 278,
28092 'plusminus': 584,
28093 'brokenbar': 280,
28094 'registered': 737,
28095 'Gbreve': 778,
28096 'Idotaccent': 278,
28097 'summation': 600,
28098 'Egrave': 667,
28099 'racute': 389,
28100 'omacron': 611,
28101 'Zacute': 611,
28102 'Zcaron': 611,
28103 'greaterequal': 549,
28104 'Eth': 722,
28105 'Ccedilla': 722,
28106 'lcommaaccent': 278,
28107 'tcaron': 389,
28108 'eogonek': 556,
28109 'Uogonek': 722,
28110 'Aacute': 722,
28111 'Adieresis': 722,
28112 'egrave': 556,
28113 'zacute': 500,
28114 'iogonek': 278,
28115 'Oacute': 778,
28116 'oacute': 611,
28117 'amacron': 556,
28118 'sacute': 556,
28119 'idieresis': 278,
28120 'Ocircumflex': 778,
28121 'Ugrave': 722,
28122 'Delta': 612,
28123 'thorn': 611,
28124 'twosuperior': 333,
28125 'Odieresis': 778,
28126 'mu': 611,
28127 'igrave': 278,
28128 'ohungarumlaut': 611,
28129 'Eogonek': 667,
28130 'dcroat': 611,
28131 'threequarters': 834,
28132 'Scedilla': 667,
28133 'lcaron': 400,
28134 'Kcommaaccent': 722,
28135 'Lacute': 611,
28136 'trademark': 1000,
28137 'edotaccent': 556,
28138 'Igrave': 278,
28139 'Imacron': 278,
28140 'Lcaron': 611,
28141 'onehalf': 834,
28142 'lessequal': 549,
28143 'ocircumflex': 611,
28144 'ntilde': 611,
28145 'Uhungarumlaut': 722,
28146 'Eacute': 667,
28147 'emacron': 556,
28148 'gbreve': 611,
28149 'onequarter': 834,
28150 'Scaron': 667,
28151 'Scommaaccent': 667,
28152 'Ohungarumlaut': 778,
28153 'degree': 400,
28154 'ograve': 611,
28155 'Ccaron': 722,
28156 'ugrave': 611,
28157 'radical': 549,
28158 'Dcaron': 722,
28159 'rcommaaccent': 389,
28160 'Ntilde': 722,
28161 'otilde': 611,
28162 'Rcommaaccent': 722,
28163 'Lcommaaccent': 611,
28164 'Atilde': 722,
28165 'Aogonek': 722,
28166 'Aring': 722,
28167 'Otilde': 778,
28168 'zdotaccent': 500,
28169 'Ecaron': 667,
28170 'Iogonek': 278,
28171 'kcommaaccent': 556,
28172 'minus': 584,
28173 'Icircumflex': 278,
28174 'ncaron': 611,
28175 'tcommaaccent': 333,
28176 'logicalnot': 584,
28177 'odieresis': 611,
28178 'udieresis': 611,
28179 'notequal': 549,
28180 'gcommaaccent': 611,
28181 'eth': 611,
28182 'zcaron': 500,
28183 'ncommaaccent': 611,
28184 'onesuperior': 333,
28185 'imacron': 278,
28186 'Euro': 556
28187 },
28188 'Helvetica-Oblique' : {
28189 'space': 278,
28190 'exclam': 278,
28191 'quotedbl': 355,
28192 'numbersign': 556,
28193 'dollar': 556,
28194 'percent': 889,
28195 'ampersand': 667,
28196 'quoteright': 222,
28197 'parenleft': 333,
28198 'parenright': 333,
28199 'asterisk': 389,
28200 'plus': 584,
28201 'comma': 278,
28202 'hyphen': 333,
28203 'period': 278,
28204 'slash': 278,
28205 'zero': 556,
28206 'one': 556,
28207 'two': 556,
28208 'three': 556,
28209 'four': 556,
28210 'five': 556,
28211 'six': 556,
28212 'seven': 556,
28213 'eight': 556,
28214 'nine': 556,
28215 'colon': 278,
28216 'semicolon': 278,
28217 'less': 584,
28218 'equal': 584,
28219 'greater': 584,
28220 'question': 556,
28221 'at': 1015,
28222 'A': 667,
28223 'B': 667,
28224 'C': 722,
28225 'D': 722,
28226 'E': 667,
28227 'F': 611,
28228 'G': 778,
28229 'H': 722,
28230 'I': 278,
28231 'J': 500,
28232 'K': 667,
28233 'L': 556,
28234 'M': 833,
28235 'N': 722,
28236 'O': 778,
28237 'P': 667,
28238 'Q': 778,
28239 'R': 722,
28240 'S': 667,
28241 'T': 611,
28242 'U': 722,
28243 'V': 667,
28244 'W': 944,
28245 'X': 667,
28246 'Y': 667,
28247 'Z': 611,
28248 'bracketleft': 278,
28249 'backslash': 278,
28250 'bracketright': 278,
28251 'asciicircum': 469,
28252 'underscore': 556,
28253 'quoteleft': 222,
28254 'a': 556,
28255 'b': 556,
28256 'c': 500,
28257 'd': 556,
28258 'e': 556,
28259 'f': 278,
28260 'g': 556,
28261 'h': 556,
28262 'i': 222,
28263 'j': 222,
28264 'k': 500,
28265 'l': 222,
28266 'm': 833,
28267 'n': 556,
28268 'o': 556,
28269 'p': 556,
28270 'q': 556,
28271 'r': 333,
28272 's': 500,
28273 't': 278,
28274 'u': 556,
28275 'v': 500,
28276 'w': 722,
28277 'x': 500,
28278 'y': 500,
28279 'z': 500,
28280 'braceleft': 334,
28281 'bar': 260,
28282 'braceright': 334,
28283 'asciitilde': 584,
28284 'exclamdown': 333,
28285 'cent': 556,
28286 'sterling': 556,
28287 'fraction': 167,
28288 'yen': 556,
28289 'florin': 556,
28290 'section': 556,
28291 'currency': 556,
28292 'quotesingle': 191,
28293 'quotedblleft': 333,
28294 'guillemotleft': 556,
28295 'guilsinglleft': 333,
28296 'guilsinglright': 333,
28297 'fi': 500,
28298 'fl': 500,
28299 'endash': 556,
28300 'dagger': 556,
28301 'daggerdbl': 556,
28302 'periodcentered': 278,
28303 'paragraph': 537,
28304 'bullet': 350,
28305 'quotesinglbase': 222,
28306 'quotedblbase': 333,
28307 'quotedblright': 333,
28308 'guillemotright': 556,
28309 'ellipsis': 1000,
28310 'perthousand': 1000,
28311 'questiondown': 611,
28312 'grave': 333,
28313 'acute': 333,
28314 'circumflex': 333,
28315 'tilde': 333,
28316 'macron': 333,
28317 'breve': 333,
28318 'dotaccent': 333,
28319 'dieresis': 333,
28320 'ring': 333,
28321 'cedilla': 333,
28322 'hungarumlaut': 333,
28323 'ogonek': 333,
28324 'caron': 333,
28325 'emdash': 1000,
28326 'AE': 1000,
28327 'ordfeminine': 370,
28328 'Lslash': 556,
28329 'Oslash': 778,
28330 'OE': 1000,
28331 'ordmasculine': 365,
28332 'ae': 889,
28333 'dotlessi': 278,
28334 'lslash': 222,
28335 'oslash': 611,
28336 'oe': 944,
28337 'germandbls': 611,
28338 'Idieresis': 278,
28339 'eacute': 556,
28340 'abreve': 556,
28341 'uhungarumlaut': 556,
28342 'ecaron': 556,
28343 'Ydieresis': 667,
28344 'divide': 584,
28345 'Yacute': 667,
28346 'Acircumflex': 667,
28347 'aacute': 556,
28348 'Ucircumflex': 722,
28349 'yacute': 500,
28350 'scommaaccent': 500,
28351 'ecircumflex': 556,
28352 'Uring': 722,
28353 'Udieresis': 722,
28354 'aogonek': 556,
28355 'Uacute': 722,
28356 'uogonek': 556,
28357 'Edieresis': 667,
28358 'Dcroat': 722,
28359 'commaaccent': 250,
28360 'copyright': 737,
28361 'Emacron': 667,
28362 'ccaron': 500,
28363 'aring': 556,
28364 'Ncommaaccent': 722,
28365 'lacute': 222,
28366 'agrave': 556,
28367 'Tcommaaccent': 611,
28368 'Cacute': 722,
28369 'atilde': 556,
28370 'Edotaccent': 667,
28371 'scaron': 500,
28372 'scedilla': 500,
28373 'iacute': 278,
28374 'lozenge': 471,
28375 'Rcaron': 722,
28376 'Gcommaaccent': 778,
28377 'ucircumflex': 556,
28378 'acircumflex': 556,
28379 'Amacron': 667,
28380 'rcaron': 333,
28381 'ccedilla': 500,
28382 'Zdotaccent': 611,
28383 'Thorn': 667,
28384 'Omacron': 778,
28385 'Racute': 722,
28386 'Sacute': 667,
28387 'dcaron': 643,
28388 'Umacron': 722,
28389 'uring': 556,
28390 'threesuperior': 333,
28391 'Ograve': 778,
28392 'Agrave': 667,
28393 'Abreve': 667,
28394 'multiply': 584,
28395 'uacute': 556,
28396 'Tcaron': 611,
28397 'partialdiff': 476,
28398 'ydieresis': 500,
28399 'Nacute': 722,
28400 'icircumflex': 278,
28401 'Ecircumflex': 667,
28402 'adieresis': 556,
28403 'edieresis': 556,
28404 'cacute': 500,
28405 'nacute': 556,
28406 'umacron': 556,
28407 'Ncaron': 722,
28408 'Iacute': 278,
28409 'plusminus': 584,
28410 'brokenbar': 260,
28411 'registered': 737,
28412 'Gbreve': 778,
28413 'Idotaccent': 278,
28414 'summation': 600,
28415 'Egrave': 667,
28416 'racute': 333,
28417 'omacron': 556,
28418 'Zacute': 611,
28419 'Zcaron': 611,
28420 'greaterequal': 549,
28421 'Eth': 722,
28422 'Ccedilla': 722,
28423 'lcommaaccent': 222,
28424 'tcaron': 317,
28425 'eogonek': 556,
28426 'Uogonek': 722,
28427 'Aacute': 667,
28428 'Adieresis': 667,
28429 'egrave': 556,
28430 'zacute': 500,
28431 'iogonek': 222,
28432 'Oacute': 778,
28433 'oacute': 556,
28434 'amacron': 556,
28435 'sacute': 500,
28436 'idieresis': 278,
28437 'Ocircumflex': 778,
28438 'Ugrave': 722,
28439 'Delta': 612,
28440 'thorn': 556,
28441 'twosuperior': 333,
28442 'Odieresis': 778,
28443 'mu': 556,
28444 'igrave': 278,
28445 'ohungarumlaut': 556,
28446 'Eogonek': 667,
28447 'dcroat': 556,
28448 'threequarters': 834,
28449 'Scedilla': 667,
28450 'lcaron': 299,
28451 'Kcommaaccent': 667,
28452 'Lacute': 556,
28453 'trademark': 1000,
28454 'edotaccent': 556,
28455 'Igrave': 278,
28456 'Imacron': 278,
28457 'Lcaron': 556,
28458 'onehalf': 834,
28459 'lessequal': 549,
28460 'ocircumflex': 556,
28461 'ntilde': 556,
28462 'Uhungarumlaut': 722,
28463 'Eacute': 667,
28464 'emacron': 556,
28465 'gbreve': 556,
28466 'onequarter': 834,
28467 'Scaron': 667,
28468 'Scommaaccent': 667,
28469 'Ohungarumlaut': 778,
28470 'degree': 400,
28471 'ograve': 556,
28472 'Ccaron': 722,
28473 'ugrave': 556,
28474 'radical': 453,
28475 'Dcaron': 722,
28476 'rcommaaccent': 333,
28477 'Ntilde': 722,
28478 'otilde': 556,
28479 'Rcommaaccent': 722,
28480 'Lcommaaccent': 556,
28481 'Atilde': 667,
28482 'Aogonek': 667,
28483 'Aring': 667,
28484 'Otilde': 778,
28485 'zdotaccent': 500,
28486 'Ecaron': 667,
28487 'Iogonek': 278,
28488 'kcommaaccent': 500,
28489 'minus': 584,
28490 'Icircumflex': 278,
28491 'ncaron': 556,
28492 'tcommaaccent': 278,
28493 'logicalnot': 584,
28494 'odieresis': 556,
28495 'udieresis': 556,
28496 'notequal': 549,
28497 'gcommaaccent': 556,
28498 'eth': 556,
28499 'zcaron': 500,
28500 'ncommaaccent': 556,
28501 'onesuperior': 333,
28502 'imacron': 278,
28503 'Euro': 556
28504 },
28505 'Symbol': {
28506 'space': 250,
28507 'exclam': 333,
28508 'universal': 713,
28509 'numbersign': 500,
28510 'existential': 549,
28511 'percent': 833,
28512 'ampersand': 778,
28513 'suchthat': 439,
28514 'parenleft': 333,
28515 'parenright': 333,
28516 'asteriskmath': 500,
28517 'plus': 549,
28518 'comma': 250,
28519 'minus': 549,
28520 'period': 250,
28521 'slash': 278,
28522 'zero': 500,
28523 'one': 500,
28524 'two': 500,
28525 'three': 500,
28526 'four': 500,
28527 'five': 500,
28528 'six': 500,
28529 'seven': 500,
28530 'eight': 500,
28531 'nine': 500,
28532 'colon': 278,
28533 'semicolon': 278,
28534 'less': 549,
28535 'equal': 549,
28536 'greater': 549,
28537 'question': 444,
28538 'congruent': 549,
28539 'Alpha': 722,
28540 'Beta': 667,
28541 'Chi': 722,
28542 'Delta': 612,
28543 'Epsilon': 611,
28544 'Phi': 763,
28545 'Gamma': 603,
28546 'Eta': 722,
28547 'Iota': 333,
28548 'theta1': 631,
28549 'Kappa': 722,
28550 'Lambda': 686,
28551 'Mu': 889,
28552 'Nu': 722,
28553 'Omicron': 722,
28554 'Pi': 768,
28555 'Theta': 741,
28556 'Rho': 556,
28557 'Sigma': 592,
28558 'Tau': 611,
28559 'Upsilon': 690,
28560 'sigma1': 439,
28561 'Omega': 768,
28562 'Xi': 645,
28563 'Psi': 795,
28564 'Zeta': 611,
28565 'bracketleft': 333,
28566 'therefore': 863,
28567 'bracketright': 333,
28568 'perpendicular': 658,
28569 'underscore': 500,
28570 'radicalex': 500,
28571 'alpha': 631,
28572 'beta': 549,
28573 'chi': 549,
28574 'delta': 494,
28575 'epsilon': 439,
28576 'phi': 521,
28577 'gamma': 411,
28578 'eta': 603,
28579 'iota': 329,
28580 'phi1': 603,
28581 'kappa': 549,
28582 'lambda': 549,
28583 'mu': 576,
28584 'nu': 521,
28585 'omicron': 549,
28586 'pi': 549,
28587 'theta': 521,
28588 'rho': 549,
28589 'sigma': 603,
28590 'tau': 439,
28591 'upsilon': 576,
28592 'omega1': 713,
28593 'omega': 686,
28594 'xi': 493,
28595 'psi': 686,
28596 'zeta': 494,
28597 'braceleft': 480,
28598 'bar': 200,
28599 'braceright': 480,
28600 'similar': 549,
28601 'Euro': 750,
28602 'Upsilon1': 620,
28603 'minute': 247,
28604 'lessequal': 549,
28605 'fraction': 167,
28606 'infinity': 713,
28607 'florin': 500,
28608 'club': 753,
28609 'diamond': 753,
28610 'heart': 753,
28611 'spade': 753,
28612 'arrowboth': 1042,
28613 'arrowleft': 987,
28614 'arrowup': 603,
28615 'arrowright': 987,
28616 'arrowdown': 603,
28617 'degree': 400,
28618 'plusminus': 549,
28619 'second': 411,
28620 'greaterequal': 549,
28621 'multiply': 549,
28622 'proportional': 713,
28623 'partialdiff': 494,
28624 'bullet': 460,
28625 'divide': 549,
28626 'notequal': 549,
28627 'equivalence': 549,
28628 'approxequal': 549,
28629 'ellipsis': 1000,
28630 'arrowvertex': 603,
28631 'arrowhorizex': 1000,
28632 'carriagereturn': 658,
28633 'aleph': 823,
28634 'Ifraktur': 686,
28635 'Rfraktur': 795,
28636 'weierstrass': 987,
28637 'circlemultiply': 768,
28638 'circleplus': 768,
28639 'emptyset': 823,
28640 'intersection': 768,
28641 'union': 768,
28642 'propersuperset': 713,
28643 'reflexsuperset': 713,
28644 'notsubset': 713,
28645 'propersubset': 713,
28646 'reflexsubset': 713,
28647 'element': 713,
28648 'notelement': 713,
28649 'angle': 768,
28650 'gradient': 713,
28651 'registerserif': 790,
28652 'copyrightserif': 790,
28653 'trademarkserif': 890,
28654 'product': 823,
28655 'radical': 549,
28656 'dotmath': 250,
28657 'logicalnot': 713,
28658 'logicaland': 603,
28659 'logicalor': 603,
28660 'arrowdblboth': 1042,
28661 'arrowdblleft': 987,
28662 'arrowdblup': 603,
28663 'arrowdblright': 987,
28664 'arrowdbldown': 603,
28665 'lozenge': 494,
28666 'angleleft': 329,
28667 'registersans': 790,
28668 'copyrightsans': 790,
28669 'trademarksans': 786,
28670 'summation': 713,
28671 'parenlefttp': 384,
28672 'parenleftex': 384,
28673 'parenleftbt': 384,
28674 'bracketlefttp': 384,
28675 'bracketleftex': 384,
28676 'bracketleftbt': 384,
28677 'bracelefttp': 494,
28678 'braceleftmid': 494,
28679 'braceleftbt': 494,
28680 'braceex': 494,
28681 'angleright': 329,
28682 'integral': 274,
28683 'integraltp': 686,
28684 'integralex': 686,
28685 'integralbt': 686,
28686 'parenrighttp': 384,
28687 'parenrightex': 384,
28688 'parenrightbt': 384,
28689 'bracketrighttp': 384,
28690 'bracketrightex': 384,
28691 'bracketrightbt': 384,
28692 'bracerighttp': 494,
28693 'bracerightmid': 494,
28694 'bracerightbt': 494,
28695 'apple': 790
28696 },
28697 'Times-Roman': {
28698 'space': 250,
28699 'exclam': 333,
28700 'quotedbl': 408,
28701 'numbersign': 500,
28702 'dollar': 500,
28703 'percent': 833,
28704 'ampersand': 778,
28705 'quoteright': 333,
28706 'parenleft': 333,
28707 'parenright': 333,
28708 'asterisk': 500,
28709 'plus': 564,
28710 'comma': 250,
28711 'hyphen': 333,
28712 'period': 250,
28713 'slash': 278,
28714 'zero': 500,
28715 'one': 500,
28716 'two': 500,
28717 'three': 500,
28718 'four': 500,
28719 'five': 500,
28720 'six': 500,
28721 'seven': 500,
28722 'eight': 500,
28723 'nine': 500,
28724 'colon': 278,
28725 'semicolon': 278,
28726 'less': 564,
28727 'equal': 564,
28728 'greater': 564,
28729 'question': 444,
28730 'at': 921,
28731 'A': 722,
28732 'B': 667,
28733 'C': 667,
28734 'D': 722,
28735 'E': 611,
28736 'F': 556,
28737 'G': 722,
28738 'H': 722,
28739 'I': 333,
28740 'J': 389,
28741 'K': 722,
28742 'L': 611,
28743 'M': 889,
28744 'N': 722,
28745 'O': 722,
28746 'P': 556,
28747 'Q': 722,
28748 'R': 667,
28749 'S': 556,
28750 'T': 611,
28751 'U': 722,
28752 'V': 722,
28753 'W': 944,
28754 'X': 722,
28755 'Y': 722,
28756 'Z': 611,
28757 'bracketleft': 333,
28758 'backslash': 278,
28759 'bracketright': 333,
28760 'asciicircum': 469,
28761 'underscore': 500,
28762 'quoteleft': 333,
28763 'a': 444,
28764 'b': 500,
28765 'c': 444,
28766 'd': 500,
28767 'e': 444,
28768 'f': 333,
28769 'g': 500,
28770 'h': 500,
28771 'i': 278,
28772 'j': 278,
28773 'k': 500,
28774 'l': 278,
28775 'm': 778,
28776 'n': 500,
28777 'o': 500,
28778 'p': 500,
28779 'q': 500,
28780 'r': 333,
28781 's': 389,
28782 't': 278,
28783 'u': 500,
28784 'v': 500,
28785 'w': 722,
28786 'x': 500,
28787 'y': 500,
28788 'z': 444,
28789 'braceleft': 480,
28790 'bar': 200,
28791 'braceright': 480,
28792 'asciitilde': 541,
28793 'exclamdown': 333,
28794 'cent': 500,
28795 'sterling': 500,
28796 'fraction': 167,
28797 'yen': 500,
28798 'florin': 500,
28799 'section': 500,
28800 'currency': 500,
28801 'quotesingle': 180,
28802 'quotedblleft': 444,
28803 'guillemotleft': 500,
28804 'guilsinglleft': 333,
28805 'guilsinglright': 333,
28806 'fi': 556,
28807 'fl': 556,
28808 'endash': 500,
28809 'dagger': 500,
28810 'daggerdbl': 500,
28811 'periodcentered': 250,
28812 'paragraph': 453,
28813 'bullet': 350,
28814 'quotesinglbase': 333,
28815 'quotedblbase': 444,
28816 'quotedblright': 444,
28817 'guillemotright': 500,
28818 'ellipsis': 1000,
28819 'perthousand': 1000,
28820 'questiondown': 444,
28821 'grave': 333,
28822 'acute': 333,
28823 'circumflex': 333,
28824 'tilde': 333,
28825 'macron': 333,
28826 'breve': 333,
28827 'dotaccent': 333,
28828 'dieresis': 333,
28829 'ring': 333,
28830 'cedilla': 333,
28831 'hungarumlaut': 333,
28832 'ogonek': 333,
28833 'caron': 333,
28834 'emdash': 1000,
28835 'AE': 889,
28836 'ordfeminine': 276,
28837 'Lslash': 611,
28838 'Oslash': 722,
28839 'OE': 889,
28840 'ordmasculine': 310,
28841 'ae': 667,
28842 'dotlessi': 278,
28843 'lslash': 278,
28844 'oslash': 500,
28845 'oe': 722,
28846 'germandbls': 500,
28847 'Idieresis': 333,
28848 'eacute': 444,
28849 'abreve': 444,
28850 'uhungarumlaut': 500,
28851 'ecaron': 444,
28852 'Ydieresis': 722,
28853 'divide': 564,
28854 'Yacute': 722,
28855 'Acircumflex': 722,
28856 'aacute': 444,
28857 'Ucircumflex': 722,
28858 'yacute': 500,
28859 'scommaaccent': 389,
28860 'ecircumflex': 444,
28861 'Uring': 722,
28862 'Udieresis': 722,
28863 'aogonek': 444,
28864 'Uacute': 722,
28865 'uogonek': 500,
28866 'Edieresis': 611,
28867 'Dcroat': 722,
28868 'commaaccent': 250,
28869 'copyright': 760,
28870 'Emacron': 611,
28871 'ccaron': 444,
28872 'aring': 444,
28873 'Ncommaaccent': 722,
28874 'lacute': 278,
28875 'agrave': 444,
28876 'Tcommaaccent': 611,
28877 'Cacute': 667,
28878 'atilde': 444,
28879 'Edotaccent': 611,
28880 'scaron': 389,
28881 'scedilla': 389,
28882 'iacute': 278,
28883 'lozenge': 471,
28884 'Rcaron': 667,
28885 'Gcommaaccent': 722,
28886 'ucircumflex': 500,
28887 'acircumflex': 444,
28888 'Amacron': 722,
28889 'rcaron': 333,
28890 'ccedilla': 444,
28891 'Zdotaccent': 611,
28892 'Thorn': 556,
28893 'Omacron': 722,
28894 'Racute': 667,
28895 'Sacute': 556,
28896 'dcaron': 588,
28897 'Umacron': 722,
28898 'uring': 500,
28899 'threesuperior': 300,
28900 'Ograve': 722,
28901 'Agrave': 722,
28902 'Abreve': 722,
28903 'multiply': 564,
28904 'uacute': 500,
28905 'Tcaron': 611,
28906 'partialdiff': 476,
28907 'ydieresis': 500,
28908 'Nacute': 722,
28909 'icircumflex': 278,
28910 'Ecircumflex': 611,
28911 'adieresis': 444,
28912 'edieresis': 444,
28913 'cacute': 444,
28914 'nacute': 500,
28915 'umacron': 500,
28916 'Ncaron': 722,
28917 'Iacute': 333,
28918 'plusminus': 564,
28919 'brokenbar': 200,
28920 'registered': 760,
28921 'Gbreve': 722,
28922 'Idotaccent': 333,
28923 'summation': 600,
28924 'Egrave': 611,
28925 'racute': 333,
28926 'omacron': 500,
28927 'Zacute': 611,
28928 'Zcaron': 611,
28929 'greaterequal': 549,
28930 'Eth': 722,
28931 'Ccedilla': 667,
28932 'lcommaaccent': 278,
28933 'tcaron': 326,
28934 'eogonek': 444,
28935 'Uogonek': 722,
28936 'Aacute': 722,
28937 'Adieresis': 722,
28938 'egrave': 444,
28939 'zacute': 444,
28940 'iogonek': 278,
28941 'Oacute': 722,
28942 'oacute': 500,
28943 'amacron': 444,
28944 'sacute': 389,
28945 'idieresis': 278,
28946 'Ocircumflex': 722,
28947 'Ugrave': 722,
28948 'Delta': 612,
28949 'thorn': 500,
28950 'twosuperior': 300,
28951 'Odieresis': 722,
28952 'mu': 500,
28953 'igrave': 278,
28954 'ohungarumlaut': 500,
28955 'Eogonek': 611,
28956 'dcroat': 500,
28957 'threequarters': 750,
28958 'Scedilla': 556,
28959 'lcaron': 344,
28960 'Kcommaaccent': 722,
28961 'Lacute': 611,
28962 'trademark': 980,
28963 'edotaccent': 444,
28964 'Igrave': 333,
28965 'Imacron': 333,
28966 'Lcaron': 611,
28967 'onehalf': 750,
28968 'lessequal': 549,
28969 'ocircumflex': 500,
28970 'ntilde': 500,
28971 'Uhungarumlaut': 722,
28972 'Eacute': 611,
28973 'emacron': 444,
28974 'gbreve': 500,
28975 'onequarter': 750,
28976 'Scaron': 556,
28977 'Scommaaccent': 556,
28978 'Ohungarumlaut': 722,
28979 'degree': 400,
28980 'ograve': 500,
28981 'Ccaron': 667,
28982 'ugrave': 500,
28983 'radical': 453,
28984 'Dcaron': 722,
28985 'rcommaaccent': 333,
28986 'Ntilde': 722,
28987 'otilde': 500,
28988 'Rcommaaccent': 667,
28989 'Lcommaaccent': 611,
28990 'Atilde': 722,
28991 'Aogonek': 722,
28992 'Aring': 722,
28993 'Otilde': 722,
28994 'zdotaccent': 444,
28995 'Ecaron': 611,
28996 'Iogonek': 333,
28997 'kcommaaccent': 500,
28998 'minus': 564,
28999 'Icircumflex': 333,
29000 'ncaron': 500,
29001 'tcommaaccent': 278,
29002 'logicalnot': 564,
29003 'odieresis': 500,
29004 'udieresis': 500,
29005 'notequal': 549,
29006 'gcommaaccent': 500,
29007 'eth': 500,
29008 'zcaron': 444,
29009 'ncommaaccent': 500,
29010 'onesuperior': 300,
29011 'imacron': 278,
29012 'Euro': 500
29013 },
29014 'Times-Bold': {
29015 'space': 250,
29016 'exclam': 333,
29017 'quotedbl': 555,
29018 'numbersign': 500,
29019 'dollar': 500,
29020 'percent': 1000,
29021 'ampersand': 833,
29022 'quoteright': 333,
29023 'parenleft': 333,
29024 'parenright': 333,
29025 'asterisk': 500,
29026 'plus': 570,
29027 'comma': 250,
29028 'hyphen': 333,
29029 'period': 250,
29030 'slash': 278,
29031 'zero': 500,
29032 'one': 500,
29033 'two': 500,
29034 'three': 500,
29035 'four': 500,
29036 'five': 500,
29037 'six': 500,
29038 'seven': 500,
29039 'eight': 500,
29040 'nine': 500,
29041 'colon': 333,
29042 'semicolon': 333,
29043 'less': 570,
29044 'equal': 570,
29045 'greater': 570,
29046 'question': 500,
29047 'at': 930,
29048 'A': 722,
29049 'B': 667,
29050 'C': 722,
29051 'D': 722,
29052 'E': 667,
29053 'F': 611,
29054 'G': 778,
29055 'H': 778,
29056 'I': 389,
29057 'J': 500,
29058 'K': 778,
29059 'L': 667,
29060 'M': 944,
29061 'N': 722,
29062 'O': 778,
29063 'P': 611,
29064 'Q': 778,
29065 'R': 722,
29066 'S': 556,
29067 'T': 667,
29068 'U': 722,
29069 'V': 722,
29070 'W': 1000,
29071 'X': 722,
29072 'Y': 722,
29073 'Z': 667,
29074 'bracketleft': 333,
29075 'backslash': 278,
29076 'bracketright': 333,
29077 'asciicircum': 581,
29078 'underscore': 500,
29079 'quoteleft': 333,
29080 'a': 500,
29081 'b': 556,
29082 'c': 444,
29083 'd': 556,
29084 'e': 444,
29085 'f': 333,
29086 'g': 500,
29087 'h': 556,
29088 'i': 278,
29089 'j': 333,
29090 'k': 556,
29091 'l': 278,
29092 'm': 833,
29093 'n': 556,
29094 'o': 500,
29095 'p': 556,
29096 'q': 556,
29097 'r': 444,
29098 's': 389,
29099 't': 333,
29100 'u': 556,
29101 'v': 500,
29102 'w': 722,
29103 'x': 500,
29104 'y': 500,
29105 'z': 444,
29106 'braceleft': 394,
29107 'bar': 220,
29108 'braceright': 394,
29109 'asciitilde': 520,
29110 'exclamdown': 333,
29111 'cent': 500,
29112 'sterling': 500,
29113 'fraction': 167,
29114 'yen': 500,
29115 'florin': 500,
29116 'section': 500,
29117 'currency': 500,
29118 'quotesingle': 278,
29119 'quotedblleft': 500,
29120 'guillemotleft': 500,
29121 'guilsinglleft': 333,
29122 'guilsinglright': 333,
29123 'fi': 556,
29124 'fl': 556,
29125 'endash': 500,
29126 'dagger': 500,
29127 'daggerdbl': 500,
29128 'periodcentered': 250,
29129 'paragraph': 540,
29130 'bullet': 350,
29131 'quotesinglbase': 333,
29132 'quotedblbase': 500,
29133 'quotedblright': 500,
29134 'guillemotright': 500,
29135 'ellipsis': 1000,
29136 'perthousand': 1000,
29137 'questiondown': 500,
29138 'grave': 333,
29139 'acute': 333,
29140 'circumflex': 333,
29141 'tilde': 333,
29142 'macron': 333,
29143 'breve': 333,
29144 'dotaccent': 333,
29145 'dieresis': 333,
29146 'ring': 333,
29147 'cedilla': 333,
29148 'hungarumlaut': 333,
29149 'ogonek': 333,
29150 'caron': 333,
29151 'emdash': 1000,
29152 'AE': 1000,
29153 'ordfeminine': 300,
29154 'Lslash': 667,
29155 'Oslash': 778,
29156 'OE': 1000,
29157 'ordmasculine': 330,
29158 'ae': 722,
29159 'dotlessi': 278,
29160 'lslash': 278,
29161 'oslash': 500,
29162 'oe': 722,
29163 'germandbls': 556,
29164 'Idieresis': 389,
29165 'eacute': 444,
29166 'abreve': 500,
29167 'uhungarumlaut': 556,
29168 'ecaron': 444,
29169 'Ydieresis': 722,
29170 'divide': 570,
29171 'Yacute': 722,
29172 'Acircumflex': 722,
29173 'aacute': 500,
29174 'Ucircumflex': 722,
29175 'yacute': 500,
29176 'scommaaccent': 389,
29177 'ecircumflex': 444,
29178 'Uring': 722,
29179 'Udieresis': 722,
29180 'aogonek': 500,
29181 'Uacute': 722,
29182 'uogonek': 556,
29183 'Edieresis': 667,
29184 'Dcroat': 722,
29185 'commaaccent': 250,
29186 'copyright': 747,
29187 'Emacron': 667,
29188 'ccaron': 444,
29189 'aring': 500,
29190 'Ncommaaccent': 722,
29191 'lacute': 278,
29192 'agrave': 500,
29193 'Tcommaaccent': 667,
29194 'Cacute': 722,
29195 'atilde': 500,
29196 'Edotaccent': 667,
29197 'scaron': 389,
29198 'scedilla': 389,
29199 'iacute': 278,
29200 'lozenge': 494,
29201 'Rcaron': 722,
29202 'Gcommaaccent': 778,
29203 'ucircumflex': 556,
29204 'acircumflex': 500,
29205 'Amacron': 722,
29206 'rcaron': 444,
29207 'ccedilla': 444,
29208 'Zdotaccent': 667,
29209 'Thorn': 611,
29210 'Omacron': 778,
29211 'Racute': 722,
29212 'Sacute': 556,
29213 'dcaron': 672,
29214 'Umacron': 722,
29215 'uring': 556,
29216 'threesuperior': 300,
29217 'Ograve': 778,
29218 'Agrave': 722,
29219 'Abreve': 722,
29220 'multiply': 570,
29221 'uacute': 556,
29222 'Tcaron': 667,
29223 'partialdiff': 494,
29224 'ydieresis': 500,
29225 'Nacute': 722,
29226 'icircumflex': 278,
29227 'Ecircumflex': 667,
29228 'adieresis': 500,
29229 'edieresis': 444,
29230 'cacute': 444,
29231 'nacute': 556,
29232 'umacron': 556,
29233 'Ncaron': 722,
29234 'Iacute': 389,
29235 'plusminus': 570,
29236 'brokenbar': 220,
29237 'registered': 747,
29238 'Gbreve': 778,
29239 'Idotaccent': 389,
29240 'summation': 600,
29241 'Egrave': 667,
29242 'racute': 444,
29243 'omacron': 500,
29244 'Zacute': 667,
29245 'Zcaron': 667,
29246 'greaterequal': 549,
29247 'Eth': 722,
29248 'Ccedilla': 722,
29249 'lcommaaccent': 278,
29250 'tcaron': 416,
29251 'eogonek': 444,
29252 'Uogonek': 722,
29253 'Aacute': 722,
29254 'Adieresis': 722,
29255 'egrave': 444,
29256 'zacute': 444,
29257 'iogonek': 278,
29258 'Oacute': 778,
29259 'oacute': 500,
29260 'amacron': 500,
29261 'sacute': 389,
29262 'idieresis': 278,
29263 'Ocircumflex': 778,
29264 'Ugrave': 722,
29265 'Delta': 612,
29266 'thorn': 556,
29267 'twosuperior': 300,
29268 'Odieresis': 778,
29269 'mu': 556,
29270 'igrave': 278,
29271 'ohungarumlaut': 500,
29272 'Eogonek': 667,
29273 'dcroat': 556,
29274 'threequarters': 750,
29275 'Scedilla': 556,
29276 'lcaron': 394,
29277 'Kcommaaccent': 778,
29278 'Lacute': 667,
29279 'trademark': 1000,
29280 'edotaccent': 444,
29281 'Igrave': 389,
29282 'Imacron': 389,
29283 'Lcaron': 667,
29284 'onehalf': 750,
29285 'lessequal': 549,
29286 'ocircumflex': 500,
29287 'ntilde': 556,
29288 'Uhungarumlaut': 722,
29289 'Eacute': 667,
29290 'emacron': 444,
29291 'gbreve': 500,
29292 'onequarter': 750,
29293 'Scaron': 556,
29294 'Scommaaccent': 556,
29295 'Ohungarumlaut': 778,
29296 'degree': 400,
29297 'ograve': 500,
29298 'Ccaron': 722,
29299 'ugrave': 556,
29300 'radical': 549,
29301 'Dcaron': 722,
29302 'rcommaaccent': 444,
29303 'Ntilde': 722,
29304 'otilde': 500,
29305 'Rcommaaccent': 722,
29306 'Lcommaaccent': 667,
29307 'Atilde': 722,
29308 'Aogonek': 722,
29309 'Aring': 722,
29310 'Otilde': 778,
29311 'zdotaccent': 444,
29312 'Ecaron': 667,
29313 'Iogonek': 389,
29314 'kcommaaccent': 556,
29315 'minus': 570,
29316 'Icircumflex': 389,
29317 'ncaron': 556,
29318 'tcommaaccent': 333,
29319 'logicalnot': 570,
29320 'odieresis': 500,
29321 'udieresis': 556,
29322 'notequal': 549,
29323 'gcommaaccent': 500,
29324 'eth': 500,
29325 'zcaron': 444,
29326 'ncommaaccent': 556,
29327 'onesuperior': 300,
29328 'imacron': 278,
29329 'Euro': 500
29330 },
29331 'Times-BoldItalic': {
29332 'space': 250,
29333 'exclam': 389,
29334 'quotedbl': 555,
29335 'numbersign': 500,
29336 'dollar': 500,
29337 'percent': 833,
29338 'ampersand': 778,
29339 'quoteright': 333,
29340 'parenleft': 333,
29341 'parenright': 333,
29342 'asterisk': 500,
29343 'plus': 570,
29344 'comma': 250,
29345 'hyphen': 333,
29346 'period': 250,
29347 'slash': 278,
29348 'zero': 500,
29349 'one': 500,
29350 'two': 500,
29351 'three': 500,
29352 'four': 500,
29353 'five': 500,
29354 'six': 500,
29355 'seven': 500,
29356 'eight': 500,
29357 'nine': 500,
29358 'colon': 333,
29359 'semicolon': 333,
29360 'less': 570,
29361 'equal': 570,
29362 'greater': 570,
29363 'question': 500,
29364 'at': 832,
29365 'A': 667,
29366 'B': 667,
29367 'C': 667,
29368 'D': 722,
29369 'E': 667,
29370 'F': 667,
29371 'G': 722,
29372 'H': 778,
29373 'I': 389,
29374 'J': 500,
29375 'K': 667,
29376 'L': 611,
29377 'M': 889,
29378 'N': 722,
29379 'O': 722,
29380 'P': 611,
29381 'Q': 722,
29382 'R': 667,
29383 'S': 556,
29384 'T': 611,
29385 'U': 722,
29386 'V': 667,
29387 'W': 889,
29388 'X': 667,
29389 'Y': 611,
29390 'Z': 611,
29391 'bracketleft': 333,
29392 'backslash': 278,
29393 'bracketright': 333,
29394 'asciicircum': 570,
29395 'underscore': 500,
29396 'quoteleft': 333,
29397 'a': 500,
29398 'b': 500,
29399 'c': 444,
29400 'd': 500,
29401 'e': 444,
29402 'f': 333,
29403 'g': 500,
29404 'h': 556,
29405 'i': 278,
29406 'j': 278,
29407 'k': 500,
29408 'l': 278,
29409 'm': 778,
29410 'n': 556,
29411 'o': 500,
29412 'p': 500,
29413 'q': 500,
29414 'r': 389,
29415 's': 389,
29416 't': 278,
29417 'u': 556,
29418 'v': 444,
29419 'w': 667,
29420 'x': 500,
29421 'y': 444,
29422 'z': 389,
29423 'braceleft': 348,
29424 'bar': 220,
29425 'braceright': 348,
29426 'asciitilde': 570,
29427 'exclamdown': 389,
29428 'cent': 500,
29429 'sterling': 500,
29430 'fraction': 167,
29431 'yen': 500,
29432 'florin': 500,
29433 'section': 500,
29434 'currency': 500,
29435 'quotesingle': 278,
29436 'quotedblleft': 500,
29437 'guillemotleft': 500,
29438 'guilsinglleft': 333,
29439 'guilsinglright': 333,
29440 'fi': 556,
29441 'fl': 556,
29442 'endash': 500,
29443 'dagger': 500,
29444 'daggerdbl': 500,
29445 'periodcentered': 250,
29446 'paragraph': 500,
29447 'bullet': 350,
29448 'quotesinglbase': 333,
29449 'quotedblbase': 500,
29450 'quotedblright': 500,
29451 'guillemotright': 500,
29452 'ellipsis': 1000,
29453 'perthousand': 1000,
29454 'questiondown': 500,
29455 'grave': 333,
29456 'acute': 333,
29457 'circumflex': 333,
29458 'tilde': 333,
29459 'macron': 333,
29460 'breve': 333,
29461 'dotaccent': 333,
29462 'dieresis': 333,
29463 'ring': 333,
29464 'cedilla': 333,
29465 'hungarumlaut': 333,
29466 'ogonek': 333,
29467 'caron': 333,
29468 'emdash': 1000,
29469 'AE': 944,
29470 'ordfeminine': 266,
29471 'Lslash': 611,
29472 'Oslash': 722,
29473 'OE': 944,
29474 'ordmasculine': 300,
29475 'ae': 722,
29476 'dotlessi': 278,
29477 'lslash': 278,
29478 'oslash': 500,
29479 'oe': 722,
29480 'germandbls': 500,
29481 'Idieresis': 389,
29482 'eacute': 444,
29483 'abreve': 500,
29484 'uhungarumlaut': 556,
29485 'ecaron': 444,
29486 'Ydieresis': 611,
29487 'divide': 570,
29488 'Yacute': 611,
29489 'Acircumflex': 667,
29490 'aacute': 500,
29491 'Ucircumflex': 722,
29492 'yacute': 444,
29493 'scommaaccent': 389,
29494 'ecircumflex': 444,
29495 'Uring': 722,
29496 'Udieresis': 722,
29497 'aogonek': 500,
29498 'Uacute': 722,
29499 'uogonek': 556,
29500 'Edieresis': 667,
29501 'Dcroat': 722,
29502 'commaaccent': 250,
29503 'copyright': 747,
29504 'Emacron': 667,
29505 'ccaron': 444,
29506 'aring': 500,
29507 'Ncommaaccent': 722,
29508 'lacute': 278,
29509 'agrave': 500,
29510 'Tcommaaccent': 611,
29511 'Cacute': 667,
29512 'atilde': 500,
29513 'Edotaccent': 667,
29514 'scaron': 389,
29515 'scedilla': 389,
29516 'iacute': 278,
29517 'lozenge': 494,
29518 'Rcaron': 667,
29519 'Gcommaaccent': 722,
29520 'ucircumflex': 556,
29521 'acircumflex': 500,
29522 'Amacron': 667,
29523 'rcaron': 389,
29524 'ccedilla': 444,
29525 'Zdotaccent': 611,
29526 'Thorn': 611,
29527 'Omacron': 722,
29528 'Racute': 667,
29529 'Sacute': 556,
29530 'dcaron': 608,
29531 'Umacron': 722,
29532 'uring': 556,
29533 'threesuperior': 300,
29534 'Ograve': 722,
29535 'Agrave': 667,
29536 'Abreve': 667,
29537 'multiply': 570,
29538 'uacute': 556,
29539 'Tcaron': 611,
29540 'partialdiff': 494,
29541 'ydieresis': 444,
29542 'Nacute': 722,
29543 'icircumflex': 278,
29544 'Ecircumflex': 667,
29545 'adieresis': 500,
29546 'edieresis': 444,
29547 'cacute': 444,
29548 'nacute': 556,
29549 'umacron': 556,
29550 'Ncaron': 722,
29551 'Iacute': 389,
29552 'plusminus': 570,
29553 'brokenbar': 220,
29554 'registered': 747,
29555 'Gbreve': 722,
29556 'Idotaccent': 389,
29557 'summation': 600,
29558 'Egrave': 667,
29559 'racute': 389,
29560 'omacron': 500,
29561 'Zacute': 611,
29562 'Zcaron': 611,
29563 'greaterequal': 549,
29564 'Eth': 722,
29565 'Ccedilla': 667,
29566 'lcommaaccent': 278,
29567 'tcaron': 366,
29568 'eogonek': 444,
29569 'Uogonek': 722,
29570 'Aacute': 667,
29571 'Adieresis': 667,
29572 'egrave': 444,
29573 'zacute': 389,
29574 'iogonek': 278,
29575 'Oacute': 722,
29576 'oacute': 500,
29577 'amacron': 500,
29578 'sacute': 389,
29579 'idieresis': 278,
29580 'Ocircumflex': 722,
29581 'Ugrave': 722,
29582 'Delta': 612,
29583 'thorn': 500,
29584 'twosuperior': 300,
29585 'Odieresis': 722,
29586 'mu': 576,
29587 'igrave': 278,
29588 'ohungarumlaut': 500,
29589 'Eogonek': 667,
29590 'dcroat': 500,
29591 'threequarters': 750,
29592 'Scedilla': 556,
29593 'lcaron': 382,
29594 'Kcommaaccent': 667,
29595 'Lacute': 611,
29596 'trademark': 1000,
29597 'edotaccent': 444,
29598 'Igrave': 389,
29599 'Imacron': 389,
29600 'Lcaron': 611,
29601 'onehalf': 750,
29602 'lessequal': 549,
29603 'ocircumflex': 500,
29604 'ntilde': 556,
29605 'Uhungarumlaut': 722,
29606 'Eacute': 667,
29607 'emacron': 444,
29608 'gbreve': 500,
29609 'onequarter': 750,
29610 'Scaron': 556,
29611 'Scommaaccent': 556,
29612 'Ohungarumlaut': 722,
29613 'degree': 400,
29614 'ograve': 500,
29615 'Ccaron': 667,
29616 'ugrave': 556,
29617 'radical': 549,
29618 'Dcaron': 722,
29619 'rcommaaccent': 389,
29620 'Ntilde': 722,
29621 'otilde': 500,
29622 'Rcommaaccent': 667,
29623 'Lcommaaccent': 611,
29624 'Atilde': 667,
29625 'Aogonek': 667,
29626 'Aring': 667,
29627 'Otilde': 722,
29628 'zdotaccent': 389,
29629 'Ecaron': 667,
29630 'Iogonek': 389,
29631 'kcommaaccent': 500,
29632 'minus': 606,
29633 'Icircumflex': 389,
29634 'ncaron': 556,
29635 'tcommaaccent': 278,
29636 'logicalnot': 606,
29637 'odieresis': 500,
29638 'udieresis': 556,
29639 'notequal': 549,
29640 'gcommaaccent': 500,
29641 'eth': 500,
29642 'zcaron': 389,
29643 'ncommaaccent': 556,
29644 'onesuperior': 300,
29645 'imacron': 278,
29646 'Euro': 500
29647 },
29648 'Times-Italic': {
29649 'space': 250,
29650 'exclam': 333,
29651 'quotedbl': 420,
29652 'numbersign': 500,
29653 'dollar': 500,
29654 'percent': 833,
29655 'ampersand': 778,
29656 'quoteright': 333,
29657 'parenleft': 333,
29658 'parenright': 333,
29659 'asterisk': 500,
29660 'plus': 675,
29661 'comma': 250,
29662 'hyphen': 333,
29663 'period': 250,
29664 'slash': 278,
29665 'zero': 500,
29666 'one': 500,
29667 'two': 500,
29668 'three': 500,
29669 'four': 500,
29670 'five': 500,
29671 'six': 500,
29672 'seven': 500,
29673 'eight': 500,
29674 'nine': 500,
29675 'colon': 333,
29676 'semicolon': 333,
29677 'less': 675,
29678 'equal': 675,
29679 'greater': 675,
29680 'question': 500,
29681 'at': 920,
29682 'A': 611,
29683 'B': 611,
29684 'C': 667,
29685 'D': 722,
29686 'E': 611,
29687 'F': 611,
29688 'G': 722,
29689 'H': 722,
29690 'I': 333,
29691 'J': 444,
29692 'K': 667,
29693 'L': 556,
29694 'M': 833,
29695 'N': 667,
29696 'O': 722,
29697 'P': 611,
29698 'Q': 722,
29699 'R': 611,
29700 'S': 500,
29701 'T': 556,
29702 'U': 722,
29703 'V': 611,
29704 'W': 833,
29705 'X': 611,
29706 'Y': 556,
29707 'Z': 556,
29708 'bracketleft': 389,
29709 'backslash': 278,
29710 'bracketright': 389,
29711 'asciicircum': 422,
29712 'underscore': 500,
29713 'quoteleft': 333,
29714 'a': 500,
29715 'b': 500,
29716 'c': 444,
29717 'd': 500,
29718 'e': 444,
29719 'f': 278,
29720 'g': 500,
29721 'h': 500,
29722 'i': 278,
29723 'j': 278,
29724 'k': 444,
29725 'l': 278,
29726 'm': 722,
29727 'n': 500,
29728 'o': 500,
29729 'p': 500,
29730 'q': 500,
29731 'r': 389,
29732 's': 389,
29733 't': 278,
29734 'u': 500,
29735 'v': 444,
29736 'w': 667,
29737 'x': 444,
29738 'y': 444,
29739 'z': 389,
29740 'braceleft': 400,
29741 'bar': 275,
29742 'braceright': 400,
29743 'asciitilde': 541,
29744 'exclamdown': 389,
29745 'cent': 500,
29746 'sterling': 500,
29747 'fraction': 167,
29748 'yen': 500,
29749 'florin': 500,
29750 'section': 500,
29751 'currency': 500,
29752 'quotesingle': 214,
29753 'quotedblleft': 556,
29754 'guillemotleft': 500,
29755 'guilsinglleft': 333,
29756 'guilsinglright': 333,
29757 'fi': 500,
29758 'fl': 500,
29759 'endash': 500,
29760 'dagger': 500,
29761 'daggerdbl': 500,
29762 'periodcentered': 250,
29763 'paragraph': 523,
29764 'bullet': 350,
29765 'quotesinglbase': 333,
29766 'quotedblbase': 556,
29767 'quotedblright': 556,
29768 'guillemotright': 500,
29769 'ellipsis': 889,
29770 'perthousand': 1000,
29771 'questiondown': 500,
29772 'grave': 333,
29773 'acute': 333,
29774 'circumflex': 333,
29775 'tilde': 333,
29776 'macron': 333,
29777 'breve': 333,
29778 'dotaccent': 333,
29779 'dieresis': 333,
29780 'ring': 333,
29781 'cedilla': 333,
29782 'hungarumlaut': 333,
29783 'ogonek': 333,
29784 'caron': 333,
29785 'emdash': 889,
29786 'AE': 889,
29787 'ordfeminine': 276,
29788 'Lslash': 556,
29789 'Oslash': 722,
29790 'OE': 944,
29791 'ordmasculine': 310,
29792 'ae': 667,
29793 'dotlessi': 278,
29794 'lslash': 278,
29795 'oslash': 500,
29796 'oe': 667,
29797 'germandbls': 500,
29798 'Idieresis': 333,
29799 'eacute': 444,
29800 'abreve': 500,
29801 'uhungarumlaut': 500,
29802 'ecaron': 444,
29803 'Ydieresis': 556,
29804 'divide': 675,
29805 'Yacute': 556,
29806 'Acircumflex': 611,
29807 'aacute': 500,
29808 'Ucircumflex': 722,
29809 'yacute': 444,
29810 'scommaaccent': 389,
29811 'ecircumflex': 444,
29812 'Uring': 722,
29813 'Udieresis': 722,
29814 'aogonek': 500,
29815 'Uacute': 722,
29816 'uogonek': 500,
29817 'Edieresis': 611,
29818 'Dcroat': 722,
29819 'commaaccent': 250,
29820 'copyright': 760,
29821 'Emacron': 611,
29822 'ccaron': 444,
29823 'aring': 500,
29824 'Ncommaaccent': 667,
29825 'lacute': 278,
29826 'agrave': 500,
29827 'Tcommaaccent': 556,
29828 'Cacute': 667,
29829 'atilde': 500,
29830 'Edotaccent': 611,
29831 'scaron': 389,
29832 'scedilla': 389,
29833 'iacute': 278,
29834 'lozenge': 471,
29835 'Rcaron': 611,
29836 'Gcommaaccent': 722,
29837 'ucircumflex': 500,
29838 'acircumflex': 500,
29839 'Amacron': 611,
29840 'rcaron': 389,
29841 'ccedilla': 444,
29842 'Zdotaccent': 556,
29843 'Thorn': 611,
29844 'Omacron': 722,
29845 'Racute': 611,
29846 'Sacute': 500,
29847 'dcaron': 544,
29848 'Umacron': 722,
29849 'uring': 500,
29850 'threesuperior': 300,
29851 'Ograve': 722,
29852 'Agrave': 611,
29853 'Abreve': 611,
29854 'multiply': 675,
29855 'uacute': 500,
29856 'Tcaron': 556,
29857 'partialdiff': 476,
29858 'ydieresis': 444,
29859 'Nacute': 667,
29860 'icircumflex': 278,
29861 'Ecircumflex': 611,
29862 'adieresis': 500,
29863 'edieresis': 444,
29864 'cacute': 444,
29865 'nacute': 500,
29866 'umacron': 500,
29867 'Ncaron': 667,
29868 'Iacute': 333,
29869 'plusminus': 675,
29870 'brokenbar': 275,
29871 'registered': 760,
29872 'Gbreve': 722,
29873 'Idotaccent': 333,
29874 'summation': 600,
29875 'Egrave': 611,
29876 'racute': 389,
29877 'omacron': 500,
29878 'Zacute': 556,
29879 'Zcaron': 556,
29880 'greaterequal': 549,
29881 'Eth': 722,
29882 'Ccedilla': 667,
29883 'lcommaaccent': 278,
29884 'tcaron': 300,
29885 'eogonek': 444,
29886 'Uogonek': 722,
29887 'Aacute': 611,
29888 'Adieresis': 611,
29889 'egrave': 444,
29890 'zacute': 389,
29891 'iogonek': 278,
29892 'Oacute': 722,
29893 'oacute': 500,
29894 'amacron': 500,
29895 'sacute': 389,
29896 'idieresis': 278,
29897 'Ocircumflex': 722,
29898 'Ugrave': 722,
29899 'Delta': 612,
29900 'thorn': 500,
29901 'twosuperior': 300,
29902 'Odieresis': 722,
29903 'mu': 500,
29904 'igrave': 278,
29905 'ohungarumlaut': 500,
29906 'Eogonek': 611,
29907 'dcroat': 500,
29908 'threequarters': 750,
29909 'Scedilla': 500,
29910 'lcaron': 300,
29911 'Kcommaaccent': 667,
29912 'Lacute': 556,
29913 'trademark': 980,
29914 'edotaccent': 444,
29915 'Igrave': 333,
29916 'Imacron': 333,
29917 'Lcaron': 611,
29918 'onehalf': 750,
29919 'lessequal': 549,
29920 'ocircumflex': 500,
29921 'ntilde': 500,
29922 'Uhungarumlaut': 722,
29923 'Eacute': 611,
29924 'emacron': 444,
29925 'gbreve': 500,
29926 'onequarter': 750,
29927 'Scaron': 500,
29928 'Scommaaccent': 500,
29929 'Ohungarumlaut': 722,
29930 'degree': 400,
29931 'ograve': 500,
29932 'Ccaron': 667,
29933 'ugrave': 500,
29934 'radical': 453,
29935 'Dcaron': 722,
29936 'rcommaaccent': 389,
29937 'Ntilde': 667,
29938 'otilde': 500,
29939 'Rcommaaccent': 611,
29940 'Lcommaaccent': 556,
29941 'Atilde': 611,
29942 'Aogonek': 611,
29943 'Aring': 611,
29944 'Otilde': 722,
29945 'zdotaccent': 389,
29946 'Ecaron': 611,
29947 'Iogonek': 333,
29948 'kcommaaccent': 444,
29949 'minus': 675,
29950 'Icircumflex': 333,
29951 'ncaron': 500,
29952 'tcommaaccent': 278,
29953 'logicalnot': 675,
29954 'odieresis': 500,
29955 'udieresis': 500,
29956 'notequal': 549,
29957 'gcommaaccent': 500,
29958 'eth': 500,
29959 'zcaron': 389,
29960 'ncommaaccent': 500,
29961 'onesuperior': 300,
29962 'imacron': 278,
29963 'Euro': 500
29964 },
29965 'ZapfDingbats': {
29966 'space': 278,
29967 'a1': 974,
29968 'a2': 961,
29969 'a202': 974,
29970 'a3': 980,
29971 'a4': 719,
29972 'a5': 789,
29973 'a119': 790,
29974 'a118': 791,
29975 'a117': 690,
29976 'a11': 960,
29977 'a12': 939,
29978 'a13': 549,
29979 'a14': 855,
29980 'a15': 911,
29981 'a16': 933,
29982 'a105': 911,
29983 'a17': 945,
29984 'a18': 974,
29985 'a19': 755,
29986 'a20': 846,
29987 'a21': 762,
29988 'a22': 761,
29989 'a23': 571,
29990 'a24': 677,
29991 'a25': 763,
29992 'a26': 760,
29993 'a27': 759,
29994 'a28': 754,
29995 'a6': 494,
29996 'a7': 552,
29997 'a8': 537,
29998 'a9': 577,
29999 'a10': 692,
30000 'a29': 786,
30001 'a30': 788,
30002 'a31': 788,
30003 'a32': 790,
30004 'a33': 793,
30005 'a34': 794,
30006 'a35': 816,
30007 'a36': 823,
30008 'a37': 789,
30009 'a38': 841,
30010 'a39': 823,
30011 'a40': 833,
30012 'a41': 816,
30013 'a42': 831,
30014 'a43': 923,
30015 'a44': 744,
30016 'a45': 723,
30017 'a46': 749,
30018 'a47': 790,
30019 'a48': 792,
30020 'a49': 695,
30021 'a50': 776,
30022 'a51': 768,
30023 'a52': 792,
30024 'a53': 759,
30025 'a54': 707,
30026 'a55': 708,
30027 'a56': 682,
30028 'a57': 701,
30029 'a58': 826,
30030 'a59': 815,
30031 'a60': 789,
30032 'a61': 789,
30033 'a62': 707,
30034 'a63': 687,
30035 'a64': 696,
30036 'a65': 689,
30037 'a66': 786,
30038 'a67': 787,
30039 'a68': 713,
30040 'a69': 791,
30041 'a70': 785,
30042 'a71': 791,
30043 'a72': 873,
30044 'a73': 761,
30045 'a74': 762,
30046 'a203': 762,
30047 'a75': 759,
30048 'a204': 759,
30049 'a76': 892,
30050 'a77': 892,
30051 'a78': 788,
30052 'a79': 784,
30053 'a81': 438,
30054 'a82': 138,
30055 'a83': 277,
30056 'a84': 415,
30057 'a97': 392,
30058 'a98': 392,
30059 'a99': 668,
30060 'a100': 668,
30061 'a89': 390,
30062 'a90': 390,
30063 'a93': 317,
30064 'a94': 317,
30065 'a91': 276,
30066 'a92': 276,
30067 'a205': 509,
30068 'a85': 509,
30069 'a206': 410,
30070 'a86': 410,
30071 'a87': 234,
30072 'a88': 234,
30073 'a95': 334,
30074 'a96': 334,
30075 'a101': 732,
30076 'a102': 544,
30077 'a103': 544,
30078 'a104': 910,
30079 'a106': 667,
30080 'a107': 760,
30081 'a108': 760,
30082 'a112': 776,
30083 'a111': 595,
30084 'a110': 694,
30085 'a109': 626,
30086 'a120': 788,
30087 'a121': 788,
30088 'a122': 788,
30089 'a123': 788,
30090 'a124': 788,
30091 'a125': 788,
30092 'a126': 788,
30093 'a127': 788,
30094 'a128': 788,
30095 'a129': 788,
30096 'a130': 788,
30097 'a131': 788,
30098 'a132': 788,
30099 'a133': 788,
30100 'a134': 788,
30101 'a135': 788,
30102 'a136': 788,
30103 'a137': 788,
30104 'a138': 788,
30105 'a139': 788,
30106 'a140': 788,
30107 'a141': 788,
30108 'a142': 788,
30109 'a143': 788,
30110 'a144': 788,
30111 'a145': 788,
30112 'a146': 788,
30113 'a147': 788,
30114 'a148': 788,
30115 'a149': 788,
30116 'a150': 788,
30117 'a151': 788,
30118 'a152': 788,
30119 'a153': 788,
30120 'a154': 788,
30121 'a155': 788,
30122 'a156': 788,
30123 'a157': 788,
30124 'a158': 788,
30125 'a159': 788,
30126 'a160': 894,
30127 'a161': 838,
30128 'a163': 1016,
30129 'a164': 458,
30130 'a196': 748,
30131 'a165': 924,
30132 'a192': 748,
30133 'a166': 918,
30134 'a167': 927,
30135 'a168': 928,
30136 'a169': 928,
30137 'a170': 834,
30138 'a171': 873,
30139 'a172': 828,
30140 'a173': 924,
30141 'a162': 924,
30142 'a174': 917,
30143 'a175': 930,
30144 'a176': 931,
30145 'a177': 463,
30146 'a178': 883,
30147 'a179': 836,
30148 'a193': 836,
30149 'a180': 867,
30150 'a199': 867,
30151 'a181': 696,
30152 'a200': 696,
30153 'a182': 874,
30154 'a201': 874,
30155 'a183': 760,
30156 'a184': 946,
30157 'a197': 771,
30158 'a185': 865,
30159 'a194': 771,
30160 'a198': 888,
30161 'a186': 967,
30162 'a195': 888,
30163 'a187': 831,
30164 'a188': 873,
30165 'a189': 927,
30166 'a190': 970,
30167 'a191': 918
30168 }
30169 };
30170
30171
30172 var EOF = {};
30173
30174 function isEOF(v) {
30175 return (v === EOF);
30176 }
30177
30178 var MAX_LENGTH_TO_CACHE = 1000;
30179
30180 var Parser = (function ParserClosure() {
30181 function Parser(lexer, allowStreams, xref) {
30182 this.lexer = lexer;
30183 this.allowStreams = allowStreams;
30184 this.xref = xref;
30185 this.imageCache = {};
30186 this.refill();
30187 }
30188
30189 Parser.prototype = {
30190 refill: function Parser_refill() {
30191 this.buf1 = this.lexer.getObj();
30192 this.buf2 = this.lexer.getObj();
30193 },
30194 shift: function Parser_shift() {
30195 if (isCmd(this.buf2, 'ID')) {
30196 this.buf1 = this.buf2;
30197 this.buf2 = null;
30198 } else {
30199 this.buf1 = this.buf2;
30200 this.buf2 = this.lexer.getObj();
30201 }
30202 },
30203 getObj: function Parser_getObj(cipherTransform) {
30204 var buf1 = this.buf1;
30205 this.shift();
30206
30207 if (buf1 instanceof Cmd) {
30208 switch (buf1.cmd) {
30209 case 'BI': // inline image
30210 return this.makeInlineImage(cipherTransform);
30211 case '[': // array
30212 var array = [];
30213 while (!isCmd(this.buf1, ']') && !isEOF(this.buf1)) {
30214 array.push(this.getObj(cipherTransform));
30215 }
30216 if (isEOF(this.buf1)) {
30217 error('End of file inside array');
30218 }
30219 this.shift();
30220 return array;
30221 case '<<': // dictionary or stream
30222 var dict = new Dict(this.xref);
30223 while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
30224 if (!isName(this.buf1)) {
30225 info('Malformed dictionary: key must be a name object');
30226 this.shift();
30227 continue;
30228 }
30229
30230 var key = this.buf1.name;
30231 this.shift();
30232 if (isEOF(this.buf1)) {
30233 break;
30234 }
30235 dict.set(key, this.getObj(cipherTransform));
30236 }
30237 if (isEOF(this.buf1)) {
30238 error('End of file inside dictionary');
30239 }
30240
30241 // Stream objects are not allowed inside content streams or
30242 // object streams.
30243 if (isCmd(this.buf2, 'stream')) {
30244 return (this.allowStreams ?
30245 this.makeStream(dict, cipherTransform) : dict);
30246 }
30247 this.shift();
30248 return dict;
30249 default: // simple object
30250 return buf1;
30251 }
30252 }
30253
30254 if (isInt(buf1)) { // indirect reference or integer
30255 var num = buf1;
30256 if (isInt(this.buf1) && isCmd(this.buf2, 'R')) {
30257 var ref = new Ref(num, this.buf1);
30258 this.shift();
30259 this.shift();
30260 return ref;
30261 }
30262 return num;
30263 }
30264
30265 if (isString(buf1)) { // string
30266 var str = buf1;
30267 if (cipherTransform) {
30268 str = cipherTransform.decryptString(str);
30269 }
30270 return str;
30271 }
30272
30273 // simple object
30274 return buf1;
30275 },
30276 /**
30277 * Find the end of the stream by searching for the /EI\s/.
30278 * @returns {number} The inline stream length.
30279 */
30280 findDefaultInlineStreamEnd:
30281 function Parser_findDefaultInlineStreamEnd(stream) {
30282 var E = 0x45, I = 0x49, SPACE = 0x20, LF = 0xA, CR = 0xD;
30283 var startPos = stream.pos, state = 0, ch, i, n, followingBytes;
30284 while ((ch = stream.getByte()) !== -1) {
30285 if (state === 0) {
30286 state = (ch === E) ? 1 : 0;
30287 } else if (state === 1) {
30288 state = (ch === I) ? 2 : 0;
30289 } else {
30290 assert(state === 2);
30291 if (ch === SPACE || ch === LF || ch === CR) {
30292 // Let's check the next five bytes are ASCII... just be sure.
30293 n = 5;
30294 followingBytes = stream.peekBytes(n);
30295 for (i = 0; i < n; i++) {
30296 ch = followingBytes[i];
30297 if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7F)) {
30298 // Not a LF, CR, SPACE or any visible ASCII character, i.e.
30299 // it's binary stuff. Resetting the state.
30300 state = 0;
30301 break;
30302 }
30303 }
30304 if (state === 2) {
30305 break; // Finished!
30306 }
30307 } else {
30308 state = 0;
30309 }
30310 }
30311 }
30312 return ((stream.pos - 4) - startPos);
30313 },
30314 /**
30315 * Find the EOI (end-of-image) marker 0xFFD9 of the stream.
30316 * @returns {number} The inline stream length.
30317 */
30318 findDCTDecodeInlineStreamEnd:
30319 function Parser_findDCTDecodeInlineStreamEnd(stream) {
30320 var startPos = stream.pos, foundEOI = false, b, markerLength, length;
30321 while ((b = stream.getByte()) !== -1) {
30322 if (b !== 0xFF) { // Not a valid marker.
30323 continue;
30324 }
30325 switch (stream.getByte()) {
30326 case 0x00: // Byte stuffing.
30327 // 0xFF00 appears to be a very common byte sequence in JPEG images.
30328 break;
30329
30330 case 0xFF: // Fill byte.
30331 // Avoid skipping a valid marker, resetting the stream position.
30332 stream.skip(-1);
30333 break;
30334
30335 case 0xD9: // EOI
30336 foundEOI = true;
30337 break;
30338
30339 case 0xC0: // SOF0
30340 case 0xC1: // SOF1
30341 case 0xC2: // SOF2
30342 case 0xC3: // SOF3
30343
30344 case 0xC5: // SOF5
30345 case 0xC6: // SOF6
30346 case 0xC7: // SOF7
30347
30348 case 0xC9: // SOF9
30349 case 0xCA: // SOF10
30350 case 0xCB: // SOF11
30351
30352 case 0xCD: // SOF13
30353 case 0xCE: // SOF14
30354 case 0xCF: // SOF15
30355
30356 case 0xC4: // DHT
30357 case 0xCC: // DAC
30358
30359 case 0xDA: // SOS
30360 case 0xDB: // DQT
30361 case 0xDC: // DNL
30362 case 0xDD: // DRI
30363 case 0xDE: // DHP
30364 case 0xDF: // EXP
30365
30366 case 0xE0: // APP0
30367 case 0xE1: // APP1
30368 case 0xE2: // APP2
30369 case 0xE3: // APP3
30370 case 0xE4: // APP4
30371 case 0xE5: // APP5
30372 case 0xE6: // APP6
30373 case 0xE7: // APP7
30374 case 0xE8: // APP8
30375 case 0xE9: // APP9
30376 case 0xEA: // APP10
30377 case 0xEB: // APP11
30378 case 0xEC: // APP12
30379 case 0xED: // APP13
30380 case 0xEE: // APP14
30381 case 0xEF: // APP15
30382
30383 case 0xFE: // COM
30384 // The marker should be followed by the length of the segment.
30385 markerLength = stream.getUint16();
30386 if (markerLength > 2) {
30387 // |markerLength| contains the byte length of the marker segment,
30388 // including its own length (2 bytes) and excluding the marker.
30389 stream.skip(markerLength - 2); // Jump to the next marker.
30390 } else {
30391 // The marker length is invalid, resetting the stream position.
30392 stream.skip(-2);
30393 }
30394 break;
30395 }
30396 if (foundEOI) {
30397 break;
30398 }
30399 }
30400 length = stream.pos - startPos;
30401 if (b === -1) {
30402 warn('Inline DCTDecode image stream: ' +
30403 'EOI marker not found, searching for /EI/ instead.');
30404 stream.skip(-length); // Reset the stream position.
30405 return this.findDefaultInlineStreamEnd(stream);
30406 }
30407 this.inlineStreamSkipEI(stream);
30408 return length;
30409 },
30410 /**
30411 * Find the EOD (end-of-data) marker '~>' (i.e. TILDE + GT) of the stream.
30412 * @returns {number} The inline stream length.
30413 */
30414 findASCII85DecodeInlineStreamEnd:
30415 function Parser_findASCII85DecodeInlineStreamEnd(stream) {
30416 var TILDE = 0x7E, GT = 0x3E;
30417 var startPos = stream.pos, ch, length;
30418 while ((ch = stream.getByte()) !== -1) {
30419 if (ch === TILDE && stream.peekByte() === GT) {
30420 stream.skip();
30421 break;
30422 }
30423 }
30424 length = stream.pos - startPos;
30425 if (ch === -1) {
30426 warn('Inline ASCII85Decode image stream: ' +
30427 'EOD marker not found, searching for /EI/ instead.');
30428 stream.skip(-length); // Reset the stream position.
30429 return this.findDefaultInlineStreamEnd(stream);
30430 }
30431 this.inlineStreamSkipEI(stream);
30432 return length;
30433 },
30434 /**
30435 * Find the EOD (end-of-data) marker '>' (i.e. GT) of the stream.
30436 * @returns {number} The inline stream length.
30437 */
30438 findASCIIHexDecodeInlineStreamEnd:
30439 function Parser_findASCIIHexDecodeInlineStreamEnd(stream) {
30440 var GT = 0x3E;
30441 var startPos = stream.pos, ch, length;
30442 while ((ch = stream.getByte()) !== -1) {
30443 if (ch === GT) {
30444 break;
30445 }
30446 }
30447 length = stream.pos - startPos;
30448 if (ch === -1) {
30449 warn('Inline ASCIIHexDecode image stream: ' +
30450 'EOD marker not found, searching for /EI/ instead.');
30451 stream.skip(-length); // Reset the stream position.
30452 return this.findDefaultInlineStreamEnd(stream);
30453 }
30454 this.inlineStreamSkipEI(stream);
30455 return length;
30456 },
30457 /**
30458 * Skip over the /EI/ for streams where we search for an EOD marker.
30459 */
30460 inlineStreamSkipEI: function Parser_inlineStreamSkipEI(stream) {
30461 var E = 0x45, I = 0x49;
30462 var state = 0, ch;
30463 while ((ch = stream.getByte()) !== -1) {
30464 if (state === 0) {
30465 state = (ch === E) ? 1 : 0;
30466 } else if (state === 1) {
30467 state = (ch === I) ? 2 : 0;
30468 } else if (state === 2) {
30469 break;
30470 }
30471 }
30472 },
30473 makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
30474 var lexer = this.lexer;
30475 var stream = lexer.stream;
30476
30477 // Parse dictionary.
30478 var dict = new Dict(null);
30479 while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
30480 if (!isName(this.buf1)) {
30481 error('Dictionary key must be a name object');
30482 }
30483 var key = this.buf1.name;
30484 this.shift();
30485 if (isEOF(this.buf1)) {
30486 break;
30487 }
30488 dict.set(key, this.getObj(cipherTransform));
30489 }
30490
30491 // Extract the name of the first (i.e. the current) image filter.
30492 var filter = this.fetchIfRef(dict.get('Filter', 'F')), filterName;
30493 if (isName(filter)) {
30494 filterName = filter.name;
30495 } else if (isArray(filter) && isName(filter[0])) {
30496 filterName = filter[0].name;
30497 }
30498
30499 // Parse image stream.
30500 var startPos = stream.pos, length, i, ii;
30501 if (filterName === 'DCTDecode' || filterName === 'DCT') {
30502 length = this.findDCTDecodeInlineStreamEnd(stream);
30503 } else if (filterName === 'ASCII85Decide' || filterName === 'A85') {
30504 length = this.findASCII85DecodeInlineStreamEnd(stream);
30505 } else if (filterName === 'ASCIIHexDecode' || filterName === 'AHx') {
30506 length = this.findASCIIHexDecodeInlineStreamEnd(stream);
30507 } else {
30508 length = this.findDefaultInlineStreamEnd(stream);
30509 }
30510 var imageStream = stream.makeSubStream(startPos, length, dict);
30511
30512 // Cache all images below the MAX_LENGTH_TO_CACHE threshold by their
30513 // adler32 checksum.
30514 var adler32;
30515 if (length < MAX_LENGTH_TO_CACHE) {
30516 var imageBytes = imageStream.getBytes();
30517 imageStream.reset();
30518
30519 var a = 1;
30520 var b = 0;
30521 for (i = 0, ii = imageBytes.length; i < ii; ++i) {
30522 // No modulo required in the loop if imageBytes.length < 5552.
30523 a += imageBytes[i] & 0xff;
30524 b += a;
30525 }
30526 adler32 = ((b % 65521) << 16) | (a % 65521);
30527
30528 if (this.imageCache.adler32 === adler32) {
30529 this.buf2 = Cmd.get('EI');
30530 this.shift();
30531
30532 this.imageCache[adler32].reset();
30533 return this.imageCache[adler32];
30534 }
30535 }
30536
30537 if (cipherTransform) {
30538 imageStream = cipherTransform.createStream(imageStream, length);
30539 }
30540
30541 imageStream = this.filter(imageStream, dict, length);
30542 imageStream.dict = dict;
30543 if (adler32 !== undefined) {
30544 imageStream.cacheKey = 'inline_' + length + '_' + adler32;
30545 this.imageCache[adler32] = imageStream;
30546 }
30547
30548 this.buf2 = Cmd.get('EI');
30549 this.shift();
30550
30551 return imageStream;
30552 },
30553 fetchIfRef: function Parser_fetchIfRef(obj) {
30554 // not relying on the xref.fetchIfRef -- xref might not be set
30555 return (isRef(obj) ? this.xref.fetch(obj) : obj);
30556 },
30557 makeStream: function Parser_makeStream(dict, cipherTransform) {
30558 var lexer = this.lexer;
30559 var stream = lexer.stream;
30560
30561 // get stream start position
30562 lexer.skipToNextLine();
30563 var pos = stream.pos - 1;
30564
30565 // get length
30566 var length = this.fetchIfRef(dict.get('Length'));
30567 if (!isInt(length)) {
30568 info('Bad ' + length + ' attribute in stream');
30569 length = 0;
30570 }
30571
30572 // skip over the stream data
30573 stream.pos = pos + length;
30574 lexer.nextChar();
30575
30576 this.shift(); // '>>'
30577 this.shift(); // 'stream'
30578 if (!isCmd(this.buf1, 'endstream')) {
30579 // bad stream length, scanning for endstream
30580 stream.pos = pos;
30581 var SCAN_BLOCK_SIZE = 2048;
30582 var ENDSTREAM_SIGNATURE_LENGTH = 9;
30583 var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65,
30584 0x61, 0x6D];
30585 var skipped = 0, found = false, i, j;
30586 while (stream.pos < stream.end) {
30587 var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE);
30588 var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH;
30589 if (scanLength <= 0) {
30590 break;
30591 }
30592 found = false;
30593 for (i = 0, j = 0; i < scanLength; i++) {
30594 var b = scanBytes[i];
30595 if (b !== ENDSTREAM_SIGNATURE[j]) {
30596 i -= j;
30597 j = 0;
30598 } else {
30599 j++;
30600 if (j >= ENDSTREAM_SIGNATURE_LENGTH) {
30601 i++;
30602 found = true;
30603 break;
30604 }
30605 }
30606 }
30607 if (found) {
30608 skipped += i - ENDSTREAM_SIGNATURE_LENGTH;
30609 stream.pos += i - ENDSTREAM_SIGNATURE_LENGTH;
30610 break;
30611 }
30612 skipped += scanLength;
30613 stream.pos += scanLength;
30614 }
30615 if (!found) {
30616 error('Missing endstream');
30617 }
30618 length = skipped;
30619
30620 lexer.nextChar();
30621 this.shift();
30622 this.shift();
30623 }
30624 this.shift(); // 'endstream'
30625
30626 stream = stream.makeSubStream(pos, length, dict);
30627 if (cipherTransform) {
30628 stream = cipherTransform.createStream(stream, length);
30629 }
30630 stream = this.filter(stream, dict, length);
30631 stream.dict = dict;
30632 return stream;
30633 },
30634 filter: function Parser_filter(stream, dict, length) {
30635 var filter = this.fetchIfRef(dict.get('Filter', 'F'));
30636 var params = this.fetchIfRef(dict.get('DecodeParms', 'DP'));
30637 if (isName(filter)) {
30638 return this.makeFilter(stream, filter.name, length, params);
30639 }
30640
30641 var maybeLength = length;
30642 if (isArray(filter)) {
30643 var filterArray = filter;
30644 var paramsArray = params;
30645 for (var i = 0, ii = filterArray.length; i < ii; ++i) {
30646 filter = filterArray[i];
30647 if (!isName(filter)) {
30648 error('Bad filter name: ' + filter);
30649 }
30650
30651 params = null;
30652 if (isArray(paramsArray) && (i in paramsArray)) {
30653 params = paramsArray[i];
30654 }
30655 stream = this.makeFilter(stream, filter.name, maybeLength, params);
30656 // after the first stream the length variable is invalid
30657 maybeLength = null;
30658 }
30659 }
30660 return stream;
30661 },
30662 makeFilter: function Parser_makeFilter(stream, name, maybeLength, params) {
30663 if (stream.dict.get('Length') === 0) {
30664 return new NullStream(stream);
30665 }
30666 try {
30667 if (params) {
30668 params = this.fetchIfRef(params);
30669 }
30670 var xrefStreamStats = this.xref.stats.streamTypes;
30671 if (name === 'FlateDecode' || name === 'Fl') {
30672 xrefStreamStats[StreamType.FLATE] = true;
30673 if (params) {
30674 return new PredictorStream(new FlateStream(stream, maybeLength),
30675 maybeLength, params);
30676 }
30677 return new FlateStream(stream, maybeLength);
30678 }
30679 if (name === 'LZWDecode' || name === 'LZW') {
30680 xrefStreamStats[StreamType.LZW] = true;
30681 var earlyChange = 1;
30682 if (params) {
30683 if (params.has('EarlyChange')) {
30684 earlyChange = params.get('EarlyChange');
30685 }
30686 return new PredictorStream(
30687 new LZWStream(stream, maybeLength, earlyChange),
30688 maybeLength, params);
30689 }
30690 return new LZWStream(stream, maybeLength, earlyChange);
30691 }
30692 if (name === 'DCTDecode' || name === 'DCT') {
30693 xrefStreamStats[StreamType.DCT] = true;
30694 return new JpegStream(stream, maybeLength, stream.dict, this.xref);
30695 }
30696 if (name === 'JPXDecode' || name === 'JPX') {
30697 xrefStreamStats[StreamType.JPX] = true;
30698 return new JpxStream(stream, maybeLength, stream.dict);
30699 }
30700 if (name === 'ASCII85Decode' || name === 'A85') {
30701 xrefStreamStats[StreamType.A85] = true;
30702 return new Ascii85Stream(stream, maybeLength);
30703 }
30704 if (name === 'ASCIIHexDecode' || name === 'AHx') {
30705 xrefStreamStats[StreamType.AHX] = true;
30706 return new AsciiHexStream(stream, maybeLength);
30707 }
30708 if (name === 'CCITTFaxDecode' || name === 'CCF') {
30709 xrefStreamStats[StreamType.CCF] = true;
30710 return new CCITTFaxStream(stream, maybeLength, params);
30711 }
30712 if (name === 'RunLengthDecode' || name === 'RL') {
30713 xrefStreamStats[StreamType.RL] = true;
30714 return new RunLengthStream(stream, maybeLength);
30715 }
30716 if (name === 'JBIG2Decode') {
30717 xrefStreamStats[StreamType.JBIG] = true;
30718 return new Jbig2Stream(stream, maybeLength, stream.dict);
30719 }
30720 warn('filter "' + name + '" not supported yet');
30721 return stream;
30722 } catch (ex) {
30723 if (ex instanceof MissingDataException) {
30724 throw ex;
30725 }
30726 warn('Invalid stream: \"' + ex + '\"');
30727 return new NullStream(stream);
30728 }
30729 }
30730 };
30731
30732 return Parser;
30733 })();
30734
30735 var Lexer = (function LexerClosure() {
30736 function Lexer(stream, knownCommands) {
30737 this.stream = stream;
30738 this.nextChar();
30739
30740 // While lexing, we build up many strings one char at a time. Using += for
30741 // this can result in lots of garbage strings. It's better to build an
30742 // array of single-char strings and then join() them together at the end.
30743 // And reusing a single array (i.e. |this.strBuf|) over and over for this
30744 // purpose uses less memory than using a new array for each string.
30745 this.strBuf = [];
30746
30747 // The PDFs might have "glued" commands with other commands, operands or
30748 // literals, e.g. "q1". The knownCommands is a dictionary of the valid
30749 // commands and their prefixes. The prefixes are built the following way:
30750 // if there a command that is a prefix of the other valid command or
30751 // literal (e.g. 'f' and 'false') the following prefixes must be included,
30752 // 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no
30753 // other commands or literals as a prefix. The knowCommands is optional.
30754 this.knownCommands = knownCommands;
30755 }
30756
30757 Lexer.isSpace = function Lexer_isSpace(ch) {
30758 // Space is one of the following characters: SPACE, TAB, CR or LF.
30759 return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A);
30760 };
30761
30762 // A '1' in this array means the character is white space. A '1' or
30763 // '2' means the character ends a name or command.
30764 var specialChars = [
30765 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
30766 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
30767 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
30768 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
30769 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
30770 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
30771 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
30772 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
30773 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
30774 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
30775 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
30776 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
30777 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
30778 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
30779 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
30780 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
30781 ];
30782
30783 function toHexDigit(ch) {
30784 if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
30785 return ch & 0x0F;
30786 }
30787 if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {
30788 // 'A'-'F', 'a'-'f'
30789 return (ch & 0x0F) + 9;
30790 }
30791 return -1;
30792 }
30793
30794 Lexer.prototype = {
30795 nextChar: function Lexer_nextChar() {
30796 return (this.currentChar = this.stream.getByte());
30797 },
30798 peekChar: function Lexer_peekChar() {
30799 return this.stream.peekByte();
30800 },
30801 getNumber: function Lexer_getNumber() {
30802 var ch = this.currentChar;
30803 var eNotation = false;
30804 var divideBy = 0; // different from 0 if it's a floating point value
30805 var sign = 1;
30806
30807 if (ch === 0x2D) { // '-'
30808 sign = -1;
30809 ch = this.nextChar();
30810 } else if (ch === 0x2B) { // '+'
30811 ch = this.nextChar();
30812 }
30813 if (ch === 0x2E) { // '.'
30814 divideBy = 10;
30815 ch = this.nextChar();
30816 }
30817 if (ch < 0x30 || ch > 0x39) { // '0' - '9'
30818 error('Invalid number: ' + String.fromCharCode(ch));
30819 return 0;
30820 }
30821
30822 var baseValue = ch - 0x30; // '0'
30823 var powerValue = 0;
30824 var powerValueSign = 1;
30825
30826 while ((ch = this.nextChar()) >= 0) {
30827 if (0x30 <= ch && ch <= 0x39) { // '0' - '9'
30828 var currentDigit = ch - 0x30; // '0'
30829 if (eNotation) { // We are after an 'e' or 'E'
30830 powerValue = powerValue * 10 + currentDigit;
30831 } else {
30832 if (divideBy !== 0) { // We are after a point
30833 divideBy *= 10;
30834 }
30835 baseValue = baseValue * 10 + currentDigit;
30836 }
30837 } else if (ch === 0x2E) { // '.'
30838 if (divideBy === 0) {
30839 divideBy = 1;
30840 } else {
30841 // A number can have only one '.'
30842 break;
30843 }
30844 } else if (ch === 0x2D) { // '-'
30845 // ignore minus signs in the middle of numbers to match
30846 // Adobe's behavior
30847 warn('Badly formated number');
30848 } else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
30849 // 'E' can be either a scientific notation or the beginning of a new
30850 // operator
30851 ch = this.peekChar();
30852 if (ch === 0x2B || ch === 0x2D) { // '+', '-'
30853 powerValueSign = (ch === 0x2D) ? -1 : 1;
30854 this.nextChar(); // Consume the sign character
30855 } else if (ch < 0x30 || ch > 0x39) { // '0' - '9'
30856 // The 'E' must be the beginning of a new operator
30857 break;
30858 }
30859 eNotation = true;
30860 } else {
30861 // the last character doesn't belong to us
30862 break;
30863 }
30864 }
30865
30866 if (divideBy !== 0) {
30867 baseValue /= divideBy;
30868 }
30869 if (eNotation) {
30870 baseValue *= Math.pow(10, powerValueSign * powerValue);
30871 }
30872 return sign * baseValue;
30873 },
30874 getString: function Lexer_getString() {
30875 var numParen = 1;
30876 var done = false;
30877 var strBuf = this.strBuf;
30878 strBuf.length = 0;
30879
30880 var ch = this.nextChar();
30881 while (true) {
30882 var charBuffered = false;
30883 switch (ch | 0) {
30884 case -1:
30885 warn('Unterminated string');
30886 done = true;
30887 break;
30888 case 0x28: // '('
30889 ++numParen;
30890 strBuf.push('(');
30891 break;
30892 case 0x29: // ')'
30893 if (--numParen === 0) {
30894 this.nextChar(); // consume strings ')'
30895 done = true;
30896 } else {
30897 strBuf.push(')');
30898 }
30899 break;
30900 case 0x5C: // '\\'
30901 ch = this.nextChar();
30902 switch (ch) {
30903 case -1:
30904 warn('Unterminated string');
30905 done = true;
30906 break;
30907 case 0x6E: // 'n'
30908 strBuf.push('\n');
30909 break;
30910 case 0x72: // 'r'
30911 strBuf.push('\r');
30912 break;
30913 case 0x74: // 't'
30914 strBuf.push('\t');
30915 break;
30916 case 0x62: // 'b'
30917 strBuf.push('\b');
30918 break;
30919 case 0x66: // 'f'
30920 strBuf.push('\f');
30921 break;
30922 case 0x5C: // '\'
30923 case 0x28: // '('
30924 case 0x29: // ')'
30925 strBuf.push(String.fromCharCode(ch));
30926 break;
30927 case 0x30: case 0x31: case 0x32: case 0x33: // '0'-'3'
30928 case 0x34: case 0x35: case 0x36: case 0x37: // '4'-'7'
30929 var x = ch & 0x0F;
30930 ch = this.nextChar();
30931 charBuffered = true;
30932 if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'
30933 x = (x << 3) + (ch & 0x0F);
30934 ch = this.nextChar();
30935 if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'
30936 charBuffered = false;
30937 x = (x << 3) + (ch & 0x0F);
30938 }
30939 }
30940 strBuf.push(String.fromCharCode(x));
30941 break;
30942 case 0x0D: // CR
30943 if (this.peekChar() === 0x0A) { // LF
30944 this.nextChar();
30945 }
30946 break;
30947 case 0x0A: // LF
30948 break;
30949 default:
30950 strBuf.push(String.fromCharCode(ch));
30951 break;
30952 }
30953 break;
30954 default:
30955 strBuf.push(String.fromCharCode(ch));
30956 break;
30957 }
30958 if (done) {
30959 break;
30960 }
30961 if (!charBuffered) {
30962 ch = this.nextChar();
30963 }
30964 }
30965 return strBuf.join('');
30966 },
30967 getName: function Lexer_getName() {
30968 var ch;
30969 var strBuf = this.strBuf;
30970 strBuf.length = 0;
30971 while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
30972 if (ch === 0x23) { // '#'
30973 ch = this.nextChar();
30974 var x = toHexDigit(ch);
30975 if (x !== -1) {
30976 var x2 = toHexDigit(this.nextChar());
30977 if (x2 === -1) {
30978 error('Illegal digit in hex char in name: ' + x2);
30979 }
30980 strBuf.push(String.fromCharCode((x << 4) | x2));
30981 } else {
30982 strBuf.push('#', String.fromCharCode(ch));
30983 }
30984 } else {
30985 strBuf.push(String.fromCharCode(ch));
30986 }
30987 }
30988 if (strBuf.length > 128) {
30989 error('Warning: name token is longer than allowed by the spec: ' +
30990 strBuf.length);
30991 }
30992 return Name.get(strBuf.join(''));
30993 },
30994 getHexString: function Lexer_getHexString() {
30995 var strBuf = this.strBuf;
30996 strBuf.length = 0;
30997 var ch = this.currentChar;
30998 var isFirstHex = true;
30999 var firstDigit;
31000 var secondDigit;
31001 while (true) {
31002 if (ch < 0) {
31003 warn('Unterminated hex string');
31004 break;
31005 } else if (ch === 0x3E) { // '>'
31006 this.nextChar();
31007 break;
31008 } else if (specialChars[ch] === 1) {
31009 ch = this.nextChar();
31010 continue;
31011 } else {
31012 if (isFirstHex) {
31013 firstDigit = toHexDigit(ch);
31014 if (firstDigit === -1) {
31015 warn('Ignoring invalid character "' + ch + '" in hex string');
31016 ch = this.nextChar();
31017 continue;
31018 }
31019 } else {
31020 secondDigit = toHexDigit(ch);
31021 if (secondDigit === -1) {
31022 warn('Ignoring invalid character "' + ch + '" in hex string');
31023 ch = this.nextChar();
31024 continue;
31025 }
31026 strBuf.push(String.fromCharCode((firstDigit << 4) | secondDigit));
31027 }
31028 isFirstHex = !isFirstHex;
31029 ch = this.nextChar();
31030 }
31031 }
31032 return strBuf.join('');
31033 },
31034 getObj: function Lexer_getObj() {
31035 // skip whitespace and comments
31036 var comment = false;
31037 var ch = this.currentChar;
31038 while (true) {
31039 if (ch < 0) {
31040 return EOF;
31041 }
31042 if (comment) {
31043 if (ch === 0x0A || ch === 0x0D) { // LF, CR
31044 comment = false;
31045 }
31046 } else if (ch === 0x25) { // '%'
31047 comment = true;
31048 } else if (specialChars[ch] !== 1) {
31049 break;
31050 }
31051 ch = this.nextChar();
31052 }
31053
31054 // start reading token
31055 switch (ch | 0) {
31056 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
31057 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
31058 case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
31059 return this.getNumber();
31060 case 0x28: // '('
31061 return this.getString();
31062 case 0x2F: // '/'
31063 return this.getName();
31064 // array punctuation
31065 case 0x5B: // '['
31066 this.nextChar();
31067 return Cmd.get('[');
31068 case 0x5D: // ']'
31069 this.nextChar();
31070 return Cmd.get(']');
31071 // hex string or dict punctuation
31072 case 0x3C: // '<'
31073 ch = this.nextChar();
31074 if (ch === 0x3C) {
31075 // dict punctuation
31076 this.nextChar();
31077 return Cmd.get('<<');
31078 }
31079 return this.getHexString();
31080 // dict punctuation
31081 case 0x3E: // '>'
31082 ch = this.nextChar();
31083 if (ch === 0x3E) {
31084 this.nextChar();
31085 return Cmd.get('>>');
31086 }
31087 return Cmd.get('>');
31088 case 0x7B: // '{'
31089 this.nextChar();
31090 return Cmd.get('{');
31091 case 0x7D: // '}'
31092 this.nextChar();
31093 return Cmd.get('}');
31094 case 0x29: // ')'
31095 error('Illegal character: ' + ch);
31096 break;
31097 }
31098
31099 // command
31100 var str = String.fromCharCode(ch);
31101 var knownCommands = this.knownCommands;
31102 var knownCommandFound = knownCommands && knownCommands[str] !== undefined;
31103 while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
31104 // stop if known command is found and next character does not make
31105 // the str a command
31106 var possibleCommand = str + String.fromCharCode(ch);
31107 if (knownCommandFound && knownCommands[possibleCommand] === undefined) {
31108 break;
31109 }
31110 if (str.length === 128) {
31111 error('Command token too long: ' + str.length);
31112 }
31113 str = possibleCommand;
31114 knownCommandFound = knownCommands && knownCommands[str] !== undefined;
31115 }
31116 if (str === 'true') {
31117 return true;
31118 }
31119 if (str === 'false') {
31120 return false;
31121 }
31122 if (str === 'null') {
31123 return null;
31124 }
31125 return Cmd.get(str);
31126 },
31127 skipToNextLine: function Lexer_skipToNextLine() {
31128 var ch = this.currentChar;
31129 while (ch >= 0) {
31130 if (ch === 0x0D) { // CR
31131 ch = this.nextChar();
31132 if (ch === 0x0A) { // LF
31133 this.nextChar();
31134 }
31135 break;
31136 } else if (ch === 0x0A) { // LF
31137 this.nextChar();
31138 break;
31139 }
31140 ch = this.nextChar();
31141 }
31142 }
31143 };
31144
31145 return Lexer;
31146 })();
31147
31148 var Linearization = {
31149 create: function LinearizationCreate(stream) {
31150 function getInt(name, allowZeroValue) {
31151 var obj = linDict.get(name);
31152 if (isInt(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) {
31153 return obj;
31154 }
31155 throw new Error('The "' + name + '" parameter in the linearization ' +
31156 'dictionary is invalid.');
31157 }
31158 function getHints() {
31159 var hints = linDict.get('H'), hintsLength, item;
31160 if (isArray(hints) &&
31161 ((hintsLength = hints.length) === 2 || hintsLength === 4)) {
31162 for (var index = 0; index < hintsLength; index++) {
31163 if (!(isInt(item = hints[index]) && item > 0)) {
31164 throw new Error('Hint (' + index +
31165 ') in the linearization dictionary is invalid.');
31166 }
31167 }
31168 return hints;
31169 }
31170 throw new Error('Hint array in the linearization dictionary is invalid.');
31171 }
31172 var parser = new Parser(new Lexer(stream), false, null);
31173 var obj1 = parser.getObj();
31174 var obj2 = parser.getObj();
31175 var obj3 = parser.getObj();
31176 var linDict = parser.getObj();
31177 var obj, length;
31178 if (!(isInt(obj1) && isInt(obj2) && isCmd(obj3, 'obj') && isDict(linDict) &&
31179 isNum(obj = linDict.get('Linearized')) && obj > 0)) {
31180 return null; // No valid linearization dictionary found.
31181 } else if ((length = getInt('L')) !== stream.length) {
31182 throw new Error('The "L" parameter in the linearization dictionary ' +
31183 'does not equal the stream length.');
31184 }
31185 return {
31186 length: length,
31187 hints: getHints(),
31188 objectNumberFirst: getInt('O'),
31189 endFirst: getInt('E'),
31190 numPages: getInt('N'),
31191 mainXRefEntriesOffset: getInt('T'),
31192 pageFirst: (linDict.has('P') ? getInt('P', true) : 0)
31193 };
31194 }
31195 };
31196
31197
31198 var PostScriptParser = (function PostScriptParserClosure() {
31199 function PostScriptParser(lexer) {
31200 this.lexer = lexer;
31201 this.operators = [];
31202 this.token = null;
31203 this.prev = null;
31204 }
31205 PostScriptParser.prototype = {
31206 nextToken: function PostScriptParser_nextToken() {
31207 this.prev = this.token;
31208 this.token = this.lexer.getToken();
31209 },
31210 accept: function PostScriptParser_accept(type) {
31211 if (this.token.type === type) {
31212 this.nextToken();
31213 return true;
31214 }
31215 return false;
31216 },
31217 expect: function PostScriptParser_expect(type) {
31218 if (this.accept(type)) {
31219 return true;
31220 }
31221 error('Unexpected symbol: found ' + this.token.type + ' expected ' +
31222 type + '.');
31223 },
31224 parse: function PostScriptParser_parse() {
31225 this.nextToken();
31226 this.expect(PostScriptTokenTypes.LBRACE);
31227 this.parseBlock();
31228 this.expect(PostScriptTokenTypes.RBRACE);
31229 return this.operators;
31230 },
31231 parseBlock: function PostScriptParser_parseBlock() {
31232 while (true) {
31233 if (this.accept(PostScriptTokenTypes.NUMBER)) {
31234 this.operators.push(this.prev.value);
31235 } else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
31236 this.operators.push(this.prev.value);
31237 } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
31238 this.parseCondition();
31239 } else {
31240 return;
31241 }
31242 }
31243 },
31244 parseCondition: function PostScriptParser_parseCondition() {
31245 // Add two place holders that will be updated later
31246 var conditionLocation = this.operators.length;
31247 this.operators.push(null, null);
31248
31249 this.parseBlock();
31250 this.expect(PostScriptTokenTypes.RBRACE);
31251 if (this.accept(PostScriptTokenTypes.IF)) {
31252 // The true block is right after the 'if' so it just falls through on
31253 // true else it jumps and skips the true block.
31254 this.operators[conditionLocation] = this.operators.length;
31255 this.operators[conditionLocation + 1] = 'jz';
31256 } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
31257 var jumpLocation = this.operators.length;
31258 this.operators.push(null, null);
31259 var endOfTrue = this.operators.length;
31260 this.parseBlock();
31261 this.expect(PostScriptTokenTypes.RBRACE);
31262 this.expect(PostScriptTokenTypes.IFELSE);
31263 // The jump is added at the end of the true block to skip the false
31264 // block.
31265 this.operators[jumpLocation] = this.operators.length;
31266 this.operators[jumpLocation + 1] = 'j';
31267
31268 this.operators[conditionLocation] = endOfTrue;
31269 this.operators[conditionLocation + 1] = 'jz';
31270 } else {
31271 error('PS Function: error parsing conditional.');
31272 }
31273 }
31274 };
31275 return PostScriptParser;
31276 })();
31277
31278 var PostScriptTokenTypes = {
31279 LBRACE: 0,
31280 RBRACE: 1,
31281 NUMBER: 2,
31282 OPERATOR: 3,
31283 IF: 4,
31284 IFELSE: 5
31285 };
31286
31287 var PostScriptToken = (function PostScriptTokenClosure() {
31288 function PostScriptToken(type, value) {
31289 this.type = type;
31290 this.value = value;
31291 }
31292
31293 var opCache = {};
31294
31295 PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
31296 var opValue = opCache[op];
31297 if (opValue) {
31298 return opValue;
31299 }
31300 return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
31301 };
31302
31303 PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE,
31304 '{');
31305 PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE,
31306 '}');
31307 PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
31308 PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE,
31309 'IFELSE');
31310 return PostScriptToken;
31311 })();
31312
31313 var PostScriptLexer = (function PostScriptLexerClosure() {
31314 function PostScriptLexer(stream) {
31315 this.stream = stream;
31316 this.nextChar();
31317
31318 this.strBuf = [];
31319 }
31320 PostScriptLexer.prototype = {
31321 nextChar: function PostScriptLexer_nextChar() {
31322 return (this.currentChar = this.stream.getByte());
31323 },
31324 getToken: function PostScriptLexer_getToken() {
31325 var comment = false;
31326 var ch = this.currentChar;
31327
31328 // skip comments
31329 while (true) {
31330 if (ch < 0) {
31331 return EOF;
31332 }
31333
31334 if (comment) {
31335 if (ch === 0x0A || ch === 0x0D) {
31336 comment = false;
31337 }
31338 } else if (ch === 0x25) { // '%'
31339 comment = true;
31340 } else if (!Lexer.isSpace(ch)) {
31341 break;
31342 }
31343 ch = this.nextChar();
31344 }
31345 switch (ch | 0) {
31346 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
31347 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
31348 case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
31349 return new PostScriptToken(PostScriptTokenTypes.NUMBER,
31350 this.getNumber());
31351 case 0x7B: // '{'
31352 this.nextChar();
31353 return PostScriptToken.LBRACE;
31354 case 0x7D: // '}'
31355 this.nextChar();
31356 return PostScriptToken.RBRACE;
31357 }
31358 // operator
31359 var strBuf = this.strBuf;
31360 strBuf.length = 0;
31361 strBuf[0] = String.fromCharCode(ch);
31362
31363 while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z'
31364 ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) {
31365 strBuf.push(String.fromCharCode(ch));
31366 }
31367 var str = strBuf.join('');
31368 switch (str.toLowerCase()) {
31369 case 'if':
31370 return PostScriptToken.IF;
31371 case 'ifelse':
31372 return PostScriptToken.IFELSE;
31373 default:
31374 return PostScriptToken.getOperator(str);
31375 }
31376 },
31377 getNumber: function PostScriptLexer_getNumber() {
31378 var ch = this.currentChar;
31379 var strBuf = this.strBuf;
31380 strBuf.length = 0;
31381 strBuf[0] = String.fromCharCode(ch);
31382
31383 while ((ch = this.nextChar()) >= 0) {
31384 if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9'
31385 ch === 0x2D || ch === 0x2E) { // '-', '.'
31386 strBuf.push(String.fromCharCode(ch));
31387 } else {
31388 break;
31389 }
31390 }
31391 var value = parseFloat(strBuf.join(''));
31392 if (isNaN(value)) {
31393 error('Invalid floating point number: ' + value);
31394 }
31395 return value;
31396 }
31397 };
31398 return PostScriptLexer;
31399 })();
31400
31401
31402 var Stream = (function StreamClosure() {
31403 function Stream(arrayBuffer, start, length, dict) {
31404 this.bytes = (arrayBuffer instanceof Uint8Array ?
31405 arrayBuffer : new Uint8Array(arrayBuffer));
31406 this.start = start || 0;
31407 this.pos = this.start;
31408 this.end = (start + length) || this.bytes.length;
31409 this.dict = dict;
31410 }
31411
31412 // required methods for a stream. if a particular stream does not
31413 // implement these, an error should be thrown
31414 Stream.prototype = {
31415 get length() {
31416 return this.end - this.start;
31417 },
31418 get isEmpty() {
31419 return this.length === 0;
31420 },
31421 getByte: function Stream_getByte() {
31422 if (this.pos >= this.end) {
31423 return -1;
31424 }
31425 return this.bytes[this.pos++];
31426 },
31427 getUint16: function Stream_getUint16() {
31428 var b0 = this.getByte();
31429 var b1 = this.getByte();
31430 if (b0 === -1 || b1 === -1) {
31431 return -1;
31432 }
31433 return (b0 << 8) + b1;
31434 },
31435 getInt32: function Stream_getInt32() {
31436 var b0 = this.getByte();
31437 var b1 = this.getByte();
31438 var b2 = this.getByte();
31439 var b3 = this.getByte();
31440 return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
31441 },
31442 // returns subarray of original buffer
31443 // should only be read
31444 getBytes: function Stream_getBytes(length) {
31445 var bytes = this.bytes;
31446 var pos = this.pos;
31447 var strEnd = this.end;
31448
31449 if (!length) {
31450 return bytes.subarray(pos, strEnd);
31451 }
31452 var end = pos + length;
31453 if (end > strEnd) {
31454 end = strEnd;
31455 }
31456 this.pos = end;
31457 return bytes.subarray(pos, end);
31458 },
31459 peekByte: function Stream_peekByte() {
31460 var peekedByte = this.getByte();
31461 this.pos--;
31462 return peekedByte;
31463 },
31464 peekBytes: function Stream_peekBytes(length) {
31465 var bytes = this.getBytes(length);
31466 this.pos -= bytes.length;
31467 return bytes;
31468 },
31469 skip: function Stream_skip(n) {
31470 if (!n) {
31471 n = 1;
31472 }
31473 this.pos += n;
31474 },
31475 reset: function Stream_reset() {
31476 this.pos = this.start;
31477 },
31478 moveStart: function Stream_moveStart() {
31479 this.start = this.pos;
31480 },
31481 makeSubStream: function Stream_makeSubStream(start, length, dict) {
31482 return new Stream(this.bytes.buffer, start, length, dict);
31483 },
31484 isStream: true
31485 };
31486
31487 return Stream;
31488 })();
31489
31490 var StringStream = (function StringStreamClosure() {
31491 function StringStream(str) {
31492 var length = str.length;
31493 var bytes = new Uint8Array(length);
31494 for (var n = 0; n < length; ++n) {
31495 bytes[n] = str.charCodeAt(n);
31496 }
31497 Stream.call(this, bytes);
31498 }
31499
31500 StringStream.prototype = Stream.prototype;
31501
31502 return StringStream;
31503 })();
31504
31505 // super class for the decoding streams
31506 var DecodeStream = (function DecodeStreamClosure() {
31507 // Lots of DecodeStreams are created whose buffers are never used. For these
31508 // we share a single empty buffer. This is (a) space-efficient and (b) avoids
31509 // having special cases that would be required if we used |null| for an empty
31510 // buffer.
31511 var emptyBuffer = new Uint8Array(0);
31512
31513 function DecodeStream(maybeMinBufferLength) {
31514 this.pos = 0;
31515 this.bufferLength = 0;
31516 this.eof = false;
31517 this.buffer = emptyBuffer;
31518 this.minBufferLength = 512;
31519 if (maybeMinBufferLength) {
31520 // Compute the first power of two that is as big as maybeMinBufferLength.
31521 while (this.minBufferLength < maybeMinBufferLength) {
31522 this.minBufferLength *= 2;
31523 }
31524 }
31525 }
31526
31527 DecodeStream.prototype = {
31528 get isEmpty() {
31529 while (!this.eof && this.bufferLength === 0) {
31530 this.readBlock();
31531 }
31532 return this.bufferLength === 0;
31533 },
31534 ensureBuffer: function DecodeStream_ensureBuffer(requested) {
31535 var buffer = this.buffer;
31536 if (requested <= buffer.byteLength) {
31537 return buffer;
31538 }
31539 var size = this.minBufferLength;
31540 while (size < requested) {
31541 size *= 2;
31542 }
31543 var buffer2 = new Uint8Array(size);
31544 buffer2.set(buffer);
31545 return (this.buffer = buffer2);
31546 },
31547 getByte: function DecodeStream_getByte() {
31548 var pos = this.pos;
31549 while (this.bufferLength <= pos) {
31550 if (this.eof) {
31551 return -1;
31552 }
31553 this.readBlock();
31554 }
31555 return this.buffer[this.pos++];
31556 },
31557 getUint16: function DecodeStream_getUint16() {
31558 var b0 = this.getByte();
31559 var b1 = this.getByte();
31560 if (b0 === -1 || b1 === -1) {
31561 return -1;
31562 }
31563 return (b0 << 8) + b1;
31564 },
31565 getInt32: function DecodeStream_getInt32() {
31566 var b0 = this.getByte();
31567 var b1 = this.getByte();
31568 var b2 = this.getByte();
31569 var b3 = this.getByte();
31570 return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
31571 },
31572 getBytes: function DecodeStream_getBytes(length) {
31573 var end, pos = this.pos;
31574
31575 if (length) {
31576 this.ensureBuffer(pos + length);
31577 end = pos + length;
31578
31579 while (!this.eof && this.bufferLength < end) {
31580 this.readBlock();
31581 }
31582 var bufEnd = this.bufferLength;
31583 if (end > bufEnd) {
31584 end = bufEnd;
31585 }
31586 } else {
31587 while (!this.eof) {
31588 this.readBlock();
31589 }
31590 end = this.bufferLength;
31591 }
31592
31593 this.pos = end;
31594 return this.buffer.subarray(pos, end);
31595 },
31596 peekByte: function DecodeStream_peekByte() {
31597 var peekedByte = this.getByte();
31598 this.pos--;
31599 return peekedByte;
31600 },
31601 peekBytes: function DecodeStream_peekBytes(length) {
31602 var bytes = this.getBytes(length);
31603 this.pos -= bytes.length;
31604 return bytes;
31605 },
31606 makeSubStream: function DecodeStream_makeSubStream(start, length, dict) {
31607 var end = start + length;
31608 while (this.bufferLength <= end && !this.eof) {
31609 this.readBlock();
31610 }
31611 return new Stream(this.buffer, start, length, dict);
31612 },
31613 skip: function DecodeStream_skip(n) {
31614 if (!n) {
31615 n = 1;
31616 }
31617 this.pos += n;
31618 },
31619 reset: function DecodeStream_reset() {
31620 this.pos = 0;
31621 },
31622 getBaseStreams: function DecodeStream_getBaseStreams() {
31623 if (this.str && this.str.getBaseStreams) {
31624 return this.str.getBaseStreams();
31625 }
31626 return [];
31627 }
31628 };
31629
31630 return DecodeStream;
31631 })();
31632
31633 var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
31634 function StreamsSequenceStream(streams) {
31635 this.streams = streams;
31636 DecodeStream.call(this, /* maybeLength = */ null);
31637 }
31638
31639 StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype);
31640
31641 StreamsSequenceStream.prototype.readBlock =
31642 function streamSequenceStreamReadBlock() {
31643
31644 var streams = this.streams;
31645 if (streams.length === 0) {
31646 this.eof = true;
31647 return;
31648 }
31649 var stream = streams.shift();
31650 var chunk = stream.getBytes();
31651 var bufferLength = this.bufferLength;
31652 var newLength = bufferLength + chunk.length;
31653 var buffer = this.ensureBuffer(newLength);
31654 buffer.set(chunk, bufferLength);
31655 this.bufferLength = newLength;
31656 };
31657
31658 StreamsSequenceStream.prototype.getBaseStreams =
31659 function StreamsSequenceStream_getBaseStreams() {
31660
31661 var baseStreams = [];
31662 for (var i = 0, ii = this.streams.length; i < ii; i++) {
31663 var stream = this.streams[i];
31664 if (stream.getBaseStreams) {
31665 Util.appendToArray(baseStreams, stream.getBaseStreams());
31666 }
31667 }
31668 return baseStreams;
31669 };
31670
31671 return StreamsSequenceStream;
31672 })();
31673
31674 var FlateStream = (function FlateStreamClosure() {
31675 var codeLenCodeMap = new Int32Array([
31676 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
31677 ]);
31678
31679 var lengthDecode = new Int32Array([
31680 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
31681 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
31682 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,
31683 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
31684 ]);
31685
31686 var distDecode = new Int32Array([
31687 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
31688 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
31689 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,
31690 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
31691 ]);
31692
31693 var fixedLitCodeTab = [new Int32Array([
31694 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
31695 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
31696 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,
31697 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,
31698 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,
31699 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,
31700 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,
31701 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,
31702 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,
31703 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,
31704 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,
31705 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,
31706 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,
31707 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,
31708 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,
31709 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,
31710 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,
31711 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,
31712 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,
31713 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,
31714 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,
31715 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,
31716 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,
31717 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,
31718 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,
31719 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,
31720 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,
31721 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,
31722 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,
31723 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,
31724 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,
31725 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,
31726 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,
31727 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,
31728 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,
31729 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,
31730 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,
31731 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,
31732 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,
31733 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,
31734 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,
31735 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,
31736 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,
31737 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,
31738 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,
31739 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,
31740 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,
31741 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,
31742 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,
31743 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,
31744 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,
31745 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,
31746 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,
31747 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,
31748 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,
31749 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,
31750 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,
31751 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,
31752 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,
31753 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7,
31754 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,
31755 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,
31756 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,
31757 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
31758 ]), 9];
31759
31760 var fixedDistCodeTab = [new Int32Array([
31761 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
31762 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
31763 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,
31764 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
31765 ]), 5];
31766
31767 function FlateStream(str, maybeLength) {
31768 this.str = str;
31769 this.dict = str.dict;
31770
31771 var cmf = str.getByte();
31772 var flg = str.getByte();
31773 if (cmf === -1 || flg === -1) {
31774 error('Invalid header in flate stream: ' + cmf + ', ' + flg);
31775 }
31776 if ((cmf & 0x0f) !== 0x08) {
31777 error('Unknown compression method in flate stream: ' + cmf + ', ' + flg);
31778 }
31779 if ((((cmf << 8) + flg) % 31) !== 0) {
31780 error('Bad FCHECK in flate stream: ' + cmf + ', ' + flg);
31781 }
31782 if (flg & 0x20) {
31783 error('FDICT bit set in flate stream: ' + cmf + ', ' + flg);
31784 }
31785
31786 this.codeSize = 0;
31787 this.codeBuf = 0;
31788
31789 DecodeStream.call(this, maybeLength);
31790 }
31791
31792 FlateStream.prototype = Object.create(DecodeStream.prototype);
31793
31794 FlateStream.prototype.getBits = function FlateStream_getBits(bits) {
31795 var str = this.str;
31796 var codeSize = this.codeSize;
31797 var codeBuf = this.codeBuf;
31798
31799 var b;
31800 while (codeSize < bits) {
31801 if ((b = str.getByte()) === -1) {
31802 error('Bad encoding in flate stream');
31803 }
31804 codeBuf |= b << codeSize;
31805 codeSize += 8;
31806 }
31807 b = codeBuf & ((1 << bits) - 1);
31808 this.codeBuf = codeBuf >> bits;
31809 this.codeSize = codeSize -= bits;
31810
31811 return b;
31812 };
31813
31814 FlateStream.prototype.getCode = function FlateStream_getCode(table) {
31815 var str = this.str;
31816 var codes = table[0];
31817 var maxLen = table[1];
31818 var codeSize = this.codeSize;
31819 var codeBuf = this.codeBuf;
31820
31821 var b;
31822 while (codeSize < maxLen) {
31823 if ((b = str.getByte()) === -1) {
31824 // premature end of stream. code might however still be valid.
31825 // codeSize < codeLen check below guards against incomplete codeVal.
31826 break;
31827 }
31828 codeBuf |= (b << codeSize);
31829 codeSize += 8;
31830 }
31831 var code = codes[codeBuf & ((1 << maxLen) - 1)];
31832 var codeLen = code >> 16;
31833 var codeVal = code & 0xffff;
31834 if (codeLen < 1 || codeSize < codeLen) {
31835 error('Bad encoding in flate stream');
31836 }
31837 this.codeBuf = (codeBuf >> codeLen);
31838 this.codeSize = (codeSize - codeLen);
31839 return codeVal;
31840 };
31841
31842 FlateStream.prototype.generateHuffmanTable =
31843 function flateStreamGenerateHuffmanTable(lengths) {
31844 var n = lengths.length;
31845
31846 // find max code length
31847 var maxLen = 0;
31848 var i;
31849 for (i = 0; i < n; ++i) {
31850 if (lengths[i] > maxLen) {
31851 maxLen = lengths[i];
31852 }
31853 }
31854
31855 // build the table
31856 var size = 1 << maxLen;
31857 var codes = new Int32Array(size);
31858 for (var len = 1, code = 0, skip = 2;
31859 len <= maxLen;
31860 ++len, code <<= 1, skip <<= 1) {
31861 for (var val = 0; val < n; ++val) {
31862 if (lengths[val] === len) {
31863 // bit-reverse the code
31864 var code2 = 0;
31865 var t = code;
31866 for (i = 0; i < len; ++i) {
31867 code2 = (code2 << 1) | (t & 1);
31868 t >>= 1;
31869 }
31870
31871 // fill the table entries
31872 for (i = code2; i < size; i += skip) {
31873 codes[i] = (len << 16) | val;
31874 }
31875 ++code;
31876 }
31877 }
31878 }
31879
31880 return [codes, maxLen];
31881 };
31882
31883 FlateStream.prototype.readBlock = function FlateStream_readBlock() {
31884 var buffer, len;
31885 var str = this.str;
31886 // read block header
31887 var hdr = this.getBits(3);
31888 if (hdr & 1) {
31889 this.eof = true;
31890 }
31891 hdr >>= 1;
31892
31893 if (hdr === 0) { // uncompressed block
31894 var b;
31895
31896 if ((b = str.getByte()) === -1) {
31897 error('Bad block header in flate stream');
31898 }
31899 var blockLen = b;
31900 if ((b = str.getByte()) === -1) {
31901 error('Bad block header in flate stream');
31902 }
31903 blockLen |= (b << 8);
31904 if ((b = str.getByte()) === -1) {
31905 error('Bad block header in flate stream');
31906 }
31907 var check = b;
31908 if ((b = str.getByte()) === -1) {
31909 error('Bad block header in flate stream');
31910 }
31911 check |= (b << 8);
31912 if (check !== (~blockLen & 0xffff) &&
31913 (blockLen !== 0 || check !== 0)) {
31914 // Ignoring error for bad "empty" block (see issue 1277)
31915 error('Bad uncompressed block length in flate stream');
31916 }
31917
31918 this.codeBuf = 0;
31919 this.codeSize = 0;
31920
31921 var bufferLength = this.bufferLength;
31922 buffer = this.ensureBuffer(bufferLength + blockLen);
31923 var end = bufferLength + blockLen;
31924 this.bufferLength = end;
31925 if (blockLen === 0) {
31926 if (str.peekByte() === -1) {
31927 this.eof = true;
31928 }
31929 } else {
31930 for (var n = bufferLength; n < end; ++n) {
31931 if ((b = str.getByte()) === -1) {
31932 this.eof = true;
31933 break;
31934 }
31935 buffer[n] = b;
31936 }
31937 }
31938 return;
31939 }
31940
31941 var litCodeTable;
31942 var distCodeTable;
31943 if (hdr === 1) { // compressed block, fixed codes
31944 litCodeTable = fixedLitCodeTab;
31945 distCodeTable = fixedDistCodeTab;
31946 } else if (hdr === 2) { // compressed block, dynamic codes
31947 var numLitCodes = this.getBits(5) + 257;
31948 var numDistCodes = this.getBits(5) + 1;
31949 var numCodeLenCodes = this.getBits(4) + 4;
31950
31951 // build the code lengths code table
31952 var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length);
31953
31954 var i;
31955 for (i = 0; i < numCodeLenCodes; ++i) {
31956 codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3);
31957 }
31958 var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
31959
31960 // build the literal and distance code tables
31961 len = 0;
31962 i = 0;
31963 var codes = numLitCodes + numDistCodes;
31964 var codeLengths = new Uint8Array(codes);
31965 var bitsLength, bitsOffset, what;
31966 while (i < codes) {
31967 var code = this.getCode(codeLenCodeTab);
31968 if (code === 16) {
31969 bitsLength = 2; bitsOffset = 3; what = len;
31970 } else if (code === 17) {
31971 bitsLength = 3; bitsOffset = 3; what = (len = 0);
31972 } else if (code === 18) {
31973 bitsLength = 7; bitsOffset = 11; what = (len = 0);
31974 } else {
31975 codeLengths[i++] = len = code;
31976 continue;
31977 }
31978
31979 var repeatLength = this.getBits(bitsLength) + bitsOffset;
31980 while (repeatLength-- > 0) {
31981 codeLengths[i++] = what;
31982 }
31983 }
31984
31985 litCodeTable =
31986 this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes));
31987 distCodeTable =
31988 this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes));
31989 } else {
31990 error('Unknown block type in flate stream');
31991 }
31992
31993 buffer = this.buffer;
31994 var limit = buffer ? buffer.length : 0;
31995 var pos = this.bufferLength;
31996 while (true) {
31997 var code1 = this.getCode(litCodeTable);
31998 if (code1 < 256) {
31999 if (pos + 1 >= limit) {
32000 buffer = this.ensureBuffer(pos + 1);
32001 limit = buffer.length;
32002 }
32003 buffer[pos++] = code1;
32004 continue;
32005 }
32006 if (code1 === 256) {
32007 this.bufferLength = pos;
32008 return;
32009 }
32010 code1 -= 257;
32011 code1 = lengthDecode[code1];
32012 var code2 = code1 >> 16;
32013 if (code2 > 0) {
32014 code2 = this.getBits(code2);
32015 }
32016 len = (code1 & 0xffff) + code2;
32017 code1 = this.getCode(distCodeTable);
32018 code1 = distDecode[code1];
32019 code2 = code1 >> 16;
32020 if (code2 > 0) {
32021 code2 = this.getBits(code2);
32022 }
32023 var dist = (code1 & 0xffff) + code2;
32024 if (pos + len >= limit) {
32025 buffer = this.ensureBuffer(pos + len);
32026 limit = buffer.length;
32027 }
32028 for (var k = 0; k < len; ++k, ++pos) {
32029 buffer[pos] = buffer[pos - dist];
32030 }
32031 }
32032 };
32033
32034 return FlateStream;
32035 })();
32036
32037 var PredictorStream = (function PredictorStreamClosure() {
32038 function PredictorStream(str, maybeLength, params) {
32039 var predictor = this.predictor = params.get('Predictor') || 1;
32040
32041 if (predictor <= 1) {
32042 return str; // no prediction
32043 }
32044 if (predictor !== 2 && (predictor < 10 || predictor > 15)) {
32045 error('Unsupported predictor: ' + predictor);
32046 }
32047
32048 if (predictor === 2) {
32049 this.readBlock = this.readBlockTiff;
32050 } else {
32051 this.readBlock = this.readBlockPng;
32052 }
32053
32054 this.str = str;
32055 this.dict = str.dict;
32056
32057 var colors = this.colors = params.get('Colors') || 1;
32058 var bits = this.bits = params.get('BitsPerComponent') || 8;
32059 var columns = this.columns = params.get('Columns') || 1;
32060
32061 this.pixBytes = (colors * bits + 7) >> 3;
32062 this.rowBytes = (columns * colors * bits + 7) >> 3;
32063
32064 DecodeStream.call(this, maybeLength);
32065 return this;
32066 }
32067
32068 PredictorStream.prototype = Object.create(DecodeStream.prototype);
32069
32070 PredictorStream.prototype.readBlockTiff =
32071 function predictorStreamReadBlockTiff() {
32072 var rowBytes = this.rowBytes;
32073
32074 var bufferLength = this.bufferLength;
32075 var buffer = this.ensureBuffer(bufferLength + rowBytes);
32076
32077 var bits = this.bits;
32078 var colors = this.colors;
32079
32080 var rawBytes = this.str.getBytes(rowBytes);
32081 this.eof = !rawBytes.length;
32082 if (this.eof) {
32083 return;
32084 }
32085
32086 var inbuf = 0, outbuf = 0;
32087 var inbits = 0, outbits = 0;
32088 var pos = bufferLength;
32089 var i;
32090
32091 if (bits === 1) {
32092 for (i = 0; i < rowBytes; ++i) {
32093 var c = rawBytes[i];
32094 inbuf = (inbuf << 8) | c;
32095 // bitwise addition is exclusive or
32096 // first shift inbuf and then add
32097 buffer[pos++] = (c ^ (inbuf >> colors)) & 0xFF;
32098 // truncate inbuf (assumes colors < 16)
32099 inbuf &= 0xFFFF;
32100 }
32101 } else if (bits === 8) {
32102 for (i = 0; i < colors; ++i) {
32103 buffer[pos++] = rawBytes[i];
32104 }
32105 for (; i < rowBytes; ++i) {
32106 buffer[pos] = buffer[pos - colors] + rawBytes[i];
32107 pos++;
32108 }
32109 } else {
32110 var compArray = new Uint8Array(colors + 1);
32111 var bitMask = (1 << bits) - 1;
32112 var j = 0, k = bufferLength;
32113 var columns = this.columns;
32114 for (i = 0; i < columns; ++i) {
32115 for (var kk = 0; kk < colors; ++kk) {
32116 if (inbits < bits) {
32117 inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);
32118 inbits += 8;
32119 }
32120 compArray[kk] = (compArray[kk] +
32121 (inbuf >> (inbits - bits))) & bitMask;
32122 inbits -= bits;
32123 outbuf = (outbuf << bits) | compArray[kk];
32124 outbits += bits;
32125 if (outbits >= 8) {
32126 buffer[k++] = (outbuf >> (outbits - 8)) & 0xFF;
32127 outbits -= 8;
32128 }
32129 }
32130 }
32131 if (outbits > 0) {
32132 buffer[k++] = (outbuf << (8 - outbits)) +
32133 (inbuf & ((1 << (8 - outbits)) - 1));
32134 }
32135 }
32136 this.bufferLength += rowBytes;
32137 };
32138
32139 PredictorStream.prototype.readBlockPng =
32140 function predictorStreamReadBlockPng() {
32141
32142 var rowBytes = this.rowBytes;
32143 var pixBytes = this.pixBytes;
32144
32145 var predictor = this.str.getByte();
32146 var rawBytes = this.str.getBytes(rowBytes);
32147 this.eof = !rawBytes.length;
32148 if (this.eof) {
32149 return;
32150 }
32151
32152 var bufferLength = this.bufferLength;
32153 var buffer = this.ensureBuffer(bufferLength + rowBytes);
32154
32155 var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
32156 if (prevRow.length === 0) {
32157 prevRow = new Uint8Array(rowBytes);
32158 }
32159
32160 var i, j = bufferLength, up, c;
32161 switch (predictor) {
32162 case 0:
32163 for (i = 0; i < rowBytes; ++i) {
32164 buffer[j++] = rawBytes[i];
32165 }
32166 break;
32167 case 1:
32168 for (i = 0; i < pixBytes; ++i) {
32169 buffer[j++] = rawBytes[i];
32170 }
32171 for (; i < rowBytes; ++i) {
32172 buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xFF;
32173 j++;
32174 }
32175 break;
32176 case 2:
32177 for (i = 0; i < rowBytes; ++i) {
32178 buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF;
32179 }
32180 break;
32181 case 3:
32182 for (i = 0; i < pixBytes; ++i) {
32183 buffer[j++] = (prevRow[i] >> 1) + rawBytes[i];
32184 }
32185 for (; i < rowBytes; ++i) {
32186 buffer[j] = (((prevRow[i] + buffer[j - pixBytes]) >> 1) +
32187 rawBytes[i]) & 0xFF;
32188 j++;
32189 }
32190 break;
32191 case 4:
32192 // we need to save the up left pixels values. the simplest way
32193 // is to create a new buffer
32194 for (i = 0; i < pixBytes; ++i) {
32195 up = prevRow[i];
32196 c = rawBytes[i];
32197 buffer[j++] = up + c;
32198 }
32199 for (; i < rowBytes; ++i) {
32200 up = prevRow[i];
32201 var upLeft = prevRow[i - pixBytes];
32202 var left = buffer[j - pixBytes];
32203 var p = left + up - upLeft;
32204
32205 var pa = p - left;
32206 if (pa < 0) {
32207 pa = -pa;
32208 }
32209 var pb = p - up;
32210 if (pb < 0) {
32211 pb = -pb;
32212 }
32213 var pc = p - upLeft;
32214 if (pc < 0) {
32215 pc = -pc;
32216 }
32217
32218 c = rawBytes[i];
32219 if (pa <= pb && pa <= pc) {
32220 buffer[j++] = left + c;
32221 } else if (pb <= pc) {
32222 buffer[j++] = up + c;
32223 } else {
32224 buffer[j++] = upLeft + c;
32225 }
32226 }
32227 break;
32228 default:
32229 error('Unsupported predictor: ' + predictor);
32230 }
32231 this.bufferLength += rowBytes;
32232 };
32233
32234 return PredictorStream;
32235 })();
32236
32237 /**
32238 * Depending on the type of JPEG a JpegStream is handled in different ways. For
32239 * JPEG's that are supported natively such as DeviceGray and DeviceRGB the image
32240 * data is stored and then loaded by the browser. For unsupported JPEG's we use
32241 * a library to decode these images and the stream behaves like all the other
32242 * DecodeStreams.
32243 */
32244 var JpegStream = (function JpegStreamClosure() {
32245 function JpegStream(stream, maybeLength, dict, xref) {
32246 // Some images may contain 'junk' before the SOI (start-of-image) marker.
32247 // Note: this seems to mainly affect inline images.
32248 var ch;
32249 while ((ch = stream.getByte()) !== -1) {
32250 if (ch === 0xFF) { // Find the first byte of the SOI marker (0xFFD8).
32251 stream.skip(-1); // Reset the stream position to the SOI.
32252 break;
32253 }
32254 }
32255 this.stream = stream;
32256 this.maybeLength = maybeLength;
32257 this.dict = dict;
32258
32259 DecodeStream.call(this, maybeLength);
32260 }
32261
32262 JpegStream.prototype = Object.create(DecodeStream.prototype);
32263
32264 Object.defineProperty(JpegStream.prototype, 'bytes', {
32265 get: function JpegStream_bytes() {
32266 // If this.maybeLength is null, we'll get the entire stream.
32267 return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
32268 },
32269 configurable: true
32270 });
32271
32272 JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
32273 if (this.bufferLength) {
32274 return;
32275 }
32276 try {
32277 var jpegImage = new JpegImage();
32278
32279 // checking if values needs to be transformed before conversion
32280 if (this.forceRGB && this.dict && isArray(this.dict.get('Decode'))) {
32281 var decodeArr = this.dict.get('Decode');
32282 var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
32283 var decodeArrLength = decodeArr.length;
32284 var transform = new Int32Array(decodeArrLength);
32285 var transformNeeded = false;
32286 var maxValue = (1 << bitsPerComponent) - 1;
32287 for (var i = 0; i < decodeArrLength; i += 2) {
32288 transform[i] = ((decodeArr[i + 1] - decodeArr[i]) * 256) | 0;
32289 transform[i + 1] = (decodeArr[i] * maxValue) | 0;
32290 if (transform[i] !== 256 || transform[i + 1] !== 0) {
32291 transformNeeded = true;
32292 }
32293 }
32294 if (transformNeeded) {
32295 jpegImage.decodeTransform = transform;
32296 }
32297 }
32298
32299 jpegImage.parse(this.bytes);
32300 var data = jpegImage.getData(this.drawWidth, this.drawHeight,
32301 this.forceRGB);
32302 this.buffer = data;
32303 this.bufferLength = data.length;
32304 this.eof = true;
32305 } catch (e) {
32306 error('JPEG error: ' + e);
32307 }
32308 };
32309
32310 JpegStream.prototype.getBytes = function JpegStream_getBytes(length) {
32311 this.ensureBuffer();
32312 return this.buffer;
32313 };
32314
32315 JpegStream.prototype.getIR = function JpegStream_getIR() {
32316 return PDFJS.createObjectURL(this.bytes, 'image/jpeg');
32317 };
32318 /**
32319 * Checks if the image can be decoded and displayed by the browser without any
32320 * further processing such as color space conversions.
32321 */
32322 JpegStream.prototype.isNativelySupported =
32323 function JpegStream_isNativelySupported(xref, res) {
32324 var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
32325 return cs.name === 'DeviceGray' || cs.name === 'DeviceRGB';
32326 };
32327 /**
32328 * Checks if the image can be decoded by the browser.
32329 */
32330 JpegStream.prototype.isNativelyDecodable =
32331 function JpegStream_isNativelyDecodable(xref, res) {
32332 var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
32333 var numComps = cs.numComps;
32334 return numComps === 1 || numComps === 3;
32335 };
32336
32337 return JpegStream;
32338 })();
32339
32340 /**
32341 * For JPEG 2000's we use a library to decode these images and
32342 * the stream behaves like all the other DecodeStreams.
32343 */
32344 var JpxStream = (function JpxStreamClosure() {
32345 function JpxStream(stream, maybeLength, dict) {
32346 this.stream = stream;
32347 this.maybeLength = maybeLength;
32348 this.dict = dict;
32349
32350 DecodeStream.call(this, maybeLength);
32351 }
32352
32353 JpxStream.prototype = Object.create(DecodeStream.prototype);
32354
32355 Object.defineProperty(JpxStream.prototype, 'bytes', {
32356 get: function JpxStream_bytes() {
32357 // If this.maybeLength is null, we'll get the entire stream.
32358 return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
32359 },
32360 configurable: true
32361 });
32362
32363 JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {
32364 if (this.bufferLength) {
32365 return;
32366 }
32367
32368 var jpxImage = new JpxImage();
32369 jpxImage.parse(this.bytes);
32370
32371 var width = jpxImage.width;
32372 var height = jpxImage.height;
32373 var componentsCount = jpxImage.componentsCount;
32374 var tileCount = jpxImage.tiles.length;
32375 if (tileCount === 1) {
32376 this.buffer = jpxImage.tiles[0].items;
32377 } else {
32378 var data = new Uint8Array(width * height * componentsCount);
32379
32380 for (var k = 0; k < tileCount; k++) {
32381 var tileComponents = jpxImage.tiles[k];
32382 var tileWidth = tileComponents.width;
32383 var tileHeight = tileComponents.height;
32384 var tileLeft = tileComponents.left;
32385 var tileTop = tileComponents.top;
32386
32387 var src = tileComponents.items;
32388 var srcPosition = 0;
32389 var dataPosition = (width * tileTop + tileLeft) * componentsCount;
32390 var imgRowSize = width * componentsCount;
32391 var tileRowSize = tileWidth * componentsCount;
32392
32393 for (var j = 0; j < tileHeight; j++) {
32394 var rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);
32395 data.set(rowBytes, dataPosition);
32396 srcPosition += tileRowSize;
32397 dataPosition += imgRowSize;
32398 }
32399 }
32400 this.buffer = data;
32401 }
32402 this.bufferLength = this.buffer.length;
32403 this.eof = true;
32404 };
32405
32406 return JpxStream;
32407 })();
32408
32409 /**
32410 * For JBIG2's we use a library to decode these images and
32411 * the stream behaves like all the other DecodeStreams.
32412 */
32413 var Jbig2Stream = (function Jbig2StreamClosure() {
32414 function Jbig2Stream(stream, maybeLength, dict) {
32415 this.stream = stream;
32416 this.maybeLength = maybeLength;
32417 this.dict = dict;
32418
32419 DecodeStream.call(this, maybeLength);
32420 }
32421
32422 Jbig2Stream.prototype = Object.create(DecodeStream.prototype);
32423
32424 Object.defineProperty(Jbig2Stream.prototype, 'bytes', {
32425 get: function Jbig2Stream_bytes() {
32426 // If this.maybeLength is null, we'll get the entire stream.
32427 return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
32428 },
32429 configurable: true
32430 });
32431
32432 Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) {
32433 if (this.bufferLength) {
32434 return;
32435 }
32436
32437 var jbig2Image = new Jbig2Image();
32438
32439 var chunks = [], xref = this.dict.xref;
32440 var decodeParams = xref.fetchIfRef(this.dict.get('DecodeParms'));
32441
32442 // According to the PDF specification, DecodeParms can be either
32443 // a dictionary, or an array whose elements are dictionaries.
32444 if (isArray(decodeParams)) {
32445 if (decodeParams.length > 1) {
32446 warn('JBIG2 - \'DecodeParms\' array with multiple elements ' +
32447 'not supported.');
32448 }
32449 decodeParams = xref.fetchIfRef(decodeParams[0]);
32450 }
32451 if (decodeParams && decodeParams.has('JBIG2Globals')) {
32452 var globalsStream = decodeParams.get('JBIG2Globals');
32453 var globals = globalsStream.getBytes();
32454 chunks.push({data: globals, start: 0, end: globals.length});
32455 }
32456 chunks.push({data: this.bytes, start: 0, end: this.bytes.length});
32457 var data = jbig2Image.parseChunks(chunks);
32458 var dataLength = data.length;
32459
32460 // JBIG2 had black as 1 and white as 0, inverting the colors
32461 for (var i = 0; i < dataLength; i++) {
32462 data[i] ^= 0xFF;
32463 }
32464
32465 this.buffer = data;
32466 this.bufferLength = dataLength;
32467 this.eof = true;
32468 };
32469
32470 return Jbig2Stream;
32471 })();
32472
32473 var DecryptStream = (function DecryptStreamClosure() {
32474 function DecryptStream(str, maybeLength, decrypt) {
32475 this.str = str;
32476 this.dict = str.dict;
32477 this.decrypt = decrypt;
32478 this.nextChunk = null;
32479 this.initialized = false;
32480
32481 DecodeStream.call(this, maybeLength);
32482 }
32483
32484 var chunkSize = 512;
32485
32486 DecryptStream.prototype = Object.create(DecodeStream.prototype);
32487
32488 DecryptStream.prototype.readBlock = function DecryptStream_readBlock() {
32489 var chunk;
32490 if (this.initialized) {
32491 chunk = this.nextChunk;
32492 } else {
32493 chunk = this.str.getBytes(chunkSize);
32494 this.initialized = true;
32495 }
32496 if (!chunk || chunk.length === 0) {
32497 this.eof = true;
32498 return;
32499 }
32500 this.nextChunk = this.str.getBytes(chunkSize);
32501 var hasMoreData = this.nextChunk && this.nextChunk.length > 0;
32502
32503 var decrypt = this.decrypt;
32504 chunk = decrypt(chunk, !hasMoreData);
32505
32506 var bufferLength = this.bufferLength;
32507 var i, n = chunk.length;
32508 var buffer = this.ensureBuffer(bufferLength + n);
32509 for (i = 0; i < n; i++) {
32510 buffer[bufferLength++] = chunk[i];
32511 }
32512 this.bufferLength = bufferLength;
32513 };
32514
32515 return DecryptStream;
32516 })();
32517
32518 var Ascii85Stream = (function Ascii85StreamClosure() {
32519 function Ascii85Stream(str, maybeLength) {
32520 this.str = str;
32521 this.dict = str.dict;
32522 this.input = new Uint8Array(5);
32523
32524 // Most streams increase in size when decoded, but Ascii85 streams
32525 // typically shrink by ~20%.
32526 if (maybeLength) {
32527 maybeLength = 0.8 * maybeLength;
32528 }
32529 DecodeStream.call(this, maybeLength);
32530 }
32531
32532 Ascii85Stream.prototype = Object.create(DecodeStream.prototype);
32533
32534 Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() {
32535 var TILDA_CHAR = 0x7E; // '~'
32536 var Z_LOWER_CHAR = 0x7A; // 'z'
32537 var EOF = -1;
32538
32539 var str = this.str;
32540
32541 var c = str.getByte();
32542 while (Lexer.isSpace(c)) {
32543 c = str.getByte();
32544 }
32545
32546 if (c === EOF || c === TILDA_CHAR) {
32547 this.eof = true;
32548 return;
32549 }
32550
32551 var bufferLength = this.bufferLength, buffer;
32552 var i;
32553
32554 // special code for z
32555 if (c === Z_LOWER_CHAR) {
32556 buffer = this.ensureBuffer(bufferLength + 4);
32557 for (i = 0; i < 4; ++i) {
32558 buffer[bufferLength + i] = 0;
32559 }
32560 this.bufferLength += 4;
32561 } else {
32562 var input = this.input;
32563 input[0] = c;
32564 for (i = 1; i < 5; ++i) {
32565 c = str.getByte();
32566 while (Lexer.isSpace(c)) {
32567 c = str.getByte();
32568 }
32569
32570 input[i] = c;
32571
32572 if (c === EOF || c === TILDA_CHAR) {
32573 break;
32574 }
32575 }
32576 buffer = this.ensureBuffer(bufferLength + i - 1);
32577 this.bufferLength += i - 1;
32578
32579 // partial ending;
32580 if (i < 5) {
32581 for (; i < 5; ++i) {
32582 input[i] = 0x21 + 84;
32583 }
32584 this.eof = true;
32585 }
32586 var t = 0;
32587 for (i = 0; i < 5; ++i) {
32588 t = t * 85 + (input[i] - 0x21);
32589 }
32590
32591 for (i = 3; i >= 0; --i) {
32592 buffer[bufferLength + i] = t & 0xFF;
32593 t >>= 8;
32594 }
32595 }
32596 };
32597
32598 return Ascii85Stream;
32599 })();
32600
32601 var AsciiHexStream = (function AsciiHexStreamClosure() {
32602 function AsciiHexStream(str, maybeLength) {
32603 this.str = str;
32604 this.dict = str.dict;
32605
32606 this.firstDigit = -1;
32607
32608 // Most streams increase in size when decoded, but AsciiHex streams shrink
32609 // by 50%.
32610 if (maybeLength) {
32611 maybeLength = 0.5 * maybeLength;
32612 }
32613 DecodeStream.call(this, maybeLength);
32614 }
32615
32616 AsciiHexStream.prototype = Object.create(DecodeStream.prototype);
32617
32618 AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() {
32619 var UPSTREAM_BLOCK_SIZE = 8000;
32620 var bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE);
32621 if (!bytes.length) {
32622 this.eof = true;
32623 return;
32624 }
32625
32626 var maxDecodeLength = (bytes.length + 1) >> 1;
32627 var buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength);
32628 var bufferLength = this.bufferLength;
32629
32630 var firstDigit = this.firstDigit;
32631 for (var i = 0, ii = bytes.length; i < ii; i++) {
32632 var ch = bytes[i], digit;
32633 if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
32634 digit = ch & 0x0F;
32635 } else if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {
32636 // 'A'-'Z', 'a'-'z'
32637 digit = (ch & 0x0F) + 9;
32638 } else if (ch === 0x3E) { // '>'
32639 this.eof = true;
32640 break;
32641 } else { // probably whitespace
32642 continue; // ignoring
32643 }
32644 if (firstDigit < 0) {
32645 firstDigit = digit;
32646 } else {
32647 buffer[bufferLength++] = (firstDigit << 4) | digit;
32648 firstDigit = -1;
32649 }
32650 }
32651 if (firstDigit >= 0 && this.eof) {
32652 // incomplete byte
32653 buffer[bufferLength++] = (firstDigit << 4);
32654 firstDigit = -1;
32655 }
32656 this.firstDigit = firstDigit;
32657 this.bufferLength = bufferLength;
32658 };
32659
32660 return AsciiHexStream;
32661 })();
32662
32663 var RunLengthStream = (function RunLengthStreamClosure() {
32664 function RunLengthStream(str, maybeLength) {
32665 this.str = str;
32666 this.dict = str.dict;
32667
32668 DecodeStream.call(this, maybeLength);
32669 }
32670
32671 RunLengthStream.prototype = Object.create(DecodeStream.prototype);
32672
32673 RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() {
32674 // The repeatHeader has following format. The first byte defines type of run
32675 // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes
32676 // (in addition to the second byte from the header), n = 129 through 255 -
32677 // duplicate the second byte from the header (257 - n) times, n = 128 - end.
32678 var repeatHeader = this.str.getBytes(2);
32679 if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] === 128) {
32680 this.eof = true;
32681 return;
32682 }
32683
32684 var buffer;
32685 var bufferLength = this.bufferLength;
32686 var n = repeatHeader[0];
32687 if (n < 128) {
32688 // copy n bytes
32689 buffer = this.ensureBuffer(bufferLength + n + 1);
32690 buffer[bufferLength++] = repeatHeader[1];
32691 if (n > 0) {
32692 var source = this.str.getBytes(n);
32693 buffer.set(source, bufferLength);
32694 bufferLength += n;
32695 }
32696 } else {
32697 n = 257 - n;
32698 var b = repeatHeader[1];
32699 buffer = this.ensureBuffer(bufferLength + n + 1);
32700 for (var i = 0; i < n; i++) {
32701 buffer[bufferLength++] = b;
32702 }
32703 }
32704 this.bufferLength = bufferLength;
32705 };
32706
32707 return RunLengthStream;
32708 })();
32709
32710 var CCITTFaxStream = (function CCITTFaxStreamClosure() {
32711
32712 var ccittEOL = -2;
32713 var twoDimPass = 0;
32714 var twoDimHoriz = 1;
32715 var twoDimVert0 = 2;
32716 var twoDimVertR1 = 3;
32717 var twoDimVertL1 = 4;
32718 var twoDimVertR2 = 5;
32719 var twoDimVertL2 = 6;
32720 var twoDimVertR3 = 7;
32721 var twoDimVertL3 = 8;
32722
32723 var twoDimTable = [
32724 [-1, -1], [-1, -1], // 000000x
32725 [7, twoDimVertL3], // 0000010
32726 [7, twoDimVertR3], // 0000011
32727 [6, twoDimVertL2], [6, twoDimVertL2], // 000010x
32728 [6, twoDimVertR2], [6, twoDimVertR2], // 000011x
32729 [4, twoDimPass], [4, twoDimPass], // 0001xxx
32730 [4, twoDimPass], [4, twoDimPass],
32731 [4, twoDimPass], [4, twoDimPass],
32732 [4, twoDimPass], [4, twoDimPass],
32733 [3, twoDimHoriz], [3, twoDimHoriz], // 001xxxx
32734 [3, twoDimHoriz], [3, twoDimHoriz],
32735 [3, twoDimHoriz], [3, twoDimHoriz],
32736 [3, twoDimHoriz], [3, twoDimHoriz],
32737 [3, twoDimHoriz], [3, twoDimHoriz],
32738 [3, twoDimHoriz], [3, twoDimHoriz],
32739 [3, twoDimHoriz], [3, twoDimHoriz],
32740 [3, twoDimHoriz], [3, twoDimHoriz],
32741 [3, twoDimVertL1], [3, twoDimVertL1], // 010xxxx
32742 [3, twoDimVertL1], [3, twoDimVertL1],
32743 [3, twoDimVertL1], [3, twoDimVertL1],
32744 [3, twoDimVertL1], [3, twoDimVertL1],
32745 [3, twoDimVertL1], [3, twoDimVertL1],
32746 [3, twoDimVertL1], [3, twoDimVertL1],
32747 [3, twoDimVertL1], [3, twoDimVertL1],
32748 [3, twoDimVertL1], [3, twoDimVertL1],
32749 [3, twoDimVertR1], [3, twoDimVertR1], // 011xxxx
32750 [3, twoDimVertR1], [3, twoDimVertR1],
32751 [3, twoDimVertR1], [3, twoDimVertR1],
32752 [3, twoDimVertR1], [3, twoDimVertR1],
32753 [3, twoDimVertR1], [3, twoDimVertR1],
32754 [3, twoDimVertR1], [3, twoDimVertR1],
32755 [3, twoDimVertR1], [3, twoDimVertR1],
32756 [3, twoDimVertR1], [3, twoDimVertR1],
32757 [1, twoDimVert0], [1, twoDimVert0], // 1xxxxxx
32758 [1, twoDimVert0], [1, twoDimVert0],
32759 [1, twoDimVert0], [1, twoDimVert0],
32760 [1, twoDimVert0], [1, twoDimVert0],
32761 [1, twoDimVert0], [1, twoDimVert0],
32762 [1, twoDimVert0], [1, twoDimVert0],
32763 [1, twoDimVert0], [1, twoDimVert0],
32764 [1, twoDimVert0], [1, twoDimVert0],
32765 [1, twoDimVert0], [1, twoDimVert0],
32766 [1, twoDimVert0], [1, twoDimVert0],
32767 [1, twoDimVert0], [1, twoDimVert0],
32768 [1, twoDimVert0], [1, twoDimVert0],
32769 [1, twoDimVert0], [1, twoDimVert0],
32770 [1, twoDimVert0], [1, twoDimVert0],
32771 [1, twoDimVert0], [1, twoDimVert0],
32772 [1, twoDimVert0], [1, twoDimVert0],
32773 [1, twoDimVert0], [1, twoDimVert0],
32774 [1, twoDimVert0], [1, twoDimVert0],
32775 [1, twoDimVert0], [1, twoDimVert0],
32776 [1, twoDimVert0], [1, twoDimVert0],
32777 [1, twoDimVert0], [1, twoDimVert0],
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 ];
32790
32791 var whiteTable1 = [
32792 [-1, -1], // 00000
32793 [12, ccittEOL], // 00001
32794 [-1, -1], [-1, -1], // 0001x
32795 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 001xx
32796 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 010xx
32797 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 011xx
32798 [11, 1792], [11, 1792], // 1000x
32799 [12, 1984], // 10010
32800 [12, 2048], // 10011
32801 [12, 2112], // 10100
32802 [12, 2176], // 10101
32803 [12, 2240], // 10110
32804 [12, 2304], // 10111
32805 [11, 1856], [11, 1856], // 1100x
32806 [11, 1920], [11, 1920], // 1101x
32807 [12, 2368], // 11100
32808 [12, 2432], // 11101
32809 [12, 2496], // 11110
32810 [12, 2560] // 11111
32811 ];
32812
32813 var whiteTable2 = [
32814 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000000xx
32815 [8, 29], [8, 29], // 00000010x
32816 [8, 30], [8, 30], // 00000011x
32817 [8, 45], [8, 45], // 00000100x
32818 [8, 46], [8, 46], // 00000101x
32819 [7, 22], [7, 22], [7, 22], [7, 22], // 0000011xx
32820 [7, 23], [7, 23], [7, 23], [7, 23], // 0000100xx
32821 [8, 47], [8, 47], // 00001010x
32822 [8, 48], [8, 48], // 00001011x
32823 [6, 13], [6, 13], [6, 13], [6, 13], // 000011xxx
32824 [6, 13], [6, 13], [6, 13], [6, 13],
32825 [7, 20], [7, 20], [7, 20], [7, 20], // 0001000xx
32826 [8, 33], [8, 33], // 00010010x
32827 [8, 34], [8, 34], // 00010011x
32828 [8, 35], [8, 35], // 00010100x
32829 [8, 36], [8, 36], // 00010101x
32830 [8, 37], [8, 37], // 00010110x
32831 [8, 38], [8, 38], // 00010111x
32832 [7, 19], [7, 19], [7, 19], [7, 19], // 0001100xx
32833 [8, 31], [8, 31], // 00011010x
32834 [8, 32], [8, 32], // 00011011x
32835 [6, 1], [6, 1], [6, 1], [6, 1], // 000111xxx
32836 [6, 1], [6, 1], [6, 1], [6, 1],
32837 [6, 12], [6, 12], [6, 12], [6, 12], // 001000xxx
32838 [6, 12], [6, 12], [6, 12], [6, 12],
32839 [8, 53], [8, 53], // 00100100x
32840 [8, 54], [8, 54], // 00100101x
32841 [7, 26], [7, 26], [7, 26], [7, 26], // 0010011xx
32842 [8, 39], [8, 39], // 00101000x
32843 [8, 40], [8, 40], // 00101001x
32844 [8, 41], [8, 41], // 00101010x
32845 [8, 42], [8, 42], // 00101011x
32846 [8, 43], [8, 43], // 00101100x
32847 [8, 44], [8, 44], // 00101101x
32848 [7, 21], [7, 21], [7, 21], [7, 21], // 0010111xx
32849 [7, 28], [7, 28], [7, 28], [7, 28], // 0011000xx
32850 [8, 61], [8, 61], // 00110010x
32851 [8, 62], [8, 62], // 00110011x
32852 [8, 63], [8, 63], // 00110100x
32853 [8, 0], [8, 0], // 00110101x
32854 [8, 320], [8, 320], // 00110110x
32855 [8, 384], [8, 384], // 00110111x
32856 [5, 10], [5, 10], [5, 10], [5, 10], // 00111xxxx
32857 [5, 10], [5, 10], [5, 10], [5, 10],
32858 [5, 10], [5, 10], [5, 10], [5, 10],
32859 [5, 10], [5, 10], [5, 10], [5, 10],
32860 [5, 11], [5, 11], [5, 11], [5, 11], // 01000xxxx
32861 [5, 11], [5, 11], [5, 11], [5, 11],
32862 [5, 11], [5, 11], [5, 11], [5, 11],
32863 [5, 11], [5, 11], [5, 11], [5, 11],
32864 [7, 27], [7, 27], [7, 27], [7, 27], // 0100100xx
32865 [8, 59], [8, 59], // 01001010x
32866 [8, 60], [8, 60], // 01001011x
32867 [9, 1472], // 010011000
32868 [9, 1536], // 010011001
32869 [9, 1600], // 010011010
32870 [9, 1728], // 010011011
32871 [7, 18], [7, 18], [7, 18], [7, 18], // 0100111xx
32872 [7, 24], [7, 24], [7, 24], [7, 24], // 0101000xx
32873 [8, 49], [8, 49], // 01010010x
32874 [8, 50], [8, 50], // 01010011x
32875 [8, 51], [8, 51], // 01010100x
32876 [8, 52], [8, 52], // 01010101x
32877 [7, 25], [7, 25], [7, 25], [7, 25], // 0101011xx
32878 [8, 55], [8, 55], // 01011000x
32879 [8, 56], [8, 56], // 01011001x
32880 [8, 57], [8, 57], // 01011010x
32881 [8, 58], [8, 58], // 01011011x
32882 [6, 192], [6, 192], [6, 192], [6, 192], // 010111xxx
32883 [6, 192], [6, 192], [6, 192], [6, 192],
32884 [6, 1664], [6, 1664], [6, 1664], [6, 1664], // 011000xxx
32885 [6, 1664], [6, 1664], [6, 1664], [6, 1664],
32886 [8, 448], [8, 448], // 01100100x
32887 [8, 512], [8, 512], // 01100101x
32888 [9, 704], // 011001100
32889 [9, 768], // 011001101
32890 [8, 640], [8, 640], // 01100111x
32891 [8, 576], [8, 576], // 01101000x
32892 [9, 832], // 011010010
32893 [9, 896], // 011010011
32894 [9, 960], // 011010100
32895 [9, 1024], // 011010101
32896 [9, 1088], // 011010110
32897 [9, 1152], // 011010111
32898 [9, 1216], // 011011000
32899 [9, 1280], // 011011001
32900 [9, 1344], // 011011010
32901 [9, 1408], // 011011011
32902 [7, 256], [7, 256], [7, 256], [7, 256], // 0110111xx
32903 [4, 2], [4, 2], [4, 2], [4, 2], // 0111xxxxx
32904 [4, 2], [4, 2], [4, 2], [4, 2],
32905 [4, 2], [4, 2], [4, 2], [4, 2],
32906 [4, 2], [4, 2], [4, 2], [4, 2],
32907 [4, 2], [4, 2], [4, 2], [4, 2],
32908 [4, 2], [4, 2], [4, 2], [4, 2],
32909 [4, 2], [4, 2], [4, 2], [4, 2],
32910 [4, 2], [4, 2], [4, 2], [4, 2],
32911 [4, 3], [4, 3], [4, 3], [4, 3], // 1000xxxxx
32912 [4, 3], [4, 3], [4, 3], [4, 3],
32913 [4, 3], [4, 3], [4, 3], [4, 3],
32914 [4, 3], [4, 3], [4, 3], [4, 3],
32915 [4, 3], [4, 3], [4, 3], [4, 3],
32916 [4, 3], [4, 3], [4, 3], [4, 3],
32917 [4, 3], [4, 3], [4, 3], [4, 3],
32918 [4, 3], [4, 3], [4, 3], [4, 3],
32919 [5, 128], [5, 128], [5, 128], [5, 128], // 10010xxxx
32920 [5, 128], [5, 128], [5, 128], [5, 128],
32921 [5, 128], [5, 128], [5, 128], [5, 128],
32922 [5, 128], [5, 128], [5, 128], [5, 128],
32923 [5, 8], [5, 8], [5, 8], [5, 8], // 10011xxxx
32924 [5, 8], [5, 8], [5, 8], [5, 8],
32925 [5, 8], [5, 8], [5, 8], [5, 8],
32926 [5, 8], [5, 8], [5, 8], [5, 8],
32927 [5, 9], [5, 9], [5, 9], [5, 9], // 10100xxxx
32928 [5, 9], [5, 9], [5, 9], [5, 9],
32929 [5, 9], [5, 9], [5, 9], [5, 9],
32930 [5, 9], [5, 9], [5, 9], [5, 9],
32931 [6, 16], [6, 16], [6, 16], [6, 16], // 101010xxx
32932 [6, 16], [6, 16], [6, 16], [6, 16],
32933 [6, 17], [6, 17], [6, 17], [6, 17], // 101011xxx
32934 [6, 17], [6, 17], [6, 17], [6, 17],
32935 [4, 4], [4, 4], [4, 4], [4, 4], // 1011xxxxx
32936 [4, 4], [4, 4], [4, 4], [4, 4],
32937 [4, 4], [4, 4], [4, 4], [4, 4],
32938 [4, 4], [4, 4], [4, 4], [4, 4],
32939 [4, 4], [4, 4], [4, 4], [4, 4],
32940 [4, 4], [4, 4], [4, 4], [4, 4],
32941 [4, 4], [4, 4], [4, 4], [4, 4],
32942 [4, 4], [4, 4], [4, 4], [4, 4],
32943 [4, 5], [4, 5], [4, 5], [4, 5], // 1100xxxxx
32944 [4, 5], [4, 5], [4, 5], [4, 5],
32945 [4, 5], [4, 5], [4, 5], [4, 5],
32946 [4, 5], [4, 5], [4, 5], [4, 5],
32947 [4, 5], [4, 5], [4, 5], [4, 5],
32948 [4, 5], [4, 5], [4, 5], [4, 5],
32949 [4, 5], [4, 5], [4, 5], [4, 5],
32950 [4, 5], [4, 5], [4, 5], [4, 5],
32951 [6, 14], [6, 14], [6, 14], [6, 14], // 110100xxx
32952 [6, 14], [6, 14], [6, 14], [6, 14],
32953 [6, 15], [6, 15], [6, 15], [6, 15], // 110101xxx
32954 [6, 15], [6, 15], [6, 15], [6, 15],
32955 [5, 64], [5, 64], [5, 64], [5, 64], // 11011xxxx
32956 [5, 64], [5, 64], [5, 64], [5, 64],
32957 [5, 64], [5, 64], [5, 64], [5, 64],
32958 [5, 64], [5, 64], [5, 64], [5, 64],
32959 [4, 6], [4, 6], [4, 6], [4, 6], // 1110xxxxx
32960 [4, 6], [4, 6], [4, 6], [4, 6],
32961 [4, 6], [4, 6], [4, 6], [4, 6],
32962 [4, 6], [4, 6], [4, 6], [4, 6],
32963 [4, 6], [4, 6], [4, 6], [4, 6],
32964 [4, 6], [4, 6], [4, 6], [4, 6],
32965 [4, 6], [4, 6], [4, 6], [4, 6],
32966 [4, 6], [4, 6], [4, 6], [4, 6],
32967 [4, 7], [4, 7], [4, 7], [4, 7], // 1111xxxxx
32968 [4, 7], [4, 7], [4, 7], [4, 7],
32969 [4, 7], [4, 7], [4, 7], [4, 7],
32970 [4, 7], [4, 7], [4, 7], [4, 7],
32971 [4, 7], [4, 7], [4, 7], [4, 7],
32972 [4, 7], [4, 7], [4, 7], [4, 7],
32973 [4, 7], [4, 7], [4, 7], [4, 7],
32974 [4, 7], [4, 7], [4, 7], [4, 7]
32975 ];
32976
32977 var blackTable1 = [
32978 [-1, -1], [-1, -1], // 000000000000x
32979 [12, ccittEOL], [12, ccittEOL], // 000000000001x
32980 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000001xx
32981 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000010xx
32982 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000011xx
32983 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000100xx
32984 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000101xx
32985 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000110xx
32986 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 00000000111xx
32987 [11, 1792], [11, 1792], [11, 1792], [11, 1792], // 00000001000xx
32988 [12, 1984], [12, 1984], // 000000010010x
32989 [12, 2048], [12, 2048], // 000000010011x
32990 [12, 2112], [12, 2112], // 000000010100x
32991 [12, 2176], [12, 2176], // 000000010101x
32992 [12, 2240], [12, 2240], // 000000010110x
32993 [12, 2304], [12, 2304], // 000000010111x
32994 [11, 1856], [11, 1856], [11, 1856], [11, 1856], // 00000001100xx
32995 [11, 1920], [11, 1920], [11, 1920], [11, 1920], // 00000001101xx
32996 [12, 2368], [12, 2368], // 000000011100x
32997 [12, 2432], [12, 2432], // 000000011101x
32998 [12, 2496], [12, 2496], // 000000011110x
32999 [12, 2560], [12, 2560], // 000000011111x
33000 [10, 18], [10, 18], [10, 18], [10, 18], // 0000001000xxx
33001 [10, 18], [10, 18], [10, 18], [10, 18],
33002 [12, 52], [12, 52], // 000000100100x
33003 [13, 640], // 0000001001010
33004 [13, 704], // 0000001001011
33005 [13, 768], // 0000001001100
33006 [13, 832], // 0000001001101
33007 [12, 55], [12, 55], // 000000100111x
33008 [12, 56], [12, 56], // 000000101000x
33009 [13, 1280], // 0000001010010
33010 [13, 1344], // 0000001010011
33011 [13, 1408], // 0000001010100
33012 [13, 1472], // 0000001010101
33013 [12, 59], [12, 59], // 000000101011x
33014 [12, 60], [12, 60], // 000000101100x
33015 [13, 1536], // 0000001011010
33016 [13, 1600], // 0000001011011
33017 [11, 24], [11, 24], [11, 24], [11, 24], // 00000010111xx
33018 [11, 25], [11, 25], [11, 25], [11, 25], // 00000011000xx
33019 [13, 1664], // 0000001100100
33020 [13, 1728], // 0000001100101
33021 [12, 320], [12, 320], // 000000110011x
33022 [12, 384], [12, 384], // 000000110100x
33023 [12, 448], [12, 448], // 000000110101x
33024 [13, 512], // 0000001101100
33025 [13, 576], // 0000001101101
33026 [12, 53], [12, 53], // 000000110111x
33027 [12, 54], [12, 54], // 000000111000x
33028 [13, 896], // 0000001110010
33029 [13, 960], // 0000001110011
33030 [13, 1024], // 0000001110100
33031 [13, 1088], // 0000001110101
33032 [13, 1152], // 0000001110110
33033 [13, 1216], // 0000001110111
33034 [10, 64], [10, 64], [10, 64], [10, 64], // 0000001111xxx
33035 [10, 64], [10, 64], [10, 64], [10, 64]
33036 ];
33037
33038 var blackTable2 = [
33039 [8, 13], [8, 13], [8, 13], [8, 13], // 00000100xxxx
33040 [8, 13], [8, 13], [8, 13], [8, 13],
33041 [8, 13], [8, 13], [8, 13], [8, 13],
33042 [8, 13], [8, 13], [8, 13], [8, 13],
33043 [11, 23], [11, 23], // 00000101000x
33044 [12, 50], // 000001010010
33045 [12, 51], // 000001010011
33046 [12, 44], // 000001010100
33047 [12, 45], // 000001010101
33048 [12, 46], // 000001010110
33049 [12, 47], // 000001010111
33050 [12, 57], // 000001011000
33051 [12, 58], // 000001011001
33052 [12, 61], // 000001011010
33053 [12, 256], // 000001011011
33054 [10, 16], [10, 16], [10, 16], [10, 16], // 0000010111xx
33055 [10, 17], [10, 17], [10, 17], [10, 17], // 0000011000xx
33056 [12, 48], // 000001100100
33057 [12, 49], // 000001100101
33058 [12, 62], // 000001100110
33059 [12, 63], // 000001100111
33060 [12, 30], // 000001101000
33061 [12, 31], // 000001101001
33062 [12, 32], // 000001101010
33063 [12, 33], // 000001101011
33064 [12, 40], // 000001101100
33065 [12, 41], // 000001101101
33066 [11, 22], [11, 22], // 00000110111x
33067 [8, 14], [8, 14], [8, 14], [8, 14], // 00000111xxxx
33068 [8, 14], [8, 14], [8, 14], [8, 14],
33069 [8, 14], [8, 14], [8, 14], [8, 14],
33070 [8, 14], [8, 14], [8, 14], [8, 14],
33071 [7, 10], [7, 10], [7, 10], [7, 10], // 0000100xxxxx
33072 [7, 10], [7, 10], [7, 10], [7, 10],
33073 [7, 10], [7, 10], [7, 10], [7, 10],
33074 [7, 10], [7, 10], [7, 10], [7, 10],
33075 [7, 10], [7, 10], [7, 10], [7, 10],
33076 [7, 10], [7, 10], [7, 10], [7, 10],
33077 [7, 10], [7, 10], [7, 10], [7, 10],
33078 [7, 10], [7, 10], [7, 10], [7, 10],
33079 [7, 11], [7, 11], [7, 11], [7, 11], // 0000101xxxxx
33080 [7, 11], [7, 11], [7, 11], [7, 11],
33081 [7, 11], [7, 11], [7, 11], [7, 11],
33082 [7, 11], [7, 11], [7, 11], [7, 11],
33083 [7, 11], [7, 11], [7, 11], [7, 11],
33084 [7, 11], [7, 11], [7, 11], [7, 11],
33085 [7, 11], [7, 11], [7, 11], [7, 11],
33086 [7, 11], [7, 11], [7, 11], [7, 11],
33087 [9, 15], [9, 15], [9, 15], [9, 15], // 000011000xxx
33088 [9, 15], [9, 15], [9, 15], [9, 15],
33089 [12, 128], // 000011001000
33090 [12, 192], // 000011001001
33091 [12, 26], // 000011001010
33092 [12, 27], // 000011001011
33093 [12, 28], // 000011001100
33094 [12, 29], // 000011001101
33095 [11, 19], [11, 19], // 00001100111x
33096 [11, 20], [11, 20], // 00001101000x
33097 [12, 34], // 000011010010
33098 [12, 35], // 000011010011
33099 [12, 36], // 000011010100
33100 [12, 37], // 000011010101
33101 [12, 38], // 000011010110
33102 [12, 39], // 000011010111
33103 [11, 21], [11, 21], // 00001101100x
33104 [12, 42], // 000011011010
33105 [12, 43], // 000011011011
33106 [10, 0], [10, 0], [10, 0], [10, 0], // 0000110111xx
33107 [7, 12], [7, 12], [7, 12], [7, 12], // 0000111xxxxx
33108 [7, 12], [7, 12], [7, 12], [7, 12],
33109 [7, 12], [7, 12], [7, 12], [7, 12],
33110 [7, 12], [7, 12], [7, 12], [7, 12],
33111 [7, 12], [7, 12], [7, 12], [7, 12],
33112 [7, 12], [7, 12], [7, 12], [7, 12],
33113 [7, 12], [7, 12], [7, 12], [7, 12],
33114 [7, 12], [7, 12], [7, 12], [7, 12]
33115 ];
33116
33117 var blackTable3 = [
33118 [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000xx
33119 [6, 9], // 000100
33120 [6, 8], // 000101
33121 [5, 7], [5, 7], // 00011x
33122 [4, 6], [4, 6], [4, 6], [4, 6], // 0010xx
33123 [4, 5], [4, 5], [4, 5], [4, 5], // 0011xx
33124 [3, 1], [3, 1], [3, 1], [3, 1], // 010xxx
33125 [3, 1], [3, 1], [3, 1], [3, 1],
33126 [3, 4], [3, 4], [3, 4], [3, 4], // 011xxx
33127 [3, 4], [3, 4], [3, 4], [3, 4],
33128 [2, 3], [2, 3], [2, 3], [2, 3], // 10xxxx
33129 [2, 3], [2, 3], [2, 3], [2, 3],
33130 [2, 3], [2, 3], [2, 3], [2, 3],
33131 [2, 3], [2, 3], [2, 3], [2, 3],
33132 [2, 2], [2, 2], [2, 2], [2, 2], // 11xxxx
33133 [2, 2], [2, 2], [2, 2], [2, 2],
33134 [2, 2], [2, 2], [2, 2], [2, 2],
33135 [2, 2], [2, 2], [2, 2], [2, 2]
33136 ];
33137
33138 function CCITTFaxStream(str, maybeLength, params) {
33139 this.str = str;
33140 this.dict = str.dict;
33141
33142 params = params || Dict.empty;
33143
33144 this.encoding = params.get('K') || 0;
33145 this.eoline = params.get('EndOfLine') || false;
33146 this.byteAlign = params.get('EncodedByteAlign') || false;
33147 this.columns = params.get('Columns') || 1728;
33148 this.rows = params.get('Rows') || 0;
33149 var eoblock = params.get('EndOfBlock');
33150 if (eoblock === null || eoblock === undefined) {
33151 eoblock = true;
33152 }
33153 this.eoblock = eoblock;
33154 this.black = params.get('BlackIs1') || false;
33155
33156 this.codingLine = new Uint32Array(this.columns + 1);
33157 this.refLine = new Uint32Array(this.columns + 2);
33158
33159 this.codingLine[0] = this.columns;
33160 this.codingPos = 0;
33161
33162 this.row = 0;
33163 this.nextLine2D = this.encoding < 0;
33164 this.inputBits = 0;
33165 this.inputBuf = 0;
33166 this.outputBits = 0;
33167
33168 var code1;
33169 while ((code1 = this.lookBits(12)) === 0) {
33170 this.eatBits(1);
33171 }
33172 if (code1 === 1) {
33173 this.eatBits(12);
33174 }
33175 if (this.encoding > 0) {
33176 this.nextLine2D = !this.lookBits(1);
33177 this.eatBits(1);
33178 }
33179
33180 DecodeStream.call(this, maybeLength);
33181 }
33182
33183 CCITTFaxStream.prototype = Object.create(DecodeStream.prototype);
33184
33185 CCITTFaxStream.prototype.readBlock = function CCITTFaxStream_readBlock() {
33186 while (!this.eof) {
33187 var c = this.lookChar();
33188 this.ensureBuffer(this.bufferLength + 1);
33189 this.buffer[this.bufferLength++] = c;
33190 }
33191 };
33192
33193 CCITTFaxStream.prototype.addPixels =
33194 function ccittFaxStreamAddPixels(a1, blackPixels) {
33195 var codingLine = this.codingLine;
33196 var codingPos = this.codingPos;
33197
33198 if (a1 > codingLine[codingPos]) {
33199 if (a1 > this.columns) {
33200 info('row is wrong length');
33201 this.err = true;
33202 a1 = this.columns;
33203 }
33204 if ((codingPos & 1) ^ blackPixels) {
33205 ++codingPos;
33206 }
33207
33208 codingLine[codingPos] = a1;
33209 }
33210 this.codingPos = codingPos;
33211 };
33212
33213 CCITTFaxStream.prototype.addPixelsNeg =
33214 function ccittFaxStreamAddPixelsNeg(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 } else if (a1 < codingLine[codingPos]) {
33230 if (a1 < 0) {
33231 info('invalid code');
33232 this.err = true;
33233 a1 = 0;
33234 }
33235 while (codingPos > 0 && a1 < codingLine[codingPos - 1]) {
33236 --codingPos;
33237 }
33238 codingLine[codingPos] = a1;
33239 }
33240
33241 this.codingPos = codingPos;
33242 };
33243
33244 CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() {
33245 var refLine = this.refLine;
33246 var codingLine = this.codingLine;
33247 var columns = this.columns;
33248
33249 var refPos, blackPixels, bits, i;
33250
33251 if (this.outputBits === 0) {
33252 if (this.eof) {
33253 return null;
33254 }
33255 this.err = false;
33256
33257 var code1, code2, code3;
33258 if (this.nextLine2D) {
33259 for (i = 0; codingLine[i] < columns; ++i) {
33260 refLine[i] = codingLine[i];
33261 }
33262 refLine[i++] = columns;
33263 refLine[i] = columns;
33264 codingLine[0] = 0;
33265 this.codingPos = 0;
33266 refPos = 0;
33267 blackPixels = 0;
33268
33269 while (codingLine[this.codingPos] < columns) {
33270 code1 = this.getTwoDimCode();
33271 switch (code1) {
33272 case twoDimPass:
33273 this.addPixels(refLine[refPos + 1], blackPixels);
33274 if (refLine[refPos + 1] < columns) {
33275 refPos += 2;
33276 }
33277 break;
33278 case twoDimHoriz:
33279 code1 = code2 = 0;
33280 if (blackPixels) {
33281 do {
33282 code1 += (code3 = this.getBlackCode());
33283 } while (code3 >= 64);
33284 do {
33285 code2 += (code3 = this.getWhiteCode());
33286 } while (code3 >= 64);
33287 } else {
33288 do {
33289 code1 += (code3 = this.getWhiteCode());
33290 } while (code3 >= 64);
33291 do {
33292 code2 += (code3 = this.getBlackCode());
33293 } while (code3 >= 64);
33294 }
33295 this.addPixels(codingLine[this.codingPos] +
33296 code1, blackPixels);
33297 if (codingLine[this.codingPos] < columns) {
33298 this.addPixels(codingLine[this.codingPos] + code2,
33299 blackPixels ^ 1);
33300 }
33301 while (refLine[refPos] <= codingLine[this.codingPos] &&
33302 refLine[refPos] < columns) {
33303 refPos += 2;
33304 }
33305 break;
33306 case twoDimVertR3:
33307 this.addPixels(refLine[refPos] + 3, blackPixels);
33308 blackPixels ^= 1;
33309 if (codingLine[this.codingPos] < columns) {
33310 ++refPos;
33311 while (refLine[refPos] <= codingLine[this.codingPos] &&
33312 refLine[refPos] < columns) {
33313 refPos += 2;
33314 }
33315 }
33316 break;
33317 case twoDimVertR2:
33318 this.addPixels(refLine[refPos] + 2, blackPixels);
33319 blackPixels ^= 1;
33320 if (codingLine[this.codingPos] < columns) {
33321 ++refPos;
33322 while (refLine[refPos] <= codingLine[this.codingPos] &&
33323 refLine[refPos] < columns) {
33324 refPos += 2;
33325 }
33326 }
33327 break;
33328 case twoDimVertR1:
33329 this.addPixels(refLine[refPos] + 1, blackPixels);
33330 blackPixels ^= 1;
33331 if (codingLine[this.codingPos] < columns) {
33332 ++refPos;
33333 while (refLine[refPos] <= codingLine[this.codingPos] &&
33334 refLine[refPos] < columns) {
33335 refPos += 2;
33336 }
33337 }
33338 break;
33339 case twoDimVert0:
33340 this.addPixels(refLine[refPos], blackPixels);
33341 blackPixels ^= 1;
33342 if (codingLine[this.codingPos] < columns) {
33343 ++refPos;
33344 while (refLine[refPos] <= codingLine[this.codingPos] &&
33345 refLine[refPos] < columns) {
33346 refPos += 2;
33347 }
33348 }
33349 break;
33350 case twoDimVertL3:
33351 this.addPixelsNeg(refLine[refPos] - 3, blackPixels);
33352 blackPixels ^= 1;
33353 if (codingLine[this.codingPos] < columns) {
33354 if (refPos > 0) {
33355 --refPos;
33356 } else {
33357 ++refPos;
33358 }
33359 while (refLine[refPos] <= codingLine[this.codingPos] &&
33360 refLine[refPos] < columns) {
33361 refPos += 2;
33362 }
33363 }
33364 break;
33365 case twoDimVertL2:
33366 this.addPixelsNeg(refLine[refPos] - 2, blackPixels);
33367 blackPixels ^= 1;
33368 if (codingLine[this.codingPos] < columns) {
33369 if (refPos > 0) {
33370 --refPos;
33371 } else {
33372 ++refPos;
33373 }
33374 while (refLine[refPos] <= codingLine[this.codingPos] &&
33375 refLine[refPos] < columns) {
33376 refPos += 2;
33377 }
33378 }
33379 break;
33380 case twoDimVertL1:
33381 this.addPixelsNeg(refLine[refPos] - 1, blackPixels);
33382 blackPixels ^= 1;
33383 if (codingLine[this.codingPos] < columns) {
33384 if (refPos > 0) {
33385 --refPos;
33386 } else {
33387 ++refPos;
33388 }
33389 while (refLine[refPos] <= codingLine[this.codingPos] &&
33390 refLine[refPos] < columns) {
33391 refPos += 2;
33392 }
33393 }
33394 break;
33395 case EOF:
33396 this.addPixels(columns, 0);
33397 this.eof = true;
33398 break;
33399 default:
33400 info('bad 2d code');
33401 this.addPixels(columns, 0);
33402 this.err = true;
33403 }
33404 }
33405 } else {
33406 codingLine[0] = 0;
33407 this.codingPos = 0;
33408 blackPixels = 0;
33409 while (codingLine[this.codingPos] < columns) {
33410 code1 = 0;
33411 if (blackPixels) {
33412 do {
33413 code1 += (code3 = this.getBlackCode());
33414 } while (code3 >= 64);
33415 } else {
33416 do {
33417 code1 += (code3 = this.getWhiteCode());
33418 } while (code3 >= 64);
33419 }
33420 this.addPixels(codingLine[this.codingPos] + code1, blackPixels);
33421 blackPixels ^= 1;
33422 }
33423 }
33424
33425 var gotEOL = false;
33426
33427 if (this.byteAlign) {
33428 this.inputBits &= ~7;
33429 }
33430
33431 if (!this.eoblock && this.row === this.rows - 1) {
33432 this.eof = true;
33433 } else {
33434 code1 = this.lookBits(12);
33435 if (this.eoline) {
33436 while (code1 !== EOF && code1 !== 1) {
33437 this.eatBits(1);
33438 code1 = this.lookBits(12);
33439 }
33440 } else {
33441 while (code1 === 0) {
33442 this.eatBits(1);
33443 code1 = this.lookBits(12);
33444 }
33445 }
33446 if (code1 === 1) {
33447 this.eatBits(12);
33448 gotEOL = true;
33449 } else if (code1 === EOF) {
33450 this.eof = true;
33451 }
33452 }
33453
33454 if (!this.eof && this.encoding > 0) {
33455 this.nextLine2D = !this.lookBits(1);
33456 this.eatBits(1);
33457 }
33458
33459 if (this.eoblock && gotEOL && this.byteAlign) {
33460 code1 = this.lookBits(12);
33461 if (code1 === 1) {
33462 this.eatBits(12);
33463 if (this.encoding > 0) {
33464 this.lookBits(1);
33465 this.eatBits(1);
33466 }
33467 if (this.encoding >= 0) {
33468 for (i = 0; i < 4; ++i) {
33469 code1 = this.lookBits(12);
33470 if (code1 !== 1) {
33471 info('bad rtc code: ' + code1);
33472 }
33473 this.eatBits(12);
33474 if (this.encoding > 0) {
33475 this.lookBits(1);
33476 this.eatBits(1);
33477 }
33478 }
33479 }
33480 this.eof = true;
33481 }
33482 } else if (this.err && this.eoline) {
33483 while (true) {
33484 code1 = this.lookBits(13);
33485 if (code1 === EOF) {
33486 this.eof = true;
33487 return null;
33488 }
33489 if ((code1 >> 1) === 1) {
33490 break;
33491 }
33492 this.eatBits(1);
33493 }
33494 this.eatBits(12);
33495 if (this.encoding > 0) {
33496 this.eatBits(1);
33497 this.nextLine2D = !(code1 & 1);
33498 }
33499 }
33500
33501 if (codingLine[0] > 0) {
33502 this.outputBits = codingLine[this.codingPos = 0];
33503 } else {
33504 this.outputBits = codingLine[this.codingPos = 1];
33505 }
33506 this.row++;
33507 }
33508
33509 var c;
33510 if (this.outputBits >= 8) {
33511 c = (this.codingPos & 1) ? 0 : 0xFF;
33512 this.outputBits -= 8;
33513 if (this.outputBits === 0 && codingLine[this.codingPos] < columns) {
33514 this.codingPos++;
33515 this.outputBits = (codingLine[this.codingPos] -
33516 codingLine[this.codingPos - 1]);
33517 }
33518 } else {
33519 bits = 8;
33520 c = 0;
33521 do {
33522 if (this.outputBits > bits) {
33523 c <<= bits;
33524 if (!(this.codingPos & 1)) {
33525 c |= 0xFF >> (8 - bits);
33526 }
33527 this.outputBits -= bits;
33528 bits = 0;
33529 } else {
33530 c <<= this.outputBits;
33531 if (!(this.codingPos & 1)) {
33532 c |= 0xFF >> (8 - this.outputBits);
33533 }
33534 bits -= this.outputBits;
33535 this.outputBits = 0;
33536 if (codingLine[this.codingPos] < columns) {
33537 this.codingPos++;
33538 this.outputBits = (codingLine[this.codingPos] -
33539 codingLine[this.codingPos - 1]);
33540 } else if (bits > 0) {
33541 c <<= bits;
33542 bits = 0;
33543 }
33544 }
33545 } while (bits);
33546 }
33547 if (this.black) {
33548 c ^= 0xFF;
33549 }
33550 return c;
33551 };
33552
33553 // This functions returns the code found from the table.
33554 // The start and end parameters set the boundaries for searching the table.
33555 // The limit parameter is optional. Function returns an array with three
33556 // values. The first array element indicates whether a valid code is being
33557 // returned. The second array element is the actual code. The third array
33558 // element indicates whether EOF was reached.
33559 CCITTFaxStream.prototype.findTableCode =
33560 function ccittFaxStreamFindTableCode(start, end, table, limit) {
33561
33562 var limitValue = limit || 0;
33563 for (var i = start; i <= end; ++i) {
33564 var code = this.lookBits(i);
33565 if (code === EOF) {
33566 return [true, 1, false];
33567 }
33568 if (i < end) {
33569 code <<= end - i;
33570 }
33571 if (!limitValue || code >= limitValue) {
33572 var p = table[code - limitValue];
33573 if (p[0] === i) {
33574 this.eatBits(i);
33575 return [true, p[1], true];
33576 }
33577 }
33578 }
33579 return [false, 0, false];
33580 };
33581
33582 CCITTFaxStream.prototype.getTwoDimCode =
33583 function ccittFaxStreamGetTwoDimCode() {
33584
33585 var code = 0;
33586 var p;
33587 if (this.eoblock) {
33588 code = this.lookBits(7);
33589 p = twoDimTable[code];
33590 if (p && p[0] > 0) {
33591 this.eatBits(p[0]);
33592 return p[1];
33593 }
33594 } else {
33595 var result = this.findTableCode(1, 7, twoDimTable);
33596 if (result[0] && result[2]) {
33597 return result[1];
33598 }
33599 }
33600 info('Bad two dim code');
33601 return EOF;
33602 };
33603
33604 CCITTFaxStream.prototype.getWhiteCode =
33605 function ccittFaxStreamGetWhiteCode() {
33606
33607 var code = 0;
33608 var p;
33609 if (this.eoblock) {
33610 code = this.lookBits(12);
33611 if (code === EOF) {
33612 return 1;
33613 }
33614
33615 if ((code >> 5) === 0) {
33616 p = whiteTable1[code];
33617 } else {
33618 p = whiteTable2[code >> 3];
33619 }
33620
33621 if (p[0] > 0) {
33622 this.eatBits(p[0]);
33623 return p[1];
33624 }
33625 } else {
33626 var result = this.findTableCode(1, 9, whiteTable2);
33627 if (result[0]) {
33628 return result[1];
33629 }
33630
33631 result = this.findTableCode(11, 12, whiteTable1);
33632 if (result[0]) {
33633 return result[1];
33634 }
33635 }
33636 info('bad white code');
33637 this.eatBits(1);
33638 return 1;
33639 };
33640
33641 CCITTFaxStream.prototype.getBlackCode =
33642 function ccittFaxStreamGetBlackCode() {
33643
33644 var code, p;
33645 if (this.eoblock) {
33646 code = this.lookBits(13);
33647 if (code === EOF) {
33648 return 1;
33649 }
33650 if ((code >> 7) === 0) {
33651 p = blackTable1[code];
33652 } else if ((code >> 9) === 0 && (code >> 7) !== 0) {
33653 p = blackTable2[(code >> 1) - 64];
33654 } else {
33655 p = blackTable3[code >> 7];
33656 }
33657
33658 if (p[0] > 0) {
33659 this.eatBits(p[0]);
33660 return p[1];
33661 }
33662 } else {
33663 var result = this.findTableCode(2, 6, blackTable3);
33664 if (result[0]) {
33665 return result[1];
33666 }
33667
33668 result = this.findTableCode(7, 12, blackTable2, 64);
33669 if (result[0]) {
33670 return result[1];
33671 }
33672
33673 result = this.findTableCode(10, 13, blackTable1);
33674 if (result[0]) {
33675 return result[1];
33676 }
33677 }
33678 info('bad black code');
33679 this.eatBits(1);
33680 return 1;
33681 };
33682
33683 CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) {
33684 var c;
33685 while (this.inputBits < n) {
33686 if ((c = this.str.getByte()) === -1) {
33687 if (this.inputBits === 0) {
33688 return EOF;
33689 }
33690 return ((this.inputBuf << (n - this.inputBits)) &
33691 (0xFFFF >> (16 - n)));
33692 }
33693 this.inputBuf = (this.inputBuf << 8) + c;
33694 this.inputBits += 8;
33695 }
33696 return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n));
33697 };
33698
33699 CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) {
33700 if ((this.inputBits -= n) < 0) {
33701 this.inputBits = 0;
33702 }
33703 };
33704
33705 return CCITTFaxStream;
33706 })();
33707
33708 var LZWStream = (function LZWStreamClosure() {
33709 function LZWStream(str, maybeLength, earlyChange) {
33710 this.str = str;
33711 this.dict = str.dict;
33712 this.cachedData = 0;
33713 this.bitsCached = 0;
33714
33715 var maxLzwDictionarySize = 4096;
33716 var lzwState = {
33717 earlyChange: earlyChange,
33718 codeLength: 9,
33719 nextCode: 258,
33720 dictionaryValues: new Uint8Array(maxLzwDictionarySize),
33721 dictionaryLengths: new Uint16Array(maxLzwDictionarySize),
33722 dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize),
33723 currentSequence: new Uint8Array(maxLzwDictionarySize),
33724 currentSequenceLength: 0
33725 };
33726 for (var i = 0; i < 256; ++i) {
33727 lzwState.dictionaryValues[i] = i;
33728 lzwState.dictionaryLengths[i] = 1;
33729 }
33730 this.lzwState = lzwState;
33731
33732 DecodeStream.call(this, maybeLength);
33733 }
33734
33735 LZWStream.prototype = Object.create(DecodeStream.prototype);
33736
33737 LZWStream.prototype.readBits = function LZWStream_readBits(n) {
33738 var bitsCached = this.bitsCached;
33739 var cachedData = this.cachedData;
33740 while (bitsCached < n) {
33741 var c = this.str.getByte();
33742 if (c === -1) {
33743 this.eof = true;
33744 return null;
33745 }
33746 cachedData = (cachedData << 8) | c;
33747 bitsCached += 8;
33748 }
33749 this.bitsCached = (bitsCached -= n);
33750 this.cachedData = cachedData;
33751 this.lastCode = null;
33752 return (cachedData >>> bitsCached) & ((1 << n) - 1);
33753 };
33754
33755 LZWStream.prototype.readBlock = function LZWStream_readBlock() {
33756 var blockSize = 512;
33757 var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize;
33758 var i, j, q;
33759
33760 var lzwState = this.lzwState;
33761 if (!lzwState) {
33762 return; // eof was found
33763 }
33764
33765 var earlyChange = lzwState.earlyChange;
33766 var nextCode = lzwState.nextCode;
33767 var dictionaryValues = lzwState.dictionaryValues;
33768 var dictionaryLengths = lzwState.dictionaryLengths;
33769 var dictionaryPrevCodes = lzwState.dictionaryPrevCodes;
33770 var codeLength = lzwState.codeLength;
33771 var prevCode = lzwState.prevCode;
33772 var currentSequence = lzwState.currentSequence;
33773 var currentSequenceLength = lzwState.currentSequenceLength;
33774
33775 var decodedLength = 0;
33776 var currentBufferLength = this.bufferLength;
33777 var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
33778
33779 for (i = 0; i < blockSize; i++) {
33780 var code = this.readBits(codeLength);
33781 var hasPrev = currentSequenceLength > 0;
33782 if (code < 256) {
33783 currentSequence[0] = code;
33784 currentSequenceLength = 1;
33785 } else if (code >= 258) {
33786 if (code < nextCode) {
33787 currentSequenceLength = dictionaryLengths[code];
33788 for (j = currentSequenceLength - 1, q = code; j >= 0; j--) {
33789 currentSequence[j] = dictionaryValues[q];
33790 q = dictionaryPrevCodes[q];
33791 }
33792 } else {
33793 currentSequence[currentSequenceLength++] = currentSequence[0];
33794 }
33795 } else if (code === 256) {
33796 codeLength = 9;
33797 nextCode = 258;
33798 currentSequenceLength = 0;
33799 continue;
33800 } else {
33801 this.eof = true;
33802 delete this.lzwState;
33803 break;
33804 }
33805
33806 if (hasPrev) {
33807 dictionaryPrevCodes[nextCode] = prevCode;
33808 dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1;
33809 dictionaryValues[nextCode] = currentSequence[0];
33810 nextCode++;
33811 codeLength = (nextCode + earlyChange) & (nextCode + earlyChange - 1) ?
33812 codeLength : Math.min(Math.log(nextCode + earlyChange) /
33813 0.6931471805599453 + 1, 12) | 0;
33814 }
33815 prevCode = code;
33816
33817 decodedLength += currentSequenceLength;
33818 if (estimatedDecodedSize < decodedLength) {
33819 do {
33820 estimatedDecodedSize += decodedSizeDelta;
33821 } while (estimatedDecodedSize < decodedLength);
33822 buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
33823 }
33824 for (j = 0; j < currentSequenceLength; j++) {
33825 buffer[currentBufferLength++] = currentSequence[j];
33826 }
33827 }
33828 lzwState.nextCode = nextCode;
33829 lzwState.codeLength = codeLength;
33830 lzwState.prevCode = prevCode;
33831 lzwState.currentSequenceLength = currentSequenceLength;
33832
33833 this.bufferLength = currentBufferLength;
33834 };
33835
33836 return LZWStream;
33837 })();
33838
33839 var NullStream = (function NullStreamClosure() {
33840 function NullStream() {
33841 Stream.call(this, new Uint8Array(0));
33842 }
33843
33844 NullStream.prototype = Stream.prototype;
33845
33846 return NullStream;
33847 })();
33848
33849
33850 var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
33851 setup: function wphSetup(handler) {
33852 var pdfManager;
33853
33854 function loadDocument(recoveryMode) {
33855 var loadDocumentCapability = createPromiseCapability();
33856
33857 var parseSuccess = function parseSuccess() {
33858 var numPagesPromise = pdfManager.ensureDoc('numPages');
33859 var fingerprintPromise = pdfManager.ensureDoc('fingerprint');
33860 var encryptedPromise = pdfManager.ensureXRef('encrypt');
33861 Promise.all([numPagesPromise, fingerprintPromise,
33862 encryptedPromise]).then(function onDocReady(results) {
33863 var doc = {
33864 numPages: results[0],
33865 fingerprint: results[1],
33866 encrypted: !!results[2],
33867 };
33868 loadDocumentCapability.resolve(doc);
33869 },
33870 parseFailure);
33871 };
33872
33873 var parseFailure = function parseFailure(e) {
33874 loadDocumentCapability.reject(e);
33875 };
33876
33877 pdfManager.ensureDoc('checkHeader', []).then(function() {
33878 pdfManager.ensureDoc('parseStartXRef', []).then(function() {
33879 pdfManager.ensureDoc('parse', [recoveryMode]).then(
33880 parseSuccess, parseFailure);
33881 }, parseFailure);
33882 }, parseFailure);
33883
33884 return loadDocumentCapability.promise;
33885 }
33886
33887 function getPdfManager(data) {
33888 var pdfManagerCapability = createPromiseCapability();
33889
33890 var source = data.source;
33891 var disableRange = data.disableRange;
33892 if (source.data) {
33893 try {
33894 pdfManager = new LocalPdfManager(source.data, source.password);
33895 pdfManagerCapability.resolve();
33896 } catch (ex) {
33897 pdfManagerCapability.reject(ex);
33898 }
33899 return pdfManagerCapability.promise;
33900 } else if (source.chunkedViewerLoading) {
33901 try {
33902 pdfManager = new NetworkPdfManager(source, handler);
33903 pdfManagerCapability.resolve();
33904 } catch (ex) {
33905 pdfManagerCapability.reject(ex);
33906 }
33907 return pdfManagerCapability.promise;
33908 }
33909
33910 var networkManager = new NetworkManager(source.url, {
33911 httpHeaders: source.httpHeaders,
33912 withCredentials: source.withCredentials
33913 });
33914 var cachedChunks = [];
33915 var fullRequestXhrId = networkManager.requestFull({
33916 onHeadersReceived: function onHeadersReceived() {
33917 if (disableRange) {
33918 return;
33919 }
33920
33921 var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId);
33922 if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') {
33923 return;
33924 }
33925
33926 var contentEncoding =
33927 fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity';
33928 if (contentEncoding !== 'identity') {
33929 return;
33930 }
33931
33932 var length = fullRequestXhr.getResponseHeader('Content-Length');
33933 length = parseInt(length, 10);
33934 if (!isInt(length)) {
33935 return;
33936 }
33937 source.length = length;
33938 if (length <= 2 * RANGE_CHUNK_SIZE) {
33939 // The file size is smaller than the size of two chunks, so it does
33940 // not make any sense to abort the request and retry with a range
33941 // request.
33942 return;
33943 }
33944
33945 if (networkManager.isStreamingRequest(fullRequestXhrId)) {
33946 // We can continue fetching when progressive loading is enabled,
33947 // and we don't need the autoFetch feature.
33948 source.disableAutoFetch = true;
33949 } else {
33950 // NOTE: by cancelling the full request, and then issuing range
33951 // requests, there will be an issue for sites where you can only
33952 // request the pdf once. However, if this is the case, then the
33953 // server should not be returning that it can support range
33954 // requests.
33955 networkManager.abortRequest(fullRequestXhrId);
33956 }
33957
33958 try {
33959 pdfManager = new NetworkPdfManager(source, handler);
33960 pdfManagerCapability.resolve(pdfManager);
33961 } catch (ex) {
33962 pdfManagerCapability.reject(ex);
33963 }
33964 },
33965
33966 onProgressiveData: source.disableStream ? null :
33967 function onProgressiveData(chunk) {
33968 if (!pdfManager) {
33969 cachedChunks.push(chunk);
33970 return;
33971 }
33972 pdfManager.sendProgressiveData(chunk);
33973 },
33974
33975 onDone: function onDone(args) {
33976 if (pdfManager) {
33977 return; // already processed
33978 }
33979
33980 var pdfFile;
33981 if (args === null) {
33982 // TODO add some streaming manager, e.g. for unknown length files.
33983 // The data was returned in the onProgressiveData, combining...
33984 var pdfFileLength = 0, pos = 0;
33985 cachedChunks.forEach(function (chunk) {
33986 pdfFileLength += chunk.byteLength;
33987 });
33988 if (source.length && pdfFileLength !== source.length) {
33989 warn('reported HTTP length is different from actual');
33990 }
33991 var pdfFileArray = new Uint8Array(pdfFileLength);
33992 cachedChunks.forEach(function (chunk) {
33993 pdfFileArray.set(new Uint8Array(chunk), pos);
33994 pos += chunk.byteLength;
33995 });
33996 pdfFile = pdfFileArray.buffer;
33997 } else {
33998 pdfFile = args.chunk;
33999 }
34000
34001 // the data is array, instantiating directly from it
34002 try {
34003 pdfManager = new LocalPdfManager(pdfFile, source.password);
34004 pdfManagerCapability.resolve();
34005 } catch (ex) {
34006 pdfManagerCapability.reject(ex);
34007 }
34008 },
34009
34010 onError: function onError(status) {
34011 var exception;
34012 if (status === 404) {
34013 exception = new MissingPDFException('Missing PDF "' +
34014 source.url + '".');
34015 handler.send('MissingPDF', exception);
34016 } else {
34017 exception = new UnexpectedResponseException(
34018 'Unexpected server response (' + status +
34019 ') while retrieving PDF "' + source.url + '".', status);
34020 handler.send('UnexpectedResponse', exception);
34021 }
34022 },
34023
34024 onProgress: function onProgress(evt) {
34025 handler.send('DocProgress', {
34026 loaded: evt.loaded,
34027 total: evt.lengthComputable ? evt.total : source.length
34028 });
34029 }
34030 });
34031
34032 return pdfManagerCapability.promise;
34033 }
34034
34035 handler.on('test', function wphSetupTest(data) {
34036 // check if Uint8Array can be sent to worker
34037 if (!(data instanceof Uint8Array)) {
34038 handler.send('test', false);
34039 return;
34040 }
34041 // making sure postMessage transfers are working
34042 var supportTransfers = data[0] === 255;
34043 handler.postMessageTransfers = supportTransfers;
34044 // check if the response property is supported by xhr
34045 var xhr = new XMLHttpRequest();
34046 var responseExists = 'response' in xhr;
34047 // check if the property is actually implemented
34048 try {
34049 var dummy = xhr.responseType;
34050 } catch (e) {
34051 responseExists = false;
34052 }
34053 if (!responseExists) {
34054 handler.send('test', false);
34055 return;
34056 }
34057 handler.send('test', {
34058 supportTypedArray: true,
34059 supportTransfers: supportTransfers
34060 });
34061 });
34062
34063 handler.on('GetDocRequest', function wphSetupDoc(data) {
34064
34065 var onSuccess = function(doc) {
34066 handler.send('GetDoc', { pdfInfo: doc });
34067 };
34068
34069 var onFailure = function(e) {
34070 if (e instanceof PasswordException) {
34071 if (e.code === PasswordResponses.NEED_PASSWORD) {
34072 handler.send('NeedPassword', e);
34073 } else if (e.code === PasswordResponses.INCORRECT_PASSWORD) {
34074 handler.send('IncorrectPassword', e);
34075 }
34076 } else if (e instanceof InvalidPDFException) {
34077 handler.send('InvalidPDF', e);
34078 } else if (e instanceof MissingPDFException) {
34079 handler.send('MissingPDF', e);
34080 } else if (e instanceof UnexpectedResponseException) {
34081 handler.send('UnexpectedResponse', e);
34082 } else {
34083 handler.send('UnknownError',
34084 new UnknownErrorException(e.message, e.toString()));
34085 }
34086 };
34087
34088 PDFJS.maxImageSize = data.maxImageSize === undefined ?
34089 -1 : data.maxImageSize;
34090 PDFJS.disableFontFace = data.disableFontFace;
34091 PDFJS.disableCreateObjectURL = data.disableCreateObjectURL;
34092 PDFJS.verbosity = data.verbosity;
34093 PDFJS.cMapUrl = data.cMapUrl === undefined ?
34094 null : data.cMapUrl;
34095 PDFJS.cMapPacked = data.cMapPacked === true;
34096
34097 getPdfManager(data).then(function () {
34098 handler.send('PDFManagerReady', null);
34099 pdfManager.onLoadedStream().then(function(stream) {
34100 handler.send('DataLoaded', { length: stream.bytes.byteLength });
34101 });
34102 }).then(function pdfManagerReady() {
34103 loadDocument(false).then(onSuccess, function loadFailure(ex) {
34104 // Try again with recoveryMode == true
34105 if (!(ex instanceof XRefParseException)) {
34106 if (ex instanceof PasswordException) {
34107 // after password exception prepare to receive a new password
34108 // to repeat loading
34109 pdfManager.passwordChanged().then(pdfManagerReady);
34110 }
34111
34112 onFailure(ex);
34113 return;
34114 }
34115
34116 pdfManager.requestLoadedStream();
34117 pdfManager.onLoadedStream().then(function() {
34118 loadDocument(true).then(onSuccess, onFailure);
34119 });
34120 }, onFailure);
34121 }, onFailure);
34122 });
34123
34124 handler.on('GetPage', function wphSetupGetPage(data) {
34125 return pdfManager.getPage(data.pageIndex).then(function(page) {
34126 var rotatePromise = pdfManager.ensure(page, 'rotate');
34127 var refPromise = pdfManager.ensure(page, 'ref');
34128 var viewPromise = pdfManager.ensure(page, 'view');
34129
34130 return Promise.all([rotatePromise, refPromise, viewPromise]).then(
34131 function(results) {
34132 return {
34133 rotate: results[0],
34134 ref: results[1],
34135 view: results[2]
34136 };
34137 });
34138 });
34139 });
34140
34141 handler.on('GetPageIndex', function wphSetupGetPageIndex(data) {
34142 var ref = new Ref(data.ref.num, data.ref.gen);
34143 var catalog = pdfManager.pdfDocument.catalog;
34144 return catalog.getPageIndex(ref);
34145 });
34146
34147 handler.on('GetDestinations',
34148 function wphSetupGetDestinations(data) {
34149 return pdfManager.ensureCatalog('destinations');
34150 }
34151 );
34152
34153 handler.on('GetDestination',
34154 function wphSetupGetDestination(data) {
34155 return pdfManager.ensureCatalog('getDestination', [ data.id ]);
34156 }
34157 );
34158
34159 handler.on('GetAttachments',
34160 function wphSetupGetAttachments(data) {
34161 return pdfManager.ensureCatalog('attachments');
34162 }
34163 );
34164
34165 handler.on('GetJavaScript',
34166 function wphSetupGetJavaScript(data) {
34167 return pdfManager.ensureCatalog('javaScript');
34168 }
34169 );
34170
34171 handler.on('GetOutline',
34172 function wphSetupGetOutline(data) {
34173 return pdfManager.ensureCatalog('documentOutline');
34174 }
34175 );
34176
34177 handler.on('GetMetadata',
34178 function wphSetupGetMetadata(data) {
34179 return Promise.all([pdfManager.ensureDoc('documentInfo'),
34180 pdfManager.ensureCatalog('metadata')]);
34181 }
34182 );
34183
34184 handler.on('GetData', function wphSetupGetData(data) {
34185 pdfManager.requestLoadedStream();
34186 return pdfManager.onLoadedStream().then(function(stream) {
34187 return stream.bytes;
34188 });
34189 });
34190
34191 handler.on('GetStats',
34192 function wphSetupGetStats(data) {
34193 return pdfManager.pdfDocument.xref.stats;
34194 }
34195 );
34196
34197 handler.on('UpdatePassword', function wphSetupUpdatePassword(data) {
34198 pdfManager.updatePassword(data);
34199 });
34200
34201 handler.on('GetAnnotations', function wphSetupGetAnnotations(data) {
34202 return pdfManager.getPage(data.pageIndex).then(function(page) {
34203 return pdfManager.ensure(page, 'getAnnotationsData', []);
34204 });
34205 });
34206
34207 handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
34208 pdfManager.getPage(data.pageIndex).then(function(page) {
34209
34210 var pageNum = data.pageIndex + 1;
34211 var start = Date.now();
34212 // Pre compile the pdf page and fetch the fonts/images.
34213 page.getOperatorList(handler, data.intent).then(function(operatorList) {
34214
34215 info('page=' + pageNum + ' - getOperatorList: time=' +
34216 (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length);
34217
34218 }, function(e) {
34219
34220 var minimumStackMessage =
34221 'worker.js: while trying to getPage() and getOperatorList()';
34222
34223 var wrappedException;
34224
34225 // Turn the error into an obj that can be serialized
34226 if (typeof e === 'string') {
34227 wrappedException = {
34228 message: e,
34229 stack: minimumStackMessage
34230 };
34231 } else if (typeof e === 'object') {
34232 wrappedException = {
34233 message: e.message || e.toString(),
34234 stack: e.stack || minimumStackMessage
34235 };
34236 } else {
34237 wrappedException = {
34238 message: 'Unknown exception type: ' + (typeof e),
34239 stack: minimumStackMessage
34240 };
34241 }
34242
34243 handler.send('PageError', {
34244 pageNum: pageNum,
34245 error: wrappedException,
34246 intent: data.intent
34247 });
34248 });
34249 });
34250 }, this);
34251
34252 handler.on('GetTextContent', function wphExtractText(data) {
34253 return pdfManager.getPage(data.pageIndex).then(function(page) {
34254 var pageNum = data.pageIndex + 1;
34255 var start = Date.now();
34256 return page.extractTextContent().then(function(textContent) {
34257 info('text indexing: page=' + pageNum + ' - time=' +
34258 (Date.now() - start) + 'ms');
34259 return textContent;
34260 });
34261 });
34262 });
34263
34264 handler.on('Cleanup', function wphCleanup(data) {
34265 return pdfManager.cleanup();
34266 });
34267
34268 handler.on('Terminate', function wphTerminate(data) {
34269 pdfManager.terminate();
34270 });
34271 }
34272 };
34273
34274 var consoleTimer = {};
34275
34276 var workerConsole = {
34277 log: function log() {
34278 var args = Array.prototype.slice.call(arguments);
34279 globalScope.postMessage({
34280 action: 'console_log',
34281 data: args
34282 });
34283 },
34284
34285 error: function error() {
34286 var args = Array.prototype.slice.call(arguments);
34287 globalScope.postMessage({
34288 action: 'console_error',
34289 data: args
34290 });
34291 throw 'pdf.js execution error';
34292 },
34293
34294 time: function time(name) {
34295 consoleTimer[name] = Date.now();
34296 },
34297
34298 timeEnd: function timeEnd(name) {
34299 var time = consoleTimer[name];
34300 if (!time) {
34301 error('Unknown timer name ' + name);
34302 }
34303 this.log('Timer:', name, Date.now() - time);
34304 }
34305 };
34306
34307
34308 // Worker thread?
34309 if (typeof window === 'undefined') {
34310 if (!('console' in globalScope)) {
34311 globalScope.console = workerConsole;
34312 }
34313
34314 // Listen for unsupported features so we can pass them on to the main thread.
34315 PDFJS.UnsupportedManager.listen(function (msg) {
34316 globalScope.postMessage({
34317 action: '_unsupported_feature',
34318 data: msg
34319 });
34320 });
34321
34322 var handler = new MessageHandler('worker_processor', this);
34323 WorkerMessageHandler.setup(handler);
34324 }
34325
34326
34327 /* This class implements the QM Coder decoding as defined in
34328 * JPEG 2000 Part I Final Committee Draft Version 1.0
34329 * Annex C.3 Arithmetic decoding procedure
34330 * available at http://www.jpeg.org/public/fcd15444-1.pdf
34331 *
34332 * The arithmetic decoder is used in conjunction with context models to decode
34333 * JPEG2000 and JBIG2 streams.
34334 */
34335 var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
34336 // Table C-2
34337 var QeTable = [
34338 {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
34339 {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
34340 {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0},
34341 {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0},
34342 {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0},
34343 {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0},
34344 {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1},
34345 {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0},
34346 {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0},
34347 {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0},
34348 {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0},
34349 {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0},
34350 {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0},
34351 {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0},
34352 {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1},
34353 {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0},
34354 {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0},
34355 {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0},
34356 {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0},
34357 {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0},
34358 {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0},
34359 {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0},
34360 {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0},
34361 {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0},
34362 {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0},
34363 {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0},
34364 {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0},
34365 {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0},
34366 {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0},
34367 {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0},
34368 {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0},
34369 {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0},
34370 {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0},
34371 {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0},
34372 {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0},
34373 {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0},
34374 {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0},
34375 {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0},
34376 {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0},
34377 {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0},
34378 {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0},
34379 {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0},
34380 {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0},
34381 {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0},
34382 {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0},
34383 {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0},
34384 {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0}
34385 ];
34386
34387 // C.3.5 Initialisation of the decoder (INITDEC)
34388 function ArithmeticDecoder(data, start, end) {
34389 this.data = data;
34390 this.bp = start;
34391 this.dataEnd = end;
34392
34393 this.chigh = data[start];
34394 this.clow = 0;
34395
34396 this.byteIn();
34397
34398 this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
34399 this.clow = (this.clow << 7) & 0xFFFF;
34400 this.ct -= 7;
34401 this.a = 0x8000;
34402 }
34403
34404 ArithmeticDecoder.prototype = {
34405 // C.3.4 Compressed data input (BYTEIN)
34406 byteIn: function ArithmeticDecoder_byteIn() {
34407 var data = this.data;
34408 var bp = this.bp;
34409 if (data[bp] === 0xFF) {
34410 var b1 = data[bp + 1];
34411 if (b1 > 0x8F) {
34412 this.clow += 0xFF00;
34413 this.ct = 8;
34414 } else {
34415 bp++;
34416 this.clow += (data[bp] << 9);
34417 this.ct = 7;
34418 this.bp = bp;
34419 }
34420 } else {
34421 bp++;
34422 this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
34423 this.ct = 8;
34424 this.bp = bp;
34425 }
34426 if (this.clow > 0xFFFF) {
34427 this.chigh += (this.clow >> 16);
34428 this.clow &= 0xFFFF;
34429 }
34430 },
34431 // C.3.2 Decoding a decision (DECODE)
34432 readBit: function ArithmeticDecoder_readBit(contexts, pos) {
34433 // contexts are packed into 1 byte:
34434 // highest 7 bits carry cx.index, lowest bit carries cx.mps
34435 var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1;
34436 var qeTableIcx = QeTable[cx_index];
34437 var qeIcx = qeTableIcx.qe;
34438 var d;
34439 var a = this.a - qeIcx;
34440
34441 if (this.chigh < qeIcx) {
34442 // exchangeLps
34443 if (a < qeIcx) {
34444 a = qeIcx;
34445 d = cx_mps;
34446 cx_index = qeTableIcx.nmps;
34447 } else {
34448 a = qeIcx;
34449 d = 1 ^ cx_mps;
34450 if (qeTableIcx.switchFlag === 1) {
34451 cx_mps = d;
34452 }
34453 cx_index = qeTableIcx.nlps;
34454 }
34455 } else {
34456 this.chigh -= qeIcx;
34457 if ((a & 0x8000) !== 0) {
34458 this.a = a;
34459 return cx_mps;
34460 }
34461 // exchangeMps
34462 if (a < qeIcx) {
34463 d = 1 ^ cx_mps;
34464 if (qeTableIcx.switchFlag === 1) {
34465 cx_mps = d;
34466 }
34467 cx_index = qeTableIcx.nlps;
34468 } else {
34469 d = cx_mps;
34470 cx_index = qeTableIcx.nmps;
34471 }
34472 }
34473 // C.3.3 renormD;
34474 do {
34475 if (this.ct === 0) {
34476 this.byteIn();
34477 }
34478
34479 a <<= 1;
34480 this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
34481 this.clow = (this.clow << 1) & 0xFFFF;
34482 this.ct--;
34483 } while ((a & 0x8000) === 0);
34484 this.a = a;
34485
34486 contexts[pos] = cx_index << 1 | cx_mps;
34487 return d;
34488 }
34489 };
34490
34491 return ArithmeticDecoder;
34492 })();
34493
34494
34495 var JpegImage = (function jpegImage() {
34496 var dctZigZag = new Uint8Array([
34497 0,
34498 1, 8,
34499 16, 9, 2,
34500 3, 10, 17, 24,
34501 32, 25, 18, 11, 4,
34502 5, 12, 19, 26, 33, 40,
34503 48, 41, 34, 27, 20, 13, 6,
34504 7, 14, 21, 28, 35, 42, 49, 56,
34505 57, 50, 43, 36, 29, 22, 15,
34506 23, 30, 37, 44, 51, 58,
34507 59, 52, 45, 38, 31,
34508 39, 46, 53, 60,
34509 61, 54, 47,
34510 55, 62,
34511 63
34512 ]);
34513
34514 var dctCos1 = 4017; // cos(pi/16)
34515 var dctSin1 = 799; // sin(pi/16)
34516 var dctCos3 = 3406; // cos(3*pi/16)
34517 var dctSin3 = 2276; // sin(3*pi/16)
34518 var dctCos6 = 1567; // cos(6*pi/16)
34519 var dctSin6 = 3784; // sin(6*pi/16)
34520 var dctSqrt2 = 5793; // sqrt(2)
34521 var dctSqrt1d2 = 2896; // sqrt(2) / 2
34522
34523 function constructor() {
34524 }
34525
34526 function buildHuffmanTable(codeLengths, values) {
34527 var k = 0, code = [], i, j, length = 16;
34528 while (length > 0 && !codeLengths[length - 1]) {
34529 length--;
34530 }
34531 code.push({children: [], index: 0});
34532 var p = code[0], q;
34533 for (i = 0; i < length; i++) {
34534 for (j = 0; j < codeLengths[i]; j++) {
34535 p = code.pop();
34536 p.children[p.index] = values[k];
34537 while (p.index > 0) {
34538 p = code.pop();
34539 }
34540 p.index++;
34541 code.push(p);
34542 while (code.length <= i) {
34543 code.push(q = {children: [], index: 0});
34544 p.children[p.index] = q.children;
34545 p = q;
34546 }
34547 k++;
34548 }
34549 if (i + 1 < length) {
34550 // p here points to last code
34551 code.push(q = {children: [], index: 0});
34552 p.children[p.index] = q.children;
34553 p = q;
34554 }
34555 }
34556 return code[0].children;
34557 }
34558
34559 function getBlockBufferOffset(component, row, col) {
34560 return 64 * ((component.blocksPerLine + 1) * row + col);
34561 }
34562
34563 function decodeScan(data, offset, frame, components, resetInterval,
34564 spectralStart, spectralEnd, successivePrev, successive) {
34565 var precision = frame.precision;
34566 var samplesPerLine = frame.samplesPerLine;
34567 var scanLines = frame.scanLines;
34568 var mcusPerLine = frame.mcusPerLine;
34569 var progressive = frame.progressive;
34570 var maxH = frame.maxH, maxV = frame.maxV;
34571
34572 var startOffset = offset, bitsData = 0, bitsCount = 0;
34573
34574 function readBit() {
34575 if (bitsCount > 0) {
34576 bitsCount--;
34577 return (bitsData >> bitsCount) & 1;
34578 }
34579 bitsData = data[offset++];
34580 if (bitsData === 0xFF) {
34581 var nextByte = data[offset++];
34582 if (nextByte) {
34583 throw 'unexpected marker: ' +
34584 ((bitsData << 8) | nextByte).toString(16);
34585 }
34586 // unstuff 0
34587 }
34588 bitsCount = 7;
34589 return bitsData >>> 7;
34590 }
34591
34592 function decodeHuffman(tree) {
34593 var node = tree;
34594 while (true) {
34595 node = node[readBit()];
34596 if (typeof node === 'number') {
34597 return node;
34598 }
34599 if (typeof node !== 'object') {
34600 throw 'invalid huffman sequence';
34601 }
34602 }
34603 }
34604
34605 function receive(length) {
34606 var n = 0;
34607 while (length > 0) {
34608 n = (n << 1) | readBit();
34609 length--;
34610 }
34611 return n;
34612 }
34613
34614 function receiveAndExtend(length) {
34615 if (length === 1) {
34616 return readBit() === 1 ? 1 : -1;
34617 }
34618 var n = receive(length);
34619 if (n >= 1 << (length - 1)) {
34620 return n;
34621 }
34622 return n + (-1 << length) + 1;
34623 }
34624
34625 function decodeBaseline(component, offset) {
34626 var t = decodeHuffman(component.huffmanTableDC);
34627 var diff = t === 0 ? 0 : receiveAndExtend(t);
34628 component.blockData[offset] = (component.pred += diff);
34629 var k = 1;
34630 while (k < 64) {
34631 var rs = decodeHuffman(component.huffmanTableAC);
34632 var s = rs & 15, r = rs >> 4;
34633 if (s === 0) {
34634 if (r < 15) {
34635 break;
34636 }
34637 k += 16;
34638 continue;
34639 }
34640 k += r;
34641 var z = dctZigZag[k];
34642 component.blockData[offset + z] = receiveAndExtend(s);
34643 k++;
34644 }
34645 }
34646
34647 function decodeDCFirst(component, offset) {
34648 var t = decodeHuffman(component.huffmanTableDC);
34649 var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
34650 component.blockData[offset] = (component.pred += diff);
34651 }
34652
34653 function decodeDCSuccessive(component, offset) {
34654 component.blockData[offset] |= readBit() << successive;
34655 }
34656
34657 var eobrun = 0;
34658 function decodeACFirst(component, offset) {
34659 if (eobrun > 0) {
34660 eobrun--;
34661 return;
34662 }
34663 var k = spectralStart, e = spectralEnd;
34664 while (k <= e) {
34665 var rs = decodeHuffman(component.huffmanTableAC);
34666 var s = rs & 15, r = rs >> 4;
34667 if (s === 0) {
34668 if (r < 15) {
34669 eobrun = receive(r) + (1 << r) - 1;
34670 break;
34671 }
34672 k += 16;
34673 continue;
34674 }
34675 k += r;
34676 var z = dctZigZag[k];
34677 component.blockData[offset + z] =
34678 receiveAndExtend(s) * (1 << successive);
34679 k++;
34680 }
34681 }
34682
34683 var successiveACState = 0, successiveACNextValue;
34684 function decodeACSuccessive(component, offset) {
34685 var k = spectralStart;
34686 var e = spectralEnd;
34687 var r = 0;
34688 var s;
34689 var rs;
34690 while (k <= e) {
34691 var z = dctZigZag[k];
34692 switch (successiveACState) {
34693 case 0: // initial state
34694 rs = decodeHuffman(component.huffmanTableAC);
34695 s = rs & 15;
34696 r = rs >> 4;
34697 if (s === 0) {
34698 if (r < 15) {
34699 eobrun = receive(r) + (1 << r);
34700 successiveACState = 4;
34701 } else {
34702 r = 16;
34703 successiveACState = 1;
34704 }
34705 } else {
34706 if (s !== 1) {
34707 throw 'invalid ACn encoding';
34708 }
34709 successiveACNextValue = receiveAndExtend(s);
34710 successiveACState = r ? 2 : 3;
34711 }
34712 continue;
34713 case 1: // skipping r zero items
34714 case 2:
34715 if (component.blockData[offset + z]) {
34716 component.blockData[offset + z] += (readBit() << successive);
34717 } else {
34718 r--;
34719 if (r === 0) {
34720 successiveACState = successiveACState === 2 ? 3 : 0;
34721 }
34722 }
34723 break;
34724 case 3: // set value for a zero item
34725 if (component.blockData[offset + z]) {
34726 component.blockData[offset + z] += (readBit() << successive);
34727 } else {
34728 component.blockData[offset + z] =
34729 successiveACNextValue << successive;
34730 successiveACState = 0;
34731 }
34732 break;
34733 case 4: // eob
34734 if (component.blockData[offset + z]) {
34735 component.blockData[offset + z] += (readBit() << successive);
34736 }
34737 break;
34738 }
34739 k++;
34740 }
34741 if (successiveACState === 4) {
34742 eobrun--;
34743 if (eobrun === 0) {
34744 successiveACState = 0;
34745 }
34746 }
34747 }
34748
34749 function decodeMcu(component, decode, mcu, row, col) {
34750 var mcuRow = (mcu / mcusPerLine) | 0;
34751 var mcuCol = mcu % mcusPerLine;
34752 var blockRow = mcuRow * component.v + row;
34753 var blockCol = mcuCol * component.h + col;
34754 var offset = getBlockBufferOffset(component, blockRow, blockCol);
34755 decode(component, offset);
34756 }
34757
34758 function decodeBlock(component, decode, mcu) {
34759 var blockRow = (mcu / component.blocksPerLine) | 0;
34760 var blockCol = mcu % component.blocksPerLine;
34761 var offset = getBlockBufferOffset(component, blockRow, blockCol);
34762 decode(component, offset);
34763 }
34764
34765 var componentsLength = components.length;
34766 var component, i, j, k, n;
34767 var decodeFn;
34768 if (progressive) {
34769 if (spectralStart === 0) {
34770 decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
34771 } else {
34772 decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
34773 }
34774 } else {
34775 decodeFn = decodeBaseline;
34776 }
34777
34778 var mcu = 0, marker;
34779 var mcuExpected;
34780 if (componentsLength === 1) {
34781 mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
34782 } else {
34783 mcuExpected = mcusPerLine * frame.mcusPerColumn;
34784 }
34785 if (!resetInterval) {
34786 resetInterval = mcuExpected;
34787 }
34788
34789 var h, v;
34790 while (mcu < mcuExpected) {
34791 // reset interval stuff
34792 for (i = 0; i < componentsLength; i++) {
34793 components[i].pred = 0;
34794 }
34795 eobrun = 0;
34796
34797 if (componentsLength === 1) {
34798 component = components[0];
34799 for (n = 0; n < resetInterval; n++) {
34800 decodeBlock(component, decodeFn, mcu);
34801 mcu++;
34802 }
34803 } else {
34804 for (n = 0; n < resetInterval; n++) {
34805 for (i = 0; i < componentsLength; i++) {
34806 component = components[i];
34807 h = component.h;
34808 v = component.v;
34809 for (j = 0; j < v; j++) {
34810 for (k = 0; k < h; k++) {
34811 decodeMcu(component, decodeFn, mcu, j, k);
34812 }
34813 }
34814 }
34815 mcu++;
34816 }
34817 }
34818
34819 // find marker
34820 bitsCount = 0;
34821 marker = (data[offset] << 8) | data[offset + 1];
34822 if (marker <= 0xFF00) {
34823 throw 'marker was not found';
34824 }
34825
34826 if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
34827 offset += 2;
34828 } else {
34829 break;
34830 }
34831 }
34832
34833 return offset - startOffset;
34834 }
34835
34836 // A port of poppler's IDCT method which in turn is taken from:
34837 // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
34838 // 'Practical Fast 1-D DCT Algorithms with 11 Multiplications',
34839 // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
34840 // 988-991.
34841 function quantizeAndInverse(component, blockBufferOffset, p) {
34842 var qt = component.quantizationTable, blockData = component.blockData;
34843 var v0, v1, v2, v3, v4, v5, v6, v7;
34844 var p0, p1, p2, p3, p4, p5, p6, p7;
34845 var t;
34846
34847 // inverse DCT on rows
34848 for (var row = 0; row < 64; row += 8) {
34849 // gather block data
34850 p0 = blockData[blockBufferOffset + row];
34851 p1 = blockData[blockBufferOffset + row + 1];
34852 p2 = blockData[blockBufferOffset + row + 2];
34853 p3 = blockData[blockBufferOffset + row + 3];
34854 p4 = blockData[blockBufferOffset + row + 4];
34855 p5 = blockData[blockBufferOffset + row + 5];
34856 p6 = blockData[blockBufferOffset + row + 6];
34857 p7 = blockData[blockBufferOffset + row + 7];
34858
34859 // dequant p0
34860 p0 *= qt[row];
34861
34862 // check for all-zero AC coefficients
34863 if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
34864 t = (dctSqrt2 * p0 + 512) >> 10;
34865 p[row] = t;
34866 p[row + 1] = t;
34867 p[row + 2] = t;
34868 p[row + 3] = t;
34869 p[row + 4] = t;
34870 p[row + 5] = t;
34871 p[row + 6] = t;
34872 p[row + 7] = t;
34873 continue;
34874 }
34875 // dequant p1 ... p7
34876 p1 *= qt[row + 1];
34877 p2 *= qt[row + 2];
34878 p3 *= qt[row + 3];
34879 p4 *= qt[row + 4];
34880 p5 *= qt[row + 5];
34881 p6 *= qt[row + 6];
34882 p7 *= qt[row + 7];
34883
34884 // stage 4
34885 v0 = (dctSqrt2 * p0 + 128) >> 8;
34886 v1 = (dctSqrt2 * p4 + 128) >> 8;
34887 v2 = p2;
34888 v3 = p6;
34889 v4 = (dctSqrt1d2 * (p1 - p7) + 128) >> 8;
34890 v7 = (dctSqrt1d2 * (p1 + p7) + 128) >> 8;
34891 v5 = p3 << 4;
34892 v6 = p5 << 4;
34893
34894 // stage 3
34895 v0 = (v0 + v1 + 1) >> 1;
34896 v1 = v0 - v1;
34897 t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
34898 v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
34899 v3 = t;
34900 v4 = (v4 + v6 + 1) >> 1;
34901 v6 = v4 - v6;
34902 v7 = (v7 + v5 + 1) >> 1;
34903 v5 = v7 - v5;
34904
34905 // stage 2
34906 v0 = (v0 + v3 + 1) >> 1;
34907 v3 = v0 - v3;
34908 v1 = (v1 + v2 + 1) >> 1;
34909 v2 = v1 - v2;
34910 t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
34911 v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
34912 v7 = t;
34913 t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
34914 v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
34915 v6 = t;
34916
34917 // stage 1
34918 p[row] = v0 + v7;
34919 p[row + 7] = v0 - v7;
34920 p[row + 1] = v1 + v6;
34921 p[row + 6] = v1 - v6;
34922 p[row + 2] = v2 + v5;
34923 p[row + 5] = v2 - v5;
34924 p[row + 3] = v3 + v4;
34925 p[row + 4] = v3 - v4;
34926 }
34927
34928 // inverse DCT on columns
34929 for (var col = 0; col < 8; ++col) {
34930 p0 = p[col];
34931 p1 = p[col + 8];
34932 p2 = p[col + 16];
34933 p3 = p[col + 24];
34934 p4 = p[col + 32];
34935 p5 = p[col + 40];
34936 p6 = p[col + 48];
34937 p7 = p[col + 56];
34938
34939 // check for all-zero AC coefficients
34940 if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
34941 t = (dctSqrt2 * p0 + 8192) >> 14;
34942 // convert to 8 bit
34943 t = (t < -2040) ? 0 : (t >= 2024) ? 255 : (t + 2056) >> 4;
34944 blockData[blockBufferOffset + col] = t;
34945 blockData[blockBufferOffset + col + 8] = t;
34946 blockData[blockBufferOffset + col + 16] = t;
34947 blockData[blockBufferOffset + col + 24] = t;
34948 blockData[blockBufferOffset + col + 32] = t;
34949 blockData[blockBufferOffset + col + 40] = t;
34950 blockData[blockBufferOffset + col + 48] = t;
34951 blockData[blockBufferOffset + col + 56] = t;
34952 continue;
34953 }
34954
34955 // stage 4
34956 v0 = (dctSqrt2 * p0 + 2048) >> 12;
34957 v1 = (dctSqrt2 * p4 + 2048) >> 12;
34958 v2 = p2;
34959 v3 = p6;
34960 v4 = (dctSqrt1d2 * (p1 - p7) + 2048) >> 12;
34961 v7 = (dctSqrt1d2 * (p1 + p7) + 2048) >> 12;
34962 v5 = p3;
34963 v6 = p5;
34964
34965 // stage 3
34966 // Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when
34967 // converting to UInt8 range later.
34968 v0 = ((v0 + v1 + 1) >> 1) + 4112;
34969 v1 = v0 - v1;
34970 t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
34971 v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
34972 v3 = t;
34973 v4 = (v4 + v6 + 1) >> 1;
34974 v6 = v4 - v6;
34975 v7 = (v7 + v5 + 1) >> 1;
34976 v5 = v7 - v5;
34977
34978 // stage 2
34979 v0 = (v0 + v3 + 1) >> 1;
34980 v3 = v0 - v3;
34981 v1 = (v1 + v2 + 1) >> 1;
34982 v2 = v1 - v2;
34983 t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
34984 v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
34985 v7 = t;
34986 t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
34987 v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
34988 v6 = t;
34989
34990 // stage 1
34991 p0 = v0 + v7;
34992 p7 = v0 - v7;
34993 p1 = v1 + v6;
34994 p6 = v1 - v6;
34995 p2 = v2 + v5;
34996 p5 = v2 - v5;
34997 p3 = v3 + v4;
34998 p4 = v3 - v4;
34999
35000 // convert to 8-bit integers
35001 p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? 255 : p0 >> 4;
35002 p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? 255 : p1 >> 4;
35003 p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? 255 : p2 >> 4;
35004 p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? 255 : p3 >> 4;
35005 p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? 255 : p4 >> 4;
35006 p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? 255 : p5 >> 4;
35007 p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? 255 : p6 >> 4;
35008 p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? 255 : p7 >> 4;
35009
35010 // store block data
35011 blockData[blockBufferOffset + col] = p0;
35012 blockData[blockBufferOffset + col + 8] = p1;
35013 blockData[blockBufferOffset + col + 16] = p2;
35014 blockData[blockBufferOffset + col + 24] = p3;
35015 blockData[blockBufferOffset + col + 32] = p4;
35016 blockData[blockBufferOffset + col + 40] = p5;
35017 blockData[blockBufferOffset + col + 48] = p6;
35018 blockData[blockBufferOffset + col + 56] = p7;
35019 }
35020 }
35021
35022 function buildComponentData(frame, component) {
35023 var blocksPerLine = component.blocksPerLine;
35024 var blocksPerColumn = component.blocksPerColumn;
35025 var computationBuffer = new Int16Array(64);
35026
35027 for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
35028 for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
35029 var offset = getBlockBufferOffset(component, blockRow, blockCol);
35030 quantizeAndInverse(component, offset, computationBuffer);
35031 }
35032 }
35033 return component.blockData;
35034 }
35035
35036 function clamp0to255(a) {
35037 return a <= 0 ? 0 : a >= 255 ? 255 : a;
35038 }
35039
35040 constructor.prototype = {
35041 parse: function parse(data) {
35042
35043 function readUint16() {
35044 var value = (data[offset] << 8) | data[offset + 1];
35045 offset += 2;
35046 return value;
35047 }
35048
35049 function readDataBlock() {
35050 var length = readUint16();
35051 var array = data.subarray(offset, offset + length - 2);
35052 offset += array.length;
35053 return array;
35054 }
35055
35056 function prepareComponents(frame) {
35057 var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);
35058 var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
35059 for (var i = 0; i < frame.components.length; i++) {
35060 component = frame.components[i];
35061 var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) *
35062 component.h / frame.maxH);
35063 var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) *
35064 component.v / frame.maxV);
35065 var blocksPerLineForMcu = mcusPerLine * component.h;
35066 var blocksPerColumnForMcu = mcusPerColumn * component.v;
35067
35068 var blocksBufferSize = 64 * blocksPerColumnForMcu *
35069 (blocksPerLineForMcu + 1);
35070 component.blockData = new Int16Array(blocksBufferSize);
35071 component.blocksPerLine = blocksPerLine;
35072 component.blocksPerColumn = blocksPerColumn;
35073 }
35074 frame.mcusPerLine = mcusPerLine;
35075 frame.mcusPerColumn = mcusPerColumn;
35076 }
35077
35078 var offset = 0, length = data.length;
35079 var jfif = null;
35080 var adobe = null;
35081 var pixels = null;
35082 var frame, resetInterval;
35083 var quantizationTables = [];
35084 var huffmanTablesAC = [], huffmanTablesDC = [];
35085 var fileMarker = readUint16();
35086 if (fileMarker !== 0xFFD8) { // SOI (Start of Image)
35087 throw 'SOI not found';
35088 }
35089
35090 fileMarker = readUint16();
35091 while (fileMarker !== 0xFFD9) { // EOI (End of image)
35092 var i, j, l;
35093 switch(fileMarker) {
35094 case 0xFFE0: // APP0 (Application Specific)
35095 case 0xFFE1: // APP1
35096 case 0xFFE2: // APP2
35097 case 0xFFE3: // APP3
35098 case 0xFFE4: // APP4
35099 case 0xFFE5: // APP5
35100 case 0xFFE6: // APP6
35101 case 0xFFE7: // APP7
35102 case 0xFFE8: // APP8
35103 case 0xFFE9: // APP9
35104 case 0xFFEA: // APP10
35105 case 0xFFEB: // APP11
35106 case 0xFFEC: // APP12
35107 case 0xFFED: // APP13
35108 case 0xFFEE: // APP14
35109 case 0xFFEF: // APP15
35110 case 0xFFFE: // COM (Comment)
35111 var appData = readDataBlock();
35112
35113 if (fileMarker === 0xFFE0) {
35114 if (appData[0] === 0x4A && appData[1] === 0x46 &&
35115 appData[2] === 0x49 && appData[3] === 0x46 &&
35116 appData[4] === 0) { // 'JFIF\x00'
35117 jfif = {
35118 version: { major: appData[5], minor: appData[6] },
35119 densityUnits: appData[7],
35120 xDensity: (appData[8] << 8) | appData[9],
35121 yDensity: (appData[10] << 8) | appData[11],
35122 thumbWidth: appData[12],
35123 thumbHeight: appData[13],
35124 thumbData: appData.subarray(14, 14 +
35125 3 * appData[12] * appData[13])
35126 };
35127 }
35128 }
35129 // TODO APP1 - Exif
35130 if (fileMarker === 0xFFEE) {
35131 if (appData[0] === 0x41 && appData[1] === 0x64 &&
35132 appData[2] === 0x6F && appData[3] === 0x62 &&
35133 appData[4] === 0x65) { // 'Adobe'
35134 adobe = {
35135 version: (appData[5] << 8) | appData[6],
35136 flags0: (appData[7] << 8) | appData[8],
35137 flags1: (appData[9] << 8) | appData[10],
35138 transformCode: appData[11]
35139 };
35140 }
35141 }
35142 break;
35143
35144 case 0xFFDB: // DQT (Define Quantization Tables)
35145 var quantizationTablesLength = readUint16();
35146 var quantizationTablesEnd = quantizationTablesLength + offset - 2;
35147 var z;
35148 while (offset < quantizationTablesEnd) {
35149 var quantizationTableSpec = data[offset++];
35150 var tableData = new Uint16Array(64);
35151 if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
35152 for (j = 0; j < 64; j++) {
35153 z = dctZigZag[j];
35154 tableData[z] = data[offset++];
35155 }
35156 } else if ((quantizationTableSpec >> 4) === 1) { //16 bit
35157 for (j = 0; j < 64; j++) {
35158 z = dctZigZag[j];
35159 tableData[z] = readUint16();
35160 }
35161 } else {
35162 throw 'DQT: invalid table spec';
35163 }
35164 quantizationTables[quantizationTableSpec & 15] = tableData;
35165 }
35166 break;
35167
35168 case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
35169 case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)
35170 case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
35171 if (frame) {
35172 throw 'Only single frame JPEGs supported';
35173 }
35174 readUint16(); // skip data length
35175 frame = {};
35176 frame.extended = (fileMarker === 0xFFC1);
35177 frame.progressive = (fileMarker === 0xFFC2);
35178 frame.precision = data[offset++];
35179 frame.scanLines = readUint16();
35180 frame.samplesPerLine = readUint16();
35181 frame.components = [];
35182 frame.componentIds = {};
35183 var componentsCount = data[offset++], componentId;
35184 var maxH = 0, maxV = 0;
35185 for (i = 0; i < componentsCount; i++) {
35186 componentId = data[offset];
35187 var h = data[offset + 1] >> 4;
35188 var v = data[offset + 1] & 15;
35189 if (maxH < h) {
35190 maxH = h;
35191 }
35192 if (maxV < v) {
35193 maxV = v;
35194 }
35195 var qId = data[offset + 2];
35196 l = frame.components.push({
35197 h: h,
35198 v: v,
35199 quantizationTable: quantizationTables[qId]
35200 });
35201 frame.componentIds[componentId] = l - 1;
35202 offset += 3;
35203 }
35204 frame.maxH = maxH;
35205 frame.maxV = maxV;
35206 prepareComponents(frame);
35207 break;
35208
35209 case 0xFFC4: // DHT (Define Huffman Tables)
35210 var huffmanLength = readUint16();
35211 for (i = 2; i < huffmanLength;) {
35212 var huffmanTableSpec = data[offset++];
35213 var codeLengths = new Uint8Array(16);
35214 var codeLengthSum = 0;
35215 for (j = 0; j < 16; j++, offset++) {
35216 codeLengthSum += (codeLengths[j] = data[offset]);
35217 }
35218 var huffmanValues = new Uint8Array(codeLengthSum);
35219 for (j = 0; j < codeLengthSum; j++, offset++) {
35220 huffmanValues[j] = data[offset];
35221 }
35222 i += 17 + codeLengthSum;
35223
35224 ((huffmanTableSpec >> 4) === 0 ?
35225 huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
35226 buildHuffmanTable(codeLengths, huffmanValues);
35227 }
35228 break;
35229
35230 case 0xFFDD: // DRI (Define Restart Interval)
35231 readUint16(); // skip data length
35232 resetInterval = readUint16();
35233 break;
35234
35235 case 0xFFDA: // SOS (Start of Scan)
35236 var scanLength = readUint16();
35237 var selectorsCount = data[offset++];
35238 var components = [], component;
35239 for (i = 0; i < selectorsCount; i++) {
35240 var componentIndex = frame.componentIds[data[offset++]];
35241 component = frame.components[componentIndex];
35242 var tableSpec = data[offset++];
35243 component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
35244 component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
35245 components.push(component);
35246 }
35247 var spectralStart = data[offset++];
35248 var spectralEnd = data[offset++];
35249 var successiveApproximation = data[offset++];
35250 var processed = decodeScan(data, offset,
35251 frame, components, resetInterval,
35252 spectralStart, spectralEnd,
35253 successiveApproximation >> 4, successiveApproximation & 15);
35254 offset += processed;
35255 break;
35256
35257 case 0xFFFF: // Fill bytes
35258 if (data[offset] !== 0xFF) { // Avoid skipping a valid marker.
35259 offset--;
35260 }
35261 break;
35262
35263 default:
35264 if (data[offset - 3] === 0xFF &&
35265 data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
35266 // could be incorrect encoding -- last 0xFF byte of the previous
35267 // block was eaten by the encoder
35268 offset -= 3;
35269 break;
35270 }
35271 throw 'unknown JPEG marker ' + fileMarker.toString(16);
35272 }
35273 fileMarker = readUint16();
35274 }
35275
35276 this.width = frame.samplesPerLine;
35277 this.height = frame.scanLines;
35278 this.jfif = jfif;
35279 this.adobe = adobe;
35280 this.components = [];
35281 for (i = 0; i < frame.components.length; i++) {
35282 component = frame.components[i];
35283 this.components.push({
35284 output: buildComponentData(frame, component),
35285 scaleX: component.h / frame.maxH,
35286 scaleY: component.v / frame.maxV,
35287 blocksPerLine: component.blocksPerLine,
35288 blocksPerColumn: component.blocksPerColumn
35289 });
35290 }
35291 this.numComponents = this.components.length;
35292 },
35293
35294 _getLinearizedBlockData: function getLinearizedBlockData(width, height) {
35295 var scaleX = this.width / width, scaleY = this.height / height;
35296
35297 var component, componentScaleX, componentScaleY, blocksPerScanline;
35298 var x, y, i, j, k;
35299 var index;
35300 var offset = 0;
35301 var output;
35302 var numComponents = this.components.length;
35303 var dataLength = width * height * numComponents;
35304 var data = new Uint8Array(dataLength);
35305 var xScaleBlockOffset = new Uint32Array(width);
35306 var mask3LSB = 0xfffffff8; // used to clear the 3 LSBs
35307
35308 for (i = 0; i < numComponents; i++) {
35309 component = this.components[i];
35310 componentScaleX = component.scaleX * scaleX;
35311 componentScaleY = component.scaleY * scaleY;
35312 offset = i;
35313 output = component.output;
35314 blocksPerScanline = (component.blocksPerLine + 1) << 3;
35315 // precalculate the xScaleBlockOffset
35316 for (x = 0; x < width; x++) {
35317 j = 0 | (x * componentScaleX);
35318 xScaleBlockOffset[x] = ((j & mask3LSB) << 3) | (j & 7);
35319 }
35320 // linearize the blocks of the component
35321 for (y = 0; y < height; y++) {
35322 j = 0 | (y * componentScaleY);
35323 index = blocksPerScanline * (j & mask3LSB) | ((j & 7) << 3);
35324 for (x = 0; x < width; x++) {
35325 data[offset] = output[index + xScaleBlockOffset[x]];
35326 offset += numComponents;
35327 }
35328 }
35329 }
35330
35331 // decodeTransform contains pairs of multiplier (-256..256) and additive
35332 var transform = this.decodeTransform;
35333 if (transform) {
35334 for (i = 0; i < dataLength;) {
35335 for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
35336 data[i] = ((data[i] * transform[k]) >> 8) + transform[k + 1];
35337 }
35338 }
35339 }
35340 return data;
35341 },
35342
35343 _isColorConversionNeeded: function isColorConversionNeeded() {
35344 if (this.adobe && this.adobe.transformCode) {
35345 // The adobe transform marker overrides any previous setting
35346 return true;
35347 } else if (this.numComponents === 3) {
35348 return true;
35349 } else {
35350 return false;
35351 }
35352 },
35353
35354 _convertYccToRgb: function convertYccToRgb(data) {
35355 var Y, Cb, Cr;
35356 for (var i = 0, length = data.length; i < length; i += 3) {
35357 Y = data[i ];
35358 Cb = data[i + 1];
35359 Cr = data[i + 2];
35360 data[i ] = clamp0to255(Y - 179.456 + 1.402 * Cr);
35361 data[i + 1] = clamp0to255(Y + 135.459 - 0.344 * Cb - 0.714 * Cr);
35362 data[i + 2] = clamp0to255(Y - 226.816 + 1.772 * Cb);
35363 }
35364 return data;
35365 },
35366
35367 _convertYcckToRgb: function convertYcckToRgb(data) {
35368 var Y, Cb, Cr, k;
35369 var offset = 0;
35370 for (var i = 0, length = data.length; i < length; i += 4) {
35371 Y = data[i];
35372 Cb = data[i + 1];
35373 Cr = data[i + 2];
35374 k = data[i + 3];
35375
35376 var r = -122.67195406894 +
35377 Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr -
35378 5.4080610064599e-5 * Y + 0.00048449797120281 * k -
35379 0.154362151871126) +
35380 Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y -
35381 0.00477271405408747 * k + 1.53380253221734) +
35382 Y * (0.000961250184130688 * Y - 0.00266257332283933 * k +
35383 0.48357088451265) +
35384 k * (-0.000336197177618394 * k + 0.484791561490776);
35385
35386 var g = 107.268039397724 +
35387 Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr +
35388 0.000659397001245577 * Y + 0.000426105652938837 * k -
35389 0.176491792462875) +
35390 Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y +
35391 0.000770482631801132 * k - 0.151051492775562) +
35392 Y * (0.00126935368114843 * Y - 0.00265090189010898 * k +
35393 0.25802910206845) +
35394 k * (-0.000318913117588328 * k - 0.213742400323665);
35395
35396 var b = -20.810012546947 +
35397 Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr +
35398 0.0020741088115012 * Y - 0.00288260236853442 * k +
35399 0.814272968359295) +
35400 Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y +
35401 0.000560833691242812 * k - 0.195152027534049) +
35402 Y * (0.00174418132927582 * Y - 0.00255243321439347 * k +
35403 0.116935020465145) +
35404 k * (-0.000343531996510555 * k + 0.24165260232407);
35405
35406 data[offset++] = clamp0to255(r);
35407 data[offset++] = clamp0to255(g);
35408 data[offset++] = clamp0to255(b);
35409 }
35410 return data;
35411 },
35412
35413 _convertYcckToCmyk: function convertYcckToCmyk(data) {
35414 var Y, Cb, Cr;
35415 for (var i = 0, length = data.length; i < length; i += 4) {
35416 Y = data[i];
35417 Cb = data[i + 1];
35418 Cr = data[i + 2];
35419 data[i ] = clamp0to255(434.456 - Y - 1.402 * Cr);
35420 data[i + 1] = clamp0to255(119.541 - Y + 0.344 * Cb + 0.714 * Cr);
35421 data[i + 2] = clamp0to255(481.816 - Y - 1.772 * Cb);
35422 // K in data[i + 3] is unchanged
35423 }
35424 return data;
35425 },
35426
35427 _convertCmykToRgb: function convertCmykToRgb(data) {
35428 var c, m, y, k;
35429 var offset = 0;
35430 var min = -255 * 255 * 255;
35431 var scale = 1 / 255 / 255;
35432 for (var i = 0, length = data.length; i < length; i += 4) {
35433 c = data[i];
35434 m = data[i + 1];
35435 y = data[i + 2];
35436 k = data[i + 3];
35437
35438 var r =
35439 c * (-4.387332384609988 * c + 54.48615194189176 * m +
35440 18.82290502165302 * y + 212.25662451639585 * k -
35441 72734.4411664936) +
35442 m * (1.7149763477362134 * m - 5.6096736904047315 * y -
35443 17.873870861415444 * k - 1401.7366389350734) +
35444 y * (-2.5217340131683033 * y - 21.248923337353073 * k +
35445 4465.541406466231) -
35446 k * (21.86122147463605 * k + 48317.86113160301);
35447 var g =
35448 c * (8.841041422036149 * c + 60.118027045597366 * m +
35449 6.871425592049007 * y + 31.159100130055922 * k -
35450 20220.756542821975) +
35451 m * (-15.310361306967817 * m + 17.575251261109482 * y +
35452 131.35250912493976 * k - 48691.05921601825) +
35453 y * (4.444339102852739 * y + 9.8632861493405 * k -
35454 6341.191035517494) -
35455 k * (20.737325471181034 * k + 47890.15695978492);
35456 var b =
35457 c * (0.8842522430003296 * c + 8.078677503112928 * m +
35458 30.89978309703729 * y - 0.23883238689178934 * k -
35459 3616.812083916688) +
35460 m * (10.49593273432072 * m + 63.02378494754052 * y +
35461 50.606957656360734 * k - 28620.90484698408) +
35462 y * (0.03296041114873217 * y + 115.60384449646641 * k -
35463 49363.43385999684) -
35464 k * (22.33816807309886 * k + 45932.16563550634);
35465
35466 data[offset++] = r >= 0 ? 255 : r <= min ? 0 : 255 + r * scale | 0;
35467 data[offset++] = g >= 0 ? 255 : g <= min ? 0 : 255 + g * scale | 0;
35468 data[offset++] = b >= 0 ? 255 : b <= min ? 0 : 255 + b * scale | 0;
35469 }
35470 return data;
35471 },
35472
35473 getData: function getData(width, height, forceRGBoutput) {
35474 if (this.numComponents > 4) {
35475 throw 'Unsupported color mode';
35476 }
35477 // type of data: Uint8Array(width * height * numComponents)
35478 var data = this._getLinearizedBlockData(width, height);
35479
35480 if (this.numComponents === 3) {
35481 return this._convertYccToRgb(data);
35482 } else if (this.numComponents === 4) {
35483 if (this._isColorConversionNeeded()) {
35484 if (forceRGBoutput) {
35485 return this._convertYcckToRgb(data);
35486 } else {
35487 return this._convertYcckToCmyk(data);
35488 }
35489 } else if (forceRGBoutput) {
35490 return this._convertCmykToRgb(data);
35491 }
35492 }
35493 return data;
35494 }
35495 };
35496
35497 return constructor;
35498 })();
35499
35500
35501 var JpxImage = (function JpxImageClosure() {
35502 // Table E.1
35503 var SubbandsGainLog2 = {
35504 'LL': 0,
35505 'LH': 1,
35506 'HL': 1,
35507 'HH': 2
35508 };
35509 function JpxImage() {
35510 this.failOnCorruptedImage = false;
35511 }
35512 JpxImage.prototype = {
35513 parse: function JpxImage_parse(data) {
35514
35515 var head = readUint16(data, 0);
35516 // No box header, immediate start of codestream (SOC)
35517 if (head === 0xFF4F) {
35518 this.parseCodestream(data, 0, data.length);
35519 return;
35520 }
35521
35522 var position = 0, length = data.length;
35523 while (position < length) {
35524 var headerSize = 8;
35525 var lbox = readUint32(data, position);
35526 var tbox = readUint32(data, position + 4);
35527 position += headerSize;
35528 if (lbox === 1) {
35529 // XLBox: read UInt64 according to spec.
35530 // JavaScript's int precision of 53 bit should be sufficient here.
35531 lbox = readUint32(data, position) * 4294967296 +
35532 readUint32(data, position + 4);
35533 position += 8;
35534 headerSize += 8;
35535 }
35536 if (lbox === 0) {
35537 lbox = length - position + headerSize;
35538 }
35539 if (lbox < headerSize) {
35540 throw new Error('JPX Error: Invalid box field size');
35541 }
35542 var dataLength = lbox - headerSize;
35543 var jumpDataLength = true;
35544 switch (tbox) {
35545 case 0x6A703268: // 'jp2h'
35546 jumpDataLength = false; // parsing child boxes
35547 break;
35548 case 0x636F6C72: // 'colr'
35549 // Colorspaces are not used, the CS from the PDF is used.
35550 var method = data[position];
35551 var precedence = data[position + 1];
35552 var approximation = data[position + 2];
35553 if (method === 1) {
35554 // enumerated colorspace
35555 var colorspace = readUint32(data, position + 3);
35556 switch (colorspace) {
35557 case 16: // this indicates a sRGB colorspace
35558 case 17: // this indicates a grayscale colorspace
35559 case 18: // this indicates a YUV colorspace
35560 break;
35561 default:
35562 warn('Unknown colorspace ' + colorspace);
35563 break;
35564 }
35565 } else if (method === 2) {
35566 info('ICC profile not supported');
35567 }
35568 break;
35569 case 0x6A703263: // 'jp2c'
35570 this.parseCodestream(data, position, position + dataLength);
35571 break;
35572 case 0x6A502020: // 'jP\024\024'
35573 if (0x0d0a870a !== readUint32(data, position)) {
35574 warn('Invalid JP2 signature');
35575 }
35576 break;
35577 // The following header types are valid but currently not used:
35578 case 0x6A501A1A: // 'jP\032\032'
35579 case 0x66747970: // 'ftyp'
35580 case 0x72726571: // 'rreq'
35581 case 0x72657320: // 'res '
35582 case 0x69686472: // 'ihdr'
35583 break;
35584 default:
35585 var headerType = String.fromCharCode((tbox >> 24) & 0xFF,
35586 (tbox >> 16) & 0xFF,
35587 (tbox >> 8) & 0xFF,
35588 tbox & 0xFF);
35589 warn('Unsupported header type ' + tbox + ' (' + headerType + ')');
35590 break;
35591 }
35592 if (jumpDataLength) {
35593 position += dataLength;
35594 }
35595 }
35596 },
35597 parseImageProperties: function JpxImage_parseImageProperties(stream) {
35598 var newByte = stream.getByte();
35599 while (newByte >= 0) {
35600 var oldByte = newByte;
35601 newByte = stream.getByte();
35602 var code = (oldByte << 8) | newByte;
35603 // Image and tile size (SIZ)
35604 if (code === 0xFF51) {
35605 stream.skip(4);
35606 var Xsiz = stream.getInt32() >>> 0; // Byte 4
35607 var Ysiz = stream.getInt32() >>> 0; // Byte 8
35608 var XOsiz = stream.getInt32() >>> 0; // Byte 12
35609 var YOsiz = stream.getInt32() >>> 0; // Byte 16
35610 stream.skip(16);
35611 var Csiz = stream.getUint16(); // Byte 36
35612 this.width = Xsiz - XOsiz;
35613 this.height = Ysiz - YOsiz;
35614 this.componentsCount = Csiz;
35615 // Results are always returned as Uint8Arrays
35616 this.bitsPerComponent = 8;
35617 return;
35618 }
35619 }
35620 throw new Error('JPX Error: No size marker found in JPX stream');
35621 },
35622 parseCodestream: function JpxImage_parseCodestream(data, start, end) {
35623 var context = {};
35624 try {
35625 var doNotRecover = false;
35626 var position = start;
35627 while (position + 1 < end) {
35628 var code = readUint16(data, position);
35629 position += 2;
35630
35631 var length = 0, j, sqcd, spqcds, spqcdSize, scalarExpounded, tile;
35632 switch (code) {
35633 case 0xFF4F: // Start of codestream (SOC)
35634 context.mainHeader = true;
35635 break;
35636 case 0xFFD9: // End of codestream (EOC)
35637 break;
35638 case 0xFF51: // Image and tile size (SIZ)
35639 length = readUint16(data, position);
35640 var siz = {};
35641 siz.Xsiz = readUint32(data, position + 4);
35642 siz.Ysiz = readUint32(data, position + 8);
35643 siz.XOsiz = readUint32(data, position + 12);
35644 siz.YOsiz = readUint32(data, position + 16);
35645 siz.XTsiz = readUint32(data, position + 20);
35646 siz.YTsiz = readUint32(data, position + 24);
35647 siz.XTOsiz = readUint32(data, position + 28);
35648 siz.YTOsiz = readUint32(data, position + 32);
35649 var componentsCount = readUint16(data, position + 36);
35650 siz.Csiz = componentsCount;
35651 var components = [];
35652 j = position + 38;
35653 for (var i = 0; i < componentsCount; i++) {
35654 var component = {
35655 precision: (data[j] & 0x7F) + 1,
35656 isSigned: !!(data[j] & 0x80),
35657 XRsiz: data[j + 1],
35658 YRsiz: data[j + 1]
35659 };
35660 calculateComponentDimensions(component, siz);
35661 components.push(component);
35662 }
35663 context.SIZ = siz;
35664 context.components = components;
35665 calculateTileGrids(context, components);
35666 context.QCC = [];
35667 context.COC = [];
35668 break;
35669 case 0xFF5C: // Quantization default (QCD)
35670 length = readUint16(data, position);
35671 var qcd = {};
35672 j = position + 2;
35673 sqcd = data[j++];
35674 switch (sqcd & 0x1F) {
35675 case 0:
35676 spqcdSize = 8;
35677 scalarExpounded = true;
35678 break;
35679 case 1:
35680 spqcdSize = 16;
35681 scalarExpounded = false;
35682 break;
35683 case 2:
35684 spqcdSize = 16;
35685 scalarExpounded = true;
35686 break;
35687 default:
35688 throw new Error('JPX Error: Invalid SQcd value ' + sqcd);
35689 }
35690 qcd.noQuantization = (spqcdSize === 8);
35691 qcd.scalarExpounded = scalarExpounded;
35692 qcd.guardBits = sqcd >> 5;
35693 spqcds = [];
35694 while (j < length + position) {
35695 var spqcd = {};
35696 if (spqcdSize === 8) {
35697 spqcd.epsilon = data[j++] >> 3;
35698 spqcd.mu = 0;
35699 } else {
35700 spqcd.epsilon = data[j] >> 3;
35701 spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
35702 j += 2;
35703 }
35704 spqcds.push(spqcd);
35705 }
35706 qcd.SPqcds = spqcds;
35707 if (context.mainHeader) {
35708 context.QCD = qcd;
35709 } else {
35710 context.currentTile.QCD = qcd;
35711 context.currentTile.QCC = [];
35712 }
35713 break;
35714 case 0xFF5D: // Quantization component (QCC)
35715 length = readUint16(data, position);
35716 var qcc = {};
35717 j = position + 2;
35718 var cqcc;
35719 if (context.SIZ.Csiz < 257) {
35720 cqcc = data[j++];
35721 } else {
35722 cqcc = readUint16(data, j);
35723 j += 2;
35724 }
35725 sqcd = data[j++];
35726 switch (sqcd & 0x1F) {
35727 case 0:
35728 spqcdSize = 8;
35729 scalarExpounded = true;
35730 break;
35731 case 1:
35732 spqcdSize = 16;
35733 scalarExpounded = false;
35734 break;
35735 case 2:
35736 spqcdSize = 16;
35737 scalarExpounded = true;
35738 break;
35739 default:
35740 throw new Error('JPX Error: Invalid SQcd value ' + sqcd);
35741 }
35742 qcc.noQuantization = (spqcdSize === 8);
35743 qcc.scalarExpounded = scalarExpounded;
35744 qcc.guardBits = sqcd >> 5;
35745 spqcds = [];
35746 while (j < (length + position)) {
35747 spqcd = {};
35748 if (spqcdSize === 8) {
35749 spqcd.epsilon = data[j++] >> 3;
35750 spqcd.mu = 0;
35751 } else {
35752 spqcd.epsilon = data[j] >> 3;
35753 spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
35754 j += 2;
35755 }
35756 spqcds.push(spqcd);
35757 }
35758 qcc.SPqcds = spqcds;
35759 if (context.mainHeader) {
35760 context.QCC[cqcc] = qcc;
35761 } else {
35762 context.currentTile.QCC[cqcc] = qcc;
35763 }
35764 break;
35765 case 0xFF52: // Coding style default (COD)
35766 length = readUint16(data, position);
35767 var cod = {};
35768 j = position + 2;
35769 var scod = data[j++];
35770 cod.entropyCoderWithCustomPrecincts = !!(scod & 1);
35771 cod.sopMarkerUsed = !!(scod & 2);
35772 cod.ephMarkerUsed = !!(scod & 4);
35773 cod.progressionOrder = data[j++];
35774 cod.layersCount = readUint16(data, j);
35775 j += 2;
35776 cod.multipleComponentTransform = data[j++];
35777
35778 cod.decompositionLevelsCount = data[j++];
35779 cod.xcb = (data[j++] & 0xF) + 2;
35780 cod.ycb = (data[j++] & 0xF) + 2;
35781 var blockStyle = data[j++];
35782 cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1);
35783 cod.resetContextProbabilities = !!(blockStyle & 2);
35784 cod.terminationOnEachCodingPass = !!(blockStyle & 4);
35785 cod.verticalyStripe = !!(blockStyle & 8);
35786 cod.predictableTermination = !!(blockStyle & 16);
35787 cod.segmentationSymbolUsed = !!(blockStyle & 32);
35788 cod.reversibleTransformation = data[j++];
35789 if (cod.entropyCoderWithCustomPrecincts) {
35790 var precinctsSizes = [];
35791 while (j < length + position) {
35792 var precinctsSize = data[j++];
35793 precinctsSizes.push({
35794 PPx: precinctsSize & 0xF,
35795 PPy: precinctsSize >> 4
35796 });
35797 }
35798 cod.precinctsSizes = precinctsSizes;
35799 }
35800 var unsupported = [];
35801 if (cod.selectiveArithmeticCodingBypass) {
35802 unsupported.push('selectiveArithmeticCodingBypass');
35803 }
35804 if (cod.resetContextProbabilities) {
35805 unsupported.push('resetContextProbabilities');
35806 }
35807 if (cod.terminationOnEachCodingPass) {
35808 unsupported.push('terminationOnEachCodingPass');
35809 }
35810 if (cod.verticalyStripe) {
35811 unsupported.push('verticalyStripe');
35812 }
35813 if (cod.predictableTermination) {
35814 unsupported.push('predictableTermination');
35815 }
35816 if (unsupported.length > 0) {
35817 doNotRecover = true;
35818 throw new Error('JPX Error: Unsupported COD options (' +
35819 unsupported.join(', ') + ')');
35820 }
35821 if (context.mainHeader) {
35822 context.COD = cod;
35823 } else {
35824 context.currentTile.COD = cod;
35825 context.currentTile.COC = [];
35826 }
35827 break;
35828 case 0xFF90: // Start of tile-part (SOT)
35829 length = readUint16(data, position);
35830 tile = {};
35831 tile.index = readUint16(data, position + 2);
35832 tile.length = readUint32(data, position + 4);
35833 tile.dataEnd = tile.length + position - 2;
35834 tile.partIndex = data[position + 8];
35835 tile.partsCount = data[position + 9];
35836
35837 context.mainHeader = false;
35838 if (tile.partIndex === 0) {
35839 // reset component specific settings
35840 tile.COD = context.COD;
35841 tile.COC = context.COC.slice(0); // clone of the global COC
35842 tile.QCD = context.QCD;
35843 tile.QCC = context.QCC.slice(0); // clone of the global COC
35844 }
35845 context.currentTile = tile;
35846 break;
35847 case 0xFF93: // Start of data (SOD)
35848 tile = context.currentTile;
35849 if (tile.partIndex === 0) {
35850 initializeTile(context, tile.index);
35851 buildPackets(context);
35852 }
35853
35854 // moving to the end of the data
35855 length = tile.dataEnd - position;
35856 parseTilePackets(context, data, position, length);
35857 break;
35858 case 0xFF55: // Tile-part lengths, main header (TLM)
35859 case 0xFF57: // Packet length, main header (PLM)
35860 case 0xFF58: // Packet length, tile-part header (PLT)
35861 case 0xFF64: // Comment (COM)
35862 length = readUint16(data, position);
35863 // skipping content
35864 break;
35865 case 0xFF53: // Coding style component (COC)
35866 throw new Error('JPX Error: Codestream code 0xFF53 (COC) is ' +
35867 'not implemented');
35868 default:
35869 throw new Error('JPX Error: Unknown codestream code: ' +
35870 code.toString(16));
35871 }
35872 position += length;
35873 }
35874 } catch (e) {
35875 if (doNotRecover || this.failOnCorruptedImage) {
35876 throw e;
35877 } else {
35878 warn('Trying to recover from ' + e.message);
35879 }
35880 }
35881 this.tiles = transformComponents(context);
35882 this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;
35883 this.height = context.SIZ.Ysiz - context.SIZ.YOsiz;
35884 this.componentsCount = context.SIZ.Csiz;
35885 }
35886 };
35887 function calculateComponentDimensions(component, siz) {
35888 // Section B.2 Component mapping
35889 component.x0 = Math.ceil(siz.XOsiz / component.XRsiz);
35890 component.x1 = Math.ceil(siz.Xsiz / component.XRsiz);
35891 component.y0 = Math.ceil(siz.YOsiz / component.YRsiz);
35892 component.y1 = Math.ceil(siz.Ysiz / component.YRsiz);
35893 component.width = component.x1 - component.x0;
35894 component.height = component.y1 - component.y0;
35895 }
35896 function calculateTileGrids(context, components) {
35897 var siz = context.SIZ;
35898 // Section B.3 Division into tile and tile-components
35899 var tile, tiles = [];
35900 var numXtiles = Math.ceil((siz.Xsiz - siz.XTOsiz) / siz.XTsiz);
35901 var numYtiles = Math.ceil((siz.Ysiz - siz.YTOsiz) / siz.YTsiz);
35902 for (var q = 0; q < numYtiles; q++) {
35903 for (var p = 0; p < numXtiles; p++) {
35904 tile = {};
35905 tile.tx0 = Math.max(siz.XTOsiz + p * siz.XTsiz, siz.XOsiz);
35906 tile.ty0 = Math.max(siz.YTOsiz + q * siz.YTsiz, siz.YOsiz);
35907 tile.tx1 = Math.min(siz.XTOsiz + (p + 1) * siz.XTsiz, siz.Xsiz);
35908 tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz);
35909 tile.width = tile.tx1 - tile.tx0;
35910 tile.height = tile.ty1 - tile.ty0;
35911 tile.components = [];
35912 tiles.push(tile);
35913 }
35914 }
35915 context.tiles = tiles;
35916
35917 var componentsCount = siz.Csiz;
35918 for (var i = 0, ii = componentsCount; i < ii; i++) {
35919 var component = components[i];
35920 for (var j = 0, jj = tiles.length; j < jj; j++) {
35921 var tileComponent = {};
35922 tile = tiles[j];
35923 tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
35924 tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
35925 tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
35926 tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz);
35927 tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0;
35928 tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0;
35929 tile.components[i] = tileComponent;
35930 }
35931 }
35932 }
35933 function getBlocksDimensions(context, component, r) {
35934 var codOrCoc = component.codingStyleParameters;
35935 var result = {};
35936 if (!codOrCoc.entropyCoderWithCustomPrecincts) {
35937 result.PPx = 15;
35938 result.PPy = 15;
35939 } else {
35940 result.PPx = codOrCoc.precinctsSizes[r].PPx;
35941 result.PPy = codOrCoc.precinctsSizes[r].PPy;
35942 }
35943 // calculate codeblock size as described in section B.7
35944 result.xcb_ = (r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) :
35945 Math.min(codOrCoc.xcb, result.PPx));
35946 result.ycb_ = (r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) :
35947 Math.min(codOrCoc.ycb, result.PPy));
35948 return result;
35949 }
35950 function buildPrecincts(context, resolution, dimensions) {
35951 // Section B.6 Division resolution to precincts
35952 var precinctWidth = 1 << dimensions.PPx;
35953 var precinctHeight = 1 << dimensions.PPy;
35954 // Jasper introduces codeblock groups for mapping each subband codeblocks
35955 // to precincts. Precinct partition divides a resolution according to width
35956 // and height parameters. The subband that belongs to the resolution level
35957 // has a different size than the level, unless it is the zero resolution.
35958
35959 // From Jasper documentation: jpeg2000.pdf, section K: Tier-2 coding:
35960 // The precinct partitioning for a particular subband is derived from a
35961 // partitioning of its parent LL band (i.e., the LL band at the next higher
35962 // resolution level)... The LL band associated with each resolution level is
35963 // divided into precincts... Each of the resulting precinct regions is then
35964 // mapped into its child subbands (if any) at the next lower resolution
35965 // level. This is accomplished by using the coordinate transformation
35966 // (u, v) = (ceil(x/2), ceil(y/2)) where (x, y) and (u, v) are the
35967 // coordinates of a point in the LL band and child subband, respectively.
35968 var isZeroRes = resolution.resLevel === 0;
35969 var precinctWidthInSubband = 1 << (dimensions.PPx + (isZeroRes ? 0 : -1));
35970 var precinctHeightInSubband = 1 << (dimensions.PPy + (isZeroRes ? 0 : -1));
35971 var numprecinctswide = (resolution.trx1 > resolution.trx0 ?
35972 Math.ceil(resolution.trx1 / precinctWidth) -
35973 Math.floor(resolution.trx0 / precinctWidth) : 0);
35974 var numprecinctshigh = (resolution.try1 > resolution.try0 ?
35975 Math.ceil(resolution.try1 / precinctHeight) -
35976 Math.floor(resolution.try0 / precinctHeight) : 0);
35977 var numprecincts = numprecinctswide * numprecinctshigh;
35978
35979 resolution.precinctParameters = {
35980 precinctWidth: precinctWidth,
35981 precinctHeight: precinctHeight,
35982 numprecinctswide: numprecinctswide,
35983 numprecinctshigh: numprecinctshigh,
35984 numprecincts: numprecincts,
35985 precinctWidthInSubband: precinctWidthInSubband,
35986 precinctHeightInSubband: precinctHeightInSubband
35987 };
35988 }
35989 function buildCodeblocks(context, subband, dimensions) {
35990 // Section B.7 Division sub-band into code-blocks
35991 var xcb_ = dimensions.xcb_;
35992 var ycb_ = dimensions.ycb_;
35993 var codeblockWidth = 1 << xcb_;
35994 var codeblockHeight = 1 << ycb_;
35995 var cbx0 = subband.tbx0 >> xcb_;
35996 var cby0 = subband.tby0 >> ycb_;
35997 var cbx1 = (subband.tbx1 + codeblockWidth - 1) >> xcb_;
35998 var cby1 = (subband.tby1 + codeblockHeight - 1) >> ycb_;
35999 var precinctParameters = subband.resolution.precinctParameters;
36000 var codeblocks = [];
36001 var precincts = [];
36002 var i, j, codeblock, precinctNumber;
36003 for (j = cby0; j < cby1; j++) {
36004 for (i = cbx0; i < cbx1; i++) {
36005 codeblock = {
36006 cbx: i,
36007 cby: j,
36008 tbx0: codeblockWidth * i,
36009 tby0: codeblockHeight * j,
36010 tbx1: codeblockWidth * (i + 1),
36011 tby1: codeblockHeight * (j + 1)
36012 };
36013
36014 codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0);
36015 codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0);
36016 codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1);
36017 codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1);
36018
36019 // Calculate precinct number for this codeblock, codeblock position
36020 // should be relative to its subband, use actual dimension and position
36021 // See comment about codeblock group width and height
36022 var pi = Math.floor((codeblock.tbx0_ - subband.tbx0) /
36023 precinctParameters.precinctWidthInSubband);
36024 var pj = Math.floor((codeblock.tby0_ - subband.tby0) /
36025 precinctParameters.precinctHeightInSubband);
36026 precinctNumber = pi + (pj * precinctParameters.numprecinctswide);
36027
36028 codeblock.precinctNumber = precinctNumber;
36029 codeblock.subbandType = subband.type;
36030 codeblock.Lblock = 3;
36031
36032 if (codeblock.tbx1_ <= codeblock.tbx0_ ||
36033 codeblock.tby1_ <= codeblock.tby0_) {
36034 continue;
36035 }
36036 codeblocks.push(codeblock);
36037 // building precinct for the sub-band
36038 var precinct = precincts[precinctNumber];
36039 if (precinct !== undefined) {
36040 if (i < precinct.cbxMin) {
36041 precinct.cbxMin = i;
36042 } else if (i > precinct.cbxMax) {
36043 precinct.cbxMax = i;
36044 }
36045 if (j < precinct.cbyMin) {
36046 precinct.cbxMin = j;
36047 } else if (j > precinct.cbyMax) {
36048 precinct.cbyMax = j;
36049 }
36050 } else {
36051 precincts[precinctNumber] = precinct = {
36052 cbxMin: i,
36053 cbyMin: j,
36054 cbxMax: i,
36055 cbyMax: j
36056 };
36057 }
36058 codeblock.precinct = precinct;
36059 }
36060 }
36061 subband.codeblockParameters = {
36062 codeblockWidth: xcb_,
36063 codeblockHeight: ycb_,
36064 numcodeblockwide: cbx1 - cbx0 + 1,
36065 numcodeblockhigh: cby1 - cby0 + 1
36066 };
36067 subband.codeblocks = codeblocks;
36068 subband.precincts = precincts;
36069 }
36070 function createPacket(resolution, precinctNumber, layerNumber) {
36071 var precinctCodeblocks = [];
36072 // Section B.10.8 Order of info in packet
36073 var subbands = resolution.subbands;
36074 // sub-bands already ordered in 'LL', 'HL', 'LH', and 'HH' sequence
36075 for (var i = 0, ii = subbands.length; i < ii; i++) {
36076 var subband = subbands[i];
36077 var codeblocks = subband.codeblocks;
36078 for (var j = 0, jj = codeblocks.length; j < jj; j++) {
36079 var codeblock = codeblocks[j];
36080 if (codeblock.precinctNumber !== precinctNumber) {
36081 continue;
36082 }
36083 precinctCodeblocks.push(codeblock);
36084 }
36085 }
36086 return {
36087 layerNumber: layerNumber,
36088 codeblocks: precinctCodeblocks
36089 };
36090 }
36091 function LayerResolutionComponentPositionIterator(context) {
36092 var siz = context.SIZ;
36093 var tileIndex = context.currentTile.index;
36094 var tile = context.tiles[tileIndex];
36095 var layersCount = tile.codingStyleDefaultParameters.layersCount;
36096 var componentsCount = siz.Csiz;
36097 var maxDecompositionLevelsCount = 0;
36098 for (var q = 0; q < componentsCount; q++) {
36099 maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
36100 tile.components[q].codingStyleParameters.decompositionLevelsCount);
36101 }
36102
36103 var l = 0, r = 0, i = 0, k = 0;
36104
36105 this.nextPacket = function JpxImage_nextPacket() {
36106 // Section B.12.1.1 Layer-resolution-component-position
36107 for (; l < layersCount; l++) {
36108 for (; r <= maxDecompositionLevelsCount; r++) {
36109 for (; i < componentsCount; i++) {
36110 var component = tile.components[i];
36111 if (r > component.codingStyleParameters.decompositionLevelsCount) {
36112 continue;
36113 }
36114
36115 var resolution = component.resolutions[r];
36116 var numprecincts = resolution.precinctParameters.numprecincts;
36117 for (; k < numprecincts;) {
36118 var packet = createPacket(resolution, k, l);
36119 k++;
36120 return packet;
36121 }
36122 k = 0;
36123 }
36124 i = 0;
36125 }
36126 r = 0;
36127 }
36128 throw new Error('JPX Error: Out of packets');
36129 };
36130 }
36131 function ResolutionLayerComponentPositionIterator(context) {
36132 var siz = context.SIZ;
36133 var tileIndex = context.currentTile.index;
36134 var tile = context.tiles[tileIndex];
36135 var layersCount = tile.codingStyleDefaultParameters.layersCount;
36136 var componentsCount = siz.Csiz;
36137 var maxDecompositionLevelsCount = 0;
36138 for (var q = 0; q < componentsCount; q++) {
36139 maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
36140 tile.components[q].codingStyleParameters.decompositionLevelsCount);
36141 }
36142
36143 var r = 0, l = 0, i = 0, k = 0;
36144
36145 this.nextPacket = function JpxImage_nextPacket() {
36146 // Section B.12.1.2 Resolution-layer-component-position
36147 for (; r <= maxDecompositionLevelsCount; r++) {
36148 for (; l < layersCount; l++) {
36149 for (; i < componentsCount; i++) {
36150 var component = tile.components[i];
36151 if (r > component.codingStyleParameters.decompositionLevelsCount) {
36152 continue;
36153 }
36154
36155 var resolution = component.resolutions[r];
36156 var numprecincts = resolution.precinctParameters.numprecincts;
36157 for (; k < numprecincts;) {
36158 var packet = createPacket(resolution, k, l);
36159 k++;
36160 return packet;
36161 }
36162 k = 0;
36163 }
36164 i = 0;
36165 }
36166 l = 0;
36167 }
36168 throw new Error('JPX Error: Out of packets');
36169 };
36170 }
36171 function ResolutionPositionComponentLayerIterator(context) {
36172 var siz = context.SIZ;
36173 var tileIndex = context.currentTile.index;
36174 var tile = context.tiles[tileIndex];
36175 var layersCount = tile.codingStyleDefaultParameters.layersCount;
36176 var componentsCount = siz.Csiz;
36177 var l, r, c, p;
36178 var maxDecompositionLevelsCount = 0;
36179 for (c = 0; c < componentsCount; c++) {
36180 var component = tile.components[c];
36181 maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
36182 component.codingStyleParameters.decompositionLevelsCount);
36183 }
36184 var maxNumPrecinctsInLevel = new Int32Array(
36185 maxDecompositionLevelsCount + 1);
36186 for (r = 0; r <= maxDecompositionLevelsCount; ++r) {
36187 var maxNumPrecincts = 0;
36188 for (c = 0; c < componentsCount; ++c) {
36189 var resolutions = tile.components[c].resolutions;
36190 if (r < resolutions.length) {
36191 maxNumPrecincts = Math.max(maxNumPrecincts,
36192 resolutions[r].precinctParameters.numprecincts);
36193 }
36194 }
36195 maxNumPrecinctsInLevel[r] = maxNumPrecincts;
36196 }
36197 l = 0;
36198 r = 0;
36199 c = 0;
36200 p = 0;
36201
36202 this.nextPacket = function JpxImage_nextPacket() {
36203 // Section B.12.1.3 Resolution-position-component-layer
36204 for (; r <= maxDecompositionLevelsCount; r++) {
36205 for (; p < maxNumPrecinctsInLevel[r]; p++) {
36206 for (; c < componentsCount; c++) {
36207 var component = tile.components[c];
36208 if (r > component.codingStyleParameters.decompositionLevelsCount) {
36209 continue;
36210 }
36211 var resolution = component.resolutions[r];
36212 var numprecincts = resolution.precinctParameters.numprecincts;
36213 if (p >= numprecincts) {
36214 continue;
36215 }
36216 for (; l < layersCount;) {
36217 var packet = createPacket(resolution, p, l);
36218 l++;
36219 return packet;
36220 }
36221 l = 0;
36222 }
36223 c = 0;
36224 }
36225 p = 0;
36226 }
36227 throw new Error('JPX Error: Out of packets');
36228 };
36229 }
36230 function PositionComponentResolutionLayerIterator(context) {
36231 var siz = context.SIZ;
36232 var tileIndex = context.currentTile.index;
36233 var tile = context.tiles[tileIndex];
36234 var layersCount = tile.codingStyleDefaultParameters.layersCount;
36235 var componentsCount = siz.Csiz;
36236 var precinctsSizes = getPrecinctSizesInImageScale(tile);
36237 var precinctsIterationSizes = precinctsSizes;
36238 var l = 0, r = 0, c = 0, px = 0, py = 0;
36239
36240 this.nextPacket = function JpxImage_nextPacket() {
36241 // Section B.12.1.4 Position-component-resolution-layer
36242 for (; py < precinctsIterationSizes.maxNumHigh; py++) {
36243 for (; px < precinctsIterationSizes.maxNumWide; px++) {
36244 for (; c < componentsCount; c++) {
36245 var component = tile.components[c];
36246 var decompositionLevelsCount =
36247 component.codingStyleParameters.decompositionLevelsCount;
36248 for (; r <= decompositionLevelsCount; r++) {
36249 var resolution = component.resolutions[r];
36250 var sizeInImageScale =
36251 precinctsSizes.components[c].resolutions[r];
36252 var k = getPrecinctIndexIfExist(
36253 px,
36254 py,
36255 sizeInImageScale,
36256 precinctsIterationSizes,
36257 resolution);
36258 if (k === null) {
36259 continue;
36260 }
36261 for (; l < layersCount;) {
36262 var packet = createPacket(resolution, k, l);
36263 l++;
36264 return packet;
36265 }
36266 l = 0;
36267 }
36268 r = 0;
36269 }
36270 c = 0;
36271 }
36272 px = 0;
36273 }
36274 throw new Error('JPX Error: Out of packets');
36275 };
36276 }
36277 function ComponentPositionResolutionLayerIterator(context) {
36278 var siz = context.SIZ;
36279 var tileIndex = context.currentTile.index;
36280 var tile = context.tiles[tileIndex];
36281 var layersCount = tile.codingStyleDefaultParameters.layersCount;
36282 var componentsCount = siz.Csiz;
36283 var precinctsSizes = getPrecinctSizesInImageScale(tile);
36284 var l = 0, r = 0, c = 0, px = 0, py = 0;
36285
36286 this.nextPacket = function JpxImage_nextPacket() {
36287 // Section B.12.1.5 Component-position-resolution-layer
36288 for (; c < componentsCount; ++c) {
36289 var component = tile.components[c];
36290 var precinctsIterationSizes = precinctsSizes.components[c];
36291 var decompositionLevelsCount =
36292 component.codingStyleParameters.decompositionLevelsCount;
36293 for (; py < precinctsIterationSizes.maxNumHigh; py++) {
36294 for (; px < precinctsIterationSizes.maxNumWide; px++) {
36295 for (; r <= decompositionLevelsCount; r++) {
36296 var resolution = component.resolutions[r];
36297 var sizeInImageScale = precinctsIterationSizes.resolutions[r];
36298 var k = getPrecinctIndexIfExist(
36299 px,
36300 py,
36301 sizeInImageScale,
36302 precinctsIterationSizes,
36303 resolution);
36304 if (k === null) {
36305 continue;
36306 }
36307 for (; l < layersCount;) {
36308 var packet = createPacket(resolution, k, l);
36309 l++;
36310 return packet;
36311 }
36312 l = 0;
36313 }
36314 r = 0;
36315 }
36316 px = 0;
36317 }
36318 py = 0;
36319 }
36320 throw new Error('JPX Error: Out of packets');
36321 };
36322 }
36323 function getPrecinctIndexIfExist(
36324 pxIndex, pyIndex, sizeInImageScale, precinctIterationSizes, resolution) {
36325 var posX = pxIndex * precinctIterationSizes.minWidth;
36326 var posY = pyIndex * precinctIterationSizes.minHeight;
36327 if (posX % sizeInImageScale.width !== 0 ||
36328 posY % sizeInImageScale.height !== 0) {
36329 return null;
36330 }
36331 var startPrecinctRowIndex =
36332 (posY / sizeInImageScale.width) *
36333 resolution.precinctParameters.numprecinctswide;
36334 return (posX / sizeInImageScale.height) + startPrecinctRowIndex;
36335 }
36336 function getPrecinctSizesInImageScale(tile) {
36337 var componentsCount = tile.components.length;
36338 var minWidth = Number.MAX_VALUE;
36339 var minHeight = Number.MAX_VALUE;
36340 var maxNumWide = 0;
36341 var maxNumHigh = 0;
36342 var sizePerComponent = new Array(componentsCount);
36343 for (var c = 0; c < componentsCount; c++) {
36344 var component = tile.components[c];
36345 var decompositionLevelsCount =
36346 component.codingStyleParameters.decompositionLevelsCount;
36347 var sizePerResolution = new Array(decompositionLevelsCount + 1);
36348 var minWidthCurrentComponent = Number.MAX_VALUE;
36349 var minHeightCurrentComponent = Number.MAX_VALUE;
36350 var maxNumWideCurrentComponent = 0;
36351 var maxNumHighCurrentComponent = 0;
36352 var scale = 1;
36353 for (var r = decompositionLevelsCount; r >= 0; --r) {
36354 var resolution = component.resolutions[r];
36355 var widthCurrentResolution =
36356 scale * resolution.precinctParameters.precinctWidth;
36357 var heightCurrentResolution =
36358 scale * resolution.precinctParameters.precinctHeight;
36359 minWidthCurrentComponent = Math.min(
36360 minWidthCurrentComponent,
36361 widthCurrentResolution);
36362 minHeightCurrentComponent = Math.min(
36363 minHeightCurrentComponent,
36364 heightCurrentResolution);
36365 maxNumWideCurrentComponent = Math.max(maxNumWideCurrentComponent,
36366 resolution.precinctParameters.numprecinctswide);
36367 maxNumHighCurrentComponent = Math.max(maxNumHighCurrentComponent,
36368 resolution.precinctParameters.numprecinctshigh);
36369 sizePerResolution[r] = {
36370 width: widthCurrentResolution,
36371 height: heightCurrentResolution
36372 };
36373 scale <<= 1;
36374 }
36375 minWidth = Math.min(minWidth, minWidthCurrentComponent);
36376 minHeight = Math.min(minHeight, minHeightCurrentComponent);
36377 maxNumWide = Math.max(maxNumWide, maxNumWideCurrentComponent);
36378 maxNumHigh = Math.max(maxNumHigh, maxNumHighCurrentComponent);
36379 sizePerComponent[c] = {
36380 resolutions: sizePerResolution,
36381 minWidth: minWidthCurrentComponent,
36382 minHeight: minHeightCurrentComponent,
36383 maxNumWide: maxNumWideCurrentComponent,
36384 maxNumHigh: maxNumHighCurrentComponent
36385 };
36386 }
36387 return {
36388 components: sizePerComponent,
36389 minWidth: minWidth,
36390 minHeight: minHeight,
36391 maxNumWide: maxNumWide,
36392 maxNumHigh: maxNumHigh
36393 };
36394 }
36395 function buildPackets(context) {
36396 var siz = context.SIZ;
36397 var tileIndex = context.currentTile.index;
36398 var tile = context.tiles[tileIndex];
36399 var componentsCount = siz.Csiz;
36400 // Creating resolutions and sub-bands for each component
36401 for (var c = 0; c < componentsCount; c++) {
36402 var component = tile.components[c];
36403 var decompositionLevelsCount =
36404 component.codingStyleParameters.decompositionLevelsCount;
36405 // Section B.5 Resolution levels and sub-bands
36406 var resolutions = [];
36407 var subbands = [];
36408 for (var r = 0; r <= decompositionLevelsCount; r++) {
36409 var blocksDimensions = getBlocksDimensions(context, component, r);
36410 var resolution = {};
36411 var scale = 1 << (decompositionLevelsCount - r);
36412 resolution.trx0 = Math.ceil(component.tcx0 / scale);
36413 resolution.try0 = Math.ceil(component.tcy0 / scale);
36414 resolution.trx1 = Math.ceil(component.tcx1 / scale);
36415 resolution.try1 = Math.ceil(component.tcy1 / scale);
36416 resolution.resLevel = r;
36417 buildPrecincts(context, resolution, blocksDimensions);
36418 resolutions.push(resolution);
36419
36420 var subband;
36421 if (r === 0) {
36422 // one sub-band (LL) with last decomposition
36423 subband = {};
36424 subband.type = 'LL';
36425 subband.tbx0 = Math.ceil(component.tcx0 / scale);
36426 subband.tby0 = Math.ceil(component.tcy0 / scale);
36427 subband.tbx1 = Math.ceil(component.tcx1 / scale);
36428 subband.tby1 = Math.ceil(component.tcy1 / scale);
36429 subband.resolution = resolution;
36430 buildCodeblocks(context, subband, blocksDimensions);
36431 subbands.push(subband);
36432 resolution.subbands = [subband];
36433 } else {
36434 var bscale = 1 << (decompositionLevelsCount - r + 1);
36435 var resolutionSubbands = [];
36436 // three sub-bands (HL, LH and HH) with rest of decompositions
36437 subband = {};
36438 subband.type = 'HL';
36439 subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
36440 subband.tby0 = Math.ceil(component.tcy0 / bscale);
36441 subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
36442 subband.tby1 = Math.ceil(component.tcy1 / bscale);
36443 subband.resolution = resolution;
36444 buildCodeblocks(context, subband, blocksDimensions);
36445 subbands.push(subband);
36446 resolutionSubbands.push(subband);
36447
36448 subband = {};
36449 subband.type = 'LH';
36450 subband.tbx0 = Math.ceil(component.tcx0 / bscale);
36451 subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
36452 subband.tbx1 = Math.ceil(component.tcx1 / bscale);
36453 subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
36454 subband.resolution = resolution;
36455 buildCodeblocks(context, subband, blocksDimensions);
36456 subbands.push(subband);
36457 resolutionSubbands.push(subband);
36458
36459 subband = {};
36460 subband.type = 'HH';
36461 subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
36462 subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
36463 subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
36464 subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
36465 subband.resolution = resolution;
36466 buildCodeblocks(context, subband, blocksDimensions);
36467 subbands.push(subband);
36468 resolutionSubbands.push(subband);
36469
36470 resolution.subbands = resolutionSubbands;
36471 }
36472 }
36473 component.resolutions = resolutions;
36474 component.subbands = subbands;
36475 }
36476 // Generate the packets sequence
36477 var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
36478 switch (progressionOrder) {
36479 case 0:
36480 tile.packetsIterator =
36481 new LayerResolutionComponentPositionIterator(context);
36482 break;
36483 case 1:
36484 tile.packetsIterator =
36485 new ResolutionLayerComponentPositionIterator(context);
36486 break;
36487 case 2:
36488 tile.packetsIterator =
36489 new ResolutionPositionComponentLayerIterator(context);
36490 break;
36491 case 3:
36492 tile.packetsIterator =
36493 new PositionComponentResolutionLayerIterator(context);
36494 break;
36495 case 4:
36496 tile.packetsIterator =
36497 new ComponentPositionResolutionLayerIterator(context);
36498 break;
36499 default:
36500 throw new Error('JPX Error: Unsupported progression order ' +
36501 progressionOrder);
36502 }
36503 }
36504 function parseTilePackets(context, data, offset, dataLength) {
36505 var position = 0;
36506 var buffer, bufferSize = 0, skipNextBit = false;
36507 function readBits(count) {
36508 while (bufferSize < count) {
36509 var b = data[offset + position];
36510 position++;
36511 if (skipNextBit) {
36512 buffer = (buffer << 7) | b;
36513 bufferSize += 7;
36514 skipNextBit = false;
36515 } else {
36516 buffer = (buffer << 8) | b;
36517 bufferSize += 8;
36518 }
36519 if (b === 0xFF) {
36520 skipNextBit = true;
36521 }
36522 }
36523 bufferSize -= count;
36524 return (buffer >>> bufferSize) & ((1 << count) - 1);
36525 }
36526 function skipMarkerIfEqual(value) {
36527 if (data[offset + position - 1] === 0xFF &&
36528 data[offset + position] === value) {
36529 skipBytes(1);
36530 return true;
36531 } else if (data[offset + position] === 0xFF &&
36532 data[offset + position + 1] === value) {
36533 skipBytes(2);
36534 return true;
36535 }
36536 return false;
36537 }
36538 function skipBytes(count) {
36539 position += count;
36540 }
36541 function alignToByte() {
36542 bufferSize = 0;
36543 if (skipNextBit) {
36544 position++;
36545 skipNextBit = false;
36546 }
36547 }
36548 function readCodingpasses() {
36549 if (readBits(1) === 0) {
36550 return 1;
36551 }
36552 if (readBits(1) === 0) {
36553 return 2;
36554 }
36555 var value = readBits(2);
36556 if (value < 3) {
36557 return value + 3;
36558 }
36559 value = readBits(5);
36560 if (value < 31) {
36561 return value + 6;
36562 }
36563 value = readBits(7);
36564 return value + 37;
36565 }
36566 var tileIndex = context.currentTile.index;
36567 var tile = context.tiles[tileIndex];
36568 var sopMarkerUsed = context.COD.sopMarkerUsed;
36569 var ephMarkerUsed = context.COD.ephMarkerUsed;
36570 var packetsIterator = tile.packetsIterator;
36571 while (position < dataLength) {
36572 alignToByte();
36573 if (sopMarkerUsed && skipMarkerIfEqual(0x91)) {
36574 // Skip also marker segment length and packet sequence ID
36575 skipBytes(4);
36576 }
36577 var packet = packetsIterator.nextPacket();
36578 if (!readBits(1)) {
36579 continue;
36580 }
36581 var layerNumber = packet.layerNumber;
36582 var queue = [], codeblock;
36583 for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {
36584 codeblock = packet.codeblocks[i];
36585 var precinct = codeblock.precinct;
36586 var codeblockColumn = codeblock.cbx - precinct.cbxMin;
36587 var codeblockRow = codeblock.cby - precinct.cbyMin;
36588 var codeblockIncluded = false;
36589 var firstTimeInclusion = false;
36590 var valueReady;
36591 if (codeblock['included'] !== undefined) {
36592 codeblockIncluded = !!readBits(1);
36593 } else {
36594 // reading inclusion tree
36595 precinct = codeblock.precinct;
36596 var inclusionTree, zeroBitPlanesTree;
36597 if (precinct['inclusionTree'] !== undefined) {
36598 inclusionTree = precinct.inclusionTree;
36599 } else {
36600 // building inclusion and zero bit-planes trees
36601 var width = precinct.cbxMax - precinct.cbxMin + 1;
36602 var height = precinct.cbyMax - precinct.cbyMin + 1;
36603 inclusionTree = new InclusionTree(width, height, layerNumber);
36604 zeroBitPlanesTree = new TagTree(width, height);
36605 precinct.inclusionTree = inclusionTree;
36606 precinct.zeroBitPlanesTree = zeroBitPlanesTree;
36607 }
36608
36609 if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {
36610 while (true) {
36611 if (readBits(1)) {
36612 valueReady = !inclusionTree.nextLevel();
36613 if (valueReady) {
36614 codeblock.included = true;
36615 codeblockIncluded = firstTimeInclusion = true;
36616 break;
36617 }
36618 } else {
36619 inclusionTree.incrementValue(layerNumber);
36620 break;
36621 }
36622 }
36623 }
36624 }
36625 if (!codeblockIncluded) {
36626 continue;
36627 }
36628 if (firstTimeInclusion) {
36629 zeroBitPlanesTree = precinct.zeroBitPlanesTree;
36630 zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);
36631 while (true) {
36632 if (readBits(1)) {
36633 valueReady = !zeroBitPlanesTree.nextLevel();
36634 if (valueReady) {
36635 break;
36636 }
36637 } else {
36638 zeroBitPlanesTree.incrementValue();
36639 }
36640 }
36641 codeblock.zeroBitPlanes = zeroBitPlanesTree.value;
36642 }
36643 var codingpasses = readCodingpasses();
36644 while (readBits(1)) {
36645 codeblock.Lblock++;
36646 }
36647 var codingpassesLog2 = log2(codingpasses);
36648 // rounding down log2
36649 var bits = ((codingpasses < (1 << codingpassesLog2)) ?
36650 codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock;
36651 var codedDataLength = readBits(bits);
36652 queue.push({
36653 codeblock: codeblock,
36654 codingpasses: codingpasses,
36655 dataLength: codedDataLength
36656 });
36657 }
36658 alignToByte();
36659 if (ephMarkerUsed) {
36660 skipMarkerIfEqual(0x92);
36661 }
36662 while (queue.length > 0) {
36663 var packetItem = queue.shift();
36664 codeblock = packetItem.codeblock;
36665 if (codeblock['data'] === undefined) {
36666 codeblock.data = [];
36667 }
36668 codeblock.data.push({
36669 data: data,
36670 start: offset + position,
36671 end: offset + position + packetItem.dataLength,
36672 codingpasses: packetItem.codingpasses
36673 });
36674 position += packetItem.dataLength;
36675 }
36676 }
36677 return position;
36678 }
36679 function copyCoefficients(coefficients, levelWidth, levelHeight, subband,
36680 delta, mb, reversible, segmentationSymbolUsed) {
36681 var x0 = subband.tbx0;
36682 var y0 = subband.tby0;
36683 var width = subband.tbx1 - subband.tbx0;
36684 var codeblocks = subband.codeblocks;
36685 var right = subband.type.charAt(0) === 'H' ? 1 : 0;
36686 var bottom = subband.type.charAt(1) === 'H' ? levelWidth : 0;
36687
36688 for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
36689 var codeblock = codeblocks[i];
36690 var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
36691 var blockHeight = codeblock.tby1_ - codeblock.tby0_;
36692 if (blockWidth === 0 || blockHeight === 0) {
36693 continue;
36694 }
36695 if (codeblock['data'] === undefined) {
36696 continue;
36697 }
36698
36699 var bitModel, currentCodingpassType;
36700 bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
36701 codeblock.zeroBitPlanes, mb);
36702 currentCodingpassType = 2; // first bit plane starts from cleanup
36703
36704 // collect data
36705 var data = codeblock.data, totalLength = 0, codingpasses = 0;
36706 var j, jj, dataItem;
36707 for (j = 0, jj = data.length; j < jj; j++) {
36708 dataItem = data[j];
36709 totalLength += dataItem.end - dataItem.start;
36710 codingpasses += dataItem.codingpasses;
36711 }
36712 var encodedData = new Uint8Array(totalLength);
36713 var position = 0;
36714 for (j = 0, jj = data.length; j < jj; j++) {
36715 dataItem = data[j];
36716 var chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
36717 encodedData.set(chunk, position);
36718 position += chunk.length;
36719 }
36720 // decoding the item
36721 var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
36722 bitModel.setDecoder(decoder);
36723
36724 for (j = 0; j < codingpasses; j++) {
36725 switch (currentCodingpassType) {
36726 case 0:
36727 bitModel.runSignificancePropogationPass();
36728 break;
36729 case 1:
36730 bitModel.runMagnitudeRefinementPass();
36731 break;
36732 case 2:
36733 bitModel.runCleanupPass();
36734 if (segmentationSymbolUsed) {
36735 bitModel.checkSegmentationSymbol();
36736 }
36737 break;
36738 }
36739 currentCodingpassType = (currentCodingpassType + 1) % 3;
36740 }
36741
36742 var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;
36743 var sign = bitModel.coefficentsSign;
36744 var magnitude = bitModel.coefficentsMagnitude;
36745 var bitsDecoded = bitModel.bitsDecoded;
36746 var magnitudeCorrection = reversible ? 0 : 0.5;
36747 var k, n, nb;
36748 position = 0;
36749 // Do the interleaving of Section F.3.3 here, so we do not need
36750 // to copy later. LL level is not interleaved, just copied.
36751 var interleave = (subband.type !== 'LL');
36752 for (j = 0; j < blockHeight; j++) {
36753 var row = (offset / width) | 0; // row in the non-interleaved subband
36754 var levelOffset = 2 * row * (levelWidth - width) + right + bottom;
36755 for (k = 0; k < blockWidth; k++) {
36756 n = magnitude[position];
36757 if (n !== 0) {
36758 n = (n + magnitudeCorrection) * delta;
36759 if (sign[position] !== 0) {
36760 n = -n;
36761 }
36762 nb = bitsDecoded[position];
36763 var pos = interleave ? (levelOffset + (offset << 1)) : offset;
36764 if (reversible && (nb >= mb)) {
36765 coefficients[pos] = n;
36766 } else {
36767 coefficients[pos] = n * (1 << (mb - nb));
36768 }
36769 }
36770 offset++;
36771 position++;
36772 }
36773 offset += width - blockWidth;
36774 }
36775 }
36776 }
36777 function transformTile(context, tile, c) {
36778 var component = tile.components[c];
36779 var codingStyleParameters = component.codingStyleParameters;
36780 var quantizationParameters = component.quantizationParameters;
36781 var decompositionLevelsCount =
36782 codingStyleParameters.decompositionLevelsCount;
36783 var spqcds = quantizationParameters.SPqcds;
36784 var scalarExpounded = quantizationParameters.scalarExpounded;
36785 var guardBits = quantizationParameters.guardBits;
36786 var segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed;
36787 var precision = context.components[c].precision;
36788
36789 var reversible = codingStyleParameters.reversibleTransformation;
36790 var transform = (reversible ? new ReversibleTransform() :
36791 new IrreversibleTransform());
36792
36793 var subbandCoefficients = [];
36794 var b = 0;
36795 for (var i = 0; i <= decompositionLevelsCount; i++) {
36796 var resolution = component.resolutions[i];
36797
36798 var width = resolution.trx1 - resolution.trx0;
36799 var height = resolution.try1 - resolution.try0;
36800 // Allocate space for the whole sublevel.
36801 var coefficients = new Float32Array(width * height);
36802
36803 for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
36804 var mu, epsilon;
36805 if (!scalarExpounded) {
36806 // formula E-5
36807 mu = spqcds[0].mu;
36808 epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0);
36809 } else {
36810 mu = spqcds[b].mu;
36811 epsilon = spqcds[b].epsilon;
36812 b++;
36813 }
36814
36815 var subband = resolution.subbands[j];
36816 var gainLog2 = SubbandsGainLog2[subband.type];
36817
36818 // calulate quantization coefficient (Section E.1.1.1)
36819 var delta = (reversible ? 1 :
36820 Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048));
36821 var mb = (guardBits + epsilon - 1);
36822
36823 // In the first resolution level, copyCoefficients will fill the
36824 // whole array with coefficients. In the succeding passes,
36825 // copyCoefficients will consecutively fill in the values that belong
36826 // to the interleaved positions of the HL, LH, and HH coefficients.
36827 // The LL coefficients will then be interleaved in Transform.iterate().
36828 copyCoefficients(coefficients, width, height, subband, delta, mb,
36829 reversible, segmentationSymbolUsed);
36830 }
36831 subbandCoefficients.push({
36832 width: width,
36833 height: height,
36834 items: coefficients
36835 });
36836 }
36837
36838 var result = transform.calculate(subbandCoefficients,
36839 component.tcx0, component.tcy0);
36840 return {
36841 left: component.tcx0,
36842 top: component.tcy0,
36843 width: result.width,
36844 height: result.height,
36845 items: result.items
36846 };
36847 }
36848 function transformComponents(context) {
36849 var siz = context.SIZ;
36850 var components = context.components;
36851 var componentsCount = siz.Csiz;
36852 var resultImages = [];
36853 for (var i = 0, ii = context.tiles.length; i < ii; i++) {
36854 var tile = context.tiles[i];
36855 var transformedTiles = [];
36856 var c;
36857 for (c = 0; c < componentsCount; c++) {
36858 transformedTiles[c] = transformTile(context, tile, c);
36859 }
36860 var tile0 = transformedTiles[0];
36861 var out = new Uint8Array(tile0.items.length * componentsCount);
36862 var result = {
36863 left: tile0.left,
36864 top: tile0.top,
36865 width: tile0.width,
36866 height: tile0.height,
36867 items: out
36868 };
36869
36870 // Section G.2.2 Inverse multi component transform
36871 var shift, offset, max, min, maxK;
36872 var pos = 0, j, jj, y0, y1, y2, r, g, b, k, val;
36873 if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
36874 var fourComponents = componentsCount === 4;
36875 var y0items = transformedTiles[0].items;
36876 var y1items = transformedTiles[1].items;
36877 var y2items = transformedTiles[2].items;
36878 var y3items = fourComponents ? transformedTiles[3].items : null;
36879
36880 // HACK: The multiple component transform formulas below assume that
36881 // all components have the same precision. With this in mind, we
36882 // compute shift and offset only once.
36883 shift = components[0].precision - 8;
36884 offset = (128 << shift) + 0.5;
36885 max = 255 * (1 << shift);
36886 maxK = max * 0.5;
36887 min = -maxK;
36888
36889 var component0 = tile.components[0];
36890 var alpha01 = componentsCount - 3;
36891 jj = y0items.length;
36892 if (!component0.codingStyleParameters.reversibleTransformation) {
36893 // inverse irreversible multiple component transform
36894 for (j = 0; j < jj; j++, pos += alpha01) {
36895 y0 = y0items[j] + offset;
36896 y1 = y1items[j];
36897 y2 = y2items[j];
36898 r = y0 + 1.402 * y2;
36899 g = y0 - 0.34413 * y1 - 0.71414 * y2;
36900 b = y0 + 1.772 * y1;
36901 out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
36902 out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
36903 out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
36904 }
36905 } else {
36906 // inverse reversible multiple component transform
36907 for (j = 0; j < jj; j++, pos += alpha01) {
36908 y0 = y0items[j] + offset;
36909 y1 = y1items[j];
36910 y2 = y2items[j];
36911 g = y0 - ((y2 + y1) >> 2);
36912 r = g + y2;
36913 b = g + y1;
36914 out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
36915 out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
36916 out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
36917 }
36918 }
36919 if (fourComponents) {
36920 for (j = 0, pos = 3; j < jj; j++, pos += 4) {
36921 k = y3items[j];
36922 out[pos] = k <= min ? 0 : k >= maxK ? 255 : (k + offset) >> shift;
36923 }
36924 }
36925 } else { // no multi-component transform
36926 for (c = 0; c < componentsCount; c++) {
36927 var items = transformedTiles[c].items;
36928 shift = components[c].precision - 8;
36929 offset = (128 << shift) + 0.5;
36930 max = (127.5 * (1 << shift));
36931 min = -max;
36932 for (pos = c, j = 0, jj = items.length; j < jj; j++) {
36933 val = items[j];
36934 out[pos] = val <= min ? 0 :
36935 val >= max ? 255 : (val + offset) >> shift;
36936 pos += componentsCount;
36937 }
36938 }
36939 }
36940 resultImages.push(result);
36941 }
36942 return resultImages;
36943 }
36944 function initializeTile(context, tileIndex) {
36945 var siz = context.SIZ;
36946 var componentsCount = siz.Csiz;
36947 var tile = context.tiles[tileIndex];
36948 for (var c = 0; c < componentsCount; c++) {
36949 var component = tile.components[c];
36950 var qcdOrQcc = (context.currentTile.QCC[c] !== undefined ?
36951 context.currentTile.QCC[c] : context.currentTile.QCD);
36952 component.quantizationParameters = qcdOrQcc;
36953 var codOrCoc = (context.currentTile.COC[c] !== undefined ?
36954 context.currentTile.COC[c] : context.currentTile.COD);
36955 component.codingStyleParameters = codOrCoc;
36956 }
36957 tile.codingStyleDefaultParameters = context.currentTile.COD;
36958 }
36959
36960 // Section B.10.2 Tag trees
36961 var TagTree = (function TagTreeClosure() {
36962 function TagTree(width, height) {
36963 var levelsLength = log2(Math.max(width, height)) + 1;
36964 this.levels = [];
36965 for (var i = 0; i < levelsLength; i++) {
36966 var level = {
36967 width: width,
36968 height: height,
36969 items: []
36970 };
36971 this.levels.push(level);
36972 width = Math.ceil(width / 2);
36973 height = Math.ceil(height / 2);
36974 }
36975 }
36976 TagTree.prototype = {
36977 reset: function TagTree_reset(i, j) {
36978 var currentLevel = 0, value = 0, level;
36979 while (currentLevel < this.levels.length) {
36980 level = this.levels[currentLevel];
36981 var index = i + j * level.width;
36982 if (level.items[index] !== undefined) {
36983 value = level.items[index];
36984 break;
36985 }
36986 level.index = index;
36987 i >>= 1;
36988 j >>= 1;
36989 currentLevel++;
36990 }
36991 currentLevel--;
36992 level = this.levels[currentLevel];
36993 level.items[level.index] = value;
36994 this.currentLevel = currentLevel;
36995 delete this.value;
36996 },
36997 incrementValue: function TagTree_incrementValue() {
36998 var level = this.levels[this.currentLevel];
36999 level.items[level.index]++;
37000 },
37001 nextLevel: function TagTree_nextLevel() {
37002 var currentLevel = this.currentLevel;
37003 var level = this.levels[currentLevel];
37004 var value = level.items[level.index];
37005 currentLevel--;
37006 if (currentLevel < 0) {
37007 this.value = value;
37008 return false;
37009 }
37010
37011 this.currentLevel = currentLevel;
37012 level = this.levels[currentLevel];
37013 level.items[level.index] = value;
37014 return true;
37015 }
37016 };
37017 return TagTree;
37018 })();
37019
37020 var InclusionTree = (function InclusionTreeClosure() {
37021 function InclusionTree(width, height, defaultValue) {
37022 var levelsLength = log2(Math.max(width, height)) + 1;
37023 this.levels = [];
37024 for (var i = 0; i < levelsLength; i++) {
37025 var items = new Uint8Array(width * height);
37026 for (var j = 0, jj = items.length; j < jj; j++) {
37027 items[j] = defaultValue;
37028 }
37029
37030 var level = {
37031 width: width,
37032 height: height,
37033 items: items
37034 };
37035 this.levels.push(level);
37036
37037 width = Math.ceil(width / 2);
37038 height = Math.ceil(height / 2);
37039 }
37040 }
37041 InclusionTree.prototype = {
37042 reset: function InclusionTree_reset(i, j, stopValue) {
37043 var currentLevel = 0;
37044 while (currentLevel < this.levels.length) {
37045 var level = this.levels[currentLevel];
37046 var index = i + j * level.width;
37047 level.index = index;
37048 var value = level.items[index];
37049
37050 if (value === 0xFF) {
37051 break;
37052 }
37053
37054 if (value > stopValue) {
37055 this.currentLevel = currentLevel;
37056 // already know about this one, propagating the value to top levels
37057 this.propagateValues();
37058 return false;
37059 }
37060
37061 i >>= 1;
37062 j >>= 1;
37063 currentLevel++;
37064 }
37065 this.currentLevel = currentLevel - 1;
37066 return true;
37067 },
37068 incrementValue: function InclusionTree_incrementValue(stopValue) {
37069 var level = this.levels[this.currentLevel];
37070 level.items[level.index] = stopValue + 1;
37071 this.propagateValues();
37072 },
37073 propagateValues: function InclusionTree_propagateValues() {
37074 var levelIndex = this.currentLevel;
37075 var level = this.levels[levelIndex];
37076 var currentValue = level.items[level.index];
37077 while (--levelIndex >= 0) {
37078 level = this.levels[levelIndex];
37079 level.items[level.index] = currentValue;
37080 }
37081 },
37082 nextLevel: function InclusionTree_nextLevel() {
37083 var currentLevel = this.currentLevel;
37084 var level = this.levels[currentLevel];
37085 var value = level.items[level.index];
37086 level.items[level.index] = 0xFF;
37087 currentLevel--;
37088 if (currentLevel < 0) {
37089 return false;
37090 }
37091
37092 this.currentLevel = currentLevel;
37093 level = this.levels[currentLevel];
37094 level.items[level.index] = value;
37095 return true;
37096 }
37097 };
37098 return InclusionTree;
37099 })();
37100
37101 // Section D. Coefficient bit modeling
37102 var BitModel = (function BitModelClosure() {
37103 var UNIFORM_CONTEXT = 17;
37104 var RUNLENGTH_CONTEXT = 18;
37105 // Table D-1
37106 // The index is binary presentation: 0dddvvhh, ddd - sum of Di (0..4),
37107 // vv - sum of Vi (0..2), and hh - sum of Hi (0..2)
37108 var LLAndLHContextsLabel = new Uint8Array([
37109 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,
37110 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,
37111 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
37112 ]);
37113 var HLContextLabel = new Uint8Array([
37114 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,
37115 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,
37116 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
37117 ]);
37118 var HHContextLabel = new Uint8Array([
37119 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,
37120 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,
37121 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
37122 ]);
37123
37124 function BitModel(width, height, subband, zeroBitPlanes, mb) {
37125 this.width = width;
37126 this.height = height;
37127
37128 this.contextLabelTable = (subband === 'HH' ? HHContextLabel :
37129 (subband === 'HL' ? HLContextLabel : LLAndLHContextsLabel));
37130
37131 var coefficientCount = width * height;
37132
37133 // coefficients outside the encoding region treated as insignificant
37134 // add border state cells for significanceState
37135 this.neighborsSignificance = new Uint8Array(coefficientCount);
37136 this.coefficentsSign = new Uint8Array(coefficientCount);
37137 this.coefficentsMagnitude = mb > 14 ? new Uint32Array(coefficientCount) :
37138 mb > 6 ? new Uint16Array(coefficientCount) :
37139 new Uint8Array(coefficientCount);
37140 this.processingFlags = new Uint8Array(coefficientCount);
37141
37142 var bitsDecoded = new Uint8Array(coefficientCount);
37143 if (zeroBitPlanes !== 0) {
37144 for (var i = 0; i < coefficientCount; i++) {
37145 bitsDecoded[i] = zeroBitPlanes;
37146 }
37147 }
37148 this.bitsDecoded = bitsDecoded;
37149
37150 this.reset();
37151 }
37152
37153 BitModel.prototype = {
37154 setDecoder: function BitModel_setDecoder(decoder) {
37155 this.decoder = decoder;
37156 },
37157 reset: function BitModel_reset() {
37158 // We have 17 contexts that are accessed via context labels,
37159 // plus the uniform and runlength context.
37160 this.contexts = new Int8Array(19);
37161
37162 // Contexts are packed into 1 byte:
37163 // highest 7 bits carry the index, lowest bit carries mps
37164 this.contexts[0] = (4 << 1) | 0;
37165 this.contexts[UNIFORM_CONTEXT] = (46 << 1) | 0;
37166 this.contexts[RUNLENGTH_CONTEXT] = (3 << 1) | 0;
37167 },
37168 setNeighborsSignificance:
37169 function BitModel_setNeighborsSignificance(row, column, index) {
37170 var neighborsSignificance = this.neighborsSignificance;
37171 var width = this.width, height = this.height;
37172 var left = (column > 0);
37173 var right = (column + 1 < width);
37174 var i;
37175
37176 if (row > 0) {
37177 i = index - width;
37178 if (left) {
37179 neighborsSignificance[i - 1] += 0x10;
37180 }
37181 if (right) {
37182 neighborsSignificance[i + 1] += 0x10;
37183 }
37184 neighborsSignificance[i] += 0x04;
37185 }
37186
37187 if (row + 1 < height) {
37188 i = index + width;
37189 if (left) {
37190 neighborsSignificance[i - 1] += 0x10;
37191 }
37192 if (right) {
37193 neighborsSignificance[i + 1] += 0x10;
37194 }
37195 neighborsSignificance[i] += 0x04;
37196 }
37197
37198 if (left) {
37199 neighborsSignificance[index - 1] += 0x01;
37200 }
37201 if (right) {
37202 neighborsSignificance[index + 1] += 0x01;
37203 }
37204 neighborsSignificance[index] |= 0x80;
37205 },
37206 runSignificancePropogationPass:
37207 function BitModel_runSignificancePropogationPass() {
37208 var decoder = this.decoder;
37209 var width = this.width, height = this.height;
37210 var coefficentsMagnitude = this.coefficentsMagnitude;
37211 var coefficentsSign = this.coefficentsSign;
37212 var neighborsSignificance = this.neighborsSignificance;
37213 var processingFlags = this.processingFlags;
37214 var contexts = this.contexts;
37215 var labels = this.contextLabelTable;
37216 var bitsDecoded = this.bitsDecoded;
37217 var processedInverseMask = ~1;
37218 var processedMask = 1;
37219 var firstMagnitudeBitMask = 2;
37220
37221 for (var i0 = 0; i0 < height; i0 += 4) {
37222 for (var j = 0; j < width; j++) {
37223 var index = i0 * width + j;
37224 for (var i1 = 0; i1 < 4; i1++, index += width) {
37225 var i = i0 + i1;
37226 if (i >= height) {
37227 break;
37228 }
37229 // clear processed flag first
37230 processingFlags[index] &= processedInverseMask;
37231
37232 if (coefficentsMagnitude[index] ||
37233 !neighborsSignificance[index]) {
37234 continue;
37235 }
37236
37237 var contextLabel = labels[neighborsSignificance[index]];
37238 var decision = decoder.readBit(contexts, contextLabel);
37239 if (decision) {
37240 var sign = this.decodeSignBit(i, j, index);
37241 coefficentsSign[index] = sign;
37242 coefficentsMagnitude[index] = 1;
37243 this.setNeighborsSignificance(i, j, index);
37244 processingFlags[index] |= firstMagnitudeBitMask;
37245 }
37246 bitsDecoded[index]++;
37247 processingFlags[index] |= processedMask;
37248 }
37249 }
37250 }
37251 },
37252 decodeSignBit: function BitModel_decodeSignBit(row, column, index) {
37253 var width = this.width, height = this.height;
37254 var coefficentsMagnitude = this.coefficentsMagnitude;
37255 var coefficentsSign = this.coefficentsSign;
37256 var contribution, sign0, sign1, significance1;
37257 var contextLabel, decoded;
37258
37259 // calculate horizontal contribution
37260 significance1 = (column > 0 && coefficentsMagnitude[index - 1] !== 0);
37261 if (column + 1 < width && coefficentsMagnitude[index + 1] !== 0) {
37262 sign1 = coefficentsSign[index + 1];
37263 if (significance1) {
37264 sign0 = coefficentsSign[index - 1];
37265 contribution = 1 - sign1 - sign0;
37266 } else {
37267 contribution = 1 - sign1 - sign1;
37268 }
37269 } else if (significance1) {
37270 sign0 = coefficentsSign[index - 1];
37271 contribution = 1 - sign0 - sign0;
37272 } else {
37273 contribution = 0;
37274 }
37275 var horizontalContribution = 3 * contribution;
37276
37277 // calculate vertical contribution and combine with the horizontal
37278 significance1 = (row > 0 && coefficentsMagnitude[index - width] !== 0);
37279 if (row + 1 < height && coefficentsMagnitude[index + width] !== 0) {
37280 sign1 = coefficentsSign[index + width];
37281 if (significance1) {
37282 sign0 = coefficentsSign[index - width];
37283 contribution = 1 - sign1 - sign0 + horizontalContribution;
37284 } else {
37285 contribution = 1 - sign1 - sign1 + horizontalContribution;
37286 }
37287 } else if (significance1) {
37288 sign0 = coefficentsSign[index - width];
37289 contribution = 1 - sign0 - sign0 + horizontalContribution;
37290 } else {
37291 contribution = horizontalContribution;
37292 }
37293
37294 if (contribution >= 0) {
37295 contextLabel = 9 + contribution;
37296 decoded = this.decoder.readBit(this.contexts, contextLabel);
37297 } else {
37298 contextLabel = 9 - contribution;
37299 decoded = this.decoder.readBit(this.contexts, contextLabel) ^ 1;
37300 }
37301 return decoded;
37302 },
37303 runMagnitudeRefinementPass:
37304 function BitModel_runMagnitudeRefinementPass() {
37305 var decoder = this.decoder;
37306 var width = this.width, height = this.height;
37307 var coefficentsMagnitude = this.coefficentsMagnitude;
37308 var neighborsSignificance = this.neighborsSignificance;
37309 var contexts = this.contexts;
37310 var bitsDecoded = this.bitsDecoded;
37311 var processingFlags = this.processingFlags;
37312 var processedMask = 1;
37313 var firstMagnitudeBitMask = 2;
37314 var length = width * height;
37315 var width4 = width * 4;
37316
37317 for (var index0 = 0, indexNext; index0 < length; index0 = indexNext) {
37318 indexNext = Math.min(length, index0 + width4);
37319 for (var j = 0; j < width; j++) {
37320 for (var index = index0 + j; index < indexNext; index += width) {
37321
37322 // significant but not those that have just become
37323 if (!coefficentsMagnitude[index] ||
37324 (processingFlags[index] & processedMask) !== 0) {
37325 continue;
37326 }
37327
37328 var contextLabel = 16;
37329 if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) {
37330 processingFlags[index] ^= firstMagnitudeBitMask;
37331 // first refinement
37332 var significance = neighborsSignificance[index] & 127;
37333 contextLabel = significance === 0 ? 15 : 14;
37334 }
37335
37336 var bit = decoder.readBit(contexts, contextLabel);
37337 coefficentsMagnitude[index] =
37338 (coefficentsMagnitude[index] << 1) | bit;
37339 bitsDecoded[index]++;
37340 processingFlags[index] |= processedMask;
37341 }
37342 }
37343 }
37344 },
37345 runCleanupPass: function BitModel_runCleanupPass() {
37346 var decoder = this.decoder;
37347 var width = this.width, height = this.height;
37348 var neighborsSignificance = this.neighborsSignificance;
37349 var coefficentsMagnitude = this.coefficentsMagnitude;
37350 var coefficentsSign = this.coefficentsSign;
37351 var contexts = this.contexts;
37352 var labels = this.contextLabelTable;
37353 var bitsDecoded = this.bitsDecoded;
37354 var processingFlags = this.processingFlags;
37355 var processedMask = 1;
37356 var firstMagnitudeBitMask = 2;
37357 var oneRowDown = width;
37358 var twoRowsDown = width * 2;
37359 var threeRowsDown = width * 3;
37360 var iNext;
37361 for (var i0 = 0; i0 < height; i0 = iNext) {
37362 iNext = Math.min(i0 + 4, height);
37363 var indexBase = i0 * width;
37364 var checkAllEmpty = i0 + 3 < height;
37365 for (var j = 0; j < width; j++) {
37366 var index0 = indexBase + j;
37367 // using the property: labels[neighborsSignificance[index]] === 0
37368 // when neighborsSignificance[index] === 0
37369 var allEmpty = (checkAllEmpty &&
37370 processingFlags[index0] === 0 &&
37371 processingFlags[index0 + oneRowDown] === 0 &&
37372 processingFlags[index0 + twoRowsDown] === 0 &&
37373 processingFlags[index0 + threeRowsDown] === 0 &&
37374 neighborsSignificance[index0] === 0 &&
37375 neighborsSignificance[index0 + oneRowDown] === 0 &&
37376 neighborsSignificance[index0 + twoRowsDown] === 0 &&
37377 neighborsSignificance[index0 + threeRowsDown] === 0);
37378 var i1 = 0, index = index0;
37379 var i = i0, sign;
37380 if (allEmpty) {
37381 var hasSignificantCoefficent =
37382 decoder.readBit(contexts, RUNLENGTH_CONTEXT);
37383 if (!hasSignificantCoefficent) {
37384 bitsDecoded[index0]++;
37385 bitsDecoded[index0 + oneRowDown]++;
37386 bitsDecoded[index0 + twoRowsDown]++;
37387 bitsDecoded[index0 + threeRowsDown]++;
37388 continue; // next column
37389 }
37390 i1 = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |
37391 decoder.readBit(contexts, UNIFORM_CONTEXT);
37392 if (i1 !== 0) {
37393 i = i0 + i1;
37394 index += i1 * width;
37395 }
37396
37397 sign = this.decodeSignBit(i, j, index);
37398 coefficentsSign[index] = sign;
37399 coefficentsMagnitude[index] = 1;
37400 this.setNeighborsSignificance(i, j, index);
37401 processingFlags[index] |= firstMagnitudeBitMask;
37402
37403 index = index0;
37404 for (var i2 = i0; i2 <= i; i2++, index += width) {
37405 bitsDecoded[index]++;
37406 }
37407
37408 i1++;
37409 }
37410 for (i = i0 + i1; i < iNext; i++, index += width) {
37411 if (coefficentsMagnitude[index] ||
37412 (processingFlags[index] & processedMask) !== 0) {
37413 continue;
37414 }
37415
37416 var contextLabel = labels[neighborsSignificance[index]];
37417 var decision = decoder.readBit(contexts, contextLabel);
37418 if (decision === 1) {
37419 sign = this.decodeSignBit(i, j, index);
37420 coefficentsSign[index] = sign;
37421 coefficentsMagnitude[index] = 1;
37422 this.setNeighborsSignificance(i, j, index);
37423 processingFlags[index] |= firstMagnitudeBitMask;
37424 }
37425 bitsDecoded[index]++;
37426 }
37427 }
37428 }
37429 },
37430 checkSegmentationSymbol: function BitModel_checkSegmentationSymbol() {
37431 var decoder = this.decoder;
37432 var contexts = this.contexts;
37433 var symbol = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 3) |
37434 (decoder.readBit(contexts, UNIFORM_CONTEXT) << 2) |
37435 (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |
37436 decoder.readBit(contexts, UNIFORM_CONTEXT);
37437 if (symbol !== 0xA) {
37438 throw new Error('JPX Error: Invalid segmentation symbol');
37439 }
37440 }
37441 };
37442
37443 return BitModel;
37444 })();
37445
37446 // Section F, Discrete wavelet transformation
37447 var Transform = (function TransformClosure() {
37448 function Transform() {}
37449
37450 Transform.prototype.calculate =
37451 function transformCalculate(subbands, u0, v0) {
37452 var ll = subbands[0];
37453 for (var i = 1, ii = subbands.length; i < ii; i++) {
37454 ll = this.iterate(ll, subbands[i], u0, v0);
37455 }
37456 return ll;
37457 };
37458 Transform.prototype.extend = function extend(buffer, offset, size) {
37459 // Section F.3.7 extending... using max extension of 4
37460 var i1 = offset - 1, j1 = offset + 1;
37461 var i2 = offset + size - 2, j2 = offset + size;
37462 buffer[i1--] = buffer[j1++];
37463 buffer[j2++] = buffer[i2--];
37464 buffer[i1--] = buffer[j1++];
37465 buffer[j2++] = buffer[i2--];
37466 buffer[i1--] = buffer[j1++];
37467 buffer[j2++] = buffer[i2--];
37468 buffer[i1] = buffer[j1];
37469 buffer[j2] = buffer[i2];
37470 };
37471 Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh,
37472 u0, v0) {
37473 var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
37474 var width = hl_lh_hh.width;
37475 var height = hl_lh_hh.height;
37476 var items = hl_lh_hh.items;
37477 var i, j, k, l, u, v;
37478
37479 // Interleave LL according to Section F.3.3
37480 for (k = 0, i = 0; i < llHeight; i++) {
37481 l = i * 2 * width;
37482 for (j = 0; j < llWidth; j++, k++, l += 2) {
37483 items[l] = llItems[k];
37484 }
37485 }
37486 // The LL band is not needed anymore.
37487 llItems = ll.items = null;
37488
37489 var bufferPadding = 4;
37490 var rowBuffer = new Float32Array(width + 2 * bufferPadding);
37491
37492 // Section F.3.4 HOR_SR
37493 if (width === 1) {
37494 // if width = 1, when u0 even keep items as is, when odd divide by 2
37495 if ((u0 & 1) !== 0) {
37496 for (v = 0, k = 0; v < height; v++, k += width) {
37497 items[k] *= 0.5;
37498 }
37499 }
37500 } else {
37501 for (v = 0, k = 0; v < height; v++, k += width) {
37502 rowBuffer.set(items.subarray(k, k + width), bufferPadding);
37503
37504 this.extend(rowBuffer, bufferPadding, width);
37505 this.filter(rowBuffer, bufferPadding, width);
37506
37507 items.set(
37508 rowBuffer.subarray(bufferPadding, bufferPadding + width),
37509 k);
37510 }
37511 }
37512
37513 // Accesses to the items array can take long, because it may not fit into
37514 // CPU cache and has to be fetched from main memory. Since subsequent
37515 // accesses to the items array are not local when reading columns, we
37516 // have a cache miss every time. To reduce cache misses, get up to
37517 // 'numBuffers' items at a time and store them into the individual
37518 // buffers. The colBuffers should be small enough to fit into CPU cache.
37519 var numBuffers = 16;
37520 var colBuffers = [];
37521 for (i = 0; i < numBuffers; i++) {
37522 colBuffers.push(new Float32Array(height + 2 * bufferPadding));
37523 }
37524 var b, currentBuffer = 0;
37525 ll = bufferPadding + height;
37526
37527 // Section F.3.5 VER_SR
37528 if (height === 1) {
37529 // if height = 1, when v0 even keep items as is, when odd divide by 2
37530 if ((v0 & 1) !== 0) {
37531 for (u = 0; u < width; u++) {
37532 items[u] *= 0.5;
37533 }
37534 }
37535 } else {
37536 for (u = 0; u < width; u++) {
37537 // if we ran out of buffers, copy several image columns at once
37538 if (currentBuffer === 0) {
37539 numBuffers = Math.min(width - u, numBuffers);
37540 for (k = u, l = bufferPadding; l < ll; k += width, l++) {
37541 for (b = 0; b < numBuffers; b++) {
37542 colBuffers[b][l] = items[k + b];
37543 }
37544 }
37545 currentBuffer = numBuffers;
37546 }
37547
37548 currentBuffer--;
37549 var buffer = colBuffers[currentBuffer];
37550 this.extend(buffer, bufferPadding, height);
37551 this.filter(buffer, bufferPadding, height);
37552
37553 // If this is last buffer in this group of buffers, flush all buffers.
37554 if (currentBuffer === 0) {
37555 k = u - numBuffers + 1;
37556 for (l = bufferPadding; l < ll; k += width, l++) {
37557 for (b = 0; b < numBuffers; b++) {
37558 items[k + b] = colBuffers[b][l];
37559 }
37560 }
37561 }
37562 }
37563 }
37564
37565 return {
37566 width: width,
37567 height: height,
37568 items: items
37569 };
37570 };
37571 return Transform;
37572 })();
37573
37574 // Section 3.8.2 Irreversible 9-7 filter
37575 var IrreversibleTransform = (function IrreversibleTransformClosure() {
37576 function IrreversibleTransform() {
37577 Transform.call(this);
37578 }
37579
37580 IrreversibleTransform.prototype = Object.create(Transform.prototype);
37581 IrreversibleTransform.prototype.filter =
37582 function irreversibleTransformFilter(x, offset, length) {
37583 var len = length >> 1;
37584 offset = offset | 0;
37585 var j, n, current, next;
37586
37587 var alpha = -1.586134342059924;
37588 var beta = -0.052980118572961;
37589 var gamma = 0.882911075530934;
37590 var delta = 0.443506852043971;
37591 var K = 1.230174104914001;
37592 var K_ = 1 / K;
37593
37594 // step 1 is combined with step 3
37595
37596 // step 2
37597 j = offset - 3;
37598 for (n = len + 4; n--; j += 2) {
37599 x[j] *= K_;
37600 }
37601
37602 // step 1 & 3
37603 j = offset - 2;
37604 current = delta * x[j -1];
37605 for (n = len + 3; n--; j += 2) {
37606 next = delta * x[j + 1];
37607 x[j] = K * x[j] - current - next;
37608 if (n--) {
37609 j += 2;
37610 current = delta * x[j + 1];
37611 x[j] = K * x[j] - current - next;
37612 } else {
37613 break;
37614 }
37615 }
37616
37617 // step 4
37618 j = offset - 1;
37619 current = gamma * x[j - 1];
37620 for (n = len + 2; n--; j += 2) {
37621 next = gamma * x[j + 1];
37622 x[j] -= current + next;
37623 if (n--) {
37624 j += 2;
37625 current = gamma * x[j + 1];
37626 x[j] -= current + next;
37627 } else {
37628 break;
37629 }
37630 }
37631
37632 // step 5
37633 j = offset;
37634 current = beta * x[j - 1];
37635 for (n = len + 1; n--; j += 2) {
37636 next = beta * x[j + 1];
37637 x[j] -= current + next;
37638 if (n--) {
37639 j += 2;
37640 current = beta * x[j + 1];
37641 x[j] -= current + next;
37642 } else {
37643 break;
37644 }
37645 }
37646
37647 // step 6
37648 if (len !== 0) {
37649 j = offset + 1;
37650 current = alpha * x[j - 1];
37651 for (n = len; n--; j += 2) {
37652 next = alpha * x[j + 1];
37653 x[j] -= current + next;
37654 if (n--) {
37655 j += 2;
37656 current = alpha * x[j + 1];
37657 x[j] -= current + next;
37658 } else {
37659 break;
37660 }
37661 }
37662 }
37663 };
37664
37665 return IrreversibleTransform;
37666 })();
37667
37668 // Section 3.8.1 Reversible 5-3 filter
37669 var ReversibleTransform = (function ReversibleTransformClosure() {
37670 function ReversibleTransform() {
37671 Transform.call(this);
37672 }
37673
37674 ReversibleTransform.prototype = Object.create(Transform.prototype);
37675 ReversibleTransform.prototype.filter =
37676 function reversibleTransformFilter(x, offset, length) {
37677 var len = length >> 1;
37678 offset = offset | 0;
37679 var j, n;
37680
37681 for (j = offset, n = len + 1; n--; j += 2) {
37682 x[j] -= (x[j - 1] + x[j + 1] + 2) >> 2;
37683 }
37684
37685 for (j = offset + 1, n = len; n--; j += 2) {
37686 x[j] += (x[j - 1] + x[j + 1]) >> 1;
37687 }
37688 };
37689
37690 return ReversibleTransform;
37691 })();
37692
37693 return JpxImage;
37694 })();
37695
37696
37697 var Jbig2Image = (function Jbig2ImageClosure() {
37698 // Utility data structures
37699 function ContextCache() {}
37700
37701 ContextCache.prototype = {
37702 getContexts: function(id) {
37703 if (id in this) {
37704 return this[id];
37705 }
37706 return (this[id] = new Int8Array(1 << 16));
37707 }
37708 };
37709
37710 function DecodingContext(data, start, end) {
37711 this.data = data;
37712 this.start = start;
37713 this.end = end;
37714 }
37715
37716 DecodingContext.prototype = {
37717 get decoder() {
37718 var decoder = new ArithmeticDecoder(this.data, this.start, this.end);
37719 return shadow(this, 'decoder', decoder);
37720 },
37721 get contextCache() {
37722 var cache = new ContextCache();
37723 return shadow(this, 'contextCache', cache);
37724 }
37725 };
37726
37727 // Annex A. Arithmetic Integer Decoding Procedure
37728 // A.2 Procedure for decoding values
37729 function decodeInteger(contextCache, procedure, decoder) {
37730 var contexts = contextCache.getContexts(procedure);
37731 var prev = 1;
37732
37733 function readBits(length) {
37734 var v = 0;
37735 for (var i = 0; i < length; i++) {
37736 var bit = decoder.readBit(contexts, prev);
37737 prev = (prev < 256 ? (prev << 1) | bit :
37738 (((prev << 1) | bit) & 511) | 256);
37739 v = (v << 1) | bit;
37740 }
37741 return v >>> 0;
37742 }
37743
37744 var sign = readBits(1);
37745 var value = readBits(1) ?
37746 (readBits(1) ?
37747 (readBits(1) ?
37748 (readBits(1) ?
37749 (readBits(1) ?
37750 (readBits(32) + 4436) :
37751 readBits(12) + 340) :
37752 readBits(8) + 84) :
37753 readBits(6) + 20) :
37754 readBits(4) + 4) :
37755 readBits(2);
37756 return (sign === 0 ? value : (value > 0 ? -value : null));
37757 }
37758
37759 // A.3 The IAID decoding procedure
37760 function decodeIAID(contextCache, decoder, codeLength) {
37761 var contexts = contextCache.getContexts('IAID');
37762
37763 var prev = 1;
37764 for (var i = 0; i < codeLength; i++) {
37765 var bit = decoder.readBit(contexts, prev);
37766 prev = (prev << 1) | bit;
37767 }
37768 if (codeLength < 31) {
37769 return prev & ((1 << codeLength) - 1);
37770 }
37771 return prev & 0x7FFFFFFF;
37772 }
37773
37774 // 7.3 Segment types
37775 var SegmentTypes = [
37776 'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null,
37777 'ImmediateTextRegion', 'ImmediateLosslessTextRegion', null, null, null,
37778 null, null, null, null, null, 'patternDictionary', null, null, null,
37779 'IntermediateHalftoneRegion', null, 'ImmediateHalftoneRegion',
37780 'ImmediateLosslessHalftoneRegion', null, null, null, null, null, null, null,
37781 null, null, null, null, null, 'IntermediateGenericRegion', null,
37782 'ImmediateGenericRegion', 'ImmediateLosslessGenericRegion',
37783 'IntermediateGenericRefinementRegion', null,
37784 'ImmediateGenericRefinementRegion',
37785 'ImmediateLosslessGenericRefinementRegion', null, null, null, null,
37786 'PageInformation', 'EndOfPage', 'EndOfStripe', 'EndOfFile', 'Profiles',
37787 'Tables', null, null, null, null, null, null, null, null,
37788 'Extension'
37789 ];
37790
37791 var CodingTemplates = [
37792 [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
37793 {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: 2, y: -1},
37794 {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
37795 [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: 2, y: -2},
37796 {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1},
37797 {x: 2, y: -1}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
37798 [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
37799 {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -2, y: 0},
37800 {x: -1, y: 0}],
37801 [{x: -3, y: -1}, {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1},
37802 {x: 1, y: -1}, {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}]
37803 ];
37804
37805 var RefinementTemplates = [
37806 {
37807 coding: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
37808 reference: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}, {x: 0, y: 0},
37809 {x: 1, y: 0}, {x: -1, y: 1}, {x: 0, y: 1}, {x: 1, y: 1}]
37810 },
37811 {
37812 coding: [{x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
37813 reference: [{x: 0, y: -1}, {x: -1, y: 0}, {x: 0, y: 0}, {x: 1, y: 0},
37814 {x: 0, y: 1}, {x: 1, y: 1}]
37815 }
37816 ];
37817
37818 // See 6.2.5.7 Decoding the bitmap.
37819 var ReusedContexts = [
37820 0x9B25, // 10011 0110010 0101
37821 0x0795, // 0011 110010 101
37822 0x00E5, // 001 11001 01
37823 0x0195 // 011001 0101
37824 ];
37825
37826 var RefinementReusedContexts = [
37827 0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)
37828 0x0008 // '0000' + '001000'
37829 ];
37830
37831 function decodeBitmapTemplate0(width, height, decodingContext) {
37832 var decoder = decodingContext.decoder;
37833 var contexts = decodingContext.contextCache.getContexts('GB');
37834 var contextLabel, i, j, pixel, row, row1, row2, bitmap = [];
37835
37836 // ...ooooo....
37837 // ..ooooooo... Context template for current pixel (X)
37838 // .ooooX...... (concatenate values of 'o'-pixels to get contextLabel)
37839 var OLD_PIXEL_MASK = 0x7BF7; // 01111 0111111 0111
37840
37841 for (i = 0; i < height; i++) {
37842 row = bitmap[i] = new Uint8Array(width);
37843 row1 = (i < 1) ? row : bitmap[i - 1];
37844 row2 = (i < 2) ? row : bitmap[i - 2];
37845
37846 // At the beginning of each row:
37847 // Fill contextLabel with pixels that are above/right of (X)
37848 contextLabel = (row2[0] << 13) | (row2[1] << 12) | (row2[2] << 11) |
37849 (row1[0] << 7) | (row1[1] << 6) | (row1[2] << 5) |
37850 (row1[3] << 4);
37851
37852 for (j = 0; j < width; j++) {
37853 row[j] = pixel = decoder.readBit(contexts, contextLabel);
37854
37855 // At each pixel: Clear contextLabel pixels that are shifted
37856 // out of the context, then add new ones.
37857 contextLabel = ((contextLabel & OLD_PIXEL_MASK) << 1) |
37858 (j + 3 < width ? row2[j + 3] << 11 : 0) |
37859 (j + 4 < width ? row1[j + 4] << 4 : 0) | pixel;
37860 }
37861 }
37862
37863 return bitmap;
37864 }
37865
37866 // 6.2 Generic Region Decoding Procedure
37867 function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
37868 decodingContext) {
37869 if (mmr) {
37870 error('JBIG2 error: MMR encoding is not supported');
37871 }
37872
37873 // Use optimized version for the most common case
37874 if (templateIndex === 0 && !skip && !prediction && at.length === 4 &&
37875 at[0].x === 3 && at[0].y === -1 && at[1].x === -3 && at[1].y === -1 &&
37876 at[2].x === 2 && at[2].y === -2 && at[3].x === -2 && at[3].y === -2) {
37877 return decodeBitmapTemplate0(width, height, decodingContext);
37878 }
37879
37880 var useskip = !!skip;
37881 var template = CodingTemplates[templateIndex].concat(at);
37882
37883 // Sorting is non-standard, and it is not required. But sorting increases
37884 // the number of template bits that can be reused from the previous
37885 // contextLabel in the main loop.
37886 template.sort(function (a, b) {
37887 return (a.y - b.y) || (a.x - b.x);
37888 });
37889
37890 var templateLength = template.length;
37891 var templateX = new Int8Array(templateLength);
37892 var templateY = new Int8Array(templateLength);
37893 var changingTemplateEntries = [];
37894 var reuseMask = 0, minX = 0, maxX = 0, minY = 0;
37895 var c, k;
37896
37897 for (k = 0; k < templateLength; k++) {
37898 templateX[k] = template[k].x;
37899 templateY[k] = template[k].y;
37900 minX = Math.min(minX, template[k].x);
37901 maxX = Math.max(maxX, template[k].x);
37902 minY = Math.min(minY, template[k].y);
37903 // Check if the template pixel appears in two consecutive context labels,
37904 // so it can be reused. Otherwise, we add it to the list of changing
37905 // template entries.
37906 if (k < templateLength - 1 &&
37907 template[k].y === template[k + 1].y &&
37908 template[k].x === template[k + 1].x - 1) {
37909 reuseMask |= 1 << (templateLength - 1 - k);
37910 } else {
37911 changingTemplateEntries.push(k);
37912 }
37913 }
37914 var changingEntriesLength = changingTemplateEntries.length;
37915
37916 var changingTemplateX = new Int8Array(changingEntriesLength);
37917 var changingTemplateY = new Int8Array(changingEntriesLength);
37918 var changingTemplateBit = new Uint16Array(changingEntriesLength);
37919 for (c = 0; c < changingEntriesLength; c++) {
37920 k = changingTemplateEntries[c];
37921 changingTemplateX[c] = template[k].x;
37922 changingTemplateY[c] = template[k].y;
37923 changingTemplateBit[c] = 1 << (templateLength - 1 - k);
37924 }
37925
37926 // Get the safe bounding box edges from the width, height, minX, maxX, minY
37927 var sbb_left = -minX;
37928 var sbb_top = -minY;
37929 var sbb_right = width - maxX;
37930
37931 var pseudoPixelContext = ReusedContexts[templateIndex];
37932 var row = new Uint8Array(width);
37933 var bitmap = [];
37934
37935 var decoder = decodingContext.decoder;
37936 var contexts = decodingContext.contextCache.getContexts('GB');
37937
37938 var ltp = 0, j, i0, j0, contextLabel = 0, bit, shift;
37939 for (var i = 0; i < height; i++) {
37940 if (prediction) {
37941 var sltp = decoder.readBit(contexts, pseudoPixelContext);
37942 ltp ^= sltp;
37943 if (ltp) {
37944 bitmap.push(row); // duplicate previous row
37945 continue;
37946 }
37947 }
37948 row = new Uint8Array(row);
37949 bitmap.push(row);
37950 for (j = 0; j < width; j++) {
37951 if (useskip && skip[i][j]) {
37952 row[j] = 0;
37953 continue;
37954 }
37955 // Are we in the middle of a scanline, so we can reuse contextLabel
37956 // bits?
37957 if (j >= sbb_left && j < sbb_right && i >= sbb_top) {
37958 // If yes, we can just shift the bits that are reusable and only
37959 // fetch the remaining ones.
37960 contextLabel = (contextLabel << 1) & reuseMask;
37961 for (k = 0; k < changingEntriesLength; k++) {
37962 i0 = i + changingTemplateY[k];
37963 j0 = j + changingTemplateX[k];
37964 bit = bitmap[i0][j0];
37965 if (bit) {
37966 bit = changingTemplateBit[k];
37967 contextLabel |= bit;
37968 }
37969 }
37970 } else {
37971 // compute the contextLabel from scratch
37972 contextLabel = 0;
37973 shift = templateLength - 1;
37974 for (k = 0; k < templateLength; k++, shift--) {
37975 j0 = j + templateX[k];
37976 if (j0 >= 0 && j0 < width) {
37977 i0 = i + templateY[k];
37978 if (i0 >= 0) {
37979 bit = bitmap[i0][j0];
37980 if (bit) {
37981 contextLabel |= bit << shift;
37982 }
37983 }
37984 }
37985 }
37986 }
37987 var pixel = decoder.readBit(contexts, contextLabel);
37988 row[j] = pixel;
37989 }
37990 }
37991 return bitmap;
37992 }
37993
37994 // 6.3.2 Generic Refinement Region Decoding Procedure
37995 function decodeRefinement(width, height, templateIndex, referenceBitmap,
37996 offsetX, offsetY, prediction, at,
37997 decodingContext) {
37998 var codingTemplate = RefinementTemplates[templateIndex].coding;
37999 if (templateIndex === 0) {
38000 codingTemplate = codingTemplate.concat([at[0]]);
38001 }
38002 var codingTemplateLength = codingTemplate.length;
38003 var codingTemplateX = new Int32Array(codingTemplateLength);
38004 var codingTemplateY = new Int32Array(codingTemplateLength);
38005 var k;
38006 for (k = 0; k < codingTemplateLength; k++) {
38007 codingTemplateX[k] = codingTemplate[k].x;
38008 codingTemplateY[k] = codingTemplate[k].y;
38009 }
38010
38011 var referenceTemplate = RefinementTemplates[templateIndex].reference;
38012 if (templateIndex === 0) {
38013 referenceTemplate = referenceTemplate.concat([at[1]]);
38014 }
38015 var referenceTemplateLength = referenceTemplate.length;
38016 var referenceTemplateX = new Int32Array(referenceTemplateLength);
38017 var referenceTemplateY = new Int32Array(referenceTemplateLength);
38018 for (k = 0; k < referenceTemplateLength; k++) {
38019 referenceTemplateX[k] = referenceTemplate[k].x;
38020 referenceTemplateY[k] = referenceTemplate[k].y;
38021 }
38022 var referenceWidth = referenceBitmap[0].length;
38023 var referenceHeight = referenceBitmap.length;
38024
38025 var pseudoPixelContext = RefinementReusedContexts[templateIndex];
38026 var bitmap = [];
38027
38028 var decoder = decodingContext.decoder;
38029 var contexts = decodingContext.contextCache.getContexts('GR');
38030
38031 var ltp = 0;
38032 for (var i = 0; i < height; i++) {
38033 if (prediction) {
38034 var sltp = decoder.readBit(contexts, pseudoPixelContext);
38035 ltp ^= sltp;
38036 if (ltp) {
38037 error('JBIG2 error: prediction is not supported');
38038 }
38039 }
38040 var row = new Uint8Array(width);
38041 bitmap.push(row);
38042 for (var j = 0; j < width; j++) {
38043 var i0, j0;
38044 var contextLabel = 0;
38045 for (k = 0; k < codingTemplateLength; k++) {
38046 i0 = i + codingTemplateY[k];
38047 j0 = j + codingTemplateX[k];
38048 if (i0 < 0 || j0 < 0 || j0 >= width) {
38049 contextLabel <<= 1; // out of bound pixel
38050 } else {
38051 contextLabel = (contextLabel << 1) | bitmap[i0][j0];
38052 }
38053 }
38054 for (k = 0; k < referenceTemplateLength; k++) {
38055 i0 = i + referenceTemplateY[k] + offsetY;
38056 j0 = j + referenceTemplateX[k] + offsetX;
38057 if (i0 < 0 || i0 >= referenceHeight || j0 < 0 ||
38058 j0 >= referenceWidth) {
38059 contextLabel <<= 1; // out of bound pixel
38060 } else {
38061 contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
38062 }
38063 }
38064 var pixel = decoder.readBit(contexts, contextLabel);
38065 row[j] = pixel;
38066 }
38067 }
38068
38069 return bitmap;
38070 }
38071
38072 // 6.5.5 Decoding the symbol dictionary
38073 function decodeSymbolDictionary(huffman, refinement, symbols,
38074 numberOfNewSymbols, numberOfExportedSymbols,
38075 huffmanTables, templateIndex, at,
38076 refinementTemplateIndex, refinementAt,
38077 decodingContext) {
38078 if (huffman) {
38079 error('JBIG2 error: huffman is not supported');
38080 }
38081
38082 var newSymbols = [];
38083 var currentHeight = 0;
38084 var symbolCodeLength = log2(symbols.length + numberOfNewSymbols);
38085
38086 var decoder = decodingContext.decoder;
38087 var contextCache = decodingContext.contextCache;
38088
38089 while (newSymbols.length < numberOfNewSymbols) {
38090 var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); // 6.5.6
38091 currentHeight += deltaHeight;
38092 var currentWidth = 0;
38093 var totalWidth = 0;
38094 while (true) {
38095 var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7
38096 if (deltaWidth === null) {
38097 break; // OOB
38098 }
38099 currentWidth += deltaWidth;
38100 totalWidth += currentWidth;
38101 var bitmap;
38102 if (refinement) {
38103 // 6.5.8.2 Refinement/aggregate-coded symbol bitmap
38104 var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);
38105 if (numberOfInstances > 1) {
38106 bitmap = decodeTextRegion(huffman, refinement,
38107 currentWidth, currentHeight, 0,
38108 numberOfInstances, 1, //strip size
38109 symbols.concat(newSymbols),
38110 symbolCodeLength,
38111 0, //transposed
38112 0, //ds offset
38113 1, //top left 7.4.3.1.1
38114 0, //OR operator
38115 huffmanTables,
38116 refinementTemplateIndex, refinementAt,
38117 decodingContext);
38118 } else {
38119 var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
38120 var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
38121 var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
38122 var symbol = (symbolId < symbols.length ? symbols[symbolId] :
38123 newSymbols[symbolId - symbols.length]);
38124 bitmap = decodeRefinement(currentWidth, currentHeight,
38125 refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,
38126 decodingContext);
38127 }
38128 } else {
38129 // 6.5.8.1 Direct-coded symbol bitmap
38130 bitmap = decodeBitmap(false, currentWidth, currentHeight,
38131 templateIndex, false, null, at, decodingContext);
38132 }
38133 newSymbols.push(bitmap);
38134 }
38135 }
38136 // 6.5.10 Exported symbols
38137 var exportedSymbols = [];
38138 var flags = [], currentFlag = false;
38139 var totalSymbolsLength = symbols.length + numberOfNewSymbols;
38140 while (flags.length < totalSymbolsLength) {
38141 var runLength = decodeInteger(contextCache, 'IAEX', decoder);
38142 while (runLength--) {
38143 flags.push(currentFlag);
38144 }
38145 currentFlag = !currentFlag;
38146 }
38147 for (var i = 0, ii = symbols.length; i < ii; i++) {
38148 if (flags[i]) {
38149 exportedSymbols.push(symbols[i]);
38150 }
38151 }
38152 for (var j = 0; j < numberOfNewSymbols; i++, j++) {
38153 if (flags[i]) {
38154 exportedSymbols.push(newSymbols[j]);
38155 }
38156 }
38157 return exportedSymbols;
38158 }
38159
38160 function decodeTextRegion(huffman, refinement, width, height,
38161 defaultPixelValue, numberOfSymbolInstances,
38162 stripSize, inputSymbols, symbolCodeLength,
38163 transposed, dsOffset, referenceCorner,
38164 combinationOperator, huffmanTables,
38165 refinementTemplateIndex, refinementAt,
38166 decodingContext) {
38167 if (huffman) {
38168 error('JBIG2 error: huffman is not supported');
38169 }
38170
38171 // Prepare bitmap
38172 var bitmap = [];
38173 var i, row;
38174 for (i = 0; i < height; i++) {
38175 row = new Uint8Array(width);
38176 if (defaultPixelValue) {
38177 for (var j = 0; j < width; j++) {
38178 row[j] = defaultPixelValue;
38179 }
38180 }
38181 bitmap.push(row);
38182 }
38183
38184 var decoder = decodingContext.decoder;
38185 var contextCache = decodingContext.contextCache;
38186 var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
38187 var firstS = 0;
38188 i = 0;
38189 while (i < numberOfSymbolInstances) {
38190 var deltaT = decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
38191 stripT += deltaT;
38192
38193 var deltaFirstS = decodeInteger(contextCache, 'IAFS', decoder); // 6.4.7
38194 firstS += deltaFirstS;
38195 var currentS = firstS;
38196 do {
38197 var currentT = (stripSize === 1 ? 0 :
38198 decodeInteger(contextCache, 'IAIT', decoder)); // 6.4.9
38199 var t = stripSize * stripT + currentT;
38200 var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
38201 var applyRefinement = (refinement &&
38202 decodeInteger(contextCache, 'IARI', decoder));
38203 var symbolBitmap = inputSymbols[symbolId];
38204 var symbolWidth = symbolBitmap[0].length;
38205 var symbolHeight = symbolBitmap.length;
38206 if (applyRefinement) {
38207 var rdw = decodeInteger(contextCache, 'IARDW', decoder); // 6.4.11.1
38208 var rdh = decodeInteger(contextCache, 'IARDH', decoder); // 6.4.11.2
38209 var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
38210 var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
38211 symbolWidth += rdw;
38212 symbolHeight += rdh;
38213 symbolBitmap = decodeRefinement(symbolWidth, symbolHeight,
38214 refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx,
38215 (rdh >> 1) + rdy, false, refinementAt,
38216 decodingContext);
38217 }
38218 var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);
38219 var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);
38220 var s2, t2, symbolRow;
38221 if (transposed) {
38222 // Place Symbol Bitmap from T1,S1
38223 for (s2 = 0; s2 < symbolHeight; s2++) {
38224 row = bitmap[offsetS + s2];
38225 if (!row) {
38226 continue;
38227 }
38228 symbolRow = symbolBitmap[s2];
38229 // To ignore Parts of Symbol bitmap which goes
38230 // outside bitmap region
38231 var maxWidth = Math.min(width - offsetT, symbolWidth);
38232 switch (combinationOperator) {
38233 case 0: // OR
38234 for (t2 = 0; t2 < maxWidth; t2++) {
38235 row[offsetT + t2] |= symbolRow[t2];
38236 }
38237 break;
38238 case 2: // XOR
38239 for (t2 = 0; t2 < maxWidth; t2++) {
38240 row[offsetT + t2] ^= symbolRow[t2];
38241 }
38242 break;
38243 default:
38244 error('JBIG2 error: operator ' + combinationOperator +
38245 ' is not supported');
38246 }
38247 }
38248 currentS += symbolHeight - 1;
38249 } else {
38250 for (t2 = 0; t2 < symbolHeight; t2++) {
38251 row = bitmap[offsetT + t2];
38252 if (!row) {
38253 continue;
38254 }
38255 symbolRow = symbolBitmap[t2];
38256 switch (combinationOperator) {
38257 case 0: // OR
38258 for (s2 = 0; s2 < symbolWidth; s2++) {
38259 row[offsetS + s2] |= symbolRow[s2];
38260 }
38261 break;
38262 case 2: // XOR
38263 for (s2 = 0; s2 < symbolWidth; s2++) {
38264 row[offsetS + s2] ^= symbolRow[s2];
38265 }
38266 break;
38267 default:
38268 error('JBIG2 error: operator ' + combinationOperator +
38269 ' is not supported');
38270 }
38271 }
38272 currentS += symbolWidth - 1;
38273 }
38274 i++;
38275 var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8
38276 if (deltaS === null) {
38277 break; // OOB
38278 }
38279 currentS += deltaS + dsOffset;
38280 } while (true);
38281 }
38282 return bitmap;
38283 }
38284
38285 function readSegmentHeader(data, start) {
38286 var segmentHeader = {};
38287 segmentHeader.number = readUint32(data, start);
38288 var flags = data[start + 4];
38289 var segmentType = flags & 0x3F;
38290 if (!SegmentTypes[segmentType]) {
38291 error('JBIG2 error: invalid segment type: ' + segmentType);
38292 }
38293 segmentHeader.type = segmentType;
38294 segmentHeader.typeName = SegmentTypes[segmentType];
38295 segmentHeader.deferredNonRetain = !!(flags & 0x80);
38296
38297 var pageAssociationFieldSize = !!(flags & 0x40);
38298 var referredFlags = data[start + 5];
38299 var referredToCount = (referredFlags >> 5) & 7;
38300 var retainBits = [referredFlags & 31];
38301 var position = start + 6;
38302 if (referredFlags === 7) {
38303 referredToCount = readUint32(data, position - 1) & 0x1FFFFFFF;
38304 position += 3;
38305 var bytes = (referredToCount + 7) >> 3;
38306 retainBits[0] = data[position++];
38307 while (--bytes > 0) {
38308 retainBits.push(data[position++]);
38309 }
38310 } else if (referredFlags === 5 || referredFlags === 6) {
38311 error('JBIG2 error: invalid referred-to flags');
38312 }
38313
38314 segmentHeader.retainBits = retainBits;
38315 var referredToSegmentNumberSize = (segmentHeader.number <= 256 ? 1 :
38316 (segmentHeader.number <= 65536 ? 2 : 4));
38317 var referredTo = [];
38318 var i, ii;
38319 for (i = 0; i < referredToCount; i++) {
38320 var number = (referredToSegmentNumberSize === 1 ? data[position] :
38321 (referredToSegmentNumberSize === 2 ? readUint16(data, position) :
38322 readUint32(data, position)));
38323 referredTo.push(number);
38324 position += referredToSegmentNumberSize;
38325 }
38326 segmentHeader.referredTo = referredTo;
38327 if (!pageAssociationFieldSize) {
38328 segmentHeader.pageAssociation = data[position++];
38329 } else {
38330 segmentHeader.pageAssociation = readUint32(data, position);
38331 position += 4;
38332 }
38333 segmentHeader.length = readUint32(data, position);
38334 position += 4;
38335
38336 if (segmentHeader.length === 0xFFFFFFFF) {
38337 // 7.2.7 Segment data length, unknown segment length
38338 if (segmentType === 38) { // ImmediateGenericRegion
38339 var genericRegionInfo = readRegionSegmentInformation(data, position);
38340 var genericRegionSegmentFlags = data[position +
38341 RegionSegmentInformationFieldLength];
38342 var genericRegionMmr = !!(genericRegionSegmentFlags & 1);
38343 // searching for the segment end
38344 var searchPatternLength = 6;
38345 var searchPattern = new Uint8Array(searchPatternLength);
38346 if (!genericRegionMmr) {
38347 searchPattern[0] = 0xFF;
38348 searchPattern[1] = 0xAC;
38349 }
38350 searchPattern[2] = (genericRegionInfo.height >>> 24) & 0xFF;
38351 searchPattern[3] = (genericRegionInfo.height >> 16) & 0xFF;
38352 searchPattern[4] = (genericRegionInfo.height >> 8) & 0xFF;
38353 searchPattern[5] = genericRegionInfo.height & 0xFF;
38354 for (i = position, ii = data.length; i < ii; i++) {
38355 var j = 0;
38356 while (j < searchPatternLength && searchPattern[j] === data[i + j]) {
38357 j++;
38358 }
38359 if (j === searchPatternLength) {
38360 segmentHeader.length = i + searchPatternLength;
38361 break;
38362 }
38363 }
38364 if (segmentHeader.length === 0xFFFFFFFF) {
38365 error('JBIG2 error: segment end was not found');
38366 }
38367 } else {
38368 error('JBIG2 error: invalid unknown segment length');
38369 }
38370 }
38371 segmentHeader.headerEnd = position;
38372 return segmentHeader;
38373 }
38374
38375 function readSegments(header, data, start, end) {
38376 var segments = [];
38377 var position = start;
38378 while (position < end) {
38379 var segmentHeader = readSegmentHeader(data, position);
38380 position = segmentHeader.headerEnd;
38381 var segment = {
38382 header: segmentHeader,
38383 data: data
38384 };
38385 if (!header.randomAccess) {
38386 segment.start = position;
38387 position += segmentHeader.length;
38388 segment.end = position;
38389 }
38390 segments.push(segment);
38391 if (segmentHeader.type === 51) {
38392 break; // end of file is found
38393 }
38394 }
38395 if (header.randomAccess) {
38396 for (var i = 0, ii = segments.length; i < ii; i++) {
38397 segments[i].start = position;
38398 position += segments[i].header.length;
38399 segments[i].end = position;
38400 }
38401 }
38402 return segments;
38403 }
38404
38405 // 7.4.1 Region segment information field
38406 function readRegionSegmentInformation(data, start) {
38407 return {
38408 width: readUint32(data, start),
38409 height: readUint32(data, start + 4),
38410 x: readUint32(data, start + 8),
38411 y: readUint32(data, start + 12),
38412 combinationOperator: data[start + 16] & 7
38413 };
38414 }
38415 var RegionSegmentInformationFieldLength = 17;
38416
38417 function processSegment(segment, visitor) {
38418 var header = segment.header;
38419
38420 var data = segment.data, position = segment.start, end = segment.end;
38421 var args, at, i, atLength;
38422 switch (header.type) {
38423 case 0: // SymbolDictionary
38424 // 7.4.2 Symbol dictionary segment syntax
38425 var dictionary = {};
38426 var dictionaryFlags = readUint16(data, position); // 7.4.2.1.1
38427 dictionary.huffman = !!(dictionaryFlags & 1);
38428 dictionary.refinement = !!(dictionaryFlags & 2);
38429 dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3;
38430 dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3;
38431 dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1;
38432 dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1;
38433 dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256);
38434 dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512);
38435 dictionary.template = (dictionaryFlags >> 10) & 3;
38436 dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;
38437 position += 2;
38438 if (!dictionary.huffman) {
38439 atLength = dictionary.template === 0 ? 4 : 1;
38440 at = [];
38441 for (i = 0; i < atLength; i++) {
38442 at.push({
38443 x: readInt8(data, position),
38444 y: readInt8(data, position + 1)
38445 });
38446 position += 2;
38447 }
38448 dictionary.at = at;
38449 }
38450 if (dictionary.refinement && !dictionary.refinementTemplate) {
38451 at = [];
38452 for (i = 0; i < 2; i++) {
38453 at.push({
38454 x: readInt8(data, position),
38455 y: readInt8(data, position + 1)
38456 });
38457 position += 2;
38458 }
38459 dictionary.refinementAt = at;
38460 }
38461 dictionary.numberOfExportedSymbols = readUint32(data, position);
38462 position += 4;
38463 dictionary.numberOfNewSymbols = readUint32(data, position);
38464 position += 4;
38465 args = [dictionary, header.number, header.referredTo,
38466 data, position, end];
38467 break;
38468 case 6: // ImmediateTextRegion
38469 case 7: // ImmediateLosslessTextRegion
38470 var textRegion = {};
38471 textRegion.info = readRegionSegmentInformation(data, position);
38472 position += RegionSegmentInformationFieldLength;
38473 var textRegionSegmentFlags = readUint16(data, position);
38474 position += 2;
38475 textRegion.huffman = !!(textRegionSegmentFlags & 1);
38476 textRegion.refinement = !!(textRegionSegmentFlags & 2);
38477 textRegion.stripSize = 1 << ((textRegionSegmentFlags >> 2) & 3);
38478 textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3;
38479 textRegion.transposed = !!(textRegionSegmentFlags & 64);
38480 textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3;
38481 textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1;
38482 textRegion.dsOffset = (textRegionSegmentFlags << 17) >> 27;
38483 textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1;
38484 if (textRegion.huffman) {
38485 var textRegionHuffmanFlags = readUint16(data, position);
38486 position += 2;
38487 textRegion.huffmanFS = (textRegionHuffmanFlags) & 3;
38488 textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3;
38489 textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3;
38490 textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3;
38491 textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3;
38492 textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3;
38493 textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3;
38494 textRegion.huffmanRefinementSizeSelector =
38495 !!(textRegionHuffmanFlags & 14);
38496 }
38497 if (textRegion.refinement && !textRegion.refinementTemplate) {
38498 at = [];
38499 for (i = 0; i < 2; i++) {
38500 at.push({
38501 x: readInt8(data, position),
38502 y: readInt8(data, position + 1)
38503 });
38504 position += 2;
38505 }
38506 textRegion.refinementAt = at;
38507 }
38508 textRegion.numberOfSymbolInstances = readUint32(data, position);
38509 position += 4;
38510 // TODO 7.4.3.1.7 Symbol ID Huffman table decoding
38511 if (textRegion.huffman) {
38512 error('JBIG2 error: huffman is not supported');
38513 }
38514 args = [textRegion, header.referredTo, data, position, end];
38515 break;
38516 case 38: // ImmediateGenericRegion
38517 case 39: // ImmediateLosslessGenericRegion
38518 var genericRegion = {};
38519 genericRegion.info = readRegionSegmentInformation(data, position);
38520 position += RegionSegmentInformationFieldLength;
38521 var genericRegionSegmentFlags = data[position++];
38522 genericRegion.mmr = !!(genericRegionSegmentFlags & 1);
38523 genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;
38524 genericRegion.prediction = !!(genericRegionSegmentFlags & 8);
38525 if (!genericRegion.mmr) {
38526 atLength = genericRegion.template === 0 ? 4 : 1;
38527 at = [];
38528 for (i = 0; i < atLength; i++) {
38529 at.push({
38530 x: readInt8(data, position),
38531 y: readInt8(data, position + 1)
38532 });
38533 position += 2;
38534 }
38535 genericRegion.at = at;
38536 }
38537 args = [genericRegion, data, position, end];
38538 break;
38539 case 48: // PageInformation
38540 var pageInfo = {
38541 width: readUint32(data, position),
38542 height: readUint32(data, position + 4),
38543 resolutionX: readUint32(data, position + 8),
38544 resolutionY: readUint32(data, position + 12)
38545 };
38546 if (pageInfo.height === 0xFFFFFFFF) {
38547 delete pageInfo.height;
38548 }
38549 var pageSegmentFlags = data[position + 16];
38550 var pageStripingInformatiom = readUint16(data, position + 17);
38551 pageInfo.lossless = !!(pageSegmentFlags & 1);
38552 pageInfo.refinement = !!(pageSegmentFlags & 2);
38553 pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1;
38554 pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3;
38555 pageInfo.requiresBuffer = !!(pageSegmentFlags & 32);
38556 pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64);
38557 args = [pageInfo];
38558 break;
38559 case 49: // EndOfPage
38560 break;
38561 case 50: // EndOfStripe
38562 break;
38563 case 51: // EndOfFile
38564 break;
38565 case 62: // 7.4.15 defines 2 extension types which
38566 // are comments and can be ignored.
38567 break;
38568 default:
38569 error('JBIG2 error: segment type ' + header.typeName + '(' +
38570 header.type + ') is not implemented');
38571 }
38572 var callbackName = 'on' + header.typeName;
38573 if (callbackName in visitor) {
38574 visitor[callbackName].apply(visitor, args);
38575 }
38576 }
38577
38578 function processSegments(segments, visitor) {
38579 for (var i = 0, ii = segments.length; i < ii; i++) {
38580 processSegment(segments[i], visitor);
38581 }
38582 }
38583
38584 function parseJbig2(data, start, end) {
38585 var position = start;
38586 if (data[position] !== 0x97 || data[position + 1] !== 0x4A ||
38587 data[position + 2] !== 0x42 || data[position + 3] !== 0x32 ||
38588 data[position + 4] !== 0x0D || data[position + 5] !== 0x0A ||
38589 data[position + 6] !== 0x1A || data[position + 7] !== 0x0A) {
38590 error('JBIG2 error: invalid header');
38591 }
38592 var header = {};
38593 position += 8;
38594 var flags = data[position++];
38595 header.randomAccess = !(flags & 1);
38596 if (!(flags & 2)) {
38597 header.numberOfPages = readUint32(data, position);
38598 position += 4;
38599 }
38600 var segments = readSegments(header, data, position, end);
38601 error('Not implemented');
38602 // processSegments(segments, new SimpleSegmentVisitor());
38603 }
38604
38605 function parseJbig2Chunks(chunks) {
38606 var visitor = new SimpleSegmentVisitor();
38607 for (var i = 0, ii = chunks.length; i < ii; i++) {
38608 var chunk = chunks[i];
38609 var segments = readSegments({}, chunk.data, chunk.start, chunk.end);
38610 processSegments(segments, visitor);
38611 }
38612 return visitor.buffer;
38613 }
38614
38615 function SimpleSegmentVisitor() {}
38616
38617 SimpleSegmentVisitor.prototype = {
38618 onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) {
38619 this.currentPageInfo = info;
38620 var rowSize = (info.width + 7) >> 3;
38621 var buffer = new Uint8Array(rowSize * info.height);
38622 // The contents of ArrayBuffers are initialized to 0.
38623 // Fill the buffer with 0xFF only if info.defaultPixelValue is set
38624 if (info.defaultPixelValue) {
38625 for (var i = 0, ii = buffer.length; i < ii; i++) {
38626 buffer[i] = 0xFF;
38627 }
38628 }
38629 this.buffer = buffer;
38630 },
38631 drawBitmap: function SimpleSegmentVisitor_drawBitmap(regionInfo, bitmap) {
38632 var pageInfo = this.currentPageInfo;
38633 var width = regionInfo.width, height = regionInfo.height;
38634 var rowSize = (pageInfo.width + 7) >> 3;
38635 var combinationOperator = pageInfo.combinationOperatorOverride ?
38636 regionInfo.combinationOperator : pageInfo.combinationOperator;
38637 var buffer = this.buffer;
38638 var mask0 = 128 >> (regionInfo.x & 7);
38639 var offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3);
38640 var i, j, mask, offset;
38641 switch (combinationOperator) {
38642 case 0: // OR
38643 for (i = 0; i < height; i++) {
38644 mask = mask0;
38645 offset = offset0;
38646 for (j = 0; j < width; j++) {
38647 if (bitmap[i][j]) {
38648 buffer[offset] |= mask;
38649 }
38650 mask >>= 1;
38651 if (!mask) {
38652 mask = 128;
38653 offset++;
38654 }
38655 }
38656 offset0 += rowSize;
38657 }
38658 break;
38659 case 2: // XOR
38660 for (i = 0; i < height; i++) {
38661 mask = mask0;
38662 offset = offset0;
38663 for (j = 0; j < width; j++) {
38664 if (bitmap[i][j]) {
38665 buffer[offset] ^= mask;
38666 }
38667 mask >>= 1;
38668 if (!mask) {
38669 mask = 128;
38670 offset++;
38671 }
38672 }
38673 offset0 += rowSize;
38674 }
38675 break;
38676 default:
38677 error('JBIG2 error: operator ' + combinationOperator +
38678 ' is not supported');
38679 }
38680 },
38681 onImmediateGenericRegion:
38682 function SimpleSegmentVisitor_onImmediateGenericRegion(region, data,
38683 start, end) {
38684 var regionInfo = region.info;
38685 var decodingContext = new DecodingContext(data, start, end);
38686 var bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height,
38687 region.template, region.prediction, null,
38688 region.at, decodingContext);
38689 this.drawBitmap(regionInfo, bitmap);
38690 },
38691 onImmediateLosslessGenericRegion:
38692 function SimpleSegmentVisitor_onImmediateLosslessGenericRegion() {
38693 this.onImmediateGenericRegion.apply(this, arguments);
38694 },
38695 onSymbolDictionary:
38696 function SimpleSegmentVisitor_onSymbolDictionary(dictionary,
38697 currentSegment,
38698 referredSegments,
38699 data, start, end) {
38700 var huffmanTables;
38701 if (dictionary.huffman) {
38702 error('JBIG2 error: huffman is not supported');
38703 }
38704
38705 // Combines exported symbols from all referred segments
38706 var symbols = this.symbols;
38707 if (!symbols) {
38708 this.symbols = symbols = {};
38709 }
38710
38711 var inputSymbols = [];
38712 for (var i = 0, ii = referredSegments.length; i < ii; i++) {
38713 inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
38714 }
38715
38716 var decodingContext = new DecodingContext(data, start, end);
38717 symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman,
38718 dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols,
38719 dictionary.numberOfExportedSymbols, huffmanTables,
38720 dictionary.template, dictionary.at,
38721 dictionary.refinementTemplate, dictionary.refinementAt,
38722 decodingContext);
38723 },
38724 onImmediateTextRegion:
38725 function SimpleSegmentVisitor_onImmediateTextRegion(region,
38726 referredSegments,
38727 data, start, end) {
38728 var regionInfo = region.info;
38729 var huffmanTables;
38730
38731 // Combines exported symbols from all referred segments
38732 var symbols = this.symbols;
38733 var inputSymbols = [];
38734 for (var i = 0, ii = referredSegments.length; i < ii; i++) {
38735 inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
38736 }
38737 var symbolCodeLength = log2(inputSymbols.length);
38738
38739 var decodingContext = new DecodingContext(data, start, end);
38740 var bitmap = decodeTextRegion(region.huffman, region.refinement,
38741 regionInfo.width, regionInfo.height, region.defaultPixelValue,
38742 region.numberOfSymbolInstances, region.stripSize, inputSymbols,
38743 symbolCodeLength, region.transposed, region.dsOffset,
38744 region.referenceCorner, region.combinationOperator, huffmanTables,
38745 region.refinementTemplate, region.refinementAt, decodingContext);
38746 this.drawBitmap(regionInfo, bitmap);
38747 },
38748 onImmediateLosslessTextRegion:
38749 function SimpleSegmentVisitor_onImmediateLosslessTextRegion() {
38750 this.onImmediateTextRegion.apply(this, arguments);
38751 }
38752 };
38753
38754 function Jbig2Image() {}
38755
38756 Jbig2Image.prototype = {
38757 parseChunks: function Jbig2Image_parseChunks(chunks) {
38758 return parseJbig2Chunks(chunks);
38759 }
38760 };
38761
38762 return Jbig2Image;
38763 })();
38764
38765
38766 var bidi = PDFJS.bidi = (function bidiClosure() {
38767 // Character types for symbols from 0000 to 00FF.
38768 var baseTypes = [
38769 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S', 'WS',
38770 'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
38771 'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET', 'ET', 'ET', 'ON',
38772 'ON', 'ON', 'ON', 'ON', 'ON', 'CS', 'ON', 'CS', 'ON', 'EN', 'EN', 'EN',
38773 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'ON', 'ON', 'ON', 'ON', 'ON',
38774 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38775 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON',
38776 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38777 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38778 'L', 'ON', 'ON', 'ON', 'ON', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN',
38779 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
38780 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
38781 'BN', 'CS', 'ON', 'ET', 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON',
38782 'ON', 'ON', 'ON', 'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON',
38783 'EN', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38784 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38785 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38786 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
38787 'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
38788 ];
38789
38790 // Character types for symbols from 0600 to 06FF
38791 var arabicTypes = [
38792 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38793 'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL',
38794 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38795 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38796 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38797 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38798 'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
38799 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL',
38800 'AL', 'AL', 'AL', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN',
38801 'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL', 'AL', 'AL',
38802 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38803 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38804 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38805 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38806 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38807 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38808 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38809 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38810 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
38811 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'ON', 'NSM',
38812 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
38813 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL'
38814 ];
38815
38816 function isOdd(i) {
38817 return (i & 1) !== 0;
38818 }
38819
38820 function isEven(i) {
38821 return (i & 1) === 0;
38822 }
38823
38824 function findUnequal(arr, start, value) {
38825 for (var j = start, jj = arr.length; j < jj; ++j) {
38826 if (arr[j] !== value) {
38827 return j;
38828 }
38829 }
38830 return j;
38831 }
38832
38833 function setValues(arr, start, end, value) {
38834 for (var j = start; j < end; ++j) {
38835 arr[j] = value;
38836 }
38837 }
38838
38839 function reverseValues(arr, start, end) {
38840 for (var i = start, j = end - 1; i < j; ++i, --j) {
38841 var temp = arr[i];
38842 arr[i] = arr[j];
38843 arr[j] = temp;
38844 }
38845 }
38846
38847 function createBidiText(str, isLTR, vertical) {
38848 return {
38849 str: str,
38850 dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl'))
38851 };
38852 }
38853
38854 // These are used in bidi(), which is called frequently. We re-use them on
38855 // each call to avoid unnecessary allocations.
38856 var chars = [];
38857 var types = [];
38858
38859 function bidi(str, startLevel, vertical) {
38860 var isLTR = true;
38861 var strLength = str.length;
38862 if (strLength === 0 || vertical) {
38863 return createBidiText(str, isLTR, vertical);
38864 }
38865
38866 // Get types and fill arrays
38867 chars.length = strLength;
38868 types.length = strLength;
38869 var numBidi = 0;
38870
38871 var i, ii;
38872 for (i = 0; i < strLength; ++i) {
38873 chars[i] = str.charAt(i);
38874
38875 var charCode = str.charCodeAt(i);
38876 var charType = 'L';
38877 if (charCode <= 0x00ff) {
38878 charType = baseTypes[charCode];
38879 } else if (0x0590 <= charCode && charCode <= 0x05f4) {
38880 charType = 'R';
38881 } else if (0x0600 <= charCode && charCode <= 0x06ff) {
38882 charType = arabicTypes[charCode & 0xff];
38883 } else if (0x0700 <= charCode && charCode <= 0x08AC) {
38884 charType = 'AL';
38885 }
38886 if (charType === 'R' || charType === 'AL' || charType === 'AN') {
38887 numBidi++;
38888 }
38889 types[i] = charType;
38890 }
38891
38892 // Detect the bidi method
38893 // - If there are no rtl characters then no bidi needed
38894 // - If less than 30% chars are rtl then string is primarily ltr
38895 // - If more than 30% chars are rtl then string is primarily rtl
38896 if (numBidi === 0) {
38897 isLTR = true;
38898 return createBidiText(str, isLTR);
38899 }
38900
38901 if (startLevel === -1) {
38902 if ((strLength / numBidi) < 0.3) {
38903 isLTR = true;
38904 startLevel = 0;
38905 } else {
38906 isLTR = false;
38907 startLevel = 1;
38908 }
38909 }
38910
38911 var levels = [];
38912 for (i = 0; i < strLength; ++i) {
38913 levels[i] = startLevel;
38914 }
38915
38916 /*
38917 X1-X10: skip most of this, since we are NOT doing the embeddings.
38918 */
38919 var e = (isOdd(startLevel) ? 'R' : 'L');
38920 var sor = e;
38921 var eor = sor;
38922
38923 /*
38924 W1. Examine each non-spacing mark (NSM) in the level run, and change the
38925 type of the NSM to the type of the previous character. If the NSM is at the
38926 start of the level run, it will get the type of sor.
38927 */
38928 var lastType = sor;
38929 for (i = 0; i < strLength; ++i) {
38930 if (types[i] === 'NSM') {
38931 types[i] = lastType;
38932 } else {
38933 lastType = types[i];
38934 }
38935 }
38936
38937 /*
38938 W2. Search backwards from each instance of a European number until the
38939 first strong type (R, L, AL, or sor) is found. If an AL is found, change
38940 the type of the European number to Arabic number.
38941 */
38942 lastType = sor;
38943 var t;
38944 for (i = 0; i < strLength; ++i) {
38945 t = types[i];
38946 if (t === 'EN') {
38947 types[i] = (lastType === 'AL') ? 'AN' : 'EN';
38948 } else if (t === 'R' || t === 'L' || t === 'AL') {
38949 lastType = t;
38950 }
38951 }
38952
38953 /*
38954 W3. Change all ALs to R.
38955 */
38956 for (i = 0; i < strLength; ++i) {
38957 t = types[i];
38958 if (t === 'AL') {
38959 types[i] = 'R';
38960 }
38961 }
38962
38963 /*
38964 W4. A single European separator between two European numbers changes to a
38965 European number. A single common separator between two numbers of the same
38966 type changes to that type:
38967 */
38968 for (i = 1; i < strLength - 1; ++i) {
38969 if (types[i] === 'ES' && types[i - 1] === 'EN' && types[i + 1] === 'EN') {
38970 types[i] = 'EN';
38971 }
38972 if (types[i] === 'CS' &&
38973 (types[i - 1] === 'EN' || types[i - 1] === 'AN') &&
38974 types[i + 1] === types[i - 1]) {
38975 types[i] = types[i - 1];
38976 }
38977 }
38978
38979 /*
38980 W5. A sequence of European terminators adjacent to European numbers changes
38981 to all European numbers:
38982 */
38983 for (i = 0; i < strLength; ++i) {
38984 if (types[i] === 'EN') {
38985 // do before
38986 var j;
38987 for (j = i - 1; j >= 0; --j) {
38988 if (types[j] !== 'ET') {
38989 break;
38990 }
38991 types[j] = 'EN';
38992 }
38993 // do after
38994 for (j = i + 1; j < strLength; --j) {
38995 if (types[j] !== 'ET') {
38996 break;
38997 }
38998 types[j] = 'EN';
38999 }
39000 }
39001 }
39002
39003 /*
39004 W6. Otherwise, separators and terminators change to Other Neutral:
39005 */
39006 for (i = 0; i < strLength; ++i) {
39007 t = types[i];
39008 if (t === 'WS' || t === 'ES' || t === 'ET' || t === 'CS') {
39009 types[i] = 'ON';
39010 }
39011 }
39012
39013 /*
39014 W7. Search backwards from each instance of a European number until the
39015 first strong type (R, L, or sor) is found. If an L is found, then change
39016 the type of the European number to L.
39017 */
39018 lastType = sor;
39019 for (i = 0; i < strLength; ++i) {
39020 t = types[i];
39021 if (t === 'EN') {
39022 types[i] = ((lastType === 'L') ? 'L' : 'EN');
39023 } else if (t === 'R' || t === 'L') {
39024 lastType = t;
39025 }
39026 }
39027
39028 /*
39029 N1. A sequence of neutrals takes the direction of the surrounding strong
39030 text if the text on both sides has the same direction. European and Arabic
39031 numbers are treated as though they were R. Start-of-level-run (sor) and
39032 end-of-level-run (eor) are used at level run boundaries.
39033 */
39034 for (i = 0; i < strLength; ++i) {
39035 if (types[i] === 'ON') {
39036 var end = findUnequal(types, i + 1, 'ON');
39037 var before = sor;
39038 if (i > 0) {
39039 before = types[i - 1];
39040 }
39041
39042 var after = eor;
39043 if (end + 1 < strLength) {
39044 after = types[end + 1];
39045 }
39046 if (before !== 'L') {
39047 before = 'R';
39048 }
39049 if (after !== 'L') {
39050 after = 'R';
39051 }
39052 if (before === after) {
39053 setValues(types, i, end, before);
39054 }
39055 i = end - 1; // reset to end (-1 so next iteration is ok)
39056 }
39057 }
39058
39059 /*
39060 N2. Any remaining neutrals take the embedding direction.
39061 */
39062 for (i = 0; i < strLength; ++i) {
39063 if (types[i] === 'ON') {
39064 types[i] = e;
39065 }
39066 }
39067
39068 /*
39069 I1. For all characters with an even (left-to-right) embedding direction,
39070 those of type R go up one level and those of type AN or EN go up two
39071 levels.
39072 I2. For all characters with an odd (right-to-left) embedding direction,
39073 those of type L, EN or AN go up one level.
39074 */
39075 for (i = 0; i < strLength; ++i) {
39076 t = types[i];
39077 if (isEven(levels[i])) {
39078 if (t === 'R') {
39079 levels[i] += 1;
39080 } else if (t === 'AN' || t === 'EN') {
39081 levels[i] += 2;
39082 }
39083 } else { // isOdd
39084 if (t === 'L' || t === 'AN' || t === 'EN') {
39085 levels[i] += 1;
39086 }
39087 }
39088 }
39089
39090 /*
39091 L1. On each line, reset the embedding level of the following characters to
39092 the paragraph embedding level:
39093
39094 segment separators,
39095 paragraph separators,
39096 any sequence of whitespace characters preceding a segment separator or
39097 paragraph separator, and any sequence of white space characters at the end
39098 of the line.
39099 */
39100
39101 // don't bother as text is only single line
39102
39103 /*
39104 L2. From the highest level found in the text to the lowest odd level on
39105 each line, reverse any contiguous sequence of characters that are at that
39106 level or higher.
39107 */
39108
39109 // find highest level & lowest odd level
39110 var highestLevel = -1;
39111 var lowestOddLevel = 99;
39112 var level;
39113 for (i = 0, ii = levels.length; i < ii; ++i) {
39114 level = levels[i];
39115 if (highestLevel < level) {
39116 highestLevel = level;
39117 }
39118 if (lowestOddLevel > level && isOdd(level)) {
39119 lowestOddLevel = level;
39120 }
39121 }
39122
39123 // now reverse between those limits
39124 for (level = highestLevel; level >= lowestOddLevel; --level) {
39125 // find segments to reverse
39126 var start = -1;
39127 for (i = 0, ii = levels.length; i < ii; ++i) {
39128 if (levels[i] < level) {
39129 if (start >= 0) {
39130 reverseValues(chars, start, i);
39131 start = -1;
39132 }
39133 } else if (start < 0) {
39134 start = i;
39135 }
39136 }
39137 if (start >= 0) {
39138 reverseValues(chars, start, levels.length);
39139 }
39140 }
39141
39142 /*
39143 L3. Combining marks applied to a right-to-left base character will at this
39144 point precede their base character. If the rendering engine expects them to
39145 follow the base characters in the final display process, then the ordering
39146 of the marks and the base character must be reversed.
39147 */
39148
39149 // don't bother for now
39150
39151 /*
39152 L4. A character that possesses the mirrored property as specified by
39153 Section 4.7, Mirrored, must be depicted by a mirrored glyph if the resolved
39154 directionality of that character is R.
39155 */
39156
39157 // don't mirror as characters are already mirrored in the pdf
39158
39159 // Finally, return string
39160 var result = '';
39161 for (i = 0, ii = chars.length; i < ii; ++i) {
39162 var ch = chars[i];
39163 if (ch !== '<' && ch !== '>') {
39164 result += ch;
39165 }
39166 }
39167 return createBidiText(result, isLTR);
39168 }
39169
39170 return bidi;
39171 })();
39172
39173 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
39174 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
39175
39176 /* Copyright 2014 Opera Software ASA
39177 *
39178 * Licensed under the Apache License, Version 2.0 (the "License");
39179 * you may not use this file except in compliance with the License.
39180 * You may obtain a copy of the License at
39181 *
39182 * http://www.apache.org/licenses/LICENSE-2.0
39183 *
39184 * Unless required by applicable law or agreed to in writing, software
39185 * distributed under the License is distributed on an "AS IS" BASIS,
39186 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39187 * See the License for the specific language governing permissions and
39188 * limitations under the License.
39189 *
39190 *
39191 * Based on https://code.google.com/p/smhasher/wiki/MurmurHash3.
39192 * Hashes roughly 100 KB per millisecond on i7 3.4 GHz.
39193 */
39194 /* globals Uint32ArrayView */
39195
39196 'use strict';
39197
39198 var MurmurHash3_64 = (function MurmurHash3_64Closure (seed) {
39199 // Workaround for missing math precison in JS.
39200 var MASK_HIGH = 0xffff0000;
39201 var MASK_LOW = 0xffff;
39202
39203 function MurmurHash3_64 (seed) {
39204 var SEED = 0xc3d2e1f0;
39205 this.h1 = seed ? seed & 0xffffffff : SEED;
39206 this.h2 = seed ? seed & 0xffffffff : SEED;
39207 }
39208
39209 var alwaysUseUint32ArrayView = false;
39210 //#if !(FIREFOX || MOZCENTRAL || B2G || CHROME)
39211 // old webkits have issues with non-aligned arrays
39212 try {
39213 new Uint32Array(new Uint8Array(5).buffer, 0, 1);
39214 } catch (e) {
39215 alwaysUseUint32ArrayView = true;
39216 }
39217 //#endif
39218
39219 MurmurHash3_64.prototype = {
39220 update: function MurmurHash3_64_update(input) {
39221 var useUint32ArrayView = alwaysUseUint32ArrayView;
39222 var i;
39223 if (typeof input === 'string') {
39224 var data = new Uint8Array(input.length * 2);
39225 var length = 0;
39226 for (i = 0; i < input.length; i++) {
39227 var code = input.charCodeAt(i);
39228 if (code <= 0xff) {
39229 data[length++] = code;
39230 }
39231 else {
39232 data[length++] = code >>> 8;
39233 data[length++] = code & 0xff;
39234 }
39235 }
39236 } else if (input instanceof Uint8Array) {
39237 data = input;
39238 length = data.length;
39239 } else if (typeof input === 'object' && ('length' in input)) {
39240 // processing regular arrays as well, e.g. for IE9
39241 data = input;
39242 length = data.length;
39243 useUint32ArrayView = true;
39244 } else {
39245 throw new Error('Wrong data format in MurmurHash3_64_update. ' +
39246 'Input must be a string or array.');
39247 }
39248
39249 var blockCounts = length >> 2;
39250 var tailLength = length - blockCounts * 4;
39251 // we don't care about endianness here
39252 var dataUint32 = useUint32ArrayView ?
39253 new Uint32ArrayView(data, blockCounts) :
39254 new Uint32Array(data.buffer, 0, blockCounts);
39255 var k1 = 0;
39256 var k2 = 0;
39257 var h1 = this.h1;
39258 var h2 = this.h2;
39259 var C1 = 0xcc9e2d51;
39260 var C2 = 0x1b873593;
39261 var C1_LOW = C1 & MASK_LOW;
39262 var C2_LOW = C2 & MASK_LOW;
39263
39264 for (i = 0; i < blockCounts; i++) {
39265 if (i & 1) {
39266 k1 = dataUint32[i];
39267 k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
39268 k1 = k1 << 15 | k1 >>> 17;
39269 k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
39270 h1 ^= k1;
39271 h1 = h1 << 13 | h1 >>> 19;
39272 h1 = h1 * 5 + 0xe6546b64;
39273 } else {
39274 k2 = dataUint32[i];
39275 k2 = (k2 * C1 & MASK_HIGH) | (k2 * C1_LOW & MASK_LOW);
39276 k2 = k2 << 15 | k2 >>> 17;
39277 k2 = (k2 * C2 & MASK_HIGH) | (k2 * C2_LOW & MASK_LOW);
39278 h2 ^= k2;
39279 h2 = h2 << 13 | h2 >>> 19;
39280 h2 = h2 * 5 + 0xe6546b64;
39281 }
39282 }
39283
39284 k1 = 0;
39285
39286 switch (tailLength) {
39287 case 3:
39288 k1 ^= data[blockCounts * 4 + 2] << 16;
39289 /* falls through */
39290 case 2:
39291 k1 ^= data[blockCounts * 4 + 1] << 8;
39292 /* falls through */
39293 case 1:
39294 k1 ^= data[blockCounts * 4];
39295 /* falls through */
39296 k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
39297 k1 = k1 << 15 | k1 >>> 17;
39298 k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
39299 if (blockCounts & 1) {
39300 h1 ^= k1;
39301 } else {
39302 h2 ^= k1;
39303 }
39304 }
39305
39306 this.h1 = h1;
39307 this.h2 = h2;
39308 return this;
39309 },
39310
39311 hexdigest: function MurmurHash3_64_hexdigest () {
39312 var h1 = this.h1;
39313 var h2 = this.h2;
39314
39315 h1 ^= h2 >>> 1;
39316 h1 = (h1 * 0xed558ccd & MASK_HIGH) | (h1 * 0x8ccd & MASK_LOW);
39317 h2 = (h2 * 0xff51afd7 & MASK_HIGH) |
39318 (((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16);
39319 h1 ^= h2 >>> 1;
39320 h1 = (h1 * 0x1a85ec53 & MASK_HIGH) | (h1 * 0xec53 & MASK_LOW);
39321 h2 = (h2 * 0xc4ceb9fe & MASK_HIGH) |
39322 (((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16);
39323 h1 ^= h2 >>> 1;
39324
39325 for (var i = 0, arr = [h1, h2], str = ''; i < arr.length; i++) {
39326 var hex = (arr[i] >>> 0).toString(16);
39327 while (hex.length < 8) {
39328 hex = '0' + hex;
39329 }
39330 str += hex;
39331 }
39332
39333 return str;
39334 }
39335 };
39336
39337 return MurmurHash3_64;
39338 })();
39339
39340
39341 }).call((typeof window === 'undefined') ? this : window);
39342
39343 if (!PDFJS.workerSrc && typeof document !== 'undefined') {
39344 // workerSrc is not set -- using last script url to define default location
39345 PDFJS.workerSrc = (function () {
39346 'use strict';
39347 var scriptTagContainer = document.body ||
39348 document.getElementsByTagName('head')[0];
39349 var pdfjsSrc = scriptTagContainer.lastChild.src;
39350 return pdfjsSrc && pdfjsSrc.replace(/\.js$/i, '.worker.js');
39351 })();
39352 }
39353
39354