Checkpoint

This commit is contained in:
Nathan Sobo
2023-10-03 05:57:15 -06:00
parent 6046ed4f5c
commit dcaf4c905f
13 changed files with 698 additions and 100 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ use crate::{
};
use parking_lot::Mutex;
use std::{marker::PhantomData, sync::Arc};
use util::arc_cow::ArcCow;
use util::{arc_cow::ArcCow, ResultExt};
impl<S: 'static> IntoAnyElement<S> for ArcCow<'static, str> {
fn into_any(self) -> AnyElement<S> {
+55 -4
View File
@@ -31,10 +31,10 @@ impl<T: Clone + Debug> Point<T> {
impl<T, Rhs> Mul<Rhs> for Point<T>
where
T: Mul<Rhs, Output = Rhs> + Clone + Debug,
T: Mul<Rhs, Output = T> + Clone + Debug,
Rhs: Clone + Debug,
{
type Output = Point<Rhs>;
type Output = Point<T>;
fn mul(self, rhs: Rhs) -> Self::Output {
Point {
@@ -105,7 +105,7 @@ impl<T: Clone + Debug> Clone for Point<T> {
unsafe impl<T: Clone + Debug + Zeroable + Pod> Zeroable for Point<T> {}
unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Point<T> {}
#[derive(Refineable, Default, Clone, Copy, Debug, PartialEq, Div)]
#[derive(Refineable, Default, Clone, Copy, Debug, PartialEq, Div, Hash)]
#[refineable(debug)]
#[repr(C)]
pub struct Size<T: Clone + Debug> {
@@ -129,6 +129,23 @@ impl<T: Clone + Debug> Size<T> {
}
}
impl<T: Clone + Debug + Ord> Size<T> {
pub fn max(&self, other: &Self) -> Self {
Size {
width: if self.width >= other.width {
self.width.clone()
} else {
other.width.clone()
},
height: if self.height >= other.height {
self.height.clone()
} else {
other.height.clone()
},
}
}
}
impl<T, Rhs> Mul<Rhs> for Size<T>
where
T: Mul<Rhs, Output = Rhs> + Debug + Clone,
@@ -151,6 +168,8 @@ impl<T: Clone + Debug + Mul<S, Output = T>, S: Clone> MulAssign<S> for Size<T> {
}
}
impl<T: Eq + Debug + Clone> Eq for Size<T> {}
impl From<Size<Option<Pixels>>> for Size<Option<f32>> {
fn from(val: Size<Option<Pixels>>) -> Self {
Size {
@@ -202,6 +221,7 @@ unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Bounds<T> {}
impl<T, Rhs> Mul<Rhs> for Bounds<T>
where
T: Mul<Rhs, Output = Rhs> + Clone + Debug,
Point<T>: Mul<Rhs, Output = Point<Rhs>>,
Rhs: Clone + Debug,
{
type Output = Bounds<Rhs>;
@@ -522,11 +542,30 @@ impl From<Pixels> for f64 {
}
#[derive(
Clone, Copy, Debug, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd,
Add,
AddAssign,
Clone,
Copy,
Debug,
Default,
Div,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
Sub,
SubAssign,
)]
#[repr(transparent)]
pub struct DevicePixels(pub(crate) u32);
impl DevicePixels {
pub fn to_bytes(&self, bytes_per_pixel: u8) -> u32 {
self.0 * bytes_per_pixel as u32
}
}
unsafe impl bytemuck::Pod for DevicePixels {}
unsafe impl bytemuck::Zeroable for DevicePixels {}
@@ -542,6 +581,18 @@ impl From<u32> for DevicePixels {
}
}
impl From<DevicePixels> for u64 {
fn from(device_pixels: DevicePixels) -> Self {
device_pixels.0 as u64
}
}
impl From<u64> for DevicePixels {
fn from(val: u64) -> Self {
DevicePixels(val as u32)
}
}
#[derive(Clone, Copy, Default, Add, Sub, Mul, Div)]
pub struct Rems(f32);
+1
View File
@@ -23,6 +23,7 @@ pub use elements::*;
pub use executor::*;
pub use geometry::*;
pub use gpui3_macros::*;
pub use platform::*;
pub use refineable::*;
pub use scene::*;
+12 -4
View File
@@ -6,8 +6,8 @@ mod mac;
mod test;
use crate::{
AnyWindowHandle, Bounds, Font, FontId, FontMetrics, GlyphId, LineLayout, Pixels, Point, Result,
Scene, SharedString, Size,
AnyWindowHandle, Bounds, DevicePixels, Font, FontId, FontMetrics, GlyphId, LineLayout,
MonochromeSprite, Pixels, Point, Result, Scene, SharedString, Size,
};
use anyhow::anyhow;
use async_task::Runnable;
@@ -122,7 +122,7 @@ pub trait PlatformWindow {
fn screen(&self) -> Rc<dyn PlatformScreen>;
fn mouse_position(&self) -> Point<Pixels>;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn set_input_handler(&mut self, input_handler: Box<dyn InputHandler>);
fn set_input_handler(&mut self, input_handler: Box<dyn PlatformInputHandler>);
fn prompt(
&self,
level: WindowPromptLevel,
@@ -180,7 +180,15 @@ pub trait PlatformTextSystem: Send + Sync {
) -> Vec<usize>;
}
pub trait InputHandler {
pub trait PlatformSpriteSystem<Key> {
fn get_or_insert_with(
&self,
key: Key,
build: impl FnOnce() -> (Size<DevicePixels>, Vec<u8>),
) -> MonochromeSprite;
}
pub trait PlatformInputHandler {
fn selected_text_range(&self) -> Option<Range<usize>>;
fn marked_text_range(&self) -> Option<Range<usize>>;
fn text_for_range(&self, range_utf16: Range<usize>) -> Option<String>;
+2
View File
@@ -6,6 +6,7 @@ mod metal_renderer;
mod open_type;
mod platform;
mod screen;
mod sprite;
mod text_system;
mod window;
mod window_appearence;
@@ -32,6 +33,7 @@ use std::{
pub use dispatcher::*;
pub use platform::*;
pub use screen::*;
pub use sprite::*;
pub use text_system::*;
pub use window::*;
+34 -12
View File
@@ -1,4 +1,4 @@
use crate::{point, size, DevicePixels, Quad, Scene, Size};
use crate::{point, size, DevicePixels, MonochromeSprite, Quad, Scene, Size};
use bytemuck::{Pod, Zeroable};
use cocoa::{
base::{NO, YES},
@@ -102,9 +102,7 @@ impl MetalRenderer {
&*self.layer
}
pub fn draw(&mut self, scene: &Scene) {
dbg!(scene);
pub fn draw(&mut self, scene: &mut Scene) {
let layer = self.layer.clone();
let viewport_size = layer.drawable_size();
let viewport_size: Size<DevicePixels> = size(
@@ -159,21 +157,35 @@ impl MetalRenderer {
zfar: 1.0,
});
let mut buffer_offset = 0;
let mut instance_offset = 0;
for layer in scene.layers() {
self.draw_quads(
&layer.quads,
&mut buffer_offset,
viewport_size,
command_encoder,
);
for batch in layer.batches() {
match batch {
crate::PrimitiveBatch::Quads(quads) => {
self.draw_quads(
quads,
&mut instance_offset,
viewport_size,
command_encoder,
);
}
crate::PrimitiveBatch::Sprites(sprites) => {
self.draw_monochrome_sprites(
sprites,
&mut instance_offset,
viewport_size,
command_encoder,
);
}
}
}
}
command_encoder.end_encoding();
self.instances.did_modify_range(NSRange {
location: 0,
length: buffer_offset as NSUInteger,
length: instance_offset as NSUInteger,
});
command_buffer.commit();
@@ -238,6 +250,16 @@ impl MetalRenderer {
);
*offset = next_offset;
}
fn draw_monochrome_sprites(
&mut self,
monochrome: &[MonochromeSprite],
offset: &mut usize,
viewport_size: Size<DevicePixels>,
command_encoder: &metal::RenderCommandEncoderRef,
) {
todo!()
}
}
fn build_pipeline_state(
@@ -198,3 +198,52 @@ float4 to_device_position(float2 pixel_position, float2 viewport_size) {
float2(-1., 1.),
0., 1.);
}
// struct SpriteFragmentInput {
// float4 position [[position]];
// float2 atlas_position;
// float4 color [[flat]];
// uchar compute_winding [[flat]];
// };
// vertex SpriteFragmentInput sprite_vertex(
// uint unit_vertex_id [[vertex_id]],
// uint sprite_id [[instance_id]],
// constant float2 *unit_vertices
// [[buffer(GPUISpriteVertexInputIndexVertices)]], constant GPUISprite
// *sprites [[buffer(GPUISpriteVertexInputIndexSprites)]], constant float2
// *viewport_size [[buffer(GPUISpriteVertexInputIndexViewportSize)]],
// constant float2 *atlas_size
// [[buffer(GPUISpriteVertexInputIndexAtlasSize)]]
// ) {
// float2 unit_vertex = unit_vertices[unit_vertex_id];
// GPUISprite sprite = sprites[sprite_id];
// float2 position = unit_vertex * sprite.target_size + sprite.origin;
// float4 device_position = to_device_position(position, *viewport_size);
// float2 atlas_position = (unit_vertex * sprite.source_size +
// sprite.atlas_origin) / *atlas_size;
// return SpriteFragmentInput {
// device_position,
// atlas_position,
// coloru_to_colorf(sprite.color),
// sprite.compute_winding
// };
// }
// fragment float4 sprite_fragment(
// SpriteFragmentInput input [[stage_in]],
// texture2d<float> atlas [[ texture(GPUISpriteFragmentInputIndexAtlas) ]]
// ) {
// constexpr sampler atlas_sampler(mag_filter::linear, min_filter::linear);
// float4 color = input.color;
// float4 sample = atlas.sample(atlas_sampler, input.atlas_position);
// float mask;
// if (input.compute_winding) {
// mask = 1. - abs(1. - fmod(sample.r, 2.));
// } else {
// mask = sample.a;
// }
// color.a *= mask;
// return color;
// }
+1
View File
@@ -0,0 +1 @@
+8 -9
View File
@@ -1,8 +1,8 @@
use super::{ns_string, MetalRenderer, NSRange};
use crate::{
point, px, size, AnyWindowHandle, Bounds, Event, InputHandler, KeyDownEvent, Keystroke,
MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent,
MouseUpEvent, NSRectExt, Pixels, Platform, PlatformDispatcher, PlatformScreen, PlatformWindow,
point, px, size, AnyWindowHandle, Bounds, Event, KeyDownEvent, Keystroke, MacScreen, Modifiers,
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, MouseUpEvent, NSRectExt,
Pixels, Platform, PlatformDispatcher, PlatformInputHandler, PlatformScreen, PlatformWindow,
Point, Scene, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
WindowPromptLevel,
};
@@ -292,7 +292,7 @@ struct MacWindowState {
should_close_callback: Option<Box<dyn FnMut() -> bool>>,
close_callback: Option<Box<dyn FnOnce()>>,
appearance_changed_callback: Option<Box<dyn FnMut()>>,
input_handler: Option<Box<dyn InputHandler>>,
input_handler: Option<Box<dyn PlatformInputHandler>>,
pending_key_down: Option<(KeyDownEvent, Option<InsertText>)>,
last_key_equivalent: Option<KeyDownEvent>,
synthetic_drag_counter: usize,
@@ -671,7 +671,7 @@ impl PlatformWindow for MacWindow {
self
}
fn set_input_handler(&mut self, input_handler: Box<dyn InputHandler>) {
fn set_input_handler(&mut self, input_handler: Box<dyn PlatformInputHandler>) {
self.0.as_ref().lock().input_handler = Some(input_handler);
}
@@ -1357,9 +1357,8 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
unsafe {
let window_state = get_window_state(this);
let mut window_state = window_state.as_ref().lock();
if let Some(scene) = window_state.scene_to_render.take() {
dbg!("render", &scene);
window_state.renderer.draw(&scene);
if let Some(mut scene) = window_state.scene_to_render.take() {
window_state.renderer.draw(&mut scene);
}
}
}
@@ -1580,7 +1579,7 @@ async fn synthetic_drag(
fn with_input_handler<F, R>(window: &Object, f: F) -> Option<R>
where
F: FnOnce(&mut dyn InputHandler) -> R,
F: FnOnce(&mut dyn PlatformInputHandler) -> R,
{
let window_state = unsafe { get_window_state(window) };
let mut lock = window_state.as_ref().lock();
+179 -54
View File
@@ -1,82 +1,201 @@
use std::mem;
use std::{iter::Peekable, mem};
use super::{Bounds, Hsla, Pixels, Point};
use crate::{Corners, Edges, FontId, GlyphId};
use crate::{Corners, DevicePixels, Edges};
use bytemuck::{Pod, Zeroable};
use collections::BTreeMap;
// Exported to metal
pub type PointF = Point<f32>;
pub type StackingOrder = SmallVec<[u32; 16]>;
#[derive(Debug)]
pub struct Scene {
layers: BTreeMap<u32, SceneLayer>,
pub(crate) scale_factor: f32,
}
#[derive(Default, Debug)]
pub struct SceneLayer {
pub quads: Vec<Quad>,
pub symbol: Vec<Symbol>,
scale_factor: f32,
pub(crate) layers: BTreeMap<StackingOrder, SceneLayer>,
}
impl Scene {
pub fn new(scale_factor: f32) -> Scene {
Scene {
layers: Default::default(),
scale_factor,
layers: BTreeMap::new(),
}
}
pub fn take(&mut self) -> Scene {
Scene {
layers: mem::take(&mut self.layers),
scale_factor: self.scale_factor,
layers: mem::take(&mut self.layers),
}
}
pub fn insert(&mut self, primitive: impl Into<Primitive>) {
let mut primitive = primitive.into();
primitive.scale(self.scale_factor);
let layer = self.layers.entry(primitive.order()).or_default();
pub fn insert(&mut self, order: StackingOrder, primitive: impl Into<Primitive>) {
let layer = self.layers.entry(order).or_default();
let primitive = primitive.into();
match primitive {
Primitive::Quad(quad) => layer.quads.push(quad),
Primitive::MonochromeGlyph(glyph) => layer.symbol.push(glyph),
Primitive::Quad(mut quad) => {
quad.scale(self.scale_factor);
layer.quads.push(quad);
}
Primitive::Sprite(mut sprite) => {
sprite.scale(self.scale_factor);
layer.sprites.push(sprite);
}
}
}
pub fn layers(&self) -> impl Iterator<Item = &SceneLayer> {
self.layers.values()
pub(crate) fn layers(&mut self) -> impl Iterator<Item = &mut SceneLayer> {
self.layers.values_mut()
}
}
#[derive(Debug, Default)]
pub(crate) struct SceneLayer {
pub quads: Vec<Quad>,
pub sprites: Vec<MonochromeSprite>,
}
impl SceneLayer {
pub fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> {
self.quads.sort_unstable_by(|a, b| a.order.cmp(&b.order));
self.sprites.sort_unstable_by(|a, b| a.order.cmp(&b.order));
BatchIterator::new(
&self.quads,
self.quads.iter().peekable(),
&self.sprites,
self.sprites.iter().peekable(),
)
}
}
struct BatchIterator<'a, Q, S>
where
Q: Iterator<Item = &'a Quad>,
S: Iterator<Item = &'a MonochromeSprite>,
{
next_batch_kind: Option<PrimitiveKind>,
quads: &'a [Quad],
sprites: &'a [MonochromeSprite],
quads_start: usize,
sprites_start: usize,
quads_iter: Peekable<Q>,
sprites_iter: Peekable<S>,
}
impl<'a, Q: 'a, S: 'a> Iterator for BatchIterator<'a, Q, S>
where
Q: Iterator<Item = &'a Quad>,
S: Iterator<Item = &'a MonochromeSprite>,
{
type Item = PrimitiveBatch<'a>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(batch_kind) = self.next_batch_kind.take() {
match batch_kind {
PrimitiveKind::Quad => {
let max_order = self
.next_order(Some(PrimitiveKind::Quad))
.unwrap_or(u32::MAX);
let quads_start = self.quads_start;
let quads_end = quads_start
+ self
.quads_iter
.by_ref()
.take_while(|quad| quad.order <= max_order)
.count();
self.quads_start = quads_end;
Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
}
PrimitiveKind::Sprite => {
let max_order = self
.next_order(Some(PrimitiveKind::Sprite))
.unwrap_or(u32::MAX);
let sprites_start = self.sprites_start;
let sprites_end = sprites_start
+ self
.sprites_iter
.by_ref()
.take_while(|sprite| sprite.order <= max_order)
.count();
self.sprites_start = sprites_end;
Some(PrimitiveBatch::Sprites(
&self.sprites[sprites_start..sprites_end],
))
}
}
} else {
None
}
}
}
impl<'a, Q: 'a, S: 'a> BatchIterator<'a, Q, S>
where
Q: Iterator<Item = &'a Quad>,
S: Iterator<Item = &'a MonochromeSprite>,
{
fn new(
quads: &'a [Quad],
quads_iter: Peekable<Q>,
sprites: &'a [MonochromeSprite],
sprites_iter: Peekable<S>,
) -> Self {
let mut this = Self {
quads,
quads_start: 0,
quads_iter,
sprites,
sprites_start: 0,
sprites_iter,
next_batch_kind: None,
};
this.next_order(None); // Called for its side effect of setting this.next_batch_kind
this
}
fn next_order(&mut self, exclude_kind: Option<PrimitiveKind>) -> Option<u32> {
let mut next_order = u32::MAX;
if exclude_kind != Some(PrimitiveKind::Quad) {
if let Some(next_quad) = self.quads_iter.peek() {
self.next_batch_kind = Some(PrimitiveKind::Quad);
next_order = next_quad.order;
}
}
if exclude_kind != Some(PrimitiveKind::Sprite) {
if let Some(next_sprite) = self.sprites_iter.peek() {
if next_sprite.order < next_order {
self.next_batch_kind = Some(PrimitiveKind::Sprite);
next_order = next_sprite.order;
}
}
}
(next_order < u32::MAX).then_some(next_order)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PrimitiveKind {
Quad,
Sprite,
}
#[derive(Clone, Debug)]
pub enum Primitive {
Quad(Quad),
MonochromeGlyph(Symbol),
Sprite(MonochromeSprite),
}
impl Primitive {
pub fn order(&self) -> u32 {
match self {
Primitive::Quad(quad) => quad.order,
Primitive::MonochromeGlyph(glyph) => glyph.order,
}
}
pub fn scale(&mut self, factor: f32) {
match self {
Primitive::Quad(quad) => {
quad.scale(factor);
}
Primitive::MonochromeGlyph(glyph) => {
glyph.scale(factor);
}
}
}
pub enum PrimitiveBatch<'a> {
Quads(&'a [Quad]),
Sprites(&'a [MonochromeSprite]),
}
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[derive(Debug, Copy, Clone, Zeroable, Pod)]
#[repr(C)]
pub struct Quad {
pub order: u32,
@@ -119,26 +238,32 @@ impl From<Quad> for Primitive {
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Clone, Debug)]
#[repr(C)]
pub struct Symbol {
pub struct MonochromeSprite {
pub order: u32,
pub origin: Point<Pixels>,
pub font_id: FontId,
pub font_size: Pixels,
pub id: GlyphId,
pub color: Hsla,
pub bounds: Bounds<Pixels>,
pub atlas_id: AtlasId,
pub tile_id: TileId,
pub bounds_in_atlas: Bounds<DevicePixels>,
pub color: Option<Hsla>,
}
impl Symbol {
impl MonochromeSprite {
pub fn scale(&mut self, factor: f32) {
self.font_size *= factor;
self.origin *= factor;
self.bounds *= factor;
}
}
impl From<Symbol> for Primitive {
fn from(glyph: Symbol) -> Self {
Primitive::MonochromeGlyph(glyph)
impl From<MonochromeSprite> for Primitive {
fn from(sprite: MonochromeSprite) -> Self {
Primitive::Sprite(sprite)
}
}
#[derive(Copy, Clone, Debug)]
pub struct AtlasId(pub(crate) usize);
use collections::BTreeMap;
use etagere::AllocId as TileId;
use smallvec::SmallVec;
+13 -10
View File
@@ -185,16 +185,19 @@ impl Style {
let background_color = self.fill.as_ref().and_then(Fill::color);
if background_color.is_some() || self.is_border_visible() {
cx.scene().insert(Quad {
order,
bounds,
clip_bounds: bounds, // todo!
clip_corner_radii: self.corner_radii.map(|length| length.to_pixels(rem_size)),
background: background_color.unwrap_or_default(),
border_color: self.border_color.unwrap_or_default(),
corner_radii: self.corner_radii.map(|length| length.to_pixels(rem_size)),
border_widths: self.border_widths.map(|length| length.to_pixels(rem_size)),
});
cx.scene().insert(
todo!(),
Quad {
order,
bounds,
clip_bounds: bounds, // todo!
clip_corner_radii: self.corner_radii.map(|length| length.to_pixels(rem_size)),
background: background_color.unwrap_or_default(),
border_color: self.border_color.unwrap_or_default(),
corner_radii: self.corner_radii.map(|length| length.to_pixels(rem_size)),
border_widths: self.border_widths.map(|length| length.to_pixels(rem_size)),
},
);
}
}
+333
View File
@@ -0,0 +1,333 @@
use crate::{
black, point, px, Bounds, FontId, Hsla, Layout, LineLayout, Pixels, Point, Run, RunStyle,
ShapedBoundary, UnderlineStyle, WindowContext,
};
use anyhow::Result;
use smallvec::SmallVec;
use std::sync::Arc;
#[derive(Default, Debug, Clone)]
pub struct Line {
layout: Arc<LineLayout>,
style_runs: SmallVec<[StyleRun; 32]>,
}
#[derive(Debug, Clone)]
struct StyleRun {
len: u32,
color: Hsla,
underline: UnderlineStyle,
}
impl Line {
pub fn new(layout: Arc<LineLayout>, 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<FontId> {
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<usize> {
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,
layout: &Layout,
visible_bounds: Bounds<Pixels>,
line_height: Pixels,
cx: &mut WindowContext,
) -> Result<()> {
let origin = layout.bounds.origin;
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;
let text_system = cx.text_system().clone();
for run in &self.layout.runs {
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<Pixels>, 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 {
todo!()
// 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 {
todo!()
// 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 {
todo!()
// cx.scene().insert(Symbol {
// order: layout.order,
// origin,
// font_id: run.font_id,
// font_size: self.layout.font_size,
// id: glyph.id,
// 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<Pixels>,
_visible_bounds: Bounds<Pixels>,
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<Pixels>, 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(())
}
}
+10 -6
View File
@@ -1,7 +1,7 @@
use crate::{
px, AnyView, AppContext, AvailableSpace, Bounds, Context, Effect, Element, EntityId, Handle,
LayoutId, MainThread, MainThreadOnly, Pixels, PlatformWindow, Point, Reference, Scene, Size,
StackContext, Style, TaffyLayoutEngine, WeakHandle, WindowOptions,
StackContext, StackingOrder, Style, TaffyLayoutEngine, WeakHandle, WindowOptions,
};
use anyhow::Result;
use futures::Future;
@@ -19,7 +19,7 @@ pub struct Window {
layout_engine: TaffyLayoutEngine,
pub(crate) root_view: Option<AnyView<()>>,
mouse_position: Point<Pixels>,
z_index_stack: SmallVec<[u32; 8]>,
current_stacking_order: StackingOrder,
pub(crate) scene: Scene,
pub(crate) dirty: bool,
}
@@ -58,7 +58,7 @@ impl Window {
layout_engine: TaffyLayoutEngine::new(),
root_view: None,
mouse_position,
z_index_stack: SmallVec::new(),
current_stacking_order: SmallVec::new(),
scene: Scene::new(scale_factor),
dirty: true,
}
@@ -129,13 +129,17 @@ impl<'a, 'w> WindowContext<'a, 'w> {
&mut self.window.scene
}
pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
self.window.z_index_stack.push(z_index);
pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
self.window.current_stacking_order.push(order);
let result = f(self);
self.window.z_index_stack.pop();
self.window.current_stacking_order.pop();
result
}
pub fn current_stack_order(&self) -> StackingOrder {
self.window.current_stacking_order.clone()
}
pub fn run_on_main<R>(
&self,
f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,