⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/desktop/
font.rs

1//! Font Rendering System for Desktop Applications
2//!
3//! Provides bitmap font rendering with support for multiple font sizes and
4//! styles.
5
6use alloc::{vec, vec::Vec};
7
8use spin::Mutex;
9
10use crate::error::KernelError;
11
12/// Font size in pixels
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum FontSize {
15    Small = 8,
16    Medium = 12,
17    Large = 16,
18    ExtraLarge = 24,
19}
20
21/// Font style
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum FontStyle {
24    Regular,
25    Bold,
26    Italic,
27    BoldItalic,
28}
29
30/// Font weight
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum FontWeight {
33    Thin = 100,
34    Light = 300,
35    Regular = 400,
36    Medium = 500,
37    Bold = 700,
38    Black = 900,
39}
40
41/// Glyph (single character) representation
42#[derive(Debug, Clone)]
43pub struct Glyph {
44    /// Character code
45    pub character: char,
46
47    /// Bitmap data (1 bit per pixel)
48    pub bitmap: Vec<u8>,
49
50    /// Width in pixels
51    pub width: u8,
52
53    /// Height in pixels
54    pub height: u8,
55
56    /// X offset for rendering
57    pub x_offset: i8,
58
59    /// Y offset for rendering
60    pub y_offset: i8,
61
62    /// Advance width (spacing to next character)
63    pub advance: u8,
64}
65
66impl Glyph {
67    /// Create a new glyph
68    pub fn new(character: char, width: u8, height: u8) -> Self {
69        let bitmap_size = (width as usize * height as usize).div_ceil(8);
70        Self {
71            character,
72            bitmap: vec![0; bitmap_size],
73            width,
74            height,
75            x_offset: 0,
76            y_offset: 0,
77            advance: width,
78        }
79    }
80
81    /// Get pixel value at (x, y)
82    pub fn get_pixel(&self, x: u8, y: u8) -> bool {
83        if x >= self.width || y >= self.height {
84            return false;
85        }
86
87        let bit_index = y as usize * self.width as usize + x as usize;
88        let byte_index = bit_index / 8;
89        let bit_offset = bit_index % 8;
90
91        if byte_index >= self.bitmap.len() {
92            return false;
93        }
94
95        (self.bitmap[byte_index] & (1 << bit_offset)) != 0
96    }
97
98    /// Set pixel value at (x, y)
99    pub fn set_pixel(&mut self, x: u8, y: u8, value: bool) {
100        if x >= self.width || y >= self.height {
101            return;
102        }
103
104        let bit_index = y as usize * self.width as usize + x as usize;
105        let byte_index = bit_index / 8;
106        let bit_offset = bit_index % 8;
107
108        if byte_index >= self.bitmap.len() {
109            return;
110        }
111
112        if value {
113            self.bitmap[byte_index] |= 1 << bit_offset;
114        } else {
115            self.bitmap[byte_index] &= !(1 << bit_offset);
116        }
117    }
118}
119
120/// Bitmap font
121pub struct Font {
122    /// Font name
123    pub name: &'static str,
124
125    /// Font size
126    pub size: FontSize,
127
128    /// Font style
129    pub style: FontStyle,
130
131    /// Glyphs for ASCII characters (32-126)
132    glyphs: Vec<Glyph>,
133
134    /// Line height
135    pub line_height: u8,
136
137    /// Baseline offset
138    pub baseline: u8,
139}
140
141impl Font {
142    /// Create a new font
143    pub fn new(name: &'static str, size: FontSize, style: FontStyle) -> Self {
144        let height = size as u8;
145        let line_height = height + 2;
146        let baseline = height - 2;
147
148        let mut font = Self {
149            name,
150            size,
151            style,
152            glyphs: Vec::new(),
153            line_height,
154            baseline,
155        };
156
157        // Initialize ASCII glyphs
158        font.initialize_ascii_glyphs();
159
160        font
161    }
162
163    /// Initialize basic ASCII glyphs (stub implementation)
164    fn initialize_ascii_glyphs(&mut self) {
165        // ASCII printable characters: 32-126
166        for ch in 32u8..=126 {
167            let character = ch as char;
168            let width = (self.size as u8 * 2) / 3; // Approximate width
169            let glyph = Glyph::new(character, width, self.size as u8);
170            self.glyphs.push(glyph);
171        }
172    }
173
174    /// Get glyph for a character
175    pub fn get_glyph(&self, ch: char) -> Option<&Glyph> {
176        let code = ch as u32;
177        if (32..=126).contains(&code) {
178            Some(&self.glyphs[(code - 32) as usize])
179        } else {
180            None
181        }
182    }
183
184    /// Measure text width
185    pub fn measure_text(&self, text: &str) -> u32 {
186        let mut width = 0u32;
187        for ch in text.chars() {
188            if let Some(glyph) = self.get_glyph(ch) {
189                width += glyph.advance as u32;
190            }
191        }
192        width
193    }
194
195    /// Render text to a bitmap buffer
196    pub fn render_text(
197        &self,
198        text: &str,
199        buffer: &mut [u8],
200        buffer_width: usize,
201        buffer_height: usize,
202        x: i32,
203        y: i32,
204    ) -> Result<(), KernelError> {
205        let mut cursor_x = x;
206        let cursor_y = y;
207
208        for ch in text.chars() {
209            if let Some(glyph) = self.get_glyph(ch) {
210                // Render glyph
211                for gy in 0..glyph.height {
212                    for gx in 0..glyph.width {
213                        if glyph.get_pixel(gx, gy) {
214                            let px = cursor_x + gx as i32 + glyph.x_offset as i32;
215                            let py = cursor_y + gy as i32 + glyph.y_offset as i32;
216
217                            if px >= 0
218                                && py >= 0
219                                && (px as usize) < buffer_width
220                                && (py as usize) < buffer_height
221                            {
222                                let pixel_index = py as usize * buffer_width + px as usize;
223                                if pixel_index < buffer.len() {
224                                    buffer[pixel_index] = 255; // White pixel
225                                }
226                            }
227                        }
228                    }
229                }
230
231                cursor_x += glyph.advance as i32;
232            }
233        }
234
235        Ok(())
236    }
237}
238
239/// Font manager for loading and caching fonts
240pub struct FontManager {
241    /// Loaded fonts
242    fonts: Vec<Font>,
243
244    /// Default font index
245    default_font: usize,
246}
247
248impl FontManager {
249    /// Create a new font manager
250    pub fn new() -> Self {
251        let mut manager = Self {
252            fonts: Vec::new(),
253            default_font: 0,
254        };
255
256        // Load default fonts
257        manager.load_default_fonts();
258
259        manager
260    }
261
262    /// Load default fonts
263    fn load_default_fonts(&mut self) {
264        // Create default font set
265        self.fonts
266            .push(Font::new("Monospace", FontSize::Small, FontStyle::Regular));
267        self.fonts
268            .push(Font::new("Monospace", FontSize::Medium, FontStyle::Regular));
269        self.fonts
270            .push(Font::new("Monospace", FontSize::Large, FontStyle::Regular));
271        self.fonts
272            .push(Font::new("Monospace", FontSize::Medium, FontStyle::Bold));
273
274        println!("[FONT] Loaded {} default fonts", self.fonts.len());
275    }
276
277    /// Get default font
278    pub fn get_default_font(&self) -> &Font {
279        &self.fonts[self.default_font]
280    }
281
282    /// Get font by size and style
283    pub fn get_font(&self, size: FontSize, style: FontStyle) -> Option<&Font> {
284        self.fonts
285            .iter()
286            .find(|f| f.size == size && f.style == style)
287    }
288
289    /// Add a font
290    pub fn add_font(&mut self, font: Font) {
291        self.fonts.push(font);
292    }
293}
294
295impl Default for FontManager {
296    fn default() -> Self {
297        Self::new()
298    }
299}
300
301/// Global font manager protected by Mutex
302static FONT_MANAGER: Mutex<Option<FontManager>> = Mutex::new(None);
303
304/// Initialize the font system
305pub fn init() -> Result<(), KernelError> {
306    let mut lock = FONT_MANAGER.lock();
307    if lock.is_some() {
308        return Err(KernelError::InvalidState {
309            expected: "uninitialized",
310            actual: "initialized",
311        });
312    }
313
314    *lock = Some(FontManager::new());
315
316    println!("[FONT] Font rendering system initialized");
317    Ok(())
318}
319
320/// Execute a closure with the font manager (mutable access)
321pub fn with_font_manager<R, F: FnOnce(&mut FontManager) -> R>(f: F) -> Result<R, KernelError> {
322    FONT_MANAGER
323        .lock()
324        .as_mut()
325        .map(f)
326        .ok_or(KernelError::InvalidState {
327            expected: "initialized",
328            actual: "uninitialized",
329        })
330}
331
332#[cfg(test)]
333mod tests {
334    use super::*;
335
336    #[test]
337    fn test_font_creation() {
338        let font = Font::new("Test", FontSize::Medium, FontStyle::Regular);
339        assert_eq!(font.name, "Test");
340        assert_eq!(font.size, FontSize::Medium);
341    }
342
343    #[test]
344    fn test_glyph_pixel_operations() {
345        let mut glyph = Glyph::new('A', 8, 12);
346        assert!(!glyph.get_pixel(0, 0));
347
348        glyph.set_pixel(0, 0, true);
349        assert!(glyph.get_pixel(0, 0));
350
351        glyph.set_pixel(0, 0, false);
352        assert!(!glyph.get_pixel(0, 0));
353    }
354
355    #[test]
356    fn test_text_measurement() {
357        let font = Font::new("Test", FontSize::Medium, FontStyle::Regular);
358        let width = font.measure_text("Hello");
359        assert!(width > 0);
360    }
361}