Checkpoint

This commit is contained in:
Nathan Sobo 2023-10-03 20:19:59 -06:00
parent da211bef96
commit 1e0ff65337
7 changed files with 57 additions and 46 deletions

View file

@ -6,8 +6,8 @@ mod mac;
mod test; mod test;
use crate::{ use crate::{
AnyWindowHandle, Bounds, DevicePixels, Font, FontId, FontMetrics, GlyphId, GlyphRasterParams, AnyWindowHandle, Bounds, DevicePixels, Font, FontId, FontMetrics, GlyphId, Pixels, Point,
Pixels, Point, Result, Scene, ShapedLine, SharedString, Size, RenderGlyphParams, Result, Scene, ShapedLine, SharedString, Size,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use async_task::Runnable; use async_task::Runnable;
@ -147,7 +147,7 @@ pub trait PlatformWindow {
fn is_topmost_for_position(&self, position: Point<Pixels>) -> bool; fn is_topmost_for_position(&self, position: Point<Pixels>) -> bool;
fn draw(&self, scene: Scene); fn draw(&self, scene: Scene);
fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas<GlyphRasterParams>>; fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas>;
} }
pub trait PlatformDispatcher: Send + Sync { pub trait PlatformDispatcher: Send + Sync {
@ -163,8 +163,8 @@ pub trait PlatformTextSystem: Send + Sync {
fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>>; fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>>;
fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Size<f32>>; fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Size<f32>>;
fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId>; fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId>;
fn glyph_raster_bounds(&self, params: &GlyphRasterParams) -> Result<Bounds<DevicePixels>>; fn glyph_raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>>;
fn rasterize_glyph(&self, params: &GlyphRasterParams) -> Result<(Size<DevicePixels>, Vec<u8>)>; fn rasterize_glyph(&self, params: &RenderGlyphParams) -> Result<(Size<DevicePixels>, Vec<u8>)>;
fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, FontId)]) -> ShapedLine; fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, FontId)]) -> ShapedLine;
fn wrap_line( fn wrap_line(
&self, &self,
@ -175,10 +175,22 @@ pub trait PlatformTextSystem: Send + Sync {
) -> Vec<usize>; ) -> Vec<usize>;
} }
pub trait PlatformAtlas<Key>: Send + Sync { #[derive(PartialEq, Eq, Hash, Clone)]
pub enum AtlasKey {
Glyph(RenderGlyphParams),
// Svg(RenderSvgParams),
}
impl From<RenderGlyphParams> for AtlasKey {
fn from(params: RenderGlyphParams) -> Self {
Self::Glyph(params)
}
}
pub trait PlatformAtlas: Send + Sync {
fn get_or_insert_with( fn get_or_insert_with(
&self, &self,
key: &Key, key: &AtlasKey,
build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Vec<u8>)>, build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Vec<u8>)>,
) -> Result<AtlasTile>; ) -> Result<AtlasTile>;

View file

@ -1,4 +1,6 @@
use crate::{AtlasTextureId, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size}; use crate::{
AtlasKey, AtlasTextureId, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size,
};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use collections::HashMap; use collections::HashMap;
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
@ -7,11 +9,10 @@ use foreign_types::ForeignType;
use metal::{Device, TextureDescriptor}; use metal::{Device, TextureDescriptor};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, sel, sel_impl};
use parking_lot::Mutex; use parking_lot::Mutex;
use std::hash::Hash;
pub struct MetalAtlas<Key>(Mutex<MetalAtlasState<Key>>); pub struct MetalAtlas(Mutex<MetalAtlasState>);
impl<Key> MetalAtlas<Key> { impl MetalAtlas {
pub fn new( pub fn new(
size: Size<DevicePixels>, size: Size<DevicePixels>,
pixel_format: metal::MTLPixelFormat, pixel_format: metal::MTLPixelFormat,
@ -34,20 +35,17 @@ impl<Key> MetalAtlas<Key> {
} }
} }
struct MetalAtlasState<Key> { struct MetalAtlasState {
device: AssertSend<Device>, device: AssertSend<Device>,
texture_descriptor: AssertSend<TextureDescriptor>, texture_descriptor: AssertSend<TextureDescriptor>,
textures: Vec<MetalAtlasTexture>, textures: Vec<MetalAtlasTexture>,
tiles_by_key: HashMap<Key, AtlasTile>, tiles_by_key: HashMap<AtlasKey, AtlasTile>,
} }
impl<Key> PlatformAtlas<Key> for MetalAtlas<Key> impl PlatformAtlas for MetalAtlas {
where
Key: Clone + Eq + Hash + Send,
{
fn get_or_insert_with( fn get_or_insert_with(
&self, &self,
key: &Key, key: &AtlasKey,
build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Vec<u8>)>, build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Vec<u8>)>,
) -> Result<AtlasTile> { ) -> Result<AtlasTile> {
let mut lock = self.0.lock(); let mut lock = self.0.lock();
@ -75,7 +73,7 @@ where
} }
} }
impl<Key> MetalAtlasState<Key> { impl MetalAtlasState {
fn push_texture(&mut self, min_size: Size<DevicePixels>) -> &mut MetalAtlasTexture { fn push_texture(&mut self, min_size: Size<DevicePixels>) -> &mut MetalAtlasTexture {
let default_atlas_size = Size { let default_atlas_size = Size {
width: self.texture_descriptor.width().into(), width: self.texture_descriptor.width().into(),

View file

@ -1,6 +1,5 @@
use crate::{ use crate::{
point, size, AtlasTextureId, DevicePixels, GlyphRasterParams, MetalAtlas, MonochromeSprite, point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, Quad, Scene, Size,
Quad, Scene, Size,
}; };
use cocoa::{ use cocoa::{
base::{NO, YES}, base::{NO, YES},
@ -21,7 +20,7 @@ pub struct MetalRenderer {
sprites_pipeline_state: metal::RenderPipelineState, sprites_pipeline_state: metal::RenderPipelineState,
unit_vertices: metal::Buffer, unit_vertices: metal::Buffer,
instances: metal::Buffer, instances: metal::Buffer,
glyph_atlas: Arc<MetalAtlas<GlyphRasterParams>>, glyph_atlas: Arc<MetalAtlas>,
} }
impl MetalRenderer { impl MetalRenderer {
@ -124,7 +123,7 @@ impl MetalRenderer {
&*self.layer &*self.layer
} }
pub fn glyph_atlas(&self) -> &Arc<MetalAtlas<GlyphRasterParams>> { pub fn glyph_atlas(&self) -> &Arc<MetalAtlas> {
&self.glyph_atlas &self.glyph_atlas
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
point, px, size, Bounds, DevicePixels, Font, FontFeatures, FontId, FontMetrics, FontStyle, point, px, size, Bounds, DevicePixels, Font, FontFeatures, FontId, FontMetrics, FontStyle,
FontWeight, GlyphId, GlyphRasterParams, Pixels, PlatformTextSystem, Point, Result, ShapedGlyph, FontWeight, GlyphId, Pixels, PlatformTextSystem, Point, RenderGlyphParams, Result, ShapedGlyph,
ShapedLine, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS, ShapedLine, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS,
}; };
use anyhow::anyhow; use anyhow::anyhow;
@ -134,13 +134,13 @@ impl PlatformTextSystem for MacTextSystem {
self.0.read().glyph_for_char(font_id, ch) self.0.read().glyph_for_char(font_id, ch)
} }
fn glyph_raster_bounds(&self, params: &GlyphRasterParams) -> Result<Bounds<DevicePixels>> { fn glyph_raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
self.0.read().raster_bounds(params) self.0.read().raster_bounds(params)
} }
fn rasterize_glyph( fn rasterize_glyph(
&self, &self,
glyph_id: &GlyphRasterParams, glyph_id: &RenderGlyphParams,
) -> Result<(Size<DevicePixels>, Vec<u8>)> { ) -> Result<(Size<DevicePixels>, Vec<u8>)> {
self.0.read().rasterize_glyph(glyph_id) self.0.read().rasterize_glyph(glyph_id)
} }
@ -234,7 +234,7 @@ impl MacTextSystemState {
}) })
} }
fn raster_bounds(&self, params: &GlyphRasterParams) -> Result<Bounds<DevicePixels>> { fn raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
let font = &self.fonts[params.font_id.0]; let font = &self.fonts[params.font_id.0];
let scale = Transform2F::from_scale(params.scale_factor); let scale = Transform2F::from_scale(params.scale_factor);
Ok(font Ok(font
@ -248,7 +248,7 @@ impl MacTextSystemState {
.into()) .into())
} }
fn rasterize_glyph(&self, params: &GlyphRasterParams) -> Result<(Size<DevicePixels>, Vec<u8>)> { fn rasterize_glyph(&self, params: &RenderGlyphParams) -> Result<(Size<DevicePixels>, Vec<u8>)> {
let glyph_bounds = self.raster_bounds(params)?; let glyph_bounds = self.raster_bounds(params)?;
if glyph_bounds.size.width.0 == 0 || glyph_bounds.size.height.0 == 0 { if glyph_bounds.size.width.0 == 0 || glyph_bounds.size.height.0 == 0 {
Err(anyhow!("glyph bounds are empty")) Err(anyhow!("glyph bounds are empty"))

View file

@ -1,10 +1,10 @@
use super::{ns_string, MetalRenderer, NSRange}; use super::{ns_string, MetalRenderer, NSRange};
use crate::{ use crate::{
point, px, size, AnyWindowHandle, Bounds, Event, GlyphRasterParams, KeyDownEvent, Keystroke, point, px, size, AnyWindowHandle, Bounds, Event, KeyDownEvent, Keystroke, MacScreen, Modifiers,
MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, MouseUpEvent, NSRectExt,
MouseUpEvent, NSRectExt, Pixels, Platform, PlatformAtlas, PlatformDispatcher, Pixels, Platform, PlatformAtlas, PlatformDispatcher, PlatformInputHandler, PlatformScreen,
PlatformInputHandler, PlatformScreen, PlatformWindow, Point, Scene, Size, Timer, PlatformWindow, Point, Scene, Size, Timer, WindowAppearance, WindowBounds, WindowKind,
WindowAppearance, WindowBounds, WindowKind, WindowOptions, WindowPromptLevel, WindowOptions, WindowPromptLevel,
}; };
use block::ConcreteBlock; use block::ConcreteBlock;
use cocoa::{ use cocoa::{
@ -886,7 +886,7 @@ impl PlatformWindow for MacWindow {
} }
} }
fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas<GlyphRasterParams>> { fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas> {
self.0.lock().renderer.glyph_atlas().clone() self.0.lock().renderer.glyph_atlas().clone()
} }
} }

View file

@ -215,13 +215,13 @@ impl TextSystem {
}) })
} }
pub fn raster_bounds(&self, params: &GlyphRasterParams) -> Result<Bounds<DevicePixels>> { pub fn raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
self.platform_text_system.glyph_raster_bounds(params) self.platform_text_system.glyph_raster_bounds(params)
} }
pub fn rasterize_glyph( pub fn rasterize_glyph(
&self, &self,
glyph_id: &GlyphRasterParams, glyph_id: &RenderGlyphParams,
) -> Result<(Size<DevicePixels>, Vec<u8>)> { ) -> Result<(Size<DevicePixels>, Vec<u8>)> {
self.platform_text_system.rasterize_glyph(glyph_id) self.platform_text_system.rasterize_glyph(glyph_id)
} }
@ -384,7 +384,7 @@ pub struct ShapedGlyph {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct GlyphRasterParams { pub struct RenderGlyphParams {
pub(crate) font_id: FontId, pub(crate) font_id: FontId,
pub(crate) glyph_id: GlyphId, pub(crate) glyph_id: GlyphId,
pub(crate) font_size: Pixels, pub(crate) font_size: Pixels,
@ -392,9 +392,9 @@ pub struct GlyphRasterParams {
pub(crate) scale_factor: f32, pub(crate) scale_factor: f32,
} }
impl Eq for GlyphRasterParams {} impl Eq for RenderGlyphParams {}
impl Hash for GlyphRasterParams { impl Hash for RenderGlyphParams {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.font_id.0.hash(state); self.font_id.0.hash(state);
self.glyph_id.0.hash(state); self.glyph_id.0.hash(state);

View file

@ -1,9 +1,9 @@
use crate::{ use crate::{
px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners, Effect, px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners, Effect,
Element, EntityId, FontId, GlyphId, GlyphRasterParams, Handle, Hsla, IsZero, LayerId, LayoutId, Element, EntityId, FontId, GlyphId, Handle, Hsla, IsZero, LayerId, LayoutId, MainThread,
MainThread, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, Reference,
Reference, ScaledPixels, Scene, Size, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, RenderGlyphParams, ScaledPixels, Scene, Size, Style, TaffyLayoutEngine, WeakHandle,
SUBPIXEL_VARIANTS, WindowOptions, SUBPIXEL_VARIANTS,
}; };
use anyhow::Result; use anyhow::Result;
use futures::Future; use futures::Future;
@ -16,7 +16,7 @@ pub struct AnyWindow {}
pub struct Window { pub struct Window {
handle: AnyWindowHandle, handle: AnyWindowHandle,
platform_window: MainThreadOnly<Box<dyn PlatformWindow>>, platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
glyph_atlas: Arc<dyn PlatformAtlas<GlyphRasterParams>>, glyph_atlas: Arc<dyn PlatformAtlas>,
rem_size: Pixels, rem_size: Pixels,
content_size: Size<Pixels>, content_size: Size<Pixels>,
layout_engine: TaffyLayoutEngine, layout_engine: TaffyLayoutEngine,
@ -222,7 +222,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
x: (glyph_origin.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8, x: (glyph_origin.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
y: (glyph_origin.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8, y: (glyph_origin.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
}; };
let params = GlyphRasterParams { let params = RenderGlyphParams {
font_id, font_id,
glyph_id, glyph_id,
font_size, font_size,
@ -236,7 +236,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
let tile = self let tile = self
.window .window
.glyph_atlas .glyph_atlas
.get_or_insert_with(&params, &mut || self.text_system().rasterize_glyph(&params))?; .get_or_insert_with(&params.clone().into(), &mut || {
self.text_system().rasterize_glyph(&params)
})?;
let bounds = Bounds { let bounds = Bounds {
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),