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