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
293font_features! {
294 fn caps(CapsVariant) -> FontFeatureExclusiveSets;
298
299 fn kerning(b"kern");
305
306 fn common_lig(b"liga", b"clig");
312
313 fn discretionary_lig(b"dlig");
319
320 fn historical_lig(b"hlig");
326
327 fn contextual_alt(b"calt");
333
334 fn ordinal(b"ordn");
340
341 fn slashed_zero(b"zero");
347
348 fn swash(b"swsh", b"cswh");
356
357 fn stylistic(b"salt");
365
366 fn historical_forms(b"hist");
372
373 fn ornaments(b"ornm");
381
382 fn annotation(b"nalt");
390
391 fn numeric(NumVariant) -> FontFeatureExclusiveSet;
395
396 fn num_spacing(NumSpacing) -> FontFeatureExclusiveSet;
400
401 fn num_fraction(NumFraction) -> FontFeatureExclusiveSet;
405
406 fn style_set(FontStyleSet) -> FontFeatureExclusiveSet;
410
411 fn char_variant(CharVariant) -> FontFeatureExclusiveSet;
415
416 fn position(FontPosition) -> FontFeatureExclusiveSet;
420
421 fn ruby(b"ruby");
427
428 fn jp_variant(JpVariant) -> FontFeatureExclusiveSet;
432
433 fn horizontal_kana(b"hkna");
437
438 fn cn_variant(CnVariant) -> FontFeatureExclusiveSet;
442
443 fn ea_width(EastAsianWidth) -> FontFeatureExclusiveSet;
447}
448
449pub struct FontFeature<'a>(hash_map::Entry<'a, FontFeatureName, u32>);
451impl FontFeature<'_> {
452 pub fn name(&self) -> FontFeatureName {
454 *self.0.key()
455 }
456
457 pub fn state(&self) -> FontFeatureState {
459 match &self.0 {
460 hash_map::Entry::Occupied(e) => FontFeatureState(Some(*e.get())),
461 hash_map::Entry::Vacant(_) => FontFeatureState::auto(),
462 }
463 }
464
465 pub fn is_enabled(&self) -> bool {
467 self.state().is_enabled()
468 }
469
470 pub fn is_disabled(&self) -> bool {
472 self.state().is_disabled()
473 }
474
475 pub fn is_auto(&self) -> bool {
477 self.state().is_auto()
478 }
479
480 pub fn set(self, state: impl Into<FontFeatureState>) -> FontFeatureState {
484 let prev = self.state();
485 match state.into().0 {
486 Some(n) => self.set_explicit(n),
487 None => self.auto(),
488 }
489 prev
490 }
491
492 fn set_explicit(self, state: u32) {
493 match self.0 {
494 hash_map::Entry::Occupied(mut e) => {
495 e.insert(state);
496 }
497 hash_map::Entry::Vacant(e) => {
498 e.insert(state);
499 }
500 }
501 }
502
503 pub fn enable(self) {
505 self.set_explicit(FEATURE_ENABLED);
506 }
507
508 pub fn enable_alt(self, alt: NonZeroU32) {
510 self.set_explicit(alt.get())
511 }
512
513 pub fn disable(self) {
515 self.set_explicit(FEATURE_DISABLED);
516 }
517
518 pub fn auto(self) {
520 if let hash_map::Entry::Occupied(e) = self.0 {
521 e.remove();
522 }
523 }
524}
525impl fmt::Debug for FontFeature<'_> {
526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527 write!(f, "b\"{}\": {:?}", self.name(), self.state())
528 }
529}
530
531pub struct FontFeatureSet<'a> {
533 features: &'a mut FontFeaturesMap,
534 names: &'static [FontFeatureName],
535}
536impl FontFeatureSet<'_> {
537 pub fn names(&self) -> &'static [FontFeatureName] {
539 self.names
540 }
541
542 pub fn state(&self) -> FontFeatureState {
546 if let Some(&a) = self.features.get(&self.names[0]) {
547 for name in &self.names[1..] {
548 if self.features.get(name) != Some(&a) {
549 return FontFeatureState::auto();
550 }
551 }
552 FontFeatureState(Some(a))
553 } else {
554 FontFeatureState::auto()
555 }
556 }
557
558 pub fn is_enabled(&self) -> bool {
560 self.state().is_enabled()
561 }
562
563 pub fn is_disabled(&self) -> bool {
565 self.state().is_disabled()
566 }
567
568 pub fn is_auto(&self) -> bool {
570 self.state().is_auto()
571 }
572
573 pub fn set(self, state: impl Into<FontFeatureState>) -> FontFeatureState {
577 let prev = self.state();
578 match state.into().0 {
579 Some(n) => self.set_explicit(n),
580 None => self.auto(),
581 }
582 prev
583 }
584
585 fn set_explicit(self, state: u32) {
586 for name in self.names {
587 self.features.insert(*name, state);
588 }
589 }
590
591 pub fn enable(self) {
593 self.set_explicit(FEATURE_ENABLED);
594 }
595
596 pub fn disable(self) {
598 self.set_explicit(FEATURE_DISABLED);
599 }
600
601 pub fn auto(self) {
603 for name in self.names {
604 self.features.remove(name);
605 }
606 }
607}
608impl fmt::Debug for FontFeatureSet<'_> {
609 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
610 write!(f, "{:?}: {:?}", self.names, self.state())
611 }
612}
613
614pub struct FontFeatureExclusiveSet<'a, S: FontFeatureExclusiveSetState> {
617 features: &'a mut FontFeaturesMap,
618 _t: PhantomData<S>,
619}
620impl<S: FontFeatureExclusiveSetState> FontFeatureExclusiveSet<'_, S> {
621 pub fn names(&self) -> &'static [FontFeatureName] {
623 S::names()
624 }
625
626 pub fn state(&self) -> S {
628 let mut state = 0;
629
630 for (i, name) in S::names().iter().enumerate() {
631 if let Some(&s) = self.features.get(name) {
632 if s == FEATURE_ENABLED && state == 0 {
633 state = i + 1; continue;
635 }
636 }
637 return S::auto();
639 }
640 S::from_variant(state as u32)
641 }
642 fn take_state(&mut self) -> S {
643 let mut state = 0;
644 let mut skip = false;
645
646 for (i, name) in S::names().iter().enumerate() {
647 if let Some(s) = self.features.remove(name) {
648 if skip {
649 continue;
650 }
651
652 if s == FEATURE_ENABLED && state == 0 {
653 state = i + 1; continue;
655 }
656 }
657 skip = true;
659 }
660
661 S::from_variant(state as u32)
662 }
663
664 pub fn is_auto(&self) -> bool {
666 self.state() == S::auto()
667 }
668
669 pub fn set(&mut self, state: impl Into<S>) -> S {
673 let prev = self.take_state();
674 if let Some(state) = state.into().variant() {
675 self.features.insert(self.names()[state as usize - 1], FEATURE_ENABLED);
676 }
677 prev
678 }
679}
680impl<S: FontFeatureExclusiveSetState + fmt::Debug> fmt::Debug for FontFeatureExclusiveSet<'_, S> {
681 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
682 fmt::Debug::fmt(&self.state(), f)
683 }
684}
685
686pub struct FontFeatureExclusiveSets<'a, S: FontFeatureExclusiveSetsState> {
689 features: &'a mut FontFeaturesMap,
690 _t: PhantomData<S>,
691}
692impl<S: FontFeatureExclusiveSetsState> FontFeatureExclusiveSets<'_, S> {
693 pub fn names(&self) -> &'static [&'static [FontFeatureName]] {
695 S::names()
696 }
697
698 pub fn state(&self) -> S {
700 let mut active = HashSet::new();
701 for &names in self.names() {
702 for name in names {
703 if let Some(&s) = self.features.get(name) {
704 if s != FEATURE_ENABLED {
705 return S::auto();
707 } else {
708 active.insert(*name);
709 }
710 }
711 }
712 }
713
714 if !active.is_empty() {
715 'names: for (i, &names) in self.names().iter().enumerate() {
716 if names.len() == active.len() {
717 for name in names {
718 if !active.contains(name) {
719 continue 'names;
720 }
721 }
722 return S::from_variant(i as u32 + 1);
723 }
724 }
725 }
726
727 S::auto()
728 }
729 fn take_state(&mut self) -> S {
730 let mut active = HashSet::new();
731 let mut force_auto = false;
732
733 for &names in self.names() {
734 for name in names {
735 if let Some(s) = self.features.remove(name) {
736 if force_auto {
737 continue;
738 }
739
740 if s != FEATURE_ENABLED {
741 force_auto = true;
743 } else {
744 active.insert(name);
745 }
746 }
747 }
748 }
749
750 if !force_auto && !active.is_empty() {
751 'names: for (i, &names) in self.names().iter().enumerate() {
752 if names.len() == active.len() {
753 for name in names {
754 if !active.contains(name) {
755 continue 'names;
756 }
757 }
758 return S::from_variant(i as u32 + 1);
759 }
760 }
761 }
762
763 S::auto()
764 }
765
766 pub fn is_auto(&self) -> bool {
768 self.state() == S::auto()
769 }
770
771 pub fn set(&mut self, state: impl Into<S>) -> S {
775 let prev = self.take_state();
776 if let Some(state) = state.into().variant() {
777 for name in self.names()[state as usize - 1] {
778 self.features.insert(*name, FEATURE_ENABLED);
779 }
780 }
781 prev
782 }
783}
784impl<S: FontFeatureExclusiveSetsState + fmt::Debug> fmt::Debug for FontFeatureExclusiveSets<'_, S> {
785 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
786 fmt::Debug::fmt(&self.state(), f)
787 }
788}
789
790pub trait FontFeatureExclusiveSetState: Copy + PartialEq + 'static {
792 fn names() -> &'static [FontFeatureName];
794 fn variant(self) -> Option<u32>;
796 fn from_variant(v: u32) -> Self;
800 fn auto() -> Self;
802}
803
804pub trait FontFeatureExclusiveSetsState: Copy + PartialEq + 'static {
807 fn names() -> &'static [&'static [FontFeatureName]];
809 fn variant(self) -> Option<u32>;
811 fn from_variant(v: u32) -> Self;
815 fn auto() -> Self;
817}
818
819#[derive(Copy, Clone, PartialEq, Eq, Hash, Default)]
821pub struct FontFeatureState(Option<u32>);
822impl FontFeatureState {
823 pub const fn auto() -> Self {
825 FontFeatureState(None)
826 }
827
828 pub const fn enabled() -> Self {
830 FontFeatureState(Some(1))
831 }
832
833 pub const fn enabled_alt(alt: NonZeroU32) -> Self {
835 FontFeatureState(Some(alt.get()))
836 }
837
838 pub const fn disabled() -> Self {
840 FontFeatureState(Some(0))
841 }
842
843 pub fn is_auto(self) -> bool {
845 self.0.is_none()
846 }
847
848 pub fn is_enabled(self) -> bool {
850 if let Some(n) = self.0 {
851 if n >= 1 {
852 return true;
853 }
854 }
855 false
856 }
857
858 pub fn is_disabled(self) -> bool {
860 self == Self::disabled()
861 }
862
863 pub fn alt(self) -> Option<u32> {
865 if let Some(n) = self.0 {
866 if n >= 1 {
867 return Some(n);
868 }
869 }
870 None
871 }
872}
873impl fmt::Debug for FontFeatureState {
874 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
875 match self.0 {
876 Some(n) => {
877 if n == FEATURE_DISABLED {
878 write!(f, "FontFeatureState::disabled()")
879 } else if n == FEATURE_ENABLED {
880 write!(f, "FontFeatureState::enabled()")
881 } else {
882 write!(f, "FontFeatureState::enabled_alt({n})")
883 }
884 }
885 None => write!(f, "FontFeatureState::auto()"),
886 }
887 }
888}
889impl_from_and_into_var! {
890 fn from(enabled: bool) -> FontFeatureState {
891 if enabled {
892 FontFeatureState::enabled()
893 } else {
894 FontFeatureState::disabled()
895 }
896 }
897
898 fn from(alt: u32) -> FontFeatureState {
900 FontFeatureState(Some(alt))
901 }
902}
903
904#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
906#[repr(u8)]
907pub enum CapsVariant {
908 #[default]
910 Auto,
911
912 SmallCaps,
916
917 AllSmallCaps,
921
922 Petite,
926
927 AllPetite,
931
932 Unicase,
936
937 TitlingCaps,
941}
942impl fmt::Debug for CapsVariant {
943 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
944 if f.alternate() {
945 write!(f, "CapsVariant::")?;
946 }
947 match self {
948 CapsVariant::Auto => write!(f, "Auto"),
949 CapsVariant::SmallCaps => write!(f, "SmallCaps"),
950 CapsVariant::AllSmallCaps => write!(f, "AllSmallCaps"),
951 CapsVariant::Petite => write!(f, "Petite"),
952 CapsVariant::AllPetite => write!(f, "AllPetite"),
953 CapsVariant::Unicase => write!(f, "Unicase"),
954 CapsVariant::TitlingCaps => write!(f, "TitlingCaps"),
955 }
956 }
957}
958impl Default for CapsVariant {
959 fn default() -> Self {
961 CapsVariant::Auto
962 }
963}
964impl FontFeatureExclusiveSetsState for CapsVariant {
965 fn names() -> &'static [&'static [FontFeatureName]] {
966 static N0: [FontFeatureName; 1] = [FontFeatureName(*b"smcp")];
967 static N1: [FontFeatureName; 2] = [FontFeatureName(*b"c2sc"), FontFeatureName(*b"smcp")];
968 static N2: [FontFeatureName; 1] = [FontFeatureName(*b"pcap")];
969 static N3: [FontFeatureName; 2] = [FontFeatureName(*b"c2pc"), FontFeatureName(*b"pcap")];
970 static N4: [FontFeatureName; 1] = [FontFeatureName(*b"unic")];
971 static N5: [FontFeatureName; 1] = [FontFeatureName(*b"titl")];
972 static NAMES: [&[FontFeatureName]; 6] = [&N0, &N1, &N2, &N3, &N4, &N5];
973 &NAMES
974 }
975
976 fn variant(self) -> Option<u32> {
977 if self == CapsVariant::Auto { None } else { Some(self as u32) }
978 }
979
980 fn from_variant(v: u32) -> Self {
981 Self::from(v as u8)
982 }
983
984 fn auto() -> Self {
985 CapsVariant::Auto
986 }
987}
988
989#[derive(Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
991#[repr(u8)]
992pub enum NumVariant {
993 #[default]
995 Auto,
996 Lining,
1000 OldStyle,
1004}
1005impl fmt::Debug for NumVariant {
1006 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1007 if f.alternate() {
1008 write!(f, "NumVariant::")?;
1009 }
1010 match self {
1011 NumVariant::Auto => write!(f, "Auto"),
1012 NumVariant::Lining => write!(f, "Lining"),
1013 NumVariant::OldStyle => write!(f, "OldStyle"),
1014 }
1015 }
1016}
1017impl Default for NumVariant {
1018 fn default() -> Self {
1020 NumVariant::Auto
1021 }
1022}
1023impl FontFeatureExclusiveSetState for NumVariant {
1024 fn names() -> &'static [FontFeatureName] {
1025 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"lnum"), FontFeatureName(*b"onum")];
1026 &NAMES
1027 }
1028
1029 fn variant(self) -> Option<u32> {
1030 match self {
1031 NumVariant::Auto => None,
1032 NumVariant::Lining => Some(1),
1033 NumVariant::OldStyle => Some(2),
1034 }
1035 }
1036
1037 fn from_variant(v: u32) -> Self {
1038 Self::from(v as u8)
1039 }
1040
1041 fn auto() -> Self {
1042 NumVariant::Auto
1043 }
1044}
1045
1046#[derive(Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
1048#[repr(u8)]
1049pub enum NumSpacing {
1050 #[default]
1052 Auto,
1053 Proportional,
1057 Tabular,
1061}
1062impl fmt::Debug for NumSpacing {
1063 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1064 if f.alternate() {
1065 write!(f, "NumSpacing::")?;
1066 }
1067 match self {
1068 NumSpacing::Auto => write!(f, "Auto"),
1069 NumSpacing::Proportional => write!(f, "Proportional"),
1070 NumSpacing::Tabular => write!(f, "Tabular"),
1071 }
1072 }
1073}
1074impl Default for NumSpacing {
1075 fn default() -> Self {
1077 NumSpacing::Auto
1078 }
1079}
1080impl FontFeatureExclusiveSetState for NumSpacing {
1081 fn names() -> &'static [FontFeatureName] {
1082 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"pnum"), FontFeatureName(*b"tnum")];
1083 &NAMES
1084 }
1085
1086 fn variant(self) -> Option<u32> {
1087 match self {
1088 NumSpacing::Auto => None,
1089 NumSpacing::Proportional => Some(1),
1090 NumSpacing::Tabular => Some(2),
1091 }
1092 }
1093
1094 fn from_variant(v: u32) -> Self {
1095 Self::from(v as u8)
1096 }
1097
1098 fn auto() -> Self {
1099 NumSpacing::Auto
1100 }
1101}
1102
1103#[derive(Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
1105#[repr(u8)]
1106pub enum NumFraction {
1107 #[default]
1109 Auto,
1110 Diagonal,
1114 Stacked,
1118}
1119impl fmt::Debug for NumFraction {
1120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1121 if f.alternate() {
1122 write!(f, "NumFraction::")?;
1123 }
1124 match self {
1125 NumFraction::Auto => write!(f, "Auto"),
1126 NumFraction::Diagonal => write!(f, "Diagonal"),
1127 NumFraction::Stacked => write!(f, "Stacked"),
1128 }
1129 }
1130}
1131impl Default for NumFraction {
1132 fn default() -> Self {
1134 NumFraction::Auto
1135 }
1136}
1137impl FontFeatureExclusiveSetState for NumFraction {
1138 fn names() -> &'static [FontFeatureName] {
1139 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"frac"), FontFeatureName(*b"afrc")];
1140 &NAMES
1141 }
1142
1143 fn variant(self) -> Option<u32> {
1144 match self {
1145 NumFraction::Auto => None,
1146 NumFraction::Diagonal => Some(1),
1147 NumFraction::Stacked => Some(2),
1148 }
1149 }
1150
1151 fn from_variant(v: u32) -> Self {
1152 Self::from(v as u8)
1153 }
1154
1155 fn auto() -> Self {
1156 NumFraction::Auto
1157 }
1158}
1159
1160#[derive(Copy, Clone, Eq, PartialEq, Hash, FromPrimitive)]
1165#[repr(u8)]
1166#[allow(missing_docs)]
1167pub enum FontStyleSet {
1168 #[default]
1170 Auto = 0,
1171
1172 S01,
1173 S02,
1174 S03,
1175 S04,
1176 S05,
1177 S06,
1178 S07,
1179 S08,
1180 S09,
1181 S10,
1182
1183 S11,
1184 S12,
1185 S13,
1186 S14,
1187 S15,
1188 S16,
1189 S17,
1190 S18,
1191 S19,
1192 S20,
1193}
1194impl Default for FontStyleSet {
1195 fn default() -> Self {
1197 FontStyleSet::Auto
1198 }
1199}
1200impl fmt::Debug for FontStyleSet {
1201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1202 if f.alternate() {
1203 write!(f, "FontStyleSet::")?;
1204 }
1205 let n = *self as u8;
1206 if n == 0 { write!(f, "Auto") } else { write!(f, "S{n:0<2}") }
1207 }
1208}
1209impl_from_and_into_var! {
1210 fn from(set: u8) -> FontStyleSet;
1211}
1212
1213impl FontFeatureExclusiveSetState for FontStyleSet {
1214 fn names() -> &'static [FontFeatureName] {
1215 static NAMES: [FontFeatureName; 20] = [
1216 FontFeatureName(*b"ss01"),
1217 FontFeatureName(*b"ss02"),
1218 FontFeatureName(*b"ss03"),
1219 FontFeatureName(*b"ss04"),
1220 FontFeatureName(*b"ss05"),
1221 FontFeatureName(*b"ss06"),
1222 FontFeatureName(*b"ss07"),
1223 FontFeatureName(*b"ss08"),
1224 FontFeatureName(*b"ss09"),
1225 FontFeatureName(*b"ss10"),
1226 FontFeatureName(*b"ss11"),
1227 FontFeatureName(*b"ss12"),
1228 FontFeatureName(*b"ss13"),
1229 FontFeatureName(*b"ss14"),
1230 FontFeatureName(*b"ss15"),
1231 FontFeatureName(*b"ss16"),
1232 FontFeatureName(*b"ss17"),
1233 FontFeatureName(*b"ss18"),
1234 FontFeatureName(*b"ss19"),
1235 FontFeatureName(*b"ss20"),
1236 ];
1237 &NAMES
1238 }
1239
1240 fn variant(self) -> Option<u32> {
1241 if self == FontStyleSet::Auto { None } else { Some(self as u32) }
1242 }
1243
1244 fn from_variant(v: u32) -> Self {
1245 Self::from(v as u8)
1246 }
1247
1248 fn auto() -> Self {
1249 FontStyleSet::Auto
1250 }
1251}
1252
1253#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
1257pub struct CharVariant(u8);
1258impl CharVariant {
1259 pub const fn new(v: u8) -> Self {
1263 if v > 99 { CharVariant(0) } else { CharVariant(v) }
1264 }
1265
1266 pub const fn auto() -> Self {
1268 CharVariant(0)
1269 }
1270
1271 pub const fn is_auto(self) -> bool {
1273 self.0 == 0
1274 }
1275}
1276impl_from_and_into_var! {
1277 fn from(v: u8) -> CharVariant {
1279 CharVariant::new(v)
1280 }
1281}
1282impl FontFeatureExclusiveSetState for CharVariant {
1283 fn names() -> &'static [FontFeatureName] {
1284 static NAMES: [FontFeatureName; 100] = [
1285 FontFeatureName(*b"cv01"),
1286 FontFeatureName(*b"cv02"),
1287 FontFeatureName(*b"cv03"),
1288 FontFeatureName(*b"cv04"),
1289 FontFeatureName(*b"cv05"),
1290 FontFeatureName(*b"cv06"),
1291 FontFeatureName(*b"cv07"),
1292 FontFeatureName(*b"cv08"),
1293 FontFeatureName(*b"cv09"),
1294 FontFeatureName(*b"cv20"),
1295 FontFeatureName(*b"cv21"),
1296 FontFeatureName(*b"cv22"),
1297 FontFeatureName(*b"cv23"),
1298 FontFeatureName(*b"cv24"),
1299 FontFeatureName(*b"cv25"),
1300 FontFeatureName(*b"cv26"),
1301 FontFeatureName(*b"cv27"),
1302 FontFeatureName(*b"cv28"),
1303 FontFeatureName(*b"cv29"),
1304 FontFeatureName(*b"cv30"),
1305 FontFeatureName(*b"cv31"),
1306 FontFeatureName(*b"cv32"),
1307 FontFeatureName(*b"cv33"),
1308 FontFeatureName(*b"cv34"),
1309 FontFeatureName(*b"cv35"),
1310 FontFeatureName(*b"cv36"),
1311 FontFeatureName(*b"cv37"),
1312 FontFeatureName(*b"cv38"),
1313 FontFeatureName(*b"cv39"),
1314 FontFeatureName(*b"cv40"),
1315 FontFeatureName(*b"cv41"),
1316 FontFeatureName(*b"cv42"),
1317 FontFeatureName(*b"cv43"),
1318 FontFeatureName(*b"cv44"),
1319 FontFeatureName(*b"cv45"),
1320 FontFeatureName(*b"cv46"),
1321 FontFeatureName(*b"cv47"),
1322 FontFeatureName(*b"cv48"),
1323 FontFeatureName(*b"cv49"),
1324 FontFeatureName(*b"cv50"),
1325 FontFeatureName(*b"cv51"),
1326 FontFeatureName(*b"cv52"),
1327 FontFeatureName(*b"cv53"),
1328 FontFeatureName(*b"cv54"),
1329 FontFeatureName(*b"cv55"),
1330 FontFeatureName(*b"cv56"),
1331 FontFeatureName(*b"cv57"),
1332 FontFeatureName(*b"cv58"),
1333 FontFeatureName(*b"cv59"),
1334 FontFeatureName(*b"cv60"),
1335 FontFeatureName(*b"cv61"),
1336 FontFeatureName(*b"cv62"),
1337 FontFeatureName(*b"cv63"),
1338 FontFeatureName(*b"cv64"),
1339 FontFeatureName(*b"cv65"),
1340 FontFeatureName(*b"cv66"),
1341 FontFeatureName(*b"cv67"),
1342 FontFeatureName(*b"cv68"),
1343 FontFeatureName(*b"cv69"),
1344 FontFeatureName(*b"cv70"),
1345 FontFeatureName(*b"cv71"),
1346 FontFeatureName(*b"cv72"),
1347 FontFeatureName(*b"cv73"),
1348 FontFeatureName(*b"cv74"),
1349 FontFeatureName(*b"cv75"),
1350 FontFeatureName(*b"cv76"),
1351 FontFeatureName(*b"cv77"),
1352 FontFeatureName(*b"cv78"),
1353 FontFeatureName(*b"cv79"),
1354 FontFeatureName(*b"cv70"),
1355 FontFeatureName(*b"cv71"),
1356 FontFeatureName(*b"cv72"),
1357 FontFeatureName(*b"cv73"),
1358 FontFeatureName(*b"cv74"),
1359 FontFeatureName(*b"cv75"),
1360 FontFeatureName(*b"cv76"),
1361 FontFeatureName(*b"cv77"),
1362 FontFeatureName(*b"cv78"),
1363 FontFeatureName(*b"cv79"),
1364 FontFeatureName(*b"cv80"),
1365 FontFeatureName(*b"cv81"),
1366 FontFeatureName(*b"cv82"),
1367 FontFeatureName(*b"cv83"),
1368 FontFeatureName(*b"cv84"),
1369 FontFeatureName(*b"cv85"),
1370 FontFeatureName(*b"cv86"),
1371 FontFeatureName(*b"cv87"),
1372 FontFeatureName(*b"cv88"),
1373 FontFeatureName(*b"cv89"),
1374 FontFeatureName(*b"cv90"),
1375 FontFeatureName(*b"cv91"),
1376 FontFeatureName(*b"cv92"),
1377 FontFeatureName(*b"cv93"),
1378 FontFeatureName(*b"cv94"),
1379 FontFeatureName(*b"cv95"),
1380 FontFeatureName(*b"cv96"),
1381 FontFeatureName(*b"cv97"),
1382 FontFeatureName(*b"cv98"),
1383 FontFeatureName(*b"cv99"),
1384 FontFeatureName(*b"cv99"),
1385 ];
1386 &NAMES
1387 }
1388
1389 fn variant(self) -> Option<u32> {
1390 if self.is_auto() { None } else { Some(self.0 as u32) }
1391 }
1392
1393 fn from_variant(v: u32) -> Self {
1394 if v > 99 { CharVariant::auto() } else { CharVariant(v as u8) }
1395 }
1396
1397 fn auto() -> Self {
1398 CharVariant::auto()
1399 }
1400}
1401
1402#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
1404#[repr(u8)]
1405pub enum FontPosition {
1406 #[default]
1408 Auto,
1409 Sub,
1413 Super,
1417}
1418impl fmt::Debug for FontPosition {
1419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1420 if f.alternate() {
1421 write!(f, "FontPosition::")?;
1422 }
1423 match self {
1424 FontPosition::Auto => write!(f, "Auto"),
1425 FontPosition::Sub => write!(f, "Sub"),
1426 FontPosition::Super => write!(f, "Super"),
1427 }
1428 }
1429}
1430impl Default for FontPosition {
1431 fn default() -> Self {
1433 FontPosition::Auto
1434 }
1435}
1436impl FontFeatureExclusiveSetState for FontPosition {
1437 fn names() -> &'static [FontFeatureName] {
1438 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"subs"), FontFeatureName(*b"sups")];
1439 &NAMES
1440 }
1441
1442 fn variant(self) -> Option<u32> {
1443 match self {
1444 FontPosition::Auto => None,
1445 FontPosition::Sub => Some(1),
1446 FontPosition::Super => Some(2),
1447 }
1448 }
1449
1450 fn from_variant(v: u32) -> Self {
1451 Self::from(v as u8)
1452 }
1453
1454 fn auto() -> Self {
1455 FontPosition::Auto
1456 }
1457}
1458
1459#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
1461#[repr(u8)]
1462pub enum JpVariant {
1463 #[default]
1465 Auto,
1466
1467 Jis78,
1471 Jis83,
1475 Jis90,
1479
1480 Jis04,
1484 NlcKanji,
1488}
1489impl fmt::Debug for JpVariant {
1490 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1491 if f.alternate() {
1492 write!(f, "JpVariant::")?;
1493 }
1494 match self {
1495 JpVariant::Auto => write!(f, "Auto"),
1496 JpVariant::Jis78 => write!(f, "Jis78"),
1497 JpVariant::Jis83 => write!(f, "Jis83"),
1498 JpVariant::Jis90 => write!(f, "Jis90"),
1499 JpVariant::Jis04 => write!(f, "Jis04"),
1500 JpVariant::NlcKanji => write!(f, "NlcKanji"),
1501 }
1502 }
1503}
1504impl Default for JpVariant {
1505 fn default() -> Self {
1507 JpVariant::Auto
1508 }
1509}
1510impl FontFeatureExclusiveSetState for JpVariant {
1511 fn names() -> &'static [FontFeatureName] {
1512 static NAMES: [FontFeatureName; 5] = [
1513 FontFeatureName(*b"jp78"),
1514 FontFeatureName(*b"jp83"),
1515 FontFeatureName(*b"jp90"),
1516 FontFeatureName(*b"jp04"),
1517 FontFeatureName(*b"nlck"),
1518 ];
1519 &NAMES
1520 }
1521
1522 fn variant(self) -> Option<u32> {
1523 if self == JpVariant::Auto { None } else { Some(self as u32) }
1524 }
1525
1526 fn from_variant(v: u32) -> Self {
1527 Self::from(v as u8)
1528 }
1529
1530 fn auto() -> Self {
1531 JpVariant::Auto
1532 }
1533}
1534#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
1536#[repr(u8)]
1537pub enum CnVariant {
1538 #[default]
1540 Auto,
1541 Simplified,
1545 Traditional,
1549}
1550impl fmt::Debug for CnVariant {
1551 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1552 if f.alternate() {
1553 write!(f, "CnVariant")?;
1554 }
1555 match self {
1556 CnVariant::Auto => write!(f, "Auto"),
1557 CnVariant::Simplified => write!(f, "Simplified"),
1558 CnVariant::Traditional => write!(f, "Traditional"),
1559 }
1560 }
1561}
1562impl Default for CnVariant {
1563 fn default() -> Self {
1565 CnVariant::Auto
1566 }
1567}
1568impl FontFeatureExclusiveSetState for CnVariant {
1569 fn names() -> &'static [FontFeatureName] {
1570 static NAMES: [FontFeatureName; 2] = [FontFeatureName(*b"smpl"), FontFeatureName(*b"trad")];
1571 &NAMES
1572 }
1573
1574 fn variant(self) -> Option<u32> {
1575 match self {
1576 CnVariant::Auto => None,
1577 CnVariant::Simplified => Some(1),
1578 CnVariant::Traditional => Some(2),
1579 }
1580 }
1581
1582 fn from_variant(v: u32) -> Self {
1583 Self::from(v as u8)
1584 }
1585
1586 fn auto() -> Self {
1587 CnVariant::Auto
1588 }
1589}
1590
1591#[derive(Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
1593#[repr(u8)]
1594pub enum EastAsianWidth {
1595 #[default]
1597 Auto,
1598
1599 Proportional,
1603
1604 ProportionalAlt,
1608
1609 ProportionalKana,
1613
1614 Full,
1618
1619 Half,
1623
1624 HalfAlt,
1628
1629 Third,
1633
1634 Quarter,
1638}
1639impl fmt::Debug for EastAsianWidth {
1640 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1641 if f.alternate() {
1642 write!(f, "EastAsianWidth::")?;
1643 }
1644 match self {
1645 EastAsianWidth::Auto => write!(f, "Auto"),
1646 EastAsianWidth::Proportional => write!(f, "Proportional"),
1647 EastAsianWidth::ProportionalAlt => write!(f, "ProportionalAlt"),
1648 EastAsianWidth::ProportionalKana => write!(f, "ProportionalKana"),
1649 EastAsianWidth::Full => write!(f, "Full"),
1650 EastAsianWidth::Half => write!(f, "Half"),
1651 EastAsianWidth::HalfAlt => write!(f, "HalfAlt"),
1652 EastAsianWidth::Third => write!(f, "Third"),
1653 EastAsianWidth::Quarter => write!(f, "Quarter"),
1654 }
1655 }
1656}
1657impl Default for EastAsianWidth {
1658 fn default() -> Self {
1660 EastAsianWidth::Auto
1661 }
1662}
1663impl FontFeatureExclusiveSetState for EastAsianWidth {
1664 fn names() -> &'static [FontFeatureName] {
1665 static NAMES: [FontFeatureName; 8] = [
1666 FontFeatureName(*b"pwid"),
1667 FontFeatureName(*b"palt"),
1668 FontFeatureName(*b"pkna"),
1669 FontFeatureName(*b"fwid"),
1670 FontFeatureName(*b"hwid"),
1671 FontFeatureName(*b"halt"),
1672 FontFeatureName(*b"twid"),
1673 FontFeatureName(*b"qwid"),
1674 ];
1675 &NAMES
1676 }
1677
1678 fn variant(self) -> Option<u32> {
1679 if self == EastAsianWidth::Auto { None } else { Some(self as u32) }
1680 }
1681
1682 fn from_variant(v: u32) -> Self {
1683 Self::from(v as u8)
1684 }
1685
1686 fn auto() -> Self {
1687 EastAsianWidth::Auto
1688 }
1689}
1690
1691#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1700pub struct FontVariationName(pub [u8; 4]);
1701impl FontVariationName {
1702 pub fn as_str(&self) -> &str {
1704 std::str::from_utf8(&self.0).unwrap_or_default()
1705 }
1706}
1707impl From<&'static [u8; 4]> for FontVariationName {
1708 fn from(name: &'static [u8; 4]) -> Self {
1709 FontVariationName(*name)
1710 }
1711}
1712impl From<FontVariationName> for ttf_parser::Tag {
1713 fn from(value: FontVariationName) -> Self {
1714 ttf_parser::Tag::from_bytes(&value.0)
1715 }
1716}
1717impl ops::Deref for FontVariationName {
1718 type Target = [u8; 4];
1719
1720 fn deref(&self) -> &Self::Target {
1721 &self.0
1722 }
1723}
1724impl fmt::Debug for FontVariationName {
1725 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1726 if self.as_str().is_empty() {
1727 write!(f, "{:?}", self.0)
1728 } else {
1729 write!(f, "{}", self.as_str())
1730 }
1731 }
1732}
1733impl fmt::Display for FontVariationName {
1734 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1735 write!(f, "{self:?}")
1736 }
1737}
1738
1739#[derive(Default, Clone, PartialEq)]
1743pub struct FontVariations(Vec<(FontVariationName, f32)>);
1744impl FontVariations {
1745 pub fn new() -> Self {
1747 Self::default()
1748 }
1749
1750 pub fn with_capacity(capacity: usize) -> Self {
1752 Self(Vec::with_capacity(capacity))
1753 }
1754
1755 pub fn from_pairs(pairs: &[(FontVariationName, f32)]) -> Self {
1757 let mut r = Self::with_capacity(pairs.len());
1758 for (name, value) in pairs {
1759 r.insert(*name, *value);
1760 }
1761 r
1762 }
1763
1764 pub fn insert(&mut self, name: FontVariationName, value: f32) -> Option<f32> {
1766 if let Some(entry) = self.0.iter_mut().find(|v| v.0 == name) {
1767 let prev = Some(entry.1);
1768 entry.1 = value;
1769 prev
1770 } else {
1771 self.0.push((name, value));
1772 None
1773 }
1774 }
1775
1776 pub fn remove(&mut self, name: FontVariationName) -> Option<f32> {
1778 if let Some(i) = self.0.iter().position(|v| v.0 == name) {
1779 Some(self.0.swap_remove(i).1)
1780 } else {
1781 None
1782 }
1783 }
1784
1785 pub fn contains(&self, name: FontVariationName) -> bool {
1787 self.0.iter().any(|v| v.0 == name)
1788 }
1789
1790 pub fn get(&self, name: FontVariationName) -> Option<f32> {
1792 self.0.iter().find(|v| v.0 == name).map(|v| v.1)
1793 }
1794
1795 pub fn get_mut(&mut self, name: FontVariationName) -> Option<&mut f32> {
1797 self.0.iter_mut().find(|v| v.0 == name).map(|v| &mut v.1)
1798 }
1799
1800 pub fn len(&self) -> usize {
1802 self.0.len()
1803 }
1804
1805 pub fn is_empty(&self) -> bool {
1807 self.0.is_empty()
1808 }
1809
1810 pub fn finalize(&self) -> RFontVariations {
1812 self.0
1813 .iter()
1814 .map(|(name, value)| rustybuzz::Variation {
1815 tag: (*name).into(),
1816 value: *value,
1817 })
1818 .collect()
1819 }
1820}
1821impl fmt::Debug for FontVariations {
1822 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1823 if f.alternate() {
1824 f.debug_tuple("FontVariations").field(&self.0).finish()
1825 } else {
1826 write!(f, "[")?;
1827 let mut first = false;
1828 for entry in &self.0 {
1829 if first {
1830 first = false;
1831 } else {
1832 write!(f, ", ")?;
1833 }
1834 write!(f, r#", b"{}": {}"#, entry.0, entry.1)?;
1835 }
1836 write!(f, "]")
1837 }
1838 }
1839}
1840
1841#[macro_export]
1855macro_rules! font_variations {
1856 [$(
1857 $name:tt : $value: expr
1858 ),* $(,)?] => {
1859 $crate::font_features::FontVariations::from_pairs(&[
1860 $(
1861 ($name.into(), $value),
1862 )*
1863 ])
1864 }
1865}
1866#[doc(inline)]
1867pub use font_variations;
1868use zng_var::impl_from_and_into_var;
1869
1870pub type RFontVariations = Vec<rustybuzz::Variation>;