summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--alacritty.yml23
-rw-r--r--font/src/darwin/mod.rs63
-rw-r--r--font/src/ft/list_fonts.rs396
-rw-r--r--font/src/ft/mod.rs102
-rw-r--r--font/src/lib.rs37
-rw-r--r--src/config.rs71
-rw-r--r--src/renderer/mod.rs33
7 files changed, 514 insertions, 211 deletions
diff --git a/alacritty.yml b/alacritty.yml
index 1fbcb63f..0d907ea0 100644
--- a/alacritty.yml
+++ b/alacritty.yml
@@ -9,14 +9,29 @@ dpi:
# Display tabs using this many cells (changes require restart)
tabspaces: 8
+# When true, bold text is drawn using the bright variant of colors.
draw_bold_text_with_bright_colors: true
# Font configuration (changes require restart)
font:
- family: DejaVu Sans Mono
- style: Book
- bold_style: Bold
- italic_style: Oblique
+ # The normal (roman) font face to use.
+ normal:
+ family: monospace # should be "Menlo" or something on macOS.
+ # 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.
+ # 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.
+ # Style can be specified to pick a specific face.
+ # style: Italic
+
# Point size of the font
size: 11.0
# Offset is the extra space around each character. offset.y can be thought of
diff --git a/font/src/darwin/mod.rs b/font/src/darwin/mod.rs
index 99f080ab..35336df9 100644
--- a/font/src/darwin/mod.rs
+++ b/font/src/darwin/mod.rs
@@ -19,6 +19,8 @@
use std::collections::HashMap;
use std::ptr;
+use ::{Slant, Weight, Style};
+
use core_foundation::base::TCFType;
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::array::CFIndex;
@@ -36,6 +38,7 @@ use core_text::font_descriptor::kCTFontDefaultOrientation;
use core_text::font_descriptor::kCTFontHorizontalOrientation;
use core_text::font_descriptor::kCTFontVerticalOrientation;
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef, CTFontOrientation};
+use core_text::font_descriptor::SymbolicTraitAccessors;
use libc::{size_t, c_int};
@@ -166,10 +169,15 @@ impl ::Rasterize for Rasterizer {
}
impl Rasterizer {
- fn get_font(&mut self, desc: &FontDesc, size: Size) -> Result<Font, Error> {
+ fn get_specific_face(
+ &mut self,
+ desc: &FontDesc,
+ style: &str,
+ size: Size
+ ) -> Result<Font, Error> {
let descriptors = descriptors_for_family(&desc.name[..]);
for descriptor in descriptors {
- if descriptor.style_name == desc.style {
+ 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);
@@ -179,6 +187,44 @@ impl Rasterizer {
Err(Error::MissingFont(desc.to_owned()))
}
+
+ fn get_matching_face(
+ &mut self,
+ desc: &FontDesc,
+ slant: Slant,
+ weight: Weight,
+ size: Size
+ ) -> Result<Font, Error> {
+ let bold = match weight {
+ Weight::Bold => true,
+ _ => false
+ };
+ let italic = match slant {
+ Slant::Normal => false,
+ _ => true,
+ };
+ let scaled_size = size.as_f32_pts() as f64 * self.device_pixel_ratio as f64;
+
+ let descriptors = descriptors_for_family(&desc.name[..]);
+ for descriptor in descriptors {
+ let font = descriptor.to_font(scaled_size);
+ if font.is_bold() == bold && font.is_italic() == italic {
+ // Found the font we want
+ return Ok(font);
+ }
+ }
+
+ Err(Error::MissingFont(desc.to_owned()))
+ }
+
+ fn get_font(&mut self, desc: &FontDesc, size: Size) -> Result<Font, Error> {
+ match desc.style {
+ Style::Specific(ref style) => self.get_specific_face(desc, style, size),
+ Style::Description { slant, weight } => {
+ self.get_matching_face(desc, slant, weight, size)
+ },
+ }
+ }
}
/// Specifies the intended rendering orientation of the font for obtaining glyph metrics
@@ -290,6 +336,14 @@ impl Font {
}
}
+ pub fn is_bold(&self) -> bool {
+ self.ct_font.symbolic_traits().is_bold()
+ }
+
+ pub fn is_italic(&self) -> bool {
+ self.ct_font.symbolic_traits().is_italic()
+ }
+
fn glyph_advance(&self, character: char) -> f64 {
let index = self.glyph_index(character).unwrap();
@@ -539,12 +593,9 @@ mod tests {
.collect::<Vec<_>>();
for font in fonts {
- // Check deref
- println!("family: {}", font.family_name());
-
// Get a glyph
for c in &['a', 'b', 'c', 'd'] {
- let glyph = font.get_glyph(*c, 72.);
+ let glyph = font.get_glyph(*c, 72.).unwrap();
// Debug the glyph.. sigh
for row in 0..glyph.height {
diff --git a/font/src/ft/list_fonts.rs b/font/src/ft/list_fonts.rs
index 0fbc7231..29912a8f 100644
--- a/font/src/ft/list_fonts.rs
+++ b/font/src/ft/list_fonts.rs
@@ -12,28 +12,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-use std::collections::HashMap;
-use std::fmt;
-use std::path::PathBuf;
-
-mod fc {
+pub mod fc {
use std::ptr;
use std::ffi::{CStr, CString};
use std::str;
use std::ops::Deref;
+ use std::path::PathBuf;
- use ffi_util::ForeignTypeRef;
+ use ffi_util::{ForeignType, ForeignTypeRef};
use libc::{c_char, c_int};
use fontconfig::fontconfig as ffi;
use self::ffi::{FcConfigGetCurrent, FcConfigGetFonts, FcSetSystem, FcSetApplication};
use self::ffi::{FcPatternGetString, FcPatternCreate, FcPatternAddString};
- use self::ffi::{FcPatternGetInteger};
+ use self::ffi::{FcPatternGetInteger, FcPatternAddInteger};
use self::ffi::{FcObjectSetCreate, FcObjectSetAdd};
- use self::ffi::{FcResultMatch, FcFontSetList};
- use self::ffi::{FcChar8, FcConfig, FcPattern, FcFontSet, FcObjectSet};
+ use self::ffi::{FcResultMatch, FcResultNoMatch, FcFontSetList};
+ use self::ffi::{FcChar8, FcConfig, FcPattern, FcFontSet, FcObjectSet, FcCharSet};
use self::ffi::{FcFontSetDestroy, FcPatternDestroy, FcObjectSetDestroy, FcConfigDestroy};
+ use self::ffi::{FcFontMatch, FcFontList, FcFontSort, FcConfigSubstitute, FcDefaultSubstitute};
+ use self::ffi::{FcMatchFont, FcMatchPattern, FcMatchScan, FC_SLANT_ITALIC, FC_SLANT_ROMAN};
+ use self::ffi::{FC_SLANT_OBLIQUE};
+ use self::ffi::{FC_WEIGHT_THIN, FC_WEIGHT_EXTRALIGHT, FC_WEIGHT_LIGHT};
+ use self::ffi::{FC_WEIGHT_BOOK, FC_WEIGHT_REGULAR, FC_WEIGHT_MEDIUM, FC_WEIGHT_SEMIBOLD};
+ use self::ffi::{FC_WEIGHT_BOLD, FC_WEIGHT_EXTRABOLD, FC_WEIGHT_BLACK, FC_WEIGHT_EXTRABLACK};
/// Iterator over a font set
pub struct FontSetIter<'a> {
@@ -48,6 +51,7 @@ mod fc {
ffi_type!(FontSet, FontSetRef, FcFontSet, FcFontSetDestroy);
impl ObjectSet {
+ #[allow(dead_code)]
pub fn new() -> ObjectSet {
ObjectSet(unsafe {
FcObjectSetCreate()
@@ -55,6 +59,89 @@ mod fc {
}
}
+ /// Find the font closest matching the provided pattern.
+ #[allow(dead_code)]
+ pub fn font_match(
+ config: &ConfigRef,
+ pattern: &mut PatternRef,
+ ) -> Option<Pattern> {
+ pattern.config_subsitute(config, MatchKind::Pattern);
+ pattern.default_substitute();
+
+ unsafe {
+ // What is this result actually used for? Seems redundant with
+ // return type.
+ let mut result = FcResultNoMatch;
+ let ptr = FcFontMatch(
+ config.as_ptr(),
+ pattern.as_ptr(),
+ &mut result,
+ );
+
+ if ptr.is_null() {
+ None
+ } else {
+ Some(Pattern::from_ptr(ptr))
+ }
+ }
+ }
+
+ /// list fonts by closeness to the pattern
+ pub fn font_sort(
+ config: &ConfigRef,
+ pattern: &mut PatternRef,
+ ) -> Option<FontSet> {
+ pattern.config_subsitute(config, MatchKind::Pattern);
+ pattern.default_substitute();
+
+ unsafe {
+ // What is this result actually used for? Seems redundant with
+ // return type.
+ let mut result = FcResultNoMatch;
+
+ let mut charsets: *mut FcCharSet = ptr::null_mut();
+
+ let ptr = FcFontSort(
+ config.as_ptr(),
+ pattern.as_ptr(),
+ 0, // false
+ &mut charsets,
+ &mut result,
+ );
+
+ if ptr.is_null() {
+ None
+ } else {
+ Some(FontSet::from_ptr(ptr))
+ }
+ }
+ }
+
+ /// List fonts matching pattern
+ #[allow(dead_code)]
+ pub fn font_list(
+ config: &ConfigRef,
+ pattern: &mut PatternRef,
+ objects: &ObjectSetRef,
+ ) -> Option<FontSet> {
+ pattern.config_subsitute(config, MatchKind::Pattern);
+ pattern.default_substitute();
+
+ unsafe {
+ let ptr = FcFontList(
+ config.as_ptr(),
+ pattern.as_ptr(),
+ objects.as_ptr(),
+ );
+
+ if ptr.is_null() {
+ None
+ } else {
+ Some(FontSet::from_ptr(ptr))
+ }
+ }
+ }
+
impl ObjectSetRef {
fn add(&mut self, property: &[u8]) {
unsafe {
@@ -79,13 +166,28 @@ mod fc {
}
macro_rules! pattern_add_string {
- ($name:ident => $object:expr) => {
- #[inline]
- pub fn $name(&mut self, value: &str) -> bool {
- unsafe {
- self.add_string($object, value)
+ ($($name:ident => $object:expr),*) => {
+ $(
+ #[inline]
+ pub fn $name(&mut self, value: &str) -> bool {
+ unsafe {
+ self.add_string($object, value)
+ }
}
- }
+ )*
+ }
+ }
+
+ macro_rules! pattern_add_int {
+ ($($name:ident => $object:expr),*) => {
+ $(
+ #[inline]
+ pub fn $name(&mut self, value: &str) -> bool {
+ unsafe {
+ self.add_string($object, value)
+ }
+ }
+ )*
}
}
@@ -102,6 +204,14 @@ mod fc {
Application = FcSetApplication as isize,
}
+ /// When matching, how to match
+ #[derive(Debug, Copy, Clone)]
+ pub enum MatchKind {
+ Font = FcMatchFont as isize,
+ Pattern = FcMatchPattern as isize,
+ Scan = FcMatchScan as isize,
+ }
+
pub unsafe fn char8_to_string(fc_str: *mut FcChar8) -> String {
str::from_utf8(CStr::from_ptr(fc_str as *const c_char).to_bytes()).unwrap().to_owned()
}
@@ -111,20 +221,24 @@ mod fc {
$(
pub fn $method(&self, id: isize) -> Option<String> {
unsafe {
- let mut format: *mut FcChar8 = ptr::null_mut();
+ self.get_string($property, id)
+ }
+ }
+ )+
+ };
+ }
- let result = FcPatternGetString(
+ macro_rules! pattern_add_integer {
+ ($($method:ident() => $property:expr),+) => {
+ $(
+ pub fn $method(&self, int: isize) -> bool {
+ unsafe {
+ FcPatternAddInteger(
self.as_ptr(),
$property.as_ptr() as *mut c_char,
- id as c_int,
- &mut format
- );
-
- if result == FcResultMatch {
- Some(char8_to_string(format))
- } else {
- None
- }
+ int as c_int,
+ &mut index
+ ) == 1
}
}
)+
@@ -155,6 +269,28 @@ mod fc {
};
}
+ #[derive(Debug, Copy, Clone)]
+ pub enum Slant {
+ Italic = FC_SLANT_ITALIC as isize,
+ Oblique = FC_SLANT_OBLIQUE as isize,
+ Roman = FC_SLANT_ROMAN as isize,
+ }
+
+ #[derive(Debug, Copy, Clone)]
+ pub enum Weight {
+ Thin = FC_WEIGHT_THIN as isize,
+ Extralight = FC_WEIGHT_EXTRALIGHT as isize,
+ Light = FC_WEIGHT_LIGHT as isize,
+ Book = FC_WEIGHT_BOOK as isize,
+ Regular = FC_WEIGHT_REGULAR as isize,
+ Medium = FC_WEIGHT_MEDIUM as isize,
+ Semibold = FC_WEIGHT_SEMIBOLD as isize,
+ Bold = FC_WEIGHT_BOLD as isize,
+ Extrabold = FC_WEIGHT_EXTRABOLD as isize,
+ Black = FC_WEIGHT_BLACK as isize,
+ Extrablack = FC_WEIGHT_EXTRABLACK as isize,
+ }
+
impl PatternRef {
/// Add a string value to the pattern
///
@@ -175,20 +311,75 @@ mod fc {
) == 1
}
+ unsafe fn add_integer(&self, object: &[u8], int: isize) -> bool {
+ FcPatternAddInteger(
+ self.as_ptr(),
+ object.as_ptr() as *mut c_char,
+ int as c_int
+ ) == 1
+ }
+
+ unsafe fn get_string(&self, object: &[u8], index: isize) -> Option<String> {
+ let mut format: *mut FcChar8 = ptr::null_mut();
+
+ let result = FcPatternGetString(
+ self.as_ptr(),
+ object.as_ptr() as *mut c_char,
+ index as c_int,
+ &mut format
+ );
+
+ if result == FcResultMatch {
+ Some(char8_to_string(format))
+ } else {
+ None
+ }
+ }
+
pattern_add_string! {
- add_family => b"family\0"
+ add_family => b"family\0",
+ add_style => b"style\0"
+ }
+
+ pub fn set_slant(&mut self, slant: Slant) -> bool {
+ unsafe {
+ self.add_integer(b"slant\0", slant as isize)
+ }
+ }
+
+ pub fn set_weight(&mut self, weight: Weight) -> bool {
+ unsafe {
+ self.add_integer(b"weight\0", weight as isize)
+ }
+ }
+
+ pub fn file(&self, index: isize) -> Option<PathBuf> {
+ unsafe {
+ self.get_string(b"file\0", index)
+ }.map(From::from)
}
pattern_get_string! {
fontformat() => b"fontformat\0",
family() => b"family\0",
- file() => b"file\0",
style() => b"style\0"
}
pattern_get_integer! {
index() => b"index\0"
}
+
+ pub fn config_subsitute(&mut self, config: &ConfigRef, kind: MatchKind) {
+ unsafe {
+ FcConfigSubstitute(config.as_ptr(), self.as_ptr(), kind as u32);
+ }
+ }
+
+ pub fn default_substitute(&mut self) {
+ unsafe {
+ FcDefaultSubstitute(self.as_ptr());
+ }
+ }
}
impl<'a> IntoIterator for &'a FontSet {
@@ -199,6 +390,8 @@ mod fc {
(*self.as_ptr()).nfont as isize
};
+ println!("num fonts = {}", num_fonts);
+
FontSetIter {
font_set: self.deref(),
num_fonts: num_fonts as _,
@@ -215,6 +408,8 @@ mod fc {
(*self.as_ptr()).nfont as isize
};
+ println!("num fonts = {}", num_fonts);
+
FontSetIter {
font_set: self,
num_fonts: num_fonts as _,
@@ -282,119 +477,50 @@ mod fc {
}
}
-fn list_families() -> Vec<String> {
- let mut families = Vec::new();
-
- let config = fc::Config::get_current();
- let font_set = config.get_fonts(fc::SetName::System);
- for font in font_set {
- if let Some(format) = font.fontformat(0) {
- if format == "TrueType" || format == "CFF" {
- for id in 0.. {
- match font.family(id) {
- Some(family) => families.push(family),
- None => break,
- }
- }
- }
- }
- }
-
- families.sort();
- families.dedup();
- families
-}
-
-#[derive(Debug)]
-pub struct Variant {
- style: String,
- file: PathBuf,
- index: isize,
-}
-
-impl Variant {
- #[inline]
- pub fn path(&self) -> &::std::path::Path {
- self.file.as_path()
- }
-
- #[inline]
- pub fn index(&self) -> isize {
- self.index
- }
-}
-
-#[derive(Debug)]
-pub struct Family {
- name: String,
- variants: HashMap<String, Variant>,
-}
+#[cfg(test)]
+mod tests {
+ use super::fc;
-impl fmt::Display for Family {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}: ", self.name)?;
- for (k, _v) in &self.variants {
- write!(f, "{}, ", k)?;
+ #[test]
+ fn font_match() {
+ let mut pattern = fc::Pattern::new();
+ pattern.add_family("monospace");
+ pattern.add_style("regular");
+
+ let config = fc::Config::get_current();
+ let font = fc::font_match(config, &mut pattern).expect("match font monospace");
+
+ print!("family={:?}", font.family(0));
+ for i in 0.. {
+ if let Some(style) = font.style(i) {
+ print!(", style={:?}, ", style);
+ } else {
+ break;
+ }
}
-
- Ok(())
+ println!("");
}
-}
-
-impl Family {
- #[inline]
- pub fn variants(&self) -> &HashMap<String, Variant> {
- &self.variants
- }
-}
-#[allow(mutable_transmutes)]
-pub fn get_family_info(family: String) -> Family {
- let mut members = Vec::new();
- let config = fc::Config::get_current();
- let font_set = config.get_fonts(fc::SetName::System);
-
- let mut pattern = fc::Pattern::new();
- pattern.add_family(&family);
-
- let mut objects = fc::ObjectSet::new();
- objects.add_file();
- objects.add_index();
- objects.add_style();
-
- let variants = fc::FontSet::list(&config, unsafe { ::std::mem::transmute(font_set) }, &pattern, &objects);
- for variant in &variants {
- if let Some(file) = variant.file(0) {
- if let Some(style) = variant.style(0) {
- if let Some(index) = variant.index(0) {
- members.push(Variant {
- style: style,
- file: PathBuf::from(file),
- index: index as isize,
- });
+ #[test]
+ fn font_sort() {
+ let mut pattern = fc::Pattern::new();
+ pattern.add_family("monospace");
+ pattern.set_slant(fc::Slant::Italic);
+
+ let config = fc::Config::get_current();
+ let fonts = fc::font_sort(config, &mut pattern)
+ .expect("sort font monospace");
+
+ for font in fonts.into_iter().take(10) {
+ print!("family={:?}", font.family(0));
+ for i in 0.. {
+ if let Some(style) = font.style(i) {
+ print!(", style={:?}", style);
+ } else {
+ break;
}
}
+ println!("");
}
}
-
- Family {
- name: family,
- variants: members.into_iter().map(|v| (v.style.clone(), v)).collect()
- }
-}
-
-pub fn get_font_families() -> HashMap<String, Family> {
- list_families()
- .into_iter()
- .map(|family| (family.clone(), get_family_info(family)))
- .collect()
-}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn get_font_families() {
- let families = super::get_font_families();
- assert!(!families.is_empty());
- }
}
diff --git a/font/src/ft/mod.rs b/font/src/ft/mod.rs
index 8e653816..0ffecf03 100644
--- a/font/src/ft/mod.rs
+++ b/font/src/ft/mod.rs
@@ -17,16 +17,16 @@ use std::collections::HashMap;
use freetype::{self, Library, Face};
+
mod list_fonts;
-use self::list_fonts::{Family, get_font_families};
-use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey};
+use self::list_fonts::fc;
+use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};
/// Rasterizes glyphs for a single font face.
pub struct FreeTypeRasterizer {
faces: HashMap<FontKey, Face<'static>>,
library: Library,
- system_fonts: HashMap<String, Family>,
keys: HashMap<FontDesc, FontKey>,
dpi_x: u32,
dpi_y: u32,
@@ -45,7 +45,6 @@ impl ::Rasterize for FreeTypeRasterizer {
let library = Library::init()?;
Ok(FreeTypeRasterizer {
- system_fonts: get_font_families(),
faces: HashMap::new(),
keys: HashMap::new(),
library: library,
@@ -130,13 +129,89 @@ impl ::Rasterize for FreeTypeRasterizer {
}
}
+pub trait IntoFontconfigType {
+ type FcType;
+ fn into_fontconfig_type(&self) -> Self::FcType;
+}
+
+impl IntoFontconfigType for Slant {
+ type FcType = fc::Slant;
+ fn into_fontconfig_type(&self) -> Self::FcType {
+ match *self {
+ Slant::Normal => fc::Slant::Roman,
+ Slant::Italic => fc::Slant::Italic,
+ Slant::Oblique => fc::Slant::Oblique,
+ }
+ }
+}
+
+impl IntoFontconfigType for Weight {
+ type FcType = fc::Weight;
+
+ fn into_fontconfig_type(&self) -> Self::FcType {
+ match *self {
+ Weight::Normal => fc::Weight::Regular,
+ Weight::Bold => fc::Weight::Bold,
+ }
+ }
+}
+
impl FreeTypeRasterizer {
+ /// Load a font face accoring to `FontDesc`
fn get_face(&mut self, desc: &FontDesc) -> Result<Face<'static>, Error> {
- self.system_fonts
- .get(&desc.name[..])
- .and_then(|font| font.variants().get(&desc.style[..]))
- .ok_or_else(|| Error::MissingFont(desc.to_owned()))
- .and_then(|variant| Ok(self.library.new_face(variant.path(), variant.index())?))
+ match desc.style {
+ Style::Description { slant, weight } => {
+ // Match nearest font
+ self.get_matching_face(&desc, slant, weight)
+ }
+ Style::Specific(ref style) => {
+ // If a name was specified, try and load specifically that font.
+ self.get_specific_face(&desc, &style)
+ }
+ }
+ }
+
+ fn get_matching_face(
+ &mut self,
+ desc: &FontDesc,
+ slant: Slant,
+ weight: Weight
+ ) -> Result<Face<'static>, Error> {
+ let mut pattern = fc::Pattern::new();
+ pattern.add_family(&desc.name);
+ pattern.set_weight(weight.into_fontconfig_type());
+ pattern.set_slant(slant.into_fontconfig_type());
+
+ let fonts = fc::font_sort(fc::Config::get_current(), &mut pattern)
+ .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
+
+ // Take first font that has a path
+ for font in &fonts {
+ if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
+ return Ok(self.library.new_face(path, index)?);
+ }
+ }
+
+ Err(Error::MissingFont(desc.to_owned()))
+ }
+
+ fn get_specific_face(
+ &mut self,
+ desc: &FontDesc,
+ style: &str
+ ) -> Result<Face<'static>, Error> {
+ let mut pattern = fc::Pattern::new();
+ pattern.add_family(&desc.name);
+ pattern.add_style(style);
+
+ let font = fc::font_match(fc::Config::get_current(), &mut pattern)
+ .ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
+ if let (Some(path), Some(index)) = (font.file(0), font.index(0)) {
+ println!("got font path={:?}", path);
+ return Ok(self.library.new_face(path, index)?);
+ } else {
+ Err(Error::MissingFont(desc.to_owned()))
+ }
}
}
@@ -193,12 +268,3 @@ impl From<freetype::Error> for Error {
}
unsafe impl Send for FreeTypeRasterizer {}
-
-#[cfg(test)]
-mod tests {
- use ::FontDesc;
-
- fn font_desc() -> FontDesc {
- FontDesc::new("Ubuntu Mono", "Regular")
- }
-}
diff --git a/font/src/lib.rs b/font/src/lib.rs
index afe2b94f..bc4a2006 100644
--- a/font/src/lib.rs
+++ b/font/src/lib.rs
@@ -57,16 +57,47 @@ pub use darwin::*;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FontDesc {
name: String,
- style: String,
+ style: Style,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Slant {
+ Normal,
+ Italic,
+ Oblique,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Weight {
+ Normal,
+ Bold
+}
+
+/// Style of font
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Style {
+ Specific(String),
+ Description { slant: Slant, weight: Weight }
+}
+
+impl fmt::Display for Style {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ 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: S) -> FontDesc
+ pub fn new<S>(name: S, style: Style) -> FontDesc
where S: Into<String>
{
FontDesc {
name: name.into(),
- style: style.into()
+ style: style
}
}
}
diff --git a/src/config.rs b/src/config.rs
index abf0bdf5..59b9f5ea 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -977,16 +977,13 @@ impl DeserializeFromF32 for Size {
#[derive(Debug, Deserialize)]
pub struct Font {
/// Font family
- family: String,
+ pub normal: FontDescription,
- /// Font style
- style: String,
+ #[serde(default="default_italic_desc")]
+ pub italic: FontDescription,
- /// Bold font style
- bold_style: Option<String>,
-
- /// Italic font style
- italic_style: Option<String>,
+ #[serde(default="default_bold_desc")]
+ pub bold: FontDescription,
// Font size in points
#[serde(deserialize_with="DeserializeFromF32::deserialize_from_f32")]
@@ -996,35 +993,31 @@ pub struct Font {
offset: FontOffset,
}
-impl Font {
- /// Get the font family
- #[inline]
- pub fn family(&self) -> &str {
- &self.family[..]
- }
+fn default_bold_desc() -> FontDescription {
+ Font::default().bold
+}
- /// Get the font style
- #[inline]
- pub fn style(&self) -> &str {
- &self.style[..]
- }
+fn default_italic_desc() -> FontDescription {
+ Font::default().italic
+}
- /// Get italic font style; assumes same family
- #[inline]
- pub fn italic_style(&self) -> Option<&str> {
- self.italic_style
- .as_ref()
- .map(|s| s.as_str())
- }
+/// Description of a single font
+#[derive(Debug, Deserialize)]
+pub struct FontDescription {
+ pub family: String,
+ pub style: Option<String>,
+}
- /// Get bold font style; assumes same family
- #[inline]
- pub fn bold_style(&self) -> Option<&str> {
- self.bold_style
- .as_ref()
- .map(|s| s.as_str())
+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 {
@@ -1042,11 +1035,10 @@ impl Font {
impl Default for Font {
fn default() -> Font {
Font {
- family: String::from("Menlo"),
- style: String::from("Regular"),
+ normal: FontDescription::new_with_family("Menlo"),
+ bold: FontDescription::new_with_family("Menlo"),
+ italic: FontDescription::new_with_family("Menlo"),
size: Size::new(11.0),
- bold_style: Some(String::from("Bold")),
- italic_style: Some(String::from("Italic")),
offset: FontOffset {
x: 0.0,
y: 0.0
@@ -1059,11 +1051,10 @@ impl Default for Font {
impl Default for Font {
fn default() -> Font {
Font {
- family: String::from("DejaVu Sans Mono"),
- style: String::from("Book"),
+ normal: FontDescription::new_with_family("monospace"),
+ bold: FontDescription::new_with_family("monospace"),
+ italic: FontDescription::new_with_family("monospace"),
size: Size::new(11.0),
- bold_style: Some(String::from("Bold")),
- italic_style: Some(String::from("Italic")),
offset: FontOffset {
// TODO should improve freetype metrics... shouldn't need such
// drastic offsets for the default!
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index d800a1b5..81ac7fd4 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -166,13 +166,29 @@ impl GlyphCache {
let size = font.size();
// Load regular font
- let regular_desc = FontDesc::new(font.family(), font.style());
+ let regular_desc = if let Some(ref style) = font.normal.style {
+ FontDesc::new(&font.normal.family[..], font::Style::Specific(style.to_owned()))
+ } else {
+ let style = font::Style::Description {
+ slant: font::Slant::Normal,
+ weight: font::Weight::Normal
+ };
+ FontDesc::new(&font.normal.family[..], style)
+ };
+
let regular = rasterizer
.load_font(&regular_desc, size)?;
// Load bold font
- let bold_style = font.bold_style().unwrap_or("Bold");
- let bold_desc = FontDesc::new(font.family(), bold_style);
+ let bold_desc = if let Some(ref style) = font.bold.style {
+ FontDesc::new(&font.bold.family[..], font::Style::Speci