CSSParser.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include <LibHTML/CSS/StyleSheet.h>
  2. #include <LibHTML/Parser/CSSParser.h>
  3. #include <ctype.h>
  4. #include <stdio.h>
  5. NonnullRefPtr<StyleValue> parse_css_value(const StringView& view)
  6. {
  7. String string(view);
  8. bool ok;
  9. int as_int = string.to_int(ok);
  10. if (ok)
  11. return LengthStyleValue::create(Length(as_int, Length::Type::Absolute));
  12. unsigned as_uint = string.to_uint(ok);
  13. if (ok)
  14. return LengthStyleValue::create(Length(as_uint, Length::Type::Absolute));
  15. if (string == "inherit")
  16. return InheritStyleValue::create();
  17. if (string == "initial")
  18. return InitialStyleValue::create();
  19. if (string == "auto")
  20. return LengthStyleValue::create(Length());
  21. return StringStyleValue::create(string);
  22. }
  23. NonnullRefPtr<StyleSheet> parse_css(const String& css)
  24. {
  25. NonnullRefPtrVector<StyleRule> rules;
  26. enum class State {
  27. Free,
  28. InSelectorComponent,
  29. InPropertyName,
  30. InPropertyValue,
  31. };
  32. struct CurrentRule {
  33. Vector<Selector> selectors;
  34. NonnullRefPtrVector<StyleDeclaration> declarations;
  35. };
  36. CurrentRule current_rule;
  37. Vector<char> buffer;
  38. int index = 0;
  39. auto peek = [&]() -> char {
  40. if (index < css.length())
  41. return css[index];
  42. return 0;
  43. };
  44. auto consume_specific = [&](char ch) {
  45. ASSERT(peek() == ch);
  46. ++index;
  47. return ch;
  48. };
  49. auto consume_one = [&]() -> char {
  50. return css[index++];
  51. };
  52. auto consume_whitespace = [&] {
  53. while (isspace(peek()))
  54. ++index;
  55. };
  56. auto is_valid_selector_char = [](char ch) {
  57. return isalnum(ch) || ch == '-' || ch == '_';
  58. };
  59. auto parse_selector = [&] {
  60. consume_whitespace();
  61. Selector::Component::Type type;
  62. if (peek() == '.')
  63. type = Selector::Component::Type::Class;
  64. else if (peek() == '#')
  65. type = Selector::Component::Type::Id;
  66. else
  67. type = Selector::Component::Type::TagName;
  68. while (is_valid_selector_char(peek()))
  69. buffer.append(consume_one());
  70. ASSERT(!buffer.is_null());
  71. auto component_string = String::copy(buffer);
  72. Vector<Selector::Component> components;
  73. components.append({ type, component_string });
  74. buffer.clear();
  75. current_rule.selectors.append(Selector(move(components)));
  76. };
  77. auto parse_selector_list = [&] {
  78. for (;;) {
  79. parse_selector();
  80. consume_whitespace();
  81. if (peek() == ',') {
  82. consume_one();
  83. continue;
  84. }
  85. if (peek() == '{')
  86. break;
  87. }
  88. };
  89. auto is_valid_property_name_char = [](char ch) {
  90. return !isspace(ch) && ch != ':';
  91. };
  92. auto is_valid_property_value_char = [](char ch) {
  93. return !isspace(ch) && ch != ';';
  94. };
  95. auto parse_declaration = [&] {
  96. consume_whitespace();
  97. buffer.clear();
  98. while (is_valid_property_name_char(peek()))
  99. buffer.append(consume_one());
  100. auto property_name = String::copy(buffer);
  101. buffer.clear();
  102. consume_whitespace();
  103. consume_specific(':');
  104. consume_whitespace();
  105. while (is_valid_property_value_char(peek()))
  106. buffer.append(consume_one());
  107. auto property_value = String::copy(buffer);
  108. buffer.clear();
  109. consume_specific(';');
  110. current_rule.declarations.append(StyleDeclaration::create(property_name, parse_css_value(property_value)));
  111. };
  112. auto parse_declarations = [&] {
  113. for (;;) {
  114. parse_declaration();
  115. consume_whitespace();
  116. if (peek() == '}')
  117. break;
  118. }
  119. };
  120. auto parse_rule = [&] {
  121. parse_selector_list();
  122. consume_specific('{');
  123. parse_declarations();
  124. consume_specific('}');
  125. rules.append(StyleRule::create(move(current_rule.selectors), move(current_rule.declarations)));
  126. };
  127. while (index < css.length()) {
  128. parse_rule();
  129. }
  130. return StyleSheet::create(move(rules));
  131. }