Add retained paints and shared text selection

This commit is contained in:
iris committed 2026-09-10 18:35:24 -04:00
1 parent 1e6d3b1edd
commit a33fbca966
42 files changed
+2424 -470

No files matched your search

+29 -18
View File
@@ -1,4 +1,4 @@
use crate::{Align, GlyphAtlas, GlyphKey, PlacedGlyph, RegionAlign, Textures, UiColor, util::Vec2};
use crate::{Align, GlyphAtlas, GlyphKey, PaintId, PlacedGlyph, RegionAlign, Textures, util::Vec2};
use parley::{
Alignment, AlignmentOptions, FontContext, FontFamily, FontFamilyName, FontStyle, FontWeight,
GenericFamily, Layout, LayoutContext, LineHeight, PositionedLayoutItem, StyleProperty,
@@ -32,7 +32,7 @@ pub struct FontDiagnostics {
pub struct TextData {
pub font_cx: FontContext,
pub layout_cx: LayoutContext<UiColor>,
pub layout_cx: LayoutContext<PaintId>,
scale_cx: ScaleContext,
pub atlas: GlyphAtlas,
/// Physical pixels per dp -- a second copy of
@@ -240,8 +240,13 @@ impl TextData {
}
}
pub fn place(&mut self, buffer: &TextBuffer, textures: &mut Textures) -> Vec<PlacedGlyph> {
pub fn place(
&mut self,
buffer: &TextBuffer,
textures: &mut Textures,
) -> (Vec<PlacedGlyph>, Vec<PaintId>) {
let mut placed = Vec::new();
let mut paints = Vec::new();
for line in buffer.layout.lines() {
for item in line.items() {
let PositionedLayoutItem::GlyphRun(run) = item else {
@@ -250,7 +255,10 @@ impl TextData {
let font = run.run().font();
let font_size = run.run().font_size();
let coords = run.run().normalized_coords();
let run_color = run.style().brush;
let run_color = run.style().brush.clone();
if !paints.contains(&run_color) {
paints.push(run_color.clone());
}
let Some(font_ref) = FontRef::from_index(font.data.as_ref(), font.index as usize)
else {
continue;
@@ -301,12 +309,12 @@ impl TextData {
glyph.x.floor() + entry.left as f32,
glyph.y.floor() - entry.top as f32,
),
color: run_color,
paint: run_color.slot(),
});
}
}
}
placed
(placed, paints)
}
pub fn render(
@@ -318,11 +326,12 @@ impl TextData {
density: f32,
) -> RenderedText {
buffer.shape(self, attrs, width, density);
let glyphs = self.place(buffer, textures);
let (glyphs, paints) = self.place(buffer, textures);
RenderedText {
glyphs: std::sync::Arc::new(glyphs),
paints: std::sync::Arc::new(paints),
size: buffer.size(),
color: attrs.color,
color: attrs.color.clone(),
generation: self.atlas.generation(),
}
}
@@ -359,7 +368,7 @@ impl Family {
#[derive(Clone, PartialEq)]
pub struct SpanStyle {
pub range: Range<usize>,
pub color: Option<UiColor>,
pub color: Option<PaintId>,
pub family: Option<Family>,
pub font_size: Option<f32>,
pub bold: bool,
@@ -379,7 +388,7 @@ impl SpanStyle {
underline: false,
}
}
pub fn color(mut self, color: UiColor) -> Self {
pub fn color(mut self, color: PaintId) -> Self {
self.color = Some(color);
self
}
@@ -407,7 +416,7 @@ impl SpanStyle {
#[derive(Clone, PartialEq)]
pub struct TextAttrs {
pub color: UiColor,
pub color: PaintId,
pub font_size: f32,
pub line_height: f32,
pub family: Family,
@@ -421,7 +430,7 @@ impl Default for TextAttrs {
fn default() -> Self {
let size = 16.0;
Self {
color: UiColor::WHITE,
color: PaintId::WHITE,
font_size: size,
line_height: size * LINE_HEIGHT_MULT,
family: Family::SansSerif,
@@ -436,7 +445,7 @@ impl Default for TextAttrs {
/// them apart is how they get out of step.
pub struct TextBuffer {
text: String,
layout: Layout<UiColor>,
layout: Layout<PaintId>,
spans: Vec<SpanStyle>,
shaped: Option<(TextAttrs, Option<f32>, f32)>,
}
@@ -464,7 +473,7 @@ impl TextBuffer {
&self.text
}
pub fn layout(&self) -> &Layout<UiColor> {
pub fn layout(&self) -> &Layout<PaintId> {
&self.layout
}
@@ -515,11 +524,11 @@ impl TextBuffer {
builder.push_default(StyleProperty::LineHeight(LineHeight::Absolute(
attrs.line_height * density,
)));
builder.push_default(StyleProperty::Brush(attrs.color));
builder.push_default(StyleProperty::Brush(attrs.color.clone()));
for (span, family) in self.spans.iter().zip(&span_families) {
let range = span.range.clone();
if let Some(color) = span.color {
builder.push(StyleProperty::Brush(color), range.clone());
if let Some(color) = &span.color {
builder.push(StyleProperty::Brush(color.clone()), range.clone());
}
if let Some(family) = family {
builder.push(StyleProperty::FontFamily(family.family()), range.clone());
@@ -563,8 +572,10 @@ fn hash_coords(coords: &[i16]) -> u64 {
#[derive(Clone)]
pub struct RenderedText {
pub glyphs: std::sync::Arc<Vec<PlacedGlyph>>,
/// The unique handles whose compact slots the glyphs above carry.
pub paints: std::sync::Arc<Vec<PaintId>>,
pub size: Vec2,
pub color: UiColor,
pub color: PaintId,
/// The [`GlyphAtlas::generation`] the glyphs above were placed against.
/// A holder must re-render rather than re-emit these quads once the
/// atlas has moved on (`GlyphAtlas::clear`'s doc says what happens