Add clipping back
This commit is contained in:
		
					parent
					
						
							
								ba52cbdba6
							
						
					
				
			
			
				commit
				
					
						8c8cfba093
					
				
			
		
					 3 changed files with 87 additions and 63 deletions
				
			
		| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
use cosmic_text::{Attrs, Buffer, Color, Family, FontSystem, Metrics, SwashCache};
 | 
					use cosmic_text::{Attrs, Buffer, Color, Family, FontSystem, Metrics, SwashCache};
 | 
				
			||||||
use glyphon::{Resolution, TextAtlas, TextRenderer};
 | 
					use glyphon::{Resolution, TextArea, TextAtlas, TextBounds, TextRenderer};
 | 
				
			||||||
use wgpu::{
 | 
					use wgpu::{
 | 
				
			||||||
    Backends, CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance,
 | 
					    Backends, CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance,
 | 
				
			||||||
    Limits, LoadOp, Operations, PresentMode, RenderPassColorAttachment, RenderPassDescriptor,
 | 
					    Limits, LoadOp, Operations, PresentMode, RenderPassColorAttachment, RenderPassDescriptor,
 | 
				
			||||||
| 
						 | 
					@ -74,7 +74,7 @@ async fn run() {
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    buffer.set_size((width as f64 * scale_factor) as i32, (height as f64) as i32);
 | 
					    buffer.set_size((width as f64 * scale_factor) as i32, (height as f64) as i32);
 | 
				
			||||||
    buffer.set_text(
 | 
					    buffer.set_text(
 | 
				
			||||||
        include_str!("./emoji.txt"),
 | 
					        include_str!("./emoji-zjw.txt"),
 | 
				
			||||||
        Attrs::new().monospaced(true).family(Family::Monospace),
 | 
					        Attrs::new().monospaced(true).family(Family::Monospace),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    buffer.shape_until_scroll();
 | 
					    buffer.shape_until_scroll();
 | 
				
			||||||
| 
						 | 
					@ -103,7 +103,15 @@ async fn run() {
 | 
				
			||||||
                            width: config.width,
 | 
					                            width: config.width,
 | 
				
			||||||
                            height: config.height,
 | 
					                            height: config.height,
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                        &buffer,
 | 
					                        &[TextArea {
 | 
				
			||||||
 | 
					                            buffer: &buffer,
 | 
				
			||||||
 | 
					                            bounds: TextBounds {
 | 
				
			||||||
 | 
					                                left: 10,
 | 
				
			||||||
 | 
					                                top: 10,
 | 
				
			||||||
 | 
					                                right: 500,
 | 
				
			||||||
 | 
					                                bottom: 50,
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
                        Color::rgb(255, 255, 255),
 | 
					                        Color::rgb(255, 255, 255),
 | 
				
			||||||
                        &mut cache,
 | 
					                        &mut cache,
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										41
									
								
								src/lib.rs
									
										
									
									
									
								
							
							
						
						
									
										41
									
								
								src/lib.rs
									
										
									
									
									
								
							| 
						 | 
					@ -1,5 +1,3 @@
 | 
				
			||||||
use etagere::AllocId;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod error;
 | 
					mod error;
 | 
				
			||||||
mod recently_used;
 | 
					mod recently_used;
 | 
				
			||||||
mod text_atlas;
 | 
					mod text_atlas;
 | 
				
			||||||
| 
						 | 
					@ -12,6 +10,7 @@ use text_render::ContentType;
 | 
				
			||||||
pub use text_render::TextRenderer;
 | 
					pub use text_render::TextRenderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use cosmic_text;
 | 
					pub use cosmic_text;
 | 
				
			||||||
 | 
					use etagere::AllocId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) enum GpuCacheStatus {
 | 
					pub(crate) enum GpuCacheStatus {
 | 
				
			||||||
    InAtlas {
 | 
					    InAtlas {
 | 
				
			||||||
| 
						 | 
					@ -58,11 +57,35 @@ pub(crate) struct Params {
 | 
				
			||||||
    _pad: [u32; 2],
 | 
					    _pad: [u32; 2],
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Controls the overflow behavior of any glyphs that are outside of the layout bounds.
 | 
					/// Controls the visible area of the text. Any text outside of the visible area will be clipped.
 | 
				
			||||||
pub enum TextOverflow {
 | 
					#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 | 
				
			||||||
    /// Glyphs can overflow the bounds.
 | 
					pub struct TextBounds {
 | 
				
			||||||
    Overflow,
 | 
					    /// The position of the left edge of the visible area.
 | 
				
			||||||
    /// Hide any glyphs outside the bounds. If a glyph is partially outside the bounds, it will be
 | 
					    pub left: i32,
 | 
				
			||||||
    /// clipped to the bounds.
 | 
					    /// The position of the top edge of the visible area.
 | 
				
			||||||
    Hide,
 | 
					    pub top: i32,
 | 
				
			||||||
 | 
					    /// The position of the right edge of the visible area.
 | 
				
			||||||
 | 
					    pub right: i32,
 | 
				
			||||||
 | 
					    /// The position of the bottom edge of the visible area.
 | 
				
			||||||
 | 
					    pub bottom: i32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The default visible area doesn't clip any text.
 | 
				
			||||||
 | 
					impl Default for TextBounds {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            left: i32::MIN,
 | 
				
			||||||
 | 
					            top: i32::MIN,
 | 
				
			||||||
 | 
					            right: i32::MAX,
 | 
				
			||||||
 | 
					            bottom: i32::MAX,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A text area containing text to be rendered along with its overflow behavior.
 | 
				
			||||||
 | 
					pub struct TextArea<'a> {
 | 
				
			||||||
 | 
					    /// The buffer containing the text to be rendered.
 | 
				
			||||||
 | 
					    pub buffer: &'a cosmic_text::Buffer<'a>,
 | 
				
			||||||
 | 
					    /// The bounds of the text area.
 | 
				
			||||||
 | 
					    pub bounds: TextBounds,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    GlyphDetails, GlyphToRender, GpuCacheStatus, Params, PrepareError, RenderError, Resolution,
 | 
					    GlyphDetails, GlyphToRender, GpuCacheStatus, Params, PrepareError, RenderError, Resolution,
 | 
				
			||||||
    TextAtlas, TextOverflow,
 | 
					    TextArea, TextAtlas,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use cosmic_text::{CacheKey, Color, SwashCache, SwashContent};
 | 
					use cosmic_text::{CacheKey, Color, SwashCache, SwashContent};
 | 
				
			||||||
use std::{collections::HashSet, iter, mem::size_of, num::NonZeroU32, slice};
 | 
					use std::{collections::HashSet, iter, mem::size_of, num::NonZeroU32, slice};
 | 
				
			||||||
| 
						 | 
					@ -53,14 +53,14 @@ impl TextRenderer {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Prepares all of the provided layouts for rendering.
 | 
					    /// Prepares all of the provided text areas for rendering.
 | 
				
			||||||
    pub fn prepare<'a>(
 | 
					    pub fn prepare<'a>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        device: &Device,
 | 
					        device: &Device,
 | 
				
			||||||
        queue: &Queue,
 | 
					        queue: &Queue,
 | 
				
			||||||
        atlas: &mut TextAtlas,
 | 
					        atlas: &mut TextAtlas,
 | 
				
			||||||
        screen_resolution: Resolution,
 | 
					        screen_resolution: Resolution,
 | 
				
			||||||
        buffer: &cosmic_text::Buffer<'a>,
 | 
					        text_areas: &[TextArea<'a>],
 | 
				
			||||||
        default_color: Color,
 | 
					        default_color: Color,
 | 
				
			||||||
        cache: &mut SwashCache,
 | 
					        cache: &mut SwashCache,
 | 
				
			||||||
    ) -> Result<(), PrepareError> {
 | 
					    ) -> Result<(), PrepareError> {
 | 
				
			||||||
| 
						 | 
					@ -97,10 +97,8 @@ impl TextRenderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.glyphs_in_use.clear();
 | 
					        self.glyphs_in_use.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut buffers = [(buffer, TextOverflow::Hide)];
 | 
					        for text_area in text_areas.iter() {
 | 
				
			||||||
 | 
					            for run in text_area.buffer.layout_runs() {
 | 
				
			||||||
        for (buffer, _) in buffers.iter_mut() {
 | 
					 | 
				
			||||||
            for run in buffer.layout_runs() {
 | 
					 | 
				
			||||||
                for glyph in run.glyphs.iter() {
 | 
					                for glyph in run.glyphs.iter() {
 | 
				
			||||||
                    self.glyphs_in_use.insert(glyph.cache_key);
 | 
					                    self.glyphs_in_use.insert(glyph.cache_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -240,15 +238,10 @@ impl TextRenderer {
 | 
				
			||||||
        let mut glyph_indices: Vec<u32> = Vec::new();
 | 
					        let mut glyph_indices: Vec<u32> = Vec::new();
 | 
				
			||||||
        let mut glyphs_added = 0;
 | 
					        let mut glyphs_added = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (buffer, overflow) in buffers.iter() {
 | 
					        for text_area in text_areas.iter() {
 | 
				
			||||||
            // Note: subpixel positioning is not currently handled, so we always truncate down to
 | 
					            // Note: subpixel positioning is not currently handled, so we always truncate down to
 | 
				
			||||||
            // the nearest pixel.
 | 
					            // the nearest pixel whenever necessary.
 | 
				
			||||||
            let bounds_min_x = i32::MIN;
 | 
					            for run in text_area.buffer.layout_runs() {
 | 
				
			||||||
            let bounds_max_x = i32::MAX;
 | 
					 | 
				
			||||||
            let bounds_min_y = i32::MIN;
 | 
					 | 
				
			||||||
            let bounds_max_y = i32::MAX;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for run in buffer.layout_runs() {
 | 
					 | 
				
			||||||
                let line_y = run.line_y;
 | 
					                let line_y = run.line_y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                for glyph in run.glyphs.iter() {
 | 
					                for glyph in run.glyphs.iter() {
 | 
				
			||||||
| 
						 | 
					@ -270,49 +263,49 @@ impl TextRenderer {
 | 
				
			||||||
                    let mut width = details.width as i32;
 | 
					                    let mut width = details.width as i32;
 | 
				
			||||||
                    let mut height = details.height as i32;
 | 
					                    let mut height = details.height as i32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    match overflow {
 | 
					                    let bounds_min_x = text_area.bounds.left.max(0);
 | 
				
			||||||
                        TextOverflow::Overflow => {}
 | 
					                    let bounds_min_y = text_area.bounds.top.max(0);
 | 
				
			||||||
                        TextOverflow::Hide => {
 | 
					                    let bounds_max_x = text_area.bounds.right.min(screen_resolution.width as i32);
 | 
				
			||||||
                            // Starts beyond right edge or ends beyond left edge
 | 
					                    let bounds_max_y = text_area.bounds.bottom.min(screen_resolution.height as i32);
 | 
				
			||||||
                            let max_x = x + width;
 | 
					 | 
				
			||||||
                            if x > bounds_max_x || max_x < bounds_min_x {
 | 
					 | 
				
			||||||
                                continue;
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            // Starts beyond bottom edge or ends beyond top edge
 | 
					                    // Starts beyond right edge or ends beyond left edge
 | 
				
			||||||
                            let max_y = y + height;
 | 
					                    let max_x = x + width;
 | 
				
			||||||
                            if y > bounds_max_y || max_y < bounds_min_y {
 | 
					                    if x > bounds_max_x || max_x < bounds_min_x {
 | 
				
			||||||
                                continue;
 | 
					                        continue;
 | 
				
			||||||
                            }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            // Clip left ege
 | 
					                    // Starts beyond bottom edge or ends beyond top edge
 | 
				
			||||||
                            if x < bounds_min_x {
 | 
					                    let max_y = y + height;
 | 
				
			||||||
                                let right_shift = bounds_min_x - x;
 | 
					                    if y > bounds_max_y || max_y < bounds_min_y {
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                x = bounds_min_x;
 | 
					                    // Clip left ege
 | 
				
			||||||
                                width = max_x - bounds_min_x;
 | 
					                    if x < bounds_min_x {
 | 
				
			||||||
                                atlas_x += right_shift as u16;
 | 
					                        let right_shift = bounds_min_x - x;
 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            // Clip right edge
 | 
					                        x = bounds_min_x;
 | 
				
			||||||
                            if x + width > bounds_max_x {
 | 
					                        width = max_x - bounds_min_x;
 | 
				
			||||||
                                width = bounds_max_x - x;
 | 
					                        atlas_x += right_shift as u16;
 | 
				
			||||||
                            }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            // Clip top edge
 | 
					                    // Clip right edge
 | 
				
			||||||
                            if y < bounds_min_y {
 | 
					                    if x + width > bounds_max_x {
 | 
				
			||||||
                                let bottom_shift = bounds_min_y - y;
 | 
					                        width = bounds_max_x - x;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                y = bounds_min_y;
 | 
					                    // Clip top edge
 | 
				
			||||||
                                height = max_y - bounds_min_y;
 | 
					                    if y < bounds_min_y {
 | 
				
			||||||
                                atlas_y += bottom_shift as u16;
 | 
					                        let bottom_shift = bounds_min_y - y;
 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            // Clip bottom edge
 | 
					                        y = bounds_min_y;
 | 
				
			||||||
                            if y + height > bounds_max_y {
 | 
					                        height = max_y - bounds_min_y;
 | 
				
			||||||
                                height = bounds_max_y - y;
 | 
					                        atlas_y += bottom_shift as u16;
 | 
				
			||||||
                            }
 | 
					                    }
 | 
				
			||||||
                        }
 | 
					
 | 
				
			||||||
 | 
					                    // Clip bottom edge
 | 
				
			||||||
 | 
					                    if y + height > bounds_max_y {
 | 
				
			||||||
 | 
					                        height = bounds_max_y - y;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    glyph_vertices.extend(
 | 
					                    glyph_vertices.extend(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue