RenderPath work

Start of a larger effort to migrate RenderPath to be immutable.

If this can be done ...
- all 'stretchy' operations to incrementally build the path will be local to the runtime, reducing cross-talk with host
- output of Renderer will all be immutable, and therefore ready to be 'recorded' and replayed (in another thread)

Migration steps:
- stop calling makeEmptyRenderPath(), since this implies subsequent edits
- then RenderPath need not inherit from CommandPath
- then (optional) can make RenderPath reference-counted (like RenderImage)

Also in this PR - remove unused Difference option from PathSpace enum

Diffs=
19578d209 Try using rawpath
diff --git a/.rive_head b/.rive_head
index 75ce8b6..900be39 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-b8ca8ded5ae71e0b4519d90e87a56bcb711e0576
+19578d2097615090bbda3f214549bc41bbc391f9
diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp
index df5ce4b..e3a5962 100644
--- a/include/rive/artboard.hpp
+++ b/include/rive/artboard.hpp
@@ -41,8 +41,8 @@
     std::vector<NestedArtboard*> m_NestedArtboards;
 
     unsigned int m_DirtDepth = 0;
-    std::unique_ptr<CommandPath> m_BackgroundPath;
-    std::unique_ptr<CommandPath> m_ClipPath;
+    std::unique_ptr<RenderPath> m_BackgroundPath;
+    std::unique_ptr<RenderPath> m_ClipPath;
     Factory* m_Factory = nullptr;
     Drawable* m_FirstDrawable = nullptr;
     bool m_IsInstance = false;
@@ -95,8 +95,9 @@
     };
     void draw(Renderer* renderer, DrawOption = DrawOption::kNormal);
 
-    CommandPath* clipPath() const { return m_ClipPath.get(); }
-    CommandPath* backgroundPath() const { return m_BackgroundPath.get(); }
+    // TODO: can we remove these getters? Who is calling them?
+    RenderPath* clipPath() const { return m_ClipPath.get(); }
+    RenderPath* backgroundPath() const { return m_BackgroundPath.get(); }
 
     const std::vector<Core*>& objects() const { return m_Objects; }
     const std::vector<NestedArtboard*> nestedArtboards() const { return m_NestedArtboards; }
diff --git a/include/rive/factory.hpp b/include/rive/factory.hpp
index 7389869..3ee59a8 100644
--- a/include/rive/factory.hpp
+++ b/include/rive/factory.hpp
@@ -47,6 +47,7 @@
                                                        Span<const PathVerb> verbs,
                                                        FillRule) = 0;
 
+    // Deprecated -- working to make RenderPath's immutable
     virtual std::unique_ptr<RenderPath> makeEmptyRenderPath() = 0;
 
     virtual std::unique_ptr<RenderPaint> makeRenderPaint() = 0;
@@ -54,6 +55,11 @@
     virtual std::unique_ptr<RenderImage> decodeImage(Span<const uint8_t>) = 0;
 
     virtual rcp<RenderFont> decodeFont(Span<const uint8_t>) { return nullptr; }
+
+    // Non-virtual helpers
+
+    std::unique_ptr<RenderPath> makeRenderPath(const AABB&);
+    std::unique_ptr<RenderPath> makeRenderPath(const RawPath&, FillRule);
 };
 
 } // namespace rive
diff --git a/include/rive/shapes/path_space.hpp b/include/rive/shapes/path_space.hpp
index 76bbf21..8e93a0a 100644
--- a/include/rive/shapes/path_space.hpp
+++ b/include/rive/shapes/path_space.hpp
@@ -8,8 +8,7 @@
     Neither = 0,
     Local = 1 << 1,
     World = 1 << 2,
-    Difference = 1 << 3,
-    Clipping = 1 << 4
+    Clipping = 1 << 3
 };
 
 inline constexpr PathSpace operator&(PathSpace lhs, PathSpace rhs) {
diff --git a/src/artboard.cpp b/src/artboard.cpp
index e9458d8..94026da 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -8,6 +8,7 @@
 #include "rive/draw_target_placement.hpp"
 #include "rive/drawable.hpp"
 #include "rive/animation/keyed_object.hpp"
+#include "rive/factory.hpp"
 #include "rive/node.hpp"
 #include "rive/renderer.hpp"
 #include "rive/shapes/paint/shape_paint.hpp"
@@ -52,8 +53,9 @@
 StatusCode Artboard::initialize() {
     StatusCode code;
 
-    m_BackgroundPath = makeCommandPath(PathSpace::Neither);
-    m_ClipPath = makeCommandPath(PathSpace::Neither);
+    // these will be re-built in update() -- are they needed here?
+    m_BackgroundPath = factory()->makeEmptyRenderPath();
+    m_ClipPath = factory()->makeEmptyRenderPath();
 
     // onAddedDirty guarantees that all objects are now available so they can be
     // looked up by index/id. This is where nodes find their parents, but they
@@ -326,13 +328,15 @@
         sortDrawOrder();
     }
     if (hasDirt(value, ComponentDirt::Path)) {
-        m_ClipPath->reset();
+        AABB bg = {-width() * originX(), -height() * originY(), width(), height()};
+        AABB clip;
         if (m_FrameOrigin) {
-            m_ClipPath->addRect(0.0f, 0.0f, width(), height());
+            clip = {0.0f, 0.0f, width(), height()};
         } else {
-            m_ClipPath->addRect(-width() * originX(), -height() * originY(), width(), height());
+            clip = bg;
         }
-        m_BackgroundPath->addRect(-width() * originX(), -height() * originY(), width(), height());
+        m_ClipPath = factory()->makeRenderPath(clip);
+        m_BackgroundPath = factory()->makeRenderPath(bg);
     }
 }
 
@@ -414,7 +418,7 @@
 void Artboard::draw(Renderer* renderer, DrawOption option) {
     renderer->save();
     if (clip()) {
-        renderer->clipPath(m_ClipPath->renderPath());
+        renderer->clipPath(m_ClipPath.get());
     }
 
     if (m_FrameOrigin) {
@@ -426,7 +430,7 @@
 
     if (option != DrawOption::kHideBG) {
         for (auto shapePaint : m_ShapePaints) {
-            shapePaint->draw(renderer, backgroundPath());
+            shapePaint->draw(renderer, m_BackgroundPath.get());
         }
     }
 
@@ -623,4 +627,4 @@
         scene = this->animationAt(0);
     }
     return scene;
-}
\ No newline at end of file
+}
diff --git a/src/factory.cpp b/src/factory.cpp
new file mode 100644
index 0000000..693a287
--- /dev/null
+++ b/src/factory.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2022 Rive
+ */
+
+#include "rive/factory.hpp"
+#include "rive/math/aabb.hpp"
+#include "rive/math/raw_path.hpp"
+
+using namespace rive;
+
+std::unique_ptr<RenderPath> Factory::makeRenderPath(const AABB& r) {
+    const Vec2D pts[] = {
+        {r.left(), r.top()},
+        {r.right(), r.top()},
+        {r.right(), r.bottom()},
+        {r.left(), r.bottom()},
+    };
+    const PathVerb verbs[] = {
+        PathVerb::move,
+        PathVerb::line,
+        PathVerb::line,
+        PathVerb::line,
+        PathVerb::close,
+    };
+    return this->makeRenderPath(pts, verbs, FillRule::nonZero);
+}
+
+std::unique_ptr<RenderPath> Factory::makeRenderPath(const RawPath& rp, FillRule fill) {
+    return this->makeRenderPath(rp.points(), rp.verbs(), fill);
+}
diff --git a/viewer/src/viewer_content/text_content.cpp b/viewer/src/viewer_content/text_content.cpp
index 01190a9..2d97a0d 100644
--- a/viewer/src/viewer_content/text_content.cpp
+++ b/viewer/src/viewer_content/text_content.cpp
@@ -52,8 +52,7 @@
         auto trans = rive::Mat2D::fromTranslate(origin.x + run.xpos[i], origin.y);
         auto rawpath = font->getPath(run.glyphs[i]);
         rawpath.transformInPlace(trans * scale);
-        auto path =
-            factory->makeRenderPath(rawpath.points(), rawpath.verbs(), rive::FillRule::nonZero);
+        auto path = factory->makeRenderPath(rawpath, rive::FillRule::nonZero);
         renderer->drawPath(path.get(), paint.get());
     }
 }
@@ -114,14 +113,20 @@
 }
 #endif
 
+static std::unique_ptr<rive::RenderPath> make_line(rive::Factory* factory,
+                                                   rive::Vec2D a,
+                                                   rive::Vec2D b) {
+    rive::Vec2D pts[] = {a, b};
+    rive::PathVerb vbs[] = {rive::PathVerb::move, rive::PathVerb::line};
+    return factory->makeRenderPath(pts, vbs, rive::FillRule::nonZero);
+}
+
 static void draw_line(rive::Factory* factory, rive::Renderer* renderer, float x) {
     auto paint = factory->makeRenderPaint();
     paint->style(rive::RenderPaintStyle::stroke);
     paint->thickness(1);
     paint->color(0xFFFFFFFF);
-    auto path = factory->makeEmptyRenderPath();
-    path->move({x, 0});
-    path->line({x, 1000});
+    auto path = make_line(factory, {x, 0}, {x, 1000});
     renderer->drawPath(path.get(), paint.get());
 }
 
diff --git a/viewer/src/viewer_content/textpath_content.cpp b/viewer/src/viewer_content/textpath_content.cpp
index 80856d8..83b1051 100644
--- a/viewer/src/viewer_content/textpath_content.cpp
+++ b/viewer/src/viewer_content/textpath_content.cpp
@@ -60,9 +60,7 @@
 ////////////////////////////////////////////////////////////////////////////////////
 
 static std::unique_ptr<RenderPath> make_rpath(const RawPath& path) {
-    return ViewerContent::RiveFactory()->makeRenderPath(path.points(),
-                                                        path.verbs(),
-                                                        FillRule::nonZero);
+    return ViewerContent::RiveFactory()->makeRenderPath(path, FillRule::nonZero);
 }
 
 static void stroke_path(Renderer* renderer, const RawPath& path, float size, ColorInt color) {
diff --git a/viewer/src/viewer_content/trimpath_content.cpp b/viewer/src/viewer_content/trimpath_content.cpp
index 89c9bb9..f5f321c 100644
--- a/viewer/src/viewer_content/trimpath_content.cpp
+++ b/viewer/src/viewer_content/trimpath_content.cpp
@@ -33,9 +33,7 @@
 ////////////////////////////////////////////////////////////////////////////////////
 
 static std::unique_ptr<RenderPath> make_rpath(const RawPath& path) {
-    return ViewerContent::RiveFactory()->makeRenderPath(path.points(),
-                                                        path.verbs(),
-                                                        FillRule::nonZero);
+    return ViewerContent::RiveFactory()->makeRenderPath(path, FillRule::nonZero);
 }
 
 static void stroke_path(Renderer* renderer, const RawPath& path, float size, ColorInt color) {