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…
Reference in a new issue