mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Refactor the harfbuzz output interpretation function to be easier to follow. Remove old commented out version.
This commit is contained in:
parent
f72548d8fa
commit
cc1a0e5d6a
2 changed files with 96 additions and 86 deletions
|
@ -51,6 +51,78 @@ use harfbuzz::bindgen::{hb_blob_create, hb_blob_destroy,
|
|||
hb_font_funcs_set_glyph_func,
|
||||
hb_font_funcs_set_glyph_h_kerning_func};
|
||||
|
||||
pub struct ShapedGlyphData {
|
||||
count: uint,
|
||||
glyph_infos: *hb_glyph_info_t,
|
||||
pos_infos: *hb_glyph_position_t,
|
||||
}
|
||||
|
||||
pub struct ShapedGlyphEntry {
|
||||
cluster: uint,
|
||||
codepoint: GlyphIndex,
|
||||
advance: Au,
|
||||
offset: Option<Point2D<Au>>,
|
||||
}
|
||||
|
||||
pub impl ShapedGlyphData {
|
||||
static pure 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 = 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));
|
||||
assert pos_infos.is_not_null();
|
||||
assert glyph_count == pos_count as uint;
|
||||
|
||||
ShapedGlyphData {
|
||||
count: glyph_count,
|
||||
glyph_infos: glyph_infos,
|
||||
pos_infos: pos_infos,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pure fn get_cluster_for_glyph(i: uint) -> uint unsafe {
|
||||
assert i < self.count;
|
||||
|
||||
let glyph_info_i = ptr::offset(self.glyph_infos, i);
|
||||
return (*glyph_info_i).cluster as uint;
|
||||
}
|
||||
|
||||
pure fn len() -> uint { self.count }
|
||||
|
||||
// Returns shaped glyph data for one glyph, and updates the y-position of the pen.
|
||||
fn get_entry_for_glyph(i: uint, y_pos: &mut Au) -> ShapedGlyphEntry unsafe {
|
||||
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))
|
||||
};
|
||||
|
||||
ShapedGlyphEntry {
|
||||
cluster: (*glyph_info_i).cluster as uint,
|
||||
codepoint: (*glyph_info_i).codepoint as GlyphIndex,
|
||||
advance: x_advance,
|
||||
offset: move offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HarfbuzzShaper {
|
||||
font: @Font,
|
||||
priv hb_face: *hb_face_t,
|
||||
|
@ -126,35 +198,25 @@ pub impl HarfbuzzShaper {
|
|||
// correctly in this routine. it will probably explode with
|
||||
// multi-byte utf8 codepoints.
|
||||
|
||||
let glyph_data = ShapedGlyphData::new(buffer);
|
||||
let glyph_count = glyph_data.len();
|
||||
let char_max = str::char_len(text);
|
||||
|
||||
// get the results out of the hb_buffer_t
|
||||
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 = 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));
|
||||
assert pos_infos.is_not_null();
|
||||
assert glyph_count == pos_count as uint;
|
||||
|
||||
// wohoo
|
||||
debug!("Shaped text[char count=%u], got back %u glyph info records.", char_max, glyph_count);
|
||||
if char_max != glyph_count {
|
||||
debug!("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
|
||||
const NO_GLYPH : i32 = -1;
|
||||
let mut charToGlyph : ~[i32] = vec::from_elem(char_max, NO_GLYPH);
|
||||
debug!("(glyph idx) -> (char cluster)");
|
||||
for i32::range(0, glyph_count as i32) |i| {
|
||||
let info_i = ptr::offset(glyph_infos, i as uint);
|
||||
for uint::range(0, glyph_data.len()) |i| {
|
||||
// loc refers to a *byte* offset within the utf8 string.
|
||||
let loc: uint = unsafe { (*info_i).cluster as uint };
|
||||
debug!("%u -> %u", i as uint, loc);
|
||||
if loc < char_max { charToGlyph[loc] = i; }
|
||||
else { debug!("Tried to set out of range charToGlyph: idx=%u, glyph idx=%u", loc, i as uint); }
|
||||
let loc = glyph_data.get_cluster_for_glyph(i);
|
||||
debug!("%u -> %u", i, loc);
|
||||
if loc < char_max { charToGlyph[loc] = i as i32; }
|
||||
else { debug!("ERROR: tried to set out of range charToGlyph: idx=%u, glyph idx=%u", loc, i); }
|
||||
}
|
||||
|
||||
debug!("text: %s", text);
|
||||
|
@ -175,10 +237,7 @@ pub impl HarfbuzzShaper {
|
|||
glyph_span.extend_by(1);
|
||||
debug!("Processing glyph at idx=%u", glyph_span.begin());
|
||||
|
||||
let glyph_info_i = ptr::offset(glyph_infos, glyph_span.begin());
|
||||
let pos_info_i = ptr::offset(pos_infos, glyph_span.begin());
|
||||
let char_end = unsafe { (*glyph_info_i).cluster as uint };
|
||||
|
||||
let char_end = glyph_data.get_cluster_for_glyph(glyph_span.begin());
|
||||
char_span.extend_to(char_end);
|
||||
|
||||
// find a range of chars corresponding to this glyph, plus
|
||||
|
@ -219,10 +278,9 @@ pub impl HarfbuzzShaper {
|
|||
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 char_span.eachi |j| {
|
||||
let glyph_info_j = ptr::offset(glyph_infos, j);
|
||||
let cluster_idx = unsafe { (*glyph_info_j).cluster as uint };
|
||||
if cluster_idx < char_span.begin() || cluster_idx > char_span.end() {
|
||||
do glyph_span.eachi |j| {
|
||||
let loc = glyph_data.get_cluster_for_glyph(j);
|
||||
if !char_span.contains(loc) {
|
||||
all_glyphs_are_within_cluster = false;
|
||||
}
|
||||
all_glyphs_are_within_cluster // if true, keep checking. else, stop.
|
||||
|
@ -264,20 +322,7 @@ pub impl HarfbuzzShaper {
|
|||
}
|
||||
|
||||
// clamp to end of text. (I don't think this will be necessary, but..)
|
||||
let covered_end = uint::min(chars_covered_span.end(), char_max);
|
||||
chars_covered_span.extend_to(covered_end);
|
||||
|
||||
// TODO: extract this into a struct passed by reference to helper function
|
||||
let mut codepoint = unsafe { (*glyph_info_i).codepoint as GlyphIndex };
|
||||
let mut x_offset = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).x_offset)) };
|
||||
let mut y_offset = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).y_offset)) };
|
||||
let mut x_advance = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).x_advance)) };
|
||||
let mut y_advance = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).y_advance)) };
|
||||
let mut offset = Point2D(x_offset, y_pos - y_offset);
|
||||
// adjust our pen..
|
||||
if y_advance > Au(0) {
|
||||
y_pos -= y_advance;
|
||||
}
|
||||
chars_covered_span.extend_to(uint::min(chars_covered_span.end(), char_max));
|
||||
|
||||
// fast path: 1-to-1 mapping of single char and single glyph.
|
||||
if glyph_span.length() == 1 {
|
||||
|
@ -285,45 +330,26 @@ pub impl HarfbuzzShaper {
|
|||
// shaping, and then consulted here.
|
||||
// for now, just pretend that every character is a cluster start.
|
||||
// (i.e., pretend there are no combining character sequences)
|
||||
let used_offset = if offset == Au::zero_point() { None } else { Some(offset) };
|
||||
let data = GlyphData(codepoint, x_advance, used_offset, false, true, true);
|
||||
let shape = glyph_data.get_entry_for_glyph(glyph_span.begin(), &mut y_pos);
|
||||
let data = GlyphData(shape.codepoint, shape.advance, shape.offset, false, true, true);
|
||||
glyphs.add_glyph_for_index(glyph_span.begin(), &data);
|
||||
} else {
|
||||
// collect all glyphs to be assigned to the first character.
|
||||
let datas = DVec();
|
||||
|
||||
// there is at least one, and its advance was already
|
||||
// measured. So, the loop condition is placed weirdly.
|
||||
loop {
|
||||
let used_offset = if offset == Au::zero_point() { None } else { Some(offset) };
|
||||
datas.push(GlyphData(codepoint, x_advance, used_offset, false, true, true));
|
||||
|
||||
while glyph_span.length() > 0 {
|
||||
let shape = glyph_data.get_entry_for_glyph(glyph_span.begin(), &mut y_pos);
|
||||
datas.push(GlyphData(shape.codepoint, shape.advance, shape.offset, false, true, true));
|
||||
glyph_span.adjust_by(1,-1);
|
||||
if glyph_span.length() == 0 { break; }
|
||||
|
||||
let glyph_info_j = ptr::offset(glyph_infos, glyph_span.begin());
|
||||
let pos_info_j = ptr::offset(pos_infos, glyph_span.begin());
|
||||
codepoint = unsafe { (*glyph_info_j).codepoint as GlyphIndex };
|
||||
x_offset = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_j).x_offset)) };
|
||||
y_offset = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_j).y_offset)) };
|
||||
x_advance = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_j).x_advance)) };
|
||||
y_advance = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_j).y_advance)) };
|
||||
offset = Point2D(x_offset, y_pos - y_offset);
|
||||
// adjust our pen..
|
||||
if y_advance > Au(0) {
|
||||
y_pos -= y_advance;
|
||||
}
|
||||
}
|
||||
|
||||
// now add the actual entry.
|
||||
// now add the detailed glyph entry.
|
||||
glyphs.add_glyphs_for_index(glyph_span.begin(), dvec::unwrap(move datas));
|
||||
|
||||
chars_covered_span.adjust_by(1, -1);
|
||||
// set the other chars, who have no glyphs
|
||||
for chars_covered_span.eachi |covered_j| {
|
||||
for uint::range(chars_covered_span.begin()+1, chars_covered_span.end()) |covered_j| {
|
||||
glyphs.add_nonglyph_for_index(covered_j, false, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// shift up our working spans past things we just handled.
|
||||
|
@ -332,26 +358,6 @@ pub impl HarfbuzzShaper {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
for uint::range(0u, glyph_count as uint) |i| { unsafe {
|
||||
let hb_info: hb_glyph_info_t = *ptr::offset(glyph_infos, i);
|
||||
let hb_pos: hb_glyph_position_t = *ptr::offset(pos_infos, i);
|
||||
let codepoint = hb_info.codepoint as GlyphIndex;
|
||||
let advance: Au = Au::from_frac_px(HarfbuzzShaper::fixed_to_float(hb_pos.x_advance));
|
||||
let offset = match (hb_pos.x_offset, hb_pos.y_offset) {
|
||||
(0, 0) => None,
|
||||
(x, y) => Some(Point2D(Au::from_frac_px(HarfbuzzShaper::fixed_to_float(x)),
|
||||
Au::from_frac_px(HarfbuzzShaper::fixed_to_float(y))))
|
||||
};
|
||||
// TODO: convert pos.y_advance into offset adjustment
|
||||
// TODO(#95): handle multiple glyphs per char, ligatures, etc.
|
||||
// NB. this debug statement is commented out, as it must be checked for every shaped char.
|
||||
debug!("glyph %?: index %?, advance %?, offset %?", i, codepoint, advance, offset);
|
||||
|
||||
let data = GlyphData(codepoint, advance, offset, false, false, false);
|
||||
glyphs.add_glyph_for_index(i, &data);
|
||||
} } */
|
||||
|
||||
static priv fn float_to_fixed(f: float) -> i32 {
|
||||
util::float_to_fixed(16, f)
|
||||
}
|
||||
|
|
|
@ -128,6 +128,10 @@ impl MutableRange {
|
|||
do uint::range(self.off, self.off + self.len) |i| { cb(i) }
|
||||
}
|
||||
|
||||
pub pure fn contains(i: uint) -> bool {
|
||||
i >= self.begin() && i < self.end()
|
||||
}
|
||||
|
||||
fn relation_to_range(&self, other: &MutableRange) -> RangeRelation {
|
||||
self.as_immutable().relation_to_range(other.as_immutable())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue