1 /* $XConsortium: set_trns.c,v 1.6 94/02/10 11:05:59 gildea Exp $ */
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.
13 BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
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.
27 /*************************** S E T _ T R N S . C *****************************
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 *
33 ****************************************************************************/
36 #include "spdo_prv.h" /* General definitions for Speedo */
42 #define SHOW(X) printf("X = %d\n", X)
46 /***** LOCAL MACROS *****/
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 \
52 while (*x_factor > (0x7fffffffL / (isw_scale >> (16 - shift))))\
54 *x_factor = (*x_factor * (isw_scale>>(16-shift))) >> shift;
56 /***** GLOBAL VARIABLES *****/
58 /***** GLOBAL FUNCTIONS *****/
60 /***** EXTERNAL VARIABLES *****/
62 /***** EXTERNAL FUNCTIONS *****/
64 /***** STATIC VARIABLES *****/
66 /***** STATIC FUNCTIONS *****/
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);
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 */
79 FUNCTION void init_tcb()
82 * Called by sp_make_char() and make_comp_char() to initialize the current
83 * transformation control block to the top level transformation.
86 sp_globals.tcb = sp_globals.tcb0;
89 FUNCTION void scale_tcb(ptcb, x_pos, y_pos, x_scale, y_scale)
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 */
97 * Called by make_comp_char() to apply position and scale for each of the
98 * components of a compound character.
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;
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;
115 type_tcb(ptcb); /* Reclassify transformation types */
118 FUNCTION ufix8 FONTFAR *skip_interpolation_table(pointer,format)
120 ufix8 FONTFAR *pointer; /* Pointer to next byte in char data */
121 ufix8 format; /* Character format byte */
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 ... */
140 format = NEXT_BYTE(pointer); /* Read format byte */
141 if (format & BIT7) /* Short Start/End point spec? */
143 pointer++; /* Skip Start/End point byte */
147 pointer += intsize[format & 0x7]; /* Skip Start point spec */
148 pointer += intsize[(format >> 3) & 0x7]; /* Skip End point spec */
153 FUNCTION ufix8 FONTFAR *skip_control_zone(pointer,format)
155 ufix8 FONTFAR *pointer; /* Pointer to next byte in char data */
156 ufix8 format; /* Character format byte */
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 ... */
166 pointer++; /* Skip short form From/To fields */
168 pointer += 2; /* Skip FROM and TO fields */
169 /* skip constraints field */
170 constr = NEXT_BYTES (pointer, tmpufix16);
178 FUNCTION ufix8 FONTFAR *plaid_tcb(pointer, format)
180 ufix8 FONTFAR *pointer; /* Pointer to next byte in char data */
181 ufix8 format; /* Character format byte */
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.
195 sp_globals.no_X_orus = (format & BIT2)?
196 (fix15)NEXT_BYTE(pointer):
198 sp_globals.no_Y_orus = (format & BIT3)?
199 (fix15)NEXT_BYTE(pointer):
201 pointer = read_oru_table(pointer); /* Updates no_X/Y/orus */
202 sp_globals.Y_edge_org = sp_globals.no_X_orus;
204 /* Skip over control zone table */
205 pointer = skip_control_zone(pointer,format);
207 /* Skip over interpolation table */
208 pointer = skip_interpolation_table(pointer,format);
214 FUNCTION ufix8 FONTFAR *plaid_tcb(pointer, format)
216 ufix8 FONTFAR *pointer; /* Pointer to next byte in char data */
217 ufix8 format; /* Character format byte */
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.
227 fix15 no_X_ctrl_zones;
228 fix15 no_Y_ctrl_zones;
229 fix15 no_X_int_zones;
230 fix15 no_Y_int_zones;
232 #if INCL_PLAID_OUT /* Plaid data monitoring included? */
236 sp_constr_update(); /* Update constraint table if required */
238 sp_globals.no_X_orus = (format & BIT2)?
239 (fix15)NEXT_BYTE(pointer):
241 sp_globals.no_Y_orus = (format & BIT3)?
242 (fix15)NEXT_BYTE(pointer):
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 */
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 */
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);
257 no_X_int_zones = (format & BIT6)?
258 (fix15)NEXT_BYTE(pointer):
260 no_Y_int_zones = (format & BIT7)?
261 (fix15)NEXT_BYTE(pointer):
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);
266 #if INCL_PLAID_OUT /* Plaid data monitoring included? */
275 FUNCTION static void sp_constr_update()
278 * Called by plaid_tcb() to update the constraint table for the current
280 * This is always carried out whenever a character is generated following
281 * a change of font or scale factor or after initialization.
287 ufix8 FONTFAR *pointer;
302 ufix16 tmpufix16; /* in extended mode, macro uses secnd term */
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? */
308 return; /* No need to update constraint table */
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 */
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 */
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++)
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? */
339 if ((format & BIT1) && /* Constraint specified and ... */
340 (constr_nr = constr_org +
341 ((format & BIT0)? /* Read unsigned constraint value */
343 (fix15)NEXT_BYTE(pointer)),
344 sp_globals.c_act[constr_nr])) /* ... and specified constraint active? */
346 pix = sp_globals.c_pix[constr_nr]; /* Use constrained pixel value */
348 for (l = 2; l > 0; l--) /* Skip 2 arguments */
351 if (size = format1 & 0x03)
355 else /* Constraint absent or inactive? */
357 orus = (format & BIT2)? /* Read unsigned oru value */
359 (fix15)NEXT_BYTE(pointer);
361 if (format & BIT5) /* Specified offset value? */
363 off = (fix31)((format & BIT4)? /* Read offset value */
365 (fix7)NEXT_BYTE(pointer));
366 off = (off << (sp_globals.multshift - 6)) + sp_globals.multrnd;
368 else /* Unspecified (zero) offset value? */
370 off = sp_globals.multrnd;
373 pix = (fix15)(((fix31)orus * ppo + off) / (1 << sp_globals.mpshift)) & sp_globals.pixfix;
376 else /* Constraint inactive? */
379 for (l = 3; l > 0; l--) /* Skip over 3 arguments */
381 if (size = format1 & 0x03)
388 if (format & 0xc0) /* Specified minimum value? */
390 min = (format & BIT7)? /* Read unsigned minimum value */
391 (fix15)NEXT_BYTE(pointer) << sp_globals.pixshift:
394 else /* Unspecified (zero) minimum value? */
399 sp_globals.c_pix[i] = (pix < min)? min: pix;
402 if (j) break; /* Finished if second time around loop */
403 constr_org = sp_globals.Y_constr_org = i;
409 printf("\nCONSTRAINT TABLE\n");
411 for (i = 0; i < n; i++)
414 if (sp_globals.c_act[i])
422 printf("%5.1f\n", ((real)sp_globals.c_pix[i] / (real)sp_globals.onepix));
424 printf("--------------\n");
426 for (i = 0; i < n; i++)
428 j = i + sp_globals.Y_constr_org;
430 if (sp_globals.c_act[j])
438 printf("%5.1f\n", ((real)sp_globals.c_pix[j] / (real)sp_globals.onepix));
445 FUNCTION ufix8 FONTFAR *read_oru_table(pointer)
447 ufix8 FONTFAR *pointer; /* Pointer to first byte in controlled coord table */
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
465 n = sp_globals.no_X_orus;
467 pos = sp_globals.tcb.xpos;
473 for (k = 0; k < n; k++)
475 oru = NEXT_WORD(pointer);
476 if (zero_not_in && (oru >= 0)) /* First positive oru value? */
479 sp_plaid.pix[i] = pos; /* Insert position in pix array */
481 if (oru != 0) /* Zero oru value omitted? */
483 sp_plaid.orus[i++] = 0; /* Insert zero value in oru array */
484 zero_added = TRUE; /* Remember to increment size of array */
486 zero_not_in = FALSE; /* Inhibit further testing for zero ins */
488 sp_plaid.orus[i++] = oru; /* Add specified oru value to array */
490 if (zero_not_in) /* All specified oru values negative? */
493 sp_plaid.pix[i] = pos; /* Insert position in pix array */
495 sp_plaid.orus[i++] = 0; /* Add zero oru value */
496 zero_added = TRUE; /* Remember to increment size of array */
498 if (j) /* Both X and Y orus read? */
501 sp_globals.no_X_orus++; /* Increment X array size */
502 n = sp_globals.no_Y_orus; /* Prepare to read Y oru values */
504 pos = sp_globals.tcb.ypos;
507 if (zero_added) /* Zero Y oru value added to array? */
508 sp_globals.no_Y_orus++; /* Increment Y array size */
511 printf("\nX ORUS\n");
512 n = sp_globals.no_X_orus;
513 for (i = 0; i < n; i++)
515 printf("%2d %4d\n", i, sp_plaid.orus[i]);
517 printf("\nY ORUS\n");
518 n = sp_globals.no_Y_orus;
519 for (i = 0; i < n; i++)
521 printf("%2d %4d\n", i, sp_plaid.orus[i + sp_globals.no_X_orus]);
525 return pointer; /* Update pointer */
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)
531 ufix8 start_edge, end_edge;
538 * Called by sp_setup_pix_table() when X squeezing is necessary
539 * to insert the correct edge in the global pix array
543 fix15 start_oru, end_oru;
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));
549 if (!sp_globals.c_act[constr_nr]) /* constraint inactive */
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))
557 /* check for minimum */
558 if ((ABS(zone_pix)) >= sp_globals.c_pix[constr_nr])
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);
565 /* look for overflow */
566 if ((sp_globals.c_pix[constr_nr] > 0) && (zone_pix < 0))
569 if (start_edge > end_edge)
571 zone_pix = -zone_pix;
574 /* assign pixel value to global pix array */
575 sp_plaid.pix[end_edge]=sp_plaid.pix[start_edge] + zone_pix;
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 */
582 /* be sure to be in the setwidth !*/
584 if (!sp_globals.import_setwidth_act) /* only check left edge if not isw only */
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;
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)
599 ufix8 start_edge, end_edge;
601 fix31 top_scale, bottom_scale;
603 fix15 em_top_pix, em_bot_pix;
606 * Called by sp_setup_pix_table() when Y squeezing is necessary
607 * to insert the correct edge in the global pix array
611 fix15 start_oru, end_oru;
612 fix31 zone_width, above_base, below_base;
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));
619 start_oru =(fix15)(SQUEEZE_MULT(sp_plaid.orus[start_edge], top_scale));
621 if (sp_plaid.orus[end_edge] < 0)
622 end_oru =(fix15)(SQUEEZE_MULT(sp_plaid.orus[end_edge], bottom_scale));
624 end_oru =(fix15)(SQUEEZE_MULT(sp_plaid.orus[end_edge], top_scale));
626 if (!sp_globals.c_act[constr_nr]) /* Constraint inactive? */
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;
632 if ((ABS(zone_pix)) >= sp_globals.c_pix[constr_nr])
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]));
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) ;
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) ;
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) *
670 (((below_base * (fix31)sp_globals.c_pix[constr_nr]) >> 16) *
671 bottom_scale)) >> 16;
674 /* make this zone pix fall on a pixel boundary */
675 zone_pix = (zone_pix + sp_globals.pixrnd) & sp_globals.pixfix;
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;
681 if (start_edge > end_edge)
683 zone_pix = -zone_pix; /* Use negatve zone size */
686 /* assign global pix value */
687 sp_plaid.pix[end_edge] = sp_plaid.pix[start_edge] + zone_pix; /* Insert end pixels */
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;
698 FUNCTION boolean calculate_x_scale(x_factor, x_offset, no_X_ctrl_zones)
702 fix15 no_X_ctrl_zones; /* Number of X control zones */
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.
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;
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;
730 if (bbox_xmax > set_width)
733 out_on_right = FALSE;
738 bbox_width =bbox_xmax - bbox_xmin;
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
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))
755 if (sp_globals.import_setwidth_act)
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;*/
763 isw_scale = 0x10000L; /* 1 in 16.16 notation */
766 /* squeezing on left and right ? */
767 if (squeeze_left && squeeze_right)
769 /* calculate scale factor */
770 if (bbox_width < set_width)
771 *x_factor = 0x10000L; /* 1 in 16.16 notation */
773 *x_factor = ((fix31)set_width<<16)/(fix31)bbox_width;
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);
784 *x_offset = 0x0L; /* 0 in 16.16 notation */
786 /* squeezing on left only and violates left */
787 else if (squeeze_left)
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;
794 *x_factor = ((fix31)set_width<<16)/
795 (fix31)(bbox_width - (bbox_xmax-set_width));
799 *x_offset = (fix31)-*x_factor * (fix31)bbox_xmin;
802 /* I must be squeezing on right, and violates right */
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 */
811 *x_offset = (fix31)-*x_factor * (fix31)bbox_xmin;
813 else if (out_on_left)
815 *x_factor = ((fix31)set_width<<16)/(fix31)bbox_width;
819 *x_offset = 0x0L; /* 0 in 16.16 notation */
823 *x_factor = ((fix31)set_width<<16)/(fix31)bbox_xmax;
827 *x_offset = 0x0L; /* 0 in 16.16 notation */
831 x_offset_pix = (fix15)(((*x_offset >> 16) * sp_globals.tcb0.xppo)
832 / (1<<sp_globals.mpshift));
834 if ((x_offset_pix >0) && (x_offset_pix < sp_globals.onepix))
835 x_offset_pix = sp_globals.onepix;
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. */
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)
845 sp_plaid.pix[i] = (SQUEEZE_MULT(sp_plaid.pix[i], *x_factor)
846 +sp_globals.pixrnd + x_offset_pix) & sp_globals.pixfix;
853 FUNCTION boolean calculate_y_scale(top_scale, bottom_scale,
854 first_Y_zone, no_Y_ctrl_zones)
856 fix31 *top_scale, *bottom_scale;
858 fix15 no_Y_ctrl_zones;
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.
868 boolean squeeze_top, squeeze_bottom;
869 boolean out_on_top, out_on_bottom;
870 fix15 bbox_top, bbox_bottom;
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;
881 if (bbox_top > EM_TOP)
886 if (bbox_bottom < EM_BOT)
887 out_on_bottom = TRUE;
889 out_on_bottom = FALSE;
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
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))
904 if (squeeze_top && (bbox_top > EM_TOP))
905 *top_scale = ((fix31)EM_TOP << 16)/(fix31)(bbox_top);
907 *top_scale = 0x10000L; /* 1 in 16.16 fixed point */
909 if (squeeze_bottom && (bbox_bottom < EM_BOT))
910 *bottom_scale = ((fix31)-(EM_BOT) << 16)/(fix31)-bbox_bottom;
912 *bottom_scale = 0x10000L;
914 if (sp_globals.squeezing_compound)
916 for (i=first_Y_zone; i < (first_Y_zone + no_Y_ctrl_zones + 1); i++)
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;
922 sp_plaid.pix[i] = (SQUEEZE_MULT(sp_plaid.pix[i], *bottom_scale)
923 +sp_globals.pixrnd) & sp_globals.pixfix;
931 FUNCTION static ufix8 FONTFAR *sp_setup_pix_table(
932 pointer, short_form, no_X_ctrl_zones, no_Y_ctrl_zones)
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 */
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
948 fix31 xppo0; /* top level pixels per oru */
949 fix31 yppo0; /* top level pixels per oru */
957 fix31 whole_zone; /* non-transformed value of the first X zone */
958 ufix16 tmpufix16; /* in extended mode, macro uses secnd term */
961 fix31 y_top_scale, y_bottom_scale;
964 fix15 setwidth_pix, em_top_pix, em_bot_pix;
968 boolean imported_width;
970 fix15 isw_setwidth_pix;
973 #if INCL_ISW || INCL_SQUEEZING
977 #if INCL_PLAID_OUT /* Plaid data monitoring included? */
978 begin_ctrl_zones(no_X_ctrl_zones, no_Y_ctrl_zones);
984 sp_globals.rnd_xmin = 0; /* initialize the error for chars with no zone */
986 ppo = sp_globals.tcb.xppo;
987 xppo0 = sp_globals.tcb0.xppo;
988 yppo0 = sp_globals.tcb0.yppo;
989 #if INCL_SQUEEZING || INCL_ISW
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),
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;
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;
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))
1024 isw_scale = compute_isw_scale();
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. */
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)
1034 sp_plaid.pix[i] = (SQUEEZE_MULT(sp_plaid.pix[i], isw_scale)
1035 +sp_globals.pixrnd) & sp_globals.pixfix;
1042 for (i = 0; ; i++) /* For X and Y control zones... */
1044 for (j = 0; j < n; j++) /* For each zone in X or Y... */
1046 if (short_form) /* 1 byte from/to specification? */
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 */
1052 else /* 2 byte from/to specification? */
1054 start_edge = edge_org + NEXT_BYTE(pointer); /* Read start edge */
1055 end_edge = edge_org + NEXT_BYTE(pointer); /* read end edge */
1057 constr_nr = constr_org +
1058 NEXT_BYTES(pointer, tmpufix16); /* Read constraint number */
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);
1070 if (i==0 && imported_width)
1071 calculate_x_pix(start_edge, end_edge, constr_nr,
1072 isw_scale, 0, ppo, isw_setwidth_pix);
1076 if (!sp_globals.c_act[constr_nr]) /* Constraint inactive? */
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) &
1082 if ((ABS(zone_pix)) >= sp_globals.c_pix[constr_nr])
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]? */
1088 zone_pix = -zone_pix; /* Use negatve zone size */
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;
1099 sp_plaid.pix[end_edge] = sp_plaid.pix[start_edge] + zone_pix; /* Insert end pixels */
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;
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;
1126 #if INCL_PLAID_OUT /* Plaid data monitoring included? */
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));
1133 if (i) /* Y pixels done? */
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;
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++)
1150 j = i + no_X_ctrl_zones + 1;
1151 printf("%2d %6.1f\n", i, (real)sp_plaid.pix[j] / (real)sp_globals.onepix);
1161 FUNCTION static ufix8 FONTFAR *sp_setup_int_table(pointer, no_X_int_zones, no_Y_int_zones)
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 */
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
1175 fix15 i, j, k, l, n;
1190 #if INCL_PLAID_OUT /* Plaid data monitoring included? */
1191 begin_int_zones(no_X_int_zones, no_Y_int_zones);
1199 for (k = 0; k < n; k++)
1201 format = NEXT_BYTE(pointer);
1202 if (format & BIT7) /* Short start/end point spec? */
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];
1212 else /* Standard start and end point spec? */
1214 format_copy = format;
1215 for (l = 0; ; l++) /* Loop for start and end point */
1217 switch (format_copy & 0x7) /* Decode start/end point format */
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];
1226 case 1: /* 1 byte fractional distance to next edge */
1227 adj_factor = 0xffff & NEXT_BYTE(pointer) << 8;
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);
1242 case 3: /* 1 byte delta orus before first edge */
1243 adj_orus = -(fix15)NEXT_BYTE(pointer);
1246 case 4: /* 2 byte delta orus before first edge */
1247 adj_orus = -NEXT_WORD(pointer);
1248 L2: edge = edge_org;
1251 case 5: /* 1 byte delta orus after last edge */
1252 adj_orus = (fix15)NEXT_BYTE(pointer);
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));
1266 if (l) /* Second time round loop? */
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 */
1273 #if INCL_PLAID_OUT /* Plaid data monitoring included? */
1275 (fix31)start_pix << (16 - sp_globals.pixshift),
1276 (fix31)end_pix << (16 - sp_globals.pixshift));
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) +
1287 if (j) /* Finished? */
1289 edge_org = sp_globals.Y_edge_org; /* Prepare to process Y ctrl zones */
1294 printf("\nX INT TABLE\n");
1296 for (i = 0; i < n; i++)
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));
1302 printf("\nY INT TABLE\n");
1304 for (i = 0; i < n; i++)
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));
1317 FUNCTION fix31 compute_isw_scale()
1322 if (sp_globals.setwidth_orus == 0)
1323 isw_scale = 0x00010000;
1325 isw_scale = ((fix31)sp_globals.imported_width << 16)/
1326 (fix31)sp_globals.setwidth_orus;