kernel/screen/basic/
font.rs1use crate::screen::basic::framebuffer::BasicFramebuffer;
7
8static MAGIC_NUMBER: u32 = 0x864ab572;
10static BACKGROUND_COLOR: u32 = 0x00000000;
12static DEFAULT_FOREGROUND_COLOR: u32 = 0x00FFFFFF;
14
15pub struct Psf2Font {
17 font: &'static [u8],
19 header: Psf2Header,
20}
21
22impl Psf2Font {
23 pub fn glyph_height(&self) -> usize {
25 self.header.height as usize
26 }
27}
28
29struct Psf2Header {
31 pub header_size: u32,
32 pub glyph_count: u32,
33 pub bytes_per_glyph: u32,
34 pub height: u32,
35 pub width: u32,
36}
37
38impl Psf2Font {
39 pub fn init() -> Self {
44 let font: &[u8] = include_bytes!("../../../resources/ter-powerline-v16n.psf");
45 Self {
46 font: font,
47 header: Psf2Header::parse(font),
48 }
49 }
50
51 fn parse_char(&self, c: char) -> Option<&'static [u8]> {
53 let char_index = c as usize;
54
55 if char_index >= self.header.glyph_count as usize {
56 return None;
57 }
58
59 let start = self.header.header_size as usize + char_index * self.header.bytes_per_glyph as usize;
60
61 Some(&self.font[start..(start + self.header.bytes_per_glyph as usize)])
62 }
63
64 pub fn draw_char(&self, fb: &BasicFramebuffer, c: char, x: usize, y: usize, font_color: Option<u32>) -> usize {
69 let Some(glyph) = self.parse_char(c) else { return x; };
70
71 if x + self.header.width as usize > fb.width as usize
72 || y + self.header.height as usize > fb.height as usize
73 {
74 return x;
75 }
76
77 let row_stride = (self.header.width + 7) / 8;
78
79 for row in 0..self.header.height as usize {
80 for col in 0..self.header.width as usize {
81 let byte = glyph[row * row_stride as usize + col / 8];
82 let bit = (byte >> (7 - (col % 8))) & 1;
83
84 let color = if bit == 1 {
85 font_color.unwrap_or(DEFAULT_FOREGROUND_COLOR)
86 } else {
87 BACKGROUND_COLOR
88 };
89 let pixel_pos = (y + row) * fb.bytes_per_row as usize + (x + col);
90
91 unsafe {
94 fb.fb_pointer.add(pixel_pos).write_volatile(color);
95 }
96 }
97 }
98
99 x + self.header.width as usize
100 }
101
102 pub fn draw_string(&self, fb: &BasicFramebuffer, string: &str, x: &mut usize, y: &mut usize, font_color: Option<u32>) {
105 for c in string.chars() {
106 if c == '\n' {
107 *x = 0;
108 *y += self.header.height as usize;
109 } else {
110 *x = self.draw_char(fb, c, *x, *y, font_color);
111 }
112 }
113 }
114}
115
116impl Psf2Header {
117 fn parse(psf2_font: &[u8]) -> Self {
122 let read_u32 = |offset: usize| -> u32 {
123 u32::from_le_bytes(psf2_font[offset..(offset + 4)].try_into().unwrap())
124 };
125
126 if read_u32(0) != MAGIC_NUMBER {
127 use crate::panic::kernel_panic;
128 use crate::types::panic_codes::PanicCode;
129
130 kernel_panic(
131 PanicCode::InvalidPsf2MagicNumber,
132 "Invalid PSF2 Magic Number",
133 );
134 }
135
136 Self {
137 header_size: read_u32(8),
138 glyph_count: read_u32(16),
139 bytes_per_glyph: read_u32(20),
140 height: read_u32(24),
141 width: read_u32(28),
142 }
143 }
144}