font_features.rs

  1use schemars::{
  2    schema::{InstanceType, Schema, SchemaObject, SingleOrVec},
  3    JsonSchema,
  4};
  5
  6macro_rules! create_definitions {
  7    ($($(#[$meta:meta])* ($name:ident, $idx:expr)),* $(,)?) => {
  8
  9        /// The OpenType features that can be configured for a given font.
 10        #[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
 11        pub struct FontFeatures {
 12            enabled: u64,
 13            disabled: u64,
 14        }
 15
 16        impl FontFeatures {
 17            $(
 18                /// Get the current value of the corresponding OpenType feature
 19                pub fn $name(&self) -> Option<bool> {
 20                    if (self.enabled & (1 << $idx)) != 0 {
 21                        Some(true)
 22                    } else if (self.disabled & (1 << $idx)) != 0 {
 23                        Some(false)
 24                    } else {
 25                        None
 26                    }
 27                }
 28            )*
 29
 30            /// Get the tag name list of the font OpenType features
 31            /// only enabled or disabled features are returned
 32            #[cfg(target_os = "windows")]
 33            pub fn tag_value_list(&self) -> Vec<(String, bool)> {
 34                let mut result = Vec::new();
 35                $(
 36                    {
 37                        let value = if (self.enabled & (1 << $idx)) != 0 {
 38                            Some(true)
 39                        } else if (self.disabled & (1 << $idx)) != 0 {
 40                            Some(false)
 41                        } else {
 42                            None
 43                        };
 44                        if let Some(enable) = value {
 45                            let tag_name = stringify!($name).to_owned();
 46                            result.push((tag_name, enable));
 47                        }
 48                    }
 49                )*
 50                result
 51            }
 52        }
 53
 54        impl std::fmt::Debug for FontFeatures {
 55            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 56                let mut debug = f.debug_struct("FontFeatures");
 57                $(
 58                    if let Some(value) = self.$name() {
 59                        debug.field(stringify!($name), &value);
 60                    };
 61                )*
 62                debug.finish()
 63            }
 64        }
 65
 66        impl<'de> serde::Deserialize<'de> for FontFeatures {
 67            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 68            where
 69                D: serde::Deserializer<'de>,
 70            {
 71                use serde::de::{MapAccess, Visitor};
 72                use std::fmt;
 73
 74                struct FontFeaturesVisitor;
 75
 76                impl<'de> Visitor<'de> for FontFeaturesVisitor {
 77                    type Value = FontFeatures;
 78
 79                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
 80                        formatter.write_str("a map of font features")
 81                    }
 82
 83                    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
 84                    where
 85                        M: MapAccess<'de>,
 86                    {
 87                        let mut enabled: u64 = 0;
 88                        let mut disabled: u64 = 0;
 89
 90                        while let Some((key, value)) = access.next_entry::<String, Option<bool>>()? {
 91                            let idx = match key.as_str() {
 92                                $(stringify!($name) => $idx,)*
 93                                _ => continue,
 94                            };
 95                            match value {
 96                                Some(true) => enabled |= 1 << idx,
 97                                Some(false) => disabled |= 1 << idx,
 98                                None => {}
 99                            };
100                        }
101                        Ok(FontFeatures { enabled, disabled })
102                    }
103                }
104
105                let features = deserializer.deserialize_map(FontFeaturesVisitor)?;
106                Ok(features)
107            }
108        }
109
110        impl serde::Serialize for FontFeatures {
111            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
112            where
113                S: serde::Serializer,
114            {
115                use serde::ser::SerializeMap;
116
117                let mut map = serializer.serialize_map(None)?;
118
119                $(
120                    {
121                        let feature = stringify!($name);
122                        if let Some(value) = self.$name() {
123                            map.serialize_entry(feature, &value)?;
124                        }
125                    }
126                )*
127
128                map.end()
129            }
130        }
131
132        impl JsonSchema for FontFeatures {
133            fn schema_name() -> String {
134                "FontFeatures".into()
135            }
136
137            fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> Schema {
138                let mut schema = SchemaObject::default();
139                let properties = &mut schema.object().properties;
140                let feature_schema = Schema::Object(SchemaObject {
141                    instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Boolean))),
142                    ..Default::default()
143                });
144
145                $(
146                    properties.insert(stringify!($name).to_owned(), feature_schema.clone());
147                )*
148
149                schema.into()
150            }
151        }
152    };
153}
154
155create_definitions!(
156    (calt, 0),
157    (case, 1),
158    (cpsp, 2),
159    (frac, 3),
160    (liga, 4),
161    (onum, 5),
162    (ordn, 6),
163    (pnum, 7),
164    (ss01, 8),
165    (ss02, 9),
166    (ss03, 10),
167    (ss04, 11),
168    (ss05, 12),
169    (ss06, 13),
170    (ss07, 14),
171    (ss08, 15),
172    (ss09, 16),
173    (ss10, 17),
174    (ss11, 18),
175    (ss12, 19),
176    (ss13, 20),
177    (ss14, 21),
178    (ss15, 22),
179    (ss16, 23),
180    (ss17, 24),
181    (ss18, 25),
182    (ss19, 26),
183    (ss20, 27),
184    (subs, 28),
185    (sups, 29),
186    (swsh, 30),
187    (titl, 31),
188    (tnum, 32),
189    (zero, 33),
190);