| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- /*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2025 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
- #include "FormattingContextDebug.h"
- #include "../../../Include/RmlUi/Core/Element.h"
- #include "../../../Include/RmlUi/Core/ElementUtilities.h"
- #include "../../../Include/RmlUi/Core/StringUtilities.h"
- #include "LayoutNode.h"
- namespace Rml {
- #ifdef RMLUI_DEBUG
- static FormattingContextDebugTracker* g_debug_format_independent_tracker = nullptr;
- FormattingContextDebugTracker::FormattingContextDebugTracker()
- {
- RMLUI_ASSERTMSG(!g_debug_format_independent_tracker, "An instance of FormattingContextDebugTracker already exists");
- g_debug_format_independent_tracker = this;
- }
- FormattingContextDebugTracker::~FormattingContextDebugTracker()
- {
- RMLUI_ASSERT(g_debug_format_independent_tracker == this);
- RMLUI_ASSERT(current_stack_level == 0);
- g_debug_format_independent_tracker = nullptr;
- }
- FormattingContextDebugTracker* FormattingContextDebugTracker::GetIf()
- {
- return g_debug_format_independent_tracker;
- }
- FormattingContextDebugTracker::Entry& FormattingContextDebugTracker::PushEntry(FormatType format_type, ContainerBox* parent_container,
- Element* element, const Box* override_initial_box, FormattingContextType type)
- {
- Entry& result = entries.emplace_back(FormattingContextDebugTracker::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 FormattingContextDebugTracker::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<FormattingContextDebugTracker::Entry::LayoutResult>({
- layout_box->GetVisibleOverflowSize(),
- layout_box->GetIfBox() ? Optional<Box>{*layout_box->GetIfBox()} : std::nullopt,
- });
- }
- }
- void FormattingContextDebugTracker::CloseEntry(Entry& entry, float max_content_width, bool from_cache)
- {
- current_stack_level -= 1;
- entry.from_cache = from_cache;
- entry.fit_width_result = Optional<FormattingContextDebugTracker::Entry::FitWidthResult>({
- max_content_width,
- });
- }
- void FormattingContextDebugTracker::Reset()
- {
- *this = {};
- }
- String FormattingContextDebugTracker::ToString() const
- {
- String result;
- for (const auto& entry : entries)
- {
- 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: ";
- switch (entry.context_type)
- {
- case FormattingContextType::Block: result += "Block"; break;
- case FormattingContextType::Table: result += "Table"; break;
- case FormattingContextType::Flex: result += "Flex"; break;
- case FormattingContextType::Replaced: result += "Replaced"; break;
- case FormattingContextType::None: result += "None"; break;
- default: result += "Unknown"; break;
- }
- if (entry.override_box)
- {
- const Box& box = *entry.override_box;
- result += newline + "| Override box: ";
- result += Rml::ToString(box.GetSize().x) + " x " + Rml::ToString(box.GetSize().y);
- result += " (outer size: " + Rml::ToString(box.GetSizeAcross(BoxDirection::Horizontal, BoxArea::Margin)) + " x " +
- Rml::ToString(box.GetSizeAcross(BoxDirection::Vertical, BoxArea::Margin)) + ")";
- }
- else
- {
- result += newline + "| Override box: none";
- }
- if (entry.layout_result)
- {
- 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_result->box)
- {
- const Box& box = *entry.layout_result->box;
- result += newline + "| Layout box: ";
- result += Rml::ToString(box.GetSize().x) + " x " + Rml::ToString(box.GetSize().y);
- result += " (outer size: " + Rml::ToString(box.GetSizeAcross(BoxDirection::Horizontal, BoxArea::Margin)) + " x " +
- Rml::ToString(box.GetSizeAcross(BoxDirection::Vertical, BoxArea::Margin)) + ")";
- }
- else
- {
- 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
- {
- result += newline + "| Layout result: none";
- }
- }
- return result;
- }
- void FormattingContextDebugTracker::LogMessage() const
- {
- Log::Message(Log::LT_INFO, "%s", ToString().c_str());
- }
- int FormattingContextDebugTracker::CountCachedEntries() const
- {
- return (int)std::count_if(entries.begin(), entries.end(), [](const auto& entry) { return entry.from_cache; });
- }
- int FormattingContextDebugTracker::CountFormattedEntries() const
- {
- return (int)entries.size() - CountCachedEntries();
- }
- int FormattingContextDebugTracker::CountEntries() const
- {
- return (int)entries.size();
- }
- void DebugLogDirtyLayoutTree(Element* root_element)
- {
- String tree_dirty_state;
- ElementUtilities::VisitElementsDepthOrder(root_element, [&](Element* element, int tree_depth) {
- tree_dirty_state += String(size_t(4 * tree_depth), ' ');
- tree_dirty_state += CreateString("%s. Self: %d Child: %d", element->GetAddress(false, tree_depth == 0).c_str(),
- element->GetLayoutNode()->IsSelfDirty(), element->GetLayoutNode()->IsChildDirty());
- tree_dirty_state += '\n';
- });
- Log::Message(Log::LT_INFO, "Dirty layout tree:\n%s\n", tree_dirty_state.c_str());
- }
- #endif // RMLUI_DEBUG
- } // namespace Rml
|