Refactor char_width and friends.
@@ -538,30 +538,48 @@ pub fn get_style_color(&self, name: &str) -> Option<&Color> {
self.themes.style_color(name)
}
+ /// Calculate the width of the character "W" (being the widest character)
+ /// at the specified font size in the editor's current font family.
pub fn char_width(&self, text: &mut PietText, font_size: f64) -> f64 {
- let text_layout = text
- .new_text_layout("W")
- .font(self.editor.font_family(), font_size)
- .build()
- .unwrap();
- text_layout.size().width
- }
+ Self::editor_text_size_internal(self.editor.font_family(), font_size, text, "W").width
+ }
+
+ /// Calculate the width of `text_to_measure` in the editor's current font family and font size.
+ pub fn editor_text_width(&self, text: &mut PietText, text_to_measure: &str) -> f64 {
+ Self::editor_text_size_internal(self.editor.font_family(), self.editor.font_size as f64, text, text_to_measure).width
+ }
+
+ /// Calculate the size of `text_to_measure` in the editor's current font family and font size.
+ pub fn editor_text_size(&self, text: &mut PietText, text_to_measure: &str) -> Size {
+ Self::editor_text_size_internal(self.editor.font_family(), self.editor.font_size as f64, text, text_to_measure)
+ }
+
+ /// Efficiently calculate the size of a piece of text, without allocating.
+ /// This function should not be made public, use one of the public wrapper functions instead.
+ fn editor_text_size_internal(font_family: FontFamily, font_size: f64, text: &mut PietText, text_to_measure: &str) -> Size {
+ // Lie about the lifetime of `text_to_measure`.
+ //
+ // The method `new_text_layout` will take ownership of the variable `static_str`
+ // and hold it inside the `text_layout` object. It will normally only do this efficiently
+ // for static strs. It is valid for it do that for static strings because they are known
+ // to live for the lifetime of the program.
+ //
+ // However, in this case we want to take advantage of the optimisation inside
+ // `new_text_layout` to measure some text without allocating either a String or
+ // an Arc or an Rc. We can safely do this because the `text_layout` produced is
+ // local to this function and hence its lifetime is always stricly less than the lifetime
+ // of `text_to_measure`, irrespective of whether `text_to_measure` is actually
+ // static or not.
+ let static_str: &'static str = unsafe {
+ std::mem::transmute(text_to_measure)
+ };
- pub fn editor_text_width(&self, text: &mut PietText, c: &str) -> f64 {
let text_layout = text
- .new_text_layout(c.to_string())
- .font(self.editor.font_family(), self.editor.font_size as f64)
+ .new_text_layout(static_str)
+ .font(font_family, font_size)
.build()
.unwrap();
- text_layout.size().width
- }
- pub fn editor_text_size(&self, text: &mut PietText, c: &str) -> Size {
- let text_layout = text
- .new_text_layout(c.to_string())
- .font(self.editor.font_family(), self.editor.font_size as f64)
- .build()
- .unwrap();
text_layout.size()
}
