Detailed changes
@@ -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);
@@ -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<Self>) -> 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);
- });
-}
@@ -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<Pixels>,
padding: Edges<Pixels>,
- corner_radii: Corners<Pixels>,
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;
@@ -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
@@ -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<f32> {
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<f32> {
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<f32> {
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<f32> {
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<storage, read> b_shadows: array<Shadow>;
@@ -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<f32> {
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<f32> {
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)
- );
-}
@@ -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;
@@ -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;
@@ -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)]
@@ -1283,8 +1283,6 @@ pub(crate) struct DispatchEventResult {
pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
/// The bounds
pub bounds: Bounds<P>,
- /// The corner radii of the content mask.
- pub corner_radii: Corners<P>,
}
impl ContentMask<Pixels> {
@@ -1292,31 +1290,13 @@ impl ContentMask<Pixels> {
pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
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()
})
}
@@ -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));
@@ -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();