From 8c8cfba093a79dc8fe801ab9d23f505fd819aac1 Mon Sep 17 00:00:00 2001 From: grovesNL Date: Thu, 26 Jan 2023 00:07:05 -0330 Subject: [PATCH] Add clipping back --- examples/hello-world.rs | 14 ++++-- src/lib.rs | 41 ++++++++++++++---- src/text_render.rs | 95 +++++++++++++++++++---------------------- 3 files changed, 87 insertions(+), 63 deletions(-) diff --git a/examples/hello-world.rs b/examples/hello-world.rs index 2bb0dc7..06ec35f 100644 --- a/examples/hello-world.rs +++ b/examples/hello-world.rs @@ -1,5 +1,5 @@ use cosmic_text::{Attrs, Buffer, Color, Family, FontSystem, Metrics, SwashCache}; -use glyphon::{Resolution, TextAtlas, TextRenderer}; +use glyphon::{Resolution, TextArea, TextAtlas, TextBounds, TextRenderer}; use wgpu::{ Backends, CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance, 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_text( - include_str!("./emoji.txt"), + include_str!("./emoji-zjw.txt"), Attrs::new().monospaced(true).family(Family::Monospace), ); buffer.shape_until_scroll(); @@ -103,7 +103,15 @@ async fn run() { width: config.width, height: config.height, }, - &buffer, + &[TextArea { + buffer: &buffer, + bounds: TextBounds { + left: 10, + top: 10, + right: 500, + bottom: 50, + }, + }], Color::rgb(255, 255, 255), &mut cache, ) diff --git a/src/lib.rs b/src/lib.rs index 60ac7c7..39959b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,3 @@ -use etagere::AllocId; - mod error; mod recently_used; mod text_atlas; @@ -12,6 +10,7 @@ use text_render::ContentType; pub use text_render::TextRenderer; pub use cosmic_text; +use etagere::AllocId; pub(crate) enum GpuCacheStatus { InAtlas { @@ -58,11 +57,35 @@ pub(crate) struct Params { _pad: [u32; 2], } -/// Controls the overflow behavior of any glyphs that are outside of the layout bounds. -pub enum TextOverflow { - /// Glyphs can overflow the bounds. - Overflow, - /// Hide any glyphs outside the bounds. If a glyph is partially outside the bounds, it will be - /// clipped to the bounds. - Hide, +/// Controls the visible area of the text. Any text outside of the visible area will be clipped. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct TextBounds { + /// The position of the left edge of the visible area. + pub left: i32, + /// The position of the top edge of the visible area. + 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, } diff --git a/src/text_render.rs b/src/text_render.rs index 14f5055..5702904 100644 --- a/src/text_render.rs +++ b/src/text_render.rs @@ -1,6 +1,6 @@ use crate::{ GlyphDetails, GlyphToRender, GpuCacheStatus, Params, PrepareError, RenderError, Resolution, - TextAtlas, TextOverflow, + TextArea, TextAtlas, }; use cosmic_text::{CacheKey, Color, SwashCache, SwashContent}; 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>( &mut self, device: &Device, queue: &Queue, atlas: &mut TextAtlas, screen_resolution: Resolution, - buffer: &cosmic_text::Buffer<'a>, + text_areas: &[TextArea<'a>], default_color: Color, cache: &mut SwashCache, ) -> Result<(), PrepareError> { @@ -97,10 +97,8 @@ impl TextRenderer { self.glyphs_in_use.clear(); - let mut buffers = [(buffer, TextOverflow::Hide)]; - - for (buffer, _) in buffers.iter_mut() { - for run in buffer.layout_runs() { + for text_area in text_areas.iter() { + for run in text_area.buffer.layout_runs() { for glyph in run.glyphs.iter() { self.glyphs_in_use.insert(glyph.cache_key); @@ -240,15 +238,10 @@ impl TextRenderer { let mut glyph_indices: Vec = Vec::new(); 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 - // the nearest pixel. - let bounds_min_x = i32::MIN; - let bounds_max_x = i32::MAX; - let bounds_min_y = i32::MIN; - let bounds_max_y = i32::MAX; - - for run in buffer.layout_runs() { + // the nearest pixel whenever necessary. + for run in text_area.buffer.layout_runs() { let line_y = run.line_y; for glyph in run.glyphs.iter() { @@ -270,49 +263,49 @@ impl TextRenderer { let mut width = details.width as i32; let mut height = details.height as i32; - match overflow { - TextOverflow::Overflow => {} - TextOverflow::Hide => { - // Starts beyond right edge or ends beyond left edge - let max_x = x + width; - if x > bounds_max_x || max_x < bounds_min_x { - continue; - } + let bounds_min_x = text_area.bounds.left.max(0); + let bounds_min_y = text_area.bounds.top.max(0); + let bounds_max_x = text_area.bounds.right.min(screen_resolution.width as i32); + let bounds_max_y = text_area.bounds.bottom.min(screen_resolution.height as i32); - // Starts beyond bottom edge or ends beyond top edge - let max_y = y + height; - if y > bounds_max_y || max_y < bounds_min_y { - continue; - } + // Starts beyond right edge or ends beyond left edge + let max_x = x + width; + if x > bounds_max_x || max_x < bounds_min_x { + continue; + } - // Clip left ege - if x < bounds_min_x { - let right_shift = bounds_min_x - x; + // Starts beyond bottom edge or ends beyond top edge + let max_y = y + height; + if y > bounds_max_y || max_y < bounds_min_y { + continue; + } - x = bounds_min_x; - width = max_x - bounds_min_x; - atlas_x += right_shift as u16; - } + // Clip left ege + if x < bounds_min_x { + let right_shift = bounds_min_x - x; - // Clip right edge - if x + width > bounds_max_x { - width = bounds_max_x - x; - } + x = bounds_min_x; + width = max_x - bounds_min_x; + atlas_x += right_shift as u16; + } - // Clip top edge - if y < bounds_min_y { - let bottom_shift = bounds_min_y - y; + // Clip right edge + if x + width > bounds_max_x { + width = bounds_max_x - x; + } - y = bounds_min_y; - height = max_y - bounds_min_y; - atlas_y += bottom_shift as u16; - } + // Clip top edge + if y < bounds_min_y { + let bottom_shift = bounds_min_y - y; - // Clip bottom edge - if y + height > bounds_max_y { - height = bounds_max_y - y; - } - } + y = bounds_min_y; + height = max_y - bounds_min_y; + atlas_y += bottom_shift as u16; + } + + // Clip bottom edge + if y + height > bounds_max_y { + height = bounds_max_y - y; } glyph_vertices.extend(