The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

SvgTable.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/SvgTable.vala.
Validate XML when importing SVG file
1 /* 2 Copyright (C) 2015 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 public class SvgTable : OtfTable { 20 21 int glyphs_in_table = 0; 22 Gee.ArrayList<SvgTableEntry> entries; 23 24 public SvgTable () { 25 id = "SVG "; 26 entries = new Gee.ArrayList<SvgTableEntry> (); 27 } 28 29 public bool has_glyphs () { 30 return glyphs_in_table > 0; 31 } 32 33 public void process (GlyfTable glyf_table) throws GLib.Error { 34 Font font = OpenFontFormatWriter.get_current_font (); 35 GlyphCollection? glyph_collection; 36 GlyphCollection glyphs; 37 string? svg_data; 38 int gid; 39 40 for (int index = 0; index < font.length (); index++) { 41 glyph_collection = font.get_glyph_collection_index (index); 42 43 if (glyph_collection != null) { 44 glyphs = (!) glyph_collection; 45 svg_data = glyphs.get_current ().color_svg_data; 46 47 if (svg_data != null) { 48 gid = glyf_table.get_gid (glyphs.get_name ()); 49 add_svg_glyph ((!) svg_data, gid, glyphs); 50 glyphs_in_table++; 51 } 52 } 53 } 54 55 process_svg_data (); 56 } 57 58 void add_svg_glyph (string svg_data, int glyph_id, GlyphCollection glyphs) { 59 SvgTableEntry entry; 60 Gee.ArrayList<Tag> layer_content; 61 Gee.ArrayList<Tag> svg_tags; 62 Gee.ArrayList<Tag> meta; 63 XmlParser xml; 64 Tag svg_root_tag; 65 Font font; 66 67 font = OpenFontFormatWriter.get_current_font (); 68 69 layer_content = new Gee.ArrayList<Tag> (); 70 svg_tags = new Gee.ArrayList<Tag> (); 71 meta = new Gee.ArrayList<Tag> (); 72 xml = new XmlParser (svg_data); 73 svg_root_tag = xml.get_root_tag (); 74 75 if (!xml.validate ()) { 76 warning("Invalid SVG data in TTF table."); 77 return; 78 } 79 80 foreach (Tag tag in svg_root_tag) { 81 string name = tag.get_name(); 82 83 if (name == "defs") { 84 svg_tags.add (tag); 85 } else if (name == "style") { 86 svg_tags.add (tag); 87 } else if (name == "metadata") { 88 meta.add (tag); 89 } else if (name == "sodipodi") { 90 meta.add (tag); 91 } else { 92 layer_content.add (tag); 93 } 94 } 95 96 StringBuilder svg = new StringBuilder (); 97 svg.append ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); 98 svg.append ("<"); 99 svg.append (svg_root_tag.get_name ()); 100 svg.append (" "); 101 append_tag_attributes (svg, svg_root_tag); 102 svg.append (">"); 103 104 foreach (Tag tag in svg_tags) { 105 append_tag (svg, tag); 106 } 107 108 svg.append ("\n\n"); 109 svg.append ("<g id="); 110 svg.append ("\""); 111 svg.append ("glyph"); 112 svg.append (@"$glyph_id"); 113 svg.append ("\" "); 114 115 // scale the internal coordinates from 100 units per em to the 116 // number of units per em in this font and move the glyph 117 // in to the em box 118 Glyph glyph = glyphs.get_current (); 119 //FIXME: DELETE double height = font.top_position - font.base_line; 120 double scale = HeadTable.UNITS; 121 double x = glyph.svg_x - glyph.left_limit; 122 double y = -glyph.svg_y; 123 svg.append (@"transform=\"scale($scale) translate($x, $y)\""); 124 125 svg.append (">"); 126 svg.append ("\n\n"); 127 128 foreach (Tag tag in layer_content) { 129 append_tag (svg, tag); 130 } 131 132 svg.append ("\n\n"); 133 svg.append ("</g>"); 134 svg.append ("\n\n"); 135 136 svg.append ("</"); 137 svg.append (svg_root_tag.get_name ()); 138 svg.append (">\n"); 139 140 entry = new SvgTableEntry ((uint16) glyph_id, svg.str); 141 entries.add (entry); 142 } 143 144 public void append_tag (StringBuilder svg, Tag tag) { 145 string content = tag.get_content (); 146 147 svg.append ("<"); 148 svg.append (tag.get_name ()); 149 150 svg.append (" "); 151 append_tag_attributes (svg, tag); 152 153 if (content == "") { 154 svg.append (" /"); 155 } 156 157 svg.append (">"); 158 159 if (content != "") { 160 svg.append (content); 161 svg.append ("</"); 162 svg.append (tag.get_name ()); 163 svg.append (">"); 164 } 165 } 166 167 public void append_tag_attributes (StringBuilder svg, Tag tag) { 168 bool first = true; 169 170 foreach (Attribute attribute in tag.get_attributes ()) { 171 string ns = attribute.get_namespace (); 172 173 if (!first) { 174 svg.append (" "); 175 } 176 177 if (ns != "") { 178 svg.append (ns); 179 svg.append (":"); 180 } 181 182 svg.append (attribute.get_name ()); 183 svg.append ("="); 184 svg.append ("\""); 185 svg.append (attribute.get_content ()); 186 svg.append ("\""); 187 188 first = false; 189 } 190 } 191 192 public void process_svg_data () throws GLib.Error { 193 FontData fd = new FontData (); 194 195 int32 svg_index_offset = 10; 196 197 fd.add_ushort (0); // version 198 fd.add_ulong (svg_index_offset); 199 fd.add_ulong (0); // reserved 200 201 uint32 document_offset = 2 + 12 * entries.size; 202 203 // SVG Documents Index 204 fd.add_ushort ((uint16) entries.size); 205 206 foreach (SvgTableEntry entry in entries) { 207 fd.add_ushort (entry.glyph_id); // start 208 fd.add_ushort (entry.glyph_id); // end 209 fd.add_ulong (document_offset); // offset 210 fd.add_ulong (entry.data.length_with_padding ()); // length 211 212 document_offset += entry.data.length_with_padding (); 213 } 214 215 foreach (SvgTableEntry entry in entries) { 216 fd.append (entry.data); 217 } 218 219 fd.pad (); 220 221 this.font_data = fd; 222 } 223 } 224 225 } 226