1use std::{
4 collections::{HashMap, HashSet, hash_map},
5 fmt,
6 marker::PhantomData,
7 num::NonZeroU32,
8 ops,
9};
10
11use num_enum::FromPrimitive;
12
13#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
22pub struct FontFeatureName(pub [u8; 4]);
23impl FontFeatureName {
24 pub fn as_str(&self) -> &str {
26 std::str::from_utf8(&self.0).unwrap_or_default()
27 }
28}
29impl From<&'static [u8; 4]> for FontFeatureName {
30 fn from(name: &'static [u8; 4]) -> Self {
31 FontFeatureName(*name)
32 }
33}
34impl From<FontFeatureName> for ttf_parser::Tag {
35 fn from(value: FontFeatureName) -> Self {
36 ttf_parser::Tag::from_bytes(&value.0)
37 }
38}
39impl ops::Deref for FontFeatureName {
40 type Target = [u8; 4];
41
42 fn deref(&self) -> &Self::Target {
43 &self.0
44 }
45}
46impl fmt::Debug for FontFeatureName {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 if self.as_str().is_empty() {
49 write!(f, "{:?}", self.0)
50 } else {
51 write!(f, "{}", self.as_str())
52 }
53 }
54}
55impl fmt::Display for FontFeatureName {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 write!(f, "{self:?}")
58 }
59}
60
61pub const FEATURE_ENABLED: u32 = 1;
63pub const FEATURE_DISABLED: u32 = 0;
65
66type FontFeaturesMap = HashMap<FontFeatureName, u32>;
67
68#[derive(Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
70pub struct FontFeatures(FontFeaturesMap);
71impl FontFeatures {
72 pub fn new() -> FontFeatures {
74 FontFeatures::default()
75 }
76
77 pub fn builder() -> FontFeaturesBuilder {
79 FontFeaturesBuilder::default()
80 }
81
82 pub fn set_all(&mut self, other: &FontFeatures) -> Vec<(FontFeatureName, Option<u32>)> {
86 let mut prev = Vec::with_capacity(other.0.len());
87 for (&name, &state) in other.0.iter() {
88 prev.push((name, self.0.insert(name, state)));
89 }
90 prev
91 }
92
93 pub fn restore(&mut self, prev: Vec<(FontFeatureName, Option<u32>)>) {
95 for (name, state) in prev {
96 match state {
97 Some(state) => {
98 self.0.insert(name, state);
99 }
100 None => {
101 self.0.remove(&name);
102 }
103 }
104 }
105 }
106
107 pub fn feature(&mut self, name: FontFeatureName) -> FontFeature<'_> {
109 FontFeature(self.0.entry(name))
110 }
111
112 pub fn feature_set(&mut self, names: &'static [FontFeatureName]) -> FontFeatureSet<'_> {
118 assert!(names.len() >= 2);
119 FontFeatureSet {
120 features: &mut self.0,
121 names,
122 }
123 }
124
125 pub fn feature_exclusive_set<S: FontFeatureExclusiveSetState>(&mut self) -> FontFeatureExclusiveSet<'_, S> {
131 assert!(S::names().len() >= 2);
132 FontFeatureExclusiveSet {
133 features: &mut self.0,
134 _t: PhantomData,
135 }
136 }
137
138 pub fn feature_exclusive_sets<S: FontFeatureExclusiveSetsState>(&mut self) -> FontFeatureExclusiveSets<'_, S> {
145 assert!(S::names().len() >= 2);
146 FontFeatureExclusiveSets {
147 features: &mut self.0,
148 _t: PhantomData,
149 }
150 }
151
152 pub fn finalize(&self) -> RFontFeatures {
154 self.0
155 .iter()
156 .map(|(&n, &s)| rustybuzz::Feature::new(ttf_parser::Tag::from(n), s, 0..usize::MAX))
157 .collect()
158 }
159}
160impl fmt::Debug for FontFeatures {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 let mut map = f.debug_map();
163 for (name, state) in self.0.iter() {
164 map.entry(&name.as_str(), state);
165 }
166 map.finish()
167 }
168}
169
170pub type RFontFeatures = Vec<rustybuzz::Feature>;
174
175#[derive(Default)]
184pub struct FontFeaturesBuilder(FontFeatures);
185impl FontFeaturesBuilder {
186 pub fn build(self) -> FontFeatures {
188 self.0
189 }
190
191 pub fn feature(mut self, name: FontFeatureName, state: impl Into<FontFeatureState>) -> Self {
193 self.0.feature(name).set(state);
194 self
195 }
196
197 pub fn feature_set(mut self, names: &'static [FontFeatureName], state: impl Into<FontFeatureState>) -> Self {
203 self.0.feature_set(names).set(state);
204 self
205 }
206
207 pub fn feature_exclusive_set<S: FontFeatureExclusiveSetState>(mut self, state: impl Into<S>) -> Self {
213 self.0.feature_exclusive_set::<S>().set(state);
214 self
215 }
216
217 pub fn feature_exclusive_sets<S: FontFeatureExclusiveSetsState>(mut self, state: impl Into<S>) -> Self {
223 self.0.feature_exclusive_sets::<S>().set(state);
224 self
225 }
226}
227
228macro_rules! font_features {
231 ($(
232 $(#[$docs:meta])*
233 fn $name:ident($feat0_or_Enum:tt $(, $feat1:tt)?) $(-> $Helper:ident)?;
234 )+) => {
235 impl FontFeatures {$(
236 font_features!{feature $(#[$docs])* fn $name($feat0_or_Enum $(, $feat1)?) $(-> $Helper)?; }
237 )+}
238
239 impl FontFeaturesBuilder {$(
240 font_features!{builder $(#[$docs])* fn $name($($feat0_or_Enum -> $Helper)?); }
241 )+}
242 };
243
244 (feature $(#[$docs:meta])* fn $name:ident($feat0:tt, $feat1:tt); ) => {
245 $(#[$docs])*
246
247 pub fn $name(&mut self) -> FontFeatureSet<'_> {
248 static FEATS: [FontFeatureName; 2] = [FontFeatureName(*$feat0), FontFeatureName(*$feat1)];
249 self.feature_set(&FEATS)
250 }
251
252 };
253
254 (feature $(#[$docs:meta])* fn $name:ident($feat0:tt);) => {
255 $(#[$docs])*
256
257 pub fn $name(&mut self) -> FontFeature<'_> {
258 self.feature(FontFeatureName(*$feat0))
259 }
260
261 };
262
263 (feature $(#[$docs:meta])* fn $name:ident($Enum:ident) -> $Helper:ident;) => {
264 $(#[$docs])*
265
266 pub fn $name(&mut self) -> $Helper<'_, $Enum> {
267 $Helper { features: &mut self.0, _t: PhantomData }
268 }
269
270 };
271
272 (builder $(#[$docs:meta])* fn $name:ident();) => {
273 $(#[$docs])*
274
275 pub fn $name(mut self, state: impl Into<FontFeatureState>) -> Self {
276 self.0.$name().set(state);
277 self
278 }
279
280 };
281
282 (builder $(#[$docs:meta])* fn $name:ident($Enum:ident -> $Helper:ident);) => {
283 $(#[$docs])*
284
285 pub fn $name(mut self, state: impl Into<$Enum>) -> Self {
286 self.0.$name().set(state);
287 self
288 }
289
290 };
291}
292
293#[rustfmt::skip]font_features! {
295 fn caps(CapsVariant) -> FontFeatureExclusiveSets;
299
300 fn kerning(b"kern");
306
307 fn common_lig(b"liga", b"clig");
313
314 fn discretionary_lig(b"dlig");
320
321 fn historical_lig(b"hlig");
327
328 fn contextual_alt(b"calt");
334
335 fn ordinal(b"ordn");
341
342 fn slashed_zero(b"zero");
348
349 fn swash(b"swsh", b"cswh");
357
358 fn stylistic(b"salt");
366
367 fn historical_forms(b"hist");
373
374 fn ornaments(b"ornm");
382
383 fn annotation(b"nalt");
391
392 fn numeric(NumVariant) -> FontFeatureExclusiveSet;
396
397 fn num_spacing(NumSpacing) -> FontFeatureExclusiveSet;
401
402 fn num_fraction(NumFraction) -> FontFeatureExclusiveSet;
406
407 fn style_set(FontStyleSet) -> FontFeatureExclusiveSet;
411
412 fn char_variant(CharVariant) -> FontFeatureExclusiveSet;
416
417 fn position(FontPosition) -> FontFeatureExclusiveSet;
421
422 fn ruby(b"ruby");
428
429 fn jp_variant(JpVariant) -> FontFeatureExclusiveSet;
433
434 fn horizontal_kana(b"hkna");
438
439 fn cn_variant(CnVariant) -> FontFeatureExclusiveSet;
443
444 fn ea_width(EastAsianWidth) -> FontFeatureExclusiveSet;
448}
449
450pub struct FontFeature<'a>(hash_map::Entry<'a, FontFeatureName, u32>);
452impl FontFeature<'_> {
453 pub fn name(&self) -> FontFeatureName {
455 *self.0.key()
456 }
457
458 pub fn state(&self) -> FontFeatureState {
460 match &self.0 {
461 hash_map::Entry::Occupied(e) => FontFeatureState(Some(*e.get())),
462 hash_map::Entry::Vacant(_) => FontFeatureState::auto(),
463 }
464 }
465
466 pub fn is_enabled(&self) -> bool {
468 self.state().is_enabled()
469 }
470
471 pub fn is_disabled(&self) -> bool {
473 self.state().is_disabled()
474 }
475
476 pub fn is_auto(&self) -> bool {
478 self.state().is_auto()
479 }
480
481 pub fn set(self, state: impl Into<FontFeatureState>) -> FontFeatureState {
485 let prev = self.state();
486 match state.into().0 {
487 Some(n) => self.set_explicit(n),
488 None => self.auto(),
489 }
490 prev
491 }
492
493 fn set_explicit(self, state: u32) {
494 match self.0 {
495 hash_map::Entry::Occupied(mut e) => {
496 e.insert(state);
497 }
498 hash_map::Entry::Vacant(e) => {
499 e.insert(state);
500 }
501 }
502 }
503
504 pub fn enable(self) {
506 self.set_explicit(FEATURE_ENABLED);
507 }
508
509 pub fn enable_alt(self, alt: NonZeroU32) {
511 self.set_explicit(alt.get())
512 }
513
514 pub fn disable(self) {
516 self.set_explicit(FEATURE_DISABLED);
517 }
518
519 pub fn auto(self) {
521 if let hash_map::Entry::Occupied(e) = self.0 {
522 e.remove();
523 }
524 }
525}
526impl fmt::Debug for FontFeature<'_> {
527 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
528 write!(f, "b\"{}\": {:?}", self.name(), self.state())
529 }
530}
531
532pub struct FontFeatureSet<'a> {
534 features: &'a mut FontFeaturesMap,
535 names: &'static [FontFeatureName],
536}
537impl FontFeatureSet<'_> {
538 pub fn names(&self) -> &'static [FontFeatureName] {
540 self.names
541 }
542
543 pub fn state(&self) -> FontFeatureState {
547 if let Some(&a) = self.features.get(&self.names[0]) {
548 for name in &self.names[1..] {
549 if self.features.get(name) != Some(&a) {
550 return FontFeatureState::auto();
551 }
552 }
553 FontFeatureState(Some(a))
554 } else {
555 FontFeatureState::auto()
556 }
557 }
558
559 pub fn is_enabled(&self) -> bool {
561 self.state().is_enabled()
562 }
563
564 pub fn is_disabled(&self) -> bool {
566 self.state().is_disabled()
567 }
568
569 pub fn is_auto(&self) -> bool {
571 self.state().is_auto()
572 }
573
574 pub fn set(self, state: impl Into<FontFeatureState>) -> FontFeatureState {
578 let prev = self.state();
579 match state.into().0 {
580 Some(n) => self.set_explicit(n),
581 None => self.auto(),
582 }
583 prev
584 }
585
586 fn set_explicit(self, state: u32) {
587 for name in self.names {
588 self.features.insert(*name, state);
589 }
590 }
591
592 pub fn enable(self) {
594 self.set_explicit(FEATURE_ENABLED);
595 }
596
597 pub fn disable(self) {
599 self.set_explicit(FEATURE_DISABLED);
600 }
601
602 pub fn auto(self) {
604 for name in self.names {
605 self.features.remove(name);
606 }
607 }
608}
609impl fmt::Debug for FontFeatureSet<'_> {
610 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611 write!(f, "{:?}: {:?}", self.names, self.state())
612 }
613}
614
615pub struct FontFeatureExclusiveSet<'a, S: FontFeatureExclusiveSetState> {
618 features: &'a mut FontFeaturesMap,
619 _t: PhantomData<S>,
620}
621impl<S: FontFeatureExclusiveSetState> FontFeatureExclusiveSet<'_, S> {
622 pub fn names(&self) -> &'static [FontFeatureName] {
624 S::names()
625 }
626
627 pub fn state(&self) -> S {
629 let mut state = 0;
630
631 for (i, name) in S::names().iter().enumerate() {
632 if let Some(&s) = self.features.get(name)
633 && s == FEATURE_ENABLED
634 && state == 0
635 {
636 state = i + 1; continue;
638 }
639 return S::auto();
641 }
642 S::from_variant(state as u32)
643 }
644 fn take_state(&mut self) -> S {
645 let mut state = 0;
646 let mut skip = false;
647
648 for (i, name) in S::names().iter().enumerate() {
649 if let Some(s) = self.features.remove(name) {
650 if skip {
651 continue;
652 }
653
654 if s == FEATURE_ENABLED && state == 0 {
655 state = i + 1; continue;
657 }
658 }
659 skip = true;
661 }
662
663 S::from_variant(state as u32)
664 }
665
666 pub fn is_auto(&self) -> bool {
668 self.state() == S::auto()
669 }
670
671 pub fn set(&mut self, state: impl Into<S>) -> S {
675 let prev = self.take_state();
676 if let Some(state) = state.into().variant() {
677 self.features.insert(self.names()[state as usize - 1], FEATURE_ENABLED);
678 }
679 prev
680 }
681}
682impl<S: FontFeatureExclusiveSetState + fmt::Debug> fmt::Debug for FontFeatureExclusiveSet<'_, S> {
683 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
684 fmt::Debug::fmt(&self.state(), f)
685 }
686}
687
688pub struct FontFeatureExclusiveSets<'a, S: FontFeatureExclusiveSetsState> {
691 features: &'a mut FontFeaturesMap,
692 _t: PhantomData<S>,
693}
694impl<S: FontFeatureExclusiveSetsState> FontFeatureExclusiveSets<'_, S> {
695 pub fn names(&self) -> &'static [&'static [FontFeatureName]] {
697 S::names()
698 }
699
700 pub fn state(&self) -> S {
702 let mut active = HashSet::new();
703 for &names in self.names() {
704 for name in names {
705 if let Some(&s) = self.features.get(name) {
706 if s != FEATURE_ENABLED {
707 return S::auto();
709 } else {
710 active.insert(*name);
711 }
712 }
713 }
714 }
715
716 if !active.is_empty() {
717 'names: for (i, &names) in self.names().iter().enumerate() {
718 if names.len() == active.len() {
719 for name in names {
720 if !active.contains(name) {
721 continue 'names;
722 }
723 }
724 return S::from_variant(i as u32 + 1);
725 }
726 }
727 }
728
729 S::auto()
730 }
731 fn take_state(&mut self) -> S {
732 let mut active = HashSet::new();
733 let mut force_auto = false;
734
735 for &names in self.names() {
736 for name in names {
737 if let Some(s) = self.features.remove(name) {
738 if force_auto {
739 continue;
740 }
741
742 if s != FEATURE_ENABLED {
743 force_auto = true;
745 } else {
746 active.insert(name);
747 }
748 }
749 }
750 }
751
752 if !force_auto && !active.is_empty() {
753 'names: for (i, &names) in self.names().iter().enumerate() {
754 if names.len() == active.len() {
755 for name in names {
756 if !active.contains(name) {
757 continue 'names;
758 }
759 }
760 return S::from_variant(i as u32 + 1);
761 }
762 }
763 }
764
765 S::auto()
766 }
767
768 pub fn is_auto(&self) -> bool {
770 self.state() == S::auto()
771 }
772
773 pub fn set(&mut self, state: impl Into<S>) -> S {
777 let prev = self.take_state();
778 if let Some(state) = state.into().variant() {
779 for name in self.names()[state as usize - 1] {
780 self.features.insert(*name, FEATURE_ENABLED);
781 }
782 }
783 prev
784 }
785}
786impl<S: FontFeatureExclusiveSetsState + fmt::Debug> fmt::Debug for FontFeatureExclusiveSets<'_, S> {
787 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
788 fmt::Debug::fmt(&self.state(), f)
789 }
790}
791
792pub trait FontFeatureExclusiveSetState: Copy + PartialEq + 'static {
794 fn names() -> &'static [FontFeatureName];
796 fn variant(self) -> Option<u32>;
798 fn from_variant(v: u32) -> Self;
802 fn auto() -> Self;
804}
805
806pub trait FontFeatureExclusiveSetsState: Copy + PartialEq + 'static {
809 fn names() -> &'static [&'static [FontFeatureName]];
811 fn variant(self) -> Option<u32>;
813 fn from_variant(v: u32) -> Self;
817 fn auto() -> Self;
819}
820
821#[derive(Copy, Clone, PartialEq, Eq, Hash, Default)]
823pub struct FontFeatureState(Option<u32>);
824impl FontFeatureState {
825 pub const fn auto() -> Self {
827 FontFeatureState(None)
828 }
829
830 pub const fn enabled() -> Self {
832 FontFeatureState(Some(1))
833 }
834
835 pub const fn enabled_alt(alt: NonZeroU32) -> Self {
837 FontFeatureState(Some(alt.get()))
838 }
839
840 pub const fn disabled() -> Self {
842 FontFeatureState(Some(0))
843 }
844
845 pub fn is_auto(self) -> bool {
847 self.0.is_none()
848 }
849
850 pub fn is_enabled(self) -> bool {
852 if let Some(n) = self.0
853 && n >= 1
854 {
855 return true;
856 }
857 false
858 }
859
860 pub fn is_disabled(self) -> bool {
862 self == Self::disabled()
863 }
864
865 pub fn alt(self) -> Option<u32> {
867 if let Some(n) = self.0
868 && n >= 1
869 {
870 return Some(n);
871 }
872 None
873 }
874}
875impl fmt::Debug for FontFeatureState {
876 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
877 match self.0 {
878 Some(n) => {
879 if n == FEATURE_DISABLED {
880 write!(f, "FontFeatureState::disabled()")
881 } else if n == FEATURE_ENABLED {
882 write!(f, "FontFeatureState::enabled()")
883 } else {
884 write!(f, "FontFeatureState::enabled_alt({n})")
885 }
886 }
887 None => write!(f, "FontFeatureState::auto()"),
888 }
889 }
890}
891impl_from_and_into_var! {
892 fn from(enabled: bool) -> FontFeatureState {
893 if enabled {
894 FontFeatureState::enabled()
895 } else {
896 FontFeatureState::disabled()
897 }
898 }
899
900 fn from(alt: u32) -> FontFeatureState {
902 FontFeatureState(Some(alt))
903 }
904}
905
906#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
908#[repr(u8)]
909pub enum CapsVariant {
910 #[default]
912 Auto,
913
914 SmallCaps,
918
919 AllSmallCaps,
923
924 Petite,
928
929 AllPetite,
933
934 Unicase,
938
939 TitlingCaps,
943}
944impl fmt::Debug for CapsVariant {
945 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
946 if f.alternate() {
947 write!(f, "CapsVariant::")?;
948 }
949 match self {
950 CapsVariant::Auto => write!(f, "Auto"),
951 CapsVariant::SmallCaps => write!(f, "SmallCaps"),
952 CapsVariant::AllSmallCaps => write!(f, "AllSmallCaps"),
953 CapsVariant::Petite => write!(f, "Petite"),
954 CapsVariant::AllPetite => write!(f, "AllPetite"),
955 CapsVariant::Unicase => write!(f, "Unicase"),
956 CapsVariant::TitlingCaps => write!(f, "TitlingCaps"),
957 }
958 }
959}
960impl Default for CapsVariant {
961 fn default() -> Self {
963 CapsVariant::Auto
964 }
965}
966impl FontFeatureExclusiveSetsState for CapsVariant {
967 fn names() -> &'static [&'static [FontFeatureName]] {
968 static N0: [FontFeatureName; 1] = [FontFeatureName(*b"smcp")];
969 static N1: [FontFeatureName; 2] = [FontFeatureName(*b"c2sc"), FontFeatureName(*b"smcp")];
970 static N2: [FontFeatureName; 1] = [FontFeatureName(*b"pcap")];
971 static N3: [FontFeatureName; 2] = [FontFeatureName(*b"c2pc"), FontFeatureName(*b"pcap")];
972 static N4: [FontFeatureName; 1] = [FontFeatureName(*b"unic")];
973 static N5: [FontFeatureName; 1] = [FontFeatureName(*b"titl")];
974 static NAMES: [&[FontFeatureName]; 6] = [&N0, &N1, &N2, &N3, &N4, &N5];
975 &NAMES
976 }
977
978 fn variant(self) -> Option<u32> {
979 if self == CapsVariant::Auto { None } else { Some(self as u32) }
980 }
981
982 fn from_variant(v: u32) -> Self {
983 Self::from(v as u8)
984 }
985
986 fn auto() -> Self {
987 CapsVariant::Auto
988 }
989}
990
991#[derive(Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
993#[repr(u8)]
994pub enum NumVariant {
995 #[default]
997 Auto,
998 Lining,
1002 OldStyle,
1006}
1007impl fmt::Debug for NumVariant {
1008 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1009 if f.alternate() {
1010 write!(f, "NumVariant::")?;
1011 }
1012 match self {
1013 NumVariant::Auto => write!(f, "Auto"),
1014 NumVariant::Lining => write!(f, "Lining"),
1015 NumVariant::OldStyle => write!(f, "OldStyle"),
1016 }
1017 }
1018}
1019impl Default for NumVariant {
1020 fn default() -> Self {
1022 NumVariant::Auto
1023 }
1024}
1025impl FontFeatureExclusiveSetState for NumVariant {
1026 fn names() -> &'static [FontFeatureName] {
1027 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"lnum"), FontFeatureName(*b"onum")];
1028 &NAMES
1029 }
1030
1031 fn variant(self) -> Option<u32> {
1032 match self {
1033 NumVariant::Auto => None,
1034 NumVariant::Lining => Some(1),
1035 NumVariant::OldStyle => Some(2),
1036 }
1037 }
1038
1039 fn from_variant(v: u32) -> Self {
1040 Self::from(v as u8)
1041 }
1042
1043 fn auto() -> Self {
1044 NumVariant::Auto
1045 }
1046}
1047
1048#[derive(Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
1050#[repr(u8)]
1051pub enum NumSpacing {
1052 #[default]
1054 Auto,
1055 Proportional,
1059 Tabular,
1063}
1064impl fmt::Debug for NumSpacing {
1065 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1066 if f.alternate() {
1067 write!(f, "NumSpacing::")?;
1068 }
1069 match self {
1070 NumSpacing::Auto => write!(f, "Auto"),
1071 NumSpacing::Proportional => write!(f, "Proportional"),
1072 NumSpacing::Tabular => write!(f, "Tabular"),
1073 }
1074 }
1075}
1076impl Default for NumSpacing {
1077 fn default() -> Self {
1079 NumSpacing::Auto
1080 }
1081}
1082impl FontFeatureExclusiveSetState for NumSpacing {
1083 fn names() -> &'static [FontFeatureName] {
1084 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"pnum"), FontFeatureName(*b"tnum")];
1085 &NAMES
1086 }
1087
1088 fn variant(self) -> Option<u32> {
1089 match self {
1090 NumSpacing::Auto => None,
1091 NumSpacing::Proportional => Some(1),
1092 NumSpacing::Tabular => Some(2),
1093 }
1094 }
1095
1096 fn from_variant(v: u32) -> Self {
1097 Self::from(v as u8)
1098 }
1099
1100 fn auto() -> Self {
1101 NumSpacing::Auto
1102 }
1103}
1104
1105#[derive(Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
1107#[repr(u8)]
1108pub enum NumFraction {
1109 #[default]
1111 Auto,
1112 Diagonal,
1116 Stacked,
1120}
1121impl fmt::Debug for NumFraction {
1122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1123 if f.alternate() {
1124 write!(f, "NumFraction::")?;
1125 }
1126 match self {
1127 NumFraction::Auto => write!(f, "Auto"),
1128 NumFraction::Diagonal => write!(f, "Diagonal"),
1129 NumFraction::Stacked => write!(f, "Stacked"),
1130 }
1131 }
1132}
1133impl Default for NumFraction {
1134 fn default() -> Self {
1136 NumFraction::Auto
1137 }
1138}
1139impl FontFeatureExclusiveSetState for NumFraction {
1140 fn names() -> &'static [FontFeatureName] {
1141 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"frac"), FontFeatureName(*b"afrc")];
1142 &NAMES
1143 }
1144
1145 fn variant(self) -> Option<u32> {
1146 match self {
1147 NumFraction::Auto => None,
1148 NumFraction::Diagonal => Some(1),
1149 NumFraction::Stacked => Some(2),
1150 }
1151 }
1152
1153 fn from_variant(v: u32) -> Self {
1154 Self::from(v as u8)
1155 }
1156
1157 fn auto() -> Self {
1158 NumFraction::Auto
1159 }
1160}
1161
1162#[derive(Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
1167#[repr(u8)]
1168#[allow(missing_docs)]
1169pub enum FontStyleSet {
1170 #[default]
1172 Auto = 0,
1173
1174 S01,
1175 S02,
1176 S03,
1177 S04,
1178 S05,
1179 S06,
1180 S07,
1181 S08,
1182 S09,
1183 S10,
1184
1185 S11,
1186 S12,
1187 S13,
1188 S14,
1189 S15,
1190 S16,
1191 S17,
1192 S18,
1193 S19,
1194 S20,
1195}
1196impl Default for FontStyleSet {
1197 fn default() -> Self {
1199 FontStyleSet::Auto
1200 }
1201}
1202impl fmt::Debug for FontStyleSet {
1203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1204 if f.alternate() {
1205 write!(f, "FontStyleSet::")?;
1206 }
1207 let n = *self as u8;
1208 if n == 0 { write!(f, "Auto") } else { write!(f, "S{n:0<2}") }
1209 }
1210}
1211impl_from_and_into_var! {
1212 fn from(set: u8) -> FontStyleSet;
1213}
1214
1215impl FontFeatureExclusiveSetState for FontStyleSet {
1216 fn names() -> &'static [FontFeatureName] {
1217 static NAMES: [FontFeatureName; 20] = [
1218 FontFeatureName(*b"ss01"),
1219 FontFeatureName(*b"ss02"),
1220 FontFeatureName(*b"ss03"),
1221 FontFeatureName(*b"ss04"),
1222 FontFeatureName(*b"ss05"),
1223 FontFeatureName(*b"ss06"),
1224 FontFeatureName(*b"ss07"),
1225 FontFeatureName(*b"ss08"),
1226 FontFeatureName(*b"ss09"),
1227 FontFeatureName(*b"ss10"),
1228 FontFeatureName(*b"ss11"),
1229 FontFeatureName(*b"ss12"),
1230 FontFeatureName(*b"ss13"),
1231 FontFeatureName(*b"ss14"),
1232 FontFeatureName(*b"ss15"),
1233 FontFeatureName(*b"ss16"),
1234 FontFeatureName(*b"ss17"),
1235 FontFeatureName(*b"ss18"),
1236 FontFeatureName(*b"ss19"),
1237 FontFeatureName(*b"ss20"),
1238 ];
1239 &NAMES
1240 }
1241
1242 fn variant(self) -> Option<u32> {
1243 if self == FontStyleSet::Auto { None } else { Some(self as u32) }
1244 }
1245
1246 fn from_variant(v: u32) -> Self {
1247 Self::from(v as u8)
1248 }
1249
1250 fn auto() -> Self {
1251 FontStyleSet::Auto
1252 }
1253}
1254
1255#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1259pub struct CharVariant(u8);
1260impl CharVariant {
1261 pub const fn new(v: u8) -> Self {
1265 if v > 99 { CharVariant(0) } else { CharVariant(v) }
1266 }
1267
1268 pub const fn auto() -> Self {
1270 CharVariant(0)
1271 }
1272
1273 pub const fn is_auto(self) -> bool {
1275 self.0 == 0
1276 }
1277}
1278impl_from_and_into_var! {
1279 fn from(v: u8) -> CharVariant {
1281 CharVariant::new(v)
1282 }
1283}
1284impl FontFeatureExclusiveSetState for CharVariant {
1285 fn names() -> &'static [FontFeatureName] {
1286 static NAMES: [FontFeatureName; 100] = [
1287 FontFeatureName(*b"cv01"),
1288 FontFeatureName(*b"cv02"),
1289 FontFeatureName(*b"cv03"),
1290 FontFeatureName(*b"cv04"),
1291 FontFeatureName(*b"cv05"),
1292 FontFeatureName(*b"cv06"),
1293 FontFeatureName(*b"cv07"),
1294 FontFeatureName(*b"cv08"),
1295 FontFeatureName(*b"cv09"),
1296 FontFeatureName(*b"cv20"),
1297 FontFeatureName(*b"cv21"),
1298 FontFeatureName(*b"cv22"),
1299 FontFeatureName(*b"cv23"),
1300 FontFeatureName(*b"cv24"),
1301 FontFeatureName(*b"cv25"),
1302 FontFeatureName(*b"cv26"),
1303 FontFeatureName(*b"cv27"),
1304 FontFeatureName(*b"cv28"),
1305 FontFeatureName(*b"cv29"),
1306 FontFeatureName(*b"cv30"),
1307 FontFeatureName(*b"cv31"),
1308 FontFeatureName(*b"cv32"),
1309 FontFeatureName(*b"cv33"),
1310 FontFeatureName(*b"cv34"),
1311 FontFeatureName(*b"cv35"),
1312 FontFeatureName(*b"cv36"),
1313 FontFeatureName(*b"cv37"),
1314 FontFeatureName(*b"cv38"),
1315 FontFeatureName(*b"cv39"),
1316 FontFeatureName(*b"cv40"),
1317 FontFeatureName(*b"cv41"),
1318 FontFeatureName(*b"cv42"),
1319 FontFeatureName(*b"cv43"),
1320 FontFeatureName(*b"cv44"),
1321 FontFeatureName(*b"cv45"),
1322 FontFeatureName(*b"cv46"),
1323 FontFeatureName(*b"cv47"),
1324 FontFeatureName(*b"cv48"),
1325 FontFeatureName(*b"cv49"),
1326 FontFeatureName(*b"cv50"),
1327 FontFeatureName(*b"cv51"),
1328 FontFeatureName(*b"cv52"),
1329 FontFeatureName(*b"cv53"),
1330 FontFeatureName(*b"cv54"),
1331 FontFeatureName(*b"cv55"),
1332 FontFeatureName(*b"cv56"),
1333 FontFeatureName(*b"cv57"),
1334 FontFeatureName(*b"cv58"),
1335 FontFeatureName(*b"cv59"),
1336 FontFeatureName(*b"cv60"),
1337 FontFeatureName(*b"cv61"),
1338 FontFeatureName(*b"cv62"),
1339 FontFeatureName(*b"cv63"),
1340 FontFeatureName(*b"cv64"),
1341 FontFeatureName(*b"cv65"),
1342 FontFeatureName(*b"cv66"),
1343 FontFeatureName(*b"cv67"),
1344 FontFeatureName(*b"cv68"),
1345 FontFeatureName(*b"cv69"),
1346 FontFeatureName(*b"cv70"),
1347 FontFeatureName(*b"cv71"),
1348 FontFeatureName(*b"cv72"),
1349 FontFeatureName(*b"cv73"),
1350 FontFeatureName(*b"cv74"),
1351 FontFeatureName(*b"cv75"),
1352 FontFeatureName(*b"cv76"),
1353 FontFeatureName(*b"cv77"),
1354 FontFeatureName(*b"cv78"),
1355 FontFeatureName(*b"cv79"),
1356 FontFeatureName(*b"cv70"),
1357 FontFeatureName(*b"cv71"),
1358 FontFeatureName(*b"cv72"),
1359 FontFeatureName(*b"cv73"),
1360 FontFeatureName(*b"cv74"),
1361 FontFeatureName(*b"cv75"),
1362 FontFeatureName(*b"cv76"),
1363 FontFeatureName(*b"cv77"),
1364 FontFeatureName(*b"cv78"),
1365 FontFeatureName(*b"cv79"),
1366 FontFeatureName(*b"cv80"),
1367 FontFeatureName(*b"cv81"),
1368 FontFeatureName(*b"cv82"),
1369 FontFeatureName(*b"cv83"),
1370 FontFeatureName(*b"cv84"),
1371 FontFeatureName(*b"cv85"),
1372 FontFeatureName(*b"cv86"),
1373 FontFeatureName(*b"cv87"),
1374 FontFeatureName(*b"cv88"),
1375 FontFeatureName(*b"cv89"),
1376 FontFeatureName(*b"cv90"),
1377 FontFeatureName(*b"cv91"),
1378 FontFeatureName(*b"cv92"),
1379 FontFeatureName(*b"cv93"),
1380 FontFeatureName(*b"cv94"),
1381 FontFeatureName(*b"cv95"),
1382 FontFeatureName(*b"cv96"),
1383 FontFeatureName(*b"cv97"),
1384 FontFeatureName(*b"cv98"),
1385 FontFeatureName(*b"cv99"),
1386 FontFeatureName(*b"cv99"),
1387 ];
1388 &NAMES
1389 }
1390
1391 fn variant(self) -> Option<u32> {
1392 if self.is_auto() { None } else { Some(self.0 as u32) }
1393 }
1394
1395 fn from_variant(v: u32) -> Self {
1396 if v > 99 { CharVariant::auto() } else { CharVariant(v as u8) }
1397 }
1398
1399 fn auto() -> Self {
1400 CharVariant::auto()
1401 }
1402}
1403
1404#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
1406#[repr(u8)]
1407pub enum FontPosition {
1408 #[default]
1410 Auto,
1411 Sub,
1415 Super,
1419}
1420impl fmt::Debug for FontPosition {
1421 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1422 if f.alternate() {
1423 write!(f, "FontPosition::")?;
1424 }
1425 match self {
1426 FontPosition::Auto => write!(f, "Auto"),
1427 FontPosition::Sub => write!(f, "Sub"),
1428 FontPosition::Super => write!(f, "Super"),
1429 }
1430 }
1431}
1432impl Default for FontPosition {
1433 fn default() -> Self {
1435 FontPosition::Auto
1436 }
1437}
1438impl FontFeatureExclusiveSetState for FontPosition {
1439 fn names() -> &'static [FontFeatureName] {
1440 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"subs"), FontFeatureName(*b"sups")];
1441 &NAMES
1442 }
1443
1444 fn variant(self) -> Option<u32> {
1445 match self {
1446 FontPosition::Auto => None,
1447 FontPosition::Sub => Some(1),
1448 FontPosition::Super => Some(2),
1449 }
1450 }
1451
1452 fn from_variant(v: u32) -> Self {
1453 Self::from(v as u8)
1454 }
1455
1456 fn auto() -> Self {
1457 FontPosition::Auto
1458 }
1459}
1460
1461#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
1463#[repr(u8)]
1464pub enum JpVariant {
1465 #[default]
1467 Auto,
1468
1469 Jis78,
1473 Jis83,
1477 Jis90,
1481
1482 Jis04,
1486 NlcKanji,
1490}
1491impl fmt::Debug for JpVariant {
1492 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1493 if f.alternate() {
1494 write!(f, "JpVariant::")?;
1495 }
1496 match self {
1497 JpVariant::Auto => write!(f, "Auto"),
1498 JpVariant::Jis78 => write!(f, "Jis78"),
1499 JpVariant::Jis83 => write!(f, "Jis83"),
1500 JpVariant::Jis90 => write!(f, "Jis90"),
1501 JpVariant::Jis04 => write!(f, "Jis04"),
1502 JpVariant::NlcKanji => write!(f, "NlcKanji"),
1503 }
1504 }
1505}
1506impl Default for JpVariant {
1507 fn default() -> Self {
1509 JpVariant::Auto
1510 }
1511}
1512impl FontFeatureExclusiveSetState for JpVariant {
1513 fn names() -> &'static [FontFeatureName] {
1514 static NAMES: [FontFeatureName; 5] = [
1515 FontFeatureName(*b"jp78"),
1516 FontFeatureName(*b"jp83"),
1517 FontFeatureName(*b"jp90"),
1518 FontFeatureName(*b"jp04"),
1519 FontFeatureName(*b"nlck"),
1520 ];
1521 &NAMES
1522 }
1523
1524 fn variant(self) -> Option<u32> {
1525 if self == JpVariant::Auto { None } else { Some(self as u32) }
1526 }
1527
1528 fn from_variant(v: u32) -> Self {
1529 Self::from(v as u8)
1530 }
1531
1532 fn auto() -> Self {
1533 JpVariant::Auto
1534 }
1535}
1536#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
1538#[repr(u8)]
1539pub enum CnVariant {
1540 #[default]
1542 Auto,
1543 Simplified,
1547 Traditional,
1551}
1552impl fmt::Debug for CnVariant {
1553 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1554 if f.alternate() {
1555 write!(f, "CnVariant")?;
1556 }
1557 match self {
1558 CnVariant::Auto => write!(f, "Auto"),
1559 CnVariant::Simplified => write!(f, "Simplified"),
1560 CnVariant::Traditional => write!(f, "Traditional"),
1561 }
1562 }
1563}
1564impl Default for CnVariant {
1565 fn default() -> Self {
1567 CnVariant::Auto
1568 }
1569}
1570impl FontFeatureExclusiveSetState for CnVariant {
1571 fn names() -> &'static [FontFeatureName] {
1572 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"smpl"), FontFeatureName(*b"trad")];
1573 &NAMES
1574 }
1575
1576 fn variant(self) -> Option<u32> {
1577 match self {
1578 CnVariant::Auto => None,
1579 CnVariant::Simplified => Some(1),
1580 CnVariant::Traditional => Some(2),
1581 }
1582 }
1583
1584 fn from_variant(v: u32) -> Self {
1585 Self::from(v as u8)
1586 }
1587
1588 fn auto() -> Self {
1589 CnVariant::Auto
1590 }
1591}
1592
1593#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
1595#[repr(u8)]
1596pub enum EastAsianWidth {
1597 #[default]
1599 Auto,
1600
1601 Proportional,
1605
1606 ProportionalAlt,
1610
1611 ProportionalKana,
1615
1616 Full,
1620
1621 Half,
1625
1626 HalfAlt,
1630
1631 Third,
1635
1636 Quarter,
1640}
1641impl fmt::Debug for EastAsianWidth {
1642 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1643 if f.alternate() {
1644 write!(f, "EastAsianWidth::")?;
1645 }
1646 match self {
1647 EastAsianWidth::Auto => write!(f, "Auto"),
1648 EastAsianWidth::Proportional => write!(f, "Proportional"),
1649 EastAsianWidth::ProportionalAlt => write!(f, "ProportionalAlt"),
1650 EastAsianWidth::ProportionalKana => write!(f, "ProportionalKana"),
1651 EastAsianWidth::Full => write!(f, "Full"),
1652 EastAsianWidth::Half => write!(f, "Half"),
1653 EastAsianWidth::HalfAlt => write!(f, "HalfAlt"),
1654 EastAsianWidth::Third => write!(f, "Third"),
1655 EastAsianWidth::Quarter => write!(f, "Quarter"),
1656 }
1657 }
1658}
1659impl Default for EastAsianWidth {
1660 fn default() -> Self {
1662 EastAsianWidth::Auto
1663 }
1664}
1665impl FontFeatureExclusiveSetState for EastAsianWidth {
1666 fn names() -> &'static [FontFeatureName] {
1667 static NAMES: [FontFeatureName; 8] = [
1668 FontFeatureName(*b"pwid"),
1669 FontFeatureName(*b"palt"),
1670 FontFeatureName(*b"pkna"),
1671 FontFeatureName(*b"fwid"),
1672 FontFeatureName(*b"hwid"),
1673 FontFeatureName(*b"halt"),
1674 FontFeatureName(*b"twid"),
1675 FontFeatureName(*b"qwid"),
1676 ];
1677 &NAMES
1678 }
1679
1680 fn variant(self) -> Option<u32> {
1681 if self == EastAsianWidth::Auto { None } else { Some(self as u32) }
1682 }
1683
1684 fn from_variant(v: u32) -> Self {
1685 Self::from(v as u8)
1686 }
1687
1688 fn auto() -> Self {
1689 EastAsianWidth::Auto
1690 }
1691}
1692
1693#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1702pub struct FontVariationName(pub [u8; 4]);
1703impl FontVariationName {
1704 pub fn as_str(&self) -> &str {
1706 std::str::from_utf8(&self.0).unwrap_or_default()
1707 }
1708}
1709impl From<&'static [u8; 4]> for FontVariationName {
1710 fn from(name: &'static [u8; 4]) -> Self {
1711 FontVariationName(*name)
1712 }
1713}
1714impl From<FontVariationName> for ttf_parser::Tag {
1715 fn from(value: FontVariationName) -> Self {
1716 ttf_parser::Tag::from_bytes(&value.0)
1717 }
1718}
1719impl ops::Deref for FontVariationName {
1720 type Target = [u8; 4];
1721
1722 fn deref(&self) -> &Self::Target {
1723 &self.0
1724 }
1725}
1726impl fmt::Debug for FontVariationName {
1727 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1728 if self.as_str().is_empty() {
1729 write!(f, "{:?}", self.0)
1730 } else {
1731 write!(f, "{}", self.as_str())
1732 }
1733 }
1734}
1735impl fmt::Display for FontVariationName {
1736 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1737 write!(f, "{self:?}")
1738 }
1739}
1740
1741#[derive(Default, Clone, PartialEq)]
1745pub struct FontVariations(Vec<(FontVariationName, f32)>);
1746impl FontVariations {
1747 pub fn new() -> Self {
1749 Self::default()
1750 }
1751
1752 pub fn with_capacity(capacity: usize) -> Self {
1754 Self(Vec::with_capacity(capacity))
1755 }
1756
1757 pub fn from_pairs(pairs: &[(FontVariationName, f32)]) -> Self {
1759 let mut r = Self::with_capacity(pairs.len());
1760 for (name, value) in pairs {
1761 r.insert(*name, *value);
1762 }
1763 r
1764 }
1765
1766 pub fn insert(&mut self, name: FontVariationName, value: f32) -> Option<f32> {
1768 if let Some(entry) = self.0.iter_mut().find(|v| v.0 == name) {
1769 let prev = Some(entry.1);
1770 entry.1 = value;
1771 prev
1772 } else {
1773 self.0.push((name, value));
1774 None
1775 }
1776 }
1777
1778 pub fn remove(&mut self, name: FontVariationName) -> Option<f32> {
1780 if let Some(i) = self.0.iter().position(|v| v.0 == name) {
1781 Some(self.0.swap_remove(i).1)
1782 } else {
1783 None
1784 }
1785 }
1786
1787 pub fn contains(&self, name: FontVariationName) -> bool {
1789 self.0.iter().any(|v| v.0 == name)
1790 }
1791
1792 pub fn get(&self, name: FontVariationName) -> Option<f32> {
1794 self.0.iter().find(|v| v.0 == name).map(|v| v.1)
1795 }
1796
1797 pub fn get_mut(&mut self, name: FontVariationName) -> Option<&mut f32> {
1799 self.0.iter_mut().find(|v| v.0 == name).map(|v| &mut v.1)
1800 }
1801
1802 pub fn len(&self) -> usize {
1804 self.0.len()
1805 }
1806
1807 pub fn is_empty(&self) -> bool {
1809 self.0.is_empty()
1810 }
1811
1812 pub fn finalize(&self) -> RFontVariations {
1814 self.0
1815 .iter()
1816 .map(|(name, value)| rustybuzz::Variation {
1817 tag: (*name).into(),
1818 value: *value,
1819 })
1820 .collect()
1821 }
1822}
1823impl fmt::Debug for FontVariations {
1824 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1825 if f.alternate() {
1826 f.debug_tuple("FontVariations").field(&self.0).finish()
1827 } else {
1828 write!(f, "[")?;
1829 let mut first = false;
1830 for entry in &self.0 {
1831 if first {
1832 first = false;
1833 } else {
1834 write!(f, ", ")?;
1835 }
1836 write!(f, r#", b"{}": {}"#, entry.0, entry.1)?;
1837 }
1838 write!(f, "]")
1839 }
1840 }
1841}
1842
1843#[macro_export]
1857macro_rules! font_variations {
1858 [$(
1859 $name:tt => $value: expr
1860 ),* $(,)?] => {
1861 $crate::font_features::FontVariations::from_pairs(&[
1862 $(
1863 ($name.into(), $value),
1864 )*
1865 ])
1866 }
1867}
1868#[doc(inline)]
1869pub use font_variations;
1870use zng_var::impl_from_and_into_var;
1871
1872pub type RFontVariations = Vec<rustybuzz::Variation>;