1
0
Fork 0
mirror of https://github.com/alacritty/alacritty.git synced 2024-11-18 13:55:23 -05:00

[WIP] Add antialias option

Still a WIP because of unimplemented Linux portion.

Support has been added for font rasterization options. At this time, the
only supported option is antialias. It's a tri-state flag which can be
either ~ for "use default", true to force antialias, and false to force
disable antialias.

The options may be specified both globally and per font section. The per
font sections override global options. An example of a complex config
follows. In the example, the global value requests using default
antialias settings, and the normal face disables antialias.

    font:
      options:
        antialias: ~
      normal:
        family: monospace
        options:
          antialias: false

Finally, note that the top level font.options is used for fallback
fonts.
This commit is contained in:
Joe Wilm 2017-10-26 20:01:17 -07:00
parent 22ccd7b4b1
commit e6c9c5036d
10 changed files with 130 additions and 50 deletions

2
Cargo.lock generated
View file

@ -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)",
]

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -5,11 +5,16 @@ authors = ["Joe Wilm <joe@jwilm.com>"]
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"

View file

@ -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<Rasterizer, Error> {
fn new(
options: Options,
device_pixel_ratio: f32,
use_thin_strokes: bool
) -> Result<Rasterizer, Error> {
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<FontKey, Error> {
fn load_font(
&mut self,
desc: &FontDesc,
size: Size,
font_options: &Options,
) -> Result<FontKey, Error> {
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<Font, Error> {
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<Font, Error> {
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<Font, Error> {
fn get_font(&mut self, desc: &FontDesc, size: Size, options: Options) -> Result<Font, Error> {
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<Font>,
antialias: bool,
}
unsafe impl Send for Font {}
@ -370,31 +389,15 @@ pub fn descriptors_for_family(family: &str) -> Vec<Descriptor> {
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::<Vec<_>>();
for font in fonts {

View file

@ -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<bool>,
}
#[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<Self, Self::Err>
fn new(_: Options, device_pixel_ratio: f32, use_thin_strokes: bool) -> Result<Self, Self::Err>
where Self: Sized;
/// Get `Metrics` for the given `FontKey`
fn metrics(&self, FontKey) -> Result<Metrics, Self::Err>;
/// Load the font described by `FontDesc` and `Size`
fn load_font(&mut self, &FontDesc, Size) -> Result<FontKey, Self::Err>;
fn load_font(&mut self, &FontDesc, Size, &Options) -> Result<FontKey, Self::Err>;
/// Rasterize the glyph described by `GlyphKey`.
fn get_glyph(&mut self, &GlyphKey) -> Result<RasterizedGlyph, Self::Err>;
}
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
}
}

View file

@ -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<String>,
/// 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"),

View file

@ -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 = {

View file

@ -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(&regular_desc, size)?;
.load_font(&regular_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))
}