diff --git a/Cargo.lock b/Cargo.lock index 61404aeb..faab4cb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -373,6 +373,8 @@ dependencies = [ "freetype-rs 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "servo-fontconfig 0.4.0 (git+https://github.com/jwilm/rust-fontconfig?branch=updated-2017-10-8)", ] diff --git a/Cargo.toml b/Cargo.toml index e983e3a2..97a84487 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ libc = "0.2.30" cgmath = "0.15" notify = "4" bitflags = "0.9.1" -font = { path = "./font" } +font = { path = "./font", features = ["with-serde"] } errno = "0.2.3" parking_lot = "0.4.5" serde = "1" diff --git a/alacritty.yml b/alacritty.yml index d2607051..d1607fc1 100644 --- a/alacritty.yml +++ b/alacritty.yml @@ -53,21 +53,31 @@ draw_bold_text_with_bright_colors: true # * https://wiki.archlinux.org/index.php/font_configuration#Fontconfig_configuration # * file:///usr/share/doc/fontconfig/fontconfig-user.html font: + # Default rasterization options + # + # These settings are used for fallback fonts *and* for normal/bold/italic + # fonts when they don't specify their own `options`. + # + # If you prefer to respect fontconfig settings, set the value of these + # properties to ~. + options: + antialias: true + # The normal (roman) font face to use. normal: - family: monospace # should be "Menlo" or something on macOS. + family: monospace # Style can be specified to pick a specific face. # style: Regular # The bold font face bold: - family: monospace # should be "Menlo" or something on macOS. + family: monospace # Style can be specified to pick a specific face. # style: Bold # The italic font face italic: - family: monospace # should be "Menlo" or something on macOS. + family: monospace # Style can be specified to pick a specific face. # style: Italic diff --git a/alacritty_macos.yml b/alacritty_macos.yml index 761542a1..0b7c5130 100644 --- a/alacritty_macos.yml +++ b/alacritty_macos.yml @@ -34,6 +34,13 @@ draw_bold_text_with_bright_colors: true # Font configuration (changes require restart) font: + # Default rasterization options + # + # These settings are used for fallback fonts *and* for normal/bold/italic + # fonts when they don't specify their own `options`. + options: + antialias: true + # The normal (roman) font face to use. normal: family: Menlo diff --git a/font/Cargo.toml b/font/Cargo.toml index 2a97f0bd..e67cdaf2 100644 --- a/font/Cargo.toml +++ b/font/Cargo.toml @@ -5,11 +5,16 @@ authors = ["Joe Wilm "] description = "Font rendering using the best available solution per platform" license = "Apache-2.0" +[features] +with-serde = ["serde", "serde_derive"] + [dependencies] euclid = "0.12.0" libc = "0.2" foreign-types = "0.2.0" log = "0.3" +serde = { version = "1", optional = true } +serde_derive = { version = "1", optional = true } [target.'cfg(not(target_os = "macos"))'.dependencies] servo-fontconfig = { git = "https://github.com/jwilm/rust-fontconfig", branch = "updated-2017-10-8" } @@ -20,3 +25,4 @@ core-foundation = "0.3.0" core-text = "6.1.0" core-graphics = "0.8.1" core-foundation-sys = "0.3.1" + diff --git a/font/src/darwin/mod.rs b/font/src/darwin/mod.rs index 70b9e1f3..73a91565 100644 --- a/font/src/darwin/mod.rs +++ b/font/src/darwin/mod.rs @@ -43,6 +43,7 @@ use euclid::rect::Rect; use euclid::size::Size2D; use super::{FontDesc, RasterizedGlyph, Metrics, FontKey, GlyphKey}; +use ::Options; pub mod byte_order; use self::byte_order::kCGBitmapByteOrder32Host; @@ -85,6 +86,7 @@ pub struct Rasterizer { keys: HashMap<(FontDesc, Size), FontKey>, device_pixel_ratio: f32, use_thin_strokes: bool, + options: ::Options, } /// Errors occurring when using the core text rasterizer @@ -130,13 +132,18 @@ impl ::std::fmt::Display for Error { impl ::Rasterize for Rasterizer { type Err = Error; - fn new(device_pixel_ratio: f32, use_thin_strokes: bool) -> Result { + fn new( + options: Options, + device_pixel_ratio: f32, + use_thin_strokes: bool + ) -> Result { info!("device_pixel_ratio: {}", device_pixel_ratio); Ok(Rasterizer { fonts: HashMap::new(), keys: HashMap::new(), device_pixel_ratio: device_pixel_ratio, use_thin_strokes: use_thin_strokes, + options: options, }) } @@ -149,12 +156,18 @@ impl ::Rasterize for Rasterizer { Ok(font.metrics()) } - fn load_font(&mut self, desc: &FontDesc, size: Size) -> Result { + fn load_font( + &mut self, + desc: &FontDesc, + size: Size, + font_options: &Options, + ) -> Result { self.keys .get(&(desc.to_owned(), size)) .map(|k| Ok(*k)) .unwrap_or_else(|| { - let mut font = self.get_font(desc, size)?; + let options = self.options.clone().merge(&font_options); + let mut font = self.get_font(desc, size, options)?; // TODO, we can't use apple's proposed // .Apple Symbol Fallback (filtered out below), @@ -166,7 +179,8 @@ impl ::Rasterize for Rasterizer { let symbols = { let fallback_style = Style::Description { slant:Slant::Normal, weight:Weight::Normal } ; let d = FontDesc::new("Apple Symbols".to_owned(), fallback_style); - self.get_font(&d, size)? + let options = self.options.clone(); + self.get_font(&d, size, options)? }; font.fallbacks.push(symbols); } @@ -209,14 +223,16 @@ impl Rasterizer { &mut self, desc: &FontDesc, style: &str, - size: Size + size: Size, + options: Options, ) -> Result { let descriptors = descriptors_for_family(&desc.name[..]); for descriptor in descriptors { if descriptor.style_name == style { // Found the font we want let scaled_size = size.as_f32_pts() as f64 * self.device_pixel_ratio as f64; - let font = descriptor.to_font(scaled_size, true); + let mut font = descriptor.to_font(scaled_size, options); + font.load_fallbacks(scaled_size, &self.options); return Ok(font); } } @@ -229,7 +245,8 @@ impl Rasterizer { desc: &FontDesc, slant: Slant, weight: Weight, - size: Size + size: Size, + options: Options, ) -> Result { let bold = match weight { Weight::Bold => true, @@ -243,7 +260,8 @@ impl Rasterizer { let descriptors = descriptors_for_family(&desc.name[..]); for descriptor in descriptors { - let font = descriptor.to_font(scaled_size, true); + let mut font = descriptor.to_font(scaled_size, options.clone()); + font.load_fallbacks(scaled_size, &self.options); if font.is_bold() == bold && font.is_italic() == italic { // Found the font we want return Ok(font); @@ -253,11 +271,11 @@ impl Rasterizer { Err(Error::MissingFont(desc.to_owned())) } - fn get_font(&mut self, desc: &FontDesc, size: Size) -> Result { + fn get_font(&mut self, desc: &FontDesc, size: Size, options: Options) -> Result { match desc.style { - Style::Specific(ref style) => self.get_specific_face(desc, style, size), + Style::Specific(ref style) => self.get_specific_face(desc, style, size, options), Style::Description { slant, weight } => { - self.get_matching_face(desc, slant, weight, size) + self.get_matching_face(desc, slant, weight, size, options) }, } } @@ -299,6 +317,7 @@ pub struct Font { ct_font: CTFont, cg_font: CGFont, fallbacks: Vec, + antialias: bool, } unsafe impl Send for Font {} @@ -370,31 +389,15 @@ pub fn descriptors_for_family(family: &str) -> Vec { impl Descriptor { /// Create a Font from this descriptor - pub fn to_font(&self, size: f64, load_fallbacks:bool) -> Font { + pub fn to_font(&self, size: f64, options: Options) -> Font { let ct_font = ct_new_from_descriptor(&self.ct_descriptor, size); let cg_font = ct_font.copy_to_CGFont(); - let fallbacks = if load_fallbacks { - // TODO fixme, hardcoded en for english - cascade_list_for_languages(&ct_font, &vec!["en".to_owned()]) - .into_iter() - // the system lists contains (at least) two strange fonts: - // .Apple Symbol Fallback - // .Noto Sans Universal - // both have a .-prefix (to indicate they are internal?) - // neither work very well. the latter even breaks things because - // it defines code points with just [?] glyphs. - .filter(|desc| desc.font_path != "") - .map(|desc| desc.to_font(size, false)) - .collect() - } else { - vec![] - }; - Font { ct_font: ct_font, cg_font: cg_font, - fallbacks: fallbacks, + fallbacks: Vec::new(), + antialias: options.antialias.unwrap_or(true), } } } @@ -505,12 +508,12 @@ impl Font { cg_context.set_allows_font_smoothing(true); cg_context.set_should_smooth_fonts(true); - cg_context.set_allows_font_subpixel_quantization(true); - cg_context.set_should_subpixel_quantize_fonts(true); - cg_context.set_allows_font_subpixel_positioning(true); - cg_context.set_should_subpixel_position_fonts(true); - cg_context.set_allows_antialiasing(true); - cg_context.set_should_antialias(true); + cg_context.set_allows_font_subpixel_quantization(self.antialias); + cg_context.set_should_subpixel_quantize_fonts(self.antialias); + cg_context.set_allows_font_subpixel_positioning(self.antialias); + cg_context.set_should_subpixel_position_fonts(self.antialias); + cg_context.set_allows_antialiasing(self.antialias); + cg_context.set_should_antialias(self.antialias); // Set fill color to white for drawing the glyph cg_context.set_rgb_fill_color(1.0, 1.0, 1.0, 1.0); @@ -563,6 +566,21 @@ impl Font { None } } + + pub fn load_fallbacks(&mut self, size: f64, options: &Options) { + // TODO fixme, hardcoded en for english + self.fallbacks = cascade_list_for_languages(&self.ct_font, &vec!["en".to_owned()]) + .into_iter() + // the system lists contains (at least) two strange fonts: + // .Apple Symbol Fallback + // .Noto Sans Universal + // both have a .-prefix (to indicate they are internal?) + // neither work very well. the latter even breaks things because + // it defines code points with just [?] glyphs. + .filter(|desc| desc.font_path != "") + .map(|desc| desc.to_font(size, options.clone())) + .collect() + } } #[cfg(test)] @@ -582,7 +600,7 @@ mod tests { // Check to_font let fonts = list.iter() - .map(|desc| desc.to_font(72., false)) + .map(|desc| desc.to_font(72., &Default::default())) .collect::>(); for font in fonts { diff --git a/font/src/lib.rs b/font/src/lib.rs index 513dacdd..18ef1949 100644 --- a/font/src/lib.rs +++ b/font/src/lib.rs @@ -33,6 +33,12 @@ extern crate core_graphics; #[cfg(target_os = "macos")] extern crate euclid; +#[cfg(feature = "with-serde")] +extern crate serde; +#[cfg_attr(feature = "with-serde", macro_use)] +#[cfg(feature = "with-serde")] +extern crate serde_derive; + extern crate libc; #[cfg(not(target_os = "macos"))] @@ -58,6 +64,12 @@ mod darwin; #[cfg(target_os = "macos")] pub use darwin::*; +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature="with-serde", derive(Deserialize))] +pub struct Options { + antialias: Option, +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FontDesc { name: String, @@ -237,15 +249,26 @@ pub trait Rasterize { type Err: ::std::error::Error + Send + Sync + 'static; /// Create a new Rasterize - fn new(device_pixel_ratio: f32, use_thin_strokes: bool) -> Result + fn new(_: Options, device_pixel_ratio: f32, use_thin_strokes: bool) -> Result where Self: Sized; /// Get `Metrics` for the given `FontKey` fn metrics(&self, FontKey) -> Result; /// Load the font described by `FontDesc` and `Size` - fn load_font(&mut self, &FontDesc, Size) -> Result; + fn load_font(&mut self, &FontDesc, Size, &Options) -> Result; /// Rasterize the glyph described by `GlyphKey`. fn get_glyph(&mut self, &GlyphKey) -> Result; } + +impl Options { + /// Merge options from other into self. Values defined in both self and + /// other will prefer other. + pub fn merge(mut self, other: &Options) -> Self { + let default = self.antialias.take(); + self.antialias = other.antialias.or(default); + + self + } +} diff --git a/src/config.rs b/src/config.rs index 3f3b6942..8f4f4450 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,7 +14,7 @@ use std::time::Duration; use std::collections::HashMap; use ::Rgb; -use font::Size; +use font::{self, Size}; use serde_yaml; use serde::{self, de, Deserialize}; use serde::de::Error as SerdeError; @@ -1305,6 +1305,10 @@ impl DeserializeFromF32 for Size { /// doesn't provide complete config is Ok. #[derive(Debug, Deserialize, Clone)] pub struct Font { + /// Default font rasterization options + #[serde(default)] + pub options: font::Options, + /// Font family pub normal: FontDescription, @@ -1342,6 +1346,9 @@ fn default_italic_desc() -> FontDescription { pub struct FontDescription { pub family: String, pub style: Option, + /// Rasterization options for this font. + #[serde(default)] + pub options: font::Options, } impl FontDescription { @@ -1349,6 +1356,7 @@ impl FontDescription { FontDescription { family: family.into(), style: None, + options: Default::default(), } } } @@ -1389,6 +1397,7 @@ impl Font { impl Default for Font { fn default() -> Font { Font { + options: Default::default(), normal: FontDescription::new_with_family("Menlo"), bold: FontDescription::new_with_family("Menlo"), italic: FontDescription::new_with_family("Menlo"), @@ -1404,6 +1413,7 @@ impl Default for Font { impl Default for Font { fn default() -> Font { Font { + options: Default::default(), normal: FontDescription::new_with_family("monospace"), bold: FontDescription::new_with_family("monospace"), italic: FontDescription::new_with_family("monospace"), diff --git a/src/display.rs b/src/display.rs index fc5a5d40..52207ac1 100644 --- a/src/display.rs +++ b/src/display.rs @@ -212,7 +212,11 @@ impl Display { { let font = config.font().clone().with_size_delta(font_size_delta as f32); let dpr = window.hidpi_factor(); - let rasterizer = font::Rasterizer::new(dpr, config.use_thin_strokes())?; + let rasterizer = font::Rasterizer::new( + font.options.clone(), + dpr, + config.use_thin_strokes() + )?; // Initialize glyph cache let glyph_cache = { diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index bb025875..7c970232 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -230,26 +230,26 @@ impl GlyphCache { let regular_desc = Self::make_desc(&font.normal, font::Slant::Normal, font::Weight::Normal); let regular = rasterizer - .load_font(®ular_desc, size)?; + .load_font(®ular_desc, size, &font.normal.options)?; // helper to load a description if it is not the regular_desc - let mut load_or_regular = |desc:FontDesc| { + let mut load_or_regular = |desc:FontDesc, options:&font::Options| { if desc == regular_desc { regular } else { - rasterizer.load_font(&desc, size).unwrap_or_else(|_| regular) + rasterizer.load_font(&desc, size, options).unwrap_or_else(|_| regular) } }; // Load bold font let bold_desc = Self::make_desc(&font.bold, font::Slant::Normal, font::Weight::Bold); - let bold = load_or_regular(bold_desc); + let bold = load_or_regular(bold_desc, &font.bold.options); // Load italic font let italic_desc = Self::make_desc(&font.italic, font::Slant::Italic, font::Weight::Normal); - let italic = load_or_regular(italic_desc); + let italic = load_or_regular(italic_desc, &font.italic.options); Ok((regular, bold, italic)) }