1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use freya_engine::prelude::*;

use crate::{
    Parse,
    ParseError,
};

impl Parse for TextAlign {
    fn parse(value: &str) -> Result<Self, ParseError> {
        Ok(match value {
            "center" => TextAlign::Center,
            "justify" => TextAlign::Justify,
            "start" => TextAlign::Start,
            "end" => TextAlign::End,
            "left" => TextAlign::Left,
            "right" => TextAlign::Right,
            _ => TextAlign::default(),
        })
    }
}

impl Parse for Slant {
    fn parse(value: &str) -> Result<Self, ParseError> {
        Ok(match value {
            "upright" => Slant::Upright,
            "italic" => Slant::Italic,
            "oblique" => Slant::Oblique,
            _ => Slant::Upright,
        })
    }
}

impl Parse for Width {
    fn parse(value: &str) -> Result<Self, ParseError> {
        Ok(match value {
            "ultra-condensed" => Width::ULTRA_CONDENSED,
            "extra-condensed" => Width::EXTRA_CONDENSED,
            "condensed" => Width::CONDENSED,
            "semi-condensed" => Width::SEMI_CONDENSED,
            "normal" => Width::NORMAL,
            "semi-expanded" => Width::SEMI_EXPANDED,
            "expanded" => Width::EXPANDED,
            "extra-expanded" => Width::EXTRA_EXPANDED,
            "ultra-expanded" => Width::ULTRA_EXPANDED,
            _ => Width::NORMAL,
        })
    }
}

impl Parse for Weight {
    // NOTES:
    // This is mostly taken from the OpenType specification (https://learn.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass)
    // CSS has one deviation from this spec, which uses the value "950" for extra_black.
    // skia_safe also has an "invisible" weight smaller than the thin weight, which could fall under CSS's interpretation of OpenType's
    // version. In this case it would be font_weight: "50".
    fn parse(value: &str) -> Result<Self, ParseError> {
        Ok(match value {
            "invisible" => Weight::INVISIBLE,
            "thin" => Weight::THIN,
            "extra-light" => Weight::EXTRA_LIGHT,
            "light" => Weight::LIGHT,
            "normal" => Weight::NORMAL,
            "medium" => Weight::MEDIUM,
            "semi-bold" => Weight::SEMI_BOLD,
            "bold" => Weight::BOLD,
            "extra-bold" => Weight::EXTRA_BOLD,
            "black" => Weight::BLACK,
            "extra-black" => Weight::EXTRA_BLACK,
            "50" => Weight::INVISIBLE,
            "100" => Weight::THIN,
            "200" => Weight::EXTRA_LIGHT,
            "300" => Weight::LIGHT,
            "400" => Weight::NORMAL,
            "500" => Weight::MEDIUM,
            "600" => Weight::SEMI_BOLD,
            "700" => Weight::BOLD,
            "800" => Weight::EXTRA_BOLD,
            "900" => Weight::BLACK,
            "950" => Weight::EXTRA_BLACK,
            _ => Weight::NORMAL,
        })
    }
}

#[derive(Default, Clone, Debug, PartialEq)]
pub enum TextOverflow {
    #[default]
    Clip,
    Ellipsis,
    Custom(String),
}

impl TextOverflow {
    pub fn get_ellipsis(&self) -> Option<&str> {
        match self {
            Self::Clip => None,
            Self::Ellipsis => Some("..."),
            Self::Custom(custom) => Some(custom),
        }
    }

    pub fn pretty(&self) -> String {
        match self {
            TextOverflow::Clip => "clip".to_string(),
            TextOverflow::Ellipsis => "ellipsis".to_string(),
            TextOverflow::Custom(text_overflow) => text_overflow.to_string(),
        }
    }
}

impl Parse for TextOverflow {
    fn parse(value: &str) -> Result<Self, ParseError> {
        Ok(match value {
            "ellipsis" => TextOverflow::Ellipsis,
            "clip" => TextOverflow::Clip,
            value => TextOverflow::Custom(value.to_string()),
        })
    }
}