Skip to content

Commit

Permalink
Finish implementing first cut at font matching. Closes #174.
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian J. Burg committed Nov 13, 2012
1 parent ebb9392 commit 0d135a4
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 34 deletions.
2 changes: 1 addition & 1 deletion src/rust-core-foundation
Submodule rust-core-foundation updated from 3e5e34 to 7fcbf5
2 changes: 1 addition & 1 deletion src/rust-core-text
Submodule rust-core-text updated from dab517 to 4c38ba
39 changes: 24 additions & 15 deletions src/servo-gfx/font.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -165,26 +167,26 @@ 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
}

// TODO(Issue #181): use deriving for trivial cmp::Eq implementations
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
}
}
Expand Down Expand Up @@ -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?
Expand All @@ -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 {
Expand Down Expand Up @@ -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> {
Expand Down
43 changes: 28 additions & 15 deletions 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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -91,30 +95,34 @@ 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);
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);
// 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;
Expand All @@ -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))
})
}
};
}
}
9 changes: 8 additions & 1 deletion 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;
Expand Down Expand Up @@ -59,13 +59,20 @@ 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;
}

priv fn find_family(family_name: &str) -> Option<@FontFamily> {
// 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;
}
Expand Down
4 changes: 4 additions & 0 deletions src/servo-gfx/quartz/font.rs
Expand Up @@ -188,5 +188,9 @@ pub impl QuartzFontHandle : FontHandleMethods {
Some(data.copy_to_buf())
});
}

pure fn face_identifier() -> ~str {
self.ctfont.postscript_name()
}
}

20 changes: 20 additions & 0 deletions 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: (),

Expand All @@ -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)
}
}
}
4 changes: 3 additions & 1 deletion src/servo-gfx/servo_gfx.rc
Expand Up @@ -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;

0 comments on commit 0d135a4

Please sign in to comment.