Add ffi-util crate and use in fontconfig wrapper

This cleans up and fixes the C-type wrapping for fontconfig.
This commit is contained in:
Joe Wilm 2016-12-30 18:55:10 -08:00
parent 44c6171bc0
commit a00970c9a8
7 changed files with 160 additions and 109 deletions

5
Cargo.lock generated
View File

@ -230,6 +230,10 @@ dependencies = [
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ffi-util"
version = "0.1.0"
[[package]]
name = "filetime"
version = "0.1.10"
@ -247,6 +251,7 @@ dependencies = [
"core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ffi-util 0.1.0",
"freetype-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-fontconfig 0.2.0 (git+https://github.com/jwilm/rust-fontconfig)",

6
ffi-util/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "ffi-util"
version = "0.1.0"
authors = ["Joe Wilm <joe@jwilm.com>"]
[dependencies]

102
ffi-util/src/lib.rs Normal file
View File

@ -0,0 +1,102 @@
// Copyright 2011 Google Inc.
// 2013 Jack Lloyd
// 2013-2014 Steven Fackler
//
// 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::cell::UnsafeCell;
/// This is intended to be used as the inner type for `FooRef` types converted from raw C pointers.
/// It has an `UnsafeCell` internally to inform the compiler about aliasability and doesn't
/// implement `Copy`, so it can't be dereferenced.
pub struct Opaque(UnsafeCell<()>);
/// A type implemented by wrappers over foreign types.
///
/// This should not be implemented by anything outside of this crate; new methods may be added at
/// any time.
pub trait ForeignType: Sized {
/// The raw C type.
type CType;
/// The type representing a reference to this type.
type Ref: ForeignTypeRef<CType = Self::CType>;
/// Constructs an instance of this type from its raw type.
unsafe fn from_ptr(ptr: *mut Self::CType) -> Self;
}
/// A trait implemented by types which reference borrowed foreign types.
///
/// This should not be implemented by anything outside of this crate; new methods may be added at
/// any time.
pub trait ForeignTypeRef: Sized {
/// The raw C type.
type CType;
/// Constructs a shared instance of this type from its raw type.
unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self {
&*(ptr as *mut _)
}
/// Constructs a mutable reference of this type from its raw type.
unsafe fn from_ptr_mut<'a>(ptr: *mut Self::CType) -> &'a mut Self {
&mut *(ptr as *mut _)
}
/// Returns a raw pointer to the wrapped value.
fn as_ptr(&self) -> *mut Self::CType {
self as *const _ as *mut _
}
}
#[macro_export]
macro_rules! ffi_type {
($n:ident, $r:ident, $c:path, $d:path) => {
pub struct $n(*mut $c);
impl $crate::ForeignType for $n {
type CType = $c;
type Ref = $r;
unsafe fn from_ptr(ptr: *mut $c) -> $n {
$n(ptr)
}
}
impl Drop for $n {
fn drop(&mut self) {
unsafe { $d(self.0) }
}
}
impl ::std::ops::Deref for $n {
type Target = $r;
fn deref(&self) -> &$r {
unsafe { $crate::ForeignTypeRef::from_ptr(self.0) }
}
}
impl ::std::ops::DerefMut for $n {
fn deref_mut(&mut self) -> &mut $r {
unsafe { $crate::ForeignTypeRef::from_ptr_mut(self.0) }
}
}
pub struct $r($crate::Opaque);
impl $crate::ForeignTypeRef for $r {
type CType = $c;
}
}
}

5
font/Cargo.lock generated
View File

@ -7,6 +7,7 @@ dependencies = [
"core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ffi-util 0.1.0",
"freetype-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-fontconfig 0.2.0 (git+https://github.com/jwilm/rust-fontconfig)",
@ -75,6 +76,10 @@ dependencies = [
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ffi-util"
version = "0.1.0"
[[package]]
name = "freetype-rs"
version = "0.9.0"

View File

@ -8,6 +8,7 @@ license = "Apache-2.0"
[dependencies]
euclid = "0.6.8"
libc = "0.2.11"
ffi-util = { path = "../ffi-util" }
[target.'cfg(not(target_os = "macos"))'.dependencies]
servo-fontconfig = { git = "https://github.com/jwilm/rust-fontconfig" }

View File

@ -20,12 +20,14 @@ mod fc {
use std::ptr;
use std::ffi::{CStr, CString};
use std::str;
use std::ops::{Deref, DerefMut};
use std::ops::Deref;
use ffi_util::ForeignTypeRef;
use libc::{c_char, c_int};
use fontconfig::fontconfig as ffi;
use self::ffi::{FcConfigGetCurrent, FcConfigGetFonts};
use self::ffi::{FcConfigGetCurrent, FcConfigGetFonts, FcSetSystem, FcSetApplication};
use self::ffi::{FcPatternGetString, FcPatternCreate, FcPatternAddString};
use self::ffi::{FcPatternGetInteger};
use self::ffi::{FcObjectSetCreate, FcObjectSetAdd};
@ -33,15 +35,6 @@ mod fc {
use self::ffi::{FcChar8, FcConfig, FcPattern, FcFontSet, FcObjectSet};
use self::ffi::{FcFontSetDestroy, FcPatternDestroy, FcObjectSetDestroy, FcConfigDestroy};
/// FcConfig - Font Configuration
pub struct Config(*mut FcConfig);
/// FcFontSet
pub struct FontSet(*mut FcFontSet);
/// FcFontSet reference
pub struct FontSetRef(*mut FcFontSet);
/// Iterator over a font set
pub struct FontSetIter<'a> {
font_set: &'a FontSetRef,
@ -49,51 +42,10 @@ mod fc {
current: usize,
}
macro_rules! ref_type {
($($owned:ty => $refty:ty),*) => {
$(
impl Deref for $owned {
type Target = $refty;
fn deref(&self) -> &Self::Target {
unsafe {
&*(self.0 as *mut _)
}
}
}
impl DerefMut for $owned {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
&mut *(self.0 as *mut _)
}
}
}
)*
}
}
/// FcPattern
pub struct Pattern(*mut FcPattern);
/// FcObjectSet
pub struct ObjectSet(*mut FcObjectSet);
/// FcObjectSet reference
pub struct ObjectSetRef(*mut FcObjectSet);
ref_type! {
ObjectSet => ObjectSetRef,
Pattern => PatternRef,
FontSet => FontSetRef
}
impl Drop for ObjectSet {
fn drop(&mut self) {
unsafe {
FcObjectSetDestroy(self.0);
}
}
}
ffi_type!(Pattern, PatternRef, FcPattern, FcPatternDestroy);
ffi_type!(Config, ConfigRef, FcConfig, FcConfigDestroy);
ffi_type!(ObjectSet, ObjectSetRef, FcObjectSet, FcObjectSetDestroy);
ffi_type!(FontSet, FontSetRef, FcFontSet, FcFontSetDestroy);
impl ObjectSet {
pub fn new() -> ObjectSet {
@ -103,11 +55,10 @@ mod fc {
}
}
impl ObjectSetRef {
fn add(&mut self, property: &[u8]) {
unsafe {
FcObjectSetAdd(self.0, property.as_ptr() as *mut c_char);
FcObjectSetAdd(self.as_ptr(), property.as_ptr() as *mut c_char);
}
}
@ -144,21 +95,11 @@ mod fc {
}
}
impl Drop for Pattern {
fn drop(&mut self) {
unsafe {
FcPatternDestroy(self.0);
}
}
}
/// FcPattern reference
pub struct PatternRef(*mut FcPattern);
/// Available font sets
#[derive(Debug, Copy, Clone)]
pub enum SetName {
System = 0,
Application = 1,
System = FcSetSystem as isize,
Application = FcSetApplication as isize,
}
pub unsafe fn char8_to_string(fc_str: *mut FcChar8) -> String {
@ -173,7 +114,7 @@ mod fc {
let mut format: *mut FcChar8 = ptr::null_mut();
let result = FcPatternGetString(
self.0,
self.as_ptr(),
$property.as_ptr() as *mut c_char,
id as c_int,
&mut format
@ -197,7 +138,7 @@ mod fc {
let mut index = 0 as c_int;
unsafe {
let result = FcPatternGetInteger(
self.0,
self.as_ptr(),
$property.as_ptr() as *mut c_char,
id as c_int,
&mut index
@ -228,7 +169,7 @@ mod fc {
let value = value.as_ptr();
FcPatternAddString(
self.0,
self.as_ptr(),
object.as_ptr() as *mut c_char,
value as *mut FcChar8
) == 1
@ -255,11 +196,11 @@ mod fc {
type IntoIter = FontSetIter<'a>;
fn into_iter(self) -> FontSetIter<'a> {
let num_fonts = unsafe {
(*self.0).nfont as isize
(*self.as_ptr()).nfont as isize
};
FontSetIter {
font_set: unsafe { &*(self.0 as *mut _) },
font_set: self.deref(),
num_fonts: num_fonts as _,
current: 0,
}
@ -271,7 +212,7 @@ mod fc {
type IntoIter = FontSetIter<'a>;
fn into_iter(self) -> FontSetIter<'a> {
let num_fonts = unsafe {
(*self.0).nfont as isize
(*self.as_ptr()).nfont as isize
};
FontSetIter {
@ -290,8 +231,8 @@ mod fc {
None
} else {
let pattern = unsafe {
let ptr = *(*self.font_set.0).fonts.offset(self.current as isize);
&*(ptr as *mut _)
let ptr = *(*self.font_set.as_ptr()).fonts.offset(self.current as isize);
PatternRef::from_ptr(ptr)
};
self.current += 1;
@ -302,18 +243,18 @@ mod fc {
impl FontSet {
pub fn list(
config: &Config,
config: &ConfigRef,
source: &mut FontSetRef,
pattern: &PatternRef,
objects: &ObjectSetRef
) -> FontSet {
let raw = unsafe {
FcFontSetList(
config.0,
&mut source.0,
config.as_ptr(),
&mut source.as_ptr(),
1 /* nsets */,
pattern.0,
objects.0
pattern.as_ptr(),
objects.as_ptr(),
)
};
FontSet(raw)
@ -322,34 +263,20 @@ mod fc {
impl Config {
/// Get the current configuration
pub fn get_current() -> Config {
Config(unsafe { FcConfigGetCurrent() })
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.0, set as u32);
&*(ptr as *mut _)
}
}
}
impl Drop for FontSet {
fn drop(&mut self) {
unsafe {
FcFontSetDestroy(self.0)
}
}
}
impl Drop for Config {
fn drop(&mut self) {
unsafe {
if self.0 != FcConfigGetCurrent() {
FcConfigDestroy(self.0)
}
let ptr = FcConfigGetFonts(self.as_ptr(), set as u32);
FontSetRef::from_ptr(ptr)
}
}
}
@ -363,9 +290,11 @@ fn list_families() -> Vec<String> {
for font in font_set {
if let Some(format) = font.fontformat(0) {
if format == "TrueType" || format == "CFF" {
let id = 0;
while let Some(family) = font.family(id) {
families.push(family);
for id in 0.. {
match font.family(id) {
Some(family) => families.push(family),
None => break,
}
}
}
}

View File

@ -36,6 +36,9 @@ extern crate core_graphics;
extern crate euclid;
extern crate libc;
#[macro_use]
extern crate ffi_util;
use std::fmt;
use std::sync::atomic::{AtomicU32, ATOMIC_U32_INIT, Ordering};