2020-06-07 23:10:45 +02:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < andreas @ ladybird . org >
2020-06-07 23:10:45 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-06-07 23:10:45 +02:00
*/
2024-04-27 12:09:58 +12:00
# include <LibWeb/Bindings/HTMLTableRowElementPrototype.h>
2022-09-30 17:16:16 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2024-12-20 11:32:17 +01:00
# include <LibWeb/CSS/ComputedProperties.h>
2023-11-19 16:20:29 +04:00
# include <LibWeb/CSS/Parser/Parser.h>
# include <LibWeb/CSS/Parser/ParsingContext.h>
2024-08-14 16:37:02 +01:00
# include <LibWeb/CSS/StyleValues/CSSColorValue.h>
2024-08-14 11:46:56 +01:00
# include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
2023-07-07 11:42:25 +02:00
# include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
# include <LibWeb/DOM/Document.h>
2022-11-05 15:18:50 +00:00
# include <LibWeb/DOM/ElementFactory.h>
2022-02-26 11:43:52 +01:00
# include <LibWeb/DOM/HTMLCollection.h>
# include <LibWeb/HTML/HTMLTableCellElement.h>
2022-03-21 16:15:10 +01:00
# include <LibWeb/HTML/HTMLTableElement.h>
2020-07-26 15:08:16 +02:00
# include <LibWeb/HTML/HTMLTableRowElement.h>
2022-03-21 16:15:10 +01:00
# include <LibWeb/HTML/HTMLTableSectionElement.h>
2023-07-04 17:18:59 +02:00
# include <LibWeb/HTML/Parser/HTMLParser.h>
2022-11-05 15:18:50 +00:00
# include <LibWeb/Namespace.h>
2020-06-07 23:10:45 +02:00
2020-07-28 18:20:36 +02:00
namespace Web : : HTML {
2020-06-07 23:10:45 +02:00
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( HTMLTableRowElement ) ;
2023-11-19 19:47:52 +01:00
2022-02-18 21:00:52 +01:00
HTMLTableRowElement : : HTMLTableRowElement ( DOM : : Document & document , DOM : : QualifiedName qualified_name )
2021-02-07 11:20:15 +01:00
: HTMLElement ( document , move ( qualified_name ) )
2020-06-07 23:10:45 +02:00
{
}
2022-03-14 13:21:51 -06:00
HTMLTableRowElement : : ~ HTMLTableRowElement ( ) = default ;
2020-06-07 23:10:45 +02:00
2023-08-07 08:41:28 +02:00
void HTMLTableRowElement : : initialize ( JS : : Realm & realm )
2023-01-10 06:28:20 -05:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( HTMLTableRowElement ) ;
2023-01-10 06:28:20 -05:00
}
2024-12-23 17:51:10 +01:00
bool HTMLTableRowElement : : is_presentational_hint ( FlyString const & name ) const
{
if ( Base : : is_presentational_hint ( name ) )
return true ;
return first_is_one_of ( name ,
HTML : : AttributeNames : : bgcolor ,
HTML : : AttributeNames : : background ,
HTML : : AttributeNames : : height ,
HTML : : AttributeNames : : valign ) ;
}
LibWeb: Split StyleComputer work into two phases with separate outputs
Before this change, StyleComputer would essentially take a DOM element,
find all the CSS rules that apply to it, and resolve the computed value
for each CSS property for that element.
This worked great, but it meant we had to do all the work of selector
matching and cascading every time.
To enable new optimizations, this change introduces a break in the
middle of this process where we've produced a "CascadedProperties".
This object contains the result of the cascade, before we've begun
turning cascaded values into computed values.
The cascaded properties are now stored with each element, which will
later allow us to do partial updates without re-running the full
StyleComputer machine. This will be particularly valuable for
re-implementing CSS inheritance, which is extremely heavy today.
Note that CSS animations and CSS transitions operate entirely on the
computed values, even though the cascade order would have you believe
they happen earlier. I'm not confident we have the right architecture
for this, but that's a separate issue.
2024-12-12 10:06:29 +01:00
void HTMLTableRowElement : : apply_presentational_hints ( GC : : Ref < CSS : : CascadedProperties > cascaded_properties ) const
2023-07-04 17:18:59 +02:00
{
LibWeb: Split StyleComputer work into two phases with separate outputs
Before this change, StyleComputer would essentially take a DOM element,
find all the CSS rules that apply to it, and resolve the computed value
for each CSS property for that element.
This worked great, but it meant we had to do all the work of selector
matching and cascading every time.
To enable new optimizations, this change introduces a break in the
middle of this process where we've produced a "CascadedProperties".
This object contains the result of the cascade, before we've begun
turning cascaded values into computed values.
The cascaded properties are now stored with each element, which will
later allow us to do partial updates without re-running the full
StyleComputer machine. This will be particularly valuable for
re-implementing CSS inheritance, which is extremely heavy today.
Note that CSS animations and CSS transitions operate entirely on the
computed values, even though the cascade order would have you believe
they happen earlier. I'm not confident we have the right architecture
for this, but that's a separate issue.
2024-12-12 10:06:29 +01:00
Base : : apply_presentational_hints ( cascaded_properties ) ;
2023-07-04 17:18:59 +02:00
for_each_attribute ( [ & ] ( auto & name , auto & value ) {
if ( name = = HTML : : AttributeNames : : bgcolor ) {
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2:rules-for-parsing-a-legacy-colour-value
auto color = parse_legacy_color_value ( value ) ;
if ( color . has_value ( ) )
LibWeb: Split StyleComputer work into two phases with separate outputs
Before this change, StyleComputer would essentially take a DOM element,
find all the CSS rules that apply to it, and resolve the computed value
for each CSS property for that element.
This worked great, but it meant we had to do all the work of selector
matching and cascading every time.
To enable new optimizations, this change introduces a break in the
middle of this process where we've produced a "CascadedProperties".
This object contains the result of the cascade, before we've begun
turning cascaded values into computed values.
The cascaded properties are now stored with each element, which will
later allow us to do partial updates without re-running the full
StyleComputer machine. This will be particularly valuable for
re-implementing CSS inheritance, which is extremely heavy today.
Note that CSS animations and CSS transitions operate entirely on the
computed values, even though the cascade order would have you believe
they happen earlier. I'm not confident we have the right architecture
for this, but that's a separate issue.
2024-12-12 10:06:29 +01:00
cascaded_properties - > set_property_from_presentational_hint ( CSS : : PropertyID : : BackgroundColor , CSS : : CSSColorValue : : create_from_color ( color . value ( ) ) ) ;
2023-07-07 11:42:25 +02:00
} else if ( name = = HTML : : AttributeNames : : background ) {
2024-12-06 16:24:08 -05:00
// https://html.spec.whatwg.org/multipage/rendering.html#tables-2:encoding-parsing-and-serializing-a-url
2025-01-23 19:40:57 +13:00
if ( auto parsed_value = document ( ) . encoding_parse_url ( value ) ; parsed_value . has_value ( ) )
cascaded_properties - > set_property_from_presentational_hint ( CSS : : PropertyID : : BackgroundImage , CSS : : ImageStyleValue : : create ( * parsed_value ) ) ;
2024-10-01 17:45:10 +01:00
} else if ( name = = HTML : : AttributeNames : : height ) {
if ( auto parsed_value = parse_dimension_value ( value ) )
LibWeb: Split StyleComputer work into two phases with separate outputs
Before this change, StyleComputer would essentially take a DOM element,
find all the CSS rules that apply to it, and resolve the computed value
for each CSS property for that element.
This worked great, but it meant we had to do all the work of selector
matching and cascading every time.
To enable new optimizations, this change introduces a break in the
middle of this process where we've produced a "CascadedProperties".
This object contains the result of the cascade, before we've begun
turning cascaded values into computed values.
The cascaded properties are now stored with each element, which will
later allow us to do partial updates without re-running the full
StyleComputer machine. This will be particularly valuable for
re-implementing CSS inheritance, which is extremely heavy today.
Note that CSS animations and CSS transitions operate entirely on the
computed values, even though the cascade order would have you believe
they happen earlier. I'm not confident we have the right architecture
for this, but that's a separate issue.
2024-12-12 10:06:29 +01:00
cascaded_properties - > set_property_from_presentational_hint ( CSS : : PropertyID : : Height , * parsed_value ) ;
2023-11-19 16:20:29 +04:00
} else if ( name = = HTML : : AttributeNames : : valign ) {
2024-01-16 19:04:45 +01:00
if ( auto parsed_value = parse_css_value ( CSS : : Parser : : ParsingContext { document ( ) } , value , CSS : : PropertyID : : VerticalAlign ) )
LibWeb: Split StyleComputer work into two phases with separate outputs
Before this change, StyleComputer would essentially take a DOM element,
find all the CSS rules that apply to it, and resolve the computed value
for each CSS property for that element.
This worked great, but it meant we had to do all the work of selector
matching and cascading every time.
To enable new optimizations, this change introduces a break in the
middle of this process where we've produced a "CascadedProperties".
This object contains the result of the cascade, before we've begun
turning cascaded values into computed values.
The cascaded properties are now stored with each element, which will
later allow us to do partial updates without re-running the full
StyleComputer machine. This will be particularly valuable for
re-implementing CSS inheritance, which is extremely heavy today.
Note that CSS animations and CSS transitions operate entirely on the
computed values, even though the cascade order would have you believe
they happen earlier. I'm not confident we have the right architecture
for this, but that's a separate issue.
2024-12-12 10:06:29 +01:00
cascaded_properties - > set_property_from_presentational_hint ( CSS : : PropertyID : : VerticalAlign , parsed_value . release_nonnull ( ) ) ;
2023-07-04 17:18:59 +02:00
}
} ) ;
}
2022-11-24 19:03:22 +01:00
void HTMLTableRowElement : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_cells ) ;
}
2022-02-26 11:43:52 +01:00
// https://html.spec.whatwg.org/multipage/tables.html#dom-tr-cells
2024-11-15 04:01:23 +13:00
GC : : Ref < DOM : : HTMLCollection > HTMLTableRowElement : : cells ( ) const
2022-02-26 11:43:52 +01:00
{
// The cells attribute must return an HTMLCollection rooted at this tr element,
// whose filter matches only td and th elements that are children of the tr element.
2022-11-24 19:03:22 +01:00
if ( ! m_cells ) {
2023-05-23 11:25:07 +02:00
m_cells = DOM : : HTMLCollection : : create ( const_cast < HTMLTableRowElement & > ( * this ) , DOM : : HTMLCollection : : Scope : : Children , [ ] ( Element const & element ) {
return is < HTMLTableCellElement > ( element ) ;
2023-08-13 13:05:26 +02:00
} ) ;
2022-11-24 19:03:22 +01:00
}
return * m_cells ;
2022-02-26 11:43:52 +01:00
}
2022-03-21 16:15:10 +01:00
// https://html.spec.whatwg.org/multipage/tables.html#dom-tr-rowindex
int HTMLTableRowElement : : row_index ( ) const
{
// The rowIndex attribute must, if this element has a parent table element,
// or a parent tbody, thead, or tfoot element and a grandparent table element,
// return the index of this tr element in that table element's rows collection.
// If there is no such table element, then the attribute must return − 1.
2024-11-15 04:01:23 +13:00
auto rows_collection = [ & ] ( ) - > GC : : Ptr < DOM : : HTMLCollection > {
2022-03-21 16:15:10 +01:00
if ( ! parent ( ) )
return nullptr ;
if ( is < HTMLTableElement > ( * parent ( ) ) )
return const_cast < HTMLTableElement & > ( static_cast < HTMLTableElement const & > ( * parent ( ) ) ) . rows ( ) ;
if ( is < HTMLTableSectionElement > ( * parent ( ) ) & & parent ( ) - > parent ( ) & & is < HTMLTableElement > ( * parent ( ) - > parent ( ) ) )
return const_cast < HTMLTableElement & > ( static_cast < HTMLTableElement const & > ( * parent ( ) - > parent ( ) ) ) . rows ( ) ;
return nullptr ;
} ( ) ;
if ( ! rows_collection )
return - 1 ;
auto rows = rows_collection - > collect_matching_elements ( ) ;
for ( size_t i = 0 ; i < rows . size ( ) ; + + i ) {
2022-08-28 13:42:07 +02:00
if ( rows [ i ] = = this )
2022-03-21 16:15:10 +01:00
return i ;
}
return - 1 ;
}
int HTMLTableRowElement : : section_row_index ( ) const
{
// The sectionRowIndex attribute must, if this element has a parent table, tbody, thead, or tfoot element,
// return the index of the tr element in the parent element's rows collection
// (for tables, that's HTMLTableElement's rows collection; for table sections, that's HTMLTableSectionElement's rows collection).
// If there is no such parent element, then the attribute must return − 1.
2024-11-15 04:01:23 +13:00
auto rows_collection = [ & ] ( ) - > GC : : Ptr < DOM : : HTMLCollection > {
2022-03-21 16:15:10 +01:00
if ( ! parent ( ) )
return nullptr ;
if ( is < HTMLTableElement > ( * parent ( ) ) )
return const_cast < HTMLTableElement & > ( static_cast < HTMLTableElement const & > ( * parent ( ) ) ) . rows ( ) ;
if ( is < HTMLTableSectionElement > ( * parent ( ) ) )
return static_cast < HTMLTableSectionElement const & > ( * parent ( ) ) . rows ( ) ;
return nullptr ;
} ( ) ;
if ( ! rows_collection )
return - 1 ;
auto rows = rows_collection - > collect_matching_elements ( ) ;
for ( size_t i = 0 ; i < rows . size ( ) ; + + i ) {
2022-08-28 13:42:07 +02:00
if ( rows [ i ] = = this )
2022-03-21 16:15:10 +01:00
return i ;
}
return - 1 ;
}
2022-11-05 15:18:50 +00:00
// https://html.spec.whatwg.org/multipage/tables.html#dom-tr-insertcell
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < GC : : Ref < HTMLTableCellElement > > HTMLTableRowElement : : insert_cell ( i32 index )
2022-11-05 15:18:50 +00:00
{
auto cells_collection = cells ( ) ;
auto cells_collection_size = static_cast < i32 > ( cells_collection - > length ( ) ) ;
// 1. If index is less than − 1 or greater than the number of elements in the cells collection, then throw an "IndexSizeError" DOMException.
if ( index < - 1 | | index > cells_collection_size )
2024-10-12 20:56:21 +02:00
return WebIDL : : IndexSizeError : : create ( realm ( ) , " Index is negative or greater than the number of cells " _string ) ;
2022-11-05 15:18:50 +00:00
2024-12-18 17:01:03 +00:00
// 2. Let table cell be the result of creating an element given this tr element's node document, "td", and the HTML namespace.
2023-11-04 18:42:04 +01:00
auto & table_cell = static_cast < HTMLTableCellElement & > ( * TRY ( DOM : : create_element ( document ( ) , HTML : : TagNames : : td , Namespace : : HTML ) ) ) ;
2022-11-05 15:18:50 +00:00
// 3. If index is equal to − 1 or equal to the number of items in cells collection, then append table cell to this tr element.
if ( index = = - 1 | | index = = cells_collection_size )
TRY ( append_child ( table_cell ) ) ;
// 4. Otherwise, insert table cell as a child of this tr element, immediately before the indexth td or th element in the cells collection.
else
insert_before ( table_cell , cells_collection - > item ( index ) ) ;
// 5. Return table cell.
2024-11-15 04:01:23 +13:00
return GC : : Ref ( table_cell ) ;
2022-11-05 15:18:50 +00:00
}
2022-11-05 15:19:16 +00:00
// https://html.spec.whatwg.org/multipage/tables.html#dom-tr-deletecell
WebIDL : : ExceptionOr < void > HTMLTableRowElement : : delete_cell ( i32 index )
{
auto cells_collection = cells ( ) ;
auto cells_collection_size = static_cast < i32 > ( cells_collection - > length ( ) ) ;
// 1. If index is less than − 1 or greater than or equal to the number of elements in the cells collection, then throw an "IndexSizeError" DOMException.
if ( index < - 1 | | index > = cells_collection_size )
2024-10-12 20:56:21 +02:00
return WebIDL : : IndexSizeError : : create ( realm ( ) , " Index is negative or greater than or equal to the number of cells " _string ) ;
2022-11-05 15:19:16 +00:00
// 2. If index is − 1, then remove the last element in the cells collection from its parent, or do nothing if the cells collection is empty.
if ( index = = - 1 ) {
if ( cells_collection_size > 0 )
cells_collection - > item ( cells_collection_size - 1 ) - > remove ( ) ;
}
// 3. Otherwise, remove the indexth element in the cells collection from its parent.
else {
cells_collection - > item ( index ) - > remove ( ) ;
}
return { } ;
}
2020-06-07 23:10:45 +02:00
}