Skip to content

Commit

Permalink
add string tags for browser polyglot classes (#2214)
Browse files Browse the repository at this point in the history
* add string tags

* set toStringTag property to configurable: true
  • Loading branch information
brettz9 committed Apr 17, 2023
1 parent f3184ba commit 5902219
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -14,6 +14,7 @@ project adheres to [Semantic Versioning](http://semver.org/).
* Avoid calling virtual methods in constructors/destructors to avoid bypassing virtual dispatch. (#2229)
* Remove unused private field `backend` in the `Backend` class. (#2229)
### Added
* Added string tags to support class detection
### Fixed
* Fix a case of use-after-free. (#2229)
* Fix usage of garbage value by filling the allocated memory entirely with zeros if it's not modified. (#2229)
Expand Down
30 changes: 30 additions & 0 deletions lib/bindings.js
Expand Up @@ -4,10 +4,40 @@ const bindings = require('../build/Release/canvas.node')

module.exports = bindings

Object.defineProperty(bindings.Canvas.prototype, Symbol.toStringTag, {
value: 'HTMLCanvasElement',
configurable: true
})

Object.defineProperty(bindings.Image.prototype, Symbol.toStringTag, {
value: 'HTMLImageElement',
configurable: true
})

bindings.ImageData.prototype.toString = function () {
return '[object ImageData]'
}

Object.defineProperty(bindings.ImageData.prototype, Symbol.toStringTag, {
value: 'ImageData',
configurable: true
})

bindings.CanvasGradient.prototype.toString = function () {
return '[object CanvasGradient]'
}

Object.defineProperty(bindings.CanvasGradient.prototype, Symbol.toStringTag, {
value: 'CanvasGradient',
configurable: true
})

Object.defineProperty(bindings.CanvasPattern.prototype, Symbol.toStringTag, {
value: 'CanvasPattern',
configurable: true
})

Object.defineProperty(bindings.CanvasRenderingContext2d.prototype, Symbol.toStringTag, {
value: 'CanvasRenderingContext2d',
configurable: true
})
22 changes: 21 additions & 1 deletion test/canvas.test.js
Expand Up @@ -1410,6 +1410,14 @@ describe('Canvas', function () {
assert.strictEqual(pattern.toString(), '[object CanvasPattern]')
})

it('CanvasPattern has class string of `CanvasPattern`', async function () {
const img = await loadImage(path.join(__dirname, '/fixtures/checkers.png'));
const canvas = createCanvas(20, 20)
const ctx = canvas.getContext('2d')
const pattern = ctx.createPattern(img)
assert.strictEqual(Object.prototype.toString.call(pattern), '[object CanvasPattern]')
})

it('Context2d#createLinearGradient()', function () {
const canvas = createCanvas(20, 1)
const ctx = canvas.getContext('2d')
Expand Down Expand Up @@ -1439,6 +1447,11 @@ describe('Canvas', function () {
assert.equal(0, imageData.data[i + 2])
assert.equal(255, imageData.data[i + 3])
})
it('Canvas has class string of `HTMLCanvasElement`', function () {
const canvas = createCanvas(20, 1)

assert.strictEqual(Object.prototype.toString.call(canvas), '[object HTMLCanvasElement]')
})

it('CanvasGradient stringifies as [object CanvasGradient]', function () {
const canvas = createCanvas(20, 1)
Expand All @@ -1447,6 +1460,13 @@ describe('Canvas', function () {
assert.strictEqual(gradient.toString(), '[object CanvasGradient]')
})

it('CanvasGradient has class string of `CanvasGradient`', function () {
const canvas = createCanvas(20, 1)
const ctx = canvas.getContext('2d')
const gradient = ctx.createLinearGradient(1, 1, 19, 1)
assert.strictEqual(Object.prototype.toString.call(gradient), '[object CanvasGradient]')
})

describe('Context2d#putImageData()', function () {
it('throws for invalid arguments', function () {
const canvas = createCanvas(2, 1)
Expand Down Expand Up @@ -1943,7 +1963,7 @@ describe('Canvas', function () {
ctx[k] = v
ctx.restore()
assert.strictEqual(ctx[k], old)

// save() doesn't modify the value:
ctx[k] = v
old = ctx[k]
Expand Down
5 changes: 5 additions & 0 deletions test/image.test.js
Expand Up @@ -30,6 +30,11 @@ describe('Image', function () {
assert(Image.prototype.hasOwnProperty('width'))
})

it('Image has class string of `HTMLImageElement`', async function () {
const img = new Image()
assert.strictEqual(Object.prototype.toString.call(img), '[object HTMLImageElement]')
})

it('loads JPEG image', function () {
return loadImage(jpgFace).then((img) => {
assert.strictEqual(img.onerror, null)
Expand Down
5 changes: 5 additions & 0 deletions test/imageData.test.js
Expand Up @@ -17,6 +17,11 @@ describe('ImageData', function () {
assert.strictEqual(imageData.toString(), '[object ImageData]')
})

it('gives class string as `ImageData`', function () {
const imageData = createImageData(2, 3)
assert.strictEqual(Object.prototype.toString.call(imageData), '[object ImageData]')
})

it('should throw with invalid numeric arguments', function () {
assert.throws(() => { createImageData(0, 0) }, /width is zero/)
assert.throws(() => { createImageData(1, 0) }, /height is zero/)
Expand Down
6 changes: 6 additions & 0 deletions test/wpt/generated/the-canvas-element.js
Expand Up @@ -171,6 +171,12 @@ describe("WPT: the-canvas-element", function () {
assert.strictEqual(window.CanvasRenderingContext2D.prototype.fill, undefined, "window.CanvasRenderingContext2D.prototype.fill", "undefined")
});

it("2d.type class string", function () {
const canvas = createCanvas(100, 50);
const ctx = canvas.getContext("2d");
assert.strictEqual(Object.prototype.toString.call(ctx), '[object CanvasRenderingContext2D]')
})

it("2d.type.replace", function () {
// Interface methods can be overridden
const canvas = createCanvas(100, 50);
Expand Down

0 comments on commit 5902219

Please sign in to comment.