Update LiteHTML sources
[claws.git] / src / plugins / litehtml_viewer / litehtml / css_selector.cpp
blob5843cb1a6ca8844d76ff74cee3348214f31d08e8
1 #include "html.h"
2 #include "css_selector.h"
3 #include "document.h"
5 void litehtml::css_element_selector::parse_nth_child_params(const string& param, int& num, int& off)
7 if (param == "odd")
9 num = 2;
10 off = 1;
12 else if (param == "even")
14 num = 2;
15 off = 0;
17 else
19 string_vector tokens;
20 split_string(param, tokens, " n", "n");
22 string s_num;
23 string s_off;
25 string s_int;
26 for (const auto& token : tokens)
28 if (token == "n")
30 s_num = s_int;
31 s_int.clear();
33 else
35 s_int += token;
38 s_off = s_int;
40 num = atoi(s_num.c_str());
41 off = atoi(s_off.c_str());
45 void litehtml::css_element_selector::parse( const string& txt )
47 string::size_type el_end = txt.find_first_of(".#[:");
48 string tag = txt.substr(0, el_end);
49 litehtml::lcase(tag);
50 if (tag == "") tag = "*";
51 m_tag = _id(tag);
53 m_attrs.clear();
54 while(el_end != string::npos)
56 if(txt[el_end] == '.')
58 css_attribute_selector attribute;
60 attribute.type = select_class;
61 string::size_type pos = txt.find_first_of(".#[:", el_end + 1);
62 string name = txt.substr(el_end + 1, pos - el_end - 1);
63 litehtml::lcase(name);
64 attribute.name = _id(name);
65 m_attrs.push_back(attribute);
66 el_end = pos;
67 } else if(txt[el_end] == '#')
69 css_attribute_selector attribute;
71 attribute.type = select_id;
72 string::size_type pos = txt.find_first_of(".#[:", el_end + 1);
73 string name = txt.substr(el_end + 1, pos - el_end - 1);
74 litehtml::lcase(name);
75 attribute.name = _id(name);
76 m_attrs.push_back(attribute);
77 el_end = pos;
78 } else if(txt[el_end] == ':')
80 css_attribute_selector attribute;
82 if(txt[el_end + 1] == ':')
84 attribute.type = select_pseudo_element;
85 string::size_type pos = txt.find_first_of(".#[:", el_end + 2);
86 string name = txt.substr(el_end + 2, pos - el_end - 2);
87 litehtml::lcase(name);
88 attribute.name = _id(name);
89 m_attrs.push_back(attribute);
90 el_end = pos;
91 } else
93 string::size_type pos = txt.find_first_of(".#[:(", el_end + 1);
94 string name = txt.substr(el_end + 1, pos - el_end - 1);
95 lcase(name);
96 attribute.name = _id(name);
97 if(attribute.name == _after_ || attribute.name == _before_)
99 attribute.type = select_pseudo_element;
100 } else
102 attribute.type = select_pseudo_class;
105 string val;
106 if(pos != string::npos && txt.at(pos) == '(')
108 auto end = find_close_bracket(txt, pos);
109 val = txt.substr(pos + 1, end - pos - 1);
110 if (end != string::npos) pos = end + 1;
113 switch (attribute.name)
115 case _nth_child_:
116 case _nth_of_type_:
117 case _nth_last_child_:
118 case _nth_last_of_type_:
119 lcase(val);
120 parse_nth_child_params(val, attribute.a, attribute.b);
121 break;
122 case _not_:
123 attribute.sel = std::make_shared<css_element_selector>();
124 attribute.sel->parse(val);
125 break;
126 case _lang_:
127 trim(val);
128 lcase(val);
129 attribute.val = val;
130 break;
133 m_attrs.push_back(attribute);
134 el_end = pos;
136 } else if(txt[el_end] == '[')
138 css_attribute_selector attribute;
140 string::size_type pos = txt.find_first_of("]~=|$*^", el_end + 1);
141 string attr = txt.substr(el_end + 1, pos - el_end - 1);
142 trim(attr);
143 litehtml::lcase(attr);
144 if(pos != string::npos)
146 if(txt[pos] == ']')
148 attribute.type = select_exists;
149 } else if(txt[pos] == '=')
151 attribute.type = select_equal;
152 pos++;
153 } else if(txt.substr(pos, 2) == "~=")
155 attribute.type = select_contain_str;
156 pos += 2;
157 } else if(txt.substr(pos, 2) == "|=")
159 attribute.type = select_start_str;
160 pos += 2;
161 } else if(txt.substr(pos, 2) == "^=")
163 attribute.type = select_start_str;
164 pos += 2;
165 } else if(txt.substr(pos, 2) == "$=")
167 attribute.type = select_end_str;
168 pos += 2;
169 } else if(txt.substr(pos, 2) == "*=")
171 attribute.type = select_contain_str;
172 pos += 2;
173 } else
175 attribute.type = select_exists;
176 pos += 1;
178 pos = txt.find_first_not_of(" \t", pos);
179 if(pos != string::npos)
181 if(txt[pos] == '"')
183 string::size_type pos2 = txt.find_first_of('\"', pos + 1);
184 attribute.val = txt.substr(pos + 1, pos2 == string::npos ? pos2 : (pos2 - pos - 1));
185 pos = pos2 == string::npos ? pos2 : (pos2 + 1);
186 } else if(txt[pos] == '\'')
188 string::size_type pos2 = txt.find_first_of('\'', pos + 1);
189 attribute.val = txt.substr(pos + 1, pos2 == string::npos ? pos2 : (pos2 - pos - 1));
190 pos = pos2 == string::npos ? pos2 : (pos2 + 1);
191 } else if(txt[pos] == ']')
193 pos ++;
194 } else
196 string::size_type pos2 = txt.find_first_of(']', pos + 1);
197 attribute.val = txt.substr(pos, pos2 == string::npos ? pos2 : (pos2 - pos));
198 trim(attribute.val);
199 pos = pos2 == string::npos ? pos2 : (pos2 + 1);
202 } else
204 attribute.type = select_exists;
206 attribute.name = _id(attr);
207 m_attrs.push_back(attribute);
208 el_end = pos;
209 } else
211 el_end++;
213 el_end = txt.find_first_of(".#[:", el_end);
218 bool litehtml::css_selector::parse( const string& text )
220 if(text.empty())
222 return false;
224 string_vector tokens;
225 split_string(text, tokens, "", " \t>+~", "([");
227 if(tokens.empty())
229 return false;
232 string left;
233 string right = tokens.back();
234 char combinator = 0;
236 tokens.pop_back();
237 while(!tokens.empty() && (tokens.back() == " " || tokens.back() == "\t" || tokens.back() == "+" || tokens.back() == "~" || tokens.back() == ">"))
239 if(combinator == ' ' || combinator == 0)
241 combinator = tokens.back()[0];
243 tokens.pop_back();
246 for(const auto & token : tokens)
248 left += token;
251 trim(left);
252 trim(right);
254 if(right.empty())
256 return false;
259 m_right.parse(right);
261 switch(combinator)
263 case '>':
264 m_combinator = combinator_child;
265 break;
266 case '+':
267 m_combinator = combinator_adjacent_sibling;
268 break;
269 case '~':
270 m_combinator = combinator_general_sibling;
271 break;
272 default:
273 m_combinator = combinator_descendant;
274 break;
277 m_left = nullptr;
279 if(!left.empty())
281 m_left = std::make_shared<css_selector>();
282 if(!m_left->parse(left))
284 return false;
288 return true;
291 void litehtml::css_selector::calc_specificity()
293 if(m_right.m_tag != star_id)
295 m_specificity.d = 1;
297 for(const auto& attr : m_right.m_attrs)
299 if(attr.type == select_id)
301 m_specificity.b++;
302 } else
304 m_specificity.c++;
307 if(m_left)
309 m_left->calc_specificity();
310 m_specificity += m_left->m_specificity;
314 void litehtml::css_selector::add_media_to_doc( document* doc ) const
316 if(m_media_query && doc)
318 doc->add_media_list(m_media_query);