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