Remove most assert() calls (issue 8506)

This replaces `assert` calls with `throw new FormatError()`/`throw new Error()`.
In a few places, throwing an `Error` (which is what `assert` meant) isn't correct since the enclosing function is supposed to return a `Promise`, hence some cases were changed to `Promise.reject(...)` and similarily for `createPromiseCapability` instances.
This commit is contained in:
Jonas Jenwald 2017-07-20 14:04:54 +02:00
parent 09f04eccda
commit 814fa1dee3
12 changed files with 193 additions and 89 deletions

View File

@ -14,7 +14,7 @@
*/
import {
assert, bytesToString, FormatError, info, isArray, stringToBytes, Util, warn
bytesToString, FormatError, info, isArray, stringToBytes, Util, warn
} from '../shared/util';
import {
ExpertCharset, ExpertSubsetCharset, ISOAdobeCharset
@ -871,7 +871,9 @@ var CFFParser = (function CFFParserClosure() {
default:
throw new FormatError(`parseFDSelect: Unknown format "${format}".`);
}
assert(fdSelect.length === length, 'parseFDSelect: Invalid font data.');
if (fdSelect.length !== length) {
throw new FormatError('parseFDSelect: Invalid font data.');
}
return new CFFFDSelect(fdSelect, rawBytes);
},
@ -1440,9 +1442,10 @@ var CFFCompiler = (function CFFCompilerClosure() {
output) {
for (var i = 0, ii = dicts.length; i < ii; ++i) {
var fontDict = dicts[i];
assert(fontDict.privateDict && fontDict.hasName('Private'),
'There must be an private dictionary.');
var privateDict = fontDict.privateDict;
if (!privateDict || !fontDict.hasName('Private')) {
throw new FormatError('There must be a private dictionary.');
}
var privateDictTracker = new CFFOffsetTracker();
var privateDictData = this.compileDict(privateDict, privateDictTracker);

View File

@ -14,8 +14,8 @@
*/
import {
arrayByteLength, arraysToBytes, assert, createPromiseCapability, isEmptyObj,
isInt, MissingDataException
arrayByteLength, arraysToBytes, createPromiseCapability, isEmptyObj, isInt,
MissingDataException
} from '../shared/util';
var ChunkedStream = (function ChunkedStreamClosure() {
@ -58,12 +58,15 @@ var ChunkedStream = (function ChunkedStreamClosure() {
onReceiveData: function ChunkedStream_onReceiveData(begin, chunk) {
var end = begin + chunk.byteLength;
assert(begin % this.chunkSize === 0, 'Bad begin offset: ' + begin);
if (begin % this.chunkSize !== 0) {
throw new Error(`Bad begin offset: ${begin}`);
}
// Using this.length is inaccurate here since this.start can be moved
// See ChunkedStream.moveStart()
var length = this.bytes.length;
assert(end % this.chunkSize === 0 || end === length,
'Bad end offset: ' + end);
if (end % this.chunkSize !== 0 && end !== length) {
throw new Error(`Bad end offset: ${end}`);
}
this.bytes.set(new Uint8Array(chunk), begin);
var chunkSize = this.chunkSize;

View File

@ -14,8 +14,8 @@
*/
import {
assert, CMapCompressionType, FormatError, isInt, isString,
MissingDataException, Util, warn
CMapCompressionType, FormatError, isInt, isString, MissingDataException, Util,
warn
} from '../shared/util';
import { isCmd, isEOF, isName, isStream } from './primitives';
import { Lexer } from './parser';
@ -561,7 +561,9 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
var sequence = !!(b & 0x10);
var dataSize = b & 15;
assert(dataSize + 1 <= MAX_NUM_SIZE);
if (dataSize + 1 > MAX_NUM_SIZE) {
throw new Error('processBinaryCMap: Invalid dataSize.');
}
var ucs2DataSize = 1;
var subitemsCount = stream.readNumber();
@ -943,7 +945,10 @@ var CMapFactory = (function CMapFactoryClosure() {
if (BUILT_IN_CMAPS.indexOf(name) === -1) {
return Promise.reject(new Error('Unknown CMap name: ' + name));
}
assert(fetchBuiltInCMap, 'Built-in CMap parameters are not provided.');
if (!fetchBuiltInCMap) {
return Promise.reject(new Error(
'Built-in CMap parameters are not provided.'));
}
return fetchBuiltInCMap(name).then(function (data) {
var cMapData = data.cMapData, compressionType = data.compressionType;
@ -955,11 +960,12 @@ var CMapFactory = (function CMapFactoryClosure() {
return extendCMap(cMap, fetchBuiltInCMap, useCMap);
});
}
assert(compressionType === CMapCompressionType.NONE,
'TODO: Only BINARY/NONE CMap compression is currently supported.');
// Uncompressed CMap.
var lexer = new Lexer(new Stream(cMapData));
return parseCMap(cMap, lexer, fetchBuiltInCMap, null);
if (compressionType === CMapCompressionType.NONE) {
var lexer = new Lexer(new Stream(cMapData));
return parseCMap(cMap, lexer, fetchBuiltInCMap, null);
}
return Promise.reject(new Error(
'TODO: Only BINARY/NONE CMap compression is currently supported.'));
});
}

View File

@ -14,8 +14,8 @@
*/
import {
assert, bytesToString, FormatError, isInt, PasswordException,
PasswordResponses, stringToBytes, utf8StringToString, warn
bytesToString, FormatError, isInt, PasswordException, PasswordResponses,
stringToBytes, utf8StringToString, warn
} from '../shared/util';
import { isDict, isName, Name } from './primitives';
import { DecryptStream } from './stream';
@ -1997,7 +1997,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
}
function buildCipherConstructor(cf, name, num, gen, key) {
assert(isName(name), 'Invalid crypt filter name.');
if (!isName(name)) {
throw new FormatError('Invalid crypt filter name.');
}
var cryptFilter = cf.get(name.name);
var cfm;
if (cryptFilter !== null && cryptFilter !== undefined) {

View File

@ -13,13 +13,12 @@
* limitations under the License.
*/
import {
assert, info, isArray, isArrayBuffer, isNum, isSpace, isString,
MissingDataException, OPS, shadow, stringToBytes, stringToPDFString, Util,
warn
} from '../shared/util';
import { Catalog, ObjectLoader, XRef } from './obj';
import { Dict, isDict, isName, isStream } from './primitives';
import {
info, isArray, isArrayBuffer, isNum, isSpace, isString, MissingDataException,
OPS, shadow, stringToBytes, stringToPDFString, Util, warn
} from '../shared/util';
import { NullStream, Stream, StreamsSequenceStream } from './stream';
import { OperatorList, PartialEvaluator } from './evaluator';
import { AnnotationFactory } from './annotation';
@ -355,7 +354,9 @@ var PDFDocument = (function PDFDocumentClosure() {
} else {
throw new Error('PDFDocument: Unknown argument type');
}
assert(stream.length > 0, 'stream must have data');
if (stream.length <= 0) {
throw new Error('PDFDocument: stream must have data');
}
this.pdfManager = pdfManager;
this.stream = stream;

View File

@ -673,7 +673,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var fontRef, xref = this.xref;
if (font) { // Loading by ref.
assert(isRef(font));
if (!isRef(font)) {
throw new Error('The "font" object should be a reference.');
}
fontRef = font;
} else { // Loading by name.
var fontRes = resources.get('Font');
@ -866,7 +868,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
resources = resources || Dict.empty;
initialState = initialState || new EvalState();
assert(operatorList, 'getOperatorList: missing "operatorList" parameter');
if (!operatorList) {
throw new Error('getOperatorList: missing "operatorList" parameter');
}
var self = this;
var xref = this.xref;
@ -928,10 +932,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var xobj = xobjs.get(name);
if (xobj) {
assert(isStream(xobj), 'XObject should be a stream');
if (!isStream(xobj)) {
throw new FormatError('XObject should be a stream');
}
var type = xobj.dict.get('Subtype');
assert(isName(type), 'XObject should have a Name subtype');
if (!isName(type)) {
throw new FormatError('XObject should have a Name subtype');
}
if (type.name === 'Form') {
stateManager.save();
@ -1087,10 +1095,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
case OPS.shadingFill:
var shadingRes = resources.get('Shading');
assert(shadingRes, 'No shading resource found');
if (!shadingRes) {
throw new FormatError('No shading resource found');
}
var shading = shadingRes.get(args[0].name);
assert(shading, 'No shading object found');
if (!shading) {
throw new FormatError('No shading object found');
}
var shadingFill = Pattern.parseShading(shading, null, xref,
resources, self.handler);
@ -1636,10 +1648,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (!xobj) {
break;
}
assert(isStream(xobj), 'XObject should be a stream');
if (!isStream(xobj)) {
throw new FormatError('XObject should be a stream');
}
var type = xobj.dict.get('Subtype');
assert(isName(type), 'XObject should have a Name subtype');
if (!isName(type)) {
throw new FormatError('XObject should have a Name subtype');
}
if (type.name !== 'Form') {
skipEmptyXObjs[name] = true;
@ -1977,7 +1993,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var cMap = properties.cMap;
toUnicode = [];
cMap.forEach(function(charcode, cid) {
assert(cid <= 0xffff, 'Max size of CID is 65,535');
if (cid > 0xffff) {
throw new FormatError('Max size of CID is 65,535');
}
// e) Map the CID obtained in step (a) according to the CMap
// obtained in step (d), producing a Unicode value.
var ucs2 = ucs2CMap.lookup(cid);
@ -2229,7 +2247,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
preEvaluateFont: function PartialEvaluator_preEvaluateFont(dict) {
var baseDict = dict;
var type = dict.get('Subtype');
assert(isName(type), 'invalid font Subtype');
if (!isName(type)) {
throw new FormatError('invalid font Subtype');
}
var composite = false;
var uint8array;
@ -2239,11 +2259,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// - set the type according to the descendant font
// - get the FontDescriptor from the descendant font
var df = dict.get('DescendantFonts');
assert(df, 'Descendant fonts are not specified');
if (!df) {
throw new FormatError('Descendant fonts are not specified');
}
dict = (isArray(df) ? this.xref.fetchIfRef(df[0]) : df);
type = dict.get('Subtype');
assert(isName(type), 'invalid font Subtype');
if (!isName(type)) {
throw new FormatError('invalid font Subtype');
}
composite = true;
}
@ -2331,7 +2355,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// FontDescriptor was not required.
// This case is here for compatibility.
var baseFontName = dict.get('BaseFont');
assert(isName(baseFontName), 'Base font is not specified');
if (!isName(baseFontName)) {
throw new FormatError('Base font is not specified');
}
// Using base font name as a font name.
baseFontName = baseFontName.name.replace(/[,_]/g, '-');
@ -2398,7 +2424,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
fontName = (fontName || baseFont);
assert(isName(fontName), 'invalid font name');
if (!isName(fontName)) {
throw new FormatError('invalid font name');
}
var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
if (fontFile) {
@ -2494,7 +2522,9 @@ var TranslatedFont = (function TranslatedFontClosure() {
this.sent = true;
},
loadType3Data(evaluator, resources, parentOperatorList, task) {
assert(this.font.isType3Font);
if (!this.font.isType3Font) {
throw new Error('Must be a Type3 font.');
}
if (this.type3Loaded) {
return this.type3Loaded;
@ -2997,7 +3027,9 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessorClosure() {
args = [];
}
args.push(obj);
assert(args.length <= 33, 'Too many arguments');
if (args.length > 33) {
throw new FormatError('Too many arguments');
}
}
}
},

View File

@ -14,9 +14,9 @@
*/
import {
assert, bytesToString, FONT_IDENTITY_MATRIX, FontType, FormatError, info,
isArray, isInt, isNum, isSpace, MissingDataException, readUint32, shadow,
string32, warn
bytesToString, FONT_IDENTITY_MATRIX, FontType, FormatError, info, isArray,
isInt, isNum, isSpace, MissingDataException, readUint32, shadow, string32,
warn
} from '../shared/util';
import {
CFF, CFFCharset, CFFCompiler, CFFHeader, CFFIndex, CFFParser, CFFPrivateDict,
@ -2286,7 +2286,9 @@ var Font = (function FontClosure() {
var isCidToGidMapEmpty = cidToGidMap.length === 0;
properties.cMap.forEach(function(charCode, cid) {
assert(cid <= 0xffff, 'Max size of CID is 65,535');
if (cid > 0xffff) {
throw new FormatError('Max size of CID is 65,535');
}
var glyphId = -1;
if (isCidToGidMapEmpty) {
glyphId = cid;

View File

@ -14,8 +14,8 @@
*/
import {
assert, bytesToString, createPromiseCapability, createValidAbsoluteUrl,
FormatError, info, InvalidPDFException, isArray, isBool, isInt, isString,
bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError,
info, InvalidPDFException, isArray, isBool, isInt, isString,
MissingDataException, shadow, stringToPDFString, stringToUTF8String, Util,
warn, XRefParseException
} from '../shared/util';
@ -33,7 +33,9 @@ var Catalog = (function CatalogClosure() {
this.pdfManager = pdfManager;
this.xref = xref;
this.catDict = xref.getCatalogObj();
assert(isDict(this.catDict), 'catalog object is not a dictionary');
if (!isDict(this.catDict)) {
throw new FormatError('catalog object is not a dictionary');
}
this.fontCache = new RefSetCache();
this.builtInCMapCache = Object.create(null);
@ -80,7 +82,9 @@ var Catalog = (function CatalogClosure() {
},
get toplevelPagesDict() {
var pagesObj = this.catDict.get('Pages');
assert(isDict(pagesObj), 'invalid top-level pages dictionary');
if (!isDict(pagesObj)) {
throw new FormatError('invalid top-level pages dictionary');
}
// shadow the prototype getter
return shadow(this, 'toplevelPagesDict', pagesObj);
},
@ -118,7 +122,9 @@ var Catalog = (function CatalogClosure() {
if (outlineDict === null) {
continue;
}
assert(outlineDict.has('Title'), 'Invalid outline item');
if (!outlineDict.has('Title')) {
throw new FormatError('Invalid outline item');
}
var data = { url: null, dest: null, };
Catalog.parseDestDictionary({
@ -163,10 +169,10 @@ var Catalog = (function CatalogClosure() {
},
get numPages() {
var obj = this.toplevelPagesDict.get('Count');
assert(
isInt(obj),
'page count in top level pages object is not an integer'
);
if (!isInt(obj)) {
throw new FormatError(
'page count in top level pages object is not an integer');
}
// shadow the prototype getter
return shadow(this, 'numPages', obj);
},
@ -258,23 +264,31 @@ var Catalog = (function CatalogClosure() {
for (var i = 0, ii = this.numPages; i < ii; i++) {
if (i in nums) {
var labelDict = nums[i];
assert(isDict(labelDict), 'The PageLabel is not a dictionary.');
if (!isDict(labelDict)) {
throw new FormatError('The PageLabel is not a dictionary.');
}
var type = labelDict.get('Type');
assert(!type || isName(type, 'PageLabel'),
'Invalid type in PageLabel dictionary.');
if (type && !isName(type, 'PageLabel')) {
throw new FormatError('Invalid type in PageLabel dictionary.');
}
var s = labelDict.get('S');
assert(!s || isName(s), 'Invalid style in PageLabel dictionary.');
if (s && !isName(s)) {
throw new FormatError('Invalid style in PageLabel dictionary.');
}
style = s ? s.name : null;
var p = labelDict.get('P');
assert(!p || isString(p), 'Invalid prefix in PageLabel dictionary.');
if (p && !isString(p)) {
throw new FormatError('Invalid prefix in PageLabel dictionary.');
}
prefix = p ? stringToPDFString(p) : '';
var st = labelDict.get('St');
assert(!st || (isInt(st) && st >= 1),
'Invalid start in PageLabel dictionary.');
if (st && !(isInt(st) && st >= 1)) {
throw new FormatError('Invalid start in PageLabel dictionary.');
}
currentIndex = st || 1;
}
@ -302,8 +316,10 @@ var Catalog = (function CatalogClosure() {
currentLabel = charBuf.join('');
break;
default:
assert(!style,
'Invalid style "' + style + '" in PageLabel dictionary.');
if (style) {
throw new FormatError(
`Invalid style "${style}" in PageLabel dictionary.`);
}
}
pageLabels[i] = prefix + currentLabel;
@ -454,8 +470,11 @@ var Catalog = (function CatalogClosure() {
}
// Must be a child page dictionary.
assert(isDict(currentNode),
'page dictionary kid reference points to wrong type of object');
if (!isDict(currentNode)) {
capability.reject(new FormatError(
'page dictionary kid reference points to wrong type of object'));
return;
}
count = currentNode.get('Count');
// Cache the Kids count, since it can reduce redundant lookups in long
@ -471,7 +490,11 @@ var Catalog = (function CatalogClosure() {
}
var kids = currentNode.get('Kids');
assert(isArray(kids), 'page dictionary kids object is not an array');
if (!isArray(kids)) {
capability.reject(new FormatError(
'page dictionary kids object is not an array'));
return;
}
// Always check all `Kids` nodes, to avoid getting stuck in an empty
// node further down in the tree (see issue5644.pdf, issue8088.pdf),
@ -480,7 +503,7 @@ var Catalog = (function CatalogClosure() {
nodesToVisit.push(kids[last]);
}
}
capability.reject('Page index ' + pageIndex + ' not found.');
capability.reject(new Error('Page index ' + pageIndex + ' not found.'));
}
next();
return capability.promise;
@ -497,19 +520,24 @@ var Catalog = (function CatalogClosure() {
return xref.fetchAsync(kidRef).then(function (node) {
if (isRefsEqual(kidRef, pageRef) && !isDict(node, 'Page') &&
!(isDict(node) && !node.has('Type') && node.has('Contents'))) {
throw new Error('The reference does not point to a /Page Dict.');
throw new FormatError(
'The reference does not point to a /Page Dict.');
}
if (!node) {
return null;
}
assert(isDict(node), 'node must be a Dict.');
if (!isDict(node)) {
throw new FormatError('node must be a Dict.');
}
parentRef = node.getRaw('Parent');
return node.getAsync('Parent');
}).then(function (parent) {
if (!parent) {
return null;
}
assert(isDict(parent), 'parent must be a Dict.');
if (!isDict(parent)) {
throw new FormatError('parent must be a Dict.');
}
return parent.getAsync('Kids');
}).then(function (kids) {
if (!kids) {
@ -519,7 +547,9 @@ var Catalog = (function CatalogClosure() {
var found = false;
for (var i = 0; i < kids.length; i++) {
var kid = kids[i];
assert(isRef(kid), 'kid must be a Ref.');
if (!isRef(kid)) {
throw new FormatError('kid must be a Ref.');
}
if (kid.num === kidRef.num) {
found = true;
break;
@ -1229,7 +1259,9 @@ var XRef = (function XRefClosure() {
},
fetch: function XRef_fetch(ref, suppressEncryption) {
assert(isRef(ref), 'ref object is not a reference');
if (!isRef(ref)) {
throw new Error('ref object is not a reference');
}
var num = ref.num;
if (num in this.cache) {
var cacheEntry = this.cache[num];
@ -1415,8 +1447,9 @@ var NameOrNumberTree = (function NameOrNumberTreeClosure() {
var kids = obj.get('Kids');
for (i = 0, n = kids.length; i < n; i++) {
var kid = kids[i];
assert(!processed.has(kid),
'Duplicate entry in "' + this._type + '" tree.');
if (processed.has(kid)) {
throw new FormatError(`Duplicate entry in "${this._type}" tree.`);
}
queue.push(kid);
processed.put(kid);
}

View File

@ -328,7 +328,9 @@ Shadings.Mesh = (function MeshClosure() {
var coord = reader.readCoordinate();
var color = reader.readComponents();
if (verticesLeft === 0) { // ignoring flags if we started a triangle
assert((0 <= f && f <= 2), 'Unknown type4 flag');
if (!(0 <= f && f <= 2)) {
throw new FormatError('Unknown type4 flag');
}
switch (f) {
case 0:
verticesLeft = 3;
@ -492,7 +494,9 @@ Shadings.Mesh = (function MeshClosure() {
var cs = new Int32Array(4); // c00, c30, c03, c33
while (reader.hasData) {
var f = reader.readFlag();
assert((0 <= f && f <= 3), 'Unknown type6 flag');
if (!(0 <= f && f <= 3)) {
throw new FormatError('Unknown type6 flag');
}
var i, ii;
var pi = coords.length;
for (i = 0, ii = (f !== 0 ? 8 : 12); i < ii; i++) {
@ -602,7 +606,9 @@ Shadings.Mesh = (function MeshClosure() {
var cs = new Int32Array(4); // c00, c30, c03, c33
while (reader.hasData) {
var f = reader.readFlag();
assert((0 <= f && f <= 3), 'Unknown type7 flag');
if (!(0 <= f && f <= 3)) {
throw new FormatError('Unknown type7 flag');
}
var i, ii;
var pi = coords.length;
for (i = 0, ii = (f !== 0 ? 12 : 16); i < ii; i++) {
@ -706,7 +712,9 @@ Shadings.Mesh = (function MeshClosure() {
}
function Mesh(stream, matrix, xref, res) {
assert(isStream(stream), 'Mesh data is not a stream');
if (!isStream(stream)) {
throw new FormatError('Mesh data is not a stream');
}
var dict = stream.dict;
this.matrix = matrix;
this.shadingType = dict.get('ShadingType');
@ -743,7 +751,9 @@ Shadings.Mesh = (function MeshClosure() {
break;
case ShadingType.LATTICE_FORM_MESH:
var verticesPerRow = dict.get('VerticesPerRow') | 0;
assert(verticesPerRow >= 2, 'Invalid VerticesPerRow');
if (verticesPerRow < 2) {
throw new FormatError('Invalid VerticesPerRow');
}
decodeType5Shading(this, reader, verticesPerRow);
break;
case ShadingType.COONS_PATCH_MESH:

View File

@ -541,7 +541,9 @@ var WorkerMessageHandler = {
if (source.chunkedViewerLoading) {
pdfStream = new PDFWorkerStream(source, handler);
} else {
assert(PDFNetworkStream, './network module is not loaded');
if (!PDFNetworkStream) {
throw new Error('./network module is not loaded');
}
pdfStream = new PDFNetworkStream(data);
}
} catch (ex) {

View File

@ -14,7 +14,7 @@
*/
import {
assert, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, info, isArray,
FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, info, isArray,
isLittleEndian, isNum, OPS, shadow, TextRenderingMode, Util, warn
} from '../shared/util';
import { getShadingPatternFromIR, TilingPattern } from './pattern_helper';
@ -1777,7 +1777,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
if (group.matrix) {
currentCtx.transform.apply(currentCtx, group.matrix);
}
assert(group.bbox, 'Bounding box is required.');
if (!group.bbox) {
throw new Error('Bounding box is required.');
}
// Based on the current transform figure out how big the bounding box
// will actually be.

View File

@ -14,7 +14,7 @@
*/
import {
assert, CMapCompressionType, createValidAbsoluteUrl, deprecated, globalScope,
CMapCompressionType, createValidAbsoluteUrl, deprecated, globalScope,
removeNullCharacters, stringToBytes, warn
} from '../shared/util';
@ -22,7 +22,9 @@ var DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
class DOMCanvasFactory {
create(width, height) {
assert(width > 0 && height > 0, 'invalid canvas size');
if (width <= 0 || height <= 0) {
throw new Error('invalid canvas size');
}
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
canvas.width = width;
@ -34,14 +36,20 @@ class DOMCanvasFactory {
}
reset(canvasAndContext, width, height) {
assert(canvasAndContext.canvas, 'canvas is not specified');
assert(width > 0 && height > 0, 'invalid canvas size');
if (!canvasAndContext.canvas) {
throw new Error('canvas is not specified');
}
if (width <= 0 || height <= 0) {
throw new Error('invalid canvas size');
}
canvasAndContext.canvas.width = width;
canvasAndContext.canvas.height = height;
}
destroy(canvasAndContext) {
assert(canvasAndContext.canvas, 'canvas is not specified');
if (!canvasAndContext.canvas) {
throw new Error('canvas is not specified');
}
// Zeroing the width and height cause Firefox to release graphics
// resources immediately, which can greatly reduce memory consumption.
canvasAndContext.canvas.width = 0;