2021-09-28 15:17:11 +01:00
/*
2022-04-23 11:29:31 +01:00
* Copyright ( c ) 2021 - 2022 , Sam Atkins < atkinssj @ serenityos . org >
2021-09-28 15:17:11 +01:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2021-10-08 16:40:50 +01:00
# include <AK/TypeCasts.h>
# include <LibWeb/CSS/CSSImportRule.h>
2021-10-08 17:02:47 +01:00
# include <LibWeb/CSS/CSSMediaRule.h>
2021-09-28 15:17:11 +01:00
# include <LibWeb/CSS/CSSRuleList.h>
2021-10-08 17:48:14 +01:00
# include <LibWeb/CSS/CSSSupportsRule.h>
2022-04-23 11:29:31 +01:00
# include <LibWeb/CSS/Parser/Parser.h>
2021-09-28 15:17:11 +01:00
namespace Web : : CSS {
CSSRuleList : : CSSRuleList ( NonnullRefPtrVector < CSSRule > & & rules )
2021-09-29 19:41:46 +02:00
: m_rules ( move ( rules ) )
2021-09-28 15:17:11 +01:00
{
}
2021-09-29 19:41:46 +02:00
bool CSSRuleList : : is_supported_property_index ( u32 index ) const
{
// The object’ s supported property indices are the numbers in the range zero to one less than the number of CSSRule objects represented by the collection.
// If there are no such CSSRule objects, then there are no supported property indices.
return index < m_rules . size ( ) ;
}
2021-10-15 19:38:39 +01:00
// https://www.w3.org/TR/cssom/#insert-a-css-rule
2022-04-23 11:29:31 +01:00
DOM : : ExceptionOr < unsigned > CSSRuleList : : insert_a_css_rule ( Variant < StringView , NonnullRefPtr < CSSRule > > rule , u32 index )
2021-09-29 21:12:39 +02:00
{
// 1. Set length to the number of items in list.
auto length = m_rules . size ( ) ;
// 2. If index is greater than length, then throw an IndexSizeError exception.
if ( index > length )
return DOM : : IndexSizeError : : create ( " CSS rule index out of bounds. " ) ;
// 3. Set new rule to the results of performing parse a CSS rule on argument rule.
2022-04-23 11:29:31 +01:00
// NOTE: The insert-a-css-rule spec expects `rule` to be a string, but the CSSStyleSheet.insertRule()
// spec calls this algorithm with an already-parsed CSSRule. So, we use a Variant and skip step 3
// if that variant holds a CSSRule already.
RefPtr < CSSRule > new_rule ;
if ( rule . has < StringView > ( ) ) {
new_rule = parse_css_rule ( CSS : : Parser : : ParsingContext { } , rule . get < StringView > ( ) ) ;
} else {
new_rule = rule . get < NonnullRefPtr < CSSRule > > ( ) ;
}
2021-09-29 21:12:39 +02:00
// 4. If new rule is a syntax error, throw a SyntaxError exception.
2022-04-23 11:29:31 +01:00
if ( ! new_rule )
return DOM : : SyntaxError : : create ( " Unable to parse CSS rule. " ) ;
2021-09-29 21:12:39 +02:00
// FIXME: 5. If new rule cannot be inserted into list at the zero-index position index due to constraints specified by CSS, then throw a HierarchyRequestError exception. [CSS21]
// FIXME: 6. If new rule is an @namespace at-rule, and list contains anything other than @import at-rules, and @namespace at-rules, throw an InvalidStateError exception.
// 7. Insert new rule into list at the zero-indexed position index.
2022-04-23 11:29:31 +01:00
m_rules . insert ( index , new_rule . release_nonnull ( ) ) ;
2021-09-29 21:12:39 +02:00
// 8. Return index.
return index ;
}
2021-10-15 19:38:39 +01:00
// https://www.w3.org/TR/cssom/#remove-a-css-rule
2021-09-29 20:28:32 +02:00
DOM : : ExceptionOr < void > CSSRuleList : : remove_a_css_rule ( u32 index )
{
// 1. Set length to the number of items in list.
auto length = m_rules . size ( ) ;
// 2. If index is greater than or equal to length, then throw an IndexSizeError exception.
if ( index > = length )
return DOM : : IndexSizeError : : create ( " CSS rule index out of bounds. " ) ;
// 3. Set old rule to the indexth item in list.
2022-06-11 18:40:06 +01:00
NonnullRefPtr < CSSRule > old_rule = m_rules [ index ] ;
2021-09-29 20:28:32 +02:00
// FIXME: 4. If old rule is an @namespace at-rule, and list contains anything other than @import at-rules, and @namespace at-rules, throw an InvalidStateError exception.
// 5. Remove rule old rule from list at the zero-indexed position index.
m_rules . remove ( index ) ;
2022-04-22 19:56:22 +01:00
// 6. Set old rule’ s parent CSS rule and parent CSS style sheet to null.
2022-06-11 18:40:06 +01:00
old_rule - > set_parent_rule ( nullptr ) ;
old_rule - > set_parent_style_sheet ( nullptr ) ;
2021-09-29 20:28:32 +02:00
return { } ;
}
2021-10-08 16:40:50 +01:00
void CSSRuleList : : for_each_effective_style_rule ( Function < void ( CSSStyleRule const & ) > const & callback ) const
{
2022-01-19 09:42:49 +01:00
for ( auto const & rule : m_rules ) {
2021-10-08 17:02:47 +01:00
switch ( rule . type ( ) ) {
2022-03-28 20:30:26 +01:00
case CSSRule : : Type : : FontFace :
2021-10-08 17:02:47 +01:00
break ;
case CSSRule : : Type : : Import : {
2022-01-19 09:42:49 +01:00
auto const & import_rule = static_cast < CSSImportRule const & > ( rule ) ;
2021-10-08 16:40:50 +01:00
if ( import_rule . has_import_result ( ) )
import_rule . loaded_style_sheet ( ) - > for_each_effective_style_rule ( callback ) ;
2021-10-08 17:02:47 +01:00
break ;
}
case CSSRule : : Type : : Media :
2022-01-19 09:42:49 +01:00
static_cast < CSSMediaRule const & > ( rule ) . for_each_effective_style_rule ( callback ) ;
2021-10-08 17:02:47 +01:00
break ;
2022-03-28 20:30:26 +01:00
case CSSRule : : Type : : Style :
callback ( static_cast < CSSStyleRule const & > ( rule ) ) ;
break ;
2021-10-08 17:48:14 +01:00
case CSSRule : : Type : : Supports :
2022-01-19 09:42:49 +01:00
static_cast < CSSSupportsRule const & > ( rule ) . for_each_effective_style_rule ( callback ) ;
2021-10-08 17:48:14 +01:00
break ;
2021-10-08 16:40:50 +01:00
}
}
}
2022-03-07 23:08:26 +01:00
bool CSSRuleList : : evaluate_media_queries ( HTML : : Window const & window )
2021-10-08 20:21:46 +01:00
{
2022-02-17 12:34:36 +00:00
bool any_media_queries_changed_match_state = false ;
2021-10-08 20:21:46 +01:00
for ( auto & rule : m_rules ) {
switch ( rule . type ( ) ) {
2022-03-28 20:30:26 +01:00
case CSSRule : : Type : : FontFace :
2021-10-08 20:21:46 +01:00
break ;
case CSSRule : : Type : : Import : {
auto & import_rule = verify_cast < CSSImportRule > ( rule ) ;
2022-02-17 12:34:36 +00:00
if ( import_rule . has_import_result ( ) & & import_rule . loaded_style_sheet ( ) - > evaluate_media_queries ( window ) )
any_media_queries_changed_match_state = true ;
2021-10-08 20:21:46 +01:00
break ;
}
case CSSRule : : Type : : Media : {
auto & media_rule = verify_cast < CSSMediaRule > ( rule ) ;
2022-02-17 12:34:36 +00:00
bool did_match = media_rule . condition_matches ( ) ;
bool now_matches = media_rule . evaluate ( window ) ;
if ( did_match ! = now_matches )
any_media_queries_changed_match_state = true ;
if ( now_matches & & media_rule . css_rules ( ) . evaluate_media_queries ( window ) )
any_media_queries_changed_match_state = true ;
2021-10-08 20:21:46 +01:00
break ;
}
2022-03-28 20:30:26 +01:00
case CSSRule : : Type : : Style :
break ;
2021-10-08 20:21:46 +01:00
case CSSRule : : Type : : Supports : {
auto & supports_rule = verify_cast < CSSSupportsRule > ( rule ) ;
2022-02-17 12:34:36 +00:00
if ( supports_rule . condition_matches ( ) & & supports_rule . css_rules ( ) . evaluate_media_queries ( window ) )
any_media_queries_changed_match_state = true ;
2021-10-08 20:21:46 +01:00
break ;
}
}
}
2022-02-17 12:34:36 +00:00
return any_media_queries_changed_match_state ;
2021-10-08 20:21:46 +01:00
}
2021-09-28 15:17:11 +01:00
}