7 typedef struct Scan Scan;
8 typedef struct TTLine TTLine;
44 dobezier(Scan *s, TTPoint p, TTPoint q, TTPoint r)
49 m = (vlong)(q.x - p.x) * (r.y - p.y) - (vlong)(q.y - p.y) * (r.x - p.x);
50 n = (vlong)(r.x - p.x) * (r.x - p.x) + (vlong)(r.y - p.y) * (r.y - p.y);
52 dobezier(s, p, (TTPoint){(p.x+q.x+1)/2, (p.y+q.y+1)/2, 0}, (TTPoint){(p.x+2*q.x+r.x+2)/4, (p.y+2*q.y+r.y+2)/4, 0});
53 dobezier(s, (TTPoint){(p.x+2*q.x+r.x+2)/4, (p.y+2*q.y+r.y+2)/4, 0}, (TTPoint){(r.x+q.x+1)/2, (r.y+q.y+1)/2, 0}, r);
56 if((s->nlines & LINEBLOCK - 1) == 0)
57 s->lines = realloc(s->lines, sizeof(TTLine) * (s->nlines + LINEBLOCK));
58 l = &s->lines[s->nlines++];
76 hlinecmp(void *va, void *vb)
82 if(a->y0 < b->y0) return -1;
83 if(a->y0 > b->y0) return 1;
88 vlinecmp(void *va, void *vb)
94 if(a->x0 < b->x0) return -1;
95 if(a->x0 > b->x0) return 1;
100 intcmp(void *va, void *vb)
106 return (a>b) - (a<b);
116 qsort(s->lines, s->nlines, sizeof(TTLine), hlinecmp);
117 s->hscanl = calloc(sizeof(int), (s->height + 1));
121 for(i = 0; i < s->height; i++){
123 for(; watch < s->nlines && s->lines[watch].y0 <= y; watch++){
124 if(s->lines[watch].y1 <= y || s->lines[watch].y0 == s->lines[watch].y1)
126 s->lines[watch].link = -1;
128 p = &s->lines[watch].link;
130 s->hscanl[i] = s->nhpts;
132 while(j = *p, j >= 0){
140 x = l->x0 + ttfvrounddiv((vlong)(y - l->y0)*(l->x1 - l->x0), l->y1 - l->y0);
141 if((s->nhpts & PTBLOCK - 1) == 0)
142 s->hpts = realloc(s->hpts, (s->nhpts + PTBLOCK) * sizeof(int));
143 s->hpts[s->nhpts++] = x << 1 | l->dir;
146 qsort(s->hpts + s->hscanl[i], s->nhpts - s->hscanl[i], sizeof(int), intcmp);
148 s->hscanl[i] = s->nhpts;
152 iswhite(Scan *s, int x, int y)
154 return (s->bit[(s->height - 1 - y) * s->stride + (x>>3)] >> 7-(x&7) & 1)==0;
158 pixel(Scan *s, int x, int y)
160 assert(x >= 0 && x < s->width && y >= 0 && y < s->height);
161 s->bit[(s->height - 1 - y) * s->stride + (x>>3)] |= (1<<7-(x&7));
165 intersectsh(Scan *s, int x, int y)
170 b = s->hscanl[y+1]-1;
172 if(a > b || s->hpts[a]>>1 > v + 64 || s->hpts[b]>>1 < v) return 0;
187 intersectsv(Scan *s, int x, int y)
192 b = s->vscanl[x+1]-1;
194 if(a > b || s->vpts[a]>>1 > v + 64 || s->vpts[b]>>1 < v) return 0;
212 int wind, match, seen, x;
214 for(i = 0; i < s->height; i++){
219 for(j = 0; j < s->width; j++){
223 while(k < e && (s->hpts[k] >> 1) <= x){
224 wind += (s->hpts[k] & 1) * 2 - 1;
225 seen |= 1<<(s->hpts[k] & 1);
226 if((s->hpts[k] >> 1) == x)
232 else if((s->flags & DROPOUTS) != 0 && seen == 3 && j > 0 && iswhite(s, j-1, i)){
233 if((s->flags & STUBDET) == 0){
237 if(i <= 0 || i > s->height - 1 || j <= 0 || j > s->width - 1)
239 if(!intersectsv(s, j-1, i-1) && !intersectsh(s, j-1, i-1) && !intersectsv(s, j, i-1) || !intersectsv(s, j-1, i) && !intersectsh(s, j-1, i+1) && !intersectsv(s, j, i))
254 for(i = 0; i < s->nlines; i++){
257 x = l->x0, l->x0 = l->x1, l->x1 = x;
258 x = l->y0, l->y0 = l->y1, l->y1 = x;
262 qsort(s->lines, s->nlines, sizeof(TTLine), vlinecmp);
263 s->vscanl = calloc(sizeof(int), (s->width + 1));
267 for(i = 0; i < s->width; i++){
269 for(; watch < s->nlines && s->lines[watch].x0 <= x; watch++){
270 if(s->lines[watch].x1 <= x || s->lines[watch].x0 == s->lines[watch].x1)
272 s->lines[watch].link = -1;
274 p = &s->lines[watch].link;
276 s->vscanl[i] = s->nvpts;
278 while(j = *p, j >= 0){
286 y = l->y0 + ttfvrounddiv((vlong)(x - l->x0) * (l->y1 - l->y0), l->x1 - l->x0);
287 if((s->nvpts & PTBLOCK - 1) == 0)
288 s->vpts = realloc(s->vpts, (s->nvpts + PTBLOCK) * sizeof(int));
289 s->vpts[s->nvpts++] = y << 1 | l->dir;
292 qsort(s->vpts + s->vscanl[i], s->nvpts - s->vscanl[i], sizeof(int), intcmp);
294 s->vscanl[i] = s->nvpts;
304 for(i = 0; i < s->width; i++){
308 for(j = 0; j < s->height; j++){
311 while(k < e && (s->vpts[k] >> 1) <= y){
312 seen |= 1<<(s->vpts[k] & 1);
315 if(seen == 3 && j > 0 && iswhite(s, i, j-1) && iswhite(s, i, j)){
316 if((s->flags & STUBDET) == 0){
320 if(i <= 0 || i > s->width - 1 || j <= 0 || j > s->height - 1)
322 if(!intersectsv(s, i-1, j-1) & !intersectsh(s, i-1, j-1) & !intersectsh(s, i-1, j) | !intersectsv(s, i+1, j-1) & !intersectsh(s, i, j-1) & !intersectsh(s, i, j))
337 memset(&s, 0, sizeof(s));
340 c = g->font->scanctrl;
341 if((c & 1<<8) != 0 && g->font->ppem <= (c & 0xff))
343 if((c & 1<<11) != 0 && g->font->ppem > (c & 0xff))
344 s.flags &= ~DROPOUTS;
346 s.flags &= ~DROPOUTS;
347 if((s.flags & DROPOUTS) != 0)
348 switch(g->font->scantype){
350 case 1: s.flags |= STUBDET; break;
351 case 2: case 3: case 6: case 7: s.flags &= ~DROPOUTS; break;
352 case 4: s.flags |= SMART; break;
353 case 5: s.flags |= SMART | STUBDET; break;
356 // s.width = (g->pt[g->npt - 1].x + 63) / 64;
357 // s.height = g->font->ascentpx + g->font->descentpx;
358 s.width = -g->xminpx + g->xmaxpx;
359 s.height = -g->yminpx + g->ymaxpx;
360 s.stride = s.width + 7 >> 3;
361 s.bit = mallocz(s.height * s.stride, 1);
362 assert(s.bit != nil);
363 for(i = 0; i < g->npt; i++){
364 g->pt[i].x -= g->xminpx * 64;
365 g->pt[i].y -= g->yminpx * 64;
366 // g->pt[i].y += g->font->descentpx * 64;
368 for(i = 0; i < g->ncon; i++){
369 if(g->confst[i] + 1 >= g->confst[i+1]) continue;
370 p = g->pt[g->confst[i]];
371 assert((p.flags & 1) != 0);
372 for(j = g->confst[i]; j++ < g->confst[i+1]; ){
373 if(j < g->confst[i+1] && (g->pt[j].flags & 1) == 0)
377 if(j >= g->confst[i+1])
378 r = g->pt[g->confst[i]];
381 if((g->pt[j].flags & 1) == 0){
382 r.x = (r.x + q.x) / 2;
383 r.y = (r.y + q.y) / 2;
386 dobezier(&s, p, q, r);
388 if(j < g->confst[i+1] && (g->pt[j].flags & 1) == 0)
393 if((s.flags & DROPOUTS) != 0)
396 if((s.flags & DROPOUTS) != 0)
405 g->height = s.height;
406 g->stride = s.stride;
410 ttfgetcontour(TTGlyph *g, int i, float **fp, int *np)
412 float offx, offy, scale;
417 if((uint)i >= g->ncon)
419 if(g->confst[i]+1 >= g->confst[i+1]){
431 scale = 1.0f * g->font->ppem / g->font->u->emsize;
435 p = g->pt[g->confst[i]];
438 *fp = malloc(2 * sizeof(float));
439 if(*fp == nil) return -1;
440 (*fp)[0] = p.x * scale;
441 (*fp)[1] = p.y * scale + offy;
443 assert((p.flags & 1) != 0);
444 for(j = g->confst[i]; j++ < g->confst[i+1]; ){
445 if(j < g->confst[i+1] && (g->pt[j].flags & 1) == 0)
449 if(j >= g->confst[i+1])
450 r = g->pt[g->confst[i]];
453 if((g->pt[j].flags & 1) == 0){
454 r.x = (r.x + q.x) / 2;
455 r.y = (r.y + q.y) / 2;
459 nf = realloc(*fp, sizeof(float) * 2 * (n + 2));
465 nf[2*n] = q.x * scale;
466 nf[2*n+1] = q.y * scale + offy;
467 nf[2*n+2] = r.x * scale;
468 nf[2*n+3] = r.y * scale + offy;
472 if(j < g->confst[i+1] && (g->pt[j].flags & 1) == 0)