aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2018-02-20 18:23:06 +0100
committerChristian Duerr <contact@christianduerr.com>2018-02-20 22:30:05 +0100
commit038899c5b3a0909a4a00116820c0d3619c1b22ed (patch)
treea78a2c31997e4cfad39ba4dad5a29917f971ce72
parent2466f81d5e0cb56dd00231f63f2dbcef1840196a (diff)
downloadalacritty-fontconfig.tar.gz
alacritty-fontconfig.zip
-rw-r--r--src/config/font.rs212
-rw-r--r--src/config/mod.rs (renamed from src/config.rs)194
-rw-r--r--src/font.rs43
-rw-r--r--src/renderer/mod.rs114
4 files changed, 283 insertions, 280 deletions
diff --git a/src/config/font.rs b/src/config/font.rs
new file mode 100644
index 00000000..2d3ae310
--- /dev/null
+++ b/src/config/font.rs
@@ -0,0 +1,212 @@
+// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use serde_yaml;
+use serde::{de, Deserialize};
+
+use config::{Delta, failure_default};
+use font::{Size, FontKey, Slant};
+
+// Global and local font configuration
+#[derive(Deserialize, Debug)]
+pub struct FontConfiguration {
+ #[serde(default, deserialize_with="failure_default")]
+ options: GlobalOptions,
+ #[serde(default, deserialize_with="deserialize_font_collection")]
+ fonts: Vec<Font>,
+}
+
+impl FontConfiguration {
+ pub fn font_by_char(&self, c: char, weight: Slant) -> FontKey {
+ for font in fonts {
+ let options = font.options();
+
+ // Skip font if font slant does not match requested slant
+ if options.unwrap_or(self.options as Options).style.unwrap_or(self.options.style) != weight {
+ continue;
+ }
+
+ let is_match = match options {
+ Some(options) => {
+ for range in options.ranges {
+ if range.start < c && range.end > c {
+ return true;
+ }
+ }
+ false
+ },
+ None => {
+ true
+ },
+ };
+
+ if is_match {
+ // TODO: Check if this font contains the char
+ }
+ }
+ }
+}
+
+impl Default for FontConfiguration {
+ fn default() -> Self {
+ Self {
+ fonts: vec!(Font::default()),
+ ..Default::default()
+ }
+ }
+}
+
+// Information about a font
+#[derive(Deserialize, Debug)]
+pub struct Font {
+ family: String,
+ #[serde(deserialize_with="failure_default")]
+ options: Option<Options>,
+}
+
+// Default font config in case of failure or missing config
+impl Default for Font {
+ #[cfg(target_os = "macos")]
+ fn default() -> Self {
+ Font {
+ family: "Menlo".into(),
+ options: None,
+ }
+ }
+
+ #[cfg(not(target_os = "macos"))]
+ fn default() -> Self {
+ Font {
+ family: "monospace".into(),
+ options: None,
+ }
+ }
+}
+
+// Options for a font
+#[derive(Deserialize, Debug)]
+pub struct Options {
+ #[serde(deserialize_with="deserialize_size")]
+ size: Option<Size>,
+ #[serde(deserialize_with="failure_default")]
+ thin_strokes: Option<bool>,
+ #[serde(deserialize_with="failure_default")]
+ antialias: Option<AntiAlias>,
+ #[serde(deserialize_with="failure_default")]
+ hinting: Option<bool>,
+ #[serde(deserialize_with="failure_default")]
+ style: Option<String>,
+ #[serde(deserialize_with="failure_default")]
+ offset: Option<Delta>,
+ #[serde(deserialize_with="failure_default")]
+ ranges: Vec<FontRange>,
+}
+
+impl Default for Options {
+ fn default() -> Self {
+ Options {
+ size: None,
+ thin_strokes: None,
+ antialias: None,
+ hinting: None,
+ style: None,
+ offset: None,
+ ranges: Vec::new(),
+ }
+ }
+}
+
+#[derive(Deserialize, Debug)]
+pub struct GlobalOptions(Options);
+impl Default for GlobalOptions {
+ fn default() -> Self {
+ GlobalOptions(Options {
+ size: Some(Size::new(12.0)),
+ thin_strokes: Some(true),
+ antialias: Some(AntiAlias::LCD),
+ hinting: Some(true),
+ style: Some("normal".into()),
+ offset: Some(Delta::default()),
+ ranges: Vec::new(),
+ })
+ }
+}
+
+// AntiAliasing settings for fonts
+#[derive(Deserialize, Debug)]
+pub enum AntiAlias {
+ LCD,
+ LCDV,
+ GRAY,
+ DISABLED,
+}
+
+// Range for which a specific font should be used
+#[derive(Deserialize, Debug)]
+pub struct FontRange {
+ #[serde(deserialize_with="failure_default")]
+ start: char,
+ #[serde(deserialize_with="failure_default")]
+ end: char,
+}
+
+// Deserialize the font vector
+fn deserialize_font_collection<'a, D>(deserializer: D)
+ -> ::std::result::Result<Vec<Font>, D::Error>
+ where D: de::Deserializer<'a>,
+{
+ // Deserialize vector as generic yaml value
+ let mut value = match serde_yaml::Value::deserialize(deserializer) {
+ Ok(value) => value,
+ Err(err) => {
+ eprintln!("problem with config: {}; Using default fonts", err);
+ return Ok(vec!(Font::default()));
+ },
+ };
+
+ // Get value as sequence
+ let sequence = match value.as_sequence_mut() {
+ Some(sequence) => sequence,
+ None => return Ok(vec!(Font::default())),
+ };
+
+ // Deserialize each element in the sequence
+ let mut font_collection = Vec::new();
+ for i in 0..sequence.len() {
+ match Font::deserialize(sequence.remove(i)) {
+ Ok(font) => font_collection.push(font),
+ // TODO: Print line or something like that?
+ Err(err) => eprintln!("problem with config: Malformed font; Skipping"),
+ }
+ }
+
+ // Return defaults if collection contains no font
+ if font_collection.is_empty() {
+ Ok(vec!(Font::default()))
+ } else {
+ Ok(font_collection)
+ }
+}
+
+// Deserialize font size
+fn deserialize_size<'a, D>(deserializer: D)
+ -> ::std::result::Result<Option<Size>, D::Error>
+ where D: de::Deserializer<'a>,
+{
+ match f32::deserialize(deserializer) {
+ Ok(value) => Ok(Some(Size::new(value))),
+ _ => {
+ Ok(None)
+ },
+ }
+}
diff --git a/src/config.rs b/src/config/mod.rs
index be967150..b3400b7d 100644
--- a/src/config.rs
+++ b/src/config/mod.rs
@@ -3,6 +3,8 @@
//! Alacritty reads from a config file at startup to determine various runtime
//! parameters including font family and style, font size, etc. In the future,
//! the config file will also hold user and platform specific keybindings.
+pub mod font;
+
use std::borrow::Cow;
use std::{env, fmt};
use std::fs::{self, File};
@@ -14,15 +16,15 @@ use std::time::Duration;
use std::collections::HashMap;
use ::Rgb;
-use font::Size;
use serde_yaml;
-use serde::{self, de, Deserialize};
+use serde::{de, Deserialize};
use serde::de::Error as SerdeError;
use serde::de::{Visitor, MapAccess, Unexpected};
use notify::{Watcher, watcher, DebouncedEvent, RecursiveMode};
use glutin::ModifiersState;
+use self::font::FontConfiguration;
use input::{Action, Binding, MouseBinding, KeyBinding};
use index::{Line, Column};
use ansi::CursorStyle;
@@ -326,7 +328,7 @@ pub struct Config {
/// Font configuration
#[serde(default, deserialize_with = "failure_default")]
- font: Font,
+ font: FontConfiguration,
/// Should show render timer
#[serde(default, deserialize_with = "failure_default")]
@@ -453,7 +455,7 @@ fn default_true_bool<'a, D>(deserializer: D) -> ::std::result::Result<bool, D::E
}
}
-fn failure_default<'a, D, T>(deserializer: D)
+pub fn failure_default<'a, D, T>(deserializer: D)
-> ::std::result::Result<T, D::Error>
where D: de::Deserializer<'a>,
T: Deserialize<'a> + Default
@@ -467,10 +469,8 @@ fn failure_default<'a, D, T>(deserializer: D)
}
}
-#[cfg(not(target_os="macos"))]
-static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty.yml");
-#[cfg(target_os="macos")]
-static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty_macos.yml");
+static DEFAULT_ALACRITTY_CONFIG: &'static str =
+ include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty.yml"));
impl Default for Config {
fn default() -> Self {
@@ -1295,12 +1295,6 @@ impl Config {
self.draw_bold_text_with_bright_colors
}
- /// Get font config
- #[inline]
- pub fn font(&self) -> &Font {
- &self.font
- }
-
/// Get window dimensions
#[inline]
pub fn dimensions(&self) -> Dimensions {
@@ -1325,11 +1319,6 @@ impl Config {
self.render_timer
}
- #[inline]
- pub fn use_thin_strokes(&self) -> bool {
- self.font.use_thin_strokes
- }
-
/// show cursor as inverted
#[inline]
pub fn custom_cursor_colors(&self) -> bool {
@@ -1464,173 +1453,6 @@ impl Default for Delta {
}
}
-trait DeserializeSize : Sized {
- fn deserialize<'a, D>(D) -> ::std::result::Result<Self, D::Error>
- where D: serde::de::Deserializer<'a>;
-}
-
-impl DeserializeSize for Size {
- fn deserialize<'a, D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: serde::de::Deserializer<'a>
- {
- use std::marker::PhantomData;
-
- struct NumVisitor<__D> {
- _marker: PhantomData<__D>,
- }
-
- impl<'a, __D> Visitor<'a> for NumVisitor<__D>
- where __D: serde::de::Deserializer<'a>
- {
- type Value = f64;
-
- fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.write_str("f64 or u64")
- }
-
- fn visit_f64<E>(self, value: f64) -> ::std::result::Result<Self::Value, E>
- where E: ::serde::de::Error
- {
- Ok(value)
- }
-
- fn visit_u64<E>(self, value: u64) -> ::std::result::Result<Self::Value, E>
- where E: ::serde::de::Error
- {
- Ok(value as f64)
- }
- }
-
- let size = deserializer
- .deserialize_any(NumVisitor::<D>{ _marker: PhantomData })
- .map(|v| Size::new(v as _));
-
- // Use font size 12 as fallback
- match size {
- Ok(size) => Ok(size),
- Err(err) => {
- eprintln!("problem with config: {}; Using size 12", err);
- Ok(Size::new(12.))
- },
- }
- }
-}
-
-/// Font config
-///
-/// Defaults are provided at the level of this struct per platform, but not per
-/// field in this struct. It might be nice in the future to have defaults for
-/// each value independently. Alternatively, maybe erroring when the user
-/// doesn't provide complete config is Ok.
-#[derive(Debug, Deserialize, Clone)]
-pub struct Font {
- /// Font family
- pub normal: FontDescription,
-
- #[serde(default="default_italic_desc")]
- pub italic: FontDescription,
-
- #[serde(default="default_bold_desc")]
- pub bold: FontDescription,
-
- // Font size in points
- #[serde(deserialize_with="DeserializeSize::deserialize")]
- pub size: Size,
-
- /// Extra spacing per character
- #[serde(default, deserialize_with = "failure_default")]
- offset: Delta,
-
- /// Glyph offset within character cell
- #[serde(default, deserialize_with = "failure_default")]
- glyph_offset: Delta,
-
- #[serde(default="true_bool", deserialize_with = "default_true_bool")]
- use_thin_strokes: bool
-}
-
-fn default_bold_desc() -> FontDescription {
- Font::default().bold
-}
-
-fn default_italic_desc() -> FontDescription {
- Font::default().italic
-}
-
-/// Description of a single font
-#[derive(Debug, Deserialize, Clone)]
-pub struct FontDescription {
- pub family: String,
- pub style: Option<String>,
-}
-
-impl FontDescription {
- fn new_with_family<S: Into<String>>(family: S) -> FontDescription {
- FontDescription {
- family: family.into(),
- style: None,
- }
- }
-}
-
-impl Font {
- /// Get the font size in points
- #[inline]
- pub fn size(&self) -> Size {
- self.size
- }
-
- /// Get offsets to font metrics
- #[inline]
- pub fn offset(&self) -> &Delta {
- &self.offset
- }
-
- /// Get cell offsets for glyphs
- #[inline]
- pub fn glyph_offset(&self) -> &Delta {
- &self.glyph_offset
- }
-
- /// Get a font clone with a size modification
- pub fn with_size(self, size: Size) -> Font {
- Font {
- size,
- .. self
- }
- }
-}
-
-#[cfg(target_os = "macos")]
-impl Default for Font {
- fn default() -> Font {
- Font {
- normal: FontDescription::new_with_family("Menlo"),
- bold: FontDescription::new_with_family("Menlo"),
- italic: FontDescription::new_with_family("Menlo"),
- size: Size::new(11.0),
- use_thin_strokes: true,
- offset: Default::default(),
- glyph_offset: Default::default()
- }
- }
-}
-
-#[cfg(any(target_os = "linux",target_os = "freebsd"))]
-impl Default for Font {
- fn default() -> Font {
- Font {
- normal: FontDescription::new_with_family("monospace"),
- bold: FontDescription::new_with_family("monospace"),
- italic: FontDescription::new_with_family("monospace"),
- size: Size::new(11.0),
- use_thin_strokes: false,
- offset: Default::default(),
- glyph_offset: Default::default()
- }
- }
-}
-
pub struct Monitor {
_thread: ::std::thread::JoinHandle<()>,
rx: mpsc::Receiver<Config>,
diff --git a/src/font.rs b/src/font.rs
new file mode 100644
index 00000000..5d80b97c
--- /dev/null
+++ b/src/font.rs
@@ -0,0 +1,43 @@
+// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use config::Delta;
+use font::Size;
+
+struct Font {
+ family: String,
+ options: Option<Options>,
+}
+
+enum AntiAlias {
+ LCD,
+ LCDV,
+ GRAY,
+ // TODO: Maybe change the name so it's not confused with Rust's None?
+ NONE,
+}
+
+struct Options {
+ size: Option<Size>,
+ thin_strokes: Option<bool>,
+ antialias: Option<AntiAlias>,
+ hinting: Option<bool>,
+ style: Option<String>,
+ offset: Option<Delta>,
+ range: Option<FontRange>,
+}
+
+struct FontRange {
+ start: char,
+ end: char,
+}
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index c0e4a9f3..9119802e 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -30,6 +30,7 @@ use index::{Line, Column, RangeInclusive};
use notify::{Watcher, watcher, RecursiveMode, DebouncedEvent};
use config::{self, Config, Delta};
+use config::font::FontConfiguration;
use term::{self, cell, RenderableCell};
use window::{Size, Pixels};
@@ -152,124 +153,47 @@ pub struct GlyphCache {
/// Rasterizer for loading new glyphs
rasterizer: Rasterizer,
- /// regular font
- font_key: FontKey,
-
- /// italic font
- italic_key: FontKey,
-
- /// bold font
- bold_key: FontKey,
-
- /// font size
- font_size: font::Size,
-
- /// glyph offset
- glyph_offset: Delta,
+ /// Font configuration with all fonts
+ font_config: FontConfiguration,
+ /// Font metrics like glyph width/height
metrics: ::font::Metrics,
}
impl GlyphCache {
pub fn new<L>(
mut rasterizer: Rasterizer,
- font: &config::Font,
+ font_config: FontConfiguration,
loader: &mut L
) -> Result<GlyphCache, font::Error>
where L: LoadGlyph
{
- let (regular, bold, italic) = Self::compute_font_keys(font, &mut rasterizer)?;
-
// Need to load at least one glyph for the face before calling metrics.
- // The glyph requested here ('m' at the time of writing) has no special
+ // The glyph requested here ('0' at the time of writing) has no special
// meaning.
- rasterizer.get_glyph(&GlyphKey { font_key: regular, c: 'm', size: font.size() })?;
+ let primary_font = font_config.font_by_char('0');
+ rasterizer.get_glyph(&GlyphKey { font_key: primary_font, c: '0', size: primary_font.size() })?;
let metrics = rasterizer.metrics(regular)?;
let mut cache = GlyphCache {
cache: HashMap::default(),
- rasterizer: rasterizer,
- font_size: font.size(),
- font_key: regular,
- bold_key: bold,
- italic_key: italic,
- glyph_offset: *font.glyph_offset(),
- metrics: metrics
+ metrics,
+ rasterizer,
+ font_config,
};
- cache.load_glyphs_for_font(regular, loader);
- cache.load_glyphs_for_font(bold, loader);
- cache.load_glyphs_for_font(italic, loader);
+ // TODO: Load set of standard glyphs
+ // cache.load_glyphs_for_font(regular, loader);
+ // cache.load_glyphs_for_font(bold, loader);
+ // cache.load_glyphs_for_font(italic, loader);
Ok(cache)
}
- fn load_glyphs_for_font<L: LoadGlyph>(
- &mut self,
- font: FontKey,
- loader: &mut L,
- ) {
- let size = self.font_size;
- for i in RangeInclusive::new(32u8, 128u8) {
- self.get(&GlyphKey {
- font_key: font,
- c: i as char,
- size: size
- }, loader);
- }
- }
-
- /// Computes font keys for (Regular, Bold, Italic)
- fn compute_font_keys(
- font: &config::Font,
- rasterizer: &mut Rasterizer
- ) -> Result<(FontKey, FontKey, FontKey), font::Error> {
- let size = font.size();
-
- // Load regular font
- let regular_desc = Self::make_desc(&font.normal, font::Slant::Normal, font::Weight::Normal);
-
- let regular = rasterizer
- .load_font(&regular_desc, size)?;
-
- // helper to load a description if it is not the regular_desc
- let mut load_or_regular = |desc:FontDesc| {
- if desc == regular_desc {
- regular
- } else {
- rasterizer.load_font(&desc, size).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);
-
- // Load italic font
- let italic_desc = Self::make_desc(&font.italic, font::Slant::Italic, font::Weight::Normal);
-
- let italic = load_or_regular(italic_desc);
-
- Ok((regular, bold, italic))
- }
-
- fn make_desc(
- desc: &config::FontDescription,
- slant: font::Slant,
- weight: font::Weight,
- ) -> FontDesc {
- let style = if let Some(ref spec) = desc.style {
- font::Style::Specific(spec.to_owned())
- } else {
- font::Style::Description {slant:slant, weight:weight}
- };
- FontDesc::new(&desc.family[..], style)
- }
-
pub fn font_metrics(&self) -> font::Metrics {
+ let primary_font = self.font_config.font_by_char('0');
self.rasterizer
- .metrics(self.font_key)
+ .metrics(primary_font)
.expect("metrics load since font is loaded at glyph cache creation")
}
@@ -292,9 +216,11 @@ impl GlyphCache {
loader.load_glyph(&rasterized)
})
}
+
+ // TODO
pub fn update_font_size<L: LoadGlyph>(
&mut self,
- font: &config::Font,
+ font: &FontConfiguration,
size: font::Size,
loader: &mut L
) -> Result<(), font::Error> {