Fix CoreText font metrics bindings.

This commit is contained in:
Brian J. Burg 2012-10-15 15:09:24 -07:00
parent ec9cbeb150
commit a81bf8692e
2 changed files with 43 additions and 42 deletions

View file

@ -52,29 +52,27 @@ pub trait FontMethods {
pub impl Font : FontMethods { pub impl Font : FontMethods {
fn measure_text(run: &TextRun, offset: uint, length: uint) -> RunMetrics { fn measure_text(run: &TextRun, offset: uint, length: uint) -> RunMetrics {
let em_size = self.metrics.em_size;
let em_ascent = self.metrics.em_ascent;
let em_descent = self.metrics.em_descent;
// TODO: alter advance direction for RTL // TODO: alter advance direction for RTL
// TODO: using inter-char and inter-word spacing settings when measuring text // TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
let mut advance = au(0); let mut advance = au(0);
let mut bounds = Rect(Point2D(au(0), em_size.scale_by(-em_ascent)), let mut bounds = Rect(Point2D(au(0), -self.metrics.ascent),
Size2D(au(0), em_size.scale_by(em_ascent + em_descent))); Size2D(au(0), self.metrics.ascent + self.metrics.descent));
do run.glyphs.iter_glyphs_for_range(offset, length) |_i, glyph| { do run.glyphs.iter_glyphs_for_range(offset, length) |_i, glyph| {
advance += glyph.advance(); advance += glyph.advance();
bounds = bounds.translate(&Point2D(glyph.advance(), au(0))); bounds = bounds.translate(&Point2D(glyph.advance(), au(0)));
} }
// TODO: support loose and tight bounding boxes; using the // TODO(Issue #125): support loose and tight bounding boxes; using the
// ascent+descent and advance is sometimes too generous and // ascent+descent and advance is sometimes too generous and
// looking at actual glyph extents can yield a tighter box. // looking at actual glyph extents can yield a tighter box.
let metrics = RunMetrics { advance_width: advance, let metrics = RunMetrics { advance_width: advance,
bounding_box: bounds, bounding_box: bounds,
ascent: em_size.scale_by(em_ascent), ascent: self.metrics.ascent,
descent: em_size.scale_by(em_descent), descent: self.metrics.descent,
}; };
debug!("Measured text range '%s' with metrics:", run.text.substr(offset, length));
debug!("%?", metrics);
return metrics; return metrics;
} }
@ -95,7 +93,6 @@ pub impl Font : FontMethods {
} }
} }
// TODO: font should compute its own metrics using native_font.
// TODO: who should own fontbuf? // TODO: who should own fontbuf?
fn Font(lib: @FontCache, fontbuf: @~[u8], native_font: NativeFont) -> Font { fn Font(lib: @FontCache, fontbuf: @~[u8], native_font: NativeFont) -> Font {
let metrics = native_font.get_metrics(); let metrics = native_font.get_metrics();
@ -103,24 +100,21 @@ fn Font(lib: @FontCache, fontbuf: @~[u8], native_font: NativeFont) -> Font {
Font { Font {
lib: lib, lib: lib,
fontbuf : fontbuf, fontbuf : fontbuf,
metrics: move metrics,
native_font : move native_font, native_font : move native_font,
metrics: move metrics
} }
} }
// Most of these metrics are in terms of em. Use em_size to convert to au. // Most of these metrics are in terms of em. Use em_size to convert to au.
struct FontMetrics { struct FontMetrics {
underline_size: float, underline_size: au,
underline_offset: float, underline_offset: au,
leading: float, leading: au,
x_height: float, x_height: au,
// how many appunits an em is equivalent to (based on point-to-au)
em_size: au, em_size: au,
em_height: float, ascent: au,
em_ascent: float, descent: au,
em_descent: float, max_advance: au
max_advance: float
} }
const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf"); const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf");

View file

@ -34,6 +34,7 @@ mod coretext {
pub const kCTFontHorizontalOrientation: CTFontOrientation = 1; pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
pub const kCTFontVerticalOrientation: CTFontOrientation = 2; pub const kCTFontVerticalOrientation: CTFontOrientation = 2;
// TODO: this is actually a libc::c_float on 32bit
pub type CGFloat = libc::c_double; pub type CGFloat = libc::c_double;
pub struct CGSize { pub struct CGSize {
@ -61,14 +62,16 @@ mod coretext {
pub fn CTFontGetGlyphsForCharacters(font: CTFontRef, characters: *UniChar, glyphs: *CGGlyph, count: CFIndex) -> bool; pub fn CTFontGetGlyphsForCharacters(font: CTFontRef, characters: *UniChar, glyphs: *CGGlyph, count: CFIndex) -> bool;
pub fn CTFontGetAdvancesForGlyphs(font: CTFontRef, orientation: CTFontOrientation, glyphs: *CGGlyph, advances: *CGSize, count: CFIndex) -> libc::c_double; pub fn CTFontGetAdvancesForGlyphs(font: CTFontRef, orientation: CTFontOrientation, glyphs: *CGGlyph, advances: *CGSize, count: CFIndex) -> libc::c_double;
pub fn CTFontGetSize(font: CTFontRef) -> CGFloat;
/* metrics API */ /* metrics API */
pub fn CTFontGetAscent(font: CTFontRef) -> libc::c_float; pub fn CTFontGetAscent(font: CTFontRef) -> CGFloat;
pub fn CTFontGetDescent(font: CTFontRef) -> libc::c_float; pub fn CTFontGetDescent(font: CTFontRef) -> CGFloat;
pub fn CTFontGetLeading(font: CTFontRef) -> libc::c_float; pub fn CTFontGetLeading(font: CTFontRef) -> CGFloat;
pub fn CTFontGetUnitsPerEm(font: CTFontRef) -> libc::c_uint; pub fn CTFontGetUnitsPerEm(font: CTFontRef) -> libc::c_uint;
pub fn CTFontGetUnderlinePosition(font: CTFontRef) -> libc::c_float; pub fn CTFontGetUnderlinePosition(font: CTFontRef) -> CGFloat;
pub fn CTFontGetUnderlineThickness(font: CTFontRef) -> libc::c_float; pub fn CTFontGetUnderlineThickness(font: CTFontRef) -> CGFloat;
pub fn CTFontGetXHeight(font: CTFontRef) -> libc::c_float; pub fn CTFontGetXHeight(font: CTFontRef) -> CGFloat;
pub fn CTFontGetBoundingBox(font: CTFontRef) -> CGRect; pub fn CTFontGetBoundingBox(font: CTFontRef) -> CGRect;
pub fn CFRelease(font: CTFontRef); pub fn CFRelease(font: CTFontRef);
@ -151,22 +154,26 @@ impl QuartzNativeFont {
let ctfont = self.ctfont; let ctfont = self.ctfont;
assert ctfont.is_not_null(); assert ctfont.is_not_null();
let convFactor : float = 1.0 / (CTFontGetUnitsPerEm(ctfont) as float);
let bounding_rect: CGRect = CTFontGetBoundingBox(ctfont); let bounding_rect: CGRect = CTFontGetBoundingBox(ctfont);
let em_ascent = CTFontGetAscent(ctfont) as float * convFactor; let ascent = au::from_pt(CTFontGetAscent(ctfont) as float);
let em_descent = CTFontGetDescent(ctfont) as float * convFactor; let descent = au::from_pt(CTFontGetDescent(ctfont) as float);
return FontMetrics { let metrics = FontMetrics {
underline_size: CTFontGetUnderlineThickness(ctfont) as float * convFactor, underline_size: au::from_pt(CTFontGetUnderlineThickness(ctfont) as float),
underline_offset: CTFontGetUnderlinePosition(ctfont) as float * convFactor, // TODO: underline metrics are not reliable. Have to pull out of font table directly.
leading: CTFontGetLeading(ctfont) as float * convFactor, // see also: https://bugs.webkit.org/show_bug.cgi?id=16768
x_height: CTFontGetXHeight(ctfont) as float * convFactor, // see also: https://bugreports.qt-project.org/browse/QTBUG-13364
em_ascent: CTFontGetAscent(ctfont) as float * convFactor, underline_offset: au::from_pt(CTFontGetUnderlinePosition(ctfont) as float),
em_descent: CTFontGetDescent(ctfont) as float * convFactor, leading: au::from_pt(CTFontGetLeading(ctfont) as float),
em_height: em_ascent + em_descent, x_height: au::from_pt(CTFontGetXHeight(ctfont) as float),
em_size: au::from_pt(21f), em_size: ascent + descent,
max_advance: bounding_rect.size.width as float * convFactor, ascent: ascent,
} descent: descent,
max_advance: au::from_pt(bounding_rect.size.width as float)
};
debug!("Font metrics (@%f pt): %?", CTFontGetSize(ctfont) as float, metrics);
return metrics;
} }
} }