Improve performance of layout lines
This commit is contained in:
parent
682407d15a
commit
3227efef89
5 changed files with 85 additions and 32 deletions
|
|
@ -1,7 +1,8 @@
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use super::FontLineIndex;
|
||||||
|
|
||||||
pub struct FontLayoutGlyph<'a, T: 'a> {
|
pub struct FontLayoutGlyph<'a, T: 'a> {
|
||||||
pub line_i: usize,
|
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
pub end: usize,
|
pub end: usize,
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
|
|
@ -14,6 +15,7 @@ pub struct FontLayoutGlyph<'a, T: 'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FontLayoutLine<'a> {
|
pub struct FontLayoutLine<'a> {
|
||||||
|
pub line_i: FontLineIndex,
|
||||||
pub glyphs: Vec<FontLayoutGlyph<'a, ()>>,
|
pub glyphs: Vec<FontLayoutGlyph<'a, ()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use super::{Font, FontShapeGlyph, FontShapeLine, FontShapeSpan};
|
use super::{Font, FontLineIndex, FontShapeGlyph, FontShapeLine, FontShapeSpan};
|
||||||
|
|
||||||
pub struct FontMatches<'a> {
|
pub struct FontMatches<'a> {
|
||||||
pub fonts: Vec<&'a Font<'a>>,
|
pub fonts: Vec<&'a Font<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FontMatches<'a> {
|
impl<'a> FontMatches<'a> {
|
||||||
fn shape_span(&self, line_i: usize, line: &str, start_span: usize, end_span: usize) -> FontShapeSpan {
|
fn shape_span(&self, line: &str, start_span: usize, end_span: usize) -> FontShapeSpan {
|
||||||
let span = &line[start_span..end_span];
|
let span = &line[start_span..end_span];
|
||||||
|
|
||||||
let mut spans_by_font = Vec::with_capacity(self.fonts.len());
|
let mut spans_by_font = Vec::with_capacity(self.fonts.len());
|
||||||
|
|
@ -44,7 +44,6 @@ impl<'a> FontMatches<'a> {
|
||||||
let inner = font.rusttype.glyph(rusttype::GlyphId(info.glyph_id as u16));
|
let inner = font.rusttype.glyph(rusttype::GlyphId(info.glyph_id as u16));
|
||||||
|
|
||||||
glyphs.push(FontShapeGlyph {
|
glyphs.push(FontShapeGlyph {
|
||||||
line_i,
|
|
||||||
start: start_span + info.cluster as usize,
|
start: start_span + info.cluster as usize,
|
||||||
end: end_span, // Set later
|
end: end_span, // Set later
|
||||||
x_advance,
|
x_advance,
|
||||||
|
|
@ -114,7 +113,7 @@ impl<'a> FontMatches<'a> {
|
||||||
spans_by_font.remove(least_misses_i).1
|
spans_by_font.remove(least_misses_i).1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shape_line(&self, line_i: usize, line: &str) -> FontShapeLine {
|
pub fn shape_line(&self, line_i: FontLineIndex, line: &str) -> FontShapeLine {
|
||||||
use unicode_script::{Script, UnicodeScript};
|
use unicode_script::{Script, UnicodeScript};
|
||||||
|
|
||||||
//TODO: more special handling of characters
|
//TODO: more special handling of characters
|
||||||
|
|
@ -130,7 +129,7 @@ impl<'a> FontMatches<'a> {
|
||||||
let cur = c.script();
|
let cur = c.script();
|
||||||
if prev != cur && prev != Script::Unknown {
|
if prev != cur && prev != Script::Unknown {
|
||||||
// No combination, start new span
|
// No combination, start new span
|
||||||
spans.push(self.shape_span(line_i, line, start, i));
|
spans.push(self.shape_span(line, start, i));
|
||||||
start = i;
|
start = i;
|
||||||
prev = Script::Unknown;
|
prev = Script::Unknown;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -138,7 +137,7 @@ impl<'a> FontMatches<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spans.push(self.shape_span(line_i, line, start, line.len()));
|
spans.push(self.shape_span(line, start, line.len()));
|
||||||
|
|
||||||
let bidi = unicode_bidi::BidiInfo::new(line, None);
|
let bidi = unicode_bidi::BidiInfo::new(line, None);
|
||||||
let rtl = if bidi.paragraphs.is_empty() {
|
let rtl = if bidi.paragraphs.is_empty() {
|
||||||
|
|
@ -149,6 +148,7 @@ impl<'a> FontMatches<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
FontShapeLine {
|
FontShapeLine {
|
||||||
|
line_i,
|
||||||
rtl,
|
rtl,
|
||||||
spans,
|
spans,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,19 @@ mod shape;
|
||||||
pub use self::system::*;
|
pub use self::system::*;
|
||||||
mod system;
|
mod system;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
pub struct FontLineIndex(usize);
|
||||||
|
|
||||||
|
impl FontLineIndex {
|
||||||
|
pub fn new(index: usize) -> Self {
|
||||||
|
Self(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> usize {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Font<'a> {
|
pub struct Font<'a> {
|
||||||
data: &'a [u8],
|
data: &'a [u8],
|
||||||
pub rustybuzz: rustybuzz::Face<'a>,
|
pub rustybuzz: rustybuzz::Face<'a>,
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@
|
||||||
use ab_glyph::Font;
|
use ab_glyph::Font;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use super::{FontLayoutGlyph, FontLayoutLine};
|
use super::{FontLayoutGlyph, FontLayoutLine, FontLineIndex};
|
||||||
|
|
||||||
pub struct FontShapeGlyph<'a> {
|
pub struct FontShapeGlyph<'a> {
|
||||||
pub line_i: usize,
|
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
pub end: usize,
|
pub end: usize,
|
||||||
pub x_advance: f32,
|
pub x_advance: f32,
|
||||||
|
|
@ -26,12 +25,13 @@ pub struct FontShapeSpan<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FontShapeLine<'a> {
|
pub struct FontShapeLine<'a> {
|
||||||
|
pub line_i: FontLineIndex,
|
||||||
pub rtl: bool,
|
pub rtl: bool,
|
||||||
pub spans: Vec<FontShapeSpan<'a>>,
|
pub spans: Vec<FontShapeSpan<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FontShapeLine<'a> {
|
impl<'a> FontShapeLine<'a> {
|
||||||
pub fn layout(&self, font_size: i32, line_width: i32, lines: &mut Vec<FontLayoutLine<'a>>) {
|
pub fn layout(&self, font_size: i32, line_width: i32, layout_lines: &mut Vec<FontLayoutLine<'a>>, mut layout_i: usize) {
|
||||||
let mut push_line = true;
|
let mut push_line = true;
|
||||||
let mut glyphs = Vec::new();
|
let mut glyphs = Vec::new();
|
||||||
|
|
||||||
|
|
@ -62,7 +62,10 @@ impl<'a> FontShapeLine<'a> {
|
||||||
if x < 0.0 {
|
if x < 0.0 {
|
||||||
let mut glyphs_swap = Vec::new();
|
let mut glyphs_swap = Vec::new();
|
||||||
std::mem::swap(&mut glyphs, &mut glyphs_swap);
|
std::mem::swap(&mut glyphs, &mut glyphs_swap);
|
||||||
lines.push(FontLayoutLine { glyphs: glyphs_swap });
|
layout_lines.push(FontLayoutLine {
|
||||||
|
line_i: self.line_i,
|
||||||
|
glyphs: glyphs_swap
|
||||||
|
});
|
||||||
|
|
||||||
x = line_width as f32 - x_advance;
|
x = line_width as f32 - x_advance;
|
||||||
y = 0.0;
|
y = 0.0;
|
||||||
|
|
@ -71,8 +74,11 @@ impl<'a> FontShapeLine<'a> {
|
||||||
if x + x_advance > line_width as f32 {
|
if x + x_advance > line_width as f32 {
|
||||||
let mut glyphs_swap = Vec::new();
|
let mut glyphs_swap = Vec::new();
|
||||||
std::mem::swap(&mut glyphs, &mut glyphs_swap);
|
std::mem::swap(&mut glyphs, &mut glyphs_swap);
|
||||||
lines.push(FontLayoutLine { glyphs: glyphs_swap });
|
layout_lines.insert(layout_i, FontLayoutLine {
|
||||||
push_line = false;
|
line_i: self.line_i,
|
||||||
|
glyphs: glyphs_swap
|
||||||
|
});
|
||||||
|
layout_i += 1;
|
||||||
|
|
||||||
x = 0.0;
|
x = 0.0;
|
||||||
y = 0.0;
|
y = 0.0;
|
||||||
|
|
@ -99,7 +105,6 @@ impl<'a> FontShapeLine<'a> {
|
||||||
));
|
));
|
||||||
|
|
||||||
glyphs.push(FontLayoutGlyph {
|
glyphs.push(FontLayoutGlyph {
|
||||||
line_i: glyph.line_i,
|
|
||||||
start: glyph.start,
|
start: glyph.start,
|
||||||
end: glyph.end,
|
end: glyph.end,
|
||||||
x,
|
x,
|
||||||
|
|
@ -119,7 +124,11 @@ impl<'a> FontShapeLine<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if push_line {
|
if push_line {
|
||||||
lines.push(FontLayoutLine { glyphs });
|
layout_lines.insert(layout_i, FontLayoutLine {
|
||||||
|
line_i: self.line_i,
|
||||||
|
glyphs
|
||||||
|
});
|
||||||
|
layout_i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use text::{
|
use text::{
|
||||||
Font,
|
Font,
|
||||||
|
FontLineIndex,
|
||||||
FontSystem,
|
FontSystem,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -91,8 +92,9 @@ fn main() {
|
||||||
let mut redraw = true;
|
let mut redraw = true;
|
||||||
let mut rehit = false;
|
let mut rehit = false;
|
||||||
let mut relayout = true;
|
let mut relayout = true;
|
||||||
|
let mut relayout_lines = Vec::new();
|
||||||
let mut reshape = true;
|
let mut reshape = true;
|
||||||
let mut reshape_lines = Vec::new();
|
let mut reshape_lines = Vec::<FontLineIndex>::new();
|
||||||
let mut scroll = 0;
|
let mut scroll = 0;
|
||||||
loop {
|
loop {
|
||||||
let (mut font_size, mut line_height) = font_sizes[font_size_i];
|
let (mut font_size, mut line_height) = font_sizes[font_size_i];
|
||||||
|
|
@ -106,13 +108,14 @@ fn main() {
|
||||||
));
|
));
|
||||||
|
|
||||||
let line_x = 8 * display_scale;
|
let line_x = 8 * display_scale;
|
||||||
|
let line_width = window.width() as i32 - line_x * 2;
|
||||||
|
|
||||||
if reshape {
|
if reshape {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
|
|
||||||
shape_lines.clear();
|
shape_lines.clear();
|
||||||
for (line_i, text_line) in text_lines.iter().enumerate() {
|
for (line_i, text_line) in text_lines.iter().enumerate() {
|
||||||
shape_lines.push(font_matches.shape_line(line_i, text_line));
|
shape_lines.push(font_matches.shape_line(FontLineIndex::new(line_i), text_line));
|
||||||
}
|
}
|
||||||
|
|
||||||
reshape = false;
|
reshape = false;
|
||||||
|
|
@ -126,12 +129,11 @@ fn main() {
|
||||||
for line_i in reshape_lines.drain(..) {
|
for line_i in reshape_lines.drain(..) {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
|
|
||||||
shape_lines[line_i] = font_matches.shape_line(line_i, &text_lines[line_i]);
|
shape_lines[line_i.get()] = font_matches.shape_line(line_i, &text_lines[line_i.get()]);
|
||||||
|
relayout_lines.push(line_i);
|
||||||
relayout = true;
|
|
||||||
|
|
||||||
let duration = instant.elapsed();
|
let duration = instant.elapsed();
|
||||||
eprintln!("reshape line {}: {:?}", line_i, duration);
|
eprintln!("reshape line {}: {:?}", line_i.get(), duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
if relayout {
|
if relayout {
|
||||||
|
|
@ -139,17 +141,44 @@ fn main() {
|
||||||
|
|
||||||
layout_lines.clear();
|
layout_lines.clear();
|
||||||
for line in shape_lines.iter() {
|
for line in shape_lines.iter() {
|
||||||
let line_width = window.width() as i32 - line_x * 2;
|
let layout_i = layout_lines.len();
|
||||||
line.layout(font_size, line_width, &mut layout_lines);
|
line.layout(font_size, line_width, &mut layout_lines, layout_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
relayout = false;
|
relayout = false;
|
||||||
|
relayout_lines.clear();
|
||||||
redraw = true;
|
redraw = true;
|
||||||
|
|
||||||
let duration = instant.elapsed();
|
let duration = instant.elapsed();
|
||||||
eprintln!("relayout: {:?}", duration);
|
eprintln!("relayout: {:?}", duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for line_i in relayout_lines.drain(..) {
|
||||||
|
let instant = Instant::now();
|
||||||
|
|
||||||
|
let mut insert_opt = None;
|
||||||
|
let mut layout_i = 0;
|
||||||
|
while layout_i < layout_lines.len() {
|
||||||
|
let layout_line = &layout_lines[layout_i];
|
||||||
|
if layout_line.line_i == line_i {
|
||||||
|
if insert_opt.is_none() {
|
||||||
|
insert_opt = Some(layout_i);
|
||||||
|
}
|
||||||
|
layout_lines.remove(layout_i);
|
||||||
|
} else {
|
||||||
|
layout_i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let shape_line = &shape_lines[line_i.get()];
|
||||||
|
shape_line.layout(font_size, line_width, &mut layout_lines, insert_opt.unwrap());
|
||||||
|
|
||||||
|
redraw = true;
|
||||||
|
|
||||||
|
let duration = instant.elapsed();
|
||||||
|
eprintln!("relayout line {}: {:?}", line_i.get(), duration);
|
||||||
|
}
|
||||||
|
|
||||||
if rehit {
|
if rehit {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
|
|
||||||
|
|
@ -222,7 +251,7 @@ fn main() {
|
||||||
Color::rgba(0xFF, 0xFF, 0xFF, 0x20)
|
Color::rgba(0xFF, 0xFF, 0xFF, 0x20)
|
||||||
);
|
);
|
||||||
|
|
||||||
let text_line = &text_lines[glyph.line_i];
|
let text_line = &text_lines[line.line_i.get()];
|
||||||
eprintln!("{}, {}: '{}'", glyph.start, glyph.end, &text_line[glyph.start..glyph.end]);
|
eprintln!("{}, {}: '{}'", glyph.start, glyph.end, &text_line[glyph.start..glyph.end]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -288,18 +317,18 @@ fn main() {
|
||||||
if cursor_glyph > 0 {
|
if cursor_glyph > 0 {
|
||||||
cursor_glyph -= 1;
|
cursor_glyph -= 1;
|
||||||
let glyph = &line.glyphs[cursor_glyph];
|
let glyph = &line.glyphs[cursor_glyph];
|
||||||
let text_line = &mut text_lines[glyph.line_i];
|
let text_line = &mut text_lines[line.line_i.get()];
|
||||||
text_line.remove(glyph.start);
|
text_line.remove(glyph.start);
|
||||||
reshape_lines.push(glyph.line_i);
|
reshape_lines.push(line.line_i);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
orbclient::K_DEL => {
|
orbclient::K_DEL => {
|
||||||
let line = &layout_lines[cursor_line];
|
let line = &layout_lines[cursor_line];
|
||||||
if cursor_glyph < line.glyphs.len() {
|
if cursor_glyph < line.glyphs.len() {
|
||||||
let glyph = &line.glyphs[cursor_glyph];
|
let glyph = &line.glyphs[cursor_glyph];
|
||||||
let text_line = &mut text_lines[glyph.line_i];
|
let text_line = &mut text_lines[line.line_i.get()];
|
||||||
text_line.remove(glyph.start);
|
text_line.remove(glyph.start);
|
||||||
reshape_lines.push(glyph.line_i);
|
reshape_lines.push(line.line_i);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
orbclient::K_0 => {
|
orbclient::K_0 => {
|
||||||
|
|
@ -322,19 +351,19 @@ fn main() {
|
||||||
if cursor_glyph >= line.glyphs.len() {
|
if cursor_glyph >= line.glyphs.len() {
|
||||||
match line.glyphs.last() {
|
match line.glyphs.last() {
|
||||||
Some(glyph) => {
|
Some(glyph) => {
|
||||||
let text_line = &mut text_lines[glyph.line_i];
|
let text_line = &mut text_lines[line.line_i.get()];
|
||||||
text_line.insert(glyph.end, event.character);
|
text_line.insert(glyph.end, event.character);
|
||||||
cursor_glyph += 1;
|
cursor_glyph += 1;
|
||||||
reshape_lines.push(glyph.line_i);
|
reshape_lines.push(line.line_i);
|
||||||
},
|
},
|
||||||
None => () // TODO
|
None => () // TODO
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let glyph = &line.glyphs[cursor_glyph];
|
let glyph = &line.glyphs[cursor_glyph];
|
||||||
let text_line = &mut text_lines[glyph.line_i];
|
let text_line = &mut text_lines[line.line_i.get()];
|
||||||
text_line.insert(glyph.start, event.character);
|
text_line.insert(glyph.start, event.character);
|
||||||
cursor_glyph += 1;
|
cursor_glyph += 1;
|
||||||
reshape_lines.push(glyph.line_i);
|
reshape_lines.push(line.line_i);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
EventOption::Mouse(event) => {
|
EventOption::Mouse(event) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue