First commit. Version 0.1.0

This commit is contained in:
2026-05-10 09:58:23 +02:00
parent af105b7f7d
commit bbab5e238d
635 changed files with 53627 additions and 175 deletions

124
src/render/setup.rs Normal file
View File

@@ -0,0 +1,124 @@
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
//! Construction + accessors for [`SoftwareCanvas`]: new / sub_canvas
//! / resize plus the font-registry installer and `blit`.
use std::collections::HashMap;
use std::sync::{ Arc, OnceLock };
use fontdue::{ Font, FontSettings };
use tiny_skia::{ Pixmap, PixmapPaint, Transform };
use crate::theme::{ FontRegistry, FontStyle };
use super::helpers::load_default_font_bytes;
use super::SoftwareCanvas;
/// Process-wide cache of the default font face. Avoids re-reading +
/// re-parsing the file on every surface bring-up. Sora is small
/// (~50 KB) so the cost was minor in absolute terms — but a layer
/// shell that brings up a launcher overlay, a QS panel, a calendar
/// popup and a handful of toast surfaces would still pay the parse
/// cost a dozen times in a single session, all of which is wasted
/// work.
static DEFAULT_FONT: OnceLock<Arc<Font>> = OnceLock::new();
fn default_font() -> Arc<Font>
{
Arc::clone( DEFAULT_FONT.get_or_init( ||
{
let bytes = load_default_font_bytes();
let font = Font::from_bytes( bytes.as_slice(), FontSettings::default() )
.expect( "bad font" );
Arc::new( font )
} ) )
}
impl SoftwareCanvas
{
/// Create a canvas of the given pixel dimensions, loading a system font.
///
/// Fallback fonts (Noto Sans / CJK / Devanagari / …) are NOT loaded
/// here — they are owned by the crate-private system-fonts chain
/// and loaded lazily per codepoint. A canvas that only ever paints
/// Latin text will never touch those files; the first non-Latin
/// glyph triggers a single targeted load and the rest of the
/// process reuses the cached `Arc<Font>`.
pub fn new( width: u32, height: u32 ) -> Self
{
Self
{
pixmap: Pixmap::new( width, height ).expect( "pixmap" ),
font: default_font(),
font_registry: None,
dpi_scale: 1.0,
global_alpha: 1.0,
glyph_cache: HashMap::new(),
clip_mask: None,
clip_bounds: Vec::new(),
}
}
/// Create a blank sub-canvas sharing the same font and DPI scale.
pub fn sub_canvas( &self, width: u32, height: u32 ) -> SoftwareCanvas
{
SoftwareCanvas
{
pixmap: Pixmap::new( width, height ).expect( "pixmap" ),
font: Arc::clone( &self.font ),
font_registry: self.font_registry.as_ref().map( Arc::clone ),
dpi_scale: self.dpi_scale,
global_alpha: self.global_alpha,
glyph_cache: HashMap::new(),
clip_mask: None,
clip_bounds: Vec::new(),
}
}
/// Install a theme font registry so [`Self::font_for`] can
/// resolve family+weight+style triples declared by the theme's
/// `fonts` block. The default [`Self::font`] stays in place as a
/// fallback.
pub fn set_font_registry( &mut self, registry: Arc<FontRegistry> )
{
self.font_registry = Some( registry );
}
/// Resolve a specific font from the theme registry, falling back
/// to the canvas' default [`Self::font`] when no registry is
/// installed or the triple cannot be satisfied.
pub fn font_for( &self, family: &str, weight: u16, style: FontStyle ) -> Arc<Font>
{
self.font_registry
.as_ref()
.and_then( |r| r.resolve( family, weight, style ) )
.unwrap_or_else( || Arc::clone( &self.font ) )
}
/// Pick the right font for `ch`. Tries the primary [`Self::font`]
/// first; on a miss, delegates to the crate-private system-fonts
/// fallback chain (lazy load of the relevant Noto pack). Falls
/// back to the primary (which paints a `.notdef` box) when no
/// installed fallback covers the codepoint.
pub fn font_for_char( &self, ch: char ) -> Arc<Font>
{
if self.font.lookup_glyph_index( ch ) != 0
{
return Arc::clone( &self.font );
}
crate::system_fonts::lookup( ch ).unwrap_or_else( || Arc::clone( &self.font ) )
}
pub fn blit( &mut self, src: &SoftwareCanvas, dest_x: i32, dest_y: i32 )
{
let paint = PixmapPaint::default();
let t = Transform::from_translate( dest_x as f32, dest_y as f32 );
self.pixmap.draw_pixmap( 0, 0, src.pixmap.as_ref(), &paint, t, self.clip_mask.as_ref() );
}
pub fn resize( &mut self, width: u32, height: u32 )
{
self.pixmap = Pixmap::new( width, height ).expect( "pixmap" );
}
}