I3F42XELTBNGNFJGKEDBRYU75HHQX2CHMWPEIEMXAGU2FFHQVHKAC 4HTJHGHFPLGVXGAEKLBNPMTGWVVMYIL67JOTWB2DREGO6L3ENYMQC SLEDIKSGLZWIB4TN6H2UTKV7YSPBLMVFORELFYDGZQEVTBXQFKYQC B5TJA6MYFWB6PLH4KGQO5D42QHUZUWC627OKENXP6HBD6PG37ECQC R6SN37XV5NNVRRB7WYOW6BL4DPA4GAKPOFSX2OT7BR4Y36X532BQC 2NFFH775XBXGXBJYGTGUAUH45T5ZI6FFJXHFGUQQS324XEAFKT7AC KLGRQAFUQPJP75NVLS5MZZ3CY4TGNVGB4K2YHQSLYVGAPKCLBLUAC NOSXMSCMJV75LYKAIRD4FG4LFPYQ4CI5SIKGQC7MEYUEAB7X7NWAC SDFC64IQZWAAG36UV4GVSAER5S3FISBQEE2NVGI4G6ODD6CCGBIAC 5S34ANJMEKYNSGROMFRDP22UA2FK2ENSGOBB4MPSHS7PG2BW6DLAC T2MYIZ6BIXHBKWZ3EJIYV65STSDAVKZHAPLTFXF27YBQIJCI7U7AC PTQ26KY65NDVZ35EG66SARWRGGYKDJ2BT3EVK4RJFS2J5AQUX6OQC B66IOHMWFZINTWC57Q5OD4YPBVQNBN3YUM3ZKX4MTDKHYGH5JHFAC X6QJYZJZSS7YSRCDOPQ2I2Y7U7VJA4HE5P74ZYENROR7FRUPPXWQC CTPHEJ2S7MMSZTNVO4LFEYHMMTKYWB5PC54RMVJHMATN5TY45GPQC V2265WPBM2LBE4BGEFB3HYCZXA5C5MJKQ5IVPFWY3ARCVIAYBZGQC LSPMIVEH5IYUPBMB7DL5VTM2HOMYDBA5ZY3GIW6ZFTCDGTUUDFFAC FVK7DUVNDKO6AVNV7XI7YFG6GIRAEBYHLSRHR75AEF24PNSPLL5AC 576YRB7XSKS6Q265TEJQS7HUGMKSGHGDRGVP6WBZS7XMK6RVJRNQC HKVKPIIWK6AB4DWCS6SB47RYEXTD4QAQIGDFNQGA3TDJEIAXBZKQC AFZQUL4VKEEDRSA5CV6YXN7PMX6PQ2PMLECTG53S4HZKTNCAIMXQC T5T2PZSJVBHIPHG7VRXZSH36WGSTR4I44BOI335X4F637E7GUWHAC L5ZNI6R53WDZIOXNECV262TURPIPWL522TVF25U5RYHOTSY7BHZAC struct FontData {// This is referred by rb_face#[allow(unused)]data: Vec<u8>,rb_face: rustybuzz::Face<'static>,fd_face: fontdue::Font,}
type Plans = HashMap<(FontIndex, Direction, Script, Option<Language>), ShapePlan>;type GlyphCache = HashMap<(FontIndex, GlyphIndex), (Metrics, Vec<u8>)>;type ShapeCache = HashMap<RcLine, (bool, Vec<(json_ui::Face, FontIndex, i32, GlyphBuffer)>)>;
pub struct Fonts {faces: Vec<FontData>,font_cache: HashMap<(FontIndex, GlyphIndex), (Metrics, Vec<u8>)>,plans: HashMap<(FontIndex, Direction, Script, Option<Language>), ShapePlan>,font_size: f32,
#[derive(Default)]pub struct Shaper {pub fonts: Vec<(Vec<u8>, rustybuzz::Face<'static>)>,pub cache: ShapeCache,pub plans: Plans,
pub struct Renderer {/// pixels depends on this being alive#[allow(unused)]pub window: Window,pub pixels: Pixels<'static>,pub size: (u32, u32),pub fonts: Fonts,}impl Fonts {pub fn new() -> Result<Self, Box<dyn Error>> {let mut fontdb = fontdb::Database::new();fontdb.load_system_fonts();let mut faces = Vec::new();for font in ["Iosevka", "Manjari"] {let id = fontdb.query(&fontdb::Query {families: &[fontdb::Family::Name(font)],..Default::default()}).ok_or("Unknown font")?;fontdb.with_face_data(id, |data, _| {let data = data.to_vec();let rb_face = rustybuzz::Face::from_slice(unsafe { &*(data.as_slice() as *const [u8]) },0,).ok_or("Failed to load rustybuzz font")?;let fd_face =fontdue::Font::from_bytes(data.as_slice(), FontSettings::default())?;faces.push(FontData {data,rb_face,fd_face,});Ok(())}).ok_or("Failed to load font").flatten()?;}Ok(Self {faces,font_cache: HashMap::new(),plans: HashMap::new(),font_size: 16.0,})}pub fn line_height(&self) -> u32 {self.faces.first().and_then(|fd| {Some(fd.fd_face.vertical_line_metrics(self.font_size)?.new_line_size as u32,)}).unwrap_or((self.font_size * 1.5) as u32)}fn shape(&mut self, font: FontIndex, mut ubuf: UnicodeBuffer) -> GlyphBuffer {
impl Shaper {fn shape(plans: &mut Plans,index: FontIndex,font: &rustybuzz::Face,mut ubuf: UnicodeBuffer,) -> GlyphBuffer {
fn rasterize_glyph(&mut self, font: FontIndex, glyph: GlyphIndex) -> &(Metrics, Vec<u8>) {self.font_cache.entry((font, glyph)).or_insert_with(|| {self.faces[font].fd_face.rasterize_indexed(glyph, self.font_size)})
fn make_runs(&mut self, line: RcLine) -> &[(json_ui::Face, FontIndex, i32, GlyphBuffer)] {let res = self.cache.entry(line.clone()).or_insert_with(|| {let mut res = Vec::new();let mut curr_font = 0;let slice: &[json_ui::Atom] = &line;for atom in slice {let mut start = 0;for (i, c) in atom.contents.char_indices() {let font = self.fonts.iter().position(|i| i.1.unicode_ranges().contains_char(c)).unwrap_or(0);if curr_font != font || c == '\n' {let mut ubuf = UnicodeBuffer::new();ubuf.push_str(&atom.contents[start..i]);let rb_font = &self.fonts[curr_font].1;let glyph_buffer = Self::shape(&mut self.plans, curr_font, rb_font, ubuf);res.push((atom.face.clone(),curr_font,rb_font.units_per_em(),glyph_buffer,));curr_font = font;start = i;}if c == '\n' {start += 1;}}let mut ubuf = UnicodeBuffer::new();ubuf.push_str(&atom.contents[start..]);let rb_font = &self.fonts[curr_font].1;let glyph_buffer = Self::shape(&mut self.plans, curr_font, rb_font, ubuf);res.push((atom.face.clone(),curr_font,rb_font.units_per_em(),glyph_buffer,));}(true, res)});&res.1
impl Renderer {pub fn new(event_loop: &ActiveEventLoop) -> Result<Self, Box<dyn Error>> {let window = event_loop.create_window(Window::default_attributes().with_inner_size(PhysicalSize::new(WIDTH as f64, HEIGHT as f64)).with_title("Kakoune Client"),)?;let st = SurfaceTexture::new(WIDTH,HEIGHT,// We need to use unsafe here because otherwise we can't have self-referencial structsunsafe { &*(&window as *const Window) },);let pixels = Pixels::new(WIDTH, HEIGHT, st)?;Ok(Self {window,pixels,size: (WIDTH, HEIGHT),fonts: Fonts::new()?,})
#[derive(Default)]pub struct Rasterizer {pub fonts: Vec<fontdue::Font>,pub cache: GlyphCache,}impl Rasterizer {fn rasterize_glyph(&mut self,font: FontIndex,glyph: GlyphIndex,font_size: f32,) -> &(Metrics, Vec<u8>) {self.cache.entry((font, glyph)).or_insert_with(|| self.fonts[font].rasterize_indexed(glyph, font_size))
let upe = self.fonts.faces[font].rb_face.units_per_em();let buf = self.pixels.frame_mut();let font_size = self.fonts.font_size as i32;let line_height = self.fonts.font_size as i32;
let fs = font_size as i32;let line_height = font_size as i32;
let x_off = gpos.x_offset * font_size / upe + metrics.xmin;let y_off = gpos.y_offset * font_size / upe - metrics.ymin - metrics.height as i32;
let x_off = gpos.x_offset * fs / upe + metrics.xmin;let y_off = gpos.y_offset * fs / upe - metrics.ymin - metrics.height as i32;
fn make_runs<'a>(line: &'a [json_ui::Atom],fonts: &[FontData],) -> Vec<(&'a str, &'a json_ui::Face, FontIndex)> {let mut res = Vec::new();let mut curr_font = 0;for atom in line {let mut start = 0;for (i, c) in atom.contents.char_indices() {let font = fonts.iter().position(|i| i.rb_face.unicode_ranges().contains_char(c)).unwrap_or(0);if curr_font != font || c == '\n' {res.push((&atom.contents[start..i], &atom.face, curr_font));curr_font = font;start = i;}if c == '\n' {start += 1;}}res.push((&atom.contents[start..], &atom.face, curr_font));
pub struct Renderer {/// pixels depends on this being alive#[allow(unused)]pub window: Window,pub pixels: Pixels<'static>,pub size: (u32, u32),shaper: Shaper,rasterizer: Rasterizer,font_size: f32,}impl Renderer {pub fn new(event_loop: &ActiveEventLoop) -> Result<Self, Box<dyn Error>> {let window = event_loop.create_window(Window::default_attributes().with_inner_size(PhysicalSize::new(WIDTH as f64, HEIGHT as f64)).with_title("Kakoune Client"),)?;let st = SurfaceTexture::new(WIDTH,HEIGHT,// We need to use unsafe here because otherwise we can't have self-referencial structsunsafe { &*(&window as *const Window) },);let pixels = Pixels::new(WIDTH, HEIGHT, st)?;let mut fontdb = fontdb::Database::new();fontdb.load_system_fonts();let mut shaper = Shaper::default();let mut rasterizer = Rasterizer::default();for font in ["Iosevka", "Manjari"] {let id = fontdb.query(&fontdb::Query {families: &[fontdb::Family::Name(font)],..Default::default()}).ok_or("Unknown font")?;fontdb.with_face_data(id, |data, _| {let data = data.to_vec();let rb_face = rustybuzz::Face::from_slice(unsafe { &*(data.as_slice() as *const [u8]) },0,).ok_or("Failed to load rustybuzz font")?;let fd_face =fontdue::Font::from_bytes(data.as_slice(), FontSettings::default())?;shaper.fonts.push((data, rb_face));rasterizer.fonts.push(fd_face);Ok(())}).ok_or("Failed to load font").flatten()?;
for (contents, face, font) in Self::make_runs(line, &self.fonts.faces) {ubuf.push_str(contents);let glyph_buffer = self.fonts.shape(font, ubuf);self.render_segment(font, face, &ui.default_face, &glyph_buffer, &mut pos);ubuf = glyph_buffer.clear();
for (face, font, upe, glyph_buffer) in self.shaper.make_runs(line.clone()) {self.rasterizer.rasterize_segment(self.pixels.frame_mut(),self.size,*font,&glyph_buffer,*upe,self.font_size,&face,&ui.default_face,&mut pos,);
for (contents, face, font) in Self::make_runs(&ui.prompt_line, &self.fonts.faces) {ubuf.push_str(contents);let glyph_buffer = self.fonts.shape(font, ubuf);self.render_segment(font, face, &ui.line_face, &glyph_buffer, &mut pos);ubuf = glyph_buffer.clear();
for (face, font, upe, glyph_buffer) in self.shaper.make_runs(ui.prompt_line.clone()) {self.rasterizer.rasterize_segment(self.pixels.frame_mut(),self.size,*font,&glyph_buffer,*upe,self.font_size,&face,&ui.default_face,&mut pos,);
let mode_line = Self::make_runs(&ui.mode_line, &self.fonts.faces);let mode_line: Vec<_> = mode_line.into_iter().map(|(contents, face, font)| {let mut ubuf = UnicodeBuffer::new();ubuf.push_str(contents);let glyph_buffer = self.fonts.shape(font, ubuf);let size = glyph_buffer
let mode_line = self.shaper.make_runs(ui.mode_line.clone());let text_width: i32 = mode_line.iter().map(|(_, _, upe, glyph_buffer)| {glyph_buffer
for (glyph_buffer, font, face, _) in mode_line {self.render_segment(font, face, &ui.line_face, &glyph_buffer, &mut pos);
for (face, font, upe, glyph_buffer) in mode_line {self.rasterizer.rasterize_segment(self.pixels.frame_mut(),self.size,*font,&glyph_buffer,*upe,self.font_size,&face,&ui.default_face,&mut pos,);
lines: Vec<json_ui::Line>,prompt_line: json_ui::Line,mode_line: json_ui::Line,
lines: Vec<RcLine>,prompt_line: RcLine,mode_line: RcLine,