diff --git a/src/rust-core-text b/src/rust-core-text index 9c398db2b06..7a42dc503a6 160000 --- a/src/rust-core-text +++ b/src/rust-core-text @@ -1 +1 @@ -Subproject commit 9c398db2b0627b150eba88edc0eb861dfb4a28ac +Subproject commit 7a42dc503a6b4578f3957c69574e07175b2ca3c5 diff --git a/src/servo-gfx/font.rs b/src/servo-gfx/font.rs index 4769f96ab1d..e126a1fb4c3 100644 --- a/src/servo-gfx/font.rs +++ b/src/servo-gfx/font.rs @@ -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; fn glyph_index(codepoint: char) -> Option; fn glyph_h_advance(GlyphIndex) -> Option; 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 { - quartz::font::QuartzFontHandle::new_from_buffer(fctx, buf, pt_size) + static pub fn new(fctx: &native::FontContextHandle, buf: @~[u8], style: &SpecifiedFontStyle) -> Result { + 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 { - freetype::font::FreeTypeFontHandle::new(fctx, buf, pt_size) + static pub fn new(fctx: &native::FontContextHandle, buf: @~[u8], style: &SpecifiedFontStyle) -> Result { + 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, 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 { diff --git a/src/servo-gfx/font_context.rs b/src/servo-gfx/font_context.rs index c6093d03871..240da0b3c7a 100644 --- a/src/servo-gfx/font_context.rs +++ b/src/servo-gfx/font_context.rs @@ -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." } - } + }; } } diff --git a/src/servo-gfx/font_list.rs b/src/servo-gfx/font_list.rs index 1a8bc6147b3..0732e0ecb08 100644 --- a/src/servo-gfx/font_list.rs +++ b/src/servo-gfx/font_list.rs @@ -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); diff --git a/src/servo-gfx/quartz/font.rs b/src/servo-gfx/quartz/font.rs index 83aa41e8b98..6ab3986978a 100644 --- a/src/servo-gfx/quartz/font.rs +++ b/src/servo-gfx/quartz/font.rs @@ -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 { + static fn new_from_buffer(_fctx: &QuartzFontContextHandle, buf: @~[u8], + style: &SpecifiedFontStyle) -> Result { 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 { + 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 { let characters: ~[UniChar] = ~[codepoint as UniChar]; diff --git a/src/servo/layout/inline.rs b/src/servo/layout/inline.rs index df2650a91e6..43c2502ff15 100644 --- a/src/servo/layout/inline.rs +++ b/src/servo/layout/inline.rs @@ -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()));