Cleanup of -Wpointer-compare warnings.
[oweals/cde.git] / cde / lib / DtHelp / Layout.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: Layout.c /main/31 1996/10/25 12:00:15 cde-hp $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:        Layout.c
28  **
29  **   Project:     CDE Info System
30  **
31  **   Description: Lays out the information on a canvas.
32  **
33  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
34  **
35  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
36  **  (c) Copyright 1993, 1994 International Business Machines Corp.
37  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
38  **  (c) Copyright 1993, 1994 Novell, Inc.
39  **
40  **
41  ****************************************************************************
42  ************************************<+>*************************************/
43
44 /*
45  * system includes
46  */
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <limits.h>
51
52 /*
53  * Canvas Engine includes
54  */
55 #include "CanvasP.h"
56 #include "CanvasSegP.h"
57
58 /*
59  * private includes
60  */
61 #include "bufioI.h"
62 #include "CanvasI.h"
63 #include "CvStringI.h"
64 #include "LayoutUtilI.h"
65 #include "SelectionI.h"
66 #include "VirtFuncsI.h"
67
68 #ifdef NLS16
69 #include <nl_types.h>
70 #endif
71
72 /******************************************************************************
73  *
74  * Private Macros
75  *
76  *****************************************************************************/
77 #define ObjHorizOrient(x)       (_DtCvContainerOrientOfSeg(x))
78 #define ObjVertOrient(x)        (_DtCvContainerVOrientOfSeg(x))
79 #define TxtHorizJustify(x)      (_DtCvContainerJustifyOfSeg(x))
80 #define TxtVertJustify(x)       (_DtCvContainerVJustifyOfSeg(x))
81 #define Border(x)               (_DtCvContainerBorderOfSeg(x))
82 #define BrdWidth(x)             (_DtCvContainerLineWidthOfSeg(x))
83 #define BrdData(x)              (_DtCvContainerLineDataOfSeg(x))
84 #define NotJoining(x)           (False == (x)->info.join)
85 #define JoinSet(x)              (True == (x)->info.join)
86
87 #define CheckAddToHyperList(a, b) \
88         _DtCvCheckAddHyperToTravList(a, b, _DtCvTRUE, \
89                         &(layout->info.lst_vis), \
90                         &(layout->info.lst_hyper), &(layout->info.cur_len))
91
92 /*****************************************************************************
93  *              Private Defines
94  *****************************************************************************/
95 /*
96  * Defines for the dimension arrays
97  */
98 #define DIMS_LEFT       0
99 #define DIMS_RIGHT      1
100
101 #define DIMS_LM         0
102 #define DIMS_CENTER     1
103 #define DIMS_RM         2
104
105 #define DIMS_TOP        0
106 #define DIMS_BOTTOM     2
107
108 #define DIMS_WIDTH      0
109 #define DIMS_HEIGHT     1
110 #define DIMS_YPOS       1
111
112 #define DIMS_TC         0
113 #define DIMS_BC         1
114
115
116 /*
117  */
118 #define GROW_SIZE       10
119
120 /******************************************************************************
121  *
122  * Private typedefs
123  *
124  *****************************************************************************/
125 /*
126  * top/bottom dimension array
127  *                  -------------------------------------------
128  *                 / DIMS_HEIGHT / DIMS_HEIGHT / DIMS_HEIGHT /|
129  *                /   DIMS_YPOS /   DIMS_YPOS /   DIMS_YPOS / |
130  *               /-------------/-------------/-------------/  |
131  *              / DIMS_WIDTH  / DIMS_WIDTH  / DIMS_WIDTH  /| /|
132  *             --------------|-------------|-------------| |/ |
133  * DIMS_TOP    |   DIMS_LM   | DIMS_CENTER |   DIMS_RM   | | /|
134  *             |-------------|-------------|-------------|/|/ |
135  *  unused     |             |             |             | | /
136  *             |-------------|-------------|-------------|/|/
137  * DIMS_BOTTOM |   DIMS_LM   | DIMS_CENTER |   DIMS_RM   | /
138  *             ------------------------------------------|/
139  */
140 typedef _DtCvUnit       TopDims[DIMS_BOTTOM+1][DIMS_RM+1][DIMS_HEIGHT+1];
141
142 /* 
143  * left/right side dimension array - contains only the height or y_pos.
144  *             ----------------------------
145  * DIMS_TOP    |  DIMS_LEFT | DIMS_RIGHT  |
146  *             |------------|-------------|
147  * DIMS_CENTER |  DIMS_LEFT | DIMS_RIGHT  |
148  *             |------------|-------------|
149  * DIMS_BOTTOM |  DIMS_LEFT | DIMS_RIGHT  |
150  *             ----------------------------
151  */
152 typedef _DtCvUnit       SideDims[DIMS_BOTTOM+1][DIMS_RIGHT+1];
153
154 /*
155  * corner dimension array - contains only the height or y_pos.
156  *            ----------------------------
157  * DIMS_TC    |  DIMS_LEFT | DIMS_RIGHT  |
158  *            |------------|-------------|
159  * DIMS_BC    |  DIMS_LEFT | DIMS_RIGHT  |
160  *            ----------------------------
161  */
162 typedef _DtCvUnit       CornerDims[DIMS_BC+1][DIMS_RIGHT+1];
163
164 /*
165  * flow dimension array
166  *            -------------|--------------
167  * DIMS_LEFT  | DIMS_WIDTH | DIMS_HEIGHT |
168  *            |            |  DIMS_YPOS  |
169  *            |------------|-------------|
170  * DIMS_RIGHT | DIMS_WIDTH | DIMS_HEIGHT |
171  *            |            |  DIMS_YPOS  |
172  *            ----------------------------
173  */
174 typedef _DtCvUnit       FlowDims[DIMS_RIGHT+1][DIMS_HEIGHT+1];
175
176 /*
177  * margin data - important for determining flowing
178  */
179 typedef struct  _dataPoint {
180         _DtCvUnit       left;
181         _DtCvUnit       right;
182         _DtCvUnit       y_pos;
183         _DtCvUnit       x_units;
184         struct _dataPoint *next_pt;
185 } DataPoint;
186
187 /*
188  * count information
189  */
190 typedef struct  _cntInfo {
191         int             beg_txt;
192         int             end_txt;
193         int             beg_ln;
194         int             end_ln;
195         int             my_lines;
196         int             beg_brk;
197         int             end_brk;
198 } CntInfo;
199
200 /*
201  * group information
202  */
203 typedef struct  _grpInfo {
204         _DtCvUnit       min_x;
205         _DtCvUnit       max_x;
206         _DtCvUnit       top_y;
207         _DtCvUnit       bot_y;
208         CntInfo         cnt;
209         struct _grpInfo *next_info;
210 } GrpInfo;
211
212 /*
213  * layout information per container
214  */
215 typedef struct  _layFrmtInfo {
216         _DtCvUnit       height;
217         _DtCvUnit       width;
218         CntInfo         cnt;
219         struct _layFrmtInfo *next_info;
220 } LayFrmtInfo;
221
222 /*
223  * the layout information carried around
224  */
225 typedef struct  _layoutInfo {
226         _DtCvUnit        max_width;     /* the current max width             */
227         _DtCvUnit        id_Ypos;       /* the y coordinate of the id found. */
228         _DtCvUnit        left;          /* the current left margin for the
229                                            current active container (incl br)*/
230         _DtCvUnit        right;         /* the current right margin for the
231                                            current active container (incl br)*/
232         _DtCvUnit        first;         /* the current first indent          */
233         _DtCvUnit        lmargin;       /* the current absolute left  margin */
234         _DtCvUnit        rmargin;       /* the current absolute right margin */
235         _DtCvUnit        divisor;       /* the current margin divisor        */
236         _DtCvUnit        string_end;
237         _DtCvUnit        sub_end;
238         _DtCvUnit        super_end;
239         _DtCvValue       id_found;      /* indicates if the id has been found*/
240         _DtCvValue       super_script;
241         _DtCvValue       sub_script;
242         _DtCvValue       stat_flag;
243         _DtCvValue       margin_non_zero;
244         _DtCvValue       brdr_flag;     /* within container with a border    */
245         _DtCvValue       table_flag;    /* within table                      */
246         _DtCvFrmtOption  txt_justify;
247         unsigned int     cur_start;     /* offset into the current segment
248                                            to process                        */
249         _DtCvSegmentI   *lst_rendered;  /* indicates the last string/region  */
250         char            *target_id;     /* if non-null, the id to search for */
251         DataPoint       *data_pts;
252         GrpInfo         *grp_lst;       /* list of groups               */
253         _DtCvLayoutInfo  info;
254 } LayoutInfo;
255
256 /*
257  * information for laying out cells in a table.
258  */
259 typedef struct  {
260         int              col_spn;
261         int              row_spn;
262         _DtCvUnit        pos_x;
263         LayFrmtInfo      info;
264         _DtCvSegmentI   *cell_seg;
265 } CellInfo;
266
267 /*
268  * column description information for a table.
269  */
270 typedef struct _columnSpec {
271         _DtCvUnit       min;
272         _DtCvUnit       max;
273         _DtCvUnit       actual;
274         _DtCvValue      hanger;
275         _DtCvFrmtOption justify;
276 } ColumnSpec;
277
278 /*
279  * row description information
280  */
281 typedef struct  _rowSpec {
282         int              column;
283         _DtCvUnit        y_adj;
284         _DtCvUnit        height;
285         _DtCvUnit        lst_height;
286         char            *next_id;
287 } RowSpec;
288
289 /*****************************************************************************
290  *              Private Variables/Data
291  *****************************************************************************/
292 static const LayFrmtInfo DefLayFrmtInfo = { 0, 0, {-1, -1, -1, -1, 0}, NULL };
293 static const GrpInfo     DefGrpInfo     = { 0, 0, 0, 0, {-1, -1, -1, -1, 0}};
294
295 static  const LayoutInfo DefInfo = {
296         0,              /* _DtCvUnit     max_width;    */
297         0,              /* _DtCvUnit     id_Ypos;      */
298         0,              /* _DtCvUnit     left;         */
299         0,              /* _DtCvUnit     right;        */
300         0,              /* _DtCvUnit     first;        */
301         0,              /* _DtCvUnit     lmargin;      */
302         0,              /* _DtCvUnit     rmargin;      */
303         1,              /* _DtCvUnit     divisor;      */
304         0,              /* _DtCvUnit     string_end;   */
305         0,              /* _DtCvUnit     sub_end;      */
306         0,              /* _DtCvUnit     super_end;    */
307         False,          /* _DtCvValue    id_found;     */
308         False,          /* _DtCvValue    super_script; */
309         False,          /* _DtCvValue    sub_script;   */
310         False,          /* _DtCvValue    stat_flag;    */
311         False,          /* _DtCvValue    margin_non_zero; */
312         False,          /* _DtCvValue    brdr_flag;    */
313         False,          /* _DtCvValue    table_flag;   */
314         _DtCvJUSTIFY_LEFT,      /* _DtCvFrmtOption txt_justify;   */
315         0,              /* unsigned int  cur_start;    */
316         NULL,           /* _DtCvSegmentI *lst_rendered; */
317         NULL,           /* char         *target_id;    */
318         NULL,           /* DataPoint    *data_pts;     */
319         NULL,           /* GrpInfo      *data_pts;     */
320 };
321
322 static const DataPoint  DefDataPt = { 0, 0, _CEFORMAT_ALL, 0, NULL};
323
324 static const double     HeadDivisor = 10000.0;
325
326 static const char *PeriodStr = ".";
327
328 static const char  *DefWidth[2] = { "", NULL };
329
330 static  const   _DtCvSegmentI   BlankTableCell =
331   {
332         _DtCvCONTAINER,         /* type         */
333         -1,                     /* link_idx     */
334           {                     /* container info */
335             NULL,                 /* id           */
336             NULL,                 /* justify_char */
337             _DtCvDYNAMIC,         /* type         */
338             _DtCvBORDER_NONE,     /* border       */
339             _DtCvJUSTIFY_LEFT,    /* justify      */
340             _DtCvJUSTIFY_TOP,     /* vjustify     */
341             _DtCvJUSTIFY_LEFT,    /* orient       */
342             _DtCvJUSTIFY_TOP,     /* vorient      */
343             _DtCvWRAP_NONE,       /* flow         */
344             0,                    /* percent      */
345             0,                    /* leading      */
346             0,                    /* fmargin      */
347             0,                    /* lmargin      */
348             0,                    /* rmargin      */
349             0,                    /* tmargin      */
350             0,                    /* bmargin      */
351             _DtCvBORDER_NONE,  /* bdr_info     */
352             NULL                  /* seg_list     */
353           },
354         NULL,                   /* next_seg     */
355         NULL,                   /* next_disp    */
356         NULL,                   /* client_use   */
357         NULL                    /* internal_use */
358   };
359
360 /*****************************************************************************
361  *              Private Function Declarations
362  *****************************************************************************/
363 static  void            AdjustForBorders(
364                                 _DtCanvasStruct *canvas,
365                                 LayoutInfo      *layout,
366                                 _DtCvFrmtOption  brdr,
367                                 _DtCvUnit        line_width,
368                                 _DtCvUnit       *ret_bot,
369                                 _DtCvUnit       *ret_right);
370 static  void            AdjustHeadPosition(
371                                 _DtCanvasStruct *canvas,
372                                 LayoutInfo      *layout,
373                                 _DtCvSegmentI   *p_seg,
374                                 TopDims         *top_bot,
375                                 SideDims        *side,
376                                 CornerDims      *corner,
377                                 FlowDims        *flow,
378                                 LayFrmtInfo     *info,
379                                 _DtCvUnit        base_y,
380                                 _DtCvUnit        base_left,
381                                 _DtCvUnit        block_width,
382                                 _DtCvUnit        left_margin,
383                                 _DtCvUnit        right_margin);
384 static  void            AdjustObjectPosition(
385                                 _DtCanvasStruct *canvas,
386                                 LayoutInfo      *layout,
387                                 _DtCvFrmtOption  justify,
388                                 int              start_txt,
389                                 int              start_ln,
390                                 int              start_brk,
391                                 int              end_txt,
392                                 int              end_ln,
393                                 int              end_brk,
394                                 int              brdr_cnt,
395                                 _DtCvUnit        height_adj,
396                                 _DtCvUnit        x_adj,
397                                 _DtCvUnit        y_adj,
398                                 _DtCvUnit        internal_y);
399 static  void            CheckSaveInfo (
400                                 _DtCanvasStruct *canvas,
401                                 LayoutInfo      *layout,
402                                 _DtCvSegmentI   *new_seg,
403                                 int              start);
404 static  void            DetermineFlowConstraints(
405                                 LayoutInfo      *layout,
406                                 FlowDims         flow_dims,
407                                 _DtCvUnit        left_margin,
408                                 _DtCvUnit        right_margin,
409                                 _DtCvUnit        start_y,
410                                 DataPoint       *left_pt,
411                                 DataPoint       *right_pt);
412 static  void            DetermineHeadPositioning(
413                                 TopDims *top_bot,
414                                 SideDims        *side,
415                                 CornerDims      *corner,
416                                 FlowDims        *flow,
417                                 _DtCvUnit        start_y,
418                                 _DtCvUnit        max_top,
419                                 _DtCvUnit        block_size,
420                                 _DtCvUnit       *ret_side_size);
421 static  void            DetermineMaxDims(
422                                 TopDims         *top_bot,
423                                 CornerDims      *corner,
424                                 _DtCvUnit        left_margin,
425                                 _DtCvUnit        right_margin,
426                                 _DtCvUnit       *top_height,
427                                 _DtCvUnit       *bot_height,
428                                 _DtCvUnit       *max_width);
429 static  int             DrawBorders(
430                                 _DtCanvasStruct *canvas,
431                                 LayoutInfo      *layout,
432                                 _DtCvFrmtOption  brdr,
433                                 _DtCvPointer     data,
434                                 _DtCvUnit        line_width,
435                                 _DtCvUnit        top_y,
436                                 _DtCvUnit        bot_y,
437                                 _DtCvUnit        left_x,
438                                 _DtCvUnit        right_x);
439 static void             FormatCell(
440                                 _DtCanvasStruct *canvas,
441                                 LayoutInfo      *layout,
442                                 _DtCvSegmentI   *cell_seg,
443                                 _DtCvUnit        span_width,
444                                 _DtCvUnit        min_height,
445                                 DataPoint        base_pt,
446                                 int             *ret_ln,
447                                 _DtCvUnit       *ret_width,
448                                 _DtCvUnit       *ret_height,
449                                 _DtCvValue      *ret_tab_flag);
450 static  void            InitDimArrays(
451                                 TopDims         *top_bot,
452                                 SideDims        *side,
453                                 CornerDims      *corner,
454                                 FlowDims        *flow);
455 static _DtCvStatus      LayoutCanvasInfo (
456                                 _DtCanvasStruct *canvas,
457                                 LayoutInfo      *layout,
458                                 _DtCvUnit        divisor,
459                                 char            *target_id);
460 static _DtCvValue       LinesMayChange(
461                                 _DtCanvasStruct *canvas,
462                                 int              start_ln,
463                                 int              end_ln,
464                                 int              brdr_cnt);
465 static _DtCvUnit        MoveGroup (
466                                 _DtCanvasStruct *canvas,
467                                 LayoutInfo      *layout,
468                                 GrpInfo         *tst_grp,
469                                 _DtCvUnit        needed);
470 static _DtCvUnit        MoveLines (
471                                 _DtCanvasStruct *canvas,
472                                 LayoutInfo      *layout,
473                                 int              idx,
474                                 _DtCvUnit        top_y,
475                                 _DtCvUnit        bot_y,
476                                 _DtCvUnit        needed);
477 static _DtCvUnit        MoveText (
478                                 _DtCanvasStruct *canvas,
479                                 LayoutInfo      *layout,
480                                 int              idx,
481                                 _DtCvUnit        top_y,
482                                 _DtCvUnit        bot_y,
483                                 _DtCvUnit        needed);
484 static void             ProcessContainer(
485                                 _DtCanvasStruct *canvas,
486                                 LayoutInfo      *layout,
487                                 _DtCvSegmentI   *con_seg,
488                                 _DtCvUnit        min_y,
489                                 _DtCvUnit       *ret_width,
490                                 _DtCvUnit       *ret_max_x,
491                                 int             *ret_cnt);
492 static  void            ProcessSegmentList(
493                                 _DtCanvasStruct *canvas,
494                                 LayoutInfo      *layout,
495                                 _DtCvSegmentI   *cur_seg,
496                                 _DtCvUnit        min_y,
497                                 _DtCvUnit       *ret_width,
498                                 _DtCvUnit       *ret_max_x,
499                                 int             **ret_vert);
500
501 /******************************************************************************
502  *
503  * Private Functions
504  *
505  *****************************************************************************/
506 /******************************************************************************
507  * Function: AdjustTextPositions
508  *
509  * changes the baseline and text_x positioning of the text line by the
510  * offsets indicated.
511  *****************************************************************************/
512 static void
513 AdjustTextPositions(
514     _DtCanvasStruct     *canvas,
515     int                  beg,
516     int                  end,
517     _DtCvUnit            x_offset,
518     _DtCvUnit            y_offset)
519 {
520     if ( 0 != y_offset || 0 != x_offset)
521       {
522         while (beg < end)
523           {
524             canvas->txt_lst[beg].baseline += y_offset;
525             canvas->txt_lst[beg].text_x   += x_offset;
526             beg++;
527           }
528       }
529 }
530
531 /******************************************************************************
532  * Function: AdjustLinePositions
533  *
534  * changes the x & positions and the max x & y values by the offsets indicated.
535  *****************************************************************************/
536 static void
537 AdjustLinePositions(
538     _DtCanvasStruct     *canvas,
539     int                  beg,
540     int                  end,
541     _DtCvUnit            x_offset,
542     _DtCvUnit            y_offset)
543 {
544     if ( 0 != y_offset || 0 != x_offset)
545       {
546         while (beg < end)
547           {
548             canvas->line_lst[beg].pos_y += y_offset;
549             canvas->line_lst[beg].max_y += y_offset;
550             canvas->line_lst[beg].pos_x += x_offset;
551             canvas->line_lst[beg].max_x += x_offset;
552
553             beg++;
554           }
555       }
556 }
557
558 /******************************************************************************
559  * Function: AdjustPgBrk
560  *
561  * changes the y position of a page break.
562  *****************************************************************************/
563 static void
564 AdjustPgBrk(
565     _DtCanvasStruct     *canvas,
566     int                  beg,
567     int                  end,
568     _DtCvUnit            y_offset)
569 {
570     if (0 != y_offset)
571       {
572         while (beg < end)
573             canvas->pg_breaks[beg++] += y_offset;
574       }
575 }
576
577 /******************************************************************************
578  * Function: MaxXOfLine
579  *
580  *  MaxXOfLine determines the max X of a line segment.
581  *
582  *****************************************************************************/
583 /******************************************************************************
584  * Function: MaxXOfLine
585  *
586  *  MaxXOfLine determines the max X of a line segment.
587  *
588  *****************************************************************************/
589 static _DtCvUnit
590 MaxXOfLine(
591     _DtCanvasStruct     *canvas,
592     _DtCvDspLine        *line)
593 {
594     _DtCvValue   lastLinkVisible = FALSE;
595     int          count        = line->length;
596     int          start        = line->byte_index;
597     int          len;
598     int          lnkInd = -1;
599     _DtCvUnit    xPos;
600     _DtCvUnit    tmpWidth;
601     _DtCvSegmentI *pSeg;
602
603     xPos = _DtCvGetStartXOfLine(line, &pSeg);
604
605     while (pSeg != NULL && count > 0)
606       {
607         xPos = _DtCvAdvanceXOfLine(canvas, pSeg, xPos,
608                                                 &lnkInd, &lastLinkVisible);
609
610         _DtCvGetWidthOfSegment(canvas, pSeg, start, count,
611                                                         &len, &tmpWidth, NULL);
612         xPos  += tmpWidth;
613         count -= len;
614         start  = 0;
615         pSeg   = pSeg->next_disp;
616       }
617
618     return xPos;
619
620 } /* End MaxXOfLine */
621
622 /*****************************************************************************
623  * Function:    void GetLinkInfo ()
624  *
625  * Parameters:
626  *              canvas          Specifies the handle for the canvas.
627  *
628  * Returns:     A handle to the canvas or NULL if an error occurs.
629  *
630  * Purpose:
631  *
632  *****************************************************************************/
633 static _DtCvValue
634 GetLinkInfo (
635     _DtCvHandle   canvas_handle,
636     int           indx,
637     _DtCvUnit    *ret_x,
638     _DtCvUnit    *ret_y,
639     _DtCvUnit    *ret_width,
640     _DtCvUnit    *ret_height)
641 {
642     int                  len;
643     int                  line;
644     int                  count;
645     int                  startChar;
646     int                  lnkIndx   = -1;
647     _DtCvUnit            startX;
648     _DtCanvasStruct     *canvas    = (_DtCanvasStruct *) canvas_handle;
649     _DtCvSegmentI       *pSeg;
650     _DtCvValue           lstVisible = False;
651     _DtCvValue           found      = False;
652     _DtCvValue           junk;
653     _DtCvUnit  endX = 0;
654     void                *pChar;
655
656     /*
657      * get the line index
658      */
659     line        = canvas->trav_lst[indx].idx;
660
661     /*
662      * get some information from the line
663      */
664     pSeg        = canvas->txt_lst[line].seg_ptr;
665     count       = canvas->txt_lst[line].length;
666     startChar   = canvas->txt_lst[line].byte_index;
667     startX      = canvas->txt_lst[line].text_x;
668     *ret_y      = canvas->txt_lst[line].baseline - canvas->txt_lst[line].ascent;
669     *ret_height = canvas->txt_lst[line].ascent + canvas->txt_lst[line].descent;
670
671     while (count > 0 && !found && pSeg != NULL)
672       {
673         if (startX < canvas->txt_lst[line].text_x)
674             startX = canvas->txt_lst[line].text_x;
675
676         /*
677          * adjust the starting position by the link space
678          */
679         junk = _DtCvIsSegVisibleLink(pSeg);
680         lstVisible = _DtCvModifyXpos (canvas->link_info, pSeg, junk,
681                     lstVisible, lnkIndx, &startX);
682         /*
683          * adjust the starting position by the traversal space
684          */
685         junk = _DtCvIsSegALink(pSeg);
686         (void) _DtCvModifyXpos (canvas->traversal_info, pSeg, junk,
687                     ((_DtCvValue) True), lnkIndx, &startX);
688
689         lnkIndx = pSeg->link_idx;
690
691         /*
692          * skip no-op
693          */
694         if (_DtCvIsSegNoop(pSeg))
695             len = 0;
696   
697         /*
698          * check region
699          */
700         else if (_DtCvIsSegRegion(pSeg))
701           {
702             len  = 1;
703             endX = startX + _DtCvWidthOfRegionSeg(pSeg);
704           }
705         else
706           {
707             /*
708              * initialize the pointer to the string
709              */
710             pChar = _DtCvStrPtr(_DtCvStringOfStringSeg(pSeg),
711                                         _DtCvIsSegWideChar(pSeg), startChar);
712  
713             /*
714              * get the length of the current string.
715              * If it is longer than the line count indicates,
716              * it must be wrapped to the next line. We are
717              * only interested in in the part of the line
718              * that is on the line selected.
719              */
720             len = _DtCvStrLen (pChar, _DtCvIsSegWideChar(pSeg));
721             if (len > count)
722                 len = count;
723          
724             /*
725              * calculate the ending pixel postion for
726              * this string segment.
727              */
728             endX = startX + _DtCvGetStringWidth(canvas,pSeg,pChar,len);
729
730           }
731
732         /*
733          * test to see if the selected segment was this segment.
734          */
735         if (pSeg == canvas->trav_lst[indx].seg_ptr)
736           {
737             found = True;
738             *ret_x     = startX;
739             *ret_width = endX - startX;
740           }
741         else
742           {
743             /*
744              * go to the next segment.
745              */
746             pSeg = pSeg->next_disp;
747
748             /*
749              * adjust for the new begining.
750              */
751             startX    = endX;
752             count     = count - len;
753             startChar = 0;
754           }
755       }
756
757     return found;
758 }
759 /******************************************************************************
760  * Function: CheckId
761  *
762  * Check to see if the id matches the target id.
763  * If so, set the 'found id' flag and indicate its y coordinate.
764  *****************************************************************************/
765 static void
766 CheckId(
767     LayoutInfo          *layout,
768     char                *id)
769 {
770     if (layout->target_id != NULL && NULL != id &&
771                         _DtCvStrCaseCmpLatin1(id, layout->target_id) == 0)
772       {
773         layout->id_Ypos  = layout->info.y_pos;
774         layout->id_found = True;
775       }
776 }
777
778 /******************************************************************************
779  * Function: CheckSetLineStart
780  *
781  * Check to see if the line information is at the beginning.
782  * If so, set the pointers to the current segment and offset.
783  *****************************************************************************/
784 static void
785 CheckSetLineStart(
786     LayoutInfo          *layout,
787     _DtCvSegmentI       *cur_seg)
788 {
789     if (layout->info.line_bytes == 0)
790       {
791         layout->info.line_seg   = cur_seg;
792         layout->info.line_start = 0;
793       }
794 }
795
796 /******************************************************************************
797  * Function: CheckForPageBreak
798  *
799  * Check to see if there is a page break on this segment.
800  * If so, remember its position.
801  *****************************************************************************/
802 static int
803 CheckForPageBreak(
804     _DtCanvasStruct     *canvas,
805     _DtCvSegmentI       *cur_seg,
806     _DtCvUnit            position)
807 {
808     /*
809      * does this segment cause a page break?
810      */
811     if (_DtCvIsSegPageBreak(cur_seg))
812       {
813         /*
814          * check to see if there is room to save the page break.
815          * if not, allocate more room.
816          */
817         if (canvas->brk_cnt >= canvas->brk_max)
818           {
819             canvas->brk_max += GROW_SIZE;
820             if (NULL != canvas->pg_breaks)
821                 canvas->pg_breaks = (_DtCvUnit *) realloc (
822                                         (void *) canvas->pg_breaks,
823                                         (sizeof(_DtCvUnit) * canvas->brk_max));
824             else
825                 canvas->pg_breaks = (_DtCvUnit *) malloc (
826                                         (sizeof(_DtCvUnit) * canvas->brk_max));
827           }
828
829         /*
830          * failed to allocate memory, abort.
831          */
832         if (NULL == canvas->pg_breaks)
833           {
834             canvas->brk_max = 0;
835             canvas->brk_cnt = 0;
836             return 1;
837           }
838
839         /*
840          * save the y position of the page break for later.
841          */
842         canvas->pg_breaks[canvas->brk_cnt++] = position;
843       }
844
845     return 0;
846 }
847
848 /******************************************************************************
849  * Function:    SetBeginCounts
850  *
851  * Parameters:
852  *              canvas  Specifies the canvas.
853  *              f_info  Specifies the layout count info.
854  *
855  * Returns:     Nothing
856  *
857  * Purpose:     Initializes the layout count information for a container.
858  *****************************************************************************/
859 static  void
860 SetBeginCounts (
861     _DtCanvasStruct     *canvas,
862     CntInfo             *cnt_info)
863 {
864     /*
865      * text counts
866      */
867     cnt_info->beg_txt = canvas->txt_cnt;
868     cnt_info->end_txt = canvas->txt_cnt;
869
870     /*
871      * line counts
872      */
873     cnt_info->beg_ln = canvas->line_cnt;
874     cnt_info->end_ln = canvas->line_cnt;
875
876     /*
877      * break counts
878      */
879     cnt_info->beg_brk = canvas->brk_cnt;
880     cnt_info->end_brk = canvas->brk_cnt;
881 }
882
883 /******************************************************************************
884  * Function:    SetEndCounts
885  *
886  * Parameters:
887  *              canvas  Specifies the canvas.
888  *              f_info  Specifies the layout count info.
889  *
890  * Returns:     Nothing
891  *
892  * Purpose:     Sets the ending layout counts for a container.
893  *****************************************************************************/
894 static  void
895 SetEndCounts (
896     _DtCanvasStruct     *canvas,
897     CntInfo             *cnt_info,
898     int                  end_ln)
899 {
900     /*
901      * text counts
902      */
903     cnt_info->end_txt = canvas->txt_cnt;
904
905     /*
906      * line counts
907      */
908     cnt_info->end_ln = canvas->line_cnt;
909
910     /*
911      * break counts
912      */
913     cnt_info->end_brk = canvas->brk_cnt;
914
915     /*
916      * the number of lines for this container.
917      * If negative, indicates the first line is for the
918      * bottom of the container and goes the length.
919      */
920     cnt_info->my_lines = end_ln;
921 }
922
923 /******************************************************************************
924  * Function:    SkipToNumber
925  *
926  * Returns:
927  *****************************************************************************/
928 static  void
929 SkipToNumber (
930     const char  **string)
931 {
932     if (string != NULL)
933       {
934         const char *str = *string;
935
936         while (*str == ' ' && *str != '\0')
937             str++;
938         *string = str;
939       }
940 }
941
942 /******************************************************************************
943  * Function:    GetValueFromString
944  *
945  * Returns:
946  *****************************************************************************/
947 static  int
948 GetValueFromString (
949     const char  **string,
950     int           def_num)
951 {
952     int  value = def_num;
953
954     if (string != NULL && *string != NULL && **string != '\0')
955       {
956         const char *str = *string;
957
958         if ('0' <= *str && *str <= '9')
959             value = atoi(str);
960
961         while ('0' <= *str && *str <= '9')
962             str++;
963
964         while (*str != ' ' && *str != '\0' && (*str < '0' || *str > '9'))
965             str++;
966
967         *string = str;
968       }
969
970     return value;
971 }
972
973 /******************************************************************************
974  * Function:    PushDataPoint
975  *
976  * Returns:
977  *****************************************************************************/
978 static  void
979 PushDataPoint (
980     LayoutInfo          *layout,
981     DataPoint           *data_pt)
982 {
983     data_pt->x_units = 0;
984     data_pt->next_pt = layout->data_pts;
985     layout->data_pts = data_pt;
986 }
987
988 /******************************************************************************
989  * Function:    InsertDataPoint
990  *
991  * Returns:
992  *****************************************************************************/
993 static  void
994 InsertDataPoint (
995     LayoutInfo          *layout,
996     DataPoint           *data_pt)
997 {
998     DataPoint   *lastPt = NULL;
999     DataPoint   *nextPt = layout->data_pts;
1000
1001     while (nextPt != NULL &&
1002         nextPt->y_pos != _CEFORMAT_ALL &&
1003         (data_pt->y_pos == _CEFORMAT_ALL || nextPt->y_pos < data_pt->y_pos))
1004       {
1005         lastPt = nextPt;
1006         nextPt = nextPt->next_pt;
1007       }
1008
1009     data_pt->next_pt = nextPt;
1010     data_pt->x_units = 0;
1011
1012     if (lastPt == NULL)
1013         layout->data_pts = data_pt;
1014     else
1015         lastPt->next_pt = data_pt;
1016 }
1017
1018 /******************************************************************************
1019  * Function:    RemoveDataPoint
1020  *
1021  * Returns:
1022  *****************************************************************************/
1023 static  void
1024 RemoveDataPoint (
1025     LayoutInfo          *layout,
1026     DataPoint           *data_pt)
1027 {
1028     DataPoint   *lastPt = NULL;
1029     DataPoint   *curPt  = layout->data_pts;
1030
1031     while (curPt != NULL && curPt != data_pt)
1032       {
1033         lastPt = curPt;
1034         curPt  = curPt->next_pt;
1035       }
1036
1037     if (curPt != NULL)
1038       {
1039         data_pt->x_units = layout->info.cur_max_x - data_pt->left;
1040         if (lastPt == NULL)
1041             layout->data_pts = curPt->next_pt;
1042         else
1043             lastPt->next_pt  = curPt->next_pt;
1044       }
1045 }
1046
1047 /******************************************************************************
1048  * Function:    GetCurrentDataPoint
1049  *
1050  * Returns:
1051  *****************************************************************************/
1052 static  void
1053 GetCurrentDataPoint (
1054     LayoutInfo          *layout,
1055     DataPoint           *data_pt)
1056 {
1057     data_pt->left  = 0;
1058     data_pt->right = 0;
1059     data_pt->y_pos = _CEFORMAT_ALL;
1060
1061     if (layout->data_pts != NULL)
1062         *data_pt = *(layout->data_pts);
1063 }
1064
1065 /******************************************************************************
1066  * Function:    SetMargins
1067  *
1068  * Purpose: Sets the margins.
1069  *****************************************************************************/
1070 static  void
1071 SetMargins (
1072     LayoutInfo          *layout)
1073 {
1074     layout->lmargin = 0;
1075     layout->rmargin = 0;
1076     layout->info.format_y = _CEFORMAT_ALL;
1077
1078     if (layout->data_pts != NULL)
1079       {
1080         /*
1081          * base 
1082          */
1083         layout->lmargin = layout->data_pts->left;
1084         layout->rmargin = layout->data_pts->right;
1085
1086         layout->info.format_y = layout->data_pts->y_pos;
1087       }
1088
1089     layout->lmargin += layout->left;
1090     layout->rmargin += layout->right;
1091 }
1092
1093 /******************************************************************************
1094  * Function:    SetTextPosition
1095  *
1096  * Purpose: Sets the text beginning position to the left margin.
1097  *          If 'first' is true, adds its value to the text beginning
1098  *          position value.
1099  *****************************************************************************/
1100 static  void
1101 SetTextPosition (
1102     LayoutInfo          *layout,
1103     _DtCvValue           first)
1104 {
1105     layout->info.text_x_pos = layout->lmargin;
1106     if (first == True)
1107         layout->info.text_x_pos += layout->first;
1108 }
1109
1110 /******************************************************************************
1111  * Function:    CheckFormat
1112  *
1113  * Purpose: Checks to see if the flowing txt boundaries have been exceeded.
1114  *          If a boundary has been exceeded, then removes that boundary
1115  *          information from the stack until it finds a valid boundary point.
1116  *
1117  *          Calls SetMargins to set the correct margin
1118  *          Calls SetTextPosition to set the text beginning position.
1119  *****************************************************************************/
1120 static  void
1121 CheckFormat (
1122     LayoutInfo          *layout,
1123     _DtCvValue           first)
1124 {
1125     while (layout->data_pts != NULL &&
1126                 layout->data_pts->y_pos != _CEFORMAT_ALL &&
1127                                 layout->data_pts->y_pos < layout->info.y_pos)
1128         RemoveDataPoint (layout, layout->data_pts);
1129
1130     SetMargins(layout);
1131     SetTextPosition(layout, first);
1132 }
1133
1134 /******************************************************************************
1135  * Function: SaveLine
1136  *
1137  * Initializes a line table element to the segment it should display.
1138  *****************************************************************************/
1139 static void
1140 SaveLine (
1141     _DtCanvasStruct     *canvas,
1142     LayoutInfo          *layout,
1143     int                  direction,
1144     _DtCvPointer         data,
1145     _DtCvUnit            line_width,
1146     _DtCvUnit            x,
1147     _DtCvUnit            y,
1148     _DtCvUnit            length)
1149 {
1150     int       i  = canvas->line_cnt;
1151     _DtCvUnit x2 = x;
1152     _DtCvUnit y2 = y;
1153
1154     if (i >= canvas->line_max)
1155       {
1156         canvas->line_max += GROW_SIZE;
1157         if (canvas->line_lst)
1158             canvas->line_lst = (_DtCvLineSeg *) realloc (
1159                                 (void *) canvas->line_lst,
1160                                 (sizeof(_DtCvLineSeg) * canvas->line_max));
1161         else
1162             canvas->line_lst = (_DtCvLineSeg *) malloc (
1163                                 (sizeof(_DtCvLineSeg) * canvas->line_max));
1164 /*
1165  * NOTE....should this routine return a value?
1166  * If (re)alloc error occurs, this simply ignores the problem.
1167  */
1168         if (canvas->line_lst == NULL)
1169           {
1170             canvas->line_max = 0;
1171             canvas->line_cnt = 0;
1172             return;
1173           }
1174       }
1175
1176     /*
1177      * does this line exceed the current maximum?
1178      */
1179     if (_DtCvLINE_HORZ == direction)
1180       {
1181         x2 += length;
1182         y2 += line_width;
1183       }
1184     else
1185       {
1186         x2 += line_width;
1187         y2 += length;
1188       }
1189
1190     if (layout->info.max_x_pos < x2)
1191         layout->info.max_x_pos = x2;
1192
1193     if (layout->info.cur_max_x < x2)
1194         layout->info.cur_max_x = x2;
1195
1196     /*
1197      * save the line information
1198      */
1199     canvas->line_lst[i].dir    = direction;
1200     canvas->line_lst[i].pos_x  = x;
1201     canvas->line_lst[i].max_x  = x2;
1202     canvas->line_lst[i].pos_y  = y;
1203     canvas->line_lst[i].max_y  = y2;
1204     canvas->line_lst[i].width  = line_width;
1205     canvas->line_lst[i].data   = data;
1206
1207     canvas->line_cnt++;
1208 }
1209
1210 /******************************************************************************
1211  * Function: SaveInfo
1212  *
1213  * Purpose: Saves the current information into the txt line struct.
1214  *          Checks to see if this line exceeds the flowing text
1215  *          boundary and resets the internal global margins.
1216  *****************************************************************************/
1217 static void
1218 SaveInfo (
1219     _DtCanvasStruct     *canvas,
1220     LayoutInfo          *layout,
1221     _DtCvSegmentI       *new_seg,
1222     int                  start)
1223 {
1224     _DtCvSaveInfo (canvas, &(layout->info),
1225                   layout->max_width, layout->rmargin, layout->txt_justify);
1226
1227     while (layout->info.delayed_search_saves > 0) {
1228         _DtCvSetSearchEntryInfo(canvas, canvas->txt_cnt - 1);
1229         layout->info.delayed_search_saves--;
1230     }
1231
1232     layout->super_end       = 0;
1233     layout->sub_end         = 0;
1234     layout->super_script    = False;
1235     layout->sub_script      = False;
1236     layout->info.line_seg   = new_seg;
1237     layout->info.line_start = start;
1238     layout->info.cur_len    = 0;
1239
1240     CheckFormat(layout, FALSE);
1241 }
1242
1243 /******************************************************************************
1244  * Function: CheckSaveInfo
1245  *
1246  * Purpose: Checks to see if there is any information to save and saves
1247  *          it if there is any.
1248  *****************************************************************************/
1249 static void
1250 CheckSaveInfo (
1251     _DtCanvasStruct     *canvas,
1252     LayoutInfo          *layout,
1253     _DtCvSegmentI       *new_seg,
1254     int                  start)
1255 {
1256     if (layout->info.line_bytes)
1257         SaveInfo (canvas, layout, new_seg, start);
1258 }
1259
1260 /******************************************************************************
1261  * Function: ProcessStringSegment
1262  *
1263  * chops a string segment up until its completely used.
1264  *
1265  *****************************************************************************/
1266 static void
1267 ProcessStringSegment(
1268     _DtCanvasStruct     *canvas,
1269     LayoutInfo          *layout,
1270     _DtCvSegmentI       *cur_seg)
1271 {
1272     layout->cur_start = 0;
1273     if (!(_DtCvIsSegSuperScript(cur_seg) || _DtCvIsSegSubScript(cur_seg))
1274         && (layout->super_script == True || layout->sub_script == True))
1275       {
1276         layout->super_end = 0;
1277         layout->sub_end   = 0;
1278         layout->super_script = False;
1279         layout->sub_script   = False;
1280       }
1281
1282     while (_DtCvProcessStringSegment(canvas, &(layout->info),
1283                         layout->max_width, layout->lmargin, layout->rmargin,
1284                         cur_seg , &(layout->cur_start),
1285                         layout->txt_justify, layout->stat_flag) == 1)
1286         CheckFormat(layout, False);
1287
1288 } /* End ProcessStringSegment */
1289
1290
1291 /******************************************************************************
1292  * Function: _DtCvUnit ResolveHeight(
1293  *
1294  * Parameters:
1295  *
1296  * Purpose: Determines the height of a row that is spanned.
1297  *****************************************************************************/
1298 static _DtCvUnit
1299 ResolveHeight(
1300     RowSpec  *row_info,
1301     CellInfo *cell_info,
1302     int       max_cols,
1303     int       row,
1304     int       span)
1305 {
1306     int i;
1307     int col;
1308     int cell;
1309     int topRow;
1310     int topCell;
1311     int zeroed;
1312     int total;
1313     int rowHeight = 0;
1314
1315     for (col = 0, cell = row * max_cols; col < max_cols; col++, cell++)
1316       {
1317         /*
1318          * if we have a row spanning cell in this column,
1319          * but it isn't from a previous column, try to fill out
1320          * the height using it.
1321          */
1322         if (cell_info[cell].row_spn == -1 && cell_info[cell].col_spn != -1)
1323           {
1324             /*
1325              * back up to the cell information containing the row
1326              * span value.
1327              */
1328             topRow  = row;
1329             topCell = cell;
1330             do
1331               {
1332                 topCell--;
1333                 topRow--;
1334               } while (cell_info[topCell].row_spn == -1);
1335
1336             /*
1337              * from here, start calculating the height of the row
1338              * spanning cell, and find out how big the row must
1339              * be to contain it.
1340              */
1341             i      = cell_info[topCell].row_spn;
1342             zeroed = span + 1;
1343             total  = 0;
1344             while (i > 0 && zeroed > 0)
1345               {
1346                 total += row_info[topRow].height;
1347                 if (row_info[topRow].height == 0)
1348                    zeroed--;
1349                 i--;
1350                 topRow++;
1351               }
1352
1353             /*
1354              * if zeroed is greater than zero, that means only the
1355              * allowd number of row heights were zeroed out (the ones
1356              * we are looking for).
1357              * go ahead and calculate a new height. Otherwise,
1358              * it may be tried later.
1359              */
1360             if (zeroed > 0)
1361               {
1362                 /*
1363                  * make sure we get a positive value out of
1364                  * this for our height.
1365                  */
1366                 if (cell_info[topCell].info.height > total)
1367                   {
1368                     total = cell_info[topCell].info.height - total;
1369                     total = total / span + (total % span ? 1 : 0);
1370                   }
1371
1372                 /*
1373                  * make sure we take the biggest value possible
1374                  * for this row. If it needs to be smaller for
1375                  * cells, we'll adjust the positioning within
1376                  * the cell.
1377                  */
1378                 if (rowHeight < total)
1379                     rowHeight = total;
1380               }
1381           }
1382       }
1383
1384    row_info[row].height = rowHeight;
1385    return rowHeight;
1386 }
1387
1388 /******************************************************************************
1389  * Function: void AdjustHeight(
1390  *
1391  * Parameters:
1392  *
1393  * Purpose: Determines the height of rows that are spanned but the 
1394  *          the spanner needs more room than the calculated row height
1395  *          allow.
1396  *****************************************************************************/
1397 static void
1398 AdjustHeight(
1399    CellInfo     *cell_info,
1400    RowSpec      *row_specs,
1401    int           max_cols,
1402    int           row,
1403    int           col)
1404 {
1405     int    cell = row * max_cols + col;
1406     int    i, j;
1407     _DtCvUnit   total;
1408     _DtCvUnit   adjustValue;
1409     _DtCvUnit   value;
1410
1411     if (cell_info[cell].col_spn == -1 || cell_info[cell].row_spn == -1)
1412         return;
1413
1414     for (j = row, i = 0, total = 0; i < cell_info[cell].row_spn; i++, j++)
1415         total += row_specs[j].height;
1416
1417     /*
1418      * adjust the row height to include all of the row spanning cell.
1419      */
1420     if (total < cell_info[cell].info.height)
1421       {
1422         _DtCvUnit   totalUsed = 0;
1423
1424         /*
1425          * first, try to grow the cells on a percentage basis.
1426          * This way, a small cell will grow the same amount relative
1427          * to the larger cells.
1428          */
1429         adjustValue = cell_info[cell].info.height - total;
1430
1431         /*
1432          * now if total is zero, we'll get a divide by zero error.
1433          * So check for this and set total to the number of rows spanned.
1434          */
1435         if (0 == total)
1436             total = cell_info[cell].row_spn;
1437
1438         for (i = 0; i < cell_info[cell].row_spn; i++)
1439           {
1440             value = (((row_specs[row + i].height * 100) / total) * adjustValue)
1441                                 / 100;
1442             row_specs[row + i].height += value;
1443             totalUsed                 += value;
1444           }
1445
1446         /*
1447          * if didn't use all the size up - apply it evenly.
1448          */
1449         if (totalUsed < adjustValue)
1450           {
1451             adjustValue = adjustValue - totalUsed;
1452             for (i = 0, j = cell_info[cell].row_spn;
1453                 adjustValue > 0 && i < cell_info[cell].row_spn; i++, j--)
1454               {
1455                 value = adjustValue / j + (adjustValue % j ? 1 : 0);
1456                 row_specs[row + i].height += value;
1457                 adjustValue               -= value;
1458                 totalUsed                 += value;
1459               }
1460           }
1461
1462         total = totalUsed;
1463       }
1464 }
1465
1466 /******************************************************************************
1467  * Function: void ReFormatCell(
1468  *
1469  * Parameters:
1470  *              canvas          Specifies the specific information about the
1471  *                              rendering area.
1472  *              layout          Specifies the currently active information
1473  *                              affecting the layout of information.
1474  *
1475  * Purpose: Based on a height and width, relay out the information in a cell.
1476  *****************************************************************************/
1477 static void
1478 ReFormatCell(
1479     _DtCanvasStruct     *canvas,
1480     LayoutInfo          *layout,
1481     CellInfo            *this_cell,
1482     ColumnSpec          *col_specs,
1483     int                  col,
1484     _DtCvUnit            new_height,
1485     _DtCvUnit            new_y)
1486 {
1487     int         i;
1488     int         saveTxt   = canvas->txt_cnt;
1489     int         saveLn    = canvas->line_cnt;
1490     _DtCvUnit   saveYpos  = layout->info.y_pos;
1491     _DtCvUnit   saveMaxX  = layout->info.cur_max_x;
1492     _DtCvUnit   cellWidth = 0;
1493     _DtCvUnit   junk;
1494     _DtCvValue  junkValue;
1495     DataPoint   basePt;
1496
1497     /*
1498      * reset the y_pos to the correct placement.
1499      * reset the line counts to the original values.
1500      * since we aren't changing the width, the number
1501      * of lines used will not change.
1502      */
1503     layout->info.y_pos = new_y;
1504     canvas->txt_cnt    = this_cell->info.cnt.beg_txt;
1505     canvas->line_cnt   = this_cell->info.cnt.beg_ln;
1506
1507     /*
1508      * determine the maximum width for the cell.
1509      */
1510     for (i = this_cell->col_spn; i > 0; i--)
1511         cellWidth += col_specs[col++].actual;
1512
1513     /*
1514      * get the current left and right margins.
1515      */
1516     GetCurrentDataPoint(layout, &basePt);
1517
1518     /*
1519      * re-format the cell
1520      */
1521     FormatCell(canvas, layout, this_cell->cell_seg, cellWidth,
1522                                 new_height,
1523                                 basePt, &i, &cellWidth, &junk, &junkValue);
1524
1525     /*
1526      * calculate the new height.
1527      */
1528     this_cell->info.height = layout->info.y_pos - new_y;
1529
1530     /*
1531      * if the new cell does not use the same number of lines as the
1532      * old formatting did, zero the length.
1533      */
1534     while (canvas->txt_cnt < this_cell->info.cnt.end_txt)
1535         canvas->txt_lst[canvas->txt_cnt++].length = 0;
1536
1537     /*
1538      * restore the saved counters
1539      */
1540     canvas->txt_cnt        = saveTxt;
1541     canvas->line_cnt       = saveLn;
1542     layout->info.y_pos     = saveYpos;
1543     layout->info.cur_max_x = saveMaxX;
1544 }
1545
1546
1547 /******************************************************************************
1548  * Function: void FormatCell(
1549  *
1550  * Parameters:
1551  *              canvas          Specifies the specific information about the
1552  *                              rendering area.
1553  *              layout          Specifies the currently active information
1554  *                              affecting the layout of information.
1555  *              span_width      Specifies the desired size constraining
1556  *                              the layout of information.
1557  *              base_pt         Specifies the base margins.
1558  *              this_cell       Specifies the cell structure to fill out.
1559  *
1560  * Purpose: Determines the width and height of the cell. Also the begin/end
1561  *          counts on text, graphics and lines.
1562  *****************************************************************************/
1563 static void
1564 FormatCell(
1565     _DtCanvasStruct     *canvas,
1566     LayoutInfo          *layout,
1567     _DtCvSegmentI       *cell_seg,
1568     _DtCvUnit            span_width,
1569     _DtCvUnit            min_height,
1570     DataPoint            base_pt,
1571     int                 *ret_ln,
1572     _DtCvUnit           *ret_width,
1573     _DtCvUnit           *ret_height,
1574     _DtCvValue          *ret_tab_flag)
1575 {
1576     _DtCvStatus only1Col  = True;
1577     _DtCvUnit   maxX;
1578     _DtCvUnit   minY      = -1;
1579     _DtCvUnit   saveYpos  = layout->info.y_pos;
1580     _DtCvUnit   saveRight = layout->right;
1581     _DtCvUnit   saveMaxX  = layout->info.cur_max_x;
1582     _DtCvSegmentI *nextSeg;
1583
1584     /*
1585      * set the limits/margins
1586      * assume the left_margin has been set by a previous call.
1587      */
1588     layout->right = layout->max_width - base_pt.left - base_pt.right
1589                                 - layout->left - span_width;
1590     /*
1591      * set the minimum Y for the container.
1592      */
1593     if (0 < min_height)
1594         minY = saveYpos + min_height;
1595
1596     /*
1597      * If a segment was specified for this cell, format it.
1598      */
1599     if (cell_seg != NULL && &BlankTableCell != cell_seg)
1600       {
1601         ProcessContainer(canvas, layout, cell_seg, minY,
1602                                         ret_width, &maxX, ret_ln);
1603
1604         /*
1605          * check to see if the only thing in this container is a
1606          * table.
1607          */
1608         nextSeg = _DtCvContainerListOfSeg(cell_seg);
1609         *ret_tab_flag = True;
1610         while (True == *ret_tab_flag && NULL != nextSeg)
1611           {
1612              /*
1613               * check to see if there is any segments that aren't one
1614               * column tables.
1615               */
1616              if (_DtCvIsSegTable(nextSeg) &&
1617                                         1 < _DtCvNumColsOfTableSeg(nextSeg))
1618                 only1Col = False;
1619
1620              else if (!(_DtCvIsSegTable(nextSeg) || _DtCvIsSegNoop(nextSeg)))
1621                 *ret_tab_flag = False;
1622
1623              nextSeg = _DtCvNextSeg(nextSeg);
1624           }
1625
1626         if (True == *ret_tab_flag && True == only1Col)
1627             *ret_tab_flag = False;
1628       }
1629
1630     /*
1631      * Calculate the height and return it.
1632      */
1633     *ret_height = layout->info.y_pos - saveYpos;
1634
1635     /*
1636      * restore the right margin
1637      */
1638     layout->right          = saveRight;
1639
1640     if (layout->info.cur_max_x < saveMaxX)
1641         layout->info.cur_max_x = saveMaxX;
1642 }
1643
1644 /******************************************************************************
1645  * Function: AdjustFrmtTxtOption
1646  *
1647  *****************************************************************************/
1648 static void
1649 AdjustFrmtTxtOption(
1650     _DtCvSegmentI       *p_seg,
1651     _DtCvFrmtOption      option)
1652 {
1653     if (p_seg != NULL && _DtCvIsSegContainer(p_seg))
1654       {
1655         TxtHorizJustify(p_seg) = option;
1656
1657         p_seg = _DtCvContainerListOfSeg(p_seg);
1658         while (p_seg != NULL)
1659           {
1660             AdjustFrmtTxtOption(p_seg, option);
1661             p_seg = p_seg->next_seg;
1662           }
1663       }
1664 }
1665
1666 /******************************************************************************
1667  * Function: ResolveCell
1668  *
1669  *****************************************************************************/
1670 static _DtCvValue
1671 ResolveCell(
1672     _DtCanvasStruct     *canvas,
1673     LayoutInfo          *layout,
1674     _DtCvSegmentI       *table,
1675     ColumnSpec          *col_specs,
1676     RowSpec             *row_specs,
1677     int                  col,
1678     int                  row,
1679     int                  max_cols,
1680     int                  max_rows,
1681     CellInfo            *ret_info)
1682 {
1683     int i;
1684     char  *id;
1685     char  *idRefs;
1686     char  *ptr;
1687     char   c;
1688     int    count;
1689     int    len;
1690     int    done;
1691     int    brdCnt;
1692     int    myCol = col;
1693     int    cell  = row * max_cols + col;
1694     _DtCvUnit   cellWidth;
1695     _DtCvUnit   retWidth;
1696     _DtCvUnit   retHeight;
1697     _DtCvUnit   saveTop;
1698     CellInfo    *thisCell = &ret_info[cell];
1699     DataPoint    basePt;
1700     _DtCvValue   reformat = False;
1701     _DtCvValue   retTabFlag = False;
1702     _DtCvSegmentI **f_data = _DtCvCellsOfTableSeg(table);
1703
1704     /*
1705      * if this column is spanned, skip
1706      */
1707     if (thisCell->col_spn == -1 || thisCell->row_spn == -1)
1708         return False;
1709
1710     GetCurrentDataPoint(layout, &basePt);
1711
1712     if (thisCell->cell_seg == NULL)
1713       {
1714         idRefs = row_specs[row].next_id;
1715
1716         /*
1717          * find the end of the id
1718          */
1719         done      = False;
1720
1721         /*
1722          * set the starting info
1723          */
1724         thisCell->col_spn = 1;
1725         thisCell->pos_x   = basePt.left + layout->left;
1726
1727         while (!done && col < max_cols)
1728           {
1729             ptr       = idRefs;
1730             id        = idRefs;
1731
1732             /*
1733              * move the ptr to the next id,
1734              * counting the characters in this id at the same time.
1735              */
1736             len = 0;
1737             while (NULL != ptr && *ptr != ' ' && *ptr != '\0')
1738               {
1739                 ptr++;
1740                 len++;
1741               }
1742
1743             /*
1744              * set idRefs to the next id.
1745              */
1746             idRefs = ptr;
1747             while (NULL != idRefs && *idRefs == ' ')
1748                 idRefs++;
1749
1750             /*
1751              * Is this id and the next the same? If so,
1752              * it spans the columns
1753              */
1754             if (0 != len && _DtCvStrNCaseCmpLatin1(id, idRefs, len) == 0 &&
1755                                 (idRefs[len] == ' ' || idRefs[len] == '\0'))
1756               {
1757                 col++;
1758                 thisCell->col_spn++;
1759                 ret_info[++cell].col_spn = -1;
1760               }
1761             else
1762                 done = True;
1763           }
1764
1765         row_specs[row].next_id = idRefs;
1766
1767         /*
1768          * find the segment
1769          */
1770         if (NULL != id && '\0' != *id)
1771           {
1772             c       = *ptr;
1773             *ptr    = '\0';
1774             while (f_data != NULL && NULL != *f_data &&
1775                 _DtCvStrCaseCmpLatin1(_DtCvContainerIdOfSeg(*f_data),id) != 0)
1776                 f_data++;
1777             /*
1778              * make sure to break the link to the next segment.
1779              * Otherwise, the formatting routines will format too much
1780              * for the cell.
1781              */
1782             if (NULL != f_data && NULL != *f_data)
1783               {
1784                 _DtCvNextSeg(*f_data) = NULL;
1785
1786                 /*
1787                  * assign the data to this cell.
1788                  */
1789                 thisCell->cell_seg = *f_data;
1790               }
1791             else /* there is no id for this cell, use a blank container */
1792                 thisCell->cell_seg = (struct _dtCvSegment*) &BlankTableCell;
1793           }
1794         else /* there is no id for this cell, use a blank container */
1795             thisCell->cell_seg = (struct _dtCvSegment*) &BlankTableCell;
1796
1797         /*
1798          * how many rows does this cell span?
1799          */
1800         len = 0;
1801         if (NULL != id)
1802             len = strlen(id);
1803
1804         for (done = False, count = 1, i = row + 1;
1805                                 0 < len && i < max_rows && False == done; i++)
1806           {
1807             done = True;
1808             if (_DtCvStrNCaseCmpLatin1(id, row_specs[i].next_id, len) == 0 &&
1809                 (row_specs[i].next_id[len] == ' ' ||
1810                                         row_specs[i].next_id[len] == '\0'))
1811               {
1812                 int    k;
1813
1814                 done = False;
1815                 count++;
1816
1817                 /*
1818                  * invalidate the columns spanned in this row
1819                  */
1820                 for (k = 0; k < thisCell->col_spn && k + myCol < max_cols; k++)
1821                   {
1822                     ret_info[i * max_cols + myCol + k].col_spn = -1;
1823                     ret_info[i * max_cols + myCol + k].row_spn = -1;
1824                   }
1825                 
1826                 idRefs  = row_specs[i].next_id;
1827                 do
1828                   {
1829                     /*
1830                      * skip the current id.
1831                      */
1832                     while (*idRefs != ' ' && *idRefs != '\0')
1833                         idRefs++;
1834
1835                     /*
1836                      * skip the space to the next id.
1837                      */
1838                     while (*idRefs == ' ')
1839                         idRefs++;
1840
1841                     /*
1842                      * now test to see if this is a match
1843                      * cycle if so. quit if the end of string
1844                      * or not a match.
1845                      */
1846                   } while (*idRefs != '\0' &&
1847                         _DtCvStrNCaseCmpLatin1(id, idRefs, len) == 0 &&
1848                                 (idRefs[len] == ' ' || idRefs[len] == '\0'));
1849
1850                 /*
1851                  * the next non-spanned column in this row will use this id.
1852                  */
1853                 row_specs[i].next_id = idRefs;
1854               }
1855           }
1856
1857         if (NULL != id && '\0' != *id)
1858             *ptr = c;
1859
1860         thisCell->row_spn = count;
1861       }
1862
1863     for (i = 0, cellWidth = 0; i < thisCell->col_spn; i++)
1864         cellWidth += col_specs[myCol + i].actual;
1865
1866     /*
1867      * set the start line and text information
1868      */
1869     SetBeginCounts(canvas, &(thisCell->info.cnt));
1870
1871     /*
1872      * check to see if this cell is overhung by a previous cell.
1873      * If so, zero the top margin. But remember and restore it
1874      * because resizing may eliminate the need for the overhang!
1875      */
1876     if (&BlankTableCell != thisCell->cell_seg)
1877       {
1878         saveTop = _DtCvContainerTMarginOfSeg(thisCell->cell_seg);
1879         if (_DtCvTRUE == col_specs[myCol].hanger
1880                 && 0 != row_specs[row].y_adj && myCol > row_specs[row].column)
1881             _DtCvContainerTMarginOfSeg(thisCell->cell_seg) = 0;
1882       }
1883
1884     /*
1885      * Format the cell
1886      */
1887     FormatCell(canvas, layout, thisCell->cell_seg, cellWidth,
1888                         row_specs[row].height, basePt,
1889                                 &brdCnt, &retWidth, &retHeight, &retTabFlag);
1890
1891     if (&BlankTableCell != thisCell->cell_seg)
1892         _DtCvContainerTMarginOfSeg(thisCell->cell_seg) = saveTop;
1893
1894     /*
1895      * set some ending information
1896      */
1897     thisCell->info.height = retHeight;
1898     thisCell->info.width  = retWidth;
1899     SetEndCounts(canvas, &(thisCell->info.cnt), brdCnt);
1900
1901     /*
1902      * check the height against previous heights
1903      */
1904     if (row_specs[row].height < retHeight && thisCell->row_spn == 1)
1905         row_specs[row].height = retHeight;
1906
1907     /*
1908      * check for run over of the desired widths
1909      */
1910     if (retWidth > cellWidth)
1911       {
1912         int j;
1913         _DtCvUnit  cellMax;
1914         _DtCvUnit  maxSlop;
1915         _DtCvUnit  value;
1916         _DtCvUnit  percent;
1917         _DtCvUnit  slopUsed = 0;
1918         _DtCvUnit  slop   = retWidth - cellWidth; /* the amount of room
1919                                                    required of the neighbors */
1920
1921         /*
1922          * set the reformat flag
1923          */
1924         if (False == retTabFlag)
1925             reformat = True;
1926
1927         /*
1928          * determine the maximum size the column can occupy
1929          */
1930         for (j = 0, cellMax = 0;
1931                         j < thisCell->col_spn && j + myCol < max_cols; j++)
1932             cellMax += col_specs[myCol+j].max;
1933         
1934         /*
1935          * determine the maximum available space from the neighbors.
1936          */
1937         for (j = myCol + thisCell->col_spn, maxSlop = 0; j < max_cols; j++)
1938             maxSlop = maxSlop + col_specs[j].actual - col_specs[j].min;
1939
1940         /*
1941          * If the slop demanded is larger than available,
1942          * simply reduced the other column specifications to their smallest
1943          * values.
1944          */
1945         if (slop >= maxSlop)
1946           {
1947             for (j = myCol + thisCell->col_spn; j < max_cols; j++)
1948                 col_specs[j].actual = col_specs[j].min;
1949
1950             /*
1951              * Is it allowed for this column to 'hang over' the others?
1952              *
1953              * And is it the first one? I.e. don't allow more than one
1954              * cell per row to overhang it's neighbors.
1955              *
1956              * And only allow it if the vertical text justification places
1957              * the text at the top of the cell.
1958              */
1959             if (_DtCvTRUE == col_specs[myCol].hanger
1960                 && 0 == row_specs[row].y_adj
1961                 && _DtCvJUSTIFY_TOP == TxtVertJustify(thisCell->cell_seg))
1962               {
1963                 /*
1964                  * now set the other columns to start a little lower
1965                  * in their objects. Remove the bottom margin from the
1966                  * adjustment. One would hope that each of the containers
1967                  * for the columns in the row have the same bottom margin
1968                  * so that the overhung cell will push the next row down
1969                  * by the appropriate amount.
1970                  */
1971                 row_specs[row].y_adj  = retHeight -
1972                                 _DtCvContainerBMarginOfSeg(thisCell->cell_seg);
1973                 row_specs[row].column = myCol;
1974                 retWidth = cellMax;
1975
1976                 /*
1977                  * clear the reformat flag
1978                  */
1979                 reformat = False;
1980               }
1981           }
1982         else if (slop > 0)
1983           {
1984             /*
1985              * the maximum slop available from the neighbors is
1986              * enough. Now take space from my neighbors based
1987              * on their orginal size. I.e. the larger they
1988              * are, the more I take from them.
1989              */
1990             for (j = myCol + thisCell->col_spn; j < max_cols; j++)
1991               {
1992                 percent   = col_specs[j].actual - col_specs[j].min;
1993                 value     = slop * percent / maxSlop;
1994                 slopUsed += value;
1995                 col_specs[j].actual -= value;
1996               }
1997
1998             /*
1999              * if any more slop is needed, grab it on a strictly
2000              * straight basis.
2001              */
2002             do {
2003                 slop -= slopUsed;
2004                 for (j = myCol + thisCell->col_spn, slopUsed = 0;
2005                                         slop > slopUsed && j < max_cols; j++)
2006                   {
2007                     if (col_specs[j].actual > col_specs[j].min)
2008                       {
2009                         col_specs[j].actual--;
2010                         slopUsed++;
2011                       }
2012                   }
2013               } while (slopUsed > 0 && slop > slopUsed);
2014           }
2015
2016         /*
2017          * set the column width in the controlling column struct.
2018          */
2019         if (thisCell->col_spn == 1)
2020           {
2021             col_specs[myCol].actual = retWidth;
2022           }
2023         else
2024           {
2025             /*
2026              * how much to spread among the columns?
2027              */
2028             slop = cellMax - retWidth;
2029
2030             /*
2031              * if the aggragate max width is smaller than required,
2032              * allocate the excess among the columns.
2033              */
2034             if (slop < 0)
2035               {
2036                 /*
2037                  * set the desired to the max and calculate the leftover
2038                  * slop and the maximum desired size.
2039                  */
2040                 for (j = 0, slop = retWidth, maxSlop = 0;
2041                         myCol + j < max_cols && j < thisCell->col_spn; j++)
2042                   {
2043                     col_specs[j].actual = col_specs[myCol + j].max;
2044                     slop    -= col_specs[myCol + j].max;
2045                     maxSlop += col_specs[myCol + j].max;
2046                   }
2047                 /*
2048                  * now allocate the leftover slop to each colum
2049                  * based on the maximum desired size.
2050                  */
2051                 for (j = 0, slopUsed = 0;
2052                         slop > slopUsed && myCol + j < max_cols
2053                                                 && j < thisCell->col_spn; j++)
2054                   {
2055                     value = slop * col_specs[myCol + j].max / maxSlop;
2056                     if (((slop*col_specs[myCol+j].max) % maxSlop) >= (maxSlop/2))
2057                         value++;
2058                     col_specs[myCol + j].actual += value;
2059                     slopUsed += value;
2060                   }
2061               }
2062             else if (slop > 0)
2063               {
2064                 slopUsed = 0;
2065                 for (j = myCol;
2066                         j < max_cols && j < myCol + thisCell->col_spn; j++)
2067                   {
2068                     percent   = col_specs[j].max - col_specs[j].actual;
2069                     value     = slop * percent / maxSlop;
2070                     slopUsed += value;
2071                     col_specs[j].actual += value;
2072                   }
2073
2074                 do {
2075                     slop -= slopUsed;
2076                     for (j = myCol, slopUsed = 0; slop > slopUsed &&
2077                         j < max_cols && j < myCol + thisCell->col_spn; j++)
2078                       {
2079                         if (col_specs[j].actual < col_specs[j].max)
2080                           {
2081                             col_specs[j].actual++;
2082                             slopUsed++;
2083                           }
2084                       }
2085                   } while (slopUsed > 0 && slop > slopUsed);
2086               }
2087             else /* if (slop == 0) */
2088               {
2089                 for (j = 0; myCol + j < max_cols && j < thisCell->col_spn; j++)
2090                     col_specs[j].actual = col_specs[myCol + j].max;
2091               }
2092           }
2093       }
2094
2095     return reformat;
2096 }
2097
2098 /******************************************************************************
2099  * Function: ProcessTable
2100  *
2101  *****************************************************************************/
2102 static void
2103 ProcessTable(
2104     _DtCanvasStruct     *canvas,
2105     LayoutInfo          *layout,
2106     _DtCvSegmentI       *table,
2107     _DtCvUnit            min_y)
2108 {
2109     int            a;
2110     int            b;
2111     int            c;
2112     int            col;
2113     int            row;
2114     int            cell;
2115     int            divisor;
2116     int            maxCols;
2117     int            maxRows;
2118     int            maxRowSpn;
2119     int            saveLnStart  = canvas->line_cnt;
2120     int            saveTxtStart = canvas->txt_cnt;
2121     int            saveTravCnt  = canvas->trav_cnt;
2122     _DtCvUnit      workWidth;
2123     _DtCvUnit      newLeft;
2124     _DtCvUnit      saveLeft    = layout->left;
2125     _DtCvUnit      saveYpos    = layout->info.y_pos;
2126     _DtCvUnit      tableYpos;
2127     _DtCvUnit      newHeight;
2128     _DtCvUnit      newWidth;
2129     _DtCvUnit      oldAlignPos;
2130     short          anchorRow = -1;
2131
2132     const char   **widthStr;
2133     const char    *saveAlignChar = layout->info.align_char;
2134     char         **rowIds;
2135     char          *alignCharacters = NULL;
2136     char           alignBuf[16];
2137
2138     _DtCvFrmtOption   saveTxtJustify = layout->txt_justify;
2139     _DtCvFrmtOption   colJustify  = _DtCvJUSTIFY_LEFT;
2140     _DtCvFrmtOption  *colJustSpec;
2141
2142     _DtCvValue     oldFound  = layout->id_found;
2143     _DtCvValue     haveBrds  = False;
2144     _DtCvValue     saveState = layout->table_flag;
2145     _DtCvValue     saveAlignFlag = layout->info.align_flag;
2146     _DtCvValue     saveAlignPos  = layout->info.align_pos;
2147     _DtCvValue     redo;
2148
2149     CellInfo     defCell;
2150     CellInfo    *cellInfo = &defCell;
2151     ColumnSpec   defColumn;
2152     ColumnSpec  *colSpecs = &defColumn;
2153     RowSpec      defRow;
2154     RowSpec     *rowSpecs = &defRow;
2155     DataPoint    basePt;
2156     GrpInfo      grpInfo = DefGrpInfo;
2157
2158     /*
2159      * get the base margins that the table will be working in.
2160      */
2161     GetCurrentDataPoint(layout, &basePt);
2162
2163     /*
2164      * find out how many rows there are.
2165      */
2166     for (rowIds = _DtCvCellIdsOfTableSeg(table), maxRows = 0;
2167                         rowIds != NULL && rowIds[maxRows] != NULL;  maxRows++);
2168
2169     if (maxRows == 0)
2170         return;
2171
2172     /*
2173      * get the number of columns and the column widths
2174      */
2175     maxCols     = _DtCvNumColsOfTableSeg(table);
2176     widthStr    = (const char **)_DtCvColWOfTableSeg(table);
2177     colJustSpec = _DtCvColJustifyOfTableSeg(table);
2178
2179     if (maxCols < 1)
2180         maxCols = 1;
2181
2182     if (widthStr == NULL)
2183         widthStr = DefWidth;
2184
2185     /*
2186      * determine the width the table has to work with.
2187      */
2188     workWidth = layout->max_width - basePt.left - basePt.right -
2189                                                 layout->left - layout->right;
2190     if (workWidth < 0)
2191         workWidth = 0;
2192
2193     /*
2194      * turn the string specifying column widths into units.
2195      */
2196     if (maxCols != 1)
2197       {
2198         colSpecs = (ColumnSpec *) malloc (sizeof(ColumnSpec) * maxCols);
2199         if (colSpecs == NULL)
2200             return;
2201       }
2202     if (maxRows != 1)
2203       {
2204         rowSpecs = (RowSpec *) malloc (sizeof(RowSpec) * maxRows);
2205         if (rowSpecs == NULL)
2206           {
2207             if (maxCols > 1)
2208                 free(colSpecs);
2209             return;
2210           }
2211       }
2212     if (maxRows != 1 || maxCols != 1)
2213       {
2214         cellInfo = (CellInfo *) malloc (sizeof(CellInfo) * maxCols * maxRows);
2215         if (cellInfo == NULL)
2216           {
2217             if (maxCols > 1)
2218                 free(colSpecs);
2219             if (maxRows > 1)
2220                 free(rowSpecs);
2221             return;
2222           }
2223       }
2224
2225     /*
2226      * for each column, process the width specification.
2227      *    '+Optimal,Take,Give'
2228      *
2229      *     +       - means the cell can 'hang over' its neighbors.
2230      *               It will take everything it can get and then
2231      *               push the other below it. (Labeled lists).
2232      *     Optimal - The desired percentage of the available space to
2233      *               use for the column.
2234      *     Take    - The percentage amount the column will take from
2235      *               other columns to make itself 'fit'.
2236      *     Give    - The percentage amount the column is willing to give up
2237      *               to other columns for them to 'fit'.
2238      */
2239     for (col = 0, divisor = 0; col < maxCols; col++)
2240       {
2241         const char  *nxtWidth = *widthStr;
2242
2243         /*
2244          * move to the meat of the width specification string.
2245          */
2246         SkipToNumber(&nxtWidth);
2247
2248         /*
2249          * set the correct 'allow hangers' flag.
2250          */
2251         colSpecs[col].hanger  = _DtCvFALSE;
2252         if ('+' == *nxtWidth)
2253           {
2254             colSpecs[col].hanger = _DtCvTRUE;
2255             nxtWidth++;
2256           }
2257
2258         /*
2259          * now process the O,G,T specification.
2260          */
2261         a = GetValueFromString(&nxtWidth, 1); if (a < 1) a = 1;
2262         b = GetValueFromString(&nxtWidth, 0); if (b < 0) b = 0;
2263         c = GetValueFromString(&nxtWidth, b); if (c > a) c = a;
2264
2265         /*
2266          * for now just get the base percentages.
2267          */
2268         colSpecs[col].min     = a - c;
2269         colSpecs[col].actual  = a;
2270         colSpecs[col].max     = a + b;
2271
2272         /*
2273          * get the column justification.
2274          */
2275         if (NULL != colJustSpec)
2276           {
2277             colJustify = *colJustSpec;
2278             colJustSpec++;
2279           }
2280         colSpecs[col].justify = colJustify;
2281         if (_DtCvINHERIT == colJustify)
2282             colSpecs[col].justify = saveTxtJustify;
2283
2284         /*
2285          * up the divisor value.
2286          */
2287         divisor += colSpecs[col].actual;
2288
2289         /*
2290          * skip to the next set of width specifications
2291          */
2292         if (col + 1 < maxCols && NULL != widthStr[1])
2293             widthStr++;
2294
2295         /*
2296          * initialize the cell information for the rows in this column
2297          */
2298         for (row = 0; row < maxRows; row++)
2299           {
2300             cellInfo[row * maxCols + col].cell_seg = NULL;
2301             cellInfo[row * maxCols + col].col_spn  = 0;
2302             cellInfo[row * maxCols + col].row_spn  = 0;
2303             cellInfo[row * maxCols + col].info     = DefLayFrmtInfo;
2304           }
2305       }
2306
2307     /*
2308      * initialize the row specs
2309      */
2310     newHeight = 0;
2311     if (-1 != min_y && 1 == maxRows)
2312         newHeight = min_y - saveYpos;
2313     for (row = 0; row < maxRows; row++)
2314       {
2315         rowSpecs[row].column  = -1;
2316         rowSpecs[row].y_adj   = 0;
2317         rowSpecs[row].height  = newHeight;
2318         rowSpecs[row].height  = newHeight;
2319         rowSpecs[row].next_id = rowIds[row];
2320       }
2321
2322     /*
2323      * now figure the real values
2324      */
2325     if (divisor < 1)
2326         divisor = 1;
2327     for (col = 0; col < maxCols; col++)
2328       {
2329         colSpecs[col].min    = workWidth * colSpecs[col].min    / divisor;
2330         colSpecs[col].actual = workWidth * colSpecs[col].actual / divisor;
2331         colSpecs[col].max    = workWidth * colSpecs[col].max    / divisor;
2332
2333         if (colSpecs[col].min < 1)
2334             colSpecs[col].min = 1;
2335         if (colSpecs[col].actual < 1)
2336             colSpecs[col].actual = 1;
2337         if (colSpecs[col].max < 1)
2338             colSpecs[col].max = 1;
2339       }
2340
2341     /*
2342      * now process the table.
2343      */
2344     tableYpos = layout->info.y_pos;
2345     maxRowSpn = 1;
2346     alignCharacters = _DtCvJustifyCharsOfTableSeg(table);
2347
2348     /*
2349      * set up the state of table processing and
2350      * the beginning line/text counts.
2351      */
2352     layout->table_flag = True;
2353     SetBeginCounts(canvas, &(grpInfo.cnt));
2354
2355     /*
2356      * now process each column, row by row.
2357      * Doing it row by row allows the columns to shake out their
2358      * sizing with less reformatting.
2359      */
2360     for (col = 0; col < maxCols; col++)
2361       {
2362         /*
2363          * remember where this column starts.
2364          */
2365         saveTravCnt  = canvas->trav_cnt;
2366         saveLnStart  = canvas->line_cnt;
2367         saveTxtStart = canvas->txt_cnt;
2368         newLeft      = layout->left;
2369         colJustify   = layout->txt_justify;
2370         layout->txt_justify = colSpecs[col].justify;
2371
2372         /*
2373          * initialize the JUSTIFY_NUM or JUSTIFY_CHAR information
2374          */
2375         layout->info.align_pos  = 0;
2376         layout->info.align_char = PeriodStr;
2377         if (_DtCvJUSTIFY_CHAR == layout->txt_justify)
2378           {
2379             /*
2380              * are any alignment characters specified?
2381              */
2382             if (NULL != alignCharacters && '\0' != *alignCharacters)
2383               {
2384                 int len = mblen(alignCharacters, MB_CUR_MAX);
2385
2386                 /*
2387                  * copy the character into a buffer
2388                  */
2389                 strncpy(alignBuf, alignCharacters, len);
2390                 alignBuf[len] = '\0';
2391                 layout->info.align_char = alignBuf;
2392
2393                 /*
2394                  * are there more characters? If so increment for the
2395                  * next column that may have JUSTIFY_CHAR. Otherwise,
2396                  * leave alone and re-use for other columns.
2397                  */
2398                 if ('\0' != alignCharacters[len])
2399                     alignCharacters += len;
2400               }
2401
2402             /* no...then default */
2403             else
2404                 layout->txt_justify = _DtCvJUSTIFY_LEFT;
2405           }
2406
2407         do {
2408             /*
2409              * reset the counts to the start
2410              */
2411             canvas->trav_cnt = saveTravCnt;
2412             canvas->line_cnt = saveLnStart;
2413             canvas->txt_cnt  = saveTxtStart;
2414             layout->left     = newLeft;
2415
2416             /*
2417              * for each row, format the cell in this columns
2418              */
2419             for (row = 0, redo = False, cell = col;
2420                                 row < maxRows && redo == False;
2421                                                 row++, cell += maxCols)
2422               {
2423                 /*
2424                  * remember the old height
2425                  */
2426                 rowSpecs[row].lst_height = rowSpecs[row].height;
2427
2428                 /*
2429                  * set the alignment flag for each column in the row.
2430                  */
2431                 layout->info.align_flag = False;
2432                 if (_DtCvJUSTIFY_CHAR == layout->txt_justify ||
2433                                         _DtCvJUSTIFY_NUM == layout->txt_justify)
2434                     layout->info.align_flag = True;
2435
2436                 /*
2437                  * remember the alignment position
2438                  */
2439                 oldAlignPos = layout->info.align_pos;
2440
2441                 /*
2442                  * layout all the cells jammed to the top of the table.
2443                  * later, they get moved down to their position.
2444                  */
2445                 layout->info.y_pos = tableYpos;
2446                 redo = ResolveCell(canvas, layout, table,
2447                                     colSpecs, rowSpecs, col, row,
2448                                     maxCols, maxRows, cellInfo);
2449                 /*
2450                  * check for maximum row span
2451                  */
2452                 if (maxRowSpn < cellInfo[cell].row_spn)
2453                     maxRowSpn = cellInfo[cell].row_spn;
2454
2455                 /*
2456                  * did the cell have borders?
2457                  */
2458                 if (0 != cellInfo[cell].info.cnt.my_lines)
2459                     haveBrds = True;
2460
2461                 /*
2462                  * check to see if the specified anchor has been found in
2463                  * this row. If so, save some information for later use.
2464                  */
2465                 if (anchorRow == -1 && oldFound != layout->id_found)
2466                     anchorRow = row;
2467
2468                 /*
2469                  * check to see if the alignment position has changed.
2470                  * for all but the first row!
2471                  */
2472                 if (0 != row && oldAlignPos != layout->info.align_pos)
2473                     redo = True;
2474               }
2475
2476             if (True == redo)
2477               {
2478                 for (a = 0; a < row; a++)
2479                   {
2480                     /*
2481                      * restore the old row heights for this column
2482                      */
2483                     rowSpecs[a].height = rowSpecs[a].lst_height;
2484
2485                     /*
2486                      * reset the hanging cell information.
2487                      */
2488                     if (col == rowSpecs[a].column)
2489                       {
2490                         rowSpecs[a].column = -1;
2491                         rowSpecs[a].y_adj  = 0;
2492                       }
2493                   }
2494               }
2495
2496           } while (redo == True);
2497         
2498         /*
2499          * push the next column to the right by size of this column
2500          */
2501         layout->left += colSpecs[col].actual;
2502
2503         /*
2504          * restore the horizontal text justification
2505          */
2506         layout->txt_justify = colJustify;
2507       }
2508
2509     /*
2510      * set the ending counts for the lines/text in the table.
2511      * and save the information as long as we are not a table
2512      * that is a descendant of some container with a border and
2513      * our cells include borders and we're going to have to honor
2514      * boundaries.
2515      */
2516     SetEndCounts(canvas, &(grpInfo.cnt), 0);
2517     if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint &&
2518                                 False == layout->brdr_flag && True == haveBrds)
2519       {
2520         GrpInfo *info = (GrpInfo *) malloc (sizeof(GrpInfo));
2521
2522         /*
2523          * warning - nothing done if malloc error.
2524          */
2525         if (NULL != info)
2526           {
2527             /*
2528              * initialize to the line counts for the table
2529              */
2530             *info = grpInfo;
2531
2532             /*
2533              * set the linked list information
2534              */
2535             info->next_info = layout->grp_lst;
2536             layout->grp_lst = info;
2537           }
2538       }
2539
2540     /*
2541      * Now go back and search for zeroed row heights and fill them in
2542      * based on spanned rows. This can only happen if maxRowSpn is
2543      * greater than 1! Otherwise, a row height really did end up zero!
2544      */
2545     if (maxRowSpn > 1)
2546       {
2547         /*
2548          * try to resolve the zero height rows
2549          */
2550         for (a = 1, redo = True; redo && a < maxRowSpn; a++)
2551           {
2552             redo = False;
2553             for (row = 0; row < maxRows; row++)
2554               {
2555                 if (rowSpecs[row].height == 0 &&
2556                     ResolveHeight(rowSpecs, cellInfo, maxCols, row, a) == 0)
2557                         redo = True;
2558               }
2559           }
2560         
2561         /*
2562          * if any of the rows comes up unresolved, force to an average
2563          * line height.
2564          *
2565          * But only do this if the first cell *does not* span all the rows
2566          * and columns.
2567          */
2568         if (redo &&
2569                 cellInfo[0].row_spn != maxRows && cellInfo[0].col_spn != maxCols)
2570           {
2571             for (row = 0; row < maxRows; row++)
2572               {
2573                 if (rowSpecs[row].height == 0)
2574                     rowSpecs[row].height = canvas->metrics.line_height;
2575               }
2576           }
2577
2578         /*
2579          * Now, double check that the row heights will accommodate
2580          * all the cells.
2581          */
2582         for (row = 0; row < maxRows; row++)
2583             for (col = 0; col < maxCols; col++)
2584                 AdjustHeight(cellInfo, rowSpecs, maxCols, row, col);
2585       }
2586
2587     /*
2588      * now check that the minimum heights used for the rows matches
2589      * or exceeds the minimum y position required.
2590      */
2591     if (-1 != min_y)
2592       {
2593         _DtCvUnit  pad;
2594
2595         for (newHeight = 0, row = 0; row < maxRows; row++)
2596             newHeight += rowSpecs[row].height;
2597
2598         if (tableYpos + newHeight < min_y)
2599           {
2600             newHeight = tableYpos - min_y;
2601             for (row = 0; 0 < newHeight && row < maxRows; row++)
2602               {
2603                 pad                   = (newHeight/(maxRows-row));
2604                 rowSpecs[row].height += pad;
2605                 newHeight            -= pad;
2606               }
2607           }
2608       }
2609
2610     /*
2611      * now reposition the cells based on the final row heights.
2612      */
2613     layout->info.y_pos = tableYpos;
2614     for (tableYpos = 0, cell = 0, row = 0; row < maxRows;
2615         tableYpos = tableYpos + rowSpecs[row].height + rowSpecs[row].y_adj,
2616         row++)
2617       {
2618         /*
2619          * check to see if the specified anchor has been found in this
2620          * row. If so, adjust the found position.
2621          */
2622         if (anchorRow == row)
2623             layout->id_Ypos += tableYpos;
2624
2625         for (col = 0, layout->left = saveLeft; col < maxCols;
2626                                 layout->left += colSpecs[col++].actual, cell++)
2627           {
2628             if (cellInfo[cell].cell_seg != NULL)
2629               {
2630                 /*
2631                  * calculate the new height
2632                  */
2633                 for (newHeight = 0, a = 0; a < cellInfo[cell].row_spn; a++)
2634                   {
2635                     newHeight += rowSpecs[row + a].height;
2636                     if (col != rowSpecs[row + a].column)
2637                         newHeight += rowSpecs[row + a].y_adj;
2638                   }
2639
2640                 /*
2641                  * calculate the new width.
2642                  */
2643                 for (newWidth = 0, a = 0; a < cellInfo[cell].col_spn; a++)
2644                     newWidth += colSpecs[col + a].actual;
2645
2646                 /*
2647                  * now get the overhang space for this cell
2648                  */
2649                 workWidth = 0;
2650                 if (col > rowSpecs[row].column)
2651                     workWidth = rowSpecs[row].y_adj;
2652
2653                 /*
2654                  * if the heights (and/or width for spanning columns)
2655                  * are different, check to see if the
2656                  * cell contains lines that may be affected by the
2657                  * height adjustment.
2658                  *
2659                  * It is strongly assumed that if a table specifies that
2660                  * a cell can hang over it's neighbors that it will *NOT*
2661                  * have borders (whereby LinesMayChange is false) and
2662                  * newWidth will not be greater than the cell's width.
2663                  */
2664                 if ((newHeight > cellInfo[cell].info.height &&
2665                         True == LinesMayChange(canvas,
2666                                         cellInfo[cell].info.cnt.beg_ln,
2667                                         cellInfo[cell].info.cnt.end_ln,
2668                                         cellInfo[cell].info.cnt.my_lines))
2669                                 ||
2670                         (1 < cellInfo[cell].col_spn &&
2671                                 newWidth > cellInfo[cell].info.width))
2672                     ReFormatCell(canvas, layout, &cellInfo[cell], colSpecs,
2673                                         col, newHeight,
2674                                         layout->info.y_pos + tableYpos);
2675
2676                 else
2677                     /* adjust the cell rather than reformatting */
2678                     AdjustObjectPosition(canvas, layout,
2679                                 TxtVertJustify(cellInfo[cell].cell_seg),
2680                                 cellInfo[cell].info.cnt.beg_txt ,
2681                                 cellInfo[cell].info.cnt.beg_ln  ,
2682                                 cellInfo[cell].info.cnt.beg_brk ,
2683                                 cellInfo[cell].info.cnt.end_txt ,
2684                                 cellInfo[cell].info.cnt.end_ln  ,
2685                                 cellInfo[cell].info.cnt.end_brk ,
2686                                 cellInfo[cell].info.cnt.my_lines,
2687                                 newHeight - cellInfo[cell].info.height,
2688                                 0,
2689                                 tableYpos, workWidth);
2690               }
2691           }
2692       }
2693
2694     /*
2695      * increment the maximum y.
2696      */
2697     layout->info.y_pos += tableYpos;
2698     layout->left        = saveLeft;
2699
2700     if (maxCols > 1)
2701         free(colSpecs);
2702     if (maxRows > 1)
2703         free(rowSpecs);
2704     if (maxRows > 1 || maxCols > 1)
2705         free(cellInfo);
2706
2707     layout->txt_justify = saveTxtJustify;
2708     layout->table_flag  = saveState;
2709
2710     /*
2711      * restore the alignment information
2712      */
2713     layout->info.align_flag = saveAlignFlag;
2714     layout->info.align_char = saveAlignChar;
2715     layout->info.align_pos  = saveAlignPos;
2716 }
2717
2718 /******************************************************************************
2719  * Function: UpdateDimensionArrays
2720  *
2721  * Purpose: Based on the object's orientation and justification,
2722  *          update the correct dimension array(s).
2723  *
2724  *****************************************************************************/
2725 static void
2726 UpdateDimensionArrays(
2727     _DtCvSegmentI *p_seg,
2728     _DtCvUnit    width,
2729     _DtCvUnit    height,
2730     TopDims     *top_bot,
2731     SideDims    *side,
2732     CornerDims  *corner,
2733     FlowDims    *flow,
2734     _DtCvUnit   *max_left,
2735     _DtCvUnit   *max_right)
2736 {
2737     int             i;
2738     int             j;
2739     int            *marginPtr;
2740     _DtCvFrmtOption orient   = ObjHorizOrient(p_seg);
2741     _DtCvFrmtOption vOrient  = ObjVertOrient(p_seg);
2742
2743     /*
2744      * modify the width that headSize should be
2745      */
2746     j = DIMS_LM;
2747     i = DIMS_TOP;
2748     switch (orient)
2749       {
2750         case _DtCvJUSTIFY_RIGHT_MARGIN:
2751                 j++;
2752         case _DtCvJUSTIFY_CENTER:
2753                 j++;
2754         case _DtCvJUSTIFY_LEFT_MARGIN:
2755                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
2756                     i = DIMS_BOTTOM;
2757
2758                 if ((*top_bot)[i][j][DIMS_WIDTH] < width)
2759                     (*top_bot)[i][j][DIMS_WIDTH] = width;
2760
2761                 if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(p_seg))
2762                     (*top_bot)[i][j][DIMS_HEIGHT] += height;
2763                 break;
2764
2765       }
2766
2767     /*
2768      * check left & right margins.
2769      */
2770     marginPtr = max_left;
2771     j = DIMS_LEFT;
2772     i = DIMS_TOP;
2773     switch(orient)
2774       {
2775
2776         case _DtCvJUSTIFY_RIGHT_CORNER:
2777         case _DtCvJUSTIFY_RIGHT:
2778                 j = DIMS_RIGHT;
2779                 marginPtr = max_right;
2780
2781         case _DtCvJUSTIFY_LEFT_CORNER:
2782         case _DtCvJUSTIFY_LEFT:
2783                 if (vOrient != _DtCvJUSTIFY_TOP)
2784                     i++;
2785                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
2786                     i++;
2787
2788                 /*
2789                  * push i to zero or 4
2790                  */
2791                 if (orient == _DtCvJUSTIFY_RIGHT_CORNER ||
2792                                             orient == _DtCvJUSTIFY_LEFT_CORNER)
2793                   {
2794                     if (i) i = DIMS_BC;
2795                     (*corner)[i][j] += height;
2796                     if (*marginPtr < width)
2797                         *marginPtr = width;
2798                   }
2799                 else if (_DtCvContainerFlowOfSeg(p_seg) != _DtCvWRAP)
2800                   {
2801                     (*side)[i][j] += height;
2802                     if (*marginPtr < width)
2803                         *marginPtr = width;
2804                   }
2805                 else
2806                   {
2807                     (*flow)[j][DIMS_HEIGHT] += height;
2808                     if ((*flow)[j][DIMS_WIDTH] < width)
2809                         (*flow)[j][DIMS_WIDTH] = width;
2810                   }
2811                 break;
2812       }
2813 }
2814
2815 /******************************************************************************
2816  * Function: DetermineMaxDims
2817  *
2818  *****************************************************************************/
2819 static void
2820 DetermineMaxDims(
2821     TopDims     *top_bot,
2822     CornerDims  *corner,
2823     _DtCvUnit    left_margin,
2824     _DtCvUnit    right_margin,
2825     _DtCvUnit   *top_height,
2826     _DtCvUnit   *bot_height,
2827     _DtCvUnit   *max_width)
2828 {
2829     int j;
2830     _DtCvUnit     topWidth;
2831     _DtCvUnit     botWidth;
2832
2833     /*
2834      * now process all the information gathered about the (sub)headings
2835      * to determine the bounding box for the (head) txt. Start by figuring
2836      * out the maximums for the dimensions.
2837      *
2838      * figure the current top and bottom max widths.
2839      */
2840     topWidth  = left_margin + right_margin;
2841     botWidth  = left_margin + right_margin;
2842     *top_height = 0;
2843     *bot_height = 0;
2844     for (j = DIMS_LM; j <= DIMS_RM; j++)
2845       {
2846         topWidth = topWidth + (*top_bot)[DIMS_TOP]   [j][DIMS_WIDTH];
2847         botWidth = botWidth + (*top_bot)[DIMS_BOTTOM][j][DIMS_WIDTH];
2848
2849         if (*top_height < (*top_bot)[DIMS_TOP][j][DIMS_HEIGHT])
2850             *top_height = (*top_bot)[DIMS_TOP][j][DIMS_HEIGHT];
2851
2852         if (*bot_height < (*top_bot)[DIMS_BOTTOM][j][DIMS_HEIGHT])
2853             *bot_height = (*top_bot)[DIMS_BOTTOM][j][DIMS_HEIGHT];
2854       }
2855
2856     /*
2857      * for the maximum top and bottom heights, take into
2858      * consideration the corner values
2859      */
2860     if (*top_height < (*corner)[DIMS_TC][DIMS_LEFT])
2861         *top_height = (*corner)[DIMS_TC][DIMS_LEFT];
2862     if (*top_height < (*corner)[DIMS_TC][DIMS_RIGHT])
2863         *top_height = (*corner)[DIMS_TC][DIMS_RIGHT];
2864
2865     if (*bot_height < (*corner)[DIMS_BC][DIMS_LEFT])
2866         *bot_height = (*corner)[DIMS_BC][DIMS_LEFT];
2867     if (*bot_height < (*corner)[DIMS_BC][DIMS_RIGHT])
2868         *bot_height = (*corner)[DIMS_BC][DIMS_RIGHT];
2869
2870     *max_width = topWidth;
2871     if (*max_width < botWidth)
2872         *max_width = botWidth;
2873
2874 }
2875
2876 /******************************************************************************
2877  * Function: DetermineFlowConstraints
2878  *
2879  *****************************************************************************/
2880 static void
2881 DetermineFlowConstraints(
2882     LayoutInfo  *layout,
2883     FlowDims     flow_dims,
2884     _DtCvUnit    left_margin,
2885     _DtCvUnit    right_margin,
2886     _DtCvUnit    start_y,
2887     DataPoint   *left_pt,
2888     DataPoint   *right_pt)
2889 {
2890     _DtCvUnit   leftSide  = flow_dims[DIMS_LEFT][DIMS_HEIGHT];
2891     _DtCvUnit   rightSide = flow_dims[DIMS_RIGHT][DIMS_HEIGHT];
2892
2893     /*
2894      * Now, if there is flowing text required, put points on the
2895      * stack to indicate them.
2896      */
2897     left_margin  += flow_dims[DIMS_LEFT][DIMS_WIDTH];
2898     right_margin += flow_dims[DIMS_RIGHT][DIMS_WIDTH];
2899
2900     GetCurrentDataPoint(layout, left_pt);
2901     GetCurrentDataPoint(layout, right_pt);
2902     left_pt->left   += left_margin;
2903     left_pt->right  += right_margin;
2904     left_pt->y_pos   = _CEFORMAT_ALL;
2905     right_pt->left  += left_margin;
2906     right_pt->right += right_margin;
2907     right_pt->y_pos  = _CEFORMAT_ALL;
2908
2909     while (leftSide > 0 || rightSide > 0)
2910       {
2911         if (leftSide > 0)
2912           {
2913             if (rightSide == 0 || leftSide <= rightSide)
2914               {
2915                 left_pt->right = right_margin;
2916                 left_pt->y_pos = start_y + leftSide;
2917                 if (leftSide != rightSide)
2918                     left_margin = 0;
2919                 leftSide = 0;
2920                 InsertDataPoint(layout, left_pt);
2921               }
2922           }
2923
2924         if (rightSide > 0)
2925           {
2926             if (leftSide == 0 || leftSide > rightSide)
2927               {
2928                 right_pt->left  = left_margin;
2929                 right_pt->y_pos = start_y + rightSide;
2930                 if (leftSide != rightSide)
2931                     right_margin = 0;
2932                 rightSide = 0;
2933                 InsertDataPoint(layout, right_pt);
2934               }
2935           }
2936       }
2937 }
2938
2939 /******************************************************************************
2940  * Function: DetermineHeadPositioning
2941  *
2942  *****************************************************************************/
2943 static void
2944 DetermineHeadPositioning(
2945     TopDims     *top_bot,
2946     SideDims    *side,
2947     CornerDims  *corner,
2948     FlowDims    *flow,
2949     _DtCvUnit    start_y,
2950     _DtCvUnit    max_top,
2951     _DtCvUnit    block_size,
2952     _DtCvUnit   *ret_side_size)
2953 {
2954     int    i;
2955     _DtCvUnit   leftSideHeight  = 0;
2956     _DtCvUnit   rightSideHeight = 0;
2957     _DtCvUnit   sideHeight      = 0;
2958
2959     /*
2960      * determine the maximum side heights
2961      */
2962     for (i = DIMS_TOP; i <= DIMS_BOTTOM; i++)
2963       {
2964         leftSideHeight  += (*side)[i][DIMS_LEFT];
2965         rightSideHeight += (*side)[i][DIMS_RIGHT];
2966       }
2967
2968     /*
2969      * determine the maximum side height
2970      */
2971     sideHeight = block_size;
2972     if (sideHeight < leftSideHeight)
2973         sideHeight = leftSideHeight;
2974     if (sideHeight < rightSideHeight)
2975         sideHeight = rightSideHeight;
2976     if (sideHeight < (*flow)[DIMS_LEFT][DIMS_HEIGHT])
2977         sideHeight  = (*flow)[DIMS_LEFT][DIMS_HEIGHT];
2978     if (sideHeight < (*flow)[DIMS_RIGHT][DIMS_HEIGHT])
2979         sideHeight = (*flow)[DIMS_RIGHT][DIMS_HEIGHT];
2980
2981     /*
2982      * calculate the starting Y position for each of the positions
2983      * reuse the arrays that were used to save the max dimension values.
2984      */
2985     for (i = DIMS_LM; i <= DIMS_RM; i++)
2986       {
2987         (*top_bot)[DIMS_TOP]   [i][DIMS_YPOS] = start_y;
2988         (*top_bot)[DIMS_BOTTOM][i][DIMS_YPOS] = start_y + max_top + sideHeight;
2989       }
2990
2991     (*corner)[DIMS_TC][DIMS_LEFT]  = start_y;
2992     (*corner)[DIMS_TC][DIMS_RIGHT] = start_y;
2993
2994     (*corner)[DIMS_BC][DIMS_LEFT]  = start_y + max_top + sideHeight;
2995     (*corner)[DIMS_BC][DIMS_RIGHT] = start_y + max_top + sideHeight;
2996
2997     (*side)[DIMS_TOP][DIMS_LEFT]  = start_y + max_top;
2998     (*side)[DIMS_TOP][DIMS_RIGHT] = start_y + max_top;
2999
3000     (*flow)[DIMS_LEFT ][DIMS_YPOS] = start_y + max_top;
3001     (*flow)[DIMS_RIGHT][DIMS_YPOS] = start_y + max_top;
3002
3003     (*side)[DIMS_CENTER][DIMS_LEFT]  = start_y + max_top +
3004                         (sideHeight - (*side)[DIMS_CENTER][DIMS_LEFT]) / 2;
3005     (*side)[DIMS_CENTER][DIMS_RIGHT] = start_y + max_top +
3006                         (sideHeight - (*side)[DIMS_CENTER][DIMS_RIGHT]) / 2;
3007
3008     (*side)[DIMS_BOTTOM][DIMS_LEFT]  = start_y + max_top +
3009                         sideHeight - (*side)[DIMS_BOTTOM][DIMS_LEFT];
3010     (*side)[DIMS_BOTTOM][DIMS_RIGHT] = start_y + max_top +
3011                         sideHeight - (*side)[DIMS_BOTTOM][DIMS_RIGHT];
3012
3013     if (ret_side_size != NULL)
3014         *ret_side_size = sideHeight;
3015 }
3016
3017 /******************************************************************************
3018  * Function: AdjustHead
3019  *
3020  * Parameters:
3021  *              base_left       Specifies the x position that the controller
3022  *                              occupying 'left_margin' space would start
3023  *                              at.
3024  *              block_width     Specifies the body's width for which to
3025  *                              center or align a controller with.
3026  *              left_margin     Specifies the space used by a controller
3027  *                              that is on the left side of the body.
3028  *              right_margin    Specifies the space used by a controller
3029  *                              on the right side of the body.
3030  *
3031  *****************************************************************************/
3032 static void
3033 AdjustHeadPosition(
3034     _DtCanvasStruct     *canvas,
3035     LayoutInfo          *layout,
3036     _DtCvSegmentI       *p_seg,
3037     TopDims             *top_bot,
3038     SideDims            *side,
3039     CornerDims          *corner,
3040     FlowDims            *flow,
3041     LayFrmtInfo         *info,
3042     _DtCvUnit            base_y,
3043     _DtCvUnit            base_left,
3044     _DtCvUnit            block_width,
3045     _DtCvUnit            left_margin,
3046     _DtCvUnit            right_margin)
3047 {
3048     int           i         = DIMS_TOP;         /* also DIMS_TC */
3049     int           j         = DIMS_LEFT;        /* also DIMS_LM */
3050     int           divisor   = 2;
3051     _DtCvUnit     adjustX   = 0;
3052     _DtCvUnit     adjustY   = 0;
3053     _DtCvUnit     newY      = 0;
3054     _DtCvUnit     headWidth = info->width;
3055     _DtCvFrmtOption  orient    = ObjHorizOrient(p_seg);
3056     _DtCvFrmtOption  vOrient   = ObjVertOrient(p_seg);
3057
3058     if (_DtCvContainerPercentOfSeg(p_seg) == 10000
3059                         && orient == _DtCvJUSTIFY_CENTER
3060                         && TxtHorizJustify(p_seg) == _DtCvJUSTIFY_LEFT)
3061         headWidth = block_width;
3062
3063     switch (orient)
3064       {
3065         case _DtCvJUSTIFY_RIGHT_MARGIN:
3066                 divisor = 1;
3067                 j++;
3068         case _DtCvJUSTIFY_CENTER:
3069                 adjustX = (block_width - headWidth) / divisor;
3070                 j++;
3071         case _DtCvJUSTIFY_LEFT_MARGIN:
3072                 adjustX += left_margin;
3073                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
3074                     i = DIMS_BOTTOM;
3075
3076                 newY  = (*top_bot)[i][j][DIMS_YPOS];
3077                 (*top_bot)[i][j][DIMS_YPOS] += info->height;
3078                 break;
3079
3080         case _DtCvJUSTIFY_RIGHT_CORNER:
3081                 adjustX = block_width + left_margin;
3082                 j       = DIMS_RIGHT;
3083
3084         case _DtCvJUSTIFY_LEFT_CORNER:
3085                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
3086                     i = DIMS_BC;
3087
3088                 newY = (*corner)[i][j];
3089                 (*corner)[i][j] += info->height;
3090                 break;
3091
3092         case _DtCvJUSTIFY_RIGHT:
3093                 adjustX = block_width + left_margin;
3094                 j = DIMS_RIGHT;
3095
3096         case _DtCvJUSTIFY_LEFT:
3097                 if (vOrient != _DtCvJUSTIFY_TOP)
3098                     i++;
3099                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
3100                     i++;
3101
3102                 if (_DtCvContainerFlowOfSeg(p_seg) == _DtCvWRAP)
3103                   {
3104                     if (orient == _DtCvJUSTIFY_LEFT)
3105                         adjustX += left_margin;
3106                     else
3107                         adjustX -= headWidth;
3108
3109                     newY = (*flow)[j][DIMS_YPOS];
3110                     (*flow)[j][DIMS_YPOS] += info->height;
3111                   }
3112                 else
3113                   {
3114                     newY = (*side)[i][j];
3115                     (*side)[i][j] += info->height;
3116                   }
3117                 break;
3118       }
3119
3120     adjustY  = newY - base_y;
3121     adjustX += base_left;
3122
3123     /*
3124      * adjust the text positions
3125      */
3126     AdjustTextPositions(canvas, info->cnt.beg_txt, info->cnt.end_txt,
3127                                                                 adjustX, adjustY);
3128
3129     /*
3130      * adjust the lines positions
3131      */
3132     AdjustLinePositions(canvas, info->cnt.beg_ln, info->cnt.end_ln,
3133                                                                 adjustX, adjustY);
3134
3135     /*
3136      * adjust the page breaks, but only if necessary.
3137      */
3138     AdjustPgBrk(canvas, info->cnt.beg_brk, info->cnt.end_brk, adjustY);
3139 }
3140
3141 /******************************************************************************
3142  * Function: InitDimArrays
3143  *
3144  *****************************************************************************/
3145 static void
3146 InitDimArrays(
3147     TopDims             *top_bot,
3148     SideDims            *side,
3149     CornerDims          *corner,
3150     FlowDims            *flow)
3151 {
3152     int             i;
3153     int             j;
3154
3155     for (i = DIMS_TOP; i <= DIMS_BOTTOM; i++)
3156       {
3157         for (j = DIMS_LM; j <= DIMS_RM; j++)
3158           {
3159             (*top_bot)[i][j][DIMS_WIDTH] = 0;
3160             (*top_bot)[i][j][DIMS_HEIGHT] = 0;
3161           }
3162         for (j = DIMS_LEFT; j <= DIMS_RIGHT; j++)
3163             (*side)[i][j] = 0;
3164       }
3165     for (i = DIMS_LEFT; i <= DIMS_RIGHT; i++)
3166       {
3167         for (j = DIMS_WIDTH; j <= DIMS_HEIGHT; j++)
3168          {
3169             (*corner)[i][j] = 0;
3170             (*flow)[i][j]   = 0;
3171          }
3172       }
3173 }
3174
3175 /******************************************************************************
3176  * Function: ProcessController
3177  *****************************************************************************/
3178 static LayFrmtInfo *
3179 ProcessController(
3180     _DtCanvasStruct     *canvas,
3181     LayoutInfo          *layout,
3182     _DtCvSegmentI       *cur_seg)
3183 {
3184     int            getLn;
3185     int            saveTravCnt  = canvas->trav_cnt;
3186     _DtCvUnit      saveYPos     = layout->info.y_pos;
3187     _DtCvUnit      saveMaxWidth = layout->max_width;
3188     _DtCvUnit      saveLeft     = layout->left;
3189     _DtCvUnit      saveRight    = layout->right;
3190     _DtCvUnit      maxWidth;
3191     _DtCvUnit      maxXPos;
3192     _DtCvUnit      myMaxWidth;
3193     LayFrmtInfo   *frmtInfo;
3194     DataPoint      basePt;
3195     DataPoint      zeroPt;
3196     _DtCvValue     redo;
3197
3198     /*
3199      * Controllers always break the formatting sequence.
3200      * So save any information in the buffer, reset the margins and
3201      * add the appropriate lines, and check for going over boundaries.
3202      */
3203     CheckSaveInfo(canvas, layout, cur_seg, 0);
3204     CheckFormat(layout, True);
3205
3206     /*
3207      * Get the controller specific information.
3208      * disallow some of the orientation & vOrient combinations
3209      */
3210     if ((ObjHorizOrient(cur_seg) == _DtCvJUSTIFY_CENTER
3211                         && ObjVertOrient(cur_seg) != _DtCvJUSTIFY_BOTTOM)
3212                 ||
3213         (ObjVertOrient(cur_seg) == _DtCvJUSTIFY_CENTER
3214                         && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT
3215                         && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_RIGHT))
3216         ObjVertOrient(cur_seg) = _DtCvJUSTIFY_TOP;
3217
3218     if (_DtCvContainerFlowOfSeg(cur_seg) == _DtCvWRAP
3219                         &&
3220             (ObjVertOrient(cur_seg) != _DtCvJUSTIFY_TOP
3221                                 ||
3222                 (ObjVertOrient(cur_seg) == _DtCvJUSTIFY_TOP
3223                         && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT
3224                         && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_RIGHT)))
3225         _DtCvContainerFlowOfSeg(cur_seg) = _DtCvWRAP_NONE;
3226
3227     if (_DtCvContainerFlowOfSeg(cur_seg) == _DtCvWRAP_JOIN
3228                         &&
3229             (ObjVertOrient(cur_seg) != _DtCvJUSTIFY_TOP
3230                 || ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT_MARGIN))
3231       {
3232         ObjVertOrient(cur_seg)  = _DtCvJUSTIFY_TOP;
3233         ObjHorizOrient(cur_seg) = _DtCvJUSTIFY_LEFT_MARGIN;
3234       }
3235     
3236     /*
3237      * malloc a formatting dimension structure and initialize it with
3238      * default values. This will be returned to the caller.
3239      */
3240     frmtInfo  = (LayFrmtInfo *) malloc (sizeof(LayFrmtInfo));
3241     *frmtInfo = DefLayFrmtInfo;
3242
3243     /*
3244      * the controller object begins here.
3245      */
3246     SetBeginCounts(canvas, &(frmtInfo->cnt));
3247
3248     /*
3249      * set the parent's data point in the stack
3250      */
3251     GetCurrentDataPoint(layout, &basePt);
3252
3253     /*
3254      * calculate the amount of space the controller can occupy.
3255      * first calculate the amount of space to work with.
3256      * then truncate to zero if necessary.
3257      * then use the percentage of that remaining area as the space
3258      *      the controller's segments can occupy.
3259      */
3260     myMaxWidth = layout->max_width - basePt.left - basePt.right
3261                                                         - saveLeft - saveRight;
3262     if (myMaxWidth < 0)
3263         myMaxWidth = 0;
3264
3265     myMaxWidth = (_DtCvUnit) (((double) myMaxWidth)
3266                         * ((double) _DtCvContainerPercentOfSeg(cur_seg))
3267                         / HeadDivisor);
3268
3269
3270     /*
3271      * Format the controller at a 'zero'ed point.
3272      * The lines it generates will be moved later to their correct position.
3273      */
3274     layout->left  = 0;
3275     layout->right = 0;
3276     zeroPt = DefDataPt;
3277     PushDataPoint(layout, &zeroPt);
3278
3279     /*
3280      * now process as a regular container
3281      */
3282     do {
3283         /*
3284          * set some counts and flags (necessary for a redo).
3285          */
3286         redo = False;
3287         canvas->trav_cnt    = saveTravCnt;
3288         canvas->line_cnt    = frmtInfo->cnt.beg_ln;
3289         canvas->txt_cnt     = frmtInfo->cnt.beg_txt;
3290         layout->max_width   = myMaxWidth;
3291         layout->info.y_pos  = 0;
3292
3293         /*
3294          * process the container
3295          */
3296         ProcessContainer(canvas,layout,cur_seg,-1,&maxWidth,&maxXPos,&getLn);
3297
3298         /*
3299          * check to see if we need to reformat because the minimum size
3300          * is larger than we asked for.
3301          */
3302         if (maxXPos + _DtCvContainerRMarginOfSeg(cur_seg) > myMaxWidth)
3303           {
3304             redo       = True;
3305             myMaxWidth = maxXPos + _DtCvContainerRMarginOfSeg(cur_seg);
3306           }
3307       } while (True == redo);
3308     
3309     /*
3310      * remove this element's data points from the stack.
3311      */
3312     RemoveDataPoint(layout, &zeroPt);
3313
3314     /*
3315      * set the ending counts for the items in this container.
3316      */
3317     SetEndCounts(canvas, &(frmtInfo->cnt), getLn);
3318     frmtInfo->width  = myMaxWidth;
3319     frmtInfo->height = layout->info.y_pos;
3320
3321     /*
3322      * does this controller want to join with the lines in a non-controller?
3323      */
3324     if (_DtCvWRAP_JOIN == _DtCvContainerFlowOfSeg(cur_seg)
3325                                 && frmtInfo->cnt.beg_txt != canvas->txt_cnt)
3326         _DtCvSetJoinInfo(&(layout->info), True, canvas->txt_cnt - 1);
3327
3328     /*
3329      * Restore the previous information
3330      */
3331     if (NULL != layout->lst_rendered)
3332         layout->lst_rendered->next_disp = NULL;
3333
3334     layout->left           = saveLeft;
3335     layout->right          = saveRight;
3336     layout->max_width      = saveMaxWidth;
3337     layout->lst_rendered   = NULL;
3338     layout->info.y_pos     = saveYPos;
3339
3340     return frmtInfo;
3341 }
3342
3343 /******************************************************************************
3344  * Function: AdjustForBorders
3345  *
3346  * Initializes the display line and graphic tables.
3347  *****************************************************************************/
3348 static void
3349 AdjustForBorders(
3350     _DtCanvasStruct     *canvas,
3351     LayoutInfo          *layout,
3352     _DtCvFrmtOption      brdr,
3353     _DtCvUnit            line_width,
3354     _DtCvUnit           *ret_bot,
3355     _DtCvUnit           *ret_right)
3356 {
3357     /*
3358      * if the line_width is zero, make it 1 so that is really takes
3359      * up some space.
3360      */
3361     if (0 == line_width)
3362         line_width = 1;
3363
3364     /*
3365      * set the flag for processing a border
3366      */
3367     if (_DtCvBORDER_NONE != brdr)
3368         layout->brdr_flag = True;
3369
3370     /*
3371      * check to see if this element has a border. If so, adjust the
3372      * boundaries.
3373      */
3374     if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_HORZ
3375                                  || brdr == _DtCvBORDER_TOP
3376                                  || brdr == _DtCvBORDER_TOP_LEFT
3377                                  || brdr == _DtCvBORDER_TOP_RIGHT)
3378         layout->info.y_pos += line_width;
3379
3380     *ret_bot = 0;
3381     if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_HORZ
3382                                  || brdr == _DtCvBORDER_BOTTOM
3383                                  || brdr == _DtCvBORDER_BOTTOM_LEFT
3384                                  || brdr == _DtCvBORDER_BOTTOM_RIGHT)
3385         *ret_bot = line_width;
3386
3387     if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_VERT
3388                                  || brdr == _DtCvBORDER_LEFT
3389                                  || brdr == _DtCvBORDER_TOP_LEFT
3390                                  || brdr == _DtCvBORDER_BOTTOM_LEFT)
3391         layout->left += line_width;
3392
3393     *ret_right = 0;
3394     if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_VERT
3395                                  || brdr == _DtCvBORDER_RIGHT
3396                                  || brdr == _DtCvBORDER_TOP_RIGHT
3397                                  || brdr == _DtCvBORDER_BOTTOM_RIGHT)
3398       {
3399         layout->right += line_width;
3400         *ret_right     = line_width;
3401       }
3402 }
3403
3404 /******************************************************************************
3405  * Function: DrawBorders
3406  *
3407  * Parameters:
3408  *              canvas          Specifies the virtual canvas on which
3409  *                              lines are drawn.
3410  *              layout          Specifies the current layout information.
3411  *              brdr            Specifies the type of border.
3412  *              top_y           Specifes the top y of the bounding box for
3413  *                              the object. Any border drawn should be
3414  *                              completely below this y.
3415  *              bot_y           Specifes the bottom y of the bounding box
3416  *                              for the object. Any border drawn should be
3417  *                              completely below this y.
3418  *              left_x          Specifies the left x of the bounding box
3419  *                              for the object. Any border drawn should be
3420  *                              completely to the right of this x.
3421  *              right_x         Specifies the right x of the bounding box
3422  *                              for the object. Any border drawn should be
3423  *                              completely to the left of this x.
3424  *
3425  *          left_x               right_x
3426  *            |                     |
3427  *            v                     v
3428  * top_y ---> xxxxxxxxxxxxxxxxxxxxxx
3429  *            xxxxxxxxxxxxxxxxxxxxxx
3430  *            xx------------------xx
3431  *            xx|                |xx  (xx represents the line.)
3432  *            xx|                |xx
3433  *            xx|                |xx
3434  *            xx|                |xx
3435  *            xx------------------xx
3436  * bot_y ---> xxxxxxxxxxxxxxxxxxxxxx
3437  *            xxxxxxxxxxxxxxxxxxxxxx
3438  *
3439  *****************************************************************************/
3440 static int
3441 DrawBorders(
3442     _DtCanvasStruct     *canvas,
3443     LayoutInfo          *layout,
3444     _DtCvFrmtOption      brdr,
3445     _DtCvPointer         data,
3446     _DtCvUnit            line_width,
3447     _DtCvUnit            top_y,
3448     _DtCvUnit            bot_y,
3449     _DtCvUnit            left_x,
3450     _DtCvUnit            right_x)
3451 {
3452     int         mod       = 1;
3453     int         cnt       = canvas->line_cnt;
3454     _DtCvUnit   width;
3455
3456     /*
3457      * if line_width is zero, make it 1 so that it really takes
3458      * up some space.
3459      */
3460     if (0 == line_width)
3461         line_width = 1;
3462
3463     /*
3464      * calculate the width of the element.
3465      */
3466     width = right_x - left_x;
3467
3468     /*
3469      * If borders are specified, draw them
3470      */
3471     if (brdr != _DtCvBORDER_NONE)
3472       {
3473         /*
3474          * now do the horizontal borders. the coordinates are the top,
3475          * left most unit of the line.
3476          */
3477         switch(brdr)
3478           {
3479             case _DtCvBORDER_FULL:
3480             case _DtCvBORDER_HORZ:
3481             case _DtCvBORDER_BOTTOM:
3482             case _DtCvBORDER_BOTTOM_LEFT:
3483             case _DtCvBORDER_BOTTOM_RIGHT:
3484                         SaveLine(canvas, layout, _DtCvLINE_HORZ,
3485                                                 data, line_width,
3486                                                 left_x, bot_y, width);
3487                         mod = -1;
3488                         if (brdr == _DtCvBORDER_BOTTOM
3489                                         || brdr == _DtCvBORDER_BOTTOM_LEFT
3490                                         || brdr == _DtCvBORDER_BOTTOM_RIGHT)
3491                             break;
3492     
3493             case _DtCvBORDER_TOP:
3494             case _DtCvBORDER_TOP_LEFT:
3495             case _DtCvBORDER_TOP_RIGHT:
3496                         SaveLine(canvas, layout, _DtCvLINE_HORZ,
3497                                                 data, line_width,
3498                                                 left_x, top_y, width);
3499           }
3500     
3501         /*
3502          * for vertical lines, the coordinates are the top, right most
3503          * unit of the line.
3504          */
3505         switch(brdr)
3506           {
3507             case _DtCvBORDER_FULL:
3508             case _DtCvBORDER_BOTTOM_LEFT:
3509                         /*
3510                          * include the line width in length for a full
3511                          * border.
3512                          */
3513                         bot_y += line_width;
3514
3515             case _DtCvBORDER_VERT:
3516             case _DtCvBORDER_LEFT:
3517             case _DtCvBORDER_TOP_LEFT:
3518                         SaveLine(canvas, layout, _DtCvLINE_VERT,
3519                                                 data, line_width,
3520                                                 left_x, top_y, bot_y - top_y);
3521                         if (brdr == _DtCvBORDER_LEFT
3522                                         || brdr == _DtCvBORDER_TOP_LEFT
3523                                         || brdr == _DtCvBORDER_BOTTOM_LEFT)
3524                             break;
3525     
3526             case _DtCvBORDER_BOTTOM_RIGHT:
3527                         /*
3528                          * if we didn't fall thru from above, we need to
3529                          * add the extension to the bottom to get the
3530                          * full length for the right vertical line.
3531                          */
3532                         if (brdr == _DtCvBORDER_BOTTOM_RIGHT)
3533                             bot_y += line_width;
3534
3535             case _DtCvBORDER_RIGHT:
3536             case _DtCvBORDER_TOP_RIGHT:
3537                         SaveLine(canvas, layout, _DtCvLINE_VERT,
3538                                                 data, line_width,
3539                                 right_x - line_width, top_y, bot_y - top_y);
3540           }
3541       }
3542
3543     return ((canvas->line_cnt - cnt) * mod);
3544 }
3545
3546 /******************************************************************************
3547  * Function: AdjustObjectPosition
3548  *
3549  * Parameters:
3550  *              canvas          Specifies the virtual canvas on which
3551  *                              lines are drawn.
3552  *              justify         Specifies the vertical adjustment for the
3553  *                              object.
3554  *              start_txt       Specifies the start index of the text list.
3555  *              start_gr        Specifies the start index of the graphics list.
3556  *              start_ln        Specifies the start index of the line list.
3557  *              end_txt         Specifies the end indext of the text list.
3558  *              end_gr          Specifies the end indext of the graphics list.
3559  *              end_ln          Specifies the end indext of the line list.
3560  *              height_adj      Specifies the internal height adjust value.
3561  *                              Depending on the justify type, this may
3562  *                              add to y_adj for text and regions, bottom
3563  *                              lines and the height of vertical lines.
3564  *              y_adj           Specifies the y position adjustment.
3565  *                              Lines, text and regions are moved this
3566  *                              amount.
3567  *              internal_y      Specifies the internal y position adjustment.
3568  *                              height_adj includes this value. Text and
3569  *                              regions are moved this amount.
3570  *
3571  * Return:      nothing.
3572  *
3573  *****************************************************************************/
3574 static void
3575 AdjustObjectPosition(
3576     _DtCanvasStruct     *canvas,
3577     LayoutInfo          *layout,
3578     _DtCvFrmtOption      justify,
3579     int                  start_txt,
3580     int                  start_ln,
3581     int                  start_brk,
3582     int                  end_txt,
3583     int                  end_ln,
3584     int                  end_brk,
3585     int                  brdr_cnt,
3586     _DtCvUnit            height_adj,
3587     _DtCvUnit            x_adj,
3588     _DtCvUnit            y_adj,
3589     _DtCvUnit            internal_y)
3590 {
3591     int   mod  = 1;
3592     _DtCvUnit  yOff = 0;
3593
3594     /*
3595      * If border count is negative, indicates the first line in the
3596      * list is bottom line. This requires special handling in adjusting
3597      * its position. Set flags accordingly.
3598      */
3599     if (brdr_cnt < 0)
3600       {
3601         mod = -1;
3602         brdr_cnt = -brdr_cnt;
3603       }
3604
3605     /*
3606      * calculate the offset value within the object for other objects
3607      * contained in this object.
3608      */
3609     if (justify != _DtCvJUSTIFY_TOP)
3610       {
3611         yOff = height_adj - internal_y;
3612         if (justify == _DtCvJUSTIFY_CENTER)
3613             yOff /= 2;
3614       }
3615     
3616     yOff += y_adj;
3617     yOff += internal_y;
3618
3619     /*
3620      * don't modify the border lines around this object yet.
3621      */
3622     end_ln -= brdr_cnt;
3623
3624     /*
3625      * modify the border lines of the objects contained within
3626      * this object.
3627      */
3628     AdjustLinePositions(canvas, start_ln, end_ln, x_adj, yOff);
3629
3630     /*
3631      * now adjust the border lines around this object.
3632      */
3633     start_ln = end_ln;
3634     end_ln += brdr_cnt;
3635     AdjustLinePositions(canvas, start_ln, end_ln, x_adj, y_adj);
3636
3637     /*
3638      * now fix the lines if they've changed height and move
3639      * the first line to its bottom position if necessary.
3640      */
3641     if (0 != height_adj)
3642       {
3643         while (start_ln < end_ln)
3644           {
3645             /*
3646              * indicates the bottom line is the first line in the
3647              * list. Move it down the height adjustment.
3648              */
3649             if (mod < 0)
3650               {
3651                 canvas->line_lst[start_ln].pos_y += height_adj;
3652                 canvas->line_lst[start_ln].max_y += height_adj;
3653
3654                 mod = 1;
3655               }
3656             /*
3657              * stretch the vertical lines
3658              */
3659             else if (canvas->line_lst[start_ln].dir == _DtCvLINE_VERT)
3660                 canvas->line_lst[start_ln].max_y += height_adj;
3661
3662             start_ln++;
3663           }
3664       }
3665
3666     /*
3667      * adjust the position of the text within this object.
3668      */
3669     AdjustTextPositions (canvas, start_txt, end_txt, x_adj, yOff);
3670
3671     /*
3672      * adjust the position of the text within this object.
3673      */
3674     AdjustPgBrk (canvas, start_brk, end_brk, yOff);
3675 }
3676
3677 /******************************************************************************
3678  * Function: LinesMayChange
3679  *
3680  * Parameters:
3681  *              canvas          Specifies the virtual canvas on which
3682  *                              lines are drawn.
3683  *              start_ln        Specifies the start index of the line list.
3684  *              end_ln          Specifies the end indext of the line list.
3685  *
3686  * Return:      True    if there is a vertical line as a child of a container.
3687  *              False   if there are no vertical lines in the child of a
3688  *                      container/cell.
3689  *
3690  *****************************************************************************/
3691 static _DtCvValue
3692 LinesMayChange(
3693     _DtCanvasStruct     *canvas,
3694     int                  start_ln,
3695     int                  end_ln,
3696     int                  brdr_cnt)
3697 {
3698     /*
3699      * If border count is negative, indicates that one of the lines
3700      * is for the bottom of the container/cell. Ignore for now.
3701      * we want to check the lines in the container/cell.
3702      */
3703     if (brdr_cnt < 0)
3704         brdr_cnt = -brdr_cnt;
3705
3706     /*
3707      * get rid of the line count for this object,
3708      * AdjustObjectPosition can take care of it.
3709      */
3710     end_ln -= brdr_cnt;
3711
3712     /*
3713      * Now check for vertical lines that would
3714      * be affected by a height change.
3715      */
3716     while (start_ln < end_ln)
3717       {
3718         if (_DtCvLINE_VERT == canvas->line_lst[start_ln].dir)
3719             return True;
3720         start_ln++;
3721       }
3722
3723     return False;
3724 }
3725
3726 /******************************************************************************
3727  * Function: ProcessContainer
3728  *
3729  * Initializes the display line and graphic tables.
3730  *****************************************************************************/
3731 static void
3732 ProcessContainer(
3733     _DtCanvasStruct     *canvas,
3734     LayoutInfo          *layout,
3735     _DtCvSegmentI       *con_seg,
3736     _DtCvUnit            min_y,
3737     _DtCvUnit           *ret_width,
3738     _DtCvUnit           *ret_max_x,
3739     int                 *ret_cnt)
3740 {
3741     int            getLn;
3742     const char    *saveJustifyChar = layout->info.align_char;
3743     _DtCvUnit      yPad         = 0;
3744     _DtCvUnit      xPad         = 0;
3745     _DtCvUnit      maxWidth     = 0;
3746     _DtCvUnit      maxXPos      = 0;
3747     _DtCvUnit      myMinY       = -1;
3748     _DtCvUnit      saveLeft     = layout->left;
3749     _DtCvUnit      saveRight    = layout->right;
3750     _DtCvUnit      saveLead     = layout->info.leading;
3751     _DtCvUnit      saveFirst    = layout->first;
3752     _DtCvUnit      saveYpos     = layout->info.y_pos;
3753     _DtCvValue     saveStatic   = layout->stat_flag;
3754     _DtCvValue     saveBrdr     = layout->brdr_flag;
3755     _DtCvFrmtOption   saveJustify  = layout->txt_justify;
3756     LayFrmtInfo    frmtInfo;
3757     DataPoint      basePt;
3758     DataPoint      curPt;
3759
3760     /*
3761      * check to see if this element breaks the formatting sequence.
3762      * If so save any information in the buffer, reset the margins and
3763      * add the appropriate lines, and check for going over boundaries.
3764      */
3765     if (NotJoining(layout))
3766       {
3767         CheckSaveInfo(canvas, layout, con_seg, 0);
3768         CheckFormat(layout, True);
3769       }
3770
3771     /*
3772      * check to see if this segment is the segment we want as our first
3773      * visible line.
3774      */
3775     CheckId(layout, _DtCvContainerIdOfSeg(con_seg));
3776
3777     /*
3778      * Set beginning text and line counts
3779      */
3780     frmtInfo = DefLayFrmtInfo;
3781     SetBeginCounts(canvas, &(frmtInfo.cnt));
3782
3783     /*
3784      * Get the first indent and set the current container pointer to me.
3785      */
3786     layout->first = _DtCvContainerFMarginOfSeg(con_seg) / layout->divisor;
3787     layout->left  = _DtCvContainerLMarginOfSeg(con_seg) / layout->divisor;
3788     layout->right = _DtCvContainerRMarginOfSeg(con_seg) / layout->divisor;
3789     layout->info.leading = _DtCvContainerLeadingOfSeg(con_seg);
3790
3791     /*
3792      * check to see if we violate the horiz_pad_hint on the left, right or
3793      * first margins.
3794      */
3795     if (canvas->metrics.horiz_pad_hint > _DtCvContainerLMarginOfSeg(con_seg))
3796         layout->left = _DtCvContainerLMarginOfSeg(con_seg);
3797     else if (layout->left < canvas->metrics.horiz_pad_hint)
3798         layout->left = canvas->metrics.horiz_pad_hint;
3799
3800     if (canvas->metrics.horiz_pad_hint > _DtCvContainerRMarginOfSeg(con_seg))
3801         layout->right = _DtCvContainerRMarginOfSeg(con_seg);
3802     else if (layout->right < canvas->metrics.horiz_pad_hint)
3803         layout->right = canvas->metrics.horiz_pad_hint;
3804
3805     if (canvas->metrics.horiz_pad_hint > _DtCvContainerFMarginOfSeg(con_seg))
3806         layout->first = _DtCvContainerFMarginOfSeg(con_seg);
3807     else if (layout->first < canvas->metrics.horiz_pad_hint)
3808         layout->first = canvas->metrics.horiz_pad_hint;
3809
3810     /*
3811      * check to see if there is more squeeze room available.
3812      */
3813     if (layout->left > canvas->metrics.horiz_pad_hint
3814                         || layout->right > canvas->metrics.horiz_pad_hint
3815                         || layout->first > canvas->metrics.horiz_pad_hint)
3816         layout->margin_non_zero = True;
3817
3818     /*
3819      * set the formatting type for this container
3820      */
3821     layout->stat_flag = False;
3822     if (_DtCvContainerTypeOfSeg(con_seg) == _DtCvLITERAL)
3823         layout->stat_flag = True;
3824
3825     /*
3826      * check to see if this element breaks the formatting sequence.
3827      * If so, add lines, etc.
3828      */
3829     if (NotJoining(layout))
3830       {
3831         /*
3832          * Adjust margins and y position for bordering
3833          */
3834         AdjustForBorders (canvas, layout, Border(con_seg), BrdWidth(con_seg),
3835                                                                 &yPad, &xPad);
3836
3837         _DtCvAddSpace(_DtCvContainerTMarginOfSeg(con_seg),
3838                                                         &(layout->info.y_pos));
3839         /*
3840          * check for flow limits.
3841          */
3842         CheckFormat(layout, True);
3843
3844         /*
3845          * get the parent's data point in the stack
3846          * and add the current container's left and right to it.
3847          */
3848         GetCurrentDataPoint(layout, &basePt);
3849         basePt.left  += saveLeft;
3850         basePt.right += saveRight;
3851
3852         /*
3853          * if we don't inherit the the text justification
3854          * set the new value.
3855          */
3856         if (_DtCvINHERIT != _DtCvContainerJustifyOfSeg(con_seg))
3857           {
3858             layout->txt_justify  = _DtCvContainerJustifyOfSeg(con_seg);
3859             if (_DtCvJUSTIFY_NUM == layout->txt_justify)
3860                 layout->info.align_char = PeriodStr;
3861             else if (_DtCvJUSTIFY_CHAR == layout->txt_justify)
3862               {
3863                 layout->info.align_char = _DtCvContainerJustifyCharOfSeg(con_seg);
3864                 /*
3865                  * check to see if the character is 'valid'.
3866                  * if not, default out of JUSTIFY_CHAR
3867                  */
3868                 if ( (NULL != layout->info.align_char) && ( '\0' != *layout->info.align_char)) 
3869                     layout->txt_justify = _DtCvJUSTIFY_LEFT;
3870               }
3871           }
3872
3873         /*
3874          * terminate the previous rendering list
3875          */
3876         if (NULL != layout->lst_rendered)
3877             layout->lst_rendered->next_disp = NULL;
3878         layout->lst_rendered = NULL;
3879
3880         /*
3881          * push the data point and reset margin/text info.
3882          */
3883         PushDataPoint(layout, &basePt);
3884         SetMargins(layout);
3885         SetTextPosition(layout, True);
3886       }
3887
3888     /*
3889      * determine the minimum Y that the child of this container should
3890      * occupy.  To do so, subtract off the bottom border pad and the
3891      * bottom margin.
3892      */
3893     if (0 < min_y)
3894       {
3895         myMinY = min_y - yPad;
3896         if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
3897           {
3898             _DtCvUnit bPad = 0;
3899
3900             _DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg), &bPad);
3901             myMinY -= bPad;
3902           }
3903       }
3904
3905     /*
3906      * format the segment
3907      */
3908     saveYpos = layout->info.y_pos;
3909
3910     GetCurrentDataPoint(layout, &curPt);
3911
3912     /*
3913      * reset the max x variable
3914      */
3915     layout->info.cur_max_x = 0;
3916     ProcessSegmentList(canvas, layout, _DtCvContainerListOfSeg(con_seg),
3917                                         myMinY,
3918                                         &maxWidth, &maxXPos, NULL);
3919     /*
3920      * if this container forces a wrap join of the next item,
3921      * save the current line, but don't add space or null the
3922      * last rendered item.
3923      */
3924     CheckSaveInfo(canvas, layout, con_seg, 0);
3925     if (maxWidth < layout->info.cur_max_x - curPt.left + layout->right)
3926         maxWidth = layout->info.cur_max_x - curPt.left + layout->right;
3927     if (maxXPos < layout->info.cur_max_x)
3928         maxXPos = layout->info.cur_max_x;
3929
3930     if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
3931       {
3932         /*
3933          * Save any information in the buffer,
3934          * reset the margins and add the appropriate lines,
3935          * and check for going over boundaries.
3936          */
3937         _DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg),
3938                                                         &(layout->info.y_pos));
3939
3940         /*
3941          * terminate the previous rendering list
3942          */
3943         if (NULL != layout->lst_rendered)
3944             layout->lst_rendered->next_disp = NULL;
3945         layout->lst_rendered = NULL;
3946       }
3947
3948     /*
3949      * remove this element's data points from the stack.
3950      */
3951     RemoveDataPoint(layout, &basePt);
3952
3953     /*
3954      * include the bottom border (if needed) in the ending y position
3955      */
3956     layout->info.y_pos += yPad;
3957
3958     /*
3959      * Set the ending counts for the lines and text in me.
3960      * This sets the ending counts for the lines contained in me,
3961      * NOT the lines in my border.
3962      */
3963     SetEndCounts(canvas, &(frmtInfo.cnt), 0);
3964
3965     /*
3966      * does this object need to be adjust within its height?
3967      */
3968     if (0 < min_y && layout->info.y_pos < min_y)
3969       {
3970         AdjustObjectPosition(canvas, layout, TxtVertJustify(con_seg),
3971                         frmtInfo.cnt.beg_txt, frmtInfo.cnt.beg_ln,
3972                         frmtInfo.cnt.beg_brk,
3973                         frmtInfo.cnt.end_txt, frmtInfo.cnt.end_ln,
3974                         frmtInfo.cnt.end_brk,
3975                         0, min_y - layout->info.y_pos - yPad, 0, 0, 0);
3976         layout->info.y_pos = min_y;
3977       }
3978
3979     /*
3980      * Now draw the borders
3981      * If borders are drawn, cur_max_x & max_x_pos may get changed
3982      * if a right side border is drawn.
3983      */
3984     if (maxWidth < layout->max_width - curPt.left - curPt.right)
3985         maxWidth = layout->max_width - curPt.left - curPt.right;
3986
3987     getLn = DrawBorders (canvas, layout, Border(con_seg),
3988                                 BrdData(con_seg), BrdWidth(con_seg),
3989                                 saveYpos, layout->info.y_pos - yPad,
3990                                 curPt.left,
3991                                 curPt.left + maxWidth);
3992
3993     /*
3994      * check to see if we need to save the container counts away
3995      * because we might need to move the entire container as one
3996      * to honor the boundary. This will occur if the flag to honor
3997      * a boundary is set to _DtCvUSE_BOUNDARY_MOVE, this container has
3998      * border lines, the container's parent is not a table nor
3999      * is the container within another container that has a border.
4000      */
4001     if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint
4002                         && True == layout->brdr_flag
4003                         && False == saveBrdr && False == layout->table_flag)
4004       {
4005         GrpInfo *info = (GrpInfo *) malloc (sizeof(GrpInfo));
4006
4007         /*
4008          * warning - nothing done if malloc error.
4009          */
4010         if (NULL != info)
4011           {
4012             /*
4013              * initialize to the end information of the container.
4014              */
4015             info->cnt = frmtInfo.cnt;
4016
4017             /*
4018              * take into account the borders for this container
4019              */
4020             SetEndCounts(canvas, &(info->cnt), getLn);
4021
4022             /*
4023              * set the linked list information
4024              */
4025             info->next_info = layout->grp_lst;
4026             layout->grp_lst = info;
4027           }
4028       }
4029
4030     /*
4031      * set the return values.
4032      */
4033     *ret_max_x = layout->info.cur_max_x;
4034     *ret_width = maxWidth;
4035     if (*ret_width < layout->max_width - curPt.left - curPt.right)
4036         *ret_width = layout->max_width - curPt.left - curPt.right;
4037
4038     /*
4039      * Restore the previous information
4040      */
4041     layout->left      = saveLeft;
4042     layout->right     = saveRight;
4043     layout->first     = saveFirst;
4044     layout->stat_flag = saveStatic;
4045     layout->brdr_flag = saveBrdr;
4046     layout->info.leading = saveLead;
4047
4048     /*
4049      * Besides checking for flow constraints, also (re)sets margins and
4050      * text information.
4051      */
4052     CheckFormat(layout, True);
4053     layout->txt_justify  = saveJustify;
4054     layout->info.align_char  = saveJustifyChar;
4055
4056     /*
4057      * for tables and such, return how many lines were drawn around this
4058      * container.
4059      */
4060     if (ret_cnt)
4061         *ret_cnt = getLn;
4062
4063     return;
4064 }
4065
4066 /******************************************************************************
4067  * Function: ProcessSegmentList
4068  *
4069  * Process the segment list, laying it out according to left, right,
4070  * and first margins specified. Returns the max_width of the all
4071  * segments processed and the maximum x coordinate used.
4072  *****************************************************************************/
4073 static void
4074 ProcessSegmentList(
4075     _DtCanvasStruct     *canvas,
4076     LayoutInfo          *layout,
4077     _DtCvSegmentI       *cur_seg,
4078     _DtCvUnit            min_y,
4079     _DtCvUnit           *ret_width,
4080     _DtCvUnit           *ret_max_x,
4081     int                 **ret_vert)
4082 {
4083     int          junk;
4084     int          saveTravCnt  = canvas->trav_cnt;
4085     int          saveTxtCnt   = canvas->txt_cnt;
4086     int          saveLineCnt  = canvas->line_cnt;
4087     int          saveBrkCnt   = canvas->brk_cnt;
4088     _DtCvUnit    tempX;
4089     _DtCvUnit    tempLen;
4090     _DtCvUnit    width;
4091     _DtCvUnit    nWidth       = 0;
4092     _DtCvUnit    leftMargin   = 0;
4093     _DtCvUnit    rightMargin  = 0;
4094     _DtCvUnit    topHeight    = 0;
4095     _DtCvUnit    botHeight    = 0;
4096     _DtCvUnit    maxWidth     = 0;
4097     _DtCvUnit    saveYpos     = layout->info.y_pos;
4098     _DtCvSegmentI       *segStart     = cur_seg;
4099     LayFrmtInfo         *headInfo     = NULL;
4100     LayFrmtInfo         *lastHead     = NULL;
4101     LayFrmtInfo         *nxtHead;
4102     _DtCvLayoutInfo      startInfo;
4103
4104     _DtCvValue   redo         = False;
4105     _DtCvValue   joinCleared  = False;
4106     _DtCvValue   flag;
4107
4108     TopDims      topBot;
4109     SideDims     sideDims;
4110     CornerDims   cornerDims;
4111     FlowDims     flowDims;
4112     DataPoint    basePt;
4113     DataPoint    leftPt;
4114     DataPoint    rightPt;
4115
4116     /*
4117      * clear the controller arrays
4118      */
4119     InitDimArrays(&topBot, &sideDims, &cornerDims, &flowDims);
4120
4121     /*
4122      * get the current left and right values or 'base'.
4123      */
4124     GetCurrentDataPoint(layout, &basePt);
4125
4126     /*
4127      * ???
4128      */
4129     leftPt  = basePt;
4130     rightPt = basePt;
4131     leftPt.y_pos  = _CEFORMAT_ALL;
4132     rightPt.y_pos = _CEFORMAT_ALL;
4133
4134     /*
4135      * process all the controller type containers in the segment list
4136      */
4137     while (NULL != cur_seg)
4138       {
4139         if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
4140           {
4141             /*
4142              * want to clear this once and only once. Then any join
4143              * directives will survive, though if two or more controllers
4144              * have the directive set, the 'last' one will win out.
4145              */
4146             if (False == joinCleared)
4147               {
4148                 _DtCvSetJoinInfo(&(layout->info), False, -1);
4149                 joinCleared = True;
4150               }
4151
4152             /*
4153              * process the 'controller'
4154              */
4155             nxtHead = ProcessController(canvas, layout, cur_seg);
4156
4157             /*
4158              * update the dimension arrays so that the controller
4159              * will get placed correctly.
4160              */
4161             UpdateDimensionArrays(cur_seg, nxtHead->width, nxtHead->height,
4162                                 &topBot, &sideDims, &cornerDims, &flowDims,
4163                                 &leftMargin, &rightMargin);
4164
4165             /*
4166              * remember this controller.
4167              */
4168             if (NULL == headInfo)
4169                 headInfo = nxtHead;
4170             else
4171                 lastHead->next_info = nxtHead;
4172             lastHead = nxtHead;
4173           }
4174
4175         /*
4176          * go to the next segment
4177          */
4178         cur_seg = cur_seg->next_seg;
4179       }
4180
4181     /*
4182      * Now reset the margins based on the controllers found
4183      */
4184     if (NULL != headInfo)
4185       {
4186         DetermineMaxDims(&topBot, &cornerDims, leftMargin, rightMargin,
4187                             &topHeight, &botHeight, &maxWidth);
4188         layout->info.y_pos += topHeight;
4189         layout->left       += leftMargin;
4190         layout->right      += rightMargin;
4191         DetermineFlowConstraints(layout, flowDims,
4192                             basePt.left, basePt.right,
4193                             layout->info.y_pos, &leftPt, &rightPt);
4194
4195         /*
4196          * get rid of the leftMargin and rightMargin values in maxWidth
4197          * otherwise the use of layout->left & layout->right will double
4198          * the value.
4199          */
4200         maxWidth = maxWidth - leftMargin - rightMargin;
4201         if (layout->max_width < maxWidth + basePt.left + basePt.right +
4202                             layout->left + layout->right)
4203             layout->max_width = maxWidth + basePt.left + basePt.right +
4204                                             layout->left + layout->right;
4205
4206         SetMargins(layout);
4207         SetTextPosition(layout, True);
4208         if (JoinSet(layout))
4209           {
4210             int  cnt;
4211             int  joinLine = layout->info.join_line;
4212             int  start    = canvas->txt_lst[joinLine].byte_index;
4213             int  count    = canvas->txt_lst[joinLine].length;
4214             _DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
4215             _DtCvUnit     tmpWidth;
4216
4217             /*
4218              * change the starting location of the following text.
4219              * take into account the left margin that *hasn't*
4220              * been added to the controlling container.
4221              */
4222             layout->info.text_x_pos  = canvas->txt_lst[joinLine].text_x
4223                                                         + layout->lmargin;
4224             layout->info.cur_len = 0;
4225
4226             /*
4227              * now calculate the width of this line.
4228              */
4229             while (pSeg != NULL && count > 0)
4230               {
4231                 _DtCvGetWidthOfSegment(canvas,pSeg,start,count,
4232                                                     &cnt, &tmpWidth, NULL);
4233                 layout->info.text_x_pos += tmpWidth;
4234                 count -= cnt;
4235                 start  = 0;
4236                 pSeg   = pSeg->next_disp;
4237               }
4238           }
4239       }
4240
4241     /*
4242      * now format for non-controller containers and non-containers.
4243      * re-start at the beginning.
4244      */
4245     cur_seg   = segStart;
4246
4247     /*
4248      * Save some information incase we have to redo the layout. I.e.
4249      * we overflow the sizing.
4250      */
4251     startInfo = layout->info;
4252     saveTravCnt = canvas->trav_cnt;
4253     saveTxtCnt   = canvas->txt_cnt;
4254     saveLineCnt  = canvas->line_cnt;
4255     saveBrkCnt   = canvas->brk_cnt;
4256
4257     while (NULL != cur_seg)
4258       {
4259         width = layout->max_width - layout->info.text_x_pos
4260                                 - layout->rmargin - layout->info.cur_len;
4261
4262         /*
4263          * check to see if this item should start a line.
4264          */
4265         CheckSetLineStart(layout, cur_seg);
4266
4267         /*
4268          * check to see if this item will cause a page break.
4269          */
4270         CheckForPageBreak(canvas, cur_seg, layout->info.y_pos);
4271
4272         switch (_DtCvPrimaryTypeOfSeg(cur_seg))
4273           {
4274             case _DtCvCONTAINER:
4275                     if (!(_DtCvIsSegController(cur_seg)))
4276                         ProcessContainer(canvas, layout, cur_seg, min_y,
4277                                                 &junk, &junk, &junk);
4278                     break;
4279
4280             case _DtCvREGION:
4281                     /*
4282                      * flag that this segment needs a line number
4283                      */
4284                     cur_seg->internal_use = (void *) -1;
4285
4286                     /*
4287                      * process the segment
4288                      */
4289                     if (_DtCvIsSegInLine(cur_seg))
4290                       {
4291                         /*
4292                          * if a hypertext link, this will add it to
4293                          * the internal list.
4294                          */
4295                         CheckAddToHyperList(canvas, cur_seg);
4296
4297                         /*
4298                          * get the traversal width
4299                          */
4300                         nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
4301                                                     layout->info.lst_hyper);
4302
4303                         /*
4304                          * check to see if this region can end a line
4305                          */
4306                         flag = _DtCvCheckLineSyntax(canvas,cur_seg,0,0,False);
4307
4308                         /*
4309                          * if this can't end a line, get the length up to
4310                          * the next segment that can and base whether to
4311                          * save pased on that.
4312                          */
4313                         tempLen = 0;
4314                         if (False == flag)
4315                           {
4316                             tempLen = _DtCvGetNextWidth(canvas,
4317                                                 _DtCvSTRING,
4318                                                 layout->info.lst_hyper,
4319                                                 cur_seg->next_seg,
4320                                                 0, cur_seg, NULL, NULL, NULL);
4321                             /*
4322                              * if the next width is zero, reset the flag.
4323                              */
4324                             if (tempLen <= 0)
4325                                 flag = True;
4326                           }
4327                         tempLen += nWidth;
4328
4329                         /*
4330                          * if not joining, but my length goes over the
4331                          * working width, save out the current buffered
4332                          * information
4333                          */
4334                         if (NotJoining(layout) &&
4335                             _DtCvWidthOfRegionSeg(cur_seg) + tempLen > width)
4336                             CheckSaveInfo (canvas, layout, cur_seg, 0);
4337
4338                         /*
4339                          * up counts on the buffered information.
4340                          */
4341                         layout->info.line_bytes += 1;
4342                         layout->info.cur_len    += 
4343                                 (_DtCvWidthOfRegionSeg(cur_seg) + nWidth);
4344
4345                         /*
4346                          * does the next segment need to join with
4347                          * this one? If so, set the information
4348                          */
4349                         _DtCvSetJoinInfo(&(layout->info), (flag ? 0 : 1), -1);
4350                         if (_DtCvIsSegNewLine(cur_seg))
4351                             SaveInfo(canvas, layout, cur_seg, 0);
4352                       }
4353                     else
4354                       {
4355                         /*
4356                          * clear out the join information
4357                          * standalone figures can't join with others.
4358                          */
4359                         _DtCvSetJoinInfo(&(layout->info), False, -1);
4360
4361                         /*
4362                          * figures are standalone. Save any
4363                          * information in the buffer away.
4364                          */
4365                         CheckSaveInfo (canvas, layout, cur_seg, 0);
4366
4367                         /*
4368                          * check to see if this segment is
4369                          * a hypertext. If so, add it to the
4370                          * list if it hasn't been added yet.
4371                          */
4372                         CheckAddToHyperList(canvas, cur_seg);
4373
4374                         /*
4375                          * get the traversal width, if any.
4376                          */
4377                         nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
4378                                                     layout->info.lst_hyper);
4379
4380                         /*
4381                          * now save the standalone figure
4382                          */
4383                         layout->info.line_bytes += 1;
4384                         layout->info.cur_len    += 
4385                                 _DtCvWidthOfRegionSeg(cur_seg) + nWidth;
4386                         SaveInfo(canvas, layout, cur_seg->next_seg, 0);
4387
4388                         /*
4389                          * check for wrapping overflow
4390                          */
4391                         CheckFormat(layout, False);
4392                       }
4393
4394                     /*
4395                      * indicate this segment as the last item rendered
4396                      */
4397                     if (NULL != layout->lst_rendered)
4398                         layout->lst_rendered->next_disp = cur_seg;
4399                     layout->lst_rendered = cur_seg;
4400                     break;
4401
4402             case _DtCvLINE:
4403                     /*
4404                      * lines are standalone. Save any
4405                      * information in the buffer away.
4406                      */
4407                     CheckSaveInfo (canvas, layout, cur_seg, 0);
4408
4409                     /*
4410                      * if the line_width is zero, make it 1 so
4411                      * that it really does take some space.
4412                      */
4413                     nWidth = _DtCvWidthOfLineSeg(cur_seg);
4414                     if (0 == nWidth)
4415                         nWidth = 1;
4416
4417                     /*
4418                      * start with it going all the way across the window.
4419                      */
4420                     width = layout->max_width;
4421                     tempX = 0;
4422
4423                     /*
4424                      * or does it only extend across the container?
4425                      */
4426                     if (_DtCvIsSegBlockLine(cur_seg))
4427                       {
4428                         tempX = layout->lmargin;
4429                         width = layout->max_width - tempX - layout->rmargin;
4430                       }
4431
4432                     SaveLine (canvas, layout, _DtCvLINE_HORZ,
4433                                 _DtCvDataOfLineSeg(cur_seg), nWidth, tempX,
4434                                 layout->info.y_pos, width);
4435
4436                     layout->info.y_pos += nWidth;
4437                     break;
4438
4439             case _DtCvMARKER:
4440                     /*
4441                      * check to see if marker is the target id
4442                      */
4443                     CheckId(layout, _DtCvIdOfMarkerSeg(cur_seg));
4444                     break;
4445
4446             case _DtCvNOOP:
4447                     if (_DtCvIsSegNewLine(cur_seg))
4448                         SaveInfo(canvas, layout, cur_seg, 0);
4449                     break;
4450
4451             case _DtCvSTRING:
4452                     /*
4453                      * flag that this segment needs a line number
4454                      */
4455                     cur_seg->internal_use = (void *) -1;
4456
4457                     /*
4458                      * process the string
4459                      */
4460                     ProcessStringSegment(canvas, layout, cur_seg);
4461
4462                     /*
4463                      * check for wrapping overflow.
4464                      */
4465                     if (_DtCvIsSegNewLine(cur_seg))
4466                         CheckFormat(layout, False);
4467
4468                     /*
4469                      * indicate this segment as the last item rendered
4470                      */
4471                     if (NULL != layout->lst_rendered)
4472                         layout->lst_rendered->next_disp = cur_seg;
4473                     layout->lst_rendered = cur_seg;
4474                     break;
4475
4476             case _DtCvTABLE:
4477                     ProcessTable(canvas, layout, cur_seg, min_y);
4478             default:
4479                     break;
4480           }
4481
4482         /*
4483          * get the next segment
4484          */
4485         cur_seg = cur_seg->next_seg;
4486
4487         /*
4488          * check the flowing text points
4489          */
4490         if (leftPt.y_pos > 0 &&
4491                 leftPt.x_units > layout->max_width - leftPt.left - leftPt.right)
4492           {
4493             layout->max_width = leftPt.x_units + leftPt.left + leftPt.right;
4494             redo = True;
4495           }
4496         if (rightPt.y_pos > 0 &&
4497                 rightPt.x_units > layout->max_width-rightPt.left-rightPt.right)
4498           {
4499             layout->max_width = rightPt.x_units + rightPt.left + rightPt.right;
4500             redo = True;
4501           }
4502
4503         /*
4504          * have we violated the available space?
4505          * if so, we'll have to reformat.
4506          */
4507         if (redo == True)
4508           {
4509             redo             = False;
4510             cur_seg          = segStart;
4511             canvas->trav_cnt = saveTravCnt;
4512             canvas->txt_cnt  = saveTxtCnt;
4513             canvas->line_cnt = saveLineCnt;
4514             canvas->brk_cnt  = saveBrkCnt;
4515             layout->info     = startInfo;
4516
4517             if (rightPt.y_pos > 0)
4518               {
4519                 RemoveDataPoint(layout, &rightPt); /* make sure its gone */
4520                 InsertDataPoint(layout, &rightPt);
4521               }
4522             if (leftPt.y_pos > 0)
4523               {
4524                 RemoveDataPoint(layout, &leftPt); /* make sure its gone */
4525                 InsertDataPoint(layout, &leftPt);
4526               }
4527
4528             /*
4529              * Now reset the margins based on the controllers found
4530              */
4531             if (NULL != headInfo)
4532               {
4533                 layout->left   += leftMargin;
4534                 layout->right  += rightMargin;
4535                 SetMargins(layout);
4536                 SetTextPosition(layout, True);
4537                 if (JoinSet(layout))
4538                   {
4539                     int  cnt;
4540                     int  joinLine = layout->info.join_line;
4541                     int  start    = canvas->txt_lst[joinLine].byte_index;
4542                     int  count    = canvas->txt_lst[joinLine].length;
4543                     _DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
4544                     _DtCvUnit     tmpWidth;
4545         
4546                     /*
4547                      * change the starting location of the following text.
4548                      * take into account the left margin that *hasn't*
4549                      * been added to the controlling container.
4550                      */
4551                     layout->info.text_x_pos  = canvas->txt_lst[joinLine].text_x
4552                                                         + layout->lmargin;
4553                     layout->info.cur_len = 0;
4554         
4555                     /*
4556                      * now calculate the width of this line.
4557                      */
4558                     while (pSeg != NULL && count > 0)
4559                       {
4560                         _DtCvGetWidthOfSegment(canvas,pSeg,start,count,
4561                                                         &cnt, &tmpWidth, NULL);
4562                         layout->info.text_x_pos += tmpWidth;
4563                         count -= cnt;
4564                         start  = 0;
4565                         pSeg   = pSeg->next_disp;
4566                       }
4567                   }
4568               }
4569           }
4570       }
4571
4572     RemoveDataPoint(layout, &leftPt);
4573     RemoveDataPoint(layout, &rightPt);
4574
4575     /*
4576      * if there were heads, now place them correctly.
4577      */
4578     if (NULL != headInfo)
4579       {
4580         _DtCvUnit       blockHeight;
4581         _DtCvUnit       blockWidth;
4582
4583         /*
4584          * make sure all of the information in the body is saved out
4585          */
4586         CheckSaveInfo (canvas, layout, NULL, 0);
4587
4588         /*
4589          * now calculate the non-controllers overall height.
4590          */
4591         blockHeight = layout->info.y_pos - saveYpos - topHeight;
4592
4593         /*
4594          * now figure the head positions.
4595          */
4596         DetermineHeadPositioning(&topBot, &sideDims, &cornerDims, &flowDims,
4597                                 saveYpos, topHeight,
4598                                 blockHeight, &blockHeight);
4599         /*
4600          * if the maximum available space was exceeded by the text
4601          * calculate a new max width
4602          */
4603         if (layout->max_width < layout->info.cur_max_x + layout->right)
4604             layout->max_width = layout->info.cur_max_x + layout->right;
4605
4606         blockWidth = layout->max_width - basePt.left - basePt.right
4607                                                 - layout->left - layout->right;
4608
4609         nxtHead = headInfo;
4610         cur_seg = segStart;
4611         while (cur_seg != NULL)
4612           {
4613             if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
4614               {
4615                 AdjustHeadPosition(canvas, layout, cur_seg,
4616                         &topBot, &sideDims, &cornerDims, &flowDims, nxtHead,
4617                         0, basePt.left + layout->left - leftMargin, blockWidth,
4618                         leftMargin, rightMargin);
4619                 /*
4620                  * go to the next head element
4621                  */
4622                 nxtHead = nxtHead->next_info;
4623
4624                 /*
4625                  * free the information.
4626                  */
4627                 free(headInfo);
4628                 headInfo = nxtHead;
4629               }
4630
4631             /*
4632              * got to the next segment
4633              */
4634             cur_seg = cur_seg->next_seg;
4635           }
4636
4637         if (layout->info.y_pos < saveYpos + topHeight + blockHeight)
4638             layout->info.y_pos = saveYpos + topHeight + blockHeight;
4639
4640         layout->info.y_pos += botHeight;
4641       }
4642
4643     /*
4644      * set the return values
4645      */
4646     *ret_width = layout->info.cur_max_x - basePt.left + layout->right;
4647     *ret_max_x = layout->info.cur_max_x;
4648
4649     return;
4650 }
4651
4652 /*****************************************************************************
4653  * Function:    static _DtCvUnit MaxOfGroup (
4654  *
4655  * Purpose: Determine the maximum of a group.
4656  *****************************************************************************/
4657 static void
4658 MaxOfGroup (
4659     GrpInfo             *group,
4660     _DtCvDspLine        *text,
4661     _DtCvLineSeg        *lines,
4662     _DtCvUnit            max_x,
4663     _DtCvUnit            max_y)
4664 {
4665     int          i;
4666
4667     /*
4668      * initialize
4669      */
4670     group->min_x = max_x;
4671     group->max_x = 0;
4672     group->top_y = max_y;
4673     group->bot_y = 0;
4674
4675     /*
4676      * find the maximum of the group
4677      */
4678     for (i = group->cnt.beg_txt; i < group->cnt.end_txt; i++)
4679       {
4680         /*
4681          * check for min's and max's
4682          */
4683         if (group->min_x > text[i].text_x)
4684             group->min_x = text[i].text_x;
4685
4686         if (group->max_x < text[i].max_x)
4687             group->max_x = text[i].max_x;
4688
4689         if (group->top_y > text[i].baseline - text[i].ascent)
4690             group->top_y = text[i].baseline - text[i].ascent;
4691
4692         if (group->bot_y < text[i].baseline + text[i].descent)
4693             group->bot_y = text[i].baseline + text[i].descent;
4694
4695         /*
4696          * indicate that this line has been processed already
4697          */
4698         _DtCvSetProcessed(text[i]);
4699       }
4700
4701     for (i = group->cnt.beg_ln; i < group->cnt.end_ln; i++)
4702       {
4703         /*
4704          * check for min's and max's
4705          */
4706         if (group->min_x > lines[i].pos_x)
4707             group->min_x = lines[i].pos_x;
4708
4709         if (group->max_x < lines[i].max_x)
4710             group->max_x = lines[i].max_x;
4711
4712         if (group->top_y > lines[i].pos_y)
4713             group->top_y = lines[i].pos_y;
4714
4715         if (group->bot_y < lines[i].max_y)
4716             group->bot_y = lines[i].max_y;
4717
4718         /*
4719          * indicate that this line has been processed already
4720          */
4721         _DtCvSetProcessed(lines[i]);
4722       }
4723 }
4724
4725 /*****************************************************************************
4726  * Function:    static _DtCvUnit TestSpacing (
4727  *
4728  * Parameters:
4729  *
4730  * Returns:     True    if the object is before (x wise) the test object.
4731  *              False   if the object is not before (x wise) the text object.
4732  *
4733  * Purpose:
4734  * 
4735  *****************************************************************************/
4736 static _DtCvStatus
4737 TestSpacing (
4738     _DtCvUnit            tst_top,
4739     _DtCvUnit            tst_bot,
4740     _DtCvUnit            tst_min,
4741     _DtCvUnit            obj_top,
4742     _DtCvUnit            obj_bot,
4743     _DtCvUnit            obj_max,
4744     _DtCvUnit            needed,
4745     _DtCvUnit            min_space,
4746     _DtCvUnit           *ret_amount)
4747 {
4748     _DtCvStatus  result = False;
4749
4750     /*
4751      * check to see if the object is to the left of the test object
4752      * to move and that it 'infringes' on the vertical
4753      * space of the test object.
4754      *
4755      * I.e.     ----obj_top------
4756      *          |               |   ----tst_top----
4757      *          ----obj_bot------   |             |
4758      *                              ----tst_bot----
4759      *
4760      * I.e.                         ----tst_top----
4761      *          ----obj_top-------  |             |
4762      *          |                |  ----tst_bot----
4763      *          ----obj_bot-------
4764      *
4765      * I.e.     ----obj_top------
4766      *          |               |   ----tst_top----
4767      *          |               |   |             |
4768      *          |               |   ----tst_bot----
4769      *          ----obj_bot------
4770      *
4771      * I.e.                         ----tst_top----
4772      *          ----obj_top-------  |             |
4773      *          |                |  |             |
4774      *          ----obj_bot-------  |             |
4775      *                              ----tst_bot----
4776      */
4777     if (obj_max < tst_min
4778         && True == _DtCvCheckInfringement(tst_top, tst_bot, obj_top, obj_bot)
4779         && needed > tst_min - obj_max)
4780       {
4781         /*
4782          * okay, this infringes on the object's space.
4783          * truncate the amount of room there is to move the object
4784          */
4785         result = True;
4786         needed = tst_min - obj_max;
4787
4788         /*
4789          * is the space between these two objects already squeezed
4790          * below the minimum allowed?
4791          */
4792         if (needed < min_space)
4793             needed = 0;
4794         else /* leave the minimum space between the objects */
4795             needed -= min_space;
4796       }
4797
4798     *ret_amount = needed;
4799     return result;
4800 }
4801
4802 /*****************************************************************************
4803  * Function:    static void MoveLeft (
4804  *
4805  * Parameters:
4806  *
4807  * Returns:
4808  *
4809  * Purpose:     Moves the object's rules/lines and text lines to the left.
4810  * 
4811  *****************************************************************************/
4812 static void
4813 MoveLeft (
4814     _DtCanvasStruct     *canvas,
4815     int                  beg_txt,
4816     int                  end_txt,
4817     int                  beg_ln,
4818     int                  end_ln,
4819     _DtCvUnit            space)
4820 {
4821     int         i;
4822
4823     /*
4824      * bail now if nothing to do.
4825      */
4826     if (1 > space)
4827         return;
4828
4829     /*
4830      * move each text/region line.
4831      */
4832     for (i = beg_txt; i < end_txt; i++)
4833       {
4834         canvas->txt_lst[i].text_x -= space;
4835         canvas->txt_lst[i].max_x  -= space;
4836       }
4837
4838     /*
4839      * move each line/rule.
4840      */
4841     for (i = beg_ln; i < end_ln; i++)
4842       {
4843         canvas->line_lst[i].pos_x -= space;
4844         canvas->line_lst[i].max_x -= space;
4845       }
4846 }
4847
4848 /*****************************************************************************
4849  * Function:    static _DtCvUnit CheckSpacing (
4850  *
4851  * Purpose:     Check the spacing before an object and move any objects
4852  *              before it to the left to make room.
4853  *
4854  *****************************************************************************/
4855 static _DtCvUnit
4856 CheckSpacing (
4857     _DtCanvasStruct     *canvas,
4858     LayoutInfo          *layout,
4859     GrpInfo             *tst_grp,
4860     int                  txt_idx,
4861     int                  line_idx,
4862     _DtCvUnit            top_y,
4863     _DtCvUnit            bot_y,
4864     _DtCvUnit            min_x,
4865     _DtCvUnit            needed)
4866 {
4867     int          i;
4868     _DtCvUnit    space;
4869     _DtCvUnit    maxSpace;
4870     _DtCvUnit    topY;
4871     _DtCvUnit    botY;
4872     GrpInfo     *nxtGrp   = layout->grp_lst;
4873
4874     /*
4875      * truncate if the amount needed is more than available.
4876      */
4877     if (min_x < needed)
4878         needed = min_x;
4879
4880     maxSpace = needed;
4881
4882     /*
4883      * see what group is before this group and how much space there is
4884      */
4885     while (NULL != nxtGrp)
4886       {
4887         /*
4888          * as long as I'm not comparing against myself, try it.
4889          */
4890         if (nxtGrp != tst_grp)
4891           {
4892             /*
4893              * is this group before(x wise) the test group, infringing
4894              * upon the test group's top and bottom positioning (y)
4895              * and is the amount of space (x wise) between them smaller
4896              * than the current smallest space found?
4897              */
4898             if (True == TestSpacing (top_y, bot_y, min_x,
4899                                         nxtGrp->top_y, nxtGrp->bot_y,
4900                                         nxtGrp->max_x, needed,
4901                                         canvas->metrics.horiz_pad_hint,
4902                                         &space))
4903               {
4904                 space += MoveGroup(canvas, layout, nxtGrp, needed - space);
4905                 if (maxSpace > space)
4906                     maxSpace = space;
4907               }
4908           }
4909
4910         /*
4911          * check the next group
4912          */
4913         nxtGrp = nxtGrp->next_info;
4914       }
4915
4916     /*
4917      * look at each of the text lines;
4918      */
4919     for (i = 0; i < canvas->txt_cnt; i++)
4920       {
4921         /*
4922          * Only look at those lines not already processed.
4923          */
4924         if (i != txt_idx && _DtCvIsNotProcessed(canvas->txt_lst[i]))
4925           {
4926             topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
4927             botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
4928             if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
4929                                 canvas->txt_lst[i].max_x, needed,
4930                                 canvas->metrics.horiz_pad_hint, &space))
4931               {
4932                 space += MoveText(canvas, layout, i, topY, botY, needed-space);
4933                 if (maxSpace > space)
4934                     maxSpace = space;
4935               }
4936           }
4937       }
4938
4939     /*
4940      * look at each of the rules/lines;
4941      */
4942     for (i = 0; i < canvas->line_cnt; i++)
4943       {
4944         /*
4945          * Only look at those lines not already processed.
4946          */
4947         if (i != line_idx && _DtCvIsNotProcessed(canvas->line_lst[i]))
4948           {
4949             /*
4950              * calculate the top and bottom of the line
4951              */
4952             topY = canvas->line_lst[i].pos_y;
4953             botY = canvas->line_lst[i].max_y;
4954
4955             if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
4956                                 canvas->line_lst[i].max_x, needed,
4957                                 canvas->metrics.horiz_pad_hint, &space))
4958               {
4959                 space += MoveLines(canvas, layout, i, topY, botY, needed-space);
4960                 if (maxSpace > space)
4961                     maxSpace = space;
4962               }
4963           }
4964       }
4965
4966     return maxSpace;
4967 }
4968
4969 /*****************************************************************************
4970  * Function:    static _DtCvUnit MoveGroup (_DtCanvasStruct canvas);
4971  *
4972  * Purpose:     To move groupings (container, tables, etc.) as a group to
4973  *              honor boundaries.
4974  * 
4975  *****************************************************************************/
4976 static _DtCvUnit
4977 MoveGroup (
4978     _DtCanvasStruct     *canvas,
4979     LayoutInfo          *layout,
4980     GrpInfo             *tst_grp,
4981     _DtCvUnit            needed)
4982 {
4983     _DtCvUnit    space;
4984
4985     /*
4986      * find out what's in front of it. And how much 'extra' room
4987      * there is.
4988      */
4989     space = CheckSpacing(canvas, layout, tst_grp, -1, -1,
4990                                 tst_grp->top_y, tst_grp->bot_y, tst_grp->min_x,
4991                                 needed);
4992     /*
4993      * now move the group
4994      */
4995     MoveLeft(canvas, tst_grp->cnt.beg_txt, tst_grp->cnt.end_txt,
4996                         tst_grp->cnt.beg_ln, tst_grp->cnt.end_ln, space);
4997
4998     tst_grp->max_x -= space;
4999     tst_grp->min_x -= space;
5000
5001     return space;
5002 }
5003
5004 /*****************************************************************************
5005  * Function:    static _DtCvUnit MoveText (_DtCanvasStruct canvas);
5006  *
5007  * Purpose: To move text lines to honor boundaries.
5008  * 
5009  *****************************************************************************/
5010 static _DtCvUnit
5011 MoveText (
5012     _DtCanvasStruct     *canvas,
5013     LayoutInfo          *layout,
5014     int                  idx,
5015     _DtCvUnit            top_y,
5016     _DtCvUnit            bot_y,
5017     _DtCvUnit            needed)
5018 {
5019     _DtCvUnit    space;
5020
5021     /*
5022      * find out what's in front of it. And how much 'extra' room
5023      * there is.
5024      */
5025     space = CheckSpacing(canvas, layout, NULL, idx, -1,
5026                                 top_y, bot_y,
5027                                 canvas->txt_lst[idx].text_x,
5028                                 needed);
5029     /*
5030      * now move the group
5031      */
5032     MoveLeft(canvas, idx, idx, -1, -1, space);
5033
5034     return space;
5035 }
5036
5037 /*****************************************************************************
5038  * Function:    static _DtCvUnit MoveLines (_DtCanvasStruct canvas);
5039  *
5040  * Purpose: To move groupings (container, tables, etc.) as a group to
5041  *          honor boundaries.
5042  * 
5043  *****************************************************************************/
5044 static _DtCvUnit
5045 MoveLines (
5046     _DtCanvasStruct     *canvas,
5047     LayoutInfo          *layout,
5048     int                  idx,
5049     _DtCvUnit            top_y,
5050     _DtCvUnit            bot_y,
5051     _DtCvUnit            needed)
5052 {
5053     _DtCvUnit    space;
5054
5055     /*
5056      * find out what's in front of it. And how much 'extra' room
5057      * there is.
5058      */
5059     space = CheckSpacing(canvas, layout, NULL, -1, idx,
5060                                 top_y, bot_y,
5061                                 canvas->line_lst[idx].pos_x,
5062                                 needed);
5063
5064     /*
5065      * now move the group
5066      */
5067     MoveLeft(canvas, -1, -1, idx, idx, space);
5068
5069     return space;
5070 }
5071
5072 /*****************************************************************************
5073  * Function:    static void CheckMoveInfo (_DtCanvasStruct canvas);
5074  *
5075  * Purpose:     To move each of the groupings, rules and text lines to
5076  *              honor boundaries.
5077  * 
5078  *****************************************************************************/
5079 static void
5080 CheckMoveInfo (
5081     _DtCanvasStruct     *canvas,
5082     LayoutInfo          *layout)
5083 {
5084     int          i;
5085     _DtCvUnit    topY;
5086     _DtCvUnit    botY;
5087     _DtCvUnit    maxWidth = canvas->metrics.width;
5088     GrpInfo     *nxtGrp;
5089
5090     /*
5091      * fill in the max x of each group
5092      */
5093     for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
5094       {
5095         /*
5096          * find the maximum of the group
5097          */
5098         MaxOfGroup(nxtGrp, canvas->txt_lst, canvas->line_lst,
5099                                 layout->info.max_x_pos, layout->info.y_pos);
5100       }
5101
5102     /*
5103      * now check each group for exceeding the boundary.
5104      */
5105     for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
5106       {
5107         /*
5108          * does this group exceed the boundary?
5109          */
5110         if (maxWidth < nxtGrp->max_x)
5111              (void) MoveGroup(canvas, layout, nxtGrp, nxtGrp->max_x - maxWidth);
5112       }
5113
5114     /*
5115      * look at each of the text lines;
5116      */
5117     for (i = 0; i < canvas->txt_cnt; i++)
5118       {
5119         /*
5120          * Only look at those lines not already processed.
5121          */
5122         if (_DtCvIsNotProcessed(canvas->txt_lst[i]) &&
5123                                         maxWidth < canvas->txt_lst[i].max_x)
5124           {
5125             topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
5126             botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
5127             (void) MoveText(canvas, layout, i, topY, botY,
5128                                         canvas->txt_lst[i].max_x - maxWidth);
5129           }
5130       }
5131
5132     /*
5133      * look at each of the rules/lines;
5134      */
5135     for (i = 0; i < canvas->line_cnt; i++)
5136       {
5137         /*
5138          * Only look at those lines not already processed.
5139          */
5140         if (_DtCvIsNotProcessed(canvas->line_lst[i]) &&
5141                                         maxWidth < canvas->line_lst[i].max_x)
5142           {
5143             /*
5144              * calculate the top and bottom of the line
5145              */
5146             topY = canvas->line_lst[i].pos_y;
5147             botY = canvas->line_lst[i].max_y;
5148
5149             (void) MoveLines(canvas, layout, i, topY, botY,
5150                                         canvas->line_lst[i].max_x - maxWidth);
5151           }
5152       }
5153 }
5154
5155 /*****************************************************************************
5156  * Function:    static void CompareUnits ()
5157  *
5158  * Parameters:
5159  *
5160  * Returns:
5161  *
5162  * Purpose:
5163  * 
5164  *****************************************************************************/
5165 static int
5166 CompareUnits (
5167     const void  *a,
5168     const void  *b)
5169 {
5170     _DtCvUnit *aPtr = (_DtCvUnit *) a;
5171     _DtCvUnit *bPtr = (_DtCvUnit *) b;
5172
5173     if (*aPtr <  *bPtr) return -1;
5174     if (*aPtr == *bPtr) return 0;
5175
5176     return 1;
5177 }
5178
5179 /*****************************************************************************
5180  * Function:    static void CompareSearchs ()
5181  *
5182  * Parameters:
5183  *
5184  * Returns:
5185  *
5186  * Purpose:
5187  * 
5188  *****************************************************************************/
5189 static int
5190 CompareSearchs (
5191     const void  *a,
5192     const void  *b)
5193 {
5194     _DtCvSearchData *searchA = (_DtCvSearchData *) a;
5195     _DtCvSearchData *searchB = (_DtCvSearchData *) b;
5196     _DtCvDspLine    *lineA   = &(searchA->lst[searchA->idx]);
5197     _DtCvDspLine    *lineB   = &(searchB->lst[searchB->idx]);
5198     _DtCvUnit        topA    = lineA->baseline - lineA->ascent;
5199     _DtCvUnit        topB    = lineB->baseline - lineB->ascent;
5200     _DtCvUnit        heightA = lineA->ascent   + lineA->descent;
5201     _DtCvUnit        heightB = lineB->ascent   + lineB->descent;
5202     _DtCvUnit        centA   =  topA + (heightA >> 1);
5203     _DtCvUnit        centB   =  topB + (heightB >> 1);
5204
5205     if (lineA->baseline + lineA->descent < centB && centA < topB)
5206         return -1;
5207
5208     if (lineB->baseline + lineB->descent < centA && centB < topA)
5209         return 1;
5210
5211     if (lineA->text_x != lineB->text_x)
5212         return ((lineA->text_x < lineB->text_x) ? -1 : 1);
5213
5214     if (topA != topB)
5215         return ((topA < topB) ? -1 : 1);
5216
5217     if (heightA != heightB)
5218         return ((heightA < heightB) ? -1 : 1);
5219
5220     if (lineA->max_x != lineB->max_x)
5221         return ((lineA->max_x < lineB->max_x) ? -1 : 1);
5222
5223     return 0;
5224 }
5225
5226 /*****************************************************************************
5227  * Function:    static Status LayoutCanvasInfo (_DtCvHandle canvas);
5228  *
5229  * Parameters:
5230  *
5231  * Returns:
5232  *
5233  * Purpose:
5234  * 
5235  *****************************************************************************/
5236 static _DtCvStatus
5237 LayoutCanvasInfo (
5238     _DtCanvasStruct     *canvas,
5239     LayoutInfo          *layout,
5240     _DtCvUnit            divisor,
5241     char                *target_id)
5242 {
5243     int                  i = 0;
5244     DataPoint            basePt;
5245     _DtCvUnit            maxWidth = 0;
5246     _DtCvUnit            maxXPos  = 0;
5247     _DtCvStatus          result   = _DtCvSTATUS_OK;
5248
5249     *layout           = DefInfo;
5250     layout->divisor   = divisor;
5251     layout->max_width = canvas->metrics.width;
5252     layout->left      = canvas->metrics.side_margin;
5253     layout->right     = canvas->metrics.side_margin;
5254     layout->target_id = target_id;
5255
5256     _DtCvInitLayoutInfo(canvas, &(layout->info));
5257
5258     basePt = DefDataPt;
5259     PushDataPoint(layout, &basePt);
5260     SetMargins (layout);
5261     SetTextPosition (layout, True);
5262
5263     ProcessSegmentList(canvas, layout, canvas->element_lst, -1,
5264                                                 &maxWidth, &maxXPos, NULL);
5265
5266     RemoveDataPoint(layout, &basePt);
5267
5268     /*
5269      * fill in the max_x of each line of text/regions.
5270      */
5271     for (i = 0; i < canvas->txt_cnt; i++)
5272         canvas->txt_lst[i].max_x = MaxXOfLine(canvas, &(canvas->txt_lst[i]));
5273
5274     /*
5275      * calculate the actual right hand side boundary.
5276      */
5277     layout->info.max_x_pos += canvas->metrics.side_margin;
5278
5279     /*
5280      * the max_x_pos so far has indicated where the *next* character,
5281      * line or region will be *started*. Therefore back up one to
5282      * indicate the true last position used.
5283      */
5284     layout->info.max_x_pos--;
5285
5286     return result;
5287
5288 }  /* End LayoutCanvasInfo */
5289
5290 /*****************************************************************************
5291  * Function:    static Status LayoutCanvas (_DtCvHandle canvas);
5292  *
5293  * Parameters:
5294  *
5295  * Returns:
5296  *
5297  * Purpose:
5298  * 
5299  *****************************************************************************/
5300 static _DtCvStatus
5301 LayoutCanvas (
5302     _DtCanvasStruct     *canvas,
5303     LayoutInfo          *layout,
5304     char                *target_id)
5305 {
5306     _DtCvUnit            divisor = 1;
5307     _DtCvValue           redo;
5308     _DtCvStatus          result;
5309
5310     int i, search_cnt = canvas->search_cnt;
5311     
5312     do {
5313         redo = False;
5314         result = LayoutCanvasInfo(canvas, layout, divisor, target_id);
5315
5316         /*
5317          * Are we suppose to honor the boundary?
5318          * If so, do any lines go over the boundary?
5319          * Is there any margins that can be decremented?
5320          */
5321         if (_DtCvSTATUS_OK == result
5322                 && (_DtCvUSE_BOUNDARY == canvas->constraint ||
5323                         _DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
5324                 && layout->info.max_x_pos >= canvas->metrics.width)
5325           {
5326             if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
5327               {
5328                 int i;
5329
5330                 /*
5331                  * clear the processed flag from all the text/region lines.
5332                  */
5333                 for (i = 0; i < canvas->txt_cnt; i++)
5334                    _DtCvClearProcessed(canvas->txt_lst[i]);
5335
5336                 /*
5337                  * clear the processed flag from all the line/rules.
5338                  */
5339                 for (i = 0; i < canvas->line_cnt; i++)
5340                    _DtCvClearProcessed(canvas->line_lst[i]);
5341
5342                 CheckMoveInfo(canvas, layout);
5343
5344                 /*
5345                  * recalculate the new max x
5346                  */
5347                 layout->info.max_x_pos = 0;
5348                 for (i = 0; i < canvas->txt_cnt; i++)
5349                     if (layout->info.max_x_pos < canvas->txt_lst[i].max_x)
5350                         layout->info.max_x_pos = canvas->txt_lst[i].max_x;
5351
5352                 for (i = 0; i < canvas->line_cnt; i++)
5353                     if (layout->info.max_x_pos < canvas->line_lst[i].max_x)
5354                         layout->info.max_x_pos = canvas->line_lst[i].max_x;
5355
5356                 layout->info.max_x_pos--;
5357               }
5358             else if (True == layout->margin_non_zero)
5359               {
5360                 redo = True;
5361                 divisor *= 2;
5362                 canvas->txt_cnt  = 0;
5363                 canvas->line_cnt = 0;
5364                 canvas->trav_cnt = 0;
5365               }
5366           }
5367
5368       } while (True == redo);
5369
5370     /*
5371      * clean up table information
5372      */
5373     if (NULL != layout->grp_lst)
5374         free(layout->grp_lst);
5375
5376     /*
5377      * subtract one from the y position to indicate the *last*
5378      * pixel/column/etc that will be rendered.
5379      */
5380     canvas->max_y = layout->info.y_pos - 1;
5381     canvas->max_x = layout->info.max_x_pos;
5382
5383     for (i = search_cnt; i < canvas->search_cnt; i++)
5384       {
5385         canvas->searchs[i - search_cnt]     = canvas->searchs[i];
5386         canvas->searchs[i - search_cnt].lst = canvas->txt_lst;
5387       }
5388
5389     canvas->search_cnt -= search_cnt;
5390
5391     /*
5392      * are there any search hits?
5393      */
5394     if (0 != canvas->search_cnt)
5395         qsort (canvas->searchs, canvas->search_cnt, sizeof(_DtCvSearchData),
5396                                                         CompareSearchs);
5397     /*
5398      * sort the page break list.
5399      */
5400     if (0 != canvas->brk_cnt)
5401         qsort (canvas->pg_breaks, canvas->brk_cnt, sizeof(_DtCvUnit),
5402                                                                 CompareUnits);
5403
5404     return result;
5405
5406 }  /* End LayoutCanvas */
5407
5408 /*****************************************************************************
5409  * Function:    static void SortTraversal (_DtCvHandle canvas);
5410  *
5411  * Parameters:
5412  *
5413  * Returns:
5414  *
5415  * Purpose:
5416  * 
5417  *****************************************************************************/
5418 static void
5419 SortTraversal (_DtCanvasStruct *canvas)
5420 {
5421     int i;
5422
5423     /*
5424      * sort the links correctly. First, establish the x,y,width,height
5425      * of each link.
5426      */
5427     for (i = 0; i < canvas->trav_cnt; i++)
5428       {
5429         if (_DtCvTraversalLink == canvas->trav_lst[i].type)
5430             GetLinkInfo(canvas, i, &(canvas->trav_lst[i].x_pos),
5431                                         &(canvas->trav_lst[i].y_pos),
5432                                         &(canvas->trav_lst[i].width),
5433                                         &(canvas->trav_lst[i].height));
5434         else
5435             _DtCvCalcMarkPos(canvas, canvas->trav_lst[i].idx,
5436                                         &(canvas->trav_lst[i].x_pos),
5437                                         &(canvas->trav_lst[i].y_pos),
5438                                         &(canvas->trav_lst[i].width),
5439                                         &(canvas->trav_lst[i].height));
5440       }
5441
5442     _DtCvSortTraversalList(canvas, _DtCvFALSE);
5443 }
5444
5445 /*****************************************************************************
5446  * Function:    static void ProcessMarks (_DtCanvasStruct *canvas);
5447  *
5448  * Parameters:
5449  *
5450  * Returns:
5451  *
5452  * Purpose:
5453  * 
5454  *****************************************************************************/
5455 static _DtCvStatus
5456 ProcessMarks (
5457     _DtCanvasStruct      *canvas,
5458     _DtCvPointInfo      **mark_lst)
5459 {
5460     int                 markIdx;
5461     int                 result = _DtCvSTATUS_OK;
5462     _DtCvSelectData     beg;
5463     _DtCvSelectData     end;
5464     _DtCvSegmentI       *firstSeg;
5465
5466     while (NULL != mark_lst && NULL != *mark_lst)
5467       {
5468         /*
5469          * convert the segments to begin and end points
5470          */
5471         if (_DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, (*mark_lst)->segs,
5472                                         &beg, &end, NULL, NULL, &firstSeg))
5473             /*
5474              * just set a return value since this indicates bad data
5475              * and not system failure.
5476              */
5477             result = _DtCvSTATUS_BAD;
5478
5479         /*
5480          * now add it to the mark list
5481          */
5482         else
5483           {
5484             markIdx =  _DtCvAddToMarkList(canvas, (*mark_lst)->client_data,
5485                                                 _DtCvFALSE, &beg, &end);
5486             /*
5487              * now put the mark in the traversal list, but don't sort
5488              * or fill out position and dimension information.
5489              * SortTraversal() will do that.
5490              *
5491              * bail here if system failure indicated.
5492              */
5493             if (-1 == markIdx || 0 != _DtCvSetTravEntryInfo(canvas,
5494                                                 _DtCvGetNextTravEntry(canvas),
5495                                                 _DtCvTraversalMark, firstSeg,
5496                                                 markIdx, _DtCvTRUE))
5497                 return _DtCvSTATUS_BAD;
5498           }
5499
5500         mark_lst++;
5501       }
5502
5503     return result;
5504 }
5505
5506 /*****************************************************************************
5507  *              Public Functions
5508  *****************************************************************************/
5509 /*****************************************************************************
5510  * Function:    void _DtCanvasResize (_DtCvHandle canvas);
5511  *
5512  * Parameters:
5513  *
5514  * Returns:
5515  *
5516  * Purpose:
5517  * 
5518  *****************************************************************************/
5519 _DtCvStatus
5520 _DtCanvasResize (
5521     _DtCvHandle          canvas_handle,
5522     _DtCvValue           force,
5523     _DtCvUnit           *ret_width,
5524     _DtCvUnit           *ret_height )
5525 {
5526     int                  i;
5527     _DtCvStatus          selectStatus;
5528     _DtCvStatus          retStatus = _DtCvSTATUS_NONE;
5529     _DtCanvasStruct     *canvas    = (_DtCanvasStruct *) canvas_handle;
5530     _DtCvUnit            oldWidth  = canvas->metrics.width;
5531     LayoutInfo           layOut;
5532     _DtCvPointInfo       selPt;
5533     _DtCvPointInfo      **markInfo;
5534
5535     selPt.client_data = NULL;
5536     selPt.segs        = NULL;
5537
5538     /*
5539      * check to see if the width has changed - if not,
5540      * don't do anything (but re-initialize the metrics
5541      * to get the new height).
5542      */
5543     (*(canvas->virt_functions.get_metrics))(canvas->client_data,
5544                                 _DtCvCANVAS_TYPE, &(canvas->metrics));
5545
5546     if (canvas->metrics.width != oldWidth || _DtCvTRUE == force)
5547       {
5548         /*
5549          * remember the current selection.
5550          */
5551         selectStatus = _DtCanvasGetSelectionPoints(canvas, &(selPt.segs),
5552                                                                 NULL, NULL);
5553         /*
5554          * remember the marks
5555          */
5556         if (_DtCvSTATUS_BAD == _DtCvGetMarkSegs(canvas, &markInfo))
5557             return _DtCvSTATUS_BAD;
5558
5559         /*
5560          * Re-Layout the information.
5561          * First step - invalidate some counters.
5562          */
5563         canvas->trav_cnt = 0;   /* zero this only because we re-process */
5564                                 /* do not zero cur_hyper or we'll loose */
5565                                 /* where we are in the TOC              */
5566         canvas->txt_cnt  = 0;
5567         canvas->line_cnt = 0;
5568         canvas->mark_cnt = 0;
5569         canvas->brk_cnt  = 0;
5570
5571         /*
5572          * Layout the information if there is anything to do
5573          */
5574         if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, NULL))
5575             return _DtCvSTATUS_BAD;
5576     
5577         /*
5578          * restore the current selection.
5579          */
5580         if (_DtCvSTATUS_OK == selectStatus)
5581           {
5582             _DtCanvasActivatePts(canvas,_DtCvACTIVATE_SELECTION, &selPt,
5583                                                                 NULL,NULL);
5584             _DtCvFreeArray((void **) selPt.segs);
5585           }
5586
5587         /*
5588          * now place the marks in the mark and traversal lists
5589          */
5590         ProcessMarks(canvas, markInfo);
5591         if (NULL != markInfo)
5592           {
5593             for (i = 0; NULL != markInfo[i]; i++)
5594                 _DtCvFreeArray((void **) (markInfo[i]->segs));
5595             _DtCvFreeArray((void **) markInfo);
5596           }
5597
5598         /*
5599          * sort the traversal list.
5600          */
5601         SortTraversal(canvas);
5602         retStatus = _DtCvSTATUS_OK;
5603       }
5604
5605     /*
5606      * return the maximum height and width used
5607      */
5608     if (ret_width != NULL)
5609         *ret_width  = canvas->max_x;
5610     if (ret_height != NULL)
5611         *ret_height = canvas->max_y;
5612
5613     return retStatus;
5614
5615 }  /* End _DtCanvasResize */
5616
5617 /*****************************************************************************
5618  * Function:    void _DtCanvasSetTopic (_DtCvHandle canvas);
5619  *
5620  * Parameters:
5621  *
5622  * Returns:
5623  *
5624  * Purpose:
5625  * 
5626  *****************************************************************************/
5627 _DtCvStatus
5628 _DtCanvasSetTopic (
5629     _DtCvHandle          canvas_handle,
5630     _DtCvTopicPtr        topic,
5631     _DtCvValue           honor_size,
5632     _DtCvUnit           *ret_width,
5633     _DtCvUnit           *ret_height,
5634     _DtCvUnit           *ret_y )
5635 {
5636     _DtCvStatus          result = _DtCvSTATUS_OK;
5637     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
5638     LayoutInfo          layOut;
5639
5640     /*
5641      * clean the canvas
5642      */
5643     _DtCanvasClean (canvas_handle);
5644
5645     /*
5646      * attach to the canvas
5647      */
5648     canvas->element_lst = topic->seg_list;
5649
5650     /*
5651      * Attach the link information
5652      */
5653     canvas->link_data = topic->link_data;
5654
5655     /*
5656      * init the internal use pointer in all containers to NULL
5657      */
5658     _DtCvClearInternalUse(canvas->element_lst, _DtCvFALSE);
5659
5660     /*
5661      * Layout the information if there is anything to do
5662      */
5663     canvas->constraint = honor_size;
5664     if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, topic->id_str))
5665         return _DtCvSTATUS_BAD;
5666     
5667     /*
5668      * add the marks to the mark and traversal lists
5669      */
5670     ProcessMarks(canvas, topic->mark_list);
5671
5672     /*
5673      * sort the traversal list.
5674      */
5675     SortTraversal(canvas);
5676
5677     /*
5678      * return the maximum height and width used
5679      * And the location of the id.
5680      */
5681     if (ret_width != NULL)
5682         *ret_width = canvas->max_x;
5683     if (ret_height != NULL)
5684         *ret_height = canvas->max_y;
5685     if (ret_y != NULL)
5686       {
5687         if (NULL != layOut.target_id && True != layOut.id_found)
5688             result = _DtCvSTATUS_ID_BAD;
5689         *ret_y = layOut.id_Ypos;
5690       }
5691
5692     return result;
5693
5694 }  /* End _DtCanvasSetTopic */