From 0d135a4fa56e35673aaef9d903f683dd2f7837e7 Mon Sep 17 00:00:00 2001 From: "Brian J. Burg" Date: Mon, 12 Nov 2012 19:24:35 -0800 Subject: [PATCH] Finish implementing first cut at font matching. Closes #174. --- src/rust-core-foundation | 2 +- src/rust-core-text | 2 +- src/servo-gfx/font.rs | 39 +++++++++++++++---------- src/servo-gfx/font_context.rs | 43 ++++++++++++++++++---------- src/servo-gfx/font_list.rs | 9 +++++- src/servo-gfx/quartz/font.rs | 4 +++ src/servo-gfx/quartz/font_context.rs | 20 +++++++++++++ src/servo-gfx/servo_gfx.rc | 4 ++- 8 files changed, 89 insertions(+), 34 deletions(-) diff --git a/src/rust-core-foundation b/src/rust-core-foundation index 3e5e34f4f46..7fcbf5112ec 160000 --- a/src/rust-core-foundation +++ b/src/rust-core-foundation @@ -1 +1 @@ -Subproject commit 3e5e34f4f46598a85465f4fb754ccaff04a98e4c +Subproject commit 7fcbf5112ec163bdc14f096ddd9a45ef744ca6a6 diff --git a/src/rust-core-text b/src/rust-core-text index dab51768967..4c38ba65d49 160000 --- a/src/rust-core-text +++ b/src/rust-core-text @@ -1 +1 @@ -Subproject commit dab5176896750f512410e24e33852ccaf13dbf08 +Subproject commit 4c38ba65d4929ba418317c9fd9d16a0aa83945c9 diff --git a/src/servo-gfx/font.rs b/src/servo-gfx/font.rs index 234efd237bb..9a5d77667fb 100644 --- a/src/servo-gfx/font.rs +++ b/src/servo-gfx/font.rs @@ -23,6 +23,8 @@ pub type FontHandle/& = quartz::font::QuartzFontHandle; pub type FontHandle/& = freetype::font::FreeTypeFontHandle; pub trait FontHandleMethods { + // an identifier usable by FontContextHandle to recreate this FontHandle. + pure fn face_identifier() -> ~str; pure fn family_name() -> ~str; pure fn face_name() -> ~str; pure fn is_italic() -> bool; @@ -165,17 +167,17 @@ pub impl FontDescriptor : cmp::Eq { } pub impl FontDescriptor { - static pure fn new(style: &UsedFontStyle, selector: &FontSelector) -> FontDescriptor { + static pure fn new(style: UsedFontStyle, selector: FontSelector) -> FontDescriptor { FontDescriptor { - style: copy *style, - selector: copy *selector, + style: move style, + selector: move selector, } } } // A FontSelector is a platform-specific strategy for serializing face names. pub enum FontSelector { - SelectorPlatformName(~str), + SelectorPlatformIdentifier(~str), SelectorStubDummy, // aka, use Josephin Sans } @@ -183,8 +185,8 @@ pub enum FontSelector { pub impl FontSelector : cmp::Eq { pure fn eq(other: &FontSelector) -> bool { match (&self, other) { + (&SelectorPlatformIdentifier(a), &SelectorPlatformIdentifier(b)) => a == b, (&SelectorStubDummy, &SelectorStubDummy) => true, - (&SelectorPlatformName(a), &SelectorPlatformName(b)) => a == b, _ => false } } @@ -275,7 +277,21 @@ impl Font { }); } - static fn new_from_handle(fctx: &FontContext, handle: &FontHandle, + static fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle, + style: &SpecifiedFontStyle, backend: BackendType) -> @Font { + let metrics = handle.get_metrics(); + + @Font { + handle : move handle, + azure_font: None, + shaper: None, + style: copy *style, + metrics: move metrics, + backend: backend, + } + } + + static fn new_from_existing_handle(fctx: &FontContext, handle: &FontHandle, style: &SpecifiedFontStyle, backend: BackendType) -> Result<@Font,()> { // TODO(Issue #179): convert between specified and used font style here? @@ -284,14 +300,7 @@ impl Font { Err(()) => return Err(()) }; - return Ok(@Font { - handle : move styled_handle, - azure_font: None, - shaper: None, - style: copy *style, - metrics: handle.get_metrics(), - backend: backend, - }); + return Ok(Font::new_from_adopted_handle(fctx, move styled_handle, style, backend)); } priv fn get_shaper(@self) -> @Shaper { @@ -454,7 +463,7 @@ pub impl Font : FontMethods { fn get_descriptor() -> FontDescriptor { // TODO(Issue #174): implement by-platform-name FontSelectors, // probably by adding such an API to FontHandle. - FontDescriptor::new(&font_context::dummy_style(), &SelectorStubDummy) + FontDescriptor::new(copy self.style, SelectorPlatformIdentifier(self.handle.face_identifier())) } fn glyph_index(codepoint: char) -> Option { diff --git a/src/servo-gfx/font_context.rs b/src/servo-gfx/font_context.rs index c46dfa52e35..71c5de6adb8 100644 --- a/src/servo-gfx/font_context.rs +++ b/src/servo-gfx/font_context.rs @@ -1,5 +1,5 @@ -use font::{Font, FontDescriptor, FontGroup, FontStyle, SelectorPlatformName, SelectorStubDummy}; -use font::{SpecifiedFontStyle}; +use font::{Font, FontDescriptor, FontGroup, FontStyle, SelectorPlatformIdentifier, SelectorStubDummy}; +use font::{SpecifiedFontStyle, UsedFontStyle}; use font_list::FontList; use native::FontHandle; use util::cache; @@ -27,14 +27,18 @@ pub fn dummy_style() -> FontStyle { } } -// TODO(Issue #163): this is a workaround for static methods and -// typedefs not working well together. It should be removed. #[cfg(target_os = "macos")] type FontContextHandle/& = quartz::font_context::QuartzFontContextHandle; #[cfg(target_os = "linux")] type FontContextHandle/& = freetype::font_context::FreeTypeFontContextHandle; +trait FontContextHandleMethods { + fn create_font_from_identifier(~str, UsedFontStyle) -> Result; +} + +// TODO(Issue #163): this is a workaround for static methods, traits, +// and typedefs not working well together. It should be removed. pub impl FontContextHandle { #[cfg(target_os = "macos")] static pub fn new() -> FontContextHandle { @@ -91,16 +95,10 @@ pub impl FontContext { } } + // TODO:(Issue #196): cache font groups on the font context. priv fn create_font_group(style: &SpecifiedFontStyle) -> @FontGroup { - // 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); @@ -108,13 +106,23 @@ pub impl FontContext { 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); + // TODO(Issue #203): route this instantion through FontContext's Font instance cache. + let instance = Font::new_from_existing_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. + // TODO(Issue #194): *always* attach a fallback font to the + // font list, so that this assertion will never fail. + + // assert fonts.len() > 0; + if fonts.len() == 0 { + let desc = FontDescriptor::new(font_context::dummy_style(), SelectorStubDummy); + match self.get_font_by_descriptor(&desc) { + Ok(instance) => fonts.push(instance), + Err(()) => {} + } + } assert fonts.len() > 0; // TODO(Issue #179): Split FontStyle into specified and used styles let used_style = copy *style; @@ -128,7 +136,12 @@ pub impl FontContext { 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." } + SelectorPlatformIdentifier(identifier) => { + let result_handle = self.handle.create_font_from_identifier(identifier, copy desc.style); + result::chain(move result_handle, |handle| { + Ok(Font::new_from_adopted_handle(&self, move handle, &desc.style, self.backend)) + }) + } }; } } diff --git a/src/servo-gfx/font_list.rs b/src/servo-gfx/font_list.rs index 0732e0ecb08..2aa19998e9a 100644 --- a/src/servo-gfx/font_list.rs +++ b/src/servo-gfx/font_list.rs @@ -1,4 +1,4 @@ -use font::{CSSFontWeight, SpecifiedFontStyle}; +use font::{CSSFontWeight, SpecifiedFontStyle, UsedFontStyle}; use native::FontHandle; use dvec::DVec; @@ -59,6 +59,10 @@ pub impl FontList { do family.iter |fam| { result = fam.find_font_for_style(style); } + + let decision = if result.is_some() { "Found" } else { "Couldn't find" }; + debug!("FontList: %s font face in family[%?] matching style: %?", decision, style, family_name); + return result; } @@ -66,6 +70,9 @@ pub impl FontList { // look up canonical name let family = self.family_map.find(&str::from_slice(family_name)); + let decision = if family.is_some() { "Found" } else { "Couldn't find" }; + debug!("FontList: %s font family with name=%s", decision, family_name); + // TODO(Issue #188): look up localized font family names if canonical name not found return family; } diff --git a/src/servo-gfx/quartz/font.rs b/src/servo-gfx/quartz/font.rs index e566e8fcc62..eddf5ec03fe 100644 --- a/src/servo-gfx/quartz/font.rs +++ b/src/servo-gfx/quartz/font.rs @@ -188,5 +188,9 @@ pub impl QuartzFontHandle : FontHandleMethods { Some(data.copy_to_buf()) }); } + + pure fn face_identifier() -> ~str { + self.ctfont.postscript_name() + } } diff --git a/src/servo-gfx/quartz/font_context.rs b/src/servo-gfx/quartz/font_context.rs index 2e227923a7b..d02fade7781 100644 --- a/src/servo-gfx/quartz/font_context.rs +++ b/src/servo-gfx/quartz/font_context.rs @@ -1,3 +1,14 @@ +extern mod core_foundation; +extern mod core_graphics; +extern mod core_text; + +use ct = core_text; +use ct::font::CTFont; + +use gfx_font::{FontHandle, UsedFontStyle}; +use font::QuartzFontHandle; +use gfx_font_context::FontContextHandleMethods; + pub struct QuartzFontContextHandle { ctx: (), @@ -9,4 +20,13 @@ pub impl QuartzFontContextHandle { static pub fn new() -> QuartzFontContextHandle { QuartzFontContextHandle { ctx: () } } +} + +pub impl QuartzFontContextHandle : FontContextHandleMethods { + fn create_font_from_identifier(name: ~str, style: UsedFontStyle) -> Result { + let ctfont_result = CTFont::new_from_name(move name, style.pt_size); + do result::chain(move ctfont_result) |ctfont| { + QuartzFontHandle::new_from_CTFont(&self, move ctfont) + } + } } \ No newline at end of file diff --git a/src/servo-gfx/servo_gfx.rc b/src/servo-gfx/servo_gfx.rc index 6eaa8cb4a89..b5697b97474 100644 --- a/src/servo-gfx/servo_gfx.rc +++ b/src/servo-gfx/servo_gfx.rc @@ -91,4 +91,6 @@ pub mod util { pub mod vec; } -use gfx_font = font; \ No newline at end of file +use gfx_font = font; +use gfx_font_context = font_context; +use gfx_font_list = font_list; \ No newline at end of file