mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
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:
parent
be1935e9ad
commit
d15dd2f199
4 changed files with 175 additions and 30 deletions
|
@ -1 +1 @@
|
|||
Subproject commit 351d5a3398f088c39d5aec28760d185237a32c66
|
||||
Subproject commit 29e5fa637965d7ce2c1b9b1347d8fe6054a71243
|
|
@ -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))
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue