Utilities for rawpath

- addPath()
- operator==

Diffs=
f9a5698be Add != operator
diff --git a/.rive_head b/.rive_head
index 944c886..a3be2d6 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-698af558ea299e28e9524d4e874f33ba7b18aa99
+f9a5698be92024c4c4a1b7337575f85341d89211
diff --git a/include/rive/math/raw_path.hpp b/include/rive/math/raw_path.hpp
index cb03941..7a89329 100644
--- a/include/rive/math/raw_path.hpp
+++ b/include/rive/math/raw_path.hpp
@@ -31,6 +31,9 @@
     RawPath() {}
     ~RawPath() {}
 
+    bool operator==(const RawPath& o) const;
+    bool operator!=(const RawPath& o) const { return !(*this == o); }
+
     bool empty() const { return m_Points.empty(); }
     AABB bounds() const;
 
@@ -77,6 +80,8 @@
     void addOval(const AABB&, PathDirection = PathDirection::cw);
     void addPoly(Span<const Vec2D>, bool isClosed);
 
+    void addPath(const RawPath&, const Mat2D* = nullptr);
+
     class Iter {
         const Vec2D* m_currPts;
         const PathVerb* m_currVerb;
diff --git a/src/math/raw_path.cpp b/src/math/raw_path.cpp
index 8e56837..5f45a8c 100644
--- a/src/math/raw_path.cpp
+++ b/src/math/raw_path.cpp
@@ -4,6 +4,8 @@
 
 #include "rive/math/raw_path.hpp"
 #include <cmath>
+#include <cstring>
+#include <algorithm>
 
 using namespace rive;
 
@@ -13,6 +15,10 @@
                  std::size_t verbCount) :
     m_Points(points, points + pointCount), m_Verbs(verbs, verbs + verbCount) {}
 
+bool RawPath::operator==(const RawPath& o) const {
+    return m_Points == o.m_Points && m_Verbs == o.m_Verbs;
+}
+
 AABB RawPath::bounds() const {
     if (this->empty()) {
         return {0, 0, 0, 0};
@@ -167,6 +173,21 @@
     }
 }
 
+void RawPath::addPath(const RawPath& src, const Mat2D* mat) {
+    m_Verbs.insert(m_Verbs.end(), src.m_Verbs.cbegin(), src.m_Verbs.cend());
+
+    if (mat) {
+        const auto oldPointCount = m_Points.size();
+        m_Points.resize(oldPointCount + src.m_Points.size());
+        Vec2D* dst = m_Points.data() + oldPointCount;
+        for (auto i = 0; i < src.m_Points.size(); ++i) {
+            dst[i] = *mat * src.m_Points[i];
+        }
+    } else {
+        m_Points.insert(m_Points.end(), src.m_Points.cbegin(), src.m_Points.cend());
+    }
+}
+
 //////////////////////////////////////////////////////////////////////////
 
 namespace rive {
diff --git a/test/raw_path_test.cpp b/test/raw_path_test.cpp
index 8b34f66..e24bf9e 100644
--- a/test/raw_path_test.cpp
+++ b/test/raw_path_test.cpp
@@ -235,3 +235,65 @@
     REQUIRE((rec && is_move(rec) && eq(rec.pts[0], 1, 2)));
     REQUIRE(rec.pts == move_pts);
 }
+
+TEST_CASE("addPath", "[rawpath]") {
+    using PathMaker = void (*)(RawPath * sink);
+
+    const PathMaker makers[] = {
+        [](RawPath* sink) {},
+        [](RawPath* sink) {
+            sink->moveTo(1, 2);
+            sink->lineTo(3, 4);
+        },
+        [](RawPath* sink) {
+            sink->moveTo(1, 2);
+            sink->lineTo(3, 4);
+            sink->close();
+        },
+        [](RawPath* sink) {
+            sink->moveTo(1, 2);
+            sink->lineTo(3, 4);
+            sink->quadTo(5, 6, 7, 8);
+            sink->cubicTo(9, 10, 11, 12, 13, 14);
+            sink->close();
+        },
+    };
+    constexpr size_t N = sizeof(makers) / sizeof(makers[0]);
+
+    auto direct = [](PathMaker m0, PathMaker m1, const Mat2D* mx) {
+        RawPath p;
+        m0(&p);
+        m1(&p);
+        if (mx) {
+            p.transformInPlace(*mx);
+        }
+        return p;
+    };
+    auto useadd = [](PathMaker m0, PathMaker m1, const Mat2D* mx) {
+        RawPath p;
+
+        RawPath tmp;
+        m0(&tmp);
+        p.addPath(tmp, mx);
+
+        tmp.reset();
+        m1(&tmp);
+        p.addPath(tmp, mx);
+        return p;
+    };
+
+    for (auto i = 0; i < N; ++i) {
+        for (auto j = 0; j < N; ++j) {
+            RawPath p0, p1;
+
+            p0 = direct(makers[i], makers[j], nullptr);
+            p1 = useadd(makers[i], makers[j], nullptr);
+            REQUIRE(p0 == p1);
+
+            auto mx = Mat2D::fromScale(2, 3);
+            p0 = direct(makers[i], makers[j], &mx);
+            p1 = useadd(makers[i], makers[j], &mx);
+            REQUIRE(p0 == p1);
+        }
+    }
+}