[harfrust] Reuse cached per-shape metadata (#6200)
diff --git a/src/rust/shape.rs b/src/rust/shape.rs
index 45a47ea..fa81c25 100644
--- a/src/rust/shape.rs
+++ b/src/rust/shape.rs
@@ -135,6 +135,9 @@
pub struct HBHarfRustFontData {
instance: FontInstance,
+ x_scale: i32,
+ y_scale: i32,
+ ptem: Option<f32>,
}
struct HBHarfBuzzFontFuncs {
@@ -251,7 +254,18 @@
let face_data = face_data as *const HBHarfRustFaceData;
let instance = font_to_instance(font, &(*face_data).font);
- let hr_font_data = HBHarfRustFontData { instance };
+ let mut x_scale = 0;
+ let mut y_scale = 0;
+ hb_font_get_scale(font, &mut x_scale, &mut y_scale);
+ let ptem = hb_font_get_ptem(font);
+ let ptem = (ptem > 0.0).then_some(ptem);
+ // HarfBuzz invalidates shaper font data when any of these values change.
+ let hr_font_data = HBHarfRustFontData {
+ instance,
+ x_scale,
+ y_scale,
+ ptem,
+ };
let hr_font_data = Box::new(hr_font_data);
let hr_font_data_ptr = Box::into_raw(hr_font_data);
@@ -366,6 +380,7 @@
let hr_buffer_box = hr_buffer_box as *mut harfrust::UnicodeBuffer;
let mut hr_buffer_box = Box::from_raw(hr_buffer_box);
let mut hr_buffer = *hr_buffer_box;
+ let shape_plan = (shape_plan as *const harfrust::ShapePlan).as_ref();
// Set buffer properties
let cluster_level = hb_buffer_get_cluster_level(buffer);
@@ -393,27 +408,32 @@
hr_buffer.set_not_found_variation_selector_glyph(not_found_variation_selector_glyph);
}
- // Segment properties:
- let script = hb_buffer_get_script(buffer);
- let language = hb_buffer_get_language(buffer);
- let direction = hb_buffer_get_direction(buffer);
- // Convert to HarfRust types
- let script = harfrust::Script::from_iso15924_tag(Tag::from_u32(script as u32))
- .unwrap_or(harfrust::script::UNKNOWN);
- let language = hb_language_to_hr_language(language);
- let direction = match direction {
- hb_direction_t_HB_DIRECTION_LTR => harfrust::Direction::LeftToRight,
- hb_direction_t_HB_DIRECTION_RTL => harfrust::Direction::RightToLeft,
- hb_direction_t_HB_DIRECTION_TTB => harfrust::Direction::TopToBottom,
- hb_direction_t_HB_DIRECTION_BTT => harfrust::Direction::BottomToTop,
- _ => harfrust::Direction::Invalid,
- };
- // Set properties on the buffer
- hr_buffer.set_script(script);
- if let Some(lang) = language {
- hr_buffer.set_language(lang);
+ if let Some(plan) = shape_plan {
+ // Language is only used to build the plan; shaping with an explicit
+ // plan reads its cached segment properties instead of buffer language.
+ hr_buffer.set_script(plan.script().unwrap_or(harfrust::script::UNKNOWN));
+ hr_buffer.set_direction(plan.direction());
+ } else {
+ // Convert segment properties when shaping without a cached plan.
+ let script = hb_buffer_get_script(buffer);
+ let language = hb_buffer_get_language(buffer);
+ let direction = hb_buffer_get_direction(buffer);
+ let script = harfrust::Script::from_iso15924_tag(Tag::from_u32(script as u32))
+ .unwrap_or(harfrust::script::UNKNOWN);
+ let language = hb_language_to_hr_language(language);
+ let direction = match direction {
+ hb_direction_t_HB_DIRECTION_LTR => harfrust::Direction::LeftToRight,
+ hb_direction_t_HB_DIRECTION_RTL => harfrust::Direction::RightToLeft,
+ hb_direction_t_HB_DIRECTION_TTB => harfrust::Direction::TopToBottom,
+ hb_direction_t_HB_DIRECTION_BTT => harfrust::Direction::BottomToTop,
+ _ => harfrust::Direction::Invalid,
+ };
+ hr_buffer.set_script(script);
+ if let Some(lang) = language {
+ hr_buffer.set_language(lang);
+ }
+ hr_buffer.set_direction(direction);
}
- hr_buffer.set_direction(direction);
// Populate buffer
let count = hb_buffer_get_length(buffer);
@@ -428,19 +448,12 @@
let post_context = std::slice::from_raw_parts(post_context, post_context_length as usize);
hr_buffer.set_post_context_codepoints(post_context);
- let ptem = hb_font_get_ptem(font);
- let ptem = if ptem > 0.0 { Some(ptem) } else { None };
-
let features = hb_feature_to_hr_feature(features, num_features);
- let shape_plan = (shape_plan as *const harfrust::ShapePlan).as_ref();
- let mut x_scale = 0;
- let mut y_scale = 0;
- hb_font_get_scale(font, &mut x_scale, &mut y_scale);
let mut font_funcs = HBHarfBuzzFontFuncs { font };
let options = ShapeOptions::new()
.plan(shape_plan)
- .scale_separate(Some((x_scale, y_scale)))
- .point_size(ptem)
+ .scale_separate(Some(((*font_data).x_scale, (*font_data).y_scale)))
+ .point_size((*font_data).ptem)
.features(&features)
.font_funcs(Some(&mut font_funcs));
let glyphs = harfrust::shape(&(*font_data).instance, hr_buffer, options);