[wasm-graphite] Initial code
This commit is contained in:
parent
ae981eec8e
commit
07ece17495
|
@ -44,8 +44,8 @@ face_reference_table (HB_WASM_EXEC_ENV_COMPOUND
|
||||||
unsigned length;
|
unsigned length;
|
||||||
const char *data = hb_blob_get_data (blob, &length);
|
const char *data = hb_blob_get_data (blob, &length);
|
||||||
|
|
||||||
ret.data = wasm_runtime_module_dup_data (module_inst, data, length);
|
|
||||||
ret.length = length;
|
ret.length = length;
|
||||||
|
ret.data = wasm_runtime_module_dup_data (module_inst, data, length);
|
||||||
|
|
||||||
hb_blob_destroy (blob);
|
hb_blob_destroy (blob);
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ _hb_wasm_shape (hb_shape_plan_t *shape_plan,
|
||||||
{
|
{
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
const hb_wasm_face_data_t *face_data = font->face->data.wasm;
|
const hb_wasm_face_data_t *face_data = font->face->data.wasm;
|
||||||
constexpr uint32_t stack_size = 8092, heap_size = 8092;
|
constexpr uint32_t stack_size = 8092, heap_size = 2 * 1024 * 1024;
|
||||||
|
|
||||||
wasm_module_inst_t module_inst = nullptr;
|
wasm_module_inst_t module_inst = nullptr;
|
||||||
wasm_exec_env_t exec_env = nullptr;
|
wasm_exec_env_t exec_env = nullptr;
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
all: test.wasm.ttf
|
||||||
|
|
||||||
|
%.wasm: %.cc ../hb-wasm-api.h
|
||||||
|
emcc \
|
||||||
|
-I .. \
|
||||||
|
-I ~/graphite/include/ \
|
||||||
|
-fvisibility=hidden \
|
||||||
|
-Wl,--allow-undefined \
|
||||||
|
-Wl,--no-entry \
|
||||||
|
-sERROR_ON_UNDEFINED_SYMBOLS=0 \
|
||||||
|
~/graphite/src/libgraphite2.a \
|
||||||
|
~/wasm/wasi-sdk-19.0/share/wasi-sysroot/lib/wasm32-wasi/libc.a \
|
||||||
|
$< \
|
||||||
|
-o $@
|
||||||
|
|
||||||
|
%.wasm.ttf: %.ttf shape.wasm addTable.py
|
||||||
|
python addTable.py $< $@ shape.wasm
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) test.wasm.ttf shape.wasm
|
||||||
|
|
||||||
|
.PRECIOUS: shape.wasm
|
|
@ -0,0 +1,16 @@
|
||||||
|
import sys
|
||||||
|
from fontTools.ttLib import TTFont
|
||||||
|
from fontTools.ttLib.tables.DefaultTable import DefaultTable
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
print("usage: python addTable.py input.ttf output.ttf Wasm.bin")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
font = TTFont(sys.argv[1])
|
||||||
|
|
||||||
|
wasm_table = DefaultTable("Wasm")
|
||||||
|
wasm_table.data = open(sys.argv[3], "rb").read()
|
||||||
|
|
||||||
|
font["Wasm"] = wasm_table
|
||||||
|
|
||||||
|
font.save(sys.argv[2])
|
|
@ -0,0 +1,210 @@
|
||||||
|
#define HB_WASM_INTERFACE(ret_t, name) __attribute__((export_name(#name))) ret_t name
|
||||||
|
|
||||||
|
#include <hb-wasm-api.h>
|
||||||
|
|
||||||
|
#include <graphite2/Segment.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void *malloc(size_t size);
|
||||||
|
void *realloc(void *ptr, size_t size);
|
||||||
|
void free(void *ptr);
|
||||||
|
void abort();
|
||||||
|
void *memset(void *s, int c, size_t n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugprint1 (char *s, int32_t);
|
||||||
|
void debugprint2 (char *s, int32_t, int32_t);
|
||||||
|
|
||||||
|
static const void *copy_table (const void *data, unsigned int tag, size_t *len)
|
||||||
|
{
|
||||||
|
face_t *face = (face_t *) data;
|
||||||
|
blob_t blob = face_reference_table (face, tag);
|
||||||
|
|
||||||
|
*len = blob.length;
|
||||||
|
return blob.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_table (const void *data, const void *table_data)
|
||||||
|
{
|
||||||
|
free ((void *) table_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t
|
||||||
|
shape (font_t *font, buffer_t *buffer)
|
||||||
|
{
|
||||||
|
face_t *face = font_get_face (font);
|
||||||
|
|
||||||
|
blob_t blob = face_reference_table (face, TAG ('c','m','a','p'));
|
||||||
|
|
||||||
|
blob_free (&blob);
|
||||||
|
|
||||||
|
buffer_contents_t contents = buffer_copy_contents (buffer);
|
||||||
|
|
||||||
|
const gr_face_ops ops = {sizeof (gr_face_ops), ©_table, nullptr};//&free_table};
|
||||||
|
gr_face *grface = gr_make_face_with_ops (face, &ops, gr_face_preloadAll);
|
||||||
|
|
||||||
|
gr_segment *seg = nullptr;
|
||||||
|
const gr_slot *is;
|
||||||
|
unsigned int ci = 0, ic = 0;
|
||||||
|
unsigned int curradvx = 0, curradvy = 0;
|
||||||
|
unsigned length = contents.length;
|
||||||
|
|
||||||
|
uint32_t *chars = (uint32_t *) malloc (length * sizeof (uint32_t));
|
||||||
|
for (unsigned int i = 0; i < contents.length; ++i)
|
||||||
|
chars[i] = contents.info[i].codepoint;
|
||||||
|
|
||||||
|
/* TODO ensure_native_direction. */
|
||||||
|
|
||||||
|
seg = gr_make_seg (nullptr, grface,
|
||||||
|
0, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148
|
||||||
|
nullptr,
|
||||||
|
gr_utf32, chars, contents.length,
|
||||||
|
2/* | (buffer_get_direction (buffer) == DIRECTION_RTL ? 1 : 0)*/);
|
||||||
|
|
||||||
|
free (chars);
|
||||||
|
|
||||||
|
if (!seg)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned int glyph_count = gr_seg_n_slots (seg);
|
||||||
|
|
||||||
|
struct cluster_t {
|
||||||
|
unsigned int base_char;
|
||||||
|
unsigned int num_chars;
|
||||||
|
unsigned int base_glyph;
|
||||||
|
unsigned int num_glyphs;
|
||||||
|
unsigned int cluster;
|
||||||
|
int advance;
|
||||||
|
};
|
||||||
|
|
||||||
|
length = glyph_count;
|
||||||
|
//contents.info = (glyph_info_t *) realloc (contents.info, length * sizeof (glyph_info_t));
|
||||||
|
//contents.pos = (glyph_position_t *) realloc (contents.pos, length * sizeof (glyph_position_t));
|
||||||
|
cluster_t *clusters = (cluster_t *) malloc (length * sizeof (cluster_t));
|
||||||
|
uint32_t *gids = (uint32_t *) malloc (length * sizeof (uint32_t));
|
||||||
|
|
||||||
|
memset (clusters, 0, sizeof (clusters[0]) * length);
|
||||||
|
hb_codepoint_t *pg = gids;
|
||||||
|
clusters[0].cluster = contents.info[0].cluster;
|
||||||
|
unsigned int upem = 2048;//hb_face_get_upem (face);
|
||||||
|
float xscale = 10;//(float) font->x_scale / upem;
|
||||||
|
float yscale = 10;//(float) font->y_scale / upem;
|
||||||
|
yscale *= yscale / xscale;
|
||||||
|
unsigned int curradv = 0;
|
||||||
|
if (0)//HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||||
|
{
|
||||||
|
curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
|
||||||
|
clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
clusters[0].advance = 0;
|
||||||
|
for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
|
||||||
|
{
|
||||||
|
unsigned int before = gr_slot_before (is);
|
||||||
|
unsigned int after = gr_slot_after (is);
|
||||||
|
*pg = gr_slot_gid (is);
|
||||||
|
pg++;
|
||||||
|
while (clusters[ci].base_char > before && ci)
|
||||||
|
{
|
||||||
|
clusters[ci-1].num_chars += clusters[ci].num_chars;
|
||||||
|
clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
|
||||||
|
clusters[ci-1].advance += clusters[ci].advance;
|
||||||
|
ci--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
|
||||||
|
{
|
||||||
|
cluster_t *c = clusters + ci + 1;
|
||||||
|
c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
|
||||||
|
c->cluster = contents.info[c->base_char].cluster;
|
||||||
|
c->num_chars = before - c->base_char;
|
||||||
|
c->base_glyph = ic;
|
||||||
|
c->num_glyphs = 0;
|
||||||
|
if (0)//HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||||
|
{
|
||||||
|
c->advance = curradv - gr_slot_origin_X(is) * xscale;
|
||||||
|
curradv -= c->advance;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c->advance = 0;
|
||||||
|
clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv;
|
||||||
|
curradv += clusters[ci].advance;
|
||||||
|
}
|
||||||
|
ci++;
|
||||||
|
}
|
||||||
|
clusters[ci].num_glyphs++;
|
||||||
|
|
||||||
|
if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
|
||||||
|
clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0)//HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||||
|
clusters[ci].advance += curradv;
|
||||||
|
else
|
||||||
|
clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
|
||||||
|
ci++;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < ci; ++i)
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
|
||||||
|
{
|
||||||
|
glyph_info_t *info = &contents.info[clusters[i].base_glyph + j];
|
||||||
|
info->codepoint = gids[clusters[i].base_glyph + j];
|
||||||
|
info->cluster = clusters[i].cluster;
|
||||||
|
info->var1 = clusters[i].advance; // all glyphs in the cluster get the same advance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contents.length = glyph_count;
|
||||||
|
|
||||||
|
/* Positioning. */
|
||||||
|
unsigned int currclus = 0xFFFFFFFF;
|
||||||
|
const glyph_info_t *info = contents.info;
|
||||||
|
glyph_position_t *pPos = contents.pos;
|
||||||
|
if (1)//!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||||
|
{
|
||||||
|
curradvx = 0;
|
||||||
|
for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
|
||||||
|
{
|
||||||
|
pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
|
||||||
|
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
|
||||||
|
if (info->cluster != currclus) {
|
||||||
|
pPos->x_advance = info->var1;
|
||||||
|
curradvx += pPos->x_advance;
|
||||||
|
currclus = info->cluster;
|
||||||
|
} else
|
||||||
|
pPos->x_advance = 0.;
|
||||||
|
|
||||||
|
pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
|
||||||
|
curradvy += pPos->y_advance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curradvx = gr_seg_advance_X(seg) * xscale;
|
||||||
|
for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
|
||||||
|
{
|
||||||
|
if (info->cluster != currclus)
|
||||||
|
{
|
||||||
|
pPos->x_advance = info->var1;
|
||||||
|
curradvx -= pPos->x_advance;
|
||||||
|
currclus = info->cluster;
|
||||||
|
} else
|
||||||
|
pPos->x_advance = 0.;
|
||||||
|
|
||||||
|
pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
|
||||||
|
curradvy -= pPos->y_advance;
|
||||||
|
pPos->x_offset = gr_slot_origin_X (is) * xscale - info->var1 - curradvx + pPos->x_advance;
|
||||||
|
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
|
||||||
|
}
|
||||||
|
//hb_buffer_reverse_clusters (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
gr_seg_destroy (seg);
|
||||||
|
|
||||||
|
buffer_set_contents (buffer, &contents);
|
||||||
|
|
||||||
|
bool ret = glyph_count;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
Loading…
Reference in New Issue