CSSParser.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #include <LibHTML/CSS/StyleSheet.h>
  2. #include <LibHTML/Parser/CSSParser.h>
  3. #include <ctype.h>
  4. #include <stdio.h>
  5. NonnullRefPtr<StyleSheet> parse_css(const String& css)
  6. {
  7. Vector<NonnullRefPtr<StyleRule>> rules;
  8. enum class State {
  9. Free,
  10. InSelectorComponent,
  11. InPropertyName,
  12. InPropertyValue,
  13. };
  14. struct CurrentRule {
  15. Vector<Selector> selectors;
  16. Vector<StyleDeclaration> declarations;
  17. };
  18. CurrentRule current_rule;
  19. Vector<char> buffer;
  20. int index = 0;
  21. auto peek = [&]() -> char {
  22. if (index + 1 < css.length())
  23. return css[index + 1];
  24. return 0;
  25. };
  26. auto consume_specific = [&](char ch) {
  27. ASSERT(peek() == ch);
  28. ++index;
  29. return ch;
  30. };
  31. auto consume_one = [&]() -> char {
  32. return css[index++];
  33. };
  34. auto consume_whitespace = [&] {
  35. while (isspace(peek()))
  36. ++index;
  37. };
  38. auto is_valid_selector_char = [](char ch) {
  39. return isalnum(ch) || ch == '-' || ch == '_';
  40. };
  41. auto parse_selector = [&] {
  42. consume_whitespace();
  43. Selector::Component::Type type;
  44. if (peek() == '.')
  45. type = Selector::Component::Type::Class;
  46. else if (peek() == '#')
  47. type = Selector::Component::Type::Id;
  48. else
  49. type = Selector::Component::Type::TagName;
  50. while (is_valid_selector_char(peek()))
  51. buffer.append(consume_one());
  52. Vector<Selector::Component> components;
  53. components.append({ type, String::copy(buffer) });
  54. buffer.clear();
  55. current_rule.selectors.append(Selector(move(components)));
  56. };
  57. auto parse_selector_list = [&] {
  58. for (;;) {
  59. parse_selector();
  60. if (peek() == ',')
  61. continue;
  62. if (peek() == '{')
  63. break;
  64. }
  65. };
  66. auto parse_declaration = [&] {
  67. consume_whitespace();
  68. };
  69. auto parse_declarations = [&] {
  70. for (;;) {
  71. parse_declaration();
  72. if (peek() == '}')
  73. break;
  74. }
  75. };
  76. auto parse_rule = [&] {
  77. parse_selector_list();
  78. consume_specific('{');
  79. parse_declarations();
  80. consume_specific('}');
  81. };
  82. while (index < css.length()) {
  83. parse_rule();
  84. }
  85. return StyleSheet::create(move(rules));
  86. }