1
#![deny(missing_docs)]
2

            
3
//! Bitmap font handling.
4

            
5
pub mod cbdt;
6
pub mod sbix;
7

            
8
use crate::error::ParseError;
9

            
10
/// Bit depth of bitmap data.
11
#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd)]
12
pub enum BitDepth {
13
    /// 1-bit per pixel (black and white).
14
    One = 1,
15
    /// 2-bits per pixel (grey).
16
    Two = 2,
17
    /// 4-bits per pixel (grey).
18
    Four = 4,
19
    /// 8-bits per pixel (grey).
20
    Eight = 8,
21
    /// 32-bits per pixel (RGBA)
22
    ThirtyTwo = 32,
23
}
24

            
25
/// A bitmap glyph with metrics.
26
pub struct BitmapGlyph {
27
    /// Horizontal pixels per em.
28
    ///
29
    /// Will be `None` if image data is a vector image.
30
    pub ppem_x: Option<u16>,
31
    /// Vertical pixels per em.
32
    ///
33
    /// Will be `None` if image data is a vector image.
34
    pub ppem_y: Option<u16>,
35
    /// `true` if this glyph's bitmap data should be flipped horizontally.
36
    pub should_flip_hori: bool,
37
    /// Glyph metrics in pixels.
38
    pub metrics: Metrics,
39
    /// Bitmap data.
40
    pub bitmap: Bitmap,
41
    /// Glyph index the bitmap data originates from, which can differ from the actual glyph index.
42
    ///
43
    /// E.g. an sbix glyph can point to bitmap data belonging to a different glyph altogether.
44
    pub bitmap_id: u16,
45
}
46

            
47
/// Bitmap data, either raw or encapsulated in a container format like PNG.
48
#[allow(missing_docs)]
49
pub enum Bitmap {
50
    Embedded(EmbeddedBitmap),
51
    Encapsulated(EncapsulatedBitmap),
52
}
53

            
54
/// Raw bitmap data.
55
pub struct EmbeddedBitmap {
56
    /// The width of the bitmap in pixels.
57
    pub width: u8,
58
    /// The height of the bitmap in pixels.
59
    pub height: u8,
60
    /// The format of the pixel data.
61
    pub format: BitDepth,
62
    /// Raw pixel data.
63
    pub data: Box<[u8]>,
64
}
65

            
66
/// Bitmap data encapsulated in a container format like PNG.
67
pub struct EncapsulatedBitmap {
68
    /// The container format used to hold the bitmap data.
69
    pub format: EncapsulatedFormat,
70
    /// Bitmap data.
71
    pub data: Box<[u8]>,
72
}
73

            
74
/// The container format of an `EncapsulatedBitmap`.
75
#[allow(missing_docs)]
76
pub enum EncapsulatedFormat {
77
    Jpeg,
78
    Png,
79
    Tiff,
80
    Svg,
81
    /// A format not part of the OpenType specification.
82
    Other(u32),
83
}
84

            
85
/// Bitmap glyph metrics either embedded or from `hmtx`/`vmtx`.
86
#[derive(Debug)]
87
pub enum Metrics {
88
    /// Metrics were embedded with the bitmap.
89
    Embedded(EmbeddedMetrics),
90
    /// Metrics are available in the `hmtx` and `vmtx` tables.
91
    HmtxVmtx(OriginOffset),
92
}
93

            
94
/// Bitmap offset from glyph origin in font units.
95
#[derive(Debug)]
96
pub struct OriginOffset {
97
    /// The horizontal (x-axis) offset from the left edge of the graphic to the glyph’s origin.
98
    pub x: i16,
99
    /// The vertical (y-axis) offset from the bottom edge of the graphic to the glyph’s origin.
100
    pub y: i16,
101
}
102

            
103
/// Metrics embedded alongside the bitmap.
104
///
105
/// One or both of the horizontal or vertical metrics with always be present.
106
#[derive(Debug)]
107
pub struct EmbeddedMetrics {
108
    /// Horizontal pixels per em.
109
    pub ppem_x: u8,
110
    /// Vertical pixels per em.
111
    pub ppem_y: u8,
112
    /// Horizontal metrics.
113
    hori: Option<BitmapMetrics>,
114
    /// Vertical metrics.
115
    vert: Option<BitmapMetrics>,
116
}
117

            
118
/// The actual embedded bitmap glyph metrics in pixels.
119
#[derive(Copy, Clone, Debug)]
120
pub struct BitmapMetrics {
121
    /// Distance in pixels from the horizontal origin to the left edge of the bitmap.
122
    pub origin_offset_x: i16,
123
    /// Distance in pixels from the horizontal origin to the bottom edge of the bitmap.
124
    pub origin_offset_y: i16,
125
    /// Advance width in pixels.
126
    pub advance: u8,
127
    /// The spacing of the line before the baseline in pixels.
128
    pub ascender: i8,
129
    /// The spacing of the line after the baseline in pixels.
130
    pub descender: i8,
131
}
132

            
133
impl EmbeddedMetrics {
134
    fn new(
135
        ppem_x: u8,
136
        ppem_y: u8,
137
        hori: Option<BitmapMetrics>,
138
        vert: Option<BitmapMetrics>,
139
    ) -> Result<Self, ParseError> {
140
        if hori.is_none() && vert.is_none() {
141
            return Err(ParseError::MissingValue);
142
        }
143

            
144
        Ok(EmbeddedMetrics {
145
            ppem_x,
146
            ppem_y,
147
            hori,
148
            vert,
149
        })
150
    }
151

            
152
    /// Metrics for horizontal layout.
153
    pub fn hori(&self) -> Option<&BitmapMetrics> {
154
        self.hori.as_ref()
155
    }
156

            
157
    /// Metrics for vertical layout.
158
    pub fn vert(&self) -> Option<&BitmapMetrics> {
159
        self.vert.as_ref()
160
    }
161
}
162

            
163
/// Returns true if `value` is closer to zero than `current_best`, favouring positive values even
164
/// if they're further away from zero.
165
///
166
/// Both call sites pass an `i16` or `i32` "ppem difference"; widening to `i32` keeps a
167
/// single concrete impl with no runtime cost.
168
fn bigger_or_closer_to_zero(value: i32, current_best: i32) -> bool {
169
    if value == 0 {
170
        return true;
171
    } else if current_best == 0 {
172
        return false;
173
    }
174

            
175
    match (current_best > 0, value > 0) {
176
        (true, true) if value < current_best => true,
177
        (true, false) => false,
178
        (false, true) => true,
179
        (false, false) if value > current_best => true,
180
        _ => false,
181
    }
182
}
183

            
184
#[cfg(test)]
185
mod tests {
186
    use super::*;
187

            
188
    #[test]
189
    fn test_bigger_or_closer_to_zero() {
190
        // zero always wins
191
        assert!(bigger_or_closer_to_zero(0, -1));
192
        assert!(bigger_or_closer_to_zero(0, 0));
193
        assert!(bigger_or_closer_to_zero(0, 1));
194
        assert!(!bigger_or_closer_to_zero(-1, 0));
195
        assert!(!bigger_or_closer_to_zero(1, 0));
196

            
197
        // current best is negative
198
        assert!(bigger_or_closer_to_zero(10, -5)); // positive wins, even if further from zero
199
        assert!(bigger_or_closer_to_zero(-2, -5)); // negative wins if closer to zero
200
        assert!(!bigger_or_closer_to_zero(-7, -5));
201

            
202
        // current best is positive
203
        assert!(bigger_or_closer_to_zero(2, 5)); // positive wins if smaller
204
        assert!(!bigger_or_closer_to_zero(-2, 5)); // positive wins, even if further from zero
205
        assert!(!bigger_or_closer_to_zero(7, 5));
206
    }
207
}