Do not store reference to font in shape or layout glyphs
This commit is contained in:
parent
3c573df261
commit
42de42d59e
5 changed files with 68 additions and 47 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// 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 orbclient::{Color, EventOption, Renderer, Window, WindowFlag};
|
||||||
use std::{env, fs, thread, time::{Duration, Instant}};
|
use std::{env, fs, thread, time::{Duration, Instant}};
|
||||||
|
|
||||||
|
|
@ -103,9 +103,6 @@ fn main() {
|
||||||
buffer.shape_until_cursor();
|
buffer.shape_until_cursor();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let font_size = buffer.metrics().font_size;
|
|
||||||
let line_height = buffer.metrics().line_height;
|
|
||||||
|
|
||||||
let mut force_drag = true;
|
let mut force_drag = true;
|
||||||
|
|
||||||
if buffer.redraw {
|
if buffer.redraw {
|
||||||
|
|
|
||||||
|
|
@ -117,13 +117,13 @@ impl fmt::Display for TextMetrics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextBufferLine<'a> {
|
pub struct TextBufferLine {
|
||||||
text: String,
|
text: String,
|
||||||
shape_opt: Option<FontShapeLine<'a>>,
|
shape_opt: Option<FontShapeLine>,
|
||||||
layout_opt: Option<Vec<FontLayoutLine<'a>>>,
|
layout_opt: Option<Vec<FontLayoutLine>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TextBufferLine<'a> {
|
impl TextBufferLine {
|
||||||
pub fn new(text: String) -> Self {
|
pub fn new(text: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
text,
|
text,
|
||||||
|
|
@ -141,7 +141,7 @@ impl<'a> TextBufferLine<'a> {
|
||||||
self.layout_opt = None;
|
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() {
|
if self.shape_opt.is_none() {
|
||||||
self.shape_opt = Some(font_matches.shape_line(&self.text));
|
self.shape_opt = Some(font_matches.shape_line(&self.text));
|
||||||
self.layout_opt = None;
|
self.layout_opt = None;
|
||||||
|
|
@ -149,7 +149,7 @@ impl<'a> TextBufferLine<'a> {
|
||||||
self.shape_opt.as_ref().unwrap()
|
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() {
|
if self.layout_opt.is_none() {
|
||||||
let mut layout = Vec::new();
|
let mut layout = Vec::new();
|
||||||
let shape = self.shape(font_matches);
|
let shape = self.shape(font_matches);
|
||||||
|
|
@ -168,7 +168,7 @@ impl<'a> TextBufferLine<'a> {
|
||||||
/// A buffer of text that is shaped and laid out
|
/// A buffer of text that is shaped and laid out
|
||||||
pub struct TextBuffer<'a> {
|
pub struct TextBuffer<'a> {
|
||||||
font_matches: &'a FontMatches<'a>,
|
font_matches: &'a FontMatches<'a>,
|
||||||
lines: Vec<TextBufferLine<'a>>,
|
lines: Vec<TextBufferLine>,
|
||||||
metrics: TextMetrics,
|
metrics: TextMetrics,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
|
|
@ -460,7 +460,7 @@ impl<'a> TextBuffer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the lines of the original text
|
/// Get the lines of the original text
|
||||||
pub fn text_lines(&self) -> &[TextBufferLine<'a>] {
|
pub fn text_lines(&self) -> &[TextBufferLine] {
|
||||||
&self.lines
|
&self.lines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -769,13 +769,14 @@ impl<'a> TextBuffer<'a> {
|
||||||
self.redraw = true;
|
self.redraw = true;
|
||||||
|
|
||||||
if let Some(glyph) = layout_line.glyphs.get(new_cursor_glyph) {
|
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];
|
let text_glyph = &line.text[glyph.start..glyph.end];
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"{}, {}: '{}' ('{}'): '{}' ({:?})",
|
"{}, {}: '{}' ('{}'): '{}' ({:?})",
|
||||||
self.cursor.line.get(),
|
self.cursor.line.get(),
|
||||||
self.cursor.index,
|
self.cursor.index,
|
||||||
glyph.font.info.family,
|
font_opt.map_or("?", |font| font.info.family.as_str()),
|
||||||
glyph.font.info.post_script_name,
|
font_opt.map_or("?", |font| font.info.post_script_name.as_str()),
|
||||||
text_glyph,
|
text_glyph,
|
||||||
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);
|
f(x, line_y + y, 1, 1, color);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,47 @@
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// 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 start: usize,
|
||||||
pub end: usize,
|
pub end: usize,
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
pub w: f32,
|
pub w: f32,
|
||||||
pub rtl: bool,
|
pub rtl: bool,
|
||||||
pub font: &'a Font<'a>,
|
pub cache_key: CacheKey,
|
||||||
pub inner: (CacheKey, i32, i32),
|
pub x_int: i32,
|
||||||
|
pub y_int: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FontLayoutLine<'a> {
|
pub struct FontLayoutLine {
|
||||||
pub rtl: bool,
|
pub rtl: bool,
|
||||||
pub glyphs: Vec<FontLayoutGlyph<'a>>,
|
pub glyphs: Vec<FontLayoutGlyph>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FontLayoutLine<'a> {
|
impl FontLayoutLine {
|
||||||
pub fn draw<F: FnMut(i32, i32, u32)>(&self, base: u32, mut f: F) {
|
pub fn draw<F: FnMut(i32, i32, u32)>(&self, matches: &FontMatches<'_>, base: u32, mut f: F) {
|
||||||
for glyph in self.glyphs.iter() {
|
for glyph in self.glyphs.iter() {
|
||||||
use swash::scale::{Render, Source, StrikeWith};
|
use swash::scale::{Render, Source, StrikeWith};
|
||||||
use swash::zeno::{Format, Vector};
|
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 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
|
// Build the scaler
|
||||||
let mut scaler = scale_context
|
let mut scaler = scale_context
|
||||||
.builder(glyph.font.swash)
|
.builder(font.swash)
|
||||||
.size(cache_key.font_size as f32)
|
.size(cache_key.font_size as f32)
|
||||||
.hint(true)
|
.hint(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ impl<'a> FontMatches<'a> {
|
||||||
missing.push(start_word + info.cluster as usize);
|
missing.push(start_word + info.cluster as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
let inner = info.glyph_id as swash::GlyphId;
|
|
||||||
glyphs.push(FontShapeGlyph {
|
glyphs.push(FontShapeGlyph {
|
||||||
start: start_word + info.cluster as usize,
|
start: start_word + info.cluster as usize,
|
||||||
end: end_word, // Set later
|
end: end_word, // Set later
|
||||||
|
|
@ -65,8 +64,8 @@ impl<'a> FontMatches<'a> {
|
||||||
y_advance,
|
y_advance,
|
||||||
x_offset,
|
x_offset,
|
||||||
y_offset,
|
y_offset,
|
||||||
font,
|
font_id: font.info.id,
|
||||||
inner,
|
glyph_id: info.glyph_id.try_into().unwrap(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,4 +324,13 @@ impl<'a> FontMatches<'a> {
|
||||||
|
|
||||||
FontShapeLine { rtl, spans }
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,64 @@
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// 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 start: usize,
|
||||||
pub end: usize,
|
pub end: usize,
|
||||||
pub x_advance: f32,
|
pub x_advance: f32,
|
||||||
pub y_advance: f32,
|
pub y_advance: f32,
|
||||||
pub x_offset: f32,
|
pub x_offset: f32,
|
||||||
pub y_offset: f32,
|
pub y_offset: f32,
|
||||||
pub font: &'a Font<'a>,
|
pub font_id: fontdb::ID,
|
||||||
pub inner: swash::GlyphId,
|
pub glyph_id: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FontShapeGlyph<'a> {
|
impl FontShapeGlyph {
|
||||||
fn layout(&self, font_size: i32, x: f32, y: f32, rtl: bool) -> FontLayoutGlyph<'a> {
|
fn layout(&self, font_size: i32, x: f32, y: f32, rtl: bool) -> FontLayoutGlyph {
|
||||||
let x_offset = font_size as f32 * self.x_offset;
|
let x_offset = font_size as f32 * self.x_offset;
|
||||||
let y_offset = font_size as f32 * self.y_offset;
|
let y_offset = font_size as f32 * self.y_offset;
|
||||||
let x_advance = font_size as f32 * self.x_advance;
|
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 {
|
FontLayoutGlyph {
|
||||||
start: self.start,
|
start: self.start,
|
||||||
end: self.end,
|
end: self.end,
|
||||||
x,
|
x,
|
||||||
w: x_advance,
|
w: x_advance,
|
||||||
rtl,
|
rtl,
|
||||||
font: self.font,
|
cache_key,
|
||||||
inner,
|
x_int,
|
||||||
|
y_int,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FontShapeWord<'a> {
|
pub struct FontShapeWord {
|
||||||
pub blank: bool,
|
pub blank: bool,
|
||||||
pub glyphs: Vec<FontShapeGlyph<'a>>,
|
pub glyphs: Vec<FontShapeGlyph>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FontShapeSpan<'a> {
|
pub struct FontShapeSpan {
|
||||||
pub rtl: bool,
|
pub rtl: bool,
|
||||||
pub words: Vec<FontShapeWord<'a>>,
|
pub words: Vec<FontShapeWord>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FontShapeLine<'a> {
|
pub struct FontShapeLine {
|
||||||
pub rtl: bool,
|
pub rtl: bool,
|
||||||
pub spans: Vec<FontShapeSpan<'a>>,
|
pub spans: Vec<FontShapeSpan>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FontShapeLine<'a> {
|
impl FontShapeLine {
|
||||||
pub fn layout(
|
pub fn layout(
|
||||||
&self,
|
&self,
|
||||||
font_size: i32,
|
font_size: i32,
|
||||||
line_width: i32,
|
line_width: i32,
|
||||||
layout_lines: &mut Vec<FontLayoutLine<'a>>,
|
layout_lines: &mut Vec<FontLayoutLine>,
|
||||||
mut layout_i: usize,
|
mut layout_i: usize,
|
||||||
) {
|
) {
|
||||||
let mut push_line = true;
|
let mut push_line = true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue