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