Checkpoint

This commit is contained in:
Nathan Sobo 2023-10-03 20:04:17 -06:00
parent 7f9e3bc787
commit da211bef96
10 changed files with 215 additions and 81 deletions

View file

@ -45,6 +45,7 @@ fn generate_shader_bindings() -> PathBuf {
"Pixels".into(), "Pixels".into(),
"PointF".into(), "PointF".into(),
"Hsla".into(), "Hsla".into(),
"ScaledContentMask".into(),
"Uniforms".into(), "Uniforms".into(),
"AtlasTile".into(), "AtlasTile".into(),
"Quad".into(), "Quad".into(),
@ -58,12 +59,14 @@ fn generate_shader_bindings() -> PathBuf {
.with_src(crate_dir.join("src/scene.rs")) .with_src(crate_dir.join("src/scene.rs"))
.with_src(crate_dir.join("src/geometry.rs")) .with_src(crate_dir.join("src/geometry.rs"))
.with_src(crate_dir.join("src/color.rs")) .with_src(crate_dir.join("src/color.rs"))
.with_src(crate_dir.join("src/window.rs"))
.with_src(crate_dir.join("src/platform.rs")) .with_src(crate_dir.join("src/platform.rs"))
.with_src(crate_dir.join("src/platform/mac/metal_renderer.rs")) .with_src(crate_dir.join("src/platform/mac/metal_renderer.rs"))
.with_config(config) .with_config(config)
.generate() .generate()
.expect("Unable to generate bindings") .expect("Unable to generate bindings")
.write_to_file(&output_path); .write_to_file(&output_path);
output_path output_path
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
AnyElement, Bounds, Element, Layout, LayoutId, Overflow, ParentElement, Pixels, Point, AnyElement, Bounds, Element, Layout, LayoutId, Overflow, ParentElement, Pixels, Point,
Refineable, RefinementCascade, Result, StackContext, Style, StyleHelpers, Styled, ViewContext, Refineable, RefinementCascade, Result, Style, StyleHelpers, Styled, ViewContext,
}; };
use parking_lot::Mutex; use parking_lot::Mutex;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -33,16 +33,9 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
cx: &mut ViewContext<S>, cx: &mut ViewContext<S>,
) -> Result<(LayoutId, Self::FrameState)> { ) -> Result<(LayoutId, Self::FrameState)> {
let style = self.computed_style(); let style = self.computed_style();
let child_layout_ids = if let Some(text_style) = style.text_style(cx) { let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx))?;
cx.with_text_style(text_style.clone(), |cx| self.layout_children(view, cx))? let layout_id = cx.request_layout(style.into(), child_layout_ids.clone())?;
} else { Ok((layout_id, child_layout_ids))
self.layout_children(view, cx)?
};
Ok((
cx.request_layout(style.into(), child_layout_ids.clone())?,
child_layout_ids,
))
} }
fn paint( fn paint(
@ -56,20 +49,18 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
let style = self.computed_style(); let style = self.computed_style();
style.paint(order, bounds, cx); style.paint(order, bounds, cx);
let overflow = &style.overflow;
// // todo!("support only one dimension being hidden")
// if style.overflow.y != Overflow::Visible || style.overflow.x != Overflow::Visible {
// cx.scene().push_layer(Some(bounds));
// pop_layer = true;
// }
if let Some(text_style) = style.text_style(cx) {
cx.with_text_style(text_style.clone(), |cx| {
self.paint_children(overflow, state, cx)
})?;
} else {
self.paint_children(overflow, state, cx)?;
}
// // todo!("support only one dimension being hidden")
let overflow = &style.overflow;
// if style.overflow.y != Overflow::Visible || style.overflow.x != Overflow::Visible {
// cx.clip(layout.bounds, style.corner_radii, || )
// }
style.apply_text_style(cx, |cx| {
style.apply_overflow(layout.bounds, cx, |cx| {
self.paint_children(overflow, state, cx)
})
})?;
self.handle_scroll(order, bounds, style.overflow.clone(), child_layouts, cx); self.handle_scroll(order, bounds, style.overflow.clone(), child_layouts, cx);
// todo!("enable inspector") // todo!("enable inspector")

View file

@ -225,6 +225,20 @@ pub struct Bounds<T: Clone + Debug> {
pub size: Size<T>, pub size: Size<T>,
} }
impl<T: Clone + Debug + Sub<Output = T>> Bounds<T> {
pub fn from_corners(upper_left: Point<T>, lower_right: Point<T>) -> Self {
let origin = Point {
x: upper_left.x.clone(),
y: upper_left.y.clone(),
};
let size = Size {
width: lower_right.x - upper_left.x,
height: lower_right.y - upper_left.y,
};
Bounds { origin, size }
}
}
impl<T, Rhs> Mul<Rhs> for Bounds<T> impl<T, Rhs> Mul<Rhs> for Bounds<T>
where where
T: Mul<Rhs, Output = Rhs> + Clone + Debug, T: Mul<Rhs, Output = Rhs> + Clone + Debug,
@ -418,6 +432,28 @@ pub struct Corners<T: Clone + Debug> {
pub bottom_left: T, pub bottom_left: T,
} }
impl Corners<AbsoluteLength> {
pub fn to_pixels(&self, rem_size: Pixels) -> Corners<Pixels> {
Corners {
top_left: self.top_left.to_pixels(rem_size),
top_right: self.top_right.to_pixels(rem_size),
bottom_right: self.bottom_right.to_pixels(rem_size),
bottom_left: self.bottom_left.to_pixels(rem_size),
}
}
}
impl Corners<Pixels> {
pub fn scale(&self, factor: f32) -> Corners<ScaledPixels> {
Corners {
top_left: self.top_left.scale(factor),
top_right: self.top_right.scale(factor),
bottom_right: self.bottom_right.scale(factor),
bottom_left: self.bottom_left.scale(factor),
}
}
}
impl<T: Clone + Debug> Corners<T> { impl<T: Clone + Debug> Corners<T> {
pub fn map<U: Clone + Debug, F: Fn(&T) -> U>(&self, f: F) -> Corners<U> { pub fn map<U: Clone + Debug, F: Fn(&T) -> U>(&self, f: F) -> Corners<U> {
Corners { Corners {

View file

@ -84,16 +84,16 @@ impl<T> DerefMut for MainThread<T> {
} }
} }
pub trait StackContext { pub trait BorrowAppContext {
fn app(&mut self) -> &mut AppContext; fn app_mut(&mut self) -> &mut AppContext;
fn with_text_style<F, R>(&mut self, style: TextStyleRefinement, f: F) -> R fn with_text_style<F, R>(&mut self, style: TextStyleRefinement, f: F) -> R
where where
F: FnOnce(&mut Self) -> R, F: FnOnce(&mut Self) -> R,
{ {
self.app().push_text_style(style); self.app_mut().push_text_style(style);
let result = f(self); let result = f(self);
self.app().pop_text_style(); self.app_mut().pop_text_style();
result result
} }
@ -101,9 +101,9 @@ pub trait StackContext {
where where
F: FnOnce(&mut Self) -> R, F: FnOnce(&mut Self) -> R,
{ {
self.app().push_state(state); self.app_mut().push_state(state);
let result = f(self); let result = f(self);
self.app().pop_state::<T>(); self.app_mut().pop_state::<T>();
result result
} }
} }

View file

@ -4,10 +4,10 @@
using namespace metal; using namespace metal;
float4 hsla_to_rgba(Hsla hsla); float4 hsla_to_rgba(Hsla hsla);
float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds, float4 to_device_position(float2 unit_vertex, Bounds_ScaledPixels bounds,
Bounds_Pixels clip_bounds, Bounds_ScaledPixels clip_bounds,
constant Size_DevicePixels *viewport_size); constant Size_DevicePixels *viewport_size);
float quad_sdf(float2 point, Bounds_Pixels bounds, Corners_Pixels corner_radii); float quad_sdf(float2 point, Bounds_ScaledPixels bounds, Corners_ScaledPixels corner_radii);
struct QuadVertexOutput { struct QuadVertexOutput {
float4 position [[position]]; float4 position [[position]];
@ -131,7 +131,7 @@ vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex(
float2 unit_vertex = unit_vertices[unit_vertex_id]; float2 unit_vertex = unit_vertices[unit_vertex_id];
MonochromeSprite sprite = sprites[sprite_id]; MonochromeSprite sprite = sprites[sprite_id];
float4 device_position = to_device_position( float4 device_position = to_device_position(
unit_vertex, sprite.bounds, sprite.clip_bounds, viewport_size); unit_vertex, sprite.bounds, sprite.content_mask.bounds, viewport_size);
float2 tile_origin = float2 tile_origin =
float2(sprite.tile.bounds.origin.x, sprite.tile.bounds.origin.y); float2(sprite.tile.bounds.origin.x, sprite.tile.bounds.origin.y);
@ -157,7 +157,7 @@ fragment float4 monochrome_sprite_fragment(
float4 sample = float4 sample =
atlas_texture.sample(atlas_texture_sampler, input.tile_position); atlas_texture.sample(atlas_texture_sampler, input.tile_position);
float clip_distance = float clip_distance =
quad_sdf(input.position.xy, sprite.clip_bounds, sprite.clip_corner_radii); quad_sdf(input.position.xy, sprite.content_mask.bounds, sprite.content_mask.corner_radii);
float4 color = input.color; float4 color = input.color;
color.a *= sample.a * saturate(0.5 - clip_distance); color.a *= sample.a * saturate(0.5 - clip_distance);
return color; return color;
@ -211,8 +211,8 @@ float4 hsla_to_rgba(Hsla hsla) {
return rgba; return rgba;
} }
float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds, float4 to_device_position(float2 unit_vertex, Bounds_ScaledPixels bounds,
Bounds_Pixels clip_bounds, Bounds_ScaledPixels clip_bounds,
constant Size_DevicePixels *input_viewport_size) { constant Size_DevicePixels *input_viewport_size) {
float2 position = float2 position =
unit_vertex * float2(bounds.size.width, bounds.size.height) + unit_vertex * float2(bounds.size.width, bounds.size.height) +
@ -229,8 +229,8 @@ float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds,
return float4(device_position, 0., 1.); return float4(device_position, 0., 1.);
} }
float quad_sdf(float2 point, Bounds_Pixels bounds, float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
Corners_Pixels corner_radii) { Corners_ScaledPixels corner_radii) {
float2 half_size = float2(bounds.size.width, bounds.size.height) / 2.; float2 half_size = float2(bounds.size.width, bounds.size.height) / 2.;
float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size; float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size;
float2 center_to_point = point - center; float2 center_to_point = point - center;

View file

@ -1,7 +1,7 @@
use std::{iter::Peekable, mem}; use std::{iter::Peekable, mem};
use super::{Bounds, Hsla, Point}; use super::{Bounds, Hsla, Point};
use crate::{AtlasTextureId, AtlasTile, Corners, Edges, ScaledPixels}; use crate::{AtlasTextureId, AtlasTile, Corners, Edges, ScaledContentMask, ScaledPixels};
use collections::BTreeMap; use collections::BTreeMap;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -234,8 +234,7 @@ impl From<Quad> for Primitive {
pub struct MonochromeSprite { pub struct MonochromeSprite {
pub order: u32, pub order: u32,
pub bounds: Bounds<ScaledPixels>, pub bounds: Bounds<ScaledPixels>,
pub clip_bounds: Bounds<ScaledPixels>, pub content_mask: ScaledContentMask,
pub clip_corner_radii: Corners<ScaledPixels>,
pub color: Hsla, pub color: Hsla,
pub tile: AtlasTile, pub tile: AtlasTile,
} }

View file

@ -1,8 +1,8 @@
use crate::{ use crate::{
phi, rems, AbsoluteLength, Bounds, Corners, CornersRefinement, DefiniteLength, Edges, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners,
EdgesRefinement, Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle,
PointRefinement, Quad, Rems, Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle,
WindowContext, SharedString, Size, SizeRefinement, ViewContext, WindowContext,
}; };
use refineable::Refineable; use refineable::Refineable;
pub use taffy::style::{ pub use taffy::style::{
@ -179,6 +179,57 @@ impl Style {
} }
} }
pub fn apply_text_style<C, F, R>(&self, cx: &mut C, f: F) -> R
where
C: BorrowAppContext,
F: FnOnce(&mut C) -> R,
{
if self.text.is_some() {
cx.with_text_style(self.text.clone(), f)
} else {
f(cx)
}
}
/// Apply overflow to content mask
pub fn apply_overflow<C, F, R>(&self, bounds: Bounds<Pixels>, cx: &mut C, f: F) -> R
where
C: BorrowWindow,
F: FnOnce(&mut C) -> R,
{
let current_mask = cx.content_mask();
let min = current_mask.bounds.origin;
let max = current_mask.bounds.lower_right();
let mask_corner_radii = Corners::default();
let mask_bounds = match (
self.overflow.x == Overflow::Visible,
self.overflow.y == Overflow::Visible,
) {
// x and y both visible
(true, true) => return f(cx),
// x visible, y hidden
(true, false) => Bounds::from_corners(
point(min.x, bounds.origin.y),
point(max.x, bounds.lower_right().y),
),
// x hidden, y visible
(false, true) => Bounds::from_corners(
point(bounds.origin.x, min.y),
point(bounds.lower_right().x, max.y),
),
// both hidden
(false, false) => bounds,
};
let mask = ContentMask {
bounds: mask_bounds,
corner_radii: mask_corner_radii,
};
cx.with_content_mask(mask, f)
}
/// Paints the background of an element styled with this style. /// Paints the background of an element styled with this style.
pub fn paint<V: 'static>(&self, order: u32, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) { pub fn paint<V: 'static>(&self, order: u32, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
let rem_size = cx.rem_size(); let rem_size = cx.rem_size();

View file

@ -2,12 +2,6 @@ use smol::future::FutureExt;
use std::{future::Future, time::Duration}; use std::{future::Future, time::Duration};
pub use util::*; pub use util::*;
pub fn post_inc(value: &mut usize) -> usize {
let prev = *value;
*value += 1;
prev
}
pub async fn timeout<F, T>(timeout: Duration, f: F) -> Result<T, ()> pub async fn timeout<F, T>(timeout: Duration, f: F) -> Result<T, ()>
where where
F: Future<Output = T>, F: Future<Output = T>,

View file

@ -1,8 +1,8 @@
use crate::{ use crate::{
px, AnyView, AppContext, AvailableSpace, Bounds, Context, Corners, Effect, Element, EntityId, px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners, Effect,
FontId, GlyphId, GlyphRasterParams, Handle, Hsla, IsZero, LayerId, LayoutId, MainThread, Element, EntityId, FontId, GlyphId, GlyphRasterParams, Handle, Hsla, IsZero, LayerId, LayoutId,
MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, Reference, MainThread, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point,
Scene, Size, StackContext, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, Reference, ScaledPixels, Scene, Size, Style, TaffyLayoutEngine, WeakHandle, WindowOptions,
SUBPIXEL_VARIANTS, SUBPIXEL_VARIANTS,
}; };
use anyhow::Result; use anyhow::Result;
@ -74,8 +74,24 @@ impl Window {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ContentMask { pub struct ContentMask {
bounds: Bounds<Pixels>, pub bounds: Bounds<Pixels>,
corner_radii: Corners<Pixels>, pub corner_radii: Corners<Pixels>,
}
impl ContentMask {
pub fn scale(&self, factor: f32) -> ScaledContentMask {
ScaledContentMask {
bounds: self.bounds.scale(factor),
corner_radii: self.corner_radii.scale(factor),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct ScaledContentMask {
bounds: Bounds<ScaledPixels>,
corner_radii: Corners<ScaledPixels>,
} }
pub struct WindowContext<'a, 'w> { pub struct WindowContext<'a, 'w> {
@ -174,20 +190,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
self.window.current_layer_id.clone() self.window.current_layer_id.clone()
} }
pub fn current_clipping_mask(&self) -> ContentMask {
self.window
.content_mask_stack
.last()
.cloned()
.unwrap_or_else(|| ContentMask {
bounds: Bounds {
origin: Point::default(),
size: self.window.content_size,
},
corner_radii: Default::default(),
})
}
pub fn run_on_main<R>( pub fn run_on_main<R>(
&self, &self,
f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static, f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,
@ -239,14 +241,14 @@ impl<'a, 'w> WindowContext<'a, 'w> {
origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into), origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
size: tile.bounds.size.map(Into::into), size: tile.bounds.size.map(Into::into),
}; };
let content_mask = self.content_mask().scale(scale_factor);
self.window.scene.insert( self.window.scene.insert(
layer_id, layer_id,
MonochromeSprite { MonochromeSprite {
order, order,
bounds, bounds,
clip_bounds: bounds, content_mask,
clip_corner_radii: Default::default(),
color, color,
tile, tile,
}, },
@ -330,8 +332,60 @@ impl<'a, 'w> std::ops::DerefMut for WindowContext<'a, 'w> {
} }
} }
impl<S> StackContext for ViewContext<'_, '_, S> { impl BorrowAppContext for WindowContext<'_, '_> {
fn app(&mut self) -> &mut AppContext { fn app_mut(&mut self) -> &mut AppContext {
&mut *self.app
}
}
pub trait BorrowWindow: BorrowAppContext {
fn window(&self) -> &Window;
fn window_mut(&mut self) -> &mut Window;
fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R {
self.window_mut().content_mask_stack.push(mask);
let result = f(self);
self.window_mut().content_mask_stack.pop();
result
}
fn content_mask(&self) -> ContentMask {
self.window()
.content_mask_stack
.last()
.cloned()
.unwrap_or_else(|| ContentMask {
bounds: Bounds {
origin: Point::default(),
size: self.window().content_size,
},
corner_radii: Default::default(),
})
}
fn rem_size(&self) -> Pixels {
self.window().rem_size
}
}
impl BorrowWindow for WindowContext<'_, '_> {
fn window(&self) -> &Window {
&*self.window
}
fn window_mut(&mut self) -> &mut Window {
&mut *self.window
}
}
pub struct ViewContext<'a, 'w, S> {
window_cx: WindowContext<'a, 'w>,
entity_type: PhantomData<S>,
entity_id: EntityId,
}
impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
fn app_mut(&mut self) -> &mut AppContext {
&mut *self.window_cx.app &mut *self.window_cx.app
} }
@ -356,10 +410,14 @@ impl<S> StackContext for ViewContext<'_, '_, S> {
} }
} }
pub struct ViewContext<'a, 'w, S> { impl<S> BorrowWindow for ViewContext<'_, '_, S> {
window_cx: WindowContext<'a, 'w>, fn window(&self) -> &Window {
entity_type: PhantomData<S>, &self.window_cx.window
entity_id: EntityId, }
fn window_mut(&mut self) -> &mut Window {
&mut *self.window_cx.window
}
} }
impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> { impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {

View file

@ -1,4 +1,6 @@
use gpui3::{Element, Hsla, Layout, LayoutId, Result, StackContext, ViewContext, WindowContext}; use gpui3::{
BorrowAppContext, Element, Hsla, Layout, LayoutId, Result, ViewContext, WindowContext,
};
use serde::{de::Visitor, Deserialize, Deserializer}; use serde::{de::Visitor, Deserialize, Deserializer};
use std::{collections::HashMap, fmt}; use std::{collections::HashMap, fmt};