1/* Copyright 2012 Mozilla Foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15/* jshint globalstrict: false */ 16/* umdutils ignore */ 17 18(function (root, factory) { 19 'use strict'; 20 if (typeof define === 'function' && define.amd) { 21 define('pdfjs-dist/build/pdf', ['exports'], factory); 22 } else if (typeof exports !== 'undefined') { 23 factory(exports); 24 } else { 25 factory((root.pdfjsDistBuildPdf = {})); 26 } 27})(this, function (exports) { 28 // Use strict in our context only - users might not want it 29 'use strict'; 30 31 var pdfjsVersion = '1.6.210'; 32 var pdfjsBuild = '4ce2356'; 33 34 var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null; 35 36 var pdfjsLibs = {}; 37 38 (function pdfjsWrapper() { 39 (function (root, factory) { 40 { 41 factory((root.pdfjsSharedUtil = {})); 42 } 43 })(this, function (exports) { 44 var globalScope = 45 typeof window !== 'undefined' 46 ? window 47 : typeof global !== 'undefined' 48 ? global 49 : typeof self !== 'undefined' 50 ? self 51 : this; 52 53 var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; 54 55 var TextRenderingMode = { 56 FILL: 0, 57 STROKE: 1, 58 FILL_STROKE: 2, 59 INVISIBLE: 3, 60 FILL_ADD_TO_PATH: 4, 61 STROKE_ADD_TO_PATH: 5, 62 FILL_STROKE_ADD_TO_PATH: 6, 63 ADD_TO_PATH: 7, 64 FILL_STROKE_MASK: 3, 65 ADD_TO_PATH_FLAG: 4, 66 }; 67 68 var ImageKind = { 69 GRAYSCALE_1BPP: 1, 70 RGB_24BPP: 2, 71 RGBA_32BPP: 3, 72 }; 73 74 var AnnotationType = { 75 TEXT: 1, 76 LINK: 2, 77 FREETEXT: 3, 78 LINE: 4, 79 SQUARE: 5, 80 CIRCLE: 6, 81 POLYGON: 7, 82 POLYLINE: 8, 83 HIGHLIGHT: 9, 84 UNDERLINE: 10, 85 SQUIGGLY: 11, 86 STRIKEOUT: 12, 87 STAMP: 13, 88 CARET: 14, 89 INK: 15, 90 POPUP: 16, 91 FILEATTACHMENT: 17, 92 SOUND: 18, 93 MOVIE: 19, 94 WIDGET: 20, 95 SCREEN: 21, 96 PRINTERMARK: 22, 97 TRAPNET: 23, 98 WATERMARK: 24, 99 THREED: 25, 100 REDACT: 26, 101 }; 102 103 var AnnotationFlag = { 104 INVISIBLE: 0x01, 105 HIDDEN: 0x02, 106 PRINT: 0x04, 107 NOZOOM: 0x08, 108 NOROTATE: 0x10, 109 NOVIEW: 0x20, 110 READONLY: 0x40, 111 LOCKED: 0x80, 112 TOGGLENOVIEW: 0x100, 113 LOCKEDCONTENTS: 0x200, 114 }; 115 116 var AnnotationFieldFlag = { 117 READONLY: 0x0000001, 118 REQUIRED: 0x0000002, 119 NOEXPORT: 0x0000004, 120 MULTILINE: 0x0001000, 121 PASSWORD: 0x0002000, 122 NOTOGGLETOOFF: 0x0004000, 123 RADIO: 0x0008000, 124 PUSHBUTTON: 0x0010000, 125 COMBO: 0x0020000, 126 EDIT: 0x0040000, 127 SORT: 0x0080000, 128 FILESELECT: 0x0100000, 129 MULTISELECT: 0x0200000, 130 DONOTSPELLCHECK: 0x0400000, 131 DONOTSCROLL: 0x0800000, 132 COMB: 0x1000000, 133 RICHTEXT: 0x2000000, 134 RADIOSINUNISON: 0x2000000, 135 COMMITONSELCHANGE: 0x4000000, 136 }; 137 138 var AnnotationBorderStyleType = { 139 SOLID: 1, 140 DASHED: 2, 141 BEVELED: 3, 142 INSET: 4, 143 UNDERLINE: 5, 144 }; 145 146 var StreamType = { 147 UNKNOWN: 0, 148 FLATE: 1, 149 LZW: 2, 150 DCT: 3, 151 JPX: 4, 152 JBIG: 5, 153 A85: 6, 154 AHX: 7, 155 CCF: 8, 156 RL: 9, 157 }; 158 159 var FontType = { 160 UNKNOWN: 0, 161 TYPE1: 1, 162 TYPE1C: 2, 163 CIDFONTTYPE0: 3, 164 CIDFONTTYPE0C: 4, 165 TRUETYPE: 5, 166 CIDFONTTYPE2: 6, 167 TYPE3: 7, 168 OPENTYPE: 8, 169 TYPE0: 9, 170 MMTYPE1: 10, 171 }; 172 173 var VERBOSITY_LEVELS = { 174 errors: 0, 175 warnings: 1, 176 infos: 5, 177 }; 178 179 // All the possible operations for an operator list. 180 var OPS = { 181 // Intentionally start from 1 so it is easy to spot bad operators that will be 182 // 0's. 183 dependency: 1, 184 setLineWidth: 2, 185 setLineCap: 3, 186 setLineJoin: 4, 187 setMiterLimit: 5, 188 setDash: 6, 189 setRenderingIntent: 7,
190 setFlatness: 8, 191 setGState: 9, 192 save: 10, 193 restore: 11, 194 transform: 12, 195 moveTo: 13, 196 lineTo: 14, 197 curveTo: 15, 198 curveTo2: 16, 199 curveTo3: 17, 200 closePath: 18, 201 rectangle: 19, 202 stroke: 20, 203 closeStroke: 21, 204 fill: 22, 205 eoFill: 23, 206 fillStroke: 24, 207 eoFillStroke: 25, 208 closeFillStroke: 26, 209 closeEOFillStroke: 27, 210 endPath: 28, 211 clip: 29, 212 eoClip: 30, 213 beginText: 31, 214 endText: 32, 215 setCharSpacing: 33, 216 setWordSpacing: 34, 217 setHScale: 35, 218 setLeading: 36, 219 setFont: 37, 220 setTextRenderingMode: 38, 221 setTextRise: 39, 222 moveText: 40, 223 setLeadingMoveText: 41, 224 setTextMatrix: 42, 225 nextLine: 43, 226 showText: 44, 227 showSpacedText: 45, 228 nextLineShowText: 46, 229 nextLineSetSpacingShowText: 47, 230 setCharWidth: 48, 231 setCharWidthAndBounds: 49, 232 setStrokeColorSpace: 50, 233 setFillColorSpace: 51, 234 setStrokeColor: 52, 235 setStrokeColorN: 53, 236 setFillColor: 54, 237 setFillColorN: 55, 238 setStrokeGray: 56, 239 setFillGray: 57, 240 setStrokeRGBColor: 58, 241 setFillRGBColor: 59, 242 setStrokeCMYKColor: 60, 243 setFillCMYKColor: 61, 244 shadingFill: 62, 245 beginInlineImage: 63, 246 beginImageData: 64, 247 endInlineImage: 65, 248 paintXObject: 66, 249 markPoint: 67, 250 markPointProps: 68, 251 beginMarkedContent: 69, 252 beginMarkedContentProps: 70, 253 endMarkedContent: 71, 254 beginCompat: 72, 255 endCompat: 73, 256 paintFormXObjectBegin: 74, 257 paintFormXObjectEnd: 75, 258 beginGroup: 76, 259 endGroup: 77, 260 beginAnnotations: 78, 261 endAnnotations: 79, 262 beginAnnotation: 80, 263 endAnnotation: 81, 264 paintJpegXObject: 82, 265 paintImageMaskXObject: 83, 266 paintImageMaskXObjectGroup: 84, 267 paintImageXObject: 85, 268 paintInlineImageXObject: 86, 269 paintInlineImageXObjectGroup: 87, 270 paintImageXObjectRepeat: 88, 271 paintImageMaskXObjectRepeat: 89, 272 paintSolidColorImageMask: 90, 273 constructPath: 91, 274 }; 275 276 var verbosity = VERBOSITY_LEVELS.warnings; 277 278 function setVerbosityLevel(level) { 279 verbosity = level; 280 } 281 282 function getVerbosityLevel() { 283 return verbosity; 284 } 285 286 // A notice for devs. These are good for things that are helpful to devs, such 287 // as warning that Workers were disabled, which is important to devs but not 288 // end users. 289 function info(msg) { 290 if (verbosity >= VERBOSITY_LEVELS.infos) { 291 console.log('Info: ' + msg); 292 } 293 } 294 295 // Non-fatal warnings. 296 function warn(msg) { 297 if (verbosity >= VERBOSITY_LEVELS.warnings) { 298 console.log('Warning: ' + msg); 299 } 300 } 301 302 // Deprecated API function -- display regardless of the PDFJS.verbosity setting. 303 function deprecated(details) { 304 console.log('Deprecated API usage: ' + details); 305 } 306 307 // Fatal errors that should trigger the fallback UI and halt execution by 308 // throwing an exception. 309 function error(msg) { 310 if (verbosity >= VERBOSITY_LEVELS.errors) { 311 console.log('Error: ' + msg); 312 console.log(backtrace()); 313 } 314 throw new Error(msg); 315 } 316 317 function backtrace() { 318 try { 319 throw new Error(); 320 } catch (e) { 321 return e.stack ? e.stack.split('\n').slice(2).join('\n') : ''; 322 } 323 } 324 325 function assert(cond, msg) { 326 if (!cond) { 327 error(msg); 328 } 329 } 330 331 var UNSUPPORTED_FEATURES = { 332 unknown: 'unknown', 333 forms: 'forms', 334 javaScript: 'javaScript', 335 smask: 'smask', 336 shadingPattern: 'shadingPattern', 337 font: 'font', 338 }; 339 340 // Checks if URLs have the same origin. For non-HTTP based URLs, returns false. 341 function isSameOrigin(baseUrl, otherUrl) { 342 try { 343 var base = new URL(baseUrl); 344 if (!base.origin || base.origin === 'null') { 345 return false; // non-HTTP url 346 } 347 } catch (e) { 348 return false;
349 } 350 351 var other = new URL(otherUrl, base); 352 return base.origin === other.origin; 353 } 354 355 // Validates if URL is safe and allowed, e.g. to avoid XSS. 356 function isValidUrl(url, allowRelative) { 357 if (!url || typeof url !== 'string') { 358 return false; 359 } 360 // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1) 361 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) 362 var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url); 363 if (!protocol) { 364 return allowRelative; 365 } 366 protocol = protocol[0].toLowerCase(); 367 switch (protocol) { 368 case 'http': 369 case 'https': 370 case 'ftp': 371 case 'mailto': 372 case 'tel': 373 return true; 374 default: 375 return false; 376 } 377 } 378 379 function shadow(obj, prop, value) { 380 Object.defineProperty(obj, prop, { 381 value: value, 382 enumerable: true, 383 configurable: true, 384 writable: false, 385 }); 386 return value; 387 } 388 389 function getLookupTableFactory(initializer) { 390 var lookup; 391 return function () { 392 if (initializer) { 393 lookup = Object.create(null); 394 initializer(lookup); 395 initializer = null; 396 } 397 return lookup; 398 }; 399 } 400 401 var PasswordResponses = { 402 NEED_PASSWORD: 1, 403 INCORRECT_PASSWORD: 2, 404 }; 405 406 var PasswordException = (function PasswordExceptionClosure() { 407 function PasswordException(msg, code) { 408 this.name = 'PasswordException'; 409 this.message = msg; 410 this.code = code; 411 } 412 413 PasswordException.prototype = new Error(); 414 PasswordException.constructor = PasswordException; 415 416 return PasswordException; 417 })(); 418 419 var UnknownErrorException = (function UnknownErrorExceptionClosure() { 420 function UnknownErrorException(msg, details) { 421 this.name = 'UnknownErrorException'; 422 this.message = msg; 423 this.details = details; 424 } 425 426 UnknownErrorException.prototype = new Error(); 427 UnknownErrorException.constructor = UnknownErrorException; 428 429 return UnknownErrorException; 430 })(); 431 432 var InvalidPDFException = (function InvalidPDFExceptionClosure() { 433 function InvalidPDFException(msg) { 434 this.name = 'InvalidPDFException'; 435 this.message = msg; 436 } 437 438 InvalidPDFException.prototype = new Error(); 439 InvalidPDFException.constructor = InvalidPDFException; 440 441 return InvalidPDFException; 442 })(); 443 444 var MissingPDFException = (function MissingPDFExceptionClosure() { 445 function MissingPDFException(msg) { 446 this.name = 'MissingPDFException'; 447 this.message = msg; 448 } 449 450 MissingPDFException.prototype = new Error(); 451 MissingPDFException.constructor = MissingPDFException; 452 453 return MissingPDFException; 454 })(); 455 456 var UnexpectedResponseException = (function UnexpectedResponseExceptionClosure() { 457 function UnexpectedResponseException(msg, status) { 458 this.name = 'UnexpectedResponseException'; 459 this.message = msg; 460 this.status = status; 461 } 462 463 UnexpectedResponseException.prototype = new Error(); 464 UnexpectedResponseException.constructor = UnexpectedResponseException; 465 466 return UnexpectedResponseException; 467 })(); 468 469 var NotImplementedException = (function NotImplementedExceptionClosure() { 470 function NotImplementedException(msg) { 471 this.message = msg; 472 } 473 474 NotImplementedException.prototype = new Error(); 475 NotImplementedException.prototype.name = 'NotImplementedException'; 476 NotImplementedException.constructor = NotImplementedException; 477 478 return NotImplementedException; 479 })(); 480 481 var MissingDataException = (function MissingDataExceptionClosure() { 482 function MissingDataException(begin, end) { 483 this.begin = begin; 484 this.end = end; 485 this.message = 'Missing data [' + begin + ', ' + end + ')'; 486 } 487 488 MissingDataException.prototype = new Error(); 489 MissingDataException.prototype.name = 'MissingDataException'; 490 MissingDataException.constructor = MissingDataException; 491 492 return MissingDataException; 493 })(); 494 495 var XRefParseException = (function XRefParseExceptionClosure() { 496 function XRefParseException(msg) { 497 this.message = msg; 498 } 499 500 XRefParseException.prototype = new Error(); 501 XRefParseException.prototype.name = 'XRefParseException'; 502 XRefParseException.constructor = XRefParseException; 503 504 return XRefParseException; 505 })(); 506 507 var NullCharactersRegExp = /\x00/g; 508 509 function removeNullCharacters(str) { 510 if (typeof str !== 'string') { 511 warn('The argument for removeNullCharacters must be a string.'); 512 return str; 513 } 514 return str.replace(NullCharactersRegExp, ''); 515 } 516 517 function bytesToString(bytes) { 518 assert( 519 bytes !== null && typeof bytes === 'object' && bytes.length !== undefined, 520 'Invalid argument for bytesToString' 521 ); 522 var length = bytes.length; 523 var MAX_ARGUMENT_COUNT = 8192; 524 if (length < MAX_ARGUMENT_COUNT) { 525 return String.fromCharCode.apply(null, bytes); 526 } 527 var strBuf = []; 528 for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) { 529 var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); 530 var chunk = bytes.subarray(i, chunkEnd); 531 strBuf.push(String.fromCharCode.apply(null, chunk)); 532 } 533 return strBuf.join(''); 534 } 535 536 function stringToBytes(str) { 537 assert(typeof str === 'string', 'Invalid argument for stringToBytes'); 538 var length = str.length; 539 var bytes = new Uint8Array(length); 540 for (var i = 0; i < length; ++i) { 541 bytes[i] = str.charCodeAt(i) & 0xff;
542 } 543 return bytes; 544 } 545 546 /** 547 * Gets length of the array (Array, Uint8Array, or string) in bytes. 548 * @param {Array|Uint8Array|string} arr 549 * @returns {number} 550 */ 551 function arrayByteLength(arr) { 552 if (arr.length !== undefined) { 553 return arr.length; 554 } 555 assert(arr.byteLength !== undefined); 556 return arr.byteLength; 557 } 558 559 /** 560 * Combines array items (arrays) into single Uint8Array object. 561 * @param {Array} arr - the array of the arrays (Array, Uint8Array, or string). 562 * @returns {Uint8Array} 563 */ 564 function arraysToBytes(arr) { 565 // Shortcut: if first and only item is Uint8Array, return it. 566 if (arr.length === 1 && arr[0] instanceof Uint8Array) { 567 return arr[0]; 568 } 569 var resultLength = 0; 570 var i, 571 ii = arr.length; 572 var item, itemLength; 573 for (i = 0; i < ii; i++) { 574 item = arr[i]; 575 itemLength = arrayByteLength(item); 576 resultLength += itemLength; 577 } 578 var pos = 0; 579 var data = new Uint8Array(resultLength); 580 for (i = 0; i < ii; i++) { 581 item = arr[i]; 582 if (!(item instanceof Uint8Array)) { 583 if (typeof item === 'string') { 584 item = stringToBytes(item); 585 } else { 586 item = new Uint8Array(item); 587 } 588 } 589 itemLength = item.byteLength; 590 data.set(item, pos); 591 pos += itemLength; 592 } 593 return data; 594 } 595 596 function string32(value) { 597 return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff, (value >> 8) & 0xff, value & 0xff); 598 } 599 600 function log2(x) { 601 var n = 1, 602 i = 0; 603 while (x > n) { 604 n <<= 1; 605 i++; 606 } 607 return i; 608 } 609 610 function readInt8(data, start) { 611 return (data[start] << 24) >> 24; 612 } 613 614 function readUint16(data, offset) { 615 return (data[offset] << 8) | data[offset + 1]; 616 } 617 618 function readUint32(data, offset) { 619 return ((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]) >>> 0; 620 } 621 622 // Lazy test the endianness of the platform 623 // NOTE: This will be 'true' for simulated TypedArrays 624 function isLittleEndian() { 625 var buffer8 = new Uint8Array(2); 626 buffer8[0] = 1; 627 var buffer16 = new Uint16Array(buffer8.buffer); 628 return buffer16[0] === 1; 629 } 630 631 // Checks if it's possible to eval JS expressions. 632 function isEvalSupported() { 633 try { 634 /* jshint evil: true */ 635 new Function(''); 636 return true; 637 } catch (e) { 638 return false; 639 } 640 } 641 642 var Uint32ArrayView = (function Uint32ArrayViewClosure() { 643 function Uint32ArrayView(buffer, length) { 644 this.buffer = buffer; 645 this.byteLength = buffer.length; 646 this.length = length === undefined ? this.byteLength >> 2 : length; 647 ensureUint32ArrayViewProps(this.length); 648 } 649 650 Uint32ArrayView.prototype = Object.create(null); 651 652 var uint32ArrayViewSetters = 0; 653 654 function createUint32ArrayProp(index) { 655 return { 656 get: function () { 657 var buffer = this.buffer, 658 offset = index << 2; 659 return ( 660 (buffer[offset] | 661 (buffer[offset + 1] << 8) | 662 (buffer[offset + 2] << 16) | 663 (buffer[offset + 3] << 24)) >>> 664 0 665 ); 666 }, 667 set: function (value) { 668 var buffer = this.buffer, 669 offset = index << 2; 670 buffer[offset] = value & 255; 671 buffer[offset + 1] = (value >> 8) & 255; 672 buffer[offset + 2] = (value >> 16) & 255; 673 buffer[offset + 3] = (value >>> 24) & 255; 674 }, 675 }; 676 } 677 678 function ensureUint32ArrayViewProps(length) { 679 while (uint32ArrayViewSetters < length) { 680 Object.defineProperty( 681 Uint32ArrayView.prototype, 682 uint32ArrayViewSetters, 683 createUint32ArrayProp(uint32ArrayViewSetters) 684 ); 685 uint32ArrayViewSetters++; 686 } 687 } 688 689 return Uint32ArrayView; 690 })(); 691 692 exports.Uint32ArrayView = Uint32ArrayView; 693 694 var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; 695 696 var Util = (function UtilClosure() { 697 function Util() {} 698 699 var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')']; 700
vendor: 4,308 bytes, lines 701-804
701 // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids 702 // creating many intermediate strings. 703 Util.makeCssRgb = function Util_makeCssRgb(r, g, b) { 704 rgbBuf[1] = r; 705 rgbBuf[3] = g; 706 rgbBuf[5] = b; 707 return rgbBuf.join(''); 708 }; 709 710 // Concatenates two transformation matrices together and returns the result. 711 Util.transform = function Util_transform(m1, m2) { 712 return [ 713 m1[0] * m2[0] + m1[2] * m2[1], 714 m1[1] * m2[0] + m1[3] * m2[1], 715 m1[0] * m2[2] + m1[2] * m2[3], 716 m1[1] * m2[2] + m1[3] * m2[3], 717 m1[0] * m2[4] + m1[2] * m2[5] + m1[4], 718 m1[1] * m2[4] + m1[3] * m2[5] + m1[5], 719 ]; 720 }; 721 722 // For 2d affine transforms 723 Util.applyTransform = function Util_applyTransform(p, m) { 724 var xt = p[0] * m[0] + p[1] * m[2] + m[4]; 725 var yt = p[0] * m[1] + p[1] * m[3] + m[5]; 726 return [xt, yt]; 727 }; 728 729 Util.applyInverseTransform = function Util_applyInverseTransform(p, m) { 730 var d = m[0] * m[3] - m[1] * m[2]; 731 var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; 732 var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; 733 return [xt, yt]; 734 }; 735 736 // Applies the transform to the rectangle and finds the minimum axially 737 // aligned bounding box. 738 Util.getAxialAlignedBoundingBox = function Util_getAxialAlignedBoundingBox(r, m) { 739 var p1 = Util.applyTransform(r, m); 740 var p2 = Util.applyTransform(r.slice(2, 4), m); 741 var p3 = Util.applyTransform([r[0], r[3]], m); 742 var p4 = Util.applyTransform([r[2], r[1]], m); 743 return [ 744 Math.min(p1[0], p2[0], p3[0], p4[0]), 745 Math.min(p1[1], p2[1], p3[1], p4[1]), 746 Math.max(p1[0], p2[0], p3[0], p4[0]), 747 Math.max(p1[1], p2[1], p3[1], p4[1]), 748 ]; 749 }; 750 751 Util.inverseTransform = function Util_inverseTransform(m) { 752 var d = m[0] * m[3] - m[1] * m[2]; 753 return [ 754 m[3] / d, 755 -m[1] / d, 756 -m[2] / d, 757 m[0] / d, 758 (m[2] * m[5] - m[4] * m[3]) / d, 759 (m[4] * m[1] - m[5] * m[0]) / d, 760 ]; 761 }; 762 763 // Apply a generic 3d matrix M on a 3-vector v: 764 // | a b c | | X | 765 // | d e f | x | Y | 766 // | g h i | | Z | 767 // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i], 768 // with v as [X,Y,Z] 769 Util.apply3dTransform = function Util_apply3dTransform(m, v) { 770 return [ 771 m[0] * v[0] + m[1] * v[1] + m[2] * v[2], 772 m[3] * v[0] + m[4] * v[1] + m[5] * v[2], 773 m[6] * v[0] + m[7] * v[1] + m[8] * v[2], 774 ]; 775 }; 776 777 // This calculation uses Singular Value Decomposition. 778 // The SVD can be represented with formula A = USV. We are interested in the 779 // matrix S here because it represents the scale values. 780 Util.singularValueDecompose2dScale = function Util_singularValueDecompose2dScale(m) { 781 var transpose = [m[0], m[2], m[1], m[3]]; 782 783 // Multiply matrix m with its transpose. 784 var a = m[0] * transpose[0] + m[1] * transpose[2]; 785 var b = m[0] * transpose[1] + m[1] * transpose[3]; 786 var c = m[2] * transpose[0] + m[3] * transpose[2]; 787 var d = m[2] * transpose[1] + m[3] * transpose[3]; 788 789 // Solve the second degree polynomial to get roots. 790 var first = (a + d) / 2; 791 var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; 792 var sx = first + second || 1; 793 var sy = first - second || 1; 794 795 // Scale values are the square roots of the eigenvalues. 796 return [Math.sqrt(sx), Math.sqrt(sy)]; 797 }; 798 799 // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2) 800 // For coordinate systems whose origin lies in the bottom-left, this 801 // means normalization to (BL,TR) ordering. For systems with origin in the 802 // top-left, this means (TL,BR) ordering. 803 Util.normalizeRect = function Util_normalizeRect(rect) { 804 var r = rect.slice(0); // clone rect
805 if (rect[0] > rect[2]) { 806 r[0] = rect[2]; 807 r[2] = rect[0]; 808 } 809 if (rect[1] > rect[3]) { 810 r[1] = rect[3]; 811 r[3] = rect[1]; 812 } 813 return r; 814 }; 815 816 // Returns a rectangle [x1, y1, x2, y2] corresponding to the 817 // intersection of rect1 and rect2. If no intersection, returns 'false' 818 // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2] 819 Util.intersect = function Util_intersect(rect1, rect2) { 820 function compare(a, b) { 821 return a - b; 822 } 823 824 // Order points along the axes 825 var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare), 826 orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare), 827 result = []; 828 829 rect1 = Util.normalizeRect(rect1); 830 rect2 = Util.normalizeRect(rect2); 831 832 // X: first and second points belong to different rectangles? 833 if ( 834 (orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) || 835 (orderedX[0] === rect2[0] && orderedX[1] === rect1[0]) 836 ) { 837 // Intersection must be between second and third points 838 result[0] = orderedX[1]; 839 result[2] = orderedX[2]; 840 } else { 841 return false; 842 } 843 844 // Y: first and second points belong to different rectangles? 845 if ( 846 (orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) || 847 (orderedY[0] === rect2[1] && orderedY[1] === rect1[1]) 848 ) { 849 // Intersection must be between second and third points 850 result[1] = orderedY[1]; 851 result[3] = orderedY[2]; 852 } else { 853 return false; 854 } 855 856 return result; 857 }; 858 859 Util.sign = function Util_sign(num) { 860 return num < 0 ? -1 : 1; 861 }; 862 863 var ROMAN_NUMBER_MAP = [ 864 '', 865 'C', 866 'CC', 867 'CCC', 868 'CD', 869 'D', 870 'DC', 871 'DCC', 872 'DCCC', 873 'CM', 874 '', 875 'X', 876 'XX', 877 'XXX', 878 'XL', 879 'L', 880 'LX', 881 'LXX', 882 'LXXX', 883 'XC', 884 '', 885 'I', 886 'II', 887 'III', 888 'IV', 889 'V', 890 'VI', 891 'VII', 892 'VIII', 893 'IX', 894 ]; 895 /** 896 * Converts positive integers to (upper case) Roman numerals. 897 * @param {integer} number - The number that should be converted. 898 * @param {boolean} lowerCase - Indicates if the result should be converted 899 * to lower case letters. The default is false. 900 * @return {string} The resulting Roman number. 901 */ 902 Util.toRoman = function Util_toRoman(number, lowerCase) { 903 assert(isInt(number) && number > 0, 'The number should be a positive integer.'); 904 var pos, 905 romanBuf = []; 906 // Thousands 907 while (number >= 1000) { 908 number -= 1000; 909 romanBuf.push('M'); 910 } 911 // Hundreds 912 pos = (number / 100) | 0; 913 number %= 100; 914 romanBuf.push(ROMAN_NUMBER_MAP[pos]); 915 // Tens 916 pos = (number / 10) | 0; 917 number %= 10; 918 romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]); 919 // Ones 920 romanBuf.push(ROMAN_NUMBER_MAP[20 + number]); 921 922 var romanStr = romanBuf.join(''); 923 return lowerCase ? romanStr.toLowerCase() : romanStr; 924 }; 925 926 Util.appendToArray = function Util_appendToArray(arr1, arr2) { 927 Array.prototype.push.apply(arr1, arr2); 928 }; 929 930 Util.prependToArray = function Util_prependToArray(arr1, arr2) { 931 Array.prototype.unshift.apply(arr1, arr2); 932 }; 933 934 Util.extendObj = function extendObj(obj1, obj2) { 935 for (var key in obj2) { 936 obj1[key] = obj2[key]; 937 } 938 }; 939 940 Util.getInheritableProperty = function Util_getInheritableProperty(dict, name) { 941 while (dict && !dict.has(name)) { 942 dict = dict.get('Parent'); 943 } 944 if (!dict) { 945 return null; 946 } 947 return dict.get(name); 948 }; 949 950 Util.inherit = function Util_inherit(sub, base, prototype) { 951 sub.prototype = Object.create(base.prototype); 952 sub.prototype.constructor = sub; 953 for (var prop in prototype) { 954 sub.prototype[prop] = prototype[prop]; 955 } 956 }; 957 958 Util.loadScript = function Util_loadScript(src, callback) { 959 var script = document.createElement('script'); 960 var loaded = false;
vendor: 4,632 bytes, lines 961-1084
961 script.setAttribute('src', src); 962 if (callback) { 963 script.onload = function () { 964 if (!loaded) { 965 callback(); 966 } 967 loaded = true; 968 }; 969 } 970 document.getElementsByTagName('head')[0].appendChild(script); 971 }; 972 973 return Util; 974 })(); 975 976 /** 977 * PDF page viewport created based on scale, rotation and offset. 978 * @class 979 * @alias PageViewport 980 */ 981 var PageViewport = (function PageViewportClosure() { 982 /** 983 * @constructor 984 * @private 985 * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates. 986 * @param scale {number} scale of the viewport. 987 * @param rotation {number} rotations of the viewport in degrees. 988 * @param offsetX {number} offset X 989 * @param offsetY {number} offset Y 990 * @param dontFlip {boolean} if true, axis Y will not be flipped. 991 */ 992 function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) { 993 this.viewBox = viewBox; 994 this.scale = scale; 995 this.rotation = rotation; 996 this.offsetX = offsetX; 997 this.offsetY = offsetY; 998 999 // creating transform to convert pdf coordinate system to the normal 1000 // canvas like coordinates taking in account scale and rotation 1001 var centerX = (viewBox[2] + viewBox[0]) / 2; 1002 var centerY = (viewBox[3] + viewBox[1]) / 2; 1003 var rotateA, rotateB, rotateC, rotateD; 1004 rotation = rotation % 360; 1005 rotation = rotation < 0 ? rotation + 360 : rotation; 1006 switch (rotation) { 1007 case 180: 1008 rotateA = -1; 1009 rotateB = 0; 1010 rotateC = 0; 1011 rotateD = 1; 1012 break; 1013 case 90: 1014 rotateA = 0; 1015 rotateB = 1; 1016 rotateC = 1; 1017 rotateD = 0; 1018 break; 1019 case 270: 1020 rotateA = 0; 1021 rotateB = -1; 1022 rotateC = -1; 1023 rotateD = 0; 1024 break; 1025 //case 0: 1026 default: 1027 rotateA = 1; 1028 rotateB = 0; 1029 rotateC = 0; 1030 rotateD = -1; 1031 break; 1032 } 1033 1034 if (dontFlip) { 1035 rotateC = -rotateC; 1036 rotateD = -rotateD; 1037 } 1038 1039 var offsetCanvasX, offsetCanvasY; 1040 var width, height; 1041 if (rotateA === 0) { 1042 offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX; 1043 offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY; 1044 width = Math.abs(viewBox[3] - viewBox[1]) * scale; 1045 height = Math.abs(viewBox[2] - viewBox[0]) * scale; 1046 } else { 1047 offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX; 1048 offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY; 1049 width = Math.abs(viewBox[2] - viewBox[0]) * scale; 1050 height = Math.abs(viewBox[3] - viewBox[1]) * scale; 1051 } 1052 // creating transform for the following operations: 1053 // translate(-centerX, -centerY), rotate and flip vertically, 1054 // scale, and translate(offsetCanvasX, offsetCanvasY) 1055 this.transform = [ 1056 rotateA * scale, 1057 rotateB * scale, 1058 rotateC * scale, 1059 rotateD * scale, 1060 offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, 1061 offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY, 1062 ]; 1063 1064 this.width = width; 1065 this.height = height; 1066 this.fontScale = scale; 1067 } 1068 1069 PageViewport.prototype = /** @lends PageViewport.prototype */ { 1070 /** 1071 * Clones viewport with additional properties. 1072 * @param args {Object} (optional) If specified, may contain the 'scale' or 1073 * 'rotation' properties to override the corresponding properties in 1074 * the cloned viewport. 1075 * @returns {PageViewport} Cloned viewport. 1076 */ 1077 clone: function PageViewPort_clone(args) { 1078 args = args || {}; 1079 var scale = 'scale' in args ? args.scale : this.scale; 1080 var rotation = 'rotation' in args ? args.rotation : this.rotation; 1081 return new PageViewport(this.viewBox.slice(), scale, rotation, this.offsetX, this.offsetY, args.dontFlip); 1082 }, 1083 /** 1084 * Converts PDF point to the viewport coordinates. For examples, useful for
1085 * converting PDF location into canvas pixel coordinates. 1086 * @param x {number} X coordinate. 1087 * @param y {number} Y coordinate. 1088 * @returns {Object} Object that contains 'x' and 'y' properties of the 1089 * point in the viewport coordinate space. 1090 * @see {@link convertToPdfPoint} 1091 * @see {@link convertToViewportRectangle} 1092 */ 1093 convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) { 1094 return Util.applyTransform([x, y], this.transform); 1095 }, 1096 /** 1097 * Converts PDF rectangle to the viewport coordinates. 1098 * @param rect {Array} xMin, yMin, xMax and yMax coordinates. 1099 * @returns {Array} Contains corresponding coordinates of the rectangle 1100 * in the viewport coordinate space. 1101 * @see {@link convertToViewportPoint} 1102 */ 1103 convertToViewportRectangle: function PageViewport_convertToViewportRectangle(rect) { 1104 var tl = Util.applyTransform([rect[0], rect[1]], this.transform); 1105 var br = Util.applyTransform([rect[2], rect[3]], this.transform); 1106 return [tl[0], tl[1], br[0], br[1]]; 1107 }, 1108 /** 1109 * Converts viewport coordinates to the PDF location. For examples, useful 1110 * for converting canvas pixel location into PDF one. 1111 * @param x {number} X coordinate. 1112 * @param y {number} Y coordinate. 1113 * @returns {Object} Object that contains 'x' and 'y' properties of the 1114 * point in the PDF coordinate space. 1115 * @see {@link convertToViewportPoint} 1116 */ 1117 convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) { 1118 return Util.applyInverseTransform([x, y], this.transform); 1119 }, 1120 }; 1121 return PageViewport; 1122 })(); 1123 1124 var PDFStringTranslateTable = [ 1125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2d8, 0x2c7, 0x2c6, 0x2d9, 0x2dd, 1126 0x2db, 0x2da, 0x2dc, 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, 0, 0, 0, 0, 1127 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1128 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, 0, 0, 0, 0x2022, 0x2020, 0x2021, 1129 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, 0x2019, 1130 0x201a, 0x2122, 0xfb01, 0xfb02, 0x141, 0x152, 0x160, 0x178, 0x17d, 0x131, 0x142, 0x153, 0x161, 0x17e, 0, 0x20ac, 1131 ]; 1132 1133 function stringToPDFString(str) { 1134 var i, 1135 n = str.length, 1136 strBuf = []; 1137 if (str[0] === '\xFE' && str[1] === '\xFF') { 1138 // UTF16BE BOM 1139 for (i = 2; i < n; i += 2) { 1140 strBuf.push(String.fromCharCode((str.charCodeAt(i) << 8) | str.charCodeAt(i + 1))); 1141 } 1142 } else { 1143 for (i = 0; i < n; ++i) { 1144 var code = PDFStringTranslateTable[str.charCodeAt(i)]; 1145 strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); 1146 } 1147 } 1148 return strBuf.join(''); 1149 } 1150 1151 function stringToUTF8String(str) { 1152 return decodeURIComponent(escape(str)); 1153 } 1154 1155 function utf8StringToString(str) { 1156 return unescape(encodeURIComponent(str)); 1157 } 1158 1159 function isEmptyObj(obj) { 1160 for (var key in obj) { 1161 return false; 1162 } 1163 return true; 1164 } 1165 1166 function isBool(v) { 1167 return typeof v === 'boolean'; 1168 } 1169 1170 function isInt(v) { 1171 return typeof v === 'number' && (v | 0) === v; 1172 } 1173 1174 function isNum(v) { 1175 return typeof v === 'number'; 1176 } 1177 1178 function isString(v) { 1179 return typeof v === 'string'; 1180 } 1181 1182 function isArray(v) { 1183 return v instanceof Array; 1184 } 1185 1186 function isArrayBuffer(v) { 1187 return typeof v === 'object' && v !== null && v.byteLength !== undefined; 1188 } 1189 1190 // Checks if ch is one of the following characters: SPACE, TAB, CR or LF. 1191 function isSpace(ch) { 1192 return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a; 1193 } 1194 1195 /** 1196 * Promise Capability object. 1197 * 1198 * @typedef {Object} PromiseCapability 1199 * @property {Promise} promise - A promise object. 1200 * @property {function} resolve - Fulfills the promise. 1201 * @property {function} reject - Rejects the promise. 1202 */ 1203 1204 /** 1205 * Creates a promise capability object. 1206 * @alias createPromiseCapability 1207 * 1208 * @return {PromiseCapability}
vendor: 11,259 bytes, lines 1208-1542
1208 A capability object contains: 1209 * - a Promise, resolve and reject methods. 1210 */ 1211 function createPromiseCapability() { 1212 var capability = {}; 1213 capability.promise = new Promise(function (resolve, reject) { 1214 capability.resolve = resolve; 1215 capability.reject = reject; 1216 }); 1217 return capability; 1218 } 1219 1220 /** 1221 * Polyfill for Promises: 1222 * The following promise implementation tries to generally implement the 1223 * Promise/A+ spec. Some notable differences from other promise libraries are: 1224 * - There currently isn't a separate deferred and promise object. 1225 * - Unhandled rejections eventually show an error if they aren't handled. 1226 * 1227 * Based off of the work in: 1228 * https://bugzilla.mozilla.org/show_bug.cgi?id=810490 1229 */ 1230 (function PromiseClosure() { 1231 if (globalScope.Promise) { 1232 // Promises existing in the DOM/Worker, checking presence of all/resolve 1233 if (typeof globalScope.Promise.all !== 'function') { 1234 globalScope.Promise.all = function (iterable) { 1235 var count = 0, 1236 results = [], 1237 resolve, 1238 reject; 1239 var promise = new globalScope.Promise(function (resolve_, reject_) { 1240 resolve = resolve_; 1241 reject = reject_; 1242 }); 1243 iterable.forEach(function (p, i) { 1244 count++; 1245 p.then(function (result) { 1246 results[i] = result; 1247 count--; 1248 if (count === 0) { 1249 resolve(results); 1250 } 1251 }, reject); 1252 }); 1253 if (count === 0) { 1254 resolve(results); 1255 } 1256 return promise; 1257 }; 1258 } 1259 if (typeof globalScope.Promise.resolve !== 'function') { 1260 globalScope.Promise.resolve = function (value) { 1261 return new globalScope.Promise(function (resolve) { 1262 resolve(value); 1263 }); 1264 }; 1265 } 1266 if (typeof globalScope.Promise.reject !== 'function') { 1267 globalScope.Promise.reject = function (reason) { 1268 return new globalScope.Promise(function (resolve, reject) { 1269 reject(reason); 1270 }); 1271 }; 1272 } 1273 if (typeof globalScope.Promise.prototype.catch !== 'function') { 1274 globalScope.Promise.prototype.catch = function (onReject) { 1275 return globalScope.Promise.prototype.then(undefined, onReject); 1276 }; 1277 } 1278 return; 1279 } 1280 var STATUS_PENDING = 0; 1281 var STATUS_RESOLVED = 1; 1282 var STATUS_REJECTED = 2; 1283 1284 // In an attempt to avoid silent exceptions, unhandled rejections are 1285 // tracked and if they aren't handled in a certain amount of time an 1286 // error is logged. 1287 var REJECTION_TIMEOUT = 500; 1288 1289 var HandlerManager = { 1290 handlers: [], 1291 running: false, 1292 unhandledRejections: [], 1293 pendingRejectionCheck: false, 1294 1295 scheduleHandlers: function scheduleHandlers(promise) { 1296 if (promise._status === STATUS_PENDING) { 1297 return; 1298 } 1299 1300 this.handlers = this.handlers.concat(promise._handlers); 1301 promise._handlers = []; 1302 1303 if (this.running) { 1304 return; 1305 } 1306 this.running = true; 1307 1308 setTimeout(this.runHandlers.bind(this), 0); 1309 }, 1310 1311 runHandlers: function runHandlers() { 1312 var RUN_TIMEOUT = 1; // ms 1313 var timeoutAt = Date.now() + RUN_TIMEOUT; 1314 while (this.handlers.length > 0) { 1315 var handler = this.handlers.shift(); 1316 1317 var nextStatus = handler.thisPromise._status; 1318 var nextValue = handler.thisPromise._value; 1319 1320 try { 1321 if (nextStatus === STATUS_RESOLVED) { 1322 if (typeof handler.onResolve === 'function') { 1323 nextValue = handler.onResolve(nextValue); 1324 } 1325 } else if (typeof handler.onReject === 'function') { 1326 nextValue = handler.onReject(nextValue); 1327 nextStatus = STATUS_RESOLVED; 1328 1329 if (handler.thisPromise._unhandledRejection) { 1330 this.removeUnhandeledRejection(handler.thisPromise); 1331 } 1332 } 1333 } catch (ex) { 1334 nextStatus = STATUS_REJECTED; 1335 nextValue = ex; 1336 } 1337 1338 handler.nextPromise._updateStatus(nextStatus, nextValue); 1339 if (Date.now() >= timeoutAt) { 1340 break; 1341 } 1342 } 1343 1344 if (this.handlers.length > 0) { 1345 setTimeout(this.runHandlers.bind(this), 0); 1346 return; 1347 } 1348 1349 this.running = false; 1350 }, 1351 1352 addUnhandledRejection: function addUnhandledRejection(promise) { 1353 this.unhandledRejections.push({ 1354 promise: promise, 1355 time: Date.now(), 1356 }); 1357 this.scheduleRejectionCheck(); 1358 }, 1359 1360 removeUnhandeledRejection: function removeUnhandeledRejection(promise) { 1361 promise._unhandledRejection = false; 1362 for (var i = 0; i < this.unhandledRejections.length; i++) { 1363 if (this.unhandledRejections[i].promise === promise) { 1364 this.unhandledRejections.splice(i); 1365 i--; 1366 } 1367 } 1368 }, 1369 1370 scheduleRejectionCheck: function scheduleRejectionCheck() { 1371 if (this.pendingRejectionCheck) { 1372 return; 1373 } 1374 this.pendingRejectionCheck = true; 1375 setTimeout( 1376 function rejectionCheck() { 1377 this.pendingRejectionCheck = false; 1378 var now = Date.now(); 1379 for (var i = 0; i < this.unhandledRejections.length; i++) { 1380 if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) { 1381 var unhandled = this.unhandledRejections[i].promise._value; 1382 var msg = 'Unhandled rejection: ' + unhandled; 1383 if (unhandled.stack) { 1384 msg += '\n' + unhandled.stack; 1385 } 1386 warn(msg); 1387 this.unhandledRejections.splice(i); 1388 i--; 1389 } 1390 } 1391 if (this.unhandledRejections.length) { 1392 this.scheduleRejectionCheck(); 1393 } 1394 }.bind(this), 1395 REJECTION_TIMEOUT 1396 ); 1397 }, 1398 }; 1399 1400 function Promise(resolver) { 1401 this._status = STATUS_PENDING; 1402 this._handlers = []; 1403 try { 1404 resolver.call(this, this._resolve.bind(this), this._reject.bind(this)); 1405 } catch (e) { 1406 this._reject(e); 1407 } 1408 } 1409 1410 /** 1411 * Builds a promise that is resolved when all the passed in promises are 1412 * resolved. 1413 * @param {array} promises array of data and/or promises to wait for. 1414 * @return {Promise} New dependent promise. 1415 */ 1416 Promise.all = function Promise_all(promises) { 1417 var resolveAll, rejectAll; 1418 var deferred = new Promise(function (resolve, reject) { 1419 resolveAll = resolve; 1420 rejectAll = reject; 1421 }); 1422 var unresolved = promises.length; 1423 var results = []; 1424 if (unresolved === 0) { 1425 resolveAll(results); 1426 return deferred; 1427 } 1428 1429 function reject(reason) { 1430 if (deferred._status === STATUS_REJECTED) { 1431 return; 1432 } 1433 results = []; 1434 rejectAll(reason); 1435 } 1436 1437 for (var i = 0, ii = promises.length; i < ii; ++i) { 1438 var promise = promises[i]; 1439 var resolve = (function (i) { 1440 return function (value) { 1441 if (deferred._status === STATUS_REJECTED) { 1442 return; 1443 } 1444 results[i] = value; 1445 unresolved--; 1446 if (unresolved === 0) { 1447 resolveAll(results); 1448 } 1449 }; 1450 })(i); 1451 if (Promise.isPromise(promise)) { 1452 promise.then(resolve, reject); 1453 } else { 1454 resolve(promise); 1455 } 1456 } 1457 return deferred; 1458 }; 1459 1460 /** 1461 * Checks if the value is likely a promise (has a 'then' function). 1462 * @return {boolean} true if value is thenable 1463 */ 1464 Promise.isPromise = function Promise_isPromise(value) { 1465 return value && typeof value.then === 'function'; 1466 }; 1467 1468 /** 1469 * Creates resolved promise 1470 * @param value resolve value 1471 * @returns {Promise} 1472 */ 1473 Promise.resolve = function Promise_resolve(value) { 1474 return new Promise(function (resolve) { 1475 resolve(value); 1476 }); 1477 }; 1478 1479 /** 1480 * Creates rejected promise 1481 * @param reason rejection value 1482 * @returns {Promise} 1483 */ 1484 Promise.reject = function Promise_reject(reason) { 1485 return new Promise(function (resolve, reject) { 1486 reject(reason); 1487 }); 1488 }; 1489 1490 Promise.prototype = { 1491 _status: null, 1492 _value: null, 1493 _handlers: null, 1494 _unhandledRejection: null, 1495 1496 _updateStatus: function Promise__updateStatus(status, value) { 1497 if (this._status === STATUS_RESOLVED || this._status === STATUS_REJECTED) { 1498 return; 1499 } 1500 1501 if (status === STATUS_RESOLVED && Promise.isPromise(value)) { 1502 value.then( 1503 this._updateStatus.bind(this, STATUS_RESOLVED), 1504 this._updateStatus.bind(this, STATUS_REJECTED) 1505 ); 1506 return; 1507 } 1508 1509 this._status = status; 1510 this._value = value; 1511 1512 if (status === STATUS_REJECTED && this._handlers.length === 0) { 1513 this._unhandledRejection = true; 1514 HandlerManager.addUnhandledRejection(this); 1515 } 1516 1517 HandlerManager.scheduleHandlers(this); 1518 }, 1519 1520 _resolve: function Promise_resolve(value) { 1521 this._updateStatus(STATUS_RESOLVED, value); 1522 }, 1523 1524 _reject: function Promise_reject(reason) { 1525 this._updateStatus(STATUS_REJECTED, reason); 1526 }, 1527 1528 then: function Promise_then(onResolve, onReject) { 1529 var nextPromise = new Promise(function (resolve, reject) { 1530 this.resolve = resolve; 1531 this.reject = reject; 1532 }); 1533 this._handlers.push({ 1534 thisPromise: this, 1535 onResolve: onResolve, 1536 onReject: onReject, 1537 nextPromise: nextPromise, 1538 }); 1539 HandlerManager.scheduleHandlers(this); 1540 return nextPromise; 1541 }, 1542
1543 catch: function Promise_catch(onReject) { 1544 return this.then(undefined, onReject); 1545 }, 1546 }; 1547 1548 globalScope.Promise = Promise; 1549 })(); 1550 1551 (function WeakMapClosure() { 1552 if (globalScope.WeakMap) { 1553 return; 1554 } 1555 1556 var id = 0; 1557 1558 function WeakMap() { 1559 this.id = '$weakmap' + id++; 1560 } 1561 1562 WeakMap.prototype = { 1563 has: function (obj) { 1564 return !!Object.getOwnPropertyDescriptor(obj, this.id); 1565 }, 1566 get: function (obj, defaultValue) { 1567 return this.has(obj) ? obj[this.id] : defaultValue; 1568 }, 1569 set: function (obj, value) { 1570 Object.defineProperty(obj, this.id, { 1571 value: value, 1572 enumerable: false, 1573 configurable: true, 1574 }); 1575 }, 1576 delete: function (obj) { 1577 delete obj[this.id]; 1578 }, 1579 }; 1580 1581 globalScope.WeakMap = WeakMap; 1582 })(); 1583 1584 var StatTimer = (function StatTimerClosure() { 1585 function rpad(str, pad, length) { 1586 while (str.length < length) { 1587 str += pad; 1588 } 1589 return str; 1590 } 1591 1592 function StatTimer() { 1593 this.started = Object.create(null); 1594 this.times = []; 1595 this.enabled = true; 1596 } 1597 1598 StatTimer.prototype = { 1599 time: function StatTimer_time(name) { 1600 if (!this.enabled) { 1601 return; 1602 } 1603 if (name in this.started) { 1604 warn('Timer is already running for ' + name); 1605 } 1606 this.started[name] = Date.now(); 1607 }, 1608 timeEnd: function StatTimer_timeEnd(name) { 1609 if (!this.enabled) { 1610 return; 1611 } 1612 if (!(name in this.started)) { 1613 warn('Timer has not been started for ' + name); 1614 } 1615 this.times.push({ 1616 name: name, 1617 start: this.started[name], 1618 end: Date.now(), 1619 }); 1620 // Remove timer from started so it can be called again. 1621 delete this.started[name]; 1622 }, 1623 toString: function StatTimer_toString() { 1624 var i, ii; 1625 var times = this.times; 1626 var out = ''; 1627 // Find the longest name for padding purposes. 1628 var longest = 0; 1629 for (i = 0, ii = times.length; i < ii; ++i) { 1630 var name = times[i]['name']; 1631 if (name.length > longest) { 1632 longest = name.length; 1633 } 1634 } 1635 for (i = 0, ii = times.length; i < ii; ++i) { 1636 var span = times[i]; 1637 var duration = span.end - span.start; 1638 out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n'; 1639 } 1640 return out; 1641 }, 1642 }; 1643 return StatTimer; 1644 })(); 1645 1646 var createBlob = function createBlob(data, contentType) { 1647 if (typeof Blob !== 'undefined') { 1648 return new Blob([data], { type: contentType }); 1649 } 1650 warn('The "Blob" constructor is not supported.'); 1651 }; 1652 1653 var createObjectURL = (function createObjectURLClosure() { 1654 // Blob/createObjectURL is not available, falling back to data schema. 1655 var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; 1656 1657 return function createObjectURL(data, contentType, forceDataSchema) { 1658 if (!forceDataSchema && typeof URL !== 'undefined' && URL.createObjectURL) { 1659 var blob = createBlob(data, contentType); 1660 return URL.createObjectURL(blob); 1661 } 1662 1663 var buffer = 'data:' + contentType + ';base64,'; 1664 for (var i = 0, ii = data.length; i < ii; i += 3) { 1665 var b1 = data[i] & 0xff; 1666 var b2 = data[i + 1] & 0xff; 1667 var b3 = data[i + 2] & 0xff;
1668 var d1 = b1 >> 2, 1669 d2 = ((b1 & 3) << 4) | (b2 >> 4); 1670 var d3 = i + 1 < ii ? ((b2 & 0xf) << 2) | (b3 >> 6) : 64; 1671 var d4 = i + 2 < ii ? b3 & 0x3f : 64; 1672 buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; 1673 } 1674 return buffer; 1675 }; 1676 })(); 1677 1678 function MessageHandler(sourceName, targetName, comObj) { 1679 this.sourceName = sourceName; 1680 this.targetName = targetName; 1681 this.comObj = comObj; 1682 this.callbackIndex = 1; 1683 this.postMessageTransfers = true; 1684 var callbacksCapabilities = (this.callbacksCapabilities = Object.create(null)); 1685 var ah = (this.actionHandler = Object.create(null)); 1686 1687 this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) { 1688 var data = event.data; 1689 if (data.targetName !== this.sourceName) { 1690 return; 1691 } 1692 if (data.isReply) { 1693 var callbackId = data.callbackId; 1694 if (data.callbackId in callbacksCapabilities) { 1695 var callback = callbacksCapabilities[callbackId]; 1696 delete callbacksCapabilities[callbackId]; 1697 if ('error' in data) { 1698 callback.reject(data.error); 1699 } else { 1700 callback.resolve(data.data); 1701 } 1702 } else { 1703 error('Cannot resolve callback ' + callbackId); 1704 } 1705 } else if (data.action in ah) { 1706 var action = ah[data.action]; 1707 if (data.callbackId) { 1708 var sourceName = this.sourceName; 1709 var targetName = data.sourceName; 1710 Promise.resolve() 1711 .then(function () { 1712 return action[0].call(action[1], data.data); 1713 }) 1714 .then( 1715 function (result) { 1716 comObj.postMessage({ 1717 sourceName: sourceName, 1718 targetName: targetName, 1719 isReply: true, 1720 callbackId: data.callbackId, 1721 data: result, 1722 }); 1723 }, 1724 function (reason) { 1725 if (reason instanceof Error) { 1726 // Serialize error to avoid "DataCloneError" 1727 reason = reason + ''; 1728 } 1729 comObj.postMessage({ 1730 sourceName: sourceName, 1731 targetName: targetName, 1732 isReply: true, 1733 callbackId: data.callbackId, 1734 error: reason, 1735 }); 1736 } 1737 ); 1738 } else { 1739 action[0].call(action[1], data.data); 1740 } 1741 } else { 1742 error('Unknown action from worker: ' + data.action); 1743 } 1744 }.bind(this); 1745 comObj.addEventListener('message', this._onComObjOnMessage); 1746 } 1747 1748 MessageHandler.prototype = { 1749 on: function messageHandlerOn(actionName, handler, scope) { 1750 var ah = this.actionHandler; 1751 if (ah[actionName]) { 1752 error('There is already an actionName called "' + actionName + '"'); 1753 } 1754 ah[actionName] = [handler, scope]; 1755 }, 1756 /** 1757 * Sends a message to the comObj to invoke the action with the supplied data. 1758 * @param {String} actionName Action to call. 1759 * @param {JSON} data JSON data to send. 1760 * @param {Array} [transfers] Optional list of transfers/ArrayBuffers 1761 */ 1762 send: function messageHandlerSend(actionName, data, transfers) { 1763 var message = { 1764 sourceName: this.sourceName, 1765 targetName: this.targetName, 1766 action: actionName, 1767 data: data, 1768 }; 1769 this.postMessage(message, transfers); 1770 }, 1771 /** 1772 * Sends a message to the comObj to invoke the action with the supplied data. 1773 * Expects that other side will callback with the response. 1774 * @param {String} actionName Action to call. 1775 * @param {JSON} data JSON data to send. 1776 * @param {Array} [transfers] Optional list of transfers/ArrayBuffers. 1777 * @returns {Promise} Promise to be resolved with response data. 1778 */
1779 sendWithPromise: function messageHandlerSendWithPromise(actionName, data, transfers) { 1780 var callbackId = this.callbackIndex++; 1781 var message = { 1782 sourceName: this.sourceName, 1783 targetName: this.targetName, 1784 action: actionName, 1785 data: data, 1786 callbackId: callbackId, 1787 }; 1788 var capability = createPromiseCapability(); 1789 this.callbacksCapabilities[callbackId] = capability; 1790 try { 1791 this.postMessage(message, transfers); 1792 } catch (e) { 1793 capability.reject(e); 1794 } 1795 return capability.promise; 1796 }, 1797 /** 1798 * Sends raw message to the comObj. 1799 * @private 1800 * @param message {Object} Raw message. 1801 * @param transfers List of transfers/ArrayBuffers, or undefined. 1802 */ 1803 postMessage: function (message, transfers) { 1804 if (transfers && this.postMessageTransfers) { 1805 this.comObj.postMessage(message, transfers); 1806 } else { 1807 this.comObj.postMessage(message); 1808 } 1809 }, 1810 1811 destroy: function () { 1812 this.comObj.removeEventListener('message', this._onComObjOnMessage); 1813 }, 1814 }; 1815 1816 function loadJpegStream(id, imageUrl, objs) { 1817 var img = new Image(); 1818 img.onload = function loadJpegStream_onloadClosure() { 1819 objs.resolve(id, img); 1820 }; 1821 img.onerror = function loadJpegStream_onerrorClosure() { 1822 objs.resolve(id, null); 1823 warn('Error during JPEG image loading'); 1824 }; 1825 img.src = imageUrl; 1826 } 1827 1828 // Polyfill from https://github.com/Polymer/URL 1829 /* Any copyright is dedicated to the Public Domain. 1830 * http://creativecommons.org/publicdomain/zero/1.0/ */ 1831 (function checkURLConstructor(scope) { 1832 // feature detect for URL constructor 1833 var hasWorkingUrl = false; 1834 try { 1835 if (typeof URL === 'function' && typeof URL.prototype === 'object' && 'origin' in URL.prototype) { 1836 var u = new URL('b', 'http://a'); 1837 u.pathname = 'c%20d'; 1838 hasWorkingUrl = u.href === 'http://a/c%20d'; 1839 } 1840 } catch (e) {} 1841 1842 if (hasWorkingUrl) { 1843 return; 1844 } 1845 1846 var relative = Object.create(null); 1847 relative['ftp'] = 21; 1848 relative['file'] = 0; 1849 relative['gopher'] = 70; 1850 relative['http'] = 80; 1851 relative['https'] = 443; 1852 relative['ws'] = 80; 1853 relative['wss'] = 443; 1854 1855 var relativePathDotMapping = Object.create(null); 1856 relativePathDotMapping['%2e'] = '.'; 1857 relativePathDotMapping['.%2e'] = '..'; 1858 relativePathDotMapping['%2e.'] = '..'; 1859 relativePathDotMapping['%2e%2e'] = '..'; 1860 1861 function isRelativeScheme(scheme) { 1862 return relative[scheme] !== undefined; 1863 } 1864
1865 function invalid() { 1866 clear.call(this); 1867 this._isInvalid = true; 1868 } 1869 1870 function IDNAToASCII(h) { 1871 if ('' === h) { 1872 invalid.call(this); 1873 } 1874 // XXX 1875 return h.toLowerCase(); 1876 } 1877 1878 function percentEscape(c) { 1879 var unicode = c.charCodeAt(0); 1880 if ( 1881 unicode > 0x20 && 1882 unicode < 0x7f && 1883 // " # < > ? ` 1884 [0x22, 0x23, 0x3c, 0x3e, 0x3f, 0x60].indexOf(unicode) === -1 1885 ) { 1886 return c; 1887 } 1888 return encodeURIComponent(c); 1889 } 1890 1891 function percentEscapeQuery(c) { 1892 // XXX This actually needs to encode c using encoding and then 1893 // convert the bytes one-by-one. 1894 1895 var unicode = c.charCodeAt(0); 1896 if ( 1897 unicode > 0x20 && 1898 unicode < 0x7f && 1899 // " # < > ` (do not escape '?') 1900 [0x22, 0x23, 0x3c, 0x3e, 0x60].indexOf(unicode) === -1 1901 ) { 1902 return c; 1903 } 1904 return encodeURIComponent(c); 1905 } 1906 1907 var EOF, 1908 ALPHA = /[a-zA-Z]/, 1909 ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/; 1910 1911 function parse(input, stateOverride, base) { 1912 function err(message) { 1913 errors.push(message); 1914 } 1915 1916 var state = stateOverride || 'scheme start', 1917 cursor = 0, 1918 buffer = '', 1919 seenAt = false, 1920 seenBracket = false, 1921 errors = []; 1922 1923 loop: while ((input[cursor - 1] !== EOF || cursor === 0) && !this._isInvalid) { 1924 var c = input[cursor]; 1925 switch (state) { 1926 case 'scheme start': 1927 if (c && ALPHA.test(c)) { 1928 buffer += c.toLowerCase(); // ASCII-safe 1929 state = 'scheme'; 1930 } else if (!stateOverride) { 1931 buffer = ''; 1932 state = 'no scheme'; 1933 continue; 1934 } else { 1935 err('Invalid scheme.'); 1936 break loop; 1937 } 1938 break; 1939 1940 case 'scheme': 1941 if (c && ALPHANUMERIC.test(c)) { 1942 buffer += c.toLowerCase(); // ASCII-safe 1943 } else if (':' === c) { 1944 this._scheme = buffer; 1945 buffer = ''; 1946 if (stateOverride) { 1947 break loop; 1948 } 1949 if (isRelativeScheme(this._scheme)) { 1950 this._isRelative = true; 1951 } 1952 if ('file' === this._scheme) { 1953 state = 'relative'; 1954 } else if (this._isRelative && base && base._scheme === this._scheme) { 1955 state = 'relative or authority'; 1956 } else if (this._isRelative) { 1957 state = 'authority first slash'; 1958 } else { 1959 state = 'scheme data'; 1960 } 1961 } else if (!stateOverride) { 1962 buffer = ''; 1963 cursor = 0; 1964 state = 'no scheme'; 1965 continue; 1966 } else if (EOF === c) { 1967 break loop; 1968 } else { 1969 err('Code point not allowed in scheme: ' + c); 1970 break loop; 1971 } 1972 break; 1973 1974 case 'scheme data': 1975 if ('?' === c) { 1976 this._query = '?'; 1977 state = 'query'; 1978 } else if ('#' === c) { 1979 this._fragment = '#'; 1980 state = 'fragment'; 1981 } else { 1982 // XXX error handling 1983 if (EOF !== c && '\t' !== c && '\n' !== c && '\r' !== c) { 1984 this._schemeData += percentEscape(c); 1985 } 1986 } 1987 break; 1988 1989 case 'no scheme': 1990 if (!base || !isRelativeScheme(base._scheme)) { 1991 err('Missing scheme.'); 1992 invalid.call(this); 1993 } else { 1994 state = 'relative'; 1995 continue; 1996 } 1997 break; 1998 1999 case 'relative or authority': 2000 if ('/' === c && '/' === input[cursor + 1]) { 2001 state = 'authority ignore slashes'; 2002 } else { 2003 err('Expected /, got: ' + c); 2004 state = 'relative'; 2005 continue; 2006 } 2007 break; 2008 2009 case 'relative': 2010 this._isRelative = true; 2011 if ('file' !== this._scheme) { 2012 this._scheme = base._scheme; 2013 } 2014 if (EOF === c) { 2015 this._host = base._host; 2016 this._port = base._port; 2017 this._path = base._path.slice(); 2018 this._query = base._query; 2019 this._username = base._username; 2020 this._password = base._password; 2021 break loop; 2022 } else if ('/' === c || '\\' === c) { 2023 if ('\\' === c) {
2024 err('\\ is an invalid code point.'); 2025 } 2026 state = 'relative slash'; 2027 } else if ('?' === c) { 2028 this._host = base._host; 2029 this._port = base._port; 2030 this._path = base._path.slice(); 2031 this._query = '?'; 2032 this._username = base._username; 2033 this._password = base._password; 2034 state = 'query'; 2035 } else if ('#' === c) { 2036 this._host = base._host; 2037 this._port = base._port; 2038 this._path = base._path.slice(); 2039 this._query = base._query; 2040 this._fragment = '#'; 2041 this._username = base._username; 2042 this._password = base._password; 2043 state = 'fragment'; 2044 } else { 2045 var nextC = input[cursor + 1]; 2046 var nextNextC = input[cursor + 2]; 2047 if ( 2048 'file' !== this._scheme || 2049 !ALPHA.test(c) || 2050 (nextC !== ':' && nextC !== '|') || 2051 (EOF !== nextNextC && 2052 '/' !== nextNextC && 2053 '\\' !== nextNextC && 2054 '?' !== nextNextC && 2055 '#' !== nextNextC) 2056 ) { 2057 this._host = base._host; 2058 this._port = base._port; 2059 this._username = base._username; 2060 this._password = base._password; 2061 this._path = base._path.slice(); 2062 this._path.pop(); 2063 } 2064 state = 'relative path'; 2065 continue; 2066 } 2067 break; 2068 2069 case 'relative slash': 2070 if ('/' === c || '\\' === c) { 2071 if ('\\' === c) { 2072 err('\\ is an invalid code point.'); 2073 } 2074 if ('file' === this._scheme) { 2075 state = 'file host'; 2076 } else { 2077 state = 'authority ignore slashes'; 2078 } 2079 } else { 2080 if ('file' !== this._scheme) { 2081 this._host = base._host; 2082 this._port = base._port; 2083 this._username = base._username; 2084 this._password = base._password; 2085 } 2086 state = 'relative path'; 2087 continue; 2088 } 2089 break; 2090 2091 case 'authority first slash': 2092 if ('/' === c) { 2093 state = 'authority second slash'; 2094 } else { 2095 err("Expected '/', got: " + c); 2096 state = 'authority ignore slashes'; 2097 continue; 2098 } 2099 break; 2100 2101 case 'authority second slash': 2102 state = 'authority ignore slashes'; 2103 if ('/' !== c) { 2104 err("Expected '/', got: " + c); 2105 continue; 2106 } 2107 break; 2108 2109 case 'authority ignore slashes': 2110 if ('/' !== c && '\\' !== c) { 2111 state = 'authority'; 2112 continue; 2113 } else { 2114 err('Expected authority, got: ' + c); 2115 } 2116 break; 2117 2118 case 'authority': 2119 if ('@' === c) { 2120 if (seenAt) { 2121 err('@ already seen.'); 2122 buffer += '%40'; 2123 } 2124 seenAt = true; 2125 for (var i = 0; i < buffer.length; i++) { 2126 var cp = buffer[i]; 2127 if ('\t' === cp || '\n' === cp || '\r' === cp) { 2128 err('Invalid whitespace in authority.'); 2129 continue; 2130 } 2131 // XXX check URL code points 2132 if (':' === cp && null === this._password) { 2133 this._password = ''; 2134 continue; 2135 } 2136 var tempC = percentEscape(cp); 2137 if (null !== this._password) { 2138 this._password += tempC; 2139 } else { 2140 this._username += tempC; 2141 } 2142 } 2143 buffer = ''; 2144 } else if (EOF === c || '/' === c || '\\' === c || '?' === c || '#' === c) { 2145 cursor -= buffer.length; 2146 buffer = ''; 2147 state = 'host'; 2148 continue; 2149 } else { 2150 buffer += c; 2151 } 2152 break; 2153 2154 case 'file host': 2155 if (EOF === c || '/' === c || '\\' === c || '?' === c || '#' === c) { 2156 if (buffer.length === 2 && ALPHA.test(buffer[0]) && (buffer[1] === ':' || buffer[1] === '|')) { 2157 state = 'relative path'; 2158 } else if (buffer.length === 0) { 2159 state = 'relative path start'; 2160 } else {
2161 this._host = IDNAToASCII.call(this, buffer); 2162 buffer = ''; 2163 state = 'relative path start'; 2164 } 2165 continue; 2166 } else if ('\t' === c || '\n' === c || '\r' === c) { 2167 err('Invalid whitespace in file host.'); 2168 } else { 2169 buffer += c; 2170 } 2171 break; 2172 2173 case 'host': 2174 case 'hostname': 2175 if (':' === c && !seenBracket) { 2176 // XXX host parsing 2177 this._host = IDNAToASCII.call(this, buffer); 2178 buffer = ''; 2179 state = 'port'; 2180 if ('hostname' === stateOverride) { 2181 break loop; 2182 } 2183 } else if (EOF === c || '/' === c || '\\' === c || '?' === c || '#' === c) { 2184 this._host = IDNAToASCII.call(this, buffer); 2185 buffer = ''; 2186 state = 'relative path start'; 2187 if (stateOverride) { 2188 break loop; 2189 } 2190 continue; 2191 } else if ('\t' !== c && '\n' !== c && '\r' !== c) { 2192 if ('[' === c) { 2193 seenBracket = true; 2194 } else if (']' === c) { 2195 seenBracket = false; 2196 } 2197 buffer += c; 2198 } else { 2199 err('Invalid code point in host/hostname: ' + c); 2200 } 2201 break; 2202 2203 case 'port': 2204 if (/[0-9]/.test(c)) { 2205 buffer += c; 2206 } else if (EOF === c || '/' === c || '\\' === c || '?' === c || '#' === c || stateOverride) { 2207 if ('' !== buffer) { 2208 var temp = parseInt(buffer, 10); 2209 if (temp !== relative[this._scheme]) { 2210 this._port = temp + ''; 2211 } 2212 buffer = ''; 2213 } 2214 if (stateOverride) { 2215 break loop; 2216 } 2217 state = 'relative path start'; 2218 continue; 2219 } else if ('\t' === c || '\n' === c || '\r' === c) { 2220 err('Invalid code point in port: ' + c); 2221 } else { 2222 invalid.call(this); 2223 } 2224 break; 2225 2226 case 'relative path start': 2227 if ('\\' === c) { 2228 err("'\\' not allowed in path."); 2229 } 2230 state = 'relative path'; 2231 if ('/' !== c && '\\' !== c) { 2232 continue; 2233 } 2234 break; 2235 2236 case 'relative path': 2237 if (EOF === c || '/' === c || '\\' === c || (!stateOverride && ('?' === c || '#' === c))) { 2238 if ('\\' === c) { 2239 err('\\ not allowed in relative path.'); 2240 } 2241 var tmp; 2242 if ((tmp = relativePathDotMapping[buffer.toLowerCase()])) { 2243 buffer = tmp; 2244 } 2245 if ('..' === buffer) { 2246 this._path.pop(); 2247 if ('/' !== c && '\\' !== c) { 2248 this._path.push(''); 2249 } 2250 } else if ('.' === buffer && '/' !== c && '\\' !== c) { 2251 this._path.push(''); 2252 } else if ('.' !== buffer) { 2253 if ( 2254 'file' === this._scheme && 2255 this._path.length === 0 && 2256 buffer.length === 2 && 2257 ALPHA.test(buffer[0]) && 2258 buffer[1] === '|' 2259 ) { 2260 buffer = buffer[0] + ':'; 2261 } 2262 this._path.push(buffer); 2263 } 2264 buffer = ''; 2265 if ('?' === c) { 2266 this._query = '?'; 2267 state = 'query'; 2268 } else if ('#' === c) { 2269 this._fragment = '#'; 2270 state = 'fragment'; 2271 } 2272 } else if ('\t' !== c && '\n' !== c && '\r' !== c) { 2273 buffer += percentEscape(c); 2274 } 2275 break; 2276 2277 case 'query': 2278 if (!stateOverride && '#' === c) { 2279 this._fragment = '#'; 2280 state = 'fragment'; 2281 }
2281 else if (EOF !== c && '\t' !== c && '\n' !== c && '\r' !== c) { 2282 this._query += percentEscapeQuery(c); 2283 } 2284 break; 2285 2286 case 'fragment': 2287 if (EOF !== c && '\t' !== c && '\n' !== c && '\r' !== c) { 2288 this._fragment += c; 2289 } 2290 break; 2291 } 2292 2293 cursor++; 2294 } 2295 } 2296 2297 function clear() { 2298 this._scheme = ''; 2299 this._schemeData = ''; 2300 this._username = ''; 2301 this._password = null; 2302 this._host = ''; 2303 this._port = ''; 2304 this._path = []; 2305 this._query = ''; 2306 this._fragment = ''; 2307 this._isInvalid = false; 2308 this._isRelative = false; 2309 } 2310 2311 // Does not process domain names or IP addresses. 2312 // Does not handle encoding for the query parameter. 2313 function JURL(url, base /* , encoding */) { 2314 if (base !== undefined && !(base instanceof JURL)) { 2315 base = new JURL(String(base)); 2316 } 2317 2318 this._url = url; 2319 clear.call(this); 2320 2321 var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, ''); 2322 // encoding = encoding || 'utf-8' 2323 2324 parse.call(this, input, null, base); 2325 } 2326 2327 JURL.prototype = { 2328 toString: function () { 2329 return this.href; 2330 }, 2331 get href() { 2332 if (this._isInvalid) { 2333 return this._url; 2334 } 2335 var authority = ''; 2336 if ('' !== this._username || null !== this._password) { 2337 authority = this._username + (null !== this._password ? ':' + this._password : '') + '@'; 2338 } 2339 2340 return ( 2341 this.protocol + 2342 (this._isRelative ? '//' + authority + this.host : '') + 2343 this.pathname + 2344 this._query + 2345 this._fragment 2346 ); 2347 }, 2348 set href(href) { 2349 clear.call(this); 2350 parse.call(this, href); 2351 }, 2352 2353 get protocol() { 2354 return this._scheme + ':'; 2355 }, 2356 set protocol(protocol) { 2357 if (this._isInvalid) { 2358 return; 2359 } 2360 parse.call(this, protocol + ':', 'scheme start'); 2361 }, 2362 2363 get host() { 2364 return this._isInvalid ? '' : this._port ? this._host + ':' + this._port : this._host; 2365 }, 2366 set host(host) { 2367 if (this._isInvalid || !this._isRelative) { 2368 return; 2369 } 2370 parse.call(this, host, 'host'); 2371 }, 2372 2373 get hostname() { 2374 return this._host; 2375 }, 2376 set hostname(hostname) { 2377 if (this._isInvalid || !this._isRelative) { 2378 return; 2379 } 2380 parse.call(this, hostname, 'hostname'); 2381 }, 2382 2383 get port() { 2384 return this._port; 2385 }, 2386 set port(port) { 2387 if (this._isInvalid || !this._isRelative) { 2388 return; 2389 } 2390 parse.call(this, port, 'port'); 2391 }, 2392 2393 get pathname() { 2394 return this._isInvalid ? '' : this._isRelative ? '/' + this._path.join('/') : this._schemeData; 2395 }, 2396 set pathname(pathname) { 2397 if (this._isInvalid || !this._isRelative) { 2398 return; 2399 } 2400 this._path = []; 2401 parse.call(this, pathname, 'relative path start'); 2402 }, 2403 2404 get search() { 2405 return this._isInvalid || !this._query || '?' === this._query ? '' : this._query; 2406 }, 2407 set search(search) { 2408 if (this._isInvalid || !this._isRelative) { 2409 return; 2410 } 2411 this._query = '?'; 2412 if ('?' === search[0]) { 2413 search = search.slice(1); 2414 } 2415 parse.call(this, search, 'query'); 2416 }, 2417 2418 get hash() { 2419 return this._isInvalid || !this._fragment || '#' === this._fragment ? '' : this._fragment; 2420 }, 2421 set hash(hash) { 2422 if (this._isInvalid) { 2423 return; 2424 } 2425 this._fragment = '#'; 2426 if ('#' === hash[0]) { 2427 hash = hash.slice(1); 2428 } 2429 parse.call(this, hash, 'fragment'); 2430 }, 2431 2432 get origin() { 2433 var host; 2434 if (this._isInvalid || !this._scheme) { 2435 return ''; 2436 } 2437 // javascript: Gecko returns String(""), WebKit/Blink String("null") 2438 // Gecko throws error for "data://" 2439 // data: Gecko returns "", Blink returns "data://", WebKit returns "null" 2440 // Gecko returns String("") for file: mailto: 2441 // WebKit/Blink returns String("SCHEME://") for file: mailto: 2442 switch (this._scheme) { 2443 case 'data': 2444 case 'file': 2445 case 'javascript': 2446 case 'mailto': 2447 return 'null';
2448 } 2449 host = this.host; 2450 if (!host) { 2451 return ''; 2452 } 2453 return this._scheme + '://' + host; 2454 }, 2455 }; 2456 2457 // Copy over the static methods 2458 var OriginalURL = scope.URL; 2459 if (OriginalURL) { 2460 JURL.createObjectURL = function (blob) { 2461 // IE extension allows a second optional options argument. 2462 // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx 2463 return OriginalURL.createObjectURL.apply(OriginalURL, arguments); 2464 }; 2465 JURL.revokeObjectURL = function (url) { 2466 OriginalURL.revokeObjectURL(url); 2467 }; 2468 } 2469 2470 scope.URL = JURL; 2471 })(globalScope); 2472 2473 exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX; 2474 exports.IDENTITY_MATRIX = IDENTITY_MATRIX; 2475 exports.OPS = OPS; 2476 exports.VERBOSITY_LEVELS = VERBOSITY_LEVELS; 2477 exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; 2478 exports.AnnotationBorderStyleType = AnnotationBorderStyleType; 2479 exports.AnnotationFieldFlag = AnnotationFieldFlag; 2480 exports.AnnotationFlag = AnnotationFlag; 2481 exports.AnnotationType = AnnotationType; 2482 exports.FontType = FontType; 2483 exports.ImageKind = ImageKind; 2484 exports.InvalidPDFException = InvalidPDFException; 2485 exports.MessageHandler = MessageHandler; 2486 exports.MissingDataException = MissingDataException; 2487 exports.MissingPDFException = MissingPDFException; 2488 exports.NotImplementedException = NotImplementedException; 2489 exports.PageViewport = PageViewport; 2490 exports.PasswordException = PasswordException; 2491 exports.PasswordResponses = PasswordResponses; 2492 exports.StatTimer = StatTimer; 2493 exports.StreamType = StreamType; 2494 exports.TextRenderingMode = TextRenderingMode; 2495 exports.UnexpectedResponseException = UnexpectedResponseException; 2496 exports.UnknownErrorException = UnknownErrorException; 2497 exports.Util = Util; 2498 exports.XRefParseException = XRefParseException; 2499 exports.arrayByteLength = arrayByteLength; 2500 exports.arraysToBytes = arraysToBytes; 2501 exports.assert = assert; 2502 exports.bytesToString = bytesToString; 2503 exports.createBlob = createBlob; 2504 exports.createPromiseCapability = createPromiseCapability; 2505 exports.createObjectURL = createObjectURL; 2506 exports.deprecated = deprecated; 2507 exports.error = error; 2508 exports.getLookupTableFactory = getLookupTableFactory; 2509 exports.getVerbosityLevel = getVerbosityLevel; 2510 exports.globalScope = globalScope; 2511 exports.info = info; 2512 exports.isArray = isArray; 2513 exports.isArrayBuffer = isArrayBuffer; 2514 exports.isBool = isBool; 2515 exports.isEmptyObj = isEmptyObj; 2516 exports.isInt = isInt; 2517 exports.isNum = isNum; 2518 exports.isString = isString; 2519 exports.isSpace = isSpace; 2520 exports.isSameOrigin = isSameOrigin; 2521 exports.isValidUrl = isValidUrl; 2522 exports.isLittleEndian = isLittleEndian; 2523 exports.isEvalSupported = isEvalSupported; 2524 exports.loadJpegStream = loadJpegStream; 2525 exports.log2 = log2; 2526 exports.readInt8 = readInt8; 2527 exports.readUint16 = readUint16; 2528 exports.readUint32 = readUint32; 2529 exports.removeNullCharacters = removeNullCharacters; 2530 exports.setVerbosityLevel = setVerbosityLevel; 2531 exports.shadow = shadow; 2532 exports.string32 = string32; 2533 exports.stringToBytes = stringToBytes; 2534 exports.stringToPDFString = stringToPDFString; 2535 exports.stringToUTF8String = stringToUTF8String; 2536 exports.utf8StringToString = utf8StringToString; 2537 exports.warn = warn; 2538 }); 2539 2540 (function (root, factory) { 2541 { 2542 factory((root.pdfjsDisplayDOMUtils = {}), root.pdfjsSharedUtil); 2543 } 2544 })(this, function (exports, sharedUtil) { 2545 var removeNullCharacters = sharedUtil.removeNullCharacters; 2546 var warn = sharedUtil.warn; 2547 2548 /** 2549 * Optimised CSS custom property getter/setter. 2550 * @class 2551 */ 2552 var CustomStyle = (function CustomStyleClosure() { 2553 // As noted on: http://www.zachstronaut.com/posts/2009/02/17/ 2554 // animate-css-transforms-firefox-webkit.html 2555 // in some versions of IE9 it is critical that ms appear in this list 2556 // before Moz 2557 var prefixes = ['ms', 'Moz', 'Webkit', 'O']; 2558 var _cache = Object.create(null); 2559 2560 function CustomStyle() {} 2561 2562 CustomStyle.getProp = function get(propName, element) { 2563 // check cache only when no element is given
2564 if (arguments.length === 1 && typeof _cache[propName] === 'string') { 2565 return _cache[propName]; 2566 } 2567 2568 element = element || document.documentElement; 2569 var style = element.style, 2570 prefixed, 2571 uPropName; 2572 2573 // test standard property first 2574 if (typeof style[propName] === 'string') { 2575 return (_cache[propName] = propName); 2576 } 2577 2578 // capitalize 2579 uPropName = propName.charAt(0).toUpperCase() + propName.slice(1); 2580 2581 // test vendor specific properties 2582 for (var i = 0, l = prefixes.length; i < l; i++) { 2583 prefixed = prefixes[i] + uPropName; 2584 if (typeof style[prefixed] === 'string') { 2585 return (_cache[propName] = prefixed); 2586 } 2587 } 2588 2589 //if all fails then set to undefined 2590 return (_cache[propName] = 'undefined'); 2591 }; 2592 2593 CustomStyle.setProp = function set(propName, element, str) { 2594 var prop = this.getProp(propName); 2595 if (prop !== 'undefined') { 2596 element.style[prop] = str; 2597 } 2598 }; 2599 2600 return CustomStyle; 2601 })(); 2602 2603 function hasCanvasTypedArrays() { 2604 var canvas = document.createElement('canvas'); 2605 canvas.width = canvas.height = 1; 2606 var ctx = canvas.getContext('2d'); 2607 var imageData = ctx.createImageData(1, 1); 2608 return typeof imageData.data.buffer !== 'undefined'; 2609 } 2610 2611 var LinkTarget = { 2612 NONE: 0, // Default value. 2613 SELF: 1, 2614 BLANK: 2, 2615 PARENT: 3, 2616 TOP: 4, 2617 }; 2618 2619 var LinkTargetStringMap = ['', '_self', '_blank', '_parent', '_top']; 2620 2621 /** 2622 * @typedef ExternalLinkParameters 2623 * @typedef {Object} ExternalLinkParameters 2624 * @property {string} url - An absolute URL. 2625 * @property {LinkTarget} target - The link target. 2626 * @property {string} rel - The link relationship. 2627 */ 2628 2629 /** 2630 * Adds various attributes (href, title, target, rel) to hyperlinks. 2631 * @param {HTMLLinkElement} link - The link element. 2632 * @param {ExternalLinkParameters} params 2633 */ 2634 function addLinkAttributes(link, params) { 2635 var url = params && params.url; 2636 link.href = link.title = url ? removeNullCharacters(url) : ''; 2637 2638 if (url) { 2639 var target = params.target; 2640 if (typeof target === 'undefined') { 2641 target = getDefaultSetting('externalLinkTarget'); 2642 } 2643 link.target = LinkTargetStringMap[target]; 2644 2645 var rel = params.rel; 2646 if (typeof rel === 'undefined') { 2647 rel = getDefaultSetting('externalLinkRel'); 2648 } 2649 link.rel = rel; 2650 } 2651 } 2652 2653 // Gets the file name from a given URL. 2654 function getFilenameFromUrl(url) { 2655 var anchor = url.indexOf('#'); 2656 var query = url.indexOf('?'); 2657 var end = Math.min(anchor > 0 ? anchor : url.length, query > 0 ? query : url.length); 2658 return url.substring(url.lastIndexOf('/', end) + 1, end); 2659 } 2660 2661 function getDefaultSetting(id) { 2662 // The list of the settings and their default is maintained for backward 2663 // compatibility and shall not be extended or modified. See also global.js. 2664 var globalSettings = sharedUtil.globalScope.PDFJS; 2665 switch (id) { 2666 case 'pdfBug': 2667 return globalSettings ? globalSettings.pdfBug : false; 2668 case 'disableAutoFetch': 2669 return globalSettings ? globalSettings.disableAutoFetch : false; 2670 case 'disableStream': 2671 return globalSettings ? globalSettings.disableStream : false; 2672 case 'disableRange': 2673 return globalSettings ? globalSettings.disableRange : false; 2674 case 'disableFontFace': 2675 return globalSettings ? globalSettings.disableFontFace : false; 2676 case 'disableCreateObjectURL': 2677 return globalSettings ? globalSettings.disableCreateObjectURL : false; 2678 case 'disableWebGL': 2679 return globalSettings ? globalSettings.disableWebGL : true; 2680 case 'cMapUrl': 2681 return globalSettings ? globalSettings.cMapUrl : null; 2682 case 'cMapPacked': 2683 return globalSettings ? globalSettings.cMapPacked : false;
2684 case 'postMessageTransfers': 2685 return globalSettings ? globalSettings.postMessageTransfers : true; 2686 case 'workerSrc': 2687 return globalSettings ? globalSettings.workerSrc : null; 2688 case 'disableWorker': 2689 return globalSettings ? globalSettings.disableWorker : false; 2690 case 'maxImageSize': 2691 return globalSettings ? globalSettings.maxImageSize : -1; 2692 case 'imageResourcesPath': 2693 return globalSettings ? globalSettings.imageResourcesPath : ''; 2694 case 'isEvalSupported': 2695 return globalSettings ? globalSettings.isEvalSupported : true; 2696 case 'externalLinkTarget': 2697 if (!globalSettings) { 2698 return LinkTarget.NONE; 2699 } 2700 switch (globalSettings.externalLinkTarget) { 2701 case LinkTarget.NONE: 2702 case LinkTarget.SELF: 2703 case LinkTarget.BLANK: 2704 case LinkTarget.PARENT: 2705 case LinkTarget.TOP: 2706 return globalSettings.externalLinkTarget; 2707 } 2708 warn('PDFJS.externalLinkTarget is invalid: ' + globalSettings.externalLinkTarget); 2709 // Reset the external link target, to suppress further warnings. 2710 globalSettings.externalLinkTarget = LinkTarget.NONE; 2711 return LinkTarget.NONE; 2712 case 'externalLinkRel': 2713 return globalSettings ? globalSettings.externalLinkRel : 'noreferrer'; 2714 case 'enableStats': 2715 return !!(globalSettings && globalSettings.enableStats); 2716 default: 2717 throw new Error('Unknown default setting: ' + id); 2718 } 2719 } 2720 2721 function isExternalLinkTargetSet() { 2722 var externalLinkTarget = getDefaultSetting('externalLinkTarget'); 2723 switch (externalLinkTarget) { 2724 case LinkTarget.NONE: 2725 return false; 2726 case LinkTarget.SELF: 2727 case LinkTarget.BLANK: 2728 case LinkTarget.PARENT: 2729 case LinkTarget.TOP: 2730 return true; 2731 } 2732 } 2733 2734 exports.CustomStyle = CustomStyle; 2735 exports.addLinkAttributes = addLinkAttributes; 2736 exports.isExternalLinkTargetSet = isExternalLinkTargetSet; 2737 exports.getFilenameFromUrl = getFilenameFromUrl; 2738 exports.LinkTarget = LinkTarget; 2739 exports.hasCanvasTypedArrays = hasCanvasTypedArrays; 2740 exports.getDefaultSetting = getDefaultSetting; 2741 }); 2742 2743 (function (root, factory) { 2744 { 2745 factory((root.pdfjsDisplayFontLoader = {}), root.pdfjsSharedUtil); 2746 } 2747 })(this, function (exports, sharedUtil) { 2748 var assert = sharedUtil.assert; 2749 var bytesToString = sharedUtil.bytesToString; 2750 var string32 = sharedUtil.string32; 2751 var shadow = sharedUtil.shadow; 2752 var warn = sharedUtil.warn; 2753 2754 function FontLoader(docId) { 2755 this.docId = docId; 2756 this.styleElement = null; 2757 this.nativeFontFaces = []; 2758 this.loadTestFontId = 0; 2759 this.loadingContext = { 2760 requests: [], 2761 nextRequestId: 0, 2762 }; 2763 } 2764 2765 FontLoader.prototype = { 2766 insertRule: function fontLoaderInsertRule(rule) { 2767 var styleElement = this.styleElement; 2768 if (!styleElement) { 2769 styleElement = this.styleElement = document.createElement('style'); 2770 styleElement.id = 'PDFJS_FONT_STYLE_TAG_' + this.docId; 2771 document.documentElement.getElementsByTagName('head')[0].appendChild(styleElement); 2772 } 2773 2774 var styleSheet = styleElement.sheet; 2775 styleSheet.insertRule(rule, styleSheet.cssRules.length); 2776 }, 2777 2778 clear: function fontLoaderClear() { 2779 var styleElement = this.styleElement; 2780 if (styleElement) { 2781 styleElement.parentNode.removeChild(styleElement); 2782 styleElement = this.styleElement = null; 2783 } 2784 this.nativeFontFaces.forEach(function (nativeFontFace) { 2785 document.fonts.delete(nativeFontFace); 2786 }); 2787 this.nativeFontFaces.length = 0; 2788 }, 2789 get loadTestFont() { 2790 // This is a CFF font with 1 glyph for '.' that fills its entire width and 2791 // height. 2792 return shadow( 2793 this, 2794 'loadTestFont', 2795 atob( 2796 'T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQAFQ' + 2797 'AABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAAALwA' + 2798 'AAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgAAAAGbm' + 2799 'FtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1AAsD6AAA' + 2800 'AADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD6AAAAAAD6A' + 2801 'ABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACMAooCvAAAAeAA' + 2802 'MQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4DIP84AFoDIQAAAA' + 2803 'AAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAA' + 2804 'AAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQ' + 2805 'AAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgABAAMAAQQJAAMAAgABAAMA' + 2806 'AQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABYAAAAAAAAAwAAAAMAAAAcAA' + 2807 'EAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAAAC7////TAAEAAAAAAAABBgAA' + 2808 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAA' + 2809 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + 2810 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + 2811 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + 2812 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAA' + 2813 'AAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAAAAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgc' + 2814 'A/gXBIwMAYuL+nz5tQXkD5j3CBLnEQACAQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWF' + 2815 'hYWFhYWFhYAAABAQAADwACAQEEE/t3Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQA' + 2816 'AAAAAAABAAAAAMmJbzEAAAAAzgTjFQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAg' + 2817 'ABAAAAAAAAAAAD6AAAAAAAAA==' 2818 ) 2819 ); 2820 }, 2821 2822 addNativeFontFace: function fontLoader_addNativeFontFace(nativeFontFace) { 2823 this.nativeFontFaces.push(nativeFontFace); 2824 document.fonts.add(nativeFontFace); 2825 }, 2826 2827 bind: function fontLoaderBind(fonts, callback) { 2828 var rules = []; 2829 var fontsToLoad = [];
2830 var fontLoadPromises = []; 2831 var getNativeFontPromise = function (nativeFontFace) { 2832 // Return a promise that is always fulfilled, even when the font fails to 2833 // load. 2834 return nativeFontFace.loaded.catch(function (e) { 2835 warn('Failed to load font "' + nativeFontFace.family + '": ' + e); 2836 }); 2837 }; 2838 for (var i = 0, ii = fonts.length; i < ii; i++) { 2839 var font = fonts[i]; 2840 2841 // Add the font to the DOM only once or skip if the font 2842 // is already loaded. 2843 if (font.attached || font.loading === false) { 2844 continue; 2845 } 2846 font.attached = true; 2847 2848 if (FontLoader.isFontLoadingAPISupported) { 2849 var nativeFontFace = font.createNativeFontFace(); 2850 if (nativeFontFace) { 2851 this.addNativeFontFace(nativeFontFace); 2852 fontLoadPromises.push(getNativeFontPromise(nativeFontFace)); 2853 } 2854 } else { 2855 var rule = font.createFontFaceRule(); 2856 if (rule) { 2857 this.insertRule(rule); 2858 rules.push(rule); 2859 fontsToLoad.push(font); 2860 } 2861 } 2862 } 2863 2864 var request = this.queueLoadingCallback(callback); 2865 if (FontLoader.isFontLoadingAPISupported) { 2866 Promise.all(fontLoadPromises).then(function () { 2867 request.complete(); 2868 }); 2869 } else if (rules.length > 0 && !FontLoader.isSyncFontLoadingSupported) { 2870 this.prepareFontLoadEvent(rules, fontsToLoad, request); 2871 } else { 2872 request.complete(); 2873 } 2874 }, 2875 2876 queueLoadingCallback: function FontLoader_queueLoadingCallback(callback) { 2877 function LoadLoader_completeRequest() { 2878 assert(!request.end, 'completeRequest() cannot be called twice'); 2879 request.end = Date.now(); 2880 2881 // sending all completed requests in order how they were queued 2882 while (context.requests.length > 0 && context.requests[0].end) { 2883 var otherRequest = context.requests.shift(); 2884 setTimeout(otherRequest.callback, 0); 2885 } 2886 } 2887 2888 var context = this.loadingContext; 2889 var requestId = 'pdfjs-font-loading-' + context.nextRequestId++; 2890 var request = { 2891 id: requestId, 2892 complete: LoadLoader_completeRequest, 2893 callback: callback, 2894 started: Date.now(), 2895 }; 2896 context.requests.push(request); 2897 return request; 2898 }, 2899 2900 prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules, fonts, request) { 2901 /** Hack begin */ 2902 // There's currently no event when a font has finished downloading so the 2903 // following code is a dirty hack to 'guess' when a font is 2904 // ready. It's assumed fonts are loaded in order, so add a known test 2905 // font after the desired fonts and then test for the loading of that 2906 // test font. 2907 2908 function int32(data, offset) { 2909 return ( 2910 (data.charCodeAt(offset) << 24) | 2911 (data.charCodeAt(offset + 1) << 16) | 2912 (data.charCodeAt(offset + 2) << 8) | 2913 (data.charCodeAt(offset + 3) & 0xff) 2914 ); 2915 } 2916 2917 function spliceString(s, offset, remove, insert) { 2918 var chunk1 = s.substr(0, offset); 2919 var chunk2 = s.substr(offset + remove); 2920 return chunk1 + insert + chunk2; 2921 } 2922 2923 var i, ii; 2924 2925 var canvas = document.createElement('canvas'); 2926 canvas.width = 1; 2927 canvas.height = 1; 2928 var ctx = canvas.getContext('2d'); 2929 2930 var called = 0; 2931 2932 function isFontReady(name, callback) { 2933 called++;
2934 // With setTimeout clamping this gives the font ~100ms to load. 2935 if (called > 30) { 2936 warn('Load test font never loaded.'); 2937 callback(); 2938 return; 2939 } 2940 ctx.font = '30px ' + name; 2941 ctx.fillText('.', 0, 20); 2942 var imageData = ctx.getImageData(0, 0, 1, 1); 2943 if (imageData.data[3] > 0) { 2944 callback(); 2945 return; 2946 } 2947 setTimeout(isFontReady.bind(null, name, callback)); 2948 } 2949 2950 var loadTestFontId = 'lt' + Date.now() + this.loadTestFontId++; 2951 // Chromium seems to cache fonts based on a hash of the actual font data, 2952 // so the font must be modified for each load test else it will appear to 2953 // be loaded already. 2954 // TODO: This could maybe be made faster by avoiding the btoa of the full 2955 // font by splitting it in chunks before hand and padding the font id. 2956 var data = this.loadTestFont; 2957 var COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum) 2958 data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length, loadTestFontId); 2959 // CFF checksum is important for IE, adjusting it 2960 var CFF_CHECKSUM_OFFSET = 16; 2961 var XXXX_VALUE = 0x58585858; // the "comment" filled with 'X' 2962 var checksum = int32(data, CFF_CHECKSUM_OFFSET); 2963 for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) { 2964 checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0; 2965 } 2966 if (i < loadTestFontId.length) { 2967 // align to 4 bytes boundary 2968 checksum = (checksum - XXXX_VALUE + int32(loadTestFontId + 'XXX', i)) | 0; 2969 } 2970 data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum)); 2971 2972 var url = 'url(data:font/opentype;base64,' + btoa(data) + ');'; 2973 var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' + url + '}'; 2974 this.insertRule(rule); 2975 2976 var names = []; 2977 for (i = 0, ii = fonts.length; i < ii; i++) { 2978 names.push(fonts[i].loadedName); 2979 } 2980 names.push(loadTestFontId); 2981 2982 var div = document.createElement('div'); 2983 div.setAttribute( 2984 'style', 2985 'visibility: hidden;' + 'width: 10px; height: 10px;' + 'position: absolute; top: 0px; left: 0px;' 2986 ); 2987 for (i = 0, ii = names.length; i < ii; ++i) { 2988 var span = document.createElement('span'); 2989 span.textContent = 'Hi'; 2990 span.style.fontFamily = names[i]; 2991 div.appendChild(span); 2992 } 2993 document.body.appendChild(div); 2994 2995 isFontReady(loadTestFontId, function () { 2996 document.body.removeChild(div); 2997 request.complete(); 2998 }); 2999 /** Hack end */ 3000 }, 3001 }; 3002 FontLoader.isFontLoadingAPISupported = typeof document !== 'undefined' && !!document.fonts; 3003 Object.defineProperty(FontLoader, 'isSyncFontLoadingSupported', { 3004 get: function () { 3005 if (typeof navigator === 'undefined') { 3006 // node.js - we can pretend sync font loading is supported. 3007 return shadow(FontLoader, 'isSyncFontLoadingSupported', true); 3008 } 3009 3010 var supported = false; 3011 3012 // User agent string sniffing is bad, but there is no reliable way to tell 3013 // if font is fully loaded and ready to be used with canvas. 3014 var m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent); 3015 if (m && m[1] >= 14) { 3016 supported = true; 3017 } 3018 return shadow(FontLoader, 'isSyncFontLoadingSupported', supported); 3019 }, 3020 enumerable: true, 3021 configurable: true, 3022 }); 3023 3024 var IsEvalSupportedCached = { 3025 get value() { 3026 return shadow(this, 'value', sharedUtil.isEvalSupported()); 3027 }, 3028 }; 3029 3030 var FontFaceObject = (function FontFaceObjectClosure() { 3031 function FontFaceObject(translatedData, options) { 3032 this.compiledGlyphs = Object.create(null); 3033 // importing translated data 3034 for (var i in translatedData) { 3035 this[i] = translatedData[i]; 3036 } 3037 this.options = options; 3038 } 3039 3040 FontFaceObject.prototype = { 3041 createNativeFontFace: function FontFaceObject_createNativeFontFace() { 3042 if (!this.data) { 3043 return null; 3044 } 3045 3046 if (this.options.disableFontFace) { 3047 this.disableFontFace = true; 3048 return null; 3049 } 3050 3051 var nativeFontFace = new FontFace(this.loadedName, this.data, {}); 3052 3053 if (this.options.fontRegistry) { 3054 this.options.fontRegistry.registerFont(this); 3055 } 3056 return nativeFontFace; 3057 }, 3058 3059 createFontFaceRule: function FontFaceObject_createFontFaceRule() { 3060 if (!this.data) { 3061 return null; 3062 } 3063 3064 if (this.options.disableFontFace) { 3065 this.disableFontFace = true; 3066 return null; 3067 } 3068 3069 var data = bytesToString(new Uint8Array(this.data)); 3070 var fontName = this.loadedName; 3071 3072 // Add the font-face rule to the document 3073 var url = 'url(data:' + this.mimetype + ';base64,' + btoa(data) + ');'; 3074 var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}'; 3075 3076 if (this.options.fontRegistry) { 3077 this.options.fontRegistry.registerFont(this, url); 3078 } 3079 3080 return rule; 3081 }, 3082 3083 getPathGenerator: function FontFaceObject_getPathGenerator(objs, character) { 3084 if (!(character in this.compiledGlyphs)) { 3085 var cmds = objs.get(this.loadedName + '_path_' + character); 3086 var current, i, len; 3087
3088 // If we can, compile cmds into JS for MAXIMUM SPEED 3089 if (this.options.isEvalSupported && IsEvalSupportedCached.value) { 3090 var args, 3091 js = ''; 3092 for (i = 0, len = cmds.length; i < len; i++) { 3093 current = cmds[i]; 3094 3095 if (current.args !== undefined) { 3096 args = current.args.join(','); 3097 } else { 3098 args = ''; 3099 } 3100 3101 js += 'c.' + current.cmd + '(' + args + ');\n'; 3102 } 3103 /* jshint -W054 */ 3104 this.compiledGlyphs[character] = new Function('c', 'size', js); 3105 } else { 3106 // But fall back on using Function.prototype.apply() if we're 3107 // blocked from using eval() for whatever reason (like CSP policies) 3108 this.compiledGlyphs[character] = function (c, size) { 3109 for (i = 0, len = cmds.length; i < len; i++) { 3110 current = cmds[i]; 3111 3112 if (current.cmd === 'scale') { 3113 current.args = [size, -size]; 3114 } 3115 3116 c[current.cmd].apply(c, current.args); 3117 } 3118 }; 3119 } 3120 } 3121 return this.compiledGlyphs[character]; 3122 }, 3123 }; 3124 return FontFaceObject; 3125 })(); 3126 3127 exports.FontFaceObject = FontFaceObject; 3128 exports.FontLoader = FontLoader; 3129 }); 3130 3131 (function (root, factory) { 3132 { 3133 factory((root.pdfjsDisplayMetadata = {}), root.pdfjsSharedUtil); 3134 } 3135 })(this, function (exports, sharedUtil) { 3136 var error = sharedUtil.error; 3137 3138 function fixMetadata(meta) { 3139 return meta.replace(/>\\376\\377([^<]+)/g, function (all, codes) { 3140 var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g, function (code, d1, d2, d3) { 3141 return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1); 3142 }); 3143 var chars = ''; 3144 for (var i = 0; i < bytes.length; i += 2) { 3145 var code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1); 3146 chars += 3147 code >= 32 && code < 127 && code !== 60 && code !== 62 && code !== 38 && false 3148 ? String.fromCharCode(code) 3149 : '&#x' + (0x10000 + code).toString(16).substring(1) + ';'; 3150 } 3151 return '>' + chars; 3152 }); 3153 } 3154 3155 function Metadata(meta) { 3156 if (typeof meta === 'string') { 3157 // Ghostscript produces invalid metadata 3158 meta = fixMetadata(meta); 3159 3160 var parser = new DOMParser(); 3161 meta = parser.parseFromString(meta, 'application/xml'); 3162 } else if (!(meta instanceof Document)) { 3163 error('Metadata: Invalid metadata object'); 3164 } 3165 3166 this.metaDocument = meta; 3167 this.metadata = Object.create(null); 3168 this.parse(); 3169 } 3170 3171 Metadata.prototype = { 3172 parse: function Metadata_parse() { 3173 var doc = this.metaDocument; 3174 var rdf = doc.documentElement; 3175 3176 if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { 3177 // Wrapped in <xmpmeta> 3178 rdf = rdf.firstChild; 3179 while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') { 3180 rdf = rdf.nextSibling; 3181 } 3182 } 3183 3184 var nodeName = rdf ? rdf.nodeName.toLowerCase() : null; 3185 if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) { 3186 return; 3187 } 3188 3189 var children = rdf.childNodes, 3190 desc, 3191 entry, 3192 name, 3193 i, 3194 ii, 3195 length, 3196 iLength; 3197 for (i = 0, length = children.length; i < length; i++) { 3198 desc = children[i]; 3199 if (desc.nodeName.toLowerCase() !== 'rdf:description') { 3200 continue; 3201 } 3202 3203 for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) { 3204 if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') { 3205 entry = desc.childNodes[ii]; 3206 name = entry.nodeName.toLowerCase(); 3207 this.metadata[name] = entry.textContent.trim(); 3208 } 3209 } 3210 } 3211 }, 3212 3213 get: function Metadata_get(name) { 3214 return this.metadata[name] || null; 3215 }, 3216 3217 has: function Metadata_has(name) { 3218 return typeof this.metadata[name] !== 'undefined'; 3219 }, 3220 }; 3221 3222 exports.Metadata = Metadata; 3223 }); 3224 3225 (function (root, factory) { 3226 { 3227 factory((root.pdfjsDisplaySVG = {}), root.pdfjsSharedUtil); 3228 } 3229 })(this, function (exports, sharedUtil) { 3230 var FONT_IDENTITY_MATRIX = sharedUtil.FONT_IDENTITY_MATRIX; 3231 var IDENTITY_MATRIX = sharedUtil.IDENTITY_MATRIX; 3232 var ImageKind = sharedUtil.ImageKind; 3233 var OPS = sharedUtil.OPS; 3234 var Util = sharedUtil.Util; 3235 var isNum = sharedUtil.isNum; 3236 var isArray = sharedUtil.isArray; 3237 var warn = sharedUtil.warn; 3238 var createObjectURL = sharedUtil.createObjectURL; 3239 3240 var SVG_DEFAULTS = { 3241 fontStyle: 'normal', 3242 fontWeight: 'normal', 3243 fillColor: '#000000', 3244 }; 3245 3246 var convertImgDataToPng = (function convertImgDataToPngClosure() { 3247 var PNG_HEADER = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); 3248 3249 var CHUNK_WRAPPER_SIZE = 12; 3250 3251 var crcTable = new Int32Array(256); 3252 for (var i = 0; i < 256; i++) { 3253 var c = i; 3254 for (var h = 0; h < 8; h++) { 3255 if (c & 1) { 3256 c = 0xedb88320 ^ ((c >> 1) & 0x7fffffff); 3257 } else { 3258 c = (c >> 1) & 0x7fffffff; 3259 } 3260 } 3261 crcTable[i] = c; 3262 } 3263 3264 function crc32(data, start, end) { 3265 var crc = -1; 3266 for (var i = start; i < end; i++) { 3267 var a = (crc ^ data[i]) & 0xff;
vendor: 4,290 bytes, lines 3268-3402
3268 var b = crcTable[a]; 3269 crc = (crc >>> 8) ^ b; 3270 } 3271 return crc ^ -1; 3272 } 3273 3274 function writePngChunk(type, body, data, offset) { 3275 var p = offset; 3276 var len = body.length; 3277 3278 data[p] = (len >> 24) & 0xff; 3279 data[p + 1] = (len >> 16) & 0xff; 3280 data[p + 2] = (len >> 8) & 0xff; 3281 data[p + 3] = len & 0xff; 3282 p += 4; 3283 3284 data[p] = type.charCodeAt(0) & 0xff; 3285 data[p + 1] = type.charCodeAt(1) & 0xff; 3286 data[p + 2] = type.charCodeAt(2) & 0xff; 3287 data[p + 3] = type.charCodeAt(3) & 0xff; 3288 p += 4; 3289 3290 data.set(body, p); 3291 p += body.length; 3292 3293 var crc = crc32(data, offset + 4, p); 3294 3295 data[p] = (crc >> 24) & 0xff; 3296 data[p + 1] = (crc >> 16) & 0xff; 3297 data[p + 2] = (crc >> 8) & 0xff; 3298 data[p + 3] = crc & 0xff; 3299 } 3300 3301 function adler32(data, start, end) { 3302 var a = 1; 3303 var b = 0; 3304 for (var i = start; i < end; ++i) { 3305 a = (a + (data[i] & 0xff)) % 65521; 3306 b = (b + a) % 65521; 3307 } 3308 return (b << 16) | a; 3309 } 3310 3311 function encode(imgData, kind, forceDataSchema) { 3312 var width = imgData.width; 3313 var height = imgData.height; 3314 var bitDepth, colorType, lineSize; 3315 var bytes = imgData.data; 3316 3317 switch (kind) { 3318 case ImageKind.GRAYSCALE_1BPP: 3319 colorType = 0; 3320 bitDepth = 1; 3321 lineSize = (width + 7) >> 3; 3322 break; 3323 case ImageKind.RGB_24BPP: 3324 colorType = 2; 3325 bitDepth = 8; 3326 lineSize = width * 3; 3327 break; 3328 case ImageKind.RGBA_32BPP: 3329 colorType = 6; 3330 bitDepth = 8; 3331 lineSize = width * 4; 3332 break; 3333 default: 3334 throw new Error('invalid format'); 3335 } 3336 3337 // prefix every row with predictor 0 3338 var literals = new Uint8Array((1 + lineSize) * height); 3339 var offsetLiterals = 0, 3340 offsetBytes = 0; 3341 var y, i; 3342 for (y = 0; y < height; ++y) { 3343 literals[offsetLiterals++] = 0; // no prediction 3344 literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize), offsetLiterals); 3345 offsetBytes += lineSize; 3346 offsetLiterals += lineSize; 3347 } 3348 3349 if (kind === ImageKind.GRAYSCALE_1BPP) { 3350 // inverting for B/W 3351 offsetLiterals = 0; 3352 for (y = 0; y < height; y++) { 3353 offsetLiterals++; // skipping predictor 3354 for (i = 0; i < lineSize; i++) { 3355 literals[offsetLiterals++] ^= 0xff; 3356 } 3357 } 3358 } 3359 3360 var ihdr = new Uint8Array([ 3361 (width >> 24) & 0xff, 3362 (width >> 16) & 0xff, 3363 (width >> 8) & 0xff, 3364 width & 0xff, 3365 (height >> 24) & 0xff, 3366 (height >> 16) & 0xff, 3367 (height >> 8) & 0xff, 3368 height & 0xff, 3369 bitDepth, // bit depth 3370 colorType, // color type 3371 0x00, // compression method 3372 0x00, // filter method 3373 0x00, // interlace method 3374 ]); 3375 3376 var len = literals.length; 3377 var maxBlockLength = 0xffff; 3378 3379 var deflateBlocks = Math.ceil(len / maxBlockLength); 3380 var idat = new Uint8Array(2 + len + deflateBlocks * 5 + 4); 3381 var pi = 0; 3382 idat[pi++] = 0x78; // compression method and flags 3383 idat[pi++] = 0x9c; // flags 3384 3385 var pos = 0; 3386 while (len > maxBlockLength) { 3387 // writing non-final DEFLATE blocks type 0 and length of 65535 3388 idat[pi++] = 0x00; 3389 idat[pi++] = 0xff; 3390 idat[pi++] = 0xff; 3391 idat[pi++] = 0x00; 3392 idat[pi++] = 0x00; 3393 idat.set(literals.subarray(pos, pos + maxBlockLength), pi); 3394 pi += maxBlockLength; 3395 pos += maxBlockLength; 3396 len -= maxBlockLength; 3397 } 3398 3399 // writing non-final DEFLATE blocks type 0 3400 idat[pi++] = 0x01; 3401 idat[pi++] = len & 0xff; 3402 idat[pi++] = (len >> 8) & 0xff;
3403 idat[pi++] = ~len & 0xffff & 0xff; 3404 idat[pi++] = ((~len & 0xffff) >> 8) & 0xff; 3405 idat.set(literals.subarray(pos), pi); 3406 pi += literals.length - pos; 3407 3408 var adler = adler32(literals, 0, literals.length); // checksum 3409 idat[pi++] = (adler >> 24) & 0xff; 3410 idat[pi++] = (adler >> 16) & 0xff; 3411 idat[pi++] = (adler >> 8) & 0xff; 3412 idat[pi++] = adler & 0xff; 3413 3414 // PNG will consists: header, IHDR+data, IDAT+data, and IEND. 3415 var pngLength = PNG_HEADER.length + CHUNK_WRAPPER_SIZE * 3 + ihdr.length + idat.length; 3416 var data = new Uint8Array(pngLength); 3417 var offset = 0; 3418 data.set(PNG_HEADER, offset); 3419 offset += PNG_HEADER.length; 3420 writePngChunk('IHDR', ihdr, data, offset); 3421 offset += CHUNK_WRAPPER_SIZE + ihdr.length; 3422 writePngChunk('IDATA', idat, data, offset); 3423 offset += CHUNK_WRAPPER_SIZE + idat.length; 3424 writePngChunk('IEND', new Uint8Array(0), data, offset); 3425 3426 return createObjectURL(data, 'image/png', forceDataSchema); 3427 } 3428 3429 return function convertImgDataToPng(imgData, forceDataSchema) { 3430 var kind = imgData.kind === undefined ? ImageKind.GRAYSCALE_1BPP : imgData.kind; 3431 return encode(imgData, kind, forceDataSchema); 3432 }; 3433 })(); 3434 3435 var SVGExtraState = (function SVGExtraStateClosure() { 3436 function SVGExtraState() { 3437 this.fontSizeScale = 1; 3438 this.fontWeight = SVG_DEFAULTS.fontWeight; 3439 this.fontSize = 0; 3440 3441 this.textMatrix = IDENTITY_MATRIX; 3442 this.fontMatrix = FONT_IDENTITY_MATRIX; 3443 this.leading = 0; 3444 3445 // Current point (in user coordinates) 3446 this.x = 0; 3447 this.y = 0; 3448 3449 // Start of text line (in text coordinates) 3450 this.lineX = 0; 3451 this.lineY = 0; 3452 3453 // Character and word spacing 3454 this.charSpacing = 0; 3455 this.wordSpacing = 0; 3456 this.textHScale = 1; 3457 this.textRise = 0; 3458 3459 // Default foreground and background colors 3460 this.fillColor = SVG_DEFAULTS.fillColor; 3461 this.strokeColor = '#000000'; 3462 3463 this.fillAlpha = 1; 3464 this.strokeAlpha = 1; 3465 this.lineWidth = 1; 3466 this.lineJoin = ''; 3467 this.lineCap = ''; 3468 this.miterLimit = 0; 3469 3470 this.dashArray = []; 3471 this.dashPhase = 0; 3472 3473 this.dependencies = []; 3474 3475 // Clipping 3476 this.clipId = ''; 3477 this.pendingClip = false; 3478 3479 this.maskId = ''; 3480 } 3481 3482 SVGExtraState.prototype = { 3483 clone: function SVGExtraState_clone() { 3484 return Object.create(this); 3485 }, 3486 setCurrentPoint: function SVGExtraState_setCurrentPoint(x, y) { 3487 this.x = x; 3488 this.y = y; 3489 }, 3490 }; 3491 return SVGExtraState; 3492 })(); 3493 3494 var SVGGraphics = (function SVGGraphicsClosure() { 3495 function createScratchSVG(width, height) { 3496 var NS = 'http://www.w3.org/2000/svg'; 3497 var svg = document.createElementNS(NS, 'svg:svg'); 3498 svg.setAttributeNS(null, 'version', '1.1'); 3499 svg.setAttributeNS(null, 'width', width + 'px'); 3500 svg.setAttributeNS(null, 'height', height + 'px'); 3501 svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height); 3502 return svg; 3503 } 3504 3505 function opListToTree(opList) { 3506 var opTree = []; 3507 var tmp = []; 3508 var opListLen = opList.length; 3509 3510 for (var x = 0; x < opListLen; x++) { 3511 if (opList[x].fn === 'save') { 3512 opTree.push({ fnId: 92, fn: 'group', items: [] }); 3513 tmp.push(opTree); 3514 opTree = opTree[opTree.length - 1].items; 3515 continue; 3516 } 3517 3518 if (opList[x].fn === 'restore') { 3519 opTree = tmp.pop(); 3520 } else { 3521 opTree.push(opList[x]); 3522 } 3523 } 3524 return opTree; 3525 } 3526 3527 /** 3528 * Formats float number. 3529 * @param value {number} number to format. 3530 * @returns {string} 3531 */ 3532 function pf(value) { 3533 if (value === (value | 0)) { 3534 // integer number 3535 return value.toString(); 3536 } 3537 var s = value.toFixed(10); 3538 var i = s.length - 1; 3539 if (s[i] !== '0') { 3540 return s; 3541 } 3542 // removing trailing zeros 3543 do { 3544 i--; 3545 } while (s[i] === '0'); 3546 return s.substr(0, s[i] === '.' ? i : i + 1); 3547 } 3548 3549 /** 3550 * Formats transform matrix. The standard rotation, scale and translate 3551 * matrices are replaced by their shorter forms, and for identity matrix 3552 * returns empty string to save the memory. 3553 * @param m {Array} matrix to format. 3554 * @returns {string} 3555 */ 3556 function pm(m) { 3557 if (m[4] === 0 && m[5] === 0) { 3558 if (m[1] === 0 && m[2] === 0) { 3559 if (m[0] === 1 && m[3] === 1) { 3560 return ''; 3561 } 3562 return 'scale(' + pf(m[0]) + ' ' + pf(m[3]) + ')'; 3563 } 3564 if (m[0] === m[3] && m[1] === -m[2]) { 3565 var a = (Math.acos(m[0]) * 180) / Math.PI; 3566 return 'rotate(' + pf(a) + ')'; 3567 } 3568 } else { 3569 if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1) { 3570 return 'translate(' + pf(m[4]) + ' ' + pf(m[5]) + ')'; 3571 } 3572 } 3573 return ( 3574 'matrix(' + 3575 pf(m[0]) + 3576 ' ' + 3577 pf(m[1]) + 3578 ' ' + 3579 pf(m[2]) + 3580 ' ' + 3581 pf(m[3]) + 3582 ' ' + 3583 pf(m[4]) + 3584 ' ' +
vendor: 31,271 bytes, lines 3585-4368
3585 pf(m[5]) + 3586 ')' 3587 ); 3588 } 3589 3590 function SVGGraphics(commonObjs, objs, forceDataSchema) { 3591 this.current = new SVGExtraState(); 3592 this.transformMatrix = IDENTITY_MATRIX; // Graphics state matrix 3593 this.transformStack = []; 3594 this.extraStack = []; 3595 this.commonObjs = commonObjs; 3596 this.objs = objs; 3597 this.pendingEOFill = false; 3598 3599 this.embedFonts = false; 3600 this.embeddedFonts = Object.create(null); 3601 this.cssStyle = null; 3602 this.forceDataSchema = !!forceDataSchema; 3603 } 3604 3605 var NS = 'http://www.w3.org/2000/svg'; 3606 var XML_NS = 'http://www.w3.org/XML/1998/namespace'; 3607 var XLINK_NS = 'http://www.w3.org/1999/xlink'; 3608 var LINE_CAP_STYLES = ['butt', 'round', 'square']; 3609 var LINE_JOIN_STYLES = ['miter', 'round', 'bevel']; 3610 var clipCount = 0; 3611 var maskCount = 0; 3612 3613 SVGGraphics.prototype = { 3614 save: function SVGGraphics_save() { 3615 this.transformStack.push(this.transformMatrix); 3616 var old = this.current; 3617 this.extraStack.push(old); 3618 this.current = old.clone(); 3619 }, 3620 3621 restore: function SVGGraphics_restore() { 3622 this.transformMatrix = this.transformStack.pop(); 3623 this.current = this.extraStack.pop(); 3624 3625 this.tgrp = document.createElementNS(NS, 'svg:g'); 3626 this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix)); 3627 this.pgrp.appendChild(this.tgrp); 3628 }, 3629 3630 group: function SVGGraphics_group(items) { 3631 this.save(); 3632 this.executeOpTree(items); 3633 this.restore(); 3634 }, 3635 3636 loadDependencies: function SVGGraphics_loadDependencies(operatorList) { 3637 var fnArray = operatorList.fnArray; 3638 var fnArrayLen = fnArray.length; 3639 var argsArray = operatorList.argsArray; 3640 3641 var self = this; 3642 for (var i = 0; i < fnArrayLen; i++) { 3643 if (OPS.dependency === fnArray[i]) { 3644 var deps = argsArray[i]; 3645 for (var n = 0, nn = deps.length; n < nn; n++) { 3646 var obj = deps[n]; 3647 var common = obj.substring(0, 2) === 'g_'; 3648 var promise; 3649 if (common) { 3650 promise = new Promise(function (resolve) { 3651 self.commonObjs.get(obj, resolve); 3652 }); 3653 } else { 3654 promise = new Promise(function (resolve) { 3655 self.objs.get(obj, resolve); 3656 }); 3657 } 3658 this.current.dependencies.push(promise); 3659 } 3660 } 3661 } 3662 return Promise.all(this.current.dependencies); 3663 }, 3664 3665 transform: function SVGGraphics_transform(a, b, c, d, e, f) { 3666 var transformMatrix = [a, b, c, d, e, f]; 3667 this.transformMatrix = Util.transform(this.transformMatrix, transformMatrix); 3668 3669 this.tgrp = document.createElementNS(NS, 'svg:g'); 3670 this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix)); 3671 }, 3672 3673 getSVG: function SVGGraphics_getSVG(operatorList, viewport) { 3674 this.svg = createScratchSVG(viewport.width, viewport.height); 3675 this.viewport = viewport; 3676 3677 return this.loadDependencies(operatorList).then( 3678 function () { 3679 this.transformMatrix = IDENTITY_MATRIX; 3680 this.pgrp = document.createElementNS(NS, 'svg:g'); // Parent group 3681 this.pgrp.setAttributeNS(null, 'transform', pm(viewport.transform)); 3682 this.tgrp = document.createElementNS(NS, 'svg:g'); // Transform group 3683 this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix)); 3684 this.defs = document.createElementNS(NS, 'svg:defs'); 3685 this.pgrp.appendChild(this.defs); 3686 this.pgrp.appendChild(this.tgrp); 3687 this.svg.appendChild(this.pgrp); 3688 var opTree = this.convertOpList(operatorList); 3689 this.executeOpTree(opTree); 3690 return this.svg; 3691 }.bind(this) 3692 ); 3693 }, 3694 3695 convertOpList: function SVGGraphics_convertOpList(operatorList) { 3696 var argsArray = operatorList.argsArray; 3697 var fnArray = operatorList.fnArray; 3698 var fnArrayLen = fnArray.length; 3699 var REVOPS = []; 3700 var opList = []; 3701 3702 for (var op in OPS) { 3703 REVOPS[OPS[op]] = op; 3704 } 3705 3706 for (var x = 0; x < fnArrayLen; x++) { 3707 var fnId = fnArray[x]; 3708 opList.push({ fnId: fnId, fn: REVOPS[fnId], args: argsArray[x] }); 3709 } 3710 return opListToTree(opList); 3711 }, 3712 3713 executeOpTree: function SVGGraphics_executeOpTree(opTree) { 3714 var opTreeLen = opTree.length; 3715 for (var x = 0; x < opTreeLen; x++) { 3716 var fn = opTree[x].fn; 3717 var fnId = opTree[x].fnId; 3718 var args = opTree[x].args; 3719 3720 switch (fnId | 0) { 3721 case OPS.beginText: 3722 this.beginText(); 3723 break; 3724 case OPS.setLeading: 3725 this.setLeading(args); 3726 break; 3727 case OPS.setLeadingMoveText: 3728 this.setLeadingMoveText(args[0], args[1]); 3729 break; 3730 case OPS.setFont: 3731 this.setFont(args); 3732 break; 3733 case OPS.showText: 3734 this.showText(args[0]); 3735 break; 3736 case OPS.showSpacedText: 3737 this.showText(args[0]); 3738 break; 3739 case OPS.endText: 3740 this.endText(); 3741 break; 3742 case OPS.moveText: 3743 this.moveText(args[0], args[1]); 3744 break; 3745 case OPS.setCharSpacing: 3746 this.setCharSpacing(args[0]); 3747 break; 3748 case OPS.setWordSpacing: 3749 this.setWordSpacing(args[0]); 3750 break; 3751 case OPS.setHScale: 3752 this.setHScale(args[0]); 3753 break; 3754 case OPS.setTextMatrix: 3755 this.setTextMatrix(args[0], args[1], args[2], args[3], args[4], args[5]); 3756 break; 3757 case OPS.setLineWidth: 3758 this.setLineWidth(args[0]); 3759 break; 3760 case OPS.setLineJoin: 3761 this.setLineJoin(args[0]); 3762 break; 3763 case OPS.setLineCap: 3764 this.setLineCap(args[0]); 3765 break; 3766 case OPS.setMiterLimit: 3767 this.setMiterLimit(args[0]); 3768 break; 3769 case OPS.setFillRGBColor: 3770 this.setFillRGBColor(args[0], args[1], args[2]); 3771 break; 3772 case OPS.setStrokeRGBColor: 3773 this.setStrokeRGBColor(args[0], args[1], args[2]); 3774 break; 3775 case OPS.setDash: 3776 this.setDash(args[0], args[1]); 3777 break; 3778 case OPS.setGState: 3779 this.setGState(args[0]); 3780 break; 3781 case OPS.fill: 3782 this.fill(); 3783 break; 3784 case OPS.eoFill: 3785 this.eoFill(); 3786 break; 3787 case OPS.stroke: 3788 this.stroke(); 3789 break; 3790 case OPS.fillStroke: 3791 this.fillStroke(); 3792 break; 3793 case OPS.eoFillStroke: 3794 this.eoFillStroke(); 3795 break; 3796 case OPS.clip: 3797 this.clip('nonzero'); 3798 break; 3799 case OPS.eoClip: 3800 this.clip('evenodd'); 3801 break; 3802 case OPS.paintSolidColorImageMask: 3803 this.paintSolidColorImageMask(); 3804 break; 3805 case OPS.paintJpegXObject: 3806 this.paintJpegXObject(args[0], args[1], args[2]); 3807 break; 3808 case OPS.paintImageXObject: 3809 this.paintImageXObject(args[0]); 3810 break; 3811 case OPS.paintInlineImageXObject: 3812 this.paintInlineImageXObject(args[0]); 3813 break; 3814 case OPS.paintImageMaskXObject: 3815 this.paintImageMaskXObject(args[0]); 3816 break; 3817 case OPS.paintFormXObjectBegin: 3818 this.paintFormXObjectBegin(args[0], args[1]); 3819 break; 3820 case OPS.paintFormXObjectEnd: 3821 this.paintFormXObjectEnd(); 3822 break; 3823 case OPS.closePath: 3824 this.closePath(); 3825 break; 3826 case OPS.closeStroke: 3827 this.closeStroke(); 3828 break; 3829 case OPS.closeFillStroke: 3830 this.closeFillStroke(); 3831 break; 3832 case OPS.nextLine: 3833 this.nextLine(); 3834 break; 3835 case OPS.transform: 3836 this.transform(args[0], args[1], args[2], args[3], args[4], args[5]); 3837 break; 3838 case OPS.constructPath: 3839 this.constructPath(args[0], args[1]); 3840 break; 3841 case OPS.endPath: 3842 this.endPath(); 3843 break; 3844 case 92: 3845 this.group(opTree[x].items); 3846 break; 3847 default: 3848 warn('Unimplemented method ' + fn); 3849 break; 3850 } 3851 } 3852 }, 3853 3854 setWordSpacing: function SVGGraphics_setWordSpacing(wordSpacing) { 3855 this.current.wordSpacing = wordSpacing; 3856 }, 3857 3858 setCharSpacing: function SVGGraphics_setCharSpacing(charSpacing) { 3859 this.current.charSpacing = charSpacing; 3860 }, 3861 3862 nextLine: function SVGGraphics_nextLine() { 3863 this.moveText(0, this.current.leading); 3864 }, 3865 3866 setTextMatrix: function SVGGraphics_setTextMatrix(a, b, c, d, e, f) { 3867 var current = this.current; 3868 this.current.textMatrix = this.current.lineMatrix = [a, b, c, d, e, f]; 3869 3870 this.current.x = this.current.lineX = 0; 3871 this.current.y = this.current.lineY = 0; 3872 3873 current.xcoords = []; 3874 current.tspan = document.createElementNS(NS, 'svg:tspan'); 3875 current.tspan.setAttributeNS(null, 'font-family', current.fontFamily); 3876 current.tspan.setAttributeNS(null, 'font-size', pf(current.fontSize) + 'px'); 3877 current.tspan.setAttributeNS(null, 'y', pf(-current.y)); 3878 3879 current.txtElement = document.createElementNS(NS, 'svg:text'); 3880 current.txtElement.appendChild(current.tspan); 3881 }, 3882 3883 beginText: function SVGGraphics_beginText() { 3884 this.current.x = this.current.lineX = 0; 3885 this.current.y = this.current.lineY = 0; 3886 this.current.textMatrix = IDENTITY_MATRIX; 3887 this.current.lineMatrix = IDENTITY_MATRIX; 3888 this.current.tspan = document.createElementNS(NS, 'svg:tspan'); 3889 this.current.txtElement = document.createElementNS(NS, 'svg:text'); 3890 this.current.txtgrp = document.createElementNS(NS, 'svg:g'); 3891 this.current.xcoords = []; 3892 }, 3893 3894 moveText: function SVGGraphics_moveText(x, y) { 3895 var current = this.current; 3896 this.current.x = this.current.lineX += x; 3897 this.current.y = this.current.lineY += y; 3898 3899 current.xcoords = []; 3900 current.tspan = document.createElementNS(NS, 'svg:tspan'); 3901 current.tspan.setAttributeNS(null, 'font-family', current.fontFamily); 3902 current.tspan.setAttributeNS(null, 'font-size', pf(current.fontSize) + 'px'); 3903 current.tspan.setAttributeNS(null, 'y', pf(-current.y)); 3904 }, 3905 3906 showText: function SVGGraphics_showText(glyphs) { 3907 var current = this.current; 3908 var font = current.font; 3909 var fontSize = current.fontSize; 3910 3911 if (fontSize === 0) { 3912 return; 3913 } 3914 3915 var charSpacing = current.charSpacing; 3916 var wordSpacing = current.wordSpacing; 3917 var fontDirection = current.fontDirection; 3918 var textHScale = current.textHScale * fontDirection; 3919 var glyphsLength = glyphs.length; 3920 var vertical = font.vertical; 3921 var widthAdvanceScale = fontSize * current.fontMatrix[0]; 3922 3923 var x = 0, 3924 i; 3925 for (i = 0; i < glyphsLength; ++i) { 3926 var glyph = glyphs[i]; 3927 if (glyph === null) { 3928 // word break 3929 x += fontDirection * wordSpacing; 3930 continue; 3931 } else if (isNum(glyph)) { 3932 x += -glyph * fontSize * 0.001; 3933 continue; 3934 } 3935 current.xcoords.push(current.x + x * textHScale); 3936 3937 var width = glyph.width; 3938 var character = glyph.fontChar; 3939 var charWidth = width * widthAdvanceScale + charSpacing * fontDirection; 3940 x += charWidth; 3941 3942 current.tspan.textContent += character; 3943 } 3944 if (vertical) { 3945 current.y -= x * textHScale; 3946 } else { 3947 current.x += x * textHScale; 3948 } 3949 3950 current.tspan.setAttributeNS(null, 'x', current.xcoords.map(pf).join(' ')); 3951 current.tspan.setAttributeNS(null, 'y', pf(-current.y)); 3952 current.tspan.setAttributeNS(null, 'font-family', current.fontFamily); 3953 current.tspan.setAttributeNS(null, 'font-size', pf(current.fontSize) + 'px'); 3954 if (current.fontStyle !== SVG_DEFAULTS.fontStyle) { 3955 current.tspan.setAttributeNS(null, 'font-style', current.fontStyle); 3956 } 3957 if (current.fontWeight !== SVG_DEFAULTS.fontWeight) { 3958 current.tspan.setAttributeNS(null, 'font-weight', current.fontWeight); 3959 } 3960 if (current.fillColor !== SVG_DEFAULTS.fillColor) { 3961 current.tspan.setAttributeNS(null, 'fill', current.fillColor); 3962 } 3963 3964 current.txtElement.setAttributeNS(null, 'transform', pm(current.textMatrix) + ' scale(1, -1)'); 3965 current.txtElement.setAttributeNS(XML_NS, 'xml:space', 'preserve'); 3966 current.txtElement.appendChild(current.tspan); 3967 current.txtgrp.appendChild(current.txtElement); 3968 3969 this.tgrp.appendChild(current.txtElement); 3970 }, 3971 3972 setLeadingMoveText: function SVGGraphics_setLeadingMoveText(x, y) { 3973 this.setLeading(-y); 3974 this.moveText(x, y); 3975 }, 3976 3977 addFontStyle: function SVGGraphics_addFontStyle(fontObj) { 3978 if (!this.cssStyle) { 3979 this.cssStyle = document.createElementNS(NS, 'svg:style'); 3980 this.cssStyle.setAttributeNS(null, 'type', 'text/css'); 3981 this.defs.appendChild(this.cssStyle); 3982 } 3983 3984 var url = createObjectURL(fontObj.data, fontObj.mimetype, this.forceDataSchema); 3985 this.cssStyle.textContent += 3986 '@font-face { font-family: "' + fontObj.loadedName + '";' + ' src: url(' + url + '); }\n'; 3987 }, 3988 3989 setFont: function SVGGraphics_setFont(details) { 3990 var current = this.current; 3991 var fontObj = this.commonObjs.get(details[0]); 3992 var size = details[1]; 3993 this.current.font = fontObj; 3994 3995 if (this.embedFonts && fontObj.data && !this.embeddedFonts[fontObj.loadedName]) { 3996 this.addFontStyle(fontObj); 3997 this.embeddedFonts[fontObj.loadedName] = fontObj; 3998 } 3999 4000 current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix : FONT_IDENTITY_MATRIX; 4001 4002 var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') : fontObj.bold ? 'bold' : 'normal'; 4003 var italic = fontObj.italic ? 'italic' : 'normal'; 4004 4005 if (size < 0) { 4006 size = -size; 4007 current.fontDirection = -1; 4008 } else { 4009 current.fontDirection = 1; 4010 } 4011 current.fontSize = size; 4012 current.fontFamily = fontObj.loadedName; 4013 current.fontWeight = bold; 4014 current.fontStyle = italic; 4015 4016 current.tspan = document.createElementNS(NS, 'svg:tspan'); 4017 current.tspan.setAttributeNS(null, 'y', pf(-current.y)); 4018 current.xcoords = []; 4019 }, 4020 4021 endText: function SVGGraphics_endText() { 4022 if (this.current.pendingClip) { 4023 this.cgrp.appendChild(this.tgrp); 4024 this.pgrp.appendChild(this.cgrp); 4025 } else { 4026 this.pgrp.appendChild(this.tgrp); 4027 } 4028 this.tgrp = document.createElementNS(NS, 'svg:g'); 4029 this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix)); 4030 }, 4031 4032 // Path properties 4033 setLineWidth: function SVGGraphics_setLineWidth(width) { 4034 this.current.lineWidth = width; 4035 }, 4036 setLineCap: function SVGGraphics_setLineCap(style) { 4037 this.current.lineCap = LINE_CAP_STYLES[style]; 4038 }, 4039 setLineJoin: function SVGGraphics_setLineJoin(style) { 4040 this.current.lineJoin = LINE_JOIN_STYLES[style]; 4041 }, 4042 setMiterLimit: function SVGGraphics_setMiterLimit(limit) { 4043 this.current.miterLimit = limit; 4044 }, 4045 setStrokeRGBColor: function SVGGraphics_setStrokeRGBColor(r, g, b) { 4046 var color = Util.makeCssRgb(r, g, b); 4047 this.current.strokeColor = color; 4048 }, 4049 setFillRGBColor: function SVGGraphics_setFillRGBColor(r, g, b) { 4050 var color = Util.makeCssRgb(r, g, b); 4051 this.current.fillColor = color; 4052 this.current.tspan = document.createElementNS(NS, 'svg:tspan'); 4053 this.current.xcoords = []; 4054 }, 4055 setDash: function SVGGraphics_setDash(dashArray, dashPhase) { 4056 this.current.dashArray = dashArray; 4057 this.current.dashPhase = dashPhase; 4058 }, 4059 4060 constructPath: function SVGGraphics_constructPath(ops, args) { 4061 var current = this.current; 4062 var x = current.x, 4063 y = current.y; 4064 current.path = document.createElementNS(NS, 'svg:path'); 4065 var d = []; 4066 var opLength = ops.length; 4067 4068 for (var i = 0, j = 0; i < opLength; i++) { 4069 switch (ops[i] | 0) { 4070 case OPS.rectangle: 4071 x = args[j++]; 4072 y = args[j++]; 4073 var width = args[j++]; 4074 var height = args[j++]; 4075 var xw = x + width; 4076 var yh = y + height; 4077 d.push('M', pf(x), pf(y), 'L', pf(xw), pf(y), 'L', pf(xw), pf(yh), 'L', pf(x), pf(yh), 'Z'); 4078 break; 4079 case OPS.moveTo: 4080 x = args[j++]; 4081 y = args[j++]; 4082 d.push('M', pf(x), pf(y)); 4083 break; 4084 case OPS.lineTo: 4085 x = args[j++]; 4086 y = args[j++]; 4087 d.push('L', pf(x), pf(y)); 4088 break; 4089 case OPS.curveTo: 4090 x = args[j + 4]; 4091 y = args[j + 5]; 4092 d.push('C', pf(args[j]), pf(args[j + 1]), pf(args[j + 2]), pf(args[j + 3]), pf(x), pf(y)); 4093 j += 6; 4094 break; 4095 case OPS.curveTo2: 4096 x = args[j + 2]; 4097 y = args[j + 3]; 4098 d.push('C', pf(x), pf(y), pf(args[j]), pf(args[j + 1]), pf(args[j + 2]), pf(args[j + 3])); 4099 j += 4; 4100 break; 4101 case OPS.curveTo3: 4102 x = args[j + 2]; 4103 y = args[j + 3]; 4104 d.push('C', pf(args[j]), pf(args[j + 1]), pf(x), pf(y), pf(x), pf(y)); 4105 j += 4; 4106 break; 4107 case OPS.closePath: 4108 d.push('Z'); 4109 break; 4110 } 4111 } 4112 current.path.setAttributeNS(null, 'd', d.join(' ')); 4113 current.path.setAttributeNS(null, 'stroke-miterlimit', pf(current.miterLimit)); 4114 current.path.setAttributeNS(null, 'stroke-linecap', current.lineCap); 4115 current.path.setAttributeNS(null, 'stroke-linejoin', current.lineJoin); 4116 current.path.setAttributeNS(null, 'stroke-width', pf(current.lineWidth) + 'px'); 4117 current.path.setAttributeNS(null, 'stroke-dasharray', current.dashArray.map(pf).join(' ')); 4118 current.path.setAttributeNS(null, 'stroke-dashoffset', pf(current.dashPhase) + 'px'); 4119 current.path.setAttributeNS(null, 'fill', 'none'); 4120 4121 this.tgrp.appendChild(current.path); 4122 if (current.pendingClip) { 4123 this.cgrp.appendChild(this.tgrp); 4124 this.pgrp.appendChild(this.cgrp); 4125 } else { 4126 this.pgrp.appendChild(this.tgrp); 4127 } 4128 // Saving a reference in current.element so that it can be addressed 4129 // in 'fill' and 'stroke' 4130 current.element = current.path; 4131 current.setCurrentPoint(x, y); 4132 }, 4133 4134 endPath: function SVGGraphics_endPath() { 4135 var current = this.current; 4136 if (current.pendingClip) { 4137 this.cgrp.appendChild(this.tgrp); 4138 this.pgrp.appendChild(this.cgrp); 4139 } else { 4140 this.pgrp.appendChild(this.tgrp); 4141 } 4142 this.tgrp = document.createElementNS(NS, 'svg:g'); 4143 this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix)); 4144 }, 4145 4146 clip: function SVGGraphics_clip(type) { 4147 var current = this.current; 4148 // Add current path to clipping path 4149 current.clipId = 'clippath' + clipCount; 4150 clipCount++; 4151 this.clippath = document.createElementNS(NS, 'svg:clipPath'); 4152 this.clippath.setAttributeNS(null, 'id', current.clipId); 4153 var clipElement = current.element.cloneNode(); 4154 if (type === 'evenodd') { 4155 clipElement.setAttributeNS(null, 'clip-rule', 'evenodd'); 4156 } else { 4157 clipElement.setAttributeNS(null, 'clip-rule', 'nonzero'); 4158 } 4159 this.clippath.setAttributeNS(null, 'transform', pm(this.transformMatrix)); 4160 this.clippath.appendChild(clipElement); 4161 this.defs.appendChild(this.clippath); 4162 4163 // Create a new group with that attribute 4164 current.pendingClip = true; 4165 this.cgrp = document.createElementNS(NS, 'svg:g'); 4166 this.cgrp.setAttributeNS(null, 'clip-path', 'url(#' + current.clipId + ')'); 4167 this.pgrp.appendChild(this.cgrp); 4168 }, 4169 4170 closePath: function SVGGraphics_closePath() { 4171 var current = this.current; 4172 var d = current.path.getAttributeNS(null, 'd'); 4173 d += 'Z'; 4174 current.path.setAttributeNS(null, 'd', d); 4175 }, 4176 4177 setLeading: function SVGGraphics_setLeading(leading) { 4178 this.current.leading = -leading; 4179 }, 4180 4181 setTextRise: function SVGGraphics_setTextRise(textRise) { 4182 this.current.textRise = textRise; 4183 }, 4184 4185 setHScale: function SVGGraphics_setHScale(scale) { 4186 this.current.textHScale = scale / 100; 4187 }, 4188 4189 setGState: function SVGGraphics_setGState(states) { 4190 for (var i = 0, ii = states.length; i < ii; i++) { 4191 var state = states[i]; 4192 var key = state[0]; 4193 var value = state[1]; 4194 4195 switch (key) { 4196 case 'LW': 4197 this.setLineWidth(value); 4198 break; 4199 case 'LC': 4200 this.setLineCap(value); 4201 break; 4202 case 'LJ': 4203 this.setLineJoin(value); 4204 break; 4205 case 'ML': 4206 this.setMiterLimit(value); 4207 break; 4208 case 'D': 4209 this.setDash(value[0], value[1]); 4210 break; 4211 case 'RI': 4212 break; 4213 case 'FL': 4214 break; 4215 case 'Font': 4216 this.setFont(value); 4217 break; 4218 case 'CA': 4219 break; 4220 case 'ca': 4221 break; 4222 case 'BM': 4223 break; 4224 case 'SMask': 4225 break; 4226 } 4227 } 4228 }, 4229 4230 fill: function SVGGraphics_fill() { 4231 var current = this.current; 4232 current.element.setAttributeNS(null, 'fill', current.fillColor); 4233 }, 4234 4235 stroke: function SVGGraphics_stroke() { 4236 var current = this.current; 4237 current.element.setAttributeNS(null, 'stroke', current.strokeColor); 4238 current.element.setAttributeNS(null, 'fill', 'none'); 4239 }, 4240 4241 eoFill: function SVGGraphics_eoFill() { 4242 var current = this.current; 4243 current.element.setAttributeNS(null, 'fill', current.fillColor); 4244 current.element.setAttributeNS(null, 'fill-rule', 'evenodd'); 4245 }, 4246 4247 fillStroke: function SVGGraphics_fillStroke() { 4248 // Order is important since stroke wants fill to be none. 4249 // First stroke, then if fill needed, it will be overwritten. 4250 this.stroke(); 4251 this.fill(); 4252 }, 4253 4254 eoFillStroke: function SVGGraphics_eoFillStroke() { 4255 this.current.element.setAttributeNS(null, 'fill-rule', 'evenodd'); 4256 this.fillStroke(); 4257 }, 4258 4259 closeStroke: function SVGGraphics_closeStroke() { 4260 this.closePath(); 4261 this.stroke(); 4262 }, 4263 4264 closeFillStroke: function SVGGraphics_closeFillStroke() { 4265 this.closePath(); 4266 this.fillStroke(); 4267 }, 4268 4269 paintSolidColorImageMask: function SVGGraphics_paintSolidColorImageMask() { 4270 var current = this.current; 4271 var rect = document.createElementNS(NS, 'svg:rect'); 4272 rect.setAttributeNS(null, 'x', '0'); 4273 rect.setAttributeNS(null, 'y', '0'); 4274 rect.setAttributeNS(null, 'width', '1px'); 4275 rect.setAttributeNS(null, 'height', '1px'); 4276 rect.setAttributeNS(null, 'fill', current.fillColor); 4277 this.tgrp.appendChild(rect); 4278 }, 4279 4280 paintJpegXObject: function SVGGraphics_paintJpegXObject(objId, w, h) { 4281 var current = this.current; 4282 var imgObj = this.objs.get(objId); 4283 var imgEl = document.createElementNS(NS, 'svg:image'); 4284 imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src); 4285 imgEl.setAttributeNS(null, 'width', imgObj.width + 'px'); 4286 imgEl.setAttributeNS(null, 'height', imgObj.height + 'px'); 4287 imgEl.setAttributeNS(null, 'x', '0'); 4288 imgEl.setAttributeNS(null, 'y', pf(-h)); 4289 imgEl.setAttributeNS(null, 'transform', 'scale(' + pf(1 / w) + ' ' + pf(-1 / h) + ')'); 4290 4291 this.tgrp.appendChild(imgEl); 4292 if (current.pendingClip) { 4293 this.cgrp.appendChild(this.tgrp); 4294 this.pgrp.appendChild(this.cgrp); 4295 } else { 4296 this.pgrp.appendChild(this.tgrp); 4297 } 4298 }, 4299 4300 paintImageXObject: function SVGGraphics_paintImageXObject(objId) { 4301 var imgData = this.objs.get(objId); 4302 if (!imgData) { 4303 warn("Dependent image isn't ready yet"); 4304 return; 4305 } 4306 this.paintInlineImageXObject(imgData); 4307 }, 4308 4309 paintInlineImageXObject: function SVGGraphics_paintInlineImageXObject(imgData, mask) { 4310 var current = this.current; 4311 var width = imgData.width; 4312 var height = imgData.height; 4313 4314 var imgSrc = convertImgDataToPng(imgData, this.forceDataSchema); 4315 var cliprect = document.createElementNS(NS, 'svg:rect'); 4316 cliprect.setAttributeNS(null, 'x', '0'); 4317 cliprect.setAttributeNS(null, 'y', '0'); 4318 cliprect.setAttributeNS(null, 'width', pf(width)); 4319 cliprect.setAttributeNS(null, 'height', pf(height)); 4320 current.element = cliprect; 4321 this.clip('nonzero'); 4322 var imgEl = document.createElementNS(NS, 'svg:image'); 4323 imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgSrc); 4324 imgEl.setAttributeNS(null, 'x', '0'); 4325 imgEl.setAttributeNS(null, 'y', pf(-height)); 4326 imgEl.setAttributeNS(null, 'width', pf(width) + 'px'); 4327 imgEl.setAttributeNS(null, 'height', pf(height) + 'px'); 4328 imgEl.setAttributeNS(null, 'transform', 'scale(' + pf(1 / width) + ' ' + pf(-1 / height) + ')'); 4329 if (mask) { 4330 mask.appendChild(imgEl); 4331 } else { 4332 this.tgrp.appendChild(imgEl); 4333 } 4334 if (current.pendingClip) { 4335 this.cgrp.appendChild(this.tgrp); 4336 this.pgrp.appendChild(this.cgrp); 4337 } else { 4338 this.pgrp.appendChild(this.tgrp); 4339 } 4340 }, 4341 4342 paintImageMaskXObject: function SVGGraphics_paintImageMaskXObject(imgData) { 4343 var current = this.current; 4344 var width = imgData.width; 4345 var height = imgData.height; 4346 var fillColor = current.fillColor; 4347 4348 current.maskId = 'mask' + maskCount++; 4349 var mask = document.createElementNS(NS, 'svg:mask'); 4350 mask.setAttributeNS(null, 'id', current.maskId); 4351 4352 var rect = document.createElementNS(NS, 'svg:rect'); 4353 rect.setAttributeNS(null, 'x', '0'); 4354 rect.setAttributeNS(null, 'y', '0'); 4355 rect.setAttributeNS(null, 'width', pf(width)); 4356 rect.setAttributeNS(null, 'height', pf(height)); 4357 rect.setAttributeNS(null, 'fill', fillColor); 4358 rect.setAttributeNS(null, 'mask', 'url(#' + current.maskId + ')'); 4359 this.defs.appendChild(mask); 4360 this.tgrp.appendChild(rect); 4361 4362 this.paintInlineImageXObject(imgData, mask); 4363 }, 4364 4365 paintFormXObjectBegin: function SVGGraphics_paintFormXObjectBegin(matrix, bbox) { 4366 this.save(); 4367 4368 if (isArray(matrix) && matrix.length === 6) {
4369 this.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); 4370 } 4371 4372 if (isArray(bbox) && bbox.length === 4) { 4373 var width = bbox[2] - bbox[0]; 4374 var height = bbox[3] - bbox[1]; 4375 4376 var cliprect = document.createElementNS(NS, 'svg:rect'); 4377 cliprect.setAttributeNS(null, 'x', bbox[0]); 4378 cliprect.setAttributeNS(null, 'y', bbox[1]); 4379 cliprect.setAttributeNS(null, 'width', pf(width)); 4380 cliprect.setAttributeNS(null, 'height', pf(height)); 4381 this.current.element = cliprect; 4382 this.clip('nonzero'); 4383 this.endPath(); 4384 } 4385 }, 4386 4387 paintFormXObjectEnd: function SVGGraphics_paintFormXObjectEnd() { 4388 this.restore(); 4389 }, 4390 }; 4391 return SVGGraphics; 4392 })(); 4393 4394 exports.SVGGraphics = SVGGraphics; 4395 }); 4396 4397 (function (root, factory) { 4398 { 4399 factory((root.pdfjsDisplayAnnotationLayer = {}), root.pdfjsSharedUtil, root.pdfjsDisplayDOMUtils); 4400 } 4401 })(this, function (exports, sharedUtil, displayDOMUtils) { 4402 var AnnotationBorderStyleType = sharedUtil.AnnotationBorderStyleType; 4403 var AnnotationType = sharedUtil.AnnotationType; 4404 var Util = sharedUtil.Util; 4405 var addLinkAttributes = displayDOMUtils.addLinkAttributes; 4406 var LinkTarget = displayDOMUtils.LinkTarget; 4407 var getFilenameFromUrl = displayDOMUtils.getFilenameFromUrl; 4408 var warn = sharedUtil.warn; 4409 var CustomStyle = displayDOMUtils.CustomStyle; 4410 var getDefaultSetting = displayDOMUtils.getDefaultSetting; 4411 4412 /** 4413 * @typedef {Object} AnnotationElementParameters 4414 * @property {Object} data 4415 * @property {HTMLDivElement} layer 4416 * @property {PDFPage} page 4417 * @property {PageViewport} viewport 4418 * @property {IPDFLinkService} linkService 4419 * @property {DownloadManager} downloadManager 4420 * @property {string} imageResourcesPath 4421 * @property {boolean} renderInteractiveForms 4422 */ 4423 4424 /** 4425 * @class 4426 * @alias AnnotationElementFactory 4427 */ 4428 function AnnotationElementFactory() {} 4429 4430 AnnotationElementFactory.prototype = /** @lends AnnotationElementFactory.prototype */ { 4431 /** 4432 * @param {AnnotationElementParameters} parameters 4433 * @returns {AnnotationElement} 4434 */ 4435 create: function AnnotationElementFactory_create(parameters) { 4436 var subtype = parameters.data.annotationType; 4437 4438 switch (subtype) { 4439 case AnnotationType.LINK: 4440 return new LinkAnnotationElement(parameters); 4441 4442 case AnnotationType.TEXT: 4443 return new TextAnnotationElement(parameters); 4444 4445 case AnnotationType.WIDGET: 4446 var fieldType = parameters.data.fieldType; 4447 4448 switch (fieldType) { 4449 case 'Tx': 4450 return new TextWidgetAnnotationElement(parameters); 4451 } 4452 return new WidgetAnnotationElement(parameters); 4453 4454 case AnnotationType.POPUP: 4455 return new PopupAnnotationElement(parameters); 4456 4457 case AnnotationType.HIGHLIGHT: 4458 return new HighlightAnnotationElement(parameters); 4459 4460 case AnnotationType.UNDERLINE: 4461 return new UnderlineAnnotationElement(parameters); 4462 4463 case AnnotationType.SQUIGGLY: 4464 return new SquigglyAnnotationElement(parameters); 4465 4466 case AnnotationType.STRIKEOUT: 4467 return new StrikeOutAnnotationElement(parameters); 4468 4469 case AnnotationType.FILEATTACHMENT: 4470 return new FileAttachmentAnnotationElement(parameters); 4471 4472 default: 4473 return new AnnotationElement(parameters); 4474 } 4475 }, 4476 }; 4477 4478 /** 4479 * @class 4480 * @alias AnnotationElement 4481 */ 4482 var AnnotationElement = (function AnnotationElementClosure() { 4483 function AnnotationElement(parameters, isRenderable) { 4484 this.isRenderable = isRenderable || false; 4485 this.data = parameters.data; 4486 this.layer = parameters.layer; 4487 this.page = parameters.page; 4488 this.viewport = parameters.viewport; 4489 this.linkService = parameters.linkService; 4490 this.downloadManager = parameters.downloadManager; 4491 this.imageResourcesPath = parameters.imageResourcesPath; 4492 this.renderInteractiveForms = parameters.renderInteractiveForms; 4493 4494 if (isRenderable) { 4495 this.container = this._createContainer(); 4496 } 4497 } 4498 4499 AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ { 4500 /** 4501 * Create an empty container for the annotation's HTML element. 4502 * 4503 * @private 4504 * @memberof AnnotationElement 4505 * @returns {HTMLSectionElement} 4506 */ 4507 _createContainer: function AnnotationElement_createContainer() { 4508 var data = this.data, 4509 page = this.page, 4510 viewport = this.viewport; 4511 var container = document.createElement('section'); 4512 var width = data.rect[2] - data.rect[0]; 4513 var height = data.rect[3] - data.rect[1]; 4514 4515 container.setAttribute('data-annotation-id', data.id); 4516 4517 // Do *not* modify `data.rect`, since that will corrupt the annotation 4518 // position on subsequent calls to `_createContainer` (see issue 6804). 4519 var rect = Util.normalizeRect([ 4520 data.rect[0], 4521 page.view[3] - data.rect[1] + page.view[1], 4522 data.rect[2], 4523 page.view[3] - data.rect[3] + page.view[1], 4524 ]); 4525 4526 CustomStyle.setProp('transform', container, 'matrix(' + viewport.transform.join(',') + ')'); 4527 CustomStyle.setProp('transformOrigin', container, -rect[0] + 'px ' + -rect[1] + 'px'); 4528 4529 if (data.borderStyle.width > 0) { 4530 container.style.borderWidth = data.borderStyle.width + 'px'; 4531 if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) { 4532 // Underline styles only have a bottom border, so we do not need 4533 // to adjust for all borders. This yields a similar result as 4534 // Adobe Acrobat/Reader. 4535 width = width - 2 * data.borderStyle.width; 4536 height = height - 2 * data.borderStyle.width; 4537 } 4538 4539 var horizontalRadius = data.borderStyle.horizontalCornerRadius; 4540 var verticalRadius = data.borderStyle.verticalCornerRadius; 4541 if (horizontalRadius > 0 || verticalRadius > 0) { 4542 var radius = horizontalRadius + 'px / ' + verticalRadius + 'px'; 4543 CustomStyle.setProp('borderRadius', container, radius); 4544 } 4545 4546 switch (data.borderStyle.style) { 4547 case AnnotationBorderStyleType.SOLID: 4548 container.style.borderStyle = 'solid'; 4549 break; 4550 4551 case AnnotationBorderStyleType.DASHED: 4552 container.style.borderStyle = 'dashed'; 4553 break; 4554 4555 case AnnotationBorderStyleType.BEVELED: 4556 warn('Unimplemented border style: beveled'); 4557 break; 4558 4559 case AnnotationBorderStyleType.INSET: 4560 warn('Unimplemented border style: inset'); 4561 break; 4562 4563 case AnnotationBorderStyleType.UNDERLINE: 4564 container.style.borderBottomStyle = 'solid'; 4565 break; 4566 4567 default: 4568 break; 4569 } 4570 4571 if (data.color) { 4572 container.style.borderColor = Util.makeCssRgb(data.color[0] | 0, data.color[1] | 0, data.color[2] | 0); 4573 } else { 4574 // Transparent (invisible) border, so do not draw it at all. 4575 container.style.borderWidth = 0; 4576 } 4577 } 4578 4579 container.style.left = rect[0] + 'px'; 4580 container.style.top = rect[1] + 'px'; 4581 4582 container.style.width = width + 'px'; 4583 container.style.height = height + 'px'; 4584 4585 return container; 4586 }, 4587 4588 /** 4589 * Create a popup for the annotation's HTML element. This is used for 4590 * annotations that do not have a Popup entry in the dictionary, but 4591 * are of a type that works with popups (such as Highlight annotations). 4592 * 4593 * @private 4594 * @param {HTMLSectionElement} container 4595 * @param {HTMLDivElement|HTMLImageElement|null} trigger 4596 * @param {Object} data 4597 * @memberof AnnotationElement 4598 */ 4599 _createPopup: function AnnotationElement_createPopup(container, trigger, data) { 4600 // If no trigger element is specified, create it. 4601 if (!trigger) { 4602 trigger = document.createElement('div'); 4603 trigger.style.height = container.style.height; 4604 trigger.style.width = container.style.width; 4605 container.appendChild(trigger); 4606 } 4607 4608 var popupElement = new PopupElement({ 4609 container: container, 4610 trigger: trigger, 4611 color: data.color, 4612 title: data.title, 4613 contents: data.contents, 4614 hideWrapper: true, 4615 }); 4616 var popup = popupElement.render(); 4617 4618 // Position the popup next to the annotation's container. 4619 popup.style.left = container.style.width; 4620
4621 container.appendChild(popup); 4622 }, 4623 4624 /** 4625 * Render the annotation's HTML element in the empty container. 4626 * 4627 * @public 4628 * @memberof AnnotationElement 4629 */ 4630 render: function AnnotationElement_render() { 4631 throw new Error('Abstract method AnnotationElement.render called'); 4632 }, 4633 }; 4634 4635 return AnnotationElement; 4636 })(); 4637 4638 /** 4639 * @class 4640 * @alias LinkAnnotationElement 4641 */ 4642 var LinkAnnotationElement = (function LinkAnnotationElementClosure() { 4643 function LinkAnnotationElement(parameters) { 4644 AnnotationElement.call(this, parameters, true); 4645 } 4646 4647 Util.inherit(LinkAnnotationElement, AnnotationElement, { 4648 /** 4649 * Render the link annotation's HTML element in the empty container. 4650 * 4651 * @public 4652 * @memberof LinkAnnotationElement 4653 * @returns {HTMLSectionElement} 4654 */ 4655 render: function LinkAnnotationElement_render() { 4656 this.container.className = 'linkAnnotation'; 4657 4658 var link = document.createElement('a'); 4659 addLinkAttributes(link, { 4660 url: this.data.url, 4661 target: this.data.newWindow ? LinkTarget.BLANK : undefined, 4662 }); 4663 4664 if (!this.data.url) { 4665 if (this.data.action) { 4666 this._bindNamedAction(link, this.data.action); 4667 } else { 4668 this._bindLink(link, this.data.dest || null); 4669 } 4670 } 4671 4672 this.container.appendChild(link); 4673 return this.container; 4674 }, 4675 4676 /** 4677 * Bind internal links to the link element. 4678 * 4679 * @private 4680 * @param {Object} link 4681 * @param {Object} destination 4682 * @memberof LinkAnnotationElement 4683 */ 4684 _bindLink: function LinkAnnotationElement_bindLink(link, destination) { 4685 var self = this; 4686 4687 link.href = this.linkService.getDestinationHash(destination); 4688 link.onclick = function () { 4689 if (destination) { 4690 self.linkService.navigateTo(destination); 4691 } 4692 return false; 4693 }; 4694 if (destination) { 4695 link.className = 'internalLink'; 4696 } 4697 }, 4698 4699 /** 4700 * Bind named actions to the link element. 4701 * 4702 * @private 4703 * @param {Object} link 4704 * @param {Object} action 4705 * @memberof LinkAnnotationElement 4706 */ 4707 _bindNamedAction: function LinkAnnotationElement_bindNamedAction(link, action) { 4708 var self = this; 4709 4710 link.href = this.linkService.getAnchorUrl(''); 4711 link.onclick = function () { 4712 self.linkService.executeNamedAction(action); 4713 return false; 4714 }; 4715 link.className = 'internalLink'; 4716 }, 4717 }); 4718 4719 return LinkAnnotationElement; 4720 })(); 4721 4722 /** 4723 * @class 4724 * @alias TextAnnotationElement 4725 */ 4726 var TextAnnotationElement = (function TextAnnotationElementClosure() { 4727 function TextAnnotationElement(parameters) { 4728 var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); 4729 AnnotationElement.call(this, parameters, isRenderable); 4730 } 4731 4732 Util.inherit(TextAnnotationElement, AnnotationElement, { 4733 /** 4734 * Render the text annotation's HTML element in the empty container. 4735 * 4736 * @public 4737 * @memberof TextAnnotationElement 4738 * @returns {HTMLSectionElement} 4739 */ 4740 render: function TextAnnotationElement_render() { 4741 this.container.className = 'textAnnotation'; 4742 4743 var image = document.createElement('img'); 4744 image.style.height = this.container.style.height; 4745 image.style.width = this.container.style.width; 4746 image.src = this.imageResourcesPath + 'annotation-' + this.data.name.toLowerCase() + '.svg'; 4747 image.alt = '[{{type}} Annotation]'; 4748 image.dataset.l10nId = 'text_annotation_type'; 4749 image.dataset.l10nArgs = JSON.stringify({ type: this.data.name }); 4750 4751 if (!this.data.hasPopup) { 4752 this._createPopup(this.container, image, this.data); 4753 } 4754 4755 this.container.appendChild(image); 4756 return this.container; 4757 }, 4758 }); 4759 4760 return TextAnnotationElement; 4761 })(); 4762 4763 /** 4764 * @class 4765 * @alias WidgetAnnotationElement 4766 */ 4767 var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() { 4768 function WidgetAnnotationElement(parameters) { 4769 var isRenderable = 4770 parameters.renderInteractiveForms || (!parameters.data.hasAppearance && !!parameters.data.fieldValue); 4771 AnnotationElement.call(this, parameters, isRenderable); 4772 } 4773 4774 Util.inherit(WidgetAnnotationElement, AnnotationElement, { 4775 /**
4776 * Render the widget annotation's HTML element in the empty container. 4777 * 4778 * @public 4779 * @memberof WidgetAnnotationElement 4780 * @returns {HTMLSectionElement} 4781 */ 4782 render: function WidgetAnnotationElement_render() { 4783 // Show only the container for unsupported field types. 4784 return this.container; 4785 }, 4786 }); 4787 4788 return WidgetAnnotationElement; 4789 })(); 4790 4791 /** 4792 * @class 4793 * @alias TextWidgetAnnotationElement 4794 */ 4795 var TextWidgetAnnotationElement = (function TextWidgetAnnotationElementClosure() { 4796 var TEXT_ALIGNMENT = ['left', 'center', 'right']; 4797 4798 function TextWidgetAnnotationElement(parameters) { 4799 WidgetAnnotationElement.call(this, parameters); 4800 } 4801 4802 Util.inherit(TextWidgetAnnotationElement, WidgetAnnotationElement, { 4803 /** 4804 * Render the text widget annotation's HTML element in the empty container. 4805 * 4806 * @public 4807 * @memberof TextWidgetAnnotationElement 4808 * @returns {HTMLSectionElement} 4809 */ 4810 render: function TextWidgetAnnotationElement_render() { 4811 this.container.className = 'textWidgetAnnotation'; 4812 4813 var element = null; 4814 if (this.renderInteractiveForms) { 4815 // NOTE: We cannot set the values using `element.value` below, since it 4816 // prevents the AnnotationLayer rasterizer in `test/driver.js` 4817 // from parsing the elements correctly for the reference tests. 4818 if (this.data.multiLine) { 4819 element = document.createElement('textarea'); 4820 element.textContent = this.data.fieldValue; 4821 } else { 4822 element = document.createElement('input'); 4823 element.type = 'text'; 4824 element.setAttribute('value', this.data.fieldValue); 4825 } 4826 4827 element.disabled = this.data.readOnly; 4828 4829 if (this.data.maxLen !== null) { 4830 element.maxLength = this.data.maxLen; 4831 } 4832 4833 if (this.data.comb) { 4834 var fieldWidth = this.data.rect[2] - this.data.rect[0]; 4835 var combWidth = fieldWidth / this.data.maxLen; 4836 4837 element.classList.add('comb'); 4838 element.style.letterSpacing = 'calc(' + combWidth + 'px - 1ch)'; 4839 } 4840 } else { 4841 element = document.createElement('div'); 4842 element.textContent = this.data.fieldValue; 4843 element.style.verticalAlign = 'middle'; 4844 element.style.display = 'table-cell'; 4845 4846 var font = null; 4847 if (this.data.fontRefName) { 4848 font = this.page.commonObjs.getData(this.data.fontRefName); 4849 } 4850 this._setTextStyle(element, font); 4851 } 4852 4853 if (this.data.textAlignment !== null) { 4854 element.style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment]; 4855 } 4856 4857 this.container.appendChild(element); 4858 return this.container; 4859 }, 4860 4861 /** 4862 * Apply text styles to the text in the element. 4863 * 4864 * @private 4865 * @param {HTMLDivElement} element 4866 * @param {Object} font 4867 * @memberof TextWidgetAnnotationElement 4868 */ 4869 _setTextStyle: function TextWidgetAnnotationElement_setTextStyle(element, font) { 4870 // TODO: This duplicates some of the logic in CanvasGraphics.setFont(). 4871 var style = element.style; 4872 style.fontSize = this.data.fontSize + 'px'; 4873 style.direction = this.data.fontDirection < 0 ? 'rtl' : 'ltr'; 4874 4875 if (!font) { 4876 return; 4877 } 4878 4879 style.fontWeight = font.black ? (font.bold ? '900' : 'bold') : font.bold ? 'bold' : 'normal'; 4880 style.fontStyle = font.italic ? 'italic' : 'normal'; 4881 4882 // Use a reasonable default font if the font doesn't specify a fallback. 4883 var fontFamily = font.loadedName ? '"' + font.loadedName + '", ' : ''; 4884 var fallbackName = font.fallbackName || 'Helvetica, sans-serif'; 4885 style.fontFamily = fontFamily + fallbackName; 4886 }, 4887 }); 4888 4889 return TextWidgetAnnotationElement; 4890 })(); 4891 4892 /** 4893 * @class 4894 * @alias PopupAnnotationElement 4895 */ 4896 var PopupAnnotationElement = (function PopupAnnotationElementClosure() { 4897 function PopupAnnotationElement(parameters) { 4898 var isRenderable = !!(parameters.data.title || parameters.data.contents); 4899 AnnotationElement.call(this, parameters, isRenderable); 4900 } 4901 4902 Util.inherit(PopupAnnotationElement, AnnotationElement, { 4903 /**
4904 * Render the popup annotation's HTML element in the empty container. 4905 * 4906 * @public 4907 * @memberof PopupAnnotationElement 4908 * @returns {HTMLSectionElement} 4909 */ 4910 render: function PopupAnnotationElement_render() { 4911 this.container.className = 'popupAnnotation'; 4912 4913 var selector = '[data-annotation-id="' + this.data.parentId + '"]'; 4914 var parentElement = this.layer.querySelector(selector); 4915 if (!parentElement) { 4916 return this.container; 4917 } 4918 4919 var popup = new PopupElement({ 4920 container: this.container, 4921 trigger: parentElement, 4922 color: this.data.color, 4923 title: this.data.title, 4924 contents: this.data.contents, 4925 }); 4926 4927 // Position the popup next to the parent annotation's container. 4928 // PDF viewers ignore a popup annotation's rectangle. 4929 var parentLeft = parseFloat(parentElement.style.left); 4930 var parentWidth = parseFloat(parentElement.style.width); 4931 CustomStyle.setProp( 4932 'transformOrigin', 4933 this.container, 4934 -(parentLeft + parentWidth) + 'px -' + parentElement.style.top 4935 ); 4936 this.container.style.left = parentLeft + parentWidth + 'px'; 4937 4938 this.container.appendChild(popup.render()); 4939 return this.container; 4940 }, 4941 }); 4942 4943 return PopupAnnotationElement; 4944 })(); 4945 4946 /** 4947 * @class 4948 * @alias PopupElement 4949 */ 4950 var PopupElement = (function PopupElementClosure() { 4951 var BACKGROUND_ENLIGHT = 0.7; 4952 4953 function PopupElement(parameters) { 4954 this.container = parameters.container; 4955 this.trigger = parameters.trigger; 4956 this.color = parameters.color; 4957 this.title = parameters.title; 4958 this.contents = parameters.contents; 4959 this.hideWrapper = parameters.hideWrapper || false; 4960 4961 this.pinned = false; 4962 } 4963 4964 PopupElement.prototype = /** @lends PopupElement.prototype */ { 4965 /** 4966 * Render the popup's HTML element. 4967 * 4968 * @public 4969 * @memberof PopupElement 4970 * @returns {HTMLSectionElement} 4971 */ 4972 render: function PopupElement_render() { 4973 var wrapper = document.createElement('div'); 4974 wrapper.className = 'popupWrapper'; 4975 4976 // For Popup annotations we hide the entire section because it contains 4977 // only the popup. However, for Text annotations without a separate Popup 4978 // annotation, we cannot hide the entire container as the image would 4979 // disappear too. In that special case, hiding the wrapper suffices. 4980 this.hideElement = this.hideWrapper ? wrapper : this.container; 4981 this.hideElement.setAttribute('hidden', true); 4982 4983 var popup = document.createElement('div'); 4984 popup.className = 'popup'; 4985 4986 var color = this.color; 4987 if (color) { 4988 // Enlighten the color. 4989 var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0]; 4990 var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1]; 4991 var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2]; 4992 popup.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0); 4993 } 4994 4995 var contents = this._formatContents(this.contents); 4996 var title = document.createElement('h1'); 4997 title.textContent = this.title; 4998 4999 // Attach the event listeners to the trigger element. 5000 this.trigger.addEventListener('click', this._toggle.bind(this)); 5001 this.trigger.addEventListener('mouseover', this._show.bind(this, false)); 5002 this.trigger.addEventListener('mouseout', this._hide.bind(this, false)); 5003 popup.addEventListener('click', this._hide.bind(this, true)); 5004 5005 popup.appendChild(title); 5006 popup.appendChild(contents);
5007 wrapper.appendChild(popup); 5008 return wrapper; 5009 }, 5010 5011 /** 5012 * Format the contents of the popup by adding newlines where necessary. 5013 * 5014 * @private 5015 * @param {string} contents 5016 * @memberof PopupElement 5017 * @returns {HTMLParagraphElement} 5018 */ 5019 _formatContents: function PopupElement_formatContents(contents) { 5020 var p = document.createElement('p'); 5021 var lines = contents.split(/(?:\r\n?|\n)/); 5022 for (var i = 0, ii = lines.length; i < ii; ++i) { 5023 var line = lines[i]; 5024 p.appendChild(document.createTextNode(line)); 5025 if (i < ii - 1) { 5026 p.appendChild(document.createElement('br')); 5027 } 5028 } 5029 return p; 5030 }, 5031 5032 /** 5033 * Toggle the visibility of the popup. 5034 * 5035 * @private 5036 * @memberof PopupElement 5037 */ 5038 _toggle: function PopupElement_toggle() { 5039 if (this.pinned) { 5040 this._hide(true); 5041 } else { 5042 this._show(true); 5043 } 5044 }, 5045 5046 /** 5047 * Show the popup. 5048 * 5049 * @private 5050 * @param {boolean} pin 5051 * @memberof PopupElement 5052 */ 5053 _show: function PopupElement_show(pin) { 5054 if (pin) { 5055 this.pinned = true; 5056 } 5057 if (this.hideElement.hasAttribute('hidden')) { 5058 this.hideElement.removeAttribute('hidden'); 5059 this.container.style.zIndex += 1; 5060 } 5061 }, 5062 5063 /** 5064 * Hide the popup. 5065 * 5066 * @private 5067 * @param {boolean} unpin 5068 * @memberof PopupElement 5069 */ 5070 _hide: function PopupElement_hide(unpin) { 5071 if (unpin) { 5072 this.pinned = false; 5073 } 5074 if (!this.hideElement.hasAttribute('hidden') && !this.pinned) { 5075 this.hideElement.setAttribute('hidden', true); 5076 this.container.style.zIndex -= 1; 5077 } 5078 }, 5079 }; 5080 5081 return PopupElement; 5082 })(); 5083 5084 /** 5085 * @class 5086 * @alias HighlightAnnotationElement 5087 */ 5088 var HighlightAnnotationElement = (function HighlightAnnotationElementClosure() { 5089 function HighlightAnnotationElement(parameters) { 5090 var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); 5091 AnnotationElement.call(this, parameters, isRenderable); 5092 } 5093 5094 Util.inherit(HighlightAnnotationElement, AnnotationElement, { 5095 /** 5096 * Render the highlight annotation's HTML element in the empty container. 5097 * 5098 * @public 5099 * @memberof HighlightAnnotationElement 5100 * @returns {HTMLSectionElement} 5101 */ 5102 render: function HighlightAnnotationElement_render() { 5103 this.container.className = 'highlightAnnotation'; 5104 5105 if (!this.data.hasPopup) { 5106 this._createPopup(this.container, null, this.data); 5107 } 5108 5109 return this.container; 5110 }, 5111 }); 5112 5113 return HighlightAnnotationElement; 5114 })(); 5115 5116 /** 5117 * @class 5118 * @alias UnderlineAnnotationElement 5119 */ 5120 var UnderlineAnnotationElement = (function UnderlineAnnotationElementClosure() { 5121 function UnderlineAnnotationElement(parameters) { 5122 var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); 5123 AnnotationElement.call(this, parameters, isRenderable); 5124 } 5125 5126 Util.inherit(UnderlineAnnotationElement, AnnotationElement, { 5127 /** 5128 * Render the underline annotation's HTML element in the empty container. 5129 * 5130 * @public 5131 * @memberof UnderlineAnnotationElement 5132 * @returns {HTMLSectionElement} 5133 */ 5134 render: function UnderlineAnnotationElement_render() { 5135 this.container.className = 'underlineAnnotation'; 5136 5137 if (!this.data.hasPopup) { 5138 this._createPopup(this.container, null, this.data); 5139 } 5140 5141 return this.container; 5142 }, 5143 }); 5144 5145 return UnderlineAnnotationElement; 5146 })(); 5147 5148 /** 5149 * @class 5150 * @alias SquigglyAnnotationElement 5151 */ 5152 var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() { 5153 function SquigglyAnnotationElement(parameters) { 5154 var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); 5155 AnnotationElement.call(this, parameters, isRenderable); 5156 } 5157 5158 Util.inherit(SquigglyAnnotationElement, AnnotationElement, { 5159 /**
5160 * Render the squiggly annotation's HTML element in the empty container. 5161 * 5162 * @public 5163 * @memberof SquigglyAnnotationElement 5164 * @returns {HTMLSectionElement} 5165 */ 5166 render: function SquigglyAnnotationElement_render() { 5167 this.container.className = 'squigglyAnnotation'; 5168 5169 if (!this.data.hasPopup) { 5170 this._createPopup(this.container, null, this.data); 5171 } 5172 5173 return this.container; 5174 }, 5175 }); 5176 5177 return SquigglyAnnotationElement; 5178 })(); 5179 5180 /** 5181 * @class 5182 * @alias StrikeOutAnnotationElement 5183 */ 5184 var StrikeOutAnnotationElement = (function StrikeOutAnnotationElementClosure() { 5185 function StrikeOutAnnotationElement(parameters) { 5186 var isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents); 5187 AnnotationElement.call(this, parameters, isRenderable); 5188 } 5189 5190 Util.inherit(StrikeOutAnnotationElement, AnnotationElement, { 5191 /** 5192 * Render the strikeout annotation's HTML element in the empty container. 5193 * 5194 * @public 5195 * @memberof StrikeOutAnnotationElement 5196 * @returns {HTMLSectionElement} 5197 */ 5198 render: function StrikeOutAnnotationElement_render() { 5199 this.container.className = 'strikeoutAnnotation'; 5200 5201 if (!this.data.hasPopup) { 5202 this._createPopup(this.container, null, this.data); 5203 } 5204 5205 return this.container; 5206 }, 5207 }); 5208 5209 return StrikeOutAnnotationElement; 5210 })(); 5211 5212 /** 5213 * @class 5214 * @alias FileAttachmentAnnotationElement 5215 */ 5216 var FileAttachmentAnnotationElement = (function FileAttachmentAnnotationElementClosure() { 5217 function FileAttachmentAnnotationElement(parameters) { 5218 AnnotationElement.call(this, parameters, true); 5219 5220 this.filename = getFilenameFromUrl(parameters.data.file.filename); 5221 this.content = parameters.data.file.content; 5222 } 5223 5224 Util.inherit(FileAttachmentAnnotationElement, AnnotationElement, { 5225 /** 5226 * Render the file attachment annotation's HTML element in the empty 5227 * container. 5228 * 5229 * @public 5230 * @memberof FileAttachmentAnnotationElement 5231 * @returns {HTMLSectionElement} 5232 */ 5233 render: function FileAttachmentAnnotationElement_render() { 5234 this.container.className = 'fileAttachmentAnnotation'; 5235 5236 var trigger = document.createElement('div'); 5237 trigger.style.height = this.container.style.height; 5238 trigger.style.width = this.container.style.width; 5239 trigger.addEventListener('dblclick', this._download.bind(this)); 5240 5241 if (!this.data.hasPopup && (this.data.title || this.data.contents)) { 5242 this._createPopup(this.container, trigger, this.data); 5243 } 5244 5245 this.container.appendChild(trigger); 5246 return this.container; 5247 }, 5248 5249 /** 5250 * Download the file attachment associated with this annotation. 5251 * 5252 * @private 5253 * @memberof FileAttachmentAnnotationElement 5254 */ 5255 _download: function FileAttachmentAnnotationElement_download() { 5256 if (!this.downloadManager) { 5257 warn('Download cannot be started due to unavailable download manager'); 5258 return; 5259 } 5260 this.downloadManager.downloadData(this.content, this.filename, ''); 5261 }, 5262 }); 5263 5264 return FileAttachmentAnnotationElement; 5265 })(); 5266 5267 /** 5268 * @typedef {Object} AnnotationLayerParameters 5269 * @property {PageViewport} viewport 5270 * @property {HTMLDivElement} div 5271 * @property {Array} annotations 5272 * @property {PDFPage} page 5273 * @property {IPDFLinkService} linkService 5274 * @property {string} imageResourcesPath 5275 * @property {boolean} renderInteractiveForms 5276 */ 5277 5278 /** 5279 * @class 5280 * @alias AnnotationLayer 5281 */ 5282 var AnnotationLayer = (function AnnotationLayerClosure() { 5283 return { 5284 /**
5285 * Render a new annotation layer with all annotation elements. 5286 * 5287 * @public 5288 * @param {AnnotationLayerParameters} parameters 5289 * @memberof AnnotationLayer 5290 */ 5291 render: function AnnotationLayer_render(parameters) { 5292 var annotationElementFactory = new AnnotationElementFactory(); 5293 5294 for (var i = 0, ii = parameters.annotations.length; i < ii; i++) { 5295 var data = parameters.annotations[i]; 5296 if (!data) { 5297 continue; 5298 } 5299 5300 var properties = { 5301 data: data, 5302 layer: parameters.div, 5303 page: parameters.page, 5304 viewport: parameters.viewport, 5305 linkService: parameters.linkService, 5306 downloadManager: parameters.downloadManager, 5307 imageResourcesPath: parameters.imageResourcesPath || getDefaultSetting('imageResourcesPath'), 5308 renderInteractiveForms: parameters.renderInteractiveForms || false, 5309 }; 5310 var element = annotationElementFactory.create(properties); 5311 if (element.isRenderable) { 5312 parameters.div.appendChild(element.render()); 5313 } 5314 } 5315 }, 5316 5317 /** 5318 * Update the annotation elements on existing annotation layer. 5319 * 5320 * @public 5321 * @param {AnnotationLayerParameters} parameters 5322 * @memberof AnnotationLayer 5323 */ 5324 update: function AnnotationLayer_update(parameters) { 5325 for (var i = 0, ii = parameters.annotations.length; i < ii; i++) { 5326 var data = parameters.annotations[i]; 5327 var element = parameters.div.querySelector('[data-annotation-id="' + data.id + '"]'); 5328 if (element) { 5329 CustomStyle.setProp('transform', element, 'matrix(' + parameters.viewport.transform.join(',') + ')'); 5330 } 5331 } 5332 parameters.div.removeAttribute('hidden'); 5333 }, 5334 }; 5335 })(); 5336 5337 exports.AnnotationLayer = AnnotationLayer; 5338 }); 5339 5340 (function (root, factory) { 5341 { 5342 factory((root.pdfjsDisplayTextLayer = {}), root.pdfjsSharedUtil, root.pdfjsDisplayDOMUtils); 5343 } 5344 })(this, function (exports, sharedUtil, displayDOMUtils) { 5345 var Util = sharedUtil.Util; 5346 var createPromiseCapability = sharedUtil.createPromiseCapability; 5347 var CustomStyle = displayDOMUtils.CustomStyle; 5348 var getDefaultSetting = displayDOMUtils.getDefaultSetting; 5349 5350 /** 5351 * Text layer render parameters. 5352 * 5353 * @typedef {Object} TextLayerRenderParameters 5354 * @property {TextContent} textContent - Text content to render (the object is 5355 * returned by the page's getTextContent() method). 5356 * @property {HTMLElement} container - HTML element that will contain text runs. 5357 * @property {PageViewport} viewport - The target viewport to properly 5358 * layout the text runs. 5359 * @property {Array} textDivs - (optional) HTML elements that are correspond 5360 * the text items of the textContent input. This is output and shall be 5361 * initially be set to empty array. 5362 * @property {number} timeout - (optional) Delay in milliseconds before 5363 * rendering of the text runs occurs. 5364 * @property {boolean} enhanceTextSelection - (optional) Whether to turn on the 5365 * text selection enhancement. 5366 */ 5367 var renderTextLayer = (function renderTextLayerClosure() { 5368 var MAX_TEXT_DIVS_TO_RENDER = 100000; 5369 5370 var NonWhitespaceRegexp = /\S/; 5371 5372 function isAllWhitespace(str) { 5373 return !NonWhitespaceRegexp.test(str); 5374 } 5375 5376 // Text layers may contain many thousand div's, and using `styleBuf` avoids 5377 // creating many intermediate strings when building their 'style' properties. 5378 var styleBuf = ['left: ', 0, 'px; top: ', 0, 'px; font-size: ', 0, 'px; font-family: ', '', ';']; 5379 5380 function appendText(task, geom, styles) { 5381 // Initialize all used properties to keep the caches monomorphic. 5382 var textDiv = document.createElement('div'); 5383 var textDivProperties = { 5384 style: null, 5385 angle: 0, 5386 canvasWidth: 0, 5387 isWhitespace: false, 5388 originalTransform: null, 5389 paddingBottom: 0, 5390 paddingLeft: 0, 5391 paddingRight: 0, 5392 paddingTop: 0, 5393 scale: 1, 5394 }; 5395 5396 task._textDivs.push(textDiv); 5397 if (isAllWhitespace(geom.str)) { 5398 textDivProperties.isWhitespace = true; 5399 task._textDivProperties.set(textDiv, textDivProperties); 5400 return; 5401 } 5402 5403 var tx = Util.transform(task._viewport.transform, geom.transform); 5404 var angle = Math.atan2(tx[1], tx[0]); 5405 var style = styles[geom.fontName]; 5406 if (style.vertical) { 5407 angle += Math.PI / 2; 5408 } 5409 var fontHeight = Math.sqrt(tx[2] * tx[2] + tx[3] * tx[3]); 5410 var fontAscent = fontHeight; 5411 if (style.ascent) { 5412 fontAscent = style.ascent * fontAscent; 5413 }
5413 else if (style.descent) { 5414 fontAscent = (1 + style.descent) * fontAscent; 5415 } 5416 5417 var left; 5418 var top; 5419 if (angle === 0) { 5420 left = tx[4]; 5421 top = tx[5] - fontAscent; 5422 } else { 5423 left = tx[4] + fontAscent * Math.sin(angle); 5424 top = tx[5] - fontAscent * Math.cos(angle); 5425 } 5426 styleBuf[1] = left; 5427 styleBuf[3] = top; 5428 styleBuf[5] = fontHeight; 5429 styleBuf[7] = style.fontFamily; 5430 textDivProperties.style = styleBuf.join(''); 5431 textDiv.setAttribute('style', textDivProperties.style); 5432 5433 textDiv.textContent = geom.str; 5434 // |fontName| is only used by the Font Inspector. This test will succeed 5435 // when e.g. the Font Inspector is off but the Stepper is on, but it's 5436 // not worth the effort to do a more accurate test. We only use `dataset` 5437 // here to make the font name available for the debugger. 5438 if (getDefaultSetting('pdfBug')) { 5439 textDiv.dataset.fontName = geom.fontName; 5440 } 5441 if (angle !== 0) { 5442 textDivProperties.angle = angle * (180 / Math.PI); 5443 } 5444 // We don't bother scaling single-char text divs, because it has very 5445 // little effect on text highlighting. This makes scrolling on docs with 5446 // lots of such divs a lot faster. 5447 if (geom.str.length > 1) { 5448 if (style.vertical) { 5449 textDivProperties.canvasWidth = geom.height * task._viewport.scale; 5450 } else { 5451 textDivProperties.canvasWidth = geom.width * task._viewport.scale; 5452 } 5453 } 5454 task._textDivProperties.set(textDiv, textDivProperties); 5455 5456 if (task._enhanceTextSelection) { 5457 var angleCos = 1, 5458 angleSin = 0; 5459 if (angle !== 0) { 5460 angleCos = Math.cos(angle); 5461 angleSin = Math.sin(angle); 5462 } 5463 var divWidth = (style.vertical ? geom.height : geom.width) * task._viewport.scale; 5464 var divHeight = fontHeight; 5465 5466 var m, b; 5467 if (angle !== 0) { 5468 m = [angleCos, angleSin, -angleSin, angleCos, left, top]; 5469 b = Util.getAxialAlignedBoundingBox([0, 0, divWidth, divHeight], m); 5470 } else { 5471 b = [left, top, left + divWidth, top + divHeight]; 5472 } 5473 5474 task._bounds.push({ 5475 left: b[0], 5476 top: b[1], 5477 right: b[2], 5478 bottom: b[3], 5479 div: textDiv, 5480 size: [divWidth, divHeight], 5481 m: m, 5482 }); 5483 } 5484 } 5485 5486 function render(task) { 5487 if (task._canceled) { 5488 return; 5489 } 5490 var textLayerFrag = task._container; 5491 var textDivs = task._textDivs; 5492 var capability = task._capability; 5493 var textDivsLength = textDivs.length; 5494 5495 // No point in rendering many divs as it would make the browser 5496 // unusable even after the divs are rendered. 5497 if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) { 5498 task._renderingDone = true; 5499 capability.resolve(); 5500 return; 5501 } 5502 5503 var canvas = document.createElement('canvas'); 5504 canvas.mozOpaque = true; 5505 var ctx = canvas.getContext('2d', { alpha: false }); 5506 5507 var lastFontSize; 5508 var lastFontFamily; 5509 for (var i = 0; i < textDivsLength; i++) { 5510 var textDiv = textDivs[i]; 5511 var textDivProperties = task._textDivProperties.get(textDiv); 5512 if (textDivProperties.isWhitespace) { 5513 continue; 5514 } 5515 5516 var fontSize = textDiv.style.fontSize; 5517 var fontFamily = textDiv.style.fontFamily; 5518 5519 // Only build font string and set to context if different from last. 5520 if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) { 5521 ctx.font = fontSize + ' ' + fontFamily; 5522 lastFontSize = fontSize; 5523 lastFontFamily = fontFamily; 5524 } 5525 5526 var width = ctx.measureText(textDiv.textContent).width; 5527 textLayerFrag.appendChild(textDiv); 5528 5529 var transform = ''; 5530 if (textDivProperties.canvasWidth !== 0 && width > 0) { 5531 textDivProperties.scale = textDivProperties.canvasWidth / width; 5532 transform = 'scaleX(' + textDivProperties.scale + ')'; 5533 } 5534 if (textDivProperties.angle !== 0) { 5535 transform = 'rotate(' + textDivProperties.angle + 'deg) ' + transform; 5536 } 5537 if (transform !== '') { 5538 textDivProperties.originalTransform = transform; 5539 CustomStyle.setProp('transform', textDiv, transform); 5540 } 5541 task._textDivProperties.set(textDiv, textDivProperties); 5542 } 5543 task._renderingDone = true; 5544 capability.resolve(); 5545 } 5546 5547 function expand(task) { 5548 var bounds = task._bounds; 5549 var viewport = task._viewport; 5550 5551 var expanded = expandBounds(viewport.width, viewport.height, bounds); 5552 for (var i = 0; i < expanded.length; i++) { 5553 var div = bounds[i].div; 5554 var divProperties = task._textDivProperties.get(div); 5555 if (divProperties.angle === 0) { 5556 divProperties.paddingLeft = bounds[i].left - expanded[i].left; 5557 divProperties.paddingTop = bounds[i].top - expanded[i].top; 5558 divProperties.paddingRight = expanded[i].right - bounds[i].right; 5559 divProperties.paddingBottom = expanded[i].bottom - bounds[i].bottom; 5560 task._textDivProperties.set(div, divProperties); 5561 continue; 5562 } 5563 // Box is rotated -- trying to find padding so rotated div will not
5564 // exceed its expanded bounds. 5565 var e = expanded[i], 5566 b = bounds[i]; 5567 var m = b.m, 5568 c = m[0], 5569 s = m[1]; 5570 // Finding intersections with expanded box. 5571 var points = [[0, 0], [0, b.size[1]], [b.size[0], 0], b.size]; 5572 var ts = new Float64Array(64); 5573 points.forEach(function (p, i) { 5574 var t = Util.applyTransform(p, m); 5575 ts[i + 0] = c && (e.left - t[0]) / c; 5576 ts[i + 4] = s && (e.top - t[1]) / s; 5577 ts[i + 8] = c && (e.right - t[0]) / c; 5578 ts[i + 12] = s && (e.bottom - t[1]) / s; 5579 5580 ts[i + 16] = s && (e.left - t[0]) / -s; 5581 ts[i + 20] = c && (e.top - t[1]) / c; 5582 ts[i + 24] = s && (e.right - t[0]) / -s; 5583 ts[i + 28] = c && (e.bottom - t[1]) / c; 5584 5585 ts[i + 32] = c && (e.left - t[0]) / -c; 5586 ts[i + 36] = s && (e.top - t[1]) / -s; 5587 ts[i + 40] = c && (e.right - t[0]) / -c; 5588 ts[i + 44] = s && (e.bottom - t[1]) / -s; 5589 5590 ts[i + 48] = s && (e.left - t[0]) / s; 5591 ts[i + 52] = c && (e.top - t[1]) / -c; 5592 ts[i + 56] = s && (e.right - t[0]) / s; 5593 ts[i + 60] = c && (e.bottom - t[1]) / -c; 5594 }); 5595 var findPositiveMin = function (ts, offset, count) { 5596 var result = 0; 5597 for (var i = 0; i < count; i++) { 5598 var t = ts[offset++]; 5599 if (t > 0) { 5600 result = result ? Math.min(t, result) : t; 5601 } 5602 } 5603 return result; 5604 }; 5605 // Not based on math, but to simplify calculations, using cos and sin 5606 // absolute values to not exceed the box (it can but insignificantly). 5607 var boxScale = 1 + Math.min(Math.abs(c), Math.abs(s)); 5608 divProperties.paddingLeft = findPositiveMin(ts, 32, 16) / boxScale; 5609 divProperties.paddingTop = findPositiveMin(ts, 48, 16) / boxScale; 5610 divProperties.paddingRight = findPositiveMin(ts, 0, 16) / boxScale; 5611 divProperties.paddingBottom = findPositiveMin(ts, 16, 16) / boxScale; 5612 task._textDivProperties.set(div, divProperties); 5613 } 5614 } 5615 5616 function expandBounds(width, height, boxes) { 5617 var bounds = boxes.map(function (box, i) { 5618 return { 5619 x1: box.left, 5620 y1: box.top, 5621 x2: box.right, 5622 y2: box.bottom, 5623 index: i, 5624 x1New: undefined, 5625 x2New: undefined, 5626 }; 5627 }); 5628 expandBoundsLTR(width, bounds); 5629 var expanded = new Array(boxes.length); 5630 bounds.forEach(function (b) { 5631 var i = b.index; 5632 expanded[i] = { 5633 left: b.x1New, 5634 top: 0, 5635 right: b.x2New, 5636 bottom: 0, 5637 }; 5638 }); 5639 5640 // Rotating on 90 degrees and extending extended boxes. Reusing the bounds 5641 // array and objects. 5642 boxes.map(function (box, i) { 5643 var e = expanded[i], 5644 b = bounds[i]; 5645 b.x1 = box.top; 5646 b.y1 = width - e.right; 5647 b.x2 = box.bottom; 5648 b.y2 = width - e.left; 5649 b.index = i; 5650 b.x1New = undefined; 5651 b.x2New = undefined; 5652 }); 5653 expandBoundsLTR(height, bounds); 5654 5655 bounds.forEach(function (b) { 5656 var i = b.index; 5657 expanded[i].top = b.x1New; 5658 expanded[i].bottom = b.x2New; 5659 }); 5660 return expanded; 5661 } 5662 5663 function expandBoundsLTR(width, bounds) { 5664 // Sorting by x1 coordinate and walk by the bounds in the same order. 5665 bounds.sort(function (a, b) { 5666 return a.x1 - b.x1 || a.index - b.index; 5667 }); 5668 5669 // First we see on the horizon is a fake boundary. 5670 var fakeBoundary = { 5671 x1: -Infinity, 5672 y1: -Infinity, 5673 x2: 0, 5674 y2: Infinity, 5675 index: -1, 5676 x1New: 0, 5677 x2New: 0, 5678 }; 5679 var horizon = [ 5680 { 5681 start: -Infinity, 5682 end: Infinity, 5683 boundary: fakeBoundary, 5684 }, 5685 ]; 5686 5687 bounds.forEach(function (boundary) { 5688 // Searching for the affected part of horizon.
5689 // TODO red-black tree or simple binary search 5690 var i = 0; 5691 while (i < horizon.length && horizon[i].end <= boundary.y1) { 5692 i++; 5693 } 5694 var j = horizon.length - 1; 5695 while (j >= 0 && horizon[j].start >= boundary.y2) { 5696 j--; 5697 } 5698 5699 var horizonPart, affectedBoundary; 5700 var q, 5701 k, 5702 maxXNew = -Infinity; 5703 for (q = i; q <= j; q++) { 5704 horizonPart = horizon[q]; 5705 affectedBoundary = horizonPart.boundary; 5706 var xNew; 5707 if (affectedBoundary.x2 > boundary.x1) { 5708 // In the middle of the previous element, new x shall be at the 5709 // boundary start. Extending if further if the affected bondary 5710 // placed on top of the current one. 5711 xNew = affectedBoundary.index > boundary.index ? affectedBoundary.x1New : boundary.x1; 5712 } else if (affectedBoundary.x2New === undefined) { 5713 // We have some space in between, new x in middle will be a fair 5714 // choice. 5715 xNew = (affectedBoundary.x2 + boundary.x1) / 2; 5716 } else { 5717 // Affected boundary has x2new set, using it as new x. 5718 xNew = affectedBoundary.x2New; 5719 } 5720 if (xNew > maxXNew) { 5721 maxXNew = xNew; 5722 } 5723 } 5724 5725 // Set new x1 for current boundary. 5726 boundary.x1New = maxXNew; 5727 5728 // Adjusts new x2 for the affected boundaries. 5729 for (q = i; q <= j; q++) { 5730 horizonPart = horizon[q]; 5731 affectedBoundary = horizonPart.boundary; 5732 if (affectedBoundary.x2New === undefined) { 5733 // Was not set yet, choosing new x if possible. 5734 if (affectedBoundary.x2 > boundary.x1) { 5735 // Current and affected boundaries intersect. If affected boundary 5736 // is placed on top of the current, shrinking the affected. 5737 if (affectedBoundary.index > boundary.index) { 5738 affectedBoundary.x2New = affectedBoundary.x2; 5739 } 5740 } else { 5741 affectedBoundary.x2New = maxXNew; 5742 } 5743 } else if (affectedBoundary.x2New > maxXNew) { 5744 // Affected boundary is touching new x, pushing it back. 5745 affectedBoundary.x2New = Math.max(maxXNew, affectedBoundary.x2); 5746 } 5747 } 5748 5749 // Fixing the horizon. 5750 var changedHorizon = [], 5751 lastBoundary = null; 5752 for (q = i; q <= j; q++) { 5753 horizonPart = horizon[q]; 5754 affectedBoundary = horizonPart.boundary; 5755 // Checking which boundary will be visible. 5756 var useBoundary = affectedBoundary.x2 > boundary.x2 ? affectedBoundary : boundary; 5757 if (lastBoundary === useBoundary) { 5758 // Merging with previous. 5759 changedHorizon[changedHorizon.length - 1].end = horizonPart.end; 5760 } else { 5761 changedHorizon.push({ 5762 start: horizonPart.start, 5763 end: horizonPart.end, 5764 boundary: useBoundary, 5765 }); 5766 lastBoundary = useBoundary; 5767 } 5768 } 5769 if (horizon[i].start < boundary.y1) { 5770 changedHorizon[0].start = boundary.y1; 5771 changedHorizon.unshift({ 5772 start: horizon[i].start, 5773 end: boundary.y1, 5774 boundary: horizon[i].boundary, 5775 }); 5776 } 5777 if (boundary.y2 < horizon[j].end) { 5778 changedHorizon[changedHorizon.length - 1].end = boundary.y2; 5779 changedHorizon.push({ 5780 start: boundary.y2, 5781 end: horizon[j].end, 5782 boundary: horizon[j].boundary, 5783 }); 5784 } 5785 5786 // Set x2 new of boundary that is no longer visible (see overlapping case 5787 // above). 5788 // TODO more efficient, e.g. via reference counting. 5789 for (q = i; q <= j; q++) { 5790 horizonPart = horizon[q]; 5791 affectedBoundary = horizonPart.boundary; 5792 if (affectedBoundary.x2New !== undefined) { 5793 continue; 5794 } 5795 var used = false;
5796 for (k = i - 1; !used && k >= 0 && horizon[k].start >= affectedBoundary.y1; k--) { 5797 used = horizon[k].boundary === affectedBoundary; 5798 } 5799 for (k = j + 1; !used && k < horizon.length && horizon[k].end <= affectedBoundary.y2; k++) { 5800 used = horizon[k].boundary === affectedBoundary; 5801 } 5802 for (k = 0; !used && k < changedHorizon.length; k++) { 5803 used = changedHorizon[k].boundary === affectedBoundary; 5804 } 5805 if (!used) { 5806 affectedBoundary.x2New = maxXNew; 5807 } 5808 } 5809 5810 Array.prototype.splice.apply(horizon, [i, j - i + 1].concat(changedHorizon)); 5811 }); 5812 5813 // Set new x2 for all unset boundaries. 5814 horizon.forEach(function (horizonPart) { 5815 var affectedBoundary = horizonPart.boundary; 5816 if (affectedBoundary.x2New === undefined) { 5817 affectedBoundary.x2New = Math.max(width, affectedBoundary.x2); 5818 } 5819 }); 5820 } 5821 5822 /** 5823 * Text layer rendering task. 5824 * 5825 * @param {TextContent} textContent 5826 * @param {HTMLElement} container 5827 * @param {PageViewport} viewport 5828 * @param {Array} textDivs 5829 * @param {boolean} enhanceTextSelection 5830 * @private 5831 */ 5832 function TextLayerRenderTask(textContent, container, viewport, textDivs, enhanceTextSelection) { 5833 this._textContent = textContent; 5834 this._container = container; 5835 this._viewport = viewport; 5836 this._textDivs = textDivs || []; 5837 this._textDivProperties = new WeakMap(); 5838 this._renderingDone = false; 5839 this._canceled = false; 5840 this._capability = createPromiseCapability(); 5841 this._renderTimer = null; 5842 this._bounds = []; 5843 this._enhanceTextSelection = !!enhanceTextSelection; 5844 } 5845 5846 TextLayerRenderTask.prototype = { 5847 get promise() { 5848 return this._capability.promise; 5849 }, 5850 5851 cancel: function TextLayer_cancel() { 5852 this._canceled = true; 5853 if (this._renderTimer !== null) { 5854 clearTimeout(this._renderTimer); 5855 this._renderTimer = null; 5856 } 5857 this._capability.reject('canceled'); 5858 }, 5859 5860 _render: function TextLayer_render(timeout) { 5861 var textItems = this._textContent.items; 5862 var textStyles = this._textContent.styles; 5863 for (var i = 0, len = textItems.length; i < len; i++) { 5864 appendText(this, textItems[i], textStyles); 5865 } 5866 5867 if (!timeout) { 5868 // Render right away 5869 render(this); 5870 } else { 5871 // Schedule 5872 var self = this; 5873 this._renderTimer = setTimeout(function () { 5874 render(self); 5875 self._renderTimer = null; 5876 }, timeout); 5877 } 5878 }, 5879 5880 expandTextDivs: function TextLayer_expandTextDivs(expandDivs) { 5881 if (!this._enhanceTextSelection || !this._renderingDone) { 5882 return; 5883 } 5884 if (this._bounds !== null) { 5885 expand(this); 5886 this._bounds = null; 5887 } 5888 5889 for (var i = 0, ii = this._textDivs.length; i < ii; i++) { 5890 var div = this._textDivs[i]; 5891 var divProperties = this._textDivProperties.get(div); 5892 5893 if (divProperties.isWhitespace) { 5894 continue; 5895 } 5896 if (expandDivs) { 5897 var transform = '', 5898 padding = ''; 5899 5900 if (divProperties.scale !== 1) { 5901 transform = 'scaleX(' + divProperties.scale + ')'; 5902 } 5903 if (divProperties.angle !== 0) { 5904 transform = 'rotate(' + divProperties.angle + 'deg) ' + transform; 5905 } 5906 if (divProperties.paddingLeft !== 0) { 5907 padding += ' padding-left: ' + divProperties.paddingLeft / divProperties.scale + 'px;'; 5908 transform += ' translateX(' + -divProperties.paddingLeft / divProperties.scale + 'px)'; 5909 } 5910 if (divProperties.paddingTop !== 0) { 5911 padding += ' padding-top: ' + divProperties.paddingTop + 'px;'; 5912 transform += ' translateY(' + -divProperties.paddingTop + 'px)'; 5913 } 5914 if (divProperties.paddingRight !== 0) { 5915 padding += ' padding-right: ' + divProperties.paddingRight / divProperties.scale + 'px;'; 5916 } 5917 if (divProperties.paddingBottom !== 0) { 5918 padding += ' padding-bottom: ' + divProperties.paddingBottom + 'px;'; 5919 } 5920 5921 if (padding !== '') { 5922 div.setAttribute('style', divProperties.style + padding); 5923 } 5924 if (transform !== '') { 5925 CustomStyle.setProp('transform', div, transform); 5926 } 5927 } else { 5928 div.style.padding = 0; 5929 CustomStyle.setProp('transform', div, divProperties.originalTransform || ''); 5930 } 5931 } 5932 }, 5933 }; 5934 5935 /** 5936 * Starts rendering of the text layer. 5937 * 5938 * @param {TextLayerRenderParameters} renderParameters 5939 * @returns {TextLayerRenderTask} 5940 */ 5941 function renderTextLayer(renderParameters) { 5942 var task = new TextLayerRenderTask( 5943 renderParameters.textContent, 5944 renderParameters.container, 5945 renderParameters.viewport, 5946 renderParameters.textDivs, 5947 renderParameters.enhanceTextSelection 5948 ); 5949 task._render(renderParameters.timeout); 5950 return task; 5951 } 5952 5953 return renderTextLayer; 5954 })(); 5955 5956 exports.renderTextLayer = renderTextLayer; 5957 }); 5958 5959 (function (root, factory) { 5960 { 5961 factory((root.pdfjsDisplayWebGL = {}), root.pdfjsSharedUtil, root.pdfjsDisplayDOMUtils); 5962 } 5963 })(this, function (exports, sharedUtil, displayDOMUtils) { 5964 var shadow = sharedUtil.shadow; 5965 var getDefaultSetting = displayDOMUtils.getDefaultSetting; 5966 5967 var WebGLUtils = (function WebGLUtilsClosure() { 5968 function loadShader(gl, code, shaderType) { 5969 var shader = gl.createShader(shaderType);
vendor: 24,909 bytes, lines 5970-6591
5970 gl.shaderSource(shader, code); 5971 gl.compileShader(shader); 5972 var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 5973 if (!compiled) { 5974 var errorMsg = gl.getShaderInfoLog(shader); 5975 throw new Error('Error during shader compilation: ' + errorMsg); 5976 } 5977 return shader; 5978 } 5979 5980 function createVertexShader(gl, code) { 5981 return loadShader(gl, code, gl.VERTEX_SHADER); 5982 } 5983 5984 function createFragmentShader(gl, code) { 5985 return loadShader(gl, code, gl.FRAGMENT_SHADER); 5986 } 5987 5988 function createProgram(gl, shaders) { 5989 var program = gl.createProgram(); 5990 for (var i = 0, ii = shaders.length; i < ii; ++i) { 5991 gl.attachShader(program, shaders[i]); 5992 } 5993 gl.linkProgram(program); 5994 var linked = gl.getProgramParameter(program, gl.LINK_STATUS); 5995 if (!linked) { 5996 var errorMsg = gl.getProgramInfoLog(program); 5997 throw new Error('Error during program linking: ' + errorMsg); 5998 } 5999 return program; 6000 } 6001 6002 function createTexture(gl, image, textureId) { 6003 gl.activeTexture(textureId); 6004 var texture = gl.createTexture(); 6005 gl.bindTexture(gl.TEXTURE_2D, texture); 6006 6007 // Set the parameters so we can render any size image. 6008 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 6009 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 6010 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 6011 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 6012 6013 // Upload the image into the texture. 6014 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); 6015 return texture; 6016 } 6017 6018 var currentGL, currentCanvas; 6019 6020 function generateGL() { 6021 if (currentGL) { 6022 return; 6023 } 6024 currentCanvas = document.createElement('canvas'); 6025 currentGL = currentCanvas.getContext('webgl', { 6026 premultipliedalpha: false, 6027 }); 6028 } 6029 6030 var smaskVertexShaderCode = 6031 '\ 6032 attribute vec2 a_position; \ 6033 attribute vec2 a_texCoord; \ 6034 \ 6035 uniform vec2 u_resolution; \ 6036 \ 6037 varying vec2 v_texCoord; \ 6038 \ 6039 void main() { \ 6040 vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \ 6041 gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \ 6042 \ 6043 v_texCoord = a_texCoord; \ 6044 } '; 6045 6046 var smaskFragmentShaderCode = 6047 '\ 6048 precision mediump float; \ 6049 \ 6050 uniform vec4 u_backdrop; \ 6051 uniform int u_subtype; \ 6052 uniform sampler2D u_image; \ 6053 uniform sampler2D u_mask; \ 6054 \ 6055 varying vec2 v_texCoord; \ 6056 \ 6057 void main() { \ 6058 vec4 imageColor = texture2D(u_image, v_texCoord); \ 6059 vec4 maskColor = texture2D(u_mask, v_texCoord); \ 6060 if (u_backdrop.a > 0.0) { \ 6061 maskColor.rgb = maskColor.rgb * maskColor.a + \ 6062 u_backdrop.rgb * (1.0 - maskColor.a); \ 6063 } \ 6064 float lum; \ 6065 if (u_subtype == 0) { \ 6066 lum = maskColor.a; \ 6067 } else { \ 6068 lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \ 6069 maskColor.b * 0.11; \ 6070 } \ 6071 imageColor.a *= lum; \ 6072 imageColor.rgb *= imageColor.a; \ 6073 gl_FragColor = imageColor; \ 6074 } '; 6075 6076 var smaskCache = null; 6077 6078 function initSmaskGL() { 6079 var canvas, gl; 6080 6081 generateGL(); 6082 canvas = currentCanvas; 6083 currentCanvas = null; 6084 gl = currentGL; 6085 currentGL = null; 6086 6087 // setup a GLSL program 6088 var vertexShader = createVertexShader(gl, smaskVertexShaderCode); 6089 var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode); 6090 var program = createProgram(gl, [vertexShader, fragmentShader]); 6091 gl.useProgram(program); 6092 6093 var cache = {}; 6094 cache.gl = gl; 6095 cache.canvas = canvas; 6096 cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution'); 6097 cache.positionLocation = gl.getAttribLocation(program, 'a_position'); 6098 cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop'); 6099 cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype'); 6100 6101 var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord'); 6102 var texLayerLocation = gl.getUniformLocation(program, 'u_image'); 6103 var texMaskLocation = gl.getUniformLocation(program, 'u_mask'); 6104 6105 // provide texture coordinates for the rectangle. 6106 var texCoordBuffer = gl.createBuffer(); 6107 gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); 6108 gl.bufferData( 6109 gl.ARRAY_BUFFER, 6110 new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]), 6111 gl.STATIC_DRAW 6112 ); 6113 gl.enableVertexAttribArray(texCoordLocation); 6114 gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0); 6115 6116 gl.uniform1i(texLayerLocation, 0); 6117 gl.uniform1i(texMaskLocation, 1); 6118 6119 smaskCache = cache; 6120 } 6121 6122 function composeSMask(layer, mask, properties) { 6123 var width = layer.width, 6124 height = layer.height; 6125 6126 if (!smaskCache) { 6127 initSmaskGL(); 6128 } 6129 var cache = smaskCache, 6130 canvas = cache.canvas, 6131 gl = cache.gl; 6132 canvas.width = width; 6133 canvas.height = height; 6134 gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); 6135 gl.uniform2f(cache.resolutionLocation, width, height); 6136 6137 if (properties.backdrop) { 6138 gl.uniform4f( 6139 cache.resolutionLocation, 6140 properties.backdrop[0], 6141 properties.backdrop[1], 6142 properties.backdrop[2], 6143 1 6144 ); 6145 } else { 6146 gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0); 6147 } 6148 gl.uniform1i(cache.subtypeLocation, properties.subtype === 'Luminosity' ? 1 : 0); 6149 6150 // Create a textures 6151 var texture = createTexture(gl, layer, gl.TEXTURE0); 6152 var maskTexture = createTexture(gl, mask, gl.TEXTURE1); 6153 6154 // Create a buffer and put a single clipspace rectangle in 6155 // it (2 triangles) 6156 var buffer = gl.createBuffer(); 6157 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 6158 gl.bufferData( 6159 gl.ARRAY_BUFFER, 6160 new Float32Array([0, 0, width, 0, 0, height, 0, height, width, 0, width, height]), 6161 gl.STATIC_DRAW 6162 ); 6163 gl.enableVertexAttribArray(cache.positionLocation); 6164 gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0); 6165 6166 // draw 6167 gl.clearColor(0, 0, 0, 0); 6168 gl.enable(gl.BLEND); 6169 gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 6170 gl.clear(gl.COLOR_BUFFER_BIT); 6171 6172 gl.drawArrays(gl.TRIANGLES, 0, 6); 6173 6174 gl.flush(); 6175 6176 gl.deleteTexture(texture); 6177 gl.deleteTexture(maskTexture); 6178 gl.deleteBuffer(buffer); 6179 6180 return canvas; 6181 } 6182 6183 var figuresVertexShaderCode = 6184 '\ 6185 attribute vec2 a_position; \ 6186 attribute vec3 a_color; \ 6187 \ 6188 uniform vec2 u_resolution; \ 6189 uniform vec2 u_scale; \ 6190 uniform vec2 u_offset; \ 6191 \ 6192 varying vec4 v_color; \ 6193 \ 6194 void main() { \ 6195 vec2 position = (a_position + u_offset) * u_scale; \ 6196 vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \ 6197 gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \ 6198 \ 6199 v_color = vec4(a_color / 255.0, 1.0); \ 6200 } '; 6201 6202 var figuresFragmentShaderCode = 6203 '\ 6204 precision mediump float; \ 6205 \ 6206 varying vec4 v_color; \ 6207 \ 6208 void main() { \ 6209 gl_FragColor = v_color; \ 6210 } '; 6211 6212 var figuresCache = null; 6213 6214 function initFiguresGL() { 6215 var canvas, gl; 6216 6217 generateGL(); 6218 canvas = currentCanvas; 6219 currentCanvas = null; 6220 gl = currentGL; 6221 currentGL = null; 6222 6223 // setup a GLSL program 6224 var vertexShader = createVertexShader(gl, figuresVertexShaderCode); 6225 var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode); 6226 var program = createProgram(gl, [vertexShader, fragmentShader]); 6227 gl.useProgram(program); 6228 6229 var cache = {}; 6230 cache.gl = gl; 6231 cache.canvas = canvas; 6232 cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution'); 6233 cache.scaleLocation = gl.getUniformLocation(program, 'u_scale'); 6234 cache.offsetLocation = gl.getUniformLocation(program, 'u_offset'); 6235 cache.positionLocation = gl.getAttribLocation(program, 'a_position'); 6236 cache.colorLocation = gl.getAttribLocation(program, 'a_color'); 6237 6238 figuresCache = cache; 6239 } 6240 6241 function drawFigures(width, height, backgroundColor, figures, context) { 6242 if (!figuresCache) { 6243 initFiguresGL(); 6244 } 6245 var cache = figuresCache, 6246 canvas = cache.canvas, 6247 gl = cache.gl; 6248 6249 canvas.width = width; 6250 canvas.height = height; 6251 gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); 6252 gl.uniform2f(cache.resolutionLocation, width, height); 6253 6254 // count triangle points 6255 var count = 0; 6256 var i, ii, rows; 6257 for (i = 0, ii = figures.length; i < ii; i++) { 6258 switch (figures[i].type) { 6259 case 'lattice': 6260 rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0; 6261 count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6; 6262 break; 6263 case 'triangles': 6264 count += figures[i].coords.length; 6265 break; 6266 } 6267 } 6268 // transfer data 6269 var coords = new Float32Array(count * 2); 6270 var colors = new Uint8Array(count * 3); 6271 var coordsMap = context.coords, 6272 colorsMap = context.colors; 6273 var pIndex = 0, 6274 cIndex = 0; 6275 for (i = 0, ii = figures.length; i < ii; i++) { 6276 var figure = figures[i], 6277 ps = figure.coords, 6278 cs = figure.colors; 6279 switch (figure.type) { 6280 case 'lattice': 6281 var cols = figure.verticesPerRow; 6282 rows = (ps.length / cols) | 0; 6283 for (var row = 1; row < rows; row++) { 6284 var offset = row * cols + 1; 6285 for (var col = 1; col < cols; col++, offset++) { 6286 coords[pIndex] = coordsMap[ps[offset - cols - 1]]; 6287 coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1]; 6288 coords[pIndex + 2] = coordsMap[ps[offset - cols]]; 6289 coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1]; 6290 coords[pIndex + 4] = coordsMap[ps[offset - 1]]; 6291 coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1]; 6292 colors[cIndex] = colorsMap[cs[offset - cols - 1]]; 6293 colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1]; 6294 colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2]; 6295 colors[cIndex + 3] = colorsMap[cs[offset - cols]]; 6296 colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1]; 6297 colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2]; 6298 colors[cIndex + 6] = colorsMap[cs[offset - 1]]; 6299 colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1]; 6300 colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2]; 6301 6302 coords[pIndex + 6] = coords[pIndex + 2]; 6303 coords[pIndex + 7] = coords[pIndex + 3]; 6304 coords[pIndex + 8] = coords[pIndex + 4]; 6305 coords[pIndex + 9] = coords[pIndex + 5]; 6306 coords[pIndex + 10] = coordsMap[ps[offset]]; 6307 coords[pIndex + 11] = coordsMap[ps[offset] + 1]; 6308 colors[cIndex + 9] = colors[cIndex + 3]; 6309 colors[cIndex + 10] = colors[cIndex + 4]; 6310 colors[cIndex + 11] = colors[cIndex + 5]; 6311 colors[cIndex + 12] = colors[cIndex + 6]; 6312 colors[cIndex + 13] = colors[cIndex + 7]; 6313 colors[cIndex + 14] = colors[cIndex + 8]; 6314 colors[cIndex + 15] = colorsMap[cs[offset]]; 6315 colors[cIndex + 16] = colorsMap[cs[offset] + 1]; 6316 colors[cIndex + 17] = colorsMap[cs[offset] + 2]; 6317 pIndex += 12; 6318 cIndex += 18; 6319 } 6320 } 6321 break; 6322 case 'triangles': 6323 for (var j = 0, jj = ps.length; j < jj; j++) { 6324 coords[pIndex] = coordsMap[ps[j]]; 6325 coords[pIndex + 1] = coordsMap[ps[j] + 1]; 6326 colors[cIndex] = colorsMap[cs[j]]; 6327 colors[cIndex + 1] = colorsMap[cs[j] + 1]; 6328 colors[cIndex + 2] = colorsMap[cs[j] + 2]; 6329 pIndex += 2; 6330 cIndex += 3; 6331 } 6332 break; 6333 } 6334 } 6335 6336 // draw 6337 if (backgroundColor) { 6338 gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255, backgroundColor[2] / 255, 1.0); 6339 } else { 6340 gl.clearColor(0, 0, 0, 0); 6341 } 6342 gl.clear(gl.COLOR_BUFFER_BIT); 6343 6344 var coordsBuffer = gl.createBuffer(); 6345 gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer); 6346 gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW); 6347 gl.enableVertexAttribArray(cache.positionLocation); 6348 gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0); 6349 6350 var colorsBuffer = gl.createBuffer(); 6351 gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer); 6352 gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); 6353 gl.enableVertexAttribArray(cache.colorLocation); 6354 gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false, 0, 0); 6355 6356 gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY); 6357 gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY); 6358 6359 gl.drawArrays(gl.TRIANGLES, 0, count); 6360 6361 gl.flush(); 6362 6363 gl.deleteBuffer(coordsBuffer); 6364 gl.deleteBuffer(colorsBuffer); 6365 6366 return canvas; 6367 } 6368 6369 function cleanup() { 6370 if (smaskCache && smaskCache.canvas) { 6371 smaskCache.canvas.width = 0; 6372 smaskCache.canvas.height = 0; 6373 } 6374 if (figuresCache && figuresCache.canvas) { 6375 figuresCache.canvas.width = 0; 6376 figuresCache.canvas.height = 0; 6377 } 6378 smaskCache = null; 6379 figuresCache = null; 6380 } 6381 6382 return { 6383 get isEnabled() { 6384 if (getDefaultSetting('disableWebGL')) { 6385 return false; 6386 } 6387 var enabled = false; 6388 try { 6389 generateGL(); 6390 enabled = !!currentGL; 6391 } catch (e) {} 6392 return shadow(this, 'isEnabled', enabled); 6393 }, 6394 composeSMask: composeSMask, 6395 drawFigures: drawFigures, 6396 clear: cleanup, 6397 }; 6398 })(); 6399 6400 exports.WebGLUtils = WebGLUtils; 6401 }); 6402 6403 (function (root, factory) { 6404 { 6405 factory((root.pdfjsDisplayPatternHelper = {}), root.pdfjsSharedUtil, root.pdfjsDisplayWebGL); 6406 } 6407 })(this, function (exports, sharedUtil, displayWebGL) { 6408 var Util = sharedUtil.Util; 6409 var info = sharedUtil.info; 6410 var isArray = sharedUtil.isArray; 6411 var error = sharedUtil.error; 6412 var WebGLUtils = displayWebGL.WebGLUtils; 6413 6414 var ShadingIRs = {}; 6415 6416 ShadingIRs.RadialAxial = { 6417 fromIR: function RadialAxial_fromIR(raw) { 6418 var type = raw[1]; 6419 var colorStops = raw[2]; 6420 var p0 = raw[3]; 6421 var p1 = raw[4]; 6422 var r0 = raw[5]; 6423 var r1 = raw[6]; 6424 return { 6425 type: 'Pattern', 6426 getPattern: function RadialAxial_getPattern(ctx) { 6427 var grad; 6428 if (type === 'axial') { 6429 grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]); 6430 } else if (type === 'radial') { 6431 grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1); 6432 } 6433 6434 for (var i = 0, ii = colorStops.length; i < ii; ++i) { 6435 var c = colorStops[i]; 6436 grad.addColorStop(c[0], c[1]); 6437 } 6438 return grad; 6439 }, 6440 }; 6441 }, 6442 }; 6443 6444 var createMeshCanvas = (function createMeshCanvasClosure() { 6445 function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) { 6446 // Very basic Gouraud-shaded triangle rasterization algorithm. 6447 var coords = context.coords, 6448 colors = context.colors; 6449 var bytes = data.data, 6450 rowSize = data.width * 4; 6451 var tmp; 6452 if (coords[p1 + 1] > coords[p2 + 1]) { 6453 tmp = p1; 6454 p1 = p2; 6455 p2 = tmp; 6456 tmp = c1; 6457 c1 = c2; 6458 c2 = tmp; 6459 } 6460 if (coords[p2 + 1] > coords[p3 + 1]) { 6461 tmp = p2; 6462 p2 = p3; 6463 p3 = tmp; 6464 tmp = c2; 6465 c2 = c3; 6466 c3 = tmp; 6467 } 6468 if (coords[p1 + 1] > coords[p2 + 1]) { 6469 tmp = p1; 6470 p1 = p2; 6471 p2 = tmp; 6472 tmp = c1; 6473 c1 = c2; 6474 c2 = tmp; 6475 } 6476 var x1 = (coords[p1] + context.offsetX) * context.scaleX; 6477 var y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY; 6478 var x2 = (coords[p2] + context.offsetX) * context.scaleX; 6479 var y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY; 6480 var x3 = (coords[p3] + context.offsetX) * context.scaleX; 6481 var y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY; 6482 if (y1 >= y3) { 6483 return; 6484 } 6485 var c1r = colors[c1], 6486 c1g = colors[c1 + 1], 6487 c1b = colors[c1 + 2]; 6488 var c2r = colors[c2], 6489 c2g = colors[c2 + 1], 6490 c2b = colors[c2 + 2]; 6491 var c3r = colors[c3], 6492 c3g = colors[c3 + 1], 6493 c3b = colors[c3 + 2]; 6494 6495 var minY = Math.round(y1), 6496 maxY = Math.round(y3); 6497 var xa, car, cag, cab; 6498 var xb, cbr, cbg, cbb; 6499 var k; 6500 for (var y = minY; y <= maxY; y++) { 6501 if (y < y2) { 6502 k = y < y1 ? 0 : y1 === y2 ? 1 : (y1 - y) / (y1 - y2); 6503 xa = x1 - (x1 - x2) * k; 6504 car = c1r - (c1r - c2r) * k; 6505 cag = c1g - (c1g - c2g) * k; 6506 cab = c1b - (c1b - c2b) * k; 6507 } else { 6508 k = y > y3 ? 1 : y2 === y3 ? 0 : (y2 - y) / (y2 - y3); 6509 xa = x2 - (x2 - x3) * k; 6510 car = c2r - (c2r - c3r) * k; 6511 cag = c2g - (c2g - c3g) * k; 6512 cab = c2b - (c2b - c3b) * k; 6513 } 6514 k = y < y1 ? 0 : y > y3 ? 1 : (y1 - y) / (y1 - y3); 6515 xb = x1 - (x1 - x3) * k; 6516 cbr = c1r - (c1r - c3r) * k; 6517 cbg = c1g - (c1g - c3g) * k; 6518 cbb = c1b - (c1b - c3b) * k; 6519 var x1_ = Math.round(Math.min(xa, xb)); 6520 var x2_ = Math.round(Math.max(xa, xb)); 6521 var j = rowSize * y + x1_ * 4; 6522 for (var x = x1_; x <= x2_; x++) { 6523 k = (xa - x) / (xa - xb); 6524 k = k < 0 ? 0 : k > 1 ? 1 : k; 6525 bytes[j++] = (car - (car - cbr) * k) | 0; 6526 bytes[j++] = (cag - (cag - cbg) * k) | 0; 6527 bytes[j++] = (cab - (cab - cbb) * k) | 0; 6528 bytes[j++] = 255; 6529 } 6530 } 6531 } 6532 6533 function drawFigure(data, figure, context) { 6534 var ps = figure.coords; 6535 var cs = figure.colors; 6536 var i, ii; 6537 switch (figure.type) { 6538 case 'lattice': 6539 var verticesPerRow = figure.verticesPerRow; 6540 var rows = Math.floor(ps.length / verticesPerRow) - 1; 6541 var cols = verticesPerRow - 1; 6542 for (i = 0; i < rows; i++) { 6543 var q = i * verticesPerRow; 6544 for (var j = 0; j < cols; j++, q++) { 6545 drawTriangle( 6546 data, 6547 context, 6548 ps[q], 6549 ps[q + 1], 6550 ps[q + verticesPerRow], 6551 cs[q], 6552 cs[q + 1], 6553 cs[q + verticesPerRow] 6554 ); 6555 drawTriangle( 6556 data, 6557 context, 6558 ps[q + verticesPerRow + 1], 6559 ps[q + 1], 6560 ps[q + verticesPerRow], 6561 cs[q + verticesPerRow + 1], 6562 cs[q + 1], 6563 cs[q + verticesPerRow] 6564 ); 6565 } 6566 } 6567 break; 6568 case 'triangles': 6569 for (i = 0, ii = ps.length; i < ii; i += 3) { 6570 drawTriangle(data, context, ps[i], ps[i + 1], ps[i + 2], cs[i], cs[i + 1], cs[i + 2]); 6571 } 6572 break; 6573 default: 6574 error('illigal figure'); 6575 break; 6576 } 6577 } 6578 6579 function createMeshCanvas(bounds, combinesScale, coords, colors, figures, backgroundColor, cachedCanvases) { 6580 // we will increase scale on some weird factor to let antialiasing take 6581 // care of "rough" edges 6582 var EXPECTED_SCALE = 1.1; 6583 // MAX_PATTERN_SIZE is used to avoid OOM situation. 6584 var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough 6585 // We need to keep transparent border around our pattern for fill(): 6586 // createPattern with 'no-repeat' will bleed edges across entire area. 6587 var BORDER_SIZE = 2; 6588 6589 var offsetX = Math.floor(bounds[0]); 6590 var offsetY = Math.floor(bounds[1]); 6591 var boundsWidth = Math.ceil(bounds[2]) - offsetX;
6592 var boundsHeight = Math.ceil(bounds[3]) - offsetY; 6593 6594 var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] * EXPECTED_SCALE)), MAX_PATTERN_SIZE); 6595 var height = Math.min( 6596 Math.ceil(Math.abs(boundsHeight * combinesScale[1] * EXPECTED_SCALE)), 6597 MAX_PATTERN_SIZE 6598 ); 6599 var scaleX = boundsWidth / width; 6600 var scaleY = boundsHeight / height; 6601 6602 var context = { 6603 coords: coords, 6604 colors: colors, 6605 offsetX: -offsetX, 6606 offsetY: -offsetY, 6607 scaleX: 1 / scaleX, 6608 scaleY: 1 / scaleY, 6609 }; 6610 6611 var paddedWidth = width + BORDER_SIZE * 2; 6612 var paddedHeight = height + BORDER_SIZE * 2; 6613 6614 var canvas, tmpCanvas, i, ii; 6615 if (WebGLUtils.isEnabled) { 6616 canvas = WebGLUtils.drawFigures(width, height, backgroundColor, figures, context); 6617 6618 // https://bugzilla.mozilla.org/show_bug.cgi?id=972126 6619 tmpCanvas = cachedCanvases.getCanvas('mesh', paddedWidth, paddedHeight, false); 6620 tmpCanvas.context.drawImage(canvas, BORDER_SIZE, BORDER_SIZE); 6621 canvas = tmpCanvas.canvas; 6622 } else { 6623 tmpCanvas = cachedCanvases.getCanvas('mesh', paddedWidth, paddedHeight, false); 6624 var tmpCtx = tmpCanvas.context; 6625 6626 var data = tmpCtx.createImageData(width, height); 6627 if (backgroundColor) { 6628 var bytes = data.data; 6629 for (i = 0, ii = bytes.length; i < ii; i += 4) { 6630 bytes[i] = backgroundColor[0]; 6631 bytes[i + 1] = backgroundColor[1]; 6632 bytes[i + 2] = backgroundColor[2]; 6633 bytes[i + 3] = 255; 6634 } 6635 } 6636 for (i = 0; i < figures.length; i++) { 6637 drawFigure(data, figures[i], context); 6638 } 6639 tmpCtx.putImageData(data, BORDER_SIZE, BORDER_SIZE); 6640 canvas = tmpCanvas.canvas; 6641 } 6642 6643 return { 6644 canvas: canvas, 6645 offsetX: offsetX - BORDER_SIZE * scaleX, 6646 offsetY: offsetY - BORDER_SIZE * scaleY, 6647 scaleX: scaleX, 6648 scaleY: scaleY, 6649 }; 6650 } 6651 6652 return createMeshCanvas; 6653 })(); 6654 6655 ShadingIRs.Mesh = { 6656 fromIR: function Mesh_fromIR(raw) { 6657 //var type = raw[1]; 6658 var coords = raw[2]; 6659 var colors = raw[3]; 6660 var figures = raw[4]; 6661 var bounds = raw[5]; 6662 var matrix = raw[6]; 6663 //var bbox = raw[7]; 6664 var background = raw[8]; 6665 return { 6666 type: 'Pattern', 6667 getPattern: function Mesh_getPattern(ctx, owner, shadingFill) { 6668 var scale; 6669 if (shadingFill) { 6670 scale = Util.singularValueDecompose2dScale(ctx.mozCurrentTransform); 6671 } else { 6672 // Obtain scale from matrix and current transformation matrix. 6673 scale = Util.singularValueDecompose2dScale(owner.baseTransform); 6674 if (matrix) { 6675 var matrixScale = Util.singularValueDecompose2dScale(matrix); 6676 scale = [scale[0] * matrixScale[0], scale[1] * matrixScale[1]]; 6677 } 6678 } 6679 6680 // Rasterizing on the main thread since sending/queue large canvases 6681 // might cause OOM. 6682 var temporaryPatternCanvas = createMeshCanvas( 6683 bounds, 6684 scale, 6685 coords, 6686 colors, 6687 figures, 6688 shadingFill ? null : background, 6689 owner.cachedCanvases 6690 ); 6691 6692 if (!shadingFill) { 6693 ctx.setTransform.apply(ctx, owner.baseTransform); 6694 if (matrix) { 6695 ctx.transform.apply(ctx, matrix); 6696 } 6697 } 6698 6699 ctx.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY); 6700 ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY); 6701 6702 return ctx.createPattern(temporaryPatternCanvas.canvas, 'no-repeat'); 6703 }, 6704 }; 6705 }, 6706 }; 6707 6708 ShadingIRs.Dummy = { 6709 fromIR: function Dummy_fromIR() { 6710 return { 6711 type: 'Pattern', 6712 getPattern: function Dummy_fromIR_getPattern() { 6713 return 'hotpink'; 6714 }, 6715 }; 6716 }, 6717 }; 6718 6719 function getShadingPatternFromIR(raw) { 6720 var shadingIR = ShadingIRs[raw[0]]; 6721 if (!shadingIR) { 6722 error('Unknown IR type: ' + raw[0]); 6723 } 6724 return shadingIR.fromIR(raw); 6725 } 6726 6727 var TilingPattern = (function TilingPatternClosure() { 6728 var PaintType = { 6729 COLORED: 1, 6730 UNCOLORED: 2, 6731 }; 6732 6733 var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough 6734 6735 function TilingPattern(IR, color, ctx, canvasGraphicsFactory, baseTransform) { 6736 this.operatorList = IR[2]; 6737 this.matrix = IR[3] || [1, 0, 0, 1, 0, 0]; 6738 this.bbox = IR[4]; 6739 this.xstep = IR[5]; 6740 this.ystep = IR[6]; 6741 this.paintType = IR[7]; 6742 this.tilingType = IR[8]; 6743 this.color = color; 6744 this.canvasGraphicsFactory = canvasGraphicsFactory; 6745 this.baseTransform = baseTransform; 6746 this.type = 'Pattern'; 6747 this.ctx = ctx; 6748 } 6749 6750 TilingPattern.prototype = { 6751 createPatternCanvas: function TilinPattern_createPatternCanvas(owner) { 6752 var operatorList = this.operatorList; 6753 var bbox = this.bbox; 6754 var xstep = this.xstep; 6755 var ystep = this.ystep; 6756 var paintType = this.paintType; 6757 var tilingType = this.tilingType; 6758 var color = this.color; 6759 var canvasGraphicsFactory = this.canvasGraphicsFactory; 6760 6761 info('TilingType: ' + tilingType); 6762 6763 var x0 = bbox[0], 6764 y0 = bbox[1], 6765 x1 = bbox[2], 6766 y1 = bbox[3]; 6767 6768 var topLeft = [x0, y0]; 6769 // we want the canvas to be as large as the step size 6770 var botRight = [x0 + xstep, y0 + ystep]; 6771 6772 var width = botRight[0] - topLeft[0]; 6773 var height = botRight[1] - topLeft[1]; 6774 6775 // Obtain scale from matrix and current transformation matrix. 6776 var matrixScale = Util.singularValueDecompose2dScale(this.matrix
vendor: 24,667 bytes, lines 6776-7447
6776); 6777 var curMatrixScale = Util.singularValueDecompose2dScale(this.baseTransform); 6778 var combinedScale = [matrixScale[0] * curMatrixScale[0], matrixScale[1] * curMatrixScale[1]]; 6779 6780 // MAX_PATTERN_SIZE is used to avoid OOM situation. 6781 // Use width and height values that are as close as possible to the end 6782 // result when the pattern is used. Too low value makes the pattern look 6783 // blurry. Too large value makes it look too crispy. 6784 width = Math.min(Math.ceil(Math.abs(width * combinedScale[0])), MAX_PATTERN_SIZE); 6785 6786 height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])), MAX_PATTERN_SIZE); 6787 6788 var tmpCanvas = owner.cachedCanvases.getCanvas('pattern', width, height, true); 6789 var tmpCtx = tmpCanvas.context; 6790 var graphics = canvasGraphicsFactory.createCanvasGraphics(tmpCtx); 6791 graphics.groupLevel = owner.groupLevel; 6792 6793 this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color); 6794 6795 this.setScale(width, height, xstep, ystep); 6796 this.transformToScale(graphics); 6797 6798 // transform coordinates to pattern space 6799 var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]]; 6800 graphics.transform.apply(graphics, tmpTranslate); 6801 6802 this.clipBbox(graphics, bbox, x0, y0, x1, y1); 6803 6804 graphics.executeOperatorList(operatorList); 6805 return tmpCanvas.canvas; 6806 }, 6807 6808 setScale: function TilingPattern_setScale(width, height, xstep, ystep) { 6809 this.scale = [width / xstep, height / ystep]; 6810 }, 6811 6812 transformToScale: function TilingPattern_transformToScale(graphics) { 6813 var scale = this.scale; 6814 var tmpScale = [scale[0], 0, 0, scale[1], 0, 0]; 6815 graphics.transform.apply(graphics, tmpScale); 6816 }, 6817 6818 scaleToContext: function TilingPattern_scaleToContext() { 6819 var scale = this.scale; 6820 this.ctx.scale(1 / scale[0], 1 / scale[1]); 6821 }, 6822 6823 clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) { 6824 if (bbox && isArray(bbox) && bbox.length === 4) { 6825 var bboxWidth = x1 - x0; 6826 var bboxHeight = y1 - y0; 6827 graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight); 6828 graphics.clip(); 6829 graphics.endPath(); 6830 } 6831 }, 6832 6833 setFillAndStrokeStyleToContext: function setFillAndStrokeStyleToContext(context, paintType, color) { 6834 switch (paintType) { 6835 case PaintType.COLORED: 6836 var ctx = this.ctx; 6837 context.fillStyle = ctx.fillStyle; 6838 context.strokeStyle = ctx.strokeStyle; 6839 break; 6840 case PaintType.UNCOLORED: 6841 var cssColor = Util.makeCssRgb(color[0], color[1], color[2]); 6842 context.fillStyle = cssColor; 6843 context.strokeStyle = cssColor; 6844 break; 6845 default: 6846 error('Unsupported paint type: ' + paintType); 6847 } 6848 }, 6849 6850 getPattern: function TilingPattern_getPattern(ctx, owner) { 6851 var temporaryPatternCanvas = this.createPatternCanvas(owner); 6852 6853 ctx = this.ctx; 6854 ctx.setTransform.apply(ctx, this.baseTransform); 6855 ctx.transform.apply(ctx, this.matrix); 6856 this.scaleToContext(); 6857 6858 return ctx.createPattern(temporaryPatternCanvas, 'repeat'); 6859 }, 6860 }; 6861 6862 return TilingPattern; 6863 })(); 6864 6865 exports.getShadingPatternFromIR = getShadingPatternFromIR; 6866 exports.TilingPattern = TilingPattern; 6867 }); 6868 6869 (function (root, factory) { 6870 { 6871 factory( 6872 (root.pdfjsDisplayCanvas = {}), 6873 root.pdfjsSharedUtil, 6874 root.pdfjsDisplayDOMUtils, 6875 root.pdfjsDisplayPatternHelper, 6876 root.pdfjsDisplayWebGL 6877 ); 6878 } 6879 })(this, function (exports, sharedUtil, displayDOMUtils, displayPatternHelper, displayWebGL) { 6880 var FONT_IDENTITY_MATRIX = sharedUtil.FONT_IDENTITY_MATRIX; 6881 var IDENTITY_MATRIX = sharedUtil.IDENTITY_MATRIX; 6882 var ImageKind = sharedUtil.ImageKind; 6883 var OPS = sharedUtil.OPS; 6884 var TextRenderingMode = sharedUtil.TextRenderingMode; 6885 var Uint32ArrayView = sharedUtil.Uint32ArrayView; 6886 var Util = sharedUtil.Util; 6887 var assert = sharedUtil.assert; 6888 var info = sharedUtil.info; 6889 var isNum = sharedUtil.isNum; 6890 var isArray = sharedUtil.isArray; 6891 var isLittleEndian = sharedUtil.isLittleEndian; 6892 var error = sharedUtil.error; 6893 var shadow = sharedUtil.shadow; 6894 var warn = sharedUtil.warn; 6895 var TilingPattern = displayPatternHelper.TilingPattern; 6896 var getShadingPatternFromIR = displayPatternHelper.getShadingPatternFromIR; 6897 var WebGLUtils = displayWebGL.WebGLUtils; 6898 var hasCanvasTypedArrays = displayDOMUtils.hasCanvasTypedArrays; 6899 6900 // <canvas> contexts store most of the state we need natively. 6901 // However, PDF needs a bit more state, which we store here. 6902 6903 // Minimal font size that would be used during canvas fillText operations. 6904 var MIN_FONT_SIZE = 16; 6905 // Maximum font size that would be used during canvas fillText operations. 6906 var MAX_FONT_SIZE = 100; 6907 var MAX_GROUP_SIZE = 4096; 6908 6909 // Heuristic value used when enforcing minimum line widths. 6910 var MIN_WIDTH_FACTOR = 0.65; 6911 6912 var COMPILE_TYPE3_GLYPHS = true; 6913 var MAX_SIZE_TO_COMPILE = 1000; 6914 6915 var FULL_CHUNK_HEIGHT = 16; 6916 6917 var HasCanvasTypedArraysCached = { 6918 get value() { 6919 return shadow(HasCanvasTypedArraysCached, 'value', hasCanvasTypedArrays()); 6920 }, 6921 }; 6922 6923 var IsLittleEndianCached = { 6924 get value() { 6925 return shadow(IsLittleEndianCached, 'value', isLittleEndian()); 6926 }, 6927 }; 6928 6929 function createScratchCanvas(width, height) { 6930 var canvas = document.createElement('canvas'); 6931 canvas.width = width; 6932 canvas.height = height; 6933 return canvas; 6934 } 6935 6936 function addContextCurrentTransform(ctx) { 6937 // If the context doesn't expose a `mozCurrentTransform`, add a JS based one. 6938 if (!ctx.mozCurrentTransform) { 6939 ctx._originalSave = ctx.save; 6940 ctx._originalRestore = ctx.restore; 6941 ctx._originalRotate = ctx.rotate; 6942 ctx._originalScale = ctx.scale; 6943 ctx._originalTranslate = ctx.translate; 6944 ctx._originalTransform = ctx.transform; 6945 ctx._originalSetTransform = ctx.setTransform; 6946 6947 ctx._transformMatrix = ctx._transformMatrix || [1, 0, 0, 1, 0, 0]; 6948 ctx._transformStack = []; 6949 6950 Object.defineProperty(ctx, 'mozCurrentTransform', { 6951 get: function getCurrentTransform() { 6952 return this._transformMatrix; 6953 }, 6954 }); 6955 6956 Object.defineProperty(ctx, 'mozCurrentTransformInverse', { 6957 get: function getCurrentTransformInverse() { 6958 // Calculation done using WolframAlpha: 6959 // http://www.wolframalpha.com/input/? 6960 // i=Inverse+{{a%2C+c%2C+e}%2C+{b%2C+d%2C+f}%2C+{0%2C+0%2C+1}} 6961 6962 var m = this._transformMatrix; 6963 var a = m[0], 6964 b = m[1], 6965 c = m[2], 6966 d = m[3], 6967 e = m[4], 6968 f = m[5]; 6969 6970 var ad_bc = a * d - b * c; 6971 var bc_ad = b * c - a * d; 6972 6973 return [d / ad_bc, b / bc_ad, c / bc_ad, a / ad_bc, (d * e - c * f) / bc_ad, (b * e - a * f) / ad_bc]; 6974 }, 6975 }); 6976 6977 ctx.save = function ctxSave() { 6978 var old = this._transformMatrix; 6979 this._transformStack.push(old); 6980 this._transformMatrix = old.slice(0, 6); 6981 6982 this._originalSave(); 6983 }; 6984 6985 ctx.restore = function ctxRestore() { 6986 var prev = this._transformStack.pop(); 6987 if (prev) { 6988 this._transformMatrix = prev; 6989 this._originalRestore(); 6990 } 6991 }; 6992 6993 ctx.translate = function ctxTranslate(x, y) { 6994 var m = this._transformMatrix; 6995 m[4] = m[0] * x + m[2] * y + m[4]; 6996 m[5] = m[1] * x + m[3] * y + m[5]; 6997 6998 this._originalTranslate(x, y); 6999 }; 7000 7001 ctx.scale = function ctxScale(x, y) { 7002 var m = this._transformMatrix; 7003 m[0] = m[0] * x; 7004 m[1] = m[1] * x; 7005 m[2] = m[2] * y; 7006 m[3] = m[3] * y; 7007 7008 this._originalScale(x, y); 7009 }; 7010 7011 ctx.transform = function ctxTransform(a, b, c, d, e, f) { 7012 var m = this._transformMatrix; 7013 this._transformMatrix = [ 7014 m[0] * a + m[2] * b, 7015 m[1] * a + m[3] * b, 7016 m[0] * c + m[2] * d, 7017 m[1] * c + m[3] * d, 7018 m[0] * e + m[2] * f + m[4], 7019 m[1] * e + m[3] * f + m[5], 7020 ]; 7021 7022 ctx._originalTransform(a, b, c, d, e, f); 7023 }; 7024 7025 ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) { 7026 this._transformMatrix = [a, b, c, d, e, f]; 7027 7028 ctx._originalSetTransform(a, b, c, d, e, f); 7029 }; 7030 7031 ctx.rotate = function ctxRotate(angle) { 7032 var cosValue = Math.cos(angle); 7033 var sinValue = Math.sin(angle); 7034 7035 var m = this._transformMatrix; 7036 this._transformMatrix = [ 7037 m[0] * cosValue + m[2] * sinValue, 7038 m[1] * cosValue + m[3] * sinValue, 7039 m[0] * -sinValue + m[2] * cosValue, 7040 m[1] * -sinValue + m[3] * cosValue, 7041 m[4], 7042 m[5], 7043 ]; 7044 7045 this._originalRotate(angle); 7046 }; 7047 } 7048 } 7049 7050 var CachedCanvases = (function CachedCanvasesClosure() { 7051 function CachedCanvases() { 7052 this.cache = Object.create(null); 7053 } 7054 7055 CachedCanvases.prototype = { 7056 getCanvas: function CachedCanvases_getCanvas(id, width, height, trackTransform) { 7057 var canvasEntry; 7058 if (this.cache[id] !== undefined) { 7059 canvasEntry = this.cache[id]; 7060 canvasEntry.canvas.width = width; 7061 canvasEntry.canvas.height = height; 7062 // reset canvas transform for emulated mozCurrentTransform, if needed 7063 canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0); 7064 } else { 7065 var canvas = createScratchCanvas(width, height); 7066 var ctx = canvas.getContext('2d'); 7067 if (trackTransform) { 7068 addContextCurrentTransform(ctx); 7069 } 7070 this.cache[id] = canvasEntry = { canvas: canvas, context: ctx }; 7071 } 7072 return canvasEntry; 7073 }, 7074 clear: function () { 7075 for (var id in this.cache) { 7076 var canvasEntry = this.cache[id]; 7077 // Zeroing the width and height causes Firefox to release graphics 7078 // resources immediately, which can greatly reduce memory consumption. 7079 canvasEntry.canvas.width = 0; 7080 canvasEntry.canvas.height = 0; 7081 delete this.cache[id]; 7082 } 7083 }, 7084 }; 7085 return CachedCanvases; 7086 })(); 7087 7088 function compileType3Glyph(imgData) { 7089 var POINT_TO_PROCESS_LIMIT = 1000; 7090 7091 var width = imgData.width, 7092 height = imgData.height; 7093 var i, 7094 j, 7095 j0, 7096 width1 = width + 1; 7097 var points = new Uint8Array(width1 * (height + 1)); 7098 var POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]); 7099 7100 // decodes bit-packed mask data 7101 var lineSize = (width + 7) & ~7, 7102 data0 = imgData.data; 7103 var data = new Uint8Array(lineSize * height), 7104 pos = 0, 7105 ii; 7106 for (i = 0, ii = data0.length; i < ii; i++) { 7107 var mask = 128, 7108 elem = data0[i]; 7109 while (mask > 0) { 7110 data[pos++] = elem & mask ? 0 : 255; 7111 mask >>= 1; 7112 } 7113 } 7114 7115 // finding iteresting points: every point is located between mask pixels, 7116 // so there will be points of the (width + 1)x(height + 1) grid. Every point 7117 // will have flags assigned based on neighboring mask pixels: 7118 // 4 | 8 7119 // --P-- 7120 // 2 | 1 7121 // We are interested only in points with the flags: 7122 // - outside corners: 1, 2, 4, 8; 7123 // - inside corners: 7, 11, 13, 14; 7124 // - and, intersections: 5, 10. 7125 var count = 0; 7126 pos = 0; 7127 if (data[pos] !== 0) { 7128 points[0] = 1; 7129 ++count; 7130 } 7131 for (j = 1; j < width; j++) { 7132 if (data[pos] !== data[pos + 1]) { 7133 points[j] = data[pos] ? 2 : 1; 7134 ++count; 7135 } 7136 pos++; 7137 } 7138 if (data[pos] !== 0) { 7139 points[j] = 2; 7140 ++count; 7141 } 7142 for (i = 1; i < height; i++) { 7143 pos = i * lineSize; 7144 j0 = i * width1; 7145 if (data[pos - lineSize] !== data[pos]) { 7146 points[j0] = data[pos] ? 1 : 8; 7147 ++count; 7148 } 7149 // 'sum' is the position of the current pixel configuration in the 'TYPES' 7150 // array (in order 8-1-2-4, so we can use '>>2' to shift the column). 7151 var sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0); 7152 for (j = 1; j < width; j++) { 7153 sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) + (data[pos - lineSize + 1] ? 8 : 0); 7154 if (POINT_TYPES[sum]) { 7155 points[j0 + j] = POINT_TYPES[sum]; 7156 ++count; 7157 } 7158 pos++; 7159 } 7160 if (data[pos - lineSize] !== data[pos]) { 7161 points[j0 + j] = data[pos] ? 2 : 4; 7162 ++count; 7163 } 7164 7165 if (count > POINT_TO_PROCESS_LIMIT) { 7166 return null; 7167 } 7168 } 7169 7170 pos = lineSize * (height - 1); 7171 j0 = i * width1; 7172 if (data[pos] !== 0) { 7173 points[j0] = 8; 7174 ++count; 7175 } 7176 for (j = 1; j < width; j++) { 7177 if (data[pos] !== data[pos + 1]) { 7178 points[j0 + j] = data[pos] ? 4 : 8; 7179 ++count; 7180 } 7181 pos++; 7182 } 7183 if (data[pos] !== 0) { 7184 points[j0 + j] = 4; 7185 ++count; 7186 } 7187 if (count > POINT_TO_PROCESS_LIMIT) { 7188 return null; 7189 } 7190 7191 // building outlines 7192 var steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]); 7193 var outlines = []; 7194 for (i = 0; count && i <= height; i++) { 7195 var p = i * width1; 7196 var end = p + width; 7197 while (p < end && !points[p]) { 7198 p++; 7199 } 7200 if (p === end) { 7201 continue; 7202 } 7203 var coords = [p % width1, i]; 7204 7205 var type = points[p], 7206 p0 = p, 7207 pp; 7208 do { 7209 var step = steps[type]; 7210 do { 7211 p += step; 7212 } while (!points[p]); 7213 7214 pp = points[p]; 7215 if (pp !== 5 && pp !== 10) { 7216 // set new direction 7217 type = pp; 7218 // delete mark 7219 points[p] = 0; 7220 } else { 7221 // type is 5 or 10, ie, a crossing 7222 // set new direction 7223 type = pp & ((0x33 * type) >> 4); 7224 // set new type for "future hit" 7225 points[p] &= (type >> 2) | (type << 2); 7226 } 7227 7228 coords.push(p % width1); 7229 coords.push((p / width1) | 0); 7230 --count; 7231 } while (p0 !== p); 7232 outlines.push(coords); 7233 --i; 7234 } 7235 7236 var drawOutline = function (c) { 7237 c.save(); 7238 // the path shall be painted in [0..1]x[0..1] space 7239 c.scale(1 / width, -1 / height); 7240 c.translate(0, -height); 7241 c.beginPath(); 7242 for (var i = 0, ii = outlines.length; i < ii; i++) { 7243 var o = outlines[i]; 7244 c.moveTo(o[0], o[1]); 7245 for (var j = 2, jj = o.length; j < jj; j += 2) { 7246 c.lineTo(o[j], o[j + 1]); 7247 } 7248 } 7249 c.fill(); 7250 c.beginPath(); 7251 c.restore(); 7252 }; 7253 7254 return drawOutline; 7255 } 7256 7257 var CanvasExtraState = (function CanvasExtraStateClosure() { 7258 function CanvasExtraState(old) { 7259 // Are soft masks and alpha values shapes or opacities? 7260 this.alphaIsShape = false; 7261 this.fontSize = 0; 7262 this.fontSizeScale = 1; 7263 this.textMatrix = IDENTITY_MATRIX; 7264 this.textMatrixScale = 1; 7265 this.fontMatrix = FONT_IDENTITY_MATRIX; 7266 this.leading = 0; 7267 // Current point (in user coordinates) 7268 this.x = 0; 7269 this.y = 0; 7270 // Start of text line (in text coordinates) 7271 this.lineX = 0; 7272 this.lineY = 0; 7273 // Character and word spacing 7274 this.charSpacing = 0; 7275 this.wordSpacing = 0; 7276 this.textHScale = 1; 7277 this.textRenderingMode = TextRenderingMode.FILL; 7278 this.textRise = 0; 7279 // Default fore and background colors 7280 this.fillColor = '#000000'; 7281 this.strokeColor = '#000000'; 7282 this.patternFill = false; 7283 // Note: fill alpha applies to all non-stroking operations 7284 this.fillAlpha = 1; 7285 this.strokeAlpha = 1; 7286 this.lineWidth = 1; 7287 this.activeSMask = null; 7288 this.resumeSMaskCtx = null; // nonclonable field (see the save method below) 7289 7290 this.old = old; 7291 } 7292 7293 CanvasExtraState.prototype = { 7294 clone: function CanvasExtraState_clone() { 7295 return Object.create(this); 7296 }, 7297 setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) { 7298 this.x = x; 7299 this.y = y; 7300 }, 7301 }; 7302 return CanvasExtraState; 7303 })(); 7304 7305 var CanvasGraphics = (function CanvasGraphicsClosure() { 7306 // Defines the time the executeOperatorList is going to be executing 7307 // before it stops and shedules a continue of execution. 7308 var EXECUTION_TIME = 15; 7309 // Defines the number of steps before checking the execution time 7310 var EXECUTION_STEPS = 10; 7311 7312 function CanvasGraphics(canvasCtx, commonObjs, objs, imageLayer) { 7313 this.ctx = canvasCtx; 7314 this.current = new CanvasExtraState(); 7315 this.stateStack = []; 7316 this.pendingClip = null; 7317 this.pendingEOFill = false; 7318 this.res = null; 7319 this.xobjs = null; 7320 this.commonObjs = commonObjs; 7321 this.objs = objs; 7322 this.imageLayer = imageLayer; 7323 this.groupStack = []; 7324 this.processingType3 = null; 7325 // Patterns are painted relative to the initial page/form transform, see pdf 7326 // spec 8.7.2 NOTE 1. 7327 this.baseTransform = null; 7328 this.baseTransformStack = []; 7329 this.groupLevel = 0; 7330 this.smaskStack = []; 7331 this.smaskCounter = 0; 7332 this.tempSMask = null; 7333 this.cachedCanvases = new CachedCanvases(); 7334 if (canvasCtx) { 7335 // NOTE: if mozCurrentTransform is polyfilled, then the current state of 7336 // the transformation must already be set in canvasCtx._transformMatrix. 7337 addContextCurrentTransform(canvasCtx); 7338 } 7339 this.cachedGetSinglePixelWidth = null; 7340 } 7341 7342 function putBinaryImageData(ctx, imgData) { 7343 if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) { 7344 ctx.putImageData(imgData, 0, 0); 7345 return; 7346 } 7347 7348 // Put the image data to the canvas in chunks, rather than putting the 7349 // whole image at once. This saves JS memory, because the ImageData object 7350 // is smaller. It also possibly saves C++ memory within the implementation 7351 // of putImageData(). (E.g. in Firefox we make two short-lived copies of 7352 // the data passed to putImageData()). |n| shouldn't be too small, however, 7353 // because too many putImageData() calls will slow things down. 7354 // 7355 // Note: as written, if the last chunk is partial, the putImageData() call 7356 // will (conceptually) put pixels past the bounds of the canvas. But 7357 // that's ok; any such pixels are ignored. 7358 7359 var height = imgData.height, 7360 width = imgData.width; 7361 var partialChunkHeight = height % FULL_CHUNK_HEIGHT; 7362 var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; 7363 var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; 7364 7365 var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); 7366 var srcPos = 0, 7367 destPos; 7368 var src = imgData.data; 7369 var dest = chunkImgData.data; 7370 var i, j, thisChunkHeight, elemsInThisChunk; 7371 7372 // There are multiple forms in which the pixel data can be passed, and 7373 // imgData.kind tells us which one this is. 7374 if (imgData.kind === ImageKind.GRAYSCALE_1BPP) { 7375 // Grayscale, 1 bit per pixel (i.e. black-and-white). 7376 var srcLength = src.byteLength; 7377 var dest32 = HasCanvasTypedArraysCached.value ? new Uint32Array(dest.buffer) : new Uint32ArrayView(dest); 7378 var dest32DataLength = dest32.length; 7379 var fullSrcDiff = (width + 7) >> 3; 7380 var white = 0xffffffff; 7381 var black = IsLittleEndianCached.value || !HasCanvasTypedArraysCached.value ? 0xff000000 : 0x000000ff; 7382 for (i = 0; i < totalChunks; i++) { 7383 thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight; 7384 destPos = 0; 7385 for (j = 0; j < thisChunkHeight; j++) { 7386 var srcDiff = srcLength - srcPos; 7387 var k = 0; 7388 var kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7; 7389 var kEndUnrolled = kEnd & ~7; 7390 var mask = 0; 7391 var srcByte = 0; 7392 for (; k < kEndUnrolled; k += 8) { 7393 srcByte = src[srcPos++]; 7394 dest32[destPos++] = srcByte & 128 ? white : black; 7395 dest32[destPos++] = srcByte & 64 ? white : black; 7396 dest32[destPos++] = srcByte & 32 ? white : black; 7397 dest32[destPos++] = srcByte & 16 ? white : black; 7398 dest32[destPos++] = srcByte & 8 ? white : black; 7399 dest32[destPos++] = srcByte & 4 ? white : black; 7400 dest32[destPos++] = srcByte & 2 ? white : black; 7401 dest32[destPos++] = srcByte & 1 ? white : black; 7402 } 7403 for (; k < kEnd; k++) { 7404 if (mask === 0) { 7405 srcByte = src[srcPos++]; 7406 mask = 128; 7407 } 7408 7409 dest32[destPos++] = srcByte & mask ? white : black; 7410 mask >>= 1; 7411 } 7412 } 7413 // We ran out of input. Make all remaining pixels transparent. 7414 while (destPos < dest32DataLength) { 7415 dest32[destPos++] = 0; 7416 } 7417 7418 ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); 7419 } 7420 } else if (imgData.kind === ImageKind.RGBA_32BPP) { 7421 // RGBA, 32-bits per pixel. 7422 7423 j = 0; 7424 elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4; 7425 for (i = 0; i < fullChunks; i++) { 7426 dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); 7427 srcPos += elemsInThisChunk; 7428 7429 ctx.putImageData(chunkImgData, 0, j); 7430 j += FULL_CHUNK_HEIGHT; 7431 } 7432 if (i < totalChunks) { 7433 elemsInThisChunk = width * partialChunkHeight * 4; 7434 dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); 7435 ctx.putImageData(chunkImgData, 0, j); 7436 } 7437 } else if (imgData.kind === ImageKind.RGB_24BPP) { 7438 // RGB, 24-bits per pixel. 7439 thisChunkHeight = FULL_CHUNK_HEIGHT; 7440 elemsInThisChunk = width * thisChunkHeight; 7441 for (i = 0; i < totalChunks; i++) { 7442 if (i >= fullChunks) { 7443 thisChunkHeight = partialChunkHeight; 7444 elemsInThisChunk = width * thisChunkHeight; 7445 } 7446 7447 destPos = 0;
7448 for (j = elemsInThisChunk; j--; ) { 7449 dest[destPos++] = src[srcPos++]; 7450 dest[destPos++] = src[srcPos++]; 7451 dest[destPos++] = src[srcPos++]; 7452 dest[destPos++] = 255; 7453 } 7454 ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); 7455 } 7456 } else { 7457 error('bad image kind: ' + imgData.kind); 7458 } 7459 } 7460 7461 function putBinaryImageMask(ctx, imgData) { 7462 var height = imgData.height, 7463 width = imgData.width; 7464 var partialChunkHeight = height % FULL_CHUNK_HEIGHT; 7465 var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT; 7466 var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1; 7467 7468 var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT); 7469 var srcPos = 0; 7470 var src = imgData.data; 7471 var dest = chunkImgData.data; 7472 7473 for (var i = 0; i < totalChunks; i++) { 7474 var thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight; 7475 7476 // Expand the mask so it can be used by the canvas. Any required 7477 // inversion has already been handled. 7478 var destPos = 3; // alpha component offset 7479 for (var j = 0; j < thisChunkHeight; j++) { 7480 var mask = 0; 7481 for (var k = 0; k < width; k++) { 7482 if (!mask) { 7483 var elem = src[srcPos++]; 7484 mask = 128; 7485 } 7486 dest[destPos] = elem & mask ? 0 : 255; 7487 destPos += 4; 7488 mask >>= 1; 7489 } 7490 } 7491 ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT); 7492 } 7493 } 7494 7495 function copyCtxState(sourceCtx, destCtx) { 7496 var properties = [ 7497 'strokeStyle', 7498 'fillStyle', 7499 'fillRule', 7500 'globalAlpha', 7501 'lineWidth', 7502 'lineCap', 7503 'lineJoin', 7504 'miterLimit', 7505 'globalCompositeOperation', 7506 'font', 7507 ]; 7508 for (var i = 0, ii = properties.length; i < ii; i++) { 7509 var property = properties[i]; 7510 if (sourceCtx[property] !== undefined) { 7511 destCtx[property] = sourceCtx[property]; 7512 } 7513 } 7514 if (sourceCtx.setLineDash !== undefined) { 7515 destCtx.setLineDash(sourceCtx.getLineDash()); 7516 destCtx.lineDashOffset = sourceCtx.lineDashOffset; 7517 } 7518 } 7519 7520 function composeSMaskBackdrop(bytes, r0, g0, b0) { 7521 var length = bytes.length; 7522 for (var i = 3; i < length; i += 4) { 7523 var alpha = bytes[i]; 7524 if (alpha === 0) { 7525 bytes[i - 3] = r0; 7526 bytes[i - 2] = g0; 7527 bytes[i - 1] = b0; 7528 } else if (alpha < 255) { 7529 var alpha_ = 255 - alpha; 7530 bytes[i - 3] = (bytes[i - 3] * alpha + r0 * alpha_) >> 8; 7531 bytes[i - 2] = (bytes[i - 2] * alpha + g0 * alpha_) >> 8; 7532 bytes[i - 1] = (bytes[i - 1] * alpha + b0 * alpha_) >> 8; 7533 } 7534 } 7535 } 7536 7537 function composeSMaskAlpha(maskData, layerData, transferMap) { 7538 var length = maskData.length; 7539 var scale = 1 / 255; 7540 for (var i = 3; i < length; i += 4) { 7541 var alpha = transferMap ? transferMap[maskData[i]] : maskData[i]; 7542 layerData[i] = (layerData[i] * alpha * scale) | 0; 7543 } 7544 } 7545 7546 function composeSMaskLuminosity(maskData, layerData, transferMap) { 7547 var length = maskData.length; 7548 for (var i = 3; i < length; i += 4) { 7549 var y = 7550 maskData[i - 3] * 77 + // * 0.3 / 255 * 0x10000 7551 maskData[i - 2] * 152 + // * 0.59 .... 7552 maskData[i - 1] * 28; // * 0.11 .... 7553 layerData[i] = transferMap ? (layerData[i] * transferMap[y >> 8]) >> 8 : (layerData[i] * y) >> 16; 7554 } 7555 } 7556 7557 function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap) { 7558 var hasBackdrop = !!backdrop; 7559 var r0 = hasBackdrop ? backdrop[0] : 0; 7560 var g0 = hasBackdrop ? backdrop[1] : 0; 7561 var b0 = hasBackdrop ? backdrop[2] : 0; 7562 7563 var composeFn; 7564 if (subtype === 'Luminosity') { 7565 composeFn = composeSMaskLuminosity; 7566 } else { 7567 composeFn = composeSMaskAlpha; 7568 } 7569 7570 // processing image in chunks to save memory 7571 var PIXELS_TO_PROCESS = 1048576; 7572 var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width)); 7573 for (var row = 0; row < height; row += chunkSize) { 7574 var chunkHeight = Math.min(chunkSize, height - row); 7575 var maskData = maskCtx.getImageData(0, row, width, chunkHeight); 7576 var layerData = layerCtx.getImageData(0, row, width, chunkHeight); 7577 7578 if (hasBackdrop) { 7579 composeSMaskBackdrop(maskData.data, r0, g0, b0); 7580 } 7581 composeFn(maskData.data, layerData.data, transferMap); 7582 7583 maskCtx.putImageData(layerData, 0, row); 7584 } 7585 } 7586 7587 function composeSMask(ctx, smask, layerCtx) { 7588 var mask = smask.canvas; 7589 var maskCtx = smask.context; 7590 7591 ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY, smask.offsetX, smask.offsetY); 7592 7593 var backdrop = smask.backdrop || null; 7594 if (!smask.transferMap && WebGLUtils.isEnabled) { 7595 var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask, { 7596 subtype: smask.subtype, 7597 backdrop: backdrop, 7598 }); 7599 ctx.setTransform(1, 0, 0, 1, 0, 0); 7600 ctx.drawImage(composed, smask.offsetX, smask.offsetY); 7601 return; 7602 } 7603 genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height, smask.subtype, backdrop, smask.transferMap); 7604 ctx.drawImage(mask, 0, 0); 7605 } 7606 7607 var LINE_CAP_STYLES = ['butt', 'round', 'square']; 7608 var LINE_JOIN_STYLES = ['miter', 'round', 'bevel']; 7609 var NORMAL_CLIP = {}; 7610 var EO_CLIP = {}; 7611 7612 CanvasGraphics.prototype = { 7613 beginDrawing: function CanvasGraphics_beginDrawing(transform, viewport, transparency) { 7614 // For pdfs that use blend modes we have to clear the canvas else certain 7615 // blend modes can look wrong since we'd be blending with a white 7616 // backdrop. The problem with a transparent backdrop though is we then 7617 // don't get sub pixel anti aliasing on text, creating temporary 7618 // transparent canvas when we have blend modes. 7619 var width = this.ctx.canvas.width; 7620 var height = this.ctx.canvas.height; 7621 7622 this.ctx.save(); 7623 this.ctx.fillStyle = 'rgb(255, 255, 255)'; 7624 this.ctx.fillRect(0, 0, width, height);
7625 this.ctx.restore(); 7626 7627 if (transparency) { 7628 var transparentCanvas = this.cachedCanvases.getCanvas('transparent', width, height, true); 7629 this.compositeCtx = this.ctx; 7630 this.transparentCanvas = transparentCanvas.canvas; 7631 this.ctx = transparentCanvas.context; 7632 this.ctx.save(); 7633 // The transform can be applied before rendering, transferring it to 7634 // the new canvas. 7635 this.ctx.transform.apply(this.ctx, this.compositeCtx.mozCurrentTransform); 7636 } 7637 7638 this.ctx.save(); 7639 if (transform) { 7640 this.ctx.transform.apply(this.ctx, transform); 7641 } 7642 this.ctx.transform.apply(this.ctx, viewport.transform); 7643 7644 this.baseTransform = this.ctx.mozCurrentTransform.slice(); 7645 7646 if (this.imageLayer) { 7647 this.imageLayer.beginLayout(); 7648 } 7649 }, 7650 7651 executeOperatorList: function CanvasGraphics_executeOperatorList( 7652 operatorList, 7653 executionStartIdx, 7654 continueCallback, 7655 stepper 7656 ) { 7657 var argsArray = operatorList.argsArray; 7658 var fnArray = operatorList.fnArray; 7659 var i = executionStartIdx || 0; 7660 var argsArrayLen = argsArray.length; 7661 7662 // Sometimes the OperatorList to execute is empty. 7663 if (argsArrayLen === i) { 7664 return i; 7665 } 7666 7667 var chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === 'function'; 7668 var endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0; 7669 var steps = 0; 7670 7671 var commonObjs = this.commonObjs; 7672 var objs = this.objs; 7673 var fnId; 7674 7675 while (true) { 7676 if (stepper !== undefined && i === stepper.nextBreakPoint) { 7677 stepper.breakIt(i, continueCallback); 7678 return i; 7679 } 7680 7681 fnId = fnArray[i]; 7682 7683 if (fnId !== OPS.dependency) { 7684 this[fnId].apply(this, argsArray[i]); 7685 } else { 7686 var deps = argsArray[i]; 7687 for (var n = 0, nn = deps.length; n < nn; n++) { 7688 var depObjId = deps[n]; 7689 var common = depObjId[0] === 'g' && depObjId[1] === '_'; 7690 var objsPool = common ? commonObjs : objs; 7691 7692 // If the promise isn't resolved yet, add the continueCallback 7693 // to the promise and bail out. 7694 if (!objsPool.isResolved(depObjId)) { 7695 objsPool.get(depObjId, continueCallback); 7696 return i; 7697 } 7698 } 7699 } 7700 7701 i++; 7702 7703 // If the entire operatorList was executed, stop as were done. 7704 if (i === argsArrayLen) { 7705 return i; 7706 } 7707 7708 // If the execution took longer then a certain amount of time and 7709 // `continueCallback` is specified, interrupt the execution. 7710 if (chunkOperations && ++steps > EXECUTION_STEPS) { 7711 if (Date.now() > endTime) { 7712 continueCallback(); 7713 return i; 7714 } 7715 steps = 0; 7716 } 7717 7718 // If the operatorList isn't executed completely yet OR the execution 7719 // time was short enough, do another execution round. 7720 } 7721 }, 7722 7723 endDrawing: function CanvasGraphics_endDrawing() { 7724 // Finishing all opened operations such as SMask group painting. 7725 if (this.current.activeSMask !== null) { 7726 this.endSMaskGroup(); 7727 } 7728 7729 this.ctx.restore(); 7730 7731 if (this.transparentCanvas) { 7732 this.ctx = this.compositeCtx; 7733 this.ctx.save(); 7734 this.ctx.setTransform(1, 0, 0, 1, 0, 0); // Avoid apply transform twice 7735 this.ctx.drawImage(this.transparentCanvas, 0, 0);
7736 this.ctx.restore(); 7737 this.transparentCanvas = null; 7738 } 7739 7740 this.cachedCanvases.clear(); 7741 WebGLUtils.clear(); 7742 7743 if (this.imageLayer) { 7744 this.imageLayer.endLayout(); 7745 } 7746 }, 7747 7748 // Graphics state 7749 setLineWidth: function CanvasGraphics_setLineWidth(width) { 7750 this.current.lineWidth = width; 7751 this.ctx.lineWidth = width; 7752 }, 7753 setLineCap: function CanvasGraphics_setLineCap(style) { 7754 this.ctx.lineCap = LINE_CAP_STYLES[style]; 7755 }, 7756 setLineJoin: function CanvasGraphics_setLineJoin(style) { 7757 this.ctx.lineJoin = LINE_JOIN_STYLES[style]; 7758 }, 7759 setMiterLimit: function CanvasGraphics_setMiterLimit(limit) { 7760 this.ctx.miterLimit = limit; 7761 }, 7762 setDash: function CanvasGraphics_setDash(dashArray, dashPhase) { 7763 var ctx = this.ctx; 7764 if (ctx.setLineDash !== undefined) { 7765 ctx.setLineDash(dashArray); 7766 ctx.lineDashOffset = dashPhase; 7767 } 7768 }, 7769 setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) { 7770 // Maybe if we one day fully support color spaces this will be important 7771 // for now we can ignore. 7772 // TODO set rendering intent? 7773 }, 7774 setFlatness: function CanvasGraphics_setFlatness(flatness) { 7775 // There's no way to control this with canvas, but we can safely ignore. 7776 // TODO set flatness? 7777 }, 7778 setGState: function CanvasGraphics_setGState(states) { 7779 for (var i = 0, ii = states.length; i < ii; i++) { 7780 var state = states[i]; 7781 var key = state[0]; 7782 var value = state[1]; 7783 7784 switch (key) { 7785 case 'LW': 7786 this.setLineWidth(value); 7787 break; 7788 case 'LC': 7789 this.setLineCap(value); 7790 break; 7791 case 'LJ': 7792 this.setLineJoin(value); 7793 break; 7794 case 'ML': 7795 this.setMiterLimit(value); 7796 break; 7797 case 'D': 7798 this.setDash(value[0], value[1]); 7799 break; 7800 case 'RI': 7801 this.setRenderingIntent(value); 7802 break; 7803 case 'FL': 7804 this.setFlatness(value); 7805 break; 7806 case 'Font': 7807 this.setFont(value[0], value[1]); 7808 break; 7809 case 'CA': 7810 this.current.strokeAlpha = state[1]; 7811 break; 7812 case 'ca': 7813 this.current.fillAlpha = state[1]; 7814 this.ctx.globalAlpha = state[1]; 7815 break; 7816 case 'BM': 7817 if (value && value.name && value.name !== 'Normal') { 7818 var mode = value.name 7819 .replace(/([A-Z])/g, function (c) { 7820 return '-' + c.toLowerCase(); 7821 }) 7822 .substring(1); 7823 this.ctx.globalCompositeOperation = mode; 7824 if (this.ctx.globalCompositeOperation !== mode) { 7825 warn('globalCompositeOperation "' + mode + '" is not supported'); 7826 } 7827 } else { 7828 this.ctx.globalCompositeOperation = 'source-over'; 7829 } 7830 break; 7831 case 'SMask': 7832 if (this.current.activeSMask) { 7833 // If SMask is currrenly used, it needs to be suspended or 7834 // finished. Suspend only makes sense when at least one save() 7835 // was performed and state needs to be reverted on restore(). 7836 if ( 7837 this.stateStack.length > 0 && 7838 this.stateStack[this.stateStack.length - 1].activeSMask === this.current.activeSMask 7839 ) { 7840 this.suspendSMaskGroup(); 7841 } else { 7842 this.endSMaskGroup(); 7843 } 7844 } 7845 this.current.activeSMask = value ? this.tempSMask : null; 7846 if (this.current.activeSMask) { 7847 this.beginSMaskGroup(); 7848 } 7849 this.tempSMask = null; 7850 break; 7851 } 7852 } 7853 }, 7854 beginSMaskGroup: function CanvasGraphics_beginSMaskGroup() { 7855 var activeSMask = this.current.activeSMask; 7856 var drawnWidth = activeSMask.canvas.width; 7857 var drawnHeight = activeSMask.canvas.height; 7858 var cacheId = 'smaskGroupAt' + this.groupLevel; 7859 var scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true); 7860 7861 var currentCtx = this.ctx; 7862 var currentTransform = currentCtx.mozCurrentTransform; 7863 this.ctx.save(); 7864 7865 var groupCtx = scratchCanvas.context; 7866 groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY); 7867 groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY); 7868 groupCtx.transform.apply(groupCtx, currentTransform); 7869 7870 activeSMask.startTransformInverse = groupCtx.mozCurrentTransformInverse; 7871 7872 copyCtxState(currentCtx, groupCtx); 7873 this.ctx = groupCtx; 7874 this.setGState([
7875 ['BM', 'Normal'], 7876 ['ca', 1], 7877 ['CA', 1], 7878 ]); 7879 this.groupStack.push(currentCtx); 7880 this.groupLevel++; 7881 }, 7882 suspendSMaskGroup: function CanvasGraphics_endSMaskGroup() { 7883 // Similar to endSMaskGroup, the intermediate canvas has to be composed 7884 // and future ctx state restored. 7885 var groupCtx = this.ctx; 7886 this.groupLevel--; 7887 this.ctx = this.groupStack.pop(); 7888 7889 composeSMask(this.ctx, this.current.activeSMask, groupCtx); 7890 this.ctx.restore(); 7891 this.ctx.save(); // save is needed since SMask will be resumed. 7892 copyCtxState(groupCtx, this.ctx); 7893 7894 // Saving state for resuming. 7895 this.current.resumeSMaskCtx = groupCtx; 7896 // Transform was changed in the SMask canvas, reflecting this change on 7897 // this.ctx. 7898 var deltaTransform = Util.transform( 7899 this.current.activeSMask.startTransformInverse, 7900 groupCtx.mozCurrentTransform 7901 ); 7902 this.ctx.transform.apply(this.ctx, deltaTransform); 7903 7904 // SMask was composed, the results at the groupCtx can be cleared. 7905 groupCtx.save(); 7906 groupCtx.setTransform(1, 0, 0, 1, 0, 0); 7907 groupCtx.clearRect(0, 0, groupCtx.canvas.width, groupCtx.canvas.height); 7908 groupCtx.restore(); 7909 }, 7910 resumeSMaskGroup: function CanvasGraphics_endSMaskGroup() { 7911 // Resuming state saved by suspendSMaskGroup. We don't need to restore 7912 // any groupCtx state since restore() command (the only caller) will do 7913 // that for us. See also beginSMaskGroup. 7914 var groupCtx = this.current.resumeSMaskCtx; 7915 var currentCtx = this.ctx; 7916 this.ctx = groupCtx; 7917 this.groupStack.push(currentCtx); 7918 this.groupLevel++; 7919 }, 7920 endSMaskGroup: function CanvasGraphics_endSMaskGroup() { 7921 var groupCtx = this.ctx; 7922 this.groupLevel--; 7923 this.ctx = this.groupStack.pop(); 7924 7925 composeSMask(this.ctx, this.current.activeSMask, groupCtx); 7926 this.ctx.restore(); 7927 copyCtxState(groupCtx, this.ctx); 7928 // Transform was changed in the SMask canvas, reflecting this change on 7929 // this.ctx. 7930 var deltaTransform = Util.transform( 7931 this.current.activeSMask.startTransformInverse, 7932 groupCtx.mozCurrentTransform 7933 ); 7934 this.ctx.transform.apply(this.ctx, deltaTransform); 7935 }, 7936 save: function CanvasGraphics_save() { 7937 this.ctx.save(); 7938 var old = this.current; 7939 this.stateStack.push(old); 7940 this.current = old.clone(); 7941 this.current.resumeSMaskCtx = null; 7942 }, 7943 restore: function CanvasGraphics_restore() { 7944 // SMask was suspended, we just need to resume it. 7945 if (this.current.resumeSMaskCtx) { 7946 this.resumeSMaskGroup(); 7947 } 7948 // SMask has to be finished once there is no states that are using the 7949 // same SMask. 7950 if ( 7951 this.current.activeSMask !== null && 7952 (this.stateStack.length === 0 || 7953 this.stateStack[this.stateStack.length - 1].activeSMask !== this.current.activeSMask) 7954 ) { 7955 this.endSMaskGroup(); 7956 } 7957 7958 if (this.stateStack.length !== 0) { 7959 this.current = this.stateStack.pop(); 7960 this.ctx.restore(); 7961 7962 // Ensure that the clipping path is reset (fixes issue6413.pdf). 7963 this.pendingClip = null; 7964 7965 this.cachedGetSinglePixelWidth = null; 7966 } 7967 }, 7968 transform: function CanvasGraphics_transform(a, b, c, d, e, f) { 7969 this.ctx.transform(a, b, c, d, e, f); 7970 7971 this.cachedGetSinglePixelWidth = null; 7972 }, 7973 7974 // Path 7975 constructPath: function CanvasGraphics_constructPath(ops, args) { 7976 var ctx = this.ctx; 7977 var current = this.current; 7978 var x = current.x, 7979 y = current.y; 7980 for (var i = 0, j = 0, ii = ops.length; i < ii; i++) { 7981 switch (ops[i] | 0) { 7982 case OPS.rectangle: 7983 x = args[j++]; 7984 y = args[j++]; 7985 var width = args[j++]; 7986 var height = args[j++]; 7987 if (width === 0) {
vendor: 15,608 bytes, lines 7988-8387
7988 width = this.getSinglePixelWidth(); 7989 } 7990 if (height === 0) { 7991 height = this.getSinglePixelWidth(); 7992 } 7993 var xw = x + width; 7994 var yh = y + height; 7995 this.ctx.moveTo(x, y); 7996 this.ctx.lineTo(xw, y); 7997 this.ctx.lineTo(xw, yh); 7998 this.ctx.lineTo(x, yh); 7999 this.ctx.lineTo(x, y); 8000 this.ctx.closePath(); 8001 break; 8002 case OPS.moveTo: 8003 x = args[j++]; 8004 y = args[j++]; 8005 ctx.moveTo(x, y); 8006 break; 8007 case OPS.lineTo: 8008 x = args[j++]; 8009 y = args[j++]; 8010 ctx.lineTo(x, y); 8011 break; 8012 case OPS.curveTo: 8013 x = args[j + 4]; 8014 y = args[j + 5]; 8015 ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y); 8016 j += 6; 8017 break; 8018 case OPS.curveTo2: 8019 ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]); 8020 x = args[j + 2]; 8021 y = args[j + 3]; 8022 j += 4; 8023 break; 8024 case OPS.curveTo3: 8025 x = args[j + 2]; 8026 y = args[j + 3]; 8027 ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y); 8028 j += 4; 8029 break; 8030 case OPS.closePath: 8031 ctx.closePath(); 8032 break; 8033 } 8034 } 8035 current.setCurrentPoint(x, y); 8036 }, 8037 closePath: function CanvasGraphics_closePath() { 8038 this.ctx.closePath(); 8039 }, 8040 stroke: function CanvasGraphics_stroke(consumePath) { 8041 consumePath = typeof consumePath !== 'undefined' ? consumePath : true; 8042 var ctx = this.ctx; 8043 var strokeColor = this.current.strokeColor; 8044 // Prevent drawing too thin lines by enforcing a minimum line width. 8045 ctx.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, this.current.lineWidth); 8046 // For stroke we want to temporarily change the global alpha to the 8047 // stroking alpha. 8048 ctx.globalAlpha = this.current.strokeAlpha; 8049 if (strokeColor && strokeColor.hasOwnProperty('type') && strokeColor.type === 'Pattern') { 8050 // for patterns, we transform to pattern space, calculate 8051 // the pattern, call stroke, and restore to user space 8052 ctx.save(); 8053 ctx.strokeStyle = strokeColor.getPattern(ctx, this); 8054 ctx.stroke(); 8055 ctx.restore(); 8056 } else { 8057 ctx.stroke(); 8058 } 8059 if (consumePath) { 8060 this.consumePath(); 8061 } 8062 // Restore the global alpha to the fill alpha 8063 ctx.globalAlpha = this.current.fillAlpha; 8064 }, 8065 closeStroke: function CanvasGraphics_closeStroke() { 8066 this.closePath(); 8067 this.stroke(); 8068 }, 8069 fill: function CanvasGraphics_fill(consumePath) { 8070 consumePath = typeof consumePath !== 'undefined' ? consumePath : true; 8071 var ctx = this.ctx; 8072 var fillColor = this.current.fillColor; 8073 var isPatternFill = this.current.patternFill; 8074 var needRestore = false; 8075 8076 if (isPatternFill) { 8077 ctx.save(); 8078 if (this.baseTransform) { 8079 ctx.setTransform.apply(ctx, this.baseTransform); 8080 } 8081 ctx.fillStyle = fillColor.getPattern(ctx, this); 8082 needRestore = true; 8083 } 8084 8085 if (this.pendingEOFill) { 8086 if (ctx.mozFillRule !== undefined) { 8087 ctx.mozFillRule = 'evenodd'; 8088 ctx.fill(); 8089 ctx.mozFillRule = 'nonzero'; 8090 } else { 8091 ctx.fill('evenodd'); 8092 } 8093 this.pendingEOFill = false; 8094 } else { 8095 ctx.fill(); 8096 } 8097 8098 if (needRestore) { 8099 ctx.restore(); 8100 } 8101 if (consumePath) { 8102 this.consumePath(); 8103 } 8104 }, 8105 eoFill: function CanvasGraphics_eoFill() { 8106 this.pendingEOFill = true; 8107 this.fill(); 8108 }, 8109 fillStroke: function CanvasGraphics_fillStroke() { 8110 this.fill(false); 8111 this.stroke(false); 8112 8113 this.consumePath(); 8114 }, 8115 eoFillStroke: function CanvasGraphics_eoFillStroke() { 8116 this.pendingEOFill = true; 8117 this.fillStroke(); 8118 }, 8119 closeFillStroke: function CanvasGraphics_closeFillStroke() { 8120 this.closePath(); 8121 this.fillStroke(); 8122 }, 8123 closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() { 8124 this.pendingEOFill = true; 8125 this.closePath(); 8126 this.fillStroke(); 8127 }, 8128 endPath: function CanvasGraphics_endPath() { 8129 this.consumePath(); 8130 }, 8131 8132 // Clipping 8133 clip: function CanvasGraphics_clip() { 8134 this.pendingClip = NORMAL_CLIP; 8135 }, 8136 eoClip: function CanvasGraphics_eoClip() { 8137 this.pendingClip = EO_CLIP; 8138 }, 8139 8140 // Text 8141 beginText: function CanvasGraphics_beginText() { 8142 this.current.textMatrix = IDENTITY_MATRIX; 8143 this.current.textMatrixScale = 1; 8144 this.current.x = this.current.lineX = 0; 8145 this.current.y = this.current.lineY = 0; 8146 }, 8147 endText: function CanvasGraphics_endText() { 8148 var paths = this.pendingTextPaths; 8149 var ctx = this.ctx; 8150 if (paths === undefined) { 8151 ctx.beginPath(); 8152 return; 8153 } 8154 8155 ctx.save(); 8156 ctx.beginPath(); 8157 for (var i = 0; i < paths.length; i++) { 8158 var path = paths[i]; 8159 ctx.setTransform.apply(ctx, path.transform); 8160 ctx.translate(path.x, path.y); 8161 path.addToPath(ctx, path.fontSize); 8162 } 8163 ctx.restore(); 8164 ctx.clip(); 8165 ctx.beginPath(); 8166 delete this.pendingTextPaths; 8167 }, 8168 setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) { 8169 this.current.charSpacing = spacing; 8170 }, 8171 setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) { 8172 this.current.wordSpacing = spacing; 8173 }, 8174 setHScale: function CanvasGraphics_setHScale(scale) { 8175 this.current.textHScale = scale / 100; 8176 }, 8177 setLeading: function CanvasGraphics_setLeading(leading) { 8178 this.current.leading = -leading; 8179 }, 8180 setFont: function CanvasGraphics_setFont(fontRefName, size) { 8181 var fontObj = this.commonObjs.get(fontRefName); 8182 var current = this.current; 8183 8184 if (!fontObj) { 8185 error("Can't find font for " + fontRefName); 8186 } 8187 8188 current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix : FONT_IDENTITY_MATRIX; 8189 8190 // A valid matrix needs all main diagonal elements to be non-zero 8191 // This also ensures we bypass FF bugzilla bug #719844. 8192 if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) { 8193 warn('Invalid font matrix for font ' + fontRefName); 8194 } 8195 8196 // The spec for Tf (setFont) says that 'size' specifies the font 'scale', 8197 // and in some docs this can be negative (inverted x-y axes). 8198 if (size < 0) { 8199 size = -size; 8200 current.fontDirection = -1; 8201 } else { 8202 current.fontDirection = 1; 8203 } 8204 8205 this.current.font = fontObj; 8206 this.current.fontSize = size; 8207 8208 if (fontObj.isType3Font) { 8209 return; // we don't need ctx.font for Type3 fonts 8210 } 8211 8212 var name = fontObj.loadedName || 'sans-serif'; 8213 var bold = fontObj.black ? (fontObj.bold ? '900' : 'bold') : fontObj.bold ? 'bold' : 'normal'; 8214 8215 var italic = fontObj.italic ? 'italic' : 'normal'; 8216 var typeface = '"' + name + '", ' + fontObj.fallbackName; 8217 8218 // Some font backends cannot handle fonts below certain size. 8219 // Keeping the font at minimal size and using the fontSizeScale to change 8220 // the current transformation matrix before the fillText/strokeText. 8221 // See https://bugzilla.mozilla.org/show_bug.cgi?id=726227 8222 var browserFontSize = size < MIN_FONT_SIZE ? MIN_FONT_SIZE : size > MAX_FONT_SIZE ? MAX_FONT_SIZE : size; 8223 this.current.fontSizeScale = size / browserFontSize; 8224 8225 var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface; 8226 this.ctx.font = rule; 8227 }, 8228 setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) { 8229 this.current.textRenderingMode = mode; 8230 }, 8231 setTextRise: function CanvasGraphics_setTextRise(rise) { 8232 this.current.textRise = rise; 8233 }, 8234 moveText: function CanvasGraphics_moveText(x, y) { 8235 this.current.x = this.current.lineX += x; 8236 this.current.y = this.current.lineY += y; 8237 }, 8238 setLeadingMoveText: function CanvasGraphics_setLeadingMoveText(x, y) { 8239 this.setLeading(-y); 8240 this.moveText(x, y); 8241 }, 8242 setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) { 8243 this.current.textMatrix = [a, b, c, d, e, f]; 8244 this.current.textMatrixScale = Math.sqrt(a * a + b * b); 8245 8246 this.current.x = this.current.lineX = 0; 8247 this.current.y = this.current.lineY = 0; 8248 }, 8249 nextLine: function CanvasGraphics_nextLine() { 8250 this.moveText(0, this.current.leading); 8251 }, 8252 8253 paintChar: function CanvasGraphics_paintChar(character, x, y) { 8254 var ctx = this.ctx; 8255 var current = this.current; 8256 var font = current.font; 8257 var textRenderingMode = current.textRenderingMode; 8258 var fontSize = current.fontSize / current.fontSizeScale; 8259 var fillStrokeMode = textRenderingMode & TextRenderingMode.FILL_STROKE_MASK; 8260 var isAddToPathSet = !!(textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG); 8261 8262 var addToPath; 8263 if (font.disableFontFace || isAddToPathSet) { 8264 addToPath = font.getPathGenerator(this.commonObjs, character); 8265 } 8266 8267 if (font.disableFontFace) { 8268 ctx.save(); 8269 ctx.translate(x, y); 8270 ctx.beginPath(); 8271 addToPath(ctx, fontSize); 8272 if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) { 8273 ctx.fill(); 8274 } 8275 if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) { 8276 ctx.stroke(); 8277 } 8278 ctx.restore(); 8279 } else { 8280 if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) { 8281 ctx.fillText(character, x, y); 8282 } 8283 if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) { 8284 ctx.strokeText(character, x, y); 8285 } 8286 } 8287 8288 if (isAddToPathSet) { 8289 var paths = this.pendingTextPaths || (this.pendingTextPaths = []); 8290 paths.push({ 8291 transform: ctx.mozCurrentTransform, 8292 x: x, 8293 y: y, 8294 fontSize: fontSize, 8295 addToPath: addToPath, 8296 }); 8297 } 8298 }, 8299 8300 get isFontSubpixelAAEnabled() { 8301 // Checks if anti-aliasing is enabled when scaled text is painted. 8302 // On Windows GDI scaled fonts looks bad. 8303 var ctx = document.createElement('canvas').getContext('2d'); 8304 ctx.scale(1.5, 1); 8305 ctx.fillText('I', 0, 10); 8306 var data = ctx.getImageData(0, 0, 10, 10).data; 8307 var enabled = false; 8308 for (var i = 3; i < data.length; i += 4) { 8309 if (data[i] > 0 && data[i] < 255) { 8310 enabled = true; 8311 break; 8312 } 8313 } 8314 return shadow(this, 'isFontSubpixelAAEnabled', enabled); 8315 }, 8316 8317 showText: function CanvasGraphics_showText(glyphs) { 8318 var current = this.current; 8319 var font = current.font; 8320 if (font.isType3Font) { 8321 return this.showType3Text(glyphs); 8322 } 8323 8324 var fontSize = current.fontSize; 8325 if (fontSize === 0) { 8326 return; 8327 } 8328 8329 var ctx = this.ctx; 8330 var fontSizeScale = current.fontSizeScale; 8331 var charSpacing = current.charSpacing; 8332 var wordSpacing = current.wordSpacing; 8333 var fontDirection = current.fontDirection; 8334 var textHScale = current.textHScale * fontDirection; 8335 var glyphsLength = glyphs.length; 8336 var vertical = font.vertical; 8337 var spacingDir = vertical ? 1 : -1; 8338 var defaultVMetrics = font.defaultVMetrics; 8339 var widthAdvanceScale = fontSize * current.fontMatrix[0]; 8340 8341 var simpleFillText = current.textRenderingMode === TextRenderingMode.FILL && !font.disableFontFace; 8342 8343 ctx.save(); 8344 ctx.transform.apply(ctx, current.textMatrix); 8345 ctx.translate(current.x, current.y + current.textRise); 8346 8347 if (current.patternFill) { 8348 // TODO: Some shading patterns are not applied correctly to text, 8349 // e.g. issues 3988 and 5432, and ShowText-ShadingPattern.pdf. 8350 ctx.fillStyle = current.fillColor.getPattern(ctx, this); 8351 } 8352 8353 if (fontDirection > 0) { 8354 ctx.scale(textHScale, -1); 8355 } else { 8356 ctx.scale(textHScale, 1); 8357 } 8358 8359 var lineWidth = current.lineWidth; 8360 var scale = current.textMatrixScale; 8361 if (scale === 0 || lineWidth === 0) { 8362 var fillStrokeMode = current.textRenderingMode & TextRenderingMode.FILL_STROKE_MASK; 8363 if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) { 8364 this.cachedGetSinglePixelWidth = null; 8365 lineWidth = this.getSinglePixelWidth() * MIN_WIDTH_FACTOR; 8366 } 8367 } else { 8368 lineWidth /= scale; 8369 } 8370 8371 if (fontSizeScale !== 1.0) { 8372 ctx.scale(fontSizeScale, fontSizeScale); 8373 lineWidth /= fontSizeScale; 8374 } 8375 8376 ctx.lineWidth = lineWidth; 8377 8378 var x = 0, 8379 i; 8380 for (i = 0; i < glyphsLength; ++i) { 8381 var glyph = glyphs[i]; 8382 if (isNum(glyph)) { 8383 x += (spacingDir * glyph * fontSize) / 1000; 8384 continue; 8385 } 8386 8387 var restoreNeeded = false;
8388 var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; 8389 var character = glyph.fontChar; 8390 var accent = glyph.accent; 8391 var scaledX, scaledY, scaledAccentX, scaledAccentY; 8392 var width = glyph.width; 8393 if (vertical) { 8394 var vmetric, vx, vy; 8395 vmetric = glyph.vmetric || defaultVMetrics; 8396 vx = glyph.vmetric ? vmetric[1] : width * 0.5; 8397 vx = -vx * widthAdvanceScale; 8398 vy = vmetric[2] * widthAdvanceScale; 8399 8400 width = vmetric ? -vmetric[0] : width; 8401 scaledX = vx / fontSizeScale; 8402 scaledY = (x + vy) / fontSizeScale; 8403 } else { 8404 scaledX = x / fontSizeScale; 8405 scaledY = 0; 8406 } 8407 8408 if (font.remeasure && width > 0) { 8409 // Some standard fonts may not have the exact width: rescale per 8410 // character if measured width is greater than expected glyph width 8411 // and subpixel-aa is enabled, otherwise just center the glyph. 8412 var measuredWidth = ((ctx.measureText(character).width * 1000) / fontSize) * fontSizeScale; 8413 if (width < measuredWidth && this.isFontSubpixelAAEnabled) { 8414 var characterScaleX = width / measuredWidth; 8415 restoreNeeded = true; 8416 ctx.save(); 8417 ctx.scale(characterScaleX, 1); 8418 scaledX /= characterScaleX; 8419 } else if (width !== measuredWidth) { 8420 scaledX += (((width - measuredWidth) / 2000) * fontSize) / fontSizeScale; 8421 } 8422 } 8423 8424 // Only attempt to draw the glyph if it is actually in the embedded font 8425 // file or if there isn't a font file so the fallback font is shown. 8426 if (glyph.isInFont || font.missingFile) { 8427 if (simpleFillText && !accent) { 8428 // common case 8429 ctx.fillText(character, scaledX, scaledY); 8430 } else { 8431 this.paintChar(character, scaledX, scaledY); 8432 if (accent) { 8433 scaledAccentX = scaledX + accent.offset.x / fontSizeScale; 8434 scaledAccentY = scaledY - accent.offset.y / fontSizeScale; 8435 this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY); 8436 } 8437 } 8438 } 8439 8440 var charWidth = width * widthAdvanceScale + spacing * fontDirection; 8441 x += charWidth; 8442 8443 if (restoreNeeded) { 8444 ctx.restore(); 8445 } 8446 } 8447 if (vertical) { 8448 current.y -= x * textHScale; 8449 } else { 8450 current.x += x * textHScale; 8451 } 8452 ctx.restore(); 8453 }, 8454 8455 showType3Text: function CanvasGraphics_showType3Text(glyphs) { 8456 // Type3 fonts - each glyph is a "mini-PDF" 8457 var ctx = this.ctx; 8458 var current = this.current; 8459 var font = current.font; 8460 var fontSize = current.fontSize; 8461 var fontDirection = current.fontDirection; 8462 var spacingDir = font.vertical ? 1 : -1; 8463 var charSpacing = current.charSpacing; 8464 var wordSpacing = current.wordSpacing; 8465 var textHScale = current.textHScale * fontDirection; 8466 var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX; 8467 var glyphsLength = glyphs.length; 8468 var isTextInvisible = current.textRenderingMode === TextRenderingMode.INVISIBLE; 8469 var i, glyph, width, spacingLength; 8470 8471 if (isTextInvisible || fontSize === 0) { 8472 return; 8473 } 8474 this.cachedGetSinglePixelWidth = null; 8475 8476 ctx.save(); 8477 ctx.transform.apply(ctx, current.textMatrix); 8478 ctx.translate(current.x, current.y); 8479 8480 ctx.scale(textHScale, fontDirection); 8481 8482 for (i = 0; i < glyphsLength; ++i) { 8483 glyph = glyphs[i]; 8484 if (isNum(glyph)) { 8485 spacingLength = (spacingDir * glyph * fontSize) / 1000; 8486 this.ctx.translate(spacingLength, 0); 8487 current.x += spacingLength * textHScale; 8488 continue; 8489 } 8490 8491 var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing; 8492 var operatorList = font.charProcOperatorList[glyph.operatorListId]; 8493 if (!operatorList) { 8494 warn('Type3 character "' + glyph.operatorListId + '" is not available'); 8495 continue; 8496 } 8497 this.processingType3 = glyph; 8498 this.save(); 8499 ctx.scale(fontSize, fontSize); 8500 ctx.transform.apply(ctx, fontMatrix); 8501 this.executeOperatorList(operatorList);
vendor: 9,911 bytes, lines 8502-8727
8502 this.restore(); 8503 8504 var transformed = Util.applyTransform([glyph.width, 0], fontMatrix); 8505 width = transformed[0] * fontSize + spacing; 8506 8507 ctx.translate(width, 0); 8508 current.x += width * textHScale; 8509 } 8510 ctx.restore(); 8511 this.processingType3 = null; 8512 }, 8513 8514 // Type3 fonts 8515 setCharWidth: function CanvasGraphics_setCharWidth(xWidth, yWidth) { 8516 // We can safely ignore this since the width should be the same 8517 // as the width in the Widths array. 8518 }, 8519 setCharWidthAndBounds: function CanvasGraphics_setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) { 8520 // TODO According to the spec we're also suppose to ignore any operators 8521 // that set color or include images while processing this type3 font. 8522 this.ctx.rect(llx, lly, urx - llx, ury - lly); 8523 this.clip(); 8524 this.endPath(); 8525 }, 8526 8527 // Color 8528 getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) { 8529 var pattern; 8530 if (IR[0] === 'TilingPattern') { 8531 var color = IR[1]; 8532 var baseTransform = this.baseTransform || this.ctx.mozCurrentTransform.slice(); 8533 var self = this; 8534 var canvasGraphicsFactory = { 8535 createCanvasGraphics: function (ctx) { 8536 return new CanvasGraphics(ctx, self.commonObjs, self.objs); 8537 }, 8538 }; 8539 pattern = new TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform); 8540 } else { 8541 pattern = getShadingPatternFromIR(IR); 8542 } 8543 return pattern; 8544 }, 8545 setStrokeColorN: function CanvasGraphics_setStrokeColorN(/*...*/) { 8546 this.current.strokeColor = this.getColorN_Pattern(arguments); 8547 }, 8548 setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) { 8549 this.current.fillColor = this.getColorN_Pattern(arguments); 8550 this.current.patternFill = true; 8551 }, 8552 setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) { 8553 var color = Util.makeCssRgb(r, g, b); 8554 this.ctx.strokeStyle = color; 8555 this.current.strokeColor = color; 8556 }, 8557 setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) { 8558 var color = Util.makeCssRgb(r, g, b); 8559 this.ctx.fillStyle = color; 8560 this.current.fillColor = color; 8561 this.current.patternFill = false; 8562 }, 8563 8564 shadingFill: function CanvasGraphics_shadingFill(patternIR) { 8565 var ctx = this.ctx; 8566 8567 this.save(); 8568 var pattern = getShadingPatternFromIR(patternIR); 8569 ctx.fillStyle = pattern.getPattern(ctx, this, true); 8570 8571 var inv = ctx.mozCurrentTransformInverse; 8572 if (inv) { 8573 var canvas = ctx.canvas; 8574 var width = canvas.width; 8575 var height = canvas.height; 8576 8577 var bl = Util.applyTransform([0, 0], inv); 8578 var br = Util.applyTransform([0, height], inv); 8579 var ul = Util.applyTransform([width, 0], inv); 8580 var ur = Util.applyTransform([width, height], inv); 8581 8582 var x0 = Math.min(bl[0], br[0], ul[0], ur[0]); 8583 var y0 = Math.min(bl[1], br[1], ul[1], ur[1]); 8584 var x1 = Math.max(bl[0], br[0], ul[0], ur[0]); 8585 var y1 = Math.max(bl[1], br[1], ul[1], ur[1]); 8586 8587 this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0); 8588 } else { 8589 // HACK to draw the gradient onto an infinite rectangle. 8590 // PDF gradients are drawn across the entire image while 8591 // Canvas only allows gradients to be drawn in a rectangle 8592 // The following bug should allow us to remove this. 8593 // https://bugzilla.mozilla.org/show_bug.cgi?id=664884 8594 8595 this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); 8596 } 8597 8598 this.restore(); 8599 }, 8600 8601 // Images 8602 beginInlineImage: function CanvasGraphics_beginInlineImage() { 8603 error('Should not call beginInlineImage'); 8604 }, 8605 beginImageData: function CanvasGraphics_beginImageData() { 8606 error('Should not call beginImageData'); 8607 }, 8608 8609 paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix, bbox) { 8610 this.save(); 8611 this.baseTransformStack.push(this.baseTransform); 8612 8613 if (isArray(matrix) && 6 === matrix.length) { 8614 this.transform.apply(this, matrix); 8615 } 8616 8617 this.baseTransform = this.ctx.mozCurrentTransform; 8618 8619 if (isArray(bbox) && 4 === bbox.length) { 8620 var width = bbox[2] - bbox[0]; 8621 var height = bbox[3] - bbox[1]; 8622 this.ctx.rect(bbox[0], bbox[1], width, height); 8623 this.clip(); 8624 this.endPath(); 8625 } 8626 }, 8627 8628 paintFormXObjectEnd: function CanvasGraphics_paintFormXObjectEnd() { 8629 this.restore(); 8630 this.baseTransform = this.baseTransformStack.pop(); 8631 }, 8632 8633 beginGroup: function CanvasGraphics_beginGroup(group) { 8634 this.save(); 8635 var currentCtx = this.ctx; 8636 // TODO non-isolated groups - according to Rik at adobe non-isolated 8637 // group results aren't usually that different and they even have tools 8638 // that ignore this setting. Notes from Rik on implementing: 8639 // - When you encounter an transparency group, create a new canvas with 8640 // the dimensions of the bbox 8641 // - copy the content from the previous canvas to the new canvas 8642 // - draw as usual 8643 // - remove the backdrop alpha: 8644 // alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha 8645 // value of your transparency group and 'alphaBackdrop' the alpha of the 8646 // backdrop 8647 // - remove background color: 8648 // colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew) 8649 if (!group.isolated) { 8650 info('TODO: Support non-isolated groups.'); 8651 } 8652 8653 // TODO knockout - supposedly possible with the clever use of compositing 8654 // modes. 8655 if (group.knockout) { 8656 warn('Knockout groups not supported.'); 8657 } 8658 8659 var currentTransform = currentCtx.mozCurrentTransform; 8660 if (group.matrix) { 8661 currentCtx.transform.apply(currentCtx, group.matrix); 8662 } 8663 assert(group.bbox, 'Bounding box is required.'); 8664 8665 // Based on the current transform figure out how big the bounding box 8666 // will actually be. 8667 var bounds = Util.getAxialAlignedBoundingBox(group.bbox, currentCtx.mozCurrentTransform); 8668 // Clip the bounding box to the current canvas. 8669 var canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height]; 8670 bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0]; 8671 // Use ceil in case we're between sizes so we don't create canvas that is 8672 // too small and make the canvas at least 1x1 pixels. 8673 var offsetX = Math.floor(bounds[0]); 8674 var offsetY = Math.floor(bounds[1]); 8675 var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1); 8676 var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1); 8677 var scaleX = 1, 8678 scaleY = 1; 8679 if (drawnWidth > MAX_GROUP_SIZE) { 8680 scaleX = drawnWidth / MAX_GROUP_SIZE; 8681 drawnWidth = MAX_GROUP_SIZE; 8682 } 8683 if (drawnHeight > MAX_GROUP_SIZE) { 8684 scaleY = drawnHeight / MAX_GROUP_SIZE; 8685 drawnHeight = MAX_GROUP_SIZE; 8686 } 8687 8688 var cacheId = 'groupAt' + this.groupLevel; 8689 if (group.smask) { 8690 // Using two cache entries is case if masks are used one after another. 8691 cacheId += '_smask_' + (this.smaskCounter++ % 2); 8692 } 8693 var scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true); 8694 var groupCtx = scratchCanvas.context; 8695 8696 // Since we created a new canvas that is just the size of the bounding box 8697 // we have to translate the group ctx. 8698 groupCtx.scale(1 / scaleX, 1 / scaleY); 8699 groupCtx.translate(-offsetX, -offsetY); 8700 groupCtx.transform.apply(groupCtx, currentTransform); 8701 8702 if (group.smask) { 8703 // Saving state and cached mask to be used in setGState. 8704 this.smaskStack.push({ 8705 canvas: scratchCanvas.canvas, 8706 context: groupCtx, 8707 offsetX: offsetX, 8708 offsetY: offsetY, 8709 scaleX: scaleX, 8710 scaleY: scaleY, 8711 subtype: group.smask.subtype, 8712 backdrop: group.smask.backdrop, 8713 transferMap: group.smask.transferMap || null, 8714 startTransformInverse: null, // used during suspend operation 8715 }); 8716 } else { 8717 // Setup the current ctx so when the group is popped we draw it at the 8718 // right location. 8719 currentCtx.setTransform(1, 0, 0, 1, 0, 0); 8720 currentCtx.translate(offsetX, offsetY); 8721 currentCtx.scale(scaleX, scaleY); 8722 } 8723 // The transparency group inherits all off the current graphics state 8724 // except the blend mode, soft mask, and alpha constants. 8725 copyCtxState(currentCtx, groupCtx); 8726 this.ctx = groupCtx; 8727 this.setGState([
8728 ['BM', 'Normal'], 8729 ['ca', 1], 8730 ['CA', 1], 8731 ]); 8732 this.groupStack.push(currentCtx); 8733 this.groupLevel++; 8734 8735 // Reseting mask state, masks will be applied on restore of the group. 8736 this.current.activeSMask = null; 8737 }, 8738 8739 endGroup: function CanvasGraphics_endGroup(group) { 8740 this.groupLevel--; 8741 var groupCtx = this.ctx; 8742 this.ctx = this.groupStack.pop(); 8743 // Turn off image smoothing to avoid sub pixel interpolation which can 8744 // look kind of blurry for some pdfs. 8745 if (this.ctx.imageSmoothingEnabled !== undefined) { 8746 this.ctx.imageSmoothingEnabled = false; 8747 } else { 8748 this.ctx.mozImageSmoothingEnabled = false; 8749 } 8750 if (group.smask) { 8751 this.tempSMask = this.smaskStack.pop(); 8752 } else { 8753 this.ctx.drawImage(groupCtx.canvas, 0, 0); 8754 } 8755 this.restore(); 8756 }, 8757 8758 beginAnnotations: function CanvasGraphics_beginAnnotations() { 8759 this.save(); 8760 this.current = new CanvasExtraState(); 8761 8762 if (this.baseTransform) { 8763 this.ctx.setTransform.apply(this.ctx, this.baseTransform); 8764 } 8765 }, 8766 8767 endAnnotations: function CanvasGraphics_endAnnotations() { 8768 this.restore(); 8769 }, 8770 8771 beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform, matrix) { 8772 this.save(); 8773
vendor: 9,388 bytes, lines 8774-9022
8774 if (isArray(rect) && 4 === rect.length) { 8775 var width = rect[2] - rect[0]; 8776 var height = rect[3] - rect[1]; 8777 this.ctx.rect(rect[0], rect[1], width, height); 8778 this.clip(); 8779 this.endPath(); 8780 } 8781 8782 this.transform.apply(this, transform); 8783 this.transform.apply(this, matrix); 8784 }, 8785 8786 endAnnotation: function CanvasGraphics_endAnnotation() { 8787 this.restore(); 8788 }, 8789 8790 paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) { 8791 var domImage = this.objs.get(objId); 8792 if (!domImage) { 8793 warn("Dependent image isn't ready yet"); 8794 return; 8795 } 8796 8797 this.save(); 8798 8799 var ctx = this.ctx; 8800 // scale the image to the unit square 8801 ctx.scale(1 / w, -1 / h); 8802 8803 ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, 0, -h, w, h); 8804 if (this.imageLayer) { 8805 var currentTransform = ctx.mozCurrentTransformInverse; 8806 var position = this.getCanvasPosition(0, 0); 8807 this.imageLayer.appendImage({ 8808 objId: objId, 8809 left: position[0], 8810 top: position[1], 8811 width: w / currentTransform[0], 8812 height: h / currentTransform[3], 8813 }); 8814 } 8815 this.restore(); 8816 }, 8817 8818 paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) { 8819 var ctx = this.ctx; 8820 var width = img.width, 8821 height = img.height; 8822 var fillColor = this.current.fillColor; 8823 var isPatternFill = this.current.patternFill; 8824 8825 var glyph = this.processingType3; 8826 8827 if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) { 8828 if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) { 8829 glyph.compiled = compileType3Glyph({ 8830 data: img.data, 8831 width: width, 8832 height: height, 8833 }); 8834 } else { 8835 glyph.compiled = null; 8836 } 8837 } 8838 8839 if (glyph && glyph.compiled) { 8840 glyph.compiled(ctx); 8841 return; 8842 } 8843 8844 var maskCanvas = this.cachedCanvases.getCanvas('maskCanvas', width, height); 8845 var maskCtx = maskCanvas.context; 8846 maskCtx.save(); 8847 8848 putBinaryImageMask(maskCtx, img); 8849 8850 maskCtx.globalCompositeOperation = 'source-in'; 8851 8852 maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor; 8853 maskCtx.fillRect(0, 0, width, height); 8854 8855 maskCtx.restore(); 8856 8857 this.paintInlineImageXObject(maskCanvas.canvas); 8858 }, 8859 8860 paintImageMaskXObjectRepeat: function CanvasGraphics_paintImageMaskXObjectRepeat( 8861 imgData, 8862 scaleX, 8863 scaleY, 8864 positions 8865 ) { 8866 var width = imgData.width; 8867 var height = imgData.height; 8868 var fillColor = this.current.fillColor; 8869 var isPatternFill = this.current.patternFill; 8870 8871 var maskCanvas = this.cachedCanvases.getCanvas('maskCanvas', width, height); 8872 var maskCtx = maskCanvas.context; 8873 maskCtx.save(); 8874 8875 putBinaryImageMask(maskCtx, imgData); 8876 8877 maskCtx.globalCompositeOperation = 'source-in'; 8878 8879 maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor; 8880 maskCtx.fillRect(0, 0, width, height); 8881 8882 maskCtx.restore(); 8883 8884 var ctx = this.ctx; 8885 for (var i = 0, ii = positions.length; i < ii; i += 2) { 8886 ctx.save(); 8887 ctx.transform(scaleX, 0, 0, scaleY, positions[i], positions[i + 1]); 8888 ctx.scale(1, -1); 8889 ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1); 8890 ctx.restore(); 8891 } 8892 }, 8893 8894 paintImageMaskXObjectGroup: function CanvasGraphics_paintImageMaskXObjectGroup(images) { 8895 var ctx = this.ctx; 8896 8897 var fillColor = this.current.fillColor; 8898 var isPatternFill = this.current.patternFill; 8899 for (var i = 0, ii = images.length; i < ii; i++) { 8900 var image = images[i]; 8901 var width = image.width, 8902 height = image.height; 8903 8904 var maskCanvas = this.cachedCanvases.getCanvas('maskCanvas', width, height); 8905 var maskCtx = maskCanvas.context; 8906 maskCtx.save(); 8907 8908 putBinaryImageMask(maskCtx, image); 8909 8910 maskCtx.globalCompositeOperation = 'source-in'; 8911 8912 maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this) : fillColor; 8913 maskCtx.fillRect(0, 0, width, height); 8914 8915 maskCtx.restore(); 8916 8917 ctx.save(); 8918 ctx.transform.apply(ctx, image.transform); 8919 ctx.scale(1, -1); 8920 ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1); 8921 ctx.restore(); 8922 } 8923 }, 8924 8925 paintImageXObject: function CanvasGraphics_paintImageXObject(objId) { 8926 var imgData = this.objs.get(objId); 8927 if (!imgData) { 8928 warn("Dependent image isn't ready yet"); 8929 return; 8930 } 8931 8932 this.paintInlineImageXObject(imgData); 8933 }, 8934 8935 paintImageXObjectRepeat: function CanvasGraphics_paintImageXObjectRepeat(objId, scaleX, scaleY, positions) { 8936 var imgData = this.objs.get(objId); 8937 if (!imgData) { 8938 warn("Dependent image isn't ready yet"); 8939 return; 8940 } 8941 8942 var width = imgData.width; 8943 var height = imgData.height; 8944 var map = []; 8945 for (var i = 0, ii = positions.length; i < ii; i += 2) { 8946 map.push({ 8947 transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]], 8948 x: 0, 8949 y: 0, 8950 w: width, 8951 h: height, 8952 }); 8953 } 8954 this.paintInlineImageXObjectGroup(imgData, map); 8955 }, 8956 8957 paintInlineImageXObject: function CanvasGraphics_paintInlineImageXObject(imgData) { 8958 var width = imgData.width; 8959 var height = imgData.height; 8960 var ctx = this.ctx; 8961 8962 this.save(); 8963 // scale the image to the unit square 8964 ctx.scale(1 / width, -1 / height); 8965 8966 var currentTransform = ctx.mozCurrentTransformInverse; 8967 var a = currentTransform[0], 8968 b = currentTransform[1]; 8969 var widthScale = Math.max(Math.sqrt(a * a + b * b), 1); 8970 var c = currentTransform[2], 8971 d = currentTransform[3]; 8972 var heightScale = Math.max(Math.sqrt(c * c + d * d), 1); 8973 8974 var imgToPaint, tmpCanvas; 8975 // instanceof HTMLElement does not work in jsdom node.js module 8976 if (imgData instanceof HTMLElement || !imgData.data) { 8977 imgToPaint = imgData; 8978 } else { 8979 tmpCanvas = this.cachedCanvases.getCanvas('inlineImage', width, height); 8980 var tmpCtx = tmpCanvas.context; 8981 putBinaryImageData(tmpCtx, imgData); 8982 imgToPaint = tmpCanvas.canvas; 8983 } 8984 8985 var paintWidth = width, 8986 paintHeight = height; 8987 var tmpCanvasId = 'prescale1'; 8988 // Vertial or horizontal scaling shall not be more than 2 to not loose the 8989 // pixels during drawImage operation, painting on the temporary canvas(es) 8990 // that are twice smaller in size 8991 while ((widthScale > 2 && paintWidth > 1) || (heightScale > 2 && paintHeight > 1)) { 8992 var newWidth = paintWidth, 8993 newHeight = paintHeight; 8994 if (widthScale > 2 && paintWidth > 1) { 8995 newWidth = Math.ceil(paintWidth / 2); 8996 widthScale /= paintWidth / newWidth; 8997 } 8998 if (heightScale > 2 && paintHeight > 1) { 8999 newHeight = Math.ceil(paintHeight / 2); 9000 heightScale /= paintHeight / newHeight; 9001 } 9002 tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight); 9003 tmpCtx = tmpCanvas.context; 9004 tmpCtx.clearRect(0, 0, newWidth, newHeight); 9005 tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight); 9006 imgToPaint = tmpCanvas.canvas; 9007 paintWidth = newWidth; 9008 paintHeight = newHeight; 9009 tmpCanvasId = tmpCanvasId === 'prescale1' ? 'prescale2' : 'prescale1'; 9010 } 9011 ctx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight, 0, -height, width, height); 9012 9013 if (this.imageLayer) { 9014 var position = this.getCanvasPosition(0, -height); 9015 this.imageLayer.appendImage({ 9016 imgData: imgData, 9017 left: position[0], 9018 top: position[1], 9019 width: width / currentTransform[0], 9020 height: height / currentTransform[3], 9021 }); 9022 }
9023 this.restore(); 9024 }, 9025 9026 paintInlineImageXObjectGroup: function CanvasGraphics_paintInlineImageXObjectGroup(imgData, map) { 9027 var ctx = this.ctx; 9028 var w = imgData.width; 9029 var h = imgData.height; 9030 9031 var tmpCanvas = this.cachedCanvases.getCanvas('inlineImage', w, h); 9032 var tmpCtx = tmpCanvas.context; 9033 putBinaryImageData(tmpCtx, imgData); 9034 9035 for (var i = 0, ii = map.length; i < ii; i++) { 9036 var entry = map[i]; 9037 ctx.save(); 9038 ctx.transform.apply(ctx, entry.transform); 9039 ctx.scale(1, -1); 9040 ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1); 9041 if (this.imageLayer) { 9042 var position = this.getCanvasPosition(entry.x, entry.y); 9043 this.imageLayer.appendImage({ 9044 imgData: imgData, 9045 left: position[0], 9046 top: position[1], 9047 width: w, 9048 height: h, 9049 }); 9050 } 9051 ctx.restore(); 9052 } 9053 }, 9054 9055 paintSolidColorImageMask: function CanvasGraphics_paintSolidColorImageMask() { 9056 this.ctx.fillRect(0, 0, 1, 1); 9057 }, 9058 9059 paintXObject: function CanvasGraphics_paintXObject() { 9060 warn("Unsupported 'paintXObject' command."); 9061 }, 9062 9063 // Marked content 9064 9065 markPoint: function CanvasGraphics_markPoint(tag) { 9066 // TODO Marked content. 9067 }, 9068 markPointProps: function CanvasGraphics_markPointProps(tag, properties) { 9069 // TODO Marked content. 9070 }, 9071 beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) { 9072 // TODO Marked content. 9073 }, 9074 beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps(tag, properties) { 9075 // TODO Marked content. 9076 }, 9077 endMarkedContent: function CanvasGraphics_endMarkedContent() { 9078 // TODO Marked content. 9079 }, 9080 9081 // Compatibility 9082 9083 beginCompat: function CanvasGraphics_beginCompat() { 9084 // TODO ignore undefined operators (should we do that anyway?) 9085 }, 9086 endCompat: function CanvasGraphics_endCompat() { 9087 // TODO stop ignoring undefined operators 9088 }, 9089 9090 // Helper functions 9091 9092 consumePath: function CanvasGraphics_consumePath() { 9093 var ctx = this.ctx; 9094 if (this.pendingClip) { 9095 if (this.pendingClip === EO_CLIP) { 9096 if (ctx.mozFillRule !== undefined) { 9097 ctx.mozFillRule = 'evenodd'; 9098 ctx.clip(); 9099 ctx.mozFillRule = 'nonzero'; 9100 } else { 9101 ctx.clip('evenodd'); 9102 } 9103 } else { 9104 ctx.clip(); 9105 } 9106 this.pendingClip = null; 9107 } 9108 ctx.beginPath(); 9109 }, 9110 getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) { 9111 if (this.cachedGetSinglePixelWidth === null) { 9112 // NOTE: The `save` and `restore` commands used below is a workaround 9113 // that is necessary in order to prevent `mozCurrentTransformInverse` 9114 // from intermittently returning incorrect values in Firefox, see: 9115 // https://github.com/mozilla/pdf.js/issues/7188. 9116 this.ctx.save(); 9117 var inverse = this.ctx.mozCurrentTransformInverse; 9118 this.ctx.restore(); 9119 // max of the current horizontal and vertical scale 9120 this.cachedGetSinglePixelWidth = Math.sqrt( 9121 Math.max( 9122 inverse[0] * inverse[0] + inverse[1] * inverse[1], 9123 inverse[2] * inverse[2] + inverse[3] * inverse[3] 9124 ) 9125 ); 9126 } 9127 return this.cachedGetSinglePixelWidth; 9128 }, 9129 getCanvasPosition: function CanvasGraphics_getCanvasPosition(x, y) { 9130 var transform = this.ctx.mozCurrentTransform; 9131 return [ 9132 transform[0] * x + transform[2] * y + transform[4], 9133 transform[1] * x + transform[3] * y + transform[5], 9134 ]; 9135 }, 9136 }; 9137 9138 for (var op in OPS) { 9139 CanvasGraphics.prototype[OPS[op]] = CanvasGraphics.prototype[op]; 9140 } 9141 9142 return CanvasGraphics; 9143 })(); 9144 9145 exports.CanvasGraphics = CanvasGraphics; 9146 exports.createScratchCanvas = createScratchCanvas; 9147 }); 9148 9149 (function (root, factory) { 9150 { 9151 factory( 9152 (root.pdfjsDisplayAPI = {}), 9153 root.pdfjsSharedUtil, 9154 root.pdfjsDisplayFontLoader, 9155 root.pdfjsDisplayCanvas, 9156 root.pdfjsDisplayMetadata, 9157 root.pdfjsDisplayDOMUtils 9158 ); 9159 } 9160 })( 9161 this, 9162 function (exports, sharedUtil, displayFontLoader, displayCanvas, displayMetadata, displayDOMUtils, amdRequire) { 9163 var InvalidPDFException = sharedUtil.InvalidPDFException; 9164 var MessageHandler = sharedUtil.MessageHandler; 9165 var MissingPDFException = sharedUtil.MissingPDFException; 9166 var PageViewport = sharedUtil.PageViewport; 9167 var PasswordResponses = sharedUtil.PasswordResponses; 9168 var PasswordException = sharedUtil.PasswordException; 9169 var StatTimer = sharedUtil.StatTimer; 9170 var UnexpectedResponseException = sharedUtil.UnexpectedResponseException; 9171 var UnknownErrorException = sharedUtil.UnknownErrorException; 9172 var Util = sharedUtil.Util; 9173 var createPromiseCapability = sharedUtil.createPromiseCapability; 9174 var error = sharedUtil.error; 9175 var deprecated = sharedUtil.deprecated; 9176 var getVerbosityLevel = sharedUtil.getVerbosityLevel; 9177 var info = sharedUtil.info; 9178 var isInt = sharedUtil.isInt; 9179 var isArray = sharedUtil.isArray; 9180 var isArrayBuffer = sharedUtil.isArrayBuffer; 9181 var isSameOrigin = sharedUtil.isSameOrigin; 9182 var loadJpegStream = sharedUtil.loadJpegStream; 9183 var stringToBytes = sharedUtil.stringToBytes; 9184 var globalScope = sharedUtil.globalScope; 9185 var warn = sharedUtil.warn; 9186 var FontFaceObject = displayFontLoader.FontFaceObject; 9187 var FontLoader = displayFontLoader.FontLoader; 9188 var CanvasGraphics = displayCanvas.CanvasGraphics; 9189 var createScratchCanvas = displayCanvas.createScratchCanvas;
9190 var Metadata = displayMetadata.Metadata; 9191 var getDefaultSetting = displayDOMUtils.getDefaultSetting; 9192 9193 var DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536 9194 9195 var isWorkerDisabled = false; 9196 var workerSrc; 9197 var isPostMessageTransfersDisabled = false; 9198 9199 var useRequireEnsure = false; 9200 if (typeof window === 'undefined') { 9201 // node.js - disable worker and set require.ensure. 9202 isWorkerDisabled = true; 9203 if (typeof require.ensure === 'undefined') { 9204 require.ensure = require('node-ensure'); 9205 } 9206 useRequireEnsure = true; 9207 } 9208 if (typeof __webpack_require__ !== 'undefined') { 9209 useRequireEnsure = true; 9210 } 9211 if (typeof requirejs !== 'undefined' && requirejs.toUrl) { 9212 workerSrc = requirejs.toUrl('pdfjs-dist/build/pdf.worker.js'); 9213 } 9214 var dynamicLoaderSupported = typeof requirejs !== 'undefined' && requirejs.load; 9215 var fakeWorkerFilesLoader = useRequireEnsure 9216 ? function (callback) { 9217 require.ensure([], function () { 9218 var worker = require('./pdf.worker.js'); 9219 callback(worker.WorkerMessageHandler); 9220 }); 9221 } 9222 : dynamicLoaderSupported 9223 ? function (callback) { 9224 requirejs(['pdfjs-dist/build/pdf.worker'], function (worker) { 9225 callback(worker.WorkerMessageHandler); 9226 }); 9227 } 9228 : null; 9229 9230 /** 9231 * Document initialization / loading parameters object. 9232 * 9233 * @typedef {Object} DocumentInitParameters 9234 * @property {string} url - The URL of the PDF. 9235 * @property {TypedArray|Array|string} data - Binary PDF data. Use typed arrays 9236 * (Uint8Array) to improve the memory usage. If PDF data is BASE64-encoded, 9237 * use atob() to convert it to a binary string first. 9238 * @property {Object} httpHeaders - Basic authentication headers. 9239 * @property {boolean} withCredentials - Indicates whether or not cross-site 9240 * Access-Control requests should be made using credentials such as cookies 9241 * or authorization headers. The default is false. 9242 * @property {string} password - For decrypting password-protected PDFs. 9243 * @property {TypedArray} initialData - A typed array with the first portion or 9244 * all of the pdf data. Used by the extension since some data is already 9245 * loaded before the switch to range requests. 9246 * @property {number} length - The PDF file length. It's used for progress 9247 * reports and range requests operations. 9248 * @property {PDFDataRangeTransport} range 9249 * @property {number} rangeChunkSize - Optional parameter to specify 9250 * maximum number of bytes fetched per range request. The default value is 9251 * 2^16 = 65536. 9252 * @property {PDFWorker} worker - The worker that will be used for the loading 9253 * and parsing of the PDF data. 9254 */ 9255 9256 /** 9257 * @typedef {Object} PDFDocumentStats 9258 * @property {Array} streamTypes - Used stream types in the document (an item 9259 * is set to true if specific stream ID was used in the document). 9260 * @property {Array} fontTypes - Used font type in the document (an item is set 9261 * to true if specific font ID was used in the document). 9262 */ 9263 9264 /** 9265 * This is the main entry point for loading a PDF and interacting with it. 9266 * NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR) 9267 * is used, which means it must follow the same origin rules that any XHR does 9268 * e.g. No cross domain requests without CORS. 9269 * 9270 * @param {string|TypedArray|DocumentInitParameters|PDFDataRangeTransport} src 9271 * Can be a url to where a PDF is located, a typed array (Uint8Array) 9272 * already populated with data or parameter object. 9273 * 9274 * @param {PDFDataRangeTransport} pdfDataRangeTransport (deprecated) It is used 9275 * if you want to manually serve range requests for data in the PDF. 9276 * 9277 * @param {function} passwordCallback (deprecated) It is used to request a 9278 * password if wrong or no password was provided. The callback receives two 9279 * parameters: function that needs to be called with new password and reason 9280 * (see {PasswordResponses}). 9281 * 9282 * @param {function} progressCallback (deprecated) It is used to be able to 9283 * monitor the loading progress of the PDF file (necessary to implement e.g. 9284 * a loading bar). The callback receives an {Object} with the properties: 9285 * {number} loaded and {number} total. 9286 * 9287 * @return {PDFDocumentLoadingTask} 9288 */ 9289 function getDocument(src, pdfDataRangeTransport, passwordCallback, progressCallback) { 9290 var task = new PDFDocumentLoadingTask(); 9291
9292 // Support of the obsolete arguments (for compatibility with API v1.0) 9293 if (arguments.length > 1) { 9294 deprecated( 9295 'getDocument is called with pdfDataRangeTransport, ' + 'passwordCallback or progressCallback argument' 9296 ); 9297 } 9298 if (pdfDataRangeTransport) { 9299 if (!(pdfDataRangeTransport instanceof PDFDataRangeTransport)) { 9300 // Not a PDFDataRangeTransport instance, trying to add missing properties. 9301 pdfDataRangeTransport = Object.create(pdfDataRangeTransport); 9302 pdfDataRangeTransport.length = src.length; 9303 pdfDataRangeTransport.initialData = src.initialData; 9304 if (!pdfDataRangeTransport.abort) { 9305 pdfDataRangeTransport.abort = function () {}; 9306 } 9307 } 9308 src = Object.create(src); 9309 src.range = pdfDataRangeTransport; 9310 } 9311 task.onPassword = passwordCallback || null; 9312 task.onProgress = progressCallback || null; 9313 9314 var source; 9315 if (typeof src === 'string') { 9316 source = { url: src }; 9317 } else if (isArrayBuffer(src)) { 9318 source = { data: src }; 9319 } else if (src instanceof PDFDataRangeTransport) { 9320 source = { range: src }; 9321 } else { 9322 if (typeof src !== 'object') { 9323 error('Invalid parameter in getDocument, need either Uint8Array, ' + 'string or a parameter object'); 9324 } 9325 if (!src.url && !src.data && !src.range) { 9326 error('Invalid parameter object: need either .data, .range or .url'); 9327 } 9328 9329 source = src; 9330 } 9331 9332 var params = {}; 9333 var rangeTransport = null; 9334 var worker = null; 9335 for (var key in source) { 9336 if (key === 'url' && typeof window !== 'undefined') { 9337 // The full path is required in the 'url' field. 9338 params[key] = new URL(source[key], window.location).href; 9339 continue; 9340 } else if (key === 'range') { 9341 rangeTransport = source[key]; 9342 continue; 9343 } else if (key === 'worker') { 9344 worker = source[key]; 9345 continue; 9346 } else if (key === 'data' && !(source[key] instanceof Uint8Array)) { 9347 // Converting string or array-like data to Uint8Array. 9348 var pdfBytes = source[key]; 9349 if (typeof pdfBytes === 'string') { 9350 params[key] = stringToBytes(pdfBytes); 9351 } else if (typeof pdfBytes === 'object' && pdfBytes !== null && !isNaN(pdfBytes.length)) { 9352 params[key] = new Uint8Array(pdfBytes); 9353 } else if (isArrayBuffer(pdfBytes)) { 9354 params[key] = new Uint8Array(pdfBytes); 9355 } else { 9356 error( 9357 'Invalid PDF binary data: either typed array, string or ' + 9358 'array-like object is expected in the data property.' 9359 ); 9360 } 9361 continue; 9362 } 9363 params[key] = source[key]; 9364 } 9365 9366 params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE; 9367 9368 if (!worker) { 9369 // Worker was not provided -- creating and owning our own. 9370 worker = new PDFWorker(); 9371 task._worker = worker; 9372 } 9373 var docId = task.docId; 9374 worker.promise 9375 .then(function () { 9376 if (task.destroyed) { 9377 throw new Error('Loading aborted'); 9378 } 9379 return _fetchDocument(worker, params, rangeTransport, docId).then(function (workerId) { 9380 if (task.destroyed) { 9381 throw new Error('Loading aborted'); 9382 } 9383 var messageHandler = new MessageHandler(docId, workerId, worker.port); 9384 var transport = new WorkerTransport(messageHandler, task, rangeTransport); 9385 task._transport = transport; 9386 messageHandler.send('Ready', null); 9387 }); 9388 }) 9389 .catch(task._capability.reject); 9390 9391 return task; 9392 } 9393 9394 /** 9395 * Starts fetching of specified PDF document/data. 9396 * @param {PDFWorker} worker 9397 * @param {Object} source 9398 * @param {PDFDataRangeTransport} pdfDataRangeTransport 9399 * @param {string} docId Unique document id, used as MessageHandler id. 9400 * @returns {Promise} The promise, which is resolved when worker id of 9401 * MessageHandler is known. 9402 * @private 9403 */ 9404 function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { 9405 if (worker.destroyed) { 9406 return Promise.reject(new Error('Worker was destroyed')); 9407 } 9408 9409 source.disableAutoFetch = getDefaultSetting('disableAutoFetch'); 9410 source.disableStream = getDefaultSetting('disableStream'); 9411 source.chunkedViewerLoading = !!pdfDataRangeTransport; 9412 if (pdfDataRangeTransport) { 9413 source.length = pdfDataRangeTransport.length; 9414 source.initialData = pdfDataRangeTransport.initialData; 9415 } 9416 return worker.messageHandler
9417 .sendWithPromise('GetDocRequest', { 9418 docId: docId, 9419 source: source, 9420 disableRange: getDefaultSetting('disableRange'), 9421 maxImageSize: getDefaultSetting('maxImageSize'), 9422 cMapUrl: getDefaultSetting('cMapUrl'), 9423 cMapPacked: getDefaultSetting('cMapPacked'), 9424 disableFontFace: getDefaultSetting('disableFontFace'), 9425 disableCreateObjectURL: getDefaultSetting('disableCreateObjectURL'), 9426 postMessageTransfers: getDefaultSetting('postMessageTransfers') && !isPostMessageTransfersDisabled, 9427 }) 9428 .then(function (workerId) { 9429 if (worker.destroyed) { 9430 throw new Error('Worker was destroyed'); 9431 } 9432 return workerId; 9433 }); 9434 } 9435 9436 /** 9437 * PDF document loading operation. 9438 * @class 9439 * @alias PDFDocumentLoadingTask 9440 */ 9441 var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() { 9442 var nextDocumentId = 0; 9443 9444 /** @constructs PDFDocumentLoadingTask */ 9445 function PDFDocumentLoadingTask() { 9446 this._capability = createPromiseCapability(); 9447 this._transport = null; 9448 this._worker = null; 9449 9450 /** 9451 * Unique document loading task id -- used in MessageHandlers. 9452 * @type {string} 9453 */ 9454 this.docId = 'd' + nextDocumentId++; 9455 9456 /** 9457 * Shows if loading task is destroyed. 9458 * @type {boolean} 9459 */ 9460 this.destroyed = false; 9461 9462 /** 9463 * Callback to request a password if wrong or no password was provided. 9464 * The callback receives two parameters: function that needs to be called 9465 * with new password and reason (see {PasswordResponses}). 9466 */ 9467 this.onPassword = null; 9468 9469 /** 9470 * Callback to be able to monitor the loading progress of the PDF file 9471 * (necessary to implement e.g. a loading bar). The callback receives 9472 * an {Object} with the properties: {number} loaded and {number} total. 9473 */ 9474 this.onProgress = null; 9475 9476 /** 9477 * Callback to when unsupported feature is used. The callback receives 9478 * an {UNSUPPORTED_FEATURES} argument. 9479 */ 9480 this.onUnsupportedFeature = null; 9481 } 9482 9483 PDFDocumentLoadingTask.prototype = /** @lends PDFDocumentLoadingTask.prototype */ { 9484 /** 9485 * @return {Promise} 9486 */ 9487 get promise() { 9488 return this._capability.promise; 9489 }, 9490 9491 /** 9492 * Aborts all network requests and destroys worker. 9493 * @return {Promise} A promise that is resolved after destruction activity 9494 * is completed. 9495 */ 9496 destroy: function () { 9497 this.destroyed = true; 9498 9499 var transportDestroyed = !this._transport ? Promise.resolve() : this._transport.destroy(); 9500 return transportDestroyed.then( 9501 function () { 9502 this._transport = null; 9503 if (this._worker) { 9504 this._worker.destroy(); 9505 this._worker = null; 9506 } 9507 }.bind(this) 9508 ); 9509 }, 9510 9511 /** 9512 * Registers callbacks to indicate the document loading completion. 9513 * 9514 * @param {function} onFulfilled The callback for the loading completion. 9515 * @param {function} onRejected The callback for the loading failure. 9516 * @return {Promise} A promise that is resolved after the onFulfilled or 9517 * onRejected callback. 9518 */ 9519 then: function PDFDocumentLoadingTask_then(onFulfilled, onRejected) { 9520 return this.promise.then.apply(this.promise, arguments); 9521 }, 9522 }; 9523 9524 return PDFDocumentLoadingTask; 9525 })(); 9526 9527 /** 9528 * Abstract class to support range requests file loading. 9529 * @class 9530 * @alias PDFDataRangeTransport 9531 * @param {number} length 9532 * @param {Uint8Array} initialData 9533 */ 9534 var PDFDataRangeTransport = (function pdfDataRangeTransportClosure() { 9535 function PDFDataRangeTransport(length, initialData) { 9536 this.length = length; 9537 this.initialData = initialData; 9538 9539 this._rangeListeners = []; 9540 this._progressListeners = []; 9541 this._progressiveReadListeners = []; 9542 this._readyCapability = createPromiseCapability(); 9543 } 9544 9545 PDFDataRangeTransport.prototype = /** @lends PDFDataRangeTransport.prototype */ { 9546 addRangeListener: function PDFDataRangeTransport_addRangeListener(listener) { 9547 this._rangeListeners.push(listener); 9548 }, 9549 9550 addProgressListener: function PDFDataRangeTransport_addProgressListener(listener) { 9551 this._progressListeners.push(listener); 9552 }, 9553 9554 addProgressiveReadListener: function PDFDataRangeTransport_addProgressiveReadListener(listener) { 9555 this._progressiveReadListeners.push(listener); 9556 }, 9557 9558 onDataRange: function PDFDataRangeTransport_onDataRange(begin, chunk) { 9559 var listeners = this._rangeListeners; 9560 for (var i = 0, n = listeners.length; i < n; ++i) { 9561 listeners[i](begin, chunk); 9562 } 9563 }, 9564 9565 onDataProgress: function PDFDataRangeTransport_onDataProgress(loaded) { 9566 this._readyCapability.promise.then( 9567 function () { 9568 var listeners = this._progressListeners; 9569 for (var i = 0, n = listeners.length; i < n; ++i) { 9570 listeners[i](loaded); 9571 } 9572 }.bind(this) 9573 ); 9574 }, 9575 9576 onDataProgressiveRead: function PDFDataRangeTransport_onDataProgress(chunk) { 9577 this._readyCapability.promise.then( 9578 function () { 9579 var listeners = this._progressiveReadListeners; 9580 for (var i = 0, n = listeners.length; i < n; ++i) { 9581 listeners[i](chunk); 9582 } 9583 }.bind(this) 9584 ); 9585 }, 9586 9587 transportReady: function PDFDataRangeTransport_transportReady() { 9588 this._readyCapability.resolve(); 9589 }, 9590 9591 requestDataRange: function PDFDataRangeTransport_requestDataRange(begin, end) { 9592 throw new Error('Abstract method PDFDataRangeTransport.requestDataRange'); 9593 }, 9594 9595 abort: function PDFDataRangeTransport_abort() {}, 9596 };
9597 return PDFDataRangeTransport; 9598 })(); 9599 9600 /** 9601 * Proxy to a PDFDocument in the worker thread. Also, contains commonly used 9602 * properties that can be read synchronously. 9603 * @class 9604 * @alias PDFDocumentProxy 9605 */ 9606 var PDFDocumentProxy = (function PDFDocumentProxyClosure() { 9607 function PDFDocumentProxy(pdfInfo, transport, loadingTask) { 9608 this.pdfInfo = pdfInfo; 9609 this.transport = transport; 9610 this.loadingTask = loadingTask; 9611 } 9612 9613 PDFDocumentProxy.prototype = /** @lends PDFDocumentProxy.prototype */ { 9614 /** 9615 * @return {number} Total number of pages the PDF contains. 9616 */ 9617 get numPages() { 9618 return this.pdfInfo.numPages; 9619 }, 9620 /** 9621 * @return {string} A unique ID to identify a PDF. Not guaranteed to be 9622 * unique. 9623 */ 9624 get fingerprint() { 9625 return this.pdfInfo.fingerprint; 9626 }, 9627 /** 9628 * @param {number} pageNumber The page number to get. The first page is 1. 9629 * @return {Promise} A promise that is resolved with a {@link PDFPageProxy} 9630 * object. 9631 */ 9632 getPage: function PDFDocumentProxy_getPage(pageNumber) { 9633 return this.transport.getPage(pageNumber); 9634 }, 9635 /** 9636 * @param {{num: number, gen: number}} ref The page reference. Must have 9637 * the 'num' and 'gen' properties. 9638 * @return {Promise} A promise that is resolved with the page index that is 9639 * associated with the reference. 9640 */ 9641 getPageIndex: function PDFDocumentProxy_getPageIndex(ref) { 9642 return this.transport.getPageIndex(ref); 9643 }, 9644 /** 9645 * @return {Promise} A promise that is resolved with a lookup table for 9646 * mapping named destinations to reference numbers. 9647 * 9648 * This can be slow for large documents: use getDestination instead 9649 */ 9650 getDestinations: function PDFDocumentProxy_getDestinations() { 9651 return this.transport.getDestinations(); 9652 }, 9653 /** 9654 * @param {string} id The named destination to get. 9655 * @return {Promise} A promise that is resolved with all information 9656 * of the given named destination. 9657 */ 9658 getDestination: function PDFDocumentProxy_getDestination(id) { 9659 return this.transport.getDestination(id); 9660 }, 9661 /** 9662 * @return {Promise} A promise that is resolved with: 9663 * an Array containing the pageLabels that correspond to the pageIndexes, 9664 * or `null` when no pageLabels are present in the PDF file. 9665 */ 9666 getPageLabels: function PDFDocumentProxy_getPageLabels() { 9667 return this.transport.getPageLabels(); 9668 }, 9669 /** 9670 * @return {Promise} A promise that is resolved with a lookup table for 9671 * mapping named attachments to their content. 9672 */ 9673 getAttachments: function PDFDocumentProxy_getAttachments() { 9674 return this.transport.getAttachments(); 9675 }, 9676 /** 9677 * @return {Promise} A promise that is resolved with an array of all the 9678 * JavaScript strings in the name tree. 9679 */ 9680 getJavaScript: function PDFDocumentProxy_getJavaScript() { 9681 return this.transport.getJavaScript(); 9682 }, 9683 /** 9684 * @return {Promise} A promise that is resolved with an {Array} that is a 9685 * tree outline (if it has one) of the PDF. The tree is in the format of: 9686 * [ 9687 * { 9688 * title: string, 9689 * bold: boolean, 9690 * italic: boolean, 9691 * color: rgb Uint8Array, 9692 * dest: dest obj, 9693 * url: string, 9694 * items: array of more items like this 9695 * }, 9696 * ... 9697 * ]. 9698 */ 9699 getOutline: function PDFDocumentProxy_getOutline() { 9700 return this.transport.getOutline(); 9701 }, 9702 /** 9703 * @return {Promise} A promise that is resolved with an {Object} that has 9704 * info and metadata properties. Info is an {Object} filled with anything 9705 * available in the information dictionary and similarly metadata is a 9706 * {Metadata} object with information from the metadata section of the PDF. 9707 */ 9708 getMetadata: function PDFDocumentProxy_getMetadata() { 9709 return this.transport.getMetadata(); 9710 }, 9711 /** 9712 * @return {Promise} A promise that is resolved with a TypedArray that has 9713 * the raw data from the PDF. 9714 */ 9715 getData: function PDFDocumentProxy_getData() { 9716 return this.transport.getData(); 9717 }, 9718 /** 9719 * @return {Promise} A promise that is resolved when the document's data 9720 * is loaded. It is resolved with an {Object} that contains the length 9721 * property that indicates size of the PDF data in bytes. 9722 */ 9723 getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() { 9724 return this.transport.downloadInfoCapability.promise; 9725 }, 9726 /** 9727 * @return {Promise} A promise this is resolved with current stats about 9728 * document structures (see {@link PDFDocumentStats}). 9729 */ 9730 getStats: function PDFDocumentProxy_getStats() { 9731 return this.transport.getStats(); 9732 }, 9733 /** 9734 * Cleans up resources allocated by the document, e.g. created @font-face. 9735 */ 9736 cleanup: function PDFDocumentProxy_cleanup() { 9737 this.transport.startCleanup(); 9738 }, 9739 /** 9740 * Destroys current document instance and terminates worker. 9741 */ 9742 destroy: function PDFDocumentProxy_destroy() { 9743 return this.loadingTask.destroy(); 9744 }, 9745 }; 9746 return PDFDocumentProxy; 9747 })(); 9748 9749 /** 9750 * Page getTextContent parameters. 9751 * 9752 * @typedef {Object} getTextContentParameters 9753 * @param {boolean} normalizeWhitespace - replaces all occurrences of 9754 * whitespace with standard spaces (0x20). The default value is `false`. 9755 * @param {boolean} disableCombineTextItems - do not attempt to combine 9756 * same line {@link TextItem}'s. The default value is `false`. 9757 */ 9758 9759 /** 9760 * Page text content. 9761 * 9762 * @typedef {Object} TextContent 9763 * @property {array} items - array of {@link TextItem} 9764 * @property {Object} styles - {@link TextStyles} objects, indexed by font 9765 * name. 9766 */ 9767 9768 /** 9769 * Page text content part. 9770 * 9771 * @typedef {Object} TextItem 9772 * @property {string} str - text content. 9773 * @property {string} dir - text direction: 'ttb', 'ltr' or 'rtl'. 9774 * @property {array} transform - transformation matrix. 9775 * @property {number} width - width in device space. 9776 * @property {number} height - height in device space. 9777 * @property {string} fontName - font name used by pdf.js for converted font. 9778 */ 9779 9780 /** 9781 * Text style. 9782 * 9783 * @typedef {Object} TextStyle 9784 * @property {number} ascent - font ascent. 9785 * @property {number} descent - font descent. 9786 * @property {boolean} vertical - text is in vertical mode. 9787 * @property {string} fontFamily - possible font family 9788 */ 9789 9790 /** 9791 * Page annotation parameters. 9792 * 9793 * @typedef {Object} GetAnnotationsParameters 9794 * @param {string} intent - Determines the annotations that will be fetched, 9795 * can be either 'display' (viewable annotations) or 'print' 9796 * (printable annotations). 9797 * If the parameter is omitted, all annotations are fetched. 9798 */ 9799 9800 /** 9801 * Page render parameters. 9802 * 9803 * @typedef {Object} RenderParameters 9804 * @property {Object} canvasContext - A 2D context of a DOM Canvas object. 9805 * @property {PageViewport} viewport - Rendering viewport obtained by 9806 * calling of PDFPage.getViewport method. 9807 * @property {string} intent - Rendering intent, can be 'display' or 'print' 9808 * (default value is 'display'). 9809 * @property {boolean} renderInteractiveForms - (optional) Whether or not 9810 * interactive form elements are rendered in the display 9811 * layer. If so, we do not render them on canvas as well. 9812 * @property {Array} transform - (optional) Additional transform, applied 9813 * just before viewport transform. 9814 * @property {Object} imageLayer - (optional) An object that has beginLayout, 9815 * endLayout and appendImage functions. 9816 * @property {function} continueCallback - (deprecated) A function that will be 9817 * called each time the rendering is paused. To continue 9818 * rendering call the function that is the first argument 9819 * to the callback. 9820 */ 9821 9822 /** 9823 * PDF page operator list. 9824 * 9825 * @typedef {Object} PDFOperatorList 9826 * @property {Array} fnArray - Array containing the operator functions. 9827 * @property {Array} argsArray - Array containing the arguments of the 9828 * functions. 9829 */ 9830 9831 /** 9832 * Proxy to a PDFPage in the worker thread. 9833 * @class 9834 * @alias PDFPageProxy 9835 */ 9836 var PDFPageProxy = (function PDFPageProxyClosure() { 9837 function PDFPageProxy(pageIndex, pageInfo, transport) { 9838 this.pageIndex = pageIndex; 9839 this.pageInfo = pageInfo; 9840 this.transport = transport; 9841 this.stats = new StatTimer(); 9842 this.stats.enabled = getDefaultSetting('enableStats'); 9843 this.commonObjs = transport.commonObjs; 9844 this.objs = new PDFObjects(); 9845 this.cleanupAfterRender = false;
9846 this.pendingCleanup = false; 9847 this.intentStates = Object.create(null); 9848 this.destroyed = false; 9849 } 9850 9851 PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ { 9852 /** 9853 * @return {number} Page number of the page. First page is 1. 9854 */ 9855 get pageNumber() { 9856 return this.pageIndex + 1; 9857 }, 9858 /** 9859 * @return {number} The number of degrees the page is rotated clockwise. 9860 */ 9861 get rotate() { 9862 return this.pageInfo.rotate; 9863 }, 9864 /** 9865 * @return {Object} The reference that points to this page. It has 'num' and 9866 * 'gen' properties. 9867 */ 9868 get ref() { 9869 return this.pageInfo.ref; 9870 }, 9871 /** 9872 * @return {Array} An array of the visible portion of the PDF page in the 9873 * user space units - [x1, y1, x2, y2]. 9874 */ 9875 get view() { 9876 return this.pageInfo.view; 9877 }, 9878 /** 9879 * @param {number} scale The desired scale of the viewport. 9880 * @param {number} rotate Degrees to rotate the viewport. If omitted this 9881 * defaults to the page rotation. 9882 * @return {PageViewport} Contains 'width' and 'height' properties 9883 * along with transforms required for rendering. 9884 */ 9885 getViewport: function PDFPageProxy_getViewport(scale, rotate) { 9886 if (arguments.length < 2) { 9887 rotate = this.rotate; 9888 } 9889 return new PageViewport(this.view, scale, rotate, 0, 0); 9890 }, 9891 /** 9892 * @param {GetAnnotationsParameters} params - Annotation parameters. 9893 * @return {Promise} A promise that is resolved with an {Array} of the 9894 * annotation objects. 9895 */ 9896 getAnnotations: function PDFPageProxy_getAnnotations(params) { 9897 var intent = (params && params.intent) || null; 9898 9899 if (!this.annotationsPromise || this.annotationsIntent !== intent) { 9900 this.annotationsPromise = this.transport.getAnnotations(this.pageIndex, intent); 9901 this.annotationsIntent = intent; 9902 } 9903 return this.annotationsPromise; 9904 }, 9905 /** 9906 * Begins the process of rendering a page to the desired context. 9907 * @param {RenderParameters} params Page render parameters. 9908 * @return {RenderTask} An object that contains the promise, which 9909 * is resolved when the page finishes rendering. 9910 */ 9911 render: function PDFPageProxy_render(params) { 9912 var stats = this.stats; 9913 stats.time('Overall'); 9914 9915 // If there was a pending destroy cancel it so no cleanup happens during 9916 // this call to render. 9917 this.pendingCleanup = false; 9918 9919 var renderingIntent = params.intent === 'print' ? 'print' : 'display'; 9920 var renderInteractiveForms = params.renderInteractiveForms === true ? true : /* Default */ false; 9921 9922 if (!this.intentStates[renderingIntent]) { 9923 this.intentStates[renderingIntent] = Object.create(null); 9924 } 9925 var intentState = this.intentStates[renderingIntent]; 9926 9927 // If there's no displayReadyCapability yet, then the operatorList 9928 // was never requested before. Make the request and create the promise. 9929 if (!intentState.displayReadyCapability) { 9930 intentState.receivingOperatorList = true; 9931 intentState.displayReadyCapability = createPromiseCapability(); 9932 intentState.operatorList = { 9933 fnArray: [], 9934 argsArray: [], 9935 lastChunk: false, 9936 }; 9937 9938 this.stats.time('Page Request'); 9939 this.transport.messageHandler.send('RenderPageRequest', { 9940 pageIndex: this.pageNumber - 1, 9941 intent: renderingIntent, 9942 renderInteractiveForms: renderInteractiveForms, 9943 }); 9944 } 9945 9946 var internalRenderTask = new InternalRenderTask( 9947 complete, 9948 params, 9949 this.objs, 9950 this.commonObjs, 9951 intentState.operatorList, 9952 this.pageNumber 9953 ); 9954 internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print'; 9955 if (!intentState.renderTasks) { 9956 intentState.renderTasks = []; 9957 } 9958 intentState.renderTasks.push(internalRenderTask); 9959 var renderTask = internalRenderTask.task; 9960 9961 // Obsolete parameter support 9962 if (params.continueCallback) { 9963 deprecated('render is used with continueCallback parameter'); 9964 renderTask.onContinue = params.continueCallback; 9965 } 9966 9967 var self = this; 9968 intentState.displayReadyCapability.promise.then( 9969 function pageDisplayReadyPromise(transparency) { 9970 if (self.pendingCleanup) { 9971 complete(); 9972 return; 9973 } 9974 stats.time('Rendering');
9975 internalRenderTask.initializeGraphics(transparency); 9976 internalRenderTask.operatorListChanged(); 9977 }, 9978 function pageDisplayReadPromiseError(reason) { 9979 complete(reason); 9980 } 9981 ); 9982 9983 function complete(error) { 9984 var i = intentState.renderTasks.indexOf(internalRenderTask); 9985 if (i >= 0) { 9986 intentState.renderTasks.splice(i, 1); 9987 } 9988 9989 if (self.cleanupAfterRender) { 9990 self.pendingCleanup = true; 9991 } 9992 self._tryCleanup(); 9993 9994 if (error) { 9995 internalRenderTask.capability.reject(error); 9996 } else { 9997 internalRenderTask.capability.resolve(); 9998 } 9999 stats.timeEnd('Rendering'); 10000 stats.timeEnd('Overall'); 10001 } 10002 10003 return renderTask; 10004 }, 10005 10006 /** 10007 * @return {Promise} A promise resolved with an {@link PDFOperatorList} 10008 * object that represents page's operator list. 10009 */ 10010 getOperatorList: function PDFPageProxy_getOperatorList() { 10011 function operatorListChanged() { 10012 if (intentState.operatorList.lastChunk) { 10013 intentState.opListReadCapability.resolve(intentState.operatorList); 10014 10015 var i = intentState.renderTasks.indexOf(opListTask); 10016 if (i >= 0) { 10017 intentState.renderTasks.splice(i, 1); 10018 } 10019 } 10020 } 10021 10022 var renderingIntent = 'oplist'; 10023 if (!this.intentStates[renderingIntent]) { 10024 this.intentStates[renderingIntent] = Object.create(null); 10025 } 10026 var intentState = this.intentStates[renderingIntent]; 10027 var opListTask; 10028 10029 if (!intentState.opListReadCapability) { 10030 opListTask = {}; 10031 opListTask.operatorListChanged = operatorListChanged; 10032 intentState.receivingOperatorList = true; 10033 intentState.opListReadCapability = createPromiseCapability(); 10034 intentState.renderTasks = []; 10035 intentState.renderTasks.push(opListTask); 10036 intentState.operatorList = { 10037 fnArray: [], 10038 argsArray: [], 10039 lastChunk: false, 10040 }; 10041 10042 this.transport.messageHandler.send('RenderPageRequest', { 10043 pageIndex: this.pageIndex, 10044 intent: renderingIntent, 10045 }); 10046 } 10047 return intentState.opListReadCapability.promise; 10048 }, 10049 10050 /** 10051 * @param {getTextContentParameters} params - getTextContent parameters. 10052 * @return {Promise} That is resolved a {@link TextContent} 10053 * object that represent the page text content. 10054 */ 10055 getTextContent: function PDFPageProxy_getTextContent(params) { 10056 return this.transport.messageHandler.sendWithPromise('GetTextContent', { 10057 pageIndex: this.pageNumber - 1, 10058 normalizeWhitespace: params && params.normalizeWhitespace === true ? true : /* Default */ false, 10059 combineTextItems: params && params.disableCombineTextItems === true ? false : /* Default */ true, 10060 }); 10061 }, 10062 10063 /** 10064 * Destroys page object. 10065 */ 10066 _destroy: function PDFPageProxy_destroy() { 10067 this.destroyed = true; 10068 this.transport.pageCache[this.pageIndex] = null; 10069 10070 var waitOn = []; 10071 Object.keys(this.intentStates).forEach(function (intent) { 10072 if (intent === 'oplist') { 10073 // Avoid errors below, since the renderTasks are just stubs. 10074 return; 10075 } 10076 var intentState = this.intentStates[intent]; 10077 intentState.renderTasks.forEach(function (renderTask) { 10078 var renderCompleted = renderTask.capability.promise.catch(function () {}); // ignoring failures 10079 waitOn.push(renderCompleted); 10080 renderTask.cancel(); 10081 }); 10082 }, this); 10083 this.objs.clear();
10084 this.annotationsPromise = null; 10085 this.pendingCleanup = false; 10086 return Promise.all(waitOn); 10087 }, 10088 10089 /** 10090 * Cleans up resources allocated by the page. (deprecated) 10091 */ 10092 destroy: function () { 10093 deprecated('page destroy method, use cleanup() instead'); 10094 this.cleanup(); 10095 }, 10096 10097 /** 10098 * Cleans up resources allocated by the page. 10099 */ 10100 cleanup: function PDFPageProxy_cleanup() { 10101 this.pendingCleanup = true; 10102 this._tryCleanup(); 10103 }, 10104 /** 10105 * For internal use only. Attempts to clean up if rendering is in a state 10106 * where that's possible. 10107 * @ignore 10108 */ 10109 _tryCleanup: function PDFPageProxy_tryCleanup() { 10110 if ( 10111 !this.pendingCleanup || 10112 Object.keys(this.intentStates).some(function (intent) { 10113 var intentState = this.intentStates[intent]; 10114 return intentState.renderTasks.length !== 0 || intentState.receivingOperatorList; 10115 }, this) 10116 ) { 10117 return; 10118 } 10119 10120 Object.keys(this.intentStates).forEach(function (intent) { 10121 delete this.intentStates[intent]; 10122 }, this); 10123 this.objs.clear(); 10124 this.annotationsPromise = null; 10125 this.pendingCleanup = false; 10126 }, 10127 /** 10128 * For internal use only. 10129 * @ignore 10130 */ 10131 _startRenderPage: function PDFPageProxy_startRenderPage(transparency, intent) { 10132 var intentState = this.intentStates[intent]; 10133 // TODO Refactor RenderPageRequest to separate rendering 10134 // and operator list logic 10135 if (intentState.displayReadyCapability) { 10136 intentState.displayReadyCapability.resolve(transparency); 10137 } 10138 }, 10139 /** 10140 * For internal use only. 10141 * @ignore 10142 */ 10143 _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk, intent) { 10144 var intentState = this.intentStates[intent]; 10145 var i, ii; 10146 // Add the new chunk to the current operator list. 10147 for (i = 0, ii = operatorListChunk.length; i < ii; i++) { 10148 intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]); 10149 intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]); 10150 } 10151 intentState.operatorList.lastChunk = operatorListChunk.lastChunk; 10152 10153 // Notify all the rendering tasks there are more operators to be consumed. 10154 for (i = 0; i < intentState.renderTasks.length; i++) { 10155 intentState.renderTasks[i].operatorListChanged(); 10156 } 10157 10158 if (operatorListChunk.lastChunk) { 10159 intentState.receivingOperatorList = false; 10160 this._tryCleanup(); 10161 } 10162 }, 10163 }; 10164 return PDFPageProxy; 10165 })(); 10166 10167 /** 10168 * PDF.js web worker abstraction, it controls instantiation of PDF documents and 10169 * WorkerTransport for them. If creation of a web worker is not possible, 10170 * a "fake" worker will be used instead. 10171 * @class 10172 */ 10173 var PDFWorker = (function PDFWorkerClosure() { 10174 var nextFakeWorkerId = 0; 10175 10176 function getWorkerSrc() { 10177 if (typeof workerSrc !== 'undefined') { 10178 return workerSrc; 10179 } 10180 if (getDefaultSetting('workerSrc')) { 10181 return getDefaultSetting('workerSrc'); 10182 } 10183 if (pdfjsFilePath) { 10184 return pdfjsFilePath.replace(/\.js$/i, '.worker.js'); 10185 } 10186 error('No PDFJS.workerSrc specified'); 10187 } 10188 10189 var fakeWorkerFilesLoadedCapability; 10190 10191 // Loads worker code into main thread. 10192 function setupFakeWorkerGlobal() { 10193 var WorkerMessageHandler; 10194 if (!fakeWorkerFilesLoadedCapability) { 10195 fakeWorkerFilesLoadedCapability = createPromiseCapability();
10196 // In the developer build load worker_loader which in turn loads all the 10197 // other files and resolves the promise. In production only the 10198 // pdf.worker.js file is needed. 10199 var loader = 10200 fakeWorkerFilesLoader || 10201 function (callback) { 10202 Util.loadScript(getWorkerSrc(), function () { 10203 callback(window.pdfjsDistBuildPdfWorker.WorkerMessageHandler); 10204 }); 10205 }; 10206 loader(fakeWorkerFilesLoadedCapability.resolve); 10207 } 10208 return fakeWorkerFilesLoadedCapability.promise; 10209 } 10210 10211 function FakeWorkerPort(defer) { 10212 this._listeners = []; 10213 this._defer = defer; 10214 this._deferred = Promise.resolve(undefined); 10215 } 10216 10217 FakeWorkerPort.prototype = { 10218 postMessage: function (obj, transfers) { 10219 function cloneValue(value) { 10220 // Trying to perform a structured clone close to the spec, including 10221 // transfers. 10222 if (typeof value !== 'object' || value === null) { 10223 return value; 10224 } 10225 if (cloned.has(value)) { 10226 // already cloned the object 10227 return cloned.get(value); 10228 } 10229 var result; 10230 var buffer; 10231 if ((buffer = value.buffer) && isArrayBuffer(buffer)) { 10232 // We found object with ArrayBuffer (typed array). 10233 var transferable = transfers && transfers.indexOf(buffer) >= 0; 10234 if (value === buffer) { 10235 // Special case when we are faking typed arrays in compatibility.js. 10236 result = value; 10237 } else if (transferable) { 10238 result = new value.constructor(buffer, value.byteOffset, value.byteLength); 10239 } else { 10240 result = new value.constructor(value); 10241 } 10242 cloned.set(value, result); 10243 return result; 10244 } 10245 result = isArray(value) ? [] : {}; 10246 cloned.set(value, result); // adding to cache now for cyclic references 10247 // Cloning all value and object properties, however ignoring properties 10248 // defined via getter. 10249 for (var i in value) { 10250 var desc, 10251 p = value; 10252 while (!(desc = Object.getOwnPropertyDescriptor(p, i))) { 10253 p = Object.getPrototypeOf(p); 10254 } 10255 if (typeof desc.value === 'undefined' || typeof desc.value === 'function') { 10256 continue; 10257 } 10258 result[i] = cloneValue(desc.value); 10259 } 10260 return result; 10261 } 10262 10263 if (!this._defer) { 10264 this._listeners.forEach(function (listener) { 10265 listener.call(this, { data: obj }); 10266 }, this); 10267 return; 10268 } 10269 10270 var cloned = new WeakMap(); 10271 var e = { data: cloneValue(obj) }; 10272 this._deferred.then( 10273 function () { 10274 this._listeners.forEach(function (listener) { 10275 listener.call(this, e); 10276 }, this); 10277 }.bind(this) 10278 ); 10279 }, 10280 addEventListener: function (name, listener) { 10281 this._listeners.push(listener); 10282 }, 10283 removeEventListener: function (name, listener) { 10284 var i = this._listeners.indexOf(listener); 10285 this._listeners.splice(i, 1); 10286 }, 10287 terminate: function () { 10288 this._listeners = []; 10289 }, 10290 }; 10291 10292 function createCDNWrapper(url) { 10293 // We will rely on blob URL's property to specify origin. 10294 // We want this function to fail in case if createObjectURL or Blob do not 10295 // exist or fail for some reason -- our Worker creation will fail anyway. 10296 var wrapper = "importScripts('" + url + "');"; 10297 return URL.createObjectURL(new Blob([wrapper])); 10298 } 10299 10300 function PDFWorker(name) { 10301 this.name = name; 10302 this.destroyed = false;
10303 10304 this._readyCapability = createPromiseCapability(); 10305 this._port = null; 10306 this._webWorker = null; 10307 this._messageHandler = null; 10308 this._initialize(); 10309 } 10310 10311 PDFWorker.prototype = /** @lends PDFWorker.prototype */ { 10312 get promise() { 10313 return this._readyCapability.promise; 10314 }, 10315 10316 get port() { 10317 return this._port; 10318 }, 10319 10320 get messageHandler() { 10321 return this._messageHandler; 10322 }, 10323 10324 _initialize: function PDFWorker_initialize() { 10325 // If worker support isn't disabled explicit and the browser has worker 10326 // support, create a new web worker and test if it/the browser fulfills 10327 // all requirements to run parts of pdf.js in a web worker. 10328 // Right now, the requirement is, that an Uint8Array is still an 10329 // Uint8Array as it arrives on the worker. (Chrome added this with v.15.) 10330 if (!isWorkerDisabled && !getDefaultSetting('disableWorker') && typeof Worker !== 'undefined') { 10331 var workerSrc = getWorkerSrc(); 10332 10333 try { 10334 // Wraps workerSrc path into blob URL, if the former does not belong 10335 // to the same origin. 10336 if (!isSameOrigin(window.location.href, workerSrc)) { 10337 workerSrc = createCDNWrapper(new URL(workerSrc, window.location).href); 10338 } 10339 // Some versions of FF can't create a worker on localhost, see: 10340 // https://bugzilla.mozilla.org/show_bug.cgi?id=683280 10341 var worker = new Worker(workerSrc); 10342 var messageHandler = new MessageHandler('main', 'worker', worker); 10343 var terminateEarly = function () { 10344 worker.removeEventListener('error', onWorkerError); 10345 messageHandler.destroy(); 10346 worker.terminate(); 10347 if (this.destroyed) { 10348 this._readyCapability.reject(new Error('Worker was destroyed')); 10349 } else { 10350 // Fall back to fake worker if the termination is caused by an 10351 // error (e.g. NetworkError / SecurityError). 10352 this._setupFakeWorker(); 10353 } 10354 }.bind(this); 10355 10356 var onWorkerError = function (event) { 10357 if (!this._webWorker) { 10358 // Worker failed to initialize due to an error. Clean up and fall 10359 // back to the fake worker. 10360 terminateEarly(); 10361 } 10362 }.bind(this); 10363 worker.addEventListener('error', onWorkerError); 10364 10365 messageHandler.on( 10366 'test', 10367 function PDFWorker_test(data) { 10368 worker.removeEventListener('error', onWorkerError); 10369 if (this.destroyed) { 10370 terminateEarly(); 10371 return; // worker was destroyed 10372 } 10373 var supportTypedArray = data && data.supportTypedArray; 10374 if (supportTypedArray) { 10375 this._messageHandler = messageHandler; 10376 this._port = worker; 10377 this._webWorker = worker; 10378 if (!data.supportTransfers) { 10379 isPostMessageTransfersDisabled = true; 10380 } 10381 this._readyCapability.resolve(); 10382 // Send global setting, e.g. verbosity level. 10383 messageHandler.send('configure', { 10384 verbosity: getVerbosityLevel(), 10385 }); 10386 } else { 10387 this._setupFakeWorker(); 10388 messageHandler.destroy(); 10389 worker.terminate(); 10390 } 10391 }.bind(this) 10392 ); 10393 10394 messageHandler.on('console_log', function (data) { 10395 console.log.apply(console, data); 10396 }); 10397 messageHandler.on('console_error', function (data) { 10398 console.error.apply(console, data); 10399 }); 10400 10401 messageHandler.on( 10402 'ready', 10403 function (data) { 10404 worker.removeEventListener('error', onWorkerError); 10405 if (this.destroyed) { 10406 terminateEarly(); 10407 return; // worker was destroyed 10408 } 10409 try { 10410 sendTest(); 10411 } catch (e) { 10412 // We need fallback to a faked worker. 10413 this._setupFakeWorker(); 10414 } 10415 }.bind(this) 10416 ); 10417 10418 var sendTest = function () { 10419 var postMessageTransfers = 10420 getDefaultSetting('postMessageTransfers') && !isPostMessageTransfersDisabled; 10421 var testObj = new Uint8Array([postMessageTransfers ? 255 : 0]); 10422 // Some versions of Opera throw a DATA_CLONE_ERR on serializing the 10423 // typed array. Also, checking if we can use transfers. 10424 try { 10425 messageHandler.send('test', testObj, [testObj.buffer]); 10426 } catch (ex) { 10427 info('Cannot use postMessage transfers'); 10428 testObj[0] = 0; 10429 messageHandler.send('test', testObj); 10430 } 10431 }; 10432 10433 // It might take time for worker to initialize (especially when AMD 10434 // loader is used). We will try to send test immediately, and then 10435 // when 'ready' message will arrive. The worker shall process only 10436 // first received 'test'. 10437 sendTest(); 10438 return; 10439 } catch (e) { 10440 info('The worker has been disabled.'); 10441 } 10442 } 10443 // Either workers are disabled, not supported or have thrown an exception. 10444 // Thus, we fallback to a faked worker. 10445 this._setupFakeWorker(); 10446 }, 10447 10448 _setupFakeWorker: function PDFWorker_setupFakeWorker() { 10449 if (!isWorkerDisabled && !getDefaultSetting('disableWorker')) { 10450 warn('Setting up fake worker.'); 10451 isWorkerDisabled = true; 10452 } 10453 10454 setupFakeWorkerGlobal().then( 10455 function (WorkerMessageHandler) { 10456 if (this.destroyed) { 10457 this._readyCapability.reject(new Error('Worker was destroyed')); 10458 return; 10459 } 10460 10461 // We cannot turn on proper fake port simulation (this includes 10462 // structured cloning) when typed arrays are not supported. Relying 10463 // on a chance that messages will be sent in proper order. 10464 var isTypedArraysPresent = Uint8Array !== Float32Array; 10465 var port = new FakeWorkerPort(isTypedArraysPresent); 10466 this._port = port;
10467 10468 // All fake workers use the same port, making id unique. 10469 var id = 'fake' + nextFakeWorkerId++; 10470 10471 // If the main thread is our worker, setup the handling for the 10472 // messages -- the main thread sends to it self. 10473 var workerHandler = new MessageHandler(id + '_worker', id, port); 10474 WorkerMessageHandler.setup(workerHandler, port); 10475 10476 var messageHandler = new MessageHandler(id, id + '_worker', port); 10477 this._messageHandler = messageHandler; 10478 this._readyCapability.resolve(); 10479 }.bind(this) 10480 ); 10481 }, 10482 10483 /** 10484 * Destroys the worker instance. 10485 */ 10486 destroy: function PDFWorker_destroy() { 10487 this.destroyed = true; 10488 if (this._webWorker) { 10489 // We need to terminate only web worker created resource. 10490 this._webWorker.terminate(); 10491 this._webWorker = null; 10492 } 10493 this._port = null; 10494 if (this._messageHandler) { 10495 this._messageHandler.destroy(); 10496 this._messageHandler = null; 10497 } 10498 }, 10499 }; 10500 10501 return PDFWorker; 10502 })(); 10503 10504 /** 10505 * For internal use only. 10506 * @ignore 10507 */ 10508 var WorkerTransport = (function WorkerTransportClosure() { 10509 function WorkerTransport(messageHandler, loadingTask, pdfDataRangeTransport) { 10510 this.messageHandler = messageHandler; 10511 this.loadingTask = loadingTask; 10512 this.pdfDataRangeTransport = pdfDataRangeTransport; 10513 this.commonObjs = new PDFObjects(); 10514 this.fontLoader = new FontLoader(loadingTask.docId); 10515 10516 this.destroyed = false; 10517 this.destroyCapability = null; 10518 10519 this.pageCache = []; 10520 this.pagePromises = []; 10521 this.downloadInfoCapability = createPromiseCapability(); 10522 10523 this.setupMessageHandler(); 10524 } 10525 10526 WorkerTransport.prototype = { 10527 destroy: function WorkerTransport_destroy() { 10528 if (this.destroyCapability) { 10529 return this.destroyCapability.promise; 10530 } 10531 10532 this.destroyed = true; 10533 this.destroyCapability = createPromiseCapability(); 10534 10535 var waitOn = []; 10536 // We need to wait for all renderings to be completed, e.g. 10537 // timeout/rAF can take a long time. 10538 this.pageCache.forEach(function (page) { 10539 if (page) { 10540 waitOn.push(page._destroy()); 10541 } 10542 }); 10543 this.pageCache = []; 10544 this.pagePromises = []; 10545 var self = this; 10546 // We also need to wait for the worker to finish its long running tasks. 10547 var terminated = this.messageHandler.sendWithPromise('Terminate', null); 10548 waitOn.push(terminated); 10549 Promise.all(waitOn).then(function () { 10550 self.fontLoader.clear(); 10551 if (self.pdfDataRangeTransport) { 10552 self.pdfDataRangeTransport.abort(); 10553 self.pdfDataRangeTransport = null; 10554 } 10555 if (self.messageHandler) { 10556 self.messageHandler.destroy(); 10557 self.messageHandler = null; 10558 } 10559 self.destroyCapability.resolve(); 10560 }, this.destroyCapability.reject); 10561 return this.destroyCapability.promise; 10562 }, 10563 10564 setupMessageHandler: function WorkerTransport_setupMessageHandler() { 10565 var messageHandler = this.messageHandler; 10566 10567 function updatePassword(password) { 10568 messageHandler.send('UpdatePassword', password); 10569 } 10570 10571 var pdfDataRangeTransport = this.pdfDataRangeTransport; 10572 if (pdfDataRangeTransport) { 10573 pdfDataRangeTransport.addRangeListener(function (begin, chunk) { 10574 messageHandler.send('OnDataRange', { 10575 begin: begin, 10576 chunk: chunk, 10577 }); 10578 }); 10579 10580 pdfDataRangeTransport.addProgressListener(function (loaded) { 10581 messageHandler.send('OnDataProgress', { 10582 loaded: loaded, 10583 }); 10584 }); 10585 10586 pdfDataRangeTransport.addProgressiveReadListener(function (chunk) { 10587 messageHandler.send('OnDataRange', { 10588 chunk: chunk, 10589 }); 10590 }); 10591 10592 messageHandler.on( 10593 'RequestDataRange', 10594 function transportDataRange(data) { 10595 pdfDataRangeTransport.requestDataRange(data.begin, data.end); 10596 }, 10597 this 10598 ); 10599 } 10600 10601 messageHandler.on( 10602 'GetDoc', 10603 function transportDoc(data) { 10604 var pdfInfo = data.pdfInfo; 10605 this.numPages = data.pdfInfo.numPages; 10606 var loadingTask = this.loadingTask; 10607 var pdfDocument = new PDFDocumentProxy(pdfInfo, this, loadingTask); 10608 this.pdfDocument = pdfDocument; 10609 loadingTask._capability.resolve(pdfDocument); 10610 }, 10611 this 10612 ); 10613 10614 messageHandler.on(
10615 'NeedPassword', 10616 function transportNeedPassword(exception) { 10617 var loadingTask = this.loadingTask; 10618 if (loadingTask.onPassword) { 10619 return loadingTask.onPassword(updatePassword, PasswordResponses.NEED_PASSWORD); 10620 } 10621 loadingTask._capability.reject(new PasswordException(exception.message, exception.code)); 10622 }, 10623 this 10624 ); 10625 10626 messageHandler.on( 10627 'IncorrectPassword', 10628 function transportIncorrectPassword(exception) { 10629 var loadingTask = this.loadingTask; 10630 if (loadingTask.onPassword) { 10631 return loadingTask.onPassword(updatePassword, PasswordResponses.INCORRECT_PASSWORD); 10632 } 10633 loadingTask._capability.reject(new PasswordException(exception.message, exception.code)); 10634 }, 10635 this 10636 ); 10637 10638 messageHandler.on( 10639 'InvalidPDF', 10640 function transportInvalidPDF(exception) { 10641 this.loadingTask._capability.reject(new InvalidPDFException(exception.message)); 10642 }, 10643 this 10644 ); 10645 10646 messageHandler.on( 10647 'MissingPDF', 10648 function transportMissingPDF(exception) { 10649 this.loadingTask._capability.reject(new MissingPDFException(exception.message)); 10650 }, 10651 this 10652 ); 10653 10654 messageHandler.on( 10655 'UnexpectedResponse', 10656 function transportUnexpectedResponse(exception) { 10657 this.loadingTask._capability.reject( 10658 new UnexpectedResponseException(exception.message, exception.status) 10659 ); 10660 }, 10661 this 10662 ); 10663 10664 messageHandler.on( 10665 'UnknownError', 10666 function transportUnknownError(exception) { 10667 this.loadingTask._capability.reject(new UnknownErrorException(exception.message, exception.details)); 10668 }, 10669 this 10670 ); 10671 10672 messageHandler.on( 10673 'DataLoaded', 10674 function transportPage(data) { 10675 this.downloadInfoCapability.resolve(data); 10676 }, 10677 this 10678 ); 10679 10680 messageHandler.on( 10681 'PDFManagerReady', 10682 function transportPage(data) { 10683 if (this.pdfDataRangeTransport) { 10684 this.pdfDataRangeTransport.transportReady(); 10685 } 10686 }, 10687 this 10688 ); 10689 10690 messageHandler.on( 10691 'StartRenderPage', 10692 function transportRender(data) { 10693 if (this.destroyed) { 10694 return;
10694 // Ignore any pending requests if the worker was terminated. 10695 } 10696 var page = this.pageCache[data.pageIndex]; 10697 10698 page.stats.timeEnd('Page Request'); 10699 page._startRenderPage(data.transparency, data.intent); 10700 }, 10701 this 10702 ); 10703 10704 messageHandler.on( 10705 'RenderPageChunk', 10706 function transportRender(data) { 10707 if (this.destroyed) { 10708 return; // Ignore any pending requests if the worker was terminated. 10709 } 10710 var page = this.pageCache[data.pageIndex]; 10711 10712 page._renderPageChunk(data.operatorList, data.intent); 10713 }, 10714 this 10715 ); 10716 10717 messageHandler.on( 10718 'commonobj', 10719 function transportObj(data) { 10720 if (this.destroyed) { 10721 return; // Ignore any pending requests if the worker was terminated. 10722 } 10723 10724 var id = data[0]; 10725 var type = data[1]; 10726 if (this.commonObjs.hasData(id)) { 10727 return; 10728 } 10729 10730 switch (type) { 10731 case 'Font': 10732 var exportedData = data[2]; 10733 10734 if ('error' in exportedData) { 10735 var exportedError = exportedData.error; 10736 warn('Error during font loading: ' + exportedError); 10737 this.commonObjs.resolve(id, exportedError); 10738 break; 10739 } 10740 var fontRegistry = null; 10741 if ( 10742 getDefaultSetting('pdfBug') && 10743 globalScope.FontInspector && 10744 globalScope['FontInspector'].enabled 10745 ) { 10746 fontRegistry = { 10747 registerFont: function (font, url) { 10748 globalScope['FontInspector'].fontAdded(font, url); 10749 }, 10750 }; 10751 } 10752 var font = new FontFaceObject(exportedData, { 10753 isEvalSuported: getDefaultSetting('isEvalSupported'), 10754 disableFontFace: getDefaultSetting('disableFontFace'), 10755 fontRegistry: fontRegistry, 10756 }); 10757 10758 this.fontLoader.bind( 10759 [font], 10760 function fontReady(fontObjs) { 10761 this.commonObjs.resolve(id, font); 10762 }.bind(this) 10763 ); 10764 break; 10765 case 'FontPath': 10766 this.commonObjs.resolve(id, data[2]); 10767 break; 10768 default: 10769 error('Got unknown common object type ' + type); 10770 } 10771 }, 10772 this 10773 ); 10774 10775 messageHandler.on( 10776 'obj', 10777 function transportObj(data) { 10778 if (this.destroyed) { 10779 return;
vendor: 1,468 bytes, lines 10779-10817
10779 // Ignore any pending requests if the worker was terminated. 10780 } 10781 10782 var id = data[0]; 10783 var pageIndex = data[1]; 10784 var type = data[2]; 10785 var pageProxy = this.pageCache[pageIndex]; 10786 var imageData; 10787 if (pageProxy.objs.hasData(id)) { 10788 return; 10789 } 10790 10791 switch (type) { 10792 case 'JpegStream': 10793 imageData = data[3]; 10794 loadJpegStream(id, imageData, pageProxy.objs); 10795 break; 10796 case 'Image': 10797 imageData = data[3]; 10798 pageProxy.objs.resolve(id, imageData); 10799 10800 // heuristics that will allow not to store large data 10801 var MAX_IMAGE_SIZE_TO_STORE = 8000000; 10802 if (imageData && 'data' in imageData && imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) { 10803 pageProxy.cleanupAfterRender = true; 10804 } 10805 break; 10806 default: 10807 error('Got unknown object type ' + type); 10808 } 10809 }, 10810 this 10811 ); 10812 10813 messageHandler.on( 10814 'DocProgress', 10815 function transportDocProgress(data) { 10816 if (this.destroyed) { 10817 return;
10817 // Ignore any pending requests if the worker was terminated. 10818 } 10819 10820 var loadingTask = this.loadingTask; 10821 if (loadingTask.onProgress) { 10822 loadingTask.onProgress({ 10823 loaded: data.loaded, 10824 total: data.total, 10825 }); 10826 } 10827 }, 10828 this 10829 ); 10830 10831 messageHandler.on( 10832 'PageError', 10833 function transportError(data) { 10834 if (this.destroyed) { 10835 return; // Ignore any pending requests if the worker was terminated. 10836 } 10837 10838 var page = this.pageCache[data.pageNum - 1]; 10839 var intentState = page.intentStates[data.intent]; 10840 10841 if (intentState.displayReadyCapability) { 10842 intentState.displayReadyCapability.reject(data.error); 10843 } else { 10844 error(data.error); 10845 } 10846 10847 if (intentState.operatorList) { 10848 // Mark operator list as complete. 10849 intentState.operatorList.lastChunk = true; 10850 for (var i = 0; i < intentState.renderTasks.length; i++) { 10851 intentState.renderTasks[i].operatorListChanged(); 10852 } 10853 } 10854 }, 10855 this 10856 ); 10857 10858 messageHandler.on( 10859 'UnsupportedFeature', 10860 function transportUnsupportedFeature(data) { 10861 if (this.destroyed) { 10862 return;
10862 // Ignore any pending requests if the worker was terminated. 10863 } 10864 var featureId = data.featureId; 10865 var loadingTask = this.loadingTask; 10866 if (loadingTask.onUnsupportedFeature) { 10867 loadingTask.onUnsupportedFeature(featureId); 10868 } 10869 _UnsupportedManager.notify(featureId); 10870 }, 10871 this 10872 ); 10873 10874 messageHandler.on( 10875 'JpegDecode', 10876 function (data) { 10877 if (this.destroyed) { 10878 return Promise.reject(new Error('Worker was destroyed')); 10879 } 10880 10881 var imageUrl = data[0]; 10882 var components = data[1]; 10883 if (components !== 3 && components !== 1) { 10884 return Promise.reject(new Error('Only 3 components or 1 component can be returned')); 10885 } 10886 10887 return new Promise(function (resolve, reject) { 10888 var img = new Image(); 10889 img.onload = function () { 10890 var width = img.width; 10891 var height = img.height; 10892 var size = width * height; 10893 var rgbaLength = size * 4; 10894 var buf = new Uint8Array(size * components); 10895 var tmpCanvas = createScratchCanvas(width, height); 10896 var tmpCtx = tmpCanvas.getContext('2d'); 10897 tmpCtx.drawImage(img, 0, 0); 10898 var data = tmpCtx.getImageData(0, 0, width, height).data; 10899 var i, j; 10900 10901 if (components === 3) { 10902 for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { 10903 buf[j] = data[i]; 10904 buf[j + 1] = data[i + 1]; 10905 buf[j + 2] = data[i + 2]; 10906 } 10907 } else if (components === 1) { 10908 for (i = 0, j = 0; i < rgbaLength; i += 4, j++) { 10909 buf[j] = data[i]; 10910 } 10911 } 10912 resolve({ data: buf, width: width, height: height }); 10913 }; 10914 img.onerror = function () { 10915 reject(new Error('JpegDecode failed to load image')); 10916 }; 10917 img.src = imageUrl; 10918 }); 10919 }, 10920 this 10921 ); 10922 }, 10923 10924 getData: function WorkerTransport_getData() { 10925 return this.messageHandler.sendWithPromise('GetData', null); 10926 }, 10927 10928 getPage: function WorkerTransport_getPage(pageNumber, capability) { 10929 if (!isInt(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) { 10930 return Promise.reject(new Error('Invalid page request')); 10931 } 10932 10933 var pageIndex = pageNumber - 1; 10934 if (pageIndex in this.pagePromises) { 10935 return this.pagePromises[pageIndex]; 10936 } 10937 var promise = this.messageHandler 10938 .sendWithPromise('GetPage', { 10939 pageIndex: pageIndex, 10940 }) 10941 .then( 10942 function (pageInfo) { 10943 if (this.destroyed) { 10944 throw new Error('Transport destroyed'); 10945 } 10946 var page = new PDFPageProxy(pageIndex, pageInfo, this); 10947 this.pageCache[pageIndex] = page; 10948 return page; 10949 }.bind(this) 10950 ); 10951 this.pagePromises[pageIndex] = promise; 10952 return promise; 10953 }, 10954 10955 getPageIndex: function WorkerTransport_getPageIndexByRef(ref) { 10956 return this.messageHandler 10957 .sendWithPromise('GetPageIndex', { 10958 ref: ref, 10959 }) 10960 .catch(function (reason) { 10961 return Promise.reject(new Error(reason)); 10962 }); 10963 }, 10964 10965 getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) {
10966 return this.messageHandler.sendWithPromise('GetAnnotations', { 10967 pageIndex: pageIndex, 10968 intent: intent, 10969 }); 10970 }, 10971 10972 getDestinations: function WorkerTransport_getDestinations() { 10973 return this.messageHandler.sendWithPromise('GetDestinations', null); 10974 }, 10975 10976 getDestination: function WorkerTransport_getDestination(id) { 10977 return this.messageHandler.sendWithPromise('GetDestination', { 10978 id: id, 10979 }); 10980 }, 10981 10982 getPageLabels: function WorkerTransport_getPageLabels() { 10983 return this.messageHandler.sendWithPromise('GetPageLabels', null); 10984 }, 10985 10986 getAttachments: function WorkerTransport_getAttachments() { 10987 return this.messageHandler.sendWithPromise('GetAttachments', null); 10988 }, 10989 10990 getJavaScript: function WorkerTransport_getJavaScript() { 10991 return this.messageHandler.sendWithPromise('GetJavaScript', null); 10992 }, 10993 10994 getOutline: function WorkerTransport_getOutline() { 10995 return this.messageHandler.sendWithPromise('GetOutline', null); 10996 }, 10997 10998 getMetadata: function WorkerTransport_getMetadata() { 10999 return this.messageHandler.sendWithPromise('GetMetadata', null).then(function transportMetadata(results) { 11000 return { 11001 info: results[0], 11002 metadata: results[1] ? new Metadata(results[1]) : null, 11003 }; 11004 }); 11005 }, 11006 11007 getStats: function WorkerTransport_getStats() { 11008 return this.messageHandler.sendWithPromise('GetStats', null); 11009 }, 11010 11011 startCleanup: function WorkerTransport_startCleanup() { 11012 this.messageHandler.sendWithPromise('Cleanup', null).then( 11013 function endCleanup() { 11014 for (var i = 0, ii = this.pageCache.length; i < ii; i++) { 11015 var page = this.pageCache[i]; 11016 if (page) { 11017 page.cleanup(); 11018 } 11019 } 11020 this.commonObjs.clear(); 11021 this.fontLoader.clear(); 11022 }.bind(this) 11023 ); 11024 }, 11025 }; 11026 return WorkerTransport; 11027 })(); 11028 11029 /** 11030 * A PDF document and page is built of many objects. E.g. there are objects 11031 * for fonts, images, rendering code and such. These objects might get processed 11032 * inside of a worker. The `PDFObjects` implements some basic functions to 11033 * manage these objects. 11034 * @ignore 11035 */ 11036 var PDFObjects = (function PDFObjectsClosure() { 11037 function PDFObjects() { 11038 this.objs = Object.create(null); 11039 } 11040 11041 PDFObjects.prototype = { 11042 /** 11043 * Internal function. 11044 * Ensures there is an object defined for `objId`. 11045 */ 11046 ensureObj: function PDFObjects_ensureObj(objId) { 11047 if (this.objs[objId]) { 11048 return this.objs[objId]; 11049 } 11050 11051 var obj = { 11052 capability: createPromiseCapability(), 11053 data: null, 11054 resolved: false, 11055 }; 11056 this.objs[objId] = obj; 11057 11058 return obj; 11059 }, 11060 11061 /** 11062 * If called *without* callback, this returns the data of `objId` but the 11063 * object needs to be resolved. If it isn't, this function throws. 11064 * 11065 * If called *with* a callback, the callback is called with the data of the 11066 * object once the object is resolved. That means, if you call this 11067 * function and the object is already resolved, the callback gets called 11068 * right away. 11069 */ 11070 get: function PDFObjects_get(objId, callback) { 11071 // If there is a callback, then the get can be async and the object is 11072 // not required to be resolved right now 11073 if (callback) { 11074 this.ensureObj(objId).capability.promise.then(callback); 11075 return null; 11076 } 11077 11078 // If there isn't a callback, the user expects to get the resolved data 11079 // directly. 11080 var obj = this.objs[objId]; 11081 11082 // If there isn't an object yet or the object isn't resolved, then the 11083 // data isn't ready yet! 11084 if (!obj || !obj.resolved) { 11085 error("Requesting object that isn't resolved yet " + objId); 11086 } 11087 11088 return obj.data; 11089 }, 11090 11091 /** 11092 * Resolves the object `objId` with optional `data`. 11093 */ 11094 resolve: function PDFObjects_resolve(objId, data) { 11095 var obj = this.ensureObj(objId); 11096 11097 obj.resolved = true; 11098 obj.data = data; 11099 obj.capability.resolve(data); 11100 }, 11101
vendor: 4,116 bytes, lines 11102-11214
11102 isResolved: function PDFObjects_isResolved(objId) { 11103 var objs = this.objs; 11104 11105 if (!objs[objId]) { 11106 return false; 11107 } else { 11108 return objs[objId].resolved; 11109 } 11110 }, 11111 11112 hasData: function PDFObjects_hasData(objId) { 11113 return this.isResolved(objId); 11114 }, 11115 11116 /** 11117 * Returns the data of `objId` if object exists, null otherwise. 11118 */ 11119 getData: function PDFObjects_getData(objId) { 11120 var objs = this.objs; 11121 if (!objs[objId] || !objs[objId].resolved) { 11122 return null; 11123 } else { 11124 return objs[objId].data; 11125 } 11126 }, 11127 11128 clear: function PDFObjects_clear() { 11129 this.objs = Object.create(null); 11130 }, 11131 }; 11132 return PDFObjects; 11133 })(); 11134 11135 /** 11136 * Allows controlling of the rendering tasks. 11137 * @class 11138 * @alias RenderTask 11139 */ 11140 var RenderTask = (function RenderTaskClosure() { 11141 function RenderTask(internalRenderTask) { 11142 this._internalRenderTask = internalRenderTask; 11143 11144 /** 11145 * Callback for incremental rendering -- a function that will be called 11146 * each time the rendering is paused. To continue rendering call the 11147 * function that is the first argument to the callback. 11148 * @type {function} 11149 */ 11150 this.onContinue = null; 11151 } 11152 11153 RenderTask.prototype = /** @lends RenderTask.prototype */ { 11154 /** 11155 * Promise for rendering task completion. 11156 * @return {Promise} 11157 */ 11158 get promise() { 11159 return this._internalRenderTask.capability.promise; 11160 }, 11161 11162 /** 11163 * Cancels the rendering task. If the task is currently rendering it will 11164 * not be cancelled until graphics pauses with a timeout. The promise that 11165 * this object extends will resolved when cancelled. 11166 */ 11167 cancel: function RenderTask_cancel() { 11168 this._internalRenderTask.cancel(); 11169 }, 11170 11171 /** 11172 * Registers callbacks to indicate the rendering task completion. 11173 * 11174 * @param {function} onFulfilled The callback for the rendering completion. 11175 * @param {function} onRejected The callback for the rendering failure. 11176 * @return {Promise} A promise that is resolved after the onFulfilled or 11177 * onRejected callback. 11178 */ 11179 then: function RenderTask_then(onFulfilled, onRejected) { 11180 return this.promise.then.apply(this.promise, arguments); 11181 }, 11182 }; 11183 11184 return RenderTask; 11185 })(); 11186 11187 /** 11188 * For internal use only. 11189 * @ignore 11190 */ 11191 var InternalRenderTask = (function InternalRenderTaskClosure() { 11192 function InternalRenderTask(callback, params, objs, commonObjs, operatorList, pageNumber) { 11193 this.callback = callback; 11194 this.params = params; 11195 this.objs = objs; 11196 this.commonObjs = commonObjs; 11197 this.operatorListIdx = null; 11198 this.operatorList = operatorList; 11199 this.pageNumber = pageNumber; 11200 this.running = false; 11201 this.graphicsReadyCallback = null; 11202 this.graphicsReady = false; 11203 this.useRequestAnimationFrame = false; 11204 this.cancelled = false; 11205 this.capability = createPromiseCapability(); 11206 this.task = new RenderTask(this); 11207 // caching this-bound methods 11208 this._continueBound = this._continue.bind(this); 11209 this._scheduleNextBound = this._scheduleNext.bind(this); 11210 this._nextBound = this._next.bind(this); 11211 } 11212 11213 InternalRenderTask.prototype = { 11214 initializeGraphics: function InternalRenderTask_initializeGraphics(trans
11214parency) { 11215 if (this.cancelled) { 11216 return; 11217 } 11218 if (getDefaultSetting('pdfBug') && globalScope.StepperManager && globalScope.StepperManager.enabled) { 11219 this.stepper = globalScope.StepperManager.create(this.pageNumber - 1); 11220 this.stepper.init(this.operatorList); 11221 this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint(); 11222 } 11223 11224 var params = this.params; 11225 this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs, this.objs, params.imageLayer); 11226 11227 this.gfx.beginDrawing(params.transform, params.viewport, transparency); 11228 this.operatorListIdx = 0; 11229 this.graphicsReady = true; 11230 if (this.graphicsReadyCallback) { 11231 this.graphicsReadyCallback(); 11232 } 11233 }, 11234 11235 cancel: function InternalRenderTask_cancel() { 11236 this.running = false; 11237 this.cancelled = true; 11238 this.callback('cancelled'); 11239 }, 11240 11241 operatorListChanged: function InternalRenderTask_operatorListChanged() { 11242 if (!this.graphicsReady) { 11243 if (!this.graphicsReadyCallback) { 11244 this.graphicsReadyCallback = this._continueBound; 11245 } 11246 return; 11247 } 11248 11249 if (this.stepper) { 11250 this.stepper.updateOperatorList(this.operatorList); 11251 } 11252 11253 if (this.running) { 11254 return; 11255 } 11256 this._continue(); 11257 }, 11258 11259 _continue: function InternalRenderTask__continue() { 11260 this.running = true; 11261 if (this.cancelled) { 11262 return; 11263 } 11264 if (this.task.onContinue) { 11265 this.task.onContinue.call(this.task, this._scheduleNextBound); 11266 } else { 11267 this._scheduleNext(); 11268 } 11269 }, 11270 11271 _scheduleNext: function InternalRenderTask__scheduleNext() { 11272 if (this.useRequestAnimationFrame && typeof window !== 'undefined') { 11273 window.requestAnimationFrame(this._nextBound); 11274 } else { 11275 Promise.resolve(undefined).then(this._nextBound); 11276 } 11277 }, 11278 11279 _next: function InternalRenderTask__next() { 11280 if (this.cancelled) { 11281 return; 11282 } 11283 this.operatorListIdx = this.gfx.executeOperatorList( 11284 this.operatorList, 11285 this.operatorListIdx, 11286 this._continueBound, 11287 this.stepper 11288 ); 11289 if (this.operatorListIdx === this.operatorList.argsArray.length) { 11290 this.running = false; 11291 if (this.operatorList.lastChunk) { 11292 this.gfx.endDrawing(); 11293 this.callback(); 11294 } 11295 } 11296 }, 11297 }; 11298 11299 return InternalRenderTask; 11300 })(); 11301 11302 /** 11303 * (Deprecated) Global observer of unsupported feature usages. Use 11304 * onUnsupportedFeature callback of the {PDFDocumentLoadingTask} instance. 11305 */ 11306 var _UnsupportedManager = (function UnsupportedManagerClosure() { 11307 var listeners = []; 11308 return { 11309 listen: function (cb) { 11310 deprecated( 11311 'Global UnsupportedManager.listen is used: ' + 11312 ' use PDFDocumentLoadingTask.onUnsupportedFeature instead' 11313 ); 11314 listeners.push(cb); 11315 }, 11316 notify: function (featureId) { 11317 for (var i = 0, ii = listeners.length; i < ii; i++) { 11318 listeners[i](featureId); 11319 } 11320 }, 11321 }; 11322 })(); 11323 11324 if (typeof pdfjsVersion !== 'undefined') { 11325 exports.version = pdfjsVersion; 11326 } 11327 if (typeof pdfjsBuild !== 'undefined') { 11328 exports.build = pdfjsBuild; 11329 } 11330 11331 exports.getDocument = getDocument; 11332 exports.PDFDataRangeTransport = PDFDataRangeTransport; 11333 exports.PDFWorker = PDFWorker; 11334 exports.PDFDocumentProxy = PDFDocumentProxy; 11335 exports.PDFPageProxy = PDFPageProxy; 11336 exports._UnsupportedManager = _UnsupportedManager; 11337 } 11338 ); 11339 11340 (function (root, factory) { 11341 { 11342 factory( 11343 (root.pdfjsDisplayGlobal = {}), 11344 root.pdfjsSharedUtil, 11345 root.pdfjsDisplayDOMUtils, 11346 root.pdfjsDisplayAPI, 11347 root.pdfjsDisplayAnnotationLayer, 11348 root.pdfjsDisplayTextLayer, 11349 root.pdfjsDisplayMetadata, 11350 root.pdfjsDisplaySVG 11351 ); 11352 } 11353 })( 11354 this, 11355 function ( 11356 exports, 11357 sharedUtil, 11358 displayDOMUtils, 11359 displayAPI, 11360 displayAnnotationLayer, 11361 displayTextLayer, 11362 displayMetadata, 11363 displaySVG 11364 ) { 11365 var globalScope = sharedUtil.globalScope; 11366 var deprecated = sharedUtil.deprecated; 11367 var warn = sharedUtil.warn; 11368 var LinkTarget = displayDOMUtils.LinkTarget; 11369 11370 var isWorker = typeof window === 'undefined'; 11371 11372 // The global PDFJS object is now deprecated and will not be supported in 11373 // the future. The members below are maintained for backward compatibility 11374 // and shall not be extended or modified. If the global.js is included as 11375 // a module, we will create a global PDFJS object instance or use existing. 11376 if (!globalScope.PDFJS) { 11377 globalScope.PDFJS = {}; 11378 } 11379 var PDFJS = globalScope.PDFJS; 11380 11381 if (typeof pdfjsVersion !== 'undefined') { 11382 PDFJS.version = pdfjsVersion; 11383 } 11384 if (typeof pdfjsBuild !== 'undefined') { 11385 PDFJS.build = pdfjsBuild; 11386 } 11387 11388 PDFJS.pdfBug = false;
11389 11390 if (PDFJS.verbosity !== undefined) { 11391 sharedUtil.setVerbosityLevel(PDFJS.verbosity); 11392 } 11393 delete PDFJS.verbosity; 11394 Object.defineProperty(PDFJS, 'verbosity', { 11395 get: function () { 11396 return sharedUtil.getVerbosityLevel(); 11397 }, 11398 set: function (level) { 11399 sharedUtil.setVerbosityLevel(level); 11400 }, 11401 enumerable: true, 11402 configurable: true, 11403 }); 11404 11405 PDFJS.VERBOSITY_LEVELS = sharedUtil.VERBOSITY_LEVELS; 11406 PDFJS.OPS = sharedUtil.OPS; 11407 PDFJS.UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES; 11408 PDFJS.isValidUrl = sharedUtil.isValidUrl; 11409 PDFJS.shadow = sharedUtil.shadow; 11410 PDFJS.createBlob = sharedUtil.createBlob; 11411 PDFJS.createObjectURL = function PDFJS_createObjectURL(data, contentType) { 11412 return sharedUtil.createObjectURL(data, contentType, PDFJS.disableCreateObjectURL); 11413 }; 11414 Object.defineProperty(PDFJS, 'isLittleEndian', { 11415 configurable: true, 11416 get: function PDFJS_isLittleEndian() { 11417 var value = sharedUtil.isLittleEndian(); 11418 return sharedUtil.shadow(PDFJS, 'isLittleEndian', value); 11419 }, 11420 }); 11421 PDFJS.removeNullCharacters = sharedUtil.removeNullCharacters; 11422 PDFJS.PasswordResponses = sharedUtil.PasswordResponses; 11423 PDFJS.PasswordException = sharedUtil.PasswordException; 11424 PDFJS.UnknownErrorException = sharedUtil.UnknownErrorException; 11425 PDFJS.InvalidPDFException = sharedUtil.InvalidPDFException; 11426 PDFJS.MissingPDFException = sharedUtil.MissingPDFException; 11427 PDFJS.UnexpectedResponseException = sharedUtil.UnexpectedResponseException; 11428 PDFJS.Util = sharedUtil.Util; 11429 PDFJS.PageViewport = sharedUtil.PageViewport; 11430 PDFJS.createPromiseCapability = sharedUtil.createPromiseCapability; 11431 11432 /** 11433 * The maximum allowed image size in total pixels e.g. width * height. Images 11434 * above this value will not be drawn. Use -1 for no limit. 11435 * @var {number} 11436 */ 11437 PDFJS.maxImageSize = PDFJS.maxImageSize === undefined ? -1 : PDFJS.maxImageSize; 11438 11439 /** 11440 * The url of where the predefined Adobe CMaps are located. Include trailing 11441 * slash. 11442 * @var {string} 11443 */ 11444 PDFJS.cMapUrl = PDFJS.cMapUrl === undefined ? null : PDFJS.cMapUrl; 11445 11446 /** 11447 * Specifies if CMaps are binary packed. 11448 * @var {boolean} 11449 */ 11450 PDFJS.cMapPacked = PDFJS.cMapPacked === undefined ? false : PDFJS.cMapPacked; 11451 11452 /** 11453 * By default fonts are converted to OpenType fonts and loaded via font face 11454 * rules. If disabled, the font will be rendered using a built in font 11455 * renderer that constructs the glyphs with primitive path commands. 11456 * @var {boolean} 11457 */ 11458 PDFJS.disableFontFace = PDFJS.disableFontFace === undefined ? false : PDFJS.disableFontFace; 11459 11460 /** 11461 * Path for image resources, mainly for annotation icons. Include trailing 11462 * slash. 11463 * @var {string} 11464 */ 11465 PDFJS.imageResourcesPath = PDFJS.imageResourcesPath === undefined ? '' : PDFJS.imageResourcesPath; 11466 11467 /** 11468 * Disable the web worker and run all code on the main thread. This will 11469 * happen automatically if the browser doesn't support workers or sending 11470 * typed arrays to workers. 11471 * @var {boolean} 11472 */ 11473 PDFJS.disableWorker = PDFJS.disableWorker === undefined ? false : PDFJS.disableWorker; 11474 11475 /** 11476 * Path and filename of the worker file. Required when the worker is enabled 11477 * in development mode. If unspecified in the production build, the worker 11478 * will be loaded based on the location of the pdf.js file. It is recommended 11479 * that the workerSrc is set in a custom application to prevent issues caused 11480 * by third-party frameworks and libraries. 11481 * @var {string} 11482 */ 11483 PDFJS.workerSrc = PDFJS.workerSrc === undefined ? null : PDFJS.workerSrc; 11484 11485 /** 11486 * Disable range request loading of PDF files. When enabled and if the server 11487 * supports partial content requests then the PDF will be fetched in chunks. 11488 * Enabled (false) by default. 11489 * @var {boolean} 11490 */ 11491 PDFJS.disableRange = PDFJS.disableRange === undefined ? false : PDFJS.disableRange; 11492 11493 /** 11494 * Disable streaming of PDF file data. By default PDF.js attempts to load PDF 11495 * in chunks. This default behavior can be disabled. 11496 * @var {boolean} 11497 */ 11498 PDFJS.disableStream = PDFJS.disableStream === undefined ? false : PDFJS.disableStream; 11499 11500 /** 11501 * Disable pre-fetching of PDF file data. When range requests are enabled 11502 * PDF.js will automatically keep fetching more data even if it isn't needed 11503 * to display the current page. This default behavior can be disabled. 11504 * 11505 * NOTE: It is also necessary to disable streaming, see above, 11506 * in order for disabling of pre-fetching to work correctly. 11507 * @var {boolean} 11508 */ 11509 PDFJS.disableAutoFetch = PDFJS.disableAutoFetch === undefined ? false : PDFJS.disableAutoFetch; 11510 11511 /** 11512 * Enables special hooks for debugging PDF.js. 11513 * @var {boolean} 11514 */ 11515 PDFJS.pdfBug = PDFJS.pdfBug === undefined ? false : PDFJS.pdfBug; 11516 11517 /** 11518 * Enables transfer usage in postMessage for ArrayBuffers. 11519 * @var {boolean} 11520 */ 11521 PDFJS.postMessageTransfers = PDFJS.postMessageTransfers === undefined ? true : PDFJS.postMessageTransfers; 11522 11523 /** 11524 * Disables URL.createObjectURL usage. 11525 * @var {boolean} 11526 */ 11527 PDFJS.disableCreateObjectURL = 11528 PDFJS.disableCreateObjectURL === undefined ? false : PDFJS.disableCreateObjectURL; 11529 11530 /** 11531 * Disables WebGL usage. 11532 * @var {boolean} 11533 */ 11534 PDFJS.disableWebGL = PDFJS.disableWebGL === undefined ? true : PDFJS.disableWebGL; 11535 11536 /** 11537 * Specifies the |target| attribute for external links. 11538 * The constants from PDFJS.LinkTarget should be used: 11539 * - NONE [default] 11540 * - SELF 11541 * - BLANK 11542 * - PARENT 11543 * - TOP 11544 * @var {number} 11545 */ 11546 PDFJS.externalLinkTarget = PDFJS.externalLinkTarget === undefined ? LinkTarget.NONE : PDFJS.externalLinkTarget; 11547 11548 /** 11549 * Specifies the |rel| attribute for external links. Defaults to stripping 11550 * the referrer. 11551 * @var {string} 11552 */ 11553 PDFJS.externalLinkRel = PDFJS.externalLinkRel === undefined ? 'noreferrer' : PDFJS.externalLinkRel; 11554 11555 /** 11556 * Determines if we can eval strings as JS. Primarily used to improve 11557 * performance for font rendering. 11558 * @var {boolean} 11559 */ 11560 PDFJS.isEvalSupported = PDFJS.isEvalSupported === undefined ? true : PDFJS.isEvalSupported; 11561 11562 var savedOpenExternalLinksInNewWindow = PDFJS.openExternalLinksInNewWindow; 11563 delete PDFJS.openExternalLinksInNewWindow; 11564 Object.defineProperty(PDFJS, 'openExternalLinksInNewWindow', { 11565 get: function () { 11566 return PDFJS.externalLinkTarget === LinkTarget.BLANK; 11567 }, 11568 set: function (value) { 11569 if (value) { 11570 deprecated( 11571 'PDFJS.openExternalLinksInNewWindow, please use ' + 11572 '"PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK" instead.' 11573 ); 11574 } 11575 if (PDFJS.externalLinkTarget !== LinkTarget.NONE) { 11576 warn('PDFJS.externalLinkTarget is already initialized'); 11577 return; 11578 } 11579 PDFJS.externalLinkTarget = value ? LinkTarget.BLANK : LinkTarget.NONE; 11580 }, 11581 enumerable: true, 11582 configurable: true, 11583 }); 11584 if (savedOpenExternalLinksInNewWindow) { 11585 /** 11586 * (Deprecated) Opens external links in a new window if enabled. 11587 * The default behavior opens external links in the PDF.js
11587window. 11588 * 11589 * NOTE: This property has been deprecated, please use 11590 * `PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK` instead. 11591 * @var {boolean} 11592 */ 11593 PDFJS.openExternalLinksInNewWindow = savedOpenExternalLinksInNewWindow; 11594 } 11595 11596 PDFJS.getDocument = displayAPI.getDocument; 11597 PDFJS.PDFDataRangeTransport = displayAPI.PDFDataRangeTransport; 11598 PDFJS.PDFWorker = displayAPI.PDFWorker; 11599 11600 Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', { 11601 configurable: true, 11602 get: function PDFJS_hasCanvasTypedArrays() { 11603 var value = displayDOMUtils.hasCanvasTypedArrays(); 11604 return sharedUtil.shadow(PDFJS, 'hasCanvasTypedArrays', value); 11605 }, 11606 }); 11607 PDFJS.CustomStyle = displayDOMUtils.CustomStyle; 11608 PDFJS.LinkTarget = LinkTarget; 11609 PDFJS.addLinkAttributes = displayDOMUtils.addLinkAttributes; 11610 PDFJS.getFilenameFromUrl = displayDOMUtils.getFilenameFromUrl; 11611 PDFJS.isExternalLinkTargetSet = displayDOMUtils.isExternalLinkTargetSet; 11612 11613 PDFJS.AnnotationLayer = displayAnnotationLayer.AnnotationLayer; 11614 11615 PDFJS.renderTextLayer = displayTextLayer.renderTextLayer; 11616 11617 PDFJS.Metadata = displayMetadata.Metadata; 11618 11619 PDFJS.SVGGraphics = displaySVG.SVGGraphics; 11620 11621 PDFJS.UnsupportedManager = displayAPI._UnsupportedManager; 11622 11623 exports.globalScope = globalScope; 11624 exports.isWorker = isWorker; 11625 exports.PDFJS = globalScope.PDFJS; 11626 } 11627 ); 11628 }).call(pdfjsLibs); 11629 11630 exports.PDFJS = pdfjsLibs.pdfjsDisplayGlobal.PDFJS; 11631 exports.build = pdfjsLibs.pdfjsDisplayAPI.build; 11632 exports.version = pdfjsLibs.pdfjsDisplayAPI.version; 11633 exports.getDocument = pdfjsLibs.pdfjsDisplayAPI.getDocument; 11634 exports.PDFDataRangeTransport = pdfjsLibs.pdfjsDisplayAPI.PDFDataRangeTransport; 11635 exports.PDFWorker = pdfjsLibs.pdfjsDisplayAPI.PDFWorker; 11636 exports.renderTextLayer = pdfjsLibs.pdfjsDisplayTextLayer.renderTextLayer; 11637 exports.AnnotationLayer = pdfjsLibs.pdfjsDisplayAnnotationLayer.AnnotationLayer; 11638 exports.CustomStyle = pdfjsLibs.pdfjsDisplayDOMUtils.CustomStyle; 11639 exports.PasswordResponses = pdfjsLibs.pdfjsSharedUtil.PasswordResponses; 11640 exports.InvalidPDFException = pdfjsLibs.pdfjsSharedUtil.InvalidPDFException; 11641 exports.MissingPDFException = pdfjsLibs.pdfjsSharedUtil.MissingPDFException; 11642 exports.SVGGraphics = pdfjsLibs.pdfjsDisplaySVG.SVGGraphics; 11643 exports.UnexpectedResponseException = pdfjsLibs.pdfjsSharedUtil.UnexpectedResponseException; 11644 exports.OPS = pdfjsLibs.pdfjsSharedUtil.OPS; 11645 exports.UNSUPPORTED_FEATURES = pdfjsLibs.pdfjsSharedUtil.UNSUPPORTED_FEATURES; 11646 exports.isValidUrl = pdfjsLibs.pdfjsSharedUtil.isValidUrl; 11647 exports.createObjectURL = pdfjsLibs.pdfjsSharedUtil.createObjectURL; 11648 exports.removeNullCharacters = pdfjsLibs.pdfjsSharedUtil.removeNullCharacters; 11649 exports.shadow = pdfjsLibs.pdfjsSharedUtil.shadow; 11650 exports.createBlob = pdfjsLibs.pdfjsSharedUtil.createBlob; 11651 exports.getFilenameFromUrl = pdfjsLibs.pdfjsDisplayDOMUtils.getFilenameFromUrl; 11652 exports.addLinkAttributes = pdfjsLibs.pdfjsDisplayDOMUtils.addLinkAttributes; 11653});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.