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