| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2023-02-14 20:03:49 +00:00
										 |  |  |  * Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org> | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 16:54:25 +00:00
										 |  |  | #include <LibJS/Runtime/Realm.h>
 | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  | #include <LibWeb/CSS/Parser/Parser.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/Supports.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Web::CSS { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-01 19:55:31 +00:00
										 |  |  | static void indent(StringBuilder& builder, int levels) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for (int i = 0; i < levels; i++) | 
					
						
							|  |  |  |         builder.append("  "sv); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  | Supports::Supports(JS::Realm& realm, NonnullOwnPtr<Condition>&& condition) | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  |     : m_condition(move(condition)) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |     m_matches = m_condition->evaluate(realm); | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  | bool Supports::Condition::evaluate(JS::Realm& realm) const | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							|  |  |  |     case Type::Not: | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |         return !children.first().evaluate(realm); | 
					
						
							| 
									
										
										
										
											2021-11-24 14:20:59 +00:00
										 |  |  |     case Type::And: | 
					
						
							| 
									
										
										
										
											2022-01-19 20:03:22 +00:00
										 |  |  |         for (auto& child : children) { | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |             if (!child.evaluate(realm)) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:03:22 +00:00
										 |  |  |                 return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2021-11-24 14:20:59 +00:00
										 |  |  |     case Type::Or: | 
					
						
							| 
									
										
										
										
											2022-01-19 20:03:22 +00:00
										 |  |  |         for (auto& child : children) { | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |             if (child.evaluate(realm)) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:03:22 +00:00
										 |  |  |                 return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     VERIFY_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  | bool Supports::InParens::evaluate(JS::Realm& realm) const | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return value.visit( | 
					
						
							| 
									
										
										
										
											2022-01-13 17:31:00 +03:30
										 |  |  |         [&](NonnullOwnPtr<Condition> const& condition) { | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |             return condition->evaluate(realm); | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-01-13 17:31:00 +03:30
										 |  |  |         [&](Feature const& feature) { | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |             return feature.evaluate(realm); | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-01-19 20:03:22 +00:00
										 |  |  |         [&](GeneralEnclosed const&) { | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  |         }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  | bool Supports::Declaration::evaluate(JS::Realm& realm) const | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |     auto style_property = parse_css_supports_condition(Parser::ParsingContext { realm }, declaration); | 
					
						
							| 
									
										
										
										
											2022-01-19 20:03:22 +00:00
										 |  |  |     return style_property.has_value(); | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  | bool Supports::Selector::evaluate(JS::Realm& realm) const | 
					
						
							| 
									
										
										
										
											2022-02-19 17:22:05 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |     auto style_property = parse_selector(Parser::ParsingContext { realm }, selector); | 
					
						
							| 
									
										
										
										
											2022-02-19 17:22:05 +00:00
										 |  |  |     return style_property.has_value(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  | bool Supports::Feature::evaluate(JS::Realm& realm) const | 
					
						
							| 
									
										
										
										
											2022-02-19 17:22:05 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     return value.visit( | 
					
						
							|  |  |  |         [&](Declaration const& declaration) { | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |             return declaration.evaluate(realm); | 
					
						
							| 
									
										
										
										
											2022-02-19 17:22:05 +00:00
										 |  |  |         }, | 
					
						
							|  |  |  |         [&](Selector const& selector) { | 
					
						
							| 
									
										
										
										
											2024-04-04 12:44:43 +02:00
										 |  |  |             return selector.evaluate(realm); | 
					
						
							| 
									
										
										
										
											2022-02-19 17:22:05 +00:00
										 |  |  |         }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  | String Supports::Declaration::to_string() const | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  |     return MUST(String::formatted("({})", declaration)); | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  | String Supports::Selector::to_string() const | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  |     return MUST(String::formatted("selector({})", selector)); | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  | String Supports::Feature::to_string() const | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-14 20:03:49 +00:00
										 |  |  |     return value.visit([](auto& it) { return it.to_string(); }); | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  | String Supports::InParens::to_string() const | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return value.visit( | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  |         [](NonnullOwnPtr<Condition> const& condition) { return MUST(String::formatted("({})", condition->to_string())); }, | 
					
						
							|  |  |  |         [](Supports::Feature const& it) { return it.to_string(); }, | 
					
						
							|  |  |  |         [](GeneralEnclosed const& it) { return it.to_string(); }); | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  | String Supports::Condition::to_string() const | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							|  |  |  |     case Type::Not: | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  |         return MUST(String::formatted("not {}", children.first().to_string())); | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  |     case Type::And: | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  |         return MUST(String::join(" and "sv, children)); | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  |     case Type::Or: | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  |         return MUST(String::join(" or "sv, children)); | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     VERIFY_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-22 12:47:38 +01:00
										 |  |  | String Supports::to_string() const | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-14 20:03:49 +00:00
										 |  |  |     return m_condition->to_string(); | 
					
						
							| 
									
										
										
										
											2022-04-22 15:18:47 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-01 19:55:31 +00:00
										 |  |  | void Supports::Declaration::dump(StringBuilder& builder, int indent_levels) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     indent(builder, indent_levels); | 
					
						
							|  |  |  |     builder.appendff("Declaration: {}\n", declaration); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Supports::Selector::dump(StringBuilder& builder, int indent_levels) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     indent(builder, indent_levels); | 
					
						
							|  |  |  |     builder.appendff("Selector: {}\n", selector); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Supports::Feature::dump(StringBuilder& builder, int indent_levels) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     value.visit([&](auto& it) { it.dump(builder, indent_levels); }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Supports::InParens::dump(StringBuilder& builder, int indent_levels) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     value.visit( | 
					
						
							|  |  |  |         [&](NonnullOwnPtr<Condition> const& condition) { condition->dump(builder, indent_levels); }, | 
					
						
							|  |  |  |         [&](Supports::Feature const& it) { it.dump(builder, indent_levels); }, | 
					
						
							|  |  |  |         [&](GeneralEnclosed const& it) { | 
					
						
							|  |  |  |             indent(builder, indent_levels); | 
					
						
							|  |  |  |             builder.appendff("GeneralEnclosed: {}\n", it.to_string()); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Supports::Condition::dump(StringBuilder& builder, int indent_levels) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     indent(builder, indent_levels); | 
					
						
							|  |  |  |     StringView type_name = [](Type type) { | 
					
						
							|  |  |  |         switch (type) { | 
					
						
							|  |  |  |         case Type::And: | 
					
						
							|  |  |  |             return "AND"sv; | 
					
						
							|  |  |  |         case Type::Or: | 
					
						
							|  |  |  |             return "OR"sv; | 
					
						
							|  |  |  |         case Type::Not: | 
					
						
							|  |  |  |             return "NOT"sv; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         VERIFY_NOT_REACHED(); | 
					
						
							|  |  |  |     }(type); | 
					
						
							|  |  |  |     builder.appendff("Condition: {}\n", type_name); | 
					
						
							|  |  |  |     for (auto const& child : children) | 
					
						
							|  |  |  |         child.dump(builder, indent_levels + 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Supports::dump(StringBuilder& builder, int indent_levels) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_condition->dump(builder, indent_levels); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-08 15:40:19 +01:00
										 |  |  | } |