#include "hb-ot.h" #include "hb.h" #include "rive/text/renderfont_hb.hpp" #include "rive/text/line_breaker.hpp" #include #include #include #include #include using namespace emscripten; using WasmPtr = uint32_t; WasmPtr makeRenderFont(emscripten::val byteArray) { std::vector bytes; const auto l = byteArray["byteLength"].as(); bytes.resize(l); emscripten::val memoryView{emscripten::typed_memory_view(l, bytes.data())}; memoryView.call("set", byteArray); auto result = HBRenderFont::Decode(bytes); if (result) { return (WasmPtr)result.release(); } return (WasmPtr) nullptr; } void deleteRenderFont(WasmPtr renderFont) { reinterpret_cast(renderFont)->unref(); } struct GlyphPath { WasmPtr rawPath; WasmPtr points; WasmPtr verbs; uint16_t verbCount; }; GlyphPath makeGlyphPath(WasmPtr renderFontPtr, rive::GlyphID id) { auto renderFont = reinterpret_cast(renderFontPtr); rive::RawPath* path = new rive::RawPath(renderFont->getPath(id)); return { .rawPath = (WasmPtr)path, .points = (WasmPtr)path->points().data(), .verbs = (WasmPtr)path->verbs().data(), .verbCount = (uint16_t)path->verbs().size(), }; } void deleteGlyphPath(WasmPtr rawPath) { delete reinterpret_cast(rawPath); } void deleteShapeResult(WasmPtr shaperResult) { delete reinterpret_cast*>(shaperResult); } WasmPtr shapeText(emscripten::val codeUnits, emscripten::val runsList) { std::vector runsBytes(runsList["byteLength"].as()); { emscripten::val memoryView{ emscripten::typed_memory_view(runsBytes.size(), runsBytes.data())}; memoryView.call("set", runsList); } std::vector codeUnitArray(codeUnits["length"].as()); { emscripten::val memoryView{ emscripten::typed_memory_view(codeUnitArray.size(), codeUnitArray.data())}; memoryView.call("set", codeUnits); } auto runCount = runsBytes.size() / (4 + 4 + 4); rive::RenderTextRun* runs = reinterpret_cast(runsBytes.data()); if (runCount > 0) { return (WasmPtr) new rive::SimpleArray( runs[0].font->shapeText(codeUnitArray, rive::Span(runs, runCount))); } return (WasmPtr) nullptr; } struct LinesResult { WasmPtr result; WasmPtr lines; uint32_t lineCount; }; LinesResult breakLines(WasmPtr runsPtr, float width, uint8_t align) { auto runs = reinterpret_cast*>(runsPtr); auto result = new std::vector( rive::RenderGlyphLine::BreakLines(*runs, width, (rive::RenderTextAlign)align)); return {(WasmPtr)result, (WasmPtr)result->data(), (uint32_t)result->size()}; } void deleteBreakLinesResult(WasmPtr breakLinesResult) { delete reinterpret_cast*>(breakLinesResult); } EMSCRIPTEN_BINDINGS(RenderFont) { function("makeRenderFont", &makeRenderFont, allow_raw_pointers()); function("deleteRenderFont", &deleteRenderFont); value_array("GlyphPath") .element(&GlyphPath::rawPath) .element(&GlyphPath::points) .element(&GlyphPath::verbs) .element(&GlyphPath::verbCount); function("makeGlyphPath", &makeGlyphPath); function("deleteGlyphPath", &deleteGlyphPath); function("shapeText", &shapeText); function("deleteShapeResult", &deleteShapeResult); value_array("LinesResult") .element(&LinesResult::result) .element(&LinesResult::lines) .element(&LinesResult::lineCount); function("breakLines", &breakLines); function("deleteBreakLinesResult", &deleteBreakLinesResult); }