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
use crate::Parse;
use skia_safe::{
    font_style::{Slant, Weight, Width},
    textlayout::TextAlign,
};

#[derive(Debug, PartialEq, Eq)]
pub struct ParseTextAlignError;

impl Parse for TextAlign {
    type Err = ParseTextAlignError;

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

#[derive(Debug, PartialEq, Eq)]
pub struct ParseSlantError;

impl Parse for Slant {
    type Err = ParseSlantError;

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

#[derive(Debug, PartialEq, Eq)]
pub struct ParseWidthError;

impl Parse for Width {
    type Err = ParseWidthError;

    fn parse(value: &str) -> Result<Self, Self::Err> {
        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,
        })
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct ParseWeightError;

impl Parse for Weight {
    type Err = ParseWeightError;

    // 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, Self::Err> {
        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,
        })
    }
}