summaryrefslogtreecommitdiffstats
path: root/font
diff options
context:
space:
mode:
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."),
+ }
+ }
+}