blob: 0bd12e378e48ba89cb55bd62910e24fda478c946 [file] [log] [blame]
/*
* Copyright 2025 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkString.h"
#include "modules/skunicode/include/SkUnicode.h"
#if defined(SK_UNICODE_BIDI_IMPLEMENTATION)
#include "modules/skunicode/include/SkUnicode_bidi.h"
#else
#error "SkUnicode bidi component is required but missing"
#endif
#include <string>
#include <vector>
#include <emscripten.h>
#include <emscripten/bind.h>
#include "modules/canvaskit/WasmCommon.h"
using namespace emscripten;
using namespace skia_private;
void JSArrayFromBidiRegions(JSArray& array, std::vector<SkUnicode::BidiRegion>& regions) {
for (auto region : regions) {
array.call<void>("push", region.start);
array.call<void>("push", region.end);
array.call<void>("push", (int32_t)region.level);
}
}
class BidiPlaceholder { };
class CodeUnitsPlaceholder { };
static sk_sp<SkUnicode> getBidiUnicode() {
static SkUnicode* unicode = SkUnicodes::Bidi::Make().release();
return sk_ref_sp(unicode);
}
EMSCRIPTEN_BINDINGS(Bidi) {
class_<BidiPlaceholder>("Bidi")
.class_function("_getBidiRegions",
optional_override([](JSString jtext, int dir) -> JSArray {
std::u16string textStorage = jtext.as<std::u16string>();
const char16_t* text = textStorage.data();
size_t textCount = textStorage.size();
JSArray result = emscripten::val::array();
std::vector<SkUnicode::BidiRegion> regions;
SkBidiIterator::Direction direction =
dir == 1 ? SkBidiIterator::Direction::kLTR
: SkBidiIterator::Direction::kRTL;
getBidiUnicode()->forEachBidiRegion((const uint16_t*)text, textCount, direction,
[&](uint16_t start, uint16_t end, SkBidiIterator::Level level) {
regions.emplace_back(start, end, level);
});
JSArrayFromBidiRegions(result, regions);
return result;
}),
allow_raw_pointers())
.class_function("_reorderVisual",
optional_override([](WASMPointerU8 runLevels,
int levelsCount) -> JSArray {
// Convert WASMPointerU8 to std::vector<SkUnicode::BidiLevel>
SkUnicode::BidiLevel* data = reinterpret_cast<SkUnicode::BidiLevel*>(runLevels);
// The resulting vector
std::vector<int32_t> logicalFromVisual;
logicalFromVisual.resize(levelsCount);
getBidiUnicode()->reorderVisual(data, levelsCount, logicalFromVisual.data());
// Convert std::vector<int32_t> to JSArray
JSArray result = emscripten::val::array();
for (auto logical : logicalFromVisual) {
result.call<void>("push", logical);
}
return result;
}),
allow_raw_pointers());
class_<CodeUnitsPlaceholder>("CodeUnits")
.class_function("_compute",
optional_override([](JSString jtext) -> JSArray {
std::u16string textStorage = jtext.as<std::u16string>();
char16_t * text = textStorage.data();
size_t textCount = textStorage.size();
skia_private::TArray<SkUnicode::CodeUnitFlags, true> flags;
flags.resize(textCount);
JSArray result = emscripten::val::array();
if (!getBidiUnicode()->computeCodeUnitFlags(
text, textCount, /*replaceTabs=*/false, &flags)) {
return result;
}
for (auto flag : flags) {
result.call<void>("push", (uint16_t)flag);
}
return result;
}),
allow_raw_pointers());
}