2020-06-04 16:06:32 +02:00
/*
2022-08-07 13:29:49 +02:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < kling @ serenityos . org >
2020-06-04 16:06:32 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-06-04 16:06:32 +02:00
*/
2022-09-09 11:08:56 +02:00
# include <AK/QuickSort.h>
2022-09-24 16:34:04 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2022-08-07 13:29:49 +02:00
# include <LibWeb/Bindings/StyleSheetListPrototype.h>
2023-05-08 06:37:18 +02:00
# include <LibWeb/CSS/StyleComputer.h>
2020-06-04 16:06:32 +02:00
# include <LibWeb/CSS/StyleSheetList.h>
2022-02-10 17:49:50 +01:00
# include <LibWeb/DOM/Document.h>
2020-06-04 16:06:32 +02:00
2020-07-21 16:23:08 +02:00
namespace Web : : CSS {
2020-06-04 16:06:32 +02:00
2022-08-07 13:14:54 +02:00
void StyleSheetList : : add_sheet ( CSSStyleSheet & sheet )
2020-06-04 16:06:32 +02:00
{
2022-08-07 13:14:54 +02:00
sheet . set_style_sheet_list ( { } , this ) ;
2022-02-10 17:49:50 +01:00
2023-03-30 11:18:50 +02:00
if ( m_sheets . is_empty ( ) ) {
// This is the first sheet, append it to the list.
m_sheets . append ( sheet ) ;
} else {
// We have sheets from before. Insert the new sheet in the correct position (DOM tree order).
bool did_insert = false ;
for ( ssize_t i = m_sheets . size ( ) - 1 ; i > = 0 ; - - i ) {
auto & existing_sheet = * m_sheets [ i ] ;
auto position = existing_sheet . owner_node ( ) - > compare_document_position ( sheet . owner_node ( ) ) ;
if ( position & DOM : : Node : : DocumentPosition : : DOCUMENT_POSITION_FOLLOWING ) {
m_sheets . insert ( i + 1 , sheet ) ;
did_insert = true ;
break ;
}
}
if ( ! did_insert )
m_sheets . prepend ( sheet ) ;
}
2022-09-09 11:08:56 +02:00
2022-10-29 14:45:17 +02:00
if ( sheet . rules ( ) . length ( ) = = 0 ) {
// NOTE: If the added sheet has no rules, we don't have to invalidate anything.
return ;
}
2023-02-26 16:09:02 -07:00
m_document - > style_computer ( ) . invalidate_rule_cache ( ) ;
m_document - > style_computer ( ) . load_fonts_from_sheet ( sheet ) ;
m_document - > invalidate_style ( ) ;
2020-06-04 16:06:32 +02:00
}
2021-09-29 23:46:16 +02:00
void StyleSheetList : : remove_sheet ( CSSStyleSheet & sheet )
{
2022-03-09 19:57:15 +01:00
sheet . set_style_sheet_list ( { } , nullptr ) ;
2022-09-09 11:08:56 +02:00
m_sheets . remove_first_matching ( [ & ] ( auto & entry ) { return entry . ptr ( ) = = & sheet ; } ) ;
2022-10-29 14:45:17 +02:00
if ( sheet . rules ( ) . length ( ) = = 0 ) {
// NOTE: If the removed sheet had no rules, we don't have to invalidate anything.
return ;
}
2022-09-09 11:08:56 +02:00
sort_sheets ( ) ;
2022-02-10 17:49:50 +01:00
2023-02-26 16:09:02 -07:00
m_document - > style_computer ( ) . invalidate_rule_cache ( ) ;
m_document - > invalidate_style ( ) ;
2021-09-29 23:46:16 +02:00
}
2023-02-14 20:30:43 +01:00
WebIDL : : ExceptionOr < JS : : NonnullGCPtr < StyleSheetList > > StyleSheetList : : create ( DOM : : Document & document )
2022-08-07 13:29:49 +02:00
{
2022-09-24 16:34:04 -06:00
auto & realm = document . realm ( ) ;
2023-02-14 20:30:43 +01:00
return MUST_OR_THROW_OOM ( realm . heap ( ) . allocate < StyleSheetList > ( realm , document ) ) ;
2022-08-07 13:29:49 +02:00
}
2020-07-26 19:37:56 +02:00
StyleSheetList : : StyleSheetList ( DOM : : Document & document )
2023-01-10 06:56:59 -05:00
: Bindings : : LegacyPlatformObject ( document . realm ( ) )
2022-08-07 13:29:49 +02:00
, m_document ( document )
{
}
2023-01-28 12:33:35 -05:00
JS : : ThrowCompletionOr < void > StyleSheetList : : initialize ( JS : : Realm & realm )
2023-01-10 06:56:59 -05:00
{
2023-01-28 12:33:35 -05:00
MUST_OR_THROW_OOM ( Base : : initialize ( realm ) ) ;
2023-01-10 06:56:59 -05:00
set_prototype ( & Bindings : : ensure_web_prototype < Bindings : : StyleSheetListPrototype > ( realm , " StyleSheetList " ) ) ;
2023-01-28 12:33:35 -05:00
return { } ;
2023-01-10 06:56:59 -05:00
}
2022-08-07 13:29:49 +02:00
void StyleSheetList : : visit_edges ( Cell : : Visitor & visitor )
2020-06-04 16:06:32 +02:00
{
2022-08-07 13:29:49 +02:00
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_document ) ;
2022-09-09 11:08:56 +02:00
for ( auto sheet : m_sheets )
visitor . visit ( sheet . ptr ( ) ) ;
2020-06-04 16:06:32 +02:00
}
2021-10-15 19:38:39 +01:00
// https://www.w3.org/TR/cssom/#ref-for-dfn-supported-property-indices%E2%91%A1
2021-09-29 13:03:09 +01:00
bool StyleSheetList : : 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 CSS style sheets represented by the collection.
// If there are no such CSS style sheets, then there are no supported property indices.
if ( m_sheets . is_empty ( ) )
return false ;
return index < m_sheets . size ( ) ;
}
2023-02-28 00:05:39 +00:00
WebIDL : : ExceptionOr < JS : : Value > StyleSheetList : : item_value ( size_t index ) const
2022-08-07 13:29:49 +02:00
{
if ( index > = m_sheets . size ( ) )
return JS : : js_undefined ( ) ;
2022-09-09 11:08:56 +02:00
return m_sheets [ index ] . ptr ( ) ;
}
void StyleSheetList : : sort_sheets ( )
{
quick_sort ( m_sheets , [ ] ( JS : : NonnullGCPtr < StyleSheet > a , JS : : NonnullGCPtr < StyleSheet > b ) {
return a - > owner_node ( ) - > is_before ( * b - > owner_node ( ) ) ;
} ) ;
2022-08-07 13:29:49 +02:00
}
2020-06-04 16:06:32 +02:00
}