10 ttfunpack(TTFontU *f, char *p, ...)
22 p1 = va_arg(va, u8int *);
26 p4 = va_arg(va, u32int *);
30 p2 = va_arg(va, u16int *);
31 *p2 = Bgetc(f->bin) << 8;
35 p4 = va_arg(va, u32int *);
36 *p4 = Bgetc(f->bin) << 8;
40 p4 = va_arg(va, u32int *);
41 *p4 = (char)Bgetc(f->bin) << 8;
45 p4 = va_arg(va, u32int *);
46 *p4 = Bgetc(f->bin) << 24;
47 *p4 |= Bgetc(f->bin) << 16;
48 *p4 |= Bgetc(f->bin) << 8;
51 case '.': Bgetc(f->bin); break;
55 n = strtol(p, &p, 10);
69 ttfunpack(f, "lw .. .. ..", &scaler, &f->ntab);
70 if(scaler != 0x74727565 && scaler != 0x10000){
71 werrstr("unknown scaler type %#ux", scaler);
74 f->tab = mallocz(sizeof(TTTable) * f->ntab, 1);
75 if(f->tab == nil) return -1;
76 for(i = 0; i < f->ntab; i++)
77 ttfunpack(f, "llll", &f->tab[i].tag, &f->tab[i].csum, &f->tab[i].offset, &f->tab[i].len);
82 ttfgototable(TTFontU *f, char *str)
87 tag = (u8int)str[0] << 24 | (u8int)str[1] << 16 | (u8int)str[2] << 8 | (u8int)str[3];
88 for(t = f->tab; t < f->tab + f->ntab; t++)
90 Bseek(f->bin, t->offset, 0);
93 werrstr("no such table '%s'", str);
98 ttfparseloca(TTFontU *f)
103 len = ttfgototable(f, "loca");
104 if(len < 0) return -1;
107 if(len > (f->numGlyphs + 1) * 4) len = (f->numGlyphs + 1) * 4;
108 for(i = 0; i < len/4; i++){
109 x = Bgetc(f->bin) << 24;
110 x |= Bgetc(f->bin) << 16;
111 x |= Bgetc(f->bin) << 8;
113 f->ginfo[i].loca = x;
116 if(len > (f->numGlyphs + 1) * 2) len = (f->numGlyphs + 1) * 2;
117 for(i = 0; i < len/2; i++){
118 x = Bgetc(f->bin) << 8;
120 f->ginfo[i].loca = x * 2;
123 for(; i < f->numGlyphs; i++)
124 f->ginfo[i].loca = x;
129 ttfparsehmtx(TTFontU *f)
136 len = ttfgototable(f, "hmtx");
139 if(f->numOfLongHorMetrics > f->numGlyphs){
140 werrstr("nonsensical header: numOfLongHorMetrics > numGlyphs");
143 for(i = 0; i < f->numOfLongHorMetrics; i++){
144 ttfunpack(f, "ww", &x, &y);
145 f->ginfo[i].advanceWidth = x;
148 maxlsb = (len - 2 * f->numOfLongHorMetrics) / 2;
149 if(maxlsb > f->numGlyphs){
150 werrstr("nonsensical header: maxlsb > f->numGlyphs");
153 for(; i < maxlsb; i++){
154 ttfunpack(f, "w", &y);
155 f->ginfo[i].advanceWidth = x;
158 for(; i < f->numGlyphs; i++){
159 f->ginfo[i].advanceWidth = x;
166 ttfparsecvt(TTFontU *f)
174 len = ttfgototable(f, "cvt ");
175 if(len <= 0) return 0;
176 f->cvtu = mallocz(len, 1);
177 if(f->cvtu == 0) return -1;
178 Bread(f->bin, f->cvtu, len);
179 p = (u8int *) f->cvtu;
182 for(i = 0; i < f->ncvtu; i++){
183 x = (short)(p[0] << 8 | p[1]);
191 ttfparseos2(TTFontU *f)
194 u16int usWinAscent, usWinDescent;
196 len = ttfgototable(f, "OS/2 ");
200 werrstr("OS/2 table too short");
203 ttfunpack(f, "68 6 ww", &usWinAscent, &usWinDescent);
204 f->ascent = usWinAscent;
205 f->descent = usWinDescent;
210 ttfcloseu(TTFontU *u)
216 for(i = 0; i < u->ncmap; i++)
217 free(u->cmap[i].tab);
233 for(i = 0; i < f->u->maxFunctionDefs; i++)
234 free(f->func[i].pgm);
245 ttfscaleu(TTFontU *u, int ppem)
250 f = mallocz(sizeof(TTFont), 1);
251 if(f == nil) return nil;
256 f->cvt = malloc(sizeof(int) * u->ncvtu);
257 if(f->cvt == nil) goto error;
258 for(i = 0; i < u->ncvtu; i++)
259 f->cvt[i] = ttfrounddiv(u->cvtu[i] * ppem * 64, u->emsize);
260 f->hintstack = mallocz(sizeof(u32int) * u->maxStackElements, 1);
261 f->func = mallocz(sizeof(TTFunction) * u->maxFunctionDefs, 1);
262 f->storage = mallocz(sizeof(u32int) * u->maxStorage, 1);
263 f->twilight = mallocz(sizeof(TTPoint) * u->maxTwilightPoints, 1);
264 f->twiorg = mallocz(sizeof(TTPoint) * u->maxTwilightPoints, 1);
265 if(f->hintstack == nil || f->func == nil || f->storage == nil || f->twilight == nil || f->twiorg == nil) goto error;
266 f->ascentpx = (u->ascent * ppem + u->emsize - 1) / (u->emsize);
267 f->descentpx = (u->descent * ppem + u->emsize - 1) / (u->emsize);
268 if(ttfrunfpgm(f) < 0) goto error;
269 if(ttfruncvt(f) < 0) goto error;
278 ttfopen(char *name, int ppem, int)
284 werrstr("invalid ppem argument");
287 b = Bopen(name, OREAD);
290 u = mallocz(sizeof(TTFontU), 1);
295 if(directory(u) < 0) goto error;
296 if(ttfgototable(u, "head") < 0) goto error;
297 ttfunpack(u, "16 w W 16 wwww 6 w", &u->flags, &u->emsize, &u->xmin, &u->ymin, &u->xmax, &u->ymax, &u->longloca);
298 if(ttfgototable(u, "maxp") < 0) goto error;
299 ttfunpack(u, "4 wwwwwwwwwwwwww",
300 &u->numGlyphs, &u->maxPoints, &u->maxCountours, &u->maxComponentPoints, &u->maxComponentCountours,
301 &u->maxZones, &u->maxTwilightPoints, &u->maxStorage, &u->maxFunctionDefs, &u->maxInstructionDefs,
302 &u->maxStackElements, &u->maxSizeOfInstructions, &u->maxComponentElements, &u->maxComponentDepth);
303 u->ginfo = mallocz(sizeof(TTGlyphInfo) * (u->numGlyphs + 1), 1);
306 if(ttfgototable(u, "hhea") < 0) goto error;
307 ttfunpack(u, "10 wwww 16 w", &u->advanceWidthMax, &u->minLeftSideBearing, &u->minRightSideBearing, &u->xMaxExtent, &u->numOfLongHorMetrics);
308 if(ttfparseloca(u) < 0) goto error;
309 if(ttfparsehmtx(u) < 0) goto error;
310 if(ttfparsecvt(u) < 0) goto error;
311 if(ttfparsecmap(u) < 0) goto error;
312 if(ttfparseos2(u) < 0) goto error;
313 return ttfscaleu(u, ppem);
321 ttfscale(TTFont *f, int ppem, int)
323 return ttfscaleu(f->u, ppem);
327 ttfrounddiv(int a, int b)
329 if(b < 0){ a = -a; b = -b; }
331 return (a + b/2) / b;
333 return (a - b/2) / b;
337 ttfvrounddiv(vlong a, int b)
339 if(b < 0){ a = -a; b = -b; }
341 return (a + b/2) / b;
343 return (a - b/2) / b;