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