Update current version of litehtml. Fix a crash when document contains no fonts
[claws.git] / src / plugins / litehtml_viewer / litehtml / css_selector.cpp
index a8e5f41ed7581f08ef27b34a7a5e3c9fd83ffe00..dc400884e7f6eb608d29d5b86b17c053f32ae730 100644 (file)
-#include "html.h"\r
-#include "css_selector.h"\r
-#include "document.h"\r
-\r
-void litehtml::css_element_selector::parse( const tstring& txt )\r
-{\r
-       tstring::size_type el_end = txt.find_first_of(_t(".#[:"));\r
-       m_tag = txt.substr(0, el_end);\r
-       litehtml::lcase(m_tag);\r
-       while(el_end != tstring::npos)\r
-       {\r
-               if(txt[el_end] == _t('.'))\r
-               {\r
-                       css_attribute_selector attribute;\r
-\r
-                       tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);\r
-                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);\r
-                       split_string( attribute.val, attribute.class_val, _t(" ") );\r
-                       attribute.condition     = select_equal;\r
-                       attribute.attribute     = _t("class");\r
-                       m_attrs.push_back(attribute);\r
-                       el_end = pos;\r
-               } else if(txt[el_end] == _t(':'))\r
-               {\r
-                       css_attribute_selector attribute;\r
-\r
-                       if(txt[el_end + 1] == _t(':'))\r
-                       {\r
-                               tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);\r
-                               attribute.val           = txt.substr(el_end + 2, pos - el_end - 2);\r
-                               attribute.condition     = select_pseudo_element;\r
-                               litehtml::lcase(attribute.val);\r
-                               attribute.attribute     = _t("pseudo-el");\r
-                               m_attrs.push_back(attribute);\r
-                               el_end = pos;\r
-                       } else\r
-                       {\r
-                               tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);\r
-                               if(pos != tstring::npos && txt.at(pos) == _t('('))\r
-                               {\r
-                                       pos = find_close_bracket(txt, pos);\r
-                                       if(pos != tstring::npos)\r
-                                       {\r
-                                               pos++;\r
-                                       } else\r
-                                       {\r
-                                               int iii = 0;\r
-                                               iii++;\r
-                                       }\r
-                               }\r
-                               if(pos != tstring::npos)\r
-                               {\r
-                                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);\r
-                               } else\r
-                               {\r
-                                       attribute.val           = txt.substr(el_end + 1);\r
-                               }\r
-                               litehtml::lcase(attribute.val);\r
-                               if(attribute.val == _t("after") || attribute.val == _t("before"))\r
-                               {\r
-                                       attribute.condition     = select_pseudo_element;\r
-                               } else\r
-                               {\r
-                                       attribute.condition     = select_pseudo_class;\r
-                               }\r
-                               attribute.attribute     = _t("pseudo");\r
-                               m_attrs.push_back(attribute);\r
-                               el_end = pos;\r
-                       }\r
-               } else if(txt[el_end] == _t('#'))\r
-               {\r
-                       css_attribute_selector attribute;\r
-\r
-                       tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);\r
-                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);\r
-                       attribute.condition     = select_equal;\r
-                       attribute.attribute     = _t("id");\r
-                       m_attrs.push_back(attribute);\r
-                       el_end = pos;\r
-               } else if(txt[el_end] == _t('['))\r
-               {\r
-                       css_attribute_selector attribute;\r
-\r
-                       tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);\r
-                       tstring attr = txt.substr(el_end + 1, pos - el_end - 1);\r
-                       trim(attr);\r
-                       litehtml::lcase(attr);\r
-                       if(pos != tstring::npos)\r
-                       {\r
-                               if(txt[pos] == _t(']'))\r
-                               {\r
-                                       attribute.condition = select_exists;\r
-                               } else if(txt[pos] == _t('='))\r
-                               {\r
-                                       attribute.condition = select_equal;\r
-                                       pos++;\r
-                               } else if(txt.substr(pos, 2) == _t("~="))\r
-                               {\r
-                                       attribute.condition = select_contain_str;\r
-                                       pos += 2;\r
-                               } else if(txt.substr(pos, 2) == _t("|="))\r
-                               {\r
-                                       attribute.condition = select_start_str;\r
-                                       pos += 2;\r
-                               } else if(txt.substr(pos, 2) == _t("^="))\r
-                               {\r
-                                       attribute.condition = select_start_str;\r
-                                       pos += 2;\r
-                               } else if(txt.substr(pos, 2) == _t("$="))\r
-                               {\r
-                                       attribute.condition = select_end_str;\r
-                                       pos += 2;\r
-                               } else if(txt.substr(pos, 2) == _t("*="))\r
-                               {\r
-                                       attribute.condition = select_contain_str;\r
-                                       pos += 2;\r
-                               } else\r
-                               {\r
-                                       attribute.condition = select_exists;\r
-                                       pos += 1;\r
-                               }\r
-                               pos = txt.find_first_not_of(_t(" \t"), pos);\r
-                               if(pos != tstring::npos)\r
-                               {\r
-                                       if(txt[pos] == _t('"'))\r
-                                       {\r
-                                               tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);\r
-                                               attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));\r
-                                               pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);\r
-                                       } else if(txt[pos] == _t(']'))\r
-                                       {\r
-                                               pos ++;\r
-                                       } else\r
-                                       {\r
-                                               tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);\r
-                                               attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));\r
-                                               trim(attribute.val);\r
-                                               pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);\r
-                                       }\r
-                               }\r
-                       } else\r
-                       {\r
-                               attribute.condition = select_exists;\r
-                       }\r
-                       attribute.attribute     = attr;\r
-                       m_attrs.push_back(attribute);\r
-                       el_end = pos;\r
-               } else\r
-               {\r
-                       el_end++;\r
-               }\r
-               el_end = txt.find_first_of(_t(".#[:"), el_end);\r
-       }\r
-}\r
-\r
-\r
-bool litehtml::css_selector::parse( const tstring& text )\r
-{\r
-       if(text.empty())\r
-       {\r
-               return false;\r
-       }\r
-       string_vector tokens;\r
-       split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));\r
-\r
-       if(tokens.empty())\r
-       {\r
-               return false;\r
-       }\r
-\r
-       tstring left;\r
-       tstring right = tokens.back();\r
-       tchar_t combinator = 0;\r
-\r
-       tokens.pop_back();\r
-       while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))\r
-       {\r
-               if(combinator == _t(' ') || combinator == 0)\r
-               {\r
-                       combinator = tokens.back()[0];\r
-               }\r
-               tokens.pop_back();\r
-       }\r
-\r
-       for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)\r
-       {\r
-               left += *i;\r
-       }\r
-\r
-       trim(left);\r
-       trim(right);\r
-\r
-       if(right.empty())\r
-       {\r
-               return false;\r
-       }\r
-\r
-       m_right.parse(right);\r
-\r
-       switch(combinator)\r
-       {\r
-       case _t('>'):\r
-               m_combinator    = combinator_child;\r
-               break;\r
-       case _t('+'):\r
-               m_combinator    = combinator_adjacent_sibling;\r
-               break;\r
-       case _t('~'):\r
-               m_combinator    = combinator_general_sibling;\r
-               break;\r
-       default:\r
-               m_combinator    = combinator_descendant;\r
-               break;\r
-       }\r
-\r
-       m_left = 0;\r
-\r
-       if(!left.empty())\r
-       {\r
-               m_left = std::make_shared<css_selector>(media_query_list::ptr(0));\r
-               if(!m_left->parse(left))\r
-               {\r
-                       return false;\r
-               }\r
-       }\r
-\r
-       return true;\r
-}\r
-\r
-void litehtml::css_selector::calc_specificity()\r
-{\r
-       if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))\r
-       {\r
-               m_specificity.d = 1;\r
-       }\r
-       for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)\r
-       {\r
-               if(i->attribute == _t("id"))\r
-               {\r
-                       m_specificity.b++;\r
-               } else\r
-               {\r
-                       if(i->attribute == _t("class"))\r
-                       {\r
-                               m_specificity.c += (int) i->class_val.size();\r
-                       } else\r
-                       {\r
-                               m_specificity.c++;\r
-                       }\r
-               }       \r
-       }\r
-       if(m_left)\r
-       {\r
-               m_left->calc_specificity();\r
-               m_specificity += m_left->m_specificity;\r
-       }\r
-}\r
-\r
-void litehtml::css_selector::add_media_to_doc( document* doc ) const\r
-{\r
-       if(m_media_query && doc)\r
-       {\r
-               doc->add_media_list(m_media_query);\r
-       }\r
-}\r
-\r
+#include "html.h"
+#include "css_selector.h"
+#include "document.h"
+
+void litehtml::css_element_selector::parse( const tstring& txt )
+{
+       tstring::size_type el_end = txt.find_first_of(_t(".#[:"));
+       m_tag = txt.substr(0, el_end);
+       litehtml::lcase(m_tag);
+       while(el_end != tstring::npos)
+       {
+               if(txt[el_end] == _t('.'))
+               {
+                       css_attribute_selector attribute;
+
+                       tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
+                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);
+                       split_string( attribute.val, attribute.class_val, _t(" ") );
+                       attribute.condition     = select_equal;
+                       attribute.attribute     = _t("class");
+                       m_attrs.push_back(attribute);
+                       el_end = pos;
+               } else if(txt[el_end] == _t(':'))
+               {
+                       css_attribute_selector attribute;
+
+                       if(txt[el_end + 1] == _t(':'))
+                       {
+                               tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 2);
+                               attribute.val           = txt.substr(el_end + 2, pos - el_end - 2);
+                               attribute.condition     = select_pseudo_element;
+                               litehtml::lcase(attribute.val);
+                               attribute.attribute     = _t("pseudo-el");
+                               m_attrs.push_back(attribute);
+                               el_end = pos;
+                       } else
+                       {
+                               tstring::size_type pos = txt.find_first_of(_t(".#[:("), el_end + 1);
+                               if(pos != tstring::npos && txt.at(pos) == _t('('))
+                               {
+                                       pos = find_close_bracket(txt, pos);
+                                       if(pos != tstring::npos)
+                                       {
+                                               pos++;
+                                       } else
+                                       {
+                                               int iii = 0;
+                                               iii++;
+                                       }
+                               }
+                               if(pos != tstring::npos)
+                               {
+                                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);
+                               } else
+                               {
+                                       attribute.val           = txt.substr(el_end + 1);
+                               }
+                               litehtml::lcase(attribute.val);
+                               if(attribute.val == _t("after") || attribute.val == _t("before"))
+                               {
+                                       attribute.condition     = select_pseudo_element;
+                               } else
+                               {
+                                       attribute.condition     = select_pseudo_class;
+                               }
+                               attribute.attribute     = _t("pseudo");
+                               m_attrs.push_back(attribute);
+                               el_end = pos;
+                       }
+               } else if(txt[el_end] == _t('#'))
+               {
+                       css_attribute_selector attribute;
+
+                       tstring::size_type pos = txt.find_first_of(_t(".#[:"), el_end + 1);
+                       attribute.val           = txt.substr(el_end + 1, pos - el_end - 1);
+                       attribute.condition     = select_equal;
+                       attribute.attribute     = _t("id");
+                       m_attrs.push_back(attribute);
+                       el_end = pos;
+               } else if(txt[el_end] == _t('['))
+               {
+                       css_attribute_selector attribute;
+
+                       tstring::size_type pos = txt.find_first_of(_t("]~=|$*^"), el_end + 1);
+                       tstring attr = txt.substr(el_end + 1, pos - el_end - 1);
+                       trim(attr);
+                       litehtml::lcase(attr);
+                       if(pos != tstring::npos)
+                       {
+                               if(txt[pos] == _t(']'))
+                               {
+                                       attribute.condition = select_exists;
+                               } else if(txt[pos] == _t('='))
+                               {
+                                       attribute.condition = select_equal;
+                                       pos++;
+                               } else if(txt.substr(pos, 2) == _t("~="))
+                               {
+                                       attribute.condition = select_contain_str;
+                                       pos += 2;
+                               } else if(txt.substr(pos, 2) == _t("|="))
+                               {
+                                       attribute.condition = select_start_str;
+                                       pos += 2;
+                               } else if(txt.substr(pos, 2) == _t("^="))
+                               {
+                                       attribute.condition = select_start_str;
+                                       pos += 2;
+                               } else if(txt.substr(pos, 2) == _t("$="))
+                               {
+                                       attribute.condition = select_end_str;
+                                       pos += 2;
+                               } else if(txt.substr(pos, 2) == _t("*="))
+                               {
+                                       attribute.condition = select_contain_str;
+                                       pos += 2;
+                               } else
+                               {
+                                       attribute.condition = select_exists;
+                                       pos += 1;
+                               }
+                               pos = txt.find_first_not_of(_t(" \t"), pos);
+                               if(pos != tstring::npos)
+                               {
+                                       if(txt[pos] == _t('"'))
+                                       {
+                                               tstring::size_type pos2 = txt.find_first_of(_t("\""), pos + 1);
+                                               attribute.val = txt.substr(pos + 1, pos2 == tstring::npos ? pos2 : (pos2 - pos - 1));
+                                               pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
+                                       } else if(txt[pos] == _t(']'))
+                                       {
+                                               pos ++;
+                                       } else
+                                       {
+                                               tstring::size_type pos2 = txt.find_first_of(_t("]"), pos + 1);
+                                               attribute.val = txt.substr(pos, pos2 == tstring::npos ? pos2 : (pos2 - pos));
+                                               trim(attribute.val);
+                                               pos = pos2 == tstring::npos ? pos2 : (pos2 + 1);
+                                       }
+                               }
+                       } else
+                       {
+                               attribute.condition = select_exists;
+                       }
+                       attribute.attribute     = attr;
+                       m_attrs.push_back(attribute);
+                       el_end = pos;
+               } else
+               {
+                       el_end++;
+               }
+               el_end = txt.find_first_of(_t(".#[:"), el_end);
+       }
+}
+
+
+bool litehtml::css_selector::parse( const tstring& text )
+{
+       if(text.empty())
+       {
+               return false;
+       }
+       string_vector tokens;
+       split_string(text, tokens, _t(""), _t(" \t>+~"), _t("(["));
+
+       if(tokens.empty())
+       {
+               return false;
+       }
+
+       tstring left;
+       tstring right = tokens.back();
+       tchar_t combinator = 0;
+
+       tokens.pop_back();
+       while(!tokens.empty() && (tokens.back() == _t(" ") || tokens.back() == _t("\t") || tokens.back() == _t("+") || tokens.back() == _t("~") || tokens.back() == _t(">")))
+       {
+               if(combinator == _t(' ') || combinator == 0)
+               {
+                       combinator = tokens.back()[0];
+               }
+               tokens.pop_back();
+       }
+
+       for(string_vector::const_iterator i = tokens.begin(); i != tokens.end(); i++)
+       {
+               left += *i;
+       }
+
+       trim(left);
+       trim(right);
+
+       if(right.empty())
+       {
+               return false;
+       }
+
+       m_right.parse(right);
+
+       switch(combinator)
+       {
+       case _t('>'):
+               m_combinator    = combinator_child;
+               break;
+       case _t('+'):
+               m_combinator    = combinator_adjacent_sibling;
+               break;
+       case _t('~'):
+               m_combinator    = combinator_general_sibling;
+               break;
+       default:
+               m_combinator    = combinator_descendant;
+               break;
+       }
+
+       m_left = 0;
+
+       if(!left.empty())
+       {
+               m_left = std::make_shared<css_selector>(media_query_list::ptr(0));
+               if(!m_left->parse(left))
+               {
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+void litehtml::css_selector::calc_specificity()
+{
+       if(!m_right.m_tag.empty() && m_right.m_tag != _t("*"))
+       {
+               m_specificity.d = 1;
+       }
+       for(css_attribute_selector::vector::iterator i = m_right.m_attrs.begin(); i != m_right.m_attrs.end(); i++)
+       {
+               if(i->attribute == _t("id"))
+               {
+                       m_specificity.b++;
+               } else
+               {
+                       if(i->attribute == _t("class"))
+                       {
+                               m_specificity.c += (int) i->class_val.size();
+                       } else
+                       {
+                               m_specificity.c++;
+                       }
+               }       
+       }
+       if(m_left)
+       {
+               m_left->calc_specificity();
+               m_specificity += m_left->m_specificity;
+       }
+}
+
+void litehtml::css_selector::add_media_to_doc( document* doc ) const
+{
+       if(m_media_query && doc)
+       {
+               doc->add_media_list(m_media_query);
+       }
+}
+