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