gpui: Add helper methods for em width and em advance (#24036)

Marshall Bowers created

This PR adds two helpers methods to the `TextSystem`:

- `em_width`
- `em_advance`

These methods return the width and advance width for an `em`,
respectively.

We were using these definitions in a number of different spots, and by
unifying them we better canonicalize that an `em` is based on the `m`
character.

Release Notes:

- N/A

Change summary

crates/editor/src/editor.rs     |  8 -----
crates/editor/src/element.rs    | 41 +++++-----------------------------
crates/gpui/src/text_system.rs  | 14 +++++++++++
crates/markdown/src/markdown.rs |  7 -----
4 files changed, 23 insertions(+), 47 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -14124,13 +14124,7 @@ impl Editor {
         let font_id = window.text_system().resolve_font(&style.text.font());
         let font_size = style.text.font_size.to_pixels(window.rem_size());
         let line_height = style.text.line_height_in_pixels(window.rem_size());
-
-        let em_width = window
-            .text_system()
-            .typographic_bounds(font_id, font_size, 'm')
-            .unwrap()
-            .size
-            .width;
+        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
 
         gpui::Point::new(em_width, line_height)
     }

crates/editor/src/element.rs 🔗

@@ -836,12 +836,7 @@ impl EditorElement {
         let style = editor.style.clone().unwrap_or_default();
         let font_id = window.text_system().resolve_font(&style.text.font());
         let font_size = style.text.font_size.to_pixels(window.rem_size());
-        let em_width = window
-            .text_system()
-            .typographic_bounds(font_id, font_size, 'm')
-            .unwrap()
-            .size
-            .width;
+        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
 
         let scroll_margin_x = EditorSettings::get_global(cx).horizontal_scroll_margin;
 
@@ -6398,12 +6393,8 @@ impl Element for EditorElement {
                                         window.text_system().resolve_font(&style.text.font());
                                     let font_size =
                                         style.text.font_size.to_pixels(window.rem_size());
-                                    let em_width = window
-                                        .text_system()
-                                        .typographic_bounds(font_id, font_size, 'm')
-                                        .unwrap()
-                                        .size
-                                        .width;
+                                    let em_width =
+                                        window.text_system().em_width(font_id, font_size).unwrap();
 
                                     size(line.width + em_width, height)
                                 },
@@ -6480,17 +6471,8 @@ impl Element for EditorElement {
                     let font_id = window.text_system().resolve_font(&style.text.font());
                     let font_size = style.text.font_size.to_pixels(window.rem_size());
                     let line_height = style.text.line_height_in_pixels(window.rem_size());
-                    let em_width = window
-                        .text_system()
-                        .typographic_bounds(font_id, font_size, 'm')
-                        .unwrap()
-                        .size
-                        .width;
-                    let em_advance = window
-                        .text_system()
-                        .advance(font_id, font_size, 'm')
-                        .unwrap()
-                        .width;
+                    let em_width = window.text_system().em_width(font_id, font_size).unwrap();
+                    let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
 
                     let letter_size = size(em_width, line_height);
 
@@ -8060,17 +8042,8 @@ fn compute_auto_height_layout(
     let font_id = window.text_system().resolve_font(&style.text.font());
     let font_size = style.text.font_size.to_pixels(window.rem_size());
     let line_height = style.text.line_height_in_pixels(window.rem_size());
-    let em_width = window
-        .text_system()
-        .typographic_bounds(font_id, font_size, 'm')
-        .unwrap()
-        .size
-        .width;
-    let em_advance = window
-        .text_system()
-        .advance(font_id, font_size, 'm')
-        .unwrap()
-        .width;
+    let em_width = window.text_system().em_width(font_id, font_size).unwrap();
+    let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
 
     let mut snapshot = editor.snapshot(window, cx);
     let gutter_dimensions = snapshot.gutter_dimensions(

crates/gpui/src/text_system.rs 🔗

@@ -195,6 +195,20 @@ impl TextSystem {
         Ok(result * font_size)
     }
 
+    /// Returns the width of an `em`.
+    ///
+    /// Uses the width of the `m` character in the given font and size.
+    pub fn em_width(&self, font_id: FontId, font_size: Pixels) -> Result<Pixels> {
+        Ok(self.typographic_bounds(font_id, font_size, 'm')?.size.width)
+    }
+
+    /// Returns the advance width of an `em`.
+    ///
+    /// Uses the advance width of the `m` character in the given font and size.
+    pub fn em_advance(&self, font_id: FontId, font_size: Pixels) -> Result<Pixels> {
+        Ok(self.advance(font_id, font_size, 'm')?.width)
+    }
+
     /// Get the number of font size units per 'em square',
     /// Per MDN: "an abstract square whose height is the intended distance between
     /// lines of type in the same type size"

crates/markdown/src/markdown.rs 🔗

@@ -528,12 +528,7 @@ impl MarkdownElement {
         let text_style = self.style.base_text_style.clone();
         let font_id = window.text_system().resolve_font(&text_style.font());
         let font_size = text_style.font_size.to_pixels(window.rem_size());
-        let em_width = window
-            .text_system()
-            .typographic_bounds(font_id, font_size, 'm')
-            .unwrap()
-            .size
-            .width;
+        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
         window.request_autoscroll(Bounds::from_corners(
             point(position.x - 3. * em_width, position.y - 3. * line_height),
             point(position.x + 3. * em_width, position.y + 3. * line_height),