Detailed changes
@@ -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)
}
}
@@ -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)]
@@ -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),
}
}
}
@@ -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,
}
@@ -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;
-// }
@@ -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()),
}
}
}
@@ -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()
}
}
@@ -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 {
@@ -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)),
},
);
}
@@ -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);
@@ -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 {
@@ -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<()> {
@@ -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)