8 ttfparsekern(TTFontU *f)
10 u16int ver, len, cov, ntab;
13 if(ttfgototable(f, "kern") < 0)
15 ttfunpack(f, "ww", &ver, &ntab);
20 for(i = 0; i < ntab; i++){
21 ttfunpack(f, "www", &ver, &len, &cov);
22 if((cov & 1) != 0) break;
23 Bseek(f->bin, len - 6, 1);
25 ttfunpack(f, "w6", &len);
27 f->kern = mallocz(sizeof(TTKern) * len, 1);
28 for(i = 0; i < len; i++)
29 ttfunpack(f, "lS", &f->kern[i].idx, &f->kern[i].val);
34 ttfkern(TTFont *f, int l, int r)
46 if(u->kern[a].idx > idx || u->kern[b].idx < idx)
50 if(u->kern[c].idx < idx){
52 }else if(u->kern[c].idx > idx){
55 return ttfrounddiv(u->kern[c].val * f->ppem, u->emsize);
79 addglyph(Render *r, char *p, TTGlyph *g)
84 if(r->nglyph >= r->aglyph){
86 v = realloc(r->glyph, sizeof(TTGlyph *) * r->aglyph);
87 if(v == nil) return -1;
89 v = realloc(r->gwidth, sizeof(int) * r->aglyph);
90 if(v == nil) return -1;
92 v = realloc(r->cpos, sizeof(char *) * r->aglyph);
93 if(v == nil) return -1;
96 r->glyph[r->nglyph] = g;
97 r->cpos[r->nglyph] = p;
98 r->gwidth[r->nglyph] = g->advanceWidthpx;
100 k = ttfkern(r->font, r->glyph[r->nglyph-1]->idx, g->idx);
101 r->gwidth[r->nglyph-1] += k;
105 r->linew += r->gwidth[r->nglyph-1];
106 if(g->idx == r->spcidx)
112 flushglyphs(Render *r, int justify)
116 int adj, spcw, nspc, c;
120 if((r->flags & TTFMODE) == TTFLALIGN && !justify)
121 while(r->nglyph > 0 && r->glyph[r->nglyph - 1]->idx == r->spcidx){
122 r->linew -= r->gwidth[--r->nglyph];
128 adj = (nspc * r->spcminus + 63) / 64;
129 if(r->linew - adj > r->b->width){
131 while(n > 0 && r->glyph[n - 1]->idx != r->spcidx)
132 llen -= r->gwidth[--n];
134 while(n > 0 && r->glyph[n - 1]->idx == r->spcidx){
135 llen -= r->gwidth[--n];
139 while(n < r->nglyph && llen + r->gwidth[n] < r->b->width)
140 llen += r->gwidth[n++];
148 spcw = (r->b->width - llen + nspc * r->spcw) * 64 / nspc;
151 switch(r->flags & TTFMODE | justify * TTFJUSTIFY){
153 x = r->b->width - llen;
156 x = (r->b->width - llen)/2;
161 y = r->oy + f->ascentpx;
163 for(i = 0; i < k; i++){
164 if(r->glyph[i]->idx == r->spcidx){
170 ttfblit(r->b, x + r->glyph[i]->xminpx, y - r->glyph[i]->ymaxpx, r->glyph[i], 0, 0, r->glyph[i]->width, r->glyph[i]->height);
173 r->linew -= r->gwidth[i];
174 ttfputglyph(r->glyph[i]);
177 r->pp = r->cpos[n-1];
179 memmove(r->glyph, r->glyph + k, (r->nglyph - k) * sizeof(TTGlyph *));
180 memmove(r->cpos, r->cpos + k, (r->nglyph - k) * sizeof(char *));
181 memmove(r->gwidth, r->gwidth + k, (r->nglyph - k) * sizeof(int));
186 _ttfrender(TTFont *f, int (*getrune)(Rune *, char *), char *p, char *end, int w, int h, int flags, char **rp)
193 if(rp != nil) *rp = p;
194 if(f->u->nkern < 0 && ttfparsekern(f->u) < 0)
196 memset(&r, 0, sizeof(Render));
199 r.b = ttfnewbitmap(w, h);
200 if(r.b == nil) goto error;
202 r.lh = f->ascentpx + f->descentpx;
205 g = ttfgetglyph(f, ttffindchar(f, ' '), 1);
207 r.spcw = g->advanceWidthpx;
208 if((flags & TTFJUSTIFY) != 0)
209 r.spcminus = r.spcw * 21;
213 while(p < end && r.oy + r.lh < h){
214 p += getrune(&ch, p);
219 g = ttfgetglyph(f, ttffindchar(f, ch), 1);
221 g = ttfgetglyph(f, 0, 1);
225 if(addglyph(&r, p, g) < 0)
227 adj = (r.nspc * r.spcminus + 63) / 64;
228 if(r.linew - adj > r.b->width){
229 flushglyphs(&r, (flags & TTFJUSTIFY) != 0);
234 for(i = 0; i < r.nglyph; i++)
235 ttfputglyph(r.glyph[i]);
250 ttfrender(TTFont *f, char *str, char *end, int w, int h, int flags, char **rstr)
255 end = str + strlen(str);
256 return _ttfrender(f, chartorune, str, end, w, h, flags, rstr);
260 incrune(Rune *r, char *s)
267 ttfrunerender(TTFont *f, Rune *str, Rune *end, int w, int h, int flags, Rune **rstr)
272 end = str + runestrlen(str);
273 return _ttfrender(f, incrune, (char *) str, (char *) end, w, h, flags, (char **) rstr);