The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

NameTable.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/NameTable.vala.
License and other descriptive fields in TTF fonts
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 public class NameTable : OtfTable { 18 19 public static const uint16 COPYRIGHT_NOTICE = 0; 20 public static const uint16 FONT_NAME = 1; 21 public static const uint16 SUBFAMILY_NAME = 2; 22 public static const uint16 UNIQUE_IDENTIFIER = 3; 23 public static const uint16 FULL_FONT_NAME = 4; // name + subfamily 24 public static const uint16 VERSION = 5; 25 public static const uint16 POSTSCRIPT_NAME = 6; 26 public static const uint16 TRADE_MARK = 7; 27 public static const uint16 MANUFACTURER = 8; 28 public static const uint16 DESIGNER = 9; 29 public static const uint16 DESCRIPTION = 10; 30 public static const uint16 VENDOR_URL = 11; 31 public static const uint16 DESIGNER_URL = 12; 32 public static const uint16 LICENSE = 13; 33 public static const uint16 LICENSE_URL = 14; 34 public static const uint16 PREFERED_FAMILY = 16; 35 public static const uint16 PREFERED_SUB_FAMILY = 17; 36 37 38 Gee.ArrayList<uint16> identifiers; 39 Gee.ArrayList<string> text; 40 41 public NameTable () { 42 id = "name"; 43 text = new Gee.ArrayList<string> (); 44 identifiers = new Gee.ArrayList<uint16> (); 45 } 46 47 public string get_name (uint16 identifier) { 48 int i = 0; 49 50 foreach (uint16 n in identifiers) { 51 if (n == identifier) { 52 return text.get (i); 53 } 54 i++; 55 } 56 57 return ""; 58 } 59 60 public override void parse (FontData dis) throws Error { 61 uint16 format; 62 63 dis.seek (offset); 64 65 format = dis.read_ushort (); 66 67 switch (format) { 68 case 0: 69 parse_format0 (dis); 70 break; 71 72 case 1: 73 warning ("name table format 1 is not implemented yet"); 74 break; 75 76 default: 77 warning (@"unknown format $format in name table"); 78 break; 79 } 80 } 81 82 public void parse_format0 (FontData dis) throws Error { 83 uint16 count; 84 uint16 storage_offset; 85 86 Gee.ArrayList<uint16> strlen = new Gee.ArrayList<uint16> (); 87 Gee.ArrayList<uint16> off = new Gee.ArrayList<uint16> (); 88 Gee.ArrayList<uint16> name_id = new Gee.ArrayList<uint16> (); 89 Gee.ArrayList<uint16> encoding_id = new Gee.ArrayList<uint16> (); 90 Gee.ArrayList<uint16> platform = new Gee.ArrayList<uint16> (); 91 Gee.ArrayList<uint16> lang = new Gee.ArrayList<uint16> (); 92 93 count = dis.read_ushort (); 94 storage_offset = dis.read_ushort (); 95 96 for (int i = 0; i < count; i++) { 97 platform.add (dis.read_ushort ()); 98 encoding_id.add (dis.read_ushort ()); 99 lang.add (dis.read_ushort ()); 100 name_id.add (dis.read_ushort ()); 101 strlen.add (dis.read_ushort ()); 102 off.add (dis.read_ushort ()); 103 104 identifiers.add (name_id.get (name_id.size - 1)); 105 } 106 107 int plat; 108 StringBuilder str; 109 for (int i = 0; i < count; i++) { 110 plat = platform.get (i); 111 dis.seek (offset + storage_offset + off.get (i)); 112 str = new StringBuilder (); 113 114 switch (plat) { 115 case 1: 116 for (int j = 0; j < strlen.get (i); j++) { 117 char c = dis.read_char (); 118 str.append_c (c); 119 } 120 break; 121 122 case 3: 123 for (int j = 0; j < strlen.get (i); j += 2) { 124 unichar c; 125 char c0 = dis.read_char (); 126 char c1 = dis.read_char (); 127 128 c = c0 << 8; 129 c += c1; 130 131 str.append_unichar (c); 132 } 133 break; 134 135 default: 136 break; 137 } 138 139 text.add (str.str); 140 } 141 } 142 143 /** Create a valid PostScript name. */ 144 public string validate_ps_name (string s) { 145 return name_validation (s, false); 146 } 147 148 public string validate_name (string s) { 149 return name_validation (s, true); 150 } 151 152 public string name_validation (string s, bool allow_space) { 153 string n; 154 int ccount; 155 unichar c; 156 StringBuilder name = new StringBuilder (); 157 158 n = s; 159 ccount = n.char_count (); 160 // truncate strings longer than 28 characters 161 for (int i = 0; i < ccount && i < 27; i++) { 162 c = n.get_char (n.index_of_nth_char (i)); 163 164 if (allow_space && c == ' ') { 165 name.append_unichar (' '); 166 } else if (is_valid_ps_name_char (c)) { 167 name.append_unichar (c); 168 } else { 169 name.append_unichar ('_'); 170 } 171 } 172 173 return name.str; 174 } 175 176 bool is_valid_ps_name_char (unichar c) { 177 switch (c) { 178 case '[': 179 return false; 180 case ']': 181 return false; 182 case '(': 183 return false; 184 case ')': 185 return false; 186 case '{': 187 return false; 188 case '}': 189 return false; 190 case '<': 191 return false; 192 case '>': 193 return false; 194 case '/': 195 return false; 196 case '%': 197 return false; 198 199 default: 200 break; 201 } 202 203 if (33 <= c <= 126) { 204 return true; 205 } 206 207 return false; 208 } 209 210 public void process () throws GLib.Error { 211 FontData fd = new FontData (); 212 Font font = OpenFontFormatWriter.get_current_font (); 213 uint16 len = 0; 214 string t; 215 uint16 p; 216 uint16 l; 217 uint16 num_records; 218 219 Gee.ArrayList<uint16> type = new Gee.ArrayList<uint16> (); 220 Gee.ArrayList<string> text = new Gee.ArrayList<string> (); 221 222 text.add (font.copyright); 223 type.add (COPYRIGHT_NOTICE); 224 225 text.add (validate_name (font.name)); 226 type.add (FONT_NAME); 227 228 text.add (validate_name (font.subfamily)); 229 type.add (SUBFAMILY_NAME); 230 231 text.add (validate_name (font.unique_identifier)); 232 type.add (UNIQUE_IDENTIFIER); 233 234 text.add (validate_name (font.full_name)); 235 type.add (FULL_FONT_NAME); 236 237 text.add (font.version); 238 type.add (VERSION); 239 240 text.add (validate_ps_name (font.postscript_name)); 241 type.add (POSTSCRIPT_NAME); 242 243 text.add (validate_ps_name (font.trademark)); 244 type.add (TRADE_MARK); 245 246 text.add (validate_ps_name (font.manufacturer)); 247 type.add (MANUFACTURER); 248 249 text.add (validate_ps_name (font.designer)); 250 type.add (DESIGNER); 251 252 text.add (font.description); 253 type.add (DESCRIPTION); 254 255 text.add (font.vendor_url); 256 type.add (VENDOR_URL); 257 258 text.add (font.designer_url); 259 type.add (DESIGNER_URL); 260 261 text.add (font.license); 262 type.add (LICENSE); 263 264 text.add (font.license_url); 265 type.add (LICENSE_URL); 266 267 text.add (validate_name (font.name)); 268 type.add (PREFERED_FAMILY); 269 270 text.add (validate_name (font.subfamily)); 271 type.add (PREFERED_SUB_FAMILY); 272 273 num_records = (uint16) text.size; 274 275 fd.add_ushort (0); // format 1 276 fd.add_ushort (2 * num_records); // nplatforms * nrecords 277 fd.add_ushort (6 + 12 * 2 * num_records); // string storage offset 278 279 for (int i = 0; i < num_records; i++) { 280 t = (!) text.get (i); 281 p = (!) type.get (i); 282 l = (uint16) FontData.macroman_strlen (t); 283 284 fd.add_ushort (1); // platform 285 fd.add_ushort (0); // encoding id 286 fd.add_ushort (0); // language 287 fd.add_ushort (p); // name id 288 fd.add_ushort (l); // strlen 289 fd.add_ushort (len); // offset from beginning of string storage 290 len += l; 291 } 292 293 for (int i = 0; i < num_records; i++) { 294 t = (!) text.get (i); 295 p = (!) type.get (i); 296 l = (uint16) FontData.utf16_strlen (t); 297 298 fd.add_ushort (3); // platform 299 fd.add_ushort (1); // encoding id 300 fd.add_ushort (0x0409); // language 301 fd.add_ushort (p); // name id 302 fd.add_ushort (l); // strlen 303 fd.add_ushort (len); // offset from beginning of string storage 304 len += l; 305 } 306 307 // platform 1 308 foreach (string s in text) { 309 fd.add_macroman_str (s); 310 } 311 312 // platform 3 313 foreach (string s in text) { 314 fd.add_str_utf16 (s); 315 } 316 317 fd.pad (); 318 319 this.font_data = fd; 320 } 321 } 322 323 } 324