Avoid reallocating spans buffer in TextPipeline (#15012)
# Objective - Don't reallocate the spans vector every time TextPipeline updates a buffer. ## Solution - Cache the spans buffer in `TextPipeline`. This is possible through some [rust magic](https://users.rust-lang.org/t/how-to-cache-a-vectors-capacity/94478/10).
This commit is contained in:
parent
3227c3de36
commit
49a06e9c76
@ -51,6 +51,10 @@ pub struct TextPipeline {
|
|||||||
///
|
///
|
||||||
/// See [`cosmic_text::SwashCache`] for more information.
|
/// See [`cosmic_text::SwashCache`] for more information.
|
||||||
swash_cache: SwashCache,
|
swash_cache: SwashCache,
|
||||||
|
/// Buffered vec for collecting spans.
|
||||||
|
///
|
||||||
|
/// See [this dark magic](https://users.rust-lang.org/t/how-to-cache-a-vectors-capacity/94478/10).
|
||||||
|
spans_buffer: Vec<(&'static str, Attrs<'static>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextPipeline {
|
impl TextPipeline {
|
||||||
@ -95,23 +99,29 @@ impl TextPipeline {
|
|||||||
// The section index is stored in the metadata of the spans, and could be used
|
// The section index is stored in the metadata of the spans, and could be used
|
||||||
// to look up the section the span came from and is not used internally
|
// to look up the section the span came from and is not used internally
|
||||||
// in cosmic-text.
|
// in cosmic-text.
|
||||||
let spans: Vec<(&str, Attrs)> = sections
|
let mut spans: Vec<(&str, Attrs)> = std::mem::take(&mut self.spans_buffer)
|
||||||
.iter()
|
.into_iter()
|
||||||
.enumerate()
|
.map(|_| -> (&str, Attrs) { unreachable!() })
|
||||||
.filter(|(_section_index, section)| section.style.font_size > 0.0)
|
|
||||||
.map(|(section_index, section)| {
|
|
||||||
(
|
|
||||||
§ion.value[..],
|
|
||||||
get_attrs(
|
|
||||||
section,
|
|
||||||
section_index,
|
|
||||||
font_system,
|
|
||||||
&self.map_handle_to_font_id,
|
|
||||||
scale_factor,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
spans.extend(
|
||||||
|
sections
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_section_index, section)| section.style.font_size > 0.0)
|
||||||
|
.map(|(section_index, section)| {
|
||||||
|
(
|
||||||
|
§ion.value[..],
|
||||||
|
get_attrs(
|
||||||
|
section,
|
||||||
|
section_index,
|
||||||
|
font_system,
|
||||||
|
&self.map_handle_to_font_id,
|
||||||
|
scale_factor,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let spans_iter = spans.iter().copied();
|
||||||
|
|
||||||
buffer.set_metrics(font_system, metrics);
|
buffer.set_metrics(font_system, metrics);
|
||||||
buffer.set_size(font_system, bounds.width, bounds.height);
|
buffer.set_size(font_system, bounds.width, bounds.height);
|
||||||
@ -126,7 +136,7 @@ impl TextPipeline {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
buffer.set_rich_text(font_system, spans, Attrs::new(), Shaping::Advanced);
|
buffer.set_rich_text(font_system, spans_iter, Attrs::new(), Shaping::Advanced);
|
||||||
|
|
||||||
// PERF: https://github.com/pop-os/cosmic-text/issues/166:
|
// PERF: https://github.com/pop-os/cosmic-text/issues/166:
|
||||||
// Setting alignment afterwards appears to invalidate some layouting performed by `set_text` which is presumably not free?
|
// Setting alignment afterwards appears to invalidate some layouting performed by `set_text` which is presumably not free?
|
||||||
@ -135,6 +145,13 @@ impl TextPipeline {
|
|||||||
}
|
}
|
||||||
buffer.shape_until_scroll(font_system, false);
|
buffer.shape_until_scroll(font_system, false);
|
||||||
|
|
||||||
|
// Recover the spans buffer.
|
||||||
|
spans.clear();
|
||||||
|
self.spans_buffer = spans
|
||||||
|
.into_iter()
|
||||||
|
.map(|_| -> (&'static str, Attrs<'static>) { unreachable!() })
|
||||||
|
.collect();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user