Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache for shrink-to-fit width #582

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Include/RmlUi/Core/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ class RMLUICORE_API Context : public ScriptInterface {
/// @return Time until next update is expected.
double GetNextUpdateDelay() const;

/// Get current frame number. Frame number is incremented every time Update() is called.
/// @return Current frame number.
int GetFrameNumber() const;

protected:
void Release() override;

Expand All @@ -307,6 +311,7 @@ class RMLUICORE_API Context : public ScriptInterface {
Vector2i dimensions;
float density_independent_pixel_ratio;
String documents_base_tag = "body";
int frame_number = 0;

SmallUnorderedSet<String> active_themes;

Expand Down
17 changes: 17 additions & 0 deletions Include/RmlUi/Core/Element.h
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,19 @@ class RMLUICORE_API Element : public ScriptInterface, public EnableObserverPtr<E
/// Return the computed values of the element's properties. These values are updated as appropriate on every Context::Update.
const ComputedValues& GetComputedValues() const;

/// Set cached shrink to fit width value.
/// @param[in] width The width to cache.
/// @param[in] container_size The size of the container (used as cache key).
void SetCachedShrinkToFitWidth(float width, Vector2f container_size);

/// Get cached shrink to fit width value.
/// Note: The cache is invalidated on each frame number increment. Values from
/// the previous frame will never be returned.
/// @param[out] width The cached width.
/// @param[in] container_size The size of the container (used as cache key).
/// @return True if a cached value was found.
bool GetCachedShrinkToFitWidth(float& width, Vector2f container_size) const;

protected:
void Update(float dp_ratio, Vector2f vp_dimensions);
void Render();
Expand Down Expand Up @@ -788,6 +801,10 @@ class RMLUICORE_API Element : public ScriptInterface, public EnableObserverPtr<E

ElementMeta* meta;

// Shrink to fit cache.
std::unordered_map<Vector2f, float, Vector2fHash> cached_shrink_to_fit_widths;
int cached_shrink_to_fit_widths_frame_number = 0;

friend class Rml::Context;
friend class Rml::ElementStyle;
friend class Rml::ContainerBox;
Expand Down
4 changes: 4 additions & 0 deletions Include/RmlUi/Core/Math.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class Vector2;
using Vector2f = Vector2<float>;
using Vector2i = Vector2<int>;

struct Vector2fHash {
auto operator()(const Vector2f& v) const noexcept -> std::size_t;
};

namespace Math {

constexpr float RMLUI_PI = 3.141592653f;
Expand Down
6 changes: 6 additions & 0 deletions Source/Core/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ bool Context::Update()
RMLUI_ZoneScoped;

next_update_timeout = std::numeric_limits<double>::infinity();
frame_number++;

if (scroll_controller->Update(mouse_position, density_independent_pixel_ratio))
RequestNextUpdate(0);
Expand Down Expand Up @@ -1411,4 +1412,9 @@ double Context::GetNextUpdateDelay() const
return next_update_timeout;
}

int Context::GetFrameNumber() const
{
return frame_number;
}

} // namespace Rml
27 changes: 27 additions & 0 deletions Source/Core/Element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2897,4 +2897,31 @@ void Element::DirtyFontFaceRecursive()
GetChild(i)->DirtyFontFaceRecursive();
}

void Element::SetCachedShrinkToFitWidth(float width, Vector2f container_size)
{
int frame_number = GetContext()->GetFrameNumber();
if (cached_shrink_to_fit_widths_frame_number != frame_number)
{
cached_shrink_to_fit_widths.clear();
cached_shrink_to_fit_widths_frame_number = frame_number;
}
cached_shrink_to_fit_widths[container_size] = width;
}

bool Element::GetCachedShrinkToFitWidth(float& width, Vector2f container_size) const
{
int frame_number = GetContext()->GetFrameNumber();
if (cached_shrink_to_fit_widths_frame_number != frame_number)
{
return false;
}
auto it = cached_shrink_to_fit_widths.find(container_size);
if (it == cached_shrink_to_fit_widths.end())
{
return false;
}
width = it->second;
return true;
}

} // namespace Rml
8 changes: 8 additions & 0 deletions Source/Core/Layout/LayoutDetails.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ float LayoutDetails::GetShrinkToFitWidth(Element* element, Vector2f containing_b
{
RMLUI_ASSERT(element);

float cached_shrink_to_fit_width;
if (element->GetCachedShrinkToFitWidth(cached_shrink_to_fit_width, containing_block))
{
return cached_shrink_to_fit_width;
}

// @performance Can we lay out the elements directly using a fit-content size mode, instead of fetching the
// shrink-to-fit width first? Use a non-definite placeholder for the box content width, and available width as a
// maximum constraint.
Expand All @@ -260,6 +266,7 @@ float LayoutDetails::GetShrinkToFitWidth(Element* element, Vector2f containing_b
const Style::Display display = element->GetDisplay();
if (display == Style::Display::Table || display == Style::Display::InlineTable)
{
element->SetCachedShrinkToFitWidth(0.f, containing_block);
return 0.f;
}

Expand All @@ -283,6 +290,7 @@ float LayoutDetails::GetShrinkToFitWidth(Element* element, Vector2f containing_b
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);
}
element->SetCachedShrinkToFitWidth(shrink_to_fit_width, containing_block);
return shrink_to_fit_width;
}

Expand Down
6 changes: 6 additions & 0 deletions Source/Core/Math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,4 +280,10 @@ namespace Math {
}

} // namespace Math

auto Vector2fHash::operator()(const Vector2f& v) const noexcept -> size_t
{
return std::hash<float>()(v.x) ^ std::hash<float>()(v.y);
}

} // namespace Rml