Browse Source

Include FitContentWidth in formatting context debugger, some cleanup

Michael Ragazzon 4 months ago
parent
commit
53d3a4b264

+ 3 - 0
Include/RmlUi/Config/Config.h

@@ -41,6 +41,7 @@
 	#include RMLUI_CUSTOM_CONFIGURATION_FILE
 	#include RMLUI_CUSTOM_CONFIGURATION_FILE
 #else
 #else
 	#include <array>
 	#include <array>
+	#include <deque>
 	#include <functional>
 	#include <functional>
 	#include <list>
 	#include <list>
 	#include <map>
 	#include <map>
@@ -83,6 +84,8 @@ using Array = std::array<T, N>;
 template <typename T>
 template <typename T>
 using Stack = std::stack<T>;
 using Stack = std::stack<T>;
 template <typename T>
 template <typename T>
+using Deque = std::deque<T>;
+template <typename T>
 using List = std::list<T>;
 using List = std::list<T>;
 template <typename T>
 template <typename T>
 using Queue = std::queue<T>;
 using Queue = std::queue<T>;

+ 40 - 38
Source/Core/Layout/FormattingContext.cpp

@@ -39,6 +39,7 @@
 #include "LayoutNode.h"
 #include "LayoutNode.h"
 #include "ReplacedFormattingContext.h"
 #include "ReplacedFormattingContext.h"
 #include "TableFormattingContext.h"
 #include "TableFormattingContext.h"
+#include <limits>
 
 
 namespace Rml {
 namespace Rml {
 
 
@@ -92,28 +93,12 @@ UniquePtr<LayoutBox> FormattingContext::FormatIndependent(ContainerBox* parent_c
 	if (type == FormattingContextType::None)
 	if (type == FormattingContextType::None)
 		return nullptr;
 		return nullptr;
 
 
-	if (element->GetId() == "special")
-		int x = 0;
-
 #ifdef RMLUI_DEBUG
 #ifdef RMLUI_DEBUG
 	auto* debug_tracker = FormatIndependentDebugTracker::GetIf();
 	auto* debug_tracker = FormatIndependentDebugTracker::GetIf();
 	FormatIndependentDebugTracker::Entry* tracker_entry = nullptr;
 	FormatIndependentDebugTracker::Entry* tracker_entry = nullptr;
-	if (debug_tracker && type != FormattingContextType::None)
-	{
-		tracker_entry = &debug_tracker->entries.emplace_back(FormatIndependentDebugTracker::Entry{
-			debug_tracker->current_stack_level,
-			parent_container->GetElement() ? parent_container->GetElement()->GetAddress() : "",
-			parent_container->GetAbsolutePositioningContainingBlockElementForDebug()
-				? parent_container->GetAbsolutePositioningContainingBlockElementForDebug()->GetAddress()
-				: "",
-			parent_container->GetContainingBlockSize(Style::Position::Static),
-			parent_container->GetContainingBlockSize(Style::Position::Absolute),
-			element->GetAddress(),
-			override_initial_box ? Optional<Box>{*override_initial_box} : std::nullopt,
-			type,
-		});
-		debug_tracker->current_stack_level += 1;
-	}
+	if (debug_tracker)
+		tracker_entry = &debug_tracker->PushEntry(FormatIndependentDebugTracker::FormatType::FormatIndependent, parent_container, element,
+			override_initial_box, type);
 #endif
 #endif
 
 
 	UniquePtr<LayoutBox> layout_box;
 	UniquePtr<LayoutBox> layout_box;
@@ -124,20 +109,34 @@ UniquePtr<LayoutBox> FormattingContext::FormatIndependent(ContainerBox* parent_c
 		const Vector2f containing_block = parent_container->GetContainingBlockSize(Style::Position::Static);
 		const Vector2f containing_block = parent_container->GetContainingBlockSize(Style::Position::Static);
 		const Vector2f absolute_containing_block = parent_container->GetContainingBlockSize(Style::Position::Absolute);
 		const Vector2f absolute_containing_block = parent_container->GetContainingBlockSize(Style::Position::Absolute);
 
 
+#ifdef RMLUI_TRACY_PROFILING
+		auto DebugCacheTracyMessage = [&](const char* cache_info) {
+			const String message = CreateString("%s on %x. Containing block: %g, %g. Absolute containing block: %g, %g. Box (size): %g, %g",
+				cache_info, element, containing_block.x, containing_block.y, absolute_containing_block.x, absolute_containing_block.y,
+				override_initial_box ? override_initial_box->GetSize().x : std::numeric_limits<float>::quiet_NaN(),
+				override_initial_box ? override_initial_box->GetSize().y : std::numeric_limits<float>::quiet_NaN());
+			RMLUI_ZoneText(message.c_str(), message.size());
+		};
+#else
+	#define DebugCacheTracyMessage(message)
+#endif
+
 		LayoutNode* layout_node = element->GetLayoutNode();
 		LayoutNode* layout_node = element->GetLayoutNode();
 		if (layout_node->CommittedLayoutMatches(containing_block, absolute_containing_block, override_initial_box,
 		if (layout_node->CommittedLayoutMatches(containing_block, absolute_containing_block, override_initial_box,
 				formatting_mode.constraint != FormattingMode::Constraint::None))
 				formatting_mode.constraint != FormattingMode::Constraint::None))
 		{
 		{
-#ifdef RMLUI_DEBUG
-			Log::Message(Log::LT_INFO, "Layout cache match on element%s: %s",
-				(formatting_mode.allow_format_independent_cache ? "" : " (skipping cache due to formatting mode)"), element->GetAddress().c_str());
-#endif
+			DebugCacheTracyMessage("Cache match");
+
 			if (formatting_mode.allow_format_independent_cache)
 			if (formatting_mode.allow_format_independent_cache)
 			{
 			{
 				layout_box = MakeUnique<CachedContainer>(element, parent_container, element->GetBox(),
 				layout_box = MakeUnique<CachedContainer>(element, parent_container, element->GetBox(),
 					layout_node->GetCommittedLayout()->visible_overflow_size, layout_node->GetCommittedLayout()->baseline_of_last_line);
 					layout_node->GetCommittedLayout()->visible_overflow_size, layout_node->GetCommittedLayout()->baseline_of_last_line);
 			}
 			}
 		}
 		}
+		else
+		{
+			DebugCacheTracyMessage(layout_node->HasCommittedLayout() ? "Cache miss" : "No cache");
+		}
 	}
 	}
 
 
 	if (!layout_box)
 	if (!layout_box)
@@ -169,8 +168,6 @@ UniquePtr<LayoutBox> FormattingContext::FormatIndependent(ContainerBox* parent_c
 		case FormattingContextType::None: RMLUI_ERROR; break;
 		case FormattingContextType::None: RMLUI_ERROR; break;
 		}
 		}
 
 
-		// TODO: If MaxContent constraint, and containing block = -1, -1, store resulting size as max-content size.
-
 		if (layout_box)
 		if (layout_box)
 		{
 		{
 			Optional<float> baseline_of_last_line;
 			Optional<float> baseline_of_last_line;
@@ -187,18 +184,7 @@ UniquePtr<LayoutBox> FormattingContext::FormatIndependent(ContainerBox* parent_c
 
 
 #ifdef RMLUI_DEBUG
 #ifdef RMLUI_DEBUG
 	if (tracker_entry)
 	if (tracker_entry)
-	{
-		debug_tracker->current_stack_level -= 1;
-		if (layout_box)
-		{
-			const bool from_cache = (layout_box->GetType() == LayoutBox::Type::CachedContainer);
-			tracker_entry->layout = Optional<FormatIndependentDebugTracker::Entry::LayoutResults>({
-				from_cache,
-				layout_box->GetVisibleOverflowSize(),
-				layout_box->GetIfBox() ? Optional<Box>{*layout_box->GetIfBox()} : std::nullopt,
-			});
-		}
-	}
+		debug_tracker->CloseEntry(*tracker_entry, layout_box.get());
 #endif
 #endif
 
 
 	return layout_box;
 	return layout_box;
@@ -274,13 +260,22 @@ void FormattingContext::FormatFitContentWidth(Box& box, Element* element, Format
 	RMLUI_ZoneText(zone_text.c_str(), zone_text.size());
 	RMLUI_ZoneText(zone_text.c_str(), zone_text.size());
 #endif
 #endif
 
 
+#ifdef RMLUI_DEBUG
+	auto* debug_tracker = FormatIndependentDebugTracker::GetIf();
+	FormatIndependentDebugTracker::Entry* tracker_entry = nullptr;
+	if (debug_tracker)
+		tracker_entry = &debug_tracker->PushEntry(FormatIndependentDebugTracker::FormatType::FormatFitContentWidth, nullptr, element, &box, type);
+#endif
+
 	const float box_height = box.GetSize().y;
 	const float box_height = box.GetSize().y;
 	LayoutNode* layout_node = element->GetLayoutNode();
 	LayoutNode* layout_node = element->GetLayoutNode();
 	float max_content_width = -1.f;
 	float max_content_width = -1.f;
+	bool from_cache = false;
 
 
 	if (Optional<float> cached_width = layout_node->GetMaxContentWidthIfCached())
 	if (Optional<float> cached_width = layout_node->GetMaxContentWidthIfCached())
 	{
 	{
 		max_content_width = *cached_width;
 		max_content_width = *cached_width;
+		from_cache = true;
 	}
 	}
 	else
 	else
 	{
 	{
@@ -299,7 +294,7 @@ void FormattingContext::FormatFitContentWidth(Box& box, Element* element, Format
 			break;
 			break;
 		case FormattingContextType::Flex: max_content_width = FlexFormattingContext::DetermineMaxContentWidth(element, box, formatting_mode); break;
 		case FormattingContextType::Flex: max_content_width = FlexFormattingContext::DetermineMaxContentWidth(element, box, formatting_mode); break;
 		case FormattingContextType::Replaced:
 		case FormattingContextType::Replaced:
-			RMLUI_ERRORMSG("Replaced elements are expected to have a positive intrinsice size and do not perform shrink-to-fit layout.");
+			RMLUI_ERRORMSG("Replaced elements are expected to have a positive intrinsic size and do not perform shrink-to-fit layout.");
 			break;
 			break;
 		case FormattingContextType::None: RMLUI_ERROR; break;
 		case FormattingContextType::None: RMLUI_ERROR; break;
 		}
 		}
@@ -309,6 +304,13 @@ void FormattingContext::FormatFitContentWidth(Box& box, Element* element, Format
 
 
 	RMLUI_ASSERTMSG(max_content_width >= 0.f, "Max-content width should evaluate to a positive size.")
 	RMLUI_ASSERTMSG(max_content_width >= 0.f, "Max-content width should evaluate to a positive size.")
 
 
+#ifdef RMLUI_DEBUG
+	if (tracker_entry)
+		debug_tracker->CloseEntry(*tracker_entry, max_content_width, from_cache);
+#else
+	(void)from_cache;
+#endif
+
 	float fit_content_width = max_content_width;
 	float fit_content_width = max_content_width;
 	if (containing_block.x >= 0.f)
 	if (containing_block.x >= 0.f)
 	{
 	{

+ 68 - 26
Source/Core/Layout/FormattingContextDebug.cpp

@@ -28,23 +28,13 @@
 
 
 #include "FormattingContextDebug.h"
 #include "FormattingContextDebug.h"
 #include "../../../Include/RmlUi/Core/Element.h"
 #include "../../../Include/RmlUi/Core/Element.h"
+#include "../../../Include/RmlUi/Core/StringUtilities.h"
 
 
 namespace Rml {
 namespace Rml {
 #ifdef RMLUI_DEBUG
 #ifdef RMLUI_DEBUG
 
 
 static FormatIndependentDebugTracker* g_debug_format_independent_tracker = nullptr;
 static FormatIndependentDebugTracker* g_debug_format_independent_tracker = nullptr;
 
 
-static std::string repeat(const std::string& input, int count)
-{
-	if (count <= 0)
-		return {};
-	std::string result;
-	result.reserve(input.size() * size_t(count));
-	for (size_t i = 0; i < size_t(count); ++i)
-		result += input;
-	return result;
-}
-
 FormatIndependentDebugTracker::FormatIndependentDebugTracker()
 FormatIndependentDebugTracker::FormatIndependentDebugTracker()
 {
 {
 	RMLUI_ASSERTMSG(!g_debug_format_independent_tracker, "An instance of FormatIndependentDebugTracker already exists");
 	RMLUI_ASSERTMSG(!g_debug_format_independent_tracker, "An instance of FormatIndependentDebugTracker already exists");
@@ -63,6 +53,47 @@ FormatIndependentDebugTracker* FormatIndependentDebugTracker::GetIf()
 	return g_debug_format_independent_tracker;
 	return g_debug_format_independent_tracker;
 }
 }
 
 
+FormatIndependentDebugTracker::Entry& FormatIndependentDebugTracker::PushEntry(FormatType format_type, ContainerBox* parent_container,
+	Element* element, const Box* override_initial_box, FormattingContextType type)
+{
+	Entry& result = entries.emplace_back(FormatIndependentDebugTracker::Entry{
+		current_stack_level,
+		format_type,
+		parent_container && parent_container->GetElement() ? parent_container->GetElement()->GetAddress() : "",
+		parent_container && parent_container->GetAbsolutePositioningContainingBlockElementForDebug()
+			? parent_container->GetAbsolutePositioningContainingBlockElementForDebug()->GetAddress()
+			: "",
+		parent_container ? parent_container->GetContainingBlockSize(Style::Position::Static) : Optional<Vector2f>{},
+		parent_container ? parent_container->GetContainingBlockSize(Style::Position::Absolute) : Optional<Vector2f>{},
+		element->GetAddress(),
+		override_initial_box ? Optional<Box>{*override_initial_box} : std::nullopt,
+		type,
+	});
+	current_stack_level += 1;
+	return result;
+}
+
+void FormatIndependentDebugTracker::CloseEntry(Entry& entry, LayoutBox* layout_box)
+{
+	current_stack_level -= 1;
+	if (layout_box)
+	{
+		entry.from_cache = (layout_box->GetType() == LayoutBox::Type::CachedContainer);
+		entry.layout_result = Optional<FormatIndependentDebugTracker::Entry::LayoutResult>({
+			layout_box->GetVisibleOverflowSize(),
+			layout_box->GetIfBox() ? Optional<Box>{*layout_box->GetIfBox()} : std::nullopt,
+		});
+	}
+}
+void FormatIndependentDebugTracker::CloseEntry(Entry& entry, float max_content_width, bool from_cache)
+{
+	current_stack_level -= 1;
+	entry.from_cache = from_cache;
+	entry.fit_width_result = Optional<FormatIndependentDebugTracker::Entry::FitWidthResult>({
+		max_content_width,
+	});
+}
+
 void FormatIndependentDebugTracker::Reset()
 void FormatIndependentDebugTracker::Reset()
 {
 {
 	*this = {};
 	*this = {};
@@ -74,15 +105,21 @@ String FormatIndependentDebugTracker::ToString() const
 
 
 	for (const auto& entry : entries)
 	for (const auto& entry : entries)
 	{
 	{
-		const std::string newline = '\n' + repeat("|   ", entry.level);
-		result += '\n' + repeat("+ - ", entry.level) + entry.element;
-		result += newline + "|   Containing block: " + Rml::ToString(entry.containing_block.x) + " x " + Rml::ToString(entry.containing_block.y) +
-			". " + entry.parent_container_element;
-		result += newline + "|   Absolute positioning containing block: " + Rml::ToString(entry.absolute_positioning_containing_block.x) + " x " +
-			Rml::ToString(entry.absolute_positioning_containing_block.y) + ". " + entry.absolute_positioning_containing_block_element;
+		auto OptionalVec2ToString = [](const Optional<Vector2f>& value) -> String {
+			if (value.has_value())
+				return Rml::ToString(value->x) + " x " + Rml::ToString(value->y);
+			return "none";
+		};
+		const std::string newline = '\n' + StringUtilities::RepeatString("|   ", entry.level);
+		result += '\n' + StringUtilities::RepeatString("+ - ", entry.level) + entry.element;
+		result +=
+			newline + "|   Format type: " + (entry.format_type == FormatType::FormatIndependent ? "FormatIndependent" : "FormatFitContentWidth");
+		result += newline + "|   Containing block: " + OptionalVec2ToString(entry.containing_block) + ". " + entry.parent_container_element;
+		result += newline + "|   Absolute positioning containing block: " + OptionalVec2ToString(entry.absolute_positioning_containing_block) + ". " +
+			entry.absolute_positioning_containing_block_element;
 
 
 		result += newline + "|   Formatting context: ";
 		result += newline + "|   Formatting context: ";
-		switch (entry.type)
+		switch (entry.context_type)
 		{
 		{
 		case FormattingContextType::Block: result += "Block"; break;
 		case FormattingContextType::Block: result += "Block"; break;
 		case FormattingContextType::Table: result += "Table"; break;
 		case FormattingContextType::Table: result += "Table"; break;
@@ -105,15 +142,15 @@ String FormatIndependentDebugTracker::ToString() const
 			result += newline + "|   Override box: none";
 			result += newline + "|   Override box: none";
 		}
 		}
 
 
-		if (entry.layout)
+		if (entry.layout_result)
 		{
 		{
-			result += newline + "|   Layout results" + (entry.layout->from_cache ? " (cached)" : "") + ":";
-			result += newline + "|       Visible overflow: " + Rml::ToString(entry.layout->visible_overflow_size.x) + " x " +
-				Rml::ToString(entry.layout->visible_overflow_size.y);
+			result += newline + "|   Layout result" + (entry.from_cache ? " (cached)" : "") + ":";
+			result += newline + "|       Visible overflow: " + Rml::ToString(entry.layout_result->visible_overflow_size.x) + " x " +
+				Rml::ToString(entry.layout_result->visible_overflow_size.y);
 
 
-			if (entry.layout->box)
+			if (entry.layout_result->box)
 			{
 			{
-				const Box& box = *entry.layout->box;
+				const Box& box = *entry.layout_result->box;
 				result += newline + "|       Layout box: ";
 				result += newline + "|       Layout box: ";
 				result += Rml::ToString(box.GetSize().x) + " x " + Rml::ToString(box.GetSize().y);
 				result += Rml::ToString(box.GetSize().x) + " x " + Rml::ToString(box.GetSize().y);
 				result += " (outer size: " + Rml::ToString(box.GetSizeAcross(BoxDirection::Horizontal, BoxArea::Margin)) + " x " +
 				result += " (outer size: " + Rml::ToString(box.GetSizeAcross(BoxDirection::Horizontal, BoxArea::Margin)) + " x " +
@@ -124,9 +161,14 @@ String FormatIndependentDebugTracker::ToString() const
 				result += newline + "|       Layout box: none";
 				result += newline + "|       Layout box: none";
 			}
 			}
 		}
 		}
+		else if (entry.fit_width_result)
+		{
+			result += newline + "|   Fit-width result" + (entry.from_cache ? " (cached)" : "") + ":";
+			result += newline + "|       Max-content width: " + Rml::ToString(entry.fit_width_result->max_content_width);
+		}
 		else
 		else
 		{
 		{
-			result += newline + "|   Layout results: none";
+			result += newline + "|   Layout result: none";
 		}
 		}
 	}
 	}
 
 
@@ -140,7 +182,7 @@ void FormatIndependentDebugTracker::LogMessage() const
 
 
 int FormatIndependentDebugTracker::CountCachedEntries() const
 int FormatIndependentDebugTracker::CountCachedEntries() const
 {
 {
-	return (int)std::count_if(entries.begin(), entries.end(), [](const auto& entry) { return entry.layout.has_value() && entry.layout->from_cache; });
+	return (int)std::count_if(entries.begin(), entries.end(), [](const auto& entry) { return entry.from_cache; });
 }
 }
 
 
 int FormatIndependentDebugTracker::CountFormattedEntries() const
 int FormatIndependentDebugTracker::CountFormattedEntries() const

+ 28 - 10
Source/Core/Layout/FormattingContextDebug.h

@@ -42,33 +42,51 @@ public:
 	~FormatIndependentDebugTracker();
 	~FormatIndependentDebugTracker();
 	static FormatIndependentDebugTracker* GetIf();
 	static FormatIndependentDebugTracker* GetIf();
 
 
+	enum class FormatType {
+		FormatIndependent,
+		FormatFitContentWidth,
+	};
+
 	struct Entry {
 	struct Entry {
 		int level = 0;
 		int level = 0;
+		FormatType format_type;
 		String parent_container_element;
 		String parent_container_element;
 		String absolute_positioning_containing_block_element;
 		String absolute_positioning_containing_block_element;
-		Vector2f containing_block;
-		Vector2f absolute_positioning_containing_block;
+		std::optional<Vector2f> containing_block;
+		std::optional<Vector2f> absolute_positioning_containing_block;
 		String element;
 		String element;
 		Optional<Box> override_box;
 		Optional<Box> override_box;
-		FormattingContextType type;
-		struct LayoutResults {
-			bool from_cache;
+		FormattingContextType context_type;
+
+		struct LayoutResult {
 			Vector2f visible_overflow_size;
 			Vector2f visible_overflow_size;
 			Optional<Box> box;
 			Optional<Box> box;
 		};
 		};
-		Optional<LayoutResults> layout;
+		struct FitWidthResult {
+			float max_content_width;
+		};
+		bool from_cache = false;
+		Optional<LayoutResult> layout_result;
+		Optional<FitWidthResult> fit_width_result;
 	};
 	};
 
 
-	List<Entry> entries;
-	int current_stack_level = 0;
-
-	void Reset();
+	Entry& PushEntry(FormatType format_type, ContainerBox* parent_container, Element* element, const Box* override_initial_box,
+		FormattingContextType type);
+	void CloseEntry(Entry& entry, LayoutBox* layout_box);
+	void CloseEntry(Entry& entry, float max_content_width, bool from_cache);
 
 
+	const Deque<Entry>& GetEntries() const { return entries; }
 	String ToString() const;
 	String ToString() const;
 	void LogMessage() const;
 	void LogMessage() const;
 	int CountEntries() const;
 	int CountEntries() const;
 	int CountCachedEntries() const;
 	int CountCachedEntries() const;
 	int CountFormattedEntries() const;
 	int CountFormattedEntries() const;
+
+	void Reset();
+
+private:
+	Deque<Entry> entries;
+	int current_stack_level = 0;
 };
 };
 
 
 #endif // RMLUI_DEBUG
 #endif // RMLUI_DEBUG

+ 2 - 0
Source/Core/Layout/LayoutNode.h

@@ -129,6 +129,8 @@ public:
 		return *override_box == compare_box;
 		return *override_box == compare_box;
 	}
 	}
 
 
+	bool HasCommittedLayout() const { return committed_layout.has_value(); }
+
 	Optional<float> GetMaxContentWidthIfCached() const { return committed_max_content_width; }
 	Optional<float> GetMaxContentWidthIfCached() const { return committed_max_content_width; }
 	void CommitMaxContentWidth(float width) { committed_max_content_width = width; }
 	void CommitMaxContentWidth(float width) { committed_max_content_width = width; }
 
 

+ 1 - 1
Tests/Source/UnitTests/LayoutIsolation.cpp

@@ -271,7 +271,7 @@ TEST_CASE("LayoutIsolation.FullLayoutFormatIndependentCount")
 
 
 	format_independent_tracker.LogMessage();
 	format_independent_tracker.LogMessage();
 
 
-	const auto count_level_1 = std::count_if(format_independent_tracker.entries.begin(), format_independent_tracker.entries.end(),
+	const auto count_level_1 = std::count_if(format_independent_tracker.GetEntries().begin(), format_independent_tracker.GetEntries().end(),
 		[](const auto& entry) { return entry.level == 1; });
 		[](const auto& entry) { return entry.level == 1; });
 	CHECK_MESSAGE(count_level_1 == 3, "Expecting one entry for each of flex, overflow, and absolute");
 	CHECK_MESSAGE(count_level_1 == 3, "Expecting one entry for each of flex, overflow, and absolute");