2 #include "css_selector.h"
5 void litehtml::css_element_selector::parse( const tstring& txt )
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 while(el_end != tstring::npos)
12 if(txt[el_end] == _t('.'))
14 css_attribute_selector attribute;
16 tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
17 attribute.val = txt.substr(el_end + 1, pos - el_end - 1);
18 split_string( attribute.val, attribute.class_val, _t(" ") );
19 attribute.condition = select_equal;
20 attribute.attribute = _t("class");
21 m_attrs.push_back(attribute);
23 } else if(txt[el_end] == _t(':'))
25 css_attribute_selector attribute;
27 if(txt[el_end + 1] == _t(':'))
29 tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);
30 attribute.val = txt.substr(el_end + 2, pos - el_end - 2);
31 attribute.condition = select_pseudo_element;
32 litehtml::lcase(attribute.val);
33 attribute.attribute = _t("pseudo-el");
34 m_attrs.push_back(attribute);
38 tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);
39 if(pos != tstring::npos && txt.at(pos) == _t('('))
41 pos = find_close_bracket(txt, pos);
42 if(pos != tstring::npos)
51 if(pos != tstring::npos)
53 attribute.val = txt.substr(el_end + 1, pos - el_end - 1);
56 attribute.val = txt.substr(el_end + 1);
58 litehtml::lcase(attribute.val);
59 if(attribute.val == _t("after") || attribute.val == _t("before"))
61 attribute.condition = select_pseudo_element;
64 attribute.condition = select_pseudo_class;
66 attribute.attribute = _t("pseudo");
67 m_attrs.push_back(attribute);
70 } else if(txt[el_end] == _t('#'))
72 css_attribute_selector attribute;
74 tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
75 attribute.val = txt.substr(el_end + 1, pos - el_end - 1);
76 attribute.condition = select_equal;
77 attribute.attribute = _t("id");
78 m_attrs.push_back(attribute);
80 } else if(txt[el_end] == _t('['))
82 css_attribute_selector attribute;
84 tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);
85 tstring attr = txt.substr(el_end + 1, pos - el_end - 1);
87 litehtml::lcase(attr);
88 if(pos != tstring::npos)
90 if(txt[pos] == _t(']'))
92 attribute.condition = select_exists;
93 } else if(txt[pos] == _t('='))
95 attribute.condition = select_equal;
97 } else if(txt.substr(pos, 2) == _t("~="))
99 attribute.condition = select_contain_str;
101 } else if(txt.substr(pos, 2) == _t("|="))
103 attribute.condition = select_start_str;
105 } else if(txt.substr(pos, 2) == _t("^="))
107 attribute.condition = select_start_str;
109 } else if(txt.substr(pos, 2) == _t("$="))
111 attribute.condition = select_end_str;
113 } else if(txt.substr(pos, 2) == _t("*="))
115 attribute.condition = select_contain_str;
119 attribute.condition = select_exists;
122 pos = txt.find_first_not_of(_t(" \t"), pos);
123 if(pos != tstring::npos)
125 if(txt[pos] == _t('"'))
127 tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);
128 attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));
129 pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
130 } else if(txt[pos] == _t(']'))
135 tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);
136 attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));
138 pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
143 attribute.condition = select_exists;
145 attribute.attribute = attr;
146 m_attrs.push_back(attribute);
152 el_end = txt.find_first_of(_t(".#[:"), el_end);
157 bool litehtml::css_selector::parse( const tstring& text )
163 string_vector tokens;
164 split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));
172 tstring right = tokens.back();
173 tchar_t combinator = 0;
176 while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))
178 if(combinator == _t(' ') || combinator == 0)
180 combinator = tokens.back()[0];
185 for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)
198 m_right.parse(right);
203 m_combinator = combinator_child;
206 m_combinator = combinator_adjacent_sibling;
209 m_combinator = combinator_general_sibling;
212 m_combinator = combinator_descendant;
220 m_left = std::make_shared<css_selector>(media_query_list::ptr(0));
221 if(!m_left->parse(left))
230 void litehtml::css_selector::calc_specificity()
232 if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))
236 for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)
238 if(i->attribute == _t("id"))
243 if(i->attribute == _t("class"))
245 m_specificity.c += (int) i->class_val.size();
254 m_left->calc_specificity();
255 m_specificity += m_left->m_specificity;
259 void litehtml::css_selector::add_media_to_doc( document* doc ) const
261 if(m_media_query && doc)
263 doc->add_media_list(m_media_query);