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
Circle boundaries heads/master
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 XmlElement tag = xml_component.get_root (); 58 59 foreach (Selector selector in styles) { 60 if (selector.match_tag (tag, id, css_class, pseudo_class)) { 61 style.apply (selector.style); 62 } 63 } 64 65 if (css_class != null) { 66 foreach (Selector selector in styles) { 67 if (selector.match_class (tag, id, css_class, pseudo_class)) { 68 style.apply (selector.style); 69 } 70 } 71 } 72 73 if (id != null) { 74 foreach (Selector selector in styles) { 75 if (selector.match_id (tag, id, css_class, pseudo_class)) { 76 style.apply (selector.style); 77 } 78 } 79 } 80 81 if (pseudo_class != null) { 82 foreach (Selector selector in styles) { 83 if (selector.match_pseudo_class (tag, id, css_class, pseudo_class)) { 84 style.apply (selector.style); 85 } 86 } 87 } 88 89 SvgStyle.set_style_properties (null, style); 90 91 return style; 92 } 93 94 public void apply_style (XmlElement tag, SvgStyle style, string? pseudo_class) { 95 string? id = null; 96 string? css_class = null; 97 string tag_name = tag.get_name (); 98 99 if (tag.get_name () == "") { 100 warning ("No tag name provided."); 101 102 if (pseudo_class != null) { 103 warning ((!) pseudo_class); 104 } 105 return; 106 } 107 108 foreach (Attribute attribute in tag.get_attributes ()) { 109 string name = attribute.get_name (); 110 111 if (name == "id") { 112 id = attribute.get_content (); 113 } else if (name == "class") { 114 css_class = attribute.get_content (); 115 } 116 } 117 118 SvgStyle new_style = get_style (tag_name, css_class, id, pseudo_class); 119 style.apply (new_style); 120 SvgStyle.set_style_properties (null, style); 121 } 122 123 public void merge (StyleSheet style_sheet) { 124 foreach (Selector selector in style_sheet.styles) { 125 styles.add (selector.copy ()); 126 } 127 } 128 129 public static StyleSheet parse (Defs defs, XmlElement style_tag) { 130 return parse_css_data (defs, style_tag.get_content ()); 131 } 132 133 public static StyleSheet parse_css_data (Defs defs, string css_data) { 134 StyleSheet style_sheet = new StyleSheet (); 135 string css = get_cdata (css_data); 136 style_sheet.css_data = css; 137 css = add_separators (css); 138 css = replace_whitespace (css); 139 140 int index = 0; 141 int start_bracket_length = "{".length; 142 int end_bracket_length = "}".length; 143 int css_length = css.length; 144 145 while (index < css_length) { 146 int style_rules_start = css.index_of ("{", index); 147 int style_rules_end = css.index_of ("}", style_rules_start); 148 149 if (style_rules_start == -1 || style_rules_end == -1) { 150 break; 151 } 152 153 int selector_end = style_rules_start - start_bracket_length; 154 string selectors = css.substring (index, selector_end - index); 155 156 int style_start = style_rules_start + start_bracket_length; 157 int style_end = style_rules_end; 158 string style_rules = css.substring (style_start, style_end - style_start); 159 160 index = style_rules_end + end_bracket_length; 161 SvgStyle style = new SvgStyle.for_properties (defs, style_rules); 162 163 Selector selector = new Selector (selectors, style); 164 style_sheet.styles.add (selector); 165 } 166 167 return style_sheet; 168 } 169 170 public static string get_cdata (string tag_content) { 171 StringBuilder data = new StringBuilder (); 172 173 int index = 0; 174 int cdata_tag_length = "<![CDATA[".length; 175 int cdata_end_tag_length = "]]>".length; 176 int content_length = tag_content.length; 177 178 while (index < content_length) { 179 int cdata_start = tag_content.index_of ("<![CDATA[", index); 180 int cdata_end = tag_content.index_of ("]]>", cdata_start); 181 182 if (cdata_start == -1 || cdata_end == -1) { 183 break; 184 } 185 186 cdata_start += cdata_tag_length; 187 data.append (tag_content.substring (cdata_start, cdata_end - cdata_start)); 188 index = cdata_end + cdata_end_tag_length; 189 } 190 191 if (index < tag_content.length) { 192 data.append (tag_content.substring (index)); 193 } 194 195 return data.str; 196 } 197 198 public static string add_separators (string data) { 199 string style_data = data.replace (">", " > "); 200 style_data = data.replace ("+", " + "); 201 return style_data; 202 } 203 204 public static string replace_whitespace (string data) { 205 string style_data = data.replace ("\n", " "); 206 style_data = style_data.replace ("\r", " "); 207 style_data = style_data.replace ("\t", " "); 208 209 while (style_data.index_of (" ") != -1) { 210 style_data = style_data.replace (" ", " "); 211 } 212 213 return style_data; 214 } 215 } 216 217 } 218