postext 1.14.1 → 1.15.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 (494) hide show
  1. package/dist/__tests__/arabic/blockLanguageDigits.test.d.ts +2 -0
  2. package/dist/__tests__/arabic/blockLanguageDigits.test.d.ts.map +1 -0
  3. package/dist/__tests__/arabic/blockLanguageDigits.test.js +54 -0
  4. package/dist/__tests__/arabic/blockLanguageDigits.test.js.map +1 -0
  5. package/dist/__tests__/arabic/emphasis.test.d.ts +2 -0
  6. package/dist/__tests__/arabic/emphasis.test.d.ts.map +1 -0
  7. package/dist/__tests__/arabic/emphasis.test.js +206 -0
  8. package/dist/__tests__/arabic/emphasis.test.js.map +1 -0
  9. package/dist/__tests__/arabic/footnotes.test.d.ts +2 -0
  10. package/dist/__tests__/arabic/footnotes.test.d.ts.map +1 -0
  11. package/dist/__tests__/arabic/footnotes.test.js +118 -0
  12. package/dist/__tests__/arabic/footnotes.test.js.map +1 -0
  13. package/dist/__tests__/arabic/harakat.test.d.ts +2 -0
  14. package/dist/__tests__/arabic/harakat.test.d.ts.map +1 -0
  15. package/dist/__tests__/arabic/harakat.test.js +167 -0
  16. package/dist/__tests__/arabic/harakat.test.js.map +1 -0
  17. package/dist/__tests__/arabic/ornateBrackets.test.d.ts +2 -0
  18. package/dist/__tests__/arabic/ornateBrackets.test.d.ts.map +1 -0
  19. package/dist/__tests__/arabic/ornateBrackets.test.js +71 -0
  20. package/dist/__tests__/arabic/ornateBrackets.test.js.map +1 -0
  21. package/dist/__tests__/arabic/tashkil.test.d.ts +2 -0
  22. package/dist/__tests__/arabic/tashkil.test.d.ts.map +1 -0
  23. package/dist/__tests__/arabic/tashkil.test.js +106 -0
  24. package/dist/__tests__/arabic/tashkil.test.js.map +1 -0
  25. package/dist/__tests__/arabicLocale.test.d.ts +2 -0
  26. package/dist/__tests__/arabicLocale.test.d.ts.map +1 -0
  27. package/dist/__tests__/arabicLocale.test.js +232 -0
  28. package/dist/__tests__/arabicLocale.test.js.map +1 -0
  29. package/dist/__tests__/arabicNumberWords.test.d.ts +2 -0
  30. package/dist/__tests__/arabicNumberWords.test.d.ts.map +1 -0
  31. package/dist/__tests__/arabicNumberWords.test.js +176 -0
  32. package/dist/__tests__/arabicNumberWords.test.js.map +1 -0
  33. package/dist/__tests__/arabicNumbering.test.d.ts +2 -0
  34. package/dist/__tests__/arabicNumbering.test.d.ts.map +1 -0
  35. package/dist/__tests__/arabicNumbering.test.js +257 -0
  36. package/dist/__tests__/arabicNumbering.test.js.map +1 -0
  37. package/dist/__tests__/arabicWords.test.d.ts +2 -0
  38. package/dist/__tests__/arabicWords.test.d.ts.map +1 -0
  39. package/dist/__tests__/arabicWords.test.js +302 -0
  40. package/dist/__tests__/arabicWords.test.js.map +1 -0
  41. package/dist/__tests__/bidi.test.d.ts +2 -0
  42. package/dist/__tests__/bidi.test.d.ts.map +1 -0
  43. package/dist/__tests__/bidi.test.js +282 -0
  44. package/dist/__tests__/bidi.test.js.map +1 -0
  45. package/dist/__tests__/blockHints.test.d.ts +2 -0
  46. package/dist/__tests__/blockHints.test.d.ts.map +1 -0
  47. package/dist/__tests__/blockHints.test.js +79 -0
  48. package/dist/__tests__/blockHints.test.js.map +1 -0
  49. package/dist/__tests__/chineseLocale.test.js +2 -2
  50. package/dist/__tests__/chineseLocale.test.js.map +1 -1
  51. package/dist/__tests__/cjk/grid.test.js +2 -2
  52. package/dist/__tests__/cjk/grid.test.js.map +1 -1
  53. package/dist/__tests__/cjk/justifyRender.test.js +2 -1
  54. package/dist/__tests__/cjk/justifyRender.test.js.map +1 -1
  55. package/dist/__tests__/defaults/folio.test.js +16 -1
  56. package/dist/__tests__/defaults/folio.test.js.map +1 -1
  57. package/dist/__tests__/direction.test.d.ts +2 -0
  58. package/dist/__tests__/direction.test.d.ts.map +1 -0
  59. package/dist/__tests__/direction.test.js +117 -0
  60. package/dist/__tests__/direction.test.js.map +1 -0
  61. package/dist/__tests__/exports.test.js +29 -0
  62. package/dist/__tests__/exports.test.js.map +1 -1
  63. package/dist/__tests__/headingLetterSpacing.test.js +1 -1
  64. package/dist/__tests__/headingLetterSpacing.test.js.map +1 -1
  65. package/dist/__tests__/headingNumberPosition.test.d.ts +2 -0
  66. package/dist/__tests__/headingNumberPosition.test.d.ts.map +1 -0
  67. package/dist/__tests__/headingNumberPosition.test.js +87 -0
  68. package/dist/__tests__/headingNumberPosition.test.js.map +1 -0
  69. package/dist/__tests__/htmlCopyText.test.d.ts +2 -0
  70. package/dist/__tests__/htmlCopyText.test.d.ts.map +1 -0
  71. package/dist/__tests__/htmlCopyText.test.js +153 -0
  72. package/dist/__tests__/htmlCopyText.test.js.map +1 -0
  73. package/dist/__tests__/kashida.test.d.ts +2 -0
  74. package/dist/__tests__/kashida.test.d.ts.map +1 -0
  75. package/dist/__tests__/kashida.test.js +281 -0
  76. package/dist/__tests__/kashida.test.js.map +1 -0
  77. package/dist/__tests__/kashidaPatterns.test.d.ts +2 -0
  78. package/dist/__tests__/kashidaPatterns.test.d.ts.map +1 -0
  79. package/dist/__tests__/kashidaPatterns.test.js +143 -0
  80. package/dist/__tests__/kashidaPatterns.test.js.map +1 -0
  81. package/dist/__tests__/links.test.js +3 -1
  82. package/dist/__tests__/links.test.js.map +1 -1
  83. package/dist/__tests__/parse/anchors.test.js +17 -0
  84. package/dist/__tests__/parse/anchors.test.js.map +1 -1
  85. package/dist/__tests__/parse/containers.test.js +1 -1
  86. package/dist/__tests__/parse/containers.test.js.map +1 -1
  87. package/dist/__tests__/rtl/designText.test.d.ts +2 -0
  88. package/dist/__tests__/rtl/designText.test.d.ts.map +1 -0
  89. package/dist/__tests__/rtl/designText.test.js +301 -0
  90. package/dist/__tests__/rtl/designText.test.js.map +1 -0
  91. package/dist/__tests__/rtl/designTextPaint.test.d.ts +2 -0
  92. package/dist/__tests__/rtl/designTextPaint.test.d.ts.map +1 -0
  93. package/dist/__tests__/rtl/designTextPaint.test.js +140 -0
  94. package/dist/__tests__/rtl/designTextPaint.test.js.map +1 -0
  95. package/dist/__tests__/rtl/htmlRtl.test.d.ts +2 -0
  96. package/dist/__tests__/rtl/htmlRtl.test.d.ts.map +1 -0
  97. package/dist/__tests__/rtl/htmlRtl.test.js +175 -0
  98. package/dist/__tests__/rtl/htmlRtl.test.js.map +1 -0
  99. package/dist/__tests__/rtl/mirroredFrame.test.d.ts +2 -0
  100. package/dist/__tests__/rtl/mirroredFrame.test.d.ts.map +1 -0
  101. package/dist/__tests__/rtl/mirroredFrame.test.js +313 -0
  102. package/dist/__tests__/rtl/mirroredFrame.test.js.map +1 -0
  103. package/dist/__tests__/rtl/mirroredPaint.test.d.ts +2 -0
  104. package/dist/__tests__/rtl/mirroredPaint.test.d.ts.map +1 -0
  105. package/dist/__tests__/rtl/mirroredPaint.test.js +116 -0
  106. package/dist/__tests__/rtl/mirroredPaint.test.js.map +1 -0
  107. package/dist/__tests__/rtl/oppositeBlocks.test.d.ts +2 -0
  108. package/dist/__tests__/rtl/oppositeBlocks.test.d.ts.map +1 -0
  109. package/dist/__tests__/rtl/oppositeBlocks.test.js +273 -0
  110. package/dist/__tests__/rtl/oppositeBlocks.test.js.map +1 -0
  111. package/dist/__tests__/rtl/segmentLang.test.d.ts +2 -0
  112. package/dist/__tests__/rtl/segmentLang.test.d.ts.map +1 -0
  113. package/dist/__tests__/rtl/segmentLang.test.js +54 -0
  114. package/dist/__tests__/rtl/segmentLang.test.js.map +1 -0
  115. package/dist/__tests__/rtlLines.test.d.ts +2 -0
  116. package/dist/__tests__/rtlLines.test.d.ts.map +1 -0
  117. package/dist/__tests__/rtlLines.test.js +180 -0
  118. package/dist/__tests__/rtlLines.test.js.map +1 -0
  119. package/dist/__tests__/tocNumberColumn.test.d.ts +2 -0
  120. package/dist/__tests__/tocNumberColumn.test.d.ts.map +1 -0
  121. package/dist/__tests__/tocNumberColumn.test.js +67 -0
  122. package/dist/__tests__/tocNumberColumn.test.js.map +1 -0
  123. package/dist/__tests__/verse.test.d.ts +2 -0
  124. package/dist/__tests__/verse.test.d.ts.map +1 -0
  125. package/dist/__tests__/verse.test.js +232 -0
  126. package/dist/__tests__/verse.test.js.map +1 -0
  127. package/dist/__tests__/vertical/geometry.test.js +2 -2
  128. package/dist/__tests__/vertical/geometry.test.js.map +1 -1
  129. package/dist/__tests__/vertical/htmlTurnedCells.test.js +2 -2
  130. package/dist/__tests__/vertical/htmlTurnedCells.test.js.map +1 -1
  131. package/dist/arabicMarks.d.ts +80 -0
  132. package/dist/arabicMarks.d.ts.map +1 -0
  133. package/dist/arabicMarks.js +267 -0
  134. package/dist/arabicMarks.js.map +1 -0
  135. package/dist/arabicNumberWords.d.ts +43 -0
  136. package/dist/arabicNumberWords.d.ts.map +1 -0
  137. package/dist/arabicNumberWords.js +163 -0
  138. package/dist/arabicNumberWords.js.map +1 -0
  139. package/dist/arabicNumerals.d.ts +54 -0
  140. package/dist/arabicNumerals.d.ts.map +1 -0
  141. package/dist/arabicNumerals.js +143 -0
  142. package/dist/arabicNumerals.js.map +1 -0
  143. package/dist/bidi.d.ts +186 -0
  144. package/dist/bidi.d.ts.map +1 -0
  145. package/dist/bidi.js +851 -0
  146. package/dist/bidi.js.map +1 -0
  147. package/dist/bidiData.d.ts +13 -0
  148. package/dist/bidiData.d.ts.map +1 -0
  149. package/dist/bidiData.js +318 -0
  150. package/dist/bidiData.js.map +1 -0
  151. package/dist/canvas-backend/blockRender.d.ts.map +1 -1
  152. package/dist/canvas-backend/blockRender.js +58 -27
  153. package/dist/canvas-backend/blockRender.js.map +1 -1
  154. package/dist/canvas-backend/chip.d.ts.map +1 -1
  155. package/dist/canvas-backend/chip.js +16 -2
  156. package/dist/canvas-backend/chip.js.map +1 -1
  157. package/dist/canvas-backend/headerFooter.d.ts.map +1 -1
  158. package/dist/canvas-backend/headerFooter.js +7 -3
  159. package/dist/canvas-backend/headerFooter.js.map +1 -1
  160. package/dist/canvas-backend/index.d.ts.map +1 -1
  161. package/dist/canvas-backend/index.js +9 -4
  162. package/dist/canvas-backend/index.js.map +1 -1
  163. package/dist/canvas-backend/mirrorFrame.d.ts +38 -0
  164. package/dist/canvas-backend/mirrorFrame.d.ts.map +1 -0
  165. package/dist/canvas-backend/mirrorFrame.js +129 -0
  166. package/dist/canvas-backend/mirrorFrame.js.map +1 -0
  167. package/dist/canvas-backend/renderResourceBlock.d.ts.map +1 -1
  168. package/dist/canvas-backend/renderResourceBlock.js +16 -5
  169. package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
  170. package/dist/canvas-backend/runDirection.d.ts +21 -0
  171. package/dist/canvas-backend/runDirection.d.ts.map +1 -0
  172. package/dist/canvas-backend/runDirection.js +46 -0
  173. package/dist/canvas-backend/runDirection.js.map +1 -0
  174. package/dist/canvas-backend/wordRuns.d.ts +49 -0
  175. package/dist/canvas-backend/wordRuns.d.ts.map +1 -0
  176. package/dist/canvas-backend/wordRuns.js +111 -0
  177. package/dist/canvas-backend/wordRuns.js.map +1 -0
  178. package/dist/columnClip.d.ts +4 -1
  179. package/dist/columnClip.d.ts.map +1 -1
  180. package/dist/columnClip.js +8 -3
  181. package/dist/columnClip.js.map +1 -1
  182. package/dist/configWarnings.d.ts +3 -1
  183. package/dist/configWarnings.d.ts.map +1 -1
  184. package/dist/configWarnings.js +59 -5
  185. package/dist/configWarnings.js.map +1 -1
  186. package/dist/defaults/bodyText.d.ts +28 -6
  187. package/dist/defaults/bodyText.d.ts.map +1 -1
  188. package/dist/defaults/bodyText.js +158 -30
  189. package/dist/defaults/bodyText.js.map +1 -1
  190. package/dist/defaults/calloutStyles.js +1 -1
  191. package/dist/defaults/calloutStyles.js.map +1 -1
  192. package/dist/defaults/captionStyle.js +5 -5
  193. package/dist/defaults/captionStyle.js.map +1 -1
  194. package/dist/defaults/folio.d.ts +4 -0
  195. package/dist/defaults/folio.d.ts.map +1 -1
  196. package/dist/defaults/folio.js +12 -1
  197. package/dist/defaults/folio.js.map +1 -1
  198. package/dist/defaults/footnotes.d.ts.map +1 -1
  199. package/dist/defaults/footnotes.js +12 -2
  200. package/dist/defaults/footnotes.js.map +1 -1
  201. package/dist/defaults/headerFooter.d.ts.map +1 -1
  202. package/dist/defaults/headerFooter.js +1 -0
  203. package/dist/defaults/headerFooter.js.map +1 -1
  204. package/dist/defaults/headingStyles.d.ts.map +1 -1
  205. package/dist/defaults/headingStyles.js +2 -1
  206. package/dist/defaults/headingStyles.js.map +1 -1
  207. package/dist/defaults/headings.d.ts.map +1 -1
  208. package/dist/defaults/headings.js +9 -2
  209. package/dist/defaults/headings.js.map +1 -1
  210. package/dist/defaults/index.d.ts +1 -1
  211. package/dist/defaults/index.d.ts.map +1 -1
  212. package/dist/defaults/index.js +7 -1
  213. package/dist/defaults/index.js.map +1 -1
  214. package/dist/defaults/indexConfig.d.ts +6 -2
  215. package/dist/defaults/indexConfig.d.ts.map +1 -1
  216. package/dist/defaults/indexConfig.js +25 -5
  217. package/dist/defaults/indexConfig.js.map +1 -1
  218. package/dist/defaults/page.d.ts +7 -4
  219. package/dist/defaults/page.d.ts.map +1 -1
  220. package/dist/defaults/page.js +10 -7
  221. package/dist/defaults/page.js.map +1 -1
  222. package/dist/defaults/paragraphStyles.js +2 -2
  223. package/dist/defaults/paragraphStyles.js.map +1 -1
  224. package/dist/defaults/parts.d.ts.map +1 -1
  225. package/dist/defaults/parts.js +2 -1
  226. package/dist/defaults/parts.js.map +1 -1
  227. package/dist/defaults/resourceTypes.d.ts +1 -1
  228. package/dist/defaults/resourceTypes.d.ts.map +1 -1
  229. package/dist/defaults/resourceTypes.js +10 -2
  230. package/dist/defaults/resourceTypes.js.map +1 -1
  231. package/dist/defaults/shared.d.ts +9 -0
  232. package/dist/defaults/shared.d.ts.map +1 -1
  233. package/dist/defaults/shared.js +15 -0
  234. package/dist/defaults/shared.js.map +1 -1
  235. package/dist/defaults/tableStyle.d.ts.map +1 -1
  236. package/dist/defaults/tableStyle.js +5 -1
  237. package/dist/defaults/tableStyle.js.map +1 -1
  238. package/dist/design/bidiText.d.ts +89 -0
  239. package/dist/design/bidiText.d.ts.map +1 -0
  240. package/dist/design/bidiText.js +165 -0
  241. package/dist/design/bidiText.js.map +1 -0
  242. package/dist/design/layout.d.ts +20 -0
  243. package/dist/design/layout.d.ts.map +1 -1
  244. package/dist/design/layout.js +46 -5
  245. package/dist/design/layout.js.map +1 -1
  246. package/dist/design/placeholders.d.ts +7 -1
  247. package/dist/design/placeholders.d.ts.map +1 -1
  248. package/dist/design/placeholders.js +6 -3
  249. package/dist/design/placeholders.js.map +1 -1
  250. package/dist/design/richText.d.ts +5 -2
  251. package/dist/design/richText.d.ts.map +1 -1
  252. package/dist/design/richText.js +35 -2
  253. package/dist/design/richText.js.map +1 -1
  254. package/dist/emphasisOverline.d.ts +27 -0
  255. package/dist/emphasisOverline.d.ts.map +1 -0
  256. package/dist/emphasisOverline.js +107 -0
  257. package/dist/emphasisOverline.js.map +1 -0
  258. package/dist/frontmatter.d.ts +25 -6
  259. package/dist/frontmatter.d.ts.map +1 -1
  260. package/dist/frontmatter.js +51 -10
  261. package/dist/frontmatter.js.map +1 -1
  262. package/dist/html-backend.d.ts +4 -1
  263. package/dist/html-backend.d.ts.map +1 -1
  264. package/dist/html-backend.js +363 -87
  265. package/dist/html-backend.js.map +1 -1
  266. package/dist/hyphenate.d.ts.map +1 -1
  267. package/dist/hyphenate.js +4 -1
  268. package/dist/hyphenate.js.map +1 -1
  269. package/dist/index.d.ts +11 -8
  270. package/dist/index.d.ts.map +1 -1
  271. package/dist/index.js +6 -4
  272. package/dist/index.js.map +1 -1
  273. package/dist/knuthPlass/breakpoints.d.ts.map +1 -1
  274. package/dist/knuthPlass/breakpoints.js +3 -0
  275. package/dist/knuthPlass/breakpoints.js.map +1 -1
  276. package/dist/knuthPlass/pretextAdapter.d.ts.map +1 -1
  277. package/dist/knuthPlass/pretextAdapter.js +9 -3
  278. package/dist/knuthPlass/pretextAdapter.js.map +1 -1
  279. package/dist/knuthPlass/richAdapter.d.ts +11 -0
  280. package/dist/knuthPlass/richAdapter.d.ts.map +1 -1
  281. package/dist/knuthPlass/richAdapter.js +11 -4
  282. package/dist/knuthPlass/richAdapter.js.map +1 -1
  283. package/dist/knuthPlass/tracking.d.ts +2 -1
  284. package/dist/knuthPlass/tracking.d.ts.map +1 -1
  285. package/dist/knuthPlass/tracking.js +5 -2
  286. package/dist/knuthPlass/tracking.js.map +1 -1
  287. package/dist/knuthPlass/types.d.ts +4 -0
  288. package/dist/knuthPlass/types.d.ts.map +1 -1
  289. package/dist/locale.d.ts +63 -9
  290. package/dist/locale.d.ts.map +1 -1
  291. package/dist/locale.js +129 -12
  292. package/dist/locale.js.map +1 -1
  293. package/dist/measure/bidiLines.d.ts +91 -0
  294. package/dist/measure/bidiLines.d.ts.map +1 -0
  295. package/dist/measure/bidiLines.js +293 -0
  296. package/dist/measure/bidiLines.js.map +1 -0
  297. package/dist/measure/cache.d.ts.map +1 -1
  298. package/dist/measure/cache.js +10 -4
  299. package/dist/measure/cache.js.map +1 -1
  300. package/dist/measure/joining.d.ts +39 -0
  301. package/dist/measure/joining.d.ts.map +1 -0
  302. package/dist/measure/joining.js +91 -0
  303. package/dist/measure/joining.js.map +1 -0
  304. package/dist/measure/joiningGroups.d.ts +7 -0
  305. package/dist/measure/joiningGroups.d.ts.map +1 -0
  306. package/dist/measure/joiningGroups.js +110 -0
  307. package/dist/measure/joiningGroups.js.map +1 -0
  308. package/dist/measure/kashida.d.ts +97 -0
  309. package/dist/measure/kashida.d.ts.map +1 -0
  310. package/dist/measure/kashida.js +285 -0
  311. package/dist/measure/kashida.js.map +1 -0
  312. package/dist/measure/kashidaPatterns.d.ts +109 -0
  313. package/dist/measure/kashidaPatterns.d.ts.map +1 -0
  314. package/dist/measure/kashidaPatterns.js +519 -0
  315. package/dist/measure/kashidaPatterns.js.map +1 -0
  316. package/dist/measure/links.d.ts.map +1 -1
  317. package/dist/measure/links.js +5 -2
  318. package/dist/measure/links.js.map +1 -1
  319. package/dist/measure/plain.d.ts.map +1 -1
  320. package/dist/measure/plain.js +31 -0
  321. package/dist/measure/plain.js.map +1 -1
  322. package/dist/measure/rich.d.ts +24 -0
  323. package/dist/measure/rich.d.ts.map +1 -1
  324. package/dist/measure/rich.js +250 -22
  325. package/dist/measure/rich.js.map +1 -1
  326. package/dist/measure/types.d.ts +14 -0
  327. package/dist/measure/types.d.ts.map +1 -1
  328. package/dist/measure/types.js.map +1 -1
  329. package/dist/numberWords.d.ts +17 -4
  330. package/dist/numberWords.d.ts.map +1 -1
  331. package/dist/numberWords.js +19 -13
  332. package/dist/numberWords.js.map +1 -1
  333. package/dist/numbering.d.ts +49 -11
  334. package/dist/numbering.d.ts.map +1 -1
  335. package/dist/numbering.js +117 -21
  336. package/dist/numbering.js.map +1 -1
  337. package/dist/parse/annotations.d.ts +6 -3
  338. package/dist/parse/annotations.d.ts.map +1 -1
  339. package/dist/parse/annotations.js +31 -7
  340. package/dist/parse/annotations.js.map +1 -1
  341. package/dist/parse/attrs.d.ts +3 -3
  342. package/dist/parse/attrs.d.ts.map +1 -1
  343. package/dist/parse/attrs.js +5 -4
  344. package/dist/parse/attrs.js.map +1 -1
  345. package/dist/parse/blockParser.d.ts.map +1 -1
  346. package/dist/parse/blockParser.js +158 -14
  347. package/dist/parse/blockParser.js.map +1 -1
  348. package/dist/parse/index.d.ts +1 -1
  349. package/dist/parse/index.d.ts.map +1 -1
  350. package/dist/parse/index.js.map +1 -1
  351. package/dist/parse/indexMarks.d.ts.map +1 -1
  352. package/dist/parse/indexMarks.js +32 -10
  353. package/dist/parse/indexMarks.js.map +1 -1
  354. package/dist/parse/inlineFormatting.d.ts.map +1 -1
  355. package/dist/parse/inlineFormatting.js +5 -4
  356. package/dist/parse/inlineFormatting.js.map +1 -1
  357. package/dist/parse/types.d.ts +63 -1
  358. package/dist/parse/types.d.ts.map +1 -1
  359. package/dist/pipeline/build.d.ts.map +1 -1
  360. package/dist/pipeline/build.js +161 -43
  361. package/dist/pipeline/build.js.map +1 -1
  362. package/dist/pipeline/buildBlockKind.d.ts +2 -0
  363. package/dist/pipeline/buildBlockKind.d.ts.map +1 -1
  364. package/dist/pipeline/buildBlockKind.js +67 -2
  365. package/dist/pipeline/buildBlockKind.js.map +1 -1
  366. package/dist/pipeline/buildHelpers.d.ts +22 -1
  367. package/dist/pipeline/buildHelpers.d.ts.map +1 -1
  368. package/dist/pipeline/buildHelpers.js +55 -5
  369. package/dist/pipeline/buildHelpers.js.map +1 -1
  370. package/dist/pipeline/calloutLayout.d.ts +6 -1
  371. package/dist/pipeline/calloutLayout.d.ts.map +1 -1
  372. package/dist/pipeline/calloutLayout.js +63 -18
  373. package/dist/pipeline/calloutLayout.js.map +1 -1
  374. package/dist/pipeline/citations.d.ts +2 -1
  375. package/dist/pipeline/citations.d.ts.map +1 -1
  376. package/dist/pipeline/citations.js +29 -9
  377. package/dist/pipeline/citations.js.map +1 -1
  378. package/dist/pipeline/cjkGrid.d.ts +3 -2
  379. package/dist/pipeline/cjkGrid.d.ts.map +1 -1
  380. package/dist/pipeline/cjkGrid.js +3 -2
  381. package/dist/pipeline/cjkGrid.js.map +1 -1
  382. package/dist/pipeline/config.d.ts +13 -1
  383. package/dist/pipeline/config.d.ts.map +1 -1
  384. package/dist/pipeline/config.js +32 -3
  385. package/dist/pipeline/config.js.map +1 -1
  386. package/dist/pipeline/contentWarnings.d.ts +10 -0
  387. package/dist/pipeline/contentWarnings.d.ts.map +1 -1
  388. package/dist/pipeline/contentWarnings.js +88 -0
  389. package/dist/pipeline/contentWarnings.js.map +1 -1
  390. package/dist/pipeline/continuation.d.ts.map +1 -1
  391. package/dist/pipeline/continuation.js +1 -1
  392. package/dist/pipeline/continuation.js.map +1 -1
  393. package/dist/pipeline/crossRefs.d.ts.map +1 -1
  394. package/dist/pipeline/crossRefs.js +2 -0
  395. package/dist/pipeline/crossRefs.js.map +1 -1
  396. package/dist/pipeline/floatPlacement.d.ts.map +1 -1
  397. package/dist/pipeline/floatPlacement.js +2 -1
  398. package/dist/pipeline/floatPlacement.js.map +1 -1
  399. package/dist/pipeline/footnotes.d.ts +13 -5
  400. package/dist/pipeline/footnotes.d.ts.map +1 -1
  401. package/dist/pipeline/footnotes.js +19 -8
  402. package/dist/pipeline/footnotes.js.map +1 -1
  403. package/dist/pipeline/headerFooter.d.ts +4 -0
  404. package/dist/pipeline/headerFooter.d.ts.map +1 -1
  405. package/dist/pipeline/headerFooter.js +41 -13
  406. package/dist/pipeline/headerFooter.js.map +1 -1
  407. package/dist/pipeline/headingDesignCuts.d.ts +1 -1
  408. package/dist/pipeline/headingDesignCuts.d.ts.map +1 -1
  409. package/dist/pipeline/headingDesignCuts.js +2 -1
  410. package/dist/pipeline/headingDesignCuts.js.map +1 -1
  411. package/dist/pipeline/headingStyles.d.ts +10 -0
  412. package/dist/pipeline/headingStyles.d.ts.map +1 -1
  413. package/dist/pipeline/headingStyles.js +46 -0
  414. package/dist/pipeline/headingStyles.js.map +1 -1
  415. package/dist/pipeline/indexDirective.d.ts.map +1 -1
  416. package/dist/pipeline/indexDirective.js +33 -6
  417. package/dist/pipeline/indexDirective.js.map +1 -1
  418. package/dist/pipeline/indexGroups.d.ts +23 -1
  419. package/dist/pipeline/indexGroups.d.ts.map +1 -1
  420. package/dist/pipeline/indexGroups.js +50 -1
  421. package/dist/pipeline/indexGroups.js.map +1 -1
  422. package/dist/pipeline/lists.d.ts +16 -4
  423. package/dist/pipeline/lists.d.ts.map +1 -1
  424. package/dist/pipeline/lists.js +51 -12
  425. package/dist/pipeline/lists.js.map +1 -1
  426. package/dist/pipeline/measureContentBlock.d.ts +5 -0
  427. package/dist/pipeline/measureContentBlock.d.ts.map +1 -1
  428. package/dist/pipeline/measureContentBlock.js +63 -4
  429. package/dist/pipeline/measureContentBlock.js.map +1 -1
  430. package/dist/pipeline/mirrorFrame.d.ts +37 -0
  431. package/dist/pipeline/mirrorFrame.d.ts.map +1 -0
  432. package/dist/pipeline/mirrorFrame.js +143 -0
  433. package/dist/pipeline/mirrorFrame.js.map +1 -0
  434. package/dist/pipeline/outline.d.ts +2 -2
  435. package/dist/pipeline/outline.d.ts.map +1 -1
  436. package/dist/pipeline/outline.js +33 -6
  437. package/dist/pipeline/outline.js.map +1 -1
  438. package/dist/pipeline/paragraphContainers.d.ts +5 -0
  439. package/dist/pipeline/paragraphContainers.d.ts.map +1 -1
  440. package/dist/pipeline/paragraphContainers.js +12 -0
  441. package/dist/pipeline/paragraphContainers.js.map +1 -1
  442. package/dist/pipeline/parts.d.ts +1 -1
  443. package/dist/pipeline/parts.d.ts.map +1 -1
  444. package/dist/pipeline/parts.js +3 -2
  445. package/dist/pipeline/parts.js.map +1 -1
  446. package/dist/pipeline/placeholders.d.ts +13 -6
  447. package/dist/pipeline/placeholders.d.ts.map +1 -1
  448. package/dist/pipeline/placeholders.js +15 -11
  449. package/dist/pipeline/placeholders.js.map +1 -1
  450. package/dist/pipeline/placement.d.ts +3 -2
  451. package/dist/pipeline/placement.d.ts.map +1 -1
  452. package/dist/pipeline/placement.js +18 -6
  453. package/dist/pipeline/placement.js.map +1 -1
  454. package/dist/pipeline/resourceLayout.d.ts.map +1 -1
  455. package/dist/pipeline/resourceLayout.js +70 -7
  456. package/dist/pipeline/resourceLayout.js.map +1 -1
  457. package/dist/pipeline/resourceNumbering.d.ts +5 -3
  458. package/dist/pipeline/resourceNumbering.d.ts.map +1 -1
  459. package/dist/pipeline/resourceNumbering.js +11 -8
  460. package/dist/pipeline/resourceNumbering.js.map +1 -1
  461. package/dist/pipeline/styles.d.ts +6 -1
  462. package/dist/pipeline/styles.d.ts.map +1 -1
  463. package/dist/pipeline/styles.js +44 -14
  464. package/dist/pipeline/styles.js.map +1 -1
  465. package/dist/pipeline/tashkil.d.ts +27 -0
  466. package/dist/pipeline/tashkil.d.ts.map +1 -0
  467. package/dist/pipeline/tashkil.js +161 -0
  468. package/dist/pipeline/tashkil.js.map +1 -0
  469. package/dist/pipeline/toc.d.ts +12 -0
  470. package/dist/pipeline/toc.d.ts.map +1 -1
  471. package/dist/pipeline/toc.js +64 -4
  472. package/dist/pipeline/toc.js.map +1 -1
  473. package/dist/pipeline/verse.d.ts +65 -0
  474. package/dist/pipeline/verse.d.ts.map +1 -0
  475. package/dist/pipeline/verse.js +252 -0
  476. package/dist/pipeline/verse.js.map +1 -0
  477. package/dist/pipeline/verticalMetrics.d.ts +1 -1
  478. package/dist/pipeline/verticalMetrics.d.ts.map +1 -1
  479. package/dist/pipeline/verticalMetrics.js +7 -5
  480. package/dist/pipeline/verticalMetrics.js.map +1 -1
  481. package/dist/table/model.d.ts +4 -3
  482. package/dist/table/model.d.ts.map +1 -1
  483. package/dist/table/model.js.map +1 -1
  484. package/dist/types.d.ts +286 -36
  485. package/dist/types.d.ts.map +1 -1
  486. package/dist/uprightArabic.d.ts +39 -0
  487. package/dist/uprightArabic.d.ts.map +1 -0
  488. package/dist/uprightArabic.js +105 -0
  489. package/dist/uprightArabic.js.map +1 -0
  490. package/dist/vdt.d.ts +276 -11
  491. package/dist/vdt.d.ts.map +1 -1
  492. package/dist/vdt.js +46 -9
  493. package/dist/vdt.js.map +1 -1
  494. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
+ import { uprightArabicSpans, uprightFace } from '../uprightArabic';
1
2
  import { createBoundingBox } from '../vdt';
2
3
  import { hyphenateText, withoutSlashJoints } from '../hyphenate';
3
4
  import { richTokensToItems, computeBreakpoints, reconstructRichLines, } from '../knuthPlass';
@@ -8,6 +9,7 @@ import { isRuntLastLine } from './runts';
8
9
  import { computeJustifiedSpaceRatio, hasOverfullLine } from './plain';
9
10
  import { quoteFamily } from './font';
10
11
  import { trimChipLineEdges } from './chipEdges';
12
+ import { directChipRuns } from '../design/bidiText';
11
13
  import { cjkJoinBreaks, hasCJK } from './cjk';
12
14
  import { composeCjkParagraph, cjkWordBreaks, composesAsCjk, spanMarks } from './cjkCompose';
13
15
  import { graphemeCount, graphemesOf } from './graphemes';
@@ -17,6 +19,10 @@ import { sliceSpan } from '../parse/links';
17
19
  import { NO_BREAK_SPACES, WORDS_AND_SPACES_RE, isBlankText, isBreakingSpace, isBreakingSpaceRun } from './spaces';
18
20
  import { breaksAfterDash, breaksAfterHardHyphen, hasCompound, isDash, raggedStretchPx } from './breakRules';
19
21
  import { GEMINATE_DOT, endsInsideGeminate, withLineEndHyphen } from './geminate';
22
+ import { insideJoiningWord, joiningScriptIn, wordLetterSpacing } from './joining';
23
+ import { applyLineDirections, applySegmentLanguages, getMeasureDirection, spanLanguages } from './bidiLines';
24
+ import { TATWEEL, justifyLinesWithKashida, kashidaCapacity } from './kashida';
25
+ import { needsBidi, resolveParagraph, spanIsolates } from '../bidi';
20
26
  /** Whether a resolved swatch colour can fill the square: a six- or
21
27
  * eight-digit hex (`#rrggbb`, `#rrggbbaa`) or an `rgb()` / `rgba()`
22
28
  * colour. Anything else leaves the swatch an empty outline. */
@@ -101,13 +107,14 @@ export function stackedScriptPairs(scripts) {
101
107
  /** Font a token is measured with: its span font, or the script font of a
102
108
  * superscript / subscript. */
103
109
  function tokenFont(t, normalFont, boldFont, italicFont, boldItalicFont) {
104
- return t.scriptFont ?? pickSpanFont(t.bold, t.italic, normalFont, boldFont, italicFont, boldItalicFont);
110
+ return t.scriptFont ?? t.faceFont ?? pickSpanFont(t.bold, t.italic, normalFont, boldFont, italicFont, boldItalicFont);
105
111
  }
106
112
  /** The script, small-caps and Chinese-mark fields a token derived from
107
113
  * another (a split, a hyphenated head) carries on. */
108
114
  function scriptOf(t) {
109
115
  return {
110
116
  ...(t.script ? { script: t.script, scriptFont: t.scriptFont, baselineShift: t.baselineShift } : {}),
117
+ ...(t.faceFont ? { faceFont: t.faceFont } : {}),
111
118
  ...(t.smallCaps ? { smallCaps: true } : {}),
112
119
  ...(t.cjkMarks ? { cjkMarks: t.cjkMarks } : {}),
113
120
  ...(t.inserted ? { inserted: true } : {}),
@@ -273,7 +280,8 @@ export function chipToken(span, normalFont, boldFont, italicFont, boldItalicFont
273
280
  runs.push({
274
281
  text: piece.text,
275
282
  fontString: piece.font,
276
- width: measureTextWidth(piece.text, piece.font) + letterSpacingPx * graphemeCount(piece.text),
283
+ // A run of a joining script takes no tracking (`measure/joining.ts`).
284
+ width: measureTextWidth(piece.text, piece.font) + wordLetterSpacing(piece.text, letterSpacingPx) * graphemeCount(piece.text),
277
285
  ...(bold ? { bold: true } : {}),
278
286
  ...(italic ? { italic: true } : {}),
279
287
  ...(baselineShift !== undefined ? { baselineShift } : {}),
@@ -292,6 +300,9 @@ export function chipToken(span, normalFont, boldFont, italicFont, boldItalicFont
292
300
  first.width = 0;
293
301
  first.stacked = true;
294
302
  }
303
+ // Right-to-left runs cut where the direction changes, and their order
304
+ // (`VDTChip.order`).
305
+ const directed = directChipRuns(runs, (t, f) => measureTextWidth(t, f) + wordLetterSpacing(t, letterSpacingPx) * graphemeCount(t));
295
306
  const textWidth = runs.reduce((sum, r) => sum + r.width, 0);
296
307
  const paddingX = box?.paddingXPx ?? 0;
297
308
  const paddingY = box?.paddingYPx ?? 0;
@@ -311,7 +322,8 @@ export function chipToken(span, normalFont, boldFont, italicFont, boldItalicFont
311
322
  width: boxWidth,
312
323
  chip: {
313
324
  styleId: box?.styleId ?? '',
314
- runs,
325
+ runs: directed.runs,
326
+ ...(directed.order ? { order: directed.order } : {}),
315
327
  marginLeft: 0,
316
328
  marginRight: 0,
317
329
  boxWidth,
@@ -426,6 +438,10 @@ export function urlBreakIndices(text) {
426
438
  * not break there, and it must not reach the line text.
427
439
  */
428
440
  function syllabify(word, hyphenate) {
441
+ // A word of a joining script is never divided, not even at a soft hyphen
442
+ // its author typed: its letters connect (`measure/joining.ts`).
443
+ if (joiningScriptIn(word))
444
+ return { clean: word.includes(SOFT_HYPHEN) ? word.split(SOFT_HYPHEN).join('') : word, soft: [] };
429
445
  const hyphenated = hyphenate ? withoutSlashJoints(word, hyphenateText(word)) : word;
430
446
  if (!hyphenated.includes(SOFT_HYPHEN))
431
447
  return { clean: hyphenated, soft: [] };
@@ -509,13 +525,25 @@ function wordBreakPoints(clean, soft, font, letterSpacingPx, smallCaps, dashBrea
509
525
  * the word carries falls after it and adds none (`hard`): never "fisica-" |
510
526
  * "-universitaria" nor "fisica--". Null when not even one character fits,
511
527
  * or, with `syllablesOnly`, when no no-break space or syllable does.
528
+ *
529
+ * A word of a joining script (Arabic…) is never cut between its letters,
530
+ * and no hyphen marks a cut in it: only at a no-break space, or where it
531
+ * touches a run of another script (`ABCكتاب`), with nothing added. Null
532
+ * when no such place fits: the word then runs past the measure, and the
533
+ * line says so (`VDTLine.wordOverflow`).
512
534
  */
513
535
  export function emergencySplit(token, font, letterSpacingPx, lineMaxWidth, syllablesOnly = false) {
514
536
  const text = token.text;
515
537
  if (text.length < 2)
516
538
  return null;
517
- const hyphenW = measureTextWidth('-', font) + letterSpacingPx;
518
- const widthBefore = (idx) => textWidth(text.slice(0, idx), font, token.smallCaps) + (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(text.slice(0, idx)));
539
+ // Styled runs of one Arabic word (`RichToken.runs`) are one shaped word.
540
+ if (token.runs)
541
+ return null;
542
+ const joining = joiningScriptIn(text);
543
+ // The word was measured untracked (`wordLetterSpacing`): its pieces too.
544
+ const spacing = joining ? 0 : letterSpacingPx;
545
+ const hyphenW = measureTextWidth('-', font) + spacing;
546
+ const widthBefore = (idx) => textWidth(text.slice(0, idx), font, token.smallCaps) + (spacing === 0 ? 0 : spacing * graphemeCount(text.slice(0, idx)));
519
547
  const flags = { bold: token.bold, italic: token.italic, captionLabel: token.captionLabel, ...scriptOf(token) };
520
548
  // A group glued by no-break spaces too wide for any line: the space is
521
549
  // the least bad place to part it (EF-66). The line ends before it and the
@@ -534,7 +562,7 @@ export function emergencySplit(token, font, letterSpacingPx, lineMaxWidth, sylla
534
562
  // No hyphen where the cut falls next to an ideograph, or right after a
535
563
  // hyphen of the text.
536
564
  const afterHyphen = (idx) => text[idx - 1] === '-';
537
- const markW = (idx) => (afterHyphen(idx) || hasCJK(text.slice(idx - 1, idx + 1)) ? 0 : hyphenW);
565
+ const markW = (idx) => (joining || afterHyphen(idx) || hasCJK(text.slice(idx - 1, idx + 1)) ? 0 : hyphenW);
538
566
  const fits = (idx) => widthBefore(idx) + markW(idx) <= lineMaxWidth;
539
567
  // The longest prefix that fits without its mark, found by doubling then
540
568
  // halving (prefix widths grow with their length): no cut past it fits,
@@ -572,6 +600,9 @@ export function emergencySplit(token, font, letterSpacingPx, lineMaxWidth, sylla
572
600
  // on it.
573
601
  if (text[idx] === '-')
574
602
  continue;
603
+ // Never between the letters of a word of a joining script.
604
+ if (joining && insideJoiningWord(text, idx))
605
+ continue;
575
606
  if (fits(idx)) {
576
607
  at = idx;
577
608
  break;
@@ -768,7 +799,7 @@ export function atomicSpanToken(span, normalFont, boldFont, italicFont, boldItal
768
799
  ...(markerFont ? { markerFont } : {}),
769
800
  ...(span.smallCaps ? { smallCaps: true } : {}),
770
801
  kind: 'text',
771
- width: textWidth(span.text, refFont, span.smallCaps) + (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(span.text)),
802
+ width: textWidth(span.text, refFont, span.smallCaps) + (letterSpacingPx === 0 ? 0 : wordLetterSpacing(span.text, letterSpacingPx) * graphemeCount(span.text)),
772
803
  ...(span.ref ? { refResourceId: span.ref.resourceId, ...(span.ref.anchor ? { refAnchor: true } : {}), ...(span.ref.pageIndex !== undefined ? { refPageIndex: span.ref.pageIndex } : {}) } : {}),
773
804
  ...(span.footnote ? { footnoteId: span.footnote.id } : {}),
774
805
  };
@@ -780,7 +811,7 @@ export function atomicSpanToken(span, normalFont, boldFont, italicFont, boldItal
780
811
  bold: span.bold,
781
812
  italic: span.italic,
782
813
  kind: 'text',
783
- width: textWidth(span.text, font, false) + (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(span.text)),
814
+ width: textWidth(span.text, font, false) + (letterSpacingPx === 0 ? 0 : wordLetterSpacing(span.text, letterSpacingPx) * graphemeCount(span.text)),
784
815
  labelTab: span.labelTab,
785
816
  };
786
817
  }
@@ -830,6 +861,7 @@ export function tokenSegment(t) {
830
861
  ...(t.labelTab ? { labelTab: true } : {}),
831
862
  ...(t.script ? { script: t.script, fontString: t.scriptFont, baselineShift: t.baselineShift } : {}),
832
863
  ...(t.markerFont && !t.script ? { fontString: t.markerFont } : {}),
864
+ ...(t.faceFont && !t.script ? { fontString: t.faceFont } : {}),
833
865
  ...(t.stacked === 'first' ? { stacked: true } : {}),
834
866
  ...(t.smallCaps ? { smallCaps: true } : {}),
835
867
  };
@@ -842,6 +874,8 @@ export function tokenSegment(t) {
842
874
  seg.cjkMarks = t.cjkMarks;
843
875
  if (t.inserted)
844
876
  seg.inserted = true;
877
+ if (t.runs)
878
+ seg.runs = t.runs;
845
879
  return seg;
846
880
  }
847
881
  /**
@@ -874,7 +908,12 @@ dashBreaks = false,
874
908
  keepCompounds = false,
875
909
  /** Whether the spans hold CJK characters (`hasCJK` of their text): only
876
910
  * then is each word looked into. */
877
- cjkText = true) {
911
+ cjkText = true,
912
+ /** The paragraph's bidi levels (`measure/bidiLines.ts`), when it has
913
+ * right-to-left text: a word whose level changes inside it (`ABC،`,
914
+ * `و١٤٤٥`, `(API)` in Arabic) is cut there into words that touch, each
915
+ * measured as it is painted, as a run of its own direction. */
916
+ bidi) {
878
917
  const tokens = [];
879
918
  // Which characters of the joined text sit in a compound, a word (across
880
919
  // runs: "*after*-dinner") with a hyphen between two letters.
@@ -882,17 +921,23 @@ cjkText = true) {
882
921
  let spanStart = 0;
883
922
  // Tracking: every character (spaces included) advances `letterSpacingPx`
884
923
  // more, exactly as canvas `letterSpacing` / CSS `letter-spacing` / PDF `Tc`
885
- // paint it, so measured widths stay in step with the renderers.
886
- const track = (text) => (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(text));
924
+ // paint it, so measured widths stay in step with the renderers. A word of
925
+ // a joining script takes none: the renderers paint it untracked too.
926
+ const track = (text) => (letterSpacingPx === 0 ? 0 : wordLetterSpacing(text, letterSpacingPx) * graphemeCount(text));
887
927
  /** The script fields of a span's tokens (font at the script size, shift). */
928
+ // The span's own face: its style's, unslanted for the Arabic words of a
929
+ // slanted style (`uprightArabic.ts`).
930
+ const faceOf = (span) => {
931
+ const face = pickSpanFont(span.bold, span.italic, normalFont, boldFont, italicFont, boldItalicFont);
932
+ return span.upright ? uprightFace(face) : face;
933
+ };
888
934
  const scriptFieldsOf = (span) => {
889
935
  if (!span.script)
890
- return {};
891
- const base = pickSpanFont(span.bold, span.italic, normalFont, boldFont, italicFont, boldItalicFont);
892
- const m = scriptMetrics(base, span.script);
936
+ return span.upright ? { faceFont: faceOf(span) } : {};
937
+ const m = scriptMetrics(faceOf(span), span.script);
893
938
  return { script: span.script, scriptFont: m.font, baselineShift: m.baselineShift };
894
939
  };
895
- const spanFont = (span) => scriptFieldsOf(span).scriptFont ?? pickSpanFont(span.bold, span.italic, normalFont, boldFont, italicFont, boldItalicFont);
940
+ const spanFont = (span) => scriptFieldsOf(span).scriptFont ?? faceOf(span);
896
941
  for (const span of spans) {
897
942
  const spanBase = spanStart;
898
943
  spanStart += span.text.length;
@@ -925,15 +970,16 @@ cjkText = true) {
925
970
  // its soft hyphens can be told apart from the ones the source carries.
926
971
  // A no-break space is no boundary: it stays inside the word it glues
927
972
  // ("37 °C"), which the line then never breaks at (EF-66).
928
- const parts = span.text.match(WORDS_AND_SPACES_RE);
929
- if (!parts)
973
+ const matched = span.text.match(WORDS_AND_SPACES_RE);
974
+ if (!matched)
930
975
  continue;
976
+ const parts = bidi ? cutAtLevels(matched, spanBase, bidi) : matched;
931
977
  let partStart = spanBase;
932
978
  for (const part of parts) {
933
979
  const partAt = partStart;
934
980
  partStart += part.length;
935
981
  const isSpace = isBreakingSpaceRun(part);
936
- if (!isSpace && URL_LIKE_RE.test(part.replace(/\u00AD/g, ''))) {
982
+ if (!isSpace && URL_LIKE_RE.test(part.replace(/\u00AD/g, '')) && !(letterSpacingPx !== 0 && joiningScriptIn(part))) {
937
983
  const clean = part.replace(/\u00AD/g, '');
938
984
  const breakPoints = urlBreakIndices(clean).map((charIndex) => ({
939
985
  charIndex,
@@ -962,7 +1008,10 @@ cjkText = true) {
962
1008
  : undefined;
963
1009
  // A word that holds CJK characters: measured unit by unit, once each.
964
1010
  const cjk = cjkText && !isSpace && hasCJK(clean) ? cjkWordBreaks(clean, font, sc, letterSpacingPx) : undefined;
965
- const breakPoints = isSpace ? [] : wordBreakPoints(clean, soft, font, letterSpacingPx, sc, dashBreaks, touching, cjk);
1011
+ // A word of a joining script is measured untracked, its break points
1012
+ // (after a hyphen or a dash it carries) too.
1013
+ const wordSpacing = isSpace ? letterSpacingPx : wordLetterSpacing(clean, letterSpacingPx);
1014
+ const breakPoints = isSpace ? [] : wordBreakPoints(clean, soft, font, wordSpacing, sc, dashBreaks, touching, cjk);
966
1015
  if (breakPoints.length > 0) {
967
1016
  tokens.push({
968
1017
  text: clean,
@@ -978,19 +1027,26 @@ cjkText = true) {
978
1027
  });
979
1028
  }
980
1029
  else {
1030
+ // A word of a joining script loses the soft hyphens it may not
1031
+ // break at (`syllabify`); any other keeps its text as written.
1032
+ const word = clean !== part && !isSpace && joiningScriptIn(part) ? clean : part;
981
1033
  tokens.push({
982
- text: part,
1034
+ text: word,
983
1035
  bold: span.bold,
984
1036
  italic: span.italic,
985
1037
  captionLabel: span.captionLabel,
986
1038
  ...scriptFields,
987
1039
  ...(isSpace ? {} : scFields),
988
1040
  kind: isSpace ? 'space' : 'text',
989
- width: textWidth(part, font, sc && !isSpace) + track(part),
1041
+ width: textWidth(word, font, sc && !isSpace) + track(word),
990
1042
  });
991
1043
  }
992
1044
  }
993
1045
  }
1046
+ // A word of a joining script cut into runs by a style change is one
1047
+ // word again (only text that holds such a script is looked at).
1048
+ if (spans.length > 1)
1049
+ joinStyledRuns(tokens, normalFont, boldFont, italicFont, boldItalicFont);
994
1050
  if (tokens.some((t) => t.script))
995
1051
  stackScriptTokens(tokens, normalFont, boldFont, italicFont, boldItalicFont);
996
1052
  if (tokens.some((t) => t.chip)) {
@@ -1000,6 +1056,108 @@ cjkText = true) {
1000
1056
  markDashJoins(tokens);
1001
1057
  return tokens;
1002
1058
  }
1059
+ /** A token that may be one run of a word set in several styles: plain
1060
+ * text, nothing set as a whole (a reference, a note marker, a chip, a
1061
+ * formula, a swatch), no script, small capitals, vertical run or marks. */
1062
+ function isStyledRunPart(t) {
1063
+ return t !== undefined && t.kind === 'text' && !t.mathRender && !t.swatch && !t.chip && t.refResourceId === undefined
1064
+ && t.footnoteId === undefined && !t.labelTab && !t.script && !t.stacked && !t.smallCaps && !t.tcy && !t.orientation
1065
+ && !t.cjkMarks && !t.inserted && !t.runs;
1066
+ }
1067
+ /** Whether two runs that touch (no space between) are pieces of one word
1068
+ * of a joining script: the cut between them falls between two of its
1069
+ * letters, or before a mark (see `insideJoiningWord`). */
1070
+ function joinsAcross(a, b) {
1071
+ if (a.length === 0 || b.length === 0)
1072
+ return false;
1073
+ if (a.charCodeAt(a.length - 1) < 0x0600 && b.charCodeAt(0) < 0x0600)
1074
+ return false;
1075
+ return insideJoiningWord(a + b, a.length);
1076
+ }
1077
+ /**
1078
+ * Join the runs a style change cuts a word of a joining script into
1079
+ * (`كتا**ب**`, a coloured letter or vowel sign in a primer) back into one
1080
+ * token. Measured in pieces, each piece would be shaped alone: the letters
1081
+ * at the cut would take their isolated or final forms, the widths would be
1082
+ * off by a fifth or more (engine-ltr-audit §1.4), and the renderers would
1083
+ * paint a broken word. The token is measured whole in the style of its
1084
+ * longest run (an approximation when the runs differ in weight, never in
1085
+ * joining) and keeps each run's text and style (`runs`), so the renderers
1086
+ * shape the word once and give each run its style. It never breaks.
1087
+ */
1088
+ function joinStyledRuns(tokens, normalFont, boldFont, italicFont, boldItalicFont) {
1089
+ for (let i = 0; i + 1 < tokens.length; i++) {
1090
+ if (!isStyledRunPart(tokens[i]))
1091
+ continue;
1092
+ // Each next run is read against the whole word so far: a run of marks
1093
+ // alone (`ب**َ**يت`, a coloured fatha) has no letter of its own to join
1094
+ // from, the letter it sits on does.
1095
+ let j = i + 1;
1096
+ let word = tokens[i].text;
1097
+ while (j < tokens.length && isStyledRunPart(tokens[j]) && joinsAcross(word, tokens[j].text)) {
1098
+ word += tokens[j].text;
1099
+ j++;
1100
+ }
1101
+ if (j === i + 1)
1102
+ continue;
1103
+ const parts = tokens.slice(i, j);
1104
+ const runs = [];
1105
+ let dominant = parts[0];
1106
+ let most = -1;
1107
+ for (const p of parts) {
1108
+ const last = runs[runs.length - 1];
1109
+ if (last && !!last.bold === p.bold && !!last.italic === p.italic)
1110
+ last.text += p.text;
1111
+ else
1112
+ runs.push({ text: p.text, ...(p.bold ? { bold: true } : {}), ...(p.italic ? { italic: true } : {}) });
1113
+ const n = graphemeCount(p.text);
1114
+ if (n > most) {
1115
+ most = n;
1116
+ dominant = p;
1117
+ }
1118
+ }
1119
+ const text = parts.map((p) => p.text).join('');
1120
+ const merged = {
1121
+ text,
1122
+ bold: dominant.bold,
1123
+ italic: dominant.italic,
1124
+ ...(parts[0].captionLabel ? { captionLabel: true } : {}),
1125
+ kind: 'text',
1126
+ width: textWidth(text, tokenFont(dominant, normalFont, boldFont, italicFont, boldItalicFont), false),
1127
+ ...(dominant.faceFont ? { faceFont: dominant.faceFont } : {}),
1128
+ ...(runs.length > 1 ? { runs } : {}),
1129
+ ...(parts[parts.length - 1].dashJoin ? { dashJoin: true } : {}),
1130
+ };
1131
+ tokens.splice(i, j - i, merged);
1132
+ }
1133
+ }
1134
+ /** The words of a span (`parts`, starting at `from` in the paragraph) cut
1135
+ * where their bidi level changes, never between two letters of a joining
1136
+ * script. Spaces are left whole. */
1137
+ function cutAtLevels(parts, from, bidi) {
1138
+ const out = [];
1139
+ let at = from;
1140
+ for (const part of parts) {
1141
+ const start = at;
1142
+ at += part.length;
1143
+ if (isBreakingSpaceRun(part)) {
1144
+ out.push(part);
1145
+ continue;
1146
+ }
1147
+ let piece = 0;
1148
+ for (let k = 1; k < part.length; k++) {
1149
+ if (bidi.levels[start + k] === bidi.levels[start + k - 1] || insideJoiningWord(part, k))
1150
+ continue;
1151
+ const c = part.charCodeAt(k);
1152
+ if (c >= 0xDC00 && c <= 0xDFFF)
1153
+ continue;
1154
+ out.push(part.slice(piece, k));
1155
+ piece = k;
1156
+ }
1157
+ out.push(part.slice(piece));
1158
+ }
1159
+ return out;
1160
+ }
1003
1161
  /** A run of words a dash break may read across: not a formula, a swatch,
1004
1162
  * a chip or one of two stacked scripts. */
1005
1163
  function isWordRun(t) {
@@ -1195,6 +1353,8 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1195
1353
  // with it, read against the whole paragraph (#222).
1196
1354
  if (measuringVertically())
1197
1355
  spans = sidewaysNumberSpans(spans, getMeasureUprightDigits(), getMeasureRegion());
1356
+ // Arabic letters are never slanted (#376, `uprightArabic.ts`).
1357
+ spans = uprightArabicSpans(spans, italicFont, boldItalicFont, normalFont, boldFont);
1198
1358
  // Chinese, Japanese or Korean text: its own composer, which breaks
1199
1359
  // between characters under the document's line-break rules and spreads
1200
1360
  // justified lines between them — also text with no two CJK letters in a
@@ -1214,7 +1374,13 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1214
1374
  const textAlign = options?.textAlign ?? 'left';
1215
1375
  const letterSpacingPx = options?.letterSpacingPx ?? 0;
1216
1376
  const hyphenationZonePx = shouldHyphenate ? options?.hyphenationZonePx : undefined;
1217
- const tokens = tokenizeSpans(spans, normalFont, boldFont, italicFont, boldItalicFont, shouldHyphenate, letterSpacingPx, options?.breakAfterDashes === true, options?.hyphenateCompounds === false, cjkText);
1377
+ // A paragraph with right-to-left text: its levels, read once, cut its
1378
+ // words where they change direction and give its lines their order.
1379
+ const bidi = paragraphBidi(spans, plainText, options);
1380
+ // The languages the paragraph's isolates name (`:ltr[…]{lang=en}`), set
1381
+ // on the segments of their text (`VDTLineSegment.lang`).
1382
+ const languages = spans.some((sp) => sp.direction?.lang !== undefined || sp.direction?.outer !== undefined) ? spanLanguages(spans) : [];
1383
+ const tokens = tokenizeSpans(spans, normalFont, boldFont, italicFont, boldItalicFont, shouldHyphenate, letterSpacingPx, options?.breakAfterDashes === true, options?.hyphenateCompounds === false, cjkText, bidi);
1218
1384
  if (options?.labelColumnPx !== undefined)
1219
1385
  setLabelTabs(tokens, (t) => t.labelTab, options.labelColumnPx, (t, w) => { t.width = w; });
1220
1386
  const repeatHyphen = options?.repeatHyphen === true;
@@ -1223,6 +1389,19 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1223
1389
  if (tokens.length === 0) {
1224
1390
  return { lines: [], totalHeight: 0 };
1225
1391
  }
1392
+ // Kashida justification (#375): a justified paragraph with Arabic words.
1393
+ const kashida = textAlign === 'justify' && options?.kashida && bidi ? options.kashida : undefined;
1394
+ if (kashida)
1395
+ markKashidaCapacity(tokens, kashida, normalFont, boldFont, italicFont, boldItalicFont);
1396
+ const fontOf = (seg) => seg.fontString ?? pickSpanFont(!!seg.bold, !!seg.italic, normalFont, boldFont, italicFont, boldItalicFont);
1397
+ const withKashida = (lines) => {
1398
+ if (!kashida)
1399
+ return;
1400
+ justifyLinesWithKashida(lines, (li) => {
1401
+ const indent = indentPx > 0 ? (hanging ? (li === 0 ? 0 : indentPx) : (li === 0 ? indentPx : 0)) : 0;
1402
+ return lineMeasure(maxWidthPx, options?.restWidths, li) - indent;
1403
+ }, normalSpaceWidth, kashida, (seg, text) => textWidth(text, fontOf(seg), false));
1404
+ };
1226
1405
  // Knuth-Plass optimal line breaking path. A Latin paragraph quoting CJK
1227
1406
  // words takes it too: the breaks next to their characters are free
1228
1407
  // penalties, as a hyphenation point that adds nothing. Ragged text takes
@@ -1274,6 +1453,11 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1274
1453
  if (!hasOverfullLine(kpLines, lineWidthFn, ragged)) {
1275
1454
  if (hasSmallCaps)
1276
1455
  expandSmallCaps(kpLines, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx);
1456
+ if (bidi)
1457
+ withDirections(kpLines, bidi, normalFont, boldFont, italicFont, boldItalicFont);
1458
+ if (languages.length > 0)
1459
+ applySegmentLanguages(kpLines, plainText, languages);
1460
+ withKashida(kpLines);
1277
1461
  return {
1278
1462
  lines: kpLines,
1279
1463
  totalHeight: kpLines.length * lineHeightPx,
@@ -1307,6 +1491,8 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1307
1491
  let lineSyllable = false;
1308
1492
  // The line ends after a hyphen the word carries (EF-140).
1309
1493
  let lineHardHyphen = false;
1494
+ // A word of a joining script wider than the line runs past it.
1495
+ let lineWordOverflow = false;
1310
1496
  // Consume leading spaces at line start (skip them)
1311
1497
  while (tokenIdx < tokens.length && tokens[tokenIdx].kind === 'space') {
1312
1498
  tokenIdx++;
@@ -1477,6 +1663,10 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1477
1663
  }
1478
1664
  // No viable split. If line is empty, force-fit this token; else break to next line.
1479
1665
  if (lineTokens.length === 0) {
1666
+ // A word of a joining script wider than the line is never cut: it
1667
+ // runs past the measure, and the line says so.
1668
+ if (token.width > lineMaxWidth && token.kind === 'text' && joiningScriptIn(token.text))
1669
+ lineWordOverflow = true;
1480
1670
  lineTokens.push(token);
1481
1671
  lineWidth += token.width;
1482
1672
  tokenIdx++;
@@ -1514,12 +1704,50 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1514
1704
  segments,
1515
1705
  isLastLine,
1516
1706
  ...(justifiedSpaceRatio !== undefined ? { justifiedSpaceRatio } : {}),
1707
+ ...(lineWordOverflow ? { wordOverflow: true } : {}),
1517
1708
  });
1518
1709
  y += lineHeightPx;
1519
1710
  lineIndex++;
1520
1711
  }
1521
1712
  if (hasSmallCaps)
1522
1713
  expandSmallCaps(lines, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx);
1714
+ if (bidi)
1715
+ withDirections(lines, bidi, normalFont, boldFont, italicFont, boldItalicFont);
1716
+ if (languages.length > 0)
1717
+ applySegmentLanguages(lines, plainText, languages);
1718
+ withKashida(lines);
1523
1719
  return { lines, totalHeight: y };
1524
1720
  }
1721
+ /** Give each Arabic word of a justified paragraph its kashida capacity
1722
+ * (`RichToken.kashida`), which Knuth–Plass counts as the stretch of its
1723
+ * box. A word in pieces (styled runs of a Latin word, a reference label, a
1724
+ * footnote marker) takes none. */
1725
+ function markKashidaCapacity(tokens, options, normalFont, boldFont, italicFont, boldItalicFont) {
1726
+ for (const t of tokens) {
1727
+ if (t.kind !== 'text' || t.inserted || t.mathRender || t.swatch || t.chip || t.refResourceId !== undefined || t.footnoteId !== undefined || t.script)
1728
+ continue;
1729
+ if (!joiningScriptIn(t.text))
1730
+ continue;
1731
+ const font = tokenFont(t, normalFont, boldFont, italicFont, boldItalicFont);
1732
+ const capacity = kashidaCapacity(t.text, options, measureTextWidth(TATWEEL, font));
1733
+ if (capacity > 0)
1734
+ t.kashida = capacity;
1735
+ }
1736
+ }
1737
+ /** A paragraph's bidi levels (UAX #9, with its inline `:rtl[…]` /
1738
+ * `:ltr[…]` isolates), when it is set right to left, holds a
1739
+ * right-to-left letter or sets a right-to-left isolate; undefined for any
1740
+ * other, which is measured as it always was. */
1741
+ function paragraphBidi(spans, plainText, options) {
1742
+ const base = options?.direction ?? getMeasureDirection();
1743
+ const isolated = spans.some((s) => s.direction?.dir === 'rtl');
1744
+ if (base !== 'rtl' && !isolated && !needsBidi(plainText))
1745
+ return undefined;
1746
+ return resolveParagraph(plainText, base, spans.some((s) => s.direction) ? spanIsolates(spans) : undefined);
1747
+ }
1748
+ /** The directions of a paragraph's lines (`measure/bidiLines.ts`). A piece
1749
+ * of a segment is measured in its font. */
1750
+ function withDirections(lines, bidi, normalFont, boldFont, italicFont, boldItalicFont) {
1751
+ applyLineDirections(lines, bidi, (seg, piece) => textWidth(piece, seg.fontString ?? pickSpanFont(!!seg.bold, !!seg.italic, normalFont, boldFont, italicFont, boldItalicFont), false));
1752
+ }
1525
1753
  //# sourceMappingURL=rich.js.map