1 /* $XConsortium: set_spcs.c,v 1.6 94/02/10 10:18:23 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.
26 /*************************** S E T _ S P C S . C *****************************
28 * This module implements all sp_set_specs() functionality. *
30 ****************************************************************************/
32 #include "spdo_prv.h" /* General definitions for Speedo */
39 #define SHOW(X) printf("X = %d\n", X)
44 /***** GLOBAL VARIABLES *****/
46 /***** GLOBAL FUNCTIONS *****/
48 /****** EXTERNAL VARIABLES *****/
50 /***** STATIC VARIABLES *****/
53 /****** STATIC FUNCTIONS *****/
56 static boolean sp_setup_consts(PROTO_DECL2 fix15 xmin, fix15 xmax,
57 fix15 ymin, fix15 ymax);
58 static void sp_setup_tcb(PROTO_DECL2 tcb_t GLOBALFAR *ptcb);
59 static fix15 sp_setup_mult(PROTO_DECL2 fix31 input_mult);
60 static fix31 sp_setup_offset(PROTO_DECL2 fix31 input_offset);
62 static void sp_setup_tcb(); /* Set up transformation control block */
63 static fix15 sp_setup_mult(); /* Convert mult to internal form */
64 static fix31 sp_setup_offset(); /* Convert offset to internal form */
65 static boolean sp_setup_consts(); /* Set up scaling constants */
70 FUNCTION boolean set_specs(specsarg)
72 specs_t STACKFAR *specsarg; /* Bundle of conversion specifications */
74 * Called by host software to set character generation specifications
77 ufix8 FONTFAR *pointer; /* Pointer to font data */
78 fix31 offcd; /* Offset to start of character directory */
79 fix31 ofcns; /* Offset to start of constraint data */
80 fix31 cd_size; /* Size of character directory */
81 fix31 no_bytes_min; /* Min number of bytes in font buffer */
82 ufix16 font_id; /* Font ID */
83 ufix16 private_off; /* offset to private header */
84 fix15 xmin; /* Minimum X ORU value in font */
85 fix15 xmax; /* Maximum X ORU value in font */
86 fix15 ymin; /* Minimum Y ORU value in font */
87 fix15 ymax; /* Maximum Y ORU value in font */
89 sp_globals.specs_valid = FALSE; /* Flag specs not valid */
91 sp_globals.specs = *specsarg; /* copy specs structure into sp_globals */
92 sp_globals.pspecs = &sp_globals.specs;
93 sp_globals.font = *sp_globals.pspecs->pfont;
94 sp_globals.pfont = &sp_globals.font;
95 sp_globals.font_org = sp_globals.font.org;
97 if (read_word_u(sp_globals.font_org + FH_FMVER + 4) != 0x0d0a)
99 report_error(4); /* Font format error */
102 if (read_word_u(sp_globals.font_org + FH_FMVER + 6) != 0x0000)
104 report_error(4); /* Font format error */
108 if (get_cust_no(*specsarg->pfont) == 0)
110 sp_globals.key32 = 0;
118 sp_globals.key32 = (KEY3 << 8) | KEY2;
119 sp_globals.key4 = KEY4;
120 sp_globals.key6 = KEY6;
121 sp_globals.key7 = KEY7;
122 sp_globals.key8 = KEY8;
126 sp_globals.no_chars_avail = read_word_u(sp_globals.font_org + FH_NCHRF);
128 /* Read sp_globals.orus per em from font header */
129 sp_globals.orus_per_em = read_word_u(sp_globals.font_org + FH_ORUPM);
131 /* compute address of private header */
132 private_off = read_word_u(sp_globals.font_org + FH_HEDSZ);
133 sp_globals.hdr2_org = sp_globals.font_org + private_off;
135 /* set metric resolution if specified, default to outline res otherwise */
136 if (private_off > EXP_FH_METRES)
138 sp_globals.metric_resolution = read_word_u(sp_globals.font_org + EXP_FH_METRES);
142 sp_globals.metric_resolution = sp_globals.orus_per_em;
146 sp_globals.kern.tkorg = sp_globals.font_org + read_long(sp_globals.hdr2_org + FH_OFFTK);
147 sp_globals.kern.pkorg = sp_globals.font_org + read_long(sp_globals.hdr2_org + FH_OFFPK);
148 sp_globals.kern.no_tracks = read_word_u(sp_globals.font_org + FH_NKTKS);
149 sp_globals.kern.no_pairs = read_word_u(sp_globals.font_org + FH_NKPRS);
152 offcd = read_long(sp_globals.hdr2_org + FH_OFFCD); /* Read offset to character directory */
153 ofcns = read_long(sp_globals.hdr2_org + FH_OFCNS); /* Read offset to constraint data */
154 cd_size = ofcns - offcd;
155 if ((((sp_globals.no_chars_avail << 1) + 3) != cd_size) &&
156 (((sp_globals.no_chars_avail * 3) + 4) != cd_size))
158 report_error(4); /* Font format error */
162 #if INCL_LCD /* Dynamic character data load suppoorted? */
164 no_bytes_min = read_long(sp_globals.hdr2_org + FH_OCHRD); /* Offset to character data */
165 #else /* Dynamic character data load not supported? */
166 no_bytes_min = read_long(sp_globals.hdr2_org + FH_OFFTK); /* Offset to track kerning data */
168 #else /* Dynamic character data load not supported? */
169 no_bytes_min = read_long(sp_globals.hdr2_org + FH_NBYTE); /* Offset to EOF + 1 */
172 sp_globals.font_buff_size = sp_globals.pfont->no_bytes;
173 if (sp_globals.font_buff_size < no_bytes_min) /* Minimum data not loaded? */
175 report_error(1); /* Insufficient font data loaded */
179 sp_globals.pchar_dir = sp_globals.font_org + offcd;
180 sp_globals.first_char_idx = read_word_u(sp_globals.font_org + FH_FCHRF);
182 /* Register font name with sp_globals.constraint mechanism */
184 font_id = read_word_u(sp_globals.font_org + FH_FNTID);
185 if (!(sp_globals.constr.font_id_valid) || (sp_globals.constr.font_id != font_id))
187 sp_globals.constr.font_id = font_id;
188 sp_globals.constr.font_id_valid = TRUE;
189 sp_globals.constr.data_valid = FALSE;
191 sp_globals.constr.org = sp_globals.font_org + ofcns;
192 sp_globals.constr.active = ((sp_globals.pspecs->flags & CONSTR_OFF) == 0);
195 /* Set up sliding point constants */
196 /* Set pixel shift to accomodate largest transformed pixel value */
197 xmin = read_word_u(sp_globals.font_org + FH_FXMIN);
198 xmax = read_word_u(sp_globals.font_org + FH_FXMAX);
199 ymin = read_word_u(sp_globals.font_org + FH_FYMIN);
200 ymax = read_word_u(sp_globals.font_org + FH_FYMAX);
202 if (!sp_setup_consts(xmin,xmax,ymin,ymax))
204 report_error(3); /* Requested specs out of range */
208 /* save the value of the max x oru that the fixed point constants are based on*/
209 sp_globals.isw_xmax = xmax;
212 /* Setup transformation control block */
213 sp_setup_tcb(&sp_globals.tcb0);
216 /* Select output module */
217 sp_globals.output_mode = sp_globals.pspecs->flags & 0x0007;
220 if (!init_userout(sp_globals.pspecs))
223 switch (sp_globals.output_mode)
226 case MODE_BLACK: /* Output mode 0 (Black writer) */
227 sp_globals.init_out = sp_init_black;
228 sp_globals.begin_char = sp_begin_char_black;
229 sp_globals.begin_sub_char = sp_begin_sub_char_out;
230 sp_globals.begin_contour = sp_begin_contour_black;
231 sp_globals.curve = sp_curve_out;
232 sp_globals.line = sp_line_black;
233 sp_globals.end_contour = sp_end_contour_out;
234 sp_globals.end_sub_char = sp_end_sub_char_out;
235 sp_globals.end_char = sp_end_char_black;
240 case MODE_SCREEN: /* Output mode 1 (Screen writer) */
241 sp_globals.init_out = sp_init_screen;
242 sp_globals.begin_char = sp_begin_char_screen;
243 sp_globals.begin_sub_char = sp_begin_sub_char_out;
244 sp_globals.begin_contour = sp_begin_contour_screen;
245 sp_globals.curve = sp_curve_screen;
246 sp_globals.line = sp_line_screen;
247 sp_globals.end_contour = sp_end_contour_screen;
248 sp_globals.end_sub_char = sp_end_sub_char_out;
249 sp_globals.end_char = sp_end_char_screen;
254 case MODE_OUTLINE: /* Output mode 2 (Vector) */
255 sp_globals.init_out = sp_init_outline;
256 sp_globals.begin_char = sp_begin_char_outline;
257 sp_globals.begin_sub_char = sp_begin_sub_char_outline;
258 sp_globals.begin_contour = sp_begin_contour_outline;
259 sp_globals.curve = sp_curve_outline;
260 sp_globals.line = sp_line_outline;
261 sp_globals.end_contour = sp_end_contour_outline;
262 sp_globals.end_sub_char = sp_end_sub_char_outline;
263 sp_globals.end_char = sp_end_char_outline;
268 case MODE_2D: /* Output mode 3 */
269 sp_globals.init_out = sp_init_2d;
270 sp_globals.begin_char = sp_begin_char_2d;
271 sp_globals.begin_sub_char = sp_begin_sub_char_out;
272 sp_globals.begin_contour = sp_begin_contour_2d;
273 sp_globals.curve = sp_curve_out;
274 sp_globals.line = sp_line_2d;
275 sp_globals.end_contour = sp_end_contour_out;
276 sp_globals.end_sub_char = sp_end_sub_char_out;
277 sp_globals.end_char = sp_end_char_2d;
282 report_error(8); /* Unsupported mode requested */
286 if (!fn_init_out(sp_globals.pspecs))
293 sp_globals.curves_out = sp_globals.pspecs->flags & CURVES_OUT;
295 if (sp_globals.pspecs->flags & BOGUS_MODE) /* Linear transformation requested? */
297 sp_globals.tcb0.xtype = sp_globals.tcb0.ytype = 4;
299 else /* Intelligent transformation requested? */
303 report_error(7); /* Rules requested; not supported */
308 if ((sp_globals.pspecs->flags & SQUEEZE_LEFT) ||
309 (sp_globals.pspecs->flags & SQUEEZE_RIGHT) ||
310 (sp_globals.pspecs->flags & SQUEEZE_TOP) ||
311 (sp_globals.pspecs->flags & SQUEEZE_BOTTOM) )
320 if ((sp_globals.pspecs->flags & CLIP_LEFT) ||
321 (sp_globals.pspecs->flags & CLIP_RIGHT) ||
322 (sp_globals.pspecs->flags & CLIP_TOP) ||
323 (sp_globals.pspecs->flags & CLIP_BOTTOM) )
332 sp_globals.specs_valid = TRUE;
339 #if INCL_BLACK || INCL_SCREEN || INCL_2D
340 FUNCTION boolean set_bitmap_device(bfuncs,size)
346 if (size != sizeof(sp_globals.bitmap_device))
349 sp_globals.bitmap_device = *bfuncs;
350 sp_globals.bitmap_device_set = TRUE;
355 FUNCTION boolean set_outline_device(ofuncs,size)
361 if (size != sizeof(sp_globals.outline_device))
364 sp_globals.outline_device = *ofuncs;
365 sp_globals.outline_device_set = TRUE;
372 FUNCTION boolean sp_setup_consts(xmin, xmax, ymin, ymax)
374 static FUNCTION boolean sp_setup_consts(xmin, xmax, ymin, ymax)
377 fix15 xmin; /* Minimum X ORU value in font */
378 fix15 xmax; /* Maximum X ORU value in font */
379 fix15 ymin; /* Minimum Y ORU value in font */
380 fix15 ymax; /* Maximum Y ORU value in font */
382 * Sets the following constants used for fixed point arithmetic:
383 * sp_globals.multshift multipliers and products; range is 14 to 8
384 * sp_globals.pixshift pixels: range is 0 to 8
385 * sp_globals.mpshift shift from product to sub-pixels (sp_globals.multshift - sp_globals.pixshift)
386 * sp_globals.multrnd rounding for products
387 * sp_globals.pixrnd rounding for pixels
388 * sp_globals.mprnd rounding for sub-pixels
389 * sp_globals.onepix 1 pixel in shifted pixel units
390 * sp_globals.pixfix mask to eliminate fractional bits of shifted pixels
391 * sp_globals.depth_adj curve splitting depth adjustment
392 * Returns FALSE if specs are out of range
395 fix31 mult; /* Successive multiplier values */
396 ufix32 num; /* Numerator of largest multiplier value */
397 ufix32 numcopy; /* Copy of numerator */
398 ufix32 denom; /* Denominator of largest multiplier value */
399 ufix32 denomcopy; /* Copy of denominator */
400 ufix32 pix_max; /* Maximum pixel rounding error */
401 fix31 xmult; /* Coefficient of X oru value in transformation */
402 fix31 ymult; /* Coefficient of Y oru value in transformation */
403 fix31 offset; /* Constant in transformation */
404 fix15 i; /* Loop counter */
405 fix15 x, y; /* Successive corners of bounding box in ORUs */
406 fix31 pixval; /* Successive pixel values multiplied by orus per em */
407 fix15 xx, yy; /* Bounding box corner that produces max pixel value */
409 /* Determine numerator and denominator of largest multiplier value */
410 mult = sp_globals.pspecs->xxmult >> 16;
415 mult = sp_globals.pspecs->xymult >> 16;
421 mult = sp_globals.pspecs->yxmult >> 16;
427 mult = sp_globals.pspecs->yymult >> 16;
432 num++; /* Max absolute pixels per em (rounded up) */
433 denom = (ufix32)sp_globals.orus_per_em;
435 /* Set curve splitting depth adjustment to accomodate largest multiplier value */
436 sp_globals.depth_adj = 0; /* 0 = 0.5 pel, 1 = 0.13 pel, 2 = 0.04 pel accuracy */
438 /* The following two occurances of a strange method of shifting twice by 1
439 are intentional and should not be changed to a single shift by 2.
440 It prevents MicroSoft C 5.1 from generating functions calls to do the shift.
441 Worse, using the REENTRANT_ALLOC option in conjunction with the /AC compiler
442 option, the function appears to be called incorrectly, causing depth_adj to always
443 be set to -7, causing very angular characters. */
445 while ((num > denomcopy) && (sp_globals.depth_adj < 5)) /* > 1, 4, 16, ... pixels per oru? */
449 sp_globals.depth_adj++; /* Add 1, 2, 3, ... to depth adjustment */
452 while ((numcopy <= denom) && (sp_globals.depth_adj > -4)) /* <= 1/4, 1/16, 1/64 pix per oru? */
456 sp_globals.depth_adj--; /* Subtract 1, 2, 3, ... from depth adjustment */
458 SHOW(sp_globals.depth_adj);
460 /* Set multiplier shift to accomodate largest multiplier value */
461 sp_globals.multshift = 14;
463 while (numcopy >= denom) /* More than 1, 2, 4, ... pix per oru? */
466 sp_globals.multshift--; /* sp_globals.multshift is 13, 12, 11, ... */
469 sp_globals.multrnd = ((fix31)1 << sp_globals.multshift) >> 1;
470 SHOW(sp_globals.multshift);
473 pix_max = (ufix32)( 0xffff & read_word_u(sp_globals.hdr2_org + FH_PIXMX));
476 xmult = ((sp_globals.pspecs->xxmult >> 16) + 1) >> 1;
477 ymult = ((sp_globals.pspecs->xymult >> 16) + 1) >> 1;
478 offset = ((sp_globals.pspecs->xoffset >> 16) + 1) >> 1;
479 for (i = 0; i < 8; i++)
483 xmult = ((sp_globals.pspecs->yxmult >> 16) + 1) >> 1;
484 ymult = ((sp_globals.pspecs->yymult >> 16) + 1) >> 1;
485 offset = ((sp_globals.pspecs->yoffset >> 16) + 1) >> 1;
487 x = (i & BIT1)? xmin: xmax;
488 y = (i & BIT0)? ymin: ymax;
489 pixval = (fix31)x * xmult + (fix31)y * ymult + offset * denom;
503 num += xx + yy + ((pix_max + 2) * denom);
504 /* Allow (with 2:1 safety margin) for 1 pixel rounding errors in */
505 /* xmult, ymult and offset values, pix_max pixel expansion */
506 /* due to intelligent scaling, and */
507 /* 1 pixel rounding of overall character position */
508 denom = denom << 14; /* Note num is in units of half pixels times orus per em */
510 sp_globals.pixshift = -1;
511 while ((num <= denom) && (sp_globals.pixshift < 8)) /* Max pixels <= 32768, 16384, 8192, ... pixels? */
514 sp_globals.pixshift++; /* sp_globals.pixshift = 0, 1, 2, ... */
516 if (sp_globals.pixshift < 0)
519 SHOW(sp_globals.pixshift);
520 sp_globals.poshift = 16 - sp_globals.pixshift;
522 sp_globals.onepix = (fix15)1 << sp_globals.pixshift;
523 sp_globals.pixrnd = sp_globals.onepix >> 1;
524 sp_globals.pixfix = ~0 << sp_globals.pixshift;
526 sp_globals.mpshift = sp_globals.multshift - sp_globals.pixshift;
527 if (sp_globals.mpshift < 0)
529 sp_globals.mprnd = ((fix31)1 << sp_globals.mpshift) >> 1;
535 FUNCTION void sp_setup_tcb(ptcb)
537 static FUNCTION void sp_setup_tcb(ptcb)
540 tcb_t GLOBALFAR *ptcb; /* Pointer to transformation control bloxk */
542 * Convert transformation coeffs to internal form
546 ptcb->xxmult = sp_setup_mult(sp_globals.pspecs->xxmult);
547 ptcb->xymult = sp_setup_mult(sp_globals.pspecs->xymult);
548 ptcb->xoffset = sp_setup_offset(sp_globals.pspecs->xoffset);
549 ptcb->yxmult = sp_setup_mult(sp_globals.pspecs->yxmult);
550 ptcb->yymult = sp_setup_mult(sp_globals.pspecs->yymult);
551 ptcb->yoffset = sp_setup_offset(sp_globals.pspecs->yoffset);
560 type_tcb(ptcb); /* Classify transformation type */
563 FUNCTION static fix15 sp_setup_mult(input_mult)
565 fix31 input_mult; /* Multiplier in input format */
567 * Called by sp_setup_tcb() to convert multiplier in transformation
568 * matrix from external to internal form.
571 fix15 imshift; /* Right shift to internal format */
572 fix31 imdenom; /* Divisor to internal format */
573 fix31 imrnd; /* Rounding for division operation */
575 imshift = 15 - sp_globals.multshift;
576 imdenom = (fix31)sp_globals.orus_per_em << imshift;
577 imrnd = imdenom >> 1;
581 return (fix15)((input_mult + imrnd) / imdenom);
583 return -(fix15)((-input_mult + imrnd) / imdenom);
586 FUNCTION static fix31 sp_setup_offset(input_offset)
588 fix31 input_offset; /* Multiplier in input format */
590 * Called by sp_setup_tcb() to convert offset in transformation
591 * matrix from external to internal form.
594 fix15 imshift; /* Right shift to internal format */
595 fix31 imrnd; /* Rounding for right shift operation */
597 imshift = 15 - sp_globals.multshift;
598 imrnd = ((fix31)1 << imshift) >> 1;
600 return (((input_offset >> 1) + imrnd) >> imshift) + sp_globals.mprnd;
603 FUNCTION void type_tcb(ptcb)
605 tcb_t GLOBALFAR *ptcb; /* Pointer to transformation control bloxk */
620 /* check for mirror image transformations */
621 xx_mult = ptcb->xxmult;
622 xy_mult = ptcb->xymult;
623 yx_mult = ptcb->yxmult;
624 yy_mult = ptcb->yymult;
626 ptcb->mirror = ((((fix31)xx_mult*(fix31)yy_mult)-
627 ((fix31)xy_mult*(fix31)yx_mult)) < 0) ? -1 : 1;
629 if (sp_globals.pspecs->flags & BOGUS_MODE) /* Linear transformation requested? */
639 else /* Intelligent tranformation requested? */
641 h_pos = ((ptcb->xoffset >> sp_globals.mpshift) + sp_globals.pixrnd) & sp_globals.pixfix;
642 v_pos = ((ptcb->yoffset >> sp_globals.mpshift) + sp_globals.pixrnd) & sp_globals.pixfix;
656 x_trans_type = 0; /* X pix is function of X orus only */
662 x_trans_type = 1; /* X pix is function of -X orus only */
668 else if (xx_mult == 0)
672 x_trans_type = 2; /* X pix is function of Y orus only */
678 x_trans_type = 3; /* X pix is function of -Y orus only */
688 y_trans_type = 0; /* Y pix is function of Y orus only */
694 y_trans_type = 1; /* Y pix is function of -Y orus only */
699 else if (yy_mult == 0)
703 y_trans_type = 2; /* Y pix is function of X orus only */
709 y_trans_type = 3; /* Y pix is function of -X orus only */
715 ptcb->xtype = x_trans_type;
716 ptcb->ytype = y_trans_type;
724 sp_globals.normal = (ptcb->xtype != 4) && (ptcb->ytype != 4);
737 FUNCTION fix31 read_long(pointer)
739 ufix8 FONTFAR *pointer; /* Pointer to first byte of encrypted 3-byte integer */
741 * Reads a 3-byte encrypted integer from the byte string starting at
742 * the specified point.
743 * Returns the decrypted value read as a signed integer.
748 tmpfix31 = (fix31)((*pointer++) ^ sp_globals.key4) << 8; /* Read middle byte */
749 tmpfix31 += (fix31)(*pointer++) << 16; /* Read most significant byte */
750 tmpfix31 += (fix31)((*pointer) ^ sp_globals.key6); /* Read least significant byte */
754 FUNCTION fix15 read_word_u(pointer)
756 ufix8 FONTFAR *pointer; /* Pointer to first byte of unencrypted 2-byte integer */
758 * Reads a 2-byte unencrypted integer from the byte string starting at
759 * the specified point.
760 * Returns the decrypted value read as a signed integer.
765 tmpfix15 = (fix15)(*pointer++) << 8; /* Read most significant byte */
766 tmpfix15 += (fix15)(*pointer); /* Add least significant byte */