postext 1.53.0 → 1.54.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.
Files changed (157) hide show
  1. package/dist/__tests__/bundle/balloonPlacementPin.test.js +6 -5
  2. package/dist/__tests__/bundle/balloonPlacementPin.test.js.map +1 -1
  3. package/dist/__tests__/bundle/designOverflowPin.test.js +1 -1
  4. package/dist/__tests__/bundle/gridBalancingPin.test.js +6 -5
  5. package/dist/__tests__/bundle/gridBalancingPin.test.js.map +1 -1
  6. package/dist/__tests__/bundle/gridBreakRulesPin.test.js +8 -7
  7. package/dist/__tests__/bundle/gridBreakRulesPin.test.js.map +1 -1
  8. package/dist/__tests__/bundle/looseOrderPin.test.js +6 -5
  9. package/dist/__tests__/bundle/looseOrderPin.test.js.map +1 -1
  10. package/dist/__tests__/bundle/markRadiusPin.test.js +1 -1
  11. package/dist/__tests__/bundle/refLabelBreaksPin.test.js +6 -5
  12. package/dist/__tests__/bundle/refLabelBreaksPin.test.js.map +1 -1
  13. package/dist/__tests__/bundle/scriptContextPin.test.js +6 -5
  14. package/dist/__tests__/bundle/scriptContextPin.test.js.map +1 -1
  15. package/dist/__tests__/bundle/shapingLanguagePin.test.js +3 -3
  16. package/dist/__tests__/bundle/taskBoxPin.test.js +1 -1
  17. package/dist/__tests__/bundle.test.js +1 -1
  18. package/dist/__tests__/codeBlocks.test.js +1 -1
  19. package/dist/__tests__/composedTemplates.test.js +1 -1
  20. package/dist/__tests__/exports.test.js +17 -0
  21. package/dist/__tests__/exports.test.js.map +1 -1
  22. package/dist/__tests__/hardBreaks.test.js +1 -1
  23. package/dist/__tests__/headingInlineMarks.test.js +1 -1
  24. package/dist/__tests__/mathSizeMigration.test.js +2 -2
  25. package/dist/__tests__/musicEngine.test.d.ts +2 -0
  26. package/dist/__tests__/musicEngine.test.d.ts.map +1 -0
  27. package/dist/__tests__/musicEngine.test.js +102 -0
  28. package/dist/__tests__/musicEngine.test.js.map +1 -0
  29. package/dist/__tests__/musicLayout.test.d.ts +2 -0
  30. package/dist/__tests__/musicLayout.test.d.ts.map +1 -0
  31. package/dist/__tests__/musicLayout.test.js +146 -0
  32. package/dist/__tests__/musicLayout.test.js.map +1 -0
  33. package/dist/__tests__/pipeline/boxParagraphStyles.test.js +2 -2
  34. package/dist/__tests__/pipeline/calloutInlineResourceGap.test.js +1 -1
  35. package/dist/__tests__/pipeline/calloutSplitMinLinesChild.test.js +1 -1
  36. package/dist/__tests__/pipeline/colonListRoom.test.js +1 -1
  37. package/dist/__tests__/pipeline/compoundBreaks.test.js +1 -1
  38. package/dist/__tests__/pipeline/dashBreaks.test.js +1 -1
  39. package/dist/__tests__/pipeline/headingSplitOrphans.test.js +1 -1
  40. package/dist/__tests__/pipeline/inlineFigureSpace.test.js +1 -1
  41. package/dist/__tests__/pipeline/paragraphContainerTail.test.js +1 -1
  42. package/dist/__tests__/pipeline/raggedOptimal.test.js +1 -1
  43. package/dist/__tests__/slashBreaks.test.js +1 -1
  44. package/dist/__tests__/verseLines.test.js +1 -1
  45. package/dist/bundle/codec.d.ts.map +1 -1
  46. package/dist/bundle/codec.js +10 -0
  47. package/dist/bundle/codec.js.map +1 -1
  48. package/dist/bundle/configVersion.d.ts +12 -2
  49. package/dist/bundle/configVersion.d.ts.map +1 -1
  50. package/dist/bundle/configVersion.js +32 -2
  51. package/dist/bundle/configVersion.js.map +1 -1
  52. package/dist/bundle/manifest.d.ts.map +1 -1
  53. package/dist/bundle/manifest.js +9 -2
  54. package/dist/bundle/manifest.js.map +1 -1
  55. package/dist/bundle/types.d.ts +6 -1
  56. package/dist/bundle/types.d.ts.map +1 -1
  57. package/dist/canvas-backend/blockRender.d.ts.map +1 -1
  58. package/dist/canvas-backend/blockRender.js +17 -2
  59. package/dist/canvas-backend/blockRender.js.map +1 -1
  60. package/dist/canvas-backend/renderResourceBlock.d.ts.map +1 -1
  61. package/dist/canvas-backend/renderResourceBlock.js +7 -0
  62. package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
  63. package/dist/canvas-backend/scoreRender.d.ts +10 -0
  64. package/dist/canvas-backend/scoreRender.d.ts.map +1 -0
  65. package/dist/canvas-backend/scoreRender.js +74 -0
  66. package/dist/canvas-backend/scoreRender.js.map +1 -0
  67. package/dist/composed/sourceMap.js +1 -1
  68. package/dist/composed/sourceMap.js.map +1 -1
  69. package/dist/defaults/index.d.ts +2 -1
  70. package/dist/defaults/index.d.ts.map +1 -1
  71. package/dist/defaults/index.js +17 -1
  72. package/dist/defaults/index.js.map +1 -1
  73. package/dist/defaults/resourceTypes.d.ts +5 -0
  74. package/dist/defaults/resourceTypes.d.ts.map +1 -1
  75. package/dist/defaults/resourceTypes.js +34 -4
  76. package/dist/defaults/resourceTypes.js.map +1 -1
  77. package/dist/defaults/scoreStyle.d.ts +15 -0
  78. package/dist/defaults/scoreStyle.d.ts.map +1 -0
  79. package/dist/defaults/scoreStyle.js +91 -0
  80. package/dist/defaults/scoreStyle.js.map +1 -0
  81. package/dist/design/elementKeys.d.ts +2 -0
  82. package/dist/design/elementKeys.d.ts.map +1 -1
  83. package/dist/design/elementKeys.js +1 -1
  84. package/dist/design/elementKeys.js.map +1 -1
  85. package/dist/html-backend.d.ts.map +1 -1
  86. package/dist/html-backend.js +47 -0
  87. package/dist/html-backend.js.map +1 -1
  88. package/dist/index.d.ts +4 -2
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +2 -1
  91. package/dist/index.js.map +1 -1
  92. package/dist/music/engine.d.ts +21 -0
  93. package/dist/music/engine.d.ts.map +1 -0
  94. package/dist/music/engine.js +309 -0
  95. package/dist/music/engine.js.map +1 -0
  96. package/dist/music/flatten.d.ts +21 -0
  97. package/dist/music/flatten.d.ts.map +1 -0
  98. package/dist/music/flatten.js +302 -0
  99. package/dist/music/flatten.js.map +1 -0
  100. package/dist/music/index.d.ts +4 -0
  101. package/dist/music/index.d.ts.map +1 -0
  102. package/dist/music/index.js +3 -0
  103. package/dist/music/index.js.map +1 -0
  104. package/dist/music/types.d.ts +88 -0
  105. package/dist/music/types.d.ts.map +1 -0
  106. package/dist/music/types.js +35 -0
  107. package/dist/music/types.js.map +1 -0
  108. package/dist/parse/blockParser.d.ts.map +1 -1
  109. package/dist/parse/blockParser.js +21 -1
  110. package/dist/parse/blockParser.js.map +1 -1
  111. package/dist/parse/types.d.ts +30 -1
  112. package/dist/parse/types.d.ts.map +1 -1
  113. package/dist/pipeline/build.d.ts.map +1 -1
  114. package/dist/pipeline/build.js +40 -7
  115. package/dist/pipeline/build.js.map +1 -1
  116. package/dist/pipeline/buildBlockKind.d.ts.map +1 -1
  117. package/dist/pipeline/buildBlockKind.js +9 -0
  118. package/dist/pipeline/buildBlockKind.js.map +1 -1
  119. package/dist/pipeline/buildMeasurement.d.ts.map +1 -1
  120. package/dist/pipeline/buildMeasurement.js +22 -0
  121. package/dist/pipeline/buildMeasurement.js.map +1 -1
  122. package/dist/pipeline/calloutLayout.d.ts.map +1 -1
  123. package/dist/pipeline/calloutLayout.js +14 -3
  124. package/dist/pipeline/calloutLayout.js.map +1 -1
  125. package/dist/pipeline/codeBlocks.d.ts.map +1 -1
  126. package/dist/pipeline/codeBlocks.js +4 -2
  127. package/dist/pipeline/codeBlocks.js.map +1 -1
  128. package/dist/pipeline/columnBalancing.d.ts.map +1 -1
  129. package/dist/pipeline/columnBalancing.js +7 -1
  130. package/dist/pipeline/columnBalancing.js.map +1 -1
  131. package/dist/pipeline/config.d.ts.map +1 -1
  132. package/dist/pipeline/config.js +3 -1
  133. package/dist/pipeline/config.js.map +1 -1
  134. package/dist/pipeline/frameLayout.js +1 -1
  135. package/dist/pipeline/frameLayout.js.map +1 -1
  136. package/dist/pipeline/lineNumbers.js +1 -1
  137. package/dist/pipeline/lineNumbers.js.map +1 -1
  138. package/dist/pipeline/resourceLayout.d.ts.map +1 -1
  139. package/dist/pipeline/resourceLayout.js +9 -0
  140. package/dist/pipeline/resourceLayout.js.map +1 -1
  141. package/dist/pipeline/scoreBlocks.d.ts +44 -0
  142. package/dist/pipeline/scoreBlocks.d.ts.map +1 -0
  143. package/dist/pipeline/scoreBlocks.js +172 -0
  144. package/dist/pipeline/scoreBlocks.js.map +1 -0
  145. package/dist/pipeline/tashkil.js +1 -1
  146. package/dist/pipeline/tashkil.js.map +1 -1
  147. package/dist/react/createLayout.d.ts.map +1 -1
  148. package/dist/react/createLayout.js +4 -0
  149. package/dist/react/createLayout.js.map +1 -1
  150. package/dist/types.d.ts +76 -1
  151. package/dist/types.d.ts.map +1 -1
  152. package/dist/vdt.d.ts +43 -4
  153. package/dist/vdt.d.ts.map +1 -1
  154. package/dist/vdt.js.map +1 -1
  155. package/dist/worker/layout.worker.js +10 -0
  156. package/dist/worker/layout.worker.js.map +1 -1
  157. package/package.json +3 -2
@@ -0,0 +1,309 @@
1
+ import { flattenVerovioSvg, itemsToSvg } from './flatten.js';
2
+ import { measureTextWidth } from '../measure/canvas.js';
3
+ import { buildFontString } from '../measure/font.js';
4
+ let toolkit = null;
5
+ let initPromise = null;
6
+ const initListeners = new Set();
7
+ let warnedWithoutEngine = false;
8
+ export function isMusicReady() {
9
+ return toolkit !== null;
10
+ }
11
+ export function onMusicReady(fn) {
12
+ if (toolkit !== null) {
13
+ fn();
14
+ return () => { };
15
+ }
16
+ initListeners.add(fn);
17
+ return () => { initListeners.delete(fn); };
18
+ }
19
+ /**
20
+ * Load Verovio and start the score engraver. Await it before laying out a
21
+ * document with scores on the main thread (the layout worker calls it
22
+ * itself): until it resolves, every score is set as a grey placeholder box.
23
+ * Idempotent; a failed start can be retried.
24
+ */
25
+ export async function initMusicEngine() {
26
+ if (toolkit !== null)
27
+ return;
28
+ if (initPromise)
29
+ return initPromise;
30
+ initPromise = (async () => {
31
+ try {
32
+ const [{ default: createVerovioModule }, { VerovioToolkit }] = await Promise.all([
33
+ import('verovio/wasm-hum'),
34
+ import('verovio/esm'),
35
+ ]);
36
+ const module = await createVerovioModule();
37
+ toolkit = new VerovioToolkit(module);
38
+ }
39
+ catch (err) {
40
+ initPromise = null;
41
+ const reason = err instanceof Error ? err.message : String(err);
42
+ throw new Error(`[postext] the music engine failed to start: ${reason}`, { cause: err });
43
+ }
44
+ for (const fn of initListeners)
45
+ fn();
46
+ initListeners.clear();
47
+ })();
48
+ return initPromise;
49
+ }
50
+ /** Called when the layout sets a score with no engine running. Warns once,
51
+ * and only when nobody asked for the engine. */
52
+ export function noteMusicWithoutEngine() {
53
+ if (toolkit !== null || initPromise !== null || warnedWithoutEngine)
54
+ return;
55
+ warnedWithoutEngine = true;
56
+ console.warn('[postext] This document contains music scores, but the music engine is not running, so every score is laid out as a grey placeholder box. '
57
+ + 'Call `await initMusicEngine()` before `buildDocument` (the layout worker does it for you).');
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // LRU cache
61
+ // ---------------------------------------------------------------------------
62
+ const MAX_CACHE = 512;
63
+ const cache = new Map();
64
+ function cacheKey(source, format, widthPx, o) {
65
+ return [
66
+ format, widthPx.toFixed(2), o.staffSizePx.toFixed(3), o.font, o.textFont ?? '', o.spacing,
67
+ o.barNumbers, o.systemSpacing, source,
68
+ ].join('|');
69
+ }
70
+ export function clearMusicCache() {
71
+ cache.clear();
72
+ }
73
+ // ---------------------------------------------------------------------------
74
+ // Rendering
75
+ // ---------------------------------------------------------------------------
76
+ /** Verovio's staff height at scale 100, in px: 4 staff spaces of 18 px. */
77
+ const STAFF_PX_AT_100 = 72;
78
+ /** The value of the first ABC header line `field:` (`T:` title, `C:`
79
+ * composer), read line by line. */
80
+ function abcField(source, field) {
81
+ for (const line of source.split('\n')) {
82
+ if (line.startsWith(`${field}:`)) {
83
+ const value = line.slice(field.length + 1).trim();
84
+ if (value)
85
+ return value;
86
+ }
87
+ }
88
+ return undefined;
89
+ }
90
+ /** The text of the first element whose opening tag starts with one of
91
+ * `openings` (`<work-title`, `<creator type="composer"`), found with plain
92
+ * string scans. */
93
+ function elementText(source, openings) {
94
+ const lower = source.toLowerCase();
95
+ for (const opening of openings) {
96
+ const at = lower.indexOf(opening);
97
+ if (at < 0)
98
+ continue;
99
+ const next = source[at + opening.length];
100
+ if (next !== '>' && next !== ' ' && next !== '\t' && next !== '\n')
101
+ continue;
102
+ const open = source.indexOf('>', at);
103
+ const close = open < 0 ? -1 : source.indexOf('<', open + 1);
104
+ if (close < 0)
105
+ continue;
106
+ const text = source.slice(open + 1, close).trim();
107
+ if (text)
108
+ return text;
109
+ }
110
+ return undefined;
111
+ }
112
+ function readMetadata(source, format) {
113
+ if (format === 'abc')
114
+ return { title: abcField(source, 'T'), composer: abcField(source, 'C') };
115
+ return {
116
+ title: elementText(source, ['<work-title', '<movement-title', '<title']),
117
+ composer: elementText(source, ['<creator type="composer"', '<persname role="composer"', '<composer']),
118
+ };
119
+ }
120
+ function verovioOptions(widthPx, o, leftMarginPx = 0) {
121
+ // Engrave at scale 100 on a page as wide as the measure at that scale; the
122
+ // slices are then scaled to the measure exactly (Verovio's scale is an
123
+ // integer percentage, too coarse for a staff size in px).
124
+ const toScale100 = STAFF_PX_AT_100 / o.staffSizePx;
125
+ return {
126
+ scale: 100,
127
+ pageWidth: Math.max(100, Math.round(widthPx * toScale100)),
128
+ // Room for a brace or bracket left of the staves (see `renderScore`).
129
+ pageMarginLeft: Math.round(leftMarginPx * toScale100),
130
+ // One system per page: each page is one breakable slice of the score.
131
+ pageHeight: 100,
132
+ adjustPageHeight: true,
133
+ breaks: 'auto',
134
+ header: 'none',
135
+ footer: 'none',
136
+ pageMarginTop: 0,
137
+ pageMarginBottom: 0,
138
+ pageMarginRight: 0,
139
+ spacingSystem: o.systemSpacing,
140
+ spacingLinear: 0.25 * o.spacing,
141
+ spacingNonLinear: 0.6,
142
+ mnumInterval: o.barNumbers === 'every' ? 1 : 0,
143
+ // Room between the words of a lyric line: at the engraver's default
144
+ // (1.2) the words of a narrow measure touch ("nigh,sha-").
145
+ lyricWordSpace: 2.5,
146
+ font: o.font,
147
+ svgViewBox: true,
148
+ svgRemoveXlink: true,
149
+ smuflTextFont: 'none',
150
+ };
151
+ }
152
+ const COORD_RUN_RE = /[MLCQST]([^A-Za-z]*)/g;
153
+ /** The leftmost x a system paints at (its paths' points; text is never
154
+ * left of the staves). */
155
+ function itemsMinX(items) {
156
+ let min = Infinity;
157
+ for (const it of items) {
158
+ if (it.type !== 'path')
159
+ continue;
160
+ for (const m of it.d.matchAll(COORD_RUN_RE)) {
161
+ const nums = m[1].trim().split(/[\s,]+/).filter(Boolean).map(Number);
162
+ for (let k = 0; k < nums.length; k += 2)
163
+ if (nums[k] < min)
164
+ min = nums[k];
165
+ }
166
+ }
167
+ return Number.isFinite(min) ? min : 0;
168
+ }
169
+ /** The face Verovio measures words in when it spaces the notes. */
170
+ const ENGRAVER_TEXT_FONT = 'Times New Roman';
171
+ /**
172
+ * A word of several runs (a chord symbol and its raised figure) as one item
173
+ * per run, each at its size and baseline, laid side by side by their widths
174
+ * in `textFont` (about half an em per character where nothing measures).
175
+ */
176
+ function layOutRuns(items, textFont) {
177
+ if (!items.some((it) => it.type === 'text' && it.runs))
178
+ return items;
179
+ const widthOf = (text, size, bold, italic) => {
180
+ try {
181
+ const w = measureTextWidth(text, buildFontString(textFont, size, bold ? 'bold' : 'normal', italic ? 'italic' : 'normal'));
182
+ if (w > 0)
183
+ return w;
184
+ }
185
+ catch {
186
+ // No measuring context: the estimate below.
187
+ }
188
+ return text.length * size * 0.5;
189
+ };
190
+ const out = [];
191
+ for (const it of items) {
192
+ if (it.type !== 'text' || !it.runs) {
193
+ out.push(it);
194
+ continue;
195
+ }
196
+ const widths = it.runs.map((r) => r.dx + widthOf(r.text, r.sizePx, r.bold ?? it.bold, r.italic ?? it.italic));
197
+ const total = widths.reduce((a, b) => a + b, 0);
198
+ let x = it.anchor === 'middle' ? it.x - total / 2 : it.anchor === 'end' ? it.x - total : it.x;
199
+ it.runs.forEach((r, i) => {
200
+ x += r.dx;
201
+ out.push({ type: 'text', x, y: it.y + r.rise, text: r.text, sizePx: r.sizePx, bold: r.bold ?? it.bold, italic: r.italic ?? it.italic });
202
+ x += widths[i] - r.dx;
203
+ });
204
+ }
205
+ return out;
206
+ }
207
+ /**
208
+ * Words set in `textFont` at the room the engraver gave them: it spaces
209
+ * lyrics and directions by its own (Times) metrics, so a wider face would
210
+ * run one syllable into the next. A word wider in `textFont` than in Times
211
+ * is set that much smaller. Without a measuring context (a bare Node
212
+ * process) the words are left as they are.
213
+ */
214
+ function fitWords(items, textFont) {
215
+ if (textFont === ENGRAVER_TEXT_FONT)
216
+ return items;
217
+ try {
218
+ return items.map((it) => {
219
+ if (it.type !== 'text')
220
+ return it;
221
+ const weight = it.bold ? 'bold' : 'normal';
222
+ const style = it.italic ? 'italic' : 'normal';
223
+ const planned = measureTextWidth(it.text, buildFontString(ENGRAVER_TEXT_FONT, 100, weight, style));
224
+ const actual = measureTextWidth(it.text, buildFontString(textFont, 100, weight, style));
225
+ if (!(planned > 0) || !(actual > planned * 1.01))
226
+ return it;
227
+ return { ...it, sizePx: it.sizePx * (planned / actual) };
228
+ });
229
+ }
230
+ catch {
231
+ return items;
232
+ }
233
+ }
234
+ const DEFAULT_TEXT_FONT = 'Times New Roman, serif';
235
+ function toSystem(svg, o, widthPx) {
236
+ const flat = flattenVerovioSvg(svg, widthPx, o.barNumbers === 'none' ? { skipClasses: ['mNum'] } : undefined);
237
+ if (!flat)
238
+ return null;
239
+ const textFont = o.textFont || DEFAULT_TEXT_FONT;
240
+ const items = fitWords(layOutRuns(flat.items, textFont), textFont);
241
+ return {
242
+ widthPx,
243
+ heightPx: flat.heightPx,
244
+ items,
245
+ // Every backend paints the same words: HTML, PDF and EPUB from this SVG.
246
+ svg: itemsToSvg(items, widthPx, flat.heightPx, 'currentColor', textFont),
247
+ textFont,
248
+ };
249
+ }
250
+ /**
251
+ * Engrave a score at a measure `widthPx` wide. Returns one slice per system;
252
+ * an empty list (with `error`) when the source does not load or the engine
253
+ * is not running.
254
+ */
255
+ export function renderScore(source, format, widthPx, options) {
256
+ const key = cacheKey(source, format, widthPx, options);
257
+ const hit = cache.get(key);
258
+ if (hit) {
259
+ cache.delete(key);
260
+ cache.set(key, hit);
261
+ return hit;
262
+ }
263
+ const meta = readMetadata(source, format);
264
+ if (toolkit === null) {
265
+ noteMusicWithoutEngine();
266
+ return { systems: [], error: 'music engine not running', ...meta };
267
+ }
268
+ const engrave = (leftMarginPx) => {
269
+ toolkit.setOptions(verovioOptions(widthPx, options, leftMarginPx));
270
+ if (!toolkit.loadData(source))
271
+ return null;
272
+ // Bar numbers need numbered measures: ABC and Humdrum import theirs
273
+ // without `@n`. Numbered in order, and read again as MEI.
274
+ if (options.barNumbers !== 'none') {
275
+ const mei = toolkit.getMEI();
276
+ if (/<measure\b(?![^>]*\bn=)/.test(mei)) {
277
+ let n = 0;
278
+ if (!toolkit.loadData(mei.replace(/<measure\b(?![^>]*\bn=)/g, () => `<measure n="${++n}"`)))
279
+ return null;
280
+ }
281
+ }
282
+ const systems = [];
283
+ const pages = toolkit.getPageCount();
284
+ for (let p = 1; p <= pages; p++) {
285
+ const slice = toSystem(toolkit.renderToSVG(p), options, widthPx);
286
+ if (slice)
287
+ systems.push(slice);
288
+ }
289
+ return systems;
290
+ };
291
+ let systems = engrave(0);
292
+ // A brace or bracket joining staves stands left of them, past the
293
+ // measure's edge: engraved again with a left margin that takes it, the
294
+ // staves indented as far.
295
+ const overhang = systems ? -Math.min(0, ...systems.map((s) => itemsMinX(s.items))) : 0;
296
+ if (systems && overhang > 0.5)
297
+ systems = engrave(Math.ceil(overhang + 1));
298
+ const result = systems
299
+ ? { systems, ...meta }
300
+ : { systems: [], error: toolkit.getLog().trim() || `the ${format} source did not load`, ...meta };
301
+ cache.set(key, result);
302
+ if (cache.size > MAX_CACHE) {
303
+ const first = cache.keys().next().value;
304
+ if (first !== undefined)
305
+ cache.delete(first);
306
+ }
307
+ return result;
308
+ }
309
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/music/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { ScoreItem } from './types.js';
2
+ /**
3
+ * Flatten a Verovio page SVG into items in px of a slice `widthPx` wide.
4
+ * Returns the items and the slice height, or null when the markup is not
5
+ * Verovio's.
6
+ */
7
+ export declare function flattenVerovioSvg(svg: string, widthPx: number,
8
+ /** Groups left out by class (`mNum`: bar numbers). */
9
+ options?: {
10
+ skipClasses?: readonly string[];
11
+ }): {
12
+ items: ScoreItem[];
13
+ heightPx: number;
14
+ } | null;
15
+ /**
16
+ * Plain SVG for a flattened system: paths and text, `currentColor` ink, the
17
+ * text in `textFont`. HTML inlines it; the PDF backend draws it with its SVG
18
+ * vector subset.
19
+ */
20
+ export declare function itemsToSvg(items: readonly ScoreItem[], widthPx: number, heightPx: number, color: string, textFont: string): string;
21
+ //# sourceMappingURL=flatten.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flatten.d.ts","sourceRoot":"","sources":["../../src/music/flatten.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAwI5C;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM;AACf,sDAAsD;AACtD,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC5C;IAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA8IjD;AAQD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYlI"}
@@ -0,0 +1,302 @@
1
+ // Flatten one Verovio system (SVG) into painted items: filled or stroked
2
+ // paths with every transform baked in, and text runs, all in px of the
3
+ // slice. Canvas paints the items; HTML and PDF take the plain SVG written
4
+ // back from them (`itemsToSvg`), which needs no stylesheet, no `<use>` and
5
+ // no nested viewport.
6
+ //
7
+ // Verovio's markup is well-formed and regular — glyphs in `<defs>` drawn by
8
+ // `<use>`, staff lines as stroked paths, stems and bar lines as rects, beams
9
+ // as polygons, dots as ellipses, words as `<text>`/`<tspan>` — so a small
10
+ // tag scanner does.
11
+ import { multiply, parseSvgTransform, scale as scaleMatrix, transformPath, } from '../math/pathTransform.js';
12
+ const ATTR_RE = /([\w:-]+)\s*=\s*"([^"]*)"/g;
13
+ function decode(s) {
14
+ return s
15
+ .replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&apos;/g, "'")
16
+ .replace(/&#x([0-9a-f]+);/gi, (_, h) => String.fromCodePoint(parseInt(h, 16)))
17
+ .replace(/&#(\d+);/g, (_, d) => String.fromCodePoint(Number(d)))
18
+ .replace(/&amp;/g, '&');
19
+ }
20
+ function parse(svg) {
21
+ const root = { name: '#root', attrs: {}, children: [], text: '' };
22
+ const stack = [root];
23
+ let i = 0;
24
+ while (i < svg.length) {
25
+ const lt = svg.indexOf('<', i);
26
+ const top = stack[stack.length - 1];
27
+ if (lt < 0)
28
+ break;
29
+ if (lt > i)
30
+ top.text += decode(svg.slice(i, lt));
31
+ if (svg.startsWith('<!--', lt)) {
32
+ const end = svg.indexOf('-->', lt);
33
+ i = end < 0 ? svg.length : end + 3;
34
+ continue;
35
+ }
36
+ const gt = svg.indexOf('>', lt);
37
+ if (gt < 0)
38
+ break;
39
+ const tag = svg.slice(lt + 1, gt);
40
+ i = gt + 1;
41
+ if (tag.startsWith('?') || tag.startsWith('!'))
42
+ continue;
43
+ if (tag.startsWith('/')) {
44
+ if (stack.length > 1)
45
+ stack.pop();
46
+ continue;
47
+ }
48
+ const selfClosing = tag.endsWith('/');
49
+ const body = selfClosing ? tag.slice(0, -1) : tag;
50
+ const sp = body.search(/\s/);
51
+ const name = (sp < 0 ? body : body.slice(0, sp)).replace(/^.*:/, '');
52
+ const attrs = {};
53
+ for (const m of body.matchAll(ATTR_RE))
54
+ attrs[m[1].replace(/^xlink:/, '')] = decode(m[2]);
55
+ const el = { name, attrs, children: [], text: '' };
56
+ top.children.push(el);
57
+ if (!selfClosing)
58
+ stack.push(el);
59
+ }
60
+ return root.children.find((c) => c.name === 'svg') ?? null;
61
+ }
62
+ function num(v, fallback = 0) {
63
+ if (v === undefined)
64
+ return fallback;
65
+ const n = parseFloat(v);
66
+ return Number.isFinite(n) ? n : fallback;
67
+ }
68
+ function rectPath(x, y, w, h) {
69
+ return `M${x} ${y}L${x + w} ${y}L${x + w} ${y + h}L${x} ${y + h}Z`;
70
+ }
71
+ /** An ellipse as four cubic Béziers (κ = 0.5523). */
72
+ function ellipsePath(cx, cy, rx, ry) {
73
+ const k = 0.5522847498;
74
+ const ox = rx * k;
75
+ const oy = ry * k;
76
+ return `M${cx - rx} ${cy}`
77
+ + `C${cx - rx} ${cy - oy} ${cx - ox} ${cy - ry} ${cx} ${cy - ry}`
78
+ + `C${cx + ox} ${cy - ry} ${cx + rx} ${cy - oy} ${cx + rx} ${cy}`
79
+ + `C${cx + rx} ${cy + oy} ${cx + ox} ${cy + ry} ${cx} ${cy + ry}`
80
+ + `C${cx - ox} ${cy + ry} ${cx - rx} ${cy + oy} ${cx - rx} ${cy}Z`;
81
+ }
82
+ function pointsPath(points) {
83
+ const n = points.trim().split(/[\s,]+/).map(Number);
84
+ let d = '';
85
+ for (let k = 0; k + 1 < n.length; k += 2)
86
+ d += `${k === 0 ? 'M' : 'L'}${n[k]} ${n[k + 1]}`;
87
+ return d ? `${d}Z` : '';
88
+ }
89
+ /** Mean scale of a matrix: what a stroke width or font size is multiplied by. */
90
+ function lengthScale(m) {
91
+ return Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));
92
+ }
93
+ /** A path of straight segments only: a line, never a filled shape. */
94
+ const LINE_ONLY_RE = /^[\sMLHVmlhv\d.,eE+-]*$/;
95
+ const BOLD_CLASSES = new Set(['ending', 'fing', 'reh', 'tempo']);
96
+ const ITALIC_CLASSES = new Set(['dir', 'dynam', 'mNum']);
97
+ /** The words of a `<text>`, one run per `<tspan>` that holds any, with the
98
+ * size, style and baseline shift each is set at: a figure raised or
99
+ * lowered beside a chord symbol (V₇, the figures of a figured bass) is a
100
+ * smaller run with a `dy` of its own. */
101
+ function leafRuns(el, inherited, at) {
102
+ const size = el.attrs['font-size'] !== undefined ? num(el.attrs['font-size'], inherited) : inherited;
103
+ const dx = num(el.attrs.dx);
104
+ at.rise += num(el.attrs.dy);
105
+ const own = el.text.replace(/\s+/g, ' ');
106
+ const out = [];
107
+ if (own.trim())
108
+ out.push({ text: own.trim(), size, style: el.attrs['font-style'], weight: el.attrs['font-weight'], rise: at.rise, dx });
109
+ let first = out.length === 0;
110
+ for (const c of el.children) {
111
+ if (c.name !== 'tspan')
112
+ continue;
113
+ for (const r of leafRuns(c, size, at)) {
114
+ out.push({ ...r, style: r.style ?? el.attrs['font-style'], weight: r.weight ?? el.attrs['font-weight'], dx: r.dx + (first ? dx : 0) });
115
+ first = false;
116
+ }
117
+ }
118
+ return out;
119
+ }
120
+ /**
121
+ * Flatten a Verovio page SVG into items in px of a slice `widthPx` wide.
122
+ * Returns the items and the slice height, or null when the markup is not
123
+ * Verovio's.
124
+ */
125
+ export function flattenVerovioSvg(svg, widthPx,
126
+ /** Groups left out by class (`mNum`: bar numbers). */
127
+ options) {
128
+ const skip = new Set(options?.skipClasses ?? []);
129
+ const root = parse(svg);
130
+ if (!root)
131
+ return null;
132
+ const inner = root.children.find((c) => c.name === 'svg') ?? root;
133
+ const vb = (inner.attrs.viewBox ?? '').trim().split(/[\s,]+/).map(Number);
134
+ if (vb.length !== 4 || !(vb[2] > 0) || !(vb[3] > 0))
135
+ return null;
136
+ const s = widthPx / vb[2];
137
+ const base = multiply(scaleMatrix(s, s), [1, 0, 0, 1, -vb[0], -vb[1]]);
138
+ const heightPx = vb[3] * s;
139
+ const defs = new Map();
140
+ const collectDefs = (el) => {
141
+ for (const c of el.children) {
142
+ if (c.name === 'defs') {
143
+ for (const d of c.children)
144
+ if (d.attrs.id)
145
+ defs.set(d.attrs.id, d);
146
+ }
147
+ else {
148
+ collectDefs(c);
149
+ }
150
+ }
151
+ };
152
+ collectDefs(root);
153
+ const items = [];
154
+ const pushPath = (d, ctx, el) => {
155
+ if (!d)
156
+ return;
157
+ const fillAttr = el.attrs.fill;
158
+ const sw = el.attrs['stroke-width'] !== undefined ? num(el.attrs['stroke-width']) : ctx.strokeWidth;
159
+ const path = transformPath(d, ctx.matrix);
160
+ const stroked = sw !== undefined && sw > 0;
161
+ const filled = fillAttr !== 'none';
162
+ // Verovio strokes staff lines, ledger lines and bar lines with the
163
+ // stylesheet's `stroke: currentColor`; their `fill` is left to the
164
+ // default black, which on a path of straight lines paints nothing. Slurs
165
+ // and ties are curves both filled and stroked.
166
+ if (filled && !(stroked && el.name === 'path' && LINE_ONLY_RE.test(d))) {
167
+ items.push({ type: 'path', d: path, fill: true });
168
+ }
169
+ if (stroked) {
170
+ items.push({
171
+ type: 'path',
172
+ d: path,
173
+ fill: false,
174
+ strokeWidth: sw * lengthScale(ctx.matrix),
175
+ ...(el.attrs['stroke-linecap'] ? { lineCap: el.attrs['stroke-linecap'] } : {}),
176
+ });
177
+ }
178
+ };
179
+ const walk = (el, parent) => {
180
+ if (el.name === 'defs' || el.name === 'style' || el.name === 'desc' || el.name === 'title')
181
+ return;
182
+ let matrix = parent.matrix;
183
+ if (el.attrs.transform)
184
+ matrix = multiply(matrix, parseSvgTransform(el.attrs.transform));
185
+ const classes = (el.attrs.class ?? '').split(/\s+/);
186
+ if (classes.some((c) => skip.has(c)))
187
+ return;
188
+ const ctx = {
189
+ matrix,
190
+ bold: parent.bold || classes.some((c) => BOLD_CLASSES.has(c)),
191
+ italic: parent.italic || classes.some((c) => ITALIC_CLASSES.has(c)),
192
+ strokeWidth: el.attrs['stroke-width'] !== undefined ? num(el.attrs['stroke-width']) : parent.strokeWidth,
193
+ };
194
+ switch (el.name) {
195
+ case 'svg':
196
+ if (el !== inner && el !== root) {
197
+ // A nested viewport (Verovio uses none inside a system; skip safely).
198
+ return;
199
+ }
200
+ break;
201
+ case 'g':
202
+ break;
203
+ case 'use': {
204
+ const ref = defs.get((el.attrs.href ?? '').replace(/^#/, ''));
205
+ if (!ref)
206
+ return;
207
+ const m = multiply(ctx.matrix, [1, 0, 0, 1, num(el.attrs.x), num(el.attrs.y)]);
208
+ walk(ref, { ...ctx, matrix: m });
209
+ return;
210
+ }
211
+ case 'path':
212
+ pushPath(el.attrs.d ?? '', ctx, el);
213
+ return;
214
+ case 'rect':
215
+ pushPath(rectPath(num(el.attrs.x), num(el.attrs.y), num(el.attrs.width), num(el.attrs.height)), ctx, el);
216
+ return;
217
+ case 'polygon':
218
+ pushPath(pointsPath(el.attrs.points ?? ''), ctx, el);
219
+ return;
220
+ case 'polyline': {
221
+ const d = pointsPath(el.attrs.points ?? '').replace(/Z$/, '');
222
+ pushPath(d, { ...ctx, strokeWidth: ctx.strokeWidth ?? 1 }, { ...el, attrs: { ...el.attrs, fill: 'none' } });
223
+ return;
224
+ }
225
+ case 'ellipse':
226
+ case 'circle': {
227
+ const rx = num(el.attrs.rx ?? el.attrs.r);
228
+ const ry = num(el.attrs.ry ?? el.attrs.r);
229
+ pushPath(ellipsePath(num(el.attrs.cx), num(el.attrs.cy), rx, ry), ctx, el);
230
+ return;
231
+ }
232
+ case 'text': {
233
+ const runs = leafRuns(el, num(el.attrs['font-size'], 0), { rise: 0 }).filter((r) => r.size > 0);
234
+ const text = runs.map((r) => r.text).join('');
235
+ const size = runs[0]?.size ?? 0;
236
+ if (!text || !(size > 0))
237
+ return;
238
+ const [x, y] = [num(el.attrs.x), num(el.attrs.y)];
239
+ const m = ctx.matrix;
240
+ const k = lengthScale(m);
241
+ const anchor = el.attrs['text-anchor'];
242
+ // Runs of one size on one baseline read as one word; others keep
243
+ // their sizes and shifts, laid side by side when the engine can
244
+ // measure them (`layOutRuns`).
245
+ const plain = runs.every((r) => r.size === size && r.rise === 0 && r.dx === 0);
246
+ items.push({
247
+ type: 'text',
248
+ x: m[0] * x + m[2] * y + m[4],
249
+ y: m[1] * x + m[3] * y + m[5],
250
+ text,
251
+ sizePx: size * k,
252
+ bold: ctx.bold || runs.some((r) => r.weight === 'bold'),
253
+ italic: ctx.italic || runs.some((r) => r.style === 'italic'),
254
+ ...(anchor === 'middle' || anchor === 'end' ? { anchor } : {}),
255
+ ...(plain ? {} : {
256
+ runs: runs.map((r) => ({
257
+ text: r.text,
258
+ sizePx: r.size * k,
259
+ rise: r.rise * k,
260
+ dx: r.dx * k,
261
+ ...(r.weight === 'bold' ? { bold: true } : {}),
262
+ ...(r.style === 'italic' ? { italic: true } : {}),
263
+ })),
264
+ }),
265
+ });
266
+ return;
267
+ }
268
+ default:
269
+ break;
270
+ }
271
+ for (const c of el.children)
272
+ walk(c, ctx);
273
+ };
274
+ const start = { matrix: base, bold: false, italic: false, strokeWidth: undefined };
275
+ for (const c of inner.children)
276
+ walk(c, start);
277
+ return { items, heightPx };
278
+ }
279
+ function esc(s) {
280
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
281
+ }
282
+ const r2 = (n) => String(Math.round(n * 100) / 100);
283
+ /**
284
+ * Plain SVG for a flattened system: paths and text, `currentColor` ink, the
285
+ * text in `textFont`. HTML inlines it; the PDF backend draws it with its SVG
286
+ * vector subset.
287
+ */
288
+ export function itemsToSvg(items, widthPx, heightPx, color, textFont) {
289
+ const out = [];
290
+ for (const it of items) {
291
+ if (it.type === 'path') {
292
+ out.push(it.fill
293
+ ? `<path d="${it.d}" fill="${color}"/>`
294
+ : `<path d="${it.d}" fill="none" stroke="${color}" stroke-width="${r2(it.strokeWidth ?? 1)}"${it.lineCap ? ` stroke-linecap="${it.lineCap}"` : ''}/>`);
295
+ }
296
+ else {
297
+ out.push(`<text x="${r2(it.x)}" y="${r2(it.y)}" font-size="${r2(it.sizePx)}"${it.bold ? ' font-weight="bold"' : ''}${it.italic ? ' font-style="italic"' : ''}${it.anchor ? ` text-anchor="${it.anchor}"` : ''} fill="${color}">${esc(it.text)}</text>`);
298
+ }
299
+ }
300
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${r2(widthPx)}" height="${r2(heightPx)}" viewBox="0 0 ${r2(widthPx)} ${r2(heightPx)}" font-family="${esc(textFont)}">${out.join('')}</svg>`;
301
+ }
302
+ //# sourceMappingURL=flatten.js.map