blitz-pdf 0.0.0-stage → 0.1.1

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 (370) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +391 -2
  3. package/THIRD_PARTY_NOTICES.md +25 -0
  4. package/assets/icon.svg +4 -0
  5. package/dist/api.d.ts +7 -0
  6. package/dist/api.d.ts.map +1 -0
  7. package/dist/api.js +46 -0
  8. package/dist/api.js.map +1 -0
  9. package/dist/assets.d.ts +7 -0
  10. package/dist/assets.d.ts.map +1 -0
  11. package/dist/assets.js +52 -0
  12. package/dist/assets.js.map +1 -0
  13. package/dist/browser.d.ts +3 -0
  14. package/dist/browser.d.ts.map +1 -0
  15. package/dist/browser.js +3 -0
  16. package/dist/browser.js.map +1 -0
  17. package/dist/node.d.ts +3 -0
  18. package/dist/node.d.ts.map +1 -0
  19. package/dist/node.js +10 -0
  20. package/dist/node.js.map +1 -0
  21. package/dist/options.d.ts +24 -0
  22. package/dist/options.d.ts.map +1 -0
  23. package/dist/options.js +135 -0
  24. package/dist/options.js.map +1 -0
  25. package/dist/types.d.ts +51 -0
  26. package/dist/types.d.ts.map +1 -0
  27. package/dist/types.js +2 -0
  28. package/dist/types.js.map +1 -0
  29. package/examples/bun.ts +8 -0
  30. package/examples/german-invoice/README.md +70 -0
  31. package/examples/german-invoice/data.mjs +83 -0
  32. package/examples/german-invoice/invoice.css +59 -0
  33. package/examples/german-invoice/template.mjs +49 -0
  34. package/examples/german-invoice.mjs +20 -0
  35. package/examples/invoice.html +29 -0
  36. package/examples/node.mjs +8 -0
  37. package/examples/pagination.html +40 -0
  38. package/examples/pagination.mjs +8 -0
  39. package/licenses/DejaVu.txt +187 -0
  40. package/licenses/RUST_DEPENDENCIES.txt +11577 -0
  41. package/package.json +89 -4
  42. package/src/api.ts +44 -0
  43. package/src/assets.ts +43 -0
  44. package/src/browser.ts +6 -0
  45. package/src/node.ts +12 -0
  46. package/src/options.ts +101 -0
  47. package/src/types.ts +49 -0
  48. package/vendor/README.md +17 -0
  49. package/vendor/stylo/.cargo-ok +1 -0
  50. package/vendor/stylo/.cargo_vcs_info.json +6 -0
  51. package/vendor/stylo/Cargo.lock +1485 -0
  52. package/vendor/stylo/Cargo.toml +274 -0
  53. package/vendor/stylo/LICENSE +373 -0
  54. package/vendor/stylo/README.md +6 -0
  55. package/vendor/stylo/applicable_declarations.rs +328 -0
  56. package/vendor/stylo/author_styles.rs +79 -0
  57. package/vendor/stylo/bezier.rs +176 -0
  58. package/vendor/stylo/bloom.rs +414 -0
  59. package/vendor/stylo/build.rs +91 -0
  60. package/vendor/stylo/build_gecko.rs +393 -0
  61. package/vendor/stylo/color/color_function.rs +601 -0
  62. package/vendor/stylo/color/component.rs +207 -0
  63. package/vendor/stylo/color/convert.rs +935 -0
  64. package/vendor/stylo/color/gamut/raytrace.rs +265 -0
  65. package/vendor/stylo/color/gamut.rs +227 -0
  66. package/vendor/stylo/color/mix.rs +645 -0
  67. package/vendor/stylo/color/mod.rs +750 -0
  68. package/vendor/stylo/color/parsing.rs +770 -0
  69. package/vendor/stylo/color/to_css.rs +297 -0
  70. package/vendor/stylo/context.rs +716 -0
  71. package/vendor/stylo/counter_style/mod.rs +754 -0
  72. package/vendor/stylo/counter_style/predefined.rs +61 -0
  73. package/vendor/stylo/counter_style/update_predefined.py +35 -0
  74. package/vendor/stylo/custom_properties.rs +2023 -0
  75. package/vendor/stylo/custom_properties_map.rs +220 -0
  76. package/vendor/stylo/data.rs +693 -0
  77. package/vendor/stylo/device/gecko.rs +486 -0
  78. package/vendor/stylo/device/mod.rs +304 -0
  79. package/vendor/stylo/device/servo.rs +507 -0
  80. package/vendor/stylo/dom.rs +1164 -0
  81. package/vendor/stylo/dom_apis.rs +937 -0
  82. package/vendor/stylo/driver.rs +172 -0
  83. package/vendor/stylo/error_reporting.rs +484 -0
  84. package/vendor/stylo/font_face.rs +558 -0
  85. package/vendor/stylo/font_metrics.rs +124 -0
  86. package/vendor/stylo/gecko/anon_boxes.toml +113 -0
  87. package/vendor/stylo/gecko/arc_types.rs +211 -0
  88. package/vendor/stylo/gecko/conversions.rs +59 -0
  89. package/vendor/stylo/gecko/data.rs +222 -0
  90. package/vendor/stylo/gecko/media_features.rs +971 -0
  91. package/vendor/stylo/gecko/mod.rs +20 -0
  92. package/vendor/stylo/gecko/non_ts_pseudo_class_list.rs +119 -0
  93. package/vendor/stylo/gecko/pseudo_element.rs +640 -0
  94. package/vendor/stylo/gecko/pseudo_element_definition.mako.rs +298 -0
  95. package/vendor/stylo/gecko/pseudo_elements.py +137 -0
  96. package/vendor/stylo/gecko/pseudo_elements.toml +197 -0
  97. package/vendor/stylo/gecko/regen_pseudo_elements.py +33 -0
  98. package/vendor/stylo/gecko/restyle_damage.rs +127 -0
  99. package/vendor/stylo/gecko/selector_parser.rs +627 -0
  100. package/vendor/stylo/gecko/snapshot.rs +202 -0
  101. package/vendor/stylo/gecko/snapshot_helpers.rs +334 -0
  102. package/vendor/stylo/gecko/traversal.rs +52 -0
  103. package/vendor/stylo/gecko/wrapper.rs +2258 -0
  104. package/vendor/stylo/gecko_bindings/mod.rs +34 -0
  105. package/vendor/stylo/gecko_bindings/sugar/mod.rs +12 -0
  106. package/vendor/stylo/gecko_bindings/sugar/ns_com_ptr.rs +15 -0
  107. package/vendor/stylo/gecko_bindings/sugar/ns_compatibility.rs +19 -0
  108. package/vendor/stylo/gecko_bindings/sugar/ns_style_auto_array.rs +111 -0
  109. package/vendor/stylo/gecko_bindings/sugar/origin_flags.rs +31 -0
  110. package/vendor/stylo/gecko_bindings/sugar/ownership.rs +70 -0
  111. package/vendor/stylo/gecko_bindings/sugar/refptr.rs +299 -0
  112. package/vendor/stylo/gecko_string_cache/mod.rs +543 -0
  113. package/vendor/stylo/gecko_string_cache/namespace.rs +106 -0
  114. package/vendor/stylo/global_style_data.rs +224 -0
  115. package/vendor/stylo/invalidation/element/document_state.rs +156 -0
  116. package/vendor/stylo/invalidation/element/element_wrapper.rs +432 -0
  117. package/vendor/stylo/invalidation/element/invalidation_map.rs +1631 -0
  118. package/vendor/stylo/invalidation/element/invalidator.rs +1470 -0
  119. package/vendor/stylo/invalidation/element/mod.rs +13 -0
  120. package/vendor/stylo/invalidation/element/relative_selector.rs +1399 -0
  121. package/vendor/stylo/invalidation/element/restyle_hints.rs +226 -0
  122. package/vendor/stylo/invalidation/element/state_and_attributes.rs +756 -0
  123. package/vendor/stylo/invalidation/media_queries.rs +144 -0
  124. package/vendor/stylo/invalidation/mod.rs +10 -0
  125. package/vendor/stylo/invalidation/stylesheets.rs +745 -0
  126. package/vendor/stylo/invalidation/viewport_units.rs +71 -0
  127. package/vendor/stylo/lib.rs +336 -0
  128. package/vendor/stylo/logical_geometry.rs +1684 -0
  129. package/vendor/stylo/macros.rs +70 -0
  130. package/vendor/stylo/matching.rs +1226 -0
  131. package/vendor/stylo/media_queries/media_list.rs +168 -0
  132. package/vendor/stylo/media_queries/media_query.rs +190 -0
  133. package/vendor/stylo/media_queries/mod.rs +13 -0
  134. package/vendor/stylo/parallel.rs +205 -0
  135. package/vendor/stylo/parser.rs +276 -0
  136. package/vendor/stylo/piecewise_linear.rs +282 -0
  137. package/vendor/stylo/prefs.rs +33 -0
  138. package/vendor/stylo/properties/build.py +119 -0
  139. package/vendor/stylo/properties/cascade.rs +2704 -0
  140. package/vendor/stylo/properties/computed_value_flags.rs +206 -0
  141. package/vendor/stylo/properties/counted_unknown_properties.py +104 -0
  142. package/vendor/stylo/properties/counter_style_descriptors.toml +45 -0
  143. package/vendor/stylo/properties/data.py +1375 -0
  144. package/vendor/stylo/properties/declaration_block.rs +1788 -0
  145. package/vendor/stylo/properties/font_face_descriptors.toml +50 -0
  146. package/vendor/stylo/properties/gecko.mako.rs +1555 -0
  147. package/vendor/stylo/properties/helpers/animated_properties.mako.rs +800 -0
  148. package/vendor/stylo/properties/helpers.mako.rs +812 -0
  149. package/vendor/stylo/properties/longhands.toml +4305 -0
  150. package/vendor/stylo/properties/mod.rs +1857 -0
  151. package/vendor/stylo/properties/properties.html.mako +31 -0
  152. package/vendor/stylo/properties/properties.mako.rs +3103 -0
  153. package/vendor/stylo/properties/property_descriptors.toml +18 -0
  154. package/vendor/stylo/properties/shorthands.rs +4241 -0
  155. package/vendor/stylo/properties/shorthands.toml +575 -0
  156. package/vendor/stylo/properties/vendored_python/mako-1.3.10-py3-none-any.whl +0 -0
  157. package/vendor/stylo/properties/vendored_python/markupsafe/LICENSE.txt +28 -0
  158. package/vendor/stylo/properties/vendored_python/markupsafe/__init__.py +384 -0
  159. package/vendor/stylo/properties/vendored_python/toml-0.10.2-py2.py3-none-any.whl +0 -0
  160. package/vendor/stylo/properties/view_transition_descriptors.toml +11 -0
  161. package/vendor/stylo/properties_and_values/mod.rs +12 -0
  162. package/vendor/stylo/properties_and_values/registry.rs +65 -0
  163. package/vendor/stylo/properties_and_values/rule.rs +331 -0
  164. package/vendor/stylo/properties_and_values/syntax/ascii.rs +60 -0
  165. package/vendor/stylo/properties_and_values/syntax/data_type.rs +146 -0
  166. package/vendor/stylo/properties_and_values/syntax/mod.rs +437 -0
  167. package/vendor/stylo/properties_and_values/value.rs +758 -0
  168. package/vendor/stylo/queries/condition.rs +996 -0
  169. package/vendor/stylo/queries/feature.rs +199 -0
  170. package/vendor/stylo/queries/feature_expression.rs +1170 -0
  171. package/vendor/stylo/queries/mod.rs +19 -0
  172. package/vendor/stylo/queries/values.rs +46 -0
  173. package/vendor/stylo/rule_cache.rs +267 -0
  174. package/vendor/stylo/rule_collector.rs +554 -0
  175. package/vendor/stylo/rule_tree/core.rs +787 -0
  176. package/vendor/stylo/rule_tree/level.rs +396 -0
  177. package/vendor/stylo/rule_tree/map.rs +201 -0
  178. package/vendor/stylo/rule_tree/mod.rs +427 -0
  179. package/vendor/stylo/rule_tree/source.rs +80 -0
  180. package/vendor/stylo/rule_tree/unsafe_box.rs +78 -0
  181. package/vendor/stylo/scoped_tls.rs +80 -0
  182. package/vendor/stylo/selector_map.rs +1050 -0
  183. package/vendor/stylo/selector_parser.rs +305 -0
  184. package/vendor/stylo/servo/animation.rs +1922 -0
  185. package/vendor/stylo/servo/attr.rs +714 -0
  186. package/vendor/stylo/servo/encoding_support.rs +81 -0
  187. package/vendor/stylo/servo/media_features.rs +254 -0
  188. package/vendor/stylo/servo/mod.rs +16 -0
  189. package/vendor/stylo/servo/restyle_damage.rs +215 -0
  190. package/vendor/stylo/servo/selector_parser.rs +1036 -0
  191. package/vendor/stylo/servo/shadow_parts.rs +207 -0
  192. package/vendor/stylo/shared_lock.rs +271 -0
  193. package/vendor/stylo/sharing/checks.rs +281 -0
  194. package/vendor/stylo/sharing/mod.rs +1000 -0
  195. package/vendor/stylo/simple_buckets_map.rs +52 -0
  196. package/vendor/stylo/str.rs +168 -0
  197. package/vendor/stylo/style_adjuster.rs +1086 -0
  198. package/vendor/stylo/style_resolver.rs +658 -0
  199. package/vendor/stylo/stylesheet_set.rs +658 -0
  200. package/vendor/stylo/stylesheets/appearance_base_rule.rs +51 -0
  201. package/vendor/stylo/stylesheets/container_rule.rs +769 -0
  202. package/vendor/stylo/stylesheets/counter_style_rule.rs +7 -0
  203. package/vendor/stylo/stylesheets/document_rule.rs +272 -0
  204. package/vendor/stylo/stylesheets/font_face_rule.rs +7 -0
  205. package/vendor/stylo/stylesheets/font_feature_values_rule.rs +481 -0
  206. package/vendor/stylo/stylesheets/font_palette_values_rule.rs +304 -0
  207. package/vendor/stylo/stylesheets/import_rule.rs +259 -0
  208. package/vendor/stylo/stylesheets/keyframes_rule.rs +733 -0
  209. package/vendor/stylo/stylesheets/layer_rule.rs +221 -0
  210. package/vendor/stylo/stylesheets/loader.rs +29 -0
  211. package/vendor/stylo/stylesheets/margin_rule.rs +190 -0
  212. package/vendor/stylo/stylesheets/media_rule.rs +191 -0
  213. package/vendor/stylo/stylesheets/mod.rs +918 -0
  214. package/vendor/stylo/stylesheets/namespace_rule.rs +43 -0
  215. package/vendor/stylo/stylesheets/nested_declarations_rule.rs +51 -0
  216. package/vendor/stylo/stylesheets/origin.rs +249 -0
  217. package/vendor/stylo/stylesheets/page_rule.rs +354 -0
  218. package/vendor/stylo/stylesheets/position_try_rule.rs +68 -0
  219. package/vendor/stylo/stylesheets/property_rule.rs +5 -0
  220. package/vendor/stylo/stylesheets/rule_list.rs +167 -0
  221. package/vendor/stylo/stylesheets/rule_parser.rs +1189 -0
  222. package/vendor/stylo/stylesheets/rules_iterator.rs +397 -0
  223. package/vendor/stylo/stylesheets/scope_rule.rs +511 -0
  224. package/vendor/stylo/stylesheets/starting_style_rule.rs +54 -0
  225. package/vendor/stylo/stylesheets/style_rule.rs +80 -0
  226. package/vendor/stylo/stylesheets/stylesheet.rs +570 -0
  227. package/vendor/stylo/stylesheets/supports_rule.rs +486 -0
  228. package/vendor/stylo/stylesheets/view_transition_rule.rs +81 -0
  229. package/vendor/stylo/stylist.rs +5076 -0
  230. package/vendor/stylo/thread_state.rs +87 -0
  231. package/vendor/stylo/traversal.rs +765 -0
  232. package/vendor/stylo/traversal_flags.rs +68 -0
  233. package/vendor/stylo/typed_om/mod.rs +981 -0
  234. package/vendor/stylo/typed_om/numeric.rs +128 -0
  235. package/vendor/stylo/typed_om/numeric_declaration.rs +93 -0
  236. package/vendor/stylo/typed_om/numeric_type.rs +640 -0
  237. package/vendor/stylo/typed_om/sum_value.rs +426 -0
  238. package/vendor/stylo/url/gecko.rs +367 -0
  239. package/vendor/stylo/url/mod.rs +71 -0
  240. package/vendor/stylo/url/servo.rs +239 -0
  241. package/vendor/stylo/use_counters/mod.rs +137 -0
  242. package/vendor/stylo/values/animated/color.rs +103 -0
  243. package/vendor/stylo/values/animated/effects.rs +26 -0
  244. package/vendor/stylo/values/animated/font.rs +37 -0
  245. package/vendor/stylo/values/animated/grid.rs +161 -0
  246. package/vendor/stylo/values/animated/lists.rs +141 -0
  247. package/vendor/stylo/values/animated/mod.rs +550 -0
  248. package/vendor/stylo/values/animated/svg.rs +46 -0
  249. package/vendor/stylo/values/animated/text.rs +58 -0
  250. package/vendor/stylo/values/animated/transform.rs +1592 -0
  251. package/vendor/stylo/values/computed/align.rs +90 -0
  252. package/vendor/stylo/values/computed/angle.rs +130 -0
  253. package/vendor/stylo/values/computed/animation.rs +124 -0
  254. package/vendor/stylo/values/computed/background.rs +13 -0
  255. package/vendor/stylo/values/computed/basic_shape.rs +267 -0
  256. package/vendor/stylo/values/computed/border.rs +163 -0
  257. package/vendor/stylo/values/computed/box.rs +267 -0
  258. package/vendor/stylo/values/computed/calc.rs +334 -0
  259. package/vendor/stylo/values/computed/color.rs +161 -0
  260. package/vendor/stylo/values/computed/column.rs +11 -0
  261. package/vendor/stylo/values/computed/corner_shape.rs +155 -0
  262. package/vendor/stylo/values/computed/counters.rs +26 -0
  263. package/vendor/stylo/values/computed/easing.rs +109 -0
  264. package/vendor/stylo/values/computed/effects.rs +30 -0
  265. package/vendor/stylo/values/computed/flex.rs +19 -0
  266. package/vendor/stylo/values/computed/font.rs +1517 -0
  267. package/vendor/stylo/values/computed/image.rs +273 -0
  268. package/vendor/stylo/values/computed/length.rs +576 -0
  269. package/vendor/stylo/values/computed/length_percentage.rs +1055 -0
  270. package/vendor/stylo/values/computed/list.rs +16 -0
  271. package/vendor/stylo/values/computed/mod.rs +1141 -0
  272. package/vendor/stylo/values/computed/motion.rs +73 -0
  273. package/vendor/stylo/values/computed/outline.rs +7 -0
  274. package/vendor/stylo/values/computed/page.rs +77 -0
  275. package/vendor/stylo/values/computed/param.rs +9 -0
  276. package/vendor/stylo/values/computed/percentage.rs +143 -0
  277. package/vendor/stylo/values/computed/position.rs +273 -0
  278. package/vendor/stylo/values/computed/ratio.rs +88 -0
  279. package/vendor/stylo/values/computed/rect.rs +19 -0
  280. package/vendor/stylo/values/computed/resolution.rs +76 -0
  281. package/vendor/stylo/values/computed/svg.rs +66 -0
  282. package/vendor/stylo/values/computed/table.rs +7 -0
  283. package/vendor/stylo/values/computed/text.rs +199 -0
  284. package/vendor/stylo/values/computed/time.rs +83 -0
  285. package/vendor/stylo/values/computed/transform.rs +559 -0
  286. package/vendor/stylo/values/computed/tree_counting.rs +30 -0
  287. package/vendor/stylo/values/computed/ui.rs +23 -0
  288. package/vendor/stylo/values/computed/url.rs +12 -0
  289. package/vendor/stylo/values/distance.rs +139 -0
  290. package/vendor/stylo/values/generics/animation.rs +363 -0
  291. package/vendor/stylo/values/generics/background.rs +65 -0
  292. package/vendor/stylo/values/generics/basic_shape.rs +1389 -0
  293. package/vendor/stylo/values/generics/border.rs +303 -0
  294. package/vendor/stylo/values/generics/box.rs +552 -0
  295. package/vendor/stylo/values/generics/calc.rs +2986 -0
  296. package/vendor/stylo/values/generics/color.rs +318 -0
  297. package/vendor/stylo/values/generics/column.rs +44 -0
  298. package/vendor/stylo/values/generics/counters.rs +320 -0
  299. package/vendor/stylo/values/generics/easing.rs +132 -0
  300. package/vendor/stylo/values/generics/effects.rs +131 -0
  301. package/vendor/stylo/values/generics/flex.rs +34 -0
  302. package/vendor/stylo/values/generics/font.rs +376 -0
  303. package/vendor/stylo/values/generics/grid.rs +962 -0
  304. package/vendor/stylo/values/generics/image.rs +653 -0
  305. package/vendor/stylo/values/generics/length.rs +656 -0
  306. package/vendor/stylo/values/generics/mod.rs +303 -0
  307. package/vendor/stylo/values/generics/motion.rs +274 -0
  308. package/vendor/stylo/values/generics/page.rs +167 -0
  309. package/vendor/stylo/values/generics/position.rs +669 -0
  310. package/vendor/stylo/values/generics/ratio.rs +88 -0
  311. package/vendor/stylo/values/generics/rect.rs +147 -0
  312. package/vendor/stylo/values/generics/size.rs +102 -0
  313. package/vendor/stylo/values/generics/svg.rs +226 -0
  314. package/vendor/stylo/values/generics/text.rs +268 -0
  315. package/vendor/stylo/values/generics/transform.rs +1157 -0
  316. package/vendor/stylo/values/generics/ui.rs +147 -0
  317. package/vendor/stylo/values/generics/url.rs +51 -0
  318. package/vendor/stylo/values/mod.rs +820 -0
  319. package/vendor/stylo/values/resolved/animation.rs +33 -0
  320. package/vendor/stylo/values/resolved/color.rs +53 -0
  321. package/vendor/stylo/values/resolved/counters.rs +45 -0
  322. package/vendor/stylo/values/resolved/mod.rs +316 -0
  323. package/vendor/stylo/values/specified/align.rs +711 -0
  324. package/vendor/stylo/values/specified/angle.rs +407 -0
  325. package/vendor/stylo/values/specified/animation.rs +921 -0
  326. package/vendor/stylo/values/specified/background.rs +270 -0
  327. package/vendor/stylo/values/specified/basic_shape.rs +986 -0
  328. package/vendor/stylo/values/specified/border.rs +430 -0
  329. package/vendor/stylo/values/specified/box.rs +2231 -0
  330. package/vendor/stylo/values/specified/calc.rs +1657 -0
  331. package/vendor/stylo/values/specified/color.rs +1210 -0
  332. package/vendor/stylo/values/specified/column.rs +11 -0
  333. package/vendor/stylo/values/specified/corner_shape.rs +152 -0
  334. package/vendor/stylo/values/specified/counters.rs +242 -0
  335. package/vendor/stylo/values/specified/easing.rs +225 -0
  336. package/vendor/stylo/values/specified/effects.rs +421 -0
  337. package/vendor/stylo/values/specified/flex.rs +42 -0
  338. package/vendor/stylo/values/specified/font.rs +2103 -0
  339. package/vendor/stylo/values/specified/frequency.rs +39 -0
  340. package/vendor/stylo/values/specified/grid.rs +407 -0
  341. package/vendor/stylo/values/specified/image.rs +1385 -0
  342. package/vendor/stylo/values/specified/intersection_observer.rs +80 -0
  343. package/vendor/stylo/values/specified/length.rs +2024 -0
  344. package/vendor/stylo/values/specified/list.rs +190 -0
  345. package/vendor/stylo/values/specified/mod.rs +531 -0
  346. package/vendor/stylo/values/specified/motion.rs +316 -0
  347. package/vendor/stylo/values/specified/number.rs +603 -0
  348. package/vendor/stylo/values/specified/outline.rs +69 -0
  349. package/vendor/stylo/values/specified/page.rs +94 -0
  350. package/vendor/stylo/values/specified/param.rs +121 -0
  351. package/vendor/stylo/values/specified/percentage.rs +364 -0
  352. package/vendor/stylo/values/specified/position.rs +2247 -0
  353. package/vendor/stylo/values/specified/ratio.rs +29 -0
  354. package/vendor/stylo/values/specified/rect.rs +28 -0
  355. package/vendor/stylo/values/specified/resolution.rs +237 -0
  356. package/vendor/stylo/values/specified/source_size_list.rs +135 -0
  357. package/vendor/stylo/values/specified/svg.rs +427 -0
  358. package/vendor/stylo/values/specified/svg_path.rs +1115 -0
  359. package/vendor/stylo/values/specified/table.rs +38 -0
  360. package/vendor/stylo/values/specified/text.rs +1561 -0
  361. package/vendor/stylo/values/specified/time.rs +313 -0
  362. package/vendor/stylo/values/specified/transform.rs +599 -0
  363. package/vendor/stylo/values/specified/tree_counting.rs +32 -0
  364. package/vendor/stylo/values/specified/ui.rs +344 -0
  365. package/vendor/stylo/values/specified/url.rs +12 -0
  366. package/vendor/stylo/values/tagged_numeric.rs +253 -0
  367. package/wasm/blitz_pdf.d.ts +67 -0
  368. package/wasm/blitz_pdf.js +699 -0
  369. package/wasm/blitz_pdf_bg.wasm +0 -0
  370. package/wasm/blitz_pdf_bg.wasm.d.ts +20 -0
@@ -0,0 +1,1922 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+
5
+ //! CSS transitions and animations.
6
+
7
+ // NOTE(emilio): This code isn't really executed in Gecko, but we don't want to
8
+ // compile it out so that people remember it exists.
9
+
10
+ use crate::context::{CascadeInputs, SharedStyleContext};
11
+ use crate::derives::*;
12
+ use crate::dom::{OpaqueNode, TDocument, TElement, TNode};
13
+ use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
14
+ use crate::properties::longhands::animation_composition::computed_value::single_value::T as AnimationComposition;
15
+ use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
16
+ use crate::properties::longhands::animation_fill_mode::computed_value::single_value::T as AnimationFillMode;
17
+ use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
18
+ use crate::properties::AnimationDeclarations;
19
+ use crate::properties::{
20
+ ComputedValues, Importance, LonghandId, PropertyDeclarationBlock, PropertyDeclarationId,
21
+ PropertyDeclarationIdSet,
22
+ };
23
+ use crate::rule_tree::{CascadeLevel, CascadeOrigin, RuleCascadeFlags};
24
+ use crate::selector_parser::PseudoElement;
25
+ use crate::shared_lock::{Locked, SharedRwLock};
26
+ use crate::style_resolver::StyleResolverForElement;
27
+ use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
28
+ use crate::stylesheets::layer_rule::LayerOrder;
29
+ use crate::values::animated::{Animate, Procedure};
30
+ use crate::values::computed::TimingFunction;
31
+ use crate::values::generics::easing::BeforeFlag;
32
+ use crate::values::specified::TransitionBehavior;
33
+ use crate::Atom;
34
+ use debug_unreachable::debug_unreachable;
35
+ use parking_lot::RwLock;
36
+ use rustc_hash::FxHashMap;
37
+ use servo_arc::Arc;
38
+ use std::fmt;
39
+
40
+ /// Represents an animation for a given property.
41
+ #[derive(Clone, Debug, MallocSizeOf)]
42
+ pub struct PropertyAnimation {
43
+ /// The value we are animating from.
44
+ from: AnimationValue,
45
+
46
+ /// The value we are animating to.
47
+ to: AnimationValue,
48
+
49
+ /// The timing function of this `PropertyAnimation`.
50
+ timing_function: TimingFunction,
51
+
52
+ /// The duration of this `PropertyAnimation` in seconds.
53
+ pub duration: f64,
54
+ }
55
+
56
+ impl PropertyAnimation {
57
+ /// Returns the given property longhand id.
58
+ pub fn property_id(&self) -> PropertyDeclarationId<'_> {
59
+ debug_assert_eq!(self.from.id(), self.to.id());
60
+ self.from.id()
61
+ }
62
+
63
+ /// The output of the timing function given the progress ration of this animation.
64
+ fn timing_function_output(&self, progress: f64) -> f64 {
65
+ let epsilon = 1. / (200. * self.duration);
66
+ // FIXME: Need to set the before flag correctly.
67
+ // In order to get the before flag, we have to know the current animation phase
68
+ // and whether the iteration is reversed. For now, we skip this calculation
69
+ // by treating as if the flag is unset at all times.
70
+ // https://drafts.csswg.org/css-easing/#step-timing-function-algo
71
+ self.timing_function
72
+ .calculate_output(progress, BeforeFlag::Unset, epsilon)
73
+ }
74
+
75
+ /// Update the given animation at a given point of progress.
76
+ fn calculate_value(&self, progress: f64) -> AnimationValue {
77
+ let progress = self.timing_function_output(progress);
78
+ let procedure = Procedure::Interpolate { progress };
79
+ self.from.animate(&self.to, procedure).unwrap_or_else(|()| {
80
+ // Fall back to discrete interpolation
81
+ if progress < 0.5 {
82
+ self.from.clone()
83
+ } else {
84
+ self.to.clone()
85
+ }
86
+ })
87
+ }
88
+ }
89
+
90
+ /// This structure represents the state of an animation.
91
+ #[derive(Clone, Debug, MallocSizeOf, PartialEq)]
92
+ pub enum AnimationState {
93
+ /// The animation has been created, but is not running yet. This state
94
+ /// is also used when an animation is still in the first delay phase.
95
+ Pending,
96
+ /// This animation is currently running.
97
+ Running,
98
+ /// This animation is paused. The inner field is the percentage of progress
99
+ /// when it was paused, from 0 to 1.
100
+ Paused(f64),
101
+ /// This animation has finished.
102
+ Finished,
103
+ /// This animation has been canceled.
104
+ Canceled,
105
+ }
106
+
107
+ impl AnimationState {
108
+ /// Whether or not this state requires its owning animation to be ticked.
109
+ fn needs_to_be_ticked(&self) -> bool {
110
+ *self == AnimationState::Running || *self == AnimationState::Pending
111
+ }
112
+ }
113
+
114
+ enum IgnoreTransitions {
115
+ Canceled,
116
+ CanceledAndFinished,
117
+ }
118
+
119
+ /// This structure represents a keyframes animation current iteration state.
120
+ ///
121
+ /// If the iteration count is infinite, there's no other state, otherwise we
122
+ /// have to keep track the current iteration and the max iteration count.
123
+ #[derive(Clone, Debug, MallocSizeOf)]
124
+ pub enum KeyframesIterationState {
125
+ /// Infinite iterations with the current iteration count.
126
+ Infinite(f64),
127
+ /// Current and max iterations.
128
+ Finite(f64, f64),
129
+ }
130
+
131
+ /// A temporary data structure used when calculating ComputedKeyframes for an
132
+ /// animation. This data structure is used to collapse information for steps
133
+ /// which may be spread across multiple keyframe declarations into a single
134
+ /// instance per `start_percentage`.
135
+ #[derive(Debug)]
136
+ struct IntermediateComputedKeyframe {
137
+ declarations: PropertyDeclarationBlock,
138
+ timing_function: Option<TimingFunction>,
139
+ composition: Option<AnimationComposition>,
140
+ start_percentage: f64,
141
+ }
142
+
143
+ impl IntermediateComputedKeyframe {
144
+ fn new(start_percentage: f64) -> Self {
145
+ IntermediateComputedKeyframe {
146
+ declarations: PropertyDeclarationBlock::new(),
147
+ timing_function: None,
148
+ composition: None,
149
+ start_percentage,
150
+ }
151
+ }
152
+
153
+ /// Walk through all keyframe declarations and combine all declarations with the
154
+ /// same `start_percentage` into individual `IntermediateComputedKeyframe`s.
155
+ fn generate_for_keyframes(
156
+ animation: &KeyframesAnimation,
157
+ context: &SharedStyleContext,
158
+ base_style: &ComputedValues,
159
+ ) -> Vec<Self> {
160
+ if animation.steps.is_empty() {
161
+ return vec![];
162
+ }
163
+
164
+ let mut intermediate_steps: Vec<Self> = Vec::with_capacity(animation.steps.len());
165
+ let mut current_step = IntermediateComputedKeyframe::new(0.);
166
+ for step in animation.steps.iter() {
167
+ let start_percentage = step.start_offset.percentage.0 as f64;
168
+ if start_percentage != current_step.start_percentage {
169
+ let new_step = IntermediateComputedKeyframe::new(start_percentage);
170
+ intermediate_steps.push(std::mem::replace(&mut current_step, new_step));
171
+ }
172
+
173
+ current_step.update_from_step(step, context, base_style);
174
+ }
175
+ intermediate_steps.push(current_step);
176
+
177
+ // We should always have a first and a last step, even if these are just
178
+ // generated by KeyframesStepValue::ComputedValues.
179
+ debug_assert!(intermediate_steps.first().unwrap().start_percentage == 0.);
180
+ debug_assert!(intermediate_steps.last().unwrap().start_percentage == 1.);
181
+
182
+ intermediate_steps
183
+ }
184
+
185
+ fn update_from_step(
186
+ &mut self,
187
+ step: &KeyframesStep,
188
+ context: &SharedStyleContext,
189
+ base_style: &ComputedValues,
190
+ ) {
191
+ // Each keyframe declaration may optionally specify a timing function, falling
192
+ // back to the one defined global for the animation.
193
+ let guard = &context.guards.author;
194
+ if let Some(timing_function) = step.get_animation_timing_function(&guard) {
195
+ self.timing_function = Some(timing_function.to_computed_value_without_context());
196
+ }
197
+
198
+ // Each keyframe declaration may optionally specify a composite operation,
199
+ // falling back to the one defined globally for the animation.
200
+ if let Some(composition) = step.get_animation_composition(&guard) {
201
+ self.composition = Some(composition);
202
+ }
203
+
204
+ let block = match step.value {
205
+ KeyframesStepValue::ComputedValues => return,
206
+ KeyframesStepValue::Declarations { ref block } => block,
207
+ };
208
+
209
+ // Filter out !important, non-animatable properties, and the
210
+ // 'display' property (which is only animatable from SMIL).
211
+ let guard = block.read_with(&guard);
212
+ for declaration in guard.normal_declaration_iter() {
213
+ if let PropertyDeclarationId::Longhand(id) = declaration.id() {
214
+ if id == LonghandId::Display {
215
+ continue;
216
+ }
217
+
218
+ if !id.is_animatable() {
219
+ continue;
220
+ }
221
+ }
222
+
223
+ self.declarations.push(
224
+ declaration.to_physical(base_style.writing_mode),
225
+ Importance::Normal,
226
+ );
227
+ }
228
+ }
229
+
230
+ fn resolve_style<E>(
231
+ self,
232
+ element: E,
233
+ context: &SharedStyleContext,
234
+ base_style: &Arc<ComputedValues>,
235
+ resolver: &mut StyleResolverForElement<E>,
236
+ ) -> Arc<ComputedValues>
237
+ where
238
+ E: TElement,
239
+ {
240
+ if !self.declarations.any_normal() {
241
+ return base_style.clone();
242
+ }
243
+
244
+ let document = element.as_node().owner_doc();
245
+ let locked_block = Arc::new(document.shared_lock().wrap(self.declarations));
246
+ let mut important_rules_changed = false;
247
+ let rule_node = base_style.rules().clone();
248
+ let new_node = context.stylist.rule_tree().update_rule_at_level(
249
+ CascadeLevel::new(CascadeOrigin::Animations),
250
+ LayerOrder::root(),
251
+ Some(locked_block.borrow_arc()),
252
+ &rule_node,
253
+ &context.guards,
254
+ &mut important_rules_changed,
255
+ );
256
+
257
+ if new_node.is_none() {
258
+ return base_style.clone();
259
+ }
260
+
261
+ let inputs = CascadeInputs {
262
+ rules: new_node,
263
+ visited_rules: base_style.visited_rules().cloned(),
264
+ flags: base_style.flags.for_cascade_inputs(),
265
+ included_cascade_flags: RuleCascadeFlags::empty(),
266
+ };
267
+ resolver
268
+ .cascade_style_and_visited_with_default_parents(inputs)
269
+ .0
270
+ }
271
+ }
272
+
273
+ #[derive(Clone, Debug, MallocSizeOf)]
274
+ struct PropertyDeclarationOffsets {
275
+ /// The absolute index of the most recent preceding keyframe that declared
276
+ /// the given property.
277
+ preceding_declaration: usize,
278
+ /// The absolute index of the next keyframe that will declare the given
279
+ /// property.
280
+ following_declaration: usize,
281
+ }
282
+
283
+ #[derive(Clone, Debug, MallocSizeOf)]
284
+ enum AnimationValueOrReference {
285
+ /// This keyframe declares the property with the given value.
286
+ AnimationValue(AnimationValue),
287
+ /// This keyframe does not declare the property.
288
+ NotDefinedHere(PropertyDeclarationOffsets),
289
+ }
290
+
291
+ /// A single computed keyframe for a CSS Animation.
292
+ #[derive(Clone, Debug, MallocSizeOf)]
293
+ struct ComputedKeyframe {
294
+ /// The timing function to use for transitions between this step
295
+ /// and the next one.
296
+ timing_function: TimingFunction,
297
+
298
+ /// The starting percentage (a number between 0 and 1) which represents
299
+ /// at what point in an animation iteration this step is.
300
+ start_percentage: f64,
301
+
302
+ /// The animation values to transition to and from when processing this
303
+ /// keyframe animation step.
304
+ values: Box<[AnimationValueOrReference]>,
305
+ }
306
+
307
+ /// Composite a keyframe value with the underlying value according to the
308
+ /// given composite operation.
309
+ ///
310
+ /// <https://drafts.csswg.org/web-animations-1/#applying-the-composite-operation>
311
+ fn composite_animation_value(
312
+ underlying_value: &AnimationValue,
313
+ keyframe_value: AnimationValue,
314
+ composition: AnimationComposition,
315
+ ) -> AnimationValue {
316
+ let procedure = match composition {
317
+ AnimationComposition::Replace => return keyframe_value,
318
+ AnimationComposition::Add => Procedure::Add,
319
+ AnimationComposition::Accumulate => Procedure::Accumulate { count: 1 },
320
+ };
321
+ underlying_value
322
+ .animate(&keyframe_value, procedure)
323
+ .unwrap_or(keyframe_value)
324
+ }
325
+
326
+ /// Caches the indices of keyframes that declare a specific property.
327
+ ///
328
+ /// While traversing the list of keyframes, this is used to avoid repeatedly
329
+ /// searching for the next or last keyframe that declares the property. That
330
+ /// would result in quadratic runtime with respect to the number of keyframes.
331
+ #[derive(Clone, Copy, Debug, Default)]
332
+ struct KeyframeOffsetCacheForProperty {
333
+ /// The index of a previous keyframe that declares the property.
334
+ ///
335
+ /// Note that if the first keyframe does not declare a property, then it implicitly
336
+ /// uses the computed value of that property. That's why there's always a preceding keyframe
337
+ /// with the property.
338
+ last_keyframe_that_defined_property: usize,
339
+
340
+ /// The index of a future keyframe or `None` if we have not yet walked the list of keyframes
341
+ /// to find the next index.
342
+ ///
343
+ /// There will always be a next keyframe because the last keyframe (like the first keyframe)
344
+ /// declares *all* animating properties.
345
+ next_keyframe_that_defines_property: Option<usize>,
346
+ }
347
+
348
+ struct KeyframeDataForProperty<'a> {
349
+ /// The timing function to use for transitions between this step
350
+ /// and the next one.
351
+ timing_function: &'a TimingFunction,
352
+
353
+ /// The starting percentage (a number between 0 and 1) which represents
354
+ /// at what point in an animation iteration this step is.
355
+ start_percentage: f64,
356
+
357
+ value: &'a AnimationValue,
358
+ }
359
+
360
+ #[derive(Clone, Copy, Debug)]
361
+ enum Direction {
362
+ Forward,
363
+ Backward,
364
+ }
365
+
366
+ impl Direction {
367
+ fn relative_to_animation_direction(&self, reverse: bool) -> Self {
368
+ match self {
369
+ Self::Forward if reverse => Self::Backward,
370
+ Self::Backward if reverse => Self::Forward,
371
+ _ => *self,
372
+ }
373
+ }
374
+ }
375
+
376
+ impl Animation {
377
+ /// Starting from the keyframe at `keyframe_index`, returns the contents of the next keyframe in `direction`
378
+ /// that sets the property at `property_index`.
379
+ ///
380
+ /// Returns `None` if there is no keyframe in the specified direction that sets the property.
381
+ fn next_relevant_keyframe_for_property_in_direction(
382
+ &self,
383
+ property_index: usize,
384
+ keyframe_index: usize,
385
+ direction: Direction,
386
+ ) -> Option<KeyframeDataForProperty<'_>> {
387
+ let relevant_keyframe = &self.computed_steps[keyframe_index];
388
+ let parameters = match &relevant_keyframe.values[property_index] {
389
+ AnimationValueOrReference::AnimationValue(animation_value) => KeyframeDataForProperty {
390
+ timing_function: &relevant_keyframe.timing_function,
391
+ start_percentage: relevant_keyframe.start_percentage,
392
+ value: animation_value,
393
+ },
394
+ AnimationValueOrReference::NotDefinedHere(offsets) => {
395
+ let next_relevant_keyframe_index = match direction {
396
+ Direction::Forward => offsets.following_declaration,
397
+ Direction::Backward => offsets.preceding_declaration,
398
+ };
399
+ let next_relevant_keyframe = &self.computed_steps[next_relevant_keyframe_index];
400
+ let AnimationValueOrReference::AnimationValue(animation_value) =
401
+ &next_relevant_keyframe.values[property_index]
402
+ else {
403
+ panic!("Referenced keyframe does not set property");
404
+ };
405
+
406
+ KeyframeDataForProperty {
407
+ timing_function: &next_relevant_keyframe.timing_function,
408
+ start_percentage: next_relevant_keyframe.start_percentage,
409
+ value: &animation_value,
410
+ }
411
+ },
412
+ };
413
+
414
+ Some(parameters)
415
+ }
416
+ }
417
+ impl ComputedKeyframe {
418
+ fn generate_for_keyframes<E>(
419
+ element: E,
420
+ animation: &KeyframesAnimation,
421
+ context: &SharedStyleContext,
422
+ base_style: &Arc<ComputedValues>,
423
+ default_timing_function: TimingFunction,
424
+ default_composition: AnimationComposition,
425
+ resolver: &mut StyleResolverForElement<E>,
426
+ animating_properties: PropertyDeclarationIdSet,
427
+ number_of_animating_properties: usize,
428
+ ) -> Box<[Self]>
429
+ where
430
+ E: TElement,
431
+ {
432
+ let animation_values_from_style: Vec<AnimationValue> = animating_properties
433
+ .iter()
434
+ .map(|property| {
435
+ AnimationValue::from_computed_values(property, &**base_style)
436
+ .expect("Unexpected non-animatable property.")
437
+ })
438
+ .collect();
439
+
440
+ let intermediate_steps =
441
+ IntermediateComputedKeyframe::generate_for_keyframes(animation, context, base_style);
442
+
443
+ // Used while iterating over the keyframes to, for each property, remember the most recent and
444
+ // next keyframe that declares the property. That avoids a quadratic number of traversals per
445
+ // property.
446
+ let mut keyframe_offset_caches: Vec<KeyframeOffsetCacheForProperty> =
447
+ vec![Default::default(); number_of_animating_properties];
448
+
449
+ let mut computed_steps: Vec<Self> = Vec::with_capacity(intermediate_steps.len());
450
+ let mut remaining_steps = intermediate_steps.into_iter();
451
+ let mut step_index = 0;
452
+ while let Some(step) = remaining_steps.next() {
453
+ let start_percentage = step.start_percentage;
454
+ let properties_changed_in_step = step.declarations.property_ids().clone();
455
+ let timing_function = step
456
+ .timing_function
457
+ .clone()
458
+ .unwrap_or_else(|| default_timing_function.clone());
459
+ let composition = step.composition.unwrap_or(default_composition);
460
+ let step_style = step.resolve_style(element, context, base_style, resolver);
461
+
462
+ let values: Box<[_]> = {
463
+ // For each property that is animating, pull the value from the resolved
464
+ // style for this step if it's in one of the declarations.
465
+ animating_properties
466
+ .iter()
467
+ .enumerate()
468
+ .map(|(property_index, property_declaration)| {
469
+ let keyframe_offset_cache = &mut keyframe_offset_caches[property_index];
470
+ if properties_changed_in_step.contains(property_declaration) {
471
+ keyframe_offset_cache.last_keyframe_that_defined_property = step_index;
472
+ let animation_value = AnimationValue::from_computed_values(
473
+ property_declaration,
474
+ &step_style,
475
+ )
476
+ .unwrap();
477
+ let animation_value = composite_animation_value(
478
+ &animation_values_from_style[property_index],
479
+ animation_value,
480
+ composition,
481
+ );
482
+ return AnimationValueOrReference::AnimationValue(animation_value);
483
+ }
484
+
485
+ // https://drafts.csswg.org/css-animations/#keyframes
486
+ // > If a 0% or from keyframe is not specified, then the user agent constructs a 0% keyframe
487
+ // > using the computed values of the properties being animated. If a 100% or to keyframe is
488
+ // > not specified, then the user agent constructs a 100% keyframe using the computed values
489
+ // > of the properties being animated.
490
+ if step_index == 0 || remaining_steps.as_slice().is_empty() {
491
+ return AnimationValueOrReference::AnimationValue(
492
+ animation_values_from_style[property_index].clone(),
493
+ );
494
+ }
495
+
496
+ // This animating property is not defined on this keyframe - we should act as if this keyframe
497
+ // didn't exist for this property, so we calculate an interpolated value.
498
+ // (https://drafts.csswg.org/css-animations/#keyframes)
499
+ //
500
+ // If the property was not defined on any previous keyframe then we use the value from style.
501
+ // and if it's not defined on any following keyframe then we've already finished animating it.
502
+ let preceding_declaration =
503
+ keyframe_offset_cache.last_keyframe_that_defined_property;
504
+ let following_declaration = keyframe_offset_cache
505
+ .next_keyframe_that_defines_property
506
+ .filter(|offset| *offset > step_index)
507
+ .unwrap_or_else(|| {
508
+ let relative_offset = remaining_steps
509
+ .as_slice()
510
+ .iter()
511
+ .position(|step| {
512
+ step.declarations.contains(property_declaration)
513
+ })
514
+ .unwrap_or(remaining_steps.as_slice().len() - 1);
515
+ let absolute_offset = step_index + 1 + relative_offset;
516
+
517
+ keyframe_offset_cache.next_keyframe_that_defines_property =
518
+ Some(absolute_offset);
519
+ absolute_offset
520
+ });
521
+
522
+ AnimationValueOrReference::NotDefinedHere(PropertyDeclarationOffsets {
523
+ preceding_declaration,
524
+ following_declaration,
525
+ })
526
+ })
527
+ .collect()
528
+ };
529
+ debug_assert_eq!(values.len(), number_of_animating_properties);
530
+
531
+ computed_steps.push(ComputedKeyframe {
532
+ timing_function,
533
+ start_percentage,
534
+ values,
535
+ });
536
+
537
+ step_index += 1;
538
+ }
539
+
540
+ // The first and last steps (at 0% and 100% respectively) should declare all animating properties.
541
+ // If they don't then we should have filled the missing properties with the computed values.
542
+ debug_assert!(computed_steps.first().is_none_or(|first_step| {
543
+ first_step
544
+ .values
545
+ .iter()
546
+ .all(|value| matches!(value, AnimationValueOrReference::AnimationValue(_)))
547
+ }));
548
+ debug_assert!(computed_steps.last().is_none_or(|first_step| {
549
+ first_step
550
+ .values
551
+ .iter()
552
+ .all(|value| matches!(value, AnimationValueOrReference::AnimationValue(_)))
553
+ }));
554
+
555
+ computed_steps.into_boxed_slice()
556
+ }
557
+ }
558
+
559
+ /// A CSS Animation
560
+ #[derive(Clone, MallocSizeOf)]
561
+ pub struct Animation {
562
+ /// The name of this animation as defined by the style.
563
+ pub name: Atom,
564
+
565
+ /// The properties that change in this animation.
566
+ properties_changed: PropertyDeclarationIdSet,
567
+
568
+ /// The computed style for each keyframe of this animation.
569
+ computed_steps: Box<[ComputedKeyframe]>,
570
+
571
+ /// The time this animation started at, which is the current value of the animation
572
+ /// timeline when this animation was created plus any animation delay.
573
+ pub started_at: f64,
574
+
575
+ /// The duration of this animation.
576
+ pub duration: f64,
577
+
578
+ /// The delay of the animation.
579
+ pub delay: f64,
580
+
581
+ /// The `animation-fill-mode` property of this animation.
582
+ pub fill_mode: AnimationFillMode,
583
+
584
+ /// The current iteration state for the animation.
585
+ pub iteration_state: KeyframesIterationState,
586
+
587
+ /// Whether this animation is paused.
588
+ pub state: AnimationState,
589
+
590
+ /// The declared animation direction of this animation.
591
+ pub direction: AnimationDirection,
592
+
593
+ /// The current animation direction. This can only be `normal` or `reverse`.
594
+ pub current_direction: AnimationDirection,
595
+
596
+ /// The number of properties that are affected by this animation.
597
+ pub number_of_animating_properties: usize,
598
+
599
+ /// Whether or not this animation is new and or has already been tracked
600
+ /// by the script thread.
601
+ pub is_new: bool,
602
+ }
603
+
604
+ impl Animation {
605
+ /// Whether or not this animation is cancelled by changes from a new style.
606
+ fn is_cancelled_in_new_style(&self, new_style: &Arc<ComputedValues>) -> bool {
607
+ let new_ui = new_style.get_ui();
608
+ let index = new_ui
609
+ .animation_name_iter()
610
+ .position(|animation_name| Some(&self.name) == animation_name.as_atom());
611
+ let index = match index {
612
+ Some(index) => index,
613
+ None => return true,
614
+ };
615
+
616
+ new_ui.animation_duration_mod(index).seconds() == 0.
617
+ }
618
+
619
+ /// Given the current time, advances this animation to the next iteration,
620
+ /// updates times, and then toggles the direction if appropriate. Otherwise
621
+ /// does nothing. Returns true if this animation has iterated.
622
+ pub fn iterate_if_necessary(&mut self, time: f64) -> bool {
623
+ if !self.iteration_over(time) {
624
+ return false;
625
+ }
626
+
627
+ // Only iterate animations that are currently running.
628
+ if self.state != AnimationState::Running {
629
+ return false;
630
+ }
631
+
632
+ self.iterate_by(1.) == 1.
633
+ }
634
+
635
+ /// Attempts to advance this animation by `n` iterations, but stops when reaching
636
+ /// the last iteration, and doesn't perform fractional iterations.
637
+ /// Returns the actual number of iterations that happened.
638
+ fn iterate_by(&mut self, n: f64) -> f64 {
639
+ let n = n.trunc().min(self.remaining_iterations().ceil() - 1.0);
640
+ if n < 1. {
641
+ return 0.;
642
+ }
643
+
644
+ match self.iteration_state {
645
+ KeyframesIterationState::Finite(ref mut current, max) => {
646
+ *current = (*current + n).min(max);
647
+ },
648
+ KeyframesIterationState::Infinite(ref mut current) => {
649
+ *current += n;
650
+ },
651
+ }
652
+
653
+ if let AnimationState::Paused(ref mut progress) = self.state {
654
+ debug_assert!(*progress >= n);
655
+ *progress -= n;
656
+ }
657
+
658
+ // Update the next iteration direction if applicable.
659
+ self.started_at += self.duration * n;
660
+ match self.direction {
661
+ AnimationDirection::Alternate | AnimationDirection::AlternateReverse
662
+ if n % 2. == 1.0 =>
663
+ {
664
+ self.current_direction = match self.current_direction {
665
+ AnimationDirection::Normal => AnimationDirection::Reverse,
666
+ AnimationDirection::Reverse => AnimationDirection::Normal,
667
+ _ => unreachable!(
668
+ "Current animation direction can only be `normal` or `reverse`."
669
+ ),
670
+ };
671
+ },
672
+ _ => {},
673
+ }
674
+
675
+ n
676
+ }
677
+
678
+ fn remaining_iterations(&self) -> f64 {
679
+ match self.iteration_state {
680
+ KeyframesIterationState::Finite(current, max) => max - current,
681
+ KeyframesIterationState::Infinite(_) => f64::INFINITY,
682
+ }
683
+ }
684
+
685
+ /// A number (> 0 and <= 1) which represents the fraction of a full iteration
686
+ /// that the current iteration of the animation lasts. This will be less than 1
687
+ /// if the current iteration is the fractional remainder of a non-integral
688
+ /// iteration count.
689
+ pub fn current_iteration_end_progress(&self) -> f64 {
690
+ self.remaining_iterations().min(1.)
691
+ }
692
+
693
+ /// The duration of the current iteration of this animation which may be less
694
+ /// than the animation duration if it has a non-integral iteration count.
695
+ pub fn current_iteration_duration(&self) -> f64 {
696
+ self.current_iteration_end_progress() * self.duration
697
+ }
698
+
699
+ /// Whether or not the current iteration is over. Note that this method assumes that
700
+ /// the animation is still running.
701
+ fn iteration_over(&self, time: f64) -> bool {
702
+ time > (self.started_at + self.current_iteration_duration())
703
+ }
704
+
705
+ /// Assuming this animation is running, whether or not it is on the last iteration.
706
+ fn on_last_iteration(&self) -> bool {
707
+ self.remaining_iterations() <= 1.
708
+ }
709
+
710
+ /// Whether or not this animation has finished at the provided time. This does
711
+ /// not take into account canceling i.e. when an animation or transition is
712
+ /// canceled due to changes in the style.
713
+ pub fn has_ended(&self, time: f64) -> bool {
714
+ if !self.on_last_iteration() {
715
+ return false;
716
+ }
717
+
718
+ let progress = match self.state {
719
+ AnimationState::Finished => return true,
720
+ AnimationState::Paused(progress) => progress,
721
+ AnimationState::Running => (time - self.started_at) / self.duration,
722
+ AnimationState::Pending | AnimationState::Canceled => return false,
723
+ };
724
+
725
+ progress >= self.current_iteration_end_progress()
726
+ }
727
+
728
+ /// Updates the appropiate state from other animation.
729
+ ///
730
+ /// This happens when an animation is re-submitted to layout, presumably
731
+ /// because of an state change.
732
+ ///
733
+ /// There are some bits of state we can't just replace, over all taking in
734
+ /// account times, so here's that logic.
735
+ pub fn update_from_other(&mut self, other: &Self, now: f64) {
736
+ use self::AnimationState::*;
737
+
738
+ debug!(
739
+ "KeyframesAnimationState::update_from_other({:?}, {:?})",
740
+ self, other
741
+ );
742
+
743
+ // NB: We shall not touch the started_at field, since we don't want to
744
+ // restart the animation.
745
+ let old_started_at = self.started_at;
746
+ let old_delay = self.delay;
747
+ let old_duration = self.duration;
748
+ let old_direction = self.current_direction;
749
+ let old_state = self.state.clone();
750
+ let old_iteration_state = self.iteration_state.clone();
751
+
752
+ *self = other.clone();
753
+ self.current_direction = old_direction;
754
+
755
+ if self.delay != old_delay {
756
+ // `started_at` incorporates the delay, so changing the delay necessarily changes `started_at`.
757
+ // Note: `started_at` may actually be in the future.
758
+ self.started_at = old_started_at + (self.delay - old_delay);
759
+
760
+ match old_state {
761
+ Paused(old_progress) => {
762
+ let mut progress = old_progress + (old_delay - self.delay) / self.duration;
763
+ progress -= self.iterate_by(progress);
764
+ self.state = Paused(progress);
765
+ },
766
+ Finished => {
767
+ if self.has_ended(now) {
768
+ self.state = Finished;
769
+ } else if self.started_at <= now {
770
+ self.state = Running;
771
+ } else {
772
+ self.state = Pending;
773
+ }
774
+ },
775
+ Canceled | Pending | Running => {
776
+ // Re-advance iterations from a fresh iteration state.
777
+ let new_starting_progress = (now - self.started_at) / self.duration;
778
+ match self.iteration_state {
779
+ KeyframesIterationState::Finite(ref mut current, _) => *current = 0.0,
780
+ _ => {},
781
+ }
782
+ if let AnimationState::Paused(starting_progress) = &mut self.state {
783
+ *starting_progress = new_starting_progress;
784
+ }
785
+ self.iterate_by(new_starting_progress);
786
+ },
787
+ }
788
+
789
+ // Don't check old_state when delay changed.
790
+ if self.state == Pending && self.started_at <= now {
791
+ self.state = Running;
792
+ }
793
+ } else {
794
+ self.started_at = old_started_at;
795
+
796
+ // Don't update the iteration count, just the iteration limit.
797
+ // TODO: see how changing the limit affects rendering in other browsers.
798
+ // We might need to keep the iteration count even when it's infinite.
799
+ match (&mut self.iteration_state, old_iteration_state) {
800
+ (
801
+ &mut KeyframesIterationState::Finite(ref mut iters, _),
802
+ KeyframesIterationState::Finite(old_iters, _),
803
+ ) => *iters = old_iters,
804
+ _ => {},
805
+ }
806
+
807
+ // Don't pause or restart animations that should remain finished.
808
+ // We call mem::replace because `has_ended(...)` looks at `Animation::state`.
809
+ let new_state = std::mem::replace(&mut self.state, Running);
810
+ if old_state == Finished && self.has_ended(now) {
811
+ self.state = Finished;
812
+ } else {
813
+ self.state = new_state;
814
+ }
815
+
816
+ // If we're unpausing the animation, fake the start time so we seem to
817
+ // restore it.
818
+ //
819
+ // If the animation keeps paused, keep the old value.
820
+ //
821
+ // If we're pausing the animation, compute the progress value.
822
+ match (&mut self.state, &old_state) {
823
+ (&mut Pending, &Paused(progress)) => {
824
+ self.started_at = now - (self.duration * progress);
825
+ },
826
+ (&mut Paused(ref mut new), &Paused(old)) => *new = old,
827
+ (&mut Paused(ref mut progress), &Running) => {
828
+ *progress = (now - old_started_at) / old_duration
829
+ },
830
+ _ => {},
831
+ }
832
+
833
+ // Try to detect when we should skip straight to the running phase to
834
+ // avoid sending multiple animationstart events.
835
+ if self.state == Pending && self.started_at <= now && old_state != Pending {
836
+ self.state = Running;
837
+ }
838
+ }
839
+ }
840
+
841
+ /// Fill in an `AnimationValueMap` with values calculated from this animation at
842
+ /// the given time value.
843
+ fn get_property_declaration_at_time(&self, now: f64, map: &mut AnimationValueMap) {
844
+ if self.computed_steps.is_empty() {
845
+ // Nothing to do.
846
+ return;
847
+ }
848
+
849
+ // Raw progress ratio of the animation: can be negative (before start) or
850
+ // >1.0 (after end or during multiple iterations).
851
+ let progress = match self.state {
852
+ AnimationState::Running | AnimationState::Pending | AnimationState::Finished => {
853
+ (now - self.started_at) / self.duration
854
+ },
855
+ AnimationState::Paused(progress) => progress,
856
+ AnimationState::Canceled => return,
857
+ };
858
+
859
+ if progress < 0.
860
+ && self.fill_mode != AnimationFillMode::Backwards
861
+ && self.fill_mode != AnimationFillMode::Both
862
+ {
863
+ return;
864
+ }
865
+ if self.has_ended(now)
866
+ && self.fill_mode != AnimationFillMode::Forwards
867
+ && self.fill_mode != AnimationFillMode::Both
868
+ {
869
+ return;
870
+ }
871
+
872
+ // If we only need to take into account one keyframe, then exit early
873
+ // in order to avoid doing more work.
874
+ let mut add_declarations_to_map = |keyframe: &ComputedKeyframe| {
875
+ for value_or_reference in keyframe.values.iter() {
876
+ let AnimationValueOrReference::AnimationValue(value) = value_or_reference else {
877
+ unreachable!("First or last keyframes define all properties");
878
+ };
879
+ map.insert(value.id().to_owned(), value.clone());
880
+ }
881
+ };
882
+
883
+ // Handle negative progress (before animation start) with backwards/both fill mode
884
+ if progress < 0.0 {
885
+ if let Some(keyframe) = match self.current_direction {
886
+ AnimationDirection::Normal => self.computed_steps.first(),
887
+ AnimationDirection::Reverse => self.computed_steps.last(),
888
+ _ => unreachable!("Current animation direction can only be `normal` or `reverse`."),
889
+ } {
890
+ add_declarations_to_map(keyframe);
891
+ }
892
+ return;
893
+ }
894
+
895
+ // Progress clamped to the current iteration [0.0, 1.0].
896
+ let total_progress = progress.min(self.current_iteration_end_progress()).max(0.0);
897
+
898
+ // At 1.0 there is nothing left to interpolate. Return end keyframe.
899
+ if total_progress == 1.0 {
900
+ let keyframe = match self.current_direction {
901
+ AnimationDirection::Normal => self.computed_steps.last().unwrap(),
902
+ AnimationDirection::Reverse => self.computed_steps.first().unwrap(),
903
+ _ => unreachable!("Current animation direction can only be `normal` or `reverse`."),
904
+ };
905
+ add_declarations_to_map(keyframe);
906
+ return;
907
+ }
908
+
909
+ // Get the indices of the previous (from) keyframe and the next (to) keyframe.
910
+ let next_keyframe_index;
911
+ let prev_keyframe_index;
912
+ let num_steps = self.computed_steps.len();
913
+ match self.current_direction {
914
+ AnimationDirection::Normal => {
915
+ next_keyframe_index = self
916
+ .computed_steps
917
+ .iter()
918
+ .position(|step| total_progress < step.start_percentage);
919
+ prev_keyframe_index = next_keyframe_index
920
+ .and_then(|pos| if pos != 0 { Some(pos - 1) } else { None })
921
+ .unwrap_or(0);
922
+ },
923
+ AnimationDirection::Reverse => {
924
+ next_keyframe_index = self
925
+ .computed_steps
926
+ .iter()
927
+ .rev()
928
+ .position(|step| total_progress <= 1. - step.start_percentage)
929
+ .map(|pos| num_steps - pos - 1);
930
+ prev_keyframe_index = next_keyframe_index
931
+ .and_then(|pos| {
932
+ if pos != num_steps - 1 {
933
+ Some(pos + 1)
934
+ } else {
935
+ None
936
+ }
937
+ })
938
+ .unwrap_or(num_steps - 1)
939
+ },
940
+ _ => unreachable!(),
941
+ }
942
+
943
+ debug!(
944
+ "Animation::get_property_declaration_at_time: keyframe from {:?} to {:?}",
945
+ prev_keyframe_index, next_keyframe_index
946
+ );
947
+
948
+ let prev_keyframe = &self.computed_steps[prev_keyframe_index];
949
+ let Some(next_keyframe_index) = next_keyframe_index else {
950
+ unsafe {
951
+ debug_unreachable!(
952
+ "next_keyframe_index should always be Some: \
953
+ total_progress is in [0, 1) at this point. \
954
+ Normal direction: keyframe with start_percentage 1.0 always satisfies. \
955
+ Reverse direction: keyframe with start_percentage 0.0 always satisfies."
956
+ );
957
+ }
958
+ };
959
+
960
+ // Prevent division by zero from percentage_between_keyframes.
961
+ // This can happen for reverse direction at total_progress == 0.0.
962
+ if prev_keyframe_index == next_keyframe_index {
963
+ add_declarations_to_map(&prev_keyframe);
964
+ return;
965
+ }
966
+
967
+ // Interpolate a new value for each animating property
968
+ let reversed = self.current_direction != AnimationDirection::Normal;
969
+ for property_index in 0..self.number_of_animating_properties {
970
+ let Some(previous_keyframe) = self.next_relevant_keyframe_for_property_in_direction(
971
+ property_index,
972
+ prev_keyframe_index,
973
+ Direction::Backward.relative_to_animation_direction(reversed),
974
+ ) else {
975
+ // Animation of this property has not started yet
976
+ continue;
977
+ };
978
+
979
+ let Some(next_keyframe) = self.next_relevant_keyframe_for_property_in_direction(
980
+ property_index,
981
+ next_keyframe_index,
982
+ Direction::Forward.relative_to_animation_direction(reversed),
983
+ ) else {
984
+ // This property has finished animating, just use the previous data
985
+ map.insert(
986
+ previous_keyframe.value.id().to_owned(),
987
+ previous_keyframe.value.clone(),
988
+ );
989
+ continue;
990
+ };
991
+
992
+ let percentage_between_keyframes =
993
+ (next_keyframe.start_percentage - previous_keyframe.start_percentage).abs();
994
+ let duration_between_keyframes = percentage_between_keyframes * self.duration;
995
+ let direction_aware_prev_keyframe_start_percentage = match self.current_direction {
996
+ AnimationDirection::Normal => previous_keyframe.start_percentage,
997
+ AnimationDirection::Reverse => 1. - previous_keyframe.start_percentage,
998
+ _ => unreachable!(),
999
+ };
1000
+ let progress_between_keyframes = (total_progress
1001
+ - direction_aware_prev_keyframe_start_percentage)
1002
+ / percentage_between_keyframes;
1003
+ let animation = PropertyAnimation {
1004
+ from: previous_keyframe.value.clone(),
1005
+ to: next_keyframe.value.clone(),
1006
+ timing_function: previous_keyframe.timing_function.clone(),
1007
+ duration: duration_between_keyframes,
1008
+ };
1009
+
1010
+ let value = animation.calculate_value(progress_between_keyframes);
1011
+ map.insert(value.id().to_owned(), value);
1012
+ }
1013
+ }
1014
+ }
1015
+
1016
+ impl fmt::Debug for Animation {
1017
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1018
+ f.debug_struct("Animation")
1019
+ .field("name", &self.name)
1020
+ .field("started_at", &self.started_at)
1021
+ .field("duration", &self.duration)
1022
+ .field("delay", &self.delay)
1023
+ .field("iteration_state", &self.iteration_state)
1024
+ .field("state", &self.state)
1025
+ .field("direction", &self.direction)
1026
+ .field("current_direction", &self.current_direction)
1027
+ .field("cascade_style", &())
1028
+ .finish()
1029
+ }
1030
+ }
1031
+
1032
+ /// A CSS Transition
1033
+ #[derive(Clone, Debug, MallocSizeOf)]
1034
+ pub struct Transition {
1035
+ /// The start time of this transition, which is the current value of the animation
1036
+ /// timeline when this transition was created plus any animation delay.
1037
+ pub start_time: f64,
1038
+
1039
+ /// The delay used for this transition.
1040
+ pub delay: f64,
1041
+
1042
+ /// The internal style `PropertyAnimation` for this transition.
1043
+ pub property_animation: PropertyAnimation,
1044
+
1045
+ /// The state of this transition.
1046
+ pub state: AnimationState,
1047
+
1048
+ /// Whether or not this transition is new and or has already been tracked
1049
+ /// by the script thread.
1050
+ pub is_new: bool,
1051
+
1052
+ /// If this `Transition` has been replaced by a new one this field is
1053
+ /// used to help produce better reversed transitions.
1054
+ pub reversing_adjusted_start_value: AnimationValue,
1055
+
1056
+ /// If this `Transition` has been replaced by a new one this field is
1057
+ /// used to help produce better reversed transitions.
1058
+ pub reversing_shortening_factor: f64,
1059
+ }
1060
+
1061
+ impl Transition {
1062
+ fn new(
1063
+ start_time: f64,
1064
+ delay: f64,
1065
+ duration: f64,
1066
+ from: AnimationValue,
1067
+ to: AnimationValue,
1068
+ timing_function: &TimingFunction,
1069
+ ) -> Self {
1070
+ let property_animation = PropertyAnimation {
1071
+ from: from.clone(),
1072
+ to,
1073
+ timing_function: timing_function.clone(),
1074
+ duration,
1075
+ };
1076
+ Self {
1077
+ start_time,
1078
+ delay,
1079
+ property_animation,
1080
+ state: AnimationState::Pending,
1081
+ is_new: true,
1082
+ reversing_adjusted_start_value: from,
1083
+ reversing_shortening_factor: 1.0,
1084
+ }
1085
+ }
1086
+
1087
+ fn update_for_possibly_reversed_transition(
1088
+ &mut self,
1089
+ replaced_transition: &Transition,
1090
+ delay: f64,
1091
+ now: f64,
1092
+ ) {
1093
+ // If we reach here, we need to calculate a reversed transition according to
1094
+ // https://drafts.csswg.org/css-transitions/#starting
1095
+ //
1096
+ // "...if the reversing-adjusted start value of the running transition
1097
+ // is the same as the value of the property in the after-change style (see
1098
+ // the section on reversing of transitions for why these case exists),
1099
+ // implementations must cancel the running transition and start
1100
+ // a new transition..."
1101
+ if replaced_transition.reversing_adjusted_start_value != self.property_animation.to {
1102
+ return;
1103
+ }
1104
+
1105
+ // "* reversing-adjusted start value is the end value of the running transition"
1106
+ let replaced_animation = &replaced_transition.property_animation;
1107
+ self.reversing_adjusted_start_value = replaced_animation.to.clone();
1108
+
1109
+ // "* reversing shortening factor is the absolute value, clamped to the
1110
+ // range [0, 1], of the sum of:
1111
+ // 1. the output of the timing function of the old transition at the
1112
+ // time of the style change event, times the reversing shortening
1113
+ // factor of the old transition
1114
+ // 2. 1 minus the reversing shortening factor of the old transition."
1115
+ let transition_progress = ((now - replaced_transition.start_time)
1116
+ / (replaced_transition.property_animation.duration))
1117
+ .min(1.0)
1118
+ .max(0.0);
1119
+ let timing_function_output = replaced_animation.timing_function_output(transition_progress);
1120
+ let old_reversing_shortening_factor = replaced_transition.reversing_shortening_factor;
1121
+ self.reversing_shortening_factor = ((timing_function_output
1122
+ * old_reversing_shortening_factor)
1123
+ + (1.0 - old_reversing_shortening_factor))
1124
+ .abs()
1125
+ .min(1.0)
1126
+ .max(0.0);
1127
+
1128
+ // "* start time is the time of the style change event plus:
1129
+ // 1. if the matching transition delay is nonnegative, the matching
1130
+ // transition delay, or.
1131
+ // 2. if the matching transition delay is negative, the product of the new
1132
+ // transition’s reversing shortening factor and the matching transition delay,"
1133
+ self.start_time = if delay >= 0. {
1134
+ now + delay
1135
+ } else {
1136
+ now + (self.reversing_shortening_factor * delay)
1137
+ };
1138
+
1139
+ // "* end time is the start time plus the product of the matching transition
1140
+ // duration and the new transition’s reversing shortening factor,"
1141
+ self.property_animation.duration *= self.reversing_shortening_factor;
1142
+
1143
+ // "* start value is the current value of the property in the running transition,
1144
+ // * end value is the value of the property in the after-change style,"
1145
+ let procedure = Procedure::Interpolate {
1146
+ progress: timing_function_output,
1147
+ };
1148
+ match replaced_animation
1149
+ .from
1150
+ .animate(&replaced_animation.to, procedure)
1151
+ {
1152
+ Ok(new_start) => self.property_animation.from = new_start,
1153
+ Err(..) => {},
1154
+ }
1155
+ }
1156
+
1157
+ /// Whether or not this animation has ended at the provided time. This does
1158
+ /// not take into account canceling i.e. when an animation or transition is
1159
+ /// canceled due to changes in the style.
1160
+ pub fn has_ended(&self, time: f64) -> bool {
1161
+ time >= self.start_time + (self.property_animation.duration)
1162
+ }
1163
+
1164
+ /// Update the given animation at a given point of progress.
1165
+ pub fn calculate_value(&self, time: f64) -> AnimationValue {
1166
+ let progress = if time < self.start_time {
1167
+ 0.0
1168
+ } else if self.property_animation.duration == 0.0 {
1169
+ 1.0
1170
+ } else {
1171
+ ((time - self.start_time) / self.property_animation.duration).clamp(0.0, 1.0)
1172
+ };
1173
+
1174
+ self.property_animation.calculate_value(progress)
1175
+ }
1176
+ }
1177
+
1178
+ /// Holds the animation state for a particular element.
1179
+ #[derive(Debug, Default, MallocSizeOf)]
1180
+ pub struct ElementAnimationSet {
1181
+ /// The animations for this element.
1182
+ pub animations: Vec<Animation>,
1183
+
1184
+ /// The transitions for this element.
1185
+ pub transitions: Vec<Transition>,
1186
+
1187
+ /// Whether or not this ElementAnimationSet has had animations or transitions
1188
+ /// which have been added, removed, or had their state changed.
1189
+ pub dirty: bool,
1190
+ }
1191
+
1192
+ impl ElementAnimationSet {
1193
+ /// Cancel all animations in this `ElementAnimationSet`. This is typically called
1194
+ /// when the element has been removed from the DOM.
1195
+ pub fn cancel_all_animations(&mut self) {
1196
+ self.dirty = !self.animations.is_empty();
1197
+ for animation in self.animations.iter_mut() {
1198
+ animation.state = AnimationState::Canceled;
1199
+ }
1200
+ self.cancel_active_transitions();
1201
+ }
1202
+
1203
+ fn cancel_active_transitions(&mut self) {
1204
+ for transition in self.transitions.iter_mut() {
1205
+ if transition.state != AnimationState::Finished {
1206
+ self.dirty = true;
1207
+ transition.state = AnimationState::Canceled;
1208
+ }
1209
+ }
1210
+ }
1211
+
1212
+ /// Apply all active animations.
1213
+ pub fn apply_active_animations(
1214
+ &self,
1215
+ context: &SharedStyleContext,
1216
+ style: &mut Arc<ComputedValues>,
1217
+ ) {
1218
+ let now = context.current_time_for_animations;
1219
+ let mutable_style = Arc::make_mut(style);
1220
+ if let Some(map) = self.get_value_map_for_active_animations(now) {
1221
+ for value in map.values() {
1222
+ value.set_in_style_for_servo(mutable_style, context);
1223
+ }
1224
+ }
1225
+
1226
+ if let Some(map) = self.get_value_map_for_transitions(now, IgnoreTransitions::Canceled) {
1227
+ for value in map.values() {
1228
+ value.set_in_style_for_servo(mutable_style, context);
1229
+ }
1230
+ }
1231
+ }
1232
+
1233
+ /// Clear all canceled animations and transitions from this `ElementAnimationSet`.
1234
+ pub fn clear_canceled_animations(&mut self) {
1235
+ self.animations
1236
+ .retain(|animation| animation.state != AnimationState::Canceled);
1237
+ self.transitions
1238
+ .retain(|animation| animation.state != AnimationState::Canceled);
1239
+ }
1240
+
1241
+ /// Whether this `ElementAnimationSet` is empty, which means it doesn't
1242
+ /// hold any animations in any state.
1243
+ pub fn is_empty(&self) -> bool {
1244
+ self.animations.is_empty() && self.transitions.is_empty()
1245
+ }
1246
+
1247
+ /// Whether or not this state needs animation ticks for its transitions
1248
+ /// or animations.
1249
+ pub fn needs_animation_ticks(&self) -> bool {
1250
+ self.animations
1251
+ .iter()
1252
+ .any(|animation| animation.state.needs_to_be_ticked())
1253
+ || self
1254
+ .transitions
1255
+ .iter()
1256
+ .any(|transition| transition.state.needs_to_be_ticked())
1257
+ }
1258
+
1259
+ /// The number of running animations and transitions for this `ElementAnimationSet`.
1260
+ pub fn running_animation_and_transition_count(&self) -> usize {
1261
+ self.animations
1262
+ .iter()
1263
+ .filter(|animation| animation.state.needs_to_be_ticked())
1264
+ .count()
1265
+ + self
1266
+ .transitions
1267
+ .iter()
1268
+ .filter(|transition| transition.state.needs_to_be_ticked())
1269
+ .count()
1270
+ }
1271
+
1272
+ /// If this `ElementAnimationSet` has any any active animations.
1273
+ pub fn has_active_animation(&self) -> bool {
1274
+ self.animations
1275
+ .iter()
1276
+ .any(|animation| animation.state != AnimationState::Canceled)
1277
+ }
1278
+
1279
+ /// If this `ElementAnimationSet` has any any active transitions.
1280
+ pub fn has_active_transition(&self) -> bool {
1281
+ self.transitions
1282
+ .iter()
1283
+ .any(|transition| transition.state != AnimationState::Canceled)
1284
+ }
1285
+
1286
+ /// Update our animations given a new style, canceling or starting new animations
1287
+ /// when appropriate.
1288
+ pub fn update_animations_for_new_style<E>(
1289
+ &mut self,
1290
+ element: E,
1291
+ context: &SharedStyleContext,
1292
+ new_style: &Arc<ComputedValues>,
1293
+ resolver: &mut StyleResolverForElement<E>,
1294
+ ) where
1295
+ E: TElement,
1296
+ {
1297
+ for animation in self.animations.iter_mut() {
1298
+ if animation.is_cancelled_in_new_style(new_style) {
1299
+ animation.state = AnimationState::Canceled;
1300
+ }
1301
+ }
1302
+
1303
+ maybe_start_animations(element, &context, &new_style, self, resolver);
1304
+ }
1305
+
1306
+ /// Update our transitions given a new style, canceling or starting new animations
1307
+ /// when appropriate.
1308
+ pub fn update_transitions_for_new_style(
1309
+ &mut self,
1310
+ might_need_transitions_update: bool,
1311
+ context: &SharedStyleContext,
1312
+ old_style: Option<&Arc<ComputedValues>>,
1313
+ after_change_style: &Arc<ComputedValues>,
1314
+ ) {
1315
+ // If this is the first style, we don't trigger any transitions and we assume
1316
+ // there were no previously triggered transitions.
1317
+ let mut before_change_style = match old_style {
1318
+ Some(old_style) => Arc::clone(old_style),
1319
+ None => return,
1320
+ };
1321
+
1322
+ // If the style of this element is display:none, then cancel all active transitions.
1323
+ if after_change_style.get_box().clone_display().is_none() {
1324
+ self.cancel_active_transitions();
1325
+ return;
1326
+ }
1327
+
1328
+ if !might_need_transitions_update {
1329
+ return;
1330
+ }
1331
+
1332
+ // We convert old values into `before-change-style` here.
1333
+ if self.has_active_transition() || self.has_active_animation() {
1334
+ self.apply_active_animations(context, &mut before_change_style);
1335
+ }
1336
+
1337
+ let transitioning_properties = start_transitions_if_applicable(
1338
+ context,
1339
+ &before_change_style,
1340
+ after_change_style,
1341
+ self,
1342
+ );
1343
+
1344
+ // Cancel any non-finished transitions that have properties which no
1345
+ // longer transition.
1346
+ //
1347
+ // Step 3 in https://drafts.csswg.org/css-transitions/#starting:
1348
+ // > If the element has a running transition or completed transition for
1349
+ // > the property, and there is not a matching transition-property value,
1350
+ // > then implementations must cancel the running transition or remove the
1351
+ // > completed transition from the set of completed transitions.
1352
+ //
1353
+ // TODO: This is happening here as opposed to in
1354
+ // `start_transition_if_applicable` as an optimization, but maybe this
1355
+ // code should be reworked to be more like the specification.
1356
+ for transition in self.transitions.iter_mut() {
1357
+ if transition.state == AnimationState::Finished
1358
+ || transition.state == AnimationState::Canceled
1359
+ {
1360
+ continue;
1361
+ }
1362
+ if transitioning_properties.contains(transition.property_animation.property_id()) {
1363
+ continue;
1364
+ }
1365
+ transition.state = AnimationState::Canceled;
1366
+ self.dirty = true;
1367
+ }
1368
+ }
1369
+
1370
+ fn start_transition_if_applicable(
1371
+ &mut self,
1372
+ context: &SharedStyleContext,
1373
+ property_declaration_id: &PropertyDeclarationId,
1374
+ index: usize,
1375
+ old_style: &ComputedValues,
1376
+ new_style: &Arc<ComputedValues>,
1377
+ ) {
1378
+ let style = new_style.get_ui();
1379
+ let allow_discrete =
1380
+ style.transition_behavior_mod(index) == TransitionBehavior::AllowDiscrete;
1381
+
1382
+ // FIXME(emilio): Handle the case where old_style and new_style's writing mode differ.
1383
+ let Some(from) = AnimationValue::from_computed_values(*property_declaration_id, old_style)
1384
+ else {
1385
+ return;
1386
+ };
1387
+ let Some(to) = AnimationValue::from_computed_values(*property_declaration_id, new_style)
1388
+ else {
1389
+ return;
1390
+ };
1391
+
1392
+ let timing_function = style.transition_timing_function_mod(index);
1393
+ let duration = style.transition_duration_mod(index).seconds() as f64;
1394
+ let delay = style.transition_delay_mod(index).seconds() as f64;
1395
+ let now = context.current_time_for_animations;
1396
+ let transitionable = property_declaration_id.is_animatable()
1397
+ && (allow_discrete || !property_declaration_id.is_discrete_animatable())
1398
+ && (allow_discrete || from.interpolable_with(&to));
1399
+
1400
+ let mut existing_transition = self.transitions.iter_mut().find(|transition| {
1401
+ transition.property_animation.property_id() == *property_declaration_id
1402
+ });
1403
+
1404
+ // Step 1:
1405
+ // > If all of the following are true:
1406
+ // > - the element does not have a running transition for the property,
1407
+ // > - the before-change style is different from the after-change style
1408
+ // > for that property, and the values for the property are
1409
+ // > transitionable,
1410
+ // > - the element does not have a completed transition for the property
1411
+ // > or the end value of the completed transition is different from the
1412
+ // > after-change style for the property,
1413
+ // > - there is a matching transition-property value, and
1414
+ // > - the combined duration is greater than 0s,
1415
+ //
1416
+ // This function is only run if there is a matching transition-property
1417
+ // value, so that check is skipped here.
1418
+ let has_running_transition = existing_transition.as_ref().is_some_and(|transition| {
1419
+ transition.state != AnimationState::Finished
1420
+ && transition.state != AnimationState::Canceled
1421
+ });
1422
+ let no_completed_transition_or_end_values_differ =
1423
+ existing_transition.as_ref().is_none_or(|transition| {
1424
+ transition.state != AnimationState::Finished
1425
+ || transition.property_animation.to != to
1426
+ });
1427
+ if !has_running_transition
1428
+ && from != to
1429
+ && transitionable
1430
+ && no_completed_transition_or_end_values_differ
1431
+ && (duration + delay > 0.0)
1432
+ {
1433
+ // > then implementations must remove the completed transition (if
1434
+ // > present) from the set of completed transitions and start a
1435
+ // > transition whose:
1436
+ // >
1437
+ // > - start time is the time of the style change event plus the matching transition delay,
1438
+ // > - end time is the start time plus the matching transition duration,
1439
+ // > - start value is the value of the transitioning property in the before-change style,
1440
+ // > - end value is the value of the transitioning property in the after-change style,
1441
+ // > - reversing-adjusted start value is the same as the start value, and
1442
+ // > - reversing shortening factor is 1.
1443
+ self.transitions.push(Transition::new(
1444
+ now + delay, /* start_time */
1445
+ delay,
1446
+ duration,
1447
+ from,
1448
+ to,
1449
+ &timing_function,
1450
+ ));
1451
+ self.dirty = true;
1452
+ return;
1453
+ }
1454
+
1455
+ // > Step 2: Otherwise, if the element has a completed transition for the
1456
+ // > property and the end value of the completed transition is different
1457
+ // > from the after-change style for the property, then implementations
1458
+ // > must remove the completed transition from the set of completed
1459
+ // > transitions.
1460
+ //
1461
+ // All completed transitions will be cleared from the `AnimationSet` in
1462
+ // `process_animations_for_style in `matching.rs`.
1463
+
1464
+ // > Step 3: If the element has a running transition or completed
1465
+ // > transition for the property, and there is not a matching
1466
+ // > transition-property value, then implementations must cancel the
1467
+ // > running transition or remove the completed transition from the set
1468
+ // > of completed transitions.
1469
+ //
1470
+ // - All completed transitions will be cleared cleared from the `AnimationSet` in
1471
+ // `process_animations_for_style in `matching.rs`.
1472
+ // - Transitions for properties that don't have a matching transition-property
1473
+ // value will be canceled in `Self::update_transitions_for_new_style`. In addition,
1474
+ // this method is only called for properties that do ahave a matching
1475
+ // transition-property value.
1476
+
1477
+ let Some(existing_transition) = existing_transition.as_mut() else {
1478
+ return;
1479
+ };
1480
+
1481
+ // > Step 4: If the element has a running transition for the property,
1482
+ // > there is a matching transition-property value, and the end value of
1483
+ // > the running transition is not equal to the value of the property in
1484
+ // > the after-change style, then:
1485
+ if has_running_transition && existing_transition.property_animation.to != to {
1486
+ // > Step 4.1: If the current value of the property in the running transition is
1487
+ // > equal to the value of the property in the after-change style, or
1488
+ // > if these two values are not transitionable, then implementations
1489
+ // > must cancel the running transition.
1490
+ let current_value = existing_transition.calculate_value(now);
1491
+ let transitionable_from_current_value =
1492
+ transitionable && (allow_discrete || current_value.interpolable_with(&to));
1493
+ if current_value == to || !transitionable_from_current_value {
1494
+ existing_transition.state = AnimationState::Canceled;
1495
+ self.dirty = true;
1496
+ return;
1497
+ }
1498
+
1499
+ // > Step 4.2: Otherwise, if the combined duration is less than or
1500
+ // > equal to 0s, or if the current value of the property in the
1501
+ // > running transition is not transitionable with the value of the
1502
+ // > property in the after-change style, then implementations must
1503
+ // > cancel the running transition.
1504
+ if duration + delay <= 0.0 {
1505
+ existing_transition.state = AnimationState::Canceled;
1506
+ self.dirty = true;
1507
+ return;
1508
+ }
1509
+
1510
+ // > Step 4.3: Otherwise, if the reversing-adjusted start value of the
1511
+ // > running transition is the same as the value of the property in
1512
+ // > the after-change style (see the section on reversing of
1513
+ // > transitions for why these case exists), implementations must
1514
+ // > cancel the running transition and start a new transition whose:
1515
+ if existing_transition.reversing_adjusted_start_value == to {
1516
+ existing_transition.state = AnimationState::Canceled;
1517
+
1518
+ let mut transition = Transition::new(
1519
+ now + delay, /* start_time */
1520
+ delay,
1521
+ duration,
1522
+ from,
1523
+ to,
1524
+ &timing_function,
1525
+ );
1526
+
1527
+ // This function takes care of applying all of the modifications to the transition
1528
+ // after "whose:" above.
1529
+ transition.update_for_possibly_reversed_transition(
1530
+ &existing_transition,
1531
+ delay,
1532
+ now,
1533
+ );
1534
+
1535
+ self.transitions.push(transition);
1536
+ self.dirty = true;
1537
+ return;
1538
+ }
1539
+
1540
+ // > Step 4.4: Otherwise, implementations must cancel the running
1541
+ // > transition and start a new transition whose:
1542
+ // > - start time is the time of the style change event plus the matching transition delay,
1543
+ // > - end time is the start time plus the matching transition duration,
1544
+ // > - start value is the current value of the property in the running transition,
1545
+ // > - end value is the value of the property in the after-change style,
1546
+ // > - reversing-adjusted start value is the same as the start value, and
1547
+ // > - reversing shortening factor is 1.
1548
+ existing_transition.state = AnimationState::Canceled;
1549
+ self.transitions.push(Transition::new(
1550
+ now + delay, /* start_time */
1551
+ delay,
1552
+ duration,
1553
+ current_value,
1554
+ to,
1555
+ &timing_function,
1556
+ ));
1557
+ self.dirty = true;
1558
+ }
1559
+ }
1560
+
1561
+ /// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
1562
+ /// transitions, ignoring those specified by the `ignore_transitions`
1563
+ /// argument.
1564
+ fn get_value_map_for_transitions(
1565
+ &self,
1566
+ now: f64,
1567
+ ignore_transitions: IgnoreTransitions,
1568
+ ) -> Option<AnimationValueMap> {
1569
+ if !self.has_active_transition() {
1570
+ return None;
1571
+ }
1572
+
1573
+ let mut map =
1574
+ AnimationValueMap::with_capacity_and_hasher(self.transitions.len(), Default::default());
1575
+ for transition in &self.transitions {
1576
+ match ignore_transitions {
1577
+ IgnoreTransitions::Canceled => {
1578
+ if transition.state == AnimationState::Canceled {
1579
+ continue;
1580
+ }
1581
+ },
1582
+ IgnoreTransitions::CanceledAndFinished => {
1583
+ if transition.state == AnimationState::Canceled
1584
+ || transition.state == AnimationState::Finished
1585
+ {
1586
+ continue;
1587
+ }
1588
+ },
1589
+ }
1590
+
1591
+ let value = transition.calculate_value(now);
1592
+ map.insert(value.id().to_owned(), value);
1593
+ }
1594
+
1595
+ Some(map)
1596
+ }
1597
+
1598
+ /// Generate a `AnimationValueMap` for this `ElementAnimationSet`'s
1599
+ /// active animations at the given time value.
1600
+ pub fn get_value_map_for_active_animations(&self, now: f64) -> Option<AnimationValueMap> {
1601
+ if !self.has_active_animation() {
1602
+ return None;
1603
+ }
1604
+
1605
+ let mut map = Default::default();
1606
+ for animation in &self.animations {
1607
+ animation.get_property_declaration_at_time(now, &mut map);
1608
+ }
1609
+
1610
+ Some(map)
1611
+ }
1612
+ }
1613
+
1614
+ #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
1615
+ /// A key that is used to identify nodes in the `DocumentAnimationSet`.
1616
+ pub struct AnimationSetKey {
1617
+ /// The node for this `AnimationSetKey`.
1618
+ pub node: OpaqueNode,
1619
+ /// The pseudo element for this `AnimationSetKey`. If `None` this key will
1620
+ /// refer to the main content for its node.
1621
+ pub pseudo_element: Option<PseudoElement>,
1622
+ }
1623
+
1624
+ impl AnimationSetKey {
1625
+ /// Create a new key given a node and optional pseudo element.
1626
+ pub fn new(node: OpaqueNode, pseudo_element: Option<PseudoElement>) -> Self {
1627
+ AnimationSetKey {
1628
+ node,
1629
+ pseudo_element,
1630
+ }
1631
+ }
1632
+
1633
+ /// Create a new key for the main content of this node.
1634
+ pub fn new_for_non_pseudo(node: OpaqueNode) -> Self {
1635
+ AnimationSetKey {
1636
+ node,
1637
+ pseudo_element: None,
1638
+ }
1639
+ }
1640
+
1641
+ /// Create a new key for given node and pseudo element.
1642
+ pub fn new_for_pseudo(node: OpaqueNode, pseudo_element: PseudoElement) -> Self {
1643
+ AnimationSetKey {
1644
+ node,
1645
+ pseudo_element: Some(pseudo_element),
1646
+ }
1647
+ }
1648
+ }
1649
+
1650
+ #[derive(Clone, Debug, Default, MallocSizeOf)]
1651
+ /// A set of animations for a document.
1652
+ pub struct DocumentAnimationSet {
1653
+ /// The `ElementAnimationSet`s that this set contains.
1654
+ #[ignore_malloc_size_of = "Arc is hard"]
1655
+ pub sets: Arc<RwLock<FxHashMap<AnimationSetKey, ElementAnimationSet>>>,
1656
+ }
1657
+
1658
+ impl DocumentAnimationSet {
1659
+ /// Return whether or not the provided node has active CSS animations.
1660
+ pub fn has_active_animations(&self, key: &AnimationSetKey) -> bool {
1661
+ self.sets
1662
+ .read()
1663
+ .get(key)
1664
+ .map_or(false, |set| set.has_active_animation())
1665
+ }
1666
+
1667
+ /// Return whether or not the provided node has active CSS transitions.
1668
+ pub fn has_active_transitions(&self, key: &AnimationSetKey) -> bool {
1669
+ self.sets
1670
+ .read()
1671
+ .get(key)
1672
+ .map_or(false, |set| set.has_active_transition())
1673
+ }
1674
+
1675
+ /// Return a locked PropertyDeclarationBlock with animation values for the given
1676
+ /// key and time.
1677
+ pub fn get_animation_declarations(
1678
+ &self,
1679
+ key: &AnimationSetKey,
1680
+ time: f64,
1681
+ shared_lock: &SharedRwLock,
1682
+ ) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
1683
+ self.sets
1684
+ .read()
1685
+ .get(key)
1686
+ .and_then(|set| set.get_value_map_for_active_animations(time))
1687
+ .map(|map| {
1688
+ let block = PropertyDeclarationBlock::from_animation_value_map(&map);
1689
+ Arc::new(shared_lock.wrap(block))
1690
+ })
1691
+ }
1692
+
1693
+ /// Return a locked PropertyDeclarationBlock with transition values for the given
1694
+ /// key and time.
1695
+ pub fn get_transition_declarations(
1696
+ &self,
1697
+ key: &AnimationSetKey,
1698
+ time: f64,
1699
+ shared_lock: &SharedRwLock,
1700
+ ) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
1701
+ self.sets
1702
+ .read()
1703
+ .get(key)
1704
+ .and_then(|set| {
1705
+ set.get_value_map_for_transitions(time, IgnoreTransitions::CanceledAndFinished)
1706
+ })
1707
+ .map(|map| {
1708
+ let block = PropertyDeclarationBlock::from_animation_value_map(&map);
1709
+ Arc::new(shared_lock.wrap(block))
1710
+ })
1711
+ }
1712
+
1713
+ /// Get all the animation declarations for the given key, returning an empty
1714
+ /// `AnimationDeclarations` if there are no animations.
1715
+ pub fn get_all_declarations(
1716
+ &self,
1717
+ key: &AnimationSetKey,
1718
+ time: f64,
1719
+ shared_lock: &SharedRwLock,
1720
+ ) -> AnimationDeclarations {
1721
+ let sets = self.sets.read();
1722
+ let set = match sets.get(key) {
1723
+ Some(set) => set,
1724
+ None => return Default::default(),
1725
+ };
1726
+
1727
+ let animations = set.get_value_map_for_active_animations(time).map(|map| {
1728
+ let block = PropertyDeclarationBlock::from_animation_value_map(&map);
1729
+ Arc::new(shared_lock.wrap(block))
1730
+ });
1731
+ let transitions = set
1732
+ .get_value_map_for_transitions(time, IgnoreTransitions::CanceledAndFinished)
1733
+ .map(|map| {
1734
+ let block = PropertyDeclarationBlock::from_animation_value_map(&map);
1735
+ Arc::new(shared_lock.wrap(block))
1736
+ });
1737
+ AnimationDeclarations {
1738
+ animations,
1739
+ transitions,
1740
+ }
1741
+ }
1742
+
1743
+ /// Cancel all animations for set at the given key.
1744
+ pub fn cancel_all_animations_for_key(&self, key: &AnimationSetKey) {
1745
+ if let Some(set) = self.sets.write().get_mut(key) {
1746
+ set.cancel_all_animations();
1747
+ }
1748
+ }
1749
+ }
1750
+
1751
+ /// Kick off any new transitions for this node and return all of the properties that are
1752
+ /// transitioning. This is at the end of calculating style for a single node.
1753
+ pub fn start_transitions_if_applicable(
1754
+ context: &SharedStyleContext,
1755
+ old_style: &ComputedValues,
1756
+ new_style: &Arc<ComputedValues>,
1757
+ animation_state: &mut ElementAnimationSet,
1758
+ ) -> PropertyDeclarationIdSet {
1759
+ // See <https://www.w3.org/TR/css-transitions-1/#transitions>
1760
+ // "If a property is specified multiple times in the value of transition-property
1761
+ // (either on its own, via a shorthand that contains it, or via the all value),
1762
+ // then the transition that starts uses the duration, delay, and timing function
1763
+ // at the index corresponding to the last item in the value of transition-property
1764
+ // that calls for animating that property."
1765
+ // See Example 3 of <https://www.w3.org/TR/css-transitions-1/#transitions>
1766
+ //
1767
+ // Reversing the transition order here means that transitions defined later in the list
1768
+ // have preference, in accordance with the specification.
1769
+ //
1770
+ // TODO: It would be better to be able to do this without having to allocate an array.
1771
+ // We should restructure the code or make `transition_properties()` return a reversible
1772
+ // iterator in order to avoid the allocation.
1773
+ let mut transition_properties = new_style.transition_properties().collect::<Vec<_>>();
1774
+ transition_properties.reverse();
1775
+
1776
+ let mut properties_that_transition = PropertyDeclarationIdSet::default();
1777
+ for transition in transition_properties {
1778
+ let physical_property = transition
1779
+ .property
1780
+ .as_borrowed()
1781
+ .to_physical(new_style.writing_mode);
1782
+ if properties_that_transition.contains(physical_property) {
1783
+ continue;
1784
+ }
1785
+
1786
+ properties_that_transition.insert(physical_property);
1787
+ animation_state.start_transition_if_applicable(
1788
+ context,
1789
+ &physical_property,
1790
+ transition.index,
1791
+ old_style,
1792
+ new_style,
1793
+ );
1794
+ }
1795
+
1796
+ properties_that_transition
1797
+ }
1798
+
1799
+ /// Triggers animations for a given node looking at the animation property
1800
+ /// values.
1801
+ pub fn maybe_start_animations<E>(
1802
+ element: E,
1803
+ context: &SharedStyleContext,
1804
+ new_style: &Arc<ComputedValues>,
1805
+ animation_state: &mut ElementAnimationSet,
1806
+ resolver: &mut StyleResolverForElement<E>,
1807
+ ) where
1808
+ E: TElement,
1809
+ {
1810
+ let style = new_style.get_ui();
1811
+ for (i, name) in style.animation_name_iter().enumerate() {
1812
+ let name = match name.as_atom() {
1813
+ Some(atom) => atom,
1814
+ None => continue,
1815
+ };
1816
+
1817
+ debug!("maybe_start_animations: name={}", name);
1818
+ let duration = style.animation_duration_mod(i).seconds() as f64;
1819
+ if duration == 0. {
1820
+ continue;
1821
+ }
1822
+
1823
+ let Some(keyframe_animation) = context.stylist.lookup_keyframes(name, element) else {
1824
+ continue;
1825
+ };
1826
+
1827
+ debug!("maybe_start_animations: animation {} found", name);
1828
+
1829
+ // NB: This delay may be negative, meaning that the animation may be created
1830
+ // in a state where we have advanced one or more iterations or even that the
1831
+ // animation begins in a finished state.
1832
+ let delay = style.animation_delay_mod(i).seconds() as f64;
1833
+
1834
+ let iteration_count = style.animation_iteration_count_mod(i);
1835
+ let iteration_state = if iteration_count.0.is_infinite() {
1836
+ KeyframesIterationState::Infinite(0.0)
1837
+ } else {
1838
+ KeyframesIterationState::Finite(0.0, iteration_count.0 as f64)
1839
+ };
1840
+
1841
+ let animation_direction = style.animation_direction_mod(i);
1842
+
1843
+ let initial_direction = match animation_direction {
1844
+ AnimationDirection::Normal | AnimationDirection::Alternate => {
1845
+ AnimationDirection::Normal
1846
+ },
1847
+ AnimationDirection::Reverse | AnimationDirection::AlternateReverse => {
1848
+ AnimationDirection::Reverse
1849
+ },
1850
+ };
1851
+
1852
+ let now = context.current_time_for_animations;
1853
+ let started_at = now + delay;
1854
+ let starting_progress = (now - started_at) / duration;
1855
+ let state = match style.animation_play_state_mod(i) {
1856
+ AnimationPlayState::Paused => AnimationState::Paused(starting_progress),
1857
+ AnimationPlayState::Running => AnimationState::Pending,
1858
+ };
1859
+
1860
+ // Determine the set of animating properties. This is not equivalent to the set of changed properties
1861
+ // when one changed property overrides another. (For example, "block-size" with writing-mode: initial
1862
+ // is the same as "height")
1863
+ let mut animating_properties = PropertyDeclarationIdSet::default();
1864
+ let mut number_of_animating_properties = 0;
1865
+ for property in keyframe_animation.properties_changed.iter() {
1866
+ debug_assert!(property.is_animatable());
1867
+
1868
+ if animating_properties.insert(property.to_physical(new_style.writing_mode)) {
1869
+ number_of_animating_properties += 1;
1870
+ }
1871
+ }
1872
+
1873
+ let computed_steps = ComputedKeyframe::generate_for_keyframes(
1874
+ element,
1875
+ &keyframe_animation,
1876
+ context,
1877
+ new_style,
1878
+ style.animation_timing_function_mod(i),
1879
+ style.animation_composition_mod(i),
1880
+ resolver,
1881
+ animating_properties,
1882
+ number_of_animating_properties,
1883
+ );
1884
+
1885
+ let mut new_animation = Animation {
1886
+ name: name.clone(),
1887
+ properties_changed: keyframe_animation.properties_changed.clone(),
1888
+ computed_steps,
1889
+ started_at,
1890
+ duration,
1891
+ fill_mode: style.animation_fill_mode_mod(i),
1892
+ delay,
1893
+ iteration_state,
1894
+ state,
1895
+ direction: animation_direction,
1896
+ current_direction: initial_direction,
1897
+ number_of_animating_properties,
1898
+ is_new: true,
1899
+ };
1900
+
1901
+ // If we started with a negative delay, make sure we iterate the animation if
1902
+ // the delay moves us past the first iteration.
1903
+ new_animation.iterate_by(starting_progress);
1904
+
1905
+ animation_state.dirty = true;
1906
+
1907
+ // If the animation was already present in the list for the node, just update its state.
1908
+ for existing_animation in animation_state.animations.iter_mut() {
1909
+ if existing_animation.state == AnimationState::Canceled {
1910
+ continue;
1911
+ }
1912
+
1913
+ if new_animation.name == existing_animation.name {
1914
+ existing_animation
1915
+ .update_from_other(&new_animation, context.current_time_for_animations);
1916
+ return;
1917
+ }
1918
+ }
1919
+
1920
+ animation_state.animations.push(new_animation);
1921
+ }
1922
+ }