]> git.sesse.net Git - rdpsrv/blob - Xserver/lib/font/Speedo/do_char.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / lib / font / Speedo / do_char.c
1 /* $XConsortium: do_char.c /main/5 1995/10/24 11:22:28 gildea $ */
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 /***************************** D O - C H A R . C *****************************
26  *                                                                           *
27  * This is the top level module for processing one simple or composite       *
28  * character.
29  *                                                                           *
30  ****************************************************************************/
31
32 #include "spdo_prv.h"               /* General definitions for Speedo    */
33
34 #define   DEBUG   0
35
36 #if DEBUG
37 #include <stdio.h>
38 #define SHOW(X) printf("X = %d\n", X)
39 #else
40 #define SHOW(X)
41 #endif
42
43 /***** GLOBAL VARIABLES *****/
44
45 /*****  GLOBAL FUNCTIONS *****/
46
47 /***** EXTERNAL VARIABLES *****/
48
49 /***** EXTERNAL FUNCTIONS *****/
50
51 /***** STATIC VARIABLES *****/
52
53 /***** STATIC FUNCTIONS *****/
54
55 #if PROTOS_AVAIL
56 static boolean sp_make_simp_char(PROTO_DECL2 ufix8 FONTFAR *pointer,ufix8 format);
57 static boolean sp_make_comp_char(PROTO_DECL2 ufix8 FONTFAR *pointer);
58 static ufix8 FONTFAR *sp_get_char_org(PROTO_DECL2 ufix16 char_index,boolean top_level);
59 static fix15 sp_get_posn_arg(PROTO_DECL2 ufix8 FONTFAR *STACKFAR *ppointer,ufix8 format);
60 static fix15 sp_get_scale_arg(PROTO_DECL2 ufix8 FONTFAR *STACKFAR *ppointer,ufix8 format);
61 #else
62 static boolean sp_make_simp_char(); /* Process simple character data */
63 static boolean sp_make_comp_char(); /* Process compound character data */
64 static ufix8 FONTFAR *sp_get_char_org();   /* Look up char in character directory */
65 static fix15   sp_get_posn_arg();   /* Read Xpos Ypos args in DOCH instruction */
66 static fix15   sp_get_scale_arg();  /* read Xscale Yscale args in DOCH instruction */
67 #endif
68
69 \f
70 FUNCTION ufix16 get_char_id(char_index)
71 GDECL
72 ufix16 char_index;     /* Index to character in char directory */
73 /*
74  * Returns character id for specified character index in currently
75  * selected font.
76  * Reports Error 10 and returns 0 if no font selected.
77  * Reports Error 12 and returns 0 if character data not available.
78  */
79 {
80 ufix8 FONTFAR  *pointer;      /* Pointer to character data */
81
82 if (!sp_globals.specs_valid)     /* Font specs not defined? */
83     {
84     report_error(10);            /* Report font not specified */
85     return (ufix16)0;            /* Return zero character id */
86     }
87
88 pointer = sp_get_char_org(char_index, TRUE); /* Get pointer to character data */
89 if (pointer == NULL)             /* Character data not available? */
90     {
91     report_error(12);            /* Report character data not avail */
92     return (ufix16)0;            /* Return zero character id */
93     }
94
95 return 0xffff & NEXT_WORD(pointer); /* Return character id */
96 }
97
98 \f
99 #if INCL_METRICS
100 FUNCTION fix31 get_char_width(char_index)
101 GDECL
102 ufix16 char_index;     /* Index to character in char directory */
103 /*
104  * Returns character set width for specified character index in currently
105  * selected font in units of 1/65536 em.
106  * Reports Error 10 and returns 0 if no font selected.
107  * Reports Error 12 and returns 0 if character data not available.
108  */
109 {
110 ufix8 FONTFAR  *pointer;      /* Pointer to character data */
111 fix31    set_width;    /* Set width of character */
112
113 if (!sp_globals.specs_valid)                /* Font specs not defined? */
114     {
115     report_error(10);            /* Report font not specified */
116     return (fix31)0;             /* Return zero character width */
117     }
118
119 pointer = sp_get_char_org(char_index, TRUE); /* Get pointer to character data */
120 if (pointer == NULL)             /* Character data not available? */
121     {
122     report_error(12);            /* Report character data not avail */
123     return (fix31)0;             /* Return zero character width */
124     }
125
126 pointer += 2;                    /* Skip over character id */
127 set_width = (fix31)NEXT_WORD(pointer); /* Read set width  and Convert units */
128 set_width = ((set_width << 16) + (sp_globals.metric_resolution >> 1)) / sp_globals.metric_resolution;
129 return set_width;                /* Return in 1/65536 em units */
130 }
131 #endif
132 \f
133 #if INCL_METRICS
134 FUNCTION fix15 get_track_kern(track, point_size)
135 GDECL
136 fix15  track;          /* Track required (0 - 3) */
137 fix15  point_size;     /* Point size (units of whole points) */
138 /*
139  * Returns inter-character spacing adjustment in units of 1/256
140  * points for the specified kerning track and point size.
141  * If the specified point size is larger than the maximum point
142  * size for the specified track, the adjustment for the maximum
143  * point size is used.
144  * If the specified point size is smaller than the minimum point
145  * size for the specified track, the adjustment for the minimum
146  * point size is used.
147  * If the specified point size is between the minimum point size
148  * and the maximum point size for the specified track, the 
149  * adjustment is interpolated linearly between the minimum and
150  * maximum adjustments.
151  * Reports Error 10 and returns 0 if no font selected.
152  * Reports Error 13 and returns 0 if track kerning data not in font.
153  */
154 {
155 ufix8 FONTFAR   *pointer;      /* Pointer to character data */
156 fix15    no_tracks;    /* Number of kerning tracks in font */
157 ufix8    format;       /* Track kerning format byte */
158 fix15    i;            /* Track counter */
159 fix15    min_pt_size;  /* Minimum point size for track */
160 fix15    max_pt_size;  /* Maximum point size for track */
161 fix15    min_adj;      /* Adjustment for min point size */
162 fix15    max_adj;      /* Adjustment for max point size */
163 fix31    delta_pt_size;/* Max point size - min point size */
164 fix31    delta_adj;    /* Min adjustment - max adjustment */
165 fix15    adj = 0;      /* Interpolated adjustment */
166
167 if (track == 0)                  /* Track zero selected? */
168     {
169     return adj;                  /* Return zero track kerning adjustment */
170     }
171
172 if (!sp_globals.specs_valid)                /* Font specs not defined? */
173     {
174     report_error(10);            /* Report font not specified */
175     return adj;                  /* Return zero track kerning adjustment */
176     }
177
178 no_tracks = sp_globals.kern.no_tracks;      /* Number of kerning tracks */
179 if (track > no_tracks)           /* Required track not available? */
180     {
181     report_error(13);            /* Report track kerning data not avail */
182     return adj;                  /* Return zero track kerning adjustment */
183     }
184
185 pointer =  sp_globals.kern.tkorg;            /* Point to start of track kern data */
186 for (i = 0; i < track; i++)      /* Read until track required is read */
187     {
188     format = NEXT_BYTE(pointer); /* Read track kerning format byte */
189     min_pt_size = (format & BIT0)? 
190         NEXT_WORD(pointer):
191         (fix15)NEXT_BYTE(pointer);
192     min_adj = (format & BIT1)? 
193         NEXT_WORD(pointer):
194         (fix15)NEXT_BYTE(pointer);
195     max_pt_size = (format & BIT2)? 
196         NEXT_WORD(pointer):
197         (fix15)NEXT_BYTE(pointer);
198     max_adj = (format & BIT3)? 
199         NEXT_WORD(pointer):
200         (fix15)NEXT_BYTE(pointer);
201     }
202
203 if (point_size <= min_pt_size)   /* Smaller than minimum point size? */
204     {
205     return min_adj;              /* Return minimum adjustment (1/256 points) */
206     }
207
208 if (point_size >= max_pt_size)   /* Larger than maximum point size? */
209     {
210     return max_adj;              /* Return maximum adjustment (1/256 points) */
211     }
212
213 delta_pt_size = (fix31)(max_pt_size - min_pt_size);
214 delta_adj = (fix31)(min_adj - max_adj);
215 adj = (fix15)(min_adj - 
216        (((fix31)(point_size - min_pt_size) * delta_adj + 
217          (delta_pt_size >> 1)) / delta_pt_size));
218 return adj;                      /* Return interpolated adjustment (1/256 points) */
219 }
220 #endif
221 \f
222 #if INCL_METRICS
223 FUNCTION fix31 get_pair_kern(char_index1, char_index2)
224 GDECL
225 ufix16 char_index1;    /* Index to first character in char directory */
226 ufix16 char_index2;    /* Index to second character in char directory */
227 /*
228  * Returns inter-character spacing adjustment in units of 1/65536 em
229  * for the specified pair of characters.
230  * Reports Error 10 and returns 0 if no font selected.
231  * Reports Error 14 and returns 0 if pair kerning data not in font.
232  */
233 {
234 ufix8 FONTFAR  *origin;       /* Pointer to first kerning pair record */
235 ufix8 FONTFAR  *pointer;      /* Pointer to character data */
236 ufix16   tmpufix16;    /* Temporary workspace */
237 fix15    no_pairs;     /* Number of kerning pairs in font */
238 ufix8    format;       /* Track kerning format byte */
239 boolean  long_id;      /* TRUE if 2-byte character ids */
240 fix15    rec_size;     /* Number of bytes in kern pair record */
241 fix15    n;            /* Number of remaining kern pairs */
242 fix15    nn;           /* Number of kern pairs in first partition */
243 fix15    base;         /* Index to first record in rem kern pairs */
244 fix15    i;            /* Index to kern pair being tested */
245 fix31    adj = 0;      /* Returned value of adjustment */
246 fix15    adj_base;     /* Adjustment base for relative adjustments */
247
248 if (!sp_globals.specs_valid)                /* Font specs not defined? */
249     {
250     report_error(10);            /* Report font not specified */
251     return adj;                  /* Return zero pair kerning adjustment */
252     }
253
254 no_pairs = sp_globals.kern.no_pairs;        /* Number of kerning pairs */
255 if (no_pairs == 0)               /* Pair kerning data not available? */
256     {
257     report_error(14);            /* Report pair kerning data not avail */
258     return adj;                  /* Return zero pair kerning adjustment */
259     }
260
261 pointer = sp_globals.kern.pkorg;            /* Point to start of pair kern data */
262 format = NEXT_BYTE(pointer);     /* Read pair kerning format byte */
263 if (!(format & BIT0))            /* One-byte adjustment values? */
264     adj_base = NEXT_WORD(pointer); /* Read base adjustment */
265 origin = pointer;                /* First byte of kerning pair data */
266 rec_size = format + 3;           /* Compute kerning pair record size */
267 long_id = format & BIT1;         /* Set flag for 2-byte char index */
268
269 n = no_pairs;                    /* Consider all kerning pairs */
270 base = 0;                        /* Set base at first kern pair record */
271 while (n != 0)                   /* While 1 or more kern pairs remain ... */
272     {
273     nn = n >> 1;                 /* Size of first partition */
274     i = base + nn;               /* Index to record to be tested */
275     pointer = origin + (i * rec_size);
276     tmpufix16 = NEXT_CHNDX(pointer, long_id);
277     if (char_index1 < tmpufix16)
278         {
279         n = nn;                  /* Number remaining in first partition */
280         continue;
281         }
282     if (char_index1 > tmpufix16)
283         {
284         n -= nn + 1;             /* Number remaining in second partition */
285         base = i + 1;            /* Base index for second partition */
286         continue;
287         }
288     tmpufix16 = NEXT_CHNDX(pointer, long_id);
289     if (char_index2 < tmpufix16)
290         {
291         n = nn;                  /* Number remaining in first partition */
292         continue;
293         }
294     if (char_index2 > tmpufix16)
295         {
296         n -= nn + 1;             /* Number remaining in second partition */
297         base = i + 1;            /* Base index for second partition */
298         continue;
299         }
300     adj = (format & BIT0)? 
301         (fix31)NEXT_WORD(pointer):
302         (fix31)(adj_base + (fix15)NEXT_BYTE(pointer));
303     adj = ((adj << 16) + (sp_globals.orus_per_em >> 1)) / sp_globals.orus_per_em; /* Convert units */
304     n = 0;                       /* No more to consider */
305     }
306 return adj;                      /* Return pair kerning adjustment */
307 }
308 #endif
309 \f
310
311 #if INCL_METRICS
312 #ifdef old
313 FUNCTION boolean get_char_bbox(char_index, bbox)
314 GDECL
315 ufix16 char_index;
316 bbox_t *bbox;
317 {
318 /*
319  *      returns true if character exists, false if it doesn't
320  *      provides transformed character bounding box in 1/65536 pixels
321  *      in the provided bbox_t structure.  Bounding box may be
322  *      conservative in the event that the transformation is not
323  *      normal or the character is compound.
324  */
325
326 ufix8 FONTFAR *pointer;
327 fix15 tmp;
328 point_t Pmin, Pmax;
329
330 #if REENTRANT_ALLOC
331 plaid_t plaid;
332 sp_globals.plaid = &plaid;
333 #endif
334
335 if (!sp_globals.specs_valid)                /* Font specs not defined? */
336     {
337     report_error(10);            /* Report font not specified */
338     return FALSE;                /* Error return */
339     }
340
341 init_tcb();                      /* Initialize transformation control block */
342
343 pointer = sp_get_char_org(char_index, TRUE); /* Point to start of character data */
344 if (pointer == NULL)             /* Character data not available? */
345     {
346     report_error(12);            /* Report character data not avail */
347     return FALSE;                /* Error return */
348     }
349
350 pointer += 2;                    /* Skip over character id */
351 tmp = NEXT_WORD(pointer); /* Read set width */
352                
353 tmp = NEXT_BYTE(pointer);
354 if (tmp & BIT1)               /* Optional data in header? */
355     {
356     tmp = (ufix8)NEXT_BYTE(pointer); /* Read size of optional data */
357     pointer += tmp;         /* Skip optional data */
358     }
359
360 pointer = plaid_tcb(pointer, tmp);              /* Process plaid data */
361 pointer = read_bbox(pointer, &Pmin, &Pmax,(boolean)FALSE);        /* Read bounding box */
362 bbox->xmin  = (fix31)Pmin.x << sp_globals.poshift;
363 bbox->xmax  = (fix31)Pmax.x << sp_globals.poshift;
364 bbox->ymin  = (fix31)Pmin.y << sp_globals.poshift;
365 bbox->ymax  = (fix31)Pmax.y << sp_globals.poshift;
366 return TRUE;
367 }
368
369 #else /* new code, 4/25/91 */
370
371 FUNCTION boolean get_char_bbox(char_index, bbox)
372 GDECL
373 ufix16 char_index;
374 bbox_t *bbox;
375 {
376 /*
377  *      returns true if character exists, false if it doesn't
378  *      provides transformed character bounding box in 1/65536 pixels
379  *      in the provided bbox_t structure.  Bounding box may be
380  *      conservative in the event that the transformation is not
381  *      normal or the character is compound.
382  */
383
384 ufix8 FONTFAR *pointer;
385 fix15 tmp;
386 fix15 format;
387 ufix16 pix_adj;
388 point_t Pmin, Pmax;
389
390 #if REENTRANT_ALLOC
391 plaid_t plaid;
392 sp_globals.plaid = &plaid;
393 #endif
394
395 if (!sp_globals.specs_valid)                /* Font specs not defined? */
396     {
397     report_error(10);            /* Report font not specified */
398     return FALSE;                /* Error return */
399     }
400
401 init_tcb();                      /* Initialize transformation control block */
402
403 pointer = sp_get_char_org(char_index, TRUE); /* Point to start of character data */
404 if (pointer == NULL)             /* Character data not available? */
405     {
406     report_error(12);            /* Report character data not avail */
407     return FALSE;                /* Error return */
408     }
409
410 pointer += 2;                    /* Skip over character id */
411 tmp = NEXT_WORD(pointer); /* Read set width */
412                
413 format = NEXT_BYTE(pointer);
414 if (format & BIT1)               /* Optional data in header? */
415     {
416     tmp = (ufix8)NEXT_BYTE(pointer); /* Read size of optional data */
417     pointer += tmp;         /* Skip optional data */
418     }
419
420 if (format & BIT0)
421     {
422     pix_adj = sp_globals.onepix << 1;          /* Allow 2 pixel expansion ... */
423     }
424 else
425     {
426     pix_adj = 0;
427     }
428
429 pointer = plaid_tcb(pointer, format);              /* Process plaid data */
430 pointer = read_bbox(pointer, &Pmin, &Pmax,(boolean)FALSE);        /* Read bounding box */
431
432 Pmin.x -= pix_adj;                         /* ... of components of ... */
433 Pmin.y -= pix_adj;                         /* ... compound ... */
434 Pmax.x += pix_adj;                         /* ... character ... */
435 Pmax.y += pix_adj;                         /* ... bounding box. */
436
437
438 bbox->xmin  = (fix31)Pmin.x << sp_globals.poshift;
439 bbox->xmax  = (fix31)Pmax.x << sp_globals.poshift;
440 bbox->ymin  = (fix31)Pmin.y << sp_globals.poshift;
441 bbox->ymax  = (fix31)Pmax.y << sp_globals.poshift;
442 return TRUE;
443 }
444 #endif  /* new code */
445
446 #endif
447
448 \f
449 #if INCL_ISW
450 FUNCTION boolean make_char_isw(char_index,imported_setwidth)
451 GDECL
452 ufix16 char_index;
453 ufix32 imported_setwidth;
454 {
455 fix15   xmin;          /* Minimum X ORU value in font */
456 fix15   xmax;          /* Maximum X ORU value in font */
457 fix15   ymin;          /* Minimum Y ORU value in font */
458 fix15   ymax;          /* Maximum Y ORU value in font */
459 ufix16  return_value;
460
461 sp_globals.import_setwidth_act = TRUE;
462 /* convert imported width to orus */
463 sp_globals.imported_width = (sp_globals.metric_resolution * 
464                             imported_setwidth) >> 16;
465 return_value = do_make_char(char_index);
466
467 if (sp_globals.isw_modified_constants)
468     {
469     /* reset fixed point constants */
470     xmin = read_word_u(sp_globals.font_org + FH_FXMIN);
471     ymin = read_word_u(sp_globals.font_org + FH_FYMIN);
472     ymax = read_word_u(sp_globals.font_org + FH_FYMAX);
473     sp_globals.constr.data_valid = FALSE;
474     xmax = read_word_u(sp_globals.font_org + FH_FXMAX);
475     if (!setup_consts(xmin,xmax,ymin,ymax))
476         {
477         report_error(3);           /* Requested specs out of range */
478         return FALSE;
479         }
480     }    
481 return (return_value);
482 }
483
484 FUNCTION boolean make_char(char_index)
485 GDECL
486 ufix16 char_index;     /* Index to character in char directory */
487 {
488 sp_globals.import_setwidth_act = FALSE;
489 return (do_make_char(char_index));
490 }
491
492 FUNCTION static boolean do_make_char(char_index)
493 #else
494 FUNCTION boolean make_char(char_index)
495 #endif
496 /*
497  * Outputs specified character using the currently selected font and
498  * scaling and output specifications.
499  * Reports Error 10 and returns FALSE if no font specifications 
500  * previously set.
501  * Reports Error 12 and returns FALSE if character data not available.
502  */
503 GDECL
504 ufix16 char_index;
505 {
506 ufix8 FONTFAR  *pointer;      /* Pointer to character data */
507 fix15    x_orus;
508 fix15    tmpfix15;
509 ufix8    format;
510
511 #if INCL_ISW
512 sp_globals.isw_modified_constants = FALSE;
513 #endif
514
515 #if REENTRANT_ALLOC
516
517 plaid_t plaid;
518
519 #if INCL_BLACK || INCL_SCREEN || INCL_2D
520 intercepts_t intercepts;
521 sp_globals.intercepts = &intercepts;
522 #endif
523
524 sp_globals.plaid = &plaid;
525 #endif
526
527 if (!sp_globals.specs_valid)                /* Font specs not defined? */
528     {
529     report_error(10);            /* Report font not specified */
530     return FALSE;                /* Error return */
531     }
532
533 #if INCL_MULTIDEV
534 #if INCL_OUTLINE
535 if (sp_globals.output_mode == MODE_OUTLINE && !sp_globals.outline_device_set)
536         {
537         report_error(2);
538         return FALSE;
539         }
540 else
541 #endif
542         if (!sp_globals.bitmap_device_set)
543                 {
544                 report_error(2);
545                 return FALSE;
546                 }
547 #endif
548
549
550 init_tcb();                      /* Initialize transformation control block */
551
552 pointer = sp_get_char_org(char_index, TRUE); /* Point to start of character data */
553 SHOW(pointer);
554 if (pointer == NULL)             /* Character data not available? */
555     {
556     report_error(12);            /* Report character data not avail */
557     return FALSE;                /* Error return */
558     }
559
560 pointer += 2;                    /* Skip over character id */
561 x_orus = NEXT_WORD(pointer); /* Read set width */
562 #if INCL_SQUEEZING || INCL_ISW
563 sp_globals.setwidth_orus = x_orus;
564 #endif
565
566 #if INCL_ISW
567 if (sp_globals.import_setwidth_act)
568     x_orus = sp_globals.imported_width;
569 #endif
570 sp_globals.Psw.x = (fix15)((fix31)
571                    (((fix31)x_orus * (sp_globals.specs.xxmult>>16) + 
572                   ( ((fix31)x_orus * (sp_globals.specs.xxmult&0xffffL) )>>16) 
573                   ) << sp_globals.pixshift) / sp_globals.metric_resolution);
574
575 sp_globals.Psw.y = (fix15)(   
576                   (fix31)( 
577                  ((fix31)x_orus * (sp_globals.specs.yxmult>>16) + 
578                 ( ((fix31)x_orus * (sp_globals.specs.yxmult&0xffffL) )>>16) 
579                   ) << sp_globals.pixshift) / sp_globals.metric_resolution);
580                
581 format = NEXT_BYTE(pointer);
582 if (format & BIT1)               /* Optional data in header? */
583     {
584     tmpfix15 = (ufix8)NEXT_BYTE(pointer); /* Read size of optional data */
585     pointer += tmpfix15;         /* Skip optional data */
586     }
587 if (format & BIT0)
588     {
589     return sp_make_comp_char(pointer); /* Output compound character */
590     }
591 else
592     {
593     return sp_make_simp_char(pointer, format); /* Output simple character */
594     }
595 }
596 \f
597 FUNCTION static boolean sp_make_simp_char(pointer, format)
598 GDECL
599 ufix8 FONTFAR  *pointer;      /* Pointer to first byte of position argument */
600 ufix8    format;       /* Character format byte */
601 /*
602  * Called by sp_make_char() to output a simple (non-compound) character.
603  * Returns TRUE on completion.
604  */
605 {
606 point_t Pmin, Pmax;    /* Transformed corners of bounding box */
607 #if INCL_SQUEEZING || INCL_ISW
608 ufix8 FONTFAR *save_pointer;
609 #endif
610 #if INCL_ISW
611 fix31   char_width;
612 fix31   isw_scale;
613 #endif
614
615 #if INCL_SQUEEZING
616 sp_globals.squeezing_compound = FALSE;
617 if ((sp_globals.pspecs->flags & SQUEEZE_LEFT) ||
618     (sp_globals.pspecs->flags & SQUEEZE_RIGHT) ||
619     (sp_globals.pspecs->flags & SQUEEZE_TOP) ||
620     (sp_globals.pspecs->flags & SQUEEZE_BOTTOM) )
621     {
622         /* get the bounding box data before processing the character */
623     save_pointer = pointer;
624     preview_bounding_box (pointer, format);
625     pointer = save_pointer;
626     }
627 #endif
628 #if (INCL_ISW)
629 if (sp_globals.import_setwidth_act)
630     {
631     save_pointer = pointer;
632     preview_bounding_box (pointer, format);
633     pointer = save_pointer;
634         /* make sure I'm not going to get fixed point overflow */
635     isw_scale = compute_isw_scale();
636     if (sp_globals.bbox_xmin_orus < 0)
637         char_width = SQUEEZE_MULT((sp_globals.bbox_xmax_orus - sp_globals.bbox_xmin_orus), isw_scale);
638     else
639         char_width = SQUEEZE_MULT(sp_globals.bbox_xmax_orus, isw_scale);
640     if (char_width >= sp_globals.isw_xmax)
641         if (!reset_xmax(char_width))
642               return FALSE;
643     }
644 #endif
645 pointer = plaid_tcb(pointer, format);              /* Process plaid data */
646 pointer = read_bbox(pointer, &Pmin, &Pmax, FALSE);      /* Read bounding box */
647 if (fn_begin_char(sp_globals.Psw, Pmin, Pmax))     /* Signal start of character output */
648         {
649         do
650         {
651             proc_outl_data(pointer);              /* Process outline data */
652         }
653         while (!fn_end_char());                      /* Repeat if not done */
654         }
655 return TRUE;
656 }
657 \f
658 FUNCTION static boolean sp_make_comp_char(pointer)
659 GDECL
660 ufix8 FONTFAR  *pointer;      /* Pointer to first byte of position argument */
661 /*
662  * Called by sp_make_char() to output a compound character.
663  * Returns FALSE if data for any sub-character is not available.
664  * Returns TRUE if output completed with no error.
665  */
666 {
667 point_t  Pmin, Pmax;   /* Transformed corners of bounding box */
668 point_t  Pssw;         /* Transformed escapement vector */
669 ufix8 FONTFAR  *pointer_sav;  /* Saved pointer to compound character data */
670 ufix8 FONTFAR  *sub_pointer;  /* Pointer to sub-character data */
671 ufix8    format;       /* Format of DOCH instruction */
672 ufix16   sub_char_index; /* Index to sub-character in character directory */
673 fix15    x_posn;       /* X position of sub-character (outline res units) */
674 fix15    y_posn;       /* Y position of sub-character (outline res units) */
675 fix15    x_scale;      /* X scale factor of sub-character (scale units) */
676 fix15    y_scale;      /* Y scale factor of sub-character (scale units) */
677 fix15    tmpfix15;     /* Temporary workspace */
678 fix15    x_orus;       /* Set width in outline resolution units */
679 fix15    pix_adj;      /* Pixel adjustment to compound char bounding box */
680 #if INCL_SQUEEZING
681 fix31    x_factor, x_offset, top_scale, bottom_scale;
682 boolean  squeezed_x, squeezed_y;
683 #endif
684 #if INCL_SQUEEZING || INCL_ISW
685 fix15    x_offset_pix;
686 #endif
687 #if INCL_ISW
688 fix31   char_width;
689 fix31   isw_scale;
690 #endif
691
692
693 #if INCL_SQUEEZING
694 sp_globals.squeezing_compound = TRUE;
695 #endif
696 pointer = read_bbox(pointer, &Pmin, &Pmax, TRUE); /* Read bounding box data */
697 pix_adj = sp_globals.onepix << 1;          /* Allow 2 pixel expansion ... */
698 Pmin.x -= pix_adj;                         /* ... of components of ... */
699 Pmin.y -= pix_adj;                         /* ... compound ... */
700 Pmax.x += pix_adj;                         /* ... character ... */
701 Pmax.y += pix_adj;                         /* ... bounding box. */
702
703 #if INCL_SQUEEZING
704 /* scale the bounding box if necessary before calling begin_char */
705 squeezed_x = calculate_x_scale(&x_factor, &x_offset, 0);
706 squeezed_y = calculate_y_scale(&top_scale, &bottom_scale,0,0);
707
708 if (squeezed_x)
709     { /* scale the x coordinates of the bbox */
710     x_offset_pix = (fix15)(((x_offset >> 16) * sp_globals.tcb0.xppo)
711                     >> sp_globals.mpshift);
712     if ((x_offset_pix >0) && (x_offset_pix < sp_globals.onepix))
713         x_offset_pix = sp_globals.onepix;
714     Pmin.x = SQUEEZE_MULT (x_factor, Pmin.x) + x_offset_pix - pix_adj;
715     Pmax.x = SQUEEZE_MULT (x_factor, Pmax.x) + x_offset_pix + pix_adj;
716     }
717 if (squeezed_y)
718     { /* scale the y coordinates of the bbox */
719     if ((Pmin.y) < 0)
720         Pmin.y = SQUEEZE_MULT (bottom_scale, Pmin.y) - pix_adj;
721     else
722         Pmin.y = SQUEEZE_MULT (top_scale, Pmin.y) - pix_adj;
723     if ((Pmax.y) < 0)
724         Pmax.y = SQUEEZE_MULT (bottom_scale, Pmax.y) + pix_adj;
725     else
726         Pmax.y = SQUEEZE_MULT (top_scale, Pmax.y) + pix_adj;
727     }
728 #endif
729 #if (INCL_ISW)
730 if (sp_globals.import_setwidth_act)
731     {
732         /* make sure I'm not going to get fixed point overflow */
733     isw_scale = ((fix31)sp_globals.imported_width << 16)/
734                  (fix31)sp_globals.setwidth_orus;
735     char_width = SQUEEZE_MULT((sp_globals.bbox_xmax_orus - 
736                                sp_globals.bbox_xmin_orus),
737 isw_scale);
738     if (char_width >= sp_globals.isw_xmax)
739         if (!reset_xmax(char_width))
740               return FALSE;
741     }
742 #endif
743
744 if (fn_begin_char(sp_globals.Psw, Pmin, Pmax)) /* Signal start of character data */
745         {
746         pointer_sav = pointer;
747         do
748             {
749             pointer = pointer_sav;                 /* Point to next DOCH or END instruction */
750             while (format = NEXT_BYTE(pointer))    /* DOCH instruction? */
751                 {
752                 init_tcb();                        /* Initialize transformation control block */
753                 x_posn = sp_get_posn_arg(&pointer, format);
754                 y_posn = sp_get_posn_arg(&pointer, (ufix8)(format >> 2));
755                 x_scale = sp_get_scale_arg(&pointer, (ufix8)(format & BIT4));
756                 y_scale = sp_get_scale_arg(&pointer, (ufix8)(format & BIT5));
757                 scale_tcb(&sp_globals.tcb, x_posn, y_posn, x_scale, y_scale); /* Scale for sub-char */
758                 sub_char_index = (format & BIT6)?  /* Read sub-char index */
759                     0xffff & NEXT_WORD(pointer):
760                     0xffff & NEXT_BYTE(pointer);
761                 sub_pointer = sp_get_char_org(sub_char_index, FALSE); /* Point to start of sub-char */
762                 if (sub_pointer == NULL)           /* Character data not available? */
763                     {
764                     return FALSE;                  /* Abort character output */
765                     }
766                 sub_pointer += 2;                  /* Skip over character id */
767                 x_orus = NEXT_WORD(sub_pointer);   /* Read set_width of sub-character */
768
769                         Pssw.x = (fix15)(   
770                                           (fix31)( 
771                               ((fix31)x_orus * (sp_globals.specs.xxmult>>16) + 
772                               ( ((fix31)x_orus * (sp_globals.specs.xxmult&0xffffL) )>>16) 
773                              ) << sp_globals.pixshift) / sp_globals.metric_resolution);
774                         Pssw.y = (fix15)(   
775                                           (fix31)( 
776                               ((fix31)x_orus * (sp_globals.specs.yxmult>>16) + 
777                               ( ((fix31)x_orus * (sp_globals.specs.yxmult&0xffffL) )>>16) 
778                              ) << sp_globals.pixshift) / sp_globals.metric_resolution);
779                
780                 format = NEXT_BYTE(sub_pointer);   /* Read sub-character format */
781                 if (format & BIT1)                 /* Optional data in header? */
782                     {
783                     tmpfix15 = (ufix8)NEXT_BYTE(sub_pointer); /* Read size of optional data */
784                     sub_pointer += tmpfix15;           /* Skip optional data */
785                     }
786                 sub_pointer = plaid_tcb(sub_pointer, format);   /* Process sub-character plaid data */
787                 sub_pointer = read_bbox(sub_pointer, &Pmin, &Pmax, FALSE); /* Read bounding box */
788                 fn_begin_sub_char(Pssw, Pmin, Pmax);  /* Signal start of sub-character data */
789                 proc_outl_data(sub_pointer);       /* Process sub-character data */
790                 fn_end_sub_char();                    /* Signal end of sub-character data */
791                 }
792             }
793         while (!fn_end_char());                       /* Signal end of character; repeat if required */
794         }
795 return TRUE;
796 }
797 \f
798 #if INCL_LCD           /* Dynamic load character data supported? */
799 FUNCTION static ufix8 FONTFAR *sp_get_char_org(char_index, top_level)
800 GDECL
801 ufix16   char_index;   /* Index of character to be accessed */
802 boolean  top_level;    /* Not a compound character element */
803 /*
804  * Called by sp_get_char_id(), sp_get_char_width(), sp_make_char() and
805  * sp_make_comp_char() to get a pointer to the start of the character data
806  * for the specified character index.
807  * Version for configuration supporting dynamic character data loading.
808  * Calls load_char_data() to load character data if not already loaded
809  * as part of the original font buffer.
810  * Returns NULL if character data not available
811  */
812 {
813 buff_t  *pchar_data;   /* Buffer descriptor requested */
814 ufix8 FONTFAR  *pointer;      /* Pointer into character directory */
815 ufix8    format;       /* Character directory format byte */
816 fix31    char_offset;  /* Offset of char data from start of font file */
817 fix31    next_char_offset; /* Offset of char data from start of font file */
818 fix15    no_bytes;     /* Number of bytes required for char data */
819
820 if (top_level)                        /* Not element of compound char? */
821     {
822     if (char_index < sp_globals.first_char_idx)  /* Before start of character set? */
823         return NULL;
824     char_index -= sp_globals.first_char_idx;
825     if (char_index >= sp_globals.no_chars_avail) /* Beyond end of character set? */
826         return NULL;
827     sp_globals.cb_offset = 0;                    /* Reset char buffer offset */
828     }
829
830 pointer = sp_globals.pchar_dir;
831 format = NEXT_BYTE(pointer);          /* Read character directory format byte */
832 pointer += char_index << 1;           /* Point to indexed character entry */
833 if (format)                           /* 3-byte entries in char directory? */
834     {
835     pointer += char_index;            /* Adjust for 3-byte entries */
836     char_offset = read_long(pointer); /* Read file offset to char data */
837     next_char_offset = read_long(pointer + 3); /* Read offset to next char */
838     }
839 else
840     {
841     char_offset = (fix31)(0xffff & NEXT_WORD(pointer)); /* Read file offset to char data */
842     next_char_offset = (fix31)(0xffff & NEXT_WORD(pointer)); /* Read offset to next char */
843     }
844
845 no_bytes = next_char_offset - char_offset;
846 if (no_bytes == 0)                    /* Character not in directory? */
847     return NULL;
848
849 if (next_char_offset <= sp_globals.font_buff_size)/* Character data already in font buffer? */
850     return sp_globals.pfont->org + char_offset;  /* Return pointer into font buffer */
851
852 pchar_data = load_char_data(char_offset, no_bytes, sp_globals.cb_offset); /* Request char data load */
853 if (pchar_data->no_bytes < no_bytes)  /* Correct number of bytes loaded? */
854     return NULL;
855
856 if (top_level)                        /* Not element of compound char? */
857     {
858     sp_globals.cb_offset = no_bytes;
859     }
860
861 return pchar_data->org;               /* Return pointer into character data buffer */
862 }
863 #endif
864 \f
865 #if INCL_LCD
866 #else                  /* Dynamic load character data not supported? */
867 FUNCTION static ufix8 FONTFAR *sp_get_char_org(char_index, top_level)
868 GDECL
869 ufix16   char_index;   /* Index of character to be accessed */
870 boolean  top_level;    /* Not a compound character element */
871 /*
872  * Called by sp_get_char_id(), sp_get_char_width(), sp_make_char() and
873  * sp_make_comp_char() to get a pointer to the start of the character data
874  * for the specified character index.
875  * Version for configuration not supporting dynamic character data loading.
876  * Returns NULL if character data not available
877  */
878 {
879 ufix8   FONTFAR *pointer;      /* Pointer into character directory */
880 ufix8    format;       /* Character directory format byte */
881 fix31    char_offset;  /* Offset of char data from start of font file */
882 fix31    next_char_offset; /* Offset of char data from start of font file */
883 fix15    no_bytes;     /* Number of bytes required for char data */
884
885 if (top_level)                        /* Not element of compound char? */
886     {
887     if (char_index < sp_globals.first_char_idx)  /* Before start of character set? */
888         return NULL;
889     char_index -= sp_globals.first_char_idx;
890     if (char_index >= sp_globals.no_chars_avail) /* Beyond end of character set? */
891         return NULL;
892     }
893
894 pointer = sp_globals.pchar_dir;
895 format = NEXT_BYTE(pointer);          /* Read character directory format byte */
896 pointer += char_index << 1;           /* Point to indexed character entry */
897 if (format)                           /* 3-byte entries in char directory? */
898     {
899     pointer += char_index;            /* Adjust for 3-byte entries */
900     char_offset = read_long(pointer); /* Read file offset to char data */
901     next_char_offset = read_long(pointer + 3); /* Read offset to next char */
902     }
903 else
904     {
905     char_offset = (fix31)(0xffff & NEXT_WORD(pointer)); /* Read file offset to char data */
906     next_char_offset = (fix31)(0xffff & NEXT_WORD(pointer)); /* Read offset to next char */
907     }
908
909 no_bytes = next_char_offset - char_offset;
910 if (no_bytes == 0)                    /* Character not in directory? */
911     return NULL;
912
913 return sp_globals.pfont->org + char_offset;      /* Return pointer into font buffer */
914 }
915 #endif
916
917 \f
918 FUNCTION static fix15 sp_get_posn_arg(ppointer, format)
919 GDECL
920 ufix8 FONTFAR * STACKFAR *ppointer;     /* Pointer to first byte of position argument */
921 ufix8    format;       /* Format of DOCH arguments */
922 /*
923  * Called by sp_make_comp_char() to read a position argument from the
924  * specified point in the font/char buffer.
925  * Updates pointer to byte following position argument.
926  * Returns value of position argument in outline resolution units
927  */
928 {
929 switch (format & 0x03)
930     {
931 case 1:
932     return NEXT_WORD(*ppointer);
933
934 case 2:
935     return (fix15)((fix7)NEXT_BYTE(*ppointer));
936
937 default:
938     return (fix15)0;
939     }
940 }
941 \f
942 FUNCTION static fix15 sp_get_scale_arg(ppointer, format)
943 GDECL
944 ufix8 FONTFAR *STACKFAR *ppointer;     /* Pointer to first byte of position argument */
945 ufix8    format;       /* Format of DOCH arguments */
946 /*
947  * Called by sp_make_comp_char() to read a scale argument from the
948  * specified point in the font/char buffer.
949  * Updates pointer to byte following scale argument.
950  * Returns value of scale argument in scale units (normally 1/4096)
951  */
952 {
953 if (format)
954     return NEXT_WORD(*ppointer);
955 else
956     return (fix15)ONE_SCALE;
957 }
958 #if INCL_ISW || INCL_SQUEEZING
959 FUNCTION static void preview_bounding_box(pointer,format)
960 GDECL
961 ufix8 FONTFAR  *pointer;      /* Pointer to first byte of position argument */
962 ufix8    format;       /* Character format byte */
963 {
964 point_t  Pmin, Pmax;   /* Transformed corners of bounding box */
965
966     sp_globals.no_X_orus = (format & BIT2)?
967         (fix15)NEXT_BYTE(pointer):
968         0;
969     sp_globals.no_Y_orus = (format & BIT3)?
970         (fix15)NEXT_BYTE(pointer):
971         0;
972     pointer = read_oru_table(pointer);
973
974     /* Skip over control zone table */
975     pointer = skip_control_zone(pointer,format);
976
977     /* Skip over interpolation table */
978     pointer = skip_interpolation_table(pointer,format);
979     /* get_args has a pathological need for this value to be set */
980     sp_globals.Y_edge_org = sp_globals.no_X_orus;
981     pointer = read_bbox(pointer, &Pmin, &Pmax, TRUE);        /* Read bounding bo
982 x */
983
984 }
985 #endif
986 #if INCL_ISW
987 FUNCTION static boolean reset_xmax(xmax)
988 GDECL
989 fix31   xmax;
990
991 {
992 fix15   xmin;          /* Minimum X ORU value in font */
993 fix15   ymin;          /* Minimum Y ORU value in font */
994 fix15   ymax;          /* Maximum Y ORU value in font */
995
996
997 sp_globals.isw_modified_constants = TRUE;
998 xmin = read_word_u(sp_globals.font_org + FH_FXMIN);
999 ymin = read_word_u(sp_globals.font_org + FH_FYMIN);
1000 ymax = read_word_u(sp_globals.font_org + FH_FYMAX);
1001
1002 if (!setup_consts(xmin,xmax,ymin,ymax))
1003     {
1004     report_error(3);           /* Requested specs out of range */
1005     return FALSE;
1006     }
1007 sp_globals.constr.data_valid = FALSE;
1008 /* recompute setwidth */
1009 sp_globals.Psw.x = (fix15)((fix31)(
1010      ((fix31)sp_globals.imported_width * (sp_globals.specs.xxmult>>16) +
1011      ( ((fix31)sp_globals.imported_width *
1012           (sp_globals.specs.xxmult&0xffffL) )>>16)
1013      ) << sp_globals.pixshift) / sp_globals.metric_resolution);
1014 sp_globals.Psw.y = (fix15)(   
1015                   (fix31)( 
1016                  ((fix31)sp_globals.imported_width * (sp_globals.specs.yxmult>>16) + 
1017                 ( ((fix31)sp_globals.imported_width * (sp_globals.specs.yxmult&0xffffL) )>>16) 
1018                   ) << sp_globals.pixshift) / sp_globals.metric_resolution);
1019                
1020 return TRUE;
1021 }
1022 #endif