rive-app / rive-app/rive-runtime
`propagateSizeToChildren()` skips `NodeBase` (Group) children, preventing layout propagation to nested Images
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 1.2k
- Forks
- 121
- PR merge metrics
- No merged PRs in 30d
Description
Summary
LayoutComponent::propagateSizeToChildren() contains a hardcoded exclusion that skips all children of type NodeBase (Groups). This prevents the layout engine from traversing into Group containers to find nested Image components, effectively cutting off the entire subtree from receiving layout dimensions. Images inside Groups inside Layouts never receive controlSize() calls and render with editor-baked scale values.
Severity
Medium-High — Affects any Layout hierarchy where Images are nested inside Groups (which DataBinding can produce via ViewModel structure).
Environment
- Runtime: rive-cpp (C++ runtime)
- Platform: All platforms using the C++ runtime
Steps to Reproduce
- Create a Rive file with:
- A
LayoutComponent(fixed dimensions) - A
Group(Node) inside the Layout - An
Imageinside the Group
- A
- Load the
.rivfile and inject a dynamic image - Observe that the Image never receives
controlSize()and renders at placeholder dimensions
Root Cause
In propagateSizeToChildren(), the original code contained:
void LayoutComponent::propagateSizeToChildren(ContainerComponent* component)
{
for (auto child : component->children())
{
if (child->is<LayoutComponent>()) { continue; }
// ⚠️ BUG: This skips ALL Group nodes, preventing recursion
// into their children where Images may live
if (child->coreType() == NodeBase::typeKey) {
continue; // ← Entire subtree cut off!
}
auto sizeableChild = IntrinsicallySizeable::from(child);
if (sizeableChild != nullptr) {
sizeableChild->controlSize(...);
}
// Recursion into ContainerComponent children
if (child->is<ContainerComponent>()) {
propagateSizeToChildren(child->as<ContainerComponent>());
}
}
}
The NodeBase::typeKey check prevents the function from ever reaching the recursive propagateSizeToChildren() call at the bottom, so any Image nested inside a Group is never visited.
Proposed Fix
Remove the NodeBase exclusion. The function should recurse into all ContainerComponent children, including Groups:
void LayoutComponent::propagateSizeToChildren(ContainerComponent* component)
{
for (auto child : component->children())
{
if (child->is<LayoutComponent>()) { continue; }
// Removed: if (child->coreType() == NodeBase::typeKey) { continue; }
auto sizeableChild = IntrinsicallySizeable::from(child);
if (sizeableChild != nullptr) {
sizeableChild->controlSize(...);
if (!sizeableChild->shouldPropagateSizeToChildren()) {
continue;
}
}
if (child->is<ContainerComponent>()) {
propagateSizeToChildren(child->as<ContainerComponent>());
}
}
}
Impact Assessment
The NodeBase exclusion may have been added to avoid traversing into Groups that shouldn't receive layout sizing (e.g., purely organizational folders). However, Groups can legitimately contain sizeable children like Images in DataBinding hierarchies. The IntrinsicallySizeable::from() check and shouldPropagateSizeToChildren() guard already handle the case where a child shouldn't receive sizing information.
Diagnostic Evidence
Before fix — Image never receives controlSize because Group child is skipped entirely:
(no propagateSizeToChildren or controlSize logs for the Image — the Group's subtree is never entered)
After fix — Group (isSizeable=0) is traversed, Image (isSizeable=1) is found and receives correct dimensions:
[RIVE DIAG] propagateSize: m_layout w=32.000000 h=32.000000, effective w=547.000000 h=461.000000, authored w=547.000000 h=461.000000
[RIVE DIAG] propagateSizeToChildren: found child (isSizeable=0)
[RIVE DIAG] propagateSizeToChildren: found child (isSizeable=1)
[RIVE DIAG] Image::controlSize called: w=547.000000, h=461.000000 (prev w=nan, h=nan)
[RIVE DIAG] updateImageScale: renderImage=000001A290F997C0, layoutW=547.000000, layoutH=461.000000, isNanW=0, isNanH=0
[RIVE DIAG] updateImageScale: COMPUTING fit=1, imgW=2160.000000, imgH=3840.000000, layoutW=547.000000, layoutH=461.000000
[RIVE DIAG] updateImageScale: CONTAIN s=0.120052, newScaleX=0.120052, newScaleY=0.120052
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at LayoutComponent::propagateSizeToChildren() and trace how its children are filtered and recursively visited. Reproduce the nested Layout, Group, and Image case with a dynamic image, then verify that the Image receives controlSize() and renders with propagated dimensions rather than editor-baked scale values.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100