Implement font features (#94)

This commit is contained in:
daa 2018-05-06 15:22:38 +03:00
parent 2dc10aa611
commit ad0ea04f93
9 changed files with 94 additions and 22 deletions

View File

@ -6,7 +6,6 @@ build = "build.rs"
[dependencies] [dependencies]
cairo-rs = "0.4" cairo-rs = "0.4"
pango = "0.4"
pango-sys = "0.6" pango-sys = "0.6"
pangocairo = "0.5" pangocairo = "0.5"
pangocairo-sys = "0.7" pangocairo-sys = "0.7"
@ -51,6 +50,10 @@ atty = "0.2"
[build-dependencies] [build-dependencies]
phf_codegen = "0.7" phf_codegen = "0.7"
[dependencies.pango]
features = ["v1_38"]
version = "0.4"
[dependencies.gtk] [dependencies.gtk]
version = "0.4" version = "0.4"
features = ["v3_22"] features = ["v3_22"]

View File

@ -52,8 +52,10 @@ function s:GuiFontCommand(fname, bang) abort
call GuiFont(a:fname, a:bang ==# '!') call GuiFont(a:fname, a:bang ==# '!')
endif endif
endfunction endfunction
command! -nargs=? -bang Guifont call s:GuiFontCommand("<args>", "<bang>") command! -nargs=1 -bang Guifont call s:GuiFontCommand("<args>", "<bang>")
command! -nargs=? -bang GuiFont call s:GuiFontCommand("<args>", "<bang>") command! -nargs=1 -bang GuiFont call s:GuiFontCommand("<args>", "<bang>")
command! -nargs=? GuiFontFeatures call rpcnotify(1, 'Gui', 'FontFeatures', <q-args>)
command! NGToggleSidebar call rpcnotify(1, 'Gui', 'Command', 'ToggleSidebar') command! NGToggleSidebar call rpcnotify(1, 'Gui', 'Command', 'ToggleSidebar')

View File

@ -86,6 +86,7 @@ pub fn call_gui_event(
) -> result::Result<(), String> { ) -> result::Result<(), String> {
match method { match method {
"Font" => call!(ui->set_font(args: str)), "Font" => call!(ui->set_font(args: str)),
"FontFeatures" => call!(ui->set_font_features(args: str)),
"Clipboard" => match try_str!(args[0]) { "Clipboard" => match try_str!(args[0]) {
"Set" => match try_str!(args[1]) { "Set" => match try_str!(args[1]) {
"*" => ui.clipboard_primary_set(try_str!(args[2])), "*" => ui.clipboard_primary_set(try_str!(args[2])),

View File

@ -8,18 +8,24 @@ use ui_model::StyledLine;
use super::itemize::ItemizeIterator; use super::itemize::ItemizeIterator;
pub struct Context { pub struct Context {
state: ContextState, font_metrics: FontMetrix,
font_features: FontFeatures,
} }
impl Context { impl Context {
pub fn new(pango_context: pango::Context) -> Self { pub fn new(pango_context: pango::Context) -> Self {
Context { Context {
state: ContextState::new(pango_context), font_metrics: FontMetrix::new(pango_context),
font_features: FontFeatures::new(),
} }
} }
pub fn update(&mut self, pango_context: pango::Context) { pub fn update(&mut self, pango_context: pango::Context) {
self.state = ContextState::new(pango_context); self.font_metrics = FontMetrix::new(pango_context);
}
pub fn update_font_features(&mut self, font_features: FontFeatures) {
self.font_features = font_features;
} }
pub fn itemize(&self, line: &StyledLine) -> Vec<sys_pango::Item> { pub fn itemize(&self, line: &StyledLine) -> Vec<sys_pango::Item> {
@ -28,7 +34,7 @@ impl Context {
ItemizeIterator::new(&line.line_str) ItemizeIterator::new(&line.line_str)
.flat_map(|(offset, len)| { .flat_map(|(offset, len)| {
sys_pango::pango_itemize( sys_pango::pango_itemize(
&self.state.pango_context, &self.font_metrics.pango_context,
&line.line_str, &line.line_str,
offset, offset,
len, len,
@ -40,32 +46,34 @@ impl Context {
} }
pub fn create_layout(&self) -> pango::Layout { pub fn create_layout(&self) -> pango::Layout {
pango::Layout::new(&self.state.pango_context) pango::Layout::new(&self.font_metrics.pango_context)
} }
#[inline]
pub fn font_description(&self) -> &pango::FontDescription { pub fn font_description(&self) -> &pango::FontDescription {
&self.state.font_desc &self.font_metrics.font_desc
} }
#[inline]
pub fn cell_metrics(&self) -> &CellMetrics { pub fn cell_metrics(&self) -> &CellMetrics {
&self.state.cell_metrics &self.font_metrics.cell_metrics
}
pub fn font_features(&self) -> &FontFeatures {
&self.font_features
} }
} }
struct ContextState { struct FontMetrix {
pango_context: pango::Context, pango_context: pango::Context,
cell_metrics: CellMetrics, cell_metrics: CellMetrics,
font_desc: pango::FontDescription, font_desc: pango::FontDescription,
} }
impl ContextState { impl FontMetrix {
pub fn new(pango_context: pango::Context) -> Self { pub fn new(pango_context: pango::Context) -> Self {
let font_metrics = pango_context.get_metrics(None, None).unwrap(); let font_metrics = pango_context.get_metrics(None, None).unwrap();
let font_desc = pango_context.get_font_description().unwrap(); let font_desc = pango_context.get_font_description().unwrap();
ContextState { FontMetrix {
pango_context, pango_context,
cell_metrics: CellMetrics::new(&font_metrics), cell_metrics: CellMetrics::new(&font_metrics),
font_desc, font_desc,
@ -115,3 +123,34 @@ impl CellMetrics {
} }
} }
} }
pub struct FontFeatures {
features: Option<String>,
}
impl FontFeatures {
pub fn new() -> Self {
FontFeatures {
features: None,
}
}
pub fn from(font_features: String) -> Self {
if font_features.trim().is_empty() {
return Self::new();
}
FontFeatures {
features: Some(font_features)
}
}
pub fn insert_attr(&self, attr_list: &pango::AttrList, end_idx: usize) {
if let Some(ref features) = self.features {
let mut attr = sys_pango::attribute::new_features(features).unwrap();
attr.set_start_index(0);
attr.set_end_index(end_idx as u32);
attr_list.insert(attr);
}
}
}

View File

@ -2,7 +2,7 @@ mod context;
mod itemize; mod itemize;
mod model_clip_iterator; mod model_clip_iterator;
pub use self::context::Context; pub use self::context::{Context, FontFeatures};
pub use self::context::CellMetrics; pub use self::context::CellMetrics;
use self::model_clip_iterator::{ModelClipIteratorFactory, RowView}; use self::model_clip_iterator::{ModelClipIteratorFactory, RowView};
@ -210,7 +210,7 @@ pub fn shape_dirty(
) { ) {
for line in ui_model.model_mut() { for line in ui_model.model_mut() {
if line.dirty_line { if line.dirty_line {
let styled_line = ui_model::StyledLine::from(line, color_model); let styled_line = ui_model::StyledLine::from(line, color_model, ctx.font_features());
let items = ctx.itemize(&styled_line); let items = ctx.itemize(&styled_line);
line.merge(&styled_line, &items); line.merge(&styled_line, &items);

View File

@ -276,6 +276,17 @@ impl State {
self.on_redraw(&RepaintMode::All); self.on_redraw(&RepaintMode::All);
} }
pub fn set_font_features(&mut self, font_features: String) {
let font_features = render::FontFeatures::from(font_features);
self.render_state
.borrow_mut()
.font_ctx
.update_font_features(font_features);
self.model.clear_glyphs();
self.on_redraw(&RepaintMode::All);
}
pub fn open_file(&self, path: &str) { pub fn open_file(&self, path: &str) {
if let Some(mut nvim) = self.nvim() { if let Some(mut nvim) = self.nvim() {
nvim.command_async(&format!("e {}", path)) nvim.command_async(&format!("e {}", path))

View File

@ -0,0 +1,12 @@
use pango_sys;
use pango;
use glib::translate::*;
pub fn new_features(features: &str) -> Option<pango::Attribute> {
unsafe {
from_glib_full(pango_sys::pango_attr_font_features_new(
features.to_glib_none().0,
))
}
}

View File

@ -2,6 +2,8 @@ mod item;
mod analysis; mod analysis;
mod attr_iterator; mod attr_iterator;
pub mod attribute;
pub use self::item::Item; pub use self::item::Item;
pub use self::analysis::Analysis; pub use self::analysis::Analysis;
pub use self::attr_iterator::{AttrIterator, AttrIteratorFactory}; pub use self::attr_iterator::{AttrIterator, AttrIteratorFactory};

View File

@ -1,10 +1,12 @@
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use sys::pango as sys_pango;
use pango;
use render;
use color; use color;
use super::cell::Cell; use super::cell::Cell;
use super::item::Item; use super::item::Item;
use sys::pango as sys_pango;
use pango;
pub struct Line { pub struct Line {
pub line: Box<[Cell]>, pub line: Box<[Cell]>,
@ -242,8 +244,7 @@ pub struct StyledLine {
} }
impl StyledLine { impl StyledLine {
pub fn from(line: &Line, color_model: &color::ColorModel) -> Self { pub fn from(line: &Line, color_model: &color::ColorModel, font_features: &render::FontFeatures) -> Self {
let average_capacity = line.line.len() * 4 * 2; // code bytes * grapheme cluster let average_capacity = line.line.len() * 4 * 2; // code bytes * grapheme cluster
let mut line_str = String::with_capacity(average_capacity); let mut line_str = String::with_capacity(average_capacity);
@ -278,6 +279,7 @@ impl StyledLine {
} }
style_attr.insert(&attr_list); style_attr.insert(&attr_list);
font_features.insert_attr(&attr_list, line_str.len());
StyledLine { StyledLine {
line_str, line_str,
@ -410,7 +412,7 @@ mod tests {
line[1].ch = "b".to_owned(); line[1].ch = "b".to_owned();
line[2].ch = "c".to_owned(); line[2].ch = "c".to_owned();
let styled_line = StyledLine::from(&line, &color::ColorModel::new()); let styled_line = StyledLine::from(&line, &color::ColorModel::new(), &render::FontFeatures::new());
assert_eq!("abc", styled_line.line_str); assert_eq!("abc", styled_line.line_str);
assert_eq!(3, styled_line.cell_to_byte.len()); assert_eq!(3, styled_line.cell_to_byte.len());
assert_eq!(0, styled_line.cell_to_byte[0]); assert_eq!(0, styled_line.cell_to_byte[0]);