servo: Create FontContext from matcher, remove platform-specific matchers. Move default font into FontCache. Fixes #166.

Source-Repo: https://github.com/servo/servo
Source-Revision: b7d4ec12174384fe7d373c45c5f7e712ea16d45b
This commit is contained in:
Brian J. Burg 2012-10-30 12:01:18 -07:00
parent a97fdf3c1e
commit 1751026a67
14 changed files with 118 additions and 112 deletions

View File

@ -15,7 +15,7 @@ use render_context::RenderContext;
use render_layers::render_layers; use render_layers::render_layers;
use std::cell::Cell; use std::cell::Cell;
use text::font_cache::FontCache; use text::font_cache::FontCache;
use text::font_matcher::FontMatcher; use text::font_context::FontContext;
pub enum Msg { pub enum Msg {
RenderMsg(RenderLayer), RenderMsg(RenderLayer),
@ -36,7 +36,7 @@ pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
port: po, port: po,
compositor: move compositor, compositor: move compositor,
mut layer_buffer_set_port: Cell(move layer_buffer_set_port), mut layer_buffer_set_port: Cell(move layer_buffer_set_port),
font_cache: @FontCache::new(@FontMatcher::new()), font_cache: @FontCache::new(@FontContext::new()),
}.start(); }.start();
} }
} }

View File

@ -25,6 +25,7 @@ use opt = core::option;
use render_task::RenderTask; use render_task::RenderTask;
use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg}; use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use resource::local_image_cache::LocalImageCache; use resource::local_image_cache::LocalImageCache;
use servo_text::font_context::FontContext;
use servo_text::font_cache::FontCache; use servo_text::font_cache::FontCache;
use servo_text::font_matcher::FontMatcher; use servo_text::font_matcher::FontMatcher;
use std::arc::ARC; use std::arc::ARC;
@ -77,6 +78,7 @@ struct Layout {
from_content: comm::Port<Msg>, from_content: comm::Port<Msg>,
font_cache: @FontCache, font_cache: @FontCache,
font_matcher: @FontMatcher,
// This is used to root auxilliary RCU reader data // This is used to root auxilliary RCU reader data
layout_refs: DVec<@LayoutData> layout_refs: DVec<@LayoutData>
} }
@ -85,12 +87,15 @@ fn Layout(render_task: RenderTask,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
from_content: comm::Port<Msg>) -> Layout { from_content: comm::Port<Msg>) -> Layout {
let fctx = @FontContext::new();
Layout { Layout {
render_task: render_task, render_task: render_task,
image_cache_task: image_cache_task.clone(), image_cache_task: image_cache_task.clone(),
local_image_cache: @LocalImageCache(move image_cache_task), local_image_cache: @LocalImageCache(move image_cache_task),
from_content: from_content, from_content: from_content,
font_cache: @FontCache::new(@FontMatcher::new()), font_matcher: @FontMatcher::new(fctx),
font_cache: @FontCache::new(fctx),
layout_refs: DVec() layout_refs: DVec()
} }
} }

View File

@ -109,8 +109,8 @@ pub mod text {
pub mod util; pub mod util;
// platform and library-specific implementations. // platform and library-specific implementations.
pub mod font_context;
pub mod native_font; pub mod native_font;
pub mod native_font_matcher;
pub mod shaper; pub mod shaper;
pub mod harfbuzz { pub mod harfbuzz {
@ -119,14 +119,14 @@ pub mod text {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub mod quartz { pub mod quartz {
pub mod font_context;
pub mod native_font; pub mod native_font;
pub mod native_font_matcher;
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub mod freetype { pub mod freetype {
pub mod font_context;
pub mod native_font; pub mod native_font;
pub mod native_font_matcher;
} }
} }

View File

@ -340,16 +340,18 @@ fn should_destruct_on_fail_without_leaking() {
#[test]; #[test];
#[should_fail]; #[should_fail];
let lib = FontCache(); let fctx = @FontContext();
let _font = lib.get_test_font(); let matcher = @FontMatcher(fctx);
let _font = matcher.get_test_font();
fail; fail;
} }
fn should_get_glyph_indexes() { fn should_get_glyph_indexes() {
#[test]; #[test];
let lib = FontCache(); let fctx = @FontContext();
let font = lib.get_test_font(); let matcher = @FontMatcher(fctx);
let font = matcher.get_test_font();
let glyph_idx = font.glyph_index('w'); let glyph_idx = font.glyph_index('w');
assert glyph_idx == Some(40u as GlyphIndex); assert glyph_idx == Some(40u as GlyphIndex);
} }
@ -358,8 +360,9 @@ fn should_get_glyph_advance() {
#[test]; #[test];
#[ignore]; #[ignore];
let lib = FontCache(); let fctx = @FontContext();
let font = lib.get_test_font(); let matcher = @FontMatcher(fctx);
let font = matcher.get_test_font();
let x = font.glyph_h_advance(40u as GlyphIndex); let x = font.glyph_h_advance(40u as GlyphIndex);
assert x == 15f || x == 16f; assert x == 15f || x == 16f;
} }
@ -375,8 +378,9 @@ fn should_get_glyph_advance_stress() {
let (chan, port) = pipes::stream(); let (chan, port) = pipes::stream();
ports += [@move port]; ports += [@move port];
do task::spawn |move chan| { do task::spawn |move chan| {
let lib = FontCache(); let fctx = @FontContext();
let font = lib.get_test_font(); let matcher = @FontMatcher(fctx);
let _font = matcher.get_test_font();
let x = font.glyph_h_advance(40u as GlyphIndex); let x = font.glyph_h_advance(40u as GlyphIndex);
assert x == 15f || x == 16f; assert x == 15f || x == 16f;
chan.send(()); chan.send(());
@ -393,8 +397,9 @@ fn should_be_able_to_create_instances_in_multiple_threads() {
for iter::repeat(10u) { for iter::repeat(10u) {
do task::spawn { do task::spawn {
let lib = FontCache(); let fctx = @FontContext();
let _font = lib.get_test_font(); let matcher = @FontMatcher(fctx);
let _font = matcher.get_test_font();
} }
} }
} }

View File

@ -1,16 +1,25 @@
use font::{Font, FontStyle, FontWeight300}; use font::{Font, FontStyle, FontWeight300};
use font_matcher::FontMatcher; use native_font::NativeFont;
use font_context::FontContext;
// TODO(Issue #164): delete, and get default font from NativeFontMatcher
const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf");
fn test_font_bin() -> ~[u8] {
return vec::from_fn(33004, |i| TEST_FONT[i]);
}
// Dummy font cache. // Dummy font cache.
struct FontCache { struct FontCache {
matcher: @FontMatcher, fctx: @FontContext,
mut cached_font: Option<@Font> mut cached_font: Option<@Font>
} }
impl FontCache { impl FontCache {
static pub fn new(matcher: @FontMatcher) -> FontCache { static pub fn new(fctx: @FontContext) -> FontCache {
FontCache { FontCache {
matcher: matcher, fctx: fctx,
cached_font: None cached_font: None
} }
} }
@ -25,10 +34,27 @@ impl FontCache {
return match self.cached_font { return match self.cached_font {
Some(font) => font, Some(font) => font,
None => match self.matcher.get_font(&dummy_style) { None => match self.get_font(&dummy_style) {
Ok(font) => { self.cached_font = Some(font); font } Ok(font) => { self.cached_font = Some(font); font }
Err(*) => /* FIXME */ fail Err(*) => /* FIXME */ fail
} }
} }
} }
// TODO: maybe FontStyle should be canonicalized when used in FontCache?
priv fn create_font(style: &FontStyle) -> Result<@Font, ()> {
let font_bin = @test_font_bin();
let native_font = NativeFont::new(self.fctx, font_bin, style.pt_size);
let native_font = if native_font.is_ok() {
result::unwrap(move native_font)
} else {
return Err(native_font.get_err());
};
return Ok(@Font::new(font_bin, move native_font, copy *style));
}
pub fn get_font(@self, style: &FontStyle) -> Result<@Font, ()> {
self.create_font(style)
}
} }

View File

@ -0,0 +1,25 @@
// TODO(Issue #163): this is a workaround for static methods and
// typedefs not working well together. It should be removed.
// TODO(Rust #1723): #cfg doesn't work for impl methods, so we have
// to conditionally define the entire impl.
#[cfg(target_os = "macos")]
type FontContext/& = quartz::font_context::QuartzFontContext;
#[cfg(target_os = "linux")]
type FontContext/& = freetype::font_context::FreeTypeFontContext;
#[cfg(target_os = "macos")]
pub impl FontContext {
static pub fn new() -> FontContext {
quartz::font_context::QuartzFontContext::new()
}
}
#[cfg(target_os = "linux")]
pub impl FontContext {
static pub fn new() -> FontContext {
freetype::font_context::FreeTypeFontContext::new()
}
}

View File

@ -1,43 +1,14 @@
use font::{Font, FontStyle}; use font::{Font, FontStyle};
use native_font::NativeFont; use font_context::FontContext;
use native_font_matcher::NativeFontMatcher;
// TODO(Issue #164): delete, and get default font from NativeFontMatcher
const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf");
fn test_font_bin() -> ~[u8] {
return vec::from_fn(33004, |i| TEST_FONT[i]);
}
struct FontMatcher { struct FontMatcher {
native_matcher: NativeFontMatcher, fctx: @FontContext,
// TODO(Issue #165): move into FontCache
mut cached_font: Option<@Font>,
} }
impl FontMatcher { impl FontMatcher {
static pub fn new() -> FontMatcher { static pub fn new(fctx: @FontContext) -> FontMatcher {
FontMatcher { FontMatcher {
native_matcher: NativeFontMatcher::new(), fctx: fctx,
cached_font: None
} }
} }
// TODO: maybe FontStyle should be canonicalized when used in FontCache?
// TODO(Issue #166): move this to FontCache or something? At the least, use it there.
priv fn create_font(style: &FontStyle) -> Result<@Font, ()> {
let font_bin = @test_font_bin();
let native_font = NativeFont::new(&self.native_matcher, font_bin, style.pt_size);
let native_font = if native_font.is_ok() {
result::unwrap(move native_font)
} else {
return Err(native_font.get_err());
};
return Ok(@Font::new(font_bin, move native_font, copy *style));
}
pub fn get_font(@self, style: &FontStyle) -> Result<@Font, ()> {
self.create_font(style)
}
} }

View File

@ -10,24 +10,24 @@ use freetype::bindgen::{
}; };
pub struct FreeTypeNativeFontMatcher { pub struct FreeTypeFontContext {
ft_lib: FT_Library, ctx: FT_Library,
drop { drop {
assert self.ft_lib.is_not_null(); assert self.ctx.is_not_null();
FT_Done_FreeType(self.ft_lib); FT_Done_FreeType(self.ctx);
} }
} }
pub impl FreeTypeNativeFontMatcher { pub impl FreeTypeFontContext {
static pub fn new() -> FreeTypeNativeFontMatcher { static pub fn new() -> FreeTypeFontContext {
let lib: FT_Library = ptr::null(); let lib: FT_Library = ptr::null();
let res = FT_Init_FreeType(ptr::addr_of(&lib)); let res = FT_Init_FreeType(ptr::addr_of(&lib));
// FIXME: error handling // FIXME: error handling
assert res == 0 as FT_Error; assert res == 0 as FT_Error;
FreeTypeNativeFontMatcher { FreeTypeFontContext {
ft_lib: lib, ctx: lib,
} }
} }
} }

View File

@ -1,7 +1,7 @@
extern mod freetype; extern mod freetype;
use font::{FontMetrics, FractionalPixel}; use font::{FontMetrics, FractionalPixel};
use native_font_matcher::FreeTypeNativeFontMatcher; use font_context::FreeTypeFontContext;
use gfx::geometry; use gfx::geometry;
use gfx::geometry::Au; use gfx::geometry::Au;
@ -45,13 +45,13 @@ pub struct FreeTypeNativeFont {
} }
pub impl FreeTypeNativeFont { pub impl FreeTypeNativeFont {
static pub fn new(matcher: &FreeTypeNativeFontMatcher, static pub fn new(fctx: &FreeTypeFontContext,
buf: @~[u8], pt_size: float) -> Result<FreeTypeNativeFont, ()> { buf: @~[u8], pt_size: float) -> Result<FreeTypeNativeFont, ()> {
let lib = matcher.ft_lib; let ft_ctx = fctx.ctx;
assert lib.is_not_null(); assert ft_ctx.is_not_null();
let face: FT_Face = null(); let face: FT_Face = null();
return vec_as_buf(*buf, |cbuf, _len| { return vec_as_buf(*buf, |cbuf, _len| {
if FT_New_Memory_Face(lib, cbuf, (*buf).len() as FT_Long, if FT_New_Memory_Face(ft_ctx, cbuf, (*buf).len() as FT_Long,
0 as FT_Long, addr_of(&face)).succeeded() { 0 as FT_Long, addr_of(&face)).succeeded() {
let res = FT_Set_Char_Size(face, // the face let res = FT_Set_Char_Size(face, // the face
float_to_fixed_ft(pt_size) as FT_F26Dot6, // char width float_to_fixed_ft(pt_size) as FT_F26Dot6, // char width

View File

@ -5,7 +5,7 @@ needed by the text shaper as well as access to the underlying
font resources needed by the graphics layer to draw glyphs. font resources needed by the graphics layer to draw glyphs.
*/ */
use native_font_matcher::NativeFontMatcher; use font_context::FontContext;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub type NativeFont/& = quartz::native_font::QuartzNativeFont; pub type NativeFont/& = quartz::native_font::QuartzNativeFont;
@ -22,14 +22,14 @@ pub type NativeFont/& = freetype::native_font::FreeTypeNativeFont;
// to conditionally define the entire impl. // to conditionally define the entire impl.
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
impl NativeFont { impl NativeFont {
static pub fn new(native_lib: &NativeFontMatcher, buf: @~[u8], pt_size: float) -> Result<NativeFont, ()> { static pub fn new(fctx: &FontContext, buf: @~[u8], pt_size: float) -> Result<NativeFont, ()> {
quartz::native_font::QuartzNativeFont::new(native_lib, buf, pt_size) quartz::native_font::QuartzNativeFont::new(fctx, buf, pt_size)
} }
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
impl NativeFont { impl NativeFont {
static pub fn new(native_lib: &NativeFontMatcher, buf: @~[u8], pt_size: float) -> Result<NativeFont, ()> { static pub fn new(fctx: &FontContext, buf: @~[u8], pt_size: float) -> Result<NativeFont, ()> {
freetype::native_font::FreeTypeNativeFont::new(native_lib, buf, pt_size) freetype::native_font::FreeTypeNativeFont::new(fctx, buf, pt_size)
} }
} }

View File

@ -1,25 +0,0 @@
// TODO(Issue #163): this is a workaround for static methods and
// typedefs not working well together. It should be removed.
// TODO(Rust #1723): #cfg doesn't work for impl methods, so we have
// to conditionally define the entire impl.
#[cfg(target_os = "macos")]
type NativeFontMatcher/& = quartz::native_font_matcher::QuartzNativeFontMatcher;
#[cfg(target_os = "linux")]
type NativeFontMatcher/& = freetype::native_font_matcher::FreeTypeNativeFontMatcher;
#[cfg(target_os = "macos")]
pub impl NativeFontMatcher {
static pub fn new() -> NativeFontMatcher {
quartz::native_font_matcher::QuartzNativeFontMatcher::new()
}
}
#[cfg(target_os = "linux")]
pub impl NativeFontMatcher {
static pub fn new() -> NativeFontMatcher {
freetype::native_font_matcher::FreeTypeNativeFontMatcher::new()
}
}

View File

@ -0,0 +1,12 @@
pub struct QuartzFontContext {
ctx: u8,
drop { }
}
pub impl QuartzFontContext {
// this is a placeholder until NSFontManager or whatever is bound in here.
static pub fn new() -> QuartzFontContext {
QuartzFontContext { ctx: 42 }
}
}

View File

@ -3,7 +3,7 @@ extern mod core_graphics;
extern mod core_text; extern mod core_text;
use font::{FontMetrics, FractionalPixel}; use font::{FontMetrics, FractionalPixel};
use native_font_matcher::QuartzNativeFontMatcher; use font_context::QuartzFontContext;
use au = gfx::geometry; use au = gfx::geometry;
use cast::transmute; use cast::transmute;
@ -68,7 +68,7 @@ pub struct QuartzNativeFont {
} }
pub impl QuartzNativeFont { pub impl QuartzNativeFont {
static pub fn new(_lib: &QuartzNativeFontMatcher, buf: @~[u8], pt_size: float) -> Result<QuartzNativeFont, ()> { static pub fn new(_fctx: &QuartzFontContext, buf: @~[u8], pt_size: float) -> Result<QuartzNativeFont, ()> {
let fontprov = vec::as_imm_buf(*buf, |cbuf, len| { let fontprov = vec::as_imm_buf(*buf, |cbuf, len| {
CGDataProviderCreateWithData( CGDataProviderCreateWithData(
null(), null(),

View File

@ -1,13 +0,0 @@
pub struct QuartzNativeFontMatcher {
dummy: int,
drop { }
}
pub impl QuartzNativeFontMatcher {
// this is a placeholder until NSFontManager or whatever is bound in here.
static pub fn new() -> QuartzNativeFontMatcher {
QuartzNativeFontMatcher { dummy: 42 }
}
}