1733 lines
32 KiB
C
1733 lines
32 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <ttf.h>
|
|
#include "impl.h"
|
|
|
|
typedef struct Hint Hint;
|
|
|
|
enum { debug = 0 };
|
|
|
|
#pragma varargck type "π" TTPoint
|
|
|
|
#define dprint(...) {if(debug) fprint(2, __VA_ARGS__);}
|
|
|
|
static TTGState defstate = {
|
|
.fvx = 16384,
|
|
.fvy = 0,
|
|
.pvx = 16384,
|
|
.pvy = 0,
|
|
.dpvx = 16384,
|
|
.dpvy = 0,
|
|
.instctrl = 0,
|
|
.scanctrl = 0,
|
|
.rperiod = 64,
|
|
.rphase = 0,
|
|
.rthold = 32,
|
|
.zp = 7,
|
|
.cvci = 68,
|
|
.loop = 1,
|
|
.singlewval = 0,
|
|
.singlewci = 0,
|
|
.deltabase = 9,
|
|
.deltashift = 3,
|
|
.autoflip = 1,
|
|
.mindist = 64,
|
|
};
|
|
|
|
struct Hint {
|
|
TTFont *f;
|
|
TTGlyph *g;
|
|
u8int *shint, *ip, *ehint;
|
|
u32int *stack;
|
|
int sp, nstack;
|
|
int level;
|
|
char err[ERRMAX];
|
|
jmp_buf jmp;
|
|
};
|
|
|
|
int
|
|
rounddiv(int a, int b)
|
|
{
|
|
if(b < 0){ a = -a; b = -b; }
|
|
if(a > 0)
|
|
return (a + b/2) / b;
|
|
else
|
|
return (a - b/2) / b;
|
|
}
|
|
|
|
int
|
|
vrounddiv(vlong a, int b)
|
|
{
|
|
if(b < 0){ a = -a; b = -b; }
|
|
if(a > 0)
|
|
return (a + b/2) / b;
|
|
else
|
|
return (a - b/2) / b;
|
|
}
|
|
|
|
static void
|
|
herror(Hint *h, char *fmt, ...)
|
|
{
|
|
va_list va;
|
|
|
|
va_start(va, fmt);
|
|
vsnprint(h->err, sizeof(h->err), fmt, va);
|
|
va_end(va);
|
|
dprint("error: %s\n", h->err);
|
|
longjmp(h->jmp, 1);
|
|
}
|
|
|
|
static void
|
|
push(Hint *h, u32int w)
|
|
{
|
|
assert(h->sp < h->nstack);
|
|
h->stack[h->sp++] = w;
|
|
}
|
|
|
|
static u32int
|
|
pop(Hint *h)
|
|
{
|
|
assert(h->sp > 0);
|
|
return h->stack[--h->sp];
|
|
}
|
|
|
|
static u8int
|
|
fetch8(Hint *h)
|
|
{
|
|
if(h->ip == h->ehint)
|
|
herror(h, "missing byte");
|
|
return *h->ip++;
|
|
}
|
|
|
|
enum {
|
|
RP0 = 0x10,
|
|
RP1 = 0x20,
|
|
RP2 = 0x30,
|
|
ZP0 = 0,
|
|
ZP1 = 0x100,
|
|
ZP2 = 0x200,
|
|
ORIG = 0x1000,
|
|
NOTOUCH = 0x2000,
|
|
};
|
|
|
|
static TTPoint
|
|
getpoint(Hint *h, int n, int pi)
|
|
{
|
|
if((n & RP2) != 0)
|
|
pi = h->f->rp[(n >> 4 & 3) - 1];
|
|
if((h->f->zp >> (n >> 8 & 3) & 1) != 0){
|
|
if(h->g == nil)
|
|
herror(h, "access to glyph zone from FPGM/CVT");
|
|
if((uint)pi >= h->g->npt)
|
|
herror(h, "glyph zone point index %d out of range", pi);
|
|
dprint("G%s%d: %+π\n", n&ORIG?"O":"", pi, (n & ORIG) != 0 ? h->g->ptorg[pi] : h->g->pt[pi]);
|
|
return (n & ORIG) != 0 ? h->g->ptorg[pi] : h->g->pt[pi];
|
|
}else{
|
|
if((uint)pi >= h->f->u->maxTwilightPoints)
|
|
herror(h, "twilight zone point index %d out of range", pi);
|
|
return (n & ORIG) != 0 ? h->f->twiorg[pi] : h->f->twilight[pi];
|
|
}
|
|
}
|
|
|
|
static void
|
|
setpoint(Hint *h, int n, int pi, TTPoint p)
|
|
{
|
|
if((n & RP2) != 0)
|
|
pi = h->f->rp[(n >> 4 & 3) - 1];
|
|
if((n & NOTOUCH) == 0){
|
|
if(h->f->fvx != 0) p.flags |= 2;
|
|
if(h->f->fvy != 0) p.flags |= 4;
|
|
}
|
|
if((h->f->zp >> (n >> 8 & 3) & 1) != 0){
|
|
if(h->g == nil)
|
|
herror(h, "access to glyph zone from FPGM/CVT");
|
|
if((uint)pi >= h->g->npt)
|
|
herror(h, "glyph zone point index %d out of range", pi);
|
|
dprint("G%d: %+π -> %+π\n", pi, h->g->pt[pi], p);
|
|
h->g->pt[pi] = p;
|
|
}else{
|
|
if((uint)pi >= h->f->u->maxTwilightPoints)
|
|
herror(h, "twilight zone point index %d out of range", pi);
|
|
dprint("T%d: %+π -> %+π\n", pi, h->f->twilight[pi], p);
|
|
h->f->twilight[pi] = p;
|
|
}
|
|
}
|
|
|
|
static TTPoint
|
|
getpointz(Hint *h, int z, int pi)
|
|
{
|
|
if((z & 1) != 0){
|
|
if(h->g == nil)
|
|
herror(h, "access to glyph zone from FPGM/CVT");
|
|
if((uint)pi >= h->g->npt)
|
|
herror(h, "glyph zone point index %d out of range", pi);
|
|
dprint("G%s%d: %+π\n", z&ORIG?"O":"", pi, (z & ORIG) != 0 ? h->g->ptorg[pi] : h->g->pt[pi]);
|
|
return (z & ORIG) != 0 ? h->g->ptorg[pi] : h->g->pt[pi];
|
|
}else{
|
|
if((uint)pi >= h->f->u->maxTwilightPoints)
|
|
herror(h, "twilight zone point index %d out of range", pi);
|
|
return (z & ORIG) != 0 ? h->f->twiorg[pi] : h->f->twilight[pi];
|
|
}
|
|
}
|
|
|
|
static void
|
|
setpointz(Hint *h, int z, int pi, TTPoint p)
|
|
{
|
|
if((z & 1) != 0){
|
|
if(h->g == nil)
|
|
herror(h, "access to glyph zone from FPGM/CVT");
|
|
if((uint)pi >= h->g->npt)
|
|
herror(h, "glyph zone point index %d out of range", pi);
|
|
dprint("G%d: %+π -> %+π\n", pi, h->g->pt[pi], p);
|
|
h->g->pt[pi] = p;
|
|
}else{
|
|
if((uint)pi >= h->f->u->maxTwilightPoints)
|
|
herror(h, "twilight zone point index %d out of range", pi);
|
|
dprint("T%d: %+π -> %+π\n", pi, h->f->twilight[pi], p);
|
|
h->f->twilight[pi] = p;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
debugprint(Hint *h, int skip)
|
|
{
|
|
Fmt f;
|
|
char buf[256];
|
|
|
|
static char *opcnames[256] = {
|
|
[0x00] "SVTCA", "SVTCA", "SPVTCA", "SPVTCA", "SFVTCA", "SFVTCA", "SPVTL", "SPVTL",
|
|
[0x08] "SFVTL", "SFVTL", "SPVFS", "SFVFS", "GPV", "GFV", "SFVTPV", "ISECT",
|
|
[0x10] "SRP0", "SRP1", "SRP2", "SZP0", "SZP1", "SZP2", "SZPS", "SLOOP",
|
|
[0x18] "RTG", "RTHG", "SMD", "ELSE", "JMPR", "SCVTCI", "SSWCI", "SSW",
|
|
[0x20] "DUP", "POP", "CLEAR", "SWAP", "DEPTH", "CINDEX", "MINDEX", "ALIGNPTS",
|
|
[0x28] nil, "UTP", "LOOPCALL", "CALL", "FDEF", "ENDF", "MDAP", "MDAP",
|
|
[0x30] "IUP", "IUP", "SHP", "SHP", "SHC", "SHC", "SHZ", "SHZ",
|
|
[0x38] "SHPIX", "IP", "MSIRP", "MSIRP", "ALIGNRP", "RTDG", "MIAP", "MIAP",
|
|
[0x40] "NPUSHB", "NPUSHW", "WS", "RS", "WCVTP", "RCVT", "GC", "GC",
|
|
[0x48] "SCFS", "MD", "MD", "MPPEM", "MPS", "FLIPON", "FLIPOFF", "DEBUG",
|
|
[0x50] "LT", "LTEQ", "GT", "GTEQ", "EQ", "NEQ", "ODD", "EVEN",
|
|
[0x58] "IF", "EIF", "AND", "OR", "NOT", "DELTAP1", "SDB", "SDS",
|
|
[0x60] "ADD", "SUB", "DIV", "MUL", "ABS", "NEG", "FLOOR", "CEILING",
|
|
[0x68] "ROUND", "ROUND", "ROUND", "ROUND", "NROUND", "NROUND", "NROUND", "NROUND",
|
|
[0x70] "WCVTF", "DELTAP2", "DELTAP3", "DELTAC1", "DELTAC2", "DELTAC3", "SROUND", "S45ROUND",
|
|
[0x78] "JROT", "JROF", "ROFF", nil, "RUTG", "RDTG", "SANGW", "AA",
|
|
[0x80] "FLIPPT", "FLIPRGON", "FLIPRGOFF", [0x85] "SCANCTRL", "SDPVTL", "SDPVTL",
|
|
[0x88] "GETINFO", "IDEF", "ROLL", "MAX", "MIN", "SCANTYPE", "INSTCTRL", nil,
|
|
[0xB0] "PUSHB", "PUSHB", "PUSHB", "PUSHB", "PUSHB", "PUSHB", "PUSHB", "PUSHB",
|
|
[0xB8] "PUSHW", "PUSHW", "PUSHW", "PUSHW", "PUSHW", "PUSHW", "PUSHW", "PUSHW",
|
|
};
|
|
static u8int argb[256] = {
|
|
[0x00] 1, 1, 1, 1, 1, 1, 1, 1,
|
|
[0x08] 1, 1, 1, 1, 1, 1,
|
|
[0x2e] 1, 1,
|
|
[0x30] 1, 1, 1, 1, 1, 1, 1, 1,
|
|
[0x38] 0, 0, 1, 1, 0, 0, 1, 1,
|
|
[0x46] 1, 1, 0, 1, 1,
|
|
[0x68] 2, 2, 2, 2, 2, 2, 2, 2,
|
|
};
|
|
u8int op;
|
|
int i;
|
|
|
|
fmtfdinit(&f, 2, buf, sizeof(buf));
|
|
op = *h->ip;
|
|
if(skip) fmtprint(&f, "** ");
|
|
fmtprint(&f, "%d %d ", h->level, (int)(h->ip - h->shint));
|
|
if(op >= 0xc0)
|
|
fmtprint(&f, "%s[%d]", op >= 0xe0 ? "MIRP" : "MDRP", op & 0x1f);
|
|
else if(opcnames[op] == nil)
|
|
fmtprint(&f, "???");
|
|
else
|
|
fmtprint(&f, argb[op] != 0 ? "%s[%d]" : "%s[]", opcnames[op], op & (1<<argb[op]) - 1);
|
|
if(!skip){
|
|
fmtprint(&f, " :: ");
|
|
for(i = 0; i < 8 && i < h->sp; i++)
|
|
fmtprint(&f, "%d ", h->stack[h->sp - 1 - i]);
|
|
}
|
|
fmtprint(&f, "\n");
|
|
fmtfdflush(&f);
|
|
}
|
|
|
|
static void
|
|
h_npushb(Hint *h)
|
|
{
|
|
u8int n, b;
|
|
|
|
n = fetch8(h);
|
|
while(n-- > 0){
|
|
b = fetch8(h);
|
|
push(h, b);
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_npushw(Hint *h)
|
|
{
|
|
u8int n;
|
|
u32int x;
|
|
|
|
n = fetch8(h);
|
|
while(n-- > 0){
|
|
x = fetch8(h) << 8;
|
|
x |= fetch8(h);
|
|
push(h, (short)x);
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_pushb(Hint *h)
|
|
{
|
|
int n;
|
|
u8int b;
|
|
|
|
n = (h->ip[-1] & 7) + 1;
|
|
while(n-- > 0){
|
|
b = fetch8(h);
|
|
push(h, b);
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_pushw(Hint *h)
|
|
{
|
|
int n;
|
|
u16int w;
|
|
|
|
n = (h->ip[-1] & 7) + 1;
|
|
while(n-- > 0){
|
|
w = fetch8(h) << 8;
|
|
w |= fetch8(h);
|
|
push(h, (short)w);
|
|
}
|
|
}
|
|
|
|
static void
|
|
skip(Hint *h, int mode)
|
|
{
|
|
int level;
|
|
|
|
level = 0;
|
|
for(;;){
|
|
if(h->ip >= h->ehint)
|
|
herror(h, "reached end of stream during skip()");
|
|
if(debug) debugprint(h, 1);
|
|
switch(mode){
|
|
case 0:
|
|
if(*h->ip == 0x2d)
|
|
return;
|
|
break;
|
|
case 1:
|
|
if(level == 0 && (*h->ip == 0x1b || *h->ip == 0x59))
|
|
return;
|
|
}
|
|
switch(*h->ip++){
|
|
case 0x40:
|
|
case 0x41:
|
|
if(h->ip < h->ehint)
|
|
h->ip += *h->ip + 1;
|
|
break;
|
|
case 0x58: level++; break;
|
|
case 0x59: level--; break;
|
|
case 0xb0: case 0xb1: case 0xb2: case 0xb3:
|
|
case 0xb4: case 0xb5: case 0xb6: case 0xb7:
|
|
h->ip += (h->ip[-1] & 7) + 1;
|
|
break;
|
|
case 0xb8: case 0xb9: case 0xba: case 0xbb:
|
|
case 0xbc: case 0xbd: case 0xbe: case 0xbf:
|
|
h->ip += 2 * ((h->ip[-1] & 7) + 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_fdef(Hint *h)
|
|
{
|
|
int i;
|
|
u8int *sp;
|
|
TTFont *f;
|
|
|
|
f = h->f;
|
|
i = pop(h);
|
|
if((uint)i >= h->f->u->maxFunctionDefs)
|
|
herror(h, "function identifier out of range");
|
|
sp = h->ip;
|
|
skip(h, 0);
|
|
f->func[i].npgm = h->ip - sp;
|
|
f->func[i].pgm = mallocz(f->func[i].npgm, 1);
|
|
if(f->func[i].pgm == nil)
|
|
herror(h, "malloc: %r");
|
|
memcpy(f->func[i].pgm, sp, f->func[i].npgm);
|
|
h->ip++;
|
|
}
|
|
|
|
static void run(Hint *);
|
|
|
|
static void
|
|
h_call(Hint *h)
|
|
{
|
|
int i;
|
|
u8int *lip, *lshint, *lehint;
|
|
|
|
i = pop(h);
|
|
if((uint)i >= h->f->u->maxFunctionDefs || h->f->func[i].npgm == 0)
|
|
herror(h, "undefined funcion %d", i);
|
|
lip = h->ip;
|
|
lshint = h->shint;
|
|
lehint = h->ehint;
|
|
h->ip = h->shint = h->f->func[i].pgm;
|
|
h->ehint = h->ip + h->f->func[i].npgm;
|
|
h->level++;
|
|
run(h);
|
|
h->level--;
|
|
h->ip = lip;
|
|
h->shint = lshint;
|
|
h->ehint = lehint;
|
|
}
|
|
|
|
static void
|
|
h_loopcall(Hint *h)
|
|
{
|
|
int i, n;
|
|
u8int *lip, *lshint, *lehint;
|
|
|
|
i = pop(h);
|
|
n = pop(h);
|
|
if((uint)i >= h->f->u->maxFunctionDefs || h->f->func[i].npgm == 0)
|
|
herror(h, "undefined funcion %d", i);
|
|
for(; n > 0; n--){
|
|
lip = h->ip;
|
|
lshint = h->shint;
|
|
lehint = h->ehint;
|
|
h->ip = h->shint = h->f->func[i].pgm;
|
|
h->ehint = h->ip + h->f->func[i].npgm;
|
|
h->level++;
|
|
run(h);
|
|
h->level--;
|
|
h->ip = lip;
|
|
h->shint = lshint;
|
|
h->ehint = lehint;
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_dup(Hint *h)
|
|
{
|
|
u32int x;
|
|
|
|
x = pop(h);
|
|
push(h, x);
|
|
push(h, x);
|
|
}
|
|
|
|
static void
|
|
h_swap(Hint *h)
|
|
{
|
|
u32int x, y;
|
|
|
|
x = pop(h);
|
|
y = pop(h);
|
|
push(h, x);
|
|
push(h, y);
|
|
}
|
|
|
|
static void
|
|
h_cindex(Hint *h)
|
|
{
|
|
int n;
|
|
|
|
n = pop(h);
|
|
if(n <= 0 || n > h->sp)
|
|
herror(h, "CINDEX[%d] out of range", n);
|
|
push(h, h->stack[h->sp - n]);
|
|
}
|
|
|
|
static void
|
|
h_mindex(Hint *h)
|
|
{
|
|
int n, x;
|
|
|
|
n = pop(h);
|
|
if(n <= 0 || n > h->sp)
|
|
herror(h, "MINDEX[%d] out of range", n);
|
|
x = h->stack[h->sp - n];
|
|
memmove(&h->stack[h->sp - n], &h->stack[h->sp - n + 1], (n - 1) * sizeof(u32int));
|
|
h->stack[h->sp - 1] = x;
|
|
}
|
|
|
|
static void
|
|
h_svtca(Hint *h)
|
|
{
|
|
int a;
|
|
|
|
a = h->ip[-1];
|
|
if(a < 2 || a >= 4){
|
|
h->f->fvx = 16384 * (a & 1);
|
|
h->f->fvy = 16384 * (~a & 1);
|
|
}
|
|
if(a < 4){
|
|
h->f->dpvx = h->f->pvx = 16384 * (a & 1);
|
|
h->f->dpvy = h->f->pvy = 16384 * (~a & 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_instctrl(Hint *h)
|
|
{
|
|
int s, v;
|
|
|
|
s = pop(h);
|
|
v = pop(h);
|
|
if(v != 0)
|
|
h->f->instctrl |= 1<<s;
|
|
else
|
|
h->f->instctrl &= ~(1<<s);
|
|
}
|
|
|
|
static void
|
|
h_mppem(Hint *h)
|
|
{
|
|
push(h, h->f->ppem);
|
|
}
|
|
|
|
static int
|
|
ttround(Hint *h, int x)
|
|
{
|
|
int y;
|
|
|
|
if(h->f->rperiod == 0) return x;
|
|
if(x >= 0){
|
|
y = x - h->f->rphase + h->f->rthold;
|
|
y -= y % h->f->rperiod;
|
|
y += h->f->rphase;
|
|
if(y < 0) y = h->f->rphase;
|
|
}else{
|
|
y = x + h->f->rphase - h->f->rthold;
|
|
y -= y % h->f->rperiod;
|
|
y -= h->f->rphase;
|
|
if(y > 0) y = -h->f->rphase;
|
|
}
|
|
return y;
|
|
}
|
|
|
|
static void
|
|
h_binop(Hint *h)
|
|
{
|
|
int a, b, r;
|
|
|
|
b = pop(h);
|
|
a = pop(h);
|
|
switch(h->ip[-1]){
|
|
case 0x50: r = a < b; break;
|
|
case 0x51: r = a <= b; break;
|
|
case 0x52: r = a > b; break;
|
|
case 0x53: r = a >= b; break;
|
|
case 0x54: r = a == b; break;
|
|
case 0x55: r = a != b; break;
|
|
case 0x5a: r = a && b; break;
|
|
case 0x5b: r = a || b; break;
|
|
case 0x60: r = a + b; break;
|
|
case 0x61: r = a - b; break;
|
|
case 0x62: if(b == 0) herror(h, "division by zero"); r = (vlong)(int)a * 64 / (int)b; break;
|
|
case 0x63: r = (vlong)(int)a * (vlong)(int)b >> 6; break;
|
|
case 0x8b: r = a < b ? b : a; break;
|
|
case 0x8c: r = a < b ? a : b; break;
|
|
default: SET(r); abort();
|
|
}
|
|
push(h, r);
|
|
}
|
|
|
|
static void
|
|
h_unop(Hint *h)
|
|
{
|
|
u32int a, r;
|
|
|
|
a = pop(h);
|
|
switch(h->ip[-1]){
|
|
case 0x56: r = (ttround(h, a) / 64 & 1) != 0; break;
|
|
case 0x57: r = (ttround(h, a) / 64 & 1) == 0; break;
|
|
case 0x5c: r = !a; break;
|
|
case 0x64: r = (int)a < 0 ? -a : a; break;
|
|
case 0x65: r = -a; break;
|
|
case 0x66: r = a & -64; break;
|
|
case 0x67: r = -(-a & -64); break;
|
|
case 0x68: case 0x69: case 0x6a: case 0x6b: r = ttround(h, a); break;
|
|
default: SET(r); abort();
|
|
}
|
|
push(h, r);
|
|
}
|
|
|
|
static void
|
|
h_rs(Hint *h)
|
|
{
|
|
int n;
|
|
|
|
n = pop(h);
|
|
if((uint)n >= h->f->u->maxStorage)
|
|
herror(h, "RS[%d] out of bounds");
|
|
push(h, h->f->storage[n]);
|
|
}
|
|
|
|
static void
|
|
h_ws(Hint *h)
|
|
{
|
|
u32int v;
|
|
int n;
|
|
|
|
v = pop(h);
|
|
n = pop(h);
|
|
if((uint)n >= h->f->u->maxStorage)
|
|
herror(h, "WS[%d] out of bounds");
|
|
h->f->storage[n] = v;
|
|
}
|
|
|
|
static void
|
|
h_if(Hint *h)
|
|
{
|
|
u32int x;
|
|
|
|
x = pop(h);
|
|
if(!x){
|
|
skip(h, 1);
|
|
h->ip++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_else(Hint *h)
|
|
{
|
|
skip(h, 1);
|
|
h->ip++;
|
|
}
|
|
|
|
static void
|
|
h_nop(Hint *)
|
|
{
|
|
}
|
|
|
|
static void
|
|
h_getinfo(Hint *h)
|
|
{
|
|
int s;
|
|
u32int r;
|
|
|
|
s = pop(h);
|
|
r = 0;
|
|
if((s & 1) != 0) r |= 3;
|
|
push(h, r);
|
|
}
|
|
|
|
static void
|
|
h_scanctrl(Hint *h)
|
|
{
|
|
h->f->scanctrl = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_scantype(Hint *h)
|
|
{
|
|
h->f->scantype = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_roundst(Hint *h)
|
|
{
|
|
h->f->rperiod = 64;
|
|
h->f->rphase = 0;
|
|
h->f->rthold = 32;
|
|
switch(h->ip[-1]){
|
|
case 0x19: /* RTHG */
|
|
h->f->rphase = 32;
|
|
break;
|
|
case 0x3D: /* RTDG */
|
|
h->f->rperiod = 32;
|
|
h->f->rthold = 16;
|
|
break;
|
|
case 0x7C: /* RUTG */
|
|
h->f->rthold = 63;
|
|
break;
|
|
case 0x7D: /* RDTG */
|
|
h->f->rthold = 0;
|
|
break;
|
|
case 0x7A: /* ROFF */
|
|
h->f->rperiod = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_sround(Hint *h)
|
|
{
|
|
u8int n;
|
|
|
|
n = pop(h);
|
|
if((n >> 6 & 3) == 3)
|
|
herror(h, "(S)ROUND: period set to reserved value 3");
|
|
if(h->ip[-1] == 0x77)
|
|
h->f->rperiod = 181 >> (2 - (n >> 6 & 3));
|
|
else
|
|
h->f->rperiod = 32 << (n >> 6 & 3);
|
|
h->f->rphase = h->f->rperiod * (n >> 4 & 3) / 4;
|
|
if((n & 15) == 0)
|
|
h->f->rthold = h->f->rperiod - 1;
|
|
else
|
|
h->f->rthold = h->f->rperiod * ((int)(n & 15) - 4) / 8;
|
|
}
|
|
|
|
static void
|
|
h_srp(Hint *h)
|
|
{
|
|
h->f->rp[h->ip[-1] & 3] = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_szp(Hint *h)
|
|
{
|
|
int n, t;
|
|
|
|
n = pop(h);
|
|
if(n>>1 != 0) herror(h, "SZP invalid argument %d", n);
|
|
t = h->ip[-1] - 0x13;
|
|
if(t == 3) h->f->zp = 7 * n;
|
|
else h->f->zp = h->f->zp & ~(1<<t) | n<<t;
|
|
}
|
|
|
|
static int
|
|
project(Hint *h, TTPoint *p, TTPoint *q)
|
|
{
|
|
if(q == nil)
|
|
return rounddiv(h->f->pvx * p->x + h->f->pvy * p->y, 16384);
|
|
return rounddiv(h->f->pvx * (p->x - q->x) + h->f->pvy * (p->y - q->y), 16384);
|
|
}
|
|
|
|
static int
|
|
dualproject(Hint *h, TTPoint *p, TTPoint *q)
|
|
{
|
|
if(q == nil)
|
|
return rounddiv(h->f->dpvx * p->x + h->f->dpvy * p->y, 16384);
|
|
return rounddiv(h->f->dpvx * (p->x - q->x) + h->f->dpvy * (p->y - q->y), 16384);
|
|
}
|
|
|
|
static TTPoint
|
|
forceproject(Hint *h, TTPoint p, int d)
|
|
{
|
|
TTFont *f;
|
|
TTPoint n;
|
|
int den;
|
|
vlong k;
|
|
|
|
f = h->f;
|
|
den = f->pvx * f->fvx + f->pvy * f->fvy;
|
|
if(den == 0) herror(h, "FV and PV orthogonal");
|
|
k = f->fvx * p.y - f->fvy * p.x;
|
|
n.x = vrounddiv(16384LL * d * f->fvx - k * f->pvy, den);
|
|
n.y = vrounddiv(16384LL * d * f->fvy + k * f->pvx, den);
|
|
n.flags = p.flags;
|
|
return n;
|
|
}
|
|
|
|
static void
|
|
h_miap(Hint *h)
|
|
{
|
|
int a, pi, di, d, d0, d1;
|
|
TTPoint p, n;
|
|
|
|
a = h->ip[-1] & 1;
|
|
di = pop(h);
|
|
pi = pop(h);
|
|
if((uint)di >= h->f->ncvt) herror(h, "MIAP out of range");
|
|
p = getpoint(h, ZP0, pi);
|
|
d0 = h->f->cvt[di];
|
|
dprint("cvt %d\n", d0);
|
|
d1 = project(h, &p, nil);
|
|
dprint("old %d\n", d1);
|
|
d = d0;
|
|
if((h->f->zp & 1) != 0){
|
|
if(a && abs(d1 - d) > h->f->cvci)
|
|
d = d1;
|
|
}else{
|
|
/* fuck you microsoft */
|
|
h->f->twiorg[pi].x = rounddiv(d0 * h->f->pvx, 16384);
|
|
h->f->twiorg[pi].y = rounddiv(d0 * h->f->pvy, 16384);
|
|
}
|
|
if(a) d = ttround(h, d);
|
|
n = forceproject(h, p, d);
|
|
setpoint(h, 0x80, pi, n);
|
|
h->f->rp[0] = h->f->rp[1] = pi;
|
|
}
|
|
|
|
static void
|
|
h_mdap(Hint *h)
|
|
{
|
|
int pi;
|
|
TTPoint p;
|
|
|
|
pi = pop(h);
|
|
p = getpoint(h, ZP0, pi);
|
|
if((h->ip[-1] & 1) != 0)
|
|
p = forceproject(h, p, ttround(h, project(h, &p, nil)));
|
|
setpoint(h, ZP0, pi, p);
|
|
h->f->rp[0] = h->f->rp[1] = pi;
|
|
}
|
|
|
|
static void
|
|
h_ip(Hint *h)
|
|
{
|
|
int i;
|
|
int pi;
|
|
TTPoint p1, op1, p2, op2, p, op, n;
|
|
int dp1, dp2, do12, d;
|
|
|
|
p1 = getpoint(h, RP1 | ZP0, 0);
|
|
op1 = getpoint(h, RP1 | ZP0 | ORIG, 0);
|
|
p2 = getpoint(h, RP2 | ZP1, 0);
|
|
op2 = getpoint(h, RP2 | ZP1 | ORIG, 0);
|
|
dp1 = project(h, &p1, nil);
|
|
dp2 = project(h, &p2, nil);
|
|
do12 = dualproject(h, &op1, &op2);
|
|
if(do12 == 0)
|
|
herror(h, "invalid IP[] call");
|
|
for(i = 0; i < h->f->loop; i++){
|
|
pi = pop(h);
|
|
p = getpoint(h, ZP2, pi);
|
|
op = getpoint(h, ZP2 | ORIG, pi);
|
|
d = ttfvrounddiv((vlong)dp1 * dualproject(h, &op, &op2) - (vlong)dp2 * dualproject(h, &op, &op1), do12);
|
|
n = forceproject(h, p, d);
|
|
setpoint(h, 0x82, pi, n);
|
|
dprint("(%d,%d) -> (%d,%d)\n", p.x, p.y, n.x, n.y);
|
|
}
|
|
h->f->loop = 1;
|
|
}
|
|
|
|
static void
|
|
h_gc0(Hint *h)
|
|
{
|
|
int pi;
|
|
TTPoint p;
|
|
|
|
pi = pop(h);
|
|
p = getpoint(h, ZP2, pi);
|
|
push(h, project(h, &p, nil));
|
|
}
|
|
|
|
static void
|
|
h_gc1(Hint *h)
|
|
{
|
|
int pi;
|
|
TTPoint p;
|
|
|
|
pi = pop(h);
|
|
p = getpoint(h, ZP2|ORIG, pi);
|
|
push(h, dualproject(h, &p, nil));
|
|
}
|
|
|
|
static void
|
|
h_wcvtp(Hint *h)
|
|
{
|
|
u32int v, l;
|
|
|
|
v = pop(h);
|
|
l = pop(h);
|
|
if(l >= h->f->ncvt) herror(h, "WCVTP out of range");
|
|
h->f->cvt[l] = v;
|
|
}
|
|
|
|
static void
|
|
h_wcvtf(Hint *h)
|
|
{
|
|
u32int v, l;
|
|
|
|
v = pop(h);
|
|
l = pop(h);
|
|
if(l >= h->f->ncvt) herror(h, "WCVTF out of range");
|
|
h->f->cvt[l] = rounddiv(v * h->f->ppem * 64, h->f->u->emsize);
|
|
}
|
|
|
|
static void
|
|
h_rcvt(Hint *h)
|
|
{
|
|
u32int l;
|
|
|
|
l = pop(h);
|
|
if(l >= h->f->ncvt) herror(h, "RCVT out of range");
|
|
push(h, h->f->cvt[l]);
|
|
}
|
|
|
|
static void
|
|
h_round(Hint *h)
|
|
{
|
|
push(h, ttround(h, pop(h)));
|
|
}
|
|
|
|
static void
|
|
h_roll(Hint *h)
|
|
{
|
|
u32int a, b, c;
|
|
|
|
a = pop(h);
|
|
b = pop(h);
|
|
c = pop(h);
|
|
push(h, b);
|
|
push(h, a);
|
|
push(h, c);
|
|
}
|
|
|
|
static void
|
|
h_pop(Hint *h)
|
|
{
|
|
pop(h);
|
|
}
|
|
|
|
static void
|
|
h_clear(Hint *h)
|
|
{
|
|
h->sp = 0;
|
|
}
|
|
|
|
static void
|
|
h_depth(Hint *h)
|
|
{
|
|
push(h, h->sp);
|
|
}
|
|
|
|
static void
|
|
h_scvtci(Hint *h)
|
|
{
|
|
h->f->cvci = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_mirp(Hint *h)
|
|
{
|
|
int a;
|
|
u32int cvti, pi;
|
|
TTPoint n, p, p0, op, op0;
|
|
int d0, d;
|
|
|
|
a = h->ip[-1] & 31;
|
|
cvti = pop(h);
|
|
pi = pop(h);
|
|
if(cvti >= h->f->ncvt)
|
|
herror(h, "MIRP out of bounds");
|
|
d = h->f->cvt[cvti];
|
|
dprint("cvt %d\n", d);
|
|
if(abs(d - h->f->singlewval) < h->f->singlewci)
|
|
d = d < 0 ? -h->f->singlewci : h->f->singlewci;
|
|
dprint("single %d\n", d);
|
|
p = getpoint(h, ZP1, pi);
|
|
p0 = getpoint(h, ZP0 | RP0, 0);
|
|
op = getpoint(h, ZP1 | ORIG, pi);
|
|
op0 = getpoint(h, ZP0 | RP0 | ORIG, 0);
|
|
d0 = dualproject(h, &op, &op0);
|
|
if(h->f->autoflip && (d0 ^ d) < 0)
|
|
d = -d;
|
|
if((a & 4) != 0){
|
|
if((h->f->zp + 1 & 3) <= 1 && abs(d - d0) > h->f->cvci)
|
|
d = d0;
|
|
dprint("cutin %d (%d)\n", d, h->f->cvci);
|
|
d = ttround(h, d);
|
|
}
|
|
dprint("round %d\n", d);
|
|
if((a & 8) != 0)
|
|
if(d0 >= 0){
|
|
if(d < h->f->mindist)
|
|
d = h->f->mindist;
|
|
}else{
|
|
if(d > -h->f->mindist)
|
|
d = -h->f->mindist;
|
|
}
|
|
dprint("mindist %d (%d)\n", d, h->f->mindist);
|
|
d += project(h, &p0, nil);
|
|
dprint("total %d\n", d);
|
|
n = forceproject(h, p, d);
|
|
setpoint(h, ZP1, pi, n);
|
|
h->f->rp[1] = h->f->rp[0];
|
|
h->f->rp[2] = pi;
|
|
if((a & 16) != 0)
|
|
h->f->rp[0] = pi;
|
|
}
|
|
|
|
static void
|
|
h_msirp(Hint *h)
|
|
{
|
|
int a;
|
|
u32int pi;
|
|
TTPoint n, p, p0;
|
|
int d;
|
|
|
|
a = h->ip[-1] & 31;
|
|
d = pop(h);
|
|
pi = pop(h);
|
|
if(abs(d - h->f->singlewval) < h->f->singlewci)
|
|
d = d < 0 ? -h->f->singlewci : h->f->singlewci;
|
|
p = getpoint(h, ZP1, pi);
|
|
p0 = getpoint(h, ZP0 | RP0, 0);
|
|
d += project(h, &p0, nil);
|
|
n = forceproject(h, p, d);
|
|
setpoint(h, ZP1, pi, n);
|
|
h->f->rp[1] = h->f->rp[0];
|
|
h->f->rp[2] = pi;
|
|
if((a & 1) != 0)
|
|
h->f->rp[0] = pi;
|
|
}
|
|
|
|
static void
|
|
h_deltac(Hint *h)
|
|
{
|
|
int n, b, c, arg;
|
|
|
|
n = pop(h);
|
|
b = (h->ip[-1] - 0x73) * 16 + h->f->deltabase;
|
|
while(n--){
|
|
c = pop(h);
|
|
arg = pop(h);
|
|
if(h->f->ppem != b + (arg >> 4)) continue;
|
|
arg &= 0xf;
|
|
arg = arg + (arg >> 3) - 8 << h->f->deltashift;
|
|
if((uint)c >= h->f->ncvt) herror(h, "DELTAC argument out of range");
|
|
h->f->cvt[c] += arg;
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_deltap(Hint *h)
|
|
{
|
|
int cnt, b, pi, arg;
|
|
TTPoint p, n;
|
|
|
|
cnt = pop(h);
|
|
b = (h->ip[-1] == 0x5d ? 0 : h->ip[-1] - 0x70) * 16 + h->f->deltabase;
|
|
while(cnt--){
|
|
pi = pop(h);
|
|
arg = pop(h);
|
|
if(h->f->ppem != b + (arg >> 4)) continue;
|
|
arg &= 0xf;
|
|
arg = arg + (arg >> 3) - 8 << h->f->deltashift;
|
|
p = getpoint(h, ZP0, pi);
|
|
n = forceproject(h, p, project(h, &p, nil) + arg);
|
|
setpoint(h, ZP0, pi, n);
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_jmpr(Hint *h)
|
|
{
|
|
h->ip += (int)pop(h) - 1;
|
|
if(h->ip < h->shint || h->ip > h->ehint)
|
|
herror(h, "JMPR out of bounds");
|
|
}
|
|
|
|
static void
|
|
h_jrcond(Hint *h)
|
|
{
|
|
u32int e;
|
|
int n;
|
|
|
|
e = pop(h);
|
|
n = pop(h) - 1;
|
|
if((e == 0) == (h->ip[-1] & 1)){
|
|
h->ip += n;
|
|
if(h->ip < h->shint || h->ip > h->ehint)
|
|
herror(h, "JROT/JROF out of bounds");
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_smd(Hint *h)
|
|
{
|
|
h->f->mindist = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_alignrp(Hint *h)
|
|
{
|
|
int i, pi;
|
|
TTPoint p, q, n;
|
|
int dq;
|
|
|
|
q = getpoint(h, ZP0 | RP0, 0);
|
|
dq = project(h, &q, nil);
|
|
for(i = 0; i < h->f->loop; i++){
|
|
pi = pop(h);
|
|
p = getpoint(h, ZP1, pi);
|
|
n = forceproject(h, p, dq);
|
|
setpoint(h, ZP1, pi, n);
|
|
}
|
|
h->f->loop = 1;
|
|
}
|
|
|
|
static TTPoint
|
|
dirvec(TTPoint a, TTPoint b)
|
|
{
|
|
TTPoint r;
|
|
double d;
|
|
|
|
r.x = a.x - b.x;
|
|
r.y = a.y - b.y;
|
|
if(r.x == 0 && r.y == 0) r.x = 1<<14;
|
|
else{
|
|
d = hypot(r.x, r.y);
|
|
r.x = r.x / d * 16384;
|
|
r.y = r.y / d * 16384;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static void
|
|
h_sxvtl(Hint *h)
|
|
{
|
|
int pi1, pi2;
|
|
TTPoint p1, p2;
|
|
TTPoint p;
|
|
int z;
|
|
|
|
pi2 = pop(h);
|
|
pi1 = pop(h);
|
|
p1 = getpoint(h, ZP1, pi1);
|
|
p2 = getpoint(h, ZP2, pi2);
|
|
p = dirvec(p1, p2);
|
|
if((h->ip[-1] & 1) != 0){
|
|
z = p.x;
|
|
p.x = -p.y;
|
|
p.y = z;
|
|
}
|
|
if(h->ip[-1] >= 8){
|
|
h->f->fvx = p.x;
|
|
h->f->fvy = p.y;
|
|
}else{
|
|
h->f->dpvx = h->f->pvx = p.x;
|
|
h->f->dpvy = h->f->pvy = p.y;
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_sfvfs(Hint *h)
|
|
{
|
|
h->f->fvy = pop(h);
|
|
h->f->fvx = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_spvfs(Hint *h)
|
|
{
|
|
h->f->dpvy = h->f->pvy = pop(h);
|
|
h->f->dpvx = h->f->pvx = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_gfv(Hint *h)
|
|
{
|
|
push(h, h->f->fvx);
|
|
push(h, h->f->fvy);
|
|
}
|
|
|
|
static void
|
|
h_gpv(Hint *h)
|
|
{
|
|
push(h, h->f->pvx);
|
|
push(h, h->f->pvy);
|
|
}
|
|
|
|
static void
|
|
h_mdrp(Hint *h)
|
|
{
|
|
int pi;
|
|
TTPoint p, p0, op, op0, n;
|
|
int d, d0;
|
|
|
|
pi = pop(h);
|
|
p = getpoint(h, ZP1, pi);
|
|
p0 = getpoint(h, ZP0 | RP0, 0);
|
|
op = getpoint(h, ZP1 | ORIG, pi);
|
|
op0 = getpoint(h, ZP0 | RP0 | ORIG, 0);
|
|
d = d0 = dualproject(h, &op, &op0);
|
|
if(abs(d - h->f->singlewval) < h->f->singlewci)
|
|
d = d >= 0 ? -h->f->singlewci : h->f->singlewci;
|
|
if((h->ip[-1] & 4) != 0)
|
|
d = ttround(h, d);
|
|
if((h->ip[-1] & 8) != 0)
|
|
if(d0 >= 0){
|
|
if(d < h->f->mindist)
|
|
d = h->f->mindist;
|
|
}else{
|
|
if(d > -h->f->mindist)
|
|
d = -h->f->mindist;
|
|
}
|
|
n = forceproject(h, p, d + project(h, &p0, nil));
|
|
setpoint(h, ZP1, pi, n);
|
|
h->f->rp[1] = h->f->rp[0];
|
|
h->f->rp[2] = pi;
|
|
if((h->ip[-1] & 16) != 0)
|
|
h->f->rp[0] = pi;
|
|
}
|
|
|
|
static void
|
|
h_sdpvtl(Hint *h)
|
|
{
|
|
int pi1, pi2;
|
|
TTPoint p1, p2;
|
|
TTPoint op1, op2;
|
|
TTPoint p;
|
|
|
|
pi2 = pop(h);
|
|
pi1 = pop(h);
|
|
p1 = getpoint(h, ZP1, pi1);
|
|
p2 = getpoint(h, ZP2, pi2);
|
|
op1 = getpoint(h, ZP1 | ORIG, pi1);
|
|
op2 = getpoint(h, ZP2 | ORIG, pi2);
|
|
p = dirvec(p1, p2);
|
|
if((h->ip[-1] & 1) != 0){
|
|
h->f->pvx = -p.y;
|
|
h->f->pvy = p.x;
|
|
}else{
|
|
h->f->pvx = p.x;
|
|
h->f->pvy = p.y;
|
|
}
|
|
p = dirvec(op1, op2);
|
|
if((h->ip[-1] & 1) != 0){
|
|
h->f->dpvx = -p.y;
|
|
h->f->dpvy = p.x;
|
|
}else{
|
|
h->f->dpvx = p.x;
|
|
h->f->dpvy = p.y;
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_sfvtpv(Hint *h)
|
|
{
|
|
h->f->fvx = h->f->pvx;
|
|
h->f->fvy = h->f->pvy;
|
|
}
|
|
|
|
static void
|
|
h_sdb(Hint *h)
|
|
{
|
|
h->f->deltabase = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_sds(Hint *h)
|
|
{
|
|
h->f->deltashift = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_ssw(Hint *h)
|
|
{
|
|
h->f->singlewval = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_sswci(Hint *h)
|
|
{
|
|
h->f->singlewci = pop(h);
|
|
}
|
|
|
|
static void
|
|
h_fliponoff(Hint *h)
|
|
{
|
|
h->f->autoflip = h->ip[-1] & 1;
|
|
}
|
|
|
|
static void
|
|
h_md0(Hint *h)
|
|
{
|
|
TTPoint p0, p1;
|
|
|
|
p1 = getpoint(h, ZP1, pop(h));
|
|
p0 = getpoint(h, ZP0, pop(h));
|
|
push(h, project(h, &p0, &p1));
|
|
}
|
|
|
|
static void
|
|
h_md1(Hint *h)
|
|
{
|
|
TTPoint p0, p1;
|
|
|
|
p1 = getpoint(h, ZP1 | ORIG, pop(h));
|
|
p0 = getpoint(h, ZP0 | ORIG, pop(h));
|
|
push(h, dualproject(h, &p0, &p1));
|
|
}
|
|
|
|
static void
|
|
h_shpix(Hint *h)
|
|
{
|
|
int i, d, pi, dx, dy;
|
|
TTPoint p;
|
|
|
|
d = pop(h);
|
|
dx = vrounddiv((vlong)h->f->fvx * d, 16384);
|
|
dy = vrounddiv((vlong)h->f->fvy * d, 16384);
|
|
for(i = 0; i < h->f->loop; i++){
|
|
pi = pop(h);
|
|
p = getpoint(h, ZP2, pi);
|
|
p.x += dx;
|
|
p.y += dy;
|
|
setpoint(h, ZP2, pi, p);
|
|
}
|
|
h->f->loop = 1;
|
|
}
|
|
|
|
static void
|
|
iup1(Hint *h, int ip, int iq, int i, int e)
|
|
{
|
|
TTGlyph *g;
|
|
int z;
|
|
|
|
g = h->g;
|
|
if(g->ptorg[ip].x == g->ptorg[iq].x)
|
|
for(; i <= e; i++)
|
|
g->pt[i].x = g->ptorg[i].x + g->pt[iq].x - g->ptorg[iq].x;
|
|
else
|
|
for(; i <= e; i++){
|
|
z = (g->ptorg[i].x - g->ptorg[iq].x) * 64 / (g->ptorg[ip].x - g->ptorg[iq].x);
|
|
if(z < 0) z = 0;
|
|
else if(z > 64) z = 64;
|
|
g->pt[i].x = g->ptorg[i].x + (((g->pt[ip].x - g->ptorg[ip].x) * z + (g->pt[iq].x - g->ptorg[iq].x) * (64 - z)) / 64);
|
|
}
|
|
}
|
|
|
|
static void
|
|
iup0(Hint *h, int ip, int iq, int i, int e)
|
|
{
|
|
TTGlyph *g;
|
|
int z;
|
|
|
|
g = h->g;
|
|
if(g->ptorg[ip].y == g->ptorg[iq].y)
|
|
for(; i <= e; i++)
|
|
g->pt[i].y = g->ptorg[i].y + g->pt[iq].y - g->ptorg[iq].y;
|
|
else
|
|
for(; i <= e; i++){
|
|
z = (g->ptorg[i].y - g->ptorg[iq].y) * 64 / (g->ptorg[ip].y - g->ptorg[iq].y);
|
|
if(z < 0) z = 0;
|
|
else if(z > 64) z = 64;
|
|
g->pt[i].y = g->ptorg[i].y + (((g->pt[ip].y - g->ptorg[ip].y) * z + (g->pt[iq].y - g->ptorg[iq].y) * (64 - z)) / 64);
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_iup(Hint *h)
|
|
{
|
|
int i, j, t0, t1;
|
|
TTPoint *p;
|
|
void (*iupp)(Hint *, int, int, int, int);
|
|
|
|
iupp = (h->ip[-1] & 1) != 0 ? iup1 : iup0;
|
|
for(i = 0; i < h->g->ncon; i++){
|
|
t0 = t1 = -1;
|
|
for(j = h->g->confst[i]; j < h->g->confst[i+1]; j++){
|
|
p = &h->g->pt[j];
|
|
if((p->flags & TOUCHY>>(h->ip[-1]&1)) != 0){
|
|
if(t0 < 0)
|
|
t0 = j;
|
|
if(t1 >= 0)
|
|
iupp(h, t1, j, t1 + 1, j - 1);
|
|
t1 = j;
|
|
}
|
|
}
|
|
if(t1 != t0){
|
|
iupp(h, t1, t0, h->g->confst[i], t0 - 1);
|
|
iupp(h, t1, t0, t1 + 1, h->g->confst[i+1]-1);
|
|
}else if(t0 >= 0)
|
|
iupp(h, t0, t0, h->g->confst[i], h->g->confst[i+1]-1);
|
|
}
|
|
|
|
for(i = 0; i < h->g->npt; i++)
|
|
dprint("%d: %+π\n", i, h->g->pt[i]);
|
|
}
|
|
|
|
static void
|
|
h_sloop(Hint *h)
|
|
{
|
|
int n;
|
|
|
|
n = pop(h);
|
|
if(n <= 0)
|
|
herror(h, "SLOOP invalid argument %d", n);
|
|
h->f->loop = n;
|
|
}
|
|
|
|
static void
|
|
h_scfs(Hint *h)
|
|
{
|
|
int d, pi;
|
|
TTPoint p, n;
|
|
|
|
d = pop(h);
|
|
pi = pop(h);
|
|
p = getpoint(h, ZP2, pi);
|
|
n = forceproject(h, p, d);
|
|
setpoint(h, ZP2, pi, n);
|
|
}
|
|
|
|
static void
|
|
h_fliprg(Hint *h)
|
|
{
|
|
int i, e;
|
|
|
|
e = pop(h);
|
|
i = pop(h);
|
|
if(h->g == nil)
|
|
herror(h, "FLIPRG without glyph");
|
|
for(; i <= e; i++)
|
|
if((int)i < h->g->npt)
|
|
h->g->pt[i].flags = h->g->pt[i].flags & ~1 | h->ip[-1] & 1;
|
|
}
|
|
|
|
static void
|
|
h_isect(Hint *h)
|
|
{
|
|
int a0i, a1i, b0i, b1i, pi;
|
|
TTPoint a0, a1, b0, b1, p;
|
|
int n0x, n0y;
|
|
vlong n0c;
|
|
int n1x, n1y;
|
|
vlong n1c;
|
|
int Δ;
|
|
|
|
a0i = pop(h);
|
|
a1i = pop(h);
|
|
b0i = pop(h);
|
|
b1i = pop(h);
|
|
pi = pop(h);
|
|
a0 = getpoint(h, ZP0, a0i);
|
|
a1 = getpoint(h, ZP0, a1i);
|
|
b0 = getpoint(h, ZP1, b0i);
|
|
b1 = getpoint(h, ZP1, b1i);
|
|
p = getpoint(h, ZP2, pi);
|
|
n0x = a1.y - a0.y;
|
|
n0y = a0.x - a1.x;
|
|
n0c = (vlong)n0x * a0.x + (vlong)n0y * a0.y;
|
|
n1x = b1.y - b0.y;
|
|
n1y = b0.x - b1.x;
|
|
n1c = (vlong)n1x * b0.x + (vlong)n1y * b0.y;
|
|
Δ = (vlong)n1x * n0y - (vlong)n0x * n1y;
|
|
if(Δ == 0){
|
|
p.x = ((a0.x + a1.x) / 2 + (b0.x + b1.x) / 2) / 2;
|
|
p.y = ((a0.y + a1.y) / 2 + (b0.y + b1.y) / 2) / 2;
|
|
}else{
|
|
p.x = vrounddiv(n0y * n1c - n1y * n0c, Δ);
|
|
p.y = vrounddiv(n1x * n0c - n0x * n1c, Δ);
|
|
}
|
|
p.flags |= TOUCH;
|
|
setpoint(h, ZP2, pi, p);
|
|
}
|
|
|
|
static void
|
|
h_shp(Hint *h)
|
|
{
|
|
int i;
|
|
TTPoint rp, orp;
|
|
int pi;
|
|
TTPoint p, n;
|
|
int d, dp;
|
|
|
|
if((h->ip[-1] & 1) != 0){
|
|
rp = getpoint(h, RP1|ZP0, 0);
|
|
orp = getpoint(h, RP1|ZP0|ORIG, 0);
|
|
}else{
|
|
rp = getpoint(h, RP2|ZP1, 0);
|
|
orp = getpoint(h, RP2|ZP1|ORIG, 0);
|
|
}
|
|
|
|
d = project(h, &rp, &orp);
|
|
for(i = 0; i < h->f->loop; i++){
|
|
pi = pop(h);
|
|
p = getpoint(h, ZP2, pi);
|
|
dp = project(h, &p, nil);
|
|
n = forceproject(h, p, dp + d);
|
|
setpoint(h, ZP2, pi, n);
|
|
}
|
|
h->f->loop = 1;
|
|
}
|
|
|
|
static void
|
|
h_shc(Hint *h)
|
|
{
|
|
int i, c;
|
|
int rpi;
|
|
TTPoint rp, orp;
|
|
TTPoint p, n;
|
|
int d, dp;
|
|
|
|
if((h->ip[-1] & 1) != 0){
|
|
rpi = h->f->rp[1];
|
|
if(((h->f->zp ^ h->f->zp >> 2) & 1) != 0)
|
|
rpi = -1;
|
|
rp = getpoint(h, RP1|ZP0, 0);
|
|
orp = getpoint(h, RP1|ZP0|ORIG, 0);
|
|
}else{
|
|
rpi = h->f->rp[2];
|
|
if(((h->f->zp ^ h->f->zp >> 1) & 1) != 0)
|
|
rpi = -1;
|
|
rp = getpoint(h, RP2|ZP1, 0);
|
|
orp = getpoint(h, RP2|ZP1|ORIG, 0);
|
|
}
|
|
c = pop(h);
|
|
if(h->g == nil)
|
|
herror(h, "SHC[] outside of glyf program");
|
|
if((uint)c >= h->g->ncon)
|
|
herror(h, "contour %d out of range", c);
|
|
d = project(h, &rp, &orp);
|
|
for(i = h->g->confst[c]; i < h->g->confst[c+1]; i++){
|
|
if(i == rpi) continue;
|
|
p = getpoint(h, ZP2, i);
|
|
dp = project(h, &p, nil);
|
|
n = forceproject(h, p, dp + d);
|
|
setpoint(h, ZP2, i, n);
|
|
}
|
|
}
|
|
|
|
static void
|
|
h_shz(Hint *h)
|
|
{
|
|
int i, e, np;
|
|
TTPoint rp, orp;
|
|
TTPoint p, n;
|
|
int d, dp;
|
|
|
|
if((h->ip[-1] & 1) != 0){
|
|
rp = getpoint(h, RP1|ZP0, 0);
|
|
orp = getpoint(h, RP1|ZP0|ORIG, 0);
|
|
}else{
|
|
rp = getpoint(h, RP2|ZP1, 0);
|
|
orp = getpoint(h, RP2|ZP1|ORIG, 0);
|
|
}
|
|
e = pop(h);
|
|
if((uint)e > 1)
|
|
herror(h, "SHZ[] with invalid zone %d", e);
|
|
d = project(h, &rp, &orp);
|
|
np = e ? h->g->npt : h->f->u->maxTwilightPoints;
|
|
for(i = 0; i < np; i++){
|
|
p = getpointz(h, e, i);
|
|
dp = project(h, &p, nil);
|
|
n = forceproject(h, p, dp + d);
|
|
setpointz(h, e, i, n);
|
|
}
|
|
}
|
|
|
|
static void (*itable[256])(Hint *) = {
|
|
[0x00] h_svtca, h_svtca, h_svtca, h_svtca, h_svtca, h_svtca,
|
|
[0x06] h_sxvtl, h_sxvtl, h_sxvtl, h_sxvtl,
|
|
[0x0a] h_spvfs,
|
|
[0x0b] h_sfvfs,
|
|
[0x0c] h_gpv,
|
|
[0x0d] h_gfv,
|
|
[0x0e] h_sfvtpv,
|
|
[0x0f] h_isect,
|
|
[0x10] h_srp, h_srp, h_srp,
|
|
[0x13] h_szp, h_szp, h_szp, h_szp,
|
|
[0x17] h_sloop,
|
|
[0x18] h_roundst, h_roundst,
|
|
[0x1a] h_smd,
|
|
[0x1b] h_else,
|
|
[0x1c] h_jmpr,
|
|
[0x1d] h_scvtci,
|
|
[0x1e] h_sswci,
|
|
[0x1f] h_ssw,
|
|
[0x20] h_dup,
|
|
[0x21] h_pop,
|
|
[0x22] h_clear,
|
|
[0x23] h_swap,
|
|
[0x24] h_depth,
|
|
[0x25] h_cindex,
|
|
[0x26] h_mindex,
|
|
[0x2a] h_loopcall,
|
|
[0x2b] h_call,
|
|
[0x2c] h_fdef,
|
|
[0x2e] h_mdap, h_mdap,
|
|
[0x30] h_iup, h_iup,
|
|
[0x32] h_shp, h_shp,
|
|
[0x34] h_shc, h_shc,
|
|
[0x36] h_shz, h_shz,
|
|
[0x38] h_shpix,
|
|
[0x39] h_ip,
|
|
[0x3a] h_msirp, h_msirp,
|
|
[0x3c] h_alignrp,
|
|
[0x3d] h_roundst,
|
|
[0x3e] h_miap, h_miap,
|
|
[0x40] h_npushb,
|
|
[0x41] h_npushw,
|
|
[0x42] h_ws,
|
|
[0x43] h_rs,
|
|
[0x44] h_wcvtp,
|
|
[0x45] h_rcvt,
|
|
[0x46] h_gc0, h_gc1,
|
|
[0x48] h_scfs,
|
|
[0x49] h_md0, h_md1,
|
|
[0x4b] h_mppem,
|
|
[0x4d] h_fliponoff, h_fliponoff,
|
|
[0x4f] h_nop,
|
|
[0x50] h_binop, h_binop, h_binop, h_binop, h_binop, h_binop,
|
|
[0x56] h_unop, h_unop,
|
|
[0x58] h_if,
|
|
[0x59] h_nop, /* endif */
|
|
[0x5a] h_binop, h_binop,
|
|
[0x5c] h_unop,
|
|
[0x5d] h_deltap,
|
|
[0x5e] h_sdb,
|
|
[0x5f] h_sds,
|
|
[0x60] h_binop, h_binop, h_binop, h_binop, h_unop, h_unop, h_unop, h_unop,
|
|
[0x68] h_unop, h_unop, h_unop, h_unop, h_nop, h_nop, h_nop, h_nop,
|
|
[0x70] h_wcvtf,
|
|
[0x71] h_deltap, h_deltap,
|
|
[0x73] h_deltac, h_deltac, h_deltac,
|
|
[0x76] h_sround, h_sround,
|
|
[0x78] h_jrcond, h_jrcond,
|
|
[0x7a] h_roundst,
|
|
[0x7c] h_roundst, h_roundst,
|
|
[0x7e] h_pop,
|
|
[0x7f] h_pop,
|
|
[0x81] h_fliprg, h_fliprg,
|
|
[0x85] h_scanctrl,
|
|
[0x86] h_sdpvtl, h_sdpvtl,
|
|
[0x88] h_getinfo,
|
|
[0x8a] h_roll,
|
|
[0x8b] h_binop, h_binop,
|
|
[0x8d] h_scantype,
|
|
[0x8e] h_instctrl,
|
|
[0xb0] h_pushb, h_pushb, h_pushb, h_pushb,
|
|
h_pushb, h_pushb, h_pushb, h_pushb,
|
|
[0xb8] h_pushw, h_pushw, h_pushw, h_pushw,
|
|
h_pushw, h_pushw, h_pushw, h_pushw,
|
|
[0xc0] h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp,
|
|
h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp,
|
|
h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp,
|
|
h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp,
|
|
[0xe0] h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp,
|
|
h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp,
|
|
h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp,
|
|
h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp,
|
|
};
|
|
|
|
static int
|
|
pointfmt(Fmt *f)
|
|
{
|
|
TTPoint p;
|
|
|
|
p = va_arg(f->args, TTPoint);
|
|
if((f->flags & FmtSign) != 0)
|
|
return fmtprint(f, "(%.2f,%.2f,%d)", (float)p.x/64, (float)p.y/64, p.flags);
|
|
else
|
|
return fmtprint(f, "(%d,%d,%d)", p.x, p.y, p.flags);
|
|
}
|
|
|
|
static void
|
|
run(Hint *h)
|
|
{
|
|
while(h->ip < h->ehint){
|
|
if(debug) debugprint(h, 0);
|
|
if(itable[*h->ip] == nil)
|
|
sysfatal("unknown hint instruction %#.2x", *h->ip);
|
|
else
|
|
itable[*h->ip++](h);
|
|
}
|
|
}
|
|
|
|
static int
|
|
runpg(TTFont *f, TTGlyph *g, uchar *buf, int n)
|
|
{
|
|
Hint h;
|
|
static int didfmt;
|
|
|
|
if(debug && !didfmt){
|
|
fmtinstall(L'π', pointfmt);
|
|
didfmt = 1;
|
|
}
|
|
memset(&h, 0, sizeof(Hint));
|
|
if(setjmp(h.jmp) != 0){
|
|
errstr(h.err, sizeof(h.err));
|
|
return -1;
|
|
}
|
|
h.g = g;
|
|
h.f = f;
|
|
h.stack = f->hintstack;
|
|
h.nstack = f->u->maxStackElements;
|
|
h.ip = h.shint = buf;
|
|
h.ehint = buf + n;
|
|
run(&h);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ttfhint(TTGlyph *g)
|
|
{
|
|
int rc, i;
|
|
|
|
if((g->font->defstate.instctrl & 1<<1) != 0)
|
|
return 0;
|
|
dprint("HINT:\n");
|
|
if((g->font->defstate.instctrl & 1<<2) != 0)
|
|
g->font->TTGState = defstate;
|
|
else
|
|
g->font->TTGState = g->font->defstate;
|
|
rc = runpg(g->font, g, g->hint, g->nhint);
|
|
if(debug && rc >= 0){
|
|
for(i = 0; i < g->npt; i++)
|
|
dprint("%d: %+π\n", i, g->pt[i]);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ttfrunfpgm(TTFont *f)
|
|
{
|
|
int len, rc;
|
|
u8int *buf;
|
|
|
|
f->TTGState = defstate;
|
|
f->defstate = defstate;
|
|
len = ttfgototable(f->u, "fpgm");
|
|
if(len <= 0)
|
|
return 0;
|
|
buf = mallocz(len, 1);
|
|
if(buf == nil)
|
|
return -1;
|
|
Bread(f->u->bin, buf, len);
|
|
dprint("FPGM:\n");
|
|
rc = runpg(f, nil, buf, len);
|
|
free(buf);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ttfruncvt(TTFont *f)
|
|
{
|
|
int len, rc;
|
|
u8int *buf;
|
|
|
|
f->TTGState = defstate;
|
|
f->defstate = defstate;
|
|
len = ttfgototable(f->u, "prep");
|
|
if(len <= 0)
|
|
return 0;
|
|
buf = mallocz(len, 1);
|
|
if(buf == nil)
|
|
return -1;
|
|
Bread(f->u->bin, buf, len);
|
|
dprint("CVT:\n");
|
|
rc = runpg(f, nil, buf, len);
|
|
free(buf);
|
|
if(rc >= 0){
|
|
f->zp = 7;
|
|
f->rp[0] = 0;
|
|
f->rp[1] = 0;
|
|
f->rp[2] = 0;
|
|
f->loop = 1;
|
|
f->rperiod = 64;
|
|
f->rphase = 0;
|
|
f->rthold = 32;
|
|
f->fvx = 16384;
|
|
f->fvy = 0;
|
|
f->pvx = 16384;
|
|
f->pvy = 0;
|
|
f->dpvx = 16384;
|
|
f->dpvy = 0;
|
|
f->defstate = f->TTGState;
|
|
}
|
|
return rc;
|
|
}
|