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(),
"PointF".into(),
"Hsla".into(),
"ScaledContentMask".into(),
"Uniforms".into(),
"AtlasTile".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/geometry.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/mac/metal_renderer.rs"))
.with_config(config)
.generate()
.expect("Unable to generate bindings")
.write_to_file(&output_path);
output_path
}

View file

@ -1,6 +1,6 @@
use crate::{
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 smallvec::SmallVec;
@ -33,16 +33,9 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
cx: &mut ViewContext<S>,
) -> Result<(LayoutId, Self::FrameState)> {
let style = self.computed_style();
let child_layout_ids = if let Some(text_style) = style.text_style(cx) {
cx.with_text_style(text_style.clone(), |cx| self.layout_children(view, cx))?
} else {
self.layout_children(view, cx)?
};
Ok((
cx.request_layout(style.into(), child_layout_ids.clone())?,
child_layout_ids,
))
let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx))?;
let layout_id = cx.request_layout(style.into(), child_layout_ids.clone())?;
Ok((layout_id, child_layout_ids))
}
fn paint(
@ -56,20 +49,18 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
let style = self.computed_style();
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);
// todo!("enable inspector")

View file

@ -225,6 +225,20 @@ pub struct Bounds<T: Clone + Debug> {
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>
where
T: Mul<Rhs, Output = Rhs> + Clone + Debug,
@ -418,6 +432,28 @@ pub struct Corners<T: Clone + Debug> {
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> {
pub fn map<U: Clone + Debug, F: Fn(&T) -> U>(&self, f: F) -> Corners<U> {
Corners {

View file

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

View file

@ -4,10 +4,10 @@
using namespace metal;
float4 hsla_to_rgba(Hsla hsla);
float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds,
Bounds_Pixels clip_bounds,
float4 to_device_position(float2 unit_vertex, Bounds_ScaledPixels bounds,
Bounds_ScaledPixels clip_bounds,
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 {
float4 position [[position]];
@ -131,7 +131,7 @@ vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex(
float2 unit_vertex = unit_vertices[unit_vertex_id];
MonochromeSprite sprite = sprites[sprite_id];
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(sprite.tile.bounds.origin.x, sprite.tile.bounds.origin.y);
@ -157,7 +157,7 @@ fragment float4 monochrome_sprite_fragment(
float4 sample =
atlas_texture.sample(atlas_texture_sampler, input.tile_position);
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;
color.a *= sample.a * saturate(0.5 - clip_distance);
return color;
@ -211,8 +211,8 @@ float4 hsla_to_rgba(Hsla hsla) {
return rgba;
}
float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds,
Bounds_Pixels clip_bounds,
float4 to_device_position(float2 unit_vertex, Bounds_ScaledPixels bounds,
Bounds_ScaledPixels clip_bounds,
constant Size_DevicePixels *input_viewport_size) {
float2 position =
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.);
}
float quad_sdf(float2 point, Bounds_Pixels bounds,
Corners_Pixels corner_radii) {
float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
Corners_ScaledPixels 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;

View file

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

View file

@ -1,8 +1,8 @@
use crate::{
phi, rems, AbsoluteLength, Bounds, Corners, CornersRefinement, DefiniteLength, Edges,
EdgesRefinement, Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point,
PointRefinement, Quad, Rems, Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext,
WindowContext,
phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners,
CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle,
FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle,
SharedString, Size, SizeRefinement, ViewContext, WindowContext,
};
use refineable::Refineable;
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.
pub fn paint<V: 'static>(&self, order: u32, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
let rem_size = cx.rem_size();

View file

@ -2,12 +2,6 @@ use smol::future::FutureExt;
use std::{future::Future, time::Duration};
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, ()>
where
F: Future<Output = T>,

View file

@ -1,8 +1,8 @@
use crate::{
px, AnyView, AppContext, AvailableSpace, Bounds, Context, Corners, Effect, Element, EntityId,
FontId, GlyphId, GlyphRasterParams, Handle, Hsla, IsZero, LayerId, LayoutId, MainThread,
MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, Reference,
Scene, Size, StackContext, Style, TaffyLayoutEngine, WeakHandle, WindowOptions,
px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners, Effect,
Element, EntityId, FontId, GlyphId, GlyphRasterParams, Handle, Hsla, IsZero, LayerId, LayoutId,
MainThread, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point,
Reference, ScaledPixels, Scene, Size, Style, TaffyLayoutEngine, WeakHandle, WindowOptions,
SUBPIXEL_VARIANTS,
};
use anyhow::Result;
@ -74,8 +74,24 @@ impl Window {
#[derive(Clone, Debug)]
pub struct ContentMask {
bounds: Bounds<Pixels>,
corner_radii: Corners<Pixels>,
pub bounds: Bounds<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> {
@ -174,20 +190,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
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>(
&self,
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),
size: tile.bounds.size.map(Into::into),
};
let content_mask = self.content_mask().scale(scale_factor);
self.window.scene.insert(
layer_id,
MonochromeSprite {
order,
bounds,
clip_bounds: bounds,
clip_corner_radii: Default::default(),
content_mask,
color,
tile,
},
@ -330,8 +332,60 @@ impl<'a, 'w> std::ops::DerefMut for WindowContext<'a, 'w> {
}
}
impl<S> StackContext for ViewContext<'_, '_, S> {
fn app(&mut self) -> &mut AppContext {
impl BorrowAppContext for WindowContext<'_, '_> {
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
}
@ -356,10 +410,14 @@ impl<S> StackContext for ViewContext<'_, '_, S> {
}
}
pub struct ViewContext<'a, 'w, S> {
window_cx: WindowContext<'a, 'w>,
entity_type: PhantomData<S>,
entity_id: EntityId,
impl<S> BorrowWindow for ViewContext<'_, '_, S> {
fn window(&self) -> &Window {
&self.window_cx.window
}
fn window_mut(&mut self) -> &mut Window {
&mut *self.window_cx.window
}
}
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 std::{collections::HashMap, fmt};