The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

SelectorTag.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 /** A part of a CSS selector pattern. */ 21 public class SelectorTag : GLib.Object { 22 public string name; 23 public string? id = null; 24 public string? css_class = null; 25 public string? pseudo_class = null; 26 Gee.ArrayList<AttributePattern>? attribute_patterns = null; 27 28 public SelectorTag.empty () { 29 } 30 31 public SelectorTag (string pattern) { 32 string tag_pattern = pattern.strip (); 33 int attribute_separator = tag_pattern.index_of ("["); 34 35 if (attribute_separator != -1) { 36 parse_attributes (tag_pattern.substring (attribute_separator)); 37 tag_pattern = tag_pattern.substring (0, attribute_separator - "[".length); 38 } 39 40 tag_pattern = create_part (tag_pattern, ":", out pseudo_class); 41 tag_pattern = create_part (tag_pattern, ".", out css_class); 42 tag_pattern = create_part (tag_pattern, "#", out id); 43 name = tag_pattern; 44 } 45 46 string create_part (string tag_pattern, string separator, out string? part) { 47 int separator_index = tag_pattern.index_of (separator); 48 int separator_length = separator.length; 49 50 part = null; 51 52 if (separator_index == -1) { 53 return tag_pattern; 54 } 55 56 if (separator_index > -1 && separator_index + separator_length < tag_pattern.length) { 57 part = tag_pattern.substring (separator_index + separator_length); 58 } 59 60 if (separator_index > separator_length) { 61 return tag_pattern.substring (0, separator_index); 62 } 63 64 return ""; 65 } 66 67 public SelectorTag copy () { 68 SelectorTag tag = new SelectorTag.empty(); 69 70 tag.name = name; 71 tag.id = id; 72 tag.css_class = css_class; 73 tag.pseudo_class = pseudo_class; 74 75 if (attribute_patterns != null) { 76 foreach (AttributePattern p in (!) attribute_patterns) { 77 ((!) attribute_patterns).add (p.copy ()); 78 } 79 } 80 81 return tag; 82 } 83 84 void parse_attributes (string attributes) { 85 int index = 0; 86 Gee.ArrayList<AttributePattern> patterns = new Gee.ArrayList<AttributePattern> (); 87 88 while (index != -1) { 89 int start = attributes.index_of ("[", index); 90 91 if (start == -1) { 92 return; 93 } 94 95 int stop = attributes.index_of ("]", start); 96 97 if (stop == -1) { 98 return; 99 } 100 101 AttributePattern pattern; 102 pattern = parse_attribute (attributes.substring (start, stop)); 103 patterns.add (pattern); 104 105 index = stop + "]".length; 106 } 107 108 attribute_patterns = patterns; 109 } 110 111 AttributePattern parse_attribute (string attribute) { 112 int starts_with = attribute.index_of ("|="); 113 int in_list = attribute.index_of ("~="); 114 int equals = attribute.index_of ("="); 115 AttributePattern pattern = new AttributePattern (); 116 117 if (starts_with != -1) { 118 pattern.name = attribute.substring (0, starts_with); 119 pattern.type = AttributePatternType.STARTS_WITH; 120 pattern.content = attribute.substring (0, equals + "~=".length); 121 } else if (in_list != -1) { 122 pattern.name = attribute.substring (0, in_list); 123 pattern.type = AttributePatternType.LIST; 124 pattern.content = attribute.substring (0, equals + "~=".length); 125 } else if (equals != -1) { 126 pattern.name = attribute.substring (0, equals); 127 pattern.type = AttributePatternType.EQUALS; 128 pattern.content = attribute.substring (0, equals + "=".length); 129 } else { 130 pattern.name = attribute; 131 pattern.type = AttributePatternType.ANYTHING; 132 } 133 134 return pattern; 135 } 136 137 public bool match (XmlElement tag, string? id, string? css_class, string? pseudo_class) { 138 string tag_name = tag.get_name (); 139 140 if (this.name != "*" && this.name != "" && tag_name != "") { 141 if (this.name != tag_name) { 142 return false; 143 } 144 } 145 146 if (this.id != null) { 147 if (id == null) { 148 return false; 149 } 150 151 if (((!) this.id) != ((!) id)) { 152 return false; 153 } 154 } 155 156 if (this.css_class != null) { 157 if (css_class == null) { 158 return false; 159 } 160 161 if (((!) this.css_class) != ((!) css_class)) { 162 return false; 163 } 164 } 165 166 if (this.pseudo_class != null) { 167 if (pseudo_class == null) { 168 return false; 169 } 170 171 if (((!) this.pseudo_class) != ((!) pseudo_class)) { 172 return false; 173 } 174 } 175 176 if (attribute_patterns != null) { 177 foreach (AttributePattern pattern in (!) attribute_patterns) { 178 if (!pattern.match (tag.get_attributes ())) { 179 return false; 180 } 181 } 182 } 183 184 return true; 185 } 186 187 public string to_string () { 188 StringBuilder s = new StringBuilder (); 189 s.append ((!) name); 190 191 if (id != null) { 192 s.append ("#"); 193 s.append ((!) id); 194 } 195 196 if (css_class != null) { 197 s.append ("."); 198 s.append ((!) css_class); 199 } 200 201 if (pseudo_class != null) { 202 s.append (":"); 203 s.append ((!) pseudo_class); 204 } 205 206 if (attribute_patterns != null) { 207 foreach (AttributePattern a in (!) attribute_patterns) { 208 s.append (a.to_string ()); 209 } 210 } 211 212 return s.str; 213 } 214 } 215 216 } 217