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:
parent
22ccd7b4b1
commit
e6c9c5036d
10 changed files with 130 additions and 50 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -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)",
|
||||
]
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue