Fix libjpg on Mac Sonoma

Diffs=
dde676085 Fix libjpg on Mac Sonoma (#7329)
e0a786c90 Runtime API for Nested Inputs (#7316)

Co-authored-by: Chris Dalton <99840794+csmartdalton@users.noreply.github.com>
Co-authored-by: Gordon Hayes <pggordonhayes@gmail.com>
Co-authored-by: Philip Chung <philterdesign@gmail.com>
diff --git a/.rive_head b/.rive_head
index ee9abc1..30ea12c 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-01d20e02661309cd2f8a0702f9de102107c1a0f1
+dde676085908d492af545660cbbb19ee0d10d91d
diff --git a/dependencies/jconfig.h b/dependencies/jconfig.h
index b0daaa1..84c05fc 100644
--- a/dependencies/jconfig.h
+++ b/dependencies/jconfig.h
@@ -1,3 +1,5 @@
+#include <stdio.h> // Required on Mac -- libjpg expects FILE to be already defined.
+
 #define HAVE_PROTOTYPES
 #define HAVE_UNSIGNED_CHAR
 #define HAVE_UNSIGNED_SHORT
@@ -8,4 +10,4 @@
 #undef NEED_SYS_TYPES_H
 #undef NEED_FAR_POINTERS
 #undef NEED_SHORT_EXTERNAL_NAMES
-#undef INCOMPLETE_TYPES_BROKEN
\ No newline at end of file
+#undef INCOMPLETE_TYPES_BROKEN
diff --git a/include/rive/animation/nested_input.hpp b/include/rive/animation/nested_input.hpp
index 0db46df..fe75467 100644
--- a/include/rive/animation/nested_input.hpp
+++ b/include/rive/animation/nested_input.hpp
@@ -1,6 +1,7 @@
 #ifndef _RIVE_NESTED_INPUT_HPP_
 #define _RIVE_NESTED_INPUT_HPP_
 #include "rive/animation/nested_state_machine.hpp"
+#include "rive/animation/state_machine_input_instance.hpp"
 #include "rive/generated/animation/nested_input_base.hpp"
 #include <stdio.h>
 namespace rive
@@ -21,7 +22,6 @@
 
     virtual void applyValue() {}
 
-protected:
     SMIInput* input() const
     {
         auto parent = this->parent();
@@ -34,6 +34,16 @@
         }
         return nullptr;
     }
+
+    const std::string name() const
+    {
+        auto smi = input();
+        if (smi != nullptr)
+        {
+            return smi->name();
+        }
+        return std::string();
+    }
 };
 } // namespace rive
 
diff --git a/include/rive/animation/nested_state_machine.hpp b/include/rive/animation/nested_state_machine.hpp
index 489d631..c76729a 100644
--- a/include/rive/animation/nested_state_machine.hpp
+++ b/include/rive/animation/nested_state_machine.hpp
@@ -30,6 +30,9 @@
     HitResult pointerExit(Vec2D position);
 
     void addNestedInput(NestedInput* input);
+    size_t inputCount() { return m_nestedInputs.size(); }
+    NestedInput* input(size_t index);
+    NestedInput* input(std::string name);
 };
 } // namespace rive
 
diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp
index 69a339d..b8fdea3 100644
--- a/include/rive/artboard.hpp
+++ b/include/rive/artboard.hpp
@@ -32,6 +32,10 @@
 class Joystick;
 class TextValueRun;
 class Event;
+class SMIBool;
+class SMIInput;
+class SMINumber;
+class SMITrigger;
 
 class Artboard : public ArtboardBase, public CoreContext, public ShapePaintContainer
 {
@@ -120,6 +124,8 @@
 
     const std::vector<Core*>& objects() const { return m_Objects; }
     const std::vector<NestedArtboard*> nestedArtboards() const { return m_NestedArtboards; }
+    NestedArtboard* nestedArtboard(const std::string& name) const;
+    NestedArtboard* nestedArtboardAtPath(const std::string& path) const;
 
     AABB bounds() const;
 
@@ -295,6 +301,13 @@
     // 3. first animation instance
     // 4. nullptr
     std::unique_ptr<Scene> defaultScene();
+
+    SMIInput* input(const std::string& name, const std::string& path);
+    template <typename InstType>
+    InstType* getNamedInput(const std::string& name, const std::string& path);
+    SMIBool* getBool(const std::string& name, const std::string& path);
+    SMINumber* getNumber(const std::string& name, const std::string& path);
+    SMITrigger* getTrigger(const std::string& name, const std::string& path);
 };
 } // namespace rive
 
diff --git a/include/rive/nested_artboard.hpp b/include/rive/nested_artboard.hpp
index e075c86..14bd7c1 100644
--- a/include/rive/nested_artboard.hpp
+++ b/include/rive/nested_artboard.hpp
@@ -10,6 +10,9 @@
 {
 class ArtboardInstance;
 class NestedAnimation;
+class NestedInput;
+class NestedStateMachine;
+class StateMachineInstance;
 class NestedArtboard : public NestedArtboardBase
 {
 
@@ -37,6 +40,10 @@
 
     bool hasNestedStateMachines() const;
     Span<NestedAnimation*> nestedAnimations();
+    NestedArtboard* nestedArtboard(std::string name) const;
+    NestedStateMachine* stateMachine(std::string name) const;
+    NestedInput* input(std::string name) const;
+    NestedInput* input(std::string name, std::string stateMachineName) const;
 
     /// Convert a world space (relative to the artboard that this
     /// NestedArtboard is a child of) to the local space of the Artboard
diff --git a/src/animation/nested_state_machine.cpp b/src/animation/nested_state_machine.cpp
index f04477f..f973429 100644
--- a/src/animation/nested_state_machine.cpp
+++ b/src/animation/nested_state_machine.cpp
@@ -32,7 +32,6 @@
             nestedInput->applyValue();
         }
     }
-    m_nestedInputs.clear();
 }
 
 StateMachineInstance* NestedStateMachine::stateMachineInstance()
@@ -76,4 +75,25 @@
     return HitResult::none;
 }
 
+NestedInput* NestedStateMachine::input(size_t index)
+{
+    if (index < m_nestedInputs.size())
+    {
+        return m_nestedInputs[index];
+    }
+    return nullptr;
+}
+
+NestedInput* NestedStateMachine::input(std::string name)
+{
+    for (auto input : m_nestedInputs)
+    {
+        if (input->name() == name)
+        {
+            return input;
+        }
+    }
+    return nullptr;
+}
+
 void NestedStateMachine::addNestedInput(NestedInput* input) { m_nestedInputs.push_back(input); }
\ No newline at end of file
diff --git a/src/artboard.cpp b/src/artboard.cpp
index 0ddaf7b..4458ecf 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -15,6 +15,10 @@
 #include "rive/importers/backboard_importer.hpp"
 #include "rive/nested_artboard.hpp"
 #include "rive/joystick.hpp"
+#include "rive/animation/nested_bool.hpp"
+#include "rive/animation/nested_number.hpp"
+#include "rive/animation/nested_trigger.hpp"
+#include "rive/animation/state_machine_input_instance.hpp"
 #include "rive/animation/state_machine_instance.hpp"
 #include "rive/shapes/shape.hpp"
 #include "rive/text/text_value_run.hpp"
@@ -758,6 +762,47 @@
     return index;
 }
 
+NestedArtboard* Artboard::nestedArtboard(const std::string& name) const
+{
+    for (auto nested : m_NestedArtboards)
+    {
+        if (nested->name() == name)
+        {
+            return nested;
+        }
+    }
+    return nullptr;
+}
+
+NestedArtboard* Artboard::nestedArtboardAtPath(const std::string& path) const
+{
+    // name parameter can be a name or a path to recursively find a nested artboard
+    std::string delimiter = "/";
+    size_t firstDelim = path.find(delimiter);
+    std::string artboardName = firstDelim == std::string::npos ? path : path.substr(0, firstDelim);
+    std::string restOfPath =
+        firstDelim == std::string::npos ? "" : path.substr(firstDelim + 1, path.size());
+
+    // Find the nested artboard at this level
+    if (!artboardName.empty())
+    {
+        auto nested = nestedArtboard(artboardName);
+        if (nested != nullptr)
+        {
+            if (restOfPath.empty())
+            {
+                return nested;
+            }
+            else
+            {
+                auto artboard = nested->artboard();
+                return artboard->nestedArtboardAtPath(restOfPath);
+            }
+        }
+    }
+    return nullptr;
+}
+
 // std::unique_ptr<ArtboardInstance> Artboard::instance() const
 // {
 //     std::unique_ptr<ArtboardInstance> artboardClone(new ArtboardInstance);
@@ -896,6 +941,43 @@
     return scene;
 }
 
+SMIInput* ArtboardInstance::input(const std::string& name, const std::string& path)
+{
+    return getNamedInput<SMIInput>(name, path);
+}
+
+template <typename InstType>
+InstType* ArtboardInstance::getNamedInput(const std::string& name, const std::string& path)
+{
+    if (!path.empty())
+    {
+        auto nestedArtboard = nestedArtboardAtPath(path);
+        if (nestedArtboard != nullptr)
+        {
+            auto input = nestedArtboard->input(name);
+            if (input != nullptr && input->input() != nullptr)
+            {
+                return static_cast<InstType*>(input->input());
+            }
+        }
+    }
+    return nullptr;
+}
+
+SMIBool* ArtboardInstance::getBool(const std::string& name, const std::string& path)
+{
+    return getNamedInput<SMIBool>(name, path);
+}
+
+SMINumber* ArtboardInstance::getNumber(const std::string& name, const std::string& path)
+{
+    return getNamedInput<SMINumber>(name, path);
+}
+SMITrigger* ArtboardInstance::getTrigger(const std::string& name, const std::string& path)
+{
+    return getNamedInput<SMITrigger>(name, path);
+}
+
 #ifdef EXTERNAL_RIVE_AUDIO_ENGINE
 rcp<AudioEngine> Artboard::audioEngine() const { return m_audioEngine; }
 void Artboard::audioEngine(rcp<AudioEngine> audioEngine)
diff --git a/src/nested_artboard.cpp b/src/nested_artboard.cpp
index 901661c..1c58040 100644
--- a/src/nested_artboard.cpp
+++ b/src/nested_artboard.cpp
@@ -164,6 +164,56 @@
 
 Span<NestedAnimation*> NestedArtboard::nestedAnimations() { return m_NestedAnimations; }
 
+NestedArtboard* NestedArtboard::nestedArtboard(std::string name) const
+{
+    if (m_Instance != nullptr)
+    {
+        return m_Instance->nestedArtboard(name);
+    }
+    return nullptr;
+}
+
+NestedStateMachine* NestedArtboard::stateMachine(std::string name) const
+{
+    for (auto animation : m_NestedAnimations)
+    {
+        if (animation->is<NestedStateMachine>() && animation->name() == name)
+        {
+            return animation->as<NestedStateMachine>();
+        }
+    }
+    return nullptr;
+}
+
+NestedInput* NestedArtboard::input(std::string name) const { return input(name, ""); }
+
+NestedInput* NestedArtboard::input(std::string name, std::string stateMachineName) const
+{
+    if (!stateMachineName.empty())
+    {
+        auto nestedSM = stateMachine(stateMachineName);
+        if (nestedSM != nullptr)
+        {
+            return nestedSM->input(name);
+        }
+    }
+    else
+    {
+        for (auto animation : m_NestedAnimations)
+        {
+            if (animation->is<NestedStateMachine>())
+            {
+                auto input = animation->as<NestedStateMachine>()->input(name);
+                if (input != nullptr)
+                {
+                    return input;
+                }
+            }
+        }
+    }
+    return nullptr;
+}
+
 bool NestedArtboard::worldToLocal(Vec2D world, Vec2D* local)
 {
     assert(local != nullptr);
diff --git a/test/assets/runtime_nested_inputs.riv b/test/assets/runtime_nested_inputs.riv
new file mode 100644
index 0000000..04c2395
--- /dev/null
+++ b/test/assets/runtime_nested_inputs.riv
Binary files differ
diff --git a/test/nested_input_test.cpp b/test/nested_input_test.cpp
new file mode 100644
index 0000000..a40b58c
--- /dev/null
+++ b/test/nested_input_test.cpp
@@ -0,0 +1,139 @@
+#include "rive/core/binary_reader.hpp"
+#include "rive/file.hpp"
+#include "rive/nested_artboard.hpp"
+#include "rive/animation/nested_bool.hpp"
+#include "rive/animation/nested_input.hpp"
+#include "rive/animation/nested_number.hpp"
+#include "rive/animation/nested_trigger.hpp"
+#include "rive/animation/state_machine_instance.hpp"
+#include "rive/animation/state_machine_input_instance.hpp"
+#include "catch.hpp"
+#include "rive_file_reader.hpp"
+#include <cstdio>
+
+TEST_CASE("validate nested boolean get/set", "[nestedInput]")
+{
+    auto file = ReadRiveFile("../../test/assets/runtime_nested_inputs.riv");
+
+    auto artboard = file->artboard("MainArtboard")->instance();
+    REQUIRE(artboard != nullptr);
+    REQUIRE(artboard->stateMachineCount() == 1);
+
+    // Test getting/setting boolean SMIInput via nested artboard path
+    auto boolInput = artboard->getBool("CircleOuterState", "CircleOuter");
+    auto smiInput = artboard->input("CircleOuterState", "CircleOuter");
+    auto smiBoolInput = static_cast<rive::SMIBool*>(smiInput);
+    auto nestedArtboard = artboard->nestedArtboard("CircleOuter");
+    auto nestedInput = nestedArtboard->input("CircleOuterState")->as<rive::NestedBool>();
+    REQUIRE(boolInput->value() == false);
+    REQUIRE(smiBoolInput->value() == false);
+    REQUIRE(nestedInput->nestedValue() == false);
+
+    boolInput->value(true);
+    REQUIRE(boolInput->value() == true);
+    REQUIRE(smiBoolInput->value() == true);
+    REQUIRE(nestedInput->nestedValue() == true);
+
+    smiBoolInput->value(false);
+    REQUIRE(boolInput->value() == false);
+    REQUIRE(smiBoolInput->value() == false);
+    REQUIRE(nestedInput->nestedValue() == false);
+
+    nestedInput->nestedValue(true);
+    REQUIRE(boolInput->value() == true);
+    REQUIRE(smiBoolInput->value() == true);
+    REQUIRE(nestedInput->nestedValue() == true);
+}
+
+TEST_CASE("validate nested number get/set", "[nestedInput]")
+{
+    auto file = ReadRiveFile("../../test/assets/runtime_nested_inputs.riv");
+
+    auto artboard = file->artboard("MainArtboard")->instance();
+    REQUIRE(artboard != nullptr);
+    REQUIRE(artboard->stateMachineCount() == 1);
+
+    // Test getting/setting number SMIInput via nested artboard path
+    auto numInput = artboard->getNumber("CircleOuterNumber", "CircleOuter");
+    auto smiInput = artboard->input("CircleOuterNumber", "CircleOuter");
+    auto smiNumInput = static_cast<rive::SMINumber*>(smiInput);
+    auto nestedArtboard = artboard->nestedArtboardAtPath("CircleOuter");
+    auto nestedInput = nestedArtboard->input("CircleOuterNumber")->as<rive::NestedNumber>();
+    REQUIRE(numInput->value() == 0);
+    REQUIRE(smiNumInput->value() == 0);
+    REQUIRE(nestedInput->nestedValue() == 0);
+
+    numInput->value(10);
+    REQUIRE(numInput->value() == 10);
+    REQUIRE(smiNumInput->value() == 10);
+    REQUIRE(nestedInput->nestedValue() == 10);
+
+    smiNumInput->value(5);
+    REQUIRE(numInput->value() == 5);
+    REQUIRE(smiNumInput->value() == 5);
+    REQUIRE(nestedInput->nestedValue() == 5);
+
+    nestedInput->nestedValue(99);
+    REQUIRE(numInput->value() == 99);
+    REQUIRE(smiNumInput->value() == 99);
+    REQUIRE(nestedInput->nestedValue() == 99);
+}
+
+TEST_CASE("validate nested trigger fire", "[nestedInput]")
+{
+    auto file = ReadRiveFile("../../test/assets/runtime_nested_inputs.riv");
+
+    auto artboard = file->artboard("MainArtboard")->instance();
+    REQUIRE(artboard != nullptr);
+    REQUIRE(artboard->stateMachineCount() == 1);
+
+    // Test getting/setting number SMIInput via nested artboard path
+    auto tInput = artboard->getTrigger("CircleOuterTrigger", "CircleOuter");
+    auto smiInput = artboard->input("CircleOuterTrigger", "CircleOuter");
+    auto smiTInput = static_cast<rive::SMITrigger*>(smiInput);
+    auto nestedArtboard = artboard->nestedArtboardAtPath("CircleOuter");
+    auto nestedInput = nestedArtboard->input("CircleOuterTrigger")->as<rive::NestedTrigger>();
+    auto nestedSMI = static_cast<rive::SMITrigger*>(nestedInput->input());
+    REQUIRE(tInput->didFire() == false);
+    REQUIRE(smiTInput->didFire() == false);
+    REQUIRE(nestedSMI->didFire() == false);
+
+    tInput->fire();
+    REQUIRE(tInput->didFire() == true);
+    REQUIRE(smiTInput->didFire() == true);
+    REQUIRE(nestedSMI->didFire() == true);
+}
+
+TEST_CASE("validate nested boolean get/set multiple nested artboards deep", "[nestedInput]")
+{
+    auto file = ReadRiveFile("../../test/assets/runtime_nested_inputs.riv");
+
+    auto artboard = file->artboard("MainArtboard")->instance();
+    REQUIRE(artboard != nullptr);
+    REQUIRE(artboard->stateMachineCount() == 1);
+
+    // Test getting/setting boolean SMIInput via nested artboard path
+    auto boolInput = artboard->getBool("CircleInnerState", "CircleOuter/CircleInner");
+    auto smiInput = artboard->input("CircleInnerState", "CircleOuter/CircleInner");
+    auto smiBoolInput = static_cast<rive::SMIBool*>(smiInput);
+    auto nestedArtboard = artboard->nestedArtboardAtPath("CircleOuter/CircleInner");
+    auto nestedInput = nestedArtboard->input("CircleInnerState")->as<rive::NestedBool>();
+    REQUIRE(boolInput->value() == false);
+    REQUIRE(smiBoolInput->value() == false);
+    REQUIRE(nestedInput->nestedValue() == false);
+
+    boolInput->value(true);
+    REQUIRE(boolInput->value() == true);
+    REQUIRE(smiBoolInput->value() == true);
+    REQUIRE(nestedInput->nestedValue() == true);
+
+    smiBoolInput->value(false);
+    REQUIRE(boolInput->value() == false);
+    REQUIRE(smiBoolInput->value() == false);
+    REQUIRE(nestedInput->nestedValue() == false);
+
+    nestedInput->nestedValue(true);
+    REQUIRE(boolInput->value() == true);
+    REQUIRE(smiBoolInput->value() == true);
+    REQUIRE(nestedInput->nestedValue() == true);
+}
\ No newline at end of file