Add basic fontconfig support - doesn't crash, and renders text in Josefin if the font is present in the fontconfig cache.

This commit is contained in:
Josh Matthews 2012-12-26 00:13:38 -05:00
parent be1935e9ad
commit d15dd2f199
4 changed files with 175 additions and 30 deletions

@ -1 +1 @@
Subproject commit 351d5a3398f088c39d5aec28760d185237a32c66
Subproject commit 29e5fa637965d7ce2c1b9b1347d8fe6054a71243

View file

@ -6,24 +6,92 @@ use ft = freetype;
use gfx_font::FontHandle;
use gfx_font_list::{FontEntry, FontFamily, FontFamilyMap};
use freetype_impl::font_context::FreeTypeFontContextHandle;
use self::fontconfig::fontconfig::{FcConfig, FcFontSet, FcChar8,
FcResultMatch, FcSetSystem, FcPattern,
FcResultNoMatch, FcMatchPattern};
use self::fontconfig::fontconfig::bindgen::{
FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
FcInitReinitialize, FcPatternDestroy, FcPatternReference,
FcFontSetDestroy, FcCharSetDestroy, FcConfigSubstitute,
FcDefaultSubstitute, FcPatternCreate, FcPatternAddString,
FcFontMatch,
};
use core::dvec::DVec;
use core::send_map::{linear, SendMap};
use libc::c_int;
use ptr::Ptr;
pub struct FontconfigFontListHandle {
fctx: (),
fctx: FreeTypeFontContextHandle,
}
pub impl FontconfigFontListHandle {
static pub fn new(_fctx: &native::FontContextHandle) -> FontconfigFontListHandle {
FontconfigFontListHandle { fctx: () }
static pub fn new(fctx: &native::FontContextHandle) -> FontconfigFontListHandle {
FontconfigFontListHandle { fctx: fctx.clone() }
}
fn get_available_families() -> FontFamilyMap {
fail;
let mut family_map : FontFamilyMap = linear::LinearMap();
unsafe {
let config = FcConfigGetCurrent();
let fontSet = FcConfigGetFonts(config, FcSetSystem);
for uint::range(0, (*fontSet).nfont as uint) |i| {
let font = (*fontSet).fonts.offset(i);
let family: *FcChar8 = ptr::null();
let mut v: c_int = 0;
do str::as_c_str("family") |FC_FAMILY| {
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
let family_name = str::raw::from_buf(family as *u8);
debug!("Creating new FontFamily for family: %s", family_name);
let new_family = @FontFamily::new(family_name);
family_map.insert(family_name, new_family);
v += 1;
}
}
}
}
return family_map;
}
fn load_variations_for_family(family: @FontFamily) {
fn load_variations_for_family(_family: @FontFamily) {
fail
}
}
pub fn path_from_identifier(name: ~str) -> Result<~str, ()> unsafe {
let config = FcConfigGetCurrent();
let pattern = FcPatternCreate();
let res = do str::as_c_str("family") |FC_FAMILY| {
do str::as_c_str(name) |family| {
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
}
};
if res != 1 {
debug!("adding family to pattern failed");
return Err(());
}
if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
debug!("substitution failed");
return Err(());
}
FcDefaultSubstitute(pattern);
let result = FcResultNoMatch;
let result_pattern = FcFontMatch(config, pattern, &result);
if result != FcResultMatch && result_pattern.is_null() {
debug!("obtaining match to pattern failed");
return Err(());
}
let file: *FcChar8 = ptr::null();
let res = do str::as_c_str("file") |FC_FILE| {
FcPatternGetString(result_pattern, FC_FILE, 0, &file)
};
if res != FcResultMatch {
debug!("getting filename for font failed");
return Err(());
}
Ok(str::raw::from_buf(file as *u8))
}

View file

@ -12,6 +12,15 @@ use gfx_font::{
FractionalPixel,
SpecifiedFontStyle,
UsedFontStyle,
FontWeight100,
FontWeight200,
FontWeight300,
FontWeight400,
FontWeight500,
FontWeight600,
FontWeight700,
FontWeight800,
FontWeight900,
};
use geometry::Au;
use text::glyph::GlyphIndex;
@ -31,6 +40,9 @@ use self::freetype::freetype::{
FT_SizeRec,
FT_UInt,
FT_Size_Metrics,
FT_STYLE_FLAG_ITALIC,
FT_STYLE_FLAG_BOLD,
ft_sfnt_os2
};
use self::freetype::freetype::bindgen::{
FT_Init_FreeType,
@ -38,9 +50,13 @@ use self::freetype::freetype::bindgen::{
FT_New_Memory_Face,
FT_Done_Face,
FT_Get_Char_Index,
FT_Get_Postscript_Name,
FT_Load_Glyph,
FT_Set_Char_Size
FT_Set_Char_Size,
FT_New_Face,
FT_Get_Sfnt_Table
};
use self::freetype::tt_os2::TT_OS2;
fn float_to_fixed_ft(f: float) -> i32 {
float_to_fixed(6, f)
@ -76,9 +92,39 @@ pub struct FreeTypeFontHandle {
}
pub impl FreeTypeFontHandle {
static priv fn set_char_size(face: FT_Face, pt_size: float) -> Result<(), ()>{
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let h_dpi = 72;
let v_dpi = 72;
let result = FT_Set_Char_Size(face, char_width, char_height, h_dpi, v_dpi);
if result.succeeded() { Ok(()) } else { Err(()) }
}
static pub fn new_from_file(fctx: &FreeTypeFontContextHandle, file: ~str,
style: &SpecifiedFontStyle) -> Result<FreeTypeFontHandle, ()> {
let ft_ctx: FT_Library = fctx.ctx.ctx;
if ft_ctx.is_null() { return Err(()); }
let mut face: FT_Face = ptr::null();
let face_index = 0 as FT_Long;
do str::as_c_str(file) |file_str| {
FT_New_Face(ft_ctx, file_str,
face_index, ptr::to_unsafe_ptr(&face));
}
if face.is_null() {
return Err(());
}
if FreeTypeFontHandle::set_char_size(face, style.pt_size).is_ok() {
Ok(FreeTypeFontHandle { buf: ~[], face: face })
} else {
Err(())
}
}
static pub fn new_from_buffer(fctx: &FreeTypeFontContextHandle,
buf: ~[u8], style: &SpecifiedFontStyle) -> Result<FreeTypeFontHandle, ()> {
let ft_ctx: FT_Library = fctx.ctx;
let ft_ctx: FT_Library = fctx.ctx.ctx;
if ft_ctx.is_null() { return Err(()); }
let face_result = do vec::as_imm_buf(buf) |bytes: *u8, len: uint| {
@ -105,15 +151,11 @@ pub impl FreeTypeFontHandle {
if !result.succeeded() || face.is_null() {
return Err(());
}
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let h_dpi = 72;
let v_dpi = 72;
let result = FT_Set_Char_Size(face, char_width, char_height, h_dpi, v_dpi);
if !result.succeeded() { return Err(()); }
Ok(face)
if FreeTypeFontHandle::set_char_size(face, pt_size).is_ok() {
Ok(face)
} else {
Err(())
}
}
}
}
@ -122,19 +164,44 @@ pub impl FreeTypeFontHandle : FontHandleMethods {
// an identifier usable by FontContextHandle to recreate this FontHandle.
pure fn face_identifier() -> ~str {
fail;
/* FT_Get_Postscript_Name seems like a better choice here, but it
doesn't give usable results for fontconfig when deserializing. */
unsafe { str::raw::from_c_str((*self.face).family_name) }
}
pure fn family_name() -> ~str {
fail;
unsafe { str::raw::from_c_str((*self.face).family_name) }
}
pure fn face_name() -> ~str {
fail;
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
}
pure fn is_italic() -> bool {
fail;
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
}
pure fn boldness() -> CSSFontWeight {
fail;
let default_weight = FontWeight400;
if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
default_weight
} else {
let os2 = unsafe { FT_Get_Sfnt_Table(self.face, ft_sfnt_os2) as *TT_OS2 };
let valid = os2.is_not_null() && unsafe { (*os2).version != 0xffff };
if valid {
let weight = unsafe { (*os2).usWeightClass };
match weight {
1 | 100..199 => FontWeight100,
2 | 200..299 => FontWeight200,
3 | 300..399 => FontWeight300,
4 | 400..499 => FontWeight400,
5 | 500..599 => FontWeight500,
6 | 600..699 => FontWeight600,
7 | 700..799 => FontWeight700,
8 | 800..899 => FontWeight800,
9 | 900..999 => FontWeight900,
_ => default_weight
}
} else {
default_weight
}
}
}
fn clone_with_style(_fctx: &native::FontContextHandle,
@ -197,7 +264,7 @@ pub impl FreeTypeFontHandle : FontHandleMethods {
}
fn get_table_for_tag(_tag: FontTableTag) -> Option<FontTable> {
fail;
None
}
}

View file

@ -1,4 +1,5 @@
extern mod freetype;
extern mod fontconfig;
use self::freetype::freetype::{
FTErrorMethods,
@ -9,14 +10,16 @@ use self::freetype::freetype::bindgen::{
FT_Init_FreeType,
FT_Done_FreeType
};
use fontconfig::font_list::path_from_identifier;
use gfx_font::{
FontHandle,
UsedFontStyle,
};
use font_context::FontContextHandleMethods;
use freetype_impl::font::FreeTypeFontHandle;
pub struct FreeTypeFontContextHandle {
struct FreeTypeLibraryHandle {
ctx: FT_Library,
drop {
@ -25,6 +28,10 @@ pub struct FreeTypeFontContextHandle {
}
}
pub struct FreeTypeFontContextHandle {
ctx: @FreeTypeLibraryHandle,
}
pub impl FreeTypeFontContextHandle {
static pub fn new() -> FreeTypeFontContextHandle {
let ctx: FT_Library = ptr::null();
@ -32,20 +39,23 @@ pub impl FreeTypeFontContextHandle {
if !result.succeeded() { fail; }
FreeTypeFontContextHandle {
ctx: ctx,
ctx: @FreeTypeLibraryHandle { ctx: ctx },
}
}
}
pub impl FreeTypeFontContextHandle : FontContextHandleMethods {
pure fn clone(&const self) -> FreeTypeFontContextHandle {
fail
FreeTypeFontContextHandle { ctx: self.ctx }
}
fn create_font_from_identifier(_identifier: ~str, _style: UsedFontStyle)
-> Result<FontHandle, ()> {
fail;
fn create_font_from_identifier(name: ~str, style: UsedFontStyle)
-> Result<FontHandle, ()> unsafe {
debug!("Creating font handle for %s", name);
do path_from_identifier(name).chain |file_name| {
debug!("Opening font face %s", file_name);
FreeTypeFontHandle::new_from_file(&self, file_name, &style)
}
}
}