diff --git a/lib/src/renderfont_wasm.dart b/lib/src/renderfont_wasm.dart index 59037f2..3e4c6ae 100644 --- a/lib/src/renderfont_wasm.dart +++ b/lib/src/renderfont_wasm.dart @@ -14,6 +14,8 @@ late js.JsFunction _makeGlyphPath; late js.JsFunction _deleteGlyphPath; late js.JsFunction _shapeText; late js.JsFunction _deleteShapeResult; +late js.JsFunction _breakLines; +late js.JsFunction _deleteBreakLinesResult; class RawPathWasm extends RawPath { final int rawPathPtr; @@ -129,9 +131,47 @@ class RawPathIterator extends Iterator { } } +class TextLineWasm implements TextLine { + @override + final double baseline; + + @override + final double bottom; + + @override + final int endIndex; + + @override + final int endRun; + + @override + final int startIndex; + + @override + final int startRun; + + @override + final double startX; + + @override + final double top; + + TextLineWasm({ + required this.baseline, + required this.bottom, + required this.endIndex, + required this.endRun, + required this.startIndex, + required this.startRun, + required this.startX, + required this.top, + }); +} + class TextShapeResultWasm extends TextShapeResult { final int rawPathResultsPtr; final List runs; + final List lines = []; TextShapeResultWasm(this.rawPathResultsPtr, this.runs); @override @@ -142,6 +182,45 @@ class TextShapeResultWasm extends TextShapeResult { @override int get runCount => runs.length; + + @override + void breakLines(double width, TextAlign alignment) { + var result = _breakLines.apply( + [ + rawPathResultsPtr, + width, + alignment.index, + ], + ) as js.JsObject; + + var rawResult = result['rawResult'] as int; + var linesBuffer = result['lines'] as Uint8List; + var lineCount = result['lineCount'] as int; + lines.clear(); + + var reader = BinaryReader.fromList(linesBuffer); + for (int i = 0; i < lineCount; i++) { + lines.add( + TextLineWasm( + startRun: reader.readUint32(), + startIndex: reader.readUint32(), + endRun: reader.readUint32(), + endIndex: reader.readUint32(), + startX: reader.readFloat32(), + top: reader.readFloat32(), + baseline: reader.readFloat32(), + bottom: reader.readFloat32(), + ), + ); + } + _deleteBreakLinesResult.apply([rawResult]); + } + + @override + TextLine lineAt(int index) => lines[index]; + + @override + int get lineCount => lines.length; } extension ByteDataWasm on ByteData { @@ -233,8 +312,6 @@ class RenderFontWasm extends RenderFont { writer.writeFloat32(run.fontSize); writer.writeUint32(run.unicharCount); } - print( - "SIZE OF UNITS: ${Uint32List.fromList(text.codeUnits).length} ${text.codeUnits.length}"); var result = _shapeText.apply( [ @@ -301,6 +378,9 @@ Future initRenderFont() async { _deleteGlyphPath = module['deleteGlyphPath'] as js.JsFunction; _shapeText = module['shapeText'] as js.JsFunction; _deleteShapeResult = module['deleteShapeResult'] as js.JsFunction; + _breakLines = module['breakLines'] as js.JsFunction; + _deleteBreakLinesResult = + module['deleteBreakLinesResult'] as js.JsFunction; completer.complete(); } ], diff --git a/wasm/js/render_font.js b/wasm/js/render_font.js index 9dc0478..e6bb163 100644 --- a/wasm/js/render_font.js +++ b/wasm/js/render_font.js @@ -49,4 +49,14 @@ RenderFont["onRuntimeInitialized"] = function () { "results": HEAPU8["subarray"](shapeResult), }; }; + + var nativeBreakLines = RenderFont["breakLines"]; + RenderFont["breakLines"] = function (runs, width, align) { + var breakResult = nativeBreakLines(runs, width, align); + return { + "rawResult": breakResult[0], + "lines": HEAPU8["subarray"](breakResult[1]), + "lineCount": breakResult[2], + }; + }; }; diff --git a/wasm/premake5_wasm.lua b/wasm/premake5_wasm.lua index d0fe554..4fc15d8 100644 --- a/wasm/premake5_wasm.lua +++ b/wasm/premake5_wasm.lua @@ -29,6 +29,7 @@ files { source .. 'rive-cpp/src/renderer.cpp', source .. 'rive-cpp/src/math/raw_path.cpp', source .. 'rive-cpp/src/text/renderfont_hb.cpp', + source .. 'rive-cpp/src/text/line_breaker.cpp', source .. 'harfbuzz/src/hb-aat-layout.cc', source .. 'harfbuzz/src/hb-aat-map.cc', source .. 'harfbuzz/src/hb-blob.cc', diff --git a/wasm/renderfont_bindings.cpp b/wasm/renderfont_bindings.cpp index faf2dba..2953405 100644 --- a/wasm/renderfont_bindings.cpp +++ b/wasm/renderfont_bindings.cpp @@ -1,6 +1,7 @@ #include "hb-ot.h" #include "hb.h" #include "rive/text/renderfont_hb.hpp" +#include "rive/text/line_breaker.hpp" #include #include @@ -78,6 +79,23 @@ WasmPtr shapeText(emscripten::val codeUnits, emscripten::val runsList) { 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); @@ -93,4 +111,11 @@ EMSCRIPTEN_BINDINGS(RenderFont) { function("shapeText", &shapeText); function("deleteShapeResult", &deleteShapeResult); + + value_array("LinesResult") + .element(&LinesResult::result) + .element(&LinesResult::lines) + .element(&LinesResult::lineCount); + function("breakLines", &breakLines); + function("deleteBreakLinesResult", &deleteBreakLinesResult); } \ No newline at end of file