The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

StyleSheet.vala in libsvgbird

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 libsvgbird/StyleSheet.vala.
SVG M instruction
1 /* 2 Copyright (C) 2016 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 Math; 17 18 namespace SvgBird { 19 20 21 public class StyleSheet : GLib.Object { 22 23 public string css_data { get; set; default = ""; } 24 public Gee.ArrayList<Selector> styles = new Gee.ArrayList<Selector> (); 25 26 public StyleSheet () { 27 } 28 29 /** Copy references to all selectors in this style sheet. */ 30 public StyleSheet shallow_copy () { 31 StyleSheet style_sheet = new StyleSheet (); 32 33 foreach (Selector selector in styles) { 34 style_sheet.styles.add (selector); 35 } 36 37 return style_sheet; 38 } 39 40 public StyleSheet copy () { 41 StyleSheet style_sheet = new StyleSheet (); 42 43 foreach (Selector selector in styles) { 44 style_sheet.styles.add (selector.copy ()); 45 } 46 47 return style_sheet; 48 } 49 50 public SvgStyle get_style (string tag_name, string? css_class = null, 51 string? id = null, string? pseudo_class = null) { 52 53 SvgStyle style = new SvgStyle (); 54 55 string xml = @"<$(tag_name) />"; 56 XmlTree xml_component = new XmlTree (xml); 57 58 if (!xml_component.validate ()) { 59 warning (@"Bad tag: $xml"); 60 warning (xml); 61 } 62 63 XmlElement tag = xml_component.get_root (); 64 65 foreach (Selector selector in styles) { 66 if (selector.match_tag (tag, id, css_class, pseudo_class)) { 67 style.apply (selector.style); 68 } 69 } 70 71 if (css_class != null) { 72 foreach (Selector selector in styles) { 73 if (selector.match_class (tag, id, css_class, pseudo_class)) { 74 style.apply (selector.style); 75 } 76 } 77 } 78 79 if (id != null) { 80 foreach (Selector selector in styles) { 81 if (selector.match_id (tag, id, css_class, pseudo_class)) { 82 style.apply (selector.style); 83 } 84 } 85 } 86 87 if (pseudo_class != null) { 88 foreach (Selector selector in styles) { 89 if (selector.match_pseudo_class (tag, id, css_class, pseudo_class)) { 90 style.apply (selector.style); 91 } 92 } 93 } 94 95 SvgStyle.set_style_properties (null, style); 96 97 return style; 98 } 99 100 public void apply_style (XmlElement tag, SvgStyle style, string? pseudo_class) { 101 string? id = null; 102 string? css_class = null; 103 string tag_name = tag.get_name (); 104 105 if (tag.get_name () == "") { 106 warning ("No tag name provided."); 107 108 if (pseudo_class != null) { 109 warning ((!) pseudo_class); 110 } 111 return; 112 } 113 114 foreach (Attribute attribute in tag.get_attributes ()) { 115 string name = attribute.get_name (); 116 117 if (name == "id") { 118 id = attribute.get_content (); 119 } else if (name == "class") { 120 css_class = attribute.get_content (); 121 } 122 } 123 124 SvgStyle new_style = get_style (tag_name, css_class, id, pseudo_class); 125 style.apply (new_style); 126 SvgStyle.set_style_properties (null, style); 127 } 128 129 public void merge (StyleSheet style_sheet) { 130 foreach (Selector selector in style_sheet.styles) { 131 styles.add (selector.copy ()); 132 } 133 } 134 135 public static StyleSheet parse (Defs defs, XmlElement style_tag) { 136 return parse_css_data (defs, style_tag.get_content ()); 137 } 138 139 public static StyleSheet parse_css_data (Defs defs, string css_data) { 140 StyleSheet style_sheet = new StyleSheet (); 141 string css = get_cdata (css_data); 142 style_sheet.css_data = css; 143 css = add_separators (css); 144 css = replace_whitespace (css); 145 146 int index = 0; 147 int start_bracket_length = "{".length; 148 int end_bracket_length = "}".length; 149 int css_length = css.length; 150 151 while (index < css_length) { 152 int style_rules_start = css.index_of ("{", index); 153 int style_rules_end = css.index_of ("}", style_rules_start); 154 155 if (style_rules_start == -1 || style_rules_end == -1) { 156 break; 157 } 158 159 int selector_end = style_rules_start - start_bracket_length; 160 string selectors = css.substring (index, selector_end - index); 161 162 int style_start = style_rules_start + start_bracket_length; 163 int style_end = style_rules_end; 164 string style_rules = css.substring (style_start, style_end - style_start); 165 166 index = style_rules_end + end_bracket_length; 167 SvgStyle style = new SvgStyle.for_properties (defs, style_rules); 168 169 Selector selector = new Selector (selectors, style); 170 style_sheet.styles.add (selector); 171 } 172 173 return style_sheet; 174 } 175 176 public static string get_cdata (string tag_content) { 177 StringBuilder data = new StringBuilder (); 178 179 int index = 0; 180 int cdata_tag_length = "<![CDATA[".length; 181 int cdata_end_tag_length = "]]>".length; 182 int content_length = tag_content.length; 183 184 while (index < content_length) { 185 int cdata_start = tag_content.index_of ("<![CDATA[", index); 186 int cdata_end = tag_content.index_of ("]]>", cdata_start); 187 188 if (cdata_start == -1 || cdata_end == -1) { 189 break; 190 } 191 192 cdata_start += cdata_tag_length; 193 data.append (tag_content.substring (cdata_start, cdata_end - cdata_start)); 194 index = cdata_end + cdata_end_tag_length; 195 } 196 197 if (index < tag_content.length) { 198 data.append (tag_content.substring (index)); 199 } 200 201 return data.str; 202 } 203 204 public static string add_separators (string data) { 205 string style_data = data.replace (">", " > "); 206 style_data = data.replace ("+", " + "); 207 return style_data; 208 } 209 210 public static string replace_whitespace (string data) { 211 string style_data = data.replace ("\n", " "); 212 style_data = style_data.replace ("\r", " "); 213 style_data = style_data.replace ("\t", " "); 214 215 while (style_data.index_of (" ") != -1) { 216 style_data = style_data.replace (" ", " "); 217 } 218 219 return style_data; 220 } 221 } 222 223 } 224