azul_core/
css.rs

1//! Module for printing the CSS to Rust code
2
3#[cfg(not(feature = "std"))]
4use alloc::string::ToString;
5use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec};
6use core::hash::Hash;
7
8use azul_css::*;
9
10// In order to generate the Rust code, all items that implement Drop
11// have to be declared before being used.
12//
13// This code does not compile:
14//
15// const A: StyleFontFamily = StyleFontFamily {
16//     inner: AzString::from_const_str("Arial")
17// };
18//
19// ... but this code does:
20//
21// static STRING_CONTENTS_1029834123098: &'static str = "Arial";
22// static STRING_1029834123098: AzString = AzString::from_const_str(STRING_CONTENTS_1029834123098);
23// const A: StyleFontFamily = StyleFontFamily { inner: STRING_1029834123098 };
24//
25// ... so during the XML-to-Rust compilation process, we have
26// to separate out all types that implement Drop:
27#[derive(Default)]
28pub struct VecContents {
29    // the u64 is the hash of the type (generated by string.get_hash())
30    strings: BTreeMap<u64, AzString>,
31    style_filters: BTreeMap<u64, StyleFilterVec>,
32    style_background_sizes: BTreeMap<u64, StyleBackgroundSizeVec>,
33    style_background_repeats: BTreeMap<u64, StyleBackgroundRepeatVec>,
34    style_background_contents: BTreeMap<u64, StyleBackgroundContentVec>,
35    style_background_positions: BTreeMap<u64, StyleBackgroundPositionVec>,
36    style_transforms: BTreeMap<u64, StyleTransformVec>,
37    font_families: BTreeMap<u64, StyleFontFamilyVec>,
38    linear_color_stops: BTreeMap<u64, NormalizedLinearColorStopVec>,
39    radial_color_stops: BTreeMap<u64, NormalizedRadialColorStopVec>,
40}
41
42impl VecContents {
43    pub fn format(&self, tabs: usize) -> String {
44        let mut result = String::new();
45        let t = "    ".repeat(tabs);
46        let t2 = "    ".repeat(tabs + 1);
47
48        for (key, item) in self.strings.iter() {
49            result.push_str(&format!(
50                "\r\n    const STRING_{}: AzString = AzString::from_const_str(\"{}\");",
51                key,
52                item.as_str()
53            ));
54        }
55
56        for (key, item) in self.style_filters.iter() {
57            let val = item
58                .iter()
59                .map(|filter| format_style_filter(filter, tabs + 1))
60                .collect::<Vec<_>>()
61                .join(&format!(",\r\n{}", t));
62
63            result.push_str(&format!(
64                "\r\n    const STYLE_FILTER_{}_ITEMS: &[StyleFilter] = &[\r\n{}{}\r\n{}];",
65                key, t2, val, t
66            ));
67        }
68
69        for (key, item) in self.style_background_sizes.iter() {
70            let val = item
71                .iter()
72                .map(|bgs| format_style_background_size(bgs))
73                .collect::<Vec<_>>()
74                .join(&format!(",\r\n{}", t));
75
76            result.push_str(&format!(
77                "\r\n    const STYLE_BACKGROUND_SIZE_{}_ITEMS: &[StyleBackgroundSize] = \
78                 &[\r\n{}{}\r\n{}];",
79                key, t2, val, t
80            ));
81        }
82
83        for (key, item) in self.style_background_repeats.iter() {
84            let val = item
85                .iter()
86                .map(|bgr| bgr.format_as_rust_code(tabs + 1))
87                .collect::<Vec<_>>()
88                .join(&format!(",\r\n{}", t));
89
90            result.push_str(&format!(
91                "\r\n    const STYLE_BACKGROUND_REPEAT_{}_ITEMS: &[StyleBackgroundRepeat] = \
92                 &[\r\n{}{}\r\n{}];",
93                key, t2, val, t
94            ));
95        }
96
97        for (key, item) in self.style_background_contents.iter() {
98            let val = item
99                .iter()
100                .map(|bgc| format_style_background_content(bgc, tabs + 1))
101                .collect::<Vec<_>>()
102                .join(&format!(",\r\n{}", t));
103
104            result.push_str(&format!(
105                "\r\n    const STYLE_BACKGROUND_CONTENT_{}_ITEMS: &[StyleBackgroundContent] = \
106                 &[\r\n{}{}\r\n{}];",
107                key, t2, val, t
108            ));
109        }
110
111        for (key, item) in self.style_background_positions.iter() {
112            let val = item
113                .iter()
114                .map(|bgp| format_style_background_position(bgp, tabs))
115                .collect::<Vec<_>>()
116                .join(&format!(",\r\n{}", t));
117
118            result.push_str(&format!(
119                "\r\n    const STYLE_BACKGROUND_POSITION_{}_ITEMS: &[StyleBackgroundPosition] = \
120                 &[\r\n{}{}\r\n{}];",
121                key, t2, val, t
122            ));
123        }
124
125        for (key, item) in self.style_transforms.iter() {
126            let val = format_style_transforms(item.as_ref(), tabs + 1);
127
128            result.push_str(&format!(
129                "\r\n    const STYLE_TRANSFORM_{}_ITEMS: &[StyleTransform] = &[\r\n{}{}\r\n{}];",
130                key, t2, val, t
131            ));
132        }
133
134        for (key, item) in self.font_families.iter() {
135            let val = format_font_ids(item.as_ref(), tabs + 1);
136
137            result.push_str(&format!(
138                "\r\n    const STYLE_FONT_FAMILY_{}_ITEMS: &[StyleFontFamily] = &[\r\n{}{}\r\n{}];",
139                key, t2, val, t
140            ));
141        }
142
143        for (key, item) in self.linear_color_stops.iter() {
144            let val = format_linear_color_stops(item.as_ref(), 1);
145
146            result.push_str(&format!(
147                "\r\n    const LINEAR_COLOR_STOP_{}_ITEMS: &[NormalizedLinearColorStop] = \
148                 &[\r\n{}{}\r\n{}];",
149                key, t2, val, t
150            ));
151        }
152
153        for (key, item) in self.radial_color_stops.iter() {
154            let val = format_radial_color_stops(item.as_ref(), tabs);
155
156            result.push_str(&format!(
157                "\r\n    const RADIAL_COLOR_STOP_{}_ITEMS: &[NormalizedRadialColorStop] = \
158                 &[\r\n{}{}\r\n{}];",
159                key, t2, val, t
160            ));
161        }
162
163        result
164    }
165
166    // given a CSS property, clones all the necessary strings (see class documentation)
167    pub fn insert_from_css_property(&mut self, prop: &CssProperty) {
168        match prop {
169            CssProperty::FontFamily(CssPropertyValue::Exact(v)) => {
170                for family in v.iter() {
171                    match family {
172                        StyleFontFamily::System(s) => {
173                            // if the font-family is surrounded by quotes, strip them ("Arial" ->
174                            // Arial)
175                            let s = s.as_str();
176                            let s = s.trim();
177                            let s = s.trim_start_matches('\"');
178                            let s = s.trim_end_matches('\"');
179                            let s = s.trim_start_matches('\'');
180                            let s = s.trim_end_matches('\'');
181
182                            self.strings.insert(s.get_hash(), s.to_string().into());
183                        }
184                        StyleFontFamily::File(s) => {
185                            let s = s.as_str();
186                            let s = s.trim();
187                            let s = s.trim_start_matches('\"');
188                            let s = s.trim_end_matches('\"');
189                            let s = s.trim_start_matches('\'');
190                            let s = s.trim_end_matches('\'');
191
192                            self.strings.insert(s.get_hash(), s.to_string().into());
193                        }
194                        _ => {}
195                    }
196                }
197                self.font_families.insert(v.get_hash(), v.clone());
198            }
199            CssProperty::Transform(CssPropertyValue::Exact(v)) => {
200                self.style_transforms.insert(v.get_hash(), v.clone());
201            }
202            CssProperty::BackgroundRepeat(CssPropertyValue::Exact(v)) => {
203                self.style_background_repeats
204                    .insert(v.get_hash(), v.clone());
205            }
206            CssProperty::BackgroundSize(CssPropertyValue::Exact(v)) => {
207                self.style_background_sizes.insert(v.get_hash(), v.clone());
208            }
209            CssProperty::BackgroundPosition(CssPropertyValue::Exact(v)) => {
210                self.style_background_positions
211                    .insert(v.get_hash(), v.clone());
212            }
213            CssProperty::BackgroundContent(CssPropertyValue::Exact(v)) => {
214                for background in v.iter() {
215                    match background {
216                        StyleBackgroundContent::Image(id) => {
217                            self.strings.insert(id.get_hash(), id.clone());
218                        }
219                        StyleBackgroundContent::LinearGradient(lg) => {
220                            self.linear_color_stops
221                                .insert(lg.stops.get_hash(), lg.stops.clone());
222                        }
223                        StyleBackgroundContent::RadialGradient(rg) => {
224                            self.linear_color_stops
225                                .insert(rg.stops.get_hash(), rg.stops.clone());
226                        }
227                        StyleBackgroundContent::ConicGradient(lg) => {
228                            self.radial_color_stops
229                                .insert(lg.stops.get_hash(), lg.stops.clone());
230                        }
231                        _ => {}
232                    }
233                }
234                self.style_background_contents
235                    .insert(v.get_hash(), v.clone());
236            }
237            CssProperty::Filter(CssPropertyValue::Exact(v)) => {
238                self.style_filters.insert(v.get_hash(), v.clone());
239            }
240            CssProperty::BackdropFilter(CssPropertyValue::Exact(v)) => {
241                self.style_filters.insert(v.get_hash(), v.clone());
242            }
243            _ => {}
244        }
245    }
246}
247
248pub fn css_to_rust_code(css: &Css) -> String {
249    let mut output = String::new();
250
251    output.push_str("const CSS: Css = Css {\r\n");
252    output.push_str("\tstylesheets: [\r\n");
253
254    for stylesheet in css.stylesheets.iter() {
255        output.push_str("\t\tStylesheet {\r\n");
256        output.push_str("\t\t\trules: [\r\n");
257
258        for block in stylesheet.rules.iter() {
259            output.push_str("\t\t\t\tCssRuleBlock: {\r\n");
260            output.push_str(&format!(
261                "\t\t\t\t\tpath: {},\r\n",
262                print_block_path(&block.path, 5)
263            ));
264
265            output.push_str("\t\t\t\t\tdeclarations: [\r\n");
266
267            for declaration in block.declarations.iter() {
268                output.push_str(&format!(
269                    "\t\t\t\t\t\t{},\r\n",
270                    print_declaraction(declaration, 6)
271                ));
272            }
273
274            output.push_str("\t\t\t\t\t]\r\n");
275
276            output.push_str("\t\t\t\t},\r\n");
277        }
278
279        output.push_str("\t\t\t]\r\n");
280        output.push_str("\t\t},\r\n");
281    }
282
283    output.push_str("\t]\r\n");
284    output.push_str("};");
285
286    let output = output.replace("\t", "    ");
287
288    output
289}
290
291fn print_block_path(path: &CssPath, tabs: usize) -> String {
292    let t = String::from("    ").repeat(tabs);
293    let t1 = String::from("    ").repeat(tabs + 1);
294
295    format!(
296        "CssPath {{\r\n{}selectors: {}\r\n{}}}",
297        t1,
298        format_selectors(path.selectors.as_ref(), tabs + 1),
299        t
300    )
301}
302
303fn format_selectors(selectors: &[CssPathSelector], tabs: usize) -> String {
304    let t = String::from("    ").repeat(tabs);
305    let t1 = String::from("    ").repeat(tabs + 1);
306
307    let selectors_formatted = selectors
308        .iter()
309        .map(|s| format!("{}{},", t1, format_single_selector(s, tabs + 1)))
310        .collect::<Vec<String>>()
311        .join("\r\n");
312
313    format!("vec![\r\n{}\r\n{}].into()", selectors_formatted, t)
314}
315
316fn format_single_selector(p: &CssPathSelector, _tabs: usize) -> String {
317    match p {
318        CssPathSelector::Global => format!("CssPathSelector::Global"),
319        CssPathSelector::Type(ntp) => format!("CssPathSelector::Type({})", format_node_type(ntp)),
320        CssPathSelector::Class(class) => {
321            format!("CssPathSelector::Class(String::from({:?}))", class)
322        }
323        CssPathSelector::Id(id) => format!("CssPathSelector::Id(String::from({:?}))", id),
324        CssPathSelector::PseudoSelector(cps) => format!(
325            "CssPathSelector::PseudoSelector({})",
326            format_pseudo_selector_type(cps)
327        ),
328        CssPathSelector::DirectChildren => format!("CssPathSelector::DirectChildren"),
329        CssPathSelector::Children => format!("CssPathSelector::Children"),
330    }
331}
332
333fn format_node_type(n: &NodeTypeTag) -> &'static str {
334    match n {
335        NodeTypeTag::Body => "NodeTypeTag::Body",
336        NodeTypeTag::Div => "NodeTypeTag::Div",
337        NodeTypeTag::Br => "NodeTypeTag::Br",
338        NodeTypeTag::P => "NodeTypeTag::P",
339        NodeTypeTag::Img => "NodeTypeTag::Img",
340        NodeTypeTag::IFrame => "NodeTypeTag::IFrame",
341    }
342}
343
344fn format_pseudo_selector_type(p: &CssPathPseudoSelector) -> String {
345    match p {
346        CssPathPseudoSelector::First => format!("CssPathPseudoSelector::First"),
347        CssPathPseudoSelector::Last => format!("CssPathPseudoSelector::Last"),
348        CssPathPseudoSelector::NthChild(n) => format!(
349            "CssPathPseudoSelector::NthChild({})",
350            format_nth_child_selector(n)
351        ),
352        CssPathPseudoSelector::Hover => format!("CssPathPseudoSelector::Hover"),
353        CssPathPseudoSelector::Active => format!("CssPathPseudoSelector::Active"),
354        CssPathPseudoSelector::Focus => format!("CssPathPseudoSelector::Focus"),
355    }
356}
357
358fn format_nth_child_selector(n: &CssNthChildSelector) -> String {
359    match n {
360        CssNthChildSelector::Number(num) => format!("CssNthChildSelector::Number({})", num),
361        CssNthChildSelector::Even => format!("CssNthChildSelector::Even"),
362        CssNthChildSelector::Odd => format!("CssNthChildSelector::Odd"),
363        CssNthChildSelector::Pattern(CssNthChildPattern { repeat, offset }) => format!(
364            "CssNthChildSelector::Pattern(CssNthChildPattern {{ repeat: {}, offset: {} }})",
365            repeat, offset
366        ),
367    }
368}
369
370fn print_declaraction(decl: &CssDeclaration, tabs: usize) -> String {
371    match decl {
372        CssDeclaration::Static(s) => format!(
373            "CssDeclaration::Static({})",
374            format_static_css_prop(s, tabs)
375        ),
376        CssDeclaration::Dynamic(d) => format!(
377            "CssDeclaration::Dynamic({})",
378            format_dynamic_css_prop(d, tabs)
379        ),
380    }
381}
382
383pub(crate) trait GetHash {
384    fn get_hash(&self) -> u64;
385}
386
387impl<T: Hash> GetHash for T {
388    fn get_hash(&self) -> u64 {
389        use highway::{HighwayHash, HighwayHasher, Key};
390        let mut hasher = HighwayHasher::new(Key([0; 4]));
391        self.hash(&mut hasher);
392        hasher.finalize64()
393    }
394}
395
396trait FormatAsRustCode {
397    fn format_as_rust_code(&self, _tabs: usize) -> String;
398}
399
400pub(crate) fn format_static_css_prop(prop: &CssProperty, tabs: usize) -> String {
401    match prop {
402        CssProperty::TextColor(p) => format!(
403            "CssProperty::TextColor({})",
404            print_css_property_value(p, tabs, "StyleTextColor")
405        ),
406        CssProperty::FontSize(p) => format!(
407            "CssProperty::FontSize({})",
408            print_css_property_value(p, tabs, "StyleFontSize")
409        ),
410        CssProperty::FontFamily(p) => format!(
411            "CssProperty::FontFamily({})",
412            print_css_property_value(p, tabs, "StyleFontFamilyVec")
413        ),
414        CssProperty::TextAlign(p) => format!(
415            "CssProperty::TextAlign({})",
416            print_css_property_value(p, tabs, "StyleTextAlign")
417        ),
418        CssProperty::LetterSpacing(p) => format!(
419            "CssProperty::LetterSpacing({})",
420            print_css_property_value(p, tabs, "StyleLetterSpacing")
421        ),
422        CssProperty::LineHeight(p) => format!(
423            "CssProperty::LineHeight({})",
424            print_css_property_value(p, tabs, "StyleLineHeight")
425        ),
426        CssProperty::WordSpacing(p) => format!(
427            "CssProperty::WordSpacing({})",
428            print_css_property_value(p, tabs, "StyleWordSpacing")
429        ),
430        CssProperty::TabWidth(p) => format!(
431            "CssProperty::TabWidth({})",
432            print_css_property_value(p, tabs, "StyleTabWidth")
433        ),
434        CssProperty::Cursor(p) => format!(
435            "CssProperty::Cursor({})",
436            print_css_property_value(p, tabs, "StyleCursor")
437        ),
438        CssProperty::Display(p) => format!(
439            "CssProperty::Display({})",
440            print_css_property_value(p, tabs, "LayoutDisplay")
441        ),
442        CssProperty::Float(p) => format!(
443            "CssProperty::Float({})",
444            print_css_property_value(p, tabs, "LayoutFloat")
445        ),
446        CssProperty::BoxSizing(p) => format!(
447            "CssProperty::BoxSizing({})",
448            print_css_property_value(p, tabs, "LayoutBoxSizing")
449        ),
450        CssProperty::Width(p) => format!(
451            "CssProperty::Width({})",
452            print_css_property_value(p, tabs, "LayoutWidth")
453        ),
454        CssProperty::Height(p) => format!(
455            "CssProperty::Height({})",
456            print_css_property_value(p, tabs, "LayoutHeight")
457        ),
458        CssProperty::MinWidth(p) => format!(
459            "CssProperty::MinWidth({})",
460            print_css_property_value(p, tabs, "LayoutMinWidth")
461        ),
462        CssProperty::MinHeight(p) => format!(
463            "CssProperty::MinHeight({})",
464            print_css_property_value(p, tabs, "LayoutMinHeight")
465        ),
466        CssProperty::MaxWidth(p) => format!(
467            "CssProperty::MaxWidth({})",
468            print_css_property_value(p, tabs, "LayoutMaxWidth")
469        ),
470        CssProperty::MaxHeight(p) => format!(
471            "CssProperty::MaxHeight({})",
472            print_css_property_value(p, tabs, "LayoutMaxHeight")
473        ),
474        CssProperty::Position(p) => format!(
475            "CssProperty::Position({})",
476            print_css_property_value(p, tabs, "LayoutPosition")
477        ),
478        CssProperty::Top(p) => format!(
479            "CssProperty::Top({})",
480            print_css_property_value(p, tabs, "LayoutTop")
481        ),
482        CssProperty::Right(p) => format!(
483            "CssProperty::Right({})",
484            print_css_property_value(p, tabs, "LayoutRight")
485        ),
486        CssProperty::Left(p) => format!(
487            "CssProperty::Left({})",
488            print_css_property_value(p, tabs, "LayoutLeft")
489        ),
490        CssProperty::Bottom(p) => format!(
491            "CssProperty::Bottom({})",
492            print_css_property_value(p, tabs, "LayoutBottom")
493        ),
494        CssProperty::FlexWrap(p) => format!(
495            "CssProperty::FlexWrap({})",
496            print_css_property_value(p, tabs, "LayoutFlexWrap")
497        ),
498        CssProperty::FlexDirection(p) => format!(
499            "CssProperty::FlexDirection({})",
500            print_css_property_value(p, tabs, "LayoutFlexDirection")
501        ),
502        CssProperty::FlexGrow(p) => format!(
503            "CssProperty::FlexGrow({})",
504            print_css_property_value(p, tabs, "LayoutFlexGrow")
505        ),
506        CssProperty::FlexShrink(p) => format!(
507            "CssProperty::FlexShrink({})",
508            print_css_property_value(p, tabs, "LayoutFlexShrink")
509        ),
510        CssProperty::JustifyContent(p) => format!(
511            "CssProperty::JustifyContent({})",
512            print_css_property_value(p, tabs, "LayoutJustifyContent")
513        ),
514        CssProperty::AlignItems(p) => format!(
515            "CssProperty::AlignItems({})",
516            print_css_property_value(p, tabs, "LayoutAlignItems")
517        ),
518        CssProperty::AlignContent(p) => format!(
519            "CssProperty::AlignContent({})",
520            print_css_property_value(p, tabs, "LayoutAlignContent")
521        ),
522        CssProperty::BackgroundContent(p) => format!(
523            "CssProperty::BackgroundContent({})",
524            print_css_property_value(p, tabs, "StyleBackgroundContentVec")
525        ),
526        CssProperty::BackgroundPosition(p) => format!(
527            "CssProperty::BackgroundPosition({})",
528            print_css_property_value(p, tabs, "StyleBackgroundPositionVec")
529        ),
530        CssProperty::BackgroundSize(p) => format!(
531            "CssProperty::BackgroundSize({})",
532            print_css_property_value(p, tabs, "StyleBackgroundSizeVec")
533        ),
534        CssProperty::BackgroundRepeat(p) => format!(
535            "CssProperty::BackgroundRepeat({})",
536            print_css_property_value(p, tabs, "StyleBackgroundRepeatVec")
537        ),
538        CssProperty::OverflowX(p) => format!(
539            "CssProperty::OverflowX({})",
540            print_css_property_value(p, tabs, "LayoutOverflow")
541        ),
542        CssProperty::OverflowY(p) => format!(
543            "CssProperty::OverflowY({})",
544            print_css_property_value(p, tabs, "LayoutOverflow")
545        ),
546        CssProperty::PaddingTop(p) => format!(
547            "CssProperty::PaddingTop({})",
548            print_css_property_value(p, tabs, "LayoutPaddingTop")
549        ),
550        CssProperty::PaddingLeft(p) => format!(
551            "CssProperty::PaddingLeft({})",
552            print_css_property_value(p, tabs, "LayoutPaddingLeft")
553        ),
554        CssProperty::PaddingRight(p) => format!(
555            "CssProperty::PaddingRight({})",
556            print_css_property_value(p, tabs, "LayoutPaddingRight")
557        ),
558        CssProperty::PaddingBottom(p) => format!(
559            "CssProperty::PaddingBottom({})",
560            print_css_property_value(p, tabs, "LayoutPaddingBottom")
561        ),
562        CssProperty::MarginTop(p) => format!(
563            "CssProperty::MarginTop({})",
564            print_css_property_value(p, tabs, "LayoutMarginTop")
565        ),
566        CssProperty::MarginLeft(p) => format!(
567            "CssProperty::MarginLeft({})",
568            print_css_property_value(p, tabs, "LayoutMarginLeft")
569        ),
570        CssProperty::MarginRight(p) => format!(
571            "CssProperty::MarginRight({})",
572            print_css_property_value(p, tabs, "LayoutMarginRight")
573        ),
574        CssProperty::MarginBottom(p) => format!(
575            "CssProperty::MarginBottom({})",
576            print_css_property_value(p, tabs, "LayoutMarginBottom")
577        ),
578        CssProperty::BorderTopLeftRadius(p) => format!(
579            "CssProperty::BorderTopLeftRadius({})",
580            print_css_property_value(p, tabs, "StyleBorderTopLeftRadius")
581        ),
582        CssProperty::BorderTopRightRadius(p) => format!(
583            "CssProperty::BorderTopRightRadius({})",
584            print_css_property_value(p, tabs, "StyleBorderTopRightRadius")
585        ),
586        CssProperty::BorderBottomLeftRadius(p) => format!(
587            "CssProperty::BorderBottomLeftRadius({})",
588            print_css_property_value(p, tabs, "StyleBorderBottomLeftRadius")
589        ),
590        CssProperty::BorderBottomRightRadius(p) => format!(
591            "CssProperty::BorderBottomRightRadius({})",
592            print_css_property_value(p, tabs, "StyleBorderBottomRightRadius")
593        ),
594        CssProperty::BorderTopColor(p) => format!(
595            "CssProperty::BorderTopColor({})",
596            print_css_property_value(p, tabs, "StyleBorderTopColor")
597        ),
598        CssProperty::BorderRightColor(p) => format!(
599            "CssProperty::BorderRightColor({})",
600            print_css_property_value(p, tabs, "StyleBorderRightColor")
601        ),
602        CssProperty::BorderLeftColor(p) => format!(
603            "CssProperty::BorderLeftColor({})",
604            print_css_property_value(p, tabs, "StyleBorderLeftColor")
605        ),
606        CssProperty::BorderBottomColor(p) => format!(
607            "CssProperty::BorderBottomColor({})",
608            print_css_property_value(p, tabs, "StyleBorderBottomColor")
609        ),
610        CssProperty::BorderTopStyle(p) => format!(
611            "CssProperty::BorderTopStyle({})",
612            print_css_property_value(p, tabs, "StyleBorderTopStyle")
613        ),
614        CssProperty::BorderRightStyle(p) => format!(
615            "CssProperty::BorderRightStyle({})",
616            print_css_property_value(p, tabs, "StyleBorderRightStyle")
617        ),
618        CssProperty::BorderLeftStyle(p) => format!(
619            "CssProperty::BorderLeftStyle({})",
620            print_css_property_value(p, tabs, "StyleBorderLeftStyle")
621        ),
622        CssProperty::BorderBottomStyle(p) => format!(
623            "CssProperty::BorderBottomStyle({})",
624            print_css_property_value(p, tabs, "StyleBorderBottomStyle")
625        ),
626        CssProperty::BorderTopWidth(p) => format!(
627            "CssProperty::BorderTopWidth({})",
628            print_css_property_value(p, tabs, "LayoutBorderTopWidth")
629        ),
630        CssProperty::BorderRightWidth(p) => format!(
631            "CssProperty::BorderRightWidth({})",
632            print_css_property_value(p, tabs, "LayoutBorderRightWidth")
633        ),
634        CssProperty::BorderLeftWidth(p) => format!(
635            "CssProperty::BorderLeftWidth({})",
636            print_css_property_value(p, tabs, "LayoutBorderLeftWidth")
637        ),
638        CssProperty::BorderBottomWidth(p) => format!(
639            "CssProperty::BorderBottomWidth({})",
640            print_css_property_value(p, tabs, "LayoutBorderBottomWidth")
641        ),
642        CssProperty::BoxShadowLeft(p) => format!(
643            "CssProperty::BoxShadowLeft({})",
644            print_css_property_value(p, tabs, "StyleBoxShadow")
645        ),
646        CssProperty::BoxShadowRight(p) => format!(
647            "CssProperty::BoxShadowRight({})",
648            print_css_property_value(p, tabs, "StyleBoxShadow")
649        ),
650        CssProperty::BoxShadowTop(p) => format!(
651            "CssProperty::BoxShadowTop({})",
652            print_css_property_value(p, tabs, "StyleBoxShadow")
653        ),
654        CssProperty::BoxShadowBottom(p) => format!(
655            "CssProperty::BoxShadowBottom({})",
656            print_css_property_value(p, tabs, "StyleBoxShadow")
657        ),
658        CssProperty::ScrollbarStyle(p) => format!(
659            "CssProperty::ScrollbarStyle({})",
660            print_css_property_value(p, tabs, "ScrollbarStyle")
661        ),
662        CssProperty::Opacity(p) => format!(
663            "CssProperty::Opacity({})",
664            print_css_property_value(p, tabs, "StyleOpacity")
665        ),
666        CssProperty::Transform(p) => format!(
667            "CssProperty::Transform({})",
668            print_css_property_value(p, tabs, "StyleTransformVec")
669        ),
670        CssProperty::TransformOrigin(p) => format!(
671            "CssProperty::TransformOrigin({})",
672            print_css_property_value(p, tabs, "StyleTransformOrigin")
673        ),
674        CssProperty::PerspectiveOrigin(p) => format!(
675            "CssProperty::PerspectiveOrigin({})",
676            print_css_property_value(p, tabs, "StylePerspectiveOrigin")
677        ),
678        CssProperty::BackfaceVisibility(p) => format!(
679            "CssProperty::BackfaceVisibility({})",
680            print_css_property_value(p, tabs, "StyleBackfaceVisibility")
681        ),
682        CssProperty::MixBlendMode(p) => format!(
683            "CssProperty::MixBlendMode({})",
684            print_css_property_value(p, tabs, "StyleMixBlendMode")
685        ),
686        CssProperty::Filter(p) => format!(
687            "CssProperty::Filter({})",
688            print_css_property_value(p, tabs, "StyleFilterVec")
689        ),
690        CssProperty::BackdropFilter(p) => format!(
691            "CssProperty::Filter({})",
692            print_css_property_value(p, tabs, "StyleFilterVec")
693        ),
694        CssProperty::TextShadow(p) => format!(
695            "CssProperty::TextShadow({})",
696            print_css_property_value(p, tabs, "StyleBoxShadow")
697        ),
698    }
699}
700
701fn print_css_property_value<T: FormatAsRustCode>(
702    prop_val: &CssPropertyValue<T>,
703    tabs: usize,
704    property_value_type: &'static str,
705) -> String {
706    match prop_val {
707        CssPropertyValue::Auto => format!("{}Value::Auto", property_value_type),
708        CssPropertyValue::None => format!("{}Value::None", property_value_type),
709        CssPropertyValue::Initial => format!("{}Value::Initial", property_value_type),
710        CssPropertyValue::Inherit => format!("{}Value::Inherit", property_value_type),
711        CssPropertyValue::Exact(t) => format!(
712            "{}Value::Exact({})",
713            property_value_type,
714            t.format_as_rust_code(tabs)
715        ),
716    }
717}
718
719fn format_dynamic_css_prop(decl: &DynamicCssProperty, tabs: usize) -> String {
720    let t = String::from("    ").repeat(tabs);
721    format!(
722        "DynamicCssProperty {{\r\n{}    dynamic_id: {:?},\r\n{}    default_value: {},\r\n{}}}",
723        t,
724        decl.dynamic_id,
725        t,
726        format_static_css_prop(&decl.default_value, tabs + 1),
727        t
728    )
729}
730
731fn format_pixel_value(p: &PixelValue) -> String {
732    match p.metric {
733        SizeMetric::Px => format!(
734            "PixelValue::const_px({})",
735            libm::roundf(p.number.get()) as isize
736        ),
737        SizeMetric::Pt => format!(
738            "PixelValue::const_pt({})",
739            libm::roundf(p.number.get()) as isize
740        ),
741        SizeMetric::Em => format!(
742            "PixelValue::const_em({})",
743            libm::roundf(p.number.get()) as isize
744        ),
745        SizeMetric::Percent => format!(
746            "PixelValue::const_percent({})",
747            libm::roundf(p.number.get()) as isize
748        ),
749    }
750}
751
752fn format_pixel_value_no_percent(p: &PixelValueNoPercent) -> String {
753    format!(
754        "PixelValueNoPercent {{ inner: {} }}",
755        format_pixel_value(&p.inner)
756    )
757}
758
759fn format_float_value(f: &FloatValue) -> String {
760    format!("FloatValue::const_new({})", libm::roundf(f.get()) as isize)
761}
762
763fn format_percentage_value(f: &PercentageValue) -> String {
764    format!(
765        "PercentageValue::const_new({})",
766        libm::roundf(f.get()) as isize
767    )
768}
769
770fn format_angle_value(f: &AngleValue) -> String {
771    format!(
772        "AngleValue::const_deg({})",
773        libm::roundf(f.to_degrees()) as isize
774    )
775}
776
777fn format_color_value(c: &ColorU) -> String {
778    format!(
779        "ColorU {{ r: {}, g: {}, b: {}, a: {} }}",
780        c.r, c.g, c.b, c.a
781    )
782}
783
784macro_rules! impl_float_value_fmt {
785    ($struct_name:ident) => {
786        impl FormatAsRustCode for $struct_name {
787            fn format_as_rust_code(&self, _tabs: usize) -> String {
788                format!(
789                    "{} {{ inner: {} }}",
790                    stringify!($struct_name),
791                    format_float_value(&self.inner)
792                )
793            }
794        }
795    };
796}
797
798impl_float_value_fmt!(LayoutFlexGrow);
799impl_float_value_fmt!(LayoutFlexShrink);
800
801macro_rules! impl_percentage_value_fmt {
802    ($struct_name:ident) => {
803        impl FormatAsRustCode for $struct_name {
804            fn format_as_rust_code(&self, _tabs: usize) -> String {
805                format!(
806                    "{} {{ inner: {} }}",
807                    stringify!($struct_name),
808                    format_percentage_value(&self.inner)
809                )
810            }
811        }
812    };
813}
814
815impl_percentage_value_fmt!(StyleTabWidth);
816impl_percentage_value_fmt!(StyleLineHeight);
817impl_percentage_value_fmt!(StyleOpacity);
818
819macro_rules! impl_pixel_value_fmt {
820    ($struct_name:ident) => {
821        impl FormatAsRustCode for $struct_name {
822            fn format_as_rust_code(&self, _tabs: usize) -> String {
823                format!(
824                    "{} {{ inner: {} }}",
825                    stringify!($struct_name),
826                    format_pixel_value(&self.inner)
827                )
828            }
829        }
830    };
831}
832
833impl_pixel_value_fmt!(StyleBorderTopLeftRadius);
834impl_pixel_value_fmt!(StyleBorderBottomLeftRadius);
835impl_pixel_value_fmt!(StyleBorderTopRightRadius);
836impl_pixel_value_fmt!(StyleBorderBottomRightRadius);
837
838impl_pixel_value_fmt!(LayoutBorderTopWidth);
839impl_pixel_value_fmt!(LayoutBorderLeftWidth);
840impl_pixel_value_fmt!(LayoutBorderRightWidth);
841impl_pixel_value_fmt!(LayoutBorderBottomWidth);
842impl_pixel_value_fmt!(StyleLetterSpacing);
843impl_pixel_value_fmt!(StyleWordSpacing);
844impl_pixel_value_fmt!(StyleFontSize);
845
846impl_pixel_value_fmt!(LayoutMarginTop);
847impl_pixel_value_fmt!(LayoutMarginBottom);
848impl_pixel_value_fmt!(LayoutMarginRight);
849impl_pixel_value_fmt!(LayoutMarginLeft);
850
851impl_pixel_value_fmt!(LayoutPaddingTop);
852impl_pixel_value_fmt!(LayoutPaddingBottom);
853impl_pixel_value_fmt!(LayoutPaddingRight);
854impl_pixel_value_fmt!(LayoutPaddingLeft);
855
856impl_pixel_value_fmt!(LayoutWidth);
857impl_pixel_value_fmt!(LayoutHeight);
858impl_pixel_value_fmt!(LayoutMinHeight);
859impl_pixel_value_fmt!(LayoutMinWidth);
860impl_pixel_value_fmt!(LayoutMaxWidth);
861impl_pixel_value_fmt!(LayoutMaxHeight);
862impl_pixel_value_fmt!(LayoutTop);
863impl_pixel_value_fmt!(LayoutBottom);
864impl_pixel_value_fmt!(LayoutRight);
865impl_pixel_value_fmt!(LayoutLeft);
866
867macro_rules! impl_color_value_fmt {
868    ($struct_name:ty) => {
869        impl FormatAsRustCode for $struct_name {
870            fn format_as_rust_code(&self, _tabs: usize) -> String {
871                format!(
872                    "{} {{ inner: {} }}",
873                    stringify!($struct_name),
874                    format_color_value(&self.inner)
875                )
876            }
877        }
878    };
879}
880
881impl_color_value_fmt!(StyleTextColor);
882impl_color_value_fmt!(StyleBorderTopColor);
883impl_color_value_fmt!(StyleBorderLeftColor);
884impl_color_value_fmt!(StyleBorderRightColor);
885impl_color_value_fmt!(StyleBorderBottomColor);
886
887macro_rules! impl_enum_fmt {($enum_name:ident, $($enum_type:ident),+) => (
888    impl FormatAsRustCode for $enum_name {
889        fn format_as_rust_code(&self, _tabs: usize) -> String {
890            match self {
891                $(
892                    $enum_name::$enum_type => String::from(concat!(stringify!($enum_name), "::", stringify!($enum_type))),
893                )+
894            }
895        }
896    }
897)}
898
899impl_enum_fmt!(
900    StyleMixBlendMode,
901    Normal,
902    Multiply,
903    Screen,
904    Overlay,
905    Darken,
906    Lighten,
907    ColorDodge,
908    ColorBurn,
909    HardLight,
910    SoftLight,
911    Difference,
912    Exclusion,
913    Hue,
914    Saturation,
915    Color,
916    Luminosity
917);
918
919impl_enum_fmt!(
920    StyleCursor,
921    Alias,
922    AllScroll,
923    Cell,
924    ColResize,
925    ContextMenu,
926    Copy,
927    Crosshair,
928    Default,
929    EResize,
930    EwResize,
931    Grab,
932    Grabbing,
933    Help,
934    Move,
935    NResize,
936    NsResize,
937    NeswResize,
938    NwseResize,
939    Pointer,
940    Progress,
941    RowResize,
942    SResize,
943    SeResize,
944    Text,
945    Unset,
946    VerticalText,
947    WResize,
948    Wait,
949    ZoomIn,
950    ZoomOut
951);
952
953impl_enum_fmt!(
954    BorderStyle,
955    None,
956    Solid,
957    Double,
958    Dotted,
959    Dashed,
960    Hidden,
961    Groove,
962    Ridge,
963    Inset,
964    Outset
965);
966
967impl FormatAsRustCode for StyleFilterVec {
968    fn format_as_rust_code(&self, tabs: usize) -> String {
969        format!(
970            "StyleFilterVec::from_const_slice(STYLE_FILTER_{}_ITEMS)",
971            self.get_hash()
972        )
973    }
974}
975
976impl FormatAsRustCode for StyleBackgroundSizeVec {
977    fn format_as_rust_code(&self, tabs: usize) -> String {
978        format!(
979            "StyleBackgroundSizeVec::from_const_slice(STYLE_BACKGROUND_SIZE_{}_ITEMS)",
980            self.get_hash()
981        )
982    }
983}
984
985fn format_style_background_size(c: &StyleBackgroundSize) -> String {
986    match c {
987        StyleBackgroundSize::Contain => String::from("StyleBackgroundSize::Contain"),
988        StyleBackgroundSize::Cover => String::from("StyleBackgroundSize::Cover"),
989        StyleBackgroundSize::ExactSize([w, h]) => format!(
990            "StyleBackgroundSize::ExactSize([{}, {}])",
991            format_pixel_value(w),
992            format_pixel_value(h)
993        ),
994    }
995}
996
997impl FormatAsRustCode for ScrollbarStyle {
998    fn format_as_rust_code(&self, tabs: usize) -> String {
999        let t = String::from("    ").repeat(tabs);
1000        let t1 = String::from("    ").repeat(tabs + 1);
1001        format!(
1002            "ScrollbarStyle {{\r\n{}horizontal: {},\r\n{}vertical: {},\r\n{}}}",
1003            t1,
1004            format_scrollbar_info(&self.horizontal, tabs + 1),
1005            t1,
1006            format_scrollbar_info(&self.vertical, tabs + 1),
1007            t,
1008        )
1009    }
1010}
1011
1012fn format_scrollbar_info(s: &ScrollbarInfo, tabs: usize) -> String {
1013    let t = String::from("    ").repeat(tabs);
1014    let t1 = String::from("    ").repeat(tabs + 1);
1015    format!(
1016        "ScrollbarInfo {{\r\n{}width: {},\r\n{}padding_left: {},\r\n{}padding_right: \
1017         {},\r\n{}track: {},\r\n{}thumb: {},\r\n{}button: {},\r\n{}button: {},\r\n{}resizer: \
1018         {},\r\n{}}}",
1019        t1,
1020        s.width.format_as_rust_code(tabs + 1),
1021        t1,
1022        s.padding_left.format_as_rust_code(tabs + 1),
1023        t1,
1024        s.padding_right.format_as_rust_code(tabs + 1),
1025        t1,
1026        format_style_background_content(&s.track, tabs + 1),
1027        t1,
1028        format_style_background_content(&s.thumb, tabs + 1),
1029        t1,
1030        format_style_background_content(&s.button, tabs + 1),
1031        t1,
1032        format_style_background_content(&s.corner, tabs + 1),
1033        t1,
1034        format_style_background_content(&s.resizer, tabs + 1),
1035        t
1036    )
1037}
1038
1039impl_enum_fmt!(StyleBackgroundRepeat, NoRepeat, Repeat, RepeatX, RepeatY);
1040
1041impl FormatAsRustCode for StyleBackgroundRepeatVec {
1042    fn format_as_rust_code(&self, tabs: usize) -> String {
1043        format!(
1044            "StyleBackgroundRepeatVec::from_const_slice(STYLE_BACKGROUND_REPEAT_{}_ITEMS)",
1045            self.get_hash()
1046        )
1047    }
1048}
1049
1050impl_enum_fmt!(LayoutDisplay, None, Flex, Block, InlineBlock);
1051
1052impl_enum_fmt!(LayoutFloat, Left, Right);
1053
1054impl_enum_fmt!(LayoutBoxSizing, ContentBox, BorderBox);
1055
1056impl_enum_fmt!(LayoutFlexDirection, Row, RowReverse, Column, ColumnReverse);
1057
1058impl_enum_fmt!(LayoutFlexWrap, Wrap, NoWrap);
1059
1060impl_enum_fmt!(
1061    LayoutJustifyContent,
1062    Start,
1063    End,
1064    Center,
1065    SpaceBetween,
1066    SpaceAround,
1067    SpaceEvenly
1068);
1069
1070impl_enum_fmt!(LayoutAlignItems, FlexStart, FlexEnd, Stretch, Center);
1071
1072impl_enum_fmt!(
1073    LayoutAlignContent,
1074    Start,
1075    End,
1076    Stretch,
1077    Center,
1078    SpaceBetween,
1079    SpaceAround
1080);
1081
1082impl_enum_fmt!(Shape, Circle, Ellipse);
1083
1084impl_enum_fmt!(LayoutPosition, Static, Fixed, Absolute, Relative);
1085
1086impl_enum_fmt!(LayoutOverflow, Auto, Scroll, Visible, Hidden);
1087
1088impl_enum_fmt!(StyleTextAlign, Center, Left, Right);
1089
1090impl_enum_fmt!(
1091    DirectionCorner,
1092    Right,
1093    Left,
1094    Top,
1095    Bottom,
1096    TopRight,
1097    TopLeft,
1098    BottomRight,
1099    BottomLeft
1100);
1101
1102impl_enum_fmt!(ExtendMode, Clamp, Repeat);
1103
1104impl_enum_fmt!(StyleBackfaceVisibility, Visible, Hidden);
1105
1106impl FormatAsRustCode for StyleBackgroundContentVec {
1107    fn format_as_rust_code(&self, tabs: usize) -> String {
1108        format!(
1109            "StyleBackgroundContentVec::from_const_slice(STYLE_BACKGROUND_CONTENT_{}_ITEMS)",
1110            self.get_hash()
1111        )
1112    }
1113}
1114
1115fn format_style_background_content(content: &StyleBackgroundContent, tabs: usize) -> String {
1116    match content {
1117        StyleBackgroundContent::LinearGradient(l) => format!(
1118            "StyleBackgroundContent::LinearGradient({})",
1119            format_linear_gradient(l, tabs)
1120        ),
1121        StyleBackgroundContent::RadialGradient(r) => format!(
1122            "StyleBackgroundContent::RadialGradient({})",
1123            format_radial_gradient(r, tabs)
1124        ),
1125        StyleBackgroundContent::ConicGradient(r) => format!(
1126            "StyleBackgroundContent::ConicGradient({})",
1127            format_conic_gradient(r, tabs)
1128        ),
1129        StyleBackgroundContent::Image(id) => format!("StyleBackgroundContent::Image({:?})", id),
1130        StyleBackgroundContent::Color(c) => {
1131            format!("StyleBackgroundContent::Color({})", format_color_value(c))
1132        }
1133    }
1134}
1135
1136fn format_direction(d: &Direction, tabs: usize) -> String {
1137    match d {
1138        Direction::Angle(fv) => format!("Direction::Angle({})", format_angle_value(fv)),
1139        Direction::FromTo(DirectionCorners { from, to }) => format!(
1140            "Direction::FromTo(DirectionCorners {{ from: {}, to: {} }})",
1141            from.format_as_rust_code(tabs + 1),
1142            to.format_as_rust_code(tabs + 1)
1143        ),
1144    }
1145}
1146
1147fn format_linear_gradient(l: &LinearGradient, tabs: usize) -> String {
1148    let t = String::from("    ").repeat(tabs);
1149    let t1 = String::from("    ").repeat(tabs + 1);
1150    format!(
1151        "LinearGradient {{\r\n{}direction: {},\r\n{}extend_mode: {},\r\n{}stops: \
1152         NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
1153        t1,
1154        format_direction(&l.direction, tabs + 1),
1155        t1,
1156        l.extend_mode.format_as_rust_code(tabs + 1),
1157        t1,
1158        l.stops.get_hash(),
1159        t,
1160    )
1161}
1162
1163fn format_conic_gradient(r: &ConicGradient, tabs: usize) -> String {
1164    let t = String::from("    ").repeat(tabs);
1165    let t1 = String::from("    ").repeat(tabs + 1);
1166
1167    format!(
1168        "ConicGradient {{\r\n{}extend_mode: {},\r\n{}center: {},\r\n{}angle: {},\r\n{}stops: \
1169         NormalizedRadialColorStopVec::from_const_slice(RADIAL_COLOR_STOP_{}_ITEMS),\r\n{}}}",
1170        t1,
1171        r.extend_mode.format_as_rust_code(tabs + 1),
1172        t1,
1173        format_style_background_position(&r.center, tabs + 1),
1174        t1,
1175        format_angle_value(&r.angle),
1176        t1,
1177        r.stops.get_hash(),
1178        t,
1179    )
1180}
1181
1182fn format_radial_gradient(r: &RadialGradient, tabs: usize) -> String {
1183    let t = String::from("    ").repeat(tabs);
1184    let t1 = String::from("    ").repeat(tabs + 1);
1185    format!(
1186        "RadialGradient {{\r\n{}shape: {},\r\n{}extend_mode: {},\r\n{}position: {},\r\n{}size: \
1187         RadialGradientSize::{:?},\r\n{}stops: \
1188         NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
1189        t1,
1190        r.shape.format_as_rust_code(tabs + 1),
1191        t1,
1192        r.extend_mode.format_as_rust_code(tabs + 1),
1193        t1,
1194        format_style_background_position(&r.position, tabs + 1),
1195        t1,
1196        r.size,
1197        t1,
1198        r.stops.get_hash(),
1199        t,
1200    )
1201}
1202
1203fn format_linear_color_stops(stops: &[NormalizedLinearColorStop], tabs: usize) -> String {
1204    let t = String::from("    ").repeat(tabs);
1205    stops
1206        .iter()
1207        .map(|s| format_linear_color_stop(s))
1208        .collect::<Vec<_>>()
1209        .join(&format!(",\r\n{}", t))
1210}
1211
1212fn format_linear_color_stop(g: &NormalizedLinearColorStop) -> String {
1213    format!(
1214        "NormalizedLinearColorStop {{ offset: {}, color: {} }}",
1215        format_percentage_value(&g.offset),
1216        format_color_value(&g.color),
1217    )
1218}
1219
1220fn format_radial_color_stops(stops: &[NormalizedRadialColorStop], tabs: usize) -> String {
1221    let t = String::from("    ").repeat(tabs);
1222    stops
1223        .iter()
1224        .map(|s| format_radial_color_stop(s))
1225        .collect::<Vec<_>>()
1226        .join(&format!(",\r\n{}", t))
1227}
1228
1229fn format_radial_color_stop(g: &NormalizedRadialColorStop) -> String {
1230    format!(
1231        "RadialColorStop {{ angle: {}, color: {} }}",
1232        format_angle_value(&g.angle),
1233        format_color_value(&g.color),
1234    )
1235}
1236
1237impl FormatAsRustCode for StyleTransformVec {
1238    fn format_as_rust_code(&self, tabs: usize) -> String {
1239        format!(
1240            "StyleTransformVec::from_const_slice(STYLE_TRANSFORM_{}_ITEMS)",
1241            self.get_hash()
1242        )
1243    }
1244}
1245
1246fn format_style_filter(st: &StyleFilter, tabs: usize) -> String {
1247    let tabs_minus_one = String::from("    ").repeat(tabs);
1248    let tabs_str = String::from("    ").repeat(tabs + 1);
1249    match st {
1250        StyleFilter::Blend(mb) => format!("StyleFilter::Blend({})", mb.format_as_rust_code(tabs)),
1251        StyleFilter::Flood(c) => format!("StyleFilter::Flood({})", format_color_value(c)),
1252        StyleFilter::Blur(m) => format!(
1253            "StyleFilter::Blur(StyleBlur {{ width: {}, height: {} }})",
1254            format_pixel_value(&m.width),
1255            format_pixel_value(&m.height)
1256        ),
1257        StyleFilter::Opacity(pct) => {
1258            format!("StyleFilter::Opacity({})", format_percentage_value(pct))
1259        }
1260        StyleFilter::ColorMatrix(cm) => format!(
1261            "StyleFilter::ColorMatrix(StyleColorMatrix {{ matrix: {} }})",
1262            cm.matrix
1263                .iter()
1264                .map(|f| format_float_value(f))
1265                .collect::<Vec<_>>()
1266                .join(&format!(",\r\n{}", tabs_str))
1267        ),
1268        StyleFilter::DropShadow(m) => {
1269            format!("StyleFilter::DropShadow({})", m.format_as_rust_code(tabs))
1270        }
1271        StyleFilter::ComponentTransfer => format!("StyleFilter::ComponentTransfer"),
1272        StyleFilter::Offset(o) => format!(
1273            "StyleFilter::Offset(StyleFilterOffset {{ x: {}, y: {} }})",
1274            format_pixel_value(&o.x),
1275            format_pixel_value(&o.y)
1276        ),
1277        StyleFilter::Composite(StyleCompositeFilter::Over) => {
1278            format!("StyleFilter::Composite(StyleCompositeFilter::Over)")
1279        }
1280        StyleFilter::Composite(StyleCompositeFilter::In) => {
1281            format!("StyleFilter::Composite(StyleCompositeFilter::In)")
1282        }
1283        StyleFilter::Composite(StyleCompositeFilter::Atop) => {
1284            format!("StyleFilter::Composite(StyleCompositeFilter::Atop)")
1285        }
1286        StyleFilter::Composite(StyleCompositeFilter::Out) => {
1287            format!("StyleFilter::Composite(StyleCompositeFilter::Out)")
1288        }
1289        StyleFilter::Composite(StyleCompositeFilter::Xor) => {
1290            format!("StyleFilter::Composite(StyleCompositeFilter::Xor)")
1291        }
1292        StyleFilter::Composite(StyleCompositeFilter::Lighter) => {
1293            format!("StyleFilter::Composite(StyleCompositeFilter::Lighter)")
1294        }
1295        StyleFilter::Composite(StyleCompositeFilter::Arithmetic(fv)) => format!(
1296            "StyleFilter::Composite(StyleCompositeFilter::Arithmetic({}))",
1297            fv.iter()
1298                .map(|f| format_float_value(f))
1299                .collect::<Vec<_>>()
1300                .join(&format!(",\r\n{}", tabs))
1301        ),
1302    }
1303}
1304
1305fn format_style_transforms(stops: &[StyleTransform], tabs: usize) -> String {
1306    let t = String::from("    ").repeat(tabs);
1307    stops
1308        .iter()
1309        .map(|s| format_style_transform(s, tabs))
1310        .collect::<Vec<_>>()
1311        .join(&format!(",\r\n{}", t))
1312}
1313
1314fn format_style_transform(st: &StyleTransform, tabs: usize) -> String {
1315    let tabs_minus_one = String::from("    ").repeat(tabs);
1316    let tabs = String::from("    ").repeat(tabs + 1);
1317    match st {
1318        StyleTransform::Matrix(m) => format!(
1319            "StyleTransform::Matrix(StyleTransformMatrix2D {{ a: {}, b: {}, c: {}, d: {}, tx: {}, \
1320             ty: {} }})",
1321            format_pixel_value(&m.a),
1322            format_pixel_value(&m.b),
1323            format_pixel_value(&m.c),
1324            format_pixel_value(&m.d),
1325            format_pixel_value(&m.tx),
1326            format_pixel_value(&m.ty)
1327        ),
1328        StyleTransform::Matrix3D(m) => format!(
1329            "StyleTransform::Matrix3D(StyleTransformMatrix3D {{\r\n{tabs}m11: {},\r\n{tabs}m12: \
1330             {},\r\n{tabs}m13: {},\r\n{tabs}m14: {},\r\n{tabs}m21: {},\r\n{tabs}m22: \
1331             {},\r\n{tabs}m23: {},\r\n{tabs}m24: {},\r\n{tabs}m31: {},\r\n{tabs}m32: \
1332             {},\r\n{tabs}m33: {},\r\n{tabs}m34: {},\r\n{tabs}m41: {},\r\n{tabs}m42: \
1333             {},\r\n{tabs}m43: {},\r\n{tabs}m44: {}\r\n{tabs_minus_one}}})",
1334            format_pixel_value(&m.m11),
1335            format_pixel_value(&m.m12),
1336            format_pixel_value(&m.m13),
1337            format_pixel_value(&m.m14),
1338            format_pixel_value(&m.m21),
1339            format_pixel_value(&m.m22),
1340            format_pixel_value(&m.m23),
1341            format_pixel_value(&m.m24),
1342            format_pixel_value(&m.m31),
1343            format_pixel_value(&m.m32),
1344            format_pixel_value(&m.m33),
1345            format_pixel_value(&m.m34),
1346            format_pixel_value(&m.m41),
1347            format_pixel_value(&m.m42),
1348            format_pixel_value(&m.m43),
1349            format_pixel_value(&m.m44),
1350            tabs = tabs,
1351            tabs_minus_one = tabs_minus_one,
1352        ),
1353        StyleTransform::Translate(t) => format!(
1354            "StyleTransform::Translate(StyleTransformTranslate2D {{ x: {}, y: {} }})",
1355            format_pixel_value(&t.x),
1356            format_pixel_value(&t.y)
1357        ),
1358        StyleTransform::Translate3D(t) => format!(
1359            "StyleTransform::Translate3D(StyleTransformTranslate3D {{ x: {}, y: {}, z: {})",
1360            format_pixel_value(&t.x),
1361            format_pixel_value(&t.y),
1362            format_pixel_value(&t.z)
1363        ),
1364        StyleTransform::TranslateX(x) => {
1365            format!("StyleTransform::TranslateX({})", format_pixel_value(&x))
1366        }
1367        StyleTransform::TranslateY(y) => {
1368            format!("StyleTransform::TranslateY({})", format_pixel_value(&y))
1369        }
1370        StyleTransform::TranslateZ(z) => {
1371            format!("StyleTransform::TranslateZ({})", format_pixel_value(&z))
1372        }
1373        StyleTransform::Rotate(r) => format!("StyleTransform::Rotate({})", format_angle_value(&r)),
1374        StyleTransform::Rotate3D(r) => format!(
1375            "StyleTransform::Rotate3D(StyleTransformRotate3D {{ {}, {}, {}, {} }})",
1376            format_percentage_value(&r.x),
1377            format_percentage_value(&r.y),
1378            format_percentage_value(&r.z),
1379            format_angle_value(&r.angle)
1380        ),
1381        StyleTransform::RotateX(x) => {
1382            format!("StyleTransform::RotateX({})", format_angle_value(&x))
1383        }
1384        StyleTransform::RotateY(y) => {
1385            format!("StyleTransform::RotateY({})", format_angle_value(&y))
1386        }
1387        StyleTransform::RotateZ(z) => {
1388            format!("StyleTransform::RotateZ({})", format_angle_value(&z))
1389        }
1390        StyleTransform::Scale(s) => format!(
1391            "StyleTransform::Scale(StyleTransformScale2D {{ x: {}, y: {} }})",
1392            format_percentage_value(&s.x),
1393            format_percentage_value(&s.y)
1394        ),
1395        StyleTransform::Scale3D(s) => format!(
1396            "StyleTransform::Scale3D(StyleTransformScale3D {{ x; {}, y: {}, z: {} }})",
1397            format_percentage_value(&s.x),
1398            format_percentage_value(&s.y),
1399            format_percentage_value(&s.z)
1400        ),
1401        StyleTransform::ScaleX(x) => {
1402            format!("StyleTransform::ScaleX({})", format_percentage_value(&x))
1403        }
1404        StyleTransform::ScaleY(y) => {
1405            format!("StyleTransform::ScaleY({})", format_percentage_value(&y))
1406        }
1407        StyleTransform::ScaleZ(z) => {
1408            format!("StyleTransform::ScaleZ({})", format_percentage_value(&z))
1409        }
1410        StyleTransform::Skew(sk) => format!(
1411            "StyleTransform::Skew(StyleTransformSkew2D {{ x: {}, y: {} }})",
1412            format_percentage_value(&sk.x),
1413            format_percentage_value(&sk.y)
1414        ),
1415        StyleTransform::SkewX(x) => {
1416            format!("StyleTransform::SkewX({})", format_percentage_value(&x))
1417        }
1418        StyleTransform::SkewY(y) => {
1419            format!("StyleTransform::SkewY({})", format_percentage_value(&y))
1420        }
1421        StyleTransform::Perspective(dist) => {
1422            format!("StyleTransform::Perspective({})", format_pixel_value(&dist))
1423        }
1424    }
1425}
1426
1427fn format_font_ids(font_ids: &[StyleFontFamily], tabs: usize) -> String {
1428    let t = String::from("    ").repeat(tabs);
1429    font_ids
1430        .iter()
1431        .map(|s| format!("{}", s.format_as_rust_code(tabs + 1)))
1432        .collect::<Vec<_>>()
1433        .join(&format!(",\r\n{}", t))
1434}
1435
1436impl FormatAsRustCode for StyleFontFamilyVec {
1437    fn format_as_rust_code(&self, tabs: usize) -> String {
1438        format!(
1439            "StyleFontFamilyVec::from_const_slice(STYLE_FONT_FAMILY_{}_ITEMS)",
1440            self.get_hash()
1441        )
1442    }
1443}
1444
1445impl FormatAsRustCode for StyleFontFamily {
1446    fn format_as_rust_code(&self, tabs: usize) -> String {
1447        use azul_css::StyleFontFamily::*;
1448        let t = String::from("    ").repeat(tabs);
1449        match self {
1450            System(id) => format!("StyleFontFamily::System(STRING_{})", id.get_hash()),
1451            File(path) => format!("StyleFontFamily::File(STRING_{})", path.get_hash()),
1452            Ref(font_ref) => format!("StyleFontFamily::Ref({:0x})", font_ref.data as usize),
1453        }
1454    }
1455}
1456
1457impl FormatAsRustCode for StyleBackgroundPositionVec {
1458    fn format_as_rust_code(&self, tabs: usize) -> String {
1459        format!(
1460            "StyleBackgroundPositionVec::from_const_slice(STYLE_BACKGROUND_POSITION_{}_ITEMS)",
1461            self.get_hash()
1462        )
1463    }
1464}
1465
1466fn format_style_background_position(b: &StyleBackgroundPosition, tabs: usize) -> String {
1467    let t = String::from("    ").repeat(tabs);
1468    let t1 = String::from("    ").repeat(tabs + 1);
1469    format!(
1470        "StyleBackgroundPosition {{\r\n{}horizontal: {},\r\n{}vertical: {},\r\n{}}}",
1471        t1,
1472        format_background_position_horizontal(&b.horizontal),
1473        t1,
1474        format_background_position_vertical(&b.vertical),
1475        t
1476    )
1477}
1478
1479fn format_background_position_horizontal(b: &BackgroundPositionHorizontal) -> String {
1480    match b {
1481        BackgroundPositionHorizontal::Left => format!("BackgroundPositionHorizontal::Left"),
1482        BackgroundPositionHorizontal::Center => format!("BackgroundPositionHorizontal::Center"),
1483        BackgroundPositionHorizontal::Right => format!("BackgroundPositionHorizontal::Right"),
1484        BackgroundPositionHorizontal::Exact(p) => format!(
1485            "BackgroundPositionHorizontal::Exact({})",
1486            format_pixel_value(p)
1487        ),
1488    }
1489}
1490
1491fn format_background_position_vertical(b: &BackgroundPositionVertical) -> String {
1492    match b {
1493        BackgroundPositionVertical::Top => format!("BackgroundPositionVertical::Top"),
1494        BackgroundPositionVertical::Center => format!("BackgroundPositionVertical::Center"),
1495        BackgroundPositionVertical::Bottom => format!("BackgroundPositionVertical::Bottom"),
1496        BackgroundPositionVertical::Exact(p) => format!(
1497            "BackgroundPositionVertical::Exact({})",
1498            format_pixel_value(p)
1499        ),
1500    }
1501}
1502
1503impl FormatAsRustCode for StyleBorderTopStyle {
1504    fn format_as_rust_code(&self, tabs: usize) -> String {
1505        format!(
1506            "StyleBorderTopStyle {{ inner: {} }}",
1507            &self.inner.format_as_rust_code(tabs)
1508        )
1509    }
1510}
1511
1512impl FormatAsRustCode for StyleBorderRightStyle {
1513    fn format_as_rust_code(&self, tabs: usize) -> String {
1514        format!(
1515            "StyleBorderRightStyle {{ inner: {} }}",
1516            &self.inner.format_as_rust_code(tabs)
1517        )
1518    }
1519}
1520
1521impl FormatAsRustCode for StyleBorderLeftStyle {
1522    fn format_as_rust_code(&self, tabs: usize) -> String {
1523        format!(
1524            "StyleBorderLeftStyle {{ inner: {} }}",
1525            &self.inner.format_as_rust_code(tabs)
1526        )
1527    }
1528}
1529
1530impl FormatAsRustCode for StyleBorderBottomStyle {
1531    fn format_as_rust_code(&self, tabs: usize) -> String {
1532        format!(
1533            "StyleBorderBottomStyle {{ inner: {} }}",
1534            &self.inner.format_as_rust_code(tabs)
1535        )
1536    }
1537}
1538
1539impl FormatAsRustCode for StyleBoxShadow {
1540    fn format_as_rust_code(&self, tabs: usize) -> String {
1541        let t = String::from("    ").repeat(tabs);
1542        format!(
1543            "StyleBoxShadow {{\r\n{}    offset: [{}, {}],\r\n{}    color: {},\r\n{}    \
1544             blur_radius: {},\r\n{}    spread_radius: {},\r\n{}    clip_mode: \
1545             BoxShadowClipMode::{:?},\r\n{}}}",
1546            t,
1547            format_pixel_value_no_percent(&self.offset[0]),
1548            format_pixel_value_no_percent(&self.offset[1]),
1549            t,
1550            format_color_value(&self.color),
1551            t,
1552            format_pixel_value_no_percent(&self.blur_radius),
1553            t,
1554            format_pixel_value_no_percent(&self.spread_radius),
1555            t,
1556            self.clip_mode,
1557            t
1558        )
1559    }
1560}
1561
1562impl FormatAsRustCode for StyleTransformOrigin {
1563    fn format_as_rust_code(&self, _tabs: usize) -> String {
1564        format!(
1565            "StyleTransformOrigin {{ x: {}, y: {} }}",
1566            format_pixel_value(&self.x),
1567            format_pixel_value(&self.y)
1568        )
1569    }
1570}
1571
1572impl FormatAsRustCode for StylePerspectiveOrigin {
1573    fn format_as_rust_code(&self, _tabs: usize) -> String {
1574        format!(
1575            "StylePerspectiveOrigin {{ x: {}, y: {} }}",
1576            format_pixel_value(&self.x),
1577            format_pixel_value(&self.y)
1578        )
1579    }
1580}