87028bb2c8a55ea2e393411220e226af89bd0886
[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 ||
3869                                         '\0' == layout->info.align_char)
3870                     layout->txt_justify = _DtCvJUSTIFY_LEFT;
3871               }
3872           }
3873
3874         /*
3875          * terminate the previous rendering list
3876          */
3877         if (NULL != layout->lst_rendered)
3878             layout->lst_rendered->next_disp = NULL;
3879         layout->lst_rendered = NULL;
3880
3881         /*
3882          * push the data point and reset margin/text info.
3883          */
3884         PushDataPoint(layout, &basePt);
3885         SetMargins(layout);
3886         SetTextPosition(layout, True);
3887       }
3888
3889     /*
3890      * determine the minimum Y that the child of this container should
3891      * occupy.  To do so, subtract off the bottom border pad and the
3892      * bottom margin.
3893      */
3894     if (0 < min_y)
3895       {
3896         myMinY = min_y - yPad;
3897         if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
3898           {
3899             _DtCvUnit bPad = 0;
3900
3901             _DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg), &bPad);
3902             myMinY -= bPad;
3903           }
3904       }
3905
3906     /*
3907      * format the segment
3908      */
3909     saveYpos = layout->info.y_pos;
3910
3911     GetCurrentDataPoint(layout, &curPt);
3912
3913     /*
3914      * reset the max x variable
3915      */
3916     layout->info.cur_max_x = 0;
3917     ProcessSegmentList(canvas, layout, _DtCvContainerListOfSeg(con_seg),
3918                                         myMinY,
3919                                         &maxWidth, &maxXPos, NULL);
3920     /*
3921      * if this container forces a wrap join of the next item,
3922      * save the current line, but don't add space or null the
3923      * last rendered item.
3924      */
3925     CheckSaveInfo(canvas, layout, con_seg, 0);
3926     if (maxWidth < layout->info.cur_max_x - curPt.left + layout->right)
3927         maxWidth = layout->info.cur_max_x - curPt.left + layout->right;
3928     if (maxXPos < layout->info.cur_max_x)
3929         maxXPos = layout->info.cur_max_x;
3930
3931     if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
3932       {
3933         /*
3934          * Save any information in the buffer,
3935          * reset the margins and add the appropriate lines,
3936          * and check for going over boundaries.
3937          */
3938         _DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg),
3939                                                         &(layout->info.y_pos));
3940
3941         /*
3942          * terminate the previous rendering list
3943          */
3944         if (NULL != layout->lst_rendered)
3945             layout->lst_rendered->next_disp = NULL;
3946         layout->lst_rendered = NULL;
3947       }
3948
3949     /*
3950      * remove this element's data points from the stack.
3951      */
3952     RemoveDataPoint(layout, &basePt);
3953
3954     /*
3955      * include the bottom border (if needed) in the ending y position
3956      */
3957     layout->info.y_pos += yPad;
3958
3959     /*
3960      * Set the ending counts for the lines and text in me.
3961      * This sets the ending counts for the lines contained in me,
3962      * NOT the lines in my border.
3963      */
3964     SetEndCounts(canvas, &(frmtInfo.cnt), 0);
3965
3966     /*
3967      * does this object need to be adjust within its height?
3968      */
3969     if (0 < min_y && layout->info.y_pos < min_y)
3970       {
3971         AdjustObjectPosition(canvas, layout, TxtVertJustify(con_seg),
3972                         frmtInfo.cnt.beg_txt, frmtInfo.cnt.beg_ln,
3973                         frmtInfo.cnt.beg_brk,
3974                         frmtInfo.cnt.end_txt, frmtInfo.cnt.end_ln,
3975                         frmtInfo.cnt.end_brk,
3976                         0, min_y - layout->info.y_pos - yPad, 0, 0, 0);
3977         layout->info.y_pos = min_y;
3978       }
3979
3980     /*
3981      * Now draw the borders
3982      * If borders are drawn, cur_max_x & max_x_pos may get changed
3983      * if a right side border is drawn.
3984      */
3985     if (maxWidth < layout->max_width - curPt.left - curPt.right)
3986         maxWidth = layout->max_width - curPt.left - curPt.right;
3987
3988     getLn = DrawBorders (canvas, layout, Border(con_seg),
3989                                 BrdData(con_seg), BrdWidth(con_seg),
3990                                 saveYpos, layout->info.y_pos - yPad,
3991                                 curPt.left,
3992                                 curPt.left + maxWidth);
3993
3994     /*
3995      * check to see if we need to save the container counts away
3996      * because we might need to move the entire container as one
3997      * to honor the boundary. This will occur if the flag to honor
3998      * a boundary is set to _DtCvUSE_BOUNDARY_MOVE, this container has
3999      * border lines, the container's parent is not a table nor
4000      * is the container within another container that has a border.
4001      */
4002     if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint
4003                         && True == layout->brdr_flag
4004                         && False == saveBrdr && False == layout->table_flag)
4005       {
4006         GrpInfo *info = (GrpInfo *) malloc (sizeof(GrpInfo));
4007
4008         /*
4009          * warning - nothing done if malloc error.
4010          */
4011         if (NULL != info)
4012           {
4013             /*
4014              * initialize to the end information of the container.
4015              */
4016             info->cnt = frmtInfo.cnt;
4017
4018             /*
4019              * take into account the borders for this container
4020              */
4021             SetEndCounts(canvas, &(info->cnt), getLn);
4022
4023             /*
4024              * set the linked list information
4025              */
4026             info->next_info = layout->grp_lst;
4027             layout->grp_lst = info;
4028           }
4029       }
4030
4031     /*
4032      * set the return values.
4033      */
4034     *ret_max_x = layout->info.cur_max_x;
4035     *ret_width = maxWidth;
4036     if (*ret_width < layout->max_width - curPt.left - curPt.right)
4037         *ret_width = layout->max_width - curPt.left - curPt.right;
4038
4039     /*
4040      * Restore the previous information
4041      */
4042     layout->left      = saveLeft;
4043     layout->right     = saveRight;
4044     layout->first     = saveFirst;
4045     layout->stat_flag = saveStatic;
4046     layout->brdr_flag = saveBrdr;
4047     layout->info.leading = saveLead;
4048
4049     /*
4050      * Besides checking for flow constraints, also (re)sets margins and
4051      * text information.
4052      */
4053     CheckFormat(layout, True);
4054     layout->txt_justify  = saveJustify;
4055     layout->info.align_char  = saveJustifyChar;
4056
4057     /*
4058      * for tables and such, return how many lines were drawn around this
4059      * container.
4060      */
4061     if (ret_cnt)
4062         *ret_cnt = getLn;
4063
4064     return;
4065 }
4066
4067 /******************************************************************************
4068  * Function: ProcessSegmentList
4069  *
4070  * Process the segment list, laying it out according to left, right,
4071  * and first margins specified. Returns the max_width of the all
4072  * segments processed and the maximum x coordinate used.
4073  *****************************************************************************/
4074 static void
4075 ProcessSegmentList(
4076     _DtCanvasStruct     *canvas,
4077     LayoutInfo          *layout,
4078     _DtCvSegmentI       *cur_seg,
4079     _DtCvUnit            min_y,
4080     _DtCvUnit           *ret_width,
4081     _DtCvUnit           *ret_max_x,
4082     int                 **ret_vert)
4083 {
4084     int          junk;
4085     int          saveTravCnt  = canvas->trav_cnt;
4086     int          saveTxtCnt   = canvas->txt_cnt;
4087     int          saveLineCnt  = canvas->line_cnt;
4088     int          saveBrkCnt   = canvas->brk_cnt;
4089     _DtCvUnit    tempX;
4090     _DtCvUnit    tempLen;
4091     _DtCvUnit    width;
4092     _DtCvUnit    nWidth       = 0;
4093     _DtCvUnit    leftMargin   = 0;
4094     _DtCvUnit    rightMargin  = 0;
4095     _DtCvUnit    topHeight    = 0;
4096     _DtCvUnit    botHeight    = 0;
4097     _DtCvUnit    maxWidth     = 0;
4098     _DtCvUnit    saveYpos     = layout->info.y_pos;
4099     _DtCvSegmentI       *segStart     = cur_seg;
4100     LayFrmtInfo         *headInfo     = NULL;
4101     LayFrmtInfo         *lastHead     = NULL;
4102     LayFrmtInfo         *nxtHead;
4103     _DtCvLayoutInfo      startInfo;
4104
4105     _DtCvValue   redo         = False;
4106     _DtCvValue   joinCleared  = False;
4107     _DtCvValue   flag;
4108
4109     TopDims      topBot;
4110     SideDims     sideDims;
4111     CornerDims   cornerDims;
4112     FlowDims     flowDims;
4113     DataPoint    basePt;
4114     DataPoint    leftPt;
4115     DataPoint    rightPt;
4116
4117     /*
4118      * clear the controller arrays
4119      */
4120     InitDimArrays(&topBot, &sideDims, &cornerDims, &flowDims);
4121
4122     /*
4123      * get the current left and right values or 'base'.
4124      */
4125     GetCurrentDataPoint(layout, &basePt);
4126
4127     /*
4128      * ???
4129      */
4130     leftPt  = basePt;
4131     rightPt = basePt;
4132     leftPt.y_pos  = _CEFORMAT_ALL;
4133     rightPt.y_pos = _CEFORMAT_ALL;
4134
4135     /*
4136      * process all the controller type containers in the segment list
4137      */
4138     while (NULL != cur_seg)
4139       {
4140         if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
4141           {
4142             /*
4143              * want to clear this once and only once. Then any join
4144              * directives will survive, though if two or more controllers
4145              * have the directive set, the 'last' one will win out.
4146              */
4147             if (False == joinCleared)
4148               {
4149                 _DtCvSetJoinInfo(&(layout->info), False, -1);
4150                 joinCleared = True;
4151               }
4152
4153             /*
4154              * process the 'controller'
4155              */
4156             nxtHead = ProcessController(canvas, layout, cur_seg);
4157
4158             /*
4159              * update the dimension arrays so that the controller
4160              * will get placed correctly.
4161              */
4162             UpdateDimensionArrays(cur_seg, nxtHead->width, nxtHead->height,
4163                                 &topBot, &sideDims, &cornerDims, &flowDims,
4164                                 &leftMargin, &rightMargin);
4165
4166             /*
4167              * remember this controller.
4168              */
4169             if (NULL == headInfo)
4170                 headInfo = nxtHead;
4171             else
4172                 lastHead->next_info = nxtHead;
4173             lastHead = nxtHead;
4174           }
4175
4176         /*
4177          * go to the next segment
4178          */
4179         cur_seg = cur_seg->next_seg;
4180       }
4181
4182     /*
4183      * Now reset the margins based on the controllers found
4184      */
4185     if (NULL != headInfo)
4186       {
4187         DetermineMaxDims(&topBot, &cornerDims, leftMargin, rightMargin,
4188                             &topHeight, &botHeight, &maxWidth);
4189         layout->info.y_pos += topHeight;
4190         layout->left       += leftMargin;
4191         layout->right      += rightMargin;
4192         DetermineFlowConstraints(layout, flowDims,
4193                             basePt.left, basePt.right,
4194                             layout->info.y_pos, &leftPt, &rightPt);
4195
4196         /*
4197          * get rid of the leftMargin and rightMargin values in maxWidth
4198          * otherwise the use of layout->left & layout->right will double
4199          * the value.
4200          */
4201         maxWidth = maxWidth - leftMargin - rightMargin;
4202         if (layout->max_width < maxWidth + basePt.left + basePt.right +
4203                             layout->left + layout->right)
4204             layout->max_width = maxWidth + basePt.left + basePt.right +
4205                                             layout->left + layout->right;
4206
4207         SetMargins(layout);
4208         SetTextPosition(layout, True);
4209         if (JoinSet(layout))
4210           {
4211             int  cnt;
4212             int  joinLine = layout->info.join_line;
4213             int  start    = canvas->txt_lst[joinLine].byte_index;
4214             int  count    = canvas->txt_lst[joinLine].length;
4215             _DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
4216             _DtCvUnit     tmpWidth;
4217
4218             /*
4219              * change the starting location of the following text.
4220              * take into account the left margin that *hasn't*
4221              * been added to the controlling container.
4222              */
4223             layout->info.text_x_pos  = canvas->txt_lst[joinLine].text_x
4224                                                         + layout->lmargin;
4225             layout->info.cur_len = 0;
4226
4227             /*
4228              * now calculate the width of this line.
4229              */
4230             while (pSeg != NULL && count > 0)
4231               {
4232                 _DtCvGetWidthOfSegment(canvas,pSeg,start,count,
4233                                                     &cnt, &tmpWidth, NULL);
4234                 layout->info.text_x_pos += tmpWidth;
4235                 count -= cnt;
4236                 start  = 0;
4237                 pSeg   = pSeg->next_disp;
4238               }
4239           }
4240       }
4241
4242     /*
4243      * now format for non-controller containers and non-containers.
4244      * re-start at the beginning.
4245      */
4246     cur_seg   = segStart;
4247
4248     /*
4249      * Save some information incase we have to redo the layout. I.e.
4250      * we overflow the sizing.
4251      */
4252     startInfo = layout->info;
4253     saveTravCnt = canvas->trav_cnt;
4254     saveTxtCnt   = canvas->txt_cnt;
4255     saveLineCnt  = canvas->line_cnt;
4256     saveBrkCnt   = canvas->brk_cnt;
4257
4258     while (NULL != cur_seg)
4259       {
4260         width = layout->max_width - layout->info.text_x_pos
4261                                 - layout->rmargin - layout->info.cur_len;
4262
4263         /*
4264          * check to see if this item should start a line.
4265          */
4266         CheckSetLineStart(layout, cur_seg);
4267
4268         /*
4269          * check to see if this item will cause a page break.
4270          */
4271         CheckForPageBreak(canvas, cur_seg, layout->info.y_pos);
4272
4273         switch (_DtCvPrimaryTypeOfSeg(cur_seg))
4274           {
4275             case _DtCvCONTAINER:
4276                     if (!(_DtCvIsSegController(cur_seg)))
4277                         ProcessContainer(canvas, layout, cur_seg, min_y,
4278                                                 &junk, &junk, &junk);
4279                     break;
4280
4281             case _DtCvREGION:
4282                     /*
4283                      * flag that this segment needs a line number
4284                      */
4285                     cur_seg->internal_use = (void *) -1;
4286
4287                     /*
4288                      * process the segment
4289                      */
4290                     if (_DtCvIsSegInLine(cur_seg))
4291                       {
4292                         /*
4293                          * if a hypertext link, this will add it to
4294                          * the internal list.
4295                          */
4296                         CheckAddToHyperList(canvas, cur_seg);
4297
4298                         /*
4299                          * get the traversal width
4300                          */
4301                         nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
4302                                                     layout->info.lst_hyper);
4303
4304                         /*
4305                          * check to see if this region can end a line
4306                          */
4307                         flag = _DtCvCheckLineSyntax(canvas,cur_seg,0,0,False);
4308
4309                         /*
4310                          * if this can't end a line, get the length up to
4311                          * the next segment that can and base whether to
4312                          * save pased on that.
4313                          */
4314                         tempLen = 0;
4315                         if (False == flag)
4316                           {
4317                             tempLen = _DtCvGetNextWidth(canvas,
4318                                                 _DtCvSTRING,
4319                                                 layout->info.lst_hyper,
4320                                                 cur_seg->next_seg,
4321                                                 0, cur_seg, NULL, NULL, NULL);
4322                             /*
4323                              * if the next width is zero, reset the flag.
4324                              */
4325                             if (tempLen <= 0)
4326                                 flag = True;
4327                           }
4328                         tempLen += nWidth;
4329
4330                         /*
4331                          * if not joining, but my length goes over the
4332                          * working width, save out the current buffered
4333                          * information
4334                          */
4335                         if (NotJoining(layout) &&
4336                             _DtCvWidthOfRegionSeg(cur_seg) + tempLen > width)
4337                             CheckSaveInfo (canvas, layout, cur_seg, 0);
4338
4339                         /*
4340                          * up counts on the buffered information.
4341                          */
4342                         layout->info.line_bytes += 1;
4343                         layout->info.cur_len    += 
4344                                 (_DtCvWidthOfRegionSeg(cur_seg) + nWidth);
4345
4346                         /*
4347                          * does the next segment need to join with
4348                          * this one? If so, set the information
4349                          */
4350                         _DtCvSetJoinInfo(&(layout->info), (flag ? 0 : 1), -1);
4351                         if (_DtCvIsSegNewLine(cur_seg))
4352                             SaveInfo(canvas, layout, cur_seg, 0);
4353                       }
4354                     else
4355                       {
4356                         /*
4357                          * clear out the join information
4358                          * standalone figures can't join with others.
4359                          */
4360                         _DtCvSetJoinInfo(&(layout->info), False, -1);
4361
4362                         /*
4363                          * figures are standalone. Save any
4364                          * information in the buffer away.
4365                          */
4366                         CheckSaveInfo (canvas, layout, cur_seg, 0);
4367
4368                         /*
4369                          * check to see if this segment is
4370                          * a hypertext. If so, add it to the
4371                          * list if it hasn't been added yet.
4372                          */
4373                         CheckAddToHyperList(canvas, cur_seg);
4374
4375                         /*
4376                          * get the traversal width, if any.
4377                          */
4378                         nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
4379                                                     layout->info.lst_hyper);
4380
4381                         /*
4382                          * now save the standalone figure
4383                          */
4384                         layout->info.line_bytes += 1;
4385                         layout->info.cur_len    += 
4386                                 _DtCvWidthOfRegionSeg(cur_seg) + nWidth;
4387                         SaveInfo(canvas, layout, cur_seg->next_seg, 0);
4388
4389                         /*
4390                          * check for wrapping overflow
4391                          */
4392                         CheckFormat(layout, False);
4393                       }
4394
4395                     /*
4396                      * indicate this segment as the last item rendered
4397                      */
4398                     if (NULL != layout->lst_rendered)
4399                         layout->lst_rendered->next_disp = cur_seg;
4400                     layout->lst_rendered = cur_seg;
4401                     break;
4402
4403             case _DtCvLINE:
4404                     /*
4405                      * lines are standalone. Save any
4406                      * information in the buffer away.
4407                      */
4408                     CheckSaveInfo (canvas, layout, cur_seg, 0);
4409
4410                     /*
4411                      * if the line_width is zero, make it 1 so
4412                      * that it really does take some space.
4413                      */
4414                     nWidth = _DtCvWidthOfLineSeg(cur_seg);
4415                     if (0 == nWidth)
4416                         nWidth = 1;
4417
4418                     /*
4419                      * start with it going all the way across the window.
4420                      */
4421                     width = layout->max_width;
4422                     tempX = 0;
4423
4424                     /*
4425                      * or does it only extend across the container?
4426                      */
4427                     if (_DtCvIsSegBlockLine(cur_seg))
4428                       {
4429                         tempX = layout->lmargin;
4430                         width = layout->max_width - tempX - layout->rmargin;
4431                       }
4432
4433                     SaveLine (canvas, layout, _DtCvLINE_HORZ,
4434                                 _DtCvDataOfLineSeg(cur_seg), nWidth, tempX,
4435                                 layout->info.y_pos, width);
4436
4437                     layout->info.y_pos += nWidth;
4438                     break;
4439
4440             case _DtCvMARKER:
4441                     /*
4442                      * check to see if marker is the target id
4443                      */
4444                     CheckId(layout, _DtCvIdOfMarkerSeg(cur_seg));
4445                     break;
4446
4447             case _DtCvNOOP:
4448                     if (_DtCvIsSegNewLine(cur_seg))
4449                         SaveInfo(canvas, layout, cur_seg, 0);
4450                     break;
4451
4452             case _DtCvSTRING:
4453                     /*
4454                      * flag that this segment needs a line number
4455                      */
4456                     cur_seg->internal_use = (void *) -1;
4457
4458                     /*
4459                      * process the string
4460                      */
4461                     ProcessStringSegment(canvas, layout, cur_seg);
4462
4463                     /*
4464                      * check for wrapping overflow.
4465                      */
4466                     if (_DtCvIsSegNewLine(cur_seg))
4467                         CheckFormat(layout, False);
4468
4469                     /*
4470                      * indicate this segment as the last item rendered
4471                      */
4472                     if (NULL != layout->lst_rendered)
4473                         layout->lst_rendered->next_disp = cur_seg;
4474                     layout->lst_rendered = cur_seg;
4475                     break;
4476
4477             case _DtCvTABLE:
4478                     ProcessTable(canvas, layout, cur_seg, min_y);
4479             default:
4480                     break;
4481           }
4482
4483         /*
4484          * get the next segment
4485          */
4486         cur_seg = cur_seg->next_seg;
4487
4488         /*
4489          * check the flowing text points
4490          */
4491         if (leftPt.y_pos > 0 &&
4492                 leftPt.x_units > layout->max_width - leftPt.left - leftPt.right)
4493           {
4494             layout->max_width = leftPt.x_units + leftPt.left + leftPt.right;
4495             redo = True;
4496           }
4497         if (rightPt.y_pos > 0 &&
4498                 rightPt.x_units > layout->max_width-rightPt.left-rightPt.right)
4499           {
4500             layout->max_width = rightPt.x_units + rightPt.left + rightPt.right;
4501             redo = True;
4502           }
4503
4504         /*
4505          * have we violated the available space?
4506          * if so, we'll have to reformat.
4507          */
4508         if (redo == True)
4509           {
4510             redo             = False;
4511             cur_seg          = segStart;
4512             canvas->trav_cnt = saveTravCnt;
4513             canvas->txt_cnt  = saveTxtCnt;
4514             canvas->line_cnt = saveLineCnt;
4515             canvas->brk_cnt  = saveBrkCnt;
4516             layout->info     = startInfo;
4517
4518             if (rightPt.y_pos > 0)
4519               {
4520                 RemoveDataPoint(layout, &rightPt); /* make sure its gone */
4521                 InsertDataPoint(layout, &rightPt);
4522               }
4523             if (leftPt.y_pos > 0)
4524               {
4525                 RemoveDataPoint(layout, &leftPt); /* make sure its gone */
4526                 InsertDataPoint(layout, &leftPt);
4527               }
4528
4529             /*
4530              * Now reset the margins based on the controllers found
4531              */
4532             if (NULL != headInfo)
4533               {
4534                 layout->left   += leftMargin;
4535                 layout->right  += rightMargin;
4536                 SetMargins(layout);
4537                 SetTextPosition(layout, True);
4538                 if (JoinSet(layout))
4539                   {
4540                     int  cnt;
4541                     int  joinLine = layout->info.join_line;
4542                     int  start    = canvas->txt_lst[joinLine].byte_index;
4543                     int  count    = canvas->txt_lst[joinLine].length;
4544                     _DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
4545                     _DtCvUnit     tmpWidth;
4546         
4547                     /*
4548                      * change the starting location of the following text.
4549                      * take into account the left margin that *hasn't*
4550                      * been added to the controlling container.
4551                      */
4552                     layout->info.text_x_pos  = canvas->txt_lst[joinLine].text_x
4553                                                         + layout->lmargin;
4554                     layout->info.cur_len = 0;
4555         
4556                     /*
4557                      * now calculate the width of this line.
4558                      */
4559                     while (pSeg != NULL && count > 0)
4560                       {
4561                         _DtCvGetWidthOfSegment(canvas,pSeg,start,count,
4562                                                         &cnt, &tmpWidth, NULL);
4563                         layout->info.text_x_pos += tmpWidth;
4564                         count -= cnt;
4565                         start  = 0;
4566                         pSeg   = pSeg->next_disp;
4567                       }
4568                   }
4569               }
4570           }
4571       }
4572
4573     RemoveDataPoint(layout, &leftPt);
4574     RemoveDataPoint(layout, &rightPt);
4575
4576     /*
4577      * if there were heads, now place them correctly.
4578      */
4579     if (NULL != headInfo)
4580       {
4581         _DtCvUnit       blockHeight;
4582         _DtCvUnit       blockWidth;
4583
4584         /*
4585          * make sure all of the information in the body is saved out
4586          */
4587         CheckSaveInfo (canvas, layout, NULL, 0);
4588
4589         /*
4590          * now calculate the non-controllers overall height.
4591          */
4592         blockHeight = layout->info.y_pos - saveYpos - topHeight;
4593
4594         /*
4595          * now figure the head positions.
4596          */
4597         DetermineHeadPositioning(&topBot, &sideDims, &cornerDims, &flowDims,
4598                                 saveYpos, topHeight,
4599                                 blockHeight, &blockHeight);
4600         /*
4601          * if the maximum available space was exceeded by the text
4602          * calculate a new max width
4603          */
4604         if (layout->max_width < layout->info.cur_max_x + layout->right)
4605             layout->max_width = layout->info.cur_max_x + layout->right;
4606
4607         blockWidth = layout->max_width - basePt.left - basePt.right
4608                                                 - layout->left - layout->right;
4609
4610         nxtHead = headInfo;
4611         cur_seg = segStart;
4612         while (cur_seg != NULL)
4613           {
4614             if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
4615               {
4616                 AdjustHeadPosition(canvas, layout, cur_seg,
4617                         &topBot, &sideDims, &cornerDims, &flowDims, nxtHead,
4618                         0, basePt.left + layout->left - leftMargin, blockWidth,
4619                         leftMargin, rightMargin);
4620                 /*
4621                  * go to the next head element
4622                  */
4623                 nxtHead = nxtHead->next_info;
4624
4625                 /*
4626                  * free the information.
4627                  */
4628                 free(headInfo);
4629                 headInfo = nxtHead;
4630               }
4631
4632             /*
4633              * got to the next segment
4634              */
4635             cur_seg = cur_seg->next_seg;
4636           }
4637
4638         if (layout->info.y_pos < saveYpos + topHeight + blockHeight)
4639             layout->info.y_pos = saveYpos + topHeight + blockHeight;
4640
4641         layout->info.y_pos += botHeight;
4642       }
4643
4644     /*
4645      * set the return values
4646      */
4647     *ret_width = layout->info.cur_max_x - basePt.left + layout->right;
4648     *ret_max_x = layout->info.cur_max_x;
4649
4650     return;
4651 }
4652
4653 /*****************************************************************************
4654  * Function:    static _DtCvUnit MaxOfGroup (
4655  *
4656  * Purpose: Determine the maximum of a group.
4657  *****************************************************************************/
4658 static void
4659 MaxOfGroup (
4660     GrpInfo             *group,
4661     _DtCvDspLine        *text,
4662     _DtCvLineSeg        *lines,
4663     _DtCvUnit            max_x,
4664     _DtCvUnit            max_y)
4665 {
4666     int          i;
4667
4668     /*
4669      * initialize
4670      */
4671     group->min_x = max_x;
4672     group->max_x = 0;
4673     group->top_y = max_y;
4674     group->bot_y = 0;
4675
4676     /*
4677      * find the maximum of the group
4678      */
4679     for (i = group->cnt.beg_txt; i < group->cnt.end_txt; i++)
4680       {
4681         /*
4682          * check for min's and max's
4683          */
4684         if (group->min_x > text[i].text_x)
4685             group->min_x = text[i].text_x;
4686
4687         if (group->max_x < text[i].max_x)
4688             group->max_x = text[i].max_x;
4689
4690         if (group->top_y > text[i].baseline - text[i].ascent)
4691             group->top_y = text[i].baseline - text[i].ascent;
4692
4693         if (group->bot_y < text[i].baseline + text[i].descent)
4694             group->bot_y = text[i].baseline + text[i].descent;
4695
4696         /*
4697          * indicate that this line has been processed already
4698          */
4699         _DtCvSetProcessed(text[i]);
4700       }
4701
4702     for (i = group->cnt.beg_ln; i < group->cnt.end_ln; i++)
4703       {
4704         /*
4705          * check for min's and max's
4706          */
4707         if (group->min_x > lines[i].pos_x)
4708             group->min_x = lines[i].pos_x;
4709
4710         if (group->max_x < lines[i].max_x)
4711             group->max_x = lines[i].max_x;
4712
4713         if (group->top_y > lines[i].pos_y)
4714             group->top_y = lines[i].pos_y;
4715
4716         if (group->bot_y < lines[i].max_y)
4717             group->bot_y = lines[i].max_y;
4718
4719         /*
4720          * indicate that this line has been processed already
4721          */
4722         _DtCvSetProcessed(lines[i]);
4723       }
4724 }
4725
4726 /*****************************************************************************
4727  * Function:    static _DtCvUnit TestSpacing (
4728  *
4729  * Parameters:
4730  *
4731  * Returns:     True    if the object is before (x wise) the test object.
4732  *              False   if the object is not before (x wise) the text object.
4733  *
4734  * Purpose:
4735  * 
4736  *****************************************************************************/
4737 static _DtCvStatus
4738 TestSpacing (
4739     _DtCvUnit            tst_top,
4740     _DtCvUnit            tst_bot,
4741     _DtCvUnit            tst_min,
4742     _DtCvUnit            obj_top,
4743     _DtCvUnit            obj_bot,
4744     _DtCvUnit            obj_max,
4745     _DtCvUnit            needed,
4746     _DtCvUnit            min_space,
4747     _DtCvUnit           *ret_amount)
4748 {
4749     _DtCvStatus  result = False;
4750
4751     /*
4752      * check to see if the object is to the left of the test object
4753      * to move and that it 'infringes' on the vertical
4754      * space of the test object.
4755      *
4756      * I.e.     ----obj_top------
4757      *          |               |   ----tst_top----
4758      *          ----obj_bot------   |             |
4759      *                              ----tst_bot----
4760      *
4761      * I.e.                         ----tst_top----
4762      *          ----obj_top-------  |             |
4763      *          |                |  ----tst_bot----
4764      *          ----obj_bot-------
4765      *
4766      * I.e.     ----obj_top------
4767      *          |               |   ----tst_top----
4768      *          |               |   |             |
4769      *          |               |   ----tst_bot----
4770      *          ----obj_bot------
4771      *
4772      * I.e.                         ----tst_top----
4773      *          ----obj_top-------  |             |
4774      *          |                |  |             |
4775      *          ----obj_bot-------  |             |
4776      *                              ----tst_bot----
4777      */
4778     if (obj_max < tst_min
4779         && True == _DtCvCheckInfringement(tst_top, tst_bot, obj_top, obj_bot)
4780         && needed > tst_min - obj_max)
4781       {
4782         /*
4783          * okay, this infringes on the object's space.
4784          * truncate the amount of room there is to move the object
4785          */
4786         result = True;
4787         needed = tst_min - obj_max;
4788
4789         /*
4790          * is the space between these two objects already squeezed
4791          * below the minimum allowed?
4792          */
4793         if (needed < min_space)
4794             needed = 0;
4795         else /* leave the minimum space between the objects */
4796             needed -= min_space;
4797       }
4798
4799     *ret_amount = needed;
4800     return result;
4801 }
4802
4803 /*****************************************************************************
4804  * Function:    static void MoveLeft (
4805  *
4806  * Parameters:
4807  *
4808  * Returns:
4809  *
4810  * Purpose:     Moves the object's rules/lines and text lines to the left.
4811  * 
4812  *****************************************************************************/
4813 static void
4814 MoveLeft (
4815     _DtCanvasStruct     *canvas,
4816     int                  beg_txt,
4817     int                  end_txt,
4818     int                  beg_ln,
4819     int                  end_ln,
4820     _DtCvUnit            space)
4821 {
4822     int         i;
4823
4824     /*
4825      * bail now if nothing to do.
4826      */
4827     if (1 > space)
4828         return;
4829
4830     /*
4831      * move each text/region line.
4832      */
4833     for (i = beg_txt; i < end_txt; i++)
4834       {
4835         canvas->txt_lst[i].text_x -= space;
4836         canvas->txt_lst[i].max_x  -= space;
4837       }
4838
4839     /*
4840      * move each line/rule.
4841      */
4842     for (i = beg_ln; i < end_ln; i++)
4843       {
4844         canvas->line_lst[i].pos_x -= space;
4845         canvas->line_lst[i].max_x -= space;
4846       }
4847 }
4848
4849 /*****************************************************************************
4850  * Function:    static _DtCvUnit CheckSpacing (
4851  *
4852  * Purpose:     Check the spacing before an object and move any objects
4853  *              before it to the left to make room.
4854  *
4855  *****************************************************************************/
4856 static _DtCvUnit
4857 CheckSpacing (
4858     _DtCanvasStruct     *canvas,
4859     LayoutInfo          *layout,
4860     GrpInfo             *tst_grp,
4861     int                  txt_idx,
4862     int                  line_idx,
4863     _DtCvUnit            top_y,
4864     _DtCvUnit            bot_y,
4865     _DtCvUnit            min_x,
4866     _DtCvUnit            needed)
4867 {
4868     int          i;
4869     _DtCvUnit    space;
4870     _DtCvUnit    maxSpace;
4871     _DtCvUnit    topY;
4872     _DtCvUnit    botY;
4873     GrpInfo     *nxtGrp   = layout->grp_lst;
4874
4875     /*
4876      * truncate if the amount needed is more than available.
4877      */
4878     if (min_x < needed)
4879         needed = min_x;
4880
4881     maxSpace = needed;
4882
4883     /*
4884      * see what group is before this group and how much space there is
4885      */
4886     while (NULL != nxtGrp)
4887       {
4888         /*
4889          * as long as I'm not comparing against myself, try it.
4890          */
4891         if (nxtGrp != tst_grp)
4892           {
4893             /*
4894              * is this group before(x wise) the test group, infringing
4895              * upon the test group's top and bottom positioning (y)
4896              * and is the amount of space (x wise) between them smaller
4897              * than the current smallest space found?
4898              */
4899             if (True == TestSpacing (top_y, bot_y, min_x,
4900                                         nxtGrp->top_y, nxtGrp->bot_y,
4901                                         nxtGrp->max_x, needed,
4902                                         canvas->metrics.horiz_pad_hint,
4903                                         &space))
4904               {
4905                 space += MoveGroup(canvas, layout, nxtGrp, needed - space);
4906                 if (maxSpace > space)
4907                     maxSpace = space;
4908               }
4909           }
4910
4911         /*
4912          * check the next group
4913          */
4914         nxtGrp = nxtGrp->next_info;
4915       }
4916
4917     /*
4918      * look at each of the text lines;
4919      */
4920     for (i = 0; i < canvas->txt_cnt; i++)
4921       {
4922         /*
4923          * Only look at those lines not already processed.
4924          */
4925         if (i != txt_idx && _DtCvIsNotProcessed(canvas->txt_lst[i]))
4926           {
4927             topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
4928             botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
4929             if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
4930                                 canvas->txt_lst[i].max_x, needed,
4931                                 canvas->metrics.horiz_pad_hint, &space))
4932               {
4933                 space += MoveText(canvas, layout, i, topY, botY, needed-space);
4934                 if (maxSpace > space)
4935                     maxSpace = space;
4936               }
4937           }
4938       }
4939
4940     /*
4941      * look at each of the rules/lines;
4942      */
4943     for (i = 0; i < canvas->line_cnt; i++)
4944       {
4945         /*
4946          * Only look at those lines not already processed.
4947          */
4948         if (i != line_idx && _DtCvIsNotProcessed(canvas->line_lst[i]))
4949           {
4950             /*
4951              * calculate the top and bottom of the line
4952              */
4953             topY = canvas->line_lst[i].pos_y;
4954             botY = canvas->line_lst[i].max_y;
4955
4956             if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
4957                                 canvas->line_lst[i].max_x, needed,
4958                                 canvas->metrics.horiz_pad_hint, &space))
4959               {
4960                 space += MoveLines(canvas, layout, i, topY, botY, needed-space);
4961                 if (maxSpace > space)
4962                     maxSpace = space;
4963               }
4964           }
4965       }
4966
4967     return maxSpace;
4968 }
4969
4970 /*****************************************************************************
4971  * Function:    static _DtCvUnit MoveGroup (_DtCanvasStruct canvas);
4972  *
4973  * Purpose:     To move groupings (container, tables, etc.) as a group to
4974  *              honor boundaries.
4975  * 
4976  *****************************************************************************/
4977 static _DtCvUnit
4978 MoveGroup (
4979     _DtCanvasStruct     *canvas,
4980     LayoutInfo          *layout,
4981     GrpInfo             *tst_grp,
4982     _DtCvUnit            needed)
4983 {
4984     _DtCvUnit    space;
4985
4986     /*
4987      * find out what's in front of it. And how much 'extra' room
4988      * there is.
4989      */
4990     space = CheckSpacing(canvas, layout, tst_grp, -1, -1,
4991                                 tst_grp->top_y, tst_grp->bot_y, tst_grp->min_x,
4992                                 needed);
4993     /*
4994      * now move the group
4995      */
4996     MoveLeft(canvas, tst_grp->cnt.beg_txt, tst_grp->cnt.end_txt,
4997                         tst_grp->cnt.beg_ln, tst_grp->cnt.end_ln, space);
4998
4999     tst_grp->max_x -= space;
5000     tst_grp->min_x -= space;
5001
5002     return space;
5003 }
5004
5005 /*****************************************************************************
5006  * Function:    static _DtCvUnit MoveText (_DtCanvasStruct canvas);
5007  *
5008  * Purpose: To move text lines to honor boundaries.
5009  * 
5010  *****************************************************************************/
5011 static _DtCvUnit
5012 MoveText (
5013     _DtCanvasStruct     *canvas,
5014     LayoutInfo          *layout,
5015     int                  idx,
5016     _DtCvUnit            top_y,
5017     _DtCvUnit            bot_y,
5018     _DtCvUnit            needed)
5019 {
5020     _DtCvUnit    space;
5021
5022     /*
5023      * find out what's in front of it. And how much 'extra' room
5024      * there is.
5025      */
5026     space = CheckSpacing(canvas, layout, NULL, idx, -1,
5027                                 top_y, bot_y,
5028                                 canvas->txt_lst[idx].text_x,
5029                                 needed);
5030     /*
5031      * now move the group
5032      */
5033     MoveLeft(canvas, idx, idx, -1, -1, space);
5034
5035     return space;
5036 }
5037
5038 /*****************************************************************************
5039  * Function:    static _DtCvUnit MoveLines (_DtCanvasStruct canvas);
5040  *
5041  * Purpose: To move groupings (container, tables, etc.) as a group to
5042  *          honor boundaries.
5043  * 
5044  *****************************************************************************/
5045 static _DtCvUnit
5046 MoveLines (
5047     _DtCanvasStruct     *canvas,
5048     LayoutInfo          *layout,
5049     int                  idx,
5050     _DtCvUnit            top_y,
5051     _DtCvUnit            bot_y,
5052     _DtCvUnit            needed)
5053 {
5054     _DtCvUnit    space;
5055
5056     /*
5057      * find out what's in front of it. And how much 'extra' room
5058      * there is.
5059      */
5060     space = CheckSpacing(canvas, layout, NULL, -1, idx,
5061                                 top_y, bot_y,
5062                                 canvas->line_lst[idx].pos_x,
5063                                 needed);
5064
5065     /*
5066      * now move the group
5067      */
5068     MoveLeft(canvas, -1, -1, idx, idx, space);
5069
5070     return space;
5071 }
5072
5073 /*****************************************************************************
5074  * Function:    static void CheckMoveInfo (_DtCanvasStruct canvas);
5075  *
5076  * Purpose:     To move each of the groupings, rules and text lines to
5077  *              honor boundaries.
5078  * 
5079  *****************************************************************************/
5080 static void
5081 CheckMoveInfo (
5082     _DtCanvasStruct     *canvas,
5083     LayoutInfo          *layout)
5084 {
5085     int          i;
5086     _DtCvUnit    topY;
5087     _DtCvUnit    botY;
5088     _DtCvUnit    maxWidth = canvas->metrics.width;
5089     GrpInfo     *nxtGrp;
5090
5091     /*
5092      * fill in the max x of each group
5093      */
5094     for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
5095       {
5096         /*
5097          * find the maximum of the group
5098          */
5099         MaxOfGroup(nxtGrp, canvas->txt_lst, canvas->line_lst,
5100                                 layout->info.max_x_pos, layout->info.y_pos);
5101       }
5102
5103     /*
5104      * now check each group for exceeding the boundary.
5105      */
5106     for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
5107       {
5108         /*
5109          * does this group exceed the boundary?
5110          */
5111         if (maxWidth < nxtGrp->max_x)
5112              (void) MoveGroup(canvas, layout, nxtGrp, nxtGrp->max_x - maxWidth);
5113       }
5114
5115     /*
5116      * look at each of the text lines;
5117      */
5118     for (i = 0; i < canvas->txt_cnt; i++)
5119       {
5120         /*
5121          * Only look at those lines not already processed.
5122          */
5123         if (_DtCvIsNotProcessed(canvas->txt_lst[i]) &&
5124                                         maxWidth < canvas->txt_lst[i].max_x)
5125           {
5126             topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
5127             botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
5128             (void) MoveText(canvas, layout, i, topY, botY,
5129                                         canvas->txt_lst[i].max_x - maxWidth);
5130           }
5131       }
5132
5133     /*
5134      * look at each of the rules/lines;
5135      */
5136     for (i = 0; i < canvas->line_cnt; i++)
5137       {
5138         /*
5139          * Only look at those lines not already processed.
5140          */
5141         if (_DtCvIsNotProcessed(canvas->line_lst[i]) &&
5142                                         maxWidth < canvas->line_lst[i].max_x)
5143           {
5144             /*
5145              * calculate the top and bottom of the line
5146              */
5147             topY = canvas->line_lst[i].pos_y;
5148             botY = canvas->line_lst[i].max_y;
5149
5150             (void) MoveLines(canvas, layout, i, topY, botY,
5151                                         canvas->line_lst[i].max_x - maxWidth);
5152           }
5153       }
5154 }
5155
5156 /*****************************************************************************
5157  * Function:    static void CompareUnits ()
5158  *
5159  * Parameters:
5160  *
5161  * Returns:
5162  *
5163  * Purpose:
5164  * 
5165  *****************************************************************************/
5166 static int
5167 CompareUnits (
5168     const void  *a,
5169     const void  *b)
5170 {
5171     _DtCvUnit *aPtr = (_DtCvUnit *) a;
5172     _DtCvUnit *bPtr = (_DtCvUnit *) b;
5173
5174     if (*aPtr <  *bPtr) return -1;
5175     if (*aPtr == *bPtr) return 0;
5176
5177     return 1;
5178 }
5179
5180 /*****************************************************************************
5181  * Function:    static void CompareSearchs ()
5182  *
5183  * Parameters:
5184  *
5185  * Returns:
5186  *
5187  * Purpose:
5188  * 
5189  *****************************************************************************/
5190 static int
5191 CompareSearchs (
5192     const void  *a,
5193     const void  *b)
5194 {
5195     _DtCvSearchData *searchA = (_DtCvSearchData *) a;
5196     _DtCvSearchData *searchB = (_DtCvSearchData *) b;
5197     _DtCvDspLine    *lineA   = &(searchA->lst[searchA->idx]);
5198     _DtCvDspLine    *lineB   = &(searchB->lst[searchB->idx]);
5199     _DtCvUnit        topA    = lineA->baseline - lineA->ascent;
5200     _DtCvUnit        topB    = lineB->baseline - lineB->ascent;
5201     _DtCvUnit        heightA = lineA->ascent   + lineA->descent;
5202     _DtCvUnit        heightB = lineB->ascent   + lineB->descent;
5203     _DtCvUnit        centA   =  topA + (heightA >> 1);
5204     _DtCvUnit        centB   =  topB + (heightB >> 1);
5205
5206     if (lineA->baseline + lineA->descent < centB && centA < topB)
5207         return -1;
5208
5209     if (lineB->baseline + lineB->descent < centA && centB < topA)
5210         return 1;
5211
5212     if (lineA->text_x != lineB->text_x)
5213         return ((lineA->text_x < lineB->text_x) ? -1 : 1);
5214
5215     if (topA != topB)
5216         return ((topA < topB) ? -1 : 1);
5217
5218     if (heightA != heightB)
5219         return ((heightA < heightB) ? -1 : 1);
5220
5221     if (lineA->max_x != lineB->max_x)
5222         return ((lineA->max_x < lineB->max_x) ? -1 : 1);
5223
5224     return 0;
5225 }
5226
5227 /*****************************************************************************
5228  * Function:    static Status LayoutCanvasInfo (_DtCvHandle canvas);
5229  *
5230  * Parameters:
5231  *
5232  * Returns:
5233  *
5234  * Purpose:
5235  * 
5236  *****************************************************************************/
5237 static _DtCvStatus
5238 LayoutCanvasInfo (
5239     _DtCanvasStruct     *canvas,
5240     LayoutInfo          *layout,
5241     _DtCvUnit            divisor,
5242     char                *target_id)
5243 {
5244     int                  i = 0;
5245     DataPoint            basePt;
5246     _DtCvUnit            maxWidth = 0;
5247     _DtCvUnit            maxXPos  = 0;
5248     _DtCvStatus          result   = _DtCvSTATUS_OK;
5249
5250     *layout           = DefInfo;
5251     layout->divisor   = divisor;
5252     layout->max_width = canvas->metrics.width;
5253     layout->left      = canvas->metrics.side_margin;
5254     layout->right     = canvas->metrics.side_margin;
5255     layout->target_id = target_id;
5256
5257     _DtCvInitLayoutInfo(canvas, &(layout->info));
5258
5259     basePt = DefDataPt;
5260     PushDataPoint(layout, &basePt);
5261     SetMargins (layout);
5262     SetTextPosition (layout, True);
5263
5264     ProcessSegmentList(canvas, layout, canvas->element_lst, -1,
5265                                                 &maxWidth, &maxXPos, NULL);
5266
5267     RemoveDataPoint(layout, &basePt);
5268
5269     /*
5270      * fill in the max_x of each line of text/regions.
5271      */
5272     for (i = 0; i < canvas->txt_cnt; i++)
5273         canvas->txt_lst[i].max_x = MaxXOfLine(canvas, &(canvas->txt_lst[i]));
5274
5275     /*
5276      * calculate the actual right hand side boundary.
5277      */
5278     layout->info.max_x_pos += canvas->metrics.side_margin;
5279
5280     /*
5281      * the max_x_pos so far has indicated where the *next* character,
5282      * line or region will be *started*. Therefore back up one to
5283      * indicate the true last position used.
5284      */
5285     layout->info.max_x_pos--;
5286
5287     return result;
5288
5289 }  /* End LayoutCanvasInfo */
5290
5291 /*****************************************************************************
5292  * Function:    static Status LayoutCanvas (_DtCvHandle canvas);
5293  *
5294  * Parameters:
5295  *
5296  * Returns:
5297  *
5298  * Purpose:
5299  * 
5300  *****************************************************************************/
5301 static _DtCvStatus
5302 LayoutCanvas (
5303     _DtCanvasStruct     *canvas,
5304     LayoutInfo          *layout,
5305     char                *target_id)
5306 {
5307     _DtCvUnit            divisor = 1;
5308     _DtCvValue           redo;
5309     _DtCvStatus          result;
5310
5311     int i, search_cnt = canvas->search_cnt;
5312     
5313     do {
5314         redo = False;
5315         result = LayoutCanvasInfo(canvas, layout, divisor, target_id);
5316
5317         /*
5318          * Are we suppose to honor the boundary?
5319          * If so, do any lines go over the boundary?
5320          * Is there any margins that can be decremented?
5321          */
5322         if (_DtCvSTATUS_OK == result
5323                 && (_DtCvUSE_BOUNDARY == canvas->constraint ||
5324                         _DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
5325                 && layout->info.max_x_pos >= canvas->metrics.width)
5326           {
5327             if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
5328               {
5329                 int i;
5330
5331                 /*
5332                  * clear the processed flag from all the text/region lines.
5333                  */
5334                 for (i = 0; i < canvas->txt_cnt; i++)
5335                    _DtCvClearProcessed(canvas->txt_lst[i]);
5336
5337                 /*
5338                  * clear the processed flag from all the line/rules.
5339                  */
5340                 for (i = 0; i < canvas->line_cnt; i++)
5341                    _DtCvClearProcessed(canvas->line_lst[i]);
5342
5343                 CheckMoveInfo(canvas, layout);
5344
5345                 /*
5346                  * recalculate the new max x
5347                  */
5348                 layout->info.max_x_pos = 0;
5349                 for (i = 0; i < canvas->txt_cnt; i++)
5350                     if (layout->info.max_x_pos < canvas->txt_lst[i].max_x)
5351                         layout->info.max_x_pos = canvas->txt_lst[i].max_x;
5352
5353                 for (i = 0; i < canvas->line_cnt; i++)
5354                     if (layout->info.max_x_pos < canvas->line_lst[i].max_x)
5355                         layout->info.max_x_pos = canvas->line_lst[i].max_x;
5356
5357                 layout->info.max_x_pos--;
5358               }
5359             else if (True == layout->margin_non_zero)
5360               {
5361                 redo = True;
5362                 divisor *= 2;
5363                 canvas->txt_cnt  = 0;
5364                 canvas->line_cnt = 0;
5365                 canvas->trav_cnt = 0;
5366               }
5367           }
5368
5369       } while (True == redo);
5370
5371     /*
5372      * clean up table information
5373      */
5374     if (NULL != layout->grp_lst)
5375         free(layout->grp_lst);
5376
5377     /*
5378      * subtract one from the y position to indicate the *last*
5379      * pixel/column/etc that will be rendered.
5380      */
5381     canvas->max_y = layout->info.y_pos - 1;
5382     canvas->max_x = layout->info.max_x_pos;
5383
5384     for (i = search_cnt; i < canvas->search_cnt; i++)
5385       {
5386         canvas->searchs[i - search_cnt]     = canvas->searchs[i];
5387         canvas->searchs[i - search_cnt].lst = canvas->txt_lst;
5388       }
5389
5390     canvas->search_cnt -= search_cnt;
5391
5392     /*
5393      * are there any search hits?
5394      */
5395     if (0 != canvas->search_cnt)
5396         qsort (canvas->searchs, canvas->search_cnt, sizeof(_DtCvSearchData),
5397                                                         CompareSearchs);
5398     /*
5399      * sort the page break list.
5400      */
5401     if (0 != canvas->brk_cnt)
5402         qsort (canvas->pg_breaks, canvas->brk_cnt, sizeof(_DtCvUnit),
5403                                                                 CompareUnits);
5404
5405     return result;
5406
5407 }  /* End LayoutCanvas */
5408
5409 /*****************************************************************************
5410  * Function:    static void SortTraversal (_DtCvHandle canvas);
5411  *
5412  * Parameters:
5413  *
5414  * Returns:
5415  *
5416  * Purpose:
5417  * 
5418  *****************************************************************************/
5419 static void
5420 SortTraversal (_DtCanvasStruct *canvas)
5421 {
5422     int i;
5423
5424     /*
5425      * sort the links correctly. First, establish the x,y,width,height
5426      * of each link.
5427      */
5428     for (i = 0; i < canvas->trav_cnt; i++)
5429       {
5430         if (_DtCvTraversalLink == canvas->trav_lst[i].type)
5431             GetLinkInfo(canvas, i, &(canvas->trav_lst[i].x_pos),
5432                                         &(canvas->trav_lst[i].y_pos),
5433                                         &(canvas->trav_lst[i].width),
5434                                         &(canvas->trav_lst[i].height));
5435         else
5436             _DtCvCalcMarkPos(canvas, canvas->trav_lst[i].idx,
5437                                         &(canvas->trav_lst[i].x_pos),
5438                                         &(canvas->trav_lst[i].y_pos),
5439                                         &(canvas->trav_lst[i].width),
5440                                         &(canvas->trav_lst[i].height));
5441       }
5442
5443     _DtCvSortTraversalList(canvas, _DtCvFALSE);
5444 }
5445
5446 /*****************************************************************************
5447  * Function:    static void ProcessMarks (_DtCanvasStruct *canvas);
5448  *
5449  * Parameters:
5450  *
5451  * Returns:
5452  *
5453  * Purpose:
5454  * 
5455  *****************************************************************************/
5456 static _DtCvStatus
5457 ProcessMarks (
5458     _DtCanvasStruct      *canvas,
5459     _DtCvPointInfo      **mark_lst)
5460 {
5461     int                 markIdx;
5462     int                 result = _DtCvSTATUS_OK;
5463     _DtCvSelectData     beg;
5464     _DtCvSelectData     end;
5465     _DtCvSegmentI       *firstSeg;
5466
5467     while (NULL != mark_lst && NULL != *mark_lst)
5468       {
5469         /*
5470          * convert the segments to begin and end points
5471          */
5472         if (_DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, (*mark_lst)->segs,
5473                                         &beg, &end, NULL, NULL, &firstSeg))
5474             /*
5475              * just set a return value since this indicates bad data
5476              * and not system failure.
5477              */
5478             result = _DtCvSTATUS_BAD;
5479
5480         /*
5481          * now add it to the mark list
5482          */
5483         else
5484           {
5485             markIdx =  _DtCvAddToMarkList(canvas, (*mark_lst)->client_data,
5486                                                 _DtCvFALSE, &beg, &end);
5487             /*
5488              * now put the mark in the traversal list, but don't sort
5489              * or fill out position and dimension information.
5490              * SortTraversal() will do that.
5491              *
5492              * bail here if system failure indicated.
5493              */
5494             if (-1 == markIdx || 0 != _DtCvSetTravEntryInfo(canvas,
5495                                                 _DtCvGetNextTravEntry(canvas),
5496                                                 _DtCvTraversalMark, firstSeg,
5497                                                 markIdx, _DtCvTRUE))
5498                 return _DtCvSTATUS_BAD;
5499           }
5500
5501         mark_lst++;
5502       }
5503
5504     return result;
5505 }
5506
5507 /*****************************************************************************
5508  *              Public Functions
5509  *****************************************************************************/
5510 /*****************************************************************************
5511  * Function:    void _DtCanvasResize (_DtCvHandle canvas);
5512  *
5513  * Parameters:
5514  *
5515  * Returns:
5516  *
5517  * Purpose:
5518  * 
5519  *****************************************************************************/
5520 _DtCvStatus
5521 _DtCanvasResize (
5522     _DtCvHandle          canvas_handle,
5523     _DtCvValue           force,
5524     _DtCvUnit           *ret_width,
5525     _DtCvUnit           *ret_height )
5526 {
5527     int                  i;
5528     _DtCvStatus          selectStatus;
5529     _DtCvStatus          retStatus = _DtCvSTATUS_NONE;
5530     _DtCanvasStruct     *canvas    = (_DtCanvasStruct *) canvas_handle;
5531     _DtCvUnit            oldWidth  = canvas->metrics.width;
5532     LayoutInfo           layOut;
5533     _DtCvPointInfo       selPt;
5534     _DtCvPointInfo      **markInfo;
5535
5536     selPt.client_data = NULL;
5537     selPt.segs        = NULL;
5538
5539     /*
5540      * check to see if the width has changed - if not,
5541      * don't do anything (but re-initialize the metrics
5542      * to get the new height).
5543      */
5544     (*(canvas->virt_functions.get_metrics))(canvas->client_data,
5545                                 _DtCvCANVAS_TYPE, &(canvas->metrics));
5546
5547     if (canvas->metrics.width != oldWidth || _DtCvTRUE == force)
5548       {
5549         /*
5550          * remember the current selection.
5551          */
5552         selectStatus = _DtCanvasGetSelectionPoints(canvas, &(selPt.segs),
5553                                                                 NULL, NULL);
5554         /*
5555          * remember the marks
5556          */
5557         if (_DtCvSTATUS_BAD == _DtCvGetMarkSegs(canvas, &markInfo))
5558             return _DtCvSTATUS_BAD;
5559
5560         /*
5561          * Re-Layout the information.
5562          * First step - invalidate some counters.
5563          */
5564         canvas->trav_cnt = 0;   /* zero this only because we re-process */
5565                                 /* do not zero cur_hyper or we'll loose */
5566                                 /* where we are in the TOC              */
5567         canvas->txt_cnt  = 0;
5568         canvas->line_cnt = 0;
5569         canvas->mark_cnt = 0;
5570         canvas->brk_cnt  = 0;
5571
5572         /*
5573          * Layout the information if there is anything to do
5574          */
5575         if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, NULL))
5576             return _DtCvSTATUS_BAD;
5577     
5578         /*
5579          * restore the current selection.
5580          */
5581         if (_DtCvSTATUS_OK == selectStatus)
5582           {
5583             _DtCanvasActivatePts(canvas,_DtCvACTIVATE_SELECTION, &selPt,
5584                                                                 NULL,NULL);
5585             _DtCvFreeArray((void **) selPt.segs);
5586           }
5587
5588         /*
5589          * now place the marks in the mark and traversal lists
5590          */
5591         ProcessMarks(canvas, markInfo);
5592         if (NULL != markInfo)
5593           {
5594             for (i = 0; NULL != markInfo[i]; i++)
5595                 _DtCvFreeArray((void **) (markInfo[i]->segs));
5596             _DtCvFreeArray((void **) markInfo);
5597           }
5598
5599         /*
5600          * sort the traversal list.
5601          */
5602         SortTraversal(canvas);
5603         retStatus = _DtCvSTATUS_OK;
5604       }
5605
5606     /*
5607      * return the maximum height and width used
5608      */
5609     if (ret_width != NULL)
5610         *ret_width  = canvas->max_x;
5611     if (ret_height != NULL)
5612         *ret_height = canvas->max_y;
5613
5614     return retStatus;
5615
5616 }  /* End _DtCanvasResize */
5617
5618 /*****************************************************************************
5619  * Function:    void _DtCanvasSetTopic (_DtCvHandle canvas);
5620  *
5621  * Parameters:
5622  *
5623  * Returns:
5624  *
5625  * Purpose:
5626  * 
5627  *****************************************************************************/
5628 _DtCvStatus
5629 _DtCanvasSetTopic (
5630     _DtCvHandle          canvas_handle,
5631     _DtCvTopicPtr        topic,
5632     _DtCvValue           honor_size,
5633     _DtCvUnit           *ret_width,
5634     _DtCvUnit           *ret_height,
5635     _DtCvUnit           *ret_y )
5636 {
5637     _DtCvStatus          result = _DtCvSTATUS_OK;
5638     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
5639     LayoutInfo          layOut;
5640
5641     /*
5642      * clean the canvas
5643      */
5644     _DtCanvasClean (canvas_handle);
5645
5646     /*
5647      * attach to the canvas
5648      */
5649     canvas->element_lst = topic->seg_list;
5650
5651     /*
5652      * Attach the link information
5653      */
5654     canvas->link_data = topic->link_data;
5655
5656     /*
5657      * init the internal use pointer in all containers to NULL
5658      */
5659     _DtCvClearInternalUse(canvas->element_lst, _DtCvFALSE);
5660
5661     /*
5662      * Layout the information if there is anything to do
5663      */
5664     canvas->constraint = honor_size;
5665     if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, topic->id_str))
5666         return _DtCvSTATUS_BAD;
5667     
5668     /*
5669      * add the marks to the mark and traversal lists
5670      */
5671     ProcessMarks(canvas, topic->mark_list);
5672
5673     /*
5674      * sort the traversal list.
5675      */
5676     SortTraversal(canvas);
5677
5678     /*
5679      * return the maximum height and width used
5680      * And the location of the id.
5681      */
5682     if (ret_width != NULL)
5683         *ret_width = canvas->max_x;
5684     if (ret_height != NULL)
5685         *ret_height = canvas->max_y;
5686     if (ret_y != NULL)
5687       {
5688         if (NULL != layOut.target_id && True != layOut.id_found)
5689             result = _DtCvSTATUS_ID_BAD;
5690         *ret_y = layOut.id_Ypos;
5691       }
5692
5693     return result;
5694
5695 }  /* End _DtCanvasSetTopic */