]> git.sesse.net Git - rdpsrv/blob - Xserver/lib/font/Speedo/set_trns.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / lib / font / Speedo / set_trns.c
1 /* $XConsortium: set_trns.c,v 1.6 94/02/10 11:05:59 gildea Exp $ */
2
3 /*
4
5 Copyright 1989-1991, Bitstream Inc., Cambridge, MA.
6 You are hereby granted permission under all Bitstream propriety rights to
7 use, copy, modify, sublicense, sell, and redistribute the Bitstream Speedo
8 software and the Bitstream Charter outline font for any purpose and without
9 restrictions; provided, that this notice is left intact on all copies of such
10 software or font and that Bitstream's trademark is acknowledged as shown below
11 on all unmodified copies of such font.
12
13 BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
14
15
16 BITSTREAM INC. DISCLAIMS ANY AND ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
17 WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18 PARTICULAR PURPOSE.  BITSTREAM SHALL NOT BE LIABLE FOR ANY DIRECT OR INDIRECT
19 DAMAGES, INCLUDING BUT NOT LIMITED TO LOST PROFITS, LOST DATA, OR ANY OTHER
20 INCIDENTAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF OR IN ANY WAY CONNECTED
21 WITH THE SPEEDO SOFTWARE OR THE BITSTREAM CHARTER OUTLINE FONT.
22
23 */
24
25
26
27 /*************************** S E T _ T R N S . C *****************************
28  *                                                                           *
29  * This module is called from do_char.c to set up the intelligent            *
30  * transformation for one character (or sub-character of a composite         *
31  * character.
32  *                                                                           *
33  ****************************************************************************/
34
35
36 #include "spdo_prv.h"               /* General definitions for Speedo   */
37
38 #define   DEBUG      0
39
40 #if DEBUG
41 #include <stdio.h>
42 #define SHOW(X) printf("X = %d\n", X)
43 #else
44 #define SHOW(X)
45 #endif
46 /***** LOCAL MACROS     *****/
47
48 #define SQUEEZE_X_ORU(A,B,C) ((((fix31)A * (fix31)B) + C) >> 16)
49 #define ABS(A) ((A < 0)? -A:A) /* absolute value */
50 #define IMPORT_FACTOR    \
51         shift = 16;\
52         while (*x_factor > (0x7fffffffL / (isw_scale >> (16 - shift))))\
53                 shift--;\
54         *x_factor = (*x_factor * (isw_scale>>(16-shift))) >> shift;
55
56 /***** GLOBAL VARIABLES *****/
57
58 /*****  GLOBAL FUNCTIONS *****/
59
60 /***** EXTERNAL VARIABLES *****/
61
62 /***** EXTERNAL FUNCTIONS *****/
63
64 /***** STATIC VARIABLES *****/
65
66 /***** STATIC FUNCTIONS *****/
67
68 #if PROTOS_AVAIL
69 static void sp_constr_update(PROTO_DECL1);
70 static ufix8 FONTFAR *sp_setup_pix_table(PROTO_DECL2 ufix8 FONTFAR *pointer,boolean short_form,fix15 no_X_ctrl_zones,fix15 no_Y_ctrl_zones);
71 static ufix8 FONTFAR *sp_setup_int_table(PROTO_DECL2 ufix8 FONTFAR *pointer,fix15 no_X_int_zones,fix15 no_Y_int_zones);
72 #else
73 static void sp_constr_update();     /* Update constraint table */
74 static ufix8 FONTFAR *sp_setup_pix_table();   /* Read control zone table */
75 static ufix8 FONTFAR *sp_setup_int_table();   /* Read interpolation zone table */
76 #endif
77
78 \f
79 FUNCTION void init_tcb()
80 GDECL
81 /*
82  * Called by sp_make_char() and make_comp_char() to initialize the current
83  * transformation control block to the top level transformation.
84  */
85 {
86 sp_globals.tcb = sp_globals.tcb0;
87 }
88 \f
89 FUNCTION void scale_tcb(ptcb, x_pos, y_pos, x_scale, y_scale)
90 GDECL
91 tcb_t GLOBALFAR *ptcb;    /* Transformation control block */
92 fix15  x_pos;   /* X position (outline res units) */
93 fix15  y_pos;   /* Y position (outline res units) */
94 fix15  x_scale; /* X scale factor * ONE_SCALE */
95 fix15  y_scale; /* Y scale factor * ONE_SCALE */
96 /*
97  * Called by make_comp_char() to apply position and scale for each of the
98  * components of a compound character.
99  */
100 {     
101 fix15 xx_mult = ptcb->xxmult;
102 fix15 xy_mult = ptcb->xymult;
103 fix31 x_offset = ptcb->xoffset;
104 fix15 yx_mult = ptcb->yxmult;
105 fix15 yy_mult = ptcb->yymult;
106 fix31 y_offset = ptcb->yoffset;
107
108 ptcb->xxmult = TRANS(xx_mult, x_scale, (fix31)SCALE_RND, SCALE_SHIFT);
109 ptcb->xymult = TRANS(xy_mult, y_scale, (fix31)SCALE_RND, SCALE_SHIFT);
110 ptcb->xoffset = MULT16(xx_mult, x_pos) + MULT16(xy_mult, y_pos) + x_offset;
111 ptcb->yxmult = TRANS(yx_mult, x_scale, (fix31)SCALE_RND, SCALE_SHIFT);
112 ptcb->yymult = TRANS(yy_mult, y_scale, (fix31)SCALE_RND, SCALE_SHIFT);
113 ptcb->yoffset = MULT16(yx_mult, x_pos) + MULT16(yy_mult, y_pos) + y_offset;
114
115 type_tcb(ptcb); /* Reclassify transformation types */
116 }
117 \f
118 FUNCTION ufix8 FONTFAR *skip_interpolation_table(pointer,format)
119 GDECL
120 ufix8 FONTFAR *pointer;  /* Pointer to next byte in char data */
121 ufix8    format;    /* Character format byte */
122 {
123 fix15 i,n;
124 ufix8 intsize[9];
125
126 intsize[0] = 1;
127 intsize[1] = 2;
128 intsize[2] = 3;
129 intsize[3] = 1;
130 intsize[4] = 2;
131 intsize[5] = 1;
132 intsize[6] = 2;
133 intsize[7] = 0;
134 intsize[8] = 0;
135
136 n = ((format & BIT6)? (fix15)NEXT_BYTE(pointer): 0) +
137     ((format & BIT7)? (fix15)NEXT_BYTE(pointer): 0);
138 for (i = 0; i < n; i++)          /* For each entry in int table ... */
139     {
140     format = NEXT_BYTE(pointer); /* Read format byte */
141     if (format & BIT7)           /* Short Start/End point spec? */
142         {
143         pointer++;               /* Skip Start/End point byte */
144         }
145     else
146         {
147         pointer += intsize[format & 0x7];  /* Skip Start point spec */
148         pointer += intsize[(format >> 3) & 0x7]; /* Skip End point spec */
149         }
150     }
151 return pointer;
152 }
153 FUNCTION ufix8 FONTFAR *skip_control_zone(pointer,format)
154 GDECL
155 ufix8 FONTFAR *pointer;  /* Pointer to next byte in char data */
156 ufix8    format;    /* Character format byte */
157 {
158 fix15    i,n;
159 ufix16   tmpufix16;
160 fix15    constr;
161
162 n = sp_globals.no_X_orus + sp_globals.no_Y_orus - 2;
163 for (i = 0; i < n; i++)          /* For each entry in control table ... */
164     {
165     if (format & BIT4)
166         pointer++;               /* Skip short form From/To fields */
167     else
168         pointer += 2;            /* Skip FROM and TO fields */
169     /* skip constraints field */
170     constr = NEXT_BYTES (pointer, tmpufix16);
171
172     }
173 return pointer;
174 }
175 \f
176 #if INCL_RULES
177 #else
178 FUNCTION ufix8 FONTFAR *plaid_tcb(pointer, format)
179 GDECL
180 ufix8 FONTFAR *pointer;  /* Pointer to next byte in char data */
181 ufix8    format;    /* Character format byte */
182 /* 
183  * Called by make_simp_char() and make_comp_char() to set up the controlled
184  * coordinate table and skip all other intelligent scaling rules embedded
185  * in the character data.
186  * Updates pointer to first byte after plaid data.
187  * This is used only if intelligent scaling is not supported in the
188  * configuration definitions.
189  */
190 {
191 fix15  i, n;
192
193
194
195 sp_globals.no_X_orus = (format & BIT2)?
196     (fix15)NEXT_BYTE(pointer):
197     0;
198 sp_globals.no_Y_orus = (format & BIT3)?
199     (fix15)NEXT_BYTE(pointer):
200     0;
201 pointer = read_oru_table(pointer);        /* Updates no_X/Y/orus */
202 sp_globals.Y_edge_org = sp_globals.no_X_orus;
203
204 /* Skip over control zone table */
205 pointer = skip_control_zone(pointer,format);
206
207 /* Skip over interpolation table */
208 pointer = skip_interpolation_table(pointer,format);
209 return pointer;
210 }
211 #endif
212 \f
213 #if INCL_RULES
214 FUNCTION ufix8 FONTFAR *plaid_tcb(pointer, format)
215 GDECL
216 ufix8 FONTFAR *pointer;  /* Pointer to next byte in char data */
217 ufix8    format;    /* Character format byte */
218 /* 
219  * Called by make_simp_char() and make_comp_char() to set up the controlled
220  * coordinate table and process all intelligent scaling rules embedded
221  * in the character data.
222  * Updates pointer to first byte after plaid data.
223  * This is used only if intelligent scaling is enabled in the
224  * configuration definitions.
225  */
226 {
227 fix15 no_X_ctrl_zones;
228 fix15 no_Y_ctrl_zones;
229 fix15 no_X_int_zones;
230 fix15 no_Y_int_zones;
231
232 #if INCL_PLAID_OUT         /* Plaid data monitoring included? */
233 begin_plaid_data();
234 #endif
235
236 sp_constr_update();           /* Update constraint table if required */
237
238 sp_globals.no_X_orus = (format & BIT2)?  
239     (fix15)NEXT_BYTE(pointer):
240     0;
241 sp_globals.no_Y_orus = (format & BIT3)?
242     (fix15)NEXT_BYTE(pointer):
243     0;
244 pointer = read_oru_table(pointer);  /* Updates no_X/Y/orus to include zero values */
245 sp_globals.Y_edge_org = sp_globals.no_X_orus;                                                  
246 if (sp_globals.no_X_orus > 1)         /* 2 or more controlled X coordinates? */
247     sp_globals.tcb.xmode = sp_globals.tcb.xtype; /* Enable intelligent scaling in X */
248
249 if (sp_globals.no_Y_orus > 1)         /* 2 or more controlled Y coordinates? */
250     sp_globals.tcb.ymode = sp_globals.tcb.ytype; /* Enable intelligent scaling in Y */
251
252 no_X_ctrl_zones = sp_globals.no_X_orus - 1;
253 no_Y_ctrl_zones = sp_globals.no_Y_orus - 1;
254 pointer = sp_setup_pix_table(pointer, (boolean)(format & BIT4), 
255     no_X_ctrl_zones, no_Y_ctrl_zones);
256
257 no_X_int_zones = (format & BIT6)?
258     (fix15)NEXT_BYTE(pointer):
259     0;
260 no_Y_int_zones = (format & BIT7)?
261     (fix15)NEXT_BYTE(pointer):
262     0;
263 sp_globals.Y_int_org = no_X_int_zones;
264 pointer = sp_setup_int_table(pointer, no_X_int_zones, no_Y_int_zones);
265
266 #if INCL_PLAID_OUT         /* Plaid data monitoring included? */
267 end_plaid_data();
268 #endif
269
270 return pointer;
271 }
272 #endif
273 \f
274 #if INCL_RULES
275 FUNCTION static void sp_constr_update()
276 GDECL
277 /*
278  * Called by plaid_tcb() to update the constraint table for the current
279  * transformation.
280  * This is always carried out whenever a character is generated following
281  * a change of font or scale factor or after initialization.     
282  */
283 {
284 fix31    ppo;
285 fix15    xppo;
286 fix15    yppo;
287 ufix8 FONTFAR  *pointer;
288 fix15    no_X_constr;
289 fix15    no_Y_constr;
290 fix15    i, j, k, l, n;
291 fix15    ppm;
292 ufix8    format;
293 ufix8    format1;
294 fix15    limit;
295 ufix16   constr_org;
296 fix15    constr_nr;
297 fix15    size;
298 fix31    off;
299 fix15    min;     
300 fix15    orus;
301 fix15    pix; 
302 ufix16   tmpufix16;  /* in extended mode, macro uses secnd term */
303
304 if (sp_globals.constr.data_valid &&         /* Constr table already done and ... */
305     (sp_globals.tcb.xppo == sp_globals.constr.xppo) && /* ... X pix per oru unchanged and ... */
306     (sp_globals.tcb.yppo == sp_globals.constr.yppo))   /* ... Y pix per oru unchanged? */
307     {
308     return;                      /* No need to update constraint table */
309     }
310
311 sp_globals.constr.xppo = xppo = sp_globals.tcb.xppo;   /* Update X pixels per oru indicator */
312 sp_globals.constr.yppo = yppo = sp_globals.tcb.yppo;   /* Update Y pixels per oru indicator */
313 sp_globals.constr.data_valid = TRUE;        /* Mark constraint table valid */
314
315 pointer = sp_globals.constr.org;            /* Point to first byte of constraint data */
316 no_X_constr = NEXT_BYTES(pointer, tmpufix16); /* Read nmbr of X constraints */
317 no_Y_constr = NEXT_BYTES(pointer, tmpufix16); /* Read nmbr of Y constraints */
318
319 i = 0;
320 constr_org = 0;
321 n = no_X_constr;
322 ppo = xppo;
323 for (j = 0; ; j++)
324     {
325     sp_globals.c_act[i] = FALSE;            /* Flag constraint 0 not active */
326     sp_globals.c_pix[i++] = 0;              /* Constraint 0 implies no minimum */
327     sp_globals.c_act[i] = FALSE;            /* Flag constraint 1 not active */
328     sp_globals.c_pix[i++] = sp_globals.onepix; /* Constraint 1 implies min 1 pixel*/
329     ppm = (ppo * (fix31)sp_globals.orus_per_em) >> sp_globals.multshift;
330     for (k = 0; k < n; k++)
331         {
332         format = NEXT_BYTE(pointer);        /* Read format byte */
333         limit = (fix15)NEXT_BYTE(pointer);  /* Read limit field */
334         sp_globals.c_act[i] = 
335             ((ppm < limit) || (limit == 255)) &&
336             sp_globals.constr.active;
337         if (sp_globals.c_act[i])            /* Constraint active? */
338             {
339             if ((format & BIT1) &&          /* Constraint specified and ... */
340                 (constr_nr = constr_org +
341                     ((format & BIT0)?       /* Read unsigned constraint value */
342                     NEXT_WORD(pointer): 
343                     (fix15)NEXT_BYTE(pointer)),
344                  sp_globals.c_act[constr_nr])) /* ... and specified constraint active? */ 
345                 {
346                 pix = sp_globals.c_pix[constr_nr]; /* Use constrained pixel value */
347                 format1 = format;
348                 for (l = 2; l > 0; l--)     /* Skip 2 arguments */
349                     {
350                     format1 >>= 2;
351                     if (size = format1 & 0x03)
352                         pointer += size - 1;
353                     }
354                 }
355             else                 /* Constraint absent or inactive? */
356                 {
357                 orus = (format & BIT2)? /* Read unsigned oru value */
358                     NEXT_WORD(pointer):
359                     (fix15)NEXT_BYTE(pointer);
360
361                 if (format & BIT5) /* Specified offset value? */
362                     {
363                     off = (fix31)((format & BIT4)? /* Read offset value */
364                         NEXT_WORD(pointer):
365                         (fix7)NEXT_BYTE(pointer));
366                     off = (off << (sp_globals.multshift - 6)) + sp_globals.multrnd;
367                     }
368                 else             /* Unspecified (zero) offset value? */
369                     {
370                     off = sp_globals.multrnd;
371                     }
372
373                 pix = (fix15)(((fix31)orus * ppo + off) / (1 << sp_globals.mpshift)) & sp_globals.pixfix;
374                 }
375             }
376         else                     /* Constraint inactive? */
377             {
378             format1 = format;
379             for (l = 3; l > 0; l--) /* Skip over 3 arguments */
380                 {
381                 if (size = format1 & 0x03)
382                     pointer += size - 1;
383                 format1 >>= 2;
384                 }
385             pix = 0;
386             }
387
388         if (format & 0xc0) /* Specified minimum value? */
389             {
390             min = (format & BIT7)? /* Read unsigned minimum value */
391                 (fix15)NEXT_BYTE(pointer) << sp_globals.pixshift:
392                 sp_globals.onepix;
393             }
394         else             /* Unspecified (zero) minimum value? */
395             {
396             min = 0;
397             }
398
399         sp_globals.c_pix[i] = (pix < min)? min: pix;
400         i++;
401         }
402     if (j) break;                /* Finished if second time around loop */
403     constr_org = sp_globals.Y_constr_org = i;
404     n = no_Y_constr;
405     ppo = yppo;
406     }
407
408 #if DEBUG
409 printf("\nCONSTRAINT TABLE\n");
410 n = no_X_constr + 2;
411 for (i = 0; i < n; i++)
412     {
413     printf("%3d   ", i);
414     if (sp_globals.c_act[i])
415         {
416         printf("T ");
417         }
418     else
419         {
420         printf("F ");
421         }
422     printf("%5.1f\n", ((real)sp_globals.c_pix[i] / (real)sp_globals.onepix));
423     }
424 printf("--------------\n");
425 n = no_Y_constr + 2;
426 for (i = 0; i < n; i++)
427     {
428     j = i + sp_globals.Y_constr_org;
429     printf("%3d   ", i);
430     if (sp_globals.c_act[j])
431         {
432         printf("T ");
433         }
434     else
435         {
436         printf("F ");
437         }
438     printf("%5.1f\n", ((real)sp_globals.c_pix[j] / (real)sp_globals.onepix));
439     }
440 #endif
441
442 }
443 #endif
444 \f
445 FUNCTION ufix8 FONTFAR *read_oru_table(pointer)
446 GDECL
447 ufix8 FONTFAR *pointer;   /* Pointer to first byte in controlled coord table */
448 /*
449  * Called by plaid_tcb() to read the controlled coordinate table from the
450  * character data in the font. 
451  * Updates the pointer to the byte following the controlled coordinate
452  * data.
453  */
454 {
455 fix15    i, j, k, n;
456 boolean  zero_not_in;
457 boolean  zero_added;
458 fix15    oru;
459
460 #if INCL_RULES
461 fix15    pos;
462 #endif
463
464 i = 0;
465 n = sp_globals.no_X_orus;
466 #if INCL_RULES
467 pos = sp_globals.tcb.xpos;
468 #endif
469 for (j = 0; ; j++)
470     {
471     zero_not_in = TRUE;
472     zero_added = FALSE;
473     for (k = 0; k < n; k++)
474         {
475         oru = NEXT_WORD(pointer);
476         if (zero_not_in && (oru >= 0)) /* First positive oru value? */
477             {
478 #if INCL_RULES
479             sp_plaid.pix[i] = pos;        /* Insert position in pix array */
480 #endif
481             if (oru != 0)        /* Zero oru value omitted? */
482                 {
483                 sp_plaid.orus[i++] = 0;   /* Insert zero value in oru array */
484                 zero_added = TRUE; /* Remember to increment size of array */
485                 }
486             zero_not_in = FALSE; /* Inhibit further testing for zero ins */
487             }
488         sp_plaid.orus[i++] = oru;         /* Add specified oru value to array */
489         }
490     if (zero_not_in)             /* All specified oru values negative? */
491         {
492 #if INCL_RULES
493         sp_plaid.pix[i] = pos;            /* Insert position in pix array */
494 #endif
495         sp_plaid.orus[i++] = 0;           /* Add zero oru value */
496         zero_added = TRUE;       /* Remember to increment size of array */
497         }
498     if (j)                       /* Both X and Y orus read? */
499         break;
500     if (zero_added)                                 
501         sp_globals.no_X_orus++;             /* Increment X array size */
502     n = sp_globals.no_Y_orus;               /* Prepare to read Y oru values */
503 #if INCL_RULES
504     pos = sp_globals.tcb.ypos;
505 #endif
506     }
507 if (zero_added)                  /* Zero Y oru value added to array? */
508     sp_globals.no_Y_orus++;                 /* Increment Y array size */
509
510 #if DEBUG
511 printf("\nX ORUS\n");
512 n = sp_globals.no_X_orus;
513 for (i = 0; i < n; i++)
514     {
515     printf("%2d %4d\n", i, sp_plaid.orus[i]);
516     }
517 printf("\nY ORUS\n");
518 n = sp_globals.no_Y_orus;
519 for (i = 0; i < n; i++)
520     {
521     printf("%2d %4d\n", i, sp_plaid.orus[i + sp_globals.no_X_orus]);
522     }
523 #endif
524
525 return pointer;             /* Update pointer */
526 }
527 #if INCL_SQUEEZING || INCL_ISW
528 FUNCTION static void calculate_x_pix(start_edge, end_edge, constr_nr,
529         x_scale, x_offset, ppo, setwidth_pix)
530 GDECL
531 ufix8 start_edge, end_edge;
532 ufix16 constr_nr;
533 fix31 x_scale;
534 fix31 x_offset;
535 fix31 ppo;
536 fix15    setwidth_pix;
537 /*
538  * Called by sp_setup_pix_table() when X squeezing is necessary
539  * to insert the correct edge in the global pix array
540  */
541 {
542 fix15 zone_pix;
543 fix15 start_oru, end_oru;
544
545 /* compute scaled oru coordinates */
546 start_oru= (fix15)(SQUEEZE_X_ORU(sp_plaid.orus[start_edge], x_scale, x_offset));
547 end_oru   = (fix15)(SQUEEZE_X_ORU(sp_plaid.orus[end_edge], x_scale, x_offset));
548
549 if (!sp_globals.c_act[constr_nr]) /* constraint inactive */
550     {
551     /* calculate zone width */
552     zone_pix = (fix15)(((((fix31)end_oru - (fix31)start_oru) * ppo) /
553         (1<<sp_globals.mpshift)) + sp_globals.pixrnd) & sp_globals.pixfix;
554     /* check for overflow */
555     if (((end_oru-start_oru) > 0) && (zone_pix < 0))
556         zone_pix = 0x7ffff;
557     /* check for minimum */
558     if ((ABS(zone_pix)) >= sp_globals.c_pix[constr_nr])
559         goto Lx;
560     }
561 /* use the zone size from the constr table - scale it */
562 zone_pix = (fix15)(((SQUEEZE_MULT(x_scale,sp_globals.c_pix[constr_nr]))
563             + sp_globals.pixrnd) & sp_globals.pixfix);
564
565 /* look for overflow */
566 if ((sp_globals.c_pix[constr_nr] > 0) && (zone_pix < 0))
567         zone_pix = 0x7fff;
568
569 if (start_edge > end_edge)
570     {
571     zone_pix = -zone_pix;
572     }
573 Lx:
574 /* assign pixel value to global pix array */
575 sp_plaid.pix[end_edge]=sp_plaid.pix[start_edge] + zone_pix;
576
577 /* check for overflow */
578 if (((sp_plaid.pix[start_edge] >0) && (zone_pix >0)) &&
579     (sp_plaid.pix[end_edge] < 0))
580         sp_plaid.pix[end_edge] = 0x7fff; /* set it to the max */
581
582 /* be sure to be in the setwidth !*/
583 #if INCL_ISW
584 if (!sp_globals.import_setwidth_act) /* only check left edge if not isw only */
585 #endif
586 if ((sp_globals.pspecs->flags & SQUEEZE_LEFT) && (sp_plaid.pix[end_edge] < 0))
587     sp_plaid.pix[end_edge] = 0;
588 if ((sp_globals.pspecs->flags & SQUEEZE_RIGHT) && 
589     (sp_plaid.pix[end_edge] > setwidth_pix))
590     sp_plaid.pix[end_edge] = setwidth_pix;
591
592 }
593 #endif
594 \f
595 #if INCL_SQUEEZING
596 FUNCTION static void calculate_y_pix(start_edge, end_edge,constr_nr,
597                 top_scale, bottom_scale,ppo,em_top_pix, em_bot_pix)
598 GDECL
599 ufix8 start_edge, end_edge;
600 ufix16 constr_nr;
601 fix31 top_scale, bottom_scale; 
602 fix31 ppo;
603 fix15 em_top_pix, em_bot_pix;
604
605 /*
606  * Called by sp_setup_pix_table() when Y squeezing is necessary
607  * to insert the correct edge in the global pix array
608  */
609 {
610 fix15 zone_pix;
611 fix15 start_oru, end_oru;
612 fix31 zone_width, above_base, below_base;
613
614 /* check whether edge is above or below the baseline                */
615 /* and apply appropriate scale factor to get scaled oru coordinates */
616 if (sp_plaid.orus[start_edge] < 0)
617     start_oru =(fix15)(SQUEEZE_MULT(sp_plaid.orus[start_edge], bottom_scale));
618 else
619     start_oru =(fix15)(SQUEEZE_MULT(sp_plaid.orus[start_edge], top_scale));
620
621 if (sp_plaid.orus[end_edge] < 0)
622     end_oru =(fix15)(SQUEEZE_MULT(sp_plaid.orus[end_edge], bottom_scale));
623 else
624     end_oru =(fix15)(SQUEEZE_MULT(sp_plaid.orus[end_edge], top_scale));
625
626 if (!sp_globals.c_act[constr_nr])   /* Constraint inactive? */
627    {
628    /* calculate zone width */
629     zone_pix = (fix15)(((((fix31)end_oru - (fix31)start_oru) * ppo)
630                 >> sp_globals.mpshift)+ sp_globals.pixrnd) & sp_globals.pixfix;
631    /* check minimum */
632     if ((ABS(zone_pix)) >= sp_globals.c_pix[constr_nr])
633                     goto Ly;
634     }
635
636 /* Use zone size from constr table */
637 if ((end_oru >= 0) && (start_oru >=0))
638     /* all above baseline */
639     zone_pix = (fix15)(SQUEEZE_MULT(top_scale, sp_globals.c_pix[constr_nr]));
640 else if ((end_oru <= 0) && (start_oru <=0))
641     /* all below baseline */
642     zone_pix = (fix15)(SQUEEZE_MULT(bottom_scale, sp_globals.c_pix[constr_nr]));
643 else
644     {
645     /* mixture */
646     if (start_oru > 0)
647         {
648         zone_width = start_oru - end_oru;
649         /* get % above baseline in 16.16 fixed point */
650         above_base = (((fix31)start_oru) << 16) /
651                      ((fix31)zone_width) ;
652         /* get % below baseline in 16.16 fixed point */
653         below_base = (((fix31)-end_oru) << 16) /
654                      ((fix31)zone_width) ;
655         }
656     else
657         {
658         zone_width = end_oru - start_oru;
659         /* get % above baseline in 16.16 fixed point */
660         above_base = (((fix31)-start_oru) << 16) /
661                      ((fix31)zone_width) ;
662         /* get % below baseline in 16.16 fixed point */
663         below_base = (((fix31)end_oru) << 16) /
664                      ((fix31)zone_width) ;
665        }
666     /* % above baseline * total zone * top_scale +  */
667     /* % below baseline * total zone * bottom_scale */
668     zone_pix = ((((above_base * (fix31)sp_globals.c_pix[constr_nr]) >> 16) *
669                 top_scale) +
670                (((below_base * (fix31)sp_globals.c_pix[constr_nr]) >> 16) *
671                 bottom_scale)) >> 16;
672     }
673
674 /* make this zone pix fall on a pixel boundary */
675 zone_pix = (zone_pix + sp_globals.pixrnd) & sp_globals.pixfix;
676
677 /* if minimum is in effect make the zone one pixel */
678 if ((sp_globals.c_pix[constr_nr] != 0) && (zone_pix < sp_globals.onepix)) 
679     zone_pix = sp_globals.onepix; 
680     
681 if (start_edge > end_edge) 
682        {
683         zone_pix = -zone_pix; /* Use negatve zone size */
684         }
685 Ly:
686 /* assign global pix value */
687 sp_plaid.pix[end_edge] = sp_plaid.pix[start_edge] + zone_pix; /* Insert end pixels */
688
689 /* make sure it is in the EM !*/
690 if ((sp_globals.pspecs->flags & SQUEEZE_TOP) && 
691     (sp_plaid.pix[end_edge] > em_top_pix))
692     sp_plaid.pix[end_edge] = em_top_pix;
693 if ((sp_globals.pspecs->flags & SQUEEZE_BOTTOM) &&
694     (sp_plaid.pix[end_edge] < em_bot_pix))
695     sp_plaid.pix[end_edge] = em_bot_pix;
696 }
697 \f
698 FUNCTION boolean calculate_x_scale(x_factor, x_offset, no_X_ctrl_zones)
699 GDECL
700 fix31 *x_factor;
701 fix31 *x_offset;
702 fix15   no_X_ctrl_zones; /* Number of X control zones */
703 /*
704  * Called by sp_setup_pix_table() when squeezing is included
705  * to determine whether X scaling is necessary.  If it is, the
706  * scale factor and offset are computed.  This function returns
707  * a boolean value TRUE = X squeezind is necessary, FALSE = no
708  * X squeezing is necessary.
709  */
710 {
711 boolean squeeze_left, squeeze_right;
712 boolean out_on_right, out_on_left;
713 fix15 bbox_width,set_width;
714 fix15 bbox_xmin, bbox_xmax;
715 fix15 x_offset_pix;
716 fix15 i;
717 #if INCL_ISW
718 fix31 isw_scale;
719 fix15 shift;
720 #endif
721
722
723 /* set up some flags and common calculations */
724 squeeze_left = (sp_globals.pspecs->flags & SQUEEZE_LEFT)? TRUE:FALSE;
725 squeeze_right = (sp_globals.pspecs->flags & SQUEEZE_RIGHT)? TRUE:FALSE;
726 bbox_xmin = sp_globals.bbox_xmin_orus;
727 bbox_xmax = sp_globals.bbox_xmax_orus;
728 set_width = sp_globals.setwidth_orus;
729
730 if (bbox_xmax > set_width)
731     out_on_right = TRUE;
732 else
733     out_on_right = FALSE;
734 if (bbox_xmin < 0)
735     out_on_left = TRUE;
736 else
737     out_on_left = FALSE;
738 bbox_width =bbox_xmax - bbox_xmin;
739
740 /*
741  * don't need X squeezing if:
742  *     - X squeezing not enabled
743  *     - bbox doesn't violate on left or right
744  *     - left squeezing only is enabled and char isn't out on left
745  *     - right squeezing only is enabled and char isn't out on right
746  */
747
748 if ((!squeeze_left && !squeeze_right) || 
749    (!out_on_right && !out_on_left) ||     
750    (squeeze_left && !squeeze_right && !out_on_left) ||
751    (squeeze_right && !squeeze_left && !out_on_right))
752     return FALSE;
753
754 #if INCL_ISW
755 if (sp_globals.import_setwidth_act)
756     {
757     /* if both isw and squeezing is going on - let the imported */
758     /* setwidth factor be factored in with the squeeze          */
759     isw_scale = compute_isw_scale();
760     /*sp_globals.setwidth_orus = sp_globals.imported_width;*/
761     }
762 else
763     isw_scale = 0x10000L; /* 1 in 16.16 notation */
764 #endif
765
766 /* squeezing on left and right ?  */
767 if (squeeze_left && squeeze_right)
768     {
769     /* calculate scale factor */
770     if (bbox_width < set_width)
771         *x_factor = 0x10000L; /* 1 in 16.16 notation */
772     else
773         *x_factor = ((fix31)set_width<<16)/(fix31)bbox_width;
774 #if INCL_ISW
775     IMPORT_FACTOR
776 #endif
777     /* calculate offset */
778     if (out_on_left) /* fall out on left ? */
779         *x_offset = -(fix31)*x_factor * (fix31)bbox_xmin;
780     /* fall out on right and I am shifting only ? */
781     else if (out_on_right && (*x_factor == 0x10000L))
782         *x_offset = -(fix31)*x_factor * (fix31)(bbox_xmax - set_width);
783     else
784         *x_offset = 0x0L; /* 0 in 16.16 notation */
785     }
786 /* squeezing on left only and violates left */
787 else if (squeeze_left)
788     {
789     if (bbox_width < set_width) /* will it fit if I shift it ? */
790         *x_factor = 0x10000L; /* 1 in 16.16 notation */
791     else if (out_on_right)
792         *x_factor = ((fix31)set_width<<16)/(fix31)bbox_width;
793     else
794         *x_factor = ((fix31)set_width<<16)/
795                     (fix31)(bbox_width - (bbox_xmax-set_width));
796 #if INCL_ISW
797     IMPORT_FACTOR
798 #endif
799     *x_offset = (fix31)-*x_factor * (fix31)bbox_xmin;
800     }
801
802 /* I must be squeezing on right, and violates right */
803 else 
804     {
805     if (bbox_width < set_width) /* will it fit if I shift it ? */
806         {  /* just shift it left - it will fit in the bbox */
807         *x_factor = 0x10000L; /* 1 in 16.16 notation */
808 #if INCL_ISW
809     IMPORT_FACTOR
810 #endif
811         *x_offset = (fix31)-*x_factor * (fix31)bbox_xmin;
812         }
813     else if (out_on_left)
814         {
815         *x_factor = ((fix31)set_width<<16)/(fix31)bbox_width;
816 #if INCL_ISW
817     IMPORT_FACTOR
818 #endif
819         *x_offset = 0x0L; /* 0 in 16.16 notation */
820         }
821     else
822         {
823         *x_factor = ((fix31)set_width<<16)/(fix31)bbox_xmax;
824 #if INCL_ISW
825     IMPORT_FACTOR
826 #endif
827         *x_offset = 0x0L; /* 0 in 16.16 notation */
828         }
829     }
830
831 x_offset_pix = (fix15)(((*x_offset >> 16) * sp_globals.tcb0.xppo)
832                 / (1<<sp_globals.mpshift)); 
833
834 if ((x_offset_pix >0) && (x_offset_pix < sp_globals.onepix))
835     x_offset_pix = sp_globals.onepix; 
836
837 /* look for the first non-negative oru value, scale and add the offset    */
838 /* to the corresponding pixel value - note that the pixel value           */
839 /* is set in read_oru_table.                                              */
840
841 /* look at all the X edges */
842 for (i=0; i < (no_X_ctrl_zones+1); i++)
843     if (sp_plaid.orus[i] >= 0)
844         {
845         sp_plaid.pix[i] = (SQUEEZE_MULT(sp_plaid.pix[i], *x_factor) 
846                   +sp_globals.pixrnd + x_offset_pix) & sp_globals.pixfix;
847         break;
848         }
849
850 return TRUE;
851 }
852 \f
853 FUNCTION boolean calculate_y_scale(top_scale, bottom_scale, 
854                                             first_Y_zone, no_Y_ctrl_zones)
855 GDECL
856 fix31   *top_scale, *bottom_scale;
857 fix15  first_Y_zone;
858 fix15  no_Y_ctrl_zones;
859 /*
860  * Called by sp_setup_pix_table() when squeezing is included
861  * to determine whether Y scaling is necessary.  If it is, 
862  * two scale factors are computed, one for above the baseline,
863  * and one for below the basline.
864  * This function returns a boolean value TRUE = Y squeezind is necessary, 
865  * FALSE = no Y squeezing is necessary.
866  */
867 {
868 boolean squeeze_top, squeeze_bottom;
869 boolean out_on_top, out_on_bottom;
870 fix15   bbox_top, bbox_bottom;
871 fix15   bbox_height;
872 fix15   i;
873
874 /* set up some flags and common calculations */
875 squeeze_top = (sp_globals.pspecs->flags & SQUEEZE_TOP)? TRUE:FALSE;
876 squeeze_bottom = (sp_globals.pspecs->flags & SQUEEZE_BOTTOM)? TRUE:FALSE;
877 bbox_top = sp_globals.bbox_ymax_orus;
878 bbox_bottom = sp_globals.bbox_ymin_orus;
879 bbox_height = bbox_top - bbox_bottom;
880
881 if (bbox_top > EM_TOP)
882     out_on_top = TRUE;
883 else
884     out_on_top = FALSE;
885
886 if (bbox_bottom < EM_BOT)
887     out_on_bottom = TRUE;
888 else
889     out_on_bottom = FALSE;
890
891 /*
892  * don't need Y squeezing if:
893  *     - Y squeezing not enabled
894  *     - bbox doesn't violate on top or bottom
895  *     - top squeezing only is enabled and char isn't out on top
896  *     - bottom squeezing only is enabled and char isn't out on bottom
897  */
898 if ((!squeeze_top && !squeeze_bottom) || 
899     (!out_on_top && !out_on_bottom) ||
900     (squeeze_top && !squeeze_bottom && !out_on_top) || 
901     (squeeze_bottom && !squeeze_top && !out_on_bottom)) 
902     return FALSE;
903
904 if (squeeze_top && (bbox_top > EM_TOP))
905     *top_scale = ((fix31)EM_TOP << 16)/(fix31)(bbox_top);
906 else
907     *top_scale = 0x10000L;  /* 1 in 16.16 fixed point */
908
909 if (squeeze_bottom && (bbox_bottom < EM_BOT))
910     *bottom_scale = ((fix31)-(EM_BOT) << 16)/(fix31)-bbox_bottom;
911 else
912     *bottom_scale = 0x10000L;
913
914 if (sp_globals.squeezing_compound)
915     {
916     for (i=first_Y_zone; i < (first_Y_zone + no_Y_ctrl_zones + 1); i++)
917         {
918         if (sp_plaid.orus[i] >= 0)
919             sp_plaid.pix[i] = (SQUEEZE_MULT(sp_plaid.pix[i], *top_scale)
920                               +sp_globals.pixrnd) & sp_globals.pixfix;
921         else
922             sp_plaid.pix[i] = (SQUEEZE_MULT(sp_plaid.pix[i], *bottom_scale)
923                               +sp_globals.pixrnd) & sp_globals.pixfix;
924         }
925     }
926 return TRUE;
927 }
928 #endif
929 \f
930 #if INCL_RULES
931 FUNCTION static ufix8 FONTFAR *sp_setup_pix_table(
932     pointer, short_form, no_X_ctrl_zones, no_Y_ctrl_zones)
933 GDECL
934 ufix8 FONTFAR *pointer;   /* Pointer to first byte in control zone table */
935 boolean short_form; /* TRUE if 1 byte from/to specification */
936 fix15   no_X_ctrl_zones; /* Number of X control zones */
937 fix15   no_Y_ctrl_zones; /* Number of Y control zones */
938 /*
939  * Called by plaid_tcb() to read the control zone table from the
940  * character data in the font.
941  * Sets up a table of pixel values for all controlled coordinates. 
942  * Updates the pointer to the byte following the control zone
943  * data.
944  */
945 {
946 fix15    i, j, n;
947 fix31    ppo;  
948 fix31    xppo0; /* top level pixels per oru */
949 fix31    yppo0; /* top level pixels per oru */
950 ufix8    edge_org;
951 ufix8    edge;
952 ufix8    start_edge;
953 ufix8    end_edge;
954 ufix16   constr_org;
955 fix15    constr_nr;
956 fix15    zone_pix;
957 fix31    whole_zone; /* non-transformed value of the first X zone */
958 ufix16   tmpufix16;  /* in extended mode, macro uses secnd term */
959 #if INCL_SQUEEZING
960 fix31    x_scale;
961 fix31    y_top_scale, y_bottom_scale;
962 fix31    x_offset;
963 boolean  squeezed_y;
964 fix15    setwidth_pix, em_top_pix, em_bot_pix;
965 #endif
966
967 #if INCL_ISW
968 boolean  imported_width;
969 fix31    isw_scale;
970 fix15    isw_setwidth_pix;
971 #endif
972
973 #if INCL_ISW || INCL_SQUEEZING
974 boolean squeezed_x;
975 #endif
976
977 #if INCL_PLAID_OUT               /* Plaid data monitoring included? */
978 begin_ctrl_zones(no_X_ctrl_zones, no_Y_ctrl_zones);
979 #endif                                                    
980
981
982 edge_org = 0;
983 constr_org = 0;
984 sp_globals.rnd_xmin = 0;  /* initialize the error for chars with no zone */
985 n = no_X_ctrl_zones;
986 ppo = sp_globals.tcb.xppo;
987 xppo0 = sp_globals.tcb0.xppo;
988 yppo0 = sp_globals.tcb0.yppo;
989 #if INCL_SQUEEZING || INCL_ISW
990 squeezed_x = FALSE;
991 #endif
992
993 #if INCL_SQUEEZING
994 squeezed_x = calculate_x_scale (&x_scale, &x_offset, no_X_ctrl_zones);
995 squeezed_y = calculate_y_scale(&y_top_scale,&y_bottom_scale,(n+1),
996              no_Y_ctrl_zones);
997 #if INCL_ISW
998 if (sp_globals.import_setwidth_act == TRUE)
999 setwidth_pix = ((fix15)(((fix31)sp_globals.imported_width * xppo0) >> 
1000              sp_globals.mpshift) + sp_globals.pixrnd) & sp_globals.pixfix;
1001
1002 else
1003 #endif
1004 setwidth_pix = ((fix15)(((fix31)sp_globals.setwidth_orus * xppo0) >> 
1005              sp_globals.mpshift) + sp_globals.pixrnd) & sp_globals.pixfix;
1006 /* check for overflow */
1007 if (setwidth_pix < 0)
1008         setwidth_pix = 0x7fff; /* set to maximum */
1009 em_bot_pix = ((fix15)(((fix31)EM_BOT * yppo0) >> 
1010              sp_globals.mpshift) + sp_globals.pixrnd) & sp_globals.pixfix;
1011 em_top_pix = ((fix15)(((fix31)EM_TOP * yppo0) >> 
1012              sp_globals.mpshift) + sp_globals.pixrnd) & sp_globals.pixfix;
1013 #endif
1014
1015 #if INCL_ISW
1016 /* convert to pixels */
1017 isw_setwidth_pix = ((fix15)(((fix31)sp_globals.imported_width * xppo0) >> 
1018              sp_globals.mpshift) + sp_globals.pixrnd) & sp_globals.pixfix;
1019 /* check for overflow */
1020 if (isw_setwidth_pix < 0)
1021         isw_setwidth_pix = 0x7fff; /* set to maximum */
1022 if (!squeezed_x && ((imported_width = sp_globals.import_setwidth_act) == TRUE))
1023     {
1024     isw_scale = compute_isw_scale();
1025
1026     /* look for the first non-negative oru value, scale and add the offset    */
1027     /* to the corresponding pixel value - note that the pixel value           */
1028     /* is set in read_oru_table.                                              */
1029     
1030     /* look at all the X edges */
1031         for (i=0; i < (no_X_ctrl_zones+1); i++)
1032         if (sp_plaid.orus[i] >= 0)
1033            {
1034            sp_plaid.pix[i] = (SQUEEZE_MULT(sp_plaid.pix[i], isw_scale)
1035                   +sp_globals.pixrnd) & sp_globals.pixfix;
1036            break;
1037            }
1038
1039     }
1040 #endif
1041
1042 for (i = 0; ; i++)               /* For X and Y control zones... */
1043     {
1044     for (j = 0; j < n; j++)      /* For each zone in X or Y... */
1045         {
1046         if (short_form)          /* 1 byte from/to specification? */
1047             {
1048             edge = NEXT_BYTE(pointer); /* Read packed from/to spec */
1049             start_edge = edge_org + (edge & 0x0f); /* Extract start edge */
1050             end_edge = edge_org + (edge >> 4); /* Extract end edge */
1051             }
1052         else                     /* 2 byte from/to specification? */
1053             {
1054             start_edge = edge_org + NEXT_BYTE(pointer); /* Read start edge */
1055             end_edge = edge_org + NEXT_BYTE(pointer); /* read end edge */
1056             }
1057         constr_nr = constr_org +
1058             NEXT_BYTES(pointer, tmpufix16); /* Read constraint number */ 
1059 #if INCL_SQUEEZING
1060         if (i == 0 && squeezed_x)
1061             calculate_x_pix(start_edge, end_edge, constr_nr,
1062                             x_scale, x_offset, ppo, setwidth_pix);
1063         else if (i == 1 && squeezed_y)
1064             calculate_y_pix(start_edge, end_edge,constr_nr,
1065                 y_top_scale, y_bottom_scale, ppo, em_top_pix, em_bot_pix);
1066         else
1067         {
1068 #endif
1069 #if INCL_ISW
1070         if (i==0 && imported_width)
1071             calculate_x_pix(start_edge, end_edge, constr_nr,
1072                             isw_scale, 0,  ppo, isw_setwidth_pix);
1073         else
1074         {
1075 #endif
1076         if (!sp_globals.c_act[constr_nr])   /* Constraint inactive? */
1077             {
1078             zone_pix = ((fix15)((((fix31)sp_plaid.orus[end_edge] -
1079                         (fix31)sp_plaid.orus[start_edge]) * ppo) /
1080                         (1<<sp_globals.mpshift)) + sp_globals.pixrnd) &
1081                         sp_globals.pixfix;
1082             if ((ABS(zone_pix)) >= sp_globals.c_pix[constr_nr])
1083                 goto L1;
1084             }
1085         zone_pix = sp_globals.c_pix[constr_nr]; /* Use zone size from constr table */
1086         if (start_edge > end_edge) /* sp_plaid.orus[start_edge] > sp_plaid.orus[end_edge]? */
1087             {
1088             zone_pix = -zone_pix; /* Use negatve zone size */
1089             }
1090     L1:
1091                         /* inter-character spacing fix */
1092         if ((j == 0) && (i == 0))      /* if this is the 1st X zone, save rounding error */
1093             {                          /*  get the non-xformed - xformed zone, in right direction */
1094             whole_zone = (((fix31)sp_plaid.orus[end_edge] -
1095                         (fix31)sp_plaid.orus[start_edge]) *
1096                         ppo) / (1<<sp_globals.mpshift);
1097             sp_globals.rnd_xmin = whole_zone - zone_pix;
1098             }
1099         sp_plaid.pix[end_edge] = sp_plaid.pix[start_edge] + zone_pix; /* Insert end pixels */
1100 #if INCL_SQUEEZING
1101         if (i == 0)  /* in the x direction */
1102             { /* brute force squeeze */
1103             if ((sp_globals.pspecs->flags & SQUEEZE_LEFT) && 
1104                 (sp_plaid.pix[end_edge] < 0))
1105                 sp_plaid.pix[end_edge] = 0;
1106             if ((sp_globals.pspecs->flags & SQUEEZE_RIGHT) && 
1107                 (sp_plaid.pix[end_edge] > setwidth_pix))
1108                 sp_plaid.pix[end_edge] = setwidth_pix;
1109             }
1110         if (i == 1) /* in the y direction */
1111             {  /* brute force squeeze */
1112             if ((sp_globals.pspecs->flags & SQUEEZE_TOP) && 
1113                 (sp_plaid.pix[end_edge] > em_top_pix))
1114                 sp_plaid.pix[end_edge] = em_top_pix;
1115             if ((sp_globals.pspecs->flags & SQUEEZE_BOTTOM) &&
1116                 (sp_plaid.pix[end_edge] < em_bot_pix))
1117                 sp_plaid.pix[end_edge] = em_bot_pix;
1118             }
1119 #endif
1120 #if INCL_SQUEEZING
1121         }
1122 #endif
1123 #if INCL_ISW
1124         }
1125 #endif
1126 #if INCL_PLAID_OUT               /* Plaid data monitoring included? */
1127         record_ctrl_zone(
1128             (fix31)sp_plaid.pix[start_edge] << (16 - sp_globals.pixshift), 
1129             (fix31)sp_plaid.pix[end_edge] << (16 - sp_globals.pixshift), 
1130             (fix15)(constr_nr - constr_org));
1131 #endif
1132         }
1133     if (i)                       /* Y pixels done? */
1134         break;                                          
1135     edge_org = sp_globals.Y_edge_org;       /* Prepare to process Y ctrl zones */
1136     constr_org = sp_globals.Y_constr_org;
1137     n = no_Y_ctrl_zones;                      
1138     ppo = sp_globals.tcb.yppo;                            
1139     }
1140
1141 #if DEBUG
1142 printf("\nX PIX TABLE\n");
1143 n = no_X_ctrl_zones + 1;
1144 for (i = 0; i < n; i++)
1145     printf("%2d %6.1f\n", i, (real)sp_plaid.pix[i] / (real)sp_globals.onepix);
1146 printf("\nY PIX TABLE\n");
1147 n = no_Y_ctrl_zones + 1;
1148 for (i = 0; i < n; i++)
1149     {
1150     j = i + no_X_ctrl_zones + 1;
1151     printf("%2d %6.1f\n", i, (real)sp_plaid.pix[j] / (real)sp_globals.onepix);
1152     }
1153 #endif
1154
1155 return pointer;
1156 }
1157 #endif
1158
1159 \f
1160 #if INCL_RULES
1161 FUNCTION static ufix8 FONTFAR *sp_setup_int_table(pointer, no_X_int_zones, no_Y_int_zones)
1162 GDECL
1163 ufix8 FONTFAR *pointer;   /* Pointer to first byte in interpolation zone table */
1164 fix15  no_X_int_zones; /* Number of X interpolation zones */
1165 fix15  no_Y_int_zones; /* Number of X interpolation zones */
1166 /*
1167  * Called by plaid_tcb() to read the interpolation zone table from the
1168  * character data in the font. 
1169  * Sets up a table of interpolation coefficients with one entry for
1170  * every X or Y interpolation zone.
1171  * Updates the pointer to the byte following the interpolation zone
1172  * data.
1173  */
1174 {
1175 fix15    i, j, k, l, n;
1176 ufix8    format;
1177 ufix8    format_copy;
1178 ufix8    tmpufix8;
1179 fix15    start_orus;
1180 ufix8    edge_org;
1181 ufix8    edge;
1182 ufix16   adj_factor;
1183 fix15    adj_orus;
1184 fix15    end_orus;
1185 fix31    zone_orus;
1186 fix15    start_pix;
1187 fix15    end_pix;
1188
1189
1190 #if INCL_PLAID_OUT               /* Plaid data monitoring included? */
1191 begin_int_zones(no_X_int_zones, no_Y_int_zones);
1192 #endif
1193
1194 i = 0;
1195 edge_org = 0;
1196 n = no_X_int_zones;
1197 for (j = 0; ; j++)
1198     {
1199     for (k = 0; k < n; k++)
1200         {
1201         format = NEXT_BYTE(pointer);
1202         if (format & BIT7)       /* Short start/end point spec? */
1203             {
1204             tmpufix8 = NEXT_BYTE(pointer);
1205             edge = edge_org + (tmpufix8 & 0xf);
1206             start_orus = sp_plaid.orus[edge];
1207             start_pix = sp_plaid.pix[edge];
1208             edge = edge_org + (tmpufix8 >> 4);
1209             end_orus = sp_plaid.orus[edge];
1210             end_pix = sp_plaid.pix[edge];
1211             }
1212         else                     /* Standard start and end point spec? */
1213             {
1214             format_copy = format;
1215             for (l = 0; ; l++)   /* Loop for start and end point */
1216                 {
1217                 switch (format_copy & 0x7) /* Decode start/end point format */
1218                     {
1219
1220                 case 0:          /* Index to control edge */
1221                     edge = edge_org + NEXT_BYTE(pointer);
1222                     end_orus = sp_plaid.orus[edge];
1223                     end_pix = sp_plaid.pix[edge];
1224                     break;
1225
1226                 case 1:          /* 1 byte fractional distance to next edge */
1227                     adj_factor =  0xffff & NEXT_BYTE(pointer) << 8;
1228                     goto L1;
1229
1230
1231                 case 2:          /* 2 byte fractional distance to next edge */
1232                     adj_factor = 0xffff & NEXT_WORD(pointer);
1233                 L1: edge = edge_org + NEXT_BYTE(pointer);
1234                     end_orus = sp_plaid.orus[edge] +
1235                         ((((fix31)sp_plaid.orus[edge + 1] - (fix31)sp_plaid.orus[edge]) * 
1236                         (ufix32)adj_factor + (fix31)32768) >> 16);
1237                     end_pix = sp_plaid.pix[edge] +
1238                         ((((fix31)sp_plaid.pix[edge + 1] - (fix31)sp_plaid.pix[edge]) * 
1239                         (ufix32)adj_factor + (fix31)32768) >> 16);
1240                     break;
1241
1242                 case 3:          /* 1 byte delta orus before first edge */
1243                     adj_orus = -(fix15)NEXT_BYTE(pointer); 
1244                     goto L2;
1245
1246                 case 4:          /* 2 byte delta orus before first edge */
1247                     adj_orus = -NEXT_WORD(pointer);
1248                 L2: edge = edge_org;
1249                     goto L4;
1250
1251                 case 5:          /* 1 byte delta orus after last edge */
1252                     adj_orus = (fix15)NEXT_BYTE(pointer);
1253                     goto L3;
1254
1255                 case 6:          /* 2 byte delta orus after last edge */
1256                     adj_orus = NEXT_WORD(pointer);
1257                 L3: edge = j? sp_globals.Y_edge_org + sp_globals.no_Y_orus - 1: sp_globals.no_X_orus - 1;
1258                 L4: end_orus = sp_plaid.orus[edge] + adj_orus;
1259                     end_pix = sp_plaid.pix[edge] + 
1260                         (((fix31)adj_orus * (fix31)(j? sp_globals.tcb.yppo: sp_globals.tcb.xppo) + 
1261                           sp_globals.mprnd) / (1<<sp_globals.mpshift));
1262                     break;
1263
1264                     }
1265
1266                 if (l)           /* Second time round loop? */
1267                     break;
1268                 format_copy >>= 3; /* Adj format to decode end point format */
1269                 start_orus = end_orus; /* Save start point oru value */
1270                 start_pix = end_pix; /* Save start point pixel value */
1271                 }
1272             }
1273 #if INCL_PLAID_OUT               /* Plaid data monitoring included? */
1274         record_int_zone(
1275             (fix31)start_pix << (16 - sp_globals.pixshift), 
1276             (fix31)end_pix << (16 - sp_globals.pixshift));
1277 #endif
1278         zone_orus = (fix31)end_orus - (fix31)start_orus;
1279         sp_plaid.mult[i] = ((((fix31)end_pix - (fix31)start_pix) << sp_globals.mpshift) + 
1280                    (zone_orus / 2)) / zone_orus;
1281         sp_plaid.offset[i] = 
1282             (((((fix31)start_pix + (fix31)end_pix) << sp_globals.mpshift) - 
1283               ((fix31)sp_plaid.mult[i] * ((fix31)start_orus + (fix31)end_orus))) / 2) + 
1284             sp_globals.mprnd;
1285         i++;
1286         }
1287     if (j)                       /* Finished? */
1288         break;
1289     edge_org = sp_globals.Y_edge_org;       /* Prepare to process Y ctrl zones */
1290     n = no_Y_int_zones;
1291     }
1292
1293 #if DEBUG
1294 printf("\nX INT TABLE\n");
1295 n = no_X_int_zones;
1296 for (i = 0; i < n; i++)
1297     {
1298     printf("%2d %7.4f %7.4f\n", i, 
1299         (real)sp_plaid.mult[i] / (real)(1 << sp_globals.multshift), 
1300         (real)sp_plaid.offset[i] / (real)(1 << sp_globals.multshift));
1301     }
1302 printf("\nY INT TABLE\n");
1303 n = no_Y_int_zones;
1304 for (i = 0; i < n; i++)
1305     {
1306     j = i + no_X_int_zones;
1307     printf("%2d %7.4f %7.4f\n", i, 
1308         (real)sp_plaid.mult[j] / (real)(1 << sp_globals.multshift), 
1309         (real)sp_plaid.offset[j] / (real)(1 << sp_globals.multshift));
1310     }
1311 #endif
1312
1313 return pointer;
1314 }
1315 #endif
1316 #if INCL_ISW
1317 FUNCTION fix31 compute_isw_scale()
1318 GDECL
1319 {
1320 fix31 isw_scale;
1321         
1322 if (sp_globals.setwidth_orus == 0)
1323     isw_scale = 0x00010000;
1324 else
1325     isw_scale = ((fix31)sp_globals.imported_width << 16)/
1326                  (fix31)sp_globals.setwidth_orus;
1327 return isw_scale;
1328 }
1329 #endif