Store original text as lines, reshape only changed lines
This commit is contained in:
parent
f7eb123140
commit
bc953df0d6
4 changed files with 46 additions and 40 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
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,
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ pub struct FontMatches<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FontMatches<'a> {
|
impl<'a> FontMatches<'a> {
|
||||||
fn shape_span(&self, string: &str, start_span: usize, end_span: usize) -> FontShapeSpan {
|
fn shape_span(&self, line_i: usize, line: &str, start_span: usize, end_span: usize) -> FontShapeSpan {
|
||||||
let span = &string[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());
|
||||||
for (font_i, font) in self.fonts.iter().enumerate() {
|
for (font_i, font) in self.fonts.iter().enumerate() {
|
||||||
|
|
@ -44,6 +44,7 @@ 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,
|
||||||
|
|
@ -113,11 +114,9 @@ impl<'a> FontMatches<'a> {
|
||||||
spans_by_font.remove(least_misses_i).1
|
spans_by_font.remove(least_misses_i).1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shape_line(&self, string: &str, start_line: usize, end_line: usize) -> FontShapeLine {
|
pub fn shape_line(&self, line_i: usize, line: &str) -> FontShapeLine {
|
||||||
use unicode_script::{Script, UnicodeScript};
|
use unicode_script::{Script, UnicodeScript};
|
||||||
|
|
||||||
let line = &string[start_line..end_line];
|
|
||||||
|
|
||||||
//TODO: more special handling of characters
|
//TODO: more special handling of characters
|
||||||
let mut spans = Vec::new();
|
let mut spans = Vec::new();
|
||||||
|
|
||||||
|
|
@ -131,7 +130,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(string, start_line + start, start_line + i));
|
spans.push(self.shape_span(line_i, line, start, i));
|
||||||
start = i;
|
start = i;
|
||||||
prev = Script::Unknown;
|
prev = Script::Unknown;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -139,7 +138,7 @@ impl<'a> FontMatches<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spans.push(self.shape_span(string, start_line + start, start_line + line.len()));
|
spans.push(self.shape_span(line_i, 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() {
|
||||||
|
|
@ -154,24 +153,4 @@ impl<'a> FontMatches<'a> {
|
||||||
spans,
|
spans,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shape(&self, string: &str) -> Vec<FontShapeLine> {
|
|
||||||
let mut lines = Vec::new();
|
|
||||||
|
|
||||||
let mut start = 0;
|
|
||||||
for (i, c) in string.char_indices() {
|
|
||||||
if ! string.is_char_boundary(i) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if c == '\n' {
|
|
||||||
lines.push(self.shape_line(string, start, i));
|
|
||||||
start = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lines.push(self.shape_line(string, start, string.len()));
|
|
||||||
|
|
||||||
lines
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use core::marker::PhantomData;
|
||||||
use super::{FontLayoutGlyph, FontLayoutLine};
|
use super::{FontLayoutGlyph, FontLayoutLine};
|
||||||
|
|
||||||
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,
|
||||||
|
|
@ -98,6 +99,7 @@ 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,
|
||||||
|
|
|
||||||
|
|
@ -37,10 +37,11 @@ fn main() {
|
||||||
#[cfg(not(feature = "mono"))]
|
#[cfg(not(feature = "mono"))]
|
||||||
let default_text = include_str!("../res/proportional.txt");
|
let default_text = include_str!("../res/proportional.txt");
|
||||||
|
|
||||||
let mut text = if let Some(arg) = env::args().nth(1) {
|
let mut text_lines: Vec<String> = if let Some(arg) = env::args().nth(1) {
|
||||||
fs::read_to_string(&arg).expect("failed to open file")
|
let text = fs::read_to_string(&arg).expect("failed to open file");
|
||||||
|
text.lines().map(String::from).collect()
|
||||||
} else {
|
} else {
|
||||||
default_text.to_string()
|
default_text.lines().map(String::from).collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
let bg_color = Color::rgb(0x34, 0x34, 0x34);
|
let bg_color = Color::rgb(0x34, 0x34, 0x34);
|
||||||
|
|
@ -91,6 +92,7 @@ fn main() {
|
||||||
let mut rehit = false;
|
let mut rehit = false;
|
||||||
let mut relayout = true;
|
let mut relayout = true;
|
||||||
let mut reshape = true;
|
let mut reshape = true;
|
||||||
|
let mut reshape_lines = Vec::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];
|
||||||
|
|
@ -100,7 +102,10 @@ fn main() {
|
||||||
if reshape {
|
if reshape {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
|
|
||||||
shape_lines = font_matches.shape(&text);
|
shape_lines.clear();
|
||||||
|
for (line_i, text_line) in text_lines.iter().enumerate() {
|
||||||
|
shape_lines.push(font_matches.shape_line(line_i, text_line));
|
||||||
|
}
|
||||||
|
|
||||||
reshape = false;
|
reshape = false;
|
||||||
relayout = true;
|
relayout = true;
|
||||||
|
|
@ -109,6 +114,17 @@ fn main() {
|
||||||
println!("reshape: {:?}", duration);
|
println!("reshape: {:?}", duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for line_i in reshape_lines.drain(..) {
|
||||||
|
let instant = Instant::now();
|
||||||
|
|
||||||
|
shape_lines[line_i] = font_matches.shape_line(line_i, &text_lines[line_i]);
|
||||||
|
|
||||||
|
relayout = true;
|
||||||
|
|
||||||
|
let duration = instant.elapsed();
|
||||||
|
println!("reshape line {}: {:?}", line_i, duration);
|
||||||
|
}
|
||||||
|
|
||||||
if relayout {
|
if relayout {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
|
|
||||||
|
|
@ -210,7 +226,9 @@ fn main() {
|
||||||
line_height as u32,
|
line_height as u32,
|
||||||
Color::rgba(0xFF, 0xFF, 0xFF, 0x20)
|
Color::rgba(0xFF, 0xFF, 0xFF, 0x20)
|
||||||
);
|
);
|
||||||
println!("{}, {}: '{}'", glyph.start, glyph.end, &text[glyph.start..glyph.end]);
|
|
||||||
|
let text_line = &text_lines[glyph.line_i];
|
||||||
|
println!("{}, {}: '{}'", glyph.start, glyph.end, &text_line[glyph.start..glyph.end]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,15 +292,19 @@ fn main() {
|
||||||
}
|
}
|
||||||
if cursor_glyph > 0 {
|
if cursor_glyph > 0 {
|
||||||
cursor_glyph -= 1;
|
cursor_glyph -= 1;
|
||||||
text.remove(line.glyphs[cursor_glyph].start);
|
let glyph = &line.glyphs[cursor_glyph];
|
||||||
reshape = true;
|
let text_line = &mut text_lines[glyph.line_i];
|
||||||
|
text_line.remove(glyph.start);
|
||||||
|
reshape_lines.push(cursor_line);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
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() {
|
||||||
text.remove(line.glyphs[cursor_glyph].start);
|
let glyph = &line.glyphs[cursor_glyph];
|
||||||
reshape = true;
|
let text_line = &mut text_lines[glyph.line_i];
|
||||||
|
text_line.remove(glyph.start);
|
||||||
|
reshape_lines.push(cursor_line);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
orbclient::K_0 => {
|
orbclient::K_0 => {
|
||||||
|
|
@ -305,17 +327,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) => {
|
||||||
text.insert(glyph.end, event.character);
|
let text_line = &mut text_lines[glyph.line_i];
|
||||||
|
text_line.insert(glyph.end, event.character);
|
||||||
cursor_glyph += 1;
|
cursor_glyph += 1;
|
||||||
reshape = true;
|
reshape_lines.push(cursor_line);
|
||||||
},
|
},
|
||||||
None => () // TODO
|
None => () // TODO
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let glyph = &line.glyphs[cursor_glyph];
|
let glyph = &line.glyphs[cursor_glyph];
|
||||||
text.insert(glyph.start, event.character);
|
let text_line = &mut text_lines[glyph.line_i];
|
||||||
|
text_line.insert(glyph.start, event.character);
|
||||||
cursor_glyph += 1;
|
cursor_glyph += 1;
|
||||||
reshape = true;
|
reshape_lines.push(cursor_line);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
EventOption::Mouse(event) => {
|
EventOption::Mouse(event) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue