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
@@ -10,7 +10,7 @@ export function parseColor(value) {
10
10
  if (normalized === "transparent") {
11
11
  return undefined;
12
12
  }
13
- const hexMatch = normalized.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
13
+ const hexMatch = normalized.match(/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i);
14
14
  if (hexMatch) {
15
15
  const digits = hexMatch[1];
16
16
  if (digits.length === 3) {
@@ -19,10 +19,25 @@ export function parseColor(value) {
19
19
  const b = parseHex(digits[2] + digits[2]);
20
20
  return { r, g, b, a: 1 };
21
21
  }
22
+ if (digits.length === 4) {
23
+ const r = parseHex(digits[0] + digits[0]);
24
+ const g = parseHex(digits[1] + digits[1]);
25
+ const b = parseHex(digits[2] + digits[2]);
26
+ const a = parseHex(digits[3] + digits[3]) / 255;
27
+ return { r, g, b, a };
28
+ }
29
+ if (digits.length === 6) {
30
+ const r = parseHex(digits.slice(0, 2));
31
+ const g = parseHex(digits.slice(2, 4));
32
+ const b = parseHex(digits.slice(4, 6));
33
+ return { r, g, b, a: 1 };
34
+ }
35
+ // 8 digits
22
36
  const r = parseHex(digits.slice(0, 2));
23
37
  const g = parseHex(digits.slice(2, 4));
24
38
  const b = parseHex(digits.slice(4, 6));
25
- return { r, g, b, a: 1 };
39
+ const a = parseHex(digits.slice(6, 8)) / 255;
40
+ return { r, g, b, a };
26
41
  }
27
42
  const rgbMatch = normalized.match(/^rgba?\((.+)\)$/);
28
43
  if (rgbMatch) {
@@ -0,0 +1,29 @@
1
+ import type { FilterFunction } from "../../css/properties/visual.js";
2
+ import type { RGBA, ShadowLayer } from "../types.js";
3
+ /**
4
+ * Extrai o multiplicador de opacity de uma lista de filter functions.
5
+ * Múltiplos `opacity()` são multiplicados entre si (composição sequencial).
6
+ * Retorna 1.0 se não houver `opacity()` na lista.
7
+ */
8
+ export declare function extractOpacityMultiplier(filters: FilterFunction[]): number;
9
+ /**
10
+ * Converte `drop-shadow()` do filter em ShadowLayer[] compatível
11
+ * com o pipeline de box-shadow existente.
12
+ *
13
+ * Diferenças em relação a box-shadow real:
14
+ * - Sem `inset` (sempre false).
15
+ * - Sem `spread-radius` (sempre 0).
16
+ * - Na prática do CSS, drop-shadow segue a forma alpha do conteúdo,
17
+ * mas no MVP aproximamos como sombra retangular (box-shadow).
18
+ */
19
+ export declare function extractDropShadowLayers(filters: FilterFunction[], fallbackColor: RGBA): ShadowLayer[];
20
+ /**
21
+ * Lista nomes de funções de filtro que não são renderizáveis no MVP.
22
+ * Usado para emitir warnings durante a fase de pintura.
23
+ */
24
+ export declare function listUnsupportedFilters(filters: FilterFunction[] | undefined): string[];
25
+ /**
26
+ * Emite warnings para filtros não suportados.
27
+ * Chamado uma vez por box durante a fase de pintura.
28
+ */
29
+ export declare function warnUnsupportedFilters(filters: FilterFunction[] | undefined, label: "filter" | "backdrop-filter", boxId: string): void;
@@ -0,0 +1,85 @@
1
+ // src/pdf/utils/filter-utils.ts
2
+ import { parseColor, cloneColor } from "./color-utils.js";
3
+ import { log } from "../../logging/debug.js";
4
+ /**
5
+ * Extrai o multiplicador de opacity de uma lista de filter functions.
6
+ * Múltiplos `opacity()` são multiplicados entre si (composição sequencial).
7
+ * Retorna 1.0 se não houver `opacity()` na lista.
8
+ */
9
+ export function extractOpacityMultiplier(filters) {
10
+ let multiplier = 1;
11
+ for (const fn of filters) {
12
+ if (fn.kind === "opacity") {
13
+ multiplier *= fn.value;
14
+ }
15
+ }
16
+ return Math.max(0, Math.min(1, multiplier));
17
+ }
18
+ /**
19
+ * Converte `drop-shadow()` do filter em ShadowLayer[] compatível
20
+ * com o pipeline de box-shadow existente.
21
+ *
22
+ * Diferenças em relação a box-shadow real:
23
+ * - Sem `inset` (sempre false).
24
+ * - Sem `spread-radius` (sempre 0).
25
+ * - Na prática do CSS, drop-shadow segue a forma alpha do conteúdo,
26
+ * mas no MVP aproximamos como sombra retangular (box-shadow).
27
+ */
28
+ export function extractDropShadowLayers(filters, fallbackColor) {
29
+ const result = [];
30
+ for (const fn of filters) {
31
+ if (fn.kind !== "drop-shadow")
32
+ continue;
33
+ const offsetX = typeof fn.offsetX === "number" ? fn.offsetX : 0;
34
+ const offsetY = typeof fn.offsetY === "number" ? fn.offsetY : 0;
35
+ const blur = typeof fn.blurRadius === "number" ? Math.max(0, fn.blurRadius) : 0;
36
+ let color;
37
+ if (fn.color) {
38
+ const parsed = parseColor(fn.color);
39
+ color = parsed ? cloneColor(parsed) : cloneColor(fallbackColor);
40
+ }
41
+ else {
42
+ color = cloneColor(fallbackColor);
43
+ }
44
+ result.push({
45
+ inset: false,
46
+ offsetX,
47
+ offsetY,
48
+ blur,
49
+ spread: 0,
50
+ color,
51
+ });
52
+ }
53
+ return result;
54
+ }
55
+ /**
56
+ * Lista nomes de funções de filtro que não são renderizáveis no MVP.
57
+ * Usado para emitir warnings durante a fase de pintura.
58
+ */
59
+ export function listUnsupportedFilters(filters) {
60
+ if (!filters || filters.length === 0)
61
+ return [];
62
+ const unsupported = [];
63
+ for (const fn of filters) {
64
+ // opacity e drop-shadow são suportados no MVP
65
+ if (fn.kind === "opacity" || fn.kind === "drop-shadow")
66
+ continue;
67
+ unsupported.push(fn.kind);
68
+ }
69
+ return unsupported;
70
+ }
71
+ /**
72
+ * Emite warnings para filtros não suportados.
73
+ * Chamado uma vez por box durante a fase de pintura.
74
+ */
75
+ export function warnUnsupportedFilters(filters, label, boxId) {
76
+ const names = label === "backdrop-filter"
77
+ ? (filters ?? []).map((fn) => fn.kind)
78
+ : listUnsupportedFilters(filters);
79
+ if (names.length === 0)
80
+ return;
81
+ log("paint", "warn", `Unsupported ${label} function(s) ignored: ${names.join(", ")}`, {
82
+ boxId,
83
+ functions: names,
84
+ });
85
+ }
@@ -20,7 +20,7 @@ export function buildNodeTextRuns(context) {
20
20
  }
21
21
  }
22
22
  if (transform && textRuns.length > 0) {
23
- applyTransformToTextRuns(textRuns, transform, borderBox);
23
+ // applyTransformToTextRuns(textRuns, transform, borderBox);
24
24
  }
25
25
  return textRuns;
26
26
  }
@@ -1,12 +1,4 @@
1
1
  import type { RenderBox } from "../types.js";
2
- /**
3
- * Global pass to fix justified layout in the render tree.
4
- *
5
- * For each RenderBox with textAlign: "justify":
6
- * - collect ALL runs from that box and its descendants
7
- * - group runs by lineIndex
8
- import type { RenderBox, Run } from "../types.js";
9
-
10
2
  /**
11
3
  * Global pass to fix justified layout in the render tree.
12
4
  *
@@ -1,11 +1,3 @@
1
- /**
2
- * Global pass to fix justified layout in the render tree.
3
- *
4
- * For each RenderBox with textAlign: "justify":
5
- * - collect ALL runs from that box and its descendants
6
- * - group runs by lineIndex
7
- import type { RenderBox, Run } from "../types.js";
8
-
9
1
  /**
10
2
  * Global pass to fix justified layout in the render tree.
11
3
  *
@@ -73,6 +65,17 @@ function adjustLinePositions(runs) {
73
65
  /^\s+$/.test(runs[firstContentIndex].text)) {
74
66
  firstContentIndex++;
75
67
  }
68
+ const hasLeadingWhitespace = firstContentIndex > 0;
69
+ if (firstContentIndex >= runs.length) {
70
+ const anchorX = runs[0].lineMatrix?.e ?? 0;
71
+ for (const run of runs) {
72
+ if (run.lineMatrix) {
73
+ run.lineMatrix.e = anchorX;
74
+ }
75
+ run.advanceWidth = 0;
76
+ }
77
+ return;
78
+ }
76
79
  // Calculate width to redistribute from leading spaces
77
80
  let widthLost = 0;
78
81
  for (let i = 0; i < firstContentIndex; i++) {
@@ -85,7 +88,7 @@ function adjustLinePositions(runs) {
85
88
  }
86
89
  const isLastLine = runs[0].isLastLine ?? false;
87
90
  // Redistribute width if not last line and we have spaces to distribute to
88
- if (!isLastLine && widthLost > 0 && remainingSpaces > 0) {
91
+ if (hasLeadingWhitespace && !isLastLine && widthLost > 0 && remainingSpaces > 0) {
89
92
  const adjustment = widthLost / remainingSpaces;
90
93
  for (let i = firstContentIndex; i < runs.length; i++) {
91
94
  const run = runs[i];
@@ -1,21 +1,26 @@
1
1
  /**
2
2
  * Browser shim for css - provides CSS parsing using browser APIs
3
- * This replaces the Node.js css package in browser builds
3
+ * This replaces the Node.js css package in browser builds.
4
+ *
5
+ * The returned AST must match the shape produced by the Node.js `css` package
6
+ * so that parse-css.ts can consume it without any platform-specific branches.
4
7
  */
5
- interface CSSRule {
6
- type: number;
8
+ interface CSSDeclaration {
9
+ type: string;
10
+ property: string;
11
+ value: string;
12
+ }
13
+ interface CSSRuleNode {
14
+ type: string;
7
15
  selectors?: string[];
8
- declarations?: Array<{
9
- property: string;
10
- value: string;
11
- }>;
12
- rules?: CSSRule[];
16
+ declarations?: CSSDeclaration[];
17
+ rules?: CSSRuleNode[];
13
18
  media?: string;
14
19
  }
15
20
  interface CSSParseResult {
16
21
  type: string;
17
22
  stylesheet?: {
18
- rules: CSSRule[];
23
+ rules: CSSRuleNode[];
19
24
  };
20
25
  }
21
26
  /**
@@ -1,13 +1,28 @@
1
1
  /**
2
2
  * Browser shim for css - provides CSS parsing using browser APIs
3
- * This replaces the Node.js css package in browser builds
3
+ * This replaces the Node.js css package in browser builds.
4
+ *
5
+ * The returned AST must match the shape produced by the Node.js `css` package
6
+ * so that parse-css.ts can consume it without any platform-specific branches.
4
7
  */
8
+ function extractDeclarations(style) {
9
+ const declarations = [];
10
+ for (let j = 0; j < style.length; j++) {
11
+ const prop = style[j];
12
+ declarations.push({
13
+ type: "declaration",
14
+ property: prop,
15
+ value: style.getPropertyValue(prop),
16
+ });
17
+ }
18
+ return declarations;
19
+ }
5
20
  /**
6
21
  * Parse CSS text into an AST-like structure
7
22
  * Compatible with the Node.js css package's parse() function
8
23
  */
9
24
  export function parse(cssText) {
10
- const style = document.createElement('style');
25
+ const style = document.createElement("style");
11
26
  style.textContent = cssText;
12
27
  document.head.appendChild(style);
13
28
  const sheet = style.sheet;
@@ -16,61 +31,57 @@ export function parse(cssText) {
16
31
  const cssRules = sheet.cssRules || [];
17
32
  for (let i = 0; i < cssRules.length; i++) {
18
33
  const rule = cssRules[i];
19
- if (rule.type === CSSRule.STYLE_RULE) {
20
- const styleRule = rule;
21
- const declarations = [];
22
- const styleObj = styleRule.style;
23
- for (let j = 0; j < styleObj.length; j++) {
24
- const prop = styleObj[j];
25
- declarations.push({
26
- property: prop,
27
- value: styleObj.getPropertyValue(prop)
28
- });
29
- }
34
+ if (rule instanceof CSSStyleRule) {
35
+ // Split compound selectors so each gets its own entry, matching the
36
+ // node `css` package behaviour (it splits on commas).
37
+ const selectors = rule.selectorText
38
+ .split(",")
39
+ .map((s) => s.trim())
40
+ .filter(Boolean);
30
41
  rules.push({
31
- type: styleRule.type,
32
- selectors: [styleRule.selectorText],
33
- declarations
42
+ type: "rule",
43
+ selectors,
44
+ declarations: extractDeclarations(rule.style),
34
45
  });
35
46
  }
36
- else if (rule.type === CSSRule.MEDIA_RULE) {
37
- const mediaRule = rule;
47
+ else if (rule instanceof CSSFontFaceRule) {
48
+ rules.push({
49
+ type: "font-face",
50
+ declarations: extractDeclarations(rule.style),
51
+ });
52
+ }
53
+ else if (rule instanceof CSSMediaRule) {
38
54
  const mediaRules = [];
39
- for (let k = 0; k < mediaRule.cssRules.length; k++) {
40
- const mediaStyleRule = mediaRule.cssRules[k];
41
- if (mediaStyleRule.type === CSSRule.STYLE_RULE) {
42
- const declarations = [];
43
- const styleObj = mediaStyleRule.style;
44
- for (let j = 0; j < styleObj.length; j++) {
45
- const prop = styleObj[j];
46
- declarations.push({
47
- property: prop,
48
- value: styleObj.getPropertyValue(prop)
49
- });
50
- }
55
+ for (let k = 0; k < rule.cssRules.length; k++) {
56
+ const inner = rule.cssRules[k];
57
+ if (inner instanceof CSSStyleRule) {
58
+ const selectors = inner.selectorText
59
+ .split(",")
60
+ .map((s) => s.trim())
61
+ .filter(Boolean);
51
62
  mediaRules.push({
52
- type: mediaStyleRule.type,
53
- selectors: [mediaStyleRule.selectorText],
54
- declarations
63
+ type: "rule",
64
+ selectors,
65
+ declarations: extractDeclarations(inner.style),
55
66
  });
56
67
  }
57
68
  }
58
69
  rules.push({
59
- type: rule.type,
70
+ type: "media",
60
71
  media: rule.conditionText,
61
- rules: mediaRules
72
+ rules: mediaRules,
62
73
  });
63
74
  }
64
75
  }
65
76
  }
66
77
  document.head.removeChild(style);
67
78
  return {
68
- type: 'stylesheet',
79
+ type: "stylesheet",
69
80
  stylesheet: {
70
- rules
71
- }
81
+ rules,
82
+ },
72
83
  };
73
84
  }
74
85
  export default {
75
- parse
86
+ parse,
76
87
  };
@@ -13,6 +13,6 @@ export interface UnitCtx {
13
13
  }
14
14
  export declare function makeUnitParsers(_ctx: UnitCtx): {
15
15
  parseLength: (value: string) => number | import("../css/length.js").RelativeLength | undefined;
16
- parseLengthOrPercent: (value: string) => number | import("../css/length.js").AbsoluteLength | import("../css/length.js").RelativeLength | undefined;
16
+ parseLengthOrPercent: (value: string) => number | import("../css/length.js").AbsoluteLength | import("../css/length.js").RelativeLength | import("../css/length.js").CalcLength | undefined;
17
17
  };
18
18
  export type UnitParsers = ReturnType<typeof makeUnitParsers>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,46 @@
1
+ import { registerAllPropertyParsers } from "../../src/css/parsers/register-parsers.js";
2
+ import { computeStyleForElement } from "../../src/css/compute-style.js";
3
+ import { ComputedStyle } from "../../src/css/style.js";
4
+ import { BoxSizing } from "../../src/css/enums.js";
5
+ import { makeUnitParsers } from "../../src/units/units.js";
6
+ function makeElement(inlineStyle) {
7
+ return {
8
+ nodeType: 1,
9
+ nodeName: "DIV",
10
+ tagName: "div",
11
+ getAttribute(name) {
12
+ if (name === "style") {
13
+ return inlineStyle;
14
+ }
15
+ return null;
16
+ },
17
+ hasAttribute(name) {
18
+ return name === "style";
19
+ },
20
+ querySelectorAll(_selectors) {
21
+ return [];
22
+ },
23
+ parentElement: null,
24
+ firstElementChild: null,
25
+ lastElementChild: null,
26
+ nextElementSibling: null,
27
+ previousElementSibling: null,
28
+ };
29
+ }
30
+ describe("box-sizing parser and computed style", () => {
31
+ beforeAll(() => {
32
+ registerAllPropertyParsers();
33
+ });
34
+ it("defaults to content-box", () => {
35
+ const style = computeStyleForElement(makeElement("width: 200px;"), [], new ComputedStyle(), makeUnitParsers({ viewport: { width: 800, height: 600 } }), 16);
36
+ expect(style.boxSizing).toBe(BoxSizing.ContentBox);
37
+ });
38
+ it("parses border-box from inline style", () => {
39
+ const style = computeStyleForElement(makeElement("box-sizing: border-box; width: 200px;"), [], new ComputedStyle(), makeUnitParsers({ viewport: { width: 800, height: 600 } }), 16);
40
+ expect(style.boxSizing).toBe(BoxSizing.BorderBox);
41
+ });
42
+ it("parses content-box explicitly", () => {
43
+ const style = computeStyleForElement(makeElement("box-sizing: content-box;"), [], new ComputedStyle(), makeUnitParsers({ viewport: { width: 800, height: 600 } }), 16);
44
+ expect(style.boxSizing).toBe(BoxSizing.ContentBox);
45
+ });
46
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,68 @@
1
+ import { parseCalcLength } from "../../src/css/parsers/calc-parser.js";
2
+ import { computeStyleForElement } from "../../src/css/compute-style.js";
3
+ import { ComputedStyle } from "../../src/css/style.js";
4
+ import { registerAllPropertyParsers } from "../../src/css/parsers/register-parsers.js";
5
+ import { makeUnitParsers } from "../../src/units/units.js";
6
+ function makeElement(inlineStyle) {
7
+ return {
8
+ nodeType: 1,
9
+ nodeName: "DIV",
10
+ tagName: "div",
11
+ getAttribute(name) {
12
+ if (name === "style") {
13
+ return inlineStyle;
14
+ }
15
+ return null;
16
+ },
17
+ hasAttribute(name) {
18
+ return name === "style";
19
+ },
20
+ querySelectorAll(_selectors) {
21
+ return [];
22
+ },
23
+ parentElement: null,
24
+ firstElementChild: null,
25
+ lastElementChild: null,
26
+ nextElementSibling: null,
27
+ previousElementSibling: null,
28
+ };
29
+ }
30
+ describe("calc() parser", () => {
31
+ beforeAll(() => {
32
+ registerAllPropertyParsers();
33
+ });
34
+ it("parses arithmetic with mixed units", () => {
35
+ const parsed = parseCalcLength("calc((10px + 5%) * 2 - 4px / 2)");
36
+ expect(parsed).toBeDefined();
37
+ expect(parsed).toEqual({
38
+ kind: "calc",
39
+ px: 18,
40
+ percent: 0.1,
41
+ em: 0,
42
+ rem: 0,
43
+ cqw: 0,
44
+ cqh: 0,
45
+ cqi: 0,
46
+ cqb: 0,
47
+ cqmin: 0,
48
+ cqmax: 0,
49
+ });
50
+ });
51
+ it("supports calc in width declarations", () => {
52
+ const style = computeStyleForElement(makeElement("width: calc(100% - 20px);"), [], new ComputedStyle(), makeUnitParsers({ viewport: { width: 800, height: 600 } }), 16);
53
+ expect(typeof style.width).toBe("object");
54
+ expect(style.width).toEqual({
55
+ kind: "calc",
56
+ px: -20,
57
+ percent: 1,
58
+ em: 0,
59
+ rem: 0,
60
+ cqw: 0,
61
+ cqh: 0,
62
+ cqi: 0,
63
+ cqb: 0,
64
+ cqmin: 0,
65
+ cqmax: 0,
66
+ });
67
+ });
68
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,64 @@
1
+ import { registerAllPropertyParsers } from "../../src/css/parsers/register-parsers.js";
2
+ import { computeStyleForElement } from "../../src/css/compute-style.js";
3
+ import { ComputedStyle } from "../../src/css/style.js";
4
+ import { makeUnitParsers } from "../../src/units/units.js";
5
+ function makeElement(inlineStyle) {
6
+ return {
7
+ nodeType: 1,
8
+ nodeName: "DIV",
9
+ tagName: "div",
10
+ getAttribute(name) {
11
+ if (name === "style") {
12
+ return inlineStyle;
13
+ }
14
+ return null;
15
+ },
16
+ hasAttribute(name) {
17
+ return name === "style";
18
+ },
19
+ querySelectorAll(_selectors) {
20
+ return [];
21
+ },
22
+ parentElement: null,
23
+ firstElementChild: null,
24
+ lastElementChild: null,
25
+ nextElementSibling: null,
26
+ previousElementSibling: null,
27
+ };
28
+ }
29
+ describe("container query length units", () => {
30
+ beforeAll(() => {
31
+ registerAllPropertyParsers();
32
+ });
33
+ it("parses cqw/cqh in normal lengths", () => {
34
+ const style = computeStyleForElement(makeElement("width:50cqw;height:25cqh;"), [], new ComputedStyle(), makeUnitParsers({ viewport: { width: 800, height: 600 } }), 16);
35
+ expect(style.width).toMatchObject({
36
+ kind: "calc",
37
+ px: 0,
38
+ percent: 0,
39
+ cqw: 0.5,
40
+ });
41
+ expect(style.height).toMatchObject({
42
+ kind: "calc",
43
+ px: 0,
44
+ percent: 0,
45
+ cqh: 0.25,
46
+ });
47
+ });
48
+ it("parses cq units inside calc()", () => {
49
+ const style = computeStyleForElement(makeElement("width:calc(10px + 10cqw - 2cqh + 1cqmin);"), [], new ComputedStyle(), makeUnitParsers({ viewport: { width: 800, height: 600 } }), 16);
50
+ expect(style.width).toEqual({
51
+ kind: "calc",
52
+ px: 10,
53
+ percent: 0,
54
+ em: 0,
55
+ rem: 0,
56
+ cqw: 0.1,
57
+ cqh: -0.02,
58
+ cqi: 0,
59
+ cqb: 0,
60
+ cqmin: 0.01,
61
+ cqmax: 0,
62
+ });
63
+ });
64
+ });
@@ -34,6 +34,13 @@ describe("content CSS property parsing", () => {
34
34
  const item = expectContentType(target.content[0], "counter");
35
35
  expect(item.style).toBe("decimal");
36
36
  });
37
+ it("parses counter() with decimal-leading-zero style", () => {
38
+ const target = {};
39
+ parseContent("counter(step, decimal-leading-zero)", target);
40
+ expect(target.content).toBeDefined();
41
+ const item = expectContentType(target.content[0], "counter");
42
+ expect(item.style).toBe("decimal-leading-zero");
43
+ });
37
44
  it("parses attr() function", () => {
38
45
  const target = {};
39
46
  parseContent('attr(data-index)', target);
@@ -85,6 +92,12 @@ describe("formatCounterValue", () => {
85
92
  expect(formatCounterValue(26, "upper-alpha")).toBe("Z");
86
93
  expect(formatCounterValue(27, "upper-alpha")).toBe("AA");
87
94
  });
95
+ it("formats decimal-leading-zero", () => {
96
+ expect(formatCounterValue(1, "decimal-leading-zero")).toBe("01");
97
+ expect(formatCounterValue(9, "decimal-leading-zero")).toBe("09");
98
+ expect(formatCounterValue(10, "decimal-leading-zero")).toBe("10");
99
+ expect(formatCounterValue(-1, "decimal-leading-zero")).toBe("-01");
100
+ });
88
101
  });
89
102
  describe("evaluateContent", () => {
90
103
  it("evaluates string content", () => {
@@ -0,0 +1 @@
1
+ export {};