Advertisement
Guest User

kerning.rs

a guest
Feb 28th, 2019
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 13.87 KB | None | 0 0
  1. use byteorder::ByteOrder;
  2. use byteorder::BigEndian as BE;
  3. use std::collections::HashMap as Map;
  4.  
  5. pub fn get_kernings(fonts: &[u8], font_index: usize) -> Map<(u16, u16), i16> {
  6.     let kern = find_table(&fonts, font_index, b"kern");
  7.     let gpos = find_table(&fonts, font_index, b"GPOS");
  8.  
  9.     let mut kernings = Map::new();
  10.     if gpos != 0 {
  11.         let gpos = &fonts[gpos..];
  12.         kernings = read_gpos_table(gpos)
  13.     }
  14.     if kern != 0 && kernings.len() == 0 {
  15.         let kern = &fonts[kern..];
  16.         kernings = read_kern_table(kern)
  17.     }
  18.     kernings
  19. }
  20.  
  21. fn read_gpos_table(gpos: &[u8]) -> Map<(u16, u16), i16> {
  22.     let script_list_offset = get(gpos, 4);
  23.     let feature_list_offset = get(gpos, 6);
  24.     let lookup_list_offset = get(gpos, 8);
  25.  
  26.  
  27.     let script_list = &gpos[script_list_offset..];
  28.     let feature_list = &gpos[feature_list_offset..];
  29.     let lookup_list = &gpos[lookup_list_offset..];
  30.  
  31.     // Locate the default script in the script list table
  32.     let script_count = BE::read_u16(script_list) as usize;
  33.  
  34.     let mut offset = 0;
  35.     for c in 0..script_count {
  36.         let script_record = &script_list[2 + c * 6..];
  37.         if &script_record[..4] == b"DFLT" {
  38.             offset = get(script_record, 4);
  39.             break;
  40.         }
  41.     }
  42.  
  43.     let mut kernings = Map::new();
  44.  
  45.     if offset == 0 {
  46.         return kernings;
  47.     }
  48.  
  49.     let script = &script_list[offset..];
  50.     let default_lang_sys_offset = get(script, 0);
  51.     if default_lang_sys_offset == 0 {
  52.         return kernings;
  53.     }
  54.  
  55.     let lang_sys = &script[default_lang_sys_offset..];
  56.     let lookup_order = BE::read_u16(lang_sys);
  57.     assert_eq!(lookup_order, 0); // reserved for future use
  58.     let feature_count = get(lang_sys, 4);
  59.  
  60.     // Find all kerning pairs from all the features that apply
  61.     let all_feature_count = get(feature_list, 0);
  62.     for c in 0..feature_count {
  63.         let feature_index = get(lang_sys, 6 + c * 2);
  64.         if feature_index < all_feature_count {
  65.             let feature_record = &feature_list[2 + 6 * feature_index..];
  66.             if &feature_record[..4] == b"kern" {
  67.                 process_kern_feature(feature_record, feature_list, lookup_list, &mut kernings);
  68.             }
  69.         }
  70.     }
  71.     kernings
  72. }
  73.  
  74. fn read_kern_table(kern: &[u8]) -> Map<(u16, u16), i16> {
  75.     let mut kernings = Map::new();
  76.  
  77.     // we only look at the first table. it must be 'horizontal' and format 0
  78.     if BE::read_u16(&kern[2..]) < 1 || BE::read_u16(&kern[8..]) != 1 {
  79.         // kern not present, OR
  80.         // no tables (need at least one), OR
  81.         // horizontal flag not set in format
  82.         return kernings;
  83.     }
  84.  
  85.     let len = BE::read_u16(&kern[10..]) as usize;
  86.     for i in 0..len {
  87.         let key = BE::read_u32(&kern[18 + i * 6..]);
  88.         let val = BE::read_i16(&kern[22 + i * 6..]);
  89.         let key = unsafe { std::mem::transmute(key) };
  90.         kernings.insert(key, val);
  91.     }
  92.     kernings
  93. }
  94.  
  95. fn process_kern_feature(feature_record: &[u8], feature_list: &[u8],
  96.                         lookup_list: &[u8], kernings: &mut Map<(u16, u16), i16>) {
  97.     let offset = get(feature_record, 4);
  98.     let feature = &feature_list[offset..];
  99.     let lookup_count = get(feature, 2);
  100.     let all_lookup_count = get(lookup_list, 0);
  101.  
  102.     for i in 0..lookup_count {
  103.         let lookup_index = get(feature, 4 + i * 2);
  104.         // Determine the features that apply (look for kerning pairs)
  105.  
  106.         // Find the adjustments in the lookup table
  107.         if lookup_index < all_lookup_count {
  108.             let lookup_offset = get(lookup_list, 2 + lookup_index * 2);
  109.             let lookup = &lookup_list[lookup_offset..];
  110.             let lookup_type = get(lookup, 0);
  111.             let sub_table_count = get(lookup, 4);
  112.  
  113.             for s in 0..sub_table_count {
  114.                 let offset = get(lookup, 6 + s * 2);
  115.                 let mut sub_table = &lookup[offset..];
  116.                 let mut real_lookup_type = lookup_type;
  117.  
  118.                 if lookup_type == 9 {
  119.                     // extension positioning
  120.                     let pos_format = get(sub_table, 0);
  121.                     assert_eq!(pos_format, 1); // reserved
  122.                     let extension_lookup_type = get(sub_table, 2);
  123.                     let extension_offset = BE::read_u32(&sub_table[4..]) as usize;
  124.  
  125.                     real_lookup_type = extension_lookup_type;
  126.                     sub_table = &sub_table[extension_offset..];
  127.                 }
  128.  
  129.                 if real_lookup_type == 2 {
  130.                     // pair adjustment
  131.                     let pos_format = get(sub_table, 0);
  132.                     if pos_format == 1 {
  133.                         process_pair_adjustment_format1(sub_table, kernings);
  134.                     } else if pos_format == 2 {
  135.                         process_pair_adjustment_format2(sub_table, kernings);
  136.                     } else {
  137.                         unreachable!()
  138.                     }
  139.                 }
  140.             }
  141.         }
  142.     }
  143. }
  144.  
  145. fn process_pair_adjustment_format2(sub_table: &[u8], kernings: &mut Map<(u16, u16), i16>) {
  146.     // Defines kerning between two classes of glyphs
  147.  
  148.     let coverage_offset = get(sub_table, 2);
  149.     let value_format1 = get(sub_table, 4);
  150.     assert_eq!(value_format1, 4); // TODO: must support others
  151.     let value_format2 = get(sub_table, 6);
  152.     assert_eq!(value_format2, 0); // TODO: must support others
  153.     let class_def_offset1 = get(sub_table, 8);
  154.     let class_def_offset2 = get(sub_table, 10);
  155.     let class_count1 = get(sub_table, 12);
  156.     let class_count2 = get(sub_table, 14);
  157.  
  158.     let value_pair_size = get_size_of_value_type(value_format1) + get_size_of_value_type(value_format2);
  159.  
  160.     // The first glyph id in the pair is found in the coverage table
  161.     // The second glyph id is determined from the class definitions
  162.  
  163.     let mut glyph1 = Vec::new();
  164.  
  165.     let coverage = &sub_table[coverage_offset..];
  166.     let coverage_format = get(coverage, 0);
  167.  
  168.     if coverage_format == 1 {
  169.         let glyph_count = get(coverage, 2);
  170.         glyph1.reserve(glyph_count);
  171.  
  172.         for g in 0..glyph_count {
  173.             let glyph_id = get(coverage, 4 + 2 * g);
  174.             glyph1.push(glyph_id);
  175.         }
  176.     } else {
  177.         let range_count = get(coverage, 2);
  178.         // Expand the ranges into the glyph1 array
  179.         for n in 0..range_count {
  180.             let start = get(coverage, 4 + n * 6);
  181.             let end = get(coverage, 6 + n * 6);
  182.  
  183.             for g in start..end + 1 {
  184.                 glyph1.push(g);
  185.             }
  186.         }
  187.     }
  188.  
  189.     for g in glyph1 {
  190.         let c1 = get_class_from_class_def(&sub_table[class_def_offset1..], g);
  191.  
  192.         assert!(c1 < class_count1);
  193.  
  194.         if c1 < class_count1 {
  195.             let c1list = &sub_table[16 + c1 * class_count2 * value_pair_size..];
  196.  
  197.             for c2 in 0..class_count2 {
  198.                 // Enumerate the glyphs that are part of the classes
  199.                 let glyph2 = get_glyphs_from_class_def(&sub_table[class_def_offset2..], c2);
  200.  
  201.                 let value_pair = &c1list[value_pair_size * c2..];
  202.  
  203.                 let x_adv1 = get_xadvance(value_pair, value_format1);
  204.                 if x_adv1 != 0 {
  205.                     // Add a kerning pair for each combination of glyphs in each of the classes
  206.                     for g2 in glyph2 {
  207.                         let key = (g as u16, g2 as u16);
  208.                         kernings.insert(key, x_adv1);
  209.                     }
  210.                 }
  211.             }
  212.         }
  213.     }
  214. }
  215.  
  216. fn process_pair_adjustment_format1(sub_table: &[u8], kernings: &mut Map<(u16, u16), i16>) {
  217.     // Defines kerning between two individual glyphs
  218.  
  219.     let coverage_offset = get(sub_table, 2);
  220.     let value_format1 = get(sub_table, 4);
  221.     assert_eq!(value_format1, 4); // TODO: Must support others
  222.     let value_format2 = get(sub_table, 6);
  223.     assert_eq!(value_format2, 0); // TODO: Must support others
  224.     let pair_set_count = get(sub_table, 8);
  225.  
  226.     let value_pair_size = get_size_of_value_type(value_format1) + get_size_of_value_type(value_format2);
  227.  
  228.     // The first glyph id in the pair is found in the coverage table
  229.     // The second glyph id in the pair is found in the PairSet records
  230.  
  231.     let coverage = &sub_table[coverage_offset..];
  232.     let coverage_format = get(coverage, 0);
  233.  
  234.     if coverage_format == 1 {
  235.         let glyph_count = get(coverage, 2);
  236.         assert_eq!(glyph_count, pair_set_count);
  237.  
  238.         for g in 0..glyph_count {
  239.             let glyph_1 = get(coverage, 4 + 2 * g);
  240.  
  241.             // For each of the glyph ids we need to search the
  242.             // PairSets for the matching kerning pairs
  243.             let pair_set_offset = get(sub_table, 10 + g * 2);
  244.             let pair_set = &sub_table[pair_set_offset..];
  245.             let pair_value_count = get(pair_set, 0);
  246.             for p in 0..pair_value_count {
  247.                 let pair_value = &pair_set[2 + p * (2 + value_pair_size)..];
  248.  
  249.                 let glyph_2 = get(pair_value, 0);
  250.                 let value = &pair_value[2..];
  251.                 let x_adv1 = get_xadvance(value, value_format1);
  252.  
  253.                 if x_adv1 != 0 {
  254.                     let key = (glyph_1 as u16, glyph_2 as u16);
  255.                     kernings.insert(key, x_adv1);
  256.                 }
  257.             }
  258.         }
  259.     } else if coverage_format == 2 {
  260.         let range_count = get(coverage, 2);
  261.  
  262.         // Expand the ranges into the glyph1 array
  263.         for n in 0..range_count {
  264.             let start = get(coverage, 4 + n * 6);
  265.             let end = get(coverage, 6 + n * 6);
  266.             let start_coverage_index = get(coverage, 8 + n * 6);
  267.  
  268.             for glyph_1 in start..end {
  269.                 let g = start_coverage_index + glyph_1 - start;
  270.  
  271.                 // For each of the glyph ids we need to search the
  272.                 // PairSets for the matching kerning pairs
  273.                 let pair_set_offset = get(sub_table, 10 + g * 2);
  274.                 let pair_set = &sub_table[pair_set_offset..];
  275.                 let pair_value_count = get(pair_set, 0);
  276.  
  277.                 for p in 0..pair_value_count {
  278.                     let pair_value = &pair_set[2 + p * (2 + value_pair_size)..];
  279.  
  280.                     let glyph_2 = get(pair_value, 0);
  281.                     let value = &pair_value[2..];
  282.                     let x_adv1 = get_xadvance(value, value_format1);
  283.  
  284.                     if x_adv1 != 0 {
  285.                         let key = (glyph_1 as u16, glyph_2 as u16);
  286.                         kernings.insert(key, x_adv1);
  287.                     }
  288.                 }
  289.             }
  290.         }
  291.     } else {
  292.         unreachable!()
  293.     }
  294. }
  295.  
  296. fn get(p: &[u8], i: usize) -> usize {
  297.     BE::read_u16(&p[i..]) as usize
  298. }
  299.  
  300. fn get_xadvance(value: &[u8], value_type: usize) -> i16 {
  301.     if value_type & 4 == 0 {
  302.         return 0;
  303.     }
  304.  
  305.     let mut offset = 0;
  306.     if value_type & 1 != 0 {
  307.         offset += 2;
  308.     }
  309.     if value_type & 2 != 0 {
  310.         offset += 2;
  311.     }
  312.  
  313.     get(value, offset) as i16
  314. }
  315.  
  316. fn get_size_of_value_type(value_type: usize) -> usize {
  317.     let mut size = 0;
  318.  
  319.     let flag = |flag| value_type & flag != 0;
  320.  
  321.     // TODO: Are these the only flags?
  322.     if flag(1) {
  323.         // x placement
  324.         size += 2;
  325.     }
  326.     if flag(2) {
  327.         // y placement
  328.         size += 2;
  329.     }
  330.     if flag(4) {
  331.         // x advance
  332.         size += 2;
  333.     }
  334.     if flag(8) {
  335.         // y advance
  336.         size += 2;
  337.     }
  338.     if flag(16) {
  339.         // offset to device x placement
  340.         size += 2;
  341.     }
  342.     if flag(32) {
  343.         // offset to device y placement
  344.         size += 2;
  345.     }
  346.     if flag(64) {
  347.         // offset to device x advance
  348.         size += 2;
  349.     }
  350.     if flag(128) {
  351.         // offset to device y advance
  352.         size += 2;
  353.     }
  354.     size
  355. }
  356.  
  357. fn find_table(data: &[u8], fontstart: usize, tag: &[u8]) -> usize {
  358.     let num_tables = BE::read_u16(&data[fontstart + 4..]);
  359.     let tabledir = fontstart + 12;
  360.     for i in 0..num_tables {
  361.         let loc = tabledir + 16 * (i as usize);
  362.         if &data[loc..loc + 4] == tag {
  363.             return BE::read_u32(&data[loc + 8..]) as usize;
  364.         }
  365.     }
  366.     0
  367. }
  368.  
  369.  
  370. fn get_class_from_class_def(class_def: &[u8], glyph_id: usize) -> usize {
  371.     // Go through the class def to determine in which class the glyph belongs
  372.     let class_format = get(class_def, 0);
  373.     if class_format == 1 {
  374.         let start_glyph = get(class_def, 2);
  375.         let glyph_count = get(class_def, 4);
  376.  
  377.         if start_glyph <= glyph_id && glyph_id - start_glyph < glyph_count {
  378.             return get(class_def, 6 + 2 * (glyph_id - start_glyph));
  379.         }
  380.     } else if class_format == 2 {
  381.         let range_count = get(class_def, 2);
  382.         for n in 0..range_count {
  383.             let start = get(class_def, 4 + 6 * n);
  384.             let end = get(class_def, 6 + 6 * n);
  385.             if start <= glyph_id && end >= glyph_id {
  386.                 return get(class_def, 8 + 6 * n);
  387.             }
  388.         }
  389.     }
  390.  
  391.     return 0;
  392. }
  393.  
  394.  
  395. fn get_glyphs_from_class_def(class_def: &[u8], class_id: usize) -> Vec<u16> {
  396.     // Find the class, and return all the glyphs that are part of it
  397.     let mut glyphs = Vec::new();
  398.  
  399.     let class_format = get(class_def, 0);
  400.     if class_format == 1 {
  401.         let start_glyph = get(class_def, 2);
  402.         let glyph_count = get(class_def, 4);
  403.  
  404.         for n in 0..glyph_count {
  405.             if get(class_def, 6 + 2 * n) == class_id {
  406.                 let g = start_glyph + n;
  407.                 glyphs.push(g as u16);
  408.             }
  409.         }
  410.     } else if class_format == 2 {
  411.         let range_count = get(class_def, 2);
  412.         for n in 0..range_count {
  413.             let start = get(class_def, 4 + 6 * n);
  414.             let end = get(class_def, 6 + 6 * n);
  415.             if get(class_def, 8 + 6 * n) == class_id {
  416.                 for g in start..end + 1 {
  417.                     glyphs.push(g as u16);
  418.                 }
  419.             }
  420.         }
  421.     }
  422.  
  423.     glyphs
  424. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement