Fix layout shape hug in CPP

Diffs=
35a52873c Fix layout shape hug in CPP (#7770)

Co-authored-by: Philip Chung <philterdesign@gmail.com>
diff --git a/.rive_head b/.rive_head
index 17eacd6..db3938f 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-949c70600a6c30bfe3ef6e59685235407af1a323
+35a52873cf0adabbda2670673762a36c91822e96
diff --git a/include/rive/shapes/parametric_path.hpp b/include/rive/shapes/parametric_path.hpp
index 477b9e2..a7469fe 100644
--- a/include/rive/shapes/parametric_path.hpp
+++ b/include/rive/shapes/parametric_path.hpp
@@ -12,6 +12,7 @@
                         float height,
                         LayoutMeasureMode heightMode) override;
     void controlSize(Vec2D size) override;
+    void markPathDirty(bool sendToLayout = true) override;
 
 protected:
     void widthChanged() override;
diff --git a/include/rive/shapes/path.hpp b/include/rive/shapes/path.hpp
index 59cc59b..0984138 100644
--- a/include/rive/shapes/path.hpp
+++ b/include/rive/shapes/path.hpp
@@ -58,7 +58,7 @@
     bool canDeferPathUpdate();
     void addVertex(PathVertex* vertex);
 
-    virtual void markPathDirty();
+    virtual void markPathDirty(bool sendToLayout = true);
     virtual bool isPathClosed() const { return true; }
     void onDirty(ComponentDirt dirt) override;
     inline bool isHidden() const { return (pathFlags() & 0x1) == 0x1; }
diff --git a/include/rive/shapes/points_path.hpp b/include/rive/shapes/points_path.hpp
index fd91881..743bf9c 100644
--- a/include/rive/shapes/points_path.hpp
+++ b/include/rive/shapes/points_path.hpp
@@ -10,7 +10,7 @@
     bool isPathClosed() const override { return isClosed(); }
     void buildDependencies() override;
     void update(ComponentDirt value) override;
-    void markPathDirty() override;
+    void markPathDirty(bool sendToLayout = true) override;
     void markSkinDirty() override;
     const Mat2D& pathTransform() const override;
 };
diff --git a/include/rive/shapes/shape.hpp b/include/rive/shapes/shape.hpp
index e55f794..cfb2d26 100644
--- a/include/rive/shapes/shape.hpp
+++ b/include/rive/shapes/shape.hpp
@@ -69,6 +69,10 @@
 
     AABB computeWorldBounds(const Mat2D* xform = nullptr) const;
     AABB computeLocalBounds() const;
+    Vec2D measureLayout(float width,
+                        LayoutMeasureMode widthMode,
+                        float height,
+                        LayoutMeasureMode heightMode) override;
 };
 } // namespace rive
 
diff --git a/src/shapes/parametric_path.cpp b/src/shapes/parametric_path.cpp
index b854cdf..aa39cf3 100644
--- a/src/shapes/parametric_path.cpp
+++ b/src/shapes/parametric_path.cpp
@@ -1,5 +1,8 @@
+#include "rive/layout_component.hpp"
 #include "rive/math/aabb.hpp"
+#include "rive/node.hpp"
 #include "rive/shapes/parametric_path.hpp"
+#include "rive/shapes/shape.hpp"
 
 using namespace rive;
 
@@ -8,32 +11,13 @@
                                     float height,
                                     LayoutMeasureMode heightMode)
 {
-    float measuredWidth, measuredHeight;
-    switch (widthMode)
-    {
-        case LayoutMeasureMode::atMost:
-            measuredWidth = std::max(ParametricPath::width(), width);
-            break;
-        case LayoutMeasureMode::exactly:
-            measuredWidth = width;
-            break;
-        case LayoutMeasureMode::undefined:
-            measuredWidth = ParametricPath::width();
-            break;
-    }
-    switch (heightMode)
-    {
-        case LayoutMeasureMode::atMost:
-            measuredHeight = std::max(ParametricPath::height(), height);
-            break;
-        case LayoutMeasureMode::exactly:
-            measuredHeight = height;
-            break;
-        case LayoutMeasureMode::undefined:
-            measuredHeight = ParametricPath::height();
-            break;
-    }
-    return Vec2D(measuredWidth, measuredHeight);
+    return Vec2D(
+        std::min(
+            (widthMode == LayoutMeasureMode::undefined ? std::numeric_limits<float>::max() : width),
+            ParametricPath::width()),
+        std::min((heightMode == LayoutMeasureMode::undefined ? std::numeric_limits<float>::max()
+                                                             : height),
+                 ParametricPath::height()));
 }
 
 void ParametricPath::controlSize(Vec2D size)
@@ -41,6 +25,35 @@
     width(size.x);
     height(size.y);
     markWorldTransformDirty();
+    markPathDirty(false);
+}
+
+void ParametricPath::markPathDirty(bool sendToLayout)
+{
+    Super::markPathDirty();
+#ifdef WITH_RIVE_LAYOUT
+    if (sendToLayout)
+    {
+        for (ContainerComponent* p = parent(); p != nullptr; p = p->parent())
+        {
+            if (p->is<LayoutComponent>())
+            {
+                p->as<LayoutComponent>()->markLayoutNodeDirty();
+                break;
+            }
+            // If we're in a group we break out because objects in groups do
+            // not affect nor are affected by parent LayoutComponents
+            if (p->is<Node>())
+            {
+                if (p->is<Shape>() && p->as<Shape>() == shape())
+                {
+                    continue;
+                }
+                break;
+            }
+        }
+    }
+#endif
 }
 
 void ParametricPath::widthChanged() { markPathDirty(); }
diff --git a/src/shapes/path.cpp b/src/shapes/path.cpp
index f5898fe..44784db 100644
--- a/src/shapes/path.cpp
+++ b/src/shapes/path.cpp
@@ -228,7 +228,7 @@
     }
 }
 
-void Path::markPathDirty()
+void Path::markPathDirty(bool sendToLayout)
 {
     addDirt(ComponentDirt::Path);
     if (m_Shape != nullptr)
diff --git a/src/shapes/points_path.cpp b/src/shapes/points_path.cpp
index a23b0ca..5795357 100644
--- a/src/shapes/points_path.cpp
+++ b/src/shapes/points_path.cpp
@@ -37,7 +37,7 @@
     Super::update(value);
 }
 
-void PointsPath::markPathDirty()
+void PointsPath::markPathDirty(bool sendToLayout)
 {
     if (skin() != nullptr)
     {
diff --git a/src/shapes/shape.cpp b/src/shapes/shape.cpp
index d69648b..68ccf59 100644
--- a/src/shapes/shape.cpp
+++ b/src/shapes/shape.cpp
@@ -302,4 +302,18 @@
     const Mat2D& world = worldTransform();
     Mat2D inverseWorld = world.invertOrIdentity();
     return computeWorldBounds(&inverseWorld);
+}
+
+Vec2D Shape::measureLayout(float width,
+                           LayoutMeasureMode widthMode,
+                           float height,
+                           LayoutMeasureMode heightMode)
+{
+    Vec2D size = Vec2D();
+    for (auto path : m_Paths)
+    {
+        Vec2D measured = path->measureLayout(width, widthMode, height, heightMode);
+        size = Vec2D(std::max(size.x, measured.x), std::max(size.y, measured.y));
+    }
+    return size;
 }
\ No newline at end of file