Cogs.Core
css_selector.cpp
1#include "html.h"
2#include "css_selector.h"
3#include "document.h"
4
5void litehtml::css_element_selector::parse( const tstring& txt )
6{
7 tstring::size_type el_end = txt.find_first_of(_t(".#[:"));
8 m_tag = txt.substr(0, el_end);
9 litehtml::lcase(m_tag);
10 m_attrs.clear();
11 while(el_end != tstring::npos)
12 {
13 if(txt[el_end] == _t('.'))
14 {
15 css_attribute_selector attribute;
16
17 tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
18 attribute.val = txt.substr(el_end + 1, pos - el_end - 1);
19 split_string( attribute.val, attribute.class_val, _t(" ") );
20 attribute.condition = select_equal;
21 attribute.attribute = _t("class");
22 m_attrs.push_back(attribute);
23 el_end = pos;
24 } else if(txt[el_end] == _t(':'))
25 {
26 css_attribute_selector attribute;
27
28 if(txt[el_end + 1] == _t(':'))
29 {
30 tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);
31 attribute.val = txt.substr(el_end + 2, pos - el_end - 2);
32 attribute.condition = select_pseudo_element;
33 litehtml::lcase(attribute.val);
34 attribute.attribute = _t("pseudo-el");
35 m_attrs.push_back(attribute);
36 el_end = pos;
37 } else
38 {
39 tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);
40 if(pos != tstring::npos && txt.at(pos) == _t('('))
41 {
42 pos = find_close_bracket(txt, pos);
43 if(pos != tstring::npos)
44 {
45 pos++;
46 } else
47 {
48 int iii = 0;
49 iii++;
50 }
51 }
52 if(pos != tstring::npos)
53 {
54 attribute.val = txt.substr(el_end + 1, pos - el_end - 1);
55 } else
56 {
57 attribute.val = txt.substr(el_end + 1);
58 }
59 litehtml::lcase(attribute.val);
60 if(attribute.val == _t("after") || attribute.val == _t("before"))
61 {
62 attribute.condition = select_pseudo_element;
63 } else
64 {
65 attribute.condition = select_pseudo_class;
66 }
67 attribute.attribute = _t("pseudo");
68 m_attrs.push_back(attribute);
69 el_end = pos;
70 }
71 } else if(txt[el_end] == _t('#'))
72 {
73 css_attribute_selector attribute;
74
75 tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
76 attribute.val = txt.substr(el_end + 1, pos - el_end - 1);
77 attribute.condition = select_equal;
78 attribute.attribute = _t("id");
79 m_attrs.push_back(attribute);
80 el_end = pos;
81 } else if(txt[el_end] == _t('['))
82 {
83 css_attribute_selector attribute;
84
85 tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);
86 tstring attr = txt.substr(el_end + 1, pos - el_end - 1);
87 trim(attr);
88 litehtml::lcase(attr);
89 if(pos != tstring::npos)
90 {
91 if(txt[pos] == _t(']'))
92 {
93 attribute.condition = select_exists;
94 } else if(txt[pos] == _t('='))
95 {
96 attribute.condition = select_equal;
97 pos++;
98 } else if(txt.substr(pos, 2) == _t("~="))
99 {
100 attribute.condition = select_contain_str;
101 pos += 2;
102 } else if(txt.substr(pos, 2) == _t("|="))
103 {
104 attribute.condition = select_start_str;
105 pos += 2;
106 } else if(txt.substr(pos, 2) == _t("^="))
107 {
108 attribute.condition = select_start_str;
109 pos += 2;
110 } else if(txt.substr(pos, 2) == _t("$="))
111 {
112 attribute.condition = select_end_str;
113 pos += 2;
114 } else if(txt.substr(pos, 2) == _t("*="))
115 {
116 attribute.condition = select_contain_str;
117 pos += 2;
118 } else
119 {
120 attribute.condition = select_exists;
121 pos += 1;
122 }
123 pos = txt.find_first_not_of(_t(" \t"), pos);
124 if(pos != tstring::npos)
125 {
126 if(txt[pos] == _t('"'))
127 {
128 tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);
129 attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));
130 pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
131 } else if(txt[pos] == _t(']'))
132 {
133 pos ++;
134 } else
135 {
136 tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);
137 attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));
138 trim(attribute.val);
139 pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
140 }
141 }
142 } else
143 {
144 attribute.condition = select_exists;
145 }
146 attribute.attribute = attr;
147 m_attrs.push_back(attribute);
148 el_end = pos;
149 } else
150 {
151 el_end++;
152 }
153 el_end = txt.find_first_of(_t(".#[:"), el_end);
154 }
155}
156
157
158bool litehtml::css_selector::parse( const tstring& text )
159{
160 if(text.empty())
161 {
162 return false;
163 }
164 string_vector tokens;
165 split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));
166
167 if(tokens.empty())
168 {
169 return false;
170 }
171
172 tstring left;
173 tstring right = tokens.back();
174 tchar_t combinator = 0;
175
176 tokens.pop_back();
177 while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))
178 {
179 if(combinator == _t(' ') || combinator == 0)
180 {
181 combinator = tokens.back()[0];
182 }
183 tokens.pop_back();
184 }
185
186 for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)
187 {
188 left += *i;
189 }
190
191 trim(left);
192 trim(right);
193
194 if(right.empty())
195 {
196 return false;
197 }
198
199 m_right.parse(right);
200
201 switch(combinator)
202 {
203 case _t('>'):
204 m_combinator = combinator_child;
205 break;
206 case _t('+'):
207 m_combinator = combinator_adjacent_sibling;
208 break;
209 case _t('~'):
210 m_combinator = combinator_general_sibling;
211 break;
212 default:
213 m_combinator = combinator_descendant;
214 break;
215 }
216
217 m_left = 0;
218
219 if(!left.empty())
220 {
221 m_left = std::make_shared<css_selector>(media_query_list::ptr(0));
222 if(!m_left->parse(left))
223 {
224 return false;
225 }
226 }
227
228 return true;
229}
230
231void litehtml::css_selector::calc_specificity()
232{
233 if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))
234 {
235 m_specificity.d = 1;
236 }
237 for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)
238 {
239 if(i->attribute == _t("id"))
240 {
241 m_specificity.b++;
242 } else
243 {
244 if(i->attribute == _t("class"))
245 {
246 m_specificity.c += (int) i->class_val.size();
247 } else
248 {
249 m_specificity.c++;
250 }
251 }
252 }
253 if(m_left)
254 {
255 m_left->calc_specificity();
256 m_specificity += m_left->m_specificity;
257 }
258}
259
260void litehtml::css_selector::add_media_to_doc( document* doc ) const
261{
262 if(m_media_query && doc)
263 {
264 doc->add_media_list(m_media_query);
265 }
266}
267