diff --git a/crates/gpui3/src/elements/text.rs b/crates/gpui3/src/elements/text.rs index b05a3c6fae9b76fd51a43f3c31a59b275e88384a..8044e1ab9ee3c0ffd03846fc0549a2c7d3878e62 100644 --- a/crates/gpui3/src/elements/text.rs +++ b/crates/gpui3/src/elements/text.rs @@ -3,7 +3,7 @@ use crate::{ }; use parking_lot::Mutex; use std::{marker::PhantomData, sync::Arc}; -use util::{arc_cow::ArcCow, ResultExt}; +use util::arc_cow::ArcCow; impl IntoAnyElement for ArcCow<'static, str> { fn into_any(self) -> AnyElement { @@ -92,8 +92,6 @@ impl Element for Text { paint_state: &mut Self::FrameState, cx: &mut ViewContext, ) -> Result<()> { - let bounds = layout.bounds; - let line; let line_height; { @@ -108,8 +106,8 @@ impl Element for Text { let _text_style = cx.text_style(); // todo!("We haven't added visible bounds to the new element system yet, so this is a placeholder."); - let visible_bounds = bounds; - line.paint(bounds.origin, visible_bounds, line_height, cx)?; + let visible_bounds = layout.bounds; + line.paint(&layout, visible_bounds, line_height, cx)?; Ok(()) } diff --git a/crates/gpui3/src/geometry.rs b/crates/gpui3/src/geometry.rs index 4f187f3252a02d39e12ae752b883d7a67f3addf2..ec5788be25aef116cca6f75c89ab0d156e107d95 100644 --- a/crates/gpui3/src/geometry.rs +++ b/crates/gpui3/src/geometry.rs @@ -425,7 +425,9 @@ unsafe impl Zeroable for Corners {} unsafe impl Pod for Corners {} -#[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)] +#[derive( + Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd, Zeroable, Pod, +)] #[repr(transparent)] pub struct Pixels(pub(crate) f32); @@ -445,6 +447,12 @@ impl Mul for f32 { } } +impl MulAssign for Pixels { + fn mul_assign(&mut self, other: f32) { + self.0 *= other; + } +} + impl Pixels { pub fn round(&self) -> Self { Self(self.0.round()) @@ -489,9 +497,6 @@ impl From for Pixels { } } -unsafe impl bytemuck::Pod for Pixels {} -unsafe impl bytemuck::Zeroable for Pixels {} - impl Debug for Pixels { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{} px", self.0) diff --git a/crates/gpui3/src/platform/mac/shaders.metal b/crates/gpui3/src/platform/mac/shaders.metal index e77f6085bac97d308bb94436c783e5fc272bc215..798ef3d66c1f32914b25253ec93af347846e06ab 100644 --- a/crates/gpui3/src/platform/mac/shaders.metal +++ b/crates/gpui3/src/platform/mac/shaders.metal @@ -7,174 +7,194 @@ float4 hsla_to_rgba(Hsla hsla); float4 to_device_position(float2 pixel_position, float2 viewport_size); struct QuadVertexOutput { - float4 position [[position]]; - float4 background_color; - float4 border_color; - uint quad_id; + float4 position [[position]]; + float4 background_color; + float4 border_color; + uint quad_id; }; vertex QuadVertexOutput quad_vertex( - uint unit_vertex_id [[vertex_id]], - uint quad_id [[instance_id]], + uint unit_vertex_id [[vertex_id]], uint quad_id [[instance_id]], constant float2 *unit_vertices [[buffer(QuadInputIndex_Vertices)]], constant Quad *quads [[buffer(QuadInputIndex_Quads)]], - constant QuadUniforms *uniforms [[buffer(QuadInputIndex_Uniforms)]] -) { - float2 unit_vertex = unit_vertices[unit_vertex_id]; - Quad quad = quads[quad_id]; - float2 position_2d = unit_vertex * float2(quad.bounds.size.width, quad.bounds.size.height) + float2(quad.bounds.origin.x, quad.bounds.origin.y); - position_2d.x = max(quad.clip_bounds.origin.x, position_2d.x); - position_2d.x = min(quad.clip_bounds.origin.x + quad.clip_bounds.size.width, position_2d.x); - position_2d.y = max(quad.clip_bounds.origin.y, position_2d.y); - position_2d.y = min(quad.clip_bounds.origin.y + quad.clip_bounds.size.height, position_2d.y); - - float2 viewport_size = float2((float)uniforms->viewport_size.width, (float)uniforms->viewport_size.height); - float4 device_position = to_device_position(position_2d, viewport_size); - float4 background_color = hsla_to_rgba(quad.background); - float4 border_color = hsla_to_rgba(quad.border_color); - return QuadVertexOutput { - device_position, - background_color, - border_color, - quad_id - }; + constant QuadUniforms *uniforms [[buffer(QuadInputIndex_Uniforms)]]) { + float2 unit_vertex = unit_vertices[unit_vertex_id]; + Quad quad = quads[quad_id]; + float2 position_2d = + unit_vertex * float2(quad.bounds.size.width, quad.bounds.size.height) + + float2(quad.bounds.origin.x, quad.bounds.origin.y); + position_2d.x = max(quad.clip_bounds.origin.x, position_2d.x); + position_2d.x = min(quad.clip_bounds.origin.x + quad.clip_bounds.size.width, + position_2d.x); + position_2d.y = max(quad.clip_bounds.origin.y, position_2d.y); + position_2d.y = min(quad.clip_bounds.origin.y + quad.clip_bounds.size.height, + position_2d.y); + + float2 viewport_size = float2((float)uniforms->viewport_size.width, + (float)uniforms->viewport_size.height); + float4 device_position = to_device_position(position_2d, viewport_size); + float4 background_color = hsla_to_rgba(quad.background); + float4 border_color = hsla_to_rgba(quad.border_color); + return QuadVertexOutput{device_position, background_color, border_color, + quad_id}; } -float quad_sdf(float2 point, Bounds_Pixels bounds, Corners_Pixels corner_radii) { - float2 half_size = float2(bounds.size.width, bounds.size.height) / 2.; - float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size; - float2 center_to_point = point - center; - float corner_radius; - if (center_to_point.x < 0.) { - if (center_to_point.y < 0.) { - corner_radius = corner_radii.top_left; - } else { - corner_radius = corner_radii.bottom_left; - } +float quad_sdf(float2 point, Bounds_Pixels bounds, + Corners_Pixels corner_radii) { + float2 half_size = float2(bounds.size.width, bounds.size.height) / 2.; + float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size; + float2 center_to_point = point - center; + float corner_radius; + if (center_to_point.x < 0.) { + if (center_to_point.y < 0.) { + corner_radius = corner_radii.top_left; } else { - if (center_to_point.y < 0.) { - corner_radius = corner_radii.top_right; - } else { - corner_radius = corner_radii.bottom_right; - } + corner_radius = corner_radii.bottom_left; } + } else { + if (center_to_point.y < 0.) { + corner_radius = corner_radii.top_right; + } else { + corner_radius = corner_radii.bottom_right; + } + } - float2 rounded_edge_to_point = abs(center_to_point) - half_size + corner_radius; - float distance = length(max(0., rounded_edge_to_point)) - + min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - - corner_radius; + float2 rounded_edge_to_point = + abs(center_to_point) - half_size + corner_radius; + float distance = + length(max(0., rounded_edge_to_point)) + + min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - + corner_radius; - return distance; + return distance; } -fragment float4 quad_fragment( - QuadVertexOutput input [[stage_in]], - constant Quad *quads [[buffer(QuadInputIndex_Quads)]] -) { - Quad quad = quads[input.quad_id]; - float2 half_size = float2(quad.bounds.size.width, quad.bounds.size.height) / 2.; - float2 center = float2(quad.bounds.origin.x, quad.bounds.origin.y) + half_size; - float2 center_to_point = input.position.xy - center; - float corner_radius; - if (center_to_point.x < 0.) { - if (center_to_point.y < 0.) { - corner_radius = quad.corner_radii.top_left; - } else { - corner_radius = quad.corner_radii.bottom_left; - } - } else { - if (center_to_point.y < 0.) { - corner_radius = quad.corner_radii.top_right; - } else { - corner_radius = quad.corner_radii.bottom_right; - } - } - - float2 rounded_edge_to_point = fabs(center_to_point) - half_size + corner_radius; - float distance = length(max(0., rounded_edge_to_point)) + min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - corner_radius; - - float vertical_border = center_to_point.x <= 0. ? quad.border_widths.left : quad.border_widths.right; - float horizontal_border = center_to_point.y <= 0. ? quad.border_widths.top : quad.border_widths.bottom; - float2 inset_size = half_size - corner_radius - float2(vertical_border, horizontal_border); - float2 point_to_inset_corner = fabs(center_to_point) - inset_size; - float border_width; - if (point_to_inset_corner.x < 0. && point_to_inset_corner.y < 0.) { - border_width = 0.; - } else if (point_to_inset_corner.y > point_to_inset_corner.x) { - border_width = horizontal_border; +fragment float4 quad_fragment(QuadVertexOutput input [[stage_in]], + constant Quad *quads + [[buffer(QuadInputIndex_Quads)]]) { + Quad quad = quads[input.quad_id]; + float2 half_size = + float2(quad.bounds.size.width, quad.bounds.size.height) / 2.; + float2 center = + float2(quad.bounds.origin.x, quad.bounds.origin.y) + half_size; + float2 center_to_point = input.position.xy - center; + float corner_radius; + if (center_to_point.x < 0.) { + if (center_to_point.y < 0.) { + corner_radius = quad.corner_radii.top_left; } else { - border_width = vertical_border; + corner_radius = quad.corner_radii.bottom_left; } - - float4 color; - if (border_width == 0.) { - color = input.background_color; + } else { + if (center_to_point.y < 0.) { + corner_radius = quad.corner_radii.top_right; } else { - float inset_distance = distance + border_width; - - // Decrease border's opacity as we move inside the background. - input.border_color.a *= 1. - saturate(0.5 - inset_distance); - - // Alpha-blend the border and the background. - float output_alpha = quad.border_color.a + quad.background.a * (1. - quad.border_color.a); - float3 premultiplied_border_rgb = input.border_color.rgb * quad.border_color.a; - float3 premultiplied_background_rgb = input.background_color.rgb * input.background_color.a; - float3 premultiplied_output_rgb = premultiplied_border_rgb + premultiplied_background_rgb * (1. - input.border_color.a); - color = float4(premultiplied_output_rgb, output_alpha); + corner_radius = quad.corner_radii.bottom_right; } - - float clip_distance = quad_sdf(input.position.xy, quad.clip_bounds, quad.clip_corner_radii); - return color * float4(1., 1., 1., saturate(0.5 - distance) * saturate(0.5 - clip_distance)); + } + + float2 rounded_edge_to_point = + fabs(center_to_point) - half_size + corner_radius; + float distance = + length(max(0., rounded_edge_to_point)) + + min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - + corner_radius; + + float vertical_border = center_to_point.x <= 0. ? quad.border_widths.left + : quad.border_widths.right; + float horizontal_border = center_to_point.y <= 0. ? quad.border_widths.top + : quad.border_widths.bottom; + float2 inset_size = + half_size - corner_radius - float2(vertical_border, horizontal_border); + float2 point_to_inset_corner = fabs(center_to_point) - inset_size; + float border_width; + if (point_to_inset_corner.x < 0. && point_to_inset_corner.y < 0.) { + border_width = 0.; + } else if (point_to_inset_corner.y > point_to_inset_corner.x) { + border_width = horizontal_border; + } else { + border_width = vertical_border; + } + + float4 color; + if (border_width == 0.) { + color = input.background_color; + } else { + float inset_distance = distance + border_width; + + // Decrease border's opacity as we move inside the background. + input.border_color.a *= 1. - saturate(0.5 - inset_distance); + + // Alpha-blend the border and the background. + float output_alpha = + quad.border_color.a + quad.background.a * (1. - quad.border_color.a); + float3 premultiplied_border_rgb = + input.border_color.rgb * quad.border_color.a; + float3 premultiplied_background_rgb = + input.background_color.rgb * input.background_color.a; + float3 premultiplied_output_rgb = + premultiplied_border_rgb + + premultiplied_background_rgb * (1. - input.border_color.a); + color = float4(premultiplied_output_rgb, output_alpha); + } + + float clip_distance = + quad_sdf(input.position.xy, quad.clip_bounds, quad.clip_corner_radii); + return color * + float4(1., 1., 1., + saturate(0.5 - distance) * saturate(0.5 - clip_distance)); } float4 hsla_to_rgba(Hsla hsla) { - float h = hsla.h * 6.0; // Now, it's an angle but scaled in [0, 6) range - float s = hsla.s; - float l = hsla.l; - float a = hsla.a; - - float c = (1.0 - fabs(2.0*l - 1.0)) * s; - float x = c * (1.0 - fabs(fmod(h, 2.0) - 1.0)); - float m = l - c/2.0; - - float r = 0.0; - float g = 0.0; - float b = 0.0; - - if (h >= 0.0 && h < 1.0) { - r = c; - g = x; - b = 0.0; - } else if (h >= 1.0 && h < 2.0) { - r = x; - g = c; - b = 0.0; - } else if (h >= 2.0 && h < 3.0) { - r = 0.0; - g = c; - b = x; - } else if (h >= 3.0 && h < 4.0) { - r = 0.0; - g = x; - b = c; - } else if (h >= 4.0 && h < 5.0) { - r = x; - g = 0.0; - b = c; - } else { - r = c; - g = 0.0; - b = x; - } - - float4 rgba; - rgba.x = (r + m); - rgba.y = (g + m); - rgba.z = (b + m); - rgba.w = a; - return rgba; + float h = hsla.h * 6.0; // Now, it's an angle but scaled in [0, 6) range + float s = hsla.s; + float l = hsla.l; + float a = hsla.a; + + float c = (1.0 - fabs(2.0 * l - 1.0)) * s; + float x = c * (1.0 - fabs(fmod(h, 2.0) - 1.0)); + float m = l - c / 2.0; + + float r = 0.0; + float g = 0.0; + float b = 0.0; + + if (h >= 0.0 && h < 1.0) { + r = c; + g = x; + b = 0.0; + } else if (h >= 1.0 && h < 2.0) { + r = x; + g = c; + b = 0.0; + } else if (h >= 2.0 && h < 3.0) { + r = 0.0; + g = c; + b = x; + } else if (h >= 3.0 && h < 4.0) { + r = 0.0; + g = x; + b = c; + } else if (h >= 4.0 && h < 5.0) { + r = x; + g = 0.0; + b = c; + } else { + r = c; + g = 0.0; + b = x; + } + + float4 rgba; + rgba.x = (r + m); + rgba.y = (g + m); + rgba.z = (b + m); + rgba.w = a; + return rgba; } float4 to_device_position(float2 pixel_position, float2 viewport_size) { - return float4(pixel_position / viewport_size * float2(2., -2.) + float2(-1., 1.), 0., 1.); + return float4(pixel_position / viewport_size * float2(2., -2.) + + float2(-1., 1.), + 0., 1.); } diff --git a/crates/gpui3/src/scene.rs b/crates/gpui3/src/scene.rs index 78c3d87246aae0e2c39f86831d3d144449b86510..6e7ee82a4186554ac96b3fa1a596484e382f78eb 100644 --- a/crates/gpui3/src/scene.rs +++ b/crates/gpui3/src/scene.rs @@ -1,7 +1,7 @@ use std::mem; use super::{Bounds, Hsla, Pixels, Point}; -use crate::{Corners, Edges}; +use crate::{Corners, Edges, FontId, GlyphId}; use bytemuck::{Pod, Zeroable}; use collections::BTreeMap; @@ -17,6 +17,7 @@ pub struct Scene { #[derive(Default, Debug)] pub struct SceneLayer { pub quads: Vec, + pub symbol: Vec, } impl Scene { @@ -40,6 +41,7 @@ impl Scene { let layer = self.layers.entry(primitive.order()).or_default(); match primitive { Primitive::Quad(quad) => layer.quads.push(quad), + Primitive::MonochromeGlyph(glyph) => layer.symbol.push(glyph), } } @@ -51,20 +53,14 @@ impl Scene { #[derive(Clone, Debug)] pub enum Primitive { Quad(Quad), + MonochromeGlyph(Symbol), } impl Primitive { pub fn order(&self) -> u32 { match self { Primitive::Quad(quad) => quad.order, - } - } - - pub fn is_transparent(&self) -> bool { - match self { - Primitive::Quad(quad) => { - quad.background.is_transparent() && quad.border_color.is_transparent() - } + Primitive::MonochromeGlyph(glyph) => glyph.order, } } @@ -73,6 +69,9 @@ impl Primitive { Primitive::Quad(quad) => { quad.scale(factor); } + Primitive::MonochromeGlyph(glyph) => { + glyph.scale(factor); + } } } } @@ -119,3 +118,27 @@ impl From for Primitive { Primitive::Quad(quad) } } + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Symbol { + pub order: u32, + pub origin: Point, + pub font_id: FontId, + pub font_size: Pixels, + pub id: GlyphId, + pub color: Hsla, +} + +impl Symbol { + pub fn scale(&mut self, factor: f32) { + self.font_size *= factor; + self.origin *= factor; + } +} + +impl From for Primitive { + fn from(glyph: Symbol) -> Self { + Primitive::MonochromeGlyph(glyph) + } +} diff --git a/crates/gpui3/src/text_system.rs b/crates/gpui3/src/text_system.rs index c7e4d763162b6a8e884386ee02f3cca470eab7db..38bb1fded4a3f1936ecdd5a45127fbced8857f17 100644 --- a/crates/gpui3/src/text_system.rs +++ b/crates/gpui3/src/text_system.rs @@ -1,9 +1,12 @@ mod font_features; +mod line; mod line_wrapper; mod text_layout_cache; use anyhow::anyhow; +use bytemuck::{Pod, Zeroable}; pub use font_features::*; +pub use line::*; use line_wrapper::*; pub use text_layout_cache::*; @@ -20,7 +23,8 @@ use std::{ sync::Arc, }; -#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] +#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug, Zeroable, Pod)] +#[repr(C)] pub struct FontId(pub usize); #[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] @@ -51,7 +55,6 @@ impl TextSystem { pub fn font_id(&self, font: &Font) -> Result { let font_id = self.font_ids_by_font.read().get(font).copied(); - if let Some(font_id) = font_id { Ok(font_id) } else { @@ -160,29 +163,18 @@ impl TextSystem { ) -> Result { let mut font_runs = self.font_runs_pool.lock().pop().unwrap_or_default(); - dbg!("got font runs from pool"); let mut last_font: Option<&Font> = None; for (len, style) in runs { - dbg!(len); if let Some(last_font) = last_font.as_ref() { - dbg!("a"); if **last_font == style.font { - dbg!("b"); font_runs.last_mut().unwrap().0 += len; - dbg!("c"); continue; } - dbg!("d"); } - dbg!("e"); last_font = Some(&style.font); - dbg!("f"); font_runs.push((*len, self.font_id(&style.font)?)); - dbg!("g"); } - dbg!("built font runs"); - let layout = self .text_layout_cache .layout_line(text, font_size, &font_runs); @@ -332,7 +324,8 @@ pub struct RunStyle { pub underline: Option, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Zeroable, Pod)] +#[repr(C)] pub struct GlyphId(u32); impl From for u32 { diff --git a/crates/gpui3/src/text_system/text_layout_cache.rs b/crates/gpui3/src/text_system/text_layout_cache.rs index 0f0d54c37e53165d7d93416707d92c1df8965b14..59cfd300eea82b102e21d8c4714aeaf00c01be9f 100644 --- a/crates/gpui3/src/text_system/text_layout_cache.rs +++ b/crates/gpui3/src/text_system/text_layout_cache.rs @@ -1,8 +1,4 @@ -use crate::{ - black, point, px, Bounds, FontId, Glyph, Hsla, LineLayout, Pixels, PlatformTextSystem, Point, - Run, RunStyle, UnderlineStyle, WindowContext, -}; -use anyhow::Result; +use crate::{FontId, Glyph, LineLayout, Pixels, PlatformTextSystem, Run}; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; use smallvec::SmallVec; use std::{ @@ -40,7 +36,6 @@ impl TextLayoutCache { font_size: Pixels, runs: &[(usize, FontId)], ) -> Arc { - dbg!("layout line"); let key = &CacheKeyRef { text, font_size, @@ -145,332 +140,12 @@ impl<'a> Hash for CacheKeyRef<'a> { } } -#[derive(Default, Debug, Clone)] -pub struct Line { - layout: Arc, - style_runs: SmallVec<[StyleRun; 32]>, -} - -#[derive(Debug, Clone)] -struct StyleRun { - len: u32, - color: Hsla, - underline: UnderlineStyle, -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct ShapedBoundary { pub run_ix: usize, pub glyph_ix: usize, } -impl Line { - pub fn new(layout: Arc, runs: &[(usize, RunStyle)]) -> Self { - let mut style_runs = SmallVec::new(); - for (len, style) in runs { - style_runs.push(StyleRun { - len: *len as u32, - color: style.color, - underline: style.underline.clone().unwrap_or_default(), - }); - } - Self { layout, style_runs } - } - - pub fn runs(&self) -> &[Run] { - &self.layout.runs - } - - pub fn width(&self) -> Pixels { - self.layout.width - } - - pub fn font_size(&self) -> Pixels { - self.layout.font_size - } - - pub fn x_for_index(&self, index: usize) -> Pixels { - for run in &self.layout.runs { - for glyph in &run.glyphs { - if glyph.index >= index { - return glyph.position.x; - } - } - } - self.layout.width - } - - pub fn font_for_index(&self, index: usize) -> Option { - for run in &self.layout.runs { - for glyph in &run.glyphs { - if glyph.index >= index { - return Some(run.font_id); - } - } - } - - None - } - - pub fn len(&self) -> usize { - self.layout.len - } - - pub fn is_empty(&self) -> bool { - self.layout.len == 0 - } - - pub fn index_for_x(&self, x: Pixels) -> Option { - if x >= self.layout.width { - None - } else { - for run in self.layout.runs.iter().rev() { - for glyph in run.glyphs.iter().rev() { - if glyph.position.x <= x { - return Some(glyph.index); - } - } - } - Some(0) - } - } - - // todo! - pub fn paint( - &self, - origin: Point, - visible_bounds: Bounds, - line_height: Pixels, - cx: &mut WindowContext, - ) -> Result<()> { - let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.; - let baseline_offset = point(px(0.), padding_top + self.layout.ascent); - - let mut style_runs = self.style_runs.iter(); - let mut run_end = 0; - let mut color = black(); - let mut underline = None; - - for run in &self.layout.runs { - cx.text_system().with_font(run.font_id, |system, font| { - let max_glyph_width = system.bounding_box(font, self.layout.font_size)?.size.width; - - for glyph in &run.glyphs { - let glyph_origin = origin + baseline_offset + glyph.position; - if glyph_origin.x > visible_bounds.upper_right().x { - break; - } - - let mut finished_underline: Option<(Point, UnderlineStyle)> = None; - if glyph.index >= run_end { - if let Some(style_run) = style_runs.next() { - if let Some((_, underline_style)) = &mut underline { - if style_run.underline != *underline_style { - finished_underline = underline.take(); - } - } - if style_run.underline.thickness > px(0.) { - underline.get_or_insert(( - point( - glyph_origin.x, - origin.y - + baseline_offset.y - + (self.layout.descent * 0.618), - ), - UnderlineStyle { - color: style_run.underline.color, - thickness: style_run.underline.thickness, - squiggly: style_run.underline.squiggly, - }, - )); - } - - run_end += style_run.len as usize; - color = style_run.color; - } else { - run_end = self.layout.len; - finished_underline = underline.take(); - } - } - - if glyph_origin.x + max_glyph_width < visible_bounds.origin.x { - continue; - } - - if let Some((_underline_origin, _underline_style)) = finished_underline { - // cx.scene().insert(Underline { - // origin: underline_origin, - // width: glyph_origin.x - underline_origin.x, - // thickness: underline_style.thickness.into(), - // color: underline_style.color.unwrap(), - // squiggly: underline_style.squiggly, - // }); - } - - // if glyph.is_emoji { - // cx.scene().push_image_glyph(scene::ImageGlyph { - // font_id: run.font_id, - // font_size: self.layout.font_size, - // id: glyph.id, - // origin: glyph_origin, - // }); - // } else { - // cx.scene().push_glyph(scene::Glyph { - // font_id: run.font_id, - // font_size: self.layout.font_size, - // id: glyph.id, - // origin: glyph_origin, - // color, - // }); - // } - } - - anyhow::Ok(()) - })??; - } - - if let Some((_underline_start, _underline_style)) = underline.take() { - let _line_end_x = origin.x + self.layout.width; - // cx.scene().push_underline(Underline { - // origin: underline_start, - // width: line_end_x - underline_start.x, - // color: underline_style.color, - // thickness: underline_style.thickness.into(), - // squiggly: underline_style.squiggly, - // }); - } - - Ok(()) - } - - pub fn paint_wrapped( - &self, - origin: Point, - _visible_bounds: Bounds, - line_height: Pixels, - boundaries: &[ShapedBoundary], - cx: &mut WindowContext, - ) -> Result<()> { - let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.; - let baseline_offset = point(px(0.), padding_top + self.layout.ascent); - - let mut boundaries = boundaries.into_iter().peekable(); - let mut color_runs = self.style_runs.iter(); - let mut style_run_end = 0; - let mut _color = black(); // todo! - let mut underline: Option<(Point, UnderlineStyle)> = None; - - let mut glyph_origin = origin; - let mut prev_position = px(0.); - for (run_ix, run) in self.layout.runs.iter().enumerate() { - for (glyph_ix, glyph) in run.glyphs.iter().enumerate() { - glyph_origin.x += glyph.position.x - prev_position; - - if boundaries - .peek() - .map_or(false, |b| b.run_ix == run_ix && b.glyph_ix == glyph_ix) - { - boundaries.next(); - if let Some((_underline_origin, _underline_style)) = underline.take() { - // cx.scene().push_underline(Underline { - // origin: underline_origin, - // width: glyph_origin.x - underline_origin.x, - // thickness: underline_style.thickness.into(), - // color: underline_style.color.unwrap(), - // squiggly: underline_style.squiggly, - // }); - } - - glyph_origin = point(origin.x, glyph_origin.y + line_height); - } - prev_position = glyph.position.x; - - let mut finished_underline = None; - if glyph.index >= style_run_end { - if let Some(style_run) = color_runs.next() { - style_run_end += style_run.len as usize; - _color = style_run.color; - if let Some((_, underline_style)) = &mut underline { - if style_run.underline != *underline_style { - finished_underline = underline.take(); - } - } - if style_run.underline.thickness > px(0.) { - underline.get_or_insert(( - glyph_origin - + point( - px(0.), - baseline_offset.y + (self.layout.descent * 0.618), - ), - UnderlineStyle { - color: Some( - style_run.underline.color.unwrap_or(style_run.color), - ), - thickness: style_run.underline.thickness, - squiggly: style_run.underline.squiggly, - }, - )); - } - } else { - style_run_end = self.layout.len; - _color = black(); - finished_underline = underline.take(); - } - } - - if let Some((_underline_origin, _underline_style)) = finished_underline { - // cx.scene().push_underline(Underline { - // origin: underline_origin, - // width: glyph_origin.x - underline_origin.x, - // thickness: underline_style.thickness.into(), - // color: underline_style.color.unwrap(), - // squiggly: underline_style.squiggly, - // }); - } - - cx.text_system().with_font(run.font_id, |system, font| { - let _glyph_bounds = Bounds { - origin: glyph_origin, - size: system.bounding_box(font, self.layout.font_size)?.size, - }; - // if glyph_bounds.intersects(visible_bounds) { - // if glyph.is_emoji { - // cx.scene().push_image_glyph(scene::ImageGlyph { - // font_id: run.font_id, - // font_size: self.layout.font_size, - // id: glyph.id, - // origin: glyph_bounds.origin() + baseline_offset, - // }); - // } else { - // cx.scene().push_glyph(scene::Glyph { - // font_id: run.font_id, - // font_size: self.layout.font_size, - // id: glyph.id, - // origin: glyph_bounds.origin() + baseline_offset, - // color, - // }); - // } - // } - anyhow::Ok(()) - })??; - } - } - - if let Some((_underline_origin, _underline_style)) = underline.take() { - // let line_end_x = glyph_origin.x + self.layout.width - prev_position; - // cx.scene().push_underline(Underline { - // origin: underline_origin, - // width: line_end_x - underline_origin.x, - // thickness: underline_style.thickness.into(), - // color: underline_style.color, - // squiggly: underline_style.squiggly, - // }); - } - - Ok(()) - } -} - impl Run { pub fn glyphs(&self) -> &[Glyph] { &self.glyphs diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 0066adfef1350f432e675d5701461c12a4f94d0f..8ec4063a275a52308c9d6f8689ec2d9246f62940 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -5,6 +5,7 @@ use crate::{ }; use anyhow::Result; use futures::Future; +use smallvec::SmallVec; use std::{any::TypeId, marker::PhantomData, mem, sync::Arc}; use util::ResultExt; @@ -18,6 +19,7 @@ pub struct Window { layout_engine: TaffyLayoutEngine, pub(crate) root_view: Option>, mouse_position: Point, + z_index_stack: SmallVec<[u32; 8]>, pub(crate) scene: Scene, pub(crate) dirty: bool, } @@ -56,6 +58,7 @@ impl Window { layout_engine: TaffyLayoutEngine::new(), root_view: None, mouse_position, + z_index_stack: SmallVec::new(), scene: Scene::new(scale_factor), dirty: true, } @@ -126,6 +129,13 @@ impl<'a, 'w> WindowContext<'a, 'w> { &mut self.window.scene } + pub fn with_z_index(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R { + self.window.z_index_stack.push(z_index); + let result = f(self); + self.window.z_index_stack.pop(); + result + } + pub fn run_on_main( &self, f: impl FnOnce(&mut MainThread) -> R + Send + 'static,