postext 1.8.5 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (565) hide show
  1. package/dist/__bench__/cjkChapter.bench.test.d.ts +2 -0
  2. package/dist/__bench__/cjkChapter.bench.test.d.ts.map +1 -0
  3. package/dist/__bench__/cjkChapter.bench.test.js +71 -0
  4. package/dist/__bench__/cjkChapter.bench.test.js.map +1 -0
  5. package/dist/__tests__/bundle.test.js +16 -0
  6. package/dist/__tests__/bundle.test.js.map +1 -1
  7. package/dist/__tests__/canvasDirection.test.d.ts +2 -0
  8. package/dist/__tests__/canvasDirection.test.d.ts.map +1 -0
  9. package/dist/__tests__/canvasDirection.test.js +45 -0
  10. package/dist/__tests__/canvasDirection.test.js.map +1 -0
  11. package/dist/__tests__/chineseLocale.test.d.ts +2 -0
  12. package/dist/__tests__/chineseLocale.test.d.ts.map +1 -0
  13. package/dist/__tests__/chineseLocale.test.js +253 -0
  14. package/dist/__tests__/chineseLocale.test.js.map +1 -0
  15. package/dist/__tests__/chineseNumbering.test.d.ts +2 -0
  16. package/dist/__tests__/chineseNumbering.test.d.ts.map +1 -0
  17. package/dist/__tests__/chineseNumbering.test.js +376 -0
  18. package/dist/__tests__/chineseNumbering.test.js.map +1 -0
  19. package/dist/__tests__/cjk/annotations.test.d.ts +2 -0
  20. package/dist/__tests__/cjk/annotations.test.d.ts.map +1 -0
  21. package/dist/__tests__/cjk/annotations.test.js +483 -0
  22. package/dist/__tests__/cjk/annotations.test.js.map +1 -0
  23. package/dist/__tests__/cjk/annotationsRender.test.d.ts +2 -0
  24. package/dist/__tests__/cjk/annotationsRender.test.d.ts.map +1 -0
  25. package/dist/__tests__/cjk/annotationsRender.test.js +263 -0
  26. package/dist/__tests__/cjk/annotationsRender.test.js.map +1 -0
  27. package/dist/__tests__/cjk/composer.test.d.ts +2 -0
  28. package/dist/__tests__/cjk/composer.test.d.ts.map +1 -0
  29. package/dist/__tests__/cjk/composer.test.js +237 -0
  30. package/dist/__tests__/cjk/composer.test.js.map +1 -0
  31. package/dist/__tests__/cjk/composerEdges.test.d.ts +2 -0
  32. package/dist/__tests__/cjk/composerEdges.test.d.ts.map +1 -0
  33. package/dist/__tests__/cjk/composerEdges.test.js +352 -0
  34. package/dist/__tests__/cjk/composerEdges.test.js.map +1 -0
  35. package/dist/__tests__/cjk/dashRule.test.d.ts +2 -0
  36. package/dist/__tests__/cjk/dashRule.test.d.ts.map +1 -0
  37. package/dist/__tests__/cjk/dashRule.test.js +261 -0
  38. package/dist/__tests__/cjk/dashRule.test.js.map +1 -0
  39. package/dist/__tests__/cjk/fuzz.test.d.ts +2 -0
  40. package/dist/__tests__/cjk/fuzz.test.d.ts.map +1 -0
  41. package/dist/__tests__/cjk/fuzz.test.js +102 -0
  42. package/dist/__tests__/cjk/fuzz.test.js.map +1 -0
  43. package/dist/__tests__/cjk/grid.test.d.ts +2 -0
  44. package/dist/__tests__/cjk/grid.test.d.ts.map +1 -0
  45. package/dist/__tests__/cjk/grid.test.js +261 -0
  46. package/dist/__tests__/cjk/grid.test.js.map +1 -0
  47. package/dist/__tests__/cjk/justifyRender.test.d.ts +2 -0
  48. package/dist/__tests__/cjk/justifyRender.test.d.ts.map +1 -0
  49. package/dist/__tests__/cjk/justifyRender.test.js +139 -0
  50. package/dist/__tests__/cjk/justifyRender.test.js.map +1 -0
  51. package/dist/__tests__/cjk/latinFastPath.test.d.ts +2 -0
  52. package/dist/__tests__/cjk/latinFastPath.test.d.ts.map +1 -0
  53. package/dist/__tests__/cjk/latinFastPath.test.js +208 -0
  54. package/dist/__tests__/cjk/latinFastPath.test.js.map +1 -0
  55. package/dist/__tests__/cjk/markCutsLatin.test.d.ts +2 -0
  56. package/dist/__tests__/cjk/markCutsLatin.test.d.ts.map +1 -0
  57. package/dist/__tests__/cjk/markCutsLatin.test.js +69 -0
  58. package/dist/__tests__/cjk/markCutsLatin.test.js.map +1 -0
  59. package/dist/__tests__/cjk/markRuns.test.d.ts +2 -0
  60. package/dist/__tests__/cjk/markRuns.test.d.ts.map +1 -0
  61. package/dist/__tests__/cjk/markRuns.test.js +347 -0
  62. package/dist/__tests__/cjk/markRuns.test.js.map +1 -0
  63. package/dist/__tests__/cjk/punctuation.test.d.ts +2 -0
  64. package/dist/__tests__/cjk/punctuation.test.d.ts.map +1 -0
  65. package/dist/__tests__/cjk/punctuation.test.js +440 -0
  66. package/dist/__tests__/cjk/punctuation.test.js.map +1 -0
  67. package/dist/__tests__/cjk/punctuationRender.test.d.ts +2 -0
  68. package/dist/__tests__/cjk/punctuationRender.test.d.ts.map +1 -0
  69. package/dist/__tests__/cjk/punctuationRender.test.js +135 -0
  70. package/dist/__tests__/cjk/punctuationRender.test.js.map +1 -0
  71. package/dist/__tests__/cjk/rubyDescenders.test.d.ts +2 -0
  72. package/dist/__tests__/cjk/rubyDescenders.test.d.ts.map +1 -0
  73. package/dist/__tests__/cjk/rubyDescenders.test.js +77 -0
  74. package/dist/__tests__/cjk/rubyDescenders.test.js.map +1 -0
  75. package/dist/__tests__/cjk/runt.test.d.ts +2 -0
  76. package/dist/__tests__/cjk/runt.test.d.ts.map +1 -0
  77. package/dist/__tests__/cjk/runt.test.js +103 -0
  78. package/dist/__tests__/cjk/runt.test.js.map +1 -0
  79. package/dist/__tests__/cjk/sharedMarks.test.d.ts +2 -0
  80. package/dist/__tests__/cjk/sharedMarks.test.d.ts.map +1 -0
  81. package/dist/__tests__/cjk/sharedMarks.test.js +347 -0
  82. package/dist/__tests__/cjk/sharedMarks.test.js.map +1 -0
  83. package/dist/__tests__/cjk/uprightDots.test.d.ts +2 -0
  84. package/dist/__tests__/cjk/uprightDots.test.d.ts.map +1 -0
  85. package/dist/__tests__/cjk/uprightDots.test.js +47 -0
  86. package/dist/__tests__/cjk/uprightDots.test.js.map +1 -0
  87. package/dist/__tests__/cjk/wordJoiner.test.d.ts +2 -0
  88. package/dist/__tests__/cjk/wordJoiner.test.d.ts.map +1 -0
  89. package/dist/__tests__/cjk/wordJoiner.test.js +47 -0
  90. package/dist/__tests__/cjk/wordJoiner.test.js.map +1 -0
  91. package/dist/__tests__/cjk/zhuyinTones.test.d.ts +2 -0
  92. package/dist/__tests__/cjk/zhuyinTones.test.d.ts.map +1 -0
  93. package/dist/__tests__/cjk/zhuyinTones.test.js +72 -0
  94. package/dist/__tests__/cjk/zhuyinTones.test.js.map +1 -0
  95. package/dist/__tests__/contentLocale.test.d.ts +2 -0
  96. package/dist/__tests__/contentLocale.test.d.ts.map +1 -0
  97. package/dist/__tests__/contentLocale.test.js +167 -0
  98. package/dist/__tests__/contentLocale.test.js.map +1 -0
  99. package/dist/__tests__/defaults/cjk.test.d.ts +2 -0
  100. package/dist/__tests__/defaults/cjk.test.d.ts.map +1 -0
  101. package/dist/__tests__/defaults/cjk.test.js +70 -0
  102. package/dist/__tests__/defaults/cjk.test.js.map +1 -0
  103. package/dist/__tests__/design/designTextRender.test.js +31 -0
  104. package/dist/__tests__/design/designTextRender.test.js.map +1 -1
  105. package/dist/__tests__/design/imageAltText.test.d.ts +2 -0
  106. package/dist/__tests__/design/imageAltText.test.d.ts.map +1 -0
  107. package/dist/__tests__/design/imageAltText.test.js +126 -0
  108. package/dist/__tests__/design/imageAltText.test.js.map +1 -0
  109. package/dist/__tests__/exports.test.js +61 -0
  110. package/dist/__tests__/exports.test.js.map +1 -1
  111. package/dist/__tests__/headingLetterSpacing.test.js +1 -1
  112. package/dist/__tests__/headingLetterSpacing.test.js.map +1 -1
  113. package/dist/__tests__/indexChinese.test.d.ts +2 -0
  114. package/dist/__tests__/indexChinese.test.d.ts.map +1 -0
  115. package/dist/__tests__/indexChinese.test.js +190 -0
  116. package/dist/__tests__/indexChinese.test.js.map +1 -0
  117. package/dist/__tests__/parse/annotations.test.d.ts +2 -0
  118. package/dist/__tests__/parse/annotations.test.d.ts.map +1 -0
  119. package/dist/__tests__/parse/annotations.test.js +175 -0
  120. package/dist/__tests__/parse/annotations.test.js.map +1 -0
  121. package/dist/__tests__/parse/attrQuoting.test.js +10 -8
  122. package/dist/__tests__/parse/attrQuoting.test.js.map +1 -1
  123. package/dist/__tests__/parse/chineseText.test.d.ts +2 -0
  124. package/dist/__tests__/parse/chineseText.test.d.ts.map +1 -0
  125. package/dist/__tests__/parse/chineseText.test.js +352 -0
  126. package/dist/__tests__/parse/chineseText.test.js.map +1 -0
  127. package/dist/__tests__/parts.test.js +25 -0
  128. package/dist/__tests__/parts.test.js.map +1 -1
  129. package/dist/__tests__/pipeline/colonListRoom.test.js +20 -0
  130. package/dist/__tests__/pipeline/colonListRoom.test.js.map +1 -1
  131. package/dist/__tests__/presets/hongloumeng.test.d.ts +2 -0
  132. package/dist/__tests__/presets/hongloumeng.test.d.ts.map +1 -0
  133. package/dist/__tests__/presets/hongloumeng.test.js +484 -0
  134. package/dist/__tests__/presets/hongloumeng.test.js.map +1 -0
  135. package/dist/__tests__/vertical/canvasPaint.test.d.ts +2 -0
  136. package/dist/__tests__/vertical/canvasPaint.test.d.ts.map +1 -0
  137. package/dist/__tests__/vertical/canvasPaint.test.js +229 -0
  138. package/dist/__tests__/vertical/canvasPaint.test.js.map +1 -0
  139. package/dist/__tests__/vertical/compositionPaint.test.d.ts +2 -0
  140. package/dist/__tests__/vertical/compositionPaint.test.d.ts.map +1 -0
  141. package/dist/__tests__/vertical/compositionPaint.test.js +538 -0
  142. package/dist/__tests__/vertical/compositionPaint.test.js.map +1 -0
  143. package/dist/__tests__/vertical/geometry.test.d.ts +2 -0
  144. package/dist/__tests__/vertical/geometry.test.d.ts.map +1 -0
  145. package/dist/__tests__/vertical/geometry.test.js +276 -0
  146. package/dist/__tests__/vertical/geometry.test.js.map +1 -0
  147. package/dist/__tests__/vertical/htmlSmoke.test.d.ts +2 -0
  148. package/dist/__tests__/vertical/htmlSmoke.test.d.ts.map +1 -0
  149. package/dist/__tests__/vertical/htmlSmoke.test.js +25 -0
  150. package/dist/__tests__/vertical/htmlSmoke.test.js.map +1 -0
  151. package/dist/__tests__/vertical/htmlTurnedCells.test.d.ts +2 -0
  152. package/dist/__tests__/vertical/htmlTurnedCells.test.d.ts.map +1 -0
  153. package/dist/__tests__/vertical/htmlTurnedCells.test.js +99 -0
  154. package/dist/__tests__/vertical/htmlTurnedCells.test.js.map +1 -0
  155. package/dist/__tests__/vertical/htmlVertical.test.d.ts +2 -0
  156. package/dist/__tests__/vertical/htmlVertical.test.d.ts.map +1 -0
  157. package/dist/__tests__/vertical/htmlVertical.test.js +145 -0
  158. package/dist/__tests__/vertical/htmlVertical.test.js.map +1 -0
  159. package/dist/__tests__/vertical/lineAxis.test.d.ts +2 -0
  160. package/dist/__tests__/vertical/lineAxis.test.d.ts.map +1 -0
  161. package/dist/__tests__/vertical/lineAxis.test.js +128 -0
  162. package/dist/__tests__/vertical/lineAxis.test.js.map +1 -0
  163. package/dist/__tests__/vertical/measurePaint.test.d.ts +2 -0
  164. package/dist/__tests__/vertical/measurePaint.test.d.ts.map +1 -0
  165. package/dist/__tests__/vertical/measurePaint.test.js +259 -0
  166. package/dist/__tests__/vertical/measurePaint.test.js.map +1 -0
  167. package/dist/__tests__/vertical/orientation.test.d.ts +2 -0
  168. package/dist/__tests__/vertical/orientation.test.d.ts.map +1 -0
  169. package/dist/__tests__/vertical/orientation.test.js +153 -0
  170. package/dist/__tests__/vertical/orientation.test.js.map +1 -0
  171. package/dist/__tests__/vertical/stub.d.ts +8 -0
  172. package/dist/__tests__/vertical/stub.d.ts.map +1 -0
  173. package/dist/__tests__/vertical/stub.js +37 -0
  174. package/dist/__tests__/vertical/stub.js.map +1 -0
  175. package/dist/__tests__/vertical/tateChuYoko.test.d.ts +2 -0
  176. package/dist/__tests__/vertical/tateChuYoko.test.d.ts.map +1 -0
  177. package/dist/__tests__/vertical/tateChuYoko.test.js +270 -0
  178. package/dist/__tests__/vertical/tateChuYoko.test.js.map +1 -0
  179. package/dist/__tests__/vertical/uprightResources.test.d.ts +2 -0
  180. package/dist/__tests__/vertical/uprightResources.test.d.ts.map +1 -0
  181. package/dist/__tests__/vertical/uprightResources.test.js +182 -0
  182. package/dist/__tests__/vertical/uprightResources.test.js.map +1 -0
  183. package/dist/__tests__/vertical/verticalDesignText.test.d.ts +2 -0
  184. package/dist/__tests__/vertical/verticalDesignText.test.d.ts.map +1 -0
  185. package/dist/__tests__/vertical/verticalDesignText.test.js +190 -0
  186. package/dist/__tests__/vertical/verticalDesignText.test.js.map +1 -0
  187. package/dist/__tests__/vertical/verticalSpans.d.ts +25 -0
  188. package/dist/__tests__/vertical/verticalSpans.d.ts.map +1 -0
  189. package/dist/__tests__/vertical/verticalSpans.js +39 -0
  190. package/dist/__tests__/vertical/verticalSpans.js.map +1 -0
  191. package/dist/__tests__/vertical/verticalTwins.test.d.ts +2 -0
  192. package/dist/__tests__/vertical/verticalTwins.test.d.ts.map +1 -0
  193. package/dist/__tests__/vertical/verticalTwins.test.js +71 -0
  194. package/dist/__tests__/vertical/verticalTwins.test.js.map +1 -0
  195. package/dist/bundle/adapters.d.ts +14 -5
  196. package/dist/bundle/adapters.d.ts.map +1 -1
  197. package/dist/bundle/adapters.js +4 -3
  198. package/dist/bundle/adapters.js.map +1 -1
  199. package/dist/bundle/codec.d.ts.map +1 -1
  200. package/dist/bundle/codec.js +27 -4
  201. package/dist/bundle/codec.js.map +1 -1
  202. package/dist/bundle/index.d.ts +1 -1
  203. package/dist/bundle/index.d.ts.map +1 -1
  204. package/dist/bundle/manifest.d.ts +6 -4
  205. package/dist/bundle/manifest.d.ts.map +1 -1
  206. package/dist/bundle/manifest.js +31 -32
  207. package/dist/bundle/manifest.js.map +1 -1
  208. package/dist/bundle/types.d.ts +7 -2
  209. package/dist/bundle/types.d.ts.map +1 -1
  210. package/dist/canvas-backend/annotations.d.ts +31 -0
  211. package/dist/canvas-backend/annotations.d.ts.map +1 -0
  212. package/dist/canvas-backend/annotations.js +120 -0
  213. package/dist/canvas-backend/annotations.js.map +1 -0
  214. package/dist/canvas-backend/blockRender.d.ts.map +1 -1
  215. package/dist/canvas-backend/blockRender.js +195 -15
  216. package/dist/canvas-backend/blockRender.js.map +1 -1
  217. package/dist/canvas-backend/decorations.d.ts +5 -0
  218. package/dist/canvas-backend/decorations.d.ts.map +1 -1
  219. package/dist/canvas-backend/decorations.js +27 -0
  220. package/dist/canvas-backend/decorations.js.map +1 -1
  221. package/dist/canvas-backend/headerFooter.d.ts.map +1 -1
  222. package/dist/canvas-backend/headerFooter.js +32 -16
  223. package/dist/canvas-backend/headerFooter.js.map +1 -1
  224. package/dist/canvas-backend/index.d.ts +2 -0
  225. package/dist/canvas-backend/index.d.ts.map +1 -1
  226. package/dist/canvas-backend/index.js +62 -2
  227. package/dist/canvas-backend/index.js.map +1 -1
  228. package/dist/canvas-backend/renderResourceBlock.d.ts.map +1 -1
  229. package/dist/canvas-backend/renderResourceBlock.js +42 -5
  230. package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
  231. package/dist/canvas-backend/segmentText.d.ts +23 -0
  232. package/dist/canvas-backend/segmentText.d.ts.map +1 -0
  233. package/dist/canvas-backend/segmentText.js +41 -0
  234. package/dist/canvas-backend/segmentText.js.map +1 -0
  235. package/dist/canvas-backend/verticalText.d.ts +113 -0
  236. package/dist/canvas-backend/verticalText.d.ts.map +1 -0
  237. package/dist/canvas-backend/verticalText.js +437 -0
  238. package/dist/canvas-backend/verticalText.js.map +1 -0
  239. package/dist/chineseNumerals.d.ts +39 -0
  240. package/dist/chineseNumerals.d.ts.map +1 -0
  241. package/dist/chineseNumerals.js +192 -0
  242. package/dist/chineseNumerals.js.map +1 -0
  243. package/dist/cjkMarks.d.ts +61 -0
  244. package/dist/cjkMarks.d.ts.map +1 -0
  245. package/dist/cjkMarks.js +441 -0
  246. package/dist/cjkMarks.js.map +1 -0
  247. package/dist/columnClip.d.ts +13 -4
  248. package/dist/columnClip.d.ts.map +1 -1
  249. package/dist/columnClip.js +33 -5
  250. package/dist/columnClip.js.map +1 -1
  251. package/dist/configWarnings.d.ts.map +1 -1
  252. package/dist/configWarnings.js +18 -3
  253. package/dist/configWarnings.js.map +1 -1
  254. package/dist/defaults/bodyText.d.ts +4 -1
  255. package/dist/defaults/bodyText.d.ts.map +1 -1
  256. package/dist/defaults/bodyText.js +27 -5
  257. package/dist/defaults/bodyText.js.map +1 -1
  258. package/dist/defaults/calloutStyles.js +1 -1
  259. package/dist/defaults/calloutStyles.js.map +1 -1
  260. package/dist/defaults/captionStyle.d.ts.map +1 -1
  261. package/dist/defaults/captionStyle.js +14 -0
  262. package/dist/defaults/captionStyle.js.map +1 -1
  263. package/dist/defaults/cjk.d.ts +33 -0
  264. package/dist/defaults/cjk.d.ts.map +1 -0
  265. package/dist/defaults/cjk.js +234 -0
  266. package/dist/defaults/cjk.js.map +1 -0
  267. package/dist/defaults/headerFooter.d.ts.map +1 -1
  268. package/dist/defaults/headerFooter.js +2 -0
  269. package/dist/defaults/headerFooter.js.map +1 -1
  270. package/dist/defaults/headingStyles.d.ts.map +1 -1
  271. package/dist/defaults/headingStyles.js +4 -0
  272. package/dist/defaults/headingStyles.js.map +1 -1
  273. package/dist/defaults/headings.d.ts.map +1 -1
  274. package/dist/defaults/headings.js +13 -6
  275. package/dist/defaults/headings.js.map +1 -1
  276. package/dist/defaults/index.d.ts +1 -0
  277. package/dist/defaults/index.d.ts.map +1 -1
  278. package/dist/defaults/index.js +10 -1
  279. package/dist/defaults/index.js.map +1 -1
  280. package/dist/defaults/indexConfig.d.ts +2 -1
  281. package/dist/defaults/indexConfig.d.ts.map +1 -1
  282. package/dist/defaults/indexConfig.js +5 -0
  283. package/dist/defaults/indexConfig.js.map +1 -1
  284. package/dist/defaults/layout.d.ts.map +1 -1
  285. package/dist/defaults/layout.js +7 -0
  286. package/dist/defaults/layout.js.map +1 -1
  287. package/dist/defaults/orderedLists.d.ts +5 -2
  288. package/dist/defaults/orderedLists.d.ts.map +1 -1
  289. package/dist/defaults/orderedLists.js +20 -5
  290. package/dist/defaults/orderedLists.js.map +1 -1
  291. package/dist/defaults/page.d.ts +8 -2
  292. package/dist/defaults/page.d.ts.map +1 -1
  293. package/dist/defaults/page.js +24 -7
  294. package/dist/defaults/page.js.map +1 -1
  295. package/dist/defaults/resourceTypes.d.ts +3 -3
  296. package/dist/defaults/resourceTypes.d.ts.map +1 -1
  297. package/dist/defaults/resourceTypes.js +23 -9
  298. package/dist/defaults/resourceTypes.js.map +1 -1
  299. package/dist/defaults/tableStyle.d.ts.map +1 -1
  300. package/dist/defaults/tableStyle.js +8 -5
  301. package/dist/defaults/tableStyle.js.map +1 -1
  302. package/dist/design/layout.d.ts +33 -0
  303. package/dist/design/layout.d.ts.map +1 -1
  304. package/dist/design/layout.js +124 -18
  305. package/dist/design/layout.js.map +1 -1
  306. package/dist/design/placeholders.d.ts.map +1 -1
  307. package/dist/design/placeholders.js +5 -1
  308. package/dist/design/placeholders.js.map +1 -1
  309. package/dist/design/richText.d.ts +24 -4
  310. package/dist/design/richText.d.ts.map +1 -1
  311. package/dist/design/richText.js +77 -16
  312. package/dist/design/richText.js.map +1 -1
  313. package/dist/html-backend.d.ts.map +1 -1
  314. package/dist/html-backend.js +635 -25
  315. package/dist/html-backend.js.map +1 -1
  316. package/dist/htmlAnnotations.d.ts +29 -0
  317. package/dist/htmlAnnotations.d.ts.map +1 -0
  318. package/dist/htmlAnnotations.js +86 -0
  319. package/dist/htmlAnnotations.js.map +1 -0
  320. package/dist/hyphenate.js +2 -1
  321. package/dist/hyphenate.js.map +1 -1
  322. package/dist/index.d.ts +28 -14
  323. package/dist/index.d.ts.map +1 -1
  324. package/dist/index.js +16 -8
  325. package/dist/index.js.map +1 -1
  326. package/dist/knuthPlass/pretextAdapter.d.ts +4 -1
  327. package/dist/knuthPlass/pretextAdapter.d.ts.map +1 -1
  328. package/dist/knuthPlass/pretextAdapter.js +9 -5
  329. package/dist/knuthPlass/pretextAdapter.js.map +1 -1
  330. package/dist/knuthPlass/richAdapter.d.ts +15 -2
  331. package/dist/knuthPlass/richAdapter.d.ts.map +1 -1
  332. package/dist/knuthPlass/richAdapter.js +16 -6
  333. package/dist/knuthPlass/richAdapter.js.map +1 -1
  334. package/dist/knuthPlass/tracking.d.ts +1 -1
  335. package/dist/knuthPlass/tracking.d.ts.map +1 -1
  336. package/dist/knuthPlass/tracking.js +4 -3
  337. package/dist/knuthPlass/tracking.js.map +1 -1
  338. package/dist/knuthPlass/types.d.ts +3 -0
  339. package/dist/knuthPlass/types.d.ts.map +1 -1
  340. package/dist/lineInk.d.ts +13 -0
  341. package/dist/lineInk.d.ts.map +1 -1
  342. package/dist/lineInk.js +28 -1
  343. package/dist/lineInk.js.map +1 -1
  344. package/dist/locale.d.ts +91 -3
  345. package/dist/locale.d.ts.map +1 -1
  346. package/dist/locale.js +245 -1
  347. package/dist/locale.js.map +1 -1
  348. package/dist/looseLines.d.ts +11 -1
  349. package/dist/looseLines.d.ts.map +1 -1
  350. package/dist/looseLines.js +26 -1
  351. package/dist/looseLines.js.map +1 -1
  352. package/dist/measure/cache.d.ts.map +1 -1
  353. package/dist/measure/cache.js +51 -3
  354. package/dist/measure/cache.js.map +1 -1
  355. package/dist/measure/canvas.d.ts +25 -0
  356. package/dist/measure/canvas.d.ts.map +1 -1
  357. package/dist/measure/canvas.js +90 -1
  358. package/dist/measure/canvas.js.map +1 -1
  359. package/dist/measure/cjk.d.ts +8 -13
  360. package/dist/measure/cjk.d.ts.map +1 -1
  361. package/dist/measure/cjk.js +29 -53
  362. package/dist/measure/cjk.js.map +1 -1
  363. package/dist/measure/cjkAnnotate.d.ts +96 -0
  364. package/dist/measure/cjkAnnotate.d.ts.map +1 -0
  365. package/dist/measure/cjkAnnotate.js +237 -0
  366. package/dist/measure/cjkAnnotate.js.map +1 -0
  367. package/dist/measure/cjkClasses.d.ts +133 -0
  368. package/dist/measure/cjkClasses.d.ts.map +1 -0
  369. package/dist/measure/cjkClasses.js +273 -0
  370. package/dist/measure/cjkClasses.js.map +1 -0
  371. package/dist/measure/cjkCompose.d.ts +86 -0
  372. package/dist/measure/cjkCompose.d.ts.map +1 -0
  373. package/dist/measure/cjkCompose.js +2022 -0
  374. package/dist/measure/cjkCompose.js.map +1 -0
  375. package/dist/measure/cjkPunctuation.d.ts +248 -0
  376. package/dist/measure/cjkPunctuation.d.ts.map +1 -0
  377. package/dist/measure/cjkPunctuation.js +492 -0
  378. package/dist/measure/cjkPunctuation.js.map +1 -0
  379. package/dist/measure/graphemes.d.ts +13 -0
  380. package/dist/measure/graphemes.d.ts.map +1 -0
  381. package/dist/measure/graphemes.js +38 -0
  382. package/dist/measure/graphemes.js.map +1 -0
  383. package/dist/measure/index.d.ts +3 -0
  384. package/dist/measure/index.d.ts.map +1 -1
  385. package/dist/measure/index.js +2 -0
  386. package/dist/measure/index.js.map +1 -1
  387. package/dist/measure/links.d.ts +6 -2
  388. package/dist/measure/links.d.ts.map +1 -1
  389. package/dist/measure/links.js +15 -5
  390. package/dist/measure/links.js.map +1 -1
  391. package/dist/measure/markCuts.d.ts +37 -0
  392. package/dist/measure/markCuts.d.ts.map +1 -0
  393. package/dist/measure/markCuts.js +77 -0
  394. package/dist/measure/markCuts.js.map +1 -0
  395. package/dist/measure/plain.d.ts.map +1 -1
  396. package/dist/measure/plain.js +33 -11
  397. package/dist/measure/plain.js.map +1 -1
  398. package/dist/measure/rich.d.ts +88 -1
  399. package/dist/measure/rich.d.ts.map +1 -1
  400. package/dist/measure/rich.js +233 -111
  401. package/dist/measure/rich.js.map +1 -1
  402. package/dist/measure/rubyLift.d.ts +11 -0
  403. package/dist/measure/rubyLift.d.ts.map +1 -0
  404. package/dist/measure/rubyLift.js +57 -0
  405. package/dist/measure/rubyLift.js.map +1 -0
  406. package/dist/measure/spaces.d.ts +12 -2
  407. package/dist/measure/spaces.d.ts.map +1 -1
  408. package/dist/measure/spaces.js +21 -7
  409. package/dist/measure/spaces.js.map +1 -1
  410. package/dist/measure/types.d.ts +20 -1
  411. package/dist/measure/types.d.ts.map +1 -1
  412. package/dist/measure/types.js.map +1 -1
  413. package/dist/measure/vertical.d.ts +104 -0
  414. package/dist/measure/vertical.d.ts.map +1 -0
  415. package/dist/measure/vertical.js +184 -0
  416. package/dist/measure/vertical.js.map +1 -0
  417. package/dist/numberWords.d.ts +3 -10
  418. package/dist/numberWords.d.ts.map +1 -1
  419. package/dist/numberWords.js +21 -9
  420. package/dist/numberWords.js.map +1 -1
  421. package/dist/numbering.d.ts +23 -5
  422. package/dist/numbering.d.ts.map +1 -1
  423. package/dist/numbering.js +99 -14
  424. package/dist/numbering.js.map +1 -1
  425. package/dist/parse/annotations.d.ts +101 -0
  426. package/dist/parse/annotations.d.ts.map +1 -0
  427. package/dist/parse/annotations.js +556 -0
  428. package/dist/parse/annotations.js.map +1 -0
  429. package/dist/parse/attrs.d.ts +48 -1
  430. package/dist/parse/attrs.d.ts.map +1 -1
  431. package/dist/parse/attrs.js +121 -8
  432. package/dist/parse/attrs.js.map +1 -1
  433. package/dist/parse/blockParser.d.ts.map +1 -1
  434. package/dist/parse/blockParser.js +50 -24
  435. package/dist/parse/blockParser.js.map +1 -1
  436. package/dist/parse/index.d.ts +3 -1
  437. package/dist/parse/index.d.ts.map +1 -1
  438. package/dist/parse/index.js +1 -0
  439. package/dist/parse/index.js.map +1 -1
  440. package/dist/parse/injectSpans.d.ts +3 -1
  441. package/dist/parse/injectSpans.d.ts.map +1 -1
  442. package/dist/parse/injectSpans.js +29 -8
  443. package/dist/parse/injectSpans.js.map +1 -1
  444. package/dist/parse/inlineFormatting.d.ts +38 -6
  445. package/dist/parse/inlineFormatting.d.ts.map +1 -1
  446. package/dist/parse/inlineFormatting.js +139 -26
  447. package/dist/parse/inlineFormatting.js.map +1 -1
  448. package/dist/parse/inlineSnippet.d.ts +2 -1
  449. package/dist/parse/inlineSnippet.d.ts.map +1 -1
  450. package/dist/parse/inlineSnippet.js +6 -2
  451. package/dist/parse/inlineSnippet.js.map +1 -1
  452. package/dist/parse/orientationMarks.d.ts +49 -0
  453. package/dist/parse/orientationMarks.d.ts.map +1 -0
  454. package/dist/parse/orientationMarks.js +138 -0
  455. package/dist/parse/orientationMarks.js.map +1 -0
  456. package/dist/parse/softBreaks.d.ts +56 -0
  457. package/dist/parse/softBreaks.d.ts.map +1 -0
  458. package/dist/parse/softBreaks.js +271 -0
  459. package/dist/parse/softBreaks.js.map +1 -0
  460. package/dist/parse/sourceMapping.d.ts.map +1 -1
  461. package/dist/parse/sourceMapping.js +41 -0
  462. package/dist/parse/sourceMapping.js.map +1 -1
  463. package/dist/parse/types.d.ts +84 -0
  464. package/dist/parse/types.d.ts.map +1 -1
  465. package/dist/pipeline/annotations.d.ts +56 -0
  466. package/dist/pipeline/annotations.d.ts.map +1 -0
  467. package/dist/pipeline/annotations.js +181 -0
  468. package/dist/pipeline/annotations.js.map +1 -0
  469. package/dist/pipeline/build.d.ts.map +1 -1
  470. package/dist/pipeline/build.js +158 -47
  471. package/dist/pipeline/build.js.map +1 -1
  472. package/dist/pipeline/buildBlockKind.d.ts +3 -0
  473. package/dist/pipeline/buildBlockKind.d.ts.map +1 -1
  474. package/dist/pipeline/buildBlockKind.js +5 -3
  475. package/dist/pipeline/buildBlockKind.js.map +1 -1
  476. package/dist/pipeline/buildHelpers.d.ts +36 -6
  477. package/dist/pipeline/buildHelpers.d.ts.map +1 -1
  478. package/dist/pipeline/buildHelpers.js +55 -8
  479. package/dist/pipeline/buildHelpers.js.map +1 -1
  480. package/dist/pipeline/buildMeasurement.d.ts +4 -0
  481. package/dist/pipeline/buildMeasurement.d.ts.map +1 -1
  482. package/dist/pipeline/buildMeasurement.js +3 -1
  483. package/dist/pipeline/buildMeasurement.js.map +1 -1
  484. package/dist/pipeline/calloutLayout.d.ts.map +1 -1
  485. package/dist/pipeline/calloutLayout.js +25 -11
  486. package/dist/pipeline/calloutLayout.js.map +1 -1
  487. package/dist/pipeline/cjkGrid.d.ts +133 -0
  488. package/dist/pipeline/cjkGrid.d.ts.map +1 -0
  489. package/dist/pipeline/cjkGrid.js +191 -0
  490. package/dist/pipeline/cjkGrid.js.map +1 -0
  491. package/dist/pipeline/config.d.ts +13 -9
  492. package/dist/pipeline/config.d.ts.map +1 -1
  493. package/dist/pipeline/config.js +43 -18
  494. package/dist/pipeline/config.js.map +1 -1
  495. package/dist/pipeline/contentWarnings.d.ts +10 -0
  496. package/dist/pipeline/contentWarnings.d.ts.map +1 -1
  497. package/dist/pipeline/contentWarnings.js +174 -2
  498. package/dist/pipeline/contentWarnings.js.map +1 -1
  499. package/dist/pipeline/floatPlacement.d.ts +9 -3
  500. package/dist/pipeline/floatPlacement.d.ts.map +1 -1
  501. package/dist/pipeline/floatPlacement.js +17 -6
  502. package/dist/pipeline/floatPlacement.js.map +1 -1
  503. package/dist/pipeline/headerFooter.d.ts +5 -2
  504. package/dist/pipeline/headerFooter.d.ts.map +1 -1
  505. package/dist/pipeline/headerFooter.js +123 -28
  506. package/dist/pipeline/headerFooter.js.map +1 -1
  507. package/dist/pipeline/headingDesignCuts.d.ts.map +1 -1
  508. package/dist/pipeline/headingDesignCuts.js +3 -1
  509. package/dist/pipeline/headingDesignCuts.js.map +1 -1
  510. package/dist/pipeline/headingStyles.d.ts +9 -3
  511. package/dist/pipeline/headingStyles.d.ts.map +1 -1
  512. package/dist/pipeline/headingStyles.js +23 -5
  513. package/dist/pipeline/headingStyles.js.map +1 -1
  514. package/dist/pipeline/indexDirective.d.ts.map +1 -1
  515. package/dist/pipeline/indexDirective.js +64 -20
  516. package/dist/pipeline/indexDirective.js.map +1 -1
  517. package/dist/pipeline/indexGroups.d.ts +55 -0
  518. package/dist/pipeline/indexGroups.d.ts.map +1 -0
  519. package/dist/pipeline/indexGroups.js +151 -0
  520. package/dist/pipeline/indexGroups.js.map +1 -0
  521. package/dist/pipeline/lists.d.ts +17 -0
  522. package/dist/pipeline/lists.d.ts.map +1 -1
  523. package/dist/pipeline/lists.js +43 -51
  524. package/dist/pipeline/lists.js.map +1 -1
  525. package/dist/pipeline/measureContentBlock.d.ts +3 -0
  526. package/dist/pipeline/measureContentBlock.d.ts.map +1 -1
  527. package/dist/pipeline/measureContentBlock.js +31 -4
  528. package/dist/pipeline/measureContentBlock.js.map +1 -1
  529. package/dist/pipeline/outline.d.ts.map +1 -1
  530. package/dist/pipeline/outline.js +13 -8
  531. package/dist/pipeline/outline.js.map +1 -1
  532. package/dist/pipeline/parts.d.ts +6 -3
  533. package/dist/pipeline/parts.d.ts.map +1 -1
  534. package/dist/pipeline/parts.js +28 -5
  535. package/dist/pipeline/parts.js.map +1 -1
  536. package/dist/pipeline/placeholders.d.ts +11 -0
  537. package/dist/pipeline/placeholders.d.ts.map +1 -1
  538. package/dist/pipeline/placeholders.js +48 -18
  539. package/dist/pipeline/placeholders.js.map +1 -1
  540. package/dist/pipeline/placement.d.ts +10 -6
  541. package/dist/pipeline/placement.d.ts.map +1 -1
  542. package/dist/pipeline/placement.js +33 -16
  543. package/dist/pipeline/placement.js.map +1 -1
  544. package/dist/pipeline/resourceLayout.d.ts +18 -1
  545. package/dist/pipeline/resourceLayout.d.ts.map +1 -1
  546. package/dist/pipeline/resourceLayout.js +109 -21
  547. package/dist/pipeline/resourceLayout.js.map +1 -1
  548. package/dist/pipeline/toc.d.ts.map +1 -1
  549. package/dist/pipeline/toc.js +6 -5
  550. package/dist/pipeline/toc.js.map +1 -1
  551. package/dist/pipeline/verticalMetrics.d.ts +14 -0
  552. package/dist/pipeline/verticalMetrics.d.ts.map +1 -0
  553. package/dist/pipeline/verticalMetrics.js +154 -0
  554. package/dist/pipeline/verticalMetrics.js.map +1 -0
  555. package/dist/types.d.ts +344 -13
  556. package/dist/types.d.ts.map +1 -1
  557. package/dist/vdt.d.ts +396 -6
  558. package/dist/vdt.d.ts.map +1 -1
  559. package/dist/vdt.js +49 -0
  560. package/dist/vdt.js.map +1 -1
  561. package/dist/writingMode.d.ts +156 -0
  562. package/dist/writingMode.d.ts.map +1 -0
  563. package/dist/writingMode.js +291 -0
  564. package/dist/writingMode.js.map +1 -0
  565. package/package.json +1 -1
@@ -8,7 +8,10 @@ import { isRuntLastLine } from './runts';
8
8
  import { computeJustifiedSpaceRatio, hasOverfullLine } from './plain';
9
9
  import { quoteFamily } from './font';
10
10
  import { trimChipLineEdges } from './chipEdges';
11
- import { cjkBreakIndices, cjkJoinBreaks, hasCJK, hasCJKRun } from './cjk';
11
+ import { cjkJoinBreaks, hasCJK } from './cjk';
12
+ import { composeCjkParagraph, cjkWordBreaks, composesAsCjk, spanMarks } from './cjkCompose';
13
+ import { graphemeCount } from './graphemes';
14
+ import { fontEm, getMeasureUprightDigits, getMeasureWritingMode, lineBaselineOffset, measuringVertically, verticalTextWidth, withMeasureWritingMode } from './vertical';
12
15
  import { NO_BREAK_SPACES, WORDS_AND_SPACES_RE, isBlankText, isBreakingSpace, isBreakingSpaceRun } from './spaces';
13
16
  import { breaksAfterDash, breaksAfterHardHyphen, hasCompound, isDash, raggedStretchPx } from './breakRules';
14
17
  /** Whether a resolved swatch colour can fill the square: a six- or
@@ -24,7 +27,7 @@ export function swatchSidePx(font) {
24
27
  const size = m ? Number(m[1]) : 16;
25
28
  return Math.max(1, size * 0.75);
26
29
  }
27
- function pickSpanFont(bold, italic, normalFont, boldFont, italicFont, boldItalicFont) {
30
+ export function pickSpanFont(bold, italic, normalFont, boldFont, italicFont, boldItalicFont) {
28
31
  if (bold && italic)
29
32
  return boldItalicFont;
30
33
  if (bold)
@@ -92,12 +95,14 @@ export function stackedScriptPairs(scripts) {
92
95
  function tokenFont(t, normalFont, boldFont, italicFont, boldItalicFont) {
93
96
  return t.scriptFont ?? pickSpanFont(t.bold, t.italic, normalFont, boldFont, italicFont, boldItalicFont);
94
97
  }
95
- /** The script and small-caps fields a token derived from another (a split,
96
- * a hyphenated head) carries on. */
98
+ /** The script, small-caps and Chinese-mark fields a token derived from
99
+ * another (a split, a hyphenated head) carries on. */
97
100
  function scriptOf(t) {
98
101
  return {
99
102
  ...(t.script ? { script: t.script, scriptFont: t.scriptFont, baselineShift: t.baselineShift } : {}),
100
103
  ...(t.smallCaps ? { smallCaps: true } : {}),
104
+ ...(t.cjkMarks ? { cjkMarks: t.cjkMarks } : {}),
105
+ ...(t.inserted ? { inserted: true } : {}),
101
106
  };
102
107
  }
103
108
  /** Small capitals are synthesised, the same way on every backend: a
@@ -142,8 +147,15 @@ export function smallCapsWidth(text, font) {
142
147
  }
143
148
  return w;
144
149
  }
145
- /** Advance of `text` in `font`, set in small capitals when `smallCaps`. */
146
- function textWidth(text, font, smallCaps) {
150
+ /** Advance of `text` in `font`, set in small capitals when `smallCaps`.
151
+ * In vertical text (`measuringVertically`) a character that stands in a
152
+ * cell of its own advances its cell (`verticalTextWidth`), as the
153
+ * renderers paint it, and so does a short number set in one cell
154
+ * (`cjk.uprightDigits`); no other ASCII text holds one. */
155
+ export function textWidth(text, font, smallCaps) {
156
+ if (measuringVertically() && (/[^\u0000-\u007F]/.test(text) || (getMeasureUprightDigits() > 0 && /[0-9]/.test(text)))) {
157
+ return verticalTextWidth(text, font, (run) => (smallCaps ? smallCapsWidth(run, font) : measureTextWidth(run, font)));
158
+ }
147
159
  return smallCaps ? smallCapsWidth(text, font) : measureTextWidth(text, font);
148
160
  }
149
161
  /**
@@ -154,7 +166,7 @@ function textWidth(text, font, smallCaps) {
154
166
  * line text follows the painted case (the same length, so source maps
155
167
  * hold).
156
168
  */
157
- function expandSmallCaps(lines, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx) {
169
+ export function expandSmallCaps(lines, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx) {
158
170
  for (const line of lines) {
159
171
  const segs = line.segments;
160
172
  if (!segs || !segs.some((s) => s.smallCaps))
@@ -180,7 +192,7 @@ function expandSmallCaps(lines, normalFont, boldFont, italicFont, boldItalicFont
180
192
  const font = run.small ? small : base;
181
193
  const width = i === runs.length - 1
182
194
  ? seg.width - used
183
- : measureTextWidth(run.text, font) + (letterSpacingPx + (line.letterSpacing ?? 0)) * run.text.length;
195
+ : measureTextWidth(run.text, font) + (letterSpacingPx + (line.letterSpacing ?? 0) + (seg.tracking ?? 0)) * graphemeCount(run.text);
184
196
  used += width;
185
197
  // Capitals keep the segment's own font (none for a plain run).
186
198
  const piece = { ...rest, text: run.text, width };
@@ -220,7 +232,7 @@ function withFace(font, family, sizePx) {
220
232
  * enters the line height. A chip span without a resolved box sets as bare
221
233
  * text.
222
234
  */
223
- function chipToken(span, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx) {
235
+ export function chipToken(span, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx) {
224
236
  const chip = span.chip;
225
237
  const box = chip.box;
226
238
  const sizeMatch = FONT_SIZE_RE.exec(normalFont);
@@ -253,7 +265,7 @@ function chipToken(span, normalFont, boldFont, italicFont, boldItalicFont, lette
253
265
  runs.push({
254
266
  text: piece.text,
255
267
  fontString: piece.font,
256
- width: measureTextWidth(piece.text, piece.font) + letterSpacingPx * piece.text.length,
268
+ width: measureTextWidth(piece.text, piece.font) + letterSpacingPx * graphemeCount(piece.text),
257
269
  ...(bold ? { bold: true } : {}),
258
270
  ...(italic ? { italic: true } : {}),
259
271
  ...(baselineShift !== undefined ? { baselineShift } : {}),
@@ -380,7 +392,7 @@ function withChipMargins(token, addLeft, addRight) {
380
392
  /** A word that is a URL or a bare DOI: never hyphenated by the dictionary,
381
393
  * but breakable at its own joints so a long link cannot force an
382
394
  * unfillable line. */
383
- const URL_LIKE_RE = /^(?:(?:https?|ftp):\/\/|www\.|10\.\d{4,}\/)\S+$/i;
395
+ export const URL_LIKE_RE = /^(?:(?:https?|ftp):\/\/|www\.|10\.\d{4,}\/)\S+$/i;
384
396
  /** Break opportunities inside a URL, following the usual editorial rule:
385
397
  * after a slash (never inside the `//` of the scheme) or before a dot,
386
398
  * hyphen or query/fragment punctuation, so the punctuation opens the next
@@ -437,10 +449,13 @@ function syllabify(word, hyphenate) {
437
449
  * start of the word needs; without it, one between two letters
438
450
  * ("largas—separadas"), for the greedy breaker only, as pretext breaks a
439
451
  * plain paragraph there;
440
- * - between ideographs, where pretext breaks a plain paragraph (so its
441
- * kinsoku rules hold here too). */
442
- function wordBreakPoints(clean, soft, font, letterSpacingPx, smallCaps, dashBreaks = false, touching) {
443
- const widthBefore = (idx) => textWidth(clean.slice(0, idx), font, smallCaps) + letterSpacingPx * idx;
452
+ * - next to CJK characters, under the line-break rules of the document's
453
+ * `cjk.lineBreak` (`cjk`: the word's units, measured once each, whose
454
+ * running sums give the widths before its breaks). */
455
+ function wordBreakPoints(clean, soft, font, letterSpacingPx, smallCaps, dashBreaks = false, touching, cjk) {
456
+ const widthBefore = cjk
457
+ ? cjk.widthBefore
458
+ : (idx) => textWidth(clean.slice(0, idx), font, smallCaps) + (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(clean.slice(0, idx)));
444
459
  const byIndex = new Map();
445
460
  const add = (bp) => {
446
461
  if (bp.charIndex <= 0 || bp.charIndex >= clean.length)
@@ -468,8 +483,9 @@ function wordBreakPoints(clean, soft, font, letterSpacingPx, smallCaps, dashBrea
468
483
  }
469
484
  for (const s of soft)
470
485
  add(s.author ? { charIndex: s.index, author: true } : { charIndex: s.index });
471
- for (const idx of cjkBreakIndices(clean, font))
472
- add({ charIndex: idx, free: true });
486
+ if (cjk)
487
+ for (const idx of cjk.breaks)
488
+ add({ charIndex: idx, free: true, cjk: true });
473
489
  return [...byIndex.values()].sort((a, b) => a.charIndex - b.charIndex);
474
490
  }
475
491
  /**
@@ -482,12 +498,12 @@ function wordBreakPoints(clean, soft, font, letterSpacingPx, smallCaps, dashBrea
482
498
  * "-universitaria" nor "fisica--". Null when not even one character fits,
483
499
  * or, with `syllablesOnly`, when no no-break space or syllable does.
484
500
  */
485
- function emergencySplit(token, font, letterSpacingPx, lineMaxWidth, syllablesOnly = false) {
501
+ export function emergencySplit(token, font, letterSpacingPx, lineMaxWidth, syllablesOnly = false) {
486
502
  const text = token.text;
487
503
  if (text.length < 2)
488
504
  return null;
489
505
  const hyphenW = measureTextWidth('-', font) + letterSpacingPx;
490
- const widthBefore = (idx) => textWidth(text.slice(0, idx), font, token.smallCaps) + letterSpacingPx * idx;
506
+ const widthBefore = (idx) => textWidth(text.slice(0, idx), font, token.smallCaps) + (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(text.slice(0, idx)));
491
507
  const flags = { bold: token.bold, italic: token.italic, captionLabel: token.captionLabel, ...scriptOf(token) };
492
508
  // A group glued by no-break spaces too wide for any line: the space is
493
509
  // the least bad place to part it (EF-66). The line ends before it and the
@@ -508,18 +524,38 @@ function emergencySplit(token, font, letterSpacingPx, lineMaxWidth, syllablesOnl
508
524
  const afterHyphen = (idx) => text[idx - 1] === '-';
509
525
  const markW = (idx) => (afterHyphen(idx) || hasCJK(text.slice(idx - 1, idx + 1)) ? 0 : hyphenW);
510
526
  const fits = (idx) => widthBefore(idx) + markW(idx) <= lineMaxWidth;
527
+ // The longest prefix that fits without its mark, found by doubling then
528
+ // halving (prefix widths grow with their length): no cut past it fits,
529
+ // so a word many lines long costs what one line of it does, not a
530
+ // measurement of every prefix.
531
+ let reach = 0;
532
+ let over = text.length;
533
+ for (let step = 1; reach + step < text.length; step *= 2) {
534
+ if (widthBefore(reach + step) > lineMaxWidth) {
535
+ over = reach + step;
536
+ break;
537
+ }
538
+ reach += step;
539
+ }
540
+ while (over - reach > 1) {
541
+ const mid = (reach + over) >> 1;
542
+ if (widthBefore(mid) <= lineMaxWidth)
543
+ reach = mid;
544
+ else
545
+ over = mid;
546
+ }
511
547
  let at = 0;
512
548
  // The dictionary's syllables, as offsets into the text: `syllabify` maps
513
549
  // them past anything else the dictionary might put in.
514
550
  const { clean, soft } = syllabify(text, true);
515
551
  if (clean === text) {
516
552
  for (const s of soft) {
517
- if (s.index > 0 && s.index < text.length && fits(s.index))
553
+ if (s.index > 0 && s.index <= reach && fits(s.index))
518
554
  at = s.index;
519
555
  }
520
556
  }
521
557
  if (at === 0 && !syllablesOnly) {
522
- for (let idx = text.length - 1; idx >= 1; idx--) {
558
+ for (let idx = reach; idx >= 1; idx--) {
523
559
  // Not right before a hyphen of the text: the next line would open
524
560
  // on it.
525
561
  if (text[idx] === '-')
@@ -579,12 +615,135 @@ function compoundMask(spans) {
579
615
  }
580
616
  return mask;
581
617
  }
618
+ /** The script fields of a span's tokens (the font at the script size, and
619
+ * the shift), none for text that is no superscript or subscript. */
620
+ export function spanScriptFields(span, normalFont, boldFont, italicFont, boldItalicFont) {
621
+ if (!span.script)
622
+ return {};
623
+ const base = pickSpanFont(span.bold, span.italic, normalFont, boldFont, italicFont, boldItalicFont);
624
+ const m = scriptMetrics(base, span.script);
625
+ return { script: span.script, scriptFont: m.font, baselineShift: m.baselineShift };
626
+ }
627
+ /** Whether a span sets something other than its text: a `:ref` or a
628
+ * note marker (its label), a chip, a swatch or a formula. The orientation
629
+ * marks of vertical text leave such a span as it is. */
630
+ export function setsObject(span) {
631
+ return span.ref !== undefined || span.footnote !== undefined || span.chip !== undefined || span.swatch !== undefined || span.math !== undefined || span.mathRender !== undefined;
632
+ }
633
+ /**
634
+ * The one token of a span that is set as a whole, or undefined for text:
635
+ * - an inline `:ref` or a footnote marker: the resolved label (already in
636
+ * `text`) as one box that never wraps apart. Kind 'text' keeps the
637
+ * generic layout and renderers treating it as a word; `refResourceId` /
638
+ * `footnoteId` flow onto the segment for link colouring and PDF links;
639
+ * - a chip: a box with its own runs, never broken or hyphenated inside;
640
+ * - a swatch: one square the size of a capital;
641
+ * - a formula: one box with the render's `widthPx`. Kind 'text' (not
642
+ * 'space'), so trimming a line's trailing spaces never drops it.
643
+ */
644
+ export function atomicSpanToken(span, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx) {
645
+ // Vertical text: a run the author set upright or sideways is one unit a
646
+ // line never breaks inside (tate-chu-yoko one em, upright letters one em
647
+ // each, a sideways run its horizontal width). A reference, a note
648
+ // marker, a chip, a swatch or a formula keeps its own setting.
649
+ if ((span.combineUpright || span.orientation) && measuringVertically() && span.text.length > 0 && !setsObject(span)) {
650
+ const font = pickSpanFont(span.bold, span.italic, normalFont, boldFont, italicFont, boldItalicFont);
651
+ const em = fontEm(font);
652
+ const count = span.combineUpright ? 1 : graphemeCount(span.text);
653
+ const track = letterSpacingPx === 0 ? 0 : letterSpacingPx * count;
654
+ return {
655
+ text: span.text,
656
+ bold: span.bold,
657
+ italic: span.italic,
658
+ captionLabel: span.captionLabel,
659
+ kind: 'text',
660
+ width: (span.combineUpright ? em : span.orientation === 'upright' ? em * count : measureTextWidth(span.text, font)) + track,
661
+ ...(span.combineUpright ? { tcy: true } : { orientation: span.orientation }),
662
+ };
663
+ }
664
+ if (span.ref || span.footnote) {
665
+ const scriptFields = spanScriptFields(span, normalFont, boldFont, italicFont, boldItalicFont);
666
+ const refFont = scriptFields.scriptFont ?? pickSpanFont(span.bold, span.italic, normalFont, boldFont, italicFont, boldItalicFont);
667
+ return {
668
+ text: span.text,
669
+ bold: span.bold,
670
+ italic: span.italic,
671
+ captionLabel: span.captionLabel,
672
+ ...scriptFields,
673
+ ...(span.smallCaps ? { smallCaps: true } : {}),
674
+ kind: 'text',
675
+ width: textWidth(span.text, refFont, span.smallCaps) + (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(span.text)),
676
+ ...(span.ref ? { refResourceId: span.ref.resourceId } : {}),
677
+ ...(span.footnote ? { footnoteId: span.footnote.id } : {}),
678
+ };
679
+ }
680
+ if (span.chip)
681
+ return chipToken(span, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx);
682
+ if (span.swatch) {
683
+ const swatchFont = pickSpanFont(span.bold, span.italic, normalFont, boldFont, italicFont, boldItalicFont);
684
+ return {
685
+ text: span.text,
686
+ bold: span.bold,
687
+ italic: span.italic,
688
+ captionLabel: span.captionLabel,
689
+ kind: 'text',
690
+ width: swatchSidePx(swatchFont),
691
+ swatch: isSwatchFill(span.swatch.color) ? { color: span.swatch.color } : {},
692
+ };
693
+ }
694
+ if (span.math && span.mathRender) {
695
+ return {
696
+ text: span.text,
697
+ bold: span.bold,
698
+ italic: span.italic,
699
+ captionLabel: span.captionLabel,
700
+ kind: 'text',
701
+ width: span.mathRender.widthPx,
702
+ mathRender: span.mathRender,
703
+ };
704
+ }
705
+ return undefined;
706
+ }
707
+ /** The segment a token (or the part of one on a line) sets: its kind, text
708
+ * (soft hyphens removed), width and every flag the renderers read. Small
709
+ * capitals stay flagged until {@link expandSmallCaps} splits them. */
710
+ export function tokenSegment(t) {
711
+ const seg = {
712
+ kind: t.mathRender ? 'math' : t.swatch ? 'swatch' : t.chip ? 'chip' : t.kind,
713
+ text: cleanSoftHyphens(t.text),
714
+ width: t.width,
715
+ bold: t.bold || undefined,
716
+ italic: t.italic || undefined,
717
+ ...(t.mathRender ? { mathRender: t.mathRender } : {}),
718
+ ...(t.swatch ? { swatch: t.swatch } : {}),
719
+ ...(t.chip ? { chip: t.chip } : {}),
720
+ ...(t.refResourceId !== undefined ? { refResourceId: t.refResourceId } : {}),
721
+ ...(t.footnoteId !== undefined ? { footnoteId: t.footnoteId } : {}),
722
+ ...(t.captionLabel ? { captionLabel: true } : {}),
723
+ ...(t.script ? { script: t.script, fontString: t.scriptFont, baselineShift: t.baselineShift } : {}),
724
+ ...(t.stacked === 'first' ? { stacked: true } : {}),
725
+ ...(t.smallCaps ? { smallCaps: true } : {}),
726
+ };
727
+ // The fields of vertical and Chinese text, last, when set.
728
+ if (t.tcy)
729
+ seg.tcy = true;
730
+ if (t.orientation)
731
+ seg.orientation = t.orientation;
732
+ if (t.cjkMarks)
733
+ seg.cjkMarks = t.cjkMarks;
734
+ if (t.inserted)
735
+ seg.inserted = true;
736
+ return seg;
737
+ }
582
738
  function tokenizeSpans(spans, normalFont, boldFont, italicFont, boldItalicFont, shouldHyphenate, letterSpacingPx = 0,
583
739
  /** `MeasureBlockOptions.breakAfterDashes`. */
584
740
  dashBreaks = false,
585
741
  /** `MeasureBlockOptions.hyphenateCompounds === false`: the dictionary
586
742
  * leaves the words of a compound whole. */
587
- keepCompounds = false) {
743
+ keepCompounds = false,
744
+ /** Whether the spans hold CJK characters (`hasCJK` of their text): only
745
+ * then is each word looked into. */
746
+ cjkText = true) {
588
747
  const tokens = [];
589
748
  // Which characters of the joined text sit in a compound, a word (across
590
749
  // runs: "*after*-dinner") with a hyphen between two letters.
@@ -593,7 +752,7 @@ keepCompounds = false) {
593
752
  // Tracking: every character (spaces included) advances `letterSpacingPx`
594
753
  // more, exactly as canvas `letterSpacing` / CSS `letter-spacing` / PDF `Tc`
595
754
  // paint it, so measured widths stay in step with the renderers.
596
- const track = (text) => letterSpacingPx * text.length;
755
+ const track = (text) => (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(text));
597
756
  /** The script fields of a span's tokens (font at the script size, shift). */
598
757
  const scriptFieldsOf = (span) => {
599
758
  if (!span.script)
@@ -606,62 +765,19 @@ keepCompounds = false) {
606
765
  for (const span of spans) {
607
766
  const spanBase = spanStart;
608
767
  spanStart += span.text.length;
609
- // Inline `:ref` spans are atomic: the resolved label (already in `text`)
610
- // is one non-breaking box so it never wraps apart. Kind 'text' keeps the
611
- // generic layout/renderers treating it like a word; `refResourceId` flows
612
- // onto the segment for link colouring / PDF link annotations.
613
- if (span.ref || span.footnote) {
614
- const refFont = spanFont(span);
615
- tokens.push({
616
- text: span.text,
617
- bold: span.bold,
618
- italic: span.italic,
619
- captionLabel: span.captionLabel,
620
- ...scriptFieldsOf(span),
621
- ...(span.smallCaps ? { smallCaps: true } : {}),
622
- kind: 'text',
623
- width: textWidth(span.text, refFont, span.smallCaps) + track(span.text),
624
- ...(span.ref ? { refResourceId: span.ref.resourceId } : {}),
625
- ...(span.footnote ? { footnoteId: span.footnote.id } : {}),
626
- });
627
- continue;
628
- }
629
- // Chips are atomic boxes: never broken or hyphenated inside.
630
- if (span.chip) {
631
- tokens.push(chipToken(span, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx));
632
- continue;
633
- }
634
- // Swatch spans are atomic too: one square box the size of a capital.
635
- if (span.swatch) {
636
- const swatchFont = pickSpanFont(span.bold, span.italic, normalFont, boldFont, italicFont, boldItalicFont);
637
- tokens.push({
638
- text: span.text,
639
- bold: span.bold,
640
- italic: span.italic,
641
- captionLabel: span.captionLabel,
642
- kind: 'text',
643
- width: swatchSidePx(swatchFont),
644
- swatch: isSwatchFill(span.swatch.color) ? { color: span.swatch.color } : {},
645
- });
646
- continue;
647
- }
648
- // Math spans are atomic: a single non-breaking box with the render's
649
- // widthPx. Kind 'text' is correct (not 'space') so trimming trailing
650
- // spaces from a line doesn't drop the formula.
651
- if (span.math && span.mathRender) {
652
- tokens.push({
653
- text: span.text,
654
- bold: span.bold,
655
- italic: span.italic,
656
- captionLabel: span.captionLabel,
657
- kind: 'text',
658
- width: span.mathRender.widthPx,
659
- mathRender: span.mathRender,
660
- });
768
+ const atomic = atomicSpanToken(span, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx);
769
+ if (atomic) {
770
+ tokens.push(atomic);
661
771
  continue;
662
772
  }
663
773
  const font = spanFont(span);
664
- const scriptFields = scriptFieldsOf(span);
774
+ // Chinese marks (#193) ride on the span's words like its script.
775
+ const marks = spanMarks(span, getMeasureWritingMode() === 'vertical-rl');
776
+ const scriptFields = {
777
+ ...scriptFieldsOf(span),
778
+ ...(marks ? { cjkMarks: marks } : {}),
779
+ ...(span.inserted ? { inserted: true } : {}),
780
+ };
665
781
  // Small capitals: the words keep their case (hyphenation reads it) and
666
782
  // measure as they will be painted.
667
783
  const sc = !!span.smallCaps;
@@ -683,7 +799,7 @@ keepCompounds = false) {
683
799
  const clean = part.replace(/\u00AD/g, '');
684
800
  const breakPoints = urlBreakIndices(clean).map((charIndex) => ({
685
801
  charIndex,
686
- widthBefore: textWidth(clean.slice(0, charIndex), font, sc) + letterSpacingPx * charIndex,
802
+ widthBefore: textWidth(clean.slice(0, charIndex), font, sc) + (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(clean.slice(0, charIndex))),
687
803
  }));
688
804
  tokens.push({
689
805
  text: clean,
@@ -706,7 +822,9 @@ keepCompounds = false) {
706
822
  const touching = dashBreaks && before && before.kind === 'text' && !before.mathRender && !before.swatch && !before.chip
707
823
  ? before.text.slice(-2)
708
824
  : undefined;
709
- const breakPoints = isSpace ? [] : wordBreakPoints(clean, soft, font, letterSpacingPx, sc, dashBreaks, touching);
825
+ // A word that holds CJK characters: measured unit by unit, once each.
826
+ const cjk = cjkText && !isSpace && hasCJK(clean) ? cjkWordBreaks(clean, font, sc, letterSpacingPx) : undefined;
827
+ const breakPoints = isSpace ? [] : wordBreakPoints(clean, soft, font, letterSpacingPx, sc, dashBreaks, touching, cjk);
710
828
  if (breakPoints.length > 0) {
711
829
  tokens.push({
712
830
  text: clean,
@@ -716,7 +834,7 @@ keepCompounds = false) {
716
834
  ...scriptFields,
717
835
  ...scFields,
718
836
  kind: 'text',
719
- width: textWidth(clean, font, sc) + track(clean),
837
+ width: cjk ? cjk.width : textWidth(clean, font, sc) + track(clean),
720
838
  breakPoints,
721
839
  hyphenWidth: measureTextWidth('-', font) + letterSpacingPx,
722
840
  });
@@ -738,7 +856,7 @@ keepCompounds = false) {
738
856
  if (tokens.some((t) => t.script))
739
857
  stackScriptTokens(tokens, normalFont, boldFont, italicFont, boldItalicFont);
740
858
  if (tokens.some((t) => t.chip)) {
741
- applyChipGaps(tokens, (t, run) => measureTextWidth(run, tokenFont(t, normalFont, boldFont, italicFont, boldItalicFont)) + letterSpacingPx * run.length);
859
+ applyChipGaps(tokens, (t, run) => measureTextWidth(run, tokenFont(t, normalFont, boldFont, italicFont, boldItalicFont)) + (letterSpacingPx === 0 ? 0 : letterSpacingPx * graphemeCount(run)));
742
860
  }
743
861
  if (dashBreaks)
744
862
  markDashJoins(tokens);
@@ -927,27 +1045,45 @@ export function measureRichSnippet(spans, normalFont, boldFont, italicFont, bold
927
1045
  return measureRichText(spans, plainText, normalFont, boldFont, italicFont, boldItalicFont, maxWidthPx, lineHeightPx, options);
928
1046
  }
929
1047
  function measureRichText(spans, plainText, normalFont, boldFont, italicFont, boldItalicFont, maxWidthPx, lineHeightPx, options) {
1048
+ // A writing mode asked for this text alone (`options.writingMode`): every
1049
+ // width below reads it.
1050
+ if (options?.writingMode !== undefined && options.writingMode !== getMeasureWritingMode()) {
1051
+ const opts = options;
1052
+ return withMeasureWritingMode(opts.writingMode, () => measureRichText(spans, plainText, normalFont, boldFont, italicFont, boldItalicFont, maxWidthPx, lineHeightPx, opts));
1053
+ }
1054
+ // Chinese, Japanese or Korean text: its own composer, which breaks
1055
+ // between characters under the document's line-break rules and spreads
1056
+ // justified lines between them — also text with no two CJK letters in a
1057
+ // row (价¥5,999。好, 第1条、第2条). A Latin paragraph that only quotes a
1058
+ // few CJK words stays here, with a break allowed next to their characters.
1059
+ // So is a paragraph with ruby or a warichu note (#194, #195), which the
1060
+ // composer alone lays out.
1061
+ // The paragraph is looked at for CJK text once (`cjkText`); a Latin one
1062
+ // then never looks into its words.
1063
+ const cjkText = hasCJK(plainText);
1064
+ if ((cjkText && composesAsCjk(plainText)) || spans.some((s) => s.ruby || s.warichu)) {
1065
+ return composeCjkParagraph(spans, normalFont, boldFont, italicFont, boldItalicFont, maxWidthPx, lineHeightPx, options);
1066
+ }
930
1067
  const shouldHyphenate = options?.hyphenate ?? false;
931
1068
  const indentPx = options?.firstLineIndentPx ?? 0;
932
1069
  const hanging = options?.hangingIndent ?? false;
933
1070
  const textAlign = options?.textAlign ?? 'left';
934
1071
  const letterSpacingPx = options?.letterSpacingPx ?? 0;
935
1072
  const hyphenationZonePx = shouldHyphenate ? options?.hyphenationZonePx : undefined;
936
- const tokens = tokenizeSpans(spans, normalFont, boldFont, italicFont, boldItalicFont, shouldHyphenate, letterSpacingPx, options?.breakAfterDashes === true, options?.hyphenateCompounds === false);
1073
+ const tokens = tokenizeSpans(spans, normalFont, boldFont, italicFont, boldItalicFont, shouldHyphenate, letterSpacingPx, options?.breakAfterDashes === true, options?.hyphenateCompounds === false, cjkText);
937
1074
  const repeatHyphen = options?.repeatHyphen === true;
938
1075
  const hasSmallCaps = tokens.some((t) => t.smallCaps);
939
1076
  const normalSpaceWidth = textAlign === 'justify' ? normalSpaceWidthFor(normalFont) + letterSpacingPx : 0;
940
1077
  if (tokens.length === 0) {
941
1078
  return { lines: [], totalHeight: 0 };
942
1079
  }
943
- // Knuth-Plass optimal line breaking path. Not for words set without
944
- // spaces (a run of ideographs or kana): a line of them has no spaces to
945
- // stretch, so it is set first-fit, breaking between ideographs, as the
946
- // plain path does. A lone CJK bracket or fullwidth sign is no reason.
947
- // Ragged text takes it too with `optimalRagged`: its word spaces keep
948
- // their width and each line gets the ragged stretch instead.
1080
+ // Knuth-Plass optimal line breaking path. A Latin paragraph quoting CJK
1081
+ // words takes it too: the breaks next to their characters are free
1082
+ // penalties, as a hyphenation point that adds nothing. Ragged text takes
1083
+ // it too with `optimalRagged`: its word spaces keep their width and each
1084
+ // line gets the ragged stretch instead.
949
1085
  const ragged = textAlign !== 'justify';
950
- if (options?.optimal && (!ragged || options.optimalRagged) && !hasCJKRun(plainText)) {
1086
+ if (options?.optimal && (!ragged || options.optimalRagged)) {
951
1087
  const maxStretchRatio = ragged ? 1 : options.maxStretchRatio ?? 1.5;
952
1088
  const minShrinkRatio = ragged ? 1 : options.minShrinkRatio ?? 0.8;
953
1089
  // The runt threshold counts word spaces on ragged text too.
@@ -988,7 +1124,7 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
988
1124
  ...(ragged && hyphenationZonePx !== undefined ? { hyphenationZone: hyphenationZonePx } : {}),
989
1125
  });
990
1126
  if (breaks.length > 0) {
991
- const kpLines = reconstructRichLines(items, breaks, tokens, lineHeightPx, lineWidthFn, lineIndentFn, normalSpaceWidth, textAlign, trackingPerChar);
1127
+ const kpLines = reconstructRichLines(items, breaks, tokens, lineHeightPx, lineWidthFn, lineIndentFn, normalSpaceWidth, textAlign, trackingPerChar, lineBaselineOffset(lineHeightPx, normalFont));
992
1128
  if (!hasOverfullLine(kpLines, lineWidthFn, ragged)) {
993
1129
  if (hasSmallCaps)
994
1130
  expandSmallCaps(kpLines, normalFont, boldFont, italicFont, boldItalicFont, letterSpacingPx);
@@ -1004,6 +1140,7 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1004
1140
  // measure (a word wider than it: the greedy breaker divides it)
1005
1141
  }
1006
1142
  const lines = [];
1143
+ const baselineOffset = lineBaselineOffset(lineHeightPx, normalFont);
1007
1144
  let y = 0;
1008
1145
  let tokenIdx = 0;
1009
1146
  let lineIndex = 0;
@@ -1076,7 +1213,7 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1076
1213
  const split = splitToken(token, chosen, mark, markW(chosen));
1077
1214
  lineTokens.push(split.head);
1078
1215
  lineWidth += split.head.width;
1079
- lineHyphenated = true;
1216
+ lineHyphenated = chosen.cjk !== true;
1080
1217
  lineSyllable = mark !== '' && !chosen.author;
1081
1218
  lineHardHyphen = chosen.bare === true;
1082
1219
  lineRepeatNext = repeatHyphen && chosen.bare === true && !token.bareBreaks;
@@ -1106,9 +1243,9 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1106
1243
  if (glued > 0) {
1107
1244
  const prev = lineTokens[lineTokens.length - 1];
1108
1245
  const font = tokenFont(token, normalFont, boldFont, italicFont, boldItalicFont);
1109
- if (token.stacked !== 'second' && cjkJoinBreaks(prev.text, token.text, font)) {
1110
- // The line ends inside the run: no space is consumed.
1111
- lineHyphenated = true;
1246
+ if (token.stacked !== 'second' && token.footnoteId === undefined && token.refResourceId === undefined && cjkJoinBreaks(prev.text, token.text)) {
1247
+ // The line ends between two runs, next to a CJK character: no
1248
+ // space is consumed and nothing is added.
1112
1249
  break;
1113
1250
  }
1114
1251
  // The group's latest plain break (between ideographs, a dash, a
@@ -1133,7 +1270,7 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1133
1270
  lineWidth += split.head.width;
1134
1271
  tokens[origIdx] = split.tail;
1135
1272
  tokenIdx = origIdx;
1136
- lineHyphenated = true;
1273
+ lineHyphenated = back.bp.cjk !== true;
1137
1274
  lineHardHyphen = back.bp.bare === true;
1138
1275
  lineRepeatNext = repeatHyphen && back.bp.bare === true && !back.token.bareBreaks;
1139
1276
  break;
@@ -1217,29 +1354,14 @@ function measureRichText(spans, plainText, normalFont, boldFont, italicFont, bol
1217
1354
  }
1218
1355
  const isLastLine = peekIdx >= tokens.length;
1219
1356
  // Build segments for justified rendering
1220
- const segments = trimChipLineEdges(lineTokens.map((t) => ({
1221
- kind: t.mathRender ? 'math' : t.swatch ? 'swatch' : t.chip ? 'chip' : t.kind,
1222
- text: cleanSoftHyphens(t.text),
1223
- width: t.width,
1224
- bold: t.bold || undefined,
1225
- italic: t.italic || undefined,
1226
- ...(t.mathRender ? { mathRender: t.mathRender } : {}),
1227
- ...(t.swatch ? { swatch: t.swatch } : {}),
1228
- ...(t.chip ? { chip: t.chip } : {}),
1229
- ...(t.refResourceId !== undefined ? { refResourceId: t.refResourceId } : {}),
1230
- ...(t.footnoteId !== undefined ? { footnoteId: t.footnoteId } : {}),
1231
- ...(t.captionLabel ? { captionLabel: true } : {}),
1232
- ...(t.script ? { script: t.script, fontString: t.scriptFont, baselineShift: t.baselineShift } : {}),
1233
- ...(t.stacked === 'first' ? { stacked: true } : {}),
1234
- ...(t.smallCaps ? { smallCaps: true } : {}),
1235
- })));
1357
+ const segments = trimChipLineEdges(lineTokens.map(tokenSegment));
1236
1358
  const lineText = lineTokens.map((t) => cleanSoftHyphens(t.text)).join('');
1237
1359
  const contentWidth = segments.reduce((sum, t) => sum + t.width, 0);
1238
1360
  const justifiedSpaceRatio = computeJustifiedSpaceRatio(segments, lineMaxWidth, normalSpaceWidth, textAlign, isLastLine);
1239
1361
  lines.push({
1240
1362
  text: lineText,
1241
1363
  bbox: createBoundingBox(lineIndent, y, contentWidth, lineHeightPx),
1242
- baseline: y + lineHeightPx * 0.8,
1364
+ baseline: y + baselineOffset,
1243
1365
  hyphenated: lineHyphenated,
1244
1366
  ...(lineHyphenated && lineHardHyphen ? { hardHyphen: true } : {}),
1245
1367
  ...(lineRepeated && lineText.startsWith('-') ? { repeatedHyphen: true } : {}),