From a821b48cf4fc155aba62ef516be4881af957b8a7 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 18 Dec 2023 15:35:21 +0100 Subject: [PATCH] Shape plan caching (#2876) --- crates/typst/src/layout/inline/shaping.rs | 35 +++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/crates/typst/src/layout/inline/shaping.rs b/crates/typst/src/layout/inline/shaping.rs index b91d0b0bf..b715f6648 100644 --- a/crates/typst/src/layout/inline/shaping.rs +++ b/crates/typst/src/layout/inline/shaping.rs @@ -2,10 +2,11 @@ use std::borrow::Cow; use std::fmt::{self, Debug, Formatter}; use std::ops::Range; use std::str::FromStr; +use std::sync::Arc; use az::SaturatingAs; use ecow::EcoString; -use rustybuzz::{Tag, UnicodeBuffer}; +use rustybuzz::{ShapePlan, Tag, UnicodeBuffer}; use unicode_script::{Script, UnicodeScript}; use super::SpanMapper; @@ -690,9 +691,21 @@ fn shape_segment<'a>( Dir::RTL => rustybuzz::Direction::RightToLeft, _ => unimplemented!("vertical text layout"), }); + buffer.guess_segment_properties(); + + // Prepare the shape plan. This plan depends on direction, script, language, + // and features, but is independent from the text and can thus be + // memoized. + let plan = create_shape_plan( + &font, + buffer.direction(), + buffer.script(), + buffer.language().as_ref(), + &ctx.features, + ); // Shape! - let buffer = rustybuzz::shape(font.rusty(), &ctx.features, buffer); + let buffer = rustybuzz::shape_with_plan(font.rusty(), &plan, buffer); let infos = buffer.glyph_infos(); let pos = buffer.glyph_positions(); let ltr = ctx.dir.is_positive(); @@ -783,6 +796,24 @@ fn shape_segment<'a>( ctx.used.pop(); } +/// Create a shape plan. +#[comemo::memoize] +fn create_shape_plan( + font: &Font, + direction: rustybuzz::Direction, + script: rustybuzz::Script, + language: Option<&rustybuzz::Language>, + features: &[rustybuzz::Feature], +) -> Arc { + Arc::new(rustybuzz::ShapePlan::new( + font.rusty(), + direction, + Some(script), + language, + features, + )) +} + /// Shape the text with tofus from the given font. fn shape_tofus(ctx: &mut ShapingContext, base: usize, text: &str, font: Font) { let x_advance = font.advance(0).unwrap_or_default();