From a00970c9a83d0a9033e70650beb2f4a924cfe9cc Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 30 Dec 2016 18:55:10 -0800 Subject: [PATCH] Add ffi-util crate and use in fontconfig wrapper This cleans up and fixes the C-type wrapping for fontconfig. --- Cargo.lock | 5 ++ ffi-util/Cargo.toml | 6 ++ ffi-util/src/lib.rs | 102 ++++++++++++++++++++++++++ font/Cargo.lock | 5 ++ font/Cargo.toml | 1 + font/src/ft/list_fonts.rs | 147 ++++++++++---------------------------- font/src/lib.rs | 3 + 7 files changed, 160 insertions(+), 109 deletions(-) create mode 100644 ffi-util/Cargo.toml create mode 100644 ffi-util/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 0d81b26..1a8a793 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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)", diff --git a/ffi-util/Cargo.toml b/ffi-util/Cargo.toml new file mode 100644 index 0000000..740a3b9 --- /dev/null +++ b/ffi-util/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ffi-util" +version = "0.1.0" +authors = ["Joe Wilm "] + +[dependencies] diff --git a/ffi-util/src/lib.rs b/ffi-util/src/lib.rs new file mode 100644 index 0000000..be82e56 --- /dev/null +++ b/ffi-util/src/lib.rs @@ -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; + + /// 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; + } + } +} diff --git a/font/Cargo.lock b/font/Cargo.lock index 5dde9e4..9464e20 100644 --- a/font/Cargo.lock +++ b/font/Cargo.lock @@ -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" diff --git a/font/Cargo.toml b/font/Cargo.toml index d6cfcc3..f0c3e06 100644 --- a/font/Cargo.toml +++ b/font/Cargo.toml @@ -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" } diff --git a/font/src/ft/list_fonts.rs b/font/src/ft/list_fonts.rs index 86ee970..0fbc723 100644 --- a/font/src/ft/list_fonts.rs +++ b/font/src/ft/list_fonts.rs @@ -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 { 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, + } } } } diff --git a/font/src/lib.rs b/font/src/lib.rs index ca8de0a..7ec5984 100644 --- a/font/src/lib.rs +++ b/font/src/lib.rs @@ -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};