Work on font-fallback

This is a way to handle missing characters from a given Font -- we detect this, and then try using other font(s).

The current test just adds some Chinese characters and tries to draw them (which are not present in most of our sample fonts).

CoreGraphics backend handles this for us, we just needed to notice when they introduce a new/different font in the GlyphRun, and wrap-it.

Diffs=
4f4b79858 Work on font-fallback
diff --git a/.rive_head b/.rive_head
index 59c273c..aa0c0ba 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-62ffe45abd81545a3838b163634ec1058b7a2eac
+4f4b7985889978f2ab8b8aa9315780cb2b0c76a7
diff --git a/include/rive/render_text.hpp b/include/rive/render_text.hpp
index e4e7886..0398a82 100644
--- a/include/rive/render_text.hpp
+++ b/include/rive/render_text.hpp
@@ -11,7 +11,7 @@
 
 namespace rive {
 
-    using Unichar = int32_t;
+    using Unichar = uint32_t;
     using GlyphID = uint16_t;
 
     struct RenderTextRun;
diff --git a/include/utils/rive_utf.hpp b/include/utils/rive_utf.hpp
new file mode 100644
index 0000000..f4c6a5d
--- /dev/null
+++ b/include/utils/rive_utf.hpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2022 Rive
+ */
+
+#ifndef _RIVE_UTF_HPP_
+#define _RIVE_UTF_HPP_
+
+#include "rive/render_text.hpp"
+
+namespace rive {
+
+    class UTF {
+    public:
+        // returns the number of bytes needed in this sequence
+        // For ascii, this will return 1
+        static int CountUTF8Length(const uint8_t utf8[]);
+
+        // Return the unichar pointed to by the utf8 pointer, and then
+        // update the pointer to point to the next sequence.
+        static Unichar NextUTF8(const uint8_t** utf8Ptr);
+
+        // Convert the unichar into (1 or 2) utf16 values, and return
+        // the number of values.
+        static int ToUTF16(Unichar uni, uint16_t utf16[]);
+    };
+
+} // namespace rive
+
+#endif
diff --git a/skia/renderer/src/renderfont_coretext.cpp b/skia/renderer/src/renderfont_coretext.cpp
index 6417616..0ed00b3 100644
--- a/skia/renderer/src/renderfont_coretext.cpp
+++ b/skia/renderer/src/renderfont_coretext.cpp
@@ -1,7 +1,10 @@
 /*
  * Copyright 2022 Rive
  */
+
 #include "rive/rive_types.hpp"
+#include "utils/rive_utf.hpp"
+
 #if defined(RIVE_BUILD_FOR_APPLE) && defined(RIVE_TEXT)
 #include "renderfont_coretext.hpp"
 #include "mac_utils.hpp"
@@ -104,6 +107,24 @@
     return rive::rcp<rive::RenderFont>(new CoreTextRenderFont(font, compute_axes(font)));
 }
 
+static CTFontRef font_from_run(CTRunRef run) {
+    auto attr = CTRunGetAttributes(run);
+    assert(attr);
+    CTFontRef ct = (CTFontRef)CFDictionaryGetValue(attr, kCTFontAttributeName);
+    assert(ct);
+    return ct;
+}
+
+static rive::rcp<rive::RenderFont> convert_to_renderfont(CTFontRef ct,
+                                                         rive::rcp<rive::RenderFont> rf) {
+    auto ctrf = static_cast<CoreTextRenderFont*>(rf.get());
+    if (ctrf->m_font == ct) {
+        return rf;
+    }
+    CFRetain(ct);
+    return rive::rcp<rive::RenderFont>(new CoreTextRenderFont(ct, compute_axes(ct)));
+}
+
 static void apply_element(void* ctx, const CGPathElement* element) {
     auto path = (rive::RawPath*)ctx;
     const CGPoint* points = element->points;
@@ -152,11 +173,17 @@
 ////////////////////////////////////////////////////////////////////////////////////
 
 struct AutoUTF16 {
-    AutoSTArray<1024, uint16_t> array;
+    std::vector<uint16_t> array;
 
-    AutoUTF16(const rive::Unichar uni[], int count) : array(count) {
+    AutoUTF16(const rive::Unichar uni[], int count) {
+        array.reserve(count);
         for (int i = 0; i < count; ++i) {
-            array[i] = rive::castTo<uint16_t>(uni[i]);
+            uint16_t tmp[2];
+            int n = rive::UTF::ToUTF16(uni[i], tmp);
+
+            for (int i = 0; i < n; ++i) {
+                array.push_back(tmp[i]);
+            }
         }
     }
 };
@@ -170,8 +197,6 @@
         gr->xpos.resize(count + 1);
         gr->textOffsets.resize(count);
 
-        const auto txStart = textStart + CTRunGetStringRange(run).location;
-
         CTRunGetGlyphs(run, {0, count}, gr->glyphs.data());
 
         AutoSTArray<1024, CFIndex> indices(count);
@@ -182,7 +207,7 @@
 
         for (CFIndex i = 0; i < count; ++i) {
             gr->xpos[i] = startX;
-            gr->textOffsets[i] = txStart + indices[i];
+            gr->textOffsets[i] = textStart + indices[i]; // utf16 offsets, will fix-up later
             startX += advances[i].width * scale;
         }
         gr->xpos[count] = startX;
@@ -196,14 +221,17 @@
     std::vector<rive::RenderGlyphRun> gruns;
     gruns.reserve(truns.size());
 
-    uint32_t unicharIndex = 0;
+    uint32_t textIndex = 0;
     float startX = 0;
     for (const auto& tr : truns) {
         CTFontRef font = ((CoreTextRenderFont*)tr.font.get())->m_font;
 
-        AutoUTF16 utf16(&text[unicharIndex], tr.unicharCount);
+        AutoUTF16 utf16(&text[textIndex], tr.unicharCount);
+        const bool hasSurrogates = utf16.array.size() != tr.unicharCount;
+        assert(!hasSurrogates);
+
         AutoCF string = CFStringCreateWithCharactersNoCopy(
-            nullptr, utf16.array.data(), tr.unicharCount, kCFAllocatorNull);
+            nullptr, utf16.array.data(), utf16.array.size(), kCFAllocatorNull);
 
         AutoCF attr = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                                 0,
@@ -220,19 +248,17 @@
         CFArrayRef run_array = CTLineGetGlyphRuns(line.get());
         CFIndex runCount = CFArrayGetCount(run_array);
         for (CFIndex i = 0; i < runCount; ++i) {
+            CTRunRef runref = (CTRunRef)CFArrayGetValueAtIndex(run_array, i);
             rive::RenderGlyphRun grun;
-            startX = add_run(&grun,
-                             (CTRunRef)CFArrayGetValueAtIndex(run_array, i),
-                             unicharIndex,
-                             tr.size,
-                             startX);
+            startX = add_run(&grun, runref, textIndex, tr.size, startX);
             if (grun.glyphs.size() > 0) {
-                grun.font = tr.font;
+                auto ct = font_from_run(runref);
+                grun.font = convert_to_renderfont(ct, tr.font);
                 grun.size = tr.size;
                 gruns.push_back(std::move(grun));
             }
         }
-        unicharIndex += tr.unicharCount;
+        textIndex += tr.unicharCount;
     }
 
     return gruns;
diff --git a/utils/rive_utf.cpp b/utils/rive_utf.cpp
new file mode 100644
index 0000000..6be3dee
--- /dev/null
+++ b/utils/rive_utf.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2022 Rive
+ */
+
+#include "utils/rive_utf.hpp"
+#include "rive/core/type_conversions.hpp"
+
+using namespace rive;
+
+int UTF::CountUTF8Length(const uint8_t utf8[]) {
+    unsigned lead = *utf8;
+    assert(lead != 0xFF);
+    assert((lead & 0xC0) != 0x80); // 10xxxxxx is not a legal lead byte
+    if ((lead & 0x80) == 0) {
+        return 1;
+    }
+    int n = 1;
+    lead <<= 1;
+    while (lead & 0x80) {
+        n += 1;
+        lead <<= 1;
+    }
+    assert(n >= 1 && n <= 4);
+    return n;
+}
+
+// Return the unichar pointed to by the utf8 pointer, and then
+// update the pointer to point to the next sequence.
+Unichar UTF::NextUTF8(const uint8_t** utf8Ptr) {
+    const uint8_t* text = *utf8Ptr;
+
+    uint32_t c = 0;
+    int n = CountUTF8Length(text);
+    assert(n >= 1 && n <= 4);
+
+    unsigned first = *text++;
+    if (n == 1) {
+        c = first;
+    } else {
+        c = first & ((unsigned)0xFF >> n);
+        --n;
+        do {
+            c = (c << 6) | (*text++ & 0x3F);
+        } while (--n);
+    }
+    *utf8Ptr = text; // update the pointer
+    return c;
+}
+
+int UTF::ToUTF16(Unichar uni, uint16_t utf16[]) {
+    if (uni > 0xFFFF) {
+        utf16[0] = castTo<uint16_t>((0xD800 - 64) | (uni >> 10));
+        utf16[1] = castTo<uint16_t>(0xDC00 | (uni & 0x3FF));
+        return 2;
+    }
+    utf16[0] = castTo<uint16_t>(uni);
+    return 1;
+}
diff --git a/viewer/build/premake5_viewer.lua b/viewer/build/premake5_viewer.lua
index 75a0758..6dac5fe 100644
--- a/viewer/build/premake5_viewer.lua
+++ b/viewer/build/premake5_viewer.lua
@@ -45,6 +45,7 @@
 
     files {
         '../src/**.cpp',
+        '../../utils/rive_utf.cpp',
         dependencies .. '/imgui/imgui.cpp',
         dependencies .. '/imgui/imgui_widgets.cpp',
         dependencies .. '/imgui/imgui_tables.cpp',
diff --git a/viewer/src/viewer_content/text_content.cpp b/viewer/src/viewer_content/text_content.cpp
index 94c471d..3d42014 100644
--- a/viewer/src/viewer_content/text_content.cpp
+++ b/viewer/src/viewer_content/text_content.cpp
@@ -3,6 +3,8 @@
  */
 
 #include "viewer/viewer_content.hpp"
+#include "utils/rive_utf.hpp"
+
 #ifdef RIVE_RENDERER_SKIA
 #include "rive/factory.hpp"
 #include "rive/refcnt.hpp"
@@ -104,9 +106,10 @@
                                   rive::rcp<rive::RenderFont> font,
                                   float size,
                                   const char text[]) {
+    const uint8_t* ptr = (const uint8_t*)text;
     uint32_t n = 0;
-    while (text[n]) {
-        unichars->push_back(text[n]); // todo: utf8 -> unichar
+    while (*ptr) {
+        unichars->push_back(rive::UTF::NextUTF8(&ptr));
         n += 1;
     }
     return {std::move(font), size, n};
@@ -145,7 +148,7 @@
         RenderFontTextRuns truns;
 
         truns.push_back(append(&m_unichars, font0->makeAtCoord(c2), 60, "U"));
-        truns.push_back(append(&m_unichars, font0->makeAtCoord(c1), 30, "neasy"));
+        truns.push_back(append(&m_unichars, font0->makeAtCoord(c1), 30, "ne漢字asy"));
         truns.push_back(append(&m_unichars, font1, 30, " fits the crown"));
         truns.push_back(append(&m_unichars, font1->makeAtCoord(c1), 30, " that often"));
         truns.push_back(append(&m_unichars, font0, 30, " lies the head."));
diff --git a/viewer/src/viewer_content/textpath_content.cpp b/viewer/src/viewer_content/textpath_content.cpp
index 7206c28..f8b1bb4 100644
--- a/viewer/src/viewer_content/textpath_content.cpp
+++ b/viewer/src/viewer_content/textpath_content.cpp
@@ -3,6 +3,8 @@
  */
 
 #include "viewer/viewer_content.hpp"
+#include "utils/rive_utf.hpp"
+
 #ifdef RIVE_RENDERER_SKIA
 #include "rive/refcnt.hpp"
 #include "rive/render_text.hpp"
@@ -90,9 +92,10 @@
 
 static RenderTextRun
 append(std::vector<Unichar>* unichars, rcp<RenderFont> font, float size, const char text[]) {
+    const uint8_t* ptr = (const uint8_t*)text;
     uint32_t n = 0;
-    while (text[n]) {
-        unichars->push_back(text[n]); // todo: utf8 -> unichar
+    while (*ptr) {
+        unichars->push_back(rive::UTF::NextUTF8(&ptr));
         n += 1;
     }
     return {std::move(font), size, n};
@@ -143,7 +146,7 @@
         RenderFontTextRuns truns;
 
         truns.push_back(append(&m_unichars, font0->makeAtCoord(c2), 60, "U"));
-        truns.push_back(append(&m_unichars, font0->makeAtCoord(c1), 30, "neasy"));
+        truns.push_back(append(&m_unichars, font0->makeAtCoord(c1), 30, "ne漢字asy"));
         truns.push_back(append(&m_unichars, font1, 30, " fits the crown"));
         truns.push_back(append(&m_unichars, font1->makeAtCoord(c1), 30, " that often"));
         truns.push_back(append(&m_unichars, font0, 30, " lies the head."));