summaryrefslogtreecommitdiffstats
path: root/font
diff options
context:
space:
mode:
authorZac Pullar-Strecker <zacps@users.noreply.github.com>2018-10-17 06:02:52 +1300
committerJoe Wilm <jwilm@users.noreply.github.com>2018-10-16 10:02:52 -0700
commit15e0deae2b49078b47a782679300cdf99d9ce687 (patch)
tree8175fbed0def1af08cd2db41583975adbb27dff1 /font
parentb41c6b736d67d61e92b174dfea58ae46813934cd (diff)
Add support for Windows (#1374)
Initial support for Windows is implemented using the winpty translation layer. Clipboard support for Windows is provided through the `clipboard` crate, and font rasterization is provided by RustType. The tty.rs file has been split into OS-specific files to separate standard pty handling from the winpty implementation. Several binary components are fetched via build script on windows including libclang and winpty. These could be integrated more directly in the future either by building those dependencies as part of the Alacritty build process or by leveraging git lfs to store the artifacts. Fixes #28.
Diffstat (limited to 'font')
-rw-r--r--font/Cargo.toml6
-rw-r--r--font/src/darwin/mod.rs2
-rw-r--r--font/src/ft/mod.rs2
-rw-r--r--font/src/lib.rs41
-rw-r--r--font/src/rusttype/mod.rs151
5 files changed, 182 insertions, 20 deletions
diff --git a/font/Cargo.toml b/font/Cargo.toml
index a0c524b8..307153f6 100644
--- a/font/Cargo.toml
+++ b/font/Cargo.toml
@@ -11,7 +11,7 @@ libc = "0.2"
foreign-types = "0.3"
log = "0.4"
-[target.'cfg(not(target_os = "macos"))'.dependencies]
+[target.'cfg(not(any(target_os = "macos", windows)))'.dependencies]
servo-fontconfig = "0.4.0"
freetype-rs = "0.19"
@@ -20,3 +20,7 @@ core-foundation = "0.6"
core-text = "13"
core-graphics = "0.17"
core-foundation-sys = "0.6"
+
+[target.'cfg(windows)'.dependencies]
+font-loader = "0.6.0"
+rusttype = "0.4.1"
diff --git a/font/src/darwin/mod.rs b/font/src/darwin/mod.rs
index c688c53d..bdcbbdfa 100644
--- a/font/src/darwin/mod.rs
+++ b/font/src/darwin/mod.rs
@@ -139,7 +139,7 @@ impl ::Rasterize for Rasterizer {
}
/// Get metrics for font specified by FontKey
- fn metrics(&self, key: FontKey) -> Result<Metrics, Error> {
+ fn metrics(&self, key: FontKey, _size: Size) -> Result<Metrics, Error> {
let font = self.fonts
.get(&key)
.ok_or(Error::FontNotLoaded)?;
diff --git a/font/src/ft/mod.rs b/font/src/ft/mod.rs
index 51c304f2..55409174 100644
--- a/font/src/ft/mod.rs
+++ b/font/src/ft/mod.rs
@@ -85,7 +85,7 @@ impl ::Rasterize for FreeTypeRasterizer {
})
}
- fn metrics(&self, key: FontKey) -> Result<Metrics, Error> {
+ fn metrics(&self, key: FontKey, _size: Size) -> Result<Metrics, Error> {
let full = self.full_metrics(key)?;
let height = (full.size_metrics.height / 64) as f64;
diff --git a/font/src/lib.rs b/font/src/lib.rs
index fe9e9e85..5fb50217 100644
--- a/font/src/lib.rs
+++ b/font/src/lib.rs
@@ -20,40 +20,45 @@
#![cfg_attr(feature = "cargo-clippy", deny(clippy, if_not_else, enum_glob_use, wrong_pub_self_convention))]
-#[cfg(not(target_os = "macos"))]
+#[cfg(not(any(target_os = "macos", windows)))]
extern crate fontconfig;
-#[cfg(not(target_os = "macos"))]
+#[cfg(not(any(target_os = "macos", windows)))]
extern crate freetype;
#[cfg(target_os = "macos")]
-extern crate core_text;
-#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_foundation_sys;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(target_os = "macos")]
+extern crate core_text;
+#[cfg(target_os = "macos")]
extern crate euclid;
extern crate libc;
-#[cfg(not(target_os = "macos"))]
+#[cfg(not(any(target_os = "macos", windows)))]
#[macro_use]
extern crate foreign_types;
-#[macro_use]
+#[cfg_attr(not(windows), macro_use)]
extern crate log;
use std::hash::{Hash, Hasher};
use std::{fmt, cmp};
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
-// If target isn't macos, reexport everything from ft
-#[cfg(not(target_os = "macos"))]
+// If target isn't macos or windows, reexport everything from ft
+#[cfg(not(any(target_os = "macos", windows)))]
pub mod ft;
-#[cfg(not(target_os = "macos"))]
-pub use ft::{FreeTypeRasterizer as Rasterizer, Error};
+#[cfg(not(any(target_os = "macos", windows)))]
+pub use ft::{Error, FreeTypeRasterizer as Rasterizer};
+
+#[cfg(windows)]
+pub mod rusttype;
+#[cfg(windows)]
+pub use rusttype::{Error, RustTypeRasterizer as Rasterizer};
// If target is macos, reexport everything from darwin
#[cfg(target_os = "macos")]
@@ -92,14 +97,14 @@ pub enum Slant {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Weight {
Normal,
- Bold
+ Bold,
}
/// Style of font
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Style {
Specific(String),
- Description { slant: Slant, weight: Weight }
+ Description { slant: Slant, weight: Weight },
}
impl fmt::Display for Style {
@@ -108,14 +113,15 @@ impl fmt::Display for Style {
Style::Specific(ref s) => f.write_str(&s),
Style::Description { slant, weight } => {
write!(f, "slant={:?}, weight={:?}", slant, weight)
- },
+ }
}
}
}
impl FontDesc {
pub fn new<S>(name: S, style: Style) -> FontDesc
- where S: Into<String>
+ where
+ S: Into<String>,
{
FontDesc {
name: name.into(),
@@ -336,12 +342,13 @@ pub trait Rasterize {
/// Errors occurring in Rasterize methods
type Err: ::std::error::Error + Send + Sync + 'static;
- /// Create a new Rasterize
+ /// Create a new Rasterizer
fn new(device_pixel_ratio: f32, use_thin_strokes: bool) -> Result<Self, Self::Err>
- where Self: Sized;
+ where
+ Self: Sized;
/// Get `Metrics` for the given `FontKey`
- fn metrics(&self, FontKey) -> Result<Metrics, Self::Err>;
+ fn metrics(&self, FontKey, Size) -> Result<Metrics, Self::Err>;
/// Load the font described by `FontDesc` and `Size`
fn load_font(&mut self, &FontDesc, Size) -> Result<FontKey, Self::Err>;
diff --git a/font/src/rusttype/mod.rs b/font/src/rusttype/mod.rs
new file mode 100644
index 00000000..dc64bc78
--- /dev/null
+++ b/font/src/rusttype/mod.rs
@@ -0,0 +1,151 @@
+extern crate font_loader;
+use self::font_loader::system_fonts;
+
+extern crate rusttype;
+use self::rusttype::{point, Codepoint, FontCollection, Scale};
+
+use super::{FontDesc, FontKey, GlyphKey, Metrics, RasterizedGlyph, Size, Slant, Style, Weight};
+
+pub struct RustTypeRasterizer {
+ fonts: Vec<rusttype::Font<'static>>,
+ dpi_ratio: f32,
+}
+
+impl ::Rasterize for RustTypeRasterizer {
+ type Err = Error;
+
+ fn new(device_pixel_ratio: f32, _: bool) -> Result<RustTypeRasterizer, Error> {
+ Ok(RustTypeRasterizer {
+ fonts: Vec::new(),
+ dpi_ratio: device_pixel_ratio,
+ })
+ }
+
+ fn metrics(&self, key: FontKey, size: Size) -> Result<Metrics, Error> {
+ let scale = Scale::uniform(size.as_f32_pts() * self.dpi_ratio * 96. / 72.);
+ let vmetrics = self.fonts[key.token as usize].v_metrics(scale);
+ let hmetrics = self.fonts[key.token as usize]
+ .glyph(
+ // If the font is monospaced all glyphs *should* have the same width
+ // 33 '!' is the first displaying character
+ Codepoint(33),
+ )
+ .ok_or(Error::MissingGlyph)?
+ .scaled(scale)
+ .h_metrics();
+ Ok(Metrics {
+ descent: vmetrics.descent,
+ average_advance: f64::from(hmetrics.advance_width),
+ line_height: f64::from(vmetrics.ascent - vmetrics.descent + vmetrics.line_gap),
+ })
+ }
+
+ fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Result<FontKey, Error> {
+ let fp = system_fonts::FontPropertyBuilder::new()
+ .family(&desc.name)
+ .monospace();
+
+ let fp = match desc.style {
+ Style::Specific(_) => unimplemented!(""),
+ Style::Description { slant, weight } => {
+ let fp = match slant {
+ Slant::Normal => fp,
+ Slant::Italic => fp.italic(),
+ // This style is not supported by rust-font-loader
+ Slant::Oblique => return Err(Error::UnsupportedStyle),
+ };
+ match weight {
+ Weight::Bold => fp.bold(),
+ Weight::Normal => fp,
+ }
+ }
+ };
+ self.fonts.push(FontCollection::from_bytes(
+ system_fonts::get(&fp.build())
+ .ok_or_else(|| Error::MissingFont(desc.clone()))?
+ .0,
+ ).into_font()
+ .ok_or(Error::UnsupportedFont)?);
+ Ok(FontKey {
+ token: (self.fonts.len() - 1) as u16,
+ })
+ }
+
+ fn get_glyph(&mut self, glyph_key: GlyphKey) -> Result<RasterizedGlyph, Error> {
+ let scaled_glyph = self.fonts[glyph_key.font_key.token as usize]
+ .glyph(glyph_key.c)
+ .ok_or(Error::MissingGlyph)?
+ .scaled(Scale::uniform(
+ glyph_key.size.as_f32_pts() * self.dpi_ratio * 96. / 72.,
+ ));
+
+ let glyph = scaled_glyph.positioned(point(0.0, 0.0));
+
+ // Pixel bounding box
+ let bb = match glyph.pixel_bounding_box() {
+ Some(bb) => bb,
+ // Bounding box calculation fails for spaces so we provide a placeholder bounding box
+ None => rusttype::Rect {
+ min: point(0, 0),
+ max: point(0, 0),
+ },
+ };
+
+ let mut buf = Vec::with_capacity((bb.width() * bb.height()) as usize);
+
+ glyph.draw(|_x, _y, v| {
+ buf.push((v * 255.0) as u8);
+ buf.push((v * 255.0) as u8);
+ buf.push((v * 255.0) as u8);
+ });
+ Ok(RasterizedGlyph {
+ c: glyph_key.c,
+ width: bb.width(),
+ height: bb.height(),
+ top: -bb.min.y,
+ left: bb.min.x,
+ buf,
+ })
+ }
+}
+
+#[derive(Debug)]
+pub enum Error {
+ MissingFont(FontDesc),
+ UnsupportedFont,
+ UnsupportedStyle,
+ // NOTE: This error is different from how the FreeType code handles it
+ MissingGlyph,
+}
+
+impl ::std::error::Error for Error {
+ fn description(&self) -> &str {
+ match *self {
+ Error::MissingFont(ref _desc) => "couldn't find the requested font",
+ Error::UnsupportedFont => "only TrueType fonts are supported",
+ Error::UnsupportedStyle => "the selected style is not supported by rusttype",
+ Error::MissingGlyph => "the selected font did not have the requested glyph",
+ }
+ }
+}
+
+impl ::std::fmt::Display for Error {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ match *self {
+ Error::MissingFont(ref desc) => write!(
+ f,
+ "Couldn't find a font with {}\
+ \n\tPlease check the font config in your alacritty.yml.",
+ desc
+ ),
+ Error::UnsupportedFont => write!(
+ f,
+ "Rusttype only supports TrueType fonts.\n\tPlease select a TrueType font instead."
+ ),
+ Error::UnsupportedStyle => {
+ write!(f, "The selected font style is not supported by rusttype.")
+ }
+ Error::MissingGlyph => write!(f, "The selected font did not have the requested glyph."),
+ }
+ }
+}