7 typedef struct Hint Hint;
11 #pragma varargck type "π" TTPoint
13 #define dprint(...) {if(debug) fprint(2, __VA_ARGS__);}
15 static TTGState defstate = {
41 u8int *shint, *ip, *ehint;
50 rounddiv(int a, int b)
52 if(b < 0){ a = -a; b = -b; }
60 vrounddiv(vlong a, int b)
62 if(b < 0){ a = -a; b = -b; }
70 herror(Hint *h, char *fmt, ...)
75 vsnprint(h->err, sizeof(h->err), fmt, va);
77 dprint("error: %s\n", h->err);
82 push(Hint *h, u32int w)
84 assert(h->sp < h->nstack);
85 h->stack[h->sp++] = w;
92 return h->stack[--h->sp];
99 herror(h, "missing byte");
115 getpoint(Hint *h, int n, int pi)
118 pi = h->f->rp[(n >> 4 & 3) - 1];
119 if((h->f->zp >> (n >> 8 & 3) & 1) != 0){
121 herror(h, "access to glyph zone from FPGM/CVT");
122 if((uint)pi >= h->g->npt)
123 herror(h, "glyph zone point index %d out of range", pi);
124 dprint("G%s%d: %+π\n", n&ORIG?"O":"", pi, (n & ORIG) != 0 ? h->g->ptorg[pi] : h->g->pt[pi]);
125 return (n & ORIG) != 0 ? h->g->ptorg[pi] : h->g->pt[pi];
127 if((uint)pi >= h->f->u->maxTwilightPoints)
128 herror(h, "twilight zone point index %d out of range", pi);
129 return (n & ORIG) != 0 ? h->f->twiorg[pi] : h->f->twilight[pi];
134 setpoint(Hint *h, int n, int pi, TTPoint p)
137 pi = h->f->rp[(n >> 4 & 3) - 1];
138 if((n & NOTOUCH) == 0){
139 if(h->f->fvx != 0) p.flags |= 2;
140 if(h->f->fvy != 0) p.flags |= 4;
142 if((h->f->zp >> (n >> 8 & 3) & 1) != 0){
144 herror(h, "access to glyph zone from FPGM/CVT");
145 if((uint)pi >= h->g->npt)
146 herror(h, "glyph zone point index %d out of range", pi);
147 dprint("G%d: %+π -> %+π\n", pi, h->g->pt[pi], p);
150 if((uint)pi >= h->f->u->maxTwilightPoints)
151 herror(h, "twilight zone point index %d out of range", pi);
152 dprint("T%d: %+π -> %+π\n", pi, h->f->twilight[pi], p);
153 h->f->twilight[pi] = p;
158 getpointz(Hint *h, int z, int pi)
162 herror(h, "access to glyph zone from FPGM/CVT");
163 if((uint)pi >= h->g->npt)
164 herror(h, "glyph zone point index %d out of range", pi);
165 dprint("G%s%d: %+π\n", z&ORIG?"O":"", pi, (z & ORIG) != 0 ? h->g->ptorg[pi] : h->g->pt[pi]);
166 return (z & ORIG) != 0 ? h->g->ptorg[pi] : h->g->pt[pi];
168 if((uint)pi >= h->f->u->maxTwilightPoints)
169 herror(h, "twilight zone point index %d out of range", pi);
170 return (z & ORIG) != 0 ? h->f->twiorg[pi] : h->f->twilight[pi];
175 setpointz(Hint *h, int z, int pi, TTPoint p)
179 herror(h, "access to glyph zone from FPGM/CVT");
180 if((uint)pi >= h->g->npt)
181 herror(h, "glyph zone point index %d out of range", pi);
182 dprint("G%d: %+π -> %+π\n", pi, h->g->pt[pi], p);
185 if((uint)pi >= h->f->u->maxTwilightPoints)
186 herror(h, "twilight zone point index %d out of range", pi);
187 dprint("T%d: %+π -> %+π\n", pi, h->f->twilight[pi], p);
188 h->f->twilight[pi] = p;
194 debugprint(Hint *h, int skip)
199 static char *opcnames[256] = {
200 [0x00] "SVTCA", "SVTCA", "SPVTCA", "SPVTCA", "SFVTCA", "SFVTCA", "SPVTL", "SPVTL",
201 [0x08] "SFVTL", "SFVTL", "SPVFS", "SFVFS", "GPV", "GFV", "SFVTPV", "ISECT",
202 [0x10] "SRP0", "SRP1", "SRP2", "SZP0", "SZP1", "SZP2", "SZPS", "SLOOP",
203 [0x18] "RTG", "RTHG", "SMD", "ELSE", "JMPR", "SCVTCI", "SSWCI", "SSW",
204 [0x20] "DUP", "POP", "CLEAR", "SWAP", "DEPTH", "CINDEX", "MINDEX", "ALIGNPTS",
205 [0x28] nil, "UTP", "LOOPCALL", "CALL", "FDEF", "ENDF", "MDAP", "MDAP",
206 [0x30] "IUP", "IUP", "SHP", "SHP", "SHC", "SHC", "SHZ", "SHZ",
207 [0x38] "SHPIX", "IP", "MSIRP", "MSIRP", "ALIGNRP", "RTDG", "MIAP", "MIAP",
208 [0x40] "NPUSHB", "NPUSHW", "WS", "RS", "WCVTP", "RCVT", "GC", "GC",
209 [0x48] "SCFS", "MD", "MD", "MPPEM", "MPS", "FLIPON", "FLIPOFF", "DEBUG",
210 [0x50] "LT", "LTEQ", "GT", "GTEQ", "EQ", "NEQ", "ODD", "EVEN",
211 [0x58] "IF", "EIF", "AND", "OR", "NOT", "DELTAP1", "SDB", "SDS",
212 [0x60] "ADD", "SUB", "DIV", "MUL", "ABS", "NEG", "FLOOR", "CEILING",
213 [0x68] "ROUND", "ROUND", "ROUND", "ROUND", "NROUND", "NROUND", "NROUND", "NROUND",
214 [0x70] "WCVTF", "DELTAP2", "DELTAP3", "DELTAC1", "DELTAC2", "DELTAC3", "SROUND", "S45ROUND",
215 [0x78] "JROT", "JROF", "ROFF", nil, "RUTG", "RDTG", "SANGW", "AA",
216 [0x80] "FLIPPT", "FLIPRGON", "FLIPRGOFF", [0x85] "SCANCTRL", "SDPVTL", "SDPVTL",
217 [0x88] "GETINFO", "IDEF", "ROLL", "MAX", "MIN", "SCANTYPE", "INSTCTRL", nil,
218 [0xB0] "PUSHB", "PUSHB", "PUSHB", "PUSHB", "PUSHB", "PUSHB", "PUSHB", "PUSHB",
219 [0xB8] "PUSHW", "PUSHW", "PUSHW", "PUSHW", "PUSHW", "PUSHW", "PUSHW", "PUSHW",
221 static u8int argb[256] = {
222 [0x00] 1, 1, 1, 1, 1, 1, 1, 1,
223 [0x08] 1, 1, 1, 1, 1, 1,
225 [0x30] 1, 1, 1, 1, 1, 1, 1, 1,
226 [0x38] 0, 0, 1, 1, 0, 0, 1, 1,
227 [0x46] 1, 1, 0, 1, 1,
228 [0x68] 2, 2, 2, 2, 2, 2, 2, 2,
233 fmtfdinit(&f, 2, buf, sizeof(buf));
235 if(skip) fmtprint(&f, "** ");
236 fmtprint(&f, "%d %d ", h->level, (int)(h->ip - h->shint));
238 fmtprint(&f, "%s[%d]", op >= 0xe0 ? "MIRP" : "MDRP", op & 0x1f);
239 else if(opcnames[op] == nil)
242 fmtprint(&f, argb[op] != 0 ? "%s[%d]" : "%s[]", opcnames[op], op & (1<<argb[op]) - 1);
244 fmtprint(&f, " :: ");
245 for(i = 0; i < 8 && i < h->sp; i++)
246 fmtprint(&f, "%d ", h->stack[h->sp - 1 - i]);
284 n = (h->ip[-1] & 7) + 1;
297 n = (h->ip[-1] & 7) + 1;
306 skip(Hint *h, int mode)
312 if(h->ip >= h->ehint)
313 herror(h, "reached end of stream during skip()");
314 if(debug) debugprint(h, 1);
321 if(level == 0 && (*h->ip == 0x1b || *h->ip == 0x59))
330 case 0x58: level++; break;
331 case 0x59: level--; break;
332 case 0xb0: case 0xb1: case 0xb2: case 0xb3:
333 case 0xb4: case 0xb5: case 0xb6: case 0xb7:
334 h->ip += (h->ip[-1] & 7) + 1;
336 case 0xb8: case 0xb9: case 0xba: case 0xbb:
337 case 0xbc: case 0xbd: case 0xbe: case 0xbf:
338 h->ip += 2 * ((h->ip[-1] & 7) + 1);
353 if((uint)i >= h->f->u->maxFunctionDefs)
354 herror(h, "function identifier out of range");
357 f->func[i].npgm = h->ip - sp;
358 f->func[i].pgm = mallocz(f->func[i].npgm, 1);
359 if(f->func[i].pgm == nil)
360 herror(h, "malloc: %r");
361 memcpy(f->func[i].pgm, sp, f->func[i].npgm);
365 static void run(Hint *);
371 u8int *lip, *lshint, *lehint;
374 if((uint)i >= h->f->u->maxFunctionDefs || h->f->func[i].npgm == 0)
375 herror(h, "undefined funcion %d", i);
379 h->ip = h->shint = h->f->func[i].pgm;
380 h->ehint = h->ip + h->f->func[i].npgm;
393 u8int *lip, *lshint, *lehint;
397 if((uint)i >= h->f->u->maxFunctionDefs || h->f->func[i].npgm == 0)
398 herror(h, "undefined funcion %d", i);
403 h->ip = h->shint = h->f->func[i].pgm;
404 h->ehint = h->ip + h->f->func[i].npgm;
441 if(n <= 0 || n > h->sp)
442 herror(h, "CINDEX[%d] out of range", n);
443 push(h, h->stack[h->sp - n]);
452 if(n <= 0 || n > h->sp)
453 herror(h, "MINDEX[%d] out of range", n);
454 x = h->stack[h->sp - n];
455 memmove(&h->stack[h->sp - n], &h->stack[h->sp - n + 1], (n - 1) * sizeof(u32int));
456 h->stack[h->sp - 1] = x;
466 h->f->fvx = 16384 * (a & 1);
467 h->f->fvy = 16384 * (~a & 1);
470 h->f->dpvx = h->f->pvx = 16384 * (a & 1);
471 h->f->dpvy = h->f->pvy = 16384 * (~a & 1);
483 h->f->instctrl |= 1<<s;
485 h->f->instctrl &= ~(1<<s);
495 ttround(Hint *h, int x)
499 if(h->f->rperiod == 0) return x;
501 y = x - h->f->rphase + h->f->rthold;
502 y -= y % h->f->rperiod;
504 if(y < 0) y = h->f->rphase;
506 y = x + h->f->rphase - h->f->rthold;
507 y -= y % h->f->rperiod;
509 if(y > 0) y = -h->f->rphase;
522 case 0x50: r = a < b; break;
523 case 0x51: r = a <= b; break;
524 case 0x52: r = a > b; break;
525 case 0x53: r = a >= b; break;
526 case 0x54: r = a == b; break;
527 case 0x55: r = a != b; break;
528 case 0x5a: r = a && b; break;
529 case 0x5b: r = a || b; break;
530 case 0x60: r = a + b; break;
531 case 0x61: r = a - b; break;
532 case 0x62: if(b == 0) herror(h, "division by zero"); r = (vlong)(int)a * 64 / (int)b; break;
533 case 0x63: r = (vlong)(int)a * (vlong)(int)b >> 6; break;
534 case 0x8b: r = a < b ? b : a; break;
535 case 0x8c: r = a < b ? a : b; break;
536 default: SET(r); abort();
548 case 0x56: r = (ttround(h, a) / 64 & 1) != 0; break;
549 case 0x57: r = (ttround(h, a) / 64 & 1) == 0; break;
550 case 0x5c: r = !a; break;
551 case 0x64: r = (int)a < 0 ? -a : a; break;
552 case 0x65: r = -a; break;
553 case 0x66: r = a & -64; break;
554 case 0x67: r = -(-a & -64); break;
555 case 0x68: case 0x69: case 0x6a: case 0x6b: r = ttround(h, a); break;
556 default: SET(r); abort();
567 if((uint)n >= h->f->u->maxStorage)
568 herror(h, "RS[%d] out of bounds");
569 push(h, h->f->storage[n]);
580 if((uint)n >= h->f->u->maxStorage)
581 herror(h, "WS[%d] out of bounds");
582 h->f->storage[n] = v;
617 if((s & 1) != 0) r |= 3;
624 h->f->scanctrl = pop(h);
630 h->f->scantype = pop(h);
640 case 0x19: /* RTHG */
643 case 0x3D: /* RTDG */
647 case 0x7C: /* RUTG */
650 case 0x7D: /* RDTG */
653 case 0x7A: /* ROFF */
665 if((n >> 6 & 3) == 3)
666 herror(h, "(S)ROUND: period set to reserved value 3");
667 if(h->ip[-1] == 0x77)
668 h->f->rperiod = 181 >> (2 - (n >> 6 & 3));
670 h->f->rperiod = 32 << (n >> 6 & 3);
671 h->f->rphase = h->f->rperiod * (n >> 4 & 3) / 4;
673 h->f->rthold = h->f->rperiod - 1;
675 h->f->rthold = h->f->rperiod * ((int)(n & 15) - 4) / 8;
681 h->f->rp[h->ip[-1] & 3] = pop(h);
690 if(n>>1 != 0) herror(h, "SZP invalid argument %d", n);
691 t = h->ip[-1] - 0x13;
692 if(t == 3) h->f->zp = 7 * n;
693 else h->f->zp = h->f->zp & ~(1<<t) | n<<t;
697 project(Hint *h, TTPoint *p, TTPoint *q)
700 return rounddiv(h->f->pvx * p->x + h->f->pvy * p->y, 16384);
701 return rounddiv(h->f->pvx * (p->x - q->x) + h->f->pvy * (p->y - q->y), 16384);
705 dualproject(Hint *h, TTPoint *p, TTPoint *q)
708 return rounddiv(h->f->dpvx * p->x + h->f->dpvy * p->y, 16384);
709 return rounddiv(h->f->dpvx * (p->x - q->x) + h->f->dpvy * (p->y - q->y), 16384);
713 forceproject(Hint *h, TTPoint p, int d)
721 den = f->pvx * f->fvx + f->pvy * f->fvy;
722 if(den == 0) herror(h, "FV and PV orthogonal");
723 k = f->fvx * p.y - f->fvy * p.x;
724 n.x = vrounddiv(16384LL * d * f->fvx - k * f->pvy, den);
725 n.y = vrounddiv(16384LL * d * f->fvy + k * f->pvx, den);
733 int a, pi, di, d, d0, d1;
739 if((uint)di >= h->f->ncvt) herror(h, "MIAP out of range");
740 p = getpoint(h, ZP0, pi);
742 dprint("cvt %d\n", d0);
743 d1 = project(h, &p, nil);
744 dprint("old %d\n", d1);
746 if((h->f->zp & 1) != 0){
747 if(a && abs(d1 - d) > h->f->cvci)
750 /* fuck you microsoft */
751 h->f->twiorg[pi].x = rounddiv(d0 * h->f->pvx, 16384);
752 h->f->twiorg[pi].y = rounddiv(d0 * h->f->pvy, 16384);
754 if(a) d = ttround(h, d);
755 n = forceproject(h, p, d);
756 setpoint(h, 0x80, pi, n);
757 h->f->rp[0] = h->f->rp[1] = pi;
767 p = getpoint(h, ZP0, pi);
768 if((h->ip[-1] & 1) != 0)
769 p = forceproject(h, p, ttround(h, project(h, &p, nil)));
770 setpoint(h, ZP0, pi, p);
771 h->f->rp[0] = h->f->rp[1] = pi;
779 TTPoint p1, op1, p2, op2, p, op, n;
780 int dp1, dp2, do12, d;
782 p1 = getpoint(h, RP1 | ZP0, 0);
783 op1 = getpoint(h, RP1 | ZP0 | ORIG, 0);
784 p2 = getpoint(h, RP2 | ZP1, 0);
785 op2 = getpoint(h, RP2 | ZP1 | ORIG, 0);
786 dp1 = project(h, &p1, nil);
787 dp2 = project(h, &p2, nil);
788 do12 = dualproject(h, &op1, &op2);
790 herror(h, "invalid IP[] call");
791 for(i = 0; i < h->f->loop; i++){
793 p = getpoint(h, ZP2, pi);
794 op = getpoint(h, ZP2 | ORIG, pi);
795 d = ttfvrounddiv((vlong)dp1 * dualproject(h, &op, &op2) - (vlong)dp2 * dualproject(h, &op, &op1), do12);
796 n = forceproject(h, p, d);
797 setpoint(h, 0x82, pi, n);
798 dprint("(%d,%d) -> (%d,%d)\n", p.x, p.y, n.x, n.y);
810 p = getpoint(h, ZP2, pi);
811 push(h, project(h, &p, nil));
821 p = getpoint(h, ZP2|ORIG, pi);
822 push(h, dualproject(h, &p, nil));
832 if(l >= h->f->ncvt) herror(h, "WCVTP out of range");
843 if(l >= h->f->ncvt) herror(h, "WCVTF out of range");
844 h->f->cvt[l] = rounddiv(v * h->f->ppem * 64, h->f->u->emsize);
853 if(l >= h->f->ncvt) herror(h, "RCVT out of range");
854 push(h, h->f->cvt[l]);
860 push(h, ttround(h, pop(h)));
905 TTPoint n, p, p0, op, op0;
911 if(cvti >= h->f->ncvt)
912 herror(h, "MIRP out of bounds");
914 dprint("cvt %d\n", d);
915 if(abs(d - h->f->singlewval) < h->f->singlewci)
916 d = d < 0 ? -h->f->singlewci : h->f->singlewci;
917 dprint("single %d\n", d);
918 p = getpoint(h, ZP1, pi);
919 p0 = getpoint(h, ZP0 | RP0, 0);
920 op = getpoint(h, ZP1 | ORIG, pi);
921 op0 = getpoint(h, ZP0 | RP0 | ORIG, 0);
922 d0 = dualproject(h, &op, &op0);
923 if(h->f->autoflip && (d0 ^ d) < 0)
926 if((h->f->zp + 1 & 3) <= 1 && abs(d - d0) > h->f->cvci)
928 dprint("cutin %d (%d)\n", d, h->f->cvci);
931 dprint("round %d\n", d);
934 if(d < h->f->mindist)
937 if(d > -h->f->mindist)
940 dprint("mindist %d (%d)\n", d, h->f->mindist);
941 d += project(h, &p0, nil);
942 dprint("total %d\n", d);
943 n = forceproject(h, p, d);
944 setpoint(h, ZP1, pi, n);
945 h->f->rp[1] = h->f->rp[0];
962 if(abs(d - h->f->singlewval) < h->f->singlewci)
963 d = d < 0 ? -h->f->singlewci : h->f->singlewci;
964 p = getpoint(h, ZP1, pi);
965 p0 = getpoint(h, ZP0 | RP0, 0);
966 d += project(h, &p0, nil);
967 n = forceproject(h, p, d);
968 setpoint(h, ZP1, pi, n);
969 h->f->rp[1] = h->f->rp[0];
981 b = (h->ip[-1] - 0x73) * 16 + h->f->deltabase;
985 if(h->f->ppem != b + (arg >> 4)) continue;
987 arg = arg + (arg >> 3) - 8 << h->f->deltashift;
988 if((uint)c >= h->f->ncvt) herror(h, "DELTAC argument out of range");
1000 b = (h->ip[-1] == 0x5d ? 0 : h->ip[-1] - 0x70) * 16 + h->f->deltabase;
1004 if(h->f->ppem != b + (arg >> 4)) continue;
1006 arg = arg + (arg >> 3) - 8 << h->f->deltashift;
1007 p = getpoint(h, ZP0, pi);
1008 n = forceproject(h, p, project(h, &p, nil) + arg);
1009 setpoint(h, ZP0, pi, n);
1016 h->ip += (int)pop(h) - 1;
1017 if(h->ip < h->shint || h->ip > h->ehint)
1018 herror(h, "JMPR out of bounds");
1029 if((e == 0) == (h->ip[-1] & 1)){
1031 if(h->ip < h->shint || h->ip > h->ehint)
1032 herror(h, "JROT/JROF out of bounds");
1039 h->f->mindist = pop(h);
1049 q = getpoint(h, ZP0 | RP0, 0);
1050 dq = project(h, &q, nil);
1051 for(i = 0; i < h->f->loop; i++){
1053 p = getpoint(h, ZP1, pi);
1054 n = forceproject(h, p, dq);
1055 setpoint(h, ZP1, pi, n);
1061 dirvec(TTPoint a, TTPoint b)
1068 if(r.x == 0 && r.y == 0) r.x = 1<<14;
1070 d = hypot(r.x, r.y);
1071 r.x = r.x / d * 16384;
1072 r.y = r.y / d * 16384;
1087 p1 = getpoint(h, ZP1, pi1);
1088 p2 = getpoint(h, ZP2, pi2);
1090 if((h->ip[-1] & 1) != 0){
1099 h->f->dpvx = h->f->pvx = p.x;
1100 h->f->dpvy = h->f->pvy = p.y;
1114 h->f->dpvy = h->f->pvy = pop(h);
1115 h->f->dpvx = h->f->pvx = pop(h);
1136 TTPoint p, p0, op, op0, n;
1140 p = getpoint(h, ZP1, pi);
1141 p0 = getpoint(h, ZP0 | RP0, 0);
1142 op = getpoint(h, ZP1 | ORIG, pi);
1143 op0 = getpoint(h, ZP0 | RP0 | ORIG, 0);
1144 d = d0 = dualproject(h, &op, &op0);
1145 if(abs(d - h->f->singlewval) < h->f->singlewci)
1146 d = d >= 0 ? -h->f->singlewci : h->f->singlewci;
1147 if((h->ip[-1] & 4) != 0)
1149 if((h->ip[-1] & 8) != 0)
1151 if(d < h->f->mindist)
1154 if(d > -h->f->mindist)
1157 n = forceproject(h, p, d + project(h, &p0, nil));
1158 setpoint(h, ZP1, pi, n);
1159 h->f->rp[1] = h->f->rp[0];
1161 if((h->ip[-1] & 16) != 0)
1175 p1 = getpoint(h, ZP1, pi1);
1176 p2 = getpoint(h, ZP2, pi2);
1177 op1 = getpoint(h, ZP1 | ORIG, pi1);
1178 op2 = getpoint(h, ZP2 | ORIG, pi2);
1180 if((h->ip[-1] & 1) != 0){
1187 p = dirvec(op1, op2);
1188 if((h->ip[-1] & 1) != 0){
1200 h->f->fvx = h->f->pvx;
1201 h->f->fvy = h->f->pvy;
1207 h->f->deltabase = pop(h);
1213 h->f->deltashift = pop(h);
1219 h->f->singlewval = pop(h);
1225 h->f->singlewci = pop(h);
1229 h_fliponoff(Hint *h)
1231 h->f->autoflip = h->ip[-1] & 1;
1239 p1 = getpoint(h, ZP1, pop(h));
1240 p0 = getpoint(h, ZP0, pop(h));
1241 push(h, project(h, &p0, &p1));
1249 p1 = getpoint(h, ZP1 | ORIG, pop(h));
1250 p0 = getpoint(h, ZP0 | ORIG, pop(h));
1251 push(h, dualproject(h, &p0, &p1));
1257 int i, d, pi, dx, dy;
1261 dx = vrounddiv((vlong)h->f->fvx * d, 16384);
1262 dy = vrounddiv((vlong)h->f->fvy * d, 16384);
1263 for(i = 0; i < h->f->loop; i++){
1265 p = getpoint(h, ZP2, pi);
1268 setpoint(h, ZP2, pi, p);
1274 iup1(Hint *h, int ip, int iq, int i, int e)
1280 if(g->ptorg[ip].x == g->ptorg[iq].x)
1282 g->pt[i].x = g->ptorg[i].x + g->pt[iq].x - g->ptorg[iq].x;
1285 z = (g->ptorg[i].x - g->ptorg[iq].x) * 64 / (g->ptorg[ip].x - g->ptorg[iq].x);
1287 else if(z > 64) z = 64;
1288 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);
1293 iup0(Hint *h, int ip, int iq, int i, int e)
1299 if(g->ptorg[ip].y == g->ptorg[iq].y)
1301 g->pt[i].y = g->ptorg[i].y + g->pt[iq].y - g->ptorg[iq].y;
1304 z = (g->ptorg[i].y - g->ptorg[iq].y) * 64 / (g->ptorg[ip].y - g->ptorg[iq].y);
1306 else if(z > 64) z = 64;
1307 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);
1316 void (*iupp)(Hint *, int, int, int, int);
1318 iupp = (h->ip[-1] & 1) != 0 ? iup1 : iup0;
1319 for(i = 0; i < h->g->ncon; i++){
1321 for(j = h->g->confst[i]; j < h->g->confst[i+1]; j++){
1323 if((p->flags & TOUCHY>>(h->ip[-1]&1)) != 0){
1327 iupp(h, t1, j, t1 + 1, j - 1);
1332 iupp(h, t1, t0, h->g->confst[i], t0 - 1);
1333 iupp(h, t1, t0, t1 + 1, h->g->confst[i+1]-1);
1335 iupp(h, t0, t0, h->g->confst[i], h->g->confst[i+1]-1);
1338 for(i = 0; i < h->g->npt; i++)
1339 dprint("%d: %+π\n", i, h->g->pt[i]);
1349 herror(h, "SLOOP invalid argument %d", n);
1361 p = getpoint(h, ZP2, pi);
1362 n = forceproject(h, p, d);
1363 setpoint(h, ZP2, pi, n);
1374 herror(h, "FLIPRG without glyph");
1376 if((int)i < h->g->npt)
1377 h->g->pt[i].flags = h->g->pt[i].flags & ~1 | h->ip[-1] & 1;
1383 int a0i, a1i, b0i, b1i, pi;
1384 TTPoint a0, a1, b0, b1, p;
1396 a0 = getpoint(h, ZP0, a0i);
1397 a1 = getpoint(h, ZP0, a1i);
1398 b0 = getpoint(h, ZP1, b0i);
1399 b1 = getpoint(h, ZP1, b1i);
1400 p = getpoint(h, ZP2, pi);
1403 n0c = (vlong)n0x * a0.x + (vlong)n0y * a0.y;
1406 n1c = (vlong)n1x * b0.x + (vlong)n1y * b0.y;
1407 Δ = (vlong)n1x * n0y - (vlong)n0x * n1y;
1409 p.x = ((a0.x + a1.x) / 2 + (b0.x + b1.x) / 2) / 2;
1410 p.y = ((a0.y + a1.y) / 2 + (b0.y + b1.y) / 2) / 2;
1412 p.x = vrounddiv(n0y * n1c - n1y * n0c, Δ);
1413 p.y = vrounddiv(n1x * n0c - n0x * n1c, Δ);
1416 setpoint(h, ZP2, pi, p);
1428 if((h->ip[-1] & 1) != 0){
1429 rp = getpoint(h, RP1|ZP0, 0);
1430 orp = getpoint(h, RP1|ZP0|ORIG, 0);
1432 rp = getpoint(h, RP2|ZP1, 0);
1433 orp = getpoint(h, RP2|ZP1|ORIG, 0);
1436 d = project(h, &rp, &orp);
1437 for(i = 0; i < h->f->loop; i++){
1439 p = getpoint(h, ZP2, pi);
1440 dp = project(h, &p, nil);
1441 n = forceproject(h, p, dp + d);
1442 setpoint(h, ZP2, pi, n);
1456 if((h->ip[-1] & 1) != 0){
1458 if(((h->f->zp ^ h->f->zp >> 2) & 1) != 0)
1460 rp = getpoint(h, RP1|ZP0, 0);
1461 orp = getpoint(h, RP1|ZP0|ORIG, 0);
1464 if(((h->f->zp ^ h->f->zp >> 1) & 1) != 0)
1466 rp = getpoint(h, RP2|ZP1, 0);
1467 orp = getpoint(h, RP2|ZP1|ORIG, 0);
1471 herror(h, "SHC[] outside of glyf program");
1472 if((uint)c >= h->g->ncon)
1473 herror(h, "contour %d out of range", c);
1474 d = project(h, &rp, &orp);
1475 for(i = h->g->confst[c]; i < h->g->confst[c+1]; i++){
1476 if(i == rpi) continue;
1477 p = getpoint(h, ZP2, i);
1478 dp = project(h, &p, nil);
1479 n = forceproject(h, p, dp + d);
1480 setpoint(h, ZP2, i, n);
1492 if((h->ip[-1] & 1) != 0){
1493 rp = getpoint(h, RP1|ZP0, 0);
1494 orp = getpoint(h, RP1|ZP0|ORIG, 0);
1496 rp = getpoint(h, RP2|ZP1, 0);
1497 orp = getpoint(h, RP2|ZP1|ORIG, 0);
1501 herror(h, "SHZ[] with invalid zone %d", e);
1502 d = project(h, &rp, &orp);
1503 np = e ? h->g->npt : h->f->u->maxTwilightPoints;
1504 for(i = 0; i < np; i++){
1505 p = getpointz(h, e, i);
1506 dp = project(h, &p, nil);
1507 n = forceproject(h, p, dp + d);
1508 setpointz(h, e, i, n);
1512 static void (*itable[256])(Hint *) = {
1513 [0x00] h_svtca, h_svtca, h_svtca, h_svtca, h_svtca, h_svtca,
1514 [0x06] h_sxvtl, h_sxvtl, h_sxvtl, h_sxvtl,
1521 [0x10] h_srp, h_srp, h_srp,
1522 [0x13] h_szp, h_szp, h_szp, h_szp,
1524 [0x18] h_roundst, h_roundst,
1541 [0x2e] h_mdap, h_mdap,
1542 [0x30] h_iup, h_iup,
1543 [0x32] h_shp, h_shp,
1544 [0x34] h_shc, h_shc,
1545 [0x36] h_shz, h_shz,
1548 [0x3a] h_msirp, h_msirp,
1551 [0x3e] h_miap, h_miap,
1558 [0x46] h_gc0, h_gc1,
1560 [0x49] h_md0, h_md1,
1562 [0x4d] h_fliponoff, h_fliponoff,
1564 [0x50] h_binop, h_binop, h_binop, h_binop, h_binop, h_binop,
1565 [0x56] h_unop, h_unop,
1567 [0x59] h_nop, /* endif */
1568 [0x5a] h_binop, h_binop,
1573 [0x60] h_binop, h_binop, h_binop, h_binop, h_unop, h_unop, h_unop, h_unop,
1574 [0x68] h_unop, h_unop, h_unop, h_unop, h_nop, h_nop, h_nop, h_nop,
1576 [0x71] h_deltap, h_deltap,
1577 [0x73] h_deltac, h_deltac, h_deltac,
1578 [0x76] h_sround, h_sround,
1579 [0x78] h_jrcond, h_jrcond,
1581 [0x7c] h_roundst, h_roundst,
1584 [0x81] h_fliprg, h_fliprg,
1586 [0x86] h_sdpvtl, h_sdpvtl,
1589 [0x8b] h_binop, h_binop,
1592 [0xb0] h_pushb, h_pushb, h_pushb, h_pushb,
1593 h_pushb, h_pushb, h_pushb, h_pushb,
1594 [0xb8] h_pushw, h_pushw, h_pushw, h_pushw,
1595 h_pushw, h_pushw, h_pushw, h_pushw,
1596 [0xc0] h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp,
1597 h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp,
1598 h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp,
1599 h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp, h_mdrp,
1600 [0xe0] h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp,
1601 h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp,
1602 h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp,
1603 h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp, h_mirp,
1611 p = va_arg(f->args, TTPoint);
1612 if((f->flags & FmtSign) != 0)
1613 return fmtprint(f, "(%.2f,%.2f,%d)", (float)p.x/64, (float)p.y/64, p.flags);
1615 return fmtprint(f, "(%d,%d,%d)", p.x, p.y, p.flags);
1621 while(h->ip < h->ehint){
1622 if(debug) debugprint(h, 0);
1623 if(itable[*h->ip] == nil)
1624 sysfatal("unknown hint instruction %#.2x", *h->ip);
1626 itable[*h->ip++](h);
1631 runpg(TTFont *f, TTGlyph *g, uchar *buf, int n)
1636 if(debug && !didfmt){
1637 fmtinstall(L'π', pointfmt);
1640 memset(&h, 0, sizeof(Hint));
1641 if(setjmp(h.jmp) != 0){
1642 errstr(h.err, sizeof(h.err));
1647 h.stack = f->hintstack;
1648 h.nstack = f->u->maxStackElements;
1649 h.ip = h.shint = buf;
1660 if((g->font->defstate.instctrl & 1<<1) != 0)
1663 if((g->font->defstate.instctrl & 1<<2) != 0)
1664 g->font->TTGState = defstate;
1666 g->font->TTGState = g->font->defstate;
1667 rc = runpg(g->font, g, g->hint, g->nhint);
1668 if(debug && rc >= 0){
1669 for(i = 0; i < g->npt; i++)
1670 dprint("%d: %+π\n", i, g->pt[i]);
1676 ttfrunfpgm(TTFont *f)
1681 f->TTGState = defstate;
1682 f->defstate = defstate;
1683 len = ttfgototable(f->u, "fpgm");
1686 buf = mallocz(len, 1);
1689 Bread(f->u->bin, buf, len);
1691 rc = runpg(f, nil, buf, len);
1697 ttfruncvt(TTFont *f)
1702 f->TTGState = defstate;
1703 f->defstate = defstate;
1704 len = ttfgototable(f->u, "prep");
1707 buf = mallocz(len, 1);
1710 Bread(f->u->bin, buf, len);
1712 rc = runpg(f, nil, buf, len);
1729 f->defstate = f->TTGState;