pagyra-js 0.0.19 → 0.0.21

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 (293) hide show
  1. package/README.md +55 -0
  2. package/dist/assets/fonts/licenses/selawik/SIL Open Font License.txt +43 -0
  3. package/dist/assets/fonts/ttf/arimo/Arimo-Bold.ttf +0 -0
  4. package/dist/assets/fonts/ttf/arimo/Arimo-BoldItalic.ttf +0 -0
  5. package/dist/assets/fonts/ttf/arimo/Arimo-Italic.ttf +0 -0
  6. package/dist/assets/fonts/ttf/arimo/Arimo-Regular.ttf +0 -0
  7. package/dist/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Black.ttf +0 -0
  8. package/dist/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Bold.ttf +0 -0
  9. package/dist/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Regular.ttf +0 -0
  10. package/dist/assets/fonts/ttf/dejavu/DejaVuSans.ttf +0 -0
  11. package/dist/assets/fonts/ttf/firecode/FiraCode-Bold.ttf +0 -0
  12. package/dist/assets/fonts/ttf/firecode/FiraCode-Light.ttf +0 -0
  13. package/dist/assets/fonts/ttf/firecode/FiraCode-Medium.ttf +0 -0
  14. package/dist/assets/fonts/ttf/firecode/FiraCode-Regular.ttf +0 -0
  15. package/dist/assets/fonts/ttf/firecode/FiraCode-SemiBold.ttf +0 -0
  16. package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-Bold.ttf +0 -0
  17. package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-Light.ttf +0 -0
  18. package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-Medium.ttf +0 -0
  19. package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-Regular.ttf +0 -0
  20. package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-SemiBold.ttf +0 -0
  21. package/dist/assets/fonts/ttf/notosans/NotoSans-Regular.ttf +0 -0
  22. package/dist/assets/fonts/ttf/roboto/Roboto-Bold.ttf +0 -0
  23. package/dist/assets/fonts/ttf/roboto/Roboto-BoldItalic.ttf +0 -0
  24. package/dist/assets/fonts/ttf/roboto/Roboto-Italic.ttf +0 -0
  25. package/dist/assets/fonts/ttf/roboto/Roboto-Regular.ttf +0 -0
  26. package/dist/assets/fonts/ttf/selawik/selawk.ttf +0 -0
  27. package/dist/assets/fonts/ttf/selawik/selawkb.ttf +0 -0
  28. package/dist/assets/fonts/ttf/selawik/selawkl.ttf +0 -0
  29. package/dist/assets/fonts/ttf/selawik/selawksb.ttf +0 -0
  30. package/dist/assets/fonts/ttf/selawik/selawksl.ttf +0 -0
  31. package/dist/assets/fonts/ttf/stixtwomath/STIXTwoMath-Regular.ttf +0 -0
  32. package/dist/assets/fonts/ttf/tinos/Tinos-Bold.ttf +0 -0
  33. package/dist/assets/fonts/ttf/tinos/Tinos-BoldItalic.ttf +0 -0
  34. package/dist/assets/fonts/ttf/tinos/Tinos-Italic.ttf +0 -0
  35. package/dist/assets/fonts/ttf/tinos/Tinos-Regular.ttf +0 -0
  36. package/dist/assets/fonts/woff/lato/lato-latin-400-italic.woff +0 -0
  37. package/dist/assets/fonts/woff/lato/lato-latin-400-normal.woff +0 -0
  38. package/dist/assets/fonts/woff/lato/lato-latin-700-italic.woff +0 -0
  39. package/dist/assets/fonts/woff/lato/lato-latin-700-normal.woff +0 -0
  40. package/dist/assets/fonts/woff2/caveat/Caveat-Bold.woff2 +0 -0
  41. package/dist/assets/fonts/woff2/caveat/Caveat-Regular.woff2 +0 -0
  42. package/dist/assets/fonts/woff2/lato/lato-latin-400-italic.woff2 +0 -0
  43. package/dist/assets/fonts/woff2/lato/lato-latin-400-normal.woff2 +0 -0
  44. package/dist/assets/fonts/woff2/lato/lato-latin-700-italic.woff2 +0 -0
  45. package/dist/assets/fonts/woff2/lato/lato-latin-700-normal.woff2 +0 -0
  46. package/dist/browser/pagyra.min.js +34 -34
  47. package/dist/browser/pagyra.min.js.map +4 -4
  48. package/dist/playground/server.js +2 -0
  49. package/dist/src/css/compute-style/base-options.d.ts +7 -0
  50. package/dist/src/css/compute-style/base-options.js +24 -0
  51. package/dist/src/css/compute-style/declarations.d.ts +10 -0
  52. package/dist/src/css/compute-style/declarations.js +77 -0
  53. package/dist/src/css/compute-style/decoration.d.ts +8 -0
  54. package/dist/src/css/compute-style/decoration.js +55 -0
  55. package/dist/src/css/compute-style/defaults.d.ts +3 -0
  56. package/dist/src/css/compute-style/defaults.js +34 -0
  57. package/dist/src/css/compute-style/display.d.ts +3 -0
  58. package/dist/src/css/compute-style/display.js +85 -0
  59. package/dist/src/css/compute-style/float.d.ts +2 -0
  60. package/dist/src/css/compute-style/float.js +13 -0
  61. package/dist/src/css/compute-style/font.d.ts +12 -0
  62. package/dist/src/css/compute-style/font.js +57 -0
  63. package/dist/src/css/compute-style/overrides.d.ts +3 -0
  64. package/dist/src/css/compute-style/overrides.js +241 -0
  65. package/dist/src/css/compute-style.d.ts +2 -0
  66. package/dist/src/css/compute-style.js +34 -487
  67. package/dist/src/css/enums.d.ts +4 -0
  68. package/dist/src/css/enums.js +5 -0
  69. package/dist/src/css/layout-property-resolver.js +30 -18
  70. package/dist/src/css/length.d.ts +26 -2
  71. package/dist/src/css/length.js +48 -0
  72. package/dist/src/css/parsers/background-parser.js +1 -1
  73. package/dist/src/css/parsers/calc-parser.d.ts +2 -0
  74. package/dist/src/css/parsers/calc-parser.js +310 -0
  75. package/dist/src/css/parsers/content-parser.d.ts +2 -1
  76. package/dist/src/css/parsers/content-parser.js +7 -2
  77. package/dist/src/css/parsers/dimension-parser.js +37 -18
  78. package/dist/src/css/parsers/display-flex-parser.d.ts +4 -0
  79. package/dist/src/css/parsers/display-flex-parser.js +97 -0
  80. package/dist/src/css/parsers/filter-parser.d.ts +14 -0
  81. package/dist/src/css/parsers/filter-parser.js +255 -0
  82. package/dist/src/css/parsers/grid-parser-extended.d.ts +1 -0
  83. package/dist/src/css/parsers/grid-parser-extended.js +40 -1
  84. package/dist/src/css/parsers/grid-parser.d.ts +5 -2
  85. package/dist/src/css/parsers/grid-parser.js +71 -7
  86. package/dist/src/css/parsers/length-parser.d.ts +8 -3
  87. package/dist/src/css/parsers/length-parser.js +45 -2
  88. package/dist/src/css/parsers/margin-block-parser.js +3 -3
  89. package/dist/src/css/parsers/margin-parser.js +3 -3
  90. package/dist/src/css/parsers/padding-block-parser.js +3 -3
  91. package/dist/src/css/parsers/padding-inline-parser.js +3 -3
  92. package/dist/src/css/parsers/padding-parser.js +6 -6
  93. package/dist/src/css/parsers/position-parser.js +2 -22
  94. package/dist/src/css/parsers/register-parsers.js +29 -2
  95. package/dist/src/css/parsers/word-break-parser.d.ts +2 -0
  96. package/dist/src/css/parsers/word-break-parser.js +23 -0
  97. package/dist/src/css/properties/grid.d.ts +16 -2
  98. package/dist/src/css/properties/layout.d.ts +3 -1
  99. package/dist/src/css/properties/layout.js +1 -1
  100. package/dist/src/css/properties/misc.d.ts +5 -0
  101. package/dist/src/css/properties/typography.d.ts +3 -0
  102. package/dist/src/css/properties/visual.d.ts +36 -0
  103. package/dist/src/css/shorthands/box-shorthand.d.ts +2 -2
  104. package/dist/src/css/style-inheritance.d.ts +2 -1
  105. package/dist/src/css/style-inheritance.js +1 -0
  106. package/dist/src/css/style.d.ts +30 -10
  107. package/dist/src/css/style.js +8 -1
  108. package/dist/src/css/ua-defaults/base-defaults.d.ts +1 -0
  109. package/dist/src/css/ua-defaults/base-defaults.js +10 -1
  110. package/dist/src/css/ua-defaults/element-defaults.js +0 -2
  111. package/dist/src/html/css/parse-css.d.ts +2 -0
  112. package/dist/src/html/css/parse-css.js +32 -3
  113. package/dist/src/html/dom-converter/background-images.d.ts +3 -0
  114. package/dist/src/html/dom-converter/background-images.js +88 -0
  115. package/dist/src/html/dom-converter/convert-dom-node.d.ts +5 -0
  116. package/dist/src/html/dom-converter/convert-dom-node.js +81 -0
  117. package/dist/src/html/dom-converter/handlers/br-handler.d.ts +2 -0
  118. package/dist/src/html/dom-converter/handlers/br-handler.js +20 -0
  119. package/dist/src/html/dom-converter/handlers/form-control-handler.d.ts +2 -0
  120. package/dist/src/html/dom-converter/handlers/form-control-handler.js +28 -0
  121. package/dist/src/html/dom-converter/handlers/img-handler.d.ts +2 -0
  122. package/dist/src/html/dom-converter/handlers/img-handler.js +4 -0
  123. package/dist/src/html/dom-converter/handlers/index.d.ts +4 -0
  124. package/dist/src/html/dom-converter/handlers/index.js +19 -0
  125. package/dist/src/html/dom-converter/handlers/svg-handler.d.ts +2 -0
  126. package/dist/src/html/dom-converter/handlers/svg-handler.js +32 -0
  127. package/dist/src/html/dom-converter/handlers/types.d.ts +12 -0
  128. package/dist/src/html/dom-converter/handlers/types.js +2 -0
  129. package/dist/src/html/dom-converter/helpers.d.ts +7 -0
  130. package/dist/src/html/dom-converter/helpers.js +35 -0
  131. package/dist/src/html/dom-converter/index.d.ts +1 -0
  132. package/dist/src/html/dom-converter/index.js +1 -0
  133. package/dist/src/html/dom-converter/pseudo-elements.d.ts +6 -0
  134. package/dist/src/html/dom-converter/pseudo-elements.js +48 -0
  135. package/dist/src/html/dom-converter/text.d.ts +15 -0
  136. package/dist/src/html/dom-converter/text.js +170 -0
  137. package/dist/src/html/dom-converter.d.ts +1 -5
  138. package/dist/src/html/dom-converter.js +1 -412
  139. package/dist/src/html/image-converter.d.ts +5 -0
  140. package/dist/src/html/image-converter.js +8 -3
  141. package/dist/src/html-to-pdf/document-css.d.ts +14 -0
  142. package/dist/src/html-to-pdf/document-css.js +45 -0
  143. package/dist/src/html-to-pdf/fonts.d.ts +16 -0
  144. package/dist/src/html-to-pdf/fonts.js +74 -0
  145. package/dist/src/html-to-pdf/header-footer.d.ts +14 -0
  146. package/dist/src/html-to-pdf/header-footer.js +101 -0
  147. package/dist/src/html-to-pdf/html-parser.d.ts +6 -0
  148. package/dist/src/html-to-pdf/html-parser.js +81 -0
  149. package/dist/src/html-to-pdf/index.d.ts +3 -0
  150. package/dist/src/html-to-pdf/index.js +2 -0
  151. package/dist/src/html-to-pdf/layout-build.d.ts +37 -0
  152. package/dist/src/html-to-pdf/layout-build.js +73 -0
  153. package/dist/src/html-to-pdf/prepare-html-render.d.ts +2 -0
  154. package/dist/src/html-to-pdf/prepare-html-render.js +121 -0
  155. package/dist/src/html-to-pdf/render-finalize.d.ts +15 -0
  156. package/dist/src/html-to-pdf/render-finalize.js +27 -0
  157. package/dist/src/html-to-pdf/render-html-to-pdf.d.ts +3 -0
  158. package/dist/src/html-to-pdf/render-html-to-pdf.js +25 -0
  159. package/dist/src/html-to-pdf/resource-loader.d.ts +6 -0
  160. package/dist/src/html-to-pdf/resource-loader.js +120 -0
  161. package/dist/src/html-to-pdf/types.d.ts +38 -0
  162. package/dist/src/html-to-pdf/types.js +2 -0
  163. package/dist/src/html-to-pdf.d.ts +1 -37
  164. package/dist/src/html-to-pdf.js +1 -537
  165. package/dist/src/image/js-png-backend.d.ts +7 -0
  166. package/dist/src/image/js-png-backend.js +9 -0
  167. package/dist/src/image/png-backend.d.ts +5 -0
  168. package/dist/src/image/png-backend.js +1 -0
  169. package/dist/src/image/png-wasm-loader.d.ts +5 -0
  170. package/dist/src/image/png-wasm-loader.js +59 -0
  171. package/dist/src/image/wasm/png_decoder_wasm.d.ts +8 -0
  172. package/dist/src/image/wasm/png_decoder_wasm.js +24 -0
  173. package/dist/src/image/wasm/png_decoder_wasm_bg.js +16 -0
  174. package/dist/src/image/wasm-png-backend.d.ts +6 -0
  175. package/dist/src/image/wasm-png-backend.js +17 -0
  176. package/dist/src/layout/counter.d.ts +1 -2
  177. package/dist/src/layout/counter.js +18 -18
  178. package/dist/src/layout/inline/inline-utils.d.ts +1 -1
  179. package/dist/src/layout/inline/inline-utils.js +8 -7
  180. package/dist/src/layout/inline/layout.js +16 -3
  181. package/dist/src/layout/inline/run-placer.d.ts +1 -0
  182. package/dist/src/layout/inline/run-placer.js +2 -10
  183. package/dist/src/layout/pipeline/out-of-flow-manager.js +25 -1
  184. package/dist/src/layout/strategies/block.js +35 -24
  185. package/dist/src/layout/strategies/flex.js +305 -61
  186. package/dist/src/layout/strategies/form.d.ts +2 -0
  187. package/dist/src/layout/strategies/form.js +38 -13
  188. package/dist/src/layout/strategies/grid.js +166 -29
  189. package/dist/src/layout/strategies/image.js +53 -27
  190. package/dist/src/layout/strategies/inline.js +26 -21
  191. package/dist/src/layout/strategies/table.js +26 -18
  192. package/dist/src/layout/utils/content-measurer.d.ts +1 -1
  193. package/dist/src/layout/utils/content-measurer.js +8 -7
  194. package/dist/src/layout/utils/floats.d.ts +1 -0
  195. package/dist/src/layout/utils/floats.js +14 -12
  196. package/dist/src/layout/utils/margin.d.ts +4 -4
  197. package/dist/src/layout/utils/margin.js +20 -16
  198. package/dist/src/layout/utils/node-math.d.ts +12 -6
  199. package/dist/src/layout/utils/node-math.js +71 -41
  200. package/dist/src/layout/utils/sizing.js +2 -1
  201. package/dist/src/pdf/font-subset/font-registry.d.ts +6 -0
  202. package/dist/src/pdf/font-subset/font-registry.js +30 -2
  203. package/dist/src/pdf/header-footer-painter.d.ts +2 -0
  204. package/dist/src/pdf/header-footer-painter.js +52 -4
  205. package/dist/src/pdf/header-footer-renderer.js +12 -1
  206. package/dist/src/pdf/layout-tree-builder.js +5 -1
  207. package/dist/src/pdf/page-painter.js +13 -0
  208. package/dist/src/pdf/pagination.js +2 -2
  209. package/dist/src/pdf/renderer/box-painter.js +28 -3
  210. package/dist/src/pdf/renderer/page-paint.js +12 -3
  211. package/dist/src/pdf/renderers/radius-utils.js +31 -38
  212. package/dist/src/pdf/renderers/shape-renderer.js +1 -1
  213. package/dist/src/pdf/renderers/shape-utils.js +1 -1
  214. package/dist/src/pdf/renderers/text-renderer.d.ts +9 -1
  215. package/dist/src/pdf/renderers/text-renderer.js +36 -2
  216. package/dist/src/pdf/stacking/build-stacking-contexts.js +1 -2
  217. package/dist/src/pdf/stacking/resolve-paint-order.d.ts +5 -6
  218. package/dist/src/pdf/stacking/resolve-paint-order.js +29 -9
  219. package/dist/src/pdf/stacking/types.d.ts +14 -0
  220. package/dist/src/pdf/svg/shape-renderer.js +47 -20
  221. package/dist/src/pdf/types.d.ts +7 -1
  222. package/dist/src/pdf/utils/border-radius-utils.js +31 -38
  223. package/dist/src/pdf/utils/color-utils.js +17 -2
  224. package/dist/src/pdf/utils/filter-utils.d.ts +29 -0
  225. package/dist/src/pdf/utils/filter-utils.js +85 -0
  226. package/dist/src/pdf/utils/node-text-run-factory.js +1 -1
  227. package/dist/src/pdf/utils/text-layout-adjuster.d.ts +0 -8
  228. package/dist/src/pdf/utils/text-layout-adjuster.js +12 -9
  229. package/dist/src/shim/css-browser.d.ts +14 -9
  230. package/dist/src/shim/css-browser.js +50 -39
  231. package/dist/src/units/units.d.ts +1 -1
  232. package/dist/tests/css/box-sizing.spec.d.ts +1 -0
  233. package/dist/tests/css/box-sizing.spec.js +46 -0
  234. package/dist/tests/css/calc-parser.spec.d.ts +1 -0
  235. package/dist/tests/css/calc-parser.spec.js +68 -0
  236. package/dist/tests/css/container-query-units.spec.d.ts +1 -0
  237. package/dist/tests/css/container-query-units.spec.js +64 -0
  238. package/dist/tests/css/content-parser.spec.js +13 -0
  239. package/dist/tests/css/filter-parser.spec.d.ts +1 -0
  240. package/dist/tests/css/filter-parser.spec.js +116 -0
  241. package/dist/tests/css/flex-shorthand.spec.d.ts +1 -0
  242. package/dist/tests/css/flex-shorthand.spec.js +45 -0
  243. package/dist/tests/css/grid-clamp.spec.d.ts +1 -0
  244. package/dist/tests/css/grid-clamp.spec.js +82 -0
  245. package/dist/tests/css/parse-css-pseudo.spec.d.ts +1 -0
  246. package/dist/tests/css/parse-css-pseudo.spec.js +26 -0
  247. package/dist/tests/helpers/render-utils.d.ts +18 -2
  248. package/dist/tests/helpers/render-utils.js +25 -12
  249. package/dist/tests/html/dom-converter-pseudo-elements.spec.d.ts +1 -0
  250. package/dist/tests/html/dom-converter-pseudo-elements.spec.js +33 -0
  251. package/dist/tests/html/dom-converter-text.spec.d.ts +1 -0
  252. package/dist/tests/html/dom-converter-text.spec.js +67 -0
  253. package/dist/tests/image/png-backend.spec.d.ts +1 -0
  254. package/dist/tests/image/png-backend.spec.js +34 -0
  255. package/dist/tests/layout/box-sizing.spec.d.ts +1 -0
  256. package/dist/tests/layout/box-sizing.spec.js +75 -0
  257. package/dist/tests/layout/calc-padding.spec.d.ts +1 -0
  258. package/dist/tests/layout/calc-padding.spec.js +19 -0
  259. package/dist/tests/layout/container-query-units.spec.d.ts +1 -0
  260. package/dist/tests/layout/container-query-units.spec.js +24 -0
  261. package/dist/tests/layout/flex-auto-height.spec.d.ts +1 -0
  262. package/dist/tests/layout/flex-auto-height.spec.js +35 -0
  263. package/dist/tests/layout/flex-wrap-cards.spec.d.ts +1 -0
  264. package/dist/tests/layout/flex-wrap-cards.spec.js +16 -0
  265. package/dist/tests/layout/flex-wrap-grow-align-content.spec.d.ts +1 -0
  266. package/dist/tests/layout/flex-wrap-grow-align-content.spec.js +20 -0
  267. package/dist/tests/layout/grid-clamp-gap.spec.d.ts +1 -0
  268. package/dist/tests/layout/grid-clamp-gap.spec.js +22 -0
  269. package/dist/tests/layout/inline-fragments.spec.js +38 -0
  270. package/dist/tests/layout/paged-body-margin.spec.d.ts +1 -0
  271. package/dist/tests/layout/paged-body-margin.spec.js +92 -0
  272. package/dist/tests/layout/pseudo-counters-generated-content.spec.d.ts +1 -0
  273. package/dist/tests/layout/pseudo-counters-generated-content.spec.js +51 -0
  274. package/dist/tests/layout/responsive-clamp-grid-parity.spec.d.ts +1 -0
  275. package/dist/tests/layout/responsive-clamp-grid-parity.spec.js +75 -0
  276. package/dist/tests/layout/run-placer-baseline.spec.js +13 -11
  277. package/dist/tests/pdf/backdrop-filter-noop.spec.d.ts +1 -0
  278. package/dist/tests/pdf/backdrop-filter-noop.spec.js +140 -0
  279. package/dist/tests/pdf/filter-drop-shadow.spec.d.ts +1 -0
  280. package/dist/tests/pdf/filter-drop-shadow.spec.js +74 -0
  281. package/dist/tests/pdf/filter-opacity.spec.d.ts +1 -0
  282. package/dist/tests/pdf/filter-opacity.spec.js +30 -0
  283. package/dist/tests/pdf/font-subset-registry-key.spec.d.ts +1 -0
  284. package/dist/tests/pdf/font-subset-registry-key.spec.js +66 -0
  285. package/dist/tests/pdf/header-footer-clip-overflow.spec.d.ts +1 -0
  286. package/dist/tests/pdf/header-footer-clip-overflow.spec.js +45 -0
  287. package/dist/tests/pdf/selawik-opt-in.spec.d.ts +1 -0
  288. package/dist/tests/pdf/selawik-opt-in.spec.js +106 -0
  289. package/dist/tests/pdf/system-ui-fallback-subset-regression.spec.d.ts +1 -0
  290. package/dist/tests/pdf/system-ui-fallback-subset-regression.spec.js +39 -0
  291. package/dist/tests/pdf/text-renderer-fallback.spec.js +55 -0
  292. package/dist/tests/pdf/text-transform-matrix.spec.js +8 -7
  293. package/package.json +2 -2
@@ -28,7 +28,8 @@ export class ContentMeasurer {
28
28
  * @param contentStartX - The X coordinate where content area begins
29
29
  * @returns Object containing the measured width and any left offset
30
30
  */
31
- measureInFlowWidth(node, referenceWidth, contentStartX) {
31
+ measureInFlowWidth(node, referenceWidth, contentStartX, containerHeight = referenceWidth) {
32
+ const containerRefs = { containerWidth: referenceWidth, containerHeight };
32
33
  let minStart = Number.POSITIVE_INFINITY;
33
34
  let maxEnd = Number.NEGATIVE_INFINITY;
34
35
  let hasContent = false;
@@ -41,14 +42,14 @@ export class ContentMeasurer {
41
42
  }
42
43
  const marginLeft = child.box.usedMarginLeft !== undefined
43
44
  ? child.box.usedMarginLeft
44
- : resolveLength(child.style.marginLeft, referenceWidth, { auto: "zero" });
45
+ : resolveLength(child.style.marginLeft, referenceWidth, { auto: "zero", ...containerRefs });
45
46
  const marginRight = child.box.usedMarginRight !== undefined
46
47
  ? child.box.usedMarginRight
47
- : resolveLength(child.style.marginRight, referenceWidth, { auto: "zero" });
48
- const borderLeft = resolveLength(child.style.borderLeft, referenceWidth, { auto: "zero" });
49
- const borderRight = resolveLength(child.style.borderRight, referenceWidth, { auto: "zero" });
50
- const paddingLeft = resolveLength(child.style.paddingLeft, referenceWidth, { auto: "zero" });
51
- const paddingRight = resolveLength(child.style.paddingRight, referenceWidth, { auto: "zero" });
48
+ : resolveLength(child.style.marginRight, referenceWidth, { auto: "zero", ...containerRefs });
49
+ const borderLeft = resolveLength(child.style.borderLeft, referenceWidth, { auto: "zero", ...containerRefs });
50
+ const borderRight = resolveLength(child.style.borderRight, referenceWidth, { auto: "zero", ...containerRefs });
51
+ const paddingLeft = resolveLength(child.style.paddingLeft, referenceWidth, { auto: "zero", ...containerRefs });
52
+ const paddingRight = resolveLength(child.style.paddingRight, referenceWidth, { auto: "zero", ...containerRefs });
52
53
  const borderBoxWidth = child.box.borderBoxWidth || Math.max(0, child.box.contentWidth + paddingLeft + paddingRight + borderLeft + borderRight);
53
54
  const marginBoxWidth = borderBoxWidth + marginLeft + marginRight;
54
55
  const marginStart = child.box.x - paddingLeft - borderLeft - marginLeft;
@@ -7,6 +7,7 @@ interface FloatPlacementOptions {
7
7
  context: LayoutContext;
8
8
  contentX: number;
9
9
  contentWidth: number;
10
+ contentHeight?: number;
10
11
  startY: number;
11
12
  }
12
13
  export declare function clearForBlock(node: LayoutNode, floatContext: FloatContext, yCursor: number): number;
@@ -15,19 +15,21 @@ export function clearForBlock(node, floatContext, yCursor) {
15
15
  }
16
16
  export function placeFloat(options) {
17
17
  const { node, floatContext, context, contentX, contentWidth } = options;
18
+ const contentHeight = options.contentHeight ?? contentWidth;
19
+ const containerRefs = { containerWidth: contentWidth, containerHeight: contentHeight };
18
20
  context.layoutChild(node);
19
- const marginLeft = resolveLength(node.style.marginLeft, contentWidth, { auto: "zero" });
20
- const marginRight = resolveLength(node.style.marginRight, contentWidth, { auto: "zero" });
21
- const marginTop = resolveLength(node.style.marginTop, contentWidth, { auto: "zero" });
22
- const marginBottom = resolveLength(node.style.marginBottom, contentWidth, { auto: "zero" });
23
- const borderLeft = resolveLength(node.style.borderLeft, contentWidth, { auto: "zero" });
24
- const borderRight = resolveLength(node.style.borderRight, contentWidth, { auto: "zero" });
25
- const borderTop = resolveLength(node.style.borderTop, contentWidth, { auto: "zero" });
26
- const borderBottom = resolveLength(node.style.borderBottom, contentWidth, { auto: "zero" });
27
- const paddingLeft = resolveLength(node.style.paddingLeft, contentWidth, { auto: "zero" });
28
- const paddingRight = resolveLength(node.style.paddingRight, contentWidth, { auto: "zero" });
29
- const paddingTop = resolveLength(node.style.paddingTop, contentWidth, { auto: "zero" });
30
- const paddingBottom = resolveLength(node.style.paddingBottom, contentWidth, { auto: "zero" });
21
+ const marginLeft = resolveLength(node.style.marginLeft, contentWidth, { auto: "zero", ...containerRefs });
22
+ const marginRight = resolveLength(node.style.marginRight, contentWidth, { auto: "zero", ...containerRefs });
23
+ const marginTop = resolveLength(node.style.marginTop, contentHeight, { auto: "zero", ...containerRefs });
24
+ const marginBottom = resolveLength(node.style.marginBottom, contentHeight, { auto: "zero", ...containerRefs });
25
+ const borderLeft = resolveLength(node.style.borderLeft, contentWidth, { auto: "zero", ...containerRefs });
26
+ const borderRight = resolveLength(node.style.borderRight, contentWidth, { auto: "zero", ...containerRefs });
27
+ const borderTop = resolveLength(node.style.borderTop, contentHeight, { auto: "zero", ...containerRefs });
28
+ const borderBottom = resolveLength(node.style.borderBottom, contentHeight, { auto: "zero", ...containerRefs });
29
+ const paddingLeft = resolveLength(node.style.paddingLeft, contentWidth, { auto: "zero", ...containerRefs });
30
+ const paddingRight = resolveLength(node.style.paddingRight, contentWidth, { auto: "zero", ...containerRefs });
31
+ const paddingTop = resolveLength(node.style.paddingTop, contentHeight, { auto: "zero", ...containerRefs });
32
+ const paddingBottom = resolveLength(node.style.paddingBottom, contentHeight, { auto: "zero", ...containerRefs });
31
33
  const borderBoxWidth = node.box.contentWidth + paddingLeft + paddingRight + borderLeft + borderRight;
32
34
  const borderBoxHeight = node.box.contentHeight + paddingTop + paddingBottom + borderTop + borderBottom;
33
35
  node.box.borderBoxWidth = borderBoxWidth;
@@ -3,7 +3,7 @@ export declare function collapseMarginSet(margins: readonly number[]): number;
3
3
  export declare function collapsedGapBetween(prevBottomMargin: number, nextTopMargin: number, parentEstablishesBfc: boolean): number;
4
4
  export declare function findFirstMarginCollapsibleChild(node: LayoutNode): LayoutNode | undefined;
5
5
  export declare function findLastMarginCollapsibleChild(node: LayoutNode): LayoutNode | undefined;
6
- export declare function canCollapseMarginStart(node: LayoutNode, containingBlockWidth: number): boolean;
7
- export declare function canCollapseMarginEnd(node: LayoutNode, containingBlockWidth: number): boolean;
8
- export declare function effectiveMarginTop(node: LayoutNode, containingBlockWidth: number): number;
9
- export declare function effectiveMarginBottom(node: LayoutNode, containingBlockWidth: number): number;
6
+ export declare function canCollapseMarginStart(node: LayoutNode, containingBlockWidth: number, containingBlockHeight?: number): boolean;
7
+ export declare function canCollapseMarginEnd(node: LayoutNode, containingBlockWidth: number, containingBlockHeight?: number): boolean;
8
+ export declare function effectiveMarginTop(node: LayoutNode, containingBlockWidth: number, containingBlockHeight?: number): number;
9
+ export declare function effectiveMarginBottom(node: LayoutNode, containingBlockWidth: number, containingBlockHeight?: number): number;
@@ -68,57 +68,61 @@ export function findLastMarginCollapsibleChild(node) {
68
68
  }
69
69
  return undefined;
70
70
  }
71
- export function canCollapseMarginStart(node, containingBlockWidth) {
71
+ export function canCollapseMarginStart(node, containingBlockWidth, containingBlockHeight = containingBlockWidth) {
72
72
  if (!isBlockLevel(node) || establishesBFC(node)) {
73
73
  return false;
74
74
  }
75
- const paddingTop = resolveLength(node.style.paddingTop, containingBlockWidth, { auto: "zero" });
76
- const borderTop = resolveLength(node.style.borderTop, containingBlockWidth, { auto: "zero" });
75
+ const containerRefs = { containerWidth: containingBlockWidth, containerHeight: containingBlockHeight };
76
+ const paddingTop = resolveLength(node.style.paddingTop, containingBlockHeight, { auto: "zero", ...containerRefs });
77
+ const borderTop = resolveLength(node.style.borderTop, containingBlockHeight, { auto: "zero", ...containerRefs });
77
78
  if (!isApproximatelyZero(paddingTop) || !isApproximatelyZero(borderTop)) {
78
79
  return false;
79
80
  }
80
81
  return findFirstMarginCollapsibleChild(node) !== undefined;
81
82
  }
82
- export function canCollapseMarginEnd(node, containingBlockWidth) {
83
+ export function canCollapseMarginEnd(node, containingBlockWidth, containingBlockHeight = containingBlockWidth) {
83
84
  if (!isBlockLevel(node) || establishesBFC(node)) {
84
85
  return false;
85
86
  }
86
- const paddingBottom = resolveLength(node.style.paddingBottom, containingBlockWidth, { auto: "zero" });
87
- const borderBottom = resolveLength(node.style.borderBottom, containingBlockWidth, { auto: "zero" });
87
+ const containerRefs = { containerWidth: containingBlockWidth, containerHeight: containingBlockHeight };
88
+ const paddingBottom = resolveLength(node.style.paddingBottom, containingBlockHeight, { auto: "zero", ...containerRefs });
89
+ const borderBottom = resolveLength(node.style.borderBottom, containingBlockHeight, { auto: "zero", ...containerRefs });
88
90
  if (!isApproximatelyZero(paddingBottom) || !isApproximatelyZero(borderBottom)) {
89
91
  return false;
90
92
  }
91
93
  return findLastMarginCollapsibleChild(node) !== undefined;
92
94
  }
93
- export function effectiveMarginTop(node, containingBlockWidth) {
94
- const ownMargin = resolveLength(node.style.marginTop, containingBlockWidth, { auto: "zero" });
95
+ export function effectiveMarginTop(node, containingBlockWidth, containingBlockHeight = containingBlockWidth) {
96
+ const containerRefs = { containerWidth: containingBlockWidth, containerHeight: containingBlockHeight };
97
+ const ownMargin = resolveLength(node.style.marginTop, containingBlockHeight, { auto: "zero", ...containerRefs });
95
98
  if (!isBlockLevel(node)) {
96
99
  return ownMargin;
97
100
  }
98
- if (!canCollapseMarginStart(node, containingBlockWidth)) {
101
+ if (!canCollapseMarginStart(node, containingBlockWidth, containingBlockHeight)) {
99
102
  return ownMargin;
100
103
  }
101
104
  const firstChild = findFirstMarginCollapsibleChild(node);
102
105
  if (!firstChild) {
103
106
  return ownMargin;
104
107
  }
105
- const childContainingWidth = resolveWidthBlock(node, containingBlockWidth);
106
- const childMargin = effectiveMarginTop(firstChild, childContainingWidth);
108
+ const childContainingWidth = resolveWidthBlock(node, containingBlockWidth, containingBlockHeight);
109
+ const childMargin = effectiveMarginTop(firstChild, childContainingWidth, containingBlockHeight);
107
110
  return collapseMarginSet([ownMargin, childMargin]);
108
111
  }
109
- export function effectiveMarginBottom(node, containingBlockWidth) {
110
- const ownMargin = resolveLength(node.style.marginBottom, containingBlockWidth, { auto: "zero" });
112
+ export function effectiveMarginBottom(node, containingBlockWidth, containingBlockHeight = containingBlockWidth) {
113
+ const containerRefs = { containerWidth: containingBlockWidth, containerHeight: containingBlockHeight };
114
+ const ownMargin = resolveLength(node.style.marginBottom, containingBlockHeight, { auto: "zero", ...containerRefs });
111
115
  if (!isBlockLevel(node)) {
112
116
  return ownMargin;
113
117
  }
114
- if (!canCollapseMarginEnd(node, containingBlockWidth)) {
118
+ if (!canCollapseMarginEnd(node, containingBlockWidth, containingBlockHeight)) {
115
119
  return ownMargin;
116
120
  }
117
121
  const lastChild = findLastMarginCollapsibleChild(node);
118
122
  if (!lastChild) {
119
123
  return ownMargin;
120
124
  }
121
- const childContainingWidth = resolveWidthBlock(node, containingBlockWidth);
122
- const childMargin = effectiveMarginBottom(lastChild, childContainingWidth);
125
+ const childContainingWidth = resolveWidthBlock(node, containingBlockWidth, containingBlockHeight);
126
+ const childMargin = effectiveMarginBottom(lastChild, childContainingWidth, containingBlockHeight);
123
127
  return collapseMarginSet([ownMargin, childMargin]);
124
128
  }
@@ -1,4 +1,5 @@
1
1
  import { LayoutNode } from "../../dom/node.js";
2
+ import { BoxSizing } from "../../css/enums.js";
2
3
  import { type LengthLike } from "../../css/length.js";
3
4
  import type { ContainingBlock, Viewport } from "../../geometry/box.js";
4
5
  export interface BoxMetrics {
@@ -14,16 +15,21 @@ export interface BoxMetrics {
14
15
  contentBoxY: number;
15
16
  }
16
17
  export declare function resolveBoxMetrics(node: LayoutNode, widthRef: number, heightRef: number): BoxMetrics;
17
- export declare function horizontalNonContent(node: LayoutNode, reference: number): number;
18
- export declare function verticalNonContent(node: LayoutNode, reference: number): number;
19
- export declare function horizontalMargin(node: LayoutNode, reference: number): number;
20
- export declare function verticalMargin(node: LayoutNode, reference: number): number;
18
+ export declare function adjustForBoxSizing(specifiedSize: number, boxSizing: BoxSizing, nonContentExtras: number): number;
19
+ export declare function horizontalNonContent(node: LayoutNode, reference: number, containerHeight?: number): number;
20
+ export declare function verticalNonContent(node: LayoutNode, reference: number, containerWidth?: number): number;
21
+ export declare function horizontalMargin(node: LayoutNode, reference: number, containerHeight?: number): number;
22
+ export declare function verticalMargin(node: LayoutNode, reference: number, containerWidth?: number): number;
21
23
  export declare function inFlow(node: LayoutNode): boolean;
22
24
  export declare function establishesBFC(node: LayoutNode): boolean;
23
25
  export declare function nearestPositionedAncestor(node: LayoutNode): LayoutNode | null;
24
26
  export declare function containingBlock(node: LayoutNode, viewport: Viewport): ContainingBlock;
25
- export declare function resolveWidthBlock(node: LayoutNode, containingBlockWidth: number): number;
26
- export declare function resolveBlockAutoMargins(containingBlockWidth: number, borderBoxWidth: number, marginLeft: LengthLike, marginRight: LengthLike): {
27
+ export declare function resolveWidthBlock(node: LayoutNode, containingBlockWidth: number, containingBlockHeight?: number): number;
28
+ export declare function resolveBlockAutoMargins(containingBlockWidth: number, borderBoxWidth: number, marginLeft: LengthLike, marginRight: LengthLike, containingBlockHeight?: number): {
27
29
  marginLeft: number;
28
30
  marginRight: number;
29
31
  };
32
+ export declare function applyMinHeight(contentHeight: number, node: LayoutNode, heightRef: number, verticalExtras: number, containerRefs: {
33
+ containerWidth: number;
34
+ containerHeight: number;
35
+ }): number;
@@ -1,16 +1,17 @@
1
1
  import { LayoutNode } from "../../dom/node.js";
2
- import { Display, FloatMode, OverflowMode, Position } from "../../css/enums.js";
2
+ import { BoxSizing, Display, FloatMode, OverflowMode, Position } from "../../css/enums.js";
3
3
  import { clampMinMax, resolveLength, isAutoLength } from "../../css/length.js";
4
4
  export function resolveBoxMetrics(node, widthRef, heightRef) {
5
5
  const { style } = node;
6
- const paddingLeft = resolveLength(style.paddingLeft, widthRef, { auto: "zero" });
7
- const paddingRight = resolveLength(style.paddingRight, widthRef, { auto: "zero" });
8
- const paddingTop = resolveLength(style.paddingTop, heightRef, { auto: "zero" });
9
- const paddingBottom = resolveLength(style.paddingBottom, heightRef, { auto: "zero" });
10
- const borderLeft = resolveLength(style.borderLeft, widthRef, { auto: "zero" });
11
- const borderRight = resolveLength(style.borderRight, widthRef, { auto: "zero" });
12
- const borderTop = resolveLength(style.borderTop, heightRef, { auto: "zero" });
13
- const borderBottom = resolveLength(style.borderBottom, heightRef, { auto: "zero" });
6
+ const containerRefs = { containerWidth: widthRef, containerHeight: heightRef };
7
+ const paddingLeft = resolveLength(style.paddingLeft, widthRef, { auto: "zero", ...containerRefs });
8
+ const paddingRight = resolveLength(style.paddingRight, widthRef, { auto: "zero", ...containerRefs });
9
+ const paddingTop = resolveLength(style.paddingTop, heightRef, { auto: "zero", ...containerRefs });
10
+ const paddingBottom = resolveLength(style.paddingBottom, heightRef, { auto: "zero", ...containerRefs });
11
+ const borderLeft = resolveLength(style.borderLeft, widthRef, { auto: "zero", ...containerRefs });
12
+ const borderRight = resolveLength(style.borderRight, widthRef, { auto: "zero", ...containerRefs });
13
+ const borderTop = resolveLength(style.borderTop, heightRef, { auto: "zero", ...containerRefs });
14
+ const borderBottom = resolveLength(style.borderBottom, heightRef, { auto: "zero", ...containerRefs });
14
15
  return {
15
16
  paddingLeft,
16
17
  paddingRight,
@@ -24,27 +25,39 @@ export function resolveBoxMetrics(node, widthRef, heightRef) {
24
25
  contentBoxY: node.box.y + borderTop + paddingTop,
25
26
  };
26
27
  }
27
- export function horizontalNonContent(node, reference) {
28
+ export function adjustForBoxSizing(specifiedSize, boxSizing, nonContentExtras) {
29
+ if (boxSizing === BoxSizing.BorderBox) {
30
+ return Math.max(0, specifiedSize - nonContentExtras);
31
+ }
32
+ return specifiedSize;
33
+ }
34
+ export function horizontalNonContent(node, reference, containerHeight = reference) {
28
35
  const { style } = node;
29
- return (resolveLength(style.paddingLeft, reference, { auto: "zero" }) +
30
- resolveLength(style.paddingRight, reference, { auto: "zero" }) +
31
- resolveLength(style.borderLeft, reference, { auto: "zero" }) +
32
- resolveLength(style.borderRight, reference, { auto: "zero" }));
36
+ const containerRefs = { containerWidth: reference, containerHeight };
37
+ return (resolveLength(style.paddingLeft, reference, { auto: "zero", ...containerRefs }) +
38
+ resolveLength(style.paddingRight, reference, { auto: "zero", ...containerRefs }) +
39
+ resolveLength(style.borderLeft, reference, { auto: "zero", ...containerRefs }) +
40
+ resolveLength(style.borderRight, reference, { auto: "zero", ...containerRefs }));
33
41
  }
34
- export function verticalNonContent(node, reference) {
42
+ export function verticalNonContent(node, reference, containerWidth = reference) {
35
43
  const { style } = node;
36
- return (resolveLength(style.paddingTop, reference, { auto: "zero" }) +
37
- resolveLength(style.paddingBottom, reference, { auto: "zero" }) +
38
- resolveLength(style.borderTop, reference, { auto: "zero" }) +
39
- resolveLength(style.borderBottom, reference, { auto: "zero" }));
44
+ const containerRefs = { containerWidth, containerHeight: reference };
45
+ return (resolveLength(style.paddingTop, reference, { auto: "zero", ...containerRefs }) +
46
+ resolveLength(style.paddingBottom, reference, { auto: "zero", ...containerRefs }) +
47
+ resolveLength(style.borderTop, reference, { auto: "zero", ...containerRefs }) +
48
+ resolveLength(style.borderBottom, reference, { auto: "zero", ...containerRefs }));
40
49
  }
41
- export function horizontalMargin(node, reference) {
50
+ export function horizontalMargin(node, reference, containerHeight = reference) {
42
51
  const { style } = node;
43
- return resolveLength(style.marginLeft, reference, { auto: "zero" }) + resolveLength(style.marginRight, reference, { auto: "zero" });
52
+ const containerRefs = { containerWidth: reference, containerHeight };
53
+ return (resolveLength(style.marginLeft, reference, { auto: "zero", ...containerRefs }) +
54
+ resolveLength(style.marginRight, reference, { auto: "zero", ...containerRefs }));
44
55
  }
45
- export function verticalMargin(node, reference) {
56
+ export function verticalMargin(node, reference, containerWidth = reference) {
46
57
  const { style } = node;
47
- return resolveLength(style.marginTop, reference, { auto: "zero" }) + resolveLength(style.marginBottom, reference, { auto: "zero" });
58
+ const containerRefs = { containerWidth, containerHeight: reference };
59
+ return (resolveLength(style.marginTop, reference, { auto: "zero", ...containerRefs }) +
60
+ resolveLength(style.marginBottom, reference, { auto: "zero", ...containerRefs }));
48
61
  }
49
62
  export function inFlow(node) {
50
63
  const { position, float: floatMode } = node.style;
@@ -109,17 +122,22 @@ export function containingBlock(node, viewport) {
109
122
  // This allows percentage heights like `height: 100%` on flex children
110
123
  // to resolve against a definite containing block height instead of 0.
111
124
  if (heightRef === 0 && parent.style.height !== "auto") {
112
- const explicitHeight = resolveLength(parent.style.height, viewport.height, { auto: "reference" });
125
+ const explicitHeight = resolveLength(parent.style.height, viewport.height, {
126
+ auto: "reference",
127
+ containerWidth: viewport.width,
128
+ containerHeight: viewport.height,
129
+ });
113
130
  if (Number.isFinite(explicitHeight) && explicitHeight > 0) {
114
131
  heightRef = explicitHeight;
115
132
  }
116
133
  }
134
+ const containerRefs = { containerWidth: widthRef, containerHeight: heightRef };
117
135
  const xOffset = parent.box.x +
118
- resolveLength(parent.style.paddingLeft, widthRef, { auto: "zero" }) +
119
- resolveLength(parent.style.borderLeft, widthRef, { auto: "zero" });
136
+ resolveLength(parent.style.paddingLeft, widthRef, { auto: "zero", ...containerRefs }) +
137
+ resolveLength(parent.style.borderLeft, widthRef, { auto: "zero", ...containerRefs });
120
138
  const yOffset = parent.box.y +
121
- resolveLength(parent.style.paddingTop, heightRef, { auto: "zero" }) +
122
- resolveLength(parent.style.borderTop, heightRef, { auto: "zero" });
139
+ resolveLength(parent.style.paddingTop, heightRef, { auto: "zero", ...containerRefs }) +
140
+ resolveLength(parent.style.borderTop, heightRef, { auto: "zero", ...containerRefs });
123
141
  return {
124
142
  x: xOffset,
125
143
  y: yOffset,
@@ -127,29 +145,34 @@ export function containingBlock(node, viewport) {
127
145
  height: heightRef,
128
146
  };
129
147
  }
130
- export function resolveWidthBlock(node, containingBlockWidth) {
148
+ export function resolveWidthBlock(node, containingBlockWidth, containingBlockHeight = containingBlockWidth) {
131
149
  const style = node.style;
150
+ const containerRefs = { containerWidth: containingBlockWidth, containerHeight: containingBlockHeight };
151
+ const hNonContent = horizontalNonContent(node, containingBlockWidth, containingBlockHeight);
132
152
  const marginLeft = isAutoLength(style.marginLeft)
133
153
  ? 0
134
- : resolveLength(style.marginLeft, containingBlockWidth, { auto: "zero" });
154
+ : resolveLength(style.marginLeft, containingBlockWidth, { auto: "zero", ...containerRefs });
135
155
  const marginRight = isAutoLength(style.marginRight)
136
156
  ? 0
137
- : resolveLength(style.marginRight, containingBlockWidth, { auto: "zero" });
138
- const available = Math.max(0, containingBlockWidth - horizontalNonContent(node, containingBlockWidth) - marginLeft - marginRight);
139
- const width = style.width === "auto"
157
+ : resolveLength(style.marginRight, containingBlockWidth, { auto: "zero", ...containerRefs });
158
+ const available = Math.max(0, containingBlockWidth - hNonContent - marginLeft - marginRight);
159
+ const width = style.width === undefined || isAutoLength(style.width)
140
160
  ? available
141
- : resolveLength(style.width, containingBlockWidth, {
142
- auto: "reference",
143
- });
144
- const minWidth = style.minWidth ? resolveLength(style.minWidth, containingBlockWidth, { auto: "zero" }) : Number.NEGATIVE_INFINITY;
145
- const maxWidth = style.maxWidth ? resolveLength(style.maxWidth, containingBlockWidth, { auto: "reference" }) : Number.POSITIVE_INFINITY;
161
+ : adjustForBoxSizing(resolveLength(style.width, containingBlockWidth, { auto: "reference", ...containerRefs }), style.boxSizing, hNonContent);
162
+ const minWidth = style.minWidth
163
+ ? adjustForBoxSizing(resolveLength(style.minWidth, containingBlockWidth, { auto: "zero", ...containerRefs }), style.boxSizing, hNonContent)
164
+ : Number.NEGATIVE_INFINITY;
165
+ const maxWidth = style.maxWidth
166
+ ? adjustForBoxSizing(resolveLength(style.maxWidth, containingBlockWidth, { auto: "reference", ...containerRefs }), style.boxSizing, hNonContent)
167
+ : Number.POSITIVE_INFINITY;
146
168
  return clampMinMax(width, minWidth, maxWidth);
147
169
  }
148
- export function resolveBlockAutoMargins(containingBlockWidth, borderBoxWidth, marginLeft, marginRight) {
170
+ export function resolveBlockAutoMargins(containingBlockWidth, borderBoxWidth, marginLeft, marginRight, containingBlockHeight = containingBlockWidth) {
171
+ const containerRefs = { containerWidth: containingBlockWidth, containerHeight: containingBlockHeight };
149
172
  const marginLeftAuto = isAutoLength(marginLeft);
150
173
  const marginRightAuto = isAutoLength(marginRight);
151
- const resolvedMarginLeft = marginLeftAuto ? 0 : resolveLength(marginLeft, containingBlockWidth, { auto: "zero" });
152
- const resolvedMarginRight = marginRightAuto ? 0 : resolveLength(marginRight, containingBlockWidth, { auto: "zero" });
174
+ const resolvedMarginLeft = marginLeftAuto ? 0 : resolveLength(marginLeft, containingBlockWidth, { auto: "zero", ...containerRefs });
175
+ const resolvedMarginRight = marginRightAuto ? 0 : resolveLength(marginRight, containingBlockWidth, { auto: "zero", ...containerRefs });
153
176
  let usedMarginLeft = resolvedMarginLeft;
154
177
  let usedMarginRight = resolvedMarginRight;
155
178
  const remainingSpace = containingBlockWidth - (borderBoxWidth + resolvedMarginLeft + resolvedMarginRight);
@@ -188,3 +211,10 @@ export function resolveBlockAutoMargins(containingBlockWidth, borderBoxWidth, ma
188
211
  }
189
212
  return { marginLeft: usedMarginLeft, marginRight: usedMarginRight };
190
213
  }
214
+ export function applyMinHeight(contentHeight, node, heightRef, verticalExtras, containerRefs) {
215
+ if (node.style.minHeight === undefined || isAutoLength(node.style.minHeight)) {
216
+ return contentHeight;
217
+ }
218
+ const minH = adjustForBoxSizing(resolveLength(node.style.minHeight, heightRef, { auto: "zero", ...containerRefs }), node.style.boxSizing, verticalExtras);
219
+ return Number.isFinite(minH) ? Math.max(contentHeight, minH) : contentHeight;
220
+ }
@@ -1,11 +1,12 @@
1
1
  import { LayoutNode } from "../../dom/node.js";
2
2
  import { resolveLength } from "../../css/length.js";
3
3
  export function shrinkToFitWidth(node, availableWidth) {
4
+ const containerRefs = { containerWidth: availableWidth, containerHeight: availableWidth };
4
5
  if (typeof node.style.width === "number") {
5
6
  return Math.min(node.style.width, availableWidth);
6
7
  }
7
8
  if (node.style.width !== "auto") {
8
- return Math.min(resolveLength(node.style.width, availableWidth), availableWidth);
9
+ return Math.min(resolveLength(node.style.width, availableWidth, { ...containerRefs }), availableWidth);
9
10
  }
10
11
  return availableWidth;
11
12
  }
@@ -17,12 +17,18 @@ export declare class PdfFontRegistry {
17
17
  private readonly glyphUsage;
18
18
  private readonly fonts;
19
19
  private fontCounter;
20
+ private identityCounter;
21
+ private readonly programIdentity;
22
+ private readonly cmapIdentity;
20
23
  constructor(encoding?: "identity" | "sequential");
21
24
  /**
22
25
  * Generates a stable key for a UnifiedFont.
23
26
  * Uses CSS metadata if available, otherwise falls back to a generic key.
24
27
  */
25
28
  private fontKey;
29
+ private resolveProgramToken;
30
+ private resolveCmapToken;
31
+ private identityFor;
26
32
  /**
27
33
  * Registers a GlyphRun, collecting its glyph IDs for later subsetting.
28
34
  */
@@ -12,19 +12,47 @@ export class PdfFontRegistry {
12
12
  this.fonts = new Map();
13
13
  // Counter for generating unique font resource names
14
14
  this.fontCounter = 0;
15
+ this.identityCounter = 0;
16
+ this.programIdentity = new WeakMap();
17
+ this.cmapIdentity = new WeakMap();
15
18
  }
16
19
  /**
17
20
  * Generates a stable key for a UnifiedFont.
18
21
  * Uses CSS metadata if available, otherwise falls back to a generic key.
19
22
  */
20
23
  fontKey(font) {
24
+ const programToken = this.resolveProgramToken(font);
25
+ const cmapToken = this.resolveCmapToken(font);
21
26
  if (font.css) {
22
27
  const { family, weight, style } = font.css;
23
- return `${family}|${weight}|${style}`;
28
+ return `${family}|${weight}|${style}|p:${programToken}|c:${cmapToken}`;
24
29
  }
25
30
  // Fallback: use unitsPerEm and ascender as a fingerprint
26
31
  const { unitsPerEm, ascender } = font.metrics.metrics;
27
- return `_fallback_${unitsPerEm}_${ascender}`;
32
+ return `_fallback_${unitsPerEm}_${ascender}|p:${programToken}|c:${cmapToken}`;
33
+ }
34
+ resolveProgramToken(font) {
35
+ const rawAccessor = font.program.getRawTableData;
36
+ if (rawAccessor) {
37
+ return `raw-${this.identityFor(this.programIdentity, rawAccessor)}`;
38
+ }
39
+ return `shape-${font.program.sourceFormat}-${font.program.unitsPerEm}-${font.program.glyphCount}`;
40
+ }
41
+ resolveCmapToken(font) {
42
+ const cmap = font.metrics.cmap;
43
+ if (cmap) {
44
+ return `map-${this.identityFor(this.cmapIdentity, cmap)}`;
45
+ }
46
+ return `none-${font.program.unitsPerEm}-${font.program.glyphCount}`;
47
+ }
48
+ identityFor(store, key) {
49
+ const existing = store.get(key);
50
+ if (existing !== undefined) {
51
+ return existing;
52
+ }
53
+ const next = ++this.identityCounter;
54
+ store.set(key, next);
55
+ return next;
28
56
  }
29
57
  /**
30
58
  * Registers a GlyphRun, collecting its glyph IDs for later subsetting.
@@ -19,6 +19,8 @@ export interface HeaderFooterPaintContext {
19
19
  fontRegistry: FontRegistry;
20
20
  /** Page offset Y for coordinate transformation */
21
21
  pageOffsetY: number;
22
+ /** Whether header/footer paint should be clipped to max height area */
23
+ clipOverflow?: boolean;
22
24
  /** Optional CSS for header/footer styling */
23
25
  css?: string;
24
26
  /** Platform environment (Node/browser) */
@@ -28,7 +28,7 @@ export async function paintHeaderFooter(painter, header, footer, tokens, pageInd
28
28
  * Renders headers and footers as full HTML through the layout pipeline.
29
29
  */
30
30
  async function paintHeaderFooterWithContext(painter, header, footer, tokens, pageIndex, totalPages, context) {
31
- const { margins, pageWidthPx, pageHeightPx, fontRegistry, pageOffsetY, css, resourceBaseDir, assetRootDir } = context;
31
+ const { margins, pageWidthPx, pageHeightPx, fontRegistry, pageOffsetY, clipOverflow = false, css, resourceBaseDir, assetRootDir } = context;
32
32
  // Calculate content width (page width minus left and right margins)
33
33
  const contentWidthPx = pageWidthPx - margins.left - margins.right;
34
34
  log("layout", "debug", "paintHeaderFooterWithContext", {
@@ -58,8 +58,26 @@ async function paintHeaderFooterWithContext(painter, header, footer, tokens, pag
58
58
  });
59
59
  if (rendered) {
60
60
  log("layout", "debug", "Header rendered successfully", { heightPx: rendered.heightPx });
61
- // Header is positioned at the top margin area
62
- await paintRenderedHeaderFooter(painter, rendered, margins.left, margins.top, fontRegistry, pageOffsetY);
61
+ const headerY = margins.top;
62
+ const shouldClip = clipOverflow && header.maxHeightPx > 0 && contentWidthPx > 0;
63
+ if (shouldClip) {
64
+ const clipPath = buildRectClipPath({
65
+ x: margins.left,
66
+ y: headerY + pageOffsetY,
67
+ width: contentWidthPx,
68
+ height: header.maxHeightPx,
69
+ });
70
+ painter.beginClipPath(clipPath);
71
+ }
72
+ try {
73
+ // Header is positioned at the top margin area
74
+ await paintRenderedHeaderFooter(painter, rendered, margins.left, headerY, fontRegistry, pageOffsetY);
75
+ }
76
+ finally {
77
+ if (shouldClip) {
78
+ painter.endClipPath();
79
+ }
80
+ }
63
81
  }
64
82
  }
65
83
  catch (err) {
@@ -87,7 +105,24 @@ async function paintHeaderFooterWithContext(painter, header, footer, tokens, pag
87
105
  if (rendered) {
88
106
  // Footer is positioned at the bottom of the page
89
107
  const footerY = pageHeightPx - margins.bottom - footer.maxHeightPx;
90
- await paintRenderedHeaderFooter(painter, rendered, margins.left, footerY, fontRegistry, pageOffsetY);
108
+ const shouldClip = clipOverflow && footer.maxHeightPx > 0 && contentWidthPx > 0;
109
+ if (shouldClip) {
110
+ const clipPath = buildRectClipPath({
111
+ x: margins.left,
112
+ y: footerY + pageOffsetY,
113
+ width: contentWidthPx,
114
+ height: footer.maxHeightPx,
115
+ });
116
+ painter.beginClipPath(clipPath);
117
+ }
118
+ try {
119
+ await paintRenderedHeaderFooter(painter, rendered, margins.left, footerY, fontRegistry, pageOffsetY);
120
+ }
121
+ finally {
122
+ if (shouldClip) {
123
+ painter.endClipPath();
124
+ }
125
+ }
91
126
  }
92
127
  }
93
128
  catch (err) {
@@ -125,3 +160,16 @@ function stringify(content) {
125
160
  }
126
161
  return JSON.stringify(content);
127
162
  }
163
+ function buildRectClipPath(rect) {
164
+ const x = rect.x;
165
+ const y = rect.y;
166
+ const right = rect.x + rect.width;
167
+ const bottom = rect.y + rect.height;
168
+ return [
169
+ { type: "moveTo", x, y },
170
+ { type: "lineTo", x: right, y },
171
+ { type: "lineTo", x: right, y: bottom },
172
+ { type: "lineTo", x, y: bottom },
173
+ { type: "closePath" },
174
+ ];
175
+ }
@@ -27,6 +27,7 @@ import { FontRegistryResolver } from "../fonts/font-registry-resolver.js";
27
27
  import { computeGlyphRun, applyWordSpacingToGlyphRun } from "./utils/node-text-run-factory.js";
28
28
  import { paintBoxAtomic } from "./renderer/box-painter.js";
29
29
  import { applyPlaceholders } from "./header-footer-tokens.js";
30
+ import { createCounterContext } from "../layout/counter.js";
30
31
  /**
31
32
  * Renders header or footer HTML into a layout tree.
32
33
  * This uses the same pipeline as the main content for full HTML/CSS support.
@@ -59,7 +60,17 @@ export async function renderHeaderFooterHtml(options) {
59
60
  rootStyle.display = Display.Block;
60
61
  }
61
62
  const rootLayout = new LayoutNode(rootStyle, [], { tagName: rootElement?.tagName?.toLowerCase() });
62
- const conversionContext = { resourceBaseDir: resolvedResourceBase, assetRootDir: resolvedAssetRoot, units, rootFontSize, environment };
63
+ const counterContext = createCounterContext();
64
+ const rootCounterScopeId = counterContext.registerScope(null);
65
+ const conversionContext = {
66
+ resourceBaseDir: resolvedResourceBase,
67
+ assetRootDir: resolvedAssetRoot,
68
+ units,
69
+ rootFontSize,
70
+ environment,
71
+ counterContext,
72
+ rootCounterScopeId,
73
+ };
63
74
  if (rootElement) {
64
75
  for (const child of Array.from(rootElement.childNodes)) {
65
76
  if (child.nodeType === child.ELEMENT_NODE) {
@@ -137,7 +137,9 @@ function convertNode(node, state, inheritedTextGradient) {
137
137
  const background = resolveBackgroundLayers(node, { borderBox, paddingBox, contentBox });
138
138
  const clipPath = resolveClipPath(node, { borderBox, paddingBox, contentBox });
139
139
  const zIndex = typeof node.style.zIndex === "number" ? node.style.zIndex : 0;
140
- const establishesStackingContext = typeof node.style.zIndex === "number" && node.style.position !== Position.Static;
140
+ const establishesStackingContext = typeof node.style.zIndex === "number" && node.style.position !== Position.Static ||
141
+ (node.style.filter !== undefined && node.style.filter.length > 0) ||
142
+ (node.style.backdropFilter !== undefined && node.style.backdropFilter.length > 0);
141
143
  const borderStyle = {
142
144
  top: normalizeBorderStyle(node.style.borderStyleTop),
143
145
  right: normalizeBorderStyle(node.style.borderStyleRight),
@@ -202,6 +204,8 @@ function convertNode(node, state, inheritedTextGradient) {
202
204
  customData,
203
205
  textAlign,
204
206
  transform,
207
+ filter: node.style.filter ? [...node.style.filter] : undefined,
208
+ backdropFilter: node.style.backdropFilter ? [...node.style.backdropFilter] : undefined,
205
209
  };
206
210
  }
207
211
  function normalizeBorderStyle(value) {
@@ -76,9 +76,20 @@ export class PagePainter {
76
76
  }
77
77
  async drawText(text, xPx, yPx, options = { fontSizePt: 10 }) {
78
78
  await this.textRenderer.drawText(text, xPx, yPx, options);
79
+ const cmds = this.textRenderer.flushCommands();
80
+ if (cmds.length > 0) {
81
+ this.shapeRenderer.pushRawCommands(cmds);
82
+ }
79
83
  }
80
84
  async drawTextRun(run) {
81
85
  await this.textRenderer.drawTextRun(run);
86
+ // Immediately move text commands into the shape stream so that
87
+ // text and background operations are interleaved in paint order,
88
+ // preserving correct z-index stacking.
89
+ const cmds = this.textRenderer.flushCommands();
90
+ if (cmds.length > 0) {
91
+ this.shapeRenderer.pushRawCommands(cmds);
92
+ }
82
93
  }
83
94
  fillRoundedRect(rect, radii, paint) {
84
95
  this.shapeRenderer.fillRoundedRect(rect, radii, paint);
@@ -153,9 +164,11 @@ export class PagePainter {
153
164
  }
154
165
  beginTransformScope(transform, rect) {
155
166
  this.transformScopeManager.beginTransformScope(transform, rect);
167
+ this.textRenderer.setTransformContext(rect);
156
168
  }
157
169
  endTransformScope() {
158
170
  this.transformScopeManager.endTransformScope();
171
+ this.textRenderer.clearTransformContext();
159
172
  }
160
173
  result() {
161
174
  // Ensure any atlas pages created by the glyph packer are registered as image resources