aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2012-12-26 00:13:38 -0500
committerJosh Matthews <josh@joshmatthews.net>2012-12-26 00:13:38 -0500
commitd15dd2f199a3d5405292ee943f4ff91ca424a506 (patch)
tree7a71b0f3d472127ab7c881e88d1f20b2ce37fdbf
parentbe1935e9ad499f053521cbb5e2721fdfacff84f5 (diff)
downloadservo-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-freetype0
-rw-r--r--src/servo-gfx/fontconfig/font_list.rs78
-rw-r--r--src/servo-gfx/freetype_impl/font.rs101
-rw-r--r--src/servo-gfx/freetype_impl/font_context.rs24
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)
+ }
}
}