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.
This commit is contained in:
Jonas Jenwald 2018-06-11 17:25:54 +02:00
parent 4b69bb7fe9
commit d4ff541b78
2 changed files with 108 additions and 2 deletions

View File

@ -14,7 +14,7 @@
*/ */
import { import {
FormatError, info, isString, shadow, unreachable, warn assert, FormatError, info, isString, shadow, unreachable, warn
} from '../shared/util'; } from '../shared/util';
import { isDict, isName, isStream } from './primitives'; import { isDict, isName, isStream } from './primitives';
@ -109,6 +109,11 @@ var ColorSpace = (function ColorSpaceClosure() {
*/ */
fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight,
bpc, comps, alpha01) { 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 count = originalWidth * originalHeight;
var rgbBuf = null; var rgbBuf = null;
var numComponentColors = 1 << bpc; var numComponentColors = 1 << bpc;
@ -433,11 +438,21 @@ var AlternateCS = (function AlternateCSClosure() {
AlternateCS.prototype = { AlternateCS.prototype = {
getRgb: ColorSpace.prototype.getRgb, getRgb: ColorSpace.prototype.getRgb,
getRgbItem(src, srcOffset, dest, destOffset) { 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; var tmpBuf = this.tmpBuf;
this.tintFn(src, srcOffset, tmpBuf, 0); this.tintFn(src, srcOffset, tmpBuf, 0);
this.base.getRgbItem(tmpBuf, 0, dest, destOffset); this.base.getRgbItem(tmpBuf, 0, dest, destOffset);
}, },
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { 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 tintFn = this.tintFn;
var base = this.base; var base = this.base;
var scale = 1 / ((1 << bits) - 1); var scale = 1 / ((1 << bits) - 1);
@ -529,11 +544,21 @@ var IndexedCS = (function IndexedCSClosure() {
IndexedCS.prototype = { IndexedCS.prototype = {
getRgb: ColorSpace.prototype.getRgb, getRgb: ColorSpace.prototype.getRgb,
getRgbItem(src, srcOffset, dest, destOffset) { 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 numComps = this.base.numComps;
var start = src[srcOffset] * numComps; var start = src[srcOffset] * numComps;
this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0); this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0);
}, },
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { 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 base = this.base;
var numComps = base.numComps; var numComps = base.numComps;
var outputDelta = base.getOutputLength(numComps, alpha01); var outputDelta = base.getOutputLength(numComps, alpha01);
@ -570,10 +595,20 @@ var DeviceGrayCS = (function DeviceGrayCSClosure() {
DeviceGrayCS.prototype = { DeviceGrayCS.prototype = {
getRgb: ColorSpace.prototype.getRgb, getRgb: ColorSpace.prototype.getRgb,
getRgbItem(src, srcOffset, dest, destOffset) { 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; let c = src[srcOffset] * 255;
dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
}, },
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { 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 scale = 255 / ((1 << bits) - 1);
var j = srcOffset, q = destOffset; var j = srcOffset, q = destOffset;
for (var i = 0; i < count; ++i) { for (var i = 0; i < count; ++i) {
@ -606,11 +641,21 @@ var DeviceRgbCS = (function DeviceRgbCSClosure() {
DeviceRgbCS.prototype = { DeviceRgbCS.prototype = {
getRgb: ColorSpace.prototype.getRgb, getRgb: ColorSpace.prototype.getRgb,
getRgbItem(src, srcOffset, dest, destOffset) { 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] = src[srcOffset] * 255;
dest[destOffset + 1] = src[srcOffset + 1] * 255; dest[destOffset + 1] = src[srcOffset + 1] * 255;
dest[destOffset + 2] = src[srcOffset + 2] * 255; dest[destOffset + 2] = src[srcOffset + 2] * 255;
}, },
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { 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) { if (bits === 8 && alpha01 === 0) {
dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
return; return;
@ -692,9 +737,19 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() {
DeviceCmykCS.prototype = { DeviceCmykCS.prototype = {
getRgb: ColorSpace.prototype.getRgb, getRgb: ColorSpace.prototype.getRgb,
getRgbItem(src, srcOffset, dest, destOffset) { 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); convertToRgb(src, srcOffset, 1, dest, destOffset);
}, },
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { 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); var scale = 1 / ((1 << bits) - 1);
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
convertToRgb(src, srcOffset, scale, dest, destOffset); convertToRgb(src, srcOffset, scale, dest, destOffset);
@ -786,9 +841,19 @@ var CalGrayCS = (function CalGrayCSClosure() {
CalGrayCS.prototype = { CalGrayCS.prototype = {
getRgb: ColorSpace.prototype.getRgb, getRgb: ColorSpace.prototype.getRgb,
getRgbItem(src, srcOffset, dest, destOffset) { 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); convertToRgb(this, src, srcOffset, dest, destOffset, 1);
}, },
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { 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); var scale = 1 / ((1 << bits) - 1);
for (var i = 0; i < count; ++i) { for (var i = 0; i < count; ++i) {
@ -1075,9 +1140,19 @@ var CalRGBCS = (function CalRGBCSClosure() {
CalRGBCS.prototype = { CalRGBCS.prototype = {
getRgb: ColorSpace.prototype.getRgb, getRgb: ColorSpace.prototype.getRgb,
getRgbItem(src, srcOffset, dest, destOffset) { 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); convertToRgb(this, src, srcOffset, dest, destOffset, 1);
}, },
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { 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); var scale = 1 / ((1 << bits) - 1);
for (var i = 0; i < count; ++i) { for (var i = 0; i < count; ++i) {
@ -1218,9 +1293,19 @@ var LabCS = (function LabCSClosure() {
LabCS.prototype = { LabCS.prototype = {
getRgb: ColorSpace.prototype.getRgb, getRgb: ColorSpace.prototype.getRgb,
getRgbItem(src, srcOffset, dest, destOffset) { 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); convertToRgb(this, src, srcOffset, false, dest, destOffset);
}, },
getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { 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; var maxVal = (1 << bits) - 1;
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
convertToRgb(this, src, srcOffset, maxVal, dest, destOffset); convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);

View File

@ -244,6 +244,11 @@ var PDFImage = (function PDFImageClosure() {
PDFImage.createMask = function({ imgArray, width, height, PDFImage.createMask = function({ imgArray, width, height,
imageIsFromDecodeStream, inverseDecode, }) { 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 // |imgArray| might not contain full data for every pixel of the mask, so
// we need to distinguish between |computedLength| and |actualLength|. // we need to distinguish between |computedLength| and |actualLength|.
// In particular, if inverseDecode is true, then the array we return must // 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) { 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 smask = this.smask;
var mask = this.mask; var mask = this.mask;
var alphaBuf, sw, sh, i, ii, j; var alphaBuf, sw, sh, i, ii, j;
@ -465,6 +475,11 @@ var PDFImage = (function PDFImageClosure() {
}, },
undoPreblend(buffer, width, height) { 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; var matte = this.smask && this.smask.matte;
if (!matte) { if (!matte) {
return; return;
@ -544,7 +559,8 @@ var PDFImage = (function PDFImageClosure() {
} }
if (this.needsDecode) { if (this.needsDecode) {
// Invert the buffer (which must be grayscale if we reached here). // 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; var buffer = imgData.data;
for (var i = 0, ii = buffer.length; i < ii; i++) { for (var i = 0, ii = buffer.length; i < ii; i++) {
buffer[i] ^= 0xff; buffer[i] ^= 0xff;
@ -610,6 +626,11 @@ var PDFImage = (function PDFImageClosure() {
}, },
fillGrayBuffer(buffer) { fillGrayBuffer(buffer) {
if (typeof PDFJSDev === 'undefined' ||
PDFJSDev.test('!PRODUCTION || TESTING')) {
assert(buffer instanceof Uint8ClampedArray,
'PDFImage.fillGrayBuffer: Unsupported "buffer" type.');
}
var numComps = this.numComps; var numComps = this.numComps;
if (numComps !== 1) { if (numComps !== 1) {
throw new FormatError( throw new FormatError(