UNPKG

jsdom

Version:

A JavaScript implementation of many web standards

118 lines (107 loc) 3.47 kB
"use strict"; const HTMLElementImpl = require("./HTMLElement-impl").implementation; const { notImplementedMethod } = require("../../browser/not-implemented"); const idlUtils = require("../../../generated/idl/utils"); const { Canvas } = require("../../utils"); class HTMLCanvasElementImpl extends HTMLElementImpl { _attrModified(name, value, oldValue) { if (this._canvas && (name === "width" || name === "height")) { this._canvas[name] = parseInt(value, 10); } super._attrModified(name, value, oldValue); } _getCanvas() { if (Canvas && !this._canvas) { const wrapper = idlUtils.wrapperForImpl(this); this._canvas = Canvas.createCanvas(wrapper.width, wrapper.height); } return this._canvas; } getContext(contextId) { const canvas = this._getCanvas(); if (canvas) { if (!this._context) { this._context = canvas.getContext(contextId) || null; if (this._context) { // Override the native canvas reference with our wrapper. This is the // reason why we need to locally cache _context, since each call to // canvas.getContext(contextId) would replace this reference again. // Perhaps in the longer term, a better solution would be to create a // full wrapper for the Context object as well. this._context.canvas = idlUtils.wrapperForImpl(this); wrapNodeCanvasMethod(this._context, "createPattern"); wrapNodeCanvasMethod(this._context, "drawImage"); } } return this._context; } notImplementedMethod( this._ownerDocument._defaultView, "HTMLCanvasElement", "getContext", "without installing the canvas npm package" ); return null; } toDataURL(...args) { const canvas = this._getCanvas(); if (canvas) { return canvas.toDataURL(...args); } notImplementedMethod( this._ownerDocument._defaultView, "HTMLCanvasElement", "toDataURL", "without installing the canvas npm package" ); return null; } toBlob(callback, type, qualityArgument) { const window = this._ownerDocument._defaultView; const canvas = this._getCanvas(); if (canvas) { const options = {}; switch (type) { case "image/jpg": case "image/jpeg": type = "image/jpeg"; options.quality = qualityArgument; break; default: type = "image/png"; } canvas.toBuffer((err, buff) => { if (err) { throw err; } callback(new window.Blob([buff], { type })); }, type, options); } else { notImplementedMethod( this._ownerDocument._defaultView, "HTMLCanvasElement", "toBlob", "without installing the canvas npm package" ); } } } // We need to wrap the methods that receive an image or canvas object // (luckily, always as the first argument), so that these objects can be // unwrapped an the expected types passed. function wrapNodeCanvasMethod(ctx, name) { const prev = ctx[name]; ctx[name] = function (image, ...rest) { const impl = idlUtils.implForWrapper(image); if (impl) { if (impl instanceof HTMLCanvasElementImpl && !impl._canvas) { impl._getCanvas(); } image = impl._image || impl._canvas; } return prev.call(ctx, image, ...rest); }; } module.exports = { implementation: HTMLCanvasElementImpl };