From 5b7e1f59cae300f379ce6e2a80d91bc9ee639b46 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sat, 21 Dec 2024 10:41:30 -0500 Subject: [PATCH 01/36] Meta: Update GN files after #25537 --- Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn index 852a9db03f9eb1..373955b7937d66 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibGfx/BUILD.gn @@ -57,6 +57,7 @@ shared_library("LibGfx") { "Font/WOFF/Font.cpp", "Font/WOFF2/Font.cpp", "FontCascadeList.cpp", + "GlassWindowTheme.cpp", "GradientPainting.cpp", "ICC/BinaryWriter.cpp", "ICC/Enums.cpp", @@ -108,6 +109,7 @@ shared_library("LibGfx") { "Palette.cpp", "Path.cpp", "PathClipper.cpp", + "PlasticWindowTheme.cpp", "Point.cpp", "Rect.cpp", "ShareableBitmap.cpp", @@ -118,7 +120,6 @@ shared_library("LibGfx") { "TextLayout.cpp", "Triangle.cpp", "VectorGraphic.cpp", - "WindowTheme.cpp", ] sources += get_target_outputs(":generate_tiff_sources") From ee4f897b0ebd49ca20fcfa1296d94f6cf1257d54 Mon Sep 17 00:00:00 2001 From: Jim Broadbent Date: Sun, 20 Oct 2024 20:40:17 +0100 Subject: [PATCH 02/36] LibWeb/Storage: Return undefined for non-existent key/index access All tests at now pass: http://wpt.live/webstorage/defineProperty.window.html (cherry picked from commit 7a663162975a7193f1d77abf9cb0e574e4017d8e) --- Tests/LibWeb/Text/expected/localStorage.txt | 4 ++++ Tests/LibWeb/Text/input/localStorage.html | 7 +++++++ Userland/Libraries/LibWeb/HTML/Storage.cpp | 4 +++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Tests/LibWeb/Text/expected/localStorage.txt b/Tests/LibWeb/Text/expected/localStorage.txt index a5ea54de5425f7..37bc923eb44c8d 100644 --- a/Tests/LibWeb/Text/expected/localStorage.txt +++ b/Tests/LibWeb/Text/expected/localStorage.txt @@ -1,6 +1,10 @@ +undefined +null value value other other +undefined +null foo foo diff --git a/Tests/LibWeb/Text/input/localStorage.html b/Tests/LibWeb/Text/input/localStorage.html index 32715a3ecf2e62..85fc7b4df296fb 100644 --- a/Tests/LibWeb/Text/input/localStorage.html +++ b/Tests/LibWeb/Text/input/localStorage.html @@ -1,6 +1,10 @@ + diff --git a/Userland/Libraries/LibWeb/HTML/Storage.cpp b/Userland/Libraries/LibWeb/HTML/Storage.cpp index 023cad9e4319cc..c883e648460465 100644 --- a/Userland/Libraries/LibWeb/HTML/Storage.cpp +++ b/Userland/Libraries/LibWeb/HTML/Storage.cpp @@ -175,7 +175,10 @@ Optional Storage::item_value(size_t index) const { // Handle index as a string since that's our key type auto key = String::number(index); - return named_item_value(key); + auto value = get_item(key); + if (!value.has_value()) + return {}; + return JS::PrimitiveString::create(vm(), value.release_value()); } JS::Value Storage::named_item_value(FlyString const& name) const From 8046e6a8bb16b9b335edeb2d719e72e47a0f9932 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Tue, 12 Nov 2024 12:13:41 +0000 Subject: [PATCH 04/36] LibWeb: Remove LegacyOverrideBuiltIns flag from Storage This was preventing https://ubereats.com/ from fully loading, because they are attempting to overwrite setItem. They seem to be trying to add error logging to setItem if it throws, as all they do is add a try/catch block that emits an error log to their monitoring service if it throws. However, because Storage is a legacy platform object with a named property setter (setItem), it will call setItem with the stringified version of the function. This is actually expected as per the spec, Firefox (Gecko) and Epiphany (WebKit) does this too, but Chromium does not as it actually overwrites the function with the new function and does not store the stringified function. The problem is that we had the LegacyOverrideBuiltIns flag accidentally set, so it would return the stored string instead of the built-in function (hence the name), then it would try and call it and throw a "not a function" error. This prevented their JS from going any further. This fix allows their UI to fully load and be fully interactive, though it is quite slow at the moment! (cherry picked from commit faf6fd11894ac1c1d8aeeb35cb3723c66f900f1a) --- ...does-not-have-legacy-override-builtins-flag.txt | 10 ++++++++++ ...oes-not-have-legacy-override-builtins-flag.html | 14 ++++++++++++++ Userland/Libraries/LibWeb/HTML/Storage.cpp | 1 - 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Tests/LibWeb/Text/expected/HTML/storage-does-not-have-legacy-override-builtins-flag.txt create mode 100644 Tests/LibWeb/Text/input/HTML/storage-does-not-have-legacy-override-builtins-flag.html diff --git a/Tests/LibWeb/Text/expected/HTML/storage-does-not-have-legacy-override-builtins-flag.txt b/Tests/LibWeb/Text/expected/HTML/storage-does-not-have-legacy-override-builtins-flag.txt new file mode 100644 index 00000000000000..0a45f632ceb9f9 --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/storage-does-not-have-legacy-override-builtins-flag.txt @@ -0,0 +1,10 @@ +key should still be native: 'function key() { [native code] }' +key's stringified function was added to storage: 'function () { println(`FAIL: Overriden ${functionName} was called`); }' +getItem should still be native: 'function getItem() { [native code] }' +getItem's stringified function was added to storage: 'function () { println(`FAIL: Overriden ${functionName} was called`); }' +setItem should still be native: 'function setItem() { [native code] }' +setItem's stringified function was added to storage: 'function () { println(`FAIL: Overriden ${functionName} was called`); }' +removeItem should still be native: 'function removeItem() { [native code] }' +removeItem's stringified function was added to storage: 'function () { println(`FAIL: Overriden ${functionName} was called`); }' +clear should still be native: 'function clear() { [native code] }' +clear's stringified function was added to storage: 'function () { println(`FAIL: Overriden ${functionName} was called`); }' diff --git a/Tests/LibWeb/Text/input/HTML/storage-does-not-have-legacy-override-builtins-flag.html b/Tests/LibWeb/Text/input/HTML/storage-does-not-have-legacy-override-builtins-flag.html new file mode 100644 index 00000000000000..c1435cff81937d --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/storage-does-not-have-legacy-override-builtins-flag.html @@ -0,0 +1,14 @@ + + + diff --git a/Userland/Libraries/LibWeb/HTML/Storage.cpp b/Userland/Libraries/LibWeb/HTML/Storage.cpp index c883e648460465..cad70e75708e36 100644 --- a/Userland/Libraries/LibWeb/HTML/Storage.cpp +++ b/Userland/Libraries/LibWeb/HTML/Storage.cpp @@ -28,7 +28,6 @@ Storage::Storage(JS::Realm& realm) .has_indexed_property_setter = true, .has_named_property_setter = true, .has_named_property_deleter = true, - .has_legacy_override_built_ins_interface_extended_attribute = true, .indexed_property_setter_has_identifier = true, .named_property_setter_has_identifier = true, .named_property_deleter_has_identifier = true, From e878639abc2e40c99e9f847f4dc6f8404b067113 Mon Sep 17 00:00:00 2001 From: joshua stein Date: Fri, 29 Nov 2024 21:53:25 -0600 Subject: [PATCH 05/36] LibWeb: Remove a misleading duplicate comment in HTMLParser (cherry picked from commit 12442ca4308267b82e7ef81e6db1f326ee19f495) --- Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index 75272c7bd11aa1..3fa1885166a0a9 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -2378,8 +2378,6 @@ void HTMLParser::handle_in_body(HTMLToken& token) // Insert an HTML element for the token. Immediately pop the current node off the stack of open elements. (void)insert_html_element(token); - - // Acknowledge the token's self-closing flag, if it is set. (void)m_stack_of_open_elements.pop(); // Acknowledge the token's self-closing flag, if it is set. From 6d061f3aa66eaf398ca2a2d92ec62620d6d8ff34 Mon Sep 17 00:00:00 2001 From: Jonne Ransijn Date: Sat, 30 Nov 2024 18:31:04 +0100 Subject: [PATCH 06/36] LibWeb: Stop allocating `Token`s and `ComponentValue`s unnecessarily When the "Consume a component value from input, and do nothing." step in `Parser::consume_the_remnants_of_a_bad_declaration` was executed, it would allocate a `ComponentValue` that was then immediately discarded. Add explicitly `{}_and_do_nothing` functions for this case that never allocate a `ComponentValue` in the first place. Also remove a `(Token)` cast, which was unnecessarily copying a `Token` as well. (cherry picked from commit 3f5e32ee8464a3bc92bc52f12d90914fa74a5f52) --- .../Libraries/LibWeb/CSS/Parser/Parser.cpp | 133 +++++++++++++++++- Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 6 + 2 files changed, 132 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 67860c266de40d..dfd81e8c582f2a 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -695,7 +695,7 @@ ComponentValue Parser::consume_a_component_value(TokenStream& input) // Process input: for (;;) { - auto& token = input.next_token(); + auto const& token = input.next_token(); // <{-token> // <[-token> @@ -719,6 +719,52 @@ ComponentValue Parser::consume_a_component_value(TokenStream& input) } } +template<> +void Parser::consume_a_component_value_and_do_nothing(TokenStream& tokens) +{ + // AD-HOC: To avoid unnecessairy allocations, we explicitly define a "do nothing" variant that discards the result immediately. + // Note: This overload is called once tokens have already been converted into component values, + // so we do not need to do the work in the more general overload. + (void)tokens.consume_a_token(); +} + +// 5.4.7. Consume a component value +// https://drafts.csswg.org/css-syntax/#consume-component-value +template +void Parser::consume_a_component_value_and_do_nothing(TokenStream& input) +{ + // AD-HOC: To avoid unnecessairy allocations, we explicitly define a "do nothing" variant that discards the result immediately. + // To consume a component value from a token stream input: + + // Process input: + for (;;) { + auto const& token = input.next_token(); + + // <{-token> + // <[-token> + // <(-token> + if (token.is(Token::Type::OpenCurly) || token.is(Token::Type::OpenSquare) || token.is(Token::Type::OpenParen)) { + // Consume a simple block from input and return the result. + consume_a_simple_block_and_do_nothing(input); + return; + } + + // + if (token.is(Token::Type::Function)) { + // Consume a function from input and return the result. + consume_a_function_and_do_nothing(input); + return; + } + + // anything else + { + // Consume a token from input and return the result. + input.discard_a_token(); + return; + } + } +} + template Vector Parser::consume_a_list_of_component_values(TokenStream& input, Optional stop_token, Nested nested) { @@ -767,11 +813,11 @@ SimpleBlock Parser::consume_a_simple_block(TokenStream& input) // To consume a simple block from a token stream input: // Assert: the next token of input is <{-token>, <[-token>, or <(-token>. - auto& next = input.next_token(); + auto const& next = input.next_token(); VERIFY(next.is(Token::Type::OpenCurly) || next.is(Token::Type::OpenSquare) || next.is(Token::Type::OpenParen)); // Let ending token be the mirror variant of the next token. (E.g. if it was called with <[-token>, the ending token is <]-token>.) - auto ending_token = ((Token)input.next_token()).mirror_variant(); + auto ending_token = input.next_token().mirror_variant(); // Let block be a new simple block with its associated token set to the next token and with its value initially set to an empty list. SimpleBlock block { @@ -784,7 +830,7 @@ SimpleBlock Parser::consume_a_simple_block(TokenStream& input) // Process input: for (;;) { - auto& token = input.next_token(); + auto const& token = input.next_token(); // // ending token @@ -803,6 +849,45 @@ SimpleBlock Parser::consume_a_simple_block(TokenStream& input) } } +// https://drafts.csswg.org/css-syntax/#consume-simple-block +template +void Parser::consume_a_simple_block_and_do_nothing(TokenStream& input) +{ + // AD-HOC: To avoid unnecessairy allocations, we explicitly define a "do nothing" variant that discards the result immediately. + // To consume a simple block from a token stream input: + + // Assert: the next token of input is <{-token>, <[-token>, or <(-token>. + auto const& next = input.next_token(); + VERIFY(next.is(Token::Type::OpenCurly) || next.is(Token::Type::OpenSquare) || next.is(Token::Type::OpenParen)); + + // Let ending token be the mirror variant of the next token. (E.g. if it was called with <[-token>, the ending token is <]-token>.) + auto ending_token = input.next_token().mirror_variant(); + + // Let block be a new simple block with its associated token set to the next token and with its value initially set to an empty list. + + // Discard a token from input. + input.discard_a_token(); + + // Process input: + for (;;) { + auto const& token = input.next_token(); + + // + // ending token + if (token.is(Token::Type::EndOfFile) || token.is(ending_token)) { + // Discard a token from input. Return block. + input.discard_a_token(); + return; + } + + // anything else + { + // Consume a component value from input and append the result to block’s value. + consume_a_component_value_and_do_nothing(input); + } + } +} + // https://drafts.csswg.org/css-syntax/#consume-function template Function Parser::consume_a_function(TokenStream& input) @@ -823,7 +908,7 @@ Function Parser::consume_a_function(TokenStream& input) // Process input: for (;;) { - auto& token = input.next_token(); + auto const& token = input.next_token(); // // <)-token> @@ -842,6 +927,40 @@ Function Parser::consume_a_function(TokenStream& input) } } +// https://drafts.csswg.org/css-syntax/#consume-function +template +void Parser::consume_a_function_and_do_nothing(TokenStream& input) +{ + // AD-HOC: To avoid unnecessairy allocations, we explicitly define a "do nothing" variant that discards the result immediately. + // To consume a function from a token stream input: + + // Assert: The next token is a . + VERIFY(input.next_token().is(Token::Type::Function)); + + // Consume a token from input, and let function be a new function with its name equal the returned token’s value, + // and a value set to an empty list. + input.discard_a_token(); + + // Process input: + for (;;) { + auto const& token = input.next_token(); + + // + // <)-token> + if (token.is(Token::Type::EndOfFile) || token.is(Token::Type::CloseParen)) { + // Discard a token from input. Return function. + input.discard_a_token(); + return; + } + + // anything else + { + // Consume a component value from input and append the result to function’s value. + consume_a_component_value_and_do_nothing(input); + } + } +} + // https://drafts.csswg.org/css-syntax/#consume-declaration template Optional Parser::consume_a_declaration(TokenStream& input, Nested nested) @@ -990,7 +1109,7 @@ void Parser::consume_the_remnants_of_a_bad_declaration(TokenStream& input, Ne // Process input: for (;;) { - auto& token = input.next_token(); + auto const& token = input.next_token(); // // @@ -1012,7 +1131,7 @@ void Parser::consume_the_remnants_of_a_bad_declaration(TokenStream& input, Ne // anything else { // Consume a component value from input, and do nothing. - (void)consume_a_component_value(input); + consume_a_component_value_and_do_nothing(input); continue; } } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index df13eace766e1f..69fbb54ccf7cb0 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -159,9 +159,15 @@ class Parser { template [[nodiscard]] ComponentValue consume_a_component_value(TokenStream&); template + void consume_a_component_value_and_do_nothing(TokenStream&); + template SimpleBlock consume_a_simple_block(TokenStream&); template + void consume_a_simple_block_and_do_nothing(TokenStream&); + template Function consume_a_function(TokenStream&); + template + void consume_a_function_and_do_nothing(TokenStream&); // TODO: consume_a_unicode_range_value() Optional parse_general_enclosed(TokenStream&); From 84f4e2dea08c5837f401552da7810cfcf7f4b746 Mon Sep 17 00:00:00 2001 From: Jonne Ransijn Date: Sun, 1 Dec 2024 22:21:18 +0100 Subject: [PATCH 07/36] LibJS: Cache source code positions more often The source code position cache was moved from a line based approach to a "chunk"-based approach to improve performance on large, minified JavaScript files with few lines, but this has had an adverse effect on _multi-line_ source files. Reintroduce some of the old behaviour by caching lines again, with some added sanity limits to avoid caching empty/overly small lines. Source code positions in files with few lines will still be cached less often, since minified JavaScript files can be assumed to be unusually large, and since stack traces for minified JavaScript are less useful as well. On WPT tests with large JavaScript dependencies like `css/css-masking/animations/clip-interpolation.html` this reduces the amount of time spent in `SourceCode::range_from_offsets` by as much as 99.98%, for the small small price of 80KB extra memory usage. (cherry picked from commit 1b3f8e1e9ad14f0777188bd6eba06e42ffd98961) --- Userland/Libraries/LibJS/Position.h | 2 ++ Userland/Libraries/LibJS/SourceCode.cpp | 25 ++++++++++++++++--------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Userland/Libraries/LibJS/Position.h b/Userland/Libraries/LibJS/Position.h index 2491e6baacbc97..49cde905c72a2b 100644 --- a/Userland/Libraries/LibJS/Position.h +++ b/Userland/Libraries/LibJS/Position.h @@ -6,6 +6,8 @@ #pragma once +#include + namespace JS { struct Position { diff --git a/Userland/Libraries/LibJS/SourceCode.cpp b/Userland/Libraries/LibJS/SourceCode.cpp index 2fc2bd12426b62..6bff882495d9e5 100644 --- a/Userland/Libraries/LibJS/SourceCode.cpp +++ b/Userland/Libraries/LibJS/SourceCode.cpp @@ -35,26 +35,31 @@ String const& SourceCode::code() const void SourceCode::fill_position_cache() const { - constexpr size_t minimum_distance_between_cached_positions = 10000; + constexpr size_t predicted_mimimum_cached_positions = 8; + constexpr size_t minimum_distance_between_cached_positions = 32; + constexpr size_t maximum_distance_between_cached_positions = 8192; if (m_code.is_empty()) return; - bool previous_code_point_was_carriage_return = false; + u32 previous_code_point = 0; size_t line = 1; size_t column = 1; size_t offset_of_last_starting_point = 0; - m_cached_positions.ensure_capacity(m_code.bytes().size() / minimum_distance_between_cached_positions); + m_cached_positions.ensure_capacity(predicted_mimimum_cached_positions + m_code.bytes().size() / maximum_distance_between_cached_positions); m_cached_positions.append({ .line = 1, .column = 1, .offset = 0 }); Utf8View const view(m_code); for (auto it = view.begin(); it != view.end(); ++it) { u32 code_point = *it; - bool is_line_terminator = code_point == '\r' || (code_point == '\n' && !previous_code_point_was_carriage_return) || code_point == LINE_SEPARATOR || code_point == PARAGRAPH_SEPARATOR; - previous_code_point_was_carriage_return = code_point == '\r'; + bool is_line_terminator = code_point == '\r' || (code_point == '\n' && previous_code_point != '\r') || code_point == LINE_SEPARATOR || code_point == PARAGRAPH_SEPARATOR; auto byte_offset = view.byte_offset_of(it); - if ((byte_offset - offset_of_last_starting_point) >= minimum_distance_between_cached_positions) { + + bool is_nonempty_line = is_line_terminator && previous_code_point != '\n' && previous_code_point != LINE_SEPARATOR && previous_code_point != PARAGRAPH_SEPARATOR && (code_point == '\n' || previous_code_point != '\r'); + auto distance_between_cached_position = byte_offset - offset_of_last_starting_point; + + if ((distance_between_cached_position >= minimum_distance_between_cached_positions && is_nonempty_line) || distance_between_cached_position >= maximum_distance_between_cached_positions) { m_cached_positions.append({ .line = line, .column = column, .offset = byte_offset }); offset_of_last_starting_point = byte_offset; } @@ -65,6 +70,8 @@ void SourceCode::fill_position_cache() const } else { column += 1; } + + previous_code_point = code_point; } } @@ -93,7 +100,7 @@ SourceRange SourceCode::range_from_offsets(u32 start_offset, u32 end_offset) con Optional start; Optional end; - bool previous_code_point_was_carriage_return = false; + u32 previous_code_point = 0; Utf8View const view(m_code); for (auto it = view.iterator_at_byte_offset_without_validation(current.offset); it != view.end(); ++it) { @@ -119,8 +126,8 @@ SourceRange SourceCode::range_from_offsets(u32 start_offset, u32 end_offset) con u32 code_point = *it; - bool const is_line_terminator = code_point == '\r' || (code_point == '\n' && !previous_code_point_was_carriage_return) || code_point == LINE_SEPARATOR || code_point == PARAGRAPH_SEPARATOR; - previous_code_point_was_carriage_return = code_point == '\r'; + bool const is_line_terminator = code_point == '\r' || (code_point == '\n' && previous_code_point != '\r') || code_point == LINE_SEPARATOR || code_point == PARAGRAPH_SEPARATOR; + previous_code_point = code_point; if (is_line_terminator) { current.line += 1; From 8aa9b8503ae81895f8275e90945492c082ed104b Mon Sep 17 00:00:00 2001 From: Milo van der Tier Date: Sun, 1 Dec 2024 16:07:11 +0100 Subject: [PATCH 08/36] LibWeb/CSS: Do not ignore self-start/self-end alignment in flex layout This makes these values the same as `start` and `end`. While this is not entirely correct, it is better than centering which is what we did previously. This fixes misaligned images on https://nos.nl (cherry picked from commit 2ee7e555f24f04ed370630836c556a7dee6dd23a) --- Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp index b676a062536dac..9d17ed05b53385 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp @@ -1488,11 +1488,15 @@ void FlexFormattingContext::align_all_flex_items_along_the_cross_axis() // Fallthrough case CSS::AlignItems::Start: case CSS::AlignItems::FlexStart: + case CSS::AlignItems::SelfStart: case CSS::AlignItems::Stretch: + // FIXME: 'start', 'flex-start' and 'self-start' have subtly different behavior. + // The same goes for the end values. item.cross_offset = -half_line_size + item.margins.cross_before + item.borders.cross_before + item.padding.cross_before; break; case CSS::AlignItems::End: case CSS::AlignItems::FlexEnd: + case CSS::AlignItems::SelfEnd: item.cross_offset = half_line_size - item.cross_size.value() - item.margins.cross_after - item.borders.cross_after - item.padding.cross_after; break; case CSS::AlignItems::Center: From f0620408936d52162d8c695e7dbbe43a43c7a9b9 Mon Sep 17 00:00:00 2001 From: Jonne Ransijn Date: Sat, 30 Nov 2024 19:26:32 +0100 Subject: [PATCH 09/36] LibWeb: Do not normalize border radii containing their initial values Most computed border-radii contain their initial values, and since the normalized initial border radii are always zero, there is no need to do expensive floating point math to normalize them. (cherry picked from commit acaf01bf7b6bd2d952dda8d5375be8c09bd84294) --- .../Libraries/LibWeb/CSS/ComputedValues.h | 26 ++++++++++++++++--- .../LibWeb/Painting/PaintableBox.cpp | 22 +++++++++------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index 6bb8437ce97ee7..8c2f6b2d8f061f 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -455,6 +455,7 @@ class ComputedValues { BorderData const& border_right() const { return m_noninherited.border_right; } BorderData const& border_bottom() const { return m_noninherited.border_bottom; } + bool has_noninitial_border_radii() const { return m_noninherited.has_noninitial_border_radii; } const CSS::BorderRadiusData& border_bottom_left_radius() const { return m_noninherited.border_bottom_left_radius; } const CSS::BorderRadiusData& border_bottom_right_radius() const { return m_noninherited.border_bottom_right_radius; } const CSS::BorderRadiusData& border_top_left_radius() const { return m_noninherited.border_top_left_radius; } @@ -619,6 +620,7 @@ class ComputedValues { BorderData border_top; BorderData border_right; BorderData border_bottom; + bool has_noninitial_border_radii; BorderRadiusData border_bottom_left_radius; BorderRadiusData border_bottom_right_radius; BorderRadiusData border_top_left_radius; @@ -762,10 +764,26 @@ class MutableComputedValues final : public ComputedValues { void set_display(CSS::Display value) { m_noninherited.display = value; } void set_backdrop_filter(CSS::ResolvedFilter backdrop_filter) { m_noninherited.backdrop_filter = move(backdrop_filter); } void set_filter(CSS::ResolvedFilter filter) { m_noninherited.filter = move(filter); } - void set_border_bottom_left_radius(CSS::BorderRadiusData value) { m_noninherited.border_bottom_left_radius = move(value); } - void set_border_bottom_right_radius(CSS::BorderRadiusData value) { m_noninherited.border_bottom_right_radius = move(value); } - void set_border_top_left_radius(CSS::BorderRadiusData value) { m_noninherited.border_top_left_radius = move(value); } - void set_border_top_right_radius(CSS::BorderRadiusData value) { m_noninherited.border_top_right_radius = move(value); } + void set_border_bottom_left_radius(CSS::BorderRadiusData value) + { + m_noninherited.has_noninitial_border_radii = true; + m_noninherited.border_bottom_left_radius = move(value); + } + void set_border_bottom_right_radius(CSS::BorderRadiusData value) + { + m_noninherited.has_noninitial_border_radii = true; + m_noninherited.border_bottom_right_radius = move(value); + } + void set_border_top_left_radius(CSS::BorderRadiusData value) + { + m_noninherited.has_noninitial_border_radii = true; + m_noninherited.border_top_left_radius = move(value); + } + void set_border_top_right_radius(CSS::BorderRadiusData value) + { + m_noninherited.has_noninitial_border_radii = true; + m_noninherited.border_top_right_radius = move(value); + } BorderData& border_left() { return m_noninherited.border_left; } BorderData& border_top() { return m_noninherited.border_top; } BorderData& border_right() { return m_noninherited.border_right; } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index de41eef6ed99e5..7a025683b014ee 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -1087,15 +1087,19 @@ void PaintableBox::resolve_paint_properties() auto const& layout_node = this->layout_node(); // Border radii - CSSPixelRect const border_rect { 0, 0, border_box_width(), border_box_height() }; - auto const& border_top_left_radius = computed_values.border_top_left_radius(); - auto const& border_top_right_radius = computed_values.border_top_right_radius(); - auto const& border_bottom_right_radius = computed_values.border_bottom_right_radius(); - auto const& border_bottom_left_radius = computed_values.border_bottom_left_radius(); - - auto radii_data = normalize_border_radii_data(layout_node, border_rect, border_top_left_radius, - border_top_right_radius, border_bottom_right_radius, - border_bottom_left_radius); + BorderRadiiData radii_data {}; + if (computed_values.has_noninitial_border_radii()) { + CSSPixelRect const border_rect { 0, 0, border_box_width(), border_box_height() }; + + auto const& border_top_left_radius = computed_values.border_top_left_radius(); + auto const& border_top_right_radius = computed_values.border_top_right_radius(); + auto const& border_bottom_right_radius = computed_values.border_bottom_right_radius(); + auto const& border_bottom_left_radius = computed_values.border_bottom_left_radius(); + + radii_data = normalize_border_radii_data(layout_node, border_rect, border_top_left_radius, + border_top_right_radius, border_bottom_right_radius, + border_bottom_left_radius); + } set_border_radii_data(radii_data); // Box shadows From 18d00eded9ed535bf7ca8c4f1e799641d428ddd3 Mon Sep 17 00:00:00 2001 From: Sidicer Date: Sat, 24 Aug 2024 03:18:57 +0300 Subject: [PATCH 10/36] UI/Qt: Fix hover_label hiding URLs m_hover_label did not have checks if the mouse is in the same location. This caused clickable URLs to be hidden. Also shortened the label text to not be longer than half of the window. (cherry picked from commit edf29857f8f8b669c45d673b088d9c0236659d73) --- Ladybird/Qt/Tab.cpp | 18 ++++++++++++++---- Ladybird/Qt/Tab.h | 21 ++++++++++++++++++++- Ladybird/Qt/WebContentView.cpp | 1 + 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Ladybird/Qt/Tab.cpp b/Ladybird/Qt/Tab.cpp index adea6d5e9c871f..c0232206feeb9e 100644 --- a/Ladybird/Qt/Tab.cpp +++ b/Ladybird/Qt/Tab.cpp @@ -61,11 +61,15 @@ Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, St m_toolbar = new QToolBar(this); m_location_edit = new LocationEdit(this); - m_hover_label = new QLabel(this); + m_hover_label = new HyperlinkLabel(this); m_hover_label->hide(); m_hover_label->setFrameShape(QFrame::Shape::Box); m_hover_label->setAutoFillBackground(true); + QObject::connect(m_hover_label, &HyperlinkLabel::mouse_entered, [this] { + update_hover_label(); + }); + auto* focus_location_editor_action = new QAction("Edit Location", this); focus_location_editor_action->setShortcut(QKeySequence("Ctrl+L")); addAction(focus_location_editor_action); @@ -862,12 +866,18 @@ void Tab::resizeEvent(QResizeEvent* event) void Tab::update_hover_label() { + m_hover_label->setText(QFontMetrics(m_hover_label->font()).elidedText(m_hover_label->text(), Qt::ElideRight, width() / 2 - 10)); m_hover_label->resize(QFontMetrics(m_hover_label->font()).boundingRect(m_hover_label->text()).adjusted(-4, -2, 4, 2).size()); - auto hover_label_height = height() - m_hover_label->height() - 8; + + auto hover_label_height = height() - m_hover_label->height(); if (m_find_in_page->isVisible()) - hover_label_height -= m_find_in_page->height() - 4; + hover_label_height -= m_find_in_page->height(); + + if (m_hover_label->underMouse() && m_hover_label->x() == 0) + m_hover_label->move(width() / 2 + (width() / 2 - m_hover_label->width()), hover_label_height); + else + m_hover_label->move(0, hover_label_height); - m_hover_label->move(6, hover_label_height); m_hover_label->raise(); } diff --git a/Ladybird/Qt/Tab.h b/Ladybird/Qt/Tab.h index 1b3cf66f4489bd..45bc455562c350 100644 --- a/Ladybird/Qt/Tab.h +++ b/Ladybird/Qt/Tab.h @@ -25,6 +25,25 @@ namespace Ladybird { class BrowserWindow; class InspectorWidget; +class HyperlinkLabel final : public QLabel { + Q_OBJECT + +public: + explicit HyperlinkLabel(QWidget* parent = nullptr) + : QLabel(parent) + { + setMouseTracking(true); + } + + virtual void enterEvent(QEnterEvent* event) override + { + emit mouse_entered(event); + } + +signals: + void mouse_entered(QEnterEvent*); +}; + class Tab final : public QWidget { Q_OBJECT @@ -114,7 +133,7 @@ public slots: FindInPageWidget* m_find_in_page { nullptr }; BrowserWindow* m_window { nullptr }; QString m_title; - QLabel* m_hover_label { nullptr }; + HyperlinkLabel* m_hover_label { nullptr }; QIcon m_favicon; QMenu* m_context_menu { nullptr }; diff --git a/Ladybird/Qt/WebContentView.cpp b/Ladybird/Qt/WebContentView.cpp index fbb9b2645e931b..8a093319d32e13 100644 --- a/Ladybird/Qt/WebContentView.cpp +++ b/Ladybird/Qt/WebContentView.cpp @@ -423,6 +423,7 @@ void WebContentView::mouseMoveEvent(QMouseEvent* event) } enqueue_native_event(Web::MouseEvent::Type::MouseMove, *event); + QWidget::mouseMoveEvent(event); } void WebContentView::mousePressEvent(QMouseEvent* event) From 058d3edc694a2a0194fc0061821e1045a3bbc83d Mon Sep 17 00:00:00 2001 From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com> Date: Fri, 29 Nov 2024 21:49:57 +0100 Subject: [PATCH 11/36] Tests: Make test less flaky This increases the animation length on this test as it has been failing for me locally. (cherry picked from commit 366f15b441abb2c3c3b244188edaa86e10712dcd) --- .../Ref/css-keyframe-invalid-transform-should-not-render.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/LibWeb/Ref/css-keyframe-invalid-transform-should-not-render.html b/Tests/LibWeb/Ref/css-keyframe-invalid-transform-should-not-render.html index 19b1aa37dec743..4a87ec62de27f3 100644 --- a/Tests/LibWeb/Ref/css-keyframe-invalid-transform-should-not-render.html +++ b/Tests/LibWeb/Ref/css-keyframe-invalid-transform-should-not-render.html @@ -5,7 +5,7 @@ width: 100px; height: 100px; background-color: blue; - animation: anim 1s; + animation: anim 100s; } @keyframes anim { from { @@ -18,5 +18,5 @@
From 4b5f6289e643e8af3655a88cde96d5a91caf95c8 Mon Sep 17 00:00:00 2001 From: Luke Warlow Date: Thu, 5 Dec 2024 23:13:17 +0000 Subject: [PATCH 12/36] LibWeb: Remove :closed pseudo class This was removed from the spec. (cherry picked from commit 7c9a162f994caeeeaf8ca3bfcc4a75bee1609b91) --- Tests/LibWeb/Ref/css-open-closed-selectors.html | 3 --- .../LibWeb/Ref/reference/css-open-closed-selectors-ref.html | 5 +---- Userland/Libraries/LibWeb/CSS/PseudoClasses.json | 3 --- Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp | 1 - 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Tests/LibWeb/Ref/css-open-closed-selectors.html b/Tests/LibWeb/Ref/css-open-closed-selectors.html index 2845e8366e533a..1c11d631d32941 100644 --- a/Tests/LibWeb/Ref/css-open-closed-selectors.html +++ b/Tests/LibWeb/Ref/css-open-closed-selectors.html @@ -4,9 +4,6 @@ :open { color: green; } -:closed { - color: red; -}
Hi diff --git a/Tests/LibWeb/Ref/reference/css-open-closed-selectors-ref.html b/Tests/LibWeb/Ref/reference/css-open-closed-selectors-ref.html index 4dd0e89ae4bf9a..f169657966d294 100644 --- a/Tests/LibWeb/Ref/reference/css-open-closed-selectors-ref.html +++ b/Tests/LibWeb/Ref/reference/css-open-closed-selectors-ref.html @@ -3,15 +3,12 @@ .open { color: green; } - .closed { - color: red; - }
Hi Well hello friends!
-
+
Hi Well hello friends!
diff --git a/Userland/Libraries/LibWeb/CSS/PseudoClasses.json b/Userland/Libraries/LibWeb/CSS/PseudoClasses.json index 6a199cc2b99e80..ecc2055050eda9 100644 --- a/Userland/Libraries/LibWeb/CSS/PseudoClasses.json +++ b/Userland/Libraries/LibWeb/CSS/PseudoClasses.json @@ -11,9 +11,6 @@ "checked": { "argument": "" }, - "closed": { - "argument": "" - }, "defined": { "argument": "" }, diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp index 5e7d2836e60b77..6a2857c3cb1eb1 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -659,7 +659,6 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla return false; } case CSS::PseudoClass::Open: - case CSS::PseudoClass::Closed: return matches_open_state_pseudo_class(element, pseudo_class.type == CSS::PseudoClass::Open); case CSS::PseudoClass::Modal: { // https://drafts.csswg.org/selectors/#modal-state From 8efc228bdeaac754d658dff7fbda52807abe6fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Mu=C3=B1oz=20Mazur?= Date: Fri, 6 Dec 2024 18:12:29 -0400 Subject: [PATCH 13/36] LibWeb: Handle abort signal in CloseWatcher (cherry picked from commit e27c59047a0deebf132ab0822db32cfe064c14ad) --- .../CloseWatcher-abort-requestClose.txt | 2 ++ .../expected/CloseWatcher-already-aborted.txt | 2 ++ .../Text/expected/CloseWatcher-fire-once.txt | 2 ++ .../input/CloseWatcher-abort-requestClose.html | 18 ++++++++++++++++++ .../input/CloseWatcher-already-aborted.html | 17 +++++++++++++++++ .../Text/input/CloseWatcher-fire-once.html | 18 ++++++++++++++++++ .../Libraries/LibWeb/HTML/CloseWatcher.cpp | 15 ++++++++++++--- 7 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/CloseWatcher-abort-requestClose.txt create mode 100644 Tests/LibWeb/Text/expected/CloseWatcher-already-aborted.txt create mode 100644 Tests/LibWeb/Text/expected/CloseWatcher-fire-once.txt create mode 100644 Tests/LibWeb/Text/input/CloseWatcher-abort-requestClose.html create mode 100644 Tests/LibWeb/Text/input/CloseWatcher-already-aborted.html create mode 100644 Tests/LibWeb/Text/input/CloseWatcher-fire-once.html diff --git a/Tests/LibWeb/Text/expected/CloseWatcher-abort-requestClose.txt b/Tests/LibWeb/Text/expected/CloseWatcher-abort-requestClose.txt new file mode 100644 index 00000000000000..4b095fd0ff9ca0 --- /dev/null +++ b/Tests/LibWeb/Text/expected/CloseWatcher-abort-requestClose.txt @@ -0,0 +1,2 @@ +false +false diff --git a/Tests/LibWeb/Text/expected/CloseWatcher-already-aborted.txt b/Tests/LibWeb/Text/expected/CloseWatcher-already-aborted.txt new file mode 100644 index 00000000000000..4b095fd0ff9ca0 --- /dev/null +++ b/Tests/LibWeb/Text/expected/CloseWatcher-already-aborted.txt @@ -0,0 +1,2 @@ +false +false diff --git a/Tests/LibWeb/Text/expected/CloseWatcher-fire-once.txt b/Tests/LibWeb/Text/expected/CloseWatcher-fire-once.txt new file mode 100644 index 00000000000000..6ed281c757a969 --- /dev/null +++ b/Tests/LibWeb/Text/expected/CloseWatcher-fire-once.txt @@ -0,0 +1,2 @@ +1 +1 diff --git a/Tests/LibWeb/Text/input/CloseWatcher-abort-requestClose.html b/Tests/LibWeb/Text/input/CloseWatcher-abort-requestClose.html new file mode 100644 index 00000000000000..36bb3747e7a6ec --- /dev/null +++ b/Tests/LibWeb/Text/input/CloseWatcher-abort-requestClose.html @@ -0,0 +1,18 @@ + + + diff --git a/Tests/LibWeb/Text/input/CloseWatcher-already-aborted.html b/Tests/LibWeb/Text/input/CloseWatcher-already-aborted.html new file mode 100644 index 00000000000000..722b3ed59cbac0 --- /dev/null +++ b/Tests/LibWeb/Text/input/CloseWatcher-already-aborted.html @@ -0,0 +1,17 @@ + + + diff --git a/Tests/LibWeb/Text/input/CloseWatcher-fire-once.html b/Tests/LibWeb/Text/input/CloseWatcher-fire-once.html new file mode 100644 index 00000000000000..a2f08d41c4ecb6 --- /dev/null +++ b/Tests/LibWeb/Text/input/CloseWatcher-fire-once.html @@ -0,0 +1,18 @@ + + + diff --git a/Userland/Libraries/LibWeb/HTML/CloseWatcher.cpp b/Userland/Libraries/LibWeb/HTML/CloseWatcher.cpp index d1a5f2d8062673..80e656e63ea5d4 100644 --- a/Userland/Libraries/LibWeb/HTML/CloseWatcher.cpp +++ b/Userland/Libraries/LibWeb/HTML/CloseWatcher.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, the Ladybird developers. + * Copyright (c) 2024, Felipe Muñoz Mazur * * SPDX-License-Identifier: BSD-2-Clause */ @@ -57,9 +58,17 @@ WebIDL::ExceptionOr> CloseWatcher::construct_impl auto close_watcher = establish(window); // 3. If options["signal"] exists, then: - if (options.signal) { - // FIXME: 3.1 If options["signal"]'s aborted, then destroy closeWatcher. - // FIXME: 3.2 Add the following steps to options["signal"]: + if (auto signal = options.signal) { + // 3.1 If options["signal"]'s aborted, then destroy closeWatcher. + if (signal->aborted()) { + close_watcher->destroy(); + } + + // 3.2 Add the following steps to options["signal"]: + signal->add_abort_algorithm([close_watcher] { + // 3.2.1 Destroy closeWatcher. + close_watcher->destroy(); + }); } return close_watcher; From 9f44f9eebeb888102caf6cc07fb86bff3461931d Mon Sep 17 00:00:00 2001 From: Pavel Shliak Date: Sun, 8 Dec 2024 14:49:10 +0400 Subject: [PATCH 14/36] LibCore: Do not include math.h in ArgsParser (cherry picked from commit 6ec06a01a2e3bd8397716fcfac6d301ab09c63bc) --- Userland/Libraries/LibCore/ArgsParser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Userland/Libraries/LibCore/ArgsParser.cpp b/Userland/Libraries/LibCore/ArgsParser.cpp index b318178c58d051..fd764bbaad415e 100644 --- a/Userland/Libraries/LibCore/ArgsParser.cpp +++ b/Userland/Libraries/LibCore/ArgsParser.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include From cdf5cac3e956c0f3a06d71614eecdc2662017166 Mon Sep 17 00:00:00 2001 From: R-Goc Date: Thu, 21 Nov 2024 20:22:23 +0100 Subject: [PATCH 15/36] LibCrypto: Use size_t integer literal (cherry picked from commit 3e69794c7d78e30591d62b4455a32e8a7ec0f052) --- Userland/Libraries/LibCrypto/ASN1/DER.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibCrypto/ASN1/DER.cpp b/Userland/Libraries/LibCrypto/ASN1/DER.cpp index c7ad2d4e525f39..642cd2b1598900 100644 --- a/Userland/Libraries/LibCrypto/ASN1/DER.cpp +++ b/Userland/Libraries/LibCrypto/ASN1/DER.cpp @@ -265,7 +265,7 @@ ErrorOr Encoder::write_length(size_t value) double minimum_bits = AK::log2(value); size_t size_in_bits = AK::floor(minimum_bits) + 1; - size_t size = ceil_div(size_in_bits, 8ul); + size_t size = ceil_div(size_in_bits, 8z); TRY(write_byte(0x80 | size)); for (size_t i = 0; i < size; i++) { @@ -433,7 +433,7 @@ ErrorOr Encoder::write_bit_string(BitStringView view, Optional clas auto total_size_in_bits = view.byte_length() * 8 - unused_bits; TRY(write_tag(class_, type, kind)); - TRY(write_length(ceil_div(total_size_in_bits, 8ul) + 1)); + TRY(write_length(ceil_div(total_size_in_bits, 8z) + 1)); TRY(write_byte(unused_bits)); return write_bytes(view.underlying_bytes()); } From 5fead97193b58baac8e5bcedb186574ebb60fe68 Mon Sep 17 00:00:00 2001 From: R-Goc Date: Thu, 21 Nov 2024 22:05:08 +0100 Subject: [PATCH 16/36] LibCrypto: DER.cpp use uz literals (cherry picked from commit e2b6ab4a699a01981f7c369d845173263e7e2801) --- Userland/Libraries/LibCrypto/ASN1/DER.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibCrypto/ASN1/DER.cpp b/Userland/Libraries/LibCrypto/ASN1/DER.cpp index 642cd2b1598900..3d4489fedac348 100644 --- a/Userland/Libraries/LibCrypto/ASN1/DER.cpp +++ b/Userland/Libraries/LibCrypto/ASN1/DER.cpp @@ -265,7 +265,7 @@ ErrorOr Encoder::write_length(size_t value) double minimum_bits = AK::log2(value); size_t size_in_bits = AK::floor(minimum_bits) + 1; - size_t size = ceil_div(size_in_bits, 8z); + size_t size = ceil_div(size_in_bits, 8uz); TRY(write_byte(0x80 | size)); for (size_t i = 0; i < size; i++) { @@ -433,7 +433,7 @@ ErrorOr Encoder::write_bit_string(BitStringView view, Optional clas auto total_size_in_bits = view.byte_length() * 8 - unused_bits; TRY(write_tag(class_, type, kind)); - TRY(write_length(ceil_div(total_size_in_bits, 8z) + 1)); + TRY(write_length(ceil_div(total_size_in_bits, 8uz) + 1)); TRY(write_byte(unused_bits)); return write_bytes(view.underlying_bytes()); } From 7a5635e9702319727ef703fb1731f8e8c4a50926 Mon Sep 17 00:00:00 2001 From: Pavel Shliak Date: Sun, 8 Dec 2024 19:58:50 +0400 Subject: [PATCH 17/36] LibWasm: Respect instance.types() bounds (cherry picked from commit e08f6a69b2e7cfcc363098555b5d90a0aab7e73c) --- Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index 5cda3d023f6152..6eee40dce1200a 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -17,7 +17,7 @@ namespace Wasm { Optional Store::allocate(ModuleInstance& instance, Module const& module, CodeSection::Code const& code, TypeIndex type_index) { FunctionAddress address { m_functions.size() }; - if (type_index.value() > instance.types().size()) + if (type_index.value() >= instance.types().size()) return {}; auto& type = instance.types()[type_index.value()]; From 1e0b3ad1ccb49236fc3e655dc6ba5bafa1d53e38 Mon Sep 17 00:00:00 2001 From: Pavel Shliak Date: Mon, 9 Dec 2024 22:08:51 +0400 Subject: [PATCH 18/36] LibWeb: Align mfrac Padding with Updated MathML Core Spec This aligns with the transition from the MathML Core Working Draft (27 November 2023) to the Editor's Draft (26 November 2024). (cherry picked from commit 10311fba87e3d2ef7029c10dc72524bcc45ada2d) --- Userland/Libraries/LibWeb/MathML/Default.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Userland/Libraries/LibWeb/MathML/Default.css b/Userland/Libraries/LibWeb/MathML/Default.css index 1104b7fb3979a4..75a654be5a640b 100644 --- a/Userland/Libraries/LibWeb/MathML/Default.css +++ b/Userland/Libraries/LibWeb/MathML/Default.css @@ -71,8 +71,7 @@ mtd { /* Fractions */ mfrac { - padding-inline-start: 1px; - padding-inline-end: 1px; + padding-inline: 1px; } mfrac > * { math-depth: auto-add; From fe61a7b8b820538e7c6d27fda1554f300bd4372a Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Mon, 9 Dec 2024 22:04:12 +0000 Subject: [PATCH 19/36] LibWeb: Respect subarrays in Crypto#getRandomBytes It is the responsibility of code that deals with TypedArrays to apply the byte offset and byte length. Not doing this caused Unity Web to crash, as they call getRandomValues with views into their full main memory. Previously, it would fill their entire memory of about 33.5 MB with random bytes. (cherry picked from commit 023c3aa5b091605316bf87a9fc516e54d03e5874) --- .../Crypto-getRandomValues-respects-subarrays.txt | 2 ++ .../Crypto-getRandomValues-respects-subarrays.html | 11 +++++++++++ Userland/Libraries/LibWeb/Crypto/Crypto.cpp | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 Tests/LibWeb/Text/expected/Crypto/Crypto-getRandomValues-respects-subarrays.txt create mode 100644 Tests/LibWeb/Text/input/Crypto/Crypto-getRandomValues-respects-subarrays.html diff --git a/Tests/LibWeb/Text/expected/Crypto/Crypto-getRandomValues-respects-subarrays.txt b/Tests/LibWeb/Text/expected/Crypto/Crypto-getRandomValues-respects-subarrays.txt new file mode 100644 index 00000000000000..e0a8ef819ca181 --- /dev/null +++ b/Tests/LibWeb/Text/expected/Crypto/Crypto-getRandomValues-respects-subarrays.txt @@ -0,0 +1,2 @@ +Is first 2 bytes still 0x41? true +Is last 6 bytes still 0x41? true diff --git a/Tests/LibWeb/Text/input/Crypto/Crypto-getRandomValues-respects-subarrays.html b/Tests/LibWeb/Text/input/Crypto/Crypto-getRandomValues-respects-subarrays.html new file mode 100644 index 00000000000000..e5ac90ba033bec --- /dev/null +++ b/Tests/LibWeb/Text/input/Crypto/Crypto-getRandomValues-respects-subarrays.html @@ -0,0 +1,11 @@ + + + diff --git a/Userland/Libraries/LibWeb/Crypto/Crypto.cpp b/Userland/Libraries/LibWeb/Crypto/Crypto.cpp index 8485d3c7408c3c..12dc7a2bba3c73 100644 --- a/Userland/Libraries/LibWeb/Crypto/Crypto.cpp +++ b/Userland/Libraries/LibWeb/Crypto/Crypto.cpp @@ -68,7 +68,7 @@ WebIDL::ExceptionOr> Crypto::get_random_valu // FIXME: Handle SharedArrayBuffers // 3. Overwrite all elements of array with cryptographically strong random values of the appropriate type. - fill_with_random(array->viewed_array_buffer()->buffer()); + fill_with_random(array->viewed_array_buffer()->buffer().bytes().slice(array->byte_offset(), array->byte_length())); // 4. Return array. return array; From 013f8b9b859a646ff15485abcbebdcd9f2861887 Mon Sep 17 00:00:00 2001 From: Simek Date: Mon, 9 Dec 2024 00:56:14 +0100 Subject: [PATCH 20/36] LibWeb/ARIA: Add missing `menuitemradio` widget role (cherry picked from commit a64432ec130ba1ea2d0ef97f80af4f0393dd1901) --- Userland/Libraries/LibWeb/ARIA/Roles.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Userland/Libraries/LibWeb/ARIA/Roles.cpp b/Userland/Libraries/LibWeb/ARIA/Roles.cpp index 823959c96ec128..aa2e182905049b 100644 --- a/Userland/Libraries/LibWeb/ARIA/Roles.cpp +++ b/Userland/Libraries/LibWeb/ARIA/Roles.cpp @@ -69,6 +69,7 @@ bool is_widget_role(Role role) Role::link, Role::menuitem, Role::menuitemcheckbox, + Role::menuitemradio, Role::option, Role::progressbar, Role::radio, From e0a4bb64006e07e507a0d9eaf3b1be43800e005c Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Wed, 11 Dec 2024 16:43:01 +0100 Subject: [PATCH 21/36] LibWeb: Update spec steps in Selection Resolves two FIXMEs in `::collapse()` and `::select_all_children()`. (cherry picked from commit d14fd8a6c88688349b015e5cafa4d7055bc34ad1) --- .../Libraries/LibWeb/Selection/Selection.cpp | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/Userland/Libraries/LibWeb/Selection/Selection.cpp b/Userland/Libraries/LibWeb/Selection/Selection.cpp index a4b084f6ab62a3..6b6496ebfa4fbe 100644 --- a/Userland/Libraries/LibWeb/Selection/Selection.cpp +++ b/Userland/Libraries/LibWeb/Selection/Selection.cpp @@ -193,28 +193,25 @@ WebIDL::ExceptionOr Selection::collapse(JS::GCPtr node, unsigne return {}; } - // FIXME: Update this to match the spec once the spec is updated. - // Spec PR: https://github.com/w3c/selection-api/pull/342 - if (node->is_document_type()) { + // 2. If node is a DocumentType, throw an InvalidNodeTypeError exception and abort these steps. + if (node->is_document_type()) return WebIDL::InvalidNodeTypeError::create(realm(), "Selection.collapse() with DocumentType node"_string); - } - // 2. The method must throw an IndexSizeError exception if offset is longer than node's length and abort these steps. - if (offset > node->length()) { + // 3. The method must throw an IndexSizeError exception if offset is longer than node's length and abort these steps. + if (offset > node->length()) return WebIDL::IndexSizeError::create(realm(), "Selection.collapse() with offset longer than node's length"_string); - } - // 3. If document associated with this is not a shadow-including inclusive ancestor of node, abort these steps. + // 4. If document associated with this is not a shadow-including inclusive ancestor of node, abort these steps. if (!m_document->is_shadow_including_inclusive_ancestor_of(*node)) return {}; - // 4. Otherwise, let newRange be a new range. + // 5. Otherwise, let newRange be a new range. auto new_range = DOM::Range::create(*m_document); - // 5. Set the start the start and the end of newRange to (node, offset). + // 6. Set the start the start and the end of newRange to (node, offset). TRY(new_range->set_start(*node, offset)); - // 6. Set this's range to newRange. + // 7. Set this's range to newRange. set_range(new_range); return {}; @@ -364,30 +361,28 @@ WebIDL::ExceptionOr Selection::set_base_and_extent(JS::NonnullGCPtr Selection::select_all_children(JS::NonnullGCPtr node) { - // FIXME: Update this to match the spec once the spec is updated. - // Spec PR: https://github.com/w3c/selection-api/pull/342 - if (node->is_document_type()) { + // 1. If node is a DocumentType, throw an InvalidNodeTypeError exception and abort these steps. + if (node->is_document_type()) return WebIDL::InvalidNodeTypeError::create(realm(), "Selection.selectAllChildren() with DocumentType node"_string); - } - // 1. If node's root is not the document associated with this, abort these steps. + // 2. If node's root is not the document associated with this, abort these steps. if (&node->root() != m_document.ptr()) return {}; - // 2. Let newRange be a new range and childCount be the number of children of node. + // 3. Let newRange be a new range and childCount be the number of children of node. auto new_range = DOM::Range::create(*m_document); auto child_count = node->child_count(); - // 3. Set newRange's start to (node, 0). + // 4. Set newRange's start to (node, 0). TRY(new_range->set_start(node, 0)); - // 4. Set newRange's end to (node, childCount). + // 5. Set newRange's end to (node, childCount). TRY(new_range->set_end(node, child_count)); - // 5. Set this's range to newRange. + // 6. Set this's range to newRange. set_range(new_range); - // 6. Set this's direction to forwards. + // 7. Set this's direction to forwards. m_direction = Direction::Forwards; return {}; From 7198c3ccd0268eeb5f8520f1700465d365469f71 Mon Sep 17 00:00:00 2001 From: Manuel Zahariev Date: Thu, 5 Dec 2024 14:25:35 -0800 Subject: [PATCH 22/36] LibWeb: Layout standalone SVG document with specified dimensions Before, standalone SVG documents were stretched to fit the agent viewport. (cherry picked from commit f5e01192cce526a61d09d364222852ac1937bce8) --- .../LibWeb/Layout/SVGFormattingContext.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp index 032e5acd5098ca..9032e25f6c1f4d 100644 --- a/Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -178,6 +179,18 @@ void SVGFormattingContext::run(AvailableSpace const& available_space) auto& svg_viewport = dynamic_cast(*context_box().dom_node()); auto& svg_box_state = m_state.get_mutable(context_box()); + if (!this->context_box().root().document().is_decoded_svg()) { + // Overwrite the content width/height with the styled node width/height (from ) + + // NOTE: If a height had not been provided by the svg element, it was set to the height of the container + // (see BlockFormattingContext::layout_viewport) + if (svg_box_state.node().computed_values().width().is_length()) + svg_box_state.set_content_width(svg_box_state.node().computed_values().width().length().to_px(svg_box_state.node())); + if (svg_box_state.node().computed_values().height().is_length()) + svg_box_state.set_content_height(svg_box_state.node().computed_values().height().length().to_px(svg_box_state.node())); + // FIXME: In SVG 2, length can also be a percentage. We'll need to support that. + } + // NOTE: We consider all SVG root elements to have definite size in both axes. // I'm not sure if this is good or bad, but our viewport transform logic depends on it. svg_box_state.set_has_definite_width(true); From e33ec0750795bce9b9a21f10cfd8b918f3677fa6 Mon Sep 17 00:00:00 2001 From: Manuel Zahariev Date: Thu, 5 Dec 2024 20:41:16 -0800 Subject: [PATCH 23/36] LibWeb: Test layout of standalone SVG document: main use case SVG document with specified width and height attributes is layed out with this width/height. (cherry picked from commit 5d77104c2f214f0a78d936c014cea21335083eaf) --- Tests/LibWeb/Layout/expected/svg/standalone.txt | 17 +++++++++++++++++ Tests/LibWeb/Layout/input/svg/standalone.svg | 7 +++++++ 2 files changed, 24 insertions(+) create mode 100644 Tests/LibWeb/Layout/expected/svg/standalone.txt create mode 100644 Tests/LibWeb/Layout/input/svg/standalone.svg diff --git a/Tests/LibWeb/Layout/expected/svg/standalone.txt b/Tests/LibWeb/Layout/expected/svg/standalone.txt new file mode 100644 index 00000000000000..a7b14e7bf2b224 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/svg/standalone.txt @@ -0,0 +1,17 @@ +Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline + SVGSVGBox at (0,0) content-size 128x256 [SVG] children: inline + TextNode <#text> + TextNode <#text> + SVGGeometryBox at (0,0) content-size 128x256 children: not-inline + TextNode <#text> + SVGGraphicsBox at (0,0) content-size 128x256 children: inline + TextNode <#text> + SVGGeometryBox at (0,0) content-size 128x256 children: not-inline + TextNode <#text> + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + SVGSVGPaintable (SVGSVGBox) [0,0 128x256] + SVGPathPaintable (SVGGeometryBox) [0,0 128x256] + SVGGraphicsPaintable (SVGGraphicsBox) [0,0 128x256] + SVGPathPaintable (SVGGeometryBox) [0,0 128x256] diff --git a/Tests/LibWeb/Layout/input/svg/standalone.svg b/Tests/LibWeb/Layout/input/svg/standalone.svg new file mode 100644 index 00000000000000..463f07a77e3be5 --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/standalone.svg @@ -0,0 +1,7 @@ + + white diamond on blue + + + + + From d8654c3361506b49f852f33d6be3291334d060d3 Mon Sep 17 00:00:00 2001 From: Manuel Zahariev Date: Thu, 5 Dec 2024 20:44:44 -0800 Subject: [PATCH 24/36] LibWeb: Test layout of standalone SVG document: edge cases Tests with different combinations of missing width, height and viewBox. All tests confirmed to work on Ladybird: - exactly the same as Chromium (131.0.6778.85) - almost the same as Firefox (129.0.2) - only difference: standalone-w.svg: same size, different alignment (cherry picked from commit 5d85f3a5c8c7fa5631ca5ece3f1ed95c68e480c4) --- .../Layout/expected/svg/standalone-h.txt | 18 ++++++++++++++++++ .../Layout/expected/svg/standalone-vb-h.txt | 18 ++++++++++++++++++ .../Layout/expected/svg/standalone-vb-w.txt | 18 ++++++++++++++++++ .../Layout/expected/svg/standalone-vb-wh.txt | 18 ++++++++++++++++++ .../Layout/expected/svg/standalone-vb.txt | 18 ++++++++++++++++++ .../Layout/expected/svg/standalone-w.txt | 18 ++++++++++++++++++ .../Layout/expected/svg/standalone-wh.txt | 18 ++++++++++++++++++ Tests/LibWeb/Layout/input/svg/standalone-h.svg | 7 +++++++ .../Layout/input/svg/standalone-vb-h.svg | 7 +++++++ .../Layout/input/svg/standalone-vb-w.svg | 7 +++++++ .../Layout/input/svg/standalone-vb-wh.svg | 7 +++++++ .../LibWeb/Layout/input/svg/standalone-vb.svg | 7 +++++++ Tests/LibWeb/Layout/input/svg/standalone-w.svg | 13 +++++++++++++ .../LibWeb/Layout/input/svg/standalone-wh.svg | 7 +++++++ 14 files changed, 181 insertions(+) create mode 100644 Tests/LibWeb/Layout/expected/svg/standalone-h.txt create mode 100644 Tests/LibWeb/Layout/expected/svg/standalone-vb-h.txt create mode 100644 Tests/LibWeb/Layout/expected/svg/standalone-vb-w.txt create mode 100644 Tests/LibWeb/Layout/expected/svg/standalone-vb-wh.txt create mode 100644 Tests/LibWeb/Layout/expected/svg/standalone-vb.txt create mode 100644 Tests/LibWeb/Layout/expected/svg/standalone-w.txt create mode 100644 Tests/LibWeb/Layout/expected/svg/standalone-wh.txt create mode 100644 Tests/LibWeb/Layout/input/svg/standalone-h.svg create mode 100644 Tests/LibWeb/Layout/input/svg/standalone-vb-h.svg create mode 100644 Tests/LibWeb/Layout/input/svg/standalone-vb-w.svg create mode 100644 Tests/LibWeb/Layout/input/svg/standalone-vb-wh.svg create mode 100644 Tests/LibWeb/Layout/input/svg/standalone-vb.svg create mode 100644 Tests/LibWeb/Layout/input/svg/standalone-w.svg create mode 100644 Tests/LibWeb/Layout/input/svg/standalone-wh.svg diff --git a/Tests/LibWeb/Layout/expected/svg/standalone-h.txt b/Tests/LibWeb/Layout/expected/svg/standalone-h.txt new file mode 100644 index 00000000000000..4c1cbf64e89090 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/svg/standalone-h.txt @@ -0,0 +1,18 @@ +Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline + SVGSVGBox at (0,0) content-size 128x600 [SVG] children: inline + TextNode <#text> + TextNode <#text> + SVGGeometryBox at (0,172) content-size 128x256 children: not-inline + TextNode <#text> + SVGGraphicsBox at (0,172) content-size 128x256 children: inline + TextNode <#text> + SVGGeometryBox at (0,172) content-size 128x256 children: not-inline + TextNode <#text> + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + SVGSVGPaintable (SVGSVGBox) [0,0 128x600] + SVGPathPaintable (SVGGeometryBox) [0,172 128x256] + SVGGraphicsPaintable (SVGGraphicsBox) [0,172 128x256] + SVGPathPaintable (SVGGeometryBox) [0,172 128x256] + diff --git a/Tests/LibWeb/Layout/expected/svg/standalone-vb-h.txt b/Tests/LibWeb/Layout/expected/svg/standalone-vb-h.txt new file mode 100644 index 00000000000000..fa98bcbc417499 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/svg/standalone-vb-h.txt @@ -0,0 +1,18 @@ +Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline + SVGSVGBox at (0,0) content-size 128x600 [SVG] children: inline + TextNode <#text> + TextNode <#text> + SVGGeometryBox at (0,0) content-size 32x64 children: not-inline + TextNode <#text> + SVGGraphicsBox at (0,0) content-size 32x64 children: inline + TextNode <#text> + SVGGeometryBox at (0,0) content-size 32x64 children: not-inline + TextNode <#text> + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + SVGSVGPaintable (SVGSVGBox) [0,0 128x600] + SVGPathPaintable (SVGGeometryBox) [0,0 32x64] + SVGGraphicsPaintable (SVGGraphicsBox) [0,0 32x64] + SVGPathPaintable (SVGGeometryBox) [0,0 32x64] + diff --git a/Tests/LibWeb/Layout/expected/svg/standalone-vb-w.txt b/Tests/LibWeb/Layout/expected/svg/standalone-vb-w.txt new file mode 100644 index 00000000000000..e5759aadaa5a33 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/svg/standalone-vb-w.txt @@ -0,0 +1,18 @@ +Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline + SVGSVGBox at (0,0) content-size 800x256 [SVG] children: inline + TextNode <#text> + TextNode <#text> + SVGGeometryBox at (0,0) content-size 32x64 children: not-inline + TextNode <#text> + SVGGraphicsBox at (0,0) content-size 32x64 children: inline + TextNode <#text> + SVGGeometryBox at (0,0) content-size 32x64 children: not-inline + TextNode <#text> + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + SVGSVGPaintable (SVGSVGBox) [0,0 800x256] + SVGPathPaintable (SVGGeometryBox) [0,0 32x64] + SVGGraphicsPaintable (SVGGraphicsBox) [0,0 32x64] + SVGPathPaintable (SVGGeometryBox) [0,0 32x64] + diff --git a/Tests/LibWeb/Layout/expected/svg/standalone-vb-wh.txt b/Tests/LibWeb/Layout/expected/svg/standalone-vb-wh.txt new file mode 100644 index 00000000000000..d1f3acb87174da --- /dev/null +++ b/Tests/LibWeb/Layout/expected/svg/standalone-vb-wh.txt @@ -0,0 +1,18 @@ +Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline + SVGSVGBox at (0,0) content-size 800x600 [SVG] children: inline + TextNode <#text> + TextNode <#text> + SVGGeometryBox at (0,0) content-size 32x64 children: not-inline + TextNode <#text> + SVGGraphicsBox at (0,0) content-size 32x64 children: inline + TextNode <#text> + SVGGeometryBox at (0,0) content-size 32x64 children: not-inline + TextNode <#text> + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + SVGSVGPaintable (SVGSVGBox) [0,0 800x600] + SVGPathPaintable (SVGGeometryBox) [0,0 32x64] + SVGGraphicsPaintable (SVGGraphicsBox) [0,0 32x64] + SVGPathPaintable (SVGGeometryBox) [0,0 32x64] + diff --git a/Tests/LibWeb/Layout/expected/svg/standalone-vb.txt b/Tests/LibWeb/Layout/expected/svg/standalone-vb.txt new file mode 100644 index 00000000000000..13db94c3ce5354 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/svg/standalone-vb.txt @@ -0,0 +1,18 @@ +Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline + SVGSVGBox at (0,0) content-size 128x256 [SVG] children: inline + TextNode <#text> + TextNode <#text> + SVGGeometryBox at (0,0) content-size 32x64 children: not-inline + TextNode <#text> + SVGGraphicsBox at (0,0) content-size 32x64 children: inline + TextNode <#text> + SVGGeometryBox at (0,0) content-size 32x64 children: not-inline + TextNode <#text> + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + SVGSVGPaintable (SVGSVGBox) [0,0 128x256] + SVGPathPaintable (SVGGeometryBox) [0,0 32x64] + SVGGraphicsPaintable (SVGGraphicsBox) [0,0 32x64] + SVGPathPaintable (SVGGeometryBox) [0,0 32x64] + diff --git a/Tests/LibWeb/Layout/expected/svg/standalone-w.txt b/Tests/LibWeb/Layout/expected/svg/standalone-w.txt new file mode 100644 index 00000000000000..d131ba6efba589 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/svg/standalone-w.txt @@ -0,0 +1,18 @@ +Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline + SVGSVGBox at (0,0) content-size 800x256 [SVG] children: inline + TextNode <#text> + TextNode <#text> + SVGGeometryBox at (336,0) content-size 128x256 children: not-inline + TextNode <#text> + SVGGraphicsBox at (336,0) content-size 128x256 children: inline + TextNode <#text> + SVGGeometryBox at (336,0) content-size 128x256 children: not-inline + TextNode <#text> + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + SVGSVGPaintable (SVGSVGBox) [0,0 800x256] + SVGPathPaintable (SVGGeometryBox) [336,0 128x256] + SVGGraphicsPaintable (SVGGraphicsBox) [336,0 128x256] + SVGPathPaintable (SVGGeometryBox) [336,0 128x256] + diff --git a/Tests/LibWeb/Layout/expected/svg/standalone-wh.txt b/Tests/LibWeb/Layout/expected/svg/standalone-wh.txt new file mode 100644 index 00000000000000..9748db92587233 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/svg/standalone-wh.txt @@ -0,0 +1,18 @@ +Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline + SVGSVGBox at (0,0) content-size 800x600 [SVG] children: inline + TextNode <#text> + TextNode <#text> + SVGGeometryBox at (250,0) content-size 300x600 children: not-inline + TextNode <#text> + SVGGraphicsBox at (250,0) content-size 300x600 children: inline + TextNode <#text> + SVGGeometryBox at (250,0) content-size 300x600 children: not-inline + TextNode <#text> + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + SVGSVGPaintable (SVGSVGBox) [0,0 800x600] + SVGPathPaintable (SVGGeometryBox) [250,0 300x600] + SVGGraphicsPaintable (SVGGraphicsBox) [250,0 300x600] + SVGPathPaintable (SVGGeometryBox) [250,0 300x600] + diff --git a/Tests/LibWeb/Layout/input/svg/standalone-h.svg b/Tests/LibWeb/Layout/input/svg/standalone-h.svg new file mode 100644 index 00000000000000..33ac71492e2f0d --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/standalone-h.svg @@ -0,0 +1,7 @@ + + white diamond on blue; no height + + + + + diff --git a/Tests/LibWeb/Layout/input/svg/standalone-vb-h.svg b/Tests/LibWeb/Layout/input/svg/standalone-vb-h.svg new file mode 100644 index 00000000000000..134db81e09191d --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/standalone-vb-h.svg @@ -0,0 +1,7 @@ + + white diamond on blue; no viewBox; no height + + + + + diff --git a/Tests/LibWeb/Layout/input/svg/standalone-vb-w.svg b/Tests/LibWeb/Layout/input/svg/standalone-vb-w.svg new file mode 100644 index 00000000000000..2418d07a9cebc1 --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/standalone-vb-w.svg @@ -0,0 +1,7 @@ + + white diamond on blue; no viewBox; no width + + + + + diff --git a/Tests/LibWeb/Layout/input/svg/standalone-vb-wh.svg b/Tests/LibWeb/Layout/input/svg/standalone-vb-wh.svg new file mode 100644 index 00000000000000..12fbe0626903ae --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/standalone-vb-wh.svg @@ -0,0 +1,7 @@ + + white diamond on blue; no viewBox; no width; no height + + + + + diff --git a/Tests/LibWeb/Layout/input/svg/standalone-vb.svg b/Tests/LibWeb/Layout/input/svg/standalone-vb.svg new file mode 100644 index 00000000000000..f0d8c8639afff1 --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/standalone-vb.svg @@ -0,0 +1,7 @@ + + white diamond on blue; no viewBox + + + + + diff --git a/Tests/LibWeb/Layout/input/svg/standalone-w.svg b/Tests/LibWeb/Layout/input/svg/standalone-w.svg new file mode 100644 index 00000000000000..dd260571df4921 --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/standalone-w.svg @@ -0,0 +1,13 @@ + + + white diamond on blue; no width + + + + + diff --git a/Tests/LibWeb/Layout/input/svg/standalone-wh.svg b/Tests/LibWeb/Layout/input/svg/standalone-wh.svg new file mode 100644 index 00000000000000..6d8d736d62e145 --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/standalone-wh.svg @@ -0,0 +1,7 @@ + + white diamond on blue; no width ; no height + + + + + From 5e1de558b7cba12a23bbb4bbc07afdb667fda9dc Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 13 Dec 2024 09:24:12 -0500 Subject: [PATCH 25/36] LibJS: Avoid internal assertion accessing detached TA internal slots This defers accessing TA internal slots until we know we have a valid, attached TA. Our implementation has assertions that guard against this. (cherry picked from commit 962441b3cf34c1350877ac7c73351657c10f675b) --- .../Libraries/LibJS/Runtime/AtomicsObject.cpp | 15 +++++++++------ .../Atomics/Atomics.compareExchange.js | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/AtomicsObject.cpp b/Userland/Libraries/LibJS/Runtime/AtomicsObject.cpp index bf4eee7ad1b5ff..41cd4701797842 100644 --- a/Userland/Libraries/LibJS/Runtime/AtomicsObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/AtomicsObject.cpp @@ -289,12 +289,6 @@ static ThrowCompletionOr atomic_compare_exchange_impl(VM& vm, TypedArrayB // 1. Let byteIndexInBuffer be ? ValidateAtomicAccessOnIntegerTypedArray(typedArray, index). auto byte_index_in_buffer = TRY(validate_atomic_access_on_integer_typed_array(vm, typed_array, index)); - // 2. Let buffer be typedArray.[[ViewedArrayBuffer]]. - auto* buffer = typed_array.viewed_array_buffer(); - - // 3. Let block be buffer.[[ArrayBufferData]]. - auto& block = buffer->buffer(); - Value expected; Value replacement; @@ -318,6 +312,15 @@ static ThrowCompletionOr atomic_compare_exchange_impl(VM& vm, TypedArrayB // 6. Perform ? RevalidateAtomicAccess(typedArray, byteIndexInBuffer). TRY(revalidate_atomic_access(vm, typed_array, byte_index_in_buffer)); + // NOTE: We defer steps 2 and 3 to ensure we have revalidated the TA before accessing these internal slots. + // In our implementation, accessing [[ArrayBufferData]] on a detached buffer will fail assertions. + + // 2. Let buffer be typedArray.[[ViewedArrayBuffer]]. + auto* buffer = typed_array.viewed_array_buffer(); + + // 3. Let block be buffer.[[ArrayBufferData]]. + auto& block = buffer->buffer(); + // 7. Let elementType be TypedArrayElementType(typedArray). // 8. Let elementSize be TypedArrayElementSize(typedArray). diff --git a/Userland/Libraries/LibJS/Tests/builtins/Atomics/Atomics.compareExchange.js b/Userland/Libraries/LibJS/Tests/builtins/Atomics/Atomics.compareExchange.js index 60a0e724adff39..ae99428a2dee51 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Atomics/Atomics.compareExchange.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Atomics/Atomics.compareExchange.js @@ -21,6 +21,24 @@ test("error cases", () => { const array = new Int32Array(4); Atomics.compareExchange(array, 100, 0, 0); }).toThrow(RangeError); + + expect(() => { + const array = new Int32Array(4); + + function detachArrayWhileAccessingIndex(array) { + return { + valueOf() { + detachArrayBuffer(array.buffer); + return 0; + }, + }; + } + + Atomics.compareExchange(array, detachArrayWhileAccessingIndex(array), 0, 0); + }).toThrowWithMessage( + TypeError, + "TypedArray contains a property which references a value at an index not contained within its buffer's bounds" + ); }); test("basic functionality (non-BigInt)", () => { From 01f6e18e931153f0c0772e032a24fe5042ae96b2 Mon Sep 17 00:00:00 2001 From: Pavel Shliak Date: Sat, 14 Dec 2024 01:57:31 +0400 Subject: [PATCH 26/36] LibGC: Preallocate space before dumping GC graph Speeds up the append_gc_graph function by preallocating space. This change reduces the time taken to dump the GC graph by 4% on about:blank. (cherry picked from commit 03ac6e6e87488fdc638cd3a84b2c59890bdba3cc) --- Userland/Libraries/LibJS/Heap/Heap.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Userland/Libraries/LibJS/Heap/Heap.cpp b/Userland/Libraries/LibJS/Heap/Heap.cpp index b23c2300d5b4d8..2282f388eeaacb 100644 --- a/Userland/Libraries/LibJS/Heap/Heap.cpp +++ b/Userland/Libraries/LibJS/Heap/Heap.cpp @@ -139,6 +139,7 @@ class GraphConstructorVisitor final : public Cell::Visitor { m_all_live_heap_blocks.set(&block); return IterationDecision::Continue; }); + m_work_queue.ensure_capacity(roots.size()); for (auto& [root, root_origin] : roots) { auto& graph_node = m_graph.ensure(bit_cast(root)); From 383fb23f2023b8f640717b05227b318de7ce55fd Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 13 Dec 2024 11:50:55 -0500 Subject: [PATCH 27/36] LibJS: Return the allocated dst register from deleting super properties Even though calling delete on a super property will ultimately throw a ReferenceError, we must return the allocated register for the result of the delete operation (which would normally be a boolean). If the delete operation is used in a return statement, the bytecode generator for the return statement must be able to assume the statement had some output. (cherry picked from commit 5947c37637f8ea3d4c323a04e5e5dfe9fad5a4d7) --- Userland/Libraries/LibJS/Bytecode/Generator.cpp | 2 +- .../Libraries/LibJS/Tests/operators/delete-basic.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index a7b1d651a3513e..a4634507d5a8b6 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -812,7 +812,7 @@ CodeGenerationErrorOr> Generator::emit_delete_reference( emit(dst, *super_reference.base, *super_reference.this_value, identifier_table_ref); } - return Optional {}; + return dst; } auto object = TRY(expression.object().generate_bytecode(*this)).value(); diff --git a/Userland/Libraries/LibJS/Tests/operators/delete-basic.js b/Userland/Libraries/LibJS/Tests/operators/delete-basic.js index f41269c5fc9e73..fc6d58b057a2be 100644 --- a/Userland/Libraries/LibJS/Tests/operators/delete-basic.js +++ b/Userland/Libraries/LibJS/Tests/operators/delete-basic.js @@ -93,6 +93,13 @@ test("deleting super property", () => { } } + class D { + static foo() { + const deleter = () => delete super.foo; + deleter(); + } + } + const obj = new B(); expect(() => { obj.bar(); @@ -106,6 +113,10 @@ test("deleting super property", () => { expect(() => { C.foo(); }).toThrowWithMessage(ReferenceError, "Can't delete a property on 'super'"); + + expect(() => { + D.foo(); + }).toThrowWithMessage(ReferenceError, "Can't delete a property on 'super'"); }); test("deleting an object computed property coerces the object to a property key", () => { From 121da9a0d8ddbf4ef28f7792eeb93377c9769ce6 Mon Sep 17 00:00:00 2001 From: Gustavo Ramirez Date: Wed, 11 Sep 2024 09:01:17 -0500 Subject: [PATCH 28/36] LibWeb/CSS: Refactor phase() method to reduce redundancy The function AnimationEffect::phase() contained duplicated condition checks for the animation phase determination. This refactor eliminates the redundant checks by simplifying the logic. (cherry picked from commit 108701c8997e8484890adee8dbf1d4cb81a51c39) --- .../LibWeb/Animations/AnimationEffect.cpp | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp b/Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp index 6dfe4652678834..7289cb8a0985e1 100644 --- a/Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp +++ b/Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp @@ -424,15 +424,25 @@ AnimationEffect::Phase AnimationEffect::phase() const { // This is a convenience method that returns the phase of the animation effect, to avoid having to call all of the // phase functions separately. - // FIXME: There is a lot of duplicated condition checking here which can probably be inlined into this function + auto local_time = this->local_time(); + if (!local_time.has_value()) + return Phase::Idle; - if (is_in_the_before_phase()) + auto before_active_boundary_time = this->before_active_boundary_time(); + // - the local time is less than the before-active boundary time, or + // - the animation direction is "backwards" and the local time is equal to the before-active boundary time. + if (local_time.value() < before_active_boundary_time || (animation_direction() == AnimationDirection::Backwards && local_time.value() == before_active_boundary_time)) return Phase::Before; - if (is_in_the_active_phase()) - return Phase::Active; - if (is_in_the_after_phase()) + + auto after_active_boundary_time = this->after_active_boundary_time(); + // - the local time is greater than the active-after boundary time, or + // - the animation direction is "forwards" and the local time is equal to the active-after boundary time. + if (local_time.value() > after_active_boundary_time || (animation_direction() == AnimationDirection::Forwards && local_time.value() == after_active_boundary_time)) return Phase::After; - return Phase::Idle; + + // - An animation effect is in the active phase if the animation effect’s local time is not unresolved and it is not + // - in either the before phase nor the after phase. + return Phase::Active; } // https://www.w3.org/TR/web-animations-1/#overall-progress From f8873038b4e221aa8d19a2ae46c4a21561ab42f9 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Wed, 18 Dec 2024 14:02:54 +0100 Subject: [PATCH 29/36] LibWeb: Remove unused (Tree)Node::index_of_child() (cherry picked from commit c357fbf03668c7da18140864b6317387d3d0fc39) --- Userland/Libraries/LibWeb/DOM/Node.h | 33 ---------------------------- Userland/Libraries/LibWeb/TreeNode.h | 18 --------------- 2 files changed, 51 deletions(-) diff --git a/Userland/Libraries/LibWeb/DOM/Node.h b/Userland/Libraries/LibWeb/DOM/Node.h index df62e44a91c1c4..9027615ca69e47 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.h +++ b/Userland/Libraries/LibWeb/DOM/Node.h @@ -371,39 +371,6 @@ class Node : public EventTarget { return index; } - Optional index_of_child(Node const& search_child) - { - VERIFY(search_child.parent() == this); - size_t index = 0; - auto* child = first_child(); - VERIFY(child); - - do { - if (child == &search_child) - return index; - index++; - } while (child && (child = child->next_sibling())); - return {}; - } - - template - Optional index_of_child(Node const& search_child) - { - VERIFY(search_child.parent() == this); - size_t index = 0; - auto* child = first_child(); - VERIFY(child); - - do { - if (!is(child)) - continue; - if (child == &search_child) - return index; - index++; - } while (child && (child = child->next_sibling())); - return {}; - } - bool is_ancestor_of(Node const&) const; bool is_inclusive_ancestor_of(Node const&) const; bool is_descendant_of(Node const&) const; diff --git a/Userland/Libraries/LibWeb/TreeNode.h b/Userland/Libraries/LibWeb/TreeNode.h index cc0088a8bc69ef..5e50ce4c2fd4ec 100644 --- a/Userland/Libraries/LibWeb/TreeNode.h +++ b/Userland/Libraries/LibWeb/TreeNode.h @@ -41,24 +41,6 @@ class TreeNode { return index; } - template - Optional index_of_child(T const& search_child) - { - VERIFY(search_child.parent() == this); - size_t index = 0; - auto* child = first_child(); - VERIFY(child); - - do { - if (!is(child)) - continue; - if (child == &search_child) - return index; - index++; - } while (child && (child = child->next_sibling())); - return {}; - } - bool is_ancestor_of(TreeNode const&) const; bool is_inclusive_ancestor_of(TreeNode const&) const; From dfa1ae529dcf809f24def3a3420c44df66c59865 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Wed, 18 Dec 2024 14:07:40 +0100 Subject: [PATCH 30/36] LibWeb: Resolve performance FIXME in Node::is_equal_node() (cherry picked from commit f29457b61ecd5b7d4a27414259010eb7e1ae6d2c) --- Userland/Libraries/LibWeb/DOM/Node.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index b3aa681bc94a50..b83742f97a6374 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -1693,20 +1693,19 @@ bool Node::is_equal_node(Node const* other_node) const } // A and B have the same number of children. - size_t this_child_count = child_count(); - size_t other_child_count = other_node->child_count(); - if (this_child_count != other_child_count) + if (child_count() != other_node->child_count()) return false; // Each child of A equals the child of B at the identical index. - // FIXME: This can be made nicer. child_at_index() is O(n). - for (size_t i = 0; i < this_child_count; ++i) { - auto* this_child = child_at_index(i); - auto* other_child = other_node->child_at_index(i); - VERIFY(this_child); + auto* this_child = first_child(); + auto* other_child = other_node->first_child(); + while (this_child) { VERIFY(other_child); if (!this_child->is_equal_node(other_child)) return false; + + this_child = this_child->next_sibling(); + other_child = other_child->next_sibling(); } return true; From bd983a254d8df2bde1818638b14fba1ca96cfe95 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 19 Dec 2024 19:15:02 +0100 Subject: [PATCH 31/36] LibWeb: Handle special cases of PseudoElement::Type correctly There are some special values for CSS::Selector::PseudoElement::Type which are after `KnownPseudoElementCount` and therefore not present in various arrays of pseudo elements, this leads to some errors, if a type after `KnownPseudoElementCount` is used without checking first. This adds explicit checks to all usages (cherry picked from commit d21bfda9001efd1f2303dc86af6c1f0a2d7da182) --- .../LibWeb/Animations/Animatable.cpp | 22 +++++++++++++--- Userland/Libraries/LibWeb/CSS/Selector.h | 7 +++++- .../Libraries/LibWeb/CSS/StyleComputer.cpp | 12 ++++++--- Userland/Libraries/LibWeb/DOM/Element.cpp | 25 +++++++++++++++++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibWeb/Animations/Animatable.cpp b/Userland/Libraries/LibWeb/Animations/Animatable.cpp index c495a2205e005a..5f4c9e72aab6ba 100644 --- a/Userland/Libraries/LibWeb/Animations/Animatable.cpp +++ b/Userland/Libraries/LibWeb/Animations/Animatable.cpp @@ -174,14 +174,21 @@ void Animatable::visit_edges(JS::Cell::Visitor& visitor) JS::GCPtr Animatable::cached_animation_name_source(Optional pseudo_element) const { - if (pseudo_element.has_value()) + if (pseudo_element.has_value()) { + if (!CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element.value())) { + return {}; + } return m_cached_animation_name_source[to_underlying(pseudo_element.value()) + 1]; + } return m_cached_animation_name_source[0]; } void Animatable::set_cached_animation_name_source(JS::GCPtr value, Optional pseudo_element) { if (pseudo_element.has_value()) { + if (!CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element.value())) { + return; + } m_cached_animation_name_source[to_underlying(pseudo_element.value()) + 1] = value; } else { m_cached_animation_name_source[0] = value; @@ -190,18 +197,27 @@ void Animatable::set_cached_animation_name_source(JS::GCPtr Animatable::cached_animation_name_animation(Optional pseudo_element) const { - if (pseudo_element.has_value()) + if (pseudo_element.has_value()) { + if (!CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element.value())) { + return {}; + } + return m_cached_animation_name_animation[to_underlying(pseudo_element.value()) + 1]; + } return m_cached_animation_name_animation[0]; } void Animatable::set_cached_animation_name_animation(JS::GCPtr value, Optional pseudo_element) { + if (pseudo_element.has_value()) { + if (!CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element.value())) { + return; + } + m_cached_animation_name_animation[to_underlying(pseudo_element.value()) + 1] = value; } else { m_cached_animation_name_animation[0] = value; } } - } diff --git a/Userland/Libraries/LibWeb/CSS/Selector.h b/Userland/Libraries/LibWeb/CSS/Selector.h index 2b478689887060..b150b0312144c2 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.h +++ b/Userland/Libraries/LibWeb/CSS/Selector.h @@ -52,7 +52,7 @@ class Selector : public RefCounted { explicit PseudoElement(Type type) : m_type(type) { - VERIFY(type != Type::UnknownWebKit); + VERIFY(is_known_pseudo_element_type(type)); } PseudoElement(Type type, String name) @@ -65,6 +65,11 @@ class Selector : public RefCounted { static Optional from_string(FlyString const&); + [[nodiscard]] static bool is_known_pseudo_element_type(Type type) + { + return to_underlying(type) < to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount); + } + static StringView name(Selector::PseudoElement::Type pseudo_element); StringView name() const diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index 9643e971577f4b..a3204cfd4181eb 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -414,8 +414,14 @@ Vector StyleComputer::collect_matching_rules(DOM::Element const& e } if (auto it = rule_cache.rules_by_tag_name.find(element.local_name()); it != rule_cache.rules_by_tag_name.end()) add_rules_to_run(it->value); - if (pseudo_element.has_value()) - add_rules_to_run(rule_cache.rules_by_pseudo_element[to_underlying(pseudo_element.value())]); + if (pseudo_element.has_value()) { + if (CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element.value())) { + add_rules_to_run(rule_cache.rules_by_pseudo_element.at(to_underlying(pseudo_element.value()))); + } else { + // NOTE: We don't cache rules for unknown pseudo-elements. They can't match anything anyway. + } + } + if (element.is_document_element()) add_rules_to_run(rule_cache.root_rules); @@ -2546,7 +2552,7 @@ NonnullOwnPtr StyleComputer::make_rule_cache_for_casca } if (!added_to_bucket) { if (matching_rule.contains_pseudo_element) { - if (to_underlying(pseudo_element.value()) < to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount)) { + if (CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element.value())) { rule_cache->rules_by_pseudo_element[to_underlying(pseudo_element.value())].append(move(matching_rule)); } else { // NOTE: We don't cache rules for unknown pseudo-elements. They can't match anything anyway. diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index 697ac08c6b5332..a1220d6e736402 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -1134,6 +1134,10 @@ void Element::set_pseudo_element_node(Badge, CSS::Selector: if (!existing_pseudo_element.has_value() && !pseudo_element_node) return; + if (!CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element)) { + return; + } + ensure_pseudo_element(pseudo_element).layout_node = move(pseudo_element_node); } @@ -2283,6 +2287,11 @@ void Element::set_pseudo_element_computed_css_values(CSS::Selector::PseudoElemen { if (!m_pseudo_element_data && !style) return; + + if (!CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element)) { + return; + } + ensure_pseudo_element(pseudo_element).computed_css_values = move(style); } @@ -2298,6 +2307,11 @@ Optional Element::get_pseudo_element(CSS::Selector::Pse { if (!m_pseudo_element_data) return {}; + + if (!CSS::Selector::PseudoElement::is_known_pseudo_element_type(type)) { + return {}; + } + return m_pseudo_element_data->at(to_underlying(type)); } @@ -2305,6 +2319,9 @@ Element::PseudoElement& Element::ensure_pseudo_element(CSS::Selector::PseudoElem { if (!m_pseudo_element_data) m_pseudo_element_data = make(); + + VERIFY(CSS::Selector::PseudoElement::is_known_pseudo_element_type(type)); + return m_pseudo_element_data->at(to_underlying(type)); } @@ -2314,6 +2331,11 @@ void Element::set_custom_properties(Optional m_custom_properties = move(custom_properties); return; } + + if (!CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element.value())) { + return; + } + ensure_pseudo_element(pseudo_element.value()).custom_properties = move(custom_properties); } @@ -2321,6 +2343,9 @@ HashMap const& Element::custom_properties(Optiona { if (!pseudo_element.has_value()) return m_custom_properties; + + VERIFY(CSS::Selector::PseudoElement::is_known_pseudo_element_type(pseudo_element.value())); + return ensure_pseudo_element(pseudo_element.value()).custom_properties; } From 64ac2dc50b74dc5619f02beff84835ddea9b6823 Mon Sep 17 00:00:00 2001 From: Totto16 Date: Thu, 19 Dec 2024 19:15:51 +0100 Subject: [PATCH 32/36] LibWeb: Add test for getComputedStyle with a PseudoElement argument This test checks the case, where an unknown pseudo element is used as second argument to getComputedStyle (cherry picked from commit 540c840755755844c84b0b9f41c50d2e835486fe) --- .../Text/expected/css/unknown-pseudo-elements-crash.txt | 1 + .../Text/input/css/unknown-pseudo-elements-crash.html | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 Tests/LibWeb/Text/expected/css/unknown-pseudo-elements-crash.txt create mode 100644 Tests/LibWeb/Text/input/css/unknown-pseudo-elements-crash.html diff --git a/Tests/LibWeb/Text/expected/css/unknown-pseudo-elements-crash.txt b/Tests/LibWeb/Text/expected/css/unknown-pseudo-elements-crash.txt new file mode 100644 index 00000000000000..aaecaf93c4a5b5 --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/unknown-pseudo-elements-crash.txt @@ -0,0 +1 @@ +PASS (didn't crash) diff --git a/Tests/LibWeb/Text/input/css/unknown-pseudo-elements-crash.html b/Tests/LibWeb/Text/input/css/unknown-pseudo-elements-crash.html new file mode 100644 index 00000000000000..582ef65c89cfaa --- /dev/null +++ b/Tests/LibWeb/Text/input/css/unknown-pseudo-elements-crash.html @@ -0,0 +1,7 @@ + + From 364bffdfde3cff1263702fcf0c366a643bff6061 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Thu, 19 Dec 2024 16:29:40 -0500 Subject: [PATCH 33/36] LibCrypto: Protect the SignedBigInteger ctor against integer overflow In particular, if given a value of -2147483648, we would invoke signed integer overflow (which is UB). (cherry picked from commit edd3b14ddf049048e5d6bd952677133237adb652) --- Tests/LibCrypto/TestBigInteger.cpp | 11 +++++++++++ .../Libraries/LibCrypto/BigInt/SignedBigInteger.h | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Tests/LibCrypto/TestBigInteger.cpp b/Tests/LibCrypto/TestBigInteger.cpp index 615c78f3d67d66..890a472794a531 100644 --- a/Tests/LibCrypto/TestBigInteger.cpp +++ b/Tests/LibCrypto/TestBigInteger.cpp @@ -664,6 +664,17 @@ TEST_CASE(test_negative_zero_is_not_allowed) EXPECT(!zero.is_negative()); } +TEST_CASE(test_i32_limits) +{ + Crypto::SignedBigInteger min { AK::NumericLimits::min() }; + EXPECT(min.is_negative()); + EXPECT(min.unsigned_value().to_u64() == static_cast(AK::NumericLimits::max()) + 1); + + Crypto::SignedBigInteger max { AK::NumericLimits::max() }; + EXPECT(!max.is_negative()); + EXPECT(max.unsigned_value().to_u64() == AK::NumericLimits::max()); +} + TEST_CASE(double_comparisons) { #define EXPECT_LESS_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt) diff --git a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h index 725e4f8bdf2a52..b5cf29aa6d4417 100644 --- a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h +++ b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h @@ -22,7 +22,7 @@ class SignedBigInteger { requires(sizeof(T) <= sizeof(i32)) SignedBigInteger(T value) : m_sign(value < 0) - , m_unsigned_data(abs(static_cast(value))) + , m_unsigned_data(static_cast(abs(static_cast(value)))) { } From 3144c4bf6d5342323deda60adb09570e44dba6e2 Mon Sep 17 00:00:00 2001 From: Pavel Shliak Date: Sun, 1 Dec 2024 02:56:22 +0400 Subject: [PATCH 34/36] LibWeb: Update Location initialization according to spec (cherry picked from commit 361c6f1b64393de645c6728712658a6052e857a1) --- Userland/Libraries/LibWeb/HTML/Location.cpp | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWeb/HTML/Location.cpp b/Userland/Libraries/LibWeb/HTML/Location.cpp index 0cccaae1d22b23..9333219e0d0a0e 100644 --- a/Userland/Libraries/LibWeb/HTML/Location.cpp +++ b/Userland/Libraries/LibWeb/HTML/Location.cpp @@ -38,12 +38,35 @@ void Location::visit_edges(Cell::Visitor& visitor) visitor.visit(m_default_properties); } +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-location-interface void Location::initialize(JS::Realm& realm) { Base::initialize(realm); WEB_SET_PROTOTYPE_FOR_INTERFACE(Location); - // FIXME: Implement steps 2.-4. + auto& vm = this->vm(); + + // Step 2: Let valueOf be location's relevant realm.[[Intrinsics]].[[%Object.prototype.valueOf%]]. + auto& intrinsics = realm.intrinsics(); + auto value_of_function = intrinsics.object_prototype()->get_without_side_effects(vm.names.valueOf); + + // Step 3: Perform ! location.[[DefineOwnProperty]]("valueOf", { [[Value]]: valueOf, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }). + auto value_of_property_descriptor = JS::PropertyDescriptor { + .value = value_of_function, + .writable = false, + .enumerable = false, + .configurable = false, + }; + MUST(internal_define_own_property(vm.names.valueOf, value_of_property_descriptor)); + + // Step 4: Perform ! location.[[DefineOwnProperty]](%Symbol.toPrimitive%, { [[Value]]: undefined, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }). + auto to_primitive_property_descriptor = JS::PropertyDescriptor { + .value = JS::js_undefined(), + .writable = false, + .enumerable = false, + .configurable = false, + }; + MUST(internal_define_own_property(vm.well_known_symbol_to_primitive(), to_primitive_property_descriptor)); // 5. Set the value of the [[DefaultProperties]] internal slot of location to location.[[OwnPropertyKeys]](). // NOTE: In LibWeb this happens before the ESO is set up, so we must avoid location's custom [[OwnPropertyKeys]]. From 67bad2d7897da5d97a5b2b83954c0fdffff29463 Mon Sep 17 00:00:00 2001 From: Pavel Shliak Date: Mon, 9 Dec 2024 15:55:18 +0400 Subject: [PATCH 35/36] LibWeb: Refer a spec issue in Location::internal_get_own_property (cherry picked from commit 4cd1ef12d7bdddc7cbb235350d50fee65fbd5f34) --- Userland/Libraries/LibWeb/HTML/Location.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Userland/Libraries/LibWeb/HTML/Location.cpp b/Userland/Libraries/LibWeb/HTML/Location.cpp index 9333219e0d0a0e..33ad827c782c8c 100644 --- a/Userland/Libraries/LibWeb/HTML/Location.cpp +++ b/Userland/Libraries/LibWeb/HTML/Location.cpp @@ -529,6 +529,7 @@ JS::ThrowCompletionOr> Location::internal_get_o auto descriptor = MUST(Object::internal_get_own_property(property_key)); // 2. If the value of the [[DefaultProperties]] internal slot of this contains P, then set desc.[[Configurable]] to true. + // FIXME: This doesn't align with what the other browsers do. Spec issue: https://github.com/whatwg/html/issues/4157 auto property_key_value = property_key.is_symbol() ? JS::Value { property_key.as_symbol() } : JS::PrimitiveString::create(vm, property_key.to_string()); From fca07a64a818f7eb3ee26fe17a537fe0a21a3c3a Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 20 Dec 2024 14:54:08 +0000 Subject: [PATCH 36/36] LibWeb/CSS: Don't overwrite active font load when requesting a pt size start_loading_next_url() is a no-op if there's a pending resource load, but not if that resource load has successfully loaded already. There is a delay between the font resource loading, and it being processed into a vector font. Calling font_with_point_size() in that gap would previously erase the previously-loaded font, if the font had multiple URLs to choose from. This fixes the icon font on mods.factorio.com :^) (cherry picked from commit 28388f1fd24c0019d2c4be7900584c6c536527ad) --- Userland/Libraries/LibWeb/CSS/StyleComputer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index a3204cfd4181eb..dace2941e0b987 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -170,7 +170,8 @@ void FontLoader::resource_did_fail() RefPtr FontLoader::font_with_point_size(float point_size) { if (!m_vector_font) { - start_loading_next_url(); + if (!resource()) + start_loading_next_url(); return nullptr; } return m_vector_font->scaled_font(point_size);