Add some RAII and black magic to let harfbuzz determine font table blob lifetimes.

This commit is contained in:
Brian J. Burg 2012-11-14 17:10:57 -08:00
parent b14505e44d
commit c74abcaa5c
3 changed files with 79 additions and 29 deletions

View file

@ -35,7 +35,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]>; fn get_table_for_tag(FontTableTag) -> Option<FontTable>;
} }
// TODO(Issue #163): this is a workaround for static methods and // TODO(Issue #163): this is a workaround for static methods and
@ -74,6 +74,16 @@ impl FontTableTag : FontTableTagConversions {
} }
} }
#[cfg(target_os = "macos")]
pub type FontTable/& = quartz::font::QuartzFontTable;
#[cfg(target_os = "linux")]
pub type FontTable/& = freetype::font::FreeTypeFontTable;
trait FontTableMethods {
fn with_buffer(fn&(*u8, uint));
}
struct FontMetrics { struct FontMetrics {
underline_size: Au, underline_size: Au,
underline_offset: Au, underline_offset: Au,
@ -311,7 +321,7 @@ impl Font {
shaper shaper
} }
fn get_table_for_tag(tag: FontTableTag) -> Option<~[u8]> { fn get_table_for_tag(tag: FontTableTag) -> Option<FontTable> {
let result = self.handle.get_table_for_tag(tag); let result = self.handle.get_table_for_tag(tag);
let status = if result.is_some() { "Found" } else { "Didn't find" }; let status = if result.is_some() { "Found" } else { "Didn't find" };

View file

@ -2,12 +2,35 @@ extern mod core_foundation;
extern mod core_graphics; extern mod core_graphics;
extern mod core_text; extern mod core_text;
use cf = core_foundation;
use cf::base::{
CFIndex,
CFRelease,
CFTypeOps,
CFTypeRef,
};
use cf::data::{CFData, CFDataRef};
use cf::string::UniChar;
use cg = core_graphics;
use cg::base::{CGFloat, CGAffineTransform};
use cg::data_provider::{CGDataProviderRef, CGDataProvider};
use cg::font::{CGFontCreateWithDataProvider, CGFontRef, CGFontRelease, CGGlyph};
use cg::geometry::CGRect;
use ct = core_text;
use ct::font::CTFont;
use ct::font_descriptor::{kCTFontDefaultOrientation, CTFontSymbolicTraits};
use ct::font_descriptor::{SymbolicTraitAccessors};
use font_context::QuartzFontContextHandle; use font_context::QuartzFontContextHandle;
use geometry::Au; use geometry::Au;
use gfx_font::{ use gfx_font::{
CSSFontWeight, CSSFontWeight,
FontHandleMethods, FontHandleMethods,
FontMetrics, FontMetrics,
FontTable,
FontTableMethods,
FontTableTag, FontTableTag,
FontWeight100, FontWeight100,
FontWeight200, FontWeight200,
@ -23,24 +46,25 @@ use gfx_font::{
}; };
use text::glyph::GlyphIndex; use text::glyph::GlyphIndex;
use cf = core_foundation;
use cf::base::{
CFIndex,
CFRelease,
CFTypeRef
};
use cf::data::CFData;
use cf::string::UniChar;
use cg = core_graphics;
use cg::base::{CGFloat, CGAffineTransform};
use cg::data_provider::{CGDataProviderRef, CGDataProvider};
use cg::font::{CGFontCreateWithDataProvider, CGFontRef, CGFontRelease, CGGlyph};
use cg::geometry::CGRect;
use core::libc::size_t; use core::libc::size_t;
use ct = core_text;
use ct::font::CTFont; struct QuartzFontTable {
use ct::font_descriptor::{kCTFontDefaultOrientation, CTFontSymbolicTraits}; data: CFData,
use ct::font_descriptor::{SymbolicTraitAccessors};
drop { }
}
pub impl QuartzFontTable {
static fn wrap(data: CFData) -> QuartzFontTable {
QuartzFontTable { data: move data }
}
}
pub impl QuartzFontTable : FontTableMethods {
fn with_buffer(blk: fn&(*u8, uint)) {
blk(self.data.bytes(), self.data.len());
}
}
pub struct QuartzFontHandle { pub struct QuartzFontHandle {
priv mut cgfont: Option<CGFontRef>, priv mut cgfont: Option<CGFontRef>,
@ -182,10 +206,10 @@ pub impl QuartzFontHandle : FontHandleMethods {
return metrics; return metrics;
} }
fn get_table_for_tag(tag: FontTableTag) -> Option<~[u8]> { fn get_table_for_tag(tag: FontTableTag) -> Option<FontTable> {
let result = self.ctfont.get_font_table(tag); let result : Option<CFData> = self.ctfont.get_font_table(tag);
return option::chain(move result, |data| { return option::chain(move result, |data| {
Some(data.copy_to_buf()) Some(QuartzFontTable::wrap(move data))
}); });
} }

View file

@ -7,6 +7,7 @@ use au::Au;
use font::{ use font::{
Font, Font,
FontTable,
FontTableTag, FontTableTag,
}; };
@ -191,16 +192,31 @@ extern fn get_font_table_func(_face: *hb_face_t, tag: hb_tag_t, user_data: *c_vo
let font: *Font = user_data as *Font; let font: *Font = user_data as *Font;
assert font.is_not_null(); assert font.is_not_null();
// TODO(Issue #197): reuse font table data, which will change return type here. // TODO(Issue #197): reuse font table data, which will change the unsound trickery 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) { match (*font).get_table_for_tag(tag as FontTableTag) {
None => return ptr::null(), None => return ptr::null(),
Some(table_buffer) => { Some(ref font_table) => {
let blob: *hb_blob_t = vec::as_imm_buf(table_buffer, |buf: *u8, len: uint| { let skinny_font_table = ~font_table;
hb_blob_create(buf as *c_char, len as c_uint, HB_MEMORY_MODE_READONLY, null(), null()) let skinny_font_table_ptr = ptr::to_unsafe_ptr(skinny_font_table);
let mut blob: *hb_blob_t = ptr::null();
(*skinny_font_table_ptr).with_buffer(|buf: *u8, len: uint| {
blob = hb_blob_create(buf as *c_char,
len as c_uint,
HB_MEMORY_MODE_READONLY,
cast::transmute(skinny_font_table_ptr), // private context for below.
destroy_blob_func); // HarfBuzz calls this when blob not needed.
}); });
assert blob.is_not_null();
return blob; return blob;
} }
} }
} }
// TODO(Issue #197): reuse font table data, which will change the unsound trickery here.
// In particular, we'll need to cast to a boxed, rather than owned, FontTable.
// even better, should cache the harfbuzz blobs directly instead of recreating a lot.
extern fn destroy_blob_func(user_data: *c_void) unsafe {
// this will cause drop to run.
let _wrapper : &~FontTable = cast::transmute(user_data);
}