From 9f94b54c89f65ef868e3de099f41059588af49d8 Mon Sep 17 00:00:00 2001 From: "Brian J. Burg" Date: Fri, 26 Oct 2012 19:53:13 -0700 Subject: [PATCH] Create FontStyle, FontFaceProperties, and hook up (hardcoded) adjustable font sizes. Also ripped out some native font tests that won't make sense with font machinery refactor. --- src/servo/text/font.rs | 98 +++++++++++++------ src/servo/text/font_cache.rs | 16 ++- src/servo/text/native_font.rs | 54 +--------- src/servo/text/native_font/ft_native_font.rs | 34 ++----- .../text/native_font/quartz_native_font.rs | 23 ++--- 5 files changed, 99 insertions(+), 126 deletions(-) diff --git a/src/servo/text/font.rs b/src/servo/text/font.rs index e69c4f80ac1..06f4b09c78e 100644 --- a/src/servo/text/font.rs +++ b/src/servo/text/font.rs @@ -19,25 +19,6 @@ use text::text_run::TextRun; // Used to abstract over the shaper's choice of fixed int representation. type FractionalPixel = float; -/** -A font handle. Layout can use this to calculate glyph metrics -and the renderer can use it to render text. -*/ -struct Font { - // TODO: is this actually needed? -bjb - // A back reference to keep the library alive - priv lib: @FontCache, - priv fontbuf: @~[u8], - priv native_font: NativeFont, - priv mut azure_font: Option, - metrics: FontMetrics, - - drop { - use azure::bindgen::AzReleaseScaledFont; - do (copy self.azure_font).iter |fontref| { AzReleaseScaledFont(*fontref); } - } -} - struct FontMetrics { underline_size: Au, underline_offset: Au, @@ -49,29 +30,80 @@ struct FontMetrics { max_advance: Au } -struct RunMetrics { - // may be negative due to negative width - advance_width: Au, +// TODO: use enum from CSS bindings +enum CSSFontWeight { + FontWeight100, + FontWeight200, + FontWeight300, + FontWeight400, + FontWeight500, + FontWeight600, + FontWeight700, + FontWeight800, + FontWeight900, +} +struct FontStyle { + pt_size: float, + weight: CSSFontWeight, + italic: bool, + oblique: bool, +} + +struct FontFaceProperties { + family_name: @str, + face_name: ~str, + priv weight: u16, + priv italic: bool, +} + +impl FontFaceProperties { + pure fn is_bold() -> bool { self.weight >= (500 as u16) } + pure fn is_italic() -> bool { self.italic } +} + +struct RunMetrics { + // may be negative due to negative width (i.e., kerning of '.' in 'P.T.') + advance_width: Au, ascent: Au, // nonzero descent: Au, // nonzero - // this bounding box is relative to the left origin baseline. // so, bounding_box.position.y = -ascent bounding_box: Rect } +/** +A font handle. Layout can use this to calculate glyph metrics +and the renderer can use it to render text. +*/ +struct Font { + // TODO: is this actually needed? -bjb + // A back reference to keep the library alive + priv lib: @FontCache, + priv fontbuf: @~[u8], + priv native_font: NativeFont, + priv mut azure_font: Option, + style: FontStyle, + metrics: FontMetrics, + + drop { + use azure::bindgen::AzReleaseScaledFont; + do (copy self.azure_font).iter |fontref| { AzReleaseScaledFont(*fontref); } + } +} + impl Font { // TODO: who should own fontbuf? - static fn new(lib: @FontCache, fontbuf: @~[u8], native_font: NativeFont) -> Font { + static fn new(lib: @FontCache, fontbuf: @~[u8], native_font: NativeFont, style: FontStyle) -> Font { let metrics = native_font.get_metrics(); Font { lib: lib, fontbuf : fontbuf, - metrics: move metrics, native_font : move native_font, - azure_font: None + azure_font: None, + style: move style, + metrics: move metrics, } } @@ -100,6 +132,7 @@ impl Font { // stones and manual memory management, and put them inside of // azure_hl.rs and elsewhere instead. let cfont = get_cairo_font(&self); + // TODO: This should probably not even use cairo let azfont = AzCreateScaledFontWithCairo(ptr::to_unsafe_ptr(&nfont), 1f as AzFloat, cfont); assert azfont.is_not_null(); cairo_scaled_font_destroy(cfont); @@ -107,6 +140,9 @@ impl Font { self.azure_font = Some(azfont); return azfont; + // TODO: these cairo-related things should be in rust-cairo. + // creating a cairo font/face from a native font resource + // should be part of the NativeFont API, not exposed here. #[cfg(target_os = "linux")] fn get_cairo_face(font: &Font) -> *cairo_font_face_t { use cairo::cairo_ft::bindgen::{cairo_ft_font_face_create_for_ft_face}; @@ -151,10 +187,14 @@ impl Font { cairo_matrix_init_identity(ptr::to_unsafe_ptr(&idmatrix)); let fontmatrix = idmatrix; - cairo_matrix_scale(ptr::to_unsafe_ptr(&fontmatrix), 21f as c_double, 21f as c_double); + cairo_matrix_scale(ptr::to_unsafe_ptr(&fontmatrix), + font.style.pt_size as c_double, + font.style.pt_size as c_double); let options = cairo_font_options_create(); - let cfont = cairo_scaled_font_create(face, ptr::to_unsafe_ptr(&fontmatrix), - ptr::to_unsafe_ptr(&idmatrix), options); + let cfont = cairo_scaled_font_create(face, + ptr::to_unsafe_ptr(&fontmatrix), + ptr::to_unsafe_ptr(&idmatrix), + options); cairo_font_options_destroy(options); cairo_font_face_destroy(face); diff --git a/src/servo/text/font_cache.rs b/src/servo/text/font_cache.rs index 1f2a7bf295d..832af0c6226 100644 --- a/src/servo/text/font_cache.rs +++ b/src/servo/text/font_cache.rs @@ -1,4 +1,7 @@ -use font::{Font, test_font_bin}; +use font::{Font, + FontStyle, + FontWeight300, + test_font_bin}; struct FontCache { native_lib: native::NativeFontCache, @@ -37,13 +40,20 @@ fn FontCache() -> @FontCache { fn create_font(lib: @FontCache, native_lib: &native::NativeFontCache) -> Result<@Font, ()> { let font_bin = @test_font_bin(); - let native_font = native_font::create(native_lib, font_bin); + let dummy_style = FontStyle { + pt_size: 40f, + weight: FontWeight300, + italic: false, + oblique: false + }; + let native_font = native_font::create(native_lib, font_bin, dummy_style.pt_size); let native_font = if native_font.is_ok() { result::unwrap(move native_font) } else { return Err(native_font.get_err()); }; - return Ok(@Font::new(lib, font_bin, move native_font)); + + return Ok(@Font::new(lib, font_bin, move native_font, move dummy_style)); } #[cfg(target_os = "linux")] diff --git a/src/servo/text/native_font.rs b/src/servo/text/native_font.rs index 31d9fa5f05d..d59dbdf5e31 100644 --- a/src/servo/text/native_font.rs +++ b/src/servo/text/native_font.rs @@ -14,57 +14,13 @@ pub type NativeFont/& = quartz_native_font::QuartzNativeFont; #[cfg(target_os = "linux")] pub type NativeFont/& = ft_native_font::FreeTypeNativeFont; +// TODO: this should be part of trait NativeFont #[cfg(target_os = "macos")] -pub fn create(_native_lib: &NativeFontCache, buf: @~[u8]) -> Result { - quartz_native_font::create(buf) +pub fn create(native_lib: &NativeFontCache, buf: @~[u8], pt_size: float) -> Result { + quartz_native_font::create(native_lib, buf, pt_size) } #[cfg(target_os = "linux")] -pub fn create(native_lib: &NativeFontCache, buf: @~[u8]) -> Result { - ft_native_font::create(native_lib, buf) -} - -#[cfg(target_os = "macos")] -pub fn with_test_native_font(f: fn@(nf: &NativeFont)) { - quartz_native_font::with_test_native_font(f); -} - -#[cfg(target_os = "linux")] -pub fn with_test_native_font(f: fn@(nf: &NativeFont)) { - ft_native_font::with_test_native_font(f); -} - -#[test] -fn should_get_glyph_indexes() { - with_test_native_font(|font| { - let idx = font.glyph_index('w'); - assert idx == Some(40u as GlyphIndex); - }) -} - -#[test] -fn should_return_none_glyph_index_for_bad_codepoints() { - with_test_native_font(|font| { - let idx = font.glyph_index(0 as char); - assert idx == None; - }) -} - -#[test] -#[ignore] -fn should_get_glyph_h_advance() { - with_test_native_font(|font| { - let adv = font.glyph_h_advance(40u as GlyphIndex); - // TODO: add correct advances; these are old - assert adv == Some(15f); - }) -} - -#[test] -#[ignore] -fn should_return_none_glyph_h_advance_for_bad_codepoints() { - with_test_native_font(|font| { - let adv = font.glyph_h_advance(-1 as GlyphIndex); - assert adv == None; - }) +pub fn create(native_lib: &NativeFontCache, buf: @~[u8], pt_size: float) -> Result { + ft_native_font::create(native_lib, buf, pt_size) } diff --git a/src/servo/text/native_font/ft_native_font.rs b/src/servo/text/native_font/ft_native_font.rs index 9cc75f171af..b8e3e25b3b4 100644 --- a/src/servo/text/native_font/ft_native_font.rs +++ b/src/servo/text/native_font/ft_native_font.rs @@ -130,14 +130,18 @@ pub impl FreeTypeNativeFont { } } -pub fn create(lib: &FT_Library, buf: @~[u8]) -> Result { +pub fn create(lib: &FT_Library, buf: @~[u8], pt_size: float) -> Result { assert lib.is_not_null(); let face: FT_Face = null(); return vec_as_buf(*buf, |cbuf, _len| { if FT_New_Memory_Face(*lib, cbuf, (*buf).len() as FT_Long, 0 as FT_Long, addr_of(&face)).succeeded() { // FIXME: These values are placeholders - let res = FT_Set_Char_Size(face, 0, 20*64, 0, 72); + let res = FT_Set_Char_Size(face, // the face + float_to_fixed_ft(pt_size), // char width + float_to_fixed_ft(pt_size), // char height + 72, // horiz. DPI + 72); // vert. DPI if !res.succeeded() { fail ~"unable to set font char size" } Ok(FreeTypeNativeFont(face, buf)) } else { @@ -153,29 +157,3 @@ trait FTErrorMethods { impl FT_Error : FTErrorMethods { fn succeeded() -> bool { self == 0 as FT_Error } } - -pub fn with_test_native_font(f: fn@(nf: &NativeFont)) { - use font::test_font_bin; - use unwrap_result = result::unwrap; - - with_lib(|lib| { - let buf = @test_font_bin(); - let font = unwrap_result(create(lib, move buf)); - f(&font); - }) -} - -fn with_lib(f: fn@((&FT_Library))) { - let lib: FT_Library = null(); - assert FT_Init_FreeType(addr_of(&lib)).succeeded(); - f(&lib); - FT_Done_FreeType(lib); -} - -#[test] -fn create_should_return_err_if_buf_is_bogus() { - with_lib(|lib| { - let buf = @~[]; - assert create(lib, buf).is_err(); - }) -} diff --git a/src/servo/text/native_font/quartz_native_font.rs b/src/servo/text/native_font/quartz_native_font.rs index 90d0a890457..bffd52b2291 100644 --- a/src/servo/text/native_font/quartz_native_font.rs +++ b/src/servo/text/native_font/quartz_native_font.rs @@ -68,11 +68,11 @@ pub struct QuartzNativeFont { } } -fn QuartzNativeFont(fontprov: CGDataProviderRef, cgfont: CGFontRef) -> QuartzNativeFont { +fn QuartzNativeFont(fontprov: CGDataProviderRef, cgfont: CGFontRef, pt_size: float) -> QuartzNativeFont { assert fontprov.is_not_null(); assert cgfont.is_not_null(); - let ctfont = ctfont_from_cgfont(cgfont); + let ctfont = ctfont_from_cgfont(cgfont, pt_size); assert ctfont.is_not_null(); QuartzNativeFont { @@ -143,14 +143,13 @@ impl QuartzNativeFont { } } -fn ctfont_from_cgfont(cgfont: CGFontRef) -> CTFontRef { +fn ctfont_from_cgfont(cgfont: CGFontRef, pt_size: float) -> CTFontRef { assert cgfont.is_not_null(); - // TODO: use actual font size here! - CTFontCreateWithGraphicsFont(cgfont, 21f as CGFloat, null(), null()) + CTFontCreateWithGraphicsFont(cgfont, pt_size as CGFloat, null(), null()) } -pub fn create(buf: @~[u8]) -> Result { +pub fn create(_lib: &NativeFontCache, buf: @~[u8], pt_size: float) -> Result { let fontprov = vec::as_imm_buf(*buf, |cbuf, len| { CGDataProviderCreateWithData( null(), @@ -163,18 +162,8 @@ pub fn create(buf: @~[u8]) -> Result { let cgfont = CGFontCreateWithDataProvider(fontprov); match cgfont.is_not_null() { - true => Ok(QuartzNativeFont(fontprov, cgfont)), + true => Ok(QuartzNativeFont(fontprov, cgfont, pt_size)), false => Err(()) } } - -pub fn with_test_native_font(f: fn@(nf: &NativeFont)) { - use font::test_font_bin; - use unwrap_result = result::unwrap; - - let buf = @test_font_bin(); - let res = create(buf); - let font = unwrap_result(move res); - f(&font); -}