postext 1.29.2 → 1.30.1

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,132 @@
1
+ import { lineWordSegmentsInOrder, sameSetWidth } from '../wordPieces';
2
+ import { graphemeCount } from '../measure/graphemes';
3
+ import { measurementGeneration } from '../measure/canvas';
4
+ import { languageOf, setLetterSpacing } from './contextState';
5
+ import { inSegmentLanguage } from './wordRuns';
6
+ import { contextTextWidth } from './contextText';
7
+ import { verticalFlowAdvance } from './verticalText';
8
+ /** A line's segments → what is known of the line. */
9
+ const painted = new WeakMap();
10
+ /** What is known of the line of `segments` under the faces loaded, the
11
+ * language and the `tracking` painted in and the line's `font`, with its
12
+ * segments as they are; nothing yet when any of those changed. */
13
+ function knownOf(ctx, line, segments, tracking, font) {
14
+ let widths = 0;
15
+ for (const seg of segments)
16
+ widths += seg.width;
17
+ const key = `${measurementGeneration()}\u0000${languageOf(ctx) ?? ''}\u0000${tracking}\u0000${segments.length}\u0000${widths}\u0000${line.hyphenated === true}\u0000${font}`;
18
+ let known = painted.get(segments);
19
+ if (known?.key !== key)
20
+ painted.set(segments, known = { key });
21
+ return known;
22
+ }
23
+ /**
24
+ * The segments to paint `line` from, and the order to advance through
25
+ * them in when the line carries one (`VDTLine.order`: a line with
26
+ * right-to-left text, any line of a mirrored page; the pieces of a
27
+ * left-to-right word are joined there too, and the order written for the
28
+ * segments that result). `composed`: a line of the CJK composer, painted
29
+ * as it is. A line set word by word down a vertical page is asked as any
30
+ * other, each text at the advance the vertical painter gives it: a Latin
31
+ * word runs sideways down the column, shaped as on a horizontal line, and
32
+ * a piece of it is as wide as the word grew by it. Chrome 154, Noto Sans
33
+ * JP at 14.58 px under `ja`: the layout holds `BY-` 21.01 and `SA` 17.23
34
+ * px, `BY-SA` being 38.24 px, where `SA` alone is 17.55 px; painted piece
35
+ * by piece `SA` ran 0.32 px into the space after it. `tracking` is the
36
+ * context's `letterSpacing` on entry, px, and on return; `fontOf` gives the font
37
+ * string a segment is painted in. The context's font is left at any
38
+ * value: the painter sets its own before each text.
39
+ */
40
+ export function paintedSegments(ctx, line, composed, tracking, fontOf) {
41
+ const segments = line.segments;
42
+ const order = segments && !composed && line.order?.length === segments.length ? line.order : undefined;
43
+ if (!segments || segments.length === 0 || composed || typeof ctx.measureText !== 'function')
44
+ return { segments, order };
45
+ const known = knownOf(ctx, line, segments, tracking, fontOf(segments[0]));
46
+ if (known.set)
47
+ return known.set;
48
+ let font = '';
49
+ let spaced = tracking !== 0;
50
+ known.set = lineWordSegmentsInOrder(line, composed, (seg, text) => {
51
+ if (spaced) {
52
+ setLetterSpacing(ctx, 0);
53
+ spaced = false;
54
+ }
55
+ let width = 0;
56
+ inSegmentLanguage(ctx, seg, () => {
57
+ const own = fontOf(seg);
58
+ if (own !== font)
59
+ ctx.font = font = own;
60
+ // Down a vertical page a text advances as its cells and its
61
+ // sideways runs do (`verticalFlowAdvance`).
62
+ width = verticalFlowAdvance(ctx, text, tracking)
63
+ ?? contextTextWidth(ctx, text) + (tracking === 0 ? 0 : tracking * graphemeCount(text));
64
+ });
65
+ return width;
66
+ });
67
+ if (tracking !== 0 && !spaced)
68
+ setLetterSpacing(ctx, tracking);
69
+ return known.set;
70
+ }
71
+ /** A character past Latin-1 (see `contextText.ts`). */
72
+ const WIDE_RE = /[^\u0000-\u00FF]/;
73
+ const LETTER_RE = /\p{L}/u;
74
+ /** Whether the browser may set the line's text otherwise as one text than
75
+ * segment by segment: two of its pieces touch (a pair kerned across the
76
+ * cut), the line ends on a hyphen the layout added (measured apart from
77
+ * its word, and a face may kern the two: at 20 px Fira Sans sets `lec-`
78
+ * 0.86 px narrower than `lec` and `-`, Crimson Pro `bo-` 0.29 px wider),
79
+ * or its text holds a character past U+00FF and one of its words is of
80
+ * Latin-1 characters with no letter among them. */
81
+ function mayDifferWhole(line, segments) {
82
+ if (line.hyphenated === true && !line.hardHyphen) {
83
+ const last = segments[segments.length - 1];
84
+ if (last?.kind === 'text' && last.text.length > 1 && last.text.endsWith('-'))
85
+ return true;
86
+ }
87
+ const wide = WIDE_RE.test(line.text);
88
+ for (let i = 0; i < segments.length; i++) {
89
+ const seg = segments[i];
90
+ if (seg.kind === 'space')
91
+ continue;
92
+ if (i > 0 && segments[i - 1].kind !== 'space')
93
+ return true;
94
+ if (wide && seg.kind === 'text' && !WIDE_RE.test(seg.text) && !LETTER_RE.test(seg.text))
95
+ return true;
96
+ }
97
+ return false;
98
+ }
99
+ /**
100
+ * Whether a line's text, painted with one `fillText` in the context's
101
+ * font (the line's `font`, set by the caller), is as wide as the layout
102
+ * measured its segments together. `tracking` is the context's
103
+ * `letterSpacing` on entry, px, and on return. A line with no two pieces
104
+ * that touch and no word the browser shapes otherwise inside a longer
105
+ * string is, with nothing asked: its words and its spaces were measured
106
+ * whole. So is any line where the context does not measure.
107
+ */
108
+ export function paintsAsOneText(ctx, line, tracking, font) {
109
+ const segments = line.segments;
110
+ if (!segments || typeof ctx.measureText !== 'function' || !mayDifferWhole(line, segments))
111
+ return true;
112
+ const known = knownOf(ctx, line, segments, tracking, font);
113
+ if (known.whole === undefined) {
114
+ let measured = 0;
115
+ let widest = 0;
116
+ for (const seg of segments) {
117
+ measured += seg.width;
118
+ if (seg.width > widest)
119
+ widest = seg.width;
120
+ }
121
+ if (tracking !== 0)
122
+ setLetterSpacing(ctx, 0);
123
+ const set = contextTextWidth(ctx, line.text) + (tracking === 0 ? 0 : tracking * graphemeCount(line.text));
124
+ if (tracking !== 0)
125
+ setLetterSpacing(ctx, tracking);
126
+ // What a kerned pair moves is small beside a line: the difference is
127
+ // weighed against the line's widest word, as a word's pieces are.
128
+ known.whole = sameSetWidth(widest + set - measured, widest);
129
+ }
130
+ return known.whole;
131
+ }
132
+ //# sourceMappingURL=wordPieces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wordPieces.js","sourceRoot":"","sources":["../../src/canvas-backend/wordPieces.ts"],"names":[],"mappings":"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"}
@@ -48,7 +48,9 @@ export declare function fillSegmentWord(ctx: CanvasRenderingContext2D, seg: VDTL
48
48
  export declare function inSegmentLanguage(ctx: CanvasRenderingContext2D, seg: VDTLineSegment, paint: () => void): void;
49
49
  /** Paint the segments that name a language in it from now on (`on`), or
50
50
  * in the page's as up to postext 1.28: the page painter says which for
51
- * the document it paints (`bodyText.shapingLanguage`). */
51
+ * the document it paints (`bodyText.shapingLanguage`). The same
52
+ * documents have the ligatures of their tracked words take the tracking
53
+ * of each letter (`setLetterTracking`, #770). */
52
54
  export declare function setSegmentLanguages(on: boolean): void;
53
55
  /** Whether a segment that names its language is painted on its own. */
54
56
  export declare function paintsSegmentLanguage(seg: VDTLineSegment): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"wordRuns.d.ts","sourceRoot":"","sources":["../../src/canvas-backend/wordRuns.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAQ7C,8EAA8E;AAC9E,MAAM,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAQlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,wBAAwB,EAC7B,GAAG,EAAE,cAAc,EACnB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,EACnD,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzD,IAAI,CAEN;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,wBAAwB,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,IAAI,GAAG,IAAI,CAa7G;AAMD;;2DAE2D;AAC3D,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAErD;AAED,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAElE;AA+BD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,wBAAwB,EAC7B,GAAG,EAAE,cAAc,EACnB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,EACnD,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzD,IAAI,CAsCN"}
1
+ {"version":3,"file":"wordRuns.d.ts","sourceRoot":"","sources":["../../src/canvas-backend/wordRuns.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAS7C,8EAA8E;AAC9E,MAAM,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAQlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,wBAAwB,EAC7B,GAAG,EAAE,cAAc,EACnB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,EACnD,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzD,IAAI,CAEN;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,wBAAwB,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,IAAI,GAAG,IAAI,CAa7G;AAMD;;;;kDAIkD;AAClD,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAGrD;AAED,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAElE;AA+BD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,wBAAwB,EAC7B,GAAG,EAAE,cAAc,EACnB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,EACnD,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzD,IAAI,CAsCN"}
@@ -1,10 +1,11 @@
1
1
  import { shapingTagOf } from '../locale';
2
2
  import { joiningScriptIn } from '../measure/joining';
3
3
  import { mirroredPaintActive } from './mirrorFrame';
4
- import { fillTrackedWord } from './trackedText';
4
+ import { fillTrackedWord, setLetterTracking } from './trackedText';
5
5
  import { fillScriptWord } from './scriptText';
6
6
  import { scriptContextUntracked } from '../measure/script';
7
7
  import { restoreContext, saveContext, setLetterSpacing } from './contextState';
8
+ import { contextTextWidth } from './contextText';
8
9
  /** How far above and below the baseline a run's clip reaches: past any
9
10
  * ascender, stacked vowel sign or descender. */
10
11
  const CLIP_REACH = 4096;
@@ -72,9 +73,12 @@ export function inSegmentLanguage(ctx, seg, paint) {
72
73
  let segmentLanguages = false;
73
74
  /** Paint the segments that name a language in it from now on (`on`), or
74
75
  * in the page's as up to postext 1.28: the page painter says which for
75
- * the document it paints (`bodyText.shapingLanguage`). */
76
+ * the document it paints (`bodyText.shapingLanguage`). The same
77
+ * documents have the ligatures of their tracked words take the tracking
78
+ * of each letter (`setLetterTracking`, #770). */
76
79
  export function setSegmentLanguages(on) {
77
80
  segmentLanguages = on;
81
+ setLetterTracking(on);
78
82
  }
79
83
  /** Whether a segment that names its language is painted on its own. */
80
84
  export function paintsSegmentLanguage(seg) {
@@ -130,7 +134,7 @@ function fillWord(ctx, seg, x, y, tracking, paint, runStyle) {
130
134
  export function paintWordRuns(ctx, seg, x, y, paint, runStyle) {
131
135
  const text = seg.text;
132
136
  const runs = seg.runs;
133
- const whole = ctx.measureText(text).width;
137
+ const whole = contextTextWidth(ctx, text);
134
138
  if (!(whole > 0))
135
139
  return;
136
140
  const rtl = seg.rtl === true;
@@ -146,8 +150,8 @@ export function paintWordRuns(ctx, seg, x, y, paint, runStyle) {
146
150
  from--;
147
151
  while (to < text.length && MARK_RE.test(text[to]))
148
152
  to++;
149
- const before = whole - ctx.measureText(text.slice(from)).width;
150
- const after = whole - ctx.measureText(text.slice(0, to)).width;
153
+ const before = whole - contextTextWidth(ctx, text.slice(from));
154
+ const after = whole - contextTextWidth(ctx, text.slice(0, to));
151
155
  let left = x + Math.max(0, rtl ? after : before);
152
156
  let right = x + whole - Math.max(0, rtl ? before : after);
153
157
  if (mirroredPaintActive())
@@ -161,7 +165,7 @@ export function paintWordRuns(ctx, seg, x, y, paint, runStyle) {
161
165
  ctx.clip();
162
166
  ctx.font = font;
163
167
  ctx.fillStyle = fill;
164
- const w = ctx.measureText(text).width;
168
+ const w = contextTextWidth(ctx, text);
165
169
  if (w > 0 && Math.abs(w - whole) > 0.01) {
166
170
  ctx.translate(x, 0);
167
171
  ctx.scale(whole / w, 1);
@@ -1 +1 @@
1
- {"version":3,"file":"wordRuns.js","sourceRoot":"","sources":["../../src/canvas-backend/wordRuns.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wordRuns.js","sourceRoot":"","sources":["../../src/canvas-backend/wordRuns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fitAsPainted.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fitAsPainted.test.d.ts","sourceRoot":"","sources":["../../../../src/comics/lettering/__tests__/fitAsPainted.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,97 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import { clearTextWidthCache, setMeasureLanguage } from '../../../measure/canvas';
3
+ import { prepareText, readLetteringText } from '../text';
4
+ import { shapeText } from '../shape-text';
5
+ import { presetLetteringStyles } from '../presets';
6
+ // #770, round 2: the lines a shaping tries are measured as the layout sets
7
+ // the ones it chooses. In a document shaped in its own language the layout
8
+ // sets a line as wide as its runs are painted, each in its own direction;
9
+ // the shaping measured every line left to right, whole, so a line of an
10
+ // Arabic balloon that ends in a stop or a guillemet was chosen at another
11
+ // width than it is set at.
12
+ const EM = 20;
13
+ const SIZE_RE = /(\d*\.?\d+)px/;
14
+ /**
15
+ * The advance of `text`, in em, in a face that draws its marks by the run
16
+ * they stand in, as Playpen Sans Arabic and Markazi Text do in Arabic: a
17
+ * guillemet is 0.47 em and a stop 0.3 em in a text measured left to right
18
+ * (a run apart from the Arabic word, shaped alone), 0.41 em and 0.2 em in
19
+ * the right-to-left run it is painted in. A space is 0.25 em, any other
20
+ * character half an em.
21
+ */
22
+ function faceWidth(text, rtl) {
23
+ let em = 0;
24
+ for (const ch of text) {
25
+ if (/[⁦-⁩]/.test(ch))
26
+ continue;
27
+ if (ch === ' ')
28
+ em += 0.25;
29
+ else if (ch === '«' || ch === '»')
30
+ em += rtl ? 0.41 : 0.47;
31
+ else if (ch === '.')
32
+ em += rtl ? 0.2 : 0.3;
33
+ else
34
+ em += 0.5;
35
+ }
36
+ return em;
37
+ }
38
+ class StubCtx {
39
+ font = `${EM}px Test`;
40
+ lang = 'inherit';
41
+ direction = 'ltr';
42
+ measureText(s) {
43
+ const px = Number(SIZE_RE.exec(this.font)?.[1] ?? EM);
44
+ return { width: faceWidth(s, this.direction === 'rtl') * px };
45
+ }
46
+ }
47
+ const globals = globalThis;
48
+ globals.OffscreenCanvasRenderingContext2D = StubCtx;
49
+ globals.OffscreenCanvas = class {
50
+ getContext() {
51
+ return new StubCtx();
52
+ }
53
+ };
54
+ clearTextWidthCache();
55
+ afterEach(() => setMeasureLanguage(undefined));
56
+ function shape(text, locale) {
57
+ const style = presetLetteringStyles({ fontSizePx: EM, locale, fontFamily: 'Test' })['speech'];
58
+ const p = prepareText(readLetteringText(text, undefined), style, { locale, vertical: false });
59
+ const shaped = shapeText(p, style, { locale, vertical: false, dpi: 96 });
60
+ return { shaped, lines: shaped.lines.map((l) => p.text.slice(l.start, l.end)) };
61
+ }
62
+ // Two sentences, each closed by a stop; the second inside guillemets.
63
+ const ARABIC = 'هذا هو النص الاول. «وهذا هو النص الثاني.»';
64
+ describe('#770: a balloon line is fitted at the width it is set at', () => {
65
+ it('in a document shaped in its own language, a right-to-left line as it is painted', () => {
66
+ setMeasureLanguage('ar');
67
+ const { shaped, lines } = shape(ARABIC, 'ar');
68
+ const set = shaped.block.lines.filter((l) => l.text.length > 0);
69
+ expect(set).toHaveLength(lines.length);
70
+ // The layout sets each line as one right-to-left run.
71
+ set.forEach((l, i) => expect(l.width).toBeCloseTo(faceWidth(lines[i], true) * EM, 6));
72
+ // And the shaping chose it at that width.
73
+ shaped.lines.forEach((l, i) => expect(l.width).toBeCloseTo(set[i].width, 6));
74
+ // The text holds marks the two directions set at other widths.
75
+ expect(faceWidth(ARABIC, false)).toBeGreaterThan(faceWidth(ARABIC, true) + 0.3);
76
+ });
77
+ it('in a document shaped in its host’s language, left to right and whole, as it was', () => {
78
+ const { shaped, lines } = shape(ARABIC, 'ar');
79
+ const set = shaped.block.lines.filter((l) => l.text.length > 0);
80
+ shaped.lines.forEach((l, i) => {
81
+ expect(l.width).toBeCloseTo(faceWidth(lines[i], false) * EM, 6);
82
+ expect(set[i].width).toBeCloseTo(l.width, 6);
83
+ });
84
+ });
85
+ it('a left-to-right line whole, whatever the document is shaped in', () => {
86
+ const text = 'This is one line. «And this is another.»';
87
+ const host = shape(text, 'en');
88
+ setMeasureLanguage('en');
89
+ const own = shape(text, 'en');
90
+ expect(own.lines).toEqual(host.lines);
91
+ own.shaped.lines.forEach((l, i) => {
92
+ expect(l.width).toBeCloseTo(faceWidth(own.lines[i], false) * EM, 6);
93
+ expect(l.width).toBeCloseTo(host.shaped.lines[i].width, 6);
94
+ });
95
+ });
96
+ });
97
+ //# sourceMappingURL=fitAsPainted.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fitAsPainted.test.js","sourceRoot":"","sources":["../../../../src/comics/lettering/__tests__/fitAsPainted.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"shape-text.d.ts","sourceRoot":"","sources":["../../../src/comics/lettering/shape-text.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAA6B,MAAM,aAAa,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAsE,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAC;AAE/G,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAEpD,+BAA+B;AAC/B,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ;wDACoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;2DACuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;0EAC0E;AAC1E,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,sEAAsE;IACtE,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,qDAAqD;IACrD,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvD,sEAAsE;IACtE,GAAG,EAAE,IAAI,EAAE,CAAC;IACZ,MAAM,EAAE,IAAI,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd;yEACqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB;iBACa;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,8CAA8C;AAC9C,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C;;yEAEyE;AACzE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAErE;AAED;;gBAEgB;AAChB,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAKxD;AA6YD,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,CAItF;AAeD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,YAAY,GAAG,UAAU,CAEhG;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CA6B3H;AAwMD,8DAA8D;AAC9D,wBAAgB,KAAK,CAAC,KAAK,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,EAAE,CAgBtF;AAED;4DAC4D;AAC5D,wBAAgB,cAAc,CAAC,KAAK,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,kBAAkB,CAMpG"}
1
+ {"version":3,"file":"shape-text.d.ts","sourceRoot":"","sources":["../../../src/comics/lettering/shape-text.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAA6B,MAAM,aAAa,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAsE,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAC;AAE/G,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAEpD,+BAA+B;AAC/B,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ;wDACoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;2DACuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;0EAC0E;AAC1E,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,sEAAsE;IACtE,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,qDAAqD;IACrD,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvD,sEAAsE;IACtE,GAAG,EAAE,IAAI,EAAE,CAAC;IACZ,MAAM,EAAE,IAAI,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd;yEACqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB;iBACa;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,8CAA8C;AAC9C,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C;;yEAEyE;AACzE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAErE;AAED;;gBAEgB;AAChB,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAKxD;AA0aD,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,CAItF;AAeD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,YAAY,GAAG,UAAU,CAEhG;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CAgC3H;AAwMD,8DAA8D;AAC9D,wBAAgB,KAAK,CAAC,KAAK,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,EAAE,CAgBtF;AAED;4DAC4D;AAC5D,wBAAgB,cAAc,CAAC,KAAK,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,kBAAkB,CAMpG"}
@@ -19,7 +19,7 @@ import { parseRichDesignText, richDesignSpans, richFontSet, RichMeasurer } from
19
19
  import { composeCjkDesignParagraph, composesDesignAsCjk } from '../../design/cjkText';
20
20
  import { cjkCompositionKey, getCjkComposition, setCjkComposition } from '../../measure/cjkPunctuation';
21
21
  import { layoutTextElementAt } from '../../design/layout';
22
- import { designBaseDirection } from '../../design/bidiText';
22
+ import { designBaseDirection, directedTextWidth, measuresRunsAsPainted } from '../../design/bidiText';
23
23
  import { primitiveToBlock } from '../../pipeline/headerFooter';
24
24
  import { cjkRegionOf, directionOf, isJapaneseLanguage, languageOf } from '../../locale';
25
25
  import { breakPoints, hasMarks, isIsolateControl, markupOf } from './text';
@@ -101,10 +101,10 @@ function measuringComposition(c) {
101
101
  * title in two (the comparison of #723). A text whose lines hold no pair
102
102
  * is shaped as it was.
103
103
  */
104
- function composedWidth(text, spans, fonts, pitch, tracking) {
104
+ function composedWidth(text, spans, fonts, pitch, tracking, flowIn) {
105
105
  if (text.includes('\n') || !composesDesignAsCjk(text))
106
106
  return undefined;
107
- const measureIn = (t, font) => Math.max(0, flowTextWidth(t, font) + tracking * graphemeCount(t));
107
+ const measureIn = (t, font) => Math.max(0, flowIn(t, font) + tracking * graphemeCount(t));
108
108
  const own = getCjkComposition();
109
109
  setCjkComposition(measuringComposition(own));
110
110
  try {
@@ -115,6 +115,27 @@ function composedWidth(text, spans, fonts, pitch, tracking) {
115
115
  setCjkComposition(own);
116
116
  }
117
117
  }
118
+ /**
119
+ * How the lines a shaping tries are measured, untracked: as the layout
120
+ * that sets the chosen ones measures them (`layoutTextElement`).
121
+ *
122
+ * That is `flowTextWidth`, the text whole and left to right, in a document
123
+ * shaped in its host's language and down a column. In a document shaped
124
+ * in its own language the layout sets a line as wide as its runs are
125
+ * painted, each in its own direction (#770, `measuresRunsAsPainted`), and
126
+ * the shaping measures the same: the line's bidi levels resolved at
127
+ * `base`, the direction the balloon is set at, each run in the direction
128
+ * it is painted in. Measured left to right, the line
129
+ * `منارة بورثكوف، هنا «غانيت».` of an Arabic balloon in Playpen Sans
130
+ * Arabic at 15.625 px is 176.82 px wide, and it is set and painted
131
+ * 177.18 px wide (Chrome 154, in `ar`): its stop and its closing guillemet
132
+ * are a run apart there, and one run with the words when painted. A line
133
+ * with no right-to-left character at a left-to-right base is measured
134
+ * whole either way.
135
+ */
136
+ function flowMeasure(base) {
137
+ return base !== undefined && measuresRunsAsPainted() ? (t, font) => directedTextWidth(t, font, base) : flowTextWidth;
138
+ }
118
139
  /** A measurer of line widths over the prepared text, in the writing mode
119
140
  * in force (call inside `withMeasureWritingMode`). Rich text is measured
120
141
  * through the design-text measurer of its own markup, so that what is
@@ -123,16 +144,18 @@ function composedWidth(text, spans, fonts, pitch, tracking) {
123
144
  * sets with the CJK composer is measured by composing it (#723, see
124
145
  * `composedWidth`): the shaping asks for it, the ruby does not (it
125
146
  * places a reading along a line, and the start of a line is no line of
126
- * its own). */
127
- function measurerFor(p, style, composed = false) {
147
+ * its own). `base`: the direction the lines are set at, for a measurer
148
+ * of whole lines ({@link flowMeasure}); the ruby gives none. */
149
+ function measurerFor(p, style, composed = false, base) {
128
150
  const tracking = trackingOf(p, style);
129
151
  const pitch = style.fontSizePx * style.lineHeight;
130
152
  const memo = new Map();
131
153
  const key = (a, b) => a * 100003 + b;
154
+ const flowIn = flowMeasure(base);
132
155
  if (hasMarks(p)) {
133
156
  const rt = parseRichDesignText(wholeMarkup(p), fontSpec(style));
134
157
  if (rt.text === p.text) {
135
- const m = new RichMeasurer(rt, tracking);
158
+ const m = new RichMeasurer(rt, tracking, flowIn === flowTextWidth ? undefined : flowIn);
136
159
  const fonts = composed ? richFontSet(fontSpec(style)) : undefined;
137
160
  return {
138
161
  rich: true,
@@ -140,7 +163,7 @@ function measurerFor(p, style, composed = false) {
140
163
  const k = key(a, b);
141
164
  let w = memo.get(k);
142
165
  if (w === undefined) {
143
- w = a >= b ? 0 : (fonts && composedWidth(p.text.slice(a, b), () => richDesignSpans(rt, a, b), fonts, pitch, tracking)) ?? m.measure(a, b);
166
+ w = a >= b ? 0 : (fonts && composedWidth(p.text.slice(a, b), () => richDesignSpans(rt, a, b), fonts, pitch, tracking, flowIn)) ?? m.measure(a, b);
144
167
  memo.set(k, w);
145
168
  }
146
169
  return w;
@@ -158,8 +181,10 @@ function measurerFor(p, style, composed = false) {
158
181
  if (w === undefined) {
159
182
  const row = p.text.slice(a, b);
160
183
  const s = row.replace(/[\u2066-\u2069]/g, '');
161
- w = a >= b ? 0 : (fonts && composedWidth(row, () => [{ text: row, bold: false, italic: false }], fonts, pitch, tracking))
162
- ?? Math.max(0, flowTextWidth(s, font) + tracking * graphemeCount(s));
184
+ // The isolates of a line set its runs' levels and print nothing:
185
+ // they stay in the text whose runs are resolved, as in the layout.
186
+ w = a >= b ? 0 : (fonts && composedWidth(row, () => [{ text: row, bold: false, italic: false }], fonts, pitch, tracking, flowIn))
187
+ ?? Math.max(0, (flowIn === flowTextWidth ? flowTextWidth(s, font) : flowIn(row, font)) + tracking * graphemeCount(s));
163
188
  memo.set(k, w);
164
189
  }
165
190
  return w;
@@ -425,10 +450,13 @@ export function shapeTextCandidates(p, style, opts, count) {
425
450
  breakings.set(p, (byKey = new Map()));
426
451
  // The composition is part of the key: a line the CJK composer sets is
427
452
  // measured by composing it (#723).
428
- const key = [mode, region, level, lang === 'ja', fontString(style), style.letterSpacing ?? 0, style.lineHeight, cjkCompositionKey(getCjkComposition())].join('|');
453
+ // So is the direction the lines are set at, which a document shaped
454
+ // in its own language measures them in (`flowMeasure`).
455
+ const base = vertical ? undefined : baseDirection(p.text, opts.locale);
456
+ const key = [mode, region, level, lang === 'ja', fontString(style), style.letterSpacing ?? 0, style.lineHeight, cjkCompositionKey(getCjkComposition()), base ?? ''].join('|');
429
457
  let b = byKey.get(key);
430
458
  if (!b)
431
- byKey.set(key, (b = breakingOf(p, breakPoints(p, level, lang === 'ja'), measurerFor(p, style, true))));
459
+ byKey.set(key, (b = breakingOf(p, breakPoints(p, level, lang === 'ja'), measurerFor(p, style, true, base))));
432
460
  // Japanese phrase breaks weigh more than a perfect profile: columns
433
461
  // move by whole characters.
434
462
  const penaltyWeight = lang === 'ja' ? 1 : 0.5;