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

Revisions

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