mirror of
https://github.com/penpot/penpot.git
synced 2025-07-13 11:57:17 +02:00
🎉 Implement font fallback to support multiple languages
This commit is contained in:
parent
9733c41ae4
commit
c40de5fb87
7 changed files with 179 additions and 38 deletions
|
@ -1,4 +1,5 @@
|
|||
use skia_safe::{self as skia, textlayout, Font, FontMgr};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::shapes::{FontFamily, FontStyle};
|
||||
use crate::uuid::Uuid;
|
||||
|
@ -21,6 +22,7 @@ pub struct FontStore {
|
|||
font_provider: textlayout::TypefaceFontProvider,
|
||||
font_collection: textlayout::FontCollection,
|
||||
debug_font: Font,
|
||||
fallback_fonts: HashSet<String>,
|
||||
}
|
||||
|
||||
impl FontStore {
|
||||
|
@ -41,6 +43,7 @@ impl FontStore {
|
|||
font_provider,
|
||||
font_collection,
|
||||
debug_font,
|
||||
fallback_fonts: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +64,7 @@ impl FontStore {
|
|||
family: FontFamily,
|
||||
font_data: &[u8],
|
||||
is_emoji: bool,
|
||||
is_fallback: bool,
|
||||
) -> Result<(), String> {
|
||||
if self.has_family(&family) {
|
||||
return Ok(());
|
||||
|
@ -80,6 +84,11 @@ impl FontStore {
|
|||
|
||||
self.font_provider.register_typeface(typeface, font_name);
|
||||
self.font_collection.clear_caches();
|
||||
|
||||
if is_fallback {
|
||||
self.fallback_fonts.insert(alias);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -87,6 +96,10 @@ impl FontStore {
|
|||
let serialized = format!("{}", family);
|
||||
self.font_provider.family_names().any(|x| x == serialized)
|
||||
}
|
||||
|
||||
pub fn get_fallback(&self) -> &HashSet<String> {
|
||||
&self.fallback_fonts
|
||||
}
|
||||
}
|
||||
|
||||
fn load_default_provider(font_mgr: &FontMgr) -> skia::textlayout::TypefaceFontProvider {
|
||||
|
|
|
@ -7,10 +7,11 @@ use skia_safe::{
|
|||
paint::Paint,
|
||||
textlayout::{FontCollection, ParagraphBuilder, ParagraphStyle},
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::FontFamily;
|
||||
use crate::shapes::{self, merge_fills, set_paint_fill, Stroke, StrokeKind};
|
||||
use crate::utils::uuid_from_u32;
|
||||
use crate::utils::{get_fallback_fonts, uuid_from_u32};
|
||||
use crate::wasm::fills::parse_fills_from_bytes;
|
||||
use crate::Uuid;
|
||||
|
||||
|
@ -94,6 +95,7 @@ impl TextContent {
|
|||
}
|
||||
|
||||
pub fn to_paragraphs(&self, fonts: &FontCollection) -> Vec<Vec<skia::textlayout::Paragraph>> {
|
||||
let fallback_fonts = get_fallback_fonts();
|
||||
let mut paragraph_group = Vec::new();
|
||||
let paragraphs = self
|
||||
.paragraphs
|
||||
|
@ -102,7 +104,7 @@ impl TextContent {
|
|||
let paragraph_style = p.paragraph_to_style();
|
||||
let mut builder = ParagraphBuilder::new(¶graph_style, fonts);
|
||||
for leaf in &p.children {
|
||||
let text_style = leaf.to_style(p, &self.bounds); // FIXME
|
||||
let text_style = leaf.to_style(p, &self.bounds, fallback_fonts); // FIXME
|
||||
let text = leaf.apply_text_transform();
|
||||
builder.push_style(&text_style);
|
||||
builder.add_text(&text);
|
||||
|
@ -121,6 +123,7 @@ impl TextContent {
|
|||
bounds: &Rect,
|
||||
fonts: &FontCollection,
|
||||
) -> Vec<Vec<skia::textlayout::Paragraph>> {
|
||||
let fallback_fonts = get_fallback_fonts();
|
||||
let mut paragraph_group = Vec::new();
|
||||
let stroke_paints = get_text_stroke_paints(stroke, bounds);
|
||||
|
||||
|
@ -130,7 +133,8 @@ impl TextContent {
|
|||
let paragraph_style = paragraph.paragraph_to_style();
|
||||
let mut builder = ParagraphBuilder::new(¶graph_style, fonts);
|
||||
for leaf in ¶graph.children {
|
||||
let stroke_style = leaf.to_stroke_style(paragraph, &stroke_paint);
|
||||
let stroke_style =
|
||||
leaf.to_stroke_style(paragraph, &stroke_paint, fallback_fonts);
|
||||
let text: String = leaf.apply_text_transform();
|
||||
builder.push_style(&stroke_style);
|
||||
builder.add_text(&text);
|
||||
|
@ -336,6 +340,7 @@ impl TextLeaf {
|
|||
&self,
|
||||
paragraph: &Paragraph,
|
||||
content_bounds: &Rect,
|
||||
fallback_fonts: &HashSet<String>,
|
||||
) -> skia::textlayout::TextStyle {
|
||||
let mut style = skia::textlayout::TextStyle::default();
|
||||
|
||||
|
@ -359,14 +364,18 @@ impl TextLeaf {
|
|||
3 => skia::textlayout::TextDecoration::OVERLINE,
|
||||
_ => skia::textlayout::TextDecoration::NO_DECORATION,
|
||||
});
|
||||
// FIXME
|
||||
|
||||
// FIXME fix decoration styles
|
||||
style.set_decoration_color(paint.color());
|
||||
|
||||
style.set_font_families(&[
|
||||
let mut font_families = vec![
|
||||
self.serialized_font_family(),
|
||||
default_font(),
|
||||
DEFAULT_EMOJI_FONT.to_string(),
|
||||
]);
|
||||
];
|
||||
|
||||
font_families.extend(fallback_fonts.iter().cloned());
|
||||
style.set_font_families(&font_families);
|
||||
|
||||
style
|
||||
}
|
||||
|
@ -375,8 +384,9 @@ impl TextLeaf {
|
|||
&self,
|
||||
paragraph: &Paragraph,
|
||||
stroke_paint: &Paint,
|
||||
fallback_fonts: &HashSet<String>,
|
||||
) -> skia::textlayout::TextStyle {
|
||||
let mut style = self.to_style(paragraph, &Rect::default());
|
||||
let mut style = self.to_style(paragraph, &Rect::default(), fallback_fonts);
|
||||
style.set_foreground_paint(stroke_paint);
|
||||
style.set_font_size(self.font_size);
|
||||
style.set_letter_spacing(paragraph.letter_spacing);
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::skia::Image;
|
|||
use crate::uuid::Uuid;
|
||||
use crate::with_state;
|
||||
use crate::STATE;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn uuid_from_u32_quartet(a: u32, b: u32, c: u32, d: u32) -> Uuid {
|
||||
let hi: u64 = ((a as u64) << 32) | b as u64;
|
||||
|
@ -25,3 +26,8 @@ pub fn uuid_from_u32(id: [u32; 4]) -> Uuid {
|
|||
pub fn get_image(image_id: &Uuid) -> Option<&Image> {
|
||||
with_state!(state, { state.render_state().images.get(image_id) })
|
||||
}
|
||||
|
||||
// FIXME: move to a different place ?
|
||||
pub fn get_fallback_fonts() -> &'static HashSet<String> {
|
||||
with_state!(state, { state.render_state().fonts().get_fallback() })
|
||||
}
|
||||
|
|
|
@ -14,19 +14,19 @@ pub extern "C" fn store_font(
|
|||
weight: u32,
|
||||
style: u8,
|
||||
is_emoji: bool,
|
||||
is_fallback: bool,
|
||||
) {
|
||||
with_state!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
let font_bytes = mem::bytes();
|
||||
|
||||
let family = FontFamily::new(id, weight, style.into());
|
||||
let res = state
|
||||
let _ = state
|
||||
.render_state()
|
||||
.fonts_mut()
|
||||
.add(family, &font_bytes, is_emoji);
|
||||
.add(family, &font_bytes, is_emoji, is_fallback);
|
||||
|
||||
if let Err(msg) = res {
|
||||
eprintln!("{}", msg);
|
||||
}
|
||||
mem::free_bytes();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue