Do not store reference to font in shape or layout glyphs

This commit is contained in:
Jeremy Soller 2022-10-25 10:13:44 -06:00
parent 3c573df261
commit 42de42d59e
No known key found for this signature in database
GPG key ID: 87F211AF2BE4C2FE
5 changed files with 68 additions and 47 deletions

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use cosmic_text::{FontSystem, TextAction, TextBuffer, TextCursor, TextLineIndex, TextMetrics};
use cosmic_text::{FontSystem, TextAction, TextBuffer, TextMetrics};
use orbclient::{Color, EventOption, Renderer, Window, WindowFlag};
use std::{env, fs, thread, time::{Duration, Instant}};
@ -103,9 +103,6 @@ fn main() {
buffer.shape_until_cursor();
loop {
let font_size = buffer.metrics().font_size;
let line_height = buffer.metrics().line_height;
let mut force_drag = true;
if buffer.redraw {

View file

@ -117,13 +117,13 @@ impl fmt::Display for TextMetrics {
}
}
pub struct TextBufferLine<'a> {
pub struct TextBufferLine {
text: String,
shape_opt: Option<FontShapeLine<'a>>,
layout_opt: Option<Vec<FontLayoutLine<'a>>>,
shape_opt: Option<FontShapeLine>,
layout_opt: Option<Vec<FontLayoutLine>>,
}
impl<'a> TextBufferLine<'a> {
impl TextBufferLine {
pub fn new(text: String) -> Self {
Self {
text,
@ -141,7 +141,7 @@ impl<'a> TextBufferLine<'a> {
self.layout_opt = None;
}
pub fn shape(&mut self, font_matches: &'a FontMatches<'a>) -> &FontShapeLine<'a> {
pub fn shape(&mut self, font_matches: &FontMatches<'_>) -> &FontShapeLine {
if self.shape_opt.is_none() {
self.shape_opt = Some(font_matches.shape_line(&self.text));
self.layout_opt = None;
@ -149,7 +149,7 @@ impl<'a> TextBufferLine<'a> {
self.shape_opt.as_ref().unwrap()
}
pub fn layout(&mut self, font_matches: &'a FontMatches<'a>, font_size: i32, width: i32) -> &[FontLayoutLine<'a>] {
pub fn layout(&mut self, font_matches: &FontMatches<'_>, font_size: i32, width: i32) -> &[FontLayoutLine] {
if self.layout_opt.is_none() {
let mut layout = Vec::new();
let shape = self.shape(font_matches);
@ -168,7 +168,7 @@ impl<'a> TextBufferLine<'a> {
/// A buffer of text that is shaped and laid out
pub struct TextBuffer<'a> {
font_matches: &'a FontMatches<'a>,
lines: Vec<TextBufferLine<'a>>,
lines: Vec<TextBufferLine>,
metrics: TextMetrics,
width: i32,
height: i32,
@ -460,7 +460,7 @@ impl<'a> TextBuffer<'a> {
}
/// Get the lines of the original text
pub fn text_lines(&self) -> &[TextBufferLine<'a>] {
pub fn text_lines(&self) -> &[TextBufferLine] {
&self.lines
}
@ -769,13 +769,14 @@ impl<'a> TextBuffer<'a> {
self.redraw = true;
if let Some(glyph) = layout_line.glyphs.get(new_cursor_glyph) {
let font_opt = self.font_matches.get_font(&glyph.cache_key.font_id);
let text_glyph = &line.text[glyph.start..glyph.end];
log::debug!(
"{}, {}: '{}' ('{}'): '{}' ({:?})",
self.cursor.line.get(),
self.cursor.index,
glyph.font.info.family,
glyph.font.info.post_script_name,
font_opt.map_or("?", |font| font.info.family.as_str()),
font_opt.map_or("?", |font| font.info.post_script_name.as_str()),
text_glyph,
text_glyph
);
@ -974,7 +975,7 @@ impl<'a> TextBuffer<'a> {
);
}
layout_line.draw(color, |x, y, color| {
layout_line.draw(self.font_matches, color, |x, y, color| {
f(x, line_y + y, 1, 1, color);
});

View file

@ -1,38 +1,47 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use super::{CacheKey, Font};
use super::{CacheKey, FontMatches};
pub struct FontLayoutGlyph<'a> {
pub struct FontLayoutGlyph {
pub start: usize,
pub end: usize,
pub x: f32,
pub w: f32,
pub rtl: bool,
pub font: &'a Font<'a>,
pub inner: (CacheKey, i32, i32),
pub cache_key: CacheKey,
pub x_int: i32,
pub y_int: i32,
}
pub struct FontLayoutLine<'a> {
pub struct FontLayoutLine {
pub rtl: bool,
pub glyphs: Vec<FontLayoutGlyph<'a>>,
pub glyphs: Vec<FontLayoutGlyph>,
}
impl<'a> FontLayoutLine<'a> {
pub fn draw<F: FnMut(i32, i32, u32)>(&self, base: u32, mut f: F) {
impl FontLayoutLine {
pub fn draw<F: FnMut(i32, i32, u32)>(&self, matches: &FontMatches<'_>, base: u32, mut f: F) {
for glyph in self.glyphs.iter() {
use swash::scale::{Render, Source, StrikeWith};
use swash::zeno::{Format, Vector};
let mut cache = glyph.font.cache.lock().unwrap();
let font = match matches.get_font(&glyph.cache_key.font_id) {
Some(some) => some,
None => {
log::warn!("did not find font {:?}", glyph.cache_key.font_id);
continue;
},
};
let (cache_key, x_int, y_int) = glyph.inner;
let mut cache = font.cache.lock().unwrap();
let (cache_key, x_int, y_int) = (glyph.cache_key, glyph.x_int, glyph.y_int);
let image_opt = cache.entry(cache_key).or_insert_with(|| {
let mut scale_context = glyph.font.scale_context.lock().unwrap();
let mut scale_context = font.scale_context.lock().unwrap();
// Build the scaler
let mut scaler = scale_context
.builder(glyph.font.swash)
.builder(font.swash)
.size(cache_key.font_size as f32)
.hint(true)
.build();

View file

@ -57,7 +57,6 @@ impl<'a> FontMatches<'a> {
missing.push(start_word + info.cluster as usize);
}
let inner = info.glyph_id as swash::GlyphId;
glyphs.push(FontShapeGlyph {
start: start_word + info.cluster as usize,
end: end_word, // Set later
@ -65,8 +64,8 @@ impl<'a> FontMatches<'a> {
y_advance,
x_offset,
y_offset,
font,
inner,
font_id: font.info.id,
glyph_id: info.glyph_id.try_into().unwrap(),
});
}
@ -325,4 +324,13 @@ impl<'a> FontMatches<'a> {
FontShapeLine { rtl, spans }
}
pub fn get_font(&self, id: &fontdb::ID) -> Option<&Font> {
for font in self.fonts.iter() {
if &font.info.id == id {
return Some(font);
}
}
None
}
}

View file

@ -1,58 +1,64 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use super::{CacheKey, Font, FontLayoutGlyph, FontLayoutLine};
use super::{CacheKey, FontLayoutGlyph, FontLayoutLine};
pub struct FontShapeGlyph<'a> {
pub struct FontShapeGlyph {
pub start: usize,
pub end: usize,
pub x_advance: f32,
pub y_advance: f32,
pub x_offset: f32,
pub y_offset: f32,
pub font: &'a Font<'a>,
pub inner: swash::GlyphId,
pub font_id: fontdb::ID,
pub glyph_id: u16,
}
impl<'a> FontShapeGlyph<'a> {
fn layout(&self, font_size: i32, x: f32, y: f32, rtl: bool) -> FontLayoutGlyph<'a> {
impl FontShapeGlyph {
fn layout(&self, font_size: i32, x: f32, y: f32, rtl: bool) -> FontLayoutGlyph {
let x_offset = font_size as f32 * self.x_offset;
let y_offset = font_size as f32 * self.y_offset;
let x_advance = font_size as f32 * self.x_advance;
let inner = CacheKey::new(self.font.info.id, self.inner, font_size, (x + x_offset, y - y_offset));
let (cache_key, x_int, y_int) = CacheKey::new(
self.font_id,
self.glyph_id,
font_size,
(x + x_offset, y - y_offset)
);
FontLayoutGlyph {
start: self.start,
end: self.end,
x,
w: x_advance,
rtl,
font: self.font,
inner,
cache_key,
x_int,
y_int,
}
}
}
pub struct FontShapeWord<'a> {
pub struct FontShapeWord {
pub blank: bool,
pub glyphs: Vec<FontShapeGlyph<'a>>,
pub glyphs: Vec<FontShapeGlyph>,
}
pub struct FontShapeSpan<'a> {
pub struct FontShapeSpan {
pub rtl: bool,
pub words: Vec<FontShapeWord<'a>>,
pub words: Vec<FontShapeWord>,
}
pub struct FontShapeLine<'a> {
pub struct FontShapeLine {
pub rtl: bool,
pub spans: Vec<FontShapeSpan<'a>>,
pub spans: Vec<FontShapeSpan>,
}
impl<'a> FontShapeLine<'a> {
impl FontShapeLine {
pub fn layout(
&self,
font_size: i32,
line_width: i32,
layout_lines: &mut Vec<FontLayoutLine<'a>>,
layout_lines: &mut Vec<FontLayoutLine>,
mut layout_i: usize,
) {
let mut push_line = true;