Browse Source

Flexbox: Skip calculating hypothetical cross when not needed, see #658

This can be a potentially slow step, particularly when we need to format flex items to find the size. In some cases the size is never used, so skip this calculation when such a case is detected. This change should produce the same layout result.
Michael Ragazzon 1 year ago
parent
commit
e9451c9cba
1 changed files with 17 additions and 1 deletions
  1. 17 1
      Source/Core/Layout/FlexFormattingContext.cpp

+ 17 - 1
Source/Core/Layout/FlexFormattingContext.cpp

@@ -675,12 +675,24 @@ void FlexFormattingContext::Format(Vector2f& flex_resulting_content_size, Vector
 		}
 		}
 	}
 	}
 
 
+	auto CanSkipHypotheticalCrossSize = [=](const FlexItem& item) {
+		// If the following conditions are met, the hypothetical cross size will never be used. This allows us to skip a
+		// potentially slow step with content-based sizing.
+		const bool stretch_item = (item.align_self == Style::AlignSelf::Stretch);
+		const bool stretched = (stretch_item && item.cross.auto_size && !item.cross.auto_margin_a && !item.cross.auto_margin_b);
+		const bool single_line_definite_cross_size = (cross_available_size >= 0.f && flex_single_line);
+		return stretched && single_line_definite_cross_size;
+	};
+
 	// -- Determine cross size (§9.4) --
 	// -- Determine cross size (§9.4) --
 	// First, determine the cross size of each item, format it if necessary.
 	// First, determine the cross size of each item, format it if necessary.
 	for (FlexLine& line : container.lines)
 	for (FlexLine& line : container.lines)
 	{
 	{
 		for (FlexItem& item : line.items)
 		for (FlexItem& item : line.items)
 		{
 		{
+			if (CanSkipHypotheticalCrossSize(item))
+				continue;
+
 			const Vector2f content_size = item.box.GetSize();
 			const Vector2f content_size = item.box.GetSize();
 
 
 			if (main_axis_horizontal)
 			if (main_axis_horizontal)
@@ -713,14 +725,17 @@ void FlexFormattingContext::Format(Vector2f& flex_resulting_content_size, Vector
 	}
 	}
 
 
 	// Determine cross size of each line.
 	// Determine cross size of each line.
-	if (cross_available_size >= 0.f && flex_single_line && container.lines.size() == 1)
+	if (cross_available_size >= 0.f && flex_single_line)
 	{
 	{
+		RMLUI_ASSERT(container.lines.size() == 1);
 		container.lines[0].cross_size = cross_available_size;
 		container.lines[0].cross_size = cross_available_size;
 	}
 	}
 	else
 	else
 	{
 	{
 		for (FlexLine& line : container.lines)
 		for (FlexLine& line : container.lines)
 		{
 		{
+			RMLUI_ASSERT(std::none_of(line.items.begin(), line.items.end(), [&](const auto& item) { return CanSkipHypotheticalCrossSize(item); }));
+
 			const float largest_hypothetical_cross_size =
 			const float largest_hypothetical_cross_size =
 				std::max_element(line.items.begin(), line.items.end(), [](const FlexItem& a, const FlexItem& b) {
 				std::max_element(line.items.begin(), line.items.end(), [](const FlexItem& a, const FlexItem& b) {
 					return a.hypothetical_cross_size < b.hypothetical_cross_size;
 					return a.hypothetical_cross_size < b.hypothetical_cross_size;
@@ -769,6 +784,7 @@ void FlexFormattingContext::Format(Vector2f& flex_resulting_content_size, Vector
 			}
 			}
 			else
 			else
 			{
 			{
+				RMLUI_ASSERT(!CanSkipHypotheticalCrossSize(item));
 				item.used_cross_size = item.hypothetical_cross_size;
 				item.used_cross_size = item.hypothetical_cross_size;
 			}
 			}
 		}
 		}