1use alloc::{collections::btree_map::BTreeMap, format, string::String, string::ToString, vec::Vec};
11use core::fmt::Write;
12use core::hash::Hash;
13
14#[allow(clippy::wildcard_imports)]
17use crate::{
18 corety::*,
19 css::*,
20 props::{basic::*, layout::*, property::*, style::*},
21};
22
23pub trait FormatAsRustCode {
25 fn format_as_rust_code(&self, tabs: usize) -> String;
26}
27
28pub trait GetHash {
30 fn get_hash(&self) -> u64;
31}
32
33impl<T: Hash> GetHash for T {
34 fn get_hash(&self) -> u64 {
35 use core::hash::Hasher;
36 let mut hasher = std::hash::DefaultHasher::new();
37 self.hash(&mut hasher);
38 hasher.finish()
39 }
40}
41
42impl<T: FormatAsRustCode + 'static> FormatAsRustCode for BoxOrStatic<T> {
46 fn format_as_rust_code(&self, tabs: usize) -> String {
47 self.as_ref().format_as_rust_code(tabs)
48 }
49}
50
51#[derive(Debug, Default)]
54pub struct VecContents {
55 pub strings: BTreeMap<u64, AzString>,
57 pub style_filters: BTreeMap<u64, StyleFilterVec>,
58 pub style_background_sizes: BTreeMap<u64, StyleBackgroundSizeVec>,
59 pub style_background_repeats: BTreeMap<u64, StyleBackgroundRepeatVec>,
60 pub style_background_contents: BTreeMap<u64, StyleBackgroundContentVec>,
61 pub style_background_positions: BTreeMap<u64, StyleBackgroundPositionVec>,
62 pub style_transforms: BTreeMap<u64, StyleTransformVec>,
63 pub font_families: BTreeMap<u64, StyleFontFamilyVec>,
64 pub linear_color_stops: BTreeMap<u64, NormalizedLinearColorStopVec>,
65 pub radial_color_stops: BTreeMap<u64, NormalizedRadialColorStopVec>,
66}
67
68impl VecContents {
69 pub fn format(&self, tabs: usize) -> String {
70 let mut result = String::new();
71 let t = " ".repeat(tabs);
72 let t2 = " ".repeat(tabs + 1);
73
74 for (key, item) in &self.strings {
75 let _ = write!(
76 result,
77 "\r\n const STRING_{}: AzString = AzString::from_const_str(\"{}\");",
78 key,
79 item.as_str()
80 );
81 }
82
83 for (key, item) in &self.style_filters {
84 let val = item
85 .iter()
86 .map(|filter| format_style_filter(filter, tabs + 1))
87 .collect::<Vec<_>>()
88 .join(&format!(",\r\n{t}"));
89
90 let _ =
91 write!(result,
92 "\r\n const STYLE_FILTER_{key}_ITEMS: &[StyleFilter] = &[\r\n{t2}{val}\r\n{t}];"
93 );
94 }
95
96 for (key, item) in &self.style_background_sizes {
97 let val = item
98 .iter()
99 .map(format_style_background_size)
100 .collect::<Vec<_>>()
101 .join(&format!(",\r\n{t}"));
102
103 let _ = write!(
104 result,
105 "\r\n const STYLE_BACKGROUND_SIZE_{key}_ITEMS: &[StyleBackgroundSize] = \
106 &[\r\n{t2}{val}\r\n{t}];"
107 );
108 }
109
110 for (key, item) in &self.style_background_repeats {
111 let val = item
112 .iter()
113 .map(|bgr| bgr.format_as_rust_code(tabs + 1))
114 .collect::<Vec<_>>()
115 .join(&format!(",\r\n{t}"));
116
117 let _ =
118 write!(result,
119 "\r\n const STYLE_BACKGROUND_REPEAT_{key}_ITEMS: &[StyleBackgroundRepeat] = \
120 &[\r\n{t2}{val}\r\n{t}];"
121 );
122 }
123
124 for (key, item) in &self.style_background_contents {
125 let val = item
126 .iter()
127 .map(|bgc| format_style_background_content(bgc, tabs + 1))
128 .collect::<Vec<_>>()
129 .join(&format!(",\r\n{t}"));
130
131 let _ =
132 write!(result,
133 "\r\n const STYLE_BACKGROUND_CONTENT_{key}_ITEMS: &[StyleBackgroundContent] = \
134 &[\r\n{t2}{val}\r\n{t}];"
135 );
136 }
137
138 for (key, item) in &self.style_background_positions {
139 let val = item
140 .iter()
141 .map(|bgp| format_style_background_position(bgp, tabs))
142 .collect::<Vec<_>>()
143 .join(&format!(",\r\n{t}"));
144
145 let _ = write!(result,
146 "\r\n const STYLE_BACKGROUND_POSITION_{key}_ITEMS: &[StyleBackgroundPosition] = \
147 &[\r\n{t2}{val}\r\n{t}];"
148 );
149 }
150
151 for (key, item) in &self.style_transforms {
152 let val = format_style_transforms(item.as_ref(), tabs + 1);
153
154 let _ = write!(result,
155 "\r\n const STYLE_TRANSFORM_{key}_ITEMS: &[StyleTransform] = &[\r\n{t2}{val}\r\n{t}];"
156 );
157 }
158
159 for (key, item) in &self.font_families {
160 let val = format_font_ids(item.as_ref(), tabs + 1);
161
162 let _ = write!(result,
163 "\r\n const STYLE_FONT_FAMILY_{key}_ITEMS: &[StyleFontFamily] = &[\r\n{t2}{val}\r\n{t}];"
164 );
165 }
166
167 for (key, item) in &self.linear_color_stops {
168 let val = format_linear_color_stops(item.as_ref(), 1);
169
170 let _ = write!(
171 result,
172 "\r\n const LINEAR_COLOR_STOP_{key}_ITEMS: &[NormalizedLinearColorStop] = \
173 &[\r\n{t2}{val}\r\n{t}];"
174 );
175 }
176
177 for (key, item) in &self.radial_color_stops {
178 let val = format_radial_color_stops(item.as_ref(), tabs);
179
180 let _ = write!(
181 result,
182 "\r\n const RADIAL_COLOR_STOP_{key}_ITEMS: &[NormalizedRadialColorStop] = \
183 &[\r\n{t2}{val}\r\n{t}];"
184 );
185 }
186
187 result
188 }
189
190 #[allow(clippy::match_same_arms)]
194 pub fn insert_from_css_property(&mut self, prop: &CssProperty) {
195 match prop {
196 CssProperty::FontFamily(CssPropertyValue::Exact(v)) => {
197 for family in v {
198 match family {
199 StyleFontFamily::System(s) => {
200 let s = s.as_str();
203 let s = s.trim();
204 let s = s.trim_start_matches('\"');
205 let s = s.trim_end_matches('\"');
206 let s = s.trim_start_matches('\'');
207 let s = s.trim_end_matches('\'');
208
209 self.strings.insert(s.get_hash(), s.to_string().into());
210 }
211 StyleFontFamily::File(s) => {
212 let s = s.as_str();
213 let s = s.trim();
214 let s = s.trim_start_matches('\"');
215 let s = s.trim_end_matches('\"');
216 let s = s.trim_start_matches('\'');
217 let s = s.trim_end_matches('\'');
218
219 self.strings.insert(s.get_hash(), s.to_string().into());
220 }
221 _ => {}
222 }
223 }
224 self.font_families.insert(v.get_hash(), v.clone());
225 }
226 CssProperty::Transform(CssPropertyValue::Exact(v)) => {
227 self.style_transforms.insert(v.get_hash(), v.clone());
228 }
229 CssProperty::BackgroundRepeat(CssPropertyValue::Exact(v)) => {
230 self.style_background_repeats
231 .insert(v.get_hash(), v.clone());
232 }
233 CssProperty::BackgroundSize(CssPropertyValue::Exact(v)) => {
234 self.style_background_sizes.insert(v.get_hash(), v.clone());
235 }
236 CssProperty::BackgroundPosition(CssPropertyValue::Exact(v)) => {
237 self.style_background_positions
238 .insert(v.get_hash(), v.clone());
239 }
240 CssProperty::BackgroundContent(CssPropertyValue::Exact(ref v)) => {
241 for background in v {
242 match background {
243 StyleBackgroundContent::Image(id) => {
244 self.strings.insert(id.get_hash(), id.clone());
245 }
246 StyleBackgroundContent::LinearGradient(lg) => {
247 self.linear_color_stops
248 .insert(lg.stops.get_hash(), lg.stops.clone());
249 }
250 StyleBackgroundContent::RadialGradient(rg) => {
251 self.linear_color_stops
252 .insert(rg.stops.get_hash(), rg.stops.clone());
253 }
254 StyleBackgroundContent::ConicGradient(lg) => {
255 self.radial_color_stops
256 .insert(lg.stops.get_hash(), lg.stops.clone());
257 }
258 _ => {}
259 }
260 }
261 self.style_background_contents
262 .insert(v.get_hash(), v.clone());
263 }
264 CssProperty::Filter(CssPropertyValue::Exact(v)) => {
265 self.style_filters.insert(v.get_hash(), v.clone());
266 }
267 CssProperty::BackdropFilter(CssPropertyValue::Exact(v)) => {
268 self.style_filters.insert(v.get_hash(), v.clone());
269 }
270 _ => {}
271 }
272 }
273}
274
275#[must_use]
279pub fn format_pixel_value(p: &PixelValue) -> String {
280 let value = p.number.get();
281
282 let abs_val = libm::fabsf(value);
286 let sign: isize = if value < 0.0 { -1 } else { 1 };
287 let pre_comma = f32_to_isize(libm::floorf(abs_val)) * sign;
288 let post_comma = f32_to_isize(libm::roundf((abs_val - libm::floorf(abs_val)) * 100.0));
289
290 match p.metric {
291 SizeMetric::Pt => format!(
292 "PixelValue::const_pt_fractional({pre_comma}, {post_comma})"
293 ),
294 SizeMetric::Em => format!(
295 "PixelValue::const_em_fractional({pre_comma}, {post_comma})"
296 ),
297 other => format!(
298 "PixelValue::const_from_metric_fractional(SizeMetric::{other:?}, {pre_comma}, {post_comma})"
299 ),
300 }
301}
302
303#[inline]
308#[allow(clippy::cast_possible_truncation)]
309const fn f32_to_isize(v: f32) -> isize {
310 v as isize
311}
312
313#[must_use]
315pub fn format_pixel_value_no_percent(p: &PixelValueNoPercent) -> String {
316 format!(
317 "PixelValueNoPercent {{ inner: {} }}",
318 format_pixel_value(&p.inner)
319 )
320}
321
322#[must_use]
324pub fn format_float_value(f: &FloatValue) -> String {
325 let value = f.get();
326 let abs_val = libm::fabsf(value);
327 let sign: isize = if value < 0.0 { -1 } else { 1 };
328 let pre_comma = f32_to_isize(libm::floorf(abs_val)) * sign;
329 let post_comma = f32_to_isize(libm::roundf((abs_val - libm::floorf(abs_val)) * 100.0));
330 format!("FloatValue::const_new_fractional({pre_comma}, {post_comma})")
331}
332
333#[must_use]
335pub fn format_percentage_value(f: &PercentageValue) -> String {
336 let value = f.normalized() * 100.0;
337 let abs_val = libm::fabsf(value);
338 let sign: isize = if value < 0.0 { -1 } else { 1 };
339 let pre_comma = f32_to_isize(libm::floorf(abs_val)) * sign;
340 let post_comma = f32_to_isize(libm::roundf((abs_val - libm::floorf(abs_val)) * 100.0));
341 format!("PercentageValue::const_new_fractional({pre_comma}, {post_comma})")
342}
343
344#[must_use]
346pub fn format_angle_value(f: &AngleValue) -> String {
347 let value = f.number.get();
348 let abs_val = libm::fabsf(value);
349 let sign: isize = if value < 0.0 { -1 } else { 1 };
350 let pre_comma = f32_to_isize(libm::floorf(abs_val)) * sign;
351 let post_comma = f32_to_isize(libm::roundf((abs_val - libm::floorf(abs_val)) * 100.0));
352 format!(
353 "AngleValue::const_from_metric_fractional(AngleMetric::{:?}, {}, {})",
354 f.metric, pre_comma, post_comma
355 )
356}
357
358#[must_use]
360pub fn format_color_value(c: &ColorU) -> String {
361 format!(
362 "ColorU {{ r: {}, g: {}, b: {}, a: {} }}",
363 c.r, c.g, c.b, c.a
364 )
365}
366
367fn format_grid_line(line: &GridLine, _tabs: usize) -> String {
368 match line {
369 GridLine::Auto => "GridLine::Auto".to_string(),
370 GridLine::Line(n) => format!("GridLine::Line({n})"),
371 GridLine::Named(named) => format!(
372 "GridLine::Named(NamedGridLine {{ grid_line_name: AzString::from_const_str({:?}), span_count: {} }})",
373 named.grid_line_name.as_ref(),
374 named.span_count,
375 ),
376 GridLine::Span(n) => format!("GridLine::Span({n})"),
377 }
378}
379
380fn format_color_or_system(c: ColorOrSystem) -> String {
381 use crate::props::basic::color::{ColorOrSystem, SystemColorRef};
382 match c {
383 ColorOrSystem::Color(color) => {
384 format!("ColorOrSystem::Color({})", format_color_value(&color))
385 }
386 ColorOrSystem::System(system_ref) => {
387 let variant = match system_ref {
388 SystemColorRef::Text => "Text",
389 SystemColorRef::Background => "Background",
390 SystemColorRef::Accent => "Accent",
391 SystemColorRef::AccentText => "AccentText",
392 SystemColorRef::ButtonFace => "ButtonFace",
393 SystemColorRef::ButtonText => "ButtonText",
394 SystemColorRef::WindowBackground => "WindowBackground",
395 SystemColorRef::SelectionBackground => "SelectionBackground",
396 SystemColorRef::SelectionText => "SelectionText",
397 };
398 format!("ColorOrSystem::System(SystemColorRef::{variant})")
399 }
400 }
401}
402
403macro_rules! impl_float_value_fmt {
406 ($struct_name:ident) => {
407 impl FormatAsRustCode for $struct_name {
408 fn format_as_rust_code(&self, _tabs: usize) -> String {
409 format!(
410 "{} {{ inner: {} }}",
411 stringify!($struct_name),
412 format_float_value(&self.inner)
413 )
414 }
415 }
416 };
417}
418
419impl_float_value_fmt!(LayoutFlexGrow);
420impl_float_value_fmt!(LayoutFlexShrink);
421
422macro_rules! impl_percentage_value_fmt {
423 ($struct_name:ident) => {
424 impl FormatAsRustCode for $struct_name {
425 fn format_as_rust_code(&self, _tabs: usize) -> String {
426 format!(
427 "{} {{ inner: {} }}",
428 stringify!($struct_name),
429 format_percentage_value(&self.inner)
430 )
431 }
432 }
433 };
434}
435
436impl_percentage_value_fmt!(StyleLineHeight);
437impl_percentage_value_fmt!(StyleOpacity);
438
439macro_rules! impl_pixel_value_fmt {
440 ($struct_name:ident) => {
441 impl FormatAsRustCode for $struct_name {
442 fn format_as_rust_code(&self, _tabs: usize) -> String {
443 format!(
444 "{} {{ inner: {} }}",
445 stringify!($struct_name),
446 format_pixel_value(&self.inner)
447 )
448 }
449 }
450 };
451}
452
453impl_pixel_value_fmt!(StyleTabSize);
454impl_pixel_value_fmt!(StyleBorderTopLeftRadius);
455impl_pixel_value_fmt!(StyleBorderBottomLeftRadius);
456impl_pixel_value_fmt!(StyleBorderTopRightRadius);
457impl_pixel_value_fmt!(StyleBorderBottomRightRadius);
458
459impl_pixel_value_fmt!(LayoutBorderTopWidth);
460impl_pixel_value_fmt!(LayoutBorderLeftWidth);
461impl_pixel_value_fmt!(LayoutBorderRightWidth);
462impl_pixel_value_fmt!(LayoutBorderBottomWidth);
463impl_pixel_value_fmt!(StyleLetterSpacing);
464impl_pixel_value_fmt!(StyleWordSpacing);
465impl_pixel_value_fmt!(StyleFontSize);
466
467impl_pixel_value_fmt!(LayoutMarginTop);
468impl_pixel_value_fmt!(LayoutMarginBottom);
469impl_pixel_value_fmt!(LayoutMarginRight);
470impl_pixel_value_fmt!(LayoutMarginLeft);
471
472impl_pixel_value_fmt!(LayoutPaddingTop);
473impl_pixel_value_fmt!(LayoutPaddingBottom);
474impl_pixel_value_fmt!(LayoutPaddingRight);
475impl_pixel_value_fmt!(LayoutPaddingLeft);
476impl_pixel_value_fmt!(LayoutPaddingInlineStart);
477impl_pixel_value_fmt!(LayoutPaddingInlineEnd);
478
479impl FormatAsRustCode for LayoutWidth {
480 fn format_as_rust_code(&self, _tabs: usize) -> String {
481 match self {
482 Self::Auto => "LayoutWidth::Auto".to_string(),
483 Self::Px(px) => format!("LayoutWidth::Px({})", format_pixel_value(px)),
484 Self::MinContent => "LayoutWidth::MinContent".to_string(),
485 Self::MaxContent => "LayoutWidth::MaxContent".to_string(),
486 Self::FitContent(px) => format!("LayoutWidth::FitContent({})", format_pixel_value(px)),
487 Self::Calc(items) => format!("LayoutWidth::Calc(/* {} items */)", items.len()),
488 }
489 }
490}
491
492impl FormatAsRustCode for LayoutHeight {
493 fn format_as_rust_code(&self, _tabs: usize) -> String {
494 match self {
495 Self::Auto => "LayoutHeight::Auto".to_string(),
496 Self::Px(px) => format!("LayoutHeight::Px({})", format_pixel_value(px)),
497 Self::MinContent => "LayoutHeight::MinContent".to_string(),
498 Self::MaxContent => "LayoutHeight::MaxContent".to_string(),
499 Self::FitContent(px) => format!("LayoutHeight::FitContent({})", format_pixel_value(px)),
500 Self::Calc(items) => format!("LayoutHeight::Calc(/* {} items */)", items.len()),
501 }
502 }
503}
504
505impl_pixel_value_fmt!(LayoutMinHeight);
506impl_pixel_value_fmt!(LayoutMinWidth);
507impl_pixel_value_fmt!(LayoutMaxWidth);
508impl_pixel_value_fmt!(LayoutMaxHeight);
509impl_pixel_value_fmt!(LayoutTop);
510impl_pixel_value_fmt!(LayoutInsetBottom);
511
512impl_pixel_value_fmt!(LayoutRight);
513impl_pixel_value_fmt!(LayoutLeft);
514
515impl_pixel_value_fmt!(LayoutColumnGap);
518impl_pixel_value_fmt!(LayoutRowGap);
519
520impl FormatAsRustCode for GridTemplate {
521 fn format_as_rust_code(&self, tabs: usize) -> String {
522 let tracks: Vec<String> = self
523 .tracks
524 .as_ref()
525 .iter()
526 .map(|t| t.format_as_rust_code(tabs))
527 .collect();
528 format!(
529 "GridTemplate {{ tracks: GridTrackSizingVec::from_vec(vec![{}]) }}",
530 tracks.join(", ")
531 )
532 }
533}
534
535impl FormatAsRustCode for GridPlacement {
536 fn format_as_rust_code(&self, tabs: usize) -> String {
537 format!(
538 "GridPlacement {{ grid_start: {}, grid_end: {} }}",
539 format_grid_line(&self.grid_start, tabs),
540 format_grid_line(&self.grid_end, tabs),
541 )
542 }
543}
544
545impl_color_value_fmt!(StyleTextColor);
546impl_color_value_fmt!(StyleBorderTopColor);
547impl_color_value_fmt!(StyleBorderLeftColor);
548impl_color_value_fmt!(StyleBorderRightColor);
549impl_color_value_fmt!(StyleBorderBottomColor);
550
551impl_enum_fmt!(
552 StyleMixBlendMode,
553 Normal,
554 Multiply,
555 Screen,
556 Overlay,
557 Darken,
558 Lighten,
559 ColorDodge,
560 ColorBurn,
561 HardLight,
562 SoftLight,
563 Difference,
564 Exclusion,
565 Hue,
566 Saturation,
567 Color,
568 Luminosity
569);
570
571impl_enum_fmt!(StyleHyphens, None, Manual, Auto);
572impl_enum_fmt!(StyleWordBreak, Normal, BreakAll, KeepAll, BreakWord);
573impl_enum_fmt!(StyleOverflowWrap, Normal, Anywhere, BreakWord);
574impl_enum_fmt!(StyleLineBreak, Auto, Loose, Normal, Strict, Anywhere);
575impl_enum_fmt!(StyleObjectFit, Fill, Contain, Cover, None, ScaleDown);
576impl_enum_fmt!(StyleTextOverflow, Clip, Ellipsis);
577
578impl FormatAsRustCode for StyleObjectPosition {
579 fn format_as_rust_code(&self, _tabs: usize) -> String {
580 format!(
581 "StyleObjectPosition {{ horizontal: {}, vertical: {} }}",
582 format_background_position_horizontal(&self.horizontal),
583 format_background_position_vertical(&self.vertical)
584 )
585 }
586}
587
588impl FormatAsRustCode for StyleAspectRatio {
589 fn format_as_rust_code(&self, _tabs: usize) -> String {
590 match self {
591 Self::Auto => "StyleAspectRatio::Auto".to_string(),
592 Self::Ratio(r) => format!(
593 "StyleAspectRatio::Ratio(AspectRatioValue {{ width: {}, height: {} }})",
594 r.width, r.height
595 ),
596 }
597 }
598}
599
600impl_enum_fmt!(StyleTextOrientation, Mixed, Upright, Sideways);
601impl_enum_fmt!(
602 StyleTextAlignLast,
603 Auto,
604 Start,
605 End,
606 Left,
607 Right,
608 Center,
609 Justify
610);
611
612impl_enum_fmt!(
613 StyleTextTransform,
614 None,
615 Capitalize,
616 Uppercase,
617 Lowercase,
618 FullWidth
619);
620
621impl_enum_fmt!(StyleDirection, Ltr, Rtl);
622
623impl_enum_fmt!(
624 StyleWhiteSpace,
625 Normal,
626 Pre,
627 Nowrap,
628 PreWrap,
629 PreLine,
630 BreakSpaces
631);
632
633impl_enum_fmt!(StyleVisibility, Visible, Hidden, Collapse);
634
635impl_enum_fmt!(LayoutWritingMode, HorizontalTb, VerticalRl, VerticalLr);
636
637impl_enum_fmt!(LayoutClear, None, Left, Right, Both);
638
639impl_enum_fmt!(
640 StyleCursor,
641 Alias,
642 AllScroll,
643 Cell,
644 ColResize,
645 ContextMenu,
646 Copy,
647 Crosshair,
648 Default,
649 EResize,
650 EwResize,
651 Grab,
652 Grabbing,
653 Help,
654 Move,
655 NResize,
656 NsResize,
657 NeswResize,
658 NwseResize,
659 Pointer,
660 Progress,
661 RowResize,
662 SResize,
663 SeResize,
664 Text,
665 Unset,
666 VerticalText,
667 WResize,
668 Wait,
669 ZoomIn,
670 ZoomOut
671);
672
673impl_enum_fmt!(
674 BorderStyle,
675 None,
676 Solid,
677 Double,
678 Dotted,
679 Dashed,
680 Hidden,
681 Groove,
682 Ridge,
683 Inset,
684 Outset
685);
686
687impl_enum_fmt!(
688 StyleBackgroundRepeat,
689 NoRepeat,
690 PatternRepeat,
691 RepeatX,
692 RepeatY
693);
694
695impl_enum_fmt!(
696 LayoutDisplay,
697 None,
698 Block,
699 Inline,
700 InlineBlock,
701 Flex,
702 InlineFlex,
703 Table,
704 InlineTable,
705 TableRowGroup,
706 TableHeaderGroup,
707 TableFooterGroup,
708 TableRow,
709 TableColumnGroup,
710 TableColumn,
711 TableCell,
712 TableCaption,
713 ListItem,
714 RunIn,
715 Marker,
716 Grid,
717 InlineGrid,
718 FlowRoot,
719 Contents
720);
721
722impl_enum_fmt!(LayoutFloat, Left, Right, None);
723
724impl_enum_fmt!(LayoutBoxSizing, ContentBox, BorderBox);
725
726impl_enum_fmt!(LayoutFlexDirection, Row, RowReverse, Column, ColumnReverse);
727
728impl_enum_fmt!(LayoutFlexWrap, Wrap, NoWrap, WrapReverse);
729
730impl_enum_fmt!(
731 LayoutJustifyContent,
732 Start,
733 End,
734 FlexStart,
735 FlexEnd,
736 Center,
737 SpaceBetween,
738 SpaceAround,
739 SpaceEvenly
740);
741
742impl_enum_fmt!(LayoutAlignItems, Stretch, Center, Start, End, Baseline);
743
744impl_enum_fmt!(
745 LayoutAlignContent,
746 Start,
747 End,
748 Stretch,
749 Center,
750 SpaceBetween,
751 SpaceAround
752);
753
754impl_enum_fmt!(Shape, Circle, Ellipse);
755
756impl_enum_fmt!(LayoutOverflow, Auto, Scroll, Visible, Hidden, Clip);
757
758impl_enum_fmt!(StyleTextAlign, Center, Left, Right, Justify, Start, End);
759
760impl_enum_fmt!(StyleUserSelect, Auto, Text, None, All);
761
762impl_enum_fmt!(StyleTextDecoration, None, Underline, Overline, LineThrough);
763
764impl_enum_fmt!(
765 DirectionCorner,
766 Right,
767 Left,
768 Top,
769 Bottom,
770 TopRight,
771 TopLeft,
772 BottomRight,
773 BottomLeft
774);
775
776impl_enum_fmt!(ExtendMode, Clamp, Repeat);
777
778impl_enum_fmt!(StyleBackfaceVisibility, Visible, Hidden);
779impl_enum_fmt!(StyleAppRegion, NoDrag, Drag);
780impl_enum_fmt!(StyleSpatialNavigationAction, Auto, Focus, Scroll);
781impl_enum_fmt!(StyleSpatialNavigationContain, Auto, Contain);
782
783impl_enum_fmt!(
784 StyleUnicodeBidi,
785 Normal,
786 Embed,
787 Isolate,
788 BidiOverride,
789 IsolateOverride,
790 Plaintext
791);
792impl_enum_fmt!(StyleTextBoxTrim, None, TrimStart, TrimEnd, TrimBoth);
793impl_enum_fmt!(
794 TextBoxEdgeOver,
795 Auto,
796 Text,
797 Cap,
798 Ex,
799 Ideographic,
800 IdeographicInk
801);
802impl_enum_fmt!(
803 TextBoxEdgeUnder,
804 Auto,
805 Text,
806 Alphabetic,
807 Ideographic,
808 IdeographicInk
809);
810impl FormatAsRustCode for StyleTextBoxEdge {
811 fn format_as_rust_code(&self, tabs: usize) -> String {
812 format!(
813 "StyleTextBoxEdge {{ over: {}, under: {} }}",
814 self.over.format_as_rust_code(tabs),
815 self.under.format_as_rust_code(tabs)
816 )
817 }
818}
819impl_enum_fmt!(
820 StyleDominantBaseline,
821 Auto,
822 TextBottom,
823 Alphabetic,
824 Ideographic,
825 Middle,
826 Central,
827 Mathematical,
828 Hanging,
829 TextTop
830);
831impl_enum_fmt!(
832 StyleAlignmentBaseline,
833 Baseline,
834 TextBottom,
835 Alphabetic,
836 Ideographic,
837 Middle,
838 Central,
839 Mathematical,
840 TextTop
841);
842impl_enum_fmt!(StyleBaselineSource, Auto, First, Last);
843impl_enum_fmt!(
844 StyleLineFitEdge,
845 Leading,
846 Text,
847 Cap,
848 Ex,
849 Ideographic,
850 IdeographicInk,
851 Alphabetic
852);
853impl_enum_fmt!(
854 StyleInitialLetterAlign,
855 Auto,
856 Alphabetic,
857 Hanging,
858 Ideographic
859);
860impl_enum_fmt!(StyleInitialLetterWrap, None, First, All, Grid);
861impl_enum_fmt!(StyleScrollbarGutter, Auto, Stable, StableBothEdges);
862
863impl FormatAsRustCode for StyleOverflowClipMargin {
864 fn format_as_rust_code(&self, tabs: usize) -> String {
865 format!(
866 "StyleOverflowClipMargin {{ inner: {} }}",
867 self.inner.format_as_rust_code(tabs)
868 )
869 }
870}
871
872impl FormatAsRustCode for StyleClipRect {
873 fn format_as_rust_code(&self, _tabs: usize) -> String {
874 fn fmt_edge(o: OptionF32) -> String {
875 match o {
876 OptionF32::None => String::from("OptionF32::None"),
877 OptionF32::Some(v) => format!("OptionF32::Some({v:?})"),
878 }
879 }
880 format!(
881 "StyleClipRect {{ top: {}, right: {}, bottom: {}, left: {} }}",
882 fmt_edge(self.top),
883 fmt_edge(self.right),
884 fmt_edge(self.bottom),
885 fmt_edge(self.left),
886 )
887 }
888}
889
890fn format_style_background_size(c: &StyleBackgroundSize) -> String {
893 match c {
894 StyleBackgroundSize::Contain => String::from("StyleBackgroundSize::Contain"),
895 StyleBackgroundSize::Cover => String::from("StyleBackgroundSize::Cover"),
896 StyleBackgroundSize::ExactSize(size) => format!(
897 "StyleBackgroundSize::ExactSize(PixelValueSize {{ width: {}, height: {} }})",
898 format_pixel_value(&size.width),
899 format_pixel_value(&size.height)
900 ),
901 }
902}
903
904#[must_use]
908pub fn format_scrollbar_info(s: &ScrollbarInfo, tabs: usize) -> String {
909 let t = String::from(" ").repeat(tabs);
910 let t1 = String::from(" ").repeat(tabs + 1);
911 format!(
912 "ScrollbarInfo {{\r\n{}width: {},\r\n{}padding_left: {},\r\n{}padding_right: \
913 {},\r\n{}track: {},\r\n{}thumb: {},\r\n{}button: {},\r\n{}button: {},\r\n{}resizer: \
914 {},\r\n{}}}",
915 t1,
916 s.width.format_as_rust_code(tabs + 1),
917 t1,
918 s.padding_left.format_as_rust_code(tabs + 1),
919 t1,
920 s.padding_right.format_as_rust_code(tabs + 1),
921 t1,
922 format_style_background_content(&s.track, tabs + 1),
923 t1,
924 format_style_background_content(&s.thumb, tabs + 1),
925 t1,
926 format_style_background_content(&s.button, tabs + 1),
927 t1,
928 format_style_background_content(&s.corner, tabs + 1),
929 t1,
930 format_style_background_content(&s.resizer, tabs + 1),
931 t
932 )
933}
934
935fn format_style_background_content(content: &StyleBackgroundContent, tabs: usize) -> String {
938 match content {
939 StyleBackgroundContent::LinearGradient(l) => format!(
940 "StyleBackgroundContent::LinearGradient({})",
941 format_linear_gradient(l, tabs)
942 ),
943 StyleBackgroundContent::RadialGradient(r) => format!(
944 "StyleBackgroundContent::RadialGradient({})",
945 format_radial_gradient(r, tabs)
946 ),
947 StyleBackgroundContent::ConicGradient(r) => format!(
948 "StyleBackgroundContent::ConicGradient({})",
949 format_conic_gradient(r, tabs)
950 ),
951 StyleBackgroundContent::Image(id) => format!("StyleBackgroundContent::Image({id:?})"),
952 StyleBackgroundContent::Color(c) => {
953 format!("StyleBackgroundContent::Color({})", format_color_value(c))
954 }
955 StyleBackgroundContent::SystemColor(s) => {
956 use crate::props::basic::color::SystemColorRef;
957 let variant = match s {
958 SystemColorRef::Text => "Text",
959 SystemColorRef::Background => "Background",
960 SystemColorRef::Accent => "Accent",
961 SystemColorRef::AccentText => "AccentText",
962 SystemColorRef::ButtonFace => "ButtonFace",
963 SystemColorRef::ButtonText => "ButtonText",
964 SystemColorRef::WindowBackground => "WindowBackground",
965 SystemColorRef::SelectionBackground => "SelectionBackground",
966 SystemColorRef::SelectionText => "SelectionText",
967 };
968 format!("StyleBackgroundContent::SystemColor(SystemColorRef::{variant})")
969 }
970 }
971}
972
973fn format_direction(d: &Direction, tabs: usize) -> String {
974 match d {
975 Direction::Angle(fv) => format!("Direction::Angle({})", format_angle_value(fv)),
976 Direction::FromTo(DirectionCorners { dir_from, dir_to }) => format!(
977 "Direction::FromTo(DirectionCorners {{ dir_from: {}, dir_to: {} }})",
978 dir_from.format_as_rust_code(tabs + 1),
979 dir_to.format_as_rust_code(tabs + 1)
980 ),
981 }
982}
983
984fn format_linear_gradient(l: &LinearGradient, tabs: usize) -> String {
985 let t = String::from(" ").repeat(tabs);
986 let t1 = String::from(" ").repeat(tabs + 1);
987 format!(
988 "LinearGradient {{\r\n{}direction: {},\r\n{}extend_mode: {},\r\n{}stops: \
989 NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
990 t1,
991 format_direction(&l.direction, tabs + 1),
992 t1,
993 l.extend_mode.format_as_rust_code(tabs + 1),
994 t1,
995 l.stops.get_hash(),
996 t,
997 )
998}
999
1000fn format_conic_gradient(r: &ConicGradient, tabs: usize) -> String {
1001 let t = String::from(" ").repeat(tabs);
1002 let t1 = String::from(" ").repeat(tabs + 1);
1003
1004 format!(
1005 "ConicGradient {{\r\n{}extend_mode: {},\r\n{}center: {},\r\n{}angle: {},\r\n{}stops: \
1006 NormalizedRadialColorStopVec::from_const_slice(RADIAL_COLOR_STOP_{}_ITEMS),\r\n{}}}",
1007 t1,
1008 r.extend_mode.format_as_rust_code(tabs + 1),
1009 t1,
1010 format_style_background_position(&r.center, tabs + 1),
1011 t1,
1012 format_angle_value(&r.angle),
1013 t1,
1014 r.stops.get_hash(),
1015 t,
1016 )
1017}
1018
1019fn format_radial_gradient(r: &RadialGradient, tabs: usize) -> String {
1020 let t = String::from(" ").repeat(tabs);
1021 let t1 = String::from(" ").repeat(tabs + 1);
1022 format!(
1023 "RadialGradient {{\r\n{}shape: {},\r\n{}extend_mode: {},\r\n{}position: {},\r\n{}size: \
1024 RadialGradientSize::{:?},\r\n{}stops: \
1025 NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
1026 t1,
1027 r.shape.format_as_rust_code(tabs + 1),
1028 t1,
1029 r.extend_mode.format_as_rust_code(tabs + 1),
1030 t1,
1031 format_style_background_position(&r.position, tabs + 1),
1032 t1,
1033 r.size,
1034 t1,
1035 r.stops.get_hash(),
1036 t,
1037 )
1038}
1039
1040fn format_linear_color_stops(stops: &[NormalizedLinearColorStop], tabs: usize) -> String {
1041 let t = String::from(" ").repeat(tabs);
1042 stops
1043 .iter()
1044 .map(format_linear_color_stop)
1045 .collect::<Vec<_>>()
1046 .join(&format!(",\r\n{t}"))
1047}
1048
1049fn format_linear_color_stop(g: &NormalizedLinearColorStop) -> String {
1050 format!(
1051 "NormalizedLinearColorStop {{ offset: {}, color: {} }}",
1052 format_percentage_value(&g.offset),
1053 format_color_or_system(g.color),
1054 )
1055}
1056
1057fn format_radial_color_stops(stops: &[NormalizedRadialColorStop], tabs: usize) -> String {
1058 let t = String::from(" ").repeat(tabs);
1059 stops
1060 .iter()
1061 .map(format_radial_color_stop)
1062 .collect::<Vec<_>>()
1063 .join(&format!(",\r\n{t}"))
1064}
1065
1066fn format_radial_color_stop(g: &NormalizedRadialColorStop) -> String {
1067 format!(
1068 "RadialColorStop {{ angle: {}, color: {} }}",
1069 format_angle_value(&g.angle),
1070 format_color_or_system(g.color),
1071 )
1072}
1073
1074fn format_style_filter(st: &StyleFilter, tabs: usize) -> String {
1075 match st {
1076 StyleFilter::Blend(mb) => format!("StyleFilter::Blend({})", mb.format_as_rust_code(tabs)),
1077 StyleFilter::Flood(c) => format!("StyleFilter::Flood({})", format_color_value(c)),
1078 StyleFilter::Blur(m) => format!(
1079 "StyleFilter::Blur(StyleBlur {{ width: {}, height: {} }})",
1080 format_pixel_value(&m.width),
1081 format_pixel_value(&m.height)
1082 ),
1083 StyleFilter::Opacity(pct) => {
1084 format!("StyleFilter::Opacity({})", format_percentage_value(pct))
1085 }
1086 StyleFilter::ColorMatrix(cm) => format!(
1087 "StyleFilter::ColorMatrix(StyleColorMatrix {{ m0: {}, m1: {}, m2: {}, m3: {}, m4: {}, \
1088 m5: {}, m6: {}, m7: {}, m8: {}, m9: {}, m10: {}, m11: {}, m12: {}, m13: {}, m14: {}, \
1089 m15: {}, m16: {}, m17: {}, m18: {}, m19: {} }})",
1090 format_float_value(&cm.m0),
1091 format_float_value(&cm.m1),
1092 format_float_value(&cm.m2),
1093 format_float_value(&cm.m3),
1094 format_float_value(&cm.m4),
1095 format_float_value(&cm.m5),
1096 format_float_value(&cm.m6),
1097 format_float_value(&cm.m7),
1098 format_float_value(&cm.m8),
1099 format_float_value(&cm.m9),
1100 format_float_value(&cm.m10),
1101 format_float_value(&cm.m11),
1102 format_float_value(&cm.m12),
1103 format_float_value(&cm.m13),
1104 format_float_value(&cm.m14),
1105 format_float_value(&cm.m15),
1106 format_float_value(&cm.m16),
1107 format_float_value(&cm.m17),
1108 format_float_value(&cm.m18),
1109 format_float_value(&cm.m19)
1110 ),
1111 StyleFilter::DropShadow(m) => {
1112 format!("StyleFilter::DropShadow({})", m.format_as_rust_code(tabs))
1113 }
1114 StyleFilter::ComponentTransfer => "StyleFilter::ComponentTransfer".to_string(),
1115 StyleFilter::Offset(o) => format!(
1116 "StyleFilter::Offset(StyleFilterOffset {{ x: {}, y: {} }})",
1117 format_pixel_value(&o.x),
1118 format_pixel_value(&o.y)
1119 ),
1120 StyleFilter::Composite(StyleCompositeFilter::Over) => {
1121 "StyleFilter::Composite(StyleCompositeFilter::Over)".to_string()
1122 }
1123 StyleFilter::Composite(StyleCompositeFilter::In) => {
1124 "StyleFilter::Composite(StyleCompositeFilter::In)".to_string()
1125 }
1126 StyleFilter::Composite(StyleCompositeFilter::Atop) => {
1127 "StyleFilter::Composite(StyleCompositeFilter::Atop)".to_string()
1128 }
1129 StyleFilter::Composite(StyleCompositeFilter::Out) => {
1130 "StyleFilter::Composite(StyleCompositeFilter::Out)".to_string()
1131 }
1132 StyleFilter::Composite(StyleCompositeFilter::Xor) => {
1133 "StyleFilter::Composite(StyleCompositeFilter::Xor)".to_string()
1134 }
1135 StyleFilter::Composite(StyleCompositeFilter::Lighter) => {
1136 "StyleFilter::Composite(StyleCompositeFilter::Lighter)".to_string()
1137 }
1138 StyleFilter::Composite(StyleCompositeFilter::Arithmetic(fv)) => format!(
1139 "StyleFilter::Composite(StyleCompositeFilter::Arithmetic(ArithmeticCoefficients {{ \
1140 k1: {}, k2: {}, k3: {}, k4: {} }}))",
1141 format_float_value(&fv.k1),
1142 format_float_value(&fv.k2),
1143 format_float_value(&fv.k3),
1144 format_float_value(&fv.k4)
1145 ),
1146 StyleFilter::Brightness(v) => {
1147 format!("StyleFilter::Brightness({})", format_percentage_value(v))
1148 }
1149 StyleFilter::Contrast(v) => {
1150 format!("StyleFilter::Contrast({})", format_percentage_value(v))
1151 }
1152 StyleFilter::Grayscale(v) => {
1153 format!("StyleFilter::Grayscale({})", format_percentage_value(v))
1154 }
1155 StyleFilter::HueRotate(a) => format!("StyleFilter::HueRotate({})", format_angle_value(a)),
1156 StyleFilter::Invert(v) => format!("StyleFilter::Invert({})", format_percentage_value(v)),
1157 StyleFilter::Saturate(v) => {
1158 format!("StyleFilter::Saturate({})", format_percentage_value(v))
1159 }
1160 StyleFilter::Sepia(v) => format!("StyleFilter::Sepia({})", format_percentage_value(v)),
1161 }
1162}
1163
1164fn format_style_transforms(stops: &[StyleTransform], tabs: usize) -> String {
1165 let t = String::from(" ").repeat(tabs);
1166 stops
1167 .iter()
1168 .map(|s| format_style_transform(s, tabs))
1169 .collect::<Vec<_>>()
1170 .join(&format!(",\r\n{t}"))
1171}
1172
1173#[allow(clippy::too_many_lines)] fn format_style_transform(st: &StyleTransform, tabs: usize) -> String {
1175 let tabs_minus_one = String::from(" ").repeat(tabs);
1176 let tabs = String::from(" ").repeat(tabs + 1);
1177 match st {
1178 StyleTransform::Matrix(m) => format!(
1179 "StyleTransform::Matrix(StyleTransformMatrix2D {{ a: {}, b: {}, c: {}, d: {}, tx: {}, \
1180 ty: {} }})",
1181 format_float_value(&m.a),
1182 format_float_value(&m.b),
1183 format_float_value(&m.c),
1184 format_float_value(&m.d),
1185 format_float_value(&m.tx),
1186 format_float_value(&m.ty)
1187 ),
1188 StyleTransform::Matrix3D(m) => format!(
1189 "StyleTransform::Matrix3D(StyleTransformMatrix3D {{\r\n{tabs}m11: {},\r\n{tabs}m12: \
1190 {},\r\n{tabs}m13: {},\r\n{tabs}m14: {},\r\n{tabs}m21: {},\r\n{tabs}m22: \
1191 {},\r\n{tabs}m23: {},\r\n{tabs}m24: {},\r\n{tabs}m31: {},\r\n{tabs}m32: \
1192 {},\r\n{tabs}m33: {},\r\n{tabs}m34: {},\r\n{tabs}m41: {},\r\n{tabs}m42: \
1193 {},\r\n{tabs}m43: {},\r\n{tabs}m44: {}\r\n{tabs_minus_one}}})",
1194 format_float_value(&m.m11),
1195 format_float_value(&m.m12),
1196 format_float_value(&m.m13),
1197 format_float_value(&m.m14),
1198 format_float_value(&m.m21),
1199 format_float_value(&m.m22),
1200 format_float_value(&m.m23),
1201 format_float_value(&m.m24),
1202 format_float_value(&m.m31),
1203 format_float_value(&m.m32),
1204 format_float_value(&m.m33),
1205 format_float_value(&m.m34),
1206 format_float_value(&m.m41),
1207 format_float_value(&m.m42),
1208 format_float_value(&m.m43),
1209 format_float_value(&m.m44),
1210 tabs = tabs,
1211 tabs_minus_one = tabs_minus_one,
1212 ),
1213 StyleTransform::Translate(t) => format!(
1214 "StyleTransform::Translate(StyleTransformTranslate2D {{ x: {}, y: {} }})",
1215 format_pixel_value(&t.x),
1216 format_pixel_value(&t.y)
1217 ),
1218 StyleTransform::Translate3D(t) => format!(
1219 "StyleTransform::Translate3D(StyleTransformTranslate3D {{ x: {}, y: {}, z: {} }})",
1220 format_pixel_value(&t.x),
1221 format_pixel_value(&t.y),
1222 format_pixel_value(&t.z)
1223 ),
1224 StyleTransform::TranslateX(x) => {
1225 format!("StyleTransform::TranslateX({})", format_pixel_value(x))
1226 }
1227 StyleTransform::TranslateY(y) => {
1228 format!("StyleTransform::TranslateY({})", format_pixel_value(y))
1229 }
1230 StyleTransform::TranslateZ(z) => {
1231 format!("StyleTransform::TranslateZ({})", format_pixel_value(z))
1232 }
1233 StyleTransform::Rotate(r) => format!("StyleTransform::Rotate({})", format_angle_value(r)),
1234 StyleTransform::Rotate3D(r) => format!(
1235 "StyleTransform::Rotate3D(StyleTransformRotate3D {{ {}, {}, {}, {} }})",
1236 format_float_value(&r.x),
1237 format_float_value(&r.y),
1238 format_float_value(&r.z),
1239 format_angle_value(&r.angle)
1240 ),
1241 StyleTransform::RotateX(x) => {
1242 format!("StyleTransform::RotateX({})", format_angle_value(x))
1243 }
1244 StyleTransform::RotateY(y) => {
1245 format!("StyleTransform::RotateY({})", format_angle_value(y))
1246 }
1247 StyleTransform::RotateZ(z) => {
1248 format!("StyleTransform::RotateZ({})", format_angle_value(z))
1249 }
1250 StyleTransform::Scale(s) => format!(
1251 "StyleTransform::Scale(StyleTransformScale2D {{ x: {}, y: {} }})",
1252 format_float_value(&s.x),
1253 format_float_value(&s.y)
1254 ),
1255 StyleTransform::Scale3D(s) => format!(
1256 "StyleTransform::Scale3D(StyleTransformScale3D {{ x: {}, y: {}, z: {} }})",
1257 format_float_value(&s.x),
1258 format_float_value(&s.y),
1259 format_float_value(&s.z)
1260 ),
1261 StyleTransform::ScaleX(x) => {
1262 format!("StyleTransform::ScaleX({})", format_percentage_value(x))
1263 }
1264 StyleTransform::ScaleY(y) => {
1265 format!("StyleTransform::ScaleY({})", format_percentage_value(y))
1266 }
1267 StyleTransform::ScaleZ(z) => {
1268 format!("StyleTransform::ScaleZ({})", format_percentage_value(z))
1269 }
1270 StyleTransform::Skew(sk) => format!(
1271 "StyleTransform::Skew(StyleTransformSkew2D {{ x: {}, y: {} }})",
1272 format_angle_value(&sk.x),
1273 format_angle_value(&sk.y)
1274 ),
1275 StyleTransform::SkewX(x) => {
1276 format!("StyleTransform::SkewX({})", format_angle_value(x))
1277 }
1278 StyleTransform::SkewY(y) => {
1279 format!("StyleTransform::SkewY({})", format_angle_value(y))
1280 }
1281 StyleTransform::Perspective(dist) => {
1282 format!("StyleTransform::Perspective({})", format_pixel_value(dist))
1283 }
1284 }
1285}
1286
1287fn format_font_ids(font_ids: &[StyleFontFamily], tabs: usize) -> String {
1288 let t = String::from(" ").repeat(tabs);
1289 font_ids
1290 .iter()
1291 .map(|s| s.format_as_rust_code(tabs + 1))
1292 .collect::<Vec<_>>()
1293 .join(&format!(",\r\n{t}"))
1294}
1295
1296fn format_style_background_position(b: &StyleBackgroundPosition, tabs: usize) -> String {
1297 let t = String::from(" ").repeat(tabs);
1298 let t1 = String::from(" ").repeat(tabs + 1);
1299 format!(
1300 "StyleBackgroundPosition {{\r\n{}horizontal: {},\r\n{}vertical: {},\r\n{}}}",
1301 t1,
1302 format_background_position_horizontal(&b.horizontal),
1303 t1,
1304 format_background_position_vertical(&b.vertical),
1305 t
1306 )
1307}
1308
1309fn format_background_position_horizontal(b: &BackgroundPositionHorizontal) -> String {
1310 match b {
1311 BackgroundPositionHorizontal::Left => "BackgroundPositionHorizontal::Left".to_string(),
1312 BackgroundPositionHorizontal::Center => "BackgroundPositionHorizontal::Center".to_string(),
1313 BackgroundPositionHorizontal::Right => "BackgroundPositionHorizontal::Right".to_string(),
1314 BackgroundPositionHorizontal::Exact(p) => format!(
1315 "BackgroundPositionHorizontal::Exact({})",
1316 format_pixel_value(p)
1317 ),
1318 }
1319}
1320
1321fn format_background_position_vertical(b: &BackgroundPositionVertical) -> String {
1322 match b {
1323 BackgroundPositionVertical::Top => "BackgroundPositionVertical::Top".to_string(),
1324 BackgroundPositionVertical::Center => "BackgroundPositionVertical::Center".to_string(),
1325 BackgroundPositionVertical::Bottom => "BackgroundPositionVertical::Bottom".to_string(),
1326 BackgroundPositionVertical::Exact(p) => format!(
1327 "BackgroundPositionVertical::Exact({})",
1328 format_pixel_value(p)
1329 ),
1330 }
1331}
1332
1333