Finish implementing first cut at font matching. Closes #174.

This commit is contained in:
Brian J. Burg 2012-11-12 19:24:35 -08:00
parent ebb9392587
commit 0d135a4fa5
8 changed files with 89 additions and 34 deletions

@ -1 +1 @@
Subproject commit 3e5e34f4f46598a85465f4fb754ccaff04a98e4c
Subproject commit 7fcbf5112ec163bdc14f096ddd9a45ef744ca6a6

@ -1 +1 @@
Subproject commit dab5176896750f512410e24e33852ccaf13dbf08
Subproject commit 4c38ba65d4929ba418317c9fd9d16a0aa83945c9

View file

@ -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<GlyphIndex> {

View file

@ -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<FontHandle, ()>;
}
// 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))
})
}
};
}
}

View file

@ -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;
}

View file

@ -188,5 +188,9 @@ pub impl QuartzFontHandle : FontHandleMethods {
Some(data.copy_to_buf())
});
}
pure fn face_identifier() -> ~str {
self.ctfont.postscript_name()
}
}

View file

@ -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<FontHandle, ()> {
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)
}
}
}

View file

@ -91,4 +91,6 @@ pub mod util {
pub mod vec;
}
use gfx_font = font;
use gfx_font = font;
use gfx_font_context = font_context;
use gfx_font_list = font_list;