T5T2PZSJVBHIPHG7VRXZSH36WGSTR4I44BOI335X4F637E7GUWHAC V2265WPBM2LBE4BGEFB3HYCZXA5C5MJKQ5IVPFWY3ARCVIAYBZGQC B66IOHMWFZINTWC57Q5OD4YPBVQNBN3YUM3ZKX4MTDKHYGH5JHFAC PTQ26KY65NDVZ35EG66SARWRGGYKDJ2BT3EVK4RJFS2J5AQUX6OQC LSPMIVEH5IYUPBMB7DL5VTM2HOMYDBA5ZY3GIW6ZFTCDGTUUDFFAC 576YRB7XSKS6Q265TEJQS7HUGMKSGHGDRGVP6WBZS7XMK6RVJRNQC L4D4HCUQDTOJKMNBIZWHUHXYEEQKOL4BCNMDI3ZOP3ARK65YNCVQC CVXA6LIYFYIZEVPTI335A332EXRVJXF2SC4B5F2NFYXZXYVDFBKQC VL4FY4YJUFRVCZR67KOTB22RILTEP2KX2GLHP4J662XF7VGS77WAC CTPHEJ2S7MMSZTNVO4LFEYHMMTKYWB5PC54RMVJHMATN5TY45GPQC HKVKPIIWK6AB4DWCS6SB47RYEXTD4QAQIGDFNQGA3TDJEIAXBZKQC AFZQUL4VKEEDRSA5CV6YXN7PMX6PQ2PMLECTG53S4HZKTNCAIMXQC L5ZNI6R53WDZIOXNECV262TURPIPWL522TVF25U5RYHOTSY7BHZAC X6QJYZJZSS7YSRCDOPQ2I2Y7U7VJA4HE5P74ZYENROR7FRUPPXWQC FVAECMP3SBASNUQGUTHGZTMXLLAGW2FK6MID7P6YP5LRD7ZHADYAC DZSYKTTKQ6DUGPMCPS7FQRSE5FO4FEHY2L3UWB73A7Y7Y6GDHWCAC // TODO: Use `fontdb`let data = include_bytes!("/usr/share/fonts/noto/NotoSans-Black.ttf");let rustybuzz_face =rustybuzz::Face::from_slice(data, 0).ok_or("Failed to load rustybuzz font")?;let fontdue_face = fontdue::Font::from_bytes(&data[..], FontSettings::default())?;
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()}).unwrap();fontdb.with_face_data(id, |data, _| {let data = data.to_vec();let rb_face =rustybuzz::Face::from_slice(unsafe { &*(&data[..] as *const [u8]) }, 0).ok_or("Failed to load rustybuzz font")?;let fd_face = fontdue::Font::from_bytes(&data[..], FontSettings::default())?;faces.push(FontData {data,rb_face,fd_face,});Ok(())}).ok_or("Failed to load font").flatten()?;}
/// Rasterizes a glyph./// Returns slice containing pixels as RGB8fn render_glyph(&mut self,font_index: FontIndex,glyph_index: GlyphIndex,) -> (&Metrics, &[u8]) {let res = self.font_cache.entry((font_index, glyph_index)).or_insert_with(|| {// TODO: Support other sizesself.fontdue_faces[font_index].rasterize_indexed_subpixel(glyph_index, 32.0)});(&res.0, &res.1)
fn line_height(&self) -> u32 {self.faces.get(0).and_then(|fd| Some(fd.fd_face.vertical_line_metrics(32.0)?.new_line_size as u32)).unwrap_or(40)
/// Shapes some textpub fn shape(&self, font_index: FontIndex, ubuf: UnicodeBuffer) -> GlyphBuffer {rustybuzz::shape(&self.rustybuzz_faces[font_index], &[], ubuf)
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, 32.0))
fn render_segment(rs: &mut RenderState,fs: &mut FontState,font: FontIndex,face: &json_ui::Face,default_face: &json_ui::Face,ubuf: UnicodeBuffer,pos: &mut (i32, i32),) -> UnicodeBuffer {let glyph_buffer = rustybuzz::shape(&fs.faces[font].rb_face, &[], ubuf);let ginfo = glyph_buffer.glyph_infos();let gpos = glyph_buffer.glyph_positions();let upe = fs.faces[font].rb_face.units_per_em();let buf = rs.pixels.frame_mut();for i in 0..glyph_buffer.len() {let (metrics, data) = fs.rasterize_glyph(font, ginfo[i].glyph_id as u16);let x_off = gpos[i].x_offset * 32 / upe + metrics.xmin;let y_off = gpos[i].y_offset * 32 / upe - metrics.ymin - metrics.height as i32;
fn redraw(rs: &mut RenderState, fs: &mut FontState, lines: &[json_ui::Line]) {let line_height = fs.fontdue_faces[0].vertical_line_metrics(32.0).map(|i| i.new_line_size).unwrap_or(40.0);let mut x = 0;let mut y = line_height as i32;for line in lines {let mut ubuf = UnicodeBuffer::new();for atom in line {ubuf.push_str(&atom.contents);
for row in 0..metrics.height {for column in 0..metrics.width {let x = pos.0 + x_off + column as i32;let y = pos.1 + y_off + row as i32;let bidx = ((x + y * rs.size.0 as i32) * 4) as usize;let sidx = column + row * metrics.width;if bidx >= buf.len() {break;}if sidx >= buf.len() {continue;}if x > rs.size.0 as i32 {break;}let color = if data[sidx] > 200 {&face.fg.to_rgba(default_face.fg.to_rgba((255, 255, 255, 0)))} else {&face.bg.to_rgba(default_face.bg.to_rgba((0, 0, 0, 255)))};buf[bidx] = color.0;buf[bidx + 1] = color.1;buf[bidx + 2] = color.2;buf[bidx + 3] = 255;}
let gbuf = fs.shape(0, ubuf);let upe = fs.rustybuzz_faces[0].units_per_em();// >i vjfor (gpos, ginfo) in gbuf.glyph_positions().iter().zip(gbuf.glyph_infos()) {let (metrics, data) = fs.render_glyph(0, ginfo.glyph_id as u16);for i in 0..metrics.width {for j in 0..metrics.height {let x_offset = gpos.x_offset * 32 / upe;let y_offset = gpos.y_offset * 32 / upe;
let py = y + j as i32 - y_offset - metrics.height as i32 - metrics.ymin;let px = x + i as i32 + x_offset + metrics.xmin;let pidx = (py * rs.pixmap.width() as i32 + px) as usize * 4;
pos.0 += gpos[i].x_advance * 32 / upe;pos.1 += gpos[i].y_advance * 32 / upe;}glyph_buffer.clear()}
if pidx >= rs.pixmap.data().len() {continue;}let didx = (j * metrics.width + i) * 3;
fn redraw(rs: &mut RenderState,fs: &mut FontState,lines: &[json_ui::Line],default_face: &json_ui::Face,) -> Result<(), Box<dyn Error>> {let bg = default_face.bg.to_rgba((0, 0, 0, 255));for c in rs.pixels.frame_mut().chunks_exact_mut(4) {c[0] = bg.0;c[1] = bg.1;c[2] = bg.2;c[3] = bg.3;}
let data_mut = rs.pixmap.data_mut();for k in 0..3 {data_mut[pidx + k] = data_mut[pidx + k].max(data[didx + k]);}data_mut[pidx + 3] = 255;
let mut ubuf = UnicodeBuffer::new();let mut curr_face = None;let mut curr_font = 0;let mut pos = (0, fs.line_height() as i32);for line in lines {for atom in line {let face = &atom.face;for c in atom.contents.chars() {let font = fs.faces.iter().position(|i| i.rb_face.glyph_index(c).is_some()).unwrap_or(0);if curr_face != Some(face) || curr_font != font || c == '\n' {ubuf = render_segment(rs,fs,curr_font,curr_face.unwrap_or(face),default_face,ubuf,&mut pos,);curr_face = Some(face);curr_font = font;ubuf.clear();}if c == '\n' {continue;
let line_height = self.font_state.fontdue_faces[0].vertical_line_metrics(32.0).map(|i| i.new_line_size).unwrap_or(40.0);let y = size.height / (line_height as u32);let x = 512;self.kakoune.send_response(Response::Resize(x, y));
rs.size = size.into();let lines = (size.height as f32 / 40.0) as u32;let cols = 512;self.kakoune.send_response(Response::Resize(lines, cols));
struct RgbaVisitor;impl<'de> Visitor<'de> for RgbaVisitor {type Value = RgbaColor;fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {formatter.write_str("A color in the format rgb:RRGGBB or rgba:RRGGBBAA")}fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>whereE: serde::de::Error,{(|| {if let Some(v) = v.strip_prefix("rgb:") {let r = u8::from_str_radix(v.get(0..2)?, 16).ok()?;let g = u8::from_str_radix(v.get(2..4)?, 16).ok()?;let b = u8::from_str_radix(v.get(4..6)?, 16).ok()?;Some(RgbaColor(r, g, b, 255))} else if let Some(v) = v.strip_prefix("rgba:") {let r = u8::from_str_radix(v.get(0..2)?, 16).ok()?;let g = u8::from_str_radix(v.get(2..4)?, 16).ok()?;let b = u8::from_str_radix(v.get(4..6)?, 16).ok()?;let a = u8::from_str_radix(v.get(6..8)?, 16).ok()?;Some(RgbaColor(r, g, b, a))} else {None}})().ok_or(E::invalid_value(Unexpected::Other("Invalid color format"),&"",))}}impl<'de> Deserialize<'de> for RgbaColor {fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>whereD: Deserializer<'de>,{deserializer.deserialize_string(RgbaVisitor)}}
Rgb(String),
Rgb(RgbaColor),}impl Color {pub fn to_rgba(&self, default: (u8, u8, u8, u8)) -> (u8, u8, u8, u8) {match self {Color::BuiltinColor(color) => match color {BuiltinColor::Black => (0, 0, 0, 255),BuiltinColor::Red => (255, 0, 0, 255),BuiltinColor::Green => (0, 255, 0, 255),BuiltinColor::Yellow => (255, 255, 0, 255),BuiltinColor::Blue => (0, 0, 255, 0),BuiltinColor::Magenta => (255, 0, 255, 255),BuiltinColor::Cyan => (0, 255, 255, 255),BuiltinColor::White => (255, 255, 255, 255),BuiltinColor::BrightBlack => (0, 0, 0, 255),BuiltinColor::BrightRed => (255, 0, 0, 255),BuiltinColor::BrightGreen => (0, 255, 0, 255),BuiltinColor::BrightYellow => (255, 255, 0, 255),BuiltinColor::BrightBlue => (0, 0, 255, 0),BuiltinColor::BrightMagenta => (255, 0, 255, 255),BuiltinColor::BrightCyan => (0, 255, 255, 255),BuiltinColor::BrightWhite => (255, 255, 255, 255),BuiltinColor::Default => default,},Color::Rgb(RgbaColor(r, g, b, a)) => (*r, *g, *b, *a),}}
name = "crc32fast"version = "1.5.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"dependencies = ["cfg-if",][[package]]
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905"dependencies = ["fontconfig-parser","log","memmap2","slotmap","tinyvec","ttf-parser 0.25.1",]
name = "png"version = "0.17.16"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"dependencies = ["bitflags 1.3.2","crc32fast","fdeflate","flate2","miniz_oxide",][[package]]