Implement lazy font table loading from FontHandles for CoreText. Tracked by #195.

This commit is contained in:
Brian J. Burg 2012-11-12 14:09:16 -08:00
parent a34f67d64b
commit 7a3a79dc36
4 changed files with 94 additions and 19 deletions

@ -1 +1 @@
Subproject commit 7a42dc503a6b4578f3957c69574e07175b2ca3c5 Subproject commit dab5176896750f512410e24e33852ccaf13dbf08

View file

@ -22,6 +22,7 @@ pub type FontHandle/& = quartz::font::QuartzFontHandle;
pub type FontHandle/& = freetype::font::FreeTypeFontHandle; pub type FontHandle/& = freetype::font::FreeTypeFontHandle;
pub trait FontHandleMethods { pub trait FontHandleMethods {
pure fn family_name() -> ~str;
pure fn face_name() -> ~str; pure fn face_name() -> ~str;
pure fn is_italic() -> bool; pure fn is_italic() -> bool;
pure fn boldness() -> CSSFontWeight; pure fn boldness() -> CSSFontWeight;
@ -30,6 +31,7 @@ pub trait FontHandleMethods {
fn glyph_index(codepoint: char) -> Option<GlyphIndex>; fn glyph_index(codepoint: char) -> Option<GlyphIndex>;
fn glyph_h_advance(GlyphIndex) -> Option<FractionalPixel>; fn glyph_h_advance(GlyphIndex) -> Option<FractionalPixel>;
fn get_metrics() -> FontMetrics; fn get_metrics() -> FontMetrics;
fn get_table_for_tag(FontTableTag) -> Option<~[u8]>;
} }
// TODO: `new` should be part of trait FontHandleMethods // TODO: `new` should be part of trait FontHandleMethods
@ -52,6 +54,22 @@ impl FontHandle {
// Used to abstract over the shaper's choice of fixed int representation. // Used to abstract over the shaper's choice of fixed int representation.
type FractionalPixel = float; type FractionalPixel = float;
pub type FontTableTag = u32;
trait FontTableTagConversions {
pub pure fn tag_to_str() -> ~str;
}
impl FontTableTag : FontTableTagConversions {
pub pure fn tag_to_str() -> ~str unsafe {
let reversed = str::raw::from_buf_len(cast::transmute(&self), 4);
return str::from_chars([reversed.char_at(3),
reversed.char_at(2),
reversed.char_at(1),
reversed.char_at(0)]);
}
}
struct FontMetrics { struct FontMetrics {
underline_size: Au, underline_size: Au,
underline_offset: Au, underline_offset: Au,
@ -290,6 +308,17 @@ impl Font {
shaper shaper
} }
fn get_table_for_tag(tag: FontTableTag) -> Option<~[u8]> {
let result = self.handle.get_table_for_tag(tag);
let status = if result.is_some() { "Found" } else { "Didn't find" };
debug!("%s font table[%s] with family=%s, face=%s",
status, tag.tag_to_str(),
self.handle.family_name(), self.handle.face_name());
return move result;
}
priv fn get_azure_font() -> AzScaledFontRef { priv fn get_azure_font() -> AzScaledFontRef {
// fast path: we've already created the azure font resource // fast path: we've already created the azure font resource
match self.azure_font { match self.azure_font {

View file

@ -8,6 +8,7 @@ use gfx::font::{
CSSFontWeight, CSSFontWeight,
FontHandleMethods, FontHandleMethods,
FontMetrics, FontMetrics,
FontTableTag,
FontWeight100, FontWeight100,
FontWeight200, FontWeight200,
FontWeight300, FontWeight300,
@ -23,7 +24,12 @@ use gfx::font::{
use text::glyph::GlyphIndex; use text::glyph::GlyphIndex;
use cf = core_foundation; use cf = core_foundation;
use cf::base::{CFIndex, CFRelease, CFTypeRef}; use cf::base::{
CFIndex,
CFRelease,
CFTypeRef
};
use cf::data::CFData;
use cf::string::UniChar; use cf::string::UniChar;
use cg = core_graphics; use cg = core_graphics;
use cg::base::{CGFloat, CGAffineTransform}; use cg::base::{CGFloat, CGAffineTransform};
@ -175,5 +181,12 @@ pub impl QuartzFontHandle : FontHandleMethods {
debug!("Font metrics (@%f pt): %?", self.ctfont.pt_size() as float, metrics); debug!("Font metrics (@%f pt): %?", self.ctfont.pt_size() as float, metrics);
return metrics; return metrics;
} }
fn get_table_for_tag(tag: FontTableTag) -> Option<~[u8]> {
let result = self.ctfont.get_font_table(tag);
return option::chain(move result, |data| {
Some(data.copy_to_buf())
});
}
} }

View file

@ -1,6 +1,14 @@
extern mod harfbuzz; extern mod harfbuzz;
use geometry::Au; use geom::Point2D;
use gfx::au;
use gfx::{
Au,
Font,
};
use gfx::font::FontTableTag;
use glyph::{GlyphStore, GlyphIndex, GlyphData}; use glyph::{GlyphStore, GlyphIndex, GlyphData};
use servo_gfx_font::Font; use servo_gfx_font::Font;
@ -20,17 +28,33 @@ use harfbuzz::bindgen::{hb_font_set_funcs, hb_font_funcs_set_glyph_h_advance_fun
use harfbuzz::bindgen::{hb_font_funcs_set_glyph_func, hb_font_funcs_set_glyph_h_kerning_func}; use harfbuzz::bindgen::{hb_font_funcs_set_glyph_func, hb_font_funcs_set_glyph_h_kerning_func};
use std::arc; use std::arc;
use harfbuzz::{HB_MEMORY_MODE_READONLY,
HB_DIRECTION_LTR};
use harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_font_funcs_t, hb_buffer_t,
hb_codepoint_t, hb_bool_t, hb_glyph_position_t,
hb_glyph_info_t, hb_var_int_t, hb_position_t, hb_tag_t};
use harfbuzz::bindgen::{hb_blob_create, hb_blob_destroy,
hb_face_create_for_tables, hb_face_destroy,
hb_font_create, hb_font_destroy,
hb_buffer_create, hb_buffer_destroy,
hb_buffer_add_utf8, hb_shape,
hb_buffer_get_glyph_infos,
hb_buffer_get_glyph_positions,
hb_font_set_ppem, hb_font_set_scale,
hb_buffer_set_direction,
hb_font_funcs_create, hb_font_funcs_destroy,
hb_font_set_funcs,
hb_font_funcs_set_glyph_h_advance_func,
hb_font_funcs_set_glyph_func,
hb_font_funcs_set_glyph_h_kerning_func};
pub struct HarfbuzzShaper { pub struct HarfbuzzShaper {
priv font: @Font, font: @Font,
priv hb_blob: *hb_blob_t,
priv hb_face: *hb_face_t, priv hb_face: *hb_face_t,
priv hb_font: *hb_font_t, priv hb_font: *hb_font_t,
priv hb_funcs: *hb_font_funcs_t, priv hb_funcs: *hb_font_funcs_t,
drop { drop {
assert self.hb_blob.is_not_null();
hb_blob_destroy(self.hb_blob);
assert self.hb_face.is_not_null(); assert self.hb_face.is_not_null();
hb_face_destroy(self.hb_face); hb_face_destroy(self.hb_face);
@ -44,16 +68,7 @@ pub struct HarfbuzzShaper {
pub impl HarfbuzzShaper { pub impl HarfbuzzShaper {
static pub fn new(font: @Font) -> HarfbuzzShaper { static pub fn new(font: @Font) -> HarfbuzzShaper {
// TODO(Issue #92): font tables should be stored in Font object and cached per-task let hb_face: *hb_face_t = hb_face_create_for_tables(get_font_table_func, ptr::to_unsafe_ptr(font) as *c_void, ptr::null());
let hb_blob: *hb_blob_t = vec::as_imm_buf(*(font).buf(), |buf: *u8, len: uint| {
hb_blob_create(buf as *c_char,
len as c_uint,
HB_MEMORY_MODE_READONLY,
null(),
null())
});
let hb_face: *hb_face_t = hb_face_create(hb_blob, 0 as c_uint);
let hb_font: *hb_font_t = hb_font_create(hb_face); let hb_font: *hb_font_t = hb_font_create(hb_face);
// Set points-per-em. if zero, performs no hinting in that direction. // Set points-per-em. if zero, performs no hinting in that direction.
let pt_size = font.style.pt_size; let pt_size = font.style.pt_size;
@ -75,7 +90,6 @@ pub impl HarfbuzzShaper {
HarfbuzzShaper { HarfbuzzShaper {
font: font, font: font,
hb_blob: hb_blob,
hb_face: hb_face, hb_face: hb_face,
hb_font: hb_font, hb_font: hb_font,
hb_funcs: hb_funcs, hb_funcs: hb_funcs,
@ -175,3 +189,22 @@ extern fn glyph_h_advance_func(_font: *hb_font_t,
let advance = (*font).glyph_h_advance(glyph as GlyphIndex); let advance = (*font).glyph_h_advance(glyph as GlyphIndex);
HarfbuzzShaper::float_to_fixed(advance) HarfbuzzShaper::float_to_fixed(advance)
} }
// Callback to get a font table out of a font.
extern fn get_font_table_func(_face: *hb_face_t, tag: hb_tag_t, user_data: *c_void) -> *hb_blob_t unsafe {
let font: *Font = user_data as *Font;
assert font.is_not_null();
// TODO(Issue #197): reuse font table data, which will change return type here.
// it will also require us to provide deletion callbacks to hb_blob_create, so
// that refcounts of shared blobs can be managed.
match (*font).get_table_for_tag(tag as FontTableTag) {
None => return ptr::null(),
Some(table_buffer) => {
let blob: *hb_blob_t = vec::as_imm_buf(table_buffer, |buf: *u8, len: uint| {
hb_blob_create(buf as *c_char, len as c_uint, HB_MEMORY_MODE_READONLY, null(), null())
});
return blob;
}
}
}