The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

SelectorPattern.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 CSS selector pattern. */ 21 public class SelectorPattern : GLib.Object { 22 Gee.ArrayList<SelectorTag> tags = new Gee.ArrayList<SelectorTag> (); 23 24 public SelectorPattern.empty () { 25 } 26 27 public SelectorPattern (string pattern) { 28 string p = pattern.strip (); 29 string[] elements = p.split (" "); 30 31 foreach (string element in elements) { 32 if (element != "") { 33 tags.add (new SelectorTag (element)); 34 } 35 } 36 } 37 38 public SelectorPattern get_id_patterns () { 39 SelectorPattern pattern = new SelectorPattern.empty (); 40 foreach (SelectorTag tag in tags) { 41 if (tag.id != null) { 42 pattern.tags.add (tag); 43 } 44 } 45 return pattern; 46 } 47 48 public SelectorPattern get_class_patterns () { 49 SelectorPattern pattern = new SelectorPattern.empty (); 50 foreach (SelectorTag tag in tags) { 51 if (tag.css_class != null) { 52 pattern.tags.add (tag); 53 } 54 } 55 return pattern; 56 } 57 58 public SelectorPattern get_pseudo_class_patterns () { 59 SelectorPattern pattern = new SelectorPattern.empty (); 60 foreach (SelectorTag tag in tags) { 61 if (tag.pseudo_class != null) { 62 pattern.tags.add (tag); 63 } 64 } 65 return pattern; 66 } 67 68 public bool has_id () { 69 foreach (SelectorTag tag in tags) { 70 if (tag.id != null) { 71 return true; 72 } 73 } 74 75 return false; 76 } 77 78 public bool has_class () { 79 foreach (SelectorTag tag in tags) { 80 if (tag.css_class != null) { 81 return true; 82 } 83 } 84 85 return false; 86 } 87 88 public bool has_pseudo_class () { 89 foreach (SelectorTag tag in tags) { 90 if (tag.pseudo_class != null) { 91 return true; 92 } 93 } 94 95 return false; 96 } 97 98 public string to_string () { 99 StringBuilder s = new StringBuilder (); 100 101 foreach (SelectorTag tag in tags) { 102 if (s.str != "") { 103 s.append (" "); 104 } 105 106 s.append (tag.to_string ()); 107 } 108 109 return s.str; 110 } 111 public SelectorPattern copy () { 112 SelectorPattern pattern = new SelectorPattern.empty (); 113 114 foreach (SelectorTag tag in tags) { 115 pattern.tags.add (tag.copy ()); 116 } 117 118 return pattern; 119 } 120 121 public bool match (XmlElement tag, string? id, string? css_class, string? pseudo_class) { 122 if (tag.get_name () == "") { 123 return false; 124 } 125 126 for (int i = tags.size - 1; i >= 0; i--) { 127 SelectorTag pattern = tags.get (i); 128 129 if (pattern.name == ">") { 130 if (i - 1 < 0) { 131 return false; 132 } 133 134 string parent = tags.get (i - 1).name; 135 136 if (!has_parent (tag, parent)) { 137 return false; 138 } 139 } else if (pattern.name == "+") { 140 if (i - 1 < 0) { 141 return false; 142 } 143 144 string previous = tags.get (i - 1).name; 145 146 if (!is_immediately_following (tag, previous)) { 147 return false; 148 } 149 } 150 151 if (!pattern.match (tag, id, css_class, pseudo_class)) { 152 return false; 153 } 154 } 155 156 return true; 157 } 158 159 public bool is_immediately_following (XmlElement tag, string previous) { 160 return get_previous (tag) == tag; 161 } 162 163 XmlElement? get_previous (XmlElement? xml_parent) { 164 if (xml_parent == null) { 165 return null; 166 } 167 168 XmlElement element = (!) xml_parent; 169 XmlElement? parent = element.get_parent (); 170 171 if (parent != null) { 172 XmlElement? previous = null; 173 174 foreach (XmlElement e in (!) parent) { 175 if (e == xml_parent) { 176 return previous; 177 } 178 179 previous = e; 180 } 181 } 182 183 return null; 184 } 185 186 public bool has_parent (XmlElement tag, string parent) { 187 XmlElement? xml_parent = tag.get_parent (); 188 189 while (xml_parent != null) { 190 if (((!) xml_parent).get_name () == parent) { 191 return true; 192 } 193 194 xml_parent = tag.get_parent (); 195 } 196 197 return false; 198 } 199 } 200 201 } 202