1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
//! Pre-rasterized bitmap font from "Noto Sans Mono", an open font from Google. \
//! * Original font files taken from: <https://fonts.google.com/noto/specimen/Noto+Sans+Mono>
//! * License: SIL Open Font License (OFL) <https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL>
//!
//! Strictly speaking, this crate is more than a basic bitmap font, because it encodes each pixel
//! as a byte and not as a bit, which results in a much nicer result on the screen.
//!
//! ## TL;DR
//! * ✅ `no_std`, zero allocations, no floating point operations
//! * ✅ most important symbols, numbers, and letters as pre-rasterized bitmap
//! * ✅ Noto Sans Mono font as base
//! * ✅ different sizes and font weights (light, normal, bold)
//! * ✅ nice anti-aliasing/smoothing and better looking than legacy bitmap fonts
//! * ✅ every pixel is encoded in a byte (0-255) and not a bit, which results in a much nicer result on the screen.
//! * ✅ relevant font sizes, such as 14, 16, 24, 32, and 64px (as optional build time features)
//!
//! ## Terminology: Is Bitmap Font The Right Term?
//! Legacy (8x8) bitmap fonts usually refer to a font where each symbol is encoded in 8 bytes. The ones in a byte
//! (`0b00110000`) means "pixel on" and the zeroes' means "pixel off". However, my bitmap font actually encodes the
//! intensity of each pixel as a byte from 0 to 255. Hence, this is less size efficient than legacy bitmap fonts,
//! but looks much better. Thus, I still use the term bitmap font, because that term is used and known when talking
//! about pre-rasterized fonts/font rendering in an early stage of the boot process.
//!
//! ## When To Use This Crate
//! If you develop a kernel, you usually don't want to use the FPU (i.e. only soft float),
//! because otherwise you need to save the floating point registers on every context switch,
//! which is expensive. Because nice font rendering of TTF fonts heavily relies on many
//! floating point operations, this is not optimal inside a kernel (noticeable performance penalties).
//! Furthermore, in my experience it was hard to get some of the popular font rasterization
//! crates to compile with CPU features "+soft-float" and "-sse" (at least on x86_64).
//!
//! Legacy 8x8 bitmap fonts are ugly when printed to the screen. My crate can be seen as a nice
//! replacement with very nice anti-aliasing.
//!
//! If you have a standard environment or support for floating point operations, you might want
//! to rasterize the font by yourself with the crate `fontdue` and some TTF fonts rather than
//! using my crate.
//!
//! ## Minimal Code Example
//! ```rust
//! use noto_sans_mono_bitmap::{get_bitmap, get_bitmap_width, BitmapHeight, FontWeight};
//!
//! // Minimal example.
//!
//! let width = get_bitmap_width(FontWeight::Regular, BitmapHeight::Size16);
//! println!(
//!     "Each char of the mono-spaced font will be {}px in width if the font \
//!      weight={:?} and the bitmap height={}",
//!     width,
//!     FontWeight::Regular,
//!     BitmapHeight::Size16.val()
//! );
//! let bitmap_char = get_bitmap('A', FontWeight::Regular, BitmapHeight::Size16).expect("unsupported char");
//! println!("{:?}", bitmap_char);
//! for (row_i, row) in bitmap_char.bitmap().iter().enumerate() {
//!     for (col_i, pixel) in row.iter().enumerate() {
//!         println!("[{:02}][{:02}]: {:03}", row_i, col_i, pixel);
//!     }
//! }
//! ```
//!
//! ## Cargo Build Time Features
//! If all Cargo features are available, this bitmap fonts supports `light`, `regular`,
//! and `bold`, but no `italic` style, because Noto Sans Mono doesn't have an italic
//! TTF file. The rasterization was done with the awesome [fontdue-Crate](https://crates.io/crates/fontdue).
//!
//! By default, all sizes and font styles/weights are included via the cargo feature `all`.
//! This can be restricted by only using features such as `regular` and `size_14`. Anyhow,
//! a test of mine showed, that including all features in a release build only increases the
//! file size by a few dozen to a few hundred kilobytes. The Rust compiler is really smart
//! throwing out unused parts of the bitmap font, even if they are included as dependency.
//! Your binary will not be bloated by a few megabytes, according to my findings.
//!
//! The bitmap font includes the following unicode range:
//! - BASIC LATIN,
//! - LATIN 1 Supplement
//! - LATIN EXTENDED-A
//!
//! This means unicode symbols from `0 .. 0x17f`, hence letters
//! and symbols from a QWERTZ/QWERTY keyboard plus symbols such as
//! Ö, Ä, and Ü. Control characters are not included.

// # THIS FILE GETS AUTO GENERATED BY THE PROJECT IN "../codegen" (see repository!)

#![no_std]
#![deny(
    clippy::all,
    clippy::cargo,
    clippy::nursery,
    // clippy::restriction,
    // clippy::pedantic
)]
// now allow a few rules which are denied by the above statement
// --> they are ridiculous and not necessary
#![allow(
    clippy::suboptimal_flops,
    clippy::redundant_pub_crate,
    clippy::fallible_impl_from
)]
#![deny(missing_debug_implementations)]
#![deny(rustdoc::all)]

// # THIS FILE GETS AUTO GENERATED BY THE PROJECT IN "../codegen" (see repository!)

mod bold;
mod light;
mod regular;

/// Describes the relevant information for a rendered char of the bitmap font.
///
/// To see why the term "bitmap" is used, see section Terminology in the README.
#[derive(Debug)]
pub struct BitmapChar {
    /// The actual font data that is `height` * `width` bytes in size.
    /// Each byte describes the intensity of a pixel from 0 to 255.
    ///
    /// To see why the term "bitmap" is used, see section Terminology in the README.
    bitmap: &'static [&'static [u8]],
    /// Height of the bitmap box. The actual font size is slightly smaller.
    height: usize,
    /// The width of the bitmap char. It is guaranteed, that all chars
    /// of the same font weight and bitmap height also have the same width
    /// (as you would expect from a mono font.)
    width: usize,
}

impl BitmapChar {
    /// The actual font data that is `height` * `width` bytes in size.
    /// Each byte describes the intensity of a pixel from 0 to 255.
    #[inline]
    pub const fn bitmap(&self) -> &'static [&'static [u8]] {
        self.bitmap
    }

    /// Height of the bitmap box. The actual font size is slightly smaller.
    #[inline]
    pub const fn height(&self) -> usize {
        self.height
    }

    /// The width of the bitmap char. It is guaranteed, that all chars
    /// of the same font weight and bitmap height also have the same width
    /// (as you would expect from a mono font).
    #[inline]
    pub const fn width(&self) -> usize {
        self.width
    }
}

/// Supported font weights.
///
/// The available variants depend on the selected Cargo build features.
#[derive(Debug, Copy, Clone)]
#[repr(usize)]
pub enum FontWeight {
    #[cfg(feature = "light")]
    Light,
    #[cfg(feature = "regular")]
    Regular,
    #[cfg(feature = "bold")]
    Bold,
}

impl FontWeight {
    /// Returns the numeric value of the enum variant.
    #[inline]
    pub const fn val(self) -> usize {
        self as _
    }
}

/// The height of the bitmap font. The font size will be a a few
/// percent less, because each bitmap letter contains vertical padding
/// for proper alignment of chars (i.e. ÄyA). The width of each bitmap
/// character will be also less than the height, because there is no
/// horizontal padding included.
///
/// The available variants depend on the selected Cargo build features.
///
/// To see why the term "bitmap" is used, see section Terminology in the README.
#[derive(Debug, Clone, Copy)]
#[repr(usize)]
pub enum BitmapHeight {
    #[cfg(feature = "size_14")]
    Size14 = 14,
    #[cfg(feature = "size_16")]
    Size16 = 16,
    #[cfg(feature = "size_18")]
    Size18 = 18,
    #[cfg(feature = "size_20")]
    Size20 = 20,
    #[cfg(feature = "size_22")]
    Size22 = 22,
    #[cfg(feature = "size_24")]
    Size24 = 24,
    #[cfg(feature = "size_32")]
    Size32 = 32,
    #[cfg(feature = "size_64")]
    Size64 = 64,
}

impl BitmapHeight {
    /// Returns the numeric value of the variant.
    #[inline]
    pub const fn val(self) -> usize {
        self as _
    }
}

/// Returns a [`BitmapChar`] for the given char, [`FontWeight`], and [`BitmapHeight`].
///
/// Returns None, if the given char is not known by the bitmap font. In this case,
/// you could fall back to `get_bitmap(' ', ...)`.
///
/// To see why the term "bitmap" is used, see section Terminology in the README.
#[inline]
pub fn get_bitmap(c: char, style: FontWeight, size: BitmapHeight) -> Option<BitmapChar> {
    let bitmap = match style {
        #[cfg(feature = "light")]
        FontWeight::Light => match size {
            #[cfg(feature = "size_14")]
            BitmapHeight::Size14 => crate::light::size_14::get_char(c),
            #[cfg(feature = "size_16")]
            BitmapHeight::Size16 => crate::light::size_16::get_char(c),
            #[cfg(feature = "size_18")]
            BitmapHeight::Size18 => crate::light::size_18::get_char(c),
            #[cfg(feature = "size_20")]
            BitmapHeight::Size20 => crate::light::size_20::get_char(c),
            #[cfg(feature = "size_22")]
            BitmapHeight::Size22 => crate::light::size_22::get_char(c),
            #[cfg(feature = "size_24")]
            BitmapHeight::Size24 => crate::light::size_24::get_char(c),
            #[cfg(feature = "size_32")]
            BitmapHeight::Size32 => crate::light::size_32::get_char(c),
            #[cfg(feature = "size_64")]
            BitmapHeight::Size64 => crate::light::size_64::get_char(c),
        },
        #[cfg(feature = "regular")]
        FontWeight::Regular => match size {
            #[cfg(feature = "size_14")]
            BitmapHeight::Size14 => crate::regular::size_14::get_char(c),
            #[cfg(feature = "size_16")]
            BitmapHeight::Size16 => crate::regular::size_16::get_char(c),
            #[cfg(feature = "size_18")]
            BitmapHeight::Size18 => crate::regular::size_18::get_char(c),
            #[cfg(feature = "size_20")]
            BitmapHeight::Size20 => crate::regular::size_20::get_char(c),
            #[cfg(feature = "size_22")]
            BitmapHeight::Size22 => crate::regular::size_22::get_char(c),
            #[cfg(feature = "size_24")]
            BitmapHeight::Size24 => crate::regular::size_24::get_char(c),
            #[cfg(feature = "size_32")]
            BitmapHeight::Size32 => crate::regular::size_32::get_char(c),
            #[cfg(feature = "size_64")]
            BitmapHeight::Size64 => crate::regular::size_64::get_char(c),
        },
        #[cfg(feature = "bold")]
        FontWeight::Bold => match size {
            #[cfg(feature = "size_14")]
            BitmapHeight::Size14 => crate::bold::size_14::get_char(c),
            #[cfg(feature = "size_16")]
            BitmapHeight::Size16 => crate::bold::size_16::get_char(c),
            #[cfg(feature = "size_18")]
            BitmapHeight::Size18 => crate::bold::size_18::get_char(c),
            #[cfg(feature = "size_20")]
            BitmapHeight::Size20 => crate::bold::size_20::get_char(c),
            #[cfg(feature = "size_22")]
            BitmapHeight::Size22 => crate::bold::size_22::get_char(c),
            #[cfg(feature = "size_24")]
            BitmapHeight::Size24 => crate::bold::size_24::get_char(c),
            #[cfg(feature = "size_32")]
            BitmapHeight::Size32 => crate::bold::size_32::get_char(c),
            #[cfg(feature = "size_64")]
            BitmapHeight::Size64 => crate::bold::size_64::get_char(c),
        },
    };

    bitmap.map(|bitmap| BitmapChar {
        bitmap,
        height: size.val(),
        width: get_bitmap_width(style, size),
    })
}

/// Returns the width in pixels a char will occupy on the screen. The width is constant for all
/// characters regarding the same combination of [`FontWeight`] and [`BitmapHeight`]. The width is
/// a few percent smaller than the height of each char
///
/// To see why the term "bitmap" is used, see section Terminology in the README.
#[inline]
pub const fn get_bitmap_width(style: FontWeight, size: BitmapHeight) -> usize {
    match style {
        #[cfg(feature = "light")]
        FontWeight::Light => match size {
            #[cfg(feature = "size_14")]
            BitmapHeight::Size14 => crate::light::size_14::BITMAP_WIDTH,
            #[cfg(feature = "size_16")]
            BitmapHeight::Size16 => crate::light::size_16::BITMAP_WIDTH,
            #[cfg(feature = "size_18")]
            BitmapHeight::Size18 => crate::light::size_18::BITMAP_WIDTH,
            #[cfg(feature = "size_20")]
            BitmapHeight::Size20 => crate::light::size_20::BITMAP_WIDTH,
            #[cfg(feature = "size_22")]
            BitmapHeight::Size22 => crate::light::size_22::BITMAP_WIDTH,
            #[cfg(feature = "size_24")]
            BitmapHeight::Size24 => crate::light::size_24::BITMAP_WIDTH,
            #[cfg(feature = "size_32")]
            BitmapHeight::Size32 => crate::light::size_32::BITMAP_WIDTH,
            #[cfg(feature = "size_64")]
            BitmapHeight::Size64 => crate::light::size_64::BITMAP_WIDTH,
        },
        #[cfg(feature = "regular")]
        FontWeight::Regular => match size {
            #[cfg(feature = "size_14")]
            BitmapHeight::Size14 => crate::regular::size_14::BITMAP_WIDTH,
            #[cfg(feature = "size_16")]
            BitmapHeight::Size16 => crate::regular::size_16::BITMAP_WIDTH,
            #[cfg(feature = "size_18")]
            BitmapHeight::Size18 => crate::regular::size_18::BITMAP_WIDTH,
            #[cfg(feature = "size_20")]
            BitmapHeight::Size20 => crate::regular::size_20::BITMAP_WIDTH,
            #[cfg(feature = "size_22")]
            BitmapHeight::Size22 => crate::regular::size_22::BITMAP_WIDTH,
            #[cfg(feature = "size_24")]
            BitmapHeight::Size24 => crate::regular::size_24::BITMAP_WIDTH,
            #[cfg(feature = "size_32")]
            BitmapHeight::Size32 => crate::regular::size_32::BITMAP_WIDTH,
            #[cfg(feature = "size_64")]
            BitmapHeight::Size64 => crate::regular::size_64::BITMAP_WIDTH,
        },
        #[cfg(feature = "bold")]
        FontWeight::Bold => match size {
            #[cfg(feature = "size_14")]
            BitmapHeight::Size14 => crate::bold::size_14::BITMAP_WIDTH,
            #[cfg(feature = "size_16")]
            BitmapHeight::Size16 => crate::bold::size_16::BITMAP_WIDTH,
            #[cfg(feature = "size_18")]
            BitmapHeight::Size18 => crate::bold::size_18::BITMAP_WIDTH,
            #[cfg(feature = "size_20")]
            BitmapHeight::Size20 => crate::bold::size_20::BITMAP_WIDTH,
            #[cfg(feature = "size_22")]
            BitmapHeight::Size22 => crate::bold::size_22::BITMAP_WIDTH,
            #[cfg(feature = "size_24")]
            BitmapHeight::Size24 => crate::bold::size_24::BITMAP_WIDTH,
            #[cfg(feature = "size_32")]
            BitmapHeight::Size32 => crate::bold::size_32::BITMAP_WIDTH,
            #[cfg(feature = "size_64")]
            BitmapHeight::Size64 => crate::bold::size_64::BITMAP_WIDTH,
        },
    }
}

// # THIS FILE GETS AUTO GENERATED BY THE PROJECT IN "../codegen" (see repository!)