Clean up font-related constructor paths to not require a byte buffer;

add FontGroup construction and interaction with TextRun.

Closes #178.
This commit is contained in:
Brian J. Burg 2012-11-12 11:07:02 -08:00
parent 84216f838f
commit a34f67d64b
6 changed files with 101 additions and 37 deletions

@ -1 +1 @@
Subproject commit 9c398db2b0627b150eba88edc0eb861dfb4a28ac
Subproject commit 7a42dc503a6b4578f3957c69574e07175b2ca3c5

View file

@ -26,6 +26,7 @@ pub trait FontHandleMethods {
pure fn is_italic() -> bool;
pure fn boldness() -> CSSFontWeight;
fn clone_with_style(fctx: &native::FontContextHandle, style: &UsedFontStyle) -> Result<FontHandle, ()>;
fn glyph_index(codepoint: char) -> Option<GlyphIndex>;
fn glyph_h_advance(GlyphIndex) -> Option<FractionalPixel>;
fn get_metrics() -> FontMetrics;
@ -38,13 +39,13 @@ pub trait FontHandleMethods {
impl FontHandle {
#[cfg(target_os = "macos")]
static pub fn new(fctx: &native::FontContextHandle, buf: @~[u8], pt_size: float) -> Result<FontHandle, ()> {
quartz::font::QuartzFontHandle::new_from_buffer(fctx, buf, pt_size)
static pub fn new(fctx: &native::FontContextHandle, buf: @~[u8], style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
quartz::font::QuartzFontHandle::new_from_buffer(fctx, buf, style)
}
#[cfg(target_os = "linux")]
static pub fn new(fctx: &native::FontContextHandle, buf: @~[u8], pt_size: float) -> Result<FontHandle, ()> {
freetype::font::FreeTypeFontHandle::new(fctx, buf, pt_size)
static pub fn new(fctx: &native::FontContextHandle, buf: @~[u8], style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
freetype::font::FreeTypeFontHandle::new(fctx, buf, style)
}
}
@ -194,6 +195,13 @@ pub impl FontGroup {
fonts: move fonts,
}
}
fn create_textrun(text: ~str) -> TextRun {
assert self.fonts.len() > 0;
// TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
return TextRun::new(self.fonts[0], move text);
}
}
struct RunMetrics {
@ -211,7 +219,7 @@ A font instance. Layout can use this to calculate glyph metrics
and the renderer can use it to render text.
*/
pub struct Font {
priv fontbuf: @~[u8],
priv mut fontbuf: Option<@~[u8]>,
priv handle: FontHandle,
priv mut azure_font: Option<AzScaledFontRef>,
priv mut shaper: Option<@Shaper>,
@ -226,22 +234,48 @@ pub struct Font {
}
impl Font {
// TODO: who should own fontbuf?
static fn new(fontbuf: @~[u8],
handle: FontHandle,
style: UsedFontStyle,
backend: BackendType) -> Font {
let metrics = handle.get_metrics();
static fn new_from_buffer(ctx: &FontContext, buffer: @~[u8],
style: &SpecifiedFontStyle, backend: BackendType) -> Result<@Font, ()> {
Font {
fontbuf : fontbuf,
let handle = FontHandle::new(&ctx.handle, buffer, style);
let handle = if handle.is_ok() {
result::unwrap(move handle)
} else {
return Err(handle.get_err());
};
let metrics = handle.get_metrics();
// TODO(Issue #179): convert between specified and used font style here?
return Ok(@Font {
fontbuf : Some(buffer),
handle : move handle,
azure_font: None,
shaper: None,
style: move style,
style: copy *style,
metrics: move metrics,
backend: backend
}
backend: backend,
});
}
static fn new_from_handle(fctx: &FontContext, handle: &FontHandle,
style: &SpecifiedFontStyle, backend: BackendType) -> Result<@Font,()> {
// TODO(Issue #179): convert between specified and used font style here?
let styled_handle = match handle.clone_with_style(&fctx.handle, style) {
Ok(move result) => move result,
Err(()) => return Err(())
};
return Ok(@Font {
fontbuf : None,
handle : move styled_handle,
azure_font: None,
shaper: None,
style: copy *style,
metrics: handle.get_metrics(),
backend: backend,
});
}
priv fn get_shaper(@self) -> @Shaper {
@ -413,7 +447,7 @@ pub impl Font : FontMethods {
}
fn buf(&self) -> @~[u8] {
self.fontbuf
option::expect(self.fontbuf, ~"This font has no buffer")
}
fn glyph_index(codepoint: char) -> Option<GlyphIndex> {

View file

@ -67,6 +67,10 @@ pub impl FontContext {
}
}
priv pure fn get_font_list(&self) -> &self/FontList {
option::get_ref(&self.font_list)
}
fn get_resolved_font_for_style(style: &SpecifiedFontStyle) -> @FontGroup {
// TODO(Issue #178, E): implement a cache of FontGroup instances.
self.create_font_group(style)
@ -88,15 +92,29 @@ pub impl FontContext {
}
priv fn create_font_group(style: &SpecifiedFontStyle) -> @FontGroup {
// TODO(Issue #178, D): implement private font matching
// TODO(Issue #174): implement by-platform-name FontSelectors
let desc = FontDescriptor::new(&font_context::dummy_style(), &SelectorStubDummy);
let fonts = DVec();
match self.get_font_by_descriptor(&desc) {
Ok(instance) => fonts.push(instance),
Err(()) => {}
}
// TODO(Issue #193): make iteration over 'font-family' more robust.
for str::split_char_each(style.families, ',') |family| {
let family_name = str::trim(family);
let list = self.get_font_list();
let result = list.find_font_in_family(family_name, style);
do result.iter |font_entry| {
let instance = Font::new_from_handle(&self, &font_entry.handle, style, self.backend);
do result::iter(&instance) |font: &@Font| { fonts.push(*font); }
};
}
// TODO(Issue #194): attach a fallback font to the font list,
// so that this assertion will never fail.
assert fonts.len() > 0;
// TODO(Issue #179): Split FontStyle into specified and used styles
let used_style = copy *style;
@ -105,20 +123,12 @@ pub impl FontContext {
}
priv fn create_font_instance(desc: &FontDescriptor) -> Result<@Font, ()> {
match desc.selector {
return match desc.selector {
SelectorStubDummy => {
let font_bin = @test_font_bin();
let handle = FontHandle::new(&self.handle, font_bin, desc.style.pt_size);
let handle = if handle.is_ok() {
result::unwrap(move handle)
} else {
return Err(handle.get_err());
};
return Ok(@Font::new(font_bin, move handle, copy desc.style, self.backend));
Font::new_from_buffer(&self, @test_font_bin(), &desc.style, self.backend)
},
// TODO(Issue #174): implement by-platform-name font selectors.
SelectorPlatformName(_) => { fail ~"FontContext::create_font_instance() can't yet handle SelectorPlatformName." }
}
};
}
}

View file

@ -53,6 +53,8 @@ pub impl FontList {
let family = self.find_family(family_name);
let mut result : Option<@FontEntry> = None;
// TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
// if such family exists, try to match style to a font
do family.iter |fam| {
result = fam.find_font_for_style(style);

View file

@ -3,10 +3,23 @@ extern mod core_graphics;
extern mod core_text;
use font_context::QuartzFontContextHandle;
use geometry::Au;
use servo_gfx_font::{CSSFontWeight, FontHandleMethods, FontMetrics, FontWeight100, FontWeight200};
use servo_gfx_font::{FontWeight300, FontWeight400, FontWeight500, FontWeight600, FontWeight700};
use servo_gfx_font::{FontWeight800, FontWeight900, FractionalPixel};
use gfx::au;
use gfx::font::{
CSSFontWeight,
FontHandleMethods,
FontMetrics,
FontWeight100,
FontWeight200,
FontWeight300,
FontWeight400,
FontWeight500,
FontWeight600,
FontWeight700,
FontWeight800,
FontWeight900,
FractionalPixel,
SpecifiedFontStyle,
};
use text::glyph::GlyphIndex;
use cf = core_foundation;
@ -37,7 +50,8 @@ pub struct QuartzFontHandle {
}
pub impl QuartzFontHandle {
static fn new_from_buffer(_fctx: &QuartzFontContextHandle, buf: @~[u8], pt_size: float) -> Result<QuartzFontHandle, ()> {
static fn new_from_buffer(_fctx: &QuartzFontContextHandle, buf: @~[u8],
style: &SpecifiedFontStyle) -> Result<QuartzFontHandle, ()> {
let fontprov = vec::as_imm_buf(*buf, |cbuf, len| {
CGDataProvider::new_from_buffer(cbuf, len)
});
@ -45,7 +59,7 @@ pub impl QuartzFontHandle {
let cgfont = CGFontCreateWithDataProvider(fontprov.get_ref());
if cgfont.is_null() { return Err(()); }
let ctfont = CTFont::new_from_CGFont(cgfont, pt_size);
let ctfont = CTFont::new_from_CGFont(cgfont, style.pt_size);
let result = Ok(QuartzFontHandle {
cgfont : Some(cgfont),
@ -105,6 +119,10 @@ pub impl QuartzFontHandle : FontHandleMethods {
else { return FontWeight900; }
}
fn clone_with_style(fctx: &QuartzFontContextHandle, style: &SpecifiedFontStyle) -> Result<QuartzFontHandle,()> {
let new_font = self.ctfont.clone_with_font_size(style.pt_size);
return QuartzFontHandle::new_from_CTFont(fctx, move new_font);
}
fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
let characters: ~[UniChar] = ~[codepoint as UniChar];

View file

@ -239,7 +239,7 @@ impl TextRunScanner {
// this is probably achieved by creating fontgroup above, and then letting FontGroup decide
// which Font to stick into the TextRun.
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&gfx::font_context::dummy_style());
let run = @TextRun::new(fontgroup.fonts[0], move transformed_text);
let run = @fontgroup.create_textrun(move transformed_text);
debug!("TextRunScanner: pushing single text box in range: %?", self.clump);
let new_box = layout::text::adapt_textbox_with_range(in_boxes[self.clump.begin()].d(), run,
Range(0, run.text.len()));