Add GNU LGPL headers to all .c .C and .h files
[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 librararies 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;
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     register 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         register 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      rightMargin = 0;
2125     _DtCvUnit      saveLeft    = layout->left;
2126     _DtCvUnit      saveYpos    = layout->info.y_pos;
2127     _DtCvUnit      tableYpos;
2128     _DtCvUnit      newHeight;
2129     _DtCvUnit      newWidth;
2130     _DtCvUnit      oldAlignPos;
2131     short          anchorRow = -1;
2132
2133     const char   **widthStr;
2134     const char    *saveAlignChar = layout->info.align_char;
2135     char         **rowIds;
2136     char          *alignCharacters = NULL;
2137     char           alignBuf[16];
2138
2139     _DtCvFrmtOption   saveTxtJustify = layout->txt_justify;
2140     _DtCvFrmtOption   colJustify  = _DtCvJUSTIFY_LEFT;
2141     _DtCvFrmtOption  *colJustSpec;
2142
2143     _DtCvValue     oldFound  = layout->id_found;
2144     _DtCvValue     haveHeads = False;
2145     _DtCvValue     haveBrds  = False;
2146     _DtCvValue     saveState = layout->table_flag;
2147     _DtCvValue     saveAlignFlag = layout->info.align_flag;
2148     _DtCvValue     saveAlignPos  = layout->info.align_pos;
2149     _DtCvValue     redo;
2150
2151     CellInfo     defCell;
2152     CellInfo    *cellInfo = &defCell;
2153     ColumnSpec   defColumn;
2154     ColumnSpec  *colSpecs = &defColumn;
2155     RowSpec      defRow;
2156     RowSpec     *rowSpecs = &defRow;
2157     DataPoint    basePt;
2158     GrpInfo      grpInfo = DefGrpInfo;
2159
2160     /*
2161      * get the base margins that the table will be working in.
2162      */
2163     GetCurrentDataPoint(layout, &basePt);
2164
2165     /*
2166      * find out how many rows there are.
2167      */
2168     for (rowIds = _DtCvCellIdsOfTableSeg(table), maxRows = 0;
2169                         rowIds != NULL && rowIds[maxRows] != NULL;  maxRows++);
2170
2171     if (maxRows == 0)
2172         return;
2173
2174     /*
2175      * get the number of columns and the column widths
2176      */
2177     maxCols     = _DtCvNumColsOfTableSeg(table);
2178     widthStr    = (const char **)_DtCvColWOfTableSeg(table);
2179     colJustSpec = _DtCvColJustifyOfTableSeg(table);
2180
2181     if (maxCols < 1)
2182         maxCols = 1;
2183
2184     if (widthStr == NULL)
2185         widthStr = DefWidth;
2186
2187     /*
2188      * determine the width the table has to work with.
2189      */
2190     workWidth = layout->max_width - basePt.left - basePt.right -
2191                                                 layout->left - layout->right;
2192     if (workWidth < 0)
2193         workWidth = 0;
2194
2195     /*
2196      * turn the string specifying column widths into units.
2197      */
2198     if (maxCols != 1)
2199       {
2200         colSpecs = (ColumnSpec *) malloc (sizeof(ColumnSpec) * maxCols);
2201         if (colSpecs == NULL)
2202             return;
2203       }
2204     if (maxRows != 1)
2205       {
2206         rowSpecs = (RowSpec *) malloc (sizeof(RowSpec) * maxRows);
2207         if (rowSpecs == NULL)
2208           {
2209             if (maxCols > 1)
2210                 free(colSpecs);
2211             return;
2212           }
2213       }
2214     if (maxRows != 1 || maxCols != 1)
2215       {
2216         cellInfo = (CellInfo *) malloc (sizeof(CellInfo) * maxCols * maxRows);
2217         if (cellInfo == NULL)
2218           {
2219             if (maxCols > 1)
2220                 free(colSpecs);
2221             if (maxRows > 1)
2222                 free(rowSpecs);
2223             return;
2224           }
2225       }
2226
2227     /*
2228      * for each column, process the width specification.
2229      *    '+Optimal,Take,Give'
2230      *
2231      *     +       - means the cell can 'hang over' its neighbors.
2232      *               It will take everything it can get and then
2233      *               push the other below it. (Labeled lists).
2234      *     Optimal - The desired percentage of the available space to
2235      *               use for the column.
2236      *     Take    - The percentage amount the column will take from
2237      *               other columns to make itself 'fit'.
2238      *     Give    - The percentage amount the column is willing to give up
2239      *               to other columns for them to 'fit'.
2240      */
2241     for (col = 0, divisor = 0; col < maxCols; col++)
2242       {
2243         const char  *nxtWidth = *widthStr;
2244
2245         /*
2246          * move to the meat of the width specification string.
2247          */
2248         SkipToNumber(&nxtWidth);
2249
2250         /*
2251          * set the correct 'allow hangers' flag.
2252          */
2253         colSpecs[col].hanger  = _DtCvFALSE;
2254         if ('+' == *nxtWidth)
2255           {
2256             colSpecs[col].hanger = _DtCvTRUE;
2257             nxtWidth++;
2258           }
2259
2260         /*
2261          * now process the O,G,T specification.
2262          */
2263         a = GetValueFromString(&nxtWidth, 1); if (a < 1) a = 1;
2264         b = GetValueFromString(&nxtWidth, 0); if (b < 0) b = 0;
2265         c = GetValueFromString(&nxtWidth, b); if (c > a) c = a;
2266
2267         /*
2268          * for now just get the base percentages.
2269          */
2270         colSpecs[col].min     = a - c;
2271         colSpecs[col].actual  = a;
2272         colSpecs[col].max     = a + b;
2273
2274         /*
2275          * get the column justification.
2276          */
2277         if (NULL != colJustSpec)
2278           {
2279             colJustify = *colJustSpec;
2280             colJustSpec++;
2281           }
2282         colSpecs[col].justify = colJustify;
2283         if (_DtCvINHERIT == colJustify)
2284             colSpecs[col].justify = saveTxtJustify;
2285
2286         /*
2287          * up the divisor value.
2288          */
2289         divisor += colSpecs[col].actual;
2290
2291         /*
2292          * skip to the next set of width specifications
2293          */
2294         if (col + 1 < maxCols && NULL != widthStr[1])
2295             widthStr++;
2296
2297         /*
2298          * initialize the cell information for the rows in this column
2299          */
2300         for (row = 0; row < maxRows; row++)
2301           {
2302             cellInfo[row * maxCols + col].cell_seg = NULL;
2303             cellInfo[row * maxCols + col].col_spn  = 0;
2304             cellInfo[row * maxCols + col].row_spn  = 0;
2305             cellInfo[row * maxCols + col].info     = DefLayFrmtInfo;
2306           }
2307       }
2308
2309     /*
2310      * initialize the row specs
2311      */
2312     newHeight = 0;
2313     if (-1 != min_y && 1 == maxRows)
2314         newHeight = min_y - saveYpos;
2315     for (row = 0; row < maxRows; row++)
2316       {
2317         rowSpecs[row].column  = -1;
2318         rowSpecs[row].y_adj   = 0;
2319         rowSpecs[row].height  = newHeight;
2320         rowSpecs[row].height  = newHeight;
2321         rowSpecs[row].next_id = rowIds[row];
2322       }
2323
2324     /*
2325      * now figure the real values
2326      */
2327     if (divisor < 1)
2328         divisor = 1;
2329     for (col = 0; col < maxCols; col++)
2330       {
2331         colSpecs[col].min    = workWidth * colSpecs[col].min    / divisor;
2332         colSpecs[col].actual = workWidth * colSpecs[col].actual / divisor;
2333         colSpecs[col].max    = workWidth * colSpecs[col].max    / divisor;
2334
2335         if (colSpecs[col].min < 1)
2336             colSpecs[col].min = 1;
2337         if (colSpecs[col].actual < 1)
2338             colSpecs[col].actual = 1;
2339         if (colSpecs[col].max < 1)
2340             colSpecs[col].max = 1;
2341       }
2342
2343     /*
2344      * now process the table.
2345      */
2346     tableYpos = layout->info.y_pos;
2347     maxRowSpn = 1;
2348     alignCharacters = _DtCvJustifyCharsOfTableSeg(table);
2349
2350     /*
2351      * set up the state of table processing and
2352      * the beginning line/text counts.
2353      */
2354     layout->table_flag = True;
2355     SetBeginCounts(canvas, &(grpInfo.cnt));
2356
2357     /*
2358      * now process each column, row by row.
2359      * Doing it row by row allows the columns to shake out their
2360      * sizing with less reformatting.
2361      */
2362     for (col = 0; col < maxCols; col++)
2363       {
2364         /*
2365          * remember where this column starts.
2366          */
2367         saveTravCnt  = canvas->trav_cnt;
2368         saveLnStart  = canvas->line_cnt;
2369         saveTxtStart = canvas->txt_cnt;
2370         newLeft      = layout->left;
2371         colJustify   = layout->txt_justify;
2372         layout->txt_justify = colSpecs[col].justify;
2373
2374         /*
2375          * initialize the JUSTIFY_NUM or JUSTIFY_CHAR information
2376          */
2377         layout->info.align_pos  = 0;
2378         layout->info.align_char = PeriodStr;
2379         if (_DtCvJUSTIFY_CHAR == layout->txt_justify)
2380           {
2381             /*
2382              * are any alignment characters specified?
2383              */
2384             if (NULL != alignCharacters && '\0' != alignCharacters)
2385               {
2386                 int len = mblen(alignCharacters, MB_CUR_MAX);
2387
2388                 /*
2389                  * copy the character into a buffer
2390                  */
2391                 strncpy(alignBuf, alignCharacters, len);
2392                 alignBuf[len] = '\0';
2393                 layout->info.align_char = alignBuf;
2394
2395                 /*
2396                  * are there more characters? If so increment for the
2397                  * next column that may have JUSTIFY_CHAR. Otherwise,
2398                  * leave alone and re-use for other columns.
2399                  */
2400                 if ('\0' != alignCharacters[len])
2401                     alignCharacters += len;
2402               }
2403
2404             /* no...then default */
2405             else
2406                 layout->txt_justify = _DtCvJUSTIFY_LEFT;
2407           }
2408
2409         do {
2410             /*
2411              * reset the counts to the start
2412              */
2413             canvas->trav_cnt = saveTravCnt;
2414             canvas->line_cnt = saveLnStart;
2415             canvas->txt_cnt  = saveTxtStart;
2416             layout->left     = newLeft;
2417
2418             /*
2419              * for each row, format the cell in this columns
2420              */
2421             for (row = 0, redo = False, cell = col;
2422                                 row < maxRows && redo == False;
2423                                                 row++, cell += maxCols)
2424               {
2425                 /*
2426                  * remember the old height
2427                  */
2428                 rowSpecs[row].lst_height = rowSpecs[row].height;
2429
2430                 /*
2431                  * set the alignment flag for each column in the row.
2432                  */
2433                 layout->info.align_flag = False;
2434                 if (_DtCvJUSTIFY_CHAR == layout->txt_justify ||
2435                                         _DtCvJUSTIFY_NUM == layout->txt_justify)
2436                     layout->info.align_flag = True;
2437
2438                 /*
2439                  * remember the alignment position
2440                  */
2441                 oldAlignPos = layout->info.align_pos;
2442
2443                 /*
2444                  * layout all the cells jammed to the top of the table.
2445                  * later, they get moved down to their position.
2446                  */
2447                 layout->info.y_pos = tableYpos;
2448                 redo = ResolveCell(canvas, layout, table,
2449                                     colSpecs, rowSpecs, col, row,
2450                                     maxCols, maxRows, cellInfo);
2451                 /*
2452                  * check for maximum row span
2453                  */
2454                 if (maxRowSpn < cellInfo[cell].row_spn)
2455                     maxRowSpn = cellInfo[cell].row_spn;
2456
2457                 /*
2458                  * did the cell have borders?
2459                  */
2460                 if (0 != cellInfo[cell].info.cnt.my_lines)
2461                     haveBrds = True;
2462
2463                 /*
2464                  * check to see if the specified anchor has been found in
2465                  * this row. If so, save some information for later use.
2466                  */
2467                 if (anchorRow == -1 && oldFound != layout->id_found)
2468                     anchorRow = row;
2469
2470                 /*
2471                  * check to see if the alignment position has changed.
2472                  * for all but the first row!
2473                  */
2474                 if (0 != row && oldAlignPos != layout->info.align_pos)
2475                     redo = True;
2476               }
2477
2478             if (True == redo)
2479               {
2480                 for (a = 0; a < row; a++)
2481                   {
2482                     /*
2483                      * restore the old row heights for this column
2484                      */
2485                     rowSpecs[a].height = rowSpecs[a].lst_height;
2486
2487                     /*
2488                      * reset the hanging cell information.
2489                      */
2490                     if (col == rowSpecs[a].column)
2491                       {
2492                         rowSpecs[a].column = -1;
2493                         rowSpecs[a].y_adj  = 0;
2494                       }
2495                   }
2496               }
2497
2498           } while (redo == True);
2499         
2500         /*
2501          * push the next column to the right by size of this column
2502          */
2503         layout->left += colSpecs[col].actual;
2504
2505         /*
2506          * restore the horizontal text justification
2507          */
2508         layout->txt_justify = colJustify;
2509       }
2510
2511     /*
2512      * set the ending counts for the lines/text in the table.
2513      * and save the information as long as we are not a table
2514      * that is a descendant of some container with a border and
2515      * our cells include borders and we're going to have to honor
2516      * boundaries.
2517      */
2518     SetEndCounts(canvas, &(grpInfo.cnt), 0);
2519     if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint &&
2520                                 False == layout->brdr_flag && True == haveBrds)
2521       {
2522         GrpInfo *info = (GrpInfo *) malloc (sizeof(GrpInfo));
2523
2524         /*
2525          * warning - nothing done if malloc error.
2526          */
2527         if (NULL != info)
2528           {
2529             /*
2530              * initialize to the line counts for the table
2531              */
2532             *info = grpInfo;
2533
2534             /*
2535              * set the linked list information
2536              */
2537             info->next_info = layout->grp_lst;
2538             layout->grp_lst = info;
2539           }
2540       }
2541
2542     /*
2543      * Now go back and search for zeroed row heights and fill them in
2544      * based on spanned rows. This can only happen if maxRowSpn is
2545      * greater than 1! Otherwise, a row height really did end up zero!
2546      */
2547     if (maxRowSpn > 1)
2548       {
2549         /*
2550          * try to resolve the zero height rows
2551          */
2552         for (a = 1, redo = True; redo && a < maxRowSpn; a++)
2553           {
2554             redo = False;
2555             for (row = 0; row < maxRows; row++)
2556               {
2557                 if (rowSpecs[row].height == 0 &&
2558                     ResolveHeight(rowSpecs, cellInfo, maxCols, row, a) == 0)
2559                         redo = True;
2560               }
2561           }
2562         
2563         /*
2564          * if any of the rows comes up unresolved, force to an average
2565          * line height.
2566          *
2567          * But only do this if the first cell *does not* span all the rows
2568          * and columns.
2569          */
2570         if (redo &&
2571                 cellInfo[0].row_spn != maxRows && cellInfo[0].col_spn != maxCols)
2572           {
2573             for (row = 0; row < maxRows; row++)
2574               {
2575                 if (rowSpecs[row].height == 0)
2576                     rowSpecs[row].height = canvas->metrics.line_height;
2577               }
2578           }
2579
2580         /*
2581          * Now, double check that the row heights will accomodate
2582          * all the cells.
2583          */
2584         for (row = 0; row < maxRows; row++)
2585             for (col = 0; col < maxCols; col++)
2586                 AdjustHeight(cellInfo, rowSpecs, maxCols, row, col);
2587       }
2588
2589     /*
2590      * now check that the minimum heights used for the rows matches
2591      * or exceeds the minimum y position required.
2592      */
2593     if (-1 != min_y)
2594       {
2595         _DtCvUnit  pad;
2596
2597         for (newHeight = 0, row = 0; row < maxRows; row++)
2598             newHeight += rowSpecs[row].height;
2599
2600         if (tableYpos + newHeight < min_y)
2601           {
2602             newHeight = tableYpos - min_y;
2603             for (row = 0; 0 < newHeight && row < maxRows; row++)
2604               {
2605                 pad                   = (newHeight/(maxRows-row));
2606                 rowSpecs[row].height += pad;
2607                 newHeight            -= pad;
2608               }
2609           }
2610       }
2611
2612     /*
2613      * now reposition the cells based on the final row heights.
2614      */
2615     layout->info.y_pos = tableYpos;
2616     for (tableYpos = 0, cell = 0, row = 0; row < maxRows;
2617         tableYpos = tableYpos + rowSpecs[row].height + rowSpecs[row].y_adj,
2618         row++)
2619       {
2620         /*
2621          * check to see if the specified anchor has been found in this
2622          * row. If so, adjust the found position.
2623          */
2624         if (anchorRow == row)
2625             layout->id_Ypos += tableYpos;
2626
2627         for (col = 0, layout->left = saveLeft; col < maxCols;
2628                                 layout->left += colSpecs[col++].actual, cell++)
2629           {
2630             if (cellInfo[cell].cell_seg != NULL)
2631               {
2632                 /*
2633                  * calculate the new height
2634                  */
2635                 for (newHeight = 0, a = 0; a < cellInfo[cell].row_spn; a++)
2636                   {
2637                     newHeight += rowSpecs[row + a].height;
2638                     if (col != rowSpecs[row + a].column)
2639                         newHeight += rowSpecs[row + a].y_adj;
2640                   }
2641
2642                 /*
2643                  * calculate the new width.
2644                  */
2645                 for (newWidth = 0, a = 0; a < cellInfo[cell].col_spn; a++)
2646                     newWidth += colSpecs[col + a].actual;
2647
2648                 /*
2649                  * now get the overhang space for this cell
2650                  */
2651                 workWidth = 0;
2652                 if (col > rowSpecs[row].column)
2653                     workWidth = rowSpecs[row].y_adj;
2654
2655                 /*
2656                  * if the heights (and/or width for spanning columns)
2657                  * are different, check to see if the
2658                  * cell contains lines that may be affected by the
2659                  * height adjustment.
2660                  *
2661                  * It is strongly assumed that if a table specifies that
2662                  * a cell can hang over it's neighbors that it will *NOT*
2663                  * have borders (whereby LinesMayChange is false) and
2664                  * newWidth will not be greater than the cell's width.
2665                  */
2666                 if ((newHeight > cellInfo[cell].info.height &&
2667                         True == LinesMayChange(canvas,
2668                                         cellInfo[cell].info.cnt.beg_ln,
2669                                         cellInfo[cell].info.cnt.end_ln,
2670                                         cellInfo[cell].info.cnt.my_lines))
2671                                 ||
2672                         (1 < cellInfo[cell].col_spn &&
2673                                 newWidth > cellInfo[cell].info.width))
2674                     ReFormatCell(canvas, layout, &cellInfo[cell], colSpecs,
2675                                         col, newHeight,
2676                                         layout->info.y_pos + tableYpos);
2677
2678                 else
2679                     /* adjust the cell rather than reformatting */
2680                     AdjustObjectPosition(canvas, layout,
2681                                 TxtVertJustify(cellInfo[cell].cell_seg),
2682                                 cellInfo[cell].info.cnt.beg_txt ,
2683                                 cellInfo[cell].info.cnt.beg_ln  ,
2684                                 cellInfo[cell].info.cnt.beg_brk ,
2685                                 cellInfo[cell].info.cnt.end_txt ,
2686                                 cellInfo[cell].info.cnt.end_ln  ,
2687                                 cellInfo[cell].info.cnt.end_brk ,
2688                                 cellInfo[cell].info.cnt.my_lines,
2689                                 newHeight - cellInfo[cell].info.height,
2690                                 0,
2691                                 tableYpos, workWidth);
2692               }
2693           }
2694       }
2695
2696     /*
2697      * increment the maximum y.
2698      */
2699     layout->info.y_pos += tableYpos;
2700     layout->left        = saveLeft;
2701
2702     if (maxCols > 1)
2703         free(colSpecs);
2704     if (maxRows > 1)
2705         free(rowSpecs);
2706     if (maxRows > 1 || maxCols > 1)
2707         free(cellInfo);
2708
2709     layout->txt_justify = saveTxtJustify;
2710     layout->table_flag  = saveState;
2711
2712     /*
2713      * restore the alignment information
2714      */
2715     layout->info.align_flag = saveAlignFlag;
2716     layout->info.align_char = saveAlignChar;
2717     layout->info.align_pos  = saveAlignPos;
2718 }
2719
2720 /******************************************************************************
2721  * Function: UpdateDimensionArrays
2722  *
2723  * Purpose: Based on the object's orientation and justification,
2724  *          update the correct dimension array(s).
2725  *
2726  *****************************************************************************/
2727 static void
2728 UpdateDimensionArrays(
2729     _DtCvSegmentI *p_seg,
2730     _DtCvUnit    width,
2731     _DtCvUnit    height,
2732     TopDims     *top_bot,
2733     SideDims    *side,
2734     CornerDims  *corner,
2735     FlowDims    *flow,
2736     _DtCvUnit   *max_left,
2737     _DtCvUnit   *max_right)
2738 {
2739     int             i;
2740     int             j;
2741     int            *marginPtr;
2742     _DtCvFrmtOption orient   = ObjHorizOrient(p_seg);
2743     _DtCvFrmtOption vOrient  = ObjVertOrient(p_seg);
2744
2745     /*
2746      * modify the width that headSize should be
2747      */
2748     j = DIMS_LM;
2749     i = DIMS_TOP;
2750     switch (orient)
2751       {
2752         case _DtCvJUSTIFY_RIGHT_MARGIN:
2753                 j++;
2754         case _DtCvJUSTIFY_CENTER:
2755                 j++;
2756         case _DtCvJUSTIFY_LEFT_MARGIN:
2757                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
2758                     i = DIMS_BOTTOM;
2759
2760                 if ((*top_bot)[i][j][DIMS_WIDTH] < width)
2761                     (*top_bot)[i][j][DIMS_WIDTH] = width;
2762
2763                 if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(p_seg))
2764                     (*top_bot)[i][j][DIMS_HEIGHT] += height;
2765                 break;
2766
2767       }
2768
2769     /*
2770      * check left & right margins.
2771      */
2772     marginPtr = max_left;
2773     j = DIMS_LEFT;
2774     i = DIMS_TOP;
2775     switch(orient)
2776       {
2777
2778         case _DtCvJUSTIFY_RIGHT_CORNER:
2779         case _DtCvJUSTIFY_RIGHT:
2780                 j = DIMS_RIGHT;
2781                 marginPtr = max_right;
2782
2783         case _DtCvJUSTIFY_LEFT_CORNER:
2784         case _DtCvJUSTIFY_LEFT:
2785                 if (vOrient != _DtCvJUSTIFY_TOP)
2786                     i++;
2787                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
2788                     i++;
2789
2790                 /*
2791                  * push i to zero or 4
2792                  */
2793                 if (orient == _DtCvJUSTIFY_RIGHT_CORNER ||
2794                                             orient == _DtCvJUSTIFY_LEFT_CORNER)
2795                   {
2796                     if (i) i = DIMS_BC;
2797                     (*corner)[i][j] += height;
2798                     if (*marginPtr < width)
2799                         *marginPtr = width;
2800                   }
2801                 else if (_DtCvContainerFlowOfSeg(p_seg) != _DtCvWRAP)
2802                   {
2803                     (*side)[i][j] += height;
2804                     if (*marginPtr < width)
2805                         *marginPtr = width;
2806                   }
2807                 else
2808                   {
2809                     (*flow)[j][DIMS_HEIGHT] += height;
2810                     if ((*flow)[j][DIMS_WIDTH] < width)
2811                         (*flow)[j][DIMS_WIDTH] = width;
2812                   }
2813                 break;
2814       }
2815 }
2816
2817 /******************************************************************************
2818  * Function: DetermineMaxDims
2819  *
2820  *****************************************************************************/
2821 static void
2822 DetermineMaxDims(
2823     TopDims     *top_bot,
2824     CornerDims  *corner,
2825     _DtCvUnit    left_margin,
2826     _DtCvUnit    right_margin,
2827     _DtCvUnit   *top_height,
2828     _DtCvUnit   *bot_height,
2829     _DtCvUnit   *max_width)
2830 {
2831     register int        j;
2832     _DtCvUnit     topWidth;
2833     _DtCvUnit     botWidth;
2834
2835     /*
2836      * now process all the information gathered about the (sub)headings
2837      * to determine the bounding box for the (head) txt. Start by figuring
2838      * out the maximums for the dimensions.
2839      *
2840      * figure the current top and bottom max widths.
2841      */
2842     topWidth  = left_margin + right_margin;
2843     botWidth  = left_margin + right_margin;
2844     *top_height = 0;
2845     *bot_height = 0;
2846     for (j = DIMS_LM; j <= DIMS_RM; j++)
2847       {
2848         topWidth = topWidth + (*top_bot)[DIMS_TOP]   [j][DIMS_WIDTH];
2849         botWidth = botWidth + (*top_bot)[DIMS_BOTTOM][j][DIMS_WIDTH];
2850
2851         if (*top_height < (*top_bot)[DIMS_TOP][j][DIMS_HEIGHT])
2852             *top_height = (*top_bot)[DIMS_TOP][j][DIMS_HEIGHT];
2853
2854         if (*bot_height < (*top_bot)[DIMS_BOTTOM][j][DIMS_HEIGHT])
2855             *bot_height = (*top_bot)[DIMS_BOTTOM][j][DIMS_HEIGHT];
2856       }
2857
2858     /*
2859      * for the maximum top and bottom heights, take into
2860      * consideration the corner values
2861      */
2862     if (*top_height < (*corner)[DIMS_TC][DIMS_LEFT])
2863         *top_height = (*corner)[DIMS_TC][DIMS_LEFT];
2864     if (*top_height < (*corner)[DIMS_TC][DIMS_RIGHT])
2865         *top_height = (*corner)[DIMS_TC][DIMS_RIGHT];
2866
2867     if (*bot_height < (*corner)[DIMS_BC][DIMS_LEFT])
2868         *bot_height = (*corner)[DIMS_BC][DIMS_LEFT];
2869     if (*bot_height < (*corner)[DIMS_BC][DIMS_RIGHT])
2870         *bot_height = (*corner)[DIMS_BC][DIMS_RIGHT];
2871
2872     *max_width = topWidth;
2873     if (*max_width < botWidth)
2874         *max_width = botWidth;
2875
2876 }
2877
2878 /******************************************************************************
2879  * Function: DetermineFlowConstraints
2880  *
2881  *****************************************************************************/
2882 static void
2883 DetermineFlowConstraints(
2884     LayoutInfo  *layout,
2885     FlowDims     flow_dims,
2886     _DtCvUnit    left_margin,
2887     _DtCvUnit    right_margin,
2888     _DtCvUnit    start_y,
2889     DataPoint   *left_pt,
2890     DataPoint   *right_pt)
2891 {
2892     _DtCvUnit   leftSide  = flow_dims[DIMS_LEFT][DIMS_HEIGHT];
2893     _DtCvUnit   rightSide = flow_dims[DIMS_RIGHT][DIMS_HEIGHT];
2894
2895     /*
2896      * Now, if there is flowing text required, put points on the
2897      * stack to indicate them.
2898      */
2899     left_margin  += flow_dims[DIMS_LEFT][DIMS_WIDTH];
2900     right_margin += flow_dims[DIMS_RIGHT][DIMS_WIDTH];
2901
2902     GetCurrentDataPoint(layout, left_pt);
2903     GetCurrentDataPoint(layout, right_pt);
2904     left_pt->left   += left_margin;
2905     left_pt->right  += right_margin;
2906     left_pt->y_pos   = _CEFORMAT_ALL;
2907     right_pt->left  += left_margin;
2908     right_pt->right += right_margin;
2909     right_pt->y_pos  = _CEFORMAT_ALL;
2910
2911     while (leftSide > 0 || rightSide > 0)
2912       {
2913         if (leftSide > 0)
2914           {
2915             if (rightSide == 0 || leftSide <= rightSide)
2916               {
2917                 left_pt->right = right_margin;
2918                 left_pt->y_pos = start_y + leftSide;
2919                 if (leftSide != rightSide)
2920                     left_margin = 0;
2921                 leftSide = 0;
2922                 InsertDataPoint(layout, left_pt);
2923               }
2924           }
2925
2926         if (rightSide > 0)
2927           {
2928             if (leftSide == 0 || leftSide > rightSide)
2929               {
2930                 right_pt->left  = left_margin;
2931                 right_pt->y_pos = start_y + rightSide;
2932                 if (leftSide != rightSide)
2933                     right_margin = 0;
2934                 rightSide = 0;
2935                 InsertDataPoint(layout, right_pt);
2936               }
2937           }
2938       }
2939 }
2940
2941 /******************************************************************************
2942  * Function: DetermineHeadPositioning
2943  *
2944  *****************************************************************************/
2945 static void
2946 DetermineHeadPositioning(
2947     TopDims     *top_bot,
2948     SideDims    *side,
2949     CornerDims  *corner,
2950     FlowDims    *flow,
2951     _DtCvUnit    start_y,
2952     _DtCvUnit    max_top,
2953     _DtCvUnit    block_size,
2954     _DtCvUnit   *ret_side_size)
2955 {
2956     int    i;
2957     _DtCvUnit   leftSideHeight  = 0;
2958     _DtCvUnit   rightSideHeight = 0;
2959     _DtCvUnit   sideHeight      = 0;
2960
2961     /*
2962      * determine the maximum side heights
2963      */
2964     for (i = DIMS_TOP; i <= DIMS_BOTTOM; i++)
2965       {
2966         leftSideHeight  += (*side)[i][DIMS_LEFT];
2967         rightSideHeight += (*side)[i][DIMS_RIGHT];
2968       }
2969
2970     /*
2971      * determine the maximum side height
2972      */
2973     sideHeight = block_size;
2974     if (sideHeight < leftSideHeight)
2975         sideHeight = leftSideHeight;
2976     if (sideHeight < rightSideHeight)
2977         sideHeight = rightSideHeight;
2978     if (sideHeight < (*flow)[DIMS_LEFT][DIMS_HEIGHT])
2979         sideHeight  = (*flow)[DIMS_LEFT][DIMS_HEIGHT];
2980     if (sideHeight < (*flow)[DIMS_RIGHT][DIMS_HEIGHT])
2981         sideHeight = (*flow)[DIMS_RIGHT][DIMS_HEIGHT];
2982
2983     /*
2984      * calculate the starting Y position for each of the positions
2985      * reuse the arrays that were used to save the max dimension values.
2986      */
2987     for (i = DIMS_LM; i <= DIMS_RM; i++)
2988       {
2989         (*top_bot)[DIMS_TOP]   [i][DIMS_YPOS] = start_y;
2990         (*top_bot)[DIMS_BOTTOM][i][DIMS_YPOS] = start_y + max_top + sideHeight;
2991       }
2992
2993     (*corner)[DIMS_TC][DIMS_LEFT]  = start_y;
2994     (*corner)[DIMS_TC][DIMS_RIGHT] = start_y;
2995
2996     (*corner)[DIMS_BC][DIMS_LEFT]  = start_y + max_top + sideHeight;
2997     (*corner)[DIMS_BC][DIMS_RIGHT] = start_y + max_top + sideHeight;
2998
2999     (*side)[DIMS_TOP][DIMS_LEFT]  = start_y + max_top;
3000     (*side)[DIMS_TOP][DIMS_RIGHT] = start_y + max_top;
3001
3002     (*flow)[DIMS_LEFT ][DIMS_YPOS] = start_y + max_top;
3003     (*flow)[DIMS_RIGHT][DIMS_YPOS] = start_y + max_top;
3004
3005     (*side)[DIMS_CENTER][DIMS_LEFT]  = start_y + max_top +
3006                         (sideHeight - (*side)[DIMS_CENTER][DIMS_LEFT]) / 2;
3007     (*side)[DIMS_CENTER][DIMS_RIGHT] = start_y + max_top +
3008                         (sideHeight - (*side)[DIMS_CENTER][DIMS_RIGHT]) / 2;
3009
3010     (*side)[DIMS_BOTTOM][DIMS_LEFT]  = start_y + max_top +
3011                         sideHeight - (*side)[DIMS_BOTTOM][DIMS_LEFT];
3012     (*side)[DIMS_BOTTOM][DIMS_RIGHT] = start_y + max_top +
3013                         sideHeight - (*side)[DIMS_BOTTOM][DIMS_RIGHT];
3014
3015     if (ret_side_size != NULL)
3016         *ret_side_size = sideHeight;
3017 }
3018
3019 /******************************************************************************
3020  * Function: AdjustHead
3021  *
3022  * Parameters:
3023  *              base_left       Specifies the x position that the controller
3024  *                              occupying 'left_margin' space would start
3025  *                              at.
3026  *              block_width     Specifies the body's width for which to
3027  *                              center or align a controller with.
3028  *              left_margin     Specifies the space used by a controller
3029  *                              that is on the left side of the body.
3030  *              right_margin    Specifies the space used by a controller
3031  *                              on the right side of the body.
3032  *
3033  *****************************************************************************/
3034 static void
3035 AdjustHeadPosition(
3036     _DtCanvasStruct     *canvas,
3037     LayoutInfo          *layout,
3038     _DtCvSegmentI       *p_seg,
3039     TopDims             *top_bot,
3040     SideDims            *side,
3041     CornerDims          *corner,
3042     FlowDims            *flow,
3043     LayFrmtInfo         *info,
3044     _DtCvUnit            base_y,
3045     _DtCvUnit            base_left,
3046     _DtCvUnit            block_width,
3047     _DtCvUnit            left_margin,
3048     _DtCvUnit            right_margin)
3049 {
3050     int           i         = DIMS_TOP;         /* also DIMS_TC */
3051     int           j         = DIMS_LEFT;        /* also DIMS_LM */
3052     int           divisor   = 2;
3053     _DtCvUnit     adjustX   = 0;
3054     _DtCvUnit     adjustY   = 0;
3055     _DtCvUnit     newY      = 0;
3056     _DtCvUnit     headWidth = info->width;
3057     _DtCvFrmtOption  orient    = ObjHorizOrient(p_seg);
3058     _DtCvFrmtOption  vOrient   = ObjVertOrient(p_seg);
3059
3060     if (_DtCvContainerPercentOfSeg(p_seg) == 10000
3061                         && orient == _DtCvJUSTIFY_CENTER
3062                         && TxtHorizJustify(p_seg) == _DtCvJUSTIFY_LEFT)
3063         headWidth = block_width;
3064
3065     switch (orient)
3066       {
3067         case _DtCvJUSTIFY_RIGHT_MARGIN:
3068                 divisor = 1;
3069                 j++;
3070         case _DtCvJUSTIFY_CENTER:
3071                 adjustX = (block_width - headWidth) / divisor;
3072                 j++;
3073         case _DtCvJUSTIFY_LEFT_MARGIN:
3074                 adjustX += left_margin;
3075                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
3076                     i = DIMS_BOTTOM;
3077
3078                 newY  = (*top_bot)[i][j][DIMS_YPOS];
3079                 (*top_bot)[i][j][DIMS_YPOS] += info->height;
3080                 break;
3081
3082         case _DtCvJUSTIFY_RIGHT_CORNER:
3083                 adjustX = block_width + left_margin;
3084                 j       = DIMS_RIGHT;
3085
3086         case _DtCvJUSTIFY_LEFT_CORNER:
3087                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
3088                     i = DIMS_BC;
3089
3090                 newY = (*corner)[i][j];
3091                 (*corner)[i][j] += info->height;
3092                 break;
3093
3094         case _DtCvJUSTIFY_RIGHT:
3095                 adjustX = block_width + left_margin;
3096                 j = DIMS_RIGHT;
3097
3098         case _DtCvJUSTIFY_LEFT:
3099                 if (vOrient != _DtCvJUSTIFY_TOP)
3100                     i++;
3101                 if (vOrient == _DtCvJUSTIFY_BOTTOM)
3102                     i++;
3103
3104                 if (_DtCvContainerFlowOfSeg(p_seg) == _DtCvWRAP)
3105                   {
3106                     if (orient == _DtCvJUSTIFY_LEFT)
3107                         adjustX += left_margin;
3108                     else
3109                         adjustX -= headWidth;
3110
3111                     newY = (*flow)[j][DIMS_YPOS];
3112                     (*flow)[j][DIMS_YPOS] += info->height;
3113                   }
3114                 else
3115                   {
3116                     newY = (*side)[i][j];
3117                     (*side)[i][j] += info->height;
3118                   }
3119                 break;
3120       }
3121
3122     adjustY  = newY - base_y;
3123     adjustX += base_left;
3124
3125     /*
3126      * adjust the text positions
3127      */
3128     AdjustTextPositions(canvas, info->cnt.beg_txt, info->cnt.end_txt,
3129                                                                 adjustX, adjustY);
3130
3131     /*
3132      * adjust the lines positions
3133      */
3134     AdjustLinePositions(canvas, info->cnt.beg_ln, info->cnt.end_ln,
3135                                                                 adjustX, adjustY);
3136
3137     /*
3138      * adjust the page breaks, but only if necessary.
3139      */
3140     AdjustPgBrk(canvas, info->cnt.beg_brk, info->cnt.end_brk, adjustY);
3141 }
3142
3143 /******************************************************************************
3144  * Function: InitDimArrays
3145  *
3146  *****************************************************************************/
3147 static void
3148 InitDimArrays(
3149     TopDims             *top_bot,
3150     SideDims            *side,
3151     CornerDims          *corner,
3152     FlowDims            *flow)
3153 {
3154     int             i;
3155     int             j;
3156
3157     for (i = DIMS_TOP; i <= DIMS_BOTTOM; i++)
3158       {
3159         for (j = DIMS_LM; j <= DIMS_RM; j++)
3160           {
3161             (*top_bot)[i][j][DIMS_WIDTH] = 0;
3162             (*top_bot)[i][j][DIMS_HEIGHT] = 0;
3163           }
3164         for (j = DIMS_LEFT; j <= DIMS_RIGHT; j++)
3165             (*side)[i][j] = 0;
3166       }
3167     for (i = DIMS_LEFT; i <= DIMS_RIGHT; i++)
3168       {
3169         for (j = DIMS_WIDTH; j <= DIMS_HEIGHT; j++)
3170          {
3171             (*corner)[i][j] = 0;
3172             (*flow)[i][j]   = 0;
3173          }
3174       }
3175 }
3176
3177 /******************************************************************************
3178  * Function: ProcessController
3179  *****************************************************************************/
3180 static LayFrmtInfo *
3181 ProcessController(
3182     _DtCanvasStruct     *canvas,
3183     LayoutInfo          *layout,
3184     _DtCvSegmentI       *cur_seg)
3185 {
3186     int            getLn;
3187     int            saveTravCnt  = canvas->trav_cnt;
3188     _DtCvUnit      saveYPos     = layout->info.y_pos;
3189     _DtCvUnit      saveMaxWidth = layout->max_width;
3190     _DtCvUnit      saveY        = layout->info.y_pos;
3191     _DtCvUnit      saveLeft     = layout->left;
3192     _DtCvUnit      saveRight    = layout->right;
3193     _DtCvUnit      maxWidth;
3194     _DtCvUnit      maxXPos;
3195     _DtCvUnit      myMaxWidth;
3196     LayFrmtInfo   *frmtInfo;
3197     DataPoint      basePt;
3198     DataPoint      zeroPt;
3199     _DtCvValue     redo;
3200
3201     /*
3202      * Controllers always break the formatting sequence.
3203      * So save any information in the buffer, reset the margins and
3204      * add the appropriate lines, and check for going over boundaries.
3205      */
3206     CheckSaveInfo(canvas, layout, cur_seg, 0);
3207     CheckFormat(layout, True);
3208
3209     /*
3210      * Get the controller specific information.
3211      * disallow some of the orientation & vOrient combinations
3212      */
3213     if ((ObjHorizOrient(cur_seg) == _DtCvJUSTIFY_CENTER
3214                         && ObjVertOrient(cur_seg) != _DtCvJUSTIFY_BOTTOM)
3215                 ||
3216         (ObjVertOrient(cur_seg) == _DtCvJUSTIFY_CENTER
3217                         && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT
3218                         && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_RIGHT))
3219         ObjVertOrient(cur_seg) = _DtCvJUSTIFY_TOP;
3220
3221     if (_DtCvContainerFlowOfSeg(cur_seg) == _DtCvWRAP
3222                         &&
3223             (ObjVertOrient(cur_seg) != _DtCvJUSTIFY_TOP
3224                                 ||
3225                 (ObjVertOrient(cur_seg) == _DtCvJUSTIFY_TOP
3226                         && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT
3227                         && ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_RIGHT)))
3228         _DtCvContainerFlowOfSeg(cur_seg) = _DtCvWRAP_NONE;
3229
3230     if (_DtCvContainerFlowOfSeg(cur_seg) == _DtCvWRAP_JOIN
3231                         &&
3232             (ObjVertOrient(cur_seg) != _DtCvJUSTIFY_TOP
3233                 || ObjHorizOrient(cur_seg) != _DtCvJUSTIFY_LEFT_MARGIN))
3234       {
3235         ObjVertOrient(cur_seg)  = _DtCvJUSTIFY_TOP;
3236         ObjHorizOrient(cur_seg) = _DtCvJUSTIFY_LEFT_MARGIN;
3237       }
3238     
3239     /*
3240      * malloc a formatting dimension structure and initialize it with
3241      * default values. This will be returned to the caller.
3242      */
3243     frmtInfo  = (LayFrmtInfo *) malloc (sizeof(LayFrmtInfo));
3244     *frmtInfo = DefLayFrmtInfo;
3245
3246     /*
3247      * the controller object begins here.
3248      */
3249     SetBeginCounts(canvas, &(frmtInfo->cnt));
3250
3251     /*
3252      * set the parent's data point in the stack
3253      */
3254     GetCurrentDataPoint(layout, &basePt);
3255
3256     /*
3257      * calculate the amount of space the controller can occupy.
3258      * first calculate the amount of space to work with.
3259      * then truncate to zero if necessary.
3260      * then use the percentage of that remaining area as the space
3261      *      the controller's segments can occupy.
3262      */
3263     myMaxWidth = layout->max_width - basePt.left - basePt.right
3264                                                         - saveLeft - saveRight;
3265     if (myMaxWidth < 0)
3266         myMaxWidth = 0;
3267
3268     myMaxWidth = (_DtCvUnit) (((double) myMaxWidth)
3269                         * ((double) _DtCvContainerPercentOfSeg(cur_seg))
3270                         / HeadDivisor);
3271
3272
3273     /*
3274      * Format the controller at a 'zero'ed point.
3275      * The lines it generates will be moved later to their correct position.
3276      */
3277     layout->left  = 0;
3278     layout->right = 0;
3279     zeroPt = DefDataPt;
3280     PushDataPoint(layout, &zeroPt);
3281
3282     /*
3283      * now process as a regular container
3284      */
3285     do {
3286         /*
3287          * set some counts and flags (necessary for a redo).
3288          */
3289         redo = False;
3290         canvas->trav_cnt    = saveTravCnt;
3291         canvas->line_cnt    = frmtInfo->cnt.beg_ln;
3292         canvas->txt_cnt     = frmtInfo->cnt.beg_txt;
3293         layout->max_width   = myMaxWidth;
3294         layout->info.y_pos  = 0;
3295
3296         /*
3297          * process the container
3298          */
3299         ProcessContainer(canvas,layout,cur_seg,-1,&maxWidth,&maxXPos,&getLn);
3300
3301         /*
3302          * check to see if we need to reformat because the minimum size
3303          * is larger than we asked for.
3304          */
3305         if (maxXPos + _DtCvContainerRMarginOfSeg(cur_seg) > myMaxWidth)
3306           {
3307             redo       = True;
3308             myMaxWidth = maxXPos + _DtCvContainerRMarginOfSeg(cur_seg);
3309           }
3310       } while (True == redo);
3311     
3312     /*
3313      * remove this element's data points from the stack.
3314      */
3315     RemoveDataPoint(layout, &zeroPt);
3316
3317     /*
3318      * set the ending counts for the items in this container.
3319      */
3320     SetEndCounts(canvas, &(frmtInfo->cnt), getLn);
3321     frmtInfo->width  = myMaxWidth;
3322     frmtInfo->height = layout->info.y_pos;
3323
3324     /*
3325      * does this controller want to join with the lines in a non-controller?
3326      */
3327     if (_DtCvWRAP_JOIN == _DtCvContainerFlowOfSeg(cur_seg)
3328                                 && frmtInfo->cnt.beg_txt != canvas->txt_cnt)
3329         _DtCvSetJoinInfo(&(layout->info), True, canvas->txt_cnt - 1);
3330
3331     /*
3332      * Restore the previous information
3333      */
3334     if (NULL != layout->lst_rendered)
3335         layout->lst_rendered->next_disp = NULL;
3336
3337     layout->left           = saveLeft;
3338     layout->right          = saveRight;
3339     layout->max_width      = saveMaxWidth;
3340     layout->lst_rendered   = NULL;
3341     layout->info.y_pos     = saveYPos;
3342
3343     return frmtInfo;
3344 }
3345
3346 /******************************************************************************
3347  * Function: AdjustForBorders
3348  *
3349  * Initializes the display line and graphic tables.
3350  *****************************************************************************/
3351 static void
3352 AdjustForBorders(
3353     _DtCanvasStruct     *canvas,
3354     LayoutInfo          *layout,
3355     _DtCvFrmtOption      brdr,
3356     _DtCvUnit            line_width,
3357     _DtCvUnit           *ret_bot,
3358     _DtCvUnit           *ret_right)
3359 {
3360     /*
3361      * if the line_width is zero, make it 1 so that is really takes
3362      * up some space.
3363      */
3364     if (0 == line_width)
3365         line_width = 1;
3366
3367     /*
3368      * set the flag for processing a border
3369      */
3370     if (_DtCvBORDER_NONE != brdr)
3371         layout->brdr_flag = True;
3372
3373     /*
3374      * check to see if this element has a border. If so, adjust the
3375      * boundaries.
3376      */
3377     if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_HORZ
3378                                  || brdr == _DtCvBORDER_TOP
3379                                  || brdr == _DtCvBORDER_TOP_LEFT
3380                                  || brdr == _DtCvBORDER_TOP_RIGHT)
3381         layout->info.y_pos += line_width;
3382
3383     *ret_bot = 0;
3384     if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_HORZ
3385                                  || brdr == _DtCvBORDER_BOTTOM
3386                                  || brdr == _DtCvBORDER_BOTTOM_LEFT
3387                                  || brdr == _DtCvBORDER_BOTTOM_RIGHT)
3388         *ret_bot = line_width;
3389
3390     if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_VERT
3391                                  || brdr == _DtCvBORDER_LEFT
3392                                  || brdr == _DtCvBORDER_TOP_LEFT
3393                                  || brdr == _DtCvBORDER_BOTTOM_LEFT)
3394         layout->left += line_width;
3395
3396     *ret_right = 0;
3397     if (brdr == _DtCvBORDER_FULL || brdr == _DtCvBORDER_VERT
3398                                  || brdr == _DtCvBORDER_RIGHT
3399                                  || brdr == _DtCvBORDER_TOP_RIGHT
3400                                  || brdr == _DtCvBORDER_BOTTOM_RIGHT)
3401       {
3402         layout->right += line_width;
3403         *ret_right     = line_width;
3404       }
3405 }
3406
3407 /******************************************************************************
3408  * Function: DrawBorders
3409  *
3410  * Parameters:
3411  *              canvas          Specifies the virtual canvas on which
3412  *                              lines are drawn.
3413  *              layout          Specifies the current layout information.
3414  *              brdr            Specifies the type of border.
3415  *              top_y           Specifes the top y of the bounding box for
3416  *                              the object. Any border drawn should be
3417  *                              completely below this y.
3418  *              bot_y           Specifes the bottom y of the bounding box
3419  *                              for the object. Any border drawn should be
3420  *                              completely below this y.
3421  *              left_x          Specifies the left x of the bounding box
3422  *                              for the object. Any border drawn should be
3423  *                              completely to the right of this x.
3424  *              right_x         Specifies the right x of the bounding box
3425  *                              for the object. Any border drawn should be
3426  *                              completely to the left of this x.
3427  *
3428  *          left_x               right_x
3429  *            |                     |
3430  *            v                     v
3431  * top_y ---> xxxxxxxxxxxxxxxxxxxxxx
3432  *            xxxxxxxxxxxxxxxxxxxxxx
3433  *            xx------------------xx
3434  *            xx|                |xx  (xx represents the line.)
3435  *            xx|                |xx
3436  *            xx|                |xx
3437  *            xx|                |xx
3438  *            xx------------------xx
3439  * bot_y ---> xxxxxxxxxxxxxxxxxxxxxx
3440  *            xxxxxxxxxxxxxxxxxxxxxx
3441  *
3442  *****************************************************************************/
3443 static int
3444 DrawBorders(
3445     _DtCanvasStruct     *canvas,
3446     LayoutInfo          *layout,
3447     _DtCvFrmtOption      brdr,
3448     _DtCvPointer         data,
3449     _DtCvUnit            line_width,
3450     _DtCvUnit            top_y,
3451     _DtCvUnit            bot_y,
3452     _DtCvUnit            left_x,
3453     _DtCvUnit            right_x)
3454 {
3455     int         mod       = 1;
3456     int         cnt       = canvas->line_cnt;
3457     _DtCvUnit   width;
3458
3459     /*
3460      * if line_width is zero, make it 1 so that it really takes
3461      * up some space.
3462      */
3463     if (0 == line_width)
3464         line_width = 1;
3465
3466     /*
3467      * calculate the width of the element.
3468      */
3469     width = right_x - left_x;
3470
3471     /*
3472      * If borders are specified, draw them
3473      */
3474     if (brdr != _DtCvBORDER_NONE)
3475       {
3476         /*
3477          * now do the horizontal borders. the coordinates are the top,
3478          * left most unit of the line.
3479          */
3480         switch(brdr)
3481           {
3482             case _DtCvBORDER_FULL:
3483             case _DtCvBORDER_HORZ:
3484             case _DtCvBORDER_BOTTOM:
3485             case _DtCvBORDER_BOTTOM_LEFT:
3486             case _DtCvBORDER_BOTTOM_RIGHT:
3487                         SaveLine(canvas, layout, _DtCvLINE_HORZ,
3488                                                 data, line_width,
3489                                                 left_x, bot_y, width);
3490                         mod = -1;
3491                         if (brdr == _DtCvBORDER_BOTTOM
3492                                         || brdr == _DtCvBORDER_BOTTOM_LEFT
3493                                         || brdr == _DtCvBORDER_BOTTOM_RIGHT)
3494                             break;
3495     
3496             case _DtCvBORDER_TOP:
3497             case _DtCvBORDER_TOP_LEFT:
3498             case _DtCvBORDER_TOP_RIGHT:
3499                         SaveLine(canvas, layout, _DtCvLINE_HORZ,
3500                                                 data, line_width,
3501                                                 left_x, top_y, width);
3502           }
3503     
3504         /*
3505          * for vertical lines, the coordinates are the top, right most
3506          * unit of the line.
3507          */
3508         switch(brdr)
3509           {
3510             case _DtCvBORDER_FULL:
3511             case _DtCvBORDER_BOTTOM_LEFT:
3512                         /*
3513                          * include the line width in length for a full
3514                          * border.
3515                          */
3516                         bot_y += line_width;
3517
3518             case _DtCvBORDER_VERT:
3519             case _DtCvBORDER_LEFT:
3520             case _DtCvBORDER_TOP_LEFT:
3521                         SaveLine(canvas, layout, _DtCvLINE_VERT,
3522                                                 data, line_width,
3523                                                 left_x, top_y, bot_y - top_y);
3524                         if (brdr == _DtCvBORDER_LEFT
3525                                         || brdr == _DtCvBORDER_TOP_LEFT
3526                                         || brdr == _DtCvBORDER_BOTTOM_LEFT)
3527                             break;
3528     
3529             case _DtCvBORDER_BOTTOM_RIGHT:
3530                         /*
3531                          * if we didn't fall thru from above, we need to
3532                          * add the extension to the bottom to get the
3533                          * full length for the right vertical line.
3534                          */
3535                         if (brdr == _DtCvBORDER_BOTTOM_RIGHT)
3536                             bot_y += line_width;
3537
3538             case _DtCvBORDER_RIGHT:
3539             case _DtCvBORDER_TOP_RIGHT:
3540                         SaveLine(canvas, layout, _DtCvLINE_VERT,
3541                                                 data, line_width,
3542                                 right_x - line_width, top_y, bot_y - top_y);
3543           }
3544       }
3545
3546     return ((canvas->line_cnt - cnt) * mod);
3547 }
3548
3549 /******************************************************************************
3550  * Function: AdjustObjectPosition
3551  *
3552  * Parameters:
3553  *              canvas          Specifies the virtual canvas on which
3554  *                              lines are drawn.
3555  *              justify         Specifies the vertical adjustment for the
3556  *                              object.
3557  *              start_txt       Specifies the start index of the text list.
3558  *              start_gr        Specifies the start index of the graphics list.
3559  *              start_ln        Specifies the start index of the line list.
3560  *              end_txt         Specifies the end indext of the text list.
3561  *              end_gr          Specifies the end indext of the graphics list.
3562  *              end_ln          Specifies the end indext of the line list.
3563  *              height_adj      Specifies the internal height adjust value.
3564  *                              Depending on the justify type, this may
3565  *                              add to y_adj for text and regions, bottom
3566  *                              lines and the height of vertical lines.
3567  *              y_adj           Specifies the y position adjustment.
3568  *                              Lines, text and regions are moved this
3569  *                              amount.
3570  *              internal_y      Specifies the internal y position adjustment.
3571  *                              height_adj includes this value. Text and
3572  *                              regions are moved this amount.
3573  *
3574  * Return:      nothing.
3575  *
3576  *****************************************************************************/
3577 static void
3578 AdjustObjectPosition(
3579     _DtCanvasStruct     *canvas,
3580     LayoutInfo          *layout,
3581     _DtCvFrmtOption      justify,
3582     int                  start_txt,
3583     int                  start_ln,
3584     int                  start_brk,
3585     int                  end_txt,
3586     int                  end_ln,
3587     int                  end_brk,
3588     int                  brdr_cnt,
3589     _DtCvUnit            height_adj,
3590     _DtCvUnit            x_adj,
3591     _DtCvUnit            y_adj,
3592     _DtCvUnit            internal_y)
3593 {
3594     int   mod  = 1;
3595     _DtCvUnit  yOff = 0;
3596
3597     /*
3598      * If border count is negative, indicates the first line in the
3599      * list is bottom line. This requires special handling in adjusting
3600      * its position. Set flags accordingly.
3601      */
3602     if (brdr_cnt < 0)
3603       {
3604         mod = -1;
3605         brdr_cnt = -brdr_cnt;
3606       }
3607
3608     /*
3609      * calculate the offset value within the object for other objects
3610      * contained in this object.
3611      */
3612     if (justify != _DtCvJUSTIFY_TOP)
3613       {
3614         yOff = height_adj - internal_y;
3615         if (justify == _DtCvJUSTIFY_CENTER)
3616             yOff /= 2;
3617       }
3618     
3619     yOff += y_adj;
3620     yOff += internal_y;
3621
3622     /*
3623      * don't modify the border lines around this object yet.
3624      */
3625     end_ln -= brdr_cnt;
3626
3627     /*
3628      * modify the border lines of the objects contained within
3629      * this object.
3630      */
3631     AdjustLinePositions(canvas, start_ln, end_ln, x_adj, yOff);
3632
3633     /*
3634      * now adjust the border lines around this object.
3635      */
3636     start_ln = end_ln;
3637     end_ln += brdr_cnt;
3638     AdjustLinePositions(canvas, start_ln, end_ln, x_adj, y_adj);
3639
3640     /*
3641      * now fix the lines if they've changed height and move
3642      * the first line to its bottom position if necessary.
3643      */
3644     if (0 != height_adj)
3645       {
3646         while (start_ln < end_ln)
3647           {
3648             /*
3649              * indicates the bottom line is the first line in the
3650              * list. Move it down the height adjustment.
3651              */
3652             if (mod < 0)
3653               {
3654                 canvas->line_lst[start_ln].pos_y += height_adj;
3655                 canvas->line_lst[start_ln].max_y += height_adj;
3656
3657                 mod = 1;
3658               }
3659             /*
3660              * stretch the vertical lines
3661              */
3662             else if (canvas->line_lst[start_ln].dir == _DtCvLINE_VERT)
3663                 canvas->line_lst[start_ln].max_y += height_adj;
3664
3665             start_ln++;
3666           }
3667       }
3668
3669     /*
3670      * adjust the position of the text within this object.
3671      */
3672     AdjustTextPositions (canvas, start_txt, end_txt, x_adj, yOff);
3673
3674     /*
3675      * adjust the position of the text within this object.
3676      */
3677     AdjustPgBrk (canvas, start_brk, end_brk, yOff);
3678 }
3679
3680 /******************************************************************************
3681  * Function: LinesMayChange
3682  *
3683  * Parameters:
3684  *              canvas          Specifies the virtual canvas on which
3685  *                              lines are drawn.
3686  *              start_ln        Specifies the start index of the line list.
3687  *              end_ln          Specifies the end indext of the line list.
3688  *
3689  * Return:      True    if there is a vertical line as a child of a container.
3690  *              False   if there are no vertical lines in the child of a
3691  *                      container/cell.
3692  *
3693  *****************************************************************************/
3694 static _DtCvValue
3695 LinesMayChange(
3696     _DtCanvasStruct     *canvas,
3697     int                  start_ln,
3698     int                  end_ln,
3699     int                  brdr_cnt)
3700 {
3701     /*
3702      * If border count is negative, indicates that one of the lines
3703      * is for the bottom of the container/cell. Ignore for now.
3704      * we want to check the lines in the container/cell.
3705      */
3706     if (brdr_cnt < 0)
3707         brdr_cnt = -brdr_cnt;
3708
3709     /*
3710      * get rid of the line count for this object,
3711      * AdjustObjectPosition can take care of it.
3712      */
3713     end_ln -= brdr_cnt;
3714
3715     /*
3716      * Now check for vertical lines that would
3717      * be affected by a height change.
3718      */
3719     while (start_ln < end_ln)
3720       {
3721         if (_DtCvLINE_VERT == canvas->line_lst[start_ln].dir)
3722             return True;
3723         start_ln++;
3724       }
3725
3726     return False;
3727 }
3728
3729 /******************************************************************************
3730  * Function: ProcessContainer
3731  *
3732  * Initializes the display line and graphic tables.
3733  *****************************************************************************/
3734 static void
3735 ProcessContainer(
3736     _DtCanvasStruct     *canvas,
3737     LayoutInfo          *layout,
3738     _DtCvSegmentI       *con_seg,
3739     _DtCvUnit            min_y,
3740     _DtCvUnit           *ret_width,
3741     _DtCvUnit           *ret_max_x,
3742     int                 *ret_cnt)
3743 {
3744     int            getLn;
3745     int            saveTravCnt  = canvas->trav_cnt;
3746     int            saveLnCnt    = canvas->line_cnt;
3747     int            saveTxtCnt   = canvas->txt_cnt;
3748     int            joinLine     = layout->info.join_line;
3749     const char    *saveJustifyChar = layout->info.align_char;
3750     _DtCvUnit      yPad         = 0;
3751     _DtCvUnit      xPad         = 0;
3752     _DtCvUnit      maxWidth     = 0;
3753     _DtCvUnit      maxXPos      = 0;
3754     _DtCvUnit      myMinY       = -1;
3755     _DtCvUnit      saveLeft     = layout->left;
3756     _DtCvUnit      saveRight    = layout->right;
3757     _DtCvUnit      saveLead     = layout->info.leading;
3758     _DtCvUnit      saveFirst    = layout->first;
3759     _DtCvUnit      saveYpos     = layout->info.y_pos;
3760     _DtCvValue     saveStatic   = layout->stat_flag;
3761     _DtCvValue     botBrdr      = False;
3762     _DtCvValue     rightBrdr    = False;
3763     _DtCvValue     joinFlag     = layout->info.join;
3764     _DtCvValue     saveBrdr     = layout->brdr_flag;
3765     _DtCvFrmtOption   saveJustify  = layout->txt_justify;
3766     LayFrmtInfo    frmtInfo;
3767     DataPoint      basePt;
3768     DataPoint      curPt;
3769
3770     /*
3771      * check to see if this element breaks the formatting sequence.
3772      * If so save any information in the buffer, reset the margins and
3773      * add the appropriate lines, and check for going over boundaries.
3774      */
3775     if (NotJoining(layout))
3776       {
3777         CheckSaveInfo(canvas, layout, con_seg, 0);
3778         CheckFormat(layout, True);
3779       }
3780
3781     /*
3782      * check to see if this segment is the segment we want as our first
3783      * visible line.
3784      */
3785     CheckId(layout, _DtCvContainerIdOfSeg(con_seg));
3786
3787     /*
3788      * Set beginning text and line counts
3789      */
3790     frmtInfo = DefLayFrmtInfo;
3791     SetBeginCounts(canvas, &(frmtInfo.cnt));
3792
3793     /*
3794      * Get the first indent and set the current container pointer to me.
3795      */
3796     layout->first = _DtCvContainerFMarginOfSeg(con_seg) / layout->divisor;
3797     layout->left  = _DtCvContainerLMarginOfSeg(con_seg) / layout->divisor;
3798     layout->right = _DtCvContainerRMarginOfSeg(con_seg) / layout->divisor;
3799     layout->info.leading = _DtCvContainerLeadingOfSeg(con_seg);
3800
3801     /*
3802      * check to see if we violate the horiz_pad_hint on the left, right or
3803      * first margins.
3804      */
3805     if (canvas->metrics.horiz_pad_hint > _DtCvContainerLMarginOfSeg(con_seg))
3806         layout->left = _DtCvContainerLMarginOfSeg(con_seg);
3807     else if (layout->left < canvas->metrics.horiz_pad_hint)
3808         layout->left = canvas->metrics.horiz_pad_hint;
3809
3810     if (canvas->metrics.horiz_pad_hint > _DtCvContainerRMarginOfSeg(con_seg))
3811         layout->right = _DtCvContainerRMarginOfSeg(con_seg);
3812     else if (layout->right < canvas->metrics.horiz_pad_hint)
3813         layout->right = canvas->metrics.horiz_pad_hint;
3814
3815     if (canvas->metrics.horiz_pad_hint > _DtCvContainerFMarginOfSeg(con_seg))
3816         layout->first = _DtCvContainerFMarginOfSeg(con_seg);
3817     else if (layout->first < canvas->metrics.horiz_pad_hint)
3818         layout->first = canvas->metrics.horiz_pad_hint;
3819
3820     /*
3821      * check to see if there is more squeeze room available.
3822      */
3823     if (layout->left > canvas->metrics.horiz_pad_hint
3824                         || layout->right > canvas->metrics.horiz_pad_hint
3825                         || layout->first > canvas->metrics.horiz_pad_hint)
3826         layout->margin_non_zero = True;
3827
3828     /*
3829      * set the formatting type for this container
3830      */
3831     layout->stat_flag = False;
3832     if (_DtCvContainerTypeOfSeg(con_seg) == _DtCvLITERAL)
3833         layout->stat_flag = True;
3834
3835     /*
3836      * check to see if this element breaks the formatting sequence.
3837      * If so, add lines, etc.
3838      */
3839     if (NotJoining(layout))
3840       {
3841         /*
3842          * Adjust margins and y position for bordering
3843          */
3844         AdjustForBorders (canvas, layout, Border(con_seg), BrdWidth(con_seg),
3845                                                                 &yPad, &xPad);
3846
3847         _DtCvAddSpace(_DtCvContainerTMarginOfSeg(con_seg),
3848                                                         &(layout->info.y_pos));
3849         /*
3850          * check for flow limits.
3851          */
3852         CheckFormat(layout, True);
3853
3854         /*
3855          * get the parent's data point in the stack
3856          * and add the current container's left and right to it.
3857          */
3858         GetCurrentDataPoint(layout, &basePt);
3859         basePt.left  += saveLeft;
3860         basePt.right += saveRight;
3861
3862         /*
3863          * if we don't inherit the the text justification
3864          * set the new value.
3865          */
3866         if (_DtCvINHERIT != _DtCvContainerJustifyOfSeg(con_seg))
3867           {
3868             layout->txt_justify  = _DtCvContainerJustifyOfSeg(con_seg);
3869             if (_DtCvJUSTIFY_NUM == layout->txt_justify)
3870                 layout->info.align_char = PeriodStr;
3871             else if (_DtCvJUSTIFY_CHAR == layout->txt_justify)
3872               {
3873                 layout->info.align_char = _DtCvContainerJustifyCharOfSeg(con_seg);
3874                 /*
3875                  * check to see if the character is 'valid'.
3876                  * if not, default out of JUSTIFY_CHAR
3877                  */
3878                 if (NULL != layout->info.align_char ||
3879                                         '\0' == layout->info.align_char)
3880                     layout->txt_justify = _DtCvJUSTIFY_LEFT;
3881               }
3882           }
3883
3884         /*
3885          * terminate the previous rendering list
3886          */
3887         if (NULL != layout->lst_rendered)
3888             layout->lst_rendered->next_disp = NULL;
3889         layout->lst_rendered = NULL;
3890
3891         /*
3892          * push the data point and reset margin/text info.
3893          */
3894         PushDataPoint(layout, &basePt);
3895         SetMargins(layout);
3896         SetTextPosition(layout, True);
3897       }
3898
3899     /*
3900      * determine the minimum Y that the child of this container should
3901      * occupy.  To do so, subtract off the bottom border pad and the
3902      * bottom margin.
3903      */
3904     if (0 < min_y)
3905       {
3906         myMinY = min_y - yPad;
3907         if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
3908           {
3909             _DtCvUnit bPad = 0;
3910
3911             _DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg), &bPad);
3912             myMinY -= bPad;
3913           }
3914       }
3915
3916     /*
3917      * format the segment
3918      */
3919     saveYpos = layout->info.y_pos;
3920
3921     GetCurrentDataPoint(layout, &curPt);
3922
3923     /*
3924      * reset the max x variable
3925      */
3926     layout->info.cur_max_x = 0;
3927     ProcessSegmentList(canvas, layout, _DtCvContainerListOfSeg(con_seg),
3928                                         myMinY,
3929                                         &maxWidth, &maxXPos, NULL);
3930     /*
3931      * if this container forces a wrap join of the next item,
3932      * save the current line, but don't add space or null the
3933      * last rendered item.
3934      */
3935     CheckSaveInfo(canvas, layout, con_seg, 0);
3936     if (maxWidth < layout->info.cur_max_x - curPt.left + layout->right)
3937         maxWidth = layout->info.cur_max_x - curPt.left + layout->right;
3938     if (maxXPos < layout->info.cur_max_x)
3939         maxXPos = layout->info.cur_max_x;
3940
3941     if (_DtCvWRAP_JOIN != _DtCvContainerFlowOfSeg(con_seg))
3942       {
3943         /*
3944          * Save any information in the buffer,
3945          * reset the margins and add the appropriate lines,
3946          * and check for going over boundaries.
3947          */
3948         _DtCvAddSpace(_DtCvContainerBMarginOfSeg(con_seg),
3949                                                         &(layout->info.y_pos));
3950
3951         /*
3952          * terminate the previous rendering list
3953          */
3954         if (NULL != layout->lst_rendered)
3955             layout->lst_rendered->next_disp = NULL;
3956         layout->lst_rendered = NULL;
3957       }
3958
3959     /*
3960      * remove this element's data points from the stack.
3961      */
3962     RemoveDataPoint(layout, &basePt);
3963
3964     /*
3965      * include the bottom border (if needed) in the ending y position
3966      */
3967     layout->info.y_pos += yPad;
3968
3969     /*
3970      * Set the ending counts for the lines and text in me.
3971      * This sets the ending counts for the lines contained in me,
3972      * NOT the lines in my border.
3973      */
3974     SetEndCounts(canvas, &(frmtInfo.cnt), 0);
3975
3976     /*
3977      * does this object need to be adjust within its height?
3978      */
3979     if (0 < min_y && layout->info.y_pos < min_y)
3980       {
3981         AdjustObjectPosition(canvas, layout, TxtVertJustify(con_seg),
3982                         frmtInfo.cnt.beg_txt, frmtInfo.cnt.beg_ln,
3983                         frmtInfo.cnt.beg_brk,
3984                         frmtInfo.cnt.end_txt, frmtInfo.cnt.end_ln,
3985                         frmtInfo.cnt.end_brk,
3986                         0, min_y - layout->info.y_pos - yPad, 0, 0, 0);
3987         layout->info.y_pos = min_y;
3988       }
3989
3990     /*
3991      * Now draw the borders
3992      * If borders are drawn, cur_max_x & max_x_pos may get changed
3993      * if a right side border is drawn.
3994      */
3995     if (maxWidth < layout->max_width - curPt.left - curPt.right)
3996         maxWidth = layout->max_width - curPt.left - curPt.right;
3997
3998     getLn = DrawBorders (canvas, layout, Border(con_seg),
3999                                 BrdData(con_seg), BrdWidth(con_seg),
4000                                 saveYpos, layout->info.y_pos - yPad,
4001                                 curPt.left,
4002                                 curPt.left + maxWidth);
4003
4004     /*
4005      * check to see if we need to save the container counts away
4006      * because we might need to move the entire container as one
4007      * to honor the boundary. This will occur if the flag to honor
4008      * a boundary is set to _DtCvUSE_BOUNDARY_MOVE, this container has
4009      * border lines, the container's parent is not a table nor
4010      * is the container within another container that has a border.
4011      */
4012     if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint
4013                         && True == layout->brdr_flag
4014                         && False == saveBrdr && False == layout->table_flag)
4015       {
4016         GrpInfo *info = (GrpInfo *) malloc (sizeof(GrpInfo));
4017
4018         /*
4019          * warning - nothing done if malloc error.
4020          */
4021         if (NULL != info)
4022           {
4023             /*
4024              * initialize to the end information of the container.
4025              */
4026             info->cnt = frmtInfo.cnt;
4027
4028             /*
4029              * take into account the borders for this container
4030              */
4031             SetEndCounts(canvas, &(info->cnt), getLn);
4032
4033             /*
4034              * set the linked list information
4035              */
4036             info->next_info = layout->grp_lst;
4037             layout->grp_lst = info;
4038           }
4039       }
4040
4041     /*
4042      * set the return values.
4043      */
4044     *ret_max_x = layout->info.cur_max_x;
4045     *ret_width = maxWidth;
4046     if (*ret_width < layout->max_width - curPt.left - curPt.right)
4047         *ret_width = layout->max_width - curPt.left - curPt.right;
4048
4049     /*
4050      * Restore the previous information
4051      */
4052     layout->left      = saveLeft;
4053     layout->right     = saveRight;
4054     layout->first     = saveFirst;
4055     layout->stat_flag = saveStatic;
4056     layout->brdr_flag = saveBrdr;
4057     layout->info.leading = saveLead;
4058
4059     /*
4060      * Besides checking for flow constraints, also (re)sets margins and
4061      * text information.
4062      */
4063     CheckFormat(layout, True);
4064     layout->txt_justify  = saveJustify;
4065     layout->info.align_char  = saveJustifyChar;
4066
4067     /*
4068      * for tables and such, return how many lines were drawn around this
4069      * container.
4070      */
4071     if (ret_cnt)
4072         *ret_cnt = getLn;
4073
4074     return;
4075 }
4076
4077 /******************************************************************************
4078  * Function: ProcessSegmentList
4079  *
4080  * Process the segment list, laying it out according to left, right,
4081  * and first margins specified. Returns the max_width of the all
4082  * segments processed and the maximum x coordinate used.
4083  *****************************************************************************/
4084 static void
4085 ProcessSegmentList(
4086     _DtCanvasStruct     *canvas,
4087     LayoutInfo          *layout,
4088     _DtCvSegmentI       *cur_seg,
4089     _DtCvUnit            min_y,
4090     _DtCvUnit           *ret_width,
4091     _DtCvUnit           *ret_max_x,
4092     int                 **ret_vert)
4093 {
4094     int          junk;
4095     int          saveTravCnt  = canvas->trav_cnt;
4096     int          saveTxtCnt   = canvas->txt_cnt;
4097     int          saveLineCnt  = canvas->line_cnt;
4098     int          saveBrkCnt   = canvas->brk_cnt;
4099     _DtCvUnit    tempX;
4100     _DtCvUnit    tempLen;
4101     _DtCvUnit    width;
4102     _DtCvUnit    nWidth       = 0;
4103     _DtCvUnit    leftMargin   = 0;
4104     _DtCvUnit    rightMargin  = 0;
4105     _DtCvUnit    topHeight    = 0;
4106     _DtCvUnit    botHeight    = 0;
4107     _DtCvUnit    maxWidth     = 0;
4108     _DtCvUnit    saveYpos     = layout->info.y_pos;
4109     _DtCvSegmentI       *segStart     = cur_seg;
4110     LayFrmtInfo         *headInfo     = NULL;
4111     LayFrmtInfo         *lastHead     = NULL;
4112     LayFrmtInfo         *nxtHead;
4113     _DtCvLayoutInfo      startInfo;
4114
4115     _DtCvValue   redo         = False;
4116     _DtCvValue   joinCleared  = False;
4117     _DtCvValue   flag;
4118
4119     TopDims      topBot;
4120     SideDims     sideDims;
4121     CornerDims   cornerDims;
4122     FlowDims     flowDims;
4123     DataPoint    basePt;
4124     DataPoint    leftPt;
4125     DataPoint    rightPt;
4126
4127     /*
4128      * clear the controller arrays
4129      */
4130     InitDimArrays(&topBot, &sideDims, &cornerDims, &flowDims);
4131
4132     /*
4133      * get the current left and right values or 'base'.
4134      */
4135     GetCurrentDataPoint(layout, &basePt);
4136
4137     /*
4138      * ???
4139      */
4140     leftPt  = basePt;
4141     rightPt = basePt;
4142     leftPt.y_pos  = _CEFORMAT_ALL;
4143     rightPt.y_pos = _CEFORMAT_ALL;
4144
4145     /*
4146      * process all the controller type containers in the segment list
4147      */
4148     while (NULL != cur_seg)
4149       {
4150         if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
4151           {
4152             /*
4153              * want to clear this once and only once. Then any join
4154              * directives will survive, though if two or more controllers
4155              * have the directive set, the 'last' one will win out.
4156              */
4157             if (False == joinCleared)
4158               {
4159                 _DtCvSetJoinInfo(&(layout->info), False, -1);
4160                 joinCleared = True;
4161               }
4162
4163             /*
4164              * process the 'controller'
4165              */
4166             nxtHead = ProcessController(canvas, layout, cur_seg);
4167
4168             /*
4169              * update the dimension arrays so that the controller
4170              * will get placed correctly.
4171              */
4172             UpdateDimensionArrays(cur_seg, nxtHead->width, nxtHead->height,
4173                                 &topBot, &sideDims, &cornerDims, &flowDims,
4174                                 &leftMargin, &rightMargin);
4175
4176             /*
4177              * remember this controller.
4178              */
4179             if (NULL == headInfo)
4180                 headInfo = nxtHead;
4181             else
4182                 lastHead->next_info = nxtHead;
4183             lastHead = nxtHead;
4184           }
4185
4186         /*
4187          * go to the next segment
4188          */
4189         cur_seg = cur_seg->next_seg;
4190       }
4191
4192     /*
4193      * Now reset the margins based on the controllers found
4194      */
4195     if (NULL != headInfo)
4196       {
4197         DetermineMaxDims(&topBot, &cornerDims, leftMargin, rightMargin,
4198                             &topHeight, &botHeight, &maxWidth);
4199         layout->info.y_pos += topHeight;
4200         layout->left       += leftMargin;
4201         layout->right      += rightMargin;
4202         DetermineFlowConstraints(layout, flowDims,
4203                             basePt.left, basePt.right,
4204                             layout->info.y_pos, &leftPt, &rightPt);
4205
4206         /*
4207          * get rid of the leftMargin and rightMargin values in maxWidth
4208          * otherwise the use of layout->left & layout->right will double
4209          * the value.
4210          */
4211         maxWidth = maxWidth - leftMargin - rightMargin;
4212         if (layout->max_width < maxWidth + basePt.left + basePt.right +
4213                             layout->left + layout->right)
4214             layout->max_width = maxWidth + basePt.left + basePt.right +
4215                                             layout->left + layout->right;
4216
4217         SetMargins(layout);
4218         SetTextPosition(layout, True);
4219         if (JoinSet(layout))
4220           {
4221             int  cnt;
4222             int  joinLine = layout->info.join_line;
4223             int  start    = canvas->txt_lst[joinLine].byte_index;
4224             int  count    = canvas->txt_lst[joinLine].length;
4225             _DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
4226             _DtCvUnit     tmpWidth;
4227
4228             /*
4229              * change the starting location of the following text.
4230              * take into account the left margin that *hasn't*
4231              * been added to the controlling container.
4232              */
4233             layout->info.text_x_pos  = canvas->txt_lst[joinLine].text_x
4234                                                         + layout->lmargin;
4235             layout->info.cur_len = 0;
4236
4237             /*
4238              * now calculate the width of this line.
4239              */
4240             while (pSeg != NULL && count > 0)
4241               {
4242                 _DtCvGetWidthOfSegment(canvas,pSeg,start,count,
4243                                                     &cnt, &tmpWidth, NULL);
4244                 layout->info.text_x_pos += tmpWidth;
4245                 count -= cnt;
4246                 start  = 0;
4247                 pSeg   = pSeg->next_disp;
4248               }
4249           }
4250       }
4251
4252     /*
4253      * now format for non-controller containers and non-containers.
4254      * re-start at the beginning.
4255      */
4256     cur_seg   = segStart;
4257
4258     /*
4259      * Save some information incase we have to redo the layout. I.e.
4260      * we overflow the sizing.
4261      */
4262     startInfo = layout->info;
4263     saveTravCnt = canvas->trav_cnt;
4264     saveTxtCnt   = canvas->txt_cnt;
4265     saveLineCnt  = canvas->line_cnt;
4266     saveBrkCnt   = canvas->brk_cnt;
4267
4268     while (NULL != cur_seg)
4269       {
4270         width = layout->max_width - layout->info.text_x_pos
4271                                 - layout->rmargin - layout->info.cur_len;
4272
4273         /*
4274          * check to see if this item should start a line.
4275          */
4276         CheckSetLineStart(layout, cur_seg);
4277
4278         /*
4279          * check to see if this item will cause a page break.
4280          */
4281         CheckForPageBreak(canvas, cur_seg, layout->info.y_pos);
4282
4283         switch (_DtCvPrimaryTypeOfSeg(cur_seg))
4284           {
4285             case _DtCvCONTAINER:
4286                     if (!(_DtCvIsSegController(cur_seg)))
4287                         ProcessContainer(canvas, layout, cur_seg, min_y,
4288                                                 &junk, &junk, &junk);
4289                     break;
4290
4291             case _DtCvREGION:
4292                     /*
4293                      * flag that this segment needs a line number
4294                      */
4295                     cur_seg->internal_use = (void *) -1;
4296
4297                     /*
4298                      * process the segment
4299                      */
4300                     if (_DtCvIsSegInLine(cur_seg))
4301                       {
4302                         /*
4303                          * if a hypertext link, this will add it to
4304                          * the internal list.
4305                          */
4306                         CheckAddToHyperList(canvas, cur_seg);
4307
4308                         /*
4309                          * get the traversal width
4310                          */
4311                         nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
4312                                                     layout->info.lst_hyper);
4313
4314                         /*
4315                          * check to see if this region can end a line
4316                          */
4317                         flag = _DtCvCheckLineSyntax(canvas,cur_seg,0,0,False);
4318
4319                         /*
4320                          * if this can't end a line, get the length up to
4321                          * the next segment that can and base whether to
4322                          * save pased on that.
4323                          */
4324                         tempLen = 0;
4325                         if (False == flag)
4326                           {
4327                             tempLen = _DtCvGetNextWidth(canvas,
4328                                                 _DtCvSTRING,
4329                                                 layout->info.lst_hyper,
4330                                                 cur_seg->next_seg,
4331                                                 0, cur_seg, NULL, NULL, NULL);
4332                             /*
4333                              * if the next width is zero, reset the flag.
4334                              */
4335                             if (tempLen <= 0)
4336                                 flag = True;
4337                           }
4338                         tempLen += nWidth;
4339
4340                         /*
4341                          * if not joining, but my length goes over the
4342                          * working width, save out the current buffered
4343                          * information
4344                          */
4345                         if (NotJoining(layout) &&
4346                             _DtCvWidthOfRegionSeg(cur_seg) + tempLen > width)
4347                             CheckSaveInfo (canvas, layout, cur_seg, 0);
4348
4349                         /*
4350                          * up counts on the buffered information.
4351                          */
4352                         layout->info.line_bytes += 1;
4353                         layout->info.cur_len    += 
4354                                 (_DtCvWidthOfRegionSeg(cur_seg) + nWidth);
4355
4356                         /*
4357                          * does the next segment need to join with
4358                          * this one? If so, set the information
4359                          */
4360                         _DtCvSetJoinInfo(&(layout->info), (flag ? 0 : 1), -1);
4361                         if (_DtCvIsSegNewLine(cur_seg))
4362                             SaveInfo(canvas, layout, cur_seg, 0);
4363                       }
4364                     else
4365                       {
4366                         /*
4367                          * clear out the join information
4368                          * standalone figures can't join with others.
4369                          */
4370                         _DtCvSetJoinInfo(&(layout->info), False, -1);
4371
4372                         /*
4373                          * figures are standalone. Save any
4374                          * information in the buffer away.
4375                          */
4376                         CheckSaveInfo (canvas, layout, cur_seg, 0);
4377
4378                         /*
4379                          * check to see if this segment is
4380                          * a hypertext. If so, add it to the
4381                          * list if it hasn't been added yet.
4382                          */
4383                         CheckAddToHyperList(canvas, cur_seg);
4384
4385                         /*
4386                          * get the traversal width, if any.
4387                          */
4388                         nWidth = _DtCvGetTraversalWidth(canvas, cur_seg,
4389                                                     layout->info.lst_hyper);
4390
4391                         /*
4392                          * now save the standalone figure
4393                          */
4394                         layout->info.line_bytes += 1;
4395                         layout->info.cur_len    += 
4396                                 _DtCvWidthOfRegionSeg(cur_seg) + nWidth;
4397                         SaveInfo(canvas, layout, cur_seg->next_seg, 0);
4398
4399                         /*
4400                          * check for wrapping overflow
4401                          */
4402                         CheckFormat(layout, False);
4403                       }
4404
4405                     /*
4406                      * indicate this segment as the last item rendered
4407                      */
4408                     if (NULL != layout->lst_rendered)
4409                         layout->lst_rendered->next_disp = cur_seg;
4410                     layout->lst_rendered = cur_seg;
4411                     break;
4412
4413             case _DtCvLINE:
4414                     /*
4415                      * lines are standalone. Save any
4416                      * information in the buffer away.
4417                      */
4418                     CheckSaveInfo (canvas, layout, cur_seg, 0);
4419
4420                     /*
4421                      * if the line_width is zero, make it 1 so
4422                      * that it really does take some space.
4423                      */
4424                     nWidth = _DtCvWidthOfLineSeg(cur_seg);
4425                     if (0 == nWidth)
4426                         nWidth = 1;
4427
4428                     /*
4429                      * start with it going all the way across the window.
4430                      */
4431                     width = layout->max_width;
4432                     tempX = 0;
4433
4434                     /*
4435                      * or does it only extend across the container?
4436                      */
4437                     if (_DtCvIsSegBlockLine(cur_seg))
4438                       {
4439                         tempX = layout->lmargin;
4440                         width = layout->max_width - tempX - layout->rmargin;
4441                       }
4442
4443                     SaveLine (canvas, layout, _DtCvLINE_HORZ,
4444                                 _DtCvDataOfLineSeg(cur_seg), nWidth, tempX,
4445                                 layout->info.y_pos, width);
4446
4447                     layout->info.y_pos += nWidth;
4448                     break;
4449
4450             case _DtCvMARKER:
4451                     /*
4452                      * check to see if marker is the target id
4453                      */
4454                     CheckId(layout, _DtCvIdOfMarkerSeg(cur_seg));
4455                     break;
4456
4457             case _DtCvNOOP:
4458                     if (_DtCvIsSegNewLine(cur_seg))
4459                         SaveInfo(canvas, layout, cur_seg, 0);
4460                     break;
4461
4462             case _DtCvSTRING:
4463                     /*
4464                      * flag that this segment needs a line number
4465                      */
4466                     cur_seg->internal_use = (void *) -1;
4467
4468                     /*
4469                      * process the string
4470                      */
4471                     ProcessStringSegment(canvas, layout, cur_seg);
4472
4473                     /*
4474                      * check for wrapping overflow.
4475                      */
4476                     if (_DtCvIsSegNewLine(cur_seg))
4477                         CheckFormat(layout, False);
4478
4479                     /*
4480                      * indicate this segment as the last item rendered
4481                      */
4482                     if (NULL != layout->lst_rendered)
4483                         layout->lst_rendered->next_disp = cur_seg;
4484                     layout->lst_rendered = cur_seg;
4485                     break;
4486
4487             case _DtCvTABLE:
4488                     ProcessTable(canvas, layout, cur_seg, min_y);
4489             default:
4490                     break;
4491           }
4492
4493         /*
4494          * get the next segment
4495          */
4496         cur_seg = cur_seg->next_seg;
4497
4498         /*
4499          * check the flowing text points
4500          */
4501         if (leftPt.y_pos > 0 &&
4502                 leftPt.x_units > layout->max_width - leftPt.left - leftPt.right)
4503           {
4504             layout->max_width = leftPt.x_units + leftPt.left + leftPt.right;
4505             redo = True;
4506           }
4507         if (rightPt.y_pos > 0 &&
4508                 rightPt.x_units > layout->max_width-rightPt.left-rightPt.right)
4509           {
4510             layout->max_width = rightPt.x_units + rightPt.left + rightPt.right;
4511             redo = True;
4512           }
4513
4514         /*
4515          * have we violated the available space?
4516          * if so, we'll have to reformat.
4517          */
4518         if (redo == True)
4519           {
4520             redo             = False;
4521             cur_seg          = segStart;
4522             canvas->trav_cnt = saveTravCnt;
4523             canvas->txt_cnt  = saveTxtCnt;
4524             canvas->line_cnt = saveLineCnt;
4525             canvas->brk_cnt  = saveBrkCnt;
4526             layout->info     = startInfo;
4527
4528             if (rightPt.y_pos > 0)
4529               {
4530                 RemoveDataPoint(layout, &rightPt); /* make sure its gone */
4531                 InsertDataPoint(layout, &rightPt);
4532               }
4533             if (leftPt.y_pos > 0)
4534               {
4535                 RemoveDataPoint(layout, &leftPt); /* make sure its gone */
4536                 InsertDataPoint(layout, &leftPt);
4537               }
4538
4539             /*
4540              * Now reset the margins based on the controllers found
4541              */
4542             if (NULL != headInfo)
4543               {
4544                 layout->left   += leftMargin;
4545                 layout->right  += rightMargin;
4546                 SetMargins(layout);
4547                 SetTextPosition(layout, True);
4548                 if (JoinSet(layout))
4549                   {
4550                     int  cnt;
4551                     int  joinLine = layout->info.join_line;
4552                     int  start    = canvas->txt_lst[joinLine].byte_index;
4553                     int  count    = canvas->txt_lst[joinLine].length;
4554                     _DtCvSegmentI *pSeg = canvas->txt_lst[joinLine].seg_ptr;
4555                     _DtCvUnit     tmpWidth;
4556         
4557                     /*
4558                      * change the starting location of the following text.
4559                      * take into account the left margin that *hasn't*
4560                      * been added to the controlling container.
4561                      */
4562                     layout->info.text_x_pos  = canvas->txt_lst[joinLine].text_x
4563                                                         + layout->lmargin;
4564                     layout->info.cur_len = 0;
4565         
4566                     /*
4567                      * now calculate the width of this line.
4568                      */
4569                     while (pSeg != NULL && count > 0)
4570                       {
4571                         _DtCvGetWidthOfSegment(canvas,pSeg,start,count,
4572                                                         &cnt, &tmpWidth, NULL);
4573                         layout->info.text_x_pos += tmpWidth;
4574                         count -= cnt;
4575                         start  = 0;
4576                         pSeg   = pSeg->next_disp;
4577                       }
4578                   }
4579               }
4580           }
4581       }
4582
4583     RemoveDataPoint(layout, &leftPt);
4584     RemoveDataPoint(layout, &rightPt);
4585
4586     /*
4587      * if there were heads, now place them correctly.
4588      */
4589     if (NULL != headInfo)
4590       {
4591         _DtCvUnit       blockHeight;
4592         _DtCvUnit       blockWidth;
4593
4594         /*
4595          * make sure all of the information in the body is saved out
4596          */
4597         CheckSaveInfo (canvas, layout, NULL, 0);
4598
4599         /*
4600          * now calculate the non-controllers overall height.
4601          */
4602         blockHeight = layout->info.y_pos - saveYpos - topHeight;
4603
4604         /*
4605          * now figure the head positions.
4606          */
4607         DetermineHeadPositioning(&topBot, &sideDims, &cornerDims, &flowDims,
4608                                 saveYpos, topHeight,
4609                                 blockHeight, &blockHeight);
4610         /*
4611          * if the maximum available space was exceeded by the text
4612          * calculate a new max width
4613          */
4614         if (layout->max_width < layout->info.cur_max_x + layout->right)
4615             layout->max_width = layout->info.cur_max_x + layout->right;
4616
4617         blockWidth = layout->max_width - basePt.left - basePt.right
4618                                                 - layout->left - layout->right;
4619
4620         nxtHead = headInfo;
4621         cur_seg = segStart;
4622         while (cur_seg != NULL)
4623           {
4624             if (_DtCvIsSegContainer(cur_seg) && _DtCvIsSegController(cur_seg))
4625               {
4626                 AdjustHeadPosition(canvas, layout, cur_seg,
4627                         &topBot, &sideDims, &cornerDims, &flowDims, nxtHead,
4628                         0, basePt.left + layout->left - leftMargin, blockWidth,
4629                         leftMargin, rightMargin);
4630                 /*
4631                  * go to the next head element
4632                  */
4633                 nxtHead = nxtHead->next_info;
4634
4635                 /*
4636                  * free the information.
4637                  */
4638                 free(headInfo);
4639                 headInfo = nxtHead;
4640               }
4641
4642             /*
4643              * got to the next segment
4644              */
4645             cur_seg = cur_seg->next_seg;
4646           }
4647
4648         if (layout->info.y_pos < saveYpos + topHeight + blockHeight)
4649             layout->info.y_pos = saveYpos + topHeight + blockHeight;
4650
4651         layout->info.y_pos += botHeight;
4652       }
4653
4654     /*
4655      * set the return values
4656      */
4657     *ret_width = layout->info.cur_max_x - basePt.left + layout->right;
4658     *ret_max_x = layout->info.cur_max_x;
4659
4660     return;
4661 }
4662
4663 /*****************************************************************************
4664  * Function:    static _DtCvUnit MaxOfGroup (
4665  *
4666  * Purpose: Determine the maximum of a group.
4667  *****************************************************************************/
4668 static void
4669 MaxOfGroup (
4670     GrpInfo             *group,
4671     _DtCvDspLine        *text,
4672     _DtCvLineSeg        *lines,
4673     _DtCvUnit            max_x,
4674     _DtCvUnit            max_y)
4675 {
4676     int          i;
4677
4678     /*
4679      * initialize
4680      */
4681     group->min_x = max_x;
4682     group->max_x = 0;
4683     group->top_y = max_y;
4684     group->bot_y = 0;
4685
4686     /*
4687      * find the maximum of the group
4688      */
4689     for (i = group->cnt.beg_txt; i < group->cnt.end_txt; i++)
4690       {
4691         /*
4692          * check for min's and max's
4693          */
4694         if (group->min_x > text[i].text_x)
4695             group->min_x = text[i].text_x;
4696
4697         if (group->max_x < text[i].max_x)
4698             group->max_x = text[i].max_x;
4699
4700         if (group->top_y > text[i].baseline - text[i].ascent)
4701             group->top_y = text[i].baseline - text[i].ascent;
4702
4703         if (group->bot_y < text[i].baseline + text[i].descent)
4704             group->bot_y = text[i].baseline + text[i].descent;
4705
4706         /*
4707          * indicate that this line has been processed already
4708          */
4709         _DtCvSetProcessed(text[i]);
4710       }
4711
4712     for (i = group->cnt.beg_ln; i < group->cnt.end_ln; i++)
4713       {
4714         /*
4715          * check for min's and max's
4716          */
4717         if (group->min_x > lines[i].pos_x)
4718             group->min_x = lines[i].pos_x;
4719
4720         if (group->max_x < lines[i].max_x)
4721             group->max_x = lines[i].max_x;
4722
4723         if (group->top_y > lines[i].pos_y)
4724             group->top_y = lines[i].pos_y;
4725
4726         if (group->bot_y < lines[i].max_y)
4727             group->bot_y = lines[i].max_y;
4728
4729         /*
4730          * indicate that this line has been processed already
4731          */
4732         _DtCvSetProcessed(lines[i]);
4733       }
4734 }
4735
4736 /*****************************************************************************
4737  * Function:    static _DtCvUnit TestSpacing (
4738  *
4739  * Parameters:
4740  *
4741  * Returns:     True    if the object is before (x wise) the test object.
4742  *              False   if the object is not before (x wise) the text object.
4743  *
4744  * Purpose:
4745  * 
4746  *****************************************************************************/
4747 static _DtCvStatus
4748 TestSpacing (
4749     _DtCvUnit            tst_top,
4750     _DtCvUnit            tst_bot,
4751     _DtCvUnit            tst_min,
4752     _DtCvUnit            obj_top,
4753     _DtCvUnit            obj_bot,
4754     _DtCvUnit            obj_max,
4755     _DtCvUnit            needed,
4756     _DtCvUnit            min_space,
4757     _DtCvUnit           *ret_amount)
4758 {
4759     _DtCvStatus  result = False;
4760
4761     /*
4762      * check to see if the object is to the left of the test object
4763      * to move and that it 'infringes' on the vertical
4764      * space of the test object.
4765      *
4766      * I.e.     ----obj_top------
4767      *          |               |   ----tst_top----
4768      *          ----obj_bot------   |             |
4769      *                              ----tst_bot----
4770      *
4771      * I.e.                         ----tst_top----
4772      *          ----obj_top-------  |             |
4773      *          |                |  ----tst_bot----
4774      *          ----obj_bot-------
4775      *
4776      * I.e.     ----obj_top------
4777      *          |               |   ----tst_top----
4778      *          |               |   |             |
4779      *          |               |   ----tst_bot----
4780      *          ----obj_bot------
4781      *
4782      * I.e.                         ----tst_top----
4783      *          ----obj_top-------  |             |
4784      *          |                |  |             |
4785      *          ----obj_bot-------  |             |
4786      *                              ----tst_bot----
4787      */
4788     if (obj_max < tst_min
4789         && True == _DtCvCheckInfringement(tst_top, tst_bot, obj_top, obj_bot)
4790         && needed > tst_min - obj_max)
4791       {
4792         /*
4793          * okay, this infringes on the object's space.
4794          * truncate the amount of room there is to move the object
4795          */
4796         result = True;
4797         needed = tst_min - obj_max;
4798
4799         /*
4800          * is the space between these two objects already squeezed
4801          * below the minimum allowed?
4802          */
4803         if (needed < min_space)
4804             needed = 0;
4805         else /* leave the minimum space between the objects */
4806             needed -= min_space;
4807       }
4808
4809     *ret_amount = needed;
4810     return result;
4811 }
4812
4813 /*****************************************************************************
4814  * Function:    static void MoveLeft (
4815  *
4816  * Parameters:
4817  *
4818  * Returns:
4819  *
4820  * Purpose:     Moves the object's rules/lines and text lines to the left.
4821  * 
4822  *****************************************************************************/
4823 static void
4824 MoveLeft (
4825     _DtCanvasStruct     *canvas,
4826     int                  beg_txt,
4827     int                  end_txt,
4828     int                  beg_ln,
4829     int                  end_ln,
4830     _DtCvUnit            space)
4831 {
4832     int         i;
4833
4834     /*
4835      * bail now if nothing to do.
4836      */
4837     if (1 > space)
4838         return;
4839
4840     /*
4841      * move each text/region line.
4842      */
4843     for (i = beg_txt; i < end_txt; i++)
4844       {
4845         canvas->txt_lst[i].text_x -= space;
4846         canvas->txt_lst[i].max_x  -= space;
4847       }
4848
4849     /*
4850      * move each line/rule.
4851      */
4852     for (i = beg_ln; i < end_ln; i++)
4853       {
4854         canvas->line_lst[i].pos_x -= space;
4855         canvas->line_lst[i].max_x -= space;
4856       }
4857 }
4858
4859 /*****************************************************************************
4860  * Function:    static _DtCvUnit CheckSpacing (
4861  *
4862  * Purpose:     Check the spacing before an object and move any objects
4863  *              before it to the left to make room.
4864  *
4865  *****************************************************************************/
4866 static _DtCvUnit
4867 CheckSpacing (
4868     _DtCanvasStruct     *canvas,
4869     LayoutInfo          *layout,
4870     GrpInfo             *tst_grp,
4871     int                  txt_idx,
4872     int                  line_idx,
4873     _DtCvUnit            top_y,
4874     _DtCvUnit            bot_y,
4875     _DtCvUnit            min_x,
4876     _DtCvUnit            needed)
4877 {
4878     int          i;
4879     _DtCvUnit    space;
4880     _DtCvUnit    maxSpace;
4881     _DtCvUnit    topY;
4882     _DtCvUnit    botY;
4883     GrpInfo     *nxtGrp   = layout->grp_lst;
4884
4885     /*
4886      * truncate if the amount needed is more than available.
4887      */
4888     if (min_x < needed)
4889         needed = min_x;
4890
4891     maxSpace = needed;
4892
4893     /*
4894      * see what group is before this group and how much space there is
4895      */
4896     while (NULL != nxtGrp)
4897       {
4898         /*
4899          * as long as I'm not comparing against myself, try it.
4900          */
4901         if (nxtGrp != tst_grp)
4902           {
4903             /*
4904              * is this group before(x wise) the test group, infringing
4905              * upon the test group's top and bottom positioning (y)
4906              * and is the amount of space (x wise) between them smaller
4907              * than the current smallest space found?
4908              */
4909             if (True == TestSpacing (top_y, bot_y, min_x,
4910                                         nxtGrp->top_y, nxtGrp->bot_y,
4911                                         nxtGrp->max_x, needed,
4912                                         canvas->metrics.horiz_pad_hint,
4913                                         &space))
4914               {
4915                 space += MoveGroup(canvas, layout, nxtGrp, needed - space);
4916                 if (maxSpace > space)
4917                     maxSpace = space;
4918               }
4919           }
4920
4921         /*
4922          * check the next group
4923          */
4924         nxtGrp = nxtGrp->next_info;
4925       }
4926
4927     /*
4928      * look at each of the text lines;
4929      */
4930     for (i = 0; i < canvas->txt_cnt; i++)
4931       {
4932         /*
4933          * Only look at those lines not already processed.
4934          */
4935         if (i != txt_idx && _DtCvIsNotProcessed(canvas->txt_lst[i]))
4936           {
4937             topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
4938             botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
4939             if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
4940                                 canvas->txt_lst[i].max_x, needed,
4941                                 canvas->metrics.horiz_pad_hint, &space))
4942               {
4943                 space += MoveText(canvas, layout, i, topY, botY, needed-space);
4944                 if (maxSpace > space)
4945                     maxSpace = space;
4946               }
4947           }
4948       }
4949
4950     /*
4951      * look at each of the rules/lines;
4952      */
4953     for (i = 0; i < canvas->line_cnt; i++)
4954       {
4955         /*
4956          * Only look at those lines not already processed.
4957          */
4958         if (i != line_idx && _DtCvIsNotProcessed(canvas->line_lst[i]))
4959           {
4960             /*
4961              * calculate the top and bottom of the line
4962              */
4963             topY = canvas->line_lst[i].pos_y;
4964             botY = canvas->line_lst[i].max_y;
4965
4966             if (True == TestSpacing(top_y, bot_y, min_x, topY, botY,
4967                                 canvas->line_lst[i].max_x, needed,
4968                                 canvas->metrics.horiz_pad_hint, &space))
4969               {
4970                 space += MoveLines(canvas, layout, i, topY, botY, needed-space);
4971                 if (maxSpace > space)
4972                     maxSpace = space;
4973               }
4974           }
4975       }
4976
4977     return maxSpace;
4978 }
4979
4980 /*****************************************************************************
4981  * Function:    static _DtCvUnit MoveGroup (_DtCanvasStruct canvas);
4982  *
4983  * Purpose:     To move groupings (container, tables, etc.) as a group to
4984  *              honor boundaries.
4985  * 
4986  *****************************************************************************/
4987 static _DtCvUnit
4988 MoveGroup (
4989     _DtCanvasStruct     *canvas,
4990     LayoutInfo          *layout,
4991     GrpInfo             *tst_grp,
4992     _DtCvUnit            needed)
4993 {
4994     _DtCvUnit    space;
4995
4996     /*
4997      * find out what's in front of it. And how much 'extra' room
4998      * there is.
4999      */
5000     space = CheckSpacing(canvas, layout, tst_grp, -1, -1,
5001                                 tst_grp->top_y, tst_grp->bot_y, tst_grp->min_x,
5002                                 needed);
5003     /*
5004      * now move the group
5005      */
5006     MoveLeft(canvas, tst_grp->cnt.beg_txt, tst_grp->cnt.end_txt,
5007                         tst_grp->cnt.beg_ln, tst_grp->cnt.end_ln, space);
5008
5009     tst_grp->max_x -= space;
5010     tst_grp->min_x -= space;
5011
5012     return space;
5013 }
5014
5015 /*****************************************************************************
5016  * Function:    static _DtCvUnit MoveText (_DtCanvasStruct canvas);
5017  *
5018  * Purpose: To move text lines to honor boundaries.
5019  * 
5020  *****************************************************************************/
5021 static _DtCvUnit
5022 MoveText (
5023     _DtCanvasStruct     *canvas,
5024     LayoutInfo          *layout,
5025     int                  idx,
5026     _DtCvUnit            top_y,
5027     _DtCvUnit            bot_y,
5028     _DtCvUnit            needed)
5029 {
5030     _DtCvUnit    space;
5031
5032     /*
5033      * find out what's in front of it. And how much 'extra' room
5034      * there is.
5035      */
5036     space = CheckSpacing(canvas, layout, NULL, idx, -1,
5037                                 top_y, bot_y,
5038                                 canvas->txt_lst[idx].text_x,
5039                                 needed);
5040     /*
5041      * now move the group
5042      */
5043     MoveLeft(canvas, idx, idx, -1, -1, space);
5044
5045     return space;
5046 }
5047
5048 /*****************************************************************************
5049  * Function:    static _DtCvUnit MoveLines (_DtCanvasStruct canvas);
5050  *
5051  * Purpose: To move groupings (container, tables, etc.) as a group to
5052  *          honor boundaries.
5053  * 
5054  *****************************************************************************/
5055 static _DtCvUnit
5056 MoveLines (
5057     _DtCanvasStruct     *canvas,
5058     LayoutInfo          *layout,
5059     int                  idx,
5060     _DtCvUnit            top_y,
5061     _DtCvUnit            bot_y,
5062     _DtCvUnit            needed)
5063 {
5064     _DtCvUnit    space;
5065
5066     /*
5067      * find out what's in front of it. And how much 'extra' room
5068      * there is.
5069      */
5070     space = CheckSpacing(canvas, layout, NULL, -1, idx,
5071                                 top_y, bot_y,
5072                                 canvas->line_lst[idx].pos_x,
5073                                 needed);
5074
5075     /*
5076      * now move the group
5077      */
5078     MoveLeft(canvas, -1, -1, idx, idx, space);
5079
5080     return space;
5081 }
5082
5083 /*****************************************************************************
5084  * Function:    static void CheckMoveInfo (_DtCanvasStruct canvas);
5085  *
5086  * Purpose:     To move each of the groupings, rules and text lines to
5087  *              honor boundaries.
5088  * 
5089  *****************************************************************************/
5090 static void
5091 CheckMoveInfo (
5092     _DtCanvasStruct     *canvas,
5093     LayoutInfo          *layout)
5094 {
5095     int          i;
5096     int          txt_idx;
5097     int          ln_idx;
5098     _DtCvUnit    topY;
5099     _DtCvUnit    botY;
5100     _DtCvUnit    space;
5101     _DtCvUnit    maxWidth = canvas->metrics.width;
5102     GrpInfo     *nxtGrp;
5103     GrpInfo     *grp;
5104
5105     /*
5106      * fill in the max x of each group
5107      */
5108     for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
5109       {
5110         /*
5111          * find the maximum of the group
5112          */
5113         MaxOfGroup(nxtGrp, canvas->txt_lst, canvas->line_lst,
5114                                 layout->info.max_x_pos, layout->info.y_pos);
5115       }
5116
5117     /*
5118      * now check each group for exceeding the boundary.
5119      */
5120     for (nxtGrp = layout->grp_lst; NULL != nxtGrp; nxtGrp = nxtGrp->next_info)
5121       {
5122         /*
5123          * does this group exceed the boundary?
5124          */
5125         if (maxWidth < nxtGrp->max_x)
5126              (void) MoveGroup(canvas, layout, nxtGrp, nxtGrp->max_x - maxWidth);
5127       }
5128
5129     /*
5130      * look at each of the text lines;
5131      */
5132     for (i = 0; i < canvas->txt_cnt; i++)
5133       {
5134         /*
5135          * Only look at those lines not already processed.
5136          */
5137         if (_DtCvIsNotProcessed(canvas->txt_lst[i]) &&
5138                                         maxWidth < canvas->txt_lst[i].max_x)
5139           {
5140             topY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].ascent;
5141             botY = canvas->txt_lst[i].baseline - canvas->txt_lst[i].descent;
5142             (void) MoveText(canvas, layout, i, topY, botY,
5143                                         canvas->txt_lst[i].max_x - maxWidth);
5144           }
5145       }
5146
5147     /*
5148      * look at each of the rules/lines;
5149      */
5150     for (i = 0; i < canvas->line_cnt; i++)
5151       {
5152         /*
5153          * Only look at those lines not already processed.
5154          */
5155         if (_DtCvIsNotProcessed(canvas->line_lst[i]) &&
5156                                         maxWidth < canvas->line_lst[i].max_x)
5157           {
5158             /*
5159              * calculate the top and bottom of the line
5160              */
5161             topY = canvas->line_lst[i].pos_y;
5162             botY = canvas->line_lst[i].max_y;
5163
5164             (void) MoveLines(canvas, layout, i, topY, botY,
5165                                         canvas->line_lst[i].max_x - maxWidth);
5166           }
5167       }
5168 }
5169
5170 /*****************************************************************************
5171  * Function:    static void CompareUnits ()
5172  *
5173  * Parameters:
5174  *
5175  * Returns:
5176  *
5177  * Purpose:
5178  * 
5179  *****************************************************************************/
5180 static int
5181 CompareUnits (
5182     const void  *a,
5183     const void  *b)
5184 {
5185     _DtCvUnit *aPtr = (_DtCvUnit *) a;
5186     _DtCvUnit *bPtr = (_DtCvUnit *) b;
5187
5188     if (*aPtr <  *bPtr) return -1;
5189     if (*aPtr == *bPtr) return 0;
5190
5191     return 1;
5192 }
5193
5194 /*****************************************************************************
5195  * Function:    static void CompareSearchs ()
5196  *
5197  * Parameters:
5198  *
5199  * Returns:
5200  *
5201  * Purpose:
5202  * 
5203  *****************************************************************************/
5204 static int
5205 CompareSearchs (
5206     const void  *a,
5207     const void  *b)
5208 {
5209     _DtCvSearchData *searchA = (_DtCvSearchData *) a;
5210     _DtCvSearchData *searchB = (_DtCvSearchData *) b;
5211     _DtCvDspLine    *lineA   = &(searchA->lst[searchA->idx]);
5212     _DtCvDspLine    *lineB   = &(searchB->lst[searchB->idx]);
5213     _DtCvUnit        topA    = lineA->baseline - lineA->ascent;
5214     _DtCvUnit        topB    = lineB->baseline - lineB->ascent;
5215     _DtCvUnit        heightA = lineA->ascent   + lineA->descent;
5216     _DtCvUnit        heightB = lineB->ascent   + lineB->descent;
5217     _DtCvUnit        centA   =  topA + (heightA >> 1);
5218     _DtCvUnit        centB   =  topB + (heightB >> 1);
5219
5220     if (lineA->baseline + lineA->descent < centB && centA < topB)
5221         return -1;
5222
5223     if (lineB->baseline + lineB->descent < centA && centB < topA)
5224         return 1;
5225
5226     if (lineA->text_x != lineB->text_x)
5227         return ((lineA->text_x < lineB->text_x) ? -1 : 1);
5228
5229     if (topA != topB)
5230         return ((topA < topB) ? -1 : 1);
5231
5232     if (heightA != heightB)
5233         return ((heightA < heightB) ? -1 : 1);
5234
5235     if (lineA->max_x != lineB->max_x)
5236         return ((lineA->max_x < lineB->max_x) ? -1 : 1);
5237
5238     return 0;
5239 }
5240
5241 /*****************************************************************************
5242  * Function:    static Status LayoutCanvasInfo (_DtCvHandle canvas);
5243  *
5244  * Parameters:
5245  *
5246  * Returns:
5247  *
5248  * Purpose:
5249  * 
5250  *****************************************************************************/
5251 static _DtCvStatus
5252 LayoutCanvasInfo (
5253     _DtCanvasStruct     *canvas,
5254     LayoutInfo          *layout,
5255     _DtCvUnit            divisor,
5256     char                *target_id)
5257 {
5258     int                  i = 0;
5259     DataPoint            basePt;
5260     _DtCvUnit            maxWidth = 0;
5261     _DtCvUnit            maxXPos  = 0;
5262     _DtCvStatus          result   = _DtCvSTATUS_OK;
5263
5264     *layout           = DefInfo;
5265     layout->divisor   = divisor;
5266     layout->max_width = canvas->metrics.width;
5267     layout->left      = canvas->metrics.side_margin;
5268     layout->right     = canvas->metrics.side_margin;
5269     layout->target_id = target_id;
5270
5271     _DtCvInitLayoutInfo(canvas, &(layout->info));
5272
5273     basePt = DefDataPt;
5274     PushDataPoint(layout, &basePt);
5275     SetMargins (layout);
5276     SetTextPosition (layout, True);
5277
5278     ProcessSegmentList(canvas, layout, canvas->element_lst, -1,
5279                                                 &maxWidth, &maxXPos, NULL);
5280
5281     RemoveDataPoint(layout, &basePt);
5282
5283     /*
5284      * fill in the max_x of each line of text/regions.
5285      */
5286     for (i = 0; i < canvas->txt_cnt; i++)
5287         canvas->txt_lst[i].max_x = MaxXOfLine(canvas, &(canvas->txt_lst[i]));
5288
5289     /*
5290      * calculate the actual right hand side boundary.
5291      */
5292     layout->info.max_x_pos += canvas->metrics.side_margin;
5293
5294     /*
5295      * the max_x_pos so far has indicated where the *next* character,
5296      * line or region will be *started*. Therefore back up one to
5297      * indicate the true last position used.
5298      */
5299     layout->info.max_x_pos--;
5300
5301     return result;
5302
5303 }  /* End LayoutCanvasInfo */
5304
5305 /*****************************************************************************
5306  * Function:    static Status LayoutCanvas (_DtCvHandle canvas);
5307  *
5308  * Parameters:
5309  *
5310  * Returns:
5311  *
5312  * Purpose:
5313  * 
5314  *****************************************************************************/
5315 static _DtCvStatus
5316 LayoutCanvas (
5317     _DtCanvasStruct     *canvas,
5318     LayoutInfo          *layout,
5319     char                *target_id)
5320 {
5321     _DtCvUnit            divisor = 1;
5322     _DtCvValue           redo;
5323     _DtCvStatus          result;
5324
5325     int i, search_cnt = canvas->search_cnt;
5326     
5327     do {
5328         redo = False;
5329         result = LayoutCanvasInfo(canvas, layout, divisor, target_id);
5330
5331         /*
5332          * Are we suppose to honor the boundary?
5333          * If so, do any lines go over the boundary?
5334          * Is there any margins that can be decremented?
5335          */
5336         if (_DtCvSTATUS_OK == result
5337                 && (_DtCvUSE_BOUNDARY == canvas->constraint ||
5338                         _DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
5339                 && layout->info.max_x_pos >= canvas->metrics.width)
5340           {
5341             if (_DtCvUSE_BOUNDARY_MOVE == canvas->constraint)
5342               {
5343                 int i;
5344
5345                 /*
5346                  * clear the processed flag from all the text/region lines.
5347                  */
5348                 for (i = 0; i < canvas->txt_cnt; i++)
5349                    _DtCvClearProcessed(canvas->txt_lst[i]);
5350
5351                 /*
5352                  * clear the processed flag from all the line/rules.
5353                  */
5354                 for (i = 0; i < canvas->line_cnt; i++)
5355                    _DtCvClearProcessed(canvas->line_lst[i]);
5356
5357                 CheckMoveInfo(canvas, layout);
5358
5359                 /*
5360                  * recalculate the new max x
5361                  */
5362                 layout->info.max_x_pos = 0;
5363                 for (i = 0; i < canvas->txt_cnt; i++)
5364                     if (layout->info.max_x_pos < canvas->txt_lst[i].max_x)
5365                         layout->info.max_x_pos = canvas->txt_lst[i].max_x;
5366
5367                 for (i = 0; i < canvas->line_cnt; i++)
5368                     if (layout->info.max_x_pos < canvas->line_lst[i].max_x)
5369                         layout->info.max_x_pos = canvas->line_lst[i].max_x;
5370
5371                 layout->info.max_x_pos--;
5372               }
5373             else if (True == layout->margin_non_zero)
5374               {
5375                 redo = True;
5376                 divisor *= 2;
5377                 canvas->txt_cnt  = 0;
5378                 canvas->line_cnt = 0;
5379                 canvas->trav_cnt = 0;
5380               }
5381           }
5382
5383       } while (True == redo);
5384
5385     /*
5386      * clean up table information
5387      */
5388     if (NULL != layout->grp_lst)
5389         free(layout->grp_lst);
5390
5391     /*
5392      * subtract one from the y position to indicate the *last*
5393      * pixel/column/etc that will be rendered.
5394      */
5395     canvas->max_y = layout->info.y_pos - 1;
5396     canvas->max_x = layout->info.max_x_pos;
5397
5398     for (i = search_cnt; i < canvas->search_cnt; i++)
5399       {
5400         canvas->searchs[i - search_cnt]     = canvas->searchs[i];
5401         canvas->searchs[i - search_cnt].lst = canvas->txt_lst;
5402       }
5403
5404     canvas->search_cnt -= search_cnt;
5405
5406     /*
5407      * are there any search hits?
5408      */
5409     if (0 != canvas->search_cnt)
5410         qsort (canvas->searchs, canvas->search_cnt, sizeof(_DtCvSearchData),
5411                                                         CompareSearchs);
5412     /*
5413      * sort the page break list.
5414      */
5415     if (0 != canvas->brk_cnt)
5416         qsort (canvas->pg_breaks, canvas->brk_cnt, sizeof(_DtCvUnit),
5417                                                                 CompareUnits);
5418
5419     return result;
5420
5421 }  /* End LayoutCanvas */
5422
5423 /*****************************************************************************
5424  * Function:    static void SortTraversal (_DtCvHandle canvas);
5425  *
5426  * Parameters:
5427  *
5428  * Returns:
5429  *
5430  * Purpose:
5431  * 
5432  *****************************************************************************/
5433 static void
5434 SortTraversal (_DtCanvasStruct *canvas)
5435 {
5436     int i;
5437
5438     /*
5439      * sort the links correctly. First, establish the x,y,width,height
5440      * of each link.
5441      */
5442     for (i = 0; i < canvas->trav_cnt; i++)
5443       {
5444         if (_DtCvTraversalLink == canvas->trav_lst[i].type)
5445             GetLinkInfo(canvas, i, &(canvas->trav_lst[i].x_pos),
5446                                         &(canvas->trav_lst[i].y_pos),
5447                                         &(canvas->trav_lst[i].width),
5448                                         &(canvas->trav_lst[i].height));
5449         else
5450             _DtCvCalcMarkPos(canvas, canvas->trav_lst[i].idx,
5451                                         &(canvas->trav_lst[i].x_pos),
5452                                         &(canvas->trav_lst[i].y_pos),
5453                                         &(canvas->trav_lst[i].width),
5454                                         &(canvas->trav_lst[i].height));
5455       }
5456
5457     _DtCvSortTraversalList(canvas, _DtCvFALSE);
5458 }
5459
5460 /*****************************************************************************
5461  * Function:    static void ProcessMarks (_DtCanvasStruct *canvas);
5462  *
5463  * Parameters:
5464  *
5465  * Returns:
5466  *
5467  * Purpose:
5468  * 
5469  *****************************************************************************/
5470 static _DtCvStatus
5471 ProcessMarks (
5472     _DtCanvasStruct      *canvas,
5473     _DtCvPointInfo      **mark_lst)
5474 {
5475     int                 markIdx;
5476     int                 result = _DtCvSTATUS_OK;
5477     _DtCvSelectData     beg;
5478     _DtCvSelectData     end;
5479     _DtCvSegmentI       *firstSeg;
5480
5481     while (NULL != mark_lst && NULL != *mark_lst)
5482       {
5483         /*
5484          * convert the segments to begin and end points
5485          */
5486         if (_DtCvSTATUS_BAD == _DtCvCvtSegsToPts(canvas, (*mark_lst)->segs,
5487                                         &beg, &end, NULL, NULL, &firstSeg))
5488             /*
5489              * just set a return value since this indicates bad data
5490              * and not system failure.
5491              */
5492             result = _DtCvSTATUS_BAD;
5493
5494         /*
5495          * now add it to the mark list
5496          */
5497         else
5498           {
5499             markIdx =  _DtCvAddToMarkList(canvas, (*mark_lst)->client_data,
5500                                                 _DtCvFALSE, &beg, &end);
5501             /*
5502              * now put the mark in the traversal list, but don't sort
5503              * or fill out position and dimension information.
5504              * SortTraversal() will do that.
5505              *
5506              * bail here if system failure indicated.
5507              */
5508             if (-1 == markIdx || 0 != _DtCvSetTravEntryInfo(canvas,
5509                                                 _DtCvGetNextTravEntry(canvas),
5510                                                 _DtCvTraversalMark, firstSeg,
5511                                                 markIdx, _DtCvTRUE))
5512                 return _DtCvSTATUS_BAD;
5513           }
5514
5515         mark_lst++;
5516       }
5517
5518     return result;
5519 }
5520
5521 /*****************************************************************************
5522  *              Public Functions
5523  *****************************************************************************/
5524 /*****************************************************************************
5525  * Function:    void _DtCanvasResize (_DtCvHandle canvas);
5526  *
5527  * Parameters:
5528  *
5529  * Returns:
5530  *
5531  * Purpose:
5532  * 
5533  *****************************************************************************/
5534 _DtCvStatus
5535 _DtCanvasResize (
5536     _DtCvHandle          canvas_handle,
5537     _DtCvValue           force,
5538     _DtCvUnit           *ret_width,
5539     _DtCvUnit           *ret_height )
5540 {
5541     int                  i;
5542     _DtCvStatus          selectStatus;
5543     _DtCvStatus          retStatus = _DtCvSTATUS_NONE;
5544     _DtCanvasStruct     *canvas    = (_DtCanvasStruct *) canvas_handle;
5545     _DtCvSpaceMetrics    oldLink   = canvas->link_info;
5546     _DtCvSpaceMetrics    oldTrav   = canvas->traversal_info;
5547     _DtCvUnit            oldWidth  = canvas->metrics.width;
5548     LayoutInfo           layOut;
5549     _DtCvPointInfo       selPt;
5550     _DtCvPointInfo      **markInfo;
5551
5552     selPt.client_data = NULL;
5553     selPt.segs        = NULL;
5554
5555     /*
5556      * check to see if the width has changed - if not,
5557      * don't do anything (but re-initialize the metrics
5558      * to get the new height).
5559      */
5560     (*(canvas->virt_functions.get_metrics))(canvas->client_data,
5561                                 _DtCvCANVAS_TYPE, &(canvas->metrics));
5562
5563     if (canvas->metrics.width != oldWidth || _DtCvTRUE == force)
5564       {
5565         /*
5566          * remember the current selection.
5567          */
5568         selectStatus = _DtCanvasGetSelectionPoints(canvas, &(selPt.segs),
5569                                                                 NULL, NULL);
5570         /*
5571          * remember the marks
5572          */
5573         if (_DtCvSTATUS_BAD == _DtCvGetMarkSegs(canvas, &markInfo))
5574             return _DtCvSTATUS_BAD;
5575
5576         /*
5577          * Re-Layout the information.
5578          * First step - invalidate some counters.
5579          */
5580         canvas->trav_cnt = 0;   /* zero this only because we re-process */
5581                                 /* do not zero cur_hyper or we'll loose */
5582                                 /* where we are in the TOC              */
5583         canvas->txt_cnt  = 0;
5584         canvas->line_cnt = 0;
5585         canvas->mark_cnt = 0;
5586         canvas->brk_cnt  = 0;
5587
5588         /*
5589          * Layout the information if there is anything to do
5590          */
5591         if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, NULL))
5592             return _DtCvSTATUS_BAD;
5593     
5594         /*
5595          * restore the current selection.
5596          */
5597         if (_DtCvSTATUS_OK == selectStatus)
5598           {
5599             _DtCanvasActivatePts(canvas,_DtCvACTIVATE_SELECTION, &selPt,
5600                                                                 NULL,NULL);
5601             _DtCvFreeArray((void **) selPt.segs);
5602           }
5603
5604         /*
5605          * now place the marks in the mark and traversal lists
5606          */
5607         ProcessMarks(canvas, markInfo);
5608         if (NULL != markInfo)
5609           {
5610             for (i = 0; NULL != markInfo[i]; i++)
5611                 _DtCvFreeArray((void **) (markInfo[i]->segs));
5612             _DtCvFreeArray((void **) markInfo);
5613           }
5614
5615         /*
5616          * sort the traversal list.
5617          */
5618         SortTraversal(canvas);
5619         retStatus = _DtCvSTATUS_OK;
5620       }
5621
5622     /*
5623      * return the maximum height and width used
5624      */
5625     if (ret_width != NULL)
5626         *ret_width  = canvas->max_x;
5627     if (ret_height != NULL)
5628         *ret_height = canvas->max_y;
5629
5630     return retStatus;
5631
5632 }  /* End _DtCanvasResize */
5633
5634 /*****************************************************************************
5635  * Function:    void _DtCanvasSetTopic (_DtCvHandle canvas);
5636  *
5637  * Parameters:
5638  *
5639  * Returns:
5640  *
5641  * Purpose:
5642  * 
5643  *****************************************************************************/
5644 _DtCvStatus
5645 _DtCanvasSetTopic (
5646     _DtCvHandle          canvas_handle,
5647     _DtCvTopicPtr        topic,
5648     _DtCvValue           honor_size,
5649     _DtCvUnit           *ret_width,
5650     _DtCvUnit           *ret_height,
5651     _DtCvUnit           *ret_y )
5652 {
5653     int                  i;
5654     _DtCvStatus          result = _DtCvSTATUS_OK;
5655     _DtCanvasStruct     *canvas = (_DtCanvasStruct *) canvas_handle;
5656     LayoutInfo          layOut;
5657
5658     /*
5659      * clean the canvas
5660      */
5661     _DtCanvasClean (canvas_handle);
5662
5663     /*
5664      * attach to the canvas
5665      */
5666     canvas->element_lst = topic->seg_list;
5667
5668     /*
5669      * Attach the link information
5670      */
5671     canvas->link_data = topic->link_data;
5672
5673     /*
5674      * init the internal use pointer in all containers to NULL
5675      */
5676     _DtCvClearInternalUse(canvas->element_lst, _DtCvFALSE);
5677
5678     /*
5679      * Layout the information if there is anything to do
5680      */
5681     canvas->constraint = honor_size;
5682     if (_DtCvSTATUS_BAD == LayoutCanvas (canvas, &layOut, topic->id_str))
5683         return _DtCvSTATUS_BAD;
5684     
5685     /*
5686      * add the marks to the mark and traversal lists
5687      */
5688     ProcessMarks(canvas, topic->mark_list);
5689
5690     /*
5691      * sort the traversal list.
5692      */
5693     SortTraversal(canvas);
5694
5695     /*
5696      * return the maximum height and width used
5697      * And the location of the id.
5698      */
5699     if (ret_width != NULL)
5700         *ret_width = canvas->max_x;
5701     if (ret_height != NULL)
5702         *ret_height = canvas->max_y;
5703     if (ret_y != NULL)
5704       {
5705         if (NULL != layOut.target_id && True != layOut.id_found)
5706             result = _DtCvSTATUS_ID_BAD;
5707         *ret_y = layOut.id_Ypos;
5708       }
5709
5710     return result;
5711
5712 }  /* End _DtCanvasSetTopic */