mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
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:
parent
2e5afb7050
commit
9f94b54c89
5 changed files with 99 additions and 126 deletions
|
@ -19,25 +19,6 @@ use text::text_run::TextRun;
|
||||||
// Used to abstract over the shaper's choice of fixed int representation.
|
// Used to abstract over the shaper's choice of fixed int representation.
|
||||||
type FractionalPixel = float;
|
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 {
|
struct FontMetrics {
|
||||||
underline_size: Au,
|
underline_size: Au,
|
||||||
underline_offset: Au,
|
underline_offset: Au,
|
||||||
|
@ -49,29 +30,80 @@ struct FontMetrics {
|
||||||
max_advance: Au
|
max_advance: Au
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RunMetrics {
|
// TODO: use enum from CSS bindings
|
||||||
// may be negative due to negative width
|
enum CSSFontWeight {
|
||||||
advance_width: Au,
|
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
|
ascent: Au, // nonzero
|
||||||
descent: Au, // nonzero
|
descent: Au, // nonzero
|
||||||
|
|
||||||
// this bounding box is relative to the left origin baseline.
|
// this bounding box is relative to the left origin baseline.
|
||||||
// so, bounding_box.position.y = -ascent
|
// so, bounding_box.position.y = -ascent
|
||||||
bounding_box: Rect<Au>
|
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 {
|
impl Font {
|
||||||
// TODO: who should own fontbuf?
|
// 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();
|
let metrics = native_font.get_metrics();
|
||||||
|
|
||||||
Font {
|
Font {
|
||||||
lib: lib,
|
lib: lib,
|
||||||
fontbuf : fontbuf,
|
fontbuf : fontbuf,
|
||||||
metrics: move metrics,
|
|
||||||
native_font : move native_font,
|
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
|
// stones and manual memory management, and put them inside of
|
||||||
// azure_hl.rs and elsewhere instead.
|
// azure_hl.rs and elsewhere instead.
|
||||||
let cfont = get_cairo_font(&self);
|
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);
|
let azfont = AzCreateScaledFontWithCairo(ptr::to_unsafe_ptr(&nfont), 1f as AzFloat, cfont);
|
||||||
assert azfont.is_not_null();
|
assert azfont.is_not_null();
|
||||||
cairo_scaled_font_destroy(cfont);
|
cairo_scaled_font_destroy(cfont);
|
||||||
|
@ -107,6 +140,9 @@ impl Font {
|
||||||
self.azure_font = Some(azfont);
|
self.azure_font = Some(azfont);
|
||||||
return 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")]
|
#[cfg(target_os = "linux")]
|
||||||
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {
|
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {
|
||||||
use cairo::cairo_ft::bindgen::{cairo_ft_font_face_create_for_ft_face};
|
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));
|
cairo_matrix_init_identity(ptr::to_unsafe_ptr(&idmatrix));
|
||||||
|
|
||||||
let fontmatrix = 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 options = cairo_font_options_create();
|
||||||
let cfont = cairo_scaled_font_create(face, ptr::to_unsafe_ptr(&fontmatrix),
|
let cfont = cairo_scaled_font_create(face,
|
||||||
ptr::to_unsafe_ptr(&idmatrix), options);
|
ptr::to_unsafe_ptr(&fontmatrix),
|
||||||
|
ptr::to_unsafe_ptr(&idmatrix),
|
||||||
|
options);
|
||||||
cairo_font_options_destroy(options);
|
cairo_font_options_destroy(options);
|
||||||
cairo_font_face_destroy(face);
|
cairo_font_face_destroy(face);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use font::{Font, test_font_bin};
|
use font::{Font,
|
||||||
|
FontStyle,
|
||||||
|
FontWeight300,
|
||||||
|
test_font_bin};
|
||||||
|
|
||||||
struct FontCache {
|
struct FontCache {
|
||||||
native_lib: native::NativeFontCache,
|
native_lib: native::NativeFontCache,
|
||||||
|
@ -37,13 +40,20 @@ fn FontCache() -> @FontCache {
|
||||||
|
|
||||||
fn create_font(lib: @FontCache, native_lib: &native::NativeFontCache) -> Result<@Font, ()> {
|
fn create_font(lib: @FontCache, native_lib: &native::NativeFontCache) -> Result<@Font, ()> {
|
||||||
let font_bin = @test_font_bin();
|
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() {
|
let native_font = if native_font.is_ok() {
|
||||||
result::unwrap(move native_font)
|
result::unwrap(move native_font)
|
||||||
} else {
|
} else {
|
||||||
return Err(native_font.get_err());
|
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")]
|
#[cfg(target_os = "linux")]
|
||||||
|
|
|
@ -14,57 +14,13 @@ pub type NativeFont/& = quartz_native_font::QuartzNativeFont;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub type NativeFont/& = ft_native_font::FreeTypeNativeFont;
|
pub type NativeFont/& = ft_native_font::FreeTypeNativeFont;
|
||||||
|
|
||||||
|
// TODO: this should be part of trait NativeFont
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn create(_native_lib: &NativeFontCache, buf: @~[u8]) -> Result<NativeFont, ()> {
|
pub fn create(native_lib: &NativeFontCache, buf: @~[u8], pt_size: float) -> Result<NativeFont, ()> {
|
||||||
quartz_native_font::create(buf)
|
quartz_native_font::create(native_lib, buf, pt_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn create(native_lib: &NativeFontCache, buf: @~[u8]) -> Result<NativeFont, ()> {
|
pub fn create(native_lib: &NativeFontCache, buf: @~[u8], pt_size: float) -> Result<NativeFont, ()> {
|
||||||
ft_native_font::create(native_lib, buf)
|
ft_native_font::create(native_lib, buf, pt_size)
|
||||||
}
|
|
||||||
|
|
||||||
#[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;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
assert lib.is_not_null();
|
||||||
let face: FT_Face = null();
|
let face: FT_Face = null();
|
||||||
return vec_as_buf(*buf, |cbuf, _len| {
|
return vec_as_buf(*buf, |cbuf, _len| {
|
||||||
if FT_New_Memory_Face(*lib, cbuf, (*buf).len() as FT_Long,
|
if FT_New_Memory_Face(*lib, cbuf, (*buf).len() as FT_Long,
|
||||||
0 as FT_Long, addr_of(&face)).succeeded() {
|
0 as FT_Long, addr_of(&face)).succeeded() {
|
||||||
// FIXME: These values are placeholders
|
// 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" }
|
if !res.succeeded() { fail ~"unable to set font char size" }
|
||||||
Ok(FreeTypeNativeFont(face, buf))
|
Ok(FreeTypeNativeFont(face, buf))
|
||||||
} else {
|
} else {
|
||||||
|
@ -153,29 +157,3 @@ trait FTErrorMethods {
|
||||||
impl FT_Error : FTErrorMethods {
|
impl FT_Error : FTErrorMethods {
|
||||||
fn succeeded() -> bool { self == 0 as FT_Error }
|
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();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 fontprov.is_not_null();
|
||||||
assert cgfont.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();
|
assert ctfont.is_not_null();
|
||||||
|
|
||||||
QuartzNativeFont {
|
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();
|
assert cgfont.is_not_null();
|
||||||
|
|
||||||
// TODO: use actual font size here!
|
CTFontCreateWithGraphicsFont(cgfont, pt_size as CGFloat, null(), null())
|
||||||
CTFontCreateWithGraphicsFont(cgfont, 21f 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| {
|
let fontprov = vec::as_imm_buf(*buf, |cbuf, len| {
|
||||||
CGDataProviderCreateWithData(
|
CGDataProviderCreateWithData(
|
||||||
null(),
|
null(),
|
||||||
|
@ -163,18 +162,8 @@ pub fn create(buf: @~[u8]) -> Result<QuartzNativeFont, ()> {
|
||||||
let cgfont = CGFontCreateWithDataProvider(fontprov);
|
let cgfont = CGFontCreateWithDataProvider(fontprov);
|
||||||
|
|
||||||
match cgfont.is_not_null() {
|
match cgfont.is_not_null() {
|
||||||
true => Ok(QuartzNativeFont(fontprov, cgfont)),
|
true => Ok(QuartzNativeFont(fontprov, cgfont, pt_size)),
|
||||||
false => Err(())
|
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);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue