diff --git a/render-wasm/src/fonts/NotoColorEmoji-Regular.ttf b/render-wasm/src/fonts/NotoColorEmoji-Regular.ttf new file mode 100644 index 000000000..9851173f4 Binary files /dev/null and b/render-wasm/src/fonts/NotoColorEmoji-Regular.ttf differ diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index eabaa1491..d85ca64df 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -86,10 +86,6 @@ pub(crate) struct RenderState { pub options: RenderOptions, pub surfaces: Surfaces, fonts: FontStore, - // TODO: we should probably have only one of these - // pub font_provider: skia::textlayout::TypefaceFontProvider, - // pub font_collection: skia::textlayout::FontCollection, - // ---- pub cached_surface_image: Option, pub viewbox: Viewbox, pub images: ImageStore, @@ -117,7 +113,6 @@ impl RenderState { // This is used multiple times everywhere so instead of creating new instances every // time we reuse this one. - RenderState { gpu_state, surfaces, @@ -140,6 +135,7 @@ impl RenderState { pub fn fonts(&self) -> &FontStore { &self.fonts } + pub fn fonts_mut(&mut self) -> &mut FontStore { &mut self.fonts } diff --git a/render-wasm/src/render/fonts.rs b/render-wasm/src/render/fonts.rs index dcaf545a6..0dd881181 100644 --- a/render-wasm/src/render/fonts.rs +++ b/render-wasm/src/render/fonts.rs @@ -3,6 +3,9 @@ use skia_safe::{self as skia, textlayout, FontMgr}; use crate::shapes::FontFamily; const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("../fonts/RobotoMono-Regular.ttf"); +const EMOJI_FONT_BYTES: &[u8] = include_bytes!("../fonts/NotoColorEmoji-Regular.ttf"); +pub static DEFAULT_FONT: &'static str = "robotomono-regular"; +pub static DEFAULT_EMOJI_FONT: &'static str = "noto-color-emoji"; pub struct FontStore { // TODO: we should probably have just one of those @@ -18,7 +21,13 @@ impl FontStore { .new_from_data(DEFAULT_FONT_BYTES, None) .expect("Failed to load font"); - font_provider.register_typeface(default_font, "robotomono-regular"); + font_provider.register_typeface(default_font, DEFAULT_FONT); + + let emoji_font = skia::FontMgr::default() + .new_from_data(EMOJI_FONT_BYTES, None) + .expect("Failed to load font"); + + font_provider.register_typeface(emoji_font, DEFAULT_EMOJI_FONT); let mut font_collection = skia::textlayout::FontCollection::new(); font_collection.set_default_font_manager(FontMgr::default(), None); @@ -50,6 +59,7 @@ impl FontStore { self.font_provider .register_typeface(typeface, alias.as_str()); + self.refresh_font_collection(); Ok(()) diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index 5e204716c..47cc12390 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -1,7 +1,10 @@ -use crate::math::Rect; +use crate::{ + math::Rect, + render::{DEFAULT_EMOJI_FONT, DEFAULT_FONT}, +}; use skia_safe::{ self as skia, - textlayout::{FontCollection, ParagraphBuilder}, + textlayout::{FontCollection, ParagraphBuilder, ParagraphStyle}, }; use super::FontFamily; @@ -57,7 +60,7 @@ impl TextContent { } pub fn to_paragraphs(&self, fonts: &FontCollection) -> Vec { - let mut paragraph_style = skia::textlayout::ParagraphStyle::default(); + let mut paragraph_style = ParagraphStyle::default(); // TODO: read text direction, align, etc. from the shape paragraph_style.set_text_direction(skia::textlayout::TextDirection::LTR); @@ -65,11 +68,14 @@ impl TextContent { .iter() .map(|p| { let mut builder = ParagraphBuilder::new(¶graph_style, fonts); + for leaf in &p.children { - builder.push_style(&leaf.to_style()); + let text_style = leaf.to_style(); + builder.push_style(&text_style); builder.add_text(&leaf.text); builder.pop(); } + builder.build() }) .collect() @@ -122,8 +128,11 @@ impl TextLeaf { let mut style = skia::textlayout::TextStyle::default(); style.set_color(skia::Color::BLACK); style.set_font_size(self.font_size); - style.set_font_families(&[self.serialized_font_family()]); - + style.set_font_families(&[ + self.serialized_font_family(), + DEFAULT_FONT.to_string(), + DEFAULT_EMOJI_FONT.to_string(), + ]); style }