The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

GposTable.vala in libbirdfont/OpenFontFormat

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/OpenFontFormat/GposTable.vala.
Language fix heads/multimaster
1 /* 2 Copyright (C) 2012, 2013, 2014 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 using Math; 15 16 namespace BirdFont { 17 18 public class GposTable : OtfTable { 19 20 GlyfTable glyf_table; 21 KernList pairs; 22 23 public GposTable () { 24 id = "GPOS"; 25 } 26 27 public override void parse (FontData dis) throws Error { 28 // Not implemented, freetype2 is used for loading fonts 29 } 30 31 public void process (GlyfTable glyf_table) throws GLib.Error { 32 FontData fd = new FontData (); 33 34 this.glyf_table = glyf_table; 35 this.pairs = new KernList (glyf_table); 36 37 printd ("Process GPOS\n"); 38 39 fd.add_ulong (0x00010000); // table version 40 fd.add_ushort (10); // offset to script list 41 fd.add_ushort (30); // offset to feature list 42 fd.add_ushort (44); // offset to lookup list 43 44 // script list ? 45 fd.add_ushort (1); // number of items in script list 46 fd.add_tag ("DFLT"); // default script 47 fd.add_ushort (8); // offset to script table from script list 48 49 // script table 50 fd.add_ushort (4); // offset to default language system 51 fd.add_ushort (0); // number of languages 52 53 // LangSys table 54 fd.add_ushort (0); // reserved 55 fd.add_ushort (0); // required features (0xFFFF is none) 56 fd.add_ushort (1); // number of features 57 fd.add_ushort (0); // feature index 58 59 // feature table 60 fd.add_ushort (1); // number of features 61 62 fd.add_tag ("kern"); // feature tag 63 fd.add_ushort (8); // offset to feature 64 65 fd.add_ushort (0); // feature prameters (null) 66 fd.add_ushort (1); // number of lookups 67 fd.add_ushort (0); // lookup indice 68 69 // lookup table 70 fd.add_ushort (1); // number of lookups 71 fd.add_ushort (4); // offset to lookup 1 72 73 fd.add_ushort (2); // lookup type 74 fd.add_ushort (0); // lookup flags 75 fd.add_ushort (1); // number of subtables 76 fd.add_ushort (8); // array of offsets to subtables 77 78 // MarkFilteringSet 79 80 fd.append (get_pair_pos_format1 ()); 81 82 fd.pad (); 83 this.font_data = fd; 84 } 85 86 uint16 get_max_pairs () { 87 return (uint16) ((uint16.MAX - 10) / 3.0); 88 } 89 90 // PairPosFormat1 subtable 91 FontData get_pair_pos_format1 () throws GLib.Error { 92 FontData fd = new FontData (); 93 uint coverage_offset; 94 uint16 max_pairs_per_table = get_max_pairs (); 95 uint16 num_pairs; 96 int i; 97 uint pair_set_offset; 98 uint written; 99 uint written_pairs; 100 uint last_gid_left; 101 uint last_gid_right; 102 uint16 pair_set_count; 103 104 if (pairs.get_length () == 0) { 105 pairs.fetch_all_pairs (); 106 } 107 108 // FIXME: add another table instead of truncating it 109 if (pairs.get_length () > max_pairs_per_table) { 110 warning (@"Too many kerning pairs. $(pairs.get_length ())"); 111 num_pairs = max_pairs_per_table; 112 } 113 114 num_pairs = (pairs.get_length () < max_pairs_per_table) ? 115 (uint16) pairs.get_length () : max_pairs_per_table; 116 117 pair_set_count = (uint16) pairs.get_length_left (); // FIXME: boundaries 118 119 coverage_offset = 10 + pairs_offset_length () + pairs_set_length (); 120 121 if (coverage_offset > uint16.MAX) { 122 warning (@"Invalid coverage offset. Number of pairs: $(pairs.get_length ())"); 123 num_pairs = 0; 124 coverage_offset = 10; 125 } 126 127 fd.add_ushort (1); // position format 128 // offset to coverage table from beginning of kern pair table 129 fd.add_ushort ((uint16) coverage_offset); 130 fd.add_ushort (0x0004); // ValueFormat1 (0x0004 is x advance) 131 fd.add_ushort (0x0000); // ValueFormat2 (null, no value) 132 fd.add_ushort (pair_set_count); // n pairs 133 134 // pair offsets orderd by coverage index 135 pair_set_offset = 10 + pairs_offset_length (); 136 137 written = 0; 138 written_pairs = 0; 139 pairs.all_pairs_format1 ((k) => { 140 try { 141 if (pair_set_offset > uint16.MAX) { 142 warning ("Invalid offset."); 143 return; 144 } 145 146 if (k.pairs.size == 0) { 147 warning ("No pairs."); 148 } 149 150 fd.add_ushort ((uint16) pair_set_offset); 151 pair_set_offset += 2; 152 pair_set_offset += 4 * k.pairs.size; 153 written += 2; 154 } catch (Error e) { 155 warning (e.message); 156 } 157 }, num_pairs); 158 159 if (unlikely (written != pairs_offset_length ())) { 160 warning (@"Bad pairs_offset_length () calculated: $(pairs_offset_length ()), real length $written"); 161 } 162 163 // pair table 164 i = 0; 165 written = 0; 166 last_gid_left = 0; 167 last_gid_right = 0; 168 pairs.all_pairs_format1 ((pn) => { 169 try { 170 PairFormat1 p = pn; 171 uint pairset_length = p.pairs.size; 172 173 if (pairset_length > uint16.MAX) { 174 warning ("Too many pairs"); 175 pairset_length = uint16.MAX; 176 } 177 178 if (unlikely (p.left < last_gid_left)) { 179 warning (@"Kerning table is not sorted $(p.left) < $last_gid_left."); 180 } 181 182 last_gid_left = p.left; 183 184 fd.add_ushort ((uint16) pairset_length); 185 written += 2; 186 last_gid_right = 0; 187 written_pairs = 0; 188 foreach (Kern k in p.pairs) { 189 190 if (k.right == 0) { 191 warning (@"GID $(p.left) is kerned zero units to $(k.right)."); 192 } 193 194 // pair value record 195 fd.add_ushort (k.right); // gid of the second glyph 196 fd.add_short (k.kerning); // value of ValueFormat1, horizontal adjustment for advance of the first glyph 197 // value of ValueFormat2 (null) 198 199 if (unlikely (k.right < last_gid_right)) { 200 warning (@"Kerning table is not sorted $(k.right) < $last_gid_right)."); 201 } 202 203 last_gid_right = k.right; 204 205 written += 4; 206 written_pairs++; 207 } 208 209 if (unlikely (written_pairs != p.pairs.size)) { 210 warning (@"written_pairs != p.pairs.length () $(written_pairs) != $(pairs.get_length ()) pairset_length: $pairset_length"); 211 } 212 213 i++; 214 } catch (Error e) { 215 warning (e.message); 216 } 217 }, num_pairs); 218 219 if (unlikely (pairs_set_length () != written)) { 220 warning (@"Bad pair set length: $(pairs_set_length ()), real length: $written"); 221 } 222 223 if (unlikely (fd.length () != coverage_offset)) { 224 warning (@"Bad coverage offset, coverage_offset: $coverage_offset, real length: $(fd.length ())"); 225 warning (@"pairs_offset_length: $(pairs_offset_length ()) pairs_set_length: $(pairs_set_length ())"); 226 } 227 228 // coverage 229 fd.add_ushort (1); // format 230 fd.add_ushort (pair_set_count); 231 232 written = 0; 233 pairs.all_pairs_format1 ((p) => { 234 try { 235 fd.add_ushort (p.left); // gid 236 written += 2; 237 } catch (Error e) { 238 warning (e.message); 239 } 240 }, num_pairs); 241 242 if (unlikely (written != 2 * pair_set_count)) { 243 warning ("written != 2 * pair_set_count"); 244 } 245 246 return fd; 247 } 248 249 public uint pairs_set_length () { 250 uint len = 0; 251 252 pairs.all_pairs_format1 ((p) => { 253 len += 2 + 4 * p.pairs.size; 254 }); 255 256 return len; 257 } 258 259 public uint pairs_offset_length () { 260 return 2 * pairs.pairs.size; 261 } 262 } 263 264 } 265