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
@@ -1,6 +1,6 @@
1
- import { Display } from "../../css/enums.js";
2
- import { resolveLength } from "../../css/length.js";
3
- import { containingBlock, horizontalMargin, horizontalNonContent, resolveWidthBlock, verticalNonContent, } from "../utils/node-math.js";
1
+ import { AlignItems, BoxSizing, Display } from "../../css/enums.js";
2
+ import { isAutoLength, resolveLength } from "../../css/length.js";
3
+ import { adjustForBoxSizing, applyMinHeight, containingBlock, horizontalMargin, horizontalNonContent, resolveWidthBlock, verticalNonContent, } from "../utils/node-math.js";
4
4
  import { calculateTrackOffsets, calculateTotalGap } from "../utils/gap-calculator.js";
5
5
  function isRepeatTrack(def) {
6
6
  return typeof def === "object" && def !== null && "kind" in def && def.kind === "repeat";
@@ -12,6 +12,8 @@ function trackMinSize(track) {
12
12
  switch (track.kind) {
13
13
  case "fixed":
14
14
  return Math.max(0, track.size);
15
+ case "clamp":
16
+ return Math.max(0, track.min);
15
17
  case "flex":
16
18
  return Math.max(0, track.min ?? 0);
17
19
  case "auto":
@@ -27,6 +29,14 @@ function cloneTrackSize(track) {
27
29
  if (track.kind === "fixed") {
28
30
  return { kind: "fixed", size: track.size };
29
31
  }
32
+ if (track.kind === "clamp") {
33
+ return {
34
+ kind: "clamp",
35
+ min: track.min,
36
+ preferred: track.preferred,
37
+ max: track.max,
38
+ };
39
+ }
30
40
  if (track.kind === "flex") {
31
41
  return {
32
42
  kind: "flex",
@@ -90,6 +100,12 @@ function resolveColumnWidths(tracks, contentWidth, columnGap) {
90
100
  switch (track.kind) {
91
101
  case "fixed":
92
102
  return Math.max(0, track.size);
103
+ case "clamp": {
104
+ const min = Math.max(0, track.min);
105
+ const max = Math.max(min, track.max);
106
+ const preferred = track.preferred;
107
+ return Math.max(min, Math.min(preferred, max));
108
+ }
93
109
  case "flex": {
94
110
  let size = minSizes[index];
95
111
  if (totalFlex > 0 && flexFactors[index] > 0) {
@@ -121,15 +137,16 @@ export class GridLayoutStrategy {
121
137
  }
122
138
  layout(node, context) {
123
139
  const cb = containingBlock(node, context.env.viewport);
124
- const baseContentWidth = resolveWidthBlock(node, cb.width);
140
+ const containerRefs = { containerWidth: cb.width, containerHeight: cb.height };
141
+ const baseContentWidth = resolveWidthBlock(node, cb.width, cb.height);
125
142
  node.box.contentWidth = baseContentWidth;
126
- const horizontalExtras = horizontalNonContent(node, baseContentWidth);
143
+ const horizontalExtras = horizontalNonContent(node, baseContentWidth, cb.height);
127
144
  node.box.borderBoxWidth = baseContentWidth + horizontalExtras;
128
- node.box.marginBoxWidth = node.box.borderBoxWidth + horizontalMargin(node, baseContentWidth);
129
- const paddingLeft = resolveLength(node.style.paddingLeft, baseContentWidth, { auto: "zero" });
130
- const paddingTop = resolveLength(node.style.paddingTop, baseContentWidth, { auto: "zero" });
131
- const borderLeft = resolveLength(node.style.borderLeft, baseContentWidth, { auto: "zero" });
132
- const borderTop = resolveLength(node.style.borderTop, baseContentWidth, { auto: "zero" });
145
+ node.box.marginBoxWidth = node.box.borderBoxWidth + horizontalMargin(node, baseContentWidth, cb.height);
146
+ const paddingLeft = resolveLength(node.style.paddingLeft, baseContentWidth, { auto: "zero", ...containerRefs });
147
+ const paddingTop = resolveLength(node.style.paddingTop, cb.height, { auto: "zero", ...containerRefs });
148
+ const borderLeft = resolveLength(node.style.borderLeft, baseContentWidth, { auto: "zero", ...containerRefs });
149
+ const borderTop = resolveLength(node.style.borderTop, cb.height, { auto: "zero", ...containerRefs });
133
150
  const contentOriginX = node.box.x + borderLeft + paddingLeft;
134
151
  const contentOriginY = node.box.y + borderTop + paddingTop;
135
152
  const columnGap = node.style.columnGap ?? 0;
@@ -141,55 +158,175 @@ export class GridLayoutStrategy {
141
158
  const resolvedContentWidth = columnWidths.length > 0 ? Math.max(baseContentWidth, totalColumnWidth) : baseContentWidth;
142
159
  node.box.contentWidth = resolvedContentWidth;
143
160
  node.box.borderBoxWidth = resolvedContentWidth + horizontalExtras;
144
- node.box.marginBoxWidth = node.box.borderBoxWidth + horizontalMargin(node, resolvedContentWidth);
161
+ node.box.marginBoxWidth = node.box.borderBoxWidth + horizontalMargin(node, resolvedContentWidth, cb.height);
145
162
  const columnOffsets = calculateTrackOffsets(columnWidths, columnGap);
146
- let contentHeight = 0;
163
+ const rows = [];
147
164
  let currentRowTop = contentOriginY;
148
165
  let currentRowHeight = 0;
149
166
  let columnIndex = 0;
150
- let rowCount = 0;
167
+ let currentRowItems = [];
151
168
  for (const child of node.children) {
152
169
  if (child.style.display === Display.None) {
153
170
  continue;
154
171
  }
155
- const columnWidth = columnWidths[columnIndex] ?? columnWidths[columnWidths.length - 1] ?? baseContentWidth;
172
+ const span = Math.min(child.style.gridColumnSpan ?? 1, columnWidths.length);
173
+ // Wrap to next row if the span doesn't fit
174
+ if (columnIndex + span > columnWidths.length) {
175
+ if (currentRowItems.length > 0) {
176
+ rows.push({ items: currentRowItems, height: currentRowHeight });
177
+ currentRowTop += currentRowHeight + rowGap;
178
+ currentRowHeight = 0;
179
+ currentRowItems = [];
180
+ }
181
+ columnIndex = 0;
182
+ }
183
+ // Calculate the total width of spanned columns
184
+ let columnWidth = 0;
185
+ for (let s = 0; s < span; s++) {
186
+ columnWidth += columnWidths[columnIndex + s] ?? 0;
187
+ }
188
+ // Add gap between spanned columns
189
+ if (span > 1) {
190
+ columnWidth += columnGap * (span - 1);
191
+ }
156
192
  const columnX = contentOriginX + (columnOffsets[columnIndex] ?? 0);
157
- child.box.x = columnX;
158
- child.box.y = currentRowTop;
159
193
  const originalContentWidth = node.box.contentWidth;
160
194
  node.box.contentWidth = columnWidth;
161
195
  context.layoutChild(child);
162
196
  node.box.contentWidth = originalContentWidth;
163
- child.box.x = columnX;
164
- child.box.y = currentRowTop;
165
197
  currentRowHeight = Math.max(currentRowHeight, child.box.borderBoxHeight);
166
- columnIndex += 1;
198
+ currentRowItems.push({
199
+ child,
200
+ columnWidth,
201
+ columnX,
202
+ });
203
+ columnIndex += span;
167
204
  if (columnIndex >= columnWidths.length) {
168
- rowCount += 1;
169
- contentHeight += currentRowHeight;
205
+ rows.push({ items: currentRowItems, height: currentRowHeight });
170
206
  currentRowTop += currentRowHeight + rowGap;
171
207
  currentRowHeight = 0;
172
208
  columnIndex = 0;
209
+ currentRowItems = [];
173
210
  }
174
211
  }
175
- if (columnIndex !== 0) {
176
- rowCount += 1;
177
- contentHeight += currentRowHeight;
212
+ if (currentRowItems.length > 0) {
213
+ rows.push({ items: currentRowItems, height: currentRowHeight });
178
214
  }
215
+ const rowCount = rows.length;
216
+ const contentHeight = rows.reduce((sum, row) => sum + row.height, 0);
179
217
  const totalRowGap = calculateTotalGap(rowGap, rowCount);
180
- const verticalExtras = verticalNonContent(node, node.box.contentWidth);
181
- node.box.contentHeight = Math.max(0, contentHeight + totalRowGap);
218
+ const verticalExtras = verticalNonContent(node, cb.height, cb.width);
219
+ let resolvedContentHeight = Math.max(0, contentHeight + totalRowGap);
220
+ if (node.style.height !== "auto" && node.style.height !== undefined) {
221
+ resolvedContentHeight = adjustForBoxSizing(resolveLength(node.style.height, cb.height, { auto: "zero", ...containerRefs }), node.style.boxSizing, verticalExtras);
222
+ }
223
+ resolvedContentHeight = applyMinHeight(resolvedContentHeight, node, cb.height, verticalExtras, containerRefs);
224
+ node.box.contentHeight = Math.max(0, resolvedContentHeight);
182
225
  node.box.borderBoxHeight = node.box.contentHeight + verticalExtras;
183
226
  node.box.marginBoxHeight =
184
227
  node.box.borderBoxHeight +
185
- resolveLength(node.style.marginTop, node.box.contentWidth, { auto: "zero" }) +
186
- resolveLength(node.style.marginBottom, node.box.contentWidth, { auto: "zero" });
228
+ resolveLength(node.style.marginTop, cb.height, { auto: "zero", ...containerRefs }) +
229
+ resolveLength(node.style.marginBottom, cb.height, { auto: "zero", ...containerRefs });
230
+ const stretchedRowHeights = resolveGridAlignContentRows(rows, rowGap, node.box.contentHeight, node.style.alignContent);
231
+ const containerAlignItems = node.style.alignItems ?? AlignItems.Stretch;
232
+ let finalRowTop = contentOriginY;
233
+ for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
234
+ const row = rows[rowIndex];
235
+ const rowHeight = stretchedRowHeights[rowIndex] ?? row.height;
236
+ for (const rowItem of row.items) {
237
+ const child = rowItem.child;
238
+ const finalX = rowItem.columnX;
239
+ const finalY = finalRowTop;
240
+ const prePlaceDx = finalX - child.box.x;
241
+ const prePlaceDy = finalY - child.box.y;
242
+ child.box.x = finalX;
243
+ child.box.y = finalY;
244
+ offsetLayoutSubtree(child, prePlaceDx, prePlaceDy);
245
+ const alignSelf = resolveGridItemAlignment(child, containerAlignItems);
246
+ const autoHeight = child.style.height === undefined || child.style.height === "auto" || isAutoLength(child.style.height);
247
+ if (alignSelf === AlignItems.Stretch && autoHeight) {
248
+ const childContainerRefs = { containerWidth: rowItem.columnWidth, containerHeight: rowHeight };
249
+ const marginTop = resolveLength(child.style.marginTop, rowHeight, { auto: "zero", ...childContainerRefs });
250
+ const marginBottom = resolveLength(child.style.marginBottom, rowHeight, { auto: "zero", ...childContainerRefs });
251
+ const targetBorderBoxHeight = Math.max(0, rowHeight - marginTop - marginBottom);
252
+ const childVerticalExtras = verticalNonContent(child, rowHeight, rowItem.columnWidth);
253
+ const stretchedSpecifiedHeight = child.style.boxSizing === BoxSizing.BorderBox
254
+ ? targetBorderBoxHeight
255
+ : Math.max(0, targetBorderBoxHeight - childVerticalExtras);
256
+ const currentBorderHeight = child.box.borderBoxHeight;
257
+ if (Math.abs(currentBorderHeight - targetBorderBoxHeight) > 0.01) {
258
+ const originalHeight = child.style.height;
259
+ const originalContentWidth = node.box.contentWidth;
260
+ try {
261
+ child.style.height = stretchedSpecifiedHeight;
262
+ child.box.x = finalX;
263
+ child.box.y = finalY;
264
+ node.box.contentWidth = rowItem.columnWidth;
265
+ context.layoutChild(child);
266
+ }
267
+ finally {
268
+ node.box.contentWidth = originalContentWidth;
269
+ child.style.height = originalHeight;
270
+ }
271
+ const relayoutDx = finalX - child.box.x;
272
+ const relayoutDy = finalY - child.box.y;
273
+ child.box.x = finalX;
274
+ child.box.y = finalY;
275
+ offsetLayoutSubtree(child, relayoutDx, relayoutDy);
276
+ }
277
+ }
278
+ }
279
+ finalRowTop += rowHeight;
280
+ if (rowIndex < rows.length - 1) {
281
+ finalRowTop += rowGap;
282
+ }
283
+ }
187
284
  node.box.scrollWidth = Math.max(node.box.contentWidth, totalColumnWidth);
188
285
  node.box.scrollHeight = node.box.contentHeight;
189
286
  if (columnWidths.length === 0) {
190
287
  node.box.contentWidth = baseContentWidth;
191
288
  node.box.borderBoxWidth = node.box.contentWidth + horizontalExtras;
192
- node.box.marginBoxWidth = node.box.borderBoxWidth + horizontalMargin(node, node.box.contentWidth);
289
+ node.box.marginBoxWidth = node.box.borderBoxWidth + horizontalMargin(node, node.box.contentWidth, cb.height);
290
+ }
291
+ }
292
+ }
293
+ function offsetLayoutSubtree(node, deltaX, deltaY) {
294
+ if (deltaX === 0 && deltaY === 0) {
295
+ return;
296
+ }
297
+ node.walk((desc) => {
298
+ if (desc !== node) {
299
+ desc.box.x += deltaX;
300
+ desc.box.y += deltaY;
301
+ }
302
+ desc.box.baseline += deltaY;
303
+ if (desc.inlineRuns && desc.inlineRuns.length > 0) {
304
+ for (const run of desc.inlineRuns) {
305
+ run.startX += deltaX;
306
+ run.baseline += deltaY;
307
+ }
308
+ }
309
+ });
310
+ }
311
+ function resolveGridItemAlignment(child, containerAlign) {
312
+ const alignSelf = child.style.alignSelf;
313
+ if (alignSelf && alignSelf !== "auto") {
314
+ return alignSelf;
315
+ }
316
+ return containerAlign;
317
+ }
318
+ function resolveGridAlignContentRows(rows, rowGap, containerContentHeight, alignContent) {
319
+ const rowHeights = rows.map((row) => row.height);
320
+ if (alignContent !== "stretch") {
321
+ return rowHeights;
322
+ }
323
+ const naturalHeight = rowHeights.reduce((sum, height) => sum + height, 0) + calculateTotalGap(rowGap, rowHeights.length);
324
+ const freeSpace = Math.max(0, containerContentHeight - naturalHeight);
325
+ if (freeSpace > 0 && rowHeights.length > 0) {
326
+ const extraPerRow = freeSpace / rowHeights.length;
327
+ for (let i = 0; i < rowHeights.length; i++) {
328
+ rowHeights[i] += extraPerRow;
193
329
  }
194
330
  }
331
+ return rowHeights;
195
332
  }
@@ -1,7 +1,7 @@
1
1
  import { LayoutNode } from "../../dom/node.js";
2
2
  import { Display } from "../../css/enums.js";
3
3
  import { resolveLength, isAutoLength } from "../../css/length.js";
4
- import { containingBlock, horizontalNonContent, horizontalMargin } from "../utils/node-math.js";
4
+ import { adjustForBoxSizing, containingBlock, horizontalNonContent, horizontalMargin } from "../utils/node-math.js";
5
5
  /**
6
6
  * Image strategy following SOLID principles:
7
7
  * - Single Responsibility: Handles image layout and sizing
@@ -27,21 +27,34 @@ export class ImageStrategy {
27
27
  * Sets up image sizing based on CSS properties
28
28
  */
29
29
  static setupImageSizing(node, _imageInfo) {
30
+ const intrinsicContainerRefs = {
31
+ containerWidth: node.intrinsicInlineSize ?? 0,
32
+ containerHeight: node.intrinsicBlockSize ?? 0,
33
+ };
30
34
  // If width is explicitly set, calculate proportional height
31
35
  if (node.style.width !== undefined && typeof node.style.width === 'number' && node.style.width > 0) {
32
- const specifiedWidth = resolveLength(node.style.width, node.intrinsicInlineSize, { auto: "zero" });
36
+ const specifiedWidth = resolveLength(node.style.width, node.intrinsicInlineSize, {
37
+ auto: "zero",
38
+ ...intrinsicContainerRefs,
39
+ });
33
40
  const scale = specifiedWidth / node.intrinsicInlineSize;
34
41
  node.intrinsicBlockSize = Math.round(node.intrinsicBlockSize * scale);
35
42
  }
36
43
  // If height is explicitly set, calculate proportional width
37
44
  else if (node.style.height !== undefined && typeof node.style.height === 'number' && node.style.height > 0) {
38
- const specifiedHeight = resolveLength(node.style.height, node.intrinsicBlockSize, { auto: "zero" });
45
+ const specifiedHeight = resolveLength(node.style.height, node.intrinsicBlockSize, {
46
+ auto: "zero",
47
+ ...intrinsicContainerRefs,
48
+ });
39
49
  const scale = specifiedHeight / node.intrinsicBlockSize;
40
50
  node.intrinsicInlineSize = Math.round(node.intrinsicInlineSize * scale);
41
51
  }
42
52
  // Handle max-width constraints
43
53
  else if (node.style.maxWidth !== undefined && typeof node.style.maxWidth === 'number') {
44
- const maxWidth = resolveLength(node.style.maxWidth, node.intrinsicInlineSize, { auto: "zero" });
54
+ const maxWidth = resolveLength(node.style.maxWidth, node.intrinsicInlineSize, {
55
+ auto: "zero",
56
+ ...intrinsicContainerRefs,
57
+ });
45
58
  if (maxWidth < node.intrinsicInlineSize) {
46
59
  const scale = maxWidth / node.intrinsicInlineSize;
47
60
  node.intrinsicInlineSize = maxWidth;
@@ -117,8 +130,20 @@ export function calculateImagePosition(node, containerWidth, containerHeight, im
117
130
  }
118
131
  case 'fill':
119
132
  // Use the specified dimensions if available
120
- width = node.style.width ? resolveLength(node.style.width, containerWidth, { auto: "zero" }) : containerWidth;
121
- height = node.style.height ? resolveLength(node.style.height, containerHeight, { auto: "zero" }) : containerHeight;
133
+ width = node.style.width
134
+ ? resolveLength(node.style.width, containerWidth, {
135
+ auto: "zero",
136
+ containerWidth,
137
+ containerHeight,
138
+ })
139
+ : containerWidth;
140
+ height = node.style.height
141
+ ? resolveLength(node.style.height, containerHeight, {
142
+ auto: "zero",
143
+ containerWidth,
144
+ containerHeight,
145
+ })
146
+ : containerHeight;
122
147
  break;
123
148
  case 'none':
124
149
  // Use original image size
@@ -153,38 +178,39 @@ export class ImageLayoutStrategy {
153
178
  const cb = containingBlock(node, context.env.viewport);
154
179
  const widthRef = Math.max(cb.width, 0);
155
180
  const heightRef = Math.max(cb.height, 0);
181
+ const containerRefs = { containerWidth: widthRef, containerHeight: heightRef };
156
182
  const intrinsicWidth = Math.max(0, node.intrinsicInlineSize ?? 0);
157
183
  const intrinsicHeight = Math.max(0, node.intrinsicBlockSize ?? 0);
158
184
  const hasIntrinsic = intrinsicWidth > 0 && intrinsicHeight > 0;
159
- const paddingLeft = resolveLength(node.style.paddingLeft, widthRef, { auto: "zero" });
160
- const paddingRight = resolveLength(node.style.paddingRight, widthRef, { auto: "zero" });
161
- const paddingTop = resolveLength(node.style.paddingTop, heightRef, { auto: "zero" });
162
- const paddingBottom = resolveLength(node.style.paddingBottom, heightRef, { auto: "zero" });
163
- const borderLeft = resolveLength(node.style.borderLeft, widthRef, { auto: "zero" });
164
- const borderRight = resolveLength(node.style.borderRight, widthRef, { auto: "zero" });
165
- const borderTop = resolveLength(node.style.borderTop, heightRef, { auto: "zero" });
166
- const borderBottom = resolveLength(node.style.borderBottom, heightRef, { auto: "zero" });
167
- const marginLeft = resolveLength(node.style.marginLeft, widthRef, { auto: "zero" });
168
- const marginRight = resolveLength(node.style.marginRight, widthRef, { auto: "zero" });
169
- const marginTop = resolveLength(node.style.marginTop, heightRef, { auto: "zero" });
170
- const marginBottom = resolveLength(node.style.marginBottom, heightRef, { auto: "zero" });
185
+ const paddingLeft = resolveLength(node.style.paddingLeft, widthRef, { auto: "zero", ...containerRefs });
186
+ const paddingRight = resolveLength(node.style.paddingRight, widthRef, { auto: "zero", ...containerRefs });
187
+ const paddingTop = resolveLength(node.style.paddingTop, heightRef, { auto: "zero", ...containerRefs });
188
+ const paddingBottom = resolveLength(node.style.paddingBottom, heightRef, { auto: "zero", ...containerRefs });
189
+ const borderLeft = resolveLength(node.style.borderLeft, widthRef, { auto: "zero", ...containerRefs });
190
+ const borderRight = resolveLength(node.style.borderRight, widthRef, { auto: "zero", ...containerRefs });
191
+ const borderTop = resolveLength(node.style.borderTop, heightRef, { auto: "zero", ...containerRefs });
192
+ const borderBottom = resolveLength(node.style.borderBottom, heightRef, { auto: "zero", ...containerRefs });
193
+ const marginLeft = resolveLength(node.style.marginLeft, widthRef, { auto: "zero", ...containerRefs });
194
+ const marginRight = resolveLength(node.style.marginRight, widthRef, { auto: "zero", ...containerRefs });
195
+ const marginTop = resolveLength(node.style.marginTop, heightRef, { auto: "zero", ...containerRefs });
196
+ const marginBottom = resolveLength(node.style.marginBottom, heightRef, { auto: "zero", ...containerRefs });
171
197
  const horizontalExtras = paddingLeft + paddingRight + borderLeft + borderRight;
172
198
  const verticalExtras = paddingTop + paddingBottom + borderTop + borderBottom;
173
- const availableContentWidth = Math.max(0, widthRef - horizontalNonContent(node, widthRef) - horizontalMargin(node, widthRef));
199
+ const availableContentWidth = Math.max(0, widthRef - horizontalNonContent(node, widthRef, heightRef) - horizontalMargin(node, widthRef, heightRef));
174
200
  const hasExplicitWidth = node.style.width !== "auto" && node.style.width !== undefined;
175
201
  const hasExplicitHeight = node.style.height !== "auto" && node.style.height !== undefined;
176
202
  let contentWidth = hasIntrinsic ? intrinsicWidth : availableContentWidth;
177
203
  let contentHeight = hasIntrinsic ? intrinsicHeight : 0;
178
204
  if (hasExplicitWidth) {
179
- const resolved = resolveLength(node.style.width, widthRef, { auto: "reference" });
205
+ const resolved = resolveLength(node.style.width, widthRef, { auto: "reference", ...containerRefs });
180
206
  if (Number.isFinite(resolved) && resolved > 0) {
181
- contentWidth = resolved;
207
+ contentWidth = adjustForBoxSizing(resolved, node.style.boxSizing, horizontalExtras);
182
208
  }
183
209
  }
184
210
  if (hasExplicitHeight) {
185
- const resolved = resolveLength(node.style.height, heightRef, { auto: "reference" });
211
+ const resolved = resolveLength(node.style.height, heightRef, { auto: "reference", ...containerRefs });
186
212
  if (Number.isFinite(resolved) && resolved > 0) {
187
- contentHeight = resolved;
213
+ contentHeight = adjustForBoxSizing(resolved, node.style.boxSizing, verticalExtras);
188
214
  }
189
215
  }
190
216
  if (hasIntrinsic) {
@@ -215,7 +241,7 @@ export class ImageLayoutStrategy {
215
241
  const lockAspectToWidth = hasIntrinsic && !hasExplicitHeight;
216
242
  const lockAspectToHeight = hasIntrinsic && !hasExplicitWidth;
217
243
  if (node.style.maxWidth !== undefined && !isAutoLength(node.style.maxWidth)) {
218
- const maxWidth = resolveLength(node.style.maxWidth, widthRef, { auto: "reference" });
244
+ const maxWidth = adjustForBoxSizing(resolveLength(node.style.maxWidth, widthRef, { auto: "reference", ...containerRefs }), node.style.boxSizing, horizontalExtras);
219
245
  if (Number.isFinite(maxWidth) && maxWidth > 0 && contentWidth > maxWidth) {
220
246
  if (lockAspectToWidth && contentWidth > 0) {
221
247
  const scale = maxWidth / contentWidth;
@@ -225,7 +251,7 @@ export class ImageLayoutStrategy {
225
251
  }
226
252
  }
227
253
  if (node.style.minWidth !== undefined && !isAutoLength(node.style.minWidth)) {
228
- const minWidth = resolveLength(node.style.minWidth, widthRef, { auto: "zero" });
254
+ const minWidth = adjustForBoxSizing(resolveLength(node.style.minWidth, widthRef, { auto: "zero", ...containerRefs }), node.style.boxSizing, horizontalExtras);
229
255
  if (Number.isFinite(minWidth) && minWidth > 0 && contentWidth < minWidth) {
230
256
  if (lockAspectToWidth && contentWidth > 0) {
231
257
  const scale = minWidth / contentWidth;
@@ -235,7 +261,7 @@ export class ImageLayoutStrategy {
235
261
  }
236
262
  }
237
263
  if (node.style.maxHeight !== undefined && !isAutoLength(node.style.maxHeight)) {
238
- const maxHeight = resolveLength(node.style.maxHeight, heightRef, { auto: "reference" });
264
+ const maxHeight = adjustForBoxSizing(resolveLength(node.style.maxHeight, heightRef, { auto: "reference", ...containerRefs }), node.style.boxSizing, verticalExtras);
239
265
  if (Number.isFinite(maxHeight) && maxHeight > 0 && contentHeight > maxHeight) {
240
266
  if (lockAspectToHeight && contentHeight > 0) {
241
267
  const scale = maxHeight / contentHeight;
@@ -245,7 +271,7 @@ export class ImageLayoutStrategy {
245
271
  }
246
272
  }
247
273
  if (node.style.minHeight !== undefined && !isAutoLength(node.style.minHeight)) {
248
- const minHeight = resolveLength(node.style.minHeight, heightRef, { auto: "zero" });
274
+ const minHeight = adjustForBoxSizing(resolveLength(node.style.minHeight, heightRef, { auto: "zero", ...containerRefs }), node.style.boxSizing, verticalExtras);
249
275
  if (Number.isFinite(minHeight) && minHeight > 0 && contentHeight < minHeight) {
250
276
  if (lockAspectToHeight && contentHeight > 0) {
251
277
  const scale = minHeight / contentHeight;
@@ -4,24 +4,28 @@ import { resolveLength } from "../../css/length.js";
4
4
  import { resolvedLineHeight } from "../../css/style.js";
5
5
  import { FloatContext } from "../context/float-context.js";
6
6
  import { defaultInlineFormatter } from "../utils/inline-formatter.js";
7
+ import { containingBlock } from "../utils/node-math.js";
7
8
  export class InlineLayoutStrategy {
8
9
  canLayout(node) {
9
10
  return node.style.display === Display.Inline;
10
11
  }
11
12
  layout(node, context) {
12
- const refWidth = Math.max(context.env.viewport.width, 0);
13
- const paddingLeft = resolveLength(node.style.paddingLeft, refWidth, { auto: "zero" });
14
- const paddingRight = resolveLength(node.style.paddingRight, refWidth, { auto: "zero" });
15
- const paddingTop = resolveLength(node.style.paddingTop, refWidth, { auto: "zero" });
16
- const paddingBottom = resolveLength(node.style.paddingBottom, refWidth, { auto: "zero" });
17
- const borderLeft = resolveLength(node.style.borderLeft, refWidth, { auto: "zero" });
18
- const borderRight = resolveLength(node.style.borderRight, refWidth, { auto: "zero" });
19
- const borderTop = resolveLength(node.style.borderTop, refWidth, { auto: "zero" });
20
- const borderBottom = resolveLength(node.style.borderBottom, refWidth, { auto: "zero" });
21
- const marginLeft = resolveLength(node.style.marginLeft, refWidth, { auto: "zero" });
22
- const marginRight = resolveLength(node.style.marginRight, refWidth, { auto: "zero" });
23
- const marginTop = resolveLength(node.style.marginTop, refWidth, { auto: "zero" });
24
- const marginBottom = resolveLength(node.style.marginBottom, refWidth, { auto: "zero" });
13
+ const cb = containingBlock(node, context.env.viewport);
14
+ const refWidth = Math.max(cb.width || context.env.viewport.width, 0);
15
+ const refHeight = Math.max(cb.height || context.env.viewport.height, 0);
16
+ const containerRefs = { containerWidth: refWidth, containerHeight: refHeight };
17
+ const paddingLeft = resolveLength(node.style.paddingLeft, refWidth, { auto: "zero", ...containerRefs });
18
+ const paddingRight = resolveLength(node.style.paddingRight, refWidth, { auto: "zero", ...containerRefs });
19
+ const paddingTop = resolveLength(node.style.paddingTop, refHeight, { auto: "zero", ...containerRefs });
20
+ const paddingBottom = resolveLength(node.style.paddingBottom, refHeight, { auto: "zero", ...containerRefs });
21
+ const borderLeft = resolveLength(node.style.borderLeft, refWidth, { auto: "zero", ...containerRefs });
22
+ const borderRight = resolveLength(node.style.borderRight, refWidth, { auto: "zero", ...containerRefs });
23
+ const borderTop = resolveLength(node.style.borderTop, refHeight, { auto: "zero", ...containerRefs });
24
+ const borderBottom = resolveLength(node.style.borderBottom, refHeight, { auto: "zero", ...containerRefs });
25
+ const marginLeft = resolveLength(node.style.marginLeft, refWidth, { auto: "zero", ...containerRefs });
26
+ const marginRight = resolveLength(node.style.marginRight, refWidth, { auto: "zero", ...containerRefs });
27
+ const marginTop = resolveLength(node.style.marginTop, refHeight, { auto: "zero", ...containerRefs });
28
+ const marginBottom = resolveLength(node.style.marginBottom, refHeight, { auto: "zero", ...containerRefs });
25
29
  const horizontalExtras = paddingLeft + paddingRight + borderLeft + borderRight;
26
30
  const verticalExtras = paddingTop + paddingBottom + borderTop + borderBottom;
27
31
  const inlineNodes = collectInlineParticipants(node);
@@ -37,7 +41,7 @@ export class InlineLayoutStrategy {
37
41
  contentWidth: availableWidth,
38
42
  startY,
39
43
  });
40
- const extent = measureInlineExtent(inlineNodes, refWidth, node.box.x + borderLeft + paddingLeft);
44
+ const extent = measureInlineExtent(inlineNodes, refWidth, refHeight, node.box.x + borderLeft + paddingLeft);
41
45
  const floatBottom = Math.max(floatContext.bottom("left"), floatContext.bottom("right"));
42
46
  const measuredHeight = Math.max(result.newCursorY, floatBottom) - startY;
43
47
  node.box.contentWidth = Math.max(0, extent);
@@ -81,19 +85,20 @@ function isInlineDisplay(display) {
81
85
  return false;
82
86
  }
83
87
  }
84
- function measureInlineExtent(inlineNodes, referenceWidth, contentStartX) {
88
+ function measureInlineExtent(inlineNodes, referenceWidth, containerHeight, contentStartX) {
85
89
  if (inlineNodes.length === 0) {
86
90
  return 0;
87
91
  }
92
+ const containerRefs = { containerWidth: referenceWidth, containerHeight };
88
93
  let minStart = Number.POSITIVE_INFINITY;
89
94
  let maxEnd = Number.NEGATIVE_INFINITY;
90
95
  for (const node of inlineNodes) {
91
- const marginLeft = resolveLength(node.style.marginLeft, referenceWidth, { auto: "zero" });
92
- const marginRight = resolveLength(node.style.marginRight, referenceWidth, { auto: "zero" });
93
- const paddingLeft = resolveLength(node.style.paddingLeft, referenceWidth, { auto: "zero" });
94
- const paddingRight = resolveLength(node.style.paddingRight, referenceWidth, { auto: "zero" });
95
- const borderLeft = resolveLength(node.style.borderLeft, referenceWidth, { auto: "zero" });
96
- const borderRight = resolveLength(node.style.borderRight, referenceWidth, { auto: "zero" });
96
+ const marginLeft = resolveLength(node.style.marginLeft, referenceWidth, { auto: "zero", ...containerRefs });
97
+ const marginRight = resolveLength(node.style.marginRight, referenceWidth, { auto: "zero", ...containerRefs });
98
+ const paddingLeft = resolveLength(node.style.paddingLeft, referenceWidth, { auto: "zero", ...containerRefs });
99
+ const paddingRight = resolveLength(node.style.paddingRight, referenceWidth, { auto: "zero", ...containerRefs });
100
+ const borderLeft = resolveLength(node.style.borderLeft, referenceWidth, { auto: "zero", ...containerRefs });
101
+ const borderRight = resolveLength(node.style.borderRight, referenceWidth, { auto: "zero", ...containerRefs });
97
102
  const marginStart = node.box.x - paddingLeft - borderLeft - marginLeft;
98
103
  const width = node.box.contentWidth +
99
104
  paddingLeft +
@@ -2,7 +2,7 @@ import { BorderModel, Display } from "../../css/enums.js";
2
2
  import { LayoutNode } from "../../dom/node.js";
3
3
  import { log } from "../../logging/debug.js";
4
4
  import { resolveLength } from "../../css/length.js";
5
- import { containingBlock, horizontalNonContent, resolveWidthBlock, verticalNonContent } from "../utils/node-math.js";
5
+ import { adjustForBoxSizing, containingBlock, horizontalNonContent, resolveWidthBlock, verticalNonContent } from "../utils/node-math.js";
6
6
  import { layoutTableCell } from "../table/cell_layout.js";
7
7
  import { auditTableCell, debugTableCell } from "../table/diagnostics.js";
8
8
  export class TableLayoutStrategy {
@@ -19,7 +19,8 @@ export class TableLayoutStrategy {
19
19
  children: node.children.length
20
20
  });
21
21
  const cb = containingBlock(node, context.env.viewport);
22
- node.box.contentWidth = resolveWidthBlock(node, cb.width);
22
+ const containerRefs = { containerWidth: cb.width, containerHeight: cb.height };
23
+ node.box.contentWidth = resolveWidthBlock(node, cb.width, cb.height);
23
24
  log("layout", "debug", "Table layout start", {
24
25
  table: node.tagName,
25
26
  availableWidth: cb.width,
@@ -109,7 +110,7 @@ export class TableLayoutStrategy {
109
110
  }
110
111
  }
111
112
  if (collapsedBorders) {
112
- const numericBorder = (value) => resolveLength(value, node.box.contentWidth, { auto: "zero" });
113
+ const numericBorder = (value) => resolveLength(value, node.box.contentWidth, { auto: "zero", ...containerRefs });
113
114
  // For collapsed borders, we need to:
114
115
  // 1. Collapse borders between adjacent cells (winner takes the shared border)
115
116
  // 2. Collapse outer cell borders with table border
@@ -236,7 +237,7 @@ export class TableLayoutStrategy {
236
237
  const colSpan = Math.min(this.cellColSpan(cell), numCols - c);
237
238
  const rowSpan = Math.min(this.cellRowSpan(cell), numRows - r);
238
239
  const spannedWidth = this.sumColumns(colWidths, c, colSpan);
239
- const boxMetrics = this.resolveCellBoxMetrics(cell, spannedWidth);
240
+ const boxMetrics = this.resolveCellBoxMetrics(cell, spannedWidth, cb.height);
240
241
  const cellAvailableWidth = spannedWidth - boxMetrics.borderLeft - boxMetrics.borderRight - boxMetrics.paddingLeft - boxMetrics.paddingRight;
241
242
  cell.box.x = 0;
242
243
  cell.box.y = 0;
@@ -294,7 +295,7 @@ export class TableLayoutStrategy {
294
295
  const rowSpan = Math.min(this.cellRowSpan(cell), numRows - r);
295
296
  const spanWidth = colOffsets[c + colSpan] - colOffsets[c];
296
297
  const spanHeight = rowOffsets[r + rowSpan] - rowOffsets[r];
297
- const boxMetrics = this.resolveCellBoxMetrics(cell, spanWidth);
298
+ const boxMetrics = this.resolveCellBoxMetrics(cell, spanWidth, cb.height);
298
299
  const availableContentHeight = spanHeight - boxMetrics.borderTop - boxMetrics.borderBottom - boxMetrics.paddingTop - boxMetrics.paddingBottom;
299
300
  const alignOffsetY = this.computeVerticalAlignOffset(cell.style.verticalAlign, availableContentHeight, cell.box.contentHeight);
300
301
  // Position the cell's border box at the column/row offset
@@ -347,9 +348,14 @@ export class TableLayoutStrategy {
347
348
  rowNode.box.borderBoxHeight = rowHeights[r];
348
349
  }
349
350
  }
350
- node.box.contentHeight = rowOffsets[numRows];
351
- node.box.borderBoxWidth = node.box.contentWidth + horizontalNonContent(node, cb.width);
352
- node.box.borderBoxHeight = node.box.contentHeight + verticalNonContent(node, cb.width);
351
+ let resolvedContentHeight = rowOffsets[numRows];
352
+ const verticalExtras = verticalNonContent(node, cb.height, cb.width);
353
+ if (node.style.height !== "auto" && node.style.height !== undefined) {
354
+ resolvedContentHeight = adjustForBoxSizing(resolveLength(node.style.height, cb.height, { auto: "zero", ...containerRefs }), node.style.boxSizing, verticalExtras);
355
+ }
356
+ node.box.contentHeight = Math.max(0, resolvedContentHeight);
357
+ node.box.borderBoxWidth = node.box.contentWidth + horizontalNonContent(node, cb.width, cb.height);
358
+ node.box.borderBoxHeight = node.box.contentHeight + verticalExtras;
353
359
  node.box.scrollWidth = node.box.contentWidth;
354
360
  node.box.scrollHeight = node.box.contentHeight;
355
361
  }
@@ -514,17 +520,19 @@ export class TableLayoutStrategy {
514
520
  }
515
521
  return offsets;
516
522
  }
517
- resolveCellBoxMetrics(cell, referenceWidth) {
518
- const resolve = (value) => resolveLength(value, referenceWidth, { auto: "zero" });
523
+ resolveCellBoxMetrics(cell, referenceWidth, referenceHeight = referenceWidth) {
524
+ const containerRefs = { containerWidth: referenceWidth, containerHeight: referenceHeight };
525
+ const resolveHorizontal = (value) => resolveLength(value, referenceWidth, { auto: "zero", ...containerRefs });
526
+ const resolveVertical = (value) => resolveLength(value, referenceHeight, { auto: "zero", ...containerRefs });
519
527
  return {
520
- borderLeft: resolve(cell.style.borderLeft),
521
- borderRight: resolve(cell.style.borderRight),
522
- borderTop: resolve(cell.style.borderTop),
523
- borderBottom: resolve(cell.style.borderBottom),
524
- paddingLeft: resolve(cell.style.paddingLeft),
525
- paddingRight: resolve(cell.style.paddingRight),
526
- paddingTop: resolve(cell.style.paddingTop),
527
- paddingBottom: resolve(cell.style.paddingBottom),
528
+ borderLeft: resolveHorizontal(cell.style.borderLeft),
529
+ borderRight: resolveHorizontal(cell.style.borderRight),
530
+ borderTop: resolveVertical(cell.style.borderTop),
531
+ borderBottom: resolveVertical(cell.style.borderBottom),
532
+ paddingLeft: resolveHorizontal(cell.style.paddingLeft),
533
+ paddingRight: resolveHorizontal(cell.style.paddingRight),
534
+ paddingTop: resolveVertical(cell.style.paddingTop),
535
+ paddingBottom: resolveVertical(cell.style.paddingBottom),
528
536
  };
529
537
  }
530
538
  computeVerticalAlignOffset(verticalAlign, available, content) {
@@ -25,7 +25,7 @@ export declare class ContentMeasurer {
25
25
  * @param contentStartX - The X coordinate where content area begins
26
26
  * @returns Object containing the measured width and any left offset
27
27
  */
28
- measureInFlowWidth(node: LayoutNode, referenceWidth: number, contentStartX: number): {
28
+ measureInFlowWidth(node: LayoutNode, referenceWidth: number, contentStartX: number, containerHeight?: number): {
29
29
  width: number;
30
30
  leftOffset: number;
31
31
  };