postext 1.29.2 → 1.30.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 (275) hide show
  1. package/dist/__tests__/arabicLocale.test.js +5 -5
  2. package/dist/__tests__/arabicLocale.test.js.map +1 -1
  3. package/dist/__tests__/bundle/balloonPlacementPin.test.js +5 -4
  4. package/dist/__tests__/bundle/balloonPlacementPin.test.js.map +1 -1
  5. package/dist/__tests__/bundle/cjkRulesPin.test.js +8 -6
  6. package/dist/__tests__/bundle/cjkRulesPin.test.js.map +1 -1
  7. package/dist/__tests__/bundle/designOverflowPin.test.js +1 -1
  8. package/dist/__tests__/bundle/flowColumnsPin.test.js +4 -3
  9. package/dist/__tests__/bundle/flowColumnsPin.test.js.map +1 -1
  10. package/dist/__tests__/bundle/gridBalancingPin.test.js +5 -4
  11. package/dist/__tests__/bundle/gridBalancingPin.test.js.map +1 -1
  12. package/dist/__tests__/bundle/gridBreakRulesPin.test.js +14 -10
  13. package/dist/__tests__/bundle/gridBreakRulesPin.test.js.map +1 -1
  14. package/dist/__tests__/bundle/indexGroupSplitPin.test.js +4 -3
  15. package/dist/__tests__/bundle/indexGroupSplitPin.test.js.map +1 -1
  16. package/dist/__tests__/bundle/looseOrderPin.test.js +5 -4
  17. package/dist/__tests__/bundle/looseOrderPin.test.js.map +1 -1
  18. package/dist/__tests__/bundle/refLabelBreaksPin.test.js +5 -4
  19. package/dist/__tests__/bundle/refLabelBreaksPin.test.js.map +1 -1
  20. package/dist/__tests__/bundle/scriptContextPin.test.js +6 -5
  21. package/dist/__tests__/bundle/scriptContextPin.test.js.map +1 -1
  22. package/dist/__tests__/bundle/shapingLanguagePin.test.js +142 -46
  23. package/dist/__tests__/bundle/shapingLanguagePin.test.js.map +1 -1
  24. package/dist/__tests__/bundle/taskBoxPin.test.js +1 -1
  25. package/dist/__tests__/bundle/trailingStepPin.test.js +4 -3
  26. package/dist/__tests__/bundle/trailingStepPin.test.js.map +1 -1
  27. package/dist/__tests__/bundle/wideFloatStretchPin.test.js +4 -3
  28. package/dist/__tests__/bundle/wideFloatStretchPin.test.js.map +1 -1
  29. package/dist/__tests__/bundle.test.js +1 -1
  30. package/dist/__tests__/cellText.test.d.ts +2 -0
  31. package/dist/__tests__/cellText.test.d.ts.map +1 -0
  32. package/dist/__tests__/cellText.test.js +281 -0
  33. package/dist/__tests__/cellText.test.js.map +1 -0
  34. package/dist/__tests__/chineseLocale.test.js +13 -11
  35. package/dist/__tests__/chineseLocale.test.js.map +1 -1
  36. package/dist/__tests__/cjk/japaneseHtml.test.js +3 -3
  37. package/dist/__tests__/cjk/japaneseHtml.test.js.map +1 -1
  38. package/dist/__tests__/cjk/japaneseRuby.test.js +1 -1
  39. package/dist/__tests__/cjk/japaneseRuby.test.js.map +1 -1
  40. package/dist/__tests__/cjk/japaneseSegmentLanguage.test.js +3 -3
  41. package/dist/__tests__/cjk/japaneseSegmentLanguage.test.js.map +1 -1
  42. package/dist/__tests__/codeBlocks.test.js +1 -1
  43. package/dist/__tests__/contextText.test.d.ts +2 -0
  44. package/dist/__tests__/contextText.test.d.ts.map +1 -0
  45. package/dist/__tests__/contextText.test.js +371 -0
  46. package/dist/__tests__/contextText.test.js.map +1 -0
  47. package/dist/__tests__/design/designTextRender.test.js +8 -1
  48. package/dist/__tests__/design/designTextRender.test.js.map +1 -1
  49. package/dist/__tests__/exports.test.js +6 -0
  50. package/dist/__tests__/exports.test.js.map +1 -1
  51. package/dist/__tests__/fontUsage.test.js +40 -0
  52. package/dist/__tests__/fontUsage.test.js.map +1 -1
  53. package/dist/__tests__/hardBreaks.test.js +1 -1
  54. package/dist/__tests__/headingInlineMarks.test.js +1 -1
  55. package/dist/__tests__/html-backend.test.js +6 -2
  56. package/dist/__tests__/html-backend.test.js.map +1 -1
  57. package/dist/__tests__/japaneseNotes.test.js +4 -2
  58. package/dist/__tests__/japaneseNotes.test.js.map +1 -1
  59. package/dist/__tests__/lineEndPieces.test.d.ts +2 -0
  60. package/dist/__tests__/lineEndPieces.test.d.ts.map +1 -0
  61. package/dist/__tests__/lineEndPieces.test.js +374 -0
  62. package/dist/__tests__/lineEndPieces.test.js.map +1 -0
  63. package/dist/__tests__/mathSizeMigration.test.js +2 -2
  64. package/dist/__tests__/pipeline/calloutInlineResourceGap.test.js +1 -1
  65. package/dist/__tests__/pipeline/calloutSplitMinLinesChild.test.js +1 -1
  66. package/dist/__tests__/pipeline/colonListRoom.test.js +1 -1
  67. package/dist/__tests__/pipeline/compoundBreaks.test.js +1 -1
  68. package/dist/__tests__/pipeline/dashBreaks.test.js +1 -1
  69. package/dist/__tests__/pipeline/headingSplitOrphans.test.js +1 -1
  70. package/dist/__tests__/pipeline/inlineFigureSpace.test.js +1 -1
  71. package/dist/__tests__/pipeline/paragraphContainerTail.test.js +1 -1
  72. package/dist/__tests__/pipeline/raggedOptimal.test.js +1 -1
  73. package/dist/__tests__/plainGeminateHead.test.d.ts +2 -0
  74. package/dist/__tests__/plainGeminateHead.test.d.ts.map +1 -0
  75. package/dist/__tests__/plainGeminateHead.test.js +92 -0
  76. package/dist/__tests__/plainGeminateHead.test.js.map +1 -0
  77. package/dist/__tests__/presets/showcaseShapingLanguage.test.d.ts +2 -0
  78. package/dist/__tests__/presets/showcaseShapingLanguage.test.d.ts.map +1 -0
  79. package/dist/__tests__/presets/showcaseShapingLanguage.test.js +52 -0
  80. package/dist/__tests__/presets/showcaseShapingLanguage.test.js.map +1 -0
  81. package/dist/__tests__/reshapedTracking.test.d.ts +2 -0
  82. package/dist/__tests__/reshapedTracking.test.d.ts.map +1 -0
  83. package/dist/__tests__/reshapedTracking.test.js +358 -0
  84. package/dist/__tests__/reshapedTracking.test.js.map +1 -0
  85. package/dist/__tests__/rtl/designRunsPainted.test.d.ts +2 -0
  86. package/dist/__tests__/rtl/designRunsPainted.test.d.ts.map +1 -0
  87. package/dist/__tests__/rtl/designRunsPainted.test.js +184 -0
  88. package/dist/__tests__/rtl/designRunsPainted.test.js.map +1 -0
  89. package/dist/__tests__/rtl/designTextPaint.test.js +5 -1
  90. package/dist/__tests__/rtl/designTextPaint.test.js.map +1 -1
  91. package/dist/__tests__/rtl/htmlRtl.test.js +3 -3
  92. package/dist/__tests__/rtl/htmlRtl.test.js.map +1 -1
  93. package/dist/__tests__/rtl/listMarkerDirection.test.js +28 -28
  94. package/dist/__tests__/rtl/listMarkerDirection.test.js.map +1 -1
  95. package/dist/__tests__/rtl/tocNumberPainted.test.d.ts +2 -0
  96. package/dist/__tests__/rtl/tocNumberPainted.test.d.ts.map +1 -0
  97. package/dist/__tests__/rtl/tocNumberPainted.test.js +113 -0
  98. package/dist/__tests__/rtl/tocNumberPainted.test.js.map +1 -0
  99. package/dist/__tests__/scriptContext.test.js +141 -1
  100. package/dist/__tests__/scriptContext.test.js.map +1 -1
  101. package/dist/__tests__/shapingLanguage.test.js +54 -41
  102. package/dist/__tests__/shapingLanguage.test.js.map +1 -1
  103. package/dist/__tests__/trackedLetters.test.d.ts +2 -0
  104. package/dist/__tests__/trackedLetters.test.d.ts.map +1 -0
  105. package/dist/__tests__/trackedLetters.test.js +380 -0
  106. package/dist/__tests__/trackedLetters.test.js.map +1 -0
  107. package/dist/__tests__/trackedLigatures.test.js +17 -5
  108. package/dist/__tests__/trackedLigatures.test.js.map +1 -1
  109. package/dist/__tests__/verseLines.test.js +1 -1
  110. package/dist/__tests__/wordCacheOrder.test.d.ts +2 -0
  111. package/dist/__tests__/wordCacheOrder.test.d.ts.map +1 -0
  112. package/dist/__tests__/wordCacheOrder.test.js +352 -0
  113. package/dist/__tests__/wordCacheOrder.test.js.map +1 -0
  114. package/dist/__tests__/wordPieces.test.d.ts +2 -0
  115. package/dist/__tests__/wordPieces.test.d.ts.map +1 -0
  116. package/dist/__tests__/wordPieces.test.js +762 -0
  117. package/dist/__tests__/wordPieces.test.js.map +1 -0
  118. package/dist/bidi.d.ts +12 -0
  119. package/dist/bidi.d.ts.map +1 -1
  120. package/dist/bidi.js +23 -0
  121. package/dist/bidi.js.map +1 -1
  122. package/dist/bundle/configVersion.d.ts +49 -23
  123. package/dist/bundle/configVersion.d.ts.map +1 -1
  124. package/dist/bundle/configVersion.js +54 -25
  125. package/dist/bundle/configVersion.js.map +1 -1
  126. package/dist/canvas-backend/blockRender.d.ts.map +1 -1
  127. package/dist/canvas-backend/blockRender.js +58 -27
  128. package/dist/canvas-backend/blockRender.js.map +1 -1
  129. package/dist/canvas-backend/cellText.d.ts +12 -0
  130. package/dist/canvas-backend/cellText.d.ts.map +1 -0
  131. package/dist/canvas-backend/cellText.js +114 -0
  132. package/dist/canvas-backend/cellText.js.map +1 -0
  133. package/dist/canvas-backend/chip.d.ts.map +1 -1
  134. package/dist/canvas-backend/chip.js +2 -1
  135. package/dist/canvas-backend/chip.js.map +1 -1
  136. package/dist/canvas-backend/contextState.d.ts +7 -0
  137. package/dist/canvas-backend/contextState.d.ts.map +1 -1
  138. package/dist/canvas-backend/contextState.js +7 -0
  139. package/dist/canvas-backend/contextState.js.map +1 -1
  140. package/dist/canvas-backend/contextText.d.ts +76 -0
  141. package/dist/canvas-backend/contextText.d.ts.map +1 -0
  142. package/dist/canvas-backend/contextText.js +102 -0
  143. package/dist/canvas-backend/contextText.js.map +1 -0
  144. package/dist/canvas-backend/headerFooter.d.ts.map +1 -1
  145. package/dist/canvas-backend/headerFooter.js +8 -1
  146. package/dist/canvas-backend/headerFooter.js.map +1 -1
  147. package/dist/canvas-backend/index.d.ts.map +1 -1
  148. package/dist/canvas-backend/index.js +19 -13
  149. package/dist/canvas-backend/index.js.map +1 -1
  150. package/dist/canvas-backend/renderResourceBlock.d.ts.map +1 -1
  151. package/dist/canvas-backend/renderResourceBlock.js +12 -6
  152. package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
  153. package/dist/canvas-backend/scriptText.d.ts.map +1 -1
  154. package/dist/canvas-backend/scriptText.js +3 -2
  155. package/dist/canvas-backend/scriptText.js.map +1 -1
  156. package/dist/canvas-backend/segmentText.d.ts.map +1 -1
  157. package/dist/canvas-backend/segmentText.js +8 -2
  158. package/dist/canvas-backend/segmentText.js.map +1 -1
  159. package/dist/canvas-backend/trackedText.d.ts +75 -1
  160. package/dist/canvas-backend/trackedText.d.ts.map +1 -1
  161. package/dist/canvas-backend/trackedText.js +185 -22
  162. package/dist/canvas-backend/trackedText.js.map +1 -1
  163. package/dist/canvas-backend/verticalText.d.ts +9 -0
  164. package/dist/canvas-backend/verticalText.d.ts.map +1 -1
  165. package/dist/canvas-backend/verticalText.js +29 -7
  166. package/dist/canvas-backend/verticalText.js.map +1 -1
  167. package/dist/canvas-backend/wordPieces.d.ts +31 -0
  168. package/dist/canvas-backend/wordPieces.d.ts.map +1 -0
  169. package/dist/canvas-backend/wordPieces.js +132 -0
  170. package/dist/canvas-backend/wordPieces.js.map +1 -0
  171. package/dist/canvas-backend/wordRuns.d.ts +3 -1
  172. package/dist/canvas-backend/wordRuns.d.ts.map +1 -1
  173. package/dist/canvas-backend/wordRuns.js +10 -6
  174. package/dist/canvas-backend/wordRuns.js.map +1 -1
  175. package/dist/comics/lettering/__tests__/fitAsPainted.test.d.ts +2 -0
  176. package/dist/comics/lettering/__tests__/fitAsPainted.test.d.ts.map +1 -0
  177. package/dist/comics/lettering/__tests__/fitAsPainted.test.js +97 -0
  178. package/dist/comics/lettering/__tests__/fitAsPainted.test.js.map +1 -0
  179. package/dist/comics/lettering/shape-text.d.ts.map +1 -1
  180. package/dist/comics/lettering/shape-text.js +39 -11
  181. package/dist/comics/lettering/shape-text.js.map +1 -1
  182. package/dist/defaults/bodyText.d.ts.map +1 -1
  183. package/dist/defaults/bodyText.js +6 -5
  184. package/dist/defaults/bodyText.js.map +1 -1
  185. package/dist/design/bidiText.d.ts +45 -6
  186. package/dist/design/bidiText.d.ts.map +1 -1
  187. package/dist/design/bidiText.js +78 -10
  188. package/dist/design/bidiText.js.map +1 -1
  189. package/dist/design/cjkText.d.ts +3 -0
  190. package/dist/design/cjkText.d.ts.map +1 -1
  191. package/dist/design/cjkText.js +1 -1
  192. package/dist/design/cjkText.js.map +1 -1
  193. package/dist/design/layout.d.ts.map +1 -1
  194. package/dist/design/layout.js +36 -5
  195. package/dist/design/layout.js.map +1 -1
  196. package/dist/design/richText.d.ts +9 -1
  197. package/dist/design/richText.d.ts.map +1 -1
  198. package/dist/design/richText.js +8 -2
  199. package/dist/design/richText.js.map +1 -1
  200. package/dist/fonts/usage.d.ts +2 -0
  201. package/dist/fonts/usage.d.ts.map +1 -1
  202. package/dist/fonts/usage.js +18 -0
  203. package/dist/fonts/usage.js.map +1 -1
  204. package/dist/html-backend.d.ts.map +1 -1
  205. package/dist/html-backend.js +664 -84
  206. package/dist/html-backend.js.map +1 -1
  207. package/dist/index.d.ts +3 -1
  208. package/dist/index.d.ts.map +1 -1
  209. package/dist/index.js +4 -1
  210. package/dist/index.js.map +1 -1
  211. package/dist/knuthPlass/breakpoints.d.ts.map +1 -1
  212. package/dist/knuthPlass/breakpoints.js +4 -2
  213. package/dist/knuthPlass/breakpoints.js.map +1 -1
  214. package/dist/knuthPlass/pretextAdapter.d.ts +6 -3
  215. package/dist/knuthPlass/pretextAdapter.d.ts.map +1 -1
  216. package/dist/knuthPlass/pretextAdapter.js +11 -3
  217. package/dist/knuthPlass/pretextAdapter.js.map +1 -1
  218. package/dist/knuthPlass/richAdapter.d.ts +13 -1
  219. package/dist/knuthPlass/richAdapter.d.ts.map +1 -1
  220. package/dist/knuthPlass/richAdapter.js +53 -5
  221. package/dist/knuthPlass/richAdapter.js.map +1 -1
  222. package/dist/knuthPlass/tracking.d.ts.map +1 -1
  223. package/dist/knuthPlass/tracking.js +3 -2
  224. package/dist/knuthPlass/tracking.js.map +1 -1
  225. package/dist/knuthPlass/types.d.ts +6 -0
  226. package/dist/knuthPlass/types.d.ts.map +1 -1
  227. package/dist/locale.d.ts +21 -17
  228. package/dist/locale.d.ts.map +1 -1
  229. package/dist/locale.js +23 -19
  230. package/dist/locale.js.map +1 -1
  231. package/dist/measure/canvas.d.ts +21 -0
  232. package/dist/measure/canvas.d.ts.map +1 -1
  233. package/dist/measure/canvas.js +165 -85
  234. package/dist/measure/canvas.js.map +1 -1
  235. package/dist/measure/cjkCompose.d.ts.map +1 -1
  236. package/dist/measure/cjkCompose.js +31 -5
  237. package/dist/measure/cjkCompose.js.map +1 -1
  238. package/dist/measure/plain.d.ts.map +1 -1
  239. package/dist/measure/plain.js +31 -6
  240. package/dist/measure/plain.js.map +1 -1
  241. package/dist/measure/pretextLanguage.d.ts.map +1 -1
  242. package/dist/measure/pretextLanguage.js +49 -7
  243. package/dist/measure/pretextLanguage.js.map +1 -1
  244. package/dist/measure/rich.d.ts +18 -1
  245. package/dist/measure/rich.d.ts.map +1 -1
  246. package/dist/measure/rich.js +200 -29
  247. package/dist/measure/rich.js.map +1 -1
  248. package/dist/measure/script.d.ts +17 -1
  249. package/dist/measure/script.d.ts.map +1 -1
  250. package/dist/measure/script.js +17 -1
  251. package/dist/measure/script.js.map +1 -1
  252. package/dist/measure/trackedLigatures.d.ts +59 -0
  253. package/dist/measure/trackedLigatures.d.ts.map +1 -0
  254. package/dist/measure/trackedLigatures.js +144 -0
  255. package/dist/measure/trackedLigatures.js.map +1 -0
  256. package/dist/pipeline/build.d.ts.map +1 -1
  257. package/dist/pipeline/build.js +4 -3
  258. package/dist/pipeline/build.js.map +1 -1
  259. package/dist/pipeline/calloutLayout.d.ts.map +1 -1
  260. package/dist/pipeline/calloutLayout.js +26 -7
  261. package/dist/pipeline/calloutLayout.js.map +1 -1
  262. package/dist/pipeline/lists.d.ts +13 -4
  263. package/dist/pipeline/lists.d.ts.map +1 -1
  264. package/dist/pipeline/lists.js +49 -12
  265. package/dist/pipeline/lists.js.map +1 -1
  266. package/dist/pipeline/toc.d.ts.map +1 -1
  267. package/dist/pipeline/toc.js +33 -9
  268. package/dist/pipeline/toc.js.map +1 -1
  269. package/dist/types.d.ts +35 -26
  270. package/dist/types.d.ts.map +1 -1
  271. package/dist/wordPieces.d.ts +120 -0
  272. package/dist/wordPieces.d.ts.map +1 -0
  273. package/dist/wordPieces.js +319 -0
  274. package/dist/wordPieces.js.map +1 -0
  275. package/package.json +1 -1
@@ -0,0 +1,374 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { clearMeasurementCache } from '../measure';
3
+ import { setMeasureLanguage } from '../measure/canvas';
4
+ import { measureRichBlock } from '../measure/rich';
5
+ import { setHyphenationLocale } from '../hyphenate';
6
+ // #770, round 2: the two halves of a word broken at a line end. In a
7
+ // paragraph cut word by word a piece of a word was as wide as the word
8
+ // grew by it, so the rest that opens the next line was the whole word
9
+ // less what stayed above: whatever the face draws across the break (the
10
+ // wide dot of a Catalan `l·l`, a ligature, a kerned pair) stayed in a box
11
+ // nothing paints it in. A document shaped in its own language measures
12
+ // each half as the text painted; one that keeps the host's language keeps
13
+ // the widths it had.
14
+ const SHY = '­';
15
+ const DOT = '·';
16
+ const sizeOf = (font) => parseFloat(/(\d*\.?\d+)px/.exec(font)?.[1] ?? '10');
17
+ /**
18
+ * The advance of `text` in a face that draws across its letters, px at
19
+ * 10 px: every letter 5; a space 2.5; a hyphen 3; a full stop 2. `Punt`
20
+ * (as Crimson Pro) sets the middle dot 6 between two `l` in Catalan and
21
+ * 2.5 anywhere else. `Lliga` (as Lora) sets it 2.5 and ligates `l·`,
22
+ * 1.3 narrower. Both: `ff` a ligature 2 narrower, `fi` one 1 narrower,
23
+ * `yo` kerned 1, `o.` kerned 0.5, `-y` kerned 0.4.
24
+ */
25
+ function faceWidth(text, font, lang) {
26
+ const catalan = lang.toLowerCase().split('-')[0] === 'ca';
27
+ const lliga = font.includes('Lliga');
28
+ const chars = Array.from(text);
29
+ let px = 0;
30
+ chars.forEach((ch, i) => {
31
+ const prev = chars[i - 1];
32
+ const next = chars[i + 1];
33
+ if (ch === ' ' || ch === ' ')
34
+ px += 2.5;
35
+ else if (ch === '-')
36
+ px += 3;
37
+ else if (ch === '.')
38
+ px += 2;
39
+ else if (ch === DOT)
40
+ px += !lliga && catalan && prev === 'l' && next === 'l' ? 6 : 2.5;
41
+ else if (ch.codePointAt(0) >= 0x2E80)
42
+ px += 10;
43
+ else
44
+ px += 5;
45
+ const pair = `${prev ?? ''}${ch}`;
46
+ if (pair === 'ff')
47
+ px -= 2;
48
+ if (pair === 'fi')
49
+ px -= 1;
50
+ if (pair === 'yo')
51
+ px -= 1;
52
+ if (pair === 'o.')
53
+ px -= 0.5;
54
+ if (pair === '-y')
55
+ px -= 0.4;
56
+ if (lliga && pair === `l${DOT}`)
57
+ px -= 1.3;
58
+ });
59
+ return (px * sizeOf(font)) / 10;
60
+ }
61
+ /** The language of the page the layout runs on: what a context left at
62
+ * `inherit` measures in. */
63
+ let host = 'en';
64
+ class MeasureContext {
65
+ font = '10px Punt';
66
+ lang = 'inherit';
67
+ direction = 'ltr';
68
+ measureText(s) {
69
+ return { width: faceWidth(s, this.font, this.lang === 'inherit' ? host : this.lang) };
70
+ }
71
+ }
72
+ const globals = globalThis;
73
+ globals.OffscreenCanvasRenderingContext2D = MeasureContext;
74
+ globals.OffscreenCanvas = class {
75
+ getContext() {
76
+ return new MeasureContext();
77
+ }
78
+ };
79
+ const PUNT = '10px Punt';
80
+ const LLIGA = '10px Lliga';
81
+ const HYPHEN = 3;
82
+ /** The width of `text` painted alone in `lang`, to a thousandth. */
83
+ const ink = (text, lang, font = PUNT) => faceWidth(text, font, lang);
84
+ const round = (n) => Math.round(n * 1000) / 1000;
85
+ const DOCUMENT_CA = { language: 'ca', locale: 'ca' };
86
+ const HOST_CA = { language: undefined, locale: 'ca' };
87
+ const DOCUMENT_EN = { language: 'en', locale: 'en-us' };
88
+ const HOST_EN = { language: undefined, locale: 'en-us' };
89
+ /** The two breakers: line by line, and Knuth–Plass on a justified text. */
90
+ const GREEDY = { textAlign: 'left', hyphenate: true };
91
+ const OPTIMAL = { textAlign: 'justify', hyphenate: true, optimal: true };
92
+ function lay(text, width, mode, options, font = PUNT) {
93
+ setHyphenationLocale(mode.locale);
94
+ setMeasureLanguage(mode.language);
95
+ return measureRichBlock([{ text, bold: false, italic: false }], font, font, font, font, width, 14, options).lines;
96
+ }
97
+ const words = (line) => (line.segments ?? []).filter((s) => s.kind === 'text');
98
+ /** The text pieces a line carries, each with its width to a thousandth. */
99
+ const pieces = (line) => words(line).map((s) => [s.text, round(s.width)]);
100
+ /** The pieces a line opens with up to its first space, joined: the rest
101
+ * of the word broken at the line before, and its width. */
102
+ function opening(line) {
103
+ let text = '';
104
+ let width = 0;
105
+ for (const s of line.segments ?? []) {
106
+ if (s.kind === 'space')
107
+ break;
108
+ text += s.text;
109
+ width += s.width;
110
+ }
111
+ return [text, round(width)];
112
+ }
113
+ /** The pieces a line ends on, back to its last space, joined. */
114
+ function closing(line) {
115
+ const segs = line.segments ?? [];
116
+ let text = '';
117
+ let width = 0;
118
+ for (let i = segs.length - 1; i >= 0 && segs[i].kind !== 'space'; i--) {
119
+ text = segs[i].text + text;
120
+ width += segs[i].width;
121
+ }
122
+ return [text, round(width)];
123
+ }
124
+ beforeEach(() => {
125
+ host = 'en';
126
+ clearMeasurementCache();
127
+ });
128
+ afterEach(() => {
129
+ setMeasureLanguage(undefined);
130
+ setHyphenationLocale('en-us');
131
+ });
132
+ describe.each([['line by line', GREEDY], ['Knuth–Plass', OPTIMAL]])('a word broken at a line end, %s', (_name, options) => {
133
+ it('the rest of a Catalan word broken inside its l·l is as wide as the text painted', () => {
134
+ // `instal·lar` is 51 px whole in Catalan (the dot 6 px between its two
135
+ // `l`) and `instal·` 32.5 px: the rest was 18.5 px for `lar`, 15 px.
136
+ const text = `aa instal${DOT}lar bb cc`;
137
+ const own = lay(text, 47, DOCUMENT_CA, options);
138
+ expect(own.map((l) => l.text)).toEqual(['aa instal-', 'lar bb cc']);
139
+ expect(opening(own[1])).toEqual(['lar', ink('lar', 'ca')]);
140
+ expect(opening(own[1])[1]).toBe(15);
141
+ // On a Catalan page a document that keeps the host's language is
142
+ // measured in Catalan too, and keeps the rest it had: what the word
143
+ // grew by, the wide dot in it.
144
+ host = 'ca';
145
+ clearMeasurementCache();
146
+ const kept = lay(text, 47, HOST_CA, options);
147
+ expect(kept.map((l) => l.text)).toEqual(['aa instal-', 'lar bb cc']);
148
+ expect(opening(kept[1])).toEqual(['lar', 18.5]);
149
+ });
150
+ it('the breaker counts the rest at the width painted: a line it fits is set', () => {
151
+ // `lar bb cc dd` is 52.5 px as painted and fits a measure of 54; with
152
+ // the rest at 18.5 px it was 56 px, and `dd` went down.
153
+ const text = `aa instal${DOT}lar bb cc dd`;
154
+ host = 'ca';
155
+ clearMeasurementCache();
156
+ expect(lay(text, 54, DOCUMENT_CA, options).map((l) => l.text)).toEqual(['aa instal-', 'lar bb cc dd']);
157
+ expect(lay(text, 54, HOST_CA, options).length).toBeGreaterThan(2);
158
+ });
159
+ it('a ligature undone by the break is not kept in the rest', () => {
160
+ // `office` 27 px (ffi), `of` 10: the rest was 17 px for `fice`, 19 px.
161
+ const text = `aa of${SHY}fice bb`;
162
+ const own = lay(text, 27, DOCUMENT_EN, options);
163
+ expect(own.map((l) => l.text)).toEqual(['aa of-', 'fice', 'bb']);
164
+ expect(opening(own[1])).toEqual(['fice', 19]);
165
+ expect(closing(own[0])).toEqual(['of-', ink('of', 'en') + HYPHEN]);
166
+ const host = lay(text, 27, HOST_EN, options);
167
+ expect(host.map((l) => l.text)).toEqual(['aa of-', 'fice', 'bb']);
168
+ expect(opening(host[1])).toEqual(['fice', 17]);
169
+ expect(closing(host[0])).toEqual(['of-', 13]);
170
+ });
171
+ it('the head of a break inside an l·l is the text before the dot and its hyphen', () => {
172
+ // Lliga ligates `l·`: `col·` is 16.2 px and the dot alone 2.5, so the
173
+ // head was 13.7 px and its hyphen for `col`, 15 px.
174
+ const text = `aa col${DOT}lecció bb`;
175
+ const own = lay(text, 32, DOCUMENT_CA, options, LLIGA);
176
+ expect(own[0].text).toBe('aa col-');
177
+ expect(closing(own[0])).toEqual(['col-', ink('col', 'ca', LLIGA) + HYPHEN]);
178
+ expect(closing(own[0])[1]).toBe(18);
179
+ const host = lay(text, 32, HOST_CA, options, LLIGA);
180
+ expect(host[0].text).toBe('aa col-');
181
+ expect(closing(host[0])[1]).toBe(16.7);
182
+ });
183
+ it('the pieces of the rest are as wide as that rest grows by them', () => {
184
+ // `official` broken after `of`: the next line opens with `ficial`,
185
+ // 29 px, whose `fi` is 9 px (7 px as a piece of `offi`).
186
+ const text = `aa of${SHY}fi${SHY}cial bb`;
187
+ const own = lay(text, 31, DOCUMENT_EN, options);
188
+ expect(own.map((l) => l.text)).toEqual(['aa of-', 'ficial', 'bb']);
189
+ expect(opening(own[1])).toEqual(['ficial', ink('ficial', 'en')]);
190
+ if (options.optimal)
191
+ expect(pieces(own[1])).toEqual([['fi', 9], ['cial', 20]]);
192
+ const host = lay(text, 31, HOST_EN, options);
193
+ expect(opening(host[1])).toEqual(['ficial', 27]);
194
+ if (options.optimal)
195
+ expect(pieces(host[1])).toEqual([['fi', 7], ['cial', 20]]);
196
+ });
197
+ it('a rest that breaks again: the line it leaves is its own text and a hyphen', () => {
198
+ // `efficient` over three lines: `ef-`, `fi-`, `cient`. The middle one
199
+ // was 7 px and a hyphen (what `effi` grew by after `ef`), for `fi`, 9.
200
+ const text = `aa ef${SHY}fi${SHY}cient bb`;
201
+ const own = lay(text, 26, DOCUMENT_EN, options);
202
+ expect(own.map((l) => l.text)).toEqual(['aa ef-', 'fi-', 'cient', 'bb']);
203
+ expect(closing(own[1])).toEqual(['fi-', ink('fi', 'en') + HYPHEN]);
204
+ expect(opening(own[2])).toEqual(['cient', 25]);
205
+ const host = lay(text, 26, HOST_EN, options);
206
+ expect(host.map((l) => l.text)).toEqual(['aa ef-', 'fi-', 'cient', 'bb']);
207
+ expect(closing(host[1])).toEqual(['fi-', 10]);
208
+ });
209
+ it('the rest of an address divided at a joint', () => {
210
+ // `www.oo.oo.oo` cut before its second dot: the pair `o.` is kerned
211
+ // 0.5 px, and the rest was that much narrower than `.oo.oo` alone.
212
+ const text = 'aa www.oo.oo.oo';
213
+ const own = lay(text, 40, DOCUMENT_EN, options);
214
+ expect(own.map((l) => l.text)).toEqual(['aa www.oo', '.oo.oo']);
215
+ expect(opening(own[1])).toEqual(['.oo.oo', ink('.oo.oo', 'en')]);
216
+ expect(opening(own[1])[1]).toBe(23.5);
217
+ const host = lay(text, 40, HOST_EN, options);
218
+ expect(opening(host[1])).toEqual(['.oo.oo', 23]);
219
+ });
220
+ it('a compound that repeats its hyphen: the rest is measured with it', () => {
221
+ const text = 'aa yoyo-yoyo bb';
222
+ const repeat = { ...options, repeatHyphen: true };
223
+ const own = lay(text, 36, DOCUMENT_EN, repeat);
224
+ expect(own.map((l) => l.text)).toEqual(['aa yoyo-', '-yoyo bb']);
225
+ expect(opening(own[1])).toEqual(['-yoyo', round(ink('-yoyo', 'en'))]);
226
+ expect(closing(own[0])).toEqual(['yoyo-', ink('yoyo-', 'en')]);
227
+ });
228
+ it('a word that stays on its line keeps the pieces it had: they add up to the word', () => {
229
+ const text = `An of${SHY}fice and an of${SHY}fi${SHY}cial`;
230
+ for (const mode of [DOCUMENT_EN, HOST_EN]) {
231
+ const lines = lay(text, 400, mode, options);
232
+ expect(lines).toHaveLength(1);
233
+ const all = pieces(lines[0]);
234
+ if (options.optimal)
235
+ expect(all).toEqual([['An', 10], ['of', 10], ['fice', 17], ['and', 15], ['an', 10], ['of', 10], ['fi', 7], ['cial', 20]]);
236
+ else
237
+ expect(all).toEqual([['An', 10], ['office', 27], ['and', 15], ['an', 10], ['official', 37]]);
238
+ }
239
+ });
240
+ });
241
+ describe('a word wider than its line', () => {
242
+ it('is divided, and what is left is measured from the cut on', () => {
243
+ // No syllable here: the word is cut at the last character that fits,
244
+ // between a `y` and the `o` it is kerned to.
245
+ const lines = lay('oyoyoyoyoy', 22.5, DOCUMENT_EN, { textAlign: 'left', hyphenate: false });
246
+ expect(lines.length).toBeGreaterThan(1);
247
+ for (let i = 0; i < lines.length; i++) {
248
+ const [text, width] = closing(lines[i]);
249
+ const body = lines[i].hyphenated && text.endsWith('-') ? text.slice(0, -1) : text;
250
+ expect([text, width]).toEqual([text, round(ink(body, 'en') + (body === text ? 0 : HYPHEN))]);
251
+ }
252
+ expect(lines.map((l) => closing(l))).toEqual([['oyoy-', 22], ['oy-', 13], ['oyoy', 19]]);
253
+ // In the host's language the rest is the word less its head: the pair
254
+ // kerned across each cut stays in it, and the last line is 1 px short
255
+ // of the text it paints for each of the two cuts.
256
+ const host = lay('oyoyoyoyoy', 22.5, HOST_EN, { textAlign: 'left', hyphenate: false });
257
+ expect(host.map((l) => closing(l))).toEqual([['oyoy-', 22], ['oy-', 13], ['oyoy', 17]]);
258
+ });
259
+ it('an address in a Chinese paragraph, cut at a joint by the composer', () => {
260
+ const text = '中文 www.oo.oo.oo 中文';
261
+ const own = lay(text, 52, { language: 'zh-Hans', locale: 'en-us' }, { textAlign: 'left' });
262
+ const at = own.findIndex((l) => l.text.startsWith('.oo'));
263
+ expect(at).toBeGreaterThan(0);
264
+ const rest = words(own[at])[0];
265
+ expect(rest.text.startsWith('.oo')).toBe(true);
266
+ expect(round(rest.width)).toBe(round(ink(rest.text, 'zh-Hans')));
267
+ const host = lay(text, 52, { language: undefined, locale: 'en-us' }, { textAlign: 'left' });
268
+ expect(host.map((l) => l.text)).toEqual(own.map((l) => l.text));
269
+ expect(round(words(host[at])[0].width)).toBe(round(ink(rest.text, 'en') - 0.5));
270
+ });
271
+ });
272
+ // A word over three lines: its middle line opens with the rest of the
273
+ // first break and ends on a hyphen of its own. Knuth–Plass counts that
274
+ // line while it chooses breaks as the rest's shift, the boxes between the
275
+ // two cuts and the second break's hyphen, and the line set is the text
276
+ // between the cuts measured alone, and its hyphen. The two are one number:
277
+ // both leave out what the word draws from the second cut on, so they part
278
+ // only where the start of the rest changes the glyphs at the second cut.
279
+ // In Chrome 154, over 9 700 such lines in Crimson Pro, Lora, Fira Sans and
280
+ // EB Garamond at measures of 40 to 300 pt (Catalan `l·l`, `ffi`, addresses,
281
+ // repeated hyphens, a soft hyphen after every letter), the breaker's count,
282
+ // the widths written and the text painted were equal to 0.001 px.
283
+ //
284
+ // Each case here sets the middle line in a measure it fills to a
285
+ // thousandth: the breaker takes it when it counts the width set, and may
286
+ // not when the measure is that much narrower.
287
+ describe.each([['line by line', GREEDY], ['Knuth–Plass', OPTIMAL]])('a word over three lines, %s', (_name, options) => {
288
+ /** The lines with no word space: their boxes, summed, to a thousandth. */
289
+ const oneWordLines = (lines) => lines
290
+ .filter((l) => !(l.segments ?? []).some((s) => s.kind === 'space'))
291
+ .map((l) => [l.text, round((l.segments ?? []).reduce((sum, s) => sum + s.width, 0))]);
292
+ /** What a line paints: its text measured alone, the hyphen the layout
293
+ * added measured apart. */
294
+ const painted = (line, lang, font = PUNT) => {
295
+ const added = line.hyphenated === true && !line.hardHyphen && line.text.endsWith('-');
296
+ const body = added ? line.text.slice(0, -1) : line.text;
297
+ return round(ink(body, lang, font) + (added ? HYPHEN : 0));
298
+ };
299
+ it('the middle line of a word whose ligature the first break undoes fills its measure', () => {
300
+ // `of|ficial|ly`: the middle line paints `ficial` (29 px, its `fi`
301
+ // ligature) and a hyphen, 32 px. As what `official` grew by after
302
+ // `of` it was 27 px and a hyphen.
303
+ const text = `aa of${SHY}ficial${SHY}ly bb`;
304
+ const own = lay(text, 32.001, DOCUMENT_EN, options);
305
+ expect(own.map((l) => l.text)).toEqual(['aa of-', 'ficial-', 'ly bb']);
306
+ expect(closing(own[1])).toEqual(['ficial-', 32]);
307
+ expect(pieces(own[1])).toEqual([['ficial-', 32]]);
308
+ // A thousandth narrower it does not fit, and nothing set is past the
309
+ // measure.
310
+ const narrow = lay(text, 31.999, DOCUMENT_EN, options);
311
+ expect(narrow.map((l) => l.text)).not.toContain('ficial-');
312
+ for (const [, width] of oneWordLines(narrow))
313
+ expect(width).toBeLessThanOrEqual(31.999);
314
+ // The host's language keeps the count it had: 30 px, set in 31.999.
315
+ const host = lay(text, 31.999, HOST_EN, options);
316
+ expect(host.map((l) => l.text)).toEqual(['aa of-', 'ficial-', 'ly bb']);
317
+ expect(closing(host[1])).toEqual(['ficial-', 30]);
318
+ });
319
+ it('a middle line that ends inside an l·l: the text before the dot and its hyphen', () => {
320
+ // `ins|tal·|lar` in Catalan: `tal` alone is 15 px, 18 with its hyphen.
321
+ // The word grew by 17.5 px from `ins` to `instal·` (the dot 2.5 px at
322
+ // the end of a text), and the rest after the dot is `lar`, 15 px.
323
+ const text = `instal${DOT}lar`;
324
+ host = 'ca';
325
+ clearMeasurementCache();
326
+ const own = lay(text, 18.001, DOCUMENT_CA, options);
327
+ expect(oneWordLines(own)).toEqual([['ins-', 18], ['tal-', 18], ['lar', 15]]);
328
+ for (const line of own)
329
+ expect(round((line.segments ?? []).reduce((sum, s) => sum + s.width, 0))).toBe(painted(line, 'ca'));
330
+ clearMeasurementCache();
331
+ const narrow = lay(text, 17.999, DOCUMENT_CA, options);
332
+ for (const [, width] of oneWordLines(narrow))
333
+ expect(width).toBeLessThanOrEqual(17.999);
334
+ // A face that ligates `l·` (Lora): the same lines, the same widths.
335
+ clearMeasurementCache();
336
+ const lliga = lay(text, 18.001, DOCUMENT_CA, options, LLIGA);
337
+ expect(oneWordLines(lliga)).toEqual([['ins-', 18], ['tal-', 18], ['lar', 15]]);
338
+ });
339
+ it('a middle line between two hyphens of a compound, the first repeated', () => {
340
+ // `yoyo-yoyo-yoyo`: the middle line paints `-yoyo-`, 23.6 px (the
341
+ // pair `-y` kerned 0.4 px).
342
+ const text = 'yoyo-yoyo-yoyo';
343
+ const repeat = { ...options, repeatHyphen: true };
344
+ const own = lay(text, 23.601, DOCUMENT_EN, repeat);
345
+ expect(oneWordLines(own)).toEqual([['yoyo-', 21], ['-yoyo-', 23.6], ['-yoyo', 20.6]]);
346
+ expect(own.map((l) => round(ink(l.text, 'en')))).toEqual([21, 23.6, 20.6]);
347
+ const narrow = lay(text, 23.599, DOCUMENT_EN, repeat);
348
+ expect(narrow.map((l) => l.text)).not.toContain('-yoyo-');
349
+ for (const [, width] of oneWordLines(narrow))
350
+ expect(width).toBeLessThanOrEqual(23.599);
351
+ });
352
+ it('an address over several lines, each longer than the rest is measured from its break', () => {
353
+ // 80 joints, 243 characters: at these measures a line holds more than
354
+ // the 32 characters measured from the break it opens at, and the rest
355
+ // of it is what the whole address grew by from there on.
356
+ const text = `www${'.oo'.repeat(80)}`;
357
+ let longMiddles = 0;
358
+ for (let measure = 190; measure <= 260; measure += 3.5) {
359
+ clearMeasurementCache();
360
+ const lines = lay(text, measure, DOCUMENT_EN, options);
361
+ expect(lines.length).toBeGreaterThan(2);
362
+ expect(lines.map((l) => l.text).join('')).toBe(text);
363
+ lines.forEach((line, i) => {
364
+ const width = round((line.segments ?? []).reduce((sum, s) => sum + s.width, 0));
365
+ expect([line.text, width]).toEqual([line.text, round(ink(line.text, 'en'))]);
366
+ expect(width).toBeLessThanOrEqual(measure);
367
+ if (i > 0 && i < lines.length - 1 && line.text.length > 32)
368
+ longMiddles++;
369
+ });
370
+ }
371
+ expect(longMiddles).toBeGreaterThan(20);
372
+ });
373
+ });
374
+ //# sourceMappingURL=lineEndPieces.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lineEndPieces.test.js","sourceRoot":"","sources":["../../src/__tests__/lineEndPieces.test.ts"],"names":[],"mappings":"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"}
@@ -143,8 +143,8 @@ describe('maths in configurations written before postext 1.5 (EF-75)', () => {
143
143
  });
144
144
  it('writes bundles for today\'s rules, which read back unpinned', async () => {
145
145
  const { manifest, bytes } = await createBundle({ name: 'Now', chapters: [{ markdown: CHAPTER }], config: BODY });
146
- expect(CONFIG_VERSION).toBe(13);
147
- expect(manifest.configVersion).toBe(13);
146
+ expect(CONFIG_VERSION).toBe(14);
147
+ expect(manifest.configVersion).toBe(14);
148
148
  const again = await openBundle(bytes);
149
149
  expect(again.config.math).toBeUndefined();
150
150
  // …and a 1.4 bundle, opened and written again, is read back as it was
@@ -101,7 +101,7 @@ describe('configurations stored before rules 6 keep the 1.4 box spacing', () =>
101
101
  // It names the box cut (EF-115), so the box gap is the pin that shows.
102
102
  const config = { layout: { layoutType: 'single', boxChildSplitMinLines: 2 } };
103
103
  it('pins a configuration whose book embeds a resource in a box, once', () => {
104
- expect(CONFIG_VERSION).toBe(13);
104
+ expect(CONFIG_VERSION).toBe(14);
105
105
  // Stamped 5 (a 1.5 prerelease): the box gap is the only pin it gets.
106
106
  expect(migrateConfig(config, 5, { content: MD }).layout).toEqual({ layoutType: 'single', boxChildSplitMinLines: 2, inlineResourceGapInBoxes: false });
107
107
  // Unversioned (1.4): both gap pins.
@@ -155,7 +155,7 @@ describe('layout.boxChildSplitMinLines', () => {
155
155
  it('is pinned to 1 for configurations stored before rules 6 whose book holds a box', () => {
156
156
  const cfg = { layout: { layoutType: 'single', inlineResourceGap: 'around', inlineResourceGapInBoxes: true } };
157
157
  const box = twoLineItems(3);
158
- expect(CONFIG_VERSION).toBe(13);
158
+ expect(CONFIG_VERSION).toBe(14);
159
159
  // Unversioned (1.4) and stamped 5 (a 1.5 prerelease): pinned.
160
160
  expect(migrateConfig(cfg, undefined, { content: box }).layout?.boxChildSplitMinLines).toBe(1);
161
161
  expect(migrateConfig(cfg, 5, { content: ['No box here.', box] }).layout?.boxChildSplitMinLines).toBe(1);
@@ -110,7 +110,7 @@ describe('colonListRoom: \'line\' keeps the postext 1.4 room check (EF-110)', ()
110
110
  describe('configurations stored before rules 6 keep the 1.4 colon-list room', () => {
111
111
  const LIST = 'Look for these signs:\n\n- one\n- two';
112
112
  it('pins a configuration older than 6 whose book introduces a list with a colon, once', () => {
113
- expect(CONFIG_VERSION).toBe(13);
113
+ expect(CONFIG_VERSION).toBe(14);
114
114
  const stored = { bodyText: { fontFamily: 'Georgia' } };
115
115
  for (const version of [undefined, 3, 4, 5]) {
116
116
  expect(migrateConfig(stored, version, { content: LIST }).bodyText, `${version}`)
@@ -121,7 +121,7 @@ describe('a break after a compound’s hyphen on both paths (EF-186)', () => {
121
121
  expect(other).toBeGreaterThan(0);
122
122
  });
123
123
  it('is pinned off for configurations stored before rules 8 whose text sets a compound', () => {
124
- expect(CONFIG_VERSION).toBe(13);
124
+ expect(CONFIG_VERSION).toBe(14);
125
125
  const stored = { bodyText: { fontFamily: 'Georgia' } };
126
126
  for (const version of [undefined, 3, 6, 7]) {
127
127
  expect(migrateConfig(stored, version, { content: EN }).bodyText?.breakAfterHyphens, `${version}`).toBe(false);
@@ -303,7 +303,7 @@ describe('breakAfterDashes in the configuration', () => {
303
303
  expect(stripBodyTextDefaults({ breakAfterDashes: false })).toEqual({ breakAfterDashes: false });
304
304
  });
305
305
  it('is pinned off for configurations stored before rules 7 whose text sets a closed dash', () => {
306
- expect(CONFIG_VERSION).toBe(13);
306
+ expect(CONFIG_VERSION).toBe(14);
307
307
  const stored = { bodyText: { fontFamily: 'Georgia' } };
308
308
  for (const version of [undefined, 3, 5, 6]) {
309
309
  expect(migrateConfig(stored, version, { content: ALICE }).bodyText?.breakAfterDashes, `${version}`).toBe(false);
@@ -103,7 +103,7 @@ describe('a paragraph kept with the heading above it splits by the orphan rule t
103
103
  }
104
104
  // Stored under today's rules, it is read as it is.
105
105
  expect(migrateConfig(stored, CONFIG_VERSION, { content: markdown })).toBe(stored);
106
- expect(CONFIG_VERSION).toBe(13);
106
+ expect(CONFIG_VERSION).toBe(14);
107
107
  });
108
108
  it('pins only what the setting changes', () => {
109
109
  const plain = { bodyText: { fontFamily: 'Georgia' } };
@@ -126,7 +126,7 @@ describe('layout.inlineResourceGap and configurations stored before postext 1.5
126
126
  });
127
127
  it('pins a stored configuration whose book embeds a resource, once', () => {
128
128
  const config = { layout: { layoutType: 'single' } };
129
- expect(CONFIG_VERSION).toBe(13);
129
+ expect(CONFIG_VERSION).toBe(14);
130
130
  const pinned = migrateConfig(config, undefined, { content: MD });
131
131
  expect(pinned.layout).toEqual({ layoutType: 'single', inlineResourceGap: 'above' });
132
132
  // Stamped 4 (a 1.5 prerelease): the gap is the only pin it gets.
@@ -240,7 +240,7 @@ describe('paragraphStyles[].snapToGrid (EF-184)', () => {
240
240
  describe('configurations stored before rules 8 keep the 1.4 space under containers', () => {
241
241
  const stored = { bodyText: { fontFamily: 'Georgia' }, paragraphStyles: [{ id: 's' }] };
242
242
  it('pins \'add\' when the book holds a :::paragraphs container', () => {
243
- expect(CONFIG_VERSION).toBe(13);
243
+ expect(CONFIG_VERSION).toBe(14);
244
244
  for (const version of [undefined, 3, 5, 6, 7]) {
245
245
  expect(migrateConfig(stored, version, { content: GROUP_THEN_HEADING }).bodyText?.paragraphContainerSpacing, `${version}`).toBe('add');
246
246
  }
@@ -168,7 +168,7 @@ describe('optimalRagged in the configuration', () => {
168
168
  expect(stripBodyTextDefaults({ optimalRagged: false })).toEqual({ optimalRagged: false });
169
169
  });
170
170
  it('is pinned off for configurations stored before rules 7 that set running text ragged', () => {
171
- expect(CONFIG_VERSION).toBe(13);
171
+ expect(CONFIG_VERSION).toBe(14);
172
172
  const ragged = { bodyText: { textAlign: 'left' } };
173
173
  for (const version of [undefined, 3, 5, 6]) {
174
174
  expect(migrateConfig(ragged, version, { content: 'Text.' }).bodyText, `${version}`).toEqual({ textAlign: 'left', optimalRagged: false, scriptContext: false, shapingLanguage: 'host' });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plainGeminateHead.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plainGeminateHead.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/plainGeminateHead.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,92 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { clearMeasurementCache, measureBlock } from '../measure';
3
+ import { setMeasureLanguage } from '../measure/canvas';
4
+ import { setHyphenationLocale } from '../hyphenate';
5
+ // #770: the head of a break inside a Catalan `l·l`, in a plain paragraph.
6
+ // The line ends on the piece `col·` and prints a hyphen in the dot's
7
+ // place, so the dot's width is given back. The dot set alone was taken
8
+ // for it; a face that sets the dot after an `l` otherwise than alone
9
+ // (Castoro's Catalan form, 0.129 em there and 0.297 em alone; Lora's
10
+ // `l·` ligature) left the head off the text painted: `til-` 22.02 px for
11
+ // 25.28 at 19.4 px in Castoro.
12
+ const DOT = '·';
13
+ /** px at 10 px: every letter 5, a space 2.5, a hyphen 3, the dot 2.5; the
14
+ * face ligates `l·`, 1.3 narrower (as Lora). */
15
+ function faceWidth(text) {
16
+ const chars = Array.from(text);
17
+ let px = 0;
18
+ chars.forEach((ch, i) => {
19
+ if (ch === ' ')
20
+ px += 2.5;
21
+ else if (ch === '-')
22
+ px += 3;
23
+ else if (ch === DOT)
24
+ px += 2.5;
25
+ else
26
+ px += 5;
27
+ if (`${chars[i - 1] ?? ''}${ch}` === `l${DOT}`)
28
+ px -= 1.3;
29
+ });
30
+ return px;
31
+ }
32
+ class MeasureContext {
33
+ font = '10px Lliga';
34
+ lang = 'inherit';
35
+ direction = 'ltr';
36
+ measureText(s) {
37
+ return { width: faceWidth(s) };
38
+ }
39
+ }
40
+ const globals = globalThis;
41
+ const saved = { canvas: globals.OffscreenCanvas, context: globals.OffscreenCanvasRenderingContext2D };
42
+ const FONT = '10px Lliga';
43
+ const TEXT = `aa col${DOT}lecció bb`;
44
+ const GREEDY = { textAlign: 'left', hyphenate: true };
45
+ const OPTIMAL = { textAlign: 'justify', hyphenate: true, optimal: true };
46
+ function lay(language, options) {
47
+ setHyphenationLocale('ca');
48
+ setMeasureLanguage(language);
49
+ return measureBlock(TEXT, FONT, 32, 14, options).lines;
50
+ }
51
+ /** The width of the pieces a line ends on, back to its last space. */
52
+ function closing(line) {
53
+ let width = 0;
54
+ for (const s of [...(line.segments ?? [])].reverse()) {
55
+ if (s.kind === 'space')
56
+ break;
57
+ width += s.width;
58
+ }
59
+ return Math.round(width * 1000) / 1000;
60
+ }
61
+ describe('the head of a break inside an l·l in a plain paragraph (#770)', () => {
62
+ beforeEach(() => {
63
+ globals.OffscreenCanvasRenderingContext2D = MeasureContext;
64
+ globals.OffscreenCanvas = class {
65
+ getContext() {
66
+ return new MeasureContext();
67
+ }
68
+ };
69
+ clearMeasurementCache();
70
+ });
71
+ afterEach(() => {
72
+ setMeasureLanguage(undefined);
73
+ clearMeasurementCache();
74
+ globals.OffscreenCanvas = saved.canvas;
75
+ globals.OffscreenCanvasRenderingContext2D = saved.context;
76
+ });
77
+ for (const [name, options] of [['line by line', GREEDY], ['Knuth–Plass', OPTIMAL]]) {
78
+ it(`${name}: a document shaped in its own language measures the letters before the dot and the hyphen`, () => {
79
+ const lines = lay('ca', options);
80
+ expect(lines[0].text).toBe('aa col-');
81
+ // `col` 15 px and the hyphen 3: the text painted.
82
+ expect(closing(lines[0])).toBe(18);
83
+ });
84
+ it(`${name}: one shaped in the host's language keeps the width it had`, () => {
85
+ const lines = lay(undefined, options);
86
+ expect(lines[0].text).toBe('aa col-');
87
+ // `col·` 16.2 px, less the dot alone, 2.5, and the hyphen.
88
+ expect(closing(lines[0])).toBe(16.7);
89
+ });
90
+ }
91
+ });
92
+ //# sourceMappingURL=plainGeminateHead.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plainGeminateHead.test.js","sourceRoot":"","sources":["../../src/__tests__/plainGeminateHead.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=showcaseShapingLanguage.test.d.ts.map