From 7ee370a394bcc4cc1a2b5af90ee8abf4571ed69b Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 11 Aug 2019 13:40:58 +0200 Subject: [PATCH 1/3] Remove the `skipEmpty` parameter from `Util.intersect` (PR 11059 follow-up) Looking at this again, it struck me that added functionality in `Util.intersect` is probably more confusing than helpful in general; sorry about the churn in this code! Based on the parameter name you'd probably expect it to only match when the intersection is `[0, 0, 0, 0]` and not when only one component is zero, hence the `skipEmpty` parameter thus feels too tightly coupled to the `Page.view` getter. --- src/core/document.js | 4 ++-- src/shared/util.js | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/core/document.js b/src/core/document.js index 993f8fa39..aba5117ef 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -137,8 +137,8 @@ class Page { if (cropBox === mediaBox || isArrayEqual(cropBox, mediaBox)) { view = mediaBox; } else { - const box = Util.intersect(cropBox, mediaBox, /* skipEmpty = */ true); - if (box) { + const box = Util.intersect(cropBox, mediaBox); + if (box && ((box[2] - box[0]) !== 0 && (box[3] - box[1]) !== 0)) { view = box; } else { warn('Empty /CropBox and /MediaBox intersection.'); diff --git a/src/shared/util.js b/src/shared/util.js index bc29e9d2b..e2545ffc0 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -748,7 +748,7 @@ var Util = (function UtilClosure() { // Returns a rectangle [x1, y1, x2, y2] corresponding to the // intersection of rect1 and rect2. If no intersection, returns 'false' // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2] - Util.intersect = function Util_intersect(rect1, rect2, skipEmpty = false) { + Util.intersect = function Util_intersect(rect1, rect2) { function compare(a, b) { return a - b; } @@ -781,10 +781,6 @@ var Util = (function UtilClosure() { return null; } - if (skipEmpty && - ((result[2] - result[0]) === 0 || (result[3] - result[1]) === 0)) { - return null; - } return result; }; From f6c4a1f08088c707be90a774ae394951d94133de Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 11 Aug 2019 13:56:15 +0200 Subject: [PATCH 2/3] Convert `Util` to a class with static methods Also replaces `var` with `const` in all the relevant code. --- src/shared/util.js | 102 +++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 55 deletions(-) diff --git a/src/shared/util.js b/src/shared/util.js index e2545ffc0..cf9d3da9c 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -627,22 +627,20 @@ function isEvalSupported() { } } -var Util = (function UtilClosure() { - function Util() {} +const rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')']; - var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')']; - - // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids +class Util { + // makeCssRgb() can be called thousands of times. Using ´rgbBuf` avoids // creating many intermediate strings. - Util.makeCssRgb = function Util_makeCssRgb(r, g, b) { + static makeCssRgb(r, g, b) { rgbBuf[1] = r; rgbBuf[3] = g; rgbBuf[5] = b; return rgbBuf.join(''); - }; + } // Concatenates two transformation matrices together and returns the result. - Util.transform = function Util_transform(m1, m2) { + static transform(m1, m2) { return [ m1[0] * m2[0] + m1[2] * m2[1], m1[1] * m2[0] + m1[3] * m2[1], @@ -651,44 +649,42 @@ var Util = (function UtilClosure() { m1[0] * m2[4] + m1[2] * m2[5] + m1[4], m1[1] * m2[4] + m1[3] * m2[5] + m1[5] ]; - }; + } // For 2d affine transforms - Util.applyTransform = function Util_applyTransform(p, m) { - var xt = p[0] * m[0] + p[1] * m[2] + m[4]; - var yt = p[0] * m[1] + p[1] * m[3] + m[5]; + static applyTransform(p, m) { + const xt = p[0] * m[0] + p[1] * m[2] + m[4]; + const yt = p[0] * m[1] + p[1] * m[3] + m[5]; return [xt, yt]; - }; + } - Util.applyInverseTransform = function Util_applyInverseTransform(p, m) { - var d = m[0] * m[3] - m[1] * m[2]; - var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; - var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; + static applyInverseTransform(p, m) { + const d = m[0] * m[3] - m[1] * m[2]; + const xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; + const yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; return [xt, yt]; - }; + } // Applies the transform to the rectangle and finds the minimum axially // aligned bounding box. - Util.getAxialAlignedBoundingBox = - function Util_getAxialAlignedBoundingBox(r, m) { - - var p1 = Util.applyTransform(r, m); - var p2 = Util.applyTransform(r.slice(2, 4), m); - var p3 = Util.applyTransform([r[0], r[3]], m); - var p4 = Util.applyTransform([r[2], r[1]], m); + static getAxialAlignedBoundingBox(r, m) { + const p1 = Util.applyTransform(r, m); + const p2 = Util.applyTransform(r.slice(2, 4), m); + const p3 = Util.applyTransform([r[0], r[3]], m); + const p4 = Util.applyTransform([r[2], r[1]], m); return [ Math.min(p1[0], p2[0], p3[0], p4[0]), Math.min(p1[1], p2[1], p3[1], p4[1]), Math.max(p1[0], p2[0], p3[0], p4[0]), Math.max(p1[1], p2[1], p3[1], p4[1]) ]; - }; + } - Util.inverseTransform = function Util_inverseTransform(m) { - var d = m[0] * m[3] - m[1] * m[2]; + static inverseTransform(m) { + const d = m[0] * m[3] - m[1] * m[2]; return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d, (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d]; - }; + } // Apply a generic 3d matrix M on a 3-vector v: // | a b c | | X | @@ -696,44 +692,42 @@ var Util = (function UtilClosure() { // | g h i | | Z | // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i], // with v as [X,Y,Z] - Util.apply3dTransform = function Util_apply3dTransform(m, v) { + static apply3dTransform(m, v) { return [ m[0] * v[0] + m[1] * v[1] + m[2] * v[2], m[3] * v[0] + m[4] * v[1] + m[5] * v[2], m[6] * v[0] + m[7] * v[1] + m[8] * v[2] ]; - }; + } // This calculation uses Singular Value Decomposition. // The SVD can be represented with formula A = USV. We are interested in the // matrix S here because it represents the scale values. - Util.singularValueDecompose2dScale = - function Util_singularValueDecompose2dScale(m) { - - var transpose = [m[0], m[2], m[1], m[3]]; + static singularValueDecompose2dScale(m) { + const transpose = [m[0], m[2], m[1], m[3]]; // Multiply matrix m with its transpose. - var a = m[0] * transpose[0] + m[1] * transpose[2]; - var b = m[0] * transpose[1] + m[1] * transpose[3]; - var c = m[2] * transpose[0] + m[3] * transpose[2]; - var d = m[2] * transpose[1] + m[3] * transpose[3]; + const a = m[0] * transpose[0] + m[1] * transpose[2]; + const b = m[0] * transpose[1] + m[1] * transpose[3]; + const c = m[2] * transpose[0] + m[3] * transpose[2]; + const d = m[2] * transpose[1] + m[3] * transpose[3]; // Solve the second degree polynomial to get roots. - var first = (a + d) / 2; - var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; - var sx = first + second || 1; - var sy = first - second || 1; + const first = (a + d) / 2; + const second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; + const sx = first + second || 1; + const sy = first - second || 1; // Scale values are the square roots of the eigenvalues. return [Math.sqrt(sx), Math.sqrt(sy)]; - }; + } // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2) // For coordinate systems whose origin lies in the bottom-left, this // means normalization to (BL,TR) ordering. For systems with origin in the // top-left, this means (TL,BR) ordering. - Util.normalizeRect = function Util_normalizeRect(rect) { - var r = rect.slice(0); // clone rect + static normalizeRect(rect) { + const r = rect.slice(0); // clone rect if (rect[0] > rect[2]) { r[0] = rect[2]; r[2] = rect[0]; @@ -743,20 +737,20 @@ var Util = (function UtilClosure() { r[3] = rect[1]; } return r; - }; + } // Returns a rectangle [x1, y1, x2, y2] corresponding to the // intersection of rect1 and rect2. If no intersection, returns 'false' // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2] - Util.intersect = function Util_intersect(rect1, rect2) { + static intersect(rect1, rect2) { function compare(a, b) { return a - b; } // Order points along the axes - var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare), - orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare), - result = []; + const orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare); + const orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare); + const result = []; rect1 = Util.normalizeRect(rect1); rect2 = Util.normalizeRect(rect2); @@ -782,10 +776,8 @@ var Util = (function UtilClosure() { } return result; - }; - - return Util; -})(); + } +} const PDFStringTranslateTable = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, From 7f456b3e2e70752996e03dc8de8ea7d38ea4d2ae Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 11 Aug 2019 14:10:29 +0200 Subject: [PATCH 3/3] Replace of all usages of `var` with `let`/`const` in the `src/shared/util.js` file Also removes a couple of unnecessary (temporary) variable assigments in `arraysToBytes` and uses template strings in a few spots. --- src/shared/util.js | 103 ++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/src/shared/util.js b/src/shared/util.js index cf9d3da9c..b628f8b49 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* eslint no-var: error */ import './compatibility'; import { ReadableStream } from './streams_polyfill'; @@ -319,14 +320,14 @@ function getVerbosityLevel() { // end users. function info(msg) { if (verbosity >= VerbosityLevel.INFOS) { - console.log('Info: ' + msg); + console.log(`Info: ${msg}`); } } // Non-fatal warnings. function warn(msg) { if (verbosity >= VerbosityLevel.WARNINGS) { - console.log('Warning: ' + msg); + console.log(`Warning: ${msg}`); } } @@ -342,8 +343,9 @@ function assert(cond, msg) { // Checks if URLs have the same origin. For non-HTTP based URLs, returns false. function isSameOrigin(baseUrl, otherUrl) { + let base; try { - var base = new URL(baseUrl); + base = new URL(baseUrl); if (!base.origin || base.origin === 'null') { return false; // non-HTTP url } @@ -351,7 +353,7 @@ function isSameOrigin(baseUrl, otherUrl) { return false; } - var other = new URL(otherUrl, base); + const other = new URL(otherUrl, base); return base.origin === other.origin; } @@ -384,7 +386,7 @@ function createValidAbsoluteUrl(url, baseUrl) { return null; } try { - var absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); + const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url); if (_isValidProtocol(absoluteUrl)) { return absoluteUrl; } @@ -400,7 +402,7 @@ function shadow(obj, prop, value) { return value; } -var PasswordException = (function PasswordExceptionClosure() { +const PasswordException = (function PasswordExceptionClosure() { function PasswordException(msg, code) { this.name = 'PasswordException'; this.message = msg; @@ -413,7 +415,7 @@ var PasswordException = (function PasswordExceptionClosure() { return PasswordException; })(); -var UnknownErrorException = (function UnknownErrorExceptionClosure() { +const UnknownErrorException = (function UnknownErrorExceptionClosure() { function UnknownErrorException(msg, details) { this.name = 'UnknownErrorException'; this.message = msg; @@ -426,7 +428,7 @@ var UnknownErrorException = (function UnknownErrorExceptionClosure() { return UnknownErrorException; })(); -var InvalidPDFException = (function InvalidPDFExceptionClosure() { +const InvalidPDFException = (function InvalidPDFExceptionClosure() { function InvalidPDFException(msg) { this.name = 'InvalidPDFException'; this.message = msg; @@ -438,7 +440,7 @@ var InvalidPDFException = (function InvalidPDFExceptionClosure() { return InvalidPDFException; })(); -var MissingPDFException = (function MissingPDFExceptionClosure() { +const MissingPDFException = (function MissingPDFExceptionClosure() { function MissingPDFException(msg) { this.name = 'MissingPDFException'; this.message = msg; @@ -450,7 +452,7 @@ var MissingPDFException = (function MissingPDFExceptionClosure() { return MissingPDFException; })(); -var UnexpectedResponseException = +const UnexpectedResponseException = (function UnexpectedResponseExceptionClosure() { function UnexpectedResponseException(msg, status) { this.name = 'UnexpectedResponseException'; @@ -467,7 +469,7 @@ var UnexpectedResponseException = /** * Error caused during parsing PDF data. */ -let FormatError = (function FormatErrorClosure() { +const FormatError = (function FormatErrorClosure() { function FormatError(msg) { this.message = msg; } @@ -482,7 +484,7 @@ let FormatError = (function FormatErrorClosure() { /** * Error used to indicate task cancellation. */ -let AbortException = (function AbortExceptionClosure() { +const AbortException = (function AbortExceptionClosure() { function AbortException(msg) { this.name = 'AbortException'; this.message = msg; @@ -494,7 +496,7 @@ let AbortException = (function AbortExceptionClosure() { return AbortException; })(); -var NullCharactersRegExp = /\x00/g; +const NullCharactersRegExp = /\x00/g; function removeNullCharacters(str) { if (typeof str !== 'string') { @@ -507,15 +509,15 @@ function removeNullCharacters(str) { function bytesToString(bytes) { assert(bytes !== null && typeof bytes === 'object' && bytes.length !== undefined, 'Invalid argument for bytesToString'); - var length = bytes.length; - var MAX_ARGUMENT_COUNT = 8192; + const length = bytes.length; + const MAX_ARGUMENT_COUNT = 8192; if (length < MAX_ARGUMENT_COUNT) { return String.fromCharCode.apply(null, bytes); } - var strBuf = []; - for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) { - var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); - var chunk = bytes.subarray(i, chunkEnd); + const strBuf = []; + for (let i = 0; i < length; i += MAX_ARGUMENT_COUNT) { + const chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); + const chunk = bytes.subarray(i, chunkEnd); strBuf.push(String.fromCharCode.apply(null, chunk)); } return strBuf.join(''); @@ -523,9 +525,9 @@ function bytesToString(bytes) { function stringToBytes(str) { assert(typeof str === 'string', 'Invalid argument for stringToBytes'); - var length = str.length; - var bytes = new Uint8Array(length); - for (var i = 0; i < length; ++i) { + const length = str.length; + const bytes = new Uint8Array(length); + for (let i = 0; i < length; ++i) { bytes[i] = str.charCodeAt(i) & 0xFF; } return bytes; @@ -550,22 +552,19 @@ function arrayByteLength(arr) { * @returns {Uint8Array} */ function arraysToBytes(arr) { + const length = arr.length; // Shortcut: if first and only item is Uint8Array, return it. - if (arr.length === 1 && (arr[0] instanceof Uint8Array)) { + if (length === 1 && (arr[0] instanceof Uint8Array)) { return arr[0]; } - var resultLength = 0; - var i, ii = arr.length; - var item, itemLength; - for (i = 0; i < ii; i++) { - item = arr[i]; - itemLength = arrayByteLength(item); - resultLength += itemLength; + let resultLength = 0; + for (let i = 0; i < length; i++) { + resultLength += arrayByteLength(arr[i]); } - var pos = 0; - var data = new Uint8Array(resultLength); - for (i = 0; i < ii; i++) { - item = arr[i]; + let pos = 0; + const data = new Uint8Array(resultLength); + for (let i = 0; i < length; i++) { + let item = arr[i]; if (!(item instanceof Uint8Array)) { if (typeof item === 'string') { item = stringToBytes(item); @@ -573,7 +572,7 @@ function arraysToBytes(arr) { item = new Uint8Array(item); } } - itemLength = item.byteLength; + const itemLength = item.byteLength; data.set(item, pos); pos += itemLength; } @@ -611,9 +610,9 @@ function readUint32(data, offset) { // Lazy test the endianness of the platform // NOTE: This will be 'true' for simulated TypedArrays function isLittleEndian() { - var buffer8 = new Uint8Array(4); + const buffer8 = new Uint8Array(4); buffer8[0] = 1; - var view32 = new Uint32Array(buffer8.buffer, 0, 1); + const view32 = new Uint32Array(buffer8.buffer, 0, 1); return (view32[0] === 1); } @@ -792,16 +791,16 @@ const PDFStringTranslateTable = [ ]; function stringToPDFString(str) { - var i, n = str.length, strBuf = []; + const length = str.length, strBuf = []; if (str[0] === '\xFE' && str[1] === '\xFF') { // UTF16BE BOM - for (i = 2; i < n; i += 2) { + for (let i = 2; i < length; i += 2) { strBuf.push(String.fromCharCode( (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1))); } } else { - for (i = 0; i < n; ++i) { - var code = PDFStringTranslateTable[str.charCodeAt(i)]; + for (let i = 0; i < length; ++i) { + const code = PDFStringTranslateTable[str.charCodeAt(i)]; strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); } } @@ -817,7 +816,7 @@ function utf8StringToString(str) { } function isEmptyObj(obj) { - for (var key in obj) { + for (let key in obj) { return false; } return true; @@ -891,9 +890,9 @@ function createPromiseCapability() { return capability; } -var createObjectURL = (function createObjectURLClosure() { +const createObjectURL = (function createObjectURLClosure() { // Blob/createObjectURL is not available, falling back to data schema. - var digits = + const digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; return function createObjectURL(data, contentType, forceDataSchema = false) { @@ -902,14 +901,14 @@ var createObjectURL = (function createObjectURLClosure() { return URL.createObjectURL(blob); } - var buffer = 'data:' + contentType + ';base64,'; - for (var i = 0, ii = data.length; i < ii; i += 3) { - var b1 = data[i] & 0xFF; - var b2 = data[i + 1] & 0xFF; - var b3 = data[i + 2] & 0xFF; - var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4); - var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64; - var d4 = i + 2 < ii ? (b3 & 0x3F) : 64; + let buffer = `data:${contentType};base64,`; + for (let i = 0, ii = data.length; i < ii; i += 3) { + const b1 = data[i] & 0xFF; + const b2 = data[i + 1] & 0xFF; + const b3 = data[i + 2] & 0xFF; + const d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4); + const d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64; + const d4 = i + 2 < ii ? (b3 & 0x3F) : 64; buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; } return buffer;