blitz-pdf 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (370) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +355 -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,4241 @@
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
+ //! Manual shorthand parsing and serialization
6
+ #![allow(missing_docs)]
7
+
8
+ use crate::parser::{Parse, ParserContext};
9
+ use crate::values::specified;
10
+ use cssparser::Parser;
11
+ use std::fmt::{self, Write};
12
+ use style_traits::{
13
+ values::SequenceWriter, CssWriter, KeywordsCollectFn, ParseError, SpecifiedValueInfo,
14
+ StyleParseErrorKind, ToCss,
15
+ };
16
+
17
+ macro_rules! expanded {
18
+ ( $( $name: ident: $value: expr ),+ ) => {
19
+ expanded!( $( $name: $value, )+ )
20
+ };
21
+ ( $( $name: ident: $value: expr, )+ ) => {
22
+ Longhands {
23
+ $(
24
+ $name: $crate::properties::MaybeBoxed::maybe_boxed($value),
25
+ )+
26
+ }
27
+ }
28
+ }
29
+ pub(crate) use expanded;
30
+
31
+ macro_rules! try_parse_one {
32
+ ($context: expr, $input: expr, $var: ident, $parse_path: path) => {
33
+ if $var.is_none() {
34
+ if let Ok(value) = $input.try_parse(|i| $parse_path($context, i)) {
35
+ $var = Some(value);
36
+ continue;
37
+ }
38
+ }
39
+ };
40
+ ($input: expr, $var: ident, $parse_path: path) => {
41
+ if $var.is_none() {
42
+ if let Ok(value) = $input.try_parse(|i| $parse_path(i)) {
43
+ $var = Some(value);
44
+ continue;
45
+ }
46
+ }
47
+ };
48
+ }
49
+
50
+ macro_rules! unwrap_or_initial {
51
+ ($prop: ident) => {
52
+ unwrap_or_initial!($prop, $prop)
53
+ };
54
+ ($prop: ident, $expr: expr) => {
55
+ $expr.unwrap_or_else(|| $prop::get_initial_specified_value())
56
+ };
57
+ }
58
+
59
+ /// Serializes a border shorthand value composed of width/style/color.
60
+ pub fn serialize_directional_border<W>(
61
+ dest: &mut CssWriter<W>,
62
+ width: &specified::BorderSideWidth,
63
+ style: &specified::BorderStyle,
64
+ color: &specified::Color,
65
+ ) -> fmt::Result
66
+ where
67
+ W: Write,
68
+ {
69
+ use specified::{BorderSideWidth, BorderStyle, Color};
70
+ let has_style = *style != BorderStyle::None;
71
+ let has_color = *color != Color::CurrentColor;
72
+ let has_width = *width != BorderSideWidth::medium();
73
+ if !has_style && !has_color && !has_width {
74
+ return width.to_css(dest);
75
+ }
76
+ let mut writer = SequenceWriter::new(dest, " ");
77
+ if has_width {
78
+ writer.item(width)?;
79
+ }
80
+ if has_style {
81
+ writer.item(style)?;
82
+ }
83
+ if has_color {
84
+ writer.item(color)?;
85
+ }
86
+ Ok(())
87
+ }
88
+
89
+ pub fn parse_border(
90
+ context: &ParserContext,
91
+ input: &mut Parser,
92
+ ) -> Result<
93
+ (
94
+ specified::BorderSideWidth,
95
+ specified::BorderStyle,
96
+ specified::Color,
97
+ ),
98
+ ParseError,
99
+ > {
100
+ use crate::values::specified::{BorderSideWidth, BorderStyle, Color};
101
+ let mut color = None;
102
+ let mut style = None;
103
+ let mut width = None;
104
+ let mut parsed = 0;
105
+ loop {
106
+ parsed += 1;
107
+ try_parse_one!(context, input, width, BorderSideWidth::parse);
108
+ try_parse_one!(input, style, BorderStyle::parse);
109
+ try_parse_one!(context, input, color, Color::parse);
110
+ parsed -= 1;
111
+ break;
112
+ }
113
+ if parsed == 0 {
114
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
115
+ }
116
+ Ok((
117
+ width.unwrap_or(BorderSideWidth::medium()),
118
+ style.unwrap_or(BorderStyle::None),
119
+ color.unwrap_or(Color::CurrentColor),
120
+ ))
121
+ }
122
+
123
+ pub mod border_block {
124
+ use super::*;
125
+ pub use crate::properties::generated::shorthands::border_block::*;
126
+
127
+ pub fn parse_value(
128
+ context: &ParserContext,
129
+ input: &mut Parser,
130
+ ) -> Result<Longhands, ParseError> {
131
+ let (width, style, color) = super::parse_border(context, input)?;
132
+ Ok(Longhands {
133
+ border_block_start_width: width.clone(),
134
+ border_block_start_style: style,
135
+ border_block_start_color: color.clone(),
136
+ border_block_end_width: width,
137
+ border_block_end_style: style,
138
+ border_block_end_color: color,
139
+ })
140
+ }
141
+
142
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
143
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
144
+ where
145
+ W: fmt::Write,
146
+ {
147
+ // FIXME: Should serialize empty if start != end, right?
148
+ super::serialize_directional_border(
149
+ dest,
150
+ self.border_block_start_width,
151
+ self.border_block_start_style,
152
+ self.border_block_start_color,
153
+ )
154
+ }
155
+ }
156
+ }
157
+
158
+ pub mod border_inline {
159
+ use super::*;
160
+ pub use crate::properties::generated::shorthands::border_inline::*;
161
+
162
+ pub fn parse_value(
163
+ context: &ParserContext,
164
+ input: &mut Parser,
165
+ ) -> Result<Longhands, ParseError> {
166
+ let (width, style, color) = super::parse_border(context, input)?;
167
+ Ok(Longhands {
168
+ border_inline_start_width: width.clone(),
169
+ border_inline_start_style: style,
170
+ border_inline_start_color: color.clone(),
171
+ border_inline_end_width: width,
172
+ border_inline_end_style: style,
173
+ border_inline_end_color: color,
174
+ })
175
+ }
176
+
177
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
178
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
179
+ where
180
+ W: fmt::Write,
181
+ {
182
+ // FIXME: Should serialize empty if start != end, right?
183
+ super::serialize_directional_border(
184
+ dest,
185
+ self.border_inline_start_width,
186
+ self.border_inline_start_style,
187
+ self.border_inline_start_color,
188
+ )
189
+ }
190
+ }
191
+ }
192
+
193
+ pub mod border_radius {
194
+ pub use crate::properties::generated::shorthands::border_radius::*;
195
+
196
+ use super::*;
197
+ use crate::values::generics::border::BorderCornerRadius;
198
+ use crate::values::generics::rect::Rect;
199
+ use crate::values::specified::BorderRadius;
200
+
201
+ pub fn parse_value(
202
+ context: &ParserContext,
203
+ input: &mut Parser,
204
+ ) -> Result<Longhands, ParseError> {
205
+ let radii = BorderRadius::parse(context, input)?;
206
+ Ok(expanded! {
207
+ border_top_left_radius: radii.top_left,
208
+ border_top_right_radius: radii.top_right,
209
+ border_bottom_right_radius: radii.bottom_right,
210
+ border_bottom_left_radius: radii.bottom_left,
211
+ })
212
+ }
213
+
214
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
215
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
216
+ where
217
+ W: fmt::Write,
218
+ {
219
+ let LonghandsToSerialize {
220
+ border_top_left_radius: BorderCornerRadius(tl),
221
+ border_top_right_radius: BorderCornerRadius(tr),
222
+ border_bottom_right_radius: BorderCornerRadius(br),
223
+ border_bottom_left_radius: BorderCornerRadius(bl),
224
+ } = *self;
225
+
226
+ let widths = Rect::new(tl.width(), tr.width(), br.width(), bl.width());
227
+ let heights = Rect::new(tl.height(), tr.height(), br.height(), bl.height());
228
+
229
+ BorderRadius::serialize_rects(widths, heights, dest)
230
+ }
231
+ }
232
+ }
233
+
234
+ pub mod corner_shape {
235
+ pub use crate::properties::generated::shorthands::corner_shape::*;
236
+
237
+ use super::*;
238
+ use crate::values::generics::rect::Rect;
239
+ use crate::values::specified::CornerShape;
240
+
241
+ /// Parses 1-4 `<corner-shape-value>` tokens with the standard CSS 4-side
242
+ /// shorthand expansion (top, right, bottom, left).
243
+ pub fn parse_value(
244
+ context: &ParserContext,
245
+ input: &mut Parser,
246
+ ) -> Result<Longhands, ParseError> {
247
+ let rect = Rect::parse_with(context, input, CornerShape::parse)?;
248
+ Ok(expanded! {
249
+ corner_top_left_shape: rect.0,
250
+ corner_top_right_shape: rect.1,
251
+ corner_bottom_right_shape: rect.2,
252
+ corner_bottom_left_shape: rect.3,
253
+ })
254
+ }
255
+
256
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
257
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
258
+ where
259
+ W: fmt::Write,
260
+ {
261
+ Rect::new(
262
+ self.corner_top_left_shape,
263
+ self.corner_top_right_shape,
264
+ self.corner_bottom_right_shape,
265
+ self.corner_bottom_left_shape,
266
+ )
267
+ .to_css(dest)
268
+ }
269
+ }
270
+ }
271
+
272
+ pub mod border_image {
273
+ pub use crate::properties::generated::shorthands::border_image::*;
274
+
275
+ use super::*;
276
+ use crate::properties::longhands::{
277
+ border_image_outset, border_image_repeat, border_image_slice, border_image_source,
278
+ border_image_width,
279
+ };
280
+
281
+ pub fn parse_value(
282
+ context: &ParserContext,
283
+ input: &mut Parser,
284
+ ) -> Result<Longhands, ParseError> {
285
+ let mut outset = border_image_outset::get_initial_specified_value();
286
+ let mut repeat = border_image_repeat::get_initial_specified_value();
287
+ let mut slice = border_image_slice::get_initial_specified_value();
288
+ let mut source = border_image_source::get_initial_specified_value();
289
+ let mut width = border_image_width::get_initial_specified_value();
290
+ let mut any = false;
291
+ let mut parsed_slice = false;
292
+ let mut parsed_source = false;
293
+ let mut parsed_repeat = false;
294
+ loop {
295
+ if !parsed_slice {
296
+ if let Ok(value) =
297
+ input.try_parse(|input| border_image_slice::parse(context, input))
298
+ {
299
+ parsed_slice = true;
300
+ any = true;
301
+ slice = value;
302
+ // Parse border image width and outset, if applicable.
303
+ let maybe_width_outset: Result<_, ParseError> = input.try_parse(|input| {
304
+ input.expect_delim('/')?;
305
+
306
+ // Parse border image width, if applicable.
307
+ let w = input
308
+ .try_parse(|input| border_image_width::parse(context, input))
309
+ .ok();
310
+
311
+ // Parse border image outset if applicable.
312
+ let o = input
313
+ .try_parse(|input| {
314
+ input.expect_delim('/')?;
315
+ border_image_outset::parse(context, input)
316
+ })
317
+ .ok();
318
+ if w.is_none() && o.is_none() {
319
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
320
+ }
321
+ Ok((w, o))
322
+ });
323
+ if let Ok((w, o)) = maybe_width_outset {
324
+ if let Some(w) = w {
325
+ width = w;
326
+ }
327
+ if let Some(o) = o {
328
+ outset = o;
329
+ }
330
+ }
331
+ continue;
332
+ }
333
+ }
334
+ if !parsed_source {
335
+ if let Ok(value) =
336
+ input.try_parse(|input| border_image_source::parse(context, input))
337
+ {
338
+ source = value;
339
+ parsed_source = true;
340
+ any = true;
341
+ continue;
342
+ }
343
+ }
344
+ if !parsed_repeat {
345
+ if let Ok(value) =
346
+ input.try_parse(|input| border_image_repeat::parse(context, input))
347
+ {
348
+ repeat = value;
349
+ parsed_repeat = true;
350
+ any = true;
351
+ continue;
352
+ }
353
+ }
354
+ break;
355
+ }
356
+ if !any {
357
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
358
+ }
359
+ Ok(expanded! {
360
+ border_image_outset: outset,
361
+ border_image_repeat: repeat,
362
+ border_image_slice: slice,
363
+ border_image_source: source,
364
+ border_image_width: width,
365
+ })
366
+ }
367
+
368
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
369
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
370
+ where
371
+ W: fmt::Write,
372
+ {
373
+ let mut has_any = false;
374
+ let has_source =
375
+ *self.border_image_source != border_image_source::get_initial_specified_value();
376
+ has_any = has_any || has_source;
377
+ let has_slice =
378
+ *self.border_image_slice != border_image_slice::get_initial_specified_value();
379
+ has_any = has_any || has_slice;
380
+ let has_outset =
381
+ *self.border_image_outset != border_image_outset::get_initial_specified_value();
382
+ has_any = has_any || has_outset;
383
+ let has_width =
384
+ *self.border_image_width != border_image_width::get_initial_specified_value();
385
+ has_any = has_any || has_width;
386
+ let has_repeat =
387
+ *self.border_image_repeat != border_image_repeat::get_initial_specified_value();
388
+ has_any = has_any || has_repeat;
389
+ if has_source || !has_any {
390
+ self.border_image_source.to_css(dest)?;
391
+ if !has_any {
392
+ return Ok(());
393
+ }
394
+ }
395
+ let needs_slice = has_slice || has_width || has_outset;
396
+ if needs_slice {
397
+ if has_source {
398
+ dest.write_char(' ')?;
399
+ }
400
+ self.border_image_slice.to_css(dest)?;
401
+ if has_width || has_outset {
402
+ dest.write_str(" /")?;
403
+ if has_width {
404
+ dest.write_char(' ')?;
405
+ self.border_image_width.to_css(dest)?;
406
+ }
407
+ if has_outset {
408
+ dest.write_str(" / ")?;
409
+ self.border_image_outset.to_css(dest)?;
410
+ }
411
+ }
412
+ }
413
+ if has_repeat {
414
+ if has_source || needs_slice {
415
+ dest.write_char(' ')?;
416
+ }
417
+ self.border_image_repeat.to_css(dest)?;
418
+ }
419
+ Ok(())
420
+ }
421
+ }
422
+ }
423
+
424
+ pub mod border {
425
+ pub use crate::properties::generated::shorthands::border::*;
426
+
427
+ use super::*;
428
+ pub use crate::properties::generated::shorthands::border_left;
429
+ use crate::properties::longhands::{
430
+ border_image_outset, border_image_repeat, border_image_slice, border_image_source,
431
+ border_image_width,
432
+ };
433
+
434
+ pub fn parse_value(
435
+ context: &ParserContext,
436
+ input: &mut Parser,
437
+ ) -> Result<Longhands, ParseError> {
438
+ let (width, style, color) = super::parse_border(context, input)?;
439
+ Ok(expanded! {
440
+ border_top_width: width.clone(),
441
+ border_top_style: style,
442
+ border_top_color: color.clone(),
443
+ border_right_width: width.clone(),
444
+ border_right_style: style,
445
+ border_right_color: color.clone(),
446
+ border_bottom_width: width.clone(),
447
+ border_bottom_style: style,
448
+ border_bottom_color: color.clone(),
449
+ border_left_width: width.clone(),
450
+ border_left_style: style,
451
+ border_left_color: color.clone(),
452
+
453
+ // The 'border' shorthand resets 'border-image' to its initial value.
454
+ // See https://drafts.csswg.org/css-backgrounds-3/#the-border-shorthands
455
+ border_image_outset: border_image_outset::get_initial_specified_value(),
456
+ border_image_repeat: border_image_repeat::get_initial_specified_value(),
457
+ border_image_slice: border_image_slice::get_initial_specified_value(),
458
+ border_image_source: border_image_source::get_initial_specified_value(),
459
+ border_image_width: border_image_width::get_initial_specified_value(),
460
+ })
461
+ }
462
+
463
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
464
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
465
+ where
466
+ W: fmt::Write,
467
+ {
468
+ use crate::properties::longhands;
469
+
470
+ // If any of the border-image longhands differ from their initial specified values we should not
471
+ // invoke serialize_directional_border(), so there is no point in continuing on to compute all_equal.
472
+ if *self.border_image_outset
473
+ != longhands::border_image_outset::get_initial_specified_value()
474
+ {
475
+ return Ok(());
476
+ }
477
+ if *self.border_image_repeat
478
+ != longhands::border_image_repeat::get_initial_specified_value()
479
+ {
480
+ return Ok(());
481
+ }
482
+ if *self.border_image_slice
483
+ != longhands::border_image_slice::get_initial_specified_value()
484
+ {
485
+ return Ok(());
486
+ }
487
+ if *self.border_image_source
488
+ != longhands::border_image_source::get_initial_specified_value()
489
+ {
490
+ return Ok(());
491
+ }
492
+ if *self.border_image_width
493
+ != longhands::border_image_width::get_initial_specified_value()
494
+ {
495
+ return Ok(());
496
+ }
497
+
498
+ let all_equal = {
499
+ let border_top_width = self.border_top_width;
500
+ let border_top_style = self.border_top_style;
501
+ let border_top_color = self.border_top_color;
502
+ let border_right_width = self.border_right_width;
503
+ let border_right_style = self.border_right_style;
504
+ let border_right_color = self.border_right_color;
505
+ let border_bottom_width = self.border_bottom_width;
506
+ let border_bottom_style = self.border_bottom_style;
507
+ let border_bottom_color = self.border_bottom_color;
508
+ let border_left_width = self.border_left_width;
509
+ let border_left_style = self.border_left_style;
510
+ let border_left_color = self.border_left_color;
511
+
512
+ border_top_width == border_right_width
513
+ && border_right_width == border_bottom_width
514
+ && border_bottom_width == border_left_width
515
+ && border_top_style == border_right_style
516
+ && border_right_style == border_bottom_style
517
+ && border_bottom_style == border_left_style
518
+ && border_top_color == border_right_color
519
+ && border_right_color == border_bottom_color
520
+ && border_bottom_color == border_left_color
521
+ };
522
+
523
+ // If all longhands are all present, then all sides should be the same,
524
+ // so we can just one set of color/style/width
525
+ if !all_equal {
526
+ return Ok(());
527
+ }
528
+ super::serialize_directional_border(
529
+ dest,
530
+ self.border_left_width,
531
+ self.border_left_style,
532
+ self.border_left_color,
533
+ )
534
+ }
535
+ }
536
+
537
+ // We need to implement this by hand because deriving this would also derive border-image,
538
+ // which this property only resets. Just use the same as border-left for simplicity.
539
+ impl SpecifiedValueInfo for Longhands {
540
+ const SUPPORTED_TYPES: u8 = border_left::Longhands::SUPPORTED_TYPES;
541
+
542
+ fn collect_completion_keywords(f: KeywordsCollectFn) {
543
+ border_left::Longhands::collect_completion_keywords(f);
544
+ }
545
+ }
546
+ }
547
+
548
+ #[cfg(feature = "gecko")]
549
+ pub mod container {
550
+ use super::*;
551
+ pub use crate::properties::generated::shorthands::container::*;
552
+
553
+ use crate::values::specified::{ContainerName, ContainerType};
554
+
555
+ pub fn parse_value(
556
+ context: &ParserContext,
557
+ input: &mut Parser,
558
+ ) -> Result<Longhands, ParseError> {
559
+ // See https://github.com/w3c/csswg-drafts/issues/7180 for why we don't match the spec.
560
+ let container_name = ContainerName::parse(context, input)?;
561
+ let container_type = if input.try_parse(|input| input.expect_delim('/')).is_ok() {
562
+ ContainerType::parse(context, input)?
563
+ } else {
564
+ ContainerType::NORMAL
565
+ };
566
+ Ok(expanded! {
567
+ container_name: container_name,
568
+ container_type: container_type,
569
+ })
570
+ }
571
+
572
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
573
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
574
+ where
575
+ W: fmt::Write,
576
+ {
577
+ self.container_name.to_css(dest)?;
578
+ if !self.container_type.is_normal() {
579
+ dest.write_str(" / ")?;
580
+ self.container_type.to_css(dest)?;
581
+ }
582
+ Ok(())
583
+ }
584
+ }
585
+ }
586
+
587
+ pub mod vertical_align {
588
+ use super::*;
589
+ pub use crate::properties::generated::shorthands::vertical_align::*;
590
+
591
+ use crate::values::specified::{AlignmentBaseline, BaselineShift, BaselineSource};
592
+
593
+ pub fn parse_value(
594
+ context: &ParserContext,
595
+ input: &mut Parser,
596
+ ) -> Result<Longhands, ParseError> {
597
+ let mut baseline_source = None;
598
+ let mut alignment_baseline = None;
599
+ let mut baseline_shift = None;
600
+ let mut parsed = 0;
601
+
602
+ loop {
603
+ parsed += 1;
604
+
605
+ try_parse_one!(input, baseline_source, BaselineSource::parse_non_auto);
606
+ try_parse_one!(input, alignment_baseline, AlignmentBaseline::parse);
607
+ try_parse_one!(context, input, baseline_shift, BaselineShift::parse);
608
+
609
+ parsed -= 1;
610
+ break;
611
+ }
612
+
613
+ if parsed == 0 {
614
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
615
+ }
616
+
617
+ Ok(expanded! {
618
+ baseline_source: baseline_source.unwrap_or(BaselineSource::Auto),
619
+ alignment_baseline: alignment_baseline.unwrap_or(AlignmentBaseline::Baseline),
620
+ baseline_shift: baseline_shift.unwrap_or(BaselineShift::zero()),
621
+ })
622
+ }
623
+
624
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
625
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
626
+ where
627
+ W: fmt::Write,
628
+ {
629
+ let mut writer = SequenceWriter::new(dest, " ");
630
+ if *self.baseline_source != BaselineSource::Auto {
631
+ writer.item(self.baseline_source)?;
632
+ }
633
+ if *self.alignment_baseline != AlignmentBaseline::Baseline {
634
+ writer.item(self.alignment_baseline)?;
635
+ }
636
+ if *self.baseline_shift != BaselineShift::zero() {
637
+ writer.item(self.baseline_shift)?;
638
+ }
639
+ if !writer.has_written() {
640
+ self.alignment_baseline.to_css(dest)?;
641
+ }
642
+ Ok(())
643
+ }
644
+ }
645
+ }
646
+
647
+ #[cfg(feature = "gecko")]
648
+ pub mod offset {
649
+ use super::*;
650
+ pub use crate::properties::generated::shorthands::offset::*;
651
+ use crate::values::specified::{
652
+ LengthPercentage, OffsetPath, OffsetPosition, OffsetRotate, PositionOrAuto,
653
+ };
654
+ use crate::Zero;
655
+
656
+ pub fn parse_value(
657
+ context: &ParserContext,
658
+ input: &mut Parser,
659
+ ) -> Result<Longhands, ParseError> {
660
+ let offset_position = input.try_parse(|i| OffsetPosition::parse(context, i)).ok();
661
+ let offset_path = input.try_parse(|i| OffsetPath::parse(context, i)).ok();
662
+
663
+ // Must have one of [offset-position, offset-path].
664
+ // FIXME: The syntax is out-of-date after the update of the spec.
665
+ if offset_position.is_none() && offset_path.is_none() {
666
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
667
+ }
668
+
669
+ let mut offset_distance = None;
670
+ let mut offset_rotate = None;
671
+ // offset-distance and offset-rotate are grouped with offset-path.
672
+ if offset_path.is_some() {
673
+ loop {
674
+ if offset_distance.is_none() {
675
+ if let Ok(value) = input.try_parse(|i| LengthPercentage::parse(context, i)) {
676
+ offset_distance = Some(value);
677
+ }
678
+ }
679
+
680
+ if offset_rotate.is_none() {
681
+ if let Ok(value) = input.try_parse(|i| OffsetRotate::parse(context, i)) {
682
+ offset_rotate = Some(value);
683
+ continue;
684
+ }
685
+ }
686
+ break;
687
+ }
688
+ }
689
+
690
+ let offset_anchor = input
691
+ .try_parse(|i| {
692
+ i.expect_delim('/')?;
693
+ PositionOrAuto::parse(context, i)
694
+ })
695
+ .ok();
696
+
697
+ Ok(expanded! {
698
+ offset_position: offset_position.unwrap_or(OffsetPosition::normal()),
699
+ offset_path: offset_path.unwrap_or(OffsetPath::none()),
700
+ offset_distance: offset_distance.unwrap_or(LengthPercentage::zero()),
701
+ offset_rotate: offset_rotate.unwrap_or(OffsetRotate::auto()),
702
+ offset_anchor: offset_anchor.unwrap_or(PositionOrAuto::auto()),
703
+ })
704
+ }
705
+
706
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
707
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
708
+ where
709
+ W: fmt::Write,
710
+ {
711
+ // The basic concept is: we must serialize offset-position or offset-path group.
712
+ // offset-path group means "offset-path offset-distance offset-rotate".
713
+ let must_serialize_path = *self.offset_path != OffsetPath::None
714
+ || (!self.offset_distance.is_zero() || !self.offset_rotate.is_auto());
715
+ let position_is_default = matches!(self.offset_position, OffsetPosition::Normal);
716
+ if !position_is_default || !must_serialize_path {
717
+ self.offset_position.to_css(dest)?;
718
+ }
719
+
720
+ if must_serialize_path {
721
+ if !position_is_default {
722
+ dest.write_char(' ')?;
723
+ }
724
+ self.offset_path.to_css(dest)?;
725
+ }
726
+
727
+ if !self.offset_distance.is_zero() {
728
+ dest.write_char(' ')?;
729
+ self.offset_distance.to_css(dest)?;
730
+ }
731
+
732
+ if !self.offset_rotate.is_auto() {
733
+ dest.write_char(' ')?;
734
+ self.offset_rotate.to_css(dest)?;
735
+ }
736
+
737
+ if *self.offset_anchor != PositionOrAuto::auto() {
738
+ dest.write_str(" / ")?;
739
+ self.offset_anchor.to_css(dest)?;
740
+ }
741
+ Ok(())
742
+ }
743
+ }
744
+ }
745
+
746
+ pub mod columns {
747
+ pub use crate::properties::generated::shorthands::columns::*;
748
+
749
+ use super::*;
750
+ use crate::properties::longhands::{column_count, column_width};
751
+
752
+ pub fn parse_value(
753
+ context: &ParserContext,
754
+ input: &mut Parser,
755
+ ) -> Result<Longhands, ParseError> {
756
+ let mut column_count = None;
757
+ let mut column_width = None;
758
+ let mut autos = 0;
759
+
760
+ loop {
761
+ if input
762
+ .try_parse(|input| input.expect_ident_matching("auto"))
763
+ .is_ok()
764
+ {
765
+ // Leave the options to None, 'auto' is the initial value.
766
+ autos += 1;
767
+ continue;
768
+ }
769
+
770
+ if column_count.is_none() {
771
+ if let Ok(value) = input.try_parse(|input| column_count::parse(context, input)) {
772
+ column_count = Some(value);
773
+ continue;
774
+ }
775
+ }
776
+
777
+ if column_width.is_none() {
778
+ if let Ok(value) = input.try_parse(|input| column_width::parse(context, input)) {
779
+ column_width = Some(value);
780
+ continue;
781
+ }
782
+ }
783
+
784
+ break;
785
+ }
786
+
787
+ let values = autos + column_count.iter().len() + column_width.iter().len();
788
+ if values == 0 || values > 2 {
789
+ Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError))
790
+ } else {
791
+ Ok(expanded! {
792
+ column_count: unwrap_or_initial!(column_count),
793
+ column_width: unwrap_or_initial!(column_width),
794
+ })
795
+ }
796
+ }
797
+
798
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
799
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
800
+ where
801
+ W: fmt::Write,
802
+ {
803
+ if self.column_width.is_auto() {
804
+ return self.column_count.to_css(dest);
805
+ }
806
+ self.column_width.to_css(dest)?;
807
+ if !self.column_count.is_auto() {
808
+ dest.write_char(' ')?;
809
+ self.column_count.to_css(dest)?;
810
+ }
811
+ Ok(())
812
+ }
813
+ }
814
+ }
815
+
816
+ #[cfg(feature = "gecko")]
817
+ pub mod column_rule {
818
+ pub use crate::properties::generated::shorthands::column_rule::*;
819
+
820
+ use super::*;
821
+ use crate::properties::longhands::column_rule_color;
822
+ use crate::properties::longhands::{column_rule_style, column_rule_width};
823
+
824
+ pub fn parse_value(
825
+ context: &ParserContext,
826
+ input: &mut Parser,
827
+ ) -> Result<Longhands, ParseError> {
828
+ let mut column_rule_width = None;
829
+ let mut column_rule_style = None;
830
+ let mut column_rule_color = None;
831
+ let mut parsed = 0;
832
+ loop {
833
+ parsed += 1;
834
+ try_parse_one!(context, input, column_rule_width, column_rule_width::parse);
835
+ try_parse_one!(context, input, column_rule_style, column_rule_style::parse);
836
+ try_parse_one!(context, input, column_rule_color, column_rule_color::parse);
837
+ parsed -= 1;
838
+ break;
839
+ }
840
+ if parsed == 0 {
841
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
842
+ }
843
+ Ok(expanded! {
844
+ column_rule_width: unwrap_or_initial!(column_rule_width),
845
+ column_rule_style: unwrap_or_initial!(column_rule_style),
846
+ column_rule_color: unwrap_or_initial!(column_rule_color),
847
+ })
848
+ }
849
+ }
850
+
851
+ #[cfg(feature = "gecko")]
852
+ pub mod text_wrap {
853
+ pub use crate::properties::generated::shorthands::text_wrap::*;
854
+
855
+ use super::*;
856
+ use crate::properties::longhands::{text_wrap_mode, text_wrap_style};
857
+
858
+ pub fn parse_value(
859
+ context: &ParserContext,
860
+ input: &mut Parser,
861
+ ) -> Result<Longhands, ParseError> {
862
+ let mut mode = None;
863
+ let mut style = None;
864
+ let mut parsed = 0;
865
+ loop {
866
+ parsed += 1;
867
+ try_parse_one!(context, input, mode, text_wrap_mode::parse);
868
+ try_parse_one!(context, input, style, text_wrap_style::parse);
869
+ parsed -= 1;
870
+ break;
871
+ }
872
+ if parsed == 0 {
873
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
874
+ }
875
+ Ok(expanded! {
876
+ text_wrap_mode: unwrap_or_initial!(text_wrap_mode, mode),
877
+ text_wrap_style: unwrap_or_initial!(text_wrap_style, style),
878
+ })
879
+ }
880
+
881
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
882
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
883
+ where
884
+ W: fmt::Write,
885
+ {
886
+ use text_wrap_mode::computed_value::T as Mode;
887
+ use text_wrap_style::computed_value::T as Style;
888
+
889
+ if matches!(self.text_wrap_style, &Style::Auto) {
890
+ return self.text_wrap_mode.to_css(dest);
891
+ }
892
+
893
+ if *self.text_wrap_mode != Mode::Wrap {
894
+ self.text_wrap_mode.to_css(dest)?;
895
+ dest.write_char(' ')?;
896
+ }
897
+
898
+ self.text_wrap_style.to_css(dest)
899
+ }
900
+ }
901
+ }
902
+
903
+ pub mod white_space {
904
+ pub use crate::properties::generated::shorthands::white_space::*;
905
+
906
+ use super::*;
907
+ use crate::properties::longhands::{text_wrap_mode, white_space_collapse};
908
+
909
+ pub fn parse_value(
910
+ context: &ParserContext,
911
+ input: &mut Parser,
912
+ ) -> Result<Longhands, ParseError> {
913
+ use text_wrap_mode::computed_value::T as Wrap;
914
+ use white_space_collapse::computed_value::T as Collapse;
915
+
916
+ fn parse_special_shorthands(input: &mut Parser) -> Result<Longhands, ParseError> {
917
+ let (mode, collapse) = try_match_ident_ignore_ascii_case! { input,
918
+ "normal" => (Wrap::Wrap, Collapse::Collapse),
919
+ "pre" => (Wrap::Nowrap, Collapse::Preserve),
920
+ "pre-wrap" => (Wrap::Wrap, Collapse::Preserve),
921
+ "pre-line" => (Wrap::Wrap, Collapse::PreserveBreaks),
922
+ };
923
+ Ok(expanded! {
924
+ text_wrap_mode: mode,
925
+ white_space_collapse: collapse,
926
+ })
927
+ }
928
+
929
+ if let Ok(result) = input.try_parse(parse_special_shorthands) {
930
+ return Ok(result);
931
+ }
932
+
933
+ let mut wrap = None;
934
+ let mut collapse = None;
935
+ let mut parsed = 0;
936
+
937
+ loop {
938
+ parsed += 1;
939
+ try_parse_one!(context, input, wrap, text_wrap_mode::parse);
940
+ try_parse_one!(context, input, collapse, white_space_collapse::parse);
941
+ parsed -= 1;
942
+ break;
943
+ }
944
+
945
+ if parsed == 0 {
946
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
947
+ }
948
+
949
+ Ok(expanded! {
950
+ text_wrap_mode: unwrap_or_initial!(text_wrap_mode, wrap),
951
+ white_space_collapse: unwrap_or_initial!(white_space_collapse, collapse),
952
+ })
953
+ }
954
+
955
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
956
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
957
+ where
958
+ W: fmt::Write,
959
+ {
960
+ use text_wrap_mode::computed_value::T as Wrap;
961
+ use white_space_collapse::computed_value::T as Collapse;
962
+
963
+ match *self.text_wrap_mode {
964
+ Wrap::Wrap => match *self.white_space_collapse {
965
+ Collapse::Collapse => return dest.write_str("normal"),
966
+ Collapse::Preserve => return dest.write_str("pre-wrap"),
967
+ Collapse::PreserveBreaks => return dest.write_str("pre-line"),
968
+ _ => (),
969
+ },
970
+ Wrap::Nowrap => {
971
+ if let Collapse::Preserve = *self.white_space_collapse {
972
+ return dest.write_str("pre");
973
+ }
974
+ },
975
+ }
976
+
977
+ let mut has_value = false;
978
+ if *self.white_space_collapse != Collapse::Collapse {
979
+ self.white_space_collapse.to_css(dest)?;
980
+ has_value = true;
981
+ }
982
+
983
+ if *self.text_wrap_mode != Wrap::Wrap {
984
+ if has_value {
985
+ dest.write_char(' ')?;
986
+ }
987
+ self.text_wrap_mode.to_css(dest)?;
988
+ }
989
+
990
+ Ok(())
991
+ }
992
+ }
993
+
994
+ impl SpecifiedValueInfo for Longhands {
995
+ fn collect_completion_keywords(f: KeywordsCollectFn) {
996
+ // Collect keywords from our longhands.
997
+ text_wrap_mode::SpecifiedValue::collect_completion_keywords(f);
998
+ white_space_collapse::SpecifiedValue::collect_completion_keywords(f);
999
+
1000
+ // Add the special values supported only by the shorthand
1001
+ // (see parse_special_shorthands() above).
1002
+ f(&["normal", "pre", "pre-wrap", "pre-line"])
1003
+ }
1004
+ }
1005
+ }
1006
+
1007
+ #[cfg(feature = "gecko")]
1008
+ pub mod _webkit_text_stroke {
1009
+ pub use crate::properties::generated::shorthands::_webkit_text_stroke::*;
1010
+
1011
+ use super::*;
1012
+ use crate::properties::longhands::{_webkit_text_stroke_color, _webkit_text_stroke_width};
1013
+
1014
+ pub fn parse_value(
1015
+ context: &ParserContext,
1016
+ input: &mut Parser,
1017
+ ) -> Result<Longhands, ParseError> {
1018
+ let mut color = None;
1019
+ let mut width = None;
1020
+ let mut parsed = 0;
1021
+ loop {
1022
+ parsed += 1;
1023
+ try_parse_one!(context, input, color, _webkit_text_stroke_color::parse);
1024
+ try_parse_one!(context, input, width, _webkit_text_stroke_width::parse);
1025
+ parsed -= 1;
1026
+ break;
1027
+ }
1028
+ if parsed == 0 {
1029
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
1030
+ }
1031
+ Ok(expanded! {
1032
+ _webkit_text_stroke_color: unwrap_or_initial!(_webkit_text_stroke_color, color),
1033
+ _webkit_text_stroke_width: unwrap_or_initial!(_webkit_text_stroke_width, width),
1034
+ })
1035
+ }
1036
+ }
1037
+
1038
+ pub mod list_style {
1039
+ pub use crate::properties::generated::shorthands::list_style::*;
1040
+
1041
+ use super::*;
1042
+ use crate::properties::longhands::{list_style_image, list_style_position, list_style_type};
1043
+ use crate::values::specified::Image;
1044
+ use selectors::parser::SelectorParseErrorKind;
1045
+
1046
+ pub fn parse_value(
1047
+ context: &ParserContext,
1048
+ input: &mut Parser,
1049
+ ) -> Result<Longhands, ParseError> {
1050
+ // `none` is ambiguous until we've finished parsing the shorthands, so we count the number
1051
+ // of times we see it.
1052
+ let mut nones = 0u8;
1053
+ let (mut image, mut position, mut list_style_type) = (None, None, None);
1054
+ let mut parsed = 0;
1055
+ loop {
1056
+ parsed += 1;
1057
+
1058
+ if input
1059
+ .try_parse(|input| input.expect_ident_matching("none"))
1060
+ .is_ok()
1061
+ {
1062
+ nones += 1;
1063
+ if nones > 2 {
1064
+ return Err(ParseError::custom(SelectorParseErrorKind::UnexpectedIdent));
1065
+ }
1066
+ continue;
1067
+ }
1068
+
1069
+ try_parse_one!(context, input, image, list_style_image::parse);
1070
+ try_parse_one!(context, input, position, list_style_position::parse);
1071
+ // list-style-type must be checked the last, because it accepts
1072
+ // arbitrary identifier for custom counter style, and thus may
1073
+ // affect values of list-style-position.
1074
+ try_parse_one!(context, input, list_style_type, list_style_type::parse);
1075
+
1076
+ parsed -= 1;
1077
+ break;
1078
+ }
1079
+
1080
+ let position = unwrap_or_initial!(list_style_position, position);
1081
+
1082
+ if parsed == 0 {
1083
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
1084
+ }
1085
+
1086
+ // If there are two `none`s, then we can't have a type or image; if there is one `none`,
1087
+ // then we can't have both a type *and* an image; if there is no `none` then we're fine as
1088
+ // long as we parsed something.
1089
+ use self::list_style_type::SpecifiedValue as ListStyleType;
1090
+ match (nones, list_style_type, image) {
1091
+ (2, None, None) => Ok(expanded! {
1092
+ list_style_position: position,
1093
+ list_style_image: Image::None,
1094
+ list_style_type: ListStyleType::none(),
1095
+ }),
1096
+ (1, None, Some(image)) => Ok(expanded! {
1097
+ list_style_position: position,
1098
+ list_style_image: image,
1099
+ list_style_type: ListStyleType::none(),
1100
+ }),
1101
+ (1, Some(list_style_type), None) => Ok(expanded! {
1102
+ list_style_position: position,
1103
+ list_style_image: Image::None,
1104
+ list_style_type: list_style_type,
1105
+ }),
1106
+ (1, None, None) => Ok(expanded! {
1107
+ list_style_position: position,
1108
+ list_style_image: Image::None,
1109
+ list_style_type: ListStyleType::none(),
1110
+ }),
1111
+ (0, list_style_type, image) => Ok(expanded! {
1112
+ list_style_position: position,
1113
+ list_style_image: unwrap_or_initial!(list_style_image, image),
1114
+ list_style_type: unwrap_or_initial!(list_style_type),
1115
+ }),
1116
+ _ => Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError)),
1117
+ }
1118
+ }
1119
+
1120
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1121
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1122
+ where
1123
+ W: fmt::Write,
1124
+ {
1125
+ use list_style_image::SpecifiedValue as ListStyleImage;
1126
+ use list_style_position::SpecifiedValue as ListStylePosition;
1127
+ use list_style_type::SpecifiedValue as ListStyleType;
1128
+
1129
+ let mut writer = SequenceWriter::new(dest, " ");
1130
+ if *self.list_style_position != ListStylePosition::Outside
1131
+ || self.list_style_type.is_name(&atom!("outside"))
1132
+ {
1133
+ writer.item(self.list_style_position)?;
1134
+ }
1135
+ if *self.list_style_image != ListStyleImage::None {
1136
+ writer.item(self.list_style_image)?;
1137
+ }
1138
+ if *self.list_style_type != ListStyleType::disc() {
1139
+ writer.item(self.list_style_type)?;
1140
+ }
1141
+ if !writer.has_written() {
1142
+ self.list_style_position.to_css(dest)?;
1143
+ }
1144
+ Ok(())
1145
+ }
1146
+ }
1147
+ }
1148
+
1149
+ pub mod gap {
1150
+ pub use crate::properties::generated::shorthands::gap::*;
1151
+
1152
+ use super::*;
1153
+ use crate::properties::longhands::{column_gap, row_gap};
1154
+
1155
+ pub fn parse_value(
1156
+ context: &ParserContext,
1157
+ input: &mut Parser,
1158
+ ) -> Result<Longhands, ParseError> {
1159
+ let r_gap = row_gap::parse(context, input)?;
1160
+ let c_gap = input
1161
+ .try_parse(|input| column_gap::parse(context, input))
1162
+ .unwrap_or(r_gap.clone());
1163
+
1164
+ Ok(expanded! {
1165
+ row_gap: r_gap,
1166
+ column_gap: c_gap,
1167
+ })
1168
+ }
1169
+
1170
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1171
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1172
+ where
1173
+ W: fmt::Write,
1174
+ {
1175
+ self.row_gap.to_css(dest)?;
1176
+ if self.row_gap != self.column_gap {
1177
+ dest.write_char(' ')?;
1178
+ self.column_gap.to_css(dest)?;
1179
+ }
1180
+ Ok(())
1181
+ }
1182
+ }
1183
+ }
1184
+
1185
+ #[cfg(feature = "gecko")]
1186
+ pub mod marker {
1187
+ pub use crate::properties::generated::shorthands::marker::*;
1188
+
1189
+ use super::*;
1190
+ use crate::values::specified::url::UrlOrNone;
1191
+
1192
+ pub fn parse_value(
1193
+ context: &ParserContext,
1194
+ input: &mut Parser,
1195
+ ) -> Result<Longhands, ParseError> {
1196
+ let url = UrlOrNone::parse(context, input)?;
1197
+
1198
+ Ok(expanded! {
1199
+ marker_start: url.clone(),
1200
+ marker_mid: url.clone(),
1201
+ marker_end: url,
1202
+ })
1203
+ }
1204
+
1205
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1206
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1207
+ where
1208
+ W: fmt::Write,
1209
+ {
1210
+ if self.marker_start == self.marker_mid && self.marker_mid == self.marker_end {
1211
+ self.marker_start.to_css(dest)
1212
+ } else {
1213
+ Ok(())
1214
+ }
1215
+ }
1216
+ }
1217
+ }
1218
+
1219
+ pub mod flex_flow {
1220
+ pub use crate::properties::generated::shorthands::flex_flow::*;
1221
+
1222
+ use super::*;
1223
+ use crate::properties::longhands::{flex_direction, flex_wrap};
1224
+
1225
+ pub fn parse_value(
1226
+ context: &ParserContext,
1227
+ input: &mut Parser,
1228
+ ) -> Result<Longhands, ParseError> {
1229
+ let mut parsed = 0;
1230
+ let mut direction = None;
1231
+ let mut wrap = None;
1232
+ loop {
1233
+ parsed += 1;
1234
+ try_parse_one!(context, input, direction, flex_direction::parse);
1235
+ try_parse_one!(context, input, wrap, flex_wrap::parse);
1236
+ parsed -= 1;
1237
+ break;
1238
+ }
1239
+ if parsed == 0 {
1240
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
1241
+ }
1242
+ Ok(expanded! {
1243
+ flex_direction: unwrap_or_initial!(flex_direction, direction),
1244
+ flex_wrap: unwrap_or_initial!(flex_wrap, wrap),
1245
+ })
1246
+ }
1247
+
1248
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1249
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1250
+ where
1251
+ W: fmt::Write,
1252
+ {
1253
+ if *self.flex_direction == flex_direction::get_initial_specified_value()
1254
+ && *self.flex_wrap != flex_wrap::get_initial_specified_value()
1255
+ {
1256
+ return self.flex_wrap.to_css(dest);
1257
+ }
1258
+ self.flex_direction.to_css(dest)?;
1259
+ if *self.flex_wrap != flex_wrap::get_initial_specified_value() {
1260
+ dest.write_char(' ')?;
1261
+ self.flex_wrap.to_css(dest)?;
1262
+ }
1263
+ Ok(())
1264
+ }
1265
+ }
1266
+ }
1267
+
1268
+ pub mod flex {
1269
+ pub use crate::properties::generated::shorthands::flex::*;
1270
+
1271
+ use super::*;
1272
+ use crate::properties::longhands::flex_basis::SpecifiedValue as FlexBasis;
1273
+ use crate::values::specified::NonNegativeNumber;
1274
+
1275
+ fn parse_flexibility(
1276
+ context: &ParserContext,
1277
+ input: &mut Parser,
1278
+ ) -> Result<(NonNegativeNumber, Option<NonNegativeNumber>), ParseError> {
1279
+ let grow = NonNegativeNumber::parse(context, input)?;
1280
+ let shrink = input
1281
+ .try_parse(|i| NonNegativeNumber::parse(context, i))
1282
+ .ok();
1283
+ Ok((grow, shrink))
1284
+ }
1285
+
1286
+ pub fn parse_value(
1287
+ context: &ParserContext,
1288
+ input: &mut Parser,
1289
+ ) -> Result<Longhands, ParseError> {
1290
+ let mut grow = None;
1291
+ let mut shrink = None;
1292
+ let mut basis = None;
1293
+
1294
+ if input
1295
+ .try_parse(|input| input.expect_ident_matching("none"))
1296
+ .is_ok()
1297
+ {
1298
+ return Ok(expanded! {
1299
+ flex_grow: NonNegativeNumber::new(0.0),
1300
+ flex_shrink: NonNegativeNumber::new(0.0),
1301
+ flex_basis: FlexBasis::auto(),
1302
+ });
1303
+ }
1304
+ loop {
1305
+ if grow.is_none() {
1306
+ if let Ok((flex_grow, flex_shrink)) =
1307
+ input.try_parse(|i| parse_flexibility(context, i))
1308
+ {
1309
+ grow = Some(flex_grow);
1310
+ shrink = flex_shrink;
1311
+ continue;
1312
+ }
1313
+ }
1314
+ if basis.is_none() {
1315
+ if let Ok(value) = input.try_parse(|input| FlexBasis::parse(context, input)) {
1316
+ basis = Some(value);
1317
+ continue;
1318
+ }
1319
+ }
1320
+ break;
1321
+ }
1322
+
1323
+ if grow.is_none() && basis.is_none() {
1324
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
1325
+ }
1326
+ Ok(expanded! {
1327
+ flex_grow: grow.unwrap_or(NonNegativeNumber::new(1.0)),
1328
+ flex_shrink: shrink.unwrap_or(NonNegativeNumber::new(1.0)),
1329
+ flex_basis: basis.unwrap_or(FlexBasis::zero_percent()),
1330
+ })
1331
+ }
1332
+ }
1333
+
1334
+ pub mod place_content {
1335
+ pub use crate::properties::generated::shorthands::place_content::*;
1336
+
1337
+ use super::*;
1338
+ use crate::values::specified::align::ContentDistribution;
1339
+
1340
+ pub fn parse_value(
1341
+ context: &ParserContext,
1342
+ input: &mut Parser,
1343
+ ) -> Result<Longhands, ParseError> {
1344
+ let align_content = ContentDistribution::parse_block(context, input)?;
1345
+ let justify_content =
1346
+ input.try_parse(|input| ContentDistribution::parse_inline(context, input));
1347
+
1348
+ let justify_content = match justify_content {
1349
+ Ok(v) => v,
1350
+ Err(..) => {
1351
+ if !align_content.is_baseline_position() {
1352
+ align_content
1353
+ } else {
1354
+ ContentDistribution::start()
1355
+ }
1356
+ },
1357
+ };
1358
+
1359
+ Ok(expanded! {
1360
+ align_content: align_content,
1361
+ justify_content: justify_content,
1362
+ })
1363
+ }
1364
+
1365
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1366
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1367
+ where
1368
+ W: fmt::Write,
1369
+ {
1370
+ self.align_content.to_css(dest)?;
1371
+ if self.align_content != self.justify_content {
1372
+ dest.write_char(' ')?;
1373
+ self.justify_content.to_css(dest)?;
1374
+ }
1375
+ Ok(())
1376
+ }
1377
+ }
1378
+ }
1379
+
1380
+ pub mod place_self {
1381
+ pub use crate::properties::generated::shorthands::place_self::*;
1382
+
1383
+ use super::*;
1384
+ use crate::values::specified::align::SelfAlignment;
1385
+
1386
+ pub fn parse_value(
1387
+ context: &ParserContext,
1388
+ input: &mut Parser,
1389
+ ) -> Result<Longhands, ParseError> {
1390
+ let align = SelfAlignment::parse_block(context, input)?;
1391
+ let justify = input.try_parse(|input| SelfAlignment::parse_inline(context, input));
1392
+
1393
+ let justify = match justify {
1394
+ Ok(v) => v,
1395
+ Err(..) => {
1396
+ debug_assert!(align.is_valid_on_both_axes());
1397
+ align
1398
+ },
1399
+ };
1400
+
1401
+ Ok(expanded! {
1402
+ align_self: align,
1403
+ justify_self: justify,
1404
+ })
1405
+ }
1406
+
1407
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1408
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1409
+ where
1410
+ W: fmt::Write,
1411
+ {
1412
+ self.align_self.to_css(dest)?;
1413
+ if self.align_self != self.justify_self {
1414
+ dest.write_char(' ')?;
1415
+ self.justify_self.to_css(dest)?;
1416
+ }
1417
+ Ok(())
1418
+ }
1419
+ }
1420
+ }
1421
+
1422
+ pub mod place_items {
1423
+ pub use crate::properties::generated::shorthands::place_items::*;
1424
+
1425
+ use super::*;
1426
+ use crate::values::specified::align::{ItemPlacement, JustifyItems};
1427
+
1428
+ pub fn parse_value(
1429
+ context: &ParserContext,
1430
+ input: &mut Parser,
1431
+ ) -> Result<Longhands, ParseError> {
1432
+ let align = ItemPlacement::parse_block(context, input)?;
1433
+ let justify = input
1434
+ .try_parse(|input| ItemPlacement::parse_inline(context, input))
1435
+ .unwrap_or(align);
1436
+
1437
+ Ok(expanded! {
1438
+ align_items: align,
1439
+ justify_items: JustifyItems(justify),
1440
+ })
1441
+ }
1442
+
1443
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1444
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1445
+ where
1446
+ W: fmt::Write,
1447
+ {
1448
+ self.align_items.to_css(dest)?;
1449
+ if self.align_items != &self.justify_items.0 {
1450
+ dest.write_char(' ')?;
1451
+ self.justify_items.to_css(dest)?;
1452
+ }
1453
+ Ok(())
1454
+ }
1455
+ }
1456
+ }
1457
+
1458
+ pub mod grid_row {
1459
+ pub use crate::properties::generated::shorthands::grid_row::*;
1460
+
1461
+ use super::*;
1462
+ use crate::values::specified::GridLine;
1463
+ use crate::Zero;
1464
+
1465
+ pub fn parse_value(
1466
+ context: &ParserContext,
1467
+ input: &mut Parser,
1468
+ ) -> Result<Longhands, ParseError> {
1469
+ let start = input.try_parse(|i| GridLine::parse(context, i))?;
1470
+ let end = if input.try_parse(|i| i.expect_delim('/')).is_ok() {
1471
+ GridLine::parse(context, input)?
1472
+ } else {
1473
+ let mut line = GridLine::auto();
1474
+ if start.line_num.is_zero() && !start.is_span {
1475
+ line.ident = start.ident.clone();
1476
+ }
1477
+
1478
+ line
1479
+ };
1480
+
1481
+ Ok(expanded! {
1482
+ grid_row_start: start,
1483
+ grid_row_end: end,
1484
+ })
1485
+ }
1486
+
1487
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1488
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1489
+ where
1490
+ W: fmt::Write,
1491
+ {
1492
+ self.grid_row_start.to_css(dest)?;
1493
+ if self.grid_row_start.can_omit(self.grid_row_end) {
1494
+ return Ok(());
1495
+ }
1496
+ dest.write_str(" / ")?;
1497
+ self.grid_row_end.to_css(dest)
1498
+ }
1499
+ }
1500
+ }
1501
+
1502
+ pub mod grid_column {
1503
+ pub use crate::properties::generated::shorthands::grid_column::*;
1504
+
1505
+ use super::*;
1506
+ use crate::values::specified::GridLine;
1507
+ use crate::Zero;
1508
+
1509
+ pub fn parse_value(
1510
+ context: &ParserContext,
1511
+ input: &mut Parser,
1512
+ ) -> Result<Longhands, ParseError> {
1513
+ let start = input.try_parse(|i| GridLine::parse(context, i))?;
1514
+ let end = if input.try_parse(|i| i.expect_delim('/')).is_ok() {
1515
+ GridLine::parse(context, input)?
1516
+ } else {
1517
+ let mut line = GridLine::auto();
1518
+ if start.line_num.is_zero() && !start.is_span {
1519
+ line.ident = start.ident.clone();
1520
+ }
1521
+
1522
+ line
1523
+ };
1524
+
1525
+ Ok(expanded! {
1526
+ grid_column_start: start,
1527
+ grid_column_end: end,
1528
+ })
1529
+ }
1530
+
1531
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1532
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1533
+ where
1534
+ W: fmt::Write,
1535
+ {
1536
+ self.grid_column_start.to_css(dest)?;
1537
+ if self.grid_column_start.can_omit(self.grid_column_end) {
1538
+ return Ok(());
1539
+ }
1540
+ dest.write_str(" / ")?;
1541
+ self.grid_column_end.to_css(dest)
1542
+ }
1543
+ }
1544
+ }
1545
+
1546
+ pub mod grid_area {
1547
+ pub use crate::properties::generated::shorthands::grid_area::*;
1548
+
1549
+ use super::*;
1550
+ use crate::values::specified::GridLine;
1551
+ use crate::Zero;
1552
+
1553
+ pub fn parse_value(
1554
+ context: &ParserContext,
1555
+ input: &mut Parser,
1556
+ ) -> Result<Longhands, ParseError> {
1557
+ fn line_with_ident_from(other: &GridLine) -> GridLine {
1558
+ let mut this = GridLine::auto();
1559
+ if other.line_num.is_zero() && !other.is_span {
1560
+ this.ident = other.ident.clone();
1561
+ }
1562
+
1563
+ this
1564
+ }
1565
+
1566
+ let row_start = input.try_parse(|i| GridLine::parse(context, i))?;
1567
+ let (column_start, row_end, column_end) =
1568
+ if input.try_parse(|i| i.expect_delim('/')).is_ok() {
1569
+ let column_start = GridLine::parse(context, input)?;
1570
+ let (row_end, column_end) = if input.try_parse(|i| i.expect_delim('/')).is_ok() {
1571
+ let row_end = GridLine::parse(context, input)?;
1572
+ let column_end = if input.try_parse(|i| i.expect_delim('/')).is_ok() {
1573
+ GridLine::parse(context, input)?
1574
+ } else {
1575
+ line_with_ident_from(&column_start)
1576
+ };
1577
+
1578
+ (row_end, column_end)
1579
+ } else {
1580
+ let row_end = line_with_ident_from(&row_start);
1581
+ let column_end = line_with_ident_from(&column_start);
1582
+ (row_end, column_end)
1583
+ };
1584
+
1585
+ (column_start, row_end, column_end)
1586
+ } else {
1587
+ let line = line_with_ident_from(&row_start);
1588
+ (line.clone(), line.clone(), line)
1589
+ };
1590
+
1591
+ Ok(expanded! {
1592
+ grid_row_start: row_start,
1593
+ grid_row_end: row_end,
1594
+ grid_column_start: column_start,
1595
+ grid_column_end: column_end,
1596
+ })
1597
+ }
1598
+
1599
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1600
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1601
+ where
1602
+ W: fmt::Write,
1603
+ {
1604
+ self.grid_row_start.to_css(dest)?;
1605
+ let mut trailing_values = 3;
1606
+ if self.grid_column_start.can_omit(self.grid_column_end) {
1607
+ trailing_values -= 1;
1608
+ if self.grid_row_start.can_omit(self.grid_row_end) {
1609
+ trailing_values -= 1;
1610
+ if self.grid_row_start.can_omit(self.grid_column_start) {
1611
+ trailing_values -= 1;
1612
+ }
1613
+ }
1614
+ }
1615
+ let values = [
1616
+ &self.grid_column_start,
1617
+ &self.grid_row_end,
1618
+ &self.grid_column_end,
1619
+ ];
1620
+ for value in values.iter().take(trailing_values) {
1621
+ dest.write_str(" / ")?;
1622
+ value.to_css(dest)?;
1623
+ }
1624
+ Ok(())
1625
+ }
1626
+ }
1627
+ }
1628
+
1629
+ #[cfg(feature = "gecko")]
1630
+ pub mod position_try {
1631
+ pub use crate::properties::generated::shorthands::position_try::*;
1632
+
1633
+ use super::*;
1634
+ use crate::values::specified::position::{PositionTryFallbacks, PositionTryOrder};
1635
+
1636
+ pub fn parse_value(
1637
+ context: &ParserContext,
1638
+ input: &mut Parser,
1639
+ ) -> Result<Longhands, ParseError> {
1640
+ let order = input.try_parse(PositionTryOrder::parse).ok();
1641
+ let fallbacks = PositionTryFallbacks::parse(context, input)?;
1642
+ Ok(expanded! {
1643
+ position_try_order: order.unwrap_or(PositionTryOrder::normal()),
1644
+ position_try_fallbacks: fallbacks,
1645
+ })
1646
+ }
1647
+
1648
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1649
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1650
+ where
1651
+ W: fmt::Write,
1652
+ {
1653
+ if !self.position_try_order.is_normal() {
1654
+ self.position_try_order.to_css(dest)?;
1655
+ dest.write_char(' ')?;
1656
+ }
1657
+ self.position_try_fallbacks.to_css(dest)
1658
+ }
1659
+ }
1660
+ }
1661
+
1662
+ #[cfg(feature = "gecko")]
1663
+ pub mod scroll_timeline {
1664
+ pub use crate::properties::generated::shorthands::scroll_timeline::*;
1665
+
1666
+ use super::*;
1667
+ use crate::properties::longhands::{scroll_timeline_axis, scroll_timeline_name};
1668
+
1669
+ pub fn parse_value(
1670
+ context: &ParserContext,
1671
+ input: &mut Parser,
1672
+ ) -> Result<Longhands, ParseError> {
1673
+ let mut names = Vec::with_capacity(1);
1674
+ let mut axes = Vec::with_capacity(1);
1675
+ input.parse_comma_separated(|input| {
1676
+ let name = scroll_timeline_name::single_value::parse(context, input)?;
1677
+ let axis = input.try_parse(|i| scroll_timeline_axis::single_value::parse(context, i));
1678
+
1679
+ names.push(name);
1680
+ axes.push(axis.unwrap_or_default());
1681
+
1682
+ Ok(())
1683
+ })?;
1684
+
1685
+ Ok(expanded! {
1686
+ scroll_timeline_name: scroll_timeline_name::SpecifiedValue(names.into()),
1687
+ scroll_timeline_axis: scroll_timeline_axis::SpecifiedValue(axes.into()),
1688
+ })
1689
+ }
1690
+
1691
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1692
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1693
+ where
1694
+ W: fmt::Write,
1695
+ {
1696
+ if self.scroll_timeline_name.0.len() != self.scroll_timeline_axis.0.len() {
1697
+ return Ok(());
1698
+ }
1699
+ let mut first = true;
1700
+ for (name, axis) in std::iter::zip(
1701
+ self.scroll_timeline_name.0.iter(),
1702
+ self.scroll_timeline_axis.0.iter(),
1703
+ ) {
1704
+ if !first {
1705
+ dest.write_str(", ")?;
1706
+ }
1707
+ name.to_css(dest)?;
1708
+ if !axis.is_default() {
1709
+ dest.write_char(' ')?;
1710
+ axis.to_css(dest)?;
1711
+ }
1712
+ first = false;
1713
+ }
1714
+ Ok(())
1715
+ }
1716
+ }
1717
+ }
1718
+
1719
+ #[cfg(feature = "gecko")]
1720
+ pub mod view_timeline {
1721
+ pub use crate::properties::generated::shorthands::view_timeline::*;
1722
+
1723
+ use super::*;
1724
+ use crate::properties::longhands::{
1725
+ view_timeline_axis, view_timeline_inset, view_timeline_name,
1726
+ };
1727
+
1728
+ pub fn parse_value(
1729
+ context: &ParserContext,
1730
+ input: &mut Parser,
1731
+ ) -> Result<Longhands, ParseError> {
1732
+ let mut names = Vec::with_capacity(1);
1733
+ let mut axes = Vec::with_capacity(1);
1734
+ let mut insets = Vec::with_capacity(1);
1735
+ input.parse_comma_separated(|input| {
1736
+ let name = view_timeline_name::single_value::parse(context, input)?;
1737
+ let mut axis = None;
1738
+ let mut inset = None;
1739
+
1740
+ loop {
1741
+ try_parse_one!(
1742
+ context,
1743
+ input,
1744
+ axis,
1745
+ view_timeline_axis::single_value::parse
1746
+ );
1747
+ try_parse_one!(
1748
+ context,
1749
+ input,
1750
+ inset,
1751
+ view_timeline_inset::single_value::parse
1752
+ );
1753
+ break;
1754
+ }
1755
+
1756
+ names.push(name);
1757
+ axes.push(axis.unwrap_or_default());
1758
+ insets.push(inset.unwrap_or_default());
1759
+
1760
+ Ok(())
1761
+ })?;
1762
+
1763
+ Ok(expanded! {
1764
+ view_timeline_name: view_timeline_name::SpecifiedValue(names.into()),
1765
+ view_timeline_axis: view_timeline_axis::SpecifiedValue(axes.into()),
1766
+ view_timeline_inset: view_timeline_inset::SpecifiedValue(insets.into()),
1767
+ })
1768
+ }
1769
+
1770
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1771
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1772
+ where
1773
+ W: fmt::Write,
1774
+ {
1775
+ use itertools::izip;
1776
+ if self.view_timeline_name.0.len() != self.view_timeline_axis.0.len()
1777
+ || self.view_timeline_name.0.len() != self.view_timeline_inset.0.len()
1778
+ {
1779
+ return Ok(());
1780
+ }
1781
+ let mut first = true;
1782
+ for (name, axis, inset) in izip!(
1783
+ self.view_timeline_name.0.iter(),
1784
+ self.view_timeline_axis.0.iter(),
1785
+ self.view_timeline_inset.0.iter(),
1786
+ ) {
1787
+ if !first {
1788
+ dest.write_str(", ")?;
1789
+ }
1790
+ name.to_css(dest)?;
1791
+ if !axis.is_default() {
1792
+ dest.write_char(' ')?;
1793
+ axis.to_css(dest)?;
1794
+ }
1795
+ if !inset.is_auto() {
1796
+ dest.write_char(' ')?;
1797
+ inset.to_css(dest)?;
1798
+ }
1799
+ first = false;
1800
+ }
1801
+ Ok(())
1802
+ }
1803
+ }
1804
+ }
1805
+
1806
+ #[cfg(feature = "gecko")]
1807
+ pub mod animation_range {
1808
+ pub use crate::properties::generated::shorthands::animation_range::*;
1809
+
1810
+ use super::*;
1811
+ use crate::properties::longhands::{animation_range_end, animation_range_start};
1812
+ use crate::values::specified::LengthPercentage;
1813
+
1814
+ pub fn parse_value(
1815
+ context: &ParserContext,
1816
+ input: &mut Parser,
1817
+ ) -> Result<Longhands, ParseError> {
1818
+ let mut starts = Vec::with_capacity(1);
1819
+ let mut ends = Vec::with_capacity(1);
1820
+ input.parse_comma_separated(|input| {
1821
+ let start = animation_range_start::single_value::parse(context, input)?;
1822
+ let end = input
1823
+ .try_parse(|i| animation_range_end::single_value::parse(context, i))
1824
+ .unwrap_or_else(|_| {
1825
+ use crate::values::generics::animation::AnimationRangeEnd;
1826
+ use crate::values::specified::animation::{
1827
+ AnimationRangeValue, TimelineRangeName,
1828
+ };
1829
+
1830
+ // If `<animation-range-start>` includes a timeline range name,
1831
+ // `animation-range-end` is set to that same timeline range name and 100%.
1832
+ // Otherwise, any omitted longhand is set to its initial value.
1833
+ let name = if start.0.name.is_none() {
1834
+ TimelineRangeName::Normal
1835
+ } else {
1836
+ start.0.name
1837
+ };
1838
+ AnimationRangeEnd(AnimationRangeValue::new(
1839
+ name,
1840
+ LengthPercentage::hundred_percent(),
1841
+ ))
1842
+ });
1843
+
1844
+ starts.push(start);
1845
+ ends.push(end);
1846
+ Ok(())
1847
+ })?;
1848
+
1849
+ Ok(expanded! {
1850
+ animation_range_start: animation_range_start::SpecifiedValue(starts.into()),
1851
+ animation_range_end: animation_range_end::SpecifiedValue(ends.into()),
1852
+ })
1853
+ }
1854
+
1855
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
1856
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1857
+ where
1858
+ W: fmt::Write,
1859
+ {
1860
+ use crate::values::specified::length::EqualsPercentage;
1861
+ let starts = &self.animation_range_start.0;
1862
+ let ends = &self.animation_range_end.0;
1863
+ if starts.len() != ends.len() {
1864
+ return Ok(());
1865
+ }
1866
+
1867
+ for (i, (start, end)) in std::iter::zip(starts.iter(), ends.iter()).enumerate() {
1868
+ if i != 0 {
1869
+ dest.write_str(", ")?;
1870
+ }
1871
+ start.to_css(dest)?;
1872
+ let can_omit_end = (start.0.name == end.0.name && end.0.lp.equals_percentage(1.0))
1873
+ || (start.0.name.is_none() && end.0.name.is_normal());
1874
+ if !can_omit_end {
1875
+ dest.write_char(' ')?;
1876
+ end.to_css(dest)?;
1877
+ }
1878
+ }
1879
+ Ok(())
1880
+ }
1881
+ }
1882
+ }
1883
+
1884
+ pub mod transition {
1885
+ pub use crate::properties::generated::shorthands::transition::*;
1886
+
1887
+ use super::*;
1888
+ use crate::properties::longhands::{
1889
+ transition_behavior, transition_delay, transition_duration, transition_property,
1890
+ transition_timing_function,
1891
+ };
1892
+ use crate::values::specified::TransitionProperty;
1893
+
1894
+ pub fn parse_value(
1895
+ context: &ParserContext,
1896
+ input: &mut Parser,
1897
+ ) -> Result<Longhands, ParseError> {
1898
+ struct SingleTransition {
1899
+ transition_property: transition_property::SingleSpecifiedValue,
1900
+ transition_duration: transition_duration::SingleSpecifiedValue,
1901
+ transition_timing_function: transition_timing_function::SingleSpecifiedValue,
1902
+ transition_delay: transition_delay::SingleSpecifiedValue,
1903
+ transition_behavior: transition_behavior::SingleSpecifiedValue,
1904
+ }
1905
+
1906
+ fn parse_one_transition(
1907
+ context: &ParserContext,
1908
+ input: &mut Parser,
1909
+ first: bool,
1910
+ ) -> Result<SingleTransition, ParseError> {
1911
+ let mut property = None;
1912
+ let mut duration = None;
1913
+ let mut timing_function = None;
1914
+ let mut delay = None;
1915
+ let mut behavior = None;
1916
+
1917
+ let mut parsed = 0;
1918
+ loop {
1919
+ parsed += 1;
1920
+
1921
+ try_parse_one!(
1922
+ context,
1923
+ input,
1924
+ duration,
1925
+ transition_duration::single_value::parse
1926
+ );
1927
+ try_parse_one!(
1928
+ context,
1929
+ input,
1930
+ timing_function,
1931
+ transition_timing_function::single_value::parse
1932
+ );
1933
+ try_parse_one!(context, input, delay, transition_delay::single_value::parse);
1934
+ try_parse_one!(
1935
+ context,
1936
+ input,
1937
+ behavior,
1938
+ transition_behavior::single_value::parse
1939
+ );
1940
+ if property.is_none() {
1941
+ if let Ok(value) = input.try_parse(|i| TransitionProperty::parse(context, i)) {
1942
+ property = Some(value);
1943
+ continue;
1944
+ }
1945
+
1946
+ if first && input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1947
+ property = Some(TransitionProperty::none());
1948
+ continue;
1949
+ }
1950
+ }
1951
+
1952
+ parsed -= 1;
1953
+ break;
1954
+ }
1955
+
1956
+ if parsed != 0 {
1957
+ Ok(SingleTransition {
1958
+ transition_property: property.unwrap_or_else(
1959
+ transition_property::single_value::get_initial_specified_value,
1960
+ ),
1961
+ transition_duration: duration.unwrap_or_else(
1962
+ transition_duration::single_value::get_initial_specified_value,
1963
+ ),
1964
+ transition_timing_function: timing_function.unwrap_or_else(
1965
+ transition_timing_function::single_value::get_initial_specified_value,
1966
+ ),
1967
+ transition_delay: delay.unwrap_or_else(
1968
+ transition_delay::single_value::get_initial_specified_value,
1969
+ ),
1970
+ transition_behavior: behavior.unwrap_or_else(
1971
+ transition_behavior::single_value::get_initial_specified_value,
1972
+ ),
1973
+ })
1974
+ } else {
1975
+ Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError))
1976
+ }
1977
+ }
1978
+
1979
+ let mut first = true;
1980
+ let mut has_transition_property_none = false;
1981
+ let results = input.parse_comma_separated(|i| {
1982
+ if has_transition_property_none {
1983
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
1984
+ }
1985
+ let transition = parse_one_transition(context, i, first)?;
1986
+ first = false;
1987
+ has_transition_property_none = transition.transition_property.is_none();
1988
+ Ok(transition)
1989
+ })?;
1990
+
1991
+ let len = results.len();
1992
+ let mut property = Vec::with_capacity(len);
1993
+ let mut duration = Vec::with_capacity(len);
1994
+ let mut timing_function = Vec::with_capacity(len);
1995
+ let mut delay = Vec::with_capacity(len);
1996
+ let mut behavior = Vec::with_capacity(len);
1997
+ for result in results {
1998
+ property.push(result.transition_property);
1999
+ duration.push(result.transition_duration);
2000
+ timing_function.push(result.transition_timing_function);
2001
+ delay.push(result.transition_delay);
2002
+ behavior.push(result.transition_behavior);
2003
+ }
2004
+
2005
+ Ok(Longhands {
2006
+ transition_property: transition_property::SpecifiedValue(property.into()),
2007
+ transition_duration: transition_duration::SpecifiedValue(duration.into()),
2008
+ transition_timing_function: transition_timing_function::SpecifiedValue(
2009
+ timing_function.into(),
2010
+ ),
2011
+ transition_delay: transition_delay::SpecifiedValue(delay.into()),
2012
+ transition_behavior: transition_behavior::SpecifiedValue(behavior.into()),
2013
+ })
2014
+ }
2015
+
2016
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
2017
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2018
+ where
2019
+ W: fmt::Write,
2020
+ {
2021
+ use crate::Zero;
2022
+ use style_traits::values::SequenceWriter;
2023
+
2024
+ let len = self.transition_property.0.len();
2025
+ debug_assert_ne!(
2026
+ len, 0,
2027
+ "We should always have at least one transition-property, even if none"
2028
+ );
2029
+ if self.transition_duration.0.len() != len {
2030
+ return Ok(());
2031
+ }
2032
+ if self.transition_delay.0.len() != len {
2033
+ return Ok(());
2034
+ }
2035
+ if self.transition_timing_function.0.len() != len {
2036
+ return Ok(());
2037
+ }
2038
+ if self.transition_behavior.0.len() != len {
2039
+ return Ok(());
2040
+ }
2041
+ for i in 0..len {
2042
+ if i != 0 {
2043
+ dest.write_str(", ")?;
2044
+ }
2045
+
2046
+ let has_duration = !self.transition_duration.0[i].is_zero();
2047
+ let has_timing = !self.transition_timing_function.0[i].is_ease();
2048
+ let has_delay = !self.transition_delay.0[i].is_zero();
2049
+ let has_behavior = !self.transition_behavior.0[i].is_normal();
2050
+ let has_any = has_duration || has_timing || has_delay || has_behavior;
2051
+
2052
+ let mut writer = SequenceWriter::new(dest, " ");
2053
+ if !self.transition_property.0[i].is_all() || !has_any {
2054
+ writer.item(&self.transition_property.0[i])?;
2055
+ }
2056
+ if has_duration || has_delay {
2057
+ writer.item(&self.transition_duration.0[i])?;
2058
+ }
2059
+ if has_timing {
2060
+ writer.item(&self.transition_timing_function.0[i])?;
2061
+ }
2062
+ if has_delay {
2063
+ writer.item(&self.transition_delay.0[i])?;
2064
+ }
2065
+ if has_behavior {
2066
+ writer.item(&self.transition_behavior.0[i])?;
2067
+ }
2068
+ }
2069
+ Ok(())
2070
+ }
2071
+ }
2072
+ }
2073
+
2074
+ pub mod outline {
2075
+ pub use crate::properties::generated::shorthands::outline::*;
2076
+
2077
+ use super::*;
2078
+ use crate::properties::longhands::{outline_color, outline_style, outline_width};
2079
+
2080
+ pub fn parse_value(
2081
+ context: &ParserContext,
2082
+ input: &mut Parser,
2083
+ ) -> Result<Longhands, ParseError> {
2084
+ let _unused = context;
2085
+ let mut color = None;
2086
+ let mut style = None;
2087
+ let mut width = None;
2088
+ let mut parsed = 0;
2089
+ loop {
2090
+ parsed += 1;
2091
+ try_parse_one!(context, input, color, specified::Color::parse);
2092
+ try_parse_one!(context, input, style, outline_style::parse);
2093
+ try_parse_one!(context, input, width, outline_width::parse);
2094
+ parsed -= 1;
2095
+ break;
2096
+ }
2097
+ if parsed == 0 {
2098
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
2099
+ }
2100
+ Ok(expanded! {
2101
+ outline_color: unwrap_or_initial!(outline_color, color),
2102
+ outline_style: unwrap_or_initial!(outline_style, style),
2103
+ outline_width: unwrap_or_initial!(outline_width, width),
2104
+ })
2105
+ }
2106
+
2107
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
2108
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2109
+ where
2110
+ W: fmt::Write,
2111
+ {
2112
+ let mut writer = SequenceWriter::new(dest, " ");
2113
+ if *self.outline_color != outline_color::get_initial_specified_value() {
2114
+ writer.item(self.outline_color)?;
2115
+ }
2116
+ if *self.outline_style != outline_style::get_initial_specified_value() {
2117
+ writer.item(self.outline_style)?;
2118
+ }
2119
+ if *self.outline_width != outline_width::get_initial_specified_value() {
2120
+ writer.item(self.outline_width)?;
2121
+ }
2122
+ if !writer.has_written() {
2123
+ self.outline_style.to_css(dest)?;
2124
+ }
2125
+ Ok(())
2126
+ }
2127
+ }
2128
+ }
2129
+
2130
+ pub mod background_position {
2131
+ pub use crate::properties::generated::shorthands::background_position::*;
2132
+
2133
+ use super::*;
2134
+ use crate::properties::longhands::{background_position_x, background_position_y};
2135
+ use crate::values::specified::position::Position;
2136
+ use crate::values::specified::AllowQuirks;
2137
+
2138
+ pub fn parse_value(
2139
+ context: &ParserContext,
2140
+ input: &mut Parser,
2141
+ ) -> Result<Longhands, ParseError> {
2142
+ let mut position_x = Vec::with_capacity(1);
2143
+ let mut position_y = Vec::with_capacity(1);
2144
+ let mut any = false;
2145
+
2146
+ input.parse_comma_separated(|input| {
2147
+ let value = Position::parse_three_value_quirky(context, input, AllowQuirks::Yes)?;
2148
+ position_x.push(value.horizontal);
2149
+ position_y.push(value.vertical);
2150
+ any = true;
2151
+ Ok(())
2152
+ })?;
2153
+ if !any {
2154
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
2155
+ }
2156
+
2157
+ Ok(expanded! {
2158
+ background_position_x: background_position_x::SpecifiedValue(position_x.into()),
2159
+ background_position_y: background_position_y::SpecifiedValue(position_y.into()),
2160
+ })
2161
+ }
2162
+
2163
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
2164
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2165
+ where
2166
+ W: fmt::Write,
2167
+ {
2168
+ let len = self.background_position_x.0.len();
2169
+ if len == 0 || len != self.background_position_y.0.len() {
2170
+ return Ok(());
2171
+ }
2172
+ for i in 0..len {
2173
+ Position {
2174
+ horizontal: self.background_position_x.0[i].clone(),
2175
+ vertical: self.background_position_y.0[i].clone(),
2176
+ }
2177
+ .to_css(dest)?;
2178
+
2179
+ if i < len - 1 {
2180
+ dest.write_str(", ")?;
2181
+ }
2182
+ }
2183
+ Ok(())
2184
+ }
2185
+ }
2186
+ }
2187
+
2188
+ pub mod background {
2189
+ pub use crate::properties::generated::shorthands::background::*;
2190
+
2191
+ use super::*;
2192
+ use crate::properties::longhands::background_clip;
2193
+ use crate::properties::longhands::background_clip::single_value::computed_value::T as Clip;
2194
+ use crate::properties::longhands::background_origin::single_value::computed_value::T as Origin;
2195
+ use crate::properties::longhands::{
2196
+ background_attachment, background_color, background_image, background_origin,
2197
+ background_size,
2198
+ };
2199
+ use crate::properties::longhands::{
2200
+ background_position_x, background_position_y, background_repeat,
2201
+ };
2202
+ use crate::values::specified::{AllowQuirks, Color, Position, PositionComponent};
2203
+
2204
+ impl From<background_origin::single_value::SpecifiedValue>
2205
+ for background_clip::single_value::SpecifiedValue
2206
+ {
2207
+ fn from(
2208
+ origin: background_origin::single_value::SpecifiedValue,
2209
+ ) -> background_clip::single_value::SpecifiedValue {
2210
+ match origin {
2211
+ background_origin::single_value::SpecifiedValue::ContentBox => {
2212
+ background_clip::single_value::SpecifiedValue::ContentBox
2213
+ },
2214
+ background_origin::single_value::SpecifiedValue::PaddingBox => {
2215
+ background_clip::single_value::SpecifiedValue::PaddingBox
2216
+ },
2217
+ background_origin::single_value::SpecifiedValue::BorderBox => {
2218
+ background_clip::single_value::SpecifiedValue::BorderBox
2219
+ },
2220
+ }
2221
+ }
2222
+ }
2223
+
2224
+ pub fn parse_value(
2225
+ context: &ParserContext,
2226
+ input: &mut Parser,
2227
+ ) -> Result<Longhands, ParseError> {
2228
+ let mut background_color = None;
2229
+
2230
+ let mut background_image = Vec::with_capacity(1);
2231
+ let mut background_position_x = Vec::with_capacity(1);
2232
+ let mut background_position_y = Vec::with_capacity(1);
2233
+ let mut background_repeat = Vec::with_capacity(1);
2234
+ let mut background_size = Vec::with_capacity(1);
2235
+ let mut background_attachment = Vec::with_capacity(1);
2236
+ let mut background_origin = Vec::with_capacity(1);
2237
+ let mut background_clip = Vec::with_capacity(1);
2238
+ input.parse_comma_separated(|input| {
2239
+ if background_color.is_some() {
2240
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
2241
+ }
2242
+
2243
+ let mut image = None;
2244
+ let mut position = None;
2245
+ let mut repeat = None;
2246
+ let mut size = None;
2247
+ let mut attachment = None;
2248
+ let mut origin = None;
2249
+ let mut clip = None;
2250
+ let mut parsed = 0;
2251
+ loop {
2252
+ parsed += 1;
2253
+ try_parse_one!(context, input, background_color, Color::parse);
2254
+ if position.is_none() {
2255
+ if let Ok(value) = input.try_parse(|input| {
2256
+ Position::parse_three_value_quirky(context, input, AllowQuirks::No)
2257
+ }) {
2258
+ position = Some(value);
2259
+
2260
+ size = input
2261
+ .try_parse(|input| {
2262
+ input.expect_delim('/')?;
2263
+ background_size::single_value::parse(context, input)
2264
+ })
2265
+ .ok();
2266
+
2267
+ continue;
2268
+ }
2269
+ }
2270
+ try_parse_one!(context, input, image, background_image::single_value::parse);
2271
+ try_parse_one!(
2272
+ context,
2273
+ input,
2274
+ repeat,
2275
+ background_repeat::single_value::parse
2276
+ );
2277
+ try_parse_one!(
2278
+ context,
2279
+ input,
2280
+ attachment,
2281
+ background_attachment::single_value::parse
2282
+ );
2283
+ try_parse_one!(
2284
+ context,
2285
+ input,
2286
+ origin,
2287
+ background_origin::single_value::parse
2288
+ );
2289
+ try_parse_one!(context, input, clip, background_clip::single_value::parse);
2290
+ parsed -= 1;
2291
+ break;
2292
+ }
2293
+ if parsed == 0 {
2294
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
2295
+ }
2296
+ if clip.is_none() {
2297
+ if let Some(origin) = origin {
2298
+ clip = Some(background_clip::single_value::SpecifiedValue::from(origin));
2299
+ }
2300
+ }
2301
+ if let Some(position) = position {
2302
+ background_position_x.push(position.horizontal);
2303
+ background_position_y.push(position.vertical);
2304
+ } else {
2305
+ background_position_x.push(PositionComponent::zero());
2306
+ background_position_y.push(PositionComponent::zero());
2307
+ }
2308
+ if let Some(bg_image) = image {
2309
+ background_image.push(bg_image);
2310
+ } else {
2311
+ background_image
2312
+ .push(background_image::single_value::get_initial_specified_value());
2313
+ }
2314
+ if let Some(bg_repeat) = repeat {
2315
+ background_repeat.push(bg_repeat);
2316
+ } else {
2317
+ background_repeat
2318
+ .push(background_repeat::single_value::get_initial_specified_value());
2319
+ }
2320
+ if let Some(bg_size) = size {
2321
+ background_size.push(bg_size);
2322
+ } else {
2323
+ background_size.push(background_size::single_value::get_initial_specified_value());
2324
+ }
2325
+ if let Some(bg_attachment) = attachment {
2326
+ background_attachment.push(bg_attachment);
2327
+ } else {
2328
+ background_attachment
2329
+ .push(background_attachment::single_value::get_initial_specified_value());
2330
+ }
2331
+ if let Some(bg_origin) = origin {
2332
+ background_origin.push(bg_origin);
2333
+ } else {
2334
+ background_origin
2335
+ .push(background_origin::single_value::get_initial_specified_value());
2336
+ }
2337
+ if let Some(bg_clip) = clip {
2338
+ background_clip.push(bg_clip);
2339
+ } else {
2340
+ background_clip.push(background_clip::single_value::get_initial_specified_value());
2341
+ }
2342
+ Ok(())
2343
+ })?;
2344
+
2345
+ Ok(expanded! {
2346
+ background_color: background_color.unwrap_or(Color::transparent()),
2347
+ background_image: background_image::SpecifiedValue(background_image.into()),
2348
+ background_position_x: background_position_x::SpecifiedValue(background_position_x.into()),
2349
+ background_position_y: background_position_y::SpecifiedValue(background_position_y.into()),
2350
+ background_repeat: background_repeat::SpecifiedValue(background_repeat.into()),
2351
+ background_size: background_size::SpecifiedValue(background_size.into()),
2352
+ background_attachment: background_attachment::SpecifiedValue(background_attachment.into()),
2353
+ background_origin: background_origin::SpecifiedValue(background_origin.into()),
2354
+ background_clip: background_clip::SpecifiedValue(background_clip.into()),
2355
+ })
2356
+ }
2357
+
2358
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
2359
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2360
+ where
2361
+ W: fmt::Write,
2362
+ {
2363
+ let len = self.background_image.0.len();
2364
+ if len == 0 {
2365
+ return Ok(());
2366
+ }
2367
+ if len != self.background_image.0.len() {
2368
+ return Ok(());
2369
+ }
2370
+ if len != self.background_position_x.0.len() {
2371
+ return Ok(());
2372
+ }
2373
+ if len != self.background_position_y.0.len() {
2374
+ return Ok(());
2375
+ }
2376
+ if len != self.background_size.0.len() {
2377
+ return Ok(());
2378
+ }
2379
+ if len != self.background_repeat.0.len() {
2380
+ return Ok(());
2381
+ }
2382
+ if len != self.background_origin.0.len() {
2383
+ return Ok(());
2384
+ }
2385
+ if len != self.background_clip.0.len() {
2386
+ return Ok(());
2387
+ }
2388
+ if len != self.background_attachment.0.len() {
2389
+ return Ok(());
2390
+ }
2391
+
2392
+ for i in 0..len {
2393
+ let image = &self.background_image.0[i];
2394
+ let position_x = &self.background_position_x.0[i];
2395
+ let position_y = &self.background_position_y.0[i];
2396
+ let repeat = &self.background_repeat.0[i];
2397
+ let size = &self.background_size.0[i];
2398
+ let attachment = &self.background_attachment.0[i];
2399
+ let origin = &self.background_origin.0[i];
2400
+ let clip = &self.background_clip.0[i];
2401
+
2402
+ if i != 0 {
2403
+ dest.write_str(", ")?;
2404
+ }
2405
+
2406
+ let mut writer = SequenceWriter::new(dest, " ");
2407
+ if *image != background_image::single_value::get_initial_specified_value() {
2408
+ writer.item(image)?;
2409
+ }
2410
+
2411
+ if *position_x != PositionComponent::zero()
2412
+ || *position_y != PositionComponent::zero()
2413
+ || *size != background_size::single_value::get_initial_specified_value()
2414
+ {
2415
+ writer.write_item(|dest| {
2416
+ Position {
2417
+ horizontal: position_x.clone(),
2418
+ vertical: position_y.clone(),
2419
+ }
2420
+ .to_css(dest)?;
2421
+ if *size != background_size::single_value::get_initial_specified_value() {
2422
+ dest.write_str(" / ")?;
2423
+ size.to_css(dest)?;
2424
+ }
2425
+ Ok(())
2426
+ })?;
2427
+ }
2428
+ if *repeat != background_repeat::single_value::get_initial_specified_value() {
2429
+ writer.item(repeat)?;
2430
+ }
2431
+ if *attachment != background_attachment::single_value::get_initial_specified_value()
2432
+ {
2433
+ writer.item(attachment)?;
2434
+ }
2435
+
2436
+ if *origin != Origin::PaddingBox || *clip != Clip::BorderBox {
2437
+ writer.item(origin)?;
2438
+ if *clip != From::from(*origin) {
2439
+ writer.item(clip)?;
2440
+ }
2441
+ }
2442
+
2443
+ if i == len - 1
2444
+ && *self.background_color != background_color::get_initial_specified_value()
2445
+ {
2446
+ writer.item(self.background_color)?;
2447
+ }
2448
+
2449
+ if !writer.has_written() {
2450
+ image.to_css(dest)?;
2451
+ }
2452
+ }
2453
+
2454
+ Ok(())
2455
+ }
2456
+ }
2457
+ }
2458
+
2459
+ pub mod font {
2460
+ pub use crate::properties::generated::shorthands::font::*;
2461
+
2462
+ use super::*;
2463
+ #[cfg(feature = "gecko")]
2464
+ use crate::properties::longhands::{
2465
+ font_family, font_size, font_size_adjust, font_variant_emoji,
2466
+ };
2467
+ use crate::properties::longhands::{
2468
+ font_feature_settings, font_kerning, font_language_override, font_optical_sizing,
2469
+ font_style, font_variant_alternates, font_variant_caps, font_variant_east_asian,
2470
+ font_variant_ligatures, font_variant_numeric, font_variant_position,
2471
+ font_variation_settings, font_weight, font_width,
2472
+ };
2473
+ #[cfg(feature = "gecko")]
2474
+ use crate::values::specified::font::SystemFont;
2475
+ use crate::values::specified::font::{
2476
+ FontFamily, FontSize, FontStyle, FontWeight, FontWidth, FontWidthKeyword, LineHeight,
2477
+ };
2478
+
2479
+ pub fn parse_value(
2480
+ context: &ParserContext,
2481
+ input: &mut Parser,
2482
+ ) -> Result<Longhands, ParseError> {
2483
+ let mut nb_normals = 0;
2484
+ let mut style = None;
2485
+ let mut variant_caps = None;
2486
+ let mut weight = None;
2487
+ let mut width = None;
2488
+ #[cfg(feature = "gecko")]
2489
+ if let Ok(sys) = input.try_parse(|i| SystemFont::parse(context, i)) {
2490
+ return Ok(Longhands {
2491
+ font_family: font_family::SpecifiedValue::system_font(sys),
2492
+ font_size: font_size::SpecifiedValue::system_font(sys),
2493
+ font_style: font_style::SpecifiedValue::system_font(sys),
2494
+ font_width: font_width::SpecifiedValue::system_font(sys),
2495
+ font_weight: font_weight::SpecifiedValue::system_font(sys),
2496
+ line_height: LineHeight::normal(),
2497
+ font_kerning: font_kerning::get_initial_specified_value(),
2498
+ font_language_override: font_language_override::get_initial_specified_value(),
2499
+ font_size_adjust: font_size_adjust::get_initial_specified_value(),
2500
+ font_variant_alternates: font_variant_alternates::get_initial_specified_value(),
2501
+ font_variant_east_asian: font_variant_east_asian::get_initial_specified_value(),
2502
+ font_variant_emoji: font_variant_emoji::get_initial_specified_value(),
2503
+ font_variant_ligatures: font_variant_ligatures::get_initial_specified_value(),
2504
+ font_variant_numeric: font_variant_numeric::get_initial_specified_value(),
2505
+ font_variant_position: font_variant_position::get_initial_specified_value(),
2506
+ font_feature_settings: font_feature_settings::get_initial_specified_value(),
2507
+ font_optical_sizing: font_optical_sizing::get_initial_specified_value(),
2508
+ font_variant_caps: font_variant_caps::get_initial_specified_value(),
2509
+ font_variation_settings: font_variation_settings::get_initial_specified_value(),
2510
+ });
2511
+ }
2512
+
2513
+ let size;
2514
+ loop {
2515
+ if input
2516
+ .try_parse(|input| input.expect_ident_matching("normal"))
2517
+ .is_ok()
2518
+ {
2519
+ nb_normals += 1;
2520
+ continue;
2521
+ }
2522
+ try_parse_one!(context, input, style, font_style::parse);
2523
+ try_parse_one!(context, input, weight, font_weight::parse);
2524
+ if variant_caps.is_none()
2525
+ && input
2526
+ .try_parse(|input| input.expect_ident_matching("small-caps"))
2527
+ .is_ok()
2528
+ {
2529
+ variant_caps = Some(font_variant_caps::SpecifiedValue::SmallCaps);
2530
+ continue;
2531
+ }
2532
+ try_parse_one!(input, width, FontWidthKeyword::parse);
2533
+ size = FontSize::parse(context, input)?;
2534
+ break;
2535
+ }
2536
+
2537
+ let line_height = if input.try_parse(|input| input.expect_delim('/')).is_ok() {
2538
+ Some(LineHeight::parse(context, input)?)
2539
+ } else {
2540
+ None
2541
+ };
2542
+
2543
+ #[inline]
2544
+ fn count<T>(opt: &Option<T>) -> u8 {
2545
+ if opt.is_some() {
2546
+ 1
2547
+ } else {
2548
+ 0
2549
+ }
2550
+ }
2551
+
2552
+ if (count(&style) + count(&weight) + count(&variant_caps) + count(&width) + nb_normals) > 4
2553
+ {
2554
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
2555
+ }
2556
+
2557
+ let family = FontFamily::parse(context, input)?;
2558
+ let width = width.map(FontWidth::Keyword);
2559
+ Ok(Longhands {
2560
+ font_style: unwrap_or_initial!(font_style, style),
2561
+ font_weight: unwrap_or_initial!(font_weight, weight),
2562
+ font_width: unwrap_or_initial!(font_width, width),
2563
+ font_variant_caps: unwrap_or_initial!(font_variant_caps, variant_caps),
2564
+ font_size: size,
2565
+ line_height: line_height.unwrap_or(LineHeight::normal()),
2566
+ font_family: family,
2567
+ font_optical_sizing: font_optical_sizing::get_initial_specified_value(),
2568
+ font_variation_settings: font_variation_settings::get_initial_specified_value(),
2569
+ font_kerning: font_kerning::get_initial_specified_value(),
2570
+ font_language_override: font_language_override::get_initial_specified_value(),
2571
+ #[cfg(feature = "gecko")]
2572
+ font_size_adjust: font_size_adjust::get_initial_specified_value(),
2573
+ font_variant_alternates: font_variant_alternates::get_initial_specified_value(),
2574
+ font_variant_east_asian: font_variant_east_asian::get_initial_specified_value(),
2575
+ #[cfg(feature = "gecko")]
2576
+ font_variant_emoji: font_variant_emoji::get_initial_specified_value(),
2577
+ font_variant_ligatures: font_variant_ligatures::get_initial_specified_value(),
2578
+ font_variant_numeric: font_variant_numeric::get_initial_specified_value(),
2579
+ font_variant_position: font_variant_position::get_initial_specified_value(),
2580
+ font_feature_settings: font_feature_settings::get_initial_specified_value(),
2581
+ })
2582
+ }
2583
+
2584
+ #[cfg(feature = "gecko")]
2585
+ enum CheckSystemResult {
2586
+ AllSystem(SystemFont),
2587
+ SomeSystem,
2588
+ None,
2589
+ }
2590
+
2591
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
2592
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2593
+ where
2594
+ W: fmt::Write,
2595
+ {
2596
+ #[cfg(feature = "gecko")]
2597
+ match self.check_system() {
2598
+ CheckSystemResult::AllSystem(sys) => return sys.to_css(dest),
2599
+ CheckSystemResult::SomeSystem => return Ok(()),
2600
+ CheckSystemResult::None => {},
2601
+ }
2602
+
2603
+ #[cfg(feature = "gecko")]
2604
+ if self.font_optical_sizing != &font_optical_sizing::get_initial_specified_value() {
2605
+ return Ok(());
2606
+ }
2607
+ #[cfg(feature = "servo")]
2608
+ if let Some(v) = self.font_optical_sizing {
2609
+ if v != &font_optical_sizing::get_initial_specified_value() {
2610
+ return Ok(());
2611
+ }
2612
+ }
2613
+ #[cfg(feature = "gecko")]
2614
+ if self.font_variation_settings
2615
+ != &font_variation_settings::get_initial_specified_value()
2616
+ {
2617
+ return Ok(());
2618
+ }
2619
+ #[cfg(feature = "servo")]
2620
+ if let Some(v) = self.font_variation_settings {
2621
+ if v != &font_variation_settings::get_initial_specified_value() {
2622
+ return Ok(());
2623
+ }
2624
+ }
2625
+ #[cfg(feature = "gecko")]
2626
+ if self.font_variant_emoji != &font_variant_emoji::get_initial_specified_value() {
2627
+ return Ok(());
2628
+ }
2629
+
2630
+ if self.font_kerning != &font_kerning::get_initial_specified_value() {
2631
+ return Ok(());
2632
+ }
2633
+ if self.font_language_override != &font_language_override::get_initial_specified_value()
2634
+ {
2635
+ return Ok(());
2636
+ }
2637
+ #[cfg(feature = "gecko")]
2638
+ if self.font_size_adjust != &font_size_adjust::get_initial_specified_value() {
2639
+ return Ok(());
2640
+ }
2641
+ if self.font_variant_alternates
2642
+ != &font_variant_alternates::get_initial_specified_value()
2643
+ {
2644
+ return Ok(());
2645
+ }
2646
+ if self.font_variant_east_asian
2647
+ != &font_variant_east_asian::get_initial_specified_value()
2648
+ {
2649
+ return Ok(());
2650
+ }
2651
+ if self.font_variant_ligatures != &font_variant_ligatures::get_initial_specified_value()
2652
+ {
2653
+ return Ok(());
2654
+ }
2655
+ if self.font_variant_numeric != &font_variant_numeric::get_initial_specified_value() {
2656
+ return Ok(());
2657
+ }
2658
+ if self.font_variant_position != &font_variant_position::get_initial_specified_value() {
2659
+ return Ok(());
2660
+ }
2661
+ if self.font_feature_settings != &font_feature_settings::get_initial_specified_value() {
2662
+ return Ok(());
2663
+ }
2664
+
2665
+ let font_width = match self.font_width {
2666
+ FontWidth::Keyword(kw) => *kw,
2667
+ FontWidth::Width(percentage) => {
2668
+ let computed = match percentage.compute() {
2669
+ Some(v) => v,
2670
+ None => return Ok(()),
2671
+ };
2672
+ match FontWidthKeyword::from_percentage(computed.0) {
2673
+ Some(kw) => kw,
2674
+ None => return Ok(()),
2675
+ }
2676
+ },
2677
+ FontWidth::System(..) => return Ok(()),
2678
+ };
2679
+
2680
+ if self.font_variant_caps != &font_variant_caps::get_initial_specified_value()
2681
+ && *self.font_variant_caps != font_variant_caps::SpecifiedValue::SmallCaps
2682
+ {
2683
+ return Ok(());
2684
+ }
2685
+
2686
+ if self.font_style != &font_style::get_initial_specified_value() {
2687
+ self.font_style.to_css(dest)?;
2688
+ dest.write_char(' ')?;
2689
+ }
2690
+ if self.font_variant_caps != &font_variant_caps::get_initial_specified_value() {
2691
+ self.font_variant_caps.to_css(dest)?;
2692
+ dest.write_char(' ')?;
2693
+ }
2694
+
2695
+ if self.font_weight != &FontWeight::normal()
2696
+ && self.font_weight != &FontWeight::from_gecko_keyword(400)
2697
+ {
2698
+ self.font_weight.to_css(dest)?;
2699
+ dest.write_char(' ')?;
2700
+ }
2701
+
2702
+ if font_width != FontWidthKeyword::Normal {
2703
+ font_width.to_css(dest)?;
2704
+ dest.write_char(' ')?;
2705
+ }
2706
+
2707
+ self.font_size.to_css(dest)?;
2708
+
2709
+ if *self.line_height != LineHeight::normal() {
2710
+ dest.write_str(" / ")?;
2711
+ self.line_height.to_css(dest)?;
2712
+ }
2713
+
2714
+ dest.write_char(' ')?;
2715
+ self.font_family.to_css(dest)?;
2716
+
2717
+ Ok(())
2718
+ }
2719
+ }
2720
+
2721
+ impl<'a> LonghandsToSerialize<'a> {
2722
+ #[cfg(feature = "gecko")]
2723
+ fn check_system(&self) -> CheckSystemResult {
2724
+ let mut sys = None;
2725
+ let mut all = true;
2726
+
2727
+ macro_rules! check {
2728
+ ($v:expr) => {
2729
+ match $v.get_system() {
2730
+ Some(s) => {
2731
+ debug_assert!(sys.is_none() || s == sys.unwrap());
2732
+ sys = Some(s);
2733
+ },
2734
+ None => {
2735
+ all = false;
2736
+ },
2737
+ }
2738
+ };
2739
+ ($e:expr, $($es:expr),+) => { check!($e); check!($($es),*); };
2740
+ }
2741
+
2742
+ check!(
2743
+ self.font_family,
2744
+ self.font_size,
2745
+ self.font_style,
2746
+ self.font_width,
2747
+ self.font_weight
2748
+ );
2749
+
2750
+ if self.line_height != &LineHeight::normal() {
2751
+ all = false
2752
+ }
2753
+ if all {
2754
+ CheckSystemResult::AllSystem(sys.unwrap())
2755
+ } else if sys.is_some() {
2756
+ CheckSystemResult::SomeSystem
2757
+ } else {
2758
+ CheckSystemResult::None
2759
+ }
2760
+ }
2761
+ }
2762
+
2763
+ impl SpecifiedValueInfo for Longhands {
2764
+ const SUPPORTED_TYPES: u8 = FontStyle::SUPPORTED_TYPES
2765
+ | FontWeight::SUPPORTED_TYPES
2766
+ | FontWidth::SUPPORTED_TYPES
2767
+ | font_variant_caps::SpecifiedValue::SUPPORTED_TYPES
2768
+ | FontSize::SUPPORTED_TYPES
2769
+ | FontFamily::SUPPORTED_TYPES;
2770
+
2771
+ fn collect_completion_keywords(f: KeywordsCollectFn) {
2772
+ FontStyle::collect_completion_keywords(f);
2773
+ FontWeight::collect_completion_keywords(f);
2774
+ FontWidth::collect_completion_keywords(f);
2775
+ font_variant_caps::SpecifiedValue::collect_completion_keywords(f);
2776
+ FontSize::collect_completion_keywords(f);
2777
+ FontFamily::collect_completion_keywords(f);
2778
+
2779
+ #[cfg(feature = "gecko")]
2780
+ SystemFont::collect_completion_keywords(f);
2781
+ }
2782
+ }
2783
+ }
2784
+
2785
+ pub mod font_variant {
2786
+ pub use crate::properties::generated::shorthands::font_variant::*;
2787
+
2788
+ use super::*;
2789
+ #[cfg(feature = "gecko")]
2790
+ use crate::properties::longhands::font_variant_emoji;
2791
+ use crate::properties::longhands::{
2792
+ font_variant_alternates, font_variant_caps, font_variant_east_asian,
2793
+ font_variant_ligatures, font_variant_numeric, font_variant_position,
2794
+ };
2795
+ use crate::values::specified::FontVariantLigatures;
2796
+
2797
+ pub fn parse_value(
2798
+ context: &ParserContext,
2799
+ input: &mut Parser,
2800
+ ) -> Result<Longhands, ParseError> {
2801
+ let mut ligatures = None;
2802
+ let mut caps = None;
2803
+ let mut alternates = None;
2804
+ let mut numeric = None;
2805
+ let mut east_asian = None;
2806
+ let mut position = None;
2807
+ #[cfg(feature = "gecko")]
2808
+ let mut emoji = None;
2809
+
2810
+ if input
2811
+ .try_parse(|input| input.expect_ident_matching("normal"))
2812
+ .is_ok()
2813
+ {
2814
+ } else if input
2815
+ .try_parse(|input| input.expect_ident_matching("none"))
2816
+ .is_ok()
2817
+ {
2818
+ ligatures = Some(FontVariantLigatures::NONE);
2819
+ } else {
2820
+ let mut parsed = 0;
2821
+ loop {
2822
+ parsed += 1;
2823
+ if input
2824
+ .try_parse(|input| input.expect_ident_matching("normal"))
2825
+ .is_ok()
2826
+ || input
2827
+ .try_parse(|input| input.expect_ident_matching("none"))
2828
+ .is_ok()
2829
+ {
2830
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
2831
+ }
2832
+ try_parse_one!(context, input, ligatures, font_variant_ligatures::parse);
2833
+ try_parse_one!(context, input, caps, font_variant_caps::parse);
2834
+ try_parse_one!(context, input, alternates, font_variant_alternates::parse);
2835
+ try_parse_one!(context, input, numeric, font_variant_numeric::parse);
2836
+ try_parse_one!(context, input, east_asian, font_variant_east_asian::parse);
2837
+ try_parse_one!(context, input, position, font_variant_position::parse);
2838
+ #[cfg(feature = "gecko")]
2839
+ try_parse_one!(context, input, emoji, font_variant_emoji::parse);
2840
+ parsed -= 1;
2841
+ break;
2842
+ }
2843
+
2844
+ if parsed == 0 {
2845
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
2846
+ }
2847
+ }
2848
+
2849
+ #[cfg(feature = "gecko")]
2850
+ return Ok(expanded! {
2851
+ font_variant_ligatures: unwrap_or_initial!(font_variant_ligatures, ligatures),
2852
+ font_variant_caps: unwrap_or_initial!(font_variant_caps, caps),
2853
+ font_variant_alternates: unwrap_or_initial!(font_variant_alternates, alternates),
2854
+ font_variant_numeric: unwrap_or_initial!(font_variant_numeric, numeric),
2855
+ font_variant_east_asian: unwrap_or_initial!(font_variant_east_asian, east_asian),
2856
+ font_variant_position: unwrap_or_initial!(font_variant_position, position),
2857
+ font_variant_emoji: unwrap_or_initial!(font_variant_emoji, emoji),
2858
+ });
2859
+ #[cfg(feature = "servo")]
2860
+ return Ok(expanded! {
2861
+ font_variant_alternates: unwrap_or_initial!(font_variant_alternates, alternates),
2862
+ font_variant_caps: unwrap_or_initial!(font_variant_caps, caps),
2863
+ font_variant_east_asian: unwrap_or_initial!(font_variant_east_asian, east_asian),
2864
+ font_variant_ligatures: unwrap_or_initial!(font_variant_ligatures, ligatures),
2865
+ font_variant_numeric: unwrap_or_initial!(font_variant_numeric, numeric),
2866
+ font_variant_position: unwrap_or_initial!(font_variant_position, position),
2867
+ });
2868
+ }
2869
+
2870
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
2871
+ #[allow(unused_assignments)]
2872
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2873
+ where
2874
+ W: fmt::Write,
2875
+ {
2876
+ let has_none_ligatures = self.font_variant_ligatures == &FontVariantLigatures::NONE;
2877
+
2878
+ #[cfg(feature = "gecko")]
2879
+ const TOTAL_SUBPROPS: usize = 7;
2880
+ #[cfg(feature = "servo")]
2881
+ const TOTAL_SUBPROPS: usize = 6;
2882
+ let mut nb_normals = 0;
2883
+ macro_rules! count_normal {
2884
+ ($e: expr, $p: ident) => {
2885
+ if *$e == $p::get_initial_specified_value() {
2886
+ nb_normals += 1;
2887
+ }
2888
+ };
2889
+ ($v: ident) => {
2890
+ count_normal!(self.$v, $v);
2891
+ };
2892
+ }
2893
+ count_normal!(font_variant_ligatures);
2894
+ count_normal!(font_variant_caps);
2895
+ count_normal!(font_variant_alternates);
2896
+ count_normal!(font_variant_numeric);
2897
+ count_normal!(font_variant_east_asian);
2898
+ count_normal!(font_variant_position);
2899
+ #[cfg(feature = "gecko")]
2900
+ count_normal!(font_variant_emoji);
2901
+
2902
+ if nb_normals == TOTAL_SUBPROPS {
2903
+ return dest.write_str("normal");
2904
+ }
2905
+ if has_none_ligatures {
2906
+ if nb_normals == TOTAL_SUBPROPS - 1 {
2907
+ dest.write_str("none")?;
2908
+ }
2909
+ return Ok(());
2910
+ }
2911
+
2912
+ let mut writer = SequenceWriter::new(dest, " ");
2913
+ macro_rules! write {
2914
+ ($e: expr, $p: ident) => {
2915
+ if *$e != $p::get_initial_specified_value() {
2916
+ writer.item($e)?;
2917
+ }
2918
+ };
2919
+ ($v: ident) => {
2920
+ write!(self.$v, $v);
2921
+ };
2922
+ }
2923
+
2924
+ write!(font_variant_ligatures);
2925
+ write!(font_variant_caps);
2926
+ write!(font_variant_alternates);
2927
+ write!(font_variant_numeric);
2928
+ write!(font_variant_east_asian);
2929
+ write!(font_variant_position);
2930
+ #[cfg(feature = "gecko")]
2931
+ write!(font_variant_emoji);
2932
+ Ok(())
2933
+ }
2934
+ }
2935
+ }
2936
+
2937
+ #[cfg(feature = "gecko")]
2938
+ pub mod font_synthesis {
2939
+ pub use crate::properties::generated::shorthands::font_synthesis::*;
2940
+
2941
+ use super::*;
2942
+ use crate::values::specified::{FontSynthesis, FontSynthesisStyle};
2943
+
2944
+ pub fn parse_value(
2945
+ _context: &ParserContext,
2946
+ input: &mut Parser,
2947
+ ) -> Result<Longhands, ParseError> {
2948
+ let mut weight = FontSynthesis::None;
2949
+ let mut style = FontSynthesisStyle::None;
2950
+ let mut small_caps = FontSynthesis::None;
2951
+ let mut position = FontSynthesis::None;
2952
+
2953
+ if input
2954
+ .try_parse(|input| input.expect_ident_matching("none"))
2955
+ .is_err()
2956
+ {
2957
+ let mut has_custom_value = false;
2958
+ while !input.is_exhausted() {
2959
+ try_match_ident_ignore_ascii_case! { input,
2960
+ "weight" if weight == FontSynthesis::None => {
2961
+ has_custom_value = true;
2962
+ weight = FontSynthesis::Auto;
2963
+ continue;
2964
+ },
2965
+ "style" if style == FontSynthesisStyle::None => {
2966
+ has_custom_value = true;
2967
+ style = FontSynthesisStyle::Auto;
2968
+ continue;
2969
+ },
2970
+ "small-caps" if small_caps == FontSynthesis::None => {
2971
+ has_custom_value = true;
2972
+ small_caps = FontSynthesis::Auto;
2973
+ continue;
2974
+ },
2975
+ "position" if position == FontSynthesis::None => {
2976
+ has_custom_value = true;
2977
+ position = FontSynthesis::Auto;
2978
+ continue;
2979
+ },
2980
+ "oblique-only" if style == FontSynthesisStyle::None => {
2981
+ has_custom_value = true;
2982
+ style = FontSynthesisStyle::ObliqueOnly;
2983
+ continue;
2984
+ },
2985
+ }
2986
+ }
2987
+ if !has_custom_value {
2988
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
2989
+ }
2990
+ }
2991
+
2992
+ Ok(expanded! {
2993
+ font_synthesis_weight: weight,
2994
+ font_synthesis_style: style,
2995
+ font_synthesis_small_caps: small_caps,
2996
+ font_synthesis_position: position,
2997
+ })
2998
+ }
2999
+
3000
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
3001
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
3002
+ where
3003
+ W: fmt::Write,
3004
+ {
3005
+ let mut writer = SequenceWriter::new(dest, " ");
3006
+ if self.font_synthesis_weight == &FontSynthesis::Auto {
3007
+ writer.raw_item("weight")?;
3008
+ }
3009
+ if self.font_synthesis_style != &FontSynthesisStyle::None {
3010
+ if self.font_synthesis_style == &FontSynthesisStyle::Auto {
3011
+ writer.raw_item("style")?;
3012
+ } else {
3013
+ writer.raw_item("oblique-only")?;
3014
+ }
3015
+ }
3016
+ if self.font_synthesis_small_caps == &FontSynthesis::Auto {
3017
+ writer.raw_item("small-caps")?;
3018
+ }
3019
+ if self.font_synthesis_position == &FontSynthesis::Auto {
3020
+ writer.raw_item("position")?;
3021
+ }
3022
+ if !writer.has_written() {
3023
+ writer.raw_item("none")?;
3024
+ }
3025
+ Ok(())
3026
+ }
3027
+ }
3028
+
3029
+ // The shorthand takes the sub-property names of the longhands, and not the
3030
+ // 'auto' keyword like they do, so we can't automatically derive this.
3031
+ impl SpecifiedValueInfo for Longhands {
3032
+ fn collect_completion_keywords(f: KeywordsCollectFn) {
3033
+ f(&[
3034
+ "none",
3035
+ "oblique-only",
3036
+ "small-caps",
3037
+ "position",
3038
+ "style",
3039
+ "weight",
3040
+ ]);
3041
+ }
3042
+ }
3043
+ }
3044
+
3045
+ #[cfg(feature = "gecko")]
3046
+ pub mod text_box {
3047
+ pub use crate::properties::generated::shorthands::text_box::*;
3048
+
3049
+ use super::*;
3050
+ use crate::values::specified::{TextBoxEdge, TextBoxTrim};
3051
+
3052
+ pub fn parse_value(
3053
+ context: &ParserContext,
3054
+ input: &mut Parser,
3055
+ ) -> Result<Longhands, ParseError> {
3056
+ let mut trim = None;
3057
+ let mut edge = None;
3058
+
3059
+ if input
3060
+ .try_parse(|input| input.expect_ident_matching("normal"))
3061
+ .is_ok()
3062
+ {
3063
+ return Ok(Longhands {
3064
+ text_box_trim: TextBoxTrim::NONE,
3065
+ text_box_edge: TextBoxEdge::Auto,
3066
+ });
3067
+ }
3068
+
3069
+ loop {
3070
+ try_parse_one!(context, input, trim, TextBoxTrim::parse);
3071
+ try_parse_one!(context, input, edge, TextBoxEdge::parse);
3072
+ break;
3073
+ }
3074
+
3075
+ if trim.is_none() && edge.is_none() {
3076
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
3077
+ }
3078
+
3079
+ // From https://drafts.csswg.org/css-inline-3/#text-box-shorthand:
3080
+ // > Omitting the 'text-box-trim' value sets it to 'trim-both'
3081
+ // > (not the initial value), while omitting the 'text-box-edge'
3082
+ // > value sets it to auto (the initial value).
3083
+ Ok(Longhands {
3084
+ text_box_trim: trim.unwrap_or(TextBoxTrim::TRIM_BOTH),
3085
+ text_box_edge: edge.unwrap_or(TextBoxEdge::Auto),
3086
+ })
3087
+ }
3088
+
3089
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
3090
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
3091
+ where
3092
+ W: fmt::Write,
3093
+ {
3094
+ if *self.text_box_trim == TextBoxTrim::NONE && *self.text_box_edge == TextBoxEdge::Auto
3095
+ {
3096
+ return dest.write_str("normal");
3097
+ }
3098
+
3099
+ let mut writer = SequenceWriter::new(dest, " ");
3100
+ if *self.text_box_trim != specified::TextBoxTrim::TRIM_BOTH {
3101
+ writer.item(self.text_box_trim)?;
3102
+ }
3103
+ if *self.text_box_edge != specified::TextBoxEdge::Auto {
3104
+ writer.item(self.text_box_edge)?;
3105
+ }
3106
+ if !writer.has_written() {
3107
+ self.text_box_trim.to_css(dest)?;
3108
+ }
3109
+ Ok(())
3110
+ }
3111
+ }
3112
+ }
3113
+
3114
+ #[cfg(feature = "gecko")]
3115
+ pub mod text_emphasis {
3116
+ pub use crate::properties::generated::shorthands::text_emphasis::*;
3117
+
3118
+ use super::*;
3119
+ use crate::properties::longhands::{text_emphasis_color, text_emphasis_style};
3120
+
3121
+ pub fn parse_value(
3122
+ context: &ParserContext,
3123
+ input: &mut Parser,
3124
+ ) -> Result<Longhands, ParseError> {
3125
+ let mut color = None;
3126
+ let mut style = None;
3127
+ let mut parsed = 0;
3128
+ loop {
3129
+ parsed += 1;
3130
+ try_parse_one!(context, input, color, text_emphasis_color::parse);
3131
+ try_parse_one!(context, input, style, text_emphasis_style::parse);
3132
+ parsed -= 1;
3133
+ break;
3134
+ }
3135
+ if parsed == 0 {
3136
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
3137
+ }
3138
+ Ok(expanded! {
3139
+ text_emphasis_color: unwrap_or_initial!(text_emphasis_color, color),
3140
+ text_emphasis_style: unwrap_or_initial!(text_emphasis_style, style),
3141
+ })
3142
+ }
3143
+ }
3144
+
3145
+ pub mod text_decoration {
3146
+ pub use crate::properties::generated::shorthands::text_decoration::*;
3147
+
3148
+ use super::*;
3149
+ use crate::properties::longhands::text_decoration_thickness;
3150
+ use crate::properties::longhands::{
3151
+ text_decoration_color, text_decoration_line, text_decoration_style,
3152
+ };
3153
+
3154
+ pub fn parse_value(
3155
+ context: &ParserContext,
3156
+ input: &mut Parser,
3157
+ ) -> Result<Longhands, ParseError> {
3158
+ let mut line = None;
3159
+ let mut style = None;
3160
+ let mut color = None;
3161
+ let mut thickness = None;
3162
+
3163
+ let mut parsed = 0;
3164
+ loop {
3165
+ parsed += 1;
3166
+ try_parse_one!(context, input, line, text_decoration_line::parse);
3167
+ try_parse_one!(context, input, style, text_decoration_style::parse);
3168
+ try_parse_one!(context, input, color, text_decoration_color::parse);
3169
+ try_parse_one!(context, input, thickness, text_decoration_thickness::parse);
3170
+ parsed -= 1;
3171
+ break;
3172
+ }
3173
+
3174
+ if parsed == 0 {
3175
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
3176
+ }
3177
+
3178
+ return Ok(expanded! {
3179
+ text_decoration_line: unwrap_or_initial!(text_decoration_line, line),
3180
+ text_decoration_style: unwrap_or_initial!(text_decoration_style, style),
3181
+ text_decoration_color: unwrap_or_initial!(text_decoration_color, color),
3182
+ text_decoration_thickness: unwrap_or_initial!(text_decoration_thickness, thickness),
3183
+ });
3184
+ }
3185
+
3186
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
3187
+ #[allow(unused)]
3188
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
3189
+ where
3190
+ W: fmt::Write,
3191
+ {
3192
+ use crate::values::specified::Color;
3193
+ use crate::values::specified::TextDecorationLine;
3194
+
3195
+ let is_solid_style =
3196
+ *self.text_decoration_style == text_decoration_style::SpecifiedValue::Solid;
3197
+ let is_current_color = *self.text_decoration_color == Color::CurrentColor;
3198
+ let is_auto_thickness = self.text_decoration_thickness.is_auto();
3199
+ let is_none = *self.text_decoration_line == TextDecorationLine::none();
3200
+
3201
+ let mut writer = SequenceWriter::new(dest, " ");
3202
+ if (is_solid_style && is_current_color && is_auto_thickness) || !is_none {
3203
+ writer.item(self.text_decoration_line)?;
3204
+ }
3205
+ if !is_auto_thickness {
3206
+ writer.item(self.text_decoration_thickness)?;
3207
+ }
3208
+ if !is_solid_style {
3209
+ writer.item(self.text_decoration_style)?;
3210
+ }
3211
+ if !is_current_color {
3212
+ writer.item(self.text_decoration_color)?;
3213
+ }
3214
+ Ok(())
3215
+ }
3216
+ }
3217
+ }
3218
+
3219
+ pub mod animation {
3220
+ pub use crate::properties::generated::shorthands::animation::*;
3221
+
3222
+ use super::*;
3223
+ use crate::properties::longhands::{
3224
+ animation_delay, animation_direction, animation_duration, animation_fill_mode,
3225
+ animation_iteration_count, animation_name, animation_play_state, animation_range_end,
3226
+ animation_range_start, animation_timeline, animation_timing_function,
3227
+ };
3228
+
3229
+ pub fn parse_value(
3230
+ context: &ParserContext,
3231
+ input: &mut Parser,
3232
+ ) -> Result<Longhands, ParseError> {
3233
+ struct SingleAnimation {
3234
+ animation_name: animation_name::SingleSpecifiedValue,
3235
+ animation_duration: animation_duration::SingleSpecifiedValue,
3236
+ animation_timing_function: animation_timing_function::SingleSpecifiedValue,
3237
+ animation_delay: animation_delay::SingleSpecifiedValue,
3238
+ animation_iteration_count: animation_iteration_count::SingleSpecifiedValue,
3239
+ animation_direction: animation_direction::SingleSpecifiedValue,
3240
+ animation_fill_mode: animation_fill_mode::SingleSpecifiedValue,
3241
+ animation_play_state: animation_play_state::SingleSpecifiedValue,
3242
+ }
3243
+
3244
+ fn parse_one_animation(
3245
+ context: &ParserContext,
3246
+ input: &mut Parser,
3247
+ ) -> Result<SingleAnimation, ParseError> {
3248
+ let mut name = None;
3249
+ let mut duration = None;
3250
+ let mut timing_function = None;
3251
+ let mut delay = None;
3252
+ let mut iteration_count = None;
3253
+ let mut direction = None;
3254
+ let mut fill_mode = None;
3255
+ let mut play_state = None;
3256
+
3257
+ let mut parsed = 0;
3258
+ loop {
3259
+ parsed += 1;
3260
+ try_parse_one!(
3261
+ context,
3262
+ input,
3263
+ duration,
3264
+ animation_duration::single_value::parse
3265
+ );
3266
+ try_parse_one!(
3267
+ context,
3268
+ input,
3269
+ timing_function,
3270
+ animation_timing_function::single_value::parse
3271
+ );
3272
+ try_parse_one!(context, input, delay, animation_delay::single_value::parse);
3273
+ try_parse_one!(
3274
+ context,
3275
+ input,
3276
+ iteration_count,
3277
+ animation_iteration_count::single_value::parse
3278
+ );
3279
+ try_parse_one!(
3280
+ context,
3281
+ input,
3282
+ direction,
3283
+ animation_direction::single_value::parse
3284
+ );
3285
+ try_parse_one!(
3286
+ context,
3287
+ input,
3288
+ fill_mode,
3289
+ animation_fill_mode::single_value::parse
3290
+ );
3291
+ try_parse_one!(
3292
+ context,
3293
+ input,
3294
+ play_state,
3295
+ animation_play_state::single_value::parse
3296
+ );
3297
+ try_parse_one!(context, input, name, animation_name::single_value::parse);
3298
+ parsed -= 1;
3299
+ break;
3300
+ }
3301
+
3302
+ if parsed == 0 {
3303
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
3304
+ }
3305
+ Ok(SingleAnimation {
3306
+ animation_name: name
3307
+ .unwrap_or_else(animation_name::single_value::get_initial_specified_value),
3308
+ animation_duration: duration
3309
+ .unwrap_or_else(animation_duration::single_value::get_initial_specified_value),
3310
+ animation_timing_function: timing_function.unwrap_or_else(
3311
+ animation_timing_function::single_value::get_initial_specified_value,
3312
+ ),
3313
+ animation_delay: delay
3314
+ .unwrap_or_else(animation_delay::single_value::get_initial_specified_value),
3315
+ animation_iteration_count: iteration_count.unwrap_or_else(
3316
+ animation_iteration_count::single_value::get_initial_specified_value,
3317
+ ),
3318
+ animation_direction: direction
3319
+ .unwrap_or_else(animation_direction::single_value::get_initial_specified_value),
3320
+ animation_fill_mode: fill_mode
3321
+ .unwrap_or_else(animation_fill_mode::single_value::get_initial_specified_value),
3322
+ animation_play_state: play_state.unwrap_or_else(
3323
+ animation_play_state::single_value::get_initial_specified_value,
3324
+ ),
3325
+ })
3326
+ }
3327
+
3328
+ let mut names = vec![];
3329
+ let mut durations = vec![];
3330
+ let mut timing_functions = vec![];
3331
+ let mut delays = vec![];
3332
+ let mut iteration_counts = vec![];
3333
+ let mut directions = vec![];
3334
+ let mut fill_modes = vec![];
3335
+ let mut play_states = vec![];
3336
+
3337
+ let results = input.parse_comma_separated(|i| parse_one_animation(context, i))?;
3338
+ for result in results.into_iter() {
3339
+ names.push(result.animation_name);
3340
+ durations.push(result.animation_duration);
3341
+ timing_functions.push(result.animation_timing_function);
3342
+ delays.push(result.animation_delay);
3343
+ iteration_counts.push(result.animation_iteration_count);
3344
+ directions.push(result.animation_direction);
3345
+ fill_modes.push(result.animation_fill_mode);
3346
+ play_states.push(result.animation_play_state);
3347
+ }
3348
+
3349
+ Ok(expanded! {
3350
+ animation_name: animation_name::SpecifiedValue(names.into()),
3351
+ animation_duration: animation_duration::SpecifiedValue(durations.into()),
3352
+ animation_timing_function: animation_timing_function::SpecifiedValue(timing_functions.into()),
3353
+ animation_delay: animation_delay::SpecifiedValue(delays.into()),
3354
+ animation_iteration_count: animation_iteration_count::SpecifiedValue(iteration_counts.into()),
3355
+ animation_direction: animation_direction::SpecifiedValue(directions.into()),
3356
+ animation_fill_mode: animation_fill_mode::SpecifiedValue(fill_modes.into()),
3357
+ animation_play_state: animation_play_state::SpecifiedValue(play_states.into()),
3358
+ animation_timeline: animation_timeline::SpecifiedValue(
3359
+ vec![animation_timeline::single_value::get_initial_specified_value()].into()
3360
+ ),
3361
+ // The animation-range properties are reset-only sub-properties of the animation
3362
+ // shorthand.
3363
+ // https://drafts.csswg.org/scroll-animations-1/#named-range-animation-declaration
3364
+ animation_range_start: animation_range_start::SpecifiedValue(
3365
+ vec![animation_range_start::single_value::get_initial_specified_value()].into()
3366
+ ),
3367
+ animation_range_end: animation_range_end::SpecifiedValue(
3368
+ vec![animation_range_end::single_value::get_initial_specified_value()].into()
3369
+ ),
3370
+ })
3371
+ }
3372
+
3373
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
3374
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
3375
+ where
3376
+ W: fmt::Write,
3377
+ {
3378
+ use crate::values::specified::easing::TimingFunction;
3379
+ use crate::values::specified::{
3380
+ AnimationDirection, AnimationFillMode, AnimationPlayState,
3381
+ };
3382
+ use crate::Zero;
3383
+ use style_traits::values::SequenceWriter;
3384
+
3385
+ let len = self.animation_name.0.len();
3386
+ if len == 0 {
3387
+ return Ok(());
3388
+ }
3389
+
3390
+ if len != self.animation_duration.0.len() {
3391
+ return Ok(());
3392
+ }
3393
+ if len != self.animation_timing_function.0.len() {
3394
+ return Ok(());
3395
+ }
3396
+ if len != self.animation_delay.0.len() {
3397
+ return Ok(());
3398
+ }
3399
+ if len != self.animation_iteration_count.0.len() {
3400
+ return Ok(());
3401
+ }
3402
+ if len != self.animation_direction.0.len() {
3403
+ return Ok(());
3404
+ }
3405
+ if len != self.animation_fill_mode.0.len() {
3406
+ return Ok(());
3407
+ }
3408
+ if len != self.animation_play_state.0.len() {
3409
+ return Ok(());
3410
+ }
3411
+
3412
+ // We don't serialize animation-timeline, animation-range-start and animation-range-end
3413
+ // if any of them are not the initial value.
3414
+ if self
3415
+ .animation_timeline
3416
+ .is_some_and(|v| v.0.len() != 1 || !v.0[0].is_auto())
3417
+ {
3418
+ return Ok(());
3419
+ }
3420
+ if self
3421
+ .animation_range_start
3422
+ .is_some_and(|v| v.0.len() != 1 || !v.0[0].0.is_normal())
3423
+ {
3424
+ return Ok(());
3425
+ }
3426
+ if self
3427
+ .animation_range_end
3428
+ .is_some_and(|v| v.0.len() != 1 || !v.0[0].0.is_normal())
3429
+ {
3430
+ return Ok(());
3431
+ }
3432
+
3433
+ for i in 0..len {
3434
+ if i != 0 {
3435
+ dest.write_str(", ")?;
3436
+ }
3437
+
3438
+ let has_duration = !self.animation_duration.0[i].is_auto()
3439
+ && !self.animation_duration.0[i].is_zero();
3440
+ let has_timing_function = !self.animation_timing_function.0[i].is_ease();
3441
+ let has_delay = !self.animation_delay.0[i].is_zero();
3442
+ let has_iteration_count = !self.animation_iteration_count.0[i].is_one();
3443
+ let has_direction =
3444
+ !matches!(self.animation_direction.0[i], AnimationDirection::Normal);
3445
+ let has_fill_mode =
3446
+ !matches!(self.animation_fill_mode.0[i], AnimationFillMode::None);
3447
+ let has_play_state =
3448
+ !matches!(self.animation_play_state.0[i], AnimationPlayState::Running);
3449
+ let animation_name = &self.animation_name.0[i];
3450
+ let has_name = !animation_name.is_none();
3451
+
3452
+ let mut writer = SequenceWriter::new(dest, " ");
3453
+
3454
+ if has_duration || has_delay {
3455
+ writer.item(&self.animation_duration.0[i])?;
3456
+ }
3457
+
3458
+ if has_timing_function || TimingFunction::match_keywords(animation_name) {
3459
+ writer.item(&self.animation_timing_function.0[i])?;
3460
+ }
3461
+
3462
+ if has_delay {
3463
+ writer.item(&self.animation_delay.0[i])?;
3464
+ }
3465
+ if has_iteration_count {
3466
+ writer.item(&self.animation_iteration_count.0[i])?;
3467
+ }
3468
+
3469
+ if has_direction || AnimationDirection::match_keywords(animation_name) {
3470
+ writer.item(&self.animation_direction.0[i])?;
3471
+ }
3472
+
3473
+ if has_fill_mode || AnimationFillMode::match_keywords(animation_name) {
3474
+ writer.item(&self.animation_fill_mode.0[i])?;
3475
+ }
3476
+
3477
+ if has_play_state || AnimationPlayState::match_keywords(animation_name) {
3478
+ writer.item(&self.animation_play_state.0[i])?;
3479
+ }
3480
+
3481
+ if has_name || !writer.has_written() {
3482
+ writer.item(animation_name)?;
3483
+ }
3484
+ }
3485
+ Ok(())
3486
+ }
3487
+ }
3488
+ }
3489
+
3490
+ pub mod mask {
3491
+ pub use crate::properties::generated::shorthands::mask::*;
3492
+
3493
+ use super::*;
3494
+ use crate::parser::Parse;
3495
+ use crate::properties::longhands::{
3496
+ mask_clip, mask_composite, mask_mode, mask_origin, mask_position_x, mask_position_y,
3497
+ mask_repeat,
3498
+ };
3499
+ use crate::properties::longhands::{mask_image, mask_size};
3500
+ use crate::values::specified::{Position, PositionComponent};
3501
+
3502
+ impl From<mask_origin::single_value::SpecifiedValue> for mask_clip::single_value::SpecifiedValue {
3503
+ fn from(
3504
+ origin: mask_origin::single_value::SpecifiedValue,
3505
+ ) -> mask_clip::single_value::SpecifiedValue {
3506
+ match origin {
3507
+ mask_origin::single_value::SpecifiedValue::ContentBox => {
3508
+ mask_clip::single_value::SpecifiedValue::ContentBox
3509
+ },
3510
+ mask_origin::single_value::SpecifiedValue::PaddingBox => {
3511
+ mask_clip::single_value::SpecifiedValue::PaddingBox
3512
+ },
3513
+ mask_origin::single_value::SpecifiedValue::BorderBox => {
3514
+ mask_clip::single_value::SpecifiedValue::BorderBox
3515
+ },
3516
+ #[cfg(feature = "gecko")]
3517
+ mask_origin::single_value::SpecifiedValue::FillBox => {
3518
+ mask_clip::single_value::SpecifiedValue::FillBox
3519
+ },
3520
+ #[cfg(feature = "gecko")]
3521
+ mask_origin::single_value::SpecifiedValue::StrokeBox => {
3522
+ mask_clip::single_value::SpecifiedValue::StrokeBox
3523
+ },
3524
+ #[cfg(feature = "gecko")]
3525
+ mask_origin::single_value::SpecifiedValue::ViewBox => {
3526
+ mask_clip::single_value::SpecifiedValue::ViewBox
3527
+ },
3528
+ }
3529
+ }
3530
+ }
3531
+
3532
+ pub fn parse_value(
3533
+ context: &ParserContext,
3534
+ input: &mut Parser,
3535
+ ) -> Result<Longhands, ParseError> {
3536
+ let mut mask_image = Vec::with_capacity(1);
3537
+ let mut mask_mode = Vec::with_capacity(1);
3538
+ let mut mask_position_x = Vec::with_capacity(1);
3539
+ let mut mask_position_y = Vec::with_capacity(1);
3540
+ let mut mask_size = Vec::with_capacity(1);
3541
+ let mut mask_repeat = Vec::with_capacity(1);
3542
+ let mut mask_origin = Vec::with_capacity(1);
3543
+ let mut mask_clip = Vec::with_capacity(1);
3544
+ let mut mask_composite = Vec::with_capacity(1);
3545
+
3546
+ input.parse_comma_separated(|input| {
3547
+ let mut image = None;
3548
+ let mut mode = None;
3549
+ let mut position = None;
3550
+ let mut size = None;
3551
+ let mut repeat = None;
3552
+ let mut origin = None;
3553
+ let mut clip = None;
3554
+ let mut composite = None;
3555
+ let mut parsed = 0;
3556
+ loop {
3557
+ parsed += 1;
3558
+
3559
+ try_parse_one!(context, input, image, mask_image::single_value::parse);
3560
+ if position.is_none() {
3561
+ if let Ok(value) = input.try_parse(|input| Position::parse(context, input)) {
3562
+ position = Some(value);
3563
+ size = input
3564
+ .try_parse(|input| {
3565
+ input.expect_delim('/')?;
3566
+ mask_size::single_value::parse(context, input)
3567
+ })
3568
+ .ok();
3569
+
3570
+ continue;
3571
+ }
3572
+ }
3573
+ try_parse_one!(context, input, repeat, mask_repeat::single_value::parse);
3574
+ try_parse_one!(context, input, origin, mask_origin::single_value::parse);
3575
+ try_parse_one!(context, input, clip, mask_clip::single_value::parse);
3576
+ try_parse_one!(
3577
+ context,
3578
+ input,
3579
+ composite,
3580
+ mask_composite::single_value::parse
3581
+ );
3582
+ try_parse_one!(context, input, mode, mask_mode::single_value::parse);
3583
+
3584
+ parsed -= 1;
3585
+ break;
3586
+ }
3587
+ if clip.is_none() {
3588
+ if let Some(origin) = origin {
3589
+ clip = Some(mask_clip::single_value::SpecifiedValue::from(origin));
3590
+ }
3591
+ }
3592
+ if parsed == 0 {
3593
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
3594
+ }
3595
+ if let Some(position) = position {
3596
+ mask_position_x.push(position.horizontal);
3597
+ mask_position_y.push(position.vertical);
3598
+ } else {
3599
+ mask_position_x.push(PositionComponent::zero());
3600
+ mask_position_y.push(PositionComponent::zero());
3601
+ }
3602
+ if let Some(m_image) = image {
3603
+ mask_image.push(m_image);
3604
+ } else {
3605
+ mask_image.push(mask_image::single_value::get_initial_specified_value());
3606
+ }
3607
+ if let Some(m_mode) = mode {
3608
+ mask_mode.push(m_mode);
3609
+ } else {
3610
+ mask_mode.push(mask_mode::single_value::get_initial_specified_value());
3611
+ }
3612
+ if let Some(m_size) = size {
3613
+ mask_size.push(m_size);
3614
+ } else {
3615
+ mask_size.push(mask_size::single_value::get_initial_specified_value());
3616
+ }
3617
+ if let Some(m_repeat) = repeat {
3618
+ mask_repeat.push(m_repeat);
3619
+ } else {
3620
+ mask_repeat.push(mask_repeat::single_value::get_initial_specified_value());
3621
+ }
3622
+ if let Some(m_origin) = origin {
3623
+ mask_origin.push(m_origin);
3624
+ } else {
3625
+ mask_origin.push(mask_origin::single_value::get_initial_specified_value());
3626
+ }
3627
+ if let Some(m_clip) = clip {
3628
+ mask_clip.push(m_clip);
3629
+ } else {
3630
+ mask_clip.push(mask_clip::single_value::get_initial_specified_value());
3631
+ }
3632
+ if let Some(m_composite) = composite {
3633
+ mask_composite.push(m_composite);
3634
+ } else {
3635
+ mask_composite.push(mask_composite::single_value::get_initial_specified_value());
3636
+ }
3637
+ Ok(())
3638
+ })?;
3639
+
3640
+ Ok(expanded! {
3641
+ mask_image: mask_image::SpecifiedValue(mask_image.into()),
3642
+ mask_mode: mask_mode::SpecifiedValue(mask_mode.into()),
3643
+ mask_position_x: mask_position_x::SpecifiedValue(mask_position_x.into()),
3644
+ mask_position_y: mask_position_y::SpecifiedValue(mask_position_y.into()),
3645
+ mask_size: mask_size::SpecifiedValue(mask_size.into()),
3646
+ mask_repeat: mask_repeat::SpecifiedValue(mask_repeat.into()),
3647
+ mask_origin: mask_origin::SpecifiedValue(mask_origin.into()),
3648
+ mask_clip: mask_clip::SpecifiedValue(mask_clip.into()),
3649
+ mask_composite: mask_composite::SpecifiedValue(mask_composite.into()),
3650
+ })
3651
+ }
3652
+
3653
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
3654
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
3655
+ where
3656
+ W: fmt::Write,
3657
+ {
3658
+ use crate::properties::longhands::mask_clip::single_value::computed_value::T as Clip;
3659
+ use crate::properties::longhands::mask_origin::single_value::computed_value::T as Origin;
3660
+ use style_traits::values::SequenceWriter;
3661
+
3662
+ let len = self.mask_image.0.len();
3663
+ if len == 0 {
3664
+ return Ok(());
3665
+ }
3666
+ if self.mask_mode.0.len() != len {
3667
+ return Ok(());
3668
+ }
3669
+ if self.mask_position_x.0.len() != len {
3670
+ return Ok(());
3671
+ }
3672
+ if self.mask_position_y.0.len() != len {
3673
+ return Ok(());
3674
+ }
3675
+ if self.mask_size.0.len() != len {
3676
+ return Ok(());
3677
+ }
3678
+ if self.mask_repeat.0.len() != len {
3679
+ return Ok(());
3680
+ }
3681
+ if self.mask_origin.0.len() != len {
3682
+ return Ok(());
3683
+ }
3684
+ if self.mask_clip.0.len() != len {
3685
+ return Ok(());
3686
+ }
3687
+ if self.mask_composite.0.len() != len {
3688
+ return Ok(());
3689
+ }
3690
+
3691
+ for i in 0..len {
3692
+ if i > 0 {
3693
+ dest.write_str(", ")?;
3694
+ }
3695
+
3696
+ let image = &self.mask_image.0[i];
3697
+ let mode = &self.mask_mode.0[i];
3698
+ let position_x = &self.mask_position_x.0[i];
3699
+ let position_y = &self.mask_position_y.0[i];
3700
+ let size = &self.mask_size.0[i];
3701
+ let repeat = &self.mask_repeat.0[i];
3702
+ let origin = &self.mask_origin.0[i];
3703
+ let clip = &self.mask_clip.0[i];
3704
+ let composite = &self.mask_composite.0[i];
3705
+
3706
+ let mut has_other = false;
3707
+ let has_image = *image != mask_image::single_value::get_initial_specified_value();
3708
+ has_other |= has_image;
3709
+ let has_mode = *mode != mask_mode::single_value::get_initial_specified_value();
3710
+ has_other |= has_mode;
3711
+ let has_size = *size != mask_size::single_value::get_initial_specified_value();
3712
+ has_other |= has_size;
3713
+ let has_repeat =
3714
+ *repeat != mask_repeat::single_value::get_initial_specified_value();
3715
+ has_other |= has_repeat;
3716
+ let has_composite =
3717
+ *composite != mask_composite::single_value::get_initial_specified_value();
3718
+ has_other |= has_composite;
3719
+ let has_position = *position_x != PositionComponent::zero()
3720
+ || *position_y != PositionComponent::zero();
3721
+ let has_origin = *origin != Origin::BorderBox;
3722
+ let has_clip = *clip != Clip::BorderBox;
3723
+
3724
+ if !has_other && !has_position && !has_origin && !has_clip {
3725
+ return image.to_css(dest);
3726
+ }
3727
+
3728
+ let mut writer = SequenceWriter::new(dest, " ");
3729
+ if has_image {
3730
+ writer.item(image)?;
3731
+ }
3732
+ if has_position || has_size {
3733
+ writer.write_item(|dest| {
3734
+ Position {
3735
+ horizontal: position_x.clone(),
3736
+ vertical: position_y.clone(),
3737
+ }
3738
+ .to_css(dest)?;
3739
+ if has_size {
3740
+ dest.write_str(" / ")?;
3741
+ size.to_css(dest)?;
3742
+ }
3743
+ Ok(())
3744
+ })?;
3745
+ }
3746
+
3747
+ if has_repeat {
3748
+ writer.item(repeat)?;
3749
+ }
3750
+
3751
+ #[cfg(feature = "gecko")]
3752
+ {
3753
+ if has_origin || (has_clip && *clip != Clip::NoClip) {
3754
+ writer.item(origin)?;
3755
+ }
3756
+ }
3757
+
3758
+ #[cfg(feature = "servo")]
3759
+ {
3760
+ if has_origin || has_clip {
3761
+ writer.item(origin)?;
3762
+ }
3763
+ }
3764
+
3765
+ if has_clip && *clip != From::from(*origin) {
3766
+ writer.item(clip)?;
3767
+ }
3768
+
3769
+ if has_composite {
3770
+ writer.item(composite)?;
3771
+ }
3772
+
3773
+ if has_mode {
3774
+ writer.item(mode)?;
3775
+ }
3776
+ }
3777
+
3778
+ Ok(())
3779
+ }
3780
+ }
3781
+ }
3782
+
3783
+ pub mod mask_position {
3784
+ pub use crate::properties::generated::shorthands::mask_position::*;
3785
+
3786
+ use super::*;
3787
+ use crate::properties::longhands::{mask_position_x, mask_position_y};
3788
+ use crate::values::specified::Position;
3789
+
3790
+ pub fn parse_value(
3791
+ context: &ParserContext,
3792
+ input: &mut Parser,
3793
+ ) -> Result<Longhands, ParseError> {
3794
+ // Vec grows from 0 to 4 by default on first push(). So allocate with capacity 1, so in
3795
+ // the common case of only one item we don't way overallocate, then shrink. Note that we
3796
+ // always push at least one item if parsing succeeds.
3797
+ let mut position_x = Vec::with_capacity(1);
3798
+ let mut position_y = Vec::with_capacity(1);
3799
+ input.parse_comma_separated(|input| {
3800
+ let value = Position::parse(context, input)?;
3801
+ position_x.push(value.horizontal);
3802
+ position_y.push(value.vertical);
3803
+ Ok(())
3804
+ })?;
3805
+
3806
+ if position_x.is_empty() {
3807
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
3808
+ }
3809
+
3810
+ Ok(expanded! {
3811
+ mask_position_x: mask_position_x::SpecifiedValue(position_x.into()),
3812
+ mask_position_y: mask_position_y::SpecifiedValue(position_y.into()),
3813
+ })
3814
+ }
3815
+
3816
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
3817
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
3818
+ where
3819
+ W: fmt::Write,
3820
+ {
3821
+ let len = self.mask_position_x.0.len();
3822
+ if len == 0 || self.mask_position_y.0.len() != len {
3823
+ return Ok(());
3824
+ }
3825
+
3826
+ for i in 0..len {
3827
+ Position {
3828
+ horizontal: self.mask_position_x.0[i].clone(),
3829
+ vertical: self.mask_position_y.0[i].clone(),
3830
+ }
3831
+ .to_css(dest)?;
3832
+
3833
+ if i < len - 1 {
3834
+ dest.write_str(", ")?;
3835
+ }
3836
+ }
3837
+
3838
+ Ok(())
3839
+ }
3840
+ }
3841
+ }
3842
+
3843
+ pub mod grid_template {
3844
+ pub use crate::properties::generated::shorthands::grid_template::*;
3845
+
3846
+ use super::*;
3847
+ use crate::parser::Parse;
3848
+ use crate::values::generics::grid::{concat_serialize_idents, TrackListValue};
3849
+ use crate::values::generics::grid::{TrackList, TrackSize};
3850
+ use crate::values::specified::grid::parse_line_names;
3851
+ use crate::values::specified::position::{
3852
+ GridTemplateAreas, TemplateAreasArc, TemplateAreasParser,
3853
+ };
3854
+ use crate::values::specified::{GenericGridTemplateComponent, GridTemplateComponent};
3855
+ use servo_arc::Arc;
3856
+
3857
+ pub fn parse_grid_template(
3858
+ context: &ParserContext,
3859
+ input: &mut Parser,
3860
+ ) -> Result<
3861
+ (
3862
+ GridTemplateComponent,
3863
+ GridTemplateComponent,
3864
+ GridTemplateAreas,
3865
+ ),
3866
+ ParseError,
3867
+ > {
3868
+ if let Ok(x) = input.try_parse(|i| {
3869
+ if i.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
3870
+ if !i.is_exhausted() {
3871
+ return Err(());
3872
+ }
3873
+ return Ok((
3874
+ GenericGridTemplateComponent::None,
3875
+ GenericGridTemplateComponent::None,
3876
+ GridTemplateAreas::None,
3877
+ ));
3878
+ }
3879
+ Err(())
3880
+ }) {
3881
+ return Ok(x);
3882
+ }
3883
+
3884
+ let first_line_names = input.try_parse(parse_line_names).unwrap_or_default();
3885
+ let mut areas_parser = TemplateAreasParser::default();
3886
+ if areas_parser.try_parse_string(input).is_ok() {
3887
+ let mut values = vec![];
3888
+ let mut line_names = vec![];
3889
+ line_names.push(first_line_names);
3890
+ loop {
3891
+ let size = input
3892
+ .try_parse(|i| TrackSize::parse(context, i))
3893
+ .unwrap_or_default();
3894
+ values.push(TrackListValue::TrackSize(size));
3895
+ let mut names = input.try_parse(parse_line_names).unwrap_or_default();
3896
+ let more_names = input.try_parse(parse_line_names);
3897
+
3898
+ match areas_parser.try_parse_string(input) {
3899
+ Ok(()) => {
3900
+ if let Ok(v) = more_names {
3901
+ let mut names_vec = names.into_vec();
3902
+ names_vec.extend(v);
3903
+ names = names_vec.into();
3904
+ }
3905
+ line_names.push(names);
3906
+ },
3907
+ Err(e) => {
3908
+ if more_names.is_ok() {
3909
+ return Err(e);
3910
+ }
3911
+ line_names.push(names);
3912
+ break;
3913
+ },
3914
+ };
3915
+ }
3916
+
3917
+ if line_names.len() == values.len() {
3918
+ line_names.push(Default::default());
3919
+ }
3920
+
3921
+ let template_areas = areas_parser
3922
+ .finish()
3923
+ .map_err(|()| ParseError::custom(StyleParseErrorKind::UnspecifiedError))?;
3924
+ let template_rows = TrackList {
3925
+ values: values.into(),
3926
+ line_names: line_names.into(),
3927
+ auto_repeat_index: usize::MAX,
3928
+ };
3929
+
3930
+ let template_cols = if input.try_parse(|i| i.expect_delim('/')).is_ok() {
3931
+ let value = GridTemplateComponent::parse_without_none(context, input)?;
3932
+ if let GenericGridTemplateComponent::TrackList(ref list) = value {
3933
+ if !list.is_explicit() {
3934
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
3935
+ }
3936
+ }
3937
+
3938
+ value
3939
+ } else {
3940
+ GridTemplateComponent::default()
3941
+ };
3942
+
3943
+ Ok((
3944
+ GenericGridTemplateComponent::TrackList(Box::new(template_rows)),
3945
+ template_cols,
3946
+ GridTemplateAreas::Areas(TemplateAreasArc(Arc::new(template_areas))),
3947
+ ))
3948
+ } else {
3949
+ let mut template_rows = GridTemplateComponent::parse(context, input)?;
3950
+ if let GenericGridTemplateComponent::TrackList(ref mut list) = template_rows {
3951
+ if list.line_names[0].is_empty() {
3952
+ list.line_names[0] = first_line_names;
3953
+ } else {
3954
+ return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
3955
+ }
3956
+ }
3957
+
3958
+ input.expect_delim('/')?;
3959
+ Ok((
3960
+ template_rows,
3961
+ GridTemplateComponent::parse(context, input)?,
3962
+ GridTemplateAreas::None,
3963
+ ))
3964
+ }
3965
+ }
3966
+
3967
+ #[inline]
3968
+ pub fn parse_value(
3969
+ context: &ParserContext,
3970
+ input: &mut Parser,
3971
+ ) -> Result<Longhands, ParseError> {
3972
+ let (rows, columns, areas) = parse_grid_template(context, input)?;
3973
+ Ok(expanded! {
3974
+ grid_template_rows: rows,
3975
+ grid_template_columns: columns,
3976
+ grid_template_areas: areas,
3977
+ })
3978
+ }
3979
+
3980
+ pub fn serialize_grid_template<W>(
3981
+ template_rows: &GridTemplateComponent,
3982
+ template_columns: &GridTemplateComponent,
3983
+ template_areas: &GridTemplateAreas,
3984
+ dest: &mut CssWriter<W>,
3985
+ ) -> fmt::Result
3986
+ where
3987
+ W: fmt::Write,
3988
+ {
3989
+ match *template_areas {
3990
+ GridTemplateAreas::None => {
3991
+ if template_rows.is_initial() && template_columns.is_initial() {
3992
+ return GridTemplateComponent::default().to_css(dest);
3993
+ }
3994
+ template_rows.to_css(dest)?;
3995
+ dest.write_str(" / ")?;
3996
+ template_columns.to_css(dest)
3997
+ },
3998
+ GridTemplateAreas::Areas(ref areas) => {
3999
+ if areas.0.strings.len() != template_rows.track_list_len() {
4000
+ return Ok(());
4001
+ }
4002
+
4003
+ let track_list = match *template_rows {
4004
+ GenericGridTemplateComponent::TrackList(ref list) => {
4005
+ if !list.is_explicit() {
4006
+ return Ok(());
4007
+ }
4008
+ list
4009
+ },
4010
+ _ => return Ok(()),
4011
+ };
4012
+
4013
+ match *template_columns {
4014
+ GenericGridTemplateComponent::TrackList(ref list) => {
4015
+ if !list.is_explicit() {
4016
+ return Ok(());
4017
+ }
4018
+ },
4019
+ GenericGridTemplateComponent::Subgrid(_) => {
4020
+ return Ok(());
4021
+ },
4022
+ _ => {},
4023
+ }
4024
+
4025
+ let mut names_iter = track_list.line_names.iter();
4026
+ for (((i, string), names), value) in areas
4027
+ .0
4028
+ .strings
4029
+ .iter()
4030
+ .enumerate()
4031
+ .zip(&mut names_iter)
4032
+ .zip(track_list.values.iter())
4033
+ {
4034
+ if i > 0 {
4035
+ dest.write_char(' ')?;
4036
+ }
4037
+
4038
+ if !names.is_empty() {
4039
+ concat_serialize_idents("[", "] ", names, " ", dest)?;
4040
+ }
4041
+
4042
+ string.to_css(dest)?;
4043
+
4044
+ if !value.is_initial() {
4045
+ dest.write_char(' ')?;
4046
+ value.to_css(dest)?;
4047
+ }
4048
+ }
4049
+
4050
+ if let Some(names) = names_iter.next() {
4051
+ concat_serialize_idents(" [", "]", names, " ", dest)?;
4052
+ }
4053
+
4054
+ if let GenericGridTemplateComponent::TrackList(ref list) = *template_columns {
4055
+ dest.write_str(" / ")?;
4056
+ list.to_css(dest)?;
4057
+ }
4058
+
4059
+ Ok(())
4060
+ },
4061
+ }
4062
+ }
4063
+
4064
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
4065
+ #[inline]
4066
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
4067
+ where
4068
+ W: fmt::Write,
4069
+ {
4070
+ serialize_grid_template(
4071
+ self.grid_template_rows,
4072
+ self.grid_template_columns,
4073
+ self.grid_template_areas,
4074
+ dest,
4075
+ )
4076
+ }
4077
+ }
4078
+ }
4079
+
4080
+ pub mod grid {
4081
+ pub use crate::properties::generated::shorthands::grid::*;
4082
+
4083
+ use super::*;
4084
+ use crate::parser::Parse;
4085
+ use crate::properties::longhands::{grid_auto_columns, grid_auto_flow, grid_auto_rows};
4086
+ use crate::values::generics::grid::GridTemplateComponent;
4087
+ use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas};
4088
+ use crate::values::specified::{GenericGridTemplateComponent, ImplicitGridTracks};
4089
+
4090
+ pub fn parse_value(
4091
+ context: &ParserContext,
4092
+ input: &mut Parser,
4093
+ ) -> Result<Longhands, ParseError> {
4094
+ let mut temp_rows = GridTemplateComponent::default();
4095
+ let mut temp_cols = GridTemplateComponent::default();
4096
+ let mut temp_areas = GridTemplateAreas::None;
4097
+ let mut auto_rows = ImplicitGridTracks::default();
4098
+ let mut auto_cols = ImplicitGridTracks::default();
4099
+ let mut flow = grid_auto_flow::get_initial_value();
4100
+
4101
+ fn parse_auto_flow(input: &mut Parser, is_row: bool) -> Result<GridAutoFlow, ParseError> {
4102
+ let mut track = None;
4103
+ let mut dense = GridAutoFlow::empty();
4104
+
4105
+ for _ in 0..2 {
4106
+ if input
4107
+ .try_parse(|i| i.expect_ident_matching("auto-flow"))
4108
+ .is_ok()
4109
+ {
4110
+ track = if is_row {
4111
+ Some(GridAutoFlow::ROW)
4112
+ } else {
4113
+ Some(GridAutoFlow::COLUMN)
4114
+ };
4115
+ } else if input
4116
+ .try_parse(|i| i.expect_ident_matching("dense"))
4117
+ .is_ok()
4118
+ {
4119
+ dense = GridAutoFlow::DENSE
4120
+ } else {
4121
+ break;
4122
+ }
4123
+ }
4124
+
4125
+ if track.is_some() {
4126
+ Ok(track.unwrap() | dense)
4127
+ } else {
4128
+ Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError))
4129
+ }
4130
+ }
4131
+
4132
+ if let Ok((rows, cols, areas)) =
4133
+ input.try_parse(|i| super::grid_template::parse_grid_template(context, i))
4134
+ {
4135
+ temp_rows = rows;
4136
+ temp_cols = cols;
4137
+ temp_areas = areas;
4138
+ } else if let Ok(rows) = input.try_parse(|i| GridTemplateComponent::parse(context, i)) {
4139
+ temp_rows = rows;
4140
+ input.expect_delim('/')?;
4141
+ flow = parse_auto_flow(input, false)?;
4142
+ auto_cols = input
4143
+ .try_parse(|i| grid_auto_columns::parse(context, i))
4144
+ .unwrap_or_default();
4145
+ } else {
4146
+ flow = parse_auto_flow(input, true)?;
4147
+ auto_rows = input
4148
+ .try_parse(|i| grid_auto_rows::parse(context, i))
4149
+ .unwrap_or_default();
4150
+ input.expect_delim('/')?;
4151
+ temp_cols = GridTemplateComponent::parse(context, input)?;
4152
+ }
4153
+
4154
+ Ok(expanded! {
4155
+ grid_template_rows: temp_rows,
4156
+ grid_template_columns: temp_cols,
4157
+ grid_template_areas: temp_areas,
4158
+ grid_auto_rows: auto_rows,
4159
+ grid_auto_columns: auto_cols,
4160
+ grid_auto_flow: flow,
4161
+ })
4162
+ }
4163
+
4164
+ impl<'a> LonghandsToSerialize<'a> {
4165
+ fn is_grid_template(&self) -> bool {
4166
+ self.grid_auto_rows.is_initial()
4167
+ && self.grid_auto_columns.is_initial()
4168
+ && *self.grid_auto_flow == grid_auto_flow::get_initial_value()
4169
+ }
4170
+ }
4171
+
4172
+ impl<'a> ToCss for LonghandsToSerialize<'a> {
4173
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
4174
+ where
4175
+ W: fmt::Write,
4176
+ {
4177
+ if self.is_grid_template() {
4178
+ return super::grid_template::serialize_grid_template(
4179
+ self.grid_template_rows,
4180
+ self.grid_template_columns,
4181
+ self.grid_template_areas,
4182
+ dest,
4183
+ );
4184
+ }
4185
+
4186
+ if *self.grid_template_areas != GridTemplateAreas::None {
4187
+ return Ok(());
4188
+ }
4189
+
4190
+ if self.grid_auto_flow.contains(GridAutoFlow::COLUMN) {
4191
+ if !self.grid_auto_rows.is_initial() || !self.grid_template_columns.is_initial() {
4192
+ return Ok(());
4193
+ }
4194
+
4195
+ if let GenericGridTemplateComponent::TrackList(ref list) = *self.grid_template_rows
4196
+ {
4197
+ if !list.is_explicit() {
4198
+ return Ok(());
4199
+ }
4200
+ }
4201
+
4202
+ self.grid_template_rows.to_css(dest)?;
4203
+ dest.write_str(" / auto-flow")?;
4204
+ if self.grid_auto_flow.contains(GridAutoFlow::DENSE) {
4205
+ dest.write_str(" dense")?;
4206
+ }
4207
+
4208
+ if !self.grid_auto_columns.is_initial() {
4209
+ dest.write_char(' ')?;
4210
+ self.grid_auto_columns.to_css(dest)?;
4211
+ }
4212
+
4213
+ return Ok(());
4214
+ }
4215
+
4216
+ if !self.grid_auto_columns.is_initial() || !self.grid_template_rows.is_initial() {
4217
+ return Ok(());
4218
+ }
4219
+
4220
+ if let GenericGridTemplateComponent::TrackList(ref list) = *self.grid_template_columns {
4221
+ if !list.is_explicit() {
4222
+ return Ok(());
4223
+ }
4224
+ }
4225
+
4226
+ dest.write_str("auto-flow")?;
4227
+ if self.grid_auto_flow.contains(GridAutoFlow::DENSE) {
4228
+ dest.write_str(" dense")?;
4229
+ }
4230
+
4231
+ if !self.grid_auto_rows.is_initial() {
4232
+ dest.write_char(' ')?;
4233
+ self.grid_auto_rows.to_css(dest)?;
4234
+ }
4235
+
4236
+ dest.write_str(" / ")?;
4237
+ self.grid_template_columns.to_css(dest)?;
4238
+ Ok(())
4239
+ }
4240
+ }
4241
+ }