diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index c21d31aa5c14e3b596a6089630b29a3e55a3084d..9822ec23d5af41ee6fbfdd7c471f6fcc9437c78b 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -6043,7 +6043,6 @@ impl EditorElement { window.with_content_mask( Some(ContentMask { bounds: layout.position_map.text_hitbox.bounds, - ..Default::default() }), |window| { let editor = self.editor.read(cx); @@ -6986,15 +6985,9 @@ impl EditorElement { } else { let mut bounds = layout.hitbox.bounds; bounds.origin.x += layout.gutter_hitbox.bounds.size.width; - window.with_content_mask( - Some(ContentMask { - bounds, - ..Default::default() - }), - |window| { - block.element.paint(window, cx); - }, - ) + window.with_content_mask(Some(ContentMask { bounds }), |window| { + block.element.paint(window, cx); + }) } } } @@ -8297,13 +8290,9 @@ impl Element for EditorElement { } let rem_size = self.rem_size(cx); - let content_mask = ContentMask { - bounds, - ..Default::default() - }; window.with_rem_size(rem_size, |window| { window.with_text_style(Some(text_style), |window| { - window.with_content_mask(Some(content_mask), |window| { + window.with_content_mask(Some(ContentMask { bounds }), |window| { let (mut snapshot, is_read_only) = self.editor.update(cx, |editor, cx| { (editor.snapshot(window, cx), editor.read_only(cx)) }); @@ -9411,13 +9400,9 @@ impl Element for EditorElement { ..Default::default() }; let rem_size = self.rem_size(cx); - let content_mask = ContentMask { - bounds, - ..Default::default() - }; window.with_rem_size(rem_size, |window| { window.with_text_style(Some(text_style), |window| { - window.with_content_mask(Some(content_mask), |window| { + window.with_content_mask(Some(ContentMask { bounds }), |window| { self.paint_mouse_listeners(layout, window, cx); self.paint_background(layout, window, cx); self.paint_indent_guides(layout, window, cx); diff --git a/crates/gpui/examples/content_mask.rs b/crates/gpui/examples/content_mask.rs deleted file mode 100644 index 8d40cc5bba7c35395cbeef009f6b648ed68826ed..0000000000000000000000000000000000000000 --- a/crates/gpui/examples/content_mask.rs +++ /dev/null @@ -1,228 +0,0 @@ -use gpui::{ - App, Application, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, - rgb, size, -}; - -struct Example {} - -impl Render for Example { - fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { - div() - .font_family(".SystemUIFont") - .flex() - .flex_col() - .size_full() - .p_4() - .gap_4() - .bg(rgb(0x505050)) - .justify_center() - .items_center() - .text_center() - .shadow_lg() - .text_sm() - .text_color(rgb(0xffffff)) - .child( - div() - .overflow_hidden() - .rounded(px(32.)) - .border(px(8.)) - .border_color(gpui::white()) - .text_color(gpui::white()) - .child( - div() - .bg(gpui::black()) - .py_2() - .px_7() - .border_l_2() - .border_r_2() - .border_b_3() - .border_color(gpui::red()) - .child("Let build applications with GPUI"), - ) - .child( - div() - .bg(rgb(0x222222)) - .text_sm() - .py_1() - .px_7() - .border_l_3() - .border_r_3() - .border_color(gpui::green()) - .child("The fast, productive UI framework for Rust"), - ) - .child( - div() - .bg(rgb(0x222222)) - .w_full() - .flex() - .flex_row() - .text_sm() - .text_color(rgb(0xc0c0c0)) - .child( - div() - .flex_1() - .p_2() - .border_3() - .border_dashed() - .border_color(gpui::blue()) - .child("Rust"), - ) - .child( - div() - .flex_1() - .p_2() - .border_t_3() - .border_r_3() - .border_b_3() - .border_dashed() - .border_color(gpui::blue()) - .child("GPU Rendering"), - ), - ), - ) - .child( - div() - .flex() - .flex_col() - .w(px(320.)) - .gap_1() - .overflow_hidden() - .rounded(px(16.)) - .child( - div() - .w_full() - .p_2() - .bg(gpui::red()) - .child("Clip background"), - ), - ) - .child( - div() - .flex() - .flex_col() - .w(px(320.)) - .gap_1() - .rounded(px(16.)) - .child( - div() - .w_full() - .p_2() - .bg(gpui::yellow()) - .text_color(gpui::black()) - .child("No content mask"), - ), - ) - .child( - div() - .flex() - .flex_col() - .w(px(320.)) - .gap_1() - .overflow_hidden() - .rounded(px(16.)) - .child( - div() - .w_full() - .p_2() - .border_4() - .border_color(gpui::blue()) - .bg(gpui::blue().alpha(0.4)) - .child("Clip borders"), - ), - ) - .child( - div() - .flex() - .flex_col() - .w(px(320.)) - .gap_1() - .overflow_hidden() - .rounded(px(20.)) - .child( - div().w_full().border_2().border_color(gpui::black()).child( - div() - .size_full() - .bg(gpui::green().alpha(0.4)) - .p_2() - .border_8() - .border_color(gpui::green()) - .child("Clip nested elements"), - ), - ), - ) - .child( - div() - .flex() - .flex_col() - .w(px(320.)) - .gap_1() - .overflow_hidden() - .rounded(px(32.)) - .child( - div() - .w_full() - .p_2() - .bg(gpui::black()) - .border_2() - .border_dashed() - .rounded_lg() - .border_color(gpui::white()) - .child("dash border full and rounded"), - ) - .child( - div() - .w_full() - .flex() - .flex_row() - .gap_2() - .child( - div() - .w_full() - .p_2() - .bg(gpui::black()) - .border_x_2() - .border_dashed() - .rounded_lg() - .border_color(gpui::white()) - .child("border x"), - ) - .child( - div() - .w_full() - .p_2() - .bg(gpui::black()) - .border_y_2() - .border_dashed() - .rounded_lg() - .border_color(gpui::white()) - .child("border y"), - ), - ) - .child( - div() - .w_full() - .p_2() - .bg(gpui::black()) - .border_2() - .border_dashed() - .border_color(gpui::white()) - .child("border full and no rounded"), - ), - ) - } -} - -fn main() { - Application::new().run(|cx: &mut App| { - let bounds = Bounds::centered(None, size(px(800.), px(600.)), cx); - cx.open_window( - WindowOptions { - window_bounds: Some(WindowBounds::Windowed(bounds)), - ..Default::default() - }, - |_, cx| cx.new(|_| Example {}), - ) - .unwrap(); - cx.activate(true); - }); -} diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index 9ae497cef92c9f1aa68eea4af6aea8bf410a817f..ed4ca64e83513531b9176f05c4c00b0af71aea74 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -8,10 +8,10 @@ //! If all of your elements are the same height, see [`crate::UniformList`] for a simpler API use crate::{ - AnyElement, App, AvailableSpace, Bounds, ContentMask, Corners, DispatchPhase, Edges, Element, - EntityId, FocusHandle, GlobalElementId, Hitbox, HitboxBehavior, InspectorElementId, - IntoElement, Overflow, Pixels, Point, ScrollDelta, ScrollWheelEvent, Size, Style, - StyleRefinement, Styled, Window, point, px, size, + AnyElement, App, AvailableSpace, Bounds, ContentMask, DispatchPhase, Edges, Element, EntityId, + FocusHandle, GlobalElementId, Hitbox, HitboxBehavior, InspectorElementId, IntoElement, + Overflow, Pixels, Point, ScrollDelta, ScrollWheelEvent, Size, Style, StyleRefinement, Styled, + Window, point, px, size, }; use collections::VecDeque; use refineable::Refineable as _; @@ -705,7 +705,6 @@ impl StateInner { &mut self, bounds: Bounds, padding: Edges, - corner_radii: Corners, autoscroll: bool, render_item: &mut RenderItemFn, window: &mut Window, @@ -729,15 +728,9 @@ impl StateInner { let mut item_origin = bounds.origin + Point::new(px(0.), padding.top); item_origin.y -= layout_response.scroll_top.offset_in_item; for item in &mut layout_response.item_layouts { - window.with_content_mask( - Some(ContentMask { - bounds, - corner_radii, - }), - |window| { - item.element.prepaint_at(item_origin, window, cx); - }, - ); + window.with_content_mask(Some(ContentMask { bounds }), |window| { + item.element.prepaint_at(item_origin, window, cx); + }); if let Some(autoscroll_bounds) = window.take_autoscroll() && autoscroll @@ -959,34 +952,19 @@ impl Element for List { state.items = new_items; } - let rem_size = window.rem_size(); - let padding = style.padding.to_pixels(bounds.size.into(), rem_size); - let corner_radii = style.corner_radii.to_pixels(rem_size); - let layout = match state.prepaint_items( - bounds, - padding, - corner_radii, - true, - &mut self.render_item, - window, - cx, - ) { - Ok(layout) => layout, - Err(autoscroll_request) => { - state.logical_scroll_top = Some(autoscroll_request); - state - .prepaint_items( - bounds, - padding, - corner_radii, - false, - &mut self.render_item, - window, - cx, - ) - .unwrap() - } - }; + let padding = style + .padding + .to_pixels(bounds.size.into(), window.rem_size()); + let layout = + match state.prepaint_items(bounds, padding, true, &mut self.render_item, window, cx) { + Ok(layout) => layout, + Err(autoscroll_request) => { + state.logical_scroll_top = Some(autoscroll_request); + state + .prepaint_items(bounds, padding, false, &mut self.render_item, window, cx) + .unwrap() + } + }; state.last_layout_bounds = Some(bounds); state.last_padding = Some(padding); @@ -1004,17 +982,11 @@ impl Element for List { cx: &mut App, ) { let current_view = window.current_view(); - window.with_content_mask( - Some(ContentMask { - bounds, - ..Default::default() - }), - |window| { - for item in &mut prepaint.layout.item_layouts { - item.element.paint(window, cx); - } - }, - ); + window.with_content_mask(Some(ContentMask { bounds }), |window| { + for item in &mut prepaint.layout.item_layouts { + item.element.paint(window, cx); + } + }); let list_state = self.state.clone(); let height = bounds.size.height; diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index db3b8c88395388bf57eb16a0bb73ce2d6f005779..cdf90d4eb8934de99a21c65b6c9efa2a2fdde258 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -411,10 +411,7 @@ impl Element for UniformList { (self.render_items)(visible_range.clone(), window, cx) }; - let content_mask = ContentMask { - bounds, - ..Default::default() - }; + let content_mask = ContentMask { bounds }; window.with_content_mask(Some(content_mask), |window| { for (mut item, ix) in items.into_iter().zip(visible_range.clone()) { let item_origin = padded_bounds.origin diff --git a/crates/gpui/src/platform/blade/shaders.wgsl b/crates/gpui/src/platform/blade/shaders.wgsl index dbab4237e3eb87c570096ae7b6d7328fa1da6ff2..95980b54fe4f25b3936d6b095219c5674211dd0a 100644 --- a/crates/gpui/src/platform/blade/shaders.wgsl +++ b/crates/gpui/src/platform/blade/shaders.wgsl @@ -53,11 +53,6 @@ struct Corners { bottom_left: f32, } -struct ContentMask { - bounds: Bounds, - corner_radii: Corners, -} - struct Edges { top: f32, right: f32, @@ -445,7 +440,7 @@ struct Quad { order: u32, border_style: u32, bounds: Bounds, - content_mask: ContentMask, + content_mask: Bounds, background: Background, border_color: Hsla, corner_radii: Corners, @@ -483,7 +478,7 @@ fn vs_quad(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index) insta out.background_color1 = gradient.color1; out.border_color = hsla_to_rgba(quad.border_color); out.quad_id = instance_id; - out.clip_distances = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask.bounds); + out.clip_distances = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask); return out; } @@ -496,19 +491,8 @@ fn fs_quad(input: QuadVarying) -> @location(0) vec4 { let quad = b_quads[input.quad_id]; - // Signed distance field threshold for inclusion of pixels. 0.5 is the - // minimum distance between the center of the pixel and the edge. - let antialias_threshold = 0.5; - - var background_color = gradient_color(quad.background, input.position.xy, quad.bounds, + let background_color = gradient_color(quad.background, input.position.xy, quad.bounds, input.background_solid, input.background_color0, input.background_color1); - var border_color = input.border_color; - - // Apply content_mask corner radii clipping - let clip_sdf = quad_sdf(input.position.xy, quad.content_mask.bounds, quad.content_mask.corner_radii); - let clip_alpha = saturate(antialias_threshold - clip_sdf); - background_color.a *= clip_alpha; - border_color.a *= clip_alpha; let unrounded = quad.corner_radii.top_left == 0.0 && quad.corner_radii.bottom_left == 0.0 && @@ -529,6 +513,10 @@ fn fs_quad(input: QuadVarying) -> @location(0) vec4 { let point = input.position.xy - quad.bounds.origin; let center_to_point = point - half_size; + // Signed distance field threshold for inclusion of pixels. 0.5 is the + // minimum distance between the center of the pixel and the edge. + let antialias_threshold = 0.5; + // Radius of the nearest corner let corner_radius = pick_corner_radius(center_to_point, quad.corner_radii); @@ -619,6 +607,8 @@ fn fs_quad(input: QuadVarying) -> @location(0) vec4 { var color = background_color; if (border_sdf < antialias_threshold) { + var border_color = input.border_color; + // Dashed border logic when border_style == 1 if (quad.border_style == 1) { // Position along the perimeter in "dash space", where each dash @@ -654,11 +644,7 @@ fn fs_quad(input: QuadVarying) -> @location(0) vec4 { let is_horizontal = corner_center_to_point.x < corner_center_to_point.y; - var border_width = select(border.y, border.x, is_horizontal); - // When border width of some side is 0, we need to use the other side width for dash velocity. - if (border_width == 0.0) { - border_width = select(border.x, border.y, is_horizontal); - } + let border_width = select(border.y, border.x, is_horizontal); dash_velocity = dv_numerator / border_width; t = select(point.y, point.x, is_horizontal) * dash_velocity; max_t = select(size.y, size.x, is_horizontal) * dash_velocity; @@ -870,7 +856,7 @@ struct Shadow { blur_radius: f32, bounds: Bounds, corner_radii: Corners, - content_mask: ContentMask, + content_mask: Bounds, color: Hsla, } var b_shadows: array; @@ -898,7 +884,7 @@ fn vs_shadow(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index) ins out.position = to_device_position(unit_vertex, shadow.bounds); out.color = hsla_to_rgba(shadow.color); out.shadow_id = instance_id; - out.clip_distances = distance_from_clip_rect(unit_vertex, shadow.bounds, shadow.content_mask.bounds); + out.clip_distances = distance_from_clip_rect(unit_vertex, shadow.bounds, shadow.content_mask); return out; } @@ -913,6 +899,7 @@ fn fs_shadow(input: ShadowVarying) -> @location(0) vec4 { let half_size = shadow.bounds.size / 2.0; let center = shadow.bounds.origin + half_size; let center_to_point = input.position.xy - center; + let corner_radius = pick_corner_radius(center_to_point, shadow.corner_radii); // The signal is only non-zero in a limited range, so don't waste samples @@ -1040,7 +1027,7 @@ struct Underline { order: u32, pad: u32, bounds: Bounds, - content_mask: ContentMask, + content_mask: Bounds, color: Hsla, thickness: f32, wavy: u32, @@ -1064,7 +1051,7 @@ fn vs_underline(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index) out.position = to_device_position(unit_vertex, underline.bounds); out.color = hsla_to_rgba(underline.color); out.underline_id = instance_id; - out.clip_distances = distance_from_clip_rect(unit_vertex, underline.bounds, underline.content_mask.bounds); + out.clip_distances = distance_from_clip_rect(unit_vertex, underline.bounds, underline.content_mask); return out; } @@ -1106,7 +1093,7 @@ struct MonochromeSprite { order: u32, pad: u32, bounds: Bounds, - content_mask: ContentMask, + content_mask: Bounds, color: Hsla, tile: AtlasTile, transformation: TransformationMatrix, @@ -1130,7 +1117,7 @@ fn vs_mono_sprite(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index out.tile_position = to_tile_position(unit_vertex, sprite.tile); out.color = hsla_to_rgba(sprite.color); - out.clip_distances = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask.bounds); + out.clip_distances = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask); return out; } @@ -1152,7 +1139,7 @@ struct PolychromeSprite { grayscale: u32, opacity: f32, bounds: Bounds, - content_mask: ContentMask, + content_mask: Bounds, corner_radii: Corners, tile: AtlasTile, } @@ -1174,7 +1161,7 @@ fn vs_poly_sprite(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index out.position = to_device_position(unit_vertex, sprite.bounds); out.tile_position = to_tile_position(unit_vertex, sprite.tile); out.sprite_id = instance_id; - out.clip_distances = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask.bounds); + out.clip_distances = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask); return out; } @@ -1247,12 +1234,3 @@ fn fs_surface(input: SurfaceVarying) -> @location(0) vec4 { return ycbcr_to_RGB * y_cb_cr; } - -fn max_corner_radii(a: Corners, b: Corners) -> Corners { - return Corners( - max(a.top_left, b.top_left), - max(a.top_right, b.top_right), - max(a.bottom_right, b.bottom_right), - max(a.bottom_left, b.bottom_left) - ); -} diff --git a/crates/gpui/src/platform/mac/shaders.metal b/crates/gpui/src/platform/mac/shaders.metal index 6aa1d18ee895ec84a6f19edbcc6618cf713aa5a5..83c978b853443d5c612f514625f94b6d6725be8a 100644 --- a/crates/gpui/src/platform/mac/shaders.metal +++ b/crates/gpui/src/platform/mac/shaders.metal @@ -99,21 +99,8 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]], constant Quad *quads [[buffer(QuadInputIndex_Quads)]]) { Quad quad = quads[input.quad_id]; - - // Signed distance field threshold for inclusion of pixels. 0.5 is the - // minimum distance between the center of the pixel and the edge. - const float antialias_threshold = 0.5; - float4 background_color = fill_color(quad.background, input.position.xy, quad.bounds, input.background_solid, input.background_color0, input.background_color1); - float4 border_color = input.border_color; - - // Apply content_mask corner radii clipping - float clip_sdf = quad_sdf(input.position.xy, quad.content_mask.bounds, - quad.content_mask.corner_radii); - float clip_alpha = saturate(antialias_threshold - clip_sdf); - background_color.a *= clip_alpha; - border_color *= clip_alpha; bool unrounded = quad.corner_radii.top_left == 0.0 && quad.corner_radii.bottom_left == 0.0 && @@ -134,6 +121,10 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]], float2 point = input.position.xy - float2(quad.bounds.origin.x, quad.bounds.origin.y); float2 center_to_point = point - half_size; + // Signed distance field threshold for inclusion of pixels. 0.5 is the + // minimum distance between the center of the pixel and the edge. + const float antialias_threshold = 0.5; + // Radius of the nearest corner float corner_radius = pick_corner_radius(center_to_point, quad.corner_radii); @@ -173,6 +164,7 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]], straight_border_inner_corner_to_point.x > 0.0 || straight_border_inner_corner_to_point.y > 0.0; + // Whether the point is far enough inside the quad, such that the pixels are // not affected by the straight border. bool is_within_inner_straight_border = @@ -216,6 +208,8 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]], float4 color = background_color; if (border_sdf < antialias_threshold) { + float4 border_color = input.border_color; + // Dashed border logic when border_style == 1 if (quad.border_style == 1) { // Position along the perimeter in "dash space", where each dash @@ -250,10 +244,6 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]], // perimeter. This way each line starts and ends with a dash. bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y; float border_width = is_horizontal ? border.x : border.y; - // When border width of some side is 0, we need to use the other side width for dash velocity. - if (border_width == 0.0) { - border_width = is_horizontal ? border.y : border.x; - } dash_velocity = dv_numerator / border_width; t = is_horizontal ? point.x : point.y; t *= dash_velocity; diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index 296a6c825f8b057b5330d108c21c27ffb4fa1b75..2cef54ae6166e313795eb42210b5f07c1bc378fc 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -453,16 +453,11 @@ float quarter_ellipse_sdf(float2 pt, float2 radii) { ** */ -struct ContentMask { - Bounds bounds; - Corners corner_radii; -}; - struct Quad { uint order; uint border_style; Bounds bounds; - ContentMask content_mask; + Bounds content_mask; Background background; Hsla border_color; Corners corner_radii; @@ -501,7 +496,7 @@ QuadVertexOutput quad_vertex(uint vertex_id: SV_VertexID, uint quad_id: SV_Insta quad.background.solid, quad.background.colors ); - float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask.bounds); + float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask); float4 border_color = hsla_to_rgba(quad.border_color); QuadVertexOutput output; @@ -517,21 +512,8 @@ QuadVertexOutput quad_vertex(uint vertex_id: SV_VertexID, uint quad_id: SV_Insta float4 quad_fragment(QuadFragmentInput input): SV_Target { Quad quad = quads[input.quad_id]; - - // Signed distance field threshold for inclusion of pixels. 0.5 is the - // minimum distance between the center of the pixel and the edge. - const float antialias_threshold = 0.5; - float4 background_color = gradient_color(quad.background, input.position.xy, quad.bounds, - input.background_solid, input.background_color0, input.background_color1); - float4 border_color = input.border_color; - - // Apply content_mask corner radii clipping - float clip_sdf = quad_sdf(input.position.xy, quad.content_mask.bounds, - quad.content_mask.corner_radii); - float clip_alpha = saturate(antialias_threshold - clip_sdf); - background_color.a *= clip_alpha; - border_color *= clip_alpha; + input.background_solid, input.background_color0, input.background_color1); bool unrounded = quad.corner_radii.top_left == 0.0 && quad.corner_radii.top_right == 0.0 && @@ -552,6 +534,10 @@ float4 quad_fragment(QuadFragmentInput input): SV_Target { float2 the_point = input.position.xy - quad.bounds.origin; float2 center_to_point = the_point - half_size; + // Signed distance field threshold for inclusion of pixels. 0.5 is the + // minimum distance between the center of the pixel and the edge. + const float antialias_threshold = 0.5; + // Radius of the nearest corner float corner_radius = pick_corner_radius(center_to_point, quad.corner_radii); @@ -634,6 +620,7 @@ float4 quad_fragment(QuadFragmentInput input): SV_Target { float4 color = background_color; if (border_sdf < antialias_threshold) { + float4 border_color = input.border_color; // Dashed border logic when border_style == 1 if (quad.border_style == 1) { // Position along the perimeter in "dash space", where each dash @@ -668,10 +655,6 @@ float4 quad_fragment(QuadFragmentInput input): SV_Target { // perimeter. This way each line starts and ends with a dash. bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y; float border_width = is_horizontal ? border.x : border.y; - // When border width of some side is 0, we need to use the other side width for dash velocity. - if (border_width == 0.0) { - border_width = is_horizontal ? border.y : border.x; - } dash_velocity = dv_numerator / border_width; t = is_horizontal ? the_point.x : the_point.y; t *= dash_velocity; @@ -822,7 +805,7 @@ struct Shadow { float blur_radius; Bounds bounds; Corners corner_radii; - ContentMask content_mask; + Bounds content_mask; Hsla color; }; @@ -851,7 +834,7 @@ ShadowVertexOutput shadow_vertex(uint vertex_id: SV_VertexID, uint shadow_id: SV bounds.size += 2.0 * margin; float4 device_position = to_device_position(unit_vertex, bounds); - float4 clip_distance = distance_from_clip_rect(unit_vertex, bounds, shadow.content_mask.bounds); + float4 clip_distance = distance_from_clip_rect(unit_vertex, bounds, shadow.content_mask); float4 color = hsla_to_rgba(shadow.color); ShadowVertexOutput output; @@ -1004,7 +987,7 @@ struct Underline { uint order; uint pad; Bounds bounds; - ContentMask content_mask; + Bounds content_mask; Hsla color; float thickness; uint wavy; @@ -1030,7 +1013,7 @@ UnderlineVertexOutput underline_vertex(uint vertex_id: SV_VertexID, uint underli Underline underline = underlines[underline_id]; float4 device_position = to_device_position(unit_vertex, underline.bounds); float4 clip_distance = distance_from_clip_rect(unit_vertex, underline.bounds, - underline.content_mask.bounds); + underline.content_mask); float4 color = hsla_to_rgba(underline.color); UnderlineVertexOutput output; @@ -1078,7 +1061,7 @@ struct MonochromeSprite { uint order; uint pad; Bounds bounds; - ContentMask content_mask; + Bounds content_mask; Hsla color; AtlasTile tile; TransformationMatrix transformation; @@ -1105,7 +1088,7 @@ MonochromeSpriteVertexOutput monochrome_sprite_vertex(uint vertex_id: SV_VertexI MonochromeSprite sprite = mono_sprites[sprite_id]; float4 device_position = to_device_position_transformed(unit_vertex, sprite.bounds, sprite.transformation); - float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask.bounds); + float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask); float2 tile_position = to_tile_position(unit_vertex, sprite.tile); float4 color = hsla_to_rgba(sprite.color); @@ -1135,7 +1118,7 @@ struct PolychromeSprite { uint grayscale; float opacity; Bounds bounds; - ContentMask content_mask; + Bounds content_mask; Corners corner_radii; AtlasTile tile; }; @@ -1160,7 +1143,7 @@ PolychromeSpriteVertexOutput polychrome_sprite_vertex(uint vertex_id: SV_VertexI PolychromeSprite sprite = poly_sprites[sprite_id]; float4 device_position = to_device_position(unit_vertex, sprite.bounds); float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds, - sprite.content_mask.bounds); + sprite.content_mask); float2 tile_position = to_tile_position(unit_vertex, sprite.tile); PolychromeSpriteVertexOutput output; diff --git a/crates/gpui/src/style.rs b/crates/gpui/src/style.rs index 09f598f9b0deb4ddd9910e32e4dbe020b54c849a..5b69ce7fa6eb06affc2f77c0d1bdfbe4165c206a 100644 --- a/crates/gpui/src/style.rs +++ b/crates/gpui/src/style.rs @@ -601,19 +601,7 @@ impl Style { (false, false) => Bounds::from_corners(min, max), }; - let corner_radii = self.corner_radii.to_pixels(rem_size); - let border_widths = self.border_widths.to_pixels(rem_size); - Some(ContentMask { - bounds: Bounds { - origin: bounds.origin - point(border_widths.left, border_widths.top), - size: bounds.size - + size( - border_widths.left + border_widths.right, - border_widths.top + border_widths.bottom, - ), - }, - corner_radii, - }) + Some(ContentMask { bounds }) } } } @@ -673,16 +661,64 @@ impl Style { if self.is_border_visible() { let border_widths = self.border_widths.to_pixels(rem_size); + let max_border_width = border_widths.max(); + let max_corner_radius = corner_radii.max(); + + let top_bounds = Bounds::from_corners( + bounds.origin, + bounds.top_right() + point(Pixels::ZERO, max_border_width.max(max_corner_radius)), + ); + let bottom_bounds = Bounds::from_corners( + bounds.bottom_left() - point(Pixels::ZERO, max_border_width.max(max_corner_radius)), + bounds.bottom_right(), + ); + let left_bounds = Bounds::from_corners( + top_bounds.bottom_left(), + bottom_bounds.origin + point(max_border_width, Pixels::ZERO), + ); + let right_bounds = Bounds::from_corners( + top_bounds.bottom_right() - point(max_border_width, Pixels::ZERO), + bottom_bounds.top_right(), + ); + let mut background = self.border_color.unwrap_or_default(); background.a = 0.; - window.paint_quad(quad( + let quad = quad( bounds, corner_radii, background, border_widths, self.border_color.unwrap_or_default(), self.border_style, - )); + ); + + window.with_content_mask(Some(ContentMask { bounds: top_bounds }), |window| { + window.paint_quad(quad.clone()); + }); + window.with_content_mask( + Some(ContentMask { + bounds: right_bounds, + }), + |window| { + window.paint_quad(quad.clone()); + }, + ); + window.with_content_mask( + Some(ContentMask { + bounds: bottom_bounds, + }), + |window| { + window.paint_quad(quad.clone()); + }, + ); + window.with_content_mask( + Some(ContentMask { + bounds: left_bounds, + }), + |window| { + window.paint_quad(quad); + }, + ); } #[cfg(debug_assertions)] diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index cebf911b734798a3965857db0f3fd6fe2be2b011..0ec73c4b0040e6c65cd8819ecf5d20a9ec1900d0 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -1283,8 +1283,6 @@ pub(crate) struct DispatchEventResult { pub struct ContentMask { /// The bounds pub bounds: Bounds

, - /// The corner radii of the content mask. - pub corner_radii: Corners

, } impl ContentMask { @@ -1292,31 +1290,13 @@ impl ContentMask { pub fn scale(&self, factor: f32) -> ContentMask { ContentMask { bounds: self.bounds.scale(factor), - corner_radii: self.corner_radii.scale(factor), } } /// Intersect the content mask with the given content mask. pub fn intersect(&self, other: &Self) -> Self { let bounds = self.bounds.intersect(&other.bounds); - ContentMask { - bounds, - corner_radii: Corners { - top_left: self.corner_radii.top_left.max(other.corner_radii.top_left), - top_right: self - .corner_radii - .top_right - .max(other.corner_radii.top_right), - bottom_right: self - .corner_radii - .bottom_right - .max(other.corner_radii.bottom_right), - bottom_left: self - .corner_radii - .bottom_left - .max(other.corner_radii.bottom_left), - }, - } + ContentMask { bounds } } } @@ -2577,7 +2557,6 @@ impl Window { origin: Point::default(), size: self.viewport_size, }, - ..Default::default() }) } diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index e4d7f226912cdb6123081dd5cfb38f205d9a9333..5bbf5ad36b3de89514d92ce9e305988817cec32f 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -1184,7 +1184,7 @@ impl Element for TerminalElement { cx: &mut App, ) { let paint_start = Instant::now(); - window.with_content_mask(Some(ContentMask { bounds, ..Default::default() }), |window| { + window.with_content_mask(Some(ContentMask { bounds }), |window| { let scroll_top = self.terminal_view.read(cx).scroll_top; window.paint_quad(fill(bounds, layout.background_color)); diff --git a/crates/ui/src/components/scrollbar.rs b/crates/ui/src/components/scrollbar.rs index 475575a483ea4659b572f8f82e13faf8b539fb37..605028202fffa37d67bbdb4a9f33a97459390dfa 100644 --- a/crates/ui/src/components/scrollbar.rs +++ b/crates/ui/src/components/scrollbar.rs @@ -303,13 +303,9 @@ impl Element for Scrollbar { window: &mut Window, _: &mut App, ) -> Self::PrepaintState { - window.with_content_mask( - Some(ContentMask { - bounds, - ..Default::default() - }), - |window| window.insert_hitbox(bounds, HitboxBehavior::Normal), - ) + window.with_content_mask(Some(ContentMask { bounds }), |window| { + window.insert_hitbox(bounds, HitboxBehavior::Normal) + }) } fn paint( @@ -323,11 +319,7 @@ impl Element for Scrollbar { cx: &mut App, ) { const EXTRA_PADDING: Pixels = px(5.0); - let content_mask = ContentMask { - bounds, - ..Default::default() - }; - window.with_content_mask(Some(content_mask), |window| { + window.with_content_mask(Some(ContentMask { bounds }), |window| { let axis = self.kind; let colors = cx.theme().colors(); let thumb_state = self.state.thumb_state.get();