emojis working

macos-click-through
Keith Simmons 5 years ago
parent 5a880d06aa
commit f8bc1a2ce4

1
Cargo.lock generated

@ -1485,6 +1485,7 @@ dependencies = [
"skribo",
"skulpin",
"tokio",
"unicode-segmentation",
"winres",
]

@ -21,6 +21,7 @@ nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "futures",
tokio = { version = "0.2.9", features = [ "blocking", "process", "time" ] }
async-trait = "0.1.18"
lazy_static = "1.4.0"
unicode-segmentation = "1.6.0"
[build-dependencies]
winres = "0.1.11"

@ -6,6 +6,7 @@ use std::sync::{Arc, Mutex};
use skulpin::skia_safe::colors;
use skulpin::winit::window::Window;
use unicode_segmentation::UnicodeSegmentation;
pub use cursor::{Cursor, CursorShape, CursorMode};
pub use style::{Colors, Style};
@ -17,7 +18,7 @@ lazy_static! {
pub static ref EDITOR: Arc<Mutex<Editor>> = Arc::new(Mutex::new(Editor::new()));
}
pub type GridCell = Option<(char, Option<Style>)>;
pub type GridCell = Option<(String, Option<Style>)>;
#[derive(new, Debug, Clone)]
pub struct DrawCommand {
@ -102,9 +103,9 @@ impl Editor {
}
}
fn add_character(command: &mut Option<DrawCommand>, character: &char, row_index: u64, col_index: u64, style: Option<Style>) {
fn add_character(command: &mut Option<DrawCommand>, character: &str, row_index: u64, col_index: u64, style: Option<Style>) {
match command {
Some(command) => command.text.push(character.clone()),
Some(command) => command.text.push_str(character),
None => {
command.replace(DrawCommand::new(character.to_string(), (col_index, row_index), style));
}
@ -112,13 +113,19 @@ impl Editor {
}
for (col_index, cell) in row.iter().enumerate() {
let (character, style) = cell.clone().unwrap_or_else(|| (' ', Some(Style::new(self.default_colors.clone()))));
let (character, style) = cell.clone().unwrap_or_else(|| (' '.to_string(), Some(Style::new(self.default_colors.clone()))));
if character.is_empty() {
add_character(&mut command, &" ", row_index as u64, col_index as u64, style.clone());
add_command(&mut draw_commands, command);
command = None;
} else {
if !command_matches(&command, &style) {
add_command(&mut draw_commands, command);
command = None;
}
add_character(&mut command, &character, row_index as u64, col_index as u64, style.clone());
}
}
add_command(&mut draw_commands, command);
}
let should_clear = self.should_clear;
@ -127,7 +134,7 @@ impl Editor {
let (x, y) = command.grid_position;
let dirty_row = &self.dirty[y as usize];
for char_index in 0..command.text.chars().count() {
for char_index in 0..command.text.graphemes(true).count() {
if dirty_row[x as usize + char_index] {
return true;
}
@ -155,15 +162,21 @@ impl Editor {
let row = self.grid.get_mut(row_index as usize).expect("Grid must have size greater than row_index");
let dirty_row = &mut self.dirty[row_index as usize];
for (i, character) in text.chars().enumerate() {
if text.is_empty() {
row[*column_pos as usize] = Some(("".to_string(), style.clone()));
dirty_row[*column_pos as usize] = true;
*column_pos = *column_pos + 1;
} else {
for (i, character) in text.graphemes(true).enumerate() {
let pointer_index = i + *column_pos as usize;
if pointer_index < row.len() {
row[pointer_index] = Some((character, style.clone()));
row[pointer_index] = Some((character.to_string(), style.clone()));
dirty_row[pointer_index] = true;
}
}
*column_pos = *column_pos + text.chars().count() as u64;
*column_pos = *column_pos + text.graphemes(true).count() as u64;
}
self.previous_style = style;
}

@ -4,7 +4,7 @@ use std::collections::HashMap;
use lru::LruCache;
use skulpin::skia_safe::{TextBlob, Font as SkiaFont, FontStyle, Typeface, TextBlobBuilder};
use font_kit::source::SystemSource;
use skribo::{layout, layout_run, FontRef as SkriboFont, FontFamily, FontCollection, TextStyle};
use skribo::{layout_run, LayoutSession, FontRef as SkriboFont, FontFamily, FontCollection, TextStyle};
const STANDARD_CHARACTER_STRING: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
@ -103,39 +103,22 @@ impl CachingShaper {
let style = TextStyle { size: base_size * scale as f32 };
let mut family = FontFamily::new();
family.add_font(font_pair.normal.1.clone());
family.add_font(font_pair.emoji.1.clone());
let mut collection = FontCollection::new();
collection.add_family(family);
let layout = layout(&style, &collection, text);
let mut normal_family = FontFamily::new();
normal_family.add_font(font_pair.normal.1.clone());
collection.add_family(normal_family);
let mut groups = Vec::new();
let mut group = Vec::new();
let mut previous_font: Option<SkriboFont> = None;
let mut emoji_family = FontFamily::new();
emoji_family.add_font(font_pair.emoji.1.clone());
collection.add_family(emoji_family);
for glyph in layout.glyphs {
if previous_font.clone().map(|previous_font| Arc::ptr_eq(&previous_font.font, &glyph.font.font)).unwrap_or(true) {
group.push(glyph);
} else {
groups.push(group);
previous_font = Some(glyph.font.clone());
group = vec![glyph];
}
}
if !group.is_empty() {
groups.push(group);
}
let session = LayoutSession::create(text, &style, &collection);
let mut blobs = Vec::new();
for group in groups {
if group.is_empty() {
continue;
}
let skribo_font = group[0].font.clone();
for layout_run in session.iter_all() {
let skribo_font = layout_run.font();
let skia_font = if Arc::ptr_eq(&skribo_font.font, &font_pair.normal.1.font) {
&font_pair.normal.0
} else {
@ -144,16 +127,14 @@ impl CachingShaper {
let mut blob_builder = TextBlobBuilder::new();
let count = group.len();
let count = layout_run.glyphs().count();
let metrics = skribo_font.font.metrics();
let ascent = metrics.ascent * base_size / metrics.units_per_em as f32;
let (glyphs, positions) = blob_builder.alloc_run_pos_h(&skia_font, count, ascent, None);
for (i, glyph_id) in group.iter().map(|glyph| glyph.glyph_id as u16).enumerate() {
glyphs[i] = glyph_id;
}
for (i, offset) in group.iter().map(|glyph| glyph.offset.x as f32).enumerate() {
positions[i] = offset;
for (i, glyph) in layout_run.glyphs().enumerate() {
glyphs[i] = glyph.glyph_id as u16;
positions[i] = glyph.offset.x;
}
blobs.push(blob_builder.make().unwrap());
}

@ -195,7 +195,22 @@ impl CursorRenderer {
let (grid_x, grid_y) = self.previous_position;
let font_dimensions: Point = (font_width, font_height).into();
let (character, font_dimensions): (String, Point) = {
let editor = EDITOR.lock().unwrap();
let character = editor.grid[grid_y as usize][grid_x as usize].clone()
.map(|(character, _)| character)
.unwrap_or(' '.to_string());
let is_double = editor.grid[grid_y as usize]
.get(grid_x as usize + 1)
.map(|cell| cell.as_ref().map(|(character, _)| character.is_empty()).unwrap_or(false))
.unwrap_or(false);
let font_width = match (is_double, &cursor.shape) {
(true, CursorShape::Block) => font_width * 2.0,
_ => font_width
};
(character, (font_width, font_height).into())
};
let destination: Point = (grid_x as f32 * font_width, grid_y as f32 * font_height).into();
let center_destination = destination + font_dimensions * 0.5;
@ -226,9 +241,6 @@ impl CursorRenderer {
// Draw foreground
paint.set_color(cursor.foreground(&default_colors).to_color());
let editor = EDITOR.lock().unwrap();
let character = editor.grid[grid_y as usize][grid_x as usize].clone()
.map(|(character, _)| character)
.unwrap_or(' ');
canvas.save();
canvas.clip_path(&path, None, Some(false));

@ -3,6 +3,7 @@ use std::time::Instant;
use skulpin::CoordinateSystemHelper;
use skulpin::skia_safe::{Canvas, Paint, Surface, Budgeted, Rect, colors};
use skulpin::skia_safe::gpu::SurfaceOrigin;
use unicode_segmentation::UnicodeSegmentation;
mod caching_shaper;
mod cursor_renderer;
@ -54,7 +55,7 @@ impl Renderer {
let (grid_x, grid_y) = grid_pos;
let x = grid_x as f32 * self.font_width;
let y = grid_y as f32 * self.font_height;
let width = text.chars().count() as f32 * self.font_width * size as f32;
let width = text.graphemes(true).count() as f32 * self.font_width * size as f32;
let height = self.font_height * size as f32;
Rect::new(x, y, x + width, y + height)
}
@ -71,13 +72,18 @@ impl Renderer {
let (grid_x, grid_y) = grid_pos;
let x = grid_x as f32 * self.font_width;
let y = grid_y as f32 * self.font_height;
let width = text.chars().count() as f32 * self.font_width;
let width = text.graphemes(true).count() as f32 * self.font_width;
let style = style.clone().unwrap_or_else(|| Style::new(default_colors.clone()));
canvas.save();
let region = self.compute_text_region(text, grid_pos, size);
let region = Rect::new(
region.x() - self.font_width,
region.y(),
region.x() + region.width() + self.font_width,
region.y() + region.height());
canvas.clip_rect(region, None, Some(false));

Loading…
Cancel
Save