fontcull_write_fonts/tables/
glyf.rs1use crate::{
4 from_obj::{FromObjRef, FromTableRef},
5 validate::{Validate, ValidationCtx},
6 FontWrite, OtRound, TableWriter,
7};
8
9use fontcull_font_types::Tag;
10use fontcull_read_fonts::{FontRead, TopLevelTable};
11use kurbo::Rect;
12
13mod composite;
14mod glyf_loca_builder;
15mod simple;
16
17pub use composite::{Anchor, Component, ComponentFlags, CompositeGlyph, Transform};
18pub use glyf_loca_builder::{GlyfLocaBuilder, SomeGlyph};
19pub use simple::{Contour, MalformedPath, SimpleGlyph};
20
21#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub struct Glyf(Vec<u8>);
30
31impl TopLevelTable for Glyf {
32 const TAG: Tag = Tag::new(b"glyf");
34}
35
36#[derive(Clone, Debug, PartialEq, Eq)]
38pub enum Glyph {
39 Empty,
41 Simple(SimpleGlyph),
42 Composite(CompositeGlyph),
43}
44
45#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
51pub struct Bbox {
52 pub x_min: i16,
53 pub y_min: i16,
54 pub x_max: i16,
55 pub y_max: i16,
56}
57
58impl Glyph {
59 pub fn bbox(&self) -> Option<Bbox> {
61 match self {
62 Glyph::Empty => None,
63 Glyph::Simple(glyph) => Some(glyph.bbox),
64 Glyph::Composite(glyph) => Some(glyph.bbox),
65 }
66 }
67}
68
69impl Bbox {
70 pub fn union(self, other: Bbox) -> Bbox {
72 Bbox {
73 x_min: self.x_min.min(other.x_min),
74 y_min: self.y_min.min(other.y_min),
75 x_max: self.x_max.max(other.x_max),
76 y_max: self.y_max.max(other.y_max),
77 }
78 }
79}
80
81impl From<Rect> for Bbox {
82 fn from(value: Rect) -> Self {
83 Bbox {
84 x_min: value.min_x().ot_round(),
85 y_min: value.min_y().ot_round(),
86 x_max: value.max_x().ot_round(),
87 y_max: value.max_y().ot_round(),
88 }
89 }
90}
91
92impl FontWrite for Bbox {
93 fn write_into(&self, writer: &mut crate::TableWriter) {
94 let Bbox {
95 x_min,
96 y_min,
97 x_max,
98 y_max,
99 } = *self;
100 [x_min, y_min, x_max, y_max].write_into(writer)
101 }
102}
103
104impl<'a> FromObjRef<fontcull_read_fonts::tables::glyf::Glyph<'a>> for Glyph {
105 fn from_obj_ref(
106 from: &fontcull_read_fonts::tables::glyf::Glyph<'a>,
107 data: fontcull_read_fonts::FontData,
108 ) -> Self {
109 match from {
110 fontcull_read_fonts::tables::glyf::Glyph::Simple(glyph) => {
111 Self::Simple(SimpleGlyph::from_obj_ref(glyph, data))
112 }
113 fontcull_read_fonts::tables::glyf::Glyph::Composite(glyph) => {
114 Self::Composite(CompositeGlyph::from_obj_ref(glyph, data))
115 }
116 }
117 }
118}
119
120impl FromTableRef<fontcull_read_fonts::tables::glyf::Glyph<'_>> for Glyph {}
121
122impl<'a> FontRead<'a> for Glyph {
123 fn read(
124 data: fontcull_read_fonts::FontData<'a>,
125 ) -> Result<Self, fontcull_read_fonts::ReadError> {
126 fontcull_read_fonts::tables::glyf::Glyph::read(data).map(|g| Glyph::from_table_ref(&g))
127 }
128}
129
130impl From<SimpleGlyph> for Glyph {
131 fn from(value: SimpleGlyph) -> Self {
132 if value.contours.is_empty() {
133 Glyph::Empty
134 } else {
135 Glyph::Simple(value)
136 }
137 }
138}
139
140impl From<CompositeGlyph> for Glyph {
141 fn from(value: CompositeGlyph) -> Self {
142 Glyph::Composite(value)
143 }
144}
145
146impl Validate for Glyph {
147 fn validate_impl(&self, ctx: &mut ValidationCtx) {
148 match self {
149 Glyph::Empty => (),
150 Glyph::Simple(glyph) => glyph.validate_impl(ctx),
151 Glyph::Composite(glyph) => glyph.validate_impl(ctx),
152 }
153 }
154}
155
156impl FontWrite for Glyph {
157 fn write_into(&self, writer: &mut crate::TableWriter) {
158 match self {
159 Glyph::Empty => (),
160 Glyph::Simple(glyph) => glyph.write_into(writer),
161 Glyph::Composite(glyph) => glyph.write_into(writer),
162 }
163 }
164}
165
166impl Validate for Glyf {
167 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
168}
169
170impl FontWrite for Glyf {
171 fn write_into(&self, writer: &mut TableWriter) {
172 writer.write_slice(&self.0)
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn union_box() {
182 assert_eq!(
183 Bbox {
184 x_min: -1,
185 y_min: -2,
186 x_max: 5,
187 y_max: 6
188 },
189 Bbox {
190 x_min: 0,
191 y_min: 0,
192 x_max: 5,
193 y_max: 6
194 }
195 .union(Bbox {
196 x_min: -1,
197 y_min: -2,
198 x_max: 3,
199 y_max: 4
200 })
201 )
202 }
203}