🎉 Store custom fonts (ttfs) and use them to write texts (wasm) (#6050)

This commit is contained in:
Belén Albeza 2025-03-14 12:45:15 +01:00 committed by GitHub
parent e4c9b736f7
commit eb6d2fb0eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 386 additions and 140 deletions

View file

@ -23,18 +23,17 @@ fn render_debug_view(render_state: &mut RenderState) {
}
pub fn render_wasm_label(render_state: &mut RenderState) {
let canvas = render_state.surfaces.canvas(SurfaceId::Current);
let font_provider = render_state.fonts().font_provider();
let typeface = font_provider
.match_family_style("robotomono-regular", skia::FontStyle::default())
.unwrap();
let canvas = render_state.surfaces.canvas(SurfaceId::Current);
let skia::ISize { width, height } = canvas.base_layer_size();
let p = skia::Point::new(width as f32 - 100.0, height as f32 - 25.0);
let mut paint = skia::Paint::default();
paint.set_color(skia::Color::from_argb(100, 0, 0, 0));
let font_provider = &render_state.font_provider;
let typeface = font_provider
.match_family_style("robotomono-regular", skia::FontStyle::default())
.unwrap();
let font = skia::Font::new(typeface, 10.0);
canvas.draw_str("WASM RENDERER", p, &font, &paint);
}

View file

@ -0,0 +1,70 @@
use skia_safe::{self as skia, textlayout, FontMgr};
use crate::shapes::FontFamily;
const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("../fonts/RobotoMono-Regular.ttf");
pub struct FontStore {
// TODO: we should probably have just one of those
font_provider: textlayout::TypefaceFontProvider,
font_collection: textlayout::FontCollection,
}
impl FontStore {
pub fn new() -> Self {
let mut font_provider = skia::textlayout::TypefaceFontProvider::new();
let default_font = skia::FontMgr::default()
.new_from_data(DEFAULT_FONT_BYTES, None)
.expect("Failed to load font");
font_provider.register_typeface(default_font, "robotomono-regular");
let mut font_collection = skia::textlayout::FontCollection::new();
font_collection.set_default_font_manager(FontMgr::default(), None);
font_collection.set_dynamic_font_manager(FontMgr::from(font_provider.clone()));
Self {
font_provider,
font_collection,
}
}
pub fn font_provider(&self) -> &textlayout::TypefaceFontProvider {
&self.font_provider
}
pub fn font_collection(&self) -> &textlayout::FontCollection {
&self.font_collection
}
pub fn add(&mut self, family: FontFamily, font_data: &[u8]) -> Result<(), String> {
if self.has_family(&family) {
return Ok(());
}
let alias = format!("{}", family);
let typeface = skia::FontMgr::default()
.new_from_data(font_data, None)
.ok_or("Failed to create typeface")?;
self.font_provider
.register_typeface(typeface, alias.as_str());
self.refresh_font_collection();
Ok(())
}
pub fn has_family(&self, family: &FontFamily) -> bool {
let serialized = format!("{}", family);
self.font_provider.family_names().any(|x| x == serialized)
}
fn refresh_font_collection(&mut self) {
self.font_collection = skia::textlayout::FontCollection::new();
self.font_collection
.set_default_font_manager(FontMgr::default(), None);
self.font_collection
.set_dynamic_font_manager(FontMgr::from(self.font_provider.clone()));
}
}

View file

@ -3,8 +3,9 @@ use crate::shapes::TextContent;
pub fn render(render_state: &mut RenderState, text: &TextContent) {
let mut offset_y = 0.0;
for mut skia_paragraph in text.to_paragraphs(&render_state.font_collection) {
for mut skia_paragraph in text.to_paragraphs(&render_state.fonts().font_collection()) {
skia_paragraph.layout(text.width());
let xy = (text.x(), text.y() + offset_y);
skia_paragraph.paint(render_state.surfaces.canvas(SurfaceId::Fills), xy);
offset_y += skia_paragraph.height();