Merge bd22402d1b
into a102b08743
This commit is contained in:
commit
f9e95b86cf
11 changed files with 446 additions and 130 deletions
|
@ -5871,6 +5871,7 @@ impl EditorElement {
|
||||||
window.with_content_mask(
|
window.with_content_mask(
|
||||||
Some(ContentMask {
|
Some(ContentMask {
|
||||||
bounds: layout.position_map.text_hitbox.bounds,
|
bounds: layout.position_map.text_hitbox.bounds,
|
||||||
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
|window| {
|
|window| {
|
||||||
let editor = self.editor.read(cx);
|
let editor = self.editor.read(cx);
|
||||||
|
@ -6808,9 +6809,15 @@ impl EditorElement {
|
||||||
} else {
|
} else {
|
||||||
let mut bounds = layout.hitbox.bounds;
|
let mut bounds = layout.hitbox.bounds;
|
||||||
bounds.origin.x += layout.gutter_hitbox.bounds.size.width;
|
bounds.origin.x += layout.gutter_hitbox.bounds.size.width;
|
||||||
window.with_content_mask(Some(ContentMask { bounds }), |window| {
|
window.with_content_mask(
|
||||||
block.element.paint(window, cx);
|
Some(ContentMask {
|
||||||
})
|
bounds,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
|window| {
|
||||||
|
block.element.paint(window, cx);
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8022,9 +8029,13 @@ impl Element for EditorElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
let rem_size = self.rem_size(cx);
|
let rem_size = self.rem_size(cx);
|
||||||
|
let content_mask = ContentMask {
|
||||||
|
bounds,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
window.with_rem_size(rem_size, |window| {
|
window.with_rem_size(rem_size, |window| {
|
||||||
window.with_text_style(Some(text_style), |window| {
|
window.with_text_style(Some(text_style), |window| {
|
||||||
window.with_content_mask(Some(ContentMask { bounds }), |window| {
|
window.with_content_mask(Some(content_mask), |window| {
|
||||||
let (mut snapshot, is_read_only) = self.editor.update(cx, |editor, cx| {
|
let (mut snapshot, is_read_only) = self.editor.update(cx, |editor, cx| {
|
||||||
(editor.snapshot(window, cx), editor.read_only(cx))
|
(editor.snapshot(window, cx), editor.read_only(cx))
|
||||||
});
|
});
|
||||||
|
@ -9124,9 +9135,13 @@ impl Element for EditorElement {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let rem_size = self.rem_size(cx);
|
let rem_size = self.rem_size(cx);
|
||||||
|
let content_mask = ContentMask {
|
||||||
|
bounds,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
window.with_rem_size(rem_size, |window| {
|
window.with_rem_size(rem_size, |window| {
|
||||||
window.with_text_style(Some(text_style), |window| {
|
window.with_text_style(Some(text_style), |window| {
|
||||||
window.with_content_mask(Some(ContentMask { bounds }), |window| {
|
window.with_content_mask(Some(content_mask), |window| {
|
||||||
self.paint_mouse_listeners(layout, window, cx);
|
self.paint_mouse_listeners(layout, window, cx);
|
||||||
self.paint_background(layout, window, cx);
|
self.paint_background(layout, window, cx);
|
||||||
self.paint_indent_guides(layout, window, cx);
|
self.paint_indent_guides(layout, window, cx);
|
||||||
|
|
228
crates/gpui/examples/content_mask.rs
Normal file
228
crates/gpui/examples/content_mask.rs
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
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 [`UniformList`] for a simpler API
|
//! If all of your elements are the same height, see [`UniformList`] for a simpler API
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, App, AvailableSpace, Bounds, ContentMask, DispatchPhase, Edges, Element, EntityId,
|
AnyElement, App, AvailableSpace, Bounds, ContentMask, Corners, DispatchPhase, Edges, Element,
|
||||||
FocusHandle, GlobalElementId, Hitbox, HitboxBehavior, InspectorElementId, IntoElement,
|
EntityId, FocusHandle, GlobalElementId, Hitbox, HitboxBehavior, InspectorElementId,
|
||||||
Overflow, Pixels, Point, ScrollDelta, ScrollWheelEvent, Size, Style, StyleRefinement, Styled,
|
IntoElement, Overflow, Pixels, Point, ScrollDelta, ScrollWheelEvent, Size, Style,
|
||||||
Window, point, px, size,
|
StyleRefinement, Styled, Window, point, px, size,
|
||||||
};
|
};
|
||||||
use collections::VecDeque;
|
use collections::VecDeque;
|
||||||
use refineable::Refineable as _;
|
use refineable::Refineable as _;
|
||||||
|
@ -705,6 +705,7 @@ impl StateInner {
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
padding: Edges<Pixels>,
|
padding: Edges<Pixels>,
|
||||||
|
corner_radii: Corners<Pixels>,
|
||||||
autoscroll: bool,
|
autoscroll: bool,
|
||||||
render_item: &mut RenderItemFn,
|
render_item: &mut RenderItemFn,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
|
@ -728,9 +729,15 @@ impl StateInner {
|
||||||
let mut item_origin = bounds.origin + Point::new(px(0.), padding.top);
|
let mut item_origin = bounds.origin + Point::new(px(0.), padding.top);
|
||||||
item_origin.y -= layout_response.scroll_top.offset_in_item;
|
item_origin.y -= layout_response.scroll_top.offset_in_item;
|
||||||
for item in &mut layout_response.item_layouts {
|
for item in &mut layout_response.item_layouts {
|
||||||
window.with_content_mask(Some(ContentMask { bounds }), |window| {
|
window.with_content_mask(
|
||||||
item.element.prepaint_at(item_origin, window, cx);
|
Some(ContentMask {
|
||||||
});
|
bounds,
|
||||||
|
corner_radii,
|
||||||
|
}),
|
||||||
|
|window| {
|
||||||
|
item.element.prepaint_at(item_origin, window, cx);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(autoscroll_bounds) = window.take_autoscroll()
|
if let Some(autoscroll_bounds) = window.take_autoscroll()
|
||||||
&& autoscroll
|
&& autoscroll
|
||||||
|
@ -952,19 +959,34 @@ impl Element for List {
|
||||||
state.items = new_items;
|
state.items = new_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
let padding = style
|
let rem_size = window.rem_size();
|
||||||
.padding
|
let padding = style.padding.to_pixels(bounds.size.into(), rem_size);
|
||||||
.to_pixels(bounds.size.into(), window.rem_size());
|
let corner_radii = style.corner_radii.to_pixels(rem_size);
|
||||||
let layout =
|
let layout = match state.prepaint_items(
|
||||||
match state.prepaint_items(bounds, padding, true, &mut self.render_item, window, cx) {
|
bounds,
|
||||||
Ok(layout) => layout,
|
padding,
|
||||||
Err(autoscroll_request) => {
|
corner_radii,
|
||||||
state.logical_scroll_top = Some(autoscroll_request);
|
true,
|
||||||
state
|
&mut self.render_item,
|
||||||
.prepaint_items(bounds, padding, false, &mut self.render_item, window, cx)
|
window,
|
||||||
.unwrap()
|
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()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
state.last_layout_bounds = Some(bounds);
|
state.last_layout_bounds = Some(bounds);
|
||||||
state.last_padding = Some(padding);
|
state.last_padding = Some(padding);
|
||||||
|
@ -982,11 +1004,17 @@ impl Element for List {
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) {
|
) {
|
||||||
let current_view = window.current_view();
|
let current_view = window.current_view();
|
||||||
window.with_content_mask(Some(ContentMask { bounds }), |window| {
|
window.with_content_mask(
|
||||||
for item in &mut prepaint.layout.item_layouts {
|
Some(ContentMask {
|
||||||
item.element.paint(window, cx);
|
bounds,
|
||||||
}
|
..Default::default()
|
||||||
});
|
}),
|
||||||
|
|window| {
|
||||||
|
for item in &mut prepaint.layout.item_layouts {
|
||||||
|
item.element.paint(window, cx);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let list_state = self.state.clone();
|
let list_state = self.state.clone();
|
||||||
let height = bounds.size.height;
|
let height = bounds.size.height;
|
||||||
|
|
|
@ -411,7 +411,10 @@ impl Element for UniformList {
|
||||||
(self.render_items)(visible_range.clone(), window, cx)
|
(self.render_items)(visible_range.clone(), window, cx)
|
||||||
};
|
};
|
||||||
|
|
||||||
let content_mask = ContentMask { bounds };
|
let content_mask = ContentMask {
|
||||||
|
bounds,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
window.with_content_mask(Some(content_mask), |window| {
|
window.with_content_mask(Some(content_mask), |window| {
|
||||||
for (mut item, ix) in items.into_iter().zip(visible_range.clone()) {
|
for (mut item, ix) in items.into_iter().zip(visible_range.clone()) {
|
||||||
let item_origin = padded_bounds.origin
|
let item_origin = padded_bounds.origin
|
||||||
|
|
|
@ -53,6 +53,11 @@ struct Corners {
|
||||||
bottom_left: f32,
|
bottom_left: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ContentMask {
|
||||||
|
bounds: Bounds,
|
||||||
|
corner_radii: Corners,
|
||||||
|
}
|
||||||
|
|
||||||
struct Edges {
|
struct Edges {
|
||||||
top: f32,
|
top: f32,
|
||||||
right: f32,
|
right: f32,
|
||||||
|
@ -440,7 +445,7 @@ struct Quad {
|
||||||
order: u32,
|
order: u32,
|
||||||
border_style: u32,
|
border_style: u32,
|
||||||
bounds: Bounds,
|
bounds: Bounds,
|
||||||
content_mask: Bounds,
|
content_mask: ContentMask,
|
||||||
background: Background,
|
background: Background,
|
||||||
border_color: Hsla,
|
border_color: Hsla,
|
||||||
corner_radii: Corners,
|
corner_radii: Corners,
|
||||||
|
@ -478,7 +483,7 @@ fn vs_quad(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index) insta
|
||||||
out.background_color1 = gradient.color1;
|
out.background_color1 = gradient.color1;
|
||||||
out.border_color = hsla_to_rgba(quad.border_color);
|
out.border_color = hsla_to_rgba(quad.border_color);
|
||||||
out.quad_id = instance_id;
|
out.quad_id = instance_id;
|
||||||
out.clip_distances = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask);
|
out.clip_distances = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask.bounds);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,8 +496,19 @@ fn fs_quad(input: QuadVarying) -> @location(0) vec4<f32> {
|
||||||
|
|
||||||
let quad = b_quads[input.quad_id];
|
let quad = b_quads[input.quad_id];
|
||||||
|
|
||||||
let background_color = gradient_color(quad.background, input.position.xy, quad.bounds,
|
// 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,
|
||||||
input.background_solid, input.background_color0, input.background_color1);
|
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 &&
|
let unrounded = quad.corner_radii.top_left == 0.0 &&
|
||||||
quad.corner_radii.bottom_left == 0.0 &&
|
quad.corner_radii.bottom_left == 0.0 &&
|
||||||
|
@ -513,10 +529,6 @@ fn fs_quad(input: QuadVarying) -> @location(0) vec4<f32> {
|
||||||
let point = input.position.xy - quad.bounds.origin;
|
let point = input.position.xy - quad.bounds.origin;
|
||||||
let center_to_point = point - half_size;
|
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
|
// Radius of the nearest corner
|
||||||
let corner_radius = pick_corner_radius(center_to_point, quad.corner_radii);
|
let corner_radius = pick_corner_radius(center_to_point, quad.corner_radii);
|
||||||
|
|
||||||
|
@ -607,8 +619,6 @@ fn fs_quad(input: QuadVarying) -> @location(0) vec4<f32> {
|
||||||
|
|
||||||
var color = background_color;
|
var color = background_color;
|
||||||
if (border_sdf < antialias_threshold) {
|
if (border_sdf < antialias_threshold) {
|
||||||
var border_color = input.border_color;
|
|
||||||
|
|
||||||
// Dashed border logic when border_style == 1
|
// Dashed border logic when border_style == 1
|
||||||
if (quad.border_style == 1) {
|
if (quad.border_style == 1) {
|
||||||
// Position along the perimeter in "dash space", where each dash
|
// Position along the perimeter in "dash space", where each dash
|
||||||
|
@ -644,7 +654,11 @@ fn fs_quad(input: QuadVarying) -> @location(0) vec4<f32> {
|
||||||
let is_horizontal =
|
let is_horizontal =
|
||||||
corner_center_to_point.x <
|
corner_center_to_point.x <
|
||||||
corner_center_to_point.y;
|
corner_center_to_point.y;
|
||||||
let border_width = select(border.y, border.x, is_horizontal);
|
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);
|
||||||
|
}
|
||||||
dash_velocity = dv_numerator / border_width;
|
dash_velocity = dv_numerator / border_width;
|
||||||
t = select(point.y, point.x, is_horizontal) * dash_velocity;
|
t = select(point.y, point.x, is_horizontal) * dash_velocity;
|
||||||
max_t = select(size.y, size.x, is_horizontal) * dash_velocity;
|
max_t = select(size.y, size.x, is_horizontal) * dash_velocity;
|
||||||
|
@ -856,7 +870,7 @@ struct Shadow {
|
||||||
blur_radius: f32,
|
blur_radius: f32,
|
||||||
bounds: Bounds,
|
bounds: Bounds,
|
||||||
corner_radii: Corners,
|
corner_radii: Corners,
|
||||||
content_mask: Bounds,
|
content_mask: ContentMask,
|
||||||
color: Hsla,
|
color: Hsla,
|
||||||
}
|
}
|
||||||
var<storage, read> b_shadows: array<Shadow>;
|
var<storage, read> b_shadows: array<Shadow>;
|
||||||
|
@ -884,7 +898,7 @@ fn vs_shadow(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index) ins
|
||||||
out.position = to_device_position(unit_vertex, shadow.bounds);
|
out.position = to_device_position(unit_vertex, shadow.bounds);
|
||||||
out.color = hsla_to_rgba(shadow.color);
|
out.color = hsla_to_rgba(shadow.color);
|
||||||
out.shadow_id = instance_id;
|
out.shadow_id = instance_id;
|
||||||
out.clip_distances = distance_from_clip_rect(unit_vertex, shadow.bounds, shadow.content_mask);
|
out.clip_distances = distance_from_clip_rect(unit_vertex, shadow.bounds, shadow.content_mask.bounds);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,7 +913,6 @@ fn fs_shadow(input: ShadowVarying) -> @location(0) vec4<f32> {
|
||||||
let half_size = shadow.bounds.size / 2.0;
|
let half_size = shadow.bounds.size / 2.0;
|
||||||
let center = shadow.bounds.origin + half_size;
|
let center = shadow.bounds.origin + half_size;
|
||||||
let center_to_point = input.position.xy - center;
|
let center_to_point = input.position.xy - center;
|
||||||
|
|
||||||
let corner_radius = pick_corner_radius(center_to_point, shadow.corner_radii);
|
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
|
// The signal is only non-zero in a limited range, so don't waste samples
|
||||||
|
@ -1027,7 +1040,7 @@ struct Underline {
|
||||||
order: u32,
|
order: u32,
|
||||||
pad: u32,
|
pad: u32,
|
||||||
bounds: Bounds,
|
bounds: Bounds,
|
||||||
content_mask: Bounds,
|
content_mask: ContentMask,
|
||||||
color: Hsla,
|
color: Hsla,
|
||||||
thickness: f32,
|
thickness: f32,
|
||||||
wavy: u32,
|
wavy: u32,
|
||||||
|
@ -1051,7 +1064,7 @@ fn vs_underline(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index)
|
||||||
out.position = to_device_position(unit_vertex, underline.bounds);
|
out.position = to_device_position(unit_vertex, underline.bounds);
|
||||||
out.color = hsla_to_rgba(underline.color);
|
out.color = hsla_to_rgba(underline.color);
|
||||||
out.underline_id = instance_id;
|
out.underline_id = instance_id;
|
||||||
out.clip_distances = distance_from_clip_rect(unit_vertex, underline.bounds, underline.content_mask);
|
out.clip_distances = distance_from_clip_rect(unit_vertex, underline.bounds, underline.content_mask.bounds);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1093,7 +1106,7 @@ struct MonochromeSprite {
|
||||||
order: u32,
|
order: u32,
|
||||||
pad: u32,
|
pad: u32,
|
||||||
bounds: Bounds,
|
bounds: Bounds,
|
||||||
content_mask: Bounds,
|
content_mask: ContentMask,
|
||||||
color: Hsla,
|
color: Hsla,
|
||||||
tile: AtlasTile,
|
tile: AtlasTile,
|
||||||
transformation: TransformationMatrix,
|
transformation: TransformationMatrix,
|
||||||
|
@ -1117,7 +1130,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.tile_position = to_tile_position(unit_vertex, sprite.tile);
|
||||||
out.color = hsla_to_rgba(sprite.color);
|
out.color = hsla_to_rgba(sprite.color);
|
||||||
out.clip_distances = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask);
|
out.clip_distances = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask.bounds);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1139,7 +1152,7 @@ struct PolychromeSprite {
|
||||||
grayscale: u32,
|
grayscale: u32,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
bounds: Bounds,
|
bounds: Bounds,
|
||||||
content_mask: Bounds,
|
content_mask: ContentMask,
|
||||||
corner_radii: Corners,
|
corner_radii: Corners,
|
||||||
tile: AtlasTile,
|
tile: AtlasTile,
|
||||||
}
|
}
|
||||||
|
@ -1161,7 +1174,7 @@ fn vs_poly_sprite(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index
|
||||||
out.position = to_device_position(unit_vertex, sprite.bounds);
|
out.position = to_device_position(unit_vertex, sprite.bounds);
|
||||||
out.tile_position = to_tile_position(unit_vertex, sprite.tile);
|
out.tile_position = to_tile_position(unit_vertex, sprite.tile);
|
||||||
out.sprite_id = instance_id;
|
out.sprite_id = instance_id;
|
||||||
out.clip_distances = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask);
|
out.clip_distances = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask.bounds);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1234,3 +1247,12 @@ fn fs_surface(input: SurfaceVarying) -> @location(0) vec4<f32> {
|
||||||
|
|
||||||
return ycbcr_to_RGB * y_cb_cr;
|
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,8 +99,21 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]],
|
||||||
constant Quad *quads
|
constant Quad *quads
|
||||||
[[buffer(QuadInputIndex_Quads)]]) {
|
[[buffer(QuadInputIndex_Quads)]]) {
|
||||||
Quad quad = quads[input.quad_id];
|
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,
|
float4 background_color = fill_color(quad.background, input.position.xy, quad.bounds,
|
||||||
input.background_solid, input.background_color0, input.background_color1);
|
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 &&
|
bool unrounded = quad.corner_radii.top_left == 0.0 &&
|
||||||
quad.corner_radii.bottom_left == 0.0 &&
|
quad.corner_radii.bottom_left == 0.0 &&
|
||||||
|
@ -121,10 +134,6 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]],
|
||||||
float2 point = input.position.xy - float2(quad.bounds.origin.x, quad.bounds.origin.y);
|
float2 point = input.position.xy - float2(quad.bounds.origin.x, quad.bounds.origin.y);
|
||||||
float2 center_to_point = point - half_size;
|
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
|
// Radius of the nearest corner
|
||||||
float corner_radius = pick_corner_radius(center_to_point, quad.corner_radii);
|
float corner_radius = pick_corner_radius(center_to_point, quad.corner_radii);
|
||||||
|
|
||||||
|
@ -164,7 +173,6 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]],
|
||||||
straight_border_inner_corner_to_point.x > 0.0 ||
|
straight_border_inner_corner_to_point.x > 0.0 ||
|
||||||
straight_border_inner_corner_to_point.y > 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
|
// Whether the point is far enough inside the quad, such that the pixels are
|
||||||
// not affected by the straight border.
|
// not affected by the straight border.
|
||||||
bool is_within_inner_straight_border =
|
bool is_within_inner_straight_border =
|
||||||
|
@ -208,8 +216,6 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]],
|
||||||
|
|
||||||
float4 color = background_color;
|
float4 color = background_color;
|
||||||
if (border_sdf < antialias_threshold) {
|
if (border_sdf < antialias_threshold) {
|
||||||
float4 border_color = input.border_color;
|
|
||||||
|
|
||||||
// Dashed border logic when border_style == 1
|
// Dashed border logic when border_style == 1
|
||||||
if (quad.border_style == 1) {
|
if (quad.border_style == 1) {
|
||||||
// Position along the perimeter in "dash space", where each dash
|
// Position along the perimeter in "dash space", where each dash
|
||||||
|
@ -244,6 +250,10 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]],
|
||||||
// perimeter. This way each line starts and ends with a dash.
|
// perimeter. This way each line starts and ends with a dash.
|
||||||
bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y;
|
bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y;
|
||||||
float border_width = is_horizontal ? border.x : border.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;
|
dash_velocity = dv_numerator / border_width;
|
||||||
t = is_horizontal ? point.x : point.y;
|
t = is_horizontal ? point.x : point.y;
|
||||||
t *= dash_velocity;
|
t *= dash_velocity;
|
||||||
|
|
|
@ -449,11 +449,16 @@ float quarter_ellipse_sdf(float2 pt, float2 radii) {
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct ContentMask {
|
||||||
|
Bounds bounds;
|
||||||
|
Corners corner_radii;
|
||||||
|
};
|
||||||
|
|
||||||
struct Quad {
|
struct Quad {
|
||||||
uint order;
|
uint order;
|
||||||
uint border_style;
|
uint border_style;
|
||||||
Bounds bounds;
|
Bounds bounds;
|
||||||
Bounds content_mask;
|
ContentMask content_mask;
|
||||||
Background background;
|
Background background;
|
||||||
Hsla border_color;
|
Hsla border_color;
|
||||||
Corners corner_radii;
|
Corners corner_radii;
|
||||||
|
@ -492,7 +497,7 @@ QuadVertexOutput quad_vertex(uint vertex_id: SV_VertexID, uint quad_id: SV_Insta
|
||||||
quad.background.solid,
|
quad.background.solid,
|
||||||
quad.background.colors
|
quad.background.colors
|
||||||
);
|
);
|
||||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask);
|
float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask.bounds);
|
||||||
float4 border_color = hsla_to_rgba(quad.border_color);
|
float4 border_color = hsla_to_rgba(quad.border_color);
|
||||||
|
|
||||||
QuadVertexOutput output;
|
QuadVertexOutput output;
|
||||||
|
@ -508,8 +513,21 @@ QuadVertexOutput quad_vertex(uint vertex_id: SV_VertexID, uint quad_id: SV_Insta
|
||||||
|
|
||||||
float4 quad_fragment(QuadFragmentInput input): SV_Target {
|
float4 quad_fragment(QuadFragmentInput input): SV_Target {
|
||||||
Quad quad = quads[input.quad_id];
|
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,
|
float4 background_color = gradient_color(quad.background, input.position.xy, quad.bounds,
|
||||||
input.background_solid, input.background_color0, input.background_color1);
|
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 &&
|
bool unrounded = quad.corner_radii.top_left == 0.0 &&
|
||||||
quad.corner_radii.top_right == 0.0 &&
|
quad.corner_radii.top_right == 0.0 &&
|
||||||
|
@ -530,10 +548,6 @@ float4 quad_fragment(QuadFragmentInput input): SV_Target {
|
||||||
float2 the_point = input.position.xy - quad.bounds.origin;
|
float2 the_point = input.position.xy - quad.bounds.origin;
|
||||||
float2 center_to_point = the_point - half_size;
|
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
|
// Radius of the nearest corner
|
||||||
float corner_radius = pick_corner_radius(center_to_point, quad.corner_radii);
|
float corner_radius = pick_corner_radius(center_to_point, quad.corner_radii);
|
||||||
|
|
||||||
|
@ -616,7 +630,6 @@ float4 quad_fragment(QuadFragmentInput input): SV_Target {
|
||||||
|
|
||||||
float4 color = background_color;
|
float4 color = background_color;
|
||||||
if (border_sdf < antialias_threshold) {
|
if (border_sdf < antialias_threshold) {
|
||||||
float4 border_color = input.border_color;
|
|
||||||
// Dashed border logic when border_style == 1
|
// Dashed border logic when border_style == 1
|
||||||
if (quad.border_style == 1) {
|
if (quad.border_style == 1) {
|
||||||
// Position along the perimeter in "dash space", where each dash
|
// Position along the perimeter in "dash space", where each dash
|
||||||
|
@ -651,6 +664,10 @@ float4 quad_fragment(QuadFragmentInput input): SV_Target {
|
||||||
// perimeter. This way each line starts and ends with a dash.
|
// perimeter. This way each line starts and ends with a dash.
|
||||||
bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y;
|
bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y;
|
||||||
float border_width = is_horizontal ? border.x : border.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;
|
dash_velocity = dv_numerator / border_width;
|
||||||
t = is_horizontal ? the_point.x : the_point.y;
|
t = is_horizontal ? the_point.x : the_point.y;
|
||||||
t *= dash_velocity;
|
t *= dash_velocity;
|
||||||
|
@ -801,7 +818,7 @@ struct Shadow {
|
||||||
float blur_radius;
|
float blur_radius;
|
||||||
Bounds bounds;
|
Bounds bounds;
|
||||||
Corners corner_radii;
|
Corners corner_radii;
|
||||||
Bounds content_mask;
|
ContentMask content_mask;
|
||||||
Hsla color;
|
Hsla color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -830,7 +847,7 @@ ShadowVertexOutput shadow_vertex(uint vertex_id: SV_VertexID, uint shadow_id: SV
|
||||||
bounds.size += 2.0 * margin;
|
bounds.size += 2.0 * margin;
|
||||||
|
|
||||||
float4 device_position = to_device_position(unit_vertex, bounds);
|
float4 device_position = to_device_position(unit_vertex, bounds);
|
||||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, bounds, shadow.content_mask);
|
float4 clip_distance = distance_from_clip_rect(unit_vertex, bounds, shadow.content_mask.bounds);
|
||||||
float4 color = hsla_to_rgba(shadow.color);
|
float4 color = hsla_to_rgba(shadow.color);
|
||||||
|
|
||||||
ShadowVertexOutput output;
|
ShadowVertexOutput output;
|
||||||
|
@ -983,7 +1000,7 @@ struct Underline {
|
||||||
uint order;
|
uint order;
|
||||||
uint pad;
|
uint pad;
|
||||||
Bounds bounds;
|
Bounds bounds;
|
||||||
Bounds content_mask;
|
ContentMask content_mask;
|
||||||
Hsla color;
|
Hsla color;
|
||||||
float thickness;
|
float thickness;
|
||||||
uint wavy;
|
uint wavy;
|
||||||
|
@ -1009,7 +1026,7 @@ UnderlineVertexOutput underline_vertex(uint vertex_id: SV_VertexID, uint underli
|
||||||
Underline underline = underlines[underline_id];
|
Underline underline = underlines[underline_id];
|
||||||
float4 device_position = to_device_position(unit_vertex, underline.bounds);
|
float4 device_position = to_device_position(unit_vertex, underline.bounds);
|
||||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, underline.bounds,
|
float4 clip_distance = distance_from_clip_rect(unit_vertex, underline.bounds,
|
||||||
underline.content_mask);
|
underline.content_mask.bounds);
|
||||||
float4 color = hsla_to_rgba(underline.color);
|
float4 color = hsla_to_rgba(underline.color);
|
||||||
|
|
||||||
UnderlineVertexOutput output;
|
UnderlineVertexOutput output;
|
||||||
|
@ -1057,7 +1074,7 @@ struct MonochromeSprite {
|
||||||
uint order;
|
uint order;
|
||||||
uint pad;
|
uint pad;
|
||||||
Bounds bounds;
|
Bounds bounds;
|
||||||
Bounds content_mask;
|
ContentMask content_mask;
|
||||||
Hsla color;
|
Hsla color;
|
||||||
AtlasTile tile;
|
AtlasTile tile;
|
||||||
TransformationMatrix transformation;
|
TransformationMatrix transformation;
|
||||||
|
@ -1084,7 +1101,7 @@ MonochromeSpriteVertexOutput monochrome_sprite_vertex(uint vertex_id: SV_VertexI
|
||||||
MonochromeSprite sprite = mono_sprites[sprite_id];
|
MonochromeSprite sprite = mono_sprites[sprite_id];
|
||||||
float4 device_position =
|
float4 device_position =
|
||||||
to_device_position_transformed(unit_vertex, sprite.bounds, sprite.transformation);
|
to_device_position_transformed(unit_vertex, sprite.bounds, sprite.transformation);
|
||||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask);
|
float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds, sprite.content_mask.bounds);
|
||||||
float2 tile_position = to_tile_position(unit_vertex, sprite.tile);
|
float2 tile_position = to_tile_position(unit_vertex, sprite.tile);
|
||||||
float4 color = hsla_to_rgba(sprite.color);
|
float4 color = hsla_to_rgba(sprite.color);
|
||||||
|
|
||||||
|
@ -1113,7 +1130,7 @@ struct PolychromeSprite {
|
||||||
uint grayscale;
|
uint grayscale;
|
||||||
float opacity;
|
float opacity;
|
||||||
Bounds bounds;
|
Bounds bounds;
|
||||||
Bounds content_mask;
|
ContentMask content_mask;
|
||||||
Corners corner_radii;
|
Corners corner_radii;
|
||||||
AtlasTile tile;
|
AtlasTile tile;
|
||||||
};
|
};
|
||||||
|
@ -1138,7 +1155,7 @@ PolychromeSpriteVertexOutput polychrome_sprite_vertex(uint vertex_id: SV_VertexI
|
||||||
PolychromeSprite sprite = poly_sprites[sprite_id];
|
PolychromeSprite sprite = poly_sprites[sprite_id];
|
||||||
float4 device_position = to_device_position(unit_vertex, sprite.bounds);
|
float4 device_position = to_device_position(unit_vertex, sprite.bounds);
|
||||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds,
|
float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds,
|
||||||
sprite.content_mask);
|
sprite.content_mask.bounds);
|
||||||
float2 tile_position = to_tile_position(unit_vertex, sprite.tile);
|
float2 tile_position = to_tile_position(unit_vertex, sprite.tile);
|
||||||
|
|
||||||
PolychromeSpriteVertexOutput output;
|
PolychromeSpriteVertexOutput output;
|
||||||
|
|
|
@ -601,7 +601,19 @@ impl Style {
|
||||||
(false, false) => Bounds::from_corners(min, max),
|
(false, false) => Bounds::from_corners(min, max),
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(ContentMask { bounds })
|
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,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -661,64 +673,16 @@ impl Style {
|
||||||
|
|
||||||
if self.is_border_visible() {
|
if self.is_border_visible() {
|
||||||
let border_widths = self.border_widths.to_pixels(rem_size);
|
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();
|
let mut background = self.border_color.unwrap_or_default();
|
||||||
background.a = 0.;
|
background.a = 0.;
|
||||||
let quad = quad(
|
window.paint_quad(quad(
|
||||||
bounds,
|
bounds,
|
||||||
corner_radii,
|
corner_radii,
|
||||||
background,
|
background,
|
||||||
border_widths,
|
border_widths,
|
||||||
self.border_color.unwrap_or_default(),
|
self.border_color.unwrap_or_default(),
|
||||||
self.border_style,
|
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)]
|
#[cfg(debug_assertions)]
|
||||||
|
|
|
@ -1209,6 +1209,8 @@ pub(crate) struct DispatchEventResult {
|
||||||
pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
|
pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
|
||||||
/// The bounds
|
/// The bounds
|
||||||
pub bounds: Bounds<P>,
|
pub bounds: Bounds<P>,
|
||||||
|
/// The corner radii of the content mask.
|
||||||
|
pub corner_radii: Corners<P>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContentMask<Pixels> {
|
impl ContentMask<Pixels> {
|
||||||
|
@ -1216,13 +1218,31 @@ impl ContentMask<Pixels> {
|
||||||
pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
|
pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
|
||||||
ContentMask {
|
ContentMask {
|
||||||
bounds: self.bounds.scale(factor),
|
bounds: self.bounds.scale(factor),
|
||||||
|
corner_radii: self.corner_radii.scale(factor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Intersect the content mask with the given content mask.
|
/// Intersect the content mask with the given content mask.
|
||||||
pub fn intersect(&self, other: &Self) -> Self {
|
pub fn intersect(&self, other: &Self) -> Self {
|
||||||
let bounds = self.bounds.intersect(&other.bounds);
|
let bounds = self.bounds.intersect(&other.bounds);
|
||||||
ContentMask { 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),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2483,6 +2503,7 @@ impl Window {
|
||||||
origin: Point::default(),
|
origin: Point::default(),
|
||||||
size: self.viewport_size,
|
size: self.viewport_size,
|
||||||
},
|
},
|
||||||
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1184,7 +1184,7 @@ impl Element for TerminalElement {
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) {
|
) {
|
||||||
let paint_start = Instant::now();
|
let paint_start = Instant::now();
|
||||||
window.with_content_mask(Some(ContentMask { bounds }), |window| {
|
window.with_content_mask(Some(ContentMask { bounds, ..Default::default() }), |window| {
|
||||||
let scroll_top = self.terminal_view.read(cx).scroll_top;
|
let scroll_top = self.terminal_view.read(cx).scroll_top;
|
||||||
|
|
||||||
window.paint_quad(fill(bounds, layout.background_color));
|
window.paint_quad(fill(bounds, layout.background_color));
|
||||||
|
|
|
@ -303,9 +303,13 @@ impl Element for Scrollbar {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
_: &mut App,
|
_: &mut App,
|
||||||
) -> Self::PrepaintState {
|
) -> Self::PrepaintState {
|
||||||
window.with_content_mask(Some(ContentMask { bounds }), |window| {
|
window.with_content_mask(
|
||||||
window.insert_hitbox(bounds, HitboxBehavior::Normal)
|
Some(ContentMask {
|
||||||
})
|
bounds,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
|window| window.insert_hitbox(bounds, HitboxBehavior::Normal),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
|
@ -319,7 +323,11 @@ impl Element for Scrollbar {
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) {
|
) {
|
||||||
const EXTRA_PADDING: Pixels = px(5.0);
|
const EXTRA_PADDING: Pixels = px(5.0);
|
||||||
window.with_content_mask(Some(ContentMask { bounds }), |window| {
|
let content_mask = ContentMask {
|
||||||
|
bounds,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
window.with_content_mask(Some(content_mask), |window| {
|
||||||
let axis = self.kind;
|
let axis = self.kind;
|
||||||
let colors = cx.theme().colors();
|
let colors = cx.theme().colors();
|
||||||
let thumb_state = self.state.thumb_state.get();
|
let thumb_state = self.state.thumb_state.get();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue