1
//! CSS properties for styling text.
2
//!
3
//! Each property type implements `PrintAsCssValue` for CSS serialization and
4
//! (behind the `parser` feature) has a corresponding `parse_style_*` function
5
//! with borrowed/owned error type pairs.
6

            
7
use alloc::string::{String, ToString};
8
use core::fmt;
9
use crate::corety::AzString;
10

            
11
use crate::{
12
    format_rust_code::FormatAsRustCode,
13
    props::{
14
        basic::{
15
            error::{InvalidValueErr, InvalidValueErrOwned},
16
            length::{PercentageParseError, PercentageParseErrorOwned, PercentageValue},
17
            pixel::{CssPixelValueParseError, CssPixelValueParseErrorOwned, PixelValue},
18
            ColorU, CssDuration,
19
        },
20
        formatter::PrintAsCssValue,
21
        macros::PixelValueTaker,
22
    },
23
};
24

            
25
// -- StyleTextColor (color property) --
26
// NOTE: `color` is a text property, but the `ColorU` type itself is in `basic/color.rs`.
27
// This is a newtype wrapper for type safety.
28

            
29
/// Represents a `color` attribute.
30
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
31
#[repr(C)]
32
pub struct StyleTextColor {
33
    pub inner: crate::props::basic::color::ColorU,
34
}
35

            
36
impl fmt::Debug for StyleTextColor {
37
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38
        write!(f, "{}", self.print_as_css_value())
39
    }
40
}
41

            
42
impl StyleTextColor {
43
    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
44
        Self {
45
            inner: self.inner.interpolate(&other.inner, t),
46
        }
47
    }
48
}
49

            
50
impl PrintAsCssValue for StyleTextColor {
51
    fn print_as_css_value(&self) -> String {
52
        self.inner.to_hash()
53
    }
54
}
55

            
56
// -- StyleTextAlign --
57

            
58
/// Horizontal text alignment enum (left, center, right) - default: `Left`
59
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
60
#[repr(C)]
61
pub enum StyleTextAlign {
62
    Left,
63
    Center,
64
    Right,
65
    Justify,
66
    #[default]
67
    Start,
68
    End,
69
}
70

            
71
impl_option!(
72
    StyleTextAlign,
73
    OptionStyleTextAlign,
74
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
75
);
76

            
77
impl PrintAsCssValue for StyleTextAlign {
78
    fn print_as_css_value(&self) -> String {
79
        String::from(match self {
80
            StyleTextAlign::Left => "left",
81
            StyleTextAlign::Center => "center",
82
            StyleTextAlign::Right => "right",
83
            StyleTextAlign::Justify => "justify",
84
            StyleTextAlign::Start => "start",
85
            StyleTextAlign::End => "end",
86
        })
87
    }
88
}
89

            
90
// -- StyleLetterSpacing --
91

            
92
/// Represents a `letter-spacing` attribute
93
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
94
#[repr(C)]
95
pub struct StyleLetterSpacing {
96
    pub inner: PixelValue,
97
}
98

            
99
impl fmt::Debug for StyleLetterSpacing {
100
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101
        write!(f, "{}", self.inner)
102
    }
103
}
104
impl Default for StyleLetterSpacing {
105
    fn default() -> Self {
106
        Self {
107
            inner: PixelValue::const_px(0),
108
        }
109
    }
110
}
111
impl_pixel_value!(StyleLetterSpacing);
112
impl PixelValueTaker for StyleLetterSpacing {
113
    fn from_pixel_value(inner: PixelValue) -> Self {
114
        Self { inner }
115
    }
116
}
117
impl PrintAsCssValue for StyleLetterSpacing {
118
    fn print_as_css_value(&self) -> String {
119
        format!("{}", self.inner)
120
    }
121
}
122

            
123
// -- StyleWordSpacing --
124

            
125
/// Represents a `word-spacing` attribute
126
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
127
#[repr(C)]
128
pub struct StyleWordSpacing {
129
    pub inner: PixelValue,
130
}
131

            
132
impl fmt::Debug for StyleWordSpacing {
133
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134
        write!(f, "{}", self.inner)
135
    }
136
}
137
impl Default for StyleWordSpacing {
138
    fn default() -> Self {
139
        Self {
140
            inner: PixelValue::const_px(0),
141
        }
142
    }
143
}
144
impl_pixel_value!(StyleWordSpacing);
145
impl PixelValueTaker for StyleWordSpacing {
146
    fn from_pixel_value(inner: PixelValue) -> Self {
147
        Self { inner }
148
    }
149
}
150
impl PrintAsCssValue for StyleWordSpacing {
151
    fn print_as_css_value(&self) -> String {
152
        format!("{}", self.inner)
153
    }
154
}
155

            
156
// -- StyleLineHeight --
157

            
158
/// Represents a `line-height` attribute
159
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
160
#[repr(C)]
161
pub struct StyleLineHeight {
162
    pub inner: PercentageValue,
163
}
164
impl Default for StyleLineHeight {
165
6972
    fn default() -> Self {
166
6972
        Self {
167
6972
            inner: PercentageValue::const_new(120),
168
6972
        }
169
6972
    }
170
}
171
impl_percentage_value!(StyleLineHeight);
172
impl PrintAsCssValue for StyleLineHeight {
173
    fn print_as_css_value(&self) -> String {
174
        format!("{}", self.inner)
175
    }
176
}
177

            
178
// -- StyleTabSize --
179

            
180
/// Represents a `tab-size` attribute
181
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
182
#[repr(C)]
183
pub struct StyleTabSize {
184
    pub inner: PixelValue, // Can be a number (space characters, em-based) or a length
185
}
186

            
187
impl fmt::Debug for StyleTabSize {
188
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189
        write!(f, "{}", self.inner)
190
    }
191
}
192
impl Default for StyleTabSize {
193
    fn default() -> Self {
194
        Self {
195
            inner: PixelValue::em(8.0),
196
        }
197
    }
198
}
199
impl_pixel_value!(StyleTabSize);
200
impl PixelValueTaker for StyleTabSize {
201
    fn from_pixel_value(inner: PixelValue) -> Self {
202
        Self { inner }
203
    }
204
}
205
impl PrintAsCssValue for StyleTabSize {
206
    fn print_as_css_value(&self) -> String {
207
        format!("{}", self.inner)
208
    }
209
}
210

            
211
// -- StyleWhiteSpace --
212

            
213
/// How to handle white space inside an element.
214
/// 
215
/// CSS Text Level 3: https://www.w3.org/TR/css-text-3/#white-space-property
216
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
217
#[repr(C)]
218
#[derive(Default)]
219
pub enum StyleWhiteSpace {
220
    /// Collapse whitespace, wrap lines
221
    #[default]
222
    Normal,
223
    /// Preserve whitespace, no wrap (except for explicit breaks)
224
    Pre,
225
    /// Collapse whitespace, no wrap
226
    Nowrap,
227
    /// Preserve whitespace, wrap lines
228
    PreWrap,
229
    /// Collapse whitespace (except newlines), wrap lines
230
    PreLine,
231
    /// Preserve whitespace, allow breaking at spaces
232
    BreakSpaces,
233
}
234
impl_option!(
235
    StyleWhiteSpace,
236
    OptionStyleWhiteSpace,
237
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
238
);
239
impl PrintAsCssValue for StyleWhiteSpace {
240
    fn print_as_css_value(&self) -> String {
241
        String::from(match self {
242
            StyleWhiteSpace::Normal => "normal",
243
            StyleWhiteSpace::Pre => "pre",
244
            StyleWhiteSpace::Nowrap => "nowrap",
245
            StyleWhiteSpace::PreWrap => "pre-wrap",
246
            StyleWhiteSpace::PreLine => "pre-line",
247
            StyleWhiteSpace::BreakSpaces => "break-spaces",
248
        })
249
    }
250
}
251

            
252
// -- StyleHyphens --
253

            
254
/// Hyphenation rules.
255
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
256
#[repr(C)]
257
#[derive(Default)]
258
pub enum StyleHyphens {
259
    /// No hyphenation: words are not broken at hyphenation opportunities.
260
    None,
261
    /// Manual hyphenation: words are only broken at explicit soft hyphens (U+00AD)
262
    /// or unconditional hyphens (U+2010).
263
    #[default]
264
    Manual,
265
    /// Automatic hyphenation: words may be broken at automatic hyphenation
266
    /// opportunities determined by a language-appropriate hyphenation resource,
267
    /// in addition to explicit opportunities.
268
    Auto,
269
}
270
impl_option!(
271
    StyleHyphens,
272
    OptionStyleHyphens,
273
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
274
);
275
impl PrintAsCssValue for StyleHyphens {
276
    fn print_as_css_value(&self) -> String {
277
        String::from(match self {
278
            StyleHyphens::None => "none",
279
            StyleHyphens::Manual => "manual",
280
            StyleHyphens::Auto => "auto",
281
        })
282
    }
283
}
284

            
285
// -- StyleLineBreak --
286

            
287
/// Controls the strictness of line breaking rules.
288
///
289
/// CSS Text Level 3: https://www.w3.org/TR/css-text-3/#line-break-property
290
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
291
#[repr(C)]
292
#[derive(Default)]
293
pub enum StyleLineBreak {
294
    /// The browser determines the set of line-breaking restrictions to use.
295
    #[default]
296
    Auto,
297
    /// Breaks text using the least restrictive set of line-breaking rules.
298
    Loose,
299
    /// Breaks text using the most common set of line-breaking rules.
300
    Normal,
301
    /// Breaks text using the most stringent set of line-breaking rules.
302
    Strict,
303
    /// There is a soft wrap opportunity around every typographic character unit,
304
    /// including around any punctuation character or preserved white spaces,
305
    /// or in the middle of words, disregarding any prohibition against line breaks.
306
    Anywhere,
307
}
308
impl_option!(
309
    StyleLineBreak,
310
    OptionStyleLineBreak,
311
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
312
);
313
impl PrintAsCssValue for StyleLineBreak {
314
    fn print_as_css_value(&self) -> String {
315
        String::from(match self {
316
            StyleLineBreak::Auto => "auto",
317
            StyleLineBreak::Loose => "loose",
318
            StyleLineBreak::Normal => "normal",
319
            StyleLineBreak::Strict => "strict",
320
            StyleLineBreak::Anywhere => "anywhere",
321
        })
322
    }
323
}
324

            
325
// -- StyleWordBreak --
326

            
327
/// Controls line breaking rules within words.
328
///
329
/// CSS Text Level 3 §5.2: https://www.w3.org/TR/css-text-3/#word-break-property
330
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
331
#[repr(C)]
332
#[derive(Default)]
333
pub enum StyleWordBreak {
334
    /// Use default line break rules.
335
    #[default]
336
    Normal,
337
    /// Allow break opportunities between any two characters (CJK and non-CJK).
338
    BreakAll,
339
    /// Forbid break opportunities within CJK character sequences.
340
    KeepAll,
341
    // +spec:line-breaking:815882 - deprecated break-word keyword: same as normal + overflow-wrap: anywhere
342
    /// Deprecated: equivalent to word-break: normal and overflow-wrap: anywhere.
343
    BreakWord,
344
}
345
impl_option!(
346
    StyleWordBreak,
347
    OptionStyleWordBreak,
348
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
349
);
350
impl PrintAsCssValue for StyleWordBreak {
351
    fn print_as_css_value(&self) -> String {
352
        String::from(match self {
353
            StyleWordBreak::Normal => "normal",
354
            StyleWordBreak::BreakAll => "break-all",
355
            StyleWordBreak::KeepAll => "keep-all",
356
            StyleWordBreak::BreakWord => "break-word",
357
        })
358
    }
359
}
360

            
361
// -- StyleOverflowWrap --
362

            
363
/// Controls whether the browser may break at otherwise disallowed points
364
/// to prevent overflow.
365
///
366
/// CSS Text Level 3 §3.3: https://www.w3.org/TR/css-text-3/#overflow-wrap-property
367
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
368
#[repr(C)]
369
#[derive(Default)]
370
pub enum StyleOverflowWrap {
371
    /// Lines may only break at allowed break points.
372
    #[default]
373
    Normal,
374
    /// An otherwise unbreakable sequence may be broken at an arbitrary point
375
    /// if there are no otherwise acceptable break points.
376
    Anywhere,
377
    /// Same as `anywhere` but soft wrap opportunities introduced are not
378
    /// considered when calculating min-content intrinsic sizes.
379
    BreakWord,
380
}
381
impl_option!(
382
    StyleOverflowWrap,
383
    OptionStyleOverflowWrap,
384
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
385
);
386
impl PrintAsCssValue for StyleOverflowWrap {
387
    fn print_as_css_value(&self) -> String {
388
        String::from(match self {
389
            StyleOverflowWrap::Normal => "normal",
390
            StyleOverflowWrap::Anywhere => "anywhere",
391
            StyleOverflowWrap::BreakWord => "break-word",
392
        })
393
    }
394
}
395

            
396
// -- StyleTextAlignLast --
397

            
398
/// Controls alignment of the last line of a block or a line right before
399
/// a forced line break.
400
///
401
/// CSS Text Level 3 §7.2: https://www.w3.org/TR/css-text-3/#text-align-last-property
402
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
403
#[repr(C)]
404
#[derive(Default)]
405
pub enum StyleTextAlignLast {
406
    /// Alignment of the last line is determined by text-align (or start if justify).
407
    #[default]
408
    Auto,
409
    /// Align to the start edge of the line box.
410
    Start,
411
    /// Align to the end edge of the line box.
412
    End,
413
    /// Align to the line left.
414
    Left,
415
    /// Align to the line right.
416
    Right,
417
    /// Center the content.
418
    Center,
419
    /// Justify the content.
420
    Justify,
421
}
422
impl_option!(
423
    StyleTextAlignLast,
424
    OptionStyleTextAlignLast,
425
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
426
);
427
impl PrintAsCssValue for StyleTextAlignLast {
428
    fn print_as_css_value(&self) -> String {
429
        String::from(match self {
430
            StyleTextAlignLast::Auto => "auto",
431
            StyleTextAlignLast::Start => "start",
432
            StyleTextAlignLast::End => "end",
433
            StyleTextAlignLast::Left => "left",
434
            StyleTextAlignLast::Right => "right",
435
            StyleTextAlignLast::Center => "center",
436
            StyleTextAlignLast::Justify => "justify",
437
        })
438
    }
439
}
440

            
441
// -- StyleDirection --
442

            
443
/// Text direction.
444
// +spec:writing-modes:46fed3 - direction property provides explicit bidi controls in CSS
445
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
446
#[repr(C)]
447
#[derive(Default)]
448
pub enum StyleDirection {
449
    /// Left-to-right text direction
450
    #[default]
451
    Ltr,
452
    /// Right-to-left text direction
453
    Rtl,
454
}
455
impl_option!(
456
    StyleDirection,
457
    OptionStyleDirection,
458
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
459
);
460
impl PrintAsCssValue for StyleDirection {
461
    fn print_as_css_value(&self) -> String {
462
        String::from(match self {
463
            StyleDirection::Ltr => "ltr",
464
            StyleDirection::Rtl => "rtl",
465
        })
466
    }
467
}
468

            
469
// -- StyleUserSelect --
470

            
471
/// Controls whether the user can select text.
472
/// Used to prevent accidental text selection on UI controls like buttons.
473
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
474
#[repr(C)]
475
#[derive(Default)]
476
pub enum StyleUserSelect {
477
    /// Browser determines selectability (default)
478
    #[default]
479
    Auto,
480
    /// Text is selectable
481
    Text,
482
    /// Text is not selectable
483
    None,
484
    /// User can select all text with a single action
485
    All,
486
}
487
impl_option!(
488
    StyleUserSelect,
489
    OptionStyleUserSelect,
490
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
491
);
492
impl PrintAsCssValue for StyleUserSelect {
493
    fn print_as_css_value(&self) -> String {
494
        String::from(match self {
495
            StyleUserSelect::Auto => "auto",
496
            StyleUserSelect::Text => "text",
497
            StyleUserSelect::None => "none",
498
            StyleUserSelect::All => "all",
499
        })
500
    }
501
}
502

            
503
// -- StyleTextDecoration --
504

            
505
/// Text decoration (underline, overline, line-through).
506
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
507
#[repr(C)]
508
#[derive(Default)]
509
pub enum StyleTextDecoration {
510
    /// No decoration
511
    #[default]
512
    None,
513
    /// Underline
514
    Underline,
515
    /// Line above text
516
    Overline,
517
    /// Strike-through line
518
    LineThrough,
519
}
520
impl_option!(
521
    StyleTextDecoration,
522
    OptionStyleTextDecoration,
523
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
524
);
525
impl PrintAsCssValue for StyleTextDecoration {
526
    fn print_as_css_value(&self) -> String {
527
        String::from(match self {
528
            StyleTextDecoration::None => "none",
529
            StyleTextDecoration::Underline => "underline",
530
            StyleTextDecoration::Overline => "overline",
531
            StyleTextDecoration::LineThrough => "line-through",
532
        })
533
    }
534
}
535

            
536
// -- StyleVerticalAlign --
537

            
538
/// CSS 2.2 §10.8.1 vertical-align property values
539
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
540
#[repr(C, u8)]
541
#[derive(Default)]
542
pub enum StyleVerticalAlign {
543
    /// CSS default - align baselines
544
    #[default]
545
    Baseline,
546
    /// Align top of element with top of line box
547
    Top,
548
    /// Align middle of element with baseline + half x-height
549
    Middle,
550
    /// Align bottom of element with bottom of line box
551
    Bottom,
552
    /// Align baseline with parent's subscript baseline
553
    Sub,
554
    /// Align baseline with parent's superscript baseline
555
    Superscript,
556
    /// Align top with top of parent's font
557
    TextTop,
558
    /// Align bottom with bottom of parent's font
559
    TextBottom,
560
    /// <percentage> refers to line-height of the element itself
561
    Percentage(PercentageValue),
562
    /// <length> offset from baseline
563
    Length(PixelValue),
564
}
565

            
566
impl_option!(
567
    StyleVerticalAlign,
568
    OptionStyleVerticalAlign,
569
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
570
);
571

            
572
impl PrintAsCssValue for StyleVerticalAlign {
573
    fn print_as_css_value(&self) -> String {
574
        match self {
575
            StyleVerticalAlign::Baseline => String::from("baseline"),
576
            StyleVerticalAlign::Top => String::from("top"),
577
            StyleVerticalAlign::Middle => String::from("middle"),
578
            StyleVerticalAlign::Bottom => String::from("bottom"),
579
            StyleVerticalAlign::Sub => String::from("sub"),
580
            StyleVerticalAlign::Superscript => String::from("super"),
581
            StyleVerticalAlign::TextTop => String::from("text-top"),
582
            StyleVerticalAlign::TextBottom => String::from("text-bottom"),
583
            StyleVerticalAlign::Percentage(p) => format!("{}%", p.normalized() * 100.0),
584
            StyleVerticalAlign::Length(l) => l.print_as_css_value(),
585
        }
586
    }
587
}
588

            
589
impl crate::format_rust_code::FormatAsRustCode for StyleVerticalAlign {
590
    fn format_as_rust_code(&self, indent: usize) -> String {
591
        match self {
592
            StyleVerticalAlign::Baseline => "StyleVerticalAlign::Baseline".to_string(),
593
            StyleVerticalAlign::Top => "StyleVerticalAlign::Top".to_string(),
594
            StyleVerticalAlign::Middle => "StyleVerticalAlign::Middle".to_string(),
595
            StyleVerticalAlign::Bottom => "StyleVerticalAlign::Bottom".to_string(),
596
            StyleVerticalAlign::Sub => "StyleVerticalAlign::Sub".to_string(),
597
            StyleVerticalAlign::Superscript => "StyleVerticalAlign::Superscript".to_string(),
598
            StyleVerticalAlign::TextTop => "StyleVerticalAlign::TextTop".to_string(),
599
            StyleVerticalAlign::TextBottom => "StyleVerticalAlign::TextBottom".to_string(),
600
            StyleVerticalAlign::Percentage(p) => format!("StyleVerticalAlign::Percentage(PercentageValue::new({}))", p.normalized() * 100.0),
601
            StyleVerticalAlign::Length(l) => format!("StyleVerticalAlign::Length({})", l),
602
        }
603
    }
604
}
605

            
606
// --- PARSERS ---
607

            
608
#[cfg(feature = "parser")]
609
use crate::props::basic::{
610
    color::{parse_css_color, CssColorParseError, CssColorParseErrorOwned},
611
    DurationParseError,
612
};
613

            
614
#[cfg(feature = "parser")]
615
#[derive(Clone, PartialEq)]
616
pub enum StyleTextColorParseError<'a> {
617
    ColorParseError(CssColorParseError<'a>),
618
}
619
#[cfg(feature = "parser")]
620
impl_debug_as_display!(StyleTextColorParseError<'a>);
621
#[cfg(feature = "parser")]
622
impl_display! { StyleTextColorParseError<'a>, {
623
    ColorParseError(e) => format!("Invalid color: {}", e),
624
}}
625
#[cfg(feature = "parser")]
626
impl_from!(
627
    CssColorParseError<'a>,
628
    StyleTextColorParseError::ColorParseError
629
);
630

            
631
#[cfg(feature = "parser")]
632
#[derive(Debug, Clone, PartialEq)]
633
#[repr(C, u8)]
634
pub enum StyleTextColorParseErrorOwned {
635
    ColorParseError(CssColorParseErrorOwned),
636
}
637

            
638
#[cfg(feature = "parser")]
639
impl<'a> StyleTextColorParseError<'a> {
640
    pub fn to_contained(&self) -> StyleTextColorParseErrorOwned {
641
        match self {
642
            Self::ColorParseError(e) => {
643
                StyleTextColorParseErrorOwned::ColorParseError(e.to_contained())
644
            }
645
        }
646
    }
647
}
648

            
649
#[cfg(feature = "parser")]
650
impl StyleTextColorParseErrorOwned {
651
    pub fn to_shared<'a>(&'a self) -> StyleTextColorParseError<'a> {
652
        match self {
653
            Self::ColorParseError(e) => StyleTextColorParseError::ColorParseError(e.to_shared()),
654
        }
655
    }
656
}
657

            
658
#[cfg(feature = "parser")]
659
1202
pub fn parse_style_text_color(input: &str) -> Result<StyleTextColor, StyleTextColorParseError<'_>> {
660
1202
    parse_css_color(input)
661
1202
        .map(|inner| StyleTextColor { inner })
662
1202
        .map_err(StyleTextColorParseError::ColorParseError)
663
1202
}
664

            
665
#[cfg(feature = "parser")]
666
#[derive(Clone, PartialEq)]
667
pub enum StyleTextAlignParseError<'a> {
668
    InvalidValue(InvalidValueErr<'a>),
669
}
670
#[cfg(feature = "parser")]
671
impl_debug_as_display!(StyleTextAlignParseError<'a>);
672
#[cfg(feature = "parser")]
673
impl_display! { StyleTextAlignParseError<'a>, {
674
    InvalidValue(e) => format!("Invalid text-align value: \"{}\"", e.0),
675
}}
676
#[cfg(feature = "parser")]
677
impl_from!(InvalidValueErr<'a>, StyleTextAlignParseError::InvalidValue);
678

            
679
#[cfg(feature = "parser")]
680
#[derive(Debug, Clone, PartialEq)]
681
#[repr(C, u8)]
682
pub enum StyleTextAlignParseErrorOwned {
683
    InvalidValue(InvalidValueErrOwned),
684
}
685

            
686
#[cfg(feature = "parser")]
687
impl<'a> StyleTextAlignParseError<'a> {
688
    pub fn to_contained(&self) -> StyleTextAlignParseErrorOwned {
689
        match self {
690
            Self::InvalidValue(e) => StyleTextAlignParseErrorOwned::InvalidValue(e.to_contained()),
691
        }
692
    }
693
}
694

            
695
#[cfg(feature = "parser")]
696
impl StyleTextAlignParseErrorOwned {
697
    pub fn to_shared<'a>(&'a self) -> StyleTextAlignParseError<'a> {
698
        match self {
699
            Self::InvalidValue(e) => StyleTextAlignParseError::InvalidValue(e.to_shared()),
700
        }
701
    }
702
}
703

            
704
#[cfg(feature = "parser")]
705
7
pub fn parse_style_text_align(input: &str) -> Result<StyleTextAlign, StyleTextAlignParseError<'_>> {
706
7
    match input.trim() {
707
7
        "left" => Ok(StyleTextAlign::Left),
708
6
        "center" => Ok(StyleTextAlign::Center),
709
5
        "right" => Ok(StyleTextAlign::Right),
710
4
        "justify" => Ok(StyleTextAlign::Justify),
711
3
        "start" => Ok(StyleTextAlign::Start),
712
2
        "end" => Ok(StyleTextAlign::End),
713
1
        other => Err(StyleTextAlignParseError::InvalidValue(InvalidValueErr(
714
1
            other,
715
1
        ))),
716
    }
717
7
}
718

            
719
#[cfg(feature = "parser")]
720
#[derive(Clone, PartialEq)]
721
pub enum StyleLetterSpacingParseError<'a> {
722
    PixelValue(CssPixelValueParseError<'a>),
723
}
724
#[cfg(feature = "parser")]
725
impl_debug_as_display!(StyleLetterSpacingParseError<'a>);
726
#[cfg(feature = "parser")]
727
impl_display! { StyleLetterSpacingParseError<'a>, {
728
    PixelValue(e) => format!("Invalid letter-spacing value: {}", e),
729
}}
730
#[cfg(feature = "parser")]
731
impl_from!(
732
    CssPixelValueParseError<'a>,
733
    StyleLetterSpacingParseError::PixelValue
734
);
735

            
736
#[cfg(feature = "parser")]
737
#[derive(Debug, Clone, PartialEq)]
738
#[repr(C, u8)]
739
pub enum StyleLetterSpacingParseErrorOwned {
740
    PixelValue(CssPixelValueParseErrorOwned),
741
}
742

            
743
#[cfg(feature = "parser")]
744
impl<'a> StyleLetterSpacingParseError<'a> {
745
    pub fn to_contained(&self) -> StyleLetterSpacingParseErrorOwned {
746
        match self {
747
            Self::PixelValue(e) => StyleLetterSpacingParseErrorOwned::PixelValue(e.to_contained()),
748
        }
749
    }
750
}
751

            
752
#[cfg(feature = "parser")]
753
impl StyleLetterSpacingParseErrorOwned {
754
    pub fn to_shared<'a>(&'a self) -> StyleLetterSpacingParseError<'a> {
755
        match self {
756
            Self::PixelValue(e) => StyleLetterSpacingParseError::PixelValue(e.to_shared()),
757
        }
758
    }
759
}
760

            
761
#[cfg(feature = "parser")]
762
2
pub fn parse_style_letter_spacing(
763
2
    input: &str,
764
2
) -> Result<StyleLetterSpacing, StyleLetterSpacingParseError<'_>> {
765
2
    crate::props::basic::pixel::parse_pixel_value(input)
766
2
        .map(|inner| StyleLetterSpacing { inner })
767
2
        .map_err(StyleLetterSpacingParseError::PixelValue)
768
2
}
769

            
770
// -- StyleTextIndent (text-indent property) --
771

            
772
/// Represents a `text-indent` attribute (indentation of first line in a block).
773
#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
774
#[repr(C)]
775
pub struct StyleTextIndent {
776
    pub inner: PixelValue,
777
    /// `each-line` keyword: indent first line of each block container
778
    /// AND each line after a forced line break (but not after soft wrap).
779
    pub each_line: bool,
780
    /// `hanging` keyword: inverts which lines are affected by the indent.
781
    pub hanging: bool,
782
}
783

            
784
impl fmt::Debug for StyleTextIndent {
785
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
786
        write!(f, "{}", self.print_as_css_value())
787
    }
788
}
789

            
790
impl StyleTextIndent {
791
    #[inline]
792
    pub const fn zero() -> Self {
793
        Self { inner: crate::props::basic::pixel::PixelValue::zero(), each_line: false, hanging: false }
794
    }
795
    #[inline]
796
    pub const fn const_px(value: isize) -> Self {
797
        Self { inner: crate::props::basic::pixel::PixelValue::const_px(value), each_line: false, hanging: false }
798
    }
799
    #[inline]
800
    pub const fn const_em(value: isize) -> Self {
801
        Self { inner: crate::props::basic::pixel::PixelValue::const_em(value), each_line: false, hanging: false }
802
    }
803
    #[inline]
804
    pub const fn const_pt(value: isize) -> Self {
805
        Self { inner: crate::props::basic::pixel::PixelValue::const_pt(value), each_line: false, hanging: false }
806
    }
807
    #[inline]
808
    pub const fn const_percent(value: isize) -> Self {
809
        Self { inner: crate::props::basic::pixel::PixelValue::const_percent(value), each_line: false, hanging: false }
810
    }
811
    #[inline]
812
    pub const fn const_in(value: isize) -> Self {
813
        Self { inner: crate::props::basic::pixel::PixelValue::const_in(value), each_line: false, hanging: false }
814
    }
815
    #[inline]
816
    pub const fn const_cm(value: isize) -> Self {
817
        Self { inner: crate::props::basic::pixel::PixelValue::const_cm(value), each_line: false, hanging: false }
818
    }
819
    #[inline]
820
    pub const fn const_mm(value: isize) -> Self {
821
        Self { inner: crate::props::basic::pixel::PixelValue::const_mm(value), each_line: false, hanging: false }
822
    }
823
    #[inline]
824
    pub const fn const_from_metric(metric: crate::props::basic::length::SizeMetric, value: isize) -> Self {
825
        Self { inner: crate::props::basic::pixel::PixelValue::const_from_metric(metric, value), each_line: false, hanging: false }
826
    }
827
    #[inline]
828
    pub fn px(value: f32) -> Self {
829
        Self { inner: crate::props::basic::pixel::PixelValue::px(value), each_line: false, hanging: false }
830
    }
831
    #[inline]
832
    pub fn em(value: f32) -> Self {
833
        Self { inner: crate::props::basic::pixel::PixelValue::em(value), each_line: false, hanging: false }
834
    }
835
    #[inline]
836
    pub fn pt(value: f32) -> Self {
837
        Self { inner: crate::props::basic::pixel::PixelValue::pt(value), each_line: false, hanging: false }
838
    }
839
    #[inline]
840
    pub fn percent(value: f32) -> Self {
841
        Self { inner: crate::props::basic::pixel::PixelValue::percent(value), each_line: false, hanging: false }
842
    }
843
    #[inline]
844
    pub fn from_metric(metric: crate::props::basic::length::SizeMetric, value: f32) -> Self {
845
        Self { inner: crate::props::basic::pixel::PixelValue::from_metric(metric, value), each_line: false, hanging: false }
846
    }
847
    #[inline]
848
    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
849
        StyleTextIndent { inner: self.inner.interpolate(&other.inner, t), each_line: self.each_line, hanging: self.hanging }
850
    }
851
}
852

            
853
impl PrintAsCssValue for StyleTextIndent {
854
    fn print_as_css_value(&self) -> String {
855
        let mut s = self.inner.to_string();
856
        if self.hanging {
857
            s.push_str(" hanging");
858
        }
859
        if self.each_line {
860
            s.push_str(" each-line");
861
        }
862
        s
863
    }
864
}
865

            
866
impl crate::format_rust_code::FormatAsRustCode for StyleTextIndent {
867
    fn format_as_rust_code(&self, _tabs: usize) -> String {
868
        format!(
869
            "StyleTextIndent {{ inner: {}, each_line: {}, hanging: {} }}",
870
            self.inner.format_as_rust_code(0), self.each_line, self.hanging
871
        )
872
    }
873
}
874

            
875
#[cfg(feature = "parser")]
876
#[derive(Clone, PartialEq)]
877
pub enum StyleTextIndentParseError<'a> {
878
    PixelValue(CssPixelValueParseError<'a>),
879
}
880
#[cfg(feature = "parser")]
881
impl_debug_as_display!(StyleTextIndentParseError<'a>);
882
#[cfg(feature = "parser")]
883
impl_display! { StyleTextIndentParseError<'a>, {
884
    PixelValue(e) => format!("Invalid text-indent value: {}", e),
885
}}
886
#[cfg(feature = "parser")]
887
impl_from!(
888
    CssPixelValueParseError<'a>,
889
    StyleTextIndentParseError::PixelValue
890
);
891

            
892
#[cfg(feature = "parser")]
893
#[derive(Debug, Clone, PartialEq)]
894
#[repr(C, u8)]
895
pub enum StyleTextIndentParseErrorOwned {
896
    PixelValue(CssPixelValueParseErrorOwned),
897
}
898

            
899
#[cfg(feature = "parser")]
900
impl<'a> StyleTextIndentParseError<'a> {
901
    pub fn to_contained(&self) -> StyleTextIndentParseErrorOwned {
902
        match self {
903
            Self::PixelValue(e) => StyleTextIndentParseErrorOwned::PixelValue(e.to_contained()),
904
        }
905
    }
906
}
907

            
908
#[cfg(feature = "parser")]
909
impl StyleTextIndentParseErrorOwned {
910
    pub fn to_shared<'a>(&'a self) -> StyleTextIndentParseError<'a> {
911
        match self {
912
            Self::PixelValue(e) => StyleTextIndentParseError::PixelValue(e.to_shared()),
913
        }
914
    }
915
}
916

            
917
#[cfg(feature = "parser")]
918
pub fn parse_style_text_indent(input: &str) -> Result<StyleTextIndent, StyleTextIndentParseError<'_>> {
919
    let mut each_line = false;
920
    let mut hanging = false;
921
    let mut pixel_part: Option<&str> = None;
922

            
923
    for token in input.split_whitespace() {
924
        match token {
925
            "each-line" => each_line = true,
926
            "hanging" => hanging = true,
927
            _ => {
928
                pixel_part = Some(token);
929
            }
930
        }
931
    }
932

            
933
    let pixel_str = pixel_part.unwrap_or("0px");
934

            
935
    crate::props::basic::pixel::parse_pixel_value(pixel_str)
936
        .map(|inner| StyleTextIndent { inner, each_line, hanging })
937
        .map_err(StyleTextIndentParseError::PixelValue)
938
}
939

            
940
/// initial-letter property for drop caps
941
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
942
#[repr(C)]
943
pub struct StyleInitialLetter {
944
    pub size: u32,
945
    pub sink: crate::corety::OptionU32,
946
}
947

            
948
impl FormatAsRustCode for StyleInitialLetter {
949
    fn format_as_rust_code(&self, _tabs: usize) -> String {
950
        format!("{:?}", self)
951
    }
952
}
953

            
954
impl PrintAsCssValue for StyleInitialLetter {
955
    fn print_as_css_value(&self) -> String {
956
        if let crate::corety::OptionU32::Some(sink) = self.sink {
957
            format!("{} {}", self.size, sink)
958
        } else {
959
            format!("{}", self.size)
960
        }
961
    }
962
}
963

            
964
#[cfg(feature = "parser")]
965
#[derive(Clone, PartialEq)]
966
pub enum StyleInitialLetterParseError<'a> {
967
    InvalidFormat(&'a str),
968
    InvalidSize(&'a str),
969
    InvalidSink(&'a str),
970
}
971
#[cfg(feature = "parser")]
972
impl_debug_as_display!(StyleInitialLetterParseError<'a>);
973
#[cfg(feature = "parser")]
974
impl_display! { StyleInitialLetterParseError<'a>, {
975
    InvalidFormat(e) => format!("Invalid initial-letter format: {}", e),
976
    InvalidSize(e) => format!("Invalid initial-letter size: {}", e),
977
    InvalidSink(e) => format!("Invalid initial-letter sink: {}", e),
978
}}
979

            
980
#[cfg(feature = "parser")]
981
#[derive(Debug, Clone, PartialEq)]
982
#[repr(C, u8)]
983
pub enum StyleInitialLetterParseErrorOwned {
984
    InvalidFormat(AzString),
985
    InvalidSize(AzString),
986
    InvalidSink(AzString),
987
}
988

            
989
#[cfg(feature = "parser")]
990
impl<'a> StyleInitialLetterParseError<'a> {
991
    pub fn to_contained(&self) -> StyleInitialLetterParseErrorOwned {
992
        match self {
993
            Self::InvalidFormat(s) => {
994
                StyleInitialLetterParseErrorOwned::InvalidFormat(s.to_string().into())
995
            }
996
            Self::InvalidSize(s) => StyleInitialLetterParseErrorOwned::InvalidSize(s.to_string().into()),
997
            Self::InvalidSink(s) => StyleInitialLetterParseErrorOwned::InvalidSink(s.to_string().into()),
998
        }
999
    }
}
#[cfg(feature = "parser")]
impl StyleInitialLetterParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleInitialLetterParseError<'a> {
        match self {
            Self::InvalidFormat(s) => StyleInitialLetterParseError::InvalidFormat(s.as_str()),
            Self::InvalidSize(s) => StyleInitialLetterParseError::InvalidSize(s.as_str()),
            Self::InvalidSink(s) => StyleInitialLetterParseError::InvalidSink(s.as_str()),
        }
    }
}
#[cfg(feature = "parser")]
impl From<StyleInitialLetterParseError<'_>> for StyleInitialLetterParseErrorOwned {
    fn from(e: StyleInitialLetterParseError) -> Self {
        match e {
            StyleInitialLetterParseError::InvalidFormat(s) => {
                StyleInitialLetterParseErrorOwned::InvalidFormat(s.to_string().into())
            }
            StyleInitialLetterParseError::InvalidSize(s) => {
                StyleInitialLetterParseErrorOwned::InvalidSize(s.to_string().into())
            }
            StyleInitialLetterParseError::InvalidSink(s) => {
                StyleInitialLetterParseErrorOwned::InvalidSink(s.to_string().into())
            }
        }
    }
}
#[cfg(feature = "parser")]
impl_display! { StyleInitialLetterParseErrorOwned, {
    InvalidFormat(e) => format!("Invalid initial-letter format: {}", e),
    InvalidSize(e) => format!("Invalid initial-letter size: {}", e),
    InvalidSink(e) => format!("Invalid initial-letter sink: {}", e),
}}
#[cfg(feature = "parser")]
pub fn parse_style_initial_letter<'a>(
    input: &'a str,
) -> Result<StyleInitialLetter, StyleInitialLetterParseError<'a>> {
    let input = input.trim();
    let parts: Vec<&str> = input.split_whitespace().collect();
    if parts.is_empty() {
        return Err(StyleInitialLetterParseError::InvalidFormat(input));
    }
    // Parse size (required)
    let size = parts[0]
        .parse::<u32>()
        .map_err(|_| StyleInitialLetterParseError::InvalidSize(parts[0]))?;
    if size == 0 {
        return Err(StyleInitialLetterParseError::InvalidSize(parts[0]));
    }
    // Parse sink (optional)
    let sink = if parts.len() > 1 {
        crate::corety::OptionU32::Some(
            parts[1]
                .parse::<u32>()
                .map_err(|_| StyleInitialLetterParseError::InvalidSink(parts[1]))?,
        )
    } else {
        crate::corety::OptionU32::None
    };
    Ok(StyleInitialLetter { size, sink })
}
/// line-clamp property for limiting visible lines
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct StyleLineClamp {
    pub max_lines: usize,
}
impl FormatAsRustCode for StyleLineClamp {
    fn format_as_rust_code(&self, _tabs: usize) -> String {
        format!("{:?}", self)
    }
}
impl PrintAsCssValue for StyleLineClamp {
    fn print_as_css_value(&self) -> String {
        format!("{}", self.max_lines)
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleLineClampParseError<'a> {
    InvalidValue(&'a str),
    ZeroValue,
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleLineClampParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleLineClampParseError<'a>, {
    InvalidValue(e) => format!("Invalid line-clamp value: {}", e),
    ZeroValue => format!("line-clamp cannot be zero"),
}}
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleLineClampParseErrorOwned {
    InvalidValue(AzString),
    ZeroValue,
}
#[cfg(feature = "parser")]
impl<'a> StyleLineClampParseError<'a> {
    pub fn to_contained(&self) -> StyleLineClampParseErrorOwned {
        match self {
            Self::InvalidValue(s) => StyleLineClampParseErrorOwned::InvalidValue(s.to_string().into()),
            Self::ZeroValue => StyleLineClampParseErrorOwned::ZeroValue,
        }
    }
}
#[cfg(feature = "parser")]
impl StyleLineClampParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleLineClampParseError<'a> {
        match self {
            Self::InvalidValue(s) => StyleLineClampParseError::InvalidValue(s.as_str()),
            Self::ZeroValue => StyleLineClampParseError::ZeroValue,
        }
    }
}
#[cfg(feature = "parser")]
impl From<StyleLineClampParseError<'_>> for StyleLineClampParseErrorOwned {
    fn from(e: StyleLineClampParseError) -> Self {
        e.to_contained()
    }
}
#[cfg(feature = "parser")]
impl_display! { StyleLineClampParseErrorOwned, {
    InvalidValue(e) => format!("Invalid line-clamp value: {}", e),
    ZeroValue => format!("line-clamp cannot be zero"),
}}
#[cfg(feature = "parser")]
pub fn parse_style_line_clamp<'a>(
    input: &'a str,
) -> Result<StyleLineClamp, StyleLineClampParseError<'a>> {
    let input = input.trim();
    let max_lines = input
        .parse::<usize>()
        .map_err(|_| StyleLineClampParseError::InvalidValue(input))?;
    if max_lines == 0 {
        return Err(StyleLineClampParseError::ZeroValue);
    }
    Ok(StyleLineClamp { max_lines })
}
/// hanging-punctuation property for hanging punctuation marks
///
/// CSS Text 3 §8: `none | [ first || [ force-end | allow-end ] || last ]`
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
#[derive(Default)]
pub struct StyleHangingPunctuation {
    pub first: bool,
    pub force_end: bool,
    pub allow_end: bool,
    pub last: bool,
}
impl StyleHangingPunctuation {
    pub fn is_enabled(&self) -> bool {
        self.first || self.force_end || self.allow_end || self.last
    }
}
impl FormatAsRustCode for StyleHangingPunctuation {
    fn format_as_rust_code(&self, _tabs: usize) -> String {
        format!("{:?}", self)
    }
}
impl PrintAsCssValue for StyleHangingPunctuation {
    fn print_as_css_value(&self) -> String {
        if !self.is_enabled() {
            return "none".to_string();
        }
        let mut parts = alloc::vec::Vec::new();
        if self.first { parts.push("first"); }
        if self.force_end { parts.push("force-end"); }
        if self.allow_end { parts.push("allow-end"); }
        if self.last { parts.push("last"); }
        parts.join(" ")
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleHangingPunctuationParseError<'a> {
    InvalidValue(&'a str),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleHangingPunctuationParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleHangingPunctuationParseError<'a>, {
    InvalidValue(e) => format!("Invalid hanging-punctuation value: {}", e),
}}
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleHangingPunctuationParseErrorOwned {
    InvalidValue(AzString),
}
#[cfg(feature = "parser")]
impl<'a> StyleHangingPunctuationParseError<'a> {
    pub fn to_contained(&self) -> StyleHangingPunctuationParseErrorOwned {
        match self {
            Self::InvalidValue(s) => {
                StyleHangingPunctuationParseErrorOwned::InvalidValue(s.to_string().into())
            }
        }
    }
}
#[cfg(feature = "parser")]
impl StyleHangingPunctuationParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleHangingPunctuationParseError<'a> {
        match self {
            Self::InvalidValue(s) => StyleHangingPunctuationParseError::InvalidValue(s.as_str()),
        }
    }
}
#[cfg(feature = "parser")]
impl From<StyleHangingPunctuationParseError<'_>> for StyleHangingPunctuationParseErrorOwned {
    fn from(e: StyleHangingPunctuationParseError) -> Self {
        e.to_contained()
    }
}
#[cfg(feature = "parser")]
impl_display! { StyleHangingPunctuationParseErrorOwned, {
    InvalidValue(e) => format!("Invalid hanging-punctuation value: {}", e),
}}
#[cfg(feature = "parser")]
pub fn parse_style_hanging_punctuation<'a>(
    input: &'a str,
) -> Result<StyleHangingPunctuation, StyleHangingPunctuationParseError<'a>> {
    let input = input.trim();
    if input.eq_ignore_ascii_case("none") {
        return Ok(StyleHangingPunctuation::default());
    }
    let mut first = false;
    let mut force_end = false;
    let mut allow_end = false;
    let mut last = false;
    for token in input.split_whitespace() {
        match token.to_lowercase().as_str() {
            "first" => first = true,
            "force-end" => force_end = true,
            "allow-end" => allow_end = true,
            "last" => last = true,
            _ => return Err(StyleHangingPunctuationParseError::InvalidValue(input)),
        }
    }
    if force_end && allow_end {
        return Err(StyleHangingPunctuationParseError::InvalidValue(input));
    }
    Ok(StyleHangingPunctuation { first, force_end, allow_end, last })
}
/// text-combine-upright property for combining horizontal text in vertical layout
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, u8)]
#[derive(Default)]
pub enum StyleTextCombineUpright {
    #[default]
    None,
    All,
    Digits(u8),
}
impl FormatAsRustCode for StyleTextCombineUpright {
    fn format_as_rust_code(&self, _tabs: usize) -> String {
        format!("{:?}", self)
    }
}
impl PrintAsCssValue for StyleTextCombineUpright {
    fn print_as_css_value(&self) -> String {
        match self {
            Self::None => "none".to_string(),
            Self::All => "all".to_string(),
            Self::Digits(n) => format!("digits {}", n),
        }
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleTextCombineUprightParseError<'a> {
    InvalidValue(&'a str),
    InvalidDigits(&'a str),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleTextCombineUprightParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleTextCombineUprightParseError<'a>, {
    InvalidValue(e) => format!("Invalid text-combine-upright value: {}", e),
    InvalidDigits(e) => format!("Invalid text-combine-upright digits: {}", e),
}}
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleTextCombineUprightParseErrorOwned {
    InvalidValue(AzString),
    InvalidDigits(AzString),
}
#[cfg(feature = "parser")]
impl<'a> StyleTextCombineUprightParseError<'a> {
    pub fn to_contained(&self) -> StyleTextCombineUprightParseErrorOwned {
        match self {
            Self::InvalidValue(s) => {
                StyleTextCombineUprightParseErrorOwned::InvalidValue(s.to_string().into())
            }
            Self::InvalidDigits(s) => {
                StyleTextCombineUprightParseErrorOwned::InvalidDigits(s.to_string().into())
            }
        }
    }
}
#[cfg(feature = "parser")]
impl StyleTextCombineUprightParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleTextCombineUprightParseError<'a> {
        match self {
            Self::InvalidValue(s) => StyleTextCombineUprightParseError::InvalidValue(s.as_str()),
            Self::InvalidDigits(s) => StyleTextCombineUprightParseError::InvalidDigits(s.as_str()),
        }
    }
}
#[cfg(feature = "parser")]
impl From<StyleTextCombineUprightParseError<'_>> for StyleTextCombineUprightParseErrorOwned {
    fn from(e: StyleTextCombineUprightParseError) -> Self {
        e.to_contained()
    }
}
#[cfg(feature = "parser")]
impl_display! { StyleTextCombineUprightParseErrorOwned, {
    InvalidValue(e) => format!("Invalid text-combine-upright value: {}", e),
    InvalidDigits(e) => format!("Invalid text-combine-upright digits: {}", e),
}}
#[cfg(feature = "parser")]
pub fn parse_style_text_combine_upright<'a>(
    input: &'a str,
) -> Result<StyleTextCombineUpright, StyleTextCombineUprightParseError<'a>> {
    let trimmed = input.trim();
    if trimmed.eq_ignore_ascii_case("none") {
        Ok(StyleTextCombineUpright::None)
    } else if trimmed.eq_ignore_ascii_case("all") {
        Ok(StyleTextCombineUpright::All)
    } else if trimmed.starts_with("digits") {
        let parts: Vec<&str> = trimmed.split_whitespace().collect();
        if parts.len() == 2 {
            let n = parts[1]
                .parse::<u8>()
                .map_err(|_| StyleTextCombineUprightParseError::InvalidDigits(input))?;
            if (2..=4).contains(&n) {
                Ok(StyleTextCombineUpright::Digits(n))
            } else {
                Err(StyleTextCombineUprightParseError::InvalidDigits(input))
            }
        } else {
            // Default to "digits 2"
            Ok(StyleTextCombineUpright::Digits(2))
        }
    } else {
        Err(StyleTextCombineUprightParseError::InvalidValue(input))
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleWordSpacingParseError<'a> {
    PixelValue(CssPixelValueParseError<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleWordSpacingParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleWordSpacingParseError<'a>, {
    PixelValue(e) => format!("Invalid word-spacing value: {}", e),
}}
#[cfg(feature = "parser")]
impl_from!(
    CssPixelValueParseError<'a>,
    StyleWordSpacingParseError::PixelValue
);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleWordSpacingParseErrorOwned {
    PixelValue(CssPixelValueParseErrorOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleWordSpacingParseError<'a> {
    pub fn to_contained(&self) -> StyleWordSpacingParseErrorOwned {
        match self {
            Self::PixelValue(e) => StyleWordSpacingParseErrorOwned::PixelValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleWordSpacingParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleWordSpacingParseError<'a> {
        match self {
            Self::PixelValue(e) => StyleWordSpacingParseError::PixelValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
1
pub fn parse_style_word_spacing(
1
    input: &str,
1
) -> Result<StyleWordSpacing, StyleWordSpacingParseError<'_>> {
1
    crate::props::basic::pixel::parse_pixel_value(input)
1
        .map(|inner| StyleWordSpacing { inner })
1
        .map_err(StyleWordSpacingParseError::PixelValue)
1
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleLineHeightParseError {
    Percentage(PercentageParseError),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleLineHeightParseError);
#[cfg(feature = "parser")]
impl_display! { StyleLineHeightParseError, {
    Percentage(e) => format!("Invalid line-height value: {}", e),
}}
#[cfg(feature = "parser")]
impl_from!(PercentageParseError, StyleLineHeightParseError::Percentage);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
pub enum StyleLineHeightParseErrorOwned {
    Percentage(PercentageParseErrorOwned),
}
#[cfg(feature = "parser")]
impl StyleLineHeightParseError {
    pub fn to_contained(&self) -> StyleLineHeightParseErrorOwned {
        match self {
            Self::Percentage(e) => StyleLineHeightParseErrorOwned::Percentage(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleLineHeightParseErrorOwned {
    pub fn to_shared(&self) -> StyleLineHeightParseError {
        match self {
            Self::Percentage(e) => StyleLineHeightParseError::Percentage(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
41
pub fn parse_style_line_height(input: &str) -> Result<StyleLineHeight, StyleLineHeightParseError> {
    // Try <number> or <percentage> first (multiplier of font-size)
41
    if let Ok(inner) = crate::props::basic::length::parse_percentage_value(input) {
21
        return Ok(StyleLineHeight { inner });
20
    }
    // Try <length> (e.g., "50px") — store as NEGATIVE PercentageValue to signal absolute px.
    // Convention: negative normalized() = absolute pixel value (CSS line-height can't be negative).
    // Resolved at layout time in fc.rs where font_size is known.
20
    if let Ok(px) = crate::props::basic::pixel::parse_pixel_value(input) {
20
        if px.metric == crate::props::basic::length::SizeMetric::Px {
20
            let px_val = px.number.get();
20
            return Ok(StyleLineHeight {
20
                inner: crate::props::basic::length::PercentageValue::new(-px_val * 100.0),
20
            });
        }
    }
    Err(StyleLineHeightParseError::Percentage(
        crate::props::basic::length::PercentageParseError::InvalidUnit("".to_string().into()),
    ))
41
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleTabSizeParseError<'a> {
    PixelValue(CssPixelValueParseError<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleTabSizeParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleTabSizeParseError<'a>, {
    PixelValue(e) => format!("Invalid tab-size value: {}", e),
}}
#[cfg(feature = "parser")]
impl_from!(
    CssPixelValueParseError<'a>,
    StyleTabSizeParseError::PixelValue
);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleTabSizeParseErrorOwned {
    PixelValue(CssPixelValueParseErrorOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleTabSizeParseError<'a> {
    pub fn to_contained(&self) -> StyleTabSizeParseErrorOwned {
        match self {
            Self::PixelValue(e) => StyleTabSizeParseErrorOwned::PixelValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleTabSizeParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleTabSizeParseError<'a> {
        match self {
            Self::PixelValue(e) => StyleTabSizeParseError::PixelValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
2
pub fn parse_style_tab_size(input: &str) -> Result<StyleTabSize, StyleTabSizeParseError<'_>> {
2
    if let Ok(number) = input.trim().parse::<f32>() {
1
        Ok(StyleTabSize {
1
            inner: PixelValue::em(number),
1
        })
    } else {
1
        crate::props::basic::pixel::parse_pixel_value(input)
1
            .map(|v| StyleTabSize { inner: v })
1
            .map_err(StyleTabSizeParseError::PixelValue)
    }
2
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleWhiteSpaceParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleWhiteSpaceParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleWhiteSpaceParseError<'a>, {
    InvalidValue(e) => format!("Invalid white-space value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleWhiteSpaceParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleWhiteSpaceParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleWhiteSpaceParseError<'a> {
    pub fn to_contained(&self) -> StyleWhiteSpaceParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleWhiteSpaceParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleWhiteSpaceParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleWhiteSpaceParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleWhiteSpaceParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
718
pub fn parse_style_white_space(input: &str) -> Result<StyleWhiteSpace, StyleWhiteSpaceParseError<'_>> {
718
    match input.trim() {
718
        "normal" => Ok(StyleWhiteSpace::Normal),
465
        "pre" => Ok(StyleWhiteSpace::Pre),
254
        "nowrap" | "no-wrap" => Ok(StyleWhiteSpace::Nowrap),
169
        "pre-wrap" => Ok(StyleWhiteSpace::PreWrap),
84
        "pre-line" => Ok(StyleWhiteSpace::PreLine),
        "break-spaces" => Ok(StyleWhiteSpace::BreakSpaces),
        other => Err(StyleWhiteSpaceParseError::InvalidValue(InvalidValueErr(
            other,
        ))),
    }
718
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleHyphensParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleHyphensParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleHyphensParseError<'a>, {
    InvalidValue(e) => format!("Invalid hyphens value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleHyphensParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleHyphensParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleHyphensParseError<'a> {
    pub fn to_contained(&self) -> StyleHyphensParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleHyphensParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleHyphensParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleHyphensParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleHyphensParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_hyphens(input: &str) -> Result<StyleHyphens, StyleHyphensParseError<'_>> {
    match input.trim() {
        "none" => Ok(StyleHyphens::None),
        "manual" => Ok(StyleHyphens::Manual),
        "auto" => Ok(StyleHyphens::Auto),
        other => Err(StyleHyphensParseError::InvalidValue(InvalidValueErr(other))),
    }
}
// -- StyleLineBreak parse --
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleLineBreakParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleLineBreakParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleLineBreakParseError<'a>, {
    InvalidValue(e) => format!("Invalid line-break value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleLineBreakParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleLineBreakParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleLineBreakParseError<'a> {
    pub fn to_contained(&self) -> StyleLineBreakParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleLineBreakParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleLineBreakParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleLineBreakParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleLineBreakParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_line_break(input: &str) -> Result<StyleLineBreak, StyleLineBreakParseError<'_>> {
    match input.trim() {
        "auto" => Ok(StyleLineBreak::Auto),
        "loose" => Ok(StyleLineBreak::Loose),
        "normal" => Ok(StyleLineBreak::Normal),
        "strict" => Ok(StyleLineBreak::Strict),
        "anywhere" => Ok(StyleLineBreak::Anywhere),
        other => Err(StyleLineBreakParseError::InvalidValue(InvalidValueErr(other))),
    }
}
// -- StyleWordBreak parse --
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleWordBreakParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleWordBreakParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleWordBreakParseError<'a>, {
    InvalidValue(e) => format!("Invalid word-break value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleWordBreakParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleWordBreakParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleWordBreakParseError<'a> {
    pub fn to_contained(&self) -> StyleWordBreakParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleWordBreakParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleWordBreakParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleWordBreakParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleWordBreakParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_word_break(input: &str) -> Result<StyleWordBreak, StyleWordBreakParseError<'_>> {
    match input.trim() {
        "normal" => Ok(StyleWordBreak::Normal),
        "break-all" => Ok(StyleWordBreak::BreakAll),
        "keep-all" => Ok(StyleWordBreak::KeepAll),
        "break-word" => Ok(StyleWordBreak::BreakWord),
        other => Err(StyleWordBreakParseError::InvalidValue(InvalidValueErr(other))),
    }
}
// -- StyleOverflowWrap parse --
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleOverflowWrapParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleOverflowWrapParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleOverflowWrapParseError<'a>, {
    InvalidValue(e) => format!("Invalid overflow-wrap value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleOverflowWrapParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleOverflowWrapParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleOverflowWrapParseError<'a> {
    pub fn to_contained(&self) -> StyleOverflowWrapParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleOverflowWrapParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleOverflowWrapParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleOverflowWrapParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleOverflowWrapParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
42
pub fn parse_style_overflow_wrap(input: &str) -> Result<StyleOverflowWrap, StyleOverflowWrapParseError<'_>> {
42
    match input.trim() {
42
        "normal" => Ok(StyleOverflowWrap::Normal),
42
        "anywhere" => Ok(StyleOverflowWrap::Anywhere),
42
        "break-word" => Ok(StyleOverflowWrap::BreakWord),
        other => Err(StyleOverflowWrapParseError::InvalidValue(InvalidValueErr(other))),
    }
42
}
// -- StyleTextAlignLast parse --
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleTextAlignLastParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleTextAlignLastParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleTextAlignLastParseError<'a>, {
    InvalidValue(e) => format!("Invalid text-align-last value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleTextAlignLastParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleTextAlignLastParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleTextAlignLastParseError<'a> {
    pub fn to_contained(&self) -> StyleTextAlignLastParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleTextAlignLastParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleTextAlignLastParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleTextAlignLastParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleTextAlignLastParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_text_align_last(input: &str) -> Result<StyleTextAlignLast, StyleTextAlignLastParseError<'_>> {
    match input.trim() {
        "auto" => Ok(StyleTextAlignLast::Auto),
        "start" => Ok(StyleTextAlignLast::Start),
        "end" => Ok(StyleTextAlignLast::End),
        "left" => Ok(StyleTextAlignLast::Left),
        "right" => Ok(StyleTextAlignLast::Right),
        "center" => Ok(StyleTextAlignLast::Center),
        "justify" => Ok(StyleTextAlignLast::Justify),
        other => Err(StyleTextAlignLastParseError::InvalidValue(InvalidValueErr(other))),
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleDirectionParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleDirectionParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleDirectionParseError<'a>, {
    InvalidValue(e) => format!("Invalid direction value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleDirectionParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleDirectionParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleDirectionParseError<'a> {
    pub fn to_contained(&self) -> StyleDirectionParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleDirectionParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleDirectionParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleDirectionParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleDirectionParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_direction(input: &str) -> Result<StyleDirection, StyleDirectionParseError<'_>> {
    match input.trim() {
        "ltr" => Ok(StyleDirection::Ltr),
        "rtl" => Ok(StyleDirection::Rtl),
        other => Err(StyleDirectionParseError::InvalidValue(InvalidValueErr(
            other,
        ))),
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleUserSelectParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleUserSelectParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleUserSelectParseError<'a>, {
    InvalidValue(e) => format!("Invalid user-select value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleUserSelectParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleUserSelectParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleUserSelectParseError<'a> {
    pub fn to_contained(&self) -> StyleUserSelectParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleUserSelectParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleUserSelectParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleUserSelectParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleUserSelectParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_user_select(input: &str) -> Result<StyleUserSelect, StyleUserSelectParseError<'_>> {
    match input.trim() {
        "auto" => Ok(StyleUserSelect::Auto),
        "text" => Ok(StyleUserSelect::Text),
        "none" => Ok(StyleUserSelect::None),
        "all" => Ok(StyleUserSelect::All),
        other => Err(StyleUserSelectParseError::InvalidValue(InvalidValueErr(
            other,
        ))),
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleTextDecorationParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleTextDecorationParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleTextDecorationParseError<'a>, {
    InvalidValue(e) => format!("Invalid text-decoration value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(
    InvalidValueErr<'a>,
    StyleTextDecorationParseError::InvalidValue
);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleTextDecorationParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleTextDecorationParseError<'a> {
    pub fn to_contained(&self) -> StyleTextDecorationParseErrorOwned {
        match self {
            Self::InvalidValue(e) => {
                StyleTextDecorationParseErrorOwned::InvalidValue(e.to_contained())
            }
        }
    }
}
#[cfg(feature = "parser")]
impl StyleTextDecorationParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleTextDecorationParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleTextDecorationParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_text_decoration(
    input: &str,
) -> Result<StyleTextDecoration, StyleTextDecorationParseError<'_>> {
    match input.trim() {
        "none" => Ok(StyleTextDecoration::None),
        "underline" => Ok(StyleTextDecoration::Underline),
        "overline" => Ok(StyleTextDecoration::Overline),
        "line-through" => Ok(StyleTextDecoration::LineThrough),
        other => Err(StyleTextDecorationParseError::InvalidValue(
            InvalidValueErr(other),
        )),
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleVerticalAlignParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleVerticalAlignParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleVerticalAlignParseError<'a>, {
    InvalidValue(e) => format!("Invalid vertical-align value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(
    InvalidValueErr<'a>,
    StyleVerticalAlignParseError::InvalidValue
);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleVerticalAlignParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleVerticalAlignParseError<'a> {
    pub fn to_contained(&self) -> StyleVerticalAlignParseErrorOwned {
        match self {
            Self::InvalidValue(e) => {
                StyleVerticalAlignParseErrorOwned::InvalidValue(e.to_contained())
            }
        }
    }
}
#[cfg(feature = "parser")]
impl StyleVerticalAlignParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleVerticalAlignParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleVerticalAlignParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_vertical_align(
    input: &str,
) -> Result<StyleVerticalAlign, StyleVerticalAlignParseError<'_>> {
    match input.trim() {
        "baseline" => Ok(StyleVerticalAlign::Baseline),
        "top" => Ok(StyleVerticalAlign::Top),
        "middle" => Ok(StyleVerticalAlign::Middle),
        "bottom" => Ok(StyleVerticalAlign::Bottom),
        "sub" => Ok(StyleVerticalAlign::Sub),
        "super" => Ok(StyleVerticalAlign::Superscript),
        "text-top" => Ok(StyleVerticalAlign::TextTop),
        "text-bottom" => Ok(StyleVerticalAlign::TextBottom),
        other if other.ends_with('%') => {
            let num_str = other.trim_end_matches('%').trim();
            match num_str.parse::<f32>() {
                Ok(val) => Ok(StyleVerticalAlign::Percentage(PercentageValue::new(val))),
                Err(_) => Err(StyleVerticalAlignParseError::InvalidValue(InvalidValueErr(other))),
            }
        }
        other => match crate::props::basic::pixel::parse_pixel_value(other) {
            Ok(pv) => Ok(StyleVerticalAlign::Length(pv)),
            Err(_) => Err(StyleVerticalAlignParseError::InvalidValue(InvalidValueErr(
                other,
            ))),
        },
    }
}
// --- CaretColor ---
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct CaretColor {
    pub inner: ColorU,
}
impl Default for CaretColor {
    fn default() -> Self {
        Self {
            inner: ColorU::BLACK,
        }
    }
}
impl PrintAsCssValue for CaretColor {
    fn print_as_css_value(&self) -> String {
        self.inner.to_hash()
    }
}
impl crate::format_rust_code::FormatAsRustCode for CaretColor {
    fn format_as_rust_code(&self, _tabs: usize) -> String {
        format!(
            "CaretColor {{ inner: {} }}",
            crate::format_rust_code::format_color_value(&self.inner)
        )
    }
}
#[cfg(feature = "parser")]
pub fn parse_caret_color(input: &str) -> Result<CaretColor, CssColorParseError<'_>> {
    parse_css_color(input).map(|inner| CaretColor { inner })
}
// --- CaretAnimationDuration ---
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct CaretAnimationDuration {
    pub inner: CssDuration,
}
impl Default for CaretAnimationDuration {
    fn default() -> Self {
        Self {
            inner: CssDuration { inner: 500 },
        } // Default 500ms blink time
    }
}
impl PrintAsCssValue for CaretAnimationDuration {
    fn print_as_css_value(&self) -> String {
        self.inner.print_as_css_value()
    }
}
impl crate::format_rust_code::FormatAsRustCode for CaretAnimationDuration {
    fn format_as_rust_code(&self, _tabs: usize) -> String {
        format!(
            "CaretAnimationDuration {{ inner: {} }}",
            self.inner.format_as_rust_code(0)
        )
    }
}
#[cfg(feature = "parser")]
pub fn parse_caret_animation_duration(
    input: &str,
) -> Result<CaretAnimationDuration, DurationParseError<'_>> {
    use crate::props::basic::parse_duration;
    parse_duration(input).map(|inner| CaretAnimationDuration { inner })
}
// --- CaretWidth ---
/// Width of the text cursor (caret) in pixels.
/// CSS doesn't have a standard property for this, so we use `-azul-caret-width`.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct CaretWidth {
    pub inner: PixelValue,
}
impl Default for CaretWidth {
    fn default() -> Self {
        Self {
            inner: PixelValue::px(2.0), // Default 2px caret width
        }
    }
}
impl PrintAsCssValue for CaretWidth {
    fn print_as_css_value(&self) -> String {
        self.inner.print_as_css_value()
    }
}
impl crate::format_rust_code::FormatAsRustCode for CaretWidth {
    fn format_as_rust_code(&self, _tabs: usize) -> String {
        format!(
            "CaretWidth {{ inner: {} }}",
            self.inner.format_as_rust_code(0)
        )
    }
}
#[cfg(feature = "parser")]
pub fn parse_caret_width(input: &str) -> Result<CaretWidth, CssPixelValueParseError<'_>> {
    use crate::props::basic::pixel::parse_pixel_value;
    parse_pixel_value(input).map(|inner| CaretWidth { inner })
}
// --- From implementations for CssProperty ---
impl From<StyleUserSelect> for crate::props::property::CssProperty {
    fn from(value: StyleUserSelect) -> Self {
        use crate::props::property::CssProperty;
        CssProperty::user_select(value)
    }
}
impl From<StyleTextDecoration> for crate::props::property::CssProperty {
    fn from(value: StyleTextDecoration) -> Self {
        use crate::props::property::CssProperty;
        CssProperty::text_decoration(value)
    }
}
#[cfg(all(test, feature = "parser"))]
mod tests {
    use super::*;
    use crate::props::basic::{color::ColorU, length::PercentageValue, pixel::PixelValue};
    #[test]
1
    fn test_parse_style_text_color() {
1
        assert_eq!(
1
            parse_style_text_color("red").unwrap().inner,
1
            ColorU::new_rgb(255, 0, 0)
        );
1
        assert_eq!(
1
            parse_style_text_color("#aabbcc").unwrap().inner,
1
            ColorU::new_rgb(170, 187, 204)
        );
1
        assert!(parse_style_text_color("not-a-color").is_err());
1
    }
    #[test]
1
    fn test_parse_style_text_align() {
1
        assert_eq!(
1
            parse_style_text_align("left").unwrap(),
            StyleTextAlign::Left
        );
1
        assert_eq!(
1
            parse_style_text_align("center").unwrap(),
            StyleTextAlign::Center
        );
1
        assert_eq!(
1
            parse_style_text_align("right").unwrap(),
            StyleTextAlign::Right
        );
1
        assert_eq!(
1
            parse_style_text_align("justify").unwrap(),
            StyleTextAlign::Justify
        );
1
        assert_eq!(
1
            parse_style_text_align("start").unwrap(),
            StyleTextAlign::Start
        );
1
        assert_eq!(parse_style_text_align("end").unwrap(), StyleTextAlign::End);
1
        assert!(parse_style_text_align("middle").is_err());
1
    }
    #[test]
1
    fn test_parse_spacing() {
1
        assert_eq!(
1
            parse_style_letter_spacing("2px").unwrap().inner,
1
            PixelValue::px(2.0)
        );
1
        assert_eq!(
1
            parse_style_letter_spacing("-0.1em").unwrap().inner,
1
            PixelValue::em(-0.1)
        );
1
        assert_eq!(
1
            parse_style_word_spacing("0.5em").unwrap().inner,
1
            PixelValue::em(0.5)
        );
1
    }
    #[test]
1
    fn test_parse_line_height() {
1
        assert_eq!(
1
            parse_style_line_height("1.5").unwrap().inner,
1
            PercentageValue::new(150.0)
        );
1
        assert_eq!(
1
            parse_style_line_height("120%").unwrap().inner,
1
            PercentageValue::new(120.0)
        );
        // px values stored as negative PercentageValue (convention: negative = absolute px)
1
        assert_eq!(
1
            parse_style_line_height("20px").unwrap().inner,
1
            PercentageValue::new(-20.0 * 100.0)
        );
1
    }
    #[test]
1
    fn test_parse_tab_size() {
        // Unitless number is treated as `em`
1
        assert_eq!(
1
            parse_style_tab_size("4").unwrap().inner,
1
            PixelValue::em(4.0)
        );
1
        assert_eq!(
1
            parse_style_tab_size("20px").unwrap().inner,
1
            PixelValue::px(20.0)
        );
1
    }
    #[test]
1
    fn test_parse_white_space() {
1
        assert_eq!(
1
            parse_style_white_space("normal").unwrap(),
            StyleWhiteSpace::Normal
        );
1
        assert_eq!(
1
            parse_style_white_space("pre").unwrap(),
            StyleWhiteSpace::Pre
        );
1
        assert_eq!(
1
            parse_style_white_space("nowrap").unwrap(),
            StyleWhiteSpace::Nowrap
        );
1
        assert_eq!(
1
            parse_style_white_space("pre-wrap").unwrap(),
            StyleWhiteSpace::PreWrap
        );
1
    }
}
// -- StyleUnicodeBidi --
/// Represents the `unicode-bidi` CSS property.
///
/// Controls how bidirectional text is handled within an element.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
#[derive(Default)]
pub enum StyleUnicodeBidi {
    /// No additional level of embedding
    #[default]
    Normal,
    /// Open an additional level of embedding
    Embed,
    /// Isolate the element from surrounding bidirectional text
    Isolate,
    /// Override the bidirectional algorithm for inline content
    BidiOverride,
    /// Combine isolation and override
    IsolateOverride,
    /// Determine paragraph direction from content without bidi algorithm
    Plaintext,
}
impl_option!(
    StyleUnicodeBidi,
    OptionStyleUnicodeBidi,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl PrintAsCssValue for StyleUnicodeBidi {
    fn print_as_css_value(&self) -> String {
        String::from(match self {
            StyleUnicodeBidi::Normal => "normal",
            StyleUnicodeBidi::Embed => "embed",
            StyleUnicodeBidi::Isolate => "isolate",
            StyleUnicodeBidi::BidiOverride => "bidi-override",
            StyleUnicodeBidi::IsolateOverride => "isolate-override",
            StyleUnicodeBidi::Plaintext => "plaintext",
        })
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleUnicodeBidiParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleUnicodeBidiParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleUnicodeBidiParseError<'a>, {
    InvalidValue(e) => format!("Invalid unicode-bidi value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleUnicodeBidiParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleUnicodeBidiParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleUnicodeBidiParseError<'a> {
    pub fn to_contained(&self) -> StyleUnicodeBidiParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleUnicodeBidiParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleUnicodeBidiParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleUnicodeBidiParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleUnicodeBidiParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_unicode_bidi(input: &str) -> Result<StyleUnicodeBidi, StyleUnicodeBidiParseError<'_>> {
    match input.trim() {
        "normal" => Ok(StyleUnicodeBidi::Normal),
        "embed" => Ok(StyleUnicodeBidi::Embed),
        "isolate" => Ok(StyleUnicodeBidi::Isolate),
        "bidi-override" => Ok(StyleUnicodeBidi::BidiOverride),
        "isolate-override" => Ok(StyleUnicodeBidi::IsolateOverride),
        "plaintext" => Ok(StyleUnicodeBidi::Plaintext),
        other => Err(StyleUnicodeBidiParseError::InvalidValue(InvalidValueErr(other))),
    }
}
// -- StyleTextBoxTrim --
/// Represents the `text-box-trim` CSS property.
///
/// Controls whether the leading is trimmed at the start/end of a block container.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
#[derive(Default)]
pub enum StyleTextBoxTrim {
    /// No trimming
    #[default]
    None,
    /// Trim leading over the first formatted line
    TrimStart,
    /// Trim leading under the last formatted line
    TrimEnd,
    /// Trim both start and end
    TrimBoth,
}
impl_option!(
    StyleTextBoxTrim,
    OptionStyleTextBoxTrim,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl PrintAsCssValue for StyleTextBoxTrim {
    fn print_as_css_value(&self) -> String {
        String::from(match self {
            StyleTextBoxTrim::None => "none",
            StyleTextBoxTrim::TrimStart => "trim-start",
            StyleTextBoxTrim::TrimEnd => "trim-end",
            StyleTextBoxTrim::TrimBoth => "trim-both",
        })
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleTextBoxTrimParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleTextBoxTrimParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleTextBoxTrimParseError<'a>, {
    InvalidValue(e) => format!("Invalid text-box-trim value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleTextBoxTrimParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleTextBoxTrimParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleTextBoxTrimParseError<'a> {
    pub fn to_contained(&self) -> StyleTextBoxTrimParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleTextBoxTrimParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleTextBoxTrimParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleTextBoxTrimParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleTextBoxTrimParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_text_box_trim(input: &str) -> Result<StyleTextBoxTrim, StyleTextBoxTrimParseError<'_>> {
    match input.trim() {
        "none" => Ok(StyleTextBoxTrim::None),
        "trim-start" => Ok(StyleTextBoxTrim::TrimStart),
        "trim-end" => Ok(StyleTextBoxTrim::TrimEnd),
        "trim-both" => Ok(StyleTextBoxTrim::TrimBoth),
        other => Err(StyleTextBoxTrimParseError::InvalidValue(InvalidValueErr(other))),
    }
}
// -- StyleTextBoxEdge --
/// Represents the `text-box-edge` CSS property.
///
/// Specifies the metrics used for determining the over/under edges of text
/// for the purposes of `text-box-trim`.
// +spec:writing-modes:daad86 - first value = over edge, second = under edge; single value applies to both (else "text" assumed for missing)
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
#[derive(Default)]
pub enum StyleTextBoxEdge {
    // +spec:line-height:cc03df - Auto uses line-fit-edge value, interpreting leading (initial) as text
    /// Use the line-fit-edge value (initial: text)
    #[default]
    Auto,
    /// Use the text-over / text-under baselines
    TextEdge,
    /// Use the cap-height baseline
    CapHeight,
    /// Use the x-height baseline
    ExHeight,
}
impl_option!(
    StyleTextBoxEdge,
    OptionStyleTextBoxEdge,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl PrintAsCssValue for StyleTextBoxEdge {
    fn print_as_css_value(&self) -> String {
        String::from(match self {
            StyleTextBoxEdge::Auto => "auto",
            StyleTextBoxEdge::TextEdge => "text",
            StyleTextBoxEdge::CapHeight => "cap",
            StyleTextBoxEdge::ExHeight => "ex",
        })
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleTextBoxEdgeParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleTextBoxEdgeParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleTextBoxEdgeParseError<'a>, {
    InvalidValue(e) => format!("Invalid text-box-edge value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleTextBoxEdgeParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleTextBoxEdgeParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleTextBoxEdgeParseError<'a> {
    pub fn to_contained(&self) -> StyleTextBoxEdgeParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleTextBoxEdgeParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleTextBoxEdgeParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleTextBoxEdgeParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleTextBoxEdgeParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_text_box_edge(input: &str) -> Result<StyleTextBoxEdge, StyleTextBoxEdgeParseError<'_>> {
    match input.trim() {
        "auto" => Ok(StyleTextBoxEdge::Auto),
        "text" => Ok(StyleTextBoxEdge::TextEdge),
        "cap" => Ok(StyleTextBoxEdge::CapHeight),
        "ex" => Ok(StyleTextBoxEdge::ExHeight),
        other => Err(StyleTextBoxEdgeParseError::InvalidValue(InvalidValueErr(other))),
    }
}
// -- StyleDominantBaseline --
/// Represents the `dominant-baseline` CSS property.
///
/// Specifies the dominant baseline used to align inline-level contents.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
#[derive(Default)]
pub enum StyleDominantBaseline {
    /// Use the dominant baseline of the parent
    #[default]
    Auto,
    /// Use the text-under baseline
    TextBottom,
    /// Use the alphabetic baseline
    Alphabetic,
    /// Use the ideographic baseline
    Ideographic,
    /// Use the middle baseline
    Middle,
    /// Use the central baseline
    Central,
    /// Use the mathematical baseline
    Mathematical,
    /// Use the hanging baseline
    Hanging,
    /// Use the text-over baseline
    TextTop,
}
impl_option!(
    StyleDominantBaseline,
    OptionStyleDominantBaseline,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl PrintAsCssValue for StyleDominantBaseline {
    fn print_as_css_value(&self) -> String {
        String::from(match self {
            StyleDominantBaseline::Auto => "auto",
            StyleDominantBaseline::TextBottom => "text-bottom",
            StyleDominantBaseline::Alphabetic => "alphabetic",
            StyleDominantBaseline::Ideographic => "ideographic",
            StyleDominantBaseline::Middle => "middle",
            StyleDominantBaseline::Central => "central",
            StyleDominantBaseline::Mathematical => "mathematical",
            StyleDominantBaseline::Hanging => "hanging",
            StyleDominantBaseline::TextTop => "text-top",
        })
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleDominantBaselineParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleDominantBaselineParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleDominantBaselineParseError<'a>, {
    InvalidValue(e) => format!("Invalid dominant-baseline value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleDominantBaselineParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleDominantBaselineParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleDominantBaselineParseError<'a> {
    pub fn to_contained(&self) -> StyleDominantBaselineParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleDominantBaselineParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleDominantBaselineParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleDominantBaselineParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleDominantBaselineParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_dominant_baseline(input: &str) -> Result<StyleDominantBaseline, StyleDominantBaselineParseError<'_>> {
    match input.trim() {
        "auto" => Ok(StyleDominantBaseline::Auto),
        "text-bottom" => Ok(StyleDominantBaseline::TextBottom),
        "alphabetic" => Ok(StyleDominantBaseline::Alphabetic),
        "ideographic" => Ok(StyleDominantBaseline::Ideographic),
        "middle" => Ok(StyleDominantBaseline::Middle),
        "central" => Ok(StyleDominantBaseline::Central),
        "mathematical" => Ok(StyleDominantBaseline::Mathematical),
        "hanging" => Ok(StyleDominantBaseline::Hanging),
        "text-top" => Ok(StyleDominantBaseline::TextTop),
        other => Err(StyleDominantBaselineParseError::InvalidValue(InvalidValueErr(other))),
    }
}
// -- StyleAlignmentBaseline --
// +spec:display-property:c90924 - alignment-baseline property: values, initial value, and applies-to per CSS Inline 3 §4.2.2
// +spec:font-metrics:fa4489 - alignment-baseline property: specifies box's alignment baseline used before post-alignment shift
// +spec:inline-block:939f05 - alignment-baseline property definition with all spec values (baseline, text-bottom, alphabetic, ideographic, middle, central, mathematical, text-top)
/// Represents the `alignment-baseline` CSS property.
///
/// Specifies which baseline of the element is aligned with the dominant baseline.
// +spec:writing-modes:cc8e70 - alignment-baseline values for inline baseline alignment
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
#[derive(Default)]
pub enum StyleAlignmentBaseline {
    /// Use the dominant baseline of the parent
    #[default]
    Baseline,
    /// Align to the text-under baseline
    TextBottom,
    /// Align to the alphabetic baseline
    Alphabetic,
    /// Align to the ideographic baseline
    Ideographic,
    /// Align to the middle baseline
    Middle,
    /// Align to the central baseline
    Central,
    /// Align to the mathematical baseline
    Mathematical,
    /// Align to the text-over baseline
    TextTop,
}
impl_option!(
    StyleAlignmentBaseline,
    OptionStyleAlignmentBaseline,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl PrintAsCssValue for StyleAlignmentBaseline {
    fn print_as_css_value(&self) -> String {
        String::from(match self {
            StyleAlignmentBaseline::Baseline => "baseline",
            StyleAlignmentBaseline::TextBottom => "text-bottom",
            StyleAlignmentBaseline::Alphabetic => "alphabetic",
            StyleAlignmentBaseline::Ideographic => "ideographic",
            StyleAlignmentBaseline::Middle => "middle",
            StyleAlignmentBaseline::Central => "central",
            StyleAlignmentBaseline::Mathematical => "mathematical",
            StyleAlignmentBaseline::TextTop => "text-top",
        })
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleAlignmentBaselineParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleAlignmentBaselineParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleAlignmentBaselineParseError<'a>, {
    InvalidValue(e) => format!("Invalid alignment-baseline value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleAlignmentBaselineParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleAlignmentBaselineParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleAlignmentBaselineParseError<'a> {
    pub fn to_contained(&self) -> StyleAlignmentBaselineParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleAlignmentBaselineParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleAlignmentBaselineParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleAlignmentBaselineParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleAlignmentBaselineParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_alignment_baseline(input: &str) -> Result<StyleAlignmentBaseline, StyleAlignmentBaselineParseError<'_>> {
    match input.trim() {
        "baseline" => Ok(StyleAlignmentBaseline::Baseline),
        "text-bottom" => Ok(StyleAlignmentBaseline::TextBottom),
        "alphabetic" => Ok(StyleAlignmentBaseline::Alphabetic),
        "ideographic" => Ok(StyleAlignmentBaseline::Ideographic),
        "middle" => Ok(StyleAlignmentBaseline::Middle),
        "central" => Ok(StyleAlignmentBaseline::Central),
        "mathematical" => Ok(StyleAlignmentBaseline::Mathematical),
        "text-top" => Ok(StyleAlignmentBaseline::TextTop),
        other => Err(StyleAlignmentBaselineParseError::InvalidValue(InvalidValueErr(other))),
    }
}
// -- StyleInitialLetterAlign --
/// Represents the `initial-letter-align` CSS property.
///
/// Specifies the alignment points used to align an initial letter.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
#[derive(Default)]
pub enum StyleInitialLetterAlign {
    /// Automatically determine alignment based on script
    #[default]
    Auto,
    /// Align to the alphabetic baseline
    Alphabetic,
    /// Align to the hanging baseline
    Hanging,
    /// Align to the ideographic baseline
    Ideographic,
}
impl_option!(
    StyleInitialLetterAlign,
    OptionStyleInitialLetterAlign,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl PrintAsCssValue for StyleInitialLetterAlign {
    fn print_as_css_value(&self) -> String {
        String::from(match self {
            StyleInitialLetterAlign::Auto => "auto",
            StyleInitialLetterAlign::Alphabetic => "alphabetic",
            StyleInitialLetterAlign::Hanging => "hanging",
            StyleInitialLetterAlign::Ideographic => "ideographic",
        })
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleInitialLetterAlignParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleInitialLetterAlignParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleInitialLetterAlignParseError<'a>, {
    InvalidValue(e) => format!("Invalid initial-letter-align value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleInitialLetterAlignParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleInitialLetterAlignParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleInitialLetterAlignParseError<'a> {
    pub fn to_contained(&self) -> StyleInitialLetterAlignParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleInitialLetterAlignParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleInitialLetterAlignParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleInitialLetterAlignParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleInitialLetterAlignParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_initial_letter_align(input: &str) -> Result<StyleInitialLetterAlign, StyleInitialLetterAlignParseError<'_>> {
    match input.trim() {
        "auto" => Ok(StyleInitialLetterAlign::Auto),
        "alphabetic" => Ok(StyleInitialLetterAlign::Alphabetic),
        "hanging" => Ok(StyleInitialLetterAlign::Hanging),
        "ideographic" => Ok(StyleInitialLetterAlign::Ideographic),
        other => Err(StyleInitialLetterAlignParseError::InvalidValue(InvalidValueErr(other))),
    }
}
// -- StyleInitialLetterWrap --
/// Represents the `initial-letter-wrap` CSS property.
///
/// Specifies how text adjacent to an initial letter wraps.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
#[derive(Default)]
pub enum StyleInitialLetterWrap {
    /// No special wrapping around the initial letter
    #[default]
    None,
    /// Wrap only the first line adjacent to the initial letter
    First,
    /// Wrap all lines adjacent to the initial letter
    All,
    /// Wrap using a grid-based layout
    Grid,
}
impl_option!(
    StyleInitialLetterWrap,
    OptionStyleInitialLetterWrap,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl PrintAsCssValue for StyleInitialLetterWrap {
    fn print_as_css_value(&self) -> String {
        String::from(match self {
            StyleInitialLetterWrap::None => "none",
            StyleInitialLetterWrap::First => "first",
            StyleInitialLetterWrap::All => "all",
            StyleInitialLetterWrap::Grid => "grid",
        })
    }
}
#[cfg(feature = "parser")]
#[derive(Clone, PartialEq)]
pub enum StyleInitialLetterWrapParseError<'a> {
    InvalidValue(InvalidValueErr<'a>),
}
#[cfg(feature = "parser")]
impl_debug_as_display!(StyleInitialLetterWrapParseError<'a>);
#[cfg(feature = "parser")]
impl_display! { StyleInitialLetterWrapParseError<'a>, {
    InvalidValue(e) => format!("Invalid initial-letter-wrap value: \"{}\"", e.0),
}}
#[cfg(feature = "parser")]
impl_from!(InvalidValueErr<'a>, StyleInitialLetterWrapParseError::InvalidValue);
#[cfg(feature = "parser")]
#[derive(Debug, Clone, PartialEq)]
#[repr(C, u8)]
pub enum StyleInitialLetterWrapParseErrorOwned {
    InvalidValue(InvalidValueErrOwned),
}
#[cfg(feature = "parser")]
impl<'a> StyleInitialLetterWrapParseError<'a> {
    pub fn to_contained(&self) -> StyleInitialLetterWrapParseErrorOwned {
        match self {
            Self::InvalidValue(e) => StyleInitialLetterWrapParseErrorOwned::InvalidValue(e.to_contained()),
        }
    }
}
#[cfg(feature = "parser")]
impl StyleInitialLetterWrapParseErrorOwned {
    pub fn to_shared<'a>(&'a self) -> StyleInitialLetterWrapParseError<'a> {
        match self {
            Self::InvalidValue(e) => StyleInitialLetterWrapParseError::InvalidValue(e.to_shared()),
        }
    }
}
#[cfg(feature = "parser")]
pub fn parse_style_initial_letter_wrap(input: &str) -> Result<StyleInitialLetterWrap, StyleInitialLetterWrapParseError<'_>> {
    match input.trim() {
        "none" => Ok(StyleInitialLetterWrap::None),
        "first" => Ok(StyleInitialLetterWrap::First),
        "all" => Ok(StyleInitialLetterWrap::All),
        "grid" => Ok(StyleInitialLetterWrap::Grid),
        other => Err(StyleInitialLetterWrapParseError::InvalidValue(InvalidValueErr(other))),
    }
}