@flighthq/shape 0.2.1-next.701.409c279 → 0.2.1-next.738.07b221d

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/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from './scale9Shape';
2
2
  export * from './shape';
3
3
  export * from './shapeCommands';
4
4
  export * from './shapeFill';
5
+ export * from './shapeStroke';
5
6
  export * from './shapeHitTestBuiltins';
6
7
  export * from './shapeHitTestRegistry';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ export * from './scale9Shape';
2
2
  export * from './shape';
3
3
  export * from './shapeCommands';
4
4
  export * from './shapeFill';
5
+ export * from './shapeStroke';
5
6
  export * from './shapeHitTestBuiltins';
6
7
  export * from './shapeHitTestRegistry';
7
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC"}
@@ -1,4 +1,7 @@
1
- import type { ShapeCommandToken, ShapeFillRegion } from '@flighthq/types';
1
+ import type { Path, ShapeCommandToken, ShapeFillRegion } from '@flighthq/types';
2
+ export declare function appendShapeGeometryCommand(path: Path, name: string, commands: readonly ShapeCommandToken[], a: number): void;
3
+ export declare function getPathCommandOperandCount(verb: number): number;
2
4
  export declare function getShapeFillRegions(commands: readonly ShapeCommandToken[]): ShapeFillRegion[] | null;
3
5
  export declare function hasNonSolidShapeFill(commands: readonly ShapeCommandToken[]): boolean;
6
+ export declare function hasShapeFill(commands: readonly ShapeCommandToken[]): boolean;
4
7
  //# sourceMappingURL=shapeFill.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shapeFill.d.ts","sourceRoot":"","sources":["../src/shapeFill.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAW7F,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,eAAe,EAAE,GAAG,IAAI,CA6HpG;AAGD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAoBpF"}
1
+ {"version":3,"file":"shapeFill.d.ts","sourceRoot":"","sources":["../src/shapeFill.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAe,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAQ7F,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,CAAC,EAAE,MAAM,GACR,IAAI,CAsEN;AAMD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc/D;AAUD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,eAAe,EAAE,GAAG,IAAI,CAuCpG;AAGD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAoBpF;AAKD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAQ5E"}
package/dist/shapeFill.js CHANGED
@@ -1,4 +1,65 @@
1
1
  import { PathCommand } from '@flighthq/types';
2
+ // Appends one shape geometry command (moveTo/lineTo/curveTo/cubicCurveTo and the drawCircle/Ellipse/
3
+ // Rectangle/RoundRectangle/Path primitives) onto `path`, expanding primitives into MOVE/LINE/CURVE
4
+ // verbs (curves kept for the renderer to flatten). Shared by the fill-region and stroke-region walkers
5
+ // so both expand geometry identically. Non-geometry command names are ignored (a no-op). `a` is the
6
+ // index of the command's first argument in `commands`.
7
+ export function appendShapeGeometryCommand(path, name, commands, a) {
8
+ switch (name) {
9
+ case 'moveTo':
10
+ pushVerb(path, PathCommand.MOVE_TO, commands[a], commands[a + 1]);
11
+ break;
12
+ case 'lineTo':
13
+ pushVerb(path, PathCommand.LINE_TO, commands[a], commands[a + 1]);
14
+ break;
15
+ case 'curveTo':
16
+ pushQuadratic(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 3]);
17
+ break;
18
+ case 'cubicCurveTo':
19
+ pushCubic(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 3], commands[a + 4], commands[a + 5]);
20
+ break;
21
+ case 'drawCircle':
22
+ appendEllipseToPath(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 2]);
23
+ break;
24
+ case 'drawEllipse': {
25
+ const w = commands[a + 2];
26
+ const h = commands[a + 3];
27
+ appendEllipseToPath(path, commands[a] + w / 2, commands[a + 1] + h / 2, w / 2, h / 2);
28
+ break;
29
+ }
30
+ case 'drawRectangle':
31
+ appendRectangleToPath(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 3]);
32
+ break;
33
+ case 'drawRoundRectangle':
34
+ appendRoundRectangleToPath(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 3], commands[a + 4] / 2, commands[a + 5] / 2);
35
+ break;
36
+ case 'drawPath':
37
+ path.winding = commands[a + 2];
38
+ appendRawPath(path, commands[a], commands[a + 1]);
39
+ break;
40
+ default:
41
+ break;
42
+ }
43
+ }
44
+ // The number of `data` numbers a PathCommand verb consumes: MOVE_TO/LINE_TO = 2, CURVE_TO (quadratic)
45
+ // and WIDE_MOVE_TO/WIDE_LINE_TO = 4, CUBIC_CURVE_TO = 6, CLOSE/NO_OP = 0. The one place that maps a raw
46
+ // Path verb to its operand width, so a verb/data stream (appendRawPath) and a closure scan
47
+ // (shapeStroke) walk it without desynchronizing the data cursor.
48
+ export function getPathCommandOperandCount(verb) {
49
+ switch (verb) {
50
+ case PathCommand.MOVE_TO:
51
+ case PathCommand.LINE_TO:
52
+ return 2;
53
+ case PathCommand.CURVE_TO:
54
+ case PathCommand.WIDE_MOVE_TO:
55
+ case PathCommand.WIDE_LINE_TO:
56
+ return 4;
57
+ case PathCommand.CUBIC_CURVE_TO:
58
+ return 6;
59
+ default: // CLOSE, NO_OP
60
+ return 0;
61
+ }
62
+ }
2
63
  // Resolves a Shape's drawing-command stream into solid-fill regions for the GPU fill path: each
3
64
  // `beginFill … endFill` (or the next fill) span becomes one `ShapeFillRegion` whose `path` carries the
4
65
  // geometry (primitives expanded to MOVE/LINE/CURVE verbs, curves kept for the renderer to flatten).
@@ -14,9 +75,7 @@ export function getShapeFillRegions(commands) {
14
75
  let path = null;
15
76
  let color = 0;
16
77
  let alpha = 1;
17
- let winding = 'nonZero';
18
- let startX = 0;
19
- let startY = 0;
78
+ const winding = 'nonZero';
20
79
  let i = 0;
21
80
  while (i < commands.length) {
22
81
  const name = commands[i];
@@ -29,7 +88,6 @@ export function getShapeFillRegions(commands) {
29
88
  regions.push({ path, color, alpha });
30
89
  color = commands[a];
31
90
  alpha = commands[a + 1];
32
- winding = 'nonZero';
33
91
  path = { commands: [], data: [], winding };
34
92
  break;
35
93
  }
@@ -39,68 +97,11 @@ export function getShapeFillRegions(commands) {
39
97
  path = null;
40
98
  break;
41
99
  }
42
- case 'moveTo': {
43
- if (path === null)
44
- break;
45
- startX = commands[a];
46
- startY = commands[a + 1];
47
- pushVerb(path, PathCommand.MOVE_TO, startX, startY);
48
- break;
49
- }
50
- case 'lineTo': {
51
- if (path === null)
52
- break;
53
- pushVerb(path, PathCommand.LINE_TO, commands[a], commands[a + 1]);
54
- break;
55
- }
56
- case 'curveTo': {
57
- if (path === null)
58
- break;
59
- pushQuadratic(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 3]);
60
- break;
61
- }
62
- case 'cubicCurveTo': {
63
- if (path === null)
64
- break;
65
- pushCubic(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 3], commands[a + 4], commands[a + 5]);
66
- break;
67
- }
68
- case 'drawCircle': {
69
- if (path === null)
70
- break;
71
- appendEllipseToPath(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 2]);
72
- break;
73
- }
74
- case 'drawEllipse': {
75
- if (path === null)
76
- break;
77
- const w = commands[a + 2];
78
- const h = commands[a + 3];
79
- appendEllipseToPath(path, commands[a] + w / 2, commands[a + 1] + h / 2, w / 2, h / 2);
80
- break;
81
- }
82
- case 'drawRectangle': {
83
- if (path === null)
84
- break;
85
- appendRectangleToPath(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 3]);
86
- break;
87
- }
88
- case 'drawRoundRectangle': {
89
- if (path === null)
90
- break;
91
- appendRoundRectangleToPath(path, commands[a], commands[a + 1], commands[a + 2], commands[a + 3], commands[a + 4] / 2, commands[a + 5] / 2);
92
- break;
93
- }
94
- case 'drawPath': {
95
- if (path === null)
96
- break;
97
- path.winding = commands[a + 2];
98
- appendRawPath(path, commands[a], commands[a + 1]);
99
- break;
100
- }
101
- // Non-geometry styling commands (lineStyle, begin*Fill variants) are handled by the
102
- // hasNonSolidShapeFill guard above or are no-ops for solid fills.
103
100
  default:
101
+ // Geometry verbs (moveTo/lineTo/curve/primitives) append to the active path; non-geometry
102
+ // styling commands (lineStyle, begin*Fill variants) are handled above / by the guard.
103
+ if (path !== null)
104
+ appendShapeGeometryCommand(path, name, commands, a);
104
105
  break;
105
106
  }
106
107
  }
@@ -128,6 +129,19 @@ export function hasNonSolidShapeFill(commands) {
128
129
  }
129
130
  return false;
130
131
  }
132
+ // True if the command stream declares any fill (solid, gradient, or bitmap). Lets the GPU stroke path
133
+ // tell a STROKE-ONLY shape (renderable as outline meshes) from a filled-and-stroked one (which still
134
+ // needs the raster fallback until the GPU fill + stroke paths compose).
135
+ export function hasShapeFill(commands) {
136
+ let i = 0;
137
+ while (i < commands.length) {
138
+ const name = commands[i];
139
+ if (name === 'beginFill' || name === 'beginGradientFill' || name === 'beginBitmapFill')
140
+ return true;
141
+ i += 2 + commands[i + 1];
142
+ }
143
+ return false;
144
+ }
131
145
  const KAPPA = 0.5522847498307936;
132
146
  function appendEllipseToPath(path, cx, cy, rx, ry) {
133
147
  const kx = rx * KAPPA;
@@ -143,7 +157,9 @@ function appendRawPath(path, verbs, data) {
143
157
  let d = 0;
144
158
  for (let v = 0; v < verbs.length; v++) {
145
159
  const verb = verbs[v];
146
- const args = verb === PathCommand.CUBIC_CURVE_TO ? 6 : verb === PathCommand.CURVE_TO ? 4 : 2;
160
+ // Per-verb operand width — CLOSE/NO_OP consume 0 and WIDE_* consume 4, so a CLOSE or wide verb
161
+ // followed by another subpath keeps the data cursor aligned (assuming 2 for all-but-curves did not).
162
+ const args = getPathCommandOperandCount(verb);
147
163
  path.commands.push(verb);
148
164
  for (let k = 0; k < args; k++)
149
165
  path.data.push(data[d + k]);
@@ -1 +1 @@
1
- {"version":3,"file":"shapeFill.js","sourceRoot":"","sources":["../src/shapeFill.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shapeFill.js","sourceRoot":"","sources":["../src/shapeFill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ShapeCommandToken, ShapeFillRegion } from '@flighthq/types';
2
+ export declare function getShapeStrokeRegions(commands: readonly ShapeCommandToken[]): ShapeFillRegion[] | null;
3
+ export declare function hasNonSolidShapeStroke(commands: readonly ShapeCommandToken[]): boolean;
4
+ //# sourceMappingURL=shapeStroke.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shapeStroke.d.ts","sourceRoot":"","sources":["../src/shapeStroke.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAQ,iBAAiB,EAAE,eAAe,EAAe,MAAM,iBAAiB,CAAC;AAuB7F,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,eAAe,EAAE,GAAG,IAAI,CA4EtG;AAID,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAQtF"}
@@ -0,0 +1,164 @@
1
+ import { strokePath } from '@flighthq/path';
2
+ import { PathCommand } from '@flighthq/types';
3
+ import { appendShapeGeometryCommand, getPathCommandOperandCount } from './shapeFill';
4
+ // Resolves a Shape's drawing-command stream into stroke OUTLINE regions for the GPU fill path: each
5
+ // `lineStyle` span's centerline geometry is offset into a fillable outline via `@flighthq/path`'s
6
+ // `strokePath` (real miter/bevel/round joins, butt/round/square caps, and dashing), emitted as a
7
+ // `ShapeFillRegion` so the renderer tessellates + fills it with the same flat-color mesh path solid
8
+ // fills use. This replaces the offscreen Canvas-2D raster-to-texture stroke fallback with
9
+ // GPU-tessellated, resolution-independent geometry (sharp when scaled, no per-shape offscreen cost,
10
+ // and no bounds-clipped miter spikes) — and is the first consumer of the otherwise-orphaned strokePath.
11
+ //
12
+ // Returns `null` when the shape uses a stroke the direct-fill outline route cannot express, so the
13
+ // caller falls back to the raster path: a gradient/bitmap stroke (non-solid color), or a CLOSED stroke.
14
+ // A closed stroke offsets into a hollow RING, and the tessellator fills each contour solid with no hole
15
+ // subtraction, so a ring can't be direct-filled — only an OPEN stroke's outline is a simple fillable
16
+ // polygon. Closure is decided geometrically on the accumulated centerline (a CLOSE verb, or a subpath
17
+ // whose end returns to its start — which covers self-closing rect/ellipse/circle/round-rect primitives,
18
+ // `appendShapePolygon`, a manual return-to-start polyline, and a `drawPath` carrying either), so it is
19
+ // stroke-span-aware: only geometry drawn under an active `lineStyle` reaches a centerline, so an
20
+ // unstroked closed primitive never forces the fallback. Solid open strokes only; ring tessellation (a
21
+ // stroke-strip or stencil-cover route) is a later addition.
22
+ export function getShapeStrokeRegions(commands) {
23
+ if (hasNonSolidShapeStroke(commands))
24
+ return null;
25
+ const regions = [];
26
+ let centerline = null; // accumulated centerline for the active stroke span
27
+ let style = null;
28
+ let color = 0;
29
+ let alpha = 1;
30
+ let penX = 0;
31
+ let penY = 0;
32
+ let deferred = false; // a stroked span closed into a ring the direct-fill route can't express
33
+ const flush = () => {
34
+ if (style === null || centerline === null || centerline.commands.length === 0)
35
+ return;
36
+ if (isCenterlineClosed(centerline)) {
37
+ deferred = true;
38
+ return;
39
+ }
40
+ const outline = strokePath(centerline, style);
41
+ if (outline.commands.length > 0)
42
+ regions.push({ path: outline, color, alpha });
43
+ };
44
+ let i = 0;
45
+ while (i < commands.length) {
46
+ const name = commands[i];
47
+ const argCount = commands[i + 1];
48
+ const a = i + 2;
49
+ i = a + argCount;
50
+ if (name === 'lineStyle') {
51
+ // A new stroke style ends the previous span's outline and opens a fresh centerline.
52
+ flush();
53
+ const thickness = commands[a];
54
+ if (thickness > 0) {
55
+ color = commands[a + 1];
56
+ alpha = commands[a + 2];
57
+ const caps = commands[a + 5];
58
+ const joints = commands[a + 6];
59
+ style = {
60
+ width: thickness,
61
+ // Shape's CapsStyle 'none' is Canvas/`strokeStyle`'s 'butt'; round/square pass through.
62
+ cap: caps === 'none' ? 'butt' : caps,
63
+ join: joints,
64
+ miterLimit: commands[a + 7],
65
+ };
66
+ centerline = { commands: [], data: [], winding: 'nonZero' };
67
+ }
68
+ else {
69
+ style = null;
70
+ centerline = null;
71
+ }
72
+ }
73
+ else if (isShapeGeometryCommand(name)) {
74
+ if (centerline !== null) {
75
+ // A span whose first geometry is a lineTo/curve (no leading moveTo) begins from the current pen
76
+ // position, matching Canvas 2D stroking the running path.
77
+ if (centerline.commands.length === 0 && name !== 'moveTo') {
78
+ centerline.commands.push(PathCommand.MOVE_TO);
79
+ centerline.data.push(penX, penY);
80
+ }
81
+ appendShapeGeometryCommand(centerline, name, commands, a);
82
+ }
83
+ // Track the pen off the polyline verbs so the next span can seed from it (primitives self-start).
84
+ if (name === 'moveTo' || name === 'lineTo') {
85
+ penX = commands[a];
86
+ penY = commands[a + 1];
87
+ }
88
+ else if (name === 'curveTo') {
89
+ penX = commands[a + 2];
90
+ penY = commands[a + 3];
91
+ }
92
+ else if (name === 'cubicCurveTo') {
93
+ penX = commands[a + 4];
94
+ penY = commands[a + 5];
95
+ }
96
+ }
97
+ // Fill-style + other non-geometry commands do not affect the stroke centerline.
98
+ }
99
+ flush();
100
+ return deferred ? null : regions;
101
+ }
102
+ // True if the stream uses a stroke the GPU outline path cannot express (a gradient or bitmap stroke),
103
+ // so the caller must fall back to the raster path. A solid `lineStyle` is expressible.
104
+ export function hasNonSolidShapeStroke(commands) {
105
+ let i = 0;
106
+ while (i < commands.length) {
107
+ const name = commands[i];
108
+ if (name === 'lineGradientStyle' || name === 'lineBitmapStyle')
109
+ return true;
110
+ i += 2 + commands[i + 1];
111
+ }
112
+ return false;
113
+ }
114
+ // True if the centerline encloses a region — a CLOSE verb, or any subpath whose end returns to its
115
+ // start (≥2 segments so it bounds area). Such a stroke offsets into a hollow ring the direct-fill
116
+ // tessellator cannot express, so the caller defers the whole shape to raster. Walks the verb/data
117
+ // stream with getPathCommandOperandCount so CLOSE/WIDE verbs keep the data cursor aligned.
118
+ function isCenterlineClosed(path) {
119
+ const { commands, data } = path;
120
+ let d = 0;
121
+ let subStartX = 0;
122
+ let subStartY = 0;
123
+ let lastX = 0;
124
+ let lastY = 0;
125
+ let segments = 0;
126
+ const subpathReturnsToStart = () => segments >= 2 && Math.abs(lastX - subStartX) < CLOSE_EPSILON && Math.abs(lastY - subStartY) < CLOSE_EPSILON;
127
+ for (let c = 0; c < commands.length; c++) {
128
+ const verb = commands[c];
129
+ if (verb === PathCommand.CLOSE)
130
+ return true;
131
+ const n = getPathCommandOperandCount(verb);
132
+ if (verb === PathCommand.MOVE_TO || verb === PathCommand.WIDE_MOVE_TO) {
133
+ if (subpathReturnsToStart())
134
+ return true;
135
+ // A WIDE_MOVE_TO's real endpoint is its trailing (x,y) pair; MOVE_TO's is its only pair.
136
+ lastX = subStartX = data[d + n - 2];
137
+ lastY = subStartY = data[d + n - 1];
138
+ segments = 0;
139
+ }
140
+ else if (n >= 2) {
141
+ // The endpoint of LINE/CURVE/CUBIC/WIDE_LINE is its trailing (x,y) pair.
142
+ lastX = data[d + n - 2];
143
+ lastY = data[d + n - 1];
144
+ segments++;
145
+ }
146
+ d += n;
147
+ }
148
+ return subpathReturnsToStart();
149
+ }
150
+ function isShapeGeometryCommand(name) {
151
+ return (name === 'moveTo' ||
152
+ name === 'lineTo' ||
153
+ name === 'curveTo' ||
154
+ name === 'cubicCurveTo' ||
155
+ name === 'drawCircle' ||
156
+ name === 'drawEllipse' ||
157
+ name === 'drawRectangle' ||
158
+ name === 'drawRoundRectangle' ||
159
+ name === 'drawPath');
160
+ }
161
+ // Endpoint-coincidence tolerance for return-to-start closure. Authored primitives (rect/ellipse) and
162
+ // polygons re-emit their start coordinate exactly, so this only absorbs trivial float noise.
163
+ const CLOSE_EPSILON = 1e-6;
164
+ //# sourceMappingURL=shapeStroke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shapeStroke.js","sourceRoot":"","sources":["../src/shapeStroke.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/shape",
3
- "version": "0.2.1-next.701.409c279",
3
+ "version": "0.2.1-next.738.07b221d",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/flighthq/flight.git",
@@ -32,10 +32,11 @@
32
32
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
33
33
  },
34
34
  "dependencies": {
35
- "@flighthq/displayobject": "0.2.1-next.701.409c279",
36
- "@flighthq/geometry": "0.2.1-next.701.409c279",
37
- "@flighthq/node": "0.2.1-next.701.409c279",
38
- "@flighthq/types": "0.2.1-next.701.409c279"
35
+ "@flighthq/displayobject": "0.2.1-next.738.07b221d",
36
+ "@flighthq/geometry": "0.2.1-next.738.07b221d",
37
+ "@flighthq/node": "0.2.1-next.738.07b221d",
38
+ "@flighthq/path": "0.2.1-next.738.07b221d",
39
+ "@flighthq/types": "0.2.1-next.738.07b221d"
39
40
  },
40
41
  "devDependencies": {
41
42
  "typescript": "^5.3.0"
@@ -11,7 +11,70 @@ import {
11
11
  appendShapeMoveTo,
12
12
  appendShapeRectangle,
13
13
  } from './shapeCommands';
14
- import { getShapeFillRegions, hasNonSolidShapeFill } from './shapeFill';
14
+ import {
15
+ appendShapeGeometryCommand,
16
+ getPathCommandOperandCount,
17
+ getShapeFillRegions,
18
+ hasNonSolidShapeFill,
19
+ hasShapeFill,
20
+ } from './shapeFill';
21
+
22
+ describe('appendShapeGeometryCommand', () => {
23
+ it('appends polyline verbs and expands primitives, ignoring non-geometry names', () => {
24
+ const path = { commands: [] as number[], data: [] as number[], winding: 'nonZero' as const };
25
+ appendShapeGeometryCommand(path, 'moveTo', ['moveTo', 2, 5, 6], 2);
26
+ appendShapeGeometryCommand(path, 'lineTo', ['lineTo', 2, 7, 8], 2);
27
+ expect(path.commands).toEqual([PathCommand.MOVE_TO, PathCommand.LINE_TO]);
28
+ expect(path.data).toEqual([5, 6, 7, 8]);
29
+
30
+ // A rectangle primitive expands into MOVE + 4 LINE verbs.
31
+ const rect = { commands: [] as number[], data: [] as number[], winding: 'nonZero' as const };
32
+ appendShapeGeometryCommand(rect, 'drawRectangle', ['drawRectangle', 4, 0, 0, 10, 10], 2);
33
+ expect(rect.commands).toEqual([
34
+ PathCommand.MOVE_TO,
35
+ PathCommand.LINE_TO,
36
+ PathCommand.LINE_TO,
37
+ PathCommand.LINE_TO,
38
+ PathCommand.LINE_TO,
39
+ ]);
40
+
41
+ // A styling command name is a no-op.
42
+ const noop = { commands: [] as number[], data: [] as number[], winding: 'nonZero' as const };
43
+ appendShapeGeometryCommand(noop, 'beginFill', ['beginFill', 2, 0xff0000, 1], 2);
44
+ expect(noop.commands).toEqual([]);
45
+ });
46
+
47
+ it('keeps the data cursor aligned across a raw CLOSE between drawPath subpaths', () => {
48
+ // A drawPath with two subpaths separated by a CLOSE verb. CLOSE consumes 0 operands: if it were
49
+ // parsed as 2, the second subpath's coordinates would shift.
50
+ const path = { commands: [] as number[], data: [] as number[], winding: 'nonZero' as const };
51
+ const verbs = [
52
+ PathCommand.MOVE_TO,
53
+ PathCommand.LINE_TO,
54
+ PathCommand.CLOSE,
55
+ PathCommand.MOVE_TO,
56
+ PathCommand.LINE_TO,
57
+ ];
58
+ const raw = [0, 0, 10, 0, 20, 20, 30, 20];
59
+ appendShapeGeometryCommand(path, 'drawPath', ['drawPath', 3, verbs, raw, 'nonZero'], 2);
60
+ expect(path.commands).toEqual(verbs);
61
+ // The second subpath still reads (20,20)->(30,20); CLOSE contributed no data.
62
+ expect(path.data).toEqual([0, 0, 10, 0, 20, 20, 30, 20]);
63
+ });
64
+ });
65
+
66
+ describe('getPathCommandOperandCount', () => {
67
+ it('reports operand width per verb (MOVE/LINE 2, CURVE/WIDE 4, CUBIC 6, CLOSE/NO_OP 0)', () => {
68
+ expect(getPathCommandOperandCount(PathCommand.MOVE_TO)).toBe(2);
69
+ expect(getPathCommandOperandCount(PathCommand.LINE_TO)).toBe(2);
70
+ expect(getPathCommandOperandCount(PathCommand.CURVE_TO)).toBe(4);
71
+ expect(getPathCommandOperandCount(PathCommand.WIDE_MOVE_TO)).toBe(4);
72
+ expect(getPathCommandOperandCount(PathCommand.WIDE_LINE_TO)).toBe(4);
73
+ expect(getPathCommandOperandCount(PathCommand.CUBIC_CURVE_TO)).toBe(6);
74
+ expect(getPathCommandOperandCount(PathCommand.CLOSE)).toBe(0);
75
+ expect(getPathCommandOperandCount(PathCommand.NO_OP)).toBe(0);
76
+ });
77
+ });
15
78
 
16
79
  describe('getShapeFillRegions', () => {
17
80
  it('resolves a solid rectangle fill into one region with a closed outline', () => {
@@ -114,3 +177,18 @@ describe('hasNonSolidShapeFill', () => {
114
177
  expect(hasNonSolidShapeFill(shape.data.commands)).toBe(true);
115
178
  });
116
179
  });
180
+
181
+ describe('hasShapeFill', () => {
182
+ it('is true when a fill is declared and false for a stroke-only shape', () => {
183
+ const filled = createShape();
184
+ appendShapeBeginFill(filled, 0xff0000);
185
+ appendShapeRectangle(filled, 0, 0, 10, 10);
186
+ expect(hasShapeFill(filled.data.commands)).toBe(true);
187
+
188
+ const strokeOnly = createShape();
189
+ appendShapeLineStyle(strokeOnly, 2, 0);
190
+ appendShapeMoveTo(strokeOnly, 0, 0);
191
+ appendShapeLineTo(strokeOnly, 10, 0);
192
+ expect(hasShapeFill(strokeOnly.data.commands)).toBe(false);
193
+ });
194
+ });
@@ -0,0 +1,136 @@
1
+ import { tessellatePath } from '@flighthq/path';
2
+ import type { ShapeCommandToken } from '@flighthq/types';
3
+ import { PathCommand } from '@flighthq/types';
4
+ import { describe, expect, it } from 'vitest';
5
+
6
+ import { createShape } from './shape';
7
+ import {
8
+ appendShapeLineStyle,
9
+ appendShapeLineTo,
10
+ appendShapeMoveTo,
11
+ appendShapePath,
12
+ appendShapePolygon,
13
+ appendShapeRectangle,
14
+ } from './shapeCommands';
15
+ import { getShapeStrokeRegions, hasNonSolidShapeStroke } from './shapeStroke';
16
+
17
+ // A 90° corner stroked with the given join, as one span.
18
+ function strokedCorner(join: 'bevel' | 'miter' | 'round', thickness = 20) {
19
+ const shape = createShape();
20
+ appendShapeLineStyle(shape, thickness, 0x112233, 0.5, false, 'normal', 'none', join, 6);
21
+ appendShapeMoveTo(shape, 0, 0);
22
+ appendShapeLineTo(shape, 100, 0);
23
+ appendShapeLineTo(shape, 100, 100);
24
+ return getShapeStrokeRegions(shape.data.commands);
25
+ }
26
+
27
+ describe('getShapeStrokeRegions', () => {
28
+ it('offsets a solid stroke span into one fillable outline region carrying its color + alpha', () => {
29
+ const regions = strokedCorner('miter');
30
+ expect(regions).not.toBeNull();
31
+ expect(regions!.length).toBe(1);
32
+ expect(regions![0].color).toBe(0x112233);
33
+ expect(regions![0].alpha).toBe(0.5);
34
+ // A real outline: closed contour(s) with MOVE + fill geometry, not empty.
35
+ expect(regions![0].path.commands.length).toBeGreaterThan(0);
36
+ expect(regions![0].path.commands[0]).toBe(PathCommand.MOVE_TO);
37
+ });
38
+
39
+ it('differentiates join styles (miter vs bevel vs round produce distinct outlines)', () => {
40
+ const miter = strokedCorner('miter')![0].path.data.length;
41
+ const bevel = strokedCorner('bevel')![0].path.data.length;
42
+ const round = strokedCorner('round')![0].path.data.length;
43
+ // The corner geometry differs per join: bevel cuts the corner, round arcs it (more points), miter
44
+ // extends it. If joins were ignored (the old raster-clip bug) these would be identical.
45
+ expect(miter).not.toBe(bevel);
46
+ expect(round).toBeGreaterThan(bevel);
47
+ });
48
+
49
+ it('emits no region for a cleared stroke (lineStyle thickness 0) and for a stroke-free shape', () => {
50
+ const cleared = createShape();
51
+ appendShapeLineStyle(cleared, 0);
52
+ appendShapeMoveTo(cleared, 0, 0);
53
+ appendShapeLineTo(cleared, 50, 0);
54
+ expect(getShapeStrokeRegions(cleared.data.commands)).toEqual([]);
55
+
56
+ const strokeFree = createShape();
57
+ appendShapeMoveTo(strokeFree, 0, 0);
58
+ appendShapeLineTo(strokeFree, 50, 0);
59
+ expect(getShapeStrokeRegions(strokeFree.data.commands)).toEqual([]);
60
+ });
61
+
62
+ it('closes each span and re-strokes on a new lineStyle (two spans → two regions)', () => {
63
+ const shape = createShape();
64
+ appendShapeLineStyle(shape, 10, 0xff0000, 1, false, 'normal', 'none', 'miter', 6);
65
+ appendShapeMoveTo(shape, 0, 0);
66
+ appendShapeLineTo(shape, 50, 0);
67
+ appendShapeLineStyle(shape, 4, 0x00ff00, 1, false, 'normal', 'round', 'round', 6);
68
+ appendShapeMoveTo(shape, 0, 20);
69
+ appendShapeLineTo(shape, 50, 20);
70
+ const regions = getShapeStrokeRegions(shape.data.commands);
71
+ expect(regions!.length).toBe(2);
72
+ expect(regions![0].color).toBe(0xff0000);
73
+ expect(regions![1].color).toBe(0x00ff00);
74
+ });
75
+
76
+ it('tessellates an OPEN stroke outline into a fillable (non-empty) mesh', () => {
77
+ const outline = strokedCorner('miter')![0].path;
78
+ // The V's outline is a simple polygon: ear-clipping fills it (indices > 0). A closed stroke's ring
79
+ // could not be direct-filled, which is why closed strokes defer (next test).
80
+ const mesh = tessellatePath(outline);
81
+ expect(mesh.indices.length).toBeGreaterThan(0);
82
+ });
83
+
84
+ it('defers a CLOSED stroke (rectangle) to the raster path — a ring is not direct-fillable (null)', () => {
85
+ const shape = createShape();
86
+ appendShapeLineStyle(shape, 8, 0xff0000, 1, false, 'normal', 'none', 'miter', 4);
87
+ appendShapeRectangle(shape, 10, 10, 100, 50);
88
+ expect(getShapeStrokeRegions(shape.data.commands)).toBeNull();
89
+ });
90
+
91
+ it('defers a stroked drawPath carrying a CLOSE verb (null)', () => {
92
+ const shape = createShape();
93
+ appendShapeLineStyle(shape, 6, 0x0000ff, 1, false, 'normal', 'none', 'miter', 4);
94
+ // A triangle subpath closed by an explicit CLOSE verb — a ring, not an open stroke.
95
+ const verbs = [PathCommand.MOVE_TO, PathCommand.LINE_TO, PathCommand.LINE_TO, PathCommand.CLOSE];
96
+ appendShapePath(shape, verbs, [0, 0, 40, 0, 20, 30], 'nonZero');
97
+ expect(getShapeStrokeRegions(shape.data.commands)).toBeNull();
98
+ });
99
+
100
+ it('defers a stroked return-to-start polygon (appendShapePolygon) even without a CLOSE verb (null)', () => {
101
+ const shape = createShape();
102
+ appendShapeLineStyle(shape, 6, 0x0000ff, 1, false, 'normal', 'none', 'miter', 4);
103
+ // appendShapePolygon re-emits the first point as a trailing lineTo (return-to-start), no CLOSE verb.
104
+ appendShapePolygon(shape, [0, 0, 50, 0, 25, 40]);
105
+ expect(getShapeStrokeRegions(shape.data.commands)).toBeNull();
106
+ });
107
+
108
+ it('ignores an UNSTROKED closed primitive and still strokes a later open line (span-aware)', () => {
109
+ const shape = createShape();
110
+ // Rectangle drawn with no active lineStyle — it never reaches a centerline, so it must NOT force the
111
+ // whole shape to the raster fallback. The later open stroked line still yields one region.
112
+ appendShapeRectangle(shape, 0, 0, 100, 50);
113
+ appendShapeLineStyle(shape, 6, 0xff0000, 1, false, 'normal', 'none', 'miter', 4);
114
+ appendShapeMoveTo(shape, 10, 80);
115
+ appendShapeLineTo(shape, 90, 80);
116
+ const regions = getShapeStrokeRegions(shape.data.commands);
117
+ expect(regions).not.toBeNull();
118
+ expect(regions!.length).toBe(1);
119
+ expect(regions![0].color).toBe(0xff0000);
120
+ });
121
+
122
+ it('defers a gradient/bitmap stroke to the raster path (null)', () => {
123
+ const gradientStroke: ShapeCommandToken[] = ['lineGradientStyle', 1, 0, 'moveTo', 2, 0, 0, 'lineTo', 2, 50, 0];
124
+ expect(getShapeStrokeRegions(gradientStroke)).toBeNull();
125
+ });
126
+ });
127
+
128
+ describe('hasNonSolidShapeStroke', () => {
129
+ it('is true only for a gradient or bitmap stroke, not a solid lineStyle', () => {
130
+ const solid = createShape();
131
+ appendShapeLineStyle(solid, 3);
132
+ expect(hasNonSolidShapeStroke(solid.data.commands)).toBe(false);
133
+ expect(hasNonSolidShapeStroke(['lineGradientStyle', 1, 0] as ShapeCommandToken[])).toBe(true);
134
+ expect(hasNonSolidShapeStroke(['lineBitmapStyle', 1, 0] as ShapeCommandToken[])).toBe(true);
135
+ });
136
+ });