libui/common/opentype.c

165 lines
3.5 KiB
C

// 25 february 2018
#include "../ui.h"
#include "uipriv.h"
#include "attrstr.h"
struct feature {
char a;
char b;
char c;
char d;
uint32_t value;
};
struct uiOpenTypeFeatures {
struct feature *data;
size_t len;
size_t cap;
};
#define bytecount(n) ((n) * sizeof (struct feature))
uiOpenTypeFeatures *uiNewOpenTypeFeatures(void)
{
uiOpenTypeFeatures *otf;
otf = uiprivNew(uiOpenTypeFeatures);
otf->cap = 16;
otf->data = (struct feature *) uiprivAlloc(bytecount(otf->cap), "struct feature[]");
otf->len = 0;
return otf;
}
void uiFreeOpenTypeFeatures(uiOpenTypeFeatures *otf)
{
uiprivFree(otf->data);
uiprivFree(otf);
}
uiOpenTypeFeatures *uiOpenTypeFeaturesClone(const uiOpenTypeFeatures *otf)
{
uiOpenTypeFeatures *ret;
ret = uiprivNew(uiOpenTypeFeatures);
ret->len = otf->len;
ret->cap = otf->cap;
ret->data = (struct feature *) uiprivAlloc(bytecount(ret->cap), "struct feature[]");
memset(ret->data, 0, bytecount(ret->cap));
memmove(ret->data, otf->data, bytecount(ret->len));
return ret;
}
#define intdiff(a, b) (((int) (a)) - ((int) (b)))
static int featurecmp(const void *a, const void *b)
{
const struct feature *f = (const struct feature *) a;
const struct feature *g = (const struct feature *) b;
if (f->a != g->a)
return intdiff(f->a, g->a);
if (f->b != g->b)
return intdiff(f->b, g->b);
if (f->c != g->c)
return intdiff(f->c, g->c);
return intdiff(f->d, g->d);
}
static struct feature mkkey(char a, char b, char c, char d)
{
struct feature f;
f.a = a;
f.b = b;
f.c = c;
f.d = d;
return f;
}
#define find(pkey, otf) bsearch(pkey, otf->data, otf->len, sizeof (struct feature), featurecmp)
void uiOpenTypeFeaturesAdd(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value)
{
struct feature *f;
struct feature key;
// replace existing value if any
key = mkkey(a, b, c, d);
f = (struct feature *) find(&key, otf);
if (f != NULL) {
f->value = value;
return;
}
// if we got here, the tag is new
if (otf->len == otf->cap) {
otf->cap *= 2;
otf->data = (struct feature *) uiprivRealloc(otf->data, bytecount(otf->cap), "struct feature[]");
}
f = otf->data + otf->len;
f->a = a;
f->b = b;
f->c = c;
f->d = d;
f->value = value;
// LONGTERM qsort here is overkill
otf->len++;
qsort(otf->data, otf->len, sizeof (struct feature), featurecmp);
}
void uiOpenTypeFeaturesRemove(uiOpenTypeFeatures *otf, char a, char b, char c, char d)
{
struct feature *f;
struct feature key;
ptrdiff_t index;
size_t count;
key = mkkey(a, b, c, d);
f = (struct feature *) find(&key, otf);
if (f == NULL)
return;
index = f - otf->data;
count = otf->len - index - 1;
memmove(f + 1, f, bytecount(count));
otf->len--;
}
int uiOpenTypeFeaturesGet(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t *value)
{
const struct feature *f;
struct feature key;
key = mkkey(a, b, c, d);
f = (const struct feature *) find(&key, otf);
if (f == NULL)
return 0;
*value = f->value;
return 1;
}
void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data)
{
size_t n;
const struct feature *p;
uiForEach ret;
p = otf->data;
for (n = 0; n < otf->len; n++) {
ret = (*f)(otf, p->a, p->b, p->c, p->d, p->value, data);
// TODO for all: require exact match?
if (ret == uiForEachStop)
return;
p++;
}
}
int uiprivOpenTypeFeaturesEqual(const uiOpenTypeFeatures *a, const uiOpenTypeFeatures *b)
{
if (a == b)
return 1;
if (a->len != b->len)
return 0;
return memcmp(a->data, b->data, bytecount(a->len)) == 0;
}