Checkpoint

This commit is contained in:
Nathan Sobo 2023-10-03 13:03:29 -06:00
parent 3698e89b88
commit a8c1958c75
13 changed files with 248 additions and 186 deletions

View file

@ -28,6 +28,15 @@ impl<T: Clone + Debug> Point<T> {
}
}
impl Point<Pixels> {
pub fn scale(&self, factor: f32) -> Point<ScaledPixels> {
Point {
x: self.x.scale(factor),
y: self.y.scale(factor),
}
}
}
impl<T, Rhs> Mul<Rhs> for Point<T>
where
T: Mul<Rhs, Output = T> + Clone + Debug,
@ -122,6 +131,15 @@ impl<T: Clone + Debug> Size<T> {
}
}
impl Size<Pixels> {
pub fn scale(&self, factor: f32) -> Size<ScaledPixels> {
Size {
width: self.width.scale(factor),
height: self.height.scale(factor),
}
}
}
impl<T: Clone + Debug + Ord> Size<T> {
pub fn max(&self, other: &Self) -> Self {
Size {
@ -207,7 +225,6 @@ pub struct Bounds<T: Clone + Debug> {
pub size: Size<T>,
}
// Bounds<f32> * Pixels = Bounds<Pixels>
impl<T, Rhs> Mul<Rhs> for Bounds<T>
where
T: Mul<Rhs, Output = Rhs> + Clone + Debug,
@ -277,6 +294,15 @@ impl<T: Clone + Debug + PartialOrd + Add<T, Output = T>> Bounds<T> {
}
}
impl Bounds<Pixels> {
pub fn scale(&self, factor: f32) -> Bounds<ScaledPixels> {
Bounds {
origin: self.origin.scale(factor),
size: self.size.scale(factor),
}
}
}
impl<T: Clone + Debug + Copy> Copy for Bounds<T> {}
#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
@ -462,8 +488,8 @@ impl Pixels {
Self(self.0.floor())
}
pub fn to_device_pixels(&self, scale: f32) -> DevicePixels {
DevicePixels((self.0 * scale).ceil() as u32)
pub fn scale(&self, factor: f32) -> ScaledPixels {
ScaledPixels(self.0 * factor)
}
}
@ -542,22 +568,22 @@ impl From<Pixels> for f64 {
SubAssign,
)]
#[repr(transparent)]
pub struct DevicePixels(pub(crate) u32);
pub struct DevicePixels(pub(crate) i32);
impl DevicePixels {
pub fn to_bytes(&self, bytes_per_pixel: u8) -> u32 {
self.0 * bytes_per_pixel as u32
self.0 as u32 * bytes_per_pixel as u32
}
}
impl From<DevicePixels> for u32 {
impl From<DevicePixels> for i32 {
fn from(device_pixels: DevicePixels) -> Self {
device_pixels.0
}
}
impl From<u32> for DevicePixels {
fn from(val: u32) -> Self {
impl From<i32> for DevicePixels {
fn from(val: i32) -> Self {
DevicePixels(val)
}
}
@ -570,7 +596,25 @@ impl From<DevicePixels> for u64 {
impl From<u64> for DevicePixels {
fn from(val: u64) -> Self {
DevicePixels(val as u32)
DevicePixels(val as i32)
}
}
#[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct ScaledPixels(pub(crate) f32);
impl Eq for ScaledPixels {}
impl Debug for ScaledPixels {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} px (scaled)", self.0)
}
}
impl From<ScaledPixels> for DevicePixels {
fn from(scaled: ScaledPixels) -> Self {
DevicePixels(scaled.0.ceil() as i32)
}
}

View file

@ -7,7 +7,7 @@ mod test;
use crate::{
AnyWindowHandle, Bounds, DevicePixels, Font, FontId, FontMetrics, GlyphId, Pixels, Point,
RasterizedGlyphId, Result, Scene, ShapedLine, SharedString, Size,
RasterizeGlyphParams, Result, Scene, ShapedLine, SharedString, Size,
};
use anyhow::anyhow;
use async_task::Runnable;
@ -147,7 +147,7 @@ pub trait PlatformWindow {
fn is_topmost_for_position(&self, position: Point<Pixels>) -> bool;
fn draw(&self, scene: Scene);
fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas<RasterizedGlyphId>>;
fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas<RasterizeGlyphParams>>;
}
pub trait PlatformDispatcher: Send + Sync {
@ -165,8 +165,8 @@ pub trait PlatformTextSystem: Send + Sync {
fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId>;
fn rasterize_glyph(
&self,
glyph_id: &RasterizedGlyphId,
) -> Result<(Bounds<DevicePixels>, Vec<u8>)>;
glyph_id: &RasterizeGlyphParams,
) -> Result<(Size<DevicePixels>, Vec<u8>)>;
fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, FontId)]) -> ShapedLine;
fn wrap_line(
&self,
@ -197,7 +197,7 @@ pub struct AtlasTile {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C)]
pub(crate) struct AtlasTextureId(pub(crate) u32);
pub(crate) struct AtlasTextureId(pub(crate) u32); // We use u32 instead of usize for Metal Shader Language compatibility
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]

View file

@ -28,6 +28,10 @@ impl<Key> MetalAtlas<Key> {
tiles_by_key: Default::default(),
}))
}
pub(crate) fn texture(&self, id: AtlasTextureId) -> metal::Texture {
self.0.lock().textures[id.0 as usize].metal_texture.clone()
}
}
struct MetalAtlasState<Key> {
@ -123,10 +127,10 @@ impl MetalAtlasTexture {
bounds: allocation.rectangle.into(),
};
let region = metal::MTLRegion::new_2d(
u32::from(tile.bounds.origin.x) as u64,
u32::from(tile.bounds.origin.y) as u64,
u32::from(tile.bounds.size.width) as u64,
u32::from(tile.bounds.size.height) as u64,
tile.bounds.origin.x.into(),
tile.bounds.origin.y.into(),
tile.bounds.size.width.into(),
tile.bounds.size.height.into(),
);
self.metal_texture.replace_region(
region,
@ -149,15 +153,15 @@ impl MetalAtlasTexture {
impl From<Size<DevicePixels>> for etagere::Size {
fn from(size: Size<DevicePixels>) -> Self {
etagere::Size::new(u32::from(size.width) as i32, u32::from(size.width) as i32)
etagere::Size::new(size.width.into(), size.width.into())
}
}
impl From<etagere::Point> for Point<DevicePixels> {
fn from(value: etagere::Point) -> Self {
Point {
x: DevicePixels::from(value.x as u32),
y: DevicePixels::from(value.y as u32),
x: DevicePixels::from(value.x),
y: DevicePixels::from(value.y),
}
}
}
@ -165,8 +169,8 @@ impl From<etagere::Point> for Point<DevicePixels> {
impl From<etagere::Size> for Size<DevicePixels> {
fn from(size: etagere::Size) -> Self {
Size {
width: DevicePixels::from(size.width as u32),
height: DevicePixels::from(size.height as u32),
width: DevicePixels::from(size.width),
height: DevicePixels::from(size.height),
}
}
}

View file

@ -1,6 +1,6 @@
use crate::{
point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, Quad,
RasterizedGlyphId, Scene, Size,
RasterizeGlyphParams, Scene, Size,
};
use cocoa::{
base::{NO, YES},
@ -18,10 +18,11 @@ pub struct MetalRenderer {
device: metal::Device,
layer: metal::MetalLayer,
command_queue: CommandQueue,
quad_pipeline_state: metal::RenderPipelineState,
quads_pipeline_state: metal::RenderPipelineState,
sprites_pipeline_state: metal::RenderPipelineState,
unit_vertices: metal::Buffer,
instances: metal::Buffer,
glyph_atlas: Arc<MetalAtlas<RasterizedGlyphId>>,
glyph_atlas: Arc<MetalAtlas<RasterizeGlyphParams>>,
}
impl MetalRenderer {
@ -81,15 +82,24 @@ impl MetalRenderer {
MTLResourceOptions::StorageModeManaged,
);
let quad_pipeline_state = build_pipeline_state(
let quads_pipeline_state = build_pipeline_state(
&device,
&library,
"quad",
"quads",
"quad_vertex",
"quad_fragment",
PIXEL_FORMAT,
);
let sprites_pipeline_state = build_pipeline_state(
&device,
&library,
"sprites",
"monochrome_sprite_vertex",
"monochrome_sprite_fragment",
PIXEL_FORMAT,
);
let command_queue = device.new_command_queue();
let glyph_atlas = Arc::new(MetalAtlas::new(
Size {
@ -104,7 +114,8 @@ impl MetalRenderer {
device,
layer,
command_queue,
quad_pipeline_state,
quads_pipeline_state,
sprites_pipeline_state,
unit_vertices,
instances,
glyph_atlas,
@ -115,7 +126,7 @@ impl MetalRenderer {
&*self.layer
}
pub fn glyph_atlas(&self) -> &Arc<MetalAtlas<RasterizedGlyphId>> {
pub fn glyph_atlas(&self) -> &Arc<MetalAtlas<RasterizeGlyphParams>> {
&self.glyph_atlas
}
@ -123,8 +134,8 @@ impl MetalRenderer {
let layer = self.layer.clone();
let viewport_size = layer.drawable_size();
let viewport_size: Size<DevicePixels> = size(
(viewport_size.width.ceil() as u32).into(),
(viewport_size.height.ceil() as u32).into(),
(viewport_size.width.ceil() as i32).into(),
(viewport_size.height.ceil() as i32).into(),
);
let drawable = if let Some(drawable) = layer.next_drawable() {
drawable
@ -144,8 +155,8 @@ impl MetalRenderer {
depth_texture_desc.set_pixel_format(metal::MTLPixelFormat::Depth32Float);
depth_texture_desc.set_storage_mode(metal::MTLStorageMode::Private);
depth_texture_desc.set_usage(metal::MTLTextureUsage::RenderTarget);
depth_texture_desc.set_width(u32::from(viewport_size.width) as u64);
depth_texture_desc.set_height(u32::from(viewport_size.height) as u64);
depth_texture_desc.set_width(i32::from(viewport_size.width) as u64);
depth_texture_desc.set_height(i32::from(viewport_size.height) as u64);
let depth_texture = self.device.new_texture(&depth_texture_desc);
let depth_attachment = render_pass_descriptor.depth_attachment().unwrap();
@ -168,8 +179,8 @@ impl MetalRenderer {
command_encoder.set_viewport(metal::MTLViewport {
originX: 0.0,
originY: 0.0,
width: u32::from(viewport_size.width) as f64,
height: u32::from(viewport_size.height) as f64,
width: i32::from(viewport_size.width) as f64,
height: i32::from(viewport_size.height) as f64,
znear: 0.0,
zfar: 1.0,
});
@ -226,7 +237,7 @@ impl MetalRenderer {
}
align_offset(offset);
command_encoder.set_render_pipeline_state(&self.quad_pipeline_state);
command_encoder.set_render_pipeline_state(&self.quads_pipeline_state);
command_encoder.set_vertex_buffer(
QuadInputIndex::Vertices as u64,
Some(&self.unit_vertices),
@ -273,12 +284,77 @@ impl MetalRenderer {
fn draw_monochrome_sprites(
&mut self,
texture_id: AtlasTextureId,
monochrome: &[MonochromeSprite],
sprites: &[MonochromeSprite],
offset: &mut usize,
viewport_size: Size<DevicePixels>,
command_encoder: &metal::RenderCommandEncoderRef,
) {
// todo!()
// dbg!(sprites);
if sprites.is_empty() {
return;
}
align_offset(offset);
let texture = self.glyph_atlas.texture(texture_id);
let texture_size = size(
DevicePixels(texture.width() as i32),
DevicePixels(texture.height() as i32),
);
command_encoder.set_render_pipeline_state(&self.sprites_pipeline_state);
command_encoder.set_vertex_buffer(
MonochromeSpriteInputIndex::Vertices as u64,
Some(&self.unit_vertices),
0,
);
command_encoder.set_vertex_buffer(
MonochromeSpriteInputIndex::Sprites as u64,
Some(&self.instances),
*offset as u64,
);
command_encoder.set_vertex_bytes(
MonochromeSpriteInputIndex::ViewportSize as u64,
mem::size_of_val(&viewport_size) as u64,
&viewport_size as *const Size<DevicePixels> as *const _,
);
command_encoder.set_vertex_bytes(
MonochromeSpriteInputIndex::AtlasTextureSize as u64,
mem::size_of_val(&texture_size) as u64,
&texture_size as *const Size<DevicePixels> as *const _,
);
command_encoder.set_fragment_buffer(
MonochromeSpriteInputIndex::Sprites as u64,
Some(&self.instances),
*offset as u64,
);
command_encoder.set_fragment_texture(
MonochromeSpriteInputIndex::AtlasTexture as u64,
Some(&texture),
);
let sprite_bytes_len = mem::size_of::<MonochromeSprite>() * sprites.len();
let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) };
unsafe {
ptr::copy_nonoverlapping(
sprites.as_ptr() as *const u8,
buffer_contents,
sprite_bytes_len,
);
}
let next_offset = *offset + sprite_bytes_len;
assert!(
next_offset <= INSTANCE_BUFFER_SIZE,
"instance buffer exhausted"
);
command_encoder.draw_primitives_instanced(
metal::MTLPrimitiveType::Triangle,
0,
6,
sprites.len() as u64,
);
*offset = next_offset;
}
}
@ -334,6 +410,6 @@ enum MonochromeSpriteInputIndex {
Vertices = 0,
Sprites = 1,
ViewportSize = 2,
AtlasSize = 3,
AtlasTextureSize = 3,
AtlasTexture = 4,
}

View file

@ -126,7 +126,7 @@ vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex(
constant Size_DevicePixels *viewport_size
[[buffer(MonochromeSpriteInputIndex_ViewportSize)]],
constant Size_DevicePixels *atlas_size
[[buffer(MonochromeSpriteInputIndex_AtlasSize)]]) {
[[buffer(MonochromeSpriteInputIndex_AtlasTextureSize)]]) {
float2 unit_vertex = unit_vertices[unit_vertex_id];
MonochromeSprite sprite = sprites[sprite_id];
@ -149,11 +149,13 @@ fragment float4 monochrome_sprite_fragment(
MonochromeSpriteVertexOutput input [[stage_in]],
constant MonochromeSprite *sprites
[[buffer(MonochromeSpriteInputIndex_Sprites)]],
texture2d<float> atlas
texture2d<float> atlas_texture
[[texture(MonochromeSpriteInputIndex_AtlasTexture)]]) {
MonochromeSprite sprite = sprites[input.sprite_id];
constexpr sampler atlas_sampler(mag_filter::linear, min_filter::linear);
float4 sample = atlas.sample(atlas_sampler, input.tile_position);
constexpr sampler atlas_texture_sampler(mag_filter::linear,
min_filter::linear);
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);
float4 color = input.color;
@ -256,52 +258,3 @@ float quad_sdf(float2 point, Bounds_Pixels bounds,
return distance;
}
// 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;
// }

View file

@ -1,7 +1,7 @@
use crate::{
point, px, size, Bounds, DevicePixels, Font, FontFeatures, FontId, FontMetrics, FontStyle,
FontWeight, GlyphId, Pixels, PlatformTextSystem, Point, RasterizedGlyphId, Result, ShapedGlyph,
ShapedLine, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS,
FontWeight, GlyphId, Pixels, PlatformTextSystem, Point, RasterizeGlyphParams, Result,
ShapedGlyph, ShapedLine, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS,
};
use anyhow::anyhow;
use cocoa::appkit::{CGFloat, CGPoint};
@ -136,8 +136,8 @@ impl PlatformTextSystem for MacTextSystem {
fn rasterize_glyph(
&self,
glyph_id: &RasterizedGlyphId,
) -> Result<(Bounds<DevicePixels>, Vec<u8>)> {
glyph_id: &RasterizeGlyphParams,
) -> Result<(Size<DevicePixels>, Vec<u8>)> {
self.0.read().rasterize_glyph(glyph_id)
}
@ -232,8 +232,8 @@ impl MacTextSystemState {
fn rasterize_glyph(
&self,
glyph_id: &RasterizedGlyphId,
) -> Result<(Bounds<DevicePixels>, Vec<u8>)> {
glyph_id: &RasterizeGlyphParams,
) -> Result<(Size<DevicePixels>, Vec<u8>)> {
let font = &self.fonts[glyph_id.font_id.0];
let scale = Transform2F::from_scale(glyph_id.scale_factor);
let glyph_bounds = font.raster_bounds(
@ -252,18 +252,15 @@ impl MacTextSystemState {
glyph_id.subpixel_variant.x.min(1) as i32,
glyph_id.subpixel_variant.y.min(1) as i32,
);
let cx_bounds = RectI::new(
glyph_bounds.origin(),
glyph_bounds.size() + subpixel_padding,
);
let bitmap_size = glyph_bounds.size() + subpixel_padding;
let mut bytes = vec![0; cx_bounds.width() as usize * cx_bounds.height() as usize];
let mut bytes = vec![0; bitmap_size.x() as usize * bitmap_size.y() as usize];
let cx = CGContext::create_bitmap_context(
Some(bytes.as_mut_ptr() as *mut _),
cx_bounds.width() as usize,
cx_bounds.height() as usize,
bitmap_size.x() as usize,
bitmap_size.y() as usize,
8,
cx_bounds.width() as usize,
bitmap_size.x() as usize,
&CGColorSpace::create_device_gray(),
kCGImageAlphaOnly,
);
@ -298,7 +295,7 @@ impl MacTextSystemState {
cx,
);
Ok((cx_bounds.into(), bytes))
Ok((bitmap_size.into(), bytes))
}
}
@ -511,14 +508,23 @@ impl From<RectF> for Bounds<f32> {
impl From<RectI> for Bounds<DevicePixels> {
fn from(rect: RectI) -> Self {
Bounds {
origin: point(
DevicePixels(rect.origin_x() as u32),
DevicePixels(rect.origin_y() as u32),
),
size: size(
DevicePixels(rect.width() as u32),
DevicePixels(rect.height() as u32),
),
origin: point(DevicePixels(rect.origin_x()), DevicePixels(rect.origin_y())),
size: size(DevicePixels(rect.width()), DevicePixels(rect.height())),
}
}
}
impl From<Vector2I> for Size<DevicePixels> {
fn from(value: Vector2I) -> Self {
size(value.x().into(), value.y().into())
}
}
impl From<RectI> for Bounds<i32> {
fn from(rect: RectI) -> Self {
Bounds {
origin: point(rect.origin_x(), rect.origin_y()),
size: size(rect.width(), rect.height()),
}
}
}

View file

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

View file

@ -1,7 +1,7 @@
use std::{iter::Peekable, mem};
use super::{Bounds, Hsla, Pixels, Point};
use crate::{AtlasTextureId, AtlasTile, Corners, Edges};
use crate::{AtlasTextureId, AtlasTile, Corners, Edges, ScaledPixels};
use collections::BTreeMap;
use smallvec::SmallVec;
@ -36,7 +36,6 @@ impl Scene {
let primitive = primitive.into();
match primitive {
Primitive::Quad(mut quad) => {
quad.scale(self.scale_factor);
layer.quads.push(quad);
}
Primitive::Sprite(sprite) => {
@ -187,17 +186,17 @@ pub(crate) enum PrimitiveBatch<'a> {
#[repr(C)]
pub struct Quad {
pub order: u32,
pub bounds: Bounds<Pixels>,
pub clip_bounds: Bounds<Pixels>,
pub clip_corner_radii: Corners<Pixels>,
pub bounds: Bounds<ScaledPixels>,
pub clip_bounds: Bounds<ScaledPixels>,
pub clip_corner_radii: Corners<ScaledPixels>,
pub background: Hsla,
pub border_color: Hsla,
pub corner_radii: Corners<Pixels>,
pub border_widths: Edges<Pixels>,
pub corner_radii: Corners<ScaledPixels>,
pub border_widths: Edges<ScaledPixels>,
}
impl Quad {
pub fn vertices(&self) -> impl Iterator<Item = Point<Pixels>> {
pub fn vertices(&self) -> impl Iterator<Item = Point<ScaledPixels>> {
let x1 = self.bounds.origin.x;
let y1 = self.bounds.origin.y;
let x2 = x1 + self.bounds.size.width;
@ -210,14 +209,6 @@ impl Quad {
]
.into_iter()
}
pub fn scale(&mut self, factor: f32) {
self.bounds *= factor;
self.clip_bounds *= factor;
self.clip_corner_radii *= factor;
self.corner_radii *= factor;
self.border_widths *= factor;
}
}
impl Ord for Quad {

View file

@ -182,6 +182,7 @@ impl Style {
/// 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();
let scale = cx.scale_factor();
let background_color = self.fill.as_ref().and_then(Fill::color);
if background_color.is_some() || self.is_border_visible() {
@ -190,13 +191,19 @@ impl Style {
layer_id,
Quad {
order,
bounds,
clip_bounds: bounds, // todo!
clip_corner_radii: self.corner_radii.map(|length| length.to_pixels(rem_size)),
bounds: bounds.scale(scale),
clip_bounds: bounds.scale(scale), // todo!
clip_corner_radii: self
.corner_radii
.map(|length| length.to_pixels(rem_size).scale(scale)),
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)),
corner_radii: self
.corner_radii
.map(|length| length.to_pixels(rem_size).scale(scale)),
border_widths: self
.border_widths
.map(|length| length.to_pixels(rem_size).scale(scale)),
},
);
}

View file

@ -217,8 +217,8 @@ impl TextSystem {
pub fn rasterize_glyph(
&self,
glyph_id: &RasterizedGlyphId,
) -> Result<(Bounds<DevicePixels>, Vec<u8>)> {
glyph_id: &RasterizeGlyphParams,
) -> Result<(Size<DevicePixels>, Vec<u8>)> {
self.platform_text_system.rasterize_glyph(glyph_id)
}
}
@ -380,7 +380,7 @@ pub struct ShapedGlyph {
}
#[derive(Clone, Debug, PartialEq)]
pub struct RasterizedGlyphId {
pub struct RasterizeGlyphParams {
pub(crate) font_id: FontId,
pub(crate) glyph_id: GlyphId,
pub(crate) font_size: Pixels,
@ -388,9 +388,9 @@ pub struct RasterizedGlyphId {
pub(crate) scale_factor: f32,
}
impl Eq for RasterizedGlyphId {}
impl Eq for RasterizeGlyphParams {}
impl Hash for RasterizedGlyphId {
impl Hash for RasterizeGlyphParams {
fn hash<H: Hasher>(&self, state: &mut H) {
self.font_id.0.hash(state);
self.glyph_id.0.hash(state);

View file

@ -157,35 +157,29 @@ impl Line {
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 {
if let Some((tile, bounds)) = cx
if let Some(tile) = cx
.rasterize_glyph(
run.font_id,
glyph.id,
self.layout.font_size,
cx.scale_factor(),
glyph_origin,
cx.scale_factor(),
)
.log_err()
{
let layer_id = cx.current_layer_id();
let bounds = Bounds {
origin: glyph_origin + todo!(),
size: todo!(),
};
// cx.text_system().raster_bounds()
cx.scene().insert(
layer_id,
MonochromeSprite {

View file

@ -1,9 +1,8 @@
use crate::{
px, AnyView, AppContext, AtlasTile, AvailableSpace, Bounds, Context, DevicePixels, Effect,
Element, EntityId, FontId, GlyphId, Handle, LayoutId, MainThread, MainThreadOnly,
MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, RasterizedGlyphId, Reference,
Scene, Size, StackContext, StackingOrder, Style, TaffyLayoutEngine, WeakHandle, WindowOptions,
SUBPIXEL_VARIANTS,
px, AnyView, AppContext, AtlasTile, AvailableSpace, Bounds, Context, Effect, Element, EntityId,
FontId, GlyphId, Handle, LayoutId, MainThread, MainThreadOnly, Pixels, PlatformAtlas,
PlatformWindow, Point, RasterizeGlyphParams, Reference, Scene, Size, StackContext,
StackingOrder, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
};
use anyhow::Result;
use futures::Future;
@ -16,7 +15,7 @@ pub struct AnyWindow {}
pub struct Window {
handle: AnyWindowHandle,
platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
glyph_atlas: Arc<dyn PlatformAtlas<RasterizedGlyphId>>,
glyph_atlas: Arc<dyn PlatformAtlas<RasterizeGlyphParams>>,
rem_size: Pixels,
content_size: Size<Pixels>,
layout_engine: TaffyLayoutEngine,
@ -171,39 +170,26 @@ impl<'a, 'w> WindowContext<'a, 'w> {
font_id: FontId,
glyph_id: GlyphId,
font_size: Pixels,
scale_factor: f32,
target_position: Point<Pixels>,
) -> Result<(AtlasTile, Bounds<Pixels>)> {
scale_factor: f32,
) -> Result<AtlasTile> {
let target_position = target_position * scale_factor;
let subpixel_variant = Point {
x: (target_position.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
y: (target_position.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
};
let rasterized_glyph_id = RasterizedGlyphId {
let rasterized_glyph_id = RasterizeGlyphParams {
font_id,
glyph_id,
font_size,
subpixel_variant,
scale_factor,
};
let mut offset = Default::default();
let tile = self
.window
self.window
.glyph_atlas
.get_or_insert_with(&rasterized_glyph_id, &mut || {
let (bounds, pixels) = self.text_system().rasterize_glyph(&rasterized_glyph_id)?;
offset = bounds.origin;
Ok((bounds.size, pixels))
})?;
// Align bounding box surrounding glyph to pixel grid
let mut origin = (target_position * scale_factor).map(|p| p.floor());
// Position glyph within bounding box
origin += offset.map(|o| px(u32::from(o) as f32));
let size = tile.bounds.size.map(|b| px(b.0 as f32));
let bounds = Bounds { origin, size };
Ok((tile, bounds))
self.text_system().rasterize_glyph(&rasterized_glyph_id)
})
}
pub(crate) fn draw(&mut self) -> Result<()> {

View file

@ -4,7 +4,7 @@ use crate::{
themes::rose_pine_dawn,
};
use gpui3::{
div, img, svg, view, Context, Element, ParentElement, RootView, StyleHelpers, View,
black, div, img, svg, view, Context, Element, ParentElement, RootView, StyleHelpers, View,
ViewContext, WindowContext,
};
@ -29,6 +29,7 @@ impl Workspace {
let theme = rose_pine_dawn();
div()
.font("Helvetica")
.text_color(black())
.text_base()
.size_full()
.fill(theme.middle.positive.default.background)