diff options
author | Josh Matthews <josh@joshmatthews.net> | 2012-12-26 00:13:38 -0500 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2012-12-26 00:13:38 -0500 |
commit | d15dd2f199a3d5405292ee943f4ff91ca424a506 (patch) | |
tree | 7a71b0f3d472127ab7c881e88d1f20b2ce37fdbf | |
parent | be1935e9ad499f053521cbb5e2721fdfacff84f5 (diff) | |
download | servo-d15dd2f199a3d5405292ee943f4ff91ca424a506.tar.gz servo-d15dd2f199a3d5405292ee943f4ff91ca424a506.zip |
Add basic fontconfig support - doesn't crash, and renders text in Josefin if the font is present in the fontconfig cache.
m--------- | src/rust-freetype | 0 | ||||
-rw-r--r-- | src/servo-gfx/fontconfig/font_list.rs | 78 | ||||
-rw-r--r-- | src/servo-gfx/freetype_impl/font.rs | 101 | ||||
-rw-r--r-- | src/servo-gfx/freetype_impl/font_context.rs | 24 |
4 files changed, 174 insertions, 29 deletions
diff --git a/src/rust-freetype b/src/rust-freetype -Subproject 351d5a3398f088c39d5aec28760d185237a32c6 +Subproject 29e5fa637965d7ce2c1b9b1347d8fe6054a7124 diff --git a/src/servo-gfx/fontconfig/font_list.rs b/src/servo-gfx/fontconfig/font_list.rs index 5242929b021..d0df8c854af 100644 --- a/src/servo-gfx/fontconfig/font_list.rs +++ b/src/servo-gfx/fontconfig/font_list.rs @@ -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)) +}
\ No newline at end of file diff --git a/src/servo-gfx/freetype_impl/font.rs b/src/servo-gfx/freetype_impl/font.rs index 2056c6c0400..746007ed25f 100644 --- a/src/servo-gfx/freetype_impl/font.rs +++ b/src/servo-gfx/freetype_impl/font.rs @@ -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 } } diff --git a/src/servo-gfx/freetype_impl/font_context.rs b/src/servo-gfx/freetype_impl/font_context.rs index 39618abfb5e..b8d455996db 100644 --- a/src/servo-gfx/freetype_impl/font_context.rs +++ b/src/servo-gfx/freetype_impl/font_context.rs @@ -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) + } } } |