mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Refactor the HarfBuzz shaper to be in line with modern Rust style
This commit is contained in:
parent
9cadf19d15
commit
bbf1582f8e
1 changed files with 168 additions and 142 deletions
|
@ -1,62 +1,59 @@
|
|||
//! Performs shaping with HarfBuzz.
|
||||
|
||||
extern mod harfbuzz;
|
||||
|
||||
use geom::Point2D;
|
||||
|
||||
use geometry::Au;
|
||||
|
||||
use font::{Font, FontHandleMethods, FontTableMethods, FontTableTag};
|
||||
use geometry::Au;
|
||||
use platform::font::FontTable;
|
||||
|
||||
use text::glyph::{GlyphStore, GlyphIndex, GlyphData};
|
||||
use text::shaper::ShaperMethods;
|
||||
|
||||
use text::util::{float_to_fixed, fixed_to_float, fixed_to_rounded_int};
|
||||
use util::range::Range;
|
||||
|
||||
use core::cast::transmute;
|
||||
use core::libc::{c_uint, c_int, c_void, c_char};
|
||||
use core::ptr::null;
|
||||
use core::util::ignore;
|
||||
|
||||
use text::harfbuzz::shaper::harfbuzz::{HB_MEMORY_MODE_READONLY, HB_DIRECTION_LTR, hb_blob_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_face_t, hb_font_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_font_funcs_t, hb_buffer_t, hb_codepoint_t, hb_bool_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_glyph_position_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_glyph_info_t, hb_position_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::hb_blob_create;
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::hb_face_destroy;
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_create, hb_font_destroy};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_create};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_destroy};
|
||||
use geom::Point2D;
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_blob_create, hb_face_create_for_tables};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_add_utf8, hb_shape};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_create};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_destroy, hb_buffer_add_utf8};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_get_glyph_infos};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_get_glyph_positions};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_ppem};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_scale};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_get_glyph_positions};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_set_direction};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_set_direction};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_face_destroy, hb_font_create};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_face_destroy};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_create, hb_font_destroy};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_destroy, hb_buffer_create};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_create, hb_font_funcs_destroy};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_create};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_destroy};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_funcs};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_set_glyph_h_advance_func};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_set_glyph_func};
|
||||
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_set_glyph_func};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_set_glyph_h_advance_func};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_set_glyph_h_advance_func};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_funcs};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_funcs};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_ppem, hb_font_set_scale};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_ppem};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_scale};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_shape, hb_buffer_get_glyph_infos};
|
||||
use text::harfbuzz::shaper::harfbuzz::{HB_MEMORY_MODE_READONLY, HB_DIRECTION_LTR, hb_blob_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{HB_MEMORY_MODE_READONLY, HB_DIRECTION_LTR};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_font_funcs_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_buffer_t, hb_codepoint_t, hb_bool_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_face_t, hb_font_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_font_funcs_t, hb_buffer_t, hb_codepoint_t, hb_bool_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_glyph_info_t, hb_position_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_glyph_position_t, hb_glyph_info_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_glyph_position_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::{hb_position_t, hb_tag_t};
|
||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_blob_create,
|
||||
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};
|
||||
|
||||
use text::util::{float_to_fixed, fixed_to_float, fixed_to_rounded_int};
|
||||
static NO_GLYPH: i32 = -1;
|
||||
static CONTINUATION_BYTE: i32 = -2;
|
||||
|
||||
pub struct ShapedGlyphData {
|
||||
count: uint,
|
||||
|
@ -71,15 +68,15 @@ pub struct ShapedGlyphEntry {
|
|||
offset: Option<Point2D<Au>>,
|
||||
}
|
||||
|
||||
pub impl ShapedGlyphData {
|
||||
fn new(buffer: *hb_buffer_t) -> ShapedGlyphData {
|
||||
impl ShapedGlyphData {
|
||||
pub fn new(buffer: *hb_buffer_t) -> ShapedGlyphData {
|
||||
unsafe {
|
||||
let glyph_count = 0 as c_uint;
|
||||
let glyph_infos = hb_buffer_get_glyph_infos(buffer, ptr::to_unsafe_ptr(&glyph_count));
|
||||
let glyph_count = 0;
|
||||
let glyph_infos = hb_buffer_get_glyph_infos(buffer, &glyph_count);
|
||||
let glyph_count = glyph_count as uint;
|
||||
assert!(glyph_infos.is_not_null());
|
||||
let pos_count = 0 as c_uint;
|
||||
let pos_infos = hb_buffer_get_glyph_positions(buffer, ptr::to_unsafe_ptr(&pos_count));
|
||||
let pos_count = 0;
|
||||
let pos_infos = hb_buffer_get_glyph_positions(buffer, &pos_count);
|
||||
assert!(pos_infos.is_not_null());
|
||||
assert!(glyph_count == pos_count as uint);
|
||||
|
||||
|
@ -92,7 +89,7 @@ pub impl ShapedGlyphData {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
priv fn byte_offset_of_glyph(&self, i: uint) -> uint {
|
||||
fn byte_offset_of_glyph(&self, i: uint) -> uint {
|
||||
assert!(i < self.count);
|
||||
|
||||
let glyph_info_i = ptr::offset(self.glyph_infos, i);
|
||||
|
@ -101,31 +98,38 @@ pub impl ShapedGlyphData {
|
|||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> uint { self.count }
|
||||
pub fn len(&self) -> uint {
|
||||
self.count
|
||||
}
|
||||
|
||||
// Returns shaped glyph data for one glyph, and updates the y-position of the pen.
|
||||
fn get_entry_for_glyph(&self, i: uint, y_pos: &mut Au) -> ShapedGlyphEntry {
|
||||
/// Returns shaped glyph data for one glyph, and updates the y-position of the pen.
|
||||
pub fn get_entry_for_glyph(&self, i: uint, y_pos: &mut Au) -> ShapedGlyphEntry {
|
||||
assert!(i < self.count);
|
||||
|
||||
let glyph_info_i = ptr::offset(self.glyph_infos, i);
|
||||
let pos_info_i = ptr::offset(self.pos_infos, i);
|
||||
let x_offset = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).x_offset)) };
|
||||
let y_offset = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).y_offset)) };
|
||||
let x_advance = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).x_advance)) };
|
||||
let y_advance = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).y_advance)) };
|
||||
let offset = if x_offset == Au(0)
|
||||
&& y_offset == Au(0)
|
||||
&& y_advance == Au(0) { None }
|
||||
else {
|
||||
// adjust the pen..
|
||||
if y_advance > Au(0) {
|
||||
*y_pos -= y_advance;
|
||||
}
|
||||
|
||||
Some(Point2D(x_offset, *y_pos - y_offset))
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let glyph_info_i = ptr::offset(self.glyph_infos, i);
|
||||
let pos_info_i = ptr::offset(self.pos_infos, i);
|
||||
let x_offset = HarfbuzzShaper::fixed_to_float((*pos_info_i).x_offset);
|
||||
let y_offset = HarfbuzzShaper::fixed_to_float((*pos_info_i).y_offset);
|
||||
let x_advance = HarfbuzzShaper::fixed_to_float((*pos_info_i).x_advance);
|
||||
let y_advance = HarfbuzzShaper::fixed_to_float((*pos_info_i).y_advance);
|
||||
|
||||
let x_offset = Au::from_frac_px(x_offset);
|
||||
let y_offset = Au::from_frac_px(y_offset);
|
||||
let x_advance = Au::from_frac_px(x_advance);
|
||||
let y_advance = Au::from_frac_px(y_advance);
|
||||
|
||||
let offset = if x_offset == Au(0) && y_offset == Au(0) && y_advance == Au(0) {
|
||||
None
|
||||
} else {
|
||||
// adjust the pen..
|
||||
if y_advance > Au(0) {
|
||||
*y_pos -= y_advance;
|
||||
}
|
||||
|
||||
Some(Point2D(x_offset, *y_pos - y_offset))
|
||||
};
|
||||
|
||||
ShapedGlyphEntry {
|
||||
cluster: (*glyph_info_i).cluster as uint,
|
||||
codepoint: (*glyph_info_i).codepoint as GlyphIndex,
|
||||
|
@ -157,102 +161,106 @@ impl Drop for HarfbuzzShaper {
|
|||
}
|
||||
}
|
||||
|
||||
pub impl HarfbuzzShaper {
|
||||
impl HarfbuzzShaper {
|
||||
pub fn new(font: @mut Font) -> HarfbuzzShaper {
|
||||
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_font: *hb_font_t = hb_font_create(hb_face);
|
||||
// Set points-per-em. if zero, performs no hinting in that direction.
|
||||
let pt_size = font.style.pt_size;
|
||||
hb_font_set_ppem(hb_font, pt_size as c_uint, pt_size as c_uint);
|
||||
// Set scaling. Note that this takes 16.16 fixed point.
|
||||
hb_font_set_scale(hb_font,
|
||||
HarfbuzzShaper::float_to_fixed(pt_size) as c_int,
|
||||
HarfbuzzShaper::float_to_fixed(pt_size) as c_int);
|
||||
|
||||
// configure static function callbacks.
|
||||
// NB. This funcs structure could be reused globally, as it never changes.
|
||||
let hb_funcs: *hb_font_funcs_t = hb_font_funcs_create();
|
||||
hb_font_funcs_set_glyph_func(hb_funcs, glyph_func, ptr::null(), ptr::null());
|
||||
hb_font_funcs_set_glyph_h_advance_func(hb_funcs, glyph_h_advance_func, ptr::null(), ptr::null());
|
||||
unsafe {
|
||||
let font_data: *c_void = ptr::addr_of(font) as *c_void;
|
||||
hb_font_set_funcs(hb_font, hb_funcs, font_data, ptr::null());
|
||||
};
|
||||
let font_ptr: *mut Font = &mut *font;
|
||||
let hb_face: *hb_face_t = hb_face_create_for_tables(get_font_table_func,
|
||||
font_ptr as *c_void,
|
||||
null());
|
||||
let hb_font: *hb_font_t = hb_font_create(hb_face);
|
||||
|
||||
HarfbuzzShaper {
|
||||
font: font,
|
||||
hb_face: hb_face,
|
||||
hb_font: hb_font,
|
||||
hb_funcs: hb_funcs,
|
||||
// Set points-per-em. if zero, performs no hinting in that direction.
|
||||
let pt_size = font.style.pt_size;
|
||||
hb_font_set_ppem(hb_font, pt_size as c_uint, pt_size as c_uint);
|
||||
|
||||
// Set scaling. Note that this takes 16.16 fixed point.
|
||||
hb_font_set_scale(hb_font,
|
||||
HarfbuzzShaper::float_to_fixed(pt_size) as c_int,
|
||||
HarfbuzzShaper::float_to_fixed(pt_size) as c_int);
|
||||
|
||||
// configure static function callbacks.
|
||||
// NB. This funcs structure could be reused globally, as it never changes.
|
||||
let hb_funcs: *hb_font_funcs_t = hb_font_funcs_create();
|
||||
hb_font_funcs_set_glyph_func(hb_funcs, glyph_func, null(), null());
|
||||
hb_font_funcs_set_glyph_h_advance_func(hb_funcs, glyph_h_advance_func, null(), null());
|
||||
hb_font_set_funcs(hb_font, hb_funcs, font_ptr as *c_void, null());
|
||||
|
||||
HarfbuzzShaper {
|
||||
font: font,
|
||||
hb_face: hb_face,
|
||||
hb_font: hb_font,
|
||||
hb_funcs: hb_funcs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
priv fn float_to_fixed(f: float) -> i32 {
|
||||
fn float_to_fixed(f: float) -> i32 {
|
||||
float_to_fixed(16, f)
|
||||
}
|
||||
|
||||
priv fn fixed_to_float(i: hb_position_t) -> float {
|
||||
fn fixed_to_float(i: hb_position_t) -> float {
|
||||
fixed_to_float(16, i)
|
||||
}
|
||||
|
||||
priv fn fixed_to_rounded_int(f: hb_position_t) -> int {
|
||||
fn fixed_to_rounded_int(f: hb_position_t) -> int {
|
||||
fixed_to_rounded_int(16, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ShaperMethods for HarfbuzzShaper {
|
||||
/**
|
||||
Calculate the layout metrics associated with a some given text
|
||||
when rendered in a specific font.
|
||||
*/
|
||||
/// Calculate the layout metrics associated with the given text when rendered in a specific
|
||||
/// font.
|
||||
fn shape_text(&self, text: &str, glyphs: &mut GlyphStore) {
|
||||
let hb_buffer: *hb_buffer_t = hb_buffer_create();
|
||||
hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);
|
||||
|
||||
// Using as_buf because it never does a copy - we don't need the trailing null
|
||||
str::as_buf(text, |ctext: *u8, _l: uint| {
|
||||
do str::as_buf(text) |ctext: *u8, _: uint| {
|
||||
hb_buffer_add_utf8(hb_buffer,
|
||||
ctext as *c_char,
|
||||
text.len() as c_int,
|
||||
0 as c_uint,
|
||||
0,
|
||||
text.len() as c_int);
|
||||
});
|
||||
}
|
||||
|
||||
hb_shape(self.hb_font, hb_buffer, ptr::null(), 0 as c_uint);
|
||||
hb_shape(self.hb_font, hb_buffer, null(), 0);
|
||||
self.save_glyph_results(text, glyphs, hb_buffer);
|
||||
hb_buffer_destroy(hb_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
pub impl HarfbuzzShaper {
|
||||
|
||||
priv fn save_glyph_results(&self, text: &str, glyphs: &mut GlyphStore, buffer: *hb_buffer_t) {
|
||||
impl HarfbuzzShaper {
|
||||
fn save_glyph_results(&self, text: &str, glyphs: &mut GlyphStore, buffer: *hb_buffer_t) {
|
||||
let glyph_data = ShapedGlyphData::new(buffer);
|
||||
let glyph_count = glyph_data.len();
|
||||
let byte_max = text.len();
|
||||
let char_max = str::char_len(text);
|
||||
|
||||
// GlyphStore records are indexed by character, not byte offset.
|
||||
// so, we must be careful to increment this when saving glyph entries.
|
||||
let mut char_idx = 0;
|
||||
|
||||
assert!(glyph_count <= char_max);
|
||||
|
||||
debug!("Shaped text[char count=%u], got back %u glyph info records.", char_max, glyph_count);
|
||||
debug!("Shaped text[char count=%u], got back %u glyph info records.",
|
||||
char_max,
|
||||
glyph_count);
|
||||
|
||||
if char_max != glyph_count {
|
||||
debug!("NOTE: Since these are not equal, we probably have been given some complex glyphs.");
|
||||
debug!("NOTE: Since these are not equal, we probably have been given some complex \
|
||||
glyphs.");
|
||||
}
|
||||
|
||||
// make map of what chars have glyphs
|
||||
static NO_GLYPH : i32 = -1;
|
||||
static CONTINUATION_BYTE : i32 = -2;
|
||||
let mut byteToGlyph : ~[i32];
|
||||
let mut byteToGlyph: ~[i32];
|
||||
|
||||
// fast path: all chars are single-byte.
|
||||
if byte_max == char_max {
|
||||
byteToGlyph = vec::from_elem(byte_max, NO_GLYPH);
|
||||
} else {
|
||||
byteToGlyph = vec::from_elem(byte_max, CONTINUATION_BYTE);
|
||||
let mut i = 0u;
|
||||
let mut i = 0;
|
||||
while i < byte_max {
|
||||
byteToGlyph[i] = NO_GLYPH;
|
||||
let range = str::char_range_at(text, i);
|
||||
|
@ -268,8 +276,11 @@ pub impl HarfbuzzShaper {
|
|||
if loc < byte_max {
|
||||
assert!(byteToGlyph[loc] != CONTINUATION_BYTE);
|
||||
byteToGlyph[loc] = i as i32;
|
||||
} else {
|
||||
debug!("ERROR: tried to set out of range byteToGlyph: idx=%u, glyph idx=%u",
|
||||
loc,
|
||||
i);
|
||||
}
|
||||
else { debug!("ERROR: tried to set out of range byteToGlyph: idx=%u, glyph idx=%u", loc, i); }
|
||||
debug!("%u -> %u", i, loc);
|
||||
}
|
||||
|
||||
|
@ -283,14 +294,15 @@ pub impl HarfbuzzShaper {
|
|||
}
|
||||
|
||||
// some helpers
|
||||
let mut glyph_span : Range = Range::empty();
|
||||
let mut glyph_span: Range = Range::empty();
|
||||
// this span contains first byte of first char, to last byte of last char in range.
|
||||
// so, end() points to first byte of last+1 char, if it's less than byte_max.
|
||||
let mut char_byte_span : Range = Range::empty();
|
||||
let mut char_byte_span: Range = Range::empty();
|
||||
let mut y_pos = Au(0);
|
||||
|
||||
// main loop over each glyph. each iteration usually processes 1 glyph and 1+ chars.
|
||||
// in cases with complex glyph-character assocations, 2+ glyphs and 1+ chars can be processed.
|
||||
// in cases with complex glyph-character assocations, 2+ glyphs and 1+ chars can be
|
||||
// processed.
|
||||
while glyph_span.begin() < glyph_count {
|
||||
// start by looking at just one glyph.
|
||||
glyph_span.extend_by(1);
|
||||
|
@ -309,8 +321,10 @@ pub impl HarfbuzzShaper {
|
|||
debug!("Processing char byte span: off=%u, len=%u for glyph idx=%u",
|
||||
char_byte_span.begin(), char_byte_span.length(), glyph_span.begin());
|
||||
|
||||
while char_byte_span.end() != byte_max && byteToGlyph[char_byte_span.end()] == NO_GLYPH {
|
||||
debug!("Extending char byte span to include byte offset=%u with no associated glyph", char_byte_span.end());
|
||||
while char_byte_span.end() != byte_max &&
|
||||
byteToGlyph[char_byte_span.end()] == NO_GLYPH {
|
||||
debug!("Extending char byte span to include byte offset=%u with no associated \
|
||||
glyph", char_byte_span.end());
|
||||
let range = str::char_range_at(text, char_byte_span.end());
|
||||
ignore(range.ch);
|
||||
char_byte_span.extend_to(range.next);
|
||||
|
@ -327,7 +341,8 @@ pub impl HarfbuzzShaper {
|
|||
|
||||
if max_glyph_idx > glyph_span.end() {
|
||||
glyph_span.extend_to(max_glyph_idx);
|
||||
debug!("Extended glyph span (off=%u, len=%u) to cover char byte span's max glyph index",
|
||||
debug!("Extended glyph span (off=%u, len=%u) to cover char byte span's max \
|
||||
glyph index",
|
||||
glyph_span.begin(), glyph_span.length());
|
||||
}
|
||||
|
||||
|
@ -338,7 +353,8 @@ pub impl HarfbuzzShaper {
|
|||
// if no glyphs were found yet, extend the char byte range more.
|
||||
if glyph_span.length() == 0 { loop; }
|
||||
|
||||
debug!("Complex (multi-glyph to multi-char) association found. This case probably doesn't work.");
|
||||
debug!("Complex (multi-glyph to multi-char) association found. This case \
|
||||
probably doesn't work.");
|
||||
|
||||
let mut all_glyphs_are_within_cluster: bool = true;
|
||||
do glyph_span.eachi |j| {
|
||||
|
@ -349,7 +365,8 @@ pub impl HarfbuzzShaper {
|
|||
all_glyphs_are_within_cluster // if true, keep checking. else, stop.
|
||||
}
|
||||
|
||||
debug!("All glyphs within char_byte_span cluster?: %?", all_glyphs_are_within_cluster);
|
||||
debug!("All glyphs within char_byte_span cluster?: %?",
|
||||
all_glyphs_are_within_cluster);
|
||||
|
||||
// found a valid range; stop extending char_span.
|
||||
if all_glyphs_are_within_cluster { break; }
|
||||
|
@ -371,10 +388,11 @@ pub impl HarfbuzzShaper {
|
|||
// gspan: [-]
|
||||
// cspan: [-]
|
||||
// covsp: [---------------]
|
||||
|
||||
let mut covered_byte_span = copy char_byte_span;
|
||||
// extend, clipping at end of text range.
|
||||
while covered_byte_span.end() < byte_max
|
||||
&& byteToGlyph[covered_byte_span.end()] == NO_GLYPH {
|
||||
&& byteToGlyph[covered_byte_span.end()] == NO_GLYPH {
|
||||
let range = str::char_range_at(text, covered_byte_span.end());
|
||||
ignore(range.ch);
|
||||
covered_byte_span.extend_to(range.next);
|
||||
|
@ -413,8 +431,8 @@ pub impl HarfbuzzShaper {
|
|||
|
||||
for glyph_span.eachi |glyph_i| {
|
||||
let shape = glyph_data.get_entry_for_glyph(glyph_i, &mut y_pos);
|
||||
datas.push(GlyphData::new(shape.codepoint,
|
||||
shape.advance,
|
||||
datas.push(GlyphData::new(shape.codepoint,
|
||||
shape.advance,
|
||||
shape.offset,
|
||||
false, // not missing
|
||||
true, // treat as cluster start
|
||||
|
@ -452,26 +470,32 @@ pub impl HarfbuzzShaper {
|
|||
}
|
||||
|
||||
/// Callbacks from Harfbuzz when font map and glyph advance lookup needed.
|
||||
extern fn glyph_func(_font: *hb_font_t,
|
||||
extern fn glyph_func(_: *hb_font_t,
|
||||
font_data: *c_void,
|
||||
unicode: hb_codepoint_t,
|
||||
_variant_selector: hb_codepoint_t,
|
||||
_: hb_codepoint_t,
|
||||
glyph: *mut hb_codepoint_t,
|
||||
_user_data: *c_void) -> hb_bool_t {
|
||||
_: *c_void)
|
||||
-> hb_bool_t {
|
||||
let font: *Font = font_data as *Font;
|
||||
assert!(font.is_not_null());
|
||||
|
||||
unsafe {
|
||||
return match (*font).glyph_index(unicode as char) {
|
||||
Some(g) => { *glyph = g as hb_codepoint_t; true },
|
||||
None => false
|
||||
} as hb_bool_t;
|
||||
match (*font).glyph_index(unicode as char) {
|
||||
Some(g) => {
|
||||
*glyph = g as hb_codepoint_t;
|
||||
true as hb_bool_t
|
||||
}
|
||||
None => false as hb_bool_t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern fn glyph_h_advance_func(_font: *hb_font_t,
|
||||
extern fn glyph_h_advance_func(_: *hb_font_t,
|
||||
font_data: *c_void,
|
||||
glyph: hb_codepoint_t,
|
||||
_user_data: *c_void) -> hb_position_t {
|
||||
_: *c_void)
|
||||
-> hb_position_t {
|
||||
let font: *Font = font_data as *Font;
|
||||
assert!(font.is_not_null());
|
||||
|
||||
|
@ -482,27 +506,29 @@ extern fn glyph_h_advance_func(_font: *hb_font_t,
|
|||
}
|
||||
|
||||
// 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 {
|
||||
extern fn get_font_table_func(_: *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 the unsound trickery here.
|
||||
match (*font).get_table_for_tag(tag as FontTableTag) {
|
||||
None => return ptr::null(),
|
||||
None => null(),
|
||||
Some(ref font_table) => {
|
||||
let skinny_font_table = ~font_table;
|
||||
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| {
|
||||
let skinny_font_table_ptr: *FontTable = font_table; // private context
|
||||
|
||||
let mut blob: *hb_blob_t = null();
|
||||
do (*skinny_font_table_ptr).with_buffer |buf: *u8, len: uint| {
|
||||
// HarfBuzz calls `destroy_blob_func` when the buffer is no longer needed.
|
||||
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.
|
||||
});
|
||||
transmute(skinny_font_table_ptr),
|
||||
destroy_blob_func);
|
||||
}
|
||||
|
||||
assert!(blob.is_not_null());
|
||||
return blob;
|
||||
blob
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +538,7 @@ extern fn get_font_table_func(_face: *hb_face_t, tag: hb_tag_t, user_data: *c_vo
|
|||
// 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) {
|
||||
// this will cause drop to run.
|
||||
let _wrapper : &~FontTable = unsafe { cast::transmute(user_data) };
|
||||
extern fn destroy_blob_func(_: *c_void) {
|
||||
// TODO: Previous code here was broken. Rewrite.
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue