1 //! This module allows you to use rusttype to provide the font operations that harfbuzz needs.
2 
3 use crate::common::Tag;
4 pub use rusttype::Error;
5 use rusttype::Font as RTFont;
6 use rusttype::{Codepoint, GlyphId, Scale};
7 
8 use crate::face;
9 use crate::font;
10 use crate::font::{Font, FontFuncs, Glyph as GlyphIndex, GlyphExtents, Position};
11 
12 use std;
13 use std::fmt::Debug;
14 use std::str::FromStr;
15 
16 // Work around weird rusttype scaling by reading the hhea table.
get_font_height(font: &font::Font<'_>) -> Result<i32, Error>17 fn get_font_height(font: &font::Font<'_>) -> Result<i32, Error> {
18     let face = font.face();
19     let tag = Tag::from_str("hhea").unwrap();
20     let hhea_table = face.table_with_tag(tag).ok_or(Error::IllFormed)?;
21     if hhea_table.len() >= 8 {
22         unsafe {
23             let ascent_ptr = (&hhea_table)[4..6].as_ptr() as *const i16;
24             let ascent = i16::from_be(*ascent_ptr);
25             let descent_ptr = (&hhea_table)[6..8].as_ptr() as *const i16;
26             let descent = i16::from_be(*descent_ptr);
27             Ok(ascent as i32 - descent as i32)
28         }
29     } else {
30         Err(Error::IllFormed)
31     }
32 }
33 
rusttype_font_from_face<'a>(face: &face::Face<'a>) -> Result<RTFont<'a>, Error>34 fn rusttype_font_from_face<'a>(face: &face::Face<'a>) -> Result<RTFont<'a>, Error> {
35     // It is unfortunate that we have to copy the face data here.
36     let font_blob = face.face_data().as_ref().to_owned();
37     let index = face.index();
38     let collection = rusttype::FontCollection::from_bytes(font_blob)?;
39     collection.font_at(index as usize)
40 }
41 
rusttype_scale_from_hb_font(font: &font::Font<'_>) -> Result<Scale, Error>42 fn rusttype_scale_from_hb_font(font: &font::Font<'_>) -> Result<Scale, Error> {
43     let font_height = get_font_height(font)? as f32;
44     let em_scale = font.scale();
45     let x_scale = em_scale.0 as f32;
46     let y_scale = em_scale.1 as f32;
47     Ok(Scale {
48         x: font_height * x_scale / y_scale,
49         y: font_height,
50     })
51 }
52 
53 struct ScaledRusttypeFont<'a> {
54     font: rusttype::Font<'a>,
55     scale: Scale,
56 }
57 
58 impl<'a> Debug for ScaledRusttypeFont<'a> {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result59     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60         f.debug_struct("ScaledRusttypeFont")
61             .field("scale", &self.scale)
62             .finish()
63     }
64 }
65 
66 impl<'a> ScaledRusttypeFont<'a> {
from_hb_font<'b>(hb_font: &font::Font<'b>) -> Result<ScaledRusttypeFont<'b>, Error>67     fn from_hb_font<'b>(hb_font: &font::Font<'b>) -> Result<ScaledRusttypeFont<'b>, Error> {
68         let font = rusttype_font_from_face(&hb_font.face())?;
69         let scale = rusttype_scale_from_hb_font(hb_font)?;
70         Ok(ScaledRusttypeFont { font, scale })
71     }
72 }
73 
74 impl<'a> FontFuncs for ScaledRusttypeFont<'a> {
get_glyph_h_advance(&self, _: &Font<'_>, glyph: GlyphIndex) -> Position75     fn get_glyph_h_advance(&self, _: &Font<'_>, glyph: GlyphIndex) -> Position {
76         let glyph = self.font.glyph(GlyphId(glyph));
77         let glyph = glyph.scaled(self.scale);
78         glyph.h_metrics().advance_width.round() as Position
79     }
get_glyph_extents(&self, _: &Font<'_>, glyph: GlyphIndex) -> Option<GlyphExtents>80     fn get_glyph_extents(&self, _: &Font<'_>, glyph: GlyphIndex) -> Option<GlyphExtents> {
81         let glyph = self.font.glyph(GlyphId(glyph));
82         let glyph = glyph.scaled(self.scale);
83         glyph.exact_bounding_box().map(|bbox| GlyphExtents {
84             x_bearing: bbox.min.x.round() as i32,
85             y_bearing: bbox.min.y.round() as i32,
86             width: (bbox.max.x - bbox.min.x).round() as i32,
87             height: (bbox.max.y - bbox.min.y).round() as i32,
88         })
89     }
get_nominal_glyph(&self, _: &font::Font<'_>, unicode: char) -> Option<GlyphIndex>90     fn get_nominal_glyph(&self, _: &font::Font<'_>, unicode: char) -> Option<GlyphIndex> {
91         let glyph = self.font.glyph(Codepoint(unicode as u32));
92         Some(glyph.id().0)
93     }
94 }
95 
96 use std::sync::Arc;
97 
98 /// Creates a new HarfBuzz `Font` object that uses RustType to provide font data.
99 ///
100 /// # Examples
101 ///
102 /// Create a basic font that uses rusttype font funcs:
103 /// ```
104 /// use std::fs;
105 /// use std::sync::Arc;
106 ///
107 /// use harfbuzz_rs::rusttype::create_harfbuzz_rusttype_font;
108 ///
109 /// let path = "testfiles/SourceSansVariable-Roman.ttf";
110 /// let bytes: Arc<[u8]> = fs::read(path).unwrap().into();
111 /// let font = create_harfbuzz_rusttype_font(bytes, 0);
112 /// ```
create_harfbuzz_rusttype_font( bytes: impl Into<Arc<[u8]>>, index: u32, ) -> Result<crate::Owned<Font<'static>>, Error>113 pub fn create_harfbuzz_rusttype_font(
114     bytes: impl Into<Arc<[u8]>>,
115     index: u32,
116 ) -> Result<crate::Owned<Font<'static>>, Error> {
117     let bytes = bytes.into();
118     let face = crate::Face::new(bytes.clone(), index);
119     let mut font = Font::new(face);
120 
121     let rt_font = rusttype::FontCollection::from_bytes(bytes)?.font_at(index as usize)?;
122     let scaled_font = ScaledRusttypeFont {
123         font: rt_font,
124         scale: rusttype_scale_from_hb_font(&font)?,
125     };
126     font.set_font_funcs(scaled_font);
127 
128     Ok(font)
129 }
130 
131 /// Extends the harfbuzz font to allow setting RustType as font funcs provider.
132 #[deprecated(since = "0.4.0")]
133 pub trait SetRustTypeFuncs {
134     /// Let a font use rusttype's font API for getting information like the
135     /// advance width of some glyph or its extents.
136     ///
137     /// # Deprecated
138     ///
139     /// This function is deprecated because it doesn't fit well with the design
140     /// of RustType (Calling this method requires to make a copy of the font
141     /// data used). You should use `create_harfbuzz_rusttype_font` instead.
142     #[deprecated(since = "0.4.0")]
set_rusttype_funcs(&mut self) -> Result<(), Error>143     fn set_rusttype_funcs(&mut self) -> Result<(), Error>;
144 }
145 
146 #[allow(deprecated)]
147 impl<'a> SetRustTypeFuncs for Font<'a> {
set_rusttype_funcs(&mut self) -> Result<(), Error>148     fn set_rusttype_funcs(&mut self) -> Result<(), Error> {
149         let font_data = ScaledRusttypeFont::from_hb_font(self)?;
150         self.set_font_funcs(font_data);
151         Ok(())
152     }
153 }
154