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

source code of qttools/src/assistant/qlitehtml/src/3rdparty/litehtml/src/css_selector.cpp