1 /* glyf.c -- Load and print Glyf outline data
2 * Copyright (C) 1996 Li-Da Lho, All right reserved
3 */
4 #ifdef HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "ttf.h"
12 #include "ttfutil.h"
13
14 /* $Id: glyf.c,v 1.1.1.1 1998/06/05 07:47:52 robert Exp $ */
15
16 static void ttfLoadSimpleGlyph(FILE *fp,GLYFPtr glyf,ULONG offset);
17 static void ttfPrintSimpleGlyph(FILE *fp,GLYFPtr glyf);
18 static void ttfLoadCompositeGlyph(FILE *fp,GLYFPtr glyf,ULONG offset);
19 static void ttfPrintCompositeGlyph(FILE*fp,GLYFPtr glyf);
20 static void ttfFreeCompositeGlyph(GLYFPtr glyf);
21 double fix2dbl(F2Dot14 fixed);
22
23 /* Naming convention about GLYF and Glyph:
24 * High level functions which are exported should have their name
25 * contain GLYF, on the other hand, low level function (or structures)
26 * which is not intended to be exported should have their name
27 * contain Glyph
28 */
ttfInitGLYF(TTFontPtr font)29 void ttfInitGLYF(TTFontPtr font)
30 {
31 ULONG tag = FT_MAKE_TAG ('g', 'l', 'y', 'f');
32 TableDirPtr ptd;
33
34 if ((ptd = ttfLookUpTableDir(tag, font)) != NULL)
35 {
36 font->glyphOffset = ptd->offset;
37 }
38 }
39 /* offset: where the specified glyph really starts
40 * callers should compute this themself form the loca tables */
ttfLoadGLYF(FILE * fp,GLYFPtr glyf,ULONG offset)41 void ttfLoadGLYF(FILE *fp, GLYFPtr glyf, ULONG offset)
42 {
43 xfseek(fp, offset, SEEK_SET, "ttfLoadGLYF");
44
45 glyf->numberOfContours = ttfGetSHORT(fp);
46 glyf->xMin = ttfGetFWord(fp);
47 glyf->yMin = ttfGetFWord(fp);
48 glyf->xMax = ttfGetFWord(fp);
49 glyf->yMax = ttfGetFWord(fp);
50
51 offset += sizeof(USHORT) + 4*sizeof(FWord);
52
53 if (glyf->numberOfContours >= 0)
54 ttfLoadSimpleGlyph(fp, glyf, offset);
55 else
56 ttfLoadCompositeGlyph(fp, glyf, offset);
57 }
ttfPrintGLYF(FILE * fp,GLYFPtr glyf)58 void ttfPrintGLYF(FILE *fp, GLYFPtr glyf)
59 {
60 fprintf(fp,"\t numberOfContours:\t %d%s\n", glyf->numberOfContours,
61 glyf->numberOfContours == -1 ? " (Composite)": "");
62 fprintf(fp,"\t xMin:\t\t\t %d\n", glyf->xMin);
63 fprintf(fp,"\t yMin:\t\t\t %d\n", glyf->yMin);
64 fprintf(fp,"\t xMax:\t\t\t %d\n", glyf->xMax);
65 fprintf(fp,"\t yMax:\t\t\t %d\n\n", glyf->yMax);
66
67 if (glyf->numberOfContours >= 0)
68 ttfPrintSimpleGlyph(fp, glyf);
69 else
70 ttfPrintCompositeGlyph(fp, glyf);
71 }
ttfFreeGLYF(GLYFPtr glyf)72 void ttfFreeGLYF(GLYFPtr glyf)
73 {
74 if (glyf->numberOfContours < 0)
75 ttfFreeCompositeGlyph(glyf);
76 }
ttfLoadSimpleGlyph(FILE * fp,GLYFPtr glyf,ULONG offset)77 static void ttfLoadSimpleGlyph(FILE *fp, GLYFPtr glyf, ULONG offset)
78 {
79 SHORT nCnts = glyf->numberOfContours;
80 USHORT i,nIns,nPts;
81
82 xfseek(fp, offset, SEEK_SET, "ttfLoadSimpleGlyph");
83
84 if (nCnts != 0)
85 {
86 ttfReadUSHORT (glyf->endPtsOfContours, nCnts, fp);
87 nPts = (glyf->endPtsOfContours)[nCnts-1]+1;
88 }
89 else
90 /* there seems to be something wrong with my interpretation of
91 * NOGLYPH chars, doing this way in case there is a char that has
92 * zero contour */
93 nPts = 0;
94
95 /* how to deal with zero instruction glyf properly ?? */
96 glyf->instructionLength = nIns = ttfGetUSHORT(fp);
97 if (nIns != 0)
98 {
99 if (fread(glyf->instructions, sizeof(BYTE), nIns, fp) != nIns)
100 ttfError("Error when getting instructions\n");
101 }
102
103 for (i=0;i<nPts;i++)
104 {
105 BYTE j,c;
106 if (((glyf->flags)[i] = c = ttfGetBYTE(fp)) & FLAGS_REPEAT)
107 { /* if this flag should be repeated */
108 j = ttfGetBYTE(fp); /* j times */
109 while (j--)
110 {
111 i++;
112 (glyf->flags)[i] = c;
113
114 }
115 }
116 }
117
118 for (i=0;i<nPts;i++)
119 {
120 BYTE flag;
121 flag = (glyf->flags)[i];
122
123 if (flag & FLAGS_X_SHORT_VECTOR)
124 { /* if the coordinate is a BYTE */
125 if (flag & FLAGS_X_SAME)
126 (glyf->xCoordinates)[i] = (SHORT) ttfGetBYTE(fp);
127 else
128 (glyf->xCoordinates)[i] = (SHORT) -ttfGetBYTE(fp);
129 }
130 else
131 { /* the coordiante is a SHORT */
132 if (flag & FLAGS_X_SAME)
133 (glyf->xCoordinates)[i] = 0;
134 else
135 (glyf->xCoordinates)[i] = ttfGetSHORT(fp);
136 }
137 }
138 for (i=0;i<nPts;i++)
139 {
140 BYTE flag;
141 flag = (glyf->flags)[i];
142
143 if (flag & FLAGS_Y_SHORT_VECTOR)
144 { /* if the coordinate is a BYTE */
145 if (flag & FLAGS_Y_SAME)
146 (glyf->yCoordinates)[i] = (SHORT) ttfGetBYTE(fp);
147 else
148 (glyf->yCoordinates)[i] = (SHORT) -ttfGetBYTE(fp);
149 }
150 else
151 { /* the coordiante is a SHORT */
152 if (flag & FLAGS_Y_SAME)
153 (glyf->yCoordinates)[i] = 0;
154 else
155 (glyf->yCoordinates)[i] = ttfGetSHORT(fp);
156 }
157 }
158 }
ttfPrintSimpleGlyph(FILE * fp,GLYFPtr glyf)159 static void ttfPrintSimpleGlyph(FILE *fp, GLYFPtr glyf)
160 {
161 USHORT i, nPts, nCnts;
162 SHORT x=0, y=0;
163
164 nPts = (glyf->endPtsOfContours)[glyf->numberOfContours-1]+1;
165 nCnts = glyf->numberOfContours;
166
167 fprintf(fp,"\t EndPoints\n");
168 fprintf(fp,"\t ---------\n");
169 for (i=0;i<nCnts;i++)
170 fprintf(fp,"\t %d: %2d\n",i,(glyf->endPtsOfContours)[i]);
171 fprintf(fp,"\n");
172
173 fprintf(fp,"\t Length of Instructions: %2d\n\n",glyf->instructionLength);
174 ttfPrintInstructions(fp,glyf->instructions);
175
176 fprintf(fp,"\t Flags\n");
177 fprintf(fp,"\t -----\n");
178 for (i=0;i<nPts;i++)
179 {
180 BYTE flag;
181 char buf[80];
182
183 flag = (glyf->flags)[i];
184
185 if (flag & FLAGS_Y_SAME)
186 sprintf(buf,"YDual ");
187 else
188 sprintf(buf," ");
189 if (flag & FLAGS_X_SAME)
190 strcat(buf,"XDual ");
191 else
192 strcat(buf," ");
193 if (flag & FLAGS_REPEAT)
194 strcat(buf,"Repeat ");
195 else
196 strcat(buf," ");
197 if (flag & FLAGS_Y_SHORT_VECTOR)
198 strcat(buf,"Y-Short ");
199 else
200 strcat(buf," ");
201 if (flag & FLAGS_X_SHORT_VECTOR)
202 strcat(buf,"X-Short ");
203 else
204 strcat(buf," ");
205 if (flag & FLAGS_ON_CURVE)
206 strcat(buf,"On\n");
207 else
208 strcat(buf,"Off\n");
209
210 fprintf(fp,"\t %2d: %s",i,buf);
211 }
212 fprintf(fp,"\n");
213 fprintf(fp,"\t Coordinates\n");
214 fprintf(fp,"\t -----------\n");
215 for (i=0;i<nPts;i++)
216 {
217 x += (glyf->xCoordinates)[i];
218 y += (glyf->yCoordinates)[i];
219 fprintf(fp,"\t %2d Rel ( %6d, %6d) -> Abs ( %6d, %6d)\n", i,
220 (glyf->xCoordinates)[i], (glyf->yCoordinates)[i], x, y);
221 }
222 fprintf(fp,"\n");
223 }
224
ttfLoadCompositeGlyph(FILE * fp,GLYFPtr glyf,ULONG offset)225 static void ttfLoadCompositeGlyph(FILE *fp, GLYFPtr glyf, ULONG offset)
226 {
227 USHORT nIns,flags;
228 Component *cur;
229
230 xfseek(fp, offset, SEEK_SET, "ttfLoadCompositeGlyph");
231
232 glyf->comp = cur = XCALLOC1 (Component);
233 cur->previous = NULL; /* beginning of a linked list */
234
235 do {
236 cur->flags = flags = ttfGetUSHORT(fp);
237 cur->glyphIndex = ttfGetUSHORT(fp);
238 if (flags & ARG_1_AND_2_ARE_WORDS)
239 {
240 (cur->data).args[0] = ttfGetSHORT(fp);
241 (cur->data).args[1] = ttfGetSHORT(fp);
242 }
243 else
244 (cur->data).args[0] = ttfGetUSHORT(fp);
245
246 if (flags & WE_HAVE_A_SCALE)
247 {
248 (cur->data).transform.scale = ttfGetF2Dot14(fp);
249 }
250 else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
251 {
252 (cur->data).transform.vector.xscale = ttfGetF2Dot14(fp);
253 (cur->data).transform.vector.yscale = ttfGetF2Dot14(fp);
254 }
255 else if (flags & WE_HAVE_A_TWO_BY_TWO)
256 {
257 (cur->data).transform.tensor.xscale = ttfGetF2Dot14(fp);
258 (cur->data).transform.tensor.scale01 = ttfGetF2Dot14(fp);
259 (cur->data).transform.tensor.scale10 = ttfGetF2Dot14(fp);
260 (cur->data).transform.tensor.yscale = ttfGetF2Dot14(fp);
261 }
262 /* allocate next component */
263 cur->next = XCALLOC1 (Component);
264 cur->next->previous = cur;
265 cur = cur->next; /* move to next component */
266 } while (flags & MORE_COMPONENT);
267 cur->next = NULL; /* end of the linked list */
268
269 if (flags & WE_HAVE_INSTRUCTIONS)
270 {
271 glyf->instructionLength = nIns = ttfGetUSHORT(fp);
272 if (fread(glyf->instructions, sizeof(BYTE), nIns, fp) != nIns)
273 ttfError("Error when loading instructions\n");
274 }
275 else
276 {
277 glyf->instructionLength = 0;
278 }
279 }
ttfPrintCompositeGlyph(FILE * fp,GLYFPtr glyf)280 static void ttfPrintCompositeGlyph(FILE *fp, GLYFPtr glyf)
281 {
282 int i = 0;
283 char buf[80];
284 USHORT flags;
285 Component *cur;
286
287 cur = glyf->comp;
288
289 do {
290 flags = cur->flags;
291 fprintf(fp, "\t %d: Flags:\t 0x%x\n", i, flags);
292 fprintf(fp, "\t Glyf Index:\t %d\n", cur->glyphIndex);
293 if (flags & ARGS_ARE_XY_VALUES)
294 {
295 if (flags & ARG_1_AND_2_ARE_WORDS)
296 {
297 fprintf(fp, "\t X WOffset:\t %d\n", (cur->data).args[0]);
298 fprintf(fp, "\t Y WOffset:\t %d\n", (cur->data).args[1]);
299 }
300 else
301 {
302 fprintf(fp, "\t X BOffset:\t %d\n",
303 (signed char) ((cur->data).args[0] >> 8 & 0xff));
304 fprintf(fp, "\t Y BOffset:\t %d\n",
305 (signed char) ((cur->data).args[0] & 0xff));
306 }
307 }
308 else
309 {
310 /* what the hell are the "patch points" ?? */
311 }
312
313 if (flags & WE_HAVE_A_SCALE)
314 {
315 fprintf(fp, "\t X,Y Scale:\t %f\n",
316 fix2dbl((cur->data).transform.scale));
317 }
318 else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
319 {
320 fprintf(fp, "\t X Scale:\t %f\n",
321 fix2dbl((cur->data).transform.vector.xscale));
322 fprintf(fp, "\t Y Scale:\t %f\n",
323 fix2dbl((cur->data).transform.vector.yscale));
324 }
325 else if (flags & WE_HAVE_A_TWO_BY_TWO)
326 {
327 fprintf(fp, "\t X Scale:\t %f\n",
328 fix2dbl((cur->data).transform.tensor.xscale));
329 fprintf(fp, "\t X,Y Scale:\t %f\n",
330 fix2dbl((cur->data).transform.tensor.scale01));
331 fprintf(fp, "\t Y,X Scale:\t %f\n",
332 fix2dbl((cur->data).transform.tensor.scale10));
333 fprintf(fp, "\t Y Scale:\t %f\n",
334 fix2dbl((cur->data).transform.tensor.yscale));
335 }
336
337 if (flags & ROUND_XY_TO_GRID)
338 sprintf(buf, "Round X,Y to Grid ");
339 else
340 sprintf(buf, " ");
341
342 if (flags & NO_OVERLAP)
343 strcat(buf, "NO Overlap ");
344 else
345 strcat(buf, " ");
346
347 if (flags & USE_MY_METRICS)
348 strcat(buf, "Use My Metrics ");
349 else
350 strcat(buf, " ");
351
352 fprintf(fp, "\t Others:\t %s\n\n", buf);
353
354 i++;
355 cur = cur->next;
356 } while (cur->next != NULL);
357
358 fprintf(fp, "\n");
359
360 if (flags & WE_HAVE_INSTRUCTIONS)
361 {
362 fprintf(fp,"\t Length of Instructions: %2d\n\n",
363 glyf->instructionLength);
364 ttfPrintInstructions(fp, glyf->instructions);
365 }
366 }
ttfFreeCompositeGlyph(GLYFPtr glyf)367 static void ttfFreeCompositeGlyph(GLYFPtr glyf)
368 {
369 Component *cur,*next;
370
371 cur = glyf->comp;
372
373 do {
374 next = cur->next;
375 free(cur);
376 cur = next;
377 } while (cur != NULL);
378 }
379
380 /* what I want:
381 * outter procedures should not have any ideas about where the glyph starts,
382 *
383 * it just provide the TTFont structure and the character code or the index
384 * of that glyph. Procedures below should do:
385 * 1. look up where the glyph data is.
386 * 2. provided some glyph cache mechanism for the reason that
387 * a. it is not necessary to load all glyph into memory, especially for
388 * eastern languages.
389 * b. if a glyph data has been loaded previously, it is not necessary to
390 * load it again.
391 * c. malloc and free are SLOW !!
392 */
393 /* Load a glyph by glyph index */
ttfLoadGlyphIndex(TTFont * font,USHORT idx)394 GLYFPtr ttfLoadGlyphIndex(TTFont *font, USHORT idx)
395 {
396 ULONG pos;
397 GLYFPtr glyf;
398
399 /* compute the actual place where the glyph stored */
400 pos = font->glyphOffset + ttfLookUpGlyfLOCA(font->loca, idx);
401 glyf = ttfLoadGlyphCached(font, pos);
402
403 return glyf;
404 }
405 /* Load a glyph by character code in the current encoding scheme */
ttfLoadGlyphCode(TTFont * font,USHORT cc)406 GLYFPtr ttfLoadGlyphCode(TTFont *font,USHORT cc)
407 {
408 USHORT index;
409
410 index = ttfLookUpCMAP(font->encoding->map,cc);
411 return ttfLoadGlyphIndex(font,index);
412 }
413
fix2dbl(F2Dot14 fixed)414 double fix2dbl(F2Dot14 fixed)
415 {
416 double mantissa, fraction;
417
418 mantissa = (double) (fixed >> 14);
419
420 fraction = (double) (double)(fixed & 0x3fff) / 16384.0;
421
422 return mantissa+fraction;
423 }
424