Add clipping back

This commit is contained in:
grovesNL 2023-01-26 00:07:05 -03:30 committed by Josh Groves
parent ba52cbdba6
commit 8c8cfba093
3 changed files with 87 additions and 63 deletions

View file

@ -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,
)

View file

@ -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,
}

View file

@ -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<u32> = 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(