The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

CmapSubtableFormat4.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/CmapSubtableFormat4.vala.
Fix compile time error
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 15 namespace BirdFont { 16 17 /** Format 4 cmap subtable */ 18 public class CmapSubtableFormat4 : GLib.Object { 19 public uint32 offset; 20 uint16 format = 0; 21 HashTable <uint64?, unichar> table = new HashTable <uint64?, unichar> (int64_hash, int_equal); 22 23 uint16 length = 0; 24 25 public CmapSubtableFormat4 () { 26 } 27 28 public uint get_length () { 29 return table.size (); 30 } 31 32 public unichar get_char (uint32 indice) { 33 int64? c = table.lookup (indice); 34 35 if (c == 0 && indice == 0) { 36 return 0; 37 } 38 39 if (c == 0) { 40 while (table.lookup (--indice) == 0) { 41 if (indice == 0) { 42 return 0; 43 } 44 } 45 46 warning (@"There is no character for glyph number $indice in cmap table. table.size: $(table.size ()))"); 47 return 0; 48 } 49 50 return (unichar) c; 51 } 52 53 public void parse (FontData dis) throws GLib.Error { 54 dis.seek (offset); 55 56 format = dis.read_ushort (); 57 58 switch (format) { 59 case 4: 60 parse_format4 (dis); 61 break; 62 63 default: 64 stderr.printf (@"CmapSubtable is in format $format, it is not supportet (yet).\n"); 65 break; 66 } 67 } 68 69 public void parse_format4 (FontData dis) throws GLib.Error { 70 uint16 lang; 71 uint16 seg_count_x2; 72 uint16 seg_count; 73 uint16 search_range; 74 uint16 entry_selector; 75 uint16 range_shift; 76 77 uint16* end_char = null; 78 uint16* start_char = null; 79 int16* id_delta = null; 80 uint16* id_range_offset = null; 81 uint16* glyph_id_array = null; 82 83 uint32 gid_len; 84 85 length = dis.read_ushort (); 86 lang = dis.read_ushort (); 87 seg_count_x2 = dis.read_ushort (); 88 search_range = dis.read_ushort (); 89 entry_selector = dis.read_ushort (); 90 range_shift = dis.read_ushort (); 91 92 return_if_fail (seg_count_x2 % 2 == 0); 93 94 seg_count = seg_count_x2 / 2; 95 96 end_char = new uint16[seg_count]; 97 for (int i = 0; i < seg_count; i++) { 98 end_char[i] = dis.read_ushort (); 99 } 100 101 if (end_char[seg_count - 1] != 0xFFFF) { 102 warning ("end_char is $(end_char[seg_count - 1]), expecting 0xFFFF."); 103 } 104 105 dis.read_ushort (); // Reserved 106 107 start_char = new uint16[seg_count]; 108 for (int i = 0; i < seg_count; i++) { 109 start_char[i] = dis.read_ushort (); 110 } 111 112 id_delta = new int16[seg_count]; 113 for (int i = 0; i < seg_count; i++) { 114 id_delta[i] = dis.read_short (); 115 } 116 117 id_range_offset = new uint16[seg_count]; 118 for (int i = 0; i < seg_count; i++) { 119 id_range_offset[i] = dis.read_ushort (); 120 } 121 122 if (length == 0) { 123 warning ("cmap subtable version 4 has length 0."); 124 return; 125 } 126 127 gid_len = (length - 16 - 8 * seg_count) / 2; 128 glyph_id_array = new uint16[gid_len]; 129 for (int i = 0; i < gid_len; i++) { 130 glyph_id_array[i] = dis.read_ushort (); 131 } 132 133 // map all values in a hashtable 134 int indice = 0; 135 unichar character = 0; 136 uint32 id; 137 for (uint16 i = 0; i < seg_count && start_char[i] != 0xFFFF; i++) { 138 139 // print_range (start_char[i], end_char[i], id_delta[i], id_range_offset[i]); 140 141 uint16 j = 0; 142 do { 143 character = start_char[i] + j; 144 indice = start_char[i] + id_delta[i] + j; 145 146 if (id_range_offset[i] == 0) { 147 table.insert (indice, character); 148 } else { 149 // the indexing trick: 150 id = id_range_offset[i] / 2 + j + i - seg_count; 151 152 if (!(0 <= id < gid_len)) { 153 warning (@"(0 <= id < gid_len) (0 <= $id < $gid_len)"); 154 break; 155 } 156 157 indice = glyph_id_array [id] + id_delta[i]; 158 159 StringBuilder s = new StringBuilder (); 160 s.append_unichar (character); 161 162 table.insert (indice, character); 163 } 164 165 j++; 166 } while (character != end_char[i]); 167 168 } 169 170 if (end_char != null) delete end_char; 171 if (start_char != null) delete start_char; 172 if (id_delta != null) delete id_delta; 173 if (id_range_offset != null) delete id_range_offset; 174 if (glyph_id_array != null) delete glyph_id_array; 175 } 176 177 public FontData get_cmap_data (GlyfTable glyf_table) throws GLib.Error { 178 FontData fd = new FontData (); 179 GlyphRange glyph_range = new GlyphRange (); 180 Gee.ArrayList<UniRange> ranges; 181 182 uint16 seg_count_2; 183 uint16 seg_count; 184 uint16 search_range; 185 uint16 entry_selector; 186 uint16 range_shift; 187 188 uint16 gid_length = 0; 189 190 uint32 indice; 191 uint32 first_assigned = 1 + glyf_table.number_of_unassigned_glyphs; 192 193 foreach (GlyphCollection g in glyf_table.glyphs) { 194 if (!g.is_unassigned () && g.get_unicode_character () < 0xFFFF) { 195 glyph_range.add_single (g.get_unicode_character ()); 196 } 197 } 198 199 ranges = glyph_range.get_ranges (); 200 seg_count = (uint16) ranges.size + 1; 201 seg_count_2 = seg_count * 2; 202 search_range = 2 * largest_pow2 (seg_count); 203 entry_selector = largest_pow2_exponent (seg_count); 204 range_shift = seg_count_2 - search_range; 205 206 // format 207 fd.add_ushort (4); 208 209 // length of subtable 210 fd.add_ushort (16 + 8 * seg_count + gid_length); 211 212 // language 213 fd.add_ushort (0); 214 215 fd.add_ushort (seg_count_2); 216 fd.add_ushort (search_range); 217 fd.add_ushort (entry_selector); 218 fd.add_ushort (range_shift); 219 220 // end codes 221 indice = first_assigned; 222 foreach (UniRange u in ranges) { 223 if (u.stop >= 0xFFFF) { 224 warning ("Not implemented yet."); 225 } else { 226 fd.add_ushort ((uint16) u.stop); 227 indice += u.length (); 228 } 229 } 230 fd.add_ushort (0xFFFF); 231 232 fd.add_ushort (0); // Reserved 233 234 // start codes 235 indice = first_assigned; // since first glyph are notdef, null and nonmarkingreturn 236 foreach (UniRange u in ranges) { 237 if (u.start >= 0xFFFF) { 238 warning ("Not implemented yet."); 239 } else { 240 fd.add_ushort ((uint16) u.start); 241 indice += u.length (); 242 } 243 } 244 fd.add_ushort (0xFFFF); 245 246 // delta 247 indice = first_assigned; 248 foreach (UniRange u in ranges) { 249 if ((u.start - indice) > 0xFFFF && u.start > indice) { 250 warning ("Need range offset."); 251 } else { 252 fd.add_ushort ((uint16) (indice - u.start)); 253 indice += u.length (); 254 } 255 } 256 fd.add_ushort (1); 257 258 // range offset 259 foreach (UniRange u in ranges) { 260 if (u.stop <= 0xFFFF) { 261 fd.add_ushort (0); 262 } else { 263 warning ("Not implemented yet."); 264 } 265 } 266 fd.add_ushort (0); 267 268 // FIXME: implement the rest of type 4 (mind gid_length in length field) 269 270 return fd; 271 } 272 } 273 274 } 275