diff --git a/Cargo.lock b/Cargo.lock index 8a6750bcd89c9f76f55fb0b55bea08e73b7771a4..f1be323064d4224fce18d27c521ebd4180ed47eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1070,20 +1070,6 @@ name = "bytemuck" version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] [[package]] name = "byteorder" @@ -3282,7 +3268,6 @@ dependencies = [ "bindgen 0.65.1", "bitflags 2.4.0", "block", - "bytemuck", "cbindgen", "cocoa", "collections", diff --git a/crates/gpui/src/image_cache.rs b/crates/gpui/src/image_cache.rs index d7682a43fd201935ae8683e1e73c166091f8efa7..00d62a16a5e17c4301cc8bf9fe042d6ddefe05d4 100644 --- a/crates/gpui/src/image_cache.rs +++ b/crates/gpui/src/image_cache.rs @@ -84,7 +84,6 @@ impl ImageCache { let format = image::guess_format(&body)?; let image = image::load_from_memory_with_format(&body, format)?.into_bgra8(); - Ok(ImageData::new(image)) } } diff --git a/crates/gpui/src/platform/mac/atlas.rs b/crates/gpui/src/platform/mac/atlas.rs index a529513ef5ef38faab25cf983e4820066ce9d28b..57a137479d7e8eaca79effad754862ddb996e366 100644 --- a/crates/gpui/src/platform/mac/atlas.rs +++ b/crates/gpui/src/platform/mac/atlas.rs @@ -109,6 +109,7 @@ impl AtlasAllocator { }; descriptor.set_width(size.x() as u64); descriptor.set_height(size.y() as u64); + self.device.new_texture(&descriptor) } else { self.device.new_texture(&self.texture_descriptor) diff --git a/crates/gpui/src/platform/mac/renderer.rs b/crates/gpui/src/platform/mac/renderer.rs index 55ec3e9e9a2f3f72c03103adf045721105d3da83..85f0af1ffddb902f00bcdb15012e474547e68fa7 100644 --- a/crates/gpui/src/platform/mac/renderer.rs +++ b/crates/gpui/src/platform/mac/renderer.rs @@ -632,6 +632,7 @@ impl Renderer { ) { // Snap sprite to pixel grid. let origin = (glyph.origin * scale_factor).floor() + sprite.offset.to_f32(); + sprites_by_atlas .entry(sprite.atlas_id) .or_insert_with(Vec::new) diff --git a/crates/gpui2/src/color.rs b/crates/gpui2/src/color.rs index 11590f967cdba57edebf52a23fd1721cbf1fc899..b128ea691c188247a1d47057b653c93c246f6571 100644 --- a/crates/gpui2/src/color.rs +++ b/crates/gpui2/src/color.rs @@ -160,6 +160,15 @@ pub fn black() -> Hsla { } } +pub fn white() -> Hsla { + Hsla { + h: 0., + s: 0., + l: 1., + a: 1., + } +} + impl From for Hsla { fn from(color: Rgba) -> Self { let r = color.r; diff --git a/crates/gpui3/Cargo.toml b/crates/gpui3/Cargo.toml index 9960e222c4071e715855b943155252a09d84cd73..855ce49d9d00f1b24e160aa637693a8b3c233a6e 100644 --- a/crates/gpui3/Cargo.toml +++ b/crates/gpui3/Cargo.toml @@ -55,7 +55,6 @@ usvg = { version = "0.14", features = [] } uuid = { version = "1.1.2", features = ["v4"] } waker-fn = "1.1.0" slotmap = "1.0.6" -bytemuck = { version = "1.14.0", features = ["derive"] } schemars.workspace = true plane-split = "0.18.0" bitflags = "2.4.0" diff --git a/crates/gpui3/build.rs b/crates/gpui3/build.rs index af63512b8a2b6c8d619291796243b45ee0f57894..60849484268b93204d95db695cb41a2eb3c32403 100644 --- a/crates/gpui3/build.rs +++ b/crates/gpui3/build.rs @@ -45,9 +45,14 @@ fn generate_shader_bindings() -> PathBuf { "Pixels".into(), "PointF".into(), "Hsla".into(), - "Quad".into(), + "ScaledContentMask".into(), + "Uniforms".into(), + "AtlasTile".into(), "QuadInputIndex".into(), - "QuadUniforms".into(), + "Quad".into(), + "SpriteInputIndex".into(), + "MonochromeSprite".into(), + "PolychromeSprite".into(), ]); config.no_includes = true; config.enumeration.prefix_with_name = true; @@ -55,11 +60,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 } diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index 124cc55c3c0cf71772669e32412f80bc94d525cc..8fbccaa83828ada97ae45060dc3eb4a8d8b7ea3b 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -8,9 +8,9 @@ pub use model_context::*; use refineable::Refineable; use crate::{ - current_platform, run_on_main, spawn_on_main, Context, LayoutId, MainThread, MainThreadOnly, - Platform, PlatformDispatcher, RootView, TextStyle, TextStyleRefinement, TextSystem, Window, - WindowContext, WindowHandle, WindowId, + current_platform, image_cache::ImageCache, run_on_main, spawn_on_main, AssetSource, Context, + LayoutId, MainThread, MainThreadOnly, Platform, PlatformDispatcher, RootView, SvgRenderer, + TextStyle, TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; use collections::{HashMap, VecDeque}; @@ -23,22 +23,33 @@ use std::{ mem, sync::{Arc, Weak}, }; -use util::ResultExt; +use util::{ + http::{self, HttpClient}, + ResultExt, +}; #[derive(Clone)] pub struct App(Arc>>); impl App { - pub fn production() -> Self { - Self::new(current_platform()) + pub fn production(asset_source: Arc) -> Self { + let http_client = http::client(); + Self::new(current_platform(), asset_source, http_client) } #[cfg(any(test, feature = "test"))] pub fn test() -> Self { - Self::new(Arc::new(super::TestPlatform::new())) + let platform = Arc::new(super::TestPlatform::new()); + let asset_source = Arc::new(()); + let http_client = util::http::FakeHttpClient::with_404_response(); + Self::new(platform, asset_source, http_client) } - fn new(platform: Arc) -> Self { + fn new( + platform: Arc, + asset_source: Arc, + http_client: Arc, + ) -> Self { let dispatcher = platform.dispatcher(); let text_system = Arc::new(TextSystem::new(platform.text_system())); let entities = EntityMap::new(); @@ -49,6 +60,8 @@ impl App { platform: MainThreadOnly::new(platform, dispatcher.clone()), dispatcher, text_system, + svg_renderer: SvgRenderer::new(asset_source), + image_cache: ImageCache::new(http_client), pending_updates: 0, text_style_stack: Vec::new(), state_stacks_by_type: HashMap::default(), @@ -83,6 +96,8 @@ pub struct AppContext { dispatcher: Arc, text_system: Arc, pending_updates: usize, + pub(crate) svg_renderer: SvgRenderer, + pub(crate) image_cache: ImageCache, pub(crate) text_style_stack: Vec, pub(crate) state_stacks_by_type: HashMap>>, pub(crate) unit_entity: Handle<()>, diff --git a/crates/gpui3/src/app/entity_map.rs b/crates/gpui3/src/app/entity_map.rs index 4976b67aae889a116a772d78e1b7809863a73837..29db57bb39cc518b8c74bdcac13dd4c551d215f1 100644 --- a/crates/gpui3/src/app/entity_map.rs +++ b/crates/gpui3/src/app/entity_map.rs @@ -125,11 +125,12 @@ impl Clone for Handle { impl Drop for Handle { fn drop(&mut self) { - if let Some(ref_counts) = self.ref_counts.upgrade() { - if let Some(count) = ref_counts.read().get(self.id) { - let prev_count = count.fetch_sub(1, SeqCst); - assert_ne!(prev_count, 0, "Detected over-release of a handle."); - } + if let Some(_ref_counts) = self.ref_counts.upgrade() { + // todo!() + // if let Some(count) = ref_counts.read().get(self.id) { + // let prev_count = count.fetch_sub(1, SeqCst); + // assert_ne!(prev_count, 0, "Detected over-release of a handle."); + // } } } } diff --git a/crates/gpui3/src/assets.rs b/crates/gpui3/src/assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..cae5a8eaae66be567c9a51a18b19855d646f2f52 --- /dev/null +++ b/crates/gpui3/src/assets.rs @@ -0,0 +1,64 @@ +use crate::{size, DevicePixels, Result, SharedString, Size}; +use anyhow::anyhow; +use image::{Bgra, ImageBuffer}; +use std::{ + borrow::Cow, + fmt, + hash::Hash, + sync::atomic::{AtomicUsize, Ordering::SeqCst}, +}; + +pub trait AssetSource: 'static + Send + Sync { + fn load(&self, path: &SharedString) -> Result>; + fn list(&self, path: &SharedString) -> Result>; +} + +impl AssetSource for () { + fn load(&self, path: &SharedString) -> Result> { + Err(anyhow!( + "get called on empty asset provider with \"{}\"", + path + )) + } + + fn list(&self, _path: &SharedString) -> Result> { + Ok(vec![]) + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct ImageId(usize); + +pub struct ImageData { + pub id: ImageId, + data: ImageBuffer, Vec>, +} + +impl ImageData { + pub fn new(data: ImageBuffer, Vec>) -> Self { + static NEXT_ID: AtomicUsize = AtomicUsize::new(0); + + Self { + id: ImageId(NEXT_ID.fetch_add(1, SeqCst)), + data, + } + } + + pub fn as_bytes(&self) -> &[u8] { + &self.data + } + + pub fn size(&self) -> Size { + let (width, height) = self.data.dimensions(); + size(width.into(), height.into()) + } +} + +impl fmt::Debug for ImageData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ImageData") + .field("id", &self.id) + .field("size", &self.data.dimensions()) + .finish() + } +} diff --git a/crates/gpui3/src/color.rs b/crates/gpui3/src/color.rs index 052ff8a6217b4dfc670716b217961c187d999d3a..1ace030482bee912acc5aebf424d8bc10c60407c 100644 --- a/crates/gpui3/src/color.rs +++ b/crates/gpui3/src/color.rs @@ -1,6 +1,5 @@ #![allow(dead_code)] -use bytemuck::{Pod, Zeroable}; use serde::de::{self, Deserialize, Deserializer, Visitor}; use std::fmt; use std::num::ParseIntError; @@ -118,7 +117,7 @@ impl TryFrom<&'_ str> for Rgba { } } -#[derive(Default, Copy, Clone, Debug, PartialEq, Zeroable, Pod)] +#[derive(Default, Copy, Clone, Debug, PartialEq)] #[repr(C)] pub struct Hsla { pub h: f32, @@ -147,6 +146,15 @@ pub fn black() -> Hsla { } } +pub fn white() -> Hsla { + Hsla { + h: 0., + s: 0., + l: 1., + a: 1., + } +} + impl Hsla { /// Returns true if the HSLA color is fully transparent, false otherwise. pub fn is_transparent(&self) -> bool { diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 6bae65c5a26ba5b7d33f26bdc0987027b6a7c167..535ccb995306a14252565f99ebb9eb130cb11230 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -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 Element for Div { cx: &mut ViewContext, ) -> 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 Element for Div { let style = self.computed_style(); style.paint(order, bounds, cx); - let overflow = &style.overflow; + // // todo!("support only one dimension being hidden") + let overflow = &style.overflow; // if style.overflow.y != Overflow::Visible || style.overflow.x != Overflow::Visible { - // cx.scene().push_layer(Some(bounds)); - // pop_layer = true; + // cx.clip(layout.bounds, style.corner_radii, || ) // } - 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)?; - } + 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") diff --git a/crates/gpui3/src/elements/img.rs b/crates/gpui3/src/elements/img.rs index 63f3e78d3db58ff928762d788cea9120ddb21c94..1d2a7bd1d44a363bd0e186231a1a2f33b5fe71f0 100644 --- a/crates/gpui3/src/elements/img.rs +++ b/crates/gpui3/src/elements/img.rs @@ -1,11 +1,15 @@ -use crate::{Element, Layout, LayoutId, Result, Style, StyleHelpers, Styled}; +use crate::{ + Element, Layout, LayoutId, Result, SharedString, Style, StyleHelpers, Styled, ViewContext, +}; +use futures::FutureExt; use refineable::RefinementCascade; use std::marker::PhantomData; -use util::arc_cow::ArcCow; +use util::ResultExt; pub struct Img { style: RefinementCascade