diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla index e6a951415102..7058e039b932 100644 --- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,4 +1,4 @@ This is the pdf.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 0.8.1114 +Current extension version is: 0.8.1181 diff --git a/browser/extensions/pdfjs/content/PdfJs.jsm b/browser/extensions/pdfjs/content/PdfJs.jsm index 89800546bc27..96ec430f0b71 100644 --- a/browser/extensions/pdfjs/content/PdfJs.jsm +++ b/browser/extensions/pdfjs/content/PdfJs.jsm @@ -61,6 +61,27 @@ function getIntPref(aPref, aDefaultValue) { } } +function initializeDefaultPreferences() { + Cu.import('resource://pdf.js/default_preferences.js'); + + var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.'); + var defaultValue; + for (var key in DEFAULT_PREFERENCES) { + defaultValue = DEFAULT_PREFERENCES[key]; + switch (typeof defaultValue) { + case 'boolean': + defaultBranch.setBoolPref(key, defaultValue); + break; + case 'number': + defaultBranch.setIntPref(key, defaultValue); + break; + case 'string': + defaultBranch.setCharPref(key, defaultValue); + break; + } + } +} + // Register/unregister a constructor as a factory. function Factory() {} Factory.prototype = { @@ -104,6 +125,8 @@ let PdfJs = { Services.obs.addObserver(this, TOPIC_PDFJS_HANDLER_CHANGED, false); Services.obs.addObserver(this, TOPIC_PLUGINS_LIST_UPDATED, false); Services.obs.addObserver(this, TOPIC_PLUGIN_INFO_UPDATED, false); + + initializeDefaultPreferences(); }, _migrate: function migrate() { diff --git a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm index c4d8aba678fb..fcbc56ed89da 100644 --- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm +++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm @@ -16,7 +16,7 @@ */ /* jshint esnext:true */ /* globals Components, Services, XPCOMUtils, NetUtil, PrivateBrowsingUtils, - dump, NetworkManager, PdfJsTelemetry, DEFAULT_PREFERENCES */ + dump, NetworkManager, PdfJsTelemetry */ 'use strict'; @@ -33,16 +33,14 @@ const PDF_CONTENT_TYPE = 'application/pdf'; const PREF_PREFIX = 'pdfjs'; const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html'; const MAX_DATABASE_LENGTH = 4096; -const MAX_STRING_PREF_LENGTH = 4096; +const MAX_NUMBER_OF_PREFS = 50; +const MAX_STRING_PREF_LENGTH = 128; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/NetUtil.jsm'); Cu.import('resource://pdf.js/network.js'); -// Load the default preferences. -Cu.import('resource://pdf.js/default_preferences.js'); - XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils', 'resource://gre/modules/PrivateBrowsingUtils.jsm'); @@ -453,56 +451,60 @@ ChromeActions.prototype = { .updateControlState(result, findPrevious); }, setPreferences: function(prefs) { - var prefValue, defaultValue, prefName, prefType, defaultType; - - for (var key in DEFAULT_PREFERENCES) { + var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.'); + var numberOfPrefs = 0; + var prefValue, prefName; + for (var key in prefs) { + if (++numberOfPrefs > MAX_NUMBER_OF_PREFS) { + log('setPreferences - Exceeded the maximum number of preferences ' + + 'that is allowed to be set at once.'); + break; + } else if (!defaultBranch.getPrefType(key)) { + continue; + } prefValue = prefs[key]; - defaultValue = DEFAULT_PREFERENCES[key]; prefName = (PREF_PREFIX + '.' + key); - - if (prefValue === undefined || prefValue === defaultValue) { - Services.prefs.clearUserPref(prefName); - } else { - prefType = typeof prefValue; - defaultType = typeof defaultValue; - - if (prefType !== defaultType) { - continue; - } - switch (defaultType) { - case 'boolean': - setBoolPref(prefName, prefValue); - break; - case 'number': - setIntPref(prefName, prefValue); - break; - case 'string': - // Protect against adding arbitrarily long strings in about:config. - if (prefValue.length <= MAX_STRING_PREF_LENGTH) { - setStringPref(prefName, prefValue); - } - break; - } + switch (typeof prefValue) { + case 'boolean': + setBoolPref(prefName, prefValue); + break; + case 'number': + setIntPref(prefName, prefValue); + break; + case 'string': + if (prefValue.length > MAX_STRING_PREF_LENGTH) { + log('setPreferences - Exceeded the maximum allowed length ' + + 'for a string preference.'); + } else { + setStringPref(prefName, prefValue); + } + break; } } }, - getPreferences: function() { - var currentPrefs = {}; - var defaultValue, prefName; - - for (var key in DEFAULT_PREFERENCES) { - defaultValue = DEFAULT_PREFERENCES[key]; + getPreferences: function(prefs) { + var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.'); + var currentPrefs = {}, numberOfPrefs = 0; + var prefValue, prefName; + for (var key in prefs) { + if (++numberOfPrefs > MAX_NUMBER_OF_PREFS) { + log('getPreferences - Exceeded the maximum number of preferences ' + + 'that is allowed to be fetched at once.'); + break; + } else if (!defaultBranch.getPrefType(key)) { + continue; + } + prefValue = prefs[key]; prefName = (PREF_PREFIX + '.' + key); - - switch (typeof defaultValue) { + switch (typeof prefValue) { case 'boolean': - currentPrefs[key] = getBoolPref(prefName, defaultValue); + currentPrefs[key] = getBoolPref(prefName, prefValue); break; case 'number': - currentPrefs[key] = getIntPref(prefName, defaultValue); + currentPrefs[key] = getIntPref(prefName, prefValue); break; case 'string': - currentPrefs[key] = getStringPref(prefName, defaultValue); + currentPrefs[key] = getStringPref(prefName, prefValue); break; } } diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js index 82dfe2d5e9be..d4f23f1787f2 100644 --- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -21,8 +21,8 @@ if (typeof PDFJS === 'undefined') { (typeof window !== 'undefined' ? window : this).PDFJS = {}; } -PDFJS.version = '0.8.1114'; -PDFJS.build = 'ea9c8f8'; +PDFJS.version = '0.8.1181'; +PDFJS.build = '31ea4e0'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it @@ -225,8 +225,9 @@ function backtrace() { } function assert(cond, msg) { - if (!cond) + if (!cond) { error(msg); + } } var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = { @@ -257,10 +258,12 @@ var UnsupportedManager = PDFJS.UnsupportedManager = // Combines two URLs. The baseUrl shall be absolute URL. If the url is an // absolute URL, it will be returned as is. function combineUrl(baseUrl, url) { - if (!url) + if (!url) { return baseUrl; - if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) + } + if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) { return url; + } if (url.charAt(0) == '/') { // absolute path var i = baseUrl.indexOf('://'); @@ -309,8 +312,9 @@ PDFJS.isValidUrl = isValidUrl; // In a well-formed PDF, |cond| holds. If it doesn't, subsequent // behavior is undefined. function assertWellFormed(cond, msg) { - if (!cond) + if (!cond) { error(msg); + } } function shadow(obj, prop, value) { @@ -427,8 +431,9 @@ function bytesToString(bytes) { function stringToBytes(str) { var length = str.length; var bytes = new Uint8Array(length); - for (var n = 0; n < length; ++n) + for (var n = 0; n < length; ++n) { bytes[n] = str.charCodeAt(n) & 0xFF; + } return bytes; } @@ -832,14 +837,15 @@ function isRef(v) { function isPDFFunction(v) { var fnDict; - if (typeof v != 'object') + if (typeof v != 'object') { return false; - else if (isDict(v)) + } else if (isDict(v)) { fnDict = v; - else if (isStream(v)) + } else if (isStream(v)) { fnDict = v.dict; - else + } else { return false; + } return fnDict.has('FunctionType'); } @@ -908,8 +914,9 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() { var StatTimer = (function StatTimerClosure() { function rpad(str, pad, length) { - while (str.length < length) + while (str.length < length) { str += pad; + } return str; } function StatTimer() { @@ -919,17 +926,21 @@ var StatTimer = (function StatTimerClosure() { } StatTimer.prototype = { time: function StatTimer_time(name) { - if (!this.enabled) + if (!this.enabled) { return; - if (name in this.started) + } + if (name in this.started) { warn('Timer is already running for ' + name); + } this.started[name] = Date.now(); }, timeEnd: function StatTimer_timeEnd(name) { - if (!this.enabled) + if (!this.enabled) { return; - if (!(name in this.started)) + } + if (!(name in this.started)) { warn('Timer has not been started for ' + name); + } this.times.push({ 'name': name, 'start': this.started[name], @@ -945,8 +956,9 @@ var StatTimer = (function StatTimerClosure() { var longest = 0; for (var i = 0, ii = times.length; i < ii; ++i) { var name = times[i]['name']; - if (name.length > longest) + if (name.length > longest) { longest = name.length; + } } for (var i = 0, ii = times.length; i < ii; ++i) { var span = times[i]; @@ -960,8 +972,9 @@ var StatTimer = (function StatTimerClosure() { })(); PDFJS.createBlob = function createBlob(data, contentType) { - if (typeof Blob !== 'undefined') + if (typeof Blob !== 'undefined') { return new Blob([data], { type: contentType }); + } // Blob builder is deprecated in FF14 and removed in FF18. var bb = new MozBlobBuilder(); bb.append(data); @@ -1238,9 +1251,9 @@ var ColorSpace = (function ColorSpaceClosure() { ColorSpace.parse = function ColorSpace_parse(cs, xref, res) { var IR = ColorSpace.parseToIR(cs, xref, res); - if (IR instanceof AlternateCS) + if (IR instanceof AlternateCS) { return IR; - + } return ColorSpace.fromIR(IR); }; @@ -1261,8 +1274,9 @@ var ColorSpace = (function ColorSpaceClosure() { return new CalGrayCS(whitePoint, blackPoint, gamma); case 'PatternCS': var basePatternCS = IR[1]; - if (basePatternCS) + if (basePatternCS) { basePatternCS = ColorSpace.fromIR(basePatternCS); + } return new PatternCS(basePatternCS); case 'IndexedCS': var baseIndexedCS = IR[1]; @@ -1292,8 +1306,9 @@ var ColorSpace = (function ColorSpaceClosure() { var colorSpaces = res.get('ColorSpace'); if (isDict(colorSpaces)) { var refcs = colorSpaces.get(cs.name); - if (refcs) + if (refcs) { cs = refcs; + } } } @@ -1342,17 +1357,19 @@ var ColorSpace = (function ColorSpaceClosure() { var stream = xref.fetchIfRef(cs[1]); var dict = stream.dict; var numComps = dict.get('N'); - if (numComps == 1) + if (numComps == 1) { return 'DeviceGrayCS'; - if (numComps == 3) + } else if (numComps == 3) { return 'DeviceRgbCS'; - if (numComps == 4) + } else if (numComps == 4) { return 'DeviceCmykCS'; + } break; case 'Pattern': var basePatternCS = cs[1]; - if (basePatternCS) + if (basePatternCS) { basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res); + } return ['PatternCS', basePatternCS]; case 'Indexed': case 'I': @@ -1367,10 +1384,11 @@ var ColorSpace = (function ColorSpaceClosure() { case 'DeviceN': var name = cs[1]; var numComps = 1; - if (isName(name)) + if (isName(name)) { numComps = 1; - else if (isArray(name)) + } else if (isArray(name)) { numComps = name.length; + } var alt = ColorSpace.parseToIR(cs[2], xref, res); var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3])); return ['AlternateCS', numComps, alt, tintFnIR]; @@ -1395,16 +1413,18 @@ var ColorSpace = (function ColorSpaceClosure() { * @param {Number} n Number of components the color space has. */ ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) { - if (!decode) + if (!decode) { return true; + } if (n * 2 !== decode.length) { warn('The decode map is not the correct length'); return true; } for (var i = 0, ii = decode.length; i < ii; i += 2) { - if (decode[i] !== 0 || decode[i + 1] != 1) + if (decode[i] !== 0 || decode[i + 1] != 1) { return false; + } } return true; }; @@ -1531,8 +1551,9 @@ var IndexedCS = (function IndexedCSClosure() { lookupArray.set(bytes); } else if (isString(lookup)) { lookupArray = new Uint8Array(length); - for (var i = 0; i < length; ++i) + for (var i = 0; i < length; ++i) { lookupArray[i] = lookup.charCodeAt(i); + } } else if (lookup instanceof Uint8Array || lookup instanceof Array) { lookupArray = lookup; } else { @@ -1865,8 +1886,9 @@ var LabCS = (function LabCSClosure() { this.numComps = 3; this.defaultColor = new Float32Array([0, 0, 0]); - if (!whitePoint) + if (!whitePoint) { error('WhitePoint missing - required for color space Lab'); + } blackPoint = blackPoint || [0, 0, 0]; range = range || [-100, 100, -100, 100]; @@ -1886,8 +1908,9 @@ var LabCS = (function LabCSClosure() { this.ZB = blackPoint[2]; // Validate vars as per spec - if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { error('Invalid WhitePoint components, no fallback available'); + } if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { info('Invalid BlackPoint, falling back to default'); @@ -1905,10 +1928,11 @@ var LabCS = (function LabCSClosure() { // Function g(x) from spec function fn_g(x) { - if (x >= 6 / 29) + if (x >= 6 / 29) { return x * x * x; - else + } else { return (108 / 841) * (x - 4 / 29); + } } function decode(value, high1, low2, high2) { @@ -2006,8 +2030,9 @@ var PDFFunction = (function PDFFunctionClosure() { getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps, str) { var length = 1; - for (var i = 0, ii = size.length; i < ii; i++) + for (var i = 0, ii = size.length; i < ii; i++) { length *= size[i]; + } length *= outputSize; var array = []; @@ -2033,8 +2058,9 @@ var PDFFunction = (function PDFFunctionClosure() { getIR: function PDFFunction_getIR(xref, fn) { var dict = fn.dict; - if (!dict) + if (!dict) { dict = fn; + } var types = [this.constructSampled, null, @@ -2044,8 +2070,9 @@ var PDFFunction = (function PDFFunctionClosure() { var typeNum = dict.get('FunctionType'); var typeFn = types[typeNum]; - if (!typeFn) + if (!typeFn) { error('Unknown type of function'); + } return typeFn.call(this, fn, dict, xref); }, @@ -2085,8 +2112,9 @@ var PDFFunction = (function PDFFunctionClosure() { var domain = dict.get('Domain'); var range = dict.get('Range'); - if (!domain || !range) + if (!domain || !range) { error('No domain or range'); + } var inputSize = domain.length / 2; var outputSize = range.length / 2; @@ -2114,10 +2142,11 @@ var PDFFunction = (function PDFFunctionClosure() { encode = toMultiArray(encode); var decode = dict.get('Decode'); - if (!decode) + if (!decode) { decode = range; - else + } else { decode = toMultiArray(decode); + } var samples = this.getSampleArray(size, outputSize, bps, str); @@ -2145,9 +2174,10 @@ var PDFFunction = (function PDFFunctionClosure() { var mask = IR[8]; var range = IR[9]; - if (m != args.length) + if (m != args.length) { error('Incorrect number of arguments: ' + m + ' != ' + args.length); + } var x = args; @@ -2156,8 +2186,9 @@ var PDFFunction = (function PDFFunctionClosure() { var cubeVertices = 1 << m; var cubeN = new Float64Array(cubeVertices); var cubeVertex = new Uint32Array(cubeVertices); - for (var j = 0; j < cubeVertices; j++) + for (var j = 0; j < cubeVertices; j++) { cubeN[j] = 1; + } var k = n, pos = 1; // Map x_i to y_j for 0 <= i < m using the sampled function. @@ -2200,8 +2231,9 @@ var PDFFunction = (function PDFFunctionClosure() { for (var j = 0; j < n; ++j) { // Sum all cube vertices' samples portions var rj = 0; - for (var i = 0; i < cubeVertices; i++) + for (var i = 0; i < cubeVertices; i++) { rj += samples[cubeVertex[i] + j] * cubeN[i]; + } // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1, // Decode_2j, Decode_2j+1) @@ -2221,13 +2253,15 @@ var PDFFunction = (function PDFFunctionClosure() { var c1 = dict.get('C1') || [1]; var n = dict.get('N'); - if (!isArray(c0) || !isArray(c1)) + if (!isArray(c0) || !isArray(c1)) { error('Illegal dictionary for interpolated function'); + } var length = c0.length; var diff = []; - for (var i = 0; i < length; ++i) + for (var i = 0; i < length; ++i) { diff.push(c1[i] - c0[i]); + } return [CONSTRUCT_INTERPOLATED, c0, diff, n]; }, @@ -2244,8 +2278,9 @@ var PDFFunction = (function PDFFunctionClosure() { var x = n == 1 ? args[0] : Math.pow(args[0], n); var out = []; - for (var j = 0; j < length; ++j) + for (var j = 0; j < length; ++j) { out.push(c0[j] + (x * diff[j])); + } return out; @@ -2255,17 +2290,20 @@ var PDFFunction = (function PDFFunctionClosure() { constructStiched: function PDFFunction_constructStiched(fn, dict, xref) { var domain = dict.get('Domain'); - if (!domain) + if (!domain) { error('No domain'); + } var inputSize = domain.length / 2; - if (inputSize != 1) + if (inputSize != 1) { error('Bad domain for stiched function'); + } var fnRefs = dict.get('Functions'); var fns = []; - for (var i = 0, ii = fnRefs.length; i < ii; ++i) + for (var i = 0, ii = fnRefs.length; i < ii; ++i) { fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i]))); + } var bounds = dict.get('Bounds'); var encode = dict.get('Encode'); @@ -2286,10 +2324,11 @@ var PDFFunction = (function PDFFunctionClosure() { return function constructStichedFromIRResult(args) { var clip = function constructStichedFromIRClip(v, min, max) { - if (v > max) + if (v > max) { v = max; - else if (v < min) + } else if (v < min) { v = min; + } return v; }; @@ -2297,24 +2336,27 @@ var PDFFunction = (function PDFFunctionClosure() { var v = clip(args[0], domain[0], domain[1]); // calulate which bound the value is in for (var i = 0, ii = bounds.length; i < ii; ++i) { - if (v < bounds[i]) + if (v < bounds[i]) { break; + } } // encode value into domain of function var dmin = domain[0]; - if (i > 0) + if (i > 0) { dmin = bounds[i - 1]; + } var dmax = domain[1]; - if (i < bounds.length) + if (i < bounds.length) { dmax = bounds[i]; + } var rmin = encode[2 * i]; var rmax = encode[2 * i + 1]; var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin); - // call the appropropriate function + // call the appropriate function return fns[i]([v2]); }; }, @@ -2324,11 +2366,13 @@ var PDFFunction = (function PDFFunctionClosure() { var domain = dict.get('Domain'); var range = dict.get('Range'); - if (!domain) + if (!domain) { error('No domain.'); + } - if (!range) + if (!range) { error('No range.'); + } var lexer = new PostScriptLexer(fn); var parser = new PostScriptParser(lexer); @@ -2354,18 +2398,20 @@ var PDFFunction = (function PDFFunctionClosure() { } var key = initialStack.join('_'); - if (cache.has(key)) + if (cache.has(key)) { return cache.get(key); + } var stack = evaluator.execute(initialStack); var transformed = []; for (i = numOutputs - 1; i >= 0; --i) { var out = stack.pop(); var rangeIndex = 2 * i; - if (out < range[rangeIndex]) + if (out < range[rangeIndex]) { out = range[rangeIndex]; - else if (out > range[rangeIndex + 1]) + } else if (out > range[rangeIndex + 1]) { out = range[rangeIndex + 1]; + } transformed[i] = out; } cache.set(key, transformed); @@ -2408,21 +2454,25 @@ var PostScriptStack = (function PostScriptStackClosure() { PostScriptStack.prototype = { push: function PostScriptStack_push(value) { - if (this.stack.length >= MAX_STACK_SIZE) + if (this.stack.length >= MAX_STACK_SIZE) { error('PostScript function stack overflow.'); + } this.stack.push(value); }, pop: function PostScriptStack_pop() { - if (this.stack.length <= 0) + if (this.stack.length <= 0) { error('PostScript function stack underflow.'); + } return this.stack.pop(); }, copy: function PostScriptStack_copy(n) { - if (this.stack.length + n >= MAX_STACK_SIZE) + if (this.stack.length + n >= MAX_STACK_SIZE) { error('PostScript function stack overflow.'); + } var stack = this.stack; - for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) + for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) { stack.push(stack[i]); + } }, index: function PostScriptStack_index(n) { this.push(this.stack[this.stack.length - n - 1]); @@ -2468,8 +2518,9 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { case 'jz': // jump if false b = stack.pop(); a = stack.pop(); - if (!a) + if (!a) { counter = b; + } break; case 'j': // jump a = stack.pop(); @@ -2489,10 +2540,11 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { case 'and': b = stack.pop(); a = stack.pop(); - if (isBool(a) && isBool(b)) + if (isBool(a) && isBool(b)) { stack.push(a && b); - else + } else { stack.push(a & b); + } break; case 'atan': a = stack.pop(); @@ -2501,10 +2553,11 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { case 'bitshift': b = stack.pop(); a = stack.pop(); - if (a > 0) + if (a > 0) { stack.push(a << b); - else + } else { stack.push(a >> b); + } break; case 'ceiling': a = stack.pop(); @@ -2611,18 +2664,20 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { break; case 'not': a = stack.pop(); - if (isBool(a) && isBool(b)) + if (isBool(a) && isBool(b)) { stack.push(a && b); - else + } else { stack.push(a & b); + } break; case 'or': b = stack.pop(); a = stack.pop(); - if (isBool(a) && isBool(b)) + if (isBool(a) && isBool(b)) { stack.push(a || b); - else + } else { stack.push(a | b); + } break; case 'pop': stack.pop(); @@ -2660,10 +2715,11 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { case 'xor': b = stack.pop(); a = stack.pop(); - if (isBool(a) && isBool(b)) + if (isBool(a) && isBool(b)) { stack.push(a != b); - else + } else { stack.push(a ^ b); + } break; default: error('Unknown operator ' + operator); @@ -2677,6 +2733,9 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { })(); +var HIGHLIGHT_OFFSET = 4; // px +var SUPPORTED_TYPES = ['Link', 'Text', 'Widget']; + var Annotation = (function AnnotationClosure() { // 12.5.5: Algorithm: Appearance streams function getTransformMatrix(rect, bbox, matrix) { @@ -2799,25 +2858,50 @@ var Annotation = (function AnnotationClosure() { }, // TODO(mack): Remove this, it's not really that helpful. - getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect) { + getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect, + borderWidth) { assert(!isWorker, 'getEmptyContainer() should be called from main thread'); + var bWidth = borderWidth || 0; + rect = rect || this.data.rect; var element = document.createElement(tagName); - element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; - element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; + element.style.borderWidth = bWidth + 'px'; + var width = rect[2] - rect[0] - 2 * bWidth; + var height = rect[3] - rect[1] - 2 * bWidth; + element.style.width = width + 'px'; + element.style.height = height + 'px'; return element; }, + isInvisible: function Annotation_isInvisible() { + var data = this.data; + if (data && SUPPORTED_TYPES.indexOf(data.subtype) !== -1) { + return false; + } else { + return !!(data && + data.annotationFlags && // Default: not invisible + data.annotationFlags & 0x1); // Invisible + } + }, + isViewable: function Annotation_isViewable() { var data = this.data; - return !!( - data && - (!data.annotationFlags || - !(data.annotationFlags & 0x22)) && // Hidden or NoView - data.rect // rectangle is nessessary - ); + return !!(!this.isInvisible() && + data && + (!data.annotationFlags || + !(data.annotationFlags & 0x22)) && // Hidden or NoView + data.rect); // rectangle is nessessary + }, + + isPrintable: function Annotation_isPrintable() { + var data = this.data; + return !!(!this.isInvisible() && + data && + data.annotationFlags && // Default: not printable + data.annotationFlags & 0x4 && // Print + data.rect); // rectangle is nessessary }, loadResources: function(keys) { @@ -2838,7 +2922,7 @@ var Annotation = (function AnnotationClosure() { return promise; }, - getOperatorList: function Annotation_getToOperatorList(evaluator) { + getOperatorList: function Annotation_getOperatorList(evaluator) { var promise = new LegacyPromise(); @@ -2945,7 +3029,7 @@ var Annotation = (function AnnotationClosure() { var annotation = new Constructor(params); - if (annotation.isViewable()) { + if (annotation.isViewable() || annotation.isPrintable()) { return annotation; } else { warn('unimplemented annotation type: ' + subtype); @@ -2953,7 +3037,7 @@ var Annotation = (function AnnotationClosure() { }; Annotation.appendToOperatorList = function Annotation_appendToOperatorList( - annotations, opList, pdfManager, partialEvaluator) { + annotations, opList, pdfManager, partialEvaluator, intent) { function reject(e) { annotationsReadyPromise.reject(e); @@ -2963,7 +3047,11 @@ var Annotation = (function AnnotationClosure() { var annotationPromises = []; for (var i = 0, n = annotations.length; i < n; ++i) { - annotationPromises.push(annotations[i].getOperatorList(partialEvaluator)); + if (intent === 'display' && annotations[i].isViewable() || + intent === 'print' && annotations[i].isPrintable()) { + annotationPromises.push( + annotations[i].getOperatorList(partialEvaluator)); + } } Promise.all(annotationPromises).then(function(datas) { opList.addOp(OPS.beginAnnotations, []); @@ -3025,8 +3113,9 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() { var j, jj; for (j = 0, jj = kids.length; j < jj; j++) { var kidRef = kids[j]; - if (kidRef.num == ref.num && kidRef.gen == ref.gen) + if (kidRef.num == ref.num && kidRef.gen == ref.gen) { break; + } } fieldName.unshift('`' + j); } @@ -3175,9 +3264,64 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() { return TextWidgetAnnotation; })(); +var InteractiveAnnotation = (function InteractiveAnnotationClosure() { + function InteractiveAnnotation(params) { + Annotation.call(this, params); + } + + Util.inherit(InteractiveAnnotation, Annotation, { + hasHtml: function InteractiveAnnotation_hasHtml() { + return true; + }, + + highlight: function InteractiveAnnotation_highlight() { + if (this.highlightElement && + this.highlightElement.hasAttribute('hidden')) { + this.highlightElement.removeAttribute('hidden'); + } + }, + + unhighlight: function InteractiveAnnotation_unhighlight() { + if (this.highlightElement && + !this.highlightElement.hasAttribute('hidden')) { + this.highlightElement.setAttribute('hidden', true); + } + }, + + initContainer: function InteractiveAnnotation_initContainer() { + + var item = this.data; + var rect = item.rect; + + var container = this.getEmptyContainer('section', rect, item.borderWidth); + container.style.backgroundColor = item.color; + + var color = item.color; + var rgb = []; + for (var i = 0; i < 3; ++i) { + rgb[i] = Math.round(color[i] * 255); + } + item.colorCssRgb = Util.makeCssRgb(rgb); + + var highlight = document.createElement('div'); + highlight.className = 'annotationHighlight'; + highlight.style.left = highlight.style.top = -HIGHLIGHT_OFFSET + 'px'; + highlight.style.right = highlight.style.bottom = -HIGHLIGHT_OFFSET + 'px'; + highlight.setAttribute('hidden', true); + + this.highlightElement = highlight; + container.appendChild(this.highlightElement); + + return container; + } + }); + + return InteractiveAnnotation; +})(); + var TextAnnotation = (function TextAnnotationClosure() { function TextAnnotation(params) { - Annotation.call(this, params); + InteractiveAnnotation.call(this, params); if (params.data) { return; @@ -3190,22 +3334,21 @@ var TextAnnotation = (function TextAnnotationClosure() { var title = dict.get('T'); data.content = stringToPDFString(content || ''); data.title = stringToPDFString(title || ''); - data.name = !dict.has('Name') ? 'Note' : dict.get('Name').name; + + if (data.hasAppearance) { + data.name = 'NoIcon'; + } else { + data.name = dict.has('Name') ? dict.get('Name').name : 'Note'; + } + + if (dict.has('C')) { + data.hasBgColor = true; + } } var ANNOT_MIN_SIZE = 10; - Util.inherit(TextAnnotation, Annotation, { - - getOperatorList: function TextAnnotation_getOperatorList(evaluator) { - var promise = new LegacyPromise(); - promise.resolve(new OperatorList()); - return promise; - }, - - hasHtml: function TextAnnotation_hasHtml() { - return true; - }, + Util.inherit(TextAnnotation, InteractiveAnnotation, { getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) { assert(!isWorker, 'getHtmlElement() shall be called from main thread'); @@ -3221,23 +3364,40 @@ var TextAnnotation = (function TextAnnotationClosure() { rect[2] = rect[0] + (rect[3] - rect[1]); // make it square } - var container = this.getEmptyContainer('section', rect); + var container = this.initContainer(); container.className = 'annotText'; - var image = document.createElement('img'); + var image = document.createElement('img'); image.style.height = container.style.height; + image.style.width = container.style.width; var iconName = item.name; image.src = PDFJS.imageResourcesPath + 'annotation-' + iconName.toLowerCase() + '.svg'; image.alt = '[{{type}} Annotation]'; image.dataset.l10nId = 'text_annotation_type'; image.dataset.l10nArgs = JSON.stringify({type: iconName}); + + var contentWrapper = document.createElement('div'); + contentWrapper.className = 'annotTextContentWrapper'; + contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px'; + contentWrapper.style.top = '-10px'; + var content = document.createElement('div'); + content.className = 'annotTextContent'; content.setAttribute('hidden', true); + if (item.hasBgColor) { + var color = item.color; + var rgb = []; + for (var i = 0; i < 3; ++i) { + // Enlighten the color (70%) + var c = Math.round(color[i] * 255); + rgb[i] = Math.round((255 - c) * 0.7) + c; + } + content.style.backgroundColor = Util.makeCssRgb(rgb); + } + var title = document.createElement('h1'); var text = document.createElement('p'); - content.style.left = Math.floor(rect[2] - rect[0]) + 'px'; - content.style.top = '0px'; title.textContent = item.title; if (!item.content && !item.title) { @@ -3248,33 +3408,63 @@ var TextAnnotation = (function TextAnnotationClosure() { for (var i = 0, ii = lines.length; i < ii; ++i) { var line = lines[i]; e.appendChild(document.createTextNode(line)); - if (i < (ii - 1)) + if (i < (ii - 1)) { e.appendChild(document.createElement('br')); + } } text.appendChild(e); - var showAnnotation = function showAnnotation() { - container.style.zIndex += 1; - content.removeAttribute('hidden'); + var pinned = false; + + var showAnnotation = function showAnnotation(pin) { + if (pin) { + pinned = true; + } + if (content.hasAttribute('hidden')) { + container.style.zIndex += 1; + content.removeAttribute('hidden'); + } }; - var hideAnnotation = function hideAnnotation(e) { - if (e.toElement || e.relatedTarget) { // No context menu is used + var hideAnnotation = function hideAnnotation(unpin) { + if (unpin) { + pinned = false; + } + if (!content.hasAttribute('hidden') && !pinned) { container.style.zIndex -= 1; content.setAttribute('hidden', true); } }; - content.addEventListener('mouseover', showAnnotation, false); - content.addEventListener('mouseout', hideAnnotation, false); - image.addEventListener('mouseover', showAnnotation, false); - image.addEventListener('mouseout', hideAnnotation, false); + var toggleAnnotation = function toggleAnnotation() { + if (pinned) { + hideAnnotation(true); + } else { + showAnnotation(true); + } + }; + + var self = this; + image.addEventListener('click', function image_clickHandler() { + toggleAnnotation(); + }, false); + image.addEventListener('mouseover', function image_mouseOverHandler() { + showAnnotation(); + }, false); + image.addEventListener('mouseout', function image_mouseOutHandler() { + hideAnnotation(); + }, false); + + content.addEventListener('click', function content_clickHandler() { + hideAnnotation(true); + }, false); } content.appendChild(title); content.appendChild(text); + contentWrapper.appendChild(content); container.appendChild(image); - container.appendChild(content); + container.appendChild(contentWrapper); return container; } @@ -3285,7 +3475,7 @@ var TextAnnotation = (function TextAnnotationClosure() { var LinkAnnotation = (function LinkAnnotationClosure() { function LinkAnnotation(params) { - Annotation.call(this, params); + InteractiveAnnotation.call(this, params); if (params.data) { return; @@ -3348,36 +3538,28 @@ var LinkAnnotation = (function LinkAnnotationClosure() { return url; } - Util.inherit(LinkAnnotation, Annotation, { + Util.inherit(LinkAnnotation, InteractiveAnnotation, { hasOperatorList: function LinkAnnotation_hasOperatorList() { return false; }, - hasHtml: function LinkAnnotation_hasHtml() { - return true; - }, - getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) { - var rect = this.data.rect; - var element = document.createElement('a'); - var borderWidth = this.data.borderWidth; - element.style.borderWidth = borderWidth + 'px'; - var color = this.data.color; - var rgb = []; - for (var i = 0; i < 3; ++i) { - rgb[i] = Math.round(color[i] * 255); - } - element.style.borderColor = Util.makeCssRgb(rgb); - element.style.borderStyle = 'solid'; + var container = this.initContainer(); + container.className = 'annotLink'; - var width = rect[2] - rect[0] - 2 * borderWidth; - var height = rect[3] - rect[1] - 2 * borderWidth; - element.style.width = width + 'px'; - element.style.height = height + 'px'; + var item = this.data; + var rect = item.rect; - element.href = this.data.url || ''; - return element; + container.style.borderColor = item.colorCssRgb; + container.style.borderStyle = 'solid'; + + var link = document.createElement('a'); + link.href = link.title = this.data.url || ''; + + container.appendChild(link); + + return container; } }); @@ -3704,10 +3886,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() { this.stats.enabled = !!globalScope.PDFJS.enableStats; this.commonObjs = transport.commonObjs; this.objs = new PDFObjects(); - this.receivingOperatorList = false; this.cleanupAfterRender = false; this.pendingDestroy = false; - this.renderTasks = []; + this.intentStates = {}; } PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ { /** @@ -3786,12 +3967,21 @@ var PDFPageProxy = (function PDFPageProxyClosure() { // this call to render. this.pendingDestroy = false; + var renderingIntent = 'intent' in params ? + (params.intent == 'print' ? 'print' : 'display') : + 'display'; + + if (!this.intentStates[renderingIntent]) { + this.intentStates[renderingIntent] = {}; + } + var intentState = this.intentStates[renderingIntent]; + // If there is no displayReadyPromise yet, then the operatorList was never // requested before. Make the request and create the promise. - if (!this.displayReadyPromise) { - this.receivingOperatorList = true; - this.displayReadyPromise = new LegacyPromise(); - this.operatorList = { + if (!intentState.displayReadyPromise) { + intentState.receivingOperatorList = true; + intentState.displayReadyPromise = new LegacyPromise(); + intentState.operatorList = { fnArray: [], argsArray: [], lastChunk: false @@ -3799,18 +3989,23 @@ var PDFPageProxy = (function PDFPageProxyClosure() { this.stats.time('Page Request'); this.transport.messageHandler.send('RenderPageRequest', { - pageIndex: this.pageNumber - 1 + pageIndex: this.pageNumber - 1, + intent: renderingIntent }); } var internalRenderTask = new InternalRenderTask(complete, params, this.objs, this.commonObjs, - this.operatorList, this.pageNumber); - this.renderTasks.push(internalRenderTask); + intentState.operatorList, + this.pageNumber); + if (!intentState.renderTasks) { + intentState.renderTasks = []; + } + intentState.renderTasks.push(internalRenderTask); var renderTask = new RenderTask(internalRenderTask); var self = this; - this.displayReadyPromise.then( + intentState.displayReadyPromise.then( function pageDisplayReadyPromise(transparency) { if (self.pendingDestroy) { complete(); @@ -3826,9 +4021,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() { ); function complete(error) { - var i = self.renderTasks.indexOf(internalRenderTask); + var i = intentState.renderTasks.indexOf(internalRenderTask); if (i >= 0) { - self.renderTasks.splice(i, 1); + intentState.renderTasks.splice(i, 1); } if (self.cleanupAfterRender) { @@ -3876,14 +4071,17 @@ var PDFPageProxy = (function PDFPageProxyClosure() { */ _tryDestroy: function PDFPageProxy__destroy() { if (!this.pendingDestroy || - this.renderTasks.length !== 0 || - this.receivingOperatorList) { + Object.keys(this.intentStates).some(function(intent) { + var intentState = this.intentStates[intent]; + return intentState.renderTasks.length !== 0 || + intentState.receivingOperatorList; + }, this)) { return; } - delete this.operatorList; - delete this.displayReadyPromise; - delete this.annotationsPromise; + Object.keys(this.intentStates).forEach(function(intent) { + delete this.intentStates[intent]; + }, this); this.objs.clear(); this.pendingDestroy = false; }, @@ -3891,28 +4089,33 @@ var PDFPageProxy = (function PDFPageProxyClosure() { * For internal use only. * @ignore */ - _startRenderPage: function PDFPageProxy_startRenderPage(transparency) { - this.displayReadyPromise.resolve(transparency); + _startRenderPage: function PDFPageProxy_startRenderPage(transparency, + intent) { + var intentState = this.intentStates[intent]; + intentState.displayReadyPromise.resolve(transparency); }, /** * For internal use only. * @ignore */ - _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk) { + _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk, + intent) { + var intentState = this.intentStates[intent]; // Add the new chunk to the current operator list. for (var i = 0, ii = operatorListChunk.length; i < ii; i++) { - this.operatorList.fnArray.push(operatorListChunk.fnArray[i]); - this.operatorList.argsArray.push(operatorListChunk.argsArray[i]); + intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]); + intentState.operatorList.argsArray.push( + operatorListChunk.argsArray[i]); } - this.operatorList.lastChunk = operatorListChunk.lastChunk; + intentState.operatorList.lastChunk = operatorListChunk.lastChunk; // Notify all the rendering tasks there are more operators to be consumed. - for (var i = 0; i < this.renderTasks.length; i++) { - this.renderTasks[i].operatorListChanged(); + for (var i = 0; i < intentState.renderTasks.length; i++) { + intentState.renderTasks[i].operatorListChanged(); } if (operatorListChunk.lastChunk) { - this.receivingOperatorList = false; + intentState.receivingOperatorList = false; this._tryDestroy(); } } @@ -4128,13 +4331,13 @@ var WorkerTransport = (function WorkerTransportClosure() { var page = this.pageCache[data.pageIndex]; page.stats.timeEnd('Page Request'); - page._startRenderPage(data.transparency); + page._startRenderPage(data.transparency, data.intent); }, this); messageHandler.on('RenderPageChunk', function transportRender(data) { var page = this.pageCache[data.pageIndex]; - page._renderPageChunk(data.operatorList); + page._renderPageChunk(data.operatorList, data.intent); }, this); messageHandler.on('commonobj', function transportObj(data) { @@ -4177,8 +4380,9 @@ var WorkerTransport = (function WorkerTransportClosure() { var pageIndex = data[1]; var type = data[2]; var pageProxy = this.pageCache[pageIndex]; - if (pageProxy.objs.hasData(id)) + if (pageProxy.objs.hasData(id)) { return; + } switch (type) { case 'JpegStream': @@ -4214,10 +4418,11 @@ var WorkerTransport = (function WorkerTransportClosure() { this.workerReadyPromise.reject(data); }, this); - messageHandler.on('PageError', function transportError(data) { + messageHandler.on('PageError', function transportError(data, intent) { var page = this.pageCache[data.pageNum - 1]; - if (page.displayReadyPromise) - page.displayReadyPromise.reject(data.error); + var intentState = page.intentStates[intent]; + if (intentState.displayReadyPromise) + intentState.displayReadyPromise.reject(data.error); else error(data.error); }, this); @@ -4619,20 +4824,22 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() { if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in rdf = rdf.firstChild; - while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') + while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') { rdf = rdf.nextSibling; + } } var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null; - if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) + if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) { return; + } var children = rdf.childNodes, desc, entry, name, i, ii, length, iLength; - for (i = 0, length = children.length; i < length; i++) { desc = children[i]; - if (desc.nodeName.toLowerCase() !== 'rdf:description') + if (desc.nodeName.toLowerCase() !== 'rdf:description') { continue; + } for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) { if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') { @@ -5143,20 +5350,15 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { } else if (imgData.kind === ImageKind.RGBA_32BPP) { // RGBA, 32-bits per pixel. - var haveSetAndSubarray = 'set' in dest && 'subarray' in src; for (var i = 0; i < totalChunks; i++) { var thisChunkHeight = (i < fullChunks) ? fullChunkHeight : partialChunkHeight; var elemsInThisChunk = imgData.width * thisChunkHeight * 4; - if (haveSetAndSubarray) { - dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); - srcPos += elemsInThisChunk; - } else { - for (var j = 0; j < elemsInThisChunk; j++) { - dest[j] = src[srcPos++]; - } - } + + dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk)); + srcPos += elemsInThisChunk; + ctx.putImageData(chunkImgData, 0, i * fullChunkHeight); } @@ -7180,15 +7382,16 @@ var FontLoader = { insertRule: function fontLoaderInsertRule(rule) { var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG'); if (!styleElement) { - styleElement = document.createElement('style'); - styleElement.id = 'PDFJS_FONT_STYLE_TAG'; - document.documentElement.getElementsByTagName('head')[0].appendChild( - styleElement); + styleElement = document.createElement('style'); + styleElement.id = 'PDFJS_FONT_STYLE_TAG'; + document.documentElement.getElementsByTagName('head')[0].appendChild( + styleElement); } var styleSheet = styleElement.sheet; styleSheet.insertRule(rule, styleSheet.cssRules.length); }, + clear: function fontLoaderClear() { var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG'); if (styleElement) { @@ -7200,8 +7403,9 @@ var FontLoader = { for (var i = 0, ii = fonts.length; i < ii; i++) { var font = fonts[i]; - if (font.attached) + if (font.attached) { continue; + } font.attached = true; font.bindDOM() @@ -7225,8 +7429,9 @@ var FontFace = (function FontFaceClosure() { } FontFace.prototype = { bindDOM: function FontFace_bindDOM() { - if (!this.data) + if (!this.data) { return null; + } if (PDFJS.disableFontFace) { this.disableFontFace = true; @@ -7240,15 +7445,16 @@ var FontFace = (function FontFaceClosure() { var url = ('url(data:' + this.mimetype + ';base64,' + window.btoa(data) + ');'); var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}'; - FontLoader.insertRule(rule); if (PDFJS.pdfBug && 'FontInspector' in globalScope && - globalScope['FontInspector'].enabled) + globalScope['FontInspector'].enabled) { globalScope['FontInspector'].fontAdded(this, url); + } return rule; }, + getPathGenerator: function (objs, character) { if (!(character in this.compiledGlyphs)) { var js = objs.get(this.loadedName + '_path_' + character); diff --git a/browser/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js index bc3d6cff0261..927388405e8a 100644 --- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -21,8 +21,8 @@ if (typeof PDFJS === 'undefined') { (typeof window !== 'undefined' ? window : this).PDFJS = {}; } -PDFJS.version = '0.8.1114'; -PDFJS.build = 'ea9c8f8'; +PDFJS.version = '0.8.1181'; +PDFJS.build = '31ea4e0'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it @@ -225,8 +225,9 @@ function backtrace() { } function assert(cond, msg) { - if (!cond) + if (!cond) { error(msg); + } } var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = { @@ -257,10 +258,12 @@ var UnsupportedManager = PDFJS.UnsupportedManager = // Combines two URLs. The baseUrl shall be absolute URL. If the url is an // absolute URL, it will be returned as is. function combineUrl(baseUrl, url) { - if (!url) + if (!url) { return baseUrl; - if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) + } + if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) { return url; + } if (url.charAt(0) == '/') { // absolute path var i = baseUrl.indexOf('://'); @@ -309,8 +312,9 @@ PDFJS.isValidUrl = isValidUrl; // In a well-formed PDF, |cond| holds. If it doesn't, subsequent // behavior is undefined. function assertWellFormed(cond, msg) { - if (!cond) + if (!cond) { error(msg); + } } function shadow(obj, prop, value) { @@ -427,8 +431,9 @@ function bytesToString(bytes) { function stringToBytes(str) { var length = str.length; var bytes = new Uint8Array(length); - for (var n = 0; n < length; ++n) + for (var n = 0; n < length; ++n) { bytes[n] = str.charCodeAt(n) & 0xFF; + } return bytes; } @@ -832,14 +837,15 @@ function isRef(v) { function isPDFFunction(v) { var fnDict; - if (typeof v != 'object') + if (typeof v != 'object') { return false; - else if (isDict(v)) + } else if (isDict(v)) { fnDict = v; - else if (isStream(v)) + } else if (isStream(v)) { fnDict = v.dict; - else + } else { return false; + } return fnDict.has('FunctionType'); } @@ -908,8 +914,9 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() { var StatTimer = (function StatTimerClosure() { function rpad(str, pad, length) { - while (str.length < length) + while (str.length < length) { str += pad; + } return str; } function StatTimer() { @@ -919,17 +926,21 @@ var StatTimer = (function StatTimerClosure() { } StatTimer.prototype = { time: function StatTimer_time(name) { - if (!this.enabled) + if (!this.enabled) { return; - if (name in this.started) + } + if (name in this.started) { warn('Timer is already running for ' + name); + } this.started[name] = Date.now(); }, timeEnd: function StatTimer_timeEnd(name) { - if (!this.enabled) + if (!this.enabled) { return; - if (!(name in this.started)) + } + if (!(name in this.started)) { warn('Timer has not been started for ' + name); + } this.times.push({ 'name': name, 'start': this.started[name], @@ -945,8 +956,9 @@ var StatTimer = (function StatTimerClosure() { var longest = 0; for (var i = 0, ii = times.length; i < ii; ++i) { var name = times[i]['name']; - if (name.length > longest) + if (name.length > longest) { longest = name.length; + } } for (var i = 0, ii = times.length; i < ii; ++i) { var span = times[i]; @@ -960,8 +972,9 @@ var StatTimer = (function StatTimerClosure() { })(); PDFJS.createBlob = function createBlob(data, contentType) { - if (typeof Blob !== 'undefined') + if (typeof Blob !== 'undefined') { return new Blob([data], { type: contentType }); + } // Blob builder is deprecated in FF14 and removed in FF18. var bb = new MozBlobBuilder(); bb.append(data); @@ -1238,9 +1251,9 @@ var ColorSpace = (function ColorSpaceClosure() { ColorSpace.parse = function ColorSpace_parse(cs, xref, res) { var IR = ColorSpace.parseToIR(cs, xref, res); - if (IR instanceof AlternateCS) + if (IR instanceof AlternateCS) { return IR; - + } return ColorSpace.fromIR(IR); }; @@ -1261,8 +1274,9 @@ var ColorSpace = (function ColorSpaceClosure() { return new CalGrayCS(whitePoint, blackPoint, gamma); case 'PatternCS': var basePatternCS = IR[1]; - if (basePatternCS) + if (basePatternCS) { basePatternCS = ColorSpace.fromIR(basePatternCS); + } return new PatternCS(basePatternCS); case 'IndexedCS': var baseIndexedCS = IR[1]; @@ -1292,8 +1306,9 @@ var ColorSpace = (function ColorSpaceClosure() { var colorSpaces = res.get('ColorSpace'); if (isDict(colorSpaces)) { var refcs = colorSpaces.get(cs.name); - if (refcs) + if (refcs) { cs = refcs; + } } } @@ -1342,17 +1357,19 @@ var ColorSpace = (function ColorSpaceClosure() { var stream = xref.fetchIfRef(cs[1]); var dict = stream.dict; var numComps = dict.get('N'); - if (numComps == 1) + if (numComps == 1) { return 'DeviceGrayCS'; - if (numComps == 3) + } else if (numComps == 3) { return 'DeviceRgbCS'; - if (numComps == 4) + } else if (numComps == 4) { return 'DeviceCmykCS'; + } break; case 'Pattern': var basePatternCS = cs[1]; - if (basePatternCS) + if (basePatternCS) { basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res); + } return ['PatternCS', basePatternCS]; case 'Indexed': case 'I': @@ -1367,10 +1384,11 @@ var ColorSpace = (function ColorSpaceClosure() { case 'DeviceN': var name = cs[1]; var numComps = 1; - if (isName(name)) + if (isName(name)) { numComps = 1; - else if (isArray(name)) + } else if (isArray(name)) { numComps = name.length; + } var alt = ColorSpace.parseToIR(cs[2], xref, res); var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3])); return ['AlternateCS', numComps, alt, tintFnIR]; @@ -1395,16 +1413,18 @@ var ColorSpace = (function ColorSpaceClosure() { * @param {Number} n Number of components the color space has. */ ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) { - if (!decode) + if (!decode) { return true; + } if (n * 2 !== decode.length) { warn('The decode map is not the correct length'); return true; } for (var i = 0, ii = decode.length; i < ii; i += 2) { - if (decode[i] !== 0 || decode[i + 1] != 1) + if (decode[i] !== 0 || decode[i + 1] != 1) { return false; + } } return true; }; @@ -1531,8 +1551,9 @@ var IndexedCS = (function IndexedCSClosure() { lookupArray.set(bytes); } else if (isString(lookup)) { lookupArray = new Uint8Array(length); - for (var i = 0; i < length; ++i) + for (var i = 0; i < length; ++i) { lookupArray[i] = lookup.charCodeAt(i); + } } else if (lookup instanceof Uint8Array || lookup instanceof Array) { lookupArray = lookup; } else { @@ -1865,8 +1886,9 @@ var LabCS = (function LabCSClosure() { this.numComps = 3; this.defaultColor = new Float32Array([0, 0, 0]); - if (!whitePoint) + if (!whitePoint) { error('WhitePoint missing - required for color space Lab'); + } blackPoint = blackPoint || [0, 0, 0]; range = range || [-100, 100, -100, 100]; @@ -1886,8 +1908,9 @@ var LabCS = (function LabCSClosure() { this.ZB = blackPoint[2]; // Validate vars as per spec - if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { error('Invalid WhitePoint components, no fallback available'); + } if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { info('Invalid BlackPoint, falling back to default'); @@ -1905,10 +1928,11 @@ var LabCS = (function LabCSClosure() { // Function g(x) from spec function fn_g(x) { - if (x >= 6 / 29) + if (x >= 6 / 29) { return x * x * x; - else + } else { return (108 / 841) * (x - 4 / 29); + } } function decode(value, high1, low2, high2) { @@ -2006,8 +2030,9 @@ var PDFFunction = (function PDFFunctionClosure() { getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps, str) { var length = 1; - for (var i = 0, ii = size.length; i < ii; i++) + for (var i = 0, ii = size.length; i < ii; i++) { length *= size[i]; + } length *= outputSize; var array = []; @@ -2033,8 +2058,9 @@ var PDFFunction = (function PDFFunctionClosure() { getIR: function PDFFunction_getIR(xref, fn) { var dict = fn.dict; - if (!dict) + if (!dict) { dict = fn; + } var types = [this.constructSampled, null, @@ -2044,8 +2070,9 @@ var PDFFunction = (function PDFFunctionClosure() { var typeNum = dict.get('FunctionType'); var typeFn = types[typeNum]; - if (!typeFn) + if (!typeFn) { error('Unknown type of function'); + } return typeFn.call(this, fn, dict, xref); }, @@ -2085,8 +2112,9 @@ var PDFFunction = (function PDFFunctionClosure() { var domain = dict.get('Domain'); var range = dict.get('Range'); - if (!domain || !range) + if (!domain || !range) { error('No domain or range'); + } var inputSize = domain.length / 2; var outputSize = range.length / 2; @@ -2114,10 +2142,11 @@ var PDFFunction = (function PDFFunctionClosure() { encode = toMultiArray(encode); var decode = dict.get('Decode'); - if (!decode) + if (!decode) { decode = range; - else + } else { decode = toMultiArray(decode); + } var samples = this.getSampleArray(size, outputSize, bps, str); @@ -2145,9 +2174,10 @@ var PDFFunction = (function PDFFunctionClosure() { var mask = IR[8]; var range = IR[9]; - if (m != args.length) + if (m != args.length) { error('Incorrect number of arguments: ' + m + ' != ' + args.length); + } var x = args; @@ -2156,8 +2186,9 @@ var PDFFunction = (function PDFFunctionClosure() { var cubeVertices = 1 << m; var cubeN = new Float64Array(cubeVertices); var cubeVertex = new Uint32Array(cubeVertices); - for (var j = 0; j < cubeVertices; j++) + for (var j = 0; j < cubeVertices; j++) { cubeN[j] = 1; + } var k = n, pos = 1; // Map x_i to y_j for 0 <= i < m using the sampled function. @@ -2200,8 +2231,9 @@ var PDFFunction = (function PDFFunctionClosure() { for (var j = 0; j < n; ++j) { // Sum all cube vertices' samples portions var rj = 0; - for (var i = 0; i < cubeVertices; i++) + for (var i = 0; i < cubeVertices; i++) { rj += samples[cubeVertex[i] + j] * cubeN[i]; + } // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1, // Decode_2j, Decode_2j+1) @@ -2221,13 +2253,15 @@ var PDFFunction = (function PDFFunctionClosure() { var c1 = dict.get('C1') || [1]; var n = dict.get('N'); - if (!isArray(c0) || !isArray(c1)) + if (!isArray(c0) || !isArray(c1)) { error('Illegal dictionary for interpolated function'); + } var length = c0.length; var diff = []; - for (var i = 0; i < length; ++i) + for (var i = 0; i < length; ++i) { diff.push(c1[i] - c0[i]); + } return [CONSTRUCT_INTERPOLATED, c0, diff, n]; }, @@ -2244,8 +2278,9 @@ var PDFFunction = (function PDFFunctionClosure() { var x = n == 1 ? args[0] : Math.pow(args[0], n); var out = []; - for (var j = 0; j < length; ++j) + for (var j = 0; j < length; ++j) { out.push(c0[j] + (x * diff[j])); + } return out; @@ -2255,17 +2290,20 @@ var PDFFunction = (function PDFFunctionClosure() { constructStiched: function PDFFunction_constructStiched(fn, dict, xref) { var domain = dict.get('Domain'); - if (!domain) + if (!domain) { error('No domain'); + } var inputSize = domain.length / 2; - if (inputSize != 1) + if (inputSize != 1) { error('Bad domain for stiched function'); + } var fnRefs = dict.get('Functions'); var fns = []; - for (var i = 0, ii = fnRefs.length; i < ii; ++i) + for (var i = 0, ii = fnRefs.length; i < ii; ++i) { fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i]))); + } var bounds = dict.get('Bounds'); var encode = dict.get('Encode'); @@ -2286,10 +2324,11 @@ var PDFFunction = (function PDFFunctionClosure() { return function constructStichedFromIRResult(args) { var clip = function constructStichedFromIRClip(v, min, max) { - if (v > max) + if (v > max) { v = max; - else if (v < min) + } else if (v < min) { v = min; + } return v; }; @@ -2297,24 +2336,27 @@ var PDFFunction = (function PDFFunctionClosure() { var v = clip(args[0], domain[0], domain[1]); // calulate which bound the value is in for (var i = 0, ii = bounds.length; i < ii; ++i) { - if (v < bounds[i]) + if (v < bounds[i]) { break; + } } // encode value into domain of function var dmin = domain[0]; - if (i > 0) + if (i > 0) { dmin = bounds[i - 1]; + } var dmax = domain[1]; - if (i < bounds.length) + if (i < bounds.length) { dmax = bounds[i]; + } var rmin = encode[2 * i]; var rmax = encode[2 * i + 1]; var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin); - // call the appropropriate function + // call the appropriate function return fns[i]([v2]); }; }, @@ -2324,11 +2366,13 @@ var PDFFunction = (function PDFFunctionClosure() { var domain = dict.get('Domain'); var range = dict.get('Range'); - if (!domain) + if (!domain) { error('No domain.'); + } - if (!range) + if (!range) { error('No range.'); + } var lexer = new PostScriptLexer(fn); var parser = new PostScriptParser(lexer); @@ -2354,18 +2398,20 @@ var PDFFunction = (function PDFFunctionClosure() { } var key = initialStack.join('_'); - if (cache.has(key)) + if (cache.has(key)) { return cache.get(key); + } var stack = evaluator.execute(initialStack); var transformed = []; for (i = numOutputs - 1; i >= 0; --i) { var out = stack.pop(); var rangeIndex = 2 * i; - if (out < range[rangeIndex]) + if (out < range[rangeIndex]) { out = range[rangeIndex]; - else if (out > range[rangeIndex + 1]) + } else if (out > range[rangeIndex + 1]) { out = range[rangeIndex + 1]; + } transformed[i] = out; } cache.set(key, transformed); @@ -2408,21 +2454,25 @@ var PostScriptStack = (function PostScriptStackClosure() { PostScriptStack.prototype = { push: function PostScriptStack_push(value) { - if (this.stack.length >= MAX_STACK_SIZE) + if (this.stack.length >= MAX_STACK_SIZE) { error('PostScript function stack overflow.'); + } this.stack.push(value); }, pop: function PostScriptStack_pop() { - if (this.stack.length <= 0) + if (this.stack.length <= 0) { error('PostScript function stack underflow.'); + } return this.stack.pop(); }, copy: function PostScriptStack_copy(n) { - if (this.stack.length + n >= MAX_STACK_SIZE) + if (this.stack.length + n >= MAX_STACK_SIZE) { error('PostScript function stack overflow.'); + } var stack = this.stack; - for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) + for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) { stack.push(stack[i]); + } }, index: function PostScriptStack_index(n) { this.push(this.stack[this.stack.length - n - 1]); @@ -2468,8 +2518,9 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { case 'jz': // jump if false b = stack.pop(); a = stack.pop(); - if (!a) + if (!a) { counter = b; + } break; case 'j': // jump a = stack.pop(); @@ -2489,10 +2540,11 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { case 'and': b = stack.pop(); a = stack.pop(); - if (isBool(a) && isBool(b)) + if (isBool(a) && isBool(b)) { stack.push(a && b); - else + } else { stack.push(a & b); + } break; case 'atan': a = stack.pop(); @@ -2501,10 +2553,11 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { case 'bitshift': b = stack.pop(); a = stack.pop(); - if (a > 0) + if (a > 0) { stack.push(a << b); - else + } else { stack.push(a >> b); + } break; case 'ceiling': a = stack.pop(); @@ -2611,18 +2664,20 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { break; case 'not': a = stack.pop(); - if (isBool(a) && isBool(b)) + if (isBool(a) && isBool(b)) { stack.push(a && b); - else + } else { stack.push(a & b); + } break; case 'or': b = stack.pop(); a = stack.pop(); - if (isBool(a) && isBool(b)) + if (isBool(a) && isBool(b)) { stack.push(a || b); - else + } else { stack.push(a | b); + } break; case 'pop': stack.pop(); @@ -2660,10 +2715,11 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { case 'xor': b = stack.pop(); a = stack.pop(); - if (isBool(a) && isBool(b)) + if (isBool(a) && isBool(b)) { stack.push(a != b); - else + } else { stack.push(a ^ b); + } break; default: error('Unknown operator ' + operator); @@ -2677,6 +2733,9 @@ var PostScriptEvaluator = (function PostScriptEvaluatorClosure() { })(); +var HIGHLIGHT_OFFSET = 4; // px +var SUPPORTED_TYPES = ['Link', 'Text', 'Widget']; + var Annotation = (function AnnotationClosure() { // 12.5.5: Algorithm: Appearance streams function getTransformMatrix(rect, bbox, matrix) { @@ -2799,25 +2858,50 @@ var Annotation = (function AnnotationClosure() { }, // TODO(mack): Remove this, it's not really that helpful. - getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect) { + getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect, + borderWidth) { assert(!isWorker, 'getEmptyContainer() should be called from main thread'); + var bWidth = borderWidth || 0; + rect = rect || this.data.rect; var element = document.createElement(tagName); - element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; - element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; + element.style.borderWidth = bWidth + 'px'; + var width = rect[2] - rect[0] - 2 * bWidth; + var height = rect[3] - rect[1] - 2 * bWidth; + element.style.width = width + 'px'; + element.style.height = height + 'px'; return element; }, + isInvisible: function Annotation_isInvisible() { + var data = this.data; + if (data && SUPPORTED_TYPES.indexOf(data.subtype) !== -1) { + return false; + } else { + return !!(data && + data.annotationFlags && // Default: not invisible + data.annotationFlags & 0x1); // Invisible + } + }, + isViewable: function Annotation_isViewable() { var data = this.data; - return !!( - data && - (!data.annotationFlags || - !(data.annotationFlags & 0x22)) && // Hidden or NoView - data.rect // rectangle is nessessary - ); + return !!(!this.isInvisible() && + data && + (!data.annotationFlags || + !(data.annotationFlags & 0x22)) && // Hidden or NoView + data.rect); // rectangle is nessessary + }, + + isPrintable: function Annotation_isPrintable() { + var data = this.data; + return !!(!this.isInvisible() && + data && + data.annotationFlags && // Default: not printable + data.annotationFlags & 0x4 && // Print + data.rect); // rectangle is nessessary }, loadResources: function(keys) { @@ -2838,7 +2922,7 @@ var Annotation = (function AnnotationClosure() { return promise; }, - getOperatorList: function Annotation_getToOperatorList(evaluator) { + getOperatorList: function Annotation_getOperatorList(evaluator) { var promise = new LegacyPromise(); @@ -2945,7 +3029,7 @@ var Annotation = (function AnnotationClosure() { var annotation = new Constructor(params); - if (annotation.isViewable()) { + if (annotation.isViewable() || annotation.isPrintable()) { return annotation; } else { warn('unimplemented annotation type: ' + subtype); @@ -2953,7 +3037,7 @@ var Annotation = (function AnnotationClosure() { }; Annotation.appendToOperatorList = function Annotation_appendToOperatorList( - annotations, opList, pdfManager, partialEvaluator) { + annotations, opList, pdfManager, partialEvaluator, intent) { function reject(e) { annotationsReadyPromise.reject(e); @@ -2963,7 +3047,11 @@ var Annotation = (function AnnotationClosure() { var annotationPromises = []; for (var i = 0, n = annotations.length; i < n; ++i) { - annotationPromises.push(annotations[i].getOperatorList(partialEvaluator)); + if (intent === 'display' && annotations[i].isViewable() || + intent === 'print' && annotations[i].isPrintable()) { + annotationPromises.push( + annotations[i].getOperatorList(partialEvaluator)); + } } Promise.all(annotationPromises).then(function(datas) { opList.addOp(OPS.beginAnnotations, []); @@ -3025,8 +3113,9 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() { var j, jj; for (j = 0, jj = kids.length; j < jj; j++) { var kidRef = kids[j]; - if (kidRef.num == ref.num && kidRef.gen == ref.gen) + if (kidRef.num == ref.num && kidRef.gen == ref.gen) { break; + } } fieldName.unshift('`' + j); } @@ -3175,9 +3264,64 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() { return TextWidgetAnnotation; })(); +var InteractiveAnnotation = (function InteractiveAnnotationClosure() { + function InteractiveAnnotation(params) { + Annotation.call(this, params); + } + + Util.inherit(InteractiveAnnotation, Annotation, { + hasHtml: function InteractiveAnnotation_hasHtml() { + return true; + }, + + highlight: function InteractiveAnnotation_highlight() { + if (this.highlightElement && + this.highlightElement.hasAttribute('hidden')) { + this.highlightElement.removeAttribute('hidden'); + } + }, + + unhighlight: function InteractiveAnnotation_unhighlight() { + if (this.highlightElement && + !this.highlightElement.hasAttribute('hidden')) { + this.highlightElement.setAttribute('hidden', true); + } + }, + + initContainer: function InteractiveAnnotation_initContainer() { + + var item = this.data; + var rect = item.rect; + + var container = this.getEmptyContainer('section', rect, item.borderWidth); + container.style.backgroundColor = item.color; + + var color = item.color; + var rgb = []; + for (var i = 0; i < 3; ++i) { + rgb[i] = Math.round(color[i] * 255); + } + item.colorCssRgb = Util.makeCssRgb(rgb); + + var highlight = document.createElement('div'); + highlight.className = 'annotationHighlight'; + highlight.style.left = highlight.style.top = -HIGHLIGHT_OFFSET + 'px'; + highlight.style.right = highlight.style.bottom = -HIGHLIGHT_OFFSET + 'px'; + highlight.setAttribute('hidden', true); + + this.highlightElement = highlight; + container.appendChild(this.highlightElement); + + return container; + } + }); + + return InteractiveAnnotation; +})(); + var TextAnnotation = (function TextAnnotationClosure() { function TextAnnotation(params) { - Annotation.call(this, params); + InteractiveAnnotation.call(this, params); if (params.data) { return; @@ -3190,22 +3334,21 @@ var TextAnnotation = (function TextAnnotationClosure() { var title = dict.get('T'); data.content = stringToPDFString(content || ''); data.title = stringToPDFString(title || ''); - data.name = !dict.has('Name') ? 'Note' : dict.get('Name').name; + + if (data.hasAppearance) { + data.name = 'NoIcon'; + } else { + data.name = dict.has('Name') ? dict.get('Name').name : 'Note'; + } + + if (dict.has('C')) { + data.hasBgColor = true; + } } var ANNOT_MIN_SIZE = 10; - Util.inherit(TextAnnotation, Annotation, { - - getOperatorList: function TextAnnotation_getOperatorList(evaluator) { - var promise = new LegacyPromise(); - promise.resolve(new OperatorList()); - return promise; - }, - - hasHtml: function TextAnnotation_hasHtml() { - return true; - }, + Util.inherit(TextAnnotation, InteractiveAnnotation, { getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) { assert(!isWorker, 'getHtmlElement() shall be called from main thread'); @@ -3221,23 +3364,40 @@ var TextAnnotation = (function TextAnnotationClosure() { rect[2] = rect[0] + (rect[3] - rect[1]); // make it square } - var container = this.getEmptyContainer('section', rect); + var container = this.initContainer(); container.className = 'annotText'; - var image = document.createElement('img'); + var image = document.createElement('img'); image.style.height = container.style.height; + image.style.width = container.style.width; var iconName = item.name; image.src = PDFJS.imageResourcesPath + 'annotation-' + iconName.toLowerCase() + '.svg'; image.alt = '[{{type}} Annotation]'; image.dataset.l10nId = 'text_annotation_type'; image.dataset.l10nArgs = JSON.stringify({type: iconName}); + + var contentWrapper = document.createElement('div'); + contentWrapper.className = 'annotTextContentWrapper'; + contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px'; + contentWrapper.style.top = '-10px'; + var content = document.createElement('div'); + content.className = 'annotTextContent'; content.setAttribute('hidden', true); + if (item.hasBgColor) { + var color = item.color; + var rgb = []; + for (var i = 0; i < 3; ++i) { + // Enlighten the color (70%) + var c = Math.round(color[i] * 255); + rgb[i] = Math.round((255 - c) * 0.7) + c; + } + content.style.backgroundColor = Util.makeCssRgb(rgb); + } + var title = document.createElement('h1'); var text = document.createElement('p'); - content.style.left = Math.floor(rect[2] - rect[0]) + 'px'; - content.style.top = '0px'; title.textContent = item.title; if (!item.content && !item.title) { @@ -3248,33 +3408,63 @@ var TextAnnotation = (function TextAnnotationClosure() { for (var i = 0, ii = lines.length; i < ii; ++i) { var line = lines[i]; e.appendChild(document.createTextNode(line)); - if (i < (ii - 1)) + if (i < (ii - 1)) { e.appendChild(document.createElement('br')); + } } text.appendChild(e); - var showAnnotation = function showAnnotation() { - container.style.zIndex += 1; - content.removeAttribute('hidden'); + var pinned = false; + + var showAnnotation = function showAnnotation(pin) { + if (pin) { + pinned = true; + } + if (content.hasAttribute('hidden')) { + container.style.zIndex += 1; + content.removeAttribute('hidden'); + } }; - var hideAnnotation = function hideAnnotation(e) { - if (e.toElement || e.relatedTarget) { // No context menu is used + var hideAnnotation = function hideAnnotation(unpin) { + if (unpin) { + pinned = false; + } + if (!content.hasAttribute('hidden') && !pinned) { container.style.zIndex -= 1; content.setAttribute('hidden', true); } }; - content.addEventListener('mouseover', showAnnotation, false); - content.addEventListener('mouseout', hideAnnotation, false); - image.addEventListener('mouseover', showAnnotation, false); - image.addEventListener('mouseout', hideAnnotation, false); + var toggleAnnotation = function toggleAnnotation() { + if (pinned) { + hideAnnotation(true); + } else { + showAnnotation(true); + } + }; + + var self = this; + image.addEventListener('click', function image_clickHandler() { + toggleAnnotation(); + }, false); + image.addEventListener('mouseover', function image_mouseOverHandler() { + showAnnotation(); + }, false); + image.addEventListener('mouseout', function image_mouseOutHandler() { + hideAnnotation(); + }, false); + + content.addEventListener('click', function content_clickHandler() { + hideAnnotation(true); + }, false); } content.appendChild(title); content.appendChild(text); + contentWrapper.appendChild(content); container.appendChild(image); - container.appendChild(content); + container.appendChild(contentWrapper); return container; } @@ -3285,7 +3475,7 @@ var TextAnnotation = (function TextAnnotationClosure() { var LinkAnnotation = (function LinkAnnotationClosure() { function LinkAnnotation(params) { - Annotation.call(this, params); + InteractiveAnnotation.call(this, params); if (params.data) { return; @@ -3348,36 +3538,28 @@ var LinkAnnotation = (function LinkAnnotationClosure() { return url; } - Util.inherit(LinkAnnotation, Annotation, { + Util.inherit(LinkAnnotation, InteractiveAnnotation, { hasOperatorList: function LinkAnnotation_hasOperatorList() { return false; }, - hasHtml: function LinkAnnotation_hasHtml() { - return true; - }, - getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) { - var rect = this.data.rect; - var element = document.createElement('a'); - var borderWidth = this.data.borderWidth; - element.style.borderWidth = borderWidth + 'px'; - var color = this.data.color; - var rgb = []; - for (var i = 0; i < 3; ++i) { - rgb[i] = Math.round(color[i] * 255); - } - element.style.borderColor = Util.makeCssRgb(rgb); - element.style.borderStyle = 'solid'; + var container = this.initContainer(); + container.className = 'annotLink'; - var width = rect[2] - rect[0] - 2 * borderWidth; - var height = rect[3] - rect[1] - 2 * borderWidth; - element.style.width = width + 'px'; - element.style.height = height + 'px'; + var item = this.data; + var rect = item.rect; - element.href = this.data.url || ''; - return element; + container.style.borderColor = item.colorCssRgb; + container.style.borderStyle = 'solid'; + + var link = document.createElement('a'); + link.href = link.title = this.data.url || ''; + + container.appendChild(link); + + return container; } }); @@ -3553,6 +3735,8 @@ var ChunkedStream = (function ChunkedStreamClosure() { }, makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) { + this.ensureRange(start, start + length); + function ChunkedStreamSubstream() {} ChunkedStreamSubstream.prototype = Object.create(this); ChunkedStreamSubstream.prototype.getMissingChunks = function() { @@ -4179,7 +4363,7 @@ var Page = (function PageClosure() { }.bind(this)); return promise; }, - getOperatorList: function Page_getOperatorList(handler) { + getOperatorList: function Page_getOperatorList(handler, intent) { var self = this; var promise = new LegacyPromise(); @@ -4214,11 +4398,12 @@ var Page = (function PageClosure() { var contentStream = data[0]; - var opList = new OperatorList(handler, self.pageIndex); + var opList = new OperatorList(intent, handler, self.pageIndex); handler.send('StartRenderPage', { transparency: partialEvaluator.hasBlendModes(self.resources), - pageIndex: self.pageIndex + pageIndex: self.pageIndex, + intent: intent }); partialEvaluator.getOperatorList(contentStream, self.resources, opList); pageListPromise.resolve(opList); @@ -4236,7 +4421,7 @@ var Page = (function PageClosure() { } var annotationsReadyPromise = Annotation.appendToOperatorList( - annotations, pageOpList, pdfManager, partialEvaluator); + annotations, pageOpList, pdfManager, partialEvaluator, intent); annotationsReadyPromise.then(function () { pageOpList.flush(true); promise.resolve(pageOpList); @@ -12963,8 +13148,9 @@ var ARCFourCipher = (function ARCFourCipherClosure() { this.b = 0; var s = new Uint8Array(256); var i, j = 0, tmp, keyLength = key.length; - for (i = 0; i < 256; ++i) + for (i = 0; i < 256; ++i) { s[i] = i; + } for (i = 0; i < 256; ++i) { tmp = s[i]; j = (j + tmp + key[i % keyLength]) & 0xFF; @@ -13024,12 +13210,14 @@ var calculateMD5 = (function calculateMD5Closure() { var paddedLength = (length + 72) & ~63; // data + 9 extra bytes var padded = new Uint8Array(paddedLength); var i, j, n; - for (i = 0; i < length; ++i) + for (i = 0; i < length; ++i) { padded[i] = data[offset++]; + } padded[i++] = 0x80; n = paddedLength - 8; - while (i < n) + while (i < n) { padded[i++] = 0; + } padded[i++] = (length << 3) & 0xFF; padded[i++] = (length >> 5) & 0xFF; padded[i++] = (length >> 13) & 0xFF; @@ -13073,18 +13261,17 @@ var calculateMD5 = (function calculateMD5Closure() { h3 = (h3 + d) | 0; } return new Uint8Array([ - h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF, - h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF, - h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF, - h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF + h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF, + h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF, + h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF, + h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF ]); } return hash; })(); var NullCipher = (function NullCipherClosure() { - function NullCipher() { - } + function NullCipher() {} NullCipher.prototype = { decryptBlock: function NullCipher_decryptBlock(data) { @@ -13240,8 +13427,9 @@ var AES128Cipher = (function AES128CipherClosure() { var i, j, k; var t, u, v; // AddRoundKey - for (j = 0, k = 160; j < 16; ++j, ++k) + for (j = 0, k = 160; j < 16; ++j, ++k) { state[j] ^= key[k]; + } for (i = 9; i >= 1; --i) { // InvShiftRows t = state[13]; state[13] = state[9]; state[9] = state[5]; @@ -13251,11 +13439,13 @@ var AES128Cipher = (function AES128CipherClosure() { t = state[15]; u = state[11]; v = state[7]; state[15] = state[3]; state[11] = t; state[7] = u; state[3] = v; // InvSubBytes - for (j = 0; j < 16; ++j) + for (j = 0; j < 16; ++j) { state[j] = inv_s[state[j]]; + } // AddRoundKey - for (j = 0, k = i * 16; j < 16; ++j, ++k) + for (j = 0, k = i * 16; j < 16; ++j, ++k) { state[j] ^= key[k]; + } // InvMixColumns for (j = 0; j < 16; j += 4) { var s0 = mix[state[j]], s1 = mix[state[j + 1]], @@ -13297,13 +13487,15 @@ var AES128Cipher = (function AES128CipherClosure() { for (i = 0; i < sourceLength; ++i) { buffer[bufferLength] = data[i]; ++bufferLength; - if (bufferLength < 16) + if (bufferLength < 16) { continue; + } // buffer is full, decrypting var plain = decrypt128(buffer, this.key); // xor-ing the IV vector to get plain text - for (j = 0; j < 16; ++j) + for (j = 0; j < 16; ++j) { plain[j] ^= iv[j]; + } iv = buffer; result.push(plain); buffer = new Uint8Array(16); @@ -13325,8 +13517,9 @@ var AES128Cipher = (function AES128CipherClosure() { result[result.length - 1] = lastBlock.subarray(0, 16 - lastBlock[15]); } var output = new Uint8Array(outputLength); - for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) + for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) { output.set(result[i], j); + } return output; } @@ -13335,8 +13528,9 @@ var AES128Cipher = (function AES128CipherClosure() { var i, sourceLength = data.length; var buffer = this.buffer, bufferLength = this.bufferPosition; // waiting for IV values -- they are at the start of the stream - for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) + for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) { buffer[bufferLength] = data[i]; + } if (bufferLength < 16) { // need more data this.bufferLength = bufferLength; @@ -13391,22 +13585,25 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { var hashData = new Uint8Array(hashDataSize), i = 0, j, n; if (password) { n = Math.min(32, password.length); - for (; i < n; ++i) + for (; i < n; ++i) { hashData[i] = password[i]; + } } j = 0; while (i < 32) { hashData[i++] = defaultPasswordBytes[j++]; } // as now the padded password in the hashData[0..i] - for (j = 0, n = ownerPassword.length; j < n; ++j) + for (j = 0, n = ownerPassword.length; j < n; ++j) { hashData[i++] = ownerPassword[j]; + } hashData[i++] = flags & 0xFF; hashData[i++] = (flags >> 8) & 0xFF; hashData[i++] = (flags >> 16) & 0xFF; hashData[i++] = (flags >>> 24) & 0xFF; - for (j = 0, n = fileId.length; j < n; ++j) + for (j = 0, n = fileId.length; j < n; ++j) { hashData[i++] = fileId[j]; + } if (revision >= 4 && !encryptMetadata) { hashData[i++] = 0xFF; hashData[i++] = 0xFF; @@ -13417,46 +13614,53 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { var keyLengthInBytes = keyLength >> 3; if (revision >= 3) { for (j = 0; j < 50; ++j) { - hash = calculateMD5(hash, 0, keyLengthInBytes); + hash = calculateMD5(hash, 0, keyLengthInBytes); } } var encryptionKey = hash.subarray(0, keyLengthInBytes); var cipher, checkData; if (revision >= 3) { - for (i = 0; i < 32; ++i) + for (i = 0; i < 32; ++i) { hashData[i] = defaultPasswordBytes[i]; - for (j = 0, n = fileId.length; j < n; ++j) + } + for (j = 0, n = fileId.length; j < n; ++j) { hashData[i++] = fileId[j]; + } cipher = new ARCFourCipher(encryptionKey); var checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i)); n = encryptionKey.length; var derivedKey = new Uint8Array(n), k; for (j = 1; j <= 19; ++j) { - for (k = 0; k < n; ++k) + for (k = 0; k < n; ++k) { derivedKey[k] = encryptionKey[k] ^ j; + } cipher = new ARCFourCipher(derivedKey); checkData = cipher.encryptBlock(checkData); } for (j = 0, n = checkData.length; j < n; ++j) { - if (userPassword[j] != checkData[j]) + if (userPassword[j] != checkData[j]) { return null; + } } } else { cipher = new ARCFourCipher(encryptionKey); checkData = cipher.encryptBlock(defaultPasswordBytes); for (j = 0, n = checkData.length; j < n; ++j) { - if (userPassword[j] != checkData[j]) + if (userPassword[j] != checkData[j]) { return null; + } } } return encryptionKey; } + function decodeUserPassword(password, ownerPassword, revision, keyLength) { var hashData = new Uint8Array(32), i = 0, j, n; n = Math.min(32, password.length); - for (; i < n; ++i) + for (; i < n; ++i) { hashData[i] = password[i]; + } j = 0; while (i < 32) { hashData[i++] = defaultPasswordBytes[j++]; @@ -13465,7 +13669,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { var keyLengthInBytes = keyLength >> 3; if (revision >= 3) { for (j = 0; j < 50; ++j) { - hash = calculateMD5(hash, 0, hash.length); + hash = calculateMD5(hash, 0, hash.length); } } @@ -13474,8 +13678,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { userPassword = ownerPassword; var derivedKey = new Uint8Array(keyLengthInBytes), k; for (j = 19; j >= 0; j--) { - for (k = 0; k < keyLengthInBytes; ++k) + for (k = 0; k < keyLengthInBytes; ++k) { derivedKey[k] = hash[k] ^ j; + } cipher = new ARCFourCipher(derivedKey); userPassword = cipher.encryptBlock(userPassword); } @@ -13490,31 +13695,36 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { function CipherTransformFactory(dict, fileId, password) { var filter = dict.get('Filter'); - if (!isName(filter) || filter.name != 'Standard') + if (!isName(filter) || filter.name != 'Standard') { error('unknown encryption method'); + } this.dict = dict; var algorithm = dict.get('V'); if (!isInt(algorithm) || - (algorithm != 1 && algorithm != 2 && algorithm != 4)) + (algorithm != 1 && algorithm != 2 && algorithm != 4)) { error('unsupported encryption algorithm'); + } this.algorithm = algorithm; var keyLength = dict.get('Length') || 40; if (!isInt(keyLength) || - keyLength < 40 || (keyLength % 8) !== 0) + keyLength < 40 || (keyLength % 8) !== 0) { error('invalid key length'); + } + // prepare keys var ownerPassword = stringToBytes(dict.get('O')).subarray(0, 32); var userPassword = stringToBytes(dict.get('U')).subarray(0, 32); var flags = dict.get('P'); var revision = dict.get('R'); - var encryptMetadata = algorithm == 4 && // meaningful when V is 4 - dict.get('EncryptMetadata') !== false; // makes true as default value + var encryptMetadata = (algorithm == 4 && // meaningful when V is 4 + dict.get('EncryptMetadata') !== false); // makes true as default value this.encryptMetadata = encryptMetadata; var fileIdBytes = stringToBytes(fileId); var passwordBytes; - if (password) + if (password) { passwordBytes = stringToBytes(password); + } var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, ownerPassword, userPassword, flags, @@ -13531,9 +13741,10 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { revision, keyLength, encryptMetadata); } - if (!encryptionKey) + if (!encryptionKey) { throw new PasswordException('Incorrect Password', PasswordResponses.INCORRECT_PASSWORD); + } this.encryptionKey = encryptionKey; @@ -13547,8 +13758,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { function buildObjectKey(num, gen, encryptionKey, isAes) { var key = new Uint8Array(encryptionKey.length + 9), i, n; - for (i = 0, n = encryptionKey.length; i < n; ++i) + for (i = 0, n = encryptionKey.length; i < n; ++i) { key[i] = encryptionKey[i]; + } key[i++] = num & 0xFF; key[i++] = (num >> 8) & 0xFF; key[i++] = (num >> 16) & 0xFF; @@ -13567,8 +13779,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { function buildCipherConstructor(cf, name, num, gen, key) { var cryptFilter = cf.get(name.name); var cfm; - if (cryptFilter !== null && cryptFilter !== undefined) + if (cryptFilter !== null && cryptFilter !== undefined) { cfm = cryptFilter.get('CFM'); + } if (!cfm || cfm.name == 'None') { return function cipherTransformFactoryBuildCipherConstructorNone() { return new NullCipher(); @@ -13576,14 +13789,12 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { } if ('V2' == cfm.name) { return function cipherTransformFactoryBuildCipherConstructorV2() { - return new ARCFourCipher( - buildObjectKey(num, gen, key, false)); + return new ARCFourCipher(buildObjectKey(num, gen, key, false)); }; } if ('AESV2' == cfm.name) { return function cipherTransformFactoryBuildCipherConstructorAESV2() { - return new AES128Cipher( - buildObjectKey(num, gen, key, true)); + return new AES128Cipher(buildObjectKey(num, gen, key, true)); }; } error('Unknown crypto method'); @@ -13595,9 +13806,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { if (this.algorithm == 4) { return new CipherTransform( buildCipherConstructor(this.cf, this.stmf, - num, gen, this.encryptionKey), + num, gen, this.encryptionKey), buildCipherConstructor(this.cf, this.strf, - num, gen, this.encryptionKey)); + num, gen, this.encryptionKey)); } // algorithms 1 and 2 var key = buildObjectKey(num, gen, this.encryptionKey, false); @@ -14535,10 +14746,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { var bitStrideLength = (width + 7) >> 3; var imgArray = image.getBytes(bitStrideLength * height); var decode = dict.get('Decode', 'D'); + var canTransfer = image instanceof DecodeStream; var inverseDecode = !!decode && decode[0] > 0; operatorList.addOp(OPS.paintImageMaskXObject, - [PDFImage.createMask(imgArray, width, height, inverseDecode)] + [PDFImage.createMask(imgArray, width, height, canTransfer, + inverseDecode)] ); return; } @@ -15765,7 +15978,7 @@ var OperatorList = (function OperatorListClosure() { } - function OperatorList(messageHandler, pageIndex) { + function OperatorList(intent, messageHandler, pageIndex) { this.messageHandler = messageHandler; // When there isn't a message handler the fn array needs to be able to grow // since we can't flush the operators. @@ -15778,6 +15991,7 @@ var OperatorList = (function OperatorListClosure() { this.dependencies = {}; this.pageIndex = pageIndex; this.fnIndex = 0; + this.intent = intent; } OperatorList.prototype = { @@ -15838,7 +16052,8 @@ var OperatorList = (function OperatorListClosure() { lastChunk: lastChunk, length: this.length }, - pageIndex: this.pageIndex + pageIndex: this.pageIndex, + intent: this.intent }, null, transfers); this.dependencies = []; this.fnIndex = 0; @@ -19787,9 +20002,11 @@ var Font = (function FontClosure() { } --ifLevel; } else if (op === 0x1C) { // JMPR - var offset = stack[stack.length - 1]; - // only jumping forward to prevent infinite loop - if (offset > 0) { i += offset - 1; } + if (!inFDEF && !inELSE) { + var offset = stack[stack.length - 1]; + // only jumping forward to prevent infinite loop + if (offset > 0) { i += offset - 1; } + } } // Adjusting stack not extactly, but just enough to get function id if (!inFDEF && !inELSE) { @@ -28386,19 +28603,25 @@ var PDFImage = (function PDFImageClosure() { return temp; }; - PDFImage.createMask = function PDFImage_createMask(imgArray, width, height, - inverseDecode) { - // Copy imgArray into a typed array (inverting if necessary) so it can be - // transferred to the main thread. - var length = ((width + 7) >> 3) * height; - var data = new Uint8Array(length); - if (inverseDecode) { - for (var i = 0; i < length; i++) { - data[i] = ~imgArray[i]; - } + PDFImage.createMask = + function PDFImage_createMask(imgArray, width, height, canTransfer, + inverseDecode) { + // If imgArray came from a DecodeStream, we're safe to transfer it. + // Otherwise, copy it. + var actualLength = imgArray.byteLength; + var data; + if (canTransfer) { + data = imgArray; } else { - for (var i = 0; i < length; i++) { - data[i] = imgArray[i]; + data = new Uint8Array(actualLength); + data.set(imgArray); + } + // Invert if necessary. It's safe to modify the array -- whether it's the + // original or a copy, we're about to transfer it anyway, so nothing else + // in this thread can be relying on its contents. + if (inverseDecode) { + for (var i = 0; i < actualLength; i++) { + data[i] = ~data[i]; } } @@ -28407,14 +28630,14 @@ var PDFImage = (function PDFImageClosure() { PDFImage.prototype = { get drawWidth() { - if (!this.smask) - return this.width; - return Math.max(this.width, this.smask.width); + return Math.max(this.width, + this.smask && this.smask.width || 0, + this.mask && this.mask.width || 0); }, get drawHeight() { - if (!this.smask) - return this.height; - return Math.max(this.height, this.smask.height); + return Math.max(this.height, + this.smask && this.smask.height || 0, + this.mask && this.mask.height || 0); }, decodeBuffer: function PDFImage_decodeBuffer(buffer) { var bpc = this.bpc; @@ -31887,7 +32110,7 @@ var Parser = (function ParserClosure() { while (stream.pos < stream.end) { var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE); var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH; - var found = false, i, ii, j; + var found = false, i, j; for (i = 0, j = 0; i < scanLength; i++) { var b = scanBytes[i]; if (b !== ENDSTREAM_SIGNATURE[j]) { @@ -31896,6 +32119,7 @@ var Parser = (function ParserClosure() { } else { j++; if (j >= ENDSTREAM_SIGNATURE_LENGTH) { + i++; found = true; break; } @@ -31971,12 +32195,10 @@ var Parser = (function ParserClosure() { return new LZWStream(stream, earlyChange); } if (name == 'DCTDecode' || name == 'DCT') { - var bytes = stream.getBytes(length); - return new JpegStream(bytes, stream.dict, this.xref); + return new JpegStream(stream, length, stream.dict, this.xref); } if (name == 'JPXDecode' || name == 'JPX') { - var bytes = stream.getBytes(length); - return new JpxStream(bytes, stream.dict); + return new JpxStream(stream, length, stream.dict); } if (name == 'ASCII85Decode' || name == 'A85') { return new Ascii85Stream(stream); @@ -31991,8 +32213,7 @@ var Parser = (function ParserClosure() { return new RunLengthStream(stream); } if (name == 'JBIG2Decode') { - var bytes = stream.getBytes(length); - return new Jbig2Stream(bytes, stream.dict); + return new Jbig2Stream(stream, length, stream.dict); } warn('filter "' + name + '" not supported yet'); return stream; @@ -32507,8 +32728,9 @@ var PostScriptParser = (function PostScriptParserClosure() { return false; }, expect: function PostScriptParser_expect(type) { - if (this.accept(type)) + if (this.accept(type)) { return true; + } error('Unexpected symbol: found ' + this.token.type + ' expected ' + type + '.'); }, @@ -32585,9 +32807,9 @@ var PostScriptToken = (function PostScriptTokenClosure() { PostScriptToken.getOperator = function PostScriptToken_getOperator(op) { var opValue = opCache[op]; - if (opValue) + if (opValue) { return opValue; - + } return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op); }; @@ -32636,8 +32858,8 @@ var PostScriptLexer = (function PostScriptLexerClosure() { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4' case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9' case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.' - return new PostScriptToken(PostScriptTokenTypes.NUMBER, - this.getNumber()); + return new PostScriptToken(PostScriptTokenTypes.NUMBER, + this.getNumber()); case 0x7B: // '{' this.nextChar(); return PostScriptToken.LBRACE; @@ -32648,7 +32870,7 @@ var PostScriptLexer = (function PostScriptLexerClosure() { // operator var str = String.fromCharCode(ch); while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z' - ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { + ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { str += String.fromCharCode(ch); } switch (str.toLowerCase()) { @@ -32665,15 +32887,16 @@ var PostScriptLexer = (function PostScriptLexerClosure() { var str = String.fromCharCode(ch); while ((ch = this.nextChar()) >= 0) { if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9' - ch === 0x2D || ch === 0x2E) { // '-', '.' + ch === 0x2D || ch === 0x2E) { // '-', '.' str += String.fromCharCode(ch); } else { break; } } var value = parseFloat(str); - if (isNaN(value)) + if (isNaN(value)) { error('Invalid floating point number: ' + value); + } return value; } }; @@ -32780,11 +33003,13 @@ var DecodeStream = (function DecodeStreamClosure() { current = 0; } var size = 512; - while (size < requested) - size <<= 1; + while (size < requested) { + size *= 2; + } var buffer2 = new Uint8Array(size); - for (var i = 0; i < current; ++i) + for (var i = 0; i < current; ++i) { buffer2[i] = buffer[i]; + } return (this.buffer = buffer2); }, getByte: function DecodeStream_getByte() { @@ -32988,13 +33213,12 @@ var FlateStream = (function FlateStreamClosure() { 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000 ]), 5]; - function FlateStream(stream) { - var bytes = stream.getBytes(); - var bytesPos = 0; + function FlateStream(str) { + this.str = str; + this.dict = str.dict; - this.dict = stream.dict; - var cmf = bytes[bytesPos++]; - var flg = bytes[bytesPos++]; + var cmf = str.getByte(); + var flg = str.getByte(); if (cmf == -1 || flg == -1) error('Invalid header in flate stream: ' + cmf + ', ' + flg); if ((cmf & 0x0f) != 0x08) @@ -33004,9 +33228,6 @@ var FlateStream = (function FlateStreamClosure() { if (flg & 0x20) error('FDICT bit set in flate stream: ' + cmf + ', ' + flg); - this.bytes = bytes; - this.bytesPos = bytesPos; - this.codeSize = 0; this.codeBuf = 0; @@ -33016,37 +33237,37 @@ var FlateStream = (function FlateStreamClosure() { FlateStream.prototype = Object.create(DecodeStream.prototype); FlateStream.prototype.getBits = function FlateStream_getBits(bits) { + var str = this.str; var codeSize = this.codeSize; var codeBuf = this.codeBuf; - var bytes = this.bytes; - var bytesPos = this.bytesPos; var b; while (codeSize < bits) { - if (typeof (b = bytes[bytesPos++]) == 'undefined') + if ((b = str.getByte()) === -1) { error('Bad encoding in flate stream'); + } codeBuf |= b << codeSize; codeSize += 8; } b = codeBuf & ((1 << bits) - 1); this.codeBuf = codeBuf >> bits; this.codeSize = codeSize -= bits; - this.bytesPos = bytesPos; + return b; }; FlateStream.prototype.getCode = function FlateStream_getCode(table) { + var str = this.str; var codes = table[0]; var maxLen = table[1]; var codeSize = this.codeSize; var codeBuf = this.codeBuf; - var bytes = this.bytes; - var bytesPos = this.bytesPos; while (codeSize < maxLen) { var b; - if (typeof (b = bytes[bytesPos++]) == 'undefined') + if ((b = str.getByte()) === -1) { error('Bad encoding in flate stream'); + } codeBuf |= (b << codeSize); codeSize += 8; } @@ -33057,7 +33278,6 @@ var FlateStream = (function FlateStreamClosure() { error('Bad encoding in flate stream'); this.codeBuf = (codeBuf >> codeLen); this.codeSize = (codeSize - codeLen); - this.bytesPos = bytesPos; return codeVal; }; @@ -33101,6 +33321,7 @@ var FlateStream = (function FlateStreamClosure() { }; FlateStream.prototype.readBlock = function FlateStream_readBlock() { + var str = this.str; // read block header var hdr = this.getBits(3); if (hdr & 1) @@ -33108,21 +33329,23 @@ var FlateStream = (function FlateStreamClosure() { hdr >>= 1; if (hdr === 0) { // uncompressed block - var bytes = this.bytes; - var bytesPos = this.bytesPos; var b; - if (typeof (b = bytes[bytesPos++]) == 'undefined') + if ((b = str.getByte()) === -1) { error('Bad block header in flate stream'); + } var blockLen = b; - if (typeof (b = bytes[bytesPos++]) == 'undefined') + if ((b = str.getByte()) === -1) { error('Bad block header in flate stream'); + } blockLen |= (b << 8); - if (typeof (b = bytes[bytesPos++]) == 'undefined') + if ((b = str.getByte()) === -1) { error('Bad block header in flate stream'); + } var check = b; - if (typeof (b = bytes[bytesPos++]) == 'undefined') + if ((b = str.getByte()) === -1) { error('Bad block header in flate stream'); + } check |= (b << 8); if (check != (~blockLen & 0xffff) && (blockLen !== 0 || check !== 0)) { @@ -33138,19 +33361,18 @@ var FlateStream = (function FlateStreamClosure() { var end = bufferLength + blockLen; this.bufferLength = end; if (blockLen === 0) { - if (typeof bytes[bytesPos] == 'undefined') { + if (str.peekBytes(1).length === 0) { this.eof = true; } } else { for (var n = bufferLength; n < end; ++n) { - if (typeof (b = bytes[bytesPos++]) == 'undefined') { + if ((b = str.getByte()) === -1) { this.eof = true; break; } buffer[n] = b; } } - this.bytesPos = bytesPos; return; } @@ -33437,17 +33659,25 @@ var PredictorStream = (function PredictorStreamClosure() { * DecodeStreams. */ var JpegStream = (function JpegStreamClosure() { - function JpegStream(bytes, dict, xref) { + function JpegStream(stream, length, dict, xref) { // TODO: per poppler, some images may have 'junk' before that // need to be removed + this.stream = stream; + this.length = length; this.dict = dict; - this.bytes = bytes; DecodeStream.call(this); } JpegStream.prototype = Object.create(DecodeStream.prototype); + Object.defineProperty(JpegStream.prototype, 'bytes', { + get: function JpegStream_bytes() { + return shadow(this, 'bytes', this.stream.getBytes(this.length)); + }, + configurable: true + }); + JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) { if (this.bufferLength) return; @@ -33496,15 +33726,23 @@ var JpegStream = (function JpegStreamClosure() { * the stream behaves like all the other DecodeStreams. */ var JpxStream = (function JpxStreamClosure() { - function JpxStream(bytes, dict) { + function JpxStream(stream, length, dict) { + this.stream = stream; + this.length = length; this.dict = dict; - this.bytes = bytes; DecodeStream.call(this); } JpxStream.prototype = Object.create(DecodeStream.prototype); + Object.defineProperty(JpxStream.prototype, 'bytes', { + get: function JpxStream_bytes() { + return shadow(this, 'bytes', this.stream.getBytes(this.length)); + }, + configurable: true + }); + JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) { if (this.bufferLength) return; @@ -33595,15 +33833,23 @@ var JpxStream = (function JpxStreamClosure() { * the stream behaves like all the other DecodeStreams. */ var Jbig2Stream = (function Jbig2StreamClosure() { - function Jbig2Stream(bytes, dict) { + function Jbig2Stream(stream, length, dict) { + this.stream = stream; + this.length = length; this.dict = dict; - this.bytes = bytes; DecodeStream.call(this); } Jbig2Stream.prototype = Object.create(DecodeStream.prototype); + Object.defineProperty(Jbig2Stream.prototype, 'bytes', { + get: function Jbig2Stream_bytes() { + return shadow(this, 'bytes', this.stream.getBytes(this.length)); + }, + configurable: true + }); + Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) { if (this.bufferLength) return; @@ -35276,7 +35522,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { var pageNum = data.pageIndex + 1; var start = Date.now(); // Pre compile the pdf page and fetch the fonts/images. - page.getOperatorList(handler).then(function(operatorList) { + page.getOperatorList(handler, data.intent).then(function(operatorList) { info('page=' + pageNum + ' - getOperatorList: time=' + (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length); @@ -35308,7 +35554,8 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { handler.send('PageError', { pageNum: pageNum, - error: wrappedException + error: wrappedException, + intent: data.intent }); }); }); @@ -35394,6 +35641,175 @@ if (typeof window === 'undefined') { } +/* This class implements the QM Coder decoding as defined in + * JPEG 2000 Part I Final Committee Draft Version 1.0 + * Annex C.3 Arithmetic decoding procedure + * available at http://www.jpeg.org/public/fcd15444-1.pdf + * + * The arithmetic decoder is used in conjunction with context models to decode + * JPEG2000 and JBIG2 streams. + */ +var ArithmeticDecoder = (function ArithmeticDecoderClosure() { + // Table C-2 + var QeTable = [ + {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1}, + {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0}, + {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0}, + {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0}, + {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0}, + {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0}, + {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1}, + {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0}, + {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0}, + {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0}, + {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0}, + {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0}, + {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0}, + {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0}, + {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1}, + {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0}, + {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0}, + {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0}, + {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0}, + {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0}, + {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0}, + {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0}, + {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0}, + {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0}, + {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0}, + {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0}, + {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0}, + {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0}, + {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0}, + {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0}, + {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0}, + {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0}, + {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0}, + {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0}, + {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0}, + {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0}, + {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0}, + {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0}, + {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0}, + {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0}, + {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0}, + {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0}, + {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0}, + {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0}, + {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0}, + {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0}, + {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0} + ]; + + // C.3.5 Initialisation of the decoder (INITDEC) + function ArithmeticDecoder(data, start, end) { + this.data = data; + this.bp = start; + this.dataEnd = end; + + this.chigh = data[start]; + this.clow = 0; + + this.byteIn(); + + this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F); + this.clow = (this.clow << 7) & 0xFFFF; + this.ct -= 7; + this.a = 0x8000; + } + + ArithmeticDecoder.prototype = { + // C.3.4 Compressed data input (BYTEIN) + byteIn: function ArithmeticDecoder_byteIn() { + var data = this.data; + var bp = this.bp; + if (data[bp] == 0xFF) { + var b1 = data[bp + 1]; + if (b1 > 0x8F) { + this.clow += 0xFF00; + this.ct = 8; + } else { + bp++; + this.clow += (data[bp] << 9); + this.ct = 7; + this.bp = bp; + } + } else { + bp++; + this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00; + this.ct = 8; + this.bp = bp; + } + if (this.clow > 0xFFFF) { + this.chigh += (this.clow >> 16); + this.clow &= 0xFFFF; + } + }, + // C.3.2 Decoding a decision (DECODE) + readBit: function ArithmeticDecoder_readBit(contexts, pos) { + // contexts are packed into 1 byte: + // highest 7 bits carry cx.index, lowest bit carries cx.mps + var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1; + var qeTableIcx = QeTable[cx_index]; + var qeIcx = qeTableIcx.qe; + var nmpsIcx = qeTableIcx.nmps; + var nlpsIcx = qeTableIcx.nlps; + var switchIcx = qeTableIcx.switchFlag; + var d; + this.a -= qeIcx; + + if (this.chigh < qeIcx) { + // exchangeLps + if (this.a < qeIcx) { + this.a = qeIcx; + d = cx_mps; + cx_index = nmpsIcx; + } else { + this.a = qeIcx; + d = 1 - cx_mps; + if (switchIcx) { + cx_mps = d; + } + cx_index = nlpsIcx; + } + } else { + this.chigh -= qeIcx; + if ((this.a & 0x8000) !== 0) { + return cx_mps; + } + // exchangeMps + if (this.a < qeIcx) { + d = 1 - cx_mps; + if (switchIcx) { + cx_mps = d; + } + cx_index = nlpsIcx; + } else { + d = cx_mps; + cx_index = nmpsIcx; + } + } + // C.3.3 renormD; + do { + if (this.ct === 0) { + this.byteIn(); + } + + this.a <<= 1; + this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1); + this.clow = (this.clow << 1) & 0xFFFF; + this.ct--; + } while ((this.a & 0x8000) === 0); + + contexts[pos] = cx_index << 1 | cx_mps; + return d; + } + }; + + return ArithmeticDecoder; +})(); + + var JpxImage = (function JpxImageClosure() { // Table E.1 var SubbandsGainLog2 = { @@ -35402,6 +35818,10 @@ var JpxImage = (function JpxImageClosure() { 'HL': 1, 'HH': 2 }; + var TransformType = { + IRREVERSIBLE: 0, + REVERSIBLE: 1 + }; function JpxImage() { this.failOnCorruptedImage = false; } @@ -35414,16 +35834,18 @@ var JpxImage = (function JpxImageClosure() { // TODO catch parse error var data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer); this.parse(data); - if (this.onload) + if (this.onload) { this.onload(); + } }).bind(this); xhr.send(null); }, parse: function JpxImage_parse(data) { function readUint(data, offset, bytes) { var n = 0; - for (var i = 0; i < bytes; i++) + for (var i = 0; i < bytes; i++) { n = n * 256 + (data[offset + i] & 0xFF); + } return n; } @@ -35445,10 +35867,12 @@ var JpxImage = (function JpxImageClosure() { position += 8; headerSize += 8; } - if (lbox === 0) + if (lbox === 0) { lbox = length - position + headerSize; - if (lbox < headerSize) + } + if (lbox < headerSize) { error('JPX error: Invalid box field size'); + } var dataLength = lbox - headerSize; var jumpDataLength = true; switch (tbox) { @@ -35465,8 +35889,9 @@ var JpxImage = (function JpxImageClosure() { this.parseCodestream(data, position, position + dataLength); break; } - if (jumpDataLength) + if (jumpDataLength) { position += dataLength; + } } }, parseCodestream: function JpxImage_parseCodestream(data, start, end) { @@ -35537,7 +35962,7 @@ var JpxImage = (function JpxImageClosure() { default: throw 'Invalid SQcd value ' + sqcd; } - qcd.noQuantization = spqcdSize == 8; + qcd.noQuantization = (spqcdSize == 8); qcd.scalarExpounded = scalarExpounded; qcd.guardBits = sqcd >> 5; var spqcds = []; @@ -35554,9 +35979,9 @@ var JpxImage = (function JpxImageClosure() { spqcds.push(spqcd); } qcd.SPqcds = spqcds; - if (context.mainHeader) + if (context.mainHeader) { context.QCD = qcd; - else { + } else { context.currentTile.QCD = qcd; context.currentTile.QCC = []; } @@ -35566,9 +35991,9 @@ var JpxImage = (function JpxImageClosure() { var qcc = {}; j = position + 2; var cqcc; - if (context.SIZ.Csiz < 257) + if (context.SIZ.Csiz < 257) { cqcc = data[j++]; - else { + } else { cqcc = readUint16(data, j); j += 2; } @@ -35590,11 +36015,11 @@ var JpxImage = (function JpxImageClosure() { default: throw 'Invalid SQcd value ' + sqcd; } - qcc.noQuantization = spqcdSize == 8; + qcc.noQuantization = (spqcdSize == 8); qcc.scalarExpounded = scalarExpounded; qcc.guardBits = sqcd >> 5; var spqcds = []; - while (j < length + position) { + while (j < (length + position)) { var spqcd = {}; if (spqcdSize == 8) { spqcd.epsilon = data[j++] >> 3; @@ -35607,10 +36032,11 @@ var JpxImage = (function JpxImageClosure() { spqcds.push(spqcd); } qcc.SPqcds = spqcds; - if (context.mainHeader) + if (context.mainHeader) { context.QCC[cqcc] = qcc; - else + } else { context.currentTile.QCC[cqcc] = qcc; + } break; case 0xFF52: // Coding style default (COD) length = readUint16(data, position); @@ -35653,13 +36079,14 @@ var JpxImage = (function JpxImageClosure() { cod.selectiveArithmeticCodingBypass || cod.resetContextProbabilities || cod.terminationOnEachCodingPass || - cod.verticalyStripe || cod.predictableTermination) + cod.verticalyStripe || cod.predictableTermination) { throw 'Unsupported COD options: ' + globalScope.JSON.stringify(cod); + } - if (context.mainHeader) + if (context.mainHeader) { context.COD = cod; - else { + } else { context.currentTile.COD = cod; context.currentTile.COC = []; } @@ -35692,7 +36119,6 @@ var JpxImage = (function JpxImageClosure() { // moving to the end of the data length = tile.dataEnd - position; - parseTilePackets(context, data, position, length); break; case 0xFF64: // Comment (COM) @@ -35705,10 +36131,11 @@ var JpxImage = (function JpxImageClosure() { position += length; } } catch (e) { - if (this.failOnCorruptedImage) + if (this.failOnCorruptedImage) { error('JPX error: ' + e); - else + } else { warn('JPX error: ' + e + '. Trying to recover'); + } } this.tiles = transformComponents(context); this.width = context.SIZ.Xsiz - context.SIZ.XOsiz; @@ -35718,7 +36145,7 @@ var JpxImage = (function JpxImageClosure() { }; function readUint32(data, offset) { return (data[offset] << 24) | (data[offset + 1] << 16) | - (data[offset + 2] << 8) | data[offset + 3]; + (data[offset + 2] << 8) | data[offset + 3]; } function readUint16(data, offset) { return (data[offset] << 8) | data[offset + 1]; @@ -35788,27 +36215,27 @@ var JpxImage = (function JpxImageClosure() { result.PPy = codOrCoc.precinctsSizes[r].PPy; } // calculate codeblock size as described in section B.7 - result.xcb_ = r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) : - Math.min(codOrCoc.xcb, result.PPx); - result.ycb_ = r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) : - Math.min(codOrCoc.ycb, result.PPy); + result.xcb_ = (r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) : + Math.min(codOrCoc.xcb, result.PPx)); + result.ycb_ = (r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) : + Math.min(codOrCoc.ycb, result.PPy)); return result; } function buildPrecincts(context, resolution, dimensions) { // Section B.6 Division resolution to precincts var precinctWidth = 1 << dimensions.PPx; var precinctHeight = 1 << dimensions.PPy; - var numprecinctswide = resolution.trx1 > resolution.trx0 ? + var numprecinctswide = (resolution.trx1 > resolution.trx0 ? Math.ceil(resolution.trx1 / precinctWidth) - - Math.floor(resolution.trx0 / precinctWidth) : 0; - var numprecinctshigh = resolution.try1 > resolution.try0 ? + Math.floor(resolution.trx0 / precinctWidth) : 0); + var numprecinctshigh = (resolution.try1 > resolution.try0 ? Math.ceil(resolution.try1 / precinctHeight) - - Math.floor(resolution.try0 / precinctHeight) : 0; + Math.floor(resolution.try0 / precinctHeight) : 0); var numprecincts = numprecinctswide * numprecinctshigh; var precinctXOffset = Math.floor(resolution.trx0 / precinctWidth) * - precinctWidth; + precinctWidth; var precinctYOffset = Math.floor(resolution.try0 / precinctHeight) * - precinctHeight; + precinctHeight; resolution.precinctParameters = { precinctXOffset: precinctXOffset, precinctYOffset: precinctYOffset, @@ -35844,13 +36271,13 @@ var JpxImage = (function JpxImageClosure() { }; // calculate precinct number var pi = Math.floor((codeblock.tbx0 - - precinctParameters.precinctXOffset) / - precinctParameters.precinctWidth); + precinctParameters.precinctXOffset) / + precinctParameters.precinctWidth); var pj = Math.floor((codeblock.tby0 - - precinctParameters.precinctYOffset) / - precinctParameters.precinctHeight); + precinctParameters.precinctYOffset) / + precinctParameters.precinctHeight); var precinctNumber = pj + - pi * precinctParameters.numprecinctswide; + pi * precinctParameters.numprecinctswide; codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0); codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0); codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1); @@ -35858,7 +36285,7 @@ var JpxImage = (function JpxImageClosure() { codeblock.precinctNumber = precinctNumber; codeblock.subbandType = subband.type; var coefficientsLength = (codeblock.tbx1_ - codeblock.tbx0_) * - (codeblock.tby1_ - codeblock.tby0_); + (codeblock.tby1_ - codeblock.tby0_); codeblock.Lblock = 3; codeblocks.push(codeblock); // building precinct for the sub-band @@ -35934,8 +36361,9 @@ var JpxImage = (function JpxImageClosure() { for (; r <= maxDecompositionLevelsCount; r++) { for (; i < componentsCount; i++) { var component = tile.components[i]; - if (r > component.codingStyleParameters.decompositionLevelsCount) + if (r > component.codingStyleParameters.decompositionLevelsCount) { continue; + } var resolution = component.resolutions[r]; var numprecincts = resolution.precinctParameters.numprecincts; @@ -35973,8 +36401,9 @@ var JpxImage = (function JpxImageClosure() { for (; l < layersCount; l++) { for (; i < componentsCount; i++) { var component = tile.components[i]; - if (r > component.codingStyleParameters.decompositionLevelsCount) + if (r > component.codingStyleParameters.decompositionLevelsCount) { continue; + } var resolution = component.resolutions[r]; var numprecincts = resolution.precinctParameters.numprecincts; @@ -36243,7 +36672,6 @@ var JpxImage = (function JpxImageClosure() { function copyCoefficients(coefficients, x0, y0, width, height, delta, mb, codeblocks, transformation, segmentationSymbolUsed) { - var r = 0.5; // formula (E-6) for (var i = 0, ii = codeblocks.length; i < ii; ++i) { var codeblock = codeblocks[i]; var blockWidth = codeblock.tbx1_ - codeblock.tbx0_; @@ -36257,7 +36685,7 @@ var JpxImage = (function JpxImageClosure() { var bitModel, currentCodingpassType; bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType, - codeblock.zeroBitPlanes); + codeblock.zeroBitPlanes); currentCodingpassType = 2; // first bit plane starts from cleanup // collect data @@ -36297,20 +36725,16 @@ var JpxImage = (function JpxImageClosure() { } var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width; - var position = 0; + var n, nb, correction, position = 0; + var irreversible = (transformation === TransformType.IRREVERSIBLE); + var sign = bitModel.coefficentsSign; + var magnitude = bitModel.coefficentsMagnitude; + var bitsDecoded = bitModel.bitsDecoded; for (var j = 0; j < blockHeight; j++) { for (var k = 0; k < blockWidth; k++) { - var n = (bitModel.coefficentsSign[position] ? -1 : 1) * - bitModel.coefficentsMagnitude[position]; - var nb = bitModel.bitsDecoded[position], correction; - if (transformation === 0 || mb > nb) { - // use r only if transformation is irreversible or - // not all bitplanes were decoded for reversible transformation - n += n < 0 ? n - r : n > 0 ? n + r : 0; - correction = 1 << (mb - nb); - } else { - correction = 1; - } + n = (sign[position] ? -1 : 1) * magnitude[position]; + nb = bitsDecoded[position]; + correction = (irreversible || mb > nb) ? 1 << (mb - nb) : 1; coefficients[offset++] = n * correction * delta; position++; } @@ -36331,6 +36755,10 @@ var JpxImage = (function JpxImageClosure() { var segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed; var precision = context.components[c].precision; + var transformation = codingStyleParameters.transformation; + var transform = (transformation === TransformType.IRREVERSIBLE ? + new IrreversibleTransform() : new ReversibleTransform()); + var subbandCoefficients = []; var k = 0, b = 0; for (var i = 0; i <= decompositionLevelsCount; i++) { @@ -36353,8 +36781,8 @@ var JpxImage = (function JpxImageClosure() { var gainLog2 = SubbandsGainLog2[subband.type]; // calulate quantization coefficient (Section E.1.1.1) - var delta = Math.pow(2, (precision + gainLog2) - epsilon) * - (1 + mu / 2048); + var delta = (transformation === TransformType.IRREVERSIBLE ? + Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048) : 1); var mb = (guardBits + epsilon - 1); var coefficients = new Float32Array(width * height); @@ -36372,11 +36800,8 @@ var JpxImage = (function JpxImageClosure() { } } - var transformation = codingStyleParameters.transformation; - var transform = transformation === 0 ? new IrreversibleTransform() : - new ReversibleTransform(); var result = transform.calculate(subbandCoefficients, - component.tcx0, component.tcy0); + component.tcx0, component.tcy0); return { left: component.tcx0, top: component.tcy0, @@ -36400,15 +36825,31 @@ var JpxImage = (function JpxImageClosure() { // Section G.2.2 Inverse multi component transform if (tile.codingStyleDefaultParameters.multipleComponentTransform) { - var y0items = result[0].items; - var y1items = result[1].items; - var y2items = result[2].items; - for (var j = 0, jj = y0items.length; j < jj; j++) { - var y0 = y0items[j], y1 = y1items[j], y2 = y2items[j]; - var i1 = y0 - ((y2 + y1) >> 2); - y1items[j] = i1; - y0items[j] = y2 + i1; - y2items[j] = y1 + i1; + var component0 = tile.components[0]; + var transformation = component0.codingStyleParameters.transformation; + if (transformation === TransformType.IRREVERSIBLE) { + // inverse irreversible multiple component transform + var y0items = result[0].items; + var y1items = result[1].items; + var y2items = result[2].items; + for (var j = 0, jj = y0items.length; j < jj; ++j) { + var y0 = y0items[j], y1 = y1items[j], y2 = y2items[j]; + y0items[j] = y0 + 1.402 * y2 + 0.5; + y1items[j] = y0 - 0.34413 * y1 - 0.71414 * y2 + 0.5; + y2items[j] = y0 + 1.772 * y1 + 0.5; + } + } else { + // inverse reversible multiple component transform + var y0items = result[0].items; + var y1items = result[1].items; + var y2items = result[2].items; + for (var j = 0, jj = y0items.length; j < jj; ++j) { + var y0 = y0items[j], y1 = y1items[j], y2 = y2items[j]; + var i1 = y0 - ((y2 + y1) >> 2); + y1items[j] = i1; + y0items[j] = y2 + i1; + y2items[j] = y1 + i1; + } } } @@ -36453,11 +36894,11 @@ var JpxImage = (function JpxImageClosure() { var resultTiles = []; for (var c = 0; c < componentsCount; c++) { var component = tile.components[c]; - var qcdOrQcc = c in context.currentTile.QCC ? - context.currentTile.QCC[c] : context.currentTile.QCD; + var qcdOrQcc = (c in context.currentTile.QCC ? + context.currentTile.QCC[c] : context.currentTile.QCD); component.quantizationParameters = qcdOrQcc; - var codOrCoc = c in context.currentTile.COC ? - context.currentTile.COC[c] : context.currentTile.COD; + var codOrCoc = (c in context.currentTile.COC ? + context.currentTile.COC[c] : context.currentTile.COD); component.codingStyleParameters = codOrCoc; } tile.codingStyleDefaultParameters = context.currentTile.COD; @@ -36604,172 +37045,10 @@ var JpxImage = (function JpxImageClosure() { return InclusionTree; })(); - // Implements C.3. Arithmetic decoding procedures - var ArithmeticDecoder = (function ArithmeticDecoderClosure() { - var QeTable = [ - {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1}, - {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0}, - {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0}, - {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0}, - {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0}, - {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0}, - {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1}, - {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0}, - {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0}, - {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0}, - {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0}, - {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0}, - {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0}, - {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0}, - {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1}, - {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0}, - {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0}, - {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0}, - {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0}, - {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0}, - {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0}, - {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0}, - {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0}, - {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0}, - {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0}, - {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0}, - {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0}, - {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0}, - {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0}, - {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0}, - {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0}, - {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0}, - {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0}, - {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0}, - {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0}, - {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0}, - {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0}, - {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0}, - {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0}, - {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0}, - {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0}, - {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0}, - {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0}, - {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0}, - {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0}, - {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0}, - {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0} - ]; - - function ArithmeticDecoder(data, start, end) { - this.data = data; - this.bp = start; - this.dataEnd = end; - - this.chigh = data[start]; - this.clow = 0; - - this.byteIn(); - - this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F); - this.clow = (this.clow << 7) & 0xFFFF; - this.ct -= 7; - this.a = 0x8000; - } - - ArithmeticDecoder.prototype = { - byteIn: function ArithmeticDecoder_byteIn() { - var data = this.data; - var bp = this.bp; - if (data[bp] == 0xFF) { - var b1 = data[bp + 1]; - if (b1 > 0x8F) { - this.clow += 0xFF00; - this.ct = 8; - } else { - bp++; - this.clow += (data[bp] << 9); - this.ct = 7; - this.bp = bp; - } - } else { - bp++; - this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00; - this.ct = 8; - this.bp = bp; - } - if (this.clow > 0xFFFF) { - this.chigh += (this.clow >> 16); - this.clow &= 0xFFFF; - } - }, - readBit: function ArithmeticDecoder_readBit(cx) { - var qeIcx = QeTable[cx.index].qe; - this.a -= qeIcx; - - if (this.chigh < qeIcx) { - var d = this.exchangeLps(cx); - this.renormD(); - return d; - } else { - this.chigh -= qeIcx; - if ((this.a & 0x8000) === 0) { - var d = this.exchangeMps(cx); - this.renormD(); - return d; - } else { - return cx.mps; - } - } - }, - renormD: function ArithmeticDecoder_renormD() { - do { - if (this.ct === 0) { - this.byteIn(); - } - - this.a <<= 1; - this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1); - this.clow = (this.clow << 1) & 0xFFFF; - this.ct--; - } while ((this.a & 0x8000) === 0); - }, - exchangeMps: function ArithmeticDecoder_exchangeMps(cx) { - var d; - var qeTableIcx = QeTable[cx.index]; - if (this.a < qeTableIcx.qe) { - d = 1 - cx.mps; - - if (qeTableIcx.switchFlag == 1) { - cx.mps = 1 - cx.mps; - } - cx.index = qeTableIcx.nlps; - } else { - d = cx.mps; - cx.index = qeTableIcx.nmps; - } - return d; - }, - exchangeLps: function ArithmeticDecoder_exchangeLps(cx) { - var d; - var qeTableIcx = QeTable[cx.index]; - if (this.a < qeTableIcx.qe) { - this.a = qeTableIcx.qe; - d = cx.mps; - cx.index = qeTableIcx.nmps; - } else { - this.a = qeTableIcx.qe; - d = 1 - cx.mps; - - if (qeTableIcx.switchFlag == 1) { - cx.mps = 1 - cx.mps; - } - cx.index = qeTableIcx.nlps; - } - return d; - } - }; - - return ArithmeticDecoder; - })(); - // Section D. Coefficient bit modeling var BitModel = (function BitModelClosure() { + var UNIFORM_CONTEXT = 17; + var RUNLENGTH_CONTEXT = 18; // Table D-1 // The index is binary presentation: 0dddvvhh, ddd - sum of Di (0..4), // vv - sum of Vi (0..2), and hh - sum of Hi (0..2) @@ -36818,8 +37097,8 @@ var JpxImage = (function JpxImageClosure() { this.width = width; this.height = height; - this.contextLabelTable = subband == 'HH' ? HHContextLabel : - subband == 'HL' ? HLContextLabel : LLAndLHContextsLabel; + this.contextLabelTable = (subband == 'HH' ? HHContextLabel : + (subband == 'HL' ? HLContextLabel : LLAndLHContextsLabel)); var coefficientCount = width * height; @@ -36831,8 +37110,9 @@ var JpxImage = (function JpxImageClosure() { this.processingFlags = new Uint8Array(coefficientCount); var bitsDecoded = new Uint8Array(this.width * this.height); - for (var i = 0, ii = bitsDecoded.length; i < ii; i++) + for (var i = 0, ii = bitsDecoded.length; i < ii; i++) { bitsDecoded[i] = zeroBitPlanes; + } this.bitsDecoded = bitsDecoded; this.reset(); @@ -36843,13 +37123,15 @@ var JpxImage = (function JpxImageClosure() { this.decoder = decoder; }, reset: function BitModel_reset() { - this.uniformContext = {index: 46, mps: 0}; - this.runLengthContext = {index: 3, mps: 0}; - this.contexts = []; - this.contexts.push({index: 4, mps: 0}); - for (var i = 1; i <= 16; i++) { - this.contexts.push({index: 0, mps: 0}); - } + // We have 17 contexts that are accessed via context labels, + // plus the uniform and runlength context. + this.contexts = new Int8Array(19); + + // Contexts are packed into 1 byte: + // highest 7 bits carry the index, lowest bit carries mps + this.contexts[0] = (4 << 1) | 0; + this.contexts[UNIFORM_CONTEXT] = (46 << 1) | 0; + this.contexts[RUNLENGTH_CONTEXT] = (3 << 1) | 0; }, setNeighborsSignificance: function BitModel_setNeighborsSignificance(row, column) { @@ -36911,12 +37193,13 @@ var JpxImage = (function JpxImageClosure() { break; } - if (coefficentsMagnitude[index] || !neighborsSignificance[index]) + if (coefficentsMagnitude[index] || + !neighborsSignificance[index]) { continue; + } var contextLabel = labels[neighborsSignificance[index]]; - var cx = contexts[contextLabel]; - var decision = decoder.readBit(cx); + var decision = decoder.readBit(contexts, contextLabel); if (decision) { var sign = this.decodeSignBit(i, j); coefficentsSign[index] = sign; @@ -36949,8 +37232,7 @@ var JpxImage = (function JpxImageClosure() { var contextLabelAndXor = SignContextLabels[ 3 * (1 - horizontalContribution) + (1 - verticalContribution)]; var contextLabel = contextLabelAndXor.contextLabel; - var cx = this.contexts[contextLabel]; - var decoded = this.decoder.readBit(cx); + var decoded = this.decoder.readBit(this.contexts, contextLabel); return decoded ^ contextLabelAndXor.xorBit; }, runMagnitudeRefinementPass: @@ -36980,8 +37262,7 @@ var JpxImage = (function JpxImageClosure() { } var contextLabel = 16; - if ((processingFlags[index] & - firstMagnitudeBitMask) !== 0) { + if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) { processingFlags[i * width + j] ^= firstMagnitudeBitMask; // first refinement var significance = neighborsSignificance[index]; @@ -36990,8 +37271,7 @@ var JpxImage = (function JpxImageClosure() { contextLabel = sumOfSignificance >= 1 ? 15 : 14; } - var cx = contexts[contextLabel]; - var bit = decoder.readBit(cx); + var bit = decoder.readBit(contexts, contextLabel); coefficentsMagnitude[index] = (coefficentsMagnitude[index] << 1) | bit; bitsDecoded[index]++; @@ -37021,7 +37301,7 @@ var JpxImage = (function JpxImageClosure() { var index0 = i0 * width + j; // using the property: labels[neighborsSignificance[index]] == 0 // when neighborsSignificance[index] == 0 - var allEmpty = i0 + 3 < height && + var allEmpty = (i0 + 3 < height && processingFlags[index0] === 0 && processingFlags[index0 + oneRowDown] === 0 && processingFlags[index0 + twoRowsDown] === 0 && @@ -37029,12 +37309,12 @@ var JpxImage = (function JpxImageClosure() { neighborsSignificance[index0] === 0 && neighborsSignificance[index0 + oneRowDown] === 0 && neighborsSignificance[index0 + twoRowsDown] === 0 && - neighborsSignificance[index0 + threeRowsDown] === 0; + neighborsSignificance[index0 + threeRowsDown] === 0); var i1 = 0, index = index0; - var cx, i; + var i; if (allEmpty) { - cx = this.runLengthContext; - var hasSignificantCoefficent = decoder.readBit(cx); + var hasSignificantCoefficent = + decoder.readBit(contexts, RUNLENGTH_CONTEXT); if (!hasSignificantCoefficent) { bitsDecoded[index0]++; bitsDecoded[index0 + oneRowDown]++; @@ -37042,8 +37322,8 @@ var JpxImage = (function JpxImageClosure() { bitsDecoded[index0 + threeRowsDown]++; continue; // next column } - cx = this.uniformContext; - i1 = (decoder.readBit(cx) << 1) | decoder.readBit(cx); + i1 = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) | + decoder.readBit(contexts, UNIFORM_CONTEXT); i = i0 + i1; index += i1 * width; @@ -37072,8 +37352,7 @@ var JpxImage = (function JpxImageClosure() { } var contextLabel = labels[neighborsSignificance[index]]; - cx = contexts[contextLabel]; - var decision = decoder.readBit(cx); + var decision = decoder.readBit(contexts, contextLabel); if (decision == 1) { var sign = this.decodeSignBit(i, j); coefficentsSign[index] = sign; @@ -37088,9 +37367,11 @@ var JpxImage = (function JpxImageClosure() { }, checkSegmentationSymbol: function BitModel_checkSegmentationSymbol() { var decoder = this.decoder; - var cx = this.uniformContext; - var symbol = (decoder.readBit(cx) << 3) | (decoder.readBit(cx) << 2) | - (decoder.readBit(cx) << 1) | decoder.readBit(cx); + var contexts = this.contexts; + var symbol = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 3) | + (decoder.readBit(contexts, UNIFORM_CONTEXT) << 2) | + (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) | + decoder.readBit(contexts, UNIFORM_CONTEXT); if (symbol != 0xA) { throw 'Invalid segmentation symbol'; } @@ -37100,10 +37381,10 @@ var JpxImage = (function JpxImageClosure() { return BitModel; })(); - // Section F, Discrete wavelet transofrmation + // Section F, Discrete wavelet transformation var Transform = (function TransformClosure() { - function Transform() { - } + function Transform() {} + Transform.prototype.calculate = function transformCalculate(subbands, u0, v0) { var ll = subbands[0]; @@ -37114,17 +37395,17 @@ var JpxImage = (function JpxImageClosure() { return ll; }; Transform.prototype.extend = function extend(buffer, offset, size) { - // Section F.3.7 extending... using max extension of 4 - var i1 = offset - 1, j1 = offset + 1; - var i2 = offset + size - 2, j2 = offset + size; - buffer[i1--] = buffer[j1++]; - buffer[j2++] = buffer[i2--]; - buffer[i1--] = buffer[j1++]; - buffer[j2++] = buffer[i2--]; - buffer[i1--] = buffer[j1++]; - buffer[j2++] = buffer[i2--]; - buffer[i1] = buffer[j1]; - buffer[j2] = buffer[i2]; + // Section F.3.7 extending... using max extension of 4 + var i1 = offset - 1, j1 = offset + 1; + var i2 = offset + size - 2, j2 = offset + size; + buffer[i1--] = buffer[j1++]; + buffer[j2++] = buffer[i2--]; + buffer[i1--] = buffer[j1++]; + buffer[j2++] = buffer[i2--]; + buffer[i1--] = buffer[j1++]; + buffer[j2++] = buffer[i2--]; + buffer[i1] = buffer[j1]; + buffer[j2] = buffer[i2]; }; Transform.prototype.iterate = function Transform_iterate(ll, hl, lh, hh, u0, v0) { @@ -37266,33 +37547,39 @@ var JpxImage = (function JpxImageClosure() { // step 1 var j = offset_ - 2; - for (var n = i0_ - 1, nn = i1_ + 2; n < nn; n++, j += 2) + for (var n = i0_ - 1, nn = i1_ + 2; n < nn; n++, j += 2) { x[j] = K * y[j]; + } // step 2 var j = offset_ - 3; - for (var n = i0_ - 2, nn = i1_ + 2; n < nn; n++, j += 2) + for (var n = i0_ - 2, nn = i1_ + 2; n < nn; n++, j += 2) { x[j] = K_ * y[j]; + } // step 3 var j = offset_ - 2; - for (var n = i0_ - 1, nn = i1_ + 2; n < nn; n++, j += 2) + for (var n = i0_ - 1, nn = i1_ + 2; n < nn; n++, j += 2) { x[j] -= delta * (x[j - 1] + x[j + 1]); + } // step 4 var j = offset_ - 1; - for (var n = i0_ - 1, nn = i1_ + 1; n < nn; n++, j += 2) + for (var n = i0_ - 1, nn = i1_ + 1; n < nn; n++, j += 2) { x[j] -= gamma * (x[j - 1] + x[j + 1]); + } // step 5 var j = offset_; - for (var n = i0_, nn = i1_ + 1; n < nn; n++, j += 2) + for (var n = i0_, nn = i1_ + 1; n < nn; n++, j += 2) { x[j] -= beta * (x[j - 1] + x[j + 1]); + } // step 6 var j = offset_ + 1; - for (var n = i0_, nn = i1_; n < nn; n++, j += 2) + for (var n = i0_, nn = i1_; n < nn; n++, j += 2) { x[j] -= alpha * (x[j - 1] + x[j + 1]); + } }; return IrreversibleTransform; @@ -37311,11 +37598,13 @@ var JpxImage = (function JpxImageClosure() { var i1_ = Math.floor((i0 + length) / 2); var offset_ = offset - (i0 % 1); - for (var n = i0_, nn = i1_ + 1, j = offset_; n < nn; n++, j += 2) + for (var n = i0_, nn = i1_ + 1, j = offset_; n < nn; n++, j += 2) { x[j] = y[j] - Math.floor((y[j - 1] + y[j + 1] + 2) / 4); + } - for (var n = i0_, nn = i1_, j = offset_ + 1; n < nn; n++, j += 2) + for (var n = i0_, nn = i1_, j = offset_ + 1; n < nn; n++, j += 2) { x[j] = y[j] + Math.floor((x[j - 1] + x[j + 1]) / 2); + } }; return ReversibleTransform; @@ -37327,170 +37616,14 @@ var JpxImage = (function JpxImageClosure() { var Jbig2Image = (function Jbig2ImageClosure() { - - // Annex E. Arithmetic Coding - var ArithmeticDecoder = (function ArithmeticDecoderClosure() { - var QeTable = [ - {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1}, - {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0}, - {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0}, - {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0}, - {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0}, - {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0}, - {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1}, - {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0}, - {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0}, - {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0}, - {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0}, - {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0}, - {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0}, - {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0}, - {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1}, - {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0}, - {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0}, - {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0}, - {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0}, - {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0}, - {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0}, - {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0}, - {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0}, - {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0}, - {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0}, - {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0}, - {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0}, - {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0}, - {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0}, - {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0}, - {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0}, - {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0}, - {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0}, - {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0}, - {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0}, - {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0}, - {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0}, - {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0}, - {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0}, - {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0}, - {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0}, - {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0}, - {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0}, - {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0}, - {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0}, - {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0}, - {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0} - ]; - - function ArithmeticDecoder(data, start, end) { - this.data = data; - this.bp = start; - this.dataEnd = end; - - this.chigh = data[start]; - this.clow = 0; - - this.byteIn(); - - this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F); - this.clow = (this.clow << 7) & 0xFFFF; - this.ct -= 7; - this.a = 0x8000; - } - - ArithmeticDecoder.prototype = { - byteIn: function ArithmeticDecoder_byteIn() { - var data = this.data; - var bp = this.bp; - if (data[bp] == 0xFF) { - var b1 = data[bp + 1]; - if (b1 > 0x8F) { - this.clow += 0xFF00; - this.ct = 8; - } else { - bp++; - this.clow += (data[bp] << 9); - this.ct = 7; - this.bp = bp; - } - } else { - bp++; - this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00; - this.ct = 8; - this.bp = bp; - } - if (this.clow > 0xFFFF) { - this.chigh += (this.clow >> 16); - this.clow &= 0xFFFF; - } - }, - readBit: function ArithmeticDecoder_readBit(contexts, pos) { - // contexts are packed into 1 byte: - // highest 7 bits carry cx.index, lowest bit carries cx.mps - var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1; - var qeTableIcx = QeTable[cx_index]; - var qeIcx = qeTableIcx.qe; - var nmpsIcx = qeTableIcx.nmps; - var nlpsIcx = qeTableIcx.nlps; - var switchIcx = qeTableIcx.switchFlag; - var d; - this.a -= qeIcx; - - if (this.chigh < qeIcx) { - // exchangeLps - if (this.a < qeIcx) { - this.a = qeIcx; - d = cx_mps; - cx_index = nmpsIcx; - } else { - this.a = qeIcx; - d = 1 - cx_mps; - if (switchIcx) { - cx_mps = d; - } - cx_index = nlpsIcx; - } - } else { - this.chigh -= qeIcx; - if ((this.a & 0x8000) !== 0) { - return cx_mps; - } - // exchangeMps - if (this.a < qeIcx) { - d = 1 - cx_mps; - if (switchIcx) { - cx_mps = d; - } - cx_index = nlpsIcx; - } else { - d = cx_mps; - cx_index = nmpsIcx; - } - } - // renormD; - do { - if (this.ct === 0) - this.byteIn(); - - this.a <<= 1; - this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1); - this.clow = (this.clow << 1) & 0xFFFF; - this.ct--; - } while ((this.a & 0x8000) === 0); - - contexts[pos] = cx_index << 1 | cx_mps; - return d; - } - }; - - return ArithmeticDecoder; - })(); - // Utility data structures function ContextCache() {} ContextCache.prototype = { getContexts: function(id) { - if (id in this) + if (id in this) { return this[id]; + } return (this[id] = new Int8Array(1<<16)); } }; @@ -37522,52 +37655,63 @@ var Jbig2Image = (function Jbig2ImageClosure() { var toRead = 32, offset = 4436; // defaults for state 7 while (state) { var bit = decoder.readBit(contexts, prev); - prev = prev < 256 ? (prev << 1) | bit : - (((prev << 1) | bit) & 511) | 256; + prev = (prev < 256 ? (prev << 1) | bit : + (((prev << 1) | bit) & 511) | 256); switch (state) { case 1: s = !!bit; break; case 2: - if (bit) break; + if (bit) { + break; + } state = 7; toRead = 2; offset = 0; break; case 3: - if (bit) break; + if (bit) { + break; + } state = 7; toRead = 4; offset = 4; break; case 4: - if (bit) break; + if (bit) { + break; + } state = 7; toRead = 6; offset = 20; break; case 5: - if (bit) break; + if (bit) { + break; + } state = 7; toRead = 8; offset = 84; break; case 6: - if (bit) break; + if (bit) { + break; + } state = 7; toRead = 12; offset = 340; break; default: v = v * 2 + bit; - if (--toRead === 0) + if (--toRead === 0) { state = 0; + } continue; } state++; } v += offset; - return !s ? v : v > 0 ? -v : null; + return (!s ? v : (v > 0 ? -v : null)); } // A.3 The IAID decoding procedure @@ -37579,10 +37723,10 @@ var Jbig2Image = (function Jbig2ImageClosure() { var bit = decoder.readBit(contexts, prev); prev = (prev * 2) + bit; } - if (codeLength < 31) + if (codeLength < 31) { return prev & ((1 << codeLength) - 1); - else - return prev - Math.pow(2, codeLength); + } + return prev - Math.pow(2, codeLength); } // 7.3 Segment types @@ -37671,8 +37815,9 @@ var Jbig2Image = (function Jbig2ImageClosure() { // 6.2 Generic Region Decoding Procedure function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at, decodingContext) { - if (mmr) + if (mmr) { error('JBIG2 error: MMR encoding is not supported'); + } var useskip = !!skip; var template = CodingTemplates[templateIndex].concat(at); @@ -37768,8 +37913,9 @@ var Jbig2Image = (function Jbig2ImageClosure() { offsetX, offsetY, prediction, at, decodingContext) { var codingTemplate = RefinementTemplates[templateIndex].coding; - if (templateIndex === 0) + if (templateIndex === 0) { codingTemplate = codingTemplate.concat([at[0]]); + } var codingTemplateLength = codingTemplate.length; var codingTemplateX = new Int32Array(codingTemplateLength); var codingTemplateY = new Int32Array(codingTemplateLength); @@ -37777,9 +37923,11 @@ var Jbig2Image = (function Jbig2ImageClosure() { codingTemplateX[k] = codingTemplate[k].x; codingTemplateY[k] = codingTemplate[k].y; } + var referenceTemplate = RefinementTemplates[templateIndex].reference; - if (templateIndex === 0) + if (templateIndex === 0) { referenceTemplate = referenceTemplate.concat([at[1]]); + } var referenceTemplateLength = referenceTemplate.length; var referenceTemplateX = new Int32Array(referenceTemplateLength); var referenceTemplateY = new Int32Array(referenceTemplateLength); @@ -37805,24 +37953,28 @@ var Jbig2Image = (function Jbig2ImageClosure() { var row = new Uint8Array(width); bitmap.push(row); for (var j = 0; j < width; j++) { - if (ltp) + if (ltp) { error('JBIG2 error: prediction is not supported'); + } var contextLabel = 0; for (var k = 0; k < codingTemplateLength; k++) { var i0 = i + codingTemplateY[k], j0 = j + codingTemplateX[k]; - if (i0 < 0 || j0 < 0 || j0 >= width) + if (i0 < 0 || j0 < 0 || j0 >= width) { contextLabel <<= 1; // out of bound pixel - else + } else { contextLabel = (contextLabel << 1) | bitmap[i0][j0]; + } } for (var k = 0; k < referenceTemplateLength; k++) { var i0 = i + referenceTemplateY[k] + offsetY; var j0 = j + referenceTemplateX[k] + offsetX; - if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || j0 >= referenceWidth) + if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || + j0 >= referenceWidth) { contextLabel <<= 1; // out of bound pixel - else + } else { contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0]; + } } var pixel = decoder.readBit(contexts, contextLabel); row[j] = pixel; @@ -37838,8 +37990,9 @@ var Jbig2Image = (function Jbig2ImageClosure() { huffmanTables, templateIndex, at, refinementTemplateIndex, refinementAt, decodingContext) { - if (huffman) + if (huffman) { error('JBIG2 error: huffman is not supported'); + } var newSymbols = []; var currentHeight = 0; @@ -37855,21 +38008,23 @@ var Jbig2Image = (function Jbig2ImageClosure() { var totalWidth = 0; while (true) { var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7 - if (deltaWidth === null) + if (deltaWidth === null) { break; // OOB + } currentWidth += deltaWidth; totalWidth += currentWidth; var bitmap; if (refinement) { // 6.5.8.2 Refinement/aggregate-coded symbol bitmap var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder); - if (numberOfInstances > 1) + if (numberOfInstances > 1) { error('JBIG2 error: number of instances > 1 is not supported'); + } var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength); var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3 var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4 - var symbol = symbolId < symbols.length ? symbols[symbolId] : - newSymbols[symbolId - symbols.length]; + var symbol = (symbolId < symbols.length ? symbols[symbolId] : + newSymbols[symbolId - symbols.length]); bitmap = decodeRefinement(currentWidth, currentHeight, refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt, decodingContext); @@ -37887,14 +38042,21 @@ var Jbig2Image = (function Jbig2ImageClosure() { var totalSymbolsLength = symbols.length + numberOfNewSymbols; while (flags.length < totalSymbolsLength) { var runLength = decodeInteger(contextCache, 'IAEX', decoder); - while (runLength--) + while (runLength--) { flags.push(currentFlag); + } currentFlag = !currentFlag; } - for (var i = 0, ii = symbols.length; i < ii; i++) - if (flags[i]) exportedSymbols.push(symbols[i]); - for (var j = 0; j < numberOfNewSymbols; i++, j++) - if (flags[i]) exportedSymbols.push(newSymbols[j]); + for (var i = 0, ii = symbols.length; i < ii; i++) { + if (flags[i]) { + exportedSymbols.push(symbols[i]); + } + } + for (var j = 0; j < numberOfNewSymbols; i++, j++) { + if (flags[i]) { + exportedSymbols.push(newSymbols[j]); + } + } return exportedSymbols; } @@ -37905,16 +38067,18 @@ var Jbig2Image = (function Jbig2ImageClosure() { combinationOperator, huffmanTables, refinementTemplateIndex, refinementAt, decodingContext) { - if (huffman) + if (huffman) { error('JBIG2 error: huffman is not supported'); + } // Prepare bitmap var bitmap = []; for (var i = 0; i < height; i++) { var row = new Uint8Array(width); if (defaultPixelValue) { - for (var j = 0; j < width; j++) + for (var j = 0; j < width; j++) { row[j] = defaultPixelValue; + } } bitmap.push(row); } @@ -38010,8 +38174,9 @@ var Jbig2Image = (function Jbig2ImageClosure() { } i++; var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8 - if (deltaS === null) + if (deltaS === null) { break; // OOB + } currentS += deltaS + dsOffset; } while (true); } @@ -38023,11 +38188,13 @@ var Jbig2Image = (function Jbig2ImageClosure() { segmentHeader.number = readUint32(data, start); var flags = data[start + 4]; var segmentType = flags & 0x3F; - if (!SegmentTypes[segmentType]) + if (!SegmentTypes[segmentType]) { error('JBIG2 error: invalid segment type: ' + segmentType); + } segmentHeader.type = segmentType; segmentHeader.typeName = SegmentTypes[segmentType]; segmentHeader.deferredNonRetain = !!(flags & 0x80); + var pageAssociationFieldSize = !!(flags & 0x40); var referredFlags = data[start + 5]; var referredToCount = (referredFlags >> 5) & 7; @@ -38041,28 +38208,31 @@ var Jbig2Image = (function Jbig2ImageClosure() { while (--bytes > 0) { retainBits.push(data[position++]); } - } else if (referredFlags == 5 || referredFlags == 6) + } else if (referredFlags == 5 || referredFlags == 6) { error('JBIG2 error: invalid referred-to flags'); + } + segmentHeader.retainBits = retainBits; - var referredToSegmentNumberSize = segmentHeader.number <= 256 ? 1 : - segmentHeader.number <= 65536 ? 2 : 4; + var referredToSegmentNumberSize = (segmentHeader.number <= 256 ? 1 : + (segmentHeader.number <= 65536 ? 2 : 4)); var referredTo = []; for (var i = 0; i < referredToCount; i++) { - var number = referredToSegmentNumberSize == 1 ? data[position] : - referredToSegmentNumberSize == 2 ? readUint16(data, position) : - readUint32(data, position); + var number = (referredToSegmentNumberSize == 1 ? data[position] : + (referredToSegmentNumberSize == 2 ? readUint16(data, position) : + readUint32(data, position))); referredTo.push(number); position += referredToSegmentNumberSize; } segmentHeader.referredTo = referredTo; - if (!pageAssociationFieldSize) + if (!pageAssociationFieldSize) { segmentHeader.pageAssociation = data[position++]; - else { + } else { segmentHeader.pageAssociation = readUint32(data, position); position += 4; } segmentHeader.length = readUint32(data, position); position += 4; + if (segmentHeader.length == 0xFFFFFFFF) { // 7.2.7 Segment data length, unknown segment length if (segmentType === 38) { // ImmediateGenericRegion @@ -38118,8 +38288,9 @@ var Jbig2Image = (function Jbig2ImageClosure() { segment.end = position; } segments.push(segment); - if (segmentHeader.type == 51) + if (segmentHeader.type == 51) { break; // end of file is found + } } if (header.randomAccess) { for (var i = 0, ii = segments.length; i < ii; i++) { @@ -38237,8 +38408,9 @@ var Jbig2Image = (function Jbig2ImageClosure() { textRegion.numberOfSymbolInstances = readUint32(data, position); position += 4; // TODO 7.4.3.1.7 Symbol ID Huffman table decoding - if (textRegion.huffman) + if (textRegion.huffman) { error('JBIG2 error: huffman is not supported'); + } args = [textRegion, header.referredTo, data, position, end]; break; case 38: // ImmediateGenericRegion @@ -38271,8 +38443,9 @@ var Jbig2Image = (function Jbig2ImageClosure() { resolutionX: readUint32(data, position + 8), resolutionY: readUint32(data, position + 12) }; - if (pageInfo.height == 0xFFFFFFFF) + if (pageInfo.height == 0xFFFFFFFF) { delete pageInfo.height; + } var pageSegmentFlags = data[position + 16]; var pageStripingInformatiom = readUint16(data, position + 17); pageInfo.lossless = !!(pageSegmentFlags & 1); @@ -38297,13 +38470,15 @@ var Jbig2Image = (function Jbig2ImageClosure() { header.type + ') is not implemented'); } var callbackName = 'on' + header.typeName; - if (callbackName in visitor) + if (callbackName in visitor) { visitor[callbackName].apply(visitor, args); + } } function processSegments(segments, visitor) { - for (var i = 0, ii = segments.length; i < ii; i++) + for (var i = 0, ii = segments.length; i < ii; i++) { processSegment(segments[i], visitor); + } } function parseJbig2(data, start, end) { @@ -38311,8 +38486,9 @@ var Jbig2Image = (function Jbig2ImageClosure() { if (data[position] != 0x97 || data[position + 1] != 0x4A || data[position + 2] != 0x42 || data[position + 3] != 0x32 || data[position + 4] != 0x0D || data[position + 5] != 0x0A || - data[position + 6] != 0x1A || data[position + 7] != 0x0A) + data[position + 6] != 0x1A || data[position + 7] != 0x0A) { error('JBIG2 error: invalid header'); + } var header = {}; position += 8; var flags = data[position++]; @@ -38409,17 +38585,20 @@ var Jbig2Image = (function Jbig2ImageClosure() { referredSegments, data, start, end) { var huffmanTables; - if (dictionary.huffman) + if (dictionary.huffman) { error('JBIG2 error: huffman is not supported'); + } // Combines exported symbols from all referred segments var symbols = this.symbols; - if (!symbols) + if (!symbols) { this.symbols = symbols = {}; + } var inputSymbols = []; - for (var i = 0, ii = referredSegments.length; i < ii; i++) + for (var i = 0, ii = referredSegments.length; i < ii; i++) { inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]); + } var decodingContext = new DecodingContext(data, start, end); symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman, @@ -38439,8 +38618,9 @@ var Jbig2Image = (function Jbig2ImageClosure() { // Combines exported symbols from all referred segments var symbols = this.symbols; var inputSymbols = []; - for (var i = 0, ii = referredSegments.length; i < ii; i++) + for (var i = 0, ii = referredSegments.length; i < ii; i++) { inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]); + } var symbolCodeLength = log2(inputSymbols.length); var decodingContext = new DecodingContext(data, start, end); @@ -38454,7 +38634,7 @@ var Jbig2Image = (function Jbig2ImageClosure() { }, onImmediateLosslessTextRegion: function SimpleSegmentVisitor_onImmediateLosslessTextRegion() { - this.onImmediateTextRegion.apply(this, arguments); + this.onImmediateTextRegion.apply(this, arguments); } }; @@ -38531,8 +38711,9 @@ var bidi = PDFJS.bidi = (function bidiClosure() { function findUnequal(arr, start, value) { var j; for (var j = start, jj = arr.length; j < jj; ++j) { - if (arr[j] != value) + if (arr[j] != value) { return j; + } } return j; } @@ -38593,17 +38774,17 @@ var bidi = PDFJS.bidi = (function bidiClosure() { function BidiResult(str, isLTR, vertical) { this.str = str; - this.dir = vertical ? 'ttb' : isLTR ? 'ltr' : 'rtl'; + this.dir = (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl')); } function bidi(str, startLevel, vertical) { var isLTR = true; var strLength = str.length; - if (strLength === 0 || vertical) + if (strLength === 0 || vertical) { return new BidiResult(str, isLTR, vertical); + } - // get types, fill arrays - + // Get types and fill arrays var chars = []; var types = []; var numBidi = 0; @@ -38613,25 +38794,25 @@ var bidi = PDFJS.bidi = (function bidiClosure() { var charCode = str.charCodeAt(i); var charType = 'L'; - if (charCode <= 0x00ff) + if (charCode <= 0x00ff) { charType = baseTypes[charCode]; - else if (0x0590 <= charCode && charCode <= 0x05f4) + } else if (0x0590 <= charCode && charCode <= 0x05f4) { charType = 'R'; - else if (0x0600 <= charCode && charCode <= 0x06ff) + } else if (0x0600 <= charCode && charCode <= 0x06ff) { charType = arabicTypes[charCode & 0xff]; - else if (0x0700 <= charCode && charCode <= 0x08AC) + } else if (0x0700 <= charCode && charCode <= 0x08AC) { charType = 'AL'; - - if (charType == 'R' || charType == 'AL' || charType == 'AN') + } + if (charType == 'R' || charType == 'AL' || charType == 'AN') { numBidi++; - + } types[i] = charType; } - // detect the bidi method - // if there are no rtl characters then no bidi needed - // if less than 30% chars are rtl then string is primarily ltr - // if more than 30% chars are rtl then string is primarily rtl + // Detect the bidi method + // - If there are no rtl characters then no bidi needed + // - If less than 30% chars are rtl then string is primarily ltr + // - If more than 30% chars are rtl then string is primarily rtl if (numBidi === 0) { isLTR = true; return new BidiResult(str, isLTR); @@ -38648,7 +38829,6 @@ var bidi = PDFJS.bidi = (function bidiClosure() { } var levels = []; - for (var i = 0; i < strLength; ++i) { levels[i] = startLevel; } @@ -38656,8 +38836,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() { /* X1-X10: skip most of this, since we are NOT doing the embeddings. */ - - var e = isOdd(startLevel) ? 'R' : 'L'; + var e = (isOdd(startLevel) ? 'R' : 'L'); var sor = e; var eor = sor; @@ -38666,13 +38845,13 @@ var bidi = PDFJS.bidi = (function bidiClosure() { type of the NSM to the type of the previous character. If the NSM is at the start of the level run, it will get the type of sor. */ - var lastType = sor; for (var i = 0; i < strLength; ++i) { - if (types[i] == 'NSM') + if (types[i] == 'NSM') { types[i] = lastType; - else + } else { lastType = types[i]; + } } /* @@ -38680,24 +38859,24 @@ var bidi = PDFJS.bidi = (function bidiClosure() { first strong type (R, L, AL, or sor) is found. If an AL is found, change the type of the European number to Arabic number. */ - var lastType = sor; for (var i = 0; i < strLength; ++i) { var t = types[i]; - if (t == 'EN') + if (t == 'EN') { types[i] = (lastType == 'AL') ? 'AN' : 'EN'; - else if (t == 'R' || t == 'L' || t == 'AL') + } else if (t == 'R' || t == 'L' || t == 'AL') { lastType = t; + } } /* W3. Change all ALs to R. */ - for (var i = 0; i < strLength; ++i) { var t = types[i]; - if (t == 'AL') + if (t == 'AL') { types[i] = 'R'; + } } /* @@ -38705,32 +38884,34 @@ var bidi = PDFJS.bidi = (function bidiClosure() { European number. A single common separator between two numbers of the same type changes to that type: */ - for (var i = 1; i < strLength - 1; ++i) { - if (types[i] == 'ES' && types[i - 1] == 'EN' && types[i + 1] == 'EN') + if (types[i] == 'ES' && types[i - 1] == 'EN' && types[i + 1] == 'EN') { types[i] = 'EN'; + } if (types[i] == 'CS' && (types[i - 1] == 'EN' || types[i - 1] == 'AN') && - types[i + 1] == types[i - 1]) + types[i + 1] == types[i - 1]) { types[i] = types[i - 1]; + } } /* W5. A sequence of European terminators adjacent to European numbers changes to all European numbers: */ - for (var i = 0; i < strLength; ++i) { if (types[i] == 'EN') { // do before for (var j = i - 1; j >= 0; --j) { - if (types[j] != 'ET') + if (types[j] != 'ET') { break; + } types[j] = 'EN'; } // do after for (var j = i + 1; j < strLength; --j) { - if (types[j] != 'ET') + if (types[j] != 'ET') { break; + } types[j] = 'EN'; } } @@ -38739,11 +38920,11 @@ var bidi = PDFJS.bidi = (function bidiClosure() { /* W6. Otherwise, separators and terminators change to Other Neutral: */ - for (var i = 0; i < strLength; ++i) { var t = types[i]; - if (t == 'WS' || t == 'ES' || t == 'ET' || t == 'CS') + if (t == 'WS' || t == 'ES' || t == 'ET' || t == 'CS') { types[i] = 'ON'; + } } /* @@ -38751,14 +38932,14 @@ var bidi = PDFJS.bidi = (function bidiClosure() { first strong type (R, L, or sor) is found. If an L is found, then change the type of the European number to L. */ - var lastType = sor; for (var i = 0; i < strLength; ++i) { var t = types[i]; - if (t == 'EN') - types[i] = (lastType == 'L') ? 'L' : 'EN'; - else if (t == 'R' || t == 'L') + if (t == 'EN') { + types[i] = ((lastType == 'L') ? 'L' : 'EN'); + } else if (t == 'R' || t == 'L') { lastType = t; + } } /* @@ -38767,22 +38948,27 @@ var bidi = PDFJS.bidi = (function bidiClosure() { numbers are treated as though they were R. Start-of-level-run (sor) and end-of-level-run (eor) are used at level run boundaries. */ - for (var i = 0; i < strLength; ++i) { if (types[i] == 'ON') { var end = findUnequal(types, i + 1, 'ON'); var before = sor; - if (i > 0) + if (i > 0) { before = types[i - 1]; + } + var after = eor; - if (end + 1 < strLength) + if (end + 1 < strLength) { after = types[end + 1]; - if (before != 'L') + } + if (before != 'L') { before = 'R'; - if (after != 'L') + } + if (after != 'L') { after = 'R'; - if (before == after) + } + if (before == after) { setValues(types, i, end, before); + } i = end - 1; // reset to end (-1 so next iteration is ok) } } @@ -38790,10 +38976,10 @@ var bidi = PDFJS.bidi = (function bidiClosure() { /* N2. Any remaining neutrals take the embedding direction. */ - for (var i = 0; i < strLength; ++i) { - if (types[i] == 'ON') + if (types[i] == 'ON') { types[i] = e; + } } /* @@ -38803,7 +38989,6 @@ var bidi = PDFJS.bidi = (function bidiClosure() { I2. For all characters with an odd (right-to-left) embedding direction, those of type L, EN or AN go up one level. */ - for (var i = 0; i < strLength; ++i) { var t = types[i]; if (isEven(levels[i])) { @@ -38812,7 +38997,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() { } else if (t == 'AN' || t == 'EN') { levels[i] += 2; } - } else { // isOdd, so + } else { // isOdd if (t == 'L' || t == 'AN' || t == 'EN') { levels[i] += 1; } @@ -38839,19 +39024,19 @@ var bidi = PDFJS.bidi = (function bidiClosure() { */ // find highest level & lowest odd level - var highestLevel = -1; var lowestOddLevel = 99; for (var i = 0, ii = levels.length; i < ii; ++i) { var level = levels[i]; - if (highestLevel < level) + if (highestLevel < level) { highestLevel = level; - if (lowestOddLevel > level && isOdd(level)) + } + if (lowestOddLevel > level && isOdd(level)) { lowestOddLevel = level; + } } // now reverse between those limits - for (var level = highestLevel; level >= lowestOddLevel; --level) { // find segments to reverse var start = -1; @@ -38888,14 +39073,13 @@ var bidi = PDFJS.bidi = (function bidiClosure() { // don't mirror as characters are already mirrored in the pdf // Finally, return string - var result = ''; for (var i = 0, ii = chars.length; i < ii; ++i) { var ch = chars[i]; - if (ch != '<' && ch != '>') + if (ch != '<' && ch != '>') { result += ch; + } } - return new BidiResult(result, isLTR); } diff --git a/browser/extensions/pdfjs/content/web/debugger.js b/browser/extensions/pdfjs/content/web/debugger.js index a70ad0cd94a6..a25136fe95b2 100644 --- a/browser/extensions/pdfjs/content/web/debugger.js +++ b/browser/extensions/pdfjs/content/web/debugger.js @@ -46,13 +46,17 @@ var FontInspector = (function FontInspectorClosure() { } } function textLayerClick(e) { - if (!e.target.dataset.fontName || e.target.tagName.toUpperCase() !== 'DIV') + if (!e.target.dataset.fontName || + e.target.tagName.toUpperCase() !== 'DIV') { return; + } var fontName = e.target.dataset.fontName; var selects = document.getElementsByTagName('input'); for (var i = 0; i < selects.length; ++i) { var select = selects[i]; - if (select.dataset.fontName != fontName) continue; + if (select.dataset.fontName != fontName) { + continue; + } select.checked = !select.checked; selectFont(fontName, select.checked); select.scrollIntoView(); @@ -140,8 +144,9 @@ var FontInspector = (function FontInspectorClosure() { // Somewhat of a hack, should probably add a hook for when the text layer // is done rendering. setTimeout(function() { - if (this.active) + if (this.active) { resetSelection(); + } }.bind(this), 2000); } }; @@ -172,8 +177,9 @@ var StepperManager = (function StepperManagerClosure() { stepperDiv = document.createElement('div'); this.panel.appendChild(stepperControls); this.panel.appendChild(stepperDiv); - if (sessionStorage.getItem('pdfjsBreakPoints')) + if (sessionStorage.getItem('pdfjsBreakPoints')) { breakPoints = JSON.parse(sessionStorage.getItem('pdfjsBreakPoints')); + } }, enabled: false, active: false, @@ -191,19 +197,22 @@ var StepperManager = (function StepperManagerClosure() { var initBreakPoints = breakPoints[pageIndex] || []; var stepper = new Stepper(debug, pageIndex, initBreakPoints); steppers.push(stepper); - if (steppers.length === 1) + if (steppers.length === 1) { this.selectStepper(pageIndex, false); + } return stepper; }, selectStepper: function selectStepper(pageIndex, selectPanel) { - if (selectPanel) + if (selectPanel) { this.manager.selectPanel(1); + } for (var i = 0; i < steppers.length; ++i) { var stepper = steppers[i]; - if (stepper.pageIndex == pageIndex) + if (stepper.pageIndex == pageIndex) { stepper.panel.removeAttribute('hidden'); - else + } else { stepper.panel.setAttribute('hidden', true); + } } var options = stepperChooser.options; for (var i = 0; i < options.length; ++i) { @@ -223,8 +232,9 @@ var Stepper = (function StepperClosure() { // Shorter way to create element and optionally set textContent. function c(tag, textContent) { var d = document.createElement(tag); - if (textContent) + if (textContent) { d.textContent = textContent; + } return d; } @@ -297,10 +307,11 @@ var Stepper = (function StepperClosure() { cbox.checked = checked; cbox.onclick = (function(x) { return function() { - if (this.checked) + if (this.checked) { self.breakPoints.push(x); - else + } else { self.breakPoints.splice(self.breakPoints.indexOf(x), 1); + } StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints); }; })(i); @@ -336,8 +347,9 @@ var Stepper = (function StepperClosure() { getNextBreakPoint: function getNextBreakPoint() { this.breakPoints.sort(function(a, b) { return a - b; }); for (var i = 0; i < this.breakPoints.length; i++) { - if (this.breakPoints[i] > this.currentIdx) + if (this.breakPoints[i] > this.currentIdx) { return this.breakPoints[i]; + } } return null; }, @@ -385,13 +397,16 @@ var Stepper = (function StepperClosure() { var Stats = (function Stats() { var stats = []; function clear(node) { - while (node.hasChildNodes()) + while (node.hasChildNodes()) { node.removeChild(node.lastChild); + } } function getStatIndex(pageNumber) { - for (var i = 0, ii = stats.length; i < ii; ++i) - if (stats[i].pageNumber === pageNumber) + for (var i = 0, ii = stats.length; i < ii; ++i) { + if (stats[i].pageNumber === pageNumber) { return i; + } + } return false; } return { @@ -408,8 +423,9 @@ var Stats = (function Stats() { active: false, // Stats specific functions. add: function(pageNumber, stat) { - if (!stat) + if (!stat) { return; + } var statsIndex = getStatIndex(pageNumber); if (statsIndex !== false) { var b = stats[statsIndex]; @@ -428,8 +444,9 @@ var Stats = (function Stats() { stats.push({ pageNumber: pageNumber, div: wrapper }); stats.sort(function(a, b) { return a.pageNumber - b.pageNumber; }); clear(this.panel); - for (var i = 0, ii = stats.length; i < ii; ++i) + for (var i = 0, ii = stats.length; i < ii; ++i) { this.panel.appendChild(stats[i].div); + } } }; })(); @@ -448,12 +465,14 @@ var PDFBug = (function PDFBugClosure() { ], enable: function(ids) { var all = false, tools = this.tools; - if (ids.length === 1 && ids[0] === 'all') + if (ids.length === 1 && ids[0] === 'all') { all = true; + } for (var i = 0; i < tools.length; ++i) { var tool = tools[i]; - if (all || ids.indexOf(tool.id) !== -1) + if (all || ids.indexOf(tool.id) !== -1) { tool.enabled = true; + } } if (!all) { // Sort the tools by the order they are enabled. @@ -509,19 +528,21 @@ var PDFBug = (function PDFBugClosure() { panels.appendChild(panel); tool.panel = panel; tool.manager = this; - if (tool.enabled) + if (tool.enabled) { tool.init(); - else + } else { panel.textContent = tool.name + ' is disabled. To enable add ' + ' "' + tool.id + '" to the pdfBug parameter ' + 'and refresh (seperate multiple by commas).'; + } buttons.push(panelButton); } this.selectPanel(0); }, selectPanel: function selectPanel(index) { - if (index === activePanel) + if (index === activePanel) { return; + } activePanel = index; var tools = this.tools; for (var j = 0; j < tools.length; ++j) { diff --git a/browser/extensions/pdfjs/content/web/images/annotation-noicon.svg b/browser/extensions/pdfjs/content/web/images/annotation-noicon.svg new file mode 100644 index 000000000000..c07d1080832b --- /dev/null +++ b/browser/extensions/pdfjs/content/web/images/annotation-noicon.svg @@ -0,0 +1,7 @@ + + + diff --git a/browser/extensions/pdfjs/content/web/viewer.css b/browser/extensions/pdfjs/content/web/viewer.css index 6865b132a586..832ea67e5e4e 100644 --- a/browser/extensions/pdfjs/content/web/viewer.css +++ b/browser/extensions/pdfjs/content/web/viewer.css @@ -1157,14 +1157,7 @@ canvas { background-color: white; } -.page > a, -.annotationLayer > a { - display: block; - position: absolute; -} - -.page > a:hover, -.annotationLayer > a:hover { +.annotLink > a:hover { opacity: 0.2; background: #ff0; box-shadow: 0px 2px 10px #ff0; @@ -1229,29 +1222,49 @@ canvas { ::selection { background:rgba(0,0,255,0.3); } ::-moz-selection { background:rgba(0,0,255,0.3); } -.annotText > div { - z-index: 200; +.annotationHighlight { position: absolute; - padding: 0.6em; - max-width: 20em; - background-color: #FFFF99; - box-shadow: 0px 2px 10px #333; - border-radius: 7px; + border: 2px #FFFF99 solid; } .annotText > img { position: absolute; - opacity: 0.6; + cursor: pointer; } -.annotText > img:hover { - opacity: 1; +.annotTextContentWrapper { + position: absolute; + width: 20em; } -.annotText > div > h1 { - font-size: 1.2em; +.annotTextContent { + z-index: 200; + float: left; + max-width: 20em; + background-color: #FFFF99; + box-shadow: 0px 2px 5px #333; + border-radius: 2px; + padding: 0.6em; + cursor: pointer; +} + +.annotTextContent > h1 { + font-size: 1em; border-bottom: 1px solid #000000; - margin: 0px; + padding-bottom: 0.2em; +} + +.annotTextContent > p { + padding-top: 0.2em; +} + +.annotLink > a { + position: absolute; + font-size: 1em; + top: 0; + left: 0; + width: 100%; + height: 100%; } #errorWrapper { diff --git a/browser/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js index 6135b5abf566..74148ba582a9 100644 --- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -68,10 +68,9 @@ var CustomStyle = (function CustomStyleClosure() { // in some versions of IE9 it is critical that ms appear in this list // before Moz var prefixes = ['ms', 'Moz', 'Webkit', 'O']; - var _cache = { }; + var _cache = {}; - function CustomStyle() { - } + function CustomStyle() {} CustomStyle.getProp = function get(propName, element) { // check cache only when no element is given @@ -104,8 +103,9 @@ var CustomStyle = (function CustomStyleClosure() { CustomStyle.setProp = function set(propName, element, str) { var prop = this.getProp(propName); - if (prop != 'undefined') + if (prop != 'undefined') { element.style[prop] = str; + } }; return CustomStyle; @@ -291,11 +291,13 @@ var Cache = function cacheCache(size) { var data = []; this.push = function cachePush(view) { var i = data.indexOf(view); - if (i >= 0) + if (i >= 0) { data.splice(i); + } data.push(view); - if (data.length > size) + if (data.length > size) { data.shift().destroy(); + } }; }; @@ -315,12 +317,13 @@ var Preferences = (function PreferencesClosure() { function Preferences() { this.prefs = {}; this.isInitializedPromiseResolved = false; - this.initializedPromise = this.readFromStorage().then(function(prefObj) { - this.isInitializedPromiseResolved = true; - if (prefObj) { - this.prefs = prefObj; - } - }.bind(this)); + this.initializedPromise = this.readFromStorage(DEFAULT_PREFERENCES).then( + function(prefObj) { + this.isInitializedPromiseResolved = true; + if (prefObj) { + this.prefs = prefObj; + } + }.bind(this)); } Preferences.prototype = { @@ -328,7 +331,7 @@ var Preferences = (function PreferencesClosure() { return; }, - readFromStorage: function Preferences_readFromStorage() { + readFromStorage: function Preferences_readFromStorage(prefObj) { var readFromStoragePromise = Promise.resolve(); return readFromStoragePromise; }, @@ -336,7 +339,7 @@ var Preferences = (function PreferencesClosure() { reset: function Preferences_reset() { if (this.isInitializedPromiseResolved) { this.prefs = {}; - this.writeToStorage(this.prefs); + this.writeToStorage(DEFAULT_PREFERENCES); } }, @@ -361,6 +364,12 @@ var Preferences = (function PreferencesClosure() { valueType + '\", expected a \"' + defaultType + '\".'); return; } + } else { + if (valueType === 'number' && (value | 0) !== value) { + console.error('Preferences_set: \'' + value + + '\' must be an \"integer\".'); + return; + } } this.prefs[name] = value; this.writeToStorage(this.prefs); @@ -427,8 +436,8 @@ var FirefoxCom = (function FirefoxComClosure() { var request = document.createTextNode(''); if (callback) { document.addEventListener('pdf.js.response', function listener(event) { - var node = event.target, - response = event.detail.response; + var node = event.target; + var response = event.detail.response; document.documentElement.removeChild(node); @@ -483,9 +492,10 @@ Preferences.prototype.writeToStorage = function(prefObj) { FirefoxCom.requestSync('setPreferences', prefObj); }; -Preferences.prototype.readFromStorage = function() { +Preferences.prototype.readFromStorage = function(prefObj) { var readFromStoragePromise = new Promise(function (resolve) { - var readPrefs = JSON.parse(FirefoxCom.requestSync('getPreferences')); + var readPrefs = JSON.parse(FirefoxCom.requestSync('getPreferences', + prefObj)); resolve(readPrefs); }); return readFromStoragePromise; @@ -576,8 +586,6 @@ var ViewHistory = (function ViewHistoryClosure() { })(); -/* globals PDFFindController, FindStates, mozL10n */ - /** * Creates a "search bar" given set of DOM elements * that act as controls for searching, or for setting @@ -586,7 +594,6 @@ var ViewHistory = (function ViewHistoryClosure() { * searching is done by PDFFindController */ var PDFFindBar = { - opened: false, bar: null, toggleButton: null, @@ -600,7 +607,7 @@ var PDFFindBar = { initialize: function(options) { if(typeof PDFFindController === 'undefined' || PDFFindController === null) { - throw 'PDFFindBar cannot be initialized ' + + throw 'PDFFindBar cannot be initialized ' + 'without a PDFFindController instance.'; } @@ -715,8 +722,9 @@ var PDFFindBar = { }, close: function() { - if (!this.opened) return; - + if (!this.opened) { + return; + } this.opened = false; this.toggleButton.classList.remove('toggled'); this.bar.classList.add('hidden'); @@ -735,8 +743,6 @@ var PDFFindBar = { -/* globals PDFFindBar, PDFJS, FindStates, FirefoxCom, Promise */ - /** * Provides a "search" or "find" functionality for the PDF. * This object actually performs the search for a given string. @@ -876,8 +882,9 @@ var PDFFindController = { self.pageContents.push(str); extractTextPromisesResolves[pageIndex](pageIndex); - if ((pageIndex + 1) < self.pdfPageSource.pages.length) + if ((pageIndex + 1) < self.pdfPageSource.pages.length) { extractPageText(pageIndex + 1); + } } ); } @@ -2432,10 +2439,11 @@ var PDFView = { viewAreaElement.addEventListener('scroll', function webViewerScroll(evt) { var currentY = viewAreaElement.scrollTop; var lastY = state.lastY; - if (currentY > lastY) + if (currentY > lastY) { state.down = true; - else if (currentY < lastY) + } else if (currentY < lastY) { state.down = false; + } // else do nothing and use previous value state.lastY = currentY; callback(); @@ -2688,8 +2696,9 @@ var PDFView = { } var args = e.data; - if (typeof args !== 'object' || !('pdfjsLoadAction' in args)) + if (typeof args !== 'object' || !('pdfjsLoadAction' in args)) { return; + } switch (args.pdfjsLoadAction) { case 'supportsRangedLoading': PDFView.open(args.pdfUrl, 0, undefined, pdfDataRangeTransport, { @@ -2884,8 +2893,9 @@ var PDFView = { }, getDestinationHash: function pdfViewGetDestinationHash(dest) { - if (typeof dest === 'string') + if (typeof dest === 'string') { return PDFView.getAnchorUrl('#' + escape(dest)); + } if (dest instanceof Array) { var destRef = dest[0]; // see navigateTo method for dest format var pageNumber = destRef instanceof Object ? @@ -3003,15 +3013,18 @@ var PDFView = { var thumbsView = document.getElementById('thumbnailView'); thumbsView.parentNode.scrollTop = 0; - while (thumbsView.hasChildNodes()) + while (thumbsView.hasChildNodes()) { thumbsView.removeChild(thumbsView.lastChild); + } - if ('_loadingInterval' in thumbsView) + if ('_loadingInterval' in thumbsView) { clearInterval(thumbsView._loadingInterval); + } var container = document.getElementById('viewer'); - while (container.hasChildNodes()) + while (container.hasChildNodes()) { container.removeChild(container.lastChild); + } var pagesCount = pdfDocument.numPages; @@ -3178,16 +3191,17 @@ var PDFView = { (PDFJS.version ? ' (PDF.js: ' + PDFJS.version + ')' : '')); var pdfTitle; - if (metadata) { - if (metadata.has('dc:title')) - pdfTitle = metadata.get('dc:title'); + if (metadata && metadata.has('dc:title')) { + pdfTitle = metadata.get('dc:title'); } - if (!pdfTitle && info && info['Title']) + if (!pdfTitle && info && info['Title']) { pdfTitle = info['Title']; + } - if (pdfTitle) + if (pdfTitle) { self.setTitle(pdfTitle + ' - ' + document.title); + } if (info.IsAcroFormPresent) { console.warn('Warning: AcroForm/XFA is not supported'); @@ -3313,21 +3327,24 @@ var PDFView = { } for (var i = 0; i < numVisible; ++i) { var view = visibleViews[i].view; - if (!this.isViewFinished(view)) + if (!this.isViewFinished(view)) { return view; + } } // All the visible views have rendered, try to render next/previous pages. if (scrolledDown) { var nextPageIndex = visible.last.id; // ID's start at 1 so no need to add 1. - if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) + if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) { return views[nextPageIndex]; + } } else { var previousPageIndex = visible.first.id - 2; if (views[previousPageIndex] && - !this.isViewFinished(views[previousPageIndex])) + !this.isViewFinished(views[previousPageIndex])) { return views[previousPageIndex]; + } } // Everything that needs to be rendered has been. return false; @@ -3360,8 +3377,9 @@ var PDFView = { }, setHash: function pdfViewSetHash(hash) { - if (!hash) + if (!hash) { return; + } if (hash.indexOf('=') >= 0) { var params = PDFView.parseQueryString(hash); @@ -3449,8 +3467,9 @@ var PDFView = { thumbsView.classList.add('hidden'); outlineView.classList.remove('hidden'); - if (outlineButton.getAttribute('disabled')) + if (outlineButton.getAttribute('disabled')) { return; + } break; } }, @@ -3567,8 +3586,9 @@ var PDFView = { afterPrint: function pdfViewSetupAfterPrint() { var div = document.getElementById('printContainer'); - while (div.hasChildNodes()) + while (div.hasChildNodes()) { div.removeChild(div.lastChild); + } }, rotatePages: function pdfViewRotatePages(delta) { @@ -3610,14 +3630,16 @@ var PDFView = { // In case one page has already been flipped there is a cooldown time // which has to expire before next page can be scrolled on to. if (currentTime > storedTime && - currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) + currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) { return; + } // In case the user decides to scroll to the opposite direction than before // clear the accumulated delta. if ((this.mouseScrollDelta > 0 && mouseScrollDelta < 0) || - (this.mouseScrollDelta < 0 && mouseScrollDelta > 0)) + (this.mouseScrollDelta < 0 && mouseScrollDelta > 0)) { this.clearMouseScrollState(); + } this.mouseScrollDelta += mouseScrollDelta; @@ -3640,8 +3662,9 @@ var PDFView = { // to do anything. if ((currentPage == 1 && pageFlipDirection == PageFlipDirection.UP) || (currentPage == this.pages.length && - pageFlipDirection == PageFlipDirection.DOWN)) + pageFlipDirection == PageFlipDirection.DOWN)) { return; + } this.page += pageFlipDirection; this.mouseScrollTimeStamp = currentTime; @@ -3946,10 +3969,13 @@ var PageView = function pageView(container, id, scale, CustomStyle.setProp('transformOrigin', element, transformOriginStr); if (data.subtype === 'Link' && !data.url) { - if (data.action) { - bindNamedAction(element, data.action); - } else { - bindLink(element, ('dest' in data) ? data.dest : null); + var link = element.getElementsByTagName('a')[0]; + if (link) { + if (data.action) { + bindNamedAction(link, data.action); + } else { + bindLink(link, ('dest' in data) ? data.dest : null); + } } } @@ -4215,6 +4241,7 @@ var PageView = function pageView(container, id, scale, canvasContext: ctx, viewport: this.viewport, textLayer: textLayer, + // intent: 'default', // === 'display' continueCallback: function pdfViewcContinueCallback(cont) { if (PDFView.highestPriorityPage !== 'page' + self.id) { self.renderingState = RenderingStates.PAUSED; @@ -4286,13 +4313,13 @@ var PageView = function pageView(container, id, scale, var renderContext = { canvasContext: ctx, - viewport: viewport + viewport: viewport, + intent: 'print' }; pdfPage.render(renderContext).promise.then(function() { // Tell the printEngine that rendering this canvas/page has finished. obj.done(); - self.pdfPage.destroy(); }, function(error) { console.error(error); // Tell the printEngine that rendering this canvas/page has failed. @@ -4302,7 +4329,6 @@ var PageView = function pageView(container, id, scale, } else { obj.done(); } - self.pdfPage.destroy(); }); }; }; @@ -4522,12 +4548,12 @@ var TextLayerBuilder = function textLayerBuilder(options) { this.viewport = options.viewport; this.isViewerInPresentationMode = options.isViewerInPresentationMode; - if(typeof PDFFindController === 'undefined') { - window.PDFFindController = null; + if (typeof PDFFindController === 'undefined') { + window.PDFFindController = null; } - if(typeof this.lastScrollSource === 'undefined') { - this.lastScrollSource = null; + if (typeof this.lastScrollSource === 'undefined') { + this.lastScrollSource = null; } this.beginLayout = function textLayerBuilderBeginLayout() { @@ -4548,8 +4574,9 @@ var TextLayerBuilder = function textLayerBuilder(options) { // No point in rendering so many divs as it'd make the browser unusable // even after the divs are rendered var MAX_TEXT_DIVS_TO_RENDER = 100000; - if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) + if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) { return; + } for (var i = 0, ii = textDivs.length; i < ii; i++) { var textDiv = textDivs[i]; @@ -4581,16 +4608,17 @@ var TextLayerBuilder = function textLayerBuilder(options) { // run it right away var RENDER_DELAY = 200; // in ms var self = this; - var lastScroll = this.lastScrollSource === null ? - 0 : this.lastScrollSource.lastScroll; + var lastScroll = (this.lastScrollSource === null ? + 0 : this.lastScrollSource.lastScroll); if (Date.now() - lastScroll > RENDER_DELAY) { // Render right away this.renderLayer(); } else { // Schedule - if (this.renderTimer) + if (this.renderTimer) { clearTimeout(this.renderTimer); + } this.renderTimer = setTimeout(function() { self.setupRenderLayoutTimer(); }, RENDER_DELAY); @@ -4608,8 +4636,8 @@ var TextLayerBuilder = function textLayerBuilder(options) { textDiv.style.fontSize = fontHeight + 'px'; textDiv.style.fontFamily = geom.fontFamily; - var fontAscent = geom.ascent ? geom.ascent * fontHeight : - geom.descent ? (1 + geom.descent) * fontHeight : fontHeight; + var fontAscent = (geom.ascent ? geom.ascent * fontHeight : + (geom.descent ? (1 + geom.descent) * fontHeight : fontHeight)); textDiv.style.left = (geom.x + (fontAscent * Math.sin(geom.angle))) + 'px'; textDiv.style.top = (geom.y - (fontAscent * Math.cos(geom.angle))) + 'px'; @@ -4621,8 +4649,9 @@ var TextLayerBuilder = function textLayerBuilder(options) { this.insertDivContent = function textLayerUpdateTextContent() { // Only set the content of the divs once layout has finished, the content // for the divs is available and content is not yet set on the divs. - if (!this.layoutDone || this.divContentDone || !this.textContent) + if (!this.layoutDone || this.divContentDone || !this.textContent) { return; + } this.divContentDone = true; @@ -4661,8 +4690,8 @@ var TextLayerBuilder = function textLayerBuilder(options) { var iIndex = 0; var bidiTexts = this.textContent; var end = bidiTexts.length - 1; - var queryLen = PDFFindController === null ? - 0 : PDFFindController.state.query.length; + var queryLen = (PDFFindController === null ? + 0 : PDFFindController.state.query.length); var lastDivIdx = -1; var pos; @@ -4721,14 +4750,14 @@ var TextLayerBuilder = function textLayerBuilder(options) { var bidiTexts = this.textContent; var textDivs = this.textDivs; var prevEnd = null; - var isSelectedPage = PDFFindController === null ? - false : (this.pageIdx === PDFFindController.selected.pageIdx); + var isSelectedPage = (PDFFindController === null ? + false : (this.pageIdx === PDFFindController.selected.pageIdx)); - var selectedMatchIdx = PDFFindController === null ? - -1 : PDFFindController.selected.matchIdx; + var selectedMatchIdx = (PDFFindController === null ? + -1 : PDFFindController.selected.matchIdx); - var highlightAll = PDFFindController === null ? - false : PDFFindController.state.highlightAll; + var highlightAll = (PDFFindController === null ? + false : PDFFindController.state.highlightAll); var infty = { divIdx: -1, @@ -4827,8 +4856,9 @@ var TextLayerBuilder = function textLayerBuilder(options) { this.updateMatches = function textLayerUpdateMatches() { // Only show matches, once all rendering is done. - if (!this.renderingDone) + if (!this.renderingDone) { return; + } // Clear out all matches. var matches = this.matches; @@ -4848,14 +4878,14 @@ var TextLayerBuilder = function textLayerBuilder(options) { clearedUntilDivIdx = match.end.divIdx + 1; } - if (PDFFindController === null || !PDFFindController.active) + if (PDFFindController === null || !PDFFindController.active) { return; + } // Convert the matches on the page controller into the match format used // for the textLayer. - this.matches = matches = - this.convertMatches(PDFFindController === null ? - [] : (PDFFindController.pageMatches[this.pageIdx] || [])); + this.matches = matches = (this.convertMatches(PDFFindController === null ? + [] : (PDFFindController.pageMatches[this.pageIdx] || []))); this.renderMatches(this.matches); }; @@ -4866,13 +4896,14 @@ var TextLayerBuilder = function textLayerBuilder(options) { var DocumentOutlineView = function documentOutlineView(outline) { var outlineView = document.getElementById('outlineView'); var outlineButton = document.getElementById('viewOutline'); - while (outlineView.firstChild) + while (outlineView.firstChild) { outlineView.removeChild(outlineView.firstChild); + } if (!outline) { - if (!outlineView.classList.contains('hidden')) + if (!outlineView.classList.contains('hidden')) { PDFView.switchSidebarView('thumbs'); - + } return; } @@ -5101,8 +5132,9 @@ document.addEventListener('DOMContentLoaded', webViewerLoad, true); function updateViewarea() { - if (!PDFView.initialized) + if (!PDFView.initialized) { return; + } var visible = PDFView.getVisiblePages(); var visiblePages = visible.views; if (visiblePages.length === 0) { @@ -5118,9 +5150,9 @@ function updateViewarea() { i < ii; ++i) { var page = visiblePages[i]; - if (page.percent < 100) + if (page.percent < 100) { break; - + } if (page.id === PDFView.page) { stillFullyVisible = true; break; @@ -5473,23 +5505,6 @@ window.addEventListener('keydown', function keydown(evt) { PDFView.rotatePages(90); break; } - if (!handled && !PresentationMode.active) { - // 33=Page Up 34=Page Down 35=End 36=Home - // 37=Left 38=Up 39=Right 40=Down - if (evt.keyCode >= 33 && evt.keyCode <= 40 && - !PDFView.container.contains(curElement)) { - // The page container is not focused, but a page navigation key has been - // pressed. Change the focus to the viewer container to make sure that - // navigation by keyboard works as expected. - PDFView.container.focus(); - } - // 32=Spacebar - if (evt.keyCode === 32 && curElementTagName !== 'BUTTON') { - // Workaround for issue in Firefox, that prevents scroll keys from working - // when elements with 'tabindex' are focused. (#3499) - PDFView.container.blur(); - } - } } if (cmd === 4) { // shift-key @@ -5509,6 +5524,24 @@ window.addEventListener('keydown', function keydown(evt) { } } + if (!handled && !PresentationMode.active) { + // 33=Page Up 34=Page Down 35=End 36=Home + // 37=Left 38=Up 39=Right 40=Down + if (evt.keyCode >= 33 && evt.keyCode <= 40 && + !PDFView.container.contains(curElement)) { + // The page container is not focused, but a page navigation key has been + // pressed. Change the focus to the viewer container to make sure that + // navigation by keyboard works as expected. + PDFView.container.focus(); + } + // 32=Spacebar + if (evt.keyCode === 32 && curElementTagName !== 'BUTTON') { + // Workaround for issue in Firefox, that prevents scroll keys from + // working when elements with 'tabindex' are focused. (#3498) + PDFView.container.blur(); + } + } + if (cmd === 2) { // alt-key switch (evt.keyCode) { case 37: // left arrow