@shqld/canvas 2.11.2-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/Readme.md +600 -0
  2. package/binding.gyp +230 -0
  3. package/browser.js +35 -0
  4. package/index.js +94 -0
  5. package/lib/DOMMatrix.js +620 -0
  6. package/lib/bindings.js +80 -0
  7. package/lib/canvas.js +113 -0
  8. package/lib/context2d.js +14 -0
  9. package/lib/image.js +96 -0
  10. package/lib/jpegstream.js +41 -0
  11. package/lib/parse-font.js +101 -0
  12. package/lib/pattern.js +17 -0
  13. package/lib/pdfstream.js +35 -0
  14. package/lib/pngstream.js +42 -0
  15. package/package.json +71 -0
  16. package/scripts/install.js +24 -0
  17. package/src/Backends.cc +18 -0
  18. package/src/Backends.h +10 -0
  19. package/src/Canvas.cc +965 -0
  20. package/src/Canvas.h +96 -0
  21. package/src/CanvasError.h +23 -0
  22. package/src/CanvasGradient.cc +123 -0
  23. package/src/CanvasGradient.h +22 -0
  24. package/src/CanvasPattern.cc +136 -0
  25. package/src/CanvasPattern.h +37 -0
  26. package/src/CanvasRenderingContext2d.cc +3360 -0
  27. package/src/CanvasRenderingContext2d.h +225 -0
  28. package/src/Image.cc +1434 -0
  29. package/src/Image.h +127 -0
  30. package/src/ImageData.cc +146 -0
  31. package/src/ImageData.h +27 -0
  32. package/src/JPEGStream.h +167 -0
  33. package/src/PNG.h +292 -0
  34. package/src/Point.h +11 -0
  35. package/src/Util.h +9 -0
  36. package/src/backend/Backend.cc +112 -0
  37. package/src/backend/Backend.h +69 -0
  38. package/src/backend/ImageBackend.cc +74 -0
  39. package/src/backend/ImageBackend.h +26 -0
  40. package/src/backend/PdfBackend.cc +53 -0
  41. package/src/backend/PdfBackend.h +24 -0
  42. package/src/backend/SvgBackend.cc +61 -0
  43. package/src/backend/SvgBackend.h +24 -0
  44. package/src/bmp/BMPParser.cc +457 -0
  45. package/src/bmp/BMPParser.h +60 -0
  46. package/src/bmp/LICENSE.md +24 -0
  47. package/src/closure.cc +26 -0
  48. package/src/closure.h +81 -0
  49. package/src/color.cc +779 -0
  50. package/src/color.h +30 -0
  51. package/src/dll_visibility.h +20 -0
  52. package/src/init.cc +94 -0
  53. package/src/register_font.cc +408 -0
  54. package/src/register_font.h +7 -0
  55. package/types/index.d.ts +484 -0
  56. package/util/has_lib.js +119 -0
  57. package/util/win_jpeg_lookup.js +21 -0
@@ -0,0 +1,620 @@
1
+ 'use strict'
2
+
3
+ const util = require('util')
4
+
5
+ // DOMMatrix per https://drafts.fxtf.org/geometry/#DOMMatrix
6
+
7
+ class DOMPoint {
8
+ constructor (x, y, z, w) {
9
+ if (typeof x === 'object' && x !== null) {
10
+ w = x.w
11
+ z = x.z
12
+ y = x.y
13
+ x = x.x
14
+ }
15
+ this.x = typeof x === 'number' ? x : 0
16
+ this.y = typeof y === 'number' ? y : 0
17
+ this.z = typeof z === 'number' ? z : 0
18
+ this.w = typeof w === 'number' ? w : 1
19
+ }
20
+ }
21
+
22
+ // Constants to index into _values (col-major)
23
+ const M11 = 0; const M12 = 1; const M13 = 2; const M14 = 3
24
+ const M21 = 4; const M22 = 5; const M23 = 6; const M24 = 7
25
+ const M31 = 8; const M32 = 9; const M33 = 10; const M34 = 11
26
+ const M41 = 12; const M42 = 13; const M43 = 14; const M44 = 15
27
+
28
+ const DEGREE_PER_RAD = 180 / Math.PI
29
+ const RAD_PER_DEGREE = Math.PI / 180
30
+
31
+ function parseMatrix (init) {
32
+ let parsed = init.replace('matrix(', '')
33
+ parsed = parsed.split(',', 7) // 6 + 1 to handle too many params
34
+ if (parsed.length !== 6) throw new Error(`Failed to parse ${init}`)
35
+ parsed = parsed.map(parseFloat)
36
+ return [
37
+ parsed[0], parsed[1], 0, 0,
38
+ parsed[2], parsed[3], 0, 0,
39
+ 0, 0, 1, 0,
40
+ parsed[4], parsed[5], 0, 1
41
+ ]
42
+ }
43
+
44
+ function parseMatrix3d (init) {
45
+ let parsed = init.replace('matrix3d(', '')
46
+ parsed = parsed.split(',', 17) // 16 + 1 to handle too many params
47
+ if (parsed.length !== 16) throw new Error(`Failed to parse ${init}`)
48
+ return parsed.map(parseFloat)
49
+ }
50
+
51
+ function parseTransform (tform) {
52
+ const type = tform.split('(', 1)[0]
53
+ switch (type) {
54
+ case 'matrix':
55
+ return parseMatrix(tform)
56
+ case 'matrix3d':
57
+ return parseMatrix3d(tform)
58
+ // TODO This is supposed to support any CSS transform value.
59
+ default:
60
+ throw new Error(`${type} parsing not implemented`)
61
+ }
62
+ }
63
+
64
+ class DOMMatrix {
65
+ constructor (init) {
66
+ this._is2D = true
67
+ this._values = new Float64Array([
68
+ 1, 0, 0, 0,
69
+ 0, 1, 0, 0,
70
+ 0, 0, 1, 0,
71
+ 0, 0, 0, 1
72
+ ])
73
+
74
+ let i
75
+
76
+ if (typeof init === 'string') { // parse CSS transformList
77
+ if (init === '') return // default identity matrix
78
+ const tforms = init.split(/\)\s+/, 20).map(parseTransform)
79
+ if (tforms.length === 0) return
80
+ init = tforms[0]
81
+ for (i = 1; i < tforms.length; i++) init = multiply(tforms[i], init)
82
+ }
83
+
84
+ i = 0
85
+ if (init && init.length === 6) {
86
+ setNumber2D(this, M11, init[i++])
87
+ setNumber2D(this, M12, init[i++])
88
+ setNumber2D(this, M21, init[i++])
89
+ setNumber2D(this, M22, init[i++])
90
+ setNumber2D(this, M41, init[i++])
91
+ setNumber2D(this, M42, init[i++])
92
+ } else if (init && init.length === 16) {
93
+ setNumber2D(this, M11, init[i++])
94
+ setNumber2D(this, M12, init[i++])
95
+ setNumber3D(this, M13, init[i++])
96
+ setNumber3D(this, M14, init[i++])
97
+ setNumber2D(this, M21, init[i++])
98
+ setNumber2D(this, M22, init[i++])
99
+ setNumber3D(this, M23, init[i++])
100
+ setNumber3D(this, M24, init[i++])
101
+ setNumber3D(this, M31, init[i++])
102
+ setNumber3D(this, M32, init[i++])
103
+ setNumber3D(this, M33, init[i++])
104
+ setNumber3D(this, M34, init[i++])
105
+ setNumber2D(this, M41, init[i++])
106
+ setNumber2D(this, M42, init[i++])
107
+ setNumber3D(this, M43, init[i++])
108
+ setNumber3D(this, M44, init[i])
109
+ } else if (init !== undefined) {
110
+ throw new TypeError('Expected string or array.')
111
+ }
112
+ }
113
+
114
+ toString () {
115
+ return this.is2D
116
+ ? `matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})`
117
+ : `matrix3d(${this._values.join(', ')})`
118
+ }
119
+
120
+ multiply (other) {
121
+ return newInstance(this._values).multiplySelf(other)
122
+ }
123
+
124
+ multiplySelf (other) {
125
+ this._values = multiply(other._values, this._values)
126
+ if (!other.is2D) this._is2D = false
127
+ return this
128
+ }
129
+
130
+ preMultiplySelf (other) {
131
+ this._values = multiply(this._values, other._values)
132
+ if (!other.is2D) this._is2D = false
133
+ return this
134
+ }
135
+
136
+ translate (tx, ty, tz) {
137
+ return newInstance(this._values).translateSelf(tx, ty, tz)
138
+ }
139
+
140
+ translateSelf (tx, ty, tz) {
141
+ if (typeof tx !== 'number') tx = 0
142
+ if (typeof ty !== 'number') ty = 0
143
+ if (typeof tz !== 'number') tz = 0
144
+ this._values = multiply([
145
+ 1, 0, 0, 0,
146
+ 0, 1, 0, 0,
147
+ 0, 0, 1, 0,
148
+ tx, ty, tz, 1
149
+ ], this._values)
150
+ if (tz !== 0) this._is2D = false
151
+ return this
152
+ }
153
+
154
+ scale (scaleX, scaleY, scaleZ, originX, originY, originZ) {
155
+ return newInstance(this._values).scaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)
156
+ }
157
+
158
+ scale3d (scale, originX, originY, originZ) {
159
+ return newInstance(this._values).scale3dSelf(scale, originX, originY, originZ)
160
+ }
161
+
162
+ scale3dSelf (scale, originX, originY, originZ) {
163
+ return this.scaleSelf(scale, scale, scale, originX, originY, originZ)
164
+ }
165
+
166
+ scaleSelf (scaleX, scaleY, scaleZ, originX, originY, originZ) {
167
+ // Not redundant with translate's checks because we need to negate the values later.
168
+ if (typeof originX !== 'number') originX = 0
169
+ if (typeof originY !== 'number') originY = 0
170
+ if (typeof originZ !== 'number') originZ = 0
171
+ this.translateSelf(originX, originY, originZ)
172
+ if (typeof scaleX !== 'number') scaleX = 1
173
+ if (typeof scaleY !== 'number') scaleY = scaleX
174
+ if (typeof scaleZ !== 'number') scaleZ = 1
175
+ this._values = multiply([
176
+ scaleX, 0, 0, 0,
177
+ 0, scaleY, 0, 0,
178
+ 0, 0, scaleZ, 0,
179
+ 0, 0, 0, 1
180
+ ], this._values)
181
+ this.translateSelf(-originX, -originY, -originZ)
182
+ if (scaleZ !== 1 || originZ !== 0) this._is2D = false
183
+ return this
184
+ }
185
+
186
+ rotateFromVector (x, y) {
187
+ return newInstance(this._values).rotateFromVectorSelf(x, y)
188
+ }
189
+
190
+ rotateFromVectorSelf (x, y) {
191
+ if (typeof x !== 'number') x = 0
192
+ if (typeof y !== 'number') y = 0
193
+ const theta = (x === 0 && y === 0) ? 0 : Math.atan2(y, x) * DEGREE_PER_RAD
194
+ return this.rotateSelf(theta)
195
+ }
196
+
197
+ rotate (rotX, rotY, rotZ) {
198
+ return newInstance(this._values).rotateSelf(rotX, rotY, rotZ)
199
+ }
200
+
201
+ rotateSelf (rotX, rotY, rotZ) {
202
+ if (rotY === undefined && rotZ === undefined) {
203
+ rotZ = rotX
204
+ rotX = rotY = 0
205
+ }
206
+ if (typeof rotY !== 'number') rotY = 0
207
+ if (typeof rotZ !== 'number') rotZ = 0
208
+ if (rotX !== 0 || rotY !== 0) this._is2D = false
209
+ rotX *= RAD_PER_DEGREE
210
+ rotY *= RAD_PER_DEGREE
211
+ rotZ *= RAD_PER_DEGREE
212
+ let c, s
213
+ c = Math.cos(rotZ)
214
+ s = Math.sin(rotZ)
215
+ this._values = multiply([
216
+ c, s, 0, 0,
217
+ -s, c, 0, 0,
218
+ 0, 0, 1, 0,
219
+ 0, 0, 0, 1
220
+ ], this._values)
221
+ c = Math.cos(rotY)
222
+ s = Math.sin(rotY)
223
+ this._values = multiply([
224
+ c, 0, -s, 0,
225
+ 0, 1, 0, 0,
226
+ s, 0, c, 0,
227
+ 0, 0, 0, 1
228
+ ], this._values)
229
+ c = Math.cos(rotX)
230
+ s = Math.sin(rotX)
231
+ this._values = multiply([
232
+ 1, 0, 0, 0,
233
+ 0, c, s, 0,
234
+ 0, -s, c, 0,
235
+ 0, 0, 0, 1
236
+ ], this._values)
237
+ return this
238
+ }
239
+
240
+ rotateAxisAngle (x, y, z, angle) {
241
+ return newInstance(this._values).rotateAxisAngleSelf(x, y, z, angle)
242
+ }
243
+
244
+ rotateAxisAngleSelf (x, y, z, angle) {
245
+ if (typeof x !== 'number') x = 0
246
+ if (typeof y !== 'number') y = 0
247
+ if (typeof z !== 'number') z = 0
248
+ // Normalize axis
249
+ const length = Math.sqrt(x * x + y * y + z * z)
250
+ if (length === 0) return this
251
+ if (length !== 1) {
252
+ x /= length
253
+ y /= length
254
+ z /= length
255
+ }
256
+ angle *= RAD_PER_DEGREE
257
+ const c = Math.cos(angle)
258
+ const s = Math.sin(angle)
259
+ const t = 1 - c
260
+ const tx = t * x
261
+ const ty = t * y
262
+ // NB: This is the generic transform. If the axis is a major axis, there are
263
+ // faster transforms.
264
+ this._values = multiply([
265
+ tx * x + c, tx * y + s * z, tx * z - s * y, 0,
266
+ tx * y - s * z, ty * y + c, ty * z + s * x, 0,
267
+ tx * z + s * y, ty * z - s * x, t * z * z + c, 0,
268
+ 0, 0, 0, 1
269
+ ], this._values)
270
+ if (x !== 0 || y !== 0) this._is2D = false
271
+ return this
272
+ }
273
+
274
+ skewX (sx) {
275
+ return newInstance(this._values).skewXSelf(sx)
276
+ }
277
+
278
+ skewXSelf (sx) {
279
+ if (typeof sx !== 'number') return this
280
+ const t = Math.tan(sx * RAD_PER_DEGREE)
281
+ this._values = multiply([
282
+ 1, 0, 0, 0,
283
+ t, 1, 0, 0,
284
+ 0, 0, 1, 0,
285
+ 0, 0, 0, 1
286
+ ], this._values)
287
+ return this
288
+ }
289
+
290
+ skewY (sy) {
291
+ return newInstance(this._values).skewYSelf(sy)
292
+ }
293
+
294
+ skewYSelf (sy) {
295
+ if (typeof sy !== 'number') return this
296
+ const t = Math.tan(sy * RAD_PER_DEGREE)
297
+ this._values = multiply([
298
+ 1, t, 0, 0,
299
+ 0, 1, 0, 0,
300
+ 0, 0, 1, 0,
301
+ 0, 0, 0, 1
302
+ ], this._values)
303
+ return this
304
+ }
305
+
306
+ flipX () {
307
+ return newInstance(multiply([
308
+ -1, 0, 0, 0,
309
+ 0, 1, 0, 0,
310
+ 0, 0, 1, 0,
311
+ 0, 0, 0, 1
312
+ ], this._values))
313
+ }
314
+
315
+ flipY () {
316
+ return newInstance(multiply([
317
+ 1, 0, 0, 0,
318
+ 0, -1, 0, 0,
319
+ 0, 0, 1, 0,
320
+ 0, 0, 0, 1
321
+ ], this._values))
322
+ }
323
+
324
+ inverse () {
325
+ return newInstance(this._values).invertSelf()
326
+ }
327
+
328
+ invertSelf () {
329
+ const m = this._values
330
+ const inv = m.map(v => 0)
331
+
332
+ inv[0] = m[5] * m[10] * m[15] -
333
+ m[5] * m[11] * m[14] -
334
+ m[9] * m[6] * m[15] +
335
+ m[9] * m[7] * m[14] +
336
+ m[13] * m[6] * m[11] -
337
+ m[13] * m[7] * m[10]
338
+
339
+ inv[4] = -m[4] * m[10] * m[15] +
340
+ m[4] * m[11] * m[14] +
341
+ m[8] * m[6] * m[15] -
342
+ m[8] * m[7] * m[14] -
343
+ m[12] * m[6] * m[11] +
344
+ m[12] * m[7] * m[10]
345
+
346
+ inv[8] = m[4] * m[9] * m[15] -
347
+ m[4] * m[11] * m[13] -
348
+ m[8] * m[5] * m[15] +
349
+ m[8] * m[7] * m[13] +
350
+ m[12] * m[5] * m[11] -
351
+ m[12] * m[7] * m[9]
352
+
353
+ inv[12] = -m[4] * m[9] * m[14] +
354
+ m[4] * m[10] * m[13] +
355
+ m[8] * m[5] * m[14] -
356
+ m[8] * m[6] * m[13] -
357
+ m[12] * m[5] * m[10] +
358
+ m[12] * m[6] * m[9]
359
+
360
+ // If the determinant is zero, this matrix cannot be inverted, and all
361
+ // values should be set to NaN, with the is2D flag set to false.
362
+
363
+ const det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]
364
+
365
+ if (det === 0) {
366
+ this._values = m.map(v => NaN)
367
+ this._is2D = false
368
+ return this
369
+ }
370
+
371
+ inv[1] = -m[1] * m[10] * m[15] +
372
+ m[1] * m[11] * m[14] +
373
+ m[9] * m[2] * m[15] -
374
+ m[9] * m[3] * m[14] -
375
+ m[13] * m[2] * m[11] +
376
+ m[13] * m[3] * m[10]
377
+
378
+ inv[5] = m[0] * m[10] * m[15] -
379
+ m[0] * m[11] * m[14] -
380
+ m[8] * m[2] * m[15] +
381
+ m[8] * m[3] * m[14] +
382
+ m[12] * m[2] * m[11] -
383
+ m[12] * m[3] * m[10]
384
+
385
+ inv[9] = -m[0] * m[9] * m[15] +
386
+ m[0] * m[11] * m[13] +
387
+ m[8] * m[1] * m[15] -
388
+ m[8] * m[3] * m[13] -
389
+ m[12] * m[1] * m[11] +
390
+ m[12] * m[3] * m[9]
391
+
392
+ inv[13] = m[0] * m[9] * m[14] -
393
+ m[0] * m[10] * m[13] -
394
+ m[8] * m[1] * m[14] +
395
+ m[8] * m[2] * m[13] +
396
+ m[12] * m[1] * m[10] -
397
+ m[12] * m[2] * m[9]
398
+
399
+ inv[2] = m[1] * m[6] * m[15] -
400
+ m[1] * m[7] * m[14] -
401
+ m[5] * m[2] * m[15] +
402
+ m[5] * m[3] * m[14] +
403
+ m[13] * m[2] * m[7] -
404
+ m[13] * m[3] * m[6]
405
+
406
+ inv[6] = -m[0] * m[6] * m[15] +
407
+ m[0] * m[7] * m[14] +
408
+ m[4] * m[2] * m[15] -
409
+ m[4] * m[3] * m[14] -
410
+ m[12] * m[2] * m[7] +
411
+ m[12] * m[3] * m[6]
412
+
413
+ inv[10] = m[0] * m[5] * m[15] -
414
+ m[0] * m[7] * m[13] -
415
+ m[4] * m[1] * m[15] +
416
+ m[4] * m[3] * m[13] +
417
+ m[12] * m[1] * m[7] -
418
+ m[12] * m[3] * m[5]
419
+
420
+ inv[14] = -m[0] * m[5] * m[14] +
421
+ m[0] * m[6] * m[13] +
422
+ m[4] * m[1] * m[14] -
423
+ m[4] * m[2] * m[13] -
424
+ m[12] * m[1] * m[6] +
425
+ m[12] * m[2] * m[5]
426
+
427
+ inv[3] = -m[1] * m[6] * m[11] +
428
+ m[1] * m[7] * m[10] +
429
+ m[5] * m[2] * m[11] -
430
+ m[5] * m[3] * m[10] -
431
+ m[9] * m[2] * m[7] +
432
+ m[9] * m[3] * m[6]
433
+
434
+ inv[7] = m[0] * m[6] * m[11] -
435
+ m[0] * m[7] * m[10] -
436
+ m[4] * m[2] * m[11] +
437
+ m[4] * m[3] * m[10] +
438
+ m[8] * m[2] * m[7] -
439
+ m[8] * m[3] * m[6]
440
+
441
+ inv[11] = -m[0] * m[5] * m[11] +
442
+ m[0] * m[7] * m[9] +
443
+ m[4] * m[1] * m[11] -
444
+ m[4] * m[3] * m[9] -
445
+ m[8] * m[1] * m[7] +
446
+ m[8] * m[3] * m[5]
447
+
448
+ inv[15] = m[0] * m[5] * m[10] -
449
+ m[0] * m[6] * m[9] -
450
+ m[4] * m[1] * m[10] +
451
+ m[4] * m[2] * m[9] +
452
+ m[8] * m[1] * m[6] -
453
+ m[8] * m[2] * m[5]
454
+
455
+ inv.forEach((v, i) => { inv[i] = v / det })
456
+ this._values = inv
457
+ return this
458
+ }
459
+
460
+ setMatrixValue (transformList) {
461
+ const temp = new DOMMatrix(transformList)
462
+ this._values = temp._values
463
+ this._is2D = temp._is2D
464
+ return this
465
+ }
466
+
467
+ transformPoint (point) {
468
+ point = new DOMPoint(point)
469
+ const x = point.x
470
+ const y = point.y
471
+ const z = point.z
472
+ const w = point.w
473
+ const values = this._values
474
+ const nx = values[M11] * x + values[M21] * y + values[M31] * z + values[M41] * w
475
+ const ny = values[M12] * x + values[M22] * y + values[M32] * z + values[M42] * w
476
+ const nz = values[M13] * x + values[M23] * y + values[M33] * z + values[M43] * w
477
+ const nw = values[M14] * x + values[M24] * y + values[M34] * z + values[M44] * w
478
+ return new DOMPoint(nx, ny, nz, nw)
479
+ }
480
+
481
+ toFloat32Array () {
482
+ return Float32Array.from(this._values)
483
+ }
484
+
485
+ toFloat64Array () {
486
+ return this._values.slice(0)
487
+ }
488
+
489
+ static fromMatrix (init) {
490
+ if (!(init instanceof DOMMatrix)) throw new TypeError('Expected DOMMatrix')
491
+ return new DOMMatrix(init._values)
492
+ }
493
+
494
+ static fromFloat32Array (init) {
495
+ if (!(init instanceof Float32Array)) throw new TypeError('Expected Float32Array')
496
+ return new DOMMatrix(init)
497
+ }
498
+
499
+ static fromFloat64Array (init) {
500
+ if (!(init instanceof Float64Array)) throw new TypeError('Expected Float64Array')
501
+ return new DOMMatrix(init)
502
+ }
503
+
504
+ [util.inspect.custom || 'inspect'] (depth, options) {
505
+ if (depth < 0) return '[DOMMatrix]'
506
+
507
+ return `DOMMatrix [
508
+ a: ${this.a}
509
+ b: ${this.b}
510
+ c: ${this.c}
511
+ d: ${this.d}
512
+ e: ${this.e}
513
+ f: ${this.f}
514
+ m11: ${this.m11}
515
+ m12: ${this.m12}
516
+ m13: ${this.m13}
517
+ m14: ${this.m14}
518
+ m21: ${this.m21}
519
+ m22: ${this.m22}
520
+ m23: ${this.m23}
521
+ m23: ${this.m23}
522
+ m31: ${this.m31}
523
+ m32: ${this.m32}
524
+ m33: ${this.m33}
525
+ m34: ${this.m34}
526
+ m41: ${this.m41}
527
+ m42: ${this.m42}
528
+ m43: ${this.m43}
529
+ m44: ${this.m44}
530
+ is2D: ${this.is2D}
531
+ isIdentity: ${this.isIdentity} ]`
532
+ }
533
+ }
534
+
535
+ /**
536
+ * Checks that `value` is a number and sets the value.
537
+ */
538
+ function setNumber2D (receiver, index, value) {
539
+ if (typeof value !== 'number') throw new TypeError('Expected number')
540
+ return (receiver._values[index] = value)
541
+ }
542
+
543
+ /**
544
+ * Checks that `value` is a number, sets `_is2D = false` if necessary and sets
545
+ * the value.
546
+ */
547
+ function setNumber3D (receiver, index, value) {
548
+ if (typeof value !== 'number') throw new TypeError('Expected number')
549
+ if (index === M33 || index === M44) {
550
+ if (value !== 1) receiver._is2D = false
551
+ } else if (value !== 0) receiver._is2D = false
552
+ return (receiver._values[index] = value)
553
+ }
554
+
555
+ Object.defineProperties(DOMMatrix.prototype, {
556
+ m11: { get () { return this._values[M11] }, set (v) { return setNumber2D(this, M11, v) } },
557
+ m12: { get () { return this._values[M12] }, set (v) { return setNumber2D(this, M12, v) } },
558
+ m13: { get () { return this._values[M13] }, set (v) { return setNumber3D(this, M13, v) } },
559
+ m14: { get () { return this._values[M14] }, set (v) { return setNumber3D(this, M14, v) } },
560
+ m21: { get () { return this._values[M21] }, set (v) { return setNumber2D(this, M21, v) } },
561
+ m22: { get () { return this._values[M22] }, set (v) { return setNumber2D(this, M22, v) } },
562
+ m23: { get () { return this._values[M23] }, set (v) { return setNumber3D(this, M23, v) } },
563
+ m24: { get () { return this._values[M24] }, set (v) { return setNumber3D(this, M24, v) } },
564
+ m31: { get () { return this._values[M31] }, set (v) { return setNumber3D(this, M31, v) } },
565
+ m32: { get () { return this._values[M32] }, set (v) { return setNumber3D(this, M32, v) } },
566
+ m33: { get () { return this._values[M33] }, set (v) { return setNumber3D(this, M33, v) } },
567
+ m34: { get () { return this._values[M34] }, set (v) { return setNumber3D(this, M34, v) } },
568
+ m41: { get () { return this._values[M41] }, set (v) { return setNumber2D(this, M41, v) } },
569
+ m42: { get () { return this._values[M42] }, set (v) { return setNumber2D(this, M42, v) } },
570
+ m43: { get () { return this._values[M43] }, set (v) { return setNumber3D(this, M43, v) } },
571
+ m44: { get () { return this._values[M44] }, set (v) { return setNumber3D(this, M44, v) } },
572
+
573
+ a: { get () { return this.m11 }, set (v) { return (this.m11 = v) } },
574
+ b: { get () { return this.m12 }, set (v) { return (this.m12 = v) } },
575
+ c: { get () { return this.m21 }, set (v) { return (this.m21 = v) } },
576
+ d: { get () { return this.m22 }, set (v) { return (this.m22 = v) } },
577
+ e: { get () { return this.m41 }, set (v) { return (this.m41 = v) } },
578
+ f: { get () { return this.m42 }, set (v) { return (this.m42 = v) } },
579
+
580
+ is2D: { get () { return this._is2D } }, // read-only
581
+
582
+ isIdentity: {
583
+ get () {
584
+ const values = this._values
585
+ return (values[M11] === 1 && values[M12] === 0 && values[M13] === 0 && values[M14] === 0 &&
586
+ values[M21] === 0 && values[M22] === 1 && values[M23] === 0 && values[M24] === 0 &&
587
+ values[M31] === 0 && values[M32] === 0 && values[M33] === 1 && values[M34] === 0 &&
588
+ values[M41] === 0 && values[M42] === 0 && values[M43] === 0 && values[M44] === 1)
589
+ }
590
+ }
591
+ })
592
+
593
+ /**
594
+ * Instantiates a DOMMatrix, bypassing the constructor.
595
+ * @param {Float64Array} values Value to assign to `_values`. This is assigned
596
+ * without copying (okay because all usages are followed by a multiply).
597
+ */
598
+ function newInstance (values) {
599
+ const instance = Object.create(DOMMatrix.prototype)
600
+ instance.constructor = DOMMatrix
601
+ instance._is2D = true
602
+ instance._values = values
603
+ return instance
604
+ }
605
+
606
+ function multiply (A, B) {
607
+ const dest = new Float64Array(16)
608
+ for (let i = 0; i < 4; i++) {
609
+ for (let j = 0; j < 4; j++) {
610
+ let sum = 0
611
+ for (let k = 0; k < 4; k++) {
612
+ sum += A[i * 4 + k] * B[k * 4 + j]
613
+ }
614
+ dest[i * 4 + j] = sum
615
+ }
616
+ }
617
+ return dest
618
+ }
619
+
620
+ module.exports = { DOMMatrix, DOMPoint }
@@ -0,0 +1,80 @@
1
+ 'use strict'
2
+
3
+ const path = require('path')
4
+
5
+ const PLATFORMS = {
6
+ 'darwin-arm64': '@shqld/canvas-darwin-arm64',
7
+ 'darwin-x64': '@shqld/canvas-darwin-x64',
8
+ 'linux-arm64-gnu': '@shqld/canvas-linux-arm64-gnu',
9
+ 'linux-arm64-musl': '@shqld/canvas-linux-arm64-musl',
10
+ 'linux-x64-gnu': '@shqld/canvas-linux-x64-gnu',
11
+ 'linux-x64-musl': '@shqld/canvas-linux-x64-musl',
12
+ 'win32-x64': '@shqld/canvas-win32-x64'
13
+ }
14
+
15
+ function getPlatformKey () {
16
+ const platform = process.platform
17
+ const arch = process.arch
18
+ let key = `${platform}-${arch}`
19
+ if (platform === 'linux') {
20
+ key += isMuslLinux() ? '-musl' : '-gnu'
21
+ }
22
+ return key
23
+ }
24
+
25
+ function isMuslLinux () {
26
+ try {
27
+ const { execFileSync } = require('child_process')
28
+ const output = execFileSync('ldd', ['--version'], {
29
+ encoding: 'utf8',
30
+ stdio: ['pipe', 'pipe', 'pipe']
31
+ })
32
+ return output.includes('musl')
33
+ } catch (e) {
34
+ return e.stderr ? e.stderr.includes('musl') : false
35
+ }
36
+ }
37
+
38
+ function loadBinding () {
39
+ const key = getPlatformKey()
40
+ const packageName = PLATFORMS[key]
41
+
42
+ if (packageName) {
43
+ try {
44
+ if (process.platform === 'win32') {
45
+ const pkgDir = path.dirname(require.resolve(`${packageName}/package.json`))
46
+ process.env.PATH = pkgDir + path.delimiter + process.env.PATH
47
+ }
48
+ return require(packageName)
49
+ } catch (_) {
50
+ // fall through to build-from-source fallback
51
+ }
52
+ }
53
+
54
+ try {
55
+ const localPath = path.resolve(__dirname, '..', 'build', 'Release')
56
+ if (process.platform === 'win32') {
57
+ process.env.PATH = localPath + path.delimiter + process.env.PATH
58
+ }
59
+ return require(path.join(localPath, 'canvas.node'))
60
+ } catch (_) {
61
+ const supported = Object.keys(PLATFORMS).join(', ')
62
+ throw new Error(
63
+ `No prebuilt canvas binary found for ${key}. ` +
64
+ `Supported platforms: ${supported}. ` +
65
+ 'To build from source: npm rebuild canvas --build-from-source'
66
+ )
67
+ }
68
+ }
69
+
70
+ const bindings = loadBinding()
71
+
72
+ module.exports = bindings
73
+
74
+ bindings.ImageData.prototype.toString = function () {
75
+ return '[object ImageData]'
76
+ }
77
+
78
+ bindings.CanvasGradient.prototype.toString = function () {
79
+ return '[object CanvasGradient]'
80
+ }