From d10fc6ce3f34239df26a81db5c2bebb6ca10c296 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 2 Apr 2021 13:49:44 +0200 Subject: [PATCH] Fix crash when selections exceed the container's bounds --- gpui/src/geometry.rs | 8 +++++++- gpui/src/platform/mac/renderer.rs | 2 ++ gpui/src/platform/mac/shaders/shaders.h | 2 ++ gpui/src/platform/mac/shaders/shaders.metal | 16 ++++++++++++++-- gpui/src/scene.rs | 4 +++- zed/src/editor/buffer_element.rs | 19 ++++++++++++------- 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/gpui/src/geometry.rs b/gpui/src/geometry.rs index af2c786513..ba6cabfea1 100644 --- a/gpui/src/geometry.rs +++ b/gpui/src/geometry.rs @@ -54,7 +54,13 @@ impl PathBuilder { self.current = point; } - pub fn build(self, color: ColorU) -> Path { + pub fn build(mut self, color: ColorU, clip_bounds: Option) -> Path { + if let Some(clip_bounds) = clip_bounds { + self.bounds = self + .bounds + .intersection(clip_bounds) + .unwrap_or(RectF::default()); + } Path { bounds: self.bounds, color, diff --git a/gpui/src/platform/mac/renderer.rs b/gpui/src/platform/mac/renderer.rs index 28576bdc57..daa27a99bc 100644 --- a/gpui/src/platform/mac/renderer.rs +++ b/gpui/src/platform/mac/renderer.rs @@ -181,6 +181,8 @@ impl Renderer { vertices.push(shaders::GPUIPathVertex { xy_position: (atlas_origin + xy_position).to_float2(), st_position: vertex.st_position.to_float2(), + clip_rect_origin: atlas_origin.to_float2(), + clip_rect_size: size.to_float2(), }); } } diff --git a/gpui/src/platform/mac/shaders/shaders.h b/gpui/src/platform/mac/shaders/shaders.h index d72d346bee..2241a25c2a 100644 --- a/gpui/src/platform/mac/shaders/shaders.h +++ b/gpui/src/platform/mac/shaders/shaders.h @@ -63,4 +63,6 @@ typedef enum { typedef struct { vector_float2 xy_position; vector_float2 st_position; + vector_float2 clip_rect_origin; + vector_float2 clip_rect_size; } GPUIPathVertex; diff --git a/gpui/src/platform/mac/shaders/shaders.metal b/gpui/src/platform/mac/shaders/shaders.metal index 9124d5744f..9efe409768 100644 --- a/gpui/src/platform/mac/shaders/shaders.metal +++ b/gpui/src/platform/mac/shaders/shaders.metal @@ -218,21 +218,33 @@ fragment float4 sprite_fragment( return color; } +struct PathAtlasVertexOutput { + float4 position [[position]]; + float2 st_position; + float clip_rect_distance [[clip_distance]] [4]; +}; + struct PathAtlasFragmentInput { float4 position [[position]]; float2 st_position; }; -vertex PathAtlasFragmentInput path_atlas_vertex( +vertex PathAtlasVertexOutput path_atlas_vertex( uint vertex_id [[vertex_id]], constant GPUIPathVertex *vertices [[buffer(GPUIPathAtlasVertexInputIndexVertices)]], constant float2 *atlas_size [[buffer(GPUIPathAtlasVertexInputIndexAtlasSize)]] ) { GPUIPathVertex v = vertices[vertex_id]; float4 device_position = to_device_position(v.xy_position, *atlas_size); - return PathAtlasFragmentInput { + return PathAtlasVertexOutput { device_position, v.st_position, + { + v.xy_position.x - v.clip_rect_origin.x, + v.clip_rect_origin.x + v.clip_rect_size.x - v.xy_position.x, + v.xy_position.y - v.clip_rect_origin.y, + v.clip_rect_origin.y + v.clip_rect_size.y - v.xy_position.y + } }; } diff --git a/gpui/src/scene.rs b/gpui/src/scene.rs index ee504c019b..49d56b0007 100644 --- a/gpui/src/scene.rs +++ b/gpui/src/scene.rs @@ -156,7 +156,9 @@ impl Layer { } fn push_path(&mut self, path: Path) { - self.paths.push(path); + if !path.bounds.is_empty() { + self.paths.push(path); + } } pub fn paths(&self) -> &[Path] { diff --git a/zed/src/editor/buffer_element.rs b/zed/src/editor/buffer_element.rs index 5d8be65769..ebb8ecfe79 100644 --- a/zed/src/editor/buffer_element.rs +++ b/zed/src/editor/buffer_element.rs @@ -259,7 +259,7 @@ impl BufferElement { .collect(), }; - selection.paint(ctx.scene); + selection.paint(bounds, ctx.scene); } if view.cursors_visible() { @@ -586,16 +586,21 @@ struct SelectionLine { } impl Selection { - fn paint(&self, scene: &mut Scene) { + fn paint(&self, bounds: RectF, scene: &mut Scene) { if self.lines.len() >= 2 && self.lines[0].start_x > self.lines[1].end_x { - self.paint_lines(self.start_y, &self.lines[0..1], scene); - self.paint_lines(self.start_y + self.line_height, &self.lines[1..], scene); + self.paint_lines(self.start_y, &self.lines[0..1], bounds, scene); + self.paint_lines( + self.start_y + self.line_height, + &self.lines[1..], + bounds, + scene, + ); } else { - self.paint_lines(self.start_y, &self.lines, scene); + self.paint_lines(self.start_y, &self.lines, bounds, scene); } } - fn paint_lines(&self, start_y: f32, lines: &[SelectionLine], scene: &mut Scene) { + fn paint_lines(&self, start_y: f32, lines: &[SelectionLine], bounds: RectF, scene: &mut Scene) { if lines.is_empty() { return; } @@ -675,7 +680,7 @@ impl Selection { path.curve_to(first_top_left + top_curve_width, first_top_left); path.line_to(first_top_right - top_curve_width); - scene.push_path(path.build(ColorF::new(0.639, 0.839, 1.0, 1.0).to_u8())); + scene.push_path(path.build(ColorF::new(0.639, 0.839, 1.0, 1.0).to_u8(), Some(bounds))); } }