Do not permanently modify ctx.features

This commit is contained in:
Malo 2025-06-29 12:49:18 +01:00
parent 06d9bec326
commit 8228d16a1e

View File

@ -804,12 +804,18 @@ fn shape_segment<'a>(
// text extraction. // text extraction.
buffer.set_flags(BufferFlags::REMOVE_DEFAULT_IGNORABLES); buffer.set_flags(BufferFlags::REMOVE_DEFAULT_IGNORABLES);
let (script_shift, script_compensation, scale) = ctx let (script_shift, script_compensation, scale, shift_feature) = ctx
.shift_settings .shift_settings
.map_or((Em::zero(), Em::zero(), Em::one()), |settings| { .map_or((Em::zero(), Em::zero(), Em::one(), None), |settings| {
compute_synthesized_shift(ctx, text, &font, settings) compute_synthesized_shift(text, &font, settings)
}); });
let has_shift_feature = shift_feature.is_some();
if let Some(feat) = shift_feature {
// Temporarily push the feature.
ctx.features.push(feat)
}
// Prepare the shape plan. This plan depends on direction, script, language, // Prepare the shape plan. This plan depends on direction, script, language,
// and features, but is independent from the text and can thus be memoized. // and features, but is independent from the text and can thus be memoized.
let plan = create_shape_plan( let plan = create_shape_plan(
@ -820,6 +826,10 @@ fn shape_segment<'a>(
&ctx.features, &ctx.features,
); );
if has_shift_feature {
ctx.features.pop();
}
// Shape! // Shape!
let buffer = rustybuzz::shape_with_plan(font.rusty(), &plan, buffer); let buffer = rustybuzz::shape_with_plan(font.rusty(), &plan, buffer);
let infos = buffer.glyph_infos(); let infos = buffer.glyph_infos();
@ -964,11 +974,10 @@ fn shape_segment<'a>(
/// synthesized, those values determine how to transform the rendered text to /// synthesized, those values determine how to transform the rendered text to
/// display scripts as expected. /// display scripts as expected.
fn compute_synthesized_shift( fn compute_synthesized_shift(
ctx: &mut ShapingContext,
text: &str, text: &str,
font: &Font, font: &Font,
settings: ShiftSettings, settings: ShiftSettings,
) -> (Em, Em, Em) { ) -> (Em, Em, Em, Option<Feature>) {
settings settings
.typographic .typographic
.then(|| { .then(|| {
@ -990,10 +999,14 @@ fn compute_synthesized_shift(
font.rusty().glyph_index(c).is_some_and(|i| coverage.contains(i)) font.rusty().glyph_index(c).is_some_and(|i| coverage.contains(i))
}) })
.then(|| { .then(|| {
ctx.features.push(Feature::new(settings.kind.feature(), 1, ..));
// If we can use the OpenType feature, we can keep the text // If we can use the OpenType feature, we can keep the text
// as is. // as is.
(Em::zero(), Em::zero(), Em::one()) (
Em::zero(),
Em::zero(),
Em::one(),
Some(Feature::new(settings.kind.feature(), 1, ..)),
)
}) })
}) })
// Reunite the cases where `typographic` is `false` or where using the // Reunite the cases where `typographic` is `false` or where using the
@ -1005,6 +1018,7 @@ fn compute_synthesized_shift(
settings.shift.unwrap_or(script_metrics.vertical_offset), settings.shift.unwrap_or(script_metrics.vertical_offset),
script_metrics.horizontal_offset, script_metrics.horizontal_offset,
settings.size.unwrap_or(script_metrics.height), settings.size.unwrap_or(script_metrics.height),
None,
) )
}) })
} }