Make `Line::paint` interface consistent with `Line::paint_wrapped`

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

gpui/examples/text.rs      |  6 ++--
gpui/src/elements/label.rs |  6 ---
gpui/src/text_layout.rs    | 14 +++++++--
zed/src/editor/element.rs  | 55 +++++++++++++++++++++++----------------
4 files changed, 46 insertions(+), 35 deletions(-)

Detailed changes

gpui/examples/text.rs 🔗

@@ -49,7 +49,7 @@ impl gpui::Element for TextElement {
     fn paint(
         &mut self,
         bounds: RectF,
-        _: RectF,
+        visible_bounds: RectF,
         _: &mut Self::LayoutState,
         cx: &mut gpui::PaintContext,
     ) -> Self::PaintState {
@@ -84,11 +84,11 @@ impl gpui::Element for TextElement {
         );
 
         cx.scene.push_quad(Quad {
-            bounds: bounds,
+            bounds,
             background: Some(Color::white()),
             ..Default::default()
         });
-        line.paint(bounds.origin(), bounds, cx);
+        line.paint(bounds.origin(), visible_bounds, bounds.height(), cx);
     }
 
     fn dispatch_event(

gpui/src/elements/label.rs 🔗

@@ -132,11 +132,7 @@ impl Element for Label {
         line: &mut Self::LayoutState,
         cx: &mut PaintContext,
     ) -> Self::PaintState {
-        line.paint(
-            bounds.origin(),
-            RectF::new(vec2f(0., 0.), bounds.size()),
-            cx,
-        )
+        line.paint(bounds.origin(), visible_bounds, bounds.size().y(), cx)
     }
 
     fn dispatch_event(

gpui/src/text_layout.rs 🔗

@@ -205,8 +205,14 @@ impl Line {
         }
     }
 
-    pub fn paint(&self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
-        let padding_top = (visible_bounds.height() - self.layout.ascent - self.layout.descent) / 2.;
+    pub fn paint(
+        &self,
+        origin: Vector2F,
+        visible_bounds: RectF,
+        line_height: f32,
+        cx: &mut PaintContext,
+    ) {
+        let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.;
         let baseline_origin = vec2f(0., padding_top + self.layout.ascent);
 
         let mut color_runs = self.color_runs.iter();
@@ -220,7 +226,7 @@ impl Line {
                 .x();
 
             for glyph in &run.glyphs {
-                let glyph_origin = baseline_origin + glyph.position;
+                let glyph_origin = origin + baseline_origin + glyph.position;
 
                 if glyph_origin.x() + max_glyph_width < visible_bounds.origin().x() {
                     continue;
@@ -243,7 +249,7 @@ impl Line {
                     font_id: run.font_id,
                     font_size: self.layout.font_size,
                     id: glyph.id,
-                    origin: origin + glyph_origin,
+                    origin: glyph_origin,
                     color,
                 });
             }

zed/src/editor/element.rs 🔗

@@ -234,25 +234,33 @@ impl EditorElement {
         }
     }
 
-    fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, cx: &mut PaintContext) {
+    fn paint_gutter(
+        &mut self,
+        bounds: RectF,
+        visible_bounds: RectF,
+        layout: &LayoutState,
+        cx: &mut PaintContext,
+    ) {
         let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
         for (ix, line) in layout.line_number_layouts.iter().enumerate() {
             if let Some(line) = line {
-                let line_origin = rect.origin()
+                let line_origin = bounds.origin()
                     + vec2f(
-                        rect.width() - line.width() - layout.gutter_padding,
+                        bounds.width() - line.width() - layout.gutter_padding,
                         ix as f32 * layout.line_height - (scroll_top % layout.line_height),
                     );
-                line.paint(
-                    line_origin,
-                    RectF::new(vec2f(0., 0.), vec2f(line.width(), layout.line_height)),
-                    cx,
-                );
+                line.paint(line_origin, visible_bounds, layout.line_height, cx);
             }
         }
     }
 
-    fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, cx: &mut PaintContext) {
+    fn paint_text(
+        &mut self,
+        bounds: RectF,
+        visible_bounds: RectF,
+        layout: &LayoutState,
+        cx: &mut PaintContext,
+    ) {
         let view = self.view(cx.app);
         let settings = self.view(cx.app).settings.borrow();
         let theme = &settings.theme.editor;
@@ -338,17 +346,18 @@ impl EditorElement {
             }
         }
 
-        // Draw glyphs
-        for (ix, line) in layout.line_layouts.iter().enumerate() {
-            let row = start_row + ix as u32;
-            line.paint(
-                content_origin + vec2f(-scroll_left, row as f32 * layout.line_height - scroll_top),
-                RectF::new(
-                    vec2f(scroll_left, 0.),
-                    vec2f(bounds.width(), layout.line_height),
-                ),
-                cx,
-            );
+        if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
+            // Draw glyphs
+            for (ix, line) in layout.line_layouts.iter().enumerate() {
+                let row = start_row + ix as u32;
+                line.paint(
+                    content_origin
+                        + vec2f(-scroll_left, row as f32 * layout.line_height - scroll_top),
+                    visible_text_bounds,
+                    layout.line_height,
+                    cx,
+                );
+            }
         }
 
         cx.scene.push_layer(Some(bounds));
@@ -559,7 +568,7 @@ impl Element for EditorElement {
     fn paint(
         &mut self,
         bounds: RectF,
-        _: RectF,
+        visible_bounds: RectF,
         layout: &mut Self::LayoutState,
         cx: &mut PaintContext,
     ) -> Self::PaintState {
@@ -574,9 +583,9 @@ impl Element for EditorElement {
 
             self.paint_background(gutter_bounds, text_bounds, layout, cx);
             if layout.gutter_size.x() > 0. {
-                self.paint_gutter(gutter_bounds, layout, cx);
+                self.paint_gutter(gutter_bounds, visible_bounds, layout, cx);
             }
-            self.paint_text(text_bounds, layout, cx);
+            self.paint_text(text_bounds, visible_bounds, layout, cx);
 
             cx.scene.pop_layer();