aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--font/src/ft/fc/pattern.rs86
-rw-r--r--font/src/ft/mod.rs51
2 files changed, 120 insertions, 17 deletions
diff --git a/font/src/ft/fc/pattern.rs b/font/src/ft/fc/pattern.rs
index 55fbaefe..e3c5261f 100644
--- a/font/src/ft/fc/pattern.rs
+++ b/font/src/ft/fc/pattern.rs
@@ -18,15 +18,15 @@ use std::path::PathBuf;
use std::str;
use std::mem;
-use libc::{c_char, c_int};
+use libc::{c_char, c_int, c_double};
use foreign_types::{ForeignType, ForeignTypeRef};
use super::ffi::FcResultMatch;
use super::ffi::{FcPatternDestroy, FcPatternAddCharSet};
-use super::ffi::{FcPatternGetString, FcPatternCreate, FcPatternAddString};
+use super::ffi::{FcPatternGetString, FcPatternCreate, FcPatternAddString, FcPatternAddDouble};
use super::ffi::{FcPatternGetInteger, FcPatternAddInteger, FcPatternPrint};
use super::ffi::{FcChar8, FcPattern, FcDefaultSubstitute, FcConfigSubstitute};
-use super::ffi::{FcFontRenderPrepare, FcPatternGetBool, FcBool};
+use super::ffi::{FcFontRenderPrepare, FcPatternGetBool, FcBool, FcPatternGetDouble};
use super::{MatchKind, ConfigRef, CharSetRef, Weight, Slant, Width, Rgba, HintStyle, LcdFilter};
@@ -115,7 +115,6 @@ pub struct IntPropertyIter<'a> {
index: usize
}
-
impl<'a> IntPropertyIter<'a> {
fn new<'b>(pattern: &'b PatternRef, object: &'b [u8]) -> IntPropertyIter<'b> {
IntPropertyIter {
@@ -227,6 +226,42 @@ impl<'a> LcdFilterPropertyIter<'a> {
}
}
+/// Iterator over interger properties
+pub struct DoublePropertyIter<'a> {
+ pattern: &'a PatternRef,
+ object: &'a [u8],
+ index: usize
+}
+
+impl<'a> DoublePropertyIter<'a> {
+ fn new<'b>(pattern: &'b PatternRef, object: &'b [u8]) -> DoublePropertyIter<'b> {
+ DoublePropertyIter {
+ pattern: pattern,
+ object: object,
+ index: 0
+ }
+ }
+
+ fn get_value(&self, index: usize) -> Option<f64> {
+ let mut value = 0 as c_double;
+
+ let result = unsafe {
+ FcPatternGetDouble(
+ self.pattern.as_ptr(),
+ self.object.as_ptr() as *mut c_char,
+ index as c_int,
+ &mut value
+ )
+ };
+
+ if result == FcResultMatch {
+ Some(value as f64)
+ } else {
+ None
+ }
+ }
+}
+
/// Implement debug for a property iterator
macro_rules! impl_property_iter_debug {
($iter:ty => $item:ty) => {
@@ -305,6 +340,7 @@ macro_rules! impl_derived_property_iter {
impl_property_iter! {
StringPropertyIter<'a> => &'a str,
IntPropertyIter<'a> => isize,
+ DoublePropertyIter<'a> => f64,
BooleanPropertyIter<'a> => bool
}
@@ -322,7 +358,7 @@ foreign_type! {
pub struct PatternRef;
}
-macro_rules! pattern_string_accessors {
+macro_rules! string_accessor {
($([$getter:ident, $setter:ident] => $object_name:expr),*) => {
$(
#[inline]
@@ -372,6 +408,18 @@ macro_rules! boolean_getter {
}
}
+macro_rules! double_getter {
+ ($($method:ident() => $property:expr),*) => {
+ $(
+ pub fn $method(&self) -> DoublePropertyIter {
+ unsafe {
+ self.get_double($property)
+ }
+ }
+ )*
+ }
+}
+
impl PatternRef {
// Prints the pattern to stdout
//
@@ -411,6 +459,14 @@ impl PatternRef {
) == 1
}
+ unsafe fn add_double(&self, object: &[u8], value: f64) -> bool {
+ FcPatternAddDouble(
+ self.as_ptr(),
+ object.as_ptr() as *mut c_char,
+ value as c_double
+ ) == 1
+ }
+
unsafe fn get_string<'a>(&'a self, object: &'a [u8]) -> StringPropertyIter<'a> {
StringPropertyIter::new(self, object)
}
@@ -419,6 +475,10 @@ impl PatternRef {
IntPropertyIter::new(self, object)
}
+ unsafe fn get_double<'a>(&'a self, object: &'a [u8]) -> DoublePropertyIter<'a> {
+ DoublePropertyIter::new(self, object)
+ }
+
unsafe fn get_boolean<'a>(&'a self, object: &'a [u8]) -> BooleanPropertyIter<'a> {
BooleanPropertyIter::new(self, object)
}
@@ -446,7 +506,15 @@ impl PatternRef {
decorative() => b"decorative\0"
}
- pattern_string_accessors! {
+ double_getter! {
+ size() => b"size\0",
+ aspect() => b"aspect\0",
+ pixelsize() => b"pixelsize\0",
+ scale() => b"scale\0",
+ dpi() => b"dpi\0"
+ }
+
+ string_accessor! {
[family, add_family] => b"family\0",
[familylang, add_familylang] => b"familylang\0",
[style, add_style] => b"style\0",
@@ -467,6 +535,12 @@ impl PatternRef {
}
}
+ pub fn add_pixelsize(&mut self, size: f64) -> bool {
+ unsafe {
+ self.add_double(b"pixelsize\0", size)
+ }
+ }
+
pub fn set_weight(&mut self, weight: Weight) -> bool {
unsafe {
self.add_integer(b"weight\0", weight as isize)
diff --git a/font/src/ft/mod.rs b/font/src/ft/mod.rs
index 1905d99d..f37a500e 100644
--- a/font/src/ft/mod.rs
+++ b/font/src/ft/mod.rs
@@ -26,12 +26,17 @@ pub mod fc;
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};
+struct FixedSize {
+ pixelsize: f64,
+}
+
struct Face {
ft_face: freetype::Face<'static>,
key: FontKey,
load_flags: freetype::face::LoadFlag,
render_mode: freetype::RenderMode,
lcd_filter: c_uint,
+ non_scalable: Option<FixedSize>
}
impl fmt::Debug for Face {
@@ -103,8 +108,8 @@ impl ::Rasterize for FreeTypeRasterizer {
})
}
- fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Result<FontKey, Error> {
- let face = self.get_face(desc)?;
+ fn load_font(&mut self, desc: &FontDesc, size: Size) -> Result<FontKey, Error> {
+ let face = self.get_face(desc, size)?;
let key = face.key;
self.faces.insert(key, face);
Ok(key)
@@ -145,15 +150,19 @@ impl IntoFontconfigType for Weight {
impl FreeTypeRasterizer {
/// Load a font face accoring to `FontDesc`
- fn get_face(&mut self, desc: &FontDesc) -> Result<Face, Error> {
+ fn get_face(&mut self, desc: &FontDesc, size: Size) -> Result<Face, Error> {
+ // Adjust for DPI
+ let scale = self.dpi_x as f32 / 72.;
+ let size = Size::new(size.as_f32_pts() * scale);
+
match desc.style {
Style::Description { slant, weight } => {
// Match nearest font
- self.get_matching_face(&desc, slant, weight)
+ self.get_matching_face(&desc, slant, weight, size)
}
Style::Specific(ref style) => {
// If a name was specified, try and load specifically that font.
- self.get_specific_face(&desc, &style)
+ self.get_specific_face(&desc, &style, size)
}
}
}
@@ -162,12 +171,14 @@ impl FreeTypeRasterizer {
&mut self,
desc: &FontDesc,
slant: Slant,
- weight: Weight
+ weight: Weight,
+ size: Size,
) -> Result<Face, 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());
+ pattern.add_pixelsize(size.as_f32_pts() as _);
let font = fc::font_match(fc::Config::get_current(), &mut pattern)
.ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
@@ -183,11 +194,13 @@ impl FreeTypeRasterizer {
fn get_specific_face(
&mut self,
desc: &FontDesc,
- style: &str
+ style: &str,
+ size: Size,
) -> Result<Face, Error> {
let mut pattern = fc::Pattern::new();
pattern.add_family(&desc.name);
pattern.add_style(style);
+ pattern.add_pixelsize(size.as_f32_pts() as _);
let font = fc::font_match(fc::Config::get_current(), &mut pattern)
.ok_or_else(|| Error::MissingFont(desc.to_owned()))?;
@@ -203,16 +216,29 @@ impl FreeTypeRasterizer {
if let (Some(path), Some(index)) = (pattern.file(0), pattern.index().nth(0)) {
trace!("got font path={:?}", path);
let ft_face = self.library.new_face(path, index)?;
+
+ // Get available pixel sizes if font isn't scalable.
+ let non_scalable = if !pattern.scalable().next().unwrap_or(true) {
+ let mut pixelsize = pattern.pixelsize();
+ debug!("pixelsizes: {:?}", pixelsize);
+
+ Some(FixedSize {
+ pixelsize: pixelsize.next().expect("has 1+ pixelsize"),
+ })
+ } else {
+ None
+ };
+
let face = Face {
ft_face: ft_face,
key: FontKey::next(),
load_flags: Self::ft_load_flags(pattern),
render_mode: Self::ft_render_mode(pattern),
lcd_filter: Self::ft_lcd_filter(pattern),
+ non_scalable: non_scalable,
};
debug!("Loaded Face {:?}", face);
-
Ok(Some(face))
} else {
Ok(None)
@@ -220,14 +246,11 @@ impl FreeTypeRasterizer {
}
fn face_for_glyph(&mut self, glyph_key: &GlyphKey, have_recursed: bool) -> Result<FontKey, Error> {
- let size = glyph_key.size.as_f32_pts() * self.dpr;
let c = glyph_key.c;
let use_initial_face = if self.faces.contains_key(&glyph_key.font_key) {
// Get face and unwrap since we just checked for presence.
let face = self.faces.get(&glyph_key.font_key).unwrap();
-
- face.ft_face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y)?;
let index = face.ft_face.get_char_index(c as usize);
if index != 0 || have_recursed {
@@ -253,6 +276,12 @@ impl FreeTypeRasterizer {
let face = self.faces.get(&font_key).unwrap();
let index = face.ft_face.get_char_index(glyph_key.c as usize);
+ let size = face.non_scalable.as_ref()
+ .map(|v| v.pixelsize as f32)
+ .unwrap_or_else(|| glyph_key.size.as_f32_pts() * self.dpi_x as f32 / 72.);
+
+ face.ft_face.set_char_size(to_freetype_26_6(size), 0, 0, 0)?;
+
unsafe {
let ft_lib = self.library.raw();
freetype::ffi::FT_Library_SetLcdFilter(ft_lib, face.lcd_filter);