postext 1.8.6 → 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
@@ -2,7 +2,48 @@ import { footnoteRuleSegments } from './columnRule';
2
2
  import { tableCellFillRects, tableFrameOutline } from './vdt';
3
3
  import { dimensionToPx } from './units';
4
4
  import { documentInkHex, isSingleInkSvgUrl, singleInkColorMatrix } from './svg/singleInk';
5
- import { lineTrailingTracking } from './lineInk';
5
+ import { lineInkExtent, lineTrailingTracking } from './lineInk';
6
+ import { CHARACTER_GRID_COLOR, cjkGridCells } from './pipeline/cjkGrid';
7
+ import { renderLangOf } from './locale';
8
+ import { hasCJK } from './measure/cjk';
9
+ import { DEFAULT_CENTRAL_BASELINE } from './vdt';
10
+ import { holdsTurnedMark, segmentOrientation, verticalRuns } from './writingMode';
11
+ import { graphemesOf } from './measure/graphemes';
12
+ import { fontFamilyOf } from './measure/vertical';
13
+ import { lineMarksHtml, rubyHtml, verticalLineMarksHtml, warichuHtml } from './htmlAnnotations';
14
+ /**
15
+ * Declarations of every box of CJK text measured with no punctuation
16
+ * trimming: the browser adds and removes nothing. Chrome's
17
+ * `text-spacing-trim: normal` (and fonts' `chws`) would set the first of
18
+ * two marks that meet half width (`)》`, `”“`), and `text-autospace` would
19
+ * add space between Han and Latin, where the layout measured them apart
20
+ * (`measureTextWidth`, `markCuts`) and the CJK composer adjusted the marks
21
+ * itself; the renderers position what it set. Set on a line of the CJK
22
+ * composer (`VDTLine.cjkComposed`), on each word of another line that holds
23
+ * CJK text (each was measured alone), on a design text line or run and a
24
+ * list marker that holds CJK text. Absent from any other box, so the
25
+ * output of other documents is unchanged.
26
+ */
27
+ const CJK_TEXT_DECL = "text-spacing-trim:space-all;text-autospace:no-autospace;font-feature-settings:'chws' 0,'halt' 0,'vchw' 0;";
28
+ /** The part of {@link CJK_TEXT_DECL} a `font` shorthand resets: repeated
29
+ * after it on an inner box in another face. */
30
+ const CJK_FEATURES_DECL = "font-feature-settings:'chws' 0,'halt' 0,'vchw' 0;";
31
+ /** A dash of a 破折号 stretched over its em (`VDTLineSegment.inkScale`):
32
+ * scaled from its start, with the glyph the layout measured. Under
33
+ * `lang="zh-Hans"` a face may swap its own Chinese form in (`locl`: Noto
34
+ * Serif SC's full-width dash), which the scale was not computed for. */
35
+ const DASH_FEATURES_DECL = "font-feature-settings:'chws' 0,'halt' 0,'vchw' 0,'locl' 0;";
36
+ const inkScaleDecl = (scale) => `transform:scaleX(${scale.toFixed(4)});transform-origin:0 0;${DASH_FEATURES_DECL}`;
37
+ /** Whether a line box carries {@link CJK_TEXT_DECL}: a line of the CJK
38
+ * composer, which it measured character by character, or a line with no
39
+ * segments (one span) holding CJK text. A word-by-word line holding CJK
40
+ * text sets it on the words that hold some (`segmentCjk`). */
41
+ function lineCjkDecl(line) {
42
+ return line.cjkComposed === true || ((!line.segments || line.segments.length === 0) && hasCJK(line.text));
43
+ }
44
+ function segmentCjk(seg, lineDecl) {
45
+ return lineDecl ? 'line' : hasCJK(seg.text) ? 'own' : false;
46
+ }
6
47
  /**
7
48
  * The resources this document anchors in its HTML (`id="pt-res-<id>"`):
8
49
  * those whose embed (a first slice, for a split table) is on one of its
@@ -152,7 +193,45 @@ function renderMathSegmentSvg(seg, xPx, line, block) {
152
193
  * which aligns on that baseline without growing or shifting the line
153
194
  * box. A face with other vertical metrics would otherwise float its own
154
195
  * baseline higher or lower than the surrounding text. */
155
- function renderTextSegment(seg, x, top, fontDecl, colorDecl, color) {
196
+ function renderTextSegment(seg, x, top, fontDecl, colorDecl, color,
197
+ /** The tracking the line box already carries (block + line); a segment's
198
+ * own (a justified CJK line) is added to it. */
199
+ tracking = 0,
200
+ /** Whether the browser's punctuation spacing is off for the segment
201
+ * (see {@link CJK_TEXT_DECL}): set by its line (`'line'`) or on its own
202
+ * box (`'own'`); a box in another face repeats the features either way. */
203
+ cjk = false) {
204
+ const spacingDecl = seg.tracking !== undefined ? `letter-spacing:${tracking + seg.tracking}px;` : '';
205
+ // A compressed CJK mark is painted before its box (`inkOffset`).
206
+ const left = seg.inkOffset !== undefined ? x + seg.inkOffset : x;
207
+ const scaleDecl = seg.inkScale !== undefined ? inkScaleDecl(seg.inkScale) : '';
208
+ const pos = `position:absolute;left:${left.toFixed(3)}px;top:${top};white-space:pre;${spacingDecl}${cjk === 'own' ? CJK_TEXT_DECL : ''}${scaleDecl}`;
209
+ // Text set with emphasis dots is emphasis (#193); the dots are the
210
+ // line's marks.
211
+ const text = seg.cjkMarks?.dots ? `<em style="font-style:inherit;">${esc(seg.text)}</em>` : esc(seg.text);
212
+ const featuresDecl = !fontDecl ? '' : scaleDecl ? DASH_FEATURES_DECL : cjk ? CJK_FEATURES_DECL : '';
213
+ if (seg.refResourceId !== undefined) {
214
+ // Anchors carry an explicit color so the UA link blue never leaks in.
215
+ const inner = `<a href="${refAnchorHref(seg.refResourceId)}" style="text-decoration:none;${fontDecl}${featuresDecl}${fontDecl ? 'line-height:0;' : ''}color:${color};">${text}</a>`;
216
+ return `<span style="${pos}">${inner}</span>`;
217
+ }
218
+ if (fontDecl) {
219
+ return `<span style="${pos}"><span style="${fontDecl}${featuresDecl}line-height:0;${colorDecl}">${text}</span></span>`;
220
+ }
221
+ return `<span style="${pos}${colorDecl}">${text}</span>`;
222
+ }
223
+ /**
224
+ * {@link renderTextSegment} for a segment of a line set word by word (not
225
+ * `VDTLine.cjkComposed`), which carries none of the composer's fields
226
+ * (`tracking`, `inkOffset`, `inkScale`): the markup every such segment had
227
+ * before the CJK features. One that holds CJK text (`cjk`) or carries
228
+ * Chinese marks goes to {@link renderMarkedWordSegment}: the browser's
229
+ * punctuation spacing off on its own box (see {@link CJK_TEXT_DECL}), its
230
+ * text in `<em>` when it is set with emphasis dots.
231
+ */
232
+ function renderWordTextSegment(seg, x, top, fontDecl, colorDecl, color, cjk) {
233
+ if (cjk || seg.cjkMarks)
234
+ return renderMarkedWordSegment(seg, x, top, fontDecl, colorDecl, color, cjk);
156
235
  const pos = `position:absolute;left:${x.toFixed(3)}px;top:${top};white-space:pre;`;
157
236
  const text = esc(seg.text);
158
237
  if (seg.refResourceId !== undefined) {
@@ -165,6 +244,24 @@ function renderTextSegment(seg, x, top, fontDecl, colorDecl, color) {
165
244
  }
166
245
  return `<span style="${pos}${colorDecl}">${text}</span>`;
167
246
  }
247
+ /** {@link renderWordTextSegment} for a segment that holds CJK text (`cjk`)
248
+ * or carries Chinese marks. */
249
+ function renderMarkedWordSegment(seg, x, top, fontDecl, colorDecl, color, cjk) {
250
+ const pos = `position:absolute;left:${x.toFixed(3)}px;top:${top};white-space:pre;${cjk ? CJK_TEXT_DECL : ''}`;
251
+ // Text set with emphasis dots is emphasis (#193); the dots are the
252
+ // line's marks.
253
+ const text = seg.cjkMarks?.dots ? `<em style="font-style:inherit;">${esc(seg.text)}</em>` : esc(seg.text);
254
+ const featuresDecl = fontDecl && cjk ? CJK_FEATURES_DECL : '';
255
+ if (seg.refResourceId !== undefined) {
256
+ // Anchors carry an explicit color so the UA link blue never leaks in.
257
+ const inner = `<a href="${refAnchorHref(seg.refResourceId)}" style="text-decoration:none;${fontDecl}${featuresDecl}${fontDecl ? 'line-height:0;' : ''}color:${color};">${text}</a>`;
258
+ return `<span style="${pos}">${inner}</span>`;
259
+ }
260
+ if (fontDecl) {
261
+ return `<span style="${pos}"><span style="${fontDecl}${featuresDecl}line-height:0;${colorDecl}">${text}</span></span>`;
262
+ }
263
+ return `<span style="${pos}${colorDecl}">${text}</span>`;
264
+ }
168
265
  /** A `:ref` painted as several runs (a label in small capitals: one run per
169
266
  * case) from `segs[start]` on. Every run is placed as measured, and all of
170
267
  * them sit in one anchor, so the reference stays one link. `paint` renders
@@ -212,7 +309,20 @@ function linkRuns() {
212
309
  function segmentHref(seg) {
213
310
  return seg.refResourceId === undefined ? seg.href : undefined;
214
311
  }
312
+ /**
313
+ * The segments of a horizontal line. A line of the CJK composer goes to
314
+ * {@link renderComposedSegments}. Any other line was set word by word and
315
+ * carries none of the composer's fields (a segment's `tracking`,
316
+ * `inkOffset`, `inkScale`, `hangs`, `autospace`, `ruby`, `warichu`): its
317
+ * markup is the one every line had before the CJK features, the browser's
318
+ * punctuation spacing turned off on each segment that holds CJK text. Only
319
+ * a line whose text holds CJK characters has its segments looked into: the
320
+ * line's `text` holds the text of every segment, except the leader of a
321
+ * contents entry (`tocEntry`).
322
+ */
215
323
  function renderSegments(line, block, targets) {
324
+ if (line.cjkComposed)
325
+ return renderComposedSegments(line, block, targets);
216
326
  // The tracking after the last glyph is advance, not ink: centring and
217
327
  // right alignment leave it out (EF-153), as the canvas does.
218
328
  const trailing = lineTrailingTracking(line, (block.letterSpacing ?? 0) + (line.letterSpacing ?? 0));
@@ -255,13 +365,14 @@ function renderSegments(line, block, targets) {
255
365
  const links = linkRuns();
256
366
  let x = leadingGap;
257
367
  const segs = line.segments;
368
+ const cjk = block.tocEntry !== undefined || hasCJK(line.text);
258
369
  const paintText = (seg, at, inLink = false) => {
259
370
  const font = quoteFontString(pickSegmentFont(seg, block));
260
371
  const color = pickSegmentColor(seg, block);
261
372
  const fontDecl = font !== quoteFontString(block.fontString) ? `font:${font};` : '';
262
373
  const colorDecl = color !== block.color ? `color:${color};` : '';
263
374
  const top = seg.baselineShift ? `${seg.baselineShift.toFixed(3)}px` : '0';
264
- return renderTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, color);
375
+ return renderWordTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, color, cjk && hasCJK(seg.text));
265
376
  };
266
377
  for (let i = 0; i < segs.length; i++) {
267
378
  const seg = segs[i];
@@ -296,6 +407,116 @@ function renderSegments(line, block, targets) {
296
407
  x += seg.width;
297
408
  }
298
409
  parts.push(links.end());
410
+ // Emphasis dots, proper-name and book-title lines (#193).
411
+ if (line.marks)
412
+ parts.push(lineMarksHtml(line, block.color));
413
+ return parts.join('');
414
+ }
415
+ /** {@link renderSegments} for a line of the CJK composer: hung marks and
416
+ * Han–Latin spaces kept out of the justification, each segment with its
417
+ * own tracking, ink offset and scale, warichu notes and ruby readings. */
418
+ function renderComposedSegments(line, block, targets) {
419
+ // The tracking after the last glyph is advance, not ink: centring and
420
+ // right alignment leave it out (EF-153), as the canvas does.
421
+ const lineTracking = (block.letterSpacing ?? 0) + (line.letterSpacing ?? 0);
422
+ const trailing = lineTrailingTracking(line, lineTracking);
423
+ if (!line.segments || line.segments.length === 0) {
424
+ const plainIndent = line.bbox.x - block.bbox.x;
425
+ const plainWidth = line.bbox.width - trailing;
426
+ const plainLeft = block.textAlign === 'right'
427
+ ? Math.max(0, block.bbox.width - plainIndent - plainWidth)
428
+ : block.textAlign === 'center'
429
+ ? Math.max(0, (block.bbox.width - plainIndent - plainWidth) / 2)
430
+ : 0;
431
+ return `<span style="position:absolute;left:${plainLeft.toFixed(3)}px;top:0;white-space:pre;">${esc(line.text)}</span>`;
432
+ }
433
+ // Match canvas justification: stretch inter-word spaces to fill effective width.
434
+ const lineIndent = line.bbox.x - block.bbox.x;
435
+ const effectiveWidth = block.bbox.width - lineIndent;
436
+ let wordWidth = 0;
437
+ let spaceCount = 0;
438
+ for (const seg of line.segments) {
439
+ // A hung mark is outside the measure; a Han–Latin space keeps its
440
+ // width.
441
+ if (seg.hangs)
442
+ continue;
443
+ if (seg.kind === 'space' && !seg.autospace)
444
+ spaceCount++;
445
+ else
446
+ wordWidth += seg.width;
447
+ }
448
+ const contentWidth = lineInkExtent(line, 0).width;
449
+ // Last lines render ragged at natural width — except when overfull:
450
+ // Knuth-Plass may accept a final line wider than the measure on the
451
+ // assumption that its inter-word glue shrinks (TeX glue-setting semantics),
452
+ // so honor that by compressing the spaces to fit the measure exactly.
453
+ const useJustify = block.textAlign === 'justify' && spaceCount > 0 &&
454
+ ((!line.isLastLine && !line.ragged) || contentWidth > effectiveWidth);
455
+ const justifiedSpaceWidth = useJustify
456
+ ? (effectiveWidth - wordWidth) / spaceCount
457
+ : 0;
458
+ // Centred / right alignment — math display blocks, ragged-left paragraph
459
+ // styles. Distribute the leading gap.
460
+ const slack = Math.max(0, effectiveWidth - (contentWidth - trailing));
461
+ const leadingGap = block.textAlign === 'center' ? slack / 2 : block.textAlign === 'right' ? slack : 0;
462
+ const parts = [];
463
+ const links = linkRuns();
464
+ let x = leadingGap;
465
+ const segs = line.segments;
466
+ const lineDecl = lineCjkDecl(line);
467
+ const paintText = (seg, at, inLink = false) => {
468
+ const font = quoteFontString(pickSegmentFont(seg, block));
469
+ const color = pickSegmentColor(seg, block);
470
+ const fontDecl = font !== quoteFontString(block.fontString) ? `font:${font};` : '';
471
+ const colorDecl = color !== block.color ? `color:${color};` : '';
472
+ const top = seg.baselineShift ? `${seg.baselineShift.toFixed(3)}px` : '0';
473
+ return renderTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, color, lineTracking, segmentCjk(seg, lineDecl));
474
+ };
475
+ for (let i = 0; i < segs.length; i++) {
476
+ const seg = segs[i];
477
+ if (seg.kind === 'space') {
478
+ x += useJustify && !seg.autospace ? justifiedSpaceWidth : seg.width;
479
+ continue;
480
+ }
481
+ parts.push(links.at(segmentHref(seg)));
482
+ if (seg.kind === 'math') {
483
+ parts.push(renderMathSegmentSvg(seg, x, line, block));
484
+ x += seg.width;
485
+ continue;
486
+ }
487
+ if (seg.kind === 'swatch') {
488
+ parts.push(renderSwatch(x, line.baseline - line.bbox.y, seg.width, seg.swatch?.color, block.color));
489
+ x += seg.width;
490
+ continue;
491
+ }
492
+ if (seg.chip) {
493
+ parts.push(renderChip(seg.chip, x, line.baseline - line.bbox.y, quoteFontString(block.fontString), block.color, (run) => pickSegmentColor({ kind: 'text', text: run.text, width: run.width, bold: run.bold, italic: run.italic }, block)));
494
+ x += seg.width;
495
+ continue;
496
+ }
497
+ if (seg.warichu) {
498
+ // A warichu note's part: its two rows (#195).
499
+ parts.push(warichuHtml(seg.warichu, x, pickSegmentColor(seg, block), quoteFontString));
500
+ x += seg.width;
501
+ continue;
502
+ }
503
+ if (seg.refResourceId !== undefined && segs[i + 1]?.refContinues) {
504
+ const group = renderRefRuns(segs, i, x, pickSegmentColor(seg, block), (run, at) => paintText(run, at, true), refLinks(seg.refResourceId, targets));
505
+ parts.push(group.html);
506
+ x = group.x;
507
+ i = group.end - 1;
508
+ continue;
509
+ }
510
+ parts.push(paintText(seg, x, seg.refResourceId !== undefined && !refLinks(seg.refResourceId, targets)));
511
+ // A ruby base's reading (#194).
512
+ if (seg.ruby)
513
+ parts.push(rubyHtml(seg.ruby, x, pickSegmentColor(seg, block), quoteFontString));
514
+ x += seg.width;
515
+ }
516
+ parts.push(links.end());
517
+ // Emphasis dots, proper-name and book-title lines (#193).
518
+ if (line.marks)
519
+ parts.push(lineMarksHtml(line, block.color));
299
520
  return parts.join('');
300
521
  }
301
522
  /** Inline colour swatch (`:swatch{…}`): a square of `side` px on the line's
@@ -330,7 +551,8 @@ function renderChip(chip, x, baselineOffset, lineFont, lineColor, inkFor) {
330
551
  const fontDecl = font !== lineFont ? `font:${font};` : '';
331
552
  const colorDecl = color !== lineColor ? `color:${color};` : '';
332
553
  const top = run.baselineShift ? `${run.baselineShift.toFixed(3)}px` : '0';
333
- parts.push(renderTextSegment({ kind: 'text', text: run.text, width: run.width }, tx, top, fontDecl, colorDecl, color));
554
+ // A chip's runs were measured one by one, as a whole each.
555
+ parts.push(renderTextSegment({ kind: 'text', text: run.text, width: run.width }, tx, top, fontDecl, colorDecl, color, 0, hasCJK(run.text) ? 'own' : false));
334
556
  tx += run.width;
335
557
  }
336
558
  return parts.join('');
@@ -367,14 +589,20 @@ function renderBullet(block) {
367
589
  `font:${onBaseline ? lineFont : font};` +
368
590
  `color:${color};` +
369
591
  `white-space:pre;` +
592
+ (hasCJK(text) ? CJK_TEXT_DECL : '') +
370
593
  (onBaseline
371
- ? `"><span style="font:${font};line-height:0;">${esc(text)}</span></div>`
594
+ ? `"><span style="font:${font};${hasCJK(text) ? CJK_FEATURES_DECL : ''}line-height:0;">${esc(text)}</span></div>`
372
595
  : `">${esc(text)}</div>`);
373
596
  let html = markerDiv('pt-bullet', block.bulletOffsetX, bulletFont, bulletColor, block.bulletText);
374
597
  // Ordered-list separator styled apart from the number (own font/colour).
375
598
  if (block.separatorText && block.separatorX !== undefined) {
376
599
  const separatorFont = quoteFontString(block.separatorFontString ?? block.bulletFontString ?? block.fontString);
377
600
  const separatorColor = block.separatorColor ?? bulletColor;
601
+ // The prefix run before the number, in the separator's style, first in
602
+ // the markup so a copy reads (一).
603
+ if (block.prefixText && block.prefixX !== undefined) {
604
+ html = markerDiv('pt-separator', block.prefixX, separatorFont, separatorColor, block.prefixText) + html;
605
+ }
378
606
  html += markerDiv('pt-separator', block.separatorX, separatorFont, separatorColor, block.separatorText);
379
607
  }
380
608
  return html;
@@ -396,8 +624,278 @@ function renderLine(line, block, targets) {
396
624
  `color:${block.color};` +
397
625
  strikethroughDecl +
398
626
  trackingDecl +
627
+ (lineCjkDecl(line) ? CJK_TEXT_DECL : '') +
399
628
  `">${renderSegments(line, block, targets)}</div>`);
400
629
  }
630
+ // ---------------------------------------------------------------------------
631
+ // Vertical text (`VDTPage.flow`)
632
+ //
633
+ // A vertical page's flow is rendered in a box turned a quarter turn
634
+ // clockwise (`pt-flow`, see `renderPageDetailed`), so boxes, rules,
635
+ // pictures, turned resource blocks and everything else of the flow land on
636
+ // the sheet as the canvas paints them. Each text line is turned back
637
+ // upright inside it — one box per line, the line's physical rectangle — and
638
+ // set with `writing-mode: vertical-rl`: the browser stands Chinese
639
+ // characters upright, takes the fonts' vertical forms and sets Latin words
640
+ // sideways. Every segment is placed where the layout put it along the line
641
+ // (`top`), its em boxes centred on the column's central axis; tate-chu-yoko
642
+ // cells are `text-combine-upright: all`, `:upright` and `:sideways` runs
643
+ // `text-orientation`.
644
+ // ---------------------------------------------------------------------------
645
+ /** The central axis of a font (em above the baseline). */
646
+ function centralOf(v, fontString) {
647
+ return v.axes?.[fontFamilyOf(fontString)] ?? DEFAULT_CENTRAL_BASELINE;
648
+ }
649
+ /** Escaped text of a vertical run, with its tate-chu-yoko cells, the
650
+ * orientation its author forced, and each turned mark in a box of its
651
+ * cell ({@link turnedCellHtml}). `font` is the run's font string (whose
652
+ * family's `dashes` stretch a dash) and `tracking` the letter spacing it
653
+ * is set with, px, which follows each cell. */
654
+ function verticalTextHtml(text, v, orient, font, tracking = 0) {
655
+ if (orient === 'tcy')
656
+ return `<span style="text-combine-upright:all;">${esc(text)}</span>`;
657
+ if (orient === 'upright')
658
+ return `<span style="text-orientation:upright;">${esc(text)}</span>`;
659
+ if (orient === 'sideways')
660
+ return `<span style="text-orientation:sideways;">${esc(text)}</span>`;
661
+ const digits = v.uprightDigits > 0 && /[0-9]/.test(text);
662
+ if (!digits && !holdsTurnedMark(text))
663
+ return esc(text);
664
+ const runs = verticalRuns(graphemesOf(text), v.region, v.uprightDigits);
665
+ if (!runs.some((r) => r.glyph.orient === 'tcy' || r.glyph.orient === 'rotate'))
666
+ return esc(text);
667
+ const advances = font !== undefined ? v.dashes?.[fontFamilyOf(font)] : undefined;
668
+ // A number in one cell combined upright; a turned mark in its cell.
669
+ return runs.map((r) => (r.glyph.orient === 'tcy'
670
+ ? `<span style="text-combine-upright:all;">${esc(r.text)}</span>`
671
+ : r.glyph.orient === 'rotate' ? turnedCellHtml(r, advances?.[r.text], tracking) : esc(r.text))).join('');
672
+ }
673
+ /**
674
+ * A mark a vertical line turns in a cell of its own (`rotate`: a dash, an
675
+ * ellipsis, an interpunct, a wave dash). The browser sets it sideways at
676
+ * its horizontal advance (Noto's · is a third of an em), where the layout
677
+ * gave it its cell (one em; half an em for the mainland interpunct), as
678
+ * the canvas and the PDF paint it: so it stands in a box the cell's
679
+ * length, centred in it, with the line's tracking after the box as after
680
+ * any cell. A dash is stretched to fill its cell, as they stretch it: by
681
+ * its advance the layout measured (`advance`, ems), with the glyph it
682
+ * measured (the face's Chinese form off, see {@link DASH_FEATURES_DECL});
683
+ * with no measured advance, in the font's full-width form (Noto's —).
684
+ */
685
+ function turnedCellHtml(run, advance, tracking) {
686
+ const cell = run.cell ?? 1;
687
+ let inner = esc(run.text);
688
+ if (run.glyph.stretch) {
689
+ inner = advance !== undefined && advance > 0
690
+ ? `<span style="${advance < cell ? `transform:scaleY(${(cell / advance).toFixed(4)});` : ''}${DASH_FEATURES_DECL}">${inner}</span>`
691
+ : `<span style="font-variant-east-asian:full-width;">${inner}</span>`;
692
+ }
693
+ return `<span style="display:inline-flex;justify-content:center;inline-size:${cell}em;letter-spacing:0;${tracking !== 0 ? `margin-inline-end:${tracking}px;` : ''}">${inner}</span>`;
694
+ }
695
+ /**
696
+ * A box of the turned flow (`left`, `top`, `width` along the line,
697
+ * `height` across it) holding a box turned back upright, set vertically:
698
+ * `content` is placed inside that one with physical `top` (along the line)
699
+ * and `right` (from the box's physical right edge, the flow's top).
700
+ */
701
+ function uprightBox(left, top, width, height, decl, content, attrs = '') {
702
+ return (`<div${attrs ? ` ${attrs}` : ''} style="position:absolute;left:${left.toFixed(3)}px;top:${top.toFixed(3)}px;width:${Math.max(0, width).toFixed(3)}px;height:${height.toFixed(3)}px;">` +
703
+ uprightInner(width, height, decl, content) +
704
+ `</div>`);
705
+ }
706
+ /** The box of {@link uprightBox} turned back upright: `height` wide on the
707
+ * sheet, `width` tall, set vertically. */
708
+ function uprightInner(width, height, decl, content) {
709
+ return (`<div style="position:absolute;left:0;top:0;width:${height.toFixed(3)}px;height:${Math.max(0, width).toFixed(3)}px;` +
710
+ `transform:translate(0,${height.toFixed(3)}px) rotate(-90deg);transform-origin:0 0;` +
711
+ `writing-mode:vertical-rl;text-orientation:mixed;${decl}">${content}</div>`);
712
+ }
713
+ /** A run of vertical text at `at` along its box, its em boxes centred
714
+ * `axis` px from the box's flow top (the physical right edge). The
715
+ * line height that centres them comes after `decl`: a `font` shorthand
716
+ * in it resets `line-height` to `normal`. */
717
+ function verticalSpan(at, axis, inner, decl = '') {
718
+ const lh = Math.max(0, 2 * axis);
719
+ return `<span style="position:absolute;top:${at.toFixed(3)}px;right:0;white-space:pre;${decl}line-height:${lh.toFixed(3)}px;">${inner}</span>`;
720
+ }
721
+ /** A run of vertical text whose em boxes are centred `axis` px from the
722
+ * box's flow top, on either side of it (a ruby reading or a warichu row
723
+ * sits outside the line's own box). */
724
+ function verticalSpanAt(at, axis, size, inner, decl = '') {
725
+ const lh = Math.max(1, 2 * size);
726
+ return `<span aria-hidden="true" style="position:absolute;top:${at.toFixed(3)}px;right:${(axis - lh / 2).toFixed(3)}px;white-space:pre;${decl}line-height:${lh.toFixed(3)}px;">${inner}</span>`;
727
+ }
728
+ /** Annotation runs of a vertical line (a ruby reading, a warichu note's
729
+ * rows, #194, #195) from `x` along it: set down the column in their own
730
+ * face, centred across it on their baseline (`dy`) less their face's
731
+ * axis, a zhuyin tone mark standing upright (`VDTAnnotationRun.upright`). */
732
+ function verticalAnnotationRuns(runs, x, color, v, axisOf) {
733
+ return runs.map((run) => {
734
+ const decl = `font:${quoteFontString(run.fontString)};color:${run.color ?? color};letter-spacing:0;`;
735
+ return verticalSpanAt(x + run.dx, axisOf(run.fontString, run.dy), extractFontSizePx(run.fontString), verticalTextHtml(run.text, v, run.upright ? 'upright' : undefined, run.fontString), decl);
736
+ }).join('');
737
+ }
738
+ /** A body line of a vertical page: its text segments down an upright box,
739
+ * its formulas, swatches and chips sideways where the canvas paints them
740
+ * (see the section comment). */
741
+ function renderVerticalLine(line, block, v, targets) {
742
+ const lineTracking = (block.letterSpacing ?? 0) + (line.letterSpacing ?? 0);
743
+ const trailing = lineTrailingTracking(line, lineTracking);
744
+ const lineIndent = line.bbox.x - block.bbox.x;
745
+ const effectiveWidth = block.bbox.width - lineIndent;
746
+ const baseline = line.baseline - line.bbox.y;
747
+ const blockFont = quoteFontString(block.fontString);
748
+ const axisOf = (fontString, shift = 0) => baseline + shift - centralOf(v, fontString) * extractFontSizePx(fontString);
749
+ const inner = [];
750
+ const sideways = [];
751
+ const segs = line.segments && line.segments.length > 0
752
+ ? line.segments
753
+ : [{ kind: 'text', text: line.text, width: line.bbox.width }];
754
+ let wordWidth = 0;
755
+ let spaceCount = 0;
756
+ for (const seg of segs) {
757
+ if (seg.hangs)
758
+ continue;
759
+ if (seg.kind === 'space' && !seg.autospace)
760
+ spaceCount++;
761
+ else
762
+ wordWidth += seg.width;
763
+ }
764
+ const contentWidth = line.segments && line.segments.length > 0 ? lineInkExtent(line, 0).width : line.bbox.width;
765
+ const useJustify = block.textAlign === 'justify' && spaceCount > 0
766
+ && ((!line.isLastLine && !line.ragged) || contentWidth > effectiveWidth);
767
+ const justifiedSpaceWidth = useJustify ? (effectiveWidth - wordWidth) / spaceCount : 0;
768
+ const slack = Math.max(0, effectiveWidth - (contentWidth - trailing));
769
+ let x = block.textAlign === 'center' ? slack / 2 : block.textAlign === 'right' ? slack : 0;
770
+ for (const seg of segs) {
771
+ if (seg.kind === 'space') {
772
+ x += useJustify && !seg.autospace ? justifiedSpaceWidth : seg.width;
773
+ continue;
774
+ }
775
+ if (seg.kind === 'math') {
776
+ sideways.push(renderMathSegmentSvg(seg, x, line, block));
777
+ x += seg.width;
778
+ continue;
779
+ }
780
+ if (seg.kind === 'swatch') {
781
+ sideways.push(renderSwatch(x, line.baseline - line.bbox.y, seg.width, seg.swatch?.color, block.color));
782
+ x += seg.width;
783
+ continue;
784
+ }
785
+ if (seg.chip) {
786
+ sideways.push(renderChip(seg.chip, x, line.baseline - line.bbox.y, blockFont, block.color, (run) => pickSegmentColor({ kind: 'text', text: run.text, width: run.width, bold: run.bold, italic: run.italic }, block)));
787
+ x += seg.width;
788
+ continue;
789
+ }
790
+ if (seg.warichu) {
791
+ // A warichu note's part: its two rows down the column, the upper
792
+ // row the right one, read once (#195).
793
+ const w = seg.warichu;
794
+ inner.push(`<span role="note" aria-label="${esc(w.upper + w.lower)}">${verticalAnnotationRuns(w.runs, x, w.color ?? pickSegmentColor(seg, block), v, axisOf)}</span>`);
795
+ x += seg.width;
796
+ continue;
797
+ }
798
+ const fontString = pickSegmentFont(seg, block);
799
+ const font = quoteFontString(fontString);
800
+ const color = pickSegmentColor(seg, block);
801
+ // A dash of a 破折号 (`inkScale`): turned with the flow (sideways) and
802
+ // stretched down the column from where the layout put its glyph, the
803
+ // face's own Chinese form off, as the canvas and the PDF paint it.
804
+ const stretched = seg.inkScale !== undefined;
805
+ const decl = (font !== blockFont ? `font:${font};` : '')
806
+ + (color !== block.color ? `color:${color};` : '')
807
+ + (seg.tracking !== undefined ? `letter-spacing:${lineTracking + seg.tracking}px;` : '')
808
+ + (stretched ? `transform:scaleY(${seg.inkScale.toFixed(4)});transform-origin:0 0;${DASH_FEATURES_DECL}` : '');
809
+ const segTracking = seg.tracking !== undefined ? lineTracking + seg.tracking : lineTracking;
810
+ let text = verticalTextHtml(seg.text, v, stretched ? 'sideways' : segmentOrientation(seg), fontString, segTracking);
811
+ // Text set with emphasis dots is emphasis (#193); the dots are the
812
+ // line's marks.
813
+ if (seg.cjkMarks?.dots)
814
+ text = `<em style="font-style:inherit;">${text}</em>`;
815
+ const href = seg.refResourceId !== undefined
816
+ ? (refLinks(seg.refResourceId, targets) ? refAnchorHref(seg.refResourceId) : undefined)
817
+ : seg.href;
818
+ if (href !== undefined)
819
+ text = `<a href="${esc(href)}" style="color:inherit;text-decoration:none;"${seg.href !== undefined && seg.refResourceId === undefined ? ' rel="noopener noreferrer"' : ''}>${text}</a>`;
820
+ inner.push(verticalSpan(x + (seg.inkOffset ?? 0), axisOf(fontString, seg.baselineShift ?? 0), text, decl));
821
+ // A ruby base's reading, beside the base (#194).
822
+ if (seg.ruby)
823
+ inner.push(verticalAnnotationRuns(seg.ruby.runs, x, seg.ruby.color ?? color, v, axisOf));
824
+ x += seg.width;
825
+ }
826
+ // Emphasis dots, proper-name and book-title lines (#193), in the turned
827
+ // flow with the line's box.
828
+ if (line.marks)
829
+ sideways.push(verticalLineMarksHtml(line, block.color));
830
+ const width = Math.max(line.bbox.width, effectiveWidth);
831
+ const decl = `font:${blockFont};color:${block.color};`
832
+ + (block.strikethroughText ? 'text-decoration:line-through;' : '')
833
+ + (lineTracking !== 0 ? `letter-spacing:${lineTracking}px;` : '')
834
+ + (lineCjkDecl(line) || hasCJK(line.text) ? CJK_TEXT_DECL : '');
835
+ return (`<div class="pt-line" data-block="${esc(block.id)}" style="position:absolute;left:${line.bbox.x}px;top:${line.bbox.y}px;width:${width}px;height:${line.bbox.height}px;">` +
836
+ uprightInner(width, line.bbox.height, decl, inner.join('')) +
837
+ sideways.join('') +
838
+ `</div>`);
839
+ }
840
+ /** A list marker of a vertical line (the bullet, the number, its prefix
841
+ * and separator), set down the column from `x`. */
842
+ function renderVerticalMarker(cls, x, block, v, fontString, color, text) {
843
+ const line = block.lines[0];
844
+ const size = extractFontSizePx(fontString);
845
+ const lineTop = line.bbox.y;
846
+ const h = line.bbox.height;
847
+ // A marker set as text sits on its baseline; a bullet is centred on
848
+ // `bulletY` (its axis).
849
+ const axis = block.bulletBaselineY !== undefined
850
+ ? block.bulletBaselineY - lineTop - centralOf(v, fontString) * size
851
+ : (block.bulletY ?? line.baseline) - lineTop;
852
+ const width = size * graphemesOf(text).length;
853
+ const decl = `font:${quoteFontString(fontString)};color:${color};${hasCJK(text) ? CJK_TEXT_DECL : ''}`;
854
+ return uprightBox(x, lineTop, width, h, decl, verticalSpan(0, axis, verticalTextHtml(text, v, undefined, fontString)), `class="${cls}" aria-hidden="true"`);
855
+ }
856
+ function renderVerticalBullet(block, v) {
857
+ if (block.type !== 'listItem' || !block.bulletText || block.bulletOffsetX === undefined || !block.lines[0])
858
+ return '';
859
+ const bulletFont = block.bulletFontString ?? block.fontString;
860
+ const bulletColor = block.bulletColor ?? block.color;
861
+ let html = renderVerticalMarker('pt-bullet', block.bulletOffsetX, block, v, bulletFont, bulletColor, block.bulletText);
862
+ if (block.separatorText && block.separatorX !== undefined) {
863
+ const sepFont = block.separatorFontString ?? bulletFont;
864
+ const sepColor = block.separatorColor ?? bulletColor;
865
+ if (block.prefixText && block.prefixX !== undefined)
866
+ html = renderVerticalMarker('pt-separator', block.prefixX, block, v, sepFont, sepColor, block.prefixText) + html;
867
+ html += renderVerticalMarker('pt-separator', block.separatorX, block, v, sepFont, sepColor, block.separatorText);
868
+ }
869
+ return html;
870
+ }
871
+ /** The lines of a design text set vertically: in the flow of a vertical
872
+ * page (an opener, a box title), or on its own (a running head set down
873
+ * the fore-edge, `VDTDesignTextBlock.writingMode`) inside the block's own
874
+ * turned frame. Each line's box runs from its baseline's line top. */
875
+ function verticalDesignLines(block, v, originX, originY) {
876
+ const size = extractFontSizePx(block.fontString);
877
+ const font = quoteFontString(block.fontString);
878
+ const parts = [];
879
+ const h = size * 2;
880
+ for (const line of block.lines) {
881
+ const top = line.baselineY - size * 1.5;
882
+ const axisOf = (fontString, shift = 0) => size * 1.5 + shift - centralOf(v, fontString) * extractFontSizePx(fontString);
883
+ const runs = line.runs ?? [{ text: line.text, fontString: block.fontString, width: line.width }];
884
+ let x = 0;
885
+ const inner = [];
886
+ for (const run of runs) {
887
+ const runFont = quoteFontString(run.fontString);
888
+ const decl = runFont !== font ? `font:${runFont};` : '';
889
+ inner.push(verticalSpan(x, axisOf(run.fontString, run.baselineShift ?? 0), verticalTextHtml(run.text, v, segmentOrientation(run), run.fontString, block.letterSpacingPx ?? 0), decl));
890
+ x += run.width;
891
+ }
892
+ const width = Math.max(line.width, x);
893
+ const decl = `font:${font};color:${block.color};${hasCJK(line.text) ? CJK_TEXT_DECL : ''}`
894
+ + (line.wordSpacingPx ? `word-spacing:${line.wordSpacingPx.toFixed(3)}px;` : '');
895
+ parts.push(uprightBox(originX + line.xOffset, originY + top, width, h, decl, inner.join('')));
896
+ }
897
+ return parts.join('');
898
+ }
401
899
  function pickResourceFont(seg, fonts) {
402
900
  if (seg.fontString)
403
901
  return seg.fontString;
@@ -416,8 +914,11 @@ function pickResourceFont(seg, fonts) {
416
914
  function renderResourceLine(line, fonts, color, linkColor, labelColor = color, targets) {
417
915
  const baseFont = quoteFontString(fonts.normal);
418
916
  const parts = [];
917
+ const lineDecl = lineCjkDecl(line);
419
918
  if (line.segments && line.segments.length > 0) {
420
919
  const segs = line.segments;
920
+ const composed = line.cjkComposed === true;
921
+ const cjk = !composed && hasCJK(line.text);
421
922
  const segColorOf = (seg) => (seg.refResourceId !== undefined
422
923
  ? linkColor
423
924
  : seg.captionLabel
@@ -429,7 +930,11 @@ function renderResourceLine(line, fonts, color, linkColor, labelColor = color, t
429
930
  const fontDecl = font !== baseFont ? `font:${font};` : '';
430
931
  const colorDecl = segColor !== color ? `color:${segColor};` : '';
431
932
  const top = seg.baselineShift ? `${seg.baselineShift.toFixed(3)}px` : '0';
432
- return renderTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, segColor);
933
+ // A line set word by word as every line was before the CJK
934
+ // features (see `renderSegments`).
935
+ return composed
936
+ ? renderTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, segColor, line.letterSpacing ?? 0, segmentCjk(seg, lineDecl))
937
+ : renderWordTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, segColor, cjk && hasCJK(seg.text));
433
938
  };
434
939
  const links = linkRuns();
435
940
  let x = 0;
@@ -475,6 +980,7 @@ function renderResourceLine(line, fonts, color, linkColor, labelColor = color, t
475
980
  // A tracked line (a table header set with `headerLetterSpacing`) was
476
981
  // measured with the tracking in its widths.
477
982
  (line.letterSpacing ? `letter-spacing:${line.letterSpacing}px;` : '') +
983
+ (lineDecl ? CJK_TEXT_DECL : '') +
478
984
  `">${parts.join('')}</div>`);
479
985
  }
480
986
  /** An image fitted to a box: `<img>` from `resourceImageUrl`, or the neutral
@@ -593,10 +1099,13 @@ function renderResourceTable(rb, bx, by, options) {
593
1099
  }
594
1100
  return parts.join('');
595
1101
  }
596
- function renderResourceBlockHtml(block, options) {
1102
+ function renderResourceBlockHtml(block, paint) {
597
1103
  const rb = block.resourceBlock;
598
1104
  if (!rb)
599
1105
  return '';
1106
+ // Its caption, notes and cells are horizontal text, in its own frame
1107
+ // (upright on a vertical page).
1108
+ const options = paint.vertical ? { ...paint, vertical: undefined } : paint;
600
1109
  const parts = [];
601
1110
  // A rotated block: its geometry is in the upright frame, emitted inside a
602
1111
  // wrapper turned a quarter turn about the frame's origin on the page.
@@ -677,10 +1186,14 @@ function renderBoxAt(bbox, style) {
677
1186
  boxStyleDecls(style) +
678
1187
  `"></div>`);
679
1188
  }
680
- function renderDesignTextBlock(block) {
1189
+ function renderDesignTextBlock(block, options) {
681
1190
  const parts = [];
682
1191
  if (block.box)
683
1192
  parts.push(renderBoxAt(block.bbox, block.box));
1193
+ if (options?.vertical)
1194
+ return parts.join('') + renderVerticalDesignText(block, options.vertical);
1195
+ if (block.vertical)
1196
+ return parts.join('') + renderTurnedDesignText(block);
684
1197
  const font = quoteFontString(block.fontString);
685
1198
  const fontSize = extractFontSizePx(block.fontString);
686
1199
  const lineParts = [];
@@ -690,17 +1203,21 @@ function renderDesignTextBlock(block) {
690
1203
  // in its own font; a script is shifted off the baseline. Of a subscript
691
1204
  // and a superscript set over each other, the first sits in a box that
692
1205
  // takes no room and the second in one as wide as the pair (EF-80).
1206
+ // Each run was measured whole, and so was a line without runs: the
1207
+ // browser's punctuation trimming is off on those that hold CJK text.
693
1208
  const inner = line.runs
694
1209
  ? line.runs.map((run, i) => {
695
1210
  const runFont = quoteFontString(run.fontString);
1211
+ const cjkDecl = hasCJK(run.text) ? CJK_TEXT_DECL : '';
696
1212
  const fontDecl = runFont !== font ? `font:${runFont};` : '';
697
1213
  const stackDecl = run.stacked
698
1214
  ? 'display:inline-block;width:0;'
699
1215
  : line.runs[i - 1]?.stacked ? `display:inline-block;min-width:${run.width.toFixed(3)}px;` : '';
700
1216
  const shiftDecl = run.baselineShift ? `position:relative;top:${run.baselineShift.toFixed(3)}px;` : '';
701
- return fontDecl || stackDecl || shiftDecl ? `<span style="${fontDecl}${stackDecl}${shiftDecl}">${esc(run.text)}</span>` : esc(run.text);
1217
+ return fontDecl || cjkDecl || stackDecl || shiftDecl ? `<span style="${fontDecl}${cjkDecl}${stackDecl}${shiftDecl}">${esc(run.text)}</span>` : esc(run.text);
702
1218
  }).join('')
703
1219
  : esc(line.text);
1220
+ const lineDecl = !line.runs && hasCJK(line.text) ? CJK_TEXT_DECL : '';
704
1221
  // A justified line: its word spaces widened as the canvas and the PDF
705
1222
  // advance its runs (EF-109).
706
1223
  const wordSpacingDecl = line.wordSpacingPx ? `word-spacing:${line.wordSpacingPx.toFixed(3)}px;` : '';
@@ -710,6 +1227,7 @@ function renderDesignTextBlock(block) {
710
1227
  `top:${top.toFixed(3)}px;` +
711
1228
  `line-height:1;white-space:pre;` +
712
1229
  wordSpacingDecl +
1230
+ lineDecl +
713
1231
  `">${inner}</span>`);
714
1232
  }
715
1233
  const clipDecl = block.clip ? 'overflow:hidden;' : '';
@@ -732,6 +1250,40 @@ function renderDesignTextBlock(block) {
732
1250
  `">${lineParts.join('')}</div>`);
733
1251
  return parts.join('');
734
1252
  }
1253
+ /** A design text of a vertical page's flow: its lines set down the
1254
+ * column, clipped, tracked and outlined as a horizontal one. A line's
1255
+ * `xOffset` is from the block's own edge (as in `renderDesignTextBlock`),
1256
+ * its `baselineY` in the flow: only the latter is taken back to the box. */
1257
+ function renderVerticalDesignText(block, v) {
1258
+ const clipDecl = block.clip ? 'overflow:hidden;' : '';
1259
+ const trackingDecl = block.letterSpacingPx ? `letter-spacing:${block.letterSpacingPx}px;` : '';
1260
+ const strokeDecl = block.stroke && block.stroke.widthPx > 0
1261
+ ? `-webkit-text-stroke:${block.stroke.widthPx}px ${block.stroke.color};` + (block.stroke.hollow ? '-webkit-text-fill-color:transparent;' : '')
1262
+ : '';
1263
+ const hidden = block.artifact ? ' aria-hidden="true"' : '';
1264
+ return (`<div${hidden} style="position:absolute;left:${block.bbox.x}px;top:${block.bbox.y}px;width:${block.bbox.width}px;height:${block.bbox.height}px;${clipDecl}${trackingDecl}${strokeDecl}">` +
1265
+ verticalDesignLines(block, v, 0, -block.bbox.y) +
1266
+ `</div>`);
1267
+ }
1268
+ /** A design text set vertically on a page or slot whose text is
1269
+ * horizontal (`VDTDesignTextBlock.vertical`): its lines in the block's own
1270
+ * frame, turned a quarter turn clockwise about the box's top right corner,
1271
+ * each line turned back upright and set vertically. */
1272
+ function renderTurnedDesignText(block) {
1273
+ const vt = block.vertical;
1274
+ const v = { region: vt.region, uprightDigits: vt.uprightDigits, axes: vt.centralBaselines };
1275
+ const clipDecl = block.clip ? 'overflow:hidden;' : '';
1276
+ const trackingDecl = block.letterSpacingPx ? `letter-spacing:${block.letterSpacingPx}px;` : '';
1277
+ const strokeDecl = block.stroke && block.stroke.widthPx > 0
1278
+ ? `-webkit-text-stroke:${block.stroke.widthPx}px ${block.stroke.color};` + (block.stroke.hollow ? '-webkit-text-fill-color:transparent;' : '')
1279
+ : '';
1280
+ const hidden = block.artifact ? ' aria-hidden="true"' : '';
1281
+ const { x, y, width, height } = block.bbox;
1282
+ return (`<div${hidden} style="position:absolute;left:${x}px;top:${y}px;width:${width}px;height:${height}px;${clipDecl}${trackingDecl}${strokeDecl}">` +
1283
+ `<div style="position:absolute;left:${width}px;top:0;width:${height}px;height:${width}px;transform:rotate(90deg);transform-origin:0 0;">` +
1284
+ verticalDesignLines(block, v, 0, 0) +
1285
+ `</div></div>`);
1286
+ }
735
1287
  function renderDesignRuleBlock(block) {
736
1288
  const w = block.direction === 'vertical' ? block.thicknessPx : block.bbox.width;
737
1289
  const h = block.direction === 'vertical' ? block.bbox.height : block.thicknessPx;
@@ -747,8 +1299,11 @@ function renderDesignBoxBlock(block) {
747
1299
  // A callout stripe on a rounded frame: clipped to the frame's outline.
748
1300
  return block.clip ? clipToOutline(html, block.clip) : html;
749
1301
  }
750
- /** Image block (e.g. a callout icon): `<img>` from `resourceImageUrl`, or a
751
- * neutral placeholder box when the host cannot supply the image. */
1302
+ /** Image block (a callout icon, a picture a design draws): `<img>` from
1303
+ * `resourceImageUrl` — with its alternative text when it is content
1304
+ * (`VDTDesignImageBlock.altText`), else `alt=""` and
1305
+ * `role="presentation"` — or a neutral placeholder box when the host
1306
+ * cannot supply the image. */
752
1307
  function renderDesignImageBlock(block, options) {
753
1308
  const { x, y, width, height } = block.bbox;
754
1309
  if (width <= 0 || height <= 0)
@@ -757,7 +1312,22 @@ function renderDesignImageBlock(block, options) {
757
1312
  if (url) {
758
1313
  const svg = block.imageKind === undefined ? undefined : block.imageKind === 'svg';
759
1314
  const filter = options ? inkFilterDecl(options, svg, url) : '';
760
- return (`<img src="${esc(url)}" alt="" style="position:absolute;` +
1315
+ const alt = block.altText ? `alt="${esc(block.altText)}"` : 'alt="" role="presentation"';
1316
+ if (options?.vertical) {
1317
+ // A picture of a vertical page's flow stands upright on the sheet:
1318
+ // turned back inside its box, which runs `width` down the sheet and
1319
+ // `height` across it (sized for that when `upright`, else fitted
1320
+ // keeping its proportions, as the canvas draws it).
1321
+ const k = block.upright ? 1 : Math.min(height / width, width / height);
1322
+ const dw = block.upright ? height : width * k;
1323
+ const dh = block.upright ? width : height * k;
1324
+ const ox = block.upright ? 0 : (height - dw) / 2;
1325
+ const oy = block.upright ? 0 : (width - dh) / 2;
1326
+ return (`<div style="position:absolute;left:${x}px;top:${y}px;width:${width}px;height:${height}px;">` +
1327
+ `<img src="${esc(url)}" ${alt} style="position:absolute;left:0;top:0;width:${dw}px;height:${dh}px;` +
1328
+ `transform:translate(0,${height}px) rotate(-90deg) translate(${ox}px,${oy}px);transform-origin:0 0;${filter}" /></div>`);
1329
+ }
1330
+ return (`<img src="${esc(url)}" ${alt} style="position:absolute;` +
761
1331
  `left:${x}px;top:${y}px;width:${width}px;height:${height}px;${filter}" />`);
762
1332
  }
763
1333
  return (`<div aria-hidden="true" style="position:absolute;` +
@@ -767,7 +1337,7 @@ function renderDesignImageBlock(block, options) {
767
1337
  }
768
1338
  function renderDesignBlock(block, options) {
769
1339
  if (block.kind === 'text')
770
- return renderDesignTextBlock(block);
1340
+ return renderDesignTextBlock(block, options);
771
1341
  if (block.kind === 'rule')
772
1342
  return renderDesignRuleBlock(block);
773
1343
  if (block.kind === 'image')
@@ -790,9 +1360,10 @@ function renderBlockInner(block, options) {
790
1360
  if (block.resourceBlock)
791
1361
  return renderResourceBlockHtml(block, options);
792
1362
  const parts = [];
793
- parts.push(renderBullet(block));
1363
+ const v = options.vertical;
1364
+ parts.push(v ? renderVerticalBullet(block, v) : renderBullet(block));
794
1365
  for (const line of block.lines) {
795
- parts.push(renderLine(line, block, options.linkTargets));
1366
+ parts.push(v ? renderVerticalLine(line, block, v, options.linkTargets) : renderLine(line, block, options.linkTargets));
796
1367
  }
797
1368
  return parts.join('');
798
1369
  }
@@ -811,7 +1382,11 @@ function renderBlock(block, options) {
811
1382
  function renderPageDetailed(page, background, pageOptions, ink = null,
812
1383
  /** With cut lines, how far the bleed box lies inside the sheet (px); 0
813
1384
  * without them. */
814
- bleedInset = 0) {
1385
+ bleedInset = 0,
1386
+ /** The character grid drawn over the type area (`cjk.grid.show`). */
1387
+ gridCells,
1388
+ /** `cjk.region` and `cjk.uprightDigits`, for a vertical page. */
1389
+ verticalRegion, verticalDigits) {
815
1390
  const bgDecl = background && background !== 'transparent' ? `background:${background};` : '';
816
1391
  // With cut lines nothing the page paints shows past the bleed box, as on
817
1392
  // the canvas and in the PDF (EF-133).
@@ -819,9 +1394,13 @@ bleedInset = 0) {
819
1394
  // A filter id local to the page and its ink, so every page is
820
1395
  // self-contained (a patcher may replace pages one by one) and two
821
1396
  // documents on one page never share a filter.
822
- const options = ink
1397
+ const inked = ink
823
1398
  ? { ...pageOptions, ink: { id: `pt-ink-${ink.hex.replace(/[^0-9a-z]/gi, '')}-${page.index}`, matrix: ink.matrix } }
824
1399
  : pageOptions;
1400
+ // A vertical page's flow sets its text down the column.
1401
+ const options = page.flow
1402
+ ? { ...inked, vertical: { region: verticalRegion ?? 'mainland', uprightDigits: verticalDigits ?? 2, ...(page.flow.centralBaselines ? { axes: page.flow.centralBaselines } : {}), ...(page.flow.dashAdvances ? { dashes: page.flow.dashAdvances } : {}) } }
1403
+ : inked;
825
1404
  const blocks = [];
826
1405
  for (const col of page.columns) {
827
1406
  for (const block of col.blocks) {
@@ -838,18 +1417,26 @@ bleedInset = 0) {
838
1417
  // under the body (a part page's full-bleed background must not cover its
839
1418
  // chapter list); header and footer paint on top.
840
1419
  const openerHtml = page.openerBand ? renderDesignSlot(page.openerBand, options) : '';
1420
+ // Running heads and folios stay on the sheet, horizontal.
1421
+ const sheetOptions = options.vertical ? { ...options, vertical: undefined } : options;
841
1422
  const slotParts = [];
842
1423
  if (page.header)
843
- slotParts.push(renderDesignSlot(page.header, options));
1424
+ slotParts.push(renderDesignSlot(page.header, sheetOptions));
844
1425
  if (page.footer)
845
- slotParts.push(renderDesignSlot(page.footer, options));
1426
+ slotParts.push(renderDesignSlot(page.footer, sheetOptions));
846
1427
  // Whether or not a picture on the page uses it: a host patching blocks
847
1428
  // one by one may bring in an SVG image the first render did not have.
848
1429
  const defsHtml = options.ink ? inkFilterDefs(options.ink) : '';
849
1430
  // The separators above the footnotes of the columns.
850
1431
  const footnoteRulesHtml = footnoteRuleSegments(page).map((r) => `<div class="pt-footnote-rule" style="position:absolute;left:${r.x}px;top:${r.y - r.lineWidthPx / 2}px;width:${r.width}px;height:${r.lineWidthPx}px;background:${r.color};"></div>`).join('');
851
- const decorationHtml = defsHtml + openerHtml + footnoteRulesHtml + slotParts.join('');
852
- const innerHtml = defsHtml + openerHtml + blocksHtml + footnoteRulesHtml + slotParts.join('');
1432
+ const gridHtml = gridCells ? renderCharacterGridSvg(gridCells, page.flow ? page.height : page.width, page.flow ? page.width : page.height) : '';
1433
+ const decorationHtml = defsHtml + gridHtml + openerHtml + footnoteRulesHtml + slotParts.join('');
1434
+ // A vertical page's flow: one box turned a quarter turn clockwise, its
1435
+ // text lines turned back and set vertically (see `renderVerticalLine`).
1436
+ const flowHtml = gridHtml + openerHtml + blocksHtml + footnoteRulesHtml;
1437
+ const innerHtml = defsHtml + (page.flow
1438
+ ? `<div class="pt-flow" style="position:absolute;left:0;top:0;width:${page.height}px;height:${page.width}px;transform:translate(${page.width}px,0) rotate(90deg);transform-origin:0 0;">${flowHtml}</div>`
1439
+ : flowHtml) + slotParts.join('');
853
1440
  const outerHtml = `<div class="pt-page" data-page="${page.index}" style="` +
854
1441
  `position:relative;` +
855
1442
  `width:${page.width}px;` +
@@ -860,6 +1447,24 @@ bleedInset = 0) {
860
1447
  `">${innerHtml}</div>`;
861
1448
  return { outerHtml, innerHtml, blocks, decorationHtml };
862
1449
  }
1450
+ /** The character grid (稿纸) as one SVG path over the page, under the
1451
+ * text (see `cjkGridCells`). */
1452
+ function renderCharacterGridSvg(cells, width, height) {
1453
+ const { cell } = cells;
1454
+ const d = [];
1455
+ const n = (v) => String(Math.round(v * 1000) / 1000);
1456
+ cells.columns.forEach((x0, c) => {
1457
+ const chars = cells.columnChars[c] ?? cells.chars;
1458
+ const w = chars * cell;
1459
+ for (const y of cells.rows) {
1460
+ d.push(`M${n(x0)} ${n(y)}h${n(w)}M${n(x0)} ${n(y + cell)}h${n(w)}`);
1461
+ for (let i = 0; i <= chars; i++)
1462
+ d.push(`M${n(x0 + i * cell)} ${n(y)}v${n(cell)}`);
1463
+ }
1464
+ });
1465
+ return `<svg class="pt-char-grid" aria-hidden="true" width="${width}" height="${height}" style="position:absolute;left:0;top:0;pointer-events:none;">` +
1466
+ `<path d="${d.join('')}" fill="none" stroke="${CHARACTER_GRID_COLOR}" stroke-width="0.5"/></svg>`;
1467
+ }
863
1468
  /**
864
1469
  * CSS declarations (a `prop:value;` list) that reset the inherited text
865
1470
  * properties to the values the engine measured with. Every line of the
@@ -889,8 +1494,9 @@ export function renderToHtmlIndexed(doc, options = {}) {
889
1494
  const gap = options.columnGap ?? 24;
890
1495
  const padding = options.padding ?? 24;
891
1496
  const background = options.background ?? doc.config.page.backgroundColor.hex ?? 'transparent';
1497
+ // A right-bound book lays its pages out right to left in a row.
892
1498
  const docStyle = mode === 'multi'
893
- ? `display:flex;flex-direction:row;gap:${gap}px;align-items:flex-start;padding:${padding}px;box-sizing:border-box;width:max-content;`
1499
+ ? `display:flex;flex-direction:${doc.binding === 'right' ? 'row-reverse' : 'row'};gap:${gap}px;align-items:flex-start;padding:${padding}px;box-sizing:border-box;width:max-content;`
894
1500
  : `display:flex;flex-direction:column;align-items:center;padding:${padding}px 0;box-sizing:border-box;`;
895
1501
  // Single-ink diagrams: SVG pictures are filtered to the ink when the host
896
1502
  // asks (its URLs are not recoloured already).
@@ -921,7 +1527,8 @@ export function renderToHtmlIndexed(doc, options = {}) {
921
1527
  },
922
1528
  }
923
1529
  : { ...options, linkTargets };
924
- const detail = renderPageDetailed(p, background, pageOptions, ink, bleedInset);
1530
+ const gridCells = doc.config.cjk?.grid?.show ? cjkGridCells(doc.config, p.contentArea, doc.baselineGrid, p.columns, p.flow) : undefined;
1531
+ const detail = renderPageDetailed(p, background, pageOptions, ink, bleedInset, gridCells, doc.config.cjk?.region, doc.config.cjk?.uprightDigits);
925
1532
  pageHtmlParts.push(detail.outerHtml);
926
1533
  indexedPages.push({
927
1534
  index: p.index,
@@ -932,8 +1539,11 @@ export function renderToHtmlIndexed(doc, options = {}) {
932
1539
  decorationHtml: detail.decorationHtml,
933
1540
  });
934
1541
  }
935
- // The host's inherited text properties are reset first (EF-96).
936
- const html = `<div class="pt-doc" data-mode="${mode}" style="${HTML_TEXT_RESET}${docStyle}">` +
1542
+ // The host's inherited text properties are reset first (EF-96). A
1543
+ // Chinese, Japanese or Korean document declares its language, so the
1544
+ // browser picks the region's glyph forms (see `renderLangOf`).
1545
+ const docLang = renderLangOf(doc.config);
1546
+ const html = `<div class="pt-doc"${docLang ? ` lang="${docLang}"` : ''} data-mode="${mode}" style="${HTML_TEXT_RESET}${docStyle}">` +
937
1547
  pageHtmlParts.join('') +
938
1548
  `</div>`;
939
1549
  return { html, mode, pages: indexedPages };