Organize fontconfig wrappers
Each Fc type is split into a separate file. This organization will help as features are added to the bindings.
This commit is contained in:
parent
044b546267
commit
65065e06d1
|
@ -0,0 +1,42 @@
|
|||
// 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 foreign_types::{ForeignTypeRef};
|
||||
|
||||
use super::ffi::{FcCharSet, FcCharSetDestroy, FcCharSetAddChar};
|
||||
use super::ffi::{FcCharSetCreate};
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcCharSet;
|
||||
fn drop = FcCharSetDestroy;
|
||||
pub struct CharSet;
|
||||
pub struct CharSetRef;
|
||||
}
|
||||
|
||||
impl CharSet {
|
||||
pub fn new() -> CharSet {
|
||||
CharSet(unsafe { FcCharSetCreate() })
|
||||
}
|
||||
}
|
||||
|
||||
impl CharSetRef {
|
||||
pub fn add(&mut self, glyph: char) -> bool {
|
||||
unsafe {
|
||||
FcCharSetAddChar(
|
||||
self.as_ptr(),
|
||||
glyph as _
|
||||
) == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// 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 foreign_types::{ForeignTypeRef};
|
||||
|
||||
use super::{SetName, FontSetRef};
|
||||
use super::ffi::{FcConfigGetCurrent, FcConfigGetFonts, FcConfig, FcConfigDestroy};
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcConfig;
|
||||
fn drop = FcConfigDestroy;
|
||||
/// Wraps an FcConfig instance (owned)
|
||||
pub struct Config;
|
||||
/// Wraps an FcConfig reference (borrowed)
|
||||
pub struct ConfigRef;
|
||||
}
|
||||
|
||||
|
||||
impl Config {
|
||||
/// Get the current configuration
|
||||
pub fn get_current() -> &'static ConfigRef {
|
||||
unsafe {
|
||||
ConfigRef::from_ptr(FcConfigGetCurrent())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigRef {
|
||||
/// Returns one of the two sets of fonts from the configuration as
|
||||
/// specified by `set`.
|
||||
pub fn get_fonts<'a>(&'a self, set: SetName) -> &'a FontSetRef {
|
||||
unsafe {
|
||||
let ptr = FcConfigGetFonts(self.as_ptr(), set as u32);
|
||||
FontSetRef::from_ptr(ptr)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
// 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 std::ops::Deref;
|
||||
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
|
||||
use super::{ConfigRef, PatternRef, ObjectSetRef};
|
||||
|
||||
use super::ffi::{FcFontSetList, FcFontSetDestroy, FcFontSet};
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcFontSet;
|
||||
fn drop = FcFontSetDestroy;
|
||||
/// Wraps an FcFontSet instance (owned)
|
||||
pub struct FontSet;
|
||||
/// Wraps an FcFontSet reference (borrowed)
|
||||
pub struct FontSetRef;
|
||||
}
|
||||
|
||||
impl FontSet {
|
||||
pub fn list(
|
||||
config: &ConfigRef,
|
||||
source: &mut FontSetRef,
|
||||
pattern: &PatternRef,
|
||||
objects: &ObjectSetRef
|
||||
) -> FontSet {
|
||||
let raw = unsafe {
|
||||
FcFontSetList(
|
||||
config.as_ptr(),
|
||||
&mut source.as_ptr(),
|
||||
1 /* nsets */,
|
||||
pattern.as_ptr(),
|
||||
objects.as_ptr(),
|
||||
)
|
||||
};
|
||||
FontSet(raw)
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over a font set
|
||||
pub struct Iter<'a> {
|
||||
font_set: &'a FontSetRef,
|
||||
num_fonts: usize,
|
||||
current: usize,
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a FontSet {
|
||||
type Item = &'a PatternRef;
|
||||
type IntoIter = Iter<'a>;
|
||||
fn into_iter(self) -> Iter<'a> {
|
||||
let num_fonts = unsafe {
|
||||
(*self.as_ptr()).nfont as isize
|
||||
};
|
||||
|
||||
info!("num fonts = {}", num_fonts);
|
||||
|
||||
Iter {
|
||||
font_set: self.deref(),
|
||||
num_fonts: num_fonts as _,
|
||||
current: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a FontSetRef {
|
||||
type Item = &'a PatternRef;
|
||||
type IntoIter = Iter<'a>;
|
||||
fn into_iter(self) -> Iter<'a> {
|
||||
let num_fonts = unsafe {
|
||||
(*self.as_ptr()).nfont as isize
|
||||
};
|
||||
|
||||
info!("num fonts = {}", num_fonts);
|
||||
|
||||
Iter {
|
||||
font_set: self,
|
||||
num_fonts: num_fonts as _,
|
||||
current: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = &'a PatternRef;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.current == self.num_fonts {
|
||||
None
|
||||
} else {
|
||||
let pattern = unsafe {
|
||||
let ptr = *(*self.font_set.as_ptr()).fonts.offset(self.current as isize);
|
||||
PatternRef::from_ptr(ptr)
|
||||
};
|
||||
|
||||
self.current += 1;
|
||||
Some(pattern)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
// 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 std::ptr;
|
||||
|
||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||
|
||||
use fontconfig::fontconfig as ffi;
|
||||
|
||||
use self::ffi::{FcSetSystem, FcSetApplication};
|
||||
use self::ffi::FcResultNoMatch;
|
||||
use self::ffi::{FcFontMatch, FcFontList, FcFontSort};
|
||||
use self::ffi::{FcMatchFont, FcMatchPattern, FcMatchScan};
|
||||
use self::ffi::{FC_SLANT_OBLIQUE, FC_SLANT_ITALIC, FC_SLANT_ROMAN};
|
||||
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};
|
||||
|
||||
mod config;
|
||||
pub use self::config::{Config, ConfigRef};
|
||||
|
||||
mod font_set;
|
||||
pub use self::font_set::{FontSet, FontSetRef};
|
||||
|
||||
mod object_set;
|
||||
pub use self::object_set::{ObjectSet, ObjectSetRef};
|
||||
|
||||
mod char_set;
|
||||
pub use self::char_set::{CharSet, CharSetRef};
|
||||
|
||||
mod pattern;
|
||||
pub use self::pattern::{Pattern, PatternRef};
|
||||
|
||||
/// Find the font closest matching the provided pattern.
|
||||
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
|
||||
#[allow(dead_code)]
|
||||
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 _ = 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Available font sets
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum SetName {
|
||||
System = FcSetSystem as isize,
|
||||
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,
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn font_match() {
|
||||
let mut pattern = Pattern::new();
|
||||
pattern.add_family("monospace");
|
||||
pattern.add_style("regular");
|
||||
|
||||
let config = Config::get_current();
|
||||
let font = super::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;
|
||||
}
|
||||
}
|
||||
info!("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn font_sort() {
|
||||
let mut pattern = Pattern::new();
|
||||
pattern.add_family("monospace");
|
||||
pattern.set_slant(Slant::Italic);
|
||||
|
||||
let config = Config::get_current();
|
||||
let fonts = super::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!("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn font_sort_with_glyph() {
|
||||
let mut charset = CharSet::new();
|
||||
charset.add('💖');
|
||||
let mut pattern = Pattern::new();
|
||||
pattern.add_charset(&charset);
|
||||
drop(charset);
|
||||
|
||||
let config = Config::get_current();
|
||||
let fonts = super::font_sort(config, &mut pattern).expect("font_sort");
|
||||
|
||||
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!("");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// 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 libc::c_char;
|
||||
|
||||
use foreign_types::ForeignTypeRef;
|
||||
use super::ffi::{FcObjectSetCreate, FcObjectSetAdd, FcObjectSet, FcObjectSetDestroy};
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcObjectSet;
|
||||
fn drop = FcObjectSetDestroy;
|
||||
pub struct ObjectSet;
|
||||
pub struct ObjectSetRef;
|
||||
}
|
||||
|
||||
impl ObjectSet {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> ObjectSet {
|
||||
ObjectSet(unsafe {
|
||||
FcObjectSetCreate()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectSetRef {
|
||||
fn add(&mut self, property: &[u8]) {
|
||||
unsafe {
|
||||
FcObjectSetAdd(self.as_ptr(), property.as_ptr() as *mut c_char);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_file(&mut self) {
|
||||
self.add(b"file\0");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_index(&mut self) {
|
||||
self.add(b"index\0");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_style(&mut self) {
|
||||
self.add(b"style\0");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
// 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 std::ptr;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::path::PathBuf;
|
||||
use std::str;
|
||||
|
||||
use libc::{c_char, c_int};
|
||||
use foreign_types::{ForeignTypeRef};
|
||||
|
||||
use super::ffi::FcResultMatch;
|
||||
use super::ffi::{FcPatternDestroy, FcPatternAddCharSet};
|
||||
use super::ffi::{FcPatternGetString, FcPatternCreate, FcPatternAddString};
|
||||
use super::ffi::{FcPatternGetInteger, FcPatternAddInteger};
|
||||
use super::ffi::{FcChar8, FcPattern, FcDefaultSubstitute, FcConfigSubstitute};
|
||||
|
||||
use super::{MatchKind, ConfigRef, CharSetRef, Weight, Slant};
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcPattern;
|
||||
fn drop = FcPatternDestroy;
|
||||
pub struct Pattern;
|
||||
pub struct PatternRef;
|
||||
}
|
||||
|
||||
macro_rules! pattern_add_string {
|
||||
($($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)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl Pattern {
|
||||
pub fn new() -> Pattern {
|
||||
Pattern(unsafe { FcPatternCreate() })
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! pattern_get_string {
|
||||
($($method:ident() => $property:expr),+) => {
|
||||
$(
|
||||
pub fn $method(&self, id: isize) -> Option<String> {
|
||||
unsafe {
|
||||
self.get_string($property, id)
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
int as c_int,
|
||||
&mut index
|
||||
) == 1
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pattern_get_integer {
|
||||
($($method:ident() => $property:expr),+) => {
|
||||
$(
|
||||
pub fn $method(&self, id: isize) -> Option<isize> {
|
||||
let mut index = 0 as c_int;
|
||||
unsafe {
|
||||
let result = FcPatternGetInteger(
|
||||
self.as_ptr(),
|
||||
$property.as_ptr() as *mut c_char,
|
||||
id as c_int,
|
||||
&mut index
|
||||
);
|
||||
|
||||
if result == FcResultMatch {
|
||||
Some(index as isize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
impl PatternRef {
|
||||
/// Add a string value to the pattern
|
||||
///
|
||||
/// If the returned value is `true`, the value is added at the end of
|
||||
/// any existing list, otherwise it is inserted at the beginning.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// `object` is not checked to be a valid null-terminated string
|
||||
unsafe fn add_string(&mut self, object: &[u8], value: &str) -> bool {
|
||||
let value = CString::new(&value[..]).unwrap();
|
||||
let value = value.as_ptr();
|
||||
|
||||
FcPatternAddString(
|
||||
self.as_ptr(),
|
||||
object.as_ptr() as *mut c_char,
|
||||
value as *mut FcChar8
|
||||
) == 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_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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Add charset to the pattern
|
||||
///
|
||||
/// The referenced charset is copied by fontconfig internally using
|
||||
/// FcValueSave so that no references to application provided memory are
|
||||
/// retained. That is, the CharSet can be safely dropped immediately
|
||||
/// after being added to the pattern.
|
||||
pub fn add_charset(&self, charset: &CharSetRef) -> bool {
|
||||
unsafe {
|
||||
FcPatternAddCharSet(
|
||||
self.as_ptr(),
|
||||
b"charset\0".as_ptr() as *mut c_char,
|
||||
charset.as_ptr()
|
||||
) == 1
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,586 +0,0 @@
|
|||
// 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.
|
||||
//
|
||||
pub mod fc {
|
||||
use std::ptr;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::str;
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use foreign_types::{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, FcPatternAddInteger};
|
||||
use self::ffi::{FcObjectSetCreate, FcObjectSetAdd};
|
||||
use self::ffi::{FcResultMatch, FcResultNoMatch, FcFontSetList};
|
||||
use self::ffi::{FcChar8, FcConfig, FcPattern, FcFontSet, FcObjectSet};
|
||||
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};
|
||||
use self::ffi::{FcCharSet, FcCharSetDestroy, FcPatternAddCharSet, FcCharSetAddChar};
|
||||
use self::ffi::{FcCharSetCreate};
|
||||
|
||||
/// Iterator over a font set
|
||||
pub struct FontSetIter<'a> {
|
||||
font_set: &'a FontSetRef,
|
||||
num_fonts: usize,
|
||||
current: usize,
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcPattern;
|
||||
fn drop = FcPatternDestroy;
|
||||
pub struct Pattern;
|
||||
pub struct PatternRef;
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcConfig;
|
||||
fn drop = FcConfigDestroy;
|
||||
pub struct Config;
|
||||
pub struct ConfigRef;
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcObjectSet;
|
||||
fn drop = FcObjectSetDestroy;
|
||||
pub struct ObjectSet;
|
||||
pub struct ObjectSetRef;
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcFontSet;
|
||||
fn drop = FcFontSetDestroy;
|
||||
pub struct FontSet;
|
||||
pub struct FontSetRef;
|
||||
}
|
||||
|
||||
foreign_type! {
|
||||
type CType = FcCharSet;
|
||||
fn drop = FcCharSetDestroy;
|
||||
pub struct CharSet;
|
||||
pub struct CharSetRef;
|
||||
}
|
||||
|
||||
impl ObjectSet {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> ObjectSet {
|
||||
ObjectSet(unsafe {
|
||||
FcObjectSetCreate()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the font closest matching the provided pattern.
|
||||
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
|
||||
#[allow(dead_code)]
|
||||
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 {
|
||||
FcObjectSetAdd(self.as_ptr(), property.as_ptr() as *mut c_char);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_file(&mut self) {
|
||||
self.add(b"file\0");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_index(&mut self) {
|
||||
self.add(b"index\0");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_style(&mut self) {
|
||||
self.add(b"style\0");
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! pattern_add_string {
|
||||
($($name:ident => $object:expr),*) => {
|
||||
$(
|
||||
#[inline]
|
||||
pub fn $name(&mut self, value: &str) -> bool {
|
||||
unsafe {
|
||||
self.add_string($object, value)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl Pattern {
|
||||
pub fn new() -> Pattern {
|
||||
Pattern(unsafe { FcPatternCreate() })
|
||||
}
|
||||
}
|
||||
|
||||
/// Available font sets
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum SetName {
|
||||
System = FcSetSystem as isize,
|
||||
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()
|
||||
}
|
||||
|
||||
macro_rules! pattern_get_string {
|
||||
($($method:ident() => $property:expr),+) => {
|
||||
$(
|
||||
pub fn $method(&self, id: isize) -> Option<String> {
|
||||
unsafe {
|
||||
self.get_string($property, id)
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pattern_get_integer {
|
||||
($($method:ident() => $property:expr),+) => {
|
||||
$(
|
||||
pub fn $method(&self, id: isize) -> Option<isize> {
|
||||
let mut index = 0 as c_int;
|
||||
unsafe {
|
||||
let result = FcPatternGetInteger(
|
||||
self.as_ptr(),
|
||||
$property.as_ptr() as *mut c_char,
|
||||
id as c_int,
|
||||
&mut index
|
||||
);
|
||||
|
||||
if result == FcResultMatch {
|
||||
Some(index as isize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
#[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 CharSet {
|
||||
pub fn new() -> CharSet {
|
||||
CharSet(unsafe { FcCharSetCreate() })
|
||||
}
|
||||
}
|
||||
|
||||
impl CharSetRef {
|
||||
pub fn add(&mut self, glyph: char) -> bool {
|
||||
unsafe {
|
||||
FcCharSetAddChar(
|
||||
self.as_ptr(),
|
||||
glyph as _
|
||||
) == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PatternRef {
|
||||
/// Add a string value to the pattern
|
||||
///
|
||||
/// If the returned value is `true`, the value is added at the end of
|
||||
/// any existing list, otherwise it is inserted at the beginning.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// `object` is not checked to be a valid null-terminated string
|
||||
unsafe fn add_string(&mut self, object: &[u8], value: &str) -> bool {
|
||||
let value = CString::new(&value[..]).unwrap();
|
||||
let value = value.as_ptr();
|
||||
|
||||
FcPatternAddString(
|
||||
self.as_ptr(),
|
||||
object.as_ptr() as *mut c_char,
|
||||
value as *mut FcChar8
|
||||
) == 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_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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Add charset to the pattern
|
||||
///
|
||||
/// The referenced charset is copied by fontconfig internally using
|
||||
/// FcValueSave so that no references to application provided memory are
|
||||
/// retained. That is, the CharSet can be safely dropped immediately
|
||||
/// after being added to the pattern.
|
||||
pub fn add_charset(&self, charset: &CharSetRef) -> bool {
|
||||
unsafe {
|
||||
FcPatternAddCharSet(
|
||||
self.as_ptr(),
|
||||
b"charset\0".as_ptr() as *mut c_char,
|
||||
charset.as_ptr()
|
||||
) == 1
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
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 {
|
||||
type Item = &'a PatternRef;
|
||||
type IntoIter = FontSetIter<'a>;
|
||||
fn into_iter(self) -> FontSetIter<'a> {
|
||||
let num_fonts = unsafe {
|
||||
(*self.as_ptr()).nfont as isize
|
||||
};
|
||||
|
||||
info!("num fonts = {}", num_fonts);
|
||||
|
||||
FontSetIter {
|
||||
font_set: self.deref(),
|
||||
num_fonts: num_fonts as _,
|
||||
current: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a FontSetRef {
|
||||
type Item = &'a PatternRef;
|
||||
type IntoIter = FontSetIter<'a>;
|
||||
fn into_iter(self) -> FontSetIter<'a> {
|
||||
let num_fonts = unsafe {
|
||||
(*self.as_ptr()).nfont as isize
|
||||
};
|
||||
|
||||
info!("num fonts = {}", num_fonts);
|
||||
|
||||
FontSetIter {
|
||||
font_set: self,
|
||||
num_fonts: num_fonts as _,
|
||||
current: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for FontSetIter<'a> {
|
||||
type Item = &'a PatternRef;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.current == self.num_fonts {
|
||||
None
|
||||
} else {
|
||||
let pattern = unsafe {
|
||||
let ptr = *(*self.font_set.as_ptr()).fonts.offset(self.current as isize);
|
||||
PatternRef::from_ptr(ptr)
|
||||
};
|
||||
|
||||
self.current += 1;
|
||||
Some(pattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FontSet {
|
||||
pub fn list(
|
||||
config: &ConfigRef,
|
||||
source: &mut FontSetRef,
|
||||
pattern: &PatternRef,
|
||||
objects: &ObjectSetRef
|
||||
) -> FontSet {
|
||||
let raw = unsafe {
|
||||
FcFontSetList(
|
||||
config.as_ptr(),
|
||||
&mut source.as_ptr(),
|
||||
1 /* nsets */,
|
||||
pattern.as_ptr(),
|
||||
objects.as_ptr(),
|
||||
)
|
||||
};
|
||||
FontSet(raw)
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Get the current configuration
|
||||
pub fn get_current() -> &'static ConfigRef {
|
||||
unsafe {
|
||||
ConfigRef::from_ptr(FcConfigGetCurrent())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigRef {
|
||||
/// Returns one of the two sets of fonts from the configuration as
|
||||
/// specified by `set`.
|
||||
pub fn get_fonts<'a>(&'a self, set: SetName) -> &'a FontSetRef {
|
||||
unsafe {
|
||||
let ptr = FcConfigGetFonts(self.as_ptr(), set as u32);
|
||||
FontSetRef::from_ptr(ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::fc;
|
||||
|
||||
#[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;
|
||||
}
|
||||
}
|
||||
info!("");
|
||||
}
|
||||
|
||||
#[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!("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn font_sort_with_glyph() {
|
||||
let mut charset = fc::CharSet::new();
|
||||
charset.add('💖');
|
||||
let mut pattern = fc::Pattern::new();
|
||||
pattern.add_charset(&charset);
|
||||
drop(charset);
|
||||
|
||||
let config = fc::Config::get_current();
|
||||
let fonts = fc::font_sort(config, &mut pattern).expect("font_sort");
|
||||
|
||||
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!("");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,9 +19,8 @@ use std::cmp::min;
|
|||
use freetype::{self, Library, Face};
|
||||
|
||||
|
||||
mod list_fonts;
|
||||
mod fc;
|
||||
|
||||
use self::list_fonts::fc;
|
||||
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};
|
||||
|
||||
/// Rasterizes glyphs for a single font face.
|
||||
|
|
Loading…
Reference in New Issue