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};
|
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};
|
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style};
|
||||||
|
|
||||||
/// Rasterizes glyphs for a single font face.
|
/// Rasterizes glyphs for a single font face.
|
||||||
|
|
Loading…
Reference in New Issue