The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

SvgFont.vala in /libbirdfont

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
Circle boundaries heads/master
1 /* 2 Copyright (C) 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 using B; 16 using SvgBird; 17 18 namespace BirdFont { 19 20 class SvgFont : GLib.Object { 21 Font font; 22 double units = 1; 23 double font_advance = 0; 24 25 public SvgFont (Font f) { 26 this.font = f; 27 } 28 29 /** Load svg font from file. */ 30 public void load (string path) { 31 string data; 32 XmlParser xml_parser; 33 try { 34 FileUtils.get_contents (path, out data); 35 xml_parser = new XmlParser (data); 36 parse_svg_font (xml_parser.get_root_tag ()); 37 } catch (GLib.Error e) { 38 warning (e.message); 39 } 40 } 41 42 void parse_svg_font (Tag tag) { 43 foreach (Tag t in tag) { 44 if (t.get_name () == "defs") { 45 parse_svg_font (t); 46 } 47 48 if (t.get_name () == "font") { 49 parse_font_tag (t); 50 parse_svg_font (t); 51 } 52 53 if (t.get_name () == "font-face") { 54 parse_font_limits (t); 55 } 56 57 if (t.get_name () == "hkern") { 58 parse_hkern (t); 59 } 60 61 if (t.get_name () == "glyph") { 62 parse_glyph (t); 63 } 64 } 65 } 66 67 void parse_hkern (Tag tag) { 68 string left = ""; 69 string right = ""; 70 string left_name = ""; 71 string right_name = ""; 72 double kerning = 0; 73 unichar l, r; 74 StringBuilder sl, sr; 75 GlyphRange grr, grl; 76 KerningClasses classes = BirdFont.get_current_font ().get_kerning_classes (); 77 78 foreach (Attribute attr in tag.get_attributes ()) { 79 // left 80 if (attr.get_name () == "u1") { 81 left = attr.get_content (); 82 } 83 84 // right 85 if (attr.get_name () == "u2") { 86 right = attr.get_content (); 87 } 88 89 if (attr.get_name () == "g1") { 90 left_name = attr.get_content (); 91 } 92 93 if (attr.get_name () == "g2") { 94 right_name = attr.get_content (); 95 } 96 97 // kerning 98 if (attr.get_name () == "k") { 99 kerning = double.parse (attr.get_content ()) * units; 100 } 101 } 102 103 // FIXME: ranges and sequences for u1 & u2 + g1 & g2 104 foreach (string lk in left.split (",")) { 105 foreach (string rk in right.split (",")) { 106 l = get_unichar (lk); 107 r = get_unichar (rk); 108 109 sl = new StringBuilder (); 110 sl.append_unichar (l); 111 112 sr = new StringBuilder (); 113 sr.append_unichar (r); 114 115 try { 116 grl = new GlyphRange (); 117 grl.parse_ranges (sl.str); 118 119 grr = new GlyphRange (); 120 grr.parse_ranges (sr.str); 121 122 classes.set_kerning (grl, grr, -kerning); 123 } catch (MarkupError e) { 124 warning (e.message); 125 } 126 } 127 } 128 } 129 130 void parse_font_limits (Tag tag) { 131 double top_limit = 0; 132 double bottom_limit = 0; 133 134 foreach (Attribute attr in tag.get_attributes ()) { 135 if (attr.get_name () == "units-per-em") { 136 units = 100.0 / double.parse (attr.get_content ()); 137 } 138 } 139 140 foreach (Attribute attr in tag.get_attributes ()) { 141 if (attr.get_name () == "ascent") { 142 top_limit = double.parse (attr.get_content ()); 143 } 144 145 if (attr.get_name () == "descent") { 146 bottom_limit = double.parse (attr.get_content ()); 147 } 148 } 149 150 top_limit *= units; 151 bottom_limit *= units; 152 153 font.bottom_limit = bottom_limit; 154 font.top_limit = top_limit; 155 } 156 157 void parse_font_tag (Tag tag) { 158 foreach (Attribute attr in tag.get_attributes ()) { 159 if (attr.get_name () == "horiz-adv-x") { 160 font_advance = double.parse (attr.get_content ()); 161 } 162 163 if (attr.get_name () == "id") { 164 font.set_name (attr.get_content ()); 165 } 166 } 167 } 168 169 /** Obtain unichar value from either a character, a hex representation of 170 * a character or series of characters (f, m or ffi). 171 */ 172 static unichar get_unichar (string val) { 173 string v = val; 174 unichar unicode_value; 175 176 if (val == "&") { 177 return '&'; 178 } 179 180 // TODO: parse ligatures 181 if (v.has_prefix ("&")) { 182 // parse hex value 183 v = v.substring (0, v.index_of (";")); 184 v = v.replace ("&#x", "U+"); 185 v = v.replace (";", ""); 186 unicode_value = Font.to_unichar (v); 187 } else { 188 // obtain unicode value 189 190 if (v.char_count () > 1) { 191 warning ("font contains ligatures"); 192 return '\0'; 193 } 194 195 unicode_value = v.get_char (0); 196 } 197 198 return unicode_value; 199 } 200 201 bool is_ligature (string v) { 202 if (v.has_prefix ("&")) { 203 return false; 204 } 205 206 return v.char_count () > 1; 207 } 208 209 void parse_glyph (Tag tag) { 210 unichar unicode_value = 0; 211 string glyph_name = ""; 212 string svg = ""; 213 Glyph glyph; 214 GlyphCollection glyph_collection; 215 double advance = font_advance; 216 string ligature = ""; 217 SvgParser parser = new SvgParser (); 218 StringBuilder unicode_name; 219 220 parser.set_format (SvgFormat.INKSCAPE); 221 222 foreach (Attribute attr in tag.get_attributes ()) { 223 if (attr.get_name () == "unicode") { 224 unicode_value = get_unichar (attr.get_content ()); 225 226 if (glyph_name == "") { 227 glyph_name = attr.get_content (); 228 } 229 230 if (is_ligature (attr.get_content ())) { 231 ligature = attr.get_content (); 232 } 233 } 234 235 // svg data 236 if (attr.get_name () == "d") { 237 svg = attr.get_content (); 238 } 239 240 if (attr.get_name () == "glyph-name") { 241 glyph_name = attr.get_content (); 242 } 243 244 if (attr.get_name () == "horiz-adv-x") { 245 advance = double.parse (attr.get_content ()); 246 } 247 } 248 249 unicode_name = new StringBuilder (); 250 unicode_name.append_unichar (unicode_value); 251 252 glyph = new Glyph (unicode_name.str, unicode_value); 253 parser.add_path_to_glyph (svg, glyph, true, units); 254 glyph.right_limit = glyph.left_limit + advance * units; 255 256 // FIXME: add svg font ligatures 257 258 glyph_collection = new GlyphCollection (unicode_value, glyph_name); 259 glyph_collection.insert_glyph (glyph, true); 260 261 font.add_glyph_collection (glyph_collection); 262 } 263 } 264 265 } 266