Checkpoint
This commit is contained in:
@@ -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> {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
|
||||
@@ -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;
|
||||
// }
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -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
@@ -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
@@ -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)),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user