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 if (is_valid_ps_name_char (c) || (allow_space && c == ' ')) { 156 name.append_unichar (c); 157 } else { 158 name.append_unichar ('_'); 159 } 160 } 161 162 return name.str; 163 } 164 165 bool is_valid_ps_name_char (unichar c) { 166 switch (c) { 167 case '[': 168 return false; 169 case ']': 170 return false; 171 case '(': 172 return false; 173 case ')': 174 return false; 175 case '{': 176 return false; 177 case '}': 178 return false; 179 case '<': 180 return false; 181 case '>': 182 return false; 183 case '/': 184 return false; 185 case '%': 186 return false; 187 188 default: 189 break; 190 } 191 192 if (33 <= c <= 126) { 193 return true; 194 } 195 196 return false; 197 } 198 199 public void process () throws GLib.Error { 200 FontData fd = new FontData (); 201 Font font = OpenFontFormatWriter.get_current_font (); 202 uint16 len = 0; 203 string t; 204 uint16 p; 205 uint16 l; 206 uint16 num_records; 207 208 Gee.ArrayList<uint16> type = new Gee.ArrayList<uint16> (); 209 Gee.ArrayList<string> text = new Gee.ArrayList<string> (); 210 211 text.add (font.copyright); 212 type.add (COPYRIGHT_NOTICE); 213 214 text.add (validate_name (font.name)); 215 type.add (FONT_NAME); 216 217 text.add (validate_name (font.subfamily)); 218 type.add (SUBFAMILY_NAME); 219 220 text.add (validate_name (font.unique_identifier)); 221 type.add (UNIQUE_IDENTIFIER); 222 223 text.add (validate_name (font.full_name)); 224 type.add (FULL_FONT_NAME); 225 226 text.add (font.version); 227 type.add (VERSION); 228 229 text.add (validate_name (font.postscript_name)); 230 type.add (POSTSCRIPT_NAME); 231 232 text.add (font.description); 233 type.add (DESCRIPTION); 234 235 text.add (validate_ps_name (font.name)); 236 type.add (PREFERED_FAMILY); 237 238 text.add (validate_name (font.subfamily)); 239 type.add (PREFERED_SUB_FAMILY); 240 241 num_records = (uint16) text.size; 242 243 fd.add_ushort (0); // format 1 244 fd.add_ushort (2 * num_records); // nplatforms * nrecords 245 fd.add_ushort (6 + 12 * 2 * num_records); // string storage offset 246 247 for (int i = 0; i < num_records; i++) { 248 t = (!) text.get (i); 249 p = (!) type.get (i); 250 l = (uint16) t.length; 251 252 fd.add_ushort (1); // platform 253 fd.add_ushort (0); // encoding id 254 fd.add_ushort (0); // language 255 fd.add_ushort (p); // name id 256 fd.add_ushort (l); // strlen 257 fd.add_ushort (len); // offset from beginning of string storage 258 len += l; 259 } 260 261 for (int i = 0; i < num_records; i++) { 262 t = (!) text.get (i); 263 p = (!) type.get (i); 264 l = (uint16) (2 * t.char_count ()); // FIXME: handle UTF-16 in a better way, gconvert it. 265 266 fd.add_ushort (3); // platform 267 fd.add_ushort (1); // encoding id 268 fd.add_ushort (0x0409); // language 269 fd.add_ushort (p); // name id 270 fd.add_ushort (l); // strlen 271 fd.add_ushort (len); // offset from beginning of string storage 272 len += l; 273 } 274 275 // platform 1 276 foreach (string s in text) { 277 fd.add_str (s); 278 } 279 280 // platform 3 281 foreach (string s in text) { 282 fd.add_str_utf16 (s); 283 } 284 285 fd.pad (); 286 287 this.font_data = fd; 288 } 289 } 290 291 } 292