fonts.rs

  1use crate::{
  2    color::Color,
  3    json::{json, ToJson},
  4};
  5pub use font_kit::{
  6    metrics::Metrics,
  7    properties::{Properties, Stretch, Style, Weight},
  8};
  9use serde::{de, Deserialize};
 10use serde_json::Value;
 11
 12#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 13pub struct FontId(pub usize);
 14
 15pub type GlyphId = u32;
 16
 17#[derive(Clone, Debug, Default, PartialEq, Eq)]
 18pub struct TextStyle {
 19    pub color: Color,
 20    pub font_properties: Properties,
 21}
 22
 23#[allow(non_camel_case_types)]
 24#[derive(Deserialize)]
 25enum WeightJson {
 26    thin,
 27    extra_light,
 28    light,
 29    normal,
 30    medium,
 31    semibold,
 32    bold,
 33    extra_bold,
 34    black,
 35}
 36
 37#[derive(Deserialize)]
 38struct TextStyleJson {
 39    color: Color,
 40    weight: Option<WeightJson>,
 41    #[serde(default)]
 42    italic: bool,
 43}
 44
 45impl<'de> Deserialize<'de> for TextStyle {
 46    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 47    where
 48        D: serde::Deserializer<'de>,
 49    {
 50        let json = Value::deserialize(deserializer)?;
 51        if json.is_object() {
 52            let style_json: TextStyleJson =
 53                serde_json::from_value(json).map_err(de::Error::custom)?;
 54            Ok(style_json.into())
 55        } else {
 56            Ok(Self {
 57                color: serde_json::from_value(json).map_err(de::Error::custom)?,
 58                font_properties: Properties::new(),
 59            })
 60        }
 61    }
 62}
 63
 64impl From<Color> for TextStyle {
 65    fn from(color: Color) -> Self {
 66        Self {
 67            color,
 68            font_properties: Default::default(),
 69        }
 70    }
 71}
 72
 73impl ToJson for TextStyle {
 74    fn to_json(&self) -> Value {
 75        json!({
 76            "color": self.color.to_json(),
 77            "font_properties": self.font_properties.to_json(),
 78        })
 79    }
 80}
 81
 82impl Into<TextStyle> for TextStyleJson {
 83    fn into(self) -> TextStyle {
 84        let weight = match self.weight.unwrap_or(WeightJson::normal) {
 85            WeightJson::thin => Weight::THIN,
 86            WeightJson::extra_light => Weight::EXTRA_LIGHT,
 87            WeightJson::light => Weight::LIGHT,
 88            WeightJson::normal => Weight::NORMAL,
 89            WeightJson::medium => Weight::MEDIUM,
 90            WeightJson::semibold => Weight::SEMIBOLD,
 91            WeightJson::bold => Weight::BOLD,
 92            WeightJson::extra_bold => Weight::EXTRA_BOLD,
 93            WeightJson::black => Weight::BLACK,
 94        };
 95        let style = if self.italic {
 96            Style::Italic
 97        } else {
 98            Style::Normal
 99        };
100        TextStyle {
101            color: self.color,
102            font_properties: *Properties::new().weight(weight).style(style),
103        }
104    }
105}
106
107impl ToJson for Properties {
108    fn to_json(&self) -> crate::json::Value {
109        json!({
110            "style": self.style.to_json(),
111            "weight": self.weight.to_json(),
112            "stretch": self.stretch.to_json(),
113        })
114    }
115}
116
117impl ToJson for Style {
118    fn to_json(&self) -> crate::json::Value {
119        match self {
120            Style::Normal => json!("normal"),
121            Style::Italic => json!("italic"),
122            Style::Oblique => json!("oblique"),
123        }
124    }
125}
126
127impl ToJson for Weight {
128    fn to_json(&self) -> crate::json::Value {
129        if self.0 == Weight::THIN.0 {
130            json!("thin")
131        } else if self.0 == Weight::EXTRA_LIGHT.0 {
132            json!("extra light")
133        } else if self.0 == Weight::LIGHT.0 {
134            json!("light")
135        } else if self.0 == Weight::NORMAL.0 {
136            json!("normal")
137        } else if self.0 == Weight::MEDIUM.0 {
138            json!("medium")
139        } else if self.0 == Weight::SEMIBOLD.0 {
140            json!("semibold")
141        } else if self.0 == Weight::BOLD.0 {
142            json!("bold")
143        } else if self.0 == Weight::EXTRA_BOLD.0 {
144            json!("extra bold")
145        } else if self.0 == Weight::BLACK.0 {
146            json!("black")
147        } else {
148            json!(self.0)
149        }
150    }
151}
152
153impl ToJson for Stretch {
154    fn to_json(&self) -> serde_json::Value {
155        json!(self.0)
156    }
157}