Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use byteorder::ByteOrder;
- use byteorder::BigEndian as BE;
- use std::collections::HashMap as Map;
- pub fn get_kernings(fonts: &[u8], font_index: usize) -> Map<(u16, u16), i16> {
- let kern = find_table(&fonts, font_index, b"kern");
- let gpos = find_table(&fonts, font_index, b"GPOS");
- let mut kernings = Map::new();
- if gpos != 0 {
- let gpos = &fonts[gpos..];
- kernings = read_gpos_table(gpos)
- }
- if kern != 0 && kernings.len() == 0 {
- let kern = &fonts[kern..];
- kernings = read_kern_table(kern)
- }
- kernings
- }
- fn read_gpos_table(gpos: &[u8]) -> Map<(u16, u16), i16> {
- let script_list_offset = get(gpos, 4);
- let feature_list_offset = get(gpos, 6);
- let lookup_list_offset = get(gpos, 8);
- let script_list = &gpos[script_list_offset..];
- let feature_list = &gpos[feature_list_offset..];
- let lookup_list = &gpos[lookup_list_offset..];
- // Locate the default script in the script list table
- let script_count = BE::read_u16(script_list) as usize;
- let mut offset = 0;
- for c in 0..script_count {
- let script_record = &script_list[2 + c * 6..];
- if &script_record[..4] == b"DFLT" {
- offset = get(script_record, 4);
- break;
- }
- }
- let mut kernings = Map::new();
- if offset == 0 {
- return kernings;
- }
- let script = &script_list[offset..];
- let default_lang_sys_offset = get(script, 0);
- if default_lang_sys_offset == 0 {
- return kernings;
- }
- let lang_sys = &script[default_lang_sys_offset..];
- let lookup_order = BE::read_u16(lang_sys);
- assert_eq!(lookup_order, 0); // reserved for future use
- let feature_count = get(lang_sys, 4);
- // Find all kerning pairs from all the features that apply
- let all_feature_count = get(feature_list, 0);
- for c in 0..feature_count {
- let feature_index = get(lang_sys, 6 + c * 2);
- if feature_index < all_feature_count {
- let feature_record = &feature_list[2 + 6 * feature_index..];
- if &feature_record[..4] == b"kern" {
- process_kern_feature(feature_record, feature_list, lookup_list, &mut kernings);
- }
- }
- }
- kernings
- }
- fn read_kern_table(kern: &[u8]) -> Map<(u16, u16), i16> {
- let mut kernings = Map::new();
- // we only look at the first table. it must be 'horizontal' and format 0
- if BE::read_u16(&kern[2..]) < 1 || BE::read_u16(&kern[8..]) != 1 {
- // kern not present, OR
- // no tables (need at least one), OR
- // horizontal flag not set in format
- return kernings;
- }
- let len = BE::read_u16(&kern[10..]) as usize;
- for i in 0..len {
- let key = BE::read_u32(&kern[18 + i * 6..]);
- let val = BE::read_i16(&kern[22 + i * 6..]);
- let key = unsafe { std::mem::transmute(key) };
- kernings.insert(key, val);
- }
- kernings
- }
- fn process_kern_feature(feature_record: &[u8], feature_list: &[u8],
- lookup_list: &[u8], kernings: &mut Map<(u16, u16), i16>) {
- let offset = get(feature_record, 4);
- let feature = &feature_list[offset..];
- let lookup_count = get(feature, 2);
- let all_lookup_count = get(lookup_list, 0);
- for i in 0..lookup_count {
- let lookup_index = get(feature, 4 + i * 2);
- // Determine the features that apply (look for kerning pairs)
- // Find the adjustments in the lookup table
- if lookup_index < all_lookup_count {
- let lookup_offset = get(lookup_list, 2 + lookup_index * 2);
- let lookup = &lookup_list[lookup_offset..];
- let lookup_type = get(lookup, 0);
- let sub_table_count = get(lookup, 4);
- for s in 0..sub_table_count {
- let offset = get(lookup, 6 + s * 2);
- let mut sub_table = &lookup[offset..];
- let mut real_lookup_type = lookup_type;
- if lookup_type == 9 {
- // extension positioning
- let pos_format = get(sub_table, 0);
- assert_eq!(pos_format, 1); // reserved
- let extension_lookup_type = get(sub_table, 2);
- let extension_offset = BE::read_u32(&sub_table[4..]) as usize;
- real_lookup_type = extension_lookup_type;
- sub_table = &sub_table[extension_offset..];
- }
- if real_lookup_type == 2 {
- // pair adjustment
- let pos_format = get(sub_table, 0);
- if pos_format == 1 {
- process_pair_adjustment_format1(sub_table, kernings);
- } else if pos_format == 2 {
- process_pair_adjustment_format2(sub_table, kernings);
- } else {
- unreachable!()
- }
- }
- }
- }
- }
- }
- fn process_pair_adjustment_format2(sub_table: &[u8], kernings: &mut Map<(u16, u16), i16>) {
- // Defines kerning between two classes of glyphs
- let coverage_offset = get(sub_table, 2);
- let value_format1 = get(sub_table, 4);
- assert_eq!(value_format1, 4); // TODO: must support others
- let value_format2 = get(sub_table, 6);
- assert_eq!(value_format2, 0); // TODO: must support others
- let class_def_offset1 = get(sub_table, 8);
- let class_def_offset2 = get(sub_table, 10);
- let class_count1 = get(sub_table, 12);
- let class_count2 = get(sub_table, 14);
- let value_pair_size = get_size_of_value_type(value_format1) + get_size_of_value_type(value_format2);
- // The first glyph id in the pair is found in the coverage table
- // The second glyph id is determined from the class definitions
- let mut glyph1 = Vec::new();
- let coverage = &sub_table[coverage_offset..];
- let coverage_format = get(coverage, 0);
- if coverage_format == 1 {
- let glyph_count = get(coverage, 2);
- glyph1.reserve(glyph_count);
- for g in 0..glyph_count {
- let glyph_id = get(coverage, 4 + 2 * g);
- glyph1.push(glyph_id);
- }
- } else {
- let range_count = get(coverage, 2);
- // Expand the ranges into the glyph1 array
- for n in 0..range_count {
- let start = get(coverage, 4 + n * 6);
- let end = get(coverage, 6 + n * 6);
- for g in start..end + 1 {
- glyph1.push(g);
- }
- }
- }
- for g in glyph1 {
- let c1 = get_class_from_class_def(&sub_table[class_def_offset1..], g);
- assert!(c1 < class_count1);
- if c1 < class_count1 {
- let c1list = &sub_table[16 + c1 * class_count2 * value_pair_size..];
- for c2 in 0..class_count2 {
- // Enumerate the glyphs that are part of the classes
- let glyph2 = get_glyphs_from_class_def(&sub_table[class_def_offset2..], c2);
- let value_pair = &c1list[value_pair_size * c2..];
- let x_adv1 = get_xadvance(value_pair, value_format1);
- if x_adv1 != 0 {
- // Add a kerning pair for each combination of glyphs in each of the classes
- for g2 in glyph2 {
- let key = (g as u16, g2 as u16);
- kernings.insert(key, x_adv1);
- }
- }
- }
- }
- }
- }
- fn process_pair_adjustment_format1(sub_table: &[u8], kernings: &mut Map<(u16, u16), i16>) {
- // Defines kerning between two individual glyphs
- let coverage_offset = get(sub_table, 2);
- let value_format1 = get(sub_table, 4);
- assert_eq!(value_format1, 4); // TODO: Must support others
- let value_format2 = get(sub_table, 6);
- assert_eq!(value_format2, 0); // TODO: Must support others
- let pair_set_count = get(sub_table, 8);
- let value_pair_size = get_size_of_value_type(value_format1) + get_size_of_value_type(value_format2);
- // The first glyph id in the pair is found in the coverage table
- // The second glyph id in the pair is found in the PairSet records
- let coverage = &sub_table[coverage_offset..];
- let coverage_format = get(coverage, 0);
- if coverage_format == 1 {
- let glyph_count = get(coverage, 2);
- assert_eq!(glyph_count, pair_set_count);
- for g in 0..glyph_count {
- let glyph_1 = get(coverage, 4 + 2 * g);
- // For each of the glyph ids we need to search the
- // PairSets for the matching kerning pairs
- let pair_set_offset = get(sub_table, 10 + g * 2);
- let pair_set = &sub_table[pair_set_offset..];
- let pair_value_count = get(pair_set, 0);
- for p in 0..pair_value_count {
- let pair_value = &pair_set[2 + p * (2 + value_pair_size)..];
- let glyph_2 = get(pair_value, 0);
- let value = &pair_value[2..];
- let x_adv1 = get_xadvance(value, value_format1);
- if x_adv1 != 0 {
- let key = (glyph_1 as u16, glyph_2 as u16);
- kernings.insert(key, x_adv1);
- }
- }
- }
- } else if coverage_format == 2 {
- let range_count = get(coverage, 2);
- // Expand the ranges into the glyph1 array
- for n in 0..range_count {
- let start = get(coverage, 4 + n * 6);
- let end = get(coverage, 6 + n * 6);
- let start_coverage_index = get(coverage, 8 + n * 6);
- for glyph_1 in start..end {
- let g = start_coverage_index + glyph_1 - start;
- // For each of the glyph ids we need to search the
- // PairSets for the matching kerning pairs
- let pair_set_offset = get(sub_table, 10 + g * 2);
- let pair_set = &sub_table[pair_set_offset..];
- let pair_value_count = get(pair_set, 0);
- for p in 0..pair_value_count {
- let pair_value = &pair_set[2 + p * (2 + value_pair_size)..];
- let glyph_2 = get(pair_value, 0);
- let value = &pair_value[2..];
- let x_adv1 = get_xadvance(value, value_format1);
- if x_adv1 != 0 {
- let key = (glyph_1 as u16, glyph_2 as u16);
- kernings.insert(key, x_adv1);
- }
- }
- }
- }
- } else {
- unreachable!()
- }
- }
- fn get(p: &[u8], i: usize) -> usize {
- BE::read_u16(&p[i..]) as usize
- }
- fn get_xadvance(value: &[u8], value_type: usize) -> i16 {
- if value_type & 4 == 0 {
- return 0;
- }
- let mut offset = 0;
- if value_type & 1 != 0 {
- offset += 2;
- }
- if value_type & 2 != 0 {
- offset += 2;
- }
- get(value, offset) as i16
- }
- fn get_size_of_value_type(value_type: usize) -> usize {
- let mut size = 0;
- let flag = |flag| value_type & flag != 0;
- // TODO: Are these the only flags?
- if flag(1) {
- // x placement
- size += 2;
- }
- if flag(2) {
- // y placement
- size += 2;
- }
- if flag(4) {
- // x advance
- size += 2;
- }
- if flag(8) {
- // y advance
- size += 2;
- }
- if flag(16) {
- // offset to device x placement
- size += 2;
- }
- if flag(32) {
- // offset to device y placement
- size += 2;
- }
- if flag(64) {
- // offset to device x advance
- size += 2;
- }
- if flag(128) {
- // offset to device y advance
- size += 2;
- }
- size
- }
- fn find_table(data: &[u8], fontstart: usize, tag: &[u8]) -> usize {
- let num_tables = BE::read_u16(&data[fontstart + 4..]);
- let tabledir = fontstart + 12;
- for i in 0..num_tables {
- let loc = tabledir + 16 * (i as usize);
- if &data[loc..loc + 4] == tag {
- return BE::read_u32(&data[loc + 8..]) as usize;
- }
- }
- 0
- }
- fn get_class_from_class_def(class_def: &[u8], glyph_id: usize) -> usize {
- // Go through the class def to determine in which class the glyph belongs
- let class_format = get(class_def, 0);
- if class_format == 1 {
- let start_glyph = get(class_def, 2);
- let glyph_count = get(class_def, 4);
- if start_glyph <= glyph_id && glyph_id - start_glyph < glyph_count {
- return get(class_def, 6 + 2 * (glyph_id - start_glyph));
- }
- } else if class_format == 2 {
- let range_count = get(class_def, 2);
- for n in 0..range_count {
- let start = get(class_def, 4 + 6 * n);
- let end = get(class_def, 6 + 6 * n);
- if start <= glyph_id && end >= glyph_id {
- return get(class_def, 8 + 6 * n);
- }
- }
- }
- return 0;
- }
- fn get_glyphs_from_class_def(class_def: &[u8], class_id: usize) -> Vec<u16> {
- // Find the class, and return all the glyphs that are part of it
- let mut glyphs = Vec::new();
- let class_format = get(class_def, 0);
- if class_format == 1 {
- let start_glyph = get(class_def, 2);
- let glyph_count = get(class_def, 4);
- for n in 0..glyph_count {
- if get(class_def, 6 + 2 * n) == class_id {
- let g = start_glyph + n;
- glyphs.push(g as u16);
- }
- }
- } else if class_format == 2 {
- let range_count = get(class_def, 2);
- for n in 0..range_count {
- let start = get(class_def, 4 + 6 * n);
- let end = get(class_def, 6 + 6 * n);
- if get(class_def, 8 + 6 * n) == class_id {
- for g in start..end + 1 {
- glyphs.push(g as u16);
- }
- }
- }
- }
- glyphs
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement