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 {
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);

View File

@ -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(