Explorar el Código

Cache max-content width

Speeds up "Nested shrink-to-fit" benchmark by about 2x.
Michael Ragazzon hace 6 meses
padre
commit
168fa11d5c

+ 23 - 9
Source/Core/Layout/LayoutDetails.cpp

@@ -36,6 +36,7 @@
 #include "ContainerBox.h"
 #include "FormattingContext.h"
 #include "LayoutEngine.h"
+#include "LayoutNode.h"
 #include <float.h>
 
 namespace Rml {
@@ -242,23 +243,36 @@ float LayoutDetails::GetShrinkToFitWidth(Element* element, Vector2f containing_b
 		return 0.f;
 	}
 
-	FormattingMode formatting_mode = current_formatting_mode;
-	formatting_mode.constraint = FormattingMode::Constraint::MaxContent;
+	LayoutNode* layout_node = element->GetLayoutNode();
+	float shrink_to_fit_width;
 
-	// First, format the element under the above-generated box. Then we ask the resulting box for its shrink-to-fit
-	// width. For block containers, this is essentially its largest line or child box.
-	// @performance. Some formatting can be simplified, e.g. absolute elements do not contribute to the shrink-to-fit
-	// width. Also, children of elements with a fixed width and height don't need to be formatted further.
-	RootBox root(Box(Vector2f(-1.f)), formatting_mode);
-	UniquePtr<LayoutBox> layout_box = FormattingContext::FormatIndependent(&root, element, &box, FormattingContextType::Block);
+	if (Optional<float> cached_width = layout_node->GetMaxContentWidthIfCached())
+	{
+		shrink_to_fit_width = *cached_width;
+	}
+	else
+	{
+		FormattingMode formatting_mode = current_formatting_mode;
+		formatting_mode.constraint = FormattingMode::Constraint::MaxContent;
+
+		// First, format the element under the above-generated box. Then we ask the resulting box for its shrink-to-fit
+		// width. For block containers, this is essentially its largest line or child box.
+		// @performance. Some formatting can be simplified, e.g. absolute elements do not contribute to the shrink-to-fit
+		// width. Also, children of elements with a fixed width and height don't need to be formatted further.
+		RootBox root(Box(Vector2f(-1.f)), formatting_mode);
+		UniquePtr<LayoutBox> layout_box = FormattingContext::FormatIndependent(&root, element, &box, FormattingContextType::Block);
+
+		shrink_to_fit_width = layout_box->GetShrinkToFitWidth();
+		layout_node->CommitMaxContentWidth(shrink_to_fit_width);
+	}
 
-	float shrink_to_fit_width = layout_box->GetShrinkToFitWidth();
 	if (containing_block.x >= 0)
 	{
 		const float available_width =
 			Math::Max(0.f, containing_block.x - box.GetSizeAcross(BoxDirection::Horizontal, BoxArea::Margin, BoxArea::Padding));
 		shrink_to_fit_width = Math::Min(shrink_to_fit_width, available_width);
 	}
+
 	return shrink_to_fit_width;
 }
 

+ 1 - 0
Source/Core/Layout/LayoutNode.cpp

@@ -79,6 +79,7 @@ void LayoutNode::SetDirty(DirtyLayoutType dirty_type)
 	// Log::Message(Log::LT_INFO, "SetDirty. Self %d  Child %d  Element: %s", (dirty_type & DirtyLayoutType::DOM) != DirtyLayoutType::None,
 	//	(dirty_type & DirtyLayoutType::Child) != DirtyLayoutType::None, element->GetAddress().c_str());
 	dirty_flag = dirty_flag | dirty_type;
+	committed_max_content_width.reset();
 }
 
 void LayoutNode::CommitLayout(Vector2f containing_block_size, Vector2f absolutely_positioning_containing_block_size, const Box* override_box,

+ 10 - 1
Source/Core/Layout/LayoutNode.h

@@ -90,7 +90,11 @@ public:
 
 	// TODO: Currently, should only be used by `Context::SetDimensions`. Ideally, we would remove this and "commit" the
 	// containing block (without the layout result, see comment in `CommitLayout`).
-	void ClearCommittedLayout() { committed_layout.reset(); }
+	void ClearCommittedLayout()
+	{
+		committed_layout.reset();
+		committed_max_content_width.reset();
+	}
 
 	bool CommittedLayoutMatches(Vector2f containing_block_size, Vector2f absolutely_positioning_containing_block_size, const Box* override_box) const
 	{
@@ -122,6 +126,10 @@ public:
 		return override_box->GetSize() == compare_size;
 	}
 
+	Optional<float> GetMaxContentWidthIfCached() const { return committed_max_content_width; }
+	void CommitMaxContentWidth(float width) { committed_max_content_width = width; }
+
+	// TODO: Remove and replace with a better interface.
 	const Optional<CommittedLayout>& GetCommittedLayout() const { return committed_layout; }
 
 	// A.k.a. reflow root.
@@ -140,6 +148,7 @@ private:
 	Vector2f containing_block;
 
 	Optional<CommittedLayout> committed_layout;
+	Optional<float> committed_max_content_width;
 };
 
 } // namespace Rml