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.

This commit is contained in:
Brian J. Burg 2012-10-26 19:53:13 -07:00
parent 2e5afb7050
commit 9f94b54c89
5 changed files with 99 additions and 126 deletions

View file

@ -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<AzScaledFontRef>,
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<Au>
}
/**
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<AzScaledFontRef>,
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);

View file

@ -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")]

View file

@ -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<NativeFont, ()> {
quartz_native_font::create(buf)
pub fn create(native_lib: &NativeFontCache, buf: @~[u8], pt_size: float) -> Result<NativeFont, ()> {
quartz_native_font::create(native_lib, buf, pt_size)
}
#[cfg(target_os = "linux")]
pub fn create(native_lib: &NativeFontCache, buf: @~[u8]) -> Result<NativeFont, ()> {
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<NativeFont, ()> {
ft_native_font::create(native_lib, buf, pt_size)
}

View file

@ -130,14 +130,18 @@ pub impl FreeTypeNativeFont {
}
}
pub fn create(lib: &FT_Library, buf: @~[u8]) -> Result<FreeTypeNativeFont, ()> {
pub fn create(lib: &FT_Library, buf: @~[u8], pt_size: float) -> Result<FreeTypeNativeFont, ()> {
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();
})
}

View file

@ -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<QuartzNativeFont, ()> {
pub fn create(_lib: &NativeFontCache, buf: @~[u8], pt_size: float) -> Result<QuartzNativeFont, ()> {
let fontprov = vec::as_imm_buf(*buf, |cbuf, len| {
CGDataProviderCreateWithData(
null(),
@ -163,18 +162,8 @@ pub fn create(buf: @~[u8]) -> Result<QuartzNativeFont, ()> {
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);
}