@sudobility/music_drawing 0.0.6 → 0.0.10

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 (53) hide show
  1. package/dist/canvas-renderer.d.ts +9 -1
  2. package/dist/canvas-renderer.d.ts.map +1 -1
  3. package/dist/canvas-renderer.js +69 -26
  4. package/dist/canvas-renderer.js.map +1 -1
  5. package/dist/drawing-context.d.ts +109 -0
  6. package/dist/drawing-context.d.ts.map +1 -0
  7. package/dist/drawing-context.js +23 -0
  8. package/dist/drawing-context.js.map +1 -0
  9. package/dist/icon-canvas.d.ts +2 -1
  10. package/dist/icon-canvas.d.ts.map +1 -1
  11. package/dist/icon-canvas.js.map +1 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/layout.d.ts.map +1 -1
  17. package/dist/layout.js +2 -1
  18. package/dist/layout.js.map +1 -1
  19. package/dist/measure-content.d.ts.map +1 -1
  20. package/dist/measure-content.js.map +1 -1
  21. package/dist/skia/css-font.d.ts +24 -0
  22. package/dist/skia/css-font.d.ts.map +1 -0
  23. package/dist/skia/css-font.js +100 -0
  24. package/dist/skia/css-font.js.map +1 -0
  25. package/dist/skia/index.d.ts +17 -0
  26. package/dist/skia/index.d.ts.map +1 -0
  27. package/dist/skia/index.js +14 -0
  28. package/dist/skia/index.js.map +1 -0
  29. package/dist/skia/skia-api.d.ts +133 -0
  30. package/dist/skia/skia-api.d.ts.map +1 -0
  31. package/dist/skia/skia-api.js +28 -0
  32. package/dist/skia/skia-api.js.map +1 -0
  33. package/dist/skia/skia-context.d.ts +58 -0
  34. package/dist/skia/skia-context.d.ts.map +1 -0
  35. package/dist/skia/skia-context.js +394 -0
  36. package/dist/skia/skia-context.js.map +1 -0
  37. package/dist/test/canvas-stub.d.ts +5 -5
  38. package/dist/test/canvas-stub.d.ts.map +1 -1
  39. package/dist/test/canvas-stub.js +3 -4
  40. package/dist/test/canvas-stub.js.map +1 -1
  41. package/dist/test/fake-skia.d.ts +81 -0
  42. package/dist/test/fake-skia.d.ts.map +1 -0
  43. package/dist/test/fake-skia.js +228 -0
  44. package/dist/test/fake-skia.js.map +1 -0
  45. package/dist/test/index.d.ts +18 -0
  46. package/dist/test/index.d.ts.map +1 -0
  47. package/dist/test/index.js +16 -0
  48. package/dist/test/index.js.map +1 -0
  49. package/dist/types.d.ts +49 -0
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/types.js +48 -1
  52. package/dist/types.js.map +1 -1
  53. package/package.json +16 -6
@@ -0,0 +1,394 @@
1
+ import { parseCssFont } from './css-font.js';
2
+ /** CSS `font-weight: bold`, and the neutral weight, as Skia's enum spells them. */
3
+ const BOLD_WEIGHT = 700;
4
+ const NORMAL_WEIGHT = 400;
5
+ /** The 2D default font, per the canvas spec. */
6
+ const DEFAULT_FONT = '10px sans-serif';
7
+ /**
8
+ * Resolved faces, shared by every context built from the same `Skia`.
9
+ *
10
+ * The idiomatic React Native pattern records a fresh `SkCanvas` per frame —
11
+ * `Skia.PictureRecorder().beginRecording()` — and therefore a fresh context per
12
+ * frame. An instance-level cache would put a `matchFamilyStyle` lookup back on
13
+ * the per-frame path for every shorthand the renderer sets. Keyed on
14
+ * `skia.Skia`, the package's own singleton, rather than on the module wrapper,
15
+ * which a host may well rebuild inline at each call.
16
+ */
17
+ const FONT_CACHES = new WeakMap();
18
+ function fontCacheFor(api) {
19
+ const existing = FONT_CACHES.get(api);
20
+ if (existing)
21
+ return existing;
22
+ const created = new Map();
23
+ FONT_CACHES.set(api, created);
24
+ return created;
25
+ }
26
+ const IDENTITY = { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
27
+ function initialState() {
28
+ return {
29
+ matrix: { ...IDENTITY },
30
+ fillStyle: '#000000',
31
+ strokeStyle: '#000000',
32
+ lineWidth: 1,
33
+ lineCap: 'butt',
34
+ lineJoin: 'miter',
35
+ font: DEFAULT_FONT,
36
+ globalAlpha: 1,
37
+ shadowBlur: 0,
38
+ shadowColor: 'rgba(0, 0, 0, 0)',
39
+ lineDash: [],
40
+ };
41
+ }
42
+ class SkiaDrawingContext {
43
+ constructor(options) {
44
+ this.state = initialState();
45
+ this.stack = [];
46
+ /** Canvas connects an arc to the current point; a fresh path has none. */
47
+ this.hasCurrentPoint = false;
48
+ this.skia = options.skia;
49
+ this.target = options.canvas;
50
+ this.canvas = { width: options.width, height: options.height };
51
+ this.fontCache = fontCacheFor(options.skia.Skia);
52
+ // After `this.skia`: a field initializer would run before the constructor
53
+ // body and find it undefined.
54
+ this.path = this.newPath();
55
+ }
56
+ // ---------------------------------------------------------------- state
57
+ save() {
58
+ this.stack.push({
59
+ ...this.state,
60
+ matrix: { ...this.state.matrix },
61
+ lineDash: [...this.state.lineDash],
62
+ });
63
+ }
64
+ restore() {
65
+ const previous = this.stack.pop();
66
+ if (previous)
67
+ this.state = previous;
68
+ }
69
+ get fillStyle() {
70
+ return this.state.fillStyle;
71
+ }
72
+ set fillStyle(value) {
73
+ this.state.fillStyle = value;
74
+ }
75
+ get strokeStyle() {
76
+ return this.state.strokeStyle;
77
+ }
78
+ set strokeStyle(value) {
79
+ this.state.strokeStyle = value;
80
+ }
81
+ get lineWidth() {
82
+ return this.state.lineWidth;
83
+ }
84
+ set lineWidth(value) {
85
+ // Canvas ignores a value that is not finite and positive, keeping the one
86
+ // before it. Skia would take a zero and stroke a hairline instead.
87
+ if (Number.isFinite(value) && value > 0)
88
+ this.state.lineWidth = value;
89
+ }
90
+ get lineCap() {
91
+ return this.state.lineCap;
92
+ }
93
+ set lineCap(value) {
94
+ this.state.lineCap = value;
95
+ }
96
+ get lineJoin() {
97
+ return this.state.lineJoin;
98
+ }
99
+ set lineJoin(value) {
100
+ this.state.lineJoin = value;
101
+ }
102
+ get font() {
103
+ return this.state.font;
104
+ }
105
+ set font(value) {
106
+ this.state.font = value;
107
+ }
108
+ get globalAlpha() {
109
+ return this.state.globalAlpha;
110
+ }
111
+ set globalAlpha(value) {
112
+ // Out of range is ignored rather than clamped, which is what canvas does.
113
+ if (Number.isFinite(value) && value >= 0 && value <= 1) {
114
+ this.state.globalAlpha = value;
115
+ }
116
+ }
117
+ get shadowBlur() {
118
+ return this.state.shadowBlur;
119
+ }
120
+ set shadowBlur(value) {
121
+ this.state.shadowBlur = value;
122
+ }
123
+ get shadowColor() {
124
+ return this.state.shadowColor;
125
+ }
126
+ set shadowColor(value) {
127
+ this.state.shadowColor = value;
128
+ }
129
+ setLineDash(segments) {
130
+ this.state.lineDash = [...segments];
131
+ }
132
+ // ------------------------------------------------------------ transform
133
+ translate(x, y) {
134
+ const m = this.state.matrix;
135
+ m.e += m.a * x + m.c * y;
136
+ m.f += m.b * x + m.d * y;
137
+ }
138
+ scale(x, y) {
139
+ const m = this.state.matrix;
140
+ m.a *= x;
141
+ m.b *= x;
142
+ m.c *= y;
143
+ m.d *= y;
144
+ }
145
+ setTransform(a, b, c, d, e, f) {
146
+ this.state.matrix = { a, b, c, d, e, f };
147
+ }
148
+ getTransform() {
149
+ return { ...this.state.matrix };
150
+ }
151
+ // ----------------------------------------------------------------- path
152
+ newPath() {
153
+ return this.skiaApi.Path.Make();
154
+ }
155
+ get skiaApi() {
156
+ return this.skia.Skia;
157
+ }
158
+ beginPath() {
159
+ this.path = this.newPath();
160
+ this.hasCurrentPoint = false;
161
+ }
162
+ closePath() {
163
+ this.path.close();
164
+ }
165
+ moveTo(x, y) {
166
+ this.path.moveTo(x, y);
167
+ this.hasCurrentPoint = true;
168
+ }
169
+ lineTo(x, y) {
170
+ // Canvas treats `lineTo` with no current point as a `moveTo`.
171
+ if (!this.hasCurrentPoint) {
172
+ this.moveTo(x, y);
173
+ return;
174
+ }
175
+ this.path.lineTo(x, y);
176
+ }
177
+ bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
178
+ this.path.cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
179
+ this.hasCurrentPoint = true;
180
+ }
181
+ quadraticCurveTo(cpx, cpy, x, y) {
182
+ this.path.quadTo(cpx, cpy, x, y);
183
+ this.hasCurrentPoint = true;
184
+ }
185
+ arc(x, y, radius, startAngle, endAngle, counterclockwise = false) {
186
+ const oval = this.skiaApi.XYWHRect(x - radius, y - radius, radius * 2, radius * 2);
187
+ this.path.arcToOval(oval, toDegrees(startAngle), toDegrees(sweepOf(startAngle, endAngle, counterclockwise)),
188
+ // Canvas draws a line from the current point to the arc's start; Skia
189
+ // does the same when told not to force a move.
190
+ !this.hasCurrentPoint);
191
+ this.hasCurrentPoint = true;
192
+ }
193
+ rect(x, y, width, height) {
194
+ this.path.addRect(this.skiaApi.XYWHRect(x, y, width, height));
195
+ // Canvas ends `rect()` with the current point at (x, y), so a following
196
+ // arc joins the path rather than opening a new contour.
197
+ this.hasCurrentPoint = true;
198
+ }
199
+ // ----------------------------------------------------------------- draw
200
+ /**
201
+ * Runs `draw` with the 2D transform installed, then takes it back off.
202
+ *
203
+ * Bracketing each draw rather than tracking Skia's matrix means the host's own
204
+ * canvas state is exactly as it was left, which matters when the context is
205
+ * one of several things painting into a frame.
206
+ */
207
+ inUserSpace(draw) {
208
+ const { a, b, c, d, e, f } = this.state.matrix;
209
+ this.target.save();
210
+ // Skia wants a row-major 3×3; canvas's six values are its top two rows.
211
+ this.target.concat([a, c, e, b, d, f, 0, 0, 1]);
212
+ draw();
213
+ this.target.restore();
214
+ }
215
+ paintFor(style, stroke) {
216
+ const paint = this.skiaApi.Paint();
217
+ paint.setAntiAlias(true);
218
+ this.applyColor(paint, style);
219
+ const alpha = this.state.globalAlpha;
220
+ if (alpha < 1)
221
+ paint.setAlphaf(paint.getAlphaf() * alpha);
222
+ if (stroke) {
223
+ paint.setStyle(this.skia.PaintStyle.Stroke);
224
+ paint.setStrokeWidth(this.state.lineWidth);
225
+ paint.setStrokeCap(this.strokeCap());
226
+ paint.setStrokeJoin(this.strokeJoin());
227
+ if (this.state.lineDash.length > 0) {
228
+ paint.setPathEffect(this.skiaApi.PathEffect.MakeDash([...this.state.lineDash]));
229
+ }
230
+ }
231
+ else {
232
+ paint.setStyle(this.skia.PaintStyle.Fill);
233
+ }
234
+ return paint;
235
+ }
236
+ /**
237
+ * Colours a paint from a 2D style value, never throwing.
238
+ *
239
+ * A gradient or pattern has no equivalent here — nothing in this package sets
240
+ * one, and a visible glyph beats a dropped one. More importantly `Skia.Color`
241
+ * throws on a string it cannot parse, where canvas ignores the assignment and
242
+ * carries on; since the renderer catches draw failures a whole system at a
243
+ * time, letting that through would turn one typo in a caller's theme into a
244
+ * swathe of missing music.
245
+ *
246
+ * If even black will not parse, the paint is left as Skia made it — which is
247
+ * opaque black already, so the fallback needs no colour at all.
248
+ */
249
+ applyColor(paint, style) {
250
+ const css = typeof style === 'string' ? style : '#000000';
251
+ try {
252
+ paint.setColor(this.skiaApi.Color(css));
253
+ return;
254
+ }
255
+ catch {
256
+ // Unparseable; try black before giving up.
257
+ }
258
+ try {
259
+ paint.setColor(this.skiaApi.Color('#000000'));
260
+ }
261
+ catch {
262
+ // Leave Skia's own default, which is opaque black.
263
+ }
264
+ }
265
+ strokeCap() {
266
+ const { StrokeCap } = this.skia;
267
+ if (this.state.lineCap === 'round')
268
+ return StrokeCap.Round;
269
+ if (this.state.lineCap === 'square')
270
+ return StrokeCap.Square;
271
+ return StrokeCap.Butt;
272
+ }
273
+ strokeJoin() {
274
+ const { StrokeJoin } = this.skia;
275
+ if (this.state.lineJoin === 'round')
276
+ return StrokeJoin.Round;
277
+ if (this.state.lineJoin === 'bevel')
278
+ return StrokeJoin.Bevel;
279
+ return StrokeJoin.Miter;
280
+ }
281
+ fill() {
282
+ const paint = this.paintFor(this.state.fillStyle, false);
283
+ this.inUserSpace(() => this.target.drawPath(this.path, paint));
284
+ }
285
+ stroke() {
286
+ const paint = this.paintFor(this.state.strokeStyle, true);
287
+ this.inUserSpace(() => this.target.drawPath(this.path, paint));
288
+ }
289
+ fillRect(x, y, width, height) {
290
+ const rect = this.skiaApi.XYWHRect(x, y, width, height);
291
+ const paint = this.paintFor(this.state.fillStyle, false);
292
+ this.inUserSpace(() => this.target.drawRect(rect, paint));
293
+ }
294
+ clearRect(x, y, width, height) {
295
+ const rect = this.skiaApi.XYWHRect(x, y, width, height);
296
+ const paint = this.skiaApi.Paint();
297
+ // Erase to transparent rather than paint black — the host's own background
298
+ // shows through, exactly as clearing a canvas does.
299
+ paint.setBlendMode(this.skia.BlendMode.Clear);
300
+ paint.setColor(this.skiaApi.Color('#00000000'));
301
+ this.inUserSpace(() => this.target.drawRect(rect, paint));
302
+ }
303
+ // ----------------------------------------------------------------- text
304
+ resolveFont() {
305
+ const key = this.state.font;
306
+ const cached = this.fontCache.get(key);
307
+ if (cached)
308
+ return cached;
309
+ const { family, sizePx, bold, italic } = parseCssFont(key);
310
+ const typeface = this.matchTypeface(family, bold, italic);
311
+ const font = this.skiaApi.Font(typeface ?? undefined, sizePx);
312
+ this.fontCache.set(key, font);
313
+ return font;
314
+ }
315
+ matchTypeface(family, bold, italic) {
316
+ try {
317
+ return this.skiaApi.FontMgr.System().matchFamilyStyle(family, {
318
+ weight: bold ? BOLD_WEIGHT : NORMAL_WEIGHT,
319
+ slant: italic
320
+ ? this.skia.FontSlant.Italic
321
+ : this.skia.FontSlant.Upright,
322
+ });
323
+ }
324
+ catch {
325
+ // No system font manager, or no match at all: Skia's default face still
326
+ // draws something legible, which beats losing the frame.
327
+ return null;
328
+ }
329
+ }
330
+ fillText(text, x, y) {
331
+ const font = this.resolveFont();
332
+ const paint = this.paintFor(this.state.fillStyle, false);
333
+ this.inUserSpace(() => this.target.drawText(text, x, y, paint, font));
334
+ }
335
+ measureText(text) {
336
+ const font = this.resolveFont();
337
+ const bounds = font.measureText(text);
338
+ const metrics = font.getMetrics();
339
+ // `measureText` returns glyph *bounds*; canvas reports the advance width,
340
+ // which includes side bearings. Summing glyph advances is the equivalent.
341
+ const widths = font.getGlyphWidths(font.getGlyphIDs(text));
342
+ const advance = widths.reduce((total, width) => total + width, 0);
343
+ return {
344
+ width: advance > 0 ? advance : bounds.width,
345
+ actualBoundingBoxAscent: -bounds.y,
346
+ actualBoundingBoxDescent: bounds.height + bounds.y,
347
+ fontBoundingBoxAscent: -metrics.ascent,
348
+ fontBoundingBoxDescent: metrics.descent,
349
+ };
350
+ }
351
+ }
352
+ const DEGREES_PER_RADIAN = 180 / Math.PI;
353
+ const TAU = Math.PI * 2;
354
+ function toDegrees(radians) {
355
+ return radians * DEGREES_PER_RADIAN;
356
+ }
357
+ /**
358
+ * Canvas's arc-direction rule as a signed sweep.
359
+ *
360
+ * Going clockwise the sweep is positive and wraps up to a full turn; going
361
+ * counterclockwise it is negative. A range wider than a full turn is clamped,
362
+ * which is what makes `arc(…, 0, 2π)` a circle rather than nothing.
363
+ */
364
+ function sweepOf(startAngle, endAngle, counterclockwise) {
365
+ const delta = endAngle - startAngle;
366
+ if (!counterclockwise) {
367
+ if (delta >= TAU)
368
+ return TAU;
369
+ return delta < 0 ? TAU - (-delta % TAU) : delta;
370
+ }
371
+ if (delta <= -TAU)
372
+ return -TAU;
373
+ return delta > 0 ? -(TAU - (delta % TAU)) : delta;
374
+ }
375
+ /**
376
+ * Wraps a Skia canvas as the 2D drawing context this package paints into.
377
+ *
378
+ * ```ts
379
+ * import * as skia from '@shopify/react-native-skia';
380
+ * import { CanvasScoreRenderer } from '@sudobility/music_drawing';
381
+ * import { createSkiaContext2D } from '@sudobility/music_drawing/skia';
382
+ *
383
+ * const ctx = createSkiaContext2D({ skia, canvas, width, height });
384
+ * new CanvasScoreRenderer().render(score, ctx, options);
385
+ * ```
386
+ *
387
+ * The Skia module is injected rather than imported so that this package
388
+ * depends on nothing but `vexflow`; passing the namespace is what type-checks
389
+ * the host's Skia against what the adapter uses.
390
+ */
391
+ export function createSkiaContext2D(options) {
392
+ return new SkiaDrawingContext(options);
393
+ }
394
+ //# sourceMappingURL=skia-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skia-context.js","sourceRoot":"","sources":["../../src/skia/skia-context.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,20 @@
1
1
  /**
2
- * A recording stand-in for `CanvasRenderingContext2D`: every method call is
2
+ * A recording stand-in for `DrawingContext2D`: every method call is
3
3
  * appended to `ops`; every property write is accepted; `measureText`
4
4
  * returns a deterministic width (8px/char) so VexFlow text layout math
5
5
  * stays finite. Proxy-based so any method VexFlow's `CanvasContext` calls
6
6
  * is recorded without this double having to enumerate the whole 2D API —
7
7
  * new methods VexFlow starts calling never require test-double updates.
8
8
  *
9
- * Exported from the package root (like `testStoreContext`) so downstream
10
- * suites music_app's jsdom setup stubs `HTMLCanvasElement.getContext`
11
- * with it — share one implementation.
9
+ * Published at `@sudobility/music_drawing/test` so downstream suites a jsdom
10
+ * setup stubbing `getContext`, say share one implementation.
12
11
  */
12
+ import type { DrawingContext2D } from '../drawing-context.js';
13
13
  export type MockOp = {
14
14
  method: string;
15
15
  args: unknown[];
16
16
  };
17
- export type Mock2DContext = CanvasRenderingContext2D & {
17
+ export type Mock2DContext = DrawingContext2D & {
18
18
  ops: MockOp[];
19
19
  };
20
20
  export declare function createMock2DContext(width?: number, height?: number): Mock2DContext;
@@ -1 +1 @@
1
- {"version":3,"file":"canvas-stub.d.ts","sourceRoot":"","sources":["../../src/test/canvas-stub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC;AACzD,MAAM,MAAM,aAAa,GAAG,wBAAwB,GAAG;IAAE,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEzE,wBAAgB,mBAAmB,CAAC,KAAK,SAAM,EAAE,MAAM,SAAM,GAAG,aAAa,CAoC5E"}
1
+ {"version":3,"file":"canvas-stub.d.ts","sourceRoot":"","sources":["../../src/test/canvas-stub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,MAAM,MAAM,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC;AACzD,MAAM,MAAM,aAAa,GAAG,gBAAgB,GAAG;IAAE,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEjE,wBAAgB,mBAAmB,CAAC,KAAK,SAAM,EAAE,MAAM,SAAM,GAAG,aAAa,CAoC5E"}
@@ -1,14 +1,13 @@
1
1
  /**
2
- * A recording stand-in for `CanvasRenderingContext2D`: every method call is
2
+ * A recording stand-in for `DrawingContext2D`: every method call is
3
3
  * appended to `ops`; every property write is accepted; `measureText`
4
4
  * returns a deterministic width (8px/char) so VexFlow text layout math
5
5
  * stays finite. Proxy-based so any method VexFlow's `CanvasContext` calls
6
6
  * is recorded without this double having to enumerate the whole 2D API —
7
7
  * new methods VexFlow starts calling never require test-double updates.
8
8
  *
9
- * Exported from the package root (like `testStoreContext`) so downstream
10
- * suites music_app's jsdom setup stubs `HTMLCanvasElement.getContext`
11
- * with it — share one implementation.
9
+ * Published at `@sudobility/music_drawing/test` so downstream suites a jsdom
10
+ * setup stubbing `getContext`, say share one implementation.
12
11
  */
13
12
  export function createMock2DContext(width = 800, height = 600) {
14
13
  const ops = [];
@@ -1 +1 @@
1
- {"version":3,"file":"canvas-stub.js","sourceRoot":"","sources":["../../src/test/canvas-stub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,MAAM,UAAU,mBAAmB,CAAC,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG;IAC3D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,KAAK,GAAqC;QAC9C,GAAG;QACH,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;QACzB,WAAW,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC;YAC9B,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAC9B,uBAAuB,EAAE,CAAC;YAC1B,wBAAwB,EAAE,CAAC;YAC3B,qBAAqB,EAAE,CAAC;YACxB,sBAAsB,EAAE,CAAC;SAC1B,CAAC;QACF,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5D,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;QAC/D,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;QAC/D,YAAY,EAAE,CAAC,EAAU,EAAE,EAAU,EAAE,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC;YAC/D,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,IAAI,EAAE,IAAI,iBAAiB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SACvC,CAAC;KACH,CAAC;IACF,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE;QACtB,GAAG,CAAC,MAAM,EAAE,IAAI;YACd,IAAI,IAAI,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;YACxC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE;gBAChC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBACzC,OAAO,SAAS,CAAC;YACnB,CAAC,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK;YACrB,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAA6B,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"canvas-stub.js","sourceRoot":"","sources":["../../src/test/canvas-stub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,MAAM,UAAU,mBAAmB,CAAC,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG;IAC3D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,KAAK,GAAqC;QAC9C,GAAG;QACH,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;QACzB,WAAW,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC;YAC9B,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAC9B,uBAAuB,EAAE,CAAC;YAC1B,wBAAwB,EAAE,CAAC;YAC3B,qBAAqB,EAAE,CAAC;YACxB,sBAAsB,EAAE,CAAC;SAC1B,CAAC;QACF,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5D,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;QAC/D,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;QAC/D,YAAY,EAAE,CAAC,EAAU,EAAE,EAAU,EAAE,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC;YAC/D,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,IAAI,EAAE,IAAI,iBAAiB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SACvC,CAAC;KACH,CAAC;IACF,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE;QACtB,GAAG,CAAC,MAAM,EAAE,IAAI;YACd,IAAI,IAAI,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;YACxC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE;gBAChC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBACzC,OAAO,SAAS,CAAC;YACnB,CAAC,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK;YACrB,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAA6B,CAAC;AACjC,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * A recording stand-in for the `@shopify/react-native-skia` module.
3
+ *
4
+ * The adapter in `src/skia/` takes its Skia by injection, which is what makes
5
+ * this possible: the whole React Native drawing path can be exercised in Node,
6
+ * with no native module, no simulator and no 1.6 GB dependency. Every draw is
7
+ * recorded with the *effective* matrix at the time it happened, so a test can
8
+ * assert where something landed and not merely that it was drawn.
9
+ *
10
+ * Published at `@sudobility/music_drawing/test` alongside
11
+ * `createMock2DContext`, so a host app can reuse it to test its own Skia render
12
+ * surface.
13
+ */
14
+ import type { SkiaCanvas, SkiaModule, SkiaRect } from '../skia/skia-api.js';
15
+ /** One path command, in the order the adapter issued it. */
16
+ export type FakePathCommand = {
17
+ command: string;
18
+ args: number[];
19
+ };
20
+ export type FakePaintState = {
21
+ color: string;
22
+ /** 0 fill, 1 stroke — Skia's own `PaintStyle` values. */
23
+ style: number;
24
+ strokeWidth: number;
25
+ cap: number;
26
+ join: number;
27
+ alpha: number;
28
+ blendMode: number | null;
29
+ dashed: boolean;
30
+ };
31
+ export type FakeDraw = {
32
+ op: 'drawPath';
33
+ commands: FakePathCommand[];
34
+ paint: FakePaintState;
35
+ matrix: number[];
36
+ } | {
37
+ op: 'drawRect';
38
+ rect: SkiaRect;
39
+ paint: FakePaintState;
40
+ matrix: number[];
41
+ } | {
42
+ op: 'drawText';
43
+ text: string;
44
+ x: number;
45
+ y: number;
46
+ paint: FakePaintState;
47
+ font: FakeFontState;
48
+ matrix: number[];
49
+ };
50
+ export type FakeFontState = {
51
+ family: string;
52
+ size: number;
53
+ bold: boolean;
54
+ };
55
+ /** A request that reached the font manager, so tests can assert style resolution. */
56
+ export type FakeFontRequest = {
57
+ family: string;
58
+ style: unknown;
59
+ };
60
+ export type FakeSkia = SkiaModule & {
61
+ canvas: SkiaCanvas;
62
+ draws: FakeDraw[];
63
+ fontRequests: FakeFontRequest[];
64
+ };
65
+ /**
66
+ * Where a point ends up under a recorded matrix, computed straight from Skia's
67
+ * row-major contract: `[scaleX, skewX, transX, skewY, scaleY, transY]`.
68
+ *
69
+ * This is the independent half of the transform tests. Asserting on the matrix
70
+ * array alone cannot catch a transposition — the adapter and this fake would
71
+ * simply agree on the wrong order, and every transform the renderer uses is
72
+ * diagonal, where a transpose is invisible. Mapping a point under a *skewed*
73
+ * matrix and comparing against what canvas semantics say it should be checks
74
+ * the two sides against the spec rather than against each other.
75
+ */
76
+ export declare function mapPoint(matrix: number[], x: number, y: number): {
77
+ x: number;
78
+ y: number;
79
+ };
80
+ export declare function createFakeSkia(): FakeSkia;
81
+ //# sourceMappingURL=fake-skia.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-skia.d.ts","sourceRoot":"","sources":["../../src/test/fake-skia.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EACV,UAAU,EAGV,UAAU,EAGV,QAAQ,EACT,MAAM,qBAAqB,CAAC;AAE7B,4DAA4D;AAC5D,MAAM,MAAM,eAAe,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAElE,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAChB;IACE,EAAE,EAAE,UAAU,CAAC;IACf,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,GACD;IAAE,EAAE,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAC3E;IACE,EAAE,EAAE,UAAU,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEN,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5E,qFAAqF;AACrF,MAAM,MAAM,eAAe,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG;IAClC,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,YAAY,EAAE,eAAe,EAAE,CAAC;CACjC,CAAC;AAUF;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EAAE,EAChB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAK1B;AAyBD,wBAAgB,cAAc,IAAI,QAAQ,CAoMzC"}