gesso-core 0.6.30 → 0.8.0
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.
- package/CHANGELOG.md +47 -0
- package/dist/{CanvasSurface-CspYfnND.js → CanvasSurface-Cy2UErXI.js} +20177 -18279
- package/dist/CanvasSurface-Cy2UErXI.js.map +1 -0
- package/dist/{index-CLCtv12G.d.ts → index-CQPJZwhG.d.ts} +2568 -1423
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2053 -224
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +46 -3
- package/dist/testing.js +99 -10
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/CanvasSurface-CspYfnND.js.map +0 -1
package/dist/testing.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $
|
|
1
|
+
import { $a as UiPlatformAdapter, Ao as UiKeyboardController, Fg as Constraints, Hn as CanvasHost, Ig as LayoutBox, Lg as LayoutResult, Lo as UiWheelController, Mo as UiPointerController, No as ScrollContainerState, Og as TextMeasurer, On as Canvas2DRenderer, Po as ScrollSink, Qa as PlatformSurface, Tl as UiGraph, Un as CanvasSurface, Vo as UiGestureRecognizer, Xg as UiNodeType, Za as PlatformEventTarget, _h as UiNode, co as UiEditingController, fc as Canvas2DContext, jo as PointerControllerOptions, lo as TouchScrollerOptions, os as UiHitTester, pa as LayoutEngine, pc as Canvas2DGradient, um as UiFocusManager, uo as UiTouchScroller, vg as LayoutRecord, wm as UiInputDispatcher } from "./index-CQPJZwhG.js";
|
|
2
2
|
//#region src/layout/LayoutTestUtils.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Shared helpers for layout specs: builds UiNode trees through
|
|
@@ -121,6 +121,21 @@ declare class HarnessScrollSink implements ScrollSink {
|
|
|
121
121
|
interface RecordedCall {
|
|
122
122
|
name: string;
|
|
123
123
|
args: unknown[];
|
|
124
|
+
/** Which context made the call, when several record into one log; absent for the frame's own. */
|
|
125
|
+
target?: string;
|
|
126
|
+
}
|
|
127
|
+
interface RecordingOptions {
|
|
128
|
+
/** A log to record into, shared with other contexts; a fresh one by default. */
|
|
129
|
+
calls?: RecordedCall[];
|
|
130
|
+
/** Stamped on every call this context records into a shared log. */
|
|
131
|
+
target?: string;
|
|
132
|
+
/**
|
|
133
|
+
* Whether the context tracks its transform and answers `getTransform`,
|
|
134
|
+
* as a real one does. Off by default, because a renderer reads the
|
|
135
|
+
* absence as "no transform worth reporting" and most specs were
|
|
136
|
+
* written against that; see `Canvas2DContext.getTransform`.
|
|
137
|
+
*/
|
|
138
|
+
transform?: boolean;
|
|
124
139
|
}
|
|
125
140
|
/**
|
|
126
141
|
* The gradient a recording context hands back, carrying what it was
|
|
@@ -144,6 +159,20 @@ declare class RecordedGradient implements Canvas2DGradient {
|
|
|
144
159
|
*/
|
|
145
160
|
declare class RecordingCanvasContext implements Canvas2DContext {
|
|
146
161
|
readonly calls: RecordedCall[];
|
|
162
|
+
private readonly target;
|
|
163
|
+
private matrix;
|
|
164
|
+
private readonly matrices;
|
|
165
|
+
getTransform?: () => {
|
|
166
|
+
a: number;
|
|
167
|
+
b: number;
|
|
168
|
+
c: number;
|
|
169
|
+
d: number;
|
|
170
|
+
e: number;
|
|
171
|
+
f: number;
|
|
172
|
+
};
|
|
173
|
+
constructor(options?: RecordingOptions);
|
|
174
|
+
/** Multiplies the current matrix by another on the right, as a canvas does. */
|
|
175
|
+
private compose;
|
|
147
176
|
private _fillStyle;
|
|
148
177
|
private _strokeStyle;
|
|
149
178
|
private _lineWidth;
|
|
@@ -232,10 +261,12 @@ declare function savedDepth(context: RecordingCanvasContext): number;
|
|
|
232
261
|
*/
|
|
233
262
|
declare class FakeCanvasHost implements CanvasHost {
|
|
234
263
|
private readonly context;
|
|
264
|
+
readonly label?: string | undefined;
|
|
235
265
|
width: number;
|
|
236
266
|
height: number;
|
|
237
267
|
private contextRequests;
|
|
238
|
-
|
|
268
|
+
/** `label` names the host for a spec that meets it again as a `drawImage` source. */
|
|
269
|
+
constructor(context: Canvas2DContext | null, label?: string | undefined);
|
|
239
270
|
getContext(_contextId: '2d'): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null;
|
|
240
271
|
get contextRequestCount(): number;
|
|
241
272
|
}
|
|
@@ -252,7 +283,19 @@ declare class RenderHarness {
|
|
|
252
283
|
readonly host: FakeCanvasHost;
|
|
253
284
|
readonly surface: CanvasSurface;
|
|
254
285
|
readonly renderer: Canvas2DRenderer;
|
|
255
|
-
|
|
286
|
+
/** The layers opacity groups were drawn in, by label; empty without `groups`. */
|
|
287
|
+
readonly groupLayers: Map<string, FakeCanvasHost>;
|
|
288
|
+
/**
|
|
289
|
+
* With `groups`, opacity groups get layers as they do in a browser:
|
|
290
|
+
* the context tracks its transform, and each layer is a recording
|
|
291
|
+
* context writing into the frame's log, its calls stamped with the
|
|
292
|
+
* layer's label (`group0`, `group1`, ...) and its host met again as
|
|
293
|
+
* the source of the `drawImage` that blends it. Text is not kept as
|
|
294
|
+
* pixels, so it is still drawn as `fillText`.
|
|
295
|
+
*/
|
|
296
|
+
constructor(logicalWidth?: number, logicalHeight?: number, dpr?: number, options?: {
|
|
297
|
+
groups?: boolean;
|
|
298
|
+
});
|
|
256
299
|
createNode(id: string, type: UiNodeType): UiNode;
|
|
257
300
|
append(parent: UiNode, ...children: UiNode[]): void;
|
|
258
301
|
layout(node: UiNode, constraints?: Constraints): LayoutResult;
|
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $
|
|
1
|
+
import { $ as UiPlatformAdapter, C as LayoutEngine, Et as UiInputDispatcher, I as Constraints, at as UiEditingController, dt as UiKeyboardController, ft as UiPointerController, lt as UiWheelController, mt as UiHitTester, ot as UiTouchScroller, pt as UiFocusManager, r as Canvas2DRenderer, st as UiGestureRecognizer, t as CanvasSurface, tr as CharacterCountTextMeasurer, wr as UiGraph, xt as scrollRange } from "./CanvasSurface-Cy2UErXI.js";
|
|
2
2
|
//#region src/layout/LayoutTestUtils.ts
|
|
3
3
|
/**
|
|
4
4
|
* Shared helpers for layout specs: builds UiNode trees through
|
|
@@ -263,7 +263,45 @@ var RecordedGradient = class {
|
|
|
263
263
|
* assignment so tests can assert the exact draw sequence.
|
|
264
264
|
*/
|
|
265
265
|
var RecordingCanvasContext = class {
|
|
266
|
-
calls
|
|
266
|
+
calls;
|
|
267
|
+
target;
|
|
268
|
+
matrix = [
|
|
269
|
+
1,
|
|
270
|
+
0,
|
|
271
|
+
0,
|
|
272
|
+
1,
|
|
273
|
+
0,
|
|
274
|
+
0
|
|
275
|
+
];
|
|
276
|
+
matrices = [];
|
|
277
|
+
getTransform;
|
|
278
|
+
constructor(options = {}) {
|
|
279
|
+
this.calls = options.calls ?? [];
|
|
280
|
+
this.target = options.target;
|
|
281
|
+
if (options.transform === true) this.getTransform = () => {
|
|
282
|
+
const [a, b, c, d, e, f] = this.matrix;
|
|
283
|
+
return {
|
|
284
|
+
a,
|
|
285
|
+
b,
|
|
286
|
+
c,
|
|
287
|
+
d,
|
|
288
|
+
e,
|
|
289
|
+
f
|
|
290
|
+
};
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/** Multiplies the current matrix by another on the right, as a canvas does. */
|
|
294
|
+
compose(a, b, c, d, e, f) {
|
|
295
|
+
const m = this.matrix;
|
|
296
|
+
this.matrix = [
|
|
297
|
+
m[0] * a + m[2] * b,
|
|
298
|
+
m[1] * a + m[3] * b,
|
|
299
|
+
m[0] * c + m[2] * d,
|
|
300
|
+
m[1] * c + m[3] * d,
|
|
301
|
+
m[0] * e + m[2] * f + m[4],
|
|
302
|
+
m[1] * e + m[3] * f + m[5]
|
|
303
|
+
];
|
|
304
|
+
}
|
|
267
305
|
_fillStyle = "#000";
|
|
268
306
|
_strokeStyle = "#000";
|
|
269
307
|
_lineWidth = 1;
|
|
@@ -389,6 +427,7 @@ var RecordingCanvasContext = class {
|
|
|
389
427
|
shadowOffsetX: this._shadowOffsetX,
|
|
390
428
|
shadowOffsetY: this._shadowOffsetY
|
|
391
429
|
});
|
|
430
|
+
this.matrices.push(this.matrix);
|
|
392
431
|
this.record("save", []);
|
|
393
432
|
}
|
|
394
433
|
restore() {
|
|
@@ -408,18 +447,32 @@ var RecordingCanvasContext = class {
|
|
|
408
447
|
this._shadowOffsetX = state.shadowOffsetX;
|
|
409
448
|
this._shadowOffsetY = state.shadowOffsetY;
|
|
410
449
|
}
|
|
450
|
+
this.matrix = this.matrices.pop() ?? this.matrix;
|
|
411
451
|
this.record("restore", []);
|
|
412
452
|
}
|
|
413
453
|
translate(x, y) {
|
|
454
|
+
this.compose(1, 0, 0, 1, x, y);
|
|
414
455
|
this.record("translate", [x, y]);
|
|
415
456
|
}
|
|
416
457
|
scale(x, y) {
|
|
458
|
+
this.compose(x, 0, 0, y, 0, 0);
|
|
417
459
|
this.record("scale", [x, y]);
|
|
418
460
|
}
|
|
419
461
|
rotate(angle) {
|
|
462
|
+
const cos = Math.cos(angle);
|
|
463
|
+
const sin = Math.sin(angle);
|
|
464
|
+
this.compose(cos, sin, -sin, cos, 0, 0);
|
|
420
465
|
this.record("rotate", [angle]);
|
|
421
466
|
}
|
|
422
467
|
setTransform(a, b, c, d, e, f) {
|
|
468
|
+
this.matrix = [
|
|
469
|
+
a,
|
|
470
|
+
b,
|
|
471
|
+
c,
|
|
472
|
+
d,
|
|
473
|
+
e,
|
|
474
|
+
f
|
|
475
|
+
];
|
|
423
476
|
this.record("setTransform", [
|
|
424
477
|
a,
|
|
425
478
|
b,
|
|
@@ -518,6 +571,7 @@ var RecordingCanvasContext = class {
|
|
|
518
571
|
]);
|
|
519
572
|
}
|
|
520
573
|
transform(a, b, c, d, e, f) {
|
|
574
|
+
this.compose(a, b, c, d, e, f);
|
|
521
575
|
this.record("transform", [
|
|
522
576
|
a,
|
|
523
577
|
b,
|
|
@@ -593,10 +647,12 @@ var RecordingCanvasContext = class {
|
|
|
593
647
|
return gradient;
|
|
594
648
|
}
|
|
595
649
|
record(name, args) {
|
|
596
|
-
|
|
650
|
+
const call = {
|
|
597
651
|
name,
|
|
598
652
|
args: args.map(normalizeNumber)
|
|
599
|
-
}
|
|
653
|
+
};
|
|
654
|
+
if (this.target !== void 0) call.target = this.target;
|
|
655
|
+
this.calls.push(call);
|
|
600
656
|
}
|
|
601
657
|
};
|
|
602
658
|
/**
|
|
@@ -626,11 +682,14 @@ function savedDepth(context) {
|
|
|
626
682
|
*/
|
|
627
683
|
var FakeCanvasHost = class {
|
|
628
684
|
context;
|
|
685
|
+
label;
|
|
629
686
|
width = 0;
|
|
630
687
|
height = 0;
|
|
631
688
|
contextRequests = 0;
|
|
632
|
-
|
|
689
|
+
/** `label` names the host for a spec that meets it again as a `drawImage` source. */
|
|
690
|
+
constructor(context, label) {
|
|
633
691
|
this.context = context;
|
|
692
|
+
this.label = label;
|
|
634
693
|
}
|
|
635
694
|
getContext(_contextId) {
|
|
636
695
|
this.contextRequests++;
|
|
@@ -649,11 +708,41 @@ var RenderHarness = class {
|
|
|
649
708
|
graph = new UiGraph();
|
|
650
709
|
measurer = new CharacterCountTextMeasurer();
|
|
651
710
|
engine = new LayoutEngine(this.measurer);
|
|
652
|
-
context
|
|
653
|
-
host
|
|
654
|
-
surface
|
|
655
|
-
renderer
|
|
656
|
-
|
|
711
|
+
context;
|
|
712
|
+
host;
|
|
713
|
+
surface;
|
|
714
|
+
renderer;
|
|
715
|
+
/** The layers opacity groups were drawn in, by label; empty without `groups`. */
|
|
716
|
+
groupLayers = /* @__PURE__ */ new Map();
|
|
717
|
+
/**
|
|
718
|
+
* With `groups`, opacity groups get layers as they do in a browser:
|
|
719
|
+
* the context tracks its transform, and each layer is a recording
|
|
720
|
+
* context writing into the frame's log, its calls stamped with the
|
|
721
|
+
* layer's label (`group0`, `group1`, ...) and its host met again as
|
|
722
|
+
* the source of the `drawImage` that blends it. Text is not kept as
|
|
723
|
+
* pixels, so it is still drawn as `fillText`.
|
|
724
|
+
*/
|
|
725
|
+
constructor(logicalWidth = 800, logicalHeight = 600, dpr = 1, options = {}) {
|
|
726
|
+
const groups = options.groups === true;
|
|
727
|
+
this.context = new RecordingCanvasContext({ transform: groups });
|
|
728
|
+
this.host = new FakeCanvasHost(this.context);
|
|
729
|
+
this.surface = new CanvasSurface(this.host);
|
|
730
|
+
this.renderer = new Canvas2DRenderer(groups ? {
|
|
731
|
+
surface: this.surface,
|
|
732
|
+
textCache: false,
|
|
733
|
+
createLayerCanvas: (width, height) => {
|
|
734
|
+
const label = `group${this.groupLayers.size}`;
|
|
735
|
+
const host = new FakeCanvasHost(new RecordingCanvasContext({
|
|
736
|
+
calls: this.context.calls,
|
|
737
|
+
target: label,
|
|
738
|
+
transform: true
|
|
739
|
+
}), label);
|
|
740
|
+
host.width = width;
|
|
741
|
+
host.height = height;
|
|
742
|
+
this.groupLayers.set(label, host);
|
|
743
|
+
return host;
|
|
744
|
+
}
|
|
745
|
+
} : { surface: this.surface });
|
|
657
746
|
this.surface.setLogicalSize(logicalWidth, logicalHeight, dpr);
|
|
658
747
|
}
|
|
659
748
|
createNode(id, type) {
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","names":[],"sources":["../src/layout/LayoutTestUtils.ts","../src/input/UiInputTestUtils.ts","../src/rendering/RenderTestUtils.ts","../src/media/Mp4TestUtils.ts"],"sourcesContent":["import { UiGraph } from '../graph/UiGraph';\nimport type { UiNode } from '../graph/UiNode';\nimport { UiNodeType } from '../graph/UiNodeType';\nimport { LayoutEngine } from './LayoutEngine';\nimport { Constraints } from './LayoutTypes';\nimport type { LayoutBox, LayoutResult } from './LayoutTypes';\nimport type { LayoutRecord } from './LayoutRecord';\nimport type { TextMeasurer } from './TextMeasurer';\n\n/**\n * Shared helpers for layout specs: builds UiNode trees through\n * the real graph and drives LayoutEngine.\n */\nexport class LayoutHarness {\n readonly graph = new UiGraph();\n readonly engine: LayoutEngine;\n\n constructor(textMeasurer?: TextMeasurer) {\n this.engine = new LayoutEngine(textMeasurer);\n }\n\n createNode(id: string, type: UiNodeType): UiNode {\n return this.graph.createNode(id, type);\n }\n\n append(parent: UiNode, ...children: UiNode[]): void {\n for (const child of children) {\n this.graph.appendChild(parent, child);\n }\n }\n\n layout(node: UiNode, constraints: Constraints = Constraints.unbounded()): LayoutResult {\n return this.engine.layout(node, constraints);\n }\n\n record(node: UiNode): LayoutRecord {\n const record = this.engine.recordFor(node);\n if (record === undefined) {\n throw new Error(`No layout record for '${node.id}'.`);\n }\n return record;\n }\n\n box(node: UiNode): LayoutBox {\n const record = this.record(node);\n return { x: record.x, y: record.y, width: record.width, height: record.height };\n }\n\n boxOf(node: UiNode): LayoutBox {\n return this.engine.worldBox(node);\n }\n\n /** Where the node is seen: scroll offsets and sticky shifts applied. */\n visibleBox(node: UiNode): LayoutBox {\n return this.engine.visibleBox(node);\n }\n}\n","import { UiNodeType } from '../graph/UiNodeType';\nimport type { UiNode } from '../graph/UiNode';\nimport { Constraints } from '../layout/LayoutTypes';\nimport { scrollRange } from '../layout/Scrollbars';\nimport { LayoutHarness } from '../layout/LayoutTestUtils';\nimport { UiHitTester } from './UiHitTester';\nimport { UiInputDispatcher } from './UiInputDispatcher';\nimport { UiPointerController, type PointerControllerOptions } from './UiPointerController';\nimport { UiGestureRecognizer } from './UiGestureRecognizer';\nimport { UiTouchScroller, type TouchScrollerOptions } from './UiTouchScroller';\nimport { UiFocusManager } from './UiFocusManager';\nimport { UiKeyboardController } from './UiKeyboardController';\nimport { UiEditingController, type EditingHost } from './UiEditingController';\nimport { UiWheelController, type ScrollContainerState, type ScrollSink } from './UiWheelController';\nimport { UiPlatformAdapter, type PlatformEventTarget, type PlatformSurface } from './UiPlatformAdapter';\nimport { CharacterCountTextMeasurer, type TextMeasurer } from '../layout/TextMeasurer';\n\n/**\n * Shared harness for input specs.\n *\n * Builds real UiNode trees through UiGraph + LayoutEngine so hit\n * testing, dispatch, focus and gestures are tested against actual\n * layout geometry rather than hand-written boxes.\n */\nexport class InputTestHarness {\n readonly layout: LayoutHarness;\n readonly root: UiNode;\n readonly dispatcher = new UiInputDispatcher();\n /** Shared, so a spec can read back what a controller scrolled. */\n readonly scrollSink = new HarnessScrollSink(this);\n\n /** A measurer is needed only by specs whose trees contain real text. */\n private readonly textMeasurer: TextMeasurer | undefined;\n\n constructor(width = 400, height = 400, textMeasurer?: TextMeasurer) {\n this.textMeasurer = textMeasurer;\n this.layout = new LayoutHarness(textMeasurer);\n this.root = this.layout.createNode('app', UiNodeType.Column);\n this.root.setProperty('width', width);\n this.root.setProperty('height', height);\n }\n\n node(id: string, type: UiNodeType, props: Record<string, unknown> = {}): UiNode {\n const node = this.layout.createNode(id, type);\n for (const [key, value] of Object.entries(props)) {\n node.setProperty(key, value);\n }\n return node;\n }\n\n add(parent: UiNode, ...children: UiNode[]): void {\n this.layout.append(parent, ...children);\n }\n\n layoutTree(): void {\n this.layout.layout(this.root, Constraints.loose(400, 400));\n }\n\n createHitTester(): UiHitTester {\n return new UiHitTester(this.layout.engine, this.root);\n }\n\n createPointerController(): UiPointerController {\n return new UiPointerController(this.createHitTester(), this.dispatcher);\n }\n\n createGestureRecognizer(): UiGestureRecognizer {\n return new UiGestureRecognizer(this.dispatcher);\n }\n\n createFocusManager(): UiFocusManager {\n return new UiFocusManager(this.root, this.dispatcher);\n }\n\n createKeyboardController(): UiKeyboardController {\n return new UiKeyboardController(this.dispatcher, this.createFocusManager(), this.root);\n }\n\n /**\n * An editing controller over this harness's layout and dispatcher.\n *\n * The host is the layout harness itself: everything `EditingHost`\n * asks for is something the layout already knows, which is why the\n * controller takes an interface rather than the engine.\n */\n createEditingController(focus: UiFocusManager = this.createFocusManager()): UiEditingController {\n const layout = this.layout;\n const hitTester = this.createHitTester();\n const host: EditingHost = {\n recordFor: node => layout.engine.recordFor(node),\n visibleBox: node => layout.engine.visibleBox(node),\n screenBox: (node, part) => layout.engine.screenBox(node, part),\n toLocal: (node, x, y) => hitTester.toLocal(node, x, y),\n // The controller measures only for caret geometry. A spec whose\n // tree has real text passes its own measurer to the harness; the\n // deterministic one is right for every other.\n measurer: this.textMeasurer ?? new CharacterCountTextMeasurer(),\n markDirty: () => undefined,\n reveal: () => undefined,\n now: () => 0\n };\n return new UiEditingController(host, this.dispatcher, focus);\n }\n\n createWheelController(): UiWheelController {\n return new UiWheelController(this.createHitTester(), this.dispatcher, this.scrollSink, () => this.root);\n }\n\n /**\n * A pointer controller with a gesture recognizer behind it, for the\n * specs that need a real Pan rather than a hand-made one.\n */\n createGesturePointerController(options: PointerControllerOptions = {}): UiPointerController {\n return new UiPointerController(this.createHitTester(), this.dispatcher, {\n gestures: new UiGestureRecognizer(this.dispatcher),\n scrollSink: this.scrollSink,\n ...options\n });\n }\n\n createTouchScroller(options: TouchScrollerOptions = {}): UiTouchScroller {\n return new UiTouchScroller(this.dispatcher, this.root, this.scrollSink, options);\n }\n\n createPlatformAdapter(): UiPlatformAdapter {\n return new UiPlatformAdapter({\n pointerController: this.createPointerController(),\n wheelController: this.createWheelController(),\n keyboardController: this.createKeyboardController()\n });\n }\n\n box(node: UiNode): { x: number; y: number; width: number; height: number } {\n return this.layout.boxOf(node);\n }\n}\n\n/**\n * Minimal fake event target for testing the platform adapter.\n */\nexport class FakeEventTarget implements PlatformEventTarget {\n private readonly listeners: { type: string; listener: (event: Event) => void }[] = [];\n\n addEventListener(type: string, listener: ((event: Event) => void) | null): void {\n if (listener !== null) {\n this.listeners.push({ type, listener });\n }\n }\n\n removeEventListener(type: string, listener: ((event: Event) => void) | null): void {\n if (listener === null) return;\n const index = this.listeners.findIndex(entry => entry.type === type && entry.listener === listener);\n if (index !== -1) {\n this.listeners.splice(index, 1);\n }\n }\n\n emit(type: string, event: Event): void {\n for (const entry of this.listeners) {\n if (entry.type === type) {\n entry.listener(event);\n }\n }\n }\n}\n\n/**\n * Fake PlatformSurface for tests. Emits DOM-like events from plain\n * objects so PointerEvent/WheelEvent/KeyboardEvent constructors are\n * not required in the test environment.\n */\nexport class FakePlatformSurface implements PlatformSurface {\n readonly pointerTarget = new FakeEventTarget();\n readonly keyboardTarget = new FakeEventTarget();\n localX = 0;\n localY = 0;\n /** The last `touch-action` the adapter asked for; '' before any. */\n touchAction = '';\n\n clientToLocal(_clientX: number, _clientY: number): { x: number; y: number } {\n return { x: this.localX, y: this.localY };\n }\n\n setTouchAction(value: string): void {\n this.touchAction = value;\n }\n}\n\n/**\n * ScrollSink backed by the harness LayoutEngine. Updates the\n * container's scrollX/scrollY properties, then re-lays out so the\n * engine re-reads and clamps the offset, mirroring how the app layer\n * drives scroll through node properties.\n */\nexport class HarnessScrollSink implements ScrollSink {\n /** Every scroll asked for, in order, so a spec can read the behaviour hint. */\n readonly calls: { node: UiNode; dx: number; dy: number; behavior: string }[] = [];\n /** Containers whose scrollbars were revealed. */\n readonly revealed: UiNode[] = [];\n\n constructor(private readonly harness: InputTestHarness) {}\n\n containerState(node: UiNode): ScrollContainerState | undefined {\n const record = this.harness.layout.engine.recordFor(node);\n if (record === undefined) {\n return undefined;\n }\n const horizontal = node.getProperty('direction') === 'row';\n return {\n scrollX: record.scrollX,\n scrollY: record.scrollY,\n maxScrollX: scrollRange(record, 'x'),\n maxScrollY: scrollRange(record, 'y'),\n horizontal,\n viewportWidth: record.width,\n viewportHeight: record.height\n };\n }\n\n scrollBy(node: UiNode, dx: number, dy: number, behavior: string = 'instant'): void {\n this.calls.push({ node, dx, dy, behavior });\n const record = this.harness.layout.engine.recordFor(node);\n if (record === undefined) {\n return;\n }\n node.setProperty('scrollX', clamp(record.scrollX + dx, 0, scrollRange(record, 'x')));\n node.setProperty('scrollY', clamp(record.scrollY + dy, 0, scrollRange(record, 'y')));\n this.harness.layoutTree();\n }\n\n scrollContainers(): Iterable<UiNode> {\n return this.harness.layout.engine.scrollContainers();\n }\n\n revealScrollbars(node: UiNode): void {\n this.revealed.push(node);\n }\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n","import { UiGraph } from '../graph/UiGraph';\nimport { UiNodeType } from '../graph/UiNodeType';\nimport type { UiNode } from '../graph/UiNode';\nimport { LayoutEngine } from '../layout/LayoutEngine';\nimport { CharacterCountTextMeasurer } from '../layout/TextMeasurer';\nimport type { TextMeasurer } from '../layout/TextMeasurer';\nimport { Constraints } from '../layout/LayoutTypes';\nimport type { LayoutBox, LayoutResult } from '../layout/LayoutTypes';\nimport type { LayoutRecord } from '../layout/LayoutRecord';\nimport { Canvas2DRenderer } from './canvas2d/Canvas2DRenderer';\nimport type { Canvas2DContext, Canvas2DGradient } from './canvas2d/Canvas2DContext';\nimport { CanvasSurface } from './canvas2d/CanvasSurface';\nimport type { CanvasHost } from './canvas2d/CanvasSurface';\nimport type { PaintContext2D, PaintGradient } from './PaintTarget';\nimport type { PaintCanvasFactory } from './PaintPicture';\nimport type { PaintLineCap, PaintLineJoin } from './PaintSurface';\n\nexport interface RecordedCall {\n name: string;\n args: unknown[];\n}\n\n/**\n * The gradient a recording context hands back, carrying what it was\n * asked for so a test can read the whole paint rather than a `[object\n * CanvasGradient]`. A real one is opaque, which is exactly what makes\n * a gradient hard to assert on without this.\n */\nexport class RecordedGradient implements Canvas2DGradient {\n readonly stops: { offset: number; color: string }[] = [];\n\n constructor(\n readonly kind: 'linear' | 'radial',\n readonly args: readonly number[]\n ) {}\n\n addColorStop(offset: number, color: string): void {\n this.stops.push({ offset, color });\n }\n}\n\n/**\n * Deterministic Canvas2D spy: records every call and style\n * assignment so tests can assert the exact draw sequence.\n */\nexport class RecordingCanvasContext implements Canvas2DContext {\n readonly calls: RecordedCall[] = [];\n\n private _fillStyle: string | Canvas2DGradient | CanvasPattern = '#000';\n private _strokeStyle: string | Canvas2DGradient | CanvasPattern = '#000';\n private _lineWidth = 1;\n private _lineJoin: CanvasLineJoin = 'miter';\n private _globalAlpha = 1;\n private _font = '';\n private _textAlign: CanvasTextAlign = 'start';\n private _textBaseline: CanvasTextBaseline = 'alphabetic';\n private _shadowColor = 'rgba(0, 0, 0, 0)';\n private _shadowBlur = 0;\n private _shadowOffsetX = 0;\n private _shadowOffsetY = 0;\n /**\n * Tracking, which is a context property rather than part of the font\n * shorthand — and sticky, so a spec can check it was cleared as well\n * as that it was set.\n */\n letterSpacing = '0px';\n\n get fillStyle(): string | Canvas2DGradient | CanvasPattern {\n return this._fillStyle;\n }\n\n set fillStyle(value: string | Canvas2DGradient | CanvasPattern) {\n this._fillStyle = value;\n this.record('set:fillStyle', [value]);\n }\n\n get strokeStyle(): string | Canvas2DGradient | CanvasPattern {\n return this._strokeStyle;\n }\n\n set strokeStyle(value: string | Canvas2DGradient | CanvasPattern) {\n this._strokeStyle = value;\n this.record('set:strokeStyle', [value]);\n }\n\n get lineWidth(): number {\n return this._lineWidth;\n }\n\n set lineWidth(value: number) {\n this._lineWidth = value;\n this.record('set:lineWidth', [value]);\n }\n\n get lineJoin(): CanvasLineJoin {\n return this._lineJoin;\n }\n\n set lineJoin(value: CanvasLineJoin) {\n this._lineJoin = value;\n this.record('set:lineJoin', [value]);\n }\n\n get globalAlpha(): number {\n return this._globalAlpha;\n }\n\n set globalAlpha(value: number) {\n this._globalAlpha = value;\n this.record('set:globalAlpha', [value]);\n }\n\n get font(): string {\n return this._font;\n }\n\n set font(value: string) {\n this._font = value;\n this.record('set:font', [value]);\n }\n\n get textAlign(): CanvasTextAlign {\n return this._textAlign;\n }\n\n set textAlign(value: CanvasTextAlign) {\n this._textAlign = value;\n this.record('set:textAlign', [value]);\n }\n\n get textBaseline(): CanvasTextBaseline {\n return this._textBaseline;\n }\n\n set textBaseline(value: CanvasTextBaseline) {\n this._textBaseline = value;\n this.record('set:textBaseline', [value]);\n }\n\n get shadowColor(): string {\n return this._shadowColor;\n }\n\n set shadowColor(value: string) {\n this._shadowColor = value;\n this.record('set:shadowColor', [value]);\n }\n\n get shadowBlur(): number {\n return this._shadowBlur;\n }\n\n set shadowBlur(value: number) {\n this._shadowBlur = value;\n this.record('set:shadowBlur', [value]);\n }\n\n get shadowOffsetX(): number {\n return this._shadowOffsetX;\n }\n\n set shadowOffsetX(value: number) {\n this._shadowOffsetX = value;\n this.record('set:shadowOffsetX', [value]);\n }\n\n get shadowOffsetY(): number {\n return this._shadowOffsetY;\n }\n\n set shadowOffsetY(value: number) {\n this._shadowOffsetY = value;\n this.record('set:shadowOffsetY', [value]);\n }\n\n /**\n * Drawing state saved by `save`, as a real context keeps it. Without\n * it a spec that renders twice read the first frame's leftovers: the\n * renderer multiplies `globalAlpha` inside a `save`, and a double that\n * did not restore it compounded the opacity frame over frame.\n */\n private readonly saved: {\n fillStyle: string | Canvas2DGradient | CanvasPattern;\n strokeStyle: string | Canvas2DGradient | CanvasPattern;\n lineWidth: number;\n lineJoin: CanvasLineJoin;\n globalAlpha: number;\n font: string;\n textAlign: CanvasTextAlign;\n textBaseline: CanvasTextBaseline;\n letterSpacing: string;\n shadowColor: string;\n shadowBlur: number;\n shadowOffsetX: number;\n shadowOffsetY: number;\n }[] = [];\n\n save(): void {\n this.saved.push({\n fillStyle: this._fillStyle,\n strokeStyle: this._strokeStyle,\n lineWidth: this._lineWidth,\n lineJoin: this._lineJoin,\n globalAlpha: this._globalAlpha,\n font: this._font,\n textAlign: this._textAlign,\n textBaseline: this._textBaseline,\n letterSpacing: this.letterSpacing,\n shadowColor: this._shadowColor,\n shadowBlur: this._shadowBlur,\n shadowOffsetX: this._shadowOffsetX,\n shadowOffsetY: this._shadowOffsetY\n });\n this.record('save', []);\n }\n\n restore(): void {\n const state = this.saved.pop();\n if (state !== undefined) {\n this._fillStyle = state.fillStyle;\n this._strokeStyle = state.strokeStyle;\n this._lineWidth = state.lineWidth;\n this._lineJoin = state.lineJoin;\n this._globalAlpha = state.globalAlpha;\n this._font = state.font;\n this._textAlign = state.textAlign;\n this._textBaseline = state.textBaseline;\n this.letterSpacing = state.letterSpacing;\n this._shadowColor = state.shadowColor;\n this._shadowBlur = state.shadowBlur;\n this._shadowOffsetX = state.shadowOffsetX;\n this._shadowOffsetY = state.shadowOffsetY;\n }\n this.record('restore', []);\n }\n\n translate(x: number, y: number): void {\n this.record('translate', [x, y]);\n }\n\n scale(x: number, y: number): void {\n this.record('scale', [x, y]);\n }\n\n rotate(angle: number): void {\n this.record('rotate', [angle]);\n }\n\n setTransform(a: number, b: number, c: number, d: number, e: number, f: number): void {\n this.record('setTransform', [a, b, c, d, e, f]);\n }\n\n clearRect(x: number, y: number, width: number, height: number): void {\n this.record('clearRect', [x, y, width, height]);\n }\n\n fillRect(x: number, y: number, width: number, height: number): void {\n this.record('fillRect', [x, y, width, height]);\n }\n\n strokeRect(x: number, y: number, width: number, height: number): void {\n this.record('strokeRect', [x, y, width, height]);\n }\n\n beginPath(): void {\n this.record('beginPath', []);\n }\n\n moveTo(x: number, y: number): void {\n this.record('moveTo', [x, y]);\n }\n\n lineTo(x: number, y: number): void {\n this.record('lineTo', [x, y]);\n }\n\n arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void {\n this.record('arcTo', [x1, y1, x2, y2, radius]);\n }\n\n closePath(): void {\n this.record('closePath', []);\n }\n\n rect(x: number, y: number, width: number, height: number): void {\n this.record('rect', [x, y, width, height]);\n }\n\n clip(): void {\n this.record('clip', []);\n }\n\n fill(): void {\n this.record('fill', []);\n }\n\n stroke(): void {\n this.record('stroke', []);\n }\n\n fillText(text: string, x: number, y: number, maxWidth?: number): void {\n const args = maxWidth === undefined ? [text, x, y] : [text, x, y, maxWidth];\n this.record('fillText', args);\n }\n\n measureText(text: string): TextMetrics {\n this.record('measureText', [text]);\n return { width: text.length * 8 } as TextMetrics;\n }\n\n drawImage(image: ImageBitmap, dx: number, dy: number, dw: number, dh: number): void {\n this.record('drawImage', [image, dx, dy, dw, dh]);\n }\n\n // Path calls a painter's recording makes when it is replayed straight\n // onto the frame's context (`PaintPictureCache.draw`), rather than\n // onto a picture canvas of its own.\n transform(a: number, b: number, c: number, d: number, e: number, f: number): void {\n this.record('transform', [a, b, c, d, e, f]);\n }\n\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): void {\n this.record('quadraticCurveTo', [cx, cy, x, y]);\n }\n\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void {\n this.record('bezierCurveTo', [c1x, c1y, c2x, c2y, x, y]);\n }\n\n arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise = false): void {\n this.record('arc', [x, y, radius, startAngle, endAngle, counterclockwise]);\n }\n\n setLineDash(segments: readonly number[]): void {\n this.record('setLineDash', [segments]);\n }\n\n createLinearGradient(x0: number, y0: number, x1: number, y1: number): RecordedGradient {\n const gradient = new RecordedGradient('linear', [x0, y0, x1, y1]);\n this.record('createLinearGradient', [x0, y0, x1, y1]);\n return gradient;\n }\n\n createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): RecordedGradient {\n const gradient = new RecordedGradient('radial', [x0, y0, r0, x1, y1, r1]);\n this.record('createRadialGradient', [x0, y0, r0, x1, y1, r1]);\n return gradient;\n }\n\n private record(name: string, args: unknown[]): void {\n this.calls.push({ name, args: args.map(normalizeNumber) });\n }\n}\n\n/**\n * Normalizes -0 to 0 so scroll translations assert cleanly.\n */\nfunction normalizeNumber(value: unknown): unknown {\n if (typeof value === 'number' && Object.is(value, -0)) {\n return 0;\n }\n return value;\n}\n\nexport function callNames(context: RecordingCanvasContext): string[] {\n return context.calls.map(call => call.name);\n}\n\nexport function callsOf(context: RecordingCanvasContext, name: string): RecordedCall[] {\n return context.calls.filter(call => call.name === name);\n}\n\nexport function callArgs(context: RecordingCanvasContext, name: string): unknown[][] {\n return callsOf(context, name).map(call => (call.name.startsWith('set:') ? call.args[0] : call.args) as unknown[]);\n}\n\nexport function savedDepth(context: RecordingCanvasContext): number {\n let depth = 0;\n for (const call of context.calls) {\n if (call.name === 'save') {\n depth++;\n } else if (call.name === 'restore') {\n depth--;\n }\n }\n return depth;\n}\n\n/**\n * Deterministic `PaintContext2D` spy: the picture rasteriser's\n * equivalent of `RecordingCanvasContext`, so a spec can assert what a\n * painter actually drew without a browser.\n */\nexport class RecordingPaintContext implements PaintContext2D {\n readonly calls: RecordedCall[] = [];\n\n lineDashOffset = 0;\n lineWidth = 1;\n lineCap: PaintLineCap = 'butt';\n lineJoin: PaintLineJoin = 'miter';\n miterLimit = 10;\n globalAlpha = 1;\n filter = 'none';\n fillStyle: string | PaintGradient = '#000';\n strokeStyle: string | PaintGradient = '#000';\n font = '';\n textAlign: 'left' | 'center' | 'right' = 'left';\n textBaseline = 'alphabetic' as const;\n\n save(): void {\n this.record('save', []);\n }\n\n restore(): void {\n this.record('restore', []);\n }\n\n translate(x: number, y: number): void {\n this.record('translate', [x, y]);\n }\n\n scale(x: number, y: number): void {\n this.record('scale', [x, y]);\n }\n\n rotate(angle: number): void {\n this.record('rotate', [angle]);\n }\n\n transform(a: number, b: number, c: number, d: number, e: number, f: number): void {\n this.record('transform', [a, b, c, d, e, f]);\n }\n\n beginPath(): void {\n this.record('beginPath', []);\n }\n\n moveTo(x: number, y: number): void {\n this.record('moveTo', [x, y]);\n }\n\n lineTo(x: number, y: number): void {\n this.record('lineTo', [x, y]);\n }\n\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): void {\n this.record('quadraticCurveTo', [cx, cy, x, y]);\n }\n\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void {\n this.record('bezierCurveTo', [c1x, c1y, c2x, c2y, x, y]);\n }\n\n arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise = false): void {\n this.record('arc', [x, y, radius, startAngle, endAngle, counterclockwise]);\n }\n\n arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void {\n this.record('arcTo', [x1, y1, x2, y2, radius]);\n }\n\n rect(x: number, y: number, width: number, height: number): void {\n this.record('rect', [x, y, width, height]);\n }\n\n closePath(): void {\n this.record('closePath', []);\n }\n\n fill(fillRule?: 'nonzero' | 'evenodd'): void {\n this.record('fill', [fillRule ?? 'nonzero', this.fillStyle]);\n }\n\n stroke(): void {\n this.record('stroke', [this.strokeStyle, this.lineWidth]);\n }\n\n clip(fillRule?: 'nonzero' | 'evenodd'): void {\n this.record('clip', [fillRule ?? 'nonzero']);\n }\n\n fillText(text: string, x: number, y: number): void {\n this.record('fillText', [text, x, y, this.font, this.textAlign]);\n }\n\n drawImage(image: ImageBitmap, dx: number, dy: number, dw: number, dh: number): void {\n this.record('drawImage', [image, dx, dy, dw, dh]);\n }\n\n setLineDash(segments: readonly number[]): void {\n this.record('setLineDash', [[...segments]]);\n }\n\n createLinearGradient(x0: number, y0: number, x1: number, y1: number): RecordedGradient {\n const gradient = new RecordedGradient('linear', [x0, y0, x1, y1]);\n this.record('createLinearGradient', [x0, y0, x1, y1]);\n return gradient;\n }\n\n createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): RecordedGradient {\n const gradient = new RecordedGradient('radial', [x0, y0, r0, x1, y1, r1]);\n this.record('createRadialGradient', [x0, y0, r0, x1, y1, r1]);\n return gradient;\n }\n\n private record(name: string, args: unknown[]): void {\n this.calls.push({ name, args: args.map(normalizeNumber) });\n }\n}\n\n/**\n * A picture that never becomes real pixels.\n *\n * `take()` hands back a stand-in for the `ImageBitmap` a browser would\n * transfer out of an `OffscreenCanvas`, carrying only the size and a\n * `close`, which is all either renderer reads off one. Every context\n * the factory hands out is kept, so a spec can assert both what was\n * drawn and how many times anything was drawn at all.\n */\nexport class FakePaintCanvases {\n readonly contexts: RecordingPaintContext[] = [];\n readonly bitmaps: { width: number; height: number; closed: boolean }[] = [];\n\n readonly create: PaintCanvasFactory = (width, height) => {\n const context = new RecordingPaintContext();\n this.contexts.push(context);\n const bitmap = { width, height, closed: false };\n this.bitmaps.push(bitmap);\n return {\n context: () => context,\n take: () =>\n ({\n width,\n height,\n close: () => {\n bitmap.closed = true;\n }\n }) as unknown as ImageBitmap\n };\n };\n\n /** The calls made into the most recent picture. */\n get last(): RecordingPaintContext {\n const context = this.contexts.at(-1);\n if (context === undefined) {\n throw new Error('No picture has been rasterised.');\n }\n return context;\n }\n\n reset(): void {\n this.contexts.length = 0;\n this.bitmaps.length = 0;\n }\n}\n\n/**\n * A canvas host backed by a recording context.\n */\nexport class FakeCanvasHost implements CanvasHost {\n width = 0;\n height = 0;\n private contextRequests = 0;\n\n constructor(private readonly context: Canvas2DContext | null) {}\n\n getContext(_contextId: '2d'): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null {\n this.contextRequests++;\n return this.context as unknown as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n }\n\n get contextRequestCount(): number {\n return this.contextRequests;\n }\n}\n\n/**\n * Shared harness: a real UiGraph + LayoutEngine + Canvas2DRenderer\n * over a recording context. Deterministic layout comes from the\n * CharacterCountTextMeasurer, shared by layout and renderer.\n */\nexport class RenderHarness {\n readonly graph = new UiGraph();\n readonly measurer: TextMeasurer = new CharacterCountTextMeasurer();\n readonly engine = new LayoutEngine(this.measurer);\n readonly context = new RecordingCanvasContext();\n readonly host = new FakeCanvasHost(this.context);\n readonly surface = new CanvasSurface(this.host);\n readonly renderer = new Canvas2DRenderer({ surface: this.surface });\n\n constructor(logicalWidth: number = 800, logicalHeight: number = 600, dpr: number = 1) {\n this.surface.setLogicalSize(logicalWidth, logicalHeight, dpr);\n }\n\n createNode(id: string, type: UiNodeType): UiNode {\n return this.graph.createNode(id, type);\n }\n\n append(parent: UiNode, ...children: UiNode[]): void {\n for (const child of children) {\n this.graph.appendChild(parent, child);\n }\n }\n\n layout(node: UiNode, constraints: Constraints = Constraints.tight(800, 600)): LayoutResult {\n return this.engine.layout(node, constraints);\n }\n\n render(node: UiNode): void {\n // Far in the future: overlay scrollbars have faded, so draw-call\n // assertions see only the scene. Pass `now` yourself to test them.\n this.renderer.render(node, { layout: this.engine, text: this.measurer, now: Number.MAX_SAFE_INTEGER });\n }\n\n record(node: UiNode): LayoutRecord {\n const record = this.engine.recordFor(node);\n if (record === undefined) {\n throw new Error(`No layout record for '${node.id}'.`);\n }\n return record;\n }\n\n box(node: UiNode): LayoutBox {\n const record = this.record(node);\n return { x: record.x, y: record.y, width: record.width, height: record.height };\n }\n}\n","/**\n * A very small MP4 writer, and a decoder that decodes nothing.\n *\n * Both exist for the same reason the demuxer's spec gives for building\n * its files by hand: a fixture `.mp4` is a better test of reality and\n * a worse test of this code, because when it fails you do not know\n * which of forty boxes was misread. Building the file means a spec can\n * name the exact field it is about, and construct the awkward cases —\n * a chunk holding several samples, composition offsets reordering\n * them, a track with no `stss` — rather than hunting for a file that\n * has one.\n *\n * In `gesso-core/testing` rather than beside a spec because two specs\n * now want it: the demuxer's, which reads these files, and the\n * resolver's, which plays them.\n */\n\nfunction u32(value: number): number[] {\n return [(value >>> 24) & 0xff, (value >>> 16) & 0xff, (value >>> 8) & 0xff, value & 0xff];\n}\n\nfunction u16(value: number): number[] {\n return [(value >>> 8) & 0xff, value & 0xff];\n}\n\nfunction ascii(text: string): number[] {\n return [...text].map(character => character.charCodeAt(0));\n}\n\n/** `size type payload`, which is every box in the format. */\nexport function box(type: string, ...payload: number[][]): number[] {\n const body = payload.flat();\n return [...u32(body.length + 8), ...ascii(type), ...body];\n}\n\n/** A full box: a version and three flag bytes before the payload. */\nexport function fullBox(type: string, version: number, ...payload: number[][]): number[] {\n return box(type, [version, 0, 0, 0], ...payload);\n}\n\n/** An AAC audio track, for a file that has sound as well as pictures. */\nexport interface AudioTrackSpec {\n timescale: number;\n deltas: { count: number; delta: number }[];\n sizes: number[];\n chunkOffsets: number[];\n chunkRuns: { firstChunk: number; samplesPerChunk: number }[];\n channels: number;\n sampleRate: number;\n /**\n * The `AudioSpecificConfig`, whose top five bits are the audio\n * object type. The default is AAC-LC at 44.1kHz stereo, which is\n * `mp4a.40.2` and what nearly every file on the web carries.\n */\n config?: number[];\n}\n\nexport interface TrackSpec {\n timescale: number;\n /** One `stts` run per entry. */\n deltas: { count: number; delta: number }[];\n compositionOffsets?: { count: number; offset: number }[];\n sizes: number[];\n chunkOffsets: number[];\n chunkRuns: { firstChunk: number; samplesPerChunk: number }[];\n /** Omitted means no `stss` at all, which means every sample is a sync sample. */\n syncSamples?: number[];\n width: number;\n height: number;\n handler?: string;\n /** The sample entry's four character code. `avc1` unless said otherwise. */\n codec?: 'avc1' | 'av01' | 'vp09';\n /** The bytes of the configuration record after any fixed header; see `configurationBox`. */\n configBytes?: number[];\n}\n\n/**\n * The codec configuration box, which differs per codec and is where a\n * codec string comes from.\n */\nfunction configurationBox(spec: TrackSpec): number[] {\n if (spec.codec === 'av01') {\n // marker+version, then seq_profile/seq_level_idx, then the tier\n // and bit depth flags.\n return box('av1C', [0x81, ...(spec.configBytes ?? [0x04, 0x00])]);\n }\n if (spec.codec === 'vp09') {\n // A full box: version and flags, then profile, level and a byte\n // whose top nibble is the bit depth.\n return fullBox('vpcC', 1, spec.configBytes ?? [0x00, 0x1f, 0x80]);\n }\n // `avc1`: length, profile, compat, level, then whatever follows.\n return box('avcC', [1, 0x64, 0x00, 0x1f, 0xff, 0xe1]);\n}\n\nfunction visualSampleEntry(spec: TrackSpec): number[] {\n return box(\n spec.codec ?? 'avc1',\n [0, 0, 0, 0, 0, 0], // reserved\n u16(1), // data_reference_index\n Array.from({ length: 16 }, () => 0), // pre_defined + reserved\n u16(spec.width),\n u16(spec.height),\n u32(0x0048_0000), // horizresolution\n u32(0x0048_0000), // vertresolution\n u32(0), // reserved\n u16(1), // frame_count\n Array.from({ length: 32 }, () => 0), // compressorname\n u16(24), // depth\n [0xff, 0xff], // pre_defined = -1\n configurationBox(spec)\n );\n}\n\n/** `esds`: the descriptor tree down to the two numbers a codec string needs. */\nfunction esds(spec: AudioTrackSpec): number[] {\n const config = spec.config ?? [0x12, 0x10];\n // DecoderSpecificInfo (tag 5)\n const dsi = [0x05, config.length, ...config];\n // DecoderConfigDescriptor (tag 4): object type 0x40 is MPEG-4 audio,\n // then a stream type, a buffer size and two bitrates.\n // Thirteen bytes of header: an object type indication, a stream\n // type, three bytes of buffer size, and two four-byte bitrates.\n const dcd = [0x04, 13 + dsi.length, 0x40, 0x15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...dsi];\n // ES_Descriptor (tag 3): an id and a flags byte with nothing set.\n const esd = [0x03, 3 + dcd.length, 0, 1, 0, ...dcd];\n return fullBox('esds', 0, esd);\n}\n\nfunction audioSampleEntry(spec: AudioTrackSpec): number[] {\n return box(\n 'mp4a',\n [0, 0, 0, 0, 0, 0], // reserved\n u16(1), // data_reference_index\n u16(0), // version\n [0, 0, 0, 0, 0, 0], // revision and vendor\n u16(spec.channels),\n u16(16), // sample size\n u16(0), // pre_defined\n u16(0), // reserved\n u16(spec.sampleRate), // 16.16 fixed, whole part\n u16(0),\n esds(spec)\n );\n}\n\nfunction audioSampleTable(spec: AudioTrackSpec): number[] {\n return box(\n 'stbl',\n fullBox('stsd', 0, u32(1), audioSampleEntry(spec)),\n fullBox('stts', 0, u32(spec.deltas.length), ...spec.deltas.map(run => [...u32(run.count), ...u32(run.delta)])),\n fullBox(\n 'stsc',\n 0,\n u32(spec.chunkRuns.length),\n ...spec.chunkRuns.map(run => [...u32(run.firstChunk), ...u32(run.samplesPerChunk), ...u32(1)])\n ),\n fullBox('stsz', 0, u32(0), u32(spec.sizes.length), ...spec.sizes.map(size => u32(size))),\n fullBox('stco', 0, u32(spec.chunkOffsets.length), ...spec.chunkOffsets.map(offset => u32(offset)))\n );\n}\n\nfunction audioTrak(spec: AudioTrackSpec): number[] {\n return box(\n 'trak',\n box(\n 'mdia',\n fullBox('mdhd', 0, u32(0), u32(0), u32(spec.timescale), u32(1000)),\n fullBox(\n 'hdlr',\n 0,\n u32(0),\n ascii('soun'),\n Array.from({ length: 12 }, () => 0),\n [0]\n ),\n box('minf', audioSampleTable(spec))\n )\n );\n}\n\nfunction sampleTable(spec: TrackSpec): number[] {\n const boxes: number[][] = [\n fullBox('stsd', 0, u32(1), visualSampleEntry(spec)),\n fullBox('stts', 0, u32(spec.deltas.length), ...spec.deltas.map(run => [...u32(run.count), ...u32(run.delta)])),\n fullBox(\n 'stsc',\n 0,\n u32(spec.chunkRuns.length),\n ...spec.chunkRuns.map(run => [...u32(run.firstChunk), ...u32(run.samplesPerChunk), ...u32(1)])\n ),\n fullBox('stsz', 0, u32(0), u32(spec.sizes.length), ...spec.sizes.map(size => u32(size))),\n fullBox('stco', 0, u32(spec.chunkOffsets.length), ...spec.chunkOffsets.map(offset => u32(offset)))\n ];\n if (spec.compositionOffsets !== undefined) {\n boxes.splice(\n 2,\n 0,\n fullBox(\n 'ctts',\n 0,\n u32(spec.compositionOffsets.length),\n ...spec.compositionOffsets.map(run => [...u32(run.count), ...u32(run.offset)])\n )\n );\n }\n if (spec.syncSamples !== undefined) {\n boxes.push(fullBox('stss', 0, u32(spec.syncSamples.length), ...spec.syncSamples.map(number => u32(number))));\n }\n return box('stbl', ...boxes);\n}\n\nexport function buildMp4(spec: TrackSpec, options: { fragmented?: boolean; audio?: AudioTrackSpec } = {}): ArrayBuffer {\n const trak = box(\n 'trak',\n box(\n 'mdia',\n fullBox('mdhd', 0, u32(0), u32(0), u32(spec.timescale), u32(1000)),\n fullBox(\n 'hdlr',\n 0,\n u32(0),\n ascii(spec.handler ?? 'vide'),\n Array.from({ length: 12 }, () => 0),\n [0]\n ),\n box('minf', sampleTable(spec))\n )\n );\n const bytes = [\n ...box('ftyp', ascii('isom'), u32(512), ascii('isomiso2avc1mp41')),\n ...box(\n 'moov',\n fullBox(\n 'mvhd',\n 0,\n Array.from({ length: 100 }, () => 0)\n ),\n trak,\n ...(options.audio === undefined ? [] : [audioTrak(options.audio)])\n ),\n ...(options.fragmented === true ? box('moof', box('mfhd', u32(1))) : []),\n // A `mdat` big enough for every offset the tables name.\n ...box(\n 'mdat',\n Array.from({ length: 512 }, () => 0x41)\n )\n ];\n return new Uint8Array(bytes).buffer;\n}\n\n/** One run of samples inside a fragment. */\nexport interface FragmentSpec {\n /** Decode time the fragment starts at, in the track's timescale. Omitted means \"carry on\". */\n baseMediaDecodeTime?: number;\n samples: { duration: number; size: number; isKey: boolean }[];\n}\n\nexport interface FragmentedSpec {\n trackId: number;\n timescale: number;\n width: number;\n height: number;\n fragments: FragmentSpec[];\n /** Written into `trex`, and used by any sample whose `trun` omits the field. */\n defaultSampleDuration?: number;\n defaultSampleSize?: number;\n /** Leave a field out of the `trun` so the default has to supply it. */\n omit?: { duration?: boolean; size?: boolean };\n}\n\nfunction tkhd(trackId: number): number[] {\n return fullBox(\n 'tkhd',\n 0,\n u32(0), // creation time\n u32(0), // modification time\n u32(trackId),\n Array.from({ length: 68 }, () => 0)\n );\n}\n\n/**\n * A fragmented MP4: a `moov` that describes the track and promises\n * fragments, then the fragments.\n *\n * The `stbl` is a shell — `stsd` and four empty tables — which is what\n * a fragmenter writes and is exactly the shape that used to make this\n * demuxer return zero samples for a file the browser played.\n */\nexport function buildFragmentedMp4(spec: FragmentedSpec): ArrayBuffer {\n const shellSpec: TrackSpec = {\n timescale: spec.timescale,\n deltas: [],\n sizes: [],\n chunkOffsets: [],\n chunkRuns: [],\n width: spec.width,\n height: spec.height\n };\n const trak = box(\n 'trak',\n tkhd(spec.trackId),\n box(\n 'mdia',\n fullBox('mdhd', 0, u32(0), u32(0), u32(spec.timescale), u32(1000)),\n fullBox(\n 'hdlr',\n 0,\n u32(0),\n ascii('vide'),\n Array.from({ length: 12 }, () => 0),\n [0]\n ),\n box('minf', sampleTable(shellSpec))\n )\n );\n const mvex = box(\n 'mvex',\n fullBox(\n 'trex',\n 0,\n u32(spec.trackId),\n u32(1), // default_sample_description_index\n u32(spec.defaultSampleDuration ?? 0),\n u32(spec.defaultSampleSize ?? 0),\n u32(0) // default_sample_flags\n )\n );\n const moov = box(\n 'moov',\n fullBox(\n 'mvhd',\n 0,\n Array.from({ length: 100 }, () => 0)\n ),\n trak,\n mvex\n );\n\n const bytes = [...box('ftyp', ascii('isom'), u32(512), ascii('isomiso6avc1mp41')), ...moov];\n\n for (const fragment of spec.fragments) {\n const payloadSize = fragment.samples.reduce((total, sample) => total + sample.size, 0);\n // Built twice: the `trun`'s data offset is relative to the start\n // of the `moof` box, and is not known until the `moof` has been\n // sized. The first pass is only for its length.\n const build = (dataOffset: number): number[] => {\n const trunFlags =\n 0x000001 | // data-offset-present\n (spec.omit?.duration === true ? 0 : 0x000100) |\n (spec.omit?.size === true ? 0 : 0x000200) |\n 0x000400; // sample-flags-present\n const entries = fragment.samples.flatMap(sample => [\n ...(spec.omit?.duration === true ? [] : u32(sample.duration)),\n ...(spec.omit?.size === true ? [] : u32(sample.size)),\n // Bit 16 set means \"not a sync sample\".\n ...u32(sample.isKey ? 0 : 0x00010000)\n ]);\n const trun = box(\n 'trun',\n [0, (trunFlags >> 16) & 0xff, (trunFlags >> 8) & 0xff, trunFlags & 0xff],\n u32(fragment.samples.length),\n u32(dataOffset),\n entries\n );\n const tfhdFlags = 0x020000; // default-base-is-moof\n const traf = box(\n 'traf',\n box('tfhd', [0, (tfhdFlags >> 16) & 0xff, (tfhdFlags >> 8) & 0xff, tfhdFlags & 0xff], u32(spec.trackId)),\n ...(fragment.baseMediaDecodeTime === undefined ? [] : [fullBox('tfdt', 0, u32(fragment.baseMediaDecodeTime))]),\n trun\n );\n return box('moof', fullBox('mfhd', 0, u32(1)), traf);\n };\n const sized = build(0);\n // The `mdat` payload begins eight bytes past the end of the `moof`.\n const moof = build(sized.length + 8);\n bytes.push(\n ...moof,\n ...box(\n 'mdat',\n Array.from({ length: payloadSize }, () => 0x42)\n )\n );\n }\n return new Uint8Array(bytes).buffer;\n}\n\n/** The offset `mdat`'s payload lands at, for a table that must point into it. */\nexport function mdatStart(data: ArrayBuffer): number {\n const view = new DataView(data);\n let at = 0;\n while (at + 8 <= data.byteLength) {\n const size = view.getUint32(at);\n const type = String.fromCharCode(\n view.getUint8(at + 4),\n view.getUint8(at + 5),\n view.getUint8(at + 6),\n view.getUint8(at + 7)\n );\n if (type === 'mdat') {\n return at + 8;\n }\n at += size;\n }\n throw new Error('no mdat');\n}\n\n/** One chunk as the fake decoder saw it. */\nexport interface DecodedChunk {\n readonly timestamp: number;\n readonly type: 'key' | 'delta';\n}\n\n/**\n * A `VideoDecoder` that records what it was asked to decode and hands\n * back a frame for each.\n *\n * What the resolver's spec is about is *which samples are submitted*:\n * a seek that starts at the wrong keyframe, or one that decodes the\n * whole clip to get somewhere, is a bug in arithmetic that has nothing\n * to do with pixels. So this decodes nothing and the frames it emits\n * carry a timestamp and a `close` and no image at all.\n *\n * Emission is synchronous, which a real decoder's never is. That makes\n * the specs readable and is the one way this lies: the ordering\n * hazards a real decoder creates — a frame arriving after the position\n * has moved past it — are `Mp4Playback`'s to handle and are asserted\n * by pushing frames in by hand rather than by waiting for a thread.\n */\nexport class FakeVideoDecoder {\n static readonly submitted: DecodedChunk[] = [];\n /** How many times a decoder was configured: a seek costs one. */\n static configures = 0;\n static resets = 0;\n /** Set to stop frames being emitted, for a spec about a queue filling up. */\n static emit = true;\n\n static install(): () => void {\n const scope = globalThis as Record<string, unknown>;\n const previous = {\n VideoDecoder: scope.VideoDecoder,\n EncodedVideoChunk: scope.EncodedVideoChunk,\n VideoFrame: scope.VideoFrame,\n createImageBitmap: scope.createImageBitmap\n };\n FakeVideoDecoder.reset();\n scope.VideoDecoder = FakeVideoDecoder;\n scope.EncodedVideoChunk = class {\n readonly timestamp: number;\n readonly type: 'key' | 'delta';\n constructor(init: { timestamp: number; type: 'key' | 'delta' }) {\n this.timestamp = init.timestamp;\n this.type = init.type;\n }\n };\n scope.VideoFrame = class {};\n // Left undefined so `MutableVideoSurface` takes the path that keeps\n // the frame itself: converting to a bitmap is asynchronous and\n // would put every assertion behind a microtask for no gain.\n scope.createImageBitmap = undefined;\n return () => Object.assign(scope, previous);\n }\n\n static reset(): void {\n FakeVideoDecoder.submitted.length = 0;\n FakeVideoDecoder.configures = 0;\n FakeVideoDecoder.resets = 0;\n FakeVideoDecoder.emit = true;\n }\n\n /** Every timestamp submitted since the last configure, in order. */\n static get sinceConfigure(): number[] {\n return FakeVideoDecoder.submitted.map(chunk => chunk.timestamp);\n }\n\n static isConfigSupported(): Promise<{ supported: boolean }> {\n return Promise.resolve({ supported: true });\n }\n\n state: 'unconfigured' | 'configured' | 'closed' = 'unconfigured';\n decodeQueueSize = 0;\n private readonly output: (frame: { timestamp: number; close(): void }) => void;\n\n constructor(init: { output: (frame: { timestamp: number; close(): void }) => void; error: (e: unknown) => void }) {\n this.output = init.output;\n }\n\n configure(): void {\n this.state = 'configured';\n FakeVideoDecoder.configures++;\n }\n\n decode(chunk: DecodedChunk): void {\n FakeVideoDecoder.submitted.push({ timestamp: chunk.timestamp, type: chunk.type });\n if (!FakeVideoDecoder.emit) {\n this.decodeQueueSize++;\n return;\n }\n this.output({ timestamp: chunk.timestamp, close: () => {} });\n }\n\n reset(): void {\n FakeVideoDecoder.resets++;\n this.decodeQueueSize = 0;\n this.state = 'unconfigured';\n }\n\n close(): void {\n this.state = 'closed';\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"testing.js","names":[],"sources":["../src/layout/LayoutTestUtils.ts","../src/input/UiInputTestUtils.ts","../src/rendering/RenderTestUtils.ts","../src/media/Mp4TestUtils.ts"],"sourcesContent":["import { UiGraph } from '../graph/UiGraph';\nimport type { UiNode } from '../graph/UiNode';\nimport { UiNodeType } from '../graph/UiNodeType';\nimport { LayoutEngine } from './LayoutEngine';\nimport { Constraints } from './LayoutTypes';\nimport type { LayoutBox, LayoutResult } from './LayoutTypes';\nimport type { LayoutRecord } from './LayoutRecord';\nimport type { TextMeasurer } from './TextMeasurer';\n\n/**\n * Shared helpers for layout specs: builds UiNode trees through\n * the real graph and drives LayoutEngine.\n */\nexport class LayoutHarness {\n readonly graph = new UiGraph();\n readonly engine: LayoutEngine;\n\n constructor(textMeasurer?: TextMeasurer) {\n this.engine = new LayoutEngine(textMeasurer);\n }\n\n createNode(id: string, type: UiNodeType): UiNode {\n return this.graph.createNode(id, type);\n }\n\n append(parent: UiNode, ...children: UiNode[]): void {\n for (const child of children) {\n this.graph.appendChild(parent, child);\n }\n }\n\n layout(node: UiNode, constraints: Constraints = Constraints.unbounded()): LayoutResult {\n return this.engine.layout(node, constraints);\n }\n\n record(node: UiNode): LayoutRecord {\n const record = this.engine.recordFor(node);\n if (record === undefined) {\n throw new Error(`No layout record for '${node.id}'.`);\n }\n return record;\n }\n\n box(node: UiNode): LayoutBox {\n const record = this.record(node);\n return { x: record.x, y: record.y, width: record.width, height: record.height };\n }\n\n boxOf(node: UiNode): LayoutBox {\n return this.engine.worldBox(node);\n }\n\n /** Where the node is seen: scroll offsets and sticky shifts applied. */\n visibleBox(node: UiNode): LayoutBox {\n return this.engine.visibleBox(node);\n }\n}\n","import { UiNodeType } from '../graph/UiNodeType';\nimport type { UiNode } from '../graph/UiNode';\nimport { Constraints } from '../layout/LayoutTypes';\nimport { scrollRange } from '../layout/Scrollbars';\nimport { LayoutHarness } from '../layout/LayoutTestUtils';\nimport { UiHitTester } from './UiHitTester';\nimport { UiInputDispatcher } from './UiInputDispatcher';\nimport { UiPointerController, type PointerControllerOptions } from './UiPointerController';\nimport { UiGestureRecognizer } from './UiGestureRecognizer';\nimport { UiTouchScroller, type TouchScrollerOptions } from './UiTouchScroller';\nimport { UiFocusManager } from './UiFocusManager';\nimport { UiKeyboardController } from './UiKeyboardController';\nimport { UiEditingController, type EditingHost } from './UiEditingController';\nimport { UiWheelController, type ScrollContainerState, type ScrollSink } from './UiWheelController';\nimport { UiPlatformAdapter, type PlatformEventTarget, type PlatformSurface } from './UiPlatformAdapter';\nimport { CharacterCountTextMeasurer, type TextMeasurer } from '../layout/TextMeasurer';\n\n/**\n * Shared harness for input specs.\n *\n * Builds real UiNode trees through UiGraph + LayoutEngine so hit\n * testing, dispatch, focus and gestures are tested against actual\n * layout geometry rather than hand-written boxes.\n */\nexport class InputTestHarness {\n readonly layout: LayoutHarness;\n readonly root: UiNode;\n readonly dispatcher = new UiInputDispatcher();\n /** Shared, so a spec can read back what a controller scrolled. */\n readonly scrollSink = new HarnessScrollSink(this);\n\n /** A measurer is needed only by specs whose trees contain real text. */\n private readonly textMeasurer: TextMeasurer | undefined;\n\n constructor(width = 400, height = 400, textMeasurer?: TextMeasurer) {\n this.textMeasurer = textMeasurer;\n this.layout = new LayoutHarness(textMeasurer);\n this.root = this.layout.createNode('app', UiNodeType.Column);\n this.root.setProperty('width', width);\n this.root.setProperty('height', height);\n }\n\n node(id: string, type: UiNodeType, props: Record<string, unknown> = {}): UiNode {\n const node = this.layout.createNode(id, type);\n for (const [key, value] of Object.entries(props)) {\n node.setProperty(key, value);\n }\n return node;\n }\n\n add(parent: UiNode, ...children: UiNode[]): void {\n this.layout.append(parent, ...children);\n }\n\n layoutTree(): void {\n this.layout.layout(this.root, Constraints.loose(400, 400));\n }\n\n createHitTester(): UiHitTester {\n return new UiHitTester(this.layout.engine, this.root);\n }\n\n createPointerController(): UiPointerController {\n return new UiPointerController(this.createHitTester(), this.dispatcher);\n }\n\n createGestureRecognizer(): UiGestureRecognizer {\n return new UiGestureRecognizer(this.dispatcher);\n }\n\n createFocusManager(): UiFocusManager {\n return new UiFocusManager(this.root, this.dispatcher);\n }\n\n createKeyboardController(): UiKeyboardController {\n return new UiKeyboardController(this.dispatcher, this.createFocusManager(), this.root);\n }\n\n /**\n * An editing controller over this harness's layout and dispatcher.\n *\n * The host is the layout harness itself: everything `EditingHost`\n * asks for is something the layout already knows, which is why the\n * controller takes an interface rather than the engine.\n */\n createEditingController(focus: UiFocusManager = this.createFocusManager()): UiEditingController {\n const layout = this.layout;\n const hitTester = this.createHitTester();\n const host: EditingHost = {\n recordFor: node => layout.engine.recordFor(node),\n visibleBox: node => layout.engine.visibleBox(node),\n screenBox: (node, part) => layout.engine.screenBox(node, part),\n toLocal: (node, x, y) => hitTester.toLocal(node, x, y),\n // The controller measures only for caret geometry. A spec whose\n // tree has real text passes its own measurer to the harness; the\n // deterministic one is right for every other.\n measurer: this.textMeasurer ?? new CharacterCountTextMeasurer(),\n markDirty: () => undefined,\n reveal: () => undefined,\n now: () => 0\n };\n return new UiEditingController(host, this.dispatcher, focus);\n }\n\n createWheelController(): UiWheelController {\n return new UiWheelController(this.createHitTester(), this.dispatcher, this.scrollSink, () => this.root);\n }\n\n /**\n * A pointer controller with a gesture recognizer behind it, for the\n * specs that need a real Pan rather than a hand-made one.\n */\n createGesturePointerController(options: PointerControllerOptions = {}): UiPointerController {\n return new UiPointerController(this.createHitTester(), this.dispatcher, {\n gestures: new UiGestureRecognizer(this.dispatcher),\n scrollSink: this.scrollSink,\n ...options\n });\n }\n\n createTouchScroller(options: TouchScrollerOptions = {}): UiTouchScroller {\n return new UiTouchScroller(this.dispatcher, this.root, this.scrollSink, options);\n }\n\n createPlatformAdapter(): UiPlatformAdapter {\n return new UiPlatformAdapter({\n pointerController: this.createPointerController(),\n wheelController: this.createWheelController(),\n keyboardController: this.createKeyboardController()\n });\n }\n\n box(node: UiNode): { x: number; y: number; width: number; height: number } {\n return this.layout.boxOf(node);\n }\n}\n\n/**\n * Minimal fake event target for testing the platform adapter.\n */\nexport class FakeEventTarget implements PlatformEventTarget {\n private readonly listeners: { type: string; listener: (event: Event) => void }[] = [];\n\n addEventListener(type: string, listener: ((event: Event) => void) | null): void {\n if (listener !== null) {\n this.listeners.push({ type, listener });\n }\n }\n\n removeEventListener(type: string, listener: ((event: Event) => void) | null): void {\n if (listener === null) return;\n const index = this.listeners.findIndex(entry => entry.type === type && entry.listener === listener);\n if (index !== -1) {\n this.listeners.splice(index, 1);\n }\n }\n\n emit(type: string, event: Event): void {\n for (const entry of this.listeners) {\n if (entry.type === type) {\n entry.listener(event);\n }\n }\n }\n}\n\n/**\n * Fake PlatformSurface for tests. Emits DOM-like events from plain\n * objects so PointerEvent/WheelEvent/KeyboardEvent constructors are\n * not required in the test environment.\n */\nexport class FakePlatformSurface implements PlatformSurface {\n readonly pointerTarget = new FakeEventTarget();\n readonly keyboardTarget = new FakeEventTarget();\n localX = 0;\n localY = 0;\n /** The last `touch-action` the adapter asked for; '' before any. */\n touchAction = '';\n\n clientToLocal(_clientX: number, _clientY: number): { x: number; y: number } {\n return { x: this.localX, y: this.localY };\n }\n\n setTouchAction(value: string): void {\n this.touchAction = value;\n }\n}\n\n/**\n * ScrollSink backed by the harness LayoutEngine. Updates the\n * container's scrollX/scrollY properties, then re-lays out so the\n * engine re-reads and clamps the offset, mirroring how the app layer\n * drives scroll through node properties.\n */\nexport class HarnessScrollSink implements ScrollSink {\n /** Every scroll asked for, in order, so a spec can read the behaviour hint. */\n readonly calls: { node: UiNode; dx: number; dy: number; behavior: string }[] = [];\n /** Containers whose scrollbars were revealed. */\n readonly revealed: UiNode[] = [];\n\n constructor(private readonly harness: InputTestHarness) {}\n\n containerState(node: UiNode): ScrollContainerState | undefined {\n const record = this.harness.layout.engine.recordFor(node);\n if (record === undefined) {\n return undefined;\n }\n const horizontal = node.getProperty('direction') === 'row';\n return {\n scrollX: record.scrollX,\n scrollY: record.scrollY,\n maxScrollX: scrollRange(record, 'x'),\n maxScrollY: scrollRange(record, 'y'),\n horizontal,\n viewportWidth: record.width,\n viewportHeight: record.height\n };\n }\n\n scrollBy(node: UiNode, dx: number, dy: number, behavior: string = 'instant'): void {\n this.calls.push({ node, dx, dy, behavior });\n const record = this.harness.layout.engine.recordFor(node);\n if (record === undefined) {\n return;\n }\n node.setProperty('scrollX', clamp(record.scrollX + dx, 0, scrollRange(record, 'x')));\n node.setProperty('scrollY', clamp(record.scrollY + dy, 0, scrollRange(record, 'y')));\n this.harness.layoutTree();\n }\n\n scrollContainers(): Iterable<UiNode> {\n return this.harness.layout.engine.scrollContainers();\n }\n\n revealScrollbars(node: UiNode): void {\n this.revealed.push(node);\n }\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n","import { UiGraph } from '../graph/UiGraph';\nimport { UiNodeType } from '../graph/UiNodeType';\nimport type { UiNode } from '../graph/UiNode';\nimport { LayoutEngine } from '../layout/LayoutEngine';\nimport { CharacterCountTextMeasurer } from '../layout/TextMeasurer';\nimport type { TextMeasurer } from '../layout/TextMeasurer';\nimport { Constraints } from '../layout/LayoutTypes';\nimport type { LayoutBox, LayoutResult } from '../layout/LayoutTypes';\nimport type { LayoutRecord } from '../layout/LayoutRecord';\nimport { Canvas2DRenderer } from './canvas2d/Canvas2DRenderer';\nimport type { Canvas2DContext, Canvas2DGradient } from './canvas2d/Canvas2DContext';\nimport { CanvasSurface } from './canvas2d/CanvasSurface';\nimport type { CanvasHost } from './canvas2d/CanvasSurface';\nimport type { PaintCanvasFactory, PaintContext2D, PaintGradient } from './PaintTarget';\nimport type { PaintLineCap, PaintLineJoin } from './PaintSurface';\n\nexport interface RecordedCall {\n name: string;\n args: unknown[];\n /** Which context made the call, when several record into one log; absent for the frame's own. */\n target?: string;\n}\n\nexport interface RecordingOptions {\n /** A log to record into, shared with other contexts; a fresh one by default. */\n calls?: RecordedCall[];\n /** Stamped on every call this context records into a shared log. */\n target?: string;\n /**\n * Whether the context tracks its transform and answers `getTransform`,\n * as a real one does. Off by default, because a renderer reads the\n * absence as \"no transform worth reporting\" and most specs were\n * written against that; see `Canvas2DContext.getTransform`.\n */\n transform?: boolean;\n}\n\ntype Matrix = [number, number, number, number, number, number];\n\n/**\n * The gradient a recording context hands back, carrying what it was\n * asked for so a test can read the whole paint rather than a `[object\n * CanvasGradient]`. A real one is opaque, which is exactly what makes\n * a gradient hard to assert on without this.\n */\nexport class RecordedGradient implements Canvas2DGradient {\n readonly stops: { offset: number; color: string }[] = [];\n\n constructor(\n readonly kind: 'linear' | 'radial',\n readonly args: readonly number[]\n ) {}\n\n addColorStop(offset: number, color: string): void {\n this.stops.push({ offset, color });\n }\n}\n\n/**\n * Deterministic Canvas2D spy: records every call and style\n * assignment so tests can assert the exact draw sequence.\n */\nexport class RecordingCanvasContext implements Canvas2DContext {\n readonly calls: RecordedCall[];\n private readonly target: string | undefined;\n private matrix: Matrix = [1, 0, 0, 1, 0, 0];\n private readonly matrices: Matrix[] = [];\n getTransform?: () => { a: number; b: number; c: number; d: number; e: number; f: number };\n\n constructor(options: RecordingOptions = {}) {\n this.calls = options.calls ?? [];\n this.target = options.target;\n if (options.transform === true) {\n this.getTransform = () => {\n const [a, b, c, d, e, f] = this.matrix;\n return { a, b, c, d, e, f };\n };\n }\n }\n\n /** Multiplies the current matrix by another on the right, as a canvas does. */\n private compose(a: number, b: number, c: number, d: number, e: number, f: number): void {\n const m = this.matrix;\n this.matrix = [\n m[0] * a + m[2] * b,\n m[1] * a + m[3] * b,\n m[0] * c + m[2] * d,\n m[1] * c + m[3] * d,\n m[0] * e + m[2] * f + m[4],\n m[1] * e + m[3] * f + m[5]\n ];\n }\n\n private _fillStyle: string | Canvas2DGradient | CanvasPattern = '#000';\n private _strokeStyle: string | Canvas2DGradient | CanvasPattern = '#000';\n private _lineWidth = 1;\n private _lineJoin: CanvasLineJoin = 'miter';\n private _globalAlpha = 1;\n private _font = '';\n private _textAlign: CanvasTextAlign = 'start';\n private _textBaseline: CanvasTextBaseline = 'alphabetic';\n private _shadowColor = 'rgba(0, 0, 0, 0)';\n private _shadowBlur = 0;\n private _shadowOffsetX = 0;\n private _shadowOffsetY = 0;\n /**\n * Tracking, which is a context property rather than part of the font\n * shorthand — and sticky, so a spec can check it was cleared as well\n * as that it was set.\n */\n letterSpacing = '0px';\n\n get fillStyle(): string | Canvas2DGradient | CanvasPattern {\n return this._fillStyle;\n }\n\n set fillStyle(value: string | Canvas2DGradient | CanvasPattern) {\n this._fillStyle = value;\n this.record('set:fillStyle', [value]);\n }\n\n get strokeStyle(): string | Canvas2DGradient | CanvasPattern {\n return this._strokeStyle;\n }\n\n set strokeStyle(value: string | Canvas2DGradient | CanvasPattern) {\n this._strokeStyle = value;\n this.record('set:strokeStyle', [value]);\n }\n\n get lineWidth(): number {\n return this._lineWidth;\n }\n\n set lineWidth(value: number) {\n this._lineWidth = value;\n this.record('set:lineWidth', [value]);\n }\n\n get lineJoin(): CanvasLineJoin {\n return this._lineJoin;\n }\n\n set lineJoin(value: CanvasLineJoin) {\n this._lineJoin = value;\n this.record('set:lineJoin', [value]);\n }\n\n get globalAlpha(): number {\n return this._globalAlpha;\n }\n\n set globalAlpha(value: number) {\n this._globalAlpha = value;\n this.record('set:globalAlpha', [value]);\n }\n\n get font(): string {\n return this._font;\n }\n\n set font(value: string) {\n this._font = value;\n this.record('set:font', [value]);\n }\n\n get textAlign(): CanvasTextAlign {\n return this._textAlign;\n }\n\n set textAlign(value: CanvasTextAlign) {\n this._textAlign = value;\n this.record('set:textAlign', [value]);\n }\n\n get textBaseline(): CanvasTextBaseline {\n return this._textBaseline;\n }\n\n set textBaseline(value: CanvasTextBaseline) {\n this._textBaseline = value;\n this.record('set:textBaseline', [value]);\n }\n\n get shadowColor(): string {\n return this._shadowColor;\n }\n\n set shadowColor(value: string) {\n this._shadowColor = value;\n this.record('set:shadowColor', [value]);\n }\n\n get shadowBlur(): number {\n return this._shadowBlur;\n }\n\n set shadowBlur(value: number) {\n this._shadowBlur = value;\n this.record('set:shadowBlur', [value]);\n }\n\n get shadowOffsetX(): number {\n return this._shadowOffsetX;\n }\n\n set shadowOffsetX(value: number) {\n this._shadowOffsetX = value;\n this.record('set:shadowOffsetX', [value]);\n }\n\n get shadowOffsetY(): number {\n return this._shadowOffsetY;\n }\n\n set shadowOffsetY(value: number) {\n this._shadowOffsetY = value;\n this.record('set:shadowOffsetY', [value]);\n }\n\n /**\n * Drawing state saved by `save`, as a real context keeps it. Without\n * it a spec that renders twice read the first frame's leftovers: the\n * renderer multiplies `globalAlpha` inside a `save`, and a double that\n * did not restore it compounded the opacity frame over frame.\n */\n private readonly saved: {\n fillStyle: string | Canvas2DGradient | CanvasPattern;\n strokeStyle: string | Canvas2DGradient | CanvasPattern;\n lineWidth: number;\n lineJoin: CanvasLineJoin;\n globalAlpha: number;\n font: string;\n textAlign: CanvasTextAlign;\n textBaseline: CanvasTextBaseline;\n letterSpacing: string;\n shadowColor: string;\n shadowBlur: number;\n shadowOffsetX: number;\n shadowOffsetY: number;\n }[] = [];\n\n save(): void {\n this.saved.push({\n fillStyle: this._fillStyle,\n strokeStyle: this._strokeStyle,\n lineWidth: this._lineWidth,\n lineJoin: this._lineJoin,\n globalAlpha: this._globalAlpha,\n font: this._font,\n textAlign: this._textAlign,\n textBaseline: this._textBaseline,\n letterSpacing: this.letterSpacing,\n shadowColor: this._shadowColor,\n shadowBlur: this._shadowBlur,\n shadowOffsetX: this._shadowOffsetX,\n shadowOffsetY: this._shadowOffsetY\n });\n this.matrices.push(this.matrix);\n this.record('save', []);\n }\n\n restore(): void {\n const state = this.saved.pop();\n if (state !== undefined) {\n this._fillStyle = state.fillStyle;\n this._strokeStyle = state.strokeStyle;\n this._lineWidth = state.lineWidth;\n this._lineJoin = state.lineJoin;\n this._globalAlpha = state.globalAlpha;\n this._font = state.font;\n this._textAlign = state.textAlign;\n this._textBaseline = state.textBaseline;\n this.letterSpacing = state.letterSpacing;\n this._shadowColor = state.shadowColor;\n this._shadowBlur = state.shadowBlur;\n this._shadowOffsetX = state.shadowOffsetX;\n this._shadowOffsetY = state.shadowOffsetY;\n }\n this.matrix = this.matrices.pop() ?? this.matrix;\n this.record('restore', []);\n }\n\n translate(x: number, y: number): void {\n this.compose(1, 0, 0, 1, x, y);\n this.record('translate', [x, y]);\n }\n\n scale(x: number, y: number): void {\n this.compose(x, 0, 0, y, 0, 0);\n this.record('scale', [x, y]);\n }\n\n rotate(angle: number): void {\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n this.compose(cos, sin, -sin, cos, 0, 0);\n this.record('rotate', [angle]);\n }\n\n setTransform(a: number, b: number, c: number, d: number, e: number, f: number): void {\n this.matrix = [a, b, c, d, e, f];\n this.record('setTransform', [a, b, c, d, e, f]);\n }\n\n clearRect(x: number, y: number, width: number, height: number): void {\n this.record('clearRect', [x, y, width, height]);\n }\n\n fillRect(x: number, y: number, width: number, height: number): void {\n this.record('fillRect', [x, y, width, height]);\n }\n\n strokeRect(x: number, y: number, width: number, height: number): void {\n this.record('strokeRect', [x, y, width, height]);\n }\n\n beginPath(): void {\n this.record('beginPath', []);\n }\n\n moveTo(x: number, y: number): void {\n this.record('moveTo', [x, y]);\n }\n\n lineTo(x: number, y: number): void {\n this.record('lineTo', [x, y]);\n }\n\n arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void {\n this.record('arcTo', [x1, y1, x2, y2, radius]);\n }\n\n closePath(): void {\n this.record('closePath', []);\n }\n\n rect(x: number, y: number, width: number, height: number): void {\n this.record('rect', [x, y, width, height]);\n }\n\n clip(): void {\n this.record('clip', []);\n }\n\n fill(): void {\n this.record('fill', []);\n }\n\n stroke(): void {\n this.record('stroke', []);\n }\n\n fillText(text: string, x: number, y: number, maxWidth?: number): void {\n const args = maxWidth === undefined ? [text, x, y] : [text, x, y, maxWidth];\n this.record('fillText', args);\n }\n\n measureText(text: string): TextMetrics {\n this.record('measureText', [text]);\n return { width: text.length * 8 } as TextMetrics;\n }\n\n drawImage(image: ImageBitmap, dx: number, dy: number, dw: number, dh: number): void {\n this.record('drawImage', [image, dx, dy, dw, dh]);\n }\n\n // Path calls a painter's recording makes when it is replayed straight\n // onto the frame's context (`PaintPictureCache.draw`), rather than\n // onto a picture canvas of its own.\n transform(a: number, b: number, c: number, d: number, e: number, f: number): void {\n this.compose(a, b, c, d, e, f);\n this.record('transform', [a, b, c, d, e, f]);\n }\n\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): void {\n this.record('quadraticCurveTo', [cx, cy, x, y]);\n }\n\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void {\n this.record('bezierCurveTo', [c1x, c1y, c2x, c2y, x, y]);\n }\n\n arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise = false): void {\n this.record('arc', [x, y, radius, startAngle, endAngle, counterclockwise]);\n }\n\n setLineDash(segments: readonly number[]): void {\n this.record('setLineDash', [segments]);\n }\n\n createLinearGradient(x0: number, y0: number, x1: number, y1: number): RecordedGradient {\n const gradient = new RecordedGradient('linear', [x0, y0, x1, y1]);\n this.record('createLinearGradient', [x0, y0, x1, y1]);\n return gradient;\n }\n\n createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): RecordedGradient {\n const gradient = new RecordedGradient('radial', [x0, y0, r0, x1, y1, r1]);\n this.record('createRadialGradient', [x0, y0, r0, x1, y1, r1]);\n return gradient;\n }\n\n private record(name: string, args: unknown[]): void {\n const call: RecordedCall = { name, args: args.map(normalizeNumber) };\n if (this.target !== undefined) {\n call.target = this.target;\n }\n this.calls.push(call);\n }\n}\n\n/**\n * Normalizes -0 to 0 so scroll translations assert cleanly.\n */\nfunction normalizeNumber(value: unknown): unknown {\n if (typeof value === 'number' && Object.is(value, -0)) {\n return 0;\n }\n return value;\n}\n\nexport function callNames(context: RecordingCanvasContext): string[] {\n return context.calls.map(call => call.name);\n}\n\nexport function callsOf(context: RecordingCanvasContext, name: string): RecordedCall[] {\n return context.calls.filter(call => call.name === name);\n}\n\nexport function callArgs(context: RecordingCanvasContext, name: string): unknown[][] {\n return callsOf(context, name).map(call => (call.name.startsWith('set:') ? call.args[0] : call.args) as unknown[]);\n}\n\nexport function savedDepth(context: RecordingCanvasContext): number {\n let depth = 0;\n for (const call of context.calls) {\n if (call.name === 'save') {\n depth++;\n } else if (call.name === 'restore') {\n depth--;\n }\n }\n return depth;\n}\n\n/**\n * Deterministic `PaintContext2D` spy: the picture rasteriser's\n * equivalent of `RecordingCanvasContext`, so a spec can assert what a\n * painter actually drew without a browser.\n */\nexport class RecordingPaintContext implements PaintContext2D {\n readonly calls: RecordedCall[] = [];\n\n lineDashOffset = 0;\n lineWidth = 1;\n lineCap: PaintLineCap = 'butt';\n lineJoin: PaintLineJoin = 'miter';\n miterLimit = 10;\n globalAlpha = 1;\n filter = 'none';\n fillStyle: string | PaintGradient = '#000';\n strokeStyle: string | PaintGradient = '#000';\n font = '';\n textAlign: 'left' | 'center' | 'right' = 'left';\n textBaseline = 'alphabetic' as const;\n\n save(): void {\n this.record('save', []);\n }\n\n restore(): void {\n this.record('restore', []);\n }\n\n translate(x: number, y: number): void {\n this.record('translate', [x, y]);\n }\n\n scale(x: number, y: number): void {\n this.record('scale', [x, y]);\n }\n\n rotate(angle: number): void {\n this.record('rotate', [angle]);\n }\n\n transform(a: number, b: number, c: number, d: number, e: number, f: number): void {\n this.record('transform', [a, b, c, d, e, f]);\n }\n\n beginPath(): void {\n this.record('beginPath', []);\n }\n\n moveTo(x: number, y: number): void {\n this.record('moveTo', [x, y]);\n }\n\n lineTo(x: number, y: number): void {\n this.record('lineTo', [x, y]);\n }\n\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): void {\n this.record('quadraticCurveTo', [cx, cy, x, y]);\n }\n\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void {\n this.record('bezierCurveTo', [c1x, c1y, c2x, c2y, x, y]);\n }\n\n arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise = false): void {\n this.record('arc', [x, y, radius, startAngle, endAngle, counterclockwise]);\n }\n\n arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void {\n this.record('arcTo', [x1, y1, x2, y2, radius]);\n }\n\n rect(x: number, y: number, width: number, height: number): void {\n this.record('rect', [x, y, width, height]);\n }\n\n closePath(): void {\n this.record('closePath', []);\n }\n\n fill(fillRule?: 'nonzero' | 'evenodd'): void {\n this.record('fill', [fillRule ?? 'nonzero', this.fillStyle]);\n }\n\n stroke(): void {\n this.record('stroke', [this.strokeStyle, this.lineWidth]);\n }\n\n clip(fillRule?: 'nonzero' | 'evenodd'): void {\n this.record('clip', [fillRule ?? 'nonzero']);\n }\n\n fillText(text: string, x: number, y: number): void {\n this.record('fillText', [text, x, y, this.font, this.textAlign]);\n }\n\n drawImage(image: ImageBitmap, dx: number, dy: number, dw: number, dh: number): void {\n this.record('drawImage', [image, dx, dy, dw, dh]);\n }\n\n setLineDash(segments: readonly number[]): void {\n this.record('setLineDash', [[...segments]]);\n }\n\n createLinearGradient(x0: number, y0: number, x1: number, y1: number): RecordedGradient {\n const gradient = new RecordedGradient('linear', [x0, y0, x1, y1]);\n this.record('createLinearGradient', [x0, y0, x1, y1]);\n return gradient;\n }\n\n createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): RecordedGradient {\n const gradient = new RecordedGradient('radial', [x0, y0, r0, x1, y1, r1]);\n this.record('createRadialGradient', [x0, y0, r0, x1, y1, r1]);\n return gradient;\n }\n\n private record(name: string, args: unknown[]): void {\n this.calls.push({ name, args: args.map(normalizeNumber) });\n }\n}\n\n/**\n * A picture that never becomes real pixels.\n *\n * `take()` hands back a stand-in for the `ImageBitmap` a browser would\n * transfer out of an `OffscreenCanvas`, carrying only the size and a\n * `close`, which is all either renderer reads off one. Every context\n * the factory hands out is kept, so a spec can assert both what was\n * drawn and how many times anything was drawn at all.\n */\nexport class FakePaintCanvases {\n readonly contexts: RecordingPaintContext[] = [];\n readonly bitmaps: { width: number; height: number; closed: boolean }[] = [];\n\n readonly create: PaintCanvasFactory = (width, height) => {\n const context = new RecordingPaintContext();\n this.contexts.push(context);\n const bitmap = { width, height, closed: false };\n this.bitmaps.push(bitmap);\n return {\n context: () => context,\n take: () =>\n ({\n width,\n height,\n close: () => {\n bitmap.closed = true;\n }\n }) as unknown as ImageBitmap\n };\n };\n\n /** The calls made into the most recent picture. */\n get last(): RecordingPaintContext {\n const context = this.contexts.at(-1);\n if (context === undefined) {\n throw new Error('No picture has been rasterised.');\n }\n return context;\n }\n\n reset(): void {\n this.contexts.length = 0;\n this.bitmaps.length = 0;\n }\n}\n\n/**\n * A canvas host backed by a recording context.\n */\nexport class FakeCanvasHost implements CanvasHost {\n width = 0;\n height = 0;\n private contextRequests = 0;\n\n /** `label` names the host for a spec that meets it again as a `drawImage` source. */\n constructor(\n private readonly context: Canvas2DContext | null,\n readonly label?: string\n ) {}\n\n getContext(_contextId: '2d'): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null {\n this.contextRequests++;\n return this.context as unknown as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n }\n\n get contextRequestCount(): number {\n return this.contextRequests;\n }\n}\n\n/**\n * Shared harness: a real UiGraph + LayoutEngine + Canvas2DRenderer\n * over a recording context. Deterministic layout comes from the\n * CharacterCountTextMeasurer, shared by layout and renderer.\n */\nexport class RenderHarness {\n readonly graph = new UiGraph();\n readonly measurer: TextMeasurer = new CharacterCountTextMeasurer();\n readonly engine = new LayoutEngine(this.measurer);\n readonly context: RecordingCanvasContext;\n readonly host: FakeCanvasHost;\n readonly surface: CanvasSurface;\n readonly renderer: Canvas2DRenderer;\n /** The layers opacity groups were drawn in, by label; empty without `groups`. */\n readonly groupLayers = new Map<string, FakeCanvasHost>();\n\n /**\n * With `groups`, opacity groups get layers as they do in a browser:\n * the context tracks its transform, and each layer is a recording\n * context writing into the frame's log, its calls stamped with the\n * layer's label (`group0`, `group1`, ...) and its host met again as\n * the source of the `drawImage` that blends it. Text is not kept as\n * pixels, so it is still drawn as `fillText`.\n */\n constructor(\n logicalWidth: number = 800,\n logicalHeight: number = 600,\n dpr: number = 1,\n options: { groups?: boolean } = {}\n ) {\n const groups = options.groups === true;\n this.context = new RecordingCanvasContext({ transform: groups });\n this.host = new FakeCanvasHost(this.context);\n this.surface = new CanvasSurface(this.host);\n this.renderer = new Canvas2DRenderer(\n groups\n ? {\n surface: this.surface,\n textCache: false,\n createLayerCanvas: (width, height) => {\n const label = `group${this.groupLayers.size}`;\n const context = new RecordingCanvasContext({ calls: this.context.calls, target: label, transform: true });\n const host = new FakeCanvasHost(context, label);\n host.width = width;\n host.height = height;\n this.groupLayers.set(label, host);\n return host;\n }\n }\n : { surface: this.surface }\n );\n this.surface.setLogicalSize(logicalWidth, logicalHeight, dpr);\n }\n\n createNode(id: string, type: UiNodeType): UiNode {\n return this.graph.createNode(id, type);\n }\n\n append(parent: UiNode, ...children: UiNode[]): void {\n for (const child of children) {\n this.graph.appendChild(parent, child);\n }\n }\n\n layout(node: UiNode, constraints: Constraints = Constraints.tight(800, 600)): LayoutResult {\n return this.engine.layout(node, constraints);\n }\n\n render(node: UiNode): void {\n // Far in the future: overlay scrollbars have faded, so draw-call\n // assertions see only the scene. Pass `now` yourself to test them.\n this.renderer.render(node, { layout: this.engine, text: this.measurer, now: Number.MAX_SAFE_INTEGER });\n }\n\n record(node: UiNode): LayoutRecord {\n const record = this.engine.recordFor(node);\n if (record === undefined) {\n throw new Error(`No layout record for '${node.id}'.`);\n }\n return record;\n }\n\n box(node: UiNode): LayoutBox {\n const record = this.record(node);\n return { x: record.x, y: record.y, width: record.width, height: record.height };\n }\n}\n","/**\n * A very small MP4 writer, and a decoder that decodes nothing.\n *\n * Both exist for the same reason the demuxer's spec gives for building\n * its files by hand: a fixture `.mp4` is a better test of reality and\n * a worse test of this code, because when it fails you do not know\n * which of forty boxes was misread. Building the file means a spec can\n * name the exact field it is about, and construct the awkward cases —\n * a chunk holding several samples, composition offsets reordering\n * them, a track with no `stss` — rather than hunting for a file that\n * has one.\n *\n * In `gesso-core/testing` rather than beside a spec because two specs\n * now want it: the demuxer's, which reads these files, and the\n * resolver's, which plays them.\n */\n\nfunction u32(value: number): number[] {\n return [(value >>> 24) & 0xff, (value >>> 16) & 0xff, (value >>> 8) & 0xff, value & 0xff];\n}\n\nfunction u16(value: number): number[] {\n return [(value >>> 8) & 0xff, value & 0xff];\n}\n\nfunction ascii(text: string): number[] {\n return [...text].map(character => character.charCodeAt(0));\n}\n\n/** `size type payload`, which is every box in the format. */\nexport function box(type: string, ...payload: number[][]): number[] {\n const body = payload.flat();\n return [...u32(body.length + 8), ...ascii(type), ...body];\n}\n\n/** A full box: a version and three flag bytes before the payload. */\nexport function fullBox(type: string, version: number, ...payload: number[][]): number[] {\n return box(type, [version, 0, 0, 0], ...payload);\n}\n\n/** An AAC audio track, for a file that has sound as well as pictures. */\nexport interface AudioTrackSpec {\n timescale: number;\n deltas: { count: number; delta: number }[];\n sizes: number[];\n chunkOffsets: number[];\n chunkRuns: { firstChunk: number; samplesPerChunk: number }[];\n channels: number;\n sampleRate: number;\n /**\n * The `AudioSpecificConfig`, whose top five bits are the audio\n * object type. The default is AAC-LC at 44.1kHz stereo, which is\n * `mp4a.40.2` and what nearly every file on the web carries.\n */\n config?: number[];\n}\n\nexport interface TrackSpec {\n timescale: number;\n /** One `stts` run per entry. */\n deltas: { count: number; delta: number }[];\n compositionOffsets?: { count: number; offset: number }[];\n sizes: number[];\n chunkOffsets: number[];\n chunkRuns: { firstChunk: number; samplesPerChunk: number }[];\n /** Omitted means no `stss` at all, which means every sample is a sync sample. */\n syncSamples?: number[];\n width: number;\n height: number;\n handler?: string;\n /** The sample entry's four character code. `avc1` unless said otherwise. */\n codec?: 'avc1' | 'av01' | 'vp09';\n /** The bytes of the configuration record after any fixed header; see `configurationBox`. */\n configBytes?: number[];\n}\n\n/**\n * The codec configuration box, which differs per codec and is where a\n * codec string comes from.\n */\nfunction configurationBox(spec: TrackSpec): number[] {\n if (spec.codec === 'av01') {\n // marker+version, then seq_profile/seq_level_idx, then the tier\n // and bit depth flags.\n return box('av1C', [0x81, ...(spec.configBytes ?? [0x04, 0x00])]);\n }\n if (spec.codec === 'vp09') {\n // A full box: version and flags, then profile, level and a byte\n // whose top nibble is the bit depth.\n return fullBox('vpcC', 1, spec.configBytes ?? [0x00, 0x1f, 0x80]);\n }\n // `avc1`: length, profile, compat, level, then whatever follows.\n return box('avcC', [1, 0x64, 0x00, 0x1f, 0xff, 0xe1]);\n}\n\nfunction visualSampleEntry(spec: TrackSpec): number[] {\n return box(\n spec.codec ?? 'avc1',\n [0, 0, 0, 0, 0, 0], // reserved\n u16(1), // data_reference_index\n Array.from({ length: 16 }, () => 0), // pre_defined + reserved\n u16(spec.width),\n u16(spec.height),\n u32(0x0048_0000), // horizresolution\n u32(0x0048_0000), // vertresolution\n u32(0), // reserved\n u16(1), // frame_count\n Array.from({ length: 32 }, () => 0), // compressorname\n u16(24), // depth\n [0xff, 0xff], // pre_defined = -1\n configurationBox(spec)\n );\n}\n\n/** `esds`: the descriptor tree down to the two numbers a codec string needs. */\nfunction esds(spec: AudioTrackSpec): number[] {\n const config = spec.config ?? [0x12, 0x10];\n // DecoderSpecificInfo (tag 5)\n const dsi = [0x05, config.length, ...config];\n // DecoderConfigDescriptor (tag 4): object type 0x40 is MPEG-4 audio,\n // then a stream type, a buffer size and two bitrates.\n // Thirteen bytes of header: an object type indication, a stream\n // type, three bytes of buffer size, and two four-byte bitrates.\n const dcd = [0x04, 13 + dsi.length, 0x40, 0x15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...dsi];\n // ES_Descriptor (tag 3): an id and a flags byte with nothing set.\n const esd = [0x03, 3 + dcd.length, 0, 1, 0, ...dcd];\n return fullBox('esds', 0, esd);\n}\n\nfunction audioSampleEntry(spec: AudioTrackSpec): number[] {\n return box(\n 'mp4a',\n [0, 0, 0, 0, 0, 0], // reserved\n u16(1), // data_reference_index\n u16(0), // version\n [0, 0, 0, 0, 0, 0], // revision and vendor\n u16(spec.channels),\n u16(16), // sample size\n u16(0), // pre_defined\n u16(0), // reserved\n u16(spec.sampleRate), // 16.16 fixed, whole part\n u16(0),\n esds(spec)\n );\n}\n\nfunction audioSampleTable(spec: AudioTrackSpec): number[] {\n return box(\n 'stbl',\n fullBox('stsd', 0, u32(1), audioSampleEntry(spec)),\n fullBox('stts', 0, u32(spec.deltas.length), ...spec.deltas.map(run => [...u32(run.count), ...u32(run.delta)])),\n fullBox(\n 'stsc',\n 0,\n u32(spec.chunkRuns.length),\n ...spec.chunkRuns.map(run => [...u32(run.firstChunk), ...u32(run.samplesPerChunk), ...u32(1)])\n ),\n fullBox('stsz', 0, u32(0), u32(spec.sizes.length), ...spec.sizes.map(size => u32(size))),\n fullBox('stco', 0, u32(spec.chunkOffsets.length), ...spec.chunkOffsets.map(offset => u32(offset)))\n );\n}\n\nfunction audioTrak(spec: AudioTrackSpec): number[] {\n return box(\n 'trak',\n box(\n 'mdia',\n fullBox('mdhd', 0, u32(0), u32(0), u32(spec.timescale), u32(1000)),\n fullBox(\n 'hdlr',\n 0,\n u32(0),\n ascii('soun'),\n Array.from({ length: 12 }, () => 0),\n [0]\n ),\n box('minf', audioSampleTable(spec))\n )\n );\n}\n\nfunction sampleTable(spec: TrackSpec): number[] {\n const boxes: number[][] = [\n fullBox('stsd', 0, u32(1), visualSampleEntry(spec)),\n fullBox('stts', 0, u32(spec.deltas.length), ...spec.deltas.map(run => [...u32(run.count), ...u32(run.delta)])),\n fullBox(\n 'stsc',\n 0,\n u32(spec.chunkRuns.length),\n ...spec.chunkRuns.map(run => [...u32(run.firstChunk), ...u32(run.samplesPerChunk), ...u32(1)])\n ),\n fullBox('stsz', 0, u32(0), u32(spec.sizes.length), ...spec.sizes.map(size => u32(size))),\n fullBox('stco', 0, u32(spec.chunkOffsets.length), ...spec.chunkOffsets.map(offset => u32(offset)))\n ];\n if (spec.compositionOffsets !== undefined) {\n boxes.splice(\n 2,\n 0,\n fullBox(\n 'ctts',\n 0,\n u32(spec.compositionOffsets.length),\n ...spec.compositionOffsets.map(run => [...u32(run.count), ...u32(run.offset)])\n )\n );\n }\n if (spec.syncSamples !== undefined) {\n boxes.push(fullBox('stss', 0, u32(spec.syncSamples.length), ...spec.syncSamples.map(number => u32(number))));\n }\n return box('stbl', ...boxes);\n}\n\nexport function buildMp4(spec: TrackSpec, options: { fragmented?: boolean; audio?: AudioTrackSpec } = {}): ArrayBuffer {\n const trak = box(\n 'trak',\n box(\n 'mdia',\n fullBox('mdhd', 0, u32(0), u32(0), u32(spec.timescale), u32(1000)),\n fullBox(\n 'hdlr',\n 0,\n u32(0),\n ascii(spec.handler ?? 'vide'),\n Array.from({ length: 12 }, () => 0),\n [0]\n ),\n box('minf', sampleTable(spec))\n )\n );\n const bytes = [\n ...box('ftyp', ascii('isom'), u32(512), ascii('isomiso2avc1mp41')),\n ...box(\n 'moov',\n fullBox(\n 'mvhd',\n 0,\n Array.from({ length: 100 }, () => 0)\n ),\n trak,\n ...(options.audio === undefined ? [] : [audioTrak(options.audio)])\n ),\n ...(options.fragmented === true ? box('moof', box('mfhd', u32(1))) : []),\n // A `mdat` big enough for every offset the tables name.\n ...box(\n 'mdat',\n Array.from({ length: 512 }, () => 0x41)\n )\n ];\n return new Uint8Array(bytes).buffer;\n}\n\n/** One run of samples inside a fragment. */\nexport interface FragmentSpec {\n /** Decode time the fragment starts at, in the track's timescale. Omitted means \"carry on\". */\n baseMediaDecodeTime?: number;\n samples: { duration: number; size: number; isKey: boolean }[];\n}\n\nexport interface FragmentedSpec {\n trackId: number;\n timescale: number;\n width: number;\n height: number;\n fragments: FragmentSpec[];\n /** Written into `trex`, and used by any sample whose `trun` omits the field. */\n defaultSampleDuration?: number;\n defaultSampleSize?: number;\n /** Leave a field out of the `trun` so the default has to supply it. */\n omit?: { duration?: boolean; size?: boolean };\n}\n\nfunction tkhd(trackId: number): number[] {\n return fullBox(\n 'tkhd',\n 0,\n u32(0), // creation time\n u32(0), // modification time\n u32(trackId),\n Array.from({ length: 68 }, () => 0)\n );\n}\n\n/**\n * A fragmented MP4: a `moov` that describes the track and promises\n * fragments, then the fragments.\n *\n * The `stbl` is a shell — `stsd` and four empty tables — which is what\n * a fragmenter writes and is exactly the shape that used to make this\n * demuxer return zero samples for a file the browser played.\n */\nexport function buildFragmentedMp4(spec: FragmentedSpec): ArrayBuffer {\n const shellSpec: TrackSpec = {\n timescale: spec.timescale,\n deltas: [],\n sizes: [],\n chunkOffsets: [],\n chunkRuns: [],\n width: spec.width,\n height: spec.height\n };\n const trak = box(\n 'trak',\n tkhd(spec.trackId),\n box(\n 'mdia',\n fullBox('mdhd', 0, u32(0), u32(0), u32(spec.timescale), u32(1000)),\n fullBox(\n 'hdlr',\n 0,\n u32(0),\n ascii('vide'),\n Array.from({ length: 12 }, () => 0),\n [0]\n ),\n box('minf', sampleTable(shellSpec))\n )\n );\n const mvex = box(\n 'mvex',\n fullBox(\n 'trex',\n 0,\n u32(spec.trackId),\n u32(1), // default_sample_description_index\n u32(spec.defaultSampleDuration ?? 0),\n u32(spec.defaultSampleSize ?? 0),\n u32(0) // default_sample_flags\n )\n );\n const moov = box(\n 'moov',\n fullBox(\n 'mvhd',\n 0,\n Array.from({ length: 100 }, () => 0)\n ),\n trak,\n mvex\n );\n\n const bytes = [...box('ftyp', ascii('isom'), u32(512), ascii('isomiso6avc1mp41')), ...moov];\n\n for (const fragment of spec.fragments) {\n const payloadSize = fragment.samples.reduce((total, sample) => total + sample.size, 0);\n // Built twice: the `trun`'s data offset is relative to the start\n // of the `moof` box, and is not known until the `moof` has been\n // sized. The first pass is only for its length.\n const build = (dataOffset: number): number[] => {\n const trunFlags =\n 0x000001 | // data-offset-present\n (spec.omit?.duration === true ? 0 : 0x000100) |\n (spec.omit?.size === true ? 0 : 0x000200) |\n 0x000400; // sample-flags-present\n const entries = fragment.samples.flatMap(sample => [\n ...(spec.omit?.duration === true ? [] : u32(sample.duration)),\n ...(spec.omit?.size === true ? [] : u32(sample.size)),\n // Bit 16 set means \"not a sync sample\".\n ...u32(sample.isKey ? 0 : 0x00010000)\n ]);\n const trun = box(\n 'trun',\n [0, (trunFlags >> 16) & 0xff, (trunFlags >> 8) & 0xff, trunFlags & 0xff],\n u32(fragment.samples.length),\n u32(dataOffset),\n entries\n );\n const tfhdFlags = 0x020000; // default-base-is-moof\n const traf = box(\n 'traf',\n box('tfhd', [0, (tfhdFlags >> 16) & 0xff, (tfhdFlags >> 8) & 0xff, tfhdFlags & 0xff], u32(spec.trackId)),\n ...(fragment.baseMediaDecodeTime === undefined ? [] : [fullBox('tfdt', 0, u32(fragment.baseMediaDecodeTime))]),\n trun\n );\n return box('moof', fullBox('mfhd', 0, u32(1)), traf);\n };\n const sized = build(0);\n // The `mdat` payload begins eight bytes past the end of the `moof`.\n const moof = build(sized.length + 8);\n bytes.push(\n ...moof,\n ...box(\n 'mdat',\n Array.from({ length: payloadSize }, () => 0x42)\n )\n );\n }\n return new Uint8Array(bytes).buffer;\n}\n\n/** The offset `mdat`'s payload lands at, for a table that must point into it. */\nexport function mdatStart(data: ArrayBuffer): number {\n const view = new DataView(data);\n let at = 0;\n while (at + 8 <= data.byteLength) {\n const size = view.getUint32(at);\n const type = String.fromCharCode(\n view.getUint8(at + 4),\n view.getUint8(at + 5),\n view.getUint8(at + 6),\n view.getUint8(at + 7)\n );\n if (type === 'mdat') {\n return at + 8;\n }\n at += size;\n }\n throw new Error('no mdat');\n}\n\n/** One chunk as the fake decoder saw it. */\nexport interface DecodedChunk {\n readonly timestamp: number;\n readonly type: 'key' | 'delta';\n}\n\n/**\n * A `VideoDecoder` that records what it was asked to decode and hands\n * back a frame for each.\n *\n * What the resolver's spec is about is *which samples are submitted*:\n * a seek that starts at the wrong keyframe, or one that decodes the\n * whole clip to get somewhere, is a bug in arithmetic that has nothing\n * to do with pixels. So this decodes nothing and the frames it emits\n * carry a timestamp and a `close` and no image at all.\n *\n * Emission is synchronous, which a real decoder's never is. That makes\n * the specs readable and is the one way this lies: the ordering\n * hazards a real decoder creates — a frame arriving after the position\n * has moved past it — are `Mp4Playback`'s to handle and are asserted\n * by pushing frames in by hand rather than by waiting for a thread.\n */\nexport class FakeVideoDecoder {\n static readonly submitted: DecodedChunk[] = [];\n /** How many times a decoder was configured: a seek costs one. */\n static configures = 0;\n static resets = 0;\n /** Set to stop frames being emitted, for a spec about a queue filling up. */\n static emit = true;\n\n static install(): () => void {\n const scope = globalThis as Record<string, unknown>;\n const previous = {\n VideoDecoder: scope.VideoDecoder,\n EncodedVideoChunk: scope.EncodedVideoChunk,\n VideoFrame: scope.VideoFrame,\n createImageBitmap: scope.createImageBitmap\n };\n FakeVideoDecoder.reset();\n scope.VideoDecoder = FakeVideoDecoder;\n scope.EncodedVideoChunk = class {\n readonly timestamp: number;\n readonly type: 'key' | 'delta';\n constructor(init: { timestamp: number; type: 'key' | 'delta' }) {\n this.timestamp = init.timestamp;\n this.type = init.type;\n }\n };\n scope.VideoFrame = class {};\n // Left undefined so `MutableVideoSurface` takes the path that keeps\n // the frame itself: converting to a bitmap is asynchronous and\n // would put every assertion behind a microtask for no gain.\n scope.createImageBitmap = undefined;\n return () => Object.assign(scope, previous);\n }\n\n static reset(): void {\n FakeVideoDecoder.submitted.length = 0;\n FakeVideoDecoder.configures = 0;\n FakeVideoDecoder.resets = 0;\n FakeVideoDecoder.emit = true;\n }\n\n /** Every timestamp submitted since the last configure, in order. */\n static get sinceConfigure(): number[] {\n return FakeVideoDecoder.submitted.map(chunk => chunk.timestamp);\n }\n\n static isConfigSupported(): Promise<{ supported: boolean }> {\n return Promise.resolve({ supported: true });\n }\n\n state: 'unconfigured' | 'configured' | 'closed' = 'unconfigured';\n decodeQueueSize = 0;\n private readonly output: (frame: { timestamp: number; close(): void }) => void;\n\n constructor(init: { output: (frame: { timestamp: number; close(): void }) => void; error: (e: unknown) => void }) {\n this.output = init.output;\n }\n\n configure(): void {\n this.state = 'configured';\n FakeVideoDecoder.configures++;\n }\n\n decode(chunk: DecodedChunk): void {\n FakeVideoDecoder.submitted.push({ timestamp: chunk.timestamp, type: chunk.type });\n if (!FakeVideoDecoder.emit) {\n this.decodeQueueSize++;\n return;\n }\n this.output({ timestamp: chunk.timestamp, close: () => {} });\n }\n\n reset(): void {\n FakeVideoDecoder.resets++;\n this.decodeQueueSize = 0;\n this.state = 'unconfigured';\n }\n\n close(): void {\n this.state = 'closed';\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED