diff --git a/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index 53dde33bcc..039baef404 100644 --- a/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -4896,10 +4896,7 @@ RefPtr parse_dimension_value(StringView string) } auto integer_value = number_string.string_view().to_number(); - // NOTE: This is apparently the largest value allowed by Firefox. - static float max_dimension_value = 17895700; - - float value = min(*integer_value, max_dimension_value); + float value = min(*integer_value, CSSPixels::max_dimension_value); // 6. If position is past the end of input, then return value as a length. if (position == input.end()) diff --git a/Libraries/LibWeb/Layout/FormattingContext.cpp b/Libraries/LibWeb/Layout/FormattingContext.cpp index c678bf09b7..c09a7aca0f 100644 --- a/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -1466,14 +1466,7 @@ CSSPixels FormattingContext::calculate_min_content_width(Layout::Box const& box) context->run(AvailableSpace(available_width, available_height)); - cache.min_content_width = context->automatic_content_width(); - - if (cache.min_content_width->might_be_saturated()) { - // HACK: If layout calculates a non-finite result, something went wrong. Force it to zero and log a little whine. - dbgln("FIXME: Calculated non-finite min-content width for {}", box.debug_description()); - cache.min_content_width = 0; - } - + cache.min_content_width = clamp_to_max_dimension_value(context->automatic_content_width()); return *cache.min_content_width; } @@ -1506,14 +1499,7 @@ CSSPixels FormattingContext::calculate_max_content_width(Layout::Box const& box) context->run(AvailableSpace(available_width, available_height)); - cache.max_content_width = context->automatic_content_width(); - - if (cache.max_content_width->might_be_saturated()) { - // HACK: If layout calculates a non-finite result, something went wrong. Force it to zero and log a little whine. - dbgln("FIXME: Calculated non-finite max-content width for {}", box.debug_description()); - cache.max_content_width = 0; - } - + cache.max_content_width = clamp_to_max_dimension_value(context->automatic_content_width()); return *cache.max_content_width; } @@ -1550,13 +1536,7 @@ CSSPixels FormattingContext::calculate_min_content_height(Layout::Box const& box context->run(AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_min_content())); - auto min_content_height = context->automatic_content_height(); - if (min_content_height.might_be_saturated()) { - // HACK: If layout calculates a non-finite result, something went wrong. Force it to zero and log a little whine. - dbgln("FIXME: Calculated non-finite min-content height for {}", box.debug_description()); - min_content_height = 0; - } - + auto min_content_height = clamp_to_max_dimension_value(context->automatic_content_height()); if (auto* cache_slot = get_cache_slot()) { *cache_slot = min_content_height; } @@ -1594,13 +1574,7 @@ CSSPixels FormattingContext::calculate_max_content_height(Layout::Box const& box context->run(AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_max_content())); - auto max_content_height = context->automatic_content_height(); - - if (max_content_height.might_be_saturated()) { - // HACK: If layout calculates a non-finite result, something went wrong. Force it to zero and log a little whine. - dbgln("FIXME: Calculated non-finite max-content height for {}", box.debug_description()); - max_content_height = 0; - } + auto max_content_height = clamp_to_max_dimension_value(context->automatic_content_height()); if (auto* cache_slot = get_cache_slot()) { *cache_slot = max_content_height; diff --git a/Libraries/LibWeb/Layout/LayoutState.cpp b/Libraries/LibWeb/Layout/LayoutState.cpp index 431570493d..3f0169a12b 100644 --- a/Libraries/LibWeb/Layout/LayoutState.cpp +++ b/Libraries/LibWeb/Layout/LayoutState.cpp @@ -535,13 +535,14 @@ void LayoutState::UsedValues::set_node(NodeWithStyle& node, UsedValues const* co || node.parent()->display().is_flow_inside())) { if (containing_block_has_definite_size) { CSSPixels available_width = containing_block_used_values->content_width(); - resolved_definite_size = available_width + resolved_definite_size = clamp_to_max_dimension_value( + available_width - margin_left - margin_right - padding_left - padding_right - border_left - - border_right; + - border_right); return true; } return false; @@ -559,19 +560,19 @@ void LayoutState::UsedValues::set_node(NodeWithStyle& node, UsedValues const* co auto containing_block_size_as_length = width ? containing_block_used_values->content_width() : containing_block_used_values->content_height(); context.percentage_basis = CSS::Length::make_px(containing_block_size_as_length); } - resolved_definite_size = adjust_for_box_sizing(size.calculated().resolve_length(context)->to_px(node), size, width); + resolved_definite_size = clamp_to_max_dimension_value(adjust_for_box_sizing(size.calculated().resolve_length(context)->to_px(node), size, width)); return true; } if (size.is_length()) { VERIFY(!size.is_auto()); // This should have been covered by the Size::is_auto() branch above. - resolved_definite_size = adjust_for_box_sizing(size.length().to_px(node), size, width); + resolved_definite_size = clamp_to_max_dimension_value(adjust_for_box_sizing(size.length().to_px(node), size, width)); return true; } if (size.is_percentage()) { if (containing_block_has_definite_size) { auto containing_block_size = width ? containing_block_used_values->content_width() : containing_block_used_values->content_height(); - resolved_definite_size = adjust_for_box_sizing(containing_block_size.scaled(size.percentage().as_fraction()), size, width); + resolved_definite_size = clamp_to_max_dimension_value(adjust_for_box_sizing(containing_block_size.scaled(size.percentage().as_fraction()), size, width)); return true; } return false; @@ -600,10 +601,10 @@ void LayoutState::UsedValues::set_node(NodeWithStyle& node, UsedValues const* co if (m_has_definite_width && m_has_definite_height) { // Both width and height are definite. } else if (m_has_definite_width) { - m_content_height = m_content_width / *aspect_ratio; + m_content_height = clamp_to_max_dimension_value(m_content_width / *aspect_ratio); m_has_definite_height = true; } else if (m_has_definite_height) { - m_content_width = m_content_height * *aspect_ratio; + m_content_width = clamp_to_max_dimension_value(m_content_height * *aspect_ratio); m_has_definite_width = true; } } @@ -611,28 +612,27 @@ void LayoutState::UsedValues::set_node(NodeWithStyle& node, UsedValues const* co if (m_has_definite_width) { if (has_definite_min_width) - m_content_width = max(min_width, m_content_width); + m_content_width = clamp_to_max_dimension_value(max(min_width, m_content_width)); if (has_definite_max_width) - m_content_width = min(max_width, m_content_width); + m_content_width = clamp_to_max_dimension_value(min(max_width, m_content_width)); } if (m_has_definite_height) { if (has_definite_min_height) - m_content_height = max(min_height, m_content_height); + m_content_height = clamp_to_max_dimension_value(max(min_height, m_content_height)); if (has_definite_max_height) - m_content_height = min(max_height, m_content_height); + m_content_height = clamp_to_max_dimension_value(min(max_height, m_content_height)); } } void LayoutState::UsedValues::set_content_width(CSSPixels width) { - VERIFY(!width.might_be_saturated()); if (width < 0) { // Negative widths are not allowed in CSS. We have a bug somewhere! Clamp to 0 to avoid doing too much damage. dbgln_if(LIBWEB_CSS_DEBUG, "FIXME: Layout calculated a negative width for {}: {}", m_node->debug_description(), width); width = 0; } - m_content_width = width; + m_content_width = clamp_to_max_dimension_value(width); // FIXME: We should not do this! Definiteness of widths should be determined early, // and not changed later (except for some special cases in flex layout..) m_has_definite_width = true; @@ -640,18 +640,17 @@ void LayoutState::UsedValues::set_content_width(CSSPixels width) void LayoutState::UsedValues::set_content_height(CSSPixels height) { - VERIFY(!height.might_be_saturated()); if (height < 0) { // Negative heights are not allowed in CSS. We have a bug somewhere! Clamp to 0 to avoid doing too much damage. dbgln_if(LIBWEB_CSS_DEBUG, "FIXME: Layout calculated a negative height for {}: {}", m_node->debug_description(), height); height = 0; } - m_content_height = height; + m_content_height = clamp_to_max_dimension_value(height); } void LayoutState::UsedValues::set_temporary_content_width(CSSPixels width) { - m_content_width = width; + m_content_width = clamp_to_max_dimension_value(width); } void LayoutState::UsedValues::set_temporary_content_height(CSSPixels height) diff --git a/Libraries/LibWeb/Layout/LayoutState.h b/Libraries/LibWeb/Layout/LayoutState.h index b20f5dada5..0d8a9f9955 100644 --- a/Libraries/LibWeb/Layout/LayoutState.h +++ b/Libraries/LibWeb/Layout/LayoutState.h @@ -244,4 +244,11 @@ private: void resolve_relative_positions(); }; +inline CSSPixels clamp_to_max_dimension_value(CSSPixels value) +{ + if (value.might_be_saturated()) + return CSSPixels(CSSPixels::max_dimension_value); + return value; +} + } diff --git a/Libraries/LibWeb/PixelUnits.h b/Libraries/LibWeb/PixelUnits.h index 65aa2663c7..5602932739 100644 --- a/Libraries/LibWeb/PixelUnits.h +++ b/Libraries/LibWeb/PixelUnits.h @@ -66,6 +66,9 @@ public: static constexpr i32 max_integer_value = NumericLimits::max() >> fractional_bits; static constexpr i32 min_integer_value = NumericLimits::min() >> fractional_bits; + // NOTE: This is apparently the largest value allowed by Firefox. Probably enough for us as well. + static constexpr float max_dimension_value = 17895700; + constexpr CSSPixels() = default; template constexpr CSSPixels(I value) diff --git a/Tests/LibWeb/Crash/CSS/height-calc-infinity-result.html b/Tests/LibWeb/Crash/CSS/height-calc-infinity-result.html new file mode 100644 index 0000000000..37a358617e --- /dev/null +++ b/Tests/LibWeb/Crash/CSS/height-calc-infinity-result.html @@ -0,0 +1,5 @@ + diff --git a/Tests/LibWeb/Crash/CSS/width-calc-infinity-result.html b/Tests/LibWeb/Crash/CSS/width-calc-infinity-result.html new file mode 100644 index 0000000000..e6c37b3df9 --- /dev/null +++ b/Tests/LibWeb/Crash/CSS/width-calc-infinity-result.html @@ -0,0 +1,5 @@ +