Implement wasm abstraction for line breaker.

This commit is contained in:
Luigi Rosso
2022-09-22 21:13:53 -07:00
parent 21af101216
commit 3d7f6d7f99
4 changed files with 118 additions and 2 deletions

View File

@ -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<RawPathCommand> {
}
}
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<RenderGlyphRun> runs;
final List<TextLineWasm> 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(
<dynamic>[
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(<dynamic>[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(
<dynamic>[
@ -301,6 +378,9 @@ Future<void> 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();
}
],

View File

@ -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],
};
};
};

View File

@ -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',

View File

@ -1,6 +1,7 @@
#include "hb-ot.h"
#include "hb.h"
#include "rive/text/renderfont_hb.hpp"
#include "rive/text/line_breaker.hpp"
#include <emscripten.h>
#include <emscripten/bind.h>
@ -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<rive::SimpleArray<rive::RenderGlyphRun>*>(runsPtr);
auto result = new std::vector<rive::RenderGlyphLine>(
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<std::vector<rive::RenderGlyphLine>*>(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>("LinesResult")
.element(&LinesResult::result)
.element(&LinesResult::lines)
.element(&LinesResult::lineCount);
function("breakLines", &breakLines);
function("deleteBreakLinesResult", &deleteBreakLinesResult);
}