Refactor text shaping

This commit is contained in:
mars 2022-07-16 19:26:02 -06:00
parent 2975477725
commit feadf8fa15
2 changed files with 74 additions and 27 deletions

View File

@ -58,6 +58,17 @@ pub enum CursorEventKind {
Deselect = 3,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
pub struct GlyphPosition {
pub face: u16,
pub index: u16,
pub hori_advance: i32,
pub vert_advance: i32,
pub xoff: i32,
pub yoff: i32,
}
#[cfg(feature = "glam")]
mod glam_interop {
use super::*;

View File

@ -10,6 +10,7 @@ use allsorts::pathfinder_geometry::{line_segment::LineSegment2F, vector::Vector2
use allsorts::tables::{glyf::GlyfTable, loca::LocaTable};
use allsorts::tables::{FontTableProvider, SfntVersion};
use allsorts::{tag, Font as AllsortsFont};
use canary_types::GlyphPosition;
use lyon::path::Path;
use ouroboros::self_referencing;
@ -131,6 +132,10 @@ pub struct GlyphMesh {
#[self_referencing]
pub struct Font {
file_buffer: Vec<u8>,
face_index: u16,
script: u32,
direction: TextDirection,
vertical: bool,
#[borrows(file_buffer)]
#[covariant]
@ -146,9 +151,19 @@ pub struct Font {
}
impl Font {
pub fn load(file_buffer: Vec<u8>) -> Self {
pub fn load(
face_index: u16,
script: u32,
direction: TextDirection,
vertical: bool,
file_buffer: Vec<u8>,
) -> Self {
FontBuilder {
file_buffer,
face_index,
script,
direction,
vertical,
read_scope_builder: |buffer| ReadScope::new(buffer),
font_data_builder: |scope| scope.read::<FontData<'_>>().unwrap(),
inner_builder: |font_data| {
@ -163,6 +178,39 @@ impl Font {
pub fn create_glyph_cache(&self) -> GlyphCache {
GlyphCache::new(self.borrow_inner())
}
pub fn shape(&mut self, text: &str) -> Vec<GlyphPosition> {
let face_index = *self.borrow_face_index() as u16;
let presentation = MatchingPresentation::Required;
let script = *self.borrow_script();
let lang_tag = None;
let features = allsorts::gsub::Features::default();
let kerning = true;
let direction = *self.borrow_direction();
let vertical = *self.borrow_vertical();
self.with_inner_mut(|font| {
let mapped = font.map_glyphs(text, script, presentation);
let infos = font
.shape(mapped, script, lang_tag, &features, kerning)
.unwrap();
let mut layout = GlyphLayout::new(font, &infos, direction, vertical);
let positions = layout.glyph_positions().unwrap();
let mut glyphs = Vec::with_capacity(positions.len());
for (glyph, position) in infos.iter().zip(&positions) {
glyphs.push(GlyphPosition {
face: face_index,
index: glyph.glyph.glyph_index,
hori_advance: position.hori_advance,
vert_advance: position.vert_advance,
xoff: position.x_offset,
yoff: position.y_offset,
});
}
glyphs
})
}
}
pub struct DummyText {
@ -173,29 +221,17 @@ pub struct DummyText {
impl Default for DummyText {
fn default() -> Self {
let script = tag::LATN;
let buffer = include_bytes!("linja-pona-4.9.otf");
let text = "toki o! nimi mi li [_mun_alasa_sona]. toki+pona li pona.";
let mut font = Font::load(buffer.to_vec());
let mut cache = font.create_glyph_cache();
let glyphs = font
.with_inner_mut(|font| font.map_glyphs(&text, script, MatchingPresentation::Required));
let lang_tag = None;
let features = allsorts::gsub::Features::default();
let kerning = true;
let infos = font.with_inner_mut(|font| {
font.shape(glyphs, script, lang_tag, &features, kerning)
.unwrap()
});
let face_index = 0;
let direction = TextDirection::LeftToRight;
let vertical = false;
let buffer = include_bytes!("linja-pona-4.9.otf");
let mut font = Font::load(face_index, script, direction, vertical, buffer.to_vec());
let positions = font.with_inner_mut(|font| {
let mut layout = GlyphLayout::new(font, &infos, direction, vertical);
layout.glyph_positions().unwrap()
});
let mut cache = font.create_glyph_cache();
let text = "toki o! nimi mi li [_mun_alasa_sona]. toki+pona li pona.";
let glyphs = font.shape(text);
let mut mesh = Self {
vertices: Vec::new(),
@ -204,12 +240,12 @@ impl Default for DummyText {
let mut xcur = 0;
let mut ycur = 0;
for (glyph, position) in infos.iter().zip(&positions) {
let xpos = xcur + position.x_offset;
let ypos = ycur + position.y_offset;
xcur += position.hori_advance;
ycur += position.vert_advance;
cache.draw(&mut mesh, glyph.glyph.glyph_index, xpos, ypos);
for glyph in glyphs.iter() {
let xpos = xcur + glyph.xoff;
let ypos = ycur + glyph.yoff;
xcur += glyph.hori_advance;
ycur += glyph.vert_advance;
cache.draw(&mut mesh, glyph.index, xpos, ypos);
}
mesh