From d4ff541b78cea1859705460085a0cad0f1ddcec9 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Mon, 11 Jun 2018 17:25:54 +0200 Subject: [PATCH] Enforce the use, in non-production/test-only mode, of `Uint8ClampedArray` in all relevant methods in `ColorSpace` and `PDFImage` Since `ColorSpace` now depends on the native clamping of `Uint8ClampedArray`, this patch adds non-production/test-only `assert`s to enforce that the expected TypedArray is used for the output. These `assert`s are purposely *not* included in PRODUCTION builds since that would break rendering completely, as opposed to "only" displaying some weird colours, when a `Uint8Array` was used. Furthermore, these are mostly added to help catch explicit developer errors when working with the `ColorSpace` and `PDFImage` code. --- src/core/colorspace.js | 87 +++++++++++++++++++++++++++++++++++++++++- src/core/image.js | 23 ++++++++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/core/colorspace.js b/src/core/colorspace.js index 0aa1b3986..7f784ce2c 100644 --- a/src/core/colorspace.js +++ b/src/core/colorspace.js @@ -14,7 +14,7 @@ */ import { - FormatError, info, isString, shadow, unreachable, warn + assert, FormatError, info, isString, shadow, unreachable, warn } from '../shared/util'; import { isDict, isName, isStream } from './primitives'; @@ -109,6 +109,11 @@ var ColorSpace = (function ColorSpaceClosure() { */ fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'ColorSpace.fillRgb: Unsupported "dest" type.'); + } var count = originalWidth * originalHeight; var rgbBuf = null; var numComponentColors = 1 << bpc; @@ -433,11 +438,21 @@ var AlternateCS = (function AlternateCSClosure() { AlternateCS.prototype = { getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'AlternateCS.getRgbItem: Unsupported "dest" type.'); + } var tmpBuf = this.tmpBuf; this.tintFn(src, srcOffset, tmpBuf, 0); this.base.getRgbItem(tmpBuf, 0, dest, destOffset); }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'AlternateCS.getRgbBuffer: Unsupported "dest" type.'); + } var tintFn = this.tintFn; var base = this.base; var scale = 1 / ((1 << bits) - 1); @@ -529,11 +544,21 @@ var IndexedCS = (function IndexedCSClosure() { IndexedCS.prototype = { getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'IndexedCS.getRgbItem: Unsupported "dest" type.'); + } var numComps = this.base.numComps; var start = src[srcOffset] * numComps; this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0); }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'IndexedCS.getRgbBuffer: Unsupported "dest" type.'); + } var base = this.base; var numComps = base.numComps; var outputDelta = base.getOutputLength(numComps, alpha01); @@ -570,10 +595,20 @@ var DeviceGrayCS = (function DeviceGrayCSClosure() { DeviceGrayCS.prototype = { getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceGrayCS.getRgbItem: Unsupported "dest" type.'); + } let c = src[srcOffset] * 255; dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceGrayCS.getRgbBuffer: Unsupported "dest" type.'); + } var scale = 255 / ((1 << bits) - 1); var j = srcOffset, q = destOffset; for (var i = 0; i < count; ++i) { @@ -606,11 +641,21 @@ var DeviceRgbCS = (function DeviceRgbCSClosure() { DeviceRgbCS.prototype = { getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceRgbCS.getRgbItem: Unsupported "dest" type.'); + } dest[destOffset] = src[srcOffset] * 255; dest[destOffset + 1] = src[srcOffset + 1] * 255; dest[destOffset + 2] = src[srcOffset + 2] * 255; }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceRgbCS.getRgbBuffer: Unsupported "dest" type.'); + } if (bits === 8 && alpha01 === 0) { dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); return; @@ -692,9 +737,19 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() { DeviceCmykCS.prototype = { getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceCmykCS.getRgbItem: Unsupported "dest" type.'); + } convertToRgb(src, srcOffset, 1, dest, destOffset); }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'DeviceCmykCS.getRgbBuffer: Unsupported "dest" type.'); + } var scale = 1 / ((1 << bits) - 1); for (var i = 0; i < count; i++) { convertToRgb(src, srcOffset, scale, dest, destOffset); @@ -786,9 +841,19 @@ var CalGrayCS = (function CalGrayCSClosure() { CalGrayCS.prototype = { getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'CalGrayCS.getRgbItem: Unsupported "dest" type.'); + } convertToRgb(this, src, srcOffset, dest, destOffset, 1); }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'CalGrayCS.getRgbBuffer: Unsupported "dest" type.'); + } var scale = 1 / ((1 << bits) - 1); for (var i = 0; i < count; ++i) { @@ -1075,9 +1140,19 @@ var CalRGBCS = (function CalRGBCSClosure() { CalRGBCS.prototype = { getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'CalRGBCS.getRgbItem: Unsupported "dest" type.'); + } convertToRgb(this, src, srcOffset, dest, destOffset, 1); }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'CalRGBCS.getRgbBuffer: Unsupported "dest" type.'); + } var scale = 1 / ((1 << bits) - 1); for (var i = 0; i < count; ++i) { @@ -1218,9 +1293,19 @@ var LabCS = (function LabCSClosure() { LabCS.prototype = { getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'LabCS.getRgbItem: Unsupported "dest" type.'); + } convertToRgb(this, src, srcOffset, false, dest, destOffset); }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(dest instanceof Uint8ClampedArray, + 'LabCS.getRgbBuffer: Unsupported "dest" type.'); + } var maxVal = (1 << bits) - 1; for (var i = 0; i < count; i++) { convertToRgb(this, src, srcOffset, maxVal, dest, destOffset); diff --git a/src/core/image.js b/src/core/image.js index f564e95b6..32a26d157 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -244,6 +244,11 @@ var PDFImage = (function PDFImageClosure() { PDFImage.createMask = function({ imgArray, width, height, imageIsFromDecodeStream, inverseDecode, }) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(imgArray instanceof Uint8ClampedArray, + 'PDFImage.createMask: Unsupported "imgArray" type.'); + } // |imgArray| might not contain full data for every pixel of the mask, so // we need to distinguish between |computedLength| and |actualLength|. // In particular, if inverseDecode is true, then the array we return must @@ -399,6 +404,11 @@ var PDFImage = (function PDFImageClosure() { }, fillOpacity(rgbaBuf, width, height, actualHeight, image) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(rgbaBuf instanceof Uint8ClampedArray, + 'PDFImage.fillOpacity: Unsupported "rgbaBuf" type.'); + } var smask = this.smask; var mask = this.mask; var alphaBuf, sw, sh, i, ii, j; @@ -465,6 +475,11 @@ var PDFImage = (function PDFImageClosure() { }, undoPreblend(buffer, width, height) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(buffer instanceof Uint8ClampedArray, + 'PDFImage.undoPreblend: Unsupported "buffer" type.'); + } var matte = this.smask && this.smask.matte; if (!matte) { return; @@ -544,7 +559,8 @@ var PDFImage = (function PDFImageClosure() { } if (this.needsDecode) { // Invert the buffer (which must be grayscale if we reached here). - assert(kind === ImageKind.GRAYSCALE_1BPP); + assert(kind === ImageKind.GRAYSCALE_1BPP, + 'PDFImage.createImageData: The image must be grayscale.'); var buffer = imgData.data; for (var i = 0, ii = buffer.length; i < ii; i++) { buffer[i] ^= 0xff; @@ -610,6 +626,11 @@ var PDFImage = (function PDFImageClosure() { }, fillGrayBuffer(buffer) { + if (typeof PDFJSDev === 'undefined' || + PDFJSDev.test('!PRODUCTION || TESTING')) { + assert(buffer instanceof Uint8ClampedArray, + 'PDFImage.fillGrayBuffer: Unsupported "buffer" type.'); + } var numComps = this.numComps; if (numComps !== 1) { throw new FormatError(